%PDF- %PDF-
Direktori : /www/varak.net/mail2.varak.net_old/libraries/afterlogic/common/managers/mail/ |
Current File : /www/varak.net/mail2.varak.net_old/libraries/afterlogic/common/managers/mail/manager.php |
<?php /* * Copyright 2004-2014, AfterLogic Corp. * Licensed under AGPLv3 license or AfterLogic license * if commercial version of the product was purchased. * See the LICENSE file for a full license statement. */ /** * @package Mail */ class CApiMailManager extends AApiManagerWithStorage { /** * @var array */ protected $aImapClientCache; /** * @param CApiGlobalManager &$oManager */ public function __construct(CApiGlobalManager &$oManager, $sForcedStorage = '') { parent::__construct('mail', $oManager); $this->inc('classes.enum'); $this->inc('classes.folder'); $this->inc('classes.folder-collection'); $this->inc('classes.message'); $this->inc('classes.message-collection'); $this->inc('classes.attachment'); $this->inc('classes.attachment-collection'); $this->inc('classes.ics'); $this->inc('classes.vcard'); $this->aImapClientCache = array(); } /** * @param CAccount $oAccount * @param int $iForceConnectTimeOut = 0 * @param int $iForceSocketTimeOut = 0 * * @return \MailSo\Imap\ImapClient|null */ protected function &getImapClient(CAccount $oAccount, $iForceConnectTimeOut = 0, $iForceSocketTimeOut = 0) { $oResult = null; if ($oAccount) { $sCacheKey = $oAccount->Email; if (!isset($this->aImapClientCache[$sCacheKey])) { $iConnectTimeOut = CApi::GetConf('socket.connect-timeout', 10); $iSocketTimeOut = CApi::GetConf('socket.get-timeout', 20); $bVerifySsl = !!CApi::GetConf('socket.verify-ssl', false); if (0 < $iForceConnectTimeOut) { $iConnectTimeOut = $iForceConnectTimeOut; } if (0 < $iForceSocketTimeOut) { $iSocketTimeOut = $iForceSocketTimeOut; } CApi::Plugin()->RunHook('webmail-imap-update-socket-timeouts', array(&$iConnectTimeOut, &$iSocketTimeOut)); $this->aImapClientCache[$sCacheKey] = \MailSo\Imap\ImapClient::NewInstance(); $this->aImapClientCache[$sCacheKey]->SetTimeOuts($iConnectTimeOut, $iSocketTimeOut); // TODO $this->aImapClientCache[$sCacheKey]->SetLogger(\CApi::MailSoLogger()); } $oResult =& $this->aImapClientCache[$sCacheKey]; if (!$oResult->IsConnected()) { $oResult->Connect($oAccount->IncomingMailServer, $oAccount->IncomingMailPort, $oAccount->IncomingMailUseSSL ? \MailSo\Net\Enumerations\ConnectionSecurityType::SSL : \MailSo\Net\Enumerations\ConnectionSecurityType::NONE, $bVerifySsl); } if (!$oResult->IsLoggined()) { $sProxyAuthUser = !empty($oAccount->CustomFields['ProxyAuthUser']) ? $oAccount->CustomFields['ProxyAuthUser'] : ''; $oResult->Login($oAccount->IncomingMailLogin, $oAccount->IncomingMailPassword, $sProxyAuthUser); } } return $oResult; } /** * @param CAccount $oAccount * * @return \MailSo\Imap\ImapClient|null * @throws CApiManagerException */ public function &ImapClient(CAccount $oAccount, $iForceConnectTimeOut = 0, $iForceSocketTimeOut = 0) { $oImap = false; try { $oImap =& $this->getImapClient($oAccount, $iForceConnectTimeOut, $iForceSocketTimeOut); } catch (\Exception $oException) { } return $oImap; } /** * @param CAccount $oAccount * * @throws CApiManagerException */ public function ValidateAccountConnection($oAccount) { try { $oImapClient = null; $oImapClient =& $this->getImapClient($oAccount); } catch (\MailSo\Net\Exceptions\SocketCanNotConnectToHostException $oException) { throw new CApiManagerException(Errs::Mail_AccountConnectToMailServerFailed, $oException); } catch (\MailSo\Imap\Exceptions\LoginBadCredentialsException $oException) { throw new CApiManagerException(Errs::Mail_AccountAuthentication, $oException); } catch (\Exception $oException) { throw new CApiManagerException(Errs::Mail_AccountLoginFailed, $oException); } } /** * @param CAccount $oAccount * @param array $aSystemNames [FolderFullName => FolderType, ...] * * @return void */ public function SetSystemFolderNames($oAccount, $aSystemNames) { return $this->oStorage->SetSystemFolderNames($oAccount, $aSystemNames); } /** * @param CAccount $oAccount * * @return array */ public function GetSystemFolderNames($oAccount) { return $this->oStorage->GetSystemFolderNames($oAccount); } /** * @param CAccount $oAccount * @param CApiMailFolderCollection $oFolderCollection * @param bool $bCreateUnExistenSystemFilders * * @return bool */ private function initSystemFolders($oAccount, &$oFolderCollection, $bCreateUnExistenSystemFilders) { $bAddSystemFolder = false; try { $aFoldersMap = $oAccount->Domain->GetFoldersMap(); unset($aFoldersMap[EFolderType::Inbox]); if (!$oAccount->IsEnabledExtension(CAccount::SpamFolderExtension) && isset($aFoldersMap[EFolderType::Spam])) { unset($aFoldersMap[EFolderType::Spam]); } $aTypes = array_keys($aFoldersMap); $aUnExistenSystemNames = array(); $aSystemNames = $this->GetSystemFolderNames($oAccount); $oInbox = $oFolderCollection->GetByFullNameRaw('INBOX'); $oInbox->SetType(EFolderType::Inbox); if (is_array($aSystemNames) && 0 < count($aSystemNames)) { unset($aSystemNames['INBOX']); $aUnExistenSystemNames = $aSystemNames; foreach ($aSystemNames as $sSystemFolderFullName => $iFolderType) { $iKey = array_search($iFolderType, $aTypes); if (false !== $iKey) { $oFolder = /* @var $oFolder CApiMailFolder */ $oFolderCollection->GetByFullNameRaw($sSystemFolderFullName, true); if ($oFolder) { unset($aTypes[$iKey]); unset($aFoldersMap[$iKey]); unset($aUnExistenSystemNames[$sSystemFolderFullName]); $oFolder->SetType($iFolderType); } } } } else { // set system type from flags $oFolderCollection->ForeachListWithSubFolders(function (/* @var $oFolder CApiMailFolder */ $oFolder) use (&$aTypes, &$aFoldersMap) { $iXListType = $oFolder->GetFolderXListType(); $iKey = array_search($iXListType, $aTypes); if (false !== $iKey && EFolderType::Custom === $oFolder->Type() && isset($aFoldersMap[$iXListType])) { unset($aTypes[$iKey]); unset($aFoldersMap[$iXListType]); $oFolder->SetType($iXListType); } } ); // set system type from domain settings if (is_array($aFoldersMap) && 0 < count($aFoldersMap)) { $oFolderCollection->ForeachListOnRootInboxAndGmailSubFolder( function (/* @var $oFolder CApiMailFolder */ $oFolder) use (&$aFoldersMap) { if (EFolderType::Custom === $oFolder->Type()) { foreach ($aFoldersMap as $iFolderType => $aFoldersNames) { $aList = array(); if (is_array($aFoldersNames)) { $aList = $aFoldersNames; } else if (is_string($aFoldersNames)) { $aList = array($aFoldersNames); } if (is_array($aList) && 0 < count($aList)) { if (in_array($oFolder->NameRaw(), $aList) || in_array($oFolder->Name(), $aList)) { unset($aFoldersMap[$iFolderType]); $oFolder->SetType($iFolderType); } } } } } ); } if (is_array($aFoldersMap) && 0 < count($aFoldersMap)) { $sNamespace = $oFolderCollection->GetNamespace(); foreach ($aFoldersMap as $iFolderType => $mFolderName) { $sFolderFullName = is_array($mFolderName) && isset($mFolderName[0]) && is_string($mFolderName[0]) && 0 < strlen($mFolderName[0]) ? $mFolderName[0] : (is_string($mFolderName) && 0 < strlen($mFolderName) ? $mFolderName : ''); if (0 < strlen($sFolderFullName)) { $aUnExistenSystemNames[$sNamespace.$sFolderFullName] = $iFolderType; } } } } if ($bCreateUnExistenSystemFilders && is_array($aUnExistenSystemNames) && 0 < count($aUnExistenSystemNames)) { foreach ($aUnExistenSystemNames as $sFolderFullName => $iFolderType) { $this->FolderCreateFromFullNameRaw($oAccount, $sFolderFullName); $bAddSystemFolder = true; } } } catch (Exception $oException) { $bAddSystemFolder = false; } return $bAddSystemFolder; } /** * @param CAccount $oAccount * @param bool $bCreateUnExistenSystemFolders = true * * @return CApiMailFolderCollection */ public function Folders($oAccount, $bCreateUnExistenSystemFolders = true) { $oFolderCollection = false; $sParent = ''; $sListPattern = '*'; $oImapClient =& $this->getImapClient($oAccount); $oNamespace = $oImapClient->GetNamespace(); $aFolders = $oImapClient->FolderList($sParent, $sListPattern); $aSubscribedFolders = $oImapClient->FolderSubscribeList($sParent, $sListPattern); $aImapSubscribedFoldersHelper = array(); if (is_array($aSubscribedFolders)) { foreach ($aSubscribedFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) { $aImapSubscribedFoldersHelper[] = $oImapFolder->FullNameRaw(); } } $aMailFoldersHelper = null; if (is_array($aFolders)) { $aMailFoldersHelper = array(); foreach ($aFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) { $aMailFoldersHelper[] = CApiMailFolder::NewInstance($oImapFolder, in_array($oImapFolder->FullNameRaw(), $aImapSubscribedFoldersHelper) || $oImapFolder->IsInbox() ); } } if (is_array($aMailFoldersHelper)) { $oFolderCollection = CApiMailFolderCollection::NewInstance(); if ($oNamespace) { $oFolderCollection->SetNamespace($oNamespace->GetPersonalNamespace()); } $oFolderCollection->InitByUnsortedMailFolderArray($aMailFoldersHelper); if ($this->initSystemFolders($oAccount, $oFolderCollection, $bCreateUnExistenSystemFolders) && $bCreateUnExistenSystemFolders) { $oFolderCollection = $this->Folders($oAccount, false); } } if ($oFolderCollection && $oNamespace) { $oFolderCollection->SetNamespace($oNamespace->GetPersonalNamespace()); } $aFoldersOrderList = null; if (!$oAccount->IsEnabledExtension(CAccount::DisableFoldersManualSort)) { $aFoldersOrderList = $this->FoldersOrder($oAccount); $aFoldersOrderList = is_array($aFoldersOrderList) && 0 < count($aFoldersOrderList) ? $aFoldersOrderList : null; } $oFolderCollection->SortByCallback(function ($oFolderA, $oFolderB) use ($aFoldersOrderList) { if (!$aFoldersOrderList) { if (EFolderType::Custom !== $oFolderA->Type() || EFolderType::Custom !== $oFolderB->Type()) { if ($oFolderA->Type() === $oFolderB->Type()) { return 0; } return $oFolderA->Type() < $oFolderB->Type() ? -1 : 1; } } else { $iPosA = array_search($oFolderA->FullNameRaw(), $aFoldersOrderList); $iPosB = array_search($oFolderB->FullNameRaw(), $aFoldersOrderList); if (is_int($iPosA) && is_int($iPosB)) { return $iPosA < $iPosB ? -1 : 1; } else if (is_int($iPosA)) { return -1; } else if (is_int($iPosB)) { return 1; } } return strnatcmp($oFolderA->FullName(), $oFolderB->FullName()); }); if (null === $aFoldersOrderList && !$oAccount->IsEnabledExtension(CAccount::DisableFoldersManualSort)) { $aNewFoldersOrderList = array(); $oFolderCollection->ForeachListWithSubFolders(function (/* @var $oFolder CApiMailFolder */ $oFolder) use (&$aNewFoldersOrderList) { if ($oFolder) { $aNewFoldersOrderList[] = $oFolder->FullNameRaw(); } }); if (0 < count($aNewFoldersOrderList)) { $this->FoldersOrderUpdate($oAccount, $aNewFoldersOrderList); } } // if ($oAccount && $oFolderCollection && $oAccount->IsGmailAccount()) // { // $oFolder = null; // $oFolder =& $oFolderCollection->GetByFullNameRaw('[Gmail]'); // if ($oFolder) // { // $oFolder->SetGmailFolder(true); // } // } return $oFolderCollection; } /** * @param CAccount $oAccount * * @return array */ public function FoldersOrder($oAccount) { return $this->oStorage->FoldersOrder($oAccount); } /** * @param CAccount $oAccount * @param array $aOrder * * @return array */ public function FoldersOrderUpdate($oAccount, $aOrder) { return $this->oStorage->FoldersOrderUpdate($oAccount, $aOrder); } /** * @param CAccount $oAccount * @param string $sFolderFullNameRaw * @param bool $bSubscribeOnCreation = true * * @throws CApiInvalidArgumentException */ public function FolderCreateFromFullNameRaw($oAccount, $sFolderFullNameRaw, $bSubscribeOnCreation = true) { if (0 === strlen($sFolderFullNameRaw)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); $oImapClient->FolderCreate($sFolderFullNameRaw); if ($bSubscribeOnCreation) { $oImapClient->FolderSubscribe($sFolderFullNameRaw); } } /** * @param type $oImapClient * @param type $sFolderFullNameRaw * * @return array [$iMessageCount, $iMessageUnseenCount, $sUidNext] */ private function folderInformation($oImapClient, $sFolderFullNameRaw) { $aFolderStatus = $oImapClient->FolderStatus($sFolderFullNameRaw, array( \MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES, \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN, \MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT )); $iStatusMessageCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES]) ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES] : 0; $iStatusMessageUnseenCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN]) ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0; $sStatusUidNext = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT]) ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT] : '0'; if (0 === strlen($sStatusUidNext)) { $sStatusUidNext = '0'; } // gmail hack $oFolder = $oImapClient->FolderCurrentInformation(); if ($oFolder && null !== $oFolder->Exists && $oFolder->FolderName === $sFolderFullNameRaw) { $iSubCount = (int) $oFolder->Exists; if (0 < $iSubCount && $iSubCount < $iStatusMessageCount) { $iStatusMessageCount = $iSubCount; } } return array($iStatusMessageCount, $iStatusMessageUnseenCount, $sStatusUidNext, api_Utils::GenerateFolderHash($sFolderFullNameRaw, $iStatusMessageCount, $iStatusMessageUnseenCount, $sStatusUidNext)); } /** * @param CAccount $oAccount * @param string $sExtentionName * * @return bool */ public function IsSupported($oAccount, $sExtentionName) { if (0 === strlen($sExtentionName)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); return $oImapClient->IsSupported($sExtentionName); } /** * @param CAccount $oAccount * @param string $sFolderFullNameRaw * * @return array */ public function FolderCounts($oAccount, $sFolderFullNameRaw) { if (0 === strlen($sFolderFullNameRaw)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); return $this->folderInformation($oImapClient, $sFolderFullNameRaw); } /** * @param CAccount $oAccount * @param string $sFolderFullNameRaw * @param string $sUidnext * * @return array */ public function GetNextMessages($oAccount, $sFolderFullNameRaw, $sUidnext) { if (0 === strlen($sFolderFullNameRaw) || 0 === strlen($sFolderFullNameRaw)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); $oImapClient->FolderExamine($sFolderFullNameRaw); $aResult = array(); $aFetchResponse = $oImapClient->Fetch(array( \MailSo\Imap\Enumerations\FetchType::INDEX, \MailSo\Imap\Enumerations\FetchType::UID, \MailSo\Imap\Enumerations\FetchType::FLAGS, \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( \MailSo\Mime\Enumerations\Header::FROM_, \MailSo\Mime\Enumerations\Header::SUBJECT, \MailSo\Mime\Enumerations\Header::CONTENT_TYPE )) ), $sUidnext.':*', true); if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse)) { foreach ($aFetchResponse as /* @var $oFetchResponse \MailSo\Imap\FetchResponse */ $oFetchResponse) { $aFlags = \array_map('strtolower', $oFetchResponse->GetFetchValue( \MailSo\Imap\Enumerations\FetchType::FLAGS)); if (!\in_array(\strtolower(\MailSo\Imap\Enumerations\MessageFlag::SEEN), $aFlags)) { $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID); $sHeaders = $oFetchResponse->GetHeaderFieldsValue(); $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sHeaders); $sContentTypeCharset = $oHeaders->ParameterValue( \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, \MailSo\Mime\Enumerations\Parameter::CHARSET ); $sCharset = ''; if (0 < \strlen($sContentTypeCharset)) { $sCharset = $sContentTypeCharset; } if (0 < \strlen($sCharset)) { $oHeaders->SetParentCharset($sCharset); } $aResult[] = array( 'Folder' => $sFolderFullNameRaw, 'Uid' => $sUid, 'Subject' => $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT, 0 === \strlen($sCharset)), 'From' => $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::FROM_, 0 === \strlen($sCharset)) ); } } } return $aResult; } /** * @param CAccount $oAccount * @param array $aFolderFullNamesRaw * @param array $aNewInboxData * @param string $sInboxUidnext = '' * * @return array */ public function FolderCountsFromArray($oAccount, $aFolderFullNamesRaw, &$aNewInboxData, $sInboxUidnext = '') { if (!is_array($aFolderFullNamesRaw) || 0 === count($aFolderFullNamesRaw)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); $aResult = array(); if (2 < count($aFolderFullNamesRaw) && $oImapClient->IsSupported('LIST-STATUS')) { $aFolders = $oImapClient->FolderStatusList(); if (is_array($aFolders)) { foreach ($aFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) { $oFolder = CApiMailFolder::NewInstance($oImapFolder, true); if ($oFolder) { $mStatus = $oFolder->Status(); if (is_array($mStatus) && isset($mStatus['MESSAGES'], $mStatus['UNSEEN'], $mStatus['UIDNEXT'])) { $aResult[$oFolder->FullNameRaw()] = array( (int) $mStatus['MESSAGES'], (int) $mStatus['UNSEEN'], (string) $mStatus['UIDNEXT'], \api_Utils::GenerateFolderHash( $oFolder->FullNameRaw(), $mStatus['MESSAGES'], $mStatus['UNSEEN'], $mStatus['UIDNEXT']) ); } } unset($oFolder); } } } else { foreach ($aFolderFullNamesRaw as $sFolderFullNameRaw) { $sFolderFullNameRaw = (string) $sFolderFullNameRaw; try { $aResult[$sFolderFullNameRaw] = $this->folderInformation($oImapClient, $sFolderFullNameRaw); } catch (\Exception $oException) {} } } if (0 < strlen($sInboxUidnext) && isset($aResult['INBOX'], $aResult['INBOX'][2]) && $aResult['INBOX'][2] !== $sInboxUidnext) { $aNewInboxData = $this->GetNextMessages($oAccount, 'INBOX', $sInboxUidnext); } return $aResult; } /** * @param CAccount $oAccount * @param string $sFolderNameInUtf8 * @param string $sDelimiter * @param string $sFolderParentFullNameRaw = '' * @param bool $bSubscribeOnCreation = true * * @throws CApiInvalidArgumentException * @throws CApiBaseException */ public function FolderCreate($oAccount, $sFolderNameInUtf8, $sDelimiter, $sFolderParentFullNameRaw = '', $bSubscribeOnCreation = true) { if (0 === strlen($sFolderNameInUtf8) || 0 === strlen($sDelimiter)) { throw new CApiInvalidArgumentException(); } $sFolderNameInUtf8 = trim($sFolderNameInUtf8); if (0 < strlen($sFolderParentFullNameRaw)) { $sFolderParentFullNameRaw .= $sDelimiter; } $sNameToCreate = \MailSo\Base\Utils::ConvertEncoding($sFolderNameInUtf8, \MailSo\Base\Enumerations\Charset::UTF_8, \MailSo\Base\Enumerations\Charset::UTF_7_IMAP); if (0 < strlen($sDelimiter) && false !== strpos($sNameToCreate, $sDelimiter)) { // TODO throw new CApiBaseException(Errs::Mail_FolderNameContainDelimiter); } $this->FolderCreateFromFullNameRaw( $oAccount, $sFolderParentFullNameRaw.$sNameToCreate, $bSubscribeOnCreation); } /** * @param CAccount $oAccount * @param string $sFolderFullNameRaw * @param bool $bUnsubscribeOnDeletion = true * * @throws CApiInvalidArgumentException */ public function FolderDelete($oAccount, $sFolderFullNameRaw, $bUnsubscribeOnDeletion = true) { if (0 === strlen($sFolderFullNameRaw)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); if ($bUnsubscribeOnDeletion) { $oImapClient->FolderUnSubscribe($sFolderFullNameRaw); } $oImapClient->FolderDelete($sFolderFullNameRaw); } /** * @param CAccount $oAccount * @param string $sPrevFolderFullNameRaw * @param string $sNewTopFolderNameInUtf8 = '' * * @return string * * @throws CApiInvalidArgumentException * @throws CApiBaseException */ public function FolderRename($oAccount, $sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf8) { $sNewTopFolderNameInUtf8 = trim($sNewTopFolderNameInUtf8); if (0 === strlen($sPrevFolderFullNameRaw) || 0 === strlen($sNewTopFolderNameInUtf8)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); $aFolders = $oImapClient->FolderList('', $sPrevFolderFullNameRaw); if (!is_array($aFolders) || !isset($aFolders[0])) { // TODO throw new CApiBaseException(Errs::Mail_CannotRenameNonExistenFolder); } $sDelimiter = $aFolders[0]->Delimiter(); $iLast = strrpos($sPrevFolderFullNameRaw, $sDelimiter); $sFolderParentFullNameRaw = false === $iLast ? '' : substr($sPrevFolderFullNameRaw, 0, $iLast + 1); $aSubscribeFolders = $oImapClient->FolderSubscribeList($sPrevFolderFullNameRaw, '*'); if (is_array($aSubscribeFolders) && 0 < count($aSubscribeFolders)) { foreach ($aSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) { $oImapClient->FolderUnSubscribe($oFolder->FullNameRaw()); } } $sNewFolderFullNameRaw = \MailSo\Base\Utils::ConvertEncoding($sNewTopFolderNameInUtf8, \MailSo\Base\Enumerations\Charset::UTF_8, \MailSo\Base\Enumerations\Charset::UTF_7_IMAP); if (0 < strlen($sDelimiter) && false !== strpos($sNewFolderFullNameRaw, $sDelimiter)) { // TODO throw new CApiBaseException(Errs::Mail_FolderNameContainDelimiter); } $sNewFolderFullNameRaw = $sFolderParentFullNameRaw.$sNewFolderFullNameRaw; $oImapClient->FolderRename($sPrevFolderFullNameRaw, $sNewFolderFullNameRaw); if (is_array($aSubscribeFolders) && 0 < count($aSubscribeFolders)) { foreach ($aSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) { $sFolderFullNameRawForResubscrine = $oFolder->FullNameRaw(); if (0 === strpos($sFolderFullNameRawForResubscrine, $sPrevFolderFullNameRaw)) { $sNewFolderFullNameRawForResubscrine = $sNewFolderFullNameRaw. substr($sFolderFullNameRawForResubscrine, strlen($sPrevFolderFullNameRaw)); $oImapClient->FolderSubscribe($sNewFolderFullNameRawForResubscrine); } } } $aOrders = $this->oStorage->FoldersOrder($oAccount); if (is_array($aOrders)) { foreach ($aOrders as &$sName) { if ($sPrevFolderFullNameRaw === $sName) { $sName = $sNewFolderFullNameRaw; $this->oStorage->FoldersOrderUpdate($oAccount, $aOrders); break; } } } return $sNewFolderFullNameRaw; } /** * @param CAccount $oAccount * @param string $sFolderFullNameRaw * @param bool $bSubscribeAction = true * * @throws CApiInvalidArgumentException */ public function FolderSubscribe($oAccount, $sFolderFullNameRaw, $bSubscribeAction = true) { if (0 === strlen($sFolderFullNameRaw)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); if ($bSubscribeAction) { $oImapClient->FolderSubscribe($sFolderFullNameRaw); } else { $oImapClient->FolderUnSubscribe($sFolderFullNameRaw); } } /** * @param CAccount $oAccount * @param string $sFolderFullNameRaw * * @throws CApiInvalidArgumentException */ public function FolderClear($oAccount, $sFolderFullNameRaw) { if (0 === strlen($sFolderFullNameRaw)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); $oImapClient->FolderSelect($sFolderFullNameRaw); $oInfo = $oImapClient->FolderCurrentInformation(); if ($oInfo && 0 < $oInfo->Exists) { $oImapClient->MessageStoreFlag('1:*', false, array(\MailSo\Imap\Enumerations\MessageFlag::DELETED), \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT ); } $oImapClient->MessageExpunge(); } /** * @param int $iSortOrder * * @return array */ protected function getSortTypesByTypeAndOrder($iSortOrder) { $aResult = array('ARRIVAL'); if (ESortOrder::DESC === $iSortOrder && 0 < count($aResult)) { array_unshift($aResult, 'REVERSE'); } return $aResult; } /** * @param CAccount $oAccount * @param string $sFolderFullNameRaw * @param array $aUids * * @throws CApiInvalidArgumentException */ public function MessageDelete($oAccount, $sFolderFullNameRaw, $aUids) { if (0 === strlen($sFolderFullNameRaw) || !is_array($aUids) || 0 === count($aUids)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); $oImapClient->FolderSelect($sFolderFullNameRaw); $sUidsRange = implode(',', $aUids); $oImapClient->MessageStoreFlag($sUidsRange, true, array(\MailSo\Imap\Enumerations\MessageFlag::DELETED), \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT ); $oImapClient->MessageExpunge($sUidsRange, true); } /** * @param CAccount $oAccount * @param string $sFromFolderFullNameRaw * @param string $sToFolderFullNameRaw * @param array $aUids * * @throws CApiInvalidArgumentException */ public function MessageMove($oAccount, $sFromFolderFullNameRaw, $sToFolderFullNameRaw, $aUids) { if (0 === strlen($sFromFolderFullNameRaw) || 0 === strlen($sToFolderFullNameRaw) || !is_array($aUids) || 0 === count($aUids)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); $oImapClient->FolderSelect($sFromFolderFullNameRaw); if ($oImapClient->IsSupported('MOVE')) { $oImapClient->MessageMove($sToFolderFullNameRaw, implode(',', $aUids), true); } else { $oImapClient->MessageCopy($sToFolderFullNameRaw, implode(',', $aUids), true); $this->MessageDelete($oAccount, $sFromFolderFullNameRaw, $aUids); } } public function MessageCopy($oAccount, $sFromFolderFullNameRaw, $sToFolderFullNameRaw, $aUids) { if (0 === strlen($sFromFolderFullNameRaw) || 0 === strlen($sToFolderFullNameRaw) || !is_array($aUids) || 0 === count($aUids)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); $oImapClient->FolderSelect($sFromFolderFullNameRaw); $oImapClient->MessageCopy($sToFolderFullNameRaw, implode(',', $aUids), true); } /** * @param CAccount $oAccount * @param \MailSo\Mime\Message $oMessage * @param CFetcher $oFetcher = null * @param string $sSentFolder = '' * @param string $sDraftFolder = '' * @param string $sDraftUid = '' * * @return array|bool * * @throws CApiInvalidArgumentException */ public function MessageSend($oAccount, $oMessage, $oFetcher = null, $sSentFolder = '', $sDraftFolder = '', $sDraftUid = '') { if (!$oAccount || !$oMessage) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); $rMessageStream = \MailSo\Base\ResourceRegistry::CreateMemoryResource(); $iMessageStreamSize = \MailSo\Base\Utils::MultipleStreamWriter( $oMessage->ToStream(true), array($rMessageStream), 8192, true, true, true); $mResult = false; if (false !== $iMessageStreamSize && is_resource($rMessageStream)) { $oRcpt = $oMessage->GetRcpt(); if ($oRcpt && 0 < $oRcpt->Count()) { $sRcptEmail = ''; try { $iConnectTimeOut = CApi::GetConf('socket.connect-timeout', 5); $iSocketTimeOut = CApi::GetConf('socket.get-timeout', 5); $bVerifySsl = !!CApi::GetConf('socket.verify-ssl', false); CApi::Plugin()->RunHook('webmail-smtp-update-socket-timeouts', array(&$iConnectTimeOut, &$iSocketTimeOut)); $oSmtpClient = \MailSo\Smtp\SmtpClient::NewInstance(); $oSmtpClient->SetTimeOuts($iConnectTimeOut, $iSocketTimeOut); $oLogger = $oImapClient->Logger(); if ($oLogger) { $oSmtpClient->SetLogger($oLogger); } $iSecure = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT; if ($oFetcher) { $iSecure = $oFetcher->OutgoingMailSecurity; } else if ($oAccount->OutgoingMailUseSSL) { $iSecure = \MailSo\Net\Enumerations\ConnectionSecurityType::SSL; } $sOutgoingMailLogin = ''; if ($oFetcher) { $sOutgoingMailLogin = $oFetcher->IncomingMailLogin; } if (0 === strlen($sOutgoingMailLogin)) { $sOutgoingMailLogin = $oAccount->OutgoingMailLogin; $sOutgoingMailLogin = 0 < strlen($sOutgoingMailLogin) ? $sOutgoingMailLogin : $oAccount->IncomingMailLogin; } $sOutgoingMailPassword = ''; if ($oFetcher) { $sOutgoingMailPassword = $oFetcher->IncomingMailPassword; } if (0 === strlen($sOutgoingMailPassword)) { $sOutgoingMailPassword = $oAccount->OutgoingMailPassword; $sOutgoingMailPassword = 0 < strlen($sOutgoingMailPassword) ? $sOutgoingMailPassword : $oAccount->IncomingMailPassword; } $sEhlo = \MailSo\Smtp\SmtpClient::EhloHelper(); CApi::Plugin()->RunHook('api-smtp-send-ehlo', array($oAccount, &$sEhlo)); if ($oFetcher) { $oSmtpClient->Connect($oFetcher->OutgoingMailServer, $oFetcher->OutgoingMailPort, $sEhlo, $iSecure, $bVerifySsl); } else { $oSmtpClient->Connect($oAccount->OutgoingMailServer, $oAccount->OutgoingMailPort, $sEhlo, $iSecure, $bVerifySsl); } if (($oFetcher && $oFetcher->OutgoingMailAuth) || (!$oFetcher && $oAccount->OutgoingMailAuth)) { $oSmtpClient->Login($sOutgoingMailLogin, $sOutgoingMailPassword); } $oSmtpClient->MailFrom($oFetcher ? $oFetcher->Email : $oAccount->Email, (string) $iMessageStreamSize); $aRcpt =& $oRcpt->GetAsArray(); CApi::Plugin()->RunHook('api-smtp-send-rcpt', array($oAccount, &$aRcpt)); foreach ($aRcpt as /* @var $oEmail \MailSo\Mime\Email */ $oEmail) { $sRcptEmail = $oEmail->GetEmail(); $oSmtpClient->Rcpt($sRcptEmail); } $oSmtpClient->DataWithStream($rMessageStream); $oSmtpClient->LogoutAndDisconnect(); } catch (\MailSo\Net\Exceptions\ConnectionException $oException) { throw new \CApiManagerException(Errs::Mail_AccountConnectToMailServerFailed, $oException); } catch (\MailSo\Smtp\Exceptions\LoginException $oException) { throw new \CApiManagerException(Errs::Mail_AccountLoginFailed, $oException); } catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) { throw new \CApiManagerException(Errs::Mail_CannotSendMessage, $oException); } catch (\MailSo\Smtp\Exceptions\MailboxUnavailableException $oException) { throw new \CApiManagerException(Errs::Mail_MailboxUnavailable, $oException, array(), array('Mailbox' => $sRcptEmail)); } if (0 < strlen($sSentFolder)) { try { if (!$oMessage->GetBcc()) { if (is_resource($rMessageStream)) { rewind($rMessageStream); } $oImapClient->MessageAppendStream( $sSentFolder, $rMessageStream, $iMessageStreamSize, array( \MailSo\Imap\Enumerations\MessageFlag::SEEN )); } else { $rAppendMessageStream = \MailSo\Base\ResourceRegistry::CreateMemoryResource(); $iAppendMessageStreamSize = \MailSo\Base\Utils::MultipleStreamWriter( $oMessage->ToStream(false), array($rAppendMessageStream), 8192, true, true, true); $oImapClient->MessageAppendStream( $sSentFolder, $rAppendMessageStream, $iAppendMessageStreamSize, array( \MailSo\Imap\Enumerations\MessageFlag::SEEN )); if (is_resource($rAppendMessageStream)) { @fclose($rAppendMessageStream); } } } catch (\Exception $oException) { throw new \CApiManagerException(Errs::Mail_CannotSaveMessageInSentItems, $oException); } if (is_resource($rMessageStream)) { @fclose($rMessageStream); } } if (0 < strlen($sDraftFolder) && 0 < strlen($sDraftUid)) { try { $this->MessageDelete($oAccount, $sDraftFolder, array($sDraftUid)); } catch (\Exception $oException) {} } $mResult = true; } else { throw new \CApiManagerException(Errs::Mail_InvalidRecipients); } } return $mResult; } /** * @param CAccount $oAccount * @param \MailSo\Mime\Message $oMessage * @param string $sDraftFolder * @param string $sDraftUid = '' * * @return array|bool * * @throws CApiInvalidArgumentException */ public function MessageSave($oAccount, $oMessage, $sDraftFolder, $sDraftUid = '') { if (!$oAccount || !$oMessage || 0 === strlen($sDraftFolder)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); $rMessageStream = \MailSo\Base\ResourceRegistry::CreateMemoryResource(); $iMessageStreamSize = \MailSo\Base\Utils::MultipleStreamWriter( $oMessage->ToStream(false), array($rMessageStream), 8192, true, true); $mResult = false; if (false !== $iMessageStreamSize && is_resource($rMessageStream)) { rewind($rMessageStream); $iNewUid = 0; $oImapClient->MessageAppendStream( $sDraftFolder, $rMessageStream, $iMessageStreamSize, array( \MailSo\Imap\Enumerations\MessageFlag::SEEN ), $iNewUid); if (null === $iNewUid || 0 === $iNewUid) { $sMessageId = $oMessage->MessageId(); if (0 < strlen($sMessageId)) { $iNewUid = $this->FindMessageUidByMessageId($oAccount, $sDraftFolder, $sMessageId); } } $mResult = true; if (0 < strlen($sDraftFolder) && 0 < strlen($sDraftUid)) { $this->MessageDelete($oAccount, $sDraftFolder, array($sDraftUid)); } if (null !== $iNewUid && 0 < $iNewUid) { $mResult = array( 'NewFolder' => $sDraftFolder, 'NewUid' => $iNewUid ); } } return $mResult; } /** * @param CAccount $oAccount * @param string $sMessageFileName * @param string $sFolderToAppend * * @return void */ public function MessageAppendFile($oAccount, $sMessageFileName, $sFolderToAppend) { $oImapClient =& $this->getImapClient($oAccount); $oImapClient->MessageAppendFile($sMessageFileName, $sFolderToAppend); } /** * @param CAccount $oAccount * @param string $sFolderFullNameRaw * @param array $aUids * @param string $sFlagString * @param int $iAction = EMailMessageStoreAction::Add * @param bool $bSetToAll = false * @param bool $bSkipNonPermanentsFlags = false * * @return true * * @throws CApiInvalidArgumentException */ public function MessageFlag($oAccount, $sFolderFullNameRaw, $aUids, $sFlagString, $iAction = EMailMessageStoreAction::Add, $bSetToAll = false, $bSkipNonPermanentsFlags = false) { if (0 === strlen($sFolderFullNameRaw) || (!$bSetToAll && (!is_array($aUids) || 0 === count($aUids)))) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); $oImapClient->FolderSelect($sFolderFullNameRaw); $aUids = is_array($aUids) ? $aUids : array(); $sUids = implode(',', $aUids); $oInfo = $oImapClient->FolderCurrentInformation(); if ($bSetToAll) { $sUids = '1:*'; if ($oInfo && 0 === $oInfo->Exists) { return true; } } $aFlagsOut = array(); $aFlags = explode(' ', $sFlagString); if ($bSkipNonPermanentsFlags && $oInfo) { if (!\in_array('\\*', $oInfo->PermanentFlags)) { foreach ($aFlags as $sFlag) { $sFlag = \trim($sFlag); if (\in_array($sFlag, $oInfo->PermanentFlags)) { $aFlagsOut[] = $sFlag; } } } else { $aFlagsOut = $aFlags; } if (0 === \count($aFlagsOut)) { return true; } } else { $aFlagsOut = $aFlags; } $sResultAction = \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT; switch ($iAction) { case EMailMessageStoreAction::Add: $sResultAction = \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT; break; case EMailMessageStoreAction::Remove: $sResultAction = \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT; break; case EMailMessageStoreAction::Set: $sResultAction = \MailSo\Imap\Enumerations\StoreAction::SET_FLAGS_SILENT; break; } $oImapClient->MessageStoreFlag($sUids, $bSetToAll ? false : true, $aFlags, $sResultAction); return true; } /** * @param CAccount $oAccount * @param string $sFolderName * @param string $sMessageId * * @return int|null */ public function FindMessageUidByMessageId($oAccount, $sFolderName, $sMessageId) { if (0 === strlen($sFolderName) || 0 === strlen($sMessageId)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); $oImapClient->FolderExamine($sFolderName); $aUids = $oImapClient->MessageSimpleSearch('HEADER Message-ID '.$sMessageId, true); return is_array($aUids) && 1 === count($aUids) && is_numeric($aUids[0]) ? (int) $aUids[0] : null; } /** * @param CAccount $oAccount * * @return array|bool */ public function Quota($oAccount) { $oImapClient =& $this->getImapClient($oAccount); return $oImapClient->Quota(); } /** * @param CAccount $oAccount * @param string $sFolderFullNameRaw * @param int $iUid * @param string $sRfc822SubMimeIndex = '' * @param bool $bParseICalAndVcard = false * @param bool $bParseAsc = false * @param int $iBodyTextLimit = 0 * * @return CApiMailMessage * * @throws CApiInvalidArgumentException */ public function Message($oAccount, $sFolderFullNameRaw, $iUid, $sRfc822SubMimeIndex = '', $bParseICalAndVcard = false, $bParseAsc = false, $iBodyTextLimit = 0) { if (0 === strlen($sFolderFullNameRaw) || !is_numeric($iUid) || 0 >= (int) $iUid) { throw new CApiInvalidArgumentException(); } $iUid = (int) $iUid; $oImapClient =& $this->getImapClient($oAccount); $oImapClient->FolderExamine($sFolderFullNameRaw); $oMessage = false; $sICalMimeIndex = ''; $sVCardMimeIndex = ''; $aTextMimeIndexes = array(); $aAscPartsIds = array(); $aFetchResponse = $oImapClient->Fetch(array( \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE), $iUid, true); $oBodyStructure = (0 < count($aFetchResponse)) ? $aFetchResponse[0]->GetFetchBodyStructure($sRfc822SubMimeIndex) : null; if ($oBodyStructure) { $aTextParts = $oBodyStructure->SearchHtmlOrPlainParts(); if (is_array($aTextParts) && 0 < count($aTextParts)) { foreach ($aTextParts as $oPart) { $aTextMimeIndexes[] = array($oPart->PartID(), $oPart->Size()); } } if ($bParseICalAndVcard) { $aICalPart = $oBodyStructure->SearchByContentType('text/calendar'); $oICalPart = is_array($aICalPart) && 0 < count($aICalPart) ? $aICalPart[0] : null; $sICalMimeIndex = $oICalPart ? $oICalPart->PartID() : ''; $aVCardPart = $oBodyStructure->SearchByContentType('text/vcard'); $aVCardPart = $aVCardPart ? $aVCardPart : $oBodyStructure->SearchByContentType('text/x-vcard'); $oVCardPart = is_array($aVCardPart) && 0 < count($aVCardPart) ? $aVCardPart[0] : null; $sVCardMimeIndex = $oVCardPart ? $oVCardPart->PartID() : ''; } if ($bParseAsc) { $aAscParts = $oBodyStructure->SearchByCallback(function (/* @var $oPart \MailSo\Imap\BodyStructure */ $oPart) { return '.asc' === \strtolower(\substr(\trim($oPart->FileName()), -4)); }); if (is_array($aAscParts) && 0 < count($aAscParts)) { foreach ($aAscParts as $oPart) { $aAscPartsIds[] = $oPart->PartID(); } } } } $aFetchItems = array( \MailSo\Imap\Enumerations\FetchType::INDEX, \MailSo\Imap\Enumerations\FetchType::UID, \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE, \MailSo\Imap\Enumerations\FetchType::INTERNALDATE, \MailSo\Imap\Enumerations\FetchType::FLAGS, 0 < strlen($sRfc822SubMimeIndex) ? \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sRfc822SubMimeIndex.'.HEADER]' : \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK ); if (0 < count($aTextMimeIndexes)) { if (0 < strlen($sRfc822SubMimeIndex) && is_numeric($sRfc822SubMimeIndex)) { $sLine = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$aTextMimeIndexes[0][0].'.1]'; if (\is_numeric($iBodyTextLimit) && 0 < $iBodyTextLimit && $iBodyTextLimit < $aTextMimeIndexes[0][1]) { $sLine .= '<0.'.((int) $iBodyTextLimit).'>'; } $aFetchItems[] = $sLine; } else { foreach ($aTextMimeIndexes as $aTextMimeIndex) { $sLine = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$aTextMimeIndex[0].']'; if (\is_numeric($iBodyTextLimit) && 0 < $iBodyTextLimit && $iBodyTextLimit < $aTextMimeIndex[1]) { $sLine .= '<0.'.((int) $iBodyTextLimit).'>'; } $aFetchItems[] = $sLine; } } } if (0 < strlen($sICalMimeIndex)) { $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sICalMimeIndex.']'; } if (0 < strlen($sVCardMimeIndex)) { $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sVCardMimeIndex.']'; } if (0 < count($aAscPartsIds)) { foreach ($aAscPartsIds as $sPartID) { $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sPartID.']'; } } if (!$oBodyStructure) { $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE; } $aFetchResponse = $oImapClient->Fetch($aFetchItems, $iUid, true); if (0 < count($aFetchResponse)) { $oMessage = CApiMailMessage::NewFetchResponseInstance($sFolderFullNameRaw, $aFetchResponse[0], $oBodyStructure, $sRfc822SubMimeIndex, $aAscPartsIds); } if ($oMessage) { $sFromEmail = ''; $oFromCollection = $oMessage->From(); if ($oFromCollection && 0 < $oFromCollection->Count()) { $oFrom =& $oFromCollection->GetByIndex(0); if ($oFrom) { $sFromEmail = trim($oFrom->GetEmail()); } } if (0 < strlen($sFromEmail)) { $oApiUsersManager = /* @var CApiUsersManager */ CApi::Manager('users'); $oMessage->SetSafety($oApiUsersManager->GetSafetySender($oAccount->IdUser, $sFromEmail, true)); } if ($bParseAsc && 0 < count($aAscPartsIds)) { } if ($bParseICalAndVcard) { $oApiCapa = /* @var CApiCapabilityManager */ CApi::Manager('capability'); $oApiFileCache = /* @var CApiFilecacheManager */ CApi::Manager('filecache'); // ICAL $sICal = $oMessage->GetExtend('ICAL_RAW'); if (!empty($sICal) && $oApiCapa->IsCalendarSupported($oAccount)) { $oApiCalendarManager = CApi::Manager('calendar'); if ($oApiCalendarManager) { $mResult = $oApiCalendarManager->ProcessICS($oAccount, trim($sICal), $sFromEmail); if (is_array($mResult) && !empty($mResult['Action']) && !empty($mResult['Body'])) { $sTemptFile = md5($mResult['Body']).'.ics'; if ($oApiFileCache && $oApiFileCache->Put($oAccount, $sTemptFile, $mResult['Body'])) { $oIcs = CApiMailIcs::NewInstance(); $oIcs->Uid = $mResult['UID']; $oIcs->File = $sTemptFile; $oIcs->Attendee = isset($mResult['Attendee']) ? $mResult['Attendee'] : null; $oIcs->Type = $mResult['Action']; $oIcs->Location = !empty($mResult['Location']) ? $mResult['Location'] : ''; $oIcs->Description = !empty($mResult['Description']) ? $mResult['Description'] : ''; $oIcs->When = !empty($mResult['When']) ? $mResult['When'] : ''; $oIcs->CalendarId = !empty($mResult['CalendarId']) ? $mResult['CalendarId'] : ''; if (!$oApiCapa->IsCalendarAppointmentsSupported($oAccount)) { $oIcs->Type = ''; } // TODO // $oIcs->Calendars = array(); // if (isset($mResult['Calendars']) && is_array($mResult['Calendars']) && 0 < count($mResult['Calendars'])) // { // foreach ($mResult['Calendars'] as $sUid => $sName) // { // $oIcs->Calendars[$sUid] = $sName; // } // } $oMessage->AddExtend('ICAL', $oIcs); } else { CApi::Log('Can\'t save temp file "'.$sTemptFile.'"', ELogLevel::Error); } } } } // VCARD $sVCard = $oMessage->GetExtend('VCARD_RAW'); if (!empty($sVCard) && $oApiCapa->IsContactsSupported($oAccount)) { $oApiContactsManager = CApi::Manager('contacts'); $oContact = new CContact(); $oContact->InitFromVCardStr($oAccount->IdUser, $sVCard); $oContact->InitBeforeChange(); $oContact->IdContact = 0; $bContactExists = false; if (0 < strlen($oContact->ViewEmail)) { if ($oApiContactsManager) { $oLocalContact = $oApiContactsManager->GetContactByEmail($oAccount->IdUser, $oContact->ViewEmail); if ($oLocalContact) { $oContact->IdContact = $oLocalContact->IdContact; $bContactExists = true; } } } $sTemptFile = md5($sVCard).'.vcf'; if ($oApiFileCache && $oApiFileCache->Put($oAccount, $sTemptFile, $sVCard)) { $oVcard = CApiMailVcard::NewInstance(); $oVcard->Uid = $oContact->IdContact; $oVcard->File = $sTemptFile; $oVcard->Exists = !!$bContactExists; $oVcard->Name = $oContact->FullName; $oVcard->Email = $oContact->ViewEmail; $oMessage->AddExtend('VCARD', $oVcard); } else { CApi::Log('Can\'t save temp file "'.$sTemptFile.'"', ELogLevel::Error); } } } } return $oMessage; } /** * @param CAccount $oAccount * @param mixed $mCallback * @param string $sFolderName * @param int $iUid * @param string $sMimeIndex = '' * * @return bool * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function MessageMimeStream($oAccount, $mCallback, $sFolderName, $iUid, $sMimeIndex = '') { if (!is_callable($mCallback)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); $oImapClient->FolderExamine($sFolderName); $sFileName = ''; $sContentType = ''; $sMailEncodingName = ''; $sMimeIndex = trim($sMimeIndex); $aFetchResponse = $oImapClient->Fetch(array( 0 === strlen($sMimeIndex) ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK : \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.'.MIME]' ), $iUid, true); if (0 < count($aFetchResponse)) { $sMime = $aFetchResponse[0]->GetFetchValue( 0 === strlen($sMimeIndex) ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER : \MailSo\Imap\Enumerations\FetchType::BODY.'['.$sMimeIndex.'.MIME]' ); if (!empty($sMime)) { $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sMime); if (!empty($sMimeIndex)) { $sFileName = $oHeaders->ParameterValue( \MailSo\Mime\Enumerations\Header::CONTENT_DISPOSITION, \MailSo\Mime\Enumerations\Parameter::FILENAME); if (empty($sFileName)) { $sFileName = $oHeaders->ParameterValue( \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, \MailSo\Mime\Enumerations\Parameter::NAME); } $sMailEncodingName = $oHeaders->ValueByName( \MailSo\Mime\Enumerations\Header::CONTENT_TRANSFER_ENCODING); $sContentType = $oHeaders->ValueByName( \MailSo\Mime\Enumerations\Header::CONTENT_TYPE); } else { $sSubject = trim($oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT)); $sFileName = (empty($sSubject) ? 'message-'.$iUid : trim($sSubject)).'.eml'; $sFileName = '.eml' === $sFileName ? 'message.eml' : $sFileName; $sContentType = 'message/rfc822'; } } } $aFetchResponse = $oImapClient->Fetch(array( array(\MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.']', function ($sParent, $sLiteralAtomUpperCase, $rImapLiteralStream) use ($mCallback, $sMimeIndex, $sMailEncodingName, $sContentType, $sFileName) { if (!empty($sLiteralAtomUpperCase)) { if (is_resource($rImapLiteralStream) && 'FETCH' === $sParent) { $rMessageMimeIndexStream = (empty($sMailEncodingName)) ? $rImapLiteralStream : \MailSo\Base\StreamWrappers\Binary::CreateStream($rImapLiteralStream, \MailSo\Base\StreamWrappers\Binary::GetInlineDecodeOrEncodeFunctionName( $sMailEncodingName, true)); call_user_func($mCallback, $rMessageMimeIndexStream, $sContentType, $sFileName, $sMimeIndex); } } } )), $iUid, true); return ($aFetchResponse && 1 === count($aFetchResponse)); } /** * @param string $sSearch * @param bool $bDetectGmail = true * * @return string */ private function escapeSearchString($oImapClient, $sSearch, $bDetectGmail = true) { return ($bDetectGmail && 'ssl://imap.gmail.com' === strtolower($oImapClient->GetConnectedHost())) // gmail ? '{'.strlen($sSearch).'+}'."\r\n".$sSearch : $oImapClient->EscapeString($sSearch); } /** * @param string $sDate * @param int $iTimeZoneOffset * * @return int */ private function parseSearchDate($sDate, $iTimeZoneOffset) { $iResult = 0; if (0 < strlen($sDate)) { $oDateTime = \DateTime::createFromFormat('Y.m.d', $sDate, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject()); return $oDateTime ? $oDateTime->getTimestamp() - $iTimeZoneOffset : 0; } return $iResult; } /** * @param string $sSearch * * @return array */ private function parseSearchString($sSearch) { $aResult = array( 'OTHER' => '' ); $aCache = array(); $sSearch = \trim(\preg_replace('/[\s]+/', ' ', $sSearch)); $sSearch = \trim(\preg_replace('/(e?mail|from|to|subject|has|date|text|body): /i', '\\1:', $sSearch)); $mMatch = array(); \preg_match_all('/".*?(?<!\\\)"/', $sSearch, $mMatch); if (\is_array($mMatch) && isset($mMatch[0]) && \is_array($mMatch[0]) && 0 < \count($mMatch[0])) { foreach ($mMatch[0] as $sItem) { do { $sKey = \md5(\mt_rand(10000, 90000).\microtime(true)); } while (isset($aCache[$sKey])); $aCache[$sKey] = \stripcslashes($sItem); $sSearch = \str_replace($sItem, $sKey, $sSearch); } } \preg_match_all('/\'.*?(?<!\\\)\'/', $sSearch, $mMatch); if (\is_array($mMatch) && isset($mMatch[0]) && \is_array($mMatch[0]) && 0 < \count($mMatch[0])) { foreach ($mMatch[0] as $sItem) { do { $sKey = \md5(\mt_rand(10000, 90000).\microtime(true)); } while (isset($aCache[$sKey])); $aCache[$sKey] = \stripcslashes($sItem); $sSearch = \str_replace($sItem, $sKey, $sSearch); } } $mMatch = array(); \preg_match_all('/(e?mail|from|to|subject|has|date|text|body):([^\s]*)/i', $sSearch, $mMatch); if (\is_array($mMatch) && isset($mMatch[1]) && \is_array($mMatch[1]) && 0 < \count($mMatch[1])) { if (\is_array($mMatch[0])) { foreach ($mMatch[0] as $sToken) { $sSearch = \str_replace($sToken, '', $sSearch); } $sSearch = \trim(\preg_replace('/[\s]+/', ' ', $sSearch)); } foreach ($mMatch[1] as $iIndex => $sName) { if (isset($mMatch[2][$iIndex]) && 0 < \strlen($mMatch[2][$iIndex])) { $sName = \strtoupper($sName); $sValue = $mMatch[2][$iIndex]; switch ($sName) { case 'TEXT': case 'BODY': case 'EMAIL': case 'MAIL': case 'FROM': case 'TO': case 'SUBJECT': case 'HAS': case 'DATE': if ('MAIL' === $sName) { $sName = 'EMAIL'; } $aResult[$sName] = $sValue; break; } } } } $aResult['OTHER'] = $sSearch; foreach ($aResult as $sName => $sValue) { if (isset($aCache[$sValue])) { $aResult[$sName] = trim($aCache[$sValue], '"\' '); } } return $aResult; } /** * @param Object $oImapClient * @param string $sSearch * @param int $iTimeZoneOffset = 0 * * @return string */ private function getImapSearchString($oImapClient, $sSearch, $iTimeZoneOffset = 0, $aFilters = array()) { $aImapSearchResult = array(); $sSearch = trim($sSearch); if (0 === strlen($sSearch) && 0 === count($aFilters)) { return 'ALL'; } $bFilterFlagged = false; $bFilterUnseen = false; $bIsGmail = $oImapClient->IsSupported('X-GM-EXT-1'); $sGmailRawSearch = ''; if (0 < strlen($sSearch)) { $aLines = $this->parseSearchString($sSearch); if (1 === count($aLines) && isset($aLines['OTHER'])) { if (true) // TODO { $sValue = $this->escapeSearchString($oImapClient, $aLines['OTHER']); $aImapSearchResult[] = 'OR OR OR'; $aImapSearchResult[] = 'FROM'; $aImapSearchResult[] = $sValue; $aImapSearchResult[] = 'TO'; $aImapSearchResult[] = $sValue; $aImapSearchResult[] = 'CC'; $aImapSearchResult[] = $sValue; $aImapSearchResult[] = 'SUBJECT'; $aImapSearchResult[] = $sValue; } else { if ($bIsGmail) { $sGmailRawSearch .= ' '.$aLines['OTHER']; } else { $aImapSearchResult[] = 'TEXT'; $aImapSearchResult[] = $this->escapeSearchString($oImapClient, $aLines['OTHER']); } } } else { if (isset($aLines['EMAIL'])) { $aEmails = explode(',', $aLines['EMAIL']); foreach ($aEmails as $sEmail) { $sEmail = trim($sEmail); if (0 < strlen($sEmail)) { $sValue = $this->escapeSearchString($oImapClient, $sEmail); $aImapSearchResult[] = 'OR OR OR'; $aImapSearchResult[] = 'FROM'; $aImapSearchResult[] = $sValue; $aImapSearchResult[] = 'TO'; $aImapSearchResult[] = $sValue; $aImapSearchResult[] = 'CC'; $aImapSearchResult[] = $sValue; $aImapSearchResult[] = 'BCC'; $aImapSearchResult[] = $sValue; } } unset($aLines['EMAIL']); } if (isset($aLines['TO'])) { $sValue = $this->escapeSearchString($oImapClient, $aLines['TO']); $aImapSearchResult[] = 'OR'; $aImapSearchResult[] = 'TO'; $aImapSearchResult[] = $sValue; $aImapSearchResult[] = 'CC'; $aImapSearchResult[] = $sValue; unset($aLines['TO']); } $sMainText = ''; foreach ($aLines as $sName => $sRawValue) { if ('' === \trim($sRawValue)) { continue; } $sValue = $this->escapeSearchString($oImapClient, $sRawValue); switch ($sName) { case 'FROM': $aImapSearchResult[] = 'FROM'; $aImapSearchResult[] = $sValue; break; case 'SUBJECT': $aImapSearchResult[] = 'SUBJECT'; $aImapSearchResult[] = $sValue; break; case 'OTHER': case 'BODY': case 'TEXT': if ($bIsGmail) { $sGmailRawSearch .= ' '.$sRawValue; } else { $sMainText .= ' '.$sRawValue; } break; case 'HAS': if (false !== strpos($sRawValue, 'attach')) { if ($bIsGmail) { $sGmailRawSearch .= ' has:attachment'; } else { $aImapSearchResult[] = 'OR OR OR'; $aImapSearchResult[] = 'HEADER Content-Type application/'; $aImapSearchResult[] = 'HEADER Content-Type multipart/m'; $aImapSearchResult[] = 'HEADER Content-Type multipart/signed'; $aImapSearchResult[] = 'HEADER Content-Type multipart/report'; } } if (false !== strpos($sRawValue, 'flag')) { $bFilterFlagged = true; $aImapSearchResult[] = 'FLAGGED'; } if (false !== strpos($sRawValue, 'unseen')) { $bFilterUnseen = true; $aImapSearchResult[] = 'UNSEEN'; } break; case 'DATE': $iDateStampFrom = $iDateStampTo = 0; $sDate = $sRawValue; $aDate = explode('/', $sDate); if (is_array($aDate) && 2 === count($aDate)) { if (0 < strlen($aDate[0])) { $iDateStampFrom = $this->parseSearchDate($aDate[0], $iTimeZoneOffset); } if (0 < strlen($aDate[1])) { $iDateStampTo = $this->parseSearchDate($aDate[1], $iTimeZoneOffset); $iDateStampTo += 60 * 60 * 24; } } else { if (0 < strlen($sDate)) { $iDateStampFrom = $this->parseSearchDate($sDate, $iTimeZoneOffset); $iDateStampTo = $iDateStampFrom + 60 * 60 * 24; } } if (0 < $iDateStampFrom) { $aImapSearchResult[] = 'SINCE'; $aImapSearchResult[] = gmdate('j-M-Y', $iDateStampFrom); } if (0 < $iDateStampTo) { $aImapSearchResult[] = 'BEFORE'; $aImapSearchResult[] = gmdate('j-M-Y', $iDateStampTo); } break; } } if ('' !== trim($sMainText)) { $sMainText = trim(trim(preg_replace('/[\s]+/', ' ', $sMainText)), '"\''); if ($bIsGmail) { $sGmailRawSearch .= ' '.$sRawValue; } else { $aImapSearchResult[] = 'BODY'; $aImapSearchResult[] = $this->escapeSearchString($oImapClient, $sMainText); } } } } if (0 < count($aFilters)) { foreach ($aFilters as $sFilter) { if ('flagged' === $sFilter && !$bFilterFlagged) { $aImapSearchResult[] = 'FLAGGED'; } else if ('unseen' === $sFilter && !$bFilterUnseen) { $aImapSearchResult[] = 'UNSEEN'; } } } $sGmailRawSearch = \trim($sGmailRawSearch); if ($bIsGmail && 0 < \strlen($sGmailRawSearch)) { $aImapSearchResult[] = 'X-GM-RAW'; $aImapSearchResult[] = $this->escapeSearchString($oImapClient, $sGmailRawSearch, false); } $sImapSearchResult = \trim(\implode(' ', $aImapSearchResult)); if ('' === $sImapSearchResult) { $sImapSearchResult = 'ALL'; } return $sImapSearchResult; } /** * @param array $aThreads * @return array */ private function threadArrayReverseRec($aThreads) { $aThreads = array_reverse($aThreads); foreach ($aThreads as &$mItem) { if (is_array($mItem)) { $mItem = $this->threadArrayReverseRec($mItem); } } return $aThreads; } /** * @param array $aThreads * @return array */ private function threadArrayMap($aThreads) { $aNew = array(); foreach ($aThreads as $mItem) { if (!is_array($mItem)) { $aNew[] = $mItem; } else { $mMap = $this->threadArrayMap($mItem); if (is_array($mMap) && 0 < count($mMap)) { $aNew = array_merge($aNew, $mMap); } } } sort($aNew, SORT_NUMERIC); return $aNew; } public function __sortHelper($a, $b, $aSortUidsFlipped) { if ($a === $b) { return 0; } $iAIndex = $iBIndex = -1; if (isset($aSortUidsFlipped[$a])) { $iAIndex = $aSortUidsFlipped[$a]; } if (isset($aSortUidsFlipped[$b])) { $iBIndex = $aSortUidsFlipped[$b]; } if ($iAIndex === $iBIndex) { return 0; } return ($iAIndex < $iBIndex) ? -1 : 1; } /** * @param array $aInput * @param array $aSortUidsFlipped */ private function sortArrayByArray(&$aInput, $aSortUidsFlipped) { $self = $this; \usort($aInput, function ($a, $b) use ($self, $aSortUidsFlipped) { return $self->__sortHelper($a, $b, $aSortUidsFlipped); }); } /** * @param array $aThreads * @param array $aSortUidsFlipped */ private function sortArrayKeyByArray(&$aThreads, $aSortUidsFlipped) { $self = $this; \uksort($aThreads, function ($a, $b) use ($self, $aSortUidsFlipped) { return $self->__sortHelper($a, $b, $aSortUidsFlipped); }); } /** * @param array $aThreads * @param bool $bIncludeBottom = true * * @return array */ private function chunkThreadArray(&$aThreads, $bIncludeBottom = true) { $iLimit = 200; foreach ($aThreads as $iKey => $mData) { if (is_array($mData) && 1 < count($mData)) { if ($iLimit < count($mData)) { $aChunks = array_chunk($mData, $iLimit); foreach ($aChunks as $iIndex => $aPart) { if (0 === $iIndex) { $aThreads[$iKey] = $aPart; } else { $iFirst = array_shift($aPart); if (0 < count($aPart)) { $aThreads[$iFirst] = $aPart; } else { $aThreads[$iFirst] = $iFirst; } } } } } } } /** * @param array $aThreads * @param array $aSortUids * * @return array */ private function resortThreadArray($aThreads, $aSortUids) { $aSortUidsFlipped = array_flip($aSortUids); foreach ($aThreads as $iKey => $mData) { if (is_array($mData) && 1 < count($mData)) { $this->sortArrayByArray($mData, $aSortUidsFlipped); $aThreads[$iKey] = $mData; } } $this->chunkThreadArray($aThreads); $this->sortArrayKeyByArray($aThreads, $aSortUidsFlipped); return $aThreads; } /** * @param array $aThreads * * @return array */ private function compileThreadArray($aThreads) { $aThreads = $this->threadArrayReverseRec($aThreads); $aResult = array(); foreach ($aThreads as $mItem) { if (is_array($mItem)) { $aMap = $this->threadArrayMap($mItem); if (is_array($aMap)) { if (1 < count($aMap)) { $iMax = array_pop($aMap); rsort($aMap, SORT_NUMERIC); $aResult[(int) $iMax] = $aMap; } else if (0 < count($aMap)) { $aResult[(int) $aMap[0]] = $aMap[0]; } } } else { $aResult[(int) $mItem] = $mItem; } } krsort($aResult, SORT_NUMERIC); return $aResult; } /** * @param Object $oImapClient * @param string $sIndexRange * @param function $fItemCallback * @param bool $bRangeAsUids = false * * @return array * * @throws CApiInvalidArgumentException */ private function specialSubRequest($oImapClient, $sIndexRange, $fItemCallback, $bRangeAsUids = false) { $aResult = array(); $aFetchResponse = $oImapClient->Fetch(array( \MailSo\Imap\Enumerations\FetchType::INDEX, \MailSo\Imap\Enumerations\FetchType::UID, \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE, \MailSo\Imap\Enumerations\FetchType::INTERNALDATE, \MailSo\Imap\Enumerations\FetchType::FLAGS, \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE ), $sIndexRange, $bRangeAsUids); if (is_array($aFetchResponse) && 0 < count($aFetchResponse)) { $oFetchResponseItem = null; foreach ($aFetchResponse as /* @var $oFetchResponseItem \MailSo\Imap\FetchResponse */ &$oFetchResponseItem) { $sUid = $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID); $sSize = $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::RFC822_SIZE); $sInternalDate = $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::INTERNALDATE); $aFlags = $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::FLAGS); $aFlagsLower = array_map('strtolower', $aFlags); $oBodyStructure = $oFetchResponseItem->GetFetchBodyStructure(); if ($oBodyStructure) { if (call_user_func_array($fItemCallback, array( $oBodyStructure, $sSize, $sInternalDate, $aFlagsLower, $sUid ))) { $aResult[] = $sUid; } } unset($oBodyStructure); unset($oFetchResponseItem); } } return $aResult; } /** * @param Object $oImapClient * @param function $fItemCallback * @param string $sFolderFullNameRaw * * @return array * * @throws CApiInvalidArgumentException */ private function specialIndexSearch($oImapClient, $fItemCallback, $sFolderFullNameRaw) { if (0 === strlen($sFolderFullNameRaw) || !is_callable($fItemCallback)) { throw new CApiInvalidArgumentException(); } $oImapClient->FolderExamine($sFolderFullNameRaw); $aResult = array(); $aList = $this->folderInformation($oImapClient, $sFolderFullNameRaw); $iCount = $aList[0]; if (0 < $iCount) { $iInc = 0; $iTopLimit = 100; $aIndexes = range(1, $iCount); $aRequestIndexes = array(); foreach ($aIndexes as $iIndex) { $iInc++; $aRequestIndexes[] = $iIndex; if ($iInc > $iTopLimit) { $aSubResult = $this->specialSubRequest($oImapClient, implode(',', $aRequestIndexes), $fItemCallback, false); $aResult = array_merge($aResult, $aSubResult); $aRequestIndexes = array(); $iInc = 0; } } if (0 < count($aRequestIndexes)) { $aSubResult = $this->specialSubRequest($oImapClient, implode(',', $aRequestIndexes), $fItemCallback, false); $aResult = array_merge($aResult, $aSubResult); } rsort($aResult, SORT_NUMERIC); } return is_array($aResult) ? $aResult : array(); } /** * @param Object $oImapClient * @param function $fItemCallback * @param string $sFolderFullNameRaw * @param array $aUids * * @return array * * @throws CApiInvalidArgumentException */ private function specialUidsSearch($oImapClient, $fItemCallback, $sFolderFullNameRaw, $aUids) { if (0 === strlen($sFolderFullNameRaw) || !is_callable($fItemCallback) || !is_array($aUids) || 0 === count($aUids)) { throw new CApiInvalidArgumentException(); } $oImapClient->FolderExamine($sFolderFullNameRaw); $aResult = array(); $iInc = 0; $iTopLimit = 100; $aRequestUids = array(); foreach ($aUids as $iUid) { $iInc++; $aRequestUids[] = $iUid; if ($iInc > $iTopLimit) { $aSubResult = $this->specialSubRequest($oImapClient, implode(',', $aRequestUids), $fItemCallback, true); $aResult = array_merge($aResult, $aSubResult); $aRequestUids = array(); $iInc = 0; } } if (0 < count($aRequestUids)) { $aSubResult = $this->specialSubRequest($oImapClient, implode(',', $aRequestUids), $fItemCallback, true); $aResult = array_merge($aResult, $aSubResult); } rsort($aResult, SORT_NUMERIC); return $aResult; } /** * @param CAccount $oAccount * @param string $sFolderFullNameRaw * @param int $iOffset = 0 * @param int $iLimit = 20 * @param string $sSearch = '' * @param bool $bUseThreads = false * @param array $aFilters = array() * @param string $sInboxUidnext = '' * * @return CApiMailMessageCollection * * @throws CApiInvalidArgumentException */ public function MessageList($oAccount, $sFolderFullNameRaw, $iOffset = 0, $iLimit = 20, $sSearch = '', $bUseThreads = false, $aFilters = array(), $sInboxUidnext = '') { if (0 === strlen($sFolderFullNameRaw) || 0 > $iOffset || 0 >= $iLimit || 999 < $iLimit) { throw new CApiInvalidArgumentException(); } $oMessageCollection = false; $oSettings =& CApi::GetSettings(); $oImapClient =& $this->getImapClient($oAccount, 20, 60 * 2); $oImapClient->FolderExamine($sFolderFullNameRaw); $aList = $this->folderInformation($oImapClient, $sFolderFullNameRaw); $iMessageCount = $aList[0]; $iRealMessageCount = $aList[0]; $iMessageUnseenCount = $aList[1]; $sUidNext = $aList[2]; $oMessageCollection = CApiMailMessageCollection::NewInstance(); $oMessageCollection->FolderName = $sFolderFullNameRaw; $oMessageCollection->Offset = $iOffset; $oMessageCollection->Limit = $iLimit; $oMessageCollection->Search = $sSearch; $oMessageCollection->UidNext = $sUidNext; $oMessageCollection->Filters = implode(',', $aFilters); $aThreads = array(); $bUseThreadsIfSupported = !!$oSettings->GetConf('WebMail/UseThreadsIfSupported'); if ($bUseThreadsIfSupported) { $bUseThreadsIfSupported = $bUseThreads; } $oMessageCollection->FolderHash = $aList[3]; $bSearch = false; if (0 < $iRealMessageCount) { $bIndexAsUid = false; $aIndexOrUids = array(); $bUseSortIfSupported = !!$oSettings->GetConf('WebMail/UseSortImapForDateMode'); if ($bUseSortIfSupported) { $bUseSortIfSupported = $oImapClient->IsSupported('SORT'); } if ($bUseThreadsIfSupported) { $bUseThreadsIfSupported = $oImapClient->IsSupported('THREAD=REFS') || $oImapClient->IsSupported('THREAD=REFERENCES') || $oImapClient->IsSupported('THREAD=ORDEREDSUBJECT'); } if (0 < strlen($sSearch) || 0 < count($aFilters)) { $sCutedSearch = $sSearch; $sCutedSearch = \preg_replace('/[\s]+/', ' ', $sCutedSearch); $sCutedSearch = \preg_replace('/attach[ ]?:[ ]?/i', 'attach:', $sCutedSearch); $bSearchAttachments = false; $fAttachmentSearchCallback = null; $aMatch = array(); if ((CApi::GetConf('labs.use-body-structures-for-has-attachments-search', false) && \preg_match('/has[ ]?:[ ]?attachments/i', $sSearch)) || \preg_match('/attach:([^\s]+)/i', $sSearch, $aMatch)) { $bSearchAttachments = true; $sAttachmentName = isset($aMatch[1]) ? trim($aMatch[1]) : ''; $sAttachmentRegs = !empty($sAttachmentName) && '*' !== $sAttachmentName ? '/[^>]*'.str_replace('\\*', '[^>]*', preg_quote(trim($sAttachmentName, '*'), '/')).'[^>]*/ui' : ''; if (CApi::GetConf('labs.use-body-structures-for-has-attachments-search', false)) { $sCutedSearch = trim(preg_replace('/has[ ]?:[ ]?attachments/i', '', $sCutedSearch)); } $sCutedSearch = trim(preg_replace('/attach:([^\s]+)/', '', $sCutedSearch)); $fAttachmentSearchCallback = function ($oBodyStructure, $sSize, $sInternalDate, $aFlagsLower, $sUid) use ($sFolderFullNameRaw, $sAttachmentRegs) { $bResult = false; if ($oBodyStructure) { $aAttachmentsParts = $oBodyStructure->SearchAttachmentsParts(); if ($aAttachmentsParts && 0 < count($aAttachmentsParts)) { $oAttachments = CApiMailAttachmentCollection::NewInstance(); foreach ($aAttachmentsParts as /* @var $oAttachmentItem \MailSo\Imap\BodyStructure */ $oAttachmentItem) { $oAttachments->Add( CApiMailAttachment::NewBodyStructureInstance($sFolderFullNameRaw, $sUid, $oAttachmentItem) ); } $bResult = $oAttachments->HasNonInlineAttachments(); if ($bResult && !empty($sAttachmentRegs)) { $aList = $oAttachments->FilterList(function ($oAttachment) use ($sAttachmentRegs) { if ($oAttachment && !$oAttachment->IsInline() && !$oAttachment->Cid()) { return !!preg_match($sAttachmentRegs, $oAttachment->FileName()); } return false; }); return is_array($aList) ? 0 < count($aList) : false; } } } unset($oBodyStructure); return $bResult; }; } if (0 < strlen($sCutedSearch) || 0 < count($aFilters)) { $bSearch = true; $sSearchCriterias = $this->getImapSearchString($oImapClient, $sCutedSearch, $oAccount->GetDefaultTimeOffset() * 60, $aFilters); $bIndexAsUid = true; $aIndexOrUids = null; if ($bUseSortIfSupported) { $aIndexOrUids = $oImapClient->MessageSimpleSort(array('REVERSE ARRIVAL'), $sSearchCriterias, $bIndexAsUid); } else { if (!\MailSo\Base\Utils::IsAscii($sCutedSearch)) { try { $aIndexOrUids = $oImapClient->MessageSimpleSearch($sSearchCriterias, $bIndexAsUid, 'UTF-8'); } catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException) { // Charset is not supported. Skip and try request without charset. $aIndexOrUids = null; } } if (null === $aIndexOrUids) { $aIndexOrUids = $oImapClient->MessageSimpleSearch($sSearchCriterias, $bIndexAsUid); } } if ($bSearchAttachments && is_array($aIndexOrUids) && 0 < count($aIndexOrUids)) { $aIndexOrUids = $this->specialUidsSearch( $oImapClient, $fAttachmentSearchCallback, $sFolderFullNameRaw, $aIndexOrUids, $iOffset, $iLimit); } } else if ($bSearchAttachments) { $bIndexAsUid = true; $aIndexOrUids = $this->specialIndexSearch( $oImapClient, $fAttachmentSearchCallback, $sFolderFullNameRaw, $iOffset, $iLimit); } } else { if ($bUseThreadsIfSupported && 1 < $iMessageCount) { $bIndexAsUid = true; $aThreadUids = array(); try { $aThreadUids = $oImapClient->MessageSimpleThread(); } catch (\MailSo\Imap\Exceptions\RuntimeException $oException) { $aThreadUids = array(); } $aThreads = $this->compileThreadArray($aThreadUids); if ($bUseSortIfSupported) { $aThreads = $this->resortThreadArray($aThreads, $oImapClient->MessageSimpleSort(array('REVERSE ARRIVAL'), 'ALL', true)); } else { // $this->chunkThreadArray($aThreads); } $aIndexOrUids = array_keys($aThreads); $iMessageCount = count($aIndexOrUids); } else if ($bUseSortIfSupported && 1 < $iMessageCount) { $bIndexAsUid = true; $aIndexOrUids = $oImapClient->MessageSimpleSort(array('REVERSE ARRIVAL'), 'ALL', $bIndexAsUid); } else { $bIndexAsUid = false; $aIndexOrUids = array(1); if (1 < $iMessageCount) { $aIndexOrUids = array_reverse(range(1, $iMessageCount)); } } } if (is_array($aIndexOrUids)) { $oMessageCollection->MessageCount = $iRealMessageCount; $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount; $oMessageCollection->MessageResultCount = 0 < strlen($sSearch) || 0 < count($aFilters) ? count($aIndexOrUids) : $iMessageCount; if (0 < count($aIndexOrUids)) { $iOffset = (0 > $iOffset) ? 0 : $iOffset; $aRequestIndexOrUids = array_slice($aIndexOrUids, $iOffset, $iLimit); if ($bIndexAsUid) { $oMessageCollection->Uids = $aRequestIndexOrUids; } if (is_array($aRequestIndexOrUids) && 0 < count($aRequestIndexOrUids)) { $aFetchResponse = $oImapClient->Fetch(array( \MailSo\Imap\Enumerations\FetchType::INDEX, \MailSo\Imap\Enumerations\FetchType::UID, \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE, \MailSo\Imap\Enumerations\FetchType::INTERNALDATE, \MailSo\Imap\Enumerations\FetchType::FLAGS, \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE, \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK ), implode(',', $aRequestIndexOrUids), $bIndexAsUid); if (is_array($aFetchResponse) && 0 < count($aFetchResponse)) { $aFetchIndexArray = array(); $oFetchResponseItem = null; foreach ($aFetchResponse as /* @var $oFetchResponseItem \MailSo\Imap\FetchResponse */ &$oFetchResponseItem) { $aFetchIndexArray[($bIndexAsUid) ? $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID) : $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::INDEX)] =& $oFetchResponseItem; unset($oFetchResponseItem); } foreach ($aRequestIndexOrUids as $iFUid) { if (isset($aFetchIndexArray[$iFUid])) { $oMailMessage = CApiMailMessage::NewFetchResponseInstance( $oMessageCollection->FolderName, $aFetchIndexArray[$iFUid]); if (!$bIndexAsUid) { $oMessageCollection->Uids[] = $oMailMessage->Uid(); } $oMessageCollection->Add($oMailMessage); unset($oMailMessage); } } } } } } } if (!$bSearch && $bUseThreadsIfSupported && 0 < count($aThreads)) { $oMessageCollection->ForeachList(function (/* @var $oMessage CApiMailMessage */ $oMessage) use ($aThreads) { $iUid = $oMessage->Uid(); if (isset($aThreads[$iUid]) && is_array($aThreads[$iUid])) { $oMessage->SetThreads($aThreads[$iUid]); } }); } if (0 < strlen($sInboxUidnext) && 'INBOX' === $oMessageCollection->FolderName && $sInboxUidnext !== $oMessageCollection->UidNext) { $oMessageCollection->New = $this->GetNextMessages($oAccount, 'INBOX', $sInboxUidnext); } return $oMessageCollection; } /** * @param CAccount $oAccount * @param string $sFolderFullNameRaw * @param array $aUids * * @return CApiMailMessageCollection * * @throws CApiInvalidArgumentException */ public function MessageListByUids($oAccount, $sFolderFullNameRaw, $aUids) { if (0 === strlen($sFolderFullNameRaw) || !is_array($aUids) || 0 === count($aUids)) { throw new CApiInvalidArgumentException(); } $oMessageCollection = false; $oImapClient =& $this->getImapClient($oAccount); $oImapClient->FolderExamine($sFolderFullNameRaw); $aList = $this->folderInformation($oImapClient, $sFolderFullNameRaw); $iMessageRealCount = $aList[0]; $iMessageUnseenCount = $aList[1]; $sUidNext = $aList[2]; $oMessageCollection = CApiMailMessageCollection::NewInstance(); $oMessageCollection->FolderName = $sFolderFullNameRaw; $oMessageCollection->Offset = 0; $oMessageCollection->Limit = 0; $oMessageCollection->Search = ''; $oMessageCollection->UidNext = $sUidNext; if (0 < $iMessageRealCount) { $bIndexAsUid = true; $aIndexOrUids = $aUids; if (is_array($aIndexOrUids)) { $oMessageCollection->MessageCount = $iMessageRealCount; $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount; $oMessageCollection->MessageSearchCount = $oMessageCollection->MessageCount; $oMessageCollection->MessageResultCount = $oMessageCollection->MessageCount; if (0 < count($aIndexOrUids)) { $aRequestIndexOrUids = $aIndexOrUids; if ($bIndexAsUid) { $oMessageCollection->Uids = $aRequestIndexOrUids; } if (is_array($aRequestIndexOrUids) && 0 < count($aRequestIndexOrUids)) { $aFetchResponse = $oImapClient->Fetch(array( \MailSo\Imap\Enumerations\FetchType::INDEX, \MailSo\Imap\Enumerations\FetchType::UID, \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE, \MailSo\Imap\Enumerations\FetchType::INTERNALDATE, \MailSo\Imap\Enumerations\FetchType::FLAGS, \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE, \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK ), implode(',', $aRequestIndexOrUids), $bIndexAsUid); if (is_array($aFetchResponse) && 0 < count($aFetchResponse)) { $aFetchIndexArray = array(); $oFetchResponseItem = null; foreach ($aFetchResponse as /* @var $oFetchResponseItem \MailSo\Imap\FetchResponse */ &$oFetchResponseItem) { $aFetchIndexArray[($bIndexAsUid) ? $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID) : $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::INDEX)] =& $oFetchResponseItem; unset($oFetchResponseItem); } foreach ($aRequestIndexOrUids as $iFUid) { if (isset($aFetchIndexArray[$iFUid])) { $oMailMessage = CApiMailMessage::NewFetchResponseInstance( $oMessageCollection->FolderName, $aFetchIndexArray[$iFUid]); if (!$bIndexAsUid) { $oMessageCollection->Uids[] = $oMailMessage->Uid(); } $oMessageCollection->Add($oMailMessage); unset($oMailMessage); } } } } } } } $oMessageCollection->FolderHash = api_Utils::GenerateFolderHash($sFolderFullNameRaw, $oMessageCollection->MessageCount, $oMessageCollection->MessageUnseenCount, $oMessageCollection->UidNext); return $oMessageCollection; } /** * @param CAccount $oAccount * @param string $sFolderFullNameRaw * @param array $aUids * * @return CApiMailMessageCollection * * @throws CApiInvalidArgumentException */ public function MessageFlags($oAccount, $sFolderFullNameRaw, $aUids) { if (0 === strlen($sFolderFullNameRaw) || !is_array($aUids) || 0 === count($aUids)) { throw new CApiInvalidArgumentException(); } $oImapClient =& $this->getImapClient($oAccount); $oImapClient->FolderExamine($sFolderFullNameRaw); $aList = $this->folderInformation($oImapClient, $sFolderFullNameRaw); $iMessageRealCount = $aList[0]; $mResult = array(); if (0 < $iMessageRealCount) { $aFetchResponse = $oImapClient->Fetch(array( \MailSo\Imap\Enumerations\FetchType::INDEX, \MailSo\Imap\Enumerations\FetchType::UID, \MailSo\Imap\Enumerations\FetchType::FLAGS ), implode(',', $aUids), true); if (is_array($aFetchResponse) && 0 < count($aFetchResponse)) { $oFetchResponseItem = null; foreach ($aFetchResponse as /* @var $oFetchResponseItem \MailSo\Imap\FetchResponse */ &$oFetchResponseItem) { $sUid = $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID); $aFlags = $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::FLAGS); if (is_array($aFlags)) { $mResult[$sUid] = array_map('strtolower', $aFlags); } } } } return $mResult; } /** * @param CAccount $oAccount * @param int $iUidFrom * @param int $iLastUid = 0 * @param int $iLimit = 5 * * @return array * * @throws CApiInvalidArgumentException */ public function HelpdeskMessagesHelper($oAccount, $iUidFrom, &$iLastUid = 0, $iLimit = 5) { if (0 > $iUidFrom) { throw new CApiInvalidArgumentException(); } $sFolderFullNameRaw = 'INBOX'; $oImapClient =& $this->getImapClient($oAccount); $oImapClient->FolderExamine($sFolderFullNameRaw); $aList = $this->folderInformation($oImapClient, $sFolderFullNameRaw); $iMessageRealCount = $aList[0]; $aUidsForRequest = array(); $aResult = array(); if (0 === $iUidFrom) { $iLastUid = (int) $aList[2]; if (1 < $iLastUid) { $iLastUid--; } } else if (0 < $iMessageRealCount) { $aFetchResponse = $oImapClient->Fetch(array( \MailSo\Imap\Enumerations\FetchType::INDEX, \MailSo\Imap\Enumerations\FetchType::UID, \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE, \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK ), $iUidFrom.':*', true); if (is_array($aFetchResponse) && 0 < count($aFetchResponse)) { $oFetchResponseItem = null; foreach ($aFetchResponse as /* @var $oFetchResponseItem \MailSo\Imap\FetchResponse */ &$oFetchResponseItem) { $iLimit--; if (0 > $iLimit) { break; } $oMailMessage = CApiMailMessage::NewFetchResponseInstance($sFolderFullNameRaw, $oFetchResponseItem); if ($oMailMessage) { $iCurUid = $oMailMessage->Uid(); if ($iCurUid && $iCurUid >= $iUidFrom) { if ($iCurUid > $iLastUid) { $iLastUid = $iCurUid; } $aUidsForRequest[] = $iCurUid; } unset($oMailMessage); } } } if (0 < count($aUidsForRequest)) { foreach ($aUidsForRequest as $iUid) { $aResult[] = $this->Message($oAccount, $sFolderFullNameRaw, $iUid); } } } return $aResult; } }