Пример #1
0
 function showConversationAction()
 {
     @($id = DevblocksPlatform::importGPC($_REQUEST['ticket_id'], 'integer'));
     @($expand_all = DevblocksPlatform::importGPC($_REQUEST['expand_all'], 'integer', '0'));
     @($active_worker = CerberusApplication::getActiveWorker());
     $tpl = DevblocksPlatform::getTemplateService();
     $tpl->assign('path', $this->_TPL_PATH);
     $tpl->assign('expand_all', $expand_all);
     $ticket = DAO_Ticket::getTicket($id);
     $tpl->assign('ticket', $ticket);
     $tpl->assign('requesters', $ticket->getRequesters());
     $messages = $ticket->getMessages();
     arsort($messages);
     $tpl->assign('latest_message_id', key($messages));
     $tpl->assign('messages', $messages);
     // Thread comments and messages on the same level
     $convo_timeline = array();
     // Track senders and their orgs
     $message_senders = array();
     $message_sender_orgs = array();
     // Loop messages
     foreach ($messages as $message_id => $message) {
         /* @var $message CerberusMessage */
         $key = $message->created_date . '_m' . $message_id;
         // build a chrono index of messages
         $convo_timeline[$key] = array('m', $message_id);
         // If we haven't cached this sender address yet
         if (!isset($message_senders[$message->address_id])) {
             if (null != ($sender_addy = DAO_Address::get($message->address_id))) {
                 $message_senders[$sender_addy->id] = $sender_addy;
                 // If we haven't cached this sender org yet
                 if (!isset($message_sender_orgs[$sender_addy->contact_org_id])) {
                     if (null != ($sender_org = DAO_ContactOrg::get($sender_addy->contact_org_id))) {
                         $message_sender_orgs[$sender_org->id] = $sender_org;
                     }
                 }
             }
         }
     }
     $tpl->assign('message_senders', $message_senders);
     $tpl->assign('message_sender_orgs', $message_sender_orgs);
     @($mail_inline_comments = DAO_WorkerPref::get($active_worker->id, 'mail_inline_comments', 1));
     if ($mail_inline_comments) {
         // if inline comments are enabled
         $comments = DAO_TicketComment::getByTicketId($id);
         arsort($comments);
         $tpl->assign('comments', $comments);
         // build a chrono index of comments
         foreach ($comments as $comment_id => $comment) {
             /* @var $comment Model_TicketComment */
             $key = $comment->created . '_c' . $comment_id;
             $convo_timeline[$key] = array('c', $comment_id);
         }
     }
     // sort the timeline
     if (!$expand_all) {
         krsort($convo_timeline);
     } else {
         ksort($convo_timeline);
     }
     $tpl->assign('convo_timeline', $convo_timeline);
     // Message Notes
     $notes = DAO_MessageNote::getByTicketId($id);
     $message_notes = array();
     // Index notes by message id
     if (is_array($notes)) {
         foreach ($notes as $note) {
             if (!isset($message_notes[$note->message_id])) {
                 $message_notes[$note->message_id] = array();
             }
             $message_notes[$note->message_id][$note->id] = $note;
         }
     }
     $tpl->assign('message_notes', $message_notes);
     // Message toolbar items
     $messageToolbarItems = DevblocksPlatform::getExtensions('cerberusweb.message.toolbaritem', true);
     if (!empty($messageToolbarItems)) {
         $tpl->assign('message_toolbaritems', $messageToolbarItems);
     }
     // Workers
     $workers = DAO_Worker::getAll();
     $tpl->assign('workers', $workers);
     $tpl->register_modifier('makehrefs', array('CerberusUtils', 'smarty_modifier_makehrefs'));
     $tpl->display('file:' . $this->_TPL_PATH . 'display/modules/conversation/index.tpl');
 }
