This commit was manufactured by cvs2svn to create tag 'freeside_1_5_0pre5'. freeside_1_5_0pre5
authorcvs2git <cvs2git>
Tue, 22 Jun 2004 03:12:02 +0000 (03:12 +0000)
committercvs2git <cvs2git>
Tue, 22 Jun 2004 03:12:02 +0000 (03:12 +0000)
19 files changed:
fs_signup/fs_signup_server [deleted file]
rt/Makefile
rt/README
rt/bin/mason_handler.fcgi
rt/bin/mason_handler.scgi
rt/bin/rt-mailgate
rt/bin/webmux.pl
rt/etc/acl.Oracle
rt/etc/schema.Pg
rt/etc/schema.mysql
rt/lib/RT.pm
rt/lib/RT/Action/Autoreply.pm
rt/lib/RT/Action/SendEmail.pm
rt/lib/RT/CurrentUser.pm
rt/lib/RT/Handle.pm
rt/lib/RT/Interface/CLI.pm
rt/lib/RT/Interface/Email.pm
rt/lib/RT/Interface/Web.pm
rt/lib/RT/Record.pm

diff --git a/fs_signup/fs_signup_server b/fs_signup/fs_signup_server
deleted file mode 100755 (executable)
index d6eb4a8..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-#!/usr/bin/perl -Tw
-#
-# fs_signup_server
-#
-
-use strict;
-use vars qw($pid);
-use IO::Handle;
-use Storable qw(nstore_fd fd_retrieve);
-use Tie::RefHash;
-use Net::SSH qw(sshopen2);
-use FS::UID qw(adminsuidsetup);
-use FS::Conf;
-use FS::Record qw( qsearch qsearchs );
-use FS::cust_main_county;
-use FS::cust_main;
-use FS::cust_bill;
-use FS::cust_pkg;
-use FS::Msgcat qw(gettext);
-
-use vars qw( $opt $Debug );
-
-$Debug = 2;
-
-my $user = shift or die &usage;
-&adminsuidsetup( $user ); 
-
-my $conf = new FS::Conf;
-
-if ($conf->exists('signup_server-quiet')) {
-    $FS::cust_bill::quiet = 1;
-    $FS::cust_pkg::quiet = 1;
-}
-
-#my @payby = qw(CARD PREPAY);
-my @payby = $conf->config('signup_server-payby');
-my $smtpmachine = $conf->config('smtpmachine');
-
-my $machine = shift or die &usage;
-
-my $agentnum = shift or die &usage;
-my $agent = qsearchs( 'agent', { 'agentnum' => $agentnum } ) or die &usage;
-my $pkgpart_href = $agent->pkgpart_hashref;
-
-my $refnum = shift or die &usage;
-
-#causing trouble for some folks
-#$SIG{CHLD} = sub { wait() };
-
-$SIG{HUP} = \&killssh;
-$SIG{INT} = \&killssh;
-$SIG{QUIT} = \&killssh;
-$SIG{TERM} = \&killssh;
-$SIG{PIPE} = \&killssh;
-sub killssh { kill 'TERM', $pid if $pid; exit; };
-
-my($fs_signupd)="/usr/local/sbin/fs_signupd";
-
-while (1) {
-  my($reader,$writer)=(new IO::Handle, new IO::Handle);
-  #seems to be broken - calling ->flush explicitly# $writer->autoflush(1);
-  warn "[fs_signup_server] Connecting to $machine...\n" if $Debug;
-  $pid = sshopen2($machine,$reader,$writer,$fs_signupd);
-
-  my @pops = qsearch('svc_acct_pop',{} );
-  my $init_data = {
-
-    #'_protocol' => 'signup',
-    #'_version' => '0.1',
-    #'_packet' => 'init'
-  
-    'cust_main_county' =>
-      [ map { $_->hashref } qsearch('cust_main_county', {}) ],
-      
-    'part_pkg' =>
-      [
-        #map { $_->hashref }
-        map { { 'payby' => [ $_->payby ], %{$_->hashref} } }
-          grep { $_->svcpart('svc_acct') && $pkgpart_href->{ $_->pkgpart } }
-            qsearch( 'part_pkg', { 'disabled' => '' } )
-      ],
-
-    'agentnum2part_pkg' =>
-      {
-        map {
-          my $href = $_->pkgpart_hashref;
-          $_->agentnum =>
-            [
-              map { { 'payby' => [ $_->payby ], %{$_->hashref} } }
-                grep { $_->svcpart('svc_acct') && $href->{ $_->pkgpart } }
-                  qsearch( 'part_pkg', { 'disabled' => '' } )
-            ];
-        } qsearch('agent', {} )
-      },
-
-    'svc_acct_pop' => [ map { $_->hashref } @pops ],
-
-    'security_phrase' => $conf->exists('security_phrase'),
-
-    'payby' => [ $conf->config('signup_server-payby') ],
-
-    'msgcat' => { map { $_=>gettext($_) } qw(
-      passwords_dont_match invalid_card unknown_card_type not_a
-    ) },
-
-    'statedefault' => $conf->config('statedefault') || 'CA',
-
-    'countrydefault' => $conf->config('countrydefault') || 'US',
-
-  };
-
-  warn "[fs_signup_server] Sending init data...\n" if $Debug;
-  nstore_fd($init_data, $writer) or die "can't send init data: $!";
-  $writer->flush;
-
-  warn "[fs_signup_server] Entering main loop...\n" if $Debug;
-  while (1) {
-    warn "[fs_signup_server] Reading (waiting for) signup data...\n" if $Debug;
-    my $signup_data = fd_retrieve($reader);
-
-    if ( $Debug > 1 ) {
-      warn join('',
-        map { "  $_ => ". $signup_data->{$_}. "\n" } keys %$signup_data );
-    }
-
-    warn "[fs_signup_server] Processing signup...\n" if $Debug;
-
-    my $error = '';
-
-    #things that aren't necessary in base class, but are for signup server
-      #return "Passwords don't match"
-      #  if $hashref->{'_password'} ne $hashref->{'_password2'}
-    $error ||= gettext('empty_password') unless $signup_data->{'_password'};
-    $error ||= gettext('no_access_number_selected')
-      unless $signup_data->{'popnum'} || !scalar(@pops);
-
-    #shares some stuff with htdocs/edit/process/cust_main.cgi... take any
-    # common that are still here and library them.
-    my $cust_main = new FS::cust_main ( {
-      #'custnum'          => '',
-      'agentnum'         => $signup_data->{agentnum} || $agentnum,
-      'refnum'           => $refnum,
-
-      map { $_ => $signup_data->{$_} } qw(
-        last first ss company address1 address2 city county state zip country
-        daytime night fax payby payinfo paydate payname referral_custnum comments
-      ),
-
-    } );
-
-    $error ||= "Illegal payment type"
-      unless grep { $_ eq $signup_data->{'payby'} } @payby;
-
-    $cust_main->payinfo($cust_main->daytime)
-      if $cust_main->payby eq 'LECB' && ! $cust_main->payinfo;
-
-    my @invoicing_list = split( /\s*\,\s*/, $signup_data->{'invoicing_list'} );
-
-    $signup_data->{'pkgpart'} =~ /^(\d+)$/ or '' =~ /^()$/;
-    my $pkgpart = $1;
-
-    my $part_pkg =
-      qsearchs( 'part_pkg', { 'pkgpart' => $pkgpart } )
-        or $error ||= "WARNING: unknown pkgpart: $pkgpart";
-    my $svcpart = $part_pkg->svcpart('svc_acct') unless $error;
-
-    my $cust_pkg = new FS::cust_pkg ( {
-      #later#'custnum' => $custnum,
-      'pkgpart' => $signup_data->{'pkgpart'},
-    } );
-    $error ||= $cust_pkg->check;
-
-    my $svc_acct = new FS::svc_acct ( {
-      'svcpart'   => $svcpart,
-      map { $_ => $signup_data->{$_} }
-        qw( username _password sec_phrase popnum ),
-    } );
-
-    my $y = $svc_acct->setdefault; # arguably should be in new method
-    $error ||= $y unless ref($y);
-
-    $error ||= $svc_acct->check;
-
-    use Tie::RefHash;
-    tie my %hash, 'Tie::RefHash';
-    %hash = ( $cust_pkg => [ $svc_acct ] );
-    $error ||= $cust_main->insert( \%hash, \@invoicing_list ); #msgcat
-
-    if ( ! $error && $conf->exists('signup_server-realtime') ) {
-
-      warn "[fs_signup_server] Billing customer...\n" if $Debug;
-
-      my $bill_error = $cust_main->bill;
-      warn "[fs_signup_server] error billing new customer: $bill_error"
-        if $bill_error;
-
-      $cust_main->apply_payments;
-      $cust_main->apply_credits;
-
-      $bill_error = $cust_main->collect;
-      warn "[fs_signup_server] error collecting from new customer: $bill_error"
-        if $bill_error;
-
-      if ( $cust_main->balance > 0 ) {
-
-        #this makes sense.  credit is "un-doing" the invoice
-        $cust_main->credit( $cust_main->balance, 'signup server decline' );
-        $cust_main->apply_credits;
-
-        #should check list for errors...
-        #$cust_main->suspend;
-        $cust_main->cancel;
-
-        $error = '_decline';
-      }
-    }
-
-    warn "[fs_signup_server] Sending results...\n" if $Debug;
-    print $writer $error, "\n";
-
-    next if $error;
-
-    if ( $conf->config('signup_server-email') ) {
-      warn "[fs_signup_server] Sending email...\n" if $Debug;
-
-      #false laziness w/FS::cust_bill::send & FS::cust_pay::delete
-      use Mail::Header;
-      use Mail::Internet 1.44;
-      use Date::Format;
-      my $from = $conf->config('invoice_from'); #??? as good as any
-      $ENV{MAILADDRESS} = $from;
-      my $header = new Mail::Header ( [
-        "From: $from",
-        "To: ". $conf->config('signup_server-email'),
-        "Sender: $from",
-        "Reply-To: $from",
-        "Date: ". time2str("%a, %d %b %Y %X %z", time),
-        "Subject: FREESIDE NOTIFICATION: Signup Server",
-      ] );
-      my $body = [
-        "This is an automatic message from your Freeside installation\n",
-        "informing you a customer has signed up via the signup server:\n",
-        "\n",
-        'custnum     : '. $cust_main->custnum. "\n",
-        'Name        : '. $cust_main->last. ", ". $cust_main->first. "\n",
-        'Agent       : '. $cust_main->agent->agent. "\n",
-        'Package     : '. $part_pkg->pkg. ' - '. $part_pkg->comment. "\n",
-        'Signup Date : '. time2str('%C', time). "\n",
-        'Username    : '. $svc_acct->username. "\n",
-        #'Password    : '. # config file to turn this on if noment insists
-        'Day phone   : '. $cust_main->daytime. "\n",
-        'Night phone : '. $cust_main->night. "\n",
-        'Address     : '. $cust_main->address1. "\n",
-        ( $cust_main->address2
-            ? '              '. $cust_main->address2. "\n"
-            : ''                                           ),
-        '              '. $cust_main->city. ', '. $cust_main->state. '  '.
-                          $cust_main->zip. "\n",
-        ( $cust_main->country eq 'US'
-            ? ''
-            : '              '. $cust_main->country. "\n" ),
-        "\n",
-      ];
-      #if ( $cust_main->balance > 0 ) {
-      #  push @$body,
-      #    "This customer has an outstanding balance and has been suspended.\n";
-      #}
-      my $message = new Mail::Internet ( 'Header' => $header, 'Body' => $body );
-      $!=0;
-      $message->smtpsend( Host => $smtpmachine )
-        or $message->smtpsend( Host => $smtpmachine, Debug => 1 )
-          or warn "[fs_signup_server] can't send email to ".
-                   $conf->config('signup_server-email').
-                   " via server $smtpmachine with SMTP: $!";
-      #end-of-send mail
-    }
-
-  }
-  close $writer;
-  close $reader;
-  warn "connection to $machine lost!  waiting 60 seconds...\n";
-  sleep 60;
-  warn "reconnecting...\n";
-}
-
-sub usage {
-  die "Usage:\n\n  fs_signup_server user machine agentnum refnum\n";
-}
-
index 6447221..0895874 100644 (file)
@@ -1,20 +1,19 @@
 # BEGIN LICENSE BLOCK
 # 
