From 42b7c57d2bdc74d1f6dacb5f5a7d1c430f73ff07 Mon Sep 17 00:00:00 2001
From: Jared Hancock <jared@osticket.com>
Date: Wed, 7 May 2014 10:48:22 -0500
Subject: [PATCH] bounce: Handle rfc-1892 style bounce notices

Sometimes an MTA may just send back the headers of the original message
rather than the entire original message. Such an email will have a
`text/rfc822-headers` part which will be the complete headers of the
original message.

Without this patch, osTicket will create a new ticket for the bounce message
rather than attaching the new internal note to the existing ticket.

References:
https://tools.ietf.org/html/rfc1892
---
 include/class.mailfetch.php | 22 +++++++++++++++-------
 include/class.mailparse.php | 16 ++++++++++++----
 2 files changed, 27 insertions(+), 11 deletions(-)

diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php
index 0b739e7c8..237d1d9f7 100644
--- a/include/class.mailfetch.php
+++ b/include/class.mailfetch.php
@@ -515,15 +515,23 @@ class MailFetcher {
         return false;
     }
 
-    function getOriginalMessage($mid) {
-        if (!($body = $this->getPart($mid, 'message/rfc822')))
-            return null;
+    function getOriginalMessageHeaders($mid) {
+        if (!($body = $this->getPart($mid, 'message/rfc822'))) {
+            // Handle rfc1892 style bounces
+            if (!($body = $this->getPart($mid, 'text/rfc822-headers'))) {
+                return null;
+            }
+            else {
+                // Add a junk body for the parser
+                $body .= "\n\nIgnored";
+            }
+        }
 
         $msg = new Mail_Parse($body);
         if (!$msg->decode())
             return null;
 
-        return $msg->struct;
+        return $msg->struct->headers;
     }
 
     function getPriority($mid) {
@@ -619,9 +627,9 @@ class MailFetcher {
 
         if ($this->isBounceNotice($mid)) {
             // Fetch the original References and assign to 'references'
-            if ($msg = $this->getOriginalMessage($mid)) {
-                $vars['references'] = $msg->headers['references'];
-                unset($vars['in-reply-to']);
+            if ($headers = $this->getOriginalMessageHeaders($mid)) {
+                $vars['references'] = $headers['references'];
+                $vars['in-reply-to'] = @$headers['in-reply-to'] ?: null;
             }
             // Fetch deliver status report
             $vars['message'] = $this->getDeliveryStatusMessage($mid);
diff --git a/include/class.mailparse.php b/include/class.mailparse.php
index 378c68c19..5b1a02710 100644
--- a/include/class.mailparse.php
+++ b/include/class.mailparse.php
@@ -268,11 +268,17 @@ class Mail_Parse {
         return false;
     }
 
-    function getOriginalMessage() {
+    function getOriginalMessageHeaders() {
         foreach ($this->struct->parts as $p) {
             $ctype = $p->ctype_primary.'/'.$p->ctype_secondary;
             if (strtolower($ctype) === 'message/rfc822')
-                return $p->parts[0];
+                return $p->parts[0]->headers;
+            // Handle rfc1892 style bounces
+            if (strtolower($ctype) === 'text/rfc822-headers') {
+                $T = new Mail_mimeDecode($p->body . "\n\nIgnored");
+                if ($struct = $T->decode())
+                    return $struct->headers;
+            }
         }
         return null;
     }
@@ -604,8 +610,10 @@ class EmailDataParser {
 
         if ($parser->isBounceNotice()) {
             // Fetch the original References and assign to 'references'
-            if ($msg = $parser->getOriginalMessage())
-                $data['references'] = $msg->headers['references'];
+            if ($headers = $parser->getOriginalMessageHeaders()) {
+                $data['references'] = $headers['references'];
+                $data['in-reply-to'] = @$headers['in-reply-to'] ?: null;
+            }
             // Fetch deliver status report
             $data['message'] = $parser->getDeliveryStatusMessage();
             $data['thread-type'] = 'N';
-- 
GitLab