function showTabPreParserAction() { $tpl = DevblocksPlatform::getTemplateService(); $tpl->assign('path', $this->_TPL_PATH); $filters = DAO_PreParseRule::getAll(true); $tpl->assign('filters', $filters); $groups = DAO_Group::getAll(); $tpl->assign('groups', $groups); // Custom Field Sources $source_manifests = DevblocksPlatform::getExtensions('cerberusweb.fields.source', false); $tpl->assign('source_manifests', $source_manifests); // Custom Fields $custom_fields = DAO_CustomField::getAll(); $tpl->assign('custom_fields', $custom_fields); // Criteria extensions $filter_criteria_exts = DevblocksPlatform::getExtensions('cerberusweb.mail_filter.criteria', false); $tpl->assign('filter_criteria_exts', $filter_criteria_exts); // Action extensions $filter_action_exts = DevblocksPlatform::getExtensions('cerberusweb.mail_filter.action', false); $tpl->assign('filter_action_exts', $filter_action_exts); $tpl->display('file:' . $this->_TPL_PATH . 'configuration/tabs/mail/mail_preparse.tpl'); }
/** * Returns a Model_PreParserRule on a match, or NULL * * @param boolean $is_new * @param string $from * @param string $to * @param CerberusParserMessage $message * @return Model_PreParserRule[] */ static function getMatches(CerberusParserMessage $message) { $filters = DAO_PreParseRule::getAll(); $headers = $message->headers; // New or reply? $is_new = isset($message->headers['in-reply-to']) || isset($message->headers['references']) ? false : true; // From address $fromInst = CerberusParser::getAddressFromHeaders($headers); // Stackable $matches = array(); // Custom fields $custom_fields = DAO_CustomField::getAll(); // Criteria extensions $filter_criteria_exts = DevblocksPlatform::getExtensions('cerberusweb.mail_filter.criteria', false); // Lazy load when needed on criteria basis $address_field_values = null; $org_field_values = null; // check filters if (is_array($filters)) { foreach ($filters as $filter) { $passed = 0; // check criteria foreach ($filter->criteria as $rule_key => $rule) { @($value = $rule['value']); switch ($rule_key) { case 'dayofweek': $current_day = strftime('%w'); // $current_day = 1; // Forced to English abbrevs as indexes $days = array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'); // Is the current day enabled? if (isset($rule[$days[$current_day]])) { $passed++; } break; case 'timeofday': $current_hour = strftime('%H'); $current_min = strftime('%M'); // $current_hour = 17; // $current_min = 5; if (null != ($from_time = @$rule['from'])) { list($from_hour, $from_min) = explode(':', $from_time); } if (null != ($to_time = @$rule['to'])) { if (list($to_hour, $to_min) = explode(':', $to_time)) { } } // Do we need to wrap around to the next day's hours? if ($from_hour > $to_hour) { // yes $to_hour += 24; // add 24 hrs to the destination (1am = 25th hour) } // Are we in the right 24 hourly range? if ((int) $current_hour >= $from_hour && (int) $current_hour <= $to_hour) { // If we're in the first hour, are we minutes early? if ($current_hour == $from_hour && (int) $current_min < $from_min) { break; } // If we're in the last hour, are we minutes late? if ($current_hour == $to_hour && (int) $current_min > $to_min) { break; } $passed++; } break; case 'type': if ($is_new && 0 == strcasecmp($value, 'new') || !$is_new && 0 == strcasecmp($value, 'reply')) { $passed++; } break; case 'from': $regexp_from = DevblocksPlatform::strToRegExp($value); if (preg_match($regexp_from, $fromInst->email)) { $passed++; } break; case 'tocc': $tocc = array(); $destinations = DevblocksPlatform::parseCsvString($value); // Build a list of To/Cc addresses on this message @($to_list = imap_rfc822_parse_adrlist($headers['to'], 'localhost')); @($cc_list = imap_rfc822_parse_adrlist($headers['cc'], 'localhost')); if (is_array($to_list)) { foreach ($to_list as $addy) { $tocc[] = $addy->mailbox . '@' . $addy->host; } } if (is_array($cc_list)) { foreach ($cc_list as $addy) { $tocc[] = $addy->mailbox . '@' . $addy->host; } } $dest_flag = false; // bail out when true if (is_array($destinations) && is_array($tocc)) { foreach ($destinations as $dest) { if ($dest_flag) { break; } $regexp_dest = DevblocksPlatform::strToRegExp($dest); foreach ($tocc as $addy) { if (@preg_match($regexp_dest, $addy)) { $passed++; $dest_flag = false; break; } } } } break; case 'header1': case 'header2': case 'header3': case 'header4': case 'header5': $header = strtolower($rule['header']); if (empty($value)) { // we're checking for null/blanks if (!isset($headers[$header]) || empty($headers[$header])) { $passed++; } } elseif (isset($headers[$header]) && !empty($headers[$header])) { $regexp_header = DevblocksPlatform::strToRegExp($value); // handle arrays like Received: and (broken)Content-Type headers (farking spammers) if (is_array($headers[$header])) { foreach ($headers[$header] as $array_header) { if (preg_match($regexp_header, str_replace(array("\r", "\n"), ' ', $array_header))) { $passed++; break; } } } else { // Flatten CRLF if (preg_match($regexp_header, str_replace(array("\r", "\n"), ' ', $headers[$header]))) { $passed++; } } } break; case 'body': // Line-by-line body scanning (sed-like) $lines = preg_split("/[\r\n]/", $message->body); if (is_array($lines)) { foreach ($lines as $line) { if (@preg_match($value, $line)) { $passed++; break; } } } break; case 'body_encoding': $regexp_bodyenc = DevblocksPlatform::strToRegExp($value); if (preg_match($regexp_bodyenc, $message->body_encoding)) { $passed++; } break; case 'attachment': $regexp_file = DevblocksPlatform::strToRegExp($value); // check the files in the raw message foreach ($message->files as $file_name => $file) { /* @var $file ParserFile */ if (preg_match($regexp_file, $file_name)) { $passed++; break; } } break; default: // ignore invalids // Custom Fields if (0 == strcasecmp('cf_', substr($rule_key, 0, 3))) { $field_id = substr($rule_key, 3); // Make sure it exists if (null == @($field = $custom_fields[$field_id])) { continue; } // Lazy values loader $field_values = array(); switch ($field->source_extension) { case ChCustomFieldSource_Address::ID: if (null == $address_field_values) { $address_field_values = array_shift(DAO_CustomFieldValue::getValuesBySourceIds(ChCustomFieldSource_Address::ID, $fromInst->id)); } $field_values =& $address_field_values; break; case ChCustomFieldSource_Org::ID: if (null == $org_field_values) { $org_field_values = array_shift(DAO_CustomFieldValue::getValuesBySourceIds(ChCustomFieldSource_Org::ID, $fromInst->contact_org_id)); } $field_values =& $org_field_values; break; } // Type sensitive value comparisons // [TODO] Operators // [TODO] Highly redundant switch ($field->type) { case 'S': // string // string case 'T': // clob // clob case 'U': // URL $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : ''; $oper = isset($rule['oper']) ? $rule['oper'] : "="; if ($oper == "=" && @preg_match(DevblocksPlatform::strToRegExp($value, true), $field_val)) { $passed++; } elseif ($oper == "!=" && @(!preg_match(DevblocksPlatform::strToRegExp($value, true), $field_val))) { $passed++; } break; case 'N': // number if (!isset($field_values[$field_id])) { break; } $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : 0; $oper = isset($rule['oper']) ? $rule['oper'] : "="; if ($oper == "=" && intval($field_val) == intval($value)) { $passed++; } elseif ($oper == "!=" && intval($field_val) != intval($value)) { $passed++; } elseif ($oper == ">" && intval($field_val) > intval($value)) { $passed++; } elseif ($oper == "<" && intval($field_val) < intval($value)) { $passed++; } break; case 'E': // date $field_val = isset($field_values[$field_id]) ? intval($field_values[$field_id]) : 0; $from = isset($rule['from']) ? $rule['from'] : "0"; $to = isset($rule['to']) ? $rule['to'] : "now"; if (intval(@strtotime($from)) <= $field_val && intval(@strtotime($to)) >= $field_val) { $passed++; } break; case 'C': // checkbox $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : 0; if (intval($value) == intval($field_val)) { $passed++; } break; case 'D': // dropdown // dropdown case 'M': // multi-picklist // multi-picklist case 'X': // multi-checkbox // multi-checkbox case 'W': // worker $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : array(); if (!is_array($value)) { $value = array($value); } if (is_array($field_val)) { // if multiple things set foreach ($field_val as $v) { // loop through possible if (isset($value[$v])) { // is any possible set? $passed++; break; } } } else { // single if (isset($value[$field_val])) { // is our set field in possibles? $passed++; break; } } break; } } elseif (isset($filter_criteria_exts[$rule_key])) { // criteria extensions try { $crit_ext = $filter_criteria_exts[$rule_key]->createInstance(); if ($crit_ext->matches($filter, $message)) { $passed++; break; } } catch (Exception $e) { // Oops! //print_r($e); } } break; } } // If our rule matched every criteria, stop and return the filter if ($passed == count($filter->criteria)) { DAO_PreParseRule::increment($filter->id); // ++ the times we've matched $matches[] = $filter; // Check our actions and see if we should bail out early if (isset($filter->actions) && !empty($filter->actions)) { foreach ($filter->actions as $action_key => $action) { switch ($action_key) { case 'nothing': case 'blackhole': case 'redirect': case 'bounce': return $matches; break; } } } } } } return $matches; }
function showTabPreParserAction() { $tpl = DevblocksPlatform::getTemplateService(); $tpl->cache_lifetime = "0"; $tpl->assign('path', $this->_TPL_PATH); $filters = DAO_PreParseRule::getAll(true); $tpl->assign('filters', $filters); $groups = DAO_Group::getAll(); $tpl->assign('groups', $groups); $tpl->display('file:' . $this->_TPL_PATH . 'configuration/tabs/mail/mail_preparse.tpl'); }
/** * Returns a Model_PreParserRule on a match, or NULL * * @param boolean $is_new * @param string $from * @param string $to * @param CerberusParserMessage $message * @return Model_PreParserRule */ private static function _checkPreParseRules($is_new, $from, $group_id, CerberusParserMessage $message) { $filters = DAO_PreParseRule::getAll(); $headers = $message->headers; // check filters if (is_array($filters)) { foreach ($filters as $filter) { $passed = 0; // check criteria foreach ($filter->criteria as $rule_key => $rule) { @($value = $rule['value']); switch ($rule_key) { case 'type': if ($is_new && 0 == strcasecmp($value, 'new') || !$is_new && 0 == strcasecmp($value, 'reply')) { $passed++; } break; case 'from': $regexp_from = DevblocksPlatform::strToRegExp($value); if (preg_match($regexp_from, $from)) { $passed++; } break; case 'to': if (intval($group_id) == intval($value)) { $passed++; } break; case 'header1': case 'header2': case 'header3': case 'header4': case 'header5': $header = strtolower($rule['header']); if (empty($value)) { // we're checking for null/blanks if (!isset($headers[$header]) || empty($headers[$header])) { $passed++; } } elseif (isset($headers[$header]) && !empty($headers[$header])) { $regexp_header = DevblocksPlatform::strToRegExp($value); // handle arrays like Received: and (broken)Content-Type headers (farking spammers) if (is_array($headers[$header])) { foreach ($headers[$header] as $array_header) { if (preg_match($regexp_header, str_replace(array("\r", "\n"), ' ', $array_header))) { $passed++; break; } } } else { // Flatten CRLF if (preg_match($regexp_header, str_replace(array("\r", "\n"), ' ', $headers[$header]))) { $passed++; } } } break; case 'body': $regexp_body = DevblocksPlatform::strToRegExp($value); // Flatten CRLF if (preg_match($regexp_body, str_replace(array("\r", "\n"), ' ', $message->body))) { $passed++; } break; case 'body_encoding': $regexp_bodyenc = DevblocksPlatform::strToRegExp($value); if (preg_match($regexp_bodyenc, $message->body_encoding)) { $passed++; } break; case 'attachment': $regexp_file = DevblocksPlatform::strToRegExp($value); // check the files in the raw message foreach ($message->files as $file_name => $file) { /* @var $file ParserFile */ if (preg_match($regexp_file, $file_name)) { $passed++; break; } } break; default: // ignore invalids continue; break; } } // If our rule matched every criteria, stop and return the filter if ($passed == count($filter->criteria)) { DAO_PreParseRule::increment($filter->id); // ++ the times we've matched return $filter; } } } return NULL; }
/** * Returns a Model_PreParserRule on a match, or NULL * * @param boolean $is_new * @param string $from * @param string $to * @param CerberusParserMessage $message * @return Model_PreParserRule */ static function getMatches($is_new, $from, CerberusParserMessage $message) { $filters = DAO_PreParseRule::getAll(); $headers = $message->headers; // [TODO] Handle stackable // check filters if (is_array($filters)) { foreach ($filters as $filter) { $passed = 0; // check criteria foreach ($filter->criteria as $rule_key => $rule) { @($value = $rule['value']); switch ($rule_key) { case 'dayofweek': $current_day = strftime('%w'); // $current_day = 1; // Forced to English abbrevs as indexes $days = array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'); // Is the current day enabled? if (isset($crit[$days[$current_day]])) { $passed++; } break; case 'timeofday': $current_hour = strftime('%H'); $current_min = strftime('%M'); // $current_hour = 17; // $current_min = 5; if (null != ($from_time = @$crit['from'])) { list($from_hour, $from_min) = split(':', $from_time); } if (null != ($to_time = @$crit['to'])) { if (list($to_hour, $to_min) = split(':', $to_time)) { } } // Do we need to wrap around to the next day's hours? if ($from_hour > $to_hour) { // yes $to_hour += 24; // add 24 hrs to the destination (1am = 25th hour) } // Are we in the right 24 hourly range? if ((int) $current_hour >= $from_hour && (int) $current_hour <= $to_hour) { // If we're in the first hour, are we minutes early? if ($current_hour == $from_hour && (int) $current_min < $from_min) { break; } // If we're in the last hour, are we minutes late? if ($current_hour == $to_hour && (int) $current_min > $to_min) { break; } $passed++; } break; case 'type': if ($is_new && 0 == strcasecmp($value, 'new') || !$is_new && 0 == strcasecmp($value, 'reply')) { $passed++; } break; case 'from': $regexp_from = DevblocksPlatform::strToRegExp($value); if (preg_match($regexp_from, $from)) { $passed++; } break; case 'tocc': $destinations = DevblocksPlatform::parseCsvString($value); // Build a list of To/Cc addresses on this message @($to_list = imap_rfc822_parse_adrlist($headers['to'], 'localhost')); @($cc_list = imap_rfc822_parse_adrlist($headers['cc'], 'localhost')); if (is_array($to_list)) { foreach ($to_list as $addy) { $tocc[] = $addy->mailbox . '@' . $addy->host; } } if (is_array($cc_list)) { foreach ($cc_list as $addy) { $tocc[] = $addy->mailbox . '@' . $addy->host; } } $dest_flag = false; // bail out when true if (is_array($destinations) && is_array($tocc)) { foreach ($destinations as $dest) { if ($dest_flag) { break; } $regexp_dest = DevblocksPlatform::strToRegExp($dest); foreach ($tocc as $addy) { if (@preg_match($regexp_dest, $addy)) { $passed++; $dest_flag = false; break; } } } } break; case 'header1': case 'header2': case 'header3': case 'header4': case 'header5': $header = strtolower($rule['header']); if (empty($value)) { // we're checking for null/blanks if (!isset($headers[$header]) || empty($headers[$header])) { $passed++; } } elseif (isset($headers[$header]) && !empty($headers[$header])) { $regexp_header = DevblocksPlatform::strToRegExp($value); // handle arrays like Received: and (broken)Content-Type headers (farking spammers) if (is_array($headers[$header])) { foreach ($headers[$header] as $array_header) { if (preg_match($regexp_header, str_replace(array("\r", "\n"), ' ', $array_header))) { $passed++; break; } } } else { // Flatten CRLF if (preg_match($regexp_header, str_replace(array("\r", "\n"), ' ', $headers[$header]))) { $passed++; } } } break; case 'body': // Line-by-line body scanning (sed-like) $lines = split("[\r\n]", $message->body); if (is_array($lines)) { foreach ($lines as $line) { if (@preg_match($value, $line)) { $passed++; break; } } } break; case 'body_encoding': $regexp_bodyenc = DevblocksPlatform::strToRegExp($value); if (preg_match($regexp_bodyenc, $message->body_encoding)) { $passed++; } break; case 'attachment': $regexp_file = DevblocksPlatform::strToRegExp($value); // check the files in the raw message foreach ($message->files as $file_name => $file) { /* @var $file ParserFile */ if (preg_match($regexp_file, $file_name)) { $passed++; break; } } break; default: // ignore invalids continue; break; } } // If our rule matched every criteria, stop and return the filter if ($passed == count($filter->criteria)) { DAO_PreParseRule::increment($filter->id); // ++ the times we've matched return $filter; } } } return NULL; }