oLogger = null; $this->oImapClient = \MailSo\Imap\ImapClient::NewInstance(); $this->oImapClient->SetTimeOuts(10, 30); // TODO } /** * @return \MailSo\Mail\MailClient */ public static function NewInstance() { return new self(); } /** * @param string $sServerName * @param int $iPort = 143 * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT * * @return \MailSo\Mail\MailClient * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function Connect($sServerName, $iPort = 143, $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT) { $this->oImapClient->Connect($sServerName, $iPort, $iSecurityType); return $this; } /** * @param string $sLogin * @param string $sPassword * @param string $sProxyAuthUser = '' * @param bool $bUseAuthPlainIfSupported = false * * @return \MailSo\Mail\MailClient * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\LoginException */ public function Login($sLogin, $sPassword, $sProxyAuthUser = '', $bUseAuthPlainIfSupported = false) { $this->oImapClient->Login($sLogin, $sPassword, $sProxyAuthUser, $bUseAuthPlainIfSupported); return $this; } /** * @param string $sXOAuth2Token * * @return \MailSo\Mail\MailClient * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\LoginException */ public function LoginWithXOauth2($sXOAuth2Token) { $this->oImapClient->LoginWithXOauth2($sXOAuth2Token); return $this; } /** * @return \MailSo\Mail\MailClient * * @throws \MailSo\Net\Exceptions\Exception */ public function Logout() { $this->oImapClient->Logout(); return $this; } /** * @return \MailSo\Mail\MailClient * * @throws \MailSo\Net\Exceptions\Exception */ public function Disconnect() { $this->oImapClient->Disconnect(); return $this; } /** * @return \MailSo\Mail\MailClient * * @throws \MailSo\Net\Exceptions\Exception */ public function LogoutAndDisconnect() { return $this->Logout()->Disconnect(); } /** * @return bool */ public function IsConnected() { return $this->oImapClient->IsConnected(); } /** * @return bool */ public function IsLoggined() { return $this->oImapClient->IsLoggined(); } /** * @return string */ private function getEnvelopeOrHeadersRequestString() { // return \MailSo\Imap\Enumerations\FetchType::ENVELOPE; return \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK; return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( \MailSo\Mime\Enumerations\Header::RETURN_PATH, \MailSo\Mime\Enumerations\Header::RECEIVED, \MailSo\Mime\Enumerations\Header::MIME_VERSION, \MailSo\Mime\Enumerations\Header::MESSAGE_ID, \MailSo\Mime\Enumerations\Header::FROM_, \MailSo\Mime\Enumerations\Header::TO_, \MailSo\Mime\Enumerations\Header::CC, \MailSo\Mime\Enumerations\Header::BCC, \MailSo\Mime\Enumerations\Header::SENDER, \MailSo\Mime\Enumerations\Header::REPLY_TO, \MailSo\Mime\Enumerations\Header::IN_REPLY_TO, \MailSo\Mime\Enumerations\Header::DATE, \MailSo\Mime\Enumerations\Header::SUBJECT, \MailSo\Mime\Enumerations\Header::X_MSMAIL_PRIORITY, \MailSo\Mime\Enumerations\Header::IMPORTANCE, \MailSo\Mime\Enumerations\Header::X_PRIORITY, \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, \MailSo\Mime\Enumerations\Header::REFERENCES, \MailSo\Mime\Enumerations\Header::X_DRAFT_INFO, ), true); } /** * @param string $sFolderName * @param string $sMessageFlag * @param bool $bSetAction = true * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception * @throws \MailSo\Mail\Exceptions\Exception */ public function MessageSetFlagToAll($sFolderName, $sMessageFlag, $bSetAction = true) { $this->oImapClient->FolderSelect($sFolderName); $oFolderInfo = $this->oImapClient->FolderCurrentInformation(); if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag)) { throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag is not supported.'); } if (0 < $oFolderInfo->Exists) { $sStoreAction = $bSetAction ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT ; $this->oImapClient->MessageStoreFlag('1:*', false, array($sMessageFlag), $sStoreAction); } } /** * @param string $sFolderName * @param array $aIndexRange * @param bool $bIndexIsUid * @param string $sMessageFlag * @param bool $bSetAction = true * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception * @throws \MailSo\Mail\Exceptions\Exception */ public function MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, $sMessageFlag, $bSetAction = true) { $this->oImapClient->FolderSelect($sFolderName); $oFolderInfo = $this->oImapClient->FolderCurrentInformation(); if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag)) { throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag is not supported.'); } $sStoreAction = $bSetAction ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT ; $sIndexRange = \implode(',', $aIndexRange); $this->oImapClient->MessageStoreFlag($sIndexRange, $bIndexIsUid, array($sMessageFlag), $sStoreAction); } /** * @param string $sFolderName * @param array $aIndexRange * @param bool $bIndexIsUid * @param bool $bSetAction = true * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function MessageSetFlagged($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true) { $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, \MailSo\Imap\Enumerations\MessageFlag::FLAGGED, $bSetAction); } /** * @param string $sFolderName * @param bool $bSetAction = true * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function MessageSetSeenToAll($sFolderName, $bSetAction = true) { $this->MessageSetFlagToAll($sFolderName, \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction); } /** * @param string $sFolderName * @param array $aIndexRange * @param bool $bIndexIsUid * @param bool $bSetAction = true * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function MessageSetSeen($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true) { $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction); } /** * @param string $sFolderName * @param string $sFolderHash * @param string $sUid * @param mixed $oCacher = null * * @return \MailSo\Mail\Message|false * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function MessageThreadInfo($sFolderName, $sFolderHash, $sUid, $oCacher) { $aResult = array( array(), array() ); $aThreads = $this->MessageListThreadsMap($sFolderName, $sFolderHash, $oCacher); if (isset($aThreads[$sUid]) && is_array($aThreads[$sUid])) { $aResult[0] = $aThreads[$sUid]; $oMessageCollection = MessageCollection::NewInstance(); $oMessageCollection->FolderName = $sFolderName; $oMessageCollection->FolderHash = $sFolderHash; $oMessageCollection->Offset = 0; $oMessageCollection->Limit = 999; $oMessageCollection->Search = ''; $this->MessageListByRequestIndexOrUids($oMessageCollection, $aThreads[$sUid], true); // $oMessageCollection->ForeachList(function (/* @var $oMessage \MailSo\Mail\Message */ $oMessage) use ($aThreads) { // $oMessage->SetThreads(isset($aThreads[$oMessage->Uid()]) && is_array($aThreads[$oMessage->Uid()]) ? // $aThreads[$oMessage->Uid()] : null); // }); $aResult[1] = $oMessageCollection; } return $aResult; } /** * @param string $sFolderName * @param int $iIndex * @param bool $bIndexIsUid = true * @param mixed $oCacher = null * * @return \MailSo\Mail\Message|false * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function Message($sFolderName, $iIndex, $bIndexIsUid = true, $oCacher = null) { if (!\MailSo\Base\Validator::RangeInt($iIndex, 1)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } $this->oImapClient->FolderExamine($sFolderName); $oBodyStructure = null; $oMessage = false; $aTextMimeIndexes = array(); $aFetchResponse = $this->oImapClient->Fetch(array(\MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE), $iIndex, $bIndexIsUid); if (0 < \count($aFetchResponse)) { $oBodyStructure = $aFetchResponse[0]->GetFetchBodyStructure(); $aTextParts = $oBodyStructure ? $oBodyStructure->SearchHtmlOrPlainParts() : null; if (is_array($aTextParts) && 0 < \count($aTextParts)) { foreach ($aTextParts as $oPart) { $aTextMimeIndexes[] = $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, $this->getEnvelopeOrHeadersRequestString() ); if (0 < \count($aTextMimeIndexes)) { foreach ($aTextMimeIndexes as $sTextMimeIndex) { $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sTextMimeIndex.']'; } } if (!$oBodyStructure) { $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE; } $aFetchResponse = $this->oImapClient->Fetch($aFetchItems, $iIndex, $bIndexIsUid); if (0 < \count($aFetchResponse)) { $oMessage = \MailSo\Mail\Message::NewFetchResponseInstance( $sFolderName, $aFetchResponse[0], $oBodyStructure); } return $oMessage; } /** * @param mixed $mCallback * @param string $sFolderName * @param int $iIndex * @param bool $bIndexIsUid = true, * @param string $sMimeIndex = '' * * @return bool * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function MessageMimeStream($mCallback, $sFolderName, $iIndex, $bIndexIsUid = true, $sMimeIndex = '') { if (!is_callable($mCallback)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } $this->oImapClient->FolderExamine($sFolderName); $sFileName = ''; $sContentType = ''; $sMailEncodingName = ''; $sMimeIndex = trim($sMimeIndex); $aFetchResponse = $this->oImapClient->Fetch(array( 0 === \strlen($sMimeIndex) ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK : \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.'.MIME]' ), $iIndex, $bIndexIsUid); 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 (0 < \strlen($sMime)) { $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sMime); if (0 < \strlen($sMimeIndex)) { $sFileName = $oHeaders->ParameterValue( \MailSo\Mime\Enumerations\Header::CONTENT_DISPOSITION, \MailSo\Mime\Enumerations\Parameter::FILENAME); if (0 === \strlen($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 = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT); $sFileName = 0 === \strlen($sSubject) ? (string) $iIndex : $sSubject; $sFileName .= '.eml'; $sContentType = 'message/rfc822'; } } } $aFetchResponse = $this->oImapClient->Fetch(array( array(\MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.']', function ($sParent, $sLiteralAtomUpperCase, $rImapLiteralStream) use ($mCallback, $sMimeIndex, $sMailEncodingName, $sContentType, $sFileName) { if (0 < \strlen($sLiteralAtomUpperCase)) { if (is_resource($rImapLiteralStream) && 'FETCH' === $sParent) { $rMessageMimeIndexStream = (0 === \strlen($sMailEncodingName)) ? $rImapLiteralStream : \MailSo\Base\StreamWrappers\Binary::CreateStream($rImapLiteralStream, \MailSo\Base\StreamWrappers\Binary::GetInlineDecodeOrEncodeFunctionName( $sMailEncodingName, true)); \call_user_func($mCallback, $rMessageMimeIndexStream, $sContentType, $sFileName, $sMimeIndex); } } } )), $iIndex, $bIndexIsUid); return ($aFetchResponse && 1 === \count($aFetchResponse)); } /** * @param string $sFolder * @param array $aIndexRange * @param bool $bIndexIsUid * @param bool $bUseExpunge = true * * @return \MailSo\Mail\MailClient * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function MessageDelete($sFolder, $aIndexRange, $bIndexIsUid, $bUseExpunge = true) { if (0 === \strlen($sFolder) || !\is_array($aIndexRange) || 0 === \count($aIndexRange)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } $this->oImapClient->FolderSelect($sFolder); $sIndexRange = \implode(',', $aIndexRange); $this->oImapClient->MessageStoreFlag($sIndexRange, $bIndexIsUid, array(\MailSo\Imap\Enumerations\MessageFlag::DELETED), \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT ); if ($bUseExpunge) { $this->oImapClient->MessageExpunge($bIndexIsUid ? $sIndexRange : '', $bIndexIsUid); } return $this; } /** * @param string $sFromFolder * @param string $sToFolder * @param array $aIndexRange * @param bool $bIndexIsUid * @param bool $bUseMoveSupported = false * * @return \MailSo\Mail\MailClient * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function MessageMove($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid, $bUseMoveSupported = false) { if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) || !\is_array($aIndexRange) || 0 === \count($aIndexRange)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } $this->oImapClient->FolderSelect($sFromFolder); if ($bUseMoveSupported && $this->oImapClient->IsSupported('MOVE')) { $this->oImapClient->MessageMove($sToFolder, \implode(',', $aIndexRange), $bIndexIsUid); } else { $this->oImapClient->MessageCopy($sToFolder, \implode(',', $aIndexRange), $bIndexIsUid); $this->MessageDelete($sFromFolder, $aIndexRange, $bIndexIsUid, true); } return $this; } /** * @param resource $rMessageStream * @param int $iMessageStreamSize * @param string $sFolderToSave * @param array $aAppendFlags = null * @param int $iUid = null * * @return \MailSo\Mail\MailClient */ public function MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags = null, &$iUid = null) { if (!\is_resource($rMessageStream) || 0 === \strlen($sFolderToSave)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } $this->oImapClient->MessageAppendStream( $sFolderToSave, $rMessageStream, $iMessageStreamSize, $aAppendFlags, $iUid); return $this; } /** * @param string $sMessageFileName * @param string $sFolderToSave * @param array $aAppendFlags = null * @param int &$iUid = null * * @return \MailSo\Mail\MailClient */ public function MessageAppendFile($sMessageFileName, $sFolderToSave, $aAppendFlags = null, &$iUid = null) { if (!@\is_file($sMessageFileName) || !@\is_readable($sMessageFileName)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } $iMessageStreamSize = \filesize($sMessageFileName); $rMessageStream = \fopen($sMessageFileName, 'rb'); $this->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags, $iUid); if (\is_resource($rMessageStream)) { @fclose($rMessageStream); } return $this; } /** * @param string $sFolderName * @param int $iCount * @param int $iUnseenCount * @param string $sUidNext * * @return void */ protected function initFolderValues($sFolderName, &$iCount, &$iUnseenCount, &$sUidNext) { $aFolderStatus = $this->oImapClient->FolderStatus($sFolderName, array( \MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES, \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN, \MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT )); $iCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES]) ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES] : 0; $iUnseenCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN]) ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0; $sUidNext = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT]) ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT] : '0'; if (0 === \strpos($sFolderName, '[Gmail]/')) { $oFolder = $this->oImapClient->FolderCurrentInformation(); if ($oFolder && null !== $oFolder->Exists) { $iCount = (int) $oFolder->Exists; } } } /** * @param string $sFolder * @param int $iCount * @param int $iUnseenCount * @param string $sUidNext * * @return string */ public static function GenerateHash($sFolder, $iCount, $iUnseenCount, $sUidNext) { $iUnseenCount = 0; return \md5($sFolder.'-'.$iCount.'-'.$iUnseenCount.'-'.$sUidNext); } /** * @param string $sFolderName * @param string $sPrevUidNext * @param string $sCurrentUidNext * * @return array */ private function getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sCurrentUidNext) { $aNewMessages = array(); if (0 < \strlen($sPrevUidNext) && (string) $sPrevUidNext !== (string) $sCurrentUidNext) { $this->oImapClient->FolderExamine($sFolderName); $aFetchResponse = $this->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 )) ), $sPrevUidNext.':*', 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::RECENT), $aFlags) || !\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); } $aNewMessages[] = array( 'Folder' => $sFolderName, '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 $aNewMessages; } /** * @param string $sFolderName * @param string $sPrevUidNext = '' * @param array $aUids = '' * * @return string * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function FolderInformation($sFolderName, $sPrevUidNext = '', $aUids = array()) { $aFlags = array(); if (\is_array($aUids) && 0 < \count($aUids)) { $this->oImapClient->FolderExamine($sFolderName); $aFetchResponse = $this->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)) { foreach ($aFetchResponse as $oFetchResponse) { $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID); $aFlags[(\is_numeric($sUid) ? (int) $sUid : 0)] = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::FLAGS); } } } $iCount = 0; $iUnseenCount = 0; $sUidNext = '0'; $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext); $aResult = array( 'Folder' => $sFolderName, 'Hash' => self::GenerateHash($sFolderName, $iCount, $iUnseenCount, $sUidNext), 'MessageCount' => $iCount, 'MessageUnseenCount' => $iUnseenCount, 'UidNext' => $sUidNext, 'Flags' => $aFlags, 'NewMessages' => 'INBOX' === $sFolderName ? $this->getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sUidNext) : array() ); return $aResult; } /** * @param string $sFolderName * * @return string * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function FolderHash($sFolderName) { $iCount = 0; $iUnseenCount = 0; $sUidNext = '0'; $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext); return self::GenerateHash($sFolderName, $iCount, $iUnseenCount, $sUidNext); } /** * @param string $sSearch * * @return string */ private function escapeSearchString($sSearch) { return ('ssl://imap.gmail.com' === \strtolower($this->oImapClient->GetConnectedHost())) // gmail ? '{'.\strlen($sSearch).'+}'."\r\n".$sSearch : $this->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('/".*?(? $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 string $sSearch * @param int $iTimeZoneOffset = 0 * * @return \MailSo\Imap\SearchBuilder */ private function getSearchBuilder($sSearch, $iTimeZoneOffset = 0) { $oSearchBuilder = \MailSo\Imap\SearchBuilder::NewInstance(); if (0 < \strlen(\trim($sSearch))) { $aLines = $this->parseSearchString($sSearch); if (1 === \count($aLines) && isset($aLines['OTHER'])) { if (true) { $sValue = $this->escapeSearchString($aLines['OTHER']); $oSearchBuilder->AddOr('FROM', $sValue); $oSearchBuilder->AddOr('TO', $sValue); $oSearchBuilder->AddOr('CC', $sValue); $oSearchBuilder->AddOr('SUBJECT', $sValue); } else { $oSearchBuilder->AddAnd('TEXT', $this->escapeSearchString($aLines['OTHER'])); } } else { if (isset($aLines['EMAIL'])) { $sValue = $this->escapeSearchString($aLines['EMAIL']); $oSearchBuilder->AddOr('FROM', $sValue); $oSearchBuilder->AddOr('TO', $sValue); $oSearchBuilder->AddOr('CC', $sValue); unset($aLines['EMAIL']); } if (isset($aLines['TO'])) { $sValue = $this->escapeSearchString($aLines['TO']); $oSearchBuilder->AddAnd('TO', $this->escapeSearchString($aLines['TO'])); $oSearchBuilder->AddOr('CC', $this->escapeSearchString($aLines['TO'])); unset($aLines['TO']); } $sMainText = ''; foreach ($aLines as $sName => $sRawValue) { if ('' === \trim($sRawValue)) { continue; } $sValue = $this->escapeSearchString($sRawValue); switch ($sName) { case 'FROM': $oSearchBuilder->AddAnd('FROM', $sValue); break; case 'SUBJECT': $oSearchBuilder->AddAnd('SUBJECT', $sValue); break; case 'OTHER': case 'BODY': case 'TEXT': $sMainText .= ' '.$sRawValue; break; case 'HAS': if (false !== \strpos($sRawValue, 'attach')) { $oSearchBuilder->AddAnd('HEADER CONTENT-TYPE', '"MULTIPART/MIXED"'); } // if (false !== strpos($sRawValue, 'flag')) // { // $oSearchBuilder->AddAnd('FLAGGED'); // } // if (false !== strpos($sRawValue, 'unseen')) // { // $oSearchBuilder->AddAnd('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) { $oSearchBuilder->AddAnd('SINCE', \gmdate('j-M-Y', $iDateStampFrom)); } if (0 < $iDateStampTo) { $oSearchBuilder->AddAnd('BEFORE', \gmdate('j-M-Y', $iDateStampTo)); } break; } } if ('' !== trim($sMainText)) { $sMainText = trim(trim(preg_replace('/[\s]+/', ' ', $sMainText)), '"'); $oSearchBuilder->AddAnd('TEXT', $this->escapeSearchString($sMainText)); } } } return $oSearchBuilder; } /** * @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; } /** * @param array $aThreads * @param array $aLastCollapsedThreadUids * @param array $aExpandedThreadsUids = array() * @param int|null $mLimit = null * * @return array */ private function compileLineThreadUids($aThreads, &$aLastCollapsedThreadUids, $aExpandedThreadsUids = array(), $mLimit = null) { $aResult = array(); $aLastCollapsedThreadUids = array(); $aExpandedThreadsUids = is_array($aExpandedThreadsUids) ? $aExpandedThreadsUids : array(); $bUseLimit = \is_int($mLimit); foreach ($aThreads as $iParentUid => $mItem) { if (\is_array($mItem)) { $aResult[] = $iParentUid; $iLocalLimit = $mLimit; foreach ($mItem as $iIndex => $mSubItem) { if (!\is_array($mSubItem)) { if (!$bUseLimit || in_array($iParentUid, $aExpandedThreadsUids)) { $aResult[] = $mSubItem; } else if (0 < $mLimit && 0 < $iLocalLimit--) { $aResult[] = $mSubItem; if (0 === $iLocalLimit && $iIndex + 1 < count($mItem)) { $aLastCollapsedThreadUids[] = $mSubItem; break; } } else if (0 === $mLimit) { $aLastCollapsedThreadUids[] = $iParentUid; break; } } } } else { $aResult[] = $iParentUid; } } return $aResult; } /** * @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 string $sFolderName * @param string $sFolderHash * @param mixed $oCacher * * @return array * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function MessageListThreadsMap($sFolderName, $sFolderHash, $oCacher) { if ($oCacher && $oCacher->IsInited()) { $sSerializedHash = 'ThreadsMap/'. $this->oImapClient->GetLogginedUser().'@'. $this->oImapClient->GetConnectedHost().':'. $this->oImapClient->GetConnectedPort().'/'. $sFolderName.'/'.$sFolderHash; $sSerializedUids = $oCacher->Get($sSerializedHash); if (!empty($sSerializedUids)) { $aSerializedUids = @\unserialize($sSerializedUids); if (is_array($aSerializedUids)) { return $aSerializedUids; } } } $this->oImapClient->FolderExamine($sFolderName); $aThreadUids = array(); try { $aThreadUids = $this->oImapClient->MessageSimpleThread(); } catch (\MailSo\Imap\Exceptions\RuntimeException $oException) { $aThreadUids = array(); } $aResult = $this->compileThreadArray($aThreadUids); if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHash)) { $oCacher->Set($sSerializedHash, serialize($aResult)); } return $aResult; } /** * @param \MailSo\Mail\MessageCollection &$oMessageCollection * @param array $aRequestIndexOrUids * @param bool $bIndexAsUid * * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function MessageListByRequestIndexOrUids(&$oMessageCollection, $aRequestIndexOrUids, $bIndexAsUid) { if (\is_array($aRequestIndexOrUids) && 0 < \count($aRequestIndexOrUids)) { $aFetchResponse = $this->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, $this->getEnvelopeOrHeadersRequestString() ), \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])) { $oMessageCollection->Add( Message::NewFetchResponseInstance( $oMessageCollection->FolderName, $aFetchIndexArray[$iFUid])); } } } } } /** * @return bool * * @throws \MailSo\Net\Exceptions\Exception */ public function IsThreadsSupported() { return $this->oImapClient->IsSupported('THREAD=REFS') || $this->oImapClient->IsSupported('THREAD=REFERENCES') || $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT'); } /** * @param string $sFolderName * @param int $iOffset = 0 * @param int $iLimit = 10 * @param string $sSearch = '' * @param string $sPrevUidNext = '' * @param mixed $oCacher = null * @param string $sCachePrefix = '' * @param bool $bUseSortIfSupported = false * @param bool $bUseThreadSortIfSupported = false * @param array $aExpandedThreadsUids = array() * * @return \MailSo\Mail\MessageCollection * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ public function MessageList($sFolderName, $iOffset = 0, $iLimit = 10, $sSearch = '', $sPrevUidNext = '', $oCacher = null, $bUseSortIfSupported = false, $bUseThreadSortIfSupported = false, $aExpandedThreadsUids = array()) { $sSearch = \trim($sSearch); if (!\MailSo\Base\Validator::RangeInt($iOffset, 0) || !\MailSo\Base\Validator::RangeInt($iLimit, 0, 999) || !is_string($sSearch)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } $this->oImapClient->FolderExamine($sFolderName); $oMessageCollection = MessageCollection::NewInstance(); $oMessageCollection->FolderName = $sFolderName; $oMessageCollection->Offset = $iOffset; $oMessageCollection->Limit = $iLimit; $oMessageCollection->Search = $sSearch; $aLastCollapsedThreadUids = array(); $aThreads = array(); $iMessageCount = 0; $iMessageRealCount = 0; $iMessageUnseenCount = 0; $sUidNext = '0'; $sSerializedHash = ''; $bUseSortIfSupported = $bUseSortIfSupported ? $this->oImapClient->IsSupported('SORT') : false; $bUseThreadSortIfSupported = $bUseThreadSortIfSupported ? ($this->oImapClient->IsSupported('THREAD=REFS') || $this->oImapClient->IsSupported('THREAD=REFERENCES') || $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT')) : false; if (!$oCacher || !($oCacher instanceof \MailSo\Cache\CacheClient)) { $oCacher = null; } $this->initFolderValues($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext); $iMessageCount = $iMessageRealCount; $oMessageCollection->FolderHash = self::GenerateHash($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext); $oMessageCollection->UidNext = $sUidNext; $oMessageCollection->NewMessages = $this->getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sUidNext); $bCacher = false; $bSearch = false; if (0 < $iMessageRealCount) { $bIndexAsUid = false; $aIndexOrUids = array(); $bSearch = 0 < \strlen($sSearch); if ($bSearch || ($bUseSortIfSupported && !$bUseThreadSortIfSupported)) { $bIndexAsUid = true; $aIndexOrUids = null; $sSearchCriterias = $this->getSearchBuilder($sSearch)->Complete(); if ($oCacher && $oCacher->IsInited()) { $sSerializedHash = ($bUseSortIfSupported ? 'S': 'N').'/'. ($bUseThreadSortIfSupported ? 'T': 'N').'/'. $this->oImapClient->GetLogginedUser().'@'. $this->oImapClient->GetConnectedHost().':'. $this->oImapClient->GetConnectedPort().'/'. $oMessageCollection->FolderName.'/'. $oMessageCollection->FolderHash.'/'. $sSearchCriterias; $sSerializedUids = $oCacher->Get($sSerializedHash); if (!empty($sSerializedUids)) { $aSerializedUids = @\unserialize($sSerializedUids); if (\is_array($aSerializedUids)) { $aIndexOrUids = $aSerializedUids; $bCacher = true; } } } if (!\is_array($aIndexOrUids)) { if ($bUseSortIfSupported && !$bUseThreadSortIfSupported) { $aIndexOrUids = $this->oImapClient->MessageSimpleSort(array('ARRIVAL'), $sSearchCriterias, $bIndexAsUid); } else { if (!\MailSo\Base\Utils::IsAscii($sSearch)) { try { $aIndexOrUids = $this->oImapClient->MessageSimpleSearch($sSearchCriterias, $bIndexAsUid, 'UTF-8'); } catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException) { $oException = null; $aIndexOrUids = null; } } if (null === $aIndexOrUids) { $aIndexOrUids = $this->oImapClient->MessageSimpleSearch($sSearchCriterias, $bIndexAsUid); } } } } else { if ($bUseThreadSortIfSupported && 1 < $iMessageCount) { $bIndexAsUid = true; $aThreads = $this->MessageListThreadsMap( $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $oCacher); $aIndexOrUids = $this->compileLineThreadUids($aThreads, $aLastCollapsedThreadUids, $aExpandedThreadsUids, 0); $iMessageCount = count($aIndexOrUids); } else { $bIndexAsUid = false; $aIndexOrUids = array(1); if (1 < $iMessageCount) { $aIndexOrUids = \array_reverse(\range(1, $iMessageCount)); } } } if ($bIndexAsUid && !$bCacher && \is_array($aIndexOrUids) && $oCacher && $oCacher->IsInited() && 0 < \strlen($sSerializedHash)) { $oCacher->Set($sSerializedHash, \serialize($aIndexOrUids)); } if (\is_array($aIndexOrUids)) { $oMessageCollection->MessageCount = $iMessageRealCount; $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount; $oMessageCollection->MessageResultCount = 0 === \strlen($sSearch) ? $iMessageCount : \count($aIndexOrUids); if (0 < count($aIndexOrUids)) { $iOffset = (0 > $iOffset) ? 0 : $iOffset; $aRequestIndexOrUids = \array_slice($aIndexOrUids, $iOffset, $iLimit); $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestIndexOrUids, $bIndexAsUid); } } } $aLastCollapsedThreadUidsForPage = array(); if (!$bSearch && $bUseThreadSortIfSupported && 0 < \count($aThreads)) { $oMessageCollection->ForeachList(function (/* @var $oMessage \MailSo\Mail\Message */ $oMessage) use ( $aThreads, $aLastCollapsedThreadUids, &$aLastCollapsedThreadUidsForPage) { $iUid = $oMessage->Uid(); if (in_array($iUid, $aLastCollapsedThreadUids)) { $aLastCollapsedThreadUidsForPage[] = $iUid; } if (isset($aThreads[$iUid]) && \is_array($aThreads[$iUid]) && 0 < \count($aThreads[$iUid])) { $oMessage->SetThreads($aThreads[$iUid]); $oMessage->SetThreadsLen(\count($aThreads[$iUid])); } else if (!isset($aThreads[$iUid])) { foreach ($aThreads as $iKeyUid => $mSubItem) { if (is_array($mSubItem) && in_array($iUid, $mSubItem)) { $oMessage->SetParentThread($iKeyUid); $oMessage->SetThreadsLen(\count($mSubItem)); } } } }); $oMessageCollection->LastCollapsedThreadUids = $aLastCollapsedThreadUidsForPage; } return $oMessageCollection; } /** * @param array $aList * @param int $iUid * @return array | null */ private function findMessageTreadUidsRec($aList, $iUid, $bRoot = false) { $mResult = null; foreach ($aList as $mItem) { if (\is_array($mItem)) { $mResult = $this->findMessageTreadUidsRec($mItem, $iUid); if (\is_array($mResult)) { break; } } else if ((int) $mItem === (int) $iUid) { $mResult = $bRoot ? null : $aList; break; } } return $mResult; } /** * @param array $aThreadUids * @param int $iUid * @return array | null */ public function GetMessageTreadUids($aThreadUids, $iUid) { return $this->findMessageTreadUidsRec($aThreadUids, $iUid, true); } /** * @return array|false */ public function Quota() { return $this->oImapClient->Quota(); } /** * @param string $sFolderName * @param string $sMessageId * * @return int|null */ public function FindMessageUidByMessageId($sFolderName, $sMessageId) { if (0 === \strlen($sMessageId)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } $this->oImapClient->FolderExamine($sFolderName); $sSearchCriterias = \MailSo\Imap\SearchBuilder::NewInstance() ->AddAnd('HEADER MESSAGE-ID', $sMessageId) ->Complete(); $aUids = $this->oImapClient->MessageSimpleSearch($sSearchCriterias, true); return \is_array($aUids) && 1 === \count($aUids) && \is_numeric($aUids[0]) ? (int) $aUids[0] : null; } /** * @param string $sParent = '' * @param string $sListPattern = '*' * @param bool $bUseListStatus = false * @param bool $bUseListSubscribeStatus = false * * @return \MailSo\Mail\FolderCollection|false */ public function Folders($sParent = '', $sListPattern = '*', $bUseListStatus = false, $bUseListSubscribeStatus = true) { $oFolderCollection = false; $aFolders = $this->oImapClient->FolderList($sParent, $sListPattern); $aSubscribedFolders = null; if ($bUseListSubscribeStatus) { try { $aSubscribedFolders = $this->oImapClient->FolderSubscribeList($sParent, $sListPattern); } catch (\Exception $oException) { } } // TODO // $mStatusFolders = null; // if ($bUseListStatus) // { // $mStatusFolders = $this->oImapClient->FolderStatusList($sParent, $sListPattern); // } $aImapSubscribedFoldersHelper = null; if (\is_array($aSubscribedFolders)) { $aImapSubscribedFoldersHelper = array(); 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[] = Folder::NewInstance($oImapFolder, (null === $aImapSubscribedFoldersHelper || \in_array($oImapFolder->FullNameRaw(), $aImapSubscribedFoldersHelper)) || $oImapFolder->IsInbox() ); } } if (\is_array($aMailFoldersHelper)) { $oFolderCollection = FolderCollection::NewInstance(); $oFolderCollection->InitByUnsortedMailFolderArray($aMailFoldersHelper); } if ($oFolderCollection) { $oFolderCollection->SortByCallback(function ($oFolderA, $oFolderB) { $sA = \strtoupper($oFolderA->FullNameRaw()); $sB = \strtoupper($oFolderB->FullNameRaw()); switch (true) { case 'INBOX' === $sA: return -1; case 'INBOX' === $sB: return 1; case '[GMAIL]' === $sA: return -1; case '[GMAIL]' === $sB: return 1; } return \strnatcmp($oFolderA->FullName(), $oFolderB->FullName()); }); $oNamespace = $this->oImapClient->GetNamespace(); if ($oNamespace) { $oFolderCollection->SetNamespace($oNamespace->GetPersonalNamespace()); } $oFolderCollection->IsThreadsSupported = $this->IsThreadsSupported(); } return $oFolderCollection; } /** * @param string $sFolderNameInUtf * @param string $sFolderParentFullNameRaw = '' * @param bool $bSubscribeOnCreation = true * * @return \MailSo\Mail\MailClient * * @throws \MailSo\Base\Exceptions\InvalidArgumentException */ public function FolderCreate($sFolderNameInUtf, $sFolderParentFullNameRaw = '', $bSubscribeOnCreation = true) { if (!\MailSo\Base\Validator::NotEmptyString($sFolderNameInUtf, true) || !\is_string($sFolderParentFullNameRaw)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } $sFolderNameInUtf = trim($sFolderNameInUtf); $aFolders = $this->oImapClient->FolderList('', 0 === \strlen(\trim($sFolderParentFullNameRaw)) ? 'INBOX' : $sFolderParentFullNameRaw); if (!\is_array($aFolders) || !isset($aFolders[0])) { // TODO throw new \MailSo\Mail\Exceptions\RuntimeException( 0 === \strlen(trim($sFolderParentFullNameRaw)) ? 'Cannot get folder delimiter' : 'Cannot create folder in non-existen parent folder'); } $sDelimiter = $aFolders[0]->Delimiter(); if (0 < \strlen($sDelimiter) && 0 < \strlen(\trim($sFolderParentFullNameRaw))) { $sFolderParentFullNameRaw .= $sDelimiter; } $sFullNameRawToCreate = \MailSo\Base\Utils::ConvertEncoding($sFolderNameInUtf, \MailSo\Base\Enumerations\Charset::UTF_8, \MailSo\Base\Enumerations\Charset::UTF_7_IMAP); if (0 < \strlen($sDelimiter) && false !== \strpos($sFullNameRawToCreate, $sDelimiter)) { // TODO throw new \MailSo\Mail\Exceptions\RuntimeException( 'New folder name contain delimiter'); } $sFullNameRawToCreate = $sFolderParentFullNameRaw.$sFullNameRawToCreate; $this->oImapClient->FolderCreate($sFullNameRawToCreate); if ($bSubscribeOnCreation) { $this->oImapClient->FolderSubscribe($sFullNameRawToCreate); } return $this; } /** * @param string $sPrevFolderFullNameRaw * @param string $sNewTopFolderNameInUtf * @param bool $bSubscribeOnRename = true * * @return \MailSo\Mail\MailClient * * @throws \MailSo\Base\Exceptions\InvalidArgumentException */ public function FolderRename($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, $bSubscribeOnRename = true) { if (0 === \strlen($sPrevFolderFullNameRaw) || 0 === \strlen($sNewTopFolderNameInUtf)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } $aFolders = $this->oImapClient->FolderList('', $sPrevFolderFullNameRaw); if (!\is_array($aFolders) || !isset($aFolders[0])) { // TODO throw new \MailSo\Mail\Exceptions\RuntimeException('Cannot rename non-existen folder'); } $sDelimiter = $aFolders[0]->Delimiter(); $iLast = \strrpos($sPrevFolderFullNameRaw, $sDelimiter); $sFolderParentFullNameRaw = false === $iLast ? '' : \substr($sPrevFolderFullNameRaw, 0, $iLast + 1); $mSubscribeFolders = null; if ($bSubscribeOnRename) { $mSubscribeFolders = $this->oImapClient->FolderSubscribeList($sPrevFolderFullNameRaw, '*'); if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders)) { foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) { $this->oImapClient->FolderUnSubscribe($oFolder->FullNameRaw()); } } } $sNewFolderFullNameRaw = \MailSo\Base\Utils::ConvertEncoding($sNewTopFolderNameInUtf, \MailSo\Base\Enumerations\Charset::UTF_8, \MailSo\Base\Enumerations\Charset::UTF_7_IMAP); if (0 < \strlen($sDelimiter) && false !== \strpos($sNewFolderFullNameRaw, $sDelimiter)) { // TODO throw new \MailSo\Mail\Exceptions\RuntimeException( 'New folder name contain delimiter'); } $sNewFolderFullNameRaw = $sFolderParentFullNameRaw.$sNewFolderFullNameRaw; $this->oImapClient->FolderRename($sPrevFolderFullNameRaw, $sNewFolderFullNameRaw); if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders)) { foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) { $sFolderFullNameRawForResubscrine = $oFolder->FullNameRaw(); if (0 === \strpos($sFolderFullNameRawForResubscrine, $sPrevFolderFullNameRaw)) { $sNewFolderFullNameRawForResubscrine = $sNewFolderFullNameRaw. \substr($sFolderFullNameRawForResubscrine, \strlen($sPrevFolderFullNameRaw)); $this->oImapClient->FolderSubscribe($sNewFolderFullNameRawForResubscrine); } } } return $this; } /** * @param string $sFolderFullNameRaw * @param bool $bUnsubscribeOnDeletion = true * * @return \MailSo\Mail\MailClient * * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Mail\Exceptions\RuntimeException */ public function FolderDelete($sFolderFullNameRaw, $bUnsubscribeOnDeletion = true) { if (0 === \strlen($sFolderFullNameRaw) || 'INBOX' === $sFolderFullNameRaw) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } $this->oImapClient->FolderExamine($sFolderFullNameRaw); $aIndexOrUids = $this->oImapClient->MessageSimpleSearch('ALL'); if (0 < \count($aIndexOrUids)) { throw new \MailSo\Mail\Exceptions\NonEmptyFolder(); } $this->oImapClient->FolderExamine('INBOX'); if ($bUnsubscribeOnDeletion) { $this->oImapClient->FolderUnSubscribe($sFolderFullNameRaw); } $this->oImapClient->FolderDelete($sFolderFullNameRaw); return $this; } /** * @param string $sFolderFullNameRaw * * @return \MailSo\Mail\MailClient * * @throws \MailSo\Base\Exceptions\InvalidArgumentException */ public function FolderClear($sFolderFullNameRaw) { $this->oImapClient->FolderSelect($sFolderFullNameRaw); $oFolderInformation = $this->oImapClient->FolderCurrentInformation(); if ($oFolderInformation && 0 < $oFolderInformation->Exists) // STATUS? { $this->oImapClient->MessageStoreFlag('1:*', false, array(\MailSo\Imap\Enumerations\MessageFlag::DELETED), \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT ); $this->oImapClient->MessageExpunge(); } return $this; } /** * @param string $sFolderFullNameRaw * @param bool $bSubscribe * * @return \MailSo\Mail\MailClient * * @throws \MailSo\Base\Exceptions\InvalidArgumentException */ public function FolderSubscribe($sFolderFullNameRaw, $bSubscribe) { if (0 === \strlen($sFolderFullNameRaw)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } $this->oImapClient->{($bSubscribe) ? 'FolderSubscribe' : 'FolderUnSubscribe'}($sFolderFullNameRaw); return $this; } /** * @param \MailSo\Log\Logger $oLogger * * @return \MailSo\Mail\MailClient * * @throws \MailSo\Base\Exceptions\InvalidArgumentException */ public function SetLogger($oLogger) { if (!($oLogger instanceof \MailSo\Log\Logger)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException(); } $this->oLogger = $oLogger; $this->oImapClient->SetLogger($this->oLogger); return $this; } }