Support::removeEmail($HTTP_POST_VARS['item'][$i]); } } $tpl->assign("associate_result", $res); } @$tpl->assign('total_emails', count($HTTP_POST_VARS['item'])); } else { @$tpl->assign('emails', $HTTP_GET_VARS['item']); @$tpl->assign('total_emails', count($HTTP_GET_VARS['item'])); $prj_id = Issue::getProjectID($HTTP_GET_VARS['issue']); if (Customer::hasCustomerIntegration($prj_id)) { // check if the selected emails all have sender email addresses that are associated with the issue' customer $senders = Support::getSender($HTTP_GET_VARS['item']); $sender_emails = array(); for ($i = 0; $i < count($senders); $i++) { $email = Mail_API::getEmailAddress($senders[$i]); $sender_emails[$email] = $senders[$i]; } $customer_id = Issue::getCustomerID($HTTP_GET_VARS['issue']); if (!empty($customer_id)) { $contact_emails = array_keys(Customer::getContactEmailAssocList($prj_id, $customer_id)); $unknown_contacts = array(); foreach ($sender_emails as $email => $address) { if (!@in_array($email, $contact_emails)) { $usr_id = User::getUserIDByEmail($email); if (empty($usr_id)) { $unknown_contacts[] = $address; } else { // if we got a real user ID, check if the customer user is the correct one // (i.e. a contact from the customer associated with the selected issue) if (User::getRoleByUser($usr_id, $prj_id) == User::getRoleID('Customer')) {
/** * Method used to get a list of emails that are associated with a given * project and issue. * * @access public * @param integer $prj_id The project ID * @param integer $issue_id The issue ID * @return array List of emails */ function getAddressBookEmails($prj_id, $issue_id) { $list = Project::getAddressBook($prj_id, $issue_id); $emails = array(); foreach ($list as $address => $name) { $emails[] = Mail_API::getEmailAddress($address); } return $emails; }
/** * Check if this email needs to be blocked and if so, block it. * * */ function blockEmailIfNeeded($email) { global $HTTP_POST_VARS; if (empty($email['issue_id'])) { return false; } $issue_id = $email['issue_id']; $prj_id = Issue::getProjectID($issue_id); $sender_email = strtolower(Mail_API::getEmailAddress($email['headers']['from'])); if (Mail_API::isVacationAutoResponder($email['headers']) || Notification::isBounceMessage($sender_email) || !Support::isAllowedToEmail($issue_id, $sender_email)) { // add the message body as a note $HTTP_POST_VARS = array('blocked_msg' => $email['full_email'], 'title' => @$email['headers']['subject'], 'note' => Mail_API::getCannedBlockedMsgExplanation($issue_id) . $email['body']); // avoid having this type of message re-open the issue if (Mail_API::isVacationAutoResponder($email['headers'])) { $closing = true; } else { $closing = false; } $res = Note::insert(Auth::getUserID(), $issue_id, $email['headers']['from'], false, $closing); // associate the email attachments as internal-only files on this issue if ($res != -1) { Support::extractAttachments($issue_id, $email['full_email'], true, $res); } $HTTP_POST_VARS['issue_id'] = $issue_id; $HTTP_POST_VARS['from'] = $sender_email; // avoid having this type of message re-open the issue if (Mail_API::isVacationAutoResponder($email['headers'])) { $email_type = 'vacation-autoresponder'; } else { $email_type = 'routed'; } Workflow::handleBlockedEmail($prj_id, $issue_id, $HTTP_POST_VARS, $email_type); // try to get usr_id of sender, if not, use system account $usr_id = User::getUserIDByEmail(Mail_API::getEmailAddress($email['from'])); if (!$usr_id) { $usr_id = APP_SYSTEM_USER_ID; } // log blocked email History::add($issue_id, $usr_id, History::getTypeID('email_blocked'), "Email from '" . $email['from'] . "' blocked."); return true; } return false; }
<?php /* * Runonce script to set the sup_usr_id field in support_email */ include_once "../../../config.inc.php"; include_once APP_INC_PATH . "db_access.php"; $stmt = "SELECT\n sup_id,\n sup_from\n FROM\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "support_email\n WHERE\n sup_usr_id IS NULL AND\n sup_iss_id != 0"; $res = $GLOBALS["db_api"]->dbh->getAssoc($stmt); foreach ($res as $sup_id => $email) { $usr_id = User::getUserIDByEmail(Mail_API::getEmailAddress($email)); if (!empty($usr_id)) { $stmt = "UPDATE\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "support_email\n SET\n sup_usr_id = {$usr_id}\n WHERE\n sup_id = {$sup_id}"; $update = $GLOBALS["db_api"]->dbh->query($stmt); if (PEAR::isError($update)) { echo "<pre>"; var_dump($update); echo "</pre>"; exit(1); } } } echo "complete";
/** * Converts a note to a draft or an email * * @access public * @param $note_id The id of the note * @param $target What the not should be converted too * @param $authorize_sender If the sender should be added to authorized senders list. */ function convertNote($note_id, $target, $authorize_sender = false) { $note_id = Misc::escapeInteger($note_id); $issue_id = Note::getIssueID($note_id); $email_account_id = Email_Account::getEmailAccount(); $blocked_message = Note::getBlockedMessage($note_id); $unknown_user = Note::getUnknownUser($note_id); $structure = Mime_Helper::decode($blocked_message, true, true); $body = Mime_Helper::getMessageBody($structure); $sender_email = strtolower(Mail_API::getEmailAddress($structure->headers['from'])); if ($target == 'email') { if (Mime_Helper::hasAttachments($blocked_message)) { $has_attachments = 1; } else { $has_attachments = 0; } list($blocked_message, $headers) = Mail_API::rewriteThreadingHeaders($issue_id, $blocked_message, @$structure->headers); $t = array('issue_id' => $issue_id, 'ema_id' => $email_account_id, 'message_id' => @$structure->headers['message-id'], 'date' => Date_API::getCurrentDateGMT(), 'from' => @$structure->headers['from'], 'to' => @$structure->headers['to'], 'cc' => @$structure->headers['cc'], 'subject' => @$structure->headers['subject'], 'body' => @$body, 'full_email' => @$blocked_message, 'has_attachment' => $has_attachments, 'headers' => $headers); // need to check for a possible customer association if (!empty($structure->headers['from'])) { $details = Email_Account::getDetails($email_account_id); // check from the associated project if we need to lookup any customers by this email address if (Customer::hasCustomerIntegration($details['ema_prj_id'])) { // check for any customer contact association list($customer_id, ) = Customer::getCustomerIDByEmails($details['ema_prj_id'], array($sender_email)); if (!empty($customer_id)) { $t['customer_id'] = $customer_id; } } } if (empty($t['customer_id'])) { $update_type = 'staff response'; $t['customer_id'] = "NULL"; } else { $update_type = 'customer action'; } $res = Support::insertEmail($t, $structure, $sup_id); if ($res != -1) { Support::extractAttachments($issue_id, $blocked_message); // notifications about new emails are always external $internal_only = false; // special case when emails are bounced back, so we don't want to notify the customer about those if (Notification::isBounceMessage($sender_email)) { $internal_only = true; } Notification::notifyNewEmail(Auth::getUserID(), $issue_id, $t, $internal_only, false, '', $sup_id); Issue::markAsUpdated($issue_id, $update_type); Note::remove($note_id, false); History::add($issue_id, Auth::getUserID(), History::getTypeID('note_converted_email'), "Note converted to e-mail (from: " . @$structure->headers['from'] . ") by " . User::getFullName(Auth::getUserID())); // now add sender as an authorized replier if ($authorize_sender) { Authorized_Replier::manualInsert($issue_id, @$structure->headers['from']); } } return $res; } else { // save message as a draft $res = Draft::saveEmail($issue_id, $structure->headers['to'], $structure->headers['cc'], $structure->headers['subject'], $body, false, $unknown_user); // remove the note, if the draft was created successfully if ($res) { Note::remove($note_id, false); History::add($issue_id, Auth::getUserID(), History::getTypeID('note_converted_draft'), "Note converted to draft (from: " . @$structure->headers['from'] . ") by " . User::getFullName(Auth::getUserID())); } return $res; } }
/** * Method used to get the associated customer and customer contact from * a given set of support emails. This is especially useful to automatically * associate an issue to the appropriate customer contact that sent a * support email. * * @access public * @param array $sup_ids The list of support email IDs * @return array The customer and customer contact ID */ function getCustomerInfoFromEmails($sup_ids) { $senders = Support::getSender($sup_ids); if (count($senders) > 0) { $emails = array(); for ($i = 0; $i < count($senders); $i++) { $emails[] = Mail_API::getEmailAddress($senders[$i]); } list($customer_id, $contact_id) = $this->getCustomerIDByEmails($emails); $company = $this->getDetails($customer_id); $contact = $this->getContactDetails($contact_id); return array('customer_id' => $customer_id, 'customer_name' => $company['customer_name'], 'contact_id' => $contact_id, 'contact_name' => $contact['first_name'] . " " . $contact['last_name'], 'contacts' => $this->getContactEmailAssocList($customer_id)); } else { return array('customer_id' => '', 'customer_name' => '', 'contact_id' => '', 'contact_name' => '', 'contacts' => ''); } }
/** * Method used to add a customized warning message to the body * of outgoing emails. * * @access public * @param integer $issue_id The issue ID * @param string $to The recipient of the message * @param string $body The body of the message * @return string The body of the message with the warning message, if appropriate */ function addWarningMessage($issue_id, $to, $body) { $setup = Setup::load(); if (@$setup['email_routing']['status'] == 'enabled' && $setup['email_routing']['warning']['status'] == 'enabled') { // check if the recipient can send emails to the customer $recipient_email = Mail_API::getEmailAddress($to); $recipient_usr_id = User::getUserIDByEmail($recipient_email); // don't add the warning message if the recipient is an unknown email address if (empty($recipient_usr_id)) { return $body; } else { // don't add anything if the recipient is a known customer contact $recipient_role_id = User::getRoleByUser($recipient_usr_id, Issue::getProjectID($issue_id)); if ($recipient_role_id == User::getRoleID('Customer')) { return $body; } else { if (!Support::isAllowedToEmail($issue_id, $recipient_email)) { return Mail_API::getWarningMessage('blocked') . "\n\n" . $body; } else { return Mail_API::getWarningMessage('allowed') . "\n\n" . $body; } } } } else { return $body; } }
/** * Returns if the specified user is authorized to reply to this issue. * * @access public * @param integer $issue_id The id of the issue. * @param string $email The email address to check. * @return boolean If the specified user is allowed to reply to the issue. */ function isAuthorizedReplier($issue_id, $email) { $email = strtolower(Mail_API::getEmailAddress($email)); // first check if this is an actual user or just an email address $user_emails = User::getAssocEmailList(); if (in_array($email, array_keys($user_emails))) { // real user, get id $usr_id = User::getUserIDByEmail($email); return Authorized_Replier::isUserAuthorizedReplier($issue_id, $usr_id); } else { // not a real user $stmt = "SELECT\n COUNT(*) AS total\n FROM\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user_replier\n WHERE\n iur_iss_id=" . Misc::escapeInteger($issue_id) . " AND\n iur_email='" . Misc::escapeString($email) . "'"; $res = $GLOBALS["db_api"]->dbh->getOne($stmt); if (PEAR::isError($res)) { Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); return false; } else { if ($res > 0) { return true; } else { return false; } } } }
$res = Support::getListDetails($HTTP_GET_VARS["item"]); $tpl->assign("emails", $res); $tpl->assign("attached_emails", @implode(",", $HTTP_GET_VARS["item"])); if (Customer::hasCustomerIntegration($prj_id)) { // also need to guess the contact_id from any attached emails $info = Customer::getCustomerInfoFromEmails($prj_id, $HTTP_GET_VARS["item"]); $tpl->assign(array("customer_id" => $info['customer_id'], 'customer_name' => $info['customer_name'], "contact_id" => $info['contact_id'], 'contact_name' => $info['contact_name'], 'contacts' => $info['contacts'])); } // if we are dealing with just one message, use the subject line as the // summary for the issue, and the body as the description if (count($HTTP_GET_VARS["item"]) == 1) { $email_details = Support::getEmailDetails(Email_Account::getAccountByEmail($HTTP_GET_VARS["item"][0]), $HTTP_GET_VARS["item"][0]); $tpl->assign(array('issue_summary' => $email_details['sup_subject'], 'issue_description' => $email_details['message'])); // also auto pre-fill the customer contact text fields if (Customer::hasCustomerIntegration($prj_id)) { $sender_email = Mail_API::getEmailAddress($email_details['sup_from']); list(, $contact_id) = Customer::getCustomerIDByEmails($prj_id, array($sender_email)); if (!empty($contact_id)) { $tpl->assign("contact_details", Customer::getContactDetails($prj_id, $contact_id)); } } } } } $tpl->assign(array("cats" => Category::getAssocList($prj_id), "priorities" => Priority::getAssocList($prj_id), "users" => Project::getUserAssocList($prj_id, 'active', User::getRoleID('Customer')), "releases" => Release::getAssocList($prj_id), "custom_fields" => Custom_Field::getListByProject($prj_id, 'report_form'), "max_attachment_size" => Attachment::getMaxAttachmentSize(), "field_display_settings" => Project::getFieldDisplaySettings($prj_id), "groups" => Group::getAssocList($prj_id))); $setup = Setup::load(); $tpl->assign("allow_unassigned_issues", @$setup["allow_unassigned_issues"]); $prefs = Prefs::get($usr_id); $tpl->assign("user_prefs", $prefs); $tpl->assign("zones", Date_API::getTimezoneList()); if (User::getRole(Auth::getCurrentRole()) == "Customer") {
/** * Adds an email to the outgoing mail queue. * * @access public * @param string $recipient The recipient of this email * @param array $headers The list of headers that should be sent with this email * @param string $body The body of the message * @param integer $save_email_copy Whether to send a copy of this email to a configurable address or not (eventum_sent@) * @param integer $issue_id The ID of the issue. If false, email will not be associated with issue. * @param string $type The type of message this is. * @param integer $sender_usr_id The id of the user sending this email. * @param integer $type_id The ID of the event that triggered this notification (issue_id, sup_id, not_id, etc) * @return true, or a PEAR_Error object */ function add($recipient, $headers, $body, $save_email_copy = 0, $issue_id = false, $type = '', $sender_usr_id = false, $type_id = false) { // avoid sending emails out to users with inactive status $recipient_email = Mail_API::getEmailAddress($recipient); $usr_id = User::getUserIDByEmail($recipient_email); if (!empty($usr_id)) { $user_status = User::getStatusByEmail($recipient_email); // if user is not set to an active status, then silently ignore if (!User::isActiveStatus($user_status) && !User::isPendingStatus($user_status)) { return false; } } $to_usr_id = User::getUserIDByEmail($recipient_email); $recipient = Mail_API::fixAddressQuoting($recipient); $reminder_addresses = Reminder::_getReminderAlertAddresses(); // add specialized headers if (!empty($issue_id) && (!empty($to_usr_id) && User::getRoleByUser($to_usr_id, Issue::getProjectID($issue_id)) > User::getRoleID("Customer")) || @in_array(Mail_API::getEmailAddress($to), $reminder_addresses)) { $headers += Mail_API::getSpecializedHeaders($issue_id, $type, $headers, $sender_usr_id); } if (empty($issue_id)) { $issue_id = 'null'; } // if the Date: header is missing, add it. if (!in_array('Date', array_keys($headers))) { $headers['Date'] = MIME_Helper::encode(date('D, j M Y H:i:s O')); } if (!empty($headers['To'])) { $headers['To'] = Mail_API::fixAddressQuoting($headers['To']); } list(, $text_headers) = Mail_API::prepareHeaders($headers); $stmt = "INSERT INTO\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "mail_queue\n (\n maq_save_copy,\n maq_queued_date,\n maq_sender_ip_address,\n maq_recipient,\n maq_headers,\n maq_body,\n maq_iss_id,\n maq_subject,\n maq_type"; if ($sender_usr_id != false) { $stmt .= ",\nmaq_usr_id"; } if ($type_id != false) { $stmt .= ",\nmaq_type_id"; } $stmt .= ") VALUES (\n {$save_email_copy},\n '" . Date_API::getCurrentDateGMT() . "',\n '" . getenv("REMOTE_ADDR") . "',\n '" . Misc::escapeString($recipient) . "',\n '" . Misc::escapeString($text_headers) . "',\n '" . Misc::escapeString($body) . "',\n " . Misc::escapeInteger($issue_id) . ",\n '" . Misc::escapeString($headers["Subject"]) . "',\n '{$type}'"; if ($sender_usr_id != false) { $stmt .= ",\n" . $sender_usr_id; } if ($type_id != false) { $stmt .= ",\n" . $type_id; } $stmt .= ")"; $res = $GLOBALS["db_api"]->dbh->query($stmt); if (PEAR::isError($res)) { Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); return $res; } else { return true; } }
/** * Creates an issue with the given email information. * * @access public * @param integer $prj_id The project ID * @param integer $usr_id The user responsible for this action * @param string $sender The original sender of this email * @param string $summary The issue summary * @param string $description The issue description * @param integer $category The category ID * @param integer $priority The priority ID * @param array $assignment The list of users to assign this issue to * @param string $date The date the email was originally sent. * @param string $msg_id The message ID of the email we are creating this issue from. * @return void */ function createFromEmail($prj_id, $usr_id, $sender, $summary, $description, $category, $priority, $assignment, $date, $msg_id) { $exclude_list = array(); $sender_email = Mail_API::getEmailAddress($sender); $sender_usr_id = User::getUserIDByEmail($sender_email); if (!empty($sender_usr_id)) { $reporter = $sender_usr_id; $exclude_list[] = $sender_usr_id; } else { $reporter = APP_SYSTEM_USER_ID; } if (Customer::hasCustomerIntegration($prj_id)) { list($customer_id, $customer_contact_id) = Customer::getCustomerIDByEmails($prj_id, array($sender_email)); if (!empty($customer_id)) { $contact = Customer::getContactDetails($prj_id, $customer_contact_id); // overwrite the reporter with the customer contact $reporter = User::getUserIDByContactID($customer_contact_id); $contact_timezone = Date_API::getPreferredTimezone($reporter); } } else { $customer_id = FALSE; } $initial_status = Project::getInitialStatus($prj_id); // add new issue $stmt = "INSERT INTO\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue\n (\n iss_prj_id,\n"; if (!empty($category)) { $stmt .= "iss_prc_id,\n"; } $stmt .= "iss_pri_id,\n iss_usr_id,"; if (!empty($initial_status)) { $stmt .= "iss_sta_id,"; } if (!empty($customer_id)) { $stmt .= "\n iss_customer_id,\n iss_customer_contact_id,\n iss_contact_person_lname,\n iss_contact_person_fname,\n iss_contact_email,\n iss_contact_phone,\n iss_contact_timezone,"; } $stmt .= "\n iss_created_date,\n iss_last_public_action_date,\n iss_last_public_action_type,\n iss_summary,\n iss_description,\n iss_root_message_id\n ) VALUES (\n " . $prj_id . ",\n"; if (!empty($category)) { $stmt .= Misc::escapeInteger($category) . ",\n"; } $stmt .= Misc::escapeInteger($priority) . ",\n " . Misc::escapeInteger($reporter) . ","; if (!empty($initial_status)) { $stmt .= Misc::escapeInteger($initial_status) . ","; } if (!empty($customer_id)) { $stmt .= "\n " . Misc::escapeInteger($customer_id) . ",\n " . Misc::escapeInteger($customer_contact_id) . ",\n '" . Misc::escapeString($contact['last_name']) . "',\n '" . Misc::escapeString($contact['first_name']) . "',\n '" . Misc::escapeString($sender_email) . "',\n '" . Misc::escapeString($contact['phone']) . "',\n '" . Misc::escapeString($contact_timezone) . "',"; } $stmt .= "\n '" . Date_API::getCurrentDateGMT() . "',\n '" . Date_API::getCurrentDateGMT() . "',\n 'created',\n '" . Misc::escapeString($summary) . "',\n '" . Misc::escapeString($description) . "',\n '" . Misc::escapeString($msg_id) . "'\n )"; $res = $GLOBALS["db_api"]->dbh->query($stmt); if (PEAR::isError($res)) { Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); return -1; } else { $new_issue_id = $GLOBALS["db_api"]->get_last_insert_id(); $has_TAM = false; $has_RR = false; // log the creation of the issue History::add($new_issue_id, $usr_id, History::getTypeID('issue_opened'), 'Issue opened by ' . $sender); $emails = array(); $manager_usr_ids = array(); if (Customer::hasCustomerIntegration($prj_id) && !empty($customer_id)) { // if there are any technical account managers associated with this customer, add these users to the notification list $managers = Customer::getAccountManagers($prj_id, $customer_id); $manager_usr_ids = array_keys($managers); $manager_emails = array_values($managers); $emails = array_merge($emails, $manager_emails); } // add the reporter to the notification list $emails[] = $sender; $emails = array_unique($emails); // COMPAT: version >= 4.0.1 $actions = Notification::getDefaultActions(); foreach ($emails as $address) { Notification::subscribeEmail($reporter, $new_issue_id, $address, $actions); } // only assign the issue to an user if the associated customer has any technical account managers $users = array(); if (Customer::hasCustomerIntegration($prj_id) && count($manager_usr_ids) > 0) { foreach ($manager_usr_ids as $manager_usr_id) { $users[] = $manager_usr_id; Issue::addUserAssociation(APP_SYSTEM_USER_ID, $new_issue_id, $manager_usr_id, false); History::add($new_issue_id, $usr_id, History::getTypeID('issue_auto_assigned'), 'Issue auto-assigned to ' . User::getFullName($manager_usr_id) . ' (TAM)'); } $has_TAM = true; } // now add the user/issue association if (@count($assignment) > 0) { for ($i = 0; $i < count($assignment); $i++) { Notification::subscribeUser($reporter, $new_issue_id, $assignment[$i], $actions); Issue::addUserAssociation(APP_SYSTEM_USER_ID, $new_issue_id, $assignment[$i]); if ($assignment[$i] != $usr_id) { $users[] = $assignment[$i]; } } } else { // only use the round-robin feature if this new issue was not // already assigned to a customer account manager if (@count($manager_usr_ids) < 1) { $assignee = Round_Robin::getNextAssignee($prj_id); // assign the issue to the round robin person if (!empty($assignee)) { Issue::addUserAssociation(APP_SYSTEM_USER_ID, $new_issue_id, $assignee, false); History::add($new_issue_id, APP_SYSTEM_USER_ID, History::getTypeID('rr_issue_assigned'), 'Issue auto-assigned to ' . User::getFullName($assignee) . ' (RR)'); $users[] = $assignee; $has_RR = true; } } } if (count($users) > 0) { $has_assignee = true; } // send special 'an issue was auto-created for you' notification back to the sender Notification::notifyAutoCreatedIssue($prj_id, $new_issue_id, $sender, $date, $summary); // also notify any users that want to receive emails anytime a new issue is created Notification::notifyNewIssue($prj_id, $new_issue_id, $exclude_list); Workflow::handleNewIssue($prj_id, $new_issue_id, $has_TAM, $has_RR); return $new_issue_id; } }
/** * Method used to update the details of a given subscription. * * @access public * @param integer $sub_id The subscription ID * @return integer 1 if the update worked, -1 otherwise */ function update($sub_id) { global $HTTP_POST_VARS; $sub_id = Misc::escapeInteger($sub_id); $stmt = "SELECT\r\n sub_iss_id,\r\n sub_usr_id\r\n FROM\r\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "subscription\r\n WHERE\r\n sub_id={$sub_id}"; list($issue_id, $usr_id) = $GLOBALS["db_api"]->dbh->getRow($stmt); $email = strtolower(Mail_API::getEmailAddress($HTTP_POST_VARS["email"])); $usr_id = User::getUserIDByEmail($email); if (!empty($usr_id)) { $email = ''; } else { $usr_id = 0; $email = Misc::escapeString($HTTP_POST_VARS["email"]); } $prj_id = Issue::getProjectID($issue_id); // call workflow to modify actions or cancel adding this user. $actions = array(); $subscriber_usr_id = false; $workflow = Workflow::handleSubscription($prj_id, $issue_id, $subscriber_usr_id, $email, $actions); if ($workflow === false) { // cancel subscribing the user return -2; } // always set the type of notification to issue-level $stmt = "UPDATE\r\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "subscription\r\n SET\r\n sub_level='issue',\r\n sub_email='" . Misc::escapeString($email) . "',\r\n sub_usr_id={$usr_id}\r\n WHERE\r\n sub_id={$sub_id}"; $res = $GLOBALS["db_api"]->dbh->query($stmt); if (PEAR::isError($res)) { Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); return -1; } else { $stmt = "DELETE FROM\r\n " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "subscription_type\r\n WHERE\r\n sbt_sub_id={$sub_id}"; $GLOBALS["db_api"]->dbh->query($stmt); // now add them all again for ($i = 0; $i < count($HTTP_POST_VARS["actions"]); $i++) { Notification::addType($sub_id, $HTTP_POST_VARS["actions"][$i]); } // need to mark the issue as updated Issue::markAsUpdated($issue_id); // need to save a history entry for this History::add($issue_id, Auth::getUserID(), History::getTypeID('notification_updated'), "Notification list entry ('" . Notification::getSubscriber($sub_id) . "') updated by " . User::getFullName(Auth::getUserID())); return 1; } }
/** * Routes a draft to the correct issue. * * @param string $full_message The complete draft. */ function route_drafts($full_message) { global $HTTP_POST_VARS; // save the full message for logging purposes Draft::saveRoutedMessage($full_message); if (preg_match("/^(boundary=).*/m", $full_message)) { $pattern = "/(Content-Type: multipart\\/)(.+); ?\r?\n(boundary=)(.*)\$/im"; $replacement = '$1$2; $3$4'; $full_message = preg_replace($pattern, $replacement, $full_message); } // need some validation here if (empty($full_message)) { return array(66, "Error: The email message was empty.\n"); } // // DON'T EDIT ANYTHING BELOW THIS LINE // // remove the reply-to: header if (preg_match("/^(reply-to:).*/im", $full_message)) { $full_message = preg_replace("/^(reply-to:).*\n/im", '', $full_message, 1); } // check if the draft interface is even supposed to be enabled $setup = Setup::load(); if (@$setup['draft_routing']['status'] != 'enabled') { return array(78, "Error: The email draft interface is disabled.\n"); } $prefix = $setup['draft_routing']['address_prefix']; // escape plus signs so '*****@*****.**' becomes a valid address $prefix = str_replace('+', '\\+', $prefix); $mail_domain = quotemeta($setup['draft_routing']['address_host']); if (empty($prefix)) { return array(78, "Error: Please configure the email address prefix.\n"); } if (empty($mail_domain)) { return array(78, "Error: Please configure the email address domain.\n"); } $structure = Mime_Helper::decode($full_message, true, false); // find which issue ID this email refers to @preg_match("/{$prefix}(\\d*)@{$mail_domain}/i", $structure->headers['to'], $matches); @($issue_id = $matches[1]); // validation is always a good idea if (empty($issue_id)) { // we need to try the Cc header as well @preg_match("/{$prefix}(\\d*)@{$mail_domain}/i", $structure->headers['cc'], $matches); if (!empty($matches[1])) { $issue_id = $matches[1]; } else { return array(65, "Error: The routed draft had no associated Eventum issue ID or had an invalid recipient address.\n"); } } $prj_id = Issue::getProjectID($issue_id); // check if the sender is allowed in this issue' project and if it is an internal user $users = Project::getUserEmailAssocList($prj_id, 'active', User::getRoleID('Customer')); $sender_email = strtolower(Mail_API::getEmailAddress($structure->headers['from'])); $user_emails = array_map('strtolower', array_values($users)); if (!in_array($sender_email, $user_emails)) { return array(77, "Error: The sender of this email is not allowed in the project associated with issue #{$issue_id}.\n"); } Auth::createFakeCookie(User::getUserIDByEmail($sender_email), $prj_id); $body = Mime_Helper::getMessageBody($structure); Draft::saveEmail($issue_id, @$structure->headers['to'], @$structure->headers['cc'], @$structure->headers['subject'], $body, false, false, false); // XXX: need to handle attachments coming from drafts as well? History::add($issue_id, Auth::getUserID(), History::getTypeID('draft_routed'), "Draft routed from " . $structure->headers['from']); return true; }