[Rt-commit] r5599 - in rt/branches/3.6-RELEASE: . bin etc html/Admin/Groups html/REST/1.0/NoAuth html/SelfService html/Ticket html/Ticket/Elements lib lib/RT lib/RT/Condition lib/RT/Interface lib/RT/Interface/Web lib/RT/URI lib/t/regression sbin

jesse at bestpractical.com jesse at bestpractical.com
Tue Jul 18 17:51:40 EDT 2006


Author: jesse
Date: Tue Jul 18 17:51:35 2006
New Revision: 5599

Added:
   rt/branches/3.6-RELEASE/lib/t/regression/23-web_attachments.t
Modified:
   rt/branches/3.6-RELEASE/   (props changed)
   rt/branches/3.6-RELEASE/bin/rt-crontool.in
   rt/branches/3.6-RELEASE/config.layout
   rt/branches/3.6-RELEASE/etc/RT_Config.pm.in
   rt/branches/3.6-RELEASE/html/Admin/Groups/index.html
   rt/branches/3.6-RELEASE/html/REST/1.0/Forms/ticket/default
   rt/branches/3.6-RELEASE/html/REST/1.0/NoAuth/mail-gateway
   rt/branches/3.6-RELEASE/html/SelfService/Create.html
   rt/branches/3.6-RELEASE/html/Ticket/Create.html
   rt/branches/3.6-RELEASE/html/Ticket/Display.html
   rt/branches/3.6-RELEASE/html/Ticket/Elements/PreviewScrips
   rt/branches/3.6-RELEASE/html/Ticket/Elements/ShowHistory
   rt/branches/3.6-RELEASE/html/Ticket/Elements/ShowRequestor
   rt/branches/3.6-RELEASE/lib/RT.pm.in
   rt/branches/3.6-RELEASE/lib/RT/Attachment_Overlay.pm
   rt/branches/3.6-RELEASE/lib/RT/Condition/Generic.pm
   rt/branches/3.6-RELEASE/lib/RT/CustomField_Overlay.pm
   rt/branches/3.6-RELEASE/lib/RT/Date.pm
   rt/branches/3.6-RELEASE/lib/RT/Interface/Email.pm
   rt/branches/3.6-RELEASE/lib/RT/Interface/Web.pm
   rt/branches/3.6-RELEASE/lib/RT/Interface/Web/Handler.pm
   rt/branches/3.6-RELEASE/lib/RT/Link_Overlay.pm
   rt/branches/3.6-RELEASE/lib/RT/Links_Overlay.pm
   rt/branches/3.6-RELEASE/lib/RT/Ticket_Overlay.pm
   rt/branches/3.6-RELEASE/lib/RT/Tickets_Overlay.pm
   rt/branches/3.6-RELEASE/lib/RT/Transaction_Overlay.pm
   rt/branches/3.6-RELEASE/lib/RT/URI.pm
   rt/branches/3.6-RELEASE/lib/RT/URI/base.pm
   rt/branches/3.6-RELEASE/lib/RT/URI/fsck_com_rt.pm
   rt/branches/3.6-RELEASE/lib/t/regression/06mailgateway.t
   rt/branches/3.6-RELEASE/lib/t/regression/22search_tix_by_txn.t
   rt/branches/3.6-RELEASE/sbin/rt-setup-database.in

Log:
 r37203 at truegrounds:  jesse | 2006-07-18 13:08:57 -0400
  r30313 at truegrounds:  jesse | 2006-03-23 01:36:27 -0500
  * Better mp2 bulletproofing
  r30314 at truegrounds:  jesse | 2006-03-23 01:36:42 -0500
  
  r37202 at truegrounds:  jesse | 2006-07-18 12:49:01 -0400
   r31084 at truegrounds (orig r4814):  jesse | 2006-03-23 22:40:37 -0500
    r10436 at hualien:  jesse | 2006-03-23 22:40:25 -0500
    * It helps when there aren't typos
   
   r31117 at truegrounds (orig r4847):  alexmv | 2006-03-28 15:50:07 -0500
    r11918 at zoq-fot-pik:  chmrr | 2006-03-28 15:49:56 -0500
     * Backport TXN fixes from 3.7 and 3.5
   
   r31194 at truegrounds (orig r4924):  jesse | 2006-03-30 21:07:23 -0500
    r10636 at hualien:  jesse | 2006-03-31 11:06:57 +0900
    RT-Ticket: 7398
    RT-Status: resolved
    RT-Update: correspond
    
    * Added a "RH" RedHat layout option to config.layout  -- Paulo Matos
   
   r31317 at truegrounds (orig r5047):  ruz | 2006-04-17 20:40:06 -0400
   * check and report error to the logs
   r31330 at truegrounds (orig r5060):  jesse | 2006-04-24 10:49:40 -0400
    r11842 at hualien:  jesse | 2006-04-24 10:49:13 -0400
    The following patch adds the useful LastUpdated field to the fields
    returned through the REST interface.
    David - who starts to wonder if his patches are actually read by someone :-)
    --
    David Schweikert        | phone: +41 44 632 7019
    System manager ISG.EE   | walk:  ETH Zentrum, ETL F24.1
    ETH Zurich, Switzerland | web:   http://people.ee.ethz.ch/dws
    
   
   r31334 at truegrounds (orig r5064):  ruz | 2006-04-24 16:42:43 -0400
   * max subject is 200 character long
   r31335 at truegrounds (orig r5065):  ruz | 2006-04-24 17:25:15 -0400
   * convert only if $enc'oding contains something
   r31336 at truegrounds (orig r5066):  ruz | 2006-04-24 20:21:32 -0400
   * simple tests for Attachments manipulation from web interface
   r31385 at truegrounds (orig r5115):  ruz | 2006-04-25 19:24:45 -0400
   * (cond) && 'selected' outputs 0 if condition fails on my system 
   r31386 at truegrounds (orig r5116):  ruz | 2006-04-25 19:35:09 -0400
   * get queue ID from page
   r31388 at truegrounds (orig r5118):  jesse | 2006-04-25 22:43:31 -0400
    r11882 at hualien:  jesse | 2006-04-25 22:43:11 -0400
    * Mark Eichin picked up that http://lists.fsck.com/pipermail/rt-devel/2004-August/006216.html had never been applied. 
    
    rt ls -l broke because of it, if your RT server wasn't at / 
   
   r31453 at truegrounds (orig r5183):  jesse | 2006-05-08 22:31:56 -0400
    r13313 at hualien:  jesse | 2006-05-08 12:01:55 -0400
     * Finding disabled groups should actually find them, now
   
   r31454 at truegrounds (orig r5184):  jesse | 2006-05-08 22:32:10 -0400
    r13314 at hualien:  jesse | 2006-05-08 12:14:26 -0400
    * Minor reformatting
   
   r31455 at truegrounds (orig r5185):  jesse | 2006-05-08 22:32:19 -0400
    r13315 at hualien:  jesse | 2006-05-08 22:31:30 -0400
    * Mail gateway refactoring to make added functioanlity a bit easier. 
      No (intentional) functional changes.
   
   r31456 at truegrounds (orig r5186):  jesse | 2006-05-08 22:56:20 -0400
    r13330 at hualien:  jesse | 2006-05-08 22:55:56 -0400
     * Reed Loden caught a perltidy error that, somewhat terrifiyingly, was still a valid mason page
   
   r31457 at truegrounds (orig r5187):  jesse | 2006-05-09 00:48:10 -0400
    r13332 at hualien:  jesse | 2006-05-09 00:47:49 -0400
    * Mismatched parens
   
   r31476 at truegrounds (orig r5206):  ruz | 2006-05-11 16:48:53 -0400
   * return values checking and more logging on errors
   r31477 at truegrounds (orig r5207):  ruz | 2006-05-11 16:56:24 -0400
   * more checks on attachments processing
   r31478 at truegrounds (orig r5208):  ruz | 2006-05-11 18:24:17 -0400
   * if ( not $xxx || $xxx->foo ) is equivalent to
     if ( not ( $xxx || $xxx->foo ) ) due to perl5 rules
     which is not expected behaviour
   r31479 at truegrounds (orig r5209):  ruz | 2006-05-11 18:31:58 -0400
   * user do next steps:
       1) open ticket #1
       2) click reply
       3) upload attachment
       4) open ticket #2 in another browser window
       5) send reply to the ticket #1
     RT looses uploaded attachment due to step 4) as RT tries
     to add attchement to the ticket #2 and drops them from session.
     As solution don't ProcessTicketMessage if there is attachments,
     but only if there is real update message.
   r31486 at truegrounds (orig r5216):  ruz | 2006-05-12 16:54:41 -0400
   * add Timezone argument in SetToMidnight
   r31487 at truegrounds (orig r5217):  ruz | 2006-05-12 17:02:54 -0400
   * use SetToMidnight( Timezone => 'server' ) to calc start and end of the day
   r31488 at truegrounds (orig r5218):  ruz | 2006-05-12 20:31:33 -0400
   * get rid of "masks earlier declaration" warnings
   r31508 at truegrounds (orig r5238):  ruz | 2006-05-16 18:39:59 -0400
   * really noisy warning
     *NOTE* that option we use is not described in config
   r31519 at truegrounds (orig r5249):  ruz | 2006-05-18 12:17:47 -0400
   * add bug comment
   r31526 at truegrounds (orig r5256):  ruz | 2006-05-18 21:45:58 -0400
   * allow to complete actions in mail plugins
   r31527 at truegrounds (orig r5257):  ruz | 2006-05-18 21:53:40 -0400
   * minor
   r31538 at truegrounds (orig r5268):  jesse | 2006-05-19 17:17:41 -0400
    r13935 at hualien:  jesse | 2006-05-19 17:17:27 -0400
    * There were divergent copies of this code. The EmailParser code was more correct
   
   r31580 at truegrounds (orig r5310):  ruz | 2006-05-26 20:39:49 -0400
   * when we could parse URI, for example object doesn't exist
     fallback to RT::URI::base resolver, so $uri->IsLocal and
     other methods wouldn't die but return undef
   r31585 at truegrounds (orig r5315):  ruz | 2006-05-28 07:19:20 -0400
   * Use "Requestor.id = $requestor->id" search instead of search by email address
     as latter is not indexed
   r31587 at truegrounds (orig r5317):  ruz | 2006-05-30 16:13:02 -0400
   * If current user changes owner from somebody else to nobody user,
     the action fails with "You can only reassign tickets that you own
     or that are unowned", but we must change owner if he has no right
     to own tickets in dest queue. Do it with Force and with SystemUser
     context.
   r31670 at truegrounds (orig r5400):  ruz | 2006-06-16 20:40:24 -0400
   * not default mail plugins has been broken during last refactoring
   ** move a code back into its scope
   ** don't forget to store $_ in $Class when $_ matches ^RT::Interface::Email
   r35569 at truegrounds (orig r5476):  ruz | 2006-06-27 17:21:07 -0400
   * nothing special, small changes I'd changed during
     the hunt over a bug
   r35573 at truegrounds (orig r5480):  ruz | 2006-06-27 20:05:49 -0400
   * minor formatting
   r35575 at truegrounds (orig r5482):  ruz | 2006-06-28 17:25:18 -0400
   * add tests for unsafe mailgate commands
   * fix bugs that were introduced during Email.pm refactoring
   r35589 at truegrounds (orig r5496):  ruz | 2006-06-30 16:09:08 -0400
   Changes:
   * new config option $OldestTransactionsFirst that allow
     administrator to reverse order of transactions on
     history page
   
   r36191 at truegrounds (orig r5520):  ruz | 2006-07-04 01:36:46 -0400
   * forgot to add option to config
   r36192 at truegrounds (orig r5521):  ruz | 2006-07-04 01:38:03 -0400
   * report error when couldn't create CF
   r36193 at truegrounds (orig r5522):  ruz | 2006-07-04 01:39:21 -0400
   * we never should call exit from libs
   r36205 at truegrounds (orig r5534):  ruz | 2006-07-06 11:19:46 -0400
   rt-crontool
   * add --transaction argument with two possible values: 'first' and 'last'
   * add --transaction-type argument to allow users select type of transactions
   ** these transactions would be passed to scrips for processing, so users
      can use conditions, actions and templates that check or use properties of
      transaction
   
   * also some existant actions, conditions and templates require scrip or
     scrip action objects to process normally, as we have no these objects
     available we now pass void (not loaded) objects. This change would allow
     users to use notify actions with crontool.
   r36241 at truegrounds (orig r5570):  kevinr | 2006-07-13 16:21:31 -0400
    r14836 at sad-girl-in-snow:  kevinr | 2006-07-13 16:17:43 -0400
    * The RT::Condition::Generic docs were wrong... fixed.
   
  
 