Пример #2
0
 private function _sendForwards($event, $is_inbound)
 {
     @($ticket_id = $event->params['ticket_id']);
     @($send_worker_id = $event->params['worker_id']);
     $url_writer = DevblocksPlatform::getUrlService();
     $ticket = DAO_Ticket::get($ticket_id);
     // (Action) Forward Email To:
     // Sanitize and combine all the destination addresses
     $context_workers = CerberusContexts::getWorkers(CerberusContexts::CONTEXT_TICKET, $ticket->id);
     if (!is_array($context_workers)) {
         return;
     }
     foreach ($context_workers as $next_worker) {
         $notify_emails = $next_worker->email;
         if (empty($notify_emails)) {
             continue;
         }
     }
     // [TODO] This could be more efficient
     $messages = DAO_Message::getMessagesByTicket($ticket_id);
     $message = end($messages);
     // last message
     unset($messages);
     $headers = $message->getHeaders();
     // The whole flipping Swift section needs wrapped to catch exceptions
     try {
         $settings = DevblocksPlatform::getPluginSettingsService();
         $reply_to = $settings->get('cerberusweb.core', CerberusSettings::DEFAULT_REPLY_FROM, CerberusSettingsDefaults::DEFAULT_REPLY_FROM);
         // See if we need a group-specific reply-to
         if (!empty($ticket->team_id)) {
             @($group_from = DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_REPLY_FROM, ''));
             if (!empty($group_from)) {
                 $reply_to = $group_from;
             }
         }
         $sender = DAO_Address::get($message->address_id);
         $sender_email = strtolower($sender->email);
         $sender_split = explode('@', $sender_email);
         if (!is_array($sender_split) || count($sender_split) != 2) {
             return;
         }
         // If return-path is blank
         if (isset($headers['return-path']) && $headers['return-path'] == '<>') {
             return;
         }
         // Ignore bounces
         if ($sender_split[0] == "postmaster" || $sender_split[0] == "mailer-daemon") {
             return;
         }
         // Ignore autoresponses autoresponses
         if (isset($headers['auto-submitted']) && $headers['auto-submitted'] != 'no') {
             return;
         }
         // Attachments
         $attachments = $message->getAttachments();
         $mime_attachments = array();
         if (is_array($attachments)) {
             foreach ($attachments as $attachment) {
                 if (0 == strcasecmp($attachment->display_name, 'original_message.html')) {
                     continue;
                 }
                 $attachment_path = APP_STORAGE_PATH . '/attachments/';
                 // [TODO] This is highly redundant in the codebase
                 if (!file_exists($attachment_path . $attachment->filepath)) {
                     continue;
                 }
                 $attach = Swift_Attachment::fromPath($attachment_path . $attachment->filepath);
                 if (!empty($attachment->display_name)) {
                     $attach->setFilename($attachment->display_name);
                 }
                 $mime_attachments[] = $attach;
             }
         }
         // Send copies
         $mail_service = DevblocksPlatform::getMailService();
         $mailer = $mail_service->getMailer(CerberusMail::getMailerDefaults());
         $mail = $mail_service->createMessage();
         /* @var $mail Swift_Message */
         $mail->setTo(array($notify_emails));
         $mail->setFrom(array($sender->email));
         $mail->setReplyTo($reply_to);
         $mail->setReturnPath($reply_to);
         $mail->setSubject(sprintf("[RW: %s #%s]: %s", $is_inbound ? 'inbound' : 'outbound', $ticket->mask, $ticket->subject));
         $hdrs = $mail->getHeaders();
         if (null !== @($msgid = $headers['message-id'])) {
             $hdrs->addTextHeader('Message-Id', $msgid);
         }
         if (null !== @($in_reply_to = $headers['in-reply-to'])) {
             $hdrs->addTextHeader('References', $in_reply_to);
             $hdrs->addTextHeader('In-Reply-To', $in_reply_to);
         }
         $hdrs->addTextHeader('X-Mailer', 'Cerberus Helpdesk (Build ' . APP_BUILD . ')');
         $hdrs->addTextHeader('Precedence', 'List');
         $hdrs->addTextHeader('Auto-Submitted', 'auto-generated');
         $mail->setBody($message->getContent());
         // Send message attachments with watcher
         if (is_array($mime_attachments)) {
             foreach ($mime_attachments as $mime_attachment) {
                 $mail->attach($mime_attachment);
             }
         }
         $result = $mailer->send($mail);
     } catch (Exception $e) {
         if (!empty($message_id)) {
             $fields = array(DAO_MessageNote::MESSAGE_ID => $message_id, DAO_MessageNote::CREATED => time(), DAO_MessageNote::WORKER_ID => 0, DAO_MessageNote::CONTENT => 'Exception thrown while sending watcher email: ' . $e->getMessage(), DAO_MessageNote::TYPE => Model_MessageNote::TYPE_ERROR);
             DAO_MessageNote::create($fields);
         }
     }
 }
Пример #3
0
 function replyAction()
 {
     @($ticket_id = DevblocksPlatform::importGPC($_REQUEST['ticket_id'], 'integer', 0));
     @($message_id = DevblocksPlatform::importGPC($_REQUEST['message_id'], 'integer'));
     @($content = DevblocksPlatform::importGPC($_REQUEST['content'], 'content'));
     @($to = DevblocksPlatform::importGPC($_REQUEST['to'], 'string'));
     // used by forward
     @($page_type = DevblocksPlatform::importGPC($_REQUEST['page_type'], 'string'));
     $worker = CerberusApplication::getActiveWorker();
     if ($page_type == 'comment') {
         $properties = array(DAO_MessageNote::MESSAGE_ID => $message_id, DAO_MessageNote::CREATED => time(), DAO_MessageNote::WORKER_ID => @$worker->id, DAO_MessageNote::CONTENT => $content);
         $note_id = DAO_MessageNote::create($properties);
     } else {
         $properties = array('message_id' => $message_id, 'content' => $content, 'agent_id' => @$worker->id, 'to' => $to);
         CerberusMail::sendTicketMessage($properties);
     }
     DevblocksPlatform::redirect(new DevblocksHttpResponse(array('mobile', 'display', $ticket_id)));
 }
