diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Folders.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Folders.php index e38fdf231..84fbaff6e 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Folders.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Folders.php @@ -16,7 +16,6 @@ use MailSo\Imap\Folder; use MailSo\Imap\FolderInformation; use MailSo\Imap\SequenceSet; use MailSo\Imap\Enumerations\FolderStatus; -use MailSo\Imap\Enumerations\FolderResponseStatus; /** * @category MailSo @@ -104,6 +103,38 @@ trait Folders return $this; } + private function FolderStatusItems() : array + { + $aStatusItems = array( + FolderStatus::MESSAGES, + FolderStatus::UNSEEN, + FolderStatus::UIDNEXT, + FolderStatus::UIDVALIDITY + ); + // RFC 4551 + if ($this->IsSupported('CONDSTORE')) { + $aStatusItems[] = FolderStatus::HIGHESTMODSEQ; + } + // RFC 7889 + if ($this->IsSupported('APPENDLIMIT')) { + $aStatusItems[] = FolderStatus::APPENDLIMIT; + } + // RFC 8474 + if ($this->IsSupported('OBJECTID')) { + $aStatusItems[] = FolderStatus::MAILBOXID; +/* + } else if ($this->IsSupported('X-DOVECOT')) { + $aStatusItems[] = 'X-GUID'; +*/ + } +/* // STATUS SIZE can take a significant amount of time, therefore not active + if ($this->IsSupported('IMAP4rev2')) { + $aStatusItems[] = FolderStatus::SIZE; + } +*/ + return $aStatusItems; + } + /** * @throws \InvalidArgumentException * @throws \MailSo\RuntimeException @@ -114,30 +145,6 @@ trait Folders */ public function FolderStatus(string $sFolderName, bool $bSelect = false) : FolderInformation { - $aStatusItems = array( - FolderResponseStatus::MESSAGES, - FolderResponseStatus::UNSEEN, - FolderResponseStatus::UIDNEXT, - FolderResponseStatus::UIDVALIDITY - ); - if ($this->IsSupported('CONDSTORE')) { - $aStatusItems[] = FolderResponseStatus::HIGHESTMODSEQ; - } - if ($this->IsSupported('APPENDLIMIT')) { - $aStatusItems[] = FolderResponseStatus::APPENDLIMIT; - } - if ($this->IsSupported('OBJECTID')) { - $aStatusItems[] = FolderResponseStatus::MAILBOXID; -/* - } else if ($this->IsSupported('X-DOVECOT')) { - $aStatusItems[] = 'X-GUID'; -*/ - } -/* // STATUS SIZE can take a significant amount of time, therefore not active - if ($this->IsSupported('IMAP4rev2')) { - $aStatusItems[] = FolderResponseStatus::SIZE; - } -*/ $oFolderInfo = $this->oCurrentFolderInfo; $bReselect = false; $bWritable = false; @@ -148,12 +155,10 @@ trait Folders * 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->MessageSimpleESearch('UNSEEN', ['COUNT'])['COUNT']; - return $aResult; + if ($this->IsSupported('ESEARCH') && !isset($oFolderInfo->UNSEEN)) { + $oFolderInfo->UNSEEN = $this->MessageSimpleESearch('UNSEEN', ['COUNT'])['COUNT']; } + return $oFolderInfo; */ $bWritable = $oFolderInfo->IsWritable; $bReselect = true; @@ -161,7 +166,7 @@ trait Folders } $oInfo = new FolderInformation($sFolderName, false); - $this->SendRequest('STATUS', array($this->EscapeFolderName($sFolderName), $aStatusItems)); + $this->SendRequest('STATUS', array($this->EscapeFolderName($sFolderName), $this->FolderStatusItems())); foreach ($this->yieldUntaggedResponses() as $oResponse) { $oInfo->setStatusFromResponse($oResponse); } @@ -170,8 +175,8 @@ trait Folders // Don't use FolderExamine, else PERMANENTFLAGS is empty in Dovecot $oFolderInformation = $this->selectOrExamineFolder($sFolderName, $bSelect || $bWritable, false); $oFolderInformation->MESSAGES = \max(0, $oFolderInformation->MESSAGES, $oInfo->MESSAGES); - // $oFolderInformation has the message sequence number of the first unseen message in the mailbox - // so we set it to the amount of unseen messages + // SELECT or EXAMINE command then UNSEEN is the message sequence number of the first unseen message. + // And deprecated in IMAP4rev2, so we set it to the amount of unseen messages $oFolderInformation->UNSEEN = \max(0, $oInfo->UNSEEN); $oFolderInformation->UIDNEXT = \max(0, $oFolderInformation->UIDNEXT, $oInfo->UIDNEXT); $oFolderInformation->UIDVALIDITY = \max(0, $oFolderInformation->UIDVALIDITY, $oInfo->UIDVALIDITY); @@ -399,9 +404,14 @@ trait Folders } } + // SELECT or EXAMINE command then UNSEEN is the message sequence number of the first unseen message. // IMAP4rev2 deprecated $oResult->UNSEEN = null; - +/* + if ($this->IsSupported('ESEARCH')) { + $oResult->UNSEEN = $this->MessageSimpleESearch('UNSEEN', ['COUNT'])['COUNT']; + } +*/ $this->oCurrentFolderInfo = $oResult; return $oResult; @@ -444,30 +454,8 @@ trait Folders // RFC 5819 if ($bUseListStatus && !$bIsSubscribeList && $this->IsSupported('LIST-STATUS')) { - $aL = array( - FolderStatus::MESSAGES, - FolderStatus::UNSEEN, - FolderStatus::UIDNEXT - ); - // RFC 4551 - if ($this->IsSupported('CONDSTORE')) { - $aL[] = FolderStatus::HIGHESTMODSEQ; - } - // RFC 7889 - if ($this->IsSupported('APPENDLIMIT')) { - $aL[] = FolderStatus::APPENDLIMIT; - } - // RFC 8474 - if ($this->IsSupported('OBJECTID')) { - $aL[] = FolderStatus::MAILBOXID; -/* - } else if ($this->IsSupported('X-DOVECOT')) { - $aL[] = 'X-GUID'; -*/ - } - $aReturnParams[] = 'STATUS'; - $aReturnParams[] = $aL; + $aReturnParams[] = $this->FolderStatusItems(); } /* // RFC 5738 diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/FolderResponseStatus.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/FolderResponseStatus.php deleted file mode 100644 index eaabe002e..000000000 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/FolderResponseStatus.php +++ /dev/null @@ -1,35 +0,0 @@ -sFullName = $sFullName; + $this->FolderName = $sFullName; $this->setDelimiter($sDelimiter); $this->setFlags($aFlags); /* @@ -72,7 +67,7 @@ class Folder public function Name() : string { - $sNameRaw = $this->sFullName; + $sNameRaw = $this->FolderName; if ($this->sDelimiter) { $aNames = \explode($this->sDelimiter, $sNameRaw); return \end($aNames); @@ -82,7 +77,7 @@ class Folder public function FullName() : string { - return $this->sFullName; + return $this->FolderName; } public function Delimiter() : ?string @@ -102,7 +97,7 @@ class Folder public function IsInbox() : bool { - return 'INBOX' === \strtoupper($this->sFullName) || \in_array('\\inbox', $this->aFlagsLowerCase); + return 'INBOX' === \strtoupper($this->FolderName) || \in_array('\\inbox', $this->aFlagsLowerCase); } public function SetMetadata(string $sName, string $sData) : void diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/FolderInformation.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/FolderInformation.php index 0954bdf7f..7cc653480 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/FolderInformation.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/FolderInformation.php @@ -19,27 +19,17 @@ class FolderInformation implements \JsonSerializable { use Traits\Status; - /** - * @var string - */ - public $FolderName; + public bool $IsWritable; /** - * @var bool - */ - public $IsWritable; - - /** - * @var array * Message flags */ - public $Flags = array(); + public array $Flags = array(); /** - * @var array * NOTE: Empty when FolderExamine is used */ - public $PermanentFlags = array(); + public array $PermanentFlags = array(); function __construct(string $sFolderName, bool $bIsWritable) { diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Traits/Status.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Traits/Status.php index 36ec68828..941b5feb3 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Traits/Status.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Traits/Status.php @@ -22,6 +22,8 @@ namespace MailSo\Imap\Traits; */ trait Status { + public string $FolderName; + public /** * The number of messages in the mailbox. @@ -92,11 +94,20 @@ trait Status */ $SIZE; - public function getStatusItems() : array + public function getHash(string $sClientHash) : ?string { - return \array_filter(\get_object_vars($this), function($v, $k){ - return \property_exists(__TRAIT__, $k); - }, ARRAY_FILTER_USE_BOTH); + if (!isset($this->MESSAGES, $this->UIDNEXT)) { + return null; + } + return \md5('FolderHash/'. \implode('-', [ + $this->FolderName, + $this->MESSAGES, + $this->UIDNEXT, + $this->UIDVALIDITY, + $this->HIGHESTMODSEQ, + $sClientHash, + \MailSo\Config::$MessageListPermanentFilter + ])); } public function setStatus(string $name, $value) : bool @@ -157,6 +168,7 @@ trait Status } // SELECT or EXAMINE command else if (\is_numeric($oResponse->ResponseList[1]) && \is_string($oResponse->ResponseList[2])) { + // UNSEEN deprecated in IMAP4rev2 if ('UNSEEN' !== $oResponse->ResponseList[2]) { $bResult |= $this->setStatus($oResponse->ResponseList[2], $oResponse->ResponseList[1]); } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Folder.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Folder.php index db5066cb8..125f6fc38 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Folder.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Folder.php @@ -95,9 +95,9 @@ class Folder implements \JsonSerializable return $this->bExists && $this->oImapFolder->IsSelectable(); } - public function Status() : array + public function Hash(string $sClientHash) : ?string { - return $this->oImapFolder->getStatusItems(); + return $this->oImapFolder->getHash($sClientHash); } public function IsInbox() : bool @@ -206,15 +206,12 @@ class Folder implements \JsonSerializable { /* $aExtended = null; - $aStatus = $this->oImapFolder->getStatusItems(); - if ($aStatus && isset($aStatus['MESSAGES'], $aStatus['UNSEEN'], $aStatus['UIDNEXT'])) { + if (isset($this->oImapFolder->MESSAGES, $this->oImapFolder->UNSEEN, $this->oImapFolder->UIDNEXT)) { $aExtended = array( - 'totalEmails' => (int) $aStatus['MESSAGES'], - 'unreadEmails' => (int) $aStatus['UNSEEN'], - 'UidNext' => (int) $aStatus['UIDNEXT'], -// 'Hash' => $this->MailClient()->GenerateFolderHash( -// $this->FullName(), $aStatus['MESSAGES'], $aStatus['UIDNEXT'], -// \max(0, $aStatus['HIGHESTMODSEQ'] ?? $aStatus['UIDVALIDITY']) + 'totalEmails' => (int) $this->oImapFolder->MESSAGES, + 'unreadEmails' => (int) $this->oImapFolder->UNSEEN, + 'UidNext' => (int) $this->oImapFolder->UIDNEXT, +// 'Hash' => $this->Hash($this->MailClient()->GenerateImapClientHash()) ); } */ diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php index 9e86a2c7d..7455b04f2 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php @@ -11,11 +11,11 @@ namespace MailSo\Mail; -use MailSo\Imap\Enumerations\FolderResponseStatus; +use MailSo\Imap\FolderInformation; +use MailSo\Imap\Enumerations\FetchType; use MailSo\Imap\Enumerations\MessageFlag; use MailSo\Imap\Enumerations\StoreAction; use MailSo\Imap\SequenceSet; -use MailSo\Imap\Enumerations\FetchType; use MailSo\Mime\Enumerations\Header as MimeHeader; use MailSo\Mime\Enumerations\Parameter as MimeParameter; @@ -407,24 +407,6 @@ class MailClient return $this; } - protected function initFolderValues(string $sFolderName) : array - { - $oFolderStatus = $this->oImapClient->FolderStatus($sFolderName); - return [ - \max(0, $oFolderStatus->MESSAGES ?: 0), - - \max(0, $oFolderStatus->UNSEEN ?: 0), - - \max(0, $oFolderStatus->UIDNEXT ?: 0), - - \max(0, $oFolderStatus->HIGHESTMODSEQ ?: $oFolderStatus->UIDVALIDITY), - - $oFolderStatus->APPENDLIMIT ?: $this->oImapClient->AppendLimit(), - - $oFolderStatus->MAILBOXID ?: '' - ]; - } - public function GenerateImapClientHash() : string { return \md5('ImapClientHash/'. @@ -434,14 +416,6 @@ class MailClient ); } - public function GenerateFolderHash(string $sFolder, int $iCount, int $iUidNext, int $iHighestModSeq) : string - { - return \md5('FolderHash/'.$sFolder.'-'.$iCount.'-'.$iUidNext.'-'. - $iHighestModSeq.'-'.$this->GenerateImapClientHash().'-'. - \MailSo\Config::$MessageListPermanentFilter - ); - } - /** * Returns list of new messages since $iPrevUidNext * Currently only for INBOX @@ -501,19 +475,14 @@ class MailClient */ public function FolderInformation(string $sFolderName, int $iPrevUidNext = 0, SequenceSet $oRange = null) : array { - list($iCount, $iUnseenCount, $iUidNext, $iHighestModSeq, $iAppendLimit, $sMailboxId) = $this->initFolderValues($sFolderName); -/* - $oInfo = $this->oImapClient->FolderStatusAndSelect($sFolderName); -*/ $aFlags = array(); if ($oRange && \count($oRange)) { - $oInfo = $this->oImapClient->FolderExamine($sFolderName); - +// $oInfo = $this->oImapClient->FolderExamine($sFolderName); + $oInfo = $this->oImapClient->FolderStatusAndSelect($sFolderName); $aFetchResponse = $this->oImapClient->Fetch(array( FetchType::UID, FetchType::FLAGS ), (string) $oRange, $oRange->UID); - foreach ($aFetchResponse as $oFetchResponse) { $iUid = (int) $oFetchResponse->GetFetchValue(FetchType::UID); $aLowerFlags = \array_map('mb_strtolower', \array_map('\\MailSo\\Base\\Utils::Utf7ModifiedToUtf8', $oFetchResponse->GetFetchValue(FetchType::FLAGS))); @@ -522,22 +491,28 @@ class MailClient 'Flags' => $aLowerFlags ); } + } else { + $oInfo = $this->oImapClient->FolderStatus($sFolderName); } return array( 'Folder' => $sFolderName, - 'totalEmails' => $iCount, - 'unreadEmails' => $iUnseenCount, - 'UidNext' => $iUidNext, - 'HighestModSeq' => $iHighestModSeq, - 'AppendLimit' => $iAppendLimit, - 'MailboxId' => $sMailboxId, + 'totalEmails' => $oInfo->MESSAGES, + 'unreadEmails' => $oInfo->UNSEEN, + 'UidNext' => $oInfo->UIDNEXT, + 'UidValidity' => $oInfo->UIDVALIDITY, + 'HighestModSeq' => $oInfo->HIGHESTMODSEQ, + 'AppendLimit' => $oInfo->APPENDLIMIT ?: $this->oImapClient->AppendLimit(), + 'MailboxId' => $oInfo->MAILBOXID ?: '', // 'Flags' => $oInfo->Flags, // 'PermanentFlags' => $oInfo->PermanentFlags, - 'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUidNext, $iHighestModSeq), -// 'Hash' => $this->GenerateFolderHash($sFolderName, $oInfo->MESSAGES, $oInfo->UIDNEXT, $oInfo->HIGHESTMODSEQ); + 'Hash' => $oInfo->getHash($this->GenerateImapClientHash()), 'MessagesFlags' => $aFlags, - 'NewMessages' => $this->getFolderNextMessageInformation($sFolderName, $iPrevUidNext, $iUidNext) + 'NewMessages' => $this->getFolderNextMessageInformation( + $sFolderName, + $iPrevUidNext, + \intval($oInfo->UIDNEXT) + ) ); } @@ -549,9 +524,7 @@ class MailClient */ public function FolderHash(string $sFolderName) : string { - list($iCount, $iUnseenCount, $iUidNext, $iHighestModSeq) = $this->initFolderValues($sFolderName); - - return $this->GenerateFolderHash($sFolderName, $iCount, $iUidNext, $iHighestModSeq); + return $this->oImapClient->FolderStatus($sFolderName)->getHash($this->GenerateImapClientHash()); } /** @@ -832,9 +805,7 @@ class MailClient $oParams->oCacher = null; } - $oMessageCollection->FolderHash = $this->GenerateFolderHash( - $oParams->sFolderName, $oInfo->MESSAGES, $oInfo->UIDNEXT, \max(0, $oInfo->HIGHESTMODSEQ ?: $oInfo->UIDVALIDITY) - ); + $oMessageCollection->FolderHash = $oInfo->getHash($this->GenerateImapClientHash()); if (!$oParams->iThreadUid) { $oMessageCollection->NewMessages = $this->getFolderNextMessageInformation( diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php index 219ed9ddd..59f10472e 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php @@ -250,14 +250,9 @@ trait Response { $aResult = $mResponse->jsonSerialize(); - $aStatus = $mResponse->Status(); - if ($aStatus && isset($aStatus['MESSAGES'], $aStatus['UIDNEXT'])) { - $aResult['Hash'] = $this->MailClient()->GenerateFolderHash( - $mResponse->FullName(), - $aStatus['MESSAGES'], - $aStatus['UIDNEXT'], - \max(0, $aStatus['HIGHESTMODSEQ'] ?? $aStatus['UIDVALIDITY']) - ); + $sHash = $mResponse->Hash($this->MailClient()->GenerateImapClientHash()); + if ($sHash) { + $aResult['Hash'] = $sHash; } if (null === $this->aCheckableFolder) {