404 lines
12 KiB
PHP

<?php
/*********************************************************************************
** The contents of this file are subject to the vtiger CRM Public License Version 1.0
* ("License"); You may not use this file except in compliance with the License
* The Original Code is: vtiger CRM Open Source
* The Initial Developer of the Original Code is vtiger.
* Portions created by vtiger are Copyright (C) vtiger.
* All Rights Reserved.
*
********************************************************************************/
require_once('modules/Settings/MailScanner/core/MailScannerAction.php');
/**
* Scanner Rule
*/
class Vtiger_MailScannerRule {
// id of this instance
var $ruleid = false;
// scanner to which this rule is linked
var $scannerid = false;
// from address criteria
var $fromaddress= false;
// to address criteria
var $toaddress = false;
// subject criteria operator
var $subjectop = false;
// subject criteria
var $subject = false;
// body criteria operator
var $bodyop = false;
// body criteria
var $body = false;
// order of this rule
var $sequence = false;
// is this action valid
var $isvalid = false;
// match criteria ALL or ANY
var $matchusing = false;
// associated actions for this rule
var $actions = false;
// TODO we are restricting one action for one rule right now
var $useaction= false;
/** DEBUG functionality **/
var $debug = false;
function log($message) {
global $log;
if($log && $this->debug) { $log->debug($message); }
else if($this->debug) echo "$message\n";
}
/**
* Constructor
*/
function __construct($forruleid) {
$this->initialize($forruleid);
}
/**
* String representation of this instance
*/
function __toString() {
$tostring = '';
$tostring .= "FROM $this->fromaddress, TO $this->toaddress";
$tostring .= ",SUBJECT $this->subjectop $this->subject, BODY $this->bodyop $this->body, MATCH USING, $this->matchusing";
return $tostring;
}
/**
* Initialize this instance
*/
function initialize($forruleid) {
global $adb;
$result = $adb->pquery("SELECT * FROM vtiger_mailscanner_rules WHERE ruleid=? ORDER BY sequence", Array($forruleid));
if($adb->num_rows($result)) {
$this->ruleid = $adb->query_result($result, 0, 'ruleid');
$this->scannerid = $adb->query_result($result, 0, 'scannerid');
$this->fromaddress= $adb->query_result($result, 0, 'fromaddress');
$this->toaddress = $adb->query_result($result, 0, 'toaddress');
$this->subjectop = $adb->query_result($result, 0, 'subjectop');
$this->subject = $adb->query_result($result, 0, 'subject');
$this->bodyop = $adb->query_result($result, 0, 'bodyop');
$this->body = $adb->query_result($result, 0, 'body');
$this->sequence = $adb->query_result($result, 0, 'sequence');
$this->matchusing = $adb->query_result($result, 0, 'matchusing');
$this->isvalid = true;
$this->initializeActions();
// At present we support only one action for a rule
if(!empty($this->actions)) $this->useaction = $this->actions[0];
}
}
/**
* Initialize the actions
*/
function initializeActions() {
global $adb;
if($this->ruleid) {
$this->actions = Array();
$actionres = $adb->pquery("SELECT actionid FROM vtiger_mailscanner_ruleactions WHERE ruleid=?",Array($this->ruleid));
$actioncount = $adb->num_rows($actionres);
if($actioncount) {
for($index = 0; $index < $actioncount; ++$index) {
$actionid = $adb->query_result($actionres, $index, 'actionid');
$ruleaction = new Vtiger_MailScannerAction($actionid);
$ruleaction->debug = $this->debug;
$this->actions[] = $ruleaction;
}
}
}
}
/**
* Is body rule defined?
*/
function hasBodyRule() {
return (!empty($this->bodyop));
}
/**
* Check if the rule criteria is matching
*/
function isMatching($matchfound1, $matchfound2=null) {
if($matchfound2 === null) return $matchfound1;
if($this->matchusing== 'AND') return ($matchfound1 && $matchfound2);
if($this->matchusing== 'OR') return ($matchfound1 || $matchfound2);
return false;
}
/**
* Apply all the criteria.
* @param $mailrecord
* @param $includingBody
* @returns false if not match is found or else all matching result found
*/
function applyAll($mailrecord, $includingBody=true) {
$matchresults = Array();
$matchfound = null;
if($this->hasACondition()) {
$subrules = Array('FROM', 'TO', 'SUBJECT', 'BODY');
foreach($subrules as $subrule) {
// Body rule could be defered later to improve performance
// in that case skip it.
if($subrule == 'BODY' && !$includingBody) continue;
$checkmatch = $this->apply($subrule, $mailrecord);
$matchfound = $this->isMatching($checkmatch, $matchfound);
// Collect matching result array
if($matchfound && is_array($checkmatch)) $matchresults[] = $checkmatch;
if($matchfound && $this->matchusing == 'OR') break;
}
} else {
$matchfound = false;
if($this->matchusing == 'OR') {
$matchfound = true;
$matchresults[] = $this->__CreateMatchResult('BLANK','','','');
}
}
return ($matchfound)? $matchresults : false;
}
/**
* Check if at least one condition is set for this rule.
*/
function hasACondition() {
$hasFromAddress = $this->fromaddress? true: false;
$hasToAddress = $this->toaddress? true : false;
$hasSubjectOp = $this->subjectop? true : false;
$hasBodyOp = $this->bodyop? true : false;
return ($hasFromAddress || $hasToAddress || $hasSubjectOp || $hasBodyOp);
}
/**
* Apply required condition on the mail record.
*/
function apply($subrule, $mailrecord) {
$matchfound = false;
if($this->isvalid) {
switch(strtoupper($subrule)) {
case 'FROM':
if($this->fromaddress) {
$matchfound = $this->find($subrule, 'Contains', $mailrecord->_from[0], $this->fromaddress);
} else {
$matchfound = $this->__CreateDefaultMatchResult($subrule);
}
break;
case 'TO':
if($this->toaddress) {
foreach($mailrecord->_to as $toemail) {
$matchfound = $this->find($subrule, 'Contains', $toemail, $this->toaddress);
if($matchfound) break;
}
} else {
$matchfound = $this->__CreateDefaultMatchResult($subrule);
}
break;
case 'SUBJECT':
if($this->subjectop) {
$matchfound = $this->find($subrule, $this->subjectop, $mailrecord->_subject, $this->subject);
} else {
$matchfound = $this->__CreateDefaultMatchResult($subrule);
}
break;
case 'BODY':
if($this->bodyop) {
$matchfound = $this->find($subrule, $this->bodyop, $mailrecord->_body, $this->body);
} else {
$matchfound = $this->__CreateDefaultMatchResult($subrule);
}
break;
}
}
return $matchfound;
}
/**
* Find if the rule matches based on condition and parameters
*/
function find($subrule, $condition, $input, $searchfor) {
if(!$input) return false;
$matchfound = false;
$matches = false;
switch($condition) {
case 'Contains':
$matchfound = stripos($input, $searchfor);
$matchfound = ($matchfound !== FALSE);
$matches = $searchfor;
break;
case 'Not Contains':
$matchfound = stripos($input, $searchfor);
$matchfound = ($matchfound === FALSE);
$matches = $searchfor;
break;
case 'Equals':
$matchfound = strcasecmp($input, $searchfor);
$matchfound = ($matchfound === 0);
$matches = $searchfor;
break;
case 'Not Equals':
$matchfound = strcasecmp($input, $searchfor);
$matchfound = ($matchfound !== 0);
$matches = $searchfor;
break;
case 'Begins With':
$matchfound = stripos($input, $searchfor);
$matchfound = ($matchfound === 0);
$matches = $searchfor;
break;
case 'Ends With':
$matchfound = strripos($input, $searchfor);
$matchfound = ($matchfound === strlen($input)-strlen($searchfor));
$matches = $searchfor;
break;
case 'Regex':
$regmatches = Array();
$matchfound = false;
$searchfor = str_replace('/', '\/', $searchfor);
if(preg_match("/$searchfor/i", $input, $regmatches)) {
// Pick the last matching group
$matches = $regmatches[count($regmatches)-1];
$matchfound = true;
}
break;
}
if($matchfound) $matchfound = $this->__CreateMatchResult($subrule, $condition, $searchfor, $matches);
return $matchfound;
}
/**
* Create matching result for the subrule.
*/
function __CreateMatchResult($subrule, $condition, $searchfor, $matches) {
return Array( 'subrule' => $subrule, 'condition' => $condition, 'searchfor' => $searchfor, 'matches' => $matches);
}
/**
* Create default success matching result
*/
function __CreateDefaultMatchResult($subrule) {
if($this->matchusing == 'OR') return false;
if($this->matchusing == 'AND') return $this->__CreateMatchResult($subrule, 'Contains', '', '');
}
/**
* Detect if the rule match result has Regex condition
* @param $matchresult result of apply obtained earlier
* @returns matchinfo if Regex match is found, false otherwise
*/
function hasRegexMatch($matchresult) {
foreach($matchresult as $matchinfo) {
$match_condition = $matchinfo['condition'];
$match_string = $matchinfo['matches'];
if($match_condition == 'Regex' && $match_string)
return $matchinfo;
}
return false;
}
/**
* Swap (reset) sequence of two rules.
*/
static function resetSequence($ruleid1, $ruleid2) {
global $adb;
$ruleresult = $adb->pquery("SELECT ruleid, sequence FROM vtiger_mailscanner_rules WHERE ruleid = ? or ruleid = ?",
Array($ruleid1, $ruleid2));
$rule_partinfo = Array();
if($adb->num_rows($ruleresult) != 2) {
return false;
} else {
$rule_partinfo[$adb->query_result($ruleresult, 0, 'ruleid')] = $adb->query_result($ruleresult, 0, 'sequence');
$rule_partinfo[$adb->query_result($ruleresult, 1, 'ruleid')] = $adb->query_result($ruleresult, 1, 'sequence');
$adb->pquery("UPDATE vtiger_mailscanner_rules SET sequence = ? WHERE ruleid = ?", Array($rule_partinfo[$ruleid2], $ruleid1));
$adb->pquery("UPDATE vtiger_mailscanner_rules SET sequence = ? WHERE ruleid = ?", Array($rule_partinfo[$ruleid1], $ruleid2));
}
}
/**
* Update rule information in database.
*/
function update() {
global $adb;
if($this->ruleid) {
$adb->pquery("UPDATE vtiger_mailscanner_rules SET scannerid=?,fromaddress=?,toaddress=?,subjectop=?,subject=?,bodyop=?,body=?,matchusing=?
WHERE ruleid=?", Array($this->scannerid, $this->fromaddress, $this->toaddress, $this->subjectop, $this->subject,
$this->bodyop, $this->body,$this->matchusing, $this->ruleid));
} else {
$this->sequence = $this->__nextsequence();
$adb->pquery("INSERT INTO vtiger_mailscanner_rules(scannerid,fromaddress,toaddress,subjectop,subject,bodyop,body,matchusing,sequence)
VALUES(?,?,?,?,?,?,?,?,?)",
Array($this->scannerid,$this->fromaddress,$this->toaddress,$this->subjectop,$this->subject,
$this->bodyop,$this->body,$this->matchusing,$this->sequence));
$this->ruleid = $adb->database->Insert_ID();
}
}
/**
* Get next sequence to use
*/
function __nextsequence() {
global $adb;
$seqres = $adb->pquery("SELECT max(sequence) AS max_sequence FROM vtiger_mailscanner_rules", Array());
$maxsequence = 0;
if($adb->num_rows($seqres)) {
$maxsequence = $adb->query_result($seqres, 0, 'max_sequence');
}
++$maxsequence;
return $maxsequence;
}
/**
* Delete the rule and associated information.
*/
function delete() {
global $adb;
// Delete dependencies
if(!empty($this->actions)) {
foreach($this->actions as $action) {
$action->delete();
}
}
if($this->ruleid) {
$adb->pquery("DELETE FROM vtiger_mailscanner_ruleactions WHERE ruleid = ?", Array($this->ruleid));
$adb->pquery("DELETE FROM vtiger_mailscanner_rules WHERE ruleid=?", Array($this->ruleid));
}
}
/**
* Update action linked to the rule.
*/
function updateAction($actionid, $actiontext) {
$action = $this->useaction;
if($actionid != '' && $actiontext == '') {
if($action) $action->delete();
} else {
if($actionid == '') {
$action = new Vtiger_MailScannerAction($actionid);
}
$action->scannerid = $this->scannerid;
$action->update($this->ruleid, $actiontext);
}
}
/**
* Take action on mail record
*/
function takeAction($mailscanner, $mailrecord, $matchresult) {
if(empty($this->actions)) return false;
$action = $this->useaction; // Action is limited to One right now
return $action->apply($mailscanner, $mailrecord, $this, $matchresult);
}
}
?>