From 22450e743015ca2b5636817e4930782d8c6cfe62 Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 19 Dec 2022 17:26:59 +0100 Subject: [PATCH] Cleanup MailSo --- .../app/libraries/MailSo/Base/Validator.php | 24 -- .../MailSo/Imap/Commands/Folders.php | 200 +++++++------ .../MailSo/Imap/Commands/Messages.php | 60 +++- .../MailSo/Imap/Commands/Metadata.php | 4 + .../app/libraries/MailSo/Imap/Folder.php | 2 +- .../app/libraries/MailSo/Imap/ImapClient.php | 15 + .../app/libraries/MailSo/Mail/Attachment.php | 117 ++------ .../app/libraries/MailSo/Mail/MailClient.php | 272 +++--------------- .../app/libraries/MailSo/Mail/Message.php | 4 +- .../MailSo/Mail/MessageListParams.php | 5 +- .../app/libraries/MailSo/Net/NetClient.php | 2 +- .../libraries/MailSo/Sieve/SieveClient.php | 4 +- .../libraries/RainLoop/Actions/Folders.php | 2 +- .../libraries/RainLoop/Actions/Response.php | 2 +- 14 files changed, 243 insertions(+), 470 deletions(-) delete mode 100644 snappymail/v/0.0.0/app/libraries/MailSo/Base/Validator.php diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Base/Validator.php b/snappymail/v/0.0.0/app/libraries/MailSo/Base/Validator.php deleted file mode 100644 index 5a62af55c..000000000 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Base/Validator.php +++ /dev/null @@ -1,24 +0,0 @@ -= $iMin) && (null === $iMax || $iNumber <= $iMax); - } -} 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 40145040e..717b27370 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,6 +16,8 @@ use MailSo\Imap\Folder; use MailSo\Imap\FolderInformation; use MailSo\Imap\SequenceSet; use MailSo\Imap\Enumerations\FolderStatus; +use MailSo\Imap\Enumerations\MessageFlag; +use MailSo\Imap\Enumerations\StoreAction; /** * @category MailSo @@ -23,20 +25,33 @@ use MailSo\Imap\Enumerations\FolderStatus; */ trait Folders { + /** + * @throws \InvalidArgumentException + */ + public function FolderClear(string $sFolderFullName) : void + { + if (0 < $this->FolderSelect($sFolderFullName)->MESSAGES) { + $this->MessageStoreFlag(new SequenceSet('1:*', false), + array(MessageFlag::DELETED), + StoreAction::ADD_FLAGS_SILENT + ); + $this->FolderExpunge(); + } + } + /** * @throws \InvalidArgumentException * @throws \MailSo\RuntimeException * @throws \MailSo\Net\Exceptions\* * @throws \MailSo\Imap\Exceptions\* */ - public function FolderCreate(string $sFolderName, bool $bSubscribe = false) : self + public function FolderCreate(string $sFolderName, bool $bSubscribe = false) : void { $this->SendRequestGetResponse('CREATE', array( $this->EscapeFolderName($sFolderName) // , ['(USE (\Drafts \Sent))'] RFC 6154 )); $bSubscribe && $this->FolderSubscribe($sFolderName); - return $this; } /** @@ -45,23 +60,34 @@ trait Folders * @throws \MailSo\Net\Exceptions\* * @throws \MailSo\Imap\Exceptions\* */ - public function FolderDelete(string $sFolderName) : self + public function FolderDelete(string $sFolderName) : void { + if (!$sFolderName || 'INBOX' === $sFolderName) { + throw new \InvalidArgumentException; + } + + $oInfo = $this->hasCapability('IMAP4rev2') + ? $this->FolderExamine($sFolderName) + : $this->FolderStatus($sFolderName); + if ($oInfo->MESSAGES) { + throw new \MailSo\Mail\Exceptions\NonEmptyFolder; + } + + $this->FolderUnsubscribe($sFolderName); + $this->FolderUnselect(); + // Uncomment will work issue #124 ? // $this->selectOrExamineFolder($sFolderName, true); - $this->SendRequestGetResponse('DELETE', - array($this->EscapeFolderName($sFolderName))); + $this->SendRequestGetResponse('DELETE', [$this->EscapeFolderName($sFolderName)]); // $this->FolderCheck(); -// $this->FolderUnselect(); // Will this workaround solve Dovecot issue #124 ? try { $this->FolderRename($sFolderName, "{$sFolderName}-dummy"); $this->FolderRename("{$sFolderName}-dummy", $sFolderName); - } catch (\Throwable $e) { + } catch (\Throwable $oException) { + $this->writeLogException($oException, \LOG_WARNING, false); } - - return $this; } /** @@ -70,11 +96,9 @@ trait Folders * @throws \MailSo\Net\Exceptions\* * @throws \MailSo\Imap\Exceptions\* */ - public function FolderSubscribe(string $sFolderName) : self + public function FolderSubscribe(string $sFolderName) : void { - $this->SendRequestGetResponse('SUBSCRIBE', - array($this->EscapeFolderName($sFolderName))); - return $this; + $this->SendRequestGetResponse('SUBSCRIBE', [$this->EscapeFolderName($sFolderName)]); } /** @@ -83,11 +107,9 @@ trait Folders * @throws \MailSo\Net\Exceptions\* * @throws \MailSo\Imap\Exceptions\* */ - public function FolderUnsubscribe(string $sFolderName) : self + public function FolderUnsubscribe(string $sFolderName) : void { - $this->SendRequestGetResponse('UNSUBSCRIBE', - array($this->EscapeFolderName($sFolderName))); - return $this; + $this->SendRequestGetResponse('UNSUBSCRIBE', [$this->EscapeFolderName($sFolderName)]); } /** @@ -96,12 +118,12 @@ trait Folders * @throws \MailSo\Net\Exceptions\* * @throws \MailSo\Imap\Exceptions\* */ - public function FolderRename(string $sOldFolderName, string $sNewFolderName) : self + public function FolderRename(string $sOldFolderName, string $sNewFolderName) : void { - $this->SendRequestGetResponse('RENAME', array( + $this->SendRequestGetResponse('RENAME', [ $this->EscapeFolderName($sOldFolderName), - $this->EscapeFolderName($sNewFolderName))); - return $this; + $this->EscapeFolderName($sNewFolderName) + ]); } private function FolderStatusItems() : array @@ -202,12 +224,11 @@ trait Folders * @throws \MailSo\Net\Exceptions\* * @throws \MailSo\Imap\Exceptions\* */ - public function FolderCheck() : self + public function FolderCheck() : void { if ($this->IsSelected()) { $this->SendRequestGetResponse('CHECK'); } - return $this; } /** @@ -232,7 +253,7 @@ trait Folders * @throws \MailSo\Net\Exceptions\* * @throws \MailSo\Imap\Exceptions\* */ - public function FolderUnselect() : self + public function FolderUnselect() : void { if ($this->IsSelected()) { if ($this->hasCapability('UNSELECT')) { @@ -243,14 +264,13 @@ trait Folders $this->SendRequestGetResponse('SELECT', ['""']); // * OK [CLOSED] Previous mailbox closed. // 3 NO [CANNOT] Invalid mailbox name: Name is empty - } catch (\MailSo\Imap\Exceptions\NegativeResponseException $e) { - if ('NO' === $e->GetResponseStatus()) { + } catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException) { + if ('NO' === $oException->GetResponseStatus()) { $this->oCurrentFolderInfo = null; } } } } - return $this; } /** @@ -453,8 +473,7 @@ trait Folders // $aParameters[] = $this->EscapeString(\strlen(\trim($sListPattern)) ? $sListPattern : '*'); // RFC 5819 - if ($bUseListStatus && !$bIsSubscribeList && $this->hasCapability('LIST-STATUS')) - { + if ($bUseListStatus && !$bIsSubscribeList && $this->hasCapability('LIST-STATUS')) { $aReturnParams[] = 'STATUS'; $aReturnParams[] = $this->FolderStatusItems(); } @@ -469,80 +488,71 @@ trait Folders $aParameters[] = $aReturnParams; } +/* $bPassthru = false; - $aReturn = array(); + if ($bPassthru) { + $this->SendRequest($sCmd, $aParameters); + $this->streamResponse(); + return []; + } +*/ // RFC 5464 $bMetadata = !$bIsSubscribeList && $this->hasCapability('METADATA'); - $aMetadata = null; - if ($bMetadata) { - // Dovecot supports fetching all METADATA at once - $aMetadata = $this->getAllMetadata(); - } + // Dovecot supports fetching all METADATA at once + $aMetadata = $bMetadata ? $this->getAllMetadata() : null; $this->SendRequest($sCmd, $aParameters); - if ($bPassthru) { - $this->streamResponse(); - } else { - $sDelimiter = ''; - $bInbox = false; - foreach ($this->yieldUntaggedResponses() as $oResponse) { - if ('STATUS' === $oResponse->StatusOrIndex && isset($oResponse->ResponseList[2])) { - $sFullName = $this->toUTF8($oResponse->ResponseList[2]); - if (!isset($aReturn[$sFullName])) { - $aReturn[$sFullName] = new Folder($sFullName); - } - $aReturn[$sFullName]->setStatusFromResponse($oResponse); + $aReturn = array(); + $sDelimiter = ''; + $bInbox = false; + foreach ($this->yieldUntaggedResponses() as $oResponse) { + if ('STATUS' === $oResponse->StatusOrIndex && isset($oResponse->ResponseList[2])) { + $sFullName = $this->toUTF8($oResponse->ResponseList[2]); + if (!isset($aReturn[$sFullName])) { + $aReturn[$sFullName] = new Folder($sFullName); } - else if ($sCmd === $oResponse->StatusOrIndex && 5 === \count($oResponse->ResponseList)) { - try - { - $sFullName = $this->toUTF8($oResponse->ResponseList[4]); - - /** - * $oResponse->ResponseList[0] = * - * $oResponse->ResponseList[1] = LIST (all) | LSUB (subscribed) - * $oResponse->ResponseList[2] = Flags - * $oResponse->ResponseList[3] = Delimiter - * $oResponse->ResponseList[4] = FullName - */ - if (!isset($aReturn[$sFullName])) { - $oFolder = new Folder($sFullName, - $oResponse->ResponseList[3], $oResponse->ResponseList[2]); - $aReturn[$sFullName] = $oFolder; - } else { - $oFolder = $aReturn[$sFullName]; - $oFolder->setDelimiter($oResponse->ResponseList[3]); - $oFolder->setFlags($oResponse->ResponseList[2]); - } - - if ($oFolder->IsInbox()) { - $bInbox = true; - } - - if (!$sDelimiter) { - $sDelimiter = $oFolder->Delimiter(); - } - - if (isset($aMetadata[$oResponse->ResponseList[4]])) { - $oFolder->SetAllMetadata($aMetadata[$oResponse->ResponseList[4]]); - } + $aReturn[$sFullName]->setStatusFromResponse($oResponse); + } + else if ($sCmd === $oResponse->StatusOrIndex && 5 === \count($oResponse->ResponseList)) { + try + { + $sFullName = $this->toUTF8($oResponse->ResponseList[4]); + /** + * $oResponse->ResponseList[0] = * + * $oResponse->ResponseList[1] = LIST (all) | LSUB (subscribed) + * $oResponse->ResponseList[2] = Flags + * $oResponse->ResponseList[3] = Delimiter + * $oResponse->ResponseList[4] = FullName + */ + if (isset($aReturn[$sFullName])) { + $oFolder = $aReturn[$sFullName]; + $oFolder->setDelimiter($oResponse->ResponseList[3]); + $oFolder->setFlags($oResponse->ResponseList[2]); + } else { + $oFolder = new Folder($sFullName, $oResponse->ResponseList[3], $oResponse->ResponseList[2]); $aReturn[$sFullName] = $oFolder; } - catch (\InvalidArgumentException $oException) - { - $this->writeLogException($oException, \LOG_WARNING, false); - } - catch (\Throwable $oException) - { - $this->writeLogException($oException, \LOG_WARNING, false); - } - } - } - if (!$bInbox && !$sParentFolderName && !isset($aReturn['INBOX'])) { - $aReturn['INBOX'] = new Folder('INBOX', $sDelimiter); + if ($oFolder->IsInbox()) { + $bInbox = true; + } + + if (!$sDelimiter) { + $sDelimiter = $oFolder->Delimiter(); + } + + if (isset($aMetadata[$oResponse->ResponseList[4]])) { + $oFolder->SetAllMetadata($aMetadata[$oResponse->ResponseList[4]]); + } + + $aReturn[$sFullName] = $oFolder; + } + catch (\Throwable $oException) + { + $this->writeLogException($oException, \LOG_WARNING, false); + } } } @@ -554,12 +564,16 @@ trait Folders $oFolder->SetAllMetadata( $this->getMetadata($oFolder->FullName(), ['/shared', '/private'], ['DEPTH'=>'infinity']) ); - } catch (\Throwable $e) { + } catch (\Throwable $oException) { // Ignore error } } } + if (!$bInbox && !$sParentFolderName && !isset($aReturn['INBOX'])) { + $aReturn['INBOX'] = new Folder('INBOX', $sDelimiter); + } + return $aReturn; } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Messages.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Messages.php index 382283b45..93fe5b7c5 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Messages.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Messages.php @@ -16,7 +16,9 @@ use MailSo\Imap\FetchResponse; use MailSo\Imap\Enumerations\FetchType; use MailSo\Imap\ResponseCollection; use MailSo\Imap\SequenceSet; +use MailSo\Imap\Enumerations\MessageFlag; use MailSo\Imap\Enumerations\ResponseType; +use MailSo\Imap\Enumerations\StoreAction; /** * @category MailSo @@ -32,8 +34,7 @@ trait Messages */ public function Fetch(array $aInputFetchItems, string $sIndexRange, bool $bIndexIsUid) : array { - if (!\strlen(\trim($sIndexRange))) - { + if (!\strlen(\trim($sIndexRange))) { $this->writeLogException(new \InvalidArgumentException, \LOG_ERR); } @@ -44,8 +45,7 @@ trait Messages FetchType::UID, FetchType::RFC822_SIZE ); - foreach ($aInputFetchItems as $mFetchKey) - { + foreach ($aInputFetchItems as $mFetchKey) { switch ($mFetchKey) { case FetchType::UID: @@ -196,12 +196,14 @@ trait Messages * @throws \MailSo\Net\Exceptions\* * @throws \MailSo\Imap\Exceptions\* */ - public function MessageCopy(string $sToFolder, SequenceSet $oRange) : ResponseCollection + public function MessageCopy(string $sFromFolder, string $sToFolder, SequenceSet $oRange) : ResponseCollection { - if (!\count($oRange)) { + if (!$sFromFolder || !$sToFolder || !\count($oRange)) { $this->writeLogException(new \InvalidArgumentException, \LOG_ERR); } + $this->FolderSelect($sFromFolder); + return $this->SendRequestGetResponse( $oRange->UID ? 'UID COPY' : 'COPY', array((string) $oRange, $this->EscapeFolderName($sToFolder)) @@ -214,20 +216,48 @@ trait Messages * @throws \MailSo\Net\Exceptions\* * @throws \MailSo\Imap\Exceptions\* */ - public function MessageMove(string $sToFolder, SequenceSet $oRange) : ResponseCollection + public function MessageMove(string $sFromFolder, string $sToFolder, SequenceSet $oRange) : ResponseCollection { - if (!\count($oRange)) { + if (!$sFromFolder || !$sToFolder || !\count($oRange)) { $this->writeLogException(new \InvalidArgumentException, \LOG_ERR); } - if (!$this->hasCapability('MOVE')) { - $this->writeLogException(new \MailSo\RuntimeException('Move is not supported'), \LOG_ERR); + if ($this->hasCapability('MOVE')) { + $this->FolderSelect($sFromFolder); + return $this->SendRequestGetResponse( + $oRange->UID ? 'UID MOVE' : 'MOVE', + array((string) $oRange, $this->EscapeFolderName($sToFolder)) + ); } - return $this->SendRequestGetResponse( - $oRange->UID ? 'UID MOVE' : 'MOVE', - array((string) $oRange, $this->EscapeFolderName($sToFolder)) + $this->MessageCopy($sFromFolder, $sToFolder, $oRange); + $this->MessageDelete($sFromFolder, $oRange, true); + } + + /** + * @throws \InvalidArgumentException + * @throws \MailSo\RuntimeException + * @throws \MailSo\Net\Exceptions\* + * @throws \MailSo\Imap\Exceptions\* + */ + public function MessageDelete(string $sFolder, SequenceSet $oRange, bool $bExpungeAll = false) : void + { + if (!$sFolder || !\count($oRange)) { + $this->writeLogException(new \InvalidArgumentException, \LOG_ERR); + } + + $this->FolderSelect($sFolder); + + $this->MessageStoreFlag($oRange, + array(MessageFlag::DELETED), + StoreAction::ADD_FLAGS_SILENT ); + + if ($bExpungeAll && $this->Settings->expunge_all_on_delete) { + $this->FolderExpunge(); + } else { + $this->FolderExpunge($oRange); + } } /** @@ -250,8 +280,8 @@ trait Messages if ($iUid) { $oRange = new SequenceSet([$iUid]); $this->MessageStoreFlag($oRange, - array(\MailSo\Imap\Enumerations\MessageFlag::DELETED), - \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT + array(MessageFlag::DELETED), + StoreAction::ADD_FLAGS_SILENT ); $this->FolderExpunge($oRange); } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Metadata.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Metadata.php index 1ed762303..b2fd84216 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Metadata.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Metadata.php @@ -126,4 +126,8 @@ trait Metadata } } + public function FolderRemoveMetadata($sFolderName, array $aEntries) : void + { + $this->FolderSetMetadata($sFolderName, \array_fill_keys(\array_keys($aEntries), null)); + } } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Folder.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Folder.php index f95e22619..f6449fcf7 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Folder.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Folder.php @@ -172,7 +172,7 @@ class Folder implements \JsonSerializable 'totalEmails' => (int) $this->MESSAGES, 'unreadEmails' => (int) $this->UNSEEN, 'UidNext' => (int) $this->UIDNEXT, -// 'Hash' => $this->Hash($this->MailClient()->GenerateImapClientHash()) +// 'Hash' => $this->Hash($this->ImapClient()->Hash()) ); } */ diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php index d470d88a3..9e67065d4 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php @@ -53,6 +53,15 @@ class ImapClient extends \MailSo\Net\NetClient private bool $UTF8 = false; + public function Hash() : string + { + return \md5('ImapClientHash/'. + $this->GetLogginedUser() . '@' . + $this->GetConnectedHost() . ':' . + $this->GetConnectedPort() + ); + } + public function GetLogginedUser() : string { return $this->sLogginedUser; @@ -379,6 +388,12 @@ class ImapClient extends \MailSo\Net\NetClient } } + public function GetPersonalNamespace() : string + { + $oNamespace = $this->GetNamespace(); + return $oNamespace ? $oNamespace->GetPersonalNamespace() : ''; + } + /** * RFC 7889 * APPENDLIMIT= indicates that the IMAP server has the same upload limit for all mailboxes. diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Attachment.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Attachment.php index 2dd75e7eb..2f3f5635a 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Attachment.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Attachment.php @@ -11,30 +11,25 @@ namespace MailSo\Mail; +use MailSo\Imap\BodyStructure; + /** * @category MailSo * @package Mail */ class Attachment implements \JsonSerializable { - /** - * @var string - */ - private $sFolder; + private string $sFolder; - /** - * @var int - */ - private $iUid; + private int $iUid; - /** - * @var \MailSo\Imap\BodyStructure - */ - private $oBodyStructure; + private ?BodyStructure $oBodyStructure; - function __construct() + function __construct(string $sFolder, int $iUid, BodyStructure $oBodyStructure) { - $this->Clear(); + $this->sFolder = $sFolder; + $this->iUid = $iUid; + $this->oBodyStructure = $oBodyStructure; } public function Clear() : self @@ -56,11 +51,6 @@ class Attachment implements \JsonSerializable return $this->iUid; } - public function MimeIndex() : string - { - return $this->oBodyStructure ? $this->oBodyStructure->PartID() : ''; - } - public function FileName(bool $bCalculateOnEmpty = false) : string { if (!$this->oBodyStructure) { @@ -72,9 +62,9 @@ class Attachment implements \JsonSerializable return $sFileName; } - $sIdx = '-' . $this->MimeIndex(); + $sIdx = '-' . $this->oBodyStructure->PartID(); - $sMimeType = \strtolower(\trim($this->MimeType())); + $sMimeType = \strtolower(\trim($this->oBodyStructure->ContentType())); if ('message/rfc822' === $sMimeType) { return "message{$sIdx}.eml"; } @@ -95,72 +85,9 @@ class Attachment implements \JsonSerializable return ($this->oBodyStructure->IsInline() ? 'inline' : 'part' ) . $sIdx; } - public function MimeType() : string + public function __call(string $name, array $arguments) //: mixed { - return $this->oBodyStructure ? $this->oBodyStructure->ContentType() : ''; - } - - public function EncodedSize() : int - { - return $this->oBodyStructure ? $this->oBodyStructure->Size() : 0; - } - - public function EstimatedSize() : int - { - return $this->oBodyStructure ? $this->oBodyStructure->EstimatedSize() : 0; - } - - public function Cid() : string - { - return $this->oBodyStructure ? $this->oBodyStructure->ContentID() : ''; - } - - public function ContentLocation() : string - { - return $this->oBodyStructure ? $this->oBodyStructure->ContentLocation() : ''; - } - - public function IsInline() : bool - { - return $this->oBodyStructure ? $this->oBodyStructure->IsInline() : false; - } - - public function IsImage() : bool - { - return $this->oBodyStructure ? $this->oBodyStructure->IsImage() : false; - } - - public function IsArchive() : bool - { - return $this->oBodyStructure ? $this->oBodyStructure->IsArchive() : false; - } - - public function IsPdf() : bool - { - return $this->oBodyStructure ? $this->oBodyStructure->IsPdf() : false; - } - - public function IsDoc() : bool - { - return $this->oBodyStructure ? $this->oBodyStructure->IsDoc() : false; - } - - public function IsPgpSignature() : bool - { - return $this->oBodyStructure ? $this->oBodyStructure->IsPgpSignature() : false; - } - - public static function NewBodyStructureInstance(string $sFolder, int $iUid, \MailSo\Imap\BodyStructure $oBodyStructure) : self - { - return (new self)->InitByBodyStructure($sFolder, $iUid, $oBodyStructure); - } - - public function InitByBodyStructure(string $sFolder, int $iUid, \MailSo\Imap\BodyStructure $oBodyStructure) : self - { - $this->sFolder = $sFolder; - $this->iUid = $iUid; - $this->oBodyStructure = $oBodyStructure; - return $this; + return $this->oBodyStructure->{$name}(...$arguments); } #[\ReturnTypeWillChange] @@ -168,15 +95,15 @@ class Attachment implements \JsonSerializable { return array( '@Object' => 'Object/Attachment', - 'Folder' => $this->Folder(), - 'Uid' => (string) $this->Uid(), - 'MimeIndex' => (string) $this->MimeIndex(), - 'MimeType' => $this->MimeType(), - 'FileName' => \MailSo\Base\Utils::SecureFileName($this->FileName(true)), - 'EstimatedSize' => $this->EstimatedSize(), - 'Cid' => $this->Cid(), - 'ContentLocation' => $this->ContentLocation(), - 'IsInline' => $this->IsInline() + 'Folder' => $this->sFolder, + 'Uid' => (string) $this->iUid, + 'MimeIndex' => (string) $this->oBodyStructure->PartID(), + 'MimeType' => $this->oBodyStructure->ContentType(), + 'FileName' => \MailSo\Base\Utils::SecureFileName($this->oBodyStructure->FileName(true)), + 'EstimatedSize' => $this->oBodyStructure->EstimatedSize(), + 'Cid' => $this->oBodyStructure->ContentID(), + 'ContentLocation' => $this->oBodyStructure->ContentLocation(), + 'IsInline' => $this->oBodyStructure->IsInline() ); } } 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 c3f5f78f0..f45b3dd32 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 @@ -121,8 +121,7 @@ class MailClient */ public function Message(string $sFolderName, int $iIndex, bool $bIndexIsUid = true, ?\MailSo\Cache\CacheClient $oCacher = null) : ?Message { - if (!\MailSo\Base\Validator::RangeInt($iIndex, 1)) - { + if (1 > $iIndex) { throw new \InvalidArgumentException; } @@ -143,13 +142,10 @@ class MailClient $iBodyTextLimit = $this->oImapClient->Settings->body_text_limit; $aFetchResponse = $this->oImapClient->Fetch(array(FetchType::BODYSTRUCTURE), $iIndex, $bIndexIsUid); - if (\count($aFetchResponse) && isset($aFetchResponse[0])) - { + if (\count($aFetchResponse) && isset($aFetchResponse[0])) { $oBodyStructure = $aFetchResponse[0]->GetFetchBodyStructure(); - if ($oBodyStructure) - { - foreach ($oBodyStructure->GetHtmlAndPlainParts() as $oPart) - { + if ($oBodyStructure) { + foreach ($oBodyStructure->GetHtmlAndPlainParts() as $oPart) { $sLine = FetchType::BODY_PEEK.'['.$oPart->PartID().']'; if (0 < $iBodyTextLimit && $iBodyTextLimit < $oPart->Size()) { $sLine .= "<0.{$iBodyTextLimit}>"; @@ -171,15 +167,13 @@ class MailClient } } - if (!$oBodyStructure) - { + if (!$oBodyStructure) { $aFetchItems[] = FetchType::BODYSTRUCTURE; } $aFetchResponse = $this->oImapClient->Fetch($aFetchItems, $iIndex, $bIndexIsUid); - if (\count($aFetchResponse)) - { - $oMessage = Message::NewFetchResponseInstance($sFolderName, $aFetchResponse[0], $oBodyStructure); + if (\count($aFetchResponse)) { + $oMessage = Message::fromFetchResponse($sFolderName, $aFetchResponse[0], $oBodyStructure); } return $oMessage; @@ -197,8 +191,7 @@ class MailClient */ public function MessageMimeStream($mCallback, string $sFolderName, int $iIndex, string $sMimeIndex) : bool { - if (!\is_callable($mCallback)) - { + if (!\is_callable($mCallback)) { throw new \InvalidArgumentException; } @@ -216,20 +209,17 @@ class MailClient : FetchType::BODY_HEADER_PEEK), $iIndex, true); - if (\count($aFetchResponse)) - { + if (\count($aFetchResponse)) { $sMime = $aFetchResponse[0]->GetFetchValue( \strlen($sMimeIndex) ? FetchType::BODY.'['.$sMimeIndex.'.MIME]' : FetchType::BODY_HEADER ); - if (\strlen($sMime)) - { + if (\strlen($sMime)) { $oHeaders = new \MailSo\Mime\HeaderCollection($sMime); - if (\strlen($sMimeIndex)) - { + if (\strlen($sMimeIndex)) { $sFileName = $oHeaders->ParameterValue(MimeHeader::CONTENT_DISPOSITION, MimeParameter::FILENAME); if (!\strlen($sFileName)) { $sFileName = $oHeaders->ParameterValue(MimeHeader::CONTENT_TYPE, MimeParameter::NAME); @@ -247,9 +237,7 @@ class MailClient } $sContentType = $oHeaders->ValueByName(MimeHeader::CONTENT_TYPE); - } - else - { + } else { $sFileName = ($oHeaders->ValueByName(MimeHeader::SUBJECT) ?: $iIndex) . '.eml'; $sContentType = 'message/rfc822'; @@ -264,8 +252,7 @@ class MailClient $sPeek.'['.$sMimeIndex.']', function ($sParent, $sLiteralAtomUpperCase, $rImapLiteralStream) use ($mCallback, $sMimeIndex, $sMailEncoding, $sContentType, $sFileName) { - if (\strlen($sLiteralAtomUpperCase) && \is_resource($rImapLiteralStream) && 'FETCH' === $sParent) - { + if (\strlen($sLiteralAtomUpperCase) && \is_resource($rImapLiteralStream) && 'FETCH' === $sParent) { $mCallback($sMailEncoding ? \MailSo\Base\StreamWrappers\Binary::CreateStream($rImapLiteralStream, $sMailEncoding) : $rImapLiteralStream, @@ -277,93 +264,6 @@ class MailClient return ($aFetchResponse && 1 === \count($aFetchResponse)); } - /** - * @throws \InvalidArgumentException - * @throws \MailSo\RuntimeException - * @throws \MailSo\Net\Exceptions\* - * @throws \MailSo\Imap\Exceptions\* - */ - public function MessageDelete(string $sFolder, SequenceSet $oRange, bool $bExpungeAll = false) : self - { - if (!\strlen($sFolder) || !\count($oRange)) - { - throw new \InvalidArgumentException; - } - - $this->oImapClient->FolderSelect($sFolder); - - $this->oImapClient->MessageStoreFlag($oRange, - array(MessageFlag::DELETED), - StoreAction::ADD_FLAGS_SILENT - ); - - if ($bExpungeAll && $this->oImapClient->Settings->expunge_all_on_delete) { - $this->oImapClient->FolderExpunge(); - } else { - $this->oImapClient->FolderExpunge($oRange); - } - - return $this; - } - - /** - * @throws \InvalidArgumentException - * @throws \MailSo\RuntimeException - * @throws \MailSo\Net\Exceptions\* - * @throws \MailSo\Imap\Exceptions\* - */ - public function MessageMove(string $sFromFolder, string $sToFolder, SequenceSet $oRange) : self - { - if (!$sFromFolder || !$sToFolder || !\count($oRange)) { - throw new \InvalidArgumentException; - } - - $this->oImapClient->FolderSelect($sFromFolder); - - if ($this->oImapClient->hasCapability('MOVE')) { - $this->oImapClient->MessageMove($sToFolder, $oRange); - } else { - $this->oImapClient->MessageCopy($sToFolder, $oRange); - $this->MessageDelete($sFromFolder, $oRange, true); - } - - return $this; - } - - /** - * @throws \InvalidArgumentException - * @throws \MailSo\RuntimeException - * @throws \MailSo\Net\Exceptions\* - * @throws \MailSo\Imap\Exceptions\* - */ - public function MessageCopy(string $sFromFolder, string $sToFolder, SequenceSet $oRange) : self - { - if (!$sFromFolder || !$sToFolder || !\count($oRange)) - { - throw new \InvalidArgumentException; - } - - $this->oImapClient->FolderSelect($sFromFolder); - $this->oImapClient->MessageCopy($sToFolder, $oRange); - - return $this; - } - - /** - * @throws \MailSo\RuntimeException - * @throws \MailSo\Net\Exceptions\* - * @throws \MailSo\Imap\Exceptions\* - */ - public function FolderUnselect() : self - { - if ($this->oImapClient->IsSelected()) - { - $this->oImapClient->FolderUnselect(); - } - - return $this; - } - /** * @param resource $rMessageStream */ @@ -382,8 +282,7 @@ class MailClient public function MessageAppendFile(string $sMessageFileName, string $sFolderToSave, array $aAppendFlags = null, int &$iUid = null) : self { - if (!\is_file($sMessageFileName) || !\is_readable($sMessageFileName)) - { + if (!\is_file($sMessageFileName) || !\is_readable($sMessageFileName)) { throw new \InvalidArgumentException; } @@ -392,23 +291,13 @@ class MailClient $this->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags, $iUid); - if (\is_resource($rMessageStream)) - { - fclose($rMessageStream); + if (\is_resource($rMessageStream)) { + \fclose($rMessageStream); } return $this; } - public function GenerateImapClientHash() : string - { - return \md5('ImapClientHash/'. - $this->oImapClient->GetLogginedUser() . '@' . - $this->oImapClient->GetConnectedHost() . ':' . - $this->oImapClient->GetConnectedPort() - ); - } - /** * Returns list of new messages since $iPrevUidNext * Currently only for INBOX @@ -496,7 +385,7 @@ class MailClient 'MailboxId' => $oInfo->MAILBOXID ?: '', // 'Flags' => $oInfo->Flags, // 'PermanentFlags' => $oInfo->PermanentFlags, - 'Hash' => $oInfo->getHash($this->GenerateImapClientHash()), + 'Hash' => $oInfo->getHash($this->oImapClient->Hash()), 'MessagesFlags' => $aFlags, 'NewMessages' => $this->getFolderNextMessageInformation( $sFolderName, @@ -514,7 +403,7 @@ class MailClient */ public function FolderHash(string $sFolderName) : string { - return $this->oImapClient->FolderStatus($sFolderName)->getHash($this->GenerateImapClientHash()); + return $this->oImapClient->FolderStatus($sFolderName)->getHash($this->oImapClient->Hash()); } /** @@ -572,14 +461,12 @@ class MailClient unset($oException); } - if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHashKey)) - { + if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHashKey)) { $oCacher->Set($sSerializedHashKey, \json_encode(array( 'ThreadsUids' => $aResult ))); - if ($this->oLogger) - { + if ($this->oLogger) { $this->oLogger->Write('Save Serialized Thread UIDS to cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aResult).']'); } } @@ -594,8 +481,7 @@ class MailClient */ protected function MessageListByRequestIndexOrUids(MessageCollection $oMessageCollection, SequenceSet $oRange) : void { - if (\count($oRange)) - { + if (\count($oRange)) { $aFetchResponse = $this->oImapClient->Fetch(array( FetchType::UID, FetchType::RFC822_SIZE, @@ -605,14 +491,13 @@ class MailClient $this->getEnvelopeOrHeadersRequestString() ), (string) $oRange, $oRange->UID); - if (\count($aFetchResponse)) - { + if (\count($aFetchResponse)) { $aCollection = \array_fill_keys($oRange->getArrayCopy(), null); foreach ($aFetchResponse as /* @var $oFetchResponseItem \MailSo\Imap\FetchResponse */ $oFetchResponseItem) { $id = $oRange->UID ? $oFetchResponseItem->GetFetchValue(FetchType::UID) : $oFetchResponseItem->oImapResponse->ResponseList[1]; - $aCollection[$id] = Message::NewFetchResponseInstance($oMessageCollection->FolderName, $oFetchResponseItem); + $aCollection[$id] = Message::fromFetchResponse($oMessageCollection->FolderName, $oFetchResponseItem); } $oMessageCollection->exchangeArray(\array_values(\array_filter($aCollection))); } @@ -686,7 +571,7 @@ class MailClient if ($bUseCacheAfterSearch) { $sSerializedHash = 'GetUids/'. ($bUseSortIfSupported ? 'S' . $sSort : 'N').'/'. - $this->GenerateImapClientHash().'/'. + $this->oImapClient->Hash().'/'. $sFolderName.'/'.$sSearchCriterias; $sSerializedLog = '"'.$sFolderName.'" / '.$sSearchCriterias.''; @@ -742,9 +627,7 @@ class MailClient */ public function MessageList(MessageListParams $oParams) : MessageCollection { - if (!\MailSo\Base\Validator::RangeInt($oParams->iOffset, 0) || - !\MailSo\Base\Validator::RangeInt($oParams->iLimit, 0, 999)) - { + if (0 > $oParams->iOffset || 0 > $oParams->iLimit || 999 < $oParams->iLimit) { throw new \InvalidArgumentException; } @@ -773,7 +656,7 @@ class MailClient $oParams->oCacher = null; } - $oMessageCollection->FolderHash = $oInfo->getHash($this->GenerateImapClientHash()); + $oMessageCollection->FolderHash = $oInfo->getHash($this->oImapClient->Hash()); if (!$oParams->iThreadUid) { $oMessageCollection->NewMessages = $this->getFolderNextMessageInformation( @@ -893,8 +776,7 @@ class MailClient public function FindMessageUidByMessageId(string $sFolderName, string $sMessageId) : ?int { - if (!\strlen($sMessageId)) - { + if (!\strlen($sMessageId)) { throw new \InvalidArgumentException; } @@ -927,7 +809,7 @@ class MailClient } } -// $this->oImapClient->Settings->disable_list_status +// $this->oImapClient->Settings->disable_list_status $aFolders = $this->oImapClient->FolderStatusList($sParent, $sListPattern); if (!$aFolders) { return null; @@ -976,12 +858,12 @@ class MailClient } } +/* // Allow non existent parent folders if (\strlen($sDelimiter) && false !== \strpos($sFolderNameInUtf8, $sDelimiter)) { // TODO: Translate - throw new \MailSo\RuntimeException( - 'New folder name contains delimiter.'); + throw new \MailSo\RuntimeException('New folder name contains delimiter.'); } - +*/ $sFullNameToCreate = $sFolderParentFullName.$sFolderNameInUtf8; $this->oImapClient->FolderCreate($sFullNameToCreate, $bSubscribeOnCreation); @@ -1039,92 +921,33 @@ class MailClient */ protected function folderModify(string $sPrevFolderFullName, string $sNewFolderFullName, bool $bSubscribe) : self { - if (!\strlen($sPrevFolderFullName) || !\strlen($sNewFolderFullName)) - { + if (!\strlen($sPrevFolderFullName) || !\strlen($sNewFolderFullName)) { throw new \InvalidArgumentException; } $aSubscribeFolders = array(); - if ($bSubscribe) - { + if ($bSubscribe) { $aSubscribeFolders = $this->oImapClient->FolderSubscribeList($sPrevFolderFullName, '*'); - foreach ($aSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) - { + foreach ($aSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) { $this->oImapClient->FolderUnsubscribe($oFolder->FullName()); } } $this->oImapClient->FolderRename($sPrevFolderFullName, $sNewFolderFullName); - foreach ($aSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) - { - $sFolderFullNameForResubscrine = $oFolder->FullName(); - if (0 === \strpos($sFolderFullNameForResubscrine, $sPrevFolderFullName)) - { - $sNewFolderFullNameForResubscrine = $sNewFolderFullName. - \substr($sFolderFullNameForResubscrine, \strlen($sPrevFolderFullName)); + foreach ($aSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder) { + $sFolderFullNameForResubscribe = $oFolder->FullName(); + if (\str_starts_with($sFolderFullNameForResubscribe, $sPrevFolderFullName)) { + $sNewFolderFullNameForResubscribe = $sNewFolderFullName. + \substr($sFolderFullNameForResubscribe, \strlen($sPrevFolderFullName)); - $this->oImapClient->FolderSubscribe($sNewFolderFullNameForResubscrine); + $this->oImapClient->FolderSubscribe($sNewFolderFullNameForResubscribe); } } return $this; } - /** - * @throws \InvalidArgumentException - * @throws \MailSo\RuntimeException - */ - public function FolderDelete(string $sFolderFullName) : self - { - if (!\strlen($sFolderFullName) || 'INBOX' === $sFolderFullName) { - throw new \InvalidArgumentException; - } - - if ($this->oImapClient->hasCapability('IMAP4rev2')) { - $oInfo = $this->oImapClient->FolderExamine($sFolderFullName); - } else { - $oInfo = $this->oImapClient->FolderStatus($sFolderFullName); - } - if ($oInfo->MESSAGES) { - throw new Exceptions\NonEmptyFolder; - } - - $this->oImapClient->FolderUnsubscribe($sFolderFullName); - - $this->oImapClient->FolderUnselect(); - $this->oImapClient->FolderDelete($sFolderFullName); - - return $this; - } - - /** - * @throws \InvalidArgumentException - */ - public function FolderClear(string $sFolderFullName) : self - { - if (0 < $this->oImapClient->FolderSelect($sFolderFullName)->MESSAGES) { - $this->oImapClient->MessageStoreFlag(new SequenceSet('1:*', false), - array(MessageFlag::DELETED), - StoreAction::ADD_FLAGS_SILENT - ); - $this->oImapClient->FolderExpunge(); - } - return $this; - } - - /** - * @throws \InvalidArgumentException - */ - public function FolderSubscribe(string $sFolderFullName, bool $bSubscribe) : self - { - if (!\strlen($sFolderFullName)) { - throw new \InvalidArgumentException; - } - $this->oImapClient->{$bSubscribe ? 'FolderSubscribe' : 'FolderUnsubscribe'}($sFolderFullName); - return $this; - } - /** * @throws \InvalidArgumentException */ @@ -1134,23 +957,8 @@ class MailClient $this->oImapClient->SetLogger($oLogger); } - public function GetPersonalNamespace() : string - { - $oNamespace = $this->oImapClient->GetNamespace(); - return $oNamespace ? $oNamespace->GetPersonalNamespace() : ''; - } - public function __call(string $name, array $arguments) /*: mixed*/ { return $this->oImapClient->{$name}(...$arguments); } - - /** - * RFC 5464 - */ - - public function FolderDeleteMetadata($sFolderName, array $aEntries) : void - { - $this->oImapClient->FolderSetMetadata($sFolderName, \array_fill_keys(\array_keys($aEntries), null)); - } } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Message.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Message.php index daa2d177e..19ebc64e9 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Message.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Message.php @@ -281,7 +281,7 @@ class Message implements \JsonSerializable $this->aThreads = $aThreads; } - public static function NewFetchResponseInstance(string $sFolder, \MailSo\Imap\FetchResponse $oFetchResponse, ?\MailSo\Imap\BodyStructure $oBodyStructure = null) : self + public static function fromFetchResponse(string $sFolder, \MailSo\Imap\FetchResponse $oFetchResponse, ?\MailSo\Imap\BodyStructure $oBodyStructure = null) : self { $oMessage = new self; @@ -625,7 +625,7 @@ class Message implements \JsonSerializable { // if ('application/pgp-keys' === $oAttachmentItem->ContentType()) import ??? $oMessage->oAttachments->append( - Attachment::NewBodyStructureInstance($oMessage->sFolder, $oMessage->iUid, $oAttachmentItem) + new Attachment($oMessage->sFolder, $oMessage->iUid, $oAttachmentItem) ); } } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MessageListParams.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MessageListParams.php index c8e929860..ab24db51a 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MessageListParams.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MessageListParams.php @@ -38,7 +38,8 @@ class MessageListParams if ('i' === $k[0]) { $this->$k = \max(0, (int) $v); } -// \MailSo\Base\Validator::RangeInt($oParams->iOffset, 0) -// \MailSo\Base\Validator::RangeInt($oParams->iLimit, 0, 999) +// 0 > $oParams->iOffset +// 0 > $oParams->iLimit +// 999 < $oParams->iLimit } } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php index 08af152f9..e1e933899 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php @@ -87,7 +87,7 @@ abstract class NetClient public function Connect(ConnectSettings $oSettings) : void { $oSettings->host = \trim($oSettings->host); - if (!\strlen($oSettings->host) || !\MailSo\Base\Validator::RangeInt($oSettings->port, 0, 65535)) { + if (!\strlen($oSettings->host) || 0 > $oSettings->port || 65535 < $oSettings->port) { $this->writeLogException(new \MailSo\Base\Exceptions\InvalidArgumentException, \LOG_ERR); } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/SieveClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/SieveClient.php index a68ab016e..a6b54b283 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/SieveClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/SieveClient.php @@ -392,8 +392,7 @@ class SieveClient extends \MailSo\Net\NetClient private function parseResponse() : array { $aResult = array(); - do - { + while (true) { $sResponseBuffer = $this->getNextBuffer(); if (null === $sResponseBuffer) { break; @@ -418,7 +417,6 @@ class SieveClient extends \MailSo\Net\NetClient break; } } - while (true); if (!$aResult || 'OK' !== \substr($aResult[\array_key_last($aResult)], 0, 2)) { $this->writeLogException(new \MailSo\Sieve\Exceptions\NegativeResponseException($aResult), \LOG_WARNING); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Folders.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Folders.php index d68769976..345d565a6 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Folders.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Folders.php @@ -125,7 +125,7 @@ trait Folders try { - $this->MailClient()->FolderSubscribe($sFolderFullName, $bSubscribe); + $this->MailClient()->{$bSubscribe ? 'FolderSubscribe' : 'FolderUnsubscribe'}($sFolderFullName); } catch (\Throwable $oException) { 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 71e4b8f20..3d4dd775f 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,7 +250,7 @@ trait Response { $aResult = $mResponse->jsonSerialize(); - $sHash = $mResponse->Hash($this->MailClient()->GenerateImapClientHash()); + $sHash = $mResponse->Hash($this->MailClient()->ImapClient()->Hash()); if ($sHash) { $aResult['Hash'] = $sHash; }