Improved support RFC8474 (MAILBOXID, EMAILID, THREADID) for RFC8621 section 4.1.1

This commit is contained in:
the-djmaze 2022-06-02 11:26:49 +02:00
parent a43fadb4e8
commit a073e7f308
9 changed files with 69 additions and 18 deletions

View file

@ -119,6 +119,10 @@ trait Folders
} }
if ($this->IsSupported('OBJECTID')) { if ($this->IsSupported('OBJECTID')) {
$aStatusItems[] = FolderResponseStatus::MAILBOXID; $aStatusItems[] = FolderResponseStatus::MAILBOXID;
/*
} else if ($this->IsSupported('X-DOVECOT')) {
$aFetchItems[] = 'X-GUID';
*/
} }
$oFolderInfo = $this->oCurrentFolderInfo; $oFolderInfo = $this->oCurrentFolderInfo;
@ -341,6 +345,9 @@ trait Folders
// $oResult->IsWritable = true; // $oResult->IsWritable = true;
} else if ('NOMODSEQ' === $key) { } else if ('NOMODSEQ' === $key) {
// https://datatracker.ietf.org/doc/html/rfc4551#section-3.1.2 // https://datatracker.ietf.org/doc/html/rfc4551#section-3.1.2
} else if ('MAILBOXID' === $key) {
// https://www.rfc-editor.org/rfc/rfc8474#section-4.2
$oResult->MAILBOXID = $oResponse->OptionalResponse[1];
} }
} }
@ -409,7 +416,11 @@ trait Folders
} }
// RFC 8474 // RFC 8474
if ($this->IsSupported('OBJECTID')) { if ($this->IsSupported('OBJECTID')) {
$aTypes[] = FolderStatus::MAILBOXID; $aL[] = FolderStatus::MAILBOXID;
/*
} else if ($this->IsSupported('X-DOVECOT')) {
$aL[] = 'X-GUID';
*/
} }
$aReturnParams[] = 'STATUS'; $aReturnParams[] = 'STATUS';

View file

@ -78,6 +78,23 @@ trait Messages
break; break;
} }
} }
if ($this->IsSupported('OBJECTID')) {
$aFetchItems[] = FetchType::EMAILID;
$aFetchItems[] = FetchType::THREADID;
} else if ($this->IsSupported('X-GM-EXT-1')) {
// https://developers.google.com/gmail/imap/imap-extensions
$aFetchItems[] = 'X-GM-MSGID';
$aFetchItems[] = 'X-GM-THRID';
/*
} else if ($this->IsSupported('X-DOVECOT')) {
$aFetchItems[] = 'X-GUID';
*/
}
/*
if ($this->IsSupported('X-GM-EXT-1') && \in_array(FetchType::FLAGS, $aFetchItems)) {
$aFetchItems[] = 'X-GM-LABELS';
}
*/
$aParams = array($sIndexRange, $aFetchItems); $aParams = array($sIndexRange, $aFetchItems);

View file

