コード例 #1
0
ファイル: display.php プロジェクト: jsjohnst/cerb4
 function doSplitMessageAction()
 {
     @($id = DevblocksPlatform::importGPC($_REQUEST['id'], 'integer', 0));
     if (null == ($orig_message = DAO_Ticket::getMessage($id))) {
         return;
     }
     if (null == ($orig_headers = $orig_message->getHeaders())) {
         return;
     }
     if (null == ($orig_ticket = DAO_Ticket::getTicket($orig_message->ticket_id))) {
         return;
     }
     if (null == ($messages = DAO_Ticket::getMessagesByTicket($orig_message->ticket_id))) {
         return;
     }
     // Create a new ticket
     $new_ticket_mask = CerberusApplication::generateTicketMask();
     $new_ticket_id = DAO_Ticket::createTicket(array(DAO_Ticket::CREATED_DATE => $orig_message->created_date, DAO_Ticket::UPDATED_DATE => $orig_message->created_date, DAO_Ticket::CATEGORY_ID => $orig_ticket->category_id, DAO_Ticket::FIRST_MESSAGE_ID => $orig_message->id, DAO_Ticket::FIRST_WROTE_ID => $orig_message->address_id, DAO_Ticket::LAST_WROTE_ID => $orig_message->address_id, DAO_Ticket::LAST_ACTION_CODE => CerberusTicketActionCode::TICKET_OPENED, DAO_Ticket::IS_CLOSED => CerberusTicketStatus::OPEN, DAO_Ticket::IS_DELETED => 0, DAO_Ticket::MASK => $new_ticket_mask, DAO_Ticket::SUBJECT => isset($orig_headers['subject']) ? $orig_headers['subject'] : $orig_ticket->subject, DAO_Ticket::TEAM_ID => $orig_ticket->team_id));
     // [TODO] SLA?
     // Copy all the original tickets requesters
     $orig_requesters = DAO_Ticket::getRequestersByTicket($orig_ticket->id);
     foreach ($orig_requesters as $orig_req_id => $orig_req_addy) {
         DAO_Ticket::createRequester($orig_req_id, $new_ticket_id);
     }
     // Pull the message off the ticket (reparent)
     unset($messages[$orig_message->id]);
     DAO_Message::update($orig_message->id, array(DAO_Message::TICKET_ID => $new_ticket_id));
     //[mdf] [CHD-979] The ticket id is also in the message_header table, so update those too
     $message_headers = DAO_MessageHeader::getAll($orig_message->id);
     foreach ($message_headers as $hk => $hv) {
         DAO_MessageHeader::create($orig_message->id, $new_ticket_id, $hk, $hv);
     }
     // Reindex the original ticket (last wrote, etc.)
     $last_message = end($messages);
     /* @var CerberusMessage $last_message */
     DAO_Ticket::updateTicket($orig_ticket->id, array(DAO_Ticket::LAST_WROTE_ID => $last_message->address_id));
     // Remove requester if they don't still have messages on the original ticket
     reset($messages);
     $found = false;
     if (is_array($messages)) {
         foreach ($messages as $msgid => $msg) {
             if ($msg->address_id == $orig_message->address_id) {
                 $found = true;
                 break;
             }
         }
     }
     if (!$found) {
         DAO_Ticket::deleteRequester($orig_ticket->id, $orig_message->address_id);
     }
     DevblocksPlatform::redirect(new DevblocksHttpResponse(array('display', $new_ticket_mask)));
 }
