403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/im/classes/general/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/im/classes/general/im_chat.php
<?php
IncludeModuleLangFile(__FILE__);

use Bitrix\Im as IM;
use Bitrix\Im\V2\Chat;
use Bitrix\Im\V2\Chat\Background\Background;
use Bitrix\Im\V2\Chat\TextField\TextFieldEnabled;
use Bitrix\Im\V2\Entity\User\UserError;
use Bitrix\Imopenlines\Model\SessionTable;
use Bitrix\Im\V2\Sync;
use Bitrix\Main\ORM\Fields\ExpressionField;
use Bitrix\Main\Type\DateTime;

class CIMChat
{
	const CHAT_ALL = 'all';
	const GENERAL_MESSAGE_TYPE_JOIN = IM\V2\Chat\GeneralChat::GENERAL_MESSAGE_TYPE_JOIN;
	const GENERAL_MESSAGE_TYPE_LEAVE = IM\V2\Chat\GeneralChat::GENERAL_MESSAGE_TYPE_LEAVE;

	private $user_id = 0;
	private $bHideLink = false;
	public $lastAvatarId = 0;
	private static $entityOption = null;

	function __construct($user_id = null, $arParams = Array())
	{
		if (is_null($user_id))
		{
			global $USER;
			if (is_object($USER))
			{
				$this->user_id = intval($USER->GetID());
			}
		}
		else
		{
			$this->user_id = intval($user_id);
		}

		if (isset($arParams['HIDE_LINK']) && $arParams['HIDE_LINK'] == 'Y')
		{
			$this->bHideLink = true;
		}
	}

	public function GetMessage($ID)
	{
		global $DB;

		$strSql = "
			SELECT
				M.*, C.TYPE as CHAT_TYPE, R.USER_ID as RID
			FROM
				b_im_message M
				INNER JOIN b_im_chat C ON C.ID = M.CHAT_ID
				LEFT JOIN b_im_relation R ON R.CHAT_ID = M.CHAT_ID AND R.USER_ID = ".$this->user_id."
			WHERE
				M.ID = ".intval($ID)."
		";

		$dbRes = $DB->Query($strSql);
		if ($arRes = $dbRes->Fetch())
		{
			$arRes['CHAT_TYPE'] = trim($arRes['CHAT_TYPE']);
			if ($arRes['CHAT_TYPE'] == IM_MESSAGE_OPEN)
			{
				if (intval($arRes['RID']) <= 0 && IM\User::getInstance($this->user_id)->isExtranet())
				{
					return false;
				}
			}
			else if (intval($arRes['RID']) <= 0)
			{
				return false;
			}
			unset($arRes['CHAT_TYPE']);
			unset($arRes['RID']);

			return $arRes;
		}

		return false;
	}

	/**
	 * @param $toChatId
	 * @param bool $fromUserId
	 * @param bool $loadExtraData
	 * @param bool $bTimeZone
	 * @param bool $limit
	 * @return array|bool
	 */
	function GetLastMessage($toChatId, $fromUserId = false, $loadExtraData = false, $bTimeZone = true, $limit = true)
	{
		global $DB;

		$fromUserId = intval($fromUserId);
		if ($fromUserId <= 0)
			$fromUserId = $this->user_id;

		$toChatId = intval($toChatId);
		if ($toChatId <= 0)
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_EMPTY_CHAT_ID"), "ERROR_TO_CHAT_ID");
			return false;
		}