@ -53,6 +53,9 @@ abstract class FetchType
const BINARY_SIZE = 'BINARY.SIZE'; const BINARY_SIZE = 'BINARY.SIZE';
// RFC 4551 // RFC 4551
const MODSEQ = 'MODSEQ'; const MODSEQ = 'MODSEQ';
// RFC 8474
const EMAILID = 'EMAILID';
const THREADID = 'THREADID';
public static function BuildBodyCustomHeaderRequest(array $aHeaders, bool $bPeek = true) : string public static function BuildBodyCustomHeaderRequest(array $aHeaders, bool $bPeek = true) : string
{ {

View file

@ -63,6 +63,7 @@ class FolderInformation implements \JsonSerializable
public function jsonSerialize() public function jsonSerialize()
{ {
return array( return array(
'id' => $this->MAILBOXID,
'Name' => $this->FolderName, 'Name' => $this->FolderName,
'Flags' => $this->Flags, 'Flags' => $this->Flags,
'PermanentFlags' => $this->PermanentFlags, 'PermanentFlags' => $this->PermanentFlags,
@ -73,7 +74,6 @@ class FolderInformation implements \JsonSerializable
'UidValidity' => $this->UIDVALIDITY, 'UidValidity' => $this->UIDVALIDITY,
'Highestmodseq' => $this->HIGHESTMODSEQ, 'Highestmodseq' => $this->HIGHESTMODSEQ,
'Appendlimit' => $this->APPENDLIMIT, 'Appendlimit' => $this->APPENDLIMIT,
'Mailboxid' => $this->MAILBOXID,
*/ */
); );
} }

View file

@ -293,6 +293,9 @@ class ImapClient extends \MailSo\Net\NetClient
if (!$this->aCapabilityItems) { if (!$this->aCapabilityItems) {
$this->setCapabilities($this->SendRequestGetResponse('CAPABILITY')); $this->setCapabilities($this->SendRequestGetResponse('CAPABILITY'));
} }
/*
$this->aCapabilityItems[] = 'X-DOVECOT';
*/
return $this->aCapabilityItems; return $this->aCapabilityItems;
} }

View file

@ -96,6 +96,8 @@ trait Status
{ {
if ('EXISTS' === $name) { if ('EXISTS' === $name) {
$name = 'MESSAGES'; $name = 'MESSAGES';
} else if ('X-GUID' === $name) {
$name = 'MAILBOXID';
} }
if (\property_exists(__TRAIT__, $name)) { if (\property_exists(__TRAIT__, $name)) {
if ('MAILBOXID' !== $name) { if ('MAILBOXID' !== $name) {

View file

@ -229,7 +229,12 @@ class Folder implements \JsonSerializable
'Flags' => $this->FlagsLowerCase(), 'Flags' => $this->FlagsLowerCase(),
// 'Extended' => $aExtended, // 'Extended' => $aExtended,
// 'PermanentFlags' => $this->oImapFolder->PermanentFlags, // 'PermanentFlags' => $this->oImapFolder->PermanentFlags,
'Metadata' => $this->oImapFolder->Metadata() 'Metadata' => $this->oImapFolder->Metadata(),
'UidNext' => $this->oImapFolder->UIDNEXT,
// RFC 8621
'totalEmails' => $this->oImapFolder->MESSAGES,
'unreadEmails' => $this->oImapFolder->UNSEEN,
'id' => $this->oImapFolder->MAILBOXID
); );
} }
} }

View file