コード例 #2
0
ファイル: Bayes.php プロジェクト: joegeck/cerb4
 private static function _markTicketAs($ticket_id, $spam = true)
 {
     // [TODO] Make sure we can't retrain tickets which are already spam trained
     // [TODO] This is a performance killer
     $ticket = DAO_Ticket::getTicket($ticket_id);
     if ($ticket->spam_training != CerberusTicketSpamTraining::BLANK) {
         return TRUE;
     }
     // pull up text of first ticket message
     // [TODO] This is a performance killer
     $first_message = DAO_Ticket::getMessage($ticket->first_message_id);
     if (empty($first_message)) {
         return FALSE;
     }
     // [TODO] This is a performance killer
     $headers = DAO_MessageHeader::getAll($first_message->id);
     // Pass text to analyze() to get back interesting words
     $content = '';
     if (!empty($ticket->subject)) {
         // SplitCamelCapsSubjects
         $hits = preg_split("{(?<=[a-z])(?=[A-Z])}x", $ticket->subject);
         if (is_array($hits) && !empty($hits)) {
             $content .= implode(' ', $hits);
         }
     }
     $content .= ' ' . $first_message->getContent();
     if (strlen($content) > self::MAX_BODY_LENGTH) {
         $content = substr($content, 0, strrpos(substr($content, 0, self::MAX_BODY_LENGTH), ' '));
     }
     $words = self::processText($content);
     // Train interesting words as spam/notspam
     //		$out = self::_calculateSpamProbability($words);
     //		self::_trainWords($out['words'],$spam);
     self::_trainWords($words, $spam);
     // [TODO] Testing, train all words
     // Increase the bayes_stats spam or notspam total count by 1
     // [TODO] This is a performance killer (could be done in batches)
     if ($spam) {
         DAO_Bayes::addOneToSpamTotal();
         DAO_Address::addOneToSpamTotal($ticket->first_wrote_address_id);
     } else {
         DAO_Bayes::addOneToNonSpamTotal();
         DAO_Address::addOneToNonSpamTotal($ticket->first_wrote_address_id);
     }
     // Forced training should leave a cache of 0.0001 or 0.9999 on the ticket table
     $fields = array('spam_score' => $spam ? 0.9999 : 0.0001, 'spam_training' => $spam ? CerberusTicketSpamTraining::SPAM : CerberusTicketSpamTraining::NOT_SPAM);
     DAO_Ticket::updateTicket($ticket_id, $fields);
     return TRUE;
 }
コード例 #3
0
ファイル: Model.class.php プロジェクト: rmiddle/cerb4
 function getHeaders()
 {
     return DAO_MessageHeader::getAll($this->id);
 }
コード例 #4
0
ファイル: App.php プロジェクト: joegeck/cerb4
 private function _getMessageXML($id)
 {
     $message = DAO_Ticket::getMessage($id);
     /* @var $message CerberusMessage */
     if (is_null($message)) {
         $this->_error("ID {$id} not valid.");
     }
     $message_content = DAO_MessageContent::get($id);
     $message_headers = DAO_MessageHeader::getAll($id);
     $message_notes = DAO_MessageNote::getByMessageId($id);
     $xml_out = new SimpleXMLElement("<message></message>");
     $xml_out->addChild('id', $message->id);
     $xml_out->addChild('ticket_id', $message->ticket_id);
     $xml_out->addChild('created_date', $message->created_date);
     $xml_out->addChild('address_id', $message->address_id);
     $xml_out->addChild('is_outgoing', $message->is_outgoing);
     $xml_out->addChild('worker_id', $message->worker_id);
     $xml_out->addChild('content', $message_content);
     $headers = $xml_out->addChild('headers');
     foreach ($message_headers as $header_name => $header_value) {
         $headers->addChild($header_name, $header_value);
     }
     $xml_notes = $xml_out->addChild('notes');
     foreach ($message_notes as $note) {
         $xml_note = $xml_notes->addChild('note');
         $xml_note->addChild('id', $note->id);
         $xml_note->addChild('type', $note->type);
         $xml_note->addChild('message_id', $note->message_id);
         $xml_note->addChild('created', $note->created);
         $xml_note->addChild('worker_id', $note->worker_id);
         $xml_note->addChild('content', $note->content);
     }
     return $xml_out;
 }
コード例 #5
0
ファイル: Mail.php プロジェクト: Hildy/cerb5
 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)));
     }
 }