From d49b75f228ebbdb13fe794d23167ce28a4973e6c Mon Sep 17 00:00:00 2001 From: Jared Hancock <jared@osticket.com> Date: Tue, 3 Feb 2015 17:37:47 -0600 Subject: [PATCH] thread: Add support for email communication without a thread entry Since tickets can be created without a message now, the emailing system should also identify the thread the message is associated with, so that a returning email can be associated with the ticket or task's thread in the event that it was created without an initial message. --- include/class.mailer.php | 61 +++++++++++++++++++++++----------------- include/class.thread.php | 4 +-- include/class.ticket.php | 5 ++++ 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/include/class.mailer.php b/include/class.mailer.php index 23270c845..a99fb7a6a 100644 --- a/include/class.mailer.php +++ b/include/class.mailer.php @@ -144,10 +144,15 @@ class Mailer { $sig = $this->getEmail()?$this->getEmail()->getEmail():'@osTicketMailer'; if ($recipient instanceof EmailContact) { // Create a tag for the outbound email - $tag = pack('VVa', + $entry = (isset($options['thread']) && $options['thread'] instanceof ThreadEntry) + ? $options['thread'] : false; + $thread = $entry ? $entry->getThread() + : (isset($options['thread']) && $options['thread'] instanceof Thread + ? $options['thread']->getId() : false); + $tag = pack('VVVa', $recipient->getId(), - (isset($options['thread']) && $options['thread'] instanceof ThreadEntry) - ? $options['thread']->getId() : 0, + $entry ? $entry->getId() : 0, + $thread ? $thread->getId() : 0, ($recipient instanceof Staff ? 'S' : ($recipient instanceof TicketOwner ? 'U' : ($recipient instanceof Collaborator ? 'C' @@ -157,7 +162,7 @@ class Mailer { // Sign the tag with the system secret salt $sig = '@' . substr(hash_hmac('sha1', $tag.$rand, SECRET_SALT), -10); } - return sprintf('<A%s-%s-%s-%s>', + return sprintf('<B%s-%s-%s-%s>', static::getSystemMessageIdCode(), $rand, $tag, $sig); } @@ -180,6 +185,7 @@ class Mailer { * 'version' - (string|FALSE) version code of the message id * 'code' - (string) unique but predictable help desk message-id * 'id' - (string) random characters serving as the unique id + * 'entryId' - (int) thread-entry-id from which the message originated * 'threadId' - (int) thread-id from which the message originated * 'staffId' - (int|null) staff the email was originally sent to * 'userId' - (int|null) user the email was originally sent to @@ -207,29 +213,32 @@ class Mailer { // Detect the MessageId version, which should be the tenth char of // the second segment $rv['version'] = @$parts[0][0]; + $format = 'Vuid/VentryId/auserClass'; switch ($rv['version']) { - case 'A': - default: - list($rv['code'], $rv['id'], $tag) = $parts; - // Drop the leading version code - $rv['code'] = substr($rv['code'], 1); - // Verify tag signature - $chksig = substr(hash_hmac('sha1', $tag.$rv['id'], SECRET_SALT), -10); - if ($tag && $sig == $chksig && ($tag = base64_decode($tag))) { - // Find user and ticket id - $rv += unpack('Vuid/VthreadId/auserClass', $tag); - // Attempt to make the user-id more specific - $classes = array( - 'S' => 'staffId', 'U' => 'userId' - ); - if (isset($classes[$rv['userClass']])) - $rv[$classes[$rv['userClass']]] = $rv['uid']; - } - // Round-trip detection - the first section is the local - // system's message-id code - $rv['loopback'] = (0 === strcasecmp($rv['code'], - static::getSystemMessageIdCode())); - break; + case 'B': + $format = 'Vuid/VentryId/VthreadId/auserClass'; + case 'A': + default: + list($rv['code'], $rv['id'], $tag) = $parts; + // Drop the leading version code + $rv['code'] = substr($rv['code'], 1); + // Verify tag signature + $chksig = substr(hash_hmac('sha1', $tag.$rv['id'], SECRET_SALT), -10); + if ($tag && $sig == $chksig && ($tag = base64_decode($tag))) { + // Find user and ticket id + $rv += unpack($format, $tag); + // Attempt to make the user-id more specific + $classes = array( + 'S' => 'staffId', 'U' => 'userId' + ); + if (isset($classes[$rv['userClass']])) + $rv[$classes[$rv['userClass']]] = $rv['uid']; + } + // Round-trip detection - the first section is the local + // system's message-id code + $rv['loopback'] = (0 === strcasecmp($rv['code'], + static::getSystemMessageIdCode())); + break; } return $rv; } diff --git a/include/class.thread.php b/include/class.thread.php index 65487811f..b8b5badeb 100644 --- a/include/class.thread.php +++ b/include/class.thread.php @@ -779,8 +779,8 @@ class ThreadEntry extends VerySimpleModel { // to true. $mid_info = Mailer::decodeMessageId($mid); if ($mid_info['loopback'] && isset($mid_info['uid']) - && @$mid_info['threadId'] - && ($t = ThreadEntry::lookup($mid_info['threadId'])) + && @$mid_info['entryId'] + && ($t = ThreadEntry::lookup($mid_info['entryId'])) ) { if (@$mid_info['userId']) { $mailinfo['userId'] = $mid_info['userId']; diff --git a/include/class.ticket.php b/include/class.ticket.php index 0c073e116..41cc69930 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -1273,6 +1273,11 @@ implements RestrictedAccess, Threadable { 'thread'=>$message ); } + else { + $options += array( + 'thread' => $this->getThread(), + ); + } //Send auto response - if enabled. if($autorespond -- GitLab