Пример #4
0
 function handleRequest(DevblocksHttpRequest $request)
 {
     $worker = CerberusApplication::getActiveWorker();
     if (empty($worker)) {
         return;
     }
     $stack = $request->path;
     array_shift($stack);
     // print
     @($object = strtolower(array_shift($stack)));
     // ticket|message|etc
     $tpl = DevblocksPlatform::getTemplateService();
     $tpl->assign('path', $this->_TPL_PATH);
     $settings = DevblocksPlatform::getPluginSettingsService();
     $tpl->assign('settings', $settings);
     $translate = DevblocksPlatform::getTranslationService();
     $tpl->assign('translate', $translate);
     $teams = DAO_Group::getAll();
     $tpl->assign('teams', $teams);
     $buckets = DAO_Bucket::getAll();
     $tpl->assign('buckets', $buckets);
     $workers = DAO_Worker::getAll();
     $tpl->assign('workers', $workers);
     // Security
     $active_worker = CerberusApplication::getActiveWorker();
     $active_worker_memberships = $active_worker->getMemberships();
     // [TODO] Make this pluggable
     // Subcontroller
     switch ($object) {
         case 'ticket':
             @($id = array_shift($stack));
             @($ticket = is_numeric($id) ? DAO_Ticket::getTicket($id) : DAO_Ticket::getTicketByMask($id));
             $convo_timeline = array();
             $messages = $ticket->getMessages();
             foreach ($messages as $message_id => $message) {
                 /* @var $message CerberusMessage */
                 $key = $message->created_date . '_m' . $message_id;
                 // build a chrono index of messages
                 $convo_timeline[$key] = array('m', $message_id);
             }
             @($mail_inline_comments = DAO_WorkerPref::get($active_worker->id, 'mail_inline_comments', 1));
             if ($mail_inline_comments) {
                 // if inline comments are enabled
                 $comments = DAO_TicketComment::getByTicketId($ticket->id);
                 arsort($comments);
                 $tpl->assign('comments', $comments);
                 // build a chrono index of comments
                 foreach ($comments as $comment_id => $comment) {
                     /* @var $comment Model_TicketComment */
                     $key = $comment->created . '_c' . $comment_id;
                     $convo_timeline[$key] = array('c', $comment_id);
                 }
             }
             ksort($convo_timeline);
             $tpl->assign('convo_timeline', $convo_timeline);
             // Comment parent addresses
             $comment_addresses = array();
             foreach ($comments as $comment) {
                 /* @var $comment Model_TicketComment */
                 $address_id = intval($comment->address_id);
                 if (!isset($comment_addresses[$address_id])) {
                     $address = DAO_Address::get($address_id);
                     $comment_addresses[$address_id] = $address;
                 }
             }
             $tpl->assign('comment_addresses', $comment_addresses);
             // Message Notes
             $notes = DAO_MessageNote::getByTicketId($ticket->id);
             $message_notes = array();
             // Index notes by message id
             if (is_array($notes)) {
                 foreach ($notes as $note) {
                     if (!isset($message_notes[$note->message_id])) {
                         $message_notes[$note->message_id] = array();
                     }
                     $message_notes[$note->message_id][$note->id] = $note;
                 }
             }
             $tpl->assign('message_notes', $message_notes);
             // Make sure we're allowed to view this ticket or message
             if (!isset($active_worker_memberships[$ticket->team_id])) {
                 echo "<H1>" . $translate->_('common.access_denied') . "</H1>";
                 return;
             }
             $tpl->assign('ticket', $ticket);
             $tpl->display('file:' . $this->_TPL_PATH . 'print/ticket.tpl');
             break;
         case 'message':
             @($id = array_shift($stack));
             @($message = DAO_Ticket::getMessage($id));
             @($ticket = DAO_Ticket::getTicket($message->ticket_id));
             // Make sure we're allowed to view this ticket or message
             if (!isset($active_worker_memberships[$ticket->team_id])) {
                 echo "<H1>" . $translate->_('common.access_denied') . "</H1>";
                 return;
             }
             // Message Notes
             $notes = DAO_MessageNote::getByTicketId($ticket->id);
             $message_notes = array();
             // Index notes by message id
             if (is_array($notes)) {
                 foreach ($notes as $note) {
                     if (!isset($message_notes[$note->message_id])) {
                         $message_notes[$note->message_id] = array();
                     }
                     $message_notes[$note->message_id][$note->id] = $note;
                 }
             }
             $tpl->assign('message_notes', $message_notes);
             $tpl->assign('message', $message);
             $tpl->assign('ticket', $ticket);
             $tpl->display('file:' . $this->_TPL_PATH . 'print/message.tpl');
             break;
     }
 }
Пример #5
0
 private function _deleteIdAction($path)
 {
     $in_id = array_shift($path);
     if (empty($in_id)) {
         $this->_error("ID was not provided.");
     }
     if (null == ($note = DAO_MessageNote::get($in_id))) {
         $this->_error("ID is not valid.");
     }
     DAO_MessageNote::delete($note->id);
     $out_xml = new SimpleXMLElement('<success></success>');
     $this->_render($out_xml->asXML());
 }
