diff options
author | Ivan Kohler <ivan@freeside.biz> | 2012-06-07 00:56:06 -0700 |
---|---|---|
committer | Ivan Kohler <ivan@freeside.biz> | 2012-06-07 00:56:06 -0700 |
commit | 43a06151e47d2c59b833cbd8c26d97865ee850b6 (patch) | |
tree | 42c51d94e7fa265461b508d061562be204ccc2c1 /rt/bin | |
parent | 6587f6ba7d047ddc1686c080090afe7d53365bd4 (diff) |
starting to work...
Diffstat (limited to 'rt/bin')
-rwxr-xr-x | rt/bin/fastcgi_server | 263 | ||||
-rw-r--r-- | rt/bin/fastcgi_server.in | 263 | ||||
-rwxr-xr-x | rt/bin/mason_handler.fcgi | 99 | ||||
-rw-r--r-- | rt/bin/mason_handler.fcgi.in | 99 | ||||
-rwxr-xr-x | rt/bin/mason_handler.scgi | 80 | ||||
-rw-r--r-- | rt/bin/mason_handler.scgi.in | 80 | ||||
-rw-r--r-- | rt/bin/mason_handler.svc | 276 | ||||
-rw-r--r-- | rt/bin/mason_handler.svc.in | 276 | ||||
-rwxr-xr-x[-rw-r--r--] | rt/bin/rt-crontool | 161 | ||||
-rw-r--r-- | rt/bin/rt-crontool.in | 159 | ||||
-rwxr-xr-x | rt/bin/rt-mailgate | 325 | ||||
-rw-r--r-- | rt/bin/rt-mailgate.in | 323 | ||||
-rw-r--r-- | rt/bin/rt.in | 129 | ||||
-rwxr-xr-x | rt/bin/standalone_httpd | 186 | ||||
-rwxr-xr-x | rt/bin/standalone_httpd.in | 186 | ||||
-rw-r--r-- | rt/bin/webmux.pl.in | 205 |
16 files changed, 771 insertions, 2339 deletions
diff --git a/rt/bin/fastcgi_server b/rt/bin/fastcgi_server deleted file mode 100755 index 4ccf014..0000000 --- a/rt/bin/fastcgi_server +++ /dev/null @@ -1,263 +0,0 @@ -#!/usr/bin/perl -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC -# <sales@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -=head1 NAME - -fastcgi_server - external FastCGI server for RT - -=head1 USAGE - - # get help - fastcgi_server -h - - # start a server using defaults - fastcgi_server - - # start server with custom option - fastcgi_server --socket /path/to/socket -n 5 - fastcgi_server --port 12345 -n 5 - -=head1 DESCRIPTION - -This is a forking external FastCGI server for RT, it can be used -with apache and other servers supporting FastCGI technology. - -An advantage is lower memory usage because of sharing memory -between process. It's easier to setup this with nginx and other -servers that can not maintain pool of fastcgi servers, apache -can do this. - -Disadvantage is that you have to start this server yourself and -monitor it, web servers wouldn't be able to restart it on crash. - -=head1 OPTIONS - -=over 4 - -=item -h, --help - get help - -=item -n, --nprocesses - number of processes to start, by default 10 - -=item -s, --socket - socket path, by default F<RT/var/path/fastcgi.sock> -usually F</opt/rt3/var/fastcgi.sock>. - -=item -p, --port - port to use instead of socket, by default socket is -used. - -=item --pidfile - pid file path, by default F<RT/var/path/fastcgi.pid>. - -=back - -=head1 SERVER CONFIGURATION - -=head2 nginx - -Below you can find example of minimal config for nginx to run RT -with this FastCGI server. It's not ideal, but a good enough start. - - worker_processes 1; - events { worker_connections 1024; } - - pid /opt/rt3/var/nginx/server.pid; - error_log /opt/rt3/var/nginx/error.log debug; - - http { - access_log /opt/rt3/var/nginx/access.log; - - server { - listen 8080; - server_name localhost; - - location / { - root /opt/rt3/share/html; - fastcgi_pass unix:/opt/rt3/var/fastcgi.sock; - - fastcgi_param QUERY_STRING $query_string; - fastcgi_param REQUEST_METHOD $request_method; - fastcgi_param CONTENT_TYPE $content_type; - fastcgi_param CONTENT_LENGTH $content_length; - fastcgi_param PATH_INFO $fastcgi_script_name; - } - - location /NoAuth/images/ { - alias /opt/rt3/share/html/NoAuth/images/; - } - } - } - -=head1 lighttpd - -Server config: - - server.name = "localhost" - server.port = 80 - - server.username = "rt_web_user" - server.groupname = "rt_web_group" - - server.pid-file = "/opt/rt3/var/lighthttpd/server.pid" - server.errorlog = "/opt/rt3/var/lighthttpd/error.log" - - server.document-root = "/opt/rt3/share/html" - - server.modules = ( "mod_fastcgi" ) - fastcgi.server = ( - "/" => (( - "socket" => "/opt/rt3/var/fastcgi.sock", - "check-local" => "disable", - "fix-root-scriptname" => "enable", - )) - ) - -=cut - - -use strict; -use warnings; -no warnings qw(once); - -package RT::Interface::Web::FCGI::Server; -use base qw(FCGI::ProcManager); - -package main; - -use Getopt::Long; - -my %opt = ( - help => 0, - socket => '', - port => 0, - nprocesses => 10, - pidfile => '', -); - -GetOptions( - 'h|help!' => \$opt{'help'}, - 's|socket=s' => \$opt{'socket'}, - 'p|port=s' => \$opt{'port'}, - 'n|nprocesses=s' => \$opt{'nprocesses'}, - 'pidfile=s' => \$opt{'pidfile'}, -); - -if ( $opt{'help'} ) { - require Pod::Usage; - Pod::Usage::pod2usage( - -message => "", - -exitval => $opt{'help'}? 0 : 1, - -verbose => 99, - -sections => $opt{'help'}? 'NAME|USAGE|DESCRIPTION|OPTIONS' : 'NAME|USAGE', - ); -} - -$ENV{'RT_WEBMUX_HEAVY_LOAD'} = 1; -use File::Basename; -require (dirname(__FILE__) .'/webmux.pl'); - -unless ( $opt{'socket'} || $opt{'port'} ) { - require File::Spec; - $opt{'socket'} = File::Spec->catfile($RT::VarPath, 'fastcgi.sock'); -} -elsif ( $opt{'port'} ) { - $opt{'socket'} = ':'. $opt{'port'}; -} -$ENV{'FCGI_SOCKET_PATH'} = $opt{'socket'}; - -$opt{'pidfile'} ||= File::Spec->catfile($RT::VarPath, 'fastcgi.pid'); - -require CGI::Fast; - -my $proc_manager = RT::Interface::Web::FCGI::Server->new({ - n_processes => $opt{'nprocesses'} || 10, - pid_fname => $opt{'pidfile'}, -}); - -$proc_manager->pm_manage(); - -while ( my $cgi = CGI::Fast->new ) { - $proc_manager->pm_pre_dispatch; - - $ENV{'PATH'} = '/bin:/usr/bin'; - $ENV{'CDPATH'} = '' if defined $ENV{'CDPATH'}; - $ENV{'SHELL'} = '/bin/sh' if defined $ENV{'SHELL'}; - $ENV{'ENV'} = '' if defined $ENV{'ENV'}; - $ENV{'IFS'} = '' if defined $ENV{'IFS'}; - - Module::Refresh->refresh if RT->Config->Get('DevelMode'); - RT::ConnectToDatabase(); - - # Each environment has its own way of handling .. and so on in paths, - # so RT consistently forbids such paths. - if ( $cgi->path_info =~ m{/\.} ) { - $RT::Logger->crit("Invalid request for ".$cgi->path_info." aborting"); - print STDOUT "HTTP/1.0 400\r\n\r\n"; - - RT::Interface::Web::Handler->CleanupRequest(); - $proc_manager->pm_post_dispatch; - - next; - } - - my $interp = $RT::Mason::Handler->interp; - if ( - !$interp->comp_exists( $cgi->path_info ) - && $interp->comp_exists( $cgi->path_info . "/index.html" ) - ) { - $cgi->path_info( $cgi->path_info . "/index.html" ); - } - - local $@; - eval { $RT::Mason::Handler->handle_cgi_object($cgi); }; - if ($@) { - $RT::Logger->crit($@); - } - RT::Interface::Web::Handler->CleanupRequest; - - $proc_manager->pm_post_dispatch; -} - -1; diff --git a/rt/bin/fastcgi_server.in b/rt/bin/fastcgi_server.in deleted file mode 100644 index d6df63c..0000000 --- a/rt/bin/fastcgi_server.in +++ /dev/null @@ -1,263 +0,0 @@ -#!@PERL@ -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC -# <sales@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -=head1 NAME - -fastcgi_server - external FastCGI server for RT - -=head1 USAGE - - # get help - fastcgi_server -h - - # start a server using defaults - fastcgi_server - - # start server with custom option - fastcgi_server --socket /path/to/socket -n 5 - fastcgi_server --port 12345 -n 5 - -=head1 DESCRIPTION - -This is a forking external FastCGI server for RT, it can be used -with apache and other servers supporting FastCGI technology. - -An advantage is lower memory usage because of sharing memory -between process. It's easier to setup this with nginx and other -servers that can not maintain pool of fastcgi servers, apache -can do this. - -Disadvantage is that you have to start this server yourself and -monitor it, web servers wouldn't be able to restart it on crash. - -=head1 OPTIONS - -=over 4 - -=item -h, --help - get help - -=item -n, --nprocesses - number of processes to start, by default 10 - -=item -s, --socket - socket path, by default F<RT/var/path/fastcgi.sock> -usually F</opt/rt3/var/fastcgi.sock>. - -=item -p, --port - port to use instead of socket, by default socket is -used. - -=item --pidfile - pid file path, by default F<RT/var/path/fastcgi.pid>. - -=back - -=head1 SERVER CONFIGURATION - -=head2 nginx - -Below you can find example of minimal config for nginx to run RT -with this FastCGI server. It's not ideal, but a good enough start. - - worker_processes 1; - events { worker_connections 1024; } - - pid /opt/rt3/var/nginx/server.pid; - error_log /opt/rt3/var/nginx/error.log debug; - - http { - access_log /opt/rt3/var/nginx/access.log; - - server { - listen 8080; - server_name localhost; - - location / { - root /opt/rt3/share/html; - fastcgi_pass unix:/opt/rt3/var/fastcgi.sock; - - fastcgi_param QUERY_STRING $query_string; - fastcgi_param REQUEST_METHOD $request_method; - fastcgi_param CONTENT_TYPE $content_type; - fastcgi_param CONTENT_LENGTH $content_length; - fastcgi_param PATH_INFO $fastcgi_script_name; - } - - location /NoAuth/images/ { - alias /opt/rt3/share/html/NoAuth/images/; - } - } - } - -=head1 lighttpd - -Server config: - - server.name = "localhost" - server.port = 80 - - server.username = "rt_web_user" - server.groupname = "rt_web_group" - - server.pid-file = "/opt/rt3/var/lighthttpd/server.pid" - server.errorlog = "/opt/rt3/var/lighthttpd/error.log" - - server.document-root = "/opt/rt3/share/html" - - server.modules = ( "mod_fastcgi" ) - fastcgi.server = ( - "/" => (( - "socket" => "/opt/rt3/var/fastcgi.sock", - "check-local" => "disable", - "fix-root-scriptname" => "enable", - )) - ) - -=cut - - -use strict; -use warnings; -no warnings qw(once); - -package RT::Interface::Web::FCGI::Server; -use base qw(FCGI::ProcManager); - -package main; - -use Getopt::Long; - -my %opt = ( - help => 0, - socket => '', - port => 0, - nprocesses => 10, - pidfile => '', -); - -GetOptions( - 'h|help!' => \$opt{'help'}, - 's|socket=s' => \$opt{'socket'}, - 'p|port=s' => \$opt{'port'}, - 'n|nprocesses=s' => \$opt{'nprocesses'}, - 'pidfile=s' => \$opt{'pidfile'}, -); - -if ( $opt{'help'} ) { - require Pod::Usage; - Pod::Usage::pod2usage( - -message => "", - -exitval => $opt{'help'}? 0 : 1, - -verbose => 99, - -sections => $opt{'help'}? 'NAME|USAGE|DESCRIPTION|OPTIONS' : 'NAME|USAGE', - ); -} - -$ENV{'RT_WEBMUX_HEAVY_LOAD'} = 1; -use File::Basename; -require (dirname(__FILE__) .'/webmux.pl'); - -unless ( $opt{'socket'} || $opt{'port'} ) { - require File::Spec; - $opt{'socket'} = File::Spec->catfile($RT::VarPath, 'fastcgi.sock'); -} -elsif ( $opt{'port'} ) { - $opt{'socket'} = ':'. $opt{'port'}; -} -$ENV{'FCGI_SOCKET_PATH'} = $opt{'socket'}; - -$opt{'pidfile'} ||= File::Spec->catfile($RT::VarPath, 'fastcgi.pid'); - -require CGI::Fast; - -my $proc_manager = RT::Interface::Web::FCGI::Server->new({ - n_processes => $opt{'nprocesses'} || 10, - pid_fname => $opt{'pidfile'}, -}); - -$proc_manager->pm_manage(); - -while ( my $cgi = CGI::Fast->new ) { - $proc_manager->pm_pre_dispatch; - - $ENV{'PATH'} = '/bin:/usr/bin'; - $ENV{'CDPATH'} = '' if defined $ENV{'CDPATH'}; - $ENV{'SHELL'} = '/bin/sh' if defined $ENV{'SHELL'}; - $ENV{'ENV'} = '' if defined $ENV{'ENV'}; - $ENV{'IFS'} = '' if defined $ENV{'IFS'}; - - Module::Refresh->refresh if RT->Config->Get('DevelMode'); - RT::ConnectToDatabase(); - - # Each environment has its own way of handling .. and so on in paths, - # so RT consistently forbids such paths. - if ( $cgi->path_info =~ m{/\.} ) { - $RT::Logger->crit("Invalid request for ".$cgi->path_info." aborting"); - print STDOUT "HTTP/1.0 400\r\n\r\n"; - - RT::Interface::Web::Handler->CleanupRequest(); - $proc_manager->pm_post_dispatch; - - next; - } - - my $interp = $RT::Mason::Handler->interp; - if ( - !$interp->comp_exists( $cgi->path_info ) - && $interp->comp_exists( $cgi->path_info . "/index.html" ) - ) { - $cgi->path_info( $cgi->path_info . "/index.html" ); - } - - local $@; - eval { $RT::Mason::Handler->handle_cgi_object($cgi); }; - if ($@) { - $RT::Logger->crit($@); - } - RT::Interface::Web::Handler->CleanupRequest; - - $proc_manager->pm_post_dispatch; -} - -1; diff --git a/rt/bin/mason_handler.fcgi b/rt/bin/mason_handler.fcgi deleted file mode 100755 index 996e960..0000000 --- a/rt/bin/mason_handler.fcgi +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/perl -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC -# <sales@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -use strict; -use warnings; -no warnings qw(once); - -use File::Basename; -require (dirname(__FILE__) .'/webmux.pl'); - -# Enter CGI::Fast mode, which should also work as a vanilla CGI script. -require CGI::Fast; - -while ( my $cgi = CGI::Fast->new ) { - # the whole point of fastcgi requires the env to get reset here.. - # So we must squash it again - $ENV{'PATH'} = '/bin:/usr/bin'; - $ENV{'CDPATH'} = '' if defined $ENV{'CDPATH'}; - $ENV{'SHELL'} = '/bin/sh' if defined $ENV{'SHELL'}; - $ENV{'ENV'} = '' if defined $ENV{'ENV'}; - $ENV{'IFS'} = '' if defined $ENV{'IFS'}; - - Module::Refresh->refresh if RT->Config->Get('DevelMode'); - RT::ConnectToDatabase(); - - # Each environment has its own way of handling .. and so on in paths, - # so RT consistently forbids such paths. - if ( $cgi->path_info =~ m{/\.} ) { - $RT::Logger->crit("Invalid request for ".$cgi->path_info." aborting"); - print STDOUT "HTTP/1.0 400\r\n\r\n"; - - RT::Interface::Web::Handler->CleanupRequest(); - - next; - } - - my $interp = $RT::Mason::Handler->interp; - if ( - !$interp->comp_exists( $cgi->path_info ) - && $interp->comp_exists( $cgi->path_info . "/index.html" ) - ) { - $cgi->path_info( $cgi->path_info . "/index.html" ); - } - - local $@; - eval { $RT::Mason::Handler->handle_cgi_object($cgi); }; - if ($@) { - $RT::Logger->crit($@); - } - RT::Interface::Web::Handler->CleanupRequest(); - -} - -1; diff --git a/rt/bin/mason_handler.fcgi.in b/rt/bin/mason_handler.fcgi.in deleted file mode 100644 index 4682abf..0000000 --- a/rt/bin/mason_handler.fcgi.in +++ /dev/null @@ -1,99 +0,0 @@ -#!@PERL@ -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC -# <sales@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -use strict; -use warnings; -no warnings qw(once); - -use File::Basename; -require (dirname(__FILE__) .'/webmux.pl'); - -# Enter CGI::Fast mode, which should also work as a vanilla CGI script. -require CGI::Fast; - -while ( my $cgi = CGI::Fast->new ) { - # the whole point of fastcgi requires the env to get reset here.. - # So we must squash it again - $ENV{'PATH'} = '/bin:/usr/bin'; - $ENV{'CDPATH'} = '' if defined $ENV{'CDPATH'}; - $ENV{'SHELL'} = '/bin/sh' if defined $ENV{'SHELL'}; - $ENV{'ENV'} = '' if defined $ENV{'ENV'}; - $ENV{'IFS'} = '' if defined $ENV{'IFS'}; - - Module::Refresh->refresh if RT->Config->Get('DevelMode'); - RT::ConnectToDatabase(); - - # Each environment has its own way of handling .. and so on in paths, - # so RT consistently forbids such paths. - if ( $cgi->path_info =~ m{/\.} ) { - $RT::Logger->crit("Invalid request for ".$cgi->path_info." aborting"); - print STDOUT "HTTP/1.0 400\r\n\r\n"; - - RT::Interface::Web::Handler->CleanupRequest(); - - next; - } - - my $interp = $RT::Mason::Handler->interp; - if ( - !$interp->comp_exists( $cgi->path_info ) - && $interp->comp_exists( $cgi->path_info . "/index.html" ) - ) { - $cgi->path_info( $cgi->path_info . "/index.html" ); - } - - local $@; - eval { $RT::Mason::Handler->handle_cgi_object($cgi); }; - if ($@) { - $RT::Logger->crit($@); - } - RT::Interface::Web::Handler->CleanupRequest(); - -} - -1; diff --git a/rt/bin/mason_handler.scgi b/rt/bin/mason_handler.scgi deleted file mode 100755 index 83649ed..0000000 --- a/rt/bin/mason_handler.scgi +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/local/bin/speedy -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC -# <sales@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -package RT::Mason; - -use strict; -use vars '$Handler'; -use File::Basename; - -require (dirname(__FILE__) . '/webmux.pl'); - -require CGI; - -my $cgi = CGI->new; - -# Each environment has its own way of handling .. and so on in paths, -# so RT consistently forbids such paths. -if ( $cgi->path_info =~ m{/\.} ) { - $RT::Logger->crit("Invalid request for ".$cgi->path_info." aborting"); - print STDOUT "HTTP/1.0 400\r\n\r\n"; - - RT::Interface::Web::Handler->CleanupRequest(); - - return 0; -} - -if ( ( !$Handler->interp->comp_exists( $cgi->path_info ) ) - && ( $Handler->interp->comp_exists( $cgi->path_info . "/index.html" ) ) ) { - $cgi->path_info( $cgi->path_info . "/index.html" ); -} - -RT::ConnectToDatabase(); -$Handler->handle_cgi_object($cgi); -RT::Interface::Web::Handler->CleanupRequest(); -1; diff --git a/rt/bin/mason_handler.scgi.in b/rt/bin/mason_handler.scgi.in deleted file mode 100644 index fa771b7..0000000 --- a/rt/bin/mason_handler.scgi.in +++ /dev/null @@ -1,80 +0,0 @@ -#!@SPEEDY_BIN@ -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC -# <sales@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -package RT::Mason; - -use strict; -use vars '$Handler'; -use File::Basename; - -require (dirname(__FILE__) . '/webmux.pl'); - -require CGI; - -my $cgi = CGI->new; - -# Each environment has its own way of handling .. and so on in paths, -# so RT consistently forbids such paths. -if ( $cgi->path_info =~ m{/\.} ) { - $RT::Logger->crit("Invalid request for ".$cgi->path_info." aborting"); - print STDOUT "HTTP/1.0 400\r\n\r\n"; - - RT::Interface::Web::Handler->CleanupRequest(); - - return 0; -} - -if ( ( !$Handler->interp->comp_exists( $cgi->path_info ) ) - && ( $Handler->interp->comp_exists( $cgi->path_info . "/index.html" ) ) ) { - $cgi->path_info( $cgi->path_info . "/index.html" ); -} - -RT::ConnectToDatabase(); -$Handler->handle_cgi_object($cgi); -RT::Interface::Web::Handler->CleanupRequest(); -1; diff --git a/rt/bin/mason_handler.svc b/rt/bin/mason_handler.svc deleted file mode 100644 index 6275a9e..0000000 --- a/rt/bin/mason_handler.svc +++ /dev/null @@ -1,276 +0,0 @@ -#!/usr/bin/perl -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC -# <sales@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -=head1 NAME - -mason_handler.svc - Win32 IIS Service handler for RT - -=head1 SYNOPSIS - - perl mason_handler.svc --install # install as service - perl mason_handler.svc --deinstall # deinstall this service - perl mason_handler.svc --help # show this help - perl mason_handler.svc # launch handler from command line - -=head1 DESCRIPTION - -This script manages a stand-alone FastCGI server, and populates the necessary -registry settings to run it with Microsoft IIS Server 4.0 or above. - -Before running it, you need to install the B<FCGI> module from CPAN, as well as -B<Win32::Daemon> from L<http://www.roth.net/perl/Daemon/> if you want to install -itself as a service. - -This script will automatically create a virtual directory under the IIS root; -its name is taken from C<$WebPath> in the F<RT_Config.pm> file. Additionally, -please install the ISAPI binary from L<http://www.caraveo.com/fastcgi/> and set -up an ISAPI Script Map that maps F<.html> files to F<isapi_fcgi.dll>. - -Once the service is launched (either via C<net start RTFastCGI> or by running -C<perl mason_handler.svc>), a FCGI server will start and bind to port C<8284> -(mnemonics: the ASCII value of C<R> and C<T>); the ISAPI handler's C<BindPath> -registry setting will also be automatically populated. - -=cut - -package RT::Mason; - -use strict; -use File::Basename; -use vars '$Handler'; -require (dirname(__FILE__) . '/webmux.pl'); - -use Cwd; -use File::Spec; - -use Win32; -use Win32::Process; -use Win32::Service; -use Win32::TieRegistry; - -my $ProcessObj; - -BEGIN { - my $runsvc = sub { - Win32::Process::Create( - $ProcessObj, $^X, "$^X $0 --run", 0, NORMAL_PRIORITY_CLASS, "." - ) or do { - die Win32::FormatMessage( Win32::GetLastError() ); - }; - - chdir File::Basename::dirname($0); - my $path = Cwd::cwd(); - $path =~ s|/|\\|g; - $path =~ s|bin$|share\\html|; - - $Win32::TieRegistry::Registry->{ - 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\\'. - 'W3SVC\Parameters\Virtual Roots\\' - }->{RT->Config->Get('WebPath') || '/'} = "$path,,205"; - - $Win32::TieRegistry::Registry->{ - 'HKEY_LOCAL_MACHINE\Software\FASTCGI\.html\\' - }->{'BindPath'} = $ENV{'FCGI_SOCKET_PATH'}; - - Win32::Service::StartService(Win32::NodeName, 'W3SVC'); - }; - - if ($ARGV[0] eq '--deinstall') { - chdir File::Basename::dirname($0); - my $path = Cwd::cwd(); - $path =~ s|/|\\|g; - - require Win32::Daemon; - Win32::Daemon::DeleteService('RTFastCGI'); - warn "Service 'RTFastCGI' successfully deleted.\n"; - exit; - } - elsif ($ARGV[0] eq '--install') { - chdir File::Basename::dirname($0); - my $path = Cwd::cwd(); - $path =~ s|/|\\|g; - - require Win32::Daemon; - Win32::Daemon::DeleteService('RTFastCGI'); - - my $rv = Win32::Daemon::CreateService( { - machine => '', - name => 'RTFastCGI', - display => 'RT FastCGI Handler', - path => $^X, - user => '', - pwd => $path, - description => 'Enables port 8284 as the RT FastCGI handler.', - parameters => File::Spec->catfile( - $path, File::Basename::basename($0) - ) . ' --service', - } ); - - if ($rv) { - warn "Service 'RTFastCGI' successfully created.\n"; - } - else { - warn "Failed to add service: " . Win32::FormatMessage( - Win32::Daemon::GetLastError() - ) . "\n"; - } - exit; - } - elsif ($ARGV[0] eq '--service') { - require Win32::Daemon; - - my $PrevState = Win32::Daemon::SERVICE_START_PENDING(); - Win32::Daemon::StartService() or die $^E; - - while ( 1 ) { - my $State = Win32::Daemon::State(); - last if $State == Win32::Daemon::SERVICE_STOPPED(); - - if ( $State == Win32::Daemon::SERVICE_START_PENDING() ) { - $runsvc->(); - Win32::Daemon::State( Win32::Daemon::SERVICE_RUNNING() ); - $PrevState = Win32::Daemon::SERVICE_RUNNING(); - } - elsif ( $State == Win32::Daemon::SERVICE_CONTINUE_PENDING() ) { - $ProcessObj->Resume; - Win32::Daemon::State( Win32::Daemon::SERVICE_RUNNING() ); - $PrevState = Win32::Daemon::SERVICE_RUNNING(); - } - elsif ( $State == Win32::Daemon::SERVICE_STOP_PENDING() ) { - $ProcessObj->Kill(0); - Win32::Daemon::State( Win32::Daemon::SERVICE_STOPPED() ); - $PrevState = Win32::Daemon::SERVICE_STOPPED(); - } - elsif ( $State == Win32::Daemon::SERVICE_RUNNING() ) { - my $Message = Win32::Daemon::QueryLastMessage(1); - if ( $Message == Win32::Daemon::SERVICE_CONTROL_INTERROGATE() ) { - Win32::Daemon::State( $PrevState ); - } - elsif ( $Message == Win32::Daemon::SERVICE_CONTROL_SHUTDOWN() ) { - Win32::Daemon::State( Win32::Daemon::SERVICE_STOP_PENDING(), 15000 ); - } - elsif ( $Message != Win32::Daemon::SERVICE_CONTROL_NONE() ) { - Win32::Daemon::State( $PrevState ); - } - } - - Win32::Sleep( 1000 ); - } - - Win32::Daemon::StopService(); - exit; - } - elsif ($ARGV[0] eq '--help') { - system("perldoc $0"); - exit; - } - elsif ($ARGV[0] ne '--run') { - $SIG{__DIE__} = sub { $ProcessObj->Kill(0) if $ProcessObj }; - $runsvc->(); - warn "RT FastCGI Handler launched. Press [Enter] to terminate...\n"; - <STDIN>; - exit; - } -} - -############################################################################### - -warn "Begin listening on $ENV{'FCGI_SOCKET_PATH'}\n"; - -require CGI::Fast; - -RT::Init(); -$Handler ||= RT::Interface::Web::Handler->new( - RT->Config->Get('MasonParameters') -); - - -# Response loop -while( my $cgi = CGI::Fast->new ) { - my $comp = $ENV{'PATH_INFO'}; - - # Each environment has its own way of handling .. and so on in paths, - # so RT consistently forbids such paths. - if ( $cgi->path_info =~ m{/\.} ) { - $RT::Logger->crit("Invalid request for ".$cgi->path_info." aborting"); - print STDOUT "HTTP/1.0 400\r\n\r\n"; - - RT::Interface::Web::Handler->CleanupRequest(); - - next; - } - - $comp = $1 if ($comp =~ /^(.*)$/); - my $web_path = RT->Config->Get('WebPath'); - $comp =~ s|^\Q$web_path\E\b||i; - $comp .= "index.html" if ($comp =~ /\/$/); - $comp =~ s/.pl$/.html/g; - - warn "Serving $comp\n"; - - $Handler->handle_cgi($comp); - RT::Interface::Web::Handler->CleanupRequest(); - # _should_ always be tied -} - -1; - -=head1 AUTHORS - -Autrijus Tang E<lt>autrijus@autrijus.orgE<gt> - -=head1 COPYRIGHT - -Copyright 2002 by Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>. - -This program is free software; you can redistribute it and/or -modify it under the same terms as Perl itself. - -See L<http://www.perl.com/perl/misc/Artistic.html> - -=cut diff --git a/rt/bin/mason_handler.svc.in b/rt/bin/mason_handler.svc.in deleted file mode 100644 index 119b110..0000000 --- a/rt/bin/mason_handler.svc.in +++ /dev/null @@ -1,276 +0,0 @@ -#!@PERL@ -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC -# <sales@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -=head1 NAME - -mason_handler.svc - Win32 IIS Service handler for RT - -=head1 SYNOPSIS - - perl mason_handler.svc --install # install as service - perl mason_handler.svc --deinstall # deinstall this service - perl mason_handler.svc --help # show this help - perl mason_handler.svc # launch handler from command line - -=head1 DESCRIPTION - -This script manages a stand-alone FastCGI server, and populates the necessary -registry settings to run it with Microsoft IIS Server 4.0 or above. - -Before running it, you need to install the B<FCGI> module from CPAN, as well as -B<Win32::Daemon> from L<http://www.roth.net/perl/Daemon/> if you want to install -itself as a service. - -This script will automatically create a virtual directory under the IIS root; -its name is taken from C<$WebPath> in the F<RT_Config.pm> file. Additionally, -please install the ISAPI binary from L<http://www.caraveo.com/fastcgi/> and set -up an ISAPI Script Map that maps F<.html> files to F<isapi_fcgi.dll>. - -Once the service is launched (either via C<net start RTFastCGI> or by running -C<perl mason_handler.svc>), a FCGI server will start and bind to port C<8284> -(mnemonics: the ASCII value of C<R> and C<T>); the ISAPI handler's C<BindPath> -registry setting will also be automatically populated. - -=cut - -package RT::Mason; - -use strict; -use File::Basename; -use vars '$Handler'; -require (dirname(__FILE__) . '/webmux.pl'); - -use Cwd; -use File::Spec; - -use Win32; -use Win32::Process; -use Win32::Service; -use Win32::TieRegistry; - -my $ProcessObj; - -BEGIN { - my $runsvc = sub { - Win32::Process::Create( - $ProcessObj, $^X, "$^X $0 --run", 0, NORMAL_PRIORITY_CLASS, "." - ) or do { - die Win32::FormatMessage( Win32::GetLastError() ); - }; - - chdir File::Basename::dirname($0); - my $path = Cwd::cwd(); - $path =~ s|/|\\|g; - $path =~ s|bin$|share\\html|; - - $Win32::TieRegistry::Registry->{ - 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\\'. - 'W3SVC\Parameters\Virtual Roots\\' - }->{RT->Config->Get('WebPath') || '/'} = "$path,,205"; - - $Win32::TieRegistry::Registry->{ - 'HKEY_LOCAL_MACHINE\Software\FASTCGI\.html\\' - }->{'BindPath'} = $ENV{'FCGI_SOCKET_PATH'}; - - Win32::Service::StartService(Win32::NodeName, 'W3SVC'); - }; - - if ($ARGV[0] eq '--deinstall') { - chdir File::Basename::dirname($0); - my $path = Cwd::cwd(); - $path =~ s|/|\\|g; - - require Win32::Daemon; - Win32::Daemon::DeleteService('RTFastCGI'); - warn "Service 'RTFastCGI' successfully deleted.\n"; - exit; - } - elsif ($ARGV[0] eq '--install') { - chdir File::Basename::dirname($0); - my $path = Cwd::cwd(); - $path =~ s|/|\\|g; - - require Win32::Daemon; - Win32::Daemon::DeleteService('RTFastCGI'); - - my $rv = Win32::Daemon::CreateService( { - machine => '', - name => 'RTFastCGI', - display => 'RT FastCGI Handler', - path => $^X, - user => '', - pwd => $path, - description => 'Enables port 8284 as the RT FastCGI handler.', - parameters => File::Spec->catfile( - $path, File::Basename::basename($0) - ) . ' --service', - } ); - - if ($rv) { - warn "Service 'RTFastCGI' successfully created.\n"; - } - else { - warn "Failed to add service: " . Win32::FormatMessage( - Win32::Daemon::GetLastError() - ) . "\n"; - } - exit; - } - elsif ($ARGV[0] eq '--service') { - require Win32::Daemon; - - my $PrevState = Win32::Daemon::SERVICE_START_PENDING(); - Win32::Daemon::StartService() or die $^E; - - while ( 1 ) { - my $State = Win32::Daemon::State(); - last if $State == Win32::Daemon::SERVICE_STOPPED(); - - if ( $State == Win32::Daemon::SERVICE_START_PENDING() ) { - $runsvc->(); - Win32::Daemon::State( Win32::Daemon::SERVICE_RUNNING() ); - $PrevState = Win32::Daemon::SERVICE_RUNNING(); - } - elsif ( $State == Win32::Daemon::SERVICE_CONTINUE_PENDING() ) { - $ProcessObj->Resume; - Win32::Daemon::State( Win32::Daemon::SERVICE_RUNNING() ); - $PrevState = Win32::Daemon::SERVICE_RUNNING(); - } - elsif ( $State == Win32::Daemon::SERVICE_STOP_PENDING() ) { - $ProcessObj->Kill(0); - Win32::Daemon::State( Win32::Daemon::SERVICE_STOPPED() ); - $PrevState = Win32::Daemon::SERVICE_STOPPED(); - } - elsif ( $State == Win32::Daemon::SERVICE_RUNNING() ) { - my $Message = Win32::Daemon::QueryLastMessage(1); - if ( $Message == Win32::Daemon::SERVICE_CONTROL_INTERROGATE() ) { - Win32::Daemon::State( $PrevState ); - } - elsif ( $Message == Win32::Daemon::SERVICE_CONTROL_SHUTDOWN() ) { - Win32::Daemon::State( Win32::Daemon::SERVICE_STOP_PENDING(), 15000 ); - } - elsif ( $Message != Win32::Daemon::SERVICE_CONTROL_NONE() ) { - Win32::Daemon::State( $PrevState ); - } - } - - Win32::Sleep( 1000 ); - } - - Win32::Daemon::StopService(); - exit; - } - elsif ($ARGV[0] eq '--help') { - system("perldoc $0"); - exit; - } - elsif ($ARGV[0] ne '--run') { - $SIG{__DIE__} = sub { $ProcessObj->Kill(0) if $ProcessObj }; - $runsvc->(); - warn "RT FastCGI Handler launched. Press [Enter] to terminate...\n"; - <STDIN>; - exit; - } -} - -############################################################################### - -warn "Begin listening on $ENV{'FCGI_SOCKET_PATH'}\n"; - -require CGI::Fast; - -RT::Init(); -$Handler ||= RT::Interface::Web::Handler->new( - RT->Config->Get('MasonParameters') -); - - -# Response loop -while( my $cgi = CGI::Fast->new ) { - my $comp = $ENV{'PATH_INFO'}; - - # Each environment has its own way of handling .. and so on in paths, - # so RT consistently forbids such paths. - if ( $cgi->path_info =~ m{/\.} ) { - $RT::Logger->crit("Invalid request for ".$cgi->path_info." aborting"); - print STDOUT "HTTP/1.0 400\r\n\r\n"; - - RT::Interface::Web::Handler->CleanupRequest(); - - next; - } - - $comp = $1 if ($comp =~ /^(.*)$/); - my $web_path = RT->Config->Get('WebPath'); - $comp =~ s|^\Q$web_path\E\b||i; - $comp .= "index.html" if ($comp =~ /\/$/); - $comp =~ s/.pl$/.html/g; - - warn "Serving $comp\n"; - - $Handler->handle_cgi($comp); - RT::Interface::Web::Handler->CleanupRequest(); - # _should_ always be tied -} - -1; - -=head1 AUTHORS - -Autrijus Tang E<lt>autrijus@autrijus.orgE<gt> - -=head1 COPYRIGHT - -Copyright 2002 by Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>. - -This program is free software; you can redistribute it and/or -modify it under the same terms as Perl itself. - -See L<http://www.perl.com/perl/misc/Artistic.html> - -=cut diff --git a/rt/bin/rt-crontool b/rt/bin/rt-crontool index 6193280..e58bafc 100644..100755 --- a/rt/bin/rt-crontool +++ b/rt/bin/rt-crontool @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -52,7 +52,7 @@ use Carp; # fix lib paths, some may be relative BEGIN { require File::Spec; - my @libs = ("lib", "local/lib"); + my @libs = ("/opt/rt3/lib", "/opt/rt3/local/lib"); my $bin_path; for my $lib (@libs) { @@ -120,7 +120,7 @@ my $CurrentUser = GetCurrentUser(); help() if $help; unless ( $CurrentUser->Id ) { - print loc("No RT user found. Please consult your RT administrator.\n"); + print loc("No RT user found. Please consult your RT administrator."); exit(1); } @@ -166,7 +166,7 @@ my $tickets = $search->TicketsObj; #for each ticket we've found while ( my $ticket = $tickets->Next() ) { - print $ticket->Id() . ": " if ($verbose); + print $ticket->Id() . ":\n" if ($verbose); my $template_obj = get_template( $ticket ); @@ -174,15 +174,15 @@ while ( my $ticket = $tickets->Next() ) { my $txns = get_transactions($ticket); my $found = 0; while ( my $txn = $txns->Next ) { - print loc("Using transaction #[_1]...", $txn->id) + print "\t".loc("Using transaction #[_1]...", $txn->id)."\n" if $verbose; process($ticket, $txn, $template_obj); $found = 1; } - print loc("Couldn't find suitable transaction, skipping") + print "\t".loc("Couldn't find suitable transaction, skipping")."\n" if $verbose && !$found; } else { - print loc("Processing without transaction, some conditions and actions may fail. Consider using --transaction argument") + print "\t".loc("Processing without transaction, some conditions and actions may fail. Consider using --transaction argument")."\n" if $verbose; process($ticket, undef, $template_obj); @@ -208,7 +208,7 @@ sub process { # if the condition doesn't apply, get out of here return unless $condition_obj->IsApplicable; - print loc("Condition matches...") if $verbose; + print "\t".loc("Condition matches...")."\n" if $verbose; } #prepare our action @@ -224,20 +224,20 @@ sub process { #if our preparation, move onto the next ticket return unless $action_obj->Prepare; - print loc("Action prepared...") if $verbose; + print "\t".loc("Action prepared...")."\n" if $verbose; #commit our action. return unless $action_obj->Commit; - print loc("Action committed.\n") if $verbose; + print "\t".loc("Action committed.")."\n" if $verbose; } -=head2 get_transactions - -Takes ticket and returns L<RT::Transactions> object with transactions -of the ticket according to command line arguments C<--transaction> -and <--transaction-type>. - -=cut +# =head2 get_transactions +# +# Takes ticket and returns L<RT::Transactions> object with transactions +# of the ticket according to command line arguments C<--transaction> +# and <--transaction-type>. +# +# =cut sub get_transactions { my $ticket = shift; @@ -258,11 +258,11 @@ sub get_transactions { return $txns; } -=head2 get_template - -Takes a ticket and returns a template according to command line options. - -=cut +# =head2 get_template +# +# Takes a ticket and returns a template according to command line options. +# +# =cut { my $cache = undef; sub get_template { @@ -273,7 +273,7 @@ sub get_template { # by id return $cache if $cache; - my $cache = RT::Template->new( $RT::SystemUser ); + my $cache = RT::Template->new( RT->SystemUser ); $cache->Load( $template ); die "Failed to load template '$template'" unless $cache->id; @@ -283,7 +283,7 @@ sub get_template { my $queue = $ticket->Queue; return $cache->{ $queue } if $cache->{ $queue }; - my $res = RT::Template->new( $RT::SystemUser ); + my $res = RT::Template->new( RT->SystemUser ); $res->LoadQueueTemplate( Queue => $queue, Name => $template ); unless ( $res->id ) { $res->LoadGlobalTemplate( $template ); @@ -293,13 +293,12 @@ sub get_template { return $cache->{ $queue } = $res; } } -# {{{ load_module - -=head2 load_module - -Loads a perl module, dying nicely if it can't find it. -=cut +# =head2 load_module +# +# Loads a perl module, dying nicely if it can't find it. +# +# =cut sub load_module { my $modname = shift; @@ -310,21 +309,18 @@ sub load_module { } -# }}} -# {{{ loc -=head2 loc LIST - -Localize this string, with the current user's currentuser object - -=cut +# =head2 loc LIST +# +# Localize this string, with the current user's currentuser object +# +# =cut sub loc { $CurrentUser->loc(@_); } -# }}} sub help { @@ -389,7 +385,7 @@ sub help { print loc("Escalate tickets"). "\n"; print " bin/rt-crontool \\\n"; print " --search RT::Search::ActiveTicketsInQueue --search-arg general \\\n"; - print " --action RT::Action::EscalatePriority\n"; + print" --action RT::Action::EscalatePriority\n"; @@ -398,3 +394,90 @@ sub help { exit(0); } + +__END__ + +=head1 NAME + +rt-crontool - a tool to act on tickets from an external scheduling tool + +=head1 SYNOPSIS + + # find all active tickets in the queue 'general' and set their priority to 99 if they are overdue: + rt-crontool \ + --search RT::Search::ActiveTicketsInQueue --search-arg general \ + --condition RT::Condition::Overdue \ + --action RT::Action::SetPriority --action-arg 99 \ + --verbose + + # Escalate tickets + rt-crontool \ + --search RT::Search::ActiveTicketsInQueue --search-arg general \ + --action RT::Action::EscalatePriority + +=head1 DESCRIPTION + +This script is a tool to act on tickets from an external scheduling tool, such +as cron. + +Security: + +This tool allows the user to run arbitrary perl modules from within RT. If +this tool were setgid, a hostile local user could use this tool to gain +administrative access to RT. It is incredibly important that nonprivileged +users not be allowed to run this tool. It is suggested that you create a +non-privileged unix user with the correct group membership and RT access to +run this tool. + + +=head1 OPTIONS + +=over + +=item search + +Specify the search module you want to use + +=item search-arg + +An argument to pass to --search + +=item condition + +Specify the condition module you want to use + +=item condition-arg + +An argument to pass to --condition + +=item action + +Specify the action module you want to use + +=item action-arg + +An argument to pass to --action + +=item template + +Specify name or id of template(s) you want to use + +=item transaction + +Specify if you want to use either 'first', 'last' or 'all' transactions + + +=item transaction-type + +Specify the comma separated list of transactions' types you want to use + +=item log + +Adjust LogToScreen config option + +=item verbose + +Output status updates to STDOUT + +=back + diff --git a/rt/bin/rt-crontool.in b/rt/bin/rt-crontool.in index 459ebf3..86251a3 100644 --- a/rt/bin/rt-crontool.in +++ b/rt/bin/rt-crontool.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -120,7 +120,7 @@ my $CurrentUser = GetCurrentUser(); help() if $help; unless ( $CurrentUser->Id ) { - print loc("No RT user found. Please consult your RT administrator.\n"); + print loc("No RT user found. Please consult your RT administrator."); exit(1); } @@ -166,7 +166,7 @@ my $tickets = $search->TicketsObj; #for each ticket we've found while ( my $ticket = $tickets->Next() ) { - print $ticket->Id() . ": " if ($verbose); + print $ticket->Id() . ":\n" if ($verbose); my $template_obj = get_template( $ticket ); @@ -174,15 +174,15 @@ while ( my $ticket = $tickets->Next() ) { my $txns = get_transactions($ticket); my $found = 0; while ( my $txn = $txns->Next ) { - print loc("Using transaction #[_1]...", $txn->id) + print "\t".loc("Using transaction #[_1]...", $txn->id)."\n" if $verbose; process($ticket, $txn, $template_obj); $found = 1; } - print loc("Couldn't find suitable transaction, skipping") + print "\t".loc("Couldn't find suitable transaction, skipping")."\n" if $verbose && !$found; } else { - print loc("Processing without transaction, some conditions and actions may fail. Consider using --transaction argument") + print "\t".loc("Processing without transaction, some conditions and actions may fail. Consider using --transaction argument")."\n" if $verbose; process($ticket, undef, $template_obj); @@ -208,7 +208,7 @@ sub process { # if the condition doesn't apply, get out of here return unless $condition_obj->IsApplicable; - print loc("Condition matches...") if $verbose; + print "\t".loc("Condition matches...")."\n" if $verbose; } #prepare our action @@ -224,20 +224,20 @@ sub process { #if our preparation, move onto the next ticket return unless $action_obj->Prepare; - print loc("Action prepared...") if $verbose; + print "\t".loc("Action prepared...")."\n" if $verbose; #commit our action. return unless $action_obj->Commit; - print loc("Action committed.\n") if $verbose; + print "\t".loc("Action committed.")."\n" if $verbose; } -=head2 get_transactions - -Takes ticket and returns L<RT::Transactions> object with transactions -of the ticket according to command line arguments C<--transaction> -and <--transaction-type>. - -=cut +# =head2 get_transactions +# +# Takes ticket and returns L<RT::Transactions> object with transactions +# of the ticket according to command line arguments C<--transaction> +# and <--transaction-type>. +# +# =cut sub get_transactions { my $ticket = shift; @@ -258,11 +258,11 @@ sub get_transactions { return $txns; } -=head2 get_template - -Takes a ticket and returns a template according to command line options. - -=cut +# =head2 get_template +# +# Takes a ticket and returns a template according to command line options. +# +# =cut { my $cache = undef; sub get_template { @@ -273,7 +273,7 @@ sub get_template { # by id return $cache if $cache; - my $cache = RT::Template->new( $RT::SystemUser ); + my $cache = RT::Template->new( RT->SystemUser ); $cache->Load( $template ); die "Failed to load template '$template'" unless $cache->id; @@ -283,7 +283,7 @@ sub get_template { my $queue = $ticket->Queue; return $cache->{ $queue } if $cache->{ $queue }; - my $res = RT::Template->new( $RT::SystemUser ); + my $res = RT::Template->new( RT->SystemUser ); $res->LoadQueueTemplate( Queue => $queue, Name => $template ); unless ( $res->id ) { $res->LoadGlobalTemplate( $template ); @@ -293,13 +293,12 @@ sub get_template { return $cache->{ $queue } = $res; } } -# {{{ load_module - -=head2 load_module - -Loads a perl module, dying nicely if it can't find it. -=cut +# =head2 load_module +# +# Loads a perl module, dying nicely if it can't find it. +# +# =cut sub load_module { my $modname = shift; @@ -310,21 +309,18 @@ sub load_module { } -# }}} -# {{{ loc -=head2 loc LIST - -Localize this string, with the current user's currentuser object - -=cut +# =head2 loc LIST +# +# Localize this string, with the current user's currentuser object +# +# =cut sub loc { $CurrentUser->loc(@_); } -# }}} sub help { @@ -389,7 +385,7 @@ sub help { print loc("Escalate tickets"). "\n"; print " bin/rt-crontool \\\n"; print " --search RT::Search::ActiveTicketsInQueue --search-arg general \\\n"; - print " --action RT::Action::EscalatePriority\n"; + print" --action RT::Action::EscalatePriority\n"; @@ -398,3 +394,90 @@ sub help { exit(0); } + +__END__ + +=head1 NAME + +rt-crontool - a tool to act on tickets from an external scheduling tool + +=head1 SYNOPSIS + + # find all active tickets in the queue 'general' and set their priority to 99 if they are overdue: + rt-crontool \ + --search RT::Search::ActiveTicketsInQueue --search-arg general \ + --condition RT::Condition::Overdue \ + --action RT::Action::SetPriority --action-arg 99 \ + --verbose + + # Escalate tickets + rt-crontool \ + --search RT::Search::ActiveTicketsInQueue --search-arg general \ + --action RT::Action::EscalatePriority + +=head1 DESCRIPTION + +This script is a tool to act on tickets from an external scheduling tool, such +as cron. + +Security: + +This tool allows the user to run arbitrary perl modules from within RT. If +this tool were setgid, a hostile local user could use this tool to gain +administrative access to RT. It is incredibly important that nonprivileged +users not be allowed to run this tool. It is suggested that you create a +non-privileged unix user with the correct group membership and RT access to +run this tool. + + +=head1 OPTIONS + +=over + +=item search + +Specify the search module you want to use + +=item search-arg + +An argument to pass to --search + +=item condition + +Specify the condition module you want to use + +=item condition-arg + +An argument to pass to --condition + +=item action + +Specify the action module you want to use + +=item action-arg + +An argument to pass to --action + +=item template + +Specify name or id of template(s) you want to use + +=item transaction + +Specify if you want to use either 'first', 'last' or 'all' transactions + + +=item transaction-type + +Specify the comma separated list of transactions' types you want to use + +=item log + +Adjust LogToScreen config option + +=item verbose + +Output status updates to STDOUT + +=back + diff --git a/rt/bin/rt-mailgate b/rt/bin/rt-mailgate index de0529d..98da587 100755 --- a/rt/bin/rt-mailgate +++ b/rt/bin/rt-mailgate @@ -1,9 +1,9 @@ -#!/usr/bin/perl -w +#!/usr/bin/perl # BEGIN BPS TAGGED BLOCK {{{ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -48,7 +48,7 @@ # END BPS TAGGED BLOCK }}} =head1 NAME -rt-mailgate - Mail interface to RT3. +rt-mailgate - Mail interface to RT. =cut @@ -56,85 +56,186 @@ use strict; use warnings; use Getopt::Long; + +my $opts = { }; +GetOptions( $opts, "queue=s", "action=s", "url=s", + "jar=s", "help", "debug", "extension=s", + "timeout=i", "verify-ssl!", "ca-file=s", + ); + +my $gateway = RT::Client::MailGateway->new(); + +$gateway->run($opts); + +package RT::Client::MailGateway; + use LWP::UserAgent; use HTTP::Request::Common qw($DYNAMIC_FILE_UPLOAD); +use File::Temp qw(tempfile tempdir); $DYNAMIC_FILE_UPLOAD = 1; use constant EX_TEMPFAIL => 75; use constant BUFFER_SIZE => 8192; -my %opts; -GetOptions( \%opts, "queue=s", "action=s", "url=s", "jar=s", "help", "debug", "extension=s", "timeout=i" ); +sub new { + my $class = shift; + my $self = bless {}, $class; + return $self; +} + +sub run { + my $self = shift; + my $opts = shift; + + if ( $opts->{running_in_test_harness} ) { + $self->{running_in_test_harness} = 1; + } + + $self->validate_cli_flags($opts); + + my $ua = $self->get_useragent($opts); + my $post_params = $self->setup_session($opts); + $self->upload_message( $ua => $post_params ); + $self->exit_with_success(); +} + +sub exit_with_success { + my $self = shift; + if ( $self->{running_in_test_harness} ) { + return 1; + } else { + exit 0; + } +} + +sub tempfail { + my $self = shift; + if ( $self->{running_in_test_harness} ) { + die "tempfail"; + } else { -if ( $opts{'help'} ) { - require Pod::Usage; - import Pod::Usage; - pod2usage("RT Mail Gateway\n"); - exit 1; # Don't want to succeed if this is really an email! + exit EX_TEMPFAIL; + } } -unless ( $opts{'url'} ) { - print STDERR "$0 invoked improperly\n\nNo 'url' provided to mail gateway!\n"; - exit 1; +sub permfail { + my $self = shift; + if ( $self->{running_in_test_harness} ) { + die "permfail"; + } else { + + exit 1; + } } -my $ua = new LWP::UserAgent; -$ua->cookie_jar( { file => $opts{'jar'} } ) if $opts{'jar'}; - -my %args = ( - SessionType => 'REST', # Surpress login box -); -foreach ( qw(queue action) ) { - $args{$_} = $opts{$_} if defined $opts{$_}; -}; - -if ( ($opts{'extension'} || '') =~ /^(?:action|queue|ticket)$/i ) { - $args{ lc $opts{'extension'} } = $ENV{'EXTENSION'} || $opts{$opts{'extension'}}; -} elsif ( $opts{'extension'} && $ENV{'EXTENSION'} ) { - print STDERR "Value of the --extension argument is not action, queue or ticket" - .", but environment variable EXTENSION is also defined. The former is ignored.\n"; +sub validate_cli_flags { + my $self = shift; + my $opts = shift; + if ( $opts->{'help'} ) { + require Pod::Usage; + Pod::Usage::pod2usage( { verbose => 2 } ); + return $self->permfail() + ; # Don't want to succeed if this is really an email! + } + + unless ( $opts->{'url'} ) { + print STDERR + "$0 invoked improperly\n\nNo 'url' provided to mail gateway!\n"; + return $self->permfail(); + } + + if (($opts->{'ca-file'} or $opts->{"verify-ssl"}) + and not LWP::UserAgent->can("ssl_opts")) { + print STDERR "Verifying SSL certificates requires LWP::UserAgent 6.0 or higher.\n"; + return $self->tempfail(); + } + + $opts->{"verify-ssl"} = 1 unless defined $opts->{"verify-ssl"}; } -# add ENV{'EXTENSION'} as X-RT-MailExtension to the message header -if ( my $value = ( $ENV{'EXTENSION'} || $opts{'extension'} ) ) { - # prepare value to avoid MIME format breakage - # strip trailing newline symbols - $value =~ s/(\r*\n)+$//; - # make a correct multiline header field, - # with tabs in the beginning of each line - $value =~ s/(\r*\n)/$1\t/g; - $opts{'headers'} .= "X-RT-Mail-Extension: $value\n"; +sub get_useragent { + my $self = shift; + my $opts = shift; + my $ua = LWP::UserAgent->new(); + $ua->cookie_jar( { file => $opts->{'jar'} } ) if $opts->{'jar'}; + + if ( $ua->can("ssl_opts") ) { + $ua->ssl_opts( verify_hostname => $opts->{'verify-ssl'} ); + $ua->ssl_opts( SSL_ca_file => $opts->{'ca-file'} ) + if $opts->{'ca-file'}; + } + + return $ua; } -# Read the message in from STDIN -my %message = write_down_message(); -unless( $message{'filename'} ) { - $args{'message'} = [ - undef, '', - 'Content-Type' => 'application/octet-stream', - Content => ${ $message{'content'} }, - ]; -} else { - $args{'message'} = [ - $message{'filename'}, '', - 'Content-Type' => 'application/octet-stream', - ]; +sub setup_session { + my $self = shift; + my $opts = shift; + my %post_params; + $post_params{SessionType} = 'REST'; # Surpress login box + foreach (qw(queue action)) { + $post_params{$_} = $opts->{$_} if defined $opts->{$_}; + } + + if ( ( $opts->{'extension'} || '' ) =~ /^(?:action|queue|ticket)$/i ) { + $post_params{ lc $opts->{'extension'} } = $ENV{'EXTENSION'} + || $opts->{ $opts->{'extension'} }; + } elsif ( $opts->{'extension'} && $ENV{'EXTENSION'} ) { + print STDERR + "Value of the --extension argument is not action, queue or ticket" + . ", but environment variable EXTENSION is also defined. The former is ignored.\n"; + } + + # add ENV{'EXTENSION'} as X-RT-MailExtension to the message header + if ( my $value = ( $ENV{'EXTENSION'} || $opts->{'extension'} ) ) { + + # prepare value to avoid MIME format breakage + # strip trailing newline symbols + $value =~ s/(\r*\n)+$//; + + # make a correct multiline header field, + # with tabs in the beginning of each line + $value =~ s/(\r*\n)/$1\t/g; + $opts->{'headers'} .= "X-RT-Mail-Extension: $value\n"; + } + + # Read the message in from STDIN + # _raw_message is used for testing + my $message = $opts->{'_raw_message'} || $self->slurp_message(); + unless ( $message->{'filename'} ) { + $post_params{'message'} = [ + undef, '', + 'Content-Type' => 'application/octet-stream', + Content => ${ $message->{'content'} }, + ]; + } else { + $post_params{'message'} = [ + $message->{'filename'}, '', + 'Content-Type' => 'application/octet-stream', + ]; + } + + return \%post_params; } -my $full_url = $opts{'url'}. "/REST/1.0/NoAuth/mail-gateway"; -print STDERR "$0: connecting to $full_url\n" if $opts{'debug'}; +sub upload_message { + my $self = shift; + my $ua = shift; + my $post_params = shift; + my $full_url = $opts->{'url'} . "/REST/1.0/NoAuth/mail-gateway"; + print STDERR "$0: connecting to $full_url\n" if $opts->{'debug'}; -$ua->timeout( exists( $opts{'timeout'} )? $opts{'timeout'}: 180 ); -my $r = $ua->post( $full_url, \%args, Content_Type => 'form-data' ); -check_failure($r); + $ua->timeout( exists( $opts->{'timeout'} ) ? $opts->{'timeout'} : 180 ); + my $r = $ua->post( $full_url, $post_params, Content_Type => 'form-data' ); + $self->check_failure($r); -my $content = $r->content; -print STDERR $content ."\n" if $opts{'debug'}; + my $content = $r->content; + print STDERR $content . "\n" if $opts->{'debug'}; -if ( $content !~ /^(ok|not ok)/ ) { + return if ( $content =~ /^(ok|not ok)/ ); - # It's not the server's fault if the mail is bogus. We just want to know that - # *something* came out of the server. + # It's not the server's fault if the mail is bogus. We just want to know that + # *something* came out of the server. print STDERR <<EOF; RT server error. @@ -144,18 +245,12 @@ said: $content EOF - exit EX_TEMPFAIL; -} - -exit; - -END { - unlink $message{'filename'} if $message{'filename'}; + return $self->tempfail(); } - sub check_failure { - my $r = shift; + my $self = shift; + my $r = shift; return if $r->is_success; # This ordinarily oughtn't to be able to happen, suggests a bug in RT. @@ -164,65 +259,67 @@ sub check_failure { require HTML::FormatText; my $error = $r->error_as_HTML; - my $tree = HTML::TreeBuilder->new->parse( $error ); + my $tree = HTML::TreeBuilder->new->parse($error); $tree->eof; # It'll be a cold day in hell before RT sends out bounces in HTML - my $formatter = HTML::FormatText->new( - leftmargin => 0, - rightmargin => 50, - ); - print STDERR $formatter->format( $tree ); - print STDERR "\n$0: undefined server error\n" if $opts{'debug'}; - exit EX_TEMPFAIL; + my $formatter = + HTML::FormatText->new( leftmargin => 0, + rightmargin => 50, ); + print STDERR $formatter->format($tree); + print STDERR "\n$0: undefined server error\n" if $opts->{'debug'}; + return $self->tempfail(); } -sub write_down_message { - use File::Temp qw(tempfile); +sub slurp_message { + my $self = shift; local $@; - my ($fh, $filename) = eval { tempfile() }; + + my %message; + my ( $fh, $filename ) + = eval { tempfile( DIR => tempdir( CLEANUP => 1 ) ) }; if ( !$fh || $@ ) { print STDERR "$0: Couldn't create temp file, using memory\n"; print STDERR "error: $@\n" if $@; - my $message = \do { local (@ARGV, $/); <STDIN> }; + my $message = \do { local ( @ARGV, $/ ); <STDIN> }; unless ( $$message =~ /\S/ ) { print STDERR "$0: no message passed on STDIN\n"; - exit 0; + $self->exit_with_success; } - $$message = $opts{'headers'} . $$message if $opts{'headers'}; - return ( content => $message ); + $$message = $opts->{'headers'} . $$message if $opts->{'headers'}; + return ( { content => $message } ); } binmode $fh; binmode \*STDIN; - - print $fh $opts{'headers'} if $opts{'headers'}; - my $buf; my $empty = 1; - while(1) { + print $fh $opts->{'headers'} if $opts->{'headers'}; + + my $buf; + my $empty = 1; + while (1) { my $status = read \*STDIN, $buf, BUFFER_SIZE; unless ( defined $status ) { print STDERR "$0: couldn't read message: $!\n"; - exit EX_TEMPFAIL; + return $self->tempfail(); } elsif ( !$status ) { last; } $empty = 0 if $buf =~ /\S/; print $fh $buf; - }; + } close $fh; - if ( $empty ) { + if ($empty) { print STDERR "$0: no message passed on STDIN\n"; - exit 0; + $self->exit_with_success; } - print STDERR "$0: temp file is '$filename'\n" if $opts{'debug'}; - return (filename => $filename); + print STDERR "$0: temp file is '$filename'\n" if $opts->{'debug'}; + return ( { filename => $filename } ); } - =head1 SYNOPSIS rt-mailgate --help : this text @@ -267,8 +364,34 @@ is found. =item C<--url> This flag tells the mail gateway where it can find your RT server. You should -probably use the same URL that users use to log into RT. +probably use the same URL that users use to log into RT. +If your RT server uses SSL, you will need to install additional Perl +libraries. RT will detect and install these dependencies if you pass the +C<--enable-ssl-mailgate> flag to configure as documented in RT's README. + +If you have a self-signed SSL certificate, you may also need to pass +C<--ca-file> or C<--no-verify-ssl>, below. + +=item C<--ca-file> I<path> + +Specifies the path to the public SSL certificate for the certificate +authority that should be used to verify the website's SSL certificate. +If your webserver uses a self-signed certificate, you should +preferentially use this option over C<--no-verify-ssl>, as it will +ensure that the self-signed certificate that the mailgate is seeing the +I<right> self-signed certificate. + +=item C<--no-verify-ssl> + +This flag tells the mail gateway to trust all SSL certificates, +regardless of if their hostname matches the certificate, and regardless +of CA. This is required if you have a self-signed certificate, or some +other certificate which is not traceable back to an certificate your +system ultimitely trusts. + +Verifying SSL certificates requires L<LWP::UserAgent> version 6.0 or +higher; explicitly passing C<--verify-ssl> on prior versions will error. =item C<--extension> OPTIONAL @@ -290,6 +413,8 @@ Print debugging output to standard error Configure the timeout for posting the message to the web server. The default timeout is 3 minutes (180 seconds). +=back + =head1 DESCRIPTION @@ -312,10 +437,10 @@ Next, you need to route mail to C<rt-mailgate> for the queues you're monitoring. For instance, if you're using F</etc/aliases> and you have a "bugs" queue, you will want something like this: - bugs: "|/opt/rt3/bin/rt-mailgate --queue bugs --action correspond + bugs: "|/opt/rt4/bin/rt-mailgate --queue bugs --action correspond --url http://rt.mycorp.com/" - bugs-comment: "|/opt/rt3/bin/rt-mailgate --queue bugs --action comment + bugs-comment: "|/opt/rt4/bin/rt-mailgate --queue bugs --action comment --url http://rt.mycorp.com/" Note that you don't have to run your RT server on your mail server, as @@ -379,7 +504,7 @@ If we don't already have a ticket id, we need to know which queue we're talking The action being performed. At the moment, it's one of "comment" or "correspond" -=back 4 +=back It returns two values, the new C<RT::CurrentUser> object, and the new authentication level. The authentication level can be zero, not allowed @@ -403,7 +528,7 @@ See also C<--extension> option. Note that value of the environment variable is always added to the message header when it's not empty even if C<--extension> option is not provided. -=back 4 +=back =cut diff --git a/rt/bin/rt-mailgate.in b/rt/bin/rt-mailgate.in index a74b2da..b125a94 100644 --- a/rt/bin/rt-mailgate.in +++ b/rt/bin/rt-mailgate.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -48,7 +48,7 @@ # END BPS TAGGED BLOCK }}} =head1 NAME -rt-mailgate - Mail interface to RT3. +rt-mailgate - Mail interface to RT. =cut @@ -56,85 +56,186 @@ use strict; use warnings; use Getopt::Long; + +my $opts = { }; +GetOptions( $opts, "queue=s", "action=s", "url=s", + "jar=s", "help", "debug", "extension=s", + "timeout=i", "verify-ssl!", "ca-file=s", + ); + +my $gateway = RT::Client::MailGateway->new(); + +$gateway->run($opts); + +package RT::Client::MailGateway; + use LWP::UserAgent; use HTTP::Request::Common qw($DYNAMIC_FILE_UPLOAD); +use File::Temp qw(tempfile tempdir); $DYNAMIC_FILE_UPLOAD = 1; use constant EX_TEMPFAIL => 75; use constant BUFFER_SIZE => 8192; -my %opts; -GetOptions( \%opts, "queue=s", "action=s", "url=s", "jar=s", "help", "debug", "extension=s", "timeout=i" ); +sub new { + my $class = shift; + my $self = bless {}, $class; + return $self; +} + +sub run { + my $self = shift; + my $opts = shift; + + if ( $opts->{running_in_test_harness} ) { + $self->{running_in_test_harness} = 1; + } + + $self->validate_cli_flags($opts); + + my $ua = $self->get_useragent($opts); + my $post_params = $self->setup_session($opts); + $self->upload_message( $ua => $post_params ); + $self->exit_with_success(); +} + +sub exit_with_success { + my $self = shift; + if ( $self->{running_in_test_harness} ) { + return 1; + } else { + exit 0; + } +} + +sub tempfail { + my $self = shift; + if ( $self->{running_in_test_harness} ) { + die "tempfail"; + } else { -if ( $opts{'help'} ) { - require Pod::Usage; - import Pod::Usage; - pod2usage("RT Mail Gateway\n"); - exit 1; # Don't want to succeed if this is really an email! + exit EX_TEMPFAIL; + } } -unless ( $opts{'url'} ) { - print STDERR "$0 invoked improperly\n\nNo 'url' provided to mail gateway!\n"; - exit 1; +sub permfail { + my $self = shift; + if ( $self->{running_in_test_harness} ) { + die "permfail"; + } else { + + exit 1; + } } -my $ua = new LWP::UserAgent; -$ua->cookie_jar( { file => $opts{'jar'} } ) if $opts{'jar'}; - -my %args = ( - SessionType => 'REST', # Surpress login box -); -foreach ( qw(queue action) ) { - $args{$_} = $opts{$_} if defined $opts{$_}; -}; - -if ( ($opts{'extension'} || '') =~ /^(?:action|queue|ticket)$/i ) { - $args{ lc $opts{'extension'} } = $ENV{'EXTENSION'} || $opts{$opts{'extension'}}; -} elsif ( $opts{'extension'} && $ENV{'EXTENSION'} ) { - print STDERR "Value of the --extension argument is not action, queue or ticket" - .", but environment variable EXTENSION is also defined. The former is ignored.\n"; +sub validate_cli_flags { + my $self = shift; + my $opts = shift; + if ( $opts->{'help'} ) { + require Pod::Usage; + Pod::Usage::pod2usage( { verbose => 2 } ); + return $self->permfail() + ; # Don't want to succeed if this is really an email! + } + + unless ( $opts->{'url'} ) { + print STDERR + "$0 invoked improperly\n\nNo 'url' provided to mail gateway!\n"; + return $self->permfail(); + } + + if (($opts->{'ca-file'} or $opts->{"verify-ssl"}) + and not LWP::UserAgent->can("ssl_opts")) { + print STDERR "Verifying SSL certificates requires LWP::UserAgent 6.0 or higher.\n"; + return $self->tempfail(); + } + + $opts->{"verify-ssl"} = 1 unless defined $opts->{"verify-ssl"}; } -# add ENV{'EXTENSION'} as X-RT-MailExtension to the message header -if ( my $value = ( $ENV{'EXTENSION'} || $opts{'extension'} ) ) { - # prepare value to avoid MIME format breakage - # strip trailing newline symbols - $value =~ s/(\r*\n)+$//; - # make a correct multiline header field, - # with tabs in the beginning of each line - $value =~ s/(\r*\n)/$1\t/g; - $opts{'headers'} .= "X-RT-Mail-Extension: $value\n"; +sub get_useragent { + my $self = shift; + my $opts = shift; + my $ua = LWP::UserAgent->new(); + $ua->cookie_jar( { file => $opts->{'jar'} } ) if $opts->{'jar'}; + + if ( $ua->can("ssl_opts") ) { + $ua->ssl_opts( verify_hostname => $opts->{'verify-ssl'} ); + $ua->ssl_opts( SSL_ca_file => $opts->{'ca-file'} ) + if $opts->{'ca-file'}; + } + + return $ua; } -# Read the message in from STDIN -my %message = write_down_message(); -unless( $message{'filename'} ) { - $args{'message'} = [ - undef, '', - 'Content-Type' => 'application/octet-stream', - Content => ${ $message{'content'} }, - ]; -} else { - $args{'message'} = [ - $message{'filename'}, '', - 'Content-Type' => 'application/octet-stream', - ]; +sub setup_session { + my $self = shift; + my $opts = shift; + my %post_params; + $post_params{SessionType} = 'REST'; # Surpress login box + foreach (qw(queue action)) { + $post_params{$_} = $opts->{$_} if defined $opts->{$_}; + } + + if ( ( $opts->{'extension'} || '' ) =~ /^(?:action|queue|ticket)$/i ) { + $post_params{ lc $opts->{'extension'} } = $ENV{'EXTENSION'} + || $opts->{ $opts->{'extension'} }; + } elsif ( $opts->{'extension'} && $ENV{'EXTENSION'} ) { + print STDERR + "Value of the --extension argument is not action, queue or ticket" + . ", but environment variable EXTENSION is also defined. The former is ignored.\n"; + } + + # add ENV{'EXTENSION'} as X-RT-MailExtension to the message header + if ( my $value = ( $ENV{'EXTENSION'} || $opts->{'extension'} ) ) { + + # prepare value to avoid MIME format breakage + # strip trailing newline symbols + $value =~ s/(\r*\n)+$//; + + # make a correct multiline header field, + # with tabs in the beginning of each line + $value =~ s/(\r*\n)/$1\t/g; + $opts->{'headers'} .= "X-RT-Mail-Extension: $value\n"; + } + + # Read the message in from STDIN + # _raw_message is used for testing + my $message = $opts->{'_raw_message'} || $self->slurp_message(); + unless ( $message->{'filename'} ) { + $post_params{'message'} = [ + undef, '', + 'Content-Type' => 'application/octet-stream', + Content => ${ $message->{'content'} }, + ]; + } else { + $post_params{'message'} = [ + $message->{'filename'}, '', + 'Content-Type' => 'application/octet-stream', + ]; + } + + return \%post_params; } -my $full_url = $opts{'url'}. "/REST/1.0/NoAuth/mail-gateway"; -print STDERR "$0: connecting to $full_url\n" if $opts{'debug'}; +sub upload_message { + my $self = shift; + my $ua = shift; + my $post_params = shift; + my $full_url = $opts->{'url'} . "/REST/1.0/NoAuth/mail-gateway"; + print STDERR "$0: connecting to $full_url\n" if $opts->{'debug'}; -$ua->timeout( exists( $opts{'timeout'} )? $opts{'timeout'}: 180 ); -my $r = $ua->post( $full_url, \%args, Content_Type => 'form-data' ); -check_failure($r); + $ua->timeout( exists( $opts->{'timeout'} ) ? $opts->{'timeout'} : 180 ); + my $r = $ua->post( $full_url, $post_params, Content_Type => 'form-data' ); + $self->check_failure($r); -my $content = $r->content; -print STDERR $content ."\n" if $opts{'debug'}; + my $content = $r->content; + print STDERR $content . "\n" if $opts->{'debug'}; -if ( $content !~ /^(ok|not ok)/ ) { + return if ( $content =~ /^(ok|not ok)/ ); - # It's not the server's fault if the mail is bogus. We just want to know that - # *something* came out of the server. + # It's not the server's fault if the mail is bogus. We just want to know that + # *something* came out of the server. print STDERR <<EOF; RT server error. @@ -144,18 +245,12 @@ said: $content EOF - exit EX_TEMPFAIL; -} - -exit; - -END { - unlink $message{'filename'} if $message{'filename'}; + return $self->tempfail(); } - sub check_failure { - my $r = shift; + my $self = shift; + my $r = shift; return if $r->is_success; # This ordinarily oughtn't to be able to happen, suggests a bug in RT. @@ -164,65 +259,67 @@ sub check_failure { require HTML::FormatText; my $error = $r->error_as_HTML; - my $tree = HTML::TreeBuilder->new->parse( $error ); + my $tree = HTML::TreeBuilder->new->parse($error); $tree->eof; # It'll be a cold day in hell before RT sends out bounces in HTML - my $formatter = HTML::FormatText->new( - leftmargin => 0, - rightmargin => 50, - ); - print STDERR $formatter->format( $tree ); - print STDERR "\n$0: undefined server error\n" if $opts{'debug'}; - exit EX_TEMPFAIL; + my $formatter = + HTML::FormatText->new( leftmargin => 0, + rightmargin => 50, ); + print STDERR $formatter->format($tree); + print STDERR "\n$0: undefined server error\n" if $opts->{'debug'}; + return $self->tempfail(); } -sub write_down_message { - use File::Temp qw(tempfile); +sub slurp_message { + my $self = shift; local $@; - my ($fh, $filename) = eval { tempfile() }; + + my %message; + my ( $fh, $filename ) + = eval { tempfile( DIR => tempdir( CLEANUP => 1 ) ) }; if ( !$fh || $@ ) { print STDERR "$0: Couldn't create temp file, using memory\n"; print STDERR "error: $@\n" if $@; - my $message = \do { local (@ARGV, $/); <STDIN> }; + my $message = \do { local ( @ARGV, $/ ); <STDIN> }; unless ( $$message =~ /\S/ ) { print STDERR "$0: no message passed on STDIN\n"; - exit 0; + $self->exit_with_success; } - $$message = $opts{'headers'} . $$message if $opts{'headers'}; - return ( content => $message ); + $$message = $opts->{'headers'} . $$message if $opts->{'headers'}; + return ( { content => $message } ); } binmode $fh; binmode \*STDIN; - - print $fh $opts{'headers'} if $opts{'headers'}; - my $buf; my $empty = 1; - while(1) { + print $fh $opts->{'headers'} if $opts->{'headers'}; + + my $buf; + my $empty = 1; + while (1) { my $status = read \*STDIN, $buf, BUFFER_SIZE; unless ( defined $status ) { print STDERR "$0: couldn't read message: $!\n"; - exit EX_TEMPFAIL; + return $self->tempfail(); } elsif ( !$status ) { last; } $empty = 0 if $buf =~ /\S/; print $fh $buf; - }; + } close $fh; - if ( $empty ) { + if ($empty) { print STDERR "$0: no message passed on STDIN\n"; - exit 0; + $self->exit_with_success; } - print STDERR "$0: temp file is '$filename'\n" if $opts{'debug'}; - return (filename => $filename); + print STDERR "$0: temp file is '$filename'\n" if $opts->{'debug'}; + return ( { filename => $filename } ); } - =head1 SYNOPSIS rt-mailgate --help : this text @@ -267,8 +364,34 @@ is found. =item C<--url> This flag tells the mail gateway where it can find your RT server. You should -probably use the same URL that users use to log into RT. +probably use the same URL that users use to log into RT. +If your RT server uses SSL, you will need to install additional Perl +libraries. RT will detect and install these dependencies if you pass the +C<--enable-ssl-mailgate> flag to configure as documented in RT's README. + +If you have a self-signed SSL certificate, you may also need to pass +C<--ca-file> or C<--no-verify-ssl>, below. + +=item C<--ca-file> I<path> + +Specifies the path to the public SSL certificate for the certificate +authority that should be used to verify the website's SSL certificate. +If your webserver uses a self-signed certificate, you should +preferentially use this option over C<--no-verify-ssl>, as it will +ensure that the self-signed certificate that the mailgate is seeing the +I<right> self-signed certificate. + +=item C<--no-verify-ssl> + +This flag tells the mail gateway to trust all SSL certificates, +regardless of if their hostname matches the certificate, and regardless +of CA. This is required if you have a self-signed certificate, or some +other certificate which is not traceable back to an certificate your +system ultimitely trusts. + +Verifying SSL certificates requires L<LWP::UserAgent> version 6.0 or +higher; explicitly passing C<--verify-ssl> on prior versions will error. =item C<--extension> OPTIONAL @@ -290,6 +413,8 @@ Print debugging output to standard error Configure the timeout for posting the message to the web server. The default timeout is 3 minutes (180 seconds). +=back + =head1 DESCRIPTION @@ -312,10 +437,10 @@ Next, you need to route mail to C<rt-mailgate> for the queues you're monitoring. For instance, if you're using F</etc/aliases> and you have a "bugs" queue, you will want something like this: - bugs: "|/opt/rt3/bin/rt-mailgate --queue bugs --action correspond + bugs: "|/opt/rt4/bin/rt-mailgate --queue bugs --action correspond --url http://rt.mycorp.com/" - bugs-comment: "|/opt/rt3/bin/rt-mailgate --queue bugs --action comment + bugs-comment: "|/opt/rt4/bin/rt-mailgate --queue bugs --action comment --url http://rt.mycorp.com/" Note that you don't have to run your RT server on your mail server, as @@ -379,7 +504,7 @@ If we don't already have a ticket id, we need to know which queue we're talking The action being performed. At the moment, it's one of "comment" or "correspond" -=back 4 +=back It returns two values, the new C<RT::CurrentUser> object, and the new authentication level. The authentication level can be zero, not allowed @@ -403,7 +528,7 @@ See also C<--extension> option. Note that value of the environment variable is always added to the message header when it's not empty even if C<--extension> option is not provided. -=back 4 +=back =cut diff --git a/rt/bin/rt.in b/rt/bin/rt.in index aefe7af..5e1c053 100644 --- a/rt/bin/rt.in +++ b/rt/bin/rt.in @@ -3,7 +3,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC # <sales@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -51,6 +51,12 @@ use strict; +if ( $ARGV[0] && $ARGV[0] =~ /^(?:--help|-h)$/ ) { + require Pod::Usage; + print Pod::Usage::pod2usage( { verbose => 2 } ); + exit; +} + # This program is intentionally written to have as few non-core module # dependencies as possible. It should stay that way. @@ -98,7 +104,7 @@ my %config = ( config_from_file($ENV{RTCONFIG} || ".rtrc"), config_from_env() ); -my $session = new Session("$HOME/.rt_sessions"); +my $session = Session->new("$HOME/.rt_sessions"); my $REST = "$config{server}/REST/1.0"; $no_strong_auth = 'switched off by externalauth=0' if defined $config{externalauth}; @@ -179,7 +185,7 @@ exit handler(); sub shell { $|=1; - my $term = new Term::ReadLine 'RT CLI'; + my $term = Term::ReadLine->new('RT CLI'); while ( defined ($_ = $term->readline($prompt)) ) { next if /^#/ || /^\s*$/; @@ -984,7 +990,7 @@ sub grant { sub submit { my ($uri, $content) = @_; my ($req, $data); - my $ua = new LWP::UserAgent(agent => "RT/3.0b", env_proxy => 1); + my $ua = LWP::UserAgent->new(agent => "RT/3.0b", env_proxy => 1); my $h = HTTP::Headers->new; # Did the caller specify any data to send with the request? @@ -1164,44 +1170,40 @@ sub submit { sub load { my ($self, $file) = @_; $file ||= $self->{file}; - local *F; - - open(F, '<', $file) && do { - $self->{file} = $file; - my $sids = $self->{sids} = {}; - while (<F>) { - chomp; - next if /^$/ || /^#/; - next unless m#^https?://[^ ]+ \w+ [^;,\s]+=[0-9A-Fa-f]+$#; - my ($server, $user, $cookie) = split / /, $_; - $sids->{$server}{$user} = $cookie; - } - return 1; - }; - return 0; + + open( my $handle, '<', $file ) or return 0; + + $self->{file} = $file; + my $sids = $self->{sids} = {}; + while (<$handle>) { + chomp; + next if /^$/ || /^#/; + next unless m#^https?://[^ ]+ \w+ [^;,\s]+=[0-9A-Fa-f]+$#; + my ($server, $user, $cookie) = split / /, $_; + $sids->{$server}{$user} = $cookie; + } + return 1; } # Writes the current session cache to the specified file. sub save { my ($self, $file) = shift; $file ||= $self->{file}; - local *F; - - open(F, '>', $file) && do { - my $sids = $self->{sids}; - foreach my $server (keys %$sids) { - foreach my $user (keys %{ $sids->{$server} }) { - my $sid = $sids->{$server}{$user}; - if (defined $sid) { - print F "$server $user $sid\n"; - } + + open( my $handle, '>', "$file" ) or return 0; + + my $sids = $self->{sids}; + foreach my $server (keys %$sids) { + foreach my $user (keys %{ $sids->{$server} }) { + my $sid = $sids->{$server}{$user}; + if (defined $sid) { + print $handle "$server $user $sid\n"; } } - close(F); - chmod 0600, $file; - return 1; - }; - return 0; + } + close($handle); + chmod 0600, $file; + return 1; } sub DESTROY { @@ -1429,19 +1431,19 @@ sub parse_config_file { my ($file) = @_; local $_; # $_ may be aliased to a constant, from line 1163 - open(CFG, '<', $file) && do { - while (<CFG>) { - chomp; - next if (/^#/ || /^\s*$/); + open( my $handle, '<', $file ) or return; - if (/^(externalauth|user|passwd|server|query|orderby|queue)\s+(.*)\s?$/) { - $cfg{$1} = $2; - } - else { - die "rt: $file:$.: unknown configuration directive.\n"; - } + while (<$handle>) { + chomp; + next if (/^#/ || /^\s*$/); + + if (/^(externalauth|user|passwd|server|query|orderby|queue)\s+(.*)\s?$/) { + $cfg{$1} = $2; + } + else { + die "rt: $file:$.: unknown configuration directive.\n"; } - }; + } return %cfg; } @@ -1476,12 +1478,18 @@ sub vi { my $file = "/tmp/rt.form.$$"; my $editor = $ENV{EDITOR} || $ENV{VISUAL} || "vi"; - local *F; local $/ = undef; - open(F, '>', $file) or die "$file: $!\n"; print F $text; close(F); + open( my $handle, '>', $file ) or die "$file: $!\n"; + print $handle $text; + close($handle); + system($editor, $file) && die "Couldn't run $editor.\n"; - open(F, '<', $file) or die "$file: $!\n"; $text = <F>; close(F); + + open( $handle, '<', $file ) or die "$file: $!\n"; + $text = <$handle>; + close($handle); + unlink($file); return $text; @@ -2157,7 +2165,7 @@ Text: ("ls", "list", and "search" are synonyms.) Conditions are expressed in the SQL-like syntax used internally by - RT3. (For more information, see "rt help query".) The query string + RT. (For more information, see "rt help query".) The query string must be supplied as one argument. (Right now, the server doesn't support listing anything but tickets. @@ -2390,7 +2398,7 @@ Text: Title: query Text: - RT3 uses an SQL-like syntax to specify object selection constraints. + RT uses an SQL-like syntax to specify object selection constraints. See the <RT:...> documentation for details. (XXX: I'm going to have to write it, aren't I?) @@ -2585,3 +2593,24 @@ Text: $ rt shell rt> quit $ + +__END__ + +=head1 NAME + +rt - command-line interface to RT 3.0 or newer + +=head1 SYNOPSIS + + rt help + +=head1 DESCRIPTION + +This script allows you to interact with an RT server over HTTP, and offers an +interface to RT's functionality that is better-suited to automation and +integration with other tools. + +In general, each invocation of this program should specify an action to +perform on one or more objects, and any other arguments required to complete +the desired action. + diff --git a/rt/bin/standalone_httpd b/rt/bin/standalone_httpd deleted file mode 100755 index a307910..0000000 --- a/rt/bin/standalone_httpd +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/perl -w -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC -# <sales@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -use warnings; -use strict; - -# fix lib paths, some may be relative -BEGIN { - require File::Spec; - my @libs = ("lib", "local/lib"); - my $bin_path; - - for my $lib (@libs) { - unless ( File::Spec->file_name_is_absolute($lib) ) { - unless ($bin_path) { - if ( File::Spec->file_name_is_absolute(__FILE__) ) { - $bin_path = ( File::Spec->splitpath(__FILE__) )[1]; - } - else { - require FindBin; - no warnings "once"; - $bin_path = $FindBin::Bin; - } - } - $lib = File::Spec->catfile( $bin_path, File::Spec->updir, $lib ); - } - unshift @INC, $lib; - } - -} - -use RT; -RT::LoadConfig(); -RT->InitLogging(); -if (RT->Config->Get('DevelMode')) { require Module::Refresh; } - -RT::CheckPerlRequirements(); -RT->InitPluginPaths(); - -my $explicit_port = shift @ARGV; -my $port = $explicit_port || RT->Config->Get('WebPort') || '8080'; - - -require RT::Handle; -my ($integrity, $state, $msg) = RT::Handle->CheckIntegrity; - -unless ( $integrity ) { - print STDERR <<EOF; - -RT couldn't connect to the database where tickets are stored. -If this is a new installation of RT, you should visit the URL below -to configure RT and initialize your database. - -If this is an existing RT installation, this may indicate a database -connectivity problem. - -The error RT got back when trying to connect to your database was: - -$msg - -EOF - - require RT::Installer; - # don't enter install mode if the file exists but is unwritable - if (-e RT::Installer->ConfigFile && !-w _) { - die 'Since your configuration exists (' - . RT::Installer->ConfigFile - . ") but is not writable, I'm refusing to do anything.\n"; - } - - RT->Config->Set( 'LexiconLanguages' => '*' ); - RT::I18N->Init; - - RT->InstallMode(1); -} else { - RT->ConnectToDatabase(); - RT->InitSystemObjects(); - RT->InitClasses( Heavy => 1 ); - RT->InitPlugins(); - RT->Config->PostLoadCheck(); - - my ($status, $msg) = RT::Handle->CheckCompatibility( - $RT::Handle->dbh, 'post' - ); - unless ( $status ) { - print STDERR $msg, "\n\n"; - exit -1; - } -} - -require RT::Interface::Web::Standalone; -my $server = RT::Interface::Web::Standalone->new; -run_server($port); -exit 0; - -sub run_server { - my $port = shift; - $server->port($port); - eval { $server->run() }; - - if ( my $err = $@ ) { - handle_startup_error($err); - } -} - -sub handle_startup_error { - my $err = shift; - if ( $err =~ /bind: Permission denied/ ) { - handle_bind_error(); - } else { - die - "Something went wrong while trying to run RT's standalone web server:\n\t" - . $err; - } -} - - -sub handle_bind_error { - - print STDERR <<EOF; -WARNING: RT couldn't start up a web server on port @{[$port]}. -This is often the case if you're running @{[$0]} as -someone other than your system's "root" user. -EOF - - if ($explicit_port) { - print STDERR - "Please check your system configuration or choose another port\n\n"; - } else { - print STDERR "\nFor now, RT has chosen an alternate port to run on.\n\n"; - if ( !$integrity ) { - print STDERR <<EOF; -You can use this server to configure and explore RT. While configuring -RT, you'll have a chance to set a permanent port and URL for your -server. - -EOF - } - run_server( 8000 + int( rand(1024) ) ); - } -} diff --git a/rt/bin/standalone_httpd.in b/rt/bin/standalone_httpd.in deleted file mode 100755 index 8c8c1ae..0000000 --- a/rt/bin/standalone_httpd.in +++ /dev/null @@ -1,186 +0,0 @@ -#!@PERL@ -w -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC -# <sales@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -use warnings; -use strict; - -# fix lib paths, some may be relative -BEGIN { - require File::Spec; - my @libs = ("@RT_LIB_PATH@", "@LOCAL_LIB_PATH@"); - my $bin_path; - - for my $lib (@libs) { - unless ( File::Spec->file_name_is_absolute($lib) ) { - unless ($bin_path) { - if ( File::Spec->file_name_is_absolute(__FILE__) ) { - $bin_path = ( File::Spec->splitpath(__FILE__) )[1]; - } - else { - require FindBin; - no warnings "once"; - $bin_path = $FindBin::Bin; - } - } - $lib = File::Spec->catfile( $bin_path, File::Spec->updir, $lib ); - } - unshift @INC, $lib; - } - -} - -use RT; -RT::LoadConfig(); -RT->InitLogging(); -if (RT->Config->Get('DevelMode')) { require Module::Refresh; } - -RT::CheckPerlRequirements(); -RT->InitPluginPaths(); - -my $explicit_port = shift @ARGV; -my $port = $explicit_port || RT->Config->Get('WebPort') || '8080'; - - -require RT::Handle; -my ($integrity, $state, $msg) = RT::Handle->CheckIntegrity; - -unless ( $integrity ) { - print STDERR <<EOF; - -RT couldn't connect to the database where tickets are stored. -If this is a new installation of RT, you should visit the URL below -to configure RT and initialize your database. - -If this is an existing RT installation, this may indicate a database -connectivity problem. - -The error RT got back when trying to connect to your database was: - -$msg - -EOF - - require RT::Installer; - # don't enter install mode if the file exists but is unwritable - if (-e RT::Installer->ConfigFile && !-w _) { - die 'Since your configuration exists (' - . RT::Installer->ConfigFile - . ") but is not writable, I'm refusing to do anything.\n"; - } - - RT->Config->Set( 'LexiconLanguages' => '*' ); - RT::I18N->Init; - - RT->InstallMode(1); -} else { - RT->ConnectToDatabase(); - RT->InitSystemObjects(); - RT->InitClasses( Heavy => 1 ); - RT->InitPlugins(); - RT->Config->PostLoadCheck(); - - my ($status, $msg) = RT::Handle->CheckCompatibility( - $RT::Handle->dbh, 'post' - ); - unless ( $status ) { - print STDERR $msg, "\n\n"; - exit -1; - } -} - -require RT::Interface::Web::Standalone; -my $server = RT::Interface::Web::Standalone->new; -run_server($port); -exit 0; - -sub run_server { - my $port = shift; - $server->port($port); - eval { $server->run() }; - - if ( my $err = $@ ) { - handle_startup_error($err); - } -} - -sub handle_startup_error { - my $err = shift; - if ( $err =~ /bind: Permission denied/ ) { - handle_bind_error(); - } else { - die - "Something went wrong while trying to run RT's standalone web server:\n\t" - . $err; - } -} - - -sub handle_bind_error { - - print STDERR <<EOF; -WARNING: RT couldn't start up a web server on port @{[$port]}. -This is often the case if you're running @{[$0]} as -someone other than your system's "root" user. -EOF - - if ($explicit_port) { - print STDERR - "Please check your system configuration or choose another port\n\n"; - } else { - print STDERR "\nFor now, RT has chosen an alternate port to run on.\n\n"; - if ( !$integrity ) { - print STDERR <<EOF; -You can use this server to configure and explore RT. While configuring -RT, you'll have a chance to set a permanent port and URL for your -server. - -EOF - } - run_server( 8000 + int( rand(1024) ) ); - } -} diff --git a/rt/bin/webmux.pl.in b/rt/bin/webmux.pl.in deleted file mode 100644 index 7aae041..0000000 --- a/rt/bin/webmux.pl.in +++ /dev/null @@ -1,205 +0,0 @@ -#!@PERL@ -# BEGIN BPS TAGGED BLOCK {{{ -# -# COPYRIGHT: -# -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC -# <sales@bestpractical.com> -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: -# -# This work is made available to you under the terms of Version 2 of -# the GNU General Public License. A copy of that license should have -# been provided with this software, but in any event can be snarfed -# from www.gnu.org. -# -# This work is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# -# CONTRIBUTION SUBMISSION POLICY: -# -# (The following paragraph is not intended to limit the rights granted -# to you to modify and distribute this software under the terms of -# the GNU General Public License and is only of importance to you if -# you choose to contribute your changes and enhancements to the -# community by submitting them to Best Practical Solutions, LLC.) -# -# By intentionally submitting any modifications, corrections or -# derivatives to this work, or any other work intended for use with -# Request Tracker, to Best Practical Solutions, LLC, you confirm that -# you are the copyright holder for those contributions and you grant -# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, -# royalty-free, perpetual, license to use, copy, create derivative -# works based on those contributions, and sublicense and distribute -# those contributions and any derivatives thereof. -# -# END BPS TAGGED BLOCK }}} -use strict; -local $ENV{'PATH'} = '/bin:/usr/bin'; # or whatever you need -local $ENV{'CDPATH'} = '' if defined $ENV{'CDPATH'}; -local $ENV{'SHELL'} = '/bin/sh' if defined $ENV{'SHELL'}; -local $ENV{'ENV'} = '' if defined $ENV{'ENV'}; -local $ENV{'IFS'} = '' if defined $ENV{'IFS'}; - -package HTML::Mason::Commands; -our %session; - -package RT::Mason; - -our ($Nobody, $SystemUser, $Handler, $r); - -my $protect_fd; - -sub handler { - ($r) = @_; - - if ( !$protect_fd && $ENV{'MOD_PERL'} && exists $ENV{'MOD_PERL_API_VERSION'} - && $ENV{'MOD_PERL_API_VERSION'} >= 2 && fileno(STDOUT) != 1 - ) { - # under mod_perl2, STDOUT gets closed and re-opened, however new STDOUT - # is not on FD #1. In this case next IO operation will occupy this FD - # and make all system() and open "|-" dangerouse, for example DBI - # can get this FD for DB connection and system() call will close - # by putting grabage into the socket - open( $protect_fd, '>', '/dev/null' ) - or die "Couldn't open /dev/null: $!"; - unless ( fileno($protect_fd) == 1 ) { - warn "We opened /dev/null to protect FD #1, but descriptor #1 is already occupied"; - } - } - - local $SIG{__WARN__}; - local $SIG{__DIE__}; - RT::InitSignalHandlers(); - - if ($r->content_type =~ m/^httpd\b.*\bdirectory/i) { - use File::Spec::Unix; - # Our DirectoryIndex is always index.html, regardless of httpd settings - $r->filename( File::Spec::Unix->catfile( $r->filename, 'index.html' ) ); - } - - Module::Refresh->refresh if RT->Config->Get('DevelMode'); - - RT::ConnectToDatabase(); - - # none of the methods in $r gives us the information we want (most - # canonicalize /foo/../bar to /bar which is exactly what we want to avoid) - my (undef, $requested) = split ' ', $r->the_request, 3; - my $uri = URI->new("http://".$r->hostname.$requested); - my $path = URI::Escape::uri_unescape($uri->path); - - ## Each environment has its own way of handling .. and so on in paths, - ## so RT consistently forbids such paths. - if ( $path =~ m{/\.} ) { - $RT::Logger->crit("Invalid request for ".$path." aborting"); - RT::Interface::Web::Handler->CleanupRequest(); - return 400; - } - - my (%session, $status); - { - local $@; - $status = eval { $Handler->handle_request($r) }; - $RT::Logger->crit( $@ ) if $@; - } - undef %session; - - RT::Interface::Web::Handler->CleanupRequest(); - - return $status; -} - -package main; - -# check mod_perl version if it's mod_perl -BEGIN { - die "RT does not support mod_perl 1.99. Please upgrade to mod_perl 2.0" - if $ENV{'MOD_PERL'} - and $ENV{'MOD_PERL'} =~ m{mod_perl/(?:1\.9)}; -} - -require CGI; -CGI->import(qw(-private_tempfiles)); - -# fix lib paths, some may be relative -BEGIN { - require File::Spec; - my @libs = ("@RT_LIB_PATH@", "@LOCAL_LIB_PATH@"); - my $bin_path; - - for my $lib (@libs) { - unless ( File::Spec->file_name_is_absolute($lib) ) { - unless ($bin_path) { - if ( File::Spec->file_name_is_absolute(__FILE__) ) { - $bin_path = ( File::Spec->splitpath(__FILE__) )[1]; - } - else { - require FindBin; - no warnings "once"; - $bin_path = $FindBin::Bin; - } - } - $lib = File::Spec->catfile( $bin_path, File::Spec->updir, $lib ); - } - unshift @INC, $lib; - } - -} - -require RT; -die "Wrong version of RT $RT::Version found; need @RT_VERSION_MAJOR@.@RT_VERSION_MINOR@.*" - unless $RT::VERSION =~ /^@RT_VERSION_MAJOR@\.@RT_VERSION_MINOR@\./; -RT::LoadConfig(); -if ( RT->Config->Get('DevelMode') ) { - require Module::Refresh; -} -RT::Init(); - -# check compatibility of the DB -{ - my $dbh = $RT::Handle->dbh; - if ( $dbh ) { - my ($status, $msg) = $RT::Handle->CheckCompatibility( $dbh, 'post' ); - die $msg unless $status; - } -} - -require RT::Interface::Web::Handler; -$RT::Mason::Handler = RT::Interface::Web::Handler->new( - RT->Config->Get('MasonParameters') -); - -# load more for mod_perl before forking -RT::InitClasses( Heavy => 1 ) if $ENV{'MOD_PERL'} || $ENV{RT_WEBMUX_HEAVY_LOAD}; - -# we must disconnect DB before fork -$RT::Handle->dbh(undef); -undef $RT::Handle; - -if ( $ENV{'MOD_PERL'} && !RT->Config->Get('DevelMode')) { - # Under static_source, we need to purge the component cache - # each time we restart, so newer components may be reloaded. - # - # We can't do this in FastCGI or we'll blow away the component - # root _every_ time a new server starts which happens every few - # hits. - - require File::Path; - require File::Glob; - my @files = File::Glob::bsd_glob("$RT::MasonDataDir/obj/*"); - File::Path::rmtree([ @files ], 0, 1) if @files; -} - -1; |