This commit is contained in:
the-djmaze 2022-12-06 10:40:02 +01:00
parent ae40214f46
commit dc335f0016
9 changed files with 101 additions and 186 deletions

View file

@ -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

View file

@ -1,35 +0,0 @@
<?php
/*
* This file is part of MailSo.
*
* (c) 2014 Usenko Timur
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace MailSo\Imap\Enumerations;
/**
* @category MailSo
* @package Imap
* @subpackage Enumerations
*/
abstract class FolderResponseStatus
{
// RFC 3501
const MESSAGES = 'MESSAGES';
// const RECENT = 'RECENT'; // IMAP4rev2 deprecated
const UIDNEXT = 'UIDNEXT';
const UIDVALIDITY = 'UIDVALIDITY';
const UNSEEN = 'UNSEEN';
// RFC 4551
const HIGHESTMODSEQ = 'HIGHESTMODSEQ';
// RFC 7889
const APPENDLIMIT = 'APPENDLIMIT';
// RFC 8474
const MAILBOXID = 'MAILBOXID';
// RFC 9051 IMAP4rev2
const SIZE = 'SIZE';
}

View file

@ -30,4 +30,6 @@ abstract class FolderStatus
const APPENDLIMIT = 'APPENDLIMIT';
// RFC 8474
const MAILBOXID = 'MAILBOXID';
// RFC 9051 IMAP4rev2
const SIZE = 'SIZE';
}

View file

@ -20,11 +20,6 @@ class Folder
// RFC5258 Response data STATUS items when using LIST-EXTENDED
use Traits\Status;
/**
* @var string
*/
private $sFullName;
/**
* @var string
*/
@ -48,7 +43,7 @@ class Folder
if (!\strlen($sFullName)) {
throw new \InvalidArgumentException;
}
$this->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

View file

@ -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)
{

View file

@ -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]);
}

View file

@ -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())
);
}
*/

View file

@ -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(

View file

@ -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) {