Modified: rt/branches/3.6-RELEASE/bin/rt-crontool.in
==============================================================================
--- rt/branches/3.6-RELEASE/bin/rt-crontool.in	(original)
+++ rt/branches/3.6-RELEASE/bin/rt-crontool.in	Tue Jul 18 17:51:35 2006
@@ -75,19 +75,28 @@
 }
 
 my ( $search, $condition, $action, $search_arg, $condition_arg, $action_arg,
-     $template_id, $help, $verbose );
-GetOptions( "search=s"        => \$search,
-            "search-arg=s"    => \$search_arg,
-            "condition=s"     => \$condition,
-            "condition-arg=s" => \$condition_arg,
-            "action-arg=s"    => \$action_arg,
-            "action=s"        => \$action,
-	    "template-id=s"   => \$template_id,
-            "help"            => \$help,
-            "verbose|v"       => \$verbose );
+     $template_id, $transaction, $transaction_type, $help, $verbose );
+GetOptions( "search=s"           => \$search,
+            "search-arg=s"       => \$search_arg,
+            "condition=s"        => \$condition,
+            "condition-arg=s"    => \$condition_arg,
+            "action-arg=s"       => \$action_arg,
+            "action=s"           => \$action,
+            "template-id=s"      => \$template_id,
+            "transaction=s"      => \$transaction,
+            "transaction-type=s" => \$transaction_type,
+            "help"               => \$help,
+            "verbose|v"          => \$verbose );
 
 help() if $help or not $search or not $action;
 
+$transaction ||= 'first';
+unless ( $transaction =~ /^(first|last)$/i ) {
+    print STDERR loc("--transaction argument could be only 'first' or 'last'");
+    exit 1;
+}
+$transaction = lc($transaction) eq 'first'? 'ASC': 'DESC';
+
 # We _must_ have a search object
 load_module($search);
 load_module($action)    if ($action);
@@ -99,6 +108,8 @@
     $template_obj = RT::Template->new($CurrentUser);
     $template_obj->Load($template_id);
 }
+my $void_scrip = RT::Scrip->new( $CurrentUser );
+my $void_scrip_action = RT::ScripAction->new( $CurrentUser );
 
 #At the appointed time:
 
