Added callable cbUntaggedResponse param to ImapClient.getResponse()

This allows one less foreach() in ImapClient functions:
* specificFolderList()
* selectOrExamineFolder()
* FolderStatus()
* Fetch()
This commit is contained in:
djmaze 2021-12-08 21:13:12 +01:00
parent f7412db3e5
commit da0d8f66d5
2 changed files with 80 additions and 73 deletions

View file

@ -482,17 +482,17 @@ class ImapClient extends \MailSo\Net\NetClient
$this->FolderUnSelect(); $this->FolderUnSelect();
} }
$oResponseCollection = $this->SendRequestGetResponse('STATUS', array($this->EscapeFolderName($sFolderName), $aStatusItems));
$oInfo = new FolderInformation($sFolderName, false); $oInfo = new FolderInformation($sFolderName, false);
foreach ($oResponseCollection as $oResponse) { $this->SendRequest('STATUS', array($this->EscapeFolderName($sFolderName), $aStatusItems));
$this->getResponse(null, function(Response $oResponse) use ($oInfo) {
$oInfo->setStatusFromResponse($oResponse); $oInfo->setStatusFromResponse($oResponse);
} return true;
$aResult = $oInfo->getStatusItems(); });
if ($bReselect) { if ($bReselect) {
$this->selectOrExamineFolder($sFolderName, $bWritable, false); $this->selectOrExamineFolder($sFolderName, $bWritable, false);
} }
return $aResult; return $oInfo->getStatusItems();
} }
/** /**
@ -562,30 +562,37 @@ class ImapClient extends \MailSo\Net\NetClient
$aParameters[] = $aReturnParams; $aParameters[] = $aReturnParams;
} }
$bPassthru = false;
$aReturn = array(); $aReturn = array();
// RFC 5464
$bMetadata = !$bIsSubscribeList && $this->IsSupported('METADATA');
$aMetadata = null;
if ($bMetadata) {
// Dovecot supports fetching all METADATA at once
$aMetadata = $this->getAllMetadata();
}
$this->SendRequest($sCmd, $aParameters); $this->SendRequest($sCmd, $aParameters);
$bPassthru = false;
if ($bPassthru) { if ($bPassthru) {
$this->streamResponse(); $this->streamResponse();
} else { } else {
$sDelimiter = ''; $sDelimiter = '';
$bInbox = false; $bInbox = false;
foreach ($this->getResponse() as $oResponse) { $oImapClient = $this;
if (Enumerations\ResponseType::UNTAGGED !== $oResponse->ResponseType) { $this->getResponse(null, function(Response $oResponse) use ($oImapClient, &$aReturn, $sCmd, &$sDelimiter, &$bInbox, $aMetadata) {
continue;
}
if ('STATUS' === $oResponse->StatusOrIndex && isset($oResponse->ResponseList[2])) { if ('STATUS' === $oResponse->StatusOrIndex && isset($oResponse->ResponseList[2])) {
$sFullName = $this->toUTF8($oResponse->ResponseList[2]); $sFullName = $oImapClient->toUTF8($oResponse->ResponseList[2]);
if (!isset($aReturn[$sFullName])) { if (!isset($aReturn[$sFullName])) {
$aReturn[$sFullName] = new Folder($sFullName); $aReturn[$sFullName] = new Folder($sFullName);
} }
$aReturn[$sFullName]->setStatusFromResponse($oResponse); $aReturn[$sFullName]->setStatusFromResponse($oResponse);
return true;
} }
else if ($sCmd === $oResponse->StatusOrIndex && 5 == \count($oResponse->ResponseList)) { else if ($sCmd === $oResponse->StatusOrIndex && 5 === \count($oResponse->ResponseList)) {
try try
{ {
$sFullName = $this->toUTF8($oResponse->ResponseList[4]); $sFullName = $oImapClient->toUTF8($oResponse->ResponseList[4]);
/** /**
* $oResponse->ResponseList[0] = * * $oResponse->ResponseList[0] = *
@ -612,18 +619,24 @@ class ImapClient extends \MailSo\Net\NetClient
$sDelimiter = $oFolder->Delimiter(); $sDelimiter = $oFolder->Delimiter();
} }
if (isset($aMetadata[$oResponse->ResponseList[4]])) {
$oFolder->SetAllMetadata($aMetadata[$oResponse->ResponseList[4]]);
}
$aReturn[$sFullName] = $oFolder; $aReturn[$sFullName] = $oFolder;
return true;
} }
catch (\MailSo\Base\Exceptions\InvalidArgumentException $oException) catch (\MailSo\Base\Exceptions\InvalidArgumentException $oException)
{ {
$this->writeLogException($oException, \MailSo\Log\Enumerations\Type::WARNING, false); $oImapClient->writeLogException($oException, \MailSo\Log\Enumerations\Type::WARNING, false);
} }
catch (\Throwable $oException) catch (\Throwable $oException)
{ {
$this->writeLogException($oException, \MailSo\Log\Enumerations\Type::WARNING, false); $oImapClient->writeLogException($oException, \MailSo\Log\Enumerations\Type::WARNING, false);
} }
} }
} return false;
});
if (!$bInbox && !$sParentFolderName && !isset($aReturn['INBOX'])) { if (!$bInbox && !$sParentFolderName && !isset($aReturn['INBOX'])) {
$aReturn['INBOX'] = new Folder('INBOX', $sDelimiter); $aReturn['INBOX'] = new Folder('INBOX', $sDelimiter);
@ -631,24 +644,14 @@ class ImapClient extends \MailSo\Net\NetClient
} }
// RFC 5464 // RFC 5464
if (!$bIsSubscribeList && $this->IsSupported('METADATA')) { if ($bMetadata && !$aMetadata) {
// Dovecot supports fetching all METADATA at once foreach ($aReturn as $oFolder) {
$aMetadata = $this->getAllMetadata(); try {
if ($aMetadata) { $oFolder->SetAllMetadata(
foreach ($aReturn as $oFolder) { $this->getMetadata($oFolder->FullName(), ['/shared', '/private'], ['DEPTH'=>'infinity'])
if (isset($aMetadata[$oFolder->FullName()])) { );
$oFolder->SetAllMetadata($aMetadata[$oFolder->FullName()]); } catch (\Throwable $e) {
} // Ignore error
}
} else {
foreach ($aReturn as $oFolder) {
try {
$oFolder->SetAllMetadata(
$this->getMetadata($oFolder->FullName(), ['/shared', '/private'], ['DEPTH'=>'infinity'])
);
} catch (\Throwable $e) {
// Ignore error
}
} }
} }
} }
@ -738,34 +741,36 @@ class ImapClient extends \MailSo\Net\NetClient
*/ */
$oResponseCollection = $this->SendRequestGetResponse($bIsWritable ? 'SELECT' : 'EXAMINE', $aParams); $oResponseCollection = $this->SendRequestGetResponse($bIsWritable ? 'SELECT' : 'EXAMINE', $aParams);
$oResult = new FolderInformation($sFolderName, $bIsWritable); $oResult = new FolderInformation($sFolderName, $bIsWritable);
foreach ($oResponseCollection as $oResponse) {
if (Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType) {
if (!$oResult->setStatusFromResponse($oResponse)) {
// OK untagged responses
if (\is_array($oResponse->OptionalResponse)) {
$key = $oResponse->OptionalResponse[0];
if (\count($oResponse->OptionalResponse) > 1) {
if ('PERMANENTFLAGS' === $key && \is_array($oResponse->OptionalResponse[1])) {
$oResult->PermanentFlags = $oResponse->OptionalResponse[1];
}
} else if ('READ-ONLY' === $key) {
// $oResult->IsWritable = false;
} else if ('READ-WRITE' === $key) {
// $oResult->IsWritable = true;
} else if ('NOMODSEQ' === $key) {
// https://datatracker.ietf.org/doc/html/rfc4551#section-3.1.2
}
}
// untagged responses $this->SendRequest($bIsWritable ? 'SELECT' : 'EXAMINE', $aParams);
else if (\count($oResponse->ResponseList) > 2 $this->getResponse(null, function(Response $oResponse) use ($oResult) {
&& 'FLAGS' === $oResponse->ResponseList[1] if (!$oResult->setStatusFromResponse($oResponse)) {
&& \is_array($oResponse->ResponseList[2])) { // OK untagged responses
$oResult->Flags = $oResponse->ResponseList[2]; if (\is_array($oResponse->OptionalResponse)) {
$key = $oResponse->OptionalResponse[0];
if (\count($oResponse->OptionalResponse) > 1) {
if ('PERMANENTFLAGS' === $key && \is_array($oResponse->OptionalResponse[1])) {
$oResult->PermanentFlags = $oResponse->OptionalResponse[1];
}
} else if ('READ-ONLY' === $key) {
// $oResult->IsWritable = false;
} else if ('READ-WRITE' === $key) {
// $oResult->IsWritable = true;
} else if ('NOMODSEQ' === $key) {
// https://datatracker.ietf.org/doc/html/rfc4551#section-3.1.2
} }
} }
// untagged responses
else if (\count($oResponse->ResponseList) > 2
&& 'FLAGS' === $oResponse->ResponseList[1]
&& \is_array($oResponse->ResponseList[2])) {
$oResult->Flags = $oResponse->ResponseList[2];
}
} }
} return true;
});
$this->oCurrentFolderInfo = $oResult; $this->oCurrentFolderInfo = $oResult;
return $this; return $this;
@ -861,6 +866,7 @@ class ImapClient extends \MailSo\Net\NetClient
\MailSo\Log\Enumerations\Type::ERROR, true); \MailSo\Log\Enumerations\Type::ERROR, true);
} }
$aReturn = array();
$this->aFetchCallbacks = array(); $this->aFetchCallbacks = array();
try { try {
$aFetchItems = Enumerations\FetchType::ChangeFetchItemsBefourRequest($aInputFetchItems); $aFetchItems = Enumerations\FetchType::ChangeFetchItemsBefourRequest($aInputFetchItems);
@ -882,21 +888,22 @@ class ImapClient extends \MailSo\Net\NetClient
* $aParams[1][] = MODSEQ * $aParams[1][] = MODSEQ
*/ */
$oResult = $this->SendRequestGetResponse($bIndexIsUid ? 'UID FETCH' : 'FETCH', $aParams); $this->SendRequest($bIndexIsUid ? 'UID FETCH' : 'FETCH', $aParams);
$oImapClient = $this;
$this->getResponse(null, function(Response $oResponse) use ($oImapClient, &$aReturn) {
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);
}
}
});
} finally { } finally {
$this->aFetchCallbacks = array(); $this->aFetchCallbacks = array();
} }
$aReturn = array();
foreach ($oResult as $oResponse) {
if (FetchResponse::IsValidFetchImapResponse($oResponse)) {
if (FetchResponse::IsNotEmptyFetchImapResponse($oResponse)) {
$aReturn[] = new FetchResponse($oResponse);
} else if ($this->oLogger) {
$this->oLogger->Write('Skipped Imap Response! ['.$oResponse->ToLine().']', \MailSo\Log\Enumerations\Type::NOTICE);
}
}
}
return $aReturn; return $aReturn;
} }
@ -1159,7 +1166,7 @@ class ImapClient extends \MailSo\Net\NetClient
} }
} }
protected function getResponse(string $sEndTag = null) : ResponseCollection protected function getResponse(string $sEndTag = null, callable $cbUntaggedResponse = null) : ResponseCollection
{ {
try { try {
$oResult = new ResponseCollection; $oResult = new ResponseCollection;
@ -1169,7 +1176,9 @@ class ImapClient extends \MailSo\Net\NetClient
while (true) { while (true) {
$oResponse = $this->partialParseResponse(); $oResponse = $this->partialParseResponse();
$oResult->append($oResponse); if (!$cbUntaggedResponse || Enumerations\ResponseType::UNTAGGED !== $oResponse->ResponseType || !$cbUntaggedResponse($oResponse)) {
$oResult->append($oResponse);
}
// RFC 5530 // RFC 5530
if ($sEndTag === $oResponse->Tag && \is_array($oResponse->OptionalResponse) && 'CLIENTBUG' === $oResponse->OptionalResponse[0]) { if ($sEndTag === $oResponse->Tag && \is_array($oResponse->OptionalResponse) && 'CLIENTBUG' === $oResponse->OptionalResponse[0]) {

View file

@ -1220,8 +1220,6 @@ class MailClient
} }
} }
$bUseListStatus = $bUseListStatus && $this->oImapClient->IsSupported('LIST-STATUS');
$aFolders = $bUseListStatus $aFolders = $bUseListStatus
? $this->oImapClient->FolderStatusList($sParent, $sListPattern) ? $this->oImapClient->FolderStatusList($sParent, $sListPattern)
: $this->oImapClient->FolderList($sParent, $sListPattern); : $this->oImapClient->FolderList($sParent, $sListPattern);