diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Messages.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Messages.php index 36461691e..5b42903d0 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Messages.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Messages.php @@ -33,14 +33,13 @@ trait Messages $oSort->sCriterias = $sSearchCriterias; $oSort->bUid = $bReturnUid; $oSort->aSortTypes = $aSortTypes; - $oResponseCollection = $oSort->SendRequestGetResponse(); + $oSort->SendRequest(); $aReturn = array(); - foreach ($oResponseCollection as $oResponse) { + foreach ($this->yieldUntaggedResponses() as $oResponse) { $iOffset = ($bReturnUid && 'UID' === $oResponse->StatusOrIndex && !empty($oResponse->ResponseList[2]) && 'SORT' === $oResponse->ResponseList[2]) ? 1 : 0; - if (ResponseType::UNTAGGED === $oResponse->ResponseType - && ('SORT' === $oResponse->StatusOrIndex || $iOffset) - && \is_array($oResponse->ResponseList) - && 2 < \count($oResponse->ResponseList)) + if (\is_array($oResponse->ResponseList) + && 2 < \count($oResponse->ResponseList) + && ('SORT' === $oResponse->StatusOrIndex || $iOffset)) { $iLen = \count($oResponse->ResponseList); for ($iIndex = 2 + $iOffset; $iIndex < $iLen; ++$iIndex) { @@ -64,7 +63,8 @@ trait Messages $oESearch->bUid = $bReturnUid; $oESearch->sLimit = $sLimit; $oESearch->sCharset = $sCharset; - return $this->getSimpleESearchOrESortResult($oESearch->SendRequestGetResponse(), $bReturnUid); + $oESearch->SendRequest(); + return $this->getSimpleESearchOrESortResult($bReturnUid); } /** @@ -80,7 +80,8 @@ trait Messages $oSort->aSortTypes = $aSortTypes; $oSort->aReturn = $aSearchReturn ?: ['ALL']; $oSort->sLimit = $sLimit; - return $this->getSimpleESearchOrESortResult($oSort->SendRequestGetResponse(), $bReturnUid); + $oSort->SendRequest(); + return $this->getSimpleESearchOrESortResult($bReturnUid); } /** @@ -146,15 +147,14 @@ trait Messages return $oThread->SendRequestGetResponse(); } - private function getSimpleESearchOrESortResult(ResponseCollection $oResponseCollection, bool $bReturnUid) : array + private function getSimpleESearchOrESortResult(bool $bReturnUid) : array { $sRequestTag = $this->getCurrentTag(); $aResult = array(); - foreach ($oResponseCollection as $oResponse) { - if (ResponseType::UNTAGGED === $oResponse->ResponseType - && ('ESEARCH' === $oResponse->StatusOrIndex || 'SORT' === $oResponse->StatusOrIndex) - && \is_array($oResponse->ResponseList) + foreach ($this->yieldUntaggedResponses() as $oResponse) { + if (\is_array($oResponse->ResponseList) && isset($oResponse->ResponseList[2][1]) + && ('ESEARCH' === $oResponse->StatusOrIndex || 'SORT' === $oResponse->StatusOrIndex) && 'TAG' === $oResponse->ResponseList[2][0] && $sRequestTag === $oResponse->ResponseList[2][1] && (!$bReturnUid || (!empty($oResponse->ResponseList[3]) && 'UID' === $oResponse->ResponseList[3])) ) diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php index 8812edb16..99ca8ea0f 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php @@ -484,10 +484,9 @@ class ImapClient extends \MailSo\Net\NetClient $oInfo = new FolderInformation($sFolderName, false); $this->SendRequest('STATUS', array($this->EscapeFolderName($sFolderName), $aStatusItems)); - $this->getResponse(null, function(Response $oResponse) use ($oInfo) { + foreach ($this->yieldUntaggedResponses() as $oResponse) { $oInfo->setStatusFromResponse($oResponse); - return true; - }); + } if ($bReselect) { $this->selectOrExamineFolder($sFolderName, $bWritable, false); @@ -579,20 +578,18 @@ class ImapClient extends \MailSo\Net\NetClient } else { $sDelimiter = ''; $bInbox = false; - $oImapClient = $this; - $this->getResponse(null, function(Response $oResponse) use ($oImapClient, &$aReturn, $sCmd, &$sDelimiter, &$bInbox, $aMetadata) { + foreach ($this->yieldUntaggedResponses() as $oResponse) { if ('STATUS' === $oResponse->StatusOrIndex && isset($oResponse->ResponseList[2])) { - $sFullName = $oImapClient->toUTF8($oResponse->ResponseList[2]); + $sFullName = $this->toUTF8($oResponse->ResponseList[2]); if (!isset($aReturn[$sFullName])) { $aReturn[$sFullName] = new Folder($sFullName); } $aReturn[$sFullName]->setStatusFromResponse($oResponse); - return true; } else if ($sCmd === $oResponse->StatusOrIndex && 5 === \count($oResponse->ResponseList)) { try { - $sFullName = $oImapClient->toUTF8($oResponse->ResponseList[4]); + $sFullName = $this->toUTF8($oResponse->ResponseList[4]); /** * $oResponse->ResponseList[0] = * @@ -624,19 +621,17 @@ class ImapClient extends \MailSo\Net\NetClient } $aReturn[$sFullName] = $oFolder; - return true; } catch (\MailSo\Base\Exceptions\InvalidArgumentException $oException) { - $oImapClient->writeLogException($oException, \MailSo\Log\Enumerations\Type::WARNING, false); + $this->writeLogException($oException, \MailSo\Log\Enumerations\Type::WARNING, false); } catch (\Throwable $oException) { - $oImapClient->writeLogException($oException, \MailSo\Log\Enumerations\Type::WARNING, false); + $this->writeLogException($oException, \MailSo\Log\Enumerations\Type::WARNING, false); } } - return false; - }); + } if (!$bInbox && !$sParentFolderName && !isset($aReturn['INBOX'])) { $aReturn['INBOX'] = new Folder('INBOX', $sDelimiter); @@ -743,7 +738,7 @@ class ImapClient extends \MailSo\Net\NetClient $oResult = new FolderInformation($sFolderName, $bIsWritable); $this->SendRequest($bIsWritable ? 'SELECT' : 'EXAMINE', $aParams); - $this->getResponse(null, function(Response $oResponse) use ($oResult) { + foreach ($this->yieldUntaggedResponses() as $oResponse) { if (!$oResult->setStatusFromResponse($oResponse)) { // OK untagged responses if (\is_array($oResponse->OptionalResponse)) { @@ -768,8 +763,7 @@ class ImapClient extends \MailSo\Net\NetClient $oResult->Flags = $oResponse->ResponseList[2]; } } - return true; - }); + } $this->oCurrentFolderInfo = $oResult; @@ -889,17 +883,15 @@ class ImapClient extends \MailSo\Net\NetClient */ $this->SendRequest($bIndexIsUid ? 'UID FETCH' : 'FETCH', $aParams); - $oImapClient = $this; - $this->getResponse(null, function(Response $oResponse) use ($oImapClient, &$aReturn) { + foreach ($this->yieldUntaggedResponses() as $oResponse) { if (FetchResponse::IsValidFetchImapResponse($oResponse)) { if (FetchResponse::IsNotEmptyFetchImapResponse($oResponse)) { $aReturn[] = new FetchResponse($oResponse); - return true; - } else if ($oImapClient->oLogger) { - $oImapClient->oLogger->Write('Skipped Imap Response! ['.$oResponse->ToLine().']', \MailSo\Log\Enumerations\Type::NOTICE); + } else if ($this->oLogger) { + $this->oLogger->Write('Skipped Imap Response! ['.$oResponse->ToLine().']', \MailSo\Log\Enumerations\Type::NOTICE); } } - }); + } } finally { $this->aFetchCallbacks = array(); } @@ -1166,7 +1158,7 @@ class ImapClient extends \MailSo\Net\NetClient } } - protected function getResponse(string $sEndTag = null, callable $cbUntaggedResponse = null) : ResponseCollection + protected function getResponse(string $sEndTag = null) : ResponseCollection { try { $oResult = new ResponseCollection; @@ -1176,9 +1168,7 @@ class ImapClient extends \MailSo\Net\NetClient while (true) { $oResponse = $this->partialParseResponse(); - if (!$cbUntaggedResponse || Enumerations\ResponseType::UNTAGGED !== $oResponse->ResponseType || !$cbUntaggedResponse($oResponse)) { - $oResult->append($oResponse); - } + $oResult->append($oResponse); // RFC 5530 if ($sEndTag === $oResponse->Tag && \is_array($oResponse->OptionalResponse) && 'CLIENTBUG' === $oResponse->OptionalResponse[0]) { @@ -1209,6 +1199,50 @@ class ImapClient extends \MailSo\Net\NetClient return $oResult; } +// public function yieldUntaggedResponses(string $sEndTag = null) : \Generator + public function yieldUntaggedResponses(string $sEndTag = null) : iterable + { + try { + $oResult = new ResponseCollection; + + if (\is_resource($this->ConnectionResource())) { + $sEndTag = $sEndTag ?: $this->getCurrentTag(); + + while (true) { + $oResponse = $this->partialParseResponse(); + if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType) { + yield $oResponse; + } else { + $oResult->append($oResponse); + } + + // RFC 5530 + if ($sEndTag === $oResponse->Tag && \is_array($oResponse->OptionalResponse) && 'CLIENTBUG' === $oResponse->OptionalResponse[0]) { + // The server has detected a client bug. +// \error_log("IMAP {$oResponse->OptionalResponse[0]}: {$this->lastCommand}"); + } + + if ($sEndTag === $oResponse->Tag || Enumerations\ResponseType::CONTINUATION === $oResponse->ResponseType) { + if (isset($this->aTagTimeouts[$sEndTag])) { + $this->writeLog((\microtime(true) - $this->aTagTimeouts[$sEndTag]).' ('.$sEndTag.')', + \MailSo\Log\Enumerations\Type::TIME); + + unset($this->aTagTimeouts[$sEndTag]); + } + + break; + } + } + } + + $oResult->validate(); + + } catch (\Throwable $e) { + $this->writeLogException($e, \MailSo\Log\Enumerations\Type::WARNING); + throw $e; + } + } + protected function prepareParamLine(array $aParams = array()) : string { $sReturn = ''; diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/ESEARCH.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/ESEARCH.php index cdb91b629..de91952db 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/ESEARCH.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/ESEARCH.php @@ -63,7 +63,7 @@ class ESEARCH extends Request parent::__construct($oImapClient); } - public function SendRequestGetResponse() : \MailSo\Imap\ResponseCollection + public function SendRequest() : string { $sCmd = 'SEARCH'; $aRequest = array(); @@ -120,7 +120,7 @@ class ESEARCH extends Request $aRequest[] = $this->sLimit; } - return $this->oImapClient->SendRequestGetResponse( + return $this->oImapClient->SendRequest( ($this->bUid ? 'UID ' : '') . $sCmd, $aRequest ); diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/SORT.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/SORT.php index e93f82f41..3f239b045 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/SORT.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/SORT.php @@ -64,7 +64,7 @@ class SORT extends Request parent::__construct($oImapClient); } - public function SendRequestGetResponse() : \MailSo\Imap\ResponseCollection + public function SendRequest() : string { if (!$this->aSortTypes) { $this->oImapClient->writeLogException( @@ -109,7 +109,7 @@ class SORT extends Request $aRequest[] = $this->sLimit; } - return $this->oImapClient->SendRequestGetResponse( + return $this->oImapClient->SendRequest( ($this->bUid ? 'UID SORT' : 'SORT'), $aRequest ); diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/THREAD.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/THREAD.php index e113ac4af..fed81ffe9 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/THREAD.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/THREAD.php @@ -63,16 +63,15 @@ class THREAD extends Request $aRequest[] = \strtoupper($this->sCharset); $aRequest[] = $sSearchCriterias; - $oResponseCollection = $this->oImapClient->SendRequestGetResponse( + $this->oImapClient->SendRequest( ($this->bUid ? 'UID THREAD' : 'THREAD'), $aRequest ); $aReturn = array(); - foreach ($oResponseCollection as $oResponse) { + foreach ($this->oImapClient->yieldUntaggedResponses() as $oResponse) { $iOffset = ($bReturnUid && 'UID' === $oResponse->StatusOrIndex && !empty($oResponse->ResponseList[2]) && 'THREAD' === $oResponse->ResponseList[2]) ? 1 : 0; - if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType - && ('THREAD' === $oResponse->StatusOrIndex || $iOffset) + if (('THREAD' === $oResponse->StatusOrIndex || $iOffset) && \is_array($oResponse->ResponseList) && 2 < \count($oResponse->ResponseList)) {