Пример #6
0
 private function _sendForwards($event, $is_inbound)
 {
     @($ticket_id = $event->params['ticket_id']);
     @($message_id = $event->params['message_id']);
     @($send_worker_id = $event->params['worker_id']);
     $ticket = DAO_Ticket::getTicket($ticket_id);
     $helpdesk_senders = CerberusApplication::getHelpdeskSenders();
     $workers = DAO_Worker::getAllActive();
     // [JAS]: Don't send obvious spam to watchers.
     if ($ticket->spam_score >= 0.9) {
         return true;
     }
     @($notifications = DAO_WorkerMailForward::getWhere(sprintf("%s = %d", DAO_WorkerMailForward::GROUP_ID, $ticket->team_id)));
     // Bail out early if we have no forwards for this group
     if (empty($notifications)) {
         return;
     }
     $message = DAO_Ticket::getMessage($message_id);
     $headers = $message->getHeaders();
     // The whole flipping Swift section needs wrapped to catch exceptions
     try {
         $settings = CerberusSettings::getInstance();
         $reply_to = $settings->get(CerberusSettings::DEFAULT_REPLY_FROM, '');
         // See if we need a group-specific reply-to
         if (!empty($ticket->team_id)) {
             @($group_from = DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_REPLY_FROM, ''));
             if (!empty($group_from)) {
                 $reply_to = $group_from;
             }
         }
         $sender = DAO_Address::get($message->address_id);
         $sender_email = strtolower($sender->email);
         $sender_split = explode('@', $sender_email);
         if (!is_array($sender_split) || count($sender_split) != 2) {
             return;
         }
         // If return-path is blank
         if (isset($headers['return-path']) && $headers['return-path'] == '<>') {
             return;
         }
         // Ignore bounces
         if ($sender_split[1] == "postmaster" || $sender_split[1] == "mailer-daemon") {
             return;
         }
         // Ignore autoresponses autoresponses
         if (isset($headers['auto-submitted']) && $headers['auto-submitted'] != 'no') {
             return;
         }
         // Headers
         //==========
         // Build mailing list
         $send_to = array();
         foreach ($notifications as $n) {
             /* @var $n Model_WorkerMailForward */
             if (!isset($n->group_id) || !isset($n->bucket_id)) {
                 continue;
             }
             // if worker no longer exists or is disabled
             if (!isset($workers[$n->worker_id])) {
                 continue;
             }
             // Don't allow a worker to usurp a helpdesk address
             if (isset($helpdesk_senders[$n->email])) {
                 continue;
             }
             if ($n->group_id == $ticket->team_id && ($n->bucket_id == -1 || $n->bucket_id == $ticket->category_id)) {
                 // Event checking
                 if ($is_inbound && ($n->event == 'i' || $n->event == 'io') || !$is_inbound && ($n->event == 'o' || $n->event == 'io') || $is_inbound && $n->event == 'r' && $ticket->next_worker_id == $n->worker_id) {
                     $send_to[$n->email] = true;
                 }
             }
         }
         // Attachments
         $attachments = $message->getAttachments();
         $mime_attachments = array();
         if (is_array($attachments)) {
             foreach ($attachments as $attachment) {
                 if (0 == strcasecmp($attachment->display_name, 'original_message.html')) {
                     continue;
                 }
                 $attachment_path = APP_STORAGE_PATH . '/attachments/';
                 // [TODO] This is highly redundant in the codebase
                 if (!file_exists($attachment_path . $attachment->filepath)) {
                     continue;
                 }
                 $file =& new Swift_File($attachment_path . $attachment->filepath);
                 $mime_attachments[] =& new Swift_Message_Attachment($file, $attachment->display_name, $attachment->mime_type);
             }
         }
         // Send copies
         if (is_array($send_to) && !empty($send_to)) {
             $mail_service = DevblocksPlatform::getMailService();
             $mailer = $mail_service->getMailer(CerberusMail::getMailerDefaults());
             foreach ($send_to as $to => $bool) {
                 // Proxy the message
                 $rcpt_to = new Swift_RecipientList();
                 $a_rcpt_to = array();
                 $mail_from = new Swift_Address($sender->email);
                 $rcpt_to->addTo($to);
                 $a_rcpt_to = new Swift_Address($to);
                 $mail = $mail_service->createMessage();
                 /* @var $mail Swift_Message */
                 $mail->setTo($a_rcpt_to);
                 $mail->setFrom($mail_from);
                 $mail->setReplyTo($reply_to);
                 $mail->setReturnPath($reply_to);
                 $mail->setSubject(sprintf("[%s #%s]: %s", $is_inbound ? 'inbound' : 'outbound', $ticket->mask, $ticket->subject));
                 if (false !== @($msgid = $headers['message-id'])) {
                     $mail->headers->set('Message-Id', $msgid);
                 }
                 if (false !== @($in_reply_to = $headers['in-reply-to'])) {
                     $mail->headers->set('References', $in_reply_to);
                     $mail->headers->set('In-Reply-To', $in_reply_to);
                 }
                 $mail->headers->set('X-Mailer', 'Cerberus Helpdesk (Build ' . APP_BUILD . ')');
                 $mail->headers->set('Precedence', 'List');
                 $mail->headers->set('Auto-Submitted', 'auto-generated');
                 $mail->attach(new Swift_Message_Part($message->getContent(), 'text/plain', 'base64', LANG_CHARSET_CODE));
                 // Send message attachments with watcher
                 if (is_array($mime_attachments)) {
                     foreach ($mime_attachments as $mime_attachment) {
                         $mail->attach($mime_attachment);
                     }
                 }
                 $mailer->send($mail, $rcpt_to, $mail_from);
             }
         }
     } catch (Exception $e) {
         $fields = array(DAO_MessageNote::MESSAGE_ID => $message_id, DAO_MessageNote::CREATED => time(), DAO_MessageNote::WORKER_ID => 0, DAO_MessageNote::CONTENT => 'Exception thrown while sending watcher email: ' . $e->getMessage(), DAO_MessageNote::TYPE => Model_MessageNote::TYPE_ERROR);
         DAO_MessageNote::create($fields);
     }
 }