@@ -119,11 +130,20 @@
 while ( my $ticket = $tickets->Next() ) {
     print $ticket->Id() . ": " if ($verbose);
 
+    my $transaction = get_transaction($ticket);
+    print loc("Using transaction #[_1]...", $transaction->id)
+        if $verbose && $transaction;
+
     # perform some more advanced check
     if ($condition) {
-        my $condition_obj = $condition->new( TicketObj => $ticket,
-                                             Argument  => $condition_arg,
-                                             CurrentUser => $CurrentUser );
+        my $condition_obj = $condition->new(
+            TransactionObj => $transaction,
+            TicketObj      => $ticket,
+            ScripObj       => $void_scrip,
+            TemplateObj    => $template_obj,
+            Argument       => $condition_arg,
+            CurrentUser    => $CurrentUser,
+        );
 
         # if the condition doesn't apply, get out of here
 
@@ -133,10 +153,13 @@
 
     #prepare our action
     my $action_obj = $action->new(
-        TicketObj   => $ticket,
-        TemplateObj => $template_obj,
-        Argument    => $action_arg,
-        CurrentUser => $CurrentUser
+        TicketObj      => $ticket,
+        TransactionObj => $transaction,
+        TemplateObj    => $template_obj,
+        Argument       => $action_arg,
+        ScripObj       => $void_scrip,
+        ScripActionObj => $void_scrip_action,
+        CurrentUser    => $CurrentUser,
     );
 
     #if our preparation, move onto the next ticket
@@ -148,6 +171,26 @@
     print loc("Action committed.\n") if ($verbose);
 }
 
+=head2 get_transaction
+
+Takes ticket and returns its transaction acording to command
+line arguments C<--transaction> and <--transaction-type>.
+
+=cut
+
+sub get_transaction {
+    my $ticket = shift;
+    my $txns = $ticket->Transactions;
+    $txns->OrderByCols(
+        { FIELD => 'Created', ORDER => $transaction },
+        { FIELD => 'id', ORDER => $transaction },
+    );
+    $txns->Limit( FIELD => 'Type', VALUE => $transaction_type )
+        if $transaction_type;
+    $txns->RowsPerPage(1);
+    return $txns->First;
+}
+
 # {{{ load_module 
 
 =head2 load_module
@@ -207,6 +250,15 @@
       . loc( "[_1] - An argument to pass to [_2]", "--action-argument", "--action" )
       . "\n";
     print "	"
+      . loc( "[_1] - Specify id of the template you want to use", "--template-id" )
+      . "\n";
+    print "	"
+      . loc( "[_1] - Specify if you want to use either 'first' or 'last' tarnsaction", "--transaction" )
+      . "\n";
+    print "	"
+      . loc( "[_1] - Specify the type of a transaction you want to use", "--transaction-type" )
+      . "\n";
+    print "	"
       . loc( "[_1] - Output status updates to STDOUT", "--verbose" ) . "\n";
     print "\n";
     print "\n";

Modified: rt/branches/3.6-RELEASE/config.layout
==============================================================================
--- rt/branches/3.6-RELEASE/config.layout	(original)
+++ rt/branches/3.6-RELEASE/config.layout	Tue Jul 18 17:51:35 2006
@@ -127,3 +127,26 @@
   customlexdir:		${customdir}/po
   customlibdir:		${customdir}/lib
 </Layout>
+
+#   RH path layout.
+<Layout RH>
+  prefix:		/usr/
+  exec_prefix:		${prefix}
+  bindir:		${exec_prefix}/bin
+  sbindir:		${exec_prefix}/sbin
+  sysconfdir:		/etc/rt
+  mandir:		${prefix}/man
+  libdir:		${prefix}/lib/rt
+  datadir:		/var/rt
+  htmldir:		${datadir}/html
+  manualdir:		${datadir}/doc
+  localstatedir:	/var/
+  logfiledir:		${localstatedir}/log/rt
+  masonstatedir:	${localstatedir}/rt/mason_data
+  sessionstatedir:	${localstatedir}/rt/session_data
+  customdir:		${prefix}/local/rt
+  custometcdir:		${customdir}/etc
+  customhtmldir:	${customdir}/html
+  customlexdir:		${customdir}/po
+  customlibdir:		${customdir}/lib
+</Layout>

Modified: rt/branches/3.6-RELEASE/etc/RT_Config.pm.in
==============================================================================
--- rt/branches/3.6-RELEASE/etc/RT_Config.pm.in	(original)
+++ rt/branches/3.6-RELEASE/etc/RT_Config.pm.in	Tue Jul 18 17:51:35 2006
@@ -439,6 +439,11 @@
 
 Set($DefaultSummaryRows, 10);
 
+# By default, RT shows newest transactions at the bottom of the ticket
+# history page, if you want see them at the top set this to '0'.
+
+Set($OldestTransactionsFirst, '1');
+
 
 # $HomepageComponents is an arrayref of allowed components on a user's
 # customized homepage ("RT at a glance").

Modified: rt/branches/3.6-RELEASE/html/Admin/Groups/index.html
==============================================================================
--- rt/branches/3.6-RELEASE/html/Admin/Groups/index.html	(original)
+++ rt/branches/3.6-RELEASE/html/Admin/Groups/index.html	Tue Jul 18 17:51:35 2006
@@ -78,6 +78,10 @@
 my $title = loc('Select a group');
 my $caption;
 
+if ($FindDisabledGroups) {
+    $Groups->FindAllRows();
+}
+
 if (length $GroupString) {
     $caption = loc("Groups matching search criteria");
     if ($GroupField =~ /^CustomField-(\d+)/) {

Modified: rt/branches/3.6-RELEASE/html/REST/1.0/Forms/ticket/default
==============================================================================
--- rt/branches/3.6-RELEASE/html/REST/1.0/Forms/ticket/default	(original)
+++ rt/branches/3.6-RELEASE/html/REST/1.0/Forms/ticket/default	Tue Jul 18 17:51:35 2006
@@ -58,7 +58,7 @@
 my ($c, $o, $k, $e) = ("", [], {}, 0);
 my %data   = %$changes;
 my $ticket = new RT::Ticket $session{CurrentUser};
-my @dates  = qw(Created Starts Started Due Resolved Told);
+my @dates  = qw(Created Starts Started Due Resolved Told LastUpdated);
 my @people = qw(Requestors Cc AdminCc);
 my @create = qw(Queue Requestor Subject Cc AdminCc Owner Status Priority
                 InitialPriority FinalPriority TimeEstimated TimeWorked

Modified: rt/branches/3.6-RELEASE/html/REST/1.0/NoAuth/mail-gateway
==============================================================================
--- rt/branches/3.6-RELEASE/html/REST/1.0/NoAuth/mail-gateway	(original)
+++ rt/branches/3.6-RELEASE/html/REST/1.0/NoAuth/mail-gateway	Tue Jul 18 17:51:35 2006
@@ -53,26 +53,30 @@
 </%ARGS>
 <%init>
 $m->comp('/Elements/Callback', _CallbackName => 'Pre', %ARGS);
-use RT::Interface::Email; 
+use RT::Interface::Email ();    # It's an exporter, but we don't care
 $r->content_type('text/plain; charset=utf-8');
 $m->error_format('text');
-my ( $status, $error, $Ticket ) = RT::Interface::Email::Gateway(\%ARGS);
- if ($status == -75 ) {
-$m->out("temporary failure - ". $error);
- }
-    elsif ($status == 1) {
-$m->out('ok');
-        if ( $Ticket->Id ) {
-$m->out('Ticket: '. $Ticket->Id);
-$m->out('Queue: '. $Ticket->QueueObj->Name );
-$m->out('Owner: '. $Ticket->OwnerObj->Name);
-$m->out('Status: '. $Ticket->Status );
-$m->out('Subject: '. $Ticket->Subject );
-$m->out('Requestor: '. $Ticket->Requestors->MemberEmailAddressesAsString );
-        }
- }   else { 
-$m->out('not ok - '.$error);
- }
-
+my ( $status, $error, $Ticket ) = RT::Interface::Email::Gateway( \%ARGS );
+if ( $status == 1 ) {
+  $m->out('ok');
+  if ( $Ticket->Id ) {
+    $m->out( 'Ticket: ' . $Ticket->Id );
+    $m->out( 'Queue: ' . $Ticket->QueueObj->Name );
+    $m->out( 'Owner: ' . $Ticket->OwnerObj->Name );
+    $m->out( 'Status: ' . $Ticket->Status );
+    $m->out( 'Subject: ' . $Ticket->Subject );
+    $m->out(
+      'Requestor: ' . $Ticket->Requestors->MemberEmailAddressesAsString );
+  }
+}
+else {
+  $RT::Logger->error( "Could not record email: " . $error );
+  if ( $status == -75 ) {
+    $m->out( "temporary failure - " . $error );
+  }
+  else {
+    $m->out( 'not ok - ' . $error );
+  }
+}
 $m->abort();
 </%init>

Modified: rt/branches/3.6-RELEASE/html/SelfService/Create.html
==============================================================================
--- rt/branches/3.6-RELEASE/html/SelfService/Create.html	(original)
+++ rt/branches/3.6-RELEASE/html/SelfService/Create.html	Tue Jul 18 17:51:35 2006
@@ -79,7 +79,7 @@
 <&|/l&>Subject</&>:
 </td>
 <td class="value">
-<input name="Subject" size="60" maxsize="100" value="" />
+<input name="Subject" size="60" maxsize="200" value="" />
 </td>
 </tr>
 <tr>

Modified: rt/branches/3.6-RELEASE/html/Ticket/Create.html
==============================================================================
--- rt/branches/3.6-RELEASE/html/Ticket/Create.html	(original)
+++ rt/branches/3.6-RELEASE/html/Ticket/Create.html	Tue Jul 18 17:51:35 2006
@@ -107,7 +107,7 @@
 <&|/l&>Subject</&>:
 </td>
 <td class="value" colspan="5">
-<input name="Subject" size="60" maxsize="100" value="<%$ARGS{Subject} || ''%>" />
+<input name="Subject" size="60" maxsize="200" value="<%$ARGS{Subject} || ''%>" />
 </td>
 </tr>
 <tr>

Modified: rt/branches/3.6-RELEASE/html/Ticket/Display.html
==============================================================================
--- rt/branches/3.6-RELEASE/html/Ticket/Display.html	(original)
+++ rt/branches/3.6-RELEASE/html/Ticket/Display.html	Tue Jul 18 17:51:35 2006
@@ -127,17 +127,19 @@
     }
 
     $ARGS{'UpdateContent'} =~ s/\r\n/\n/g if defined $ARGS{'UpdateContent'};
-    if ( $ARGS{'UpdateTimeWorked'} ||
-	 $session{'Attachments'} || 
-	 (   defined $ARGS{'UpdateContent'}
-             && $ARGS{'UpdateContent'} ne ''
-	     && $ARGS{'UpdateContent'} ne "-- \n"
-	     . $session{'CurrentUser'}->UserObj->Signature )) {
-	$ARGS{UpdateAttachments} = $session{'Attachments'};
-	ProcessUpdateMessage( ARGSRef   => \%ARGS,
-			      Actions   => \@Actions,
-			      TicketObj => $TicketObj );
-	delete $session{'Attachments'};
+    if ( $ARGS{'UpdateTimeWorked'} || (
+        defined $ARGS{'UpdateContent'}
+        && $ARGS{'UpdateContent'} ne ''
+	    && $ARGS{'UpdateContent'} ne "-- \n"
+	       . $session{'CurrentUser'}->UserObj->Signature ) )
+    {
+	    $ARGS{UpdateAttachments} = $session{'Attachments'};
+	    ProcessUpdateMessage(
+            ARGSRef   => \%ARGS,
+			Actions   => \@Actions,
+			TicketObj => $TicketObj,
+        );
+	    delete $session{'Attachments'};
     }
     #Process status updates
     my @BasicActions = ProcessTicketBasics(ARGSRef => \%ARGS, TicketObj=>$TicketObj);

Modified: rt/branches/3.6-RELEASE/html/Ticket/Elements/PreviewScrips
==============================================================================
--- rt/branches/3.6-RELEASE/html/Ticket/Elements/PreviewScrips	(original)
+++ rt/branches/3.6-RELEASE/html/Ticket/Elements/PreviewScrips	Tue Jul 18 17:51:35 2006
@@ -86,6 +86,9 @@
     TimeTaken    => $ARGS{'UpdateTimeWorked'},
     DryRun       => 1
 );
+unless ( $Transaction ) {
+    $RT::Logger->error("Coulfn't fire '$action' action: $Description");
+}
 
 
 my @non_recipients = $TicketObj->SquelchMailTo;

Modified: rt/branches/3.6-RELEASE/html/Ticket/Elements/ShowHistory
==============================================================================
--- rt/branches/3.6-RELEASE/html/Ticket/Elements/ShowHistory	(original)
+++ rt/branches/3.6-RELEASE/html/Ticket/Elements/ShowHistory	Tue Jul 18 17:51:35 2006
@@ -134,8 +134,16 @@
 } else {
     $Transactions = $Ticket->Transactions;
 }
-my $i;
 
+
+my $OldestFirst = $RT::OldestTransactionsFirst? 'DESC': 'ASC';
+$Transactions->OrderByCols( { FIELD => 'Created',
+                              ORDER => $OldestFirst },
+                            { FIELD => 'id',
+                              ORDER => $OldestFirst },
+                          );
+
+my $i;
 $Attachments ||=  $m->comp('/Ticket/Elements/FindAttachments', Ticket => $Ticket, Tickets => $Tickets || undef);
 $AttachmentContent ||= $m->comp('/Ticket/Elements/LoadTextAttachments', Ticket => $Ticket);
 

Modified: rt/branches/3.6-RELEASE/html/Ticket/Elements/ShowRequestor
==============================================================================
--- rt/branches/3.6-RELEASE/html/Ticket/Elements/ShowRequestor	(original)
+++ rt/branches/3.6-RELEASE/html/Ticket/Elements/ShowRequestor	Tue Jul 18 17:51:35 2006
@@ -47,18 +47,15 @@
 my $rows = 10;
 my $people = $Ticket->Requestors->UserMembersObj;
 while (my $requestor=$people->Next) {
+next if $requestor->Privileged;
 my $name=$requestor->RealName || $requestor->EmailAddress;	
 my $tickets = RT::Tickets->new($session{'CurrentUser'});
 my $has_right_adminusers = $session{'CurrentUser'}->HasRight(Object => $RT::System, Right => 'AdminUsers');
-$tickets->LimitWatcher(TYPE => 'Requestor', VALUE => $requestor->EmailAddress );
-$tickets->LimitStatus( VALUE => 'open');
-$tickets->LimitStatus( VALUE => 'new');
+$tickets->FromSQL( "Requestor.id = ". $requestor->id ." AND (Status = 'open' OR Status = 'new')" );
 $tickets->RowsPerPage($rows);
-$tickets->OrderBy(FIELD => 'Priority',
-		  ORDER => 'DESC');
+$tickets->OrderBy(FIELD => 'Priority', ORDER => 'DESC');
 </%PERL>
 
-% unless ($requestor->Privileged) {
 <&| /Widgets/TitleBox, title_href => $has_right_adminusers ? "$RT::WebPath/Admin/Users/Modify.html?id=".$requestor->id : undef, title=> loc("More about [_1]", $name) &>
 
 %# Additional information about this user.  Empty by default.
@@ -80,7 +77,6 @@
 
 </&>
 
-% }
 %}
 <%ARGS>
 $Ticket=>undef

Modified: rt/branches/3.6-RELEASE/lib/RT.pm.in
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT.pm.in	(original)
+++ rt/branches/3.6-RELEASE/lib/RT.pm.in	Tue Jul 18 17:51:35 2006
@@ -311,19 +311,13 @@
 
 #When we call die, trap it and log->crit with the value of the die.
 
-    $SIG{__DIE__}  = sub {
-        unless ($^S || !defined $^S ) {
-            $RT::Handle->Rollback();
-            $RT::Logger->crit("$_[0]");
-            # XXX: we should never exit, even if we are not in eval context
-            # could someone explane this code?
-            exit(-1);
-        }
-        else {
-            # Get out of here if we're in an eval
-            die $_[0];
-        }
-    };
+$SIG{__DIE__}  = sub {
+    unless ($^S || !defined $^S ) {
+        $RT::Handle->Rollback();
+        $RT::Logger->crit("$_[0]");
+    }
+    die $_[0];
+};
 
 # }}}
 

Modified: rt/branches/3.6-RELEASE/lib/RT/Attachment_Overlay.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/Attachment_Overlay.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/Attachment_Overlay.pm	Tue Jul 18 17:51:35 2006
@@ -295,7 +295,7 @@
     eval {return( Encode::decode_utf8($content))} || return ($content);
   }
   
-  eval { Encode::from_to($content, 'utf8' => $enc);};
+  eval { Encode::from_to($content, 'utf8' => $enc) } if $enc;
   if ($@) {
 	$RT::Logger->error("Could not convert attachment from assumed utf8 to '$enc' :".$@);
   }

Modified: rt/branches/3.6-RELEASE/lib/RT/Condition/Generic.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/Condition/Generic.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/Condition/Generic.pm	Tue Jul 18 17:51:35 2006
@@ -50,7 +50,7 @@
 =head1 SYNOPSIS
 
     use RT::Condition::Generic;
-    my $foo = new RT::Condition::IsApplicable( 
+    my $foo = RT::Condition::Generic->new( 
 		TransactionObj => $tr, 
 		TicketObj => $ti, 
 		ScripObj => $scr, 

Modified: rt/branches/3.6-RELEASE/lib/RT/CustomField_Overlay.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/CustomField_Overlay.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/CustomField_Overlay.pm	Tue Jul 18 17:51:35 2006
@@ -941,10 +941,10 @@
     if ( $ObjectCF->Id ) {
         return ( 0, $self->loc("That is already the current value") );
     }
-    my ( $ret, $msg ) =
+    my ( $oid, $msg ) =
       $ObjectCF->Create( ObjectId => $id, CustomField => $self->Id );
 
-    return ( $ret, $msg );
+    return ( $oid, $msg );
 }
 
 
@@ -976,9 +976,10 @@
     unless ( $ObjectCF->Id ) {
         return ( 0, $self->loc("This custom field does not apply to that object") );
     }
-    my ( $ret, $msg ) = $ObjectCF->Delete;
+    # XXX: Delete doesn't return anything
+    my ( $oid, $msg ) = $ObjectCF->Delete;
 
-    return ( $ret, $msg );
+    return ( $oid, $msg );
 }
 
 # {{{ AddValueForObject

Modified: rt/branches/3.6-RELEASE/lib/RT/Date.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/Date.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/Date.pm	Tue Jul 18 17:51:35 2006
@@ -225,23 +225,28 @@
 
 # {{{ sub SetToMidnight 
 
-=head2 SetToMidnight
+=head2 SetToMidnight [Timezone => 'utc']
 
-Sets the date to midnight (at the beginning of the day) GMT
+Sets the date to midnight (at the beginning of the day).
 Returns the unixtime at midnight.
 
+Arguments:
+
+=over 4
+
+=item Timezone - Timezone context C<server> or C<UTC>
+
 =cut
 
 sub SetToMidnight {
     my $self = shift;
-    
-    use Time::Local;
-    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime($self->Unix);
-    $self->Unix(timegm (0,0,0,$mday,$mon,$year,$wday,$yday));
-    
+    my %args = ( Timezone => 'UTC', @_ );
+    if ( lc $args{'Timezone'} eq 'server' ) {
+        $self->Unix( Time::Local::timelocal( 0,0,0,(localtime $self->Unix)[3..7] ) );
+    } else {
+        $self->Unix( Time::Local::timegm( 0,0,0,(gmtime $self->Unix)[3..7] ) );
+    }
     return ($self->Unix);
-    
-    
 }
 
 

Modified: rt/branches/3.6-RELEASE/lib/RT/Interface/Email.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/Interface/Email.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/Interface/Email.pm	Tue Jul 18 17:51:35 2006
@@ -1,38 +1,38 @@
 # BEGIN BPS TAGGED BLOCK {{{
-# 
+#
 # COPYRIGHT:
 #  
 # This software is Copyright (c) 1996-2006 Best Practical Solutions, LLC 
 #                                          <jesse at 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-# 
-# 
+#
+#
 # 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
@@ -41,7 +41,7 @@
 # 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::Interface::Email;
 
@@ -50,31 +50,32 @@
 use MIME::Entity;
 use RT::EmailParser;
 use File::Temp;
+use UNIVERSAL::require;
 
 BEGIN {
     use Exporter ();
-    use vars qw ($VERSION  @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
-    
+    use vars qw ( @ISA @EXPORT_OK);
+
     # 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
-    
-    @ISA         = qw(Exporter);
-    
+    our $VERSION = 2.0;
+
+    @ISA = qw(Exporter);
+
     # your exported package globals go here,
     # as well as any optionally exported functions
-    @EXPORT_OK   = qw(
-              &CreateUser
-              &GetMessageContent
-              &CheckForLoops 
-              &CheckForSuspiciousSender
-              &CheckForAutoGenerated 
-              &CheckForBounce 
-              &MailError 
-              &ParseCcAddressesFromHead
-              &ParseSenderAddressFromHead 
-              &ParseErrorsToAddressFromHead
-              &ParseAddressFromHeader
-              &Gateway);
+    @EXPORT_OK = qw(
+        &CreateUser
+        &GetMessageContent
+        &CheckForLoops
+        &CheckForSuspiciousSender
+        &CheckForAutoGenerated
+        &CheckForBounce
+        &MailError
+        &ParseCcAddressesFromHead
+        &ParseSenderAddressFromHead
+        &ParseErrorsToAddressFromHead
+        &ParseAddressFromHeader
+        &Gateway);
 
 }
 
@@ -103,19 +104,18 @@
 
 =cut
 
+# {{{ sub CheckForLoops
 
-# {{{ sub CheckForLoops 
-
-sub CheckForLoops  {
+sub CheckForLoops {
     my $head = shift;
-    
+
     #If this instance of RT sent it our, we don't want to take it in
     my $RTLoop = $head->get("X-RT-Loop-Prevention") || "";
-    chomp ($RTLoop); #remove that newline
-    if ($RTLoop eq "$RT::rtname") {
-	return (1);
+    chomp($RTLoop);    #remove that newline
+    if ( $RTLoop eq "$RT::rtname" ) {
+        return (1);
     }
-    
+
     # TODO: We might not trap the case where RT instance A sends a mail
     # to RT instance B which sends a mail to ...
     return (undef);
@@ -129,23 +129,24 @@
     my $head = shift;
 
     #if it's from a postmaster or mailer daemon, it's likely a bounce.
-    
+
     #TODO: better algorithms needed here - there is no standards for
     #bounces, so it's very difficult to separate them from anything
     #else.  At the other hand, the Return-To address is only ment to be
     #used as an error channel, we might want to put up a separate
     #Return-To address which is treated differently.
-    
+
     #TODO: search through the whole email and find the right Ticket ID.
 
-    my ($From, $junk) = ParseSenderAddressFromHead($head);
-    
-    if (($From =~ /^mailer-daemon\@/i) or
-	($From =~ /^postmaster\@/i)){
-	return (1);
-	
+    my ( $From, $junk ) = ParseSenderAddressFromHead($head);
+
+    if (   ( $From =~ /^mailer-daemon\@/i )
+        or ( $From =~ /^postmaster\@/i ) )
+    {
+        return (1);
+
     }
-    
+
     return (undef);
 
 }
@@ -155,15 +156,15 @@
 # {{{ sub CheckForAutoGenerated
 sub CheckForAutoGenerated {
     my $head = shift;
-    
-    my $Precedence = $head->get("Precedence") || "" ;
-    if ($Precedence =~ /^(bulk|junk)/i) {
-	return (1);
+
+    my $Precedence = $head->get("Precedence") || "";
+    if ( $Precedence =~ /^(bulk|junk)/i ) {
+        return (1);
     }
-    
+
     # First Class mailer uses this as a clue.
     my $FCJunk = $head->get("X-FC-Machinegenerated") || "";
-    if ($FCJunk =~ /^true/i) {
+    if ( $FCJunk =~ /^true/i ) {
         return (1);
     }
 
@@ -175,9 +176,9 @@
 # {{{ sub CheckForBounce
 sub CheckForBounce {
     my $head = shift;
-   
-    my $ReturnPath = $head->get("Return-path") || "" ;
-    return ($ReturnPath =~ /<>/);
+
+    my $ReturnPath = $head->get("Return-path") || "";
+    return ( $ReturnPath =~ /<>/ );
 }
 
 # }}}
@@ -195,11 +196,12 @@
 sub IsRTAddress {
     my $address = shift || '';
 
-    # Example: the following rule would tell RT not to Cc 
+    # Example: the following rule would tell RT not to Cc
     #   "tickets at noc.example.com"
-    if ( defined($RT::RTAddressRegexp) &&
-                       $address =~ /$RT::RTAddressRegexp/i ) {
-        return(1);
+    if ( defined($RT::RTAddressRegexp)
+        && $address =~ /$RT::RTAddressRegexp/i )
+    {
+        return (1);
     } else {
         return (undef);
     }
@@ -217,56 +219,61 @@
 =cut
 
 sub CullRTAddresses {
-    return (grep { IsRTAddress($_) } @_);
+    return ( grep { IsRTAddress($_) } @_ );
 }
 
 # }}}
 
-# {{{ sub MailError 
+# {{{ sub MailError
 sub MailError {
-    my %args = (To => $RT::OwnerEmail,
-		Bcc => undef,
-		From => $RT::CorrespondAddress,
-		Subject => 'There has been an error',
-		Explanation => 'Unexplained error',
-		MIMEObj => undef,
-        Attach => undef,
-		LogLevel => 'crit',
-		@_);
-
-
-    $RT::Logger->log(level => $args{'LogLevel'}, 
-		     message => $args{'Explanation'}
-		    );
-    my $entity = MIME::Entity->build( Type  =>"multipart/mixed",
-				      From => $args{'From'},
-				      Bcc => $args{'Bcc'},
-				      To => $args{'To'},
-				      Subject => $args{'Subject'},
-				      Precedence => 'bulk',
-				      'X-RT-Loop-Prevention' => $RT::rtname,
-				    );
+    my %args = (
+        To          => $RT::OwnerEmail,
+        Bcc         => undef,
+        From        => $RT::CorrespondAddress,
+        Subject     => 'There has been an error',
+        Explanation => 'Unexplained error',
+        MIMEObj     => undef,
+        Attach      => undef,
+        LogLevel    => 'crit',
+        @_
+    );
+
+    $RT::Logger->log(
+        level   => $args{'LogLevel'},
+        message => $args{'Explanation'}
+    );
+    my $entity = MIME::Entity->build(
+        Type                   => "multipart/mixed",
+        From                   => $args{'From'},
+        Bcc                    => $args{'Bcc'},
+        To                     => $args{'To'},
+        Subject                => $args{'Subject'},
+        Precedence             => 'bulk',
+        'X-RT-Loop-Prevention' => $RT::rtname,
+    );
+
+    $entity->attach( Data => $args{'Explanation'} . "\n" );
 
-    $entity->attach(  Data => $args{'Explanation'}."\n");
-    
     my $mimeobj = $args{'MIMEObj'};
     if ($mimeobj) {
         $mimeobj->sync_headers();
         $entity->add_part($mimeobj);
     }
-   
-    if ($args{'Attach'}) {
-        $entity->attach(Data => $args{'Attach'}, Type => 'message/rfc822');
+
+    if ( $args{'Attach'} ) {
+        $entity->attach( Data => $args{'Attach'}, Type => 'message/rfc822' );
 
     }
 
-    if ($RT::MailCommand eq 'sendmailpipe') {
-        open (MAIL, "|$RT::SendmailPath $RT::SendmailBounceArguments $RT::SendmailArguments") || return(0);
+    if ( $RT::MailCommand eq 'sendmailpipe' ) {
+        open( MAIL,
+            "|$RT::SendmailPath $RT::SendmailBounceArguments $RT::SendmailArguments"
+            )
+            || return (0);
         print MAIL $entity->as_string;
         close(MAIL);
-    }
-    else {
-    	$entity->send($RT::MailCommand, $RT::MailParams);
+    } else {
+        $entity->send( $RT::MailCommand, $RT::MailParams );
     }
 }
 
@@ -275,37 +282,39 @@
 # {{{ Create User
 
 sub CreateUser {
-    my ($Username, $Address, $Name, $ErrorsTo, $entity) = @_;
+    my ( $Username, $Address, $Name, $ErrorsTo, $entity ) = @_;
     my $NewUser = RT::User->new($RT::SystemUser);
 
-    my ($Val, $Message) = 
-      $NewUser->Create(Name => ($Username || $Address),
-                       EmailAddress => $Address,
-                       RealName => $Name,
-                       Password => undef,
-                       Privileged => 0,
-                       Comments => 'Autocreated on ticket submission'
-                      );
-    
+    my ( $Val, $Message ) = $NewUser->Create(
+        Name => ( $Username || $Address ),
+        EmailAddress => $Address,
+        RealName     => $Name,
+        Password     => undef,
+        Privileged   => 0,
+        Comments     => 'Autocreated on ticket submission'
+    );
+
     unless ($Val) {
-        
+
         # Deal with the race condition of two account creations at once
         #
         if ($Username) {
             $NewUser->LoadByName($Username);
         }
-        
-        unless ($NewUser->Id) {
+
+        unless ( $NewUser->Id ) {
             $NewUser->LoadByEmail($Address);
         }
-        
-        unless ($NewUser->Id) {  
-            MailError( To => $ErrorsTo,
-                       Subject => "User could not be created",
-                       Explanation => "User creation failed in mailgateway: $Message",
-                       MIMEObj => $entity,
-                       LogLevel => 'crit'
-                     );
+
+        unless ( $NewUser->Id ) {
+            MailError(
+                To          => $ErrorsTo,
+                Subject     => "User could not be created",
+                Explanation =>
+                    "User creation failed in mailgateway: $Message",
+                MIMEObj  => $entity,
+                LogLevel => 'crit'
+            );
         }
     }
 
@@ -313,21 +322,25 @@
     my $CurrentUser = RT::CurrentUser->new();
     $CurrentUser->LoadByEmail($Address);
 
-    unless ($CurrentUser->id) {
-            $RT::Logger->warning("Couldn't load user '$Address'.".  "giving up");
-                MailError( To => $ErrorsTo,
-                           Subject => "User could not be loaded",
-                           Explanation => "User  '$Address' could not be loaded in the mail gateway",
-                           MIMEObj => $entity,
-                           LogLevel => 'crit'
-                     );
+    unless ( $CurrentUser->id ) {
+        $RT::Logger->warning(
+            "Couldn't load user '$Address'." . "giving up" );
+        MailError(
+            To          => $ErrorsTo,
+            Subject     => "User could not be loaded",
+            Explanation =>
+                "User  '$Address' could not be loaded in the mail gateway",
+            MIMEObj  => $entity,
+            LogLevel => 'crit'
+        );
     }
 
     return $CurrentUser;
 }
+
 # }}}
 
-# {{{ ParseCcAddressesFromHead 
+# {{{ ParseCcAddressesFromHead
 
 =head2 ParseCcAddressesFromHead HASHREF
 
@@ -337,32 +350,34 @@
 email address  and anything that the configuration sub RT::IsRTAddress matches.
 
 =cut
-  
+
 sub ParseCcAddressesFromHead {
-    my %args = ( Head => undef,
-		 QueueObj => undef,
-		 CurrentUser => undef,
-		 @_ );
-    
+    my %args = (
+        Head        => undef,
+        QueueObj    => undef,
+        CurrentUser => undef,
+        @_
+    );
+
     my (@Addresses);
-        
-    my @ToObjs = Mail::Address->parse($args{'Head'}->get('To'));
-    my @CcObjs = Mail::Address->parse($args{'Head'}->get('Cc'));
-    
-    foreach my $AddrObj (@ToObjs, @CcObjs) {
-	my $Address = $AddrObj->address;
-	$Address = $args{'CurrentUser'}->UserObj->CanonicalizeEmailAddress($Address);
- 	next if ($args{'CurrentUser'}->EmailAddress =~ /^\Q$Address\E$/i);
-	next if ($args{'QueueObj'}->CorrespondAddress =~ /^\Q$Address\E$/i);
-	next if ($args{'QueueObj'}->CommentAddress =~ /^\Q$Address\E$/i);
-	next if (RT::EmailParser->IsRTAddress($Address));
-	
-	push (@Addresses, $Address);
+
+    my @ToObjs = Mail::Address->parse( $args{'Head'}->get('To') );
+    my @CcObjs = Mail::Address->parse( $args{'Head'}->get('Cc') );
+
+    foreach my $AddrObj ( @ToObjs, @CcObjs ) {
+        my $Address = $AddrObj->address;
+        $Address = $args{'CurrentUser'}
+            ->UserObj->CanonicalizeEmailAddress($Address);
+        next if ( $args{'CurrentUser'}->EmailAddress   =~ /^\Q$Address\E$/i );
+        next if ( $args{'QueueObj'}->CorrespondAddress =~ /^\Q$Address\E$/i );
+        next if ( $args{'QueueObj'}->CommentAddress    =~ /^\Q$Address\E$/i );
+        next if ( RT::EmailParser->IsRTAddress($Address) );
+
+        push( @Addresses, $Address );
     }
     return (@Addresses);
 }
 
-
 # }}}
 
 # {{{ ParseSenderAdddressFromHead
@@ -376,12 +391,14 @@
 
 sub ParseSenderAddressFromHead {
     my $head = shift;
+
     #Figure out who's sending this message.
-    my $From = $head->get('Reply-To') || 
-      $head->get('From') || 
-	$head->get('Sender');
-    return (ParseAddressFromHeader($From));
+    my $From = $head->get('Reply-To')
+        || $head->get('From')
+        || $head->get('Sender');
+    return ( ParseAddressFromHeader($From) );
 }
+
 # }}}
 
 # {{{ ParseErrorsToAdddressFromHead
@@ -396,18 +413,22 @@
 
 sub ParseErrorsToAddressFromHead {
     my $head = shift;
+
     #Figure out who's sending this message.
 
-    foreach my $header ('Return-path', 'Errors-To' , 'Reply-To', 'From', 'Sender' ) {
-	# If there's a header of that name
-	my $headerobj = $head->get($header);
-	if ($headerobj) {
-		my ($addr, $name ) = ParseAddressFromHeader($headerobj);
-		# If it's got actual useful content...
-		return ($addr) if ($addr);
-	}
+    foreach my $header ( 'Errors-To', 'Reply-To', 'From', 'Sender' ) {
+
+        # If there's a header of that name
+        my $headerobj = $head->get($header);
+        if ($headerobj) {
+            my ( $addr, $name ) = ParseAddressFromHeader($headerobj);
+
+            # If it's got actual useful content...
+            return ($addr) if ($addr);
+        }
     }
 }
+
 # }}}
 
 # {{{ ParseAddressFromHeader
@@ -418,31 +439,28 @@
 
 =cut
 
-
-sub ParseAddressFromHeader{
+sub ParseAddressFromHeader {
     my $Addr = shift;
-    
-    # Perl 5.8.0 breaks when doing regex matches on utf8
-    Encode::_utf8_off($Addr) if $] == 5.008;
+
     my @Addresses = Mail::Address->parse($Addr);
-    
+
     my $AddrObj = $Addresses[0];
 
-    unless (ref($AddrObj)) {
-	return(undef,undef);
+    unless ( ref($AddrObj) ) {
+        return ( undef, undef );
     }
- 
-    my $Name =  ($AddrObj->phrase || $AddrObj->comment || $AddrObj->address);
-    
+
+    my $Name = ( $AddrObj->phrase || $AddrObj->comment || $AddrObj->address );
+
     #Lets take the from and load a user object.
     my $Address = $AddrObj->address;
 
-    return ($Address, $Name);
+    return ( $Address, $Name );
 }
-# }}}
 
-# {{{ sub ParseTicketId 
+# }}}
 
+# {{{ sub ParseTicketId
 
 sub ParseTicketId {
     my $Subject = shift;
@@ -454,15 +472,13 @@
         my $id = $1;
         $RT::Logger->debug("Found a ticket ID. It's $id");
         return ($id);
-    }
-    else {
+    } else {
         return (undef);
     }
 }
 
 # }}}
 
-
 =head2 Gateway ARGSREF
 
 
@@ -501,50 +517,53 @@
 
 sub Gateway {
     my $argsref = shift;
+    my %args    = (
+        action  => 'correspond',
+        queue   => '1',
+        ticket  => undef,
+        message => undef,
+        %$argsref
+    );
 
-    my %args = %$argsref;
-
-    # Set some reasonable defaults
-    $args{'action'} ||= 'correspond';
-    $args{'queue'}  ||= '1';
+    my $SystemTicket;
+    my $Right;
 
     # Validate the action
-    my ($status, @actions) = IsCorrectAction( $args{'action'} );
-    unless ( $status ) {
-
-        # Can't safely loc this. What object do we loc around?
-        $RT::Logger->crit("Mail gateway called with an invalid action paramenter '".$actions[0]."' for queue '".$args{'queue'}."'");
-
-        return ( -75, "Invalid 'action' parameter", undef );
+    my ( $status, @actions ) = IsCorrectAction( $args{'action'} );
+    unless ($status) {
+        return (
+            -75,
+            "Invalid 'action' parameter "
+                . $actions[0]
+                . " for queue "
+                . $args{'queue'},
+            undef
+        );
     }
 
     my $parser = RT::EmailParser->new();
+    $parser->SmartParseMIMEEntityFromScalar( Message => $args{'message'} );
+    my $Message = $parser->Entity();
 
-    $parser->SmartParseMIMEEntityFromScalar( Message => $args{'message'});
-
-    if (!$parser->Entity()) {
+    unless ($Message) {
         MailError(
             To          => $RT::OwnerEmail,
             Subject     => "RT Bounce: Unparseable message",
             Explanation => "RT couldn't process the message below",
-            Attach     => $args{'message'}
+            Attach      => $args{'message'}
         );
 
-        return(0,"Failed to parse this message. Something is likely badly wrong with the 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 ( $CurrentUser, $AuthStat, $error );
-
-    # Initalize AuthStat so comparisons work correctly
-    $AuthStat = -9999999;
+    my $head = $Message->head;
 
     my $ErrorsTo = ParseErrorsToAddressFromHead($head);
 
     my $MessageId = $head->get('Message-ID')
-      || "<no-message-id-" . time . rand(2000) . "\@.$RT::Organization>";
+        || "<no-message-id-" . time . rand(2000) . "\@.$RT::Organization>";
 
     #Pull apart the subject line
     my $Subject = $head->get('Subject') || '';
@@ -552,13 +571,12 @@
 
     $args{'ticket'} ||= ParseTicketId($Subject);
 
-    my $SystemTicket;
-    my $Right = 'CreateTicket';
-    if ( $args{'ticket'} ) {
-        $SystemTicket = RT::Ticket->new($RT::SystemUser);
-        $SystemTicket->Load( $args{'ticket'} );
-	# if there's an existing ticket, this must be a reply
-	$Right = 'ReplyToTicket';
+    $SystemTicket = RT::Ticket->new($RT::SystemUser);
+    $SystemTicket->Load( $args{'ticket'} ) if ( $args{'ticket'} ) ;
+    if ( $SystemTicket->id ) {
+        $Right = 'ReplyToTicket';
+    } else {
+        $Right = 'CreateTicket';
     }
 
     #Set up a queue object
@@ -566,190 +584,124 @@
     $SystemQueueObj->Load( $args{'queue'} );
 
     # We can safely have no queue of we have a known-good ticket
-    unless ( $args{'ticket'} || $SystemQueueObj->id ) {
+    unless ( $SystemTicket->id || $SystemQueueObj->id ) {
         return ( -75, "RT couldn't find the queue: " . $args{'queue'}, undef );
     }
 
-    # Authentication Level
+    # Authentication Level ($AuthStat)
     # -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
+    my ( $CurrentUser, $AuthStat, $error );
+
+    # Initalize AuthStat so comparisons work correctly
+    $AuthStat = -9999999;
 
     push @RT::MailPlugins, "Auth::MailFrom" unless @RT::MailPlugins;
 
-    # Since this needs loading, no matter what
+    # if plugin returns AuthStat -2 we skip action
+    # NOTE: this is experimental API and it would be changed
+    my %skip_action = ();
 
+    # Since this needs loading, no matter what
     foreach (@RT::MailPlugins) {
-        my $Code;
-        my $NewAuthStat;
+        my ($Code, $NewAuthStat);
         if ( ref($_) eq "CODE" ) {
             $Code = $_;
-        }
-        else {
-            $_ = "RT::Interface::Email::".$_ unless $_ =~ /^RT::Interface::Email::/;
-            eval "require $_;";
-            if ($@) {
-                $RT::Logger->crit("Couldn't load module '$_': $@");
-                next;
-            }
+        } else {
+            my $Class = $_;
+            $Class = "RT::Interface::Email::" . $Class
+                unless $Class =~ /^RT::Interface::Email::/;
+            $Class->require or
+                do { $RT::Logger->error("Couldn't load $Class: $@"); next };
+
             no strict 'refs';
-            if ( !defined( $Code = *{ $_ . "::GetCurrentUser" }{CODE} ) ) {
-                $RT::Logger->crit("No GetCurrentUser code found in $_ module");
+            unless ( defined( $Code = *{ $Class . "::GetCurrentUser" }{CODE} ) ) {
+                $RT::Logger->crit( "No 'GetCurrentUser' function found in '$Class' module");
                 next;
             }
         }
 
-	foreach my $action ( @actions ) {
-
+        foreach my $action (@actions) {
             ( $CurrentUser, $NewAuthStat ) = $Code->(
-                Message     => $Message,
+                Message       => $Message,
                 RawMessageRef => \$args{'message'},
-                CurrentUser => $CurrentUser,
-                AuthLevel   => $AuthStat,
-                Action      => $action,
-                Ticket      => $SystemTicket,
-                Queue       => $SystemQueueObj
+                CurrentUser   => $CurrentUser,
+                AuthLevel     => $AuthStat,
+                Action        => $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.
-            $AuthStat = $NewAuthStat if $NewAuthStat > $AuthStat;
+# You get the highest level of authentication you were assigned, unless you get the magic -1
+# If a module returns a "-1" then we discard the ticket, so.
+            $AuthStat = $NewAuthStat
+                if ( $NewAuthStat > $AuthStat or $NewAuthStat == -1 or $NewAuthStat == -2 );
 
             last if $AuthStat == -1;
-	}
+            $skip_action{$action}++ if $AuthStat == -2;
+        }
 
         last if $AuthStat == -1;
     }
-
     # {{{ If authentication fails and no new user was created, get out.
-    if ( !$CurrentUser or !$CurrentUser->Id or $AuthStat == -1 ) {
+    if ( !$CurrentUser || !$CurrentUser->id || $AuthStat == -1 ) {
 
         # If the plugins refused to create one, they lose.
         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 this email ($ErrorsTo).
-
-You might need to grant 'Everyone' the right '$Right' for the
-queue @{[$args{'queue'}]}.
-
-EOT
-                MIMEObj  => $Message,
-                LogLevel => 'error'
+            _NoAuthorizedUserFound(
+                Right     => $Right,
+                Message   => $Message,
+                Requestor => $ErrorsTo,
+                Queue     => $args{'queue'}
             );
 
-            # 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 );
     }
 
-    # }}}
-
-    # {{{ Lets check for mail loops of various sorts.
-    my $IsBounce = CheckForBounce($head);
-
-    my $IsAutoGenerated = CheckForAutoGenerated($head);
-
-    my $IsSuspiciousSender = CheckForSuspiciousSender($head);
-
-    my $IsALoop = CheckForLoops($head);
-
-    my $SquelchReplies = 0;
-
-    #If the message is autogenerated, we need to know, so we can not
-    # send mail to the sender
-    if ( $IsBounce || $IsSuspiciousSender || $IsAutoGenerated || $IsALoop ) {
-        $SquelchReplies = 1;
-        $ErrorsTo       = $RT::OwnerEmail;
-    }
-
-    # }}}
-
-    # {{{ Drop it if it's disallowed
+    # If we got a user, but they don't have the right to say things
     if ( $AuthStat == 0 ) {
         MailError(
             To          => $ErrorsTo,
             Subject     => "Permission Denied",
-            Explanation => "You do not have permission to communicate with RT",
-            MIMEObj     => $Message
+            Explanation =>
+                "You do not have permission to communicate with RT",
+            MIMEObj => $Message
         );
-    }
-
-    # }}}
-    # {{{ Warn someone  if it's a loop
-
-    # Warn someone if it's a loop, before we drop it on the ground
-    if ($IsALoop) {
-        $RT::Logger->crit("RT Recieved mail ($MessageId) from itself.");
-
-        #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
-            );
-        }
-
-        #Do we actually want to store it?
-        return ( 0, "Message Bounced", undef ) unless ($RT::StoreLoops);
-    }
-
-    # }}}
-
-    # {{{ 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')
+        return (
+            0,
+            "$ErrorsTo tried to submit a message to "
+                . $args{'Queue'}
+                . " without permission.",
+            undef
         );
-        $head->delete('RT-Squelch-Replies-To');
     }
 
-    if ($SquelchReplies) {
-
-        # Squelch replies to the sender, and also leave a clue to
-        # allow us to squelch ALL outbound messages. This way we
-        # can punt the logic of "what to do when we get a bounce"
-        # to the scrip. We might want to notify nobody. Or just
-        # the RT Owner. Or maybe all Privileged watchers.
-        my ( $Sender, $junk ) = ParseSenderAddressFromHead($head);
-        $head->add( 'RT-Squelch-Replies-To', $Sender );
-        $head->add( 'RT-DetectedAutoGenerated', 'true' );
+    # {{{ Lets check for mail loops of various sorts.
+    my ($continue, $result);
+     ( $continue, $ErrorsTo, $result ) = _HandleMachineGeneratedMail(
+        Message  => $Message,
+        ErrorsTo => $ErrorsTo,
+        Subject  => $Subject,
+        MessageId => $MessageId
+    );
+
+    unless ($continue) {
+        return ( 0, $result, undef );
     }
+    
+    # strip actions we should skip
+    @actions = grep !$skip_action{$_}, @actions;
 
-    # }}}
+    # if plugin's updated SystemTicket then update arguments
+    $args{'ticket'} = $SystemTicket->Id if $SystemTicket && $SystemTicket->Id;
 
     my $Ticket = RT::Ticket->new($CurrentUser);
 
-    # {{{ If we don't have a ticket Id, we're creating a new ticket
-    if ( (!$SystemTicket || !$SystemTicket->Id) && 
-           grep /^(comment|correspond)$/, @actions ) {
-
-        # {{{ Create a new ticket
+    if ( !$args{'ticket'} && grep /^(comment|correspond)$/, @actions )
+    {
 
         my @Cc;
         my @Requestors = ( $CurrentUser->id );
@@ -776,42 +728,39 @@
                 Explanation => $ErrStr,
                 MIMEObj     => $Message
             );
-            $RT::Logger->error("Create failed: $id / $Transaction / $ErrStr ");
-            return ( 0, "Ticket creation failed", $Ticket );
+            return ( 0, "Ticket creation failed: $ErrStr", $Ticket );
         }
-	# strip comments&corresponds from the actions we don't need record twice
-	@actions = grep !/^(comment|correspond)$/, @actions;
-	$args{'ticket'} = $id;
 
-        # }}}
-    }
+        # strip comments&corresponds from the actions we don't need
+        # to record them if we've created the ticket just now
+        @actions = grep !/^(comment|correspond)$/, @actions;
+        $args{'ticket'} = $id;
 
-    $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 );
+    } else {
+
+        $Ticket->Load( $args{'ticket'} );
+        unless ( $Ticket->Id ) {
+            my $error = "Could not find a ticket with id " . $args{'ticket'};
+            MailError(
+                To          => $ErrorsTo,
+                Subject     => "Message not recorded",
+                Explanation => $error,
+                MIMEObj     => $Message
+            );
+
+            return ( 0, $error );
+        }
     }
 
     # }}}
-    foreach my $action( @actions ) {
+    foreach my $action (@actions) {
+
         #   If the action is comment, add a comment.
-        if ( $action =~ /^(comment|correspond)$/i ) {
-            my ( $status, $msg );
-            if ( $action =~ /^correspond$/i ) {
-                ( $status, $msg ) = $Ticket->Correspond( MIMEObj => $Message );
-            }
-            else {
-                ( $status, $msg ) = $Ticket->Comment( MIMEObj => $Message );
-            }
+        if ( $action =~ /^(?:comment|correspond)$/i ) {
+            my $method = ucfirst lc $action;
+            my ( $status, $msg ) = $Ticket->$method( MIMEObj => $Message );
             unless ($status) {
-    
+
                 #Warn the sender that we couldn't actually submit the comment.
                 MailError(
                     To          => $ErrorsTo,
@@ -819,79 +768,201 @@
                     Explanation => $msg,
                     MIMEObj     => $Message
                 );
-                return ( 0, "Message not recorded", $Ticket );
-            }
-        }
-        elsif ($RT::UnsafeEmailCommands && $action =~ /^take$/i ) {
-            my ( $status, $msg ) = $Ticket->SetOwner( $CurrentUser->id );
-            unless ($status) {
-    
-                #Warn the sender that we couldn't actually submit the comment.
-                MailError(
-                    To          => $ErrorsTo,
-                    Subject     => "Ticket not taken",
-                    Explanation => $msg,
-                    MIMEObj     => $Message
-                );
-                return ( 0, "Ticket not taken", $Ticket );
-            }
-        }
-        elsif ( $RT::UnsafeEmailCommands && $action =~ /^resolve$/i ) {
-            my ( $status, $msg ) = $Ticket->SetStatus( 'resolved' );
-            unless ($status) {
-                #Warn the sender that we couldn't actually submit the comment.
-                MailError(
-                    To          => $ErrorsTo,
-                    Subject     => "Ticket not resolved",
-                    Explanation => $msg,
-                    MIMEObj     => $Message
-                );
-                return ( 0, "Ticket not resolved", $Ticket );
+                return ( 0, "Message not recorded: $msg", $Ticket );
             }
+        } elsif ($RT::UnsafeEmailCommands) {
+            my ( $status, $msg ) = _RunUnsafeAction(
+                Action      => $action,
+                ErrorsTo    => $ErrorsTo,
+                Message     => $Message,
+                Ticket      => $Ticket,
+                CurrentUser => $CurrentUser,
+            );
+            return ($status, $msg, $Ticket) unless $status == 1;
         }
-    
-        else {
-    
-            #Return mail to the sender with an error
+    }
+    return ( 1, "Success", $Ticket );
+}
+
+sub _RunUnsafeAction {
+    my %args = (
+        Action      => undef,
+        ErrorsTo    => undef,
+        Message     => undef,
+        Ticket      => undef,
+        CurrentUser => undef,
+        @_
+    );
+
+    if ( $args{'Action'} =~ /^take$/i ) {
+        my ( $status, $msg ) = $args{'Ticket'}->SetOwner( $args{'CurrentUser'}->id );
+        unless ($status) {
             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
+                To          => $args{'ErrorsTo'},
+                Subject     => "Ticket not taken",
+                Explanation => $msg,
+                MIMEObj     => $args{'Message'}
             );
-            $RT::Logger->crit( $args{'action'} . " type unknown for $MessageId" );
-            return (
-                -75,
-                "Configuration error: "
-                  . $args{'action'}
-                  . " not a recognized action",
-                $Ticket
+            return ( 0, "Ticket not taken" );
+        }
+    } elsif ( $args{'Action'} =~ /^resolve$/i ) {
+        my ( $status, $msg ) = $args{'Ticket'}->SetStatus('resolved');
+        unless ($status) {
+
+            #Warn the sender that we couldn't actually submit the comment.
+            MailError(
+                To          => $args{'ErrorsTo'},
+                Subject     => "Ticket not resolved",
+                Explanation => $msg,
+                MIMEObj     => $args{'Message'}
             );
-    
+            return ( 0, "Ticket not resolved" );
         }
+    } else {
+        return ( 0, "Not supported unsafe action $args{'Action'}", $args{'Ticket'} );
     }
+    return ( 1, "Success" );
+}
 
-    return ( 1, "Success", $Ticket );
+=head2 _NoAuthorizedUserFound
+
+Emails the RT Owner and the requestor when the auth plugins return "No auth user found"
+
+=cut
+
+sub _NoAuthorizedUserFound {
+    my %args = (
+        Right     => undef,
+        Message   => undef,
+        Requestor => undef,
+        Queue     => undef,
+        @_
+    );
+
+    # Notify the RT Admin of the failure.
+    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 this email (@{[$args{Requestor}]}).
+
+You might need to grant 'Everyone' the right '@{[$args{Right}]}' for the
+queue @{[$args{'Queue'}]}.
+
+EOT
+        MIMEObj  => $args{'Message'},
+        LogLevel => 'error'
+    );
+
+    # Also notify the requestor that his request has been dropped.
+    MailError(
+        To          => $args{'Requestor'},
+        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  => $args{'Message'},
+        LogLevel => 'error'
+    );
 }
 
-sub IsCorrectAction
-{
-	my $action = shift;
-	my @actions = split /-/, $action;
-	foreach ( @actions ) {
-		return (0, $_) unless /^(?:comment|correspond|take|resolve)$/;
-	}
-	return (1, @actions);
+=head2 _HandleMachineGeneratedMail
+
+Takes named params:
+    Message
+    ErrorsTo
+    Subject
+
+Checks the message to see if it's a bounce, if it looks like a loop, if it's autogenerated, etc.
+Returns a triple of ("Should we continue (boolean)", "New value for $ErrorsTo", "Status message");
+
+=cut
+
+sub _HandleMachineGeneratedMail {
+    my %args = ( Message => undef, ErrorsTo => undef, Subject => undef, MessageId => undef, @_ );
+    my $head = $args{'Message'}->head;
+    my $ErrorsTo = $args{'ErrorsTo'};
+
+    my $IsBounce = CheckForBounce($head);
+
+    my $IsAutoGenerated = CheckForAutoGenerated($head);
+
+    my $IsSuspiciousSender = CheckForSuspiciousSender($head);
+
+    my $IsALoop = CheckForLoops($head);
+
+    my $SquelchReplies = 0;
+
+    #If the message is autogenerated, we need to know, so we can not
+    # send mail to the sender
+    if ( $IsBounce || $IsSuspiciousSender || $IsAutoGenerated || $IsALoop ) {
+        $SquelchReplies = 1;
+        $ErrorsTo       = $RT::OwnerEmail;
+    }
+
+    # Warn someone if it's a loop, before we drop it on the ground
+    if ($IsALoop) {
+        $RT::Logger->crit("RT Recieved mail (".$args{MessageId}.") from itself.");
+
+        #Should we mail it to RTOwner?
+        if ($RT::LoopsToRTOwner) {
+            MailError(
+                To          => $RT::OwnerEmail,
+                Subject     => "RT Bounce: ".$args{'Subject'},
+                Explanation => "RT thinks this message may be a bounce",
+                MIMEObj     => $args{Message}
+            );
+        }
+
+        #Do we actually want to store it?
+        return ( 0, $ErrorsTo, "Message Bounced" ) unless ($RT::StoreLoops);
+    }
+
+    # 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->delete('RT-Squelch-Replies-To');
+    }
+
+    if ($SquelchReplies) {
+
+        # Squelch replies to the sender, and also leave a clue to
+        # allow us to squelch ALL outbound messages. This way we
+        # can punt the logic of "what to do when we get a bounce"
+        # to the scrip. We might want to notify nobody. Or just
+        # the RT Owner. Or maybe all Privileged watchers.
+        my ( $Sender, $junk ) = ParseSenderAddressFromHead($head);
+        $head->add( 'RT-Squelch-Replies-To',    $Sender );
+        $head->add( 'RT-DetectedAutoGenerated', 'true' );
+    }
+    return ( 1, $ErrorsTo, "Handled machine detection" );
 }
 
+=head2 IsCorrectAction
+
+Returns a list of valid actions we've found for this message
+
+=cut
+
+sub IsCorrectAction {
+    my $action = shift;
+    my @actions = split /-/, $action;
+    foreach (@actions) {
+        return ( 0, $_ ) unless /^(?:comment|correspond|take|resolve)$/;
+    }
+    return ( 1, @actions );
+}
 
 eval "require RT::Interface::Email_Vendor";
-die $@ if ($@ && $@ !~ qr{^Can't locate RT/Interface/Email_Vendor.pm});
+die $@ if ( $@ && $@ !~ qr{^Can't locate RT/Interface/Email_Vendor.pm} );
 eval "require RT::Interface::Email_Local";
-die $@ if ($@ && $@ !~ qr{^Can't locate RT/Interface/Email_Local.pm});
+die $@ if ( $@ && $@ !~ qr{^Can't locate RT/Interface/Email_Local.pm} );
 
 1;

Modified: rt/branches/3.6-RELEASE/lib/RT/Interface/Web.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/Interface/Web.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/Interface/Web.pm	Tue Jul 18 17:51:35 2006
@@ -339,9 +339,18 @@
         Body                => $ARGS{'Content'},
     );
 
-    if ($ARGS{'Attachments'}) {
-        $MIMEObj->make_multipart;
-        $MIMEObj->add_part($_) foreach values %{$ARGS{'Attachments'}};
+    if ( $ARGS{'Attachments'} ) {
+        my $rv = $MIMEObj->make_multipart;
+        $RT::Logger->error("Couldn't make multipart message")
+            if !$rv || $rv !~ /^(?:DONE|ALREADY)$/;
+
+        foreach ( values %{$ARGS{'Attachments'}} ) {
+            unless ( $_ ) {
+                $RT::Logger->error("Couldn't add empty attachemnt");
+                next;
+            }
+            $MIMEObj->add_part($_);
+        }
     }
 
     my %create_args = (

Modified: rt/branches/3.6-RELEASE/lib/RT/Interface/Web/Handler.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/Interface/Web/Handler.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/Interface/Web/Handler.pm	Tue Jul 18 17:51:35 2006
@@ -107,9 +107,10 @@
         umask(0077);
 
         if ($CGI::MOD_PERL) { local $@; eval {
+
             chown( Apache->server->uid, Apache->server->gid,
                 $RT::MasonSessionDir )
-        } }
+        }} 
 
         # Die if WebSessionDir doesn't exist or we can't write to it
         stat($RT::MasonSessionDir);

Modified: rt/branches/3.6-RELEASE/lib/RT/Link_Overlay.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/Link_Overlay.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/Link_Overlay.pm	Tue Jul 18 17:51:35 2006
@@ -267,8 +267,8 @@
 =cut
 
 sub TargetObj {
-  my $self = shift;
-   return $self->TargetURI->Object;
+    my $self = shift;
+    return $self->TargetURI->Object;
 }
 # }}}
 

Modified: rt/branches/3.6-RELEASE/lib/RT/Links_Overlay.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/Links_Overlay.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/Links_Overlay.pm	Tue Jul 18 17:51:35 2006
@@ -153,19 +153,17 @@
     my $self = shift;
  	
     my $Link = $self->SUPER::Next();
-    if ((defined($Link)) and (ref($Link))) {
-        # Skip links to local objects thast are deleted
-        if      ($Link->TargetURI->IsLocal and UNIVERSAL::isa($Link->TargetObj,"RT::Ticket")
-                 and $Link->TargetObj->__Value('status') eq "deleted") {
-            return $self->Next;
-        } elsif ($Link->BaseURI->IsLocal   and UNIVERSAL::isa($Link->BaseObj,"RT::Ticket")
-                 and $Link->BaseObj->__Value('status') eq "deleted") {
-            return $self->Next;
-        } else {
-            return $Link;
-        }
+    return $Link unless $Link && ref $Link;
+
+    # Skip links to local objects thast are deleted
+    if ( $Link->TargetURI->IsLocal and UNIVERSAL::isa($Link->TargetObj,"RT::Ticket")
+             and $Link->TargetObj->__Value('status') eq "deleted") {
+        return $self->Next;
+    } elsif ($Link->BaseURI->IsLocal   and UNIVERSAL::isa($Link->BaseObj,"RT::Ticket")
+             and $Link->BaseObj->__Value('status') eq "deleted") {
+        return $self->Next;
     } else {
-        return undef;
+        return $Link;
     }
 }
 

Modified: rt/branches/3.6-RELEASE/lib/RT/Ticket_Overlay.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/Ticket_Overlay.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/Ticket_Overlay.pm	Tue Jul 18 17:51:35 2006
@@ -441,9 +441,9 @@
     if ( $args{'Due'} ) {
         $Due->Set( Format => 'ISO', Value => $args{'Due'} );
     }
-    elsif ( $QueueObj->DefaultDueIn ) {
+    elsif ( my $due_in = $QueueObj->DefaultDueIn ) {
         $Due->SetToNow;
-        $Due->AddDays( $QueueObj->DefaultDueIn );
+        $Due->AddDays( $due_in );
     }
 
     my $Starts = new RT::Date( $self->CurrentUser );
@@ -1330,6 +1330,10 @@
         @_
     );
 
+    # XXX, FIXME, BUG: if only email is provided then we only check
+    # for ModifyTicket right, but must try to get PrincipalId and
+    # check Watch* rights too if user exist
+
     # {{{ Check ACLS
     #If the watcher we're trying to add is for the current user
     if ( $self->CurrentUser->PrincipalId  eq $args{'PrincipalId'}
@@ -1997,11 +2001,16 @@
         )
       )
     {
-        $self->Untake();
+        my $clone = RT::Ticket->new( $RT::SystemUser );
+        $clone->Load( $self->Id );
+        unless ( $clone->Id ) {
+            return ( 0, $self->loc("Couldn't load copy of ticket #[_1].", $self->Id) );
+        }
+        my ($status, $msg) = $clone->SetOwner( $RT::Nobody->Id, 'Force' );
+        $RT::Logger->error("Couldn't set owner on queue change: $msg") unless $status;
     }
 
     return ( $self->_Set( Field => 'Queue', Value => $NewQueueObj->Id() ) );
-
 }
 
 # }}}
@@ -3057,23 +3066,23 @@
         return ( 0, $self->loc("Could not change owner. ") . $msg );
     }
 
-    $RT::Handle->Commit(); 
-    my $trans;
-    ( $trans, $msg, undef ) = $self->_NewTransaction(
-                                                   Type     => $Type,
-                                                   Field    => 'Owner',
-                                                   NewValue => $NewOwnerObj->Id,
-                                                   OldValue => $OldOwnerObj->Id,
-                                                   TimeTaken => 0 );
+    $RT::Handle->Commit();
 
-    if ($trans) {
+    ($val, $msg) = $self->_NewTransaction(
+        Type      => $Type,
+        Field     => 'Owner',
+        NewValue  => $NewOwnerObj->Id,
+        OldValue  => $OldOwnerObj->Id,
+        TimeTaken => 0,
+    );
+
+    if ( $val ) {
         $msg = $self->loc( "Owner changed from [_1] to [_2]",
                            $OldOwnerObj->Name, $NewOwnerObj->Name );
 
         # TODO: make sure the trans committed properly
     }
-    return ( $trans, $msg );
-
+    return ( $val, $msg );
 }
 
 # }}}

Modified: rt/branches/3.6-RELEASE/lib/RT/Tickets_Overlay.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/Tickets_Overlay.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/Tickets_Overlay.pm	Tue Jul 18 17:51:35 2006
@@ -471,11 +471,8 @@
     die "Incorrect Meta Data for $field"
         unless ( defined $meta->[1] );
 
-    use POSIX 'strftime';
-
     my $date = RT::Date->new( $sb->CurrentUser );
     $date->Set( Format => 'unknown', Value => $value );
-    my $time = $date->Unix;
 
     if ( $op eq "=" ) {
 
@@ -483,10 +480,10 @@
         # particular single day.  in the database, we need to check for >
         # and < the edges of that day.
 
-        my $daystart = strftime( "%Y-%m-%d %H:%M",
-            gmtime( $time - ( $time % 86400 ) ) );
-        my $dayend = strftime( "%Y-%m-%d %H:%M",
-            gmtime( $time + ( 86399 - $time % 86400 ) ) );
+        $date->SetToMidnight( Timezone => 'server' );
+        my $daystart = $date->ISO;
+        $date->AddDay;
+        my $dayend = $date->ISO;
 
         $sb->_OpenParen;
 
@@ -509,11 +506,10 @@
 
     }
     else {
-        $value = strftime( "%Y-%m-%d %H:%M", gmtime($time) );
         $sb->_SQLLimit(
             FIELD    => $meta->[1],
             OPERATOR => $op,
-            VALUE    => $value,
+            VALUE    => $date->ISO,
             @rest,
         );
     }
@@ -566,7 +562,6 @@
 
     my $date = RT::Date->new( $sb->CurrentUser );
     $date->Set( Format => 'unknown', Value => $value );
-    my $time = $date->Unix;
 
     $sb->_OpenParen;
     if ( $op eq "=" ) {
@@ -575,10 +570,10 @@
         # particular single day.  in the database, we need to check for >
         # and < the edges of that day.
 
-        my $daystart = strftime( "%Y-%m-%d %H:%M",
-            gmtime( $time - ( $time % 86400 ) ) );
-        my $dayend = strftime( "%Y-%m-%d %H:%M",
-            gmtime( $time + ( 86399 - $time % 86400 ) ) );
+        $date->SetToMidnight( Timezone => 'server' );
+        my $daystart = $date->ISO;
+        $date->AddDay;
+        my $dayend = $date->ISO;
 
         $sb->_SQLLimit(
             ALIAS         => $sb->{_sql_transalias},
@@ -608,7 +603,7 @@
             ALIAS         => $sb->{_sql_transalias},
             FIELD         => 'Created',
             OPERATOR      => $op,
-            VALUE         => $value,
+            VALUE         => $date->ISO,
             CASESENSITIVE => 0,
             @rest
         );

Modified: rt/branches/3.6-RELEASE/lib/RT/Transaction_Overlay.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/Transaction_Overlay.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/Transaction_Overlay.pm	Tue Jul 18 17:51:35 2006
@@ -152,7 +152,13 @@
  
     my $id = $self->SUPER::Create(%params);
     $self->Load($id);
-    $self->_Attach( $args{'MIMEObj'} ) if defined $args{'MIMEObj'};
+    if ( defined $args{'MIMEObj'} ) {
+        my ($id, $msg) = $self->_Attach( $args{'MIMEObj'} );
+        unless ( $id ) {
+            $RT::Logger->error("Couldn't add attachment: $msg");
+            return ( 0, $self->loc("Couldn't add attachment") );
+        }
+    }
 
 
     #Provide a way to turn off scrips if we need to
@@ -476,11 +482,11 @@
     }
 
     my $Attachment = new RT::Attachment( $self->CurrentUser );
-    $Attachment->Create(
+    my ($id, $msg) = $Attachment->Create(
         TransactionId => $self->Id,
         Attachment    => $MIMEObject
     );
-    return ( $Attachment, $self->loc("Attachment created") );
+    return ( $Attachment, $msg || $self->loc("Attachment created") );
 
 }
 

Modified: rt/branches/3.6-RELEASE/lib/RT/URI.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/URI.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/URI.pm	Tue Jul 18 17:51:35 2006
@@ -143,7 +143,7 @@
     
     unless ($self->Resolver->ParseURI($uri)) {
         $RT::Logger->warning("Resolver ".ref($self->Resolver)." could not parse $uri");
-        $self->{resolver} = undef; # clear resolver
+        $self->{resolver} = RT::URI::base->new( $self->CurrentUser ); # clear resolver
     	return (undef);
     }
 

Modified: rt/branches/3.6-RELEASE/lib/RT/URI/base.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/URI/base.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/URI/base.pm	Tue Jul 18 17:51:35 2006
@@ -81,12 +81,8 @@
     my $self = shift;
     my $obj = shift;
     $self->{'uri'} = "unknown-object:".ref($obj);
-
-
 }
 
-
-
 sub ParseURI { 
     my $self = shift;
     my $uri = shift;

Modified: rt/branches/3.6-RELEASE/lib/RT/URI/fsck_com_rt.pm
==============================================================================
--- rt/branches/3.6-RELEASE/lib/RT/URI/fsck_com_rt.pm	(original)
+++ rt/branches/3.6-RELEASE/lib/RT/URI/fsck_com_rt.pm	Tue Jul 18 17:51:35 2006
@@ -128,7 +128,7 @@
 sub URIForObject {
     my $self = shift;
     my $obj = shift;
-    return ($self->LocalURIPrefix."/".$self->ObjectType($obj)."/". $obj->Id);
+    return ($self->LocalURIPrefix ."/". $self->ObjectType($obj) ."/". $obj->Id);
 }
 
 
@@ -143,12 +143,12 @@
     my $self = shift;
     my $uri  = shift;
 
-    if ( $uri =~ /^(\d+)$/ ) {
+    if ( $uri =~ /^\d+$/ ) {
         my $ticket = RT::Ticket->new( $self->CurrentUser );
-        $ticket->Load($uri);
+        $ticket->Load( $uri );
         $self->{'uri'} = $ticket->URI;
         $self->{'object'} = $ticket;
-        return($ticket->id);
+        return ($ticket->id);
     }
     else {
         $self->{'uri'} = $uri;
@@ -156,9 +156,8 @@
 
     #If it's a local URI, load the ticket object and return its URI
     if ( $self->IsLocal ) {
-
         my $local_uri_prefix = $self->LocalURIPrefix;
-        if ( $self->{'uri'} =~ /^$local_uri_prefix\/(.*?)\/(\d+)$/i ) {
+        if ( $self->{'uri'} =~ /^\Q$local_uri_prefix\E\/(.*?)\/(\d+)$/i ) {
             my $type = $1;
             my $id   = $2;
 
@@ -192,9 +191,9 @@
 
 sub IsLocal {
 	my $self = shift;
-        my $local_uri_prefix = $self->LocalURIPrefix;
-	if ($self->{'uri'} =~ /^$local_uri_prefix/i) {
-		return 1;
+    my $local_uri_prefix = $self->LocalURIPrefix;
+    if ( $self->{'uri'} =~ /^\Q$local_uri_prefix/i ) {
+        return 1;
     }
 	else {
 		return undef;

Modified: rt/branches/3.6-RELEASE/lib/t/regression/06mailgateway.t
==============================================================================
--- rt/branches/3.6-RELEASE/lib/t/regression/06mailgateway.t	(original)
+++ rt/branches/3.6-RELEASE/lib/t/regression/06mailgateway.t	Tue Jul 18 17:51:35 2006
@@ -52,16 +52,19 @@
 =cut
 
 use strict;
-use Test::More tests => 57;
+use Test::More tests => 104;
+
 use RT;
 RT::LoadConfig();
 RT::Init();
 use RT::I18N;
+
 no warnings 'once';
-my $url = $RT::WebURL;
+my $url = join( ':', grep $_, "http://localhost", $RT::WebPort ) . $RT::WebPath ."/";
 
 # Make sure that when we call the mailgate wrong, it tempfails
 
+$! = '';
 ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url http://this.test.for.non-connection.is.expected.to.generate.an.error"), "Opened the mailgate - The error below is expected - $@");
 print MAIL <<EOF;
 From: root\@localhost
@@ -78,7 +81,8 @@
 
 # {{{ Test new ticket creation by root who is privileged and superuser
 
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate  --debug --url $url --queue general --action correspond"), "Opened the mailgate - $@");
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate  --debug --url $url --queue general --action correspond"), "Opened the mailgate - $!");
 print MAIL <<EOF;
 From: root\@localhost
 To: rt\@$RT::rtname
@@ -106,7 +110,8 @@
 
 # {{{This is a test of new ticket creation as an unknown user
 
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $@");
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $!");
 print MAIL <<EOF;
 From: doesnotexist\@$RT::rtname
 To: rt\@$RT::rtname
@@ -142,7 +147,8 @@
 ok ($val, "Granted everybody the right to create tickets - $msg");
 
 
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $@");
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $!");
 print MAIL <<EOF;
 From: doesnotexist\@$RT::rtname
 To: rt\@$RT::rtname
@@ -175,7 +181,8 @@
 #($val,$msg) = $g->PrincipalObj->GrantRight(Right => 'CreateTicket');
 #ok ($val, "Granted everybody the right to create tickets - $msg");
 
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $@");
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $!");
 print MAIL <<EOF;
 From: doesnotexist-2\@$RT::rtname
 To: rt\@$RT::rtname
@@ -200,7 +207,8 @@
 ($val,$msg) = $g->PrincipalObj->GrantRight(Right => 'ReplyToTicket');
 ok ($val, "Granted everybody the right to reply to  tickets - $msg");
 
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $@");
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $!");
 print MAIL <<EOF;
 From: doesnotexist-2\@$RT::rtname
 To: rt\@$RT::rtname
@@ -226,7 +234,8 @@
 #($val,$msg) = $g->PrincipalObj->GrantRight(Right => 'CreateTicket');
 #ok ($val, "Granted everybody the right to create tickets - $msg");
 
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action comment"), "Opened the mailgate - $@");
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action comment"), "Opened the mailgate - $!");
 print MAIL <<EOF;
 From: doesnotexist-3\@$RT::rtname
 To: rt\@$RT::rtname
@@ -251,7 +260,8 @@
 ($val,$msg) = $g->PrincipalObj->GrantRight(Right => 'CommentOnTicket');
 ok ($val, "Granted everybody the right to reply to  tickets - $msg");
 
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action comment"), "Opened the mailgate - $@");
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action comment"), "Opened the mailgate - $!");
 print MAIL <<EOF;
 From: doesnotexist-3\@$RT::rtname
 To: rt\@$RT::rtname
@@ -292,7 +302,8 @@
                 Encoding => 'base64');
 
 # Create a ticket with a binary attachment
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $@");
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $!");
 
 $entity->print(\*MAIL);
 
@@ -350,7 +361,8 @@
 
 # {{{ Simple I18N testing
 
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $@");
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $!");
                                                                          
 print MAIL <<EOF;
 From: root\@localhost
@@ -384,7 +396,8 @@
 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, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $@");
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $!");
                                                                          
 print MAIL <<EOF;
 From: root\@localhost
@@ -423,20 +436,28 @@
 ($val,$msg) = $g->PrincipalObj->RevokeRight(Right => 'CreateTicket');
 ok ($val, $msg);
 
-=for later
+##=for later
+
+SKIP: {
+skip "Advanced mailgate actions require an unsafe configuration", 47 unless $RT::UnsafeEmailCommands;
 
-TODO: {
+#create new queue to be shure we don't mess with rights
+use RT::Queue;
+my $queue = RT::Queue->new($RT::SystemUser);
+my ($qid) = $queue->Create( Name => 'ext-mailgate');
+ok( $qid, 'queue created for ext-mailgate tests' );
 
 # {{{ Check take and resolve actions
 
 # create ticket that is owned by nobody
 use RT::Ticket;
 $tick = RT::Ticket->new($RT::SystemUser);
-my ($id) = $tick->Create( Queue => 'general', Subject => 'test');
+my ($id) = $tick->Create( Queue => 'ext-mailgate', Subject => 'test');
 ok( $id, 'new ticket created' );
 is( $tick->Owner, $RT::Nobody->Id, 'owner of the new ticket is nobody' );
 
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action take"), "Opened the mailgate - $@");
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action take"), "Opened the mailgate - $!");
 print MAIL <<EOF;
 From: root\@localhost
 Subject: [$RT::rtname \#$id] test
@@ -453,14 +474,15 @@
 # check that there is no text transactions writen
 is( $tick->Transactions->Count, 2, 'no superfluous transactions');
 
+my $status;
 ($status, $msg) = $tick->SetOwner( $RT::Nobody->Id, 'Force' );
 ok( $status, 'successfuly changed owner: '. ($msg||'') );
 is( $tick->Owner, $RT::Nobody->Id, 'set owner back to nobody');
 
 
 
-    local $TODO = "Advanced mailgate actions require an unsafe configuration";
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue general --action take-correspond"), "Opened the mailgate - $@");
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue ext-mailgate --action take-correspond"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: root\@localhost
 Subject: [$RT::rtname \#$id] correspondence
@@ -470,17 +492,21 @@
 close (MAIL);
 is ($? >> 8, 0, "The mail gateway exited normally");
 
+DBIx::SearchBuilder::Record::Cachable->FlushCache;
+
 $tick = RT::Ticket->new($RT::SystemUser);
 $tick->Load( $id );
-is( $tick->Id, $id, 'load correct ticket');
+is( $tick->Id, $id, "load correct ticket #$id");
 is( $tick->OwnerObj->EmailAddress, 'root at localhost', 'successfuly take ticket via email');
 my $txns = $tick->Transactions;
 $txns->Limit( FIELD => 'Type', VALUE => 'Correspond');
-is( $txns->Last->Subject, "[$RT::rtname \#$id] correspondence", 'successfuly add correspond within take via email' );
+$txns->OrderBy( FIELD => 'id', ORDER => 'DESC' );
 # +1 because of auto open
 is( $tick->Transactions->Count, 6, 'no superfluous transactions');
+is( $txns->First->Subject, "[$RT::rtname \#$id] correspondence", 'successfuly add correspond within take via email' );
 
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action resolve --debug"), "Opened the mailgate - $@");
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action resolve --debug"), "Opened the mailgate - $!");
 print MAIL <<EOF;
 From: root\@localhost
 Subject: [$RT::rtname \#$id] test
@@ -497,10 +523,115 @@
 is( $tick->Status, 'resolved', 'successfuly resolved ticket via email');
 is( $tick->Transactions->Count, 7, 'no superfluous transactions');
 
-};
+use RT::User;
+my $user = RT::User->new( $RT::SystemUser );
+my ($uid) = $user->Create( Name => 'ext-mailgate',
+			   EmailAddress => 'ext-mailgate at localhost',
+			   Privileged => 1,
+			   Password => 'qwe123',
+			 );
+ok( $uid, 'user created for ext-mailgate tests' );
+ok( !$user->HasRight( Right => 'OwnTicket', Object => $queue ), "User can't own ticket" );
+
+$tick = RT::Ticket->new($RT::SystemUser);
+($id) = $tick->Create( Queue => $qid, Subject => 'test' );
+ok( $id, 'create new ticket' );
+
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action take"), "Opened the mailgate - $!");
+print MAIL <<EOF;
+From: ext-mailgate\@localhost
+Subject: [example.com \#$id] test
+
+EOF
+close (MAIL);
+is ( $? >> 8, 0, "mailgate exited normally" );
+DBIx::SearchBuilder::Record::Cachable->FlushCache;
+
+cmp_ok( $tick->Owner, '!=', $user->id, "we didn't change owner" );
+
+($status, $msg) = $user->PrincipalObj->GrantRight( Object => $queue, Right => 'ReplyToTicket' );
+ok( $status, "successfuly granted right: $msg" );
+my $ace_id = $status;
+ok( $user->HasRight( Right => 'ReplyToTicket', Object => $tick ), "User can reply to ticket" );
+
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action correspond-take"), "Opened the mailgate - $!");
+print MAIL <<EOF;
+From: ext-mailgate\@localhost
+Subject: [example.com \#$id] test
+
+correspond-take
+EOF
+close (MAIL);
+is ( $? >> 8, 0, "mailgate exited normally" );
+DBIx::SearchBuilder::Record::Cachable->FlushCache;
+
+cmp_ok( $tick->Owner, '!=', $user->id, "we didn't change owner" );
+is( $tick->Transactions->Count, 3, "one transactions added" );
+
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action take-correspond"), "Opened the mailgate - $!");
+print MAIL <<EOF;
+From: ext-mailgate\@localhost
+Subject: [example.com \#$id] test
+
+correspond-take
+EOF
+close (MAIL);
+is ( $? >> 8, 0, "mailgate exited normally" );
+DBIx::SearchBuilder::Record::Cachable->FlushCache;
+
+cmp_ok( $tick->Owner, '!=', $user->id, "we didn't change owner" );
+is( $tick->Transactions->Count, 3, "no transactions added, user can't take ticket first" );
+
+# revoke ReplyToTicket right
+use RT::ACE;
+my $ace = RT::ACE->new($RT::SystemUser);
+$ace->Load( $ace_id );
+$ace->Delete;
+my $acl = RT::ACL->new($RT::SystemUser);
+$acl->Limit( FIELD => 'RightName', VALUE => 'ReplyToTicket' );
+$acl->LimitToObject( $RT::System );
+while( my $ace = $acl->Next ) {
+	$ace->Delete;
+}
+
+ok( !$user->HasRight( Right => 'ReplyToTicket', Object => $tick ), "User can't reply to ticket any more" );
+
+
+my $group = RT::Group->new( $RT::SystemUser );
+ok( $group->LoadQueueRoleGroup( Queue => $qid, Type=> 'Owner' ), "load queue owners role group" );
+$ace = RT::ACE->new( $RT::SystemUser );
+($ace_id, $msg) = $group->PrincipalObj->GrantRight( Right => 'ReplyToTicket', Object => $queue );
+ok( $ace_id, "Granted queue owners role group with ReplyToTicket right" );
+
+($status, $msg) = $user->PrincipalObj->GrantRight( Object => $queue, Right => 'OwnTicket' );
+ok( $status, "successfuly granted right: $msg" );
+($status, $msg) = $user->PrincipalObj->GrantRight( Object => $queue, Right => 'TakeTicket' );
+ok( $status, "successfuly granted right: $msg" );
+
+$! = '';
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action take-correspond"), "Opened the mailgate - $!");
+print MAIL <<EOF;
+From: ext-mailgate\@localhost
+Subject: [example.com \#$id] test
+
+take-correspond with reply right granted to owner role
+EOF
+close (MAIL);
+is ( $? >> 8, 0, "mailgate exited normally" );
+DBIx::SearchBuilder::Record::Cachable->FlushCache;
+
+$tick->Load( $id );
+is( $tick->Owner, $user->id, "we changed owner" );
+ok( $user->HasRight( Right => 'ReplyToTicket', Object => $tick ), "owner can reply to ticket" );
+is( $tick->Transactions->Count, 5, "transactions added" );
 
-=cut
 
 # }}}
+};
+
 
 1;
+

Modified: rt/branches/3.6-RELEASE/lib/t/regression/22search_tix_by_txn.t
==============================================================================
--- rt/branches/3.6-RELEASE/lib/t/regression/22search_tix_by_txn.t	(original)
+++ rt/branches/3.6-RELEASE/lib/t/regression/22search_tix_by_txn.t	Tue Jul 18 17:51:35 2006
@@ -1,6 +1,13 @@
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+
 #use Test::More tests => 26;
 use Test::More qw/no_plan/;
+
 $ENV{'TZ'} = 'GMT';
+
 use RT;
 RT::LoadConfig();
 RT::Init();
@@ -29,4 +36,5 @@
 
 $tix->FromSQL(qq{Updated = "2005-08-05" AND Subject = "$SUBJECT"});
 is( $tix->Count, 1);
-1;
+
+exit 0;

Added: rt/branches/3.6-RELEASE/lib/t/regression/23-web_attachments.t
==============================================================================
--- (empty file)
+++ rt/branches/3.6-RELEASE/lib/t/regression/23-web_attachments.t	Tue Jul 18 17:51:35 2006
@@ -0,0 +1,60 @@
+#!/usr/bin/perl -w
+use strict;
+
+use Test::More tests => 15;
+use RT;
+RT::LoadConfig;
+RT::Init;
+use Test::WWW::Mechanize;
+
+$RT::WebURL ||= 0; # avoid stupid warning
+my $BaseURL = $RT::WebURL;
+use constant LogoFile => $RT::MasonComponentRoot .'/NoAuth/images/bplogo.gif';
+use constant FaviconFile => $RT::MasonComponentRoot .'/NoAuth/images/favicon.png';
+
+my $queue_name = 'General';
+
+my $m = Test::WWW::Mechanize->new;
+isa_ok($m, 'Test::WWW::Mechanize');
+
+$m->get_ok( $BaseURL."?user=root;pass=password" );
+$m->content_like(qr/Logout/, 'we did log in');
+
+my $qid;
+{
+    $m->content =~ /<SELECT\s+NAME\s*="Queue">.*?<OPTION\s+VALUE="(\d+)"\s*\d*>\s*\Q$queue_name\E\s*<\/OPTION>/msi;
+    ok( $qid = $1, "found id of the '$queue_name' queue");
+}
+
+$m->form_number(1);
+$m->field('Queue', $qid);
+$m->submit;
+is($m->status, 200, "request successful");
+$m->content_like(qr/Create a new ticket/, 'ticket create page');
+
+$m->form('TicketCreate');
+$m->field('Subject', 'Attachments test');
+$m->field('Attach',  LogoFile);
+$m->field('Content', 'Some content');
+$m->submit;
+is($m->status, 200, "request successful");
+
+$m->content_like(qr/Attachments test/, 'we have subject on the page');
+$m->content_like(qr/Some content/, 'and content');
+$m->content_like(qr/Download bplogo\.gif/, 'page has file name');
+
+$m->follow_link_ok({text => 'Reply'}, "reply to the ticket");
+$m->form('TicketUpdate');
+$m->field('Attach',  LogoFile);
+$m->click('AddMoreAttach');
+is($m->status, 200, "request successful");
+
+$m->form('TicketUpdate');
+$m->field('Attach',  FaviconFile);
+$m->field('UpdateContent', 'Message');
+$m->click('SubmitTicket');
+is($m->status, 200, "request successful");
+
+$m->content_like(qr/Download bplogo\.gif/, 'page has file name');
+$m->content_like(qr/Download favicon\.png/, 'page has file name');
+

Modified: rt/branches/3.6-RELEASE/sbin/rt-setup-database.in
==============================================================================
--- rt/branches/3.6-RELEASE/sbin/rt-setup-database.in	(original)
+++ rt/branches/3.6-RELEASE/sbin/rt-setup-database.in	Tue Jul 18 17:51:35 2006
@@ -559,6 +559,10 @@
                 next;
             }
             my ( $return, $msg ) = $new_entry->Create(%$item);
+            unless( $return ) {
+                print "(Error: $msg)\n";
+                next;
+            }
 
             foreach my $value ( @{$values} ) {
                 my ( $eval, $emsg ) = $new_entry->AddValue(%$value);


More information about the Rt-commit mailing list