X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=rt%2Flib%2FRT%2FInterface%2FEmail.pm;h=9216887cddb801b87eb4880987b154d13527c26b;hp=b669b5b2f831ef0b7321f5fd558a71e4f6b2fe2d;hb=ff4e86db92ebc49762302c40dd31e0325f9afd1c;hpb=b4b0c7e72d7eaee2fbfc7022022c9698323203dd diff --git a/rt/lib/RT/Interface/Email.pm b/rt/lib/RT/Interface/Email.pm index b669b5b2f..9216887cd 100755 --- a/rt/lib/RT/Interface/Email.pm +++ b/rt/lib/RT/Interface/Email.pm @@ -1,40 +1,40 @@ # BEGIN BPS TAGGED BLOCK {{{ -# +# # COPYRIGHT: -# -# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC -# -# +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# +# # (Except where explicitly superseded by other copyright notices) -# -# +# +# # LICENSE: -# +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 or visit their web page on the internet at # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# +# +# # CONTRIBUTION SUBMISSION POLICY: -# +# # (The following paragraph is not intended to limit the rights granted # to you to modify and distribute this software under the terms of # the GNU General Public License and is only of importance to you if # you choose to contribute your changes and enhancements to the # community by submitting them to Best Practical Solutions, LLC.) -# +# # By intentionally submitting any modifications, corrections or # derivatives to this work, or any other work intended for use with # Request Tracker, to Best Practical Solutions, LLC, you confirm that @@ -43,7 +43,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; @@ -245,16 +245,23 @@ sub MailError { level => $args{'LogLevel'}, message => $args{'Explanation'} ) if $args{'LogLevel'}; + # the colons are necessary to make ->build include non-standard headers - my $entity = MIME::Entity->build( - Type => "multipart/mixed", - From => $args{'From'}, - Bcc => $args{'Bcc'}, - To => $args{'To'}, - Subject => $args{'Subject'}, - 'Precedence:' => 'bulk', + my %entity_args = ( + Type => "multipart/mixed", + From => $args{'From'}, + Bcc => $args{'Bcc'}, + To => $args{'To'}, + Subject => $args{'Subject'}, 'X-RT-Loop-Prevention:' => RT->Config->Get('rtname'), ); + + # only set precedence if the sysadmin wants us to + if (defined(RT->Config->Get('DefaultErrorMailPrecedence'))) { + $entity_args{'Precedence:'} = RT->Config->Get('DefaultErrorMailPrecedence'); + } + + my $entity = MIME::Entity->build(%entity_args); SetInReplyTo( Message => $entity, InReplyTo => $args{'MIMEObj'} ); $entity->attach( Data => $args{'Explanation'} . "\n" ); @@ -280,6 +287,9 @@ RT's outgoing mail configuration. If C is passed, and is a true value, the message will be marked as an autogenerated error, if possible. Sets Date field of the head to now if it's not set. +If the C header is set to any true value, the mail will +not be sent. One use is to let extensions easily cancel outgoing mail. + Ticket and Transaction arguments are optional. If Transaction is specified and Ticket is not then ticket of the transaction is used, but only if the transaction belongs to a ticket. @@ -343,6 +353,11 @@ sub SendEmail { return -1; } + if ($args{'Entity'}->head->get('X-RT-Squelch')) { + $RT::Logger->info( $msgid . " Squelch header found. Not sending." ); + return -1; + } + if ( $TransactionObj && !$TicketObj && $TransactionObj->ObjectType eq 'RT::Ticket' ) { @@ -379,8 +394,9 @@ sub SendEmail { my $mail_command = RT->Config->Get('MailCommand'); - if ($mail_command eq 'testfile') { + if ($mail_command eq 'testfile' and not $Mail::Mailer::testfile::config{outfile}) { $Mail::Mailer::testfile::config{outfile} = File::Temp->new; + $RT::Logger->info("Storing outgoing emails in $Mail::Mailer::testfile::config{outfile}"); } # if it is a sub routine, we just return it; @@ -429,7 +445,8 @@ sub SendEmail { # don't ignore CHLD signal to get proper exit code local $SIG{'CHLD'} = 'DEFAULT'; - open my $mail, "|$path $args" or die "couldn't execute program: $!"; + open( my $mail, '|-', "$path $args >/dev/null" ) + or die "couldn't execute program: $!"; # if something wrong with $mail->print we will get PIPE signal, handle it local $SIG{'PIPE'} = sub { die "program unexpectedly closed pipe" }; @@ -442,10 +459,14 @@ sub SendEmail { my $msg = "$msgid: `$path $args` exitted with code ". ($?>>8); $msg = ", interrupted by signal ". ($?&127) if $?&127; $RT::Logger->error( $msg ); + die $msg; } }; if ( $@ ) { $RT::Logger->crit( "$msgid: Could not send mail with command `$path $args`: " . $@ ); + if ( $TicketObj ) { + _RecordSendEmailFailure( $TicketObj ); + } return 0; } } @@ -457,6 +478,9 @@ sub SendEmail { ) } }; unless ( $smtp ) { $RT::Logger->crit( "Could not connect to SMTP server."); + if ($TicketObj) { + _RecordSendEmailFailure( $TicketObj ); + } return 0; } @@ -485,6 +509,9 @@ sub SendEmail { unless ( $status ) { $RT::Logger->crit( "$msgid: Could not send mail via SMTP." ); + if ( $TicketObj ) { + _RecordSendEmailFailure( $TicketObj ); + } return 0; } } @@ -502,6 +529,9 @@ sub SendEmail { unless ( $args{'Entity'}->send( @mailer_args ) ) { $RT::Logger->crit( "$msgid: Could not send mail." ); + if ( $TicketObj ) { + _RecordSendEmailFailure( $TicketObj ); + } return 0; } } @@ -565,7 +595,7 @@ sub SendEmailUsingTemplate { return -1; } - $mail->head->set( $_ => $args{ $_ } ) + $mail->head->set( $_ => Encode::encode_utf8( $args{ $_ } ) ) foreach grep defined $args{$_}, qw(To Cc Bcc From); SetInReplyTo( Message => $mail, InReplyTo => $args{'InReplyTo'} ); @@ -963,25 +993,32 @@ sub ParseCcAddressesFromHead { @_ ); - my @recipients = - map lc $_->address, + my $current_address = lc $args{'CurrentUser'}->EmailAddress; + my $user = $args{'CurrentUser'}->UserObj; + + return + grep { $_ ne $current_address + && !RT::EmailParser->IsRTAddress( $_ ) + && !IgnoreCcAddress( $_ ) + } + map lc $user->CanonicalizeEmailAddress( $_->address ), map Email::Address->parse( $args{'Head'}->get( $_ ) ), qw(To Cc); +} - my @res; - foreach my $address ( @recipients ) { - $address = $args{'CurrentUser'}->UserObj->CanonicalizeEmailAddress( $address ); - next if lc $args{'CurrentUser'}->EmailAddress eq $address; - next if lc $args{'QueueObj'}->CorrespondAddress eq $address; - next if lc $args{'QueueObj'}->CommentAddress eq $address; - next if RT::EmailParser->IsRTAddress( $address ); +=head2 IgnoreCcAddress ADDRESS - push @res, $address; - } - return @res; -} +Returns true if ADDRESS matches the $IgnoreCcRegexp config variable. +=cut +sub IgnoreCcAddress { + my $address = shift; + if ( my $address_re = RT->Config->Get('IgnoreCcRegexp') ) { + return 1 if $address =~ /$address_re/i; + } + return undef; +} =head2 ParseSenderAddressFromHead HEAD @@ -1772,9 +1809,21 @@ sub IsCorrectAction { return ( 1, @actions ); } -eval "require RT::Interface::Email_Vendor"; -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} ); +sub _RecordSendEmailFailure { + my $ticket = shift; + if ($ticket) { + $ticket->_RecordNote( + NoteType => 'SystemError', + Content => "Sending the previous mail has failed. Please contact your admin, they can find more details in the logs.", + ); + return 1; + } + else { + $RT::Logger->error( "Can't record send email failure as ticket is missing" ); + return; + } +} + +RT::Base->_ImportOverlays(); 1;