Your IP : 3.12.196.93
<?
use Bitrix\Mail\Helper\MailContact;
IncludeModuleLangFile(__FILE__);
global $BX_MAIL_ERRORs, $B_MAIL_MAX_ALLOWED;
$BX_MAIL_ERRORs = Array();
$B_MAIL_MAX_ALLOWED = false;
class CMail
{
const ERR_DEFAULT = 1;
const ERR_DB = 2;
const ERR_API_DEFAULT = 101;
const ERR_API_DENIED = 102;
const ERR_API_DOMAINLIST_EMPTY = 103;
const ERR_API_NAME_OCCUPIED = 104;
const ERR_API_USER_NOTFOUND = 105;
const ERR_API_EMPTY_DOMAIN = 106;
const ERR_API_EMPTY_NAME = 107;
const ERR_API_EMPTY_PASSWORD = 108;
const ERR_API_SHORT_PASSWORD = 109;
const ERR_API_BAD_NAME = 110;
const ERR_API_BAD_PASSWORD = 111;
const ERR_API_PASSWORD_LIKELOGIN = 112;
const ERR_API_LONG_NAME = 113;
const ERR_API_LONG_PASSWORD = 114;
const ERR_API_OP_DENIED = 115;
const ERR_API_OLD_TOKEN = 116;
const ERR_API_DOMAIN_OCCUPIED = 201;
const ERR_API_BAD_DOMAIN = 202;
const ERR_API_PROHIBITED_DOMAIN = 203;
const ERR_ENTRY_NOT_FOUND = 301;
const F_DOMAIN_LOGO = 1;
const F_DOMAIN_REG = 2;
public static function getErrorMessage($code)
{
switch ($code)
{
case self::ERR_DB:
return GetMessage('MAIL_ERR_DB');
case self::ERR_API_DEFAULT:
return GetMessage('MAIL_ERR_API_DEFAULT');
case self::ERR_API_DENIED:
return GetMessage('MAIL_ERR_API_DENIED');
case self::ERR_API_NAME_OCCUPIED:
return GetMessage('MAIL_ERR_API_NAME_OCCUPIED');
case self::ERR_API_USER_NOTFOUND:
return GetMessage('MAIL_ERR_API_USER_NOTFOUND');
case self::ERR_API_EMPTY_DOMAIN:
return GetMessage('MAIL_ERR_API_EMPTY_DOMAIN');
case self::ERR_API_EMPTY_NAME:
return GetMessage('MAIL_ERR_API_EMPTY_NAME');
case self::ERR_API_EMPTY_PASSWORD:
return GetMessage('MAIL_ERR_API_EMPTY_PASSWORD');
case self::ERR_API_SHORT_PASSWORD:
return GetMessage('MAIL_ERR_API_SHORT_PASSWORD');
case self::ERR_API_BAD_NAME:
return GetMessage('MAIL_ERR_API_BAD_NAME');
case self::ERR_API_BAD_PASSWORD:
return GetMessage('MAIL_ERR_API_BAD_PASSWORD');
case self::ERR_API_PASSWORD_LIKELOGIN:
return GetMessage('MAIL_ERR_API_PASSWORD_LIKELOGIN');
case self::ERR_API_LONG_NAME:
return GetMessage('MAIL_ERR_API_LONG_NAME');
case self::ERR_API_LONG_PASSWORD:
return GetMessage('MAIL_ERR_API_LONG_PASSWORD');
case self::ERR_API_OP_DENIED:
return GetMessage('MAIL_ERR_API_OP_DENIED');
case self::ERR_API_OLD_TOKEN:
return getMessage('MAIL_ERR_API_OLD_TOKEN');
case self::ERR_API_DOMAIN_OCCUPIED:
return GetMessage('MAIL_ERR_API_DOMAIN_OCCUPIED');
case self::ERR_API_BAD_DOMAIN:
return GetMessage('MAIL_ERR_API_BAD_DOMAIN');
case self::ERR_API_PROHIBITED_DOMAIN:
return GetMessage('MAIL_ERR_API_PROHIBITED_DOMAIN');
case self::ERR_ENTRY_NOT_FOUND:
return GetMessage('MAIL_ERR_ENTRY_NOT_FOUND');
default:
return GetMessage('MAIL_ERR_DEFAULT');
}
}
public static function onUserUpdate($arFields)
{
if ($arFields['RESULT'] && isset($arFields['ACTIVE']) && $arFields['ACTIVE'] == 'N')
{
$selectResult = CMailbox::getList(array(), array('USER_ID' => intval($arFields['ID']), 'ACTIVE' => 'Y'));
while ($mailbox = $selectResult->fetch())
CMailbox::update($mailbox['ID'], array('ACTIVE' => 'N'));
}
}
public static function onUserDelete($id)
{
$selectResult = CMailbox::getList(array(), array('USER_ID' => intval($id)));
while ($mailbox = $selectResult->fetch())
CMailbox::delete($mailbox['ID']);
}
public static function option($name, $value = null)
{
static $options;
if (!is_scalar($name))
throw new \Bitrix\Main\ArgumentTypeException('name');
if (is_null($options))
$options = array();
if (is_null($value))
{
return array_key_exists($name, $options) ? $options[$name] : null;
}
else
{
$options[$name] = $value;
return $value;
}
}
}
class CMailError
{
public static function ResetErrors()
{
global $BX_MAIL_ERRORs;
$BX_MAIL_ERRORs = Array();
}
public static function SetError($ID, $TITLE="", $DESC="")
{
global $BX_MAIL_ERRORs;
$BX_MAIL_ERRORs[] = array("ID"=>$ID, "TITLE"=>$TITLE, "DESCRIPTION"=>$DESC);
return false;
}
public static function GetLastError($type=false)
{
global $BX_MAIL_ERRORs;
if($type===false)
return $BX_MAIL_ERRORs[count($BX_MAIL_ERRORs)-1];
return $BX_MAIL_ERRORs[count($BX_MAIL_ERRORs)-1][$type];
}
public static function GetErrors()
{
global $BX_MAIL_ERRORs;
return $BX_MAIL_ERRORs;
}
public static function GetErrorsText($delim="<br>")
{
global $BX_MAIL_ERRORs;
$str = "";
foreach($BX_MAIL_ERRORs as $err)
{
if ($str!="")
$str .= $delim;
$str.=$err["TITLE"];
}
return $str;
}
public static function ErrCount()
{
global $BX_MAIL_ERRORs;
if(!is_array($BX_MAIL_ERRORs))
return 0;
return count($BX_MAIL_ERRORs);
}
}
class _CMailBoxDBRes extends CDBResult
{
function _CMailBoxDBRes($res)
{
parent::CDBResult($res);
}
function Fetch()
{
if($res = parent::Fetch())
{
$res["PASSWORD"] = CMailUtil::Decrypt($res["PASSWORD"]);
$res['OPTIONS'] = unserialize($res['OPTIONS']);
}
return $res;
}
}
///////////////////////////////////////////////////////////////////////////////////
// class CMailBox
///////////////////////////////////////////////////////////////////////////////////
class CAllMailBox
{
var $pop3_conn = false;
var $mess_count = 0;
var $mess_size = 0;
var $resp = true;
var $last_result = true;
var $response = "";
var $response_body = "";
public $mailbox_id = 0;
public $new_mess_count = 0;
public $deleted_mess_count = 0;
public static function GetList($arOrder=Array(), $arFilter=Array())
{
global $DB;
$strSql =
"SELECT MB.*, C.CHARSET as LANG_CHARSET, ".
" ".$DB->DateToCharFunction("MB.TIMESTAMP_X")." as TIMESTAMP_X ".
"FROM b_mail_mailbox MB, b_lang L, b_culture C ".
"WHERE MB.LID=L.LID AND C.ID=L.CULTURE_ID";
if(!is_array($arFilter))
$arFilter = Array();
$arSqlSearch = Array();
$filter_keys = array_keys($arFilter);
for($i = 0, $n = count($filter_keys); $i < $n; $i++)
{
$val = $arFilter[$filter_keys[$i]];
if (strlen($val)<=0) continue;
$key = strtoupper($filter_keys[$i]);
$strNegative = false;
if (substr($key, 0, 1) == '!')
{
$key = substr($key, 1);
$strNegative = 'Y';
}
$strExact = false;
if (substr($key, 0, 1) == '=')
{
$key = substr($key, 1);
$strExact = 'Y';
}
switch ($key)
{
case 'ID':
case 'PORT':
case 'DELETE_MESSAGES':
case 'ACTIVE':
case 'USE_MD5':
case 'RELAY':
case 'AUTH_RELAY':
$arSqlSearch[] = GetFilterQuery('MB.'.$key, ($strNegative == 'Y' ? '~' : '').$val, 'N');
break;
case 'LID':
case 'LOGIN':
case 'SERVER':
case 'NAME':
case 'DESCRIPTION':
case 'DOMAINS':
case 'SERVER_TYPE':
$arSqlSearch[] = GetFilterQuery('MB.'.$key, ($strNegative == 'Y' ? '~' : '').$val, $strExact == 'Y' ? 'N' : 'Y');
break;
case 'SERVICE_ID':
case 'USER_ID':
$arSqlSearch[] = 'MB.' . $key . ($strNegative == 'Y' ? ' != ' : ' = ') . intval($val);
break;
}
}
$is_filtered = false;
$strSqlSearch = "";
for($i = 0, $n = count($arSqlSearch); $i < $n; $i++)
{
if(strlen($arSqlSearch[$i])>0)
{
$is_filtered = true;
$strSqlSearch .= " AND (".$arSqlSearch[$i].") ";
}
}
$arSqlOrder = Array();
foreach($arOrder as $by=>$order)
{
$order = strtolower($order);
if ($order!="asc")
$order = "desc".(strtoupper($DB->type)=="ORACLE"?" NULLS LAST":"");
else
$order = "asc".(strtoupper($DB->type)=="ORACLE"?" NULLS FIRST":"");
switch(strtoupper($by))
{
case "TIMESTAMP_X":
case "LID":
case "ACTIVE":
case "NAME":
case "SERVER":
case "PORT":
case "LOGIN":
case "USE_MD5":
case "DELETE_MESSAGES":
case "RELAY":
case "AUTH_RELAY":
case "SERVER_TYPE":
case "PERIOD_CHECK":
$arSqlOrder[] = " MB.".$by." ".$order." ";
break;
default:
$arSqlOrder[] = " MB.ID ".$order." ";
}
}
$strSqlOrder = "";
$arSqlOrder = array_unique($arSqlOrder);
DelDuplicateSort($arSqlOrder);
for ($i = 0, $n = count($arSqlOrder); $i < $n; $i++)
{
if($i==0)
$strSqlOrder = " ORDER BY ";
else
$strSqlOrder .= ",";
$strSqlOrder .= $arSqlOrder[$i];
}
$strSql .= $strSqlSearch.$strSqlOrder;
$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$res = new _CMailBoxDBRes($res);
$res->is_filtered = $is_filtered;
return $res;
}
function GetByID($ID)
{
return CMailBox::GetList(Array(), Array("ID"=>$ID));
}
function CheckMail($mailbox_id = false)
{
global $DB;
$mbx = Array();
if($mailbox_id===false)
{
$strSql =
"SELECT MB.ID ".
"FROM b_mail_mailbox MB ".
"WHERE ACTIVE='Y' ";
$dbr = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
while($ar = $dbr->Fetch())
$mbx[] = $ar["ID"];
}
else
{
$mbx[] = $mailbox_id;
}
$bNoErrors = true;
foreach($mbx as $mailboxId)
{
$mb = new CMailbox();
if(!$mb->Connect($mailboxId))
{
$bNoErrors = false;
CMailError::SetError("ERR_CHECK_MAIL", GetMessage("MAIL_CL_ERR_CHECK_MAIL")." (mailbox id: ".$mailboxId.").", "");
}
}
return $bNoErrors;
}
function CheckMailAgent($ID)
{
global $DB, $USER;
$bUserCreated = false;
if (!isset($USER) || !is_object($USER))
{
$USER = new CUser();
$bUserCreated = true;
}
$ID = IntVal($ID);
$strSql =
"SELECT MB.ID, MB.PERIOD_CHECK ".
"FROM b_mail_mailbox MB ".
"WHERE ACTIVE='Y' ".
" AND ID=".$ID.
" AND USER_ID = 0";
$strReturn = '';
$dbr = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
if($ar = $dbr->Fetch())
{
$mb = new CMailbox();
$mb->Connect($ID);
if(intval($ar["PERIOD_CHECK"])>0)
$strReturn = "CMailbox::CheckMailAgent(".$ID.");";
}
if ($bUserCreated)
{
unset($USER);
}
return $strReturn;
}
function CheckFields($arFields, $ID=false)
{
global $APPLICATION;
$arMsg = array();
if (is_set($arFields, 'NAME') && strlen($arFields['NAME']) < 1)
{
CMailError::SetError('B_MAIL_ERR_NAME', GetMessage('MAIL_CL_ERR_NAME').' "'.GetMessage('MAIL_CL_NAME').'"');
$arMsg[] = array('id' => 'NAME', 'text' => GetMessage('MAIL_CL_ERR_NAME').' "'.GetMessage('MAIL_CL_NAME').'"');
}
if (in_array(strtolower($arFields['SERVER_TYPE']), array('pop3', 'imap', 'controller', 'domain', 'crdomain')) && is_set($arFields, 'LOGIN') && strlen($arFields['LOGIN']) < 1)
{
CMailError::SetError('B_MAIL_ERR_LOGIN', GetMessage('MAIL_CL_ERR_NAME').' "'.GetMessage('MAIL_CL_LOGIN').'"');
$arMsg[] = array('id' => 'LOGIN', 'text' => GetMessage('MAIL_CL_ERR_NAME').' "'.GetMessage('MAIL_CL_LOGIN').'"');
}
if (in_array(strtolower($arFields['SERVER_TYPE']), array('pop3', 'imap')) && is_set($arFields, 'PASSWORD') && strlen($arFields['PASSWORD']) < 1)
{
CMailError::SetError('B_MAIL_ERR_PASSWORD', GetMessage('MAIL_CL_ERR_NAME').' "'.GetMessage('MAIL_CL_PASSWORD').'"');
$arMsg[] = array('id' => 'PASSWORD', 'text' => GetMessage('MAIL_CL_ERR_NAME').' "'.GetMessage('MAIL_CL_PASSWORD').'"');
}
if (in_array(strtolower($arFields['SERVER_TYPE']), array('controller', 'domain', 'crdomain')) && is_set($arFields, 'USER_ID') && $arFields['USER_ID'] < 1)
{
CMailError::SetError('B_MAIL_ERR_USER_ID', GetMessage('MAIL_CL_ERR_NAME').' "'.GetMessage('MAIL_CL_USER_ID').'"');
$arMsg[] = array('id' => 'USER_ID', 'text' => GetMessage('MAIL_CL_ERR_NAME').' "'.GetMessage('MAIL_CL_USER_ID').'"');
}
if (in_array(strtolower($arFields['SERVER_TYPE']), array('pop3', 'smtp', 'imap')) && is_set($arFields, 'SERVER') && strlen($arFields['SERVER']) < 1)
{
CMailError::SetError('B_MAIL_ERR_SERVER_NAME', GetMessage('MAIL_CL_ERR_NAME').' "'.GetMessage('MAIL_CL_SERVER').'"');
$arMsg[] = array('id' => 'SERVER', 'text' => GetMessage('MAIL_CL_ERR_NAME').' "'.GetMessage('MAIL_CL_SERVER').'"');
}
elseif (strtolower($arFields['SERVER_TYPE']) == 'smtp')
{
$dbres = CMailBox::GetList(array(), array('ACTIVE' => 'Y', 'SERVER_TYPE' => 'smtp', 'SERVER' => $arFields['SERVER'], 'PORT' => $arFields['PORT']));
while($arres = $dbres->Fetch())
{
if ($ID === false || $arres['ID'] != $ID)
{
CMailError::SetError('B_MAIL_ERR_SERVER_NAME', GetMessage('B_MAIL_ERR_SN').' "'.GetMessage('MAIL_CL_SERVER').'"');
$arMsg[] = array('id' => 'SERVER', 'text' => GetMessage('B_MAIL_ERR_SN').' "'.GetMessage('MAIL_CL_SERVER').'"');
break;
}
}
}
if (is_set($arFields, 'LID'))
{
$r = CLang::GetByID($arFields['LID']);
if (!$r->Fetch())
{
CMailError::SetError('B_MAIL_ERR_BAD_LANG', GetMessage('MAIL_CL_ERR_BAD_LANG'));
$arMsg[] = array('id' => 'LID', 'text' => GetMessage('MAIL_CL_ERR_BAD_LANG'));
}
}
elseif ($ID === false)
{
CMailError::SetError('B_MAIL_ERR_BAD_LANG_NA', GetMessage('MAIL_CL_ERR_BAD_LANG_NX'));
$arMsg[] = array('id' => 'LID', 'text' => GetMessage('MAIL_CL_ERR_BAD_LANG_NX'));
}
if (in_array(strtolower($arFields['SERVER_TYPE']), array('imap', 'controller', 'domain', 'crdomain')))
{
if (is_set($arFields, 'SERVICE_ID'))
{
if (!empty($arFields['LID']) || $ID)
{
$LID_tmp = $arFields['LID'];
if (empty($arFields['LID']))
{
$arMb_tmp = CMailBox::GetList(array(), array('ID' => $ID))->fetch();
$LID_tmp = $arMb_tmp['LID'];
}
$result = Bitrix\Mail\MailServicesTable::getList(array(
'filter' => array('=SITE_ID' => $LID_tmp, '=ID' => $arFields['SERVICE_ID'])
));
if (!$result->fetch())
{
CMailError::SetError('B_MAIL_ERR_BAD_SERVICE_ID', GetMessage('MAIL_CL_ERR_BAD_SERVICE_ID'));
$arMsg[] = array('id' => 'SERVICE_ID', 'text' => GetMessage('MAIL_CL_ERR_BAD_SERVICE_ID'));
}
}
}
else if ($ID === false)
{
CMailError::SetError('B_MAIL_ERR_BAD_SERVICE_ID_NA', GetMessage('MAIL_CL_ERR_BAD_SERVICE_ID_NX'));
$arMsg[] = array('id' => 'SERVICE_ID', 'text' => GetMessage('MAIL_CL_ERR_BAD_SERVICE_ID_NX'));
}
}
if (!empty($arMsg))
{
$e = new CAdminException($arMsg);
$APPLICATION->ThrowException($e);
return false;
}
return true;
}
function Add($arFields)
{
global $DB;
CMailError::ResetErrors();
if($arFields["ACTIVE"] != "Y")
$arFields["ACTIVE"] = "N";
if($arFields["DELETE_MESSAGES"] != "Y")
$arFields["DELETE_MESSAGES"] = "N";
if($arFields["USE_MD5"] != "Y")
$arFields["USE_MD5"] = "N";
if ($arFields['USE_TLS'] != 'Y' && $arFields['USE_TLS'] != 'S')
$arFields["USE_TLS"] = "N";
if (!in_array($arFields["SERVER_TYPE"], array("pop3", "smtp", "imap", "controller", "domain", "crdomain")))
$arFields["SERVER_TYPE"] = "pop3";
if (!CMailBox::CheckFields($arFields))
return false;
if (is_set($arFields, "PASSWORD"))
$arFields["PASSWORD"] = CMailUtil::Crypt($arFields["PASSWORD"]);
if (is_set($arFields, 'OPTIONS'))
{
$arFields['OPTIONS'] = serialize($arFields['OPTIONS']);
}
$ID = $DB->Add("b_mail_mailbox", $arFields);
if ($arFields['ACTIVE'] == 'Y' && $arFields['USER_ID'] != 0)
{
CUserCounter::Clear($arFields['USER_ID'], 'mail_unseen', $arFields['LID']);
$mailboxSyncManager = new \Bitrix\Mail\Helper\Mailbox\MailboxSyncManager($arFields['USER_ID']);
$mailboxSyncManager->setDefaultSyncData($ID);
}
if (in_array($arFields['SERVER_TYPE'], array('imap', 'controller', 'domain', 'crdomain')))
{
\CAgent::addAgent(sprintf('Bitrix\Mail\Helper::syncMailboxAgent(%u);', $ID), 'mail', 'N', (int) $arFields['PERIOD_CHECK'] * 60);
}
if ($arFields['SERVER_TYPE'] == 'pop3' && (int) $arFields['PERIOD_CHECK'] > 0)
CAgent::addAgent(sprintf('CMailbox::CheckMailAgent(%u);', $ID), 'mail', 'N', (int) $arFields['PERIOD_CHECK']*60);
CMailbox::SMTPReload();
return $ID;
}
function Update($ID, $arFields)
{
global $DB;
$ID = IntVal($ID);
CMailError::ResetErrors();
if(is_set($arFields, "ACTIVE") && $arFields["ACTIVE"]!="Y")
$arFields["ACTIVE"]="N";
if(is_set($arFields, "DELETE_MESSAGES") && $arFields["DELETE_MESSAGES"]!="Y")
$arFields["DELETE_MESSAGES"]="N";
if(is_set($arFields, "USE_MD5") && $arFields["USE_MD5"]!="Y")
$arFields["USE_MD5"]="N";
if(is_set($arFields, 'USE_TLS') && $arFields['USE_TLS'] != 'Y' && $arFields['USE_TLS'] != 'S')
$arFields["USE_TLS"]="N";
if (is_set($arFields, "SERVER_TYPE") && !in_array($arFields["SERVER_TYPE"], array("pop3", "smtp", "imap", "controller", "domain", "crdomain")))
$arFields["SERVER_TYPE"] = "pop3";
if(!CMailBox::CheckFields($arFields, $ID))
return false;
if(is_set($arFields, "PASSWORD"))
$arFields["PASSWORD"]=CMailUtil::Crypt($arFields["PASSWORD"]);
$mbox = CMailbox::getList(array(), array('ID' => $ID))->fetch();
$userId = is_set($arFields, 'USER_ID') ? $arFields['USER_ID'] : $mbox['USER_ID'];
$serverType = is_set($arFields, 'SERVER_TYPE') ? $arFields['SERVER_TYPE'] : $mbox['SERVER_TYPE'];
$periodCheck = is_set($arFields, 'PERIOD_CHECK') ? $arFields['PERIOD_CHECK'] : $mbox['PERIOD_CHECK'];
$options = is_set($arFields, 'OPTIONS') ? $arFields['OPTIONS'] : $mbox['OPTIONS'];
if (is_set($arFields, 'OPTIONS'))
$arFields['OPTIONS'] = serialize($arFields['OPTIONS']);
if (!empty($mbox))
{
$userChanged = isset($arFields['USER_ID']) && $mbox['USER_ID'] != $arFields['USER_ID'];
$siteChanged = isset($arFields['LID']) && $mbox['LID'] != $arFields['LID'];
if ($userChanged || $siteChanged)
{
if ($mbox['ACTIVE'] == 'Y')
{
if ($mbox['USER_ID'] > 0)
{
$mailboxSyncManager = new \Bitrix\Mail\Helper\Mailbox\MailboxSyncManager($mbox['USER_ID']);
$mailboxSyncManager->deleteSyncData($mbox['ID']);
}
}
$newActive = isset($arFields['ACTIVE']) ? $arFields['ACTIVE'] : $mbox['ACTIVE'];
if ($newActive == 'Y')
{
$newUserId = isset($arFields['USER_ID']) ? $arFields['USER_ID'] : $mbox['USER_ID'];
$newSiteId = isset($arFields['LID']) ? $arFields['LID'] : $mbox['LID'];
if ($newUserId > 0)
{
$mailboxSyncManager = new \Bitrix\Mail\Helper\Mailbox\MailboxSyncManager($newUserId);
$mailboxSyncManager->setDefaultSyncData($mbox['ID']);
}
}
}
if ($mbox['USER_ID'] != 0 || isset($arFields['USER_ID']) && $arFields['USER_ID'] != 0)
{
CUserCounter::Clear($mbox['USER_ID'], 'mail_unseen', $mbox['LID']);
if ($siteChanged)
CUserCounter::Clear($mbox['USER_ID'], 'mail_unseen', $arFields['LID']);
if ($userChanged)
{
CUserCounter::Clear($arFields['USER_ID'], 'mail_unseen', $mbox['LID']);
if (isset($arFields['LID']) && $mbox['LID'] != $arFields['LID'])
CUserCounter::Clear($arFields['USER_ID'], 'mail_unseen', $arFields['LID']);
}
}
}
CAgent::removeAgent(sprintf('CMailbox::CheckMailAgent(%u);', $ID), 'mail');
CAgent::removeAgent(sprintf('Bitrix\Mail\Helper::syncMailboxAgent(%u);', $ID), 'mail');
$strSql = sprintf(
'UPDATE b_mail_mailbox SET %s WHERE ID = %u',
$DB->prepareUpdate('b_mail_mailbox', $arFields), $ID
);
$DB->query($strSql, false, 'File: '.__FILE__.'<br>Line: '.__LINE__);
if (in_array($serverType, array('imap', 'controller', 'domain', 'crdomain')))
{
\CAgent::addAgent(sprintf('Bitrix\Mail\Helper::syncMailboxAgent(%u);', $ID), 'mail', 'N', (int) $periodCheck*60);
}
if ($serverType == 'pop3' && (int) $periodCheck > 0)
CAgent::addAgent(sprintf('CMailbox::CheckMailAgent(%u);', $ID), 'mail', 'N', (int) $periodCheck*60);
CMailbox::SMTPReload();
return true;
}
function Delete($ID)
{
global $DB;
$ID = IntVal($ID);
Bitrix\Main\Loader::includeModule('mail');
$db_msg = Bitrix\Mail\MailMessageTable::getList(array(
'select' => array('ID'),
'filter' => array('MAILBOX_ID' => $ID)
));
while($msg = $db_msg->Fetch())
{
if(!CMailMessage::Delete($msg["ID"]))
return false;
}
$db_flt = CMailFilter::GetList(Array(), Array("MAILBOX_ID"=>$ID));
while($flt = $db_flt->Fetch())
{
if(!CMailFilter::Delete($flt["ID"]))
return false;
}
$db_mbox = \CMailbox::getList(array('ID' => $ID, 'ACTIVE' => 'Y'));
if ($mbox = $db_mbox->fetch())
{
if ($mbox['USER_ID'] > 0)
{
\CUserCounter::clear($mbox['USER_ID'], 'mail_unseen', $mbox['LID']);
$mailboxSyncManager = new \Bitrix\Mail\Helper\Mailbox\MailboxSyncManager($mbox['USER_ID']);
$mailboxSyncManager->deleteSyncData($ID);
}
}
CAgent::removeAgent(sprintf('CMailbox::CheckMailAgent(%u);', $ID), 'mail');
CAgent::removeAgent(sprintf('Bitrix\Mail\Helper::syncMailboxAgent(%u);', $ID), 'mail');
$strSql = "DELETE FROM b_mail_log WHERE MAILBOX_ID=".$ID;
if(!$DB->Query($strSql, true))
return false;
$strSql = "DELETE FROM b_mail_message_uid WHERE MAILBOX_ID=".$ID;
if(!$DB->Query($strSql, true))
return false;
$strSql = "DELETE FROM b_mail_blacklist WHERE MAILBOX_ID=".$ID;
if(!$DB->Query($strSql, true))
return false;
CMailbox::SMTPReload();
$strSql = "DELETE FROM b_mail_mailbox WHERE ID=".$ID;
return $DB->Query($strSql, true);
}
function SMTPReload()
{
global $CACHE_MANAGER;
$CACHE_MANAGER->Read(3600000, $cache_id = "smtpd_reload");
$CACHE_MANAGER->Set($cache_id, true);
}
function SendCommand($command)
{
//SSRF "filter"
$command = preg_replace("/[\\n\\r]/", "", $command);
fputs($this->pop3_conn, $command."\r\n");
if($this->mailbox_id>0)
{
CMailLog::AddMessage(
Array(
"MAILBOX_ID"=>$this->mailbox_id,
"STATUS_GOOD"=>"Y",
"MESSAGE"=>"> ".nl2br(preg_replace("'PASS .*'", "PASS ******", $command))
)
);
}
$this->resp = true;
}
function GetResponse($bMultiline = false, $bSkipFirst = true)
{
if(!$this->resp) return false;
$this->resp = false;
socket_set_timeout($this->pop3_conn, 20);
$res = rtrim(fgets($this->pop3_conn, 1024), "\r\n");
// socket_set_blocking($this->pop3_conn, false);
// socket_set_blocking($this->pop3_conn, true);
$this->last_result = ($res[0]=="+");
$this->response = $res;
if($this->mailbox_id>0)
{
CMailLog::AddMessage(
Array(
"MAILBOX_ID"=>$this->mailbox_id,
"STATUS_GOOD"=>($this->last_result?"Y":"N"),
"MESSAGE"=>"< ".$res
)
);
}
if($bMultiline && $res[0]=="+")
{
if($bSkipFirst)
$res = "";
else
$res .= "\r\n";
$s = fgets($this->pop3_conn, 1024);
while(strlen($s)>0 && $s!=".\r\n")
{
if(substr($s, 0, 2)=="..")
$s = substr($s, 1);
$res .= $s;
$s = fgets($this->pop3_conn, 1024);
}
}
$this->response_body = $res;
return $this->last_result;
}
function GetResponseBody()
{
return $this->response_body;
}
function GetResponseString()
{
return $this->response_body;
}
function GetPassword($p)
{
}
function Check($server, $port, $use_tls, $login, $passw)
{
if (($use_tls == 'Y' || $use_tls == 'S') && !preg_match('#^(tls|ssl)://#', $server))
$server = 'ssl://' . $server;
$skip_cert = $use_tls != 'Y' || PHP_VERSION_ID < 50600;
$pop3_conn = &$this->pop3_conn;
$pop3_conn = stream_socket_client(
sprintf('%s:%s', $server, $port),
$errno, $errstr,
COption::getOptionInt('mail', 'connect_timeout', B_MAIL_TIMEOUT),
STREAM_CLIENT_CONNECT,
stream_context_create(array('ssl' => array('verify_peer' => !$skip_cert, 'verify_peer_name' => !$skip_cert)))
);
if(!$pop3_conn)
return array(false, GetMessage("MAIL_CL_TIMEOUT")." $errstr ($errno)");
$this->GetResponse();
$greeting = $this->GetResponseString();
$this->SendCommand("USER ".$login);
if(!$this->GetResponse())
return array(false, GetMessage("MAIL_CL_ERR_USER").' ('.$this->GetResponseString().')');
$this->SendCommand("PASS ".$passw);
if(!$this->GetResponse())
return array(false, GetMessage("MAIL_CL_ERR_PASSWORD").' ('.$this->GetResponseString().')');
$this->SendCommand("STAT");
if(!$this->GetResponse())
return array(false, GetMessage("MAIL_CL_ERR_STAT").' ('.$this->GetResponseString().')');
$stat = trim($this->GetResponseBody());
$arStat = explode(" ", $stat);
return array(true, $arStat[1]);
}
function Connect($mailbox_id)
{
global $DB;
$mailbox_id = IntVal($mailbox_id);
$strSql =
"SELECT MB.*, C.CHARSET as LANG_CHARSET ".
"FROM b_mail_mailbox MB, b_lang L, b_culture C ".
"WHERE MB.LID=L.LID AND C.ID=L.CULTURE_ID ".
" AND MB.ID=".$mailbox_id;
$dbr = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$dbr = new _CMailBoxDBRes($dbr);
if(!$arMAILBOX_PARAMS = $dbr->Fetch())
return CMailError::SetError("ERR_MAILBOX_NOT_FOUND", GetMessage("MAIL_CL_ERR_MAILBOX_NOT_FOUND"), GetMessage("MAIL_CL_ERR_MAILBOX_NOT_FOUND"));
if ($arMAILBOX_PARAMS['SYNC_LOCK'] > time()-600)
return;
$DB->query('UPDATE b_mail_mailbox SET SYNC_LOCK = '.time().' WHERE ID = '.$mailbox_id);
$result = $this->_connect($mailbox_id, $arMAILBOX_PARAMS);
$DB->query('UPDATE b_mail_mailbox SET SYNC_LOCK = 0 WHERE ID = '.$mailbox_id);
return $result;
}
private function _connect($mailbox_id, $arMAILBOX_PARAMS)
{
global $DB;
@set_time_limit(0);
// https://support.google.com/mail/answer/47948
if ($arMAILBOX_PARAMS["SERVER"] == 'pop.gmail.com')
$arMAILBOX_PARAMS["LOGIN"] = 'recent:' . $arMAILBOX_PARAMS["LOGIN"];
$server = $arMAILBOX_PARAMS["SERVER"];
if (($arMAILBOX_PARAMS['USE_TLS'] == 'Y' || $arMAILBOX_PARAMS['USE_TLS'] == 'S') && !preg_match('#^(tls|ssl)://#', $server))
$server = 'ssl://' . $server;
$skip_cert = $arMAILBOX_PARAMS['USE_TLS'] != 'Y' || PHP_VERSION_ID < 50600;
$pop3_conn = &$this->pop3_conn;
$pop3_conn = stream_socket_client(
sprintf('%s:%s', $server, $arMAILBOX_PARAMS["PORT"]),
$errno, $errstr,
COption::getOptionInt('mail', 'connect_timeout', B_MAIL_TIMEOUT),
STREAM_CLIENT_CONNECT,
stream_context_create(array('ssl' => array('verify_peer' => !$skip_cert, 'verify_peer_name' => !$skip_cert)))
);
CMailLog::AddMessage(
Array(
"MAILBOX_ID"=>$mailbox_id,
"STATUS_GOOD"=>"Y",
"MESSAGE"=>GetMessage("MAIL_CL_CONNECT_TO")." ".$arMAILBOX_PARAMS["SERVER"]
)
);
if(!$pop3_conn || !is_resource($pop3_conn))
{
CMailLog::AddMessage(
Array(
"MAILBOX_ID"=>$mailbox_id,
"STATUS_GOOD"=>"N",
"MESSAGE"=>GetMessage("MAIL_CL_TIMEOUT")
)
);
return CMailError::SetError("ERR_CONNECT_TIMEOUT", GetMessage("MAIL_CL_TIMEOUT"), "$errstr ($errno)");
}
$this->mailbox_id = $mailbox_id;
if($arMAILBOX_PARAMS["CHARSET"]!='')
$this->charset = $arMAILBOX_PARAMS["CHARSET"];
else
$this->charset = $arMAILBOX_PARAMS["LANG_CHARSET"];
$this->use_md5 = $arMAILBOX_PARAMS["USE_MD5"];
$session_id = md5(uniqid(""));
$this->GetResponse();
$greeting = $this->GetResponseString();
if($this->use_md5=="Y" && preg_match("'(<.+>)'", $greeting, $reg))
{
$this->SendCommand("APOP ".$arMAILBOX_PARAMS["LOGIN"]." ".md5($reg[1].$arMAILBOX_PARAMS["PASSWORD"]));
if(!$this->GetResponse())
return CMailError::SetError("ERR_AFTER_USER", GetMessage("MAIL_CL_ERR_APOP"), $this->GetResponseString());
}
else
{
$this->SendCommand("USER ".$arMAILBOX_PARAMS["LOGIN"]);
if(!$this->GetResponse())
return CMailError::SetError("ERR_AFTER_USER", GetMessage("MAIL_CL_ERR_USER"), $this->GetResponseString());
$this->SendCommand("PASS ".$arMAILBOX_PARAMS["PASSWORD"]);
if(!$this->GetResponse())
return CMailError::SetError("ERR_AFTER_PASS", GetMessage("MAIL_CL_ERR_PASSWORD"), $this->GetResponseString());
}
$this->SendCommand("STAT");
if(!$this->GetResponse())
return CMailError::SetError("ERR_AFTER_STAT", GetMessage("MAIL_CL_ERR_STAT"), $this->GetResponseString());
$stat = trim($this->GetResponseBody());
$arStat = explode(" ", $stat);
$this->mess_count = $arStat[1];
if($this->mess_count>0)
{
$this->mess_size = $arStat[2];
$arLIST = array();
if($arMAILBOX_PARAMS["MAX_MSG_SIZE"]>0)
{
$this->SendCommand("LIST");
if(!$this->GetResponse(true))
return CMailError::SetError("ERR_AFTER_LIST", "LIST command error", $this->GetResponseString());
$list = $this->GetResponseBody();
preg_match_all("'([0-9]+)[ ]+?(.+)'", $list, $arLIST_temp, PREG_SET_ORDER);
for($i = 0, $n = count($arLIST_temp); $i < $n; $i++)
$arLIST[IntVal($arLIST_temp[$i][1])] = IntVal($arLIST_temp[$i][2]);
}
$this->SendCommand("UIDL");
if(!$this->GetResponse(true))
return CMailError::SetError("ERR_AFTER_UIDL", GetMessage("MAIL_CL_ERR_UIDL"), $this->GetResponseString());
$uidl = $this->GetResponseBody();
preg_match_all("'([0-9]+)[ ]+?(.+)'", $uidl, $arUIDL_temp, PREG_SET_ORDER);
$arUIDL = array();
$cnt = count($arUIDL_temp);
for ($i = 0; $i < $cnt; $i++)
$arUIDL[md5($arUIDL_temp[$i][2])] = $arUIDL_temp[$i][1];
$skipOldUIDL = $cnt < $this->mess_count;
if ($skipOldUIDL)
{
AddMessage2Log(sprintf(
"%s\n%s of %s",
$this->response, $cnt, $this->mess_count
), 'mail');
}
$arOldUIDL = array();
if (count($arUIDL) > 0)
{
$strSql = 'SELECT ID FROM b_mail_message_uid WHERE MAILBOX_ID = ' . $mailbox_id;
$db_res = $DB->query($strSql, false, 'File: '.__FILE__.'<br>Line: '.__LINE__);
while ($ar_res = $db_res->fetch())
{
if (isset($arUIDL[$ar_res['ID']]))
unset($arUIDL[$ar_res['ID']]);
else if (!$skipOldUIDL)
$arOldUIDL[] = $ar_res['ID'];
}
}
while (count($arOldUIDL) > 0)
{
$ids = "'" . join("','", array_splice($arOldUIDL, 0, 1000)) . "'";
$strSql = 'DELETE FROM b_mail_message_uid WHERE MAILBOX_ID = ' . $mailbox_id . ' AND ID IN (' . $ids . ')';
$DB->query($strSql, false, 'File: '.__FILE__.'<br>Line: '.__LINE__);
}
$this->new_mess_count = 0;
$this->deleted_mess_count = 0;
$session_id = md5(uniqid(""));
foreach($arUIDL as $msguid=>$msgnum)
{
if($arMAILBOX_PARAMS["MAX_MSG_SIZE"]<=0 || $arLIST[$msgnum]<=$arMAILBOX_PARAMS["MAX_MSG_SIZE"])
$this->GetMessage($mailbox_id, $msgnum, $msguid, $session_id);
if($arMAILBOX_PARAMS["DELETE_MESSAGES"]=="Y")
{
$this->DeleteMessage($msgnum);
$this->deleted_mess_count++;
}
$this->new_mess_count++;
if($arMAILBOX_PARAMS["MAX_MSG_COUNT"]>0 && $arMAILBOX_PARAMS["MAX_MSG_COUNT"]<=$this->new_mess_count)
break;
}
}
$this->SendCommand("QUIT");
if(!$this->GetResponse())
return CMailError::SetError("ERR_AFTER_QUIT", GetMessage("MAIL_CL_ERR_DISCONNECT"), $this->GetResponseString());
fclose($pop3_conn);
return true;
}
function GetMessage($mailbox_id, $msgnum, $msguid, $session_id)
{
global $DB;
$this->SendCommand("RETR ".$msgnum);
if(!$this->GetResponse(true))
return CMailError::SetError("ERR_AFTER_RETR", GetMessage("MAIL_CL_ERR_RETR"), $this->GetResponseString());
$message = $this->GetResponseBody();
$strSql = "INSERT INTO b_mail_message_uid(ID, MAILBOX_ID, SESSION_ID, DATE_INSERT, MESSAGE_ID) VALUES('".$DB->ForSql($msguid)."', ".IntVal($mailbox_id).", '".$DB->ForSql($session_id)."', ".$DB->GetNowFunction().", 0)";
$DB->Query($strSql);
$message_id = CMailMessage::AddMessage($mailbox_id, $message, $this->charset);
if($message_id>0)
{
$strSql = "UPDATE b_mail_message_uid SET MESSAGE_ID = " . intval($message_id) . " WHERE ID = '" . $DB->forSql($msguid) . "' AND MAILBOX_ID = " . intval($mailbox_id);
$DB->Query($strSql);
}
return $message_id;
} // function GetMessage(...
/*********************************************************************
*********************************************************************/
function DeleteMessage($msgnum)
{
$this->SendCommand("DELE ".$msgnum);
if(!$this->GetResponse())
return CMailError::SetError("ERR_AFTER_DELE", GetMessage("MAIL_CL_ERR_DELE"), $this->GetResponseString());
}
}
///////////////////////////////////////////////////////////////////////////////////
// class CMailHeader
///////////////////////////////////////////////////////////////////////////////////
class CMailHeader
{
var $arHeader = Array();
var $arHeaderLines = Array();
var $strHeader = "";
var $bMultipart = false;
var $content_type, $boundary, $charset, $filename, $MultipartType="mixed";
public $content_id = '';
function ConvertHeader($encoding, $type, $str, $charset)
{
if(strtoupper($type)=="B")
$str = base64_decode($str);
else
$str = quoted_printable_decode(str_replace("_", " ", $str));
$str = CMailUtil::ConvertCharset($str, $encoding, $charset);
return $str;
}
function DecodeHeader($str, $charset_to, $charset_document)
{
while(preg_match('/(=\?[^?]+\?(Q|B)\?[^?]*\?=)(\s)+=\?/i', $str))
$str = preg_replace('/(=\?[^?]+\?(Q|B)\?[^?]*\?=)(\s)+=\?/i', '\1=?', $str);
if(!preg_match("'=\?(.*)\?(B|Q)\?(.*)\?='i", $str))
{
if ($charset_document != '')
$str = CMailUtil::ConvertCharset($str, $charset_document, $charset_to);
}
else
{
$str = preg_replace_callback(
"'=\?(.*?)\?(B|Q)\?(.*?)\?='i",
create_function('$m', "return CMailHeader::ConvertHeader(\$m[1], \$m[2], \$m[3], '".AddSlashes($charset_to)."');"),
$str
);
}
return $str;
}
function Parse($message_header, $charset)
{
$this->charset = defined('BX_MAIL_DEFAULT_CHARSET') && BX_MAIL_DEFAULT_CHARSET != '' ? BX_MAIL_DEFAULT_CHARSET : $charset;
if(preg_match("'content-type:.*?charset\s*=\s*([^\r\n;]+)'is", $message_header, $res))
$this->charset = strtolower(trim($res[1], ' "'));
$ar_message_header_tmp = explode("\r\n", $message_header);
$n = -1;
$bConvertSubject = false;
for($i = 0, $num = count($ar_message_header_tmp); $i < $num; $i++)
{
$line = $ar_message_header_tmp[$i];
if(($line[0]==" " || $line[0]=="\t") && $n>=0)
{
$line = ltrim($line, " \t");
$bAdd = true;
}
else
$bAdd = false;
$line = CMailHeader::DecodeHeader($line, $charset, $this->charset);
if($bAdd)
$this->arHeaderLines[$n] = $this->arHeaderLines[$n].$line;
else
{
$n++;
$this->arHeaderLines[] = $line;
}
}
$this->arHeader = Array();
for($i = 0, $num = count($this->arHeaderLines); $i < $num; $i++)
{
$p = strpos($this->arHeaderLines[$i], ":");
if($p>0)
{
$header_name = strtoupper(trim(substr($this->arHeaderLines[$i], 0, $p)));
$header_value = trim(substr($this->arHeaderLines[$i], $p+1));
$this->arHeader[$header_name] = $header_value;
}
}
$full_content_type = $this->arHeader["CONTENT-TYPE"];
if(strlen($full_content_type)<=0)
$full_content_type = "text/plain";
if(!($p = strpos($full_content_type, ";")))
$p = strlen($full_content_type);
$this->content_type = trim(substr($full_content_type, 0, $p));
if(strpos(strtolower($this->content_type), "multipart/") === 0)
{
$this->bMultipart = true;
if (!preg_match("'boundary\s*=(.+?);'i", $full_content_type, $res))
preg_match("'boundary\s*=(.+)'i", $full_content_type, $res);
$this->boundary = trim($res[1], '"');
if($p = strpos($this->content_type, "/"))
$this->MultipartType = substr($this->content_type, $p+1);
}
if($p < strlen($full_content_type))
{
$add = substr($full_content_type, $p+1);
if(preg_match("'name=([^;]+)'i", $full_content_type, $res))
$this->filename = trim($res[1], '"');
}
$cd = $this->arHeader["CONTENT-DISPOSITION"];
if (strlen($cd) > 0)
{
if (preg_match("'filename=([^;]+)'i", $cd, $res))
{
$this->filename = trim($res[1], '"');
}
else if (preg_match("'filename\*=([^;]+)'i", $cd, $res))
{
list($fncharset, $fnstr) = preg_split("/'[^']*'/", trim($res[1], '"'));
$this->filename = CMailUtil::ConvertCharset(rawurldecode($fnstr), $fncharset, $charset);
}
else if (preg_match("'filename\*0=([^;]+)'i", $cd, $res))
{
$this->filename = trim($res[1], '"');
$i = 0;
while (preg_match("'filename\*".(++$i)."=([^;]+)'i", $cd, $res))
$this->filename .= trim($res[1], '"');
}
else if (preg_match("'filename\*0\*=([^;]+)'i", $cd, $res))
{
$fnstr = trim($res[1], '"');
$i = 0;
while (preg_match("'filename\*".(++$i)."\*?=([^;]+)'i", $cd, $res))
$fnstr .= trim($res[1], '"');
list($fncharset, $fnstr) = preg_split("/'[^']*'/", $fnstr);
$this->filename = CMailUtil::convertCharset(rawurldecode($fnstr), $fncharset, $charset);
}
}
if($this->arHeader["CONTENT-ID"]!='')
$this->content_id = trim($this->arHeader["CONTENT-ID"], '"<>');
$this->strHeader = implode("\r\n", $this->arHeaderLines);
return true;
}
function IsMultipart()
{
return $this->bMultipart;
}
function MultipartType()
{
return strtolower($this->MultipartType);
}
function GetBoundary()
{
return $this->boundary;
}
function GetHeader($type)
{
return $this->arHeader[strtoupper($type)];
}
}
class CMailMessageDBResult extends CDBResult
{
function fetch()
{
if ($item = parent::fetch())
{
$item['OPTIONS'] = (array) @unserialize($item['OPTIONS']);
}
$item['FOR_SPAM_TEST'] = sprintf('%s %s', $item['HEADER'], $item['BODY_HTML'] ?: $item['BODY']);
return $item;
}
}
///////////////////////////////////////////////////////////////////////////////////
// class CMailMessage
///////////////////////////////////////////////////////////////////////////////////
class CAllMailMessage
{
public static function GetList($arOrder = Array(), $arFilter = Array(), $bCnt = false)
{
global $DB;
if(strtoupper($DB->type)=="MYSQL")
$sum = "IF(NEW_MESSAGE='Y', 1, 0)";
else
$sum = "case when NEW_MESSAGE='Y' then 1 else 0 end";
$strSql =
"SELECT ".
($bCnt?
"COUNT('x') as CNT, SUM(".$sum.") as CNT_NEW, COUNT('x')-SUM(".$sum.") as CNT_OLD "
:
"MS.*, MB.NAME as MAILBOX_NAME, MB.LID, ".
" ".$DB->DateToCharFunction("MS.DATE_INSERT")." as DATE_INSERT, ".
" ".$DB->DateToCharFunction("MS.FIELD_DATE")." as FIELD_DATE "
).
"FROM b_mail_message MS ".
($bCnt? "":" INNER JOIN b_mail_mailbox MB ON MS.MAILBOX_ID=MB.ID ");
$arSqlSearch = Array();
$filter_keys = array_keys($arFilter);
for($i = 0, $n = count($filter_keys); $i < $n; $i++)
{
$key = $filter_keys[$i];
$val = $arFilter[$key];
$res = CMailUtil::MkOperationFilter($key);
$key = strtoupper($res["FIELD"]);
$cOperationType = $res["OPERATION"];
if($cOperationType == "?")
{
if (strlen($val)<=0) continue;
switch($key)
{
case "ID":
case "MAILBOX_ID":
case "MSGUID":
$arSqlSearch[] = GetFilterQuery("MS.".$key, $val, "N");
break;
case "FIELD_FROM":
case "FIELD_TO":
case "FIELD_CC":
case "FIELD_BCC":
$arSqlSearch[] = GetFilterQuery("MS.".$key, $val, "Y", Array("@", "_", ".", "-"));
break;
case "NEW_MESSAGE":
case "SUBJECT":
case "HEADER":
case "MSG_ID":
case "IN_REPLY_TO":
case "BODY":
$arSqlSearch[] = GetFilterQuery("MS.".$key, $val);
break;
case "SENDER":
$arSqlSearch[] = GetFilterQuery("MS.FIELD_FROM", $val, "Y", array("@","_",".","-"));
break;
case "RECIPIENT":
$arSqlSearch[] = GetFilterQuery("MS.FIELD_TO, MS.FIELD_CC, MS.FIELD_BCC", $val, "Y", array("@","_",".","-"));
break;
case "SPAM_RATING":
CMailFilter::RecalcSpamRating();
$arSqlSearch[] = GetFilterQuery("MS.SPAM_RATING", $val, "N");
break;
case "SPAM":
$arSqlSearch[] = GetFilterQuery("MS.SPAM", $val, "Y", array("?"));
break;
case "ALL":
$arSqlSearch[] = GetFilterQuery("MS.HEADER, MS.BODY", $val);
break;
}
}
else
{
switch($key)
{
case "SPAM":
case "NEW_MESSAGE":
$arSqlSearch[] = CMailUtil::FilterCreate("MS.".$key, $val, "string_equal", $cOperationType);
break;
case "ID":
case "MAILBOX_ID":
$arSqlSearch[] = CMailUtil::FilterCreate("MS.".$key, $val, "number", $cOperationType);
break;
case "SUBJECT":
case "HEADER":
case "BODY":
case "MSGUID":
case "FIELD_FROM":
case "FIELD_TO":
case "FIELD_CC":
case "MSG_ID":
case "IN_REPLY_TO":
case "FIELD_BCC":
$arSqlSearch[] = CMailUtil::FilterCreate("MS.".$key, $val, "string", $cOperationType);
break;
case "SPAM_RATING":
$arSqlSearch[] = CMailUtil::FilterCreate("MS.".$key, $val, "number", $cOperationType);
CMailFilter::RecalcSpamRating();
break;
/*
case "TIMESTAMP_X":
$arSqlSearch[] = CIBlock::FilterCreate("BE.TIMESTAMP_X", $val, "date", $cOperationType);
break;
*/
}
}
}
$is_filtered = false;
$strSqlSearch = "";
for($i = 0, $n = count($arSqlSearch); $i < $n; $i++)
{
if(strlen($arSqlSearch[$i])>0)
{
$strSqlSearch .= " AND (".$arSqlSearch[$i].") ";
$is_filtered = true;
}
}
$arSqlOrder = Array();
foreach($arOrder as $by=>$order)
{
$by = strtolower($by);
$order = strtolower($order);
if ($order!="asc")
$order = "desc".(strtoupper($DB->type)=="ORACLE"?" NULLS LAST":"");
else
$order = "asc".(strtoupper($DB->type)=="ORACLE"?" NULLS FIRST":"");
if ($by == "field_date") $arSqlOrder[] = " MS.FIELD_DATE ".$order." ";
elseif ($by == "field_from") $arSqlOrder[] = " MS.FIELD_FROM ".$order." ";
elseif ($by == "field_reply_to")$arSqlOrder[] = " MS.FIELD_REPLY_TO ".$order." ";
elseif ($by == "field_to") $arSqlOrder[] = " MS.FIELD_TO ".$order." ";
elseif ($by == "field_cc") $arSqlOrder[] = " MS.FIELD_CC ".$order." ";
elseif ($by == "field_bcc") $arSqlOrder[] = " MS.FIELD_BCC ".$order." ";
elseif ($by == "subject") $arSqlOrder[] = " MS.SUBJECT ".$order." ";
elseif ($by == "attachments") $arSqlOrder[] = " MS.ATTACHMENTS ".$order." ";
elseif ($by == "date_insert") $arSqlOrder[] = " MS.DATE_INSERT ".$order." ";
elseif ($by == "msguid") $arSqlOrder[] = " MS.MSGUID ".$order." ";
elseif ($by == "mailbox_id") $arSqlOrder[] = " MS.MAILBOX_ID ".$order." ";
elseif ($by == "new_message") $arSqlOrder[] = " MS.NEW_MESSAGE ".$order." ";
elseif ($by == "mailbox_name" && !$bCnt) $arSqlOrder[] = " MB.NAME ".$order." ";
elseif ($by == "spam_rating")
{
$arSqlOrder[] = " MS.SPAM_RATING ".$order." "; CMailFilter::RecalcSpamRating();
}
else $arSqlOrder[] = " MS.ID ".$order." ";
}
$strSqlOrder = "";
$arSqlOrder = array_unique($arSqlOrder);
DelDuplicateSort($arSqlOrder);
for ($i = 0, $n = count($arSqlOrder); $i < $n; $i++)
{
if($i==0)
$strSqlOrder = " ORDER BY ";
else
$strSqlOrder .= ",";
$strSqlOrder .= $arSqlOrder[$i];
}
$strSql .= " WHERE 1=1 ".$strSqlSearch.$strSqlOrder;
$dbr = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$dbr = new \CMailMessageDBResult($dbr);
$dbr->is_filtered = $is_filtered;
return $dbr;
}
function GetByID($ID)
{
return CMailMessage::GetList(Array(), Array("=ID"=>$ID));
}
function GetSpamRating($msgid, $arRow=false)
{
global $DB;
if(!is_array($arRow))
$res = $DB->Query("SELECT SPAM_RATING, SPAM_LAST_RESULT, HEADER, BODY_HTML, BODY FROM b_mail_message WHERE ID=".Intval($msgid));
else
$ar = $arRow;
if(is_array($arRow) || $ar = $res->Fetch())
{
if (empty($ar['FOR_SPAM_TEST']))
{
$ar['FOR_SPAM_TEST'] = sprintf('%s %s', $ar['HEADER'], $ar['BODY_HTML'] ?: $ar['BODY'] );
}
if($ar["SPAM_LAST_RESULT"]=="Y")
return $ar["SPAM_RATING"];
$arSpam = CMailFilter::GetSpamRating($ar["FOR_SPAM_TEST"]);
$num = Round($arSpam["RATING"], 4);
$DB->Query("UPDATE b_mail_message SET SPAM_RATING=".$num.", SPAM_LAST_RESULT='Y', SPAM_WORDS='".$DB->ForSql($arSpam["WORDS"], 255)."' WHERE ID=".Intval($msgid));
return $num;
}
}
function ParseHeader($message_header, $charset)
{
$h = new CMailHeader();
$h->Parse($message_header, $charset);
return $h;
}
private static function decodeMessageBody($header, $body, $charset)
{
$encoding = strtolower($header->GetHeader('CONTENT-TRANSFER-ENCODING'));
if ($encoding == 'base64')
$body = base64_decode($body);
elseif ($encoding == 'quoted-printable')
$body = quoted_printable_decode($body);
elseif ($encoding == 'x-uue')
$body = CMailUtil::uue_decode($body);
$content_type = strtolower($header->content_type);
if (
preg_match('/plain|html|text/', $content_type)
&& (empty($header->filename) || !empty($header->charset))
&& strpos($content_type, 'x-vcard') === false
&& strpos($content_type, 'csv') === false
)
{
$body = CMailUtil::convertCharset($body, $header->charset, $charset);
}
return array(
'CONTENT-TYPE' => $content_type,
'CONTENT-ID' => $header->content_id,
'BODY' => $body,
'FILENAME' => $header->filename
);
}
private static function parseMessage($message, $charset)
{
$headerP = \CUtil::binStrpos($message, "\r\n\r\n");
if (false === $headerP)
{
$rawHeader = '';
$body = $message;
}
else
{
$rawHeader = \CUtil::binSubstr($message, 0, $headerP);
$body = \CUtil::binSubstr($message, $headerP+4);
}
$header = \CMailMessage::parseHeader($rawHeader, $charset);
$htmlBody = '';
$textBody = '';
$parts = array();
if ($header->isMultipart())
{
$startP = 0;
$startRegex = sprintf('/(^|\r\n)--%s\r\n/', preg_quote($header->getBoundary(), '/'));
if (preg_match($startRegex, $body, $matches, PREG_OFFSET_CAPTURE))
{
$startP = $matches[0][1] + \CUtil::binStrlen($matches[0][0]);
}
$endP = \CUtil::binStrlen($body);
$endRegex = sprintf('/\r\n--%s--(\r\n|$)/', preg_quote($header->getBoundary(), '/'));
if (preg_match($endRegex, $body, $matches, PREG_OFFSET_CAPTURE))
{
$endP = $matches[0][1];
}
if (!($startP < $endP))
{
$startP = 0;
}
$data = \CUtil::binSubstr($body, $startP, $endP-$startP);
$isHtml = false;
$rawParts = preg_split(sprintf('/\r\n--%s\r\n/', preg_quote($header->getBoundary(), '/')), $data);
$tmpParts = array();
foreach ($rawParts as $part)
{
if (CUtil::binSubstr($part, 0, 2) == "\r\n")
$part = "\r\n" . $part;
list(, $subHtml, $subText, $subParts) = CMailMessage::parseMessage($part, $charset);
if ($subHtml)
$isHtml = true;
if ($subText)
$tmpParts[] = array($subHtml, $subText);
$parts = array_merge($parts, $subParts);
}
if (strtolower($header->MultipartType()) == 'alternative')
{
$candidate = '';
foreach ($tmpParts as $part)
{
if ($part[0])
{
if (!$htmlBody || (strlen($htmlBody) < strlen($part[0])))
{
$htmlBody = $part[0];
$candidate = $part[1];
}
}
else
{
if (!$textBody || strlen($textBody) < strlen($part[1]))
$textBody = $part[1];
}
}
if (!trim($textBody))
$textBody = $candidate;
}
else
{
foreach ($tmpParts as $part)
{
if ($textBody)
$textBody .= "\r\n\r\n";
$textBody .= $part[1];
if ($isHtml)
{
if ($htmlBody)
$htmlBody .= "\r\n\r\n";
$htmlBody .= $part[0] ?: $part[1];
}
}
}
}
else
{
$bodyPart = CMailMessage::decodeMessageBody($header, $body, $charset);
if (!$bodyPart['FILENAME'] && strpos(strtolower($bodyPart['CONTENT-TYPE']), 'text/') === 0)
{
if (strtolower($bodyPart['CONTENT-TYPE']) == 'text/html')
{
$htmlBody = $bodyPart['BODY'];
$textBody = html_entity_decode(htmlToTxt($bodyPart['BODY']), ENT_QUOTES | ENT_HTML401, $charset);
}
else
{
$textBody = $bodyPart['BODY'];
}
}
else
{
$parts[] = $bodyPart;
}
}
return array($header, $htmlBody, $textBody, $parts);
}
function AddMessage($mailbox_id, $message, $charset, $params = array())
{
global $DB;
list($obHeader, $message_body_html, $message_body, $arMessageParts) = CMailMessage::parseMessage($message, $charset);
$arFields = array(
"MAILBOX_ID" => $mailbox_id,
"HEADER" => $obHeader->strHeader,
"FIELD_DATE_ORIGINAL" => $obHeader->GetHeader("DATE"),
"NEW_MESSAGE" => "Y",
"FIELD_FROM" => $obHeader->GetHeader("FROM"),
"FIELD_REPLY_TO" => $obHeader->GetHeader("REPLY-TO"),
"FIELD_TO" => $obHeader->GetHeader("TO"),
"FIELD_CC" => $obHeader->GetHeader("CC"),
"FIELD_BCC" => ($obHeader->GetHeader('X-Original-Rcpt-to')!=''?$obHeader->GetHeader('X-Original-Rcpt-to').($obHeader->GetHeader("BCC")!=''?', ':''):'').$obHeader->GetHeader("BCC"),
"MSG_ID" => trim($obHeader->GetHeader("MESSAGE-ID"), " <>"),
"IN_REPLY_TO" => trim($obHeader->GetHeader("IN-REPLY-TO"), " <>"),
"FIELD_PRIORITY" => IntVal($obHeader->GetHeader("X-PRIORITY")),
"MESSAGE_SIZE" => strlen($message),
"SUBJECT" => $obHeader->GetHeader("SUBJECT"),
"BODY" => rtrim($message_body)
);
if(COption::GetOptionString("mail", "save_src", B_MAIL_SAVE_SRC)=="Y")
$arFields["FULL_TEXT"] = $message;
$forSpamTest = sprintf('%s %s', $arFields['HEADER'], $message_body_html ?: $message_body);
$arFields["SPAM"] = "?";
if(COption::GetOptionString("mail", "spam_check", B_MAIL_CHECK_SPAM)=="Y")
{
$arSpam = \CMailFilter::getSpamRating($forSpamTest);
$arFields["SPAM_RATING"] = $arSpam["RATING"];
$arFields["SPAM_WORDS"] = $arSpam["WORDS"];
$arFields["SPAM_LAST_RESULT"] = "Y";
}
// @TODO: MAX_ALLOWED_PACKET
$arFields['SEARCH_CONTENT'] = \Bitrix\Mail\Helper\Message::prepareSearchContent($arFields);
$arFields['INDEX_VERSION'] = \Bitrix\Mail\Helper\MessageIndexStepper::INDEX_VERSION;
if(isset($params['trackable']) && $params['trackable'])
{
$arFields['OPTIONS']['trackable'] = true;
}
if ($message_id = \CMailMessage::add($arFields))
{
$arFields['ID'] = $message_id;
$arFields['FOR_SPAM_TEST'] = $forSpamTest;
\CMailLog::addMessage(array(
'MAILBOX_ID' => $mailbox_id,
'MESSAGE_ID' => $message_id,
'STATUS_GOOD' => 'Y',
'LOG_TYPE' => 'NEW_MESSAGE',
'MESSAGE' => sprintf(
'%s (%s)%s', $arFields['SUBJECT'], $arFields['MESSAGE_SIZE'],
\Bitrix\Main\Config\Option::get('mail', 'spam_check', B_MAIL_CHECK_SPAM) == 'Y'
? sprintf(' [%.3f]', $arFields['SPAM_RATING']) : ''
),
));
$DB->query(sprintf(
'INSERT INTO b_mail_message_closure (MESSAGE_ID, PARENT_ID) VALUES (%1$u, %1$u)',
$message_id
));
if ($arFields['IN_REPLY_TO'])
{
$DB->query(sprintf(
"INSERT INTO b_mail_message_closure (MESSAGE_ID, PARENT_ID)
(
SELECT DISTINCT %u, C.PARENT_ID
FROM b_mail_message M INNER JOIN b_mail_message_closure C ON M.ID = C.MESSAGE_ID
WHERE M.MAILBOX_ID = %u AND M.MSG_ID = '%s'
)",
$message_id,
$mailbox_id,
$DB->forSql($arFields['IN_REPLY_TO'])
));
}
if ($arFields['MSG_ID'])
{
$DB->query(sprintf(
"INSERT IGNORE INTO b_mail_message_closure (MESSAGE_ID, PARENT_ID)
(
SELECT DISTINCT C.MESSAGE_ID, P.PARENT_ID
FROM b_mail_message M
INNER JOIN b_mail_message_closure C ON M.ID = C.PARENT_ID
INNER JOIN b_mail_message_closure P ON P.MESSAGE_ID = %u
WHERE M.MAILBOX_ID = %u AND M.IN_REPLY_TO = '%s'
)",
$message_id,
$mailbox_id,
$DB->forSql($arFields['MSG_ID'])
));
}
$mailbox = Bitrix\Mail\MailboxTable::getList(array(
'select' => array('ID', 'USER_ID'),
'filter' => array('ID' => $mailbox_id, 'ACTIVE' => 'Y'),
))->fetch();
if ($mailbox['USER_ID'] > 0)
{
\Bitrix\Mail\Internals\MailContactTable::addContactsBatch(array_merge(
MailContact::getContactsData($arFields['FIELD_TO'], $mailbox['USER_ID'], \Bitrix\Mail\Internals\MailContactTable::ADDED_TYPE_TO),
MailContact::getContactsData($arFields['FIELD_FROM'], $mailbox['USER_ID'], \Bitrix\Mail\Internals\MailContactTable::ADDED_TYPE_FROM),
MailContact::getContactsData($arFields['FIELD_CC'], $mailbox['USER_ID'], \Bitrix\Mail\Internals\MailContactTable::ADDED_TYPE_CC),
MailContact::getContactsData($arFields['FIELD_REPLY_TO'], $mailbox['USER_ID'], \Bitrix\Mail\Internals\MailContactTable::ADDED_TYPE_REPLY_TO),
MailContact::getContactsData($arFields['FIELD_BCC'], $mailbox['USER_ID'], \Bitrix\Mail\Internals\MailContactTable::ADDED_TYPE_BCC)
));
}
$atchCnt = 0;
if (\Bitrix\Main\Config\Option::get('mail', 'save_attachments', B_MAIL_SAVE_ATTACHMENTS) == 'Y')
{
foreach ($arMessageParts as $i => $part)
{
$attachFields = array(
'MESSAGE_ID' => $message_id,
'FILE_NAME' => $part['FILENAME'],
'CONTENT_TYPE' => $part['CONTENT-TYPE'],
'FILE_DATA' => $part['BODY'],
'CONTENT_ID' => $part['CONTENT-ID'],
);
$arMessageParts[$i]['ATTACHMENT-ID'] = \CMailMessage::addAttachment($attachFields);
if (!$arMessageParts[$i]['ATTACHMENT-ID'])
{
\CMailMessage::delete($message_id);
return false;
}
$atchCnt++;
}
}
$arFields['ATTACHMENTS'] = $atchCnt;
if (is_set($arFields, 'FIELD_DATE_ORIGINAL') && !is_set($arFields, 'FIELD_DATE'))
{
$date = preg_replace('/(?<=[\s\d])UT$/i', '+0000', $arFields['FIELD_DATE_ORIGINAL']);
$arFields['FIELD_DATE'] = $DB->formatDate(
date('d.m.Y H:i:s', strtotime($date) + \CTimeZone::getOffset()),
'DD.MM.YYYY HH:MI:SS', \CLang::getDateFormat('FULL')
);
}
$arFields['IS_OUTCOME'] = !empty($params['outcome']);
$arFields['IS_SEEN'] = !empty($params['seen']);
$arFields['MSG_HASH'] = $params['hash'];
if ($message_body_html)
{
$msg = array(
'html' => $message_body_html,
'attachments' => array(),
);
foreach ($arMessageParts as $part)
{
$msg['attachments'][] = array(
'contentId' => $part['CONTENT-ID'],
'uniqueId' => sprintf('attachment_%u', $part['ATTACHMENT-ID']),
);
}
$arFields['BODY_BB'] = \Bitrix\Mail\Message::parseMessage($msg);
$msg = preg_replace('/<!--.*?-->/is', '', $message_body_html);
$msg = preg_replace('/<script[^>]*>.*?<\/script>/is', '', $msg);
$msg = preg_replace('/<title[^>]*>.*?<\/title>/is', '', $msg);
$sanitizer = new \CBXSanitizer();
$sanitizer->setLevel(\CBXSanitizer::SECURE_LEVEL_LOW);
$sanitizer->applyHtmlSpecChars(false);
$sanitizer->addTags(array('style' => array()));
$arFields['BODY_HTML'] = $sanitizer->sanitizeHtml($msg);
foreach ($arMessageParts as $part)
{
$arFields['BODY_HTML'] = preg_replace(
sprintf('/<img([^>]+)src\s*=\s*(\'|\")?\s*(http:\/\/cid:%s)\s*\2([^>]*)>/is', preg_quote($part['CONTENT-ID'], '/')),
sprintf('<img\1src="aid:%u"\4>', $part['ATTACHMENT-ID']),
$arFields['BODY_HTML']
);
}
\CMailMessage::update($message_id, array('BODY_HTML' => $arFields['BODY_HTML']));
}
\CMailFilter::filter($arFields, 'R');
}
return $message_id;
}
function Add($arFields)
{
global $DB;
if(is_set($arFields, "NEW_MESSAGE") && $arFields["NEW_MESSAGE"]!="N")
$arFields["NEW_MESSAGE"]="Y";
if(is_set($arFields, "FULL_TEXT") && !is_set($arFields, "MESSAGE_SIZE"))
$arFields["MESSAGE_SIZE"] = strlen($arFields["FULL_TEXT"]);
if(!is_set($arFields, "DATE_INSERT"))
$arFields["~DATE_INSERT"] = $DB->GetNowFunction();
if(is_set($arFields, "FIELD_DATE_ORIGINAL") && !is_set($arFields, "FIELD_DATE"))
{
$date = preg_replace('/(?<=[\s\d])UT$/i', '+0000', $arFields['FIELD_DATE_ORIGINAL']);
$arFields['FIELD_DATE'] = $DB->formatDate(
date('d.m.Y H:i:s', strtotime($date) + CTimeZone::getOffset()),
'DD.MM.YYYY HH:MI:SS', CLang::getDateFormat('FULL')
);
}
if (array_key_exists('SUBJECT', $arFields))
{
$arFields['SUBJECT'] = strval(substr($arFields['SUBJECT'], 0, 255));
}
if (array_key_exists('OPTIONS', $arFields))
{
$arFields['OPTIONS'] = serialize($arFields['OPTIONS']);
}
$ID = $DB->Add("b_mail_message", $arFields, Array("FULL_TEXT", "HEADER", "BODY", "FOR_SPAM_TEST"));
return $ID;
}
function Update($ID, $arFields)
{
global $DB;
$ID = Intval($ID);
if(is_set($arFields, "FIELD_DATE_ORIGINAL") && !is_set($arFields, "FIELD_DATE"))
{
$date = preg_replace('/(?<=[\s\d])UT$/i', '+0000', $arFields['FIELD_DATE_ORIGINAL']);
$arFields['FIELD_DATE'] = $DB->formatDate(
date('d.m.Y H:i:s', strtotime($date) + CTimeZone::getOffset()),
'DD.MM.YYYY HH:MI:SS', CLang::getDateFormat('FULL')
);
}
if (array_key_exists('SUBJECT', $arFields))
{
$arFields['SUBJECT'] = strval(substr($arFields['SUBJECT'], 0, 255));
}
if (array_key_exists('OPTIONS', $arFields))
{
$arFields['OPTIONS'] = serialize($arFields['OPTIONS']);
}
$strUpdate = $DB->PrepareUpdate("b_mail_message", $arFields);
$strSql = "UPDATE b_mail_message SET ".$strUpdate." WHERE ID=".$ID;
$DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
return true;
}
public static function Delete($id)
{
global $DB;
$id = intval($id);
$res = $DB->query('SELECT FILE_ID FROM b_mail_msg_attachment WHERE MESSAGE_ID = '.$id);
while ($file = $res->fetch())
{
if ($file['FILE_ID'])
CFile::delete($file['FILE_ID']);
}
$strSql = "DELETE FROM b_mail_msg_attachment WHERE MESSAGE_ID=".$id;
$DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$strSql = "DELETE FROM b_mail_message WHERE ID=".$id;
$DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$DB->query(sprintf('DELETE FROM b_mail_message_closure WHERE MESSAGE_ID = %1$u OR PARENT_ID = %1$u', $id));
return true;
}
function MarkAsSpam($ID, $bIsSPAM = true, $arRow = false)
{
global $DB;
if(!is_array($arRow))
$res = $DB->Query("SELECT SPAM, HEADER, BODY_HTML, BODY, MAILBOX_ID FROM b_mail_message WHERE ID=".Intval($ID));
else
$ar = $arRow;
if(is_array($arRow) || $ar = $res->Fetch())
{
if (empty($ar['FOR_SPAM_TEST']))
{
$ar['FOR_SPAM_TEST'] = sprintf('%s %s', $ar['HEADER'], $ar['BODY_HTML'] ?: $ar['BODY'] );
}
if($bIsSPAM)
{
if($ar["SPAM"]!="Y")
{
if($ar["SPAM"]=="N")
CMailFilter::DeleteFromSpamBase($ar["FOR_SPAM_TEST"], false);
CMailFilter::MarkAsSpam($ar["FOR_SPAM_TEST"], true);
CMailMessage::Update($ID, Array("SPAM"=>"Y"));
CMailLog::AddMessage(
Array(
"MAILBOX_ID"=>$ar["MAILBOX_ID"],
"MESSAGE_ID"=>$ID,
"LOG_TYPE"=>"SPAM"
)
);
}
}
else
{
if($ar["SPAM"]!="N")
{
if($ar["SPAM"]=="Y")
CMailFilter::DeleteFromSpamBase($ar["FOR_SPAM_TEST"], true);
CMailFilter::MarkAsSpam($ar["FOR_SPAM_TEST"], false);
CMailMessage::Update($ID, Array("SPAM"=>"N"));
CMailLog::AddMessage(
Array(
"MAILBOX_ID"=>$ar["MAILBOX_ID"],
"MESSAGE_ID"=>$ID,
"LOG_TYPE"=>"NOTSPAM"
)
);
}
}
$DB->Query("UPDATE b_mail_message SET SPAM_LAST_RESULT='N' WHERE ID=".IntVal($ID));
}
}
function addAttachment($arFields)
{
global $DB;
$arFields['FILE_NAME'] = trim($arFields['FILE_NAME']);
$strSql = "SELECT ID, MAILBOX_ID, ATTACHMENTS FROM b_mail_message WHERE ID=".IntVal($arFields["MESSAGE_ID"]);
$dbr = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
if(!($dbr_arr = $dbr->Fetch()))
return false;
$n = IntVal($dbr_arr["ATTACHMENTS"])+1;
if (empty($arFields['FILE_NAME']))
{
$arFields['FILE_NAME'] = sprintf(
'%u-%u-%u.%s',
$dbr_arr['MAILBOX_ID'], $dbr_arr['ID'], $n,
strpos($arFields['CONTENT_TYPE'], 'message/') === 0 ? 'msg' : 'file'
);
}
if(is_set($arFields, "CONTENT_TYPE"))
$arFields["CONTENT_TYPE"] = strtolower($arFields["CONTENT_TYPE"]);
if(strpos($arFields["CONTENT_TYPE"], "image/")===0 && (!is_set($arFields, "IMAGE_WIDTH") || !is_set($arFields, "IMAGE_HEIGHT")) && is_set($arFields, "FILE_DATA"))
{
$filename = CTempFile::GetFileName(md5(uniqid("")).'.tmp');
CheckDirPath($filename);
if(file_put_contents($filename, $arFields["FILE_DATA"]) !== false)
{
$img_arr = CFile::GetImageSize($filename);
$arFields["IMAGE_WIDTH"] = $img_arr? $img_arr[0]: 0;
$arFields["IMAGE_HEIGHT"] = $img_arr? $img_arr[1]: 0;
}
}
if(is_set($arFields, "FILE_DATA") && !is_set($arFields, "FILE_SIZE"))
$arFields["FILE_SIZE"] = CUtil::BinStrlen($arFields["FILE_DATA"]);
$file = array(
'name' => md5($arFields['FILE_NAME']),
'size' => $arFields['FILE_SIZE'],
'type' => $arFields['CONTENT_TYPE'],
'content' => $arFields['FILE_DATA'],
'MODULE_ID' => 'mail'
);
if (!($file_id = CFile::saveFile($file, 'mail/attachment')))
{
\CMail::option('attachment_failure', true);
return false;
}
\CMail::option('attachment_failure', false);
unset($arFields['FILE_DATA']);
$arFields['FILE_ID'] = $file_id;
$ID = $DB->add('b_mail_msg_attachment', $arFields);
if ($ID > 0)
{
$strSql = 'UPDATE b_mail_message SET ATTACHMENTS = ' . $n . ' WHERE ID = ' . intval($arFields['MESSAGE_ID']);
$DB->query($strSql, false, 'File: '.__FILE__.'<br>Line: '.__LINE__);
\Bitrix\Mail\Helper\Attachment\Storage::registerAttachment(array(
'FILE_ID' => $arFields['FILE_ID'],
'FILE_NAME' => $arFields['FILE_NAME'],
'FILE_SIZE' => $arFields['FILE_SIZE'],
));
}
return $ID;
}
}
class _CMailAttachmentDBRes extends CDBResult
{
function __construct($res)
{
parent::__construct($res);
}
function fetch()
{
if (($res = parent::fetch()) && $res['FILE_ID'] > 0)
{
if ($file = \CFile::makeFileArray($res['FILE_ID']))
$res['FILE_DATA'] = file_get_contents($file['tmp_name']);
}
return $res;
}
}
class CMailAttachment
{
function GetList($arOrder=Array(), $arFilter=Array())
{
global $DB;
$strSql =
"SELECT * ".
"FROM b_mail_msg_attachment MA ";
$arSqlSearch = Array();
foreach ($arFilter as $key => $val)
{
$res = CMailUtil::MkOperationFilter($key);
$key = strtoupper($res["FIELD"]);
$cOperationType = $res["OPERATION"];
if($cOperationType == "?")
{
if (strlen($val)<=0) continue;
switch($key)
{
case "ID":
case "MESSAGE_ID":
case "FILE_SIZE":
case "IMAGE_WIDTH":
case "IMAGE_HEIGHT":
$arSqlSearch[] = GetFilterQuery("MA.".$key, $val, "N");
break;
case "FILE_NAME":
case "FILE_DATA":
$arSqlSearch[] = GetFilterQuery("MA.".$key, $val);
break;
case "CONTENT_TYPE":
$arSqlSearch[] = GetFilterQuery("MA.".$key, $val, "Y", array("/"));
break;
}
}
else
{
switch($key)
{
case "ID":
case "MESSAGE_ID":
case "FILE_SIZE":
case "IMAGE_WIDTH":
case "IMAGE_HEIGHT":
$arSqlSearch[] = CMailUtil::FilterCreate("MA.".$key, $val, "number", $cOperationType);
break;
case "FILE_NAME":
case "CONTENT_TYPE":
case "FILE_DATA":
$arSqlSearch[] = CMailUtil::FilterCreate("MA.".$key, $val, "string", $cOperationType);
break;
}
}
}
$is_filtered = false;
$strSqlSearch = "";
for($i = 0, $n = count($arSqlSearch); $i < $n; $i++)
{
if(strlen($arSqlSearch[$i])>0)
{
$strSqlSearch .= " AND (".$arSqlSearch[$i].") ";
$is_filtered = true;
}
}
$arSqlOrder = Array();
foreach($arOrder as $by=>$order)
{
$by = strtolower($by);
$order = strtolower($order);
if ($order!="asc")
$order = "desc".(strtoupper($DB->type)=="ORACLE"?" NULLS LAST":"");
else
$order = "asc".(strtoupper($DB->type)=="ORACLE"?" NULLS FIRST":"");
if ($by == "message_id") $arSqlOrder[] = " MA.MESSAGE_ID ".$order." ";
elseif ($by == "file_name") $arSqlOrder[] = " MA.FILE_NAME ".$order." ";
elseif ($by == "file_size") $arSqlOrder[] = " MA.FILE_SIZE ".$order." ";
elseif ($by == "content_type") $arSqlOrder[] = " MA.CONTENT_TYPE ".$order." ";
elseif ($by == "image_width") $arSqlOrder[] = " MA.IMAGE_WIDTH ".$order." ";
elseif ($by == "image_height") $arSqlOrder[] = " MA.IMAGE_HEIGHT ".$order." ";
else $arSqlOrder[] = " MA.ID ".$order." ";
}
$strSqlOrder = "";
$arSqlOrder = array_unique($arSqlOrder);
DelDuplicateSort($arSqlOrder);
for ($i = 0, $n = count($arSqlOrder); $i < $n; $i++)
{
if($i==0)
$strSqlOrder = " ORDER BY ";
else
$strSqlOrder .= ",";
$strSqlOrder .= $arSqlOrder[$i];
}
$strSql .= " WHERE 1=1 ".$strSqlSearch.$strSqlOrder;
//echo "<pre>".$strSql."</pre>";
$dbr = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$dbr = new _CMailAttachmentDBRes($dbr);
$dbr->is_filtered = $is_filtered;
return $dbr;
}
function GetByID($ID)
{
return CMailAttachment::GetList(Array(), Array("=ID"=>$ID));
}
function Delete($id)
{
global $DB;
$id = IntVal($id);
$res = $DB->query('SELECT FILE_ID FROM b_mail_msg_attachment WHERE MESSAGE_ID = '.$id);
while ($file = $res->fetch())
{
if ($file['FILE_ID'])
CFile::delete($file['FILE_ID']);
}
$strSql = "DELETE FROM b_mail_msg_attachment WHERE ID=".$id;
$DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
}
public static function getContents($attachment)
{
if (!is_array($attachment))
{
if ($res = CMailAttachment::getByID($attachment))
$attachment = $res->fetch();
}
if (is_array($attachment))
{
if (!empty($attachment['FILE_DATA']))
return $attachment['FILE_DATA'];
if ($attachment['FILE_ID'] > 0)
{
if ($file = \CFile::makeFileArray($attachment['FILE_ID']))
return file_get_contents($file['tmp_name']);
}
}
return false;
}
}
class CAllMailUtil
{
public static function convertCharset($str, $from, $to)
{
if (!trim($str))
return $str;
$from = trim(strtolower($from));
$to = trim(strtolower($to));
$escape = function ($matches)
{
return isset($matches[2]) ? '?' : $matches[1];
};
if ($from != $to)
{
if (in_array($from, array('utf-8', 'utf8')))
{
// escape all invalid (rfc-3629) utf-8 characters
$str = preg_replace_callback('/
([\x00-\x7F]+
|[\xC2-\xDF][\x80-\xBF]
|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]
|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})
|([\x80-\xFF])
/x', $escape, $str);
}
if ($result = Bitrix\Main\Text\Encoding::convertEncoding($str, $from, $to, $error))
$str = $result;
else
addMessage2Log(sprintf('Failed to convert email part. (%s -> %s : %s)', $from, $to, $error));
}
if (in_array($to, array('utf-8', 'utf8')))
{
// escape invalid (rfc-3629) and 4-bytes utf-8 characters
$str = preg_replace_callback('/
([\x00-\x7F]+
|[\xC2-\xDF][\x80-\xBF]
|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF])
|([\x80-\xFF])
/x', $escape, $str);
}
return $str;
}
public static function uue_decode($str)
{
preg_match("/begin [0-7]{3} .+?\r?\n(.+)?\r?\nend/i", $str, $reg);
$str = $reg[1];
$res = '';
$str = preg_split("/\r?\n/", trim($str));
$strlen = count($str);
for ($i = 0; $i < $strlen; $i++)
{
$pos = 1;
$d = 0;
$len= (int)(((ord(substr($str[$i],0,1)) -32) - ' ') & 077);
while (($d + 3 <= $len) AND ($pos + 4 <= strlen($str[$i])))
{
$c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
$c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
$c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20);
$c3 = (ord(substr($str[$i],$pos+3,1)) ^ 0x20);
$res .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4)).
chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2)).
chr(((($c2 - ' ') & 077) << 6) | (($c3 - ' ') & 077));
$pos += 4;
$d += 3;
}
if (($d + 2 <= $len) && ($pos + 3 <= strlen($str[$i])))
{
$c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
$c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
$c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20);
$res .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4)).
chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2));
$pos += 3;
$d += 2;
}
if (($d + 1 <= $len) && ($pos + 2 <= strlen($str[$i])))
{
$c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
$c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
$res .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));
}
}
return $res;
}
function MkOperationFilter($key)
{
if(substr($key, 0, 1)=="!")
{
$key = substr($key, 1);
$cOperationType = "N";
}
elseif(substr($key, 0, 2)==">=")
{
$key = substr($key, 2);
$cOperationType = "GE";
}
elseif(substr($key, 0, 1)==">")
{
$key = substr($key, 1);
$cOperationType = "G";
}
elseif(substr($key, 0, 2)=="<=")
{
$key = substr($key, 2);
$cOperationType = "LE";
}
elseif(substr($key, 0, 1)=="<")
{
$key = substr($key, 1);
$cOperationType = "L";
}
elseif(substr($key, 0, 1)=="=")
{
$key = substr($key, 1);
$cOperationType = "E";
}
else
$cOperationType = "?";
return Array("FIELD"=>$key, "OPERATION"=>$cOperationType);
}
function FilterCreate($fname, $vals, $type, $cOperationType=false, $bSkipEmpty = true)
{
return CMailUtil::FilterCreateEx($fname, $vals, $type, $bFullJoin, $cOperationType, $bSkipEmpty);
}
function FilterCreateEx($fname, $vals, $type, &$bFullJoin, $cOperationType=false, $bSkipEmpty = true)
{
global $DB;
if(!is_array($vals))
$vals=Array($vals);
if(count($vals)<1)
return "";
if(is_bool($cOperationType))
{
if($cOperationType===true)
$cOperationType = "N";
else
$cOperationType = "E";
}
if($cOperationType=="G")
$strOperation = ">";
elseif($cOperationType=="GE")
$strOperation = ">=";
elseif($cOperationType=="LE")
$strOperation = "<=";
elseif($cOperationType=="L")
$strOperation = "<";
else
$strOperation = "=";
$bFullJoin = false;
$bWasLeftJoin = false;
$res = Array();
for($i = 0, $n = count($vals); $i < $n; $i++)
{
$val = $vals[$i];
if(!$bSkipEmpty || strlen($val)>0 || (is_bool($val) && $val===false))
{
switch ($type)
{
case "string_equal":
if(strlen($val)<=0)
$res[] = ($cOperationType=="N"?"NOT":"")."(".$fname." IS NULL OR ".$DB->Length($fname)."<=0)";
else
$res[] = ($cOperationType=="N"?" ".$fname." IS NULL OR NOT ":"")."(".CIBlock::_Upper($fname).$strOperation.CIBlock::_Upper("'".$DB->ForSql($val)."'").")";
break;
case "string":
if(strlen($val)<=0)
$res[] = ($cOperationType=="N"?"NOT":"")."(".$fname." IS NULL OR ".$DB->Length($fname)."<=0)";
else
if($strOperation=="=")
$res[] = ($cOperationType=="N"?" ".$fname." IS NULL OR NOT ":"")."(".(strtoupper($DB->type)=="ORACLE"?CIBlock::_Upper($fname)." LIKE ".CIBlock::_Upper("'".$DB->ForSqlLike($val)."'")." ESCAPE '\\'" : $fname." ".($strOperation=="="?"LIKE":$strOperation)." '".$DB->ForSqlLike($val)."'").")";
else
$res[] = ($cOperationType=="N"?" ".$fname." IS NULL OR NOT ":"")."(".(strtoupper($DB->type)=="ORACLE"?CIBlock::_Upper($fname)." ".$strOperation." ".CIBlock::_Upper("'".$DB->ForSql($val)."'")." " : $fname." ".$strOperation." '".$DB->ForSql($val)."'").")";
break;
case "date":
if(strlen($val)<=0)
$res[] = ($cOperationType=="N"?"NOT":"")."(".$fname." IS NULL)";
else
$res[] = ($cOperationType=="N"?" ".$fname." IS NULL OR NOT ":"")."(".$fname." ".$strOperation." ".$DB->CharToDateFunction($DB->ForSql($val), "FULL").")";
break;
case "number":
if(strlen($val)<=0)
$res[] = ($cOperationType=="N"?"NOT":"")."(".$fname." IS NULL)";
else
$res[] = ($cOperationType=="N"?" ".$fname." IS NULL OR NOT ":"")."(".$fname." ".$strOperation." '".DoubleVal($val)."')";
break;
case "number_above":
if(strlen($val)<=0)
$res[] = ($cOperationType=="N"?"NOT":"")."(".$fname." IS NULL)";
else
$res[] = ($cOperationType=="N"?" ".$fname." IS NULL OR NOT ":"")."(".$fname." ".$strOperation." '".$DB->ForSql($val)."')";
break;
}
// INNER JOIN on such conditions
if(strlen($val)>0 && $cOperationType!="N")
$bFullJoin = true;
else
$bWasLeftJoin = true;
}
}
$strResult = "";
for($i = 0, $n = count($res); $i < $n; $i++)
{
if($i>0)
$strResult .= ($cOperationType=="N"?" AND ":" OR ");
$strResult .= "(".$res[$i].")";
}
if($strResult!="")
$strResult = "(".$strResult.")";
if($bFullJoin && $bWasLeftJoin && $cOperationType!="N")
$bFullJoin = false;
return $strResult;
}
function ByteXOR($a,$b,$l)
{
$c="";
for($i=0; $i<$l; $i++)
$c .= $a[$i]^$b[$i];
return($c);
}
function BinMD5($val)
{
return(pack("H*",md5($val)));
}
public static function Decrypt($str, $key=false)
{
$res = '';
if($key===false)
$key = COption::GetOptionString("main", "pwdhashadd", "");
$key1 = CMailUtil::BinMD5($key);
$str = base64_decode($str);
while (\CUtil::binStrlen($str) > 0)
{
$m = CUtil::BinSubstr($str, 0, 16);
$str = CUtil::BinSubstr($str, 16);
$m = CMailUtil::ByteXOR($m, $key1, 16);
$res .= $m;
$key1 = CMailUtil::BinMD5($key.$key1.$m);
}
return $res;
}
public static function Crypt($str, $key=false)
{
$res = '';
if($key===false)
$key = COption::GetOptionString("main", "pwdhashadd", "");
$key1 = CMailUtil::BinMD5($key);
while (\CUtil::binStrlen($str) > 0)
{
$m = CUtil::BinSubstr($str, 0, 16);
$str = CUtil::BinSubstr($str, 16);
$res .= CMailUtil::ByteXOR($m, $key1, 16);
$key1 = CMailUtil::BinMD5($key.$key1.$m);
}
return(base64_encode($res));
}
function ExtractAllMailAddresses($emails)
{
$result = array();
$arEMails = explode(",", $emails);
foreach($arEMails as $mail)
{
$result[] = CMailUtil::ExtractMailAddress($mail);
}
return $result;
}
function ExtractMailAddress($email)
{
$email = trim($email);
if(($pos = strpos($email, "<"))!==false)
$email = substr($email, $pos+1);
if(($pos = strpos($email, ">"))!==false)
$email = substr($email, 0, $pos);
return strtolower($email);
}
public static function checkImapMailbox($server, $port, $use_tls, $login, $password, &$error)
{
$use_tls = is_string($use_tls) ? $use_tls : ($use_tls ? 'Y' : 'N');
$imap = new \Bitrix\Mail\Imap(
$server, $port,
$use_tls == 'Y' || $use_tls == 'S',
$use_tls == 'Y',
$login, $password,
'UTF-8'
);
if (($unseen = $imap->getUnseen('INBOX', $error)) === false)
return (-1);
$error = false;
return $unseen;
}
}
global $BX_MAIL_FILTER_CACHE, $BX_MAIL_SPAM_CNT;
$BX_MAIL_FILTER_CACHE = Array();
$BX_MAIL_SPAM_CNT = Array();
class CMailFilter
{
public static function GetList($arOrder=Array(), $arFilter=Array(), $bCnt=false)
{
global $DB;
$strSql =
"SELECT ".
($bCnt
?
" COUNT('x') as CNT "
:
" MF.*, MB.NAME as MAILBOX_NAME, MB.ID as MAILBOX_ID, MB.SERVER_TYPE as MAILBOX_TYPE, MB.DOMAINS as DOMAINS, ".
" ".$DB->DateToCharFunction("MF.TIMESTAMP_X")." as TIMESTAMP_X "
).
" ".
"FROM b_mail_mailbox MB ".($arFilter["EMPTY"]=="Y"?"LEFT":"INNER")." JOIN b_mail_filter MF ON MB.ID=MF.MAILBOX_ID ";
if(!is_array($arFilter))
$arFilter = Array();
$arSqlSearch = Array();
$filter_keys = array_keys($arFilter);
for($i = 0, $n = count($filter_keys); $i < $n; $i++)
{
$val = $arFilter[$filter_keys[$i]];
if (strlen($val)<=0) continue;
$key = strtoupper($filter_keys[$i]);
switch($key)
{
case "NAME":
case "PHP_CONDITION":
case "ACTION_PHP":
$arSqlSearch[] = GetFilterQuery("MF.".$key, $val);
break;
case "SERVER_TYPE":
$arSqlSearch[] = GetFilterQuery("MB.".$key, $val, "N");
break;
case "ID":
case "ACTION_TYPE":
case "MAILBOX_ID":
case "PARENT_FILTER_ID":
case "SORT":
case "WHEN_MAIL_RECEIVED":
case "WHEN_MANUALLY_RUN":
case "ACTION_STOP_EXEC":
case "ACTION_DELETE_MESSAGE":
case "ACTION_READ":
case "ACTIVE":
$arSqlSearch[] = GetFilterQuery("MF.".$key, $val, "N");
break;
}
}
$is_filtered = false;
$strSqlSearch = "";
for($i = 0, $n = count($arSqlSearch); $i < $n; $i++)
{
if(strlen($arSqlSearch[$i])>0)
{
$strSqlSearch .= " AND (".$arSqlSearch[$i].") ";
$is_filtered = true;
}
}
$arSqlOrder = Array();
foreach($arOrder as $by=>$order)
{
$order = strtolower($order);
if ($order!="asc")
$order = "desc".(strtoupper($DB->type)=="ORACLE"?" NULLS LAST":"");
else
$order = "asc".(strtoupper($DB->type)=="ORACLE"?" NULLS FIRST":"");
switch(strtoupper($by))
{
case "TIMESTAMP_X":
case "MAILBOX_ID":
case "ACTIVE":
case "NAME":
case "SORT":
case "PARENT_FILTER_ID":
case "WHEN_MAIL_RECEIVED":
case "WHEN_MANUALLY_RUN":
case "ACTION_STOP_EXEC":
case "ACTION_DELETE_MESSAGE":
case "ACTION_READ":
$arSqlOrder[] = " MF.".$by." ".$order." ";
break;
case "MAILBOX_NAME":
$arSqlOrder[] = " MB.NAME ".$order." ";
$arSqlOrder[] = " MF.ID ".$order." ";
break;
default:
$arSqlOrder[] = " MF.ID ".$order." ";
}
}
$strSqlOrder = "";
$arSqlOrder = array_unique($arSqlOrder);
DelDuplicateSort($arSqlOrder);
for ($i = 0, $n = count($arSqlOrder); $i < $n; $i++)
{
if($i==0)
$strSqlOrder = " ORDER BY ";
else
$strSqlOrder .= ",";
$strSqlOrder .= $arSqlOrder[$i];
}
$strSql .= " WHERE 1=1 ".$strSqlSearch.$strSqlOrder;
$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$res->is_filtered = $is_filtered;
return $res;
}
function GetByID($ID)
{
global $DB;
return CMailFilter::GetList(Array(), Array("ID"=>$ID));
}
function CheckPHP($code, $field_name)
{
return true; // not work - E_CODE_ERROR
global $php_errormsg;
ini_set("track_errors", "on");
$php_errormsg_prev = $php_errormsg;
ob_start();
error_reporting(0);
@eval($code);
ob_end_clean();
if($php_errormsg != "")
CMailError::SetError("B_MAIL_ERR_PHP", GetMessage("MAIL_CL_ERR_IN_PHP").$field_name.". (".$php_errormsg.")");
$php_errormsg = $php_errormsg_prev;
ini_set("track_errors", $prev);
}
function CheckFields($arFields, $ID=false)
{
$err_cnt = CMailError::ErrCount();
$arMsg = Array();
if(is_set($arFields, "NAME") && strlen($arFields["NAME"])<1)
{
CMailError::SetError("B_MAIL_ERR_NAME", GetMessage("MAIL_CL_ERR_NAME")." \"".GetMessage("MAIL_CL_NAME")."\"");
$arMsg[] = array("id"=>"NAME", "text"=> GetMessage("MAIL_CL_ERR_NAME")." \"".GetMessage("MAIL_CL_NAME")."\"");
}
if(is_set($arFields, "PHP_CONDITION") && strlen(trim($arFields["PHP_CONDITION"]))>0)
{
if (!CMailFilter::CheckPHP($arFields["PHP_CONDITION"], GetMessage("MAIL_CL_PHP_COND")))
$arMsg[] = array("id"=>"PHP_CONDITION", "text"=> GetMessage("MAIL_CL_ERR_IN_PHP").GetMessage("MAIL_CL_PHP_COND"));
}
if(is_set($arFields, "ACTION_PHP") && strlen(trim($arFields["ACTION_PHP"]))>0)
{
if (!CMailFilter::CheckPHP($arFields["ACTION_PHP"], GetMessage("MAIL_CL_PHP_ACT")))
$arMsg[] = array("id"=>"ACTION_PHP", "text"=> GetMessage("MAIL_CL_ERR_IN_PHP").GetMessage("MAIL_CL_PHP_ACT"));
}
if(is_set($arFields, "MAILBOX_ID"))
{
$r = CMailBox::GetByID($arFields["MAILBOX_ID"]);
if(!$r->Fetch())
{
CMailError::SetError("B_MAIL_ERR_BAD_MAILBOX", GetMessage("MAIL_CL_ERR_WRONG_MAILBOX"));
$arMsg[] = array("id"=>"MAILBOX_ID", "text"=> GetMessage("MAIL_CL_ERR_WRONG_MAILBOX"));
}
}
elseif($ID===false)
{
CMailError::SetError("B_MAIL_ERR_BAD_MAILBOX_NA", GetMessage("MAIL_CL_ERR_MAILBOX_NA"));
$arMsg[] = array("id"=>"MAILBOX_ID", "text"=> GetMessage("MAIL_CL_ERR_MAILBOX_NA"));
}
if(!empty($arMsg))
{
$e = new CAdminException($arMsg);
$GLOBALS["APPLICATION"]->ThrowException($e);
return false;
}
return true;
//return ($err_cnt == CMailError::ErrCount());
}
function Add($arFields)
{
global $DB;
if(is_set($arFields, "ACTIVE") && $arFields["ACTIVE"]!="Y")
$arFields["ACTIVE"]="N";
if(is_set($arFields, "ACTION_READ") && $arFields["ACTION_READ"]!="Y" && $arFields["ACTION_READ"]!="N")
$arFields["ACTION_READ"] = "-";
if(is_set($arFields, "ACTION_SPAM") && $arFields["ACTION_SPAM"]!="Y" && $arFields["ACTION_SPAM"]!="N")
$arFields["ACTION_SPAM"] = "-";
if(is_set($arFields, "ACTION_DELETE_MESSAGE") && $arFields["ACTION_DELETE_MESSAGE"]!="Y")
$arFields["ACTION_DELETE_MESSAGE"] ="N";
if(is_set($arFields, "ACTION_STOP_EXEC") && $arFields["ACTION_STOP_EXEC"]!="Y")
$arFields["ACTION_STOP_EXEC"] = "N";
if(!CMailFilter::CheckFields($arFields))
return false;
$ID = $DB->Add("b_mail_filter", $arFields, Array("PHP_CONDITION", "ACTION_PHP"));
if(is_set($arFields, "CONDITIONS"))
CMailFilterCondition::SetConditions($ID, $arFields["CONDITIONS"]);
CMailbox::SMTPReload();
return $ID;
}
function Update($ID, $arFields)
{
global $DB;
$ID = IntVal($ID);
if(is_set($arFields, "ACTIVE") && $arFields["ACTIVE"]!="Y")
$arFields["ACTIVE"]="N";
if(is_set($arFields, "WHEN_MAIL_RECEIVED") && $arFields["WHEN_MAIL_RECEIVED"]!="Y")
$arFields["WHEN_MAIL_RECEIVED"] = "N";
if(is_set($arFields, "WHEN_MANUALLY_RUN") && $arFields["WHEN_MANUALLY_RUN"]!="Y")
$arFields["WHEN_MANUALLY_RUN"] = "N";
if(is_set($arFields, "ACTION_READ") && $arFields["ACTION_READ"]!="Y" && $arFields["ACTION_READ"]!="N")
$arFields["ACTION_READ"] = "-";
if(is_set($arFields, "ACTION_SPAM") && $arFields["ACTION_SPAM"]!="Y" && $arFields["ACTION_SPAM"]!="N")
$arFields["ACTION_SPAM"] = "-";
if(is_set($arFields, "ACTION_DELETE_MESSAGE") && $arFields["ACTION_DELETE_MESSAGE"]!="Y")
$arFields["ACTION_DELETE_MESSAGE"] ="N";
if(is_set($arFields, "ACTION_STOP_EXEC") && $arFields["ACTION_STOP_EXEC"]!="Y")
$arFields["ACTION_STOP_EXEC"] = "N";
if(!CMailFilter::CheckFields($arFields, $ID))
return false;
$arUpdateBinds = array();
$strUpdate = $DB->PrepareUpdateBind("b_mail_filter", $arFields,"", false, $arUpdateBinds);
$strSql =
"UPDATE b_mail_filter SET ".
$strUpdate." ".
"WHERE ID=".$ID;
$arBinds = array();
foreach($arUpdateBinds as $field_id)
$arBinds[$field_id] = $arFields[$field_id];
$DB->QueryBind($strSql, $arBinds);
if(is_set($arFields, "CONDITIONS"))
CMailFilterCondition::SetConditions($ID, $arFields["CONDITIONS"]);
CMailbox::SMTPReload();
return true;
}
public static function Delete($ID)
{
global $DB;
$ID = IntVal($ID);
$dbr = CMailFilterCondition::GetList(Array(), Array("FILTER_ID"=>$ID));
while($r = $dbr->Fetch())
{
if(!CMailFilterCondition::Delete($r["ID"]))
return false;
}
$strSql = "DELETE FROM b_mail_filter WHERE ID=".$ID;
CMailbox::SMTPReload();
return $DB->Query($strSql, true);
}
function Filter($arFields, $event, $FILTER_ID=false, $PARENT_FILTER_ID = false)
{
global $BX_MAIL_FILTER_CACHE, $DB;
$PARENT_FILTER_ID = IntVal($PARENT_FILTER_ID);
$MAILBOX_ID = IntVal($arFields["MAILBOX_ID"]);
$MESSAGE_ID = IntVal($arFields["ID"]);
$cache_param = $MAILBOX_ID."|".$PARENT_FILTER_ID."|".$event."|".$FILTER_ID;
if(is_set($BX_MAIL_FILTER_CACHE, $cache_param))
{
$arFilterCond = $BX_MAIL_FILTER_CACHE[$cache_param]["CONDITIONS"];
$arFilter = $BX_MAIL_FILTER_CACHE[$cache_param]["FILTER"];
}
else
{
$strSqlAdd = "";
if($event=="R")
$strSqlAdd .= " AND (WHEN_MAIL_RECEIVED='Y')";
else
$strSqlAdd .= " AND (WHEN_MANUALLY_RUN='Y' ".(IntVal($FILTER_ID)>0?" AND f.ID='".IntVal($FILTER_ID)."'":"").")";
$strSql =
"SELECT f.*, c.*, f.ID, c.ID as CONDITION_ID
FROM b_mail_filter f LEFT JOIN b_mail_filter_cond c ON f.ID = c.FILTER_ID
WHERE (f.MAILBOX_ID = ".$MAILBOX_ID." OR MAILBOX_ID IS NULL)
AND f.ACTIVE = 'Y'
AND (f.PARENT_FILTER_ID = " . ($PARENT_FILTER_ID > 0 ? $PARENT_FILTER_ID : "'' OR f.PARENT_FILTER_ID IS NULL") . ")" .
$strSqlAdd."
ORDER BY f.SORT, f.ID";
$dbr = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$arFilter = Array();
$arFilterCond = Array();
$prev_ID = 0;
$arr_prev = false;
$arConds = Array();
while($arr = $dbr->Fetch())
{
$arFilter[$arr["ID"]] = $arr;
if($arr["CONDITION_ID"]>0)
{
if(!is_array($arFilterCond[$arr["ID"]]))
$arFilterCond[$arr["ID"]] = Array();
$arFilterCond[$arr["ID"]][] = $arr;
}
}
$BX_MAIL_FILTER_CACHE[$cache_param] = Array("FILTER"=>$arFilter, "CONDITIONS"=>$arFilterCond);
}
$arFieldsOriginal = $arFields;
foreach($arFilter as $filter_id=>$arFilterParams)
{
$arFields = $arFieldsOriginal;
$arFields["MAIL_FILTER"] = $arFilterParams;
$arAllConditions = $arFilterCond[$filter_id];
$bCondOK = true;
if(!is_array($arAllConditions))
$arAllConditions = Array();
foreach($arAllConditions as $k => $arCondition)
{
$bCondOK = false;
$type = $arCondition["TYPE"];
switch($type)
{
case "ALL":case "RECIPIENT":case "SENDER":
if($type=="ALL")
$arFields[$type] = $arFields["HEADER"]."\r\n".$arFields["BODY"];
elseif($type=="RECIPIENT")
$arFields[$type] = $arFields["FIELD_CC"]."\r\n".$arFields["FIELD_TO"]."\r\n".$arFields["FIELD_BCC"];
else
$arFields[$type] = $arFields["FIELD_FROM"]."\r\n".$arFields["FIELD_REPLY_TO"];
case "HEADER": case "FIELD_FROM": case "FIELD_REPLY_TO": case "FIELD_TO": case "FIELD_CC": case "SUBJECT": case "BODY":
$arStrings = explode("\n", $arCondition["STRINGS"]);
if($arCondition["COMPARE_TYPE"]=="NOT_EQUAL" || $arCondition["COMPARE_TYPE"]=="NOT_CONTAIN")
{
$bCondOK = true;
for($i = 0, $n = count($arStrings); $i < $n; $i++)
{
$str = strtoupper(Trim($arStrings[$i], "\r"));
switch($arCondition["COMPARE_TYPE"])
{
case "NOT_CONTAIN":
if(strlen($str)>0 && strpos(strtoupper($arFields[$type]), $str)!==false)
$bCondOK = false;
break;
case "NOT_EQUAL":
if($str==strtoupper($arFields[$type]))
$bCondOK = false;
break;
}
if(!$bCondOK)
break;
}
}
else
{
for($i = 0, $n = count($arStrings); $i < $n; $i++)
{
$str = strtoupper(Trim($arStrings[$i], "\r"));
switch($arCondition["COMPARE_TYPE"])
{
case "CONTAIN":
if(strlen($str)>0 && strpos(strtoupper($arFields[$type]), $str)!==false)
$bCondOK = true;
break;
case "EQUAL":
if($str==strtoupper($arFields[$type]))
$bCondOK = true;
break;
case "REGEXP":
if(preg_match("'".str_replace("'", "\'", $str)."'i", $arFields[$type]))
$bCondOK = true;
break;
}
if($bCondOK)
break;
}
}
break;
case "ATTACHMENT":
$db_att = CMailAttachment::GetList(Array(), Array("MESSAGE_ID"=>$arFields["ID"]));
$arStrings = explode("\n", $arCondition["STRINGS"]);
if($arCondition["COMPARE_TYPE"]=="NOT_EQUAL" || $arCondition["COMPARE_TYPE"]=="NOT_CONTAIN")
{
$bCondOK = true;
while($arr_att = $db_att->Fetch())
{
for($i = 0, $n = count($arStrings); $i < $n; $i++)
{
$str = strtoupper(Trim($arStrings[$i], "\r"));
switch($arCondition["COMPARE_TYPE"])
{
case "NOT_CONTAIN":
if(strlen($str)>0 && strpos(strtoupper($arr_att["FILE_NAME"]), $str)!==false)
$bCondOK = false;
break;
case "NOT_EQUAL":
if($str==strtoupper($arr_att["FILE_NAME"]))
$bCondOK = false;
break;
}
}
if(!$bCondOK)
break;
}
}
else
{
while($arr_att = $db_att->Fetch())
{
for($i = 0, $n = count($arStrings); $i < $n; $i++)
{
$str = strtoupper(Trim($arStrings[$i], "\r"));
switch($arCondition["COMPARE_TYPE"])
{
case "CONTAIN":
if(strlen($str)>0 && strpos(strtoupper($arr_att["FILE_NAME"]), $str)!==false)
$bCondOK = true;
break;
case "EQUAL":
if($str==strtoupper($arr_att["FILE_NAME"]))
$bCondOK = true;
break;
case "REGEXP":
if(preg_match("'".str_replace("'", "\'", $str)."'i", $arr_att["FILE_NAME"]))
$bCondOK = true;
break;
}
}
if($bCondOK)
break;
}
}
break;
} //switch
if(!$bCondOK)
break;
} //foreach($arAllConditions as $k => $arCondition)
if(!$bCondOK)
continue;
if($arFilterParams["SPAM_RATING"]>0)
{
$arFields["SPAM_RATING"] = CMailMessage::GetSpamRating($arFields["ID"], $arFields);
if($arFilterParams["SPAM_RATING_TYPE"]==">" && $arFields["SPAM_RATING"]<=$arFilterParams["SPAM_RATING"])
continue;
if($arFilterParams["SPAM_RATING_TYPE"]!=">" && $arFields["SPAM_RATING"]>=$arFilterParams["SPAM_RATING"])
continue;
}
if($arFilterParams["MESSAGE_SIZE"]>0)
{
$MESSAGE_SIZE = $arFields["MESSAGE_SIZE"];
if($arFilterParams["MESSAGE_SIZE_UNIT"]=="k")
$MESSAGE_SIZE = IntVal($MESSAGE_SIZE/1024);
elseif($arFilterParams["MESSAGE_SIZE_UNIT"]=="m")
$MESSAGE_SIZE = IntVal($MESSAGE_SIZE/1024/1024);
if($arFilterParams["MESSAGE_SIZE_TYPE"]==">" && $MESSAGE_SIZE<=$arFilterParams["MESSAGE_SIZE"])
continue;
if($arFilterParams["MESSAGE_SIZE_TYPE"]!=">" && $MESSAGE_SIZE>=$arFilterParams["MESSAGE_SIZE"])
continue;
}
if(strlen($arFilterParams["PHP_CONDITION"])>0)
if(!CMailFilter::DoPHPAction("php_cond_".$arFilterParams["ID"]."_", $arFilterParams["PHP_CONDITION"], $arFields))
continue;
$arModFilter = false;
if($arFilterParams["ACTION_TYPE"]!="")
{
$res = CMailFilter::GetFilterList($arFilterParams["ACTION_TYPE"]);
if($arModFilter = $res->Fetch())
{
if (
(is_array($arModFilter["CONDITION_FUNC"]) && count($arModFilter["CONDITION_FUNC"]) > 0) ||
strlen($arModFilter["CONDITION_FUNC"]) > 0
)
if(!call_user_func_array($arModFilter["CONDITION_FUNC"], Array(&$arFields, &$arFilterParams["ACTION_VARS"])))
continue;
}
}
CMailLog::AddMessage(
Array(
"MAILBOX_ID"=>$MAILBOX_ID,
"MESSAGE_ID"=>$MESSAGE_ID,
"FILTER_ID"=>$filter_id,
"STATUS_GOOD"=>"Y",
"LOG_TYPE"=>"FILTER_OK",
"MESSAGE"=>$event,
)
);
if($arModFilter)
if (
(is_array($arModFilter["ACTION_FUNC"]) && count($arModFilter["ACTION_FUNC"]) > 0) ||
strlen($arModFilter["ACTION_FUNC"]) > 0
)
call_user_func_array($arModFilter["ACTION_FUNC"], array(&$arFields, &$arFilterParams["ACTION_VARS"]));
if(strlen(Trim($arFilterParams["ACTION_PHP"]))>0)
{
$res = CMailFilter::DoPHPAction("php_act_".$arFilterParams["ID"]."_", $arFilterParams["ACTION_PHP"], $arFields);
CMailLog::AddMessage(
Array(
"MAILBOX_ID"=>$MAILBOX_ID,
"MESSAGE_ID"=>$MESSAGE_ID,
"FILTER_ID"=>$filter_id,
"LOG_TYPE"=>"DO_PHP",
"MESSAGE"=>""
)
);
}
if($arFilterParams["ACTION_SPAM"]=="Y" && $arFields["SPAM"]!="Y")
{
if($arFields["SPAM"]=="N")
CMailFilter::DeleteFromSpamBase($arFields["FOR_SPAM_TEST"], false);
CMailFilter::MarkAsSpam($arFields["FOR_SPAM_TEST"], true);
CMailMessage::Update($MESSAGE_ID, Array("SPAM"=>"Y"));
CMailLog::AddMessage(
Array(
"MAILBOX_ID"=>$MAILBOX_ID,
"MESSAGE_ID"=>$MESSAGE_ID,
"FILTER_ID"=>$filter_id,
"LOG_TYPE"=>"SPAM",
"MESSAGE"=>""
)
);
$arFields["SPAM"] = "Y";
}
elseif($arFilterParams["ACTION_SPAM"]=="N" && $arFields["SPAM"]!="N")
{
if($arFields["SPAM"]=="Y")
CMailFilter::DeleteFromSpamBase($arFields["FOR_SPAM_TEST"], true);
CMailFilter::MarkAsSpam($arFields["FOR_SPAM_TEST"], false);
CMailMessage::Update($MESSAGE_ID, Array("SPAM"=>"N"));
CMailLog::AddMessage(
Array(
"MAILBOX_ID"=>$MAILBOX_ID,
"MESSAGE_ID"=>$MESSAGE_ID,
"FILTER_ID"=>$filter_id,
"LOG_TYPE"=>"NOTSPAM",
"MESSAGE"=>""
)
);
$arFields["SPAM"] = "N";
}
if($arFilterParams["ACTION_READ"]=="Y" && $arFields["NEW_MESSAGE"]=="Y")
{
$arFields["NEW_MESSAGE"] = "N";
CMailMessage::Update($MESSAGE_ID, Array("NEW_MESSAGE"=>"N"));
}
elseif($arFilterParams["ACTION_READ"]=="N" && $arFields["NEW_MESSAGE"]!="Y")
{
$arFields["NEW_MESSAGE"] = "Y";
CMailMessage::Update($MESSAGE_ID, Array("NEW_MESSAGE"=>"Y"));
}
if($arFilterParams["ACTION_DELETE_MESSAGE"]=="Y")
{
CMailLog::AddMessage(
Array(
"MAILBOX_ID"=>$MAILBOX_ID,
"MESSAGE_ID"=>$MESSAGE_ID,
"FILTER_ID"=>$filter_id,
"STATUS_GOOD"=>"Y",
"LOG_TYPE"=>"MESSAGE_DELETED",
"MESSAGE"=>""
)
);
CMailMessage::Delete($MESSAGE_ID);
}
if($arFilterParams["ACTION_STOP_EXEC"]=="Y")
{
CMailLog::AddMessage(
Array(
"MAILBOX_ID"=>$MAILBOX_ID,
"MESSAGE_ID"=>$MESSAGE_ID,
"FILTER_ID"=>$filter_id,
"STATUS_GOOD"=>"Y",
"LOG_TYPE"=>"FILTER_STOP",
"MESSAGE"=>""
)
);
return true;
}
}
return true;
}
public static function FilterMessage($message_id, $event, $FILTER_ID=false)
{
$res = CMailMessage::GetByID($message_id);
if($arFields = $res->Fetch())
return CMailFilter::Filter($arFields, $event, $FILTER_ID);
return false;
}
function RecalcSpamRating()
{
global $DB;
$res = $DB->Query("SELECT ID, HEADER, BODY_HTML, BODY FROM b_mail_message WHERE SPAM_LAST_RESULT<>'N'");
while($arr = $res->Fetch())
{
$forSpamTest = sprintf('%s %s', $arr['HEADER'], $arr['BODY_HTML'] ?: $arr['BODY']);
$arSpam = CMailFilter::GetSpamRating($forSpamTest);
$DB->Query("UPDATE b_mail_message SET SPAM_RATING=".Round($arSpam["RATING"], 4).", SPAM_LAST_RESULT='Y', SPAM_WORDS='".$DB->ForSql($arSpam["WORDS"], 255)."' WHERE ID=".$arr["ID"]);
}
}
function GetSpamRating($message)
{
global $DB;
$arWords = CMailFilter::getWords($message, 1000);
if (empty($arWords))
return 0;
// for every word find Si
$arWords = array_map("md5", $arWords);
global $BX_MAIL_SPAM_CNT;
if(!is_set($BX_MAIL_SPAM_CNT, "G"))
{
$strSql = "SELECT MAX(GOOD_CNT) as G, MAX(BAD_CNT) as B FROM b_mail_spam_weight";
if($res = $DB->Query($strSql))
$BX_MAIL_SPAM_CNT = $res->Fetch();
if(intval($BX_MAIL_SPAM_CNT["G"])<=0)
$BX_MAIL_SPAM_CNT["G"] = 1;
if(intval($BX_MAIL_SPAM_CNT["B"])<=0)
$BX_MAIL_SPAM_CNT["B"] = 1;
}
$CNT_WORDS = COption::GetOptionInt("mail", "spam_word_count", B_MAIL_WORD_CNT);
$MIN_COUNT = COption::GetOptionInt("mail", "spam_min_count", B_MAIL_MIN_CNT);
// select $CNT_WORDS words with max |Si - 0.5|
// if the word placed less then xxx (5) times, then ignore
$strSql =
"SELECT SW.*, ".
" (BAD_CNT/".$BX_MAIL_SPAM_CNT["B"].".0) / (2*GOOD_CNT/".$BX_MAIL_SPAM_CNT["G"].".0 + BAD_CNT/".$BX_MAIL_SPAM_CNT["B"].".0) as RATING, ".
" ABS((BAD_CNT/".$BX_MAIL_SPAM_CNT["B"].".0) / (2*GOOD_CNT/".$BX_MAIL_SPAM_CNT["G"].".0 + BAD_CNT/".$BX_MAIL_SPAM_CNT["B"].".0) - 0.5) as MOD_RATING ".
"FROM b_mail_spam_weight SW ".
"WHERE WORD_ID IN ('".implode("', '", $arWords)."') ".
" AND ABS((BAD_CNT/".$BX_MAIL_SPAM_CNT["B"].".0) / (2*GOOD_CNT/".$BX_MAIL_SPAM_CNT["G"].".0 + BAD_CNT/".$BX_MAIL_SPAM_CNT["B"].".0) - 0.5) > 0.1 ".
" AND TOTAL_CNT>".$MIN_COUNT." ".
"ORDER BY MOD_RATING DESC ".
(strtoupper($DB->type)=="MYSQL"?"LIMIT ".$CNT_WORDS : "");
//echo htmlspecialcharsbx($strSql)."<br>";
$a = 1;
$b = 1;
$dbr = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$arr = true;
$words = "";
for($i=0; $i<$CNT_WORDS; $i++)
{
if($arr && $arr = $dbr->Fetch())
{
//echo "<font size='-3'>".htmlspecialcharsbx($arr["WORD_REAL"])."=".$arr["RATING"]."<br></font> ";
$words .= $arr["WORD_REAL"]." ".Round($arr["RATING"]*100, 4)." ".$arr["BAD_CNT"]." ".$arr["GOOD_CNT"]."\n";
$a = $a * ($arr["RATING"]==0?0.00001:$arr["RATING"]);
$b = $b * (1 - ($arr["RATING"]==1?0.9999:$arr["RATING"]));
}
else
{
//if there is no word then weight Si = 0.4
$a = $a * 0.4;
$b = $b * (1 - 0.4);
}
}
// calculate Bayes for the whole message
$rating = $a/($a+$b) * 100;
return Array("RATING"=>$rating, "WORDS"=>$words);
}
function getWords($message, $max_words)
{
static $tok = null;
if (!isset($tok))
{
$tok = "}{~";
for($i = ord("\x01"); $i < ord("\x23"); $i++)
$tok .= chr($i);
for($i = ord("\x25"); $i < ord("\x3F"); $i++)
$tok .= chr($i);
for($i = ord("\x5B"); $i < ord("\x5E"); $i++)
$tok .= chr($i);
}
$arWords = array();
$word = strtok($message, $tok);
while($word !== false)
{
$arWords[$word] = $word;
if (count($arWords) >= $max_words)
break;
$word = strtok($tok);
}
return $arWords;
}
function DoPHPAction($id, $action, &$arMessageFields)
{
return eval($action);
}
function DeleteFromSpamBase($message, $bIsSPAM = true)
{
return CMailFilter::SpamAction($message, $bIsSPAM, true);
}
function MarkAsSpam($message, $bIsSPAM = true)
{
return CMailFilter::SpamAction($message, $bIsSPAM);
}
function SpamAction($message, $bIsSPAM, $bDelete = false)
{
global $DB;
global $BX_MAIL_SPAM_CNT;
if(!is_set($BX_MAIL_SPAM_CNT, "G"))
{
$strSql = "SELECT MAX(GOOD_CNT) as G, MAX(BAD_CNT) as B FROM b_mail_spam_weight";
if($res = $DB->Query($strSql))
$BX_MAIL_SPAM_CNT = $res->Fetch();
if(intval($BX_MAIL_SPAM_CNT["G"])<=0)
$BX_MAIL_SPAM_CNT["G"] = 1;
if(intval($BX_MAIL_SPAM_CNT["B"])<=0)
$BX_MAIL_SPAM_CNT["B"] = 1;
}
if($bDelete && $bIsSPAM)
$BX_MAIL_SPAM_CNT["B"]--;
elseif($bDelete && !$bIsSPAM)
$BX_MAIL_SPAM_CNT["G"]--;
elseif(!$bDelete && $bIsSPAM)
$BX_MAIL_SPAM_CNT["B"]++;
elseif(!$bDelete && !$bIsSPAM)
$BX_MAIL_SPAM_CNT["G"]++;
@set_time_limit(30);
// split to words
$arWords = CMailFilter::getWords($message, 1000);
// for every word find Si
$strWords = "''";
foreach($arWords as $word)
{
$word_md5 = md5($word);
// change weight
$strSql =
"INSERT INTO b_mail_spam_weight(WORD_ID, WORD_REAL, GOOD_CNT, BAD_CNT, TOTAL_CNT) ".
"VALUES('".$word_md5."', '".$DB->ForSql($word, 40)."', ".($bIsSPAM?0:1).", ".($bIsSPAM?1:0).", 1)";
if($bDelete || (!$DB->Query($strSql, true)))
{
if($bDelete)
{
$strSql =
"UPDATE b_mail_spam_weight SET ".
" GOOD_CNT = GOOD_CNT - ".($bIsSPAM?0:1).", ".
" BAD_CNT = BAD_CNT - ".($bIsSPAM?1:0).", ".
" TOTAL_CNT = TOTAL_CNT - 1 ".
"WHERE WORD_ID = '".$word_md5."' ".
" AND ".($bIsSPAM?"BAD_CNT>0":"GOOD_CNT>0");// AND WORD_REAL = '".$DB->ForSql($word, 40)."'";
}
else
{
$strSql =
"UPDATE b_mail_spam_weight SET ".
" GOOD_CNT = GOOD_CNT + ".($bIsSPAM?0:1).", ".
" BAD_CNT = BAD_CNT + ".($bIsSPAM?1:0).", ".
" TOTAL_CNT = TOTAL_CNT + 1 ".
"WHERE WORD_ID='".$word_md5."'";// AND WORD_REAL = '".$DB->ForSql($word, 40)."'";
}
$DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
}
}
if(COption::GetOptionString("mail", "reset_all_spam_result", "N") == "Y")
$DB->Query("UPDATE b_mail_message SET SPAM_LAST_RESULT='N'");
}
function GetFilterList($id = "")
{
static $BX_MAIL_CUST_FILTER_LIST = false;
if($BX_MAIL_CUST_FILTER_LIST === false)
{
$BX_MAIL_CUST_FILTER_LIST = array();
foreach(GetModuleEvents("mail", "OnGetFilterList", true) as $arEvent)
{
$arResult = ExecuteModuleEventEx($arEvent);
if(is_array($arResult))
$BX_MAIL_CUST_FILTER_LIST[] = $arResult;
}
}
if($id != "")
{
$allResultsTemp = array();
foreach($BX_MAIL_CUST_FILTER_LIST as $arResult)
{
if($arResult["ID"] == $id)
{
$allResultsTemp[] = $arResult;
break;
}
}
}
else
{
$allResultsTemp = $BX_MAIL_CUST_FILTER_LIST;
}
$db_res = new CDBResult;
$db_res->InitFromArray($allResultsTemp);
return $db_res;
}
}
class CMailFilterCondition
{
function GetList($arOrder=Array(), $arFilter=Array())
{
global $DB;
$strSql =
"SELECT MFC.* ".
"FROM b_mail_filter_cond MFC ";
if(!is_array($arFilter))
$arFilter = Array();
$arSqlSearch = Array();
$filter_keys = array_keys($arFilter);
for($i = 0, $n = count($filter_keys); $i < $n; $i++)
{
$val = $arFilter[$filter_keys[$i]];
if (strlen($val)<=0) continue;
$key = strtoupper($filter_keys[$i]);
switch($key)
{
case "TYPE":
case "STRINGS":
case "COMPARE_TYPE":
$arSqlSearch[] = GetFilterQuery("MFC.".$key, $val);
break;
case "ID":
case "FILTER_ID":
$arSqlSearch[] = GetFilterQuery("MFC.".$key, $val, "N");
break;
}
}
$strSqlSearch = "";
for($i = 0, $n = count($arSqlSearch); $i < $n; $i++)
{
if(strlen($arSqlSearch[$i])>0)
$strSqlSearch .= " AND (".$arSqlSearch[$i].") ";
}
$arSqlOrder = Array();
foreach($arOrder as $by=>$order)
{
$order = strtolower($order);
if ($order!="asc")
$order = "desc".(strtoupper($DB->type)=="ORACLE"?" NULLS LAST":"");
else
$order = "asc".(strtoupper($DB->type)=="ORACLE"?" NULLS FIRST":"");
switch(strtoupper($by))
{
case "FILTER_ID":
case "TYPE":
case "STRINGS":
case "COMPARE_TYPE":
$arSqlOrder[] = " MFC.".$by." ".$order." ";
break;
default:
$arSqlOrder[] = " MFC.ID ".$order." ";
}
}
$strSqlOrder = "";
$arSqlOrder = array_unique($arSqlOrder);
DelDuplicateSort($arSqlOrder);
for ($i = 0, $n = count($arSqlOrder); $i < $n; $i++)
{
if($i==0)
$strSqlOrder = " ORDER BY ";
else
$strSqlOrder .= ",";
$strSqlOrder .= $arSqlOrder[$i];
}
$strSql .= " WHERE 1=1 ".$strSqlSearch.$strSqlOrder;
$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$res->is_filtered = (count($arSqlOrder)>0);
return $res;
}
function GetByID($ID)
{
global $DB;
return CMailFilterCondition::GetList(Array(), Array("ID"=>$ID));
}
function Delete($ID)
{
global $DB;
$ID = Intval($ID);
$strSql = "DELETE FROM b_mail_filter_cond WHERE ID=".$ID;
return $DB->Query($strSql, true);
}
function SetConditions($FILTER_ID, $CONDITIONS, $bClearOther = true)
{
global $DB;
$FILTER_ID = IntVal($FILTER_ID);
$strSql=
"SELECT ID ".
"FROM b_mail_filter_cond ".
"WHERE FILTER_ID=".$FILTER_ID;
$dbr = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
while($dbr_arr = $dbr->Fetch())
{
if(is_set($CONDITIONS, $dbr_arr["ID"]) && is_array($CONDITIONS[$dbr_arr["ID"]]) && strlen($CONDITIONS[$dbr_arr["ID"]]["STRINGS"])>0)
{
$arFields = $CONDITIONS[$dbr_arr["ID"]];
unset($arFields["ID"]);
$arFields["FILTER_ID"] = $FILTER_ID;
CMailFilterCondition::Update($dbr_arr["ID"], $arFields);
unset($CONDITIONS[$dbr_arr["ID"]]);
}
elseif($bClearOther)
{
$DB->Query("DELETE FROM b_mail_filter_cond WHERE ID=".$dbr_arr["ID"]);
}
}
foreach($CONDITIONS as $arFields)
{
if(is_array($arFields) && strlen($arFields["STRINGS"])>0)
{
$arFields["FILTER_ID"] = $FILTER_ID;
unset($arFields["ID"]);
CMailFilterCondition::Add($arFields);
}
}
}
function Add($arFields)
{
global $DB;
if(is_set($arFields, "COMPARE_TYPE") && $arFields["COMPARE_TYPE"]!="EQUAL" && $arFields["COMPARE_TYPE"]!="NOT_EQUAL" && $arFields["COMPARE_TYPE"]!="NOT_CONTAIN" && $arFields["COMPARE_TYPE"]!="REGEXP")
$arFields["COMPARE_TYPE"]="CONTAIN";
$ID = $DB->Add("b_mail_filter_cond", $arFields);
return $ID;
}
function Update($ID, $arFields)
{
global $DB;
$ID = IntVal($ID);
if(is_set($arFields, "COMPARE_TYPE") && $arFields["COMPARE_TYPE"]!="EQUAL" && $arFields["COMPARE_TYPE"]!="NOT_EQUAL" && $arFields["COMPARE_TYPE"]!="NOT_CONTAIN" && $arFields["COMPARE_TYPE"]!="REGEXP")
$arFields["COMPARE_TYPE"]="CONTAIN";
$strUpdate = $DB->PrepareUpdate("b_mail_filter_cond", $arFields);
$strSql =
"UPDATE b_mail_filter_cond SET ".
$strUpdate." ".
"WHERE ID=".$ID;
$DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
return true;
}
}
class CMailLog
{
public static function AddMessage($arFields)
{
global $DB;
if (COption::getOptionString('mail', 'disable_log', 'N') == 'Y')
return;
$arFields["~DATE_INSERT"] = $DB->GetNowFunction();
if(array_key_exists('MESSAGE', $arFields))
$arFields['MESSAGE'] = strval(substr($arFields['MESSAGE'], 0, 255));
else
$arFields['MESSAGE'] = '';
return $DB->Add("b_mail_log", $arFields);
}
public static function Delete($ID)
{
global $DB;
$ID = IntVal($ID);
$strSql = "DELETE FROM b_mail_log WHERE ID=".$ID;
return $DB->Query($strSql, true);
}
function GetList($arOrder=Array(), $arFilter=Array())
{
global $DB;
$strSql =
"SELECT ML.*, MB.NAME as MAILBOX_NAME, ".
" MF.NAME as FILTER_NAME, ".
" MM.SUBJECT as MESSAGE_SUBJECT, ".
" ".$DB->DateToCharFunction("ML.DATE_INSERT")." as DATE_INSERT ".
" ".
"FROM b_mail_log ML ".
" INNER JOIN b_mail_mailbox MB ON MB.ID=ML.MAILBOX_ID ".
" LEFT JOIN b_mail_filter MF ON MF.ID=ML.FILTER_ID ".
" LEFT JOIN b_mail_message MM ON MM.ID=ML.MESSAGE_ID ";
if(!is_array($arFilter))
$arFilter = Array();
$arSqlSearch = Array();
$filter_keys = array_keys($arFilter);
for($i = 0, $n = count($filter_keys); $i < $n; $i++)
{
$val = $arFilter[$filter_keys[$i]];
if (strlen($val)<=0) continue;
$key = strtoupper($filter_keys[$i]);
switch($key)
{
case "ID":
case "MAILBOX_ID":
case "FILTER_ID":
case "MESSAGE_ID":
case "LOG_TYPE":
case "STATUS_GOOD":
$arSqlSearch[] = GetFilterQuery("ML.".$key, $val, "N");
break;
case "MESSAGE":
$arSqlSearch[] = GetFilterQuery("ML.".$key, $val);
break;
case "FILTER_NAME":
$arSqlSearch[] = GetFilterQuery("MF.NAME", $val);
break;
case "MAILBOX_NAME":
$arSqlSearch[] = GetFilterQuery("MB.NAME", $val);
break;
case "MESSAGE_SUBJECT":
$arSqlSearch[] = GetFilterQuery("MM.SUBJECT", $val);
break;
}
}
$is_filtered = false;
$strSqlSearch = "";
for($i = 0, $n = count($arSqlSearch); $i < $n; $i++)
{
if(strlen($arSqlSearch[$i])>0)
{
$strSqlSearch .= " AND (".$arSqlSearch[$i].") ";
$is_filtered = true;
}
}
$arSqlOrder = Array();
foreach($arOrder as $by=>$order)
{
$order = strtolower($order);
if ($order!="asc")
$order = "desc".(strtoupper($DB->type)=="ORACLE"?" NULLS LAST":"");
else
$order = "asc".(strtoupper($DB->type)=="ORACLE"?" NULLS FIRST":"");
switch(strtoupper($by))
{
case "ID":
case "MAILBOX_ID":
case "FILTER_ID":
case "MESSAGE_ID":
case "DATE_INSERT":
case "LOG_TYPE":
case "STATUS_GOOD":
case "MESSAGE":
$arSqlOrder[] = " ML.".$by." ".$order." ";
case "MESSAGE_SUBJECT":
$arSqlOrder[] = " MM.SUBJECT ".$order." ";
case "FILTER_NAME":
$arSqlOrder[] = " MF.NAME ".$order." ";
case "MAILBOX_NAME":
$arSqlOrder[] = " MB.NAME ".$order." ";
default:
$arSqlOrder[] = " ML.ID ".$order." ";
}
}
$strSqlOrder = "";
$arSqlOrder = array_unique($arSqlOrder);
DelDuplicateSort($arSqlOrder);
for ($i = 0, $n = count($arSqlOrder); $i < $n; $i++)
{
if($i==0)
$strSqlOrder = " ORDER BY ";
else
$strSqlOrder .= ",";
$strSqlOrder .= $arSqlOrder[$i];
}
$strSql .= " WHERE 1=1 ".$strSqlSearch.$strSqlOrder;
$res = $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
$res = new _CMailLogDBRes($res);
$res->is_filtered = $is_filtered;
return $res;
}
function ConvertRow($arr_log)
{
switch($arr_log["LOG_TYPE"])
{
case "FILTER_OK":
$arr_log["MESSAGE_TEXT"] = GetMessage("MAIL_CL_RULE_RUN")." \"[".$arr_log["FILTER_ID"]."] ".substr($arr_log["FILTER_NAME"], 0, 30).(strlen($arr_log["FILTER_NAME"])>30?"...":"")."\" ";
if($arr_log["MESSAGE"]=="R")
$arr_log["MESSAGE_TEXT"] .= GetMessage("MAIL_CL_WHEN_CONNECT");
else
$arr_log["MESSAGE_TEXT"] .= GetMessage("MAIL_CL_WHEN_MANUAL");
break;
case "NEW_MESSAGE":
$arr_log["MESSAGE_TEXT"] = GetMessage("MAIL_CL_NEW_MESSAGE")." ".$arr_log["MESSAGE"];
break;
case "SPAM":
if($arr_log["FILTER_ID"]>0)
$arr_log["MESSAGE_TEXT"] = " ".GetMessage("MAIL_CL_RULE_ACT_SPAM");
else
$arr_log["MESSAGE_TEXT"] = GetMessage("MAIL_CL_ACT_SPAM");
break;
case "NOTSPAM":
if($arr_log["FILTER_ID"]>0)
$arr_log["MESSAGE_TEXT"] = " ".GetMessage("MAIL_CL_RULE_ACT_NOTSPAM");
else
$arr_log["MESSAGE_TEXT"] = GetMessage("MAIL_CL_ACT_NOTSPAM");
break;
case "DO_PHP":
$arr_log["MESSAGE_TEXT"] = " ".GetMessage("MAIL_CL_RULE_ACT_PHP");
break;
case "MESSAGE_DELETED":
$arr_log["MESSAGE_TEXT"] = " ".GetMessage("MAIL_CL_RULE_ACT_DEL");
break;
case "FILTER_STOP":
$arr_log["MESSAGE_TEXT"] = " ".GetMessage("MAIL_CL_RULE_ACT_CANC");
break;
default:
$arr_log["MESSAGE_TEXT"] = $arr_log["MESSAGE"];
}
return $arr_log;
}
}
class _CMailLogDBRes extends CDBResult
{
function _CMailLogDBRes($res)
{
parent::CDBResult($res);
}
function Fetch()
{
if($arr_log = parent::Fetch())
return CMailLog::ConvertRow($arr_log);
return false;
}
}
?>