		$orm = IM\Model\ChatTable::getById($toChatId);
		if (!($chatData = $orm->fetch()))
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_CHAT_NOT_EXISTS"), "ERROR_CHAT_NOT_EXISTS");
			return false;
		}

		if ($chatData['TYPE'] == IM_MESSAGE_OPEN && !CIMMessenger::CheckEnableOpenChat())
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_CHAT_NOT_EXISTS"), "ERROR_CHAT_NOT_EXISTS");
			return false;
		}

		$sqlLimit = '';
		if ($limit)
		{
			if ($DB->type == "MSSQL")
			{
				$sqlLimit = " AND M.DATE_CREATE > dateadd(day, -30, getdate())";
			}
			elseif ($DB->type == "ORACLE")
			{
				$sqlLimit = " AND M.DATE_CREATE > SYSDATE-30";
			}
			else
			{
				//$sqlLimit = " AND M.DATE_CREATE > DATE_SUB(NOW(), INTERVAL 30 DAY)";
				$connection = \Bitrix\Main\Application::getInstance()->getConnection();
				$helper = $connection->getSqlHelper();
				$sqlLimit = " AND M.DATE_CREATE > ".$helper->addDaysToDateTime(-30);
			}
		}

		$readService = new IM\V2\Message\ReadService($fromUserId);
		$lastMessageIdInChat = $readService->getLastMessageIdInChat($toChatId);
		$limitById = '';
		$limitFetchMessages = 30;
		$relations = \CIMChat::GetRelationById($toChatId, false, $bTimeZone, false);
		if (isset($relations[$fromUserId]))
		{
			if ($relations[$fromUserId]['START_ID'] > 0)
			{
				$limitById = 'AND M.ID >= '.intval($relations[$fromUserId]['START_ID']);
			}

			//if ($relations[$fromUserId]['STATUS'] != IM_STATUS_READ && $relations[$fromUserId]['COUNTER'] > $limitFetchMessages)
			$messageCountFilter = \Bitrix\Main\ORM\Query\Query::filter()
				->where('ID', '>=', (int)$relations[$fromUserId]['START_ID'])
				->where('ID', '>=', (int)$relations[$fromUserId]['LAST_ID'])
				->where('ID', '<=', $lastMessageIdInChat)
				->where('CHAT_ID', $toChatId)
			;
			$messageCount = \Bitrix\Im\Model\MessageTable::getCount($messageCountFilter);
			$limitFetchMessages = max($messageCount, 30);
		}

		if (!$bTimeZone)
			CTimeZone::Disable();

		$lineId = 0;
		$crmEntityType = null;
		$crmEntityId = null;
		if (
			$chatData['TYPE'] == IM_MESSAGE_OPEN_LINE
			&& \Bitrix\Main\Loader::includeModule('imopenlines')
		)
		{
			$explodeData = explode('|', $chatData['ENTITY_DATA_1']);
			$crmEntityType = ($explodeData[0] == 'Y') ? $explodeData[1] : null;
			$crmEntityId = ($explodeData[0] == 'Y') ? intval($explodeData[2]) : null;

			$lineId = \Bitrix\ImOpenLines\Chat::parseLinesChatEntityId($chatData['ENTITY_ID'])['lineId'];
		}

		$strSql = "";
		if ($chatData['TYPE'] == IM_MESSAGE_OPEN)
		{
			$strSql = "
				SELECT
					M.ID,
					M.CHAT_ID,
					M.MESSAGE,
					".$DB->DatetimeToTimestampFunction('M.DATE_CREATE')." as DATE_CREATE,
					M.AUTHOR_ID,
					C.TYPE as CHAT_TYPE,
					C.ENTITY_TYPE as CHAT_ENTITY_TYPE,
					R.USER_ID as RID
				FROM b_im_message M
				INNER JOIN b_im_chat C ON C.ID = M.CHAT_ID AND C.TYPE = '".IM_MESSAGE_OPEN."'
				LEFT JOIN b_im_relation R ON R.CHAT_ID = M.CHAT_ID AND R.USER_ID = ".$fromUserId."
				WHERE
					M.CHAT_ID = ".$toChatId."
					".$limitById."
					#LIMIT#
				ORDER BY M.DATE_CREATE DESC
			";
		}
		else if (
			$chatData['TYPE'] == IM_MESSAGE_OPEN_LINE
			&& \Bitrix\Main\Loader::includeModule('imopenlines')
			&& \Bitrix\ImOpenLines\Config::canJoin($lineId, $crmEntityType, $crmEntityId)
		)
		{
			$strSql = "
				SELECT
					M.ID,
					M.CHAT_ID,
					M.MESSAGE,
					".$DB->DatetimeToTimestampFunction('M.DATE_CREATE')." as DATE_CREATE,
					M.AUTHOR_ID,
					C.TYPE as CHAT_TYPE,
					C.ENTITY_TYPE as CHAT_ENTITY_TYPE,
					R.USER_ID as RID
				FROM b_im_message M
				INNER JOIN b_im_chat C ON C.ID = M.CHAT_ID AND C.TYPE = '".IM_MESSAGE_OPEN_LINE."'
				LEFT JOIN b_im_relation R ON R.CHAT_ID = M.CHAT_ID AND R.USER_ID = ".$fromUserId."
				WHERE
					M.CHAT_ID = ".$toChatId."
					".$limitById."
					#LIMIT#
				ORDER BY M.DATE_CREATE DESC
			";

			\Bitrix\Im\Disk\NoRelationPermission::add($toChatId, $fromUserId);
		}
		else if (isset($relations[$fromUserId]))
		{
			$strSql = "
				SELECT
					M.ID,
					M.CHAT_ID,
					M.MESSAGE,
					".$DB->DatetimeToTimestampFunction('M.DATE_CREATE')." as DATE_CREATE,
					M.AUTHOR_ID,
					C.TYPE as CHAT_TYPE,
					C.ENTITY_TYPE as CHAT_ENTITY_TYPE,
					'".$fromUserId."' as RID
				FROM b_im_message M
				INNER JOIN b_im_chat C ON C.ID = M.CHAT_ID
				WHERE
					M.CHAT_ID = ".$toChatId."
					".$limitById."
					#LIMIT#
				ORDER BY M.DATE_CREATE DESC
			";
		}
		else
		{
			if (
				$chatData['TYPE'] == IM_MESSAGE_OPEN_LINE
				&& \Bitrix\Main\Loader::includeModule('imopenlines')
				&& \Bitrix\ImOpenLines\Model\RecentTable::getCount([
					'=CHAT_ID' => $toChatId,
					'=USER_ID' => $fromUserId,
				])
			)
			{
				$strSql = "
					SELECT
						M.ID,
						M.CHAT_ID,
						M.MESSAGE,
						".$DB->DatetimeToTimestampFunction('M.DATE_CREATE')." as DATE_CREATE,
						M.AUTHOR_ID,
						C.TYPE as CHAT_TYPE,
						C.ENTITY_TYPE as CHAT_ENTITY_TYPE,
						'".$fromUserId."' as RID
					FROM b_im_message M
					INNER JOIN b_im_chat C ON C.ID = M.CHAT_ID
					WHERE
						M.CHAT_ID = ".$toChatId."
						".$limitById."
						#LIMIT#
					ORDER BY M.DATE_CREATE DESC
				";
			}
		}

		if (!$bTimeZone)
			CTimeZone::Enable();

		$chatType = $chatData['TYPE'];
		$chatRelationUserId = 0;

		$arUsers = Array();
		$arMessages = Array();
		$arMessageId = Array();
		$arUsersMessage = Array();
		$arUnreadMessages = Array();
		$readedList = Array();

		if ($strSql)
		{
			$strSql = $DB->TopSql($strSql, $limitFetchMessages);
			//LEFT JOIN b_im_message_param MP on MP.MESSAGE_ID = M.ID and MP.PARAM_NAME = 'FOR_USER_ID'
			//and (MP.PARAM_VALUE is null or MP.PARAM_VALUE = '".$fromUserId."')

			if ($limit)
			{
				$dbRes = $DB->Query(str_replace("#LIMIT#", $sqlLimit, $strSql));
				if (!$dbRes->SelectedRowsCount())
					$dbRes = $DB->Query(str_replace("#LIMIT#", "", $strSql));
			}
			else
			{
				$dbRes = $DB->Query(str_replace("#LIMIT#", "", $strSql));
			}

			$lastReads = $readService
				->getViewedService()
				->getDateViewedByMessageIdForEachUser($lastMessageIdInChat, array_keys($relations))
			;
			while ($arRes = $dbRes->Fetch())
			{
				if ($arRes['CHAT_ENTITY_TYPE'] != 'LIVECHAT' && \Bitrix\Im\User::getInstance($fromUserId)->isConnector())
				{
					return false;
				}
				$arRes['CHAT_TYPE'] = trim($arRes['CHAT_TYPE']);

				$chatType = $arRes['CHAT_TYPE'];
				$chatRelationUserId = intval($arRes['RID']);

				$arMessages[$arRes['ID']] = Array(
					'id' => $arRes['ID'],
					'chatId' => $arRes['CHAT_ID'],
					'senderId' => $arRes['AUTHOR_ID'],
					'recipientId' => $arRes['CHAT_ID'],
					'date' => DateTime::createFromTimestamp($arRes['DATE_CREATE']),
					'text' => \Bitrix\Im\Text::parse($arRes['MESSAGE']),
					'textLegacy' => \Bitrix\Im\Text::parseLegacyFormat($arRes['MESSAGE']),
				);

				$arMessageId[] = $arRes['ID'];
				if ($arRes['AUTHOR_ID'] > 0)
				{
					$arUsers[] = $arRes['AUTHOR_ID'];
				}
				if (isset($relations[$fromUserId]) && $relations[$fromUserId]['LAST_ID'] < $arRes['ID'])
				{
					$arUnreadMessages['chat'.$arRes['CHAT_ID']][] = $arRes['ID'];
				}
				$arUsersMessage[$arRes['CHAT_ID']][] = $arRes['ID'];

				foreach ($relations as $userId => $relation)
				{
					$readedList['chat'.$arRes['CHAT_ID']][$relation['USER_ID']] = Array(
						'messageId' => $relation['LAST_ID'],
						'date' => $lastReads[$userId] ?? null,
					);
				}
			}

			foreach ($arUsersMessage as $chatId => $messageIds)
			{
				$arUsersMessage[$chatId] = array_values(array_unique($messageIds));
			}
		}

		if (
			$chatType == IM_MESSAGE_OPEN && $chatRelationUserId <= 0
			|| $chatType == IM_MESSAGE_OPEN_LINE && $chatRelationUserId <= 0
		)
		{
			if (IM\User::getInstance($fromUserId)->isExtranet())
			{
				$arMessages = Array();
				$arMessageId = Array();
				$arUsersMessage = Array();
				$loadExtraData = false;
			}
			else if (
				CModule::IncludeModule('pull')
				&& \Bitrix\Im\V2\Chat::getInstance($toChatId)->checkAccess($fromUserId)->isSuccess()
			)
			{
				CPullWatch::Add($fromUserId, 'IM_PUBLIC_'.$toChatId, true);
			}
		}

		$params = CIMMessageParam::Get($arMessageId);

		$arFiles = Array();
		foreach ($params as $messageId => $param)
		{
			$arMessages[$messageId]['params'] = $param;

			if (
				mb_strlen($arMessages[$messageId]['text']) <= 0
				&& !isset($param['FILE_ID'])
				&& !isset($param['KEYBOARD'])
				&& !isset($param['ATTACH'])
			)
			{
				$arMessages[$messageId]['text'] = GetMessage('IM_MESSAGE_DELETED');
				$arMessages[$messageId]['params']['IS_DELETED'] = 'Y';
			}

			if (isset($param['FILE_ID']))
			{
				foreach ($param['FILE_ID'] as $fileId)
				{
					$arFiles[$fileId] = $fileId;
				}
			}
		}

		$arChatFiles = CIMDisk::GetFiles($toChatId, $arFiles);
		$arMessages = CIMMessageLink::prepareShow($arMessages, $params);

		$arResult = Array(
			'chatId' => $toChatId,
			'message' => $arMessages,
			'usersMessage' => $arUsersMessage,
			'unreadMessage' => $arUnreadMessages,
			'users' => Array(),
			'userInGroup' => Array(),
			'readedList' => $readedList,
			'files' => $arChatFiles
		);

		if (is_array($loadExtraData) || is_bool($loadExtraData) && $loadExtraData == true)
		{
			$bDepartment = true;
			if (is_array($loadExtraData) && $loadExtraData['DEPARTMENT'] == 'N')
				$bDepartment = false;

			$arChat = self::GetChatData(array(
				'ID' => $toChatId,
				'USE_CACHE' => 'N'
			));
			if (
				isset($arChat['chat'][$toChatId]) && $arChat['chat'][$toChatId]['message_type'] == IM_MESSAGE_OPEN
				|| isset($arChat['chat'][$toChatId]) && $arChat['chat'][$toChatId]['message_type'] == IM_MESSAGE_OPEN_LINE
				|| isset($arChat['userInChat'][$toChatId]) && in_array($fromUserId, $arChat['userInChat'][$toChatId])
			)
			{
				$arResult['lines']  = $arChat['lines'];
				$arResult['userInChat']  = $arChat['userInChat'];
				$arResult['userChatBlockStatus'] = $arChat['userChatBlockStatus'];

				$ar = CIMContactList::GetUserData(array(
						'ID' => array_values(array_merge($arUsers, $arChat['userInChat'][$toChatId])),
						'DEPARTMENT' => ($bDepartment? 'Y': 'N'),
						'USE_CACHE' => 'N'
					)
				);
				$arResult['users'] = $ar['users'];
				$arResult['userInGroup']  = $ar['userInGroup'];

				if ($arChat['chat'][$toChatId]['extranet'] === "")
				{
					$isExtranet = false;
					foreach ($ar['users'] as $userData)
					{
						if ($userData['extranet'])
						{
							$isExtranet = true;
							break;
						}
					}
					IM\Model\ChatTable::update($toChatId, Array('EXTRANET' => $isExtranet? "Y":"N"));

					$arChat['chat'][$toChatId]['extranet'] = $isExtranet;
				}
				$arResult['chat'] = $arChat['chat'];
			}
		}

		if ($chatData['ENTITY_TYPE'] == 'LINES' && $chatData['ENTITY_ID'] && CModule::IncludeModule('imopenlines'))
		{
			[, $lineId] = explode('|', $chatData["ENTITY_ID"]);
			$configManager = new \Bitrix\ImOpenLines\Config();
			$arResult['openlines']['canVoteAsHead'][$lineId] = $configManager->canVoteAsHead($lineId);
		}
		else if ($chatData['ENTITY_TYPE'] == 'LIVECHAT' && $chatData['ENTITY_ID'] && CModule::IncludeModule('imopenlines'))
		{
			[$lineId, $userId] = explode('|', $chatData["ENTITY_ID"]);
			$userCode = 'livechat|' . $lineId . '|' . $chatData['ID'] . '|' . $userId;
			unset($lineId, $userId);
			foreach ($arResult['users'] as $userId => $userData)
			{
				$arResult['users'][$userId] = \Bitrix\ImOpenLines\Connector::getOperatorInfo($lineId, $userId, $userCode);
			}
		}

		return $arResult;
	}

	function GetLastMessageLimit($chatId, $messageStartId, $messageEndId = 0, $loadExtraData = false, $bTimeZone = true, $order = 'DESC')
	{
		$messageStartId = intval($messageStartId);
		$messageEndId = intval($messageEndId);
		$chatId = intval($chatId);

		if ($chatId <= 0)
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_EMPTY_CHAT_ID"), "ERROR_TO_CHAT_ID");
			return false;
		}

		$orm = IM\Model\ChatTable::getById($chatId);
		if (!($chatData = $orm->fetch()))
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_CHAT_NOT_EXISTS"), "ERROR_CHAT_NOT_EXISTS");
			return false;
		}

		global $DB;
		if (!$bTimeZone)
			CTimeZone::Disable();

		$strSql = "
			SELECT
				M.ID,
				M.CHAT_ID,
				M.MESSAGE,
				".$DB->DatetimeToTimestampFunction('M.DATE_CREATE')." as DATE_CREATE,
				M.AUTHOR_ID,
				C.TYPE as CHAT_TYPE
			FROM b_im_message M
			INNER JOIN b_im_chat C ON C.ID = M.CHAT_ID
			WHERE
				M.CHAT_ID = ".$chatId."
				AND M.ID >= ".$messageStartId."
				".($messageEndId > 0? "AND M.ID <= ".$messageEndId: "")."
			ORDER BY M.DATE_CREATE ".($order == 'ASC'? 'ASC': 'DESC')."
		";

		if (!$bTimeZone)
			CTimeZone::Enable();

		$dbRes = $DB->Query($strSql);

		$arMessages = Array();
		$arMessageId = Array();
		$arUsers = Array();
		$arUsersMessage = Array();
		while ($arRes = $dbRes->Fetch())
		{
			$arMessages[$arRes['ID']] = Array(
				'id' => $arRes['ID'],
				'chatId' => $arRes['CHAT_ID'],
				'senderId' => $arRes['AUTHOR_ID'],
				'recipientId' => $arRes['CHAT_ID'],
				'date' => DateTime::createFromTimestamp($arRes['DATE_CREATE']),
				'text' => \Bitrix\Im\Text::parse($arRes['MESSAGE']),
				'textLegacy' => \Bitrix\Im\Text::parseLegacyFormat($arRes['MESSAGE']),
			);

			$arMessageId[] = $arRes['ID'];
			$arUsersMessage[$arRes['CHAT_ID']][] = $arRes['ID'];
			$arUsers[$arRes['CHAT_ID']][] = $arRes['AUTHOR_ID'];
		}

		if ($chatData['TYPE'] == IM_MESSAGE_OPEN_LINE)
		{
			\Bitrix\Im\Disk\NoRelationPermission::add($chatId, $this->user_id);
		}

		$params = CIMMessageParam::Get($arMessageId);

		$arFiles = Array();
		foreach ($params as $messageId => $param)
		{
			$arMessages[$messageId]['params'] = $param;
			if (isset($param['FILE_ID']))
			{
				foreach ($param['FILE_ID'] as $fileId)
				{
					$arFiles[$fileId] = $fileId;
				}
			}
		}

		$arChatFiles = CIMDisk::GetFiles($chatId, $arFiles); // TODO get files for sessions
		$arMessages = CIMMessageLink::prepareShow($arMessages, $params);

		$arResult = Array(
			'chatId' => $chatId,
			'message' => $arMessages,
			'usersMessage' => $arUsersMessage,
			'users' => Array(),
			'userInGroup' => Array(),
			'files' => $arChatFiles
		);

		if (is_array($loadExtraData) || is_bool($loadExtraData) && $loadExtraData == true)
		{
			$bDepartment = true;
			if (is_array($loadExtraData) && $loadExtraData['DEPARTMENT'] == 'N')
				$bDepartment = false;

			$arChat = self::GetChatData(array(
				'ID' => $chatId,
				'USE_CACHE' => 'N'
			));

			$arResult['lines']  = $arChat['lines'];
			$arResult['userInChat']  = $arChat['userInChat'];
			$arResult['userChatBlockStatus'] = $arChat['userChatBlockStatus'];

			$ar = CIMContactList::GetUserData(array(
					'ID' => $arUsers[$chatId],
					'DEPARTMENT' => ($bDepartment? 'Y': 'N'),
					'USE_CACHE' => 'N'
				)
			);
			$arResult['users'] = $ar['users'];
			$arResult['userInGroup']  = $ar['userInGroup'];
			$arResult['chat'] = $arChat['chat'];
		}

		return $arResult;
	}

	public static function getChatType($chatData)
	{
		return \Bitrix\Im\Chat::getType($chatData);
	}

	public function GetLastSendMessage($arParams)
	{
		global $DB;

		if (!isset($arParams['ID']))
			return false;

		$chatId = $arParams['ID'];

		$fromUserId = isset($arParams['FROM_USER_ID']) && intval($arParams['FROM_USER_ID'])>0? intval($arParams['FROM_USER_ID']): $this->user_id;
		$limit = isset($arParams['LIMIT']) && intval($arParams['LIMIT'])>0? intval($arParams['LIMIT']): false;
		$bTimeZone = isset($arParams['USE_TIME_ZONE']) && $arParams['USE_TIME_ZONE'] == 'N'? false: true;

		$arChatId = Array();
		if (is_array($chatId))
		{
			foreach ($chatId as $val)
				$arChatId[] = intval($val);
		}
		else
		{
			$arChatId[] = intval($chatId);
		}
		if (empty($arChatId))
			return Array();

		$sqlLimit = '';
		if ($limit)
		{
			if ($DB->type == "MSSQL")
			{
				$sqlLimit = " AND M.DATE_CREATE > dateadd(day, -".$limit.", getdate())";
			}
			elseif ($DB->type == "ORACLE")
			{
				$sqlLimit = " AND M.DATE_CREATE > SYSDATE-".$limit;
			}
			else
			{
				$connection = \Bitrix\Main\Application::getInstance()->getConnection();
				$helper = $connection->getSqlHelper();
				$sqlLimit = " AND M.DATE_CREATE > ". $helper->addDaysToDateTime(-1 * $limit);
			}
		}
		if (!$bTimeZone)
			CTimeZone::Disable();

		$strSql = "
			SELECT
				M.ID,
				M.CHAT_ID,
				M.MESSAGE,
				".$DB->DatetimeToTimestampFunction('M.DATE_CREATE')." as DATE_CREATE,
				M.AUTHOR_ID,
				C.TITLE as CHAT_TITLE,
				C.COLOR as CHAT_COLOR,
				C.ENTITY_TYPE as CHAT_ENTITY_TYPE,
				C.ENTITY_DATA_1 as CHAT_ENTITY_DATA_1,
				C.ENTITY_DATA_2 as CHAT_ENTITY_DATA_2,
				C.ENTITY_DATA_3 as CHAT_ENTITY_DATA_3,
				".$DB->DatetimeToTimestampFunction('C.DATE_CREATE')." as CHAT_DATE_CREATE,
				C.TYPE as CHAT_TYPE,
				R.ID as RID
			FROM b_im_message M
			INNER JOIN b_im_chat C ON C.ID = M.CHAT_ID AND C.LAST_MESSAGE_ID = M.ID
			LEFT JOIN b_im_relation R ON R.CHAT_ID = M.CHAT_ID AND R.USER_ID = ".$fromUserId."
			WHERE
				M.ID = C.LAST_MESSAGE_ID
				AND M.CHAT_ID IN (".implode(",",$arChatId).")
				".$sqlLimit."
		";
		if (!$bTimeZone)
			CTimeZone::Enable();

		$arMessages = Array();
		$enableOpenChat = CIMMessenger::CheckEnableOpenChat();
		$dbRes = $DB->Query($strSql);
		while ($arRes = $dbRes->Fetch())
		{
			$arRes['CHAT_TYPE'] = trim($arRes['CHAT_TYPE']);

			if ($arRes['CHAT_TYPE'] == IM_MESSAGE_OPEN)
			{
				if (!$enableOpenChat)
				{
					continue;
				}
				else if (intval($arRes['RID']) <= 0 && IM\User::getInstance($this->user_id)->isExtranet())
				{
					continue;
				}
			}
			else if (intval($arRes['RID']) <= 0)
			{
				continue;
			}

			$chatType = \Bitrix\Im\Chat::getType($arRes);

			$arMessages[$arRes['CHAT_ID']] = Array(
				'id' => $arRes['ID'],
				'senderId' => $arRes['AUTHOR_ID'],
				'recipientId' => $arRes['CHAT_ID'],
				'chatTitle' => \Bitrix\Im\Text::decodeEmoji($arRes['CHAT_TITLE']),
				'date' => DateTime::createFromTimestamp($arRes['DATE_CREATE']),
				'color' => $arRes["CHAT_COLOR"] == ""? IM\Color::getColorByNumber($arRes['CHAT_ID']): IM\Color::getColor($arRes['CHAT_COLOR']),
				'type' => $chatType,
				'messageType' => $arRes["CHAT_TYPE"],
				'text' => \Bitrix\Im\Text::parse($arRes['MESSAGE']),
				'textLegacy' => \Bitrix\Im\Text::parseLegacyFormat($arRes['MESSAGE']),
			);
		}

		return $arMessages;
	}

	public static function GetRelationById($ID, $userId = false, $timezone = true, $withCounter = true, bool $raw = false)
	{
		global $DB;

		$ID = intval($ID);
		$userId = intval($userId);
		$arResult = Array();

		if (!$timezone)
		{
			CTimeZone::Disable();
		}

		$strSql = "
			SELECT
				R.*,
				U.EXTERNAL_AUTH_ID
			FROM b_im_relation R
			LEFT JOIN b_user U ON U.ID = R.USER_ID
			WHERE R.CHAT_ID = ".$ID." ".($userId>0? "AND R.USER_ID = ".$userId: "");

		if (!$timezone)
		{
			CTimeZone::Enable();
		}

		$dbRes = $DB->Query($strSql);
		while ($arRes = $dbRes->Fetch())
			$arResult[$arRes['USER_ID']] = $arRes;

		if (!$raw)
		{
			$arResult = IM\Chat::filterRelationsByAccess($ID, $arResult);
		}

		if ($userId > 0)
			$arResult = isset($arResult[$userId])? $arResult[$userId]: false;

		if ($arResult === false)
		{
			return $arResult;
		}

		// region New counter
		if ($withCounter)
		{
			$readService = new IM\V2\Message\ReadService($userId);
			if ($userId > 0)
			{
				$arResult['COUNTER'] = $readService->getCounterService()->getByChatWithOverflow($ID);
				$lastRead =  $readService->getViewedService()->getDateViewedByMessageId($arResult['LAST_ID']);
				$arResult['LAST_READ'] = isset($lastRead) ? $lastRead->format('Y-m-d H:i:s') : null;
			}
			else
			{
				$userIds = array_keys($arResult);
				$counters = $readService->getCounterService()->getByChatForEachUsers($ID, $userIds);
				$lastIdInChat = $readService->getLastMessageIdInChat($ID);
				$lastReads = $readService->getViewedService()->getDateViewedByMessageIdForEachUser($lastIdInChat, $userIds);
				foreach ($arResult as $id => $user)
				{
					$arResult[$id]['COUNTER'] = $counters[$id] ?? 0;
					$arResult[$id]['LAST_READ'] = isset($lastReads[$id]) ? $lastReads[$id]->format('Y-m-d H:i:s') : null;
				}
			}
		}
		// endregion

		return $arResult;
	}

	public function GetPersonalChat(?int $userId = null)
	{
		if (!$userId)
		{
			$userId = $this->user_id;
		}

		$favoriteChatResult = \Bitrix\IM\V2\Chat\FavoriteChat::find(['TO_USER_ID' => $userId]);
		if (!$favoriteChatResult->hasResult())
		{
			$favoriteChatResult = IM\V2\Chat\ChatFactory::getInstance()->addChat([
				'TYPE' => \Bitrix\Im\V2\Chat::IM_TYPE_PRIVATE,
				'ENTITY_TYPE' => \Bitrix\Im\V2\Chat::ENTITY_TYPE_FAVORITE,
				'AUTHOR_ID' => $userId,
				'USERS' => [$userId],
				'MESSAGE' => GetMessage('IM_PERSONAL_DESCRIPTION')
			]);

			return $favoriteChatResult->getResult()['CHAT_ID'];
		}

		return $favoriteChatResult->getResult()['ID'];
	}

	/**
	 * @deprecated
	 * @use ...
	 * @param $fromUserId
	 * @param $toUserId
	 * @return array
	 */
	public static function GetPrivateRelation($fromUserId, $toUserId)
	{
		global $DB;

		$fromUserId = intval($fromUserId);
		$toUserId = intval($toUserId);

		$arResult = Array();
		$strSql = "
			SELECT
				RF.*
			FROM
				b_im_relation RF
				INNER JOIN b_im_relation RT on RF.CHAT_ID = RT.CHAT_ID
			WHERE
				RF.USER_ID = ".$fromUserId."
			and RT.USER_ID = ".$toUserId."
			and RF.MESSAGE_TYPE = '".IM_MESSAGE_PRIVATE."'
		";
		$dbRes = $DB->Query($strSql);
		if ($arRes = $dbRes->Fetch())
			$arResult = $arRes;

		return $arResult;
	}

	// region General Chat
	/**
	 * @deprecated Use \Bitrix\Im\V2\Chat\GeneralChat::getGeneralChatId()
	 */
	public static function GetGeneralChatId()
	{
		return IM\V2\Chat\GeneralChat::getGeneralChatId() ?? 0;
	}

	/**
	 * @deprecated Use \Bitrix\Im\V2\Chat\GeneralChat::add()
	 */
	public static function InstallGeneralChat($agentMode = false)
	{
		(new IM\V2\Chat\GeneralChat())->add([]);
	}

	/**
	 * @deprecated Use \Bitrix\Im\V2\Chat\GeneralChat::getAutoMessageStatus()
	 */
	public static function GetGeneralChatAutoMessageStatus($type)
	{
		return \Bitrix\Im\V2\Chat\GeneralChat::getAutoMessageStatus((string)$type);
	}

	/**
	 * @deprecated Use \Bitrix\Im\V2\Chat\GeneralChat::hasPostAccess()
	 */
	public static function CanSendMessageToGeneralChat($userId = null)
	{
		$generalChat = IM\V2\Chat\ChatFactory::getInstance()->getGeneralChat();
		if ($generalChat instanceof Chat\GeneralChat)
		{
			return $generalChat->hasManageMessagesAccess($userId);
		}

		$generalChatId = \COption::GetOptionString('im', 'general_chat_id');
		$generalChat = IM\V2\Chat::getInstance((int)$generalChatId);
		if ($generalChat instanceof IM\V2\Chat\GeneralChat)
		{
			return $generalChat->hasManageMessagesAccess($userId);
		}

		return false;
	}

	/**
	 * @deprecated Use \Bitrix\Im\V2\Chat::setManageMessages()
	 */
	public static function SetAccessToGeneralChat($allowAll = true, $allowCodes = Array())
	{
		$prevAllow = COption::GetOptionString("im", "allow_send_to_general_chat_all");
		$prevCodes = COption::GetOptionString("im", "allow_send_to_general_chat_rights");

		if ($allowAll)
		{
			$allow = 'Y';
			$codes = 'AU';
		}
		else
		{
			$allow = 'N';

			if (is_array($allowCodes) && count($allowCodes) > 0)
			{
				$codes = implode(",", $allowCodes);
			}
			else
			{
				$codes = "";
			}
		}
		COption::SetOptionString("im", "allow_send_to_general_chat_all", $allow);
		COption::SetOptionString("im", "allow_send_to_general_chat_rights", $codes);

		if ($prevAllow != $allow || $prevCodes != $codes)
		{
			if (CModule::IncludeModule('pull'))
			{
				CPullStack::AddShared(Array(
					'module_id' => 'im',
					'command' => 'generalChatAccess',
					'params' => Array(
						"status" => $prevAllow == 'Y' && $allow == 'N'? 'blocked': 'allowed'
					),
					'extra' => \Bitrix\Im\Common::getPullExtra()
				));
			}
		}

		return true;
	}

	/**
	 * @deprecated Use \Bitrix\Im\V2\Chat\GeneralChat::canJoinGeneralChat()
	 */
	public static function CanJoinGeneralChatId($userId)
	{
		$generalChat = IM\V2\Chat\ChatFactory::getInstance()->getGeneralChat();

		if ($generalChat)
		{
			return $generalChat->canJoinGeneralChat((int)$userId);
		}

		return false;
	}

	/**
	 * @deprecated Use \Bitrix\Im\V2\Chat\GeneralChat::linkGeneralChat()
	 */
	public static function linkGeneralChatId($chatId)
	{
		return IM\V2\Chat\GeneralChat::linkGeneralChat((int) $chatId);
	}

	/**
	 * @deprecated Use \Bitrix\Im\V2\Chat\GeneralChat::unlinkGeneralChat()
	 */
	public static function UnlinkGeneralChatId()
	{
		return IM\V2\Chat\GeneralChat::unlinkGeneralChat();
	}

	public static function AddGeneralMessage($arFields)
	{
		$arFields['MESSAGE_TYPE'] = IM_MESSAGE_OPEN;
		$arFields['TO_CHAT_ID'] = self::GetGeneralChatId();

		return CIMMessenger::Add($arFields);
	}
	// endregion

	public static function GetChatData($arParams = Array())
	{
		global $DB;

		$arParams['PHOTO_SIZE'] = isset($arParams['PHOTO_SIZE'])? intval($arParams['PHOTO_SIZE']): 200;

		$from = "
			FROM b_im_chat C
			LEFT JOIN b_im_alias A ON A.ENTITY_ID = C.ID AND A.ENTITY_TYPE = C.ENTITY_TYPE
			LEFT JOIN b_im_relation R1 ON C.ID = R1.CHAT_ID
		";
		$groupTypes = self::implodeTypesForQuery(self::getGroupTypes());

		if (isset($arParams['SKIP_PRIVATE']) && $arParams['SKIP_PRIVATE'] == 'Y')
		{
			$from .= " AND C.TYPE IN ({$groupTypes})";
		}

		$innerJoin = $whereUser = "";
		if (isset($arParams['GET_LIST']) && $arParams['GET_LIST'] == 'Y')
		{
			if (!isset($arParams['USER_ID']))
				return false;

			$innerJoin = "INNER JOIN b_im_relation R2 ON R2.CHAT_ID = C.ID";
			$whereGeneral = "WHERE R2.USER_ID = ".intval($arParams['USER_ID']);
		}
		else
		{
			$arFilter = Array();
			if (isset($arParams['ID']) && is_array($arParams['ID']))
			{
				foreach ($arParams['ID'] as $key => $value)
					$arFilter['ID'][$key] = intval($value);
			}
			else if (isset($arParams['ID']) && intval($arParams['ID']) > 0)
			{
				$arFilter['ID'][] = intval($arParams['ID']);
			}

			if (empty($arFilter['ID']))
			{
				return false;
			}

			if (isset($arParams['USER_ID']))
			{
				$innerJoin = "LEFT JOIN b_im_relation R2 ON R2.CHAT_ID = C.ID AND R2.USER_ID = ".intval($arParams['USER_ID']);
			}
			$whereGeneral = "WHERE C.ID IN (".implode(',', $arFilter['ID']).") ";
		}

		$connection = \Bitrix\Main\Application::getConnection();
		$helper = $connection->getSqlHelper();
		$strSql = "
			SELECT
				C.ID as CHAT_ID,
				C.PARENT_ID as CHAT_PARENT_ID,
				C.PARENT_MID as CHAT_PARENT_MID,
				C.TITLE as CHAT_TITLE,
				C.CALL_TYPE as CHAT_CALL_TYPE,
				C.AUTHOR_ID as CHAT_OWNER_ID,
				C.CALL_NUMBER as CHAT_CALL_NUMBER,
				C.EXTRANET as CHAT_EXTRANET,
				C.COLOR as CHAT_COLOR,
				C.TYPE as CHAT_TYPE,
				C.AVATAR,
				C.ENTITY_TYPE,
				C.ENTITY_DATA_1 as ENTITY_DATA_1,
				C.ENTITY_DATA_2 as ENTITY_DATA_2,
				C.ENTITY_DATA_3 as ENTITY_DATA_3,
				C.MESSAGE_COUNT as CHAT_MESSAGE_COUNT,
				C.MANAGE_USERS_ADD,
				C.MANAGE_USERS_DELETE,
				C.MANAGE_UI,
				C.MANAGE_SETTINGS,
				C.CAN_POST,
				A.ALIAS ALIAS_NAME,
				".$DB->DatetimeToTimestampFunction('C.DATE_CREATE')." as CHAT_DATE_CREATE,
				C.ENTITY_ID,
				R1.NOTIFY_BLOCK as RELATION_NOTIFY_BLOCK,
				R1.USER_ID as RELATION_USER_ID,
				R1.CALL_STATUS,
				R1.MANAGER as RELATION_MANAGER
				".(isset($arParams['USER_ID'])? ", R2.ID as RID": "")."
			".$from."
			".$innerJoin."
			".$whereGeneral."
		";

		$arChat = Array();
		$arLines = Array();
		$linesChatIds = [];
		$multidialogChats = [];
		$multidialogs = [];
		$arUserInChat = Array();
		$arUserCallStatus = Array();
		$arUserChatBlockStatus = Array();
		$arManagerList = Array();
		$enableOpenChat = CIMMessenger::CheckEnableOpenChat();
		$generalChatId = CIMChat::GetGeneralChatId();

		$dbRes = $DB->Query($strSql);
		while ($arRes = $dbRes->GetNext(true, false))
		{
			$arRes['CHAT_TYPE'] = trim($arRes['CHAT_TYPE']);

			if (isset($arParams['USER_ID']))
			{
				if ($arRes['CHAT_TYPE'] == IM_MESSAGE_OPEN)
				{
					if (!$enableOpenChat)
					{
						continue;
					}
					else if (intval($arRes['RID']) <= 0 && IM\User::getInstance($arParams['USER_ID'])->isExtranet())
					{
						continue;
					}
				}
				else if (intval($arRes['RID']) <= 0)
				{
					if ($arRes['CHAT_TYPE'] === IM_MESSAGE_OPEN_LINE && CModule::IncludeModule('imopenlines'))
					{
						$userCodeParts = \Bitrix\ImOpenLines\Session\Common::parseUserCode($arRes['ENTITY_ID']);
						if(!\Bitrix\ImOpenLines\Config::canJoin($userCodeParts['CONFIG_ID']))
						{
							continue;
						}
					}
					else
					{
						continue;
					}
				}
			}

			if (!isset($arChat[$arRes["CHAT_ID"]]))
			{
				$avatar = '/bitrix/js/im/images/blank.gif';
				if (intval($arRes["AVATAR"]) > 0)
				{
					$avatar = self::GetAvatarImage($arRes["AVATAR"], $arParams['PHOTO_SIZE']);
				}

				$chatType = \Bitrix\Im\Chat::getType($arRes);

				if ($arRes["ENTITY_TYPE"] == 'LINES')
				{
					$fieldData = explode("|", $arRes['ENTITY_DATA_1']);
					if ($fieldData[5] > 0)
					{
						$arLines[$arRes["CHAT_ID"]] = $fieldData[5];
					}
					else
					{
						$linesChatIds[] = (int)$arRes['CHAT_ID'];
					}
				}
				elseif (\Bitrix\Main\Loader::includeModule('imbot'))
				{
					if (in_array($arRes["ENTITY_TYPE"], [\Bitrix\ImBot\Bot\Support24::CHAT_ENTITY_TYPE, \Bitrix\ImBot\Bot\Network::CHAT_ENTITY_TYPE], true))
					{
						$multidialogChats[$arRes['CHAT_ID']] = [
							'type' => $arRes['ENTITY_TYPE'],
							'botId' => (int)$arRes['CHAT_OWNER_ID'],
						];
					}
				}
				else if ($generalChatId == $arRes['CHAT_ID'])
				{
					$arRes["ENTITY_TYPE"] = 'GENERAL';
				}

				$publicOption = '';
				if ($arRes['ALIAS_NAME'])
				{
					$publicOption = [
						'code' => $arRes['ALIAS_NAME'],
						'link' => IM\Alias::getPublicLink($arRes['ENTITY_TYPE'], $arRes['ALIAS_NAME'])
					];
				}

				$dateCreate = $arRes["CHAT_DATE_CREATE"]? DateTime::createFromTimestamp($arRes["CHAT_DATE_CREATE"]): false;

				$arChat[$arRes["CHAT_ID"]] = Array(
					'id' => $arRes["CHAT_ID"],
					'parent_chat_id' => (int)($arRes['CHAT_PARENT_ID'] ?? 0),
					'parent_message_id' => (int)($arRes['CHAT_PARENT_MID'] ?? 0),
					'name' => \Bitrix\Im\Text::decodeEmoji($arRes["CHAT_TITLE"]),
					'owner' => $arRes["CHAT_OWNER_ID"],
					'color' => $arRes["CHAT_COLOR"] == ""? IM\Color::getColorByNumber($arRes['CHAT_ID']): IM\Color::getColor($arRes['CHAT_COLOR']),
					'extranet' => $arRes["CHAT_EXTRANET"] == ""? "": ($arRes["CHAT_EXTRANET"] == "Y"? true: false),
					'avatar' => $avatar,
					'call' => trim($arRes["CHAT_CALL_TYPE"]),
					'call_number' => trim($arRes["CHAT_CALL_NUMBER"]),
					'entity_type' => trim($arRes["ENTITY_TYPE"]),
					'entity_id' => trim($arRes["ENTITY_ID"]),
					'entity_data_1' => trim($arRes["ENTITY_DATA_1"]),
					'entity_data_2' => trim($arRes["ENTITY_DATA_2"]),
					'entity_data_3' => trim($arRes["ENTITY_DATA_3"]),
					'message_count' => (int)($arRes['CHAT_MESSAGE_COUNT'] ?? 0),
					'public' => $publicOption,
					'mute_list' => array(),
					'manager_list' => array(),
					'date_create' => $dateCreate,
					'type' => $chatType,
					'entity_link' => IM\V2\Chat\EntityLink::getInstance(self::initChatByArray($arRes))->toRestFormat(),
					'permissions' => [
						'manage_users_add' => mb_strtolower($arRes['MANAGE_USERS_ADD']),
						'manage_users_delete' => mb_strtolower($arRes['MANAGE_USERS_DELETE']),
						'manage_ui' => mb_strtolower($arRes['MANAGE_UI']),
						'manage_settings' => mb_strtolower($arRes['MANAGE_SETTINGS']),
						'manage_messages' => mb_strtolower($arRes['CAN_POST']),
						'can_post' => mb_strtolower($arRes['CAN_POST']),
					],
					'text_field_enabled' => (new TextFieldEnabled((int)$arRes["CHAT_ID"]))->get(),
					'background_id' => (new Background((int)$arRes["CHAT_ID"]))->get(),
					'message_type' => $arRes["CHAT_TYPE"],
					'is_new' => CIMChat::isNewChat($arRes['CHAT_TYPE'], $dateCreate ?: null),
				);
				$arUserInChat[$arRes["CHAT_ID"]] = [];
				$arUserChatBlockStatus[$arRes["CHAT_ID"]] = [];
				$arUserCallStatus[$arRes["CHAT_ID"]] = [];
				$arManagerList[$arRes["CHAT_ID"]] = [];
			}
			if (isset($arRes['RELATION_USER_ID']))
			{
				$arRes["RELATION_USER_ID"] =  (int)$arRes["RELATION_USER_ID"];
				$arUserInChat[$arRes["CHAT_ID"]][] = $arRes["RELATION_USER_ID"];
				$arUserChatBlockStatus[$arRes["CHAT_ID"]][$arRes["RELATION_USER_ID"]] = $arRes["RELATION_NOTIFY_BLOCK"] == 'Y';
				$arUserCallStatus[$arRes["CHAT_ID"]][$arRes["RELATION_USER_ID"]] = trim($arRes["CALL_STATUS"]);
				$arChat[$arRes["CHAT_ID"]]['mute_list'] = $arUserChatBlockStatus[$arRes["CHAT_ID"]];
				if ($arRes["RELATION_MANAGER"] == 'Y')
				{
					$arManagerList[$arRes["CHAT_ID"]][] = (int)$arRes["RELATION_USER_ID"];
				}
				$arChat[$arRes["CHAT_ID"]]['manager_list'] = $arManagerList[$arRes["CHAT_ID"]] ?? null;
			}
		}

		foreach ($arUserInChat as $chatId => $userIds)
		{
			$arUserInChat[$chatId] = array_values(array_unique($userIds));

			if (isset($multidialogChats[$chatId]) && count($arUserInChat[$chatId]) == 2)
			{
				foreach ($arUserInChat[$chatId] as $userId)
				{
					if ($userId != $multidialogChats[$chatId]['botId'])
					{
						$multidialog = self::getMultidialog(
							$multidialogChats[$chatId]['type'],
							$chatId,
							$userId,
							$multidialogChats[$chatId]['botId']
						);

						if ($multidialog)
						{
							$multidialogs[$chatId] = $multidialog;
						}

						break;
					}
				}
			}
		}

		$lines = Array();
		if (CModule::IncludeModule('imopenlines'))
		{
			if (!empty($arLines))
			{
				$orm = SessionTable::getList(Array(
					'select' => Array(
						'CHAT_ID',
						'ID',
						'STATUS',
						'DATE_CREATE',
						'CONFIG_ID',
						'PAUSE',
						'CLOSED',
						'OPERATOR_ID',
					),
					'filter' => Array(
						'=ID' => array_values($arLines)
					)
				));
				while($row = $orm->fetch())
				{
					$statusGroup = null;

					if (isset($row['STATUS']))
					{
						$statusGroup = Bitrix\ImOpenLines\V2\Status\StatusGroup::getFromNumericalCode((int)$row['STATUS']);
					}

					$lines[$row['CHAT_ID']] = Array(
						'id' => (int)$row['ID'],
						'status' => (int)$row['STATUS'],
						'date_create' => $row['DATE_CREATE'],
						'statusGroup' => $statusGroup->name,
						'queueId' => $row['CONFIG_ID'],
						'pinned' => $row['PAUSE'] === 'Y',
						'isClosed' => $row['CLOSED'] === 'Y',
						'operatorId' => (int)$row['OPERATOR_ID'],
					);
				}
			}

			if (!empty($linesChatIds))
			{
				$orm = SessionTable::getList([
					'select' => [
						new ExpressionField('ID', 'MAX(ID)'),
					],
					'filter' => [
						'=CHAT_ID' => array_values($linesChatIds),
					],
					'group' => ['CHAT_ID'],
				]);

				$ids = [];

				while($row = $orm->fetch())
				{
					$ids[] = $row['ID'];
				}

				$orm = SessionTable::getList([
					'select' => [
						'CHAT_ID',
						'ID',
						'STATUS',
						'DATE_CREATE',
						'CONFIG_ID',
						'PAUSE',
						'CLOSED',
						'OPERATOR_ID',
					],
					'filter' => [
						'=ID' => $ids,
					],
				]);

				while($row = $orm->fetch())
				{
					$statusGroup = null;

					if (isset($row['STATUS']))
					{
						$statusGroup = Bitrix\ImOpenLines\V2\Status\StatusGroup::getFromNumericalCode((int)$row['STATUS']);
					}

					$lines[$row['CHAT_ID']] = [
						'id' => (int)$row['ID'],
						'status' => (int)$row['STATUS'],
						'date_create' => $row['DATE_CREATE'],
						'statusGroup' => $statusGroup->name,
						'queueId' => $row['CONFIG_ID'],
						'pinned' => $row['PAUSE'] === 'Y',
						'isClosed' => $row['CLOSED'] === 'Y',
						'operatorId' => (int)$row['OPERATOR_ID'],
					];
				}
			}
		}

		$result = [
			'chat' => $arChat,
			'lines' => $lines,
			'multidialogs' => $multidialogs,
			'userInChat' => $arUserInChat,
			'userCallStatus' => $arUserCallStatus,
			'userChatBlockStatus' => $arUserChatBlockStatus
		];

		return $result;
	}

	public static function getMultidialog($type, $chatId, $userId, $botId)
	{
		if ($type === \Bitrix\ImBot\Bot\Support24::CHAT_ENTITY_TYPE)
		{
			/** @var \Bitrix\Imbot\Bot\SupportBot $classSupport */
			if (
				\Bitrix\Main\Loader::includeModule('bitrix24')
				&& \Bitrix\ImBot\Bot\Support24::isEnabled()
			)
			{
				$classSupport = \Bitrix\ImBot\Bot\Support24::class;
			}
			elseif (\Bitrix\ImBot\Bot\SupportBox::isEnabled())
			{
				$classSupport = \Bitrix\ImBot\Bot\SupportBox::class;
			}

			$multidialog = $classSupport::getMultidialog((int)$chatId, (int)$botId, $userId);
		}
		elseif($type === \Bitrix\ImBot\Bot\Network::CHAT_ENTITY_TYPE)
		{
			$multidialog = \Bitrix\ImBot\Bot\Network::getMultidialog((int)$chatId, (int)$botId, $userId);
		}

		return $multidialog;
	}

	public static function GetOpenChatData($arParams = Array())
	{
		global $DB;

		$arParams['PHOTO_SIZE'] = isset($arParams['PHOTO_SIZE'])? intval($arParams['PHOTO_SIZE']): 100;

		$strSql = "
			SELECT
				C.ID as CHAT_ID,
				C.TITLE as CHAT_TITLE,
				C.CALL_TYPE as CHAT_CALL_TYPE,
				C.AUTHOR_ID as CHAT_OWNER_ID,
				C.CALL_NUMBER as CHAT_CALL_NUMBER,
				C.EXTRANET as CHAT_EXTRANET,
				C.COLOR as CHAT_COLOR,
				C.TYPE as CHAT_TYPE,
				C.AVATAR,
				C.ENTITY_TYPE,
				C.ENTITY_DATA_1,
				C.ENTITY_DATA_2,
				C.ENTITY_DATA_3,
				".$DB->DatetimeToTimestampFunction('C.DATE_CREATE')." as CHAT_DATE_CREATE,
				C.ENTITY_ID,
				R2.NOTIFY_BLOCK as RELATION_NOTIFY_BLOCK,
				R2.USER_ID as RELATION_USER_ID,
				R2.USER_ID as RELATION_MANAGER,
				R2.CALL_STATUS,
				R2.ID as RID
			FROM 
				b_im_chat C
				LEFT JOIN b_im_relation R2 ON R2.CHAT_ID = C.ID AND R2.USER_ID = ".(int)$arParams['USER_ID']."
			WHERE 
				C.TYPE = '".IM_MESSAGE_OPEN."' 
				AND EXISTS(SELECT R3.ID FROM b_im_relation R3 WHERE R3.CHAT_ID = C.ID LIMIT 1)
		";

		$arChat = Array();
		$arUserInChat = Array();
		$arUserCallStatus = Array();
		$arUserChatBlockStatus = Array();
		$arManagerList = Array();

		$generalChatId = CIMChat::GetGeneralChatId();

		$dbRes = $DB->Query($strSql);
		while ($arRes = $dbRes->GetNext(true, false))
		{
			if (intval($arRes['RID']) <= 0 && IM\User::getInstance($arParams['USER_ID'])->isExtranet())
			{
				continue;
			}

			$arRes['CHAT_TYPE'] = trim($arRes['CHAT_TYPE']);

			if (!isset($arChat[$arRes["CHAT_ID"]]))
			{
				$avatar = '/bitrix/js/im/images/blank.gif';
				if (intval($arRes["AVATAR"]) > 0)
				{
					$avatar = self::GetAvatarImage($arRes["AVATAR"], $arParams['PHOTO_SIZE']);
				}

				$chatType = \Bitrix\Im\Chat::getType($arRes);

				if ($generalChatId == $arRes['CHAT_ID'])
				{
					$arRes["ENTITY_TYPE"] = 'GENERAL';
				}

				$arChat[$arRes["CHAT_ID"]] = Array(
					'id' => $arRes["CHAT_ID"],
					'name' => \Bitrix\Im\Text::decodeEmoji($arRes["CHAT_TITLE"]),
					'owner' => $arRes["CHAT_OWNER_ID"],
					'color' => $arRes["CHAT_COLOR"] == ""? IM\Color::getColorByNumber($arRes['CHAT_ID']): IM\Color::getColor($arRes['CHAT_COLOR']),
					'extranet' => $arRes["CHAT_EXTRANET"] == ""? "": ($arRes["CHAT_EXTRANET"] == "Y"? true: false),
					'avatar' => $avatar,
					'call' => trim($arRes["CHAT_CALL_TYPE"]),
					'call_number' => trim($arRes["CHAT_CALL_NUMBER"]),
					'entity_type' => trim($arRes["ENTITY_TYPE"]),
					'entity_data_1' => trim($arRes["ENTITY_DATA_1"]),
					'entity_data_2' => trim($arRes["ENTITY_DATA_2"]),
					'entity_data_3' => trim($arRes["ENTITY_DATA_3"]),
					'mute_list' => array(),
					'manager_list' => array(),
					'date_create' => $arRes["CHAT_DATE_CREATE"]? DateTime::createFromTimestamp($arRes["CHAT_DATE_CREATE"]): false,
					'entity_id' => trim($arRes["ENTITY_ID"]),
					'type' => $chatType,
					'message_type' => $arRes["CHAT_TYPE"],
				);

			}
			$arUserChatBlockStatus[$arRes["CHAT_ID"]][$arRes["RELATION_USER_ID"]] = $arRes['RELATION_NOTIFY_BLOCK'] == 'Y';
			$arUserInChat[$arRes["CHAT_ID"]][] = $arRes["RELATION_USER_ID"];
			$arUserCallStatus[$arRes["CHAT_ID"]][$arRes["RELATION_USER_ID"]] = trim($arRes["CALL_STATUS"] ?? '');
			$arChat[$arRes["CHAT_ID"]]['mute_list'] = $arUserChatBlockStatus[$arRes["CHAT_ID"]];

			if ($arRes["RELATION_MANAGER"] == 'Y')
			{
				$arManagerList[$arRes["CHAT_ID"]][] = (int)$arRes["RELATION_USER_ID"];
			}
			$arChat[$arRes["CHAT_ID"]]['manager_list'] = $arManagerList[$arRes["CHAT_ID"]] ?? null;
		}

		$result = array(
			'chat' => $arChat,
			'userInChat' => $arUserInChat,
			'userCallStatus' => $arUserCallStatus,
			'userChatBlockStatus' => $arUserChatBlockStatus
		);

		return $result;
	}

	public function SetReadMessage($chatId, $lastId = null, $byEvent = false)
	{
		global $DB;

		$chatId = intval($chatId);
		if ($chatId <= 0)
			return false;

		CIMMessenger::SpeedFileDelete($this->user_id, IM_SPEED_GROUP);

		$chat = IM\V2\Chat::getInstance($chatId);

		if (
			$chat->getType() == IM_MESSAGE_OPEN_LINE
			&& $chat->getAuthorId() == 0
		)
		{
			return false;
		}

		$readService = new IM\V2\Message\ReadService($this->user_id);

		$startId = $readService->getLastIdByChatId($chatId);
		$counter = 0;
		$viewedMessages = [];

		if (isset($lastId))
		{
			$message = new \Bitrix\Im\V2\Message();
			$message->setMessageId((int)$lastId)->setChatId($chatId);
			$readResult = $readService->readTo($message);
			$counter = $readResult->getResult()['COUNTER'];
			$viewedMessages = $readResult->getResult()['VIEWED_MESSAGES'];
		}
		else
		{
			$counter = $readService->readAllInChat($chatId)->getResult()['COUNTER'];
		}

		$relation = CIMMessage::SetLastId($chatId, $this->user_id, 0);

		if (!$relation)
		{
			return false;
		}

		$endId = (int)($relation['LAST_ID'] ?? 0);

		/*\Bitrix\Main\Application::getConnection()->query(
			"UPDATE b_im_recent SET DATE_UPDATE = NOW() WHERE USER_ID = ".$this->user_id." AND ITEM_CID = ".intval($chatId)
		);*/

		if (CModule::IncludeModule("pull"))
		{
			CIMNotify::DeleteBySubTag("IM_MESS_".$chatId.'_'.$this->user_id, false, false);
			CPushManager::DeleteFromQueueBySubTag($this->user_id, 'IM_MESS');

			if (
				$chat->getEntityType() == 'LIVECHAT'
				|| !\Bitrix\Im\User::getInstance($this->user_id)->isConnector()
			)
			{
				\Bitrix\Pull\Event::add($this->user_id, Array(
					'module_id' => 'im',
					'command' => 'readMessageChat',
					'params' => Array(
						'dialogId' => 'chat'.$chatId,
						'chatId' => (int)$chatId,
						'parentChatId' => $chat->getParentChatId(),
						'type' => $chat->getExtendedType(),
						'lastId' => $endId,
						'counter' => $counter,
						'muted' => $relation['NOTIFY_BLOCK'] === 'Y',
						'unread' => Im\Recent::isUnread($this->user_id, $relation['MESSAGE_TYPE'], 'chat'.$chatId),
						'lines' => $relation['MESSAGE_TYPE'] === IM_MESSAGE_OPEN_LINE,
						'viewedMessages' => $viewedMessages,
						'counterType' => $chat->getCounterType()->value,
						'recentConfig' => $chat->getRecentConfig()->toPullFormat(),
					),
					'extra' => \Bitrix\Im\Common::getPullExtra()
				));
			}

			$arRelation = self::GetRelationById($chatId, false, true, false);
			unset($arRelation[$this->user_id]);

			$pushMessage = Array(
				'module_id' => 'im',
				'command' => 'readMessageChatOpponent',
				'expiry' => 600,
				'params' => Array(
					'dialogId' => 'chat'.$chatId,
					'chatId' => (int)$chatId,
					'userId' => (int)$this->user_id,
					'userName' => \Bitrix\Im\User::getInstance($this->user_id)->getFullName(false),
					'lastId' => $endId,
					'date' => date('c', time()),
					'viewedMessages' => $viewedMessages,
					'chatMessageStatus' => $relation['CHAT_MESSAGE_STATUS'],
				),
				'extra' => \Bitrix\Im\Common::getPullExtra()
			);
			if ($chat->getEntityType() == 'LINES')
			{
				foreach ($arRelation as $rel)
				{
					if ($rel["EXTERNAL_AUTH_ID"] == 'imconnector')
					{
						unset($arRelation[$rel["USER_ID"]]);
					}
				}
			}
			if (count($arRelation) < 200)
			{
				\Bitrix\Pull\Event::add(array_keys($arRelation), $pushMessage);
				if ($chat->needToSendPublicPull())
				{
					CPullWatch::AddToStack('IM_PUBLIC_'.$chatId, $pushMessage);
				}
			}
		}

		foreach(GetModuleEvents("im", "OnAfterChatRead", true) as $arEvent)
		{
			ExecuteModuleEventEx($arEvent, array(Array(
				'CHAT_ID' => $chat->getChatId(),
				'CHAT_ENTITY_TYPE' => $chat->getEntityType(),
				'CHAT_ENTITY_ID' => $chat->getEntityId(),
				'START_ID' => $startId,
				'END_ID' => $endId,
				'COUNT' => $relation['COUNTER'],
				'USER_ID' => $this->user_id,
				'BY_EVENT' => $byEvent
			)));
		}

		return Array(
			'DIALOG_ID' => 'chat'.$chatId,
			'CHAT_ID' => (int)$chatId,
			'LAST_ID' => $endId,
			'COUNTER' => (int)$relation['COUNTER']
		);
	}

	public function SetUnReadMessage($chatId, $lastId)
	{
		$chatId = intval($chatId);
		if ($chatId <= 0)
			return false;

		$lastId = intval($lastId);
		if (intval($lastId) <= 0)
			return false;

		/*$result = Bitrix\Im\V2\Chat::getInstance($chatId)->unreadToMessage(new IM\V2\Message($lastId));

		return $result->isSuccess();*/
		$readService = new IM\V2\Message\ReadService($this->user_id);
		$endId = $readService->getLastMessageIdInChat($chatId);
		$relation = CIMMessage::SetLastIdForUnread($chatId, $this->user_id, $lastId);
		if ($relation)
		{
			$chat = Bitrix\Im\V2\Chat::getInstance($chatId);
			\Bitrix\Main\Application::getConnection()->query(
				"UPDATE b_im_recent SET DATE_UPDATE = NOW() WHERE USER_ID = ".$this->user_id." AND ITEM_CID = ".intval($chatId)
			);

			CIMMessenger::SpeedFileDelete($this->user_id, IM_SPEED_GROUP);

			if (CModule::IncludeModule("pull"))
			{
				\Bitrix\Pull\Event::add($this->user_id, Array(
					'module_id' => 'im',
					'command' => 'unreadMessageChat',
					'params' => Array(
						'dialogId' => 'chat'.$chatId,
						'chatId' => (int)$chatId,
						'lastId' => $endId,
						'date' => new DateTime(),
						'counter' => (int)$relation['COUNTER'],
						'muted' => $relation['NOTIFY_BLOCK'] === 'Y',
						'lines' => $relation['MESSAGE_TYPE'] === IM_MESSAGE_OPEN_LINE,
						'unreadTo' => $lastId,
						'unread' => Im\Recent::isUnread($this->user_id, $relation['MESSAGE_TYPE'], 'chat'.$chatId),
						'lastMessageViews' => Im\Common::toJson($chat->getLastMessageViews()),
						'counterType' => $chat->getCounterType()->value,
						'recentConfig' => $chat->getRecentConfig()->toPullFormat(),
					),
					'push' => Array('badge' => 'Y'),
					'extra' => \Bitrix\Im\Common::getPullExtra()
				));

				$arRelation = self::GetRelationById($chatId, false, true, false);
				unset($arRelation[$this->user_id]);

				$pushMessage = Array(
					'module_id' => 'im',
					'command' => 'unreadMessageChatOpponent',
					'expiry' => 600,
					'params' => Array(
						'dialogId' => 'chat'.$chatId,
						'chatId' => (int)$chatId,
						'userId' => (int)$this->user_id,
						'chatMessageStatus' => $relation['CHAT_MESSAGE_STATUS'],
						'unreadTo' => $lastId,
						'lastMessageStatuses' => $lastMessageStatuses,
					),
					'extra' => \Bitrix\Im\Common::getPullExtra()
				);
				if ($chat->getEntityType() == 'LINES')
				{
					foreach ($arRelation as $rel)
					{
						if ($rel["EXTERNAL_AUTH_ID"] == 'imconnector')
						{
							unset($arRelation[$rel["USER_ID"]]);
						}
					}
				}
				$viewsByGroups = $chat->getLastMessageViewsByGroups();
				$usersForPush = array_keys($arRelation);
				$viewers = array_intersect($usersForPush, $viewsByGroups['USERS'] ?? []);
				$notViewers = array_diff($usersForPush, $viewers);
				$pushMessage['params']['lastMessageViews'] = Im\Common::toJson($viewsByGroups['FOR_VIEWERS'] ?? []);
				\Bitrix\Pull\Event::add($viewers, $pushMessage);
				$pushMessage['params']['lastMessageViews'] = Im\Common::toJson($viewsByGroups['FOR_NOT_VIEWERS'] ?? []);
				\Bitrix\Pull\Event::add($notViewers, $pushMessage);
				/*\Bitrix\Pull\Event::add(array_keys($arRelation), $pushMessage);
				if ($chat->getType() == IM_MESSAGE_OPEN || $chat->getType() == IM_MESSAGE_OPEN_LINE)
				{
					CPullWatch::AddToStack('IM_PUBLIC_'.$chatId, $pushMessage);
				}*/
			}

			Sync\Logger::getInstance()->add(
				new Sync\Event(Sync\Event::ADD_EVENT, Sync\Event::CHAT_ENTITY, $chat->getChatId()),
				$this->user_id,
				$chat
			);


			return true;
		}

		return false;
	}

	/**
	 * @deprecated
	 * @use ..
	 * @param $arParams
	 * @return array
	 */
	public function GetUnreadMessage($arParams = Array())
	{
		global $DB;

		$bSpeedCheck = isset($arParams['SPEED_CHECK']) && $arParams['SPEED_CHECK'] == 'N'? false: true;
		$lastId = !isset($arParams['LAST_ID']) || $arParams['LAST_ID'] == null? null: intval($arParams['LAST_ID']);
		$loadDepartment = isset($arParams['LOAD_DEPARTMENT']) && $arParams['LOAD_DEPARTMENT'] == 'N'? false: true;
		$bTimeZone = isset($arParams['USE_TIME_ZONE']) && $arParams['USE_TIME_ZONE'] == 'N'? false: true;
		$bGroupByChat = isset($arParams['GROUP_BY_CHAT']) && $arParams['GROUP_BY_CHAT'] == 'Y'? true: false;
		$bUserLoad = isset($arParams['USER_LOAD']) && $arParams['USER_LOAD'] == 'N'? false: true;
		$bFileLoad = isset($arParams['FILE_LOAD']) && $arParams['FILE_LOAD'] == 'N'? false: true;
		$arExistUserData = isset($arParams['EXIST_USER_DATA']) && is_array($arParams['EXIST_USER_DATA'])? $arParams['EXIST_USER_DATA']: Array();
		$messageType = isset($arParams['MESSAGE_TYPE']) && in_array($arParams['MESSAGE_TYPE'], self::getGroupTypes())? $arParams['MESSAGE_TYPE']: 'ALL';

		$arMessages = Array();
		$arUnreadMessage = Array();
		$arUsersMessage = Array();

		$arResult = Array(
			'message' => Array(),
			'unreadMessage' => Array(),
			'usersMessage' => Array(),
			'users' => Array(),
			'userInGroup' => Array(),
			'files' => Array(),
			'countMessage' => 0,
			'chat' => Array(),
			'userChatBlockStatus' => Array(),
			'userInChat' => Array(),
			'result' => false
		);
		$bLoadMessage = $bSpeedCheck? CIMMessenger::SpeedFileExists($this->user_id, IM_SPEED_GROUP): false;
		$count = CIMMessenger::SpeedFileGet($this->user_id, IM_SPEED_GROUP);
		if (!$bLoadMessage || ($bLoadMessage && intval($count) > 0))
		{
			/*$ssqlLastId = "R1.LAST_ID";
			$ssqlStatus = " AND R1.STATUS < ".IM_STATUS_READ;
			if (!is_null($lastId) && intval($lastId) > 0 && !CIMMessenger::CheckXmppStatusOnline())
			{
				$ssqlLastId = intval($lastId);
				$ssqlStatus = "";
			}

			$arRelations = Array();
			if ($ssqlStatus <> '')
			{
				$strSql ="
					SELECT
						R1.USER_ID,
						R1.CHAT_ID,
						R1.LAST_ID
					FROM
						b_im_relation R1
					WHERE
						R1.USER_ID = ".$this->user_id."
						".($messageType == 'ALL'? "AND R1.MESSAGE_TYPE IN ('".IM_MESSAGE_OPEN."','".IM_MESSAGE_CHAT."','".IM_MESSAGE_OPEN_LINE."')": "AND R1.MESSAGE_TYPE = '".$messageType."'")."
						".$ssqlStatus."
				";
				$dbSubRes = $DB->Query($strSql);
				while ($arRes = $dbSubRes->Fetch())
				{
					//$ssqlLastId = intval($arRes['LAST_ID']);
					$arRelations[] = $arRes;
				}
			}*/

			$arMessageId = Array();
			$arMessageChatId = Array();
			$arLastMessage = Array();
			$arMark = Array();
			$arChat = Array();

			$arPrepareResult = Array();
			$arFilteredResult = Array();

			if (!$bTimeZone)
				CTimeZone::Disable();
			$groupTypes = self::implodeTypesForQuery(self::getGroupTypes());
			$strSql = "
					SELECT
						M.ID,
						M.CHAT_ID,
						M.MESSAGE,
						".$DB->DatetimeToTimestampFunction('M.DATE_CREATE')." as DATE_CREATE,
						M.AUTHOR_ID,
						R1.MESSAGE_TYPE as MESSAGE_TYPE
					FROM b_im_message M
					INNER JOIN b_im_relation R1 ON M.CHAT_ID = R1.CHAT_ID AND R1.USER_ID != M.AUTHOR_ID
					INNER JOIN b_im_message_unread MU ON M.ID = MU.MESSAGE_ID AND MU.USER_ID = " . $this->user_id . "
					WHERE
						R1.USER_ID = ".$this->user_id."
						".($messageType == 'ALL'? "AND R1.MESSAGE_TYPE IN ({$groupTypes})": "AND R1.MESSAGE_TYPE = '".$messageType."'")."
				";
			if (!$bTimeZone)
				CTimeZone::Enable();

			$strSql = $DB->TopSql($strSql, 1000);

			$dbRes = $DB->Query($strSql);

			while ($arRes = $dbRes->Fetch())
			{
				$arPrepareResult[$arRes['CHAT_ID']][$arRes['ID']] = $arRes;
			}
			foreach ($arPrepareResult as $chatId => $arRes)
			{
				if (count($arPrepareResult[$chatId]) > 100)
				{
					$arPrepareResult[$chatId] = array_slice($arRes, -100, 100);
				}
				$arFilteredResult = array_merge($arFilteredResult, $arPrepareResult[$chatId]);
			}
			unset($arPrepareResult);

			foreach ($arFilteredResult as $arRes)
			{
				$arUsers[] = $arRes['AUTHOR_ID'];

				$arMessages[$arRes['ID']] = Array(
					'id' => $arRes['ID'],
					'chatId' => $arRes['CHAT_ID'],
					'senderId' => $arRes['AUTHOR_ID'],
					'recipientId' => $arRes['CHAT_ID'],
					'date' => DateTime::createFromTimestamp($arRes['DATE_CREATE']),
					'text' => $arRes['MESSAGE'],
					'messageType' => $arRes['MESSAGE_TYPE'],
				);
				if ($bGroupByChat)
				{
					$arMessages[$arRes['ID']]['conversation'] = $arRes['CHAT_ID'];
					$arMessages[$arRes['ID']]['unread'] = $this->user_id != $arRes['AUTHOR_ID']? 'Y': 'N';
				}
				else
				{
					$arUsersMessage[$arRes['CHAT_ID']][] = $arRes['ID'];
				}

				/*if ($arRes['R1_STATUS'] == IM_STATUS_UNREAD && (!isset($arMark[$arRes["CHAT_ID"]]) || $arMark[$arRes["CHAT_ID"]] < $arRes["ID"]))
					$arMark[$arRes["CHAT_ID"]] = $arRes["ID"];*/

				if (!isset($arLastMessage[$arRes["CHAT_ID"]]) || $arLastMessage[$arRes["CHAT_ID"]] < $arRes["ID"])
					$arLastMessage[$arRes["CHAT_ID"]] = $arRes["ID"];

				$arChat[$arRes["CHAT_ID"]] = $arRes["CHAT_ID"];
				$arMessageId[] = $arRes['ID'];
				$arMessageChatId[$arRes['CHAT_ID']][$arRes["ID"]] = $arRes["ID"];
			}
			$params = CIMMessageParam::Get($arMessageId);

			if ($bFileLoad)
			{
				foreach ($arMessageChatId as $chatId => $messages)
				{
					$files = Array();
					foreach ($messages as $messageId)
					{
						$arMessages[$messageId]['params'] = $params[$messageId];

						if (isset($params[$messageId]['FILE_ID']))
						{
							foreach ($params[$messageId]['FILE_ID'] as $fileId)
							{
								$files[$fileId] = $fileId;
							}
						}
					}

					$arMessageFiles = CIMDisk::GetFiles($chatId, $files);
					foreach ($arMessageFiles as $key => $value)
					{
						$arResult['files'][$chatId][$key] = $value;
					}
				}
			}
			else
			{
				foreach ($params as $messageId => $param)
				{
					$arMessages[$messageId]['params'] = $param;
				}
			}

			if (!empty($arMessages))
			{
				foreach ($arMark as $chatId => $lastSendId)
					CIMMessage::SetLastSendId($chatId, $this->user_id, $lastSendId);
			}

			if ($bGroupByChat)
			{
				foreach ($arMessages as $key => $value)
				{
					$arMessages[$arLastMessage[$value['conversation']]]['counter']++;
					if ($arLastMessage[$value['conversation']] != $value['id'])
					{
						unset($arMessages[$key]);
					}
					else
					{
						$arMessages[$key]['text'] = \Bitrix\Im\Text::parse($value['text']);
						$arMessages[$key]['textLegacy'] = \Bitrix\Im\Text::parseLegacyFormat($value['text']);

						$arUsersMessage[$value['conversation']][] = $value['id'];

						if ($value['params']['NOTIFY'] === 'N' || is_array($value['params']['NOTIFY']) && !in_array($this->user_id, $value['params']['NOTIFY']))
						{
							// skip unread
						}
						else if ($value['unread'] == 'Y')
						{
							$arUnreadMessage[$value['conversation']][] = $value['id'];
						}

						unset($arMessages[$key]['conversation']);
						unset($arMessages[$key]['unread']);
					}
				}
			}
			else
			{
				foreach ($arMessages as $key => $value)
				{
					$arMessages[$key]['text'] = \Bitrix\Im\Text::parse($value['text']);
					$arMessages[$key]['textLegacy'] = \Bitrix\Im\Text::parseLegacyFormat($value['text']);

					if ($value['params']['NOTIFY'] === 'N' || is_array($value['params']['NOTIFY']) && !in_array($this->user_id, $value['params']['NOTIFY']))
					{
						// skip unread
					}
					else if ($this->user_id != $value['senderId'])
					{
						$arUnreadMessage[$value['chatId']][] = $value['id'];
					}
				}
			}

			$arResult['message'] = $arMessages;
			$arResult['unreadMessage'] = $arUnreadMessage;
			$arResult['usersMessage'] = $arUsersMessage;

			$arChat = self::GetChatData(array(
				'ID' => $arChat,
				'USE_CACHE' => 'N'
			));
			if (!empty($arChat))
			{
				$arResult['lines'] = $arChat['lines'];
				$arResult['chat'] = $arChat['chat'];
				$arResult['userChatBlockStatus'] = $arChat['userChatBlockStatus'];
				$arResult['userInChat']  = $arChat['userInChat'];

				foreach ($arChat['userInChat'] as $value)
					$arUsers[] = $value;
			}

			if ($bUserLoad && !empty($arUsers))
			{
				$arUserData = CIMContactList::GetUserData(Array('ID' => array_diff(array_unique($arUsers), $arExistUserData), 'DEPARTMENT' => ($loadDepartment? 'Y': 'N')));
				$arResult['users'] = $arUserData['users'];
				$arResult['userInGroup'] = $arUserData['userInGroup'];
			}
			else
			{
				$arResult['users'] = Array();
				$arResult['userInGroup'] = Array();
				$arResult['userInGroup'] = Array();
			}

			$arResult['countMessage'] = CIMMessenger::GetMessageCounter($this->user_id, $arResult);
			if (!$bGroupByChat)
				CIMMessenger::SpeedFileCreate($this->user_id, $arResult['countMessage'], IM_SPEED_GROUP);
			$arResult['result'] = true;
		}
		else
		{
			$arResult['countMessage'] = CIMMessenger::GetMessageCounter($this->user_id, $arResult);
		}

		return $arResult;
	}

	public function SetOwner($chatId, $userId, $checkPermission = true)
	{
		$chatId = intval($chatId);
		$userId = intval($userId);

		$chat = IM\Model\ChatTable::getById($chatId)->fetch();
		if (!$chat)
		{
			return false;
		}

		if ($checkPermission && $chat['AUTHOR_ID'] != $this->user_id)
		{
			return false;
		}

		if ($userId == $chat['AUTHOR_ID'])
		{
			return true;
		}

		$arRelation = self::GetRelationById($chatId, false, true, false);
		if (!isset($arRelation[$userId]))
		{
			return false;
		}

		if ($this->user_id !== 0 && !self::canDo($chat, $arRelation, IM\V2\Permission\Action::ChangeOwner))
		{
			return false;
		}

		IM\Model\ChatTable::update($chatId, Array('AUTHOR_ID' => $userId));
		IM\Model\RelationTable::update($arRelation[$userId]['ID'], Array('MANAGER' => 'Y'));
		if (isset($arRelation[$chat['AUTHOR_ID']]))
		{
			IM\Model\RelationTable::update($arRelation[$chat['AUTHOR_ID']]['ID'], Array('MANAGER' => 'N'));
		}

		if (CModule::IncludeModule('pull'))
		{
			\Bitrix\Pull\Event::add(array_keys($arRelation), Array(
				'module_id' => 'im',
				'command' => 'chatOwner',
				'params' => Array(
					'dialogId' => 'chat'.$chatId,
					'chatId' => (int)$chatId,
					'userId' => $userId
				),
				'extra' => \Bitrix\Im\Common::getPullExtra()
			));
		}

		return true;
	}

	public function SetDescription($chatId, $description)
	{
		$chatId = intval($chatId);
		$chat = Chat\GroupChat::getInstance($chatId);

		if (!$chat instanceof Chat\GroupChat)
		{
			return false;
		}

		if ($this->user_id !== 0 && !$chat->canDo(IM\V2\Permission\Action::ChangeDescription))
		{
			return false;
		}

		$fields = Chat\Update\UpdateFields::create(['DESCRIPTION' => $description]);
		(new Chat\Update\UpdateService($chat, $fields))->updateChat();
		$arRelation = $chat->getRelations()->getUserIds();

		if (CModule::IncludeModule('pull'))
		{
			\Bitrix\Pull\Event::add(array_keys($arRelation), Array(
				'module_id' => 'im',
				'command' => 'chatDescription',
				'params' => Array(
					'chatId' => $chatId,
					'description' => \Bitrix\Im\Text::parse($description)
				),
				'extra' => \Bitrix\Im\Common::getPullExtra()
			));
		}

		return true;
	}

	public static function SetChatParams($chatId, $params)
	{
		$update = [];
		if (isset($params['ENTITY_TYPE']))
			$update['ENTITY_TYPE'] = $params['ENTITY_TYPE'];

		if (isset($params['ENTITY_ID']))
			$update['ENTITY_ID'] = $params['ENTITY_ID'];

		if (isset($params['ENTITY_DATA_1']))
			$update['ENTITY_DATA_1'] = $params['ENTITY_DATA_1'];

		if (isset($params['ENTITY_DATA_2']))
			$update['ENTITY_DATA_2'] = $params['ENTITY_DATA_2'];

		if (isset($params['ENTITY_DATA_3']))
			$update['ENTITY_DATA_3'] = $params['ENTITY_DATA_3'];

		\Bitrix\Im\Model\ChatTable::update($chatId, $update);

		if (CModule::IncludeModule('pull'))
		{
			if (isset($update['NAME']))
			{
				$update['NAME'] = htmlspecialcharsbx($update['NAME']);
			}

			$arRelation = self::GetRelationById($chatId, false, true, false);
			\Bitrix\Pull\Event::add(array_keys($arRelation), Array(
				'module_id' => 'im',
				'command' => 'chatUpdateParams',
				'params' => Array(
					'dialogId' => 'chat'.$chatId,
					'chatId' => (int)$chatId,
					'params' => array_change_key_case($update)
				),
				'extra' => \Bitrix\Im\Common::getPullExtra()
			));
		}

		return true;
	}

	public function SetManager($chatId, $userId, $isManager = true, $checkPermission = true)
	{
		return $this->SetManagers($chatId, Array($userId => $isManager), $checkPermission);
	}

	public function SetManagers($chatId, $users, $checkPermission = true)
	{
		$chatId = (int)$chatId;
		$chat = Chat::getInstance($chatId);

		if (!$chat instanceof Chat\GroupChat)
		{
			return false;
		}

		if (
			$checkPermission
			&& $this->user_id !== 0
			&& $chat->getAuthorId() !== $this->user_id
			&& !$chat->canDo(IM\V2\Permission\Action::ChangeManagers))
		{
			return false;
		}

		$chat->changeManagersByMap($users);

		return true;
	}

	public function SetColor($chatId, $color)
	{
		global $DB;
		$chatId = intval($chatId);
		$color = mb_strtoupper($color);

		if ($chatId <= 0 || !IM\Color::isSafeColor($color))
		{
			return false;
		}

		$groupTypes = self::implodeTypesForQuery(self::getGroupTypes());

		$strSql = "
			SELECT 
				R.CHAT_ID, 
				C.COLOR as CHAT_COLOR, 
				C.AUTHOR_ID as CHAT_AUTHOR_ID, 
				C.TYPE as CHAT_TYPE,
				C.ENTITY_TYPE as CHAT_ENTITY_TYPE, 
				C.ENTITY_ID as CHAT_ENTITY_ID,
				C.MANAGE_UI, 
				C.MANAGE_USERS_ADD, 
				C.MANAGE_USERS_DELETE, 
				C.MANAGE_SETTINGS 
			FROM 
				b_im_relation R 
				LEFT JOIN b_im_chat C 
					ON R.CHAT_ID = C.ID
			WHERE 
				R.USER_ID = ".$this->user_id." 
				AND R.MESSAGE_TYPE IN ({$groupTypes}) 
				AND R.CHAT_ID = ".$chatId;
		$dbRes = $DB->Query($strSql);
		if ($arRes = $dbRes->Fetch())
		{
			$arRes['CHAT_TYPE'] = trim($arRes['CHAT_TYPE']);
			if ($arRes['CHAT_COLOR'] == $color)
				return false;

			$ar = CIMChat::GetRelationById($chatId, false, true, false);

			if ($this->user_id !== 0 && !self::canDo($arRes, $ar, IM\V2\Permission\Action::ChangeColor))
			{
				return false;
			}

			IM\Model\ChatTable::update($chatId, array('COLOR' => $color));

			CIMChat::AddSystemMessage(Array(
				'CHAT_ID' => $chatId,
				'USER_ID' => $this->user_id,
				'MESSAGE_CODE' => 'IM_CHAT_CHANGE_COLOR_',
				'MESSAGE_REPLACE' => Array('#CHAT_COLOR#' => IM\Color::getName($color))
			));

			if ($arRes['CHAT_ENTITY_TYPE'] == 'LINES')
			{
				foreach ($ar as $rel)
				{
					if ($rel["EXTERNAL_AUTH_ID"] == 'imconnector')
					{
						unset($ar[$rel["USER_ID"]]);
					}
				}
			}

			if ($arRes['CHAT_TYPE'] == IM_MESSAGE_OPEN)
			{
				CIMContactList::CleanAllChatCache();
			}
			else
			{
				foreach ($ar as $rel)
				{
					CIMContactList::CleanChatCache($rel['USER_ID']);
				}
			}
			if (CModule::IncludeModule("pull"))
			{
				$arPushMessage = Array(
					'module_id' => 'im',
					'command' => 'chatChangeColor',
					'expiry' => 3600,
					'params' => Array(
						'chatId' => $chatId,
						'color' => IM\Color::getColor($color),
					),
					'extra' => \Bitrix\Im\Common::getPullExtra()
				);
				\Bitrix\Pull\Event::add(array_keys($ar), $arPushMessage);
				if (CIMMessenger::needToSendPublicPull($arRes['CHAT_TYPE']))
				{
					CPullWatch::AddToStack('IM_PUBLIC_'.$chatId, $arPushMessage);
				}
			}

			return true;
		}
		return false;
	}

	public function SetAvatarId($chatId, $fileId)
	{
		if ($chatId <= 0)
		{
			return false;
		}

		$orm = \Bitrix\Im\Model\ChatTable::getById($chatId);
		$chat = $orm->fetch();
		if (!$chat)
		{
			return false;
		}

		$relation = self::GetRelationById($chatId, false, true, false);

		if ($this->user_id !== 0 && !self::canDo($chat, $relation, IM\V2\Permission\Action::ChangeAvatar))
		{
			return false;
		}

		if ($fileId > 0)
		{
			$orm = \Bitrix\Main\FileTable::getById($fileId);
			$file = $orm->fetch();
			if (!$file)
				return false;

			if ($file['HEIGHT'] <= 0 || $file['WIDTH'] <= 0)
				return false;
		}

		IM\Model\ChatTable::update($chatId, Array('AVATAR' => $fileId));

		if (CModule::IncludeModule('pull'))
		{
			$users = [];
			foreach ($relation as $rel)
			{
				if ($rel["EXTERNAL_AUTH_ID"] != 'imconnector')
				{
					$users[$rel['USER_ID']] = $rel['USER_ID'];
				}
			}
			\Bitrix\Pull\Event::add($users, Array(
				'module_id' => 'im',
				'command' => 'chatAvatar',
				'params' => Array(
					'chatId' => $chatId,
					'avatar' => self::GetAvatarImage($fileId),
				),
				'extra' => \Bitrix\Im\Common::getPullExtra()
			));
		}

		return true;
	}

	public function Rename($chatId, $title, $checkPermission = true, $sendMessage = true)
	{
		global $DB;
		$chatId = intval($chatId);
		$title = mb_substr(trim($title), 0, 255);

		if ($chatId <= 0 || $title == '')
		{
			return false;
		}

		$groupTypes = self::implodeTypesForQuery(self::getGroupTypes());
		if ($checkPermission)
		{
			$strSql = "
				SELECT 
					R.CHAT_ID, 
					C.TITLE as CHAT_TITLE, 
					C.AUTHOR_ID as CHAT_AUTHOR_ID, 
					C.TYPE as CHAT_TYPE, 
					C.ENTITY_TYPE as CHAT_ENTITY_TYPE, 
					C.ENTITY_ID as CHAT_ENTITY_ID, 
					R.MANAGER as IS_MANAGER, 
					C.MANAGE_UI, 
					C.MANAGE_USERS_ADD, 
					C.MANAGE_USERS_DELETE, 
					C.MANAGE_SETTINGS 
				FROM b_im_relation R LEFT JOIN b_im_chat C ON R.CHAT_ID = C.ID
				WHERE 
					R.USER_ID = ".$this->user_id." 
					AND R.MESSAGE_TYPE IN ({$groupTypes}) 
					AND R.CHAT_ID = ".$chatId;
		}
		else
		{
			$strSql = "
				SELECT 
					C.ID as CHAT_ID, 
					C.TITLE as CHAT_TITLE, 
					C.AUTHOR_ID as CHAT_AUTHOR_ID, 
					C.TYPE as CHAT_TYPE, 
					C.ENTITY_TYPE as CHAT_ENTITY_TYPE, 
					C.ENTITY_ID as CHAT_ENTITY_ID, 
					'Y' as IS_MANAGER, 
					C.MANAGE_UI, 
					C.MANAGE_USERS_ADD, 
					C.MANAGE_USERS_DELETE, 
					C.MANAGE_SETTINGS 
				FROM b_im_chat C
				WHERE 
					C.ID = ".$chatId." 
					AND C.TYPE IN ({$groupTypes})";
		}
		$dbRes = $DB->Query($strSql);
		if ($arRes = $dbRes->Fetch())
		{
			$ar = CIMChat::GetRelationById($chatId, false, true, false);

			if ($this->user_id !== 0 && $checkPermission && !self::canDo($arRes, $ar, IM\V2\Permission\Action::Rename))
			{
				return false;
			}

			$arRes['CHAT_TITLE'] = \Bitrix\Im\Text::decodeEmoji($arRes['CHAT_TITLE']);

			if ($arRes['CHAT_TITLE'] == $title)
				return false;

			if ($arRes['CHAT_ENTITY_TYPE'] === 'ANNOUNCEMENT' && $arRes['IS_MANAGER'] !== 'Y')
			{
				return false;
			}

			$arRes['CHAT_TYPE'] = trim($arRes['CHAT_TYPE']);

			IM\Model\ChatTable::update($chatId, array('TITLE' => $title));

			if ($sendMessage)
			{
				if ($checkPermission)
				{
					if (
						$arRes['CHAT_TYPE'] === Chat::IM_TYPE_CHANNEL
						|| $arRes['CHAT_TYPE'] === Chat::IM_TYPE_OPEN_CHANNEL
					)
					{
						$type = 'CHANNEL';
						$messageCodeVersion = '';
					}
					else
					{
						$type = 'CHAT';
						$messageCodeVersion = '_MSGVER_1';
					}

					CIMChat::AddSystemMessage(Array(
						'CHAT_ID' => $chatId,
						'USER_ID' => $this->user_id,
						'MESSAGE_CODE' => "IM_{$type}_CHANGE_TITLE_",
						'MESSAGE_REPLACE' => Array('#CHAT_TITLE#' => $title),
						'MESSAGE_CODE_VERSION' => $messageCodeVersion,
					));
				}
				else
				{
					self::AddMessage(Array(
						"TO_CHAT_ID" => $chatId,
						"MESSAGE" => GetMessage("IM_CHAT_CHANGE_TITLE", Array('#CHAT_TITLE#' => $title)),
						"SYSTEM" => 'Y',
						"SKIP_USER_CHECK" => 'Y',
					));
				}
			}

			if ($arRes['CHAT_ENTITY_TYPE'] == 'LINES')
			{
				foreach ($ar as $rel)
				{
					if ($rel["EXTERNAL_AUTH_ID"] == 'imconnector')
					{
						unset($ar[$rel["USER_ID"]]);
					}
				}
			}

			if ($arRes['CHAT_TYPE'] == IM_MESSAGE_OPEN)
			{
				CIMContactList::CleanAllChatCache();
			}
			else
			{
				foreach ($ar as $rel)
				{
					CIMContactList::CleanChatCache($rel['USER_ID']);
				}
			}
			if (CModule::IncludeModule("pull"))
			{
				$pushMessage = Array(
					'module_id' => 'im',
					'command' => 'chatRename',
					'params' => Array(
						'chatId' => $chatId,
						'name' => \Bitrix\Main\Text\Emoji::decode($title),
					),
					'extra' => \Bitrix\Im\Common::getPullExtra()
				);
				\Bitrix\Pull\Event::add(array_keys($ar), $pushMessage);
				if (CIMMessenger::needToSendPublicPull($arRes['CHAT_TYPE']))
				{
					CPullWatch::AddToStack('IM_PUBLIC_'.$chatId, $pushMessage);
				}
				if ($arRes['CHAT_TYPE'] === Chat::IM_TYPE_OPEN_CHANNEL)
				{
					Chat\OpenChannelChat::sendSharedPull($pushMessage);
				}
			}

			foreach(GetModuleEvents("im", "OnChatRename", true) as $arEvent)
			{
				ExecuteModuleEventEx($arEvent, array($chatId, $title, $arRes['CHAT_ENTITY_TYPE'], $arRes['CHAT_ENTITY_ID'], $this->user_id));
			}

			return true;
		}
		return false;
	}

	/**
	 * @param $arParams
	 * @return array|false|int
	 * @throws Exception
	 *
	 * @deprecated Use Bitrix\Im\V2\Chat\ChatFactory::addChat()
	 * @see Bitrix\Im\V2\Chat\ChatFactory::addChat()
	 */
	public function Add($arParams)
	{
		$type = '';
		if (isset($arParams['MESSAGE_TYPE']))
		{
			$type = $arParams['MESSAGE_TYPE'];
		}
		elseif (isset($arParams['TYPE']))
		{
			$type = $arParams['MESSAGE_TYPE'] = $arParams['TYPE'];
		}

		$arParams['USER_ID'] = $this->user_id;

		$authorId = $arParams['USER_ID'];
		if (isset($arParams['AUTHOR_ID']))
		{
			$authorId = intval($arParams['AUTHOR_ID']);
		}

		if (isset($arParams['OWNER_ID']))
		{
			$authorId = intval($arParams['OWNER_ID']);
		}

		if ($authorId)
		{
			$arParams['AUTHOR_ID'] = $authorId;
		}

		if (isset($arParams['AVATAR_ID']))
		{
			$arParams['AVATAR'] = (int) $arParams['AVATAR_ID'];
		}

		$chatResult = IM\V2\Chat\ChatFactory::getInstance()->addChat($arParams);
		if (!$chatResult->isSuccess() || !$chatResult->hasResult())
		{
			return false;
		}

		if (isset($arParams['MESSAGE']))
		{
			$message = trim($arParams['MESSAGE']);
		}

		if (isset($message) && $message)
		{
			if ($type === IM\V2\Chat::IM_TYPE_PRIVATE)
			{
				CIMMessage::Add([
					"FROM_USER_ID" => $this->user_id,
					"TO_USER_ID" => $this->user_id,
					"MESSAGE" => $message,
				]);
			}
			else
			{
				self::AddMessage([
					"TO_CHAT_ID" => $chatResult->getResult()['CHAT_ID'],
					"FROM_USER_ID" => $this->user_id,
					"SYSTEM" => $this->user_id ? 'N' : 'Y',
					"MESSAGE" => $message,
				]);
			}
		}

		$chat = $chatResult->getResult()['CHAT'];

		CIMContactList::CleanAllChatCache();

		return $chat->getChatId();
	}

	public static function AddMessage($arFields)
	{
		$arFields['MESSAGE_TYPE'] = IM_MESSAGE_CHAT;

		return CIMMessenger::Add($arFields);
	}

	public function Join($chatId)
	{
		$chatId = intval($chatId);
		if ($chatId <= 0)
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_EMPTY_CHAT_ID"), "EMPTY_CHAT_ID");
			return false;
		}

		$orm = IM\Model\ChatTable::getById($chatId);
		if (!($chatData = $orm->fetch()))
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_CHAT_NOT_EXISTS"), "ERROR_CHAT_NOT_EXISTS");
			return false;
		}

		if ($chatData['TYPE'] != IM_MESSAGE_OPEN)
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_ACCESS_JOIN"), "ACCESS_JOIN");
			return false;
		}

		if (IM\User::getInstance($this->user_id)->isExtranet())
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_ACCESS_JOIN"), "ACCESS_JOIN");
			return false;
		}

		$chat = new CIMChat(0);
		$chat->AddUser($chatId, $this->user_id);

		return true;
	}

	public function JoinParent($chatId, $messageId)
	{
		$chatId = intval($chatId);
		if ($chatId <= 0)
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_EMPTY_CHAT_ID"), "EMPTY_CHAT_ID");
			return false;
		}

		$messageId = intval($messageId);
		if ($messageId <= 0)
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_EMPTY_CHAT_ID"), "EMPTY_CHAT_ID");
			return false;
		}

		$CIMMessage = new CIMMessage($this->user_id);
		$message = $CIMMessage->GetMessage($messageId, true);
		if (!$message)
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_ACCESS_JOIN"), "ACCESS_JOIN");
			return false;
		}

		$relations = IM\Chat::getRelation($chatId, ['WITHOUT_COUNTERS' => 'Y']);
		if (!isset($relations[$this->user_id]))
		{
			$chat = new CIMChat(0);
			$chat->AddUser($chatId, $this->user_id);
		}

		return true;
	}

	public function AddUser($chatId, $userId, $hideHistory = null, $skipMessage = false, $skipRecent = false, $skipRelation = false)
	{
		$chatId = intval($chatId);
		if ($chatId <= 0)
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_EMPTY_CHAT_ID"), "EMPTY_CHAT_ID");
			return false;
		}

		$arUserId = Array();
		if (is_array($userId))
		{
			$arUserId = \CIMContactList::PrepareUserIds($userId);
		}
		else if (intval($userId) > 0)
		{
			$arUserId[intval($userId)] = intval($userId);
		}
		if ($this->user_id > 0)
		{
			$arUserId[$this->user_id] = $this->user_id;
		}

		if (count($arUserId) <= 0)
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_EMPTY_USER_ID"), "EMPTY_USER_ID");
			return false;
		}

		$chat = Chat::getInstance($chatId)->withContextUser($this->user_id);

		if ($this->user_id !== 0 && !$chat->canDo(IM\V2\Permission\Action::Extend))
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_CHAT_ACCESS_DENIED_EXTEND_USERS"), "ACCESS_DENIED_EXTEND");
			return false;
		}

		$config = new IM\V2\Relation\AddUsersConfig([], $hideHistory, !$skipMessage, $skipRecent, $skipRelation);
		$chat->addUsers($arUserId, $config);

		return true;
	}

	public function MuteNotify($chatId, $mute = true)
	{
		return \Bitrix\Im\Chat::mute($chatId, $mute, $this->user_id);
	}

	public function DeleteUser(
		$chatId,
		$userId,
		$checkPermission = true,
		$skipMessage = false,
		$skipRecent = false,
		$withoutRead = false,
		$additionalParams = []
	)
	{
		$chatId = (int)$chatId;
		$userId = (int)$userId;

		if ($chatId <= 0 || $userId <= 0)
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_EMPTY_USER_OR_CHAT"), "EMPTY_USER_OR_CHAT");

			return false;
		}

		$chat = Chat::getInstance($chatId)->withContextUser($this->user_id);

		if ($this->user_id !== 0 && !$chat->canDo(IM\V2\Permission\Action::Kick, $userId))
		{
			if ($this->user_id === $userId && $chat->getAuthorId() === $userId)
			{
				$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_LEAVE_OWNER_FORBIDDEN"), "LEAVE_OWNER_FORBIDDEN");
			}
			else
			{
				$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_CHAT_ACCESS_DENIED_KICK_USERS"), "ACCESS_DENIED_KICK");
			}

			return false;
		}

		if ($checkPermission && $this->user_id !== $userId && $chat->getAuthorId() !== $this->user_id)
		{
			$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_KICK"), "IM_ERROR_KICK");

			return false;
		}

		$config = new IM\V2\Relation\DeleteUserConfig(
			!$skipMessage,
			$skipRecent,
			true,
			false,
			$withoutRead
		);
		$result = $chat->deleteUser($userId, $config);

		if ($result->getError() !== null)
		{
			if ($result->getError()?->getCode() === UserError::NOT_FOUND)
			{
				$GLOBALS["APPLICATION"]->ThrowException(GetMessage("IM_ERROR_USER_NOT_FOUND"), UserError::NOT_FOUND);

				return false;
			}

			$GLOBALS["APPLICATION"]->ThrowException($result->getError()->getMessage(), $result->getError()->getCode());

			return false;
		}

		return true;
	}

	public static function GetAvatarImage($id, $size = 200, $addBlankPicture = true)
	{
		$url = $addBlankPicture? '/bitrix/js/im/images/blank.gif': '';

		$id = intval($id);
		if ($id > 0 && $size > 0)
		{
			$arFileTmp = CFile::ResizeImageGet(
				$id,
				array('width' => $size, 'height' => $size),
				BX_RESIZE_IMAGE_EXACT,
				false,
				false,
				true
			);
			if (!empty($arFileTmp['src']))
			{
				$url = $arFileTmp['src'];
			}
		}
		return $url;
	}

	public static function AddSystemMessage($params)
	{
		$chatId = intval($params['CHAT_ID']);
		if ($chatId <= 0)
			return false;

		$arUser = false;
		$userId = intval($params['USER_ID']);
		if ($userId > 0)
		{
			$arSelect = Array("ID", "LAST_NAME", "NAME", "LOGIN", "SECOND_NAME", "PERSONAL_GENDER");
			$dbUsers = CUser::GetList('', '', array('ID_EQUAL_EXACT' => $userId), array('FIELDS' => $arSelect));
			if ($arUser = $dbUsers->Fetch())
			{
				$arUser['NAME'] = \Bitrix\Im\User::formatFullNameFromDatabase($arUser);
				$arUser['PERSONAL_GENDER'] = $arUser["PERSONAL_GENDER"] == 'F'? 'F': 'M';
			}
		}

		if (isset($params['MESSAGE_CODE']))
		{
			$messageCodeVersion = $params['MESSAGE_CODE_VERSION'] ?? '';
			$messageReplace = is_array($params['MESSAGE_REPLACE'])? $params['MESSAGE_REPLACE']: Array();
			if ($arUser)
			{
				$messageReplace['#USER_NAME#'] = $arUser['NAME'];
				$message = GetMessage($params['MESSAGE_CODE'].$arUser['PERSONAL_GENDER'].$messageCodeVersion, $messageReplace);
			}
			else
			{
				$message = GetMessage($params['MESSAGE_CODE'], $messageReplace);
			}
		}
		else
		{
			$messageReplace = is_array($params['MESSAGE_REPLACE'])? $params['MESSAGE_REPLACE']: Array();
			$message = trim($params['MESSAGE']);
			if ($message <> '' && !empty($messageReplace))
			{
				$message = str_replace(array_keys($messageReplace), array_values($messageReplace), $message);
			}
		}
		if ($message == '')
			return false;

		return self::AddMessage(Array(
			"TO_CHAT_ID" => $chatId,
			"FROM_USER_ID" => $userId,
			"MESSAGE" => $message,
			"SYSTEM" => 'Y',
			"SKIP_USER_CHECK" => 'Y',
		));
	}

	public static function CheckRestriction($chatId, $action)
	{
		if (is_int($chatId))
		{
			if (self::GetGeneralChatId() == $chatId)
			{
				$chat['ENTITY_TYPE'] = 'GENERAL';
			}
			else
			{
				$chat = IM\Model\ChatTable::getById($chatId)->fetch();
				if (!$chat)
					return true;
			}
		}
		else if(is_array($chatId))
		{
			$chat = $chatId;
		}
		else
		{
			return true;
		}

		$options = self::GetChatOptions();
		if (isset($options[$chat['ENTITY_TYPE']][$action]) && !self::$entityOption[$chat['ENTITY_TYPE']][$action])
		{
			return true;
		}

		return false;
	}

	public static function GetChatOptions()
	{
		if (!is_null(self::$entityOption))
		{
			return self::$entityOption;
		}

		global $USER;

		self::$entityOption = [];

		$default = [
			'AVATAR' => true,
			'RENAME' => true,
			'EXTEND' => true,
			'CALL' => true,
			'MUTE' => true,
			'LEAVE' => true,
			'LEAVE_OWNER' => true,
			'SEND' => true,
			'USER_LIST' => true,
		];

		self::$entityOption['GENERAL'] = [
			'AVATAR' => false,
			'RENAME' => false,
			'EXTEND' => false,
			'CALL' => true,
			'LEAVE' => false,
			'LEAVE_OWNER' => false,
			'SEND' => CIMChat::CanSendMessageToGeneralChat(($USER instanceof \CUser) ? (int)$USER->GetID() : null)
		];

		if (\Bitrix\Main\Loader::includeModule('imbot'))
		{
			self::$entityOption[\Bitrix\ImBot\Service\Notifier::CHAT_ENTITY_TYPE] = [
				'AVATAR' => false,
				'RENAME' => false,
				'LEAVE_OWNER' => false,
			];
			self::$entityOption[\Bitrix\ImBot\Bot\Support24::CHAT_ENTITY_TYPE] = [
				'AVATAR' => false,
				'RENAME' => true,
				'EXTEND' => false,
				'CALL' => false,
				'MUTE' => false,
				'LEAVE' => false,
				'LEAVE_OWNER' => false,
				'USER_LIST' => false,
			];
			self::$entityOption[\Bitrix\ImBot\Bot\Network::CHAT_ENTITY_TYPE] =
				self::$entityOption[\Bitrix\ImBot\Bot\Support24::CHAT_ENTITY_TYPE]
			;
		}

		if (\Bitrix\Main\ModuleManager::isModuleInstalled('socialnetwork'))
		{
			$path = COption::GetOptionString("socialnetwork", "workgroups_page", "/workgroups/", SITE_ID);
			$path = $path.'group/#ID#/';

			self::$entityOption['SONET_GROUP'] = [
				'AVATAR' => false,
				'RENAME' => false,
				'EXTEND' => false,
				'LEAVE' => false,
				'LEAVE_OWNER' => false,
				'PATH' => $path,
				'PATH_TITLE' => GetMessage('IM_PATH_TITLE_SONET')
			];
		}

		if (\Bitrix\Main\Loader::includeModule('tasks'))
		{
			$path = \CTasksTools::GetOptionPathTaskUserEntry(SITE_ID, "/company/personal/user/#user_id#/tasks/task/view/#task_id#/");
			$path = str_replace(Array('#user_id#', '#task_id#'), Array(($USER instanceof \CUser) ? (int)$USER->GetId() : 0, '#ID#'), mb_strtolower($path));

			self::$entityOption['TASKS'] = Array(
				'AVATAR' => true,
				'RENAME' => true,
				'EXTEND' => true,
				'LEAVE' => true,
				'LEAVE_OWNER' => true,
				'PATH' => $path,
				'PATH_TITLE' => GetMessage('IM_PATH_TITLE_TASKS')
			);
		}

		if (\Bitrix\Main\Loader::includeModule('calendar'))
		{
			$path = \CCalendar::GetPathForCalendarEx(($USER instanceof \CUser) ? (int)$USER->GetId() : 0);
			$path = \CHTTP::urlAddParams($path, ['EVENT_ID' => '#ID#']);

			self::$entityOption[\CCalendar::CALENDAR_CHAT_ENTITY_TYPE] = Array(
				'AVATAR' => true,
				'RENAME' => true,
				'EXTEND' => true,
				'LEAVE' => true,
				'LEAVE_OWNER' => true,
				'PATH' => $path,
				'PATH_TITLE' => GetMessage('IM_PATH_TITLE_CALENDAR_EVENT')
			);
		}

		if (\Bitrix\Main\Loader::includeModule('crm'))
		{
			self::$entityOption['CRM'] = Array(
				'AVATAR' => false,
				'RENAME' => false,
				'EXTEND' => true,
				'LEAVE' => true,
				'LEAVE_OWNER' => false,
				'PATH' => '',
				'PATH_TITLE' => ''
			);
		}

		if (\Bitrix\Main\Loader::includeModule('voximplant'))
		{
			self::$entityOption['CALL'] = Array(
				'AVATAR' => true,
				'RENAME' => true,
				'EXTEND' => false,
				'CALL' => false,
				'MUTE' => false,
				'LEAVE' => false,
				'LEAVE_OWNER' => false,
				'SEND' => true,
				'USER_LIST' => true,
			);
		}

		foreach (self::$entityOption as $code => $value)
		{
			self::$entityOption[$code] = array_merge($default, $value);
		}

		self::$entityOption['DEFAULT'] = $default;

		return self::$entityOption;
	}

	public static function GetSonetGroupChatId($groupId)
	{
		if (!CModule::IncludeModule('socialnetwork'))
			return false;

		$chatData = \Bitrix\Socialnetwork\Integration\Im\Chat\Workgroup::getChatData(Array(
			'group_id' => $groupId,
			'skipAvailabilityCheck' => true
		));
		if (!empty($chatData[$groupId]) && intval($chatData[$groupId]) > 0)
		{
			$chatId = $chatData[$groupId];
		}
		else
		{
			$chatId = \Bitrix\Socialnetwork\Integration\Im\Chat\Workgroup::createChat(Array(
				'group_id' => $groupId
			));
		}

		return $chatId;
	}

	public static function GetCrmChatId($code)
	{
		if (!CModule::IncludeModule('crm'))
			return false;

		[$entityType, $entityId] = explode('|', $code);

		global $USER;

		$chatId = \Bitrix\Crm\Integration\Im\Chat::joinChat(Array(
			'ENTITY_TYPE' => $entityType,
			'ENTITY_ID' => $entityId,
			'USER_ID' => $USER->GetId()
		));

		return $chatId;
	}

	public static function GetUserCount($chatId)
	{
		$result = \Bitrix\Im\Model\ChatTable::getList(
			[
				'select' => ['USER_COUNT'],
				'filter' => ['=ID' => $chatId]
			]
		)->fetch();

		if (!$result)
		{
			return false;
		}

		return (int)$result['USER_COUNT'];
	}

	public static function GetEntityChat($entityType, $entityId)
	{
		$entityType = trim($entityType);
		$entityId = trim($entityId);

		if (empty($entityType) || empty($entityId))
		{
			return false;
		}

		$chatData = \Bitrix\Im\Model\ChatTable::getList(Array(
			'select' => ['ID'],
			'filter' => [
				'=ENTITY_TYPE' => $entityType,
				'=ENTITY_ID' => $entityId,
			]
		))->fetch();

		if (!$chatData)
		{
			return false;
		}

		return $chatData['ID'];
	}

	public static function DeleteEntityChat($entityType, $entityId)
	{
		$entityType = trim($entityType);
		$entityId = trim($entityId);

		if (empty($entityType) || empty($entityId))
		{
			return false;
		}

		$chatData = \Bitrix\Im\Model\ChatTable::getList(Array(
			'select' => ['ID', 'DISK_FOLDER_ID'],
			'filter' => [
				'=ENTITY_TYPE' => $entityType,
				'=ENTITY_ID' => $entityId,
			],
		))->fetch();
		if (!$chatData)
		{
			return false;
		}

		self::deleteChat($chatData);

		return true;
	}

	public static function deleteChat(array $chatData): void
	{
		global $DB;

		self::hide($chatData['ID']);

		$strSQL = "DELETE FROM b_im_chat WHERE ID = ".$chatData['ID'];
		$DB->Query($strSQL, true);

		$strSQL = "DELETE FROM b_im_relation WHERE CHAT_ID = ".$chatData['ID'];
		$DB->Query($strSQL, true);

		$strSQL = "DELETE FROM b_im_message WHERE CHAT_ID = ".$chatData['ID'];
		$DB->Query($strSQL, true);

		IM\V2\Link\Url\UrlCollection::deleteByChatsIds([(int)$chatData['ID']]);
		IM\V2\Chat::cleanCache((int)$chatData['ID']);

		if ($chatData['DISK_FOLDER_ID'])
		{
			$folderModel = \Bitrix\Disk\Folder::getById($chatData['DISK_FOLDER_ID']);
			if ($folderModel)
			{
				$folderModel->deleteTree(\Bitrix\Disk\SystemUser::SYSTEM_USER_ID);
			}
		}
	}

	public static function hide($chatId)
	{
		$pushList = [];
		$lines = false;
		$relations = \CIMChat::GetRelationById($chatId, false, true, false);
		foreach($relations as $userId => $relation)
		{
			if ($relation['MESSAGE_TYPE'] === Chat::IM_TYPE_OPEN_LINE)
			{
				$lines = true;
			}
			\CIMContactList::DeleteRecent($chatId, true, $userId);

			if (!\Bitrix\Im\User::getInstance($userId)->isConnector())
			{
				$pushList[] = $userId;
			}
		}

		if (
			!empty($pushList)
			&& \Bitrix\Main\Loader::includeModule("pull")
		)
		{
			\Bitrix\Pull\Event::add($pushList, Array(
				'module_id' => 'im',
				'command' => 'chatHide',
				'expiry' => 3600,
				'params' => Array(
					'dialogId' => 'chat'.$chatId,
					'chatId' => $chatId,
					'lines' => $lines
				),
				'extra' => \Bitrix\Im\Common::getPullExtra()
			));
		}

		return true;
	}

	public static function index($chatId)
	{
		$index =
			\Bitrix\Im\Internals\ChatIndex::create()
				->setChatId((int)$chatId)
		;
		static::fillChatIndexWithUserFullNames($index);

		\Bitrix\Im\Model\ChatTable::indexRecord($index);

		return true;
	}

	public static function addChatIndex(int $chatId, string $chatTitle)
	{
		$index =
			\Bitrix\Im\Internals\ChatIndex::create()
				->setChatId($chatId)
				->setTitle($chatTitle)
		;
		static::fillChatIndexWithUserFullNames($index);

		\Bitrix\Im\Model\ChatTable::addIndexRecord($index);

		return true;
	}

	public static function updateChatIndex($chatId)
	{
		$index =
			\Bitrix\Im\Internals\ChatIndex::create()
				->setChatId((int)$chatId)
		;
		static::fillChatIndexWithUserFullNames($index);

		\Bitrix\Im\Model\ChatTable::updateIndexRecord($index);

		return true;
	}

	public static function fillChatIndexWithUserFullNames(\Bitrix\Im\Internals\ChatIndex $index)
	{
		$query =
			\Bitrix\Im\Model\RelationTable::query()
				->addSelect('USER_ID')
				->where('CHAT_ID', $index->getChatId())
				->setLimit(100)
		;

		$users = [];
		foreach ($query->exec() as $relation)
		{
			$users[] = \Bitrix\Im\User::getInstance($relation['USER_ID'])->getFullName(false);
		}

		$index->setUserList($users);
	}

	public static function getNextConferenceDefaultTitle()
	{
		$counter = CGlobalCounter::GetValue('im_videoconf_count', CGlobalCounter::ALL_SITES) + 1;

		return GetMessage('IM_VIDEOCONF_NAME_FORMAT_NEW', [
			'#NUMBER#' => $counter
		]);
	}

	public static function isNewChat(string $type, ?DateTime $dateCreate): bool
	{
		if ($type !== Chat::IM_TYPE_OPEN_CHANNEL || $dateCreate === null)
		{
			return false;
		}

		$lastDay = (new DateTime())->add('-1 day');

		return $dateCreate->getTimestamp() > $lastDay->getTimestamp();
	}

	public static function canDo(array $chatData, array $relations, IM\V2\Permission\Action $action, mixed $target = null): bool
	{
		$chatData['RELATIONS'] = new IM\V2\RelationCollection($relations);

		return self::initChatByArray($chatData)->canDo($action, $target);
	}

	public static function initChatByArray(array $chatData): Chat
	{
		$preparedChatData = $chatData;
		$preparedChatData['ID'] = $chatData['ID'] ?? $chatData['CHAT_ID'] ?? $chatData['ITEM_CID'] ?? null;
		$preparedChatData['TYPE'] = $chatData['TYPE'] ?? $chatData['CHAT_TYPE'] ?? null;
		$preparedChatData['ENTITY_TYPE'] = $chatData['ENTITY_TYPE'] ?? $chatData['CHAT_ENTITY_TYPE'] ?? null;
		$preparedChatData['ENTITY_ID'] = $chatData['ENTITY_ID'] ?? $chatData['CHAT_ENTITY_ID'] ?? null;
		$preparedChatData['ENTITY_DATA_1'] = $chatData['ENTITY_DATA_1'] ?? $chatData['CHAT_ENTITY_DATA_1'] ?? null;
		$preparedChatData['ENTITY_DATA_2'] = $chatData['ENTITY_DATA_2'] ?? $chatData['CHAT_ENTITY_DATA_2'] ?? null;
		$preparedChatData['ENTITY_DATA_3'] = $chatData['ENTITY_DATA_3'] ?? $chatData['CHAT_ENTITY_DATA_3'] ?? null;
		$preparedChatData['DATE_CREATE'] = $chatData['DATE_CREATE'] ?? $chatData['CHAT_DATE_CREATE'] ?? null;

		return Chat\ChatFactory::getInstance()->initChat($preparedChatData);
	}

	public static function getGroupTypes(): array
	{
		return [
			Chat::IM_TYPE_OPEN,
			Chat::IM_TYPE_CHAT,
			Chat::IM_TYPE_OPEN_LINE,
			Chat::IM_TYPE_COPILOT,
			Chat::IM_TYPE_CHANNEL,
			Chat::IM_TYPE_OPEN_CHANNEL,
			Chat::IM_TYPE_COLLAB,
			Chat::IM_TYPE_EXTERNAL,
		];
	}

	public static function getGroupTypesExtra(): array
	{
		$types = self::getGroupTypes();
		$types[] = Chat::IM_TYPE_COMMENT;

		return $types;
	}

	public static function implodeTypesForQuery(array $types): string
	{
		return "'" . implode("','", $types) . "'";
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit