Added support for rfc7889 and impoved rfc8474

This commit is contained in:
djmaze 2021-10-31 00:33:22 +02:00
parent d4117dc723
commit e4149b655c
6 changed files with 105 additions and 46 deletions

View file

@ -26,4 +26,8 @@ abstract class FolderResponseStatus
const UNSEEN = 'UNSEEN';
// rfc4551
const HIGHESTMODSEQ = 'HIGHESTMODSEQ';
// rfc7889
const APPENDLIMIT = 'APPENDLIMIT';
// rfc8474
const MAILBOXID = 'MAILBOXID';
}

View file

@ -26,6 +26,8 @@ abstract class FolderStatus
const UNSEEN = 'UNSEEN';
// rfc4551
const HIGHESTMODSEQ = 'HIGHESTMODSEQ';
// rfc7889
const APPENDLIMIT = 'APPENDLIMIT';
// rfc8474
const MAILBOXID = 'MAILBOXID';
}

View file

@ -54,12 +54,12 @@ class FetchResponse
{
$oResult = null;
$aEmails = $this->GetFetchEnvelopeValue($iIndex);
if (is_array($aEmails) && 0 < count($aEmails))
if (\is_array($aEmails) && \count($aEmails))
{
$oResult = new \MailSo\Mime\EmailCollection;
foreach ($aEmails as $aEmailItem)
{
if (is_array($aEmailItem) && 4 === count($aEmailItem))
if (\is_array($aEmailItem) && 4 === \count($aEmailItem))
{
$sDisplayName = \MailSo\Base\Utils::DecodeHeaderValue(
self::findEnvelopeIndex($aEmailItem, 0, ''), $sParentCharset);
@ -70,7 +70,7 @@ class FetchResponse
$sLocalPart = self::findEnvelopeIndex($aEmailItem, 2, '');
$sDomainPart = self::findEnvelopeIndex($aEmailItem, 3, '');
if (0 < strlen($sLocalPart) && 0 < strlen($sDomainPart))
if (\strlen($sLocalPart) && \strlen($sDomainPart))
{
$oResult->append(
new \MailSo\Mime\Email($sLocalPart.'@'.$sDomainPart, $sDisplayName)
@ -87,9 +87,9 @@ class FetchResponse
{
$aBodyStructureArray = $this->GetFetchValue(Enumerations\FetchType::BODYSTRUCTURE);
if (is_array($aBodyStructureArray))
if (\is_array($aBodyStructureArray))
{
if (0 < strlen($sRfc822SubMimeIndex))
if (\strlen($sRfc822SubMimeIndex))
{
return BodyStructure::NewInstanceFromRfc822SubPart($aBodyStructureArray, $sRfc822SubMimeIndex);
}
@ -100,6 +100,7 @@ class FetchResponse
}
/**
* Like: UID, RFC822.SIZE, MODSEQ, INTERNALDATE, FLAGS, BODYSTRUCTURE
* @return mixed
*/
public function GetFetchValue(string $sFetchItemName)
@ -124,11 +125,15 @@ class FetchResponse
return null;
}
/**
* Like: BODY[HEADER.FIELDS (RETURN-PATH RECEIVED MIME-VERSION MESSAGE-ID CONTENT-TYPE FROM TO CC BCC SENDER REPLY-TO DELIVERED-TO IN-REPLY-TO REFERENCES DATE SUBJECT SENSITIVITY X-MSMAIL-PRIORITY IMPORTANCE X-PRIORITY X-DRAFT-INFO RETURN-RECEIPT-TO DISPOSITION-NOTIFICATION-TO X-CONFIRM-READING-TO AUTHENTICATION-RESULTS X-DKIM-AUTHENTICATION-RESULTS LIST-UNSUBSCRIBE X-SPAM-STATUS X-SPAMD-RESULT X-BOGOSITY X-VIRUS X-VIRUS-SCANNED X-VIRUS-STATUS)]
* @return mixed
*/
public function GetHeaderFieldsValue(string $sRfc822SubMimeIndex = '') : string
{
$bNextIsValue = false;
$sRfc822SubMimeIndex = 0 < \strlen($sRfc822SubMimeIndex) ? ''.$sRfc822SubMimeIndex.'.' : '';
$sRfc822SubMimeIndex = \strlen($sRfc822SubMimeIndex) ? ''.$sRfc822SubMimeIndex.'.' : '';
if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3]))
{

View file

@ -334,6 +334,25 @@ class ImapClient extends \MailSo\Net\NetClient
}
}
/**
* RFC 7889
* APPENDLIMIT=<number> indicates that the IMAP server has the same upload limit for all mailboxes.
* APPENDLIMIT without any value indicates that the IMAP server supports this extension,
* and that the client will need to discover upload limits for each mailbox,
* as they might differ from mailbox to mailbox.
*/
public function AppendLimit() : ?int
{
if ($this->aCapabilityItems) {
foreach ($this->aCapabilityItems as $string) {
if ('APPENDLIMIT=' === \substr($string, 0, 12)) {
return (int) \substr($string, 12);
}
}
}
return null;
}
/**
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Imap\Exceptions\Exception
@ -416,21 +435,36 @@ class ImapClient extends \MailSo\Net\NetClient
*/
public function FolderStatus(string $sFolderName, array $aStatusItems) : ?array
{
if (!\count($aStatusItems)) {
return null;
}
$oFolderInfo = $this->oCurrentFolderInfo;
$bReselect = false;
$bWritable = false;
if ($oFolderInfo && $sFolderName === $oFolderInfo->FolderName) {
// Not supported by Outlook/Hotmail/Office365
/**
* There's a long standing IMAP CLIENTBUG where STATUS command is executed
* after SELECT/EXAMINE on same folder (it should not).
* So we must unselect the folder to be able to get the APPENDLIMIT and UNSEEN.
*/
/*
if ($this->IsSupported('ESEARCH')) {
$aResult = $oFolderInfo->getStatusItems();
// SELECT or EXAMINE command then UNSEEN is the message sequence number of the first unseen message
$aResult['UNSEEN'] = $this->simpleESearchOrESortHelper(false, 'UNSEEN', ['COUNT'])['COUNT'];
return $aResult;
}
// $this->FolderUnSelect();
*/
$bWritable = $oFolderInfo->IsWritable;
$bReselect = true;
$this->FolderUnSelect();
}
return \count($aStatusItems)
? $this->SendRequestGetResponse('STATUS', array($this->EscapeString($sFolderName), $aStatusItems))
->getStatusFolderInformationResult()
: null;
$aResult = $this->SendRequestGetResponse('STATUS', array($this->EscapeString($sFolderName), $aStatusItems))
->getStatusFolderInformationResult();
if ($bReselect) {
$this->selectOrExamineFolder($sFolderName, $bWritable, false);
}
return $aResult;
}
/**
@ -461,18 +495,26 @@ class ImapClient extends \MailSo\Net\NetClient
$aParameters[] = $this->EscapeString($sParentFolderName);
$aParameters[] = $this->EscapeString(\strlen(\trim($sListPattern)) ? $sListPattern : '*');
// RFC 5819
if ($bUseListStatus && !$bIsSubscribeList && $this->IsSupported('LIST-STATUS'))
{
// RFC 5819
$aL = array(
Enumerations\FolderStatus::MESSAGES,
Enumerations\FolderStatus::UNSEEN,
Enumerations\FolderStatus::UIDNEXT
);
// RFC 4551
if ($this->IsSupported('CONDSTORE')) {
$aL[] = Enumerations\FolderStatus::HIGHESTMODSEQ;
}
// RFC 7889
if ($this->IsSupported('APPENDLIMIT')) {
$aL[] = Enumerations\FolderStatus::APPENDLIMIT;
}
// RFC 8474
if ($this->IsSupported('OBJECTID')) {
$aTypes[] = Enumerations\FolderStatus::MAILBOXID;
}
$aReturnParams[] = 'STATUS';
$aReturnParams[] = $aL;
@ -560,11 +602,17 @@ class ImapClient extends \MailSo\Net\NetClient
throw new \MailSo\Base\Exceptions\InvalidArgumentException;
}
$aParams = array($this->EscapeString($sFolderName));
/*
if ($this->IsSupported('CONDSTORE')) {
$aParams[] = ['CONDSTORE'];
}
*/
/**
* IMAP4rev2 SELECT/EXAMINE are now required to return an untagged LIST response.
*/
$this->oCurrentFolderInfo = $this->SendRequestGetResponse($bIsWritable ? 'SELECT' : 'EXAMINE',
array($this->EscapeString($sFolderName)))
$aParams)
->getCurrentFolderInformation($sFolderName, $bIsWritable);
return $this;

View file

@ -70,6 +70,13 @@ trait Status
*/
$HIGHESTMODSEQ,
/**
* RFC7889
* Message upload size limit.
* @var int
*/
$APPENDLIMIT,
/**
* RFC8474
* A server-allocated unique identifier for the mailbox.
@ -81,7 +88,7 @@ trait Status
public function getStatusItems() : array
{
return \array_filter(\get_object_vars($this), function($v, $k){
return isset($v) && \property_exists(__TRAIT__, $k);
return \property_exists(__TRAIT__, $k);
}, ARRAY_FILTER_USE_BOTH);
}

View file

@ -519,8 +519,7 @@ class MailClient
return $this;
}
protected function initFolderValues(string $sFolderName, int &$iCount, int &$iUnseenCount,
int &$iUidNext, int &$iHighestModSeq) : void
protected function initFolderValues(string $sFolderName) : array
{
$aTypes = array(
FolderResponseStatus::MESSAGES,
@ -528,24 +527,31 @@ class MailClient
FolderResponseStatus::UIDNEXT
);
if ($this->oImapClient->IsSupported('CONDSTORE'))
{
if ($this->oImapClient->IsSupported('CONDSTORE')) {
$aTypes[] = FolderResponseStatus::HIGHESTMODSEQ;
}
if ($this->oImapClient->IsSupported('APPENDLIMIT')) {
$aTypes[] = FolderResponseStatus::APPENDLIMIT;
}
if ($this->oImapClient->IsSupported('OBJECTID')) {
$aTypes[] = FolderResponseStatus::MAILBOXID;
}
$aFolderStatus = $this->oImapClient->FolderStatus($sFolderName, $aTypes);
$iCount = (int) $aFolderStatus[FolderResponseStatus::MESSAGES] ?? 0;
return [
$aFolderStatus[FolderResponseStatus::MESSAGES] ?: 0,
$iUnseenCount = (int) $aFolderStatus[FolderResponseStatus::UNSEEN] ?? 0;
$aFolderStatus[FolderResponseStatus::UNSEEN] ?: 0,
$iUidNext = (int) $aFolderStatus[FolderResponseStatus::UIDNEXT] ?? 0;
$aFolderStatus[FolderResponseStatus::UIDNEXT] ?: 0,
if (isset($aFolderStatus[FolderResponseStatus::HIGHESTMODSEQ])) {
$iHighestModSeq = (int) $aFolderStatus[FolderResponseStatus::HIGHESTMODSEQ];
} else {
$iHighestModSeq = 0;
}
$aFolderStatus[FolderResponseStatus::HIGHESTMODSEQ] ?: 0,
$aFolderStatus[FolderResponseStatus::APPENDLIMIT] ?: $this->oImapClient->AppendLimit(),
$aFolderStatus[FolderResponseStatus::MAILBOXID] ?: ''
];
}
public function GenerateImapClientHash() : string
@ -652,12 +658,7 @@ class MailClient
}
}
$iCount = 0;
$iUnseenCount = 0;
$iUidNext = 0;
$iHighestModSeq = 0;
$this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $iUidNext, $iHighestModSeq);
list($iCount, $iUnseenCount, $iUidNext, $iHighestModSeq, $iAppendLimit, $sMailboxId) = $this->initFolderValues($sFolderName);
return array(
'Folder' => $sFolderName,
@ -667,6 +668,8 @@ class MailClient
'UidNext' => $iUidNext,
'MessageFlags' => $aFlags,
'HighestModSeq' => $iHighestModSeq,
'AppendLimit' => $iAppendLimit,
'MailboxId' => $sMailboxId,
'NewMessages' => 'INBOX' === $sFolderName && \MailSo\Config::$CheckNewMessages ?
$this->getFolderNextMessageInformation($sFolderName, $iPrevUidNext, $iUidNext) : array()
);
@ -679,12 +682,7 @@ class MailClient
*/
public function FolderHash(string $sFolderName) : string
{
$iCount = 0;
$iUnseenCount = 0;
$iUidNext = 0;
$iHighestModSeq = 0;
$this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $iUidNext, $iHighestModSeq);
list($iCount, $iUnseenCount, $iUidNext, $iHighestModSeq) = $this->initFolderValues($sFolderName);
return $this->GenerateFolderHash($sFolderName, $iCount, $iUidNext, $iHighestModSeq);
}
@ -1555,11 +1553,6 @@ class MailClient
$mAllSortedUids = null;
$mAllThreads = null;
$iMessageRealCount = 0;
$iMessageUnseenCount = 0;
$iUidNext = 0;
$iHighestModSeq = 0;
$bUseSortIfSupported = $bUseSortIfSupported && $this->oImapClient->IsSupported('SORT');
$bUseThreadSortIfSupported = $bUseThreadSortIfSupported ?
@ -1575,7 +1568,7 @@ class MailClient
$oCacher = null;
}
$this->initFolderValues($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $iUidNext, $iHighestModSeq);
list($iMessageRealCount, $iMessageUnseenCount, $iUidNext, $iHighestModSeq) = $this->initFolderValues($sFolderName);
if ($bUseFilter)
{