diff --git a/include/class.filter.php b/include/class.filter.php index a17962cf2e9c44e50f44c1b1f3571c3fd4eadd0c..80081aa8ace454e5d1368b60522e4263ae6188bd 100644 --- a/include/class.filter.php +++ b/include/class.filter.php @@ -818,19 +818,22 @@ class TicketFilter { * http://msdn.microsoft.com/en-us/library/ee219609(v=exchg.80).aspx */ /* static */ - function isAutoResponse($headers) { + function isAutoReply($headers) { if($headers && !is_array($headers)) $headers = Mail_Parse::splitHeaders($headers); $auto_headers = array( - 'Auto-Submitted' => 'AUTO-REPLIED', + 'Auto-Submitted' => array('AUTO-REPLIED', 'AUTO-GENERATED'), 'Precedence' => array('AUTO_REPLY', 'BULK', 'JUNK', 'LIST'), - 'Subject' => array('OUT OF OFFICE', 'AUTO-REPLY:', 'AUTORESPONSE'), + 'X-Precedence' => array('AUTO_REPLY', 'BULK', 'JUNK', 'LIST'), 'X-Autoreply' => 'YES', 'X-Auto-Response-Suppress' => array('ALL', 'DR', 'RN', 'NRN', 'OOF', 'AutoReply'), - 'X-Autoresponse' => '', - 'X-Auto-Reply-From' => '' + 'X-Autoresponse' => '*', + 'X-AutoReply-From' => '*', + 'X-Autorespond' => '*', + 'X-Mail-Autoreply' => '*', + 'X-Autogenerated' => 'REPLY', ); foreach ($auto_headers as $header=>$find) { @@ -846,39 +849,44 @@ class TicketFilter { foreach ($find as $f) if (strpos($value, $f) === 0) return true; + } elseif ($find === '*') { + return true; } elseif (strpos($value, $find) === 0) { return true; } } - # Bounces also counts as auto-responses. - if(self::isAutoBounce($headers)) - return true; - return false; } - function isAutoBounce($headers) { + static function isBounce($headers) { if($headers && !is_array($headers)) $headers = Mail_Parse::splitHeaders($headers); $bounce_headers = array( - 'From' => array('<MAILER-DAEMON@MAILER-DAEMON>', 'MAILER-DAEMON', '<>'), - 'Subject' => array('DELIVERY FAILURE', 'DELIVERY STATUS', 'UNDELIVERABLE:'), + 'From' => array('stripos', + array('MAILER-DAEMON', '<>'), null, false), + 'Subject' => array('stripos', + array('DELIVERY FAILURE', 'DELIVERY STATUS', + 'UNDELIVERABLE:', 'Undelivered Mail Returned'), 0), + 'Return-Path' => array('strcmp', array('<>'), 0), + 'Content-Type' => array('stripos', array('report-type=delivery-status'), null, false), + 'X-Failed-Recipients' => array('strpos', array('@'), null, false) ); foreach ($bounce_headers as $header => $find) { if(!isset($headers[$header])) continue; - $value = strtoupper($headers[$header]); + @list($func, $searches, $pos, $neg) = $find; - if (is_array($find)) { - foreach ($find as $f) - if (strpos($value, $f) === 0) - return true; - } elseif (strpos($value, $find) === 0) { - return true; + if(!($value = $headers[$header]) || !is_array($searches)) + continue; + + foreach ($searches as $f) { + $result = call_user_func($func, $value, $f); + if (($pos === null && $result !== $neg) or ($result === $pos)) + return true; } } diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php index 21797c2313d815ccf5185bfca09d1a59aba7e2f0..6be341d8c34aa4da658509161d39f35c5b6b49f7 100644 --- a/include/class.mailfetch.php +++ b/include/class.mailfetch.php @@ -626,12 +626,6 @@ class MailFetcher { return true; } - # check if it's a bounce! - if($vars['header'] && TicketFilter::isAutoBounce($vars['header'])) { - $ost->logWarning('Bounced email', $vars['message'], false); - return true; - } - //TODO: Log error.. return null; } diff --git a/include/class.mailparse.php b/include/class.mailparse.php index 34209b67c52badeb4e982f624f34cea0050848a9..21e8dc5286f968ebf7860fceec8326f47159d1aa 100644 --- a/include/class.mailparse.php +++ b/include/class.mailparse.php @@ -107,7 +107,7 @@ class Mail_Parse { foreach ($headers as $hdr) { list($name, $val) = explode(": ", $hdr, 2); # Create list of values if header is specified more than once - if ($array[$name] && $as_array) { + if (isset($array[$name]) && $as_array) { if (is_array($array[$name])) $array[$name][] = $val; else $array[$name] = array($array[$name], $val); } else { diff --git a/include/class.thread.php b/include/class.thread.php index 2fda4bcae682487687a6ea162a2f32454a82dd24..8a1f42ecf0ccce1ef02528dff661e7321900ce4c 100644 --- a/include/class.thread.php +++ b/include/class.thread.php @@ -376,8 +376,26 @@ Class ThreadEntry { return $this->ht['headers']; } - function isAutoResponse() { - return $this->getEmailHeader()?TicketFilter::isAutoResponse($this->getEmailHeader()):false; + function isAutoReply() { + + if (!isset($this->is_autoreply)) + $this->is_autoreply = $this->getEmailHeader() + ? TicketFilter::isAutoReply($this->getEmailHeader()) : false; + + return $this->is_autoreply; + } + + function isBounce() { + + if (!isset($this->is_bounce)) + $this->is_bounce = $this->getEmailHeader() + ? TicketFilter::isBounce($this->getEmailHeader()) : false; + + return $this->is_bounce; + } + + function isBounceOrAutoReply() { + return ($this->isAutoReply() || $this->isBounce()); } //Web uploads - caller is expected to format, validate and set any errors. diff --git a/include/class.ticket.php b/include/class.ticket.php index 7b2f92784e64bba0889a8023ad164e790ffa1f28..76445c867f099de96e02f73fe2e38f6aec415150 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -782,6 +782,10 @@ class Ticket { $msg = $this->replaceVars($msg->asArray(), array('message' => $message)); $recipients=$sentlist=array(); + //Exclude the auto responding email just incase it's from staff member. + if ($message->isAutoReply()) + $sentlist[] = $this->getEmail(); + //Alert admin?? if($cfg->alertAdminONNewTicket()) { $alert = str_replace('%{recipient}', 'Admin', $msg['body']); @@ -1371,7 +1375,7 @@ class Ticket { if(!$alerts) return $message; //Our work is done... $autorespond = true; - if ($autorespond && $message->isAutoResponse()) + if ($autorespond && $message->isBounceOrAutoReply()) $autorespond=false; $this->onMessage($autorespond, $message); //must be called b4 sending alerts to staff. @@ -2151,15 +2155,8 @@ class Ticket { # Messages that are clearly auto-responses from email systems should # not have a return 'ping' message - if ($autorespond && $message && $message->isAutoResponse()) - $autorespond=false; - - //Don't auto respond to mailer daemons. - if( $autorespond && - (strpos(strtolower($vars['email']),'mailer-daemon@')!==false - || strpos(strtolower($vars['email']),'postmaster@')!==false)) { - $autorespond=false; - } + if ($autorespond && $message->isAutoReply()) + $autorespond = false; //post canned auto-response IF any (disables new ticket auto-response). if ($vars['cannedResponseId'] @@ -2173,6 +2170,11 @@ class Ticket { if($autorespond && $dept && !$dept->autoRespONNewTicket()) $autorespond=false; + //Don't send alerts to staff when the message is a bounce + // this is necessary to avoid possible loop (especially on new ticket) + if ($alertstaff && $message->isBounce()) + $alertstaff = false; + /***** See if we need to send some alerts ****/ $ticket->onNewTicket($message, $autorespond, $alertstaff);