function run(Model_PreParseRule $filter, CerberusParserMessage $message) { $message_headers = $message->headers; $ticket_fields = DAO_CustomField::getAll(); $params = $filter->actions[self::EXTENSION_ID]; $headers = $params['headers']; $custom_fields = $params['custom_fields']; print_r($custom_fields); foreach ($headers as $idx => $header) { if ($message_headers[strtolower($header)] != null) { $header_value = $message_headers[strtolower($header)]; // handle array headers if (is_array($header_value)) { $value = DevblocksPlatform::parseCrlfString(implode('\\r\\n', $header_value)); } else { $value = DevblocksPlatform::parseCrlfString($header_value); } // collapse multi-line headers to single line for single-line text fields if ($ticket_fields[$custom_fields[$idx]]->type == Model_CustomField::TYPE_SINGLE_LINE) { $message->custom_fields[$custom_fields[$idx]] = trim(implode(' ', $value)); } elseif ($ticket_fields[$custom_fields[$idx]]->type == Model_CustomField::TYPE_MULTI_LINE) { $message->custom_fields[$custom_fields[$idx]] = trim(implode('\\r\\n', $value)); } } } }
function handleRequest(DevblocksHttpRequest $request) { @($reload = DevblocksPlatform::importGPC($_REQUEST['reload'], 'integer', 0)); @($loglevel = DevblocksPlatform::importGPC($_REQUEST['loglevel'], 'integer', 0)); $logger = DevblocksPlatform::getConsoleLog(); $translate = DevblocksPlatform::getTranslationService(); $settings = CerberusSettings::getInstance(); $authorized_ips_str = $settings->get(CerberusSettings::AUTHORIZED_IPS); $authorized_ips = DevblocksPlatform::parseCrlfString($authorized_ips_str); $authorized_ip_defaults = DevblocksPlatform::parseCsvString(AUTHORIZED_IPS_DEFAULTS); $authorized_ips = array_merge($authorized_ips, $authorized_ip_defaults); @($is_ignoring_wait = DevblocksPlatform::importGPC($_REQUEST['ignore_wait'], 'integer', 0)); $pass = false; foreach ($authorized_ips as $ip) { if (substr($ip, 0, strlen($ip)) == substr($_SERVER['REMOTE_ADDR'], 0, strlen($ip))) { $pass = true; break; } } if (!$pass) { echo vsprintf($translate->_('cron.ip_unauthorized'), $_SERVER['REMOTE_ADDR']); return; } $stack = $request->path; array_shift($stack); // cron $job_id = array_shift($stack); @set_time_limit(0); // Unlimited (if possible) $url = DevblocksPlatform::getUrlService(); $timelimit = intval(ini_get('max_execution_time')); if ($reload) { $reload_url = sprintf("%s?reload=%d&loglevel=%d&ignore_wait=%d", $url->write('c=cron' . ($job_id ? "&a=" . $job_id : "")), intval($reload), intval($loglevel), intval($is_ignoring_wait)); echo "<HTML>" . "<HEAD>" . "<TITLE></TITLE>" . "<meta http-equiv='Refresh' content='" . intval($reload) . ";" . $reload_url . "'>" . "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>" . "</HEAD>" . "<BODY>"; // onload=\"setTimeout(\\\"window.location.replace('".$url->write('c=cron')."')\\\",30);\" } // [TODO] Determine if we're on a time limit under 60 seconds $cron_manifests = DevblocksPlatform::getExtensions('cerberusweb.cron', true, true); $jobs = array(); if (empty($job_id)) { // do everything // Determine who wants to go first by next time and longest waiting $nexttime = time() + 86400; if (is_array($cron_manifests)) { foreach ($cron_manifests as $idx => $instance) { /* @var $instance CerberusCronPageExtension */ $lastrun = $instance->getParam(CerberusCronPageExtension::PARAM_LASTRUN, 0); if ($instance->isReadyToRun($is_ignoring_wait)) { if ($timelimit) { if ($lastrun < $nexttime) { $jobs[0] = $cron_manifests[$idx]; $nexttime = $lastrun; } } else { $jobs[] =& $cron_manifests[$idx]; } } } } } else { // single job $manifest = DevblocksPlatform::getExtension($job_id, false, true); if (empty($manifest)) { exit; } $instance = $manifest->createInstance(); if ($instance) { if ($instance->isReadyToRun($is_ignoring_wait)) { $jobs[0] =& $instance; } } } if (!empty($jobs)) { foreach ($jobs as $nextjob) { $nextjob->setParam(CerberusCronPageExtension::PARAM_LOCKED, time()); $nextjob->_run(); } } elseif ($reload) { $logger->info(vsprintf($translate->_('cron.nothing_to_do'), intval($reload))); } if ($reload) { echo "</BODY>" . "</HTML>"; } exit; }
/** * Enter description here... * * @param CerberusParserMessage $message * @return integer */ public static function parseMessage(CerberusParserMessage $message, $options = array()) { /* * options: * 'no_autoreply' */ $logger = DevblocksPlatform::getConsoleLog(); $settings = DevblocksPlatform::getPluginSettingsService(); $helpdesk_senders = CerberusApplication::getHelpdeskSenders(); // Pre-parse mail filters $pre_filters = Model_PreParseRule::getMatches($message); if (is_array($pre_filters) && !empty($pre_filters)) { // Load filter action manifests for reuse $ext_action_mfts = DevblocksPlatform::getExtensions('cerberusweb.mail_filter.action', false); // Loop through all matching filters foreach ($pre_filters as $pre_filter) { // Do something with matching filter's actions foreach ($pre_filter->actions as $action_key => $action) { switch ($action_key) { case 'blackhole': return NULL; break; case 'redirect': @($to = $action['to']); CerberusMail::reflect($message, $to); return NULL; break; case 'bounce': @($msg = $action['message']); @($subject = 'Delivery failed: ' . self::fixQuotePrintableString($message->headers['subject'])); // [TODO] Follow the RFC spec on a true bounce if (null != ($fromAddressInst = CerberusParser::getAddressFromHeaders($message->headers))) { CerberusMail::quickSend($fromAddressInst->email, $subject, $msg); } return NULL; break; default: // Plugin pre-parser filter actions if (isset($ext_action_mfts[$action_key])) { if (null != @($ext_action = $ext_action_mfts[$action_key]->createInstance())) { try { /* @var $ext_action Extension_MailFilterAction */ $ext_action->run($pre_filter, $message); } catch (Exception $e) { } } } break; } } } } $headers =& $message->headers; // From if (null == ($fromAddressInst = CerberusParser::getAddressFromHeaders($headers))) { $logger->err("[Parser] 'From' address could not be created."); return NULL; } // To/Cc/Bcc $to = array(); $sTo = @$headers['to']; $bIsNew = true; if (!empty($sTo)) { // [TODO] Do we still need this RFC address parser? $to = CerberusParser::parseRfcAddress($sTo); } // Subject // Fix quote printable subject (quoted blocks can appear anywhere in subject) $sSubject = ""; if (isset($headers['subject']) && !empty($headers['subject'])) { $sSubject = $headers['subject']; if (is_array($sSubject)) { $sSubject = array_shift($sSubject); } } // The subject can still end up empty after QP decode if (empty($sSubject)) { $sSubject = "(no subject)"; } // Date $iDate = @strtotime($headers['date']); // If blank, or in the future, set to the current date if (empty($iDate) || $iDate > time()) { $iDate = time(); } // Is banned? if (1 == $fromAddressInst->is_banned) { $logger->info("[Parser] Ignoring ticket from banned address: " . $fromAddressInst->email); return NULL; } // Overloadable $enumSpamTraining = ''; // Message Id / References / In-Reply-To @($sMessageId = $headers['message-id']); $body_append_text = array(); $body_append_html = array(); // [mdf]Check attached files before creating the ticket because we may need to overwrite the message-id // also store any contents of rfc822 files so we can include them after the body foreach ($message->files as $filename => $file) { /* @var $file ParserFile */ switch ($file->mime_type) { case 'message/rfc822': $full_filename = $file->tmpname; $mail = mailparse_msg_parse_file($full_filename); $struct = mailparse_msg_get_structure($mail); $msginfo = mailparse_msg_get_part_data($mail); $inline_headers = $msginfo['headers']; if (isset($headers['from']) && (strtolower(substr($headers['from'], 0, 11)) == 'postmaster@' || strtolower(substr($headers['from'], 0, 14)) == 'mailer-daemon@')) { $headers['in-reply-to'] = $inline_headers['message-id']; } break; } } // [JAS] [TODO] References header may contain multiple message-ids to find if (null != ($ids = self::findParentMessage($headers))) { $bIsNew = false; $id = $ids['ticket_id']; $msgid = $ids['message_id']; // Is it a worker reply from an external client? If so, proxy if (null != ($worker_address = DAO_AddressToWorker::getByAddress($fromAddressInst->email))) { $logger->info("[Parser] Handling an external worker response from " . $fromAddressInst->email); if (!DAO_Ticket::isTicketRequester($worker_address->address, $id)) { // Watcher Commands [TODO] Document on wiki/etc if (0 != ($matches = preg_match_all("/\\[(.*?)\\]/i", $message->headers['subject'], $commands))) { @($command = strtolower(array_pop($commands[1]))); $logger->info("[Parser] Worker command: " . $command); switch ($command) { case 'close': DAO_Ticket::updateTicket($id, array(DAO_Ticket::IS_CLOSED => CerberusTicketStatus::CLOSED)); break; case 'take': DAO_Ticket::updateTicket($id, array(DAO_Ticket::NEXT_WORKER_ID => $worker_address->worker_id)); break; case 'comment': $comment_id = DAO_TicketComment::create(array(DAO_TicketComment::ADDRESS_ID => $fromAddressInst->id, DAO_TicketComment::CREATED => time(), DAO_TicketComment::TICKET_ID => $id, DAO_TicketComment::COMMENT => $message->body)); return $id; break; default: // Typo? break; } } $attachment_files = array(); $attachment_files['name'] = array(); $attachment_files['type'] = array(); $attachment_files['tmp_name'] = array(); $attachment_files['size'] = array(); $i = 0; foreach ($message->files as $filename => $file) { $attachment_files['name'][$i] = $filename; $attachment_files['type'][$i] = $file->mime_type; $attachment_files['tmp_name'][$i] = $file->tmpname; $attachment_files['size'][$i] = $file->file_size; $i++; } CerberusMail::sendTicketMessage(array('message_id' => $msgid, 'content' => $message->body, 'files' => $attachment_files, 'agent_id' => $worker_address->worker_id)); return $id; } else { // ... worker is a requester, treat as normal $logger->info("[Parser] The external worker was a ticket requester, so we're not treating them as a watcher."); } } else { // Reply: Not sent by a worker /* * [TODO] check that this sender is a requester on the matched ticket * Otherwise blank out the $id */ } } $group_id = 0; if (empty($id)) { // New Ticket $sMask = CerberusApplication::generateTicketMask(); $groups = DAO_Group::getAll(); // Routing new tickets if (null != ($routing_rules = Model_MailToGroupRule::getMatches($fromAddressInst, $message))) { if (is_array($routing_rules)) { foreach ($routing_rules as $rule) { // Only end up with the last 'move' action (ignore the previous) if (isset($rule->actions['move'])) { $group_id = intval($rule->actions['move']['group_id']); // We don't need to move again when running rule actions unset($rule->actions['move']); } } } } // Make sure the group exists if (!isset($groups[$group_id])) { $group_id = null; } // Last ditch effort to check for a default group to deliver to if (empty($group_id)) { if (null != ($default_team = DAO_Group::getDefaultGroup())) { $group_id = $default_team->id; } else { // Bounce return null; } } // [JAS] It's important to not set the group_id on the ticket until the messages exist // or inbox filters will just abort. $fields = array(DAO_Ticket::MASK => $sMask, DAO_Ticket::SUBJECT => $sSubject, DAO_Ticket::IS_CLOSED => 0, DAO_Ticket::FIRST_WROTE_ID => intval($fromAddressInst->id), DAO_Ticket::LAST_WROTE_ID => intval($fromAddressInst->id), DAO_Ticket::CREATED_DATE => $iDate, DAO_Ticket::UPDATED_DATE => $iDate, DAO_Ticket::LAST_ACTION_CODE => CerberusTicketActionCode::TICKET_OPENED); $id = DAO_Ticket::createTicket($fields); // Apply routing actions to our new ticket ID if (isset($routing_rules) && is_array($routing_rules)) { foreach ($routing_rules as $rule) { $rule->run($id); } } } // [JAS]: Add requesters to the ticket if (!empty($fromAddressInst->id) && !empty($id)) { // Don't add a requester if the sender is a helpdesk address if (isset($helpdesk_senders[$fromAddressInst->email])) { $logger->info("[Parser] Not adding ourselves as a requester: " . $fromAddressInst->email); } else { DAO_Ticket::createRequester($fromAddressInst->id, $id); } } // Add the other TO/CC addresses to the ticket // [TODO] This should be cleaned up and optimized if ($settings->get('cerberusweb.core', CerberusSettings::PARSER_AUTO_REQ, 0)) { @($autoreq_exclude_list = $settings->get('cerberusweb.core', CerberusSettings::PARSER_AUTO_REQ_EXCLUDE, '')); $destinations = self::getDestinations($headers); if (is_array($destinations) && !empty($destinations)) { // Filter out any excluded requesters if (!empty($autoreq_exclude_list)) { @($autoreq_exclude = DevblocksPlatform::parseCrlfString($autoreq_exclude_list)); if (is_array($autoreq_exclude) && !empty($autoreq_exclude)) { foreach ($autoreq_exclude as $excl_pattern) { $excl_regexp = DevblocksPlatform::parseStringAsRegExp($excl_pattern); // Check all destinations for this pattern foreach ($destinations as $idx => $dest) { if (@preg_match($excl_regexp, $dest)) { unset($destinations[$idx]); } } } } } foreach ($destinations as $dest) { if (null != ($destInst = CerberusApplication::hashLookupAddress($dest, true))) { // Skip if the destination is one of our senders or the matching TO if (isset($helpdesk_senders[$destInst->email])) { continue; } DAO_Ticket::createRequester($destInst->id, $id); } } } } $attachment_path = APP_STORAGE_PATH . '/attachments/'; // [TODO] This should allow external attachments (S3) $fields = array(DAO_Message::TICKET_ID => $id, DAO_Message::CREATED_DATE => $iDate, DAO_Message::ADDRESS_ID => $fromAddressInst->id); $email_id = DAO_Message::create($fields); // Content DAO_MessageContent::create($email_id, $message->body); // Headers foreach ($headers as $hk => $hv) { DAO_MessageHeader::create($email_id, $hk, $hv); } // [mdf] Loop through files to insert attachment records in the db, and move temporary files if (!empty($email_id)) { foreach ($message->files as $filename => $file) { /* @var $file ParserFile */ //[mdf] skip rfc822 messages since we extracted their content above if ($file->mime_type == 'message/rfc822') { continue; } $fields = array(DAO_Attachment::MESSAGE_ID => $email_id, DAO_Attachment::DISPLAY_NAME => $filename, DAO_Attachment::MIME_TYPE => $file->mime_type, DAO_Attachment::FILE_SIZE => intval($file->file_size)); $file_id = DAO_Attachment::create($fields); if (empty($file_id)) { @unlink($file->tmpname); // remove our temp file continue; } // Make file attachments use buckets so we have a max per directory $attachment_bucket = sprintf("%03d/", mt_rand(1, 100)); $attachment_file = $file_id; if (!file_exists($attachment_path . $attachment_bucket)) { @mkdir($attachment_path . $attachment_bucket, 0770, true); // [TODO] Needs error checking } rename($file->getTempFile(), $attachment_path . $attachment_bucket . $attachment_file); // [TODO] Split off attachments into its own DAO DAO_Attachment::update($file_id, array(DAO_Attachment::FILEPATH => $attachment_bucket . $attachment_file)); } } // Pre-load custom fields if (isset($message->custom_fields) && !empty($message->custom_fields)) { foreach ($message->custom_fields as $cf_id => $cf_val) { if (is_array($cf_val) && !empty($cf_val) || !is_array($cf_val) && 0 != strlen($cf_val)) { DAO_CustomFieldValue::setFieldValue('cerberusweb.fields.source.ticket', $id, $cf_id, $cf_val); } } } // Finalize our new ticket details (post-message creation) if ($bIsNew && !empty($id) && !empty($email_id)) { // First thread (needed for anti-spam) DAO_Ticket::updateTicket($id, array(DAO_Ticket::FIRST_MESSAGE_ID => $email_id)); // Prime the change fields (which a few things like anti-spam might change before we commit) $change_fields = array(DAO_Ticket::TEAM_ID => $group_id); $out = CerberusBayes::calculateTicketSpamProbability($id); if (!empty($group_id)) { @($spam_threshold = DAO_GroupSettings::get($group_id, DAO_GroupSettings::SETTING_SPAM_THRESHOLD, 80)); @($spam_action = DAO_GroupSettings::get($group_id, DAO_GroupSettings::SETTING_SPAM_ACTION, '')); @($spam_action_param = DAO_GroupSettings::get($group_id, DAO_GroupSettings::SETTING_SPAM_ACTION_PARAM, '')); if ($out['probability'] * 100 >= $spam_threshold) { $enumSpamTraining = CerberusTicketSpamTraining::SPAM; switch ($spam_action) { default: case 0: // do nothing break; case 1: // delete $change_fields[DAO_Ticket::IS_CLOSED] = 1; $change_fields[DAO_Ticket::IS_DELETED] = 1; break; case 2: // move $buckets = DAO_Bucket::getAll(); // Verify bucket exists if (!empty($spam_action_param) && isset($buckets[$spam_action_param])) { $change_fields[DAO_Ticket::TEAM_ID] = $group_id; $change_fields[DAO_Ticket::CATEGORY_ID] = $spam_action_param; } break; } } } // end spam training // Save properties if (!empty($change_fields)) { DAO_Ticket::updateTicket($id, $change_fields); } } // Reply notifications (new messages are handled by 'move' listener) if (!$bIsNew) { // Inbound Reply Event $eventMgr = DevblocksPlatform::getEventService(); $eventMgr->trigger(new Model_DevblocksEvent('ticket.reply.inbound', array('ticket_id' => $id))); } // New ticket processing if ($bIsNew) { // Auto reply @($autoreply_enabled = DAO_GroupSettings::get($group_id, DAO_GroupSettings::SETTING_AUTO_REPLY_ENABLED, 0)); @($autoreply = DAO_GroupSettings::get($group_id, DAO_GroupSettings::SETTING_AUTO_REPLY, '')); /* * Send the group's autoreply if one exists, as long as this ticket isn't spam */ if (!isset($options['no_autoreply']) && $autoreply_enabled && !empty($autoreply) && $enumSpamTraining != CerberusTicketSpamTraining::SPAM) { CerberusMail::sendTicketMessage(array('ticket_id' => $id, 'message_id' => $email_id, 'content' => str_replace(array('#ticket_id#', '#mask#', '#subject#', '#timestamp#', '#sender#', '#sender_first#', '#orig_body#'), array($id, $sMask, $sSubject, date('r'), $fromAddressInst->email, $fromAddressInst->first_name, ltrim($message->body)), $autoreply), 'is_autoreply' => true, 'dont_keep_copy' => true)); } } // end bIsNew unset($message); // Re-open and update our date on new replies if (!$bIsNew) { DAO_Ticket::updateTicket($id, array(DAO_Ticket::UPDATED_DATE => time(), DAO_Ticket::IS_WAITING => 0, DAO_Ticket::IS_CLOSED => 0, DAO_Ticket::IS_DELETED => 0, DAO_Ticket::LAST_WROTE_ID => $fromAddressInst->id, DAO_Ticket::LAST_ACTION_CODE => CerberusTicketActionCode::TICKET_CUSTOMER_REPLY)); // [TODO] The TICKET_CUSTOMER_REPLY should be sure of this message address not being a worker } @imap_errors(); // Prevent errors from spilling out into STDOUT return $id; }
function handleRequest(DevblocksHttpRequest $request) { @set_time_limit(0); // no timelimit (when possible) $translate = DevblocksPlatform::getTranslationService(); $stack = $request->path; array_shift($stack); // update $cache = DevblocksPlatform::getCacheService(); /* @var $cache _DevblocksCacheManager */ switch (array_shift($stack)) { case 'locked': if (!DevblocksPlatform::versionConsistencyCheck()) { $url = DevblocksPlatform::getUrlService(); echo "<h1>Feg - Fax Email Gateway 1.x</h1>"; echo "The application is currently waiting for an administrator to finish upgrading. " . "Please wait a few minutes and then " . sprintf("<a href='%s'>try again</a>.<br><br>", $url->write('c=update&a=locked')); echo sprintf("If you're an admin you may <a href='%s'>finish the upgrade</a>.", $url->write('c=update')); } else { DevblocksPlatform::redirect(new DevblocksHttpResponse(array('login'))); } break; default: $path = APP_TEMP_PATH . DIRECTORY_SEPARATOR; $file = $path . 'feg_update_lock'; $settings = DevblocksPlatform::getPluginSettingsService(); $authorized_ips_str = $settings->get('feg.core', FegSettings::AUTHORIZED_IPS); $authorized_ips = DevblocksPlatform::parseCrlfString($authorized_ips_str); $authorized_ip_defaults = DevblocksPlatform::parseCsvString(AUTHORIZED_IPS_DEFAULTS); $authorized_ips = array_merge($authorized_ips, $authorized_ip_defaults); // Is this IP authorized? $pass = false; foreach ($authorized_ips as $ip) { if (substr($ip, 0, strlen($ip)) == substr($_SERVER['REMOTE_ADDR'], 0, strlen($ip))) { $pass = true; break; } } if (!$pass) { echo vsprintf($translate->_('update.ip_unauthorized'), $_SERVER['REMOTE_ADDR']); return; } // Check requirements $errors = FegApplication::checkRequirements(); if (!empty($errors)) { echo $translate->_('update.correct_errors'); echo "<ul style='color:red;'>"; foreach ($errors as $error) { echo "<li>" . $error . "</li>"; } echo "</ul>"; exit; } try { // If authorized, lock and attempt update if (!file_exists($file) || @filectime($file) + 600 < time()) { // 10 min lock // Log everybody out since we're touching the database $session = DevblocksPlatform::getSessionService(); $session->clearAll(); // Lock file touch($file); // Recursive patch FegApplication::update(); // Clean up @unlink($file); $cache = DevblocksPlatform::getCacheService(); $cache->save(APP_BUILD, "devblocks_app_build"); // Clear all caches $cache->clean(); DevblocksPlatform::getClassLoaderService()->destroy(); // Clear compiled templates $tpl = DevblocksPlatform::getTemplateService(); $tpl->utility->clearCompiledTemplate(); $tpl->cache->clearAll(); // Reload plugin translations DAO_Translation::reloadPluginStrings(); // Redirect DevblocksPlatform::redirect(new DevblocksHttpResponse(array('login'))); } else { echo $translate->_('update.locked_another'); } } catch (Exception $e) { unlink($file); die($e->getMessage()); } } exit; }
private static function _createObjectsFromResultSet($rs) { $db = DevblocksPlatform::getDatabaseService(); $objects = array(); while ($row = mysql_fetch_assoc($rs)) { $object = new Model_CustomField(); $object->id = intval($row['id']); $object->name = $row['name']; $object->type = $row['type']; $object->source_extension = $row['source_extension']; $object->pos = intval($row['pos']); $object->options = DevblocksPlatform::parseCrlfString($row['options']); $objects[$object->id] = $object; } mysql_free_result($rs); return $objects; }
function saveRequestersPanelAction() { @($ticket_id = DevblocksPlatform::importGPC($_POST['ticket_id'], 'integer')); @($msg_id = DevblocksPlatform::importGPC($_POST['msg_id'], 'integer')); // Dels @($req_deletes = DevblocksPlatform::importGPC($_POST['req_deletes'], 'array', array())); if (!empty($req_deletes)) { foreach ($req_deletes as $del_id) { DAO_Ticket::deleteRequester($ticket_id, $del_id); } } // Adds @($req_adds = DevblocksPlatform::importGPC($_POST['req_adds'], 'string', '')); $req_list = DevblocksPlatform::parseCrlfString($req_adds); $req_addys = array(); if (is_array($req_list) && !empty($req_list)) { foreach ($req_list as $req) { if (empty($req)) { continue; } $rfc_addys = imap_rfc822_parse_adrlist($req, 'localhost'); foreach ($rfc_addys as $rfc_addy) { $addy = $rfc_addy->mailbox . '@' . $rfc_addy->host; if (null != ($req_addy = CerberusApplication::hashLookupAddress($addy, true))) { DAO_Ticket::createRequester($req_addy->id, $ticket_id); } } } } $requesters = DAO_Ticket::getRequestersByTicket($ticket_id); $list = array(); foreach ($requesters as $requester) { $list[] = $requester->email; } echo implode(', ', $list); exit; }
function saveTabBucketsAction() { @($team_id = DevblocksPlatform::importGPC($_REQUEST['team_id'], 'integer')); @($active_worker = CerberusApplication::getActiveWorker()); if (!$active_worker->isTeamManager($team_id) && !$active_worker->is_superuser) { return; } // Inbox assignable @($inbox_assignable = DevblocksPlatform::importGPC($_REQUEST['inbox_assignable'], 'integer', 0)); DAO_GroupSettings::set($team_id, DAO_GroupSettings::SETTING_INBOX_IS_ASSIGNABLE, intval($inbox_assignable)); //========== BUCKETS @($ids = DevblocksPlatform::importGPC($_REQUEST['ids'], 'array')); @($add_str = DevblocksPlatform::importGPC($_REQUEST['add'], 'string')); @($pos = DevblocksPlatform::importGPC($_REQUEST['pos'], 'array')); @($names = DevblocksPlatform::importGPC($_REQUEST['names'], 'array')); @($assignables = DevblocksPlatform::importGPC($_REQUEST['is_assignable'], 'array')); @($deletes = DevblocksPlatform::importGPC($_REQUEST['deletes'], 'array')); // Updates if (!empty($ids)) { $cats = DAO_Bucket::getList($ids); foreach ($ids as $idx => $id) { @($cat = $cats[$id]); if (is_object($cat)) { $is_assignable = false === array_search($id, $assignables) ? 0 : 1; $fields = array(DAO_Bucket::NAME => $names[$idx], DAO_Bucket::POS => intval($pos[$idx]), DAO_Bucket::IS_ASSIGNABLE => intval($is_assignable)); DAO_Bucket::update($id, $fields); } } } // Adds: Sort and insert team categories $categories = DevblocksPlatform::parseCrlfString($add_str); if (is_array($categories)) { foreach ($categories as $category) { $cat_id = DAO_Bucket::create($category, $team_id); } } if (!empty($deletes)) { DAO_Bucket::delete(array_values($deletes)); } DevblocksPlatform::redirect(new DevblocksHttpResponse(array('groups', $team_id, 'buckets'))); }
function handleRequest(DevblocksHttpRequest $request) { @set_time_limit(0); // no timelimit (when possible) $translate = DevblocksPlatform::getTranslationService(); $stack = $request->path; array_shift($stack); // update $cache = DevblocksPlatform::getCacheService(); /* @var $cache _DevblocksCacheManager */ $settings = DevblocksPlatform::getPluginSettingsService(); switch (array_shift($stack)) { case 'locked': if (!DevblocksPlatform::versionConsistencyCheck()) { $url = DevblocksPlatform::getUrlService(); echo "<h1>Cerberus Helpdesk 5.x</h1>"; echo "The helpdesk is currently waiting for an administrator to finish upgrading. " . "Please wait a few minutes and then " . sprintf("<a href='%s'>try again</a>.<br><br>", $url->write('c=update&a=locked')); echo sprintf("If you're an admin you may <a href='%s'>finish the upgrade</a>.", $url->write('c=update')); } else { DevblocksPlatform::redirect(new DevblocksHttpResponse(array('login'))); } break; default: $path = APP_TEMP_PATH . DIRECTORY_SEPARATOR; $file = $path . 'c4update_lock'; $authorized_ips_str = $settings->get('cerberusweb.core', CerberusSettings::AUTHORIZED_IPS); $authorized_ips = DevblocksPlatform::parseCrlfString($authorized_ips_str); $authorized_ip_defaults = DevblocksPlatform::parseCsvString(AUTHORIZED_IPS_DEFAULTS); $authorized_ips = array_merge($authorized_ips, $authorized_ip_defaults); // Is this IP authorized? $pass = false; foreach ($authorized_ips as $ip) { if (substr($ip, 0, strlen($ip)) == substr($_SERVER['REMOTE_ADDR'], 0, strlen($ip))) { $pass = true; break; } } if (!$pass) { echo vsprintf($translate->_('update.ip_unauthorized'), $_SERVER['REMOTE_ADDR']); return; } // Check requirements $errors = CerberusApplication::checkRequirements(); if (!empty($errors)) { echo $translate->_('update.correct_errors'); echo "<ul style='color:red;'>"; foreach ($errors as $error) { echo "<li>" . $error . "</li>"; } echo "</ul>"; exit; } // If authorized, lock and attempt update if (!file_exists($file) || @filectime($file) + 600 < time()) { // 10 min lock touch($file); //echo "Running plugin patches...<br>"; if (DevblocksPlatform::runPluginPatches('core.patches')) { @unlink($file); // [JAS]: Clear all caches $cache->clean(); DevblocksPlatform::getClassLoaderService()->destroy(); // Clear compiled templates $tpl = DevblocksPlatform::getTemplateService(); $tpl->clear_compiled_tpl(); // Reload plugin translations DAO_Translation::reloadPluginStrings(); DevblocksPlatform::redirect(new DevblocksHttpResponse(array('login'))); } else { @unlink($file); echo "Failure!"; // [TODO] Needs elaboration } break; } else { echo $translate->_('update.locked_another'); } } exit; }
function import() { $sources = DAO_ForumsSource::getWhere(); $settings = CerberusSettings::getInstance(); // Track posters that are also workers $poster_workers = array(); if (null != ($poster_workers_str = $settings->get(ChForumsPlugin::SETTING_POSTER_WORKERS, null))) { $poster_workers = DevblocksPlatform::parseCrlfString($poster_workers_str); } foreach ($sources as $source) { /* @var $source Model_ForumsSource */ // [TODO] Convert to REST client (move into Devblocks) $source_url = sprintf("%s?lastpostid=%d&limit=100", $source->url, $source->last_postid); $xml_in = file_get_contents($source_url); $xml = new SimpleXMLElement($xml_in); $last_postid = 0; foreach ($xml->thread as $thread) { @($thread_id = (string) $thread->id); @($thread_title = (string) $thread->title); @($thread_last_updated = (string) $thread->last_updated); @($thread_last_postid = (string) $thread->last_postid); @($thread_last_poster = (string) $thread->last_poster); @($thread_link = (string) $thread->link); if (null == ($th = DAO_ForumsThread::getBySourceThreadId($source->id, $thread_id))) { $fields = array(DAO_ForumsThread::FORUM_ID => $source->id, DAO_ForumsThread::THREAD_ID => $thread_id, DAO_ForumsThread::TITLE => $thread_title, DAO_ForumsThread::LAST_UPDATED => intval($thread_last_updated), DAO_ForumsThread::LAST_POSTER => $thread_last_poster, DAO_ForumsThread::LINK => $thread_link); DAO_ForumsThread::create($fields); } else { // If the last post was a worker, leave the thread at the current closed state $closed = false === array_search(strtolower($thread_last_poster), $poster_workers) ? 0 : $th->is_closed; $fields = array(DAO_ForumsThread::LAST_UPDATED => intval($thread_last_updated), DAO_ForumsThread::LAST_POSTER => $thread_last_poster, DAO_ForumsThread::LINK => $thread_link, DAO_ForumsThread::IS_CLOSED => $closed); DAO_ForumsThread::update($th->id, $fields); } $last_postid = $thread_last_postid; } // foreach($xml->thread) // Save our progress to the database if (!empty($last_postid)) { DAO_ForumsSource::update($source->id, array(DAO_ForumsSource::LAST_POSTID => $last_postid)); } } // foreach($sources) }
private static function _createObjectsFromResultSet(ADORecordSet $rs) { $db = DevblocksPlatform::getDatabaseService(); $objects = array(); if ($rs instanceof ADORecordSet) { while (!$rs->EOF) { $object = new Model_CustomField(); $object->id = intval($rs->fields['id']); $object->name = $rs->fields['name']; $object->type = $rs->fields['type']; $object->source_extension = $rs->fields['source_extension']; $object->group_id = intval($rs->fields['group_id']); $object->pos = intval($rs->fields['pos']); $object->options = DevblocksPlatform::parseCrlfString($rs->fields['options']); $objects[$object->id] = $object; $rs->MoveNext(); } } return $objects; }
function doBatchUpdateAction() { @($ticket_id_str = DevblocksPlatform::importGPC($_REQUEST['ticket_ids'], 'string')); @($shortcut_name = DevblocksPlatform::importGPC($_REQUEST['shortcut_name'], 'string', '')); @($filter = DevblocksPlatform::importGPC($_REQUEST['filter'], 'string', '')); @($senders = DevblocksPlatform::importGPC($_REQUEST['senders'], 'string', '')); @($subjects = DevblocksPlatform::importGPC($_REQUEST['subjects'], 'string', '')); @($view_id = DevblocksPlatform::importGPC($_REQUEST['view_id'], 'string')); $view = C4_AbstractViewLoader::getView($view_id); $subjects = DevblocksPlatform::parseCrlfString($subjects); $senders = DevblocksPlatform::parseCrlfString($senders); $do = array(); // [TODO] This logic is repeated in several places -- try to condense (like custom field form handlers) // Move to Group/Bucket @($move_code = DevblocksPlatform::importGPC($_REQUEST['do_move'], 'string', null)); if (0 != strlen($move_code)) { list($g_id, $b_id) = CerberusApplication::translateTeamCategoryCode($move_code); $do['move'] = array('group_id' => intval($g_id), 'bucket_id' => intval($b_id)); } // Assign to worker @($worker_id = DevblocksPlatform::importGPC($_REQUEST['do_assign'], 'string', null)); if (0 != strlen($worker_id)) { $do['assign'] = array('worker_id' => intval($worker_id)); } // Spam training @($is_spam = DevblocksPlatform::importGPC($_REQUEST['do_spam'], 'string', null)); if (0 != strlen($is_spam)) { $do['spam'] = array('is_spam' => !$is_spam ? 0 : 1); } // Set status @($status = DevblocksPlatform::importGPC($_REQUEST['do_status'], 'string', null)); if (0 != strlen($status)) { $do['status'] = array('is_waiting' => 3 == $status ? 1 : 0, 'is_closed' => 0 == $status || 3 == $status ? 0 : 1, 'is_deleted' => 2 == $status ? 1 : 0); } $data = array(); $ticket_ids = array(); if ($filter == 'sender') { $data = $senders; } elseif ($filter == 'subject') { $data = $subjects; } elseif ($filter == 'checks') { $filter = ''; // bulk update just looks for $ticket_ids == !null $ticket_ids = DevblocksPlatform::parseCsvString($ticket_id_str); } // Restrict to current worker groups $active_worker = CerberusApplication::getActiveWorker(); $memberships = $active_worker->getMemberships(); $view->params['tmp'] = new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_TEAM_ID, 'in', array_keys($memberships)); // Do: Custom fields $do = DAO_CustomFieldValue::handleBulkPost($do); $view->doBulkUpdate($filter, '', $data, $do, $ticket_ids); // Clear our temporary group restriction before re-rendering unset($view->params['tmp']); $view->render(); return; }
function handleRequest(DevblocksHttpRequest $request) { @set_time_limit(0); // no timelimit (when possible) $stack = $request->path; array_shift($stack); // update // $cache = DevblocksPlatform::getCacheService(); /* @var $cache _DevblocksCacheManager */ $settings = DevblocksPlatform::getPluginSettingsService(); $authorized_ips_str = $settings->get('cerberusweb.core', CerberusSettings::AUTHORIZED_IPS); $authorized_ips = DevblocksPlatform::parseCrlfString($authorized_ips_str); $authorized_ip_defaults = DevblocksPlatform::parseCsvString(AUTHORIZED_IPS_DEFAULTS); $authorized_ips = array_merge($authorized_ips, $authorized_ip_defaults); // Is this IP authorized? $pass = false; foreach ($authorized_ips as $ip) { if (substr($ip, 0, strlen($ip)) == substr($_SERVER['REMOTE_ADDR'], 0, strlen($ip))) { $pass = true; break; } } if (!$pass) { echo 'Your IP address (' . $_SERVER['REMOTE_ADDR'] . ') is not authorized to debug this helpdesk. Your administrator needs to authorize your IP in Helpdesk Setup or in the framework.config.php file under AUTHORIZED_IPS_DEFAULTS.'; return; } switch (array_shift($stack)) { case 'phpinfo': phpinfo(); break; case 'check': echo sprintf("<html>\n\t\t\t\t\t<head>\n\t\t\t\t\t\t<title></title>\n\t\t\t\t\t\t<style>\n\t\t\t\t\t\t\tBODY {font-family: Arial, Helvetica, sans-serif; font-size: 12px;}\n\t\t\t\t\t\t\tFORM {margin:0px; } \n\t\t\t\t\t\t\tH1 { margin:0px; }\n\t\t\t\t\t\t\t.fail {color:red;font-weight:bold;}\n\t\t\t\t\t\t\t.pass {color:green;font-weight:bold;}\n\t\t\t\t\t\t</style>\n\t\t\t\t\t</head>\n\t\t\t\t\t<body>\n\t\t\t\t\t\t<h1>Cerberus Helpdesk - Requirements Checker:</h1>\n\t\t\t\t\t"); $errors = CerberusApplication::checkRequirements(); if (!empty($errors)) { echo "<ul class='fail'>"; foreach ($errors as $error) { echo sprintf("<li>%s</li>", $error); } echo "</ul>"; } else { echo '<span class="pass">Your server is compatible with Cerberus Helpdesk 5.x!</span>'; } echo sprintf("\n\t\t\t\t\t</body>\n\t\t\t\t\t</html>\n\t\t\t\t"); break; case 'report': @($db = DevblocksPlatform::getDatabaseService()); @($settings = DevblocksPlatform::getPluginSettingsService()); @($tables = $db->MetaTables('TABLE', false)); $report_output = sprintf("[Cerberus Helpdesk] App Build: %s\n" . "[Cerberus Helpdesk] Devblocks Build: %s\n" . "[Cerberus Helpdesk] URL-Rewrite: %s\n" . "\n" . "[Privs] storage/attachments: %s\n" . "[Privs] storage/mail/new: %s\n" . "[Privs] storage/mail/fail: %s\n" . "[Privs] storage/tmp: %s\n" . "[Privs] storage/tmp/templates_c: %s\n" . "[Privs] storage/tmp/cache: %s\n" . "\n" . "[PHP] Version: %s\n" . "[PHP] OS: %s\n" . "[PHP] SAPI: %s\n" . "\n" . "[php.ini] safe_mode: %s\n" . "[php.ini] max_execution_time: %s\n" . "[php.ini] memory_limit: %s\n" . "[php.ini] file_uploads: %s\n" . "[php.ini] upload_max_filesize: %s\n" . "[php.ini] post_max_size: %s\n" . "\n" . "[PHP:Extension] MySQL: %s\n" . "[PHP:Extension] PostgreSQL: %s\n" . "[PHP:Extension] MailParse: %s\n" . "[PHP:Extension] IMAP: %s\n" . "[PHP:Extension] Session: %s\n" . "[PHP:Extension] PCRE: %s\n" . "[PHP:Extension] GD: %s\n" . "[PHP:Extension] mbstring: %s\n" . "[PHP:Extension] XML: %s\n" . "[PHP:Extension] SimpleXML: %s\n" . "[PHP:Extension] DOM: %s\n" . "[PHP:Extension] SPL: %s\n" . "\n" . '%s', APP_BUILD, PLATFORM_BUILD, file_exists(APP_PATH . '/.htaccess') ? 'YES' : 'NO', substr(sprintf('%o', fileperms(APP_STORAGE_PATH . '/attachments')), -4), substr(sprintf('%o', fileperms(APP_STORAGE_PATH . '/mail/new')), -4), substr(sprintf('%o', fileperms(APP_STORAGE_PATH . '/mail/fail')), -4), substr(sprintf('%o', fileperms(APP_TEMP_PATH)), -4), substr(sprintf('%o', fileperms(APP_TEMP_PATH . '/templates_c')), -4), substr(sprintf('%o', fileperms(APP_TEMP_PATH . '/cache')), -4), PHP_VERSION, PHP_OS . ' (' . php_uname() . ')', php_sapi_name(), ini_get('safe_mode'), ini_get('max_execution_time'), ini_get('memory_limit'), ini_get('file_uploads'), ini_get('upload_max_filesize'), ini_get('post_max_size'), extension_loaded("mysql") ? 'YES' : 'NO', extension_loaded("pgsql") ? 'YES' : 'NO', extension_loaded("mailparse") ? 'YES' : 'NO', extension_loaded("imap") ? 'YES' : 'NO', extension_loaded("session") ? 'YES' : 'NO', extension_loaded("pcre") ? 'YES' : 'NO', extension_loaded("gd") ? 'YES' : 'NO', extension_loaded("mbstring") ? 'YES' : 'NO', extension_loaded("xml") ? 'YES' : 'NO', extension_loaded("simplexml") ? 'YES' : 'NO', extension_loaded("dom") ? 'YES' : 'NO', extension_loaded("spl") ? 'YES' : 'NO', ''); if (!empty($settings)) { $report_output .= sprintf("[Setting] HELPDESK_TITLE: %s\n" . "[Setting] DEFAULT_REPLY_FROM: %s\n" . "[Setting] DEFAULT_REPLY_PERSONAL: %s\n" . "[Setting] SMTP_HOST: %s\n" . "[Setting] SMTP_PORT: %s\n" . "[Setting] SMTP_ENCRYPTION_TYPE: %s\n" . "\n" . '%s', $settings->get('cerberusweb.core', CerberusSettings::HELPDESK_TITLE, ''), str_replace(array('@', '.'), array(' at ', ' dot '), $settings->get('cerberusweb.core', CerberusSettings::DEFAULT_REPLY_FROM, '')), $settings->get('cerberusweb.core', CerberusSettings::DEFAULT_REPLY_PERSONAL, ''), $settings->get('cerberusweb.core', CerberusSettings::SMTP_HOST, ''), $settings->get('cerberusweb.core', CerberusSettings::SMTP_PORT, ''), $settings->get('cerberusweb.core', CerberusSettings::SMTP_ENCRYPTION_TYPE, ''), ''); } if (is_array($tables) && !empty($tables)) { $report_output .= sprintf("[Stats] # Workers: %s\n" . "[Stats] # Groups: %s\n" . "[Stats] # Tickets: %s\n" . "[Stats] # Messages: %s\n" . "\n" . "[Database] Tables:\n * %s\n" . "\n" . '%s', intval($db->getOne('SELECT count(id) FROM worker')), intval($db->getOne('SELECT count(id) FROM team')), intval($db->getOne('SELECT count(id) FROM ticket')), intval($db->getOne('SELECT count(id) FROM message')), implode("\n * ", array_values($tables)), ''); } echo sprintf("<html>\n\t\t\t\t\t<head>\n\t\t\t\t\t\t<title></title>\n\t\t\t\t\t\t<style>\n\t\t\t\t\t\t\tBODY {font-family: Arial, Helvetica, sans-serif; font-size: 12px;}\n\t\t\t\t\t\t\tFORM {margin:0px; } \n\t\t\t\t\t\t\tH1 { margin:0px; }\n\t\t\t\t\t\t\t.fail {color:red;font-weight:bold;}\n\t\t\t\t\t\t\t.pass {color:green;font-weight:bold;}\n\t\t\t\t\t\t</style>\n\t\t\t\t\t</head>\n\t\t\t\t\t<body>\n\t\t\t\t\t\t<form>\n\t\t\t\t\t\t\t<h1>Cerberus Helpdesk - Debug Report:</h1>\n\t\t\t\t\t\t\t<textarea rows='25' cols='100'>%s</textarea>\n\t\t\t\t\t\t</form>\t\n\t\t\t\t\t</body>\n\t\t\t\t\t</html>\n\t\t\t\t\t", $report_output); break; default: $url_service = DevblocksPlatform::getUrlService(); echo sprintf("<html>\n\t\t\t\t\t<head>\n\t\t\t\t\t\t<title></title>\n\t\t\t\t\t\t<style>\n\t\t\t\t\t\t\tBODY {font-family: Arial, Helvetica, sans-serif; font-size: 12px;}\n\t\t\t\t\t\t\tFORM {margin:0px; } \n\t\t\t\t\t\t\tH1 { margin:0px; }\n\t\t\t\t\t\t</style>\n\t\t\t\t\t</head>\n\t\t\t\t\t<body>\n\t\t\t\t\t\t<form>\n\t\t\t\t\t\t\t<h1>Cerberus Helpdesk - Debug Menu:</h1>\n\t\t\t\t\t\t\t<ul>\n\t\t\t\t\t\t\t\t<li><a href='%s'>Requirements Checker</a></li>\n\t\t\t\t\t\t\t\t<li><a href='%s'>Debug Report (for technical support)</a></li>\n\t\t\t\t\t\t\t\t<li><a href='%s'>phpinfo()</a></li>\n\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t</form>\t\n\t\t\t\t\t</body>\n\t\t\t\t\t</html>\n\t\t\t\t\t", $url_service->write('c=debug&a=check'), $url_service->write('c=debug&a=report'), $url_service->write('c=debug&a=phpinfo')); break; } exit; }
public function savePropertiesAction() { @($ticket_id = DevblocksPlatform::importGPC($_POST['ticket_id'], 'integer', 0)); @($remove = DevblocksPlatform::importGPC($_POST['remove'], 'array', array())); @($next_worker_id = DevblocksPlatform::importGPC($_POST['next_worker_id'], 'integer', 0)); @($ticket_reopen = DevblocksPlatform::importGPC($_POST['ticket_reopen'], 'string', '')); @($unlock_date = DevblocksPlatform::importGPC($_POST['unlock_date'], 'string', '')); @($subject = DevblocksPlatform::importGPC($_POST['subject'], 'string', '')); @($closed = DevblocksPlatform::importGPC($_POST['closed'], 'closed', 0)); @($ticket = DAO_Ticket::getTicket($ticket_id)); if (empty($ticket_id) || empty($ticket)) { return; } $fields = array(); // Properties if (empty($next_worker_id)) { $unlock_date = ""; } // Status if (isset($closed)) { switch ($closed) { case 0: // open if (array(0, 0, 0) != array($ticket->is_waiting, $ticket->is_closed, $ticket->is_deleted)) { $fields[DAO_Ticket::IS_WAITING] = 0; $fields[DAO_Ticket::IS_CLOSED] = 0; $fields[DAO_Ticket::IS_DELETED] = 0; $fields[DAO_Ticket::DUE_DATE] = 0; } break; case 1: // closed if (array(0, 1, 0) != array($ticket->is_waiting, $ticket->is_closed, $ticket->is_deleted)) { $fields[DAO_Ticket::IS_WAITING] = 0; $fields[DAO_Ticket::IS_CLOSED] = 1; $fields[DAO_Ticket::IS_DELETED] = 0; } if (isset($ticket_reopen)) { @($time = intval(strtotime($ticket_reopen))); $fields[DAO_Ticket::DUE_DATE] = $time; } break; case 2: // waiting if (array(1, 0, 0) != array($ticket->is_waiting, $ticket->is_closed, $ticket->is_deleted)) { $fields[DAO_Ticket::IS_WAITING] = 1; $fields[DAO_Ticket::IS_CLOSED] = 0; $fields[DAO_Ticket::IS_DELETED] = 0; } if (isset($ticket_reopen)) { @($time = intval(strtotime($ticket_reopen))); $fields[DAO_Ticket::DUE_DATE] = $time; } break; case 3: // deleted if (array(0, 1, 1) != array($ticket->is_waiting, $ticket->is_closed, $ticket->is_deleted)) { $fields[DAO_Ticket::IS_WAITING] = 0; $fields[DAO_Ticket::IS_CLOSED] = 1; $fields[DAO_Ticket::IS_DELETED] = 1; } $fields[DAO_Ticket::DUE_DATE] = 0; break; } } if (isset($next_worker_id)) { $fields[DAO_Ticket::NEXT_WORKER_ID] = $next_worker_id; } if (isset($unlock_date)) { @($time = intval(strtotime($unlock_date))); $fields[DAO_Ticket::UNLOCK_DATE] = $time; } if (!empty($subject)) { $fields[DAO_Ticket::SUBJECT] = $subject; } if (!empty($fields)) { DAO_Ticket::updateTicket($ticket_id, $fields); } // Custom field saves @($field_ids = DevblocksPlatform::importGPC($_POST['field_ids'], 'array', array())); DAO_CustomFieldValue::handleFormPost(ChCustomFieldSource_Ticket::ID, $ticket_id, $field_ids); // Requesters @($req_list = DevblocksPlatform::importGPC($_POST['add'], 'string', '')); if (!empty($req_list)) { $req_list = DevblocksPlatform::parseCrlfString($req_list); $req_list = array_unique($req_list); // [TODO] This is redundant with the Requester Peek on Reply if (is_array($req_list) && !empty($req_list)) { foreach ($req_list as $req) { if (empty($req)) { continue; } $rfc_addys = imap_rfc822_parse_adrlist($req, 'localhost'); foreach ($rfc_addys as $rfc_addy) { $addy = $rfc_addy->mailbox . '@' . $rfc_addy->host; DAO_Ticket::createRequester($addy, $ticket_id); } } } } if (!empty($remove) && is_array($remove)) { foreach ($remove as $address_id) { $addy = DAO_Address::get($address_id); DAO_Ticket::deleteRequester($ticket_id, $address_id); } } DevblocksPlatform::redirect(new DevblocksHttpResponse(array('iphone', 'tickets', 'display', $ticket->id, 'properties'))); }