Exemple #1
0
 private function _handleImportTicket($xml)
 {
     $settings = CerberusSettings::getInstance();
     $logger = DevblocksPlatform::getConsoleLog();
     $workers = DAO_Worker::getAll();
     static $email_to_worker_id = null;
     static $group_name_to_id = null;
     static $bucket_name_to_id = null;
     // Hash Workers so we can ID their incoming tickets
     if (null == $email_to_worker_id) {
         $email_to_worker_id = array();
         if (is_array($workers)) {
             foreach ($workers as $worker) {
                 /* @var $worker CerberusWorker */
                 $email_to_worker_id[strtolower($worker->email)] = intval($worker->id);
             }
         }
     }
     // Hash Group names
     if (null == $group_name_to_id) {
         $groups = DAO_Group::getAll();
         $group_name_to_id = array();
         if (is_array($groups)) {
             foreach ($groups as $group) {
                 $group_name_to_id[strtolower($group->name)] = intval($group->id);
             }
         }
     }
     // Hash Bucket names
     if (null == $bucket_name_to_id) {
         $buckets = DAO_Bucket::getAll();
         $bucket_name_to_id = array();
         if (is_array($buckets)) {
             foreach ($buckets as $bucket) {
                 /* @var $bucket CerberusCategory */
                 // Hash by team ID and bucket name
                 $hash = md5($bucket->team_id . strtolower($bucket->name));
                 $bucket_to_id[$hash] = intval($bucket->id);
             }
         }
     }
     $sMask = (string) $xml->mask;
     $sSubject = substr((string) $xml->subject, 0, 255);
     $sGroup = (string) $xml->group;
     $sBucket = (string) $xml->bucket;
     $iCreatedDate = (int) $xml->created_date;
     $iUpdatedDate = (int) $xml->updated_date;
     $isWaiting = (int) $xml->is_waiting;
     $isClosed = (int) $xml->is_closed;
     if (empty($sMask)) {
         $sMask = CerberusApplication::generateTicketMask();
     }
     // Find the destination Group + Bucket (or create them)
     if (empty($sGroup)) {
         $iDestGroupId = 0;
         if (null != ($iDestGroup = DAO_Group::getDefaultGroup())) {
             $iDestGroupId = $iDestGroup->id;
         }
     } elseif (null == ($iDestGroupId = @$group_name_to_id[strtolower($sGroup)])) {
         $iDestGroupId = DAO_Group::createTeam(array(DAO_Group::TEAM_NAME => $sGroup));
         // Give all superusers manager access to this new group
         if (is_array($workers)) {
             foreach ($workers as $worker) {
                 if ($worker->is_superuser) {
                     DAO_Group::setTeamMember($iDestGroupId, $worker->id, true);
                 }
             }
         }
         // Rehash
         DAO_Group::getAll(true);
         $group_name_to_id[strtolower($sGroup)] = $iDestGroupId;
     }
     if (empty($sBucket)) {
         $iDestBucketId = 0;
         // Inbox
     } elseif (null == ($iDestBucketId = @$bucket_name_to_id[md5($iDestGroupId . strtolower($sBucket))])) {
         $iDestBucketId = DAO_Bucket::create($sBucket, $iDestGroupId);
         // Rehash
         DAO_Bucket::getAll(true);
         $bucket_name_to_id[strtolower($sBucket)] = $iDestBucketId;
     }
     // Xpath the first and last "from" out of "/ticket/messages/message/headers/from"
     $aMessageNodes = $xml->xpath("/ticket/messages/message");
     $iNumMessages = count($aMessageNodes);
     @($eFirstMessage = reset($aMessageNodes));
     if (is_null($eFirstMessage)) {
         $logger->warn('[Importer] Ticket ' . $sMask . " doesn't have any messages.  Skipping.");
         return false;
     }
     if (is_null($eFirstMessage->headers) || is_null($eFirstMessage->headers->from)) {
         $logger->warn('[Importer] Ticket ' . $sMask . " first message doesn't provide a sender address.");
         return false;
     }
     $sFirstWrote = self::_parseRfcAddressList($eFirstMessage->headers->from, true);
     if (null == ($firstWroteInst = CerberusApplication::hashLookupAddress($sFirstWrote, true))) {
         $logger->warn('[Importer] Ticket ' . $sMask . " - Invalid sender adddress: " . $sFirstWrote);
         return false;
     }
     $eLastMessage = end($aMessageNodes);
     if (is_null($eLastMessage)) {
         $logger->warn('[Importer] Ticket ' . $sMask . " doesn't have any messages.  Skipping.");
         return false;
     }
     if (is_null($eLastMessage->headers) || is_null($eLastMessage->headers->from)) {
         $logger->warn('[Importer] Ticket ' . $sMask . " last message doesn't provide a sender address.");
         return false;
     }
     $sLastWrote = self::_parseRfcAddressList($eLastMessage->headers->from, true);
     if (null == ($lastWroteInst = CerberusApplication::hashLookupAddress($sLastWrote, true))) {
         $logger->warn('[Importer] Ticket ' . $sMask . ' last message has an invalid sender address: ' . $sLastWrote);
         return false;
     }
     // Last action code + last worker
     $sLastActionCode = CerberusTicketActionCode::TICKET_OPENED;
     $iLastWorkerId = 0;
     if ($iNumMessages > 1) {
         if (null != @($iLastWorkerId = $email_to_worker_id[strtolower($lastWroteInst->email)])) {
             $sLastActionCode = CerberusTicketActionCode::TICKET_WORKER_REPLY;
         } else {
             $sLastActionCode = CerberusTicketActionCode::TICKET_CUSTOMER_REPLY;
             $iLastWorkerId = 0;
         }
     }
     // Dupe check by ticket mask
     if (null != DAO_Ticket::getTicketByMask($sMask)) {
         $logger->warn("[Importer] Ticket mask '" . $sMask . "' already exists.  Making it unique.");
         $uniqueness = 1;
         $origMask = $sMask;
         // Append new uniqueness to the ticket mask:  LLL-NNNNN-NNN-1, LLL-NNNNN-NNN-2, ...
         do {
             $sMask = $origMask . '-' . ++$uniqueness;
         } while (null != DAO_Ticket::getTicketIdByMask($sMask));
         $logger->info("[Importer] The unique mask for '" . $origMask . "' is now '" . $sMask . "'");
     }
     // Create ticket
     $fields = array(DAO_Ticket::MASK => $sMask, DAO_Ticket::SUBJECT => $sSubject, DAO_Ticket::IS_WAITING => $isWaiting, DAO_Ticket::IS_CLOSED => $isClosed, DAO_Ticket::FIRST_WROTE_ID => intval($firstWroteInst->id), DAO_Ticket::LAST_WROTE_ID => intval($lastWroteInst->id), DAO_Ticket::CREATED_DATE => $iCreatedDate, DAO_Ticket::UPDATED_DATE => $iUpdatedDate, DAO_Ticket::TEAM_ID => intval($iDestGroupId), DAO_Ticket::CATEGORY_ID => intval($iDestBucketId), DAO_Ticket::LAST_ACTION_CODE => $sLastActionCode, DAO_Ticket::LAST_WORKER_ID => intval($iLastWorkerId));
     $ticket_id = DAO_Ticket::createTicket($fields);
     //		echo "Ticket: ",$ticket_id,"<BR>";
     //		print_r($fields);
     // Create requesters
     if (!is_null($xml->requesters)) {
         foreach ($xml->requesters->address as $eAddress) {
             /* @var $eAddress SimpleXMLElement */
             $sRequesterAddy = (string) $eAddress;
             // [TODO] RFC822
             // Insert requesters
             if (null == ($requesterAddyInst = CerberusApplication::hashLookupAddress($sRequesterAddy, true))) {
                 $logger->warn('[Importer] Ticket ' . $sMask . ' - Ignoring malformed requester: ' . $sRequesterAddy);
                 continue;
             }
             DAO_Ticket::createRequester($requesterAddyInst->id, $ticket_id);
         }
     }
     // Create messages
     $is_first = true;
     if (!is_null($xml->messages)) {
         foreach ($xml->messages->message as $eMessage) {
             /* @var $eMessage SimpleXMLElement */
             $eHeaders =& $eMessage->headers;
             /* @var $eHeaders SimpleXMLElement */
             $sMsgFrom = (string) $eHeaders->from;
             $sMsgDate = (string) $eHeaders->date;
             $sMsgFrom = self::_parseRfcAddressList($sMsgFrom, true);
             if (NULL == $sMsgFrom) {
                 $logger->warn('[Importer] Ticket ' . $sMask . ' - Invalid message sender: ' . $sMsgFrom . ' (skipping)');
                 continue;
             }
             if (null == ($msgFromInst = CerberusApplication::hashLookupAddress($sMsgFrom, true))) {
                 $logger->warn('[Importer] Ticket ' . $sMask . ' - Invalid message sender: ' . $sMsgFrom . ' (skipping)');
                 continue;
             }
             @($msgWorkerId = intval($email_to_worker_id[strtolower($msgFromInst->email)]));
             //			$logger->info('Checking if '.$msgFromInst->email.' is a worker');
             $fields = array(DAO_Message::TICKET_ID => $ticket_id, DAO_Message::CREATED_DATE => strtotime($sMsgDate), DAO_Message::ADDRESS_ID => $msgFromInst->id, DAO_Message::IS_OUTGOING => !empty($msgWorkerId) ? 1 : 0, DAO_Message::WORKER_ID => !empty($msgWorkerId) ? $msgWorkerId : 0);
             $email_id = DAO_Message::create($fields);
             // First thread
             if ($is_first) {
                 DAO_Ticket::updateTicket($ticket_id, array(DAO_Ticket::FIRST_MESSAGE_ID => $email_id));
                 $is_first = false;
             }
             // Create attachments
             if (!is_null($eMessage->attachments)) {
                 foreach ($eMessage->attachments->attachment as $eAttachment) {
                     /* @var $eAttachment SimpleXMLElement */
                     $sFileName = (string) $eAttachment->name;
                     $sMimeType = (string) $eAttachment->mimetype;
                     $sFileSize = (int) $eAttachment->size;
                     $sFileContentB64 = (string) $eAttachment->content;
                     // [TODO] This could be a little smarter about detecting extensions
                     if (empty($sMimeType)) {
                         $sMimeType = "application/octet-stream";
                     }
                     $sFileContent = base64_decode($sFileContentB64);
                     unset($sFileContentB64);
                     $fields = array(DAO_Attachment::MESSAGE_ID => $email_id, DAO_Attachment::DISPLAY_NAME => $sFileName, DAO_Attachment::FILE_SIZE => intval($sFileSize), DAO_Attachment::FILEPATH => '', DAO_Attachment::MIME_TYPE => $sMimeType);
                     $file_id = DAO_Attachment::create($fields);
                     // Write file to disk using ID (Model)
                     $file_path = Model_Attachment::saveToFile($file_id, $sFileContent);
                     unset($sFileContent);
                     // Update attachment table
                     DAO_Attachment::update($file_id, array(DAO_Attachment::FILEPATH => $file_path));
                 }
             }
             // Create message content
             $sMessageContentB64 = (string) $eMessage->content;
             $sMessageContent = base64_decode($sMessageContentB64);
             // Content-type specific handling
             if (isset($eMessage->content['content-type'])) {
                 // do we have a content-type?
                 if (strtolower($eMessage->content['content-type']) == 'html') {
                     // html?
                     // Force to plaintext part
                     $sMessageContent = CerberusApplication::stripHTML($sMessageContent);
                 }
             }
             unset($sMessageContentB64);
             DAO_MessageContent::create($email_id, $sMessageContent);
             unset($sMessageContent);
             // Headers
             foreach ($eHeaders->children() as $eHeader) {
                 /* @var $eHeader SimpleXMLElement */
                 DAO_MessageHeader::create($email_id, $eHeader->getName(), (string) $eHeader);
             }
         }
     }
     // Create comments
     if (!is_null($xml->comments)) {
         foreach ($xml->comments->comment as $eComment) {
             /* @var $eMessage SimpleXMLElement */
             $iCommentDate = (int) $eComment->created_date;
             $sCommentAuthor = (string) $eComment->author;
             // [TODO] Address Hash Lookup
             $sCommentTextB64 = (string) $eComment->content;
             $sCommentText = base64_decode($sCommentTextB64);
             unset($sCommentTextB64);
             $commentAuthorInst = CerberusApplication::hashLookupAddress($sCommentAuthor, true);
             // [TODO] Sanity checking
             $fields = array(DAO_TicketComment::TICKET_ID => intval($ticket_id), DAO_TicketComment::CREATED => intval($iCommentDate), DAO_TicketComment::ADDRESS_ID => intval($commentAuthorInst->id), DAO_TicketComment::COMMENT => $sCommentText);
             $comment_id = DAO_TicketComment::create($fields);
             unset($sCommentText);
         }
     }
     $logger->info('[Importer] Imported ticket #' . $ticket_id);
     return true;
 }
