diff options
Diffstat (limited to 'rt/bin/rt-mailgate')
-rwxr-xr-x | rt/bin/rt-mailgate | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/rt/bin/rt-mailgate b/rt/bin/rt-mailgate new file mode 100755 index 000000000..e6f0d95c5 --- /dev/null +++ b/rt/bin/rt-mailgate @@ -0,0 +1,367 @@ +#!!!PERL!! -w + +# $Header: /home/cvs/cvsroot/freeside/rt/bin/rt-mailgate,v 1.1 2002-08-12 06:17:07 ivan Exp $ +# (c) 1996-2001 Jesse Vincent <jesse@fsck.com> +# This software is redistributable under the terms of the GNU GPL + + +package RT; +use strict; +use vars qw($VERSION $Handle $Nobody $SystemUser); + +$VERSION="!!RT_VERSION!!"; + + +use lib "!!RT_LIB_PATH!!"; +use lib "!!RT_ETC_PATH!!"; + +use RT::Interface::Email qw(CleanEnv LoadConfig DBConnect + GetCurrentUser + GetMessageContent + CheckForLoops + CheckForSuspiciousSender + CheckForAutoGenerated + ParseMIMEEntityFromSTDIN + ParseTicketId + MailError + ParseCcAddressesFromHead + ParseSenderAddressFromHead + ParseErrorsToAddressFromHead + ); + +#Clean out all the nasties from the environment +CleanEnv(); + +#Load etc/config.pm and drop privs +LoadConfig(); + +#Connect to the database and get RT::SystemUser and RT::Nobody loaded +DBConnect(); + +#Drop setgid permissions +RT::DropSetGIDPermissions(); + +use RT::Ticket; +use RT::Queue; +use MIME::Parser; +use File::Temp; +use Mail::Address; + + +#Set some sensible defaults +my $Queue = 1; +my $time = time; +my $Action = "correspond"; + +my ($Verbose, $ReturnTid, $Debug); +my ($From, $TicketId, $Subject,$SquelchReplies); + +# using --owner-from-extension, this will let you set ticket owner on create +my $AssignTicketTo = undef; +my ($status, $msg); + +# {{{ parse commandline + +while (my $flag = shift @ARGV) { + if (($flag eq '-v') or ($flag eq '--verbose')) { + $Verbose = 1; + } + if (($flag eq '-t') or ($flag eq '--ticketid')) { + $ReturnTid = 1; + } + + if (($flag eq '-d') or ($flag eq '--debug')) { + $RT::Logger->debug("Debug mode enabled\n"); + $Debug = 1; + } + + if (($flag eq '-q') or ($flag eq '--queue')) { + $Queue = shift @ARGV; + } + if ($flag eq '--ticket-id-from-extension') { + $TicketId = $ENV{'EXTENSION'}; + } + if ($flag eq '--queue-from-extension') { + $Queue = $ENV{'EXTENSION'}; + } + if ($flag eq '--owner-from-extension') { + $AssignTicketTo = $ENV{'EXTENSION'}; + } + + if (($flag eq '-a') or ($flag eq '--action')) { + $Action = shift @ARGV; + } + + +} + +# }}} + +# get the current mime entity from stdin +my ($entity, $head) = ParseMIMEEntityFromSTDIN(); + +#Get someone to send runtime errors to; +my $ErrorsTo = ParseErrorsToAddressFromHead($head); + +#Get us a current user object. +my $CurrentUser = GetCurrentUser($head, $entity, $ErrorsTo); + +# We've already performed a warning and sent the mail off to somewhere safe ($RTOwner). +# this is _exceedingly_ unlikely but we don't want to keep going if we don't have a current user + +unless ($CurrentUser->Id) { + exit(1); +} + +my $MessageId = $head->get('Message-Id') || + "<no-message-id-".time.rand(2000)."\@.$RT::Organization>"; + +#Pull apart the subject line +$Subject = $head->get('Subject') || "[no subject]"; +chomp $Subject; + +# Get the ticket ID unless it's already set +$TicketId = ParseTicketId($Subject) unless ($TicketId); + +#Set up a queue object +my $QueueObj = RT::Queue->new($CurrentUser); +$QueueObj->Load($Queue); +unless ($QueueObj->id ) { + + MailError(To => $RT::OwnerEmail, + Subject => "RT Bounce: $Subject", + Explanation => "RT couldn't find the queue: $Queue", + MIMEObj => $entity); + +} + +# {{{ Lets check for mail loops of various sorts. + +my $IsAutoGenerated = CheckForAutoGenerated($head); + +my $IsSuspiciousSender = CheckForSuspiciousSender($head); + +my $IsALoop = CheckForLoops($head); + + +#If the message is autogenerated, we need to know, so we can not +# send mail to the sender +if ($IsSuspiciousSender || $IsAutoGenerated || $IsALoop) { + $SquelchReplies = 1; + + $ErrorsTo = $RT::OwnerEmail; + + #TODO: Is what we want to do here really + # "Make the requestor cease to get mail from RT"? + # This might wreak havoc with vacation-mailing users. + # Maybe have a "disabled for bouncing" state that gets + # turned off when we get a legit incoming 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 Received 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 => $entity); + + #Do we actually want to store it? + exit unless ($RT::StoreLoops); + } +} + +# }}} + + + #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) { + ## TODO: This is a hack. It should be some other way to + ## indicate that the transaction should be "silent". + + my ($Sender, $junk) = ParseSenderAddressFromHead($head); + $head->add('RT-Squelch-Replies-To', $Sender); +} + +# }}} + + +# {{{ If we require that the sender be found in an external DB and they're not +# forward this message to RTOwner + + + +if ($RT::LookupSenderInExternalDatabase && + $RT::SenderMustExistInExternalDatabase ) { + + MailError(To => $RT::OwnerEmail, + Subject => "RT Bounce: $Subject", + Explanation => "RT couldn't find requestor via its external database lookup", + MIMEObj => $entity); + +} + +# }}} + +# {{{ elsif we don't have a ticket Id, we're creating a new ticket + + + +elsif (!defined($TicketId)) { + + # {{{ Create a new ticket + if ($Action =~ /correspond/) { + + # open a new ticket + my @Requestors = ($CurrentUser->id); + + my @Cc; + if ($RT::ParseNewMessageForTicketCcs) { + @Cc = ParseCcAddressesFromHead(Head => $head, + CurrentUser => $CurrentUser, + QueueObj => $QueueObj ); + } + + my $Ticket = new RT::Ticket($CurrentUser); + my ($id, $Transaction, $ErrStr) = + $Ticket->Create ( Queue => $Queue, + Subject => $Subject, + Owner => $AssignTicketTo, + Requestor => \@Requestors, + Cc => \@Cc, + MIMEObj => $entity + ); + if ($id == 0 ) { + MailError( To => $ErrorsTo, + Subject => "Ticket creation failed", + Explanation => $ErrStr, + MIMEObj => $entity + ); + $RT::Logger->error("Create failed: $id / $Transaction / $ErrStr "); + } + } + + # }}} + + else { + #TODO Return an error message + MailError( To => $ErrorsTo, + Subject => "No ticket id specified", + Explanation => "$Action aliases require a TicketId to work on", + MIMEObj => $entity + ); + + $RT::Logger->crit("$Action aliases require a TicketId to work on ". + "(from ".$CurrentUser->UserObj->EmailAddress.") ". + $MessageId); + } +} + +# }}} + +# {{{ If we've got a ticket ID, update the ticket + +else { + + # If the action is comment, add a comment. + if ($Action =~ /comment/i){ + + my $Ticket = new RT::Ticket($CurrentUser); + $Ticket->Load($TicketId); + unless ($Ticket->Id) { + MailError( To => $ErrorsTo, + Subject => "Comment not recorded", + Explanation => "Could not find a ticket with id $TicketId", + MIMEObj => $entity + ); + #Return an error message saying that Ticket "#foo" wasn't found. + } + + ($status, $msg) = $Ticket->Comment(MIMEObj=>$entity); + unless ($status) { + #Warn the sender that we couldn't actually submit the comment. + MailError( To => $ErrorsTo, + Subject => "Comment not recorded", + Explanation => $msg, + MIMEObj => $entity + ); + } + } + + # If the message is correspondence, add it to the ticket + elsif ($Action =~ /correspond/i) { + my $Ticket = RT::Ticket->new($CurrentUser); + $Ticket->Load($TicketId); + + #TODO: Check for error conditions + ($status, $msg) = $Ticket->Correspond(MIMEObj => $entity); + unless ($status) { + + #Return mail to the sender with an error + MailError( To => $ErrorsTo, + Subject => "Correspondence not recorded", + Explanation => $msg, + MIMEObj => $entity + ); + } + } + + else { + #Return mail to the sender with an error + MailError( To => $ErrorsTo, + Subject => "RT Configuration error", + Explanation => "'$Action' not a recognized action.". + " Your RT administrator has misconfigured ". + "the mail aliases which invoke RT" , + MIMEObj => $entity + ); + + $RT::Logger->crit("$Action type unknown for $MessageId"); + + } + +} + +# }}} + +$RT::Handle->Disconnect(); + + +# Everything below this line is a helper sub. most of them will eventually +# move to Interface::Email + +#When we call die, trap it and log->crit with the value of the die. +$SIG{__DIE__} = sub { + unless ($^S || !defined $^S ) { + $RT::Logger->crit("$_[0]"); + MailError( To => $ErrorsTo, + Bcc => $RT::OwnerEmail, + Subject => "RT Critical error. Message not recorded!", + Explanation => "$_[0]", + MIMEObj => $entity + ); + exit(-1); + } + else { + #Get out of here if we're in an eval + die $_[0]; + } +}; + + + +1; |