Пример #7
0
 static function sendTicketMessage($properties = array())
 {
     $settings = DevblocksPlatform::getPluginSettingsService();
     $helpdesk_senders = CerberusApplication::getHelpdeskSenders();
     @($from_addy = $settings->get('cerberusweb.core', CerberusSettings::DEFAULT_REPLY_FROM, $_SERVER['SERVER_ADMIN']));
     @($from_personal = $settings->get('cerberusweb.core', CerberusSettings::DEFAULT_REPLY_PERSONAL, ''));
     // [TODO] If we still don't have a $from_addy we need a graceful failure.
     /*
     	     * [TODO] Move these into constants?
     	    'message_id'
     	    -----'ticket_id'
     'subject'
     	    'to'
     	    'cc'
     	    'bcc'
     	    'content'
     	    'files'
     	    'closed'
     	    'ticket_reopen'
     	    'unlock_date'
     	    'bucket_id'
     	    'agent_id',
     'is_autoreply',
     'dont_send',
     'dont_save_copy'
     */
     $mail_succeeded = true;
     try {
         // objects
         $mail_service = DevblocksPlatform::getMailService();
         $mailer = $mail_service->getMailer(CerberusMail::getMailerDefaults());
         $mail = $mail_service->createMessage();
         // properties
         @($reply_message_id = $properties['message_id']);
         @($content = $properties['content']);
         @($files = $properties['files']);
         @($forward_files = $properties['forward_files']);
         @($worker_id = $properties['agent_id']);
         @($subject = $properties['subject']);
         $message = DAO_Ticket::getMessage($reply_message_id);
         $message_headers = DAO_MessageHeader::getAll($reply_message_id);
         $ticket_id = $message->ticket_id;
         $ticket = DAO_Ticket::getTicket($ticket_id);
         // [TODO] Check that message|ticket isn't NULL
         // If this ticket isn't spam trained and our outgoing message isn't an autoreply
         if ($ticket->spam_training == CerberusTicketSpamTraining::BLANK && (!isset($properties['is_autoreply']) || !$properties['is_autoreply'])) {
             CerberusBayes::markTicketAsNotSpam($ticket_id);
         }
         // Allow teams to override the default from/personal
         @($group_reply = DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_REPLY_FROM, ''));
         @($group_personal = DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_REPLY_PERSONAL, ''));
         @($group_personal_with_worker = DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_REPLY_PERSONAL_WITH_WORKER, 0));
         if (!empty($group_reply)) {
             $from_addy = $group_reply;
         }
         if (!empty($group_personal)) {
             $from_personal = $group_personal;
         }
         // Prefix the worker name on the personal line?
         if (!empty($group_personal_with_worker) && null != ($reply_worker = DAO_Worker::getAgent($worker_id))) {
             $from_personal = $reply_worker->getName() . (!empty($from_personal) ? ', ' . $from_personal : "");
         }
         // Headers
         $mail->setFrom(array($from_addy => $from_personal));
         $mail->generateId();
         $headers = $mail->getHeaders();
         $headers->addTextHeader('X-Mailer', 'Cerberus Helpdesk (Build ' . APP_BUILD . ')');
         // Subject
         if (empty($subject)) {
             $subject = $ticket->subject;
         }
         if (!empty($properties['to'])) {
             // forward
             $mail->setSubject($subject);
         } else {
             // reply
             @($group_has_subject = intval(DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_SUBJECT_HAS_MASK, 0)));
             @($group_subject_prefix = DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_SUBJECT_PREFIX, ''));
             $prefix = sprintf("[%s#%s] ", !empty($group_subject_prefix) ? $group_subject_prefix . ' ' : '', $ticket->mask);
             $mail->setSubject(sprintf('Re: %s%s', $group_has_subject ? $prefix : '', $subject));
         }
         // References
         if (!empty($message) && false !== @($in_reply_to = $message_headers['message-id'])) {
             $headers->addTextHeader('References', $in_reply_to);
             $headers->addTextHeader('In-Reply-To', $in_reply_to);
         }
         // Auto-reply handling (RFC-3834 compliant)
         if (isset($properties['is_autoreply']) && $properties['is_autoreply']) {
             $headers->addTextHeader('Auto-Submitted', 'auto-replied');
             if (null == ($first_address = DAO_Address::get($ticket->first_wrote_address_id))) {
                 return;
             }
             // Don't send e-mail to ourselves
             if (isset($helpdesk_senders[$first_address->email])) {
                 return;
             }
             // Make sure we haven't mailed this address an autoreply within 5 minutes
             if ($first_address->last_autoreply > 0 && $first_address->last_autoreply > time() - 300) {
                 return;
             }
             $first_email = strtolower($first_address->email);
             $first_split = explode('@', $first_email);
             if (!is_array($first_split) || count($first_split) != 2) {
                 return;
             }
             // If return-path is blank
             if (isset($message_headers['return-path']) && $message_headers['return-path'] == '<>') {
                 return;
             }
             // Ignore bounces
             if ($first_split[0] == "postmaster" || $first_split[0] == "mailer-daemon") {
                 return;
             }
             // Ignore autoresponses to autoresponses
             if (isset($message_headers['auto-submitted']) && $message_headers['auto-submitted'] != 'no') {
                 return;
             }
             if (isset($message_headers['precedence']) && ($message_headers['precedence'] == 'list' || $message_headers['precedence'] == 'junk' || ($message_headers['precedence'] = 'bulk'))) {
                 return;
             }
             // Set the auto-reply date for this address to right now
             DAO_Address::update($ticket->first_wrote_address_id, array(DAO_Address::LAST_AUTOREPLY => time()));
             // Auto-reply just to the initial requester
             $mail->addTo($first_address->email);
             // Not an auto-reply
         } else {
             // Forwards
             if (!empty($properties['to'])) {
                 $aTo = DevblocksPlatform::parseCsvString(str_replace(';', ',', $properties['to']));
                 if (is_array($aTo)) {
                     foreach ($aTo as $to_addy) {
                         $mail->addTo($to_addy);
                     }
                 }
                 // Replies
             } else {
                 // Recipients
                 $requesters = DAO_Ticket::getRequestersByTicket($ticket_id);
                 if (is_array($requesters)) {
                     foreach ($requesters as $requester) {
                         /* @var $requester Model_Address */
                         $mail->addTo($requester->email);
                     }
                 }
             }
             // Ccs
             if (!empty($properties['cc'])) {
                 $aCc = DevblocksPlatform::parseCsvString(str_replace(';', ',', $properties['cc']));
                 $mail->setCc($aCc);
             }
             // Bccs
             if (!empty($properties['bcc'])) {
                 $aBcc = DevblocksPlatform::parseCsvString(str_replace(';', ',', $properties['bcc']));
                 $mail->setBcc($aBcc);
             }
         }
         /*
          * [IMPORTANT -- Yes, this is simply a line in the sand.]
          * You're welcome to modify the code to meet your needs, but please respect 
          * our licensing.  Buy a legitimate copy to help support the project!
          * http://www.cerberusweb.com/
          */
         $license = CerberusLicense::getInstance();
         if (empty($license) || @empty($license['serial'])) {
             $content .= base64_decode("DQoNCi0tLQ0KQ29tYmF0IHNwYW0gYW5kIGltcHJvdmUgcmVzc" . "G9uc2UgdGltZXMgd2l0aCBDZXJiZXJ1cyBIZWxwZGVzayA0LjAhDQpodHRwOi8vd3d3LmNlc" . "mJlcnVzd2ViLmNvbS8NCg");
         }
         // Body
         $mail->setBody($content);
         // Mime Attachments
         if (is_array($files) && !empty($files)) {
             foreach ($files['tmp_name'] as $idx => $file) {
                 if (empty($file) || empty($files['name'][$idx])) {
                     continue;
                 }
                 $mail->attach(Swift_Attachment::fromPath($file)->setFilename($files['name'][$idx]));
             }
         }
         // Forward Attachments
         if (!empty($forward_files) && is_array($forward_files)) {
             $attachments_path = APP_STORAGE_PATH . '/attachments/';
             foreach ($forward_files as $file_id) {
                 $attachment = DAO_Attachment::get($file_id);
                 $attachment_path = $attachments_path . $attachment->filepath;
                 $mail->attach(Swift_Attachment::fromPath($attachment_path)->setFilename($attachment->display_name));
             }
         }
         if (!DEMO_MODE) {
             // If we're not supposed to send
             if (isset($properties['dont_send']) && $properties['dont_send']) {
                 // ...do nothing
             } else {
                 // otherwise send
                 if (!$mailer->send($mail)) {
                     $mail_succeeded = false;
                     throw new Exception('Mail not sent.');
                 }
             }
         }
     } catch (Exception $e) {
         // tag failure, so we can add a note to the message later
         $mail_succeeded = false;
     }
     // Handle post-mail actions
     $change_fields = array();
     $fromAddressInst = CerberusApplication::hashLookupAddress($from_addy, true);
     $fromAddressId = $fromAddressInst->id;
     if ((!isset($properties['dont_keep_copy']) || !$properties['dont_keep_copy']) && (!isset($properties['is_autoreply']) || !$properties['is_autoreply'])) {
         $change_fields[DAO_Ticket::LAST_WROTE_ID] = $fromAddressId;
         $change_fields[DAO_Ticket::UPDATED_DATE] = time();
         if (!empty($worker_id)) {
             $change_fields[DAO_Ticket::LAST_WORKER_ID] = $worker_id;
             $change_fields[DAO_Ticket::LAST_ACTION_CODE] = CerberusTicketActionCode::TICKET_WORKER_REPLY;
         }
         // Only change the subject if not forwarding
         if (!empty($subject) && empty($properties['to'])) {
             $change_fields[DAO_Ticket::SUBJECT] = $subject;
         }
         $fields = array(DAO_Message::TICKET_ID => $ticket_id, DAO_Message::CREATED_DATE => time(), DAO_Message::ADDRESS_ID => $fromAddressId, DAO_Message::IS_OUTGOING => 1, DAO_Message::WORKER_ID => !empty($worker_id) ? $worker_id : 0);
         $message_id = DAO_Message::create($fields);
         // Content
         DAO_MessageContent::create($message_id, $content);
         $headers = $mail->getHeaders();
         // Headers
         foreach ($headers->getAll() as $hdr) {
             if (null != ($hdr_val = $hdr->getFieldBody())) {
                 if (!empty($hdr_val)) {
                     DAO_MessageHeader::create($message_id, $hdr->getFieldName(), CerberusParser::fixQuotePrintableString($hdr_val));
                 }
             }
         }
         // Attachments
         if (is_array($files) && !empty($files)) {
             $attachment_path = APP_STORAGE_PATH . '/attachments/';
             reset($files);
             foreach ($files['tmp_name'] as $idx => $file) {
                 if (empty($file) || empty($files['name'][$idx]) || !file_exists($file)) {
                     continue;
                 }
                 $fields = array(DAO_Attachment::MESSAGE_ID => $message_id, DAO_Attachment::DISPLAY_NAME => $files['name'][$idx], DAO_Attachment::MIME_TYPE => $files['type'][$idx], DAO_Attachment::FILE_SIZE => filesize($file));
                 $file_id = DAO_Attachment::create($fields);
                 $attachment_bucket = sprintf("%03d/", mt_rand(1, 100));
                 $attachment_file = $file_id;
                 if (!file_exists($attachment_path . $attachment_bucket)) {
                     mkdir($attachment_path . $attachment_bucket, 0775, true);
                 }
                 if (!is_writeable($attachment_path . $attachment_bucket)) {
                     echo "Can't write to bucket " . $attachment_path . $attachment_bucket . "<BR>";
                 }
                 copy($file, $attachment_path . $attachment_bucket . $attachment_file);
                 @unlink($file);
                 DAO_Attachment::update($file_id, array(DAO_Attachment::FILEPATH => $attachment_bucket . $attachment_file));
             }
         }
         // add note to message if email failed
         if ($mail_succeeded === false) {
             $fields = array(DAO_MessageNote::MESSAGE_ID => $message_id, DAO_MessageNote::CREATED => time(), DAO_MessageNote::WORKER_ID => 0, DAO_MessageNote::CONTENT => 'Exception thrown while sending email: ' . $e->getMessage(), DAO_MessageNote::TYPE => Model_MessageNote::TYPE_ERROR);
             DAO_MessageNote::create($fields);
         }
     }
     // Post-Reply Change Properties
     if (isset($properties['closed'])) {
         switch ($properties['closed']) {
             case 0:
                 // open
                 $change_fields[DAO_Ticket::IS_WAITING] = 0;
                 $change_fields[DAO_Ticket::IS_CLOSED] = 0;
                 $change_fields[DAO_Ticket::IS_DELETED] = 0;
                 $change_fields[DAO_Ticket::DUE_DATE] = 0;
                 break;
             case 1:
                 // closed
                 $change_fields[DAO_Ticket::IS_WAITING] = 0;
                 $change_fields[DAO_Ticket::IS_CLOSED] = 1;
                 $change_fields[DAO_Ticket::IS_DELETED] = 0;
                 if (isset($properties['ticket_reopen'])) {
                     @($time = intval(strtotime($properties['ticket_reopen'])));
                     $change_fields[DAO_Ticket::DUE_DATE] = $time;
                 }
                 break;
             case 2:
                 // waiting
                 $change_fields[DAO_Ticket::IS_WAITING] = 1;
                 $change_fields[DAO_Ticket::IS_CLOSED] = 0;
                 $change_fields[DAO_Ticket::IS_DELETED] = 0;
                 if (isset($properties['ticket_reopen'])) {
                     @($time = intval(strtotime($properties['ticket_reopen'])));
                     $change_fields[DAO_Ticket::DUE_DATE] = $time;
                 }
                 break;
         }
     }
     // Who should handle the followup?
     if (isset($properties['next_worker_id'])) {
         $change_fields[DAO_Ticket::NEXT_WORKER_ID] = $properties['next_worker_id'];
     }
     // Allow anybody to reply after
     if (isset($properties['unlock_date']) && !empty($properties['unlock_date'])) {
         $unlock = strtotime($properties['unlock_date']);
         if (intval($unlock) > 0) {
             $change_fields[DAO_Ticket::UNLOCK_DATE] = $unlock;
         }
     }
     // Move
     if (!empty($properties['bucket_id'])) {
         // [TODO] Use API to move, or fire event
         // [TODO] Ensure team/bucket exist
         list($team_id, $bucket_id) = CerberusApplication::translateTeamCategoryCode($properties['bucket_id']);
         $change_fields[DAO_Ticket::TEAM_ID] = $team_id;
         $change_fields[DAO_Ticket::CATEGORY_ID] = $bucket_id;
     }
     if (!empty($ticket_id) && !empty($change_fields)) {
         DAO_Ticket::updateTicket($ticket_id, $change_fields);
     }
     // Outbound Reply Event (not automated reply, etc.)
     if (!empty($worker_id)) {
         $eventMgr = DevblocksPlatform::getEventService();
         $eventMgr->trigger(new Model_DevblocksEvent('ticket.reply.outbound', array('ticket_id' => $ticket_id, 'worker_id' => $worker_id)));
     }
 }