@ -36,6 +36,12 @@ class Message implements \JsonSerializable
$sHeaderDate = '', $sHeaderDate = '',
$aFlagsLowerCase = [], $aFlagsLowerCase = [],
/**
* https://www.rfc-editor.org/rfc/rfc8474#section-5
*/
$sEmailId = '',
$sThreadId = '',
/** /**
* @var \MailSo\Mime\EmailCollection * @var \MailSo\Mime\EmailCollection
*/ */
@ -287,16 +293,21 @@ class Message implements \JsonSerializable
$oBodyStructure = $oFetchResponse->GetFetchBodyStructure(); $oBodyStructure = $oFetchResponse->GetFetchBodyStructure();
} }
$sInternalDate = $oFetchResponse->GetFetchValue(FetchType::INTERNALDATE);
$aFlags = $oFetchResponse->GetFetchValue(FetchType::FLAGS); $aFlags = $oFetchResponse->GetFetchValue(FetchType::FLAGS);
$oMessage->sFolder = $sFolder; $oMessage->sFolder = $sFolder;
$oMessage->iUid = (int) $oFetchResponse->GetFetchValue(FetchType::UID); $oMessage->iUid = (int) $oFetchResponse->GetFetchValue(FetchType::UID);
$oMessage->iSize = (int) $oFetchResponse->GetFetchValue(FetchType::RFC822_SIZE); $oMessage->iSize = (int) $oFetchResponse->GetFetchValue(FetchType::RFC822_SIZE);
$oMessage->aFlagsLowerCase = \array_map('mb_strtolower', \array_map('\\MailSo\\Base\\Utils::Utf7ModifiedToUtf8', $aFlags ?: [])); $oMessage->aFlagsLowerCase = \array_map('mb_strtolower', \array_map('\\MailSo\\Base\\Utils::Utf7ModifiedToUtf8', $aFlags ?: []));
$oMessage->iInternalTimeStampInUTC = \MailSo\Base\DateTimeHelper::ParseInternalDateString(
$oFetchResponse->GetFetchValue(FetchType::INTERNALDATE)
);
$oMessage->iInternalTimeStampInUTC = $oMessage->sEmailId = $oFetchResponse->GetFetchValue(FetchType::EMAILID)
\MailSo\Base\DateTimeHelper::ParseInternalDateString($sInternalDate); // ?: $oFetchResponse->GetFetchValue('X-GUID')
?: $oFetchResponse->GetFetchValue('X-GM-MSGID');
$oMessage->sThreadId = $oFetchResponse->GetFetchValue(FetchType::THREADID)
?: $oFetchResponse->GetFetchValue('X-GM-THRID');
$sCharset = $oBodyStructure ? Utils::NormalizeCharset($oBodyStructure->SearchCharset()) : ''; $sCharset = $oBodyStructure ? Utils::NormalizeCharset($oBodyStructure->SearchCharset()) : '';
@ -660,9 +671,13 @@ class Message implements \JsonSerializable
'Flags' => $this->aFlagsLowerCase, 'Flags' => $this->aFlagsLowerCase,
// https://datatracker.ietf.org/doc/html/rfc8621#section-4.1.1 // https://datatracker.ietf.org/doc/html/rfc8621#section-4.1.1
'id' => $this->sEmailId,
// 'blobId' => $this->sEmailIdBlob,
'threadId' => $this->sThreadId,
// 'mailboxIds' => ['mailboxid'=>true],
// 'keywords' => \array_fill_keys($this->aFlagsLowerCase, true),
'size' => $this->iSize, 'size' => $this->iSize,
'receivedAt' => \gmdate('Y-m-d\\TH:i:s\\Z', $this->iInternalTimeStampInUTC) 'receivedAt' => \gmdate('Y-m-d\\TH:i:s\\Z', $this->iInternalTimeStampInUTC)
// 'keywords' => \array_fill_keys($this->aFlagsLowerCase, true)
); );
} }
} }

View file

@ -269,17 +269,12 @@ trait Response
$aResult = $mResponse->jsonSerialize(); $aResult = $mResponse->jsonSerialize();
$aStatus = $mResponse->Status(); $aStatus = $mResponse->Status();
if ($aStatus && isset($aStatus['MESSAGES'], $aStatus['UNSEEN'], $aStatus['UIDNEXT'])) { if ($aStatus && isset($aStatus['MESSAGES'], $aStatus['UIDNEXT'])) {
$aResult = \array_merge( $aResult['Hash'] = $this->MailClient()->GenerateFolderHash(
$aResult, $mResponse->FullName(),
[ $aStatus['MESSAGES'],
'totalEmails' => (int) $aStatus['MESSAGES'], $aStatus['UIDNEXT'],
'unreadEmails' => (int) $aStatus['UNSEEN'], empty($aStatus['HIGHESTMODSEQ']) ? 0 : $aStatus['HIGHESTMODSEQ']
'UidNext' => (int) $aStatus['UIDNEXT'],
'Hash' => $this->MailClient()->GenerateFolderHash(
$mResponse->FullName(), $aStatus['MESSAGES'], $aStatus['UIDNEXT'],
empty($aStatus['HIGHESTMODSEQ']) ? 0 : $aStatus['HIGHESTMODSEQ'])
]
); );
} }