diff --git a/include/api.tickets.php b/include/api.tickets.php index 9fbbd853658fdd7270d97726864f983f9c611dc5..fcb55d81b5b27cc62ee8b3cfb71d4128f0344fab 100644 --- a/include/api.tickets.php +++ b/include/api.tickets.php @@ -40,7 +40,7 @@ class TicketApiController extends ApiController { $supported = array_merge($supported, array('header', 'mid', 'emailId', 'to-email-id', 'ticketId', 'reply-to', 'reply-to-name', 'in-reply-to', 'references', 'thread-type', - 'flags' => array('bounce', 'auto-reply'), + 'flags' => array('bounce', 'auto-reply', 'spam', 'viral'), 'recipients' => array('*' => array('name', 'email', 'source')) )); diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php index 3ab0d891a84e15a14a7a7c2ccd0634d557776a6b..0958e8be1015065fbac6b369c474a1bb251661b8 100644 --- a/include/class.mailfetch.php +++ b/include/class.mailfetch.php @@ -269,13 +269,22 @@ class MailFetcher { if(!($headerinfo=imap_headerinfo($this->mbox, $mid)) || !$headerinfo->from) return null; + $raw_header = $this->getHeader($mid); + $info = array( + 'raw_header' => &$raw_header, + 'headers' => $headerinfo, + 'decoder' => $this, + 'type' => $this->getMimeType($headerinfo), + ); + Signal::send('mail.decoded', $this, $info); + $sender=$headerinfo->from[0]; //Just what we need... $header=array('name' => $this->mime_decode(@$sender->personal), 'email' => trim(strtolower($sender->mailbox).'@'.$sender->host), 'subject'=> $this->mime_decode(@$headerinfo->subject), 'mid' => trim(@$headerinfo->message_id), - 'header' => $this->getHeader($mid), + 'header' => $raw_header, 'in-reply-to' => $headerinfo->in_reply_to, 'references' => $headerinfo->references, ); @@ -624,6 +633,7 @@ class MailFetcher { $vars['subject'] = $mailinfo['subject'] ?: '[No Subject]'; $vars['emailId'] = $mailinfo['emailId'] ?: $this->getEmailId(); $vars['to-email-id'] = $mailinfo['emailId'] ?: 0; + $vars['flags'] = new ArrayObject(); if ($this->isBounceNotice($mid)) { // Fetch the original References and assign to 'references' @@ -694,6 +704,9 @@ class MailFetcher { } } + // Allow signal handlers to interact with the message decoding + Signal::send('mail.processed', $this, $vars); + $seen = false; if (($thread = ThreadEntry::lookupByEmailHeaders($vars, $seen)) && ($message = $thread->postEmail($vars))) { @@ -715,11 +728,18 @@ class MailFetcher { return true; } - //TODO: Log error.. + // Log an error to the system logs + $mailbox = Email::lookup($vars['emailId']); + $ost->logError('Mail Processing Exception', sprintf( + "Mailbox: %s\nError(s): %s", + $mailbox->getEmail(), + print_r($errors, true) + ), false); + + // Indicate failure of mail processing return null; } - return $ticket; } diff --git a/include/class.mailparse.php b/include/class.mailparse.php index 48a402dfb013e724f1b8eb9c1d683007fa5d896e..9e3623a3812124982cf79390a06197ff36d1b813 100644 --- a/include/class.mailparse.php +++ b/include/class.mailparse.php @@ -58,6 +58,9 @@ class Mail_Parse { 'decode_headers'=> $this->decode_headers, 'decode_bodies' => $this->decode_bodies); + $info = array('raw' => &$this->mime_message); + Signal::send('mail.received', $this, $info); + $this->splitBodyHeader(); $decoder = new Mail_mimeDecode($this->mime_message); @@ -66,6 +69,18 @@ class Mail_Parse { if (PEAR::isError($this->struct)) return false; + $info = array( + 'raw_header' => &$this->header, + 'headers' => &$this->struct->headers, + 'body' => &$this->struct->parts, + 'type' => $this->struct->ctype_primary.'/'.$this->struct->ctype_secondary, + 'mail' => $this->struct, + 'decoder' => $decoder, + ); + + // Allow signal handlers to interact with the processing + Signal::send('mail.decoded', $decoder, $info); + // Handle wrapped emails when forwarded if ($this->struct && $this->struct->parts) { $outer = $this->struct; @@ -533,6 +548,7 @@ class EmailDataParser { $data['header'] = $parser->getHeader(); $data['mid'] = $parser->getMessageId(); $data['priorityId'] = $parser->getPriority(); + $data['flags'] = new ArrayObject(); //FROM address: who sent the email. if(($fromlist = $parser->getFromAddressList())) { diff --git a/include/class.osticket.php b/include/class.osticket.php index ce5d6354498dbb022ec66213f756eb49ffb1c69b..284eebff2dc7d692e3f2df86e4d65a7582486b26 100644 --- a/include/class.osticket.php +++ b/include/class.osticket.php @@ -305,6 +305,14 @@ class osTicket { $level=3; //Debug } + $info = array( + 'title' => &$title, + 'level' => $loglevel[$level], + 'level_id' => $level, + 'body' => &$message, + ); + Signal::send('syslog', null, $info); + //Logging everything during upgrade. if($this->getConfig()->getLogLevel()<$level && !$force) return false; diff --git a/include/class.thread.php b/include/class.thread.php index 24016f02d3305ca0d82701f4a5d27bc5d4287d36..3b773bfda402c0633e5aab07a96e5e7ab840e469 100644 --- a/include/class.thread.php +++ b/include/class.thread.php @@ -1361,6 +1361,11 @@ class ThreadBody /* extends SplString */ { throw new Exception('display: Abstract dispplay() method not implemented'); } + function getSearchable() { + return $this->body; + // TODO: Normalize Unicode string + } + static function fromFormattedText($text, $format=false) { switch ($format) { case 'text': @@ -1428,6 +1433,13 @@ class HtmlThreadBody extends ThreadBody { return trim($this->body, " <>br/\t\n\r") ? Format::sanitize($this->body) : ''; } + function getSearchable() { + // <br> -> \n + $body = preg_replace('/\<br(\s*)?\/?\>/i', "\n", $this->body); + return Format::striptags($body); + // TODO: Normalize Unicode string + } + function display($output=false) { if ($this->isEmpty()) return '(empty)'; diff --git a/include/class.ticket.php b/include/class.ticket.php index 63dde20fa9e247ca48643e82d1b407347ce7e2f1..7b41282aed91167d827c1b8a93f005510873e99c 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -1595,7 +1595,9 @@ class Ticket { if(!$alerts) return $message; //Our work is done... // Do not auto-respond to bounces and other auto-replies - $autorespond = isset($vars['flags']) ? !$vars['flags']['bounce'] : true; + $autorespond = isset($vars['flags']) + ? !$vars['flags']['bounce'] && !$vars['flags']['auto-reply'] + : true; if ($autorespond && $message->isAutoReply()) $autorespond = false; @@ -1849,9 +1851,12 @@ class Ticket { if(!($note=$this->getThread()->addNote($vars, $errors))) return null; - if (isset($vars['flags']) && $vars['flags']['bounce']) - // No alerts for bounce emails - $alert = false; + $alert = $alert && ( + isset($vars['flags']) + // No alerts for bounce and auto-reply emails + ? !$vars['flags']['bounce'] && !$vars['flags']['auto-reply'] + : true + ); // Get assigned staff just in case the ticket is closed. $assignee = $this->getStaff();