Пример #8
0
 private function _sendForwards($event, $is_inbound)
 {
     @($ticket_id = $event->params['ticket_id']);
     @($send_worker_id = $event->params['worker_id']);
     $ticket = DAO_Ticket::getTicket($ticket_id);
     // Find all our matching filters
     if (false == ($matches = Model_WatcherMailFilter::getMatches($ticket, $is_inbound ? 'mail_incoming' : 'mail_outgoing'))) {
         return;
     }
     // Sanitize and combine all the destination addresses
     $notify_emails = $this->_getMailingListFromMatches($matches);
     if (empty($notify_emails)) {
         return;
     }
     // [TODO] This could be more efficient
     $messages = DAO_Ticket::getMessagesByTicket($ticket_id);
     $message = end($messages);
     // last message
     unset($messages);
     $headers = $message->getHeaders();
     // The whole flipping Swift section needs wrapped to catch exceptions
     try {
         $settings = CerberusSettings::getInstance();
         $reply_to = $settings->get(CerberusSettings::DEFAULT_REPLY_FROM, '');
         // See if we need a group-specific reply-to
         if (!empty($ticket->team_id)) {
             @($group_from = DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_REPLY_FROM, ''));
             if (!empty($group_from)) {
                 $reply_to = $group_from;
             }
         }
         $sender = DAO_Address::get($message->address_id);
         $sender_email = strtolower($sender->email);
         $sender_split = explode('@', $sender_email);
         if (!is_array($sender_split) || count($sender_split) != 2) {
             return;
         }
         // If return-path is blank
         if (isset($headers['return-path']) && $headers['return-path'] == '<>') {
             return;
         }
         // Ignore bounces
         if ($sender_split[0] == "postmaster" || $sender_split[0] == "mailer-daemon") {
             return;
         }
         // Ignore autoresponses autoresponses
         if (isset($headers['auto-submitted']) && $headers['auto-submitted'] != 'no') {
             return;
         }
         // Attachments
         $attachments = $message->getAttachments();
         $mime_attachments = array();
         if (is_array($attachments)) {
             foreach ($attachments as $attachment) {
                 if (0 == strcasecmp($attachment->display_name, 'original_message.html')) {
                     continue;
                 }
                 $attachment_path = APP_STORAGE_PATH . '/attachments/';
                 // [TODO] This is highly redundant in the codebase
                 if (!file_exists($attachment_path . $attachment->filepath)) {
                     continue;
                 }
                 $file =& new Swift_File($attachment_path . $attachment->filepath);
                 $mime_attachments[] =& new Swift_Message_Attachment($file, $attachment->display_name, $attachment->mime_type);
             }
         }
         // Send copies
         if (is_array($notify_emails) && !empty($notify_emails)) {
             $mail_service = DevblocksPlatform::getMailService();
             $mailer = $mail_service->getMailer(CerberusMail::getMailerDefaults());
             foreach ($notify_emails as $to) {
                 // Proxy the message
                 $rcpt_to = new Swift_RecipientList();
                 $a_rcpt_to = array();
                 $mail_from = new Swift_Address($sender->email);
                 $rcpt_to->addTo($to);
                 $a_rcpt_to = new Swift_Address($to);
                 $mail = $mail_service->createMessage();
                 /* @var $mail Swift_Message */
                 $mail->setTo($a_rcpt_to);
                 $mail->setFrom($mail_from);
                 $mail->setReplyTo($reply_to);
                 $mail->setReturnPath($reply_to);
                 $mail->setSubject(sprintf("[%s #%s]: %s", $is_inbound ? 'inbound' : 'outbound', $ticket->mask, $ticket->subject));
                 if (false !== @($msgid = $headers['message-id'])) {
                     $mail->headers->set('Message-Id', $msgid);
                 }
                 if (false !== @($in_reply_to = $headers['in-reply-to'])) {
                     $mail->headers->set('References', $in_reply_to);
                     $mail->headers->set('In-Reply-To', $in_reply_to);
                 }
                 $mail->headers->set('X-Mailer', 'Cerberus Helpdesk (Build ' . APP_BUILD . ')');
                 $mail->headers->set('Precedence', 'List');
                 $mail->headers->set('Auto-Submitted', 'auto-generated');
                 $mail->attach(new Swift_Message_Part($message->getContent(), 'text/plain', 'base64', LANG_CHARSET_CODE));
                 // Send message attachments with watcher
                 if (is_array($mime_attachments)) {
                     foreach ($mime_attachments as $mime_attachment) {
                         $mail->attach($mime_attachment);
                     }
                 }
                 $mailer->send($mail, $rcpt_to, $mail_from);
             }
         }
     } catch (Exception $e) {
         $fields = array(DAO_MessageNote::MESSAGE_ID => $message_id, DAO_MessageNote::CREATED => time(), DAO_MessageNote::WORKER_ID => 0, DAO_MessageNote::CONTENT => 'Exception thrown while sending watcher email: ' . $e->getMessage(), DAO_MessageNote::TYPE => Model_MessageNote::TYPE_ERROR);
         DAO_MessageNote::create($fields);
     }
 }
