static function sendMailProperties($properties) { $status = true; @($toStr = $properties['to']); @($cc = $properties['cc']); @($bcc = $properties['bcc']); @($subject = $properties['subject']); @($content = $properties['content']); @($files = $properties['files']); $mail_settings = self::getMailerDefaults(); if (empty($properties['from_addy'])) { @($from_addy = $settings->get('feg.core', FegSettings::DEFAULT_REPLY_FROM, $_SERVER['SERVER_ADMIN'])); } if (empty($properties['from_personal'])) { @($from_personal = $settings->get('feg.core', FegSettings::DEFAULT_REPLY_PERSONAL, '')); } if (empty($subject)) { $subject = '(no subject)'; } // [JAS]: Replace any semi-colons with commas (people like using either) $toList = DevblocksPlatform::parseCsvString(str_replace(';', ',', $toStr)); $mail_headers = array(); $mail_headers['X-FegCompose'] = '1'; // Headers needed for the ticket message $log_headers = new Swift_Message_Headers(); $log_headers->setCharset(LANG_CHARSET_CODE); $log_headers->set('To', $toList); $log_headers->set('From', !empty($from_personal) ? sprintf("%s <%s>", $from_personal, $from_addy) : sprintf('%s', $from_addy)); $log_headers->set('Subject', $subject); $log_headers->set('Date', date('r')); foreach ($log_headers->getList() as $hdr => $v) { if (null != ($hdr_val = $log_headers->getEncoded($hdr))) { if (!empty($hdr_val)) { $mail_headers[$hdr] = $hdr_val; } } } try { $mail_service = DevblocksPlatform::getMailService(); $mailer = $mail_service->getMailer(FegMail::getMailerDefaults()); $email = $mail_service->createMessage(); $email->setTo($toList); // cc $ccs = array(); if (!empty($cc) && null != ($ccList = DevblocksPlatform::parseCsvString(str_replace(';', ',', $cc)))) { $email->setCc($ccList); } // bcc if (!empty($bcc) && null != ($bccList = DevblocksPlatform::parseCsvString(str_replace(';', ',', $bcc)))) { $email->setBcc($bccList); } $email->setFrom(array($from => $personal)); $email->setSubject($subject); $email->generateId(); $headers = $email->getHeaders(); $headers->addTextHeader('X-Mailer', 'Fax Email Gateway (FEG) ' . APP_VERSION . ' (Build ' . APP_BUILD . ')'); $email->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; } $email->attach(Swift_Attachment::fromPath($file)->setFilename($files['name'][$idx])); } } // Headers foreach ($email->getHeaders()->getAll() as $hdr) { if (null != ($hdr_val = $hdr->getFieldBody())) { if (!empty($hdr_val)) { $mail_headers[$hdr->getFieldName()] = $hdr_val; } } } // [TODO] Allow separated addresses (parseRfcAddress) // $mailer->log->enable(); if (!@$mailer->send($email)) { throw new Exception('Mail failed to send: unknown reason'); } // $mailer->log->dump(); } catch (Exception $e) { // Do Something $status = false; } // Give plugins a chance to note a message is imported. $eventMgr = DevblocksPlatform::getEventService(); $eventMgr->trigger(new Model_DevblocksEvent('email.send', array('properties' => $properties, 'send_status' => $status ? 2 : 1))); return $status; }
static function compose($properties) { @($team_id = $properties['team_id']); @($toStr = $properties['to']); @($cc = $properties['cc']); @($bcc = $properties['bcc']); @($subject = $properties['subject']); @($content = $properties['content']); @($files = $properties['files']); @($no_mail = $properties['no_mail']); @($closed = $properties['closed']); @($move_bucket = $properties['move_bucket']); @($next_worker_id = $properties['next_worker_id']); @($ticket_reopen = $properties['ticket_reopen']); @($unlock_date = $properties['unlock_date']); $worker = CerberusApplication::getActiveWorker(); $settings = DevblocksPlatform::getPluginSettingsService(); $default_from = $settings->get('cerberusweb.core', CerberusSettings::DEFAULT_REPLY_FROM); $default_personal = $settings->get('cerberusweb.core', CerberusSettings::DEFAULT_REPLY_PERSONAL); $team_from = DAO_GroupSettings::get($team_id, DAO_GroupSettings::SETTING_REPLY_FROM, ''); $team_personal = DAO_GroupSettings::get($team_id, DAO_GroupSettings::SETTING_REPLY_PERSONAL, ''); $team_personal_with_worker = DAO_GroupSettings::get($team_id, DAO_GroupSettings::SETTING_REPLY_PERSONAL_WITH_WORKER, 0); $from = !empty($team_from) ? $team_from : $default_from; $personal = !empty($team_personal) ? $team_personal : $default_personal; // Prefix the worker name on the personal line? if (!empty($team_personal_with_worker) && !empty($worker)) { $personal = $worker->getName() . ', ' . $personal; } $mask = CerberusApplication::generateTicketMask(); if (empty($subject)) { $subject = '(no subject)'; } // add mask to subject if group setting calls for it @($group_has_subject = intval(DAO_GroupSettings::get($team_id, DAO_GroupSettings::SETTING_SUBJECT_HAS_MASK, 0))); @($group_subject_prefix = DAO_GroupSettings::get($team_id, DAO_GroupSettings::SETTING_SUBJECT_PREFIX, '')); $prefix = sprintf("[%s#%s] ", !empty($group_subject_prefix) ? $group_subject_prefix . ' ' : '', $mask); $subject_mailed = sprintf('%s%s', $group_has_subject ? $prefix : '', $subject); // [JAS]: Replace any semi-colons with commas (people like using either) $toList = DevblocksPlatform::parseCsvString(str_replace(';', ',', $toStr)); $mail_headers = array(); $mail_headers['X-CerberusCompose'] = '1'; $mail_succeeded = true; if (!empty($no_mail)) { // allow compose without sending mail // Headers needed for the ticket message $log_headers = new Swift_Message_Headers(); $log_headers->setCharset(LANG_CHARSET_CODE); $log_headers->set('To', $toStr); $log_headers->set('From', !empty($personal) ? sprintf("%s <%s>", $personal, $from) : sprintf('%s', $from)); $log_headers->set('Subject', $subject_mailed); $log_headers->set('Date', date('r')); foreach ($log_headers->getList() as $hdr => $v) { if (null != ($hdr_val = $log_headers->getEncoded($hdr))) { if (!empty($hdr_val)) { $mail_headers[$hdr] = $hdr_val; } } } } else { // regular mail sending try { $mail_service = DevblocksPlatform::getMailService(); $mailer = $mail_service->getMailer(CerberusMail::getMailerDefaults()); $email = $mail_service->createMessage(); $email->setTo($toList); // cc $ccs = array(); if (!empty($cc) && null != ($ccList = DevblocksPlatform::parseCsvString(str_replace(';', ',', $cc)))) { $email->setCc($ccList); } // bcc if (!empty($bcc) && null != ($bccList = DevblocksPlatform::parseCsvString(str_replace(';', ',', $bcc)))) { $email->setBcc($bccList); } $email->setFrom(array($from => $personal)); $email->setSubject($subject_mailed); $email->generateId(); $headers = $email->getHeaders(); $headers->addTextHeader('X-Mailer', 'Cerberus Helpdesk (Build ' . APP_BUILD . ')'); $email->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; } $email->attach(Swift_Attachment::fromPath($file)->setFilename($files['name'][$idx])); } } // [TODO] Allow separated addresses (parseRfcAddress) // $mailer->log->enable(); if (!$mailer->send($email)) { $mail_succeeded = false; throw new Exception('Mail failed to send: unknown reason'); } // $mailer->log->dump(); } catch (Exception $e) { // tag mail as failed, add note to message after message gets created $mail_succeeded = false; } // Headers foreach ($email->getHeaders()->getAll() as $hdr) { if (null != ($hdr_val = $hdr->getFieldBody())) { if (!empty($hdr_val)) { $mail_headers[$hdr->getFieldName()] = $hdr_val; } } } } $fromAddressInst = CerberusApplication::hashLookupAddress($from, true); $fromAddressId = $fromAddressInst->id; // [TODO] this is redundant with the Parser code. Should be refactored later $fields = array(DAO_Ticket::MASK => $mask, DAO_Ticket::SUBJECT => $subject, DAO_Ticket::CREATED_DATE => time(), DAO_Ticket::FIRST_WROTE_ID => $fromAddressId, DAO_Ticket::LAST_WROTE_ID => $fromAddressId, DAO_Ticket::LAST_ACTION_CODE => CerberusTicketActionCode::TICKET_WORKER_REPLY, DAO_Ticket::LAST_WORKER_ID => $worker->id, DAO_Ticket::NEXT_WORKER_ID => 0, DAO_Ticket::TEAM_ID => $team_id); // "Next:" [TODO] This is highly redundant with CerberusMail::reply if (isset($closed) && 1 == $closed) { $fields[DAO_Ticket::IS_CLOSED] = 1; } if (isset($closed) && 2 == $closed) { $fields[DAO_Ticket::IS_WAITING] = 1; } if (!empty($move_bucket)) { list($team_id, $bucket_id) = CerberusApplication::translateTeamCategoryCode($move_bucket); $fields[DAO_Ticket::TEAM_ID] = $team_id; $fields[DAO_Ticket::CATEGORY_ID] = $bucket_id; } if (isset($next_worker_id)) { $fields[DAO_Ticket::NEXT_WORKER_ID] = intval($next_worker_id); } if (isset($ticket_reopen) && !empty($ticket_reopen)) { $due = strtotime($ticket_reopen); if ($due) { $fields[DAO_Ticket::DUE_DATE] = $due; } } // Allow anybody to reply after if (!empty($unlock_date)) { $unlock = strtotime($unlock_date); if (intval($unlock) > 0) { $fields[DAO_Ticket::UNLOCK_DATE] = $unlock; } } // End "Next:" $ticket_id = DAO_Ticket::createTicket($fields); $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); // Link Message to Ticket DAO_Ticket::updateTicket($ticket_id, array(DAO_Ticket::FIRST_MESSAGE_ID => $message_id)); // Content DAO_MessageContent::create($message_id, $content); // Set recipients to requesters foreach ($toList as $to) { if (null != ($reqAddressInst = CerberusApplication::hashLookupAddress($to, true))) { $reqAddressId = $reqAddressInst->id; DAO_Ticket::createRequester($reqAddressId, $ticket_id); } } // Headers foreach ($mail_headers as $hdr => $hdr_val) { DAO_MessageHeader::create($message_id, $hdr, CerberusParser::fixQuotePrintableString($hdr_val)); } // add files to ticket // [TODO] redundant with parser (like most of the rest of this function) 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 " . $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)); } } // Train as not spam CerberusBayes::markTicketAsNotSpam($ticket_id); // Inbound/Outbound Reply Event // [TODO] This pivots on $no_mail for now, but this functionality may change $eventMgr = DevblocksPlatform::getEventService(); if ($no_mail) { // inbound $eventMgr->trigger(new Model_DevblocksEvent('ticket.reply.inbound', array('ticket_id' => $ticket_id))); } else { // outbound if (!empty($worker->id)) { $eventMgr->trigger(new Model_DevblocksEvent('ticket.reply.outbound', array('ticket_id' => $ticket_id, 'worker_id' => $worker->id))); } } // if email sending failed, add an error note to the message 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); } return $ticket_id; }