static function imapEmailMessageAdd($msgFields, $actionVars = null, &$error = null)
{
global $DB;
$error = null;
if (!\CModule::includeModule('crm'))
return false;
$eventTag = sprintf('%x%x', time(), rand(0, 0xffffffff));
$messageId = isset($msgFields['ID']) ? intval($msgFields['ID']) : 0;
$mailboxId = isset($msgFields['MAILBOX_ID']) ? intval($msgFields['MAILBOX_ID']) : 0;
if (empty($mailboxId))
{
static::log(
$eventTag,
'CCrmEmail: empty MAILBOX_ID',
array(
'ID' => $msgFields['ID'],
'MAILBOX_ID' => $msgFields['MAILBOX_ID'],
)
);
return false;
}
$mailbox = \CMailBox::getById($mailboxId)->fetch();
if (empty($mailbox))
{
static::log(
$eventTag,
'CCrmEmail: empty mailbox',
array(
'ID' => $msgFields['ID'],
'MAILBOX_ID' => $msgFields['MAILBOX_ID'],
)
);
return false;
}
$crmNewEntityOptionName = empty($msgFields['IS_OUTCOME']) ? 'crm_new_entity_in' : 'crm_new_entity_out';
static::log(
$eventTag,
'CCrmEmail: IMAP email message received',
array(
'ID' => $msgFields['ID'],
'MAILBOX_ID' => $msgFields['MAILBOX_ID'],
'MSG_HASH' => $msgFields['MSG_HASH'],
'OPTIONS' => array_filter(array(
'flags' => $mailbox['OPTIONS']['flags'],
'crm_sync_from' => $mailbox['OPTIONS']['crm_sync_from'],
//'crm_lead_resp' => $mailbox['OPTIONS']['crm_lead_resp'],
//'crm_new_lead_for' => $mailbox['OPTIONS']['crm_new_lead_for'],
$crmNewEntityOptionName => $mailbox['OPTIONS'][$crmNewEntityOptionName],
)),
'TAGS' => array_keys(array_filter(array(
'IS_INCOME' => empty($msgFields['IS_OUTCOME']),
'IS_OUTCOME' => !empty($msgFields['IS_OUTCOME']),
'IS_DRAFT' => !empty($msgFields['IS_DRAFT']),
'IS_TRASH' => !empty($msgFields['IS_TRASH']),
'IS_SPAM' => !empty($msgFields['IS_SPAM']),
'__forced' => !empty($msgFields['__forced']),
))),
)
);
$isForced = !empty($msgFields['__forced']);
if (!$isForced && !empty($mailbox['OPTIONS']['crm_sync_from']))
{
$timestamp = makeTimestamp($msgFields['FIELD_DATE'], FORMAT_DATETIME) - \CTimeZone::getOffset();
if ($timestamp < (int) $mailbox['OPTIONS']['crm_sync_from'])
{
static::log($eventTag, 'CCrmEmail: too old');
return false;
}
}
$mailbox['__email'] = '';
if (check_email($mailbox['NAME'], true))
$mailbox['__email'] = $mailbox['NAME'];
else if (check_email($mailbox['LOGIN'], true))
$mailbox['__email'] = $mailbox['LOGIN'];
$publicBindings = false;
$denyNewEntityIn = false;
$denyNewEntityOut = false;
$denyNewContact = false;
if (!empty($mailbox['OPTIONS']['flags']) && is_array($mailbox['OPTIONS']['flags']))
{
$publicBindings = in_array('crm_public_bind', $mailbox['OPTIONS']['flags']);
$denyNewContact = in_array('crm_deny_new_contact', $mailbox['OPTIONS']['flags']);
if (!$isForced)
{
$denyNewEntityIn = in_array('crm_deny_new_lead', $mailbox['OPTIONS']['flags']);
$denyNewEntityIn = $denyNewEntityIn || in_array('crm_deny_entity_in', $mailbox['OPTIONS']['flags']);
$denyNewEntityOut = in_array('crm_deny_new_lead', $mailbox['OPTIONS']['flags']);
$denyNewEntityOut = $denyNewEntityOut || in_array('crm_deny_entity_out', $mailbox['OPTIONS']['flags']);
}
}
$isIncome = empty($msgFields['IS_OUTCOME']);
$isDraft = !empty($msgFields['IS_DRAFT']);
$isTrash = !empty($msgFields['IS_TRASH']);
$isSpam = !empty($msgFields['IS_SPAM']);
$isUnseen = empty($msgFields['IS_SEEN']);
if (!$isForced and $isDraft || $isTrash || $isSpam)
{
static::log($eventTag, 'CCrmEmail: draft|trash|spam');
return false;
}
$userId = 0;
$ownerTypeId = 0;
$ownerId = 0;
$parentId = 0;
$msgId = isset($msgFields['MSG_ID']) ? $msgFields['MSG_ID'] : '';
$inReplyTo = isset($msgFields['IN_REPLY_TO']) ? $msgFields['IN_REPLY_TO'] : '';
$from = isset($msgFields['FIELD_FROM']) ? $msgFields['FIELD_FROM'] : '';
$replyTo = isset($msgFields['FIELD_REPLY_TO']) ? $msgFields['FIELD_REPLY_TO'] : '';
$senderAddress = array();
$sender = array();
foreach (array_merge(explode(',', $replyTo), explode(',', $from)) as $item)
{
if (trim($item))
{
$address = new \Bitrix\Main\Mail\Address($item);
if ($address->validate() && !in_array($address->getEmail(), $sender))
{
$senderAddress[] = $address;
$sender[] = $address->getEmail();
}
}
}
$to = isset($msgFields['FIELD_TO']) ? $msgFields['FIELD_TO'] : '';
$cc = isset($msgFields['FIELD_CC']) ? $msgFields['FIELD_CC'] : '';
$bcc = isset($msgFields['FIELD_BCC']) ? $msgFields['FIELD_BCC'] : '';
$rcptAddress = array();
$rcpt = array();
foreach (array_merge(explode(',', $to), explode(',', $cc), explode(',', $bcc)) as $item)
{
if (trim($item))
{
$address = new \Bitrix\Main\Mail\Address($item);
if ($address->validate() && !in_array($address->getEmail(), $rcpt))
{
$rcptAddress[] = $address;
$rcpt[] = $address->getEmail();
}
}
}
$subject = trim($msgFields['SUBJECT']) ?: getMessage('CRM_EMAIL_DEFAULT_SUBJECT');
$emailFacility = new Bitrix\Crm\Activity\EmailFacility();
if (!$isForced && $isIncome && preg_match('/\nX-EVENT_NAME:/i', $msgFields['HEADER']))
{
$defaultEmailFrom = \Bitrix\Main\Config\Option::get('main', 'email_from', 'admin@'.$GLOBALS['SERVER_NAME']);
$defaultEmailFrom = mb_strtolower(trim($defaultEmailFrom));
foreach ($sender as $item)
{
if (mb_strtolower(trim($item)) == $defaultEmailFrom)
{
static::log($eventTag, 'CCrmEmail: system email');
return false;
}
}
}
// @TODO: killmail
if (!empty($msgId))
{
if (!$isIncome && preg_match('/]+>/i', sprintf('<%s>', $msgId), $matches))
{
$matchActivity = \CCrmActivity::getList(
array(),
array(
'ID' => $matches[2],
'CHECK_PERMISSIONS' => 'N',
),
false,
false,
array('ID', 'URN', 'UF_MAIL_MESSAGE')
)->fetch();
if ($matchActivity && mb_strtolower($matchActivity['URN']) == mb_strtolower($matches[1]))
{
\CCrmActivity::update(
$matchActivity['ID'],
array(
'UF_MAIL_MESSAGE' => $messageId,
),
false,
false
);
static::log($eventTag, 'CCrmEmail: matches outgoing');
return true;
}
}
}
// skip employees
$employeesEmails = array();
{
$filter = array(
'=ACTIVE' => 'Y',
'=EMAIL' => $isIncome ? $sender : $rcpt,
'IS_REAL_USER' => 'Y',
);
$res = \Bitrix\Main\UserTable::getList(array(
'select' => array('ID', 'EMAIL', 'UF_DEPARTMENT'),
'filter' => $filter,
));
if ($isIncome)
{
while ($employee = $res->fetch())
{
$departments = empty($employee['UF_DEPARTMENT']) ? array() : (array) $employee['UF_DEPARTMENT'];
if (reset($departments) > 0)
{
static::log(
$eventTag,
'CCrmEmail: from employee',
array(
'USER_ID' => $employee['ID'],
'USER_EMAIL' => $employee['EMAIL'],
)
);
$error = new \Bitrix\Main\Error(Loc::getMessage('CRM_EMAIL_IMAP_ERROR_EMPLOYE_IN'));
return false;
}
}
if (CModule::includeModule('mail'))
{
// @TODO: index
$employee = \Bitrix\Mail\MailboxTable::getList(array(
'select' => array('ID', 'EMAIL', 'NAME', 'LOGIN', 'USER_ID'),
'filter' => array(
'=ACTIVE' => 'Y',
array(
'LOGIC' => 'OR',
'EMAIL' => $sender,
'NAME' => $sender,
'LOGIN' => $sender,
),
),
'limit' => 1,
))->fetch();
if (!empty($employee))
{
static::log(
$eventTag,
'CCrmEmail: from employee',
array(
'USER_ID' => $employee['USER_ID'],
'MAILBOX_ID' => $employee['ID'],
'MAILBOX_EMAIL' => $employee['EMAIL'],
'MAILBOX_NAME' => $employee['NAME'],
'MAILBOX_LOGIN' => $employee['LOGIN'],
)
);
$error = new \Bitrix\Main\Error(Loc::getMessage('CRM_EMAIL_IMAP_ERROR_EMPLOYE_IN'));
return false;
}
}
}
else
{
$employees = array();
while ($employee = $res->fetch())
{
$departments = empty($employee['UF_DEPARTMENT']) ? array() : (array) $employee['UF_DEPARTMENT'];
if (reset($departments) > 0)
{
$employees[] = array(
'USER_ID' => $employee['ID'],
'USER_EMAIL' => $employee['EMAIL'],
);
$employeesEmails[] = $employee['EMAIL'];
}
}
$employeesEmails = array_unique(array_map('mb_strtolower', $employeesEmails));
if (count($employeesEmails) >= count($rcpt))
{
static::log(
$eventTag,
'CCrmEmail: to employees',
array(
'LIST' => $employees,
)
);
$error = new \Bitrix\Main\Error(Loc::getMessage('CRM_EMAIL_IMAP_ERROR_EMPLOYE_OUT'));
return false;
}
if (CModule::includeModule('mail'))
{
// @TODO: index
$res = \Bitrix\Mail\MailboxTable::getList(array(
'select' => array('ID', 'EMAIL', 'NAME', 'LOGIN', 'USER_ID'),
'filter' => array(
'=ACTIVE' => 'Y',
array(
'LOGIC' => 'OR',
'EMAIL' => $rcpt,
'NAME' => $rcpt,
'LOGIN' => $rcpt,
),
),
));
$employees = array();
while ($employee = $res->fetch())
{
$employees[] = array(
'USER_ID' => $employee['USER_ID'],
'MAILBOX_ID' => $employee['ID'],
'MAILBOX_EMAIL' => $employee['EMAIL'],
'MAILBOX_NAME' => $employee['NAME'],
'MAILBOX_LOGIN' => $employee['LOGIN'],
);
$employeesEmails[] = (check_email($employee['EMAIL'], true) ? $employee['EMAIL'] : (check_email($employee['NAME'], true) ? $employee['NAME'] : $employee['LOGIN']));
}
$employeesEmails = array_unique(array_map('mb_strtolower', $employeesEmails));
if (count($employeesEmails) >= count($rcpt))
{
static::log(
$eventTag,
'CCrmEmail: to employees',
array(
'LIST' => $employees,
)
);
$error = new \Bitrix\Main\Error(Loc::getMessage('CRM_EMAIL_IMAP_ERROR_EMPLOYE_OUT'));
return false;
}
}
}
}
$mailboxOwnerId = (int)$mailbox['USER_ID'] ?? 0;
// initialize responsible queue
$respQueue = array();
{
$respOption = array_values(array_unique((array) $mailbox['OPTIONS']['crm_lead_resp']));
if (empty($respOption) && $mailboxOwnerId > 0)
{
$respOption = array($mailboxOwnerId);
}
if (!empty($respOption))
{
$res = \Bitrix\Main\UserTable::getList(array(
'select' => array('ID', 'ACTIVE'),
'filter' => array(
'@ID' => $respOption,
'=ACTIVE' => 'Y',
),
));
$respActive = array();
while ($resp = $res->fetch())
{
$respQueue[] = $resp['ID'];
if ($resp['ACTIVE'] == 'Y')
{
$respActive[] = $resp['ID'];
}
}
if (!empty($respActive))
{
$respQueue = $respActive;
}
$respOrder = array_flip($respOption);
usort(
$respQueue,
function ($a, $b) use (&$respOrder)
{
return isset($respOrder[$a], $respOrder[$b]) ? $respOrder[$a]-$respOrder[$b] : 0;
}
);
if (count($respOption) > 0 && count($respActive) == count($respOption))
{
\Bitrix\Main\Config\Option::set('crm', 'email_resp_queue_ok_'.$mailboxId, 'Y');
}
else
{
$shouldNotify = \Bitrix\Main\Config\Option::get('crm', 'email_resp_queue_ok_' . $mailboxId, 'Y') == 'Y';
if ($shouldNotify && \CModule::includeModule('im'))
{
\Bitrix\Main\Config\Option::set('crm', 'email_resp_queue_ok_' . $mailboxId, 'N');
$configUrl = str_replace(
'#id#',
$mailboxId,
\Bitrix\Main\Config\Option::get('intranet', 'path_mail_config', '/mail/', $mailbox['LID'])
);
$internalMessage = getMessage('CRM_EMAIL_BAD_RESP_QUEUE', array(
'#EMAIL#' => htmlspecialcharsbx($mailbox['NAME']),
'#CONFIG_URL#' => htmlspecialcharsbx($configUrl),
));
$externalMessage = getMessage('CRM_EMAIL_BAD_RESP_QUEUE', array(
'#EMAIL#' => htmlspecialcharsbx($mailbox['NAME']),
'#CONFIG_URL#' => htmlspecialcharsbx(\CCrmUrlUtil::toAbsoluteUrl($configUrl)),
));
\CCrmNotifier::notify(
$mailbox['USER_ID'],
$internalMessage,
$externalMessage,
0,
'email_resp_queue_ok_' . $mailboxId
);
}
}
}
if (empty($respQueue))
{
$respQueue = array_column(self::getAdminsList(), 'ID') ?: array(1);
}
}
$targetActivity = Bitrix\Crm\Activity\Provider\Email::getParentByEmail($msgFields);
if (!empty($targetActivity))
{
static::log(
$eventTag,
'CCrmEmail: parent found',
array(
'ACTIVITY_ID' => $targetActivity['ID'],
)
);
$parentId = $targetActivity['ID'];
$isForced = true;
switch ($targetActivity['OWNER_TYPE_ID'])
{
case \CCrmOwnerType::Deal:
$owner = \Bitrix\Crm\DealTable::getList(array(
'select' => array('ID', 'ASSIGNED_BY_ID'),
'filter' => array(
'=ID' => $targetActivity['OWNER_ID'],
$publicBindings ? array() : array('@ASSIGNED_BY_ID' => $respQueue),
'=STAGE_SEMANTIC_ID' => \Bitrix\Crm\PhaseSemantics::PROCESS,
),
))->fetch();
break;
case \CCrmOwnerType::Lead:
$owner = \Bitrix\Crm\LeadTable::getList(array(
'select' => array('ID', 'ASSIGNED_BY_ID'),
'filter' => array(
'=ID' => $targetActivity['OWNER_ID'],
$publicBindings ? array() : array('@ASSIGNED_BY_ID' => $respQueue),
'=STATUS_SEMANTIC_ID' => \Bitrix\Crm\PhaseSemantics::PROCESS,
),
))->fetch();
break;
}
// @TODO: converted lead
if (!empty($owner))
{
static::log(
$eventTag,
'CCrmEmail: parent owner is active lead|deal',
array(
'OWNER_TYPE_ID' => $targetActivity['OWNER_TYPE_ID'],
'OWNER_ID' => $targetActivity['OWNER_ID'],
)
);
$ownerTypeId = $targetActivity['OWNER_TYPE_ID'];
$ownerId = $targetActivity['OWNER_ID'];
}
}
$forceNewLead = false;
if ($isIncome && empty($targetActivity)) // @TODO: do not check $targetActivity?
{
if (!empty($mailbox['OPTIONS']['crm_new_lead_for']) && is_array($mailbox['OPTIONS']['crm_new_lead_for']))
{
$matches = array_intersect(
array_map('mb_strtolower', array_map('trim', $sender)),
array_map('mb_strtolower', array_map('trim', $mailbox['OPTIONS']['crm_new_lead_for']))
);
if ($forceNewLead = (boolean) $matches)
{
static::log($eventTag, 'CCrmEmail: force new lead', $matches);
}
}
}
$rankingModifier = function ($ranking) use (&$respQueue)
{
$knownTypes = array(
\CCrmOwnerType::Contact => 'CCrmContact',
\CCrmOwnerType::Company => 'CCrmCompany',
\CCrmOwnerType::Lead => 'CCrmLead',
);
$typeId = $ranking->getEntityTypeId();
$list = array();
if (array_key_exists($typeId, $knownTypes) && !empty($ranking->getRankedList()))
{
$res = $knownTypes[$typeId]::getListEx(
array(),
array(
'ID' => (array) $ranking->getRankedList(),
'ASSIGNED_BY_ID' => $respQueue,
'CHECK_PERMISSIONS' => 'N',
),
false,
false,
array('ID')
);
while ($item = $res->fetch())
{
$list[] = $item['ID'];
}
}
$ranking->setModifiedList($list);
$ranking->setRankedList($list);
};
$newEntityTypeId = \CCrmOwnerType::Lead;
$filteredAddress = array_filter(
$isIncome ? $senderAddress : $rcptAddress,
function ($item) use (&$employeesEmails)
{
return !in_array($item->getEmail(), $employeesEmails);
}
);
$trace = Tracking\Trace::create()->addChannel(
new Tracking\Channel\Mail(!empty($rcptAddress) ?
reset($rcptAddress)->getEmail() : null
)
);
if ($forceNewLead)
{
$commAddress = $filteredAddress;
$facility = new \Bitrix\Crm\EntityManageFacility();
$facility->setDirection($isIncome ? $facility::DIRECTION_INCOMING : $facility::DIRECTION_OUTGOING);
$facility->setTrace($trace);
if ($isForced)
{
$facility->getSelector()->disableExclusionChecking();
}
}
else
{
$commAddress = array();
foreach ($filteredAddress as $item)
{
$itemSelector = new \Bitrix\Crm\Integrity\ActualEntitySelector();
$itemSelector->appendEmailCriterion($item->getEmail());
if (!$publicBindings)
{
$itemSelector->getRanking()->addModifier($rankingModifier);
}
if ($isForced)
{
$itemSelector->disableExclusionChecking();
}
$itemSelector->search();
if ($itemSelector->hasExclusions())
{
if ($isIncome)
{
$selector = $itemSelector;
break;
}
else
{
continue;
}
}
if (empty($firstSelector))
{
$firstSelector = $itemSelector;
}
if ($itemSelector->hasEntities())
{
if (empty($selector))
{
$selector = $itemSelector;
array_unshift($commAddress, $item);
}
}
else
{
$commAddress[] = $item;
}
}
if (empty($selector))
{
if (empty($firstSelector))
{
return false;
}
$selector = $firstSelector;
}
else
{
if (!$isIncome)
{
$commAddress = array();
}
}
$facility = new \Bitrix\Crm\EntityManageFacility($selector);
$facility->setDirection($isIncome ? $facility::DIRECTION_INCOMING : $facility::DIRECTION_OUTGOING);
$facility->setTrace($trace);
$emailFacility->setBindings($facility->getActivityBindings());
$criterions = $selector->getCriteria();
static::log(
$eventTag,
'CCrmEmail: search results',
array(
'SEARCH_VALUE' => reset($criterions)->getValue(),
'IS_EXCLUSION' => $selector->hasExclusions(),
'LIST' => $facility->getActivityBindings(),
)
);
if ($parentId > 0 && ($ownerTypeId > 0 && $ownerId > 0))
{
$cantCreate = true;
$emailFacility->setOwner($ownerTypeId, $ownerId);
$emailFacility->setBindings(array_filter(
$emailFacility->getBindings(),
function ($item)
{
return !in_array($item['OWNER_TYPE_ID'], array(\CCrmOwnerType::Deal, \CCrmOwnerType::Lead));
}
));
}
else
{
$cantCreate = $isIncome
? ($denyNewEntityIn && empty($emailFacility->getBindings()))
: ($denyNewEntityOut || !empty($emailFacility->getBindings()));
}
if ($cantCreate)
{
$facility->setRegisterMode($facility::REGISTER_MODE_ONLY_UPDATE);
}
$newEntityType = $mailbox['OPTIONS'][$isIncome ? 'crm_new_entity_in' : 'crm_new_entity_out'];
if (\CCrmOwnerType::ContactName == $newEntityType && empty($emailFacility->getBindings()))
{
$newEntityTypeId = \CCrmOwnerType::Contact;
}
}
if (!empty($emailFacility->getBindings()))
{
$userId = $emailFacility->getOwnerResponsibleId();
}
else if ($facility->canAddEntity($newEntityTypeId))
{
$luckyOne = \Bitrix\Main\Config\Option::get('crm', 'last_resp_' . $mailboxId, -1) + 1;
if ($luckyOne > count($respQueue) - 1)
{
$luckyOne = 0;
}
\Bitrix\Main\Config\Option::set('crm', 'last_resp_' . $mailboxId, $luckyOne);
$userId = $respQueue[$luckyOne];
}
else
{
return false;
}
$contactFields = array();
$contactTypes = \CCrmStatus::getStatusList('CONTACT_TYPE');
if (isset($contactTypes['CLIENT']))
{
$contactFields['TYPE_ID'] = 'CLIENT';
}
else if (isset($contactTypes['OTHER']))
{
$contactFields['TYPE_ID'] = 'OTHER';
}
$leadFields = array(
'COMPANY_TITLE' => \CCrmCompany::getDefaultTitle(),
);
if (trim($msgFields['SUBJECT']))
{
$leadFields['TITLE'] = trim($msgFields['SUBJECT']);
}
else
{
$leadFields['TITLE'] = getMessage(
($isIncome ? 'CRM_MAIL_LEAD_FROM_EMAIL_TITLE' : 'CRM_MAIL_LEAD_FROM_USER_EMAIL_TITLE'),
array('%SENDER%' => $replyTo ?: $from)
);
}
$entityFields = array(
'COMMENTS' => htmlspecialcharsbx($subject),
'ORIGINATOR_ID' => 'email-tracker',
'ORIGIN_ID' => $mailboxId,
);
$sourceList = \CCrmStatus::getStatusList('SOURCE');
$sourceId = $mailbox['OPTIONS']['crm_lead_source'];
if (empty($sourceId) || !isset($sourceList[$sourceId]))
{
if (isset($sourceList['EMAIL']))
{
$sourceId = 'EMAIL';
}
else if (isset($sourceList['OTHER']))
{
$sourceId = 'OTHER';
}
}
if ($sourceId != '')
$entityFields['SOURCE_ID'] = $sourceId;
if (!empty($commAddress))
{
$entityFields['FM'] = array('EMAIL' => array());
foreach ($commAddress as $i => $item)
{
$entityFields['FM']['EMAIL'][sprintf('n%u', $i+1)] = array(
'VALUE_TYPE' => 'WORK',
'VALUE' => $item->getEmail(),
);
if (empty($entityFields['NAME']) && !empty($item->getName()))
{
$entityFields['NAME'] = $item->getName();
}
}
if (empty($entityFields['NAME']))
{
$entityFields['NAME'] = reset($commAddress)->getEmail();
}
}
$entitiesFields = array(
\CCrmOwnerType::Lead => $leadFields + $entityFields,
\CCrmOwnerType::Contact => $contactFields + $entityFields,
);
// @TODO: update lead
$facility->registerTouch(
$newEntityTypeId,
$entitiesFields,
true,
array(
'CURRENT_USER' => $userId,
'DISABLE_USER_FIELD_CHECK' => true,
'REGISTER_SONET_EVENT' => true,
)
);
if ($facility->getRegisteredId() > 0)
{
static::log(
$eventTag,
'CCrmEmail: created entity',
array(
'ENTITY_TYPE' => \CCrmOwnerType::resolveName($facility->getRegisteredTypeId()),
'ENTITY_TYPE_ID' => $facility->getRegisteredTypeId(),
'ENTITY_ID' => $facility->getRegisteredId(),
)
);
$emailFacility->setBindings($facility->getActivityBindings(), true);
$channelTrackerParams = array(
'ORIGIN_ID' => sprintf('%u|%u', $mailbox['USER_ID'], $mailbox['ID'])
);
if ($facility->getRegisteredTypeId() == \CCrmOwnerType::Lead)
{
Channel\EmailTracker::getInstance()->registerLead($facility->getRegisteredId(), $channelTrackerParams);
}
else if ($facility->getRegisteredTypeId() == \CCrmOwnerType::Deal)
{
Channel\EmailTracker::getInstance()->registerDeal($facility->getRegisteredId(), $channelTrackerParams);
}
}
if (empty($emailFacility->getBindings()))
{
return false;
}
$ownerTypeId = $emailFacility->getOwnerTypeId();
$ownerId = $emailFacility->getOwnerId();
$attachmentMaxSizeMb = (int) \COption::getOptionString('crm', 'email_attachment_max_size', 24);
$attachmentMaxSize = $attachmentMaxSizeMb > 0 ? $attachmentMaxSizeMb*1024*1024 : 0;
// @TODO: update $msgFields
if (\Bitrix\Mail\Helper\Message::ensureAttachments($msgFields) > 0)
{
if ($message = \CMailMessage::getById($messageId)->fetch())
{
$msgFields = $message + $msgFields;
}
}
$body = isset($msgFields['BODY']) ? $msgFields['BODY'] : '';
$body_bb = isset($msgFields['BODY_BB']) ? $msgFields['BODY_BB'] : '';
$body_html = isset($msgFields['BODY_HTML']) ? $msgFields['BODY_HTML'] : '';
$filesData = array();
$bannedAttachments = array();
$res = \CMailAttachment::getList(array(), array('MESSAGE_ID' => $messageId));
while ($attachment = $res->fetch())
{
if (getFileExtension(mb_strtolower($attachment['FILE_NAME'])) == 'vcf' && !$denyNewContact)
{
if ($attachment['FILE_ID'])
$attachment['FILE_DATA'] = \CMailAttachment::getContents($attachment);
self::tryImportVCard($attachment['FILE_DATA'], $userId);
}
$fileSize = isset($attachment['FILE_SIZE']) ? intval($attachment['FILE_SIZE']) : 0;
if ($fileSize <= 0)
continue;
if ($attachmentMaxSize > 0 && $fileSize > $attachmentMaxSize)
{
$bannedAttachments[] = array(
'name' => $attachment['FILE_NAME'],
'size' => $fileSize
);
continue;
}
if ($attachment['FILE_ID'] && empty($attachment['FILE_DATA']))
$attachment['FILE_DATA'] = \CMailAttachment::getContents($attachment);
$filesData[] = array(
'name' => $attachment['FILE_NAME'],
'type' => $attachment['CONTENT_TYPE'],
'content' => $attachment['FILE_DATA'],
'MODULE_ID' => 'crm',
'attachment_id' => $attachment['ID'],
);
}
$eventBindings = array();
foreach ($emailFacility->getBindings() as $item)
{
$eventBindings[] = array(
'USER_ID' => $userId,
'ENTITY_TYPE' => \CCrmOwnerType::resolveName($item['OWNER_TYPE_ID']),
'ENTITY_ID' => $item['OWNER_ID'],
);
}
$eventText = ''.getMessage('CRM_EMAIL_SUBJECT').': '.$subject.PHP_EOL;
$eventText .= ''.getMessage('CRM_EMAIL_FROM').': '.join(', ', $sender).PHP_EOL;
$eventText .= ''.getMessage('CRM_EMAIL_TO').': '.join(', ', $rcpt).PHP_EOL;
if (!empty($bannedAttachments))
{
$eventText .= ''.getMessage('CRM_EMAIL_BANNENED_ATTACHMENTS', array('%MAX_SIZE%' => $attachmentMaxSizeMb)).': ';
foreach ($bannedAttachments as $attachmentInfo)
{
$eventText .= getMessage(
'CRM_EMAIL_BANNENED_ATTACHMENT_INFO',
array(
'%NAME%' => $attachmentInfo['name'],
'%SIZE%' => round($attachmentInfo['size']/1024/1024, 1)
)
);
}
$eventText .= PHP_EOL;
}
$eventText .= preg_replace('/(\r\n|\n|\r)+/', PHP_EOL, htmlspecialcharsbx($body));
$crmEvent = new \CCrmEvent();
$crmEvent->add(
array(
'USER_ID' => $mailbox['USER_ID'],
'ENTITY' => $eventBindings,
'ENTITY_TYPE' => \CCrmOwnerType::resolveName($ownerTypeId),
'ENTITY_ID' => $ownerId,
'EVENT_NAME' => getMessage('CRM_EMAIL_GET_EMAIL'),
'EVENT_TYPE' => 2,
'EVENT_TEXT_1' => $eventText,
'FILES' => $filesData,
),
false
);
$storageTypeId = \CCrmActivity::getDefaultStorageTypeID();
$elementIds = array();
foreach ($filesData as $i => $fileData)
{
$fileId = \CFile::saveFile($fileData, 'crm', true);
if (!($fileId > 0))
continue;
$fileData = \CFile::getFileArray($fileId);
if (empty($fileData))
continue;
if (trim($fileData['ORIGINAL_NAME']) == '')
$fileData['ORIGINAL_NAME'] = $fileData['FILE_NAME'];
$elementId = StorageManager::saveEmailAttachment(
$fileData, $storageTypeId, '',
array('USER_ID' => $userId)
);
if ($elementId > 0)
{
$elementIds[] = (int) $elementId;
$filesData[$i]['element_id'] = (int) $elementId;
}
}
if (!empty($body_html))
{
$checkInlineFiles = true;
$descr = $body_html;
}
else if (!empty($body_bb))
{
$bbCodeParser = new \CTextParser();
$descr = $bbCodeParser->convertText($body_bb);
foreach ($filesData as $item)
{
$descr = preg_replace(
sprintf('/\[ATTACHMENT=attachment_%u\]/is', $item['attachment_id']),
sprintf('
', $item['attachment_id']),
$descr, -1, $count
);
if ($count > 0)
$checkInlineFiles = true;
}
}
else
{
$descr = preg_replace('/\r\n|\n|\r/', '
', htmlspecialcharsbx($body));
}
$isIncomingChannel = false;
if ($isIncome)
{
$direction = \CCrmActivityDirection::Incoming;
$completed = $isUnseen ? 'N' : 'Y';
$isIncomingChannel = \Bitrix\Crm\Settings\Crm::isUniversalActivityScenarioEnabled();
}
else
{
$direction = \CCrmActivityDirection::Outgoing;
$completed = 'Y';
}
$currentUserOffset = \CTimeZone::getOffset();
$userOffset = \CTimeZone::getOffset($userId);
$nowTimestamp = time();
$siteId = \Bitrix\Crm\Integration\Main\Site::getPortalSiteId();
$datetime = convertTimeStamp($nowTimestamp + $currentUserOffset, 'FULL', $siteId);
if (!empty($msgFields['FIELD_DATE']) && $DB->isDate($msgFields['FIELD_DATE'], FORMAT_DATETIME))
{
$datetime = $msgFields['FIELD_DATE'];
}
$deadlineTimestamp = strtotime('tomorrow') + $currentUserOffset - $userOffset;
$deadline = convertTimeStamp($deadlineTimestamp, 'FULL', $siteId);
if (CModule::includeModule('calendar'))
{
$calendarSettings = \CCalendar::getSettings();
$workTimeEndHour = $calendarSettings['work_time_end'] > 0 ? $calendarSettings['work_time_end'] : 19;
$dummyDeadline = new \Bitrix\Main\Type\DateTime();
$dummyDeadline->setTime(
$workTimeEndHour,
0,
$currentUserOffset - $userOffset
);
$deadlineTimestamp += $workTimeEndHour * 60 * 60; // work time end in tomorrow
$deadline = convertTimeStamp($deadlineTimestamp, 'FULL', $siteId);
if ($dummyDeadline->getTimestamp() > $nowTimestamp + $currentUserOffset)
{
$deadline = $dummyDeadline->format(\Bitrix\Main\Type\DateTime::convertFormatToPhp(FORMAT_DATETIME));
}
}
$activityFields = array(
'OWNER_ID' => $ownerId,
'OWNER_TYPE_ID' => $ownerTypeId,
'BINDINGS' => $emailFacility->getBindings(),
'TYPE_ID' => \CCrmActivityType::Email,
'ASSOCIATED_ENTITY_ID' => 0,
'PARENT_ID' => $parentId,
'SUBJECT' => \Bitrix\Main\Text\Emoji::encode($subject),
'START_TIME' => (string) $datetime,
'END_TIME' => (string) $deadline,
'COMPLETED' => $completed,
'AUTHOR_ID' => $mailbox['USER_ID'],
'RESPONSIBLE_ID' => $userId,
'EDITOR_ID' => $userId,
'PRIORITY' => \CCrmActivityPriority::Medium,
'DESCRIPTION' => \Bitrix\Main\Text\Emoji::encode($descr),
'DESCRIPTION_TYPE' => \CCrmContentType::Html,
'DIRECTION' => $direction,
'LOCATION' => '',
'NOTIFY_TYPE' => \CCrmActivityNotifyType::None,
'STORAGE_TYPE_ID' => $storageTypeId,
'STORAGE_ELEMENT_IDS' => $elementIds,
'SETTINGS' => array(
'EMAIL_META' => array(
'__email' => $mailbox['__email'],
'from' => $from,
'replyTo' => $replyTo,
'to' => $to,
'cc' => $cc,
'bcc' => $bcc,
),
),
'UF_MAIL_MESSAGE' => $messageId,
'IS_INCOMING_CHANNEL' => $isIncomingChannel ? 'Y' : 'N',
);
if (!empty($isIncome ? $sender : $rcpt))
{
$subfilter = array(
'LOGIC' => 'OR',
);
foreach ($activityFields['BINDINGS'] as $item)
{
$subfilter[] = array(
'=ENTITY_ID' => \CCrmOwnerType::resolveName($item['OWNER_TYPE_ID']),
'=ELEMENT_ID' => $item['OWNER_ID'],
);
}
$res = \Bitrix\Crm\FieldMultiTable::getList(array(
'select' => array('ENTITY_ID', 'ELEMENT_ID', 'VALUE'),
'group' => array('ENTITY_ID', 'ELEMENT_ID', 'VALUE'),
'filter' => array(
$subfilter,
'=TYPE_ID' => 'EMAIL',
'@VALUE' => $isIncome ? $sender : $rcpt,
),
));
while ($item = $res->fetch())
{
$activityFields['COMMUNICATIONS'][] = array(
'ENTITY_TYPE_ID' => \CCrmOwnerType::resolveId($item['ENTITY_ID']),
'ENTITY_ID' => $item['ELEMENT_ID'],
'VALUE' => $item['VALUE'],
'TYPE' => 'EMAIL',
);
}
}
$activityId = \CCrmActivity::add($activityFields, false, false, array('REGISTER_SONET_EVENT' => true));
if ($activityId > 0)
{
static::log(
$eventTag,
'CCrmEmail: created activity',
array(
'ID' => $activityId,
'OWNER_ID' => $ownerId,
'OWNER_TYPE_ID' => $ownerTypeId,
'RESPONSIBLE_ID' => $userId,
)
);
if (!empty($checkInlineFiles))
{
foreach ($filesData as $item)
{
$info = \Bitrix\Crm\Integration\DiskManager::getFileInfo(
$item['element_id'], false,
array('OWNER_TYPE_ID' => \CCrmOwnerType::Activity, 'OWNER_ID' => $activityId)
);
$descr = preg_replace(
sprintf('/
]+)src\s*=\s*(\'|\")?\s*(aid:%u)\s*\2([^>]*)>/is', $item['attachment_id']),
sprintf('
', $info['VIEW_URL']),
$descr, -1, $count
);
if ($count > 0)
$descrUpdated = true;
}
if (!empty($descrUpdated))
{
\CCrmActivity::update($activityId, array(
'DESCRIPTION' => $descr,
), false, false);
}
}
\Bitrix\Crm\Activity\MailMetaTable::add(array(
'ACTIVITY_ID' => $activityId,
'MSG_ID_HASH' => !empty($msgId) ? md5(mb_strtolower($msgId)) : '',
'MSG_INREPLY_HASH' => !empty($inReplyTo) ? md5(mb_strtolower($inReplyTo)) : '',
'MSG_HEADER_HASH' => $msgFields['MSG_HASH'],
));
$res = \Bitrix\Crm\Activity\MailMetaTable::getList(array(
'select' => array('ACTIVITY_ID'),
'filter' => array(
'=MSG_INREPLY_HASH' => md5(mb_strtolower($msgId)),
),
));
while ($mailMeta = $res->fetch())
{
\CCrmActivity::update($mailMeta['ACTIVITY_ID'], array(
'PARENT_ID' => $activityId,
), false, false);
}
if ($isIncome)
{
\Bitrix\Crm\Automation\Trigger\EmailTrigger::execute($activityFields['BINDINGS'], $activityFields);
}
Channel\EmailTracker::getInstance()->registerActivity($activityId, array('ORIGIN_ID' => sprintf('%u|%u', $mailbox['USER_ID'], $mailbox['ID'])));
}
//Notify the responsible user if a message has been added from ajax sync to CRM
if ($userId > 0 && $isIncome && $completed != 'Y')
{
\CCrmActivity::notify(
$activityFields,
\CCrmNotifierSchemeType::IncomingEmail,
sprintf('crm_email_%u_%u', $activityFields['OWNER_TYPE_ID'], $activityFields['OWNER_ID']),
$isForced,
[],
);
}
return true;
}