Пример #9
0
 function showTab()
 {
     $response = DevblocksPlatform::getHttpResponse();
     $path = $response->path;
     array_shift($path);
     // iphone
     array_shift($path);
     // tickets
     array_shift($path);
     // current ('display')
     $id = array_shift($path);
     // ticket id
     @($active_worker = CerberusApplication::getActiveWorker());
     $tpl = DevblocksPlatform::getTemplateService();
     $tpl->assign('path', $this->_TPL_PATH);
     $tpl->assign('expand_all', $expand_all);
     $ticket = DAO_Ticket::getTicket($id);
     $tpl->assign('requesters', $ticket->getRequesters());
     // Drafts
     $drafts = DAO_MailQueue::getWhere(sprintf("%s = %d AND %s = %s", DAO_MailQueue::TICKET_ID, $id, DAO_MailQueue::TYPE, C4_ORMHelper::qstr(Model_MailQueue::TYPE_TICKET_REPLY)));
     if (!empty($drafts)) {
         $tpl->assign('drafts', $drafts);
     }
     // Only unqueued drafts
     $pending_drafts = array();
     if (!empty($drafts) && is_array($drafts)) {
         foreach ($drafts as $draft_id => $draft) {
             if (!$draft->is_queued) {
                 $pending_drafts[$draft_id] = $draft;
             }
         }
     }
     if (!empty($pending_drafts)) {
         $tpl->assign('pending_drafts', $pending_drafts);
     }
     // Messages
     $messages = $ticket->getMessages();
     arsort($messages);
     $tpl->assign('latest_message_id', key($messages));
     $tpl->assign('messages', $messages);
     // Thread comments and messages on the same level
     $convo_timeline = array();
     // Track senders and their orgs
     $message_senders = array();
     $message_sender_orgs = array();
     // Loop messages
     foreach ($messages as $message_id => $message) {
         /* @var $message Model_Message */
         $key = $message->created_date . '_m' . $message_id;
         // build a chrono index of messages
         $convo_timeline[$key] = array('m', $message_id);
         // If we haven't cached this sender address yet
         if (!isset($message_senders[$message->address_id])) {
             if (null != ($sender_addy = DAO_Address::get($message->address_id))) {
                 $message_senders[$sender_addy->id] = $sender_addy;
                 // If we haven't cached this sender org yet
                 if (!isset($message_sender_orgs[$sender_addy->contact_org_id])) {
                     if (null != ($sender_org = DAO_ContactOrg::get($sender_addy->contact_org_id))) {
                         $message_sender_orgs[$sender_org->id] = $sender_org;
                     }
                 }
             }
         }
     }
     $tpl->assign('message_senders', $message_senders);
     $tpl->assign('message_sender_orgs', $message_sender_orgs);
     @($mail_inline_comments = DAO_WorkerPref::get($active_worker->id, 'mail_inline_comments', 1));
     if ($mail_inline_comments) {
         // if inline comments are enabled
         $comments = DAO_TicketComment::getByTicketId($id);
         arsort($comments);
         $tpl->assign('comments', $comments);
         // build a chrono index of comments
         foreach ($comments as $comment_id => $comment) {
             /* @var $comment Model_TicketComment */
             $key = $comment->created . '_c' . $comment_id;
             $convo_timeline[$key] = array('c', $comment_id);
         }
     }
     // Thread drafts into conversation
     if (!empty($drafts)) {
         foreach ($drafts as $draft_id => $draft) {
             /* @var $draft Model_MailQueue */
             $key = $draft->updated . '_d' . $draft_id;
             $convo_timeline[$key] = array('d', $draft_id);
         }
     }
     // sort the timeline
     if (!$expand_all) {
         krsort($convo_timeline);
     } else {
         ksort($convo_timeline);
     }
     $tpl->assign('convo_timeline', $convo_timeline);
     // Message Notes
     $notes = DAO_MessageNote::getByTicketId($id);
     $message_notes = array();
     // Index notes by message id
     if (is_array($notes)) {
         foreach ($notes as $note) {
             if (!isset($message_notes[$note->message_id])) {
                 $message_notes[$note->message_id] = array();
             }
             $message_notes[$note->message_id][$note->id] = $note;
         }
     }
     $tpl->assign('message_notes', $message_notes);
     // Message toolbar items
     $messageToolbarItems = DevblocksPlatform::getExtensions('cerberusweb.message.toolbaritem', true);
     if (!empty($messageToolbarItems)) {
         $tpl->assign('message_toolbaritems', $messageToolbarItems);
     }
     // Workers
     $workers = DAO_Worker::getAll();
     $tpl->assign('workers', $workers);
     $tpl->display('file:' . $this->_TPL_PATH . 'tickets/display/conversation.tpl');
 }