-# Copyright (c) 1996-2002 Jesse Vincent <jesse@bestpractical.com>
+# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
 # 
 # (Except where explictly superceded by other copyright notices)
 # 
 # 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
+# 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.
 # 
-# 
 # Unless otherwise specified, all modifications, corrections or
 # extensions to this work which alter its source code become the
 # property of Best Practical Solutions, LLC when submitted for
@@ -22,8 +21,6 @@
 # 
 # 
 # END LICENSE BLOCK
-
-
 #
 # DO NOT HAND-EDIT the file named 'Makefile'. This file is autogenerated.
 # Have a look at "configure" and "Makefile.in" instead
@@ -39,7 +36,7 @@ SITE_CONFIG_FILE              =       $(CONFIG_FILE_PATH)/RT_SiteConfig.pm
 
 RT_VERSION_MAJOR       =       3
 RT_VERSION_MINOR       =       0
-RT_VERSION_PATCH       =       4
+RT_VERSION_PATCH       =       9
 
 RT_VERSION =   $(RT_VERSION_MAJOR).$(RT_VERSION_MINOR).$(RT_VERSION_PATCH)
 TAG       =    rt-$(RT_VERSION_MAJOR)-$(RT_VERSION_MINOR)-$(RT_VERSION_PATCH)
@@ -101,8 +98,8 @@ RT_MODPERL_HANDLER   =       $(RT_BIN_PATH)/webmux.pl
 RT_FASTCGI_HANDLER     =       $(RT_BIN_PATH)/mason_handler.fcgi
 # RT_WIN32_FASTCGI_HANDLER is the mason handler script for FastCGI
 RT_WIN32_FASTCGI_HANDLER       =       $(RT_BIN_PATH)/mason_handler.svc
-# RT's admin CLI
-RT_CLI_ADMIN_BIN       =       $(RT_BIN_PATH)/rtadmin
+# RT's CLI
+RT_CLI_BIN             =       $(RT_BIN_PATH)/rt
 # RT's mail gateway
 RT_MAILGATE_BIN                =       $(RT_BIN_PATH)/rt-mailgate
 # RT's cron tool
@@ -115,6 +112,7 @@ SETGID_BINARIES             =       $(DESTDIR)/$(RT_FASTCGI_HANDLER) \
 
 BINARIES               =       $(DESTDIR)/$(RT_MODPERL_HANDLER) \
                                $(DESTDIR)/$(RT_MAILGATE_BIN) \
+                               $(DESTDIR)/$(RT_CLI_BIN) \
                                $(DESTDIR)/$(RT_CRON_BIN) \
                                $(SETGID_BINARIES)
 SYSTEM_BINARIES                =       $(DESTDIR)/$(RT_SBIN_PATH)/
@@ -128,6 +126,7 @@ SYSTEM_BINARIES             =       $(DESTDIR)/$(RT_SBIN_PATH)/
 # DB_TYPE defines what sort of database RT trys to talk to
 # "mysql" is known to work.
 # "Pg" is known to work
+# "Informix" is known to work
 
 DB_TYPE                        =       mysql
 
@@ -138,7 +137,8 @@ DB_TYPE                     =       mysql
 
 # For mysql, you probably want 'root'
 # For Pg, you probably want 'postgres' 
-# For oracle, you want 'system'
+# For Oracle, you want 'system'
+# For Informix, you want 'informix'
 
 DB_DBA                 =       root
 
@@ -211,7 +211,7 @@ upgrade-instruct:
        @echo "    $(RT_SBIN_PATH)/rt-setup-database --action insert --datafile etc/upgrade/<version>"
 
 
-upgrade: dirs upgrade-noclobber upgrade-instruct
+upgrade: config-install dirs files-install fixperms upgrade-instruct
 
 upgrade-noclobber: config-install libs-install html-install bin-install local-install doc-install fixperms
 
@@ -312,13 +312,16 @@ config-install:
 test: 
        $(PERL) -Ilib lib/t/00smoke.t
 
-regression-nosetgid-quiet: config-install dirs files-install libs-install sbin-install bin-install regression-instruct regression-reset-db  testify-pods fixperms-nosetgid apachectl
+regression-install: config-install
+       $(PERL) -pi -e 's/Set\(\$$DatabaseName.*\);/Set\(\$$DatabaseName, "rt3regression"\);/' $(DESTDIR)/$(CONFIG_FILE)
+
+regression-nosetgid-quiet: regression-install dirs files-install libs-install sbin-install bin-install regression-instruct regression-reset-db  testify-pods fixperms-nosetgid apachectl
        $(PERL) sbin/regression_harness
 
-regression-nosetgid: config-install dirs files-install libs-install sbin-install bin-install regression-instruct regression-reset-db  testify-pods fixperms-nosetgid apachectl
+regression-nosetgid: regression-install dirs files-install libs-install sbin-install bin-install regression-instruct regression-reset-db  testify-pods fixperms-nosetgid apachectl
        $(PERL) lib/t/02regression.t
 
-regression: config-install dirs files-install libs-install sbin-install bin-install regression-instruct regression-reset-db  testify-pods apachectl
+regression: regression-install dirs files-install libs-install sbin-install bin-install regression-instruct regression-reset-db  testify-pods fixperms apachectl
        $(PERL) lib/t/02regression.t
 
 regression-quiet:
@@ -397,7 +400,9 @@ bin-install:
        -cp -rp \
                bin/rt-mailgate \
                bin/mason_handler.fcgi \
+               bin/mason_handler.scgi \
                bin/mason_handler.svc \
+               bin/rt \
                bin/webmux.pl \
                bin/rt-crontool \
                $(DESTDIR)/$(RT_BIN_PATH)
index 7c5e4d4..7188f09 100755 (executable)
--- a/rt/README
+++ b/rt/README
@@ -21,6 +21,7 @@
 # 
 # 
 # END LICENSE BLOCK
+
 RT is an enterprise-grade issue tracking system. It allows
 organizations to keep track of their to-do lists, who is working
 on which tasks, what's already been done, and when tasks were
@@ -36,22 +37,22 @@ up and use.
 REQUIRED PACKAGES:
 ------------------
 
-o   Perl 5.8.0 or later (http://www.perl.com).
+o   Perl 5.8.3 or later (http://www.perl.com).
 
        (If you intend to use the FastCGI or SpeedyCGI support, you 
         need to make sure that perl has been built with support for 
         setgid perl scripts.)`
 
+    Perl versions prior to 5.8.3 contain bugs that could result in data
+    corruption. We recommend strongly that you use 5.8.3 or newer.
+
     Perl 5.6.1 is currently deprecated and will be officially desupported
     in a future release
 
 o   A DB backend; MySQL is recommended ( http://www.mysql.com ) 
         Currently supported:  Mysql 4.0.13 or later. 
                               Postgres 7.2 or later.
-
-                              Mysql 3.23.46 or newer with support for InnoDB 
-                             is currently deprecated and will be officially
-                             desupported in a future release.
+                              Oracle 9iR2.
 
 o   Apache version 1.3.x or 2.x (http://httpd.apache.org) 
     with mod_perl -- (http://perl.apache.org ) 
@@ -119,7 +120,7 @@ http://www.bestpractical.com/rt
    perl sbin/rt-test-dependencies \ 
                 --with-<databasename> --with-<web-environment>
 
-        databasename is one of: mysql, postgres
+        databasename is one of: mysql, postgres, oracle
         web-environment is one of: fastcgi, modperl1, modperl2
 
 3.2   If there are unsatisfied dependencies, install them by hand or run:
@@ -151,6 +152,10 @@ http://www.bestpractical.com/rt
 
 5b  FOR UPGRADING: (Within the RT 3.0.x series)
 
+
+        Read through the UPGRADING document included in this distribution.
+        It may contain important instructions for updating your database
+
         As root, type: 
                 make upgrade     (replace "make" with the local name for 
                                   Make, if you need to)
@@ -160,6 +165,14 @@ http://www.bestpractical.com/rt
         
         It may then instruct you to update your RT system database objects 
 
+5c  FOR UPGRADING: (From RT 2.0.x)
+
+    Download the RT2 to RT3 migration tools from:
+
+    http://bestpractical.com/pub/rt/devel/rt2-to-rt3.tar.gz
+
+    Follow the included instructions.
+
 6   Edit etc/RT_SiteConfig.pm in your RT installation directory, by specifying
     any values you need to change from the defaults in etc/RT_Config.pm
 
@@ -192,31 +205,20 @@ Apache
     DocumentRoot /opt/rt3/share/html
     AddDefaultCharset UTF-8
 
-    # this line applies to Apache2+mod_perl2 only
+    # these four lines apply to Apache2+mod_perl2 only: {{{
+    PerlSetVar MasonArgsMethod CGI
     PerlModule Apache2 Apache::compat
+    RewriteEngine On
+    RewriteRule ^(.*)/$ $1/index.html
+    # }}}
 
     PerlModule Apache::DBI
     PerlRequire /opt/rt3/bin/webmux.pl
 
-    # this section applies to Apache 1 only
     <Location />
         SetHandler perl-script
         PerlHandler RT::Mason
     </Location>
-
-    # this section applies to Apache2+mod_perl2 only
-    <FilesMatch "\.html$">
-        SetHandler perl-script
-        PerlHandler RT::Mason
-    </FilesMatch>
-    <LocationMatch "/Attachment/">
-        SetHandler perl-script
-        PerlHandler RT::Mason
-    </LocationMatch>
-    <LocationMatch "/REST/">
-        SetHandler perl-script
-        PerlHandler RT::Mason
-    </LocationMatch>
 </VirtualHost>
 
 
index 431eccb..93d1f88 100755 (executable)
@@ -27,7 +27,7 @@ use strict;
 use File::Basename;
 require ('/opt/rt3/bin/webmux.pl');
 
-my $h = &RT::Interface::Web::NewCGIHandler();
+my $h = &RT::Interface::Web::NewCGIHandler(@RT::MasonParameters);
 
 # Enter CGI::Fast mode, which should also work as a vanilla CGI script.
 require CGI::Fast;
@@ -44,11 +44,25 @@ while ( my $cgi = CGI::Fast->new ) {
     $ENV{'ENV'}    = '' if defined $ENV{'ENV'};
     $ENV{'IFS'}    = '' if defined $ENV{'IFS'};
 
-    unless ($h->interp->comp_exists($cgi->path_info)) {
-       $cgi->path_info($cgi->path_info . "/index.html");
+    RT::ConnectToDatabase();
+
+    if ( ( !$h->interp->comp_exists( $cgi->path_info ) )
+        && ( $h->interp->comp_exists( $cgi->path_info . "/index.html" ) ) ) {
+        $cgi->path_info( $cgi->path_info . "/index.html" );
+    }
+
+    eval { $h->handle_cgi_object($cgi); };
+    if ($@) {
+        $RT::Logger->crit($@);
+    }
+
+
+    if ($RT::Handle->TransactionDepth) {
+        $RT::Handle->ForceRollback;
+        $RT::Logger->crit("Transaction not committed. Usually indicates a software fault. Data loss may have occurred") ;
     }
-    $h->handle_cgi_object($cgi);
-    # _should_ always be tied
+
+
 }
 
 1;
index 8e1135c..7774189 100755 (executable)
 use strict;
 require ('/opt/rt3/bin/webmux.pl');
 
-my $h = &RT::Interface::Web::NewCGIHandler();
+my $h = &RT::Interface::Web::NewCGIHandler(@RT::MasonParameters);
 
 require CGI;
 
 RT::Init();
 
 my $cgi = CGI->new;
-unless ($h->interp->comp_exists($cgi->path_info)) {
-    $cgi->path_info($cgi->path_info . "/index.html");
+if ( ( !$h->interp->comp_exists( $cgi->path_info ) )
+    && ( $h->interp->comp_exists( $cgi->path_info . "/index.html" ) ) ) {
+    $cgi->path_info( $cgi->path_info . "/index.html" );
 }
+
 $h->handle_cgi_object($cgi);
 
 1;
index b304436..8af8002 100755 (executable)
@@ -1,26 +1,26 @@
 #!/usr/bin/perl -w
 # BEGIN LICENSE BLOCK
-#
+# 
 # Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-#
+# 
 # (Except where explictly superceded by other copyright notices)
-#
+# 
 # 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.
-#
+# 
 # Unless otherwise specified, all modifications, corrections or
 # extensions to this work which alter its source code become the
 # property of Best Practical Solutions, LLC when submitted for
 # inclusion in the work.
-#
-#
+# 
+# 
 # END LICENSE BLOCK
 
 =head1 NAME
@@ -31,10 +31,25 @@ rt-mailgate - Mail interface to RT3.
 
 use RT::I18N;
 
+# Make sure that when we call the mailgate wrong, it tempfails
+
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://bad.address"), "Opened the mailgate - The error below is expected - $@");
+print MAIL <<EOF;
+From: root\@localhost
+To: rt\@example.com
+Subject: This is a test of new ticket creation
+
+Foob!
+EOF
+close (MAIL);
+
+# Check the return value
+is ( $? >> 8, 75, "The error message above is expected The mail gateway exited with a failure. yay");
+
 
 # {{{ Test new ticket creation by root who is privileged and superuser
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: root\@localhost
 To: rt\@example.com
@@ -45,6 +60,9 @@ Foob!
 EOF
 close (MAIL);
 
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
+
 use RT::Tickets;
 my $tickets = RT::Tickets->new($RT::SystemUser);
 $tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
@@ -59,7 +77,7 @@ ok ($tick->Subject eq 'This is a test of new ticket creation', "Created the tick
 
 # {{{This is a test of new ticket creation as an unknown user
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: doesnotexist\@example.com
 To: rt\@example.com
@@ -69,6 +87,8 @@ Blah!
 Foob!
 EOF
 close (MAIL);
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
 
 $tickets = RT::Tickets->new($RT::SystemUser);
 $tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
@@ -94,7 +114,7 @@ ok ($val, "Granted everybody the right to create tickets - $msg");
 
 sleep(60); # gotta sleep so the remote process' ACL cache times out
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: doesnotexist\@example.com
 To: rt\@example.com
@@ -104,6 +124,8 @@ Blah!
 Foob!
 EOF
 close (MAIL);
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
 
 
 $tickets = RT::Tickets->new($RT::SystemUser);
@@ -126,7 +148,7 @@ ok( $u->Id != 0, " user does not exist and was created by ticket submission");
 #ok ($val, "Granted everybody the right to create tickets - $msg");
 #sleep(60); # gotta sleep so the remote process' ACL cache times out
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: doesnotexist-2\@example.com
 To: rt\@example.com
@@ -136,6 +158,8 @@ Blah!
 Foob!
 EOF
 close (MAIL);
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
 
 $u = RT::User->new($RT::SystemUser);
 $u->Load('doesnotexist-2@example.com');
@@ -148,7 +172,7 @@ ok( $u->Id == 0, " user does not exist and was not created by ticket corresponde
 ok ($val, "Granted everybody the right to reply to  tickets - $msg");
 sleep(60); # gotta sleep so the remote process' ACL cache times out
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: doesnotexist-2\@example.com
 To: rt\@example.com
@@ -158,6 +182,8 @@ Blah!
 Foob!
 EOF
 close (MAIL);
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
 
 
 $u = RT::User->new($RT::SystemUser);
@@ -173,7 +199,7 @@ ok( $u->Id != 0, " user exists and was created by ticket correspondence submissi
 #ok ($val, "Granted everybody the right to create tickets - $msg");
 #sleep(60); # gotta sleep so the remote process' ACL cache times out
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action comment"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action comment"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: doesnotexist-3\@example.com
 To: rt\@example.com
@@ -184,6 +210,9 @@ Foob!
 EOF
 close (MAIL);
 
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
+
 $u = RT::User->new($RT::SystemUser);
 $u->Load('doesnotexist-3@example.com');
 ok( $u->Id == 0, " user does not exist and was not created by ticket comment submission");
@@ -196,7 +225,7 @@ ok( $u->Id == 0, " user does not exist and was not created by ticket comment sub
 ok ($val, "Granted everybody the right to reply to  tickets - $msg");
 sleep(60); # gotta sleep so the remote process' ACL cache times out
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action comment"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action comment"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: doesnotexist-3\@example.com
 To: rt\@example.com
@@ -207,6 +236,8 @@ Foob!
 EOF
 close (MAIL);
 
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
 
 $u = RT::User->new($RT::SystemUser);
 $u->Load('doesnotexist-3@example.com');
@@ -227,17 +258,20 @@ my $entity = MIME::Entity->build( From => 'root@localhost',
                                 Data => ['This is a test of a binary attachment']);
 
 # currently in lib/t/autogen
-$entity->attach(Path => '../../../html/NoAuth/images/spacer.gif', 
+$entity->attach(Path => '/opt/rt3/share/html/NoAuth/images/spacer.gif', 
                 Type => 'image/gif',
                 Encoding => 'base64');
 
 # Create a ticket with a binary attachment
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
 
 $entity->print(\*MAIL);
 
 close (MAIL);
 
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
+
 my $tickets = RT::Tickets->new($RT::SystemUser);
 $tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
 $tickets->Limit(FIELD => 'id', OPERATOR => '>', VALUE => '0');
@@ -273,7 +307,7 @@ use LWP::UserAgent;
 # Grab the binary attachment via the web ui
 my $ua      = LWP::UserAgent->new();
 
-my $full_url = "http://localhost/Ticket/Attachment/".$attachment->TransactionId."/".$attachment->id."/spacer.gif?&user=root&pass=password";
+my $full_url = "http://localhost".$RT::WebPath."/Ticket/Attachment/".$attachment->TransactionId."/".$attachment->id."/spacer.gif?&user=root&pass=password";
 my $r = $ua->get( $full_url);
 
 
@@ -286,7 +320,7 @@ is($file, $r->content, 'The attachment isn\'t screwed up in download');
 
 # {{{ Simple I18N testing
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
                                                                          
 print MAIL <<EOF;
 From: root\@localhost
@@ -301,6 +335,9 @@ bye
 EOF
 close (MAIL);
 
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
+
 my $unitickets = RT::Tickets->new($RT::SystemUser);
 $unitickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
 $unitickets->Limit(FIELD => 'id', OPERATOR => '>', VALUE => '0');
@@ -317,7 +354,7 @@ is ($unitick->Transactions->First->Content, $unitick->Transactions->First->Attac
 ok($unitick->Transactions->First->Attachments->First->Content =~ /$unistring/i, $unitick->Id." appears to be unicode ". $unitick->Transactions->First->Attachments->First->Id);
 # supposedly I18N fails on the second message sent in.
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
                                                                          
 print MAIL <<EOF;
 From: root\@localhost
@@ -332,6 +369,9 @@ bye
 EOF
 close (MAIL);
 
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
+
 my $tickets2 = RT::Tickets->new($RT::SystemUser);
 $tickets2->OrderBy(FIELD => 'id', ORDER => 'DESC');
 $tickets2->Limit(FIELD => 'id', OPERATOR => '>', VALUE => '0');
@@ -367,7 +407,7 @@ use LWP::UserAgent;
 use constant EX_TEMPFAIL => 75;
 
 my %opts;
-GetOptions( \%opts, "queue=s", "action=s", "url=s", "jar=s", "help", "debug", "extension=s" );
+GetOptions( \%opts, "queue=s", "action=s", "url=s", "jar=s", "help", "debug", "extension=s", "timeout=i" );
 
 if ( $opts{help} ) {
     require Pod::Usage;
@@ -381,17 +421,18 @@ for (qw(url)) {
 }
 
 undef $/;
-my $message = <>;
 my $ua      = LWP::UserAgent->new();
 $ua->cookie_jar( { file => $opts{jar} } );
 
 my %args = (
     queue   => $opts{queue},
     action  => $opts{action},
-    message => $message,
     SessionType => 'REST',    # Surpress login box
 );
 
+# Read the message in from STDIN
+$args{'message'} = <>;
+
 
 if ($opts{'extension'}) {
         $args{$opts{'extension'}} = $ENV{'EXTENSION'};
@@ -404,6 +445,7 @@ warn "Connecting to $full_url" if $opts{'debug'};
 
 
 
+$ua->timeout(exists($opts{'timeout'}) ? $opts{'timeout'} : 180);
 my $r = $ua->post( $full_url, {%args} );
 check_failure($r);
 
@@ -414,7 +456,7 @@ 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.
-    die <<EOF
+    warn <<EOF;
 RT server error.
 
 The RT server which handled your email did not behave as expected. It
@@ -423,8 +465,13 @@ said:
 $content
 EOF
 
+exit EX_TEMPFAIL;
+
 }
 
+exit;
+
+
 sub check_failure {
     my $r = shift;
     return if $r->is_success();
@@ -455,7 +502,11 @@ Usual invocation (from MTA):
 
     rt-mailgate --action (correspond|comment) --queue queuename
                 --url http://your.rt.server/
-                [ --extension (queue|action|ticket)
+                [ --debug ]
+                [ --extension (queue|action|ticket) ]
+                [ --timeout seconds ]
+
+
 
 See C<man rt-mailgate> for more.
 
@@ -486,6 +537,16 @@ submitted to will be set to the value of $EXTENSION. By specifying
 is related to.  "action" will allow the user to specify either "comment" or
 "correspond" in the address extension.
 
+=item C<--debug> OPTIONAL
+
+Print debugging output to standard error
+
+
+=item C<--timeout> OPTIONAL
+
+Configure the timeout for posting the message to the web server.  The
+default timeout is 3 minutes (180 seconds).
+
 
 =head1 DESCRIPTION
 
index 21cb83f..96e7ebf 100755 (executable)
@@ -31,6 +31,7 @@ BEGIN {
     $ENV{'SHELL'}  = '/bin/sh' if defined $ENV{'SHELL'};
     $ENV{'ENV'}    = '' if defined $ENV{'ENV'};
     $ENV{'IFS'}    = '' if defined $ENV{'IFS'};
+    
 }
 
 use lib ("/opt/rt3/local/lib", "/opt/rt3/lib");
@@ -42,6 +43,17 @@ use CGI qw(-private_tempfiles);    #bring this in before mason, to make sure we
                                    #set private_tempfiles
 
 BEGIN {
+    if ($mod_perl::VERSION >= 1.9908) {
+       require Apache::RequestUtil;
+       no warnings 'redefine';
+       my $sub = *Apache::request{CODE};
+       *Apache::request = sub {
+           my $r;
+           eval { $r = $sub->('Apache'); };
+           # warn $@ if $@;
+           return $r;
+       };
+    }
     if ($CGI::MOD_PERL) {
        require HTML::Mason::ApacheHandler;
     }
@@ -104,21 +116,32 @@ if ( $CGI::MOD_PERL)  {
        unless ( ( -d _ ) and ( -r _ ) and ( -w _ ) );
 }
 
-my $ah = &RT::Interface::Web::NewApacheHandler() if $CGI::MOD_PERL;
+my $ah = &RT::Interface::Web::NewApacheHandler(@RT::MasonParameters) if $CGI::MOD_PERL;
 
 sub handler {
     ($r) = @_;
 
+    local $SIG{__WARN__};
+    local $SIG{__DIE__};
+
     RT::Init();
 
     # We don't need to handle non-text items
     return -1 if defined( $r->content_type ) && $r->content_type !~ m|^text/|io;
 
     my %session;
-    my $status = $ah->handle_request($r);
+    my $status;
+    eval { $status = $ah->handle_request($r) };
+    if ($@) {
+       $RT::Logger->crit($@);
+    }
+
     undef (%session);
 
-    $RT::Logger->crit("Transaction not committed. Usually indicates a software fault. Data loss may have occurred") if $RT::Handle->TransactionDepth;
+    if ($RT::Handle->TransactionDepth) {
+       $RT::Handle->ForceRollback;
+       $RT::Logger->crit("Transaction not committed. Usually indicates a software fault. Data loss may have occurred") ;
+    }
     return $status;
 }
 
index c8667c0..ac29215 100644 (file)
@@ -1,10 +1,10 @@
 sub acl {
 return (
-"CREATE USER ${RT::DatabaseUser} identified by ${RT::DatabasePassword}".
-"temporary tablespace TEMP" .
-"default tablespace USERS" .
-"quota unlimited on USERS;" ,
-"grant connect, resource to ${RT::DatabaseUser};",
-"exit;");
+"CREATE USER ${RT::DatabaseUser} identified by ${RT::DatabasePassword} ".
+"default tablespace USERS " .
+"temporary tablespace TEMP " .
+"quota unlimited on USERS" ,
+"grant connect, resource to ${RT::DatabaseUser}"
+);
 }
 1;
index ba0d6fc..085c615 100755 (executable)
@@ -3,9 +3,6 @@
 --
 ------------------------------------------------------------------
 
-BEGIN;
-
-
 
 
 --
@@ -93,6 +90,7 @@ CREATE TABLE Links (
 
 );
 CREATE UNIQUE INDEX Links1 ON Links (Base, Target, Type) ;
+CREATE INDEX Links4 ON Links(Type,LocalBase);
 
 -- }}}
 
@@ -136,7 +134,7 @@ CREATE TABLE Groups (
   Description varchar(255) NULL  ,
   Domain varchar(64),
   Type varchar(64),
-  Instance varchar(64),
+  Instance integer,
   PRIMARY KEY (id)
 
 );
@@ -192,7 +190,7 @@ CREATE TABLE Transactions (
   Field varchar(40) NULL  ,
   OldValue varchar(255) NULL  ,
   NewValue varchar(255) NULL  ,
-  Data varchar(100) NULL  ,
+  Data varchar(255) NULL  ,
 
   Creator integer NOT NULL DEFAULT 0  ,
   Created TIMESTAMP NULL  ,
@@ -500,6 +498,9 @@ CREATE TABLE TicketCustomFieldValues (
 
 );
 
+CREATE INDEX TicketCustomFieldValues1 ON TicketCustomFieldValues (CustomField,Ticket,Content); 
+CREATE INDEX TicketCustomFieldValues2 ON TicketCustomFieldValues (CustomField,Ticket); 
+
 -- }}}
 
 -- {{{ CustomFields
@@ -556,6 +557,8 @@ CREATE TABLE CustomFieldValues (
 
 );
 
+CREATE INDEX CustomFieldValues1 ON CustomFieldValues (CustomField);
+
 -- }}}
 
 -- {{{ Sessions
@@ -573,6 +576,3 @@ CREATE TABLE sessions (
 
 -- }}}
 
-
-
-COMMIT;
index 46f8ec5..14e9223 100755 (executable)
@@ -62,6 +62,7 @@ CREATE TABLE Links (
 CREATE UNIQUE INDEX Links1 ON Links (Base, Target, Type) ;
 CREATE INDEX Links2 ON Links (Base,  Type) ;
 CREATE INDEX Links3 ON Links (Target,  Type) ;
+CREATE INDEX Links4 ON Links(Type,LocalBase);
 
 # }}}
 
@@ -87,7 +88,7 @@ CREATE TABLE Groups (
   Description varchar(255) NULL  ,
   Domain varchar(64),
   Type varchar(64),
-  Instance varchar(64),
+  Instance integer,
   PRIMARY KEY (id)
 ) TYPE=InnoDB;
 
@@ -125,7 +126,7 @@ CREATE TABLE Transactions (
   Field varchar(40) NULL  ,
   OldValue varchar(255) NULL  ,
   NewValue varchar(255) NULL  ,
-  Data varchar(100) NULL  ,
+  Data varchar(255) NULL  ,
 
   Creator integer NOT NULL DEFAULT 0  ,
   Created DATETIME NULL  ,
@@ -358,6 +359,9 @@ CREATE TABLE TicketCustomFieldValues (
   PRIMARY KEY (id)
 ) TYPE=InnoDB;
 
+CREATE INDEX TicketCustomFieldValues1 ON TicketCustomFieldValues (CustomField,Ticket,Content); 
+CREATE INDEX TicketCustomFieldValues2 ON TicketCustomFieldValues (CustomField,Ticket); 
+
 # }}}
 
 # {{{ CustomFields
@@ -399,6 +403,8 @@ CREATE TABLE CustomFieldValues (
   PRIMARY KEY (id)
 ) TYPE=InnoDB;
 
+CREATE INDEX CustomFieldValues1 ON CustomFieldValues (CustomField);
 # }}}
 
 # {{{ Sessions
index 90c332b..7e941a2 100644 (file)
@@ -47,7 +47,7 @@ use vars qw($VERSION $System $SystemUser $Nobody $Handle $Logger
         $MasonSessionDir
 );
 
-$VERSION = '3.0.4';
+$VERSION = '3.0.9';
 $CORE_CONFIG_FILE = "/opt/rt3/etc/RT_Config.pm";
 $SITE_CONFIG_FILE = "/opt/rt3/etc/RT_SiteConfig.pm";
 
@@ -117,13 +117,10 @@ sub LoadConfig {
 =cut
 
 sub Init {
-    require RT::Handle;
+
     #Get a database connection
-        unless ($Handle && $Handle->dbh->ping) {
-    $Handle = RT::Handle->new();
-        } 
-    $Handle->Connect();
-    
+    ConnectToDatabase();
+
     #RT's system user is a genuine database user. its id lives here
     $SystemUser = new RT::CurrentUser();
     $SystemUser->LoadByName('RT_System');
@@ -137,6 +134,21 @@ sub Init {
    InitLogging(); 
 }
 
+  
+=head2 ConnectToDatabase
+
+Get a database connection
+
+=cut
+sub ConnectToDatabase {
+    require RT::Handle;
+    unless ($Handle && $Handle->dbh && $Handle->dbh->ping) {
+        $Handle = RT::Handle->new();
+    } 
+    $Handle->Connect();
+}
+    
 =head2 InitLogging
 
 Create the RT::Logger object. 
@@ -282,8 +294,15 @@ sub DropSetGIDPermissions {
 
 =head1 BUGS
 
+Please report them to rt-3.0-bugs@fsck.com, if you know what's broken and have at least some idea of what needs to be fixed.
+If you're not sure what's going on, report them rt-devel@lists.fsck.com.
+
 =head1 SEE ALSO
 
+L<RT::StyleGuide>
+L<DBIx::SearchBuilder>
+
+
 
 =begin testing
 
index 81f7bdd..f58b8f2 100755 (executable)
@@ -74,10 +74,18 @@ sub SetReturnAddress {
     }
     
     unless ($self->TemplateObj->MIMEObj->head->get('From')) {
-       my $friendly_name = $self->TicketObj->QueueObj->Description ||
-               $self->TicketObj->QueueObj->Name;
-       $friendly_name =~ s/"/\\"/g;
-       $self->SetHeader('From', "\"$friendly_name\" <$replyto>");
+       if ($RT::UseFriendlyFromLine) {
+           my $friendly_name = $self->TicketObj->QueueObj->Description ||
+                   $self->TicketObj->QueueObj->Name;
+           $friendly_name =~ s/"/\\"/g;
+           $self->SetHeader( 'From',
+                       sprintf($RT::FriendlyFromLineFormat, 
+                $self->MIMEEncodeString( $friendly_name, $RT::EmailOutputEncoding ), $replyto),
+           );
+       }
+       else {
+           $self->SetHeader( 'From', $replyto );
+       }
     }
     
     unless ($self->TemplateObj->MIMEObj->head->get('Reply-To')) {
index dac8fc8..6592380 100755 (executable)
@@ -129,7 +129,7 @@ sub Commit {
     $self->SetHeader( 'Cc', join ( ',', @{ $self->{'Cc'} } ) )
       if ( $self->{'Cc'} && @{ $self->{'Cc'} } );
     $self->SetHeader( 'Bcc', join ( ',', @{ $self->{'Bcc'} } ) )
-      if ( $self->{'Cc'} && @{ $self->{'Bcc'} } );
+      if ( $self->{'Bcc'} && @{ $self->{'Bcc'} } );
 
 
     $self->SetHeader('MIME-Version', '1.0');
@@ -266,7 +266,7 @@ sub SendMessage {
            and ( !$MIMEObj->head->get('To') ) );
     if ( $RT::MailCommand eq 'sendmailpipe' ) {
         eval {
-            open( MAIL, "|$RT::SendmailPath $RT::SendmailArguments" );
+            open( MAIL, "|$RT::SendmailPath $RT::SendmailArguments" ) || die $!;
             print MAIL $MIMEObj->as_string;
             close(MAIL);
           };
index 4ca2f98..7fcc65c 100755 (executable)
@@ -70,7 +70,7 @@ sub _Init  {
     $self->Load($Name);
   }
   
-  $self->CurrentUser($self);
# $self->CurrentUser($self);
 
 }
 # }}}
@@ -104,15 +104,13 @@ sub Delete {
 sub UserObj {
     my $self = shift;
     
-    unless ($self->{'UserObj'}) {
        use RT::User;
-       $self->{'UserObj'} = RT::User->new($self);
-       unless ($self->{'UserObj'}->Load($self->Id)) {
+       my $user = RT::User->new($self);
+
+       unless ($user->Load($self->Id)) {
            $RT::Logger->err($self->loc("Couldn't load [_1] from the users database.\n", $self->Id));
        }
-       
-    }
-    return ($self->{'UserObj'});
+    return ($user);
 }
 # }}}
 
@@ -160,6 +158,7 @@ sub _Accessible  {
              Gecos => 'read',
              RealName => 'read',
              Password => 'neither',
+          Lang => 'read',
              EmailAddress => 'read',
              Privileged => 'read',
              IsAdministrator => 'read'
@@ -241,6 +240,11 @@ sub Load  {
   if ($identifier !~ /\D/) {
     $self->SUPER::LoadById($identifier);
   }
+
+  elsif (UNIVERSAL::isa($identifier,"RT::User")) { 
+         # DWIM if they pass a user in 
+         $self->SUPER::LoadById($identifier->Id); 
+  } 
   else {
       # This is a bit dangerous, we might get false authen if somebody
       # uses ambigous userids or real names:
@@ -329,6 +333,9 @@ sub LanguageHandle {
     if  ((!defined $self->{'LangHandle'}) || 
          (!UNIVERSAL::can($self->{'LangHandle'}, 'maketext')) || 
          (@_))  {
+       if ( $self->Lang) {
+           push @_, $self->Lang;
+       }
         $self->{'LangHandle'} = RT::I18N->get_handle(@_);
     }
     # Fall back to english.
@@ -365,6 +372,19 @@ sub loc_fuzzy {
 }
 # }}}
 
+
+=head2 CurrentUser
+
+Return  the current currentuser object
+
+=cut
+
+sub CurrentUser  {
+    my $self = shift;
+    return($self);
+
+}
+
 eval "require RT::CurrentUser_Vendor";
 die $@ if ($@ && $@ !~ qr{^Can't locate RT/CurrentUser_Vendor.pm});
 eval "require RT::CurrentUser_Local";
index 5cdb65e..9b611b9 100644 (file)
@@ -60,9 +60,12 @@ Takes nothing. Calls SUPER::Connect with the needed args
 sub Connect {
 my $self=shift;
 
-# Unless the database port is a positive integer, we really don't want to pass it.
 
-$self->SUPER::Connect(
+    if ($RT::DatabaseType eq 'Oracle') {
+        $ENV{'NLS_LANG'} = ".UTF8";
+    }
+
+    $self->SUPER::Connect(
                         User => $RT::DatabaseUser,
                         Password => $RT::DatabasePassword,
                        );
@@ -79,9 +82,11 @@ from the config file.
 
 sub BuildDSN {
     my $self = shift;
+# Unless the database port is a positive integer, we really don't want to pass it.
 $RT::DatabasePort = undef unless (defined $RT::DatabasePort && $RT::DatabasePort =~ /^(\d+)$/);
 $RT::DatabaseHost = undef unless (defined $RT::DatabaseHost && $RT::DatabaseHost ne '');
 
+
     $self->SUPER::BuildDSN(Host => $RT::DatabaseHost, 
                         Database => $RT::DatabaseName, 
                         Port => $RT::DatabasePort,
index ec0e877..a3c840a 100644 (file)
@@ -33,7 +33,7 @@ BEGIN {
     use vars qw ($VERSION  @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
     
     # set the version for version checking
-    $VERSION = do { my @r = (q$Revision: 1.2 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker
+    $VERSION = do { my @r = (q$Revision: 1.1.1.1 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker
     
     @ISA         = qw(Exporter);
     
index 7eec050..241f5f3 100755 (executable)
@@ -27,14 +27,14 @@ use strict;
 use Mail::Address;
 use MIME::Entity;
 use RT::EmailParser;
-
+use File::Temp;
 
 BEGIN {
     use Exporter ();
     use vars qw ($VERSION  @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
     
     # set the version for version checking
-    $VERSION = do { my @r = (q$Revision: 1.2 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker
+    $VERSION = do { my @r = (q$Revision: 1.1.1.2 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker
     
     @ISA         = qw(Exporter);
     
@@ -153,6 +153,7 @@ sub MailError {
                Subject => 'There has been an error',
                Explanation => 'Unexplained error',
                MIMEObj => undef,
+        Attach => undef,
                LogLevel => 'crit',
                @_);
 
@@ -175,7 +176,13 @@ sub MailError {
         $mimeobj->sync_headers();
         $entity->add_part($mimeobj);
     }
-    
+   
+    if ($args{'Attach'}) {
+        $entity->attach(Data => $args{'Attach'}, Type => 'message/rfc822');
+
+    }
+
     if ($RT::MailCommand eq 'sendmailpipe') {
         open (MAIL, "|$RT::SendmailPath $RT::SendmailArguments") || return(0);
         print MAIL $entity->as_string;
@@ -194,12 +201,6 @@ sub CreateUser {
     my ($Username, $Address, $Name, $ErrorsTo, $entity) = @_;
     my $NewUser = RT::User->new($RT::SystemUser);
 
-    # This data is tainted by some Very Broken mailers.
-    # (Sometimes they send raw ISO 8859-1 data here. fear that.
-    require Encode;
-    $Username = Encode::encode(utf8 => $Username, Encode::FB_PERLQQ()) if defined $Username;
-    $Name = Encode::encode(utf8 => $Name, Encode::FB_PERLQQ()) if defined $Name;
-    
     my ($Val, $Message) = 
       $NewUser->Create(Name => ($Username || $Address),
                        EmailAddress => $Address,
@@ -361,36 +362,108 @@ sub ParseAddressFromHeader{
 
 
 
-=head2 Gateway
+=head2 Gateway ARGSREF
+
+
+Takes parameters:
+
+    action
+    queue
+    message
+
 
 This performs all the "guts" of the mail rt-mailgate program, and is
 designed to be called from the web interface with a message, user
 object, and so on.
 
+Returns:
+
+    An array of:
+    
+    (status code, message, optional ticket object)
+
+    status code is a numeric value.
+
+    for temporary failures, status code should be -75
+
+    for permanent failures which are handled by RT, status code should be 0
+    
+    for succces, the status code should be 1
+
+
+
 =cut
 
 sub Gateway {
-    my %args = ( message => undef,
-                 queue   => 1,
-                 action  => 'correspond',
-                 ticket  => undef,
-                 @_ );
+    my $argsref = shift;
+
+    my %args = %$argsref;
+
+    # Set some reasonable defaults
+    $args{'action'} = 'correspond' unless ( $args{'action'} );
+    $args{'queue'}  = '1'          unless ( $args{'queue'} );
 
     # Validate the action
     unless ( $args{'action'} =~ /^(comment|correspond|action)$/ ) {
 
         # Can't safely loc this. What object do we loc around?
-        return ( 0, "Invalid 'action' parameter", undef );
+        $RT::Logger->crit("Mail gateway called with an invalid action paramenter '".$args{'action'}."' for queue '".$args{'queue'}."'");
+
+        return ( -75, "Invalid 'action' parameter", undef );
     }
 
     my $parser = RT::EmailParser->new();
-    $parser->ParseMIMEEntityFromScalar( $args{'message'} );
+    my ( $fh, $temp_file );
+    for ( 1 .. 10 ) {
+
+        # on NFS and NTFS, it is possible that tempfile() conflicts
+        # with other processes, causing a race condition. we try to
+        # accommodate this by pausing and retrying.
+        last if ( $fh, $temp_file ) = eval { File::Temp::tempfile(undef, UNLINK => 0) };
+        sleep 1;
+    }
+    if ($fh) {
+        binmode $fh;    #thank you, windows
+        $fh->autoflush(1);
+        print $fh $args{'message'};
+        close($fh);
+
+        if ( -f $temp_file ) {
+            $parser->ParseMIMEEntityFromFile($temp_file);
+            File::Temp::unlink0( $fh, $temp_file );
+            if ($parser->Entity) {
+                delete $args{'message'};
+            }
+        }
+
+    }
+
+    #If for some reason we weren't able to parse the message using a temp file 
+    # try it with a scalar
+    if ($args{'message'}) {
+        $parser->ParseMIMEEntityFromScalar($args{'message'});
+
+    } 
+
+    if (!$parser->Entity()) {
+        MailError(
+            To          => $RT::OwnerEmail,
+            Subject     => "RT Bounce: Unparseable message",
+            Explanation => "RT couldn't process the message below",
+            Attach     => $args{'message'}
+        );
+
+        return(0,"Failed to parse this message. Something is likely badly wrong with the message");
+    }
 
     my $Message = $parser->Entity();
-    my $head = $Message->head;
+    my $head    = $Message->head;
 
     my ( $CurrentUser, $AuthStat, $status, $error );
 
+    # Initalize AuthStat so comparisons work correctly
+    $AuthStat = -9999999;
+
     my $ErrorsTo = ParseErrorsToAddressFromHead($head);
 
     my $MessageId = $head->get('Message-Id')
@@ -400,37 +473,31 @@ sub Gateway {
     my $Subject = $head->get('Subject') || '';
     chomp $Subject;
 
-
     $args{'ticket'} ||= $parser->ParseTicketId($Subject);
 
     my $SystemTicket;
-    if ($args{'ticket'} ) {
+    if ( $args{'ticket'} ) {
         $SystemTicket = RT::Ticket->new($RT::SystemUser);
-        $SystemTicket->Load($args{'ticket'});
+        $SystemTicket->Load( $args{'ticket'} );
     }
 
     #Set up a queue object
     my $SystemQueueObj = RT::Queue->new($RT::SystemUser);
     $SystemQueueObj->Load( $args{'queue'} );
 
-
     # We can safely have no queue of we have a known-good ticket
     unless ( $args{'ticket'} || $SystemQueueObj->id ) {
-        MailError(
-                 To          => $RT::OwnerEmail,
-                 Subject     => "RT Bounce: $Subject",
-                 Explanation => "RT couldn't find the queue: " . $args{'queue'},
-                 MIMEObj     => $Message );
-        return ( 0, "RT couldn't find the queue: " . $args{'queue'}, undef );
+        return ( -75, "RT couldn't find the queue: " . $args{'queue'}, undef );
     }
 
     # Authentication Level
-    # -1 - Get out.  this user has been explicitly declined 
+    # -1 - Get out.  this user has been explicitly declined
     # 0 - User may not do anything (Not used at the moment)
     # 1 - Normal user
     # 2 - User is allowed to specify status updates etc. a la enhanced-mailgate
 
-    push @RT::MailPlugins, "Auth::MailFrom"   unless @RT::MailPlugins;
+    push @RT::MailPlugins, "Auth::MailFrom" unless @RT::MailPlugins;
+
     # Since this needs loading, no matter what
 
     for (@RT::MailPlugins) {
@@ -453,35 +520,59 @@ sub Gateway {
             }
         }
 
-        ( $CurrentUser, $NewAuthStat ) = $Code->( Message     => $Message,
-                                                  CurrentUser => $CurrentUser,
-                                                  AuthLevel   => $AuthStat,
-                                                  Action => $args{'action'},
-                                                  Ticket => $SystemTicket,
-                                                  Queue  => $SystemQueueObj );
+        ( $CurrentUser, $NewAuthStat ) = $Code->(
+            Message     => $Message,
+            CurrentUser => $CurrentUser,
+            AuthLevel   => $AuthStat,
+            Action      => $args{'action'},
+            Ticket      => $SystemTicket,
+            Queue       => $SystemQueueObj
+        );
+
+        # If a module returns a "-1" then we discard the ticket, so.
+        $AuthStat = -1 if $NewAuthStat == -1;
 
         # You get the highest level of authentication you were assigned.
-        last if $AuthStat == -1;
         $AuthStat = $NewAuthStat if $NewAuthStat > $AuthStat;
+        last if $AuthStat == -1;
     }
 
     # {{{ If authentication fails and no new user was created, get out.
     if ( !$CurrentUser or !$CurrentUser->Id or $AuthStat == -1 ) {
 
         # If the plugins refused to create one, they lose.
-        MailError(
-            Subject     => "Could not load a valid user",
-            Explanation => <<EOT,
+        unless ( $AuthStat == -1 ) {
+
+            # Notify the RT Admin of the failure.
+            # XXX Should this be configurable?
+            MailError(
+                To          => $RT::OwnerEmail,
+                Subject     => "Could not load a valid user",
+                Explanation => <<EOT,
 RT could not load a valid user, and RT's configuration does not allow
-for the creation of a new user for your email.
+for the creation of a new user for this email ($ErrorsTo).
 
-Your RT administrator needs to grant 'Everyone' the right 'CreateTicket'
-for this queue.
+You might need to grant 'Everyone' the right 'CreateTicket' for the
+queue @{[$args{'queue'}]}.
 
 EOT
-            MIMEObj  => $Message,
-            LogLevel => 'error' )
-          unless $AuthStat == -1;
+                MIMEObj  => $Message,
+                LogLevel => 'error'
+            );
+
+            # Also notify the requestor that his request has been dropped.
+            MailError(
+                To          => $ErrorsTo,
+                Subject     => "Could not load a valid user",
+                Explanation => <<EOT,
+RT could not load a valid user, and RT's configuration does not allow
+for the creation of a new user for your email.
+
+EOT
+                MIMEObj  => $Message,
+                LogLevel => 'error'
+            );
+        }
         return ( 0, "Could not load a valid user", undef );
     }
 
@@ -508,10 +599,11 @@ EOT
     # {{{ Drop it if it's disallowed
     if ( $AuthStat == 0 ) {
         MailError(
-             To          => $ErrorsTo,
-             Subject     => "Permission Denied",
-             Explanation => "You do not have permission to communicate with RT",
-             MIMEObj     => $Message );
+            To          => $ErrorsTo,
+            Subject     => "Permission Denied",
+            Explanation => "You do not have permission to communicate with RT",
+            MIMEObj     => $Message
+        );
     }
 
     # }}}
@@ -523,10 +615,12 @@ EOT
 
         #Should we mail it to RTOwner?
         if ($RT::LoopsToRTOwner) {
-            MailError( To          => $RT::OwnerEmail,
-                       Subject     => "RT Bounce: $Subject",
-                       Explanation => "RT thinks this message may be a bounce",
-                       MIMEObj     => $Message );
+            MailError(
+                To          => $RT::OwnerEmail,
+                Subject     => "RT Bounce: $Subject",
+                Explanation => "RT thinks this message may be a bounce",
+                MIMEObj     => $Message
+            );
 
             #Do we actually want to store it?
             return ( 0, "Message Bounced", undef ) unless ($RT::StoreLoops);
@@ -538,8 +632,10 @@ EOT
     # {{{ Squelch replies if necessary
     # Don't let the user stuff the RT-Squelch-Replies-To header.
     if ( $head->get('RT-Squelch-Replies-To') ) {
-        $head->add( 'RT-Relocated-Squelch-Replies-To',
-                    $head->get('RT-Squelch-Replies-To') );
+        $head->add(
+            'RT-Relocated-Squelch-Replies-To',
+            $head->get('RT-Squelch-Replies-To')
+        );
         $head->delete('RT-Squelch-Replies-To');
     }
 
@@ -564,22 +660,27 @@ EOT
         my @Requestors = ( $CurrentUser->id );
 
         if ($RT::ParseNewMessageForTicketCcs) {
-            @Cc = ParseCcAddressesFromHead( Head        => $head,
-                                            CurrentUser => $CurrentUser,
-                                            QueueObj    => $SystemQueueObj );
+            @Cc = ParseCcAddressesFromHead(
+                Head        => $head,
+                CurrentUser => $CurrentUser,
+                QueueObj    => $SystemQueueObj
+            );
         }
 
         my ( $id, $Transaction, $ErrStr ) = $Ticket->Create(
-                                                      Queue     => $SystemQueueObj->Id,
-                                                      Subject   => $Subject,
-                                                      Requestor => \@Requestors,
-                                                      Cc        => \@Cc,
-                                                      MIMEObj   => $Message );
+            Queue     => $SystemQueueObj->Id,
+            Subject   => $Subject,
+            Requestor => \@Requestors,
+            Cc        => \@Cc,
+            MIMEObj   => $Message
+        );
         if ( $id == 0 ) {
-            MailError( To          => $ErrorsTo,
-                       Subject     => "Ticket creation failed",
-                       Explanation => $ErrStr,
-                       MIMEObj     => $Message );
+            MailError(
+                To          => $ErrorsTo,
+                Subject     => "Ticket creation failed",
+                Explanation => $ErrStr,
+                MIMEObj     => $Message
+            );
             $RT::Logger->error("Create failed: $id / $Transaction / $ErrStr ");
             return ( 0, "Ticket creation failed", $Ticket );
         }
@@ -591,15 +692,17 @@ EOT
 
     #   If the action is comment, add a comment.
     elsif ( $args{'action'} =~ /^(comment|correspond)$/i ) {
-        $Ticket->Load($args{'ticket'});
+        $Ticket->Load( $args{'ticket'} );
         unless ( $Ticket->Id ) {
-            my $message = "Could not find a ticket with id ".$args{'ticket'};
-            MailError( To          => $ErrorsTo,
-                     Subject     => "Message not recorded",
-                     Explanation => $message,
-                     MIMEObj     => $Message );
-
-            return ( 0, $message);
+            my $message = "Could not find a ticket with id " . $args{'ticket'};
+            MailError(
+                To          => $ErrorsTo,
+                Subject     => "Message not recorded",
+                Explanation => $message,
+                MIMEObj     => $Message
+            );
+
+            return ( 0, $message );
         }
 
         my ( $status, $msg );
@@ -612,10 +715,12 @@ EOT
         unless ($status) {
 
             #Warn the sender that we couldn't actually submit the comment.
-            MailError( To          => $ErrorsTo,
-                       Subject     => "Message not recorded",
-                       Explanation => $msg,
-                       MIMEObj     => $Message );
+            MailError(
+                To          => $ErrorsTo,
+                Subject     => "Message not recorded",
+                Explanation => $msg,
+                MIMEObj     => $Message
+            );
             return ( 0, "Message not recorded", $Ticket );
         }
     }
@@ -623,21 +728,28 @@ EOT
     else {
 
         #Return mail to the sender with an error
-        MailError( To          => $ErrorsTo,
-                   Subject     => "RT Configuration error",
-                   Explanation => "'"
-                     . $args{'action'}
-                     . "' not a recognized action."
-                     . " Your RT administrator has misconfigured "
-                     . "the mail aliases which invoke RT",
-                   MIMEObj => $Message );
+        MailError(
+            To          => $ErrorsTo,
+            Subject     => "RT Configuration error",
+            Explanation => "'"
+              . $args{'action'}
+              . "' not a recognized action."
+              . " Your RT administrator has misconfigured "
+              . "the mail aliases which invoke RT",
+            MIMEObj => $Message
+        );
         $RT::Logger->crit( $args{'action'} . " type unknown for $MessageId" );
-        return ( 0, "Configuration error: " . $args{'action'} . " not a recognized action", $Ticket );
+        return (
+            -75,
+            "Configuration error: "
+              . $args{'action'}
+              . " not a recognized action",
+            $Ticket
+        );
 
     }
 
-
-return ( 1, "Success", $Ticket );
+    return ( 1, "Success", $Ticket );
 }
 
 eval "require RT::Interface::Email_Vendor";
index 5097f54..8d66239 100644 (file)
@@ -68,6 +68,7 @@ sub NewApacheHandler {
         default_escape_flags => 'h',
         allow_globals        => [qw(%session)],
         data_dir => "$RT::MasonDataDir",
+        autoflush => 1,
         @_
     );
 
@@ -98,7 +99,8 @@ sub NewCGIHandler {
         ],
         data_dir => "$RT::MasonDataDir",
         default_escape_flags => 'h',
-        allow_globals        => [qw(%session)]
+        allow_globals        => [qw(%session)],
+        autoflush => 1,
     );
   
 
@@ -137,6 +139,60 @@ sub EscapeUTF8  {
 
 # }}}
 
+# {{{ WebCanonicalizeInfo
+
+=head2 WebCanonicalizeInfo();
+
+Different web servers set different environmental varibles. This
+function must return something suitable for REMOTE_USER. By default,
+just downcase $ENV{'REMOTE_USER'}
+
+=cut
+
+sub WebCanonicalizeInfo {
+    my $user;
+
+    if ( defined $ENV{'REMOTE_USER'} ) {
+       $user = lc ( $ENV{'REMOTE_USER'} ) if( length($ENV{'REMOTE_USER'}) );
+    }
+
+    return $user;
+}
+
+# }}}
+
+# {{{ WebExternalAutoInfo
+
+=head2 WebExternalAutoInfo($user);
+
+Returns a hash of user attributes, used when WebExternalAuto is set.
+
+=cut
+
+sub WebExternalAutoInfo {
+    my $user = shift;
+
+    my %user_info;
+
+    $user_info{'Privileged'} = 1;
+
+    if ($^O !~ /^(?:riscos|MacOS|MSWin32|dos|os2)$/) {
+       # Populate fields with information from Unix /etc/passwd
+
+       my ($comments, $realname) = (getpwnam($user))[5, 6];
+       $user_info{'Comments'} = $comments if defined $comments;
+       $user_info{'RealName'} = $realname if defined $realname;
+    }
+    elsif ($^O eq 'MSWin32' and eval 'use Net::AdminMisc; 1') {
+       # Populate fields with information from NT domain controller
+    }
+
+    # and return the wad of stuff
+    return {%user_info};
+}
+
+# }}}
+
 
 package HTML::Mason::Commands;
 use strict;
@@ -160,10 +216,13 @@ sub loc {
         UNIVERSAL::can($session{'CurrentUser'}, 'loc')){
         return($session{'CurrentUser'}->loc(@_));
     }
-    else  {
-        my $u = RT::CurrentUser->new($RT::SystemUser);
+    elsif ( my $u = eval { RT::CurrentUser->new($RT::SystemUser->Id) } ) {
         return ($u->loc(@_));
     }
+    else {
+       # pathetic case -- SystemUser is gone.
+       return $_[0];
+    }
 }
 
 # }}}
@@ -189,7 +248,7 @@ sub loc_fuzzy {
         return($session{'CurrentUser'}->loc_fuzzy($msg));
     }
     else  {
-        my $u = RT::CurrentUser->new($RT::SystemUser);
+        my $u = RT::CurrentUser->new($RT::SystemUser->Id);
         return ($u->loc_fuzzy($msg));
     }
 }
@@ -365,7 +424,8 @@ sub ProcessUpdateMessage {
     );
 
     #Make the update content have no 'weird' newlines in it
-    if ( $args{ARGSRef}->{'UpdateContent'} ) {
+    if ( $args{ARGSRef}->{'UpdateContent'} ||
+        $args{ARGSRef}->{'UpdateAttachments'}) {
 
         if (
             $args{ARGSRef}->{'UpdateSubject'} eq $args{'TicketObj'}->Subject() )
@@ -433,7 +493,8 @@ sub MakeMIMEEntity {
         Cc                  => undef,
         Body                => undef,
         AttachmentFieldName => undef,
-        map Encode::encode_utf8($_), @_,
+#        map Encode::encode_utf8($_), @_,
+        @_,
     );
 
     #Make the update content have no 'weird' newlines in it
@@ -449,6 +510,7 @@ sub MakeMIMEEntity {
             Subject => $args{'Subject'} || "",
             From    => $args{'From'},
             Cc      => $args{'Cc'},
+            Charset => 'utf8',
             Data    => [ $args{'Body'} ]
         );
     }
@@ -463,7 +525,14 @@ sub MakeMIMEEntity {
 
     #foreach my $filehandle (@filenames) {
 
-    my ( $fh, $temp_file ) = tempfile();
+    my ( $fh, $temp_file );
+    for ( 1 .. 10 ) {
+        # on NFS and NTFS, it is possible that tempfile() conflicts
+        # with other processes, causing a race condition. we try to
+        # accommodate this by pausing and retrying.
+        last if ($fh, $temp_file) = eval { tempfile() };
+        sleep 1;
+    }
 
     binmode $fh;    #thank you, windows
     my ($buffer);
@@ -481,7 +550,7 @@ sub MakeMIMEEntity {
 
     $Message->attach(
         Path     => $temp_file,
-        Filename => $filename,
+        Filename => Encode::decode_utf8($filename),
         Type     => $uploadinfo->{'Content-Type'},
     );
     close($fh);
@@ -594,13 +663,13 @@ sub ProcessSearchQuery {
 
     # }}}
     # {{{ Limit requestor email
+     if ( $args{ARGS}->{'ValueOfWatcherRole'} ne '' ) {
+         $session{'tickets'}->LimitWatcher(
+             TYPE     => $args{ARGS}->{'WatcherRole'},
+             VALUE    => $args{ARGS}->{'ValueOfWatcherRole'},
+             OPERATOR => $args{ARGS}->{'WatcherRoleOp'},
 
-    if ( $args{ARGS}->{'ValueOfRequestor'} ne '' ) {
-        my $alias = $session{'tickets'}->LimitRequestor(
-            VALUE    => $args{ARGS}->{'ValueOfRequestor'},
-            OPERATOR => $args{ARGS}->{'RequestorOp'},
         );
-
     }
 
     # }}}
@@ -780,17 +849,13 @@ sub ProcessACLChanges {
 
             my $obj;
 
-            if ($object_type eq 'RT::Queue') {
-                $obj = RT::Queue->new($session{'CurrentUser'});
-                $obj->Load($object_id);      
-            } elsif ($object_type eq 'RT::Group') {
-                $obj = RT::Group->new($session{'CurrentUser'});
-                $obj->Load($object_id);      
-
-            } elsif ($object_type eq 'RT::System') {
+             if ($object_type eq 'RT::System') {
                 $obj = $RT::System;
+           } elsif ($RT::ACE::OBJECT_TYPES{$object_type}) {
+                $obj = $object_type->new($session{'CurrentUser'});
+                $obj->Load($object_id);      
             } else {
-                push (@results, loc("System Error").
+                push (@results, loc("System Error"). ': '.
                                 loc("Rights could not be granted for [_1]", $object_type));
                 next;
             }
@@ -813,17 +878,14 @@ sub ProcessACLChanges {
             next unless ($right);
             my $obj;
 
-            if ($object_type eq 'RT::Queue') {
-                $obj = RT::Queue->new($session{'CurrentUser'});
-                $obj->Load($object_id);      
-            } elsif ($object_type eq 'RT::Group') {
-                $obj = RT::Group->new($session{'CurrentUser'});
-                $obj->Load($object_id);      
-
-            } elsif ($object_type eq 'RT::System') {
+             if ($object_type eq 'RT::System') {
                 $obj = $RT::System;
+           } elsif ($RT::ACE::OBJECT_TYPES{$object_type}) {
+                $obj = $object_type->new($session{'CurrentUser'});
+                $obj->Load($object_id);      
             } else {
-                push (@results, loc("System Error").
+               die;
+                push (@results, loc("System Error"). ': '.
                                 loc("Rights could not be revoked for [_1]", $object_type));
                 next;
             }
@@ -953,6 +1015,17 @@ sub ProcessCustomFieldUpdates {
         my ( $err, $msg ) = $Object->DeleteValue($id);
         push ( @results, $msg );
     }
+
+    my $vals = $Object->Values();
+    while (my $cfv = $vals->Next()) {
+        if (my $so = $ARGSRef->{ 'CustomField-' . $Object->Id . '-SortOrder' . $cfv->Id }) {
+            if ($cfv->SortOrder != $so) {
+                my ( $err, $msg ) = $cfv->SetSortOrder($so);
+                push ( @results, $msg );
+            }
+        }
+    }
+
     return (@results);
 }
 
@@ -1050,8 +1123,11 @@ sub ProcessTicketCustomFieldUpdates {
 
     # For each of those tickets
     foreach my $tick ( keys %custom_fields_to_mod ) {
-        my $Ticket = RT::Ticket->new( $session{'CurrentUser'} );
-        $Ticket->Load($tick);
+        my $Ticket = $args{'TicketObj'};
+       if (!$Ticket or $Ticket->id != $tick) {
+           $Ticket = RT::Ticket->new( $session{'CurrentUser'} );
+           $Ticket->Load($tick);
+       }
 
         # For each custom field  
         foreach my $cf ( keys %{ $custom_fields_to_mod{$tick} } ) {
@@ -1074,10 +1150,10 @@ sub ProcessTicketCustomFieldUpdates {
                 my @values =
                   ( ref( $ARGSRef->{$arg} ) eq 'ARRAY' ) 
                   ? @{ $ARGSRef->{$arg} }
-                  : ( $ARGSRef->{$arg} );
+                  : split /\n/, $ARGSRef->{$arg} ;
                 if ( ( $arg =~ /-AddValue$/ ) || ( $arg =~ /-Value$/ ) ) {
                     foreach my $value (@values) {
-                        next unless ($value);
+                        next unless length($value);
                         my ( $val, $msg ) = $Ticket->AddCustomFieldValue(
                             Field => $cf,
                             Value => $value
@@ -1087,7 +1163,7 @@ sub ProcessTicketCustomFieldUpdates {
                 }
                 elsif ( $arg =~ /-DeleteValues$/ ) {
                     foreach my $value (@values) {
-                        next unless ($value);
+                        next unless length($value);
                         my ( $val, $msg ) = $Ticket->DeleteCustomFieldValue(
                             Field => $cf,
                             Value => $value
@@ -1100,7 +1176,7 @@ sub ProcessTicketCustomFieldUpdates {
 
                     my %values_hash;
                     foreach my $value (@values) {
-                        next unless ($value);
+                        next unless length($value);
 
                         # build up a hash of values that the new set has
                         $values_hash{$value} = 1;
index 6962221..7a86906 100755 (executable)
@@ -211,7 +211,10 @@ sub LoadByCols {
                 $newhash{$key} = $hash{$key};
             }
             else {
-                $newhash{ "lower(" . $key . ")" } = lc( $hash{$key} );
+                my ($op, $val);
+                ($key, $op, $val) = $self->_Handle->_MakeClauseCaseInsensitive($key, '=', $hash{$key});
+                $newhash{$key}->{operator} = $op;
+                $newhash{$key}->{value} = $val;
             }
         }