Exemple #2
0
 /**
  * Enter description here...
  *
  * @param object $mime
  * @return CerberusParserMessage
  */
 public static function parseMime($mime, $full_filename)
 {
     $struct = mailparse_msg_get_structure($mime);
     $msginfo = mailparse_msg_get_part_data($mime);
     $message = new CerberusParserMessage();
     @($message->encoding = $msginfo['content-charset']);
     @($message->body_encoding = $message->encoding);
     // default
     // Decode headers
     @($message->headers = $msginfo['headers']);
     if (is_array($message->headers)) {
         foreach ($message->headers as $header_name => $header_val) {
             if (is_array($header_val)) {
                 foreach ($header_val as $idx => $val) {
                     $message->headers[$header_name][$idx] = self::fixQuotePrintableString($val);
                 }
             } else {
                 $message->headers[$header_name] = self::fixQuotePrintableString($header_val);
             }
         }
     }
     $settings = DevblocksPlatform::getPluginSettingsService();
     $is_attachments_enabled = $settings->get('cerberusweb.core', CerberusSettings::ATTACHMENTS_ENABLED, 1);
     $attachments_max_size = $settings->get('cerberusweb.core', CerberusSettings::ATTACHMENTS_MAX_SIZE, 10);
     foreach ($struct as $st) {
         //		    echo "PART $st...<br>\r\n";
         $section = mailparse_msg_get_part($mime, $st);
         $info = mailparse_msg_get_part_data($section);
         // handle parts that shouldn't have a content-name, don't handle twice
         $handled = 0;
         if (empty($info['content-name'])) {
             if ($info['content-type'] == 'text/plain') {
                 $text = mailparse_msg_extract_part_file($section, $full_filename, NULL);
                 if (isset($info['content-charset']) && !empty($info['content-charset'])) {
                     $message->body_encoding = $info['content-charset'];
                     if (@mb_check_encoding($text, $info['content-charset'])) {
                         $text = mb_convert_encoding($text, LANG_CHARSET_CODE, $info['content-charset']);
                     } else {
                         $text = mb_convert_encoding($text, LANG_CHARSET_CODE);
                     }
                 }
                 @($message->body .= $text);
                 unset($text);
                 $handled = 1;
             } elseif ($info['content-type'] == 'text/html') {
                 @($text = mailparse_msg_extract_part_file($section, $full_filename, NULL));
                 if (isset($info['content-charset']) && !empty($info['content-charset'])) {
                     if (@mb_check_encoding($text, $info['content-charset'])) {
                         $text = mb_convert_encoding($text, LANG_CHARSET_CODE, $info['content-charset']);
                     } else {
                         $text = mb_convert_encoding($text, LANG_CHARSET_CODE);
                     }
                 }
                 $message->htmlbody .= $text;
                 unset($text);
                 // Add the html part as an attachment
                 // [TODO] Make attaching the HTML part an optional config option (off by default)
                 $tmpname = ParserFile::makeTempFilename();
                 $html_attach = new ParserFile();
                 $html_attach->setTempFile($tmpname, 'text/html');
                 @file_put_contents($tmpname, $message->htmlbody);
                 $html_attach->file_size = filesize($tmpname);
                 $message->files["original_message.html"] = $html_attach;
                 unset($html_attach);
                 $handled = 1;
             } elseif ($info['content-type'] == 'message/rfc822') {
                 @($message_content = mailparse_msg_extract_part_file($section, $full_filename, NULL));
                 $message_counter = empty($message_counter) ? 1 : $message_counter + 1;
                 $tmpname = ParserFile::makeTempFilename();
                 $html_attach = new ParserFile();
                 $html_attach->setTempFile($tmpname, 'message/rfc822');
                 @file_put_contents($tmpname, $message_content);
                 $html_attach->file_size = filesize($tmpname);
                 $message->files['inline' . $message_counter . '.msg'] = $html_attach;
                 unset($html_attach);
                 $handled = 1;
             }
         }
         // whether or not it has a content-name, we need to add it as an attachment (if not already handled)
         if ($handled == 0) {
             if (false === strpos(strtolower($info['content-type']), 'multipart')) {
                 if (!$is_attachments_enabled) {
                     break;
                     // skip attachment
                 }
                 $attach = new ParseCronFileBuffer($section, $info, $full_filename);
                 // [TODO] This could be more efficient by not even saving in the first place above:
                 // Make sure our attachment is under the max preferred size
                 if (filesize($attach->tmpname) > $attachments_max_size * 1024000) {
                     @unlink($attach->tmpname);
                     break;
                 }
                 // if un-named, call it "unnamed message part"
                 if (!isset($info['content-name']) || isset($info['content-name']) && empty($info['content-name'])) {
                     // or blank
                     $info['content-name'] = 'unnamed_message_part';
                 }
                 // filenames can be quoted-printable strings, too...
                 $info['content-name'] = self::fixQuotePrintableString($info['content-name']);
                 // content-name is not necessarily unique...
                 if (isset($message->files[$info['content-name']])) {
                     $j = 1;
                     while (isset($message->files[$info['content-name'] . '(' . $j . ')'])) {
                         $j++;
                     }
                     $info['content-name'] = $info['content-name'] . '(' . $j . ')';
                 }
                 $message->files[$info['content-name']] = $attach;
             }
         }
     }
     // generate the plaintext part (if necessary)
     if (empty($message->body) && !empty($message->htmlbody)) {
         $message->body = CerberusApplication::stripHTML($message->htmlbody);
     }
     return $message;
 }