From 304c67534bf3cb7b17fbb8a794c1914f6df146a5 Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Tue, 13 Feb 2024 02:05:38 +0100 Subject: [PATCH] Added: support all namespaces --- .../MailSo/Imap/Commands/Folders.php | 6 +- .../MailSo/Imap/Commands/Metadata.php | 45 ++++++----- .../app/libraries/MailSo/Imap/ImapClient.php | 14 +--- .../libraries/MailSo/Imap/NamespaceResult.php | 79 +++++++++++++------ .../libraries/RainLoop/Actions/Folders.php | 20 ++++- 5 files changed, 102 insertions(+), 62 deletions(-) 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 b53209e72..311e7358d 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 @@ -574,8 +574,8 @@ trait Folders } } } - - // ACL RIGHTS=texk +/* + // RFC 4314 if ($this->hasCapability('ACL') || $this->CapabilityValue('RIGHTS')) { foreach ($oFolderCollection as $oFolder) { if ($oFolder->Selectable()) try { @@ -586,7 +586,7 @@ trait Folders } } } - +*/ if (!$bInbox && !$sParentFolderName && !isset($oFolderCollection['INBOX'])) { $oFolderCollection['INBOX'] = new Folder('INBOX', $sDelimiter); } 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 a1895f950..43b147fef 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 @@ -24,33 +24,36 @@ trait Metadata * Dovecot 2.2+ supports fetching all METADATA at once (wildcard). * RFC 5464 doesn't specify this, but its earlier draft did, and Kolab uses it. */ + private ?array $allMetadata = null; public function getAllMetadata() : array { - $aReturn = array(); - try { - $arguments = [ - '(DEPTH infinity)', - $this->EscapeString('*') - ]; - $arguments[] = '(' . \implode(' ', \array_map([$this, 'EscapeString'], ['/shared', '/private'])) . ')'; - $this->SendRequest('GETMETADATA', $arguments); - foreach ($this->yieldUntaggedResponses() as $oResponse) { - if (isset($oResponse->ResponseList[3]) - && \is_array($oResponse->ResponseList[3]) - && 'METADATA' === $oResponse->ResponseList[1] - ) { - $aMetadata = array(); - $c = \count($oResponse->ResponseList[3]); - for ($i = 0; $i < $c; $i += 2) { - $aMetadata[$oResponse->ResponseList[3][$i]] = $oResponse->ResponseList[3][$i+1]; + if (null === $this->allMetadata) { + $this->allMetadata = array(); + try { + $arguments = [ + '(DEPTH infinity)', + $this->EscapeString('*') + ]; + $arguments[] = '(' . \implode(' ', \array_map([$this, 'EscapeString'], ['/shared', '/private'])) . ')'; + $this->SendRequest('GETMETADATA', $arguments); + foreach ($this->yieldUntaggedResponses() as $oResponse) { + if (isset($oResponse->ResponseList[3]) + && \is_array($oResponse->ResponseList[3]) + && 'METADATA' === $oResponse->ResponseList[1] + ) { + $aMetadata = array(); + $c = \count($oResponse->ResponseList[3]); + for ($i = 0; $i < $c; $i += 2) { + $aMetadata[$oResponse->ResponseList[3][$i]] = $oResponse->ResponseList[3][$i+1]; + } + $this->allMetadata[$this->toUTF8($oResponse->ResponseList[2])] = $aMetadata; } - $aReturn[$this->toUTF8($oResponse->ResponseList[2])] = $aMetadata; } + } catch (\Throwable $e) { + //\SnappyMail\Log::warning('IMAP', $e->getMessage()); } - } catch (\Throwable $e) { - //\SnappyMail\Log::warning('IMAP', $e->getMessage()); } - return $aReturn; + return $this->allMetadata; } public function getMetadata(string $sFolderName, array $aEntries, array $aOptions = []) : array 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 5323de692..fcf2f9e79 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 @@ -363,7 +363,7 @@ class ImapClient extends \MailSo\Net\NetClient * @throws \MailSo\Net\Exceptions\* * @throws \MailSo\Imap\Exceptions\* */ - public function GetNamespace() : ?NamespaceResult + public function GetNamespaces() : ?NamespaceResult { if (!$this->hasCapability('NAMESPACE')) { return null; @@ -384,17 +384,6 @@ class ImapClient extends \MailSo\Net\NetClient } } - public function GetPrivateNamespace() : string - { - $oNamespace = $this->GetNamespace(); - return $oNamespace ? $oNamespace->GetPrivateNamespace() : ''; - } - /** Deprecated */ - public function GetPersonalNamespace() : string - { - return $this->GetPrivateNamespace(); - } - /** * RFC 7889 * APPENDLIMIT= indicates that the IMAP server has the same upload limit for all mailboxes. @@ -523,6 +512,7 @@ class ImapClient extends \MailSo\Net\NetClient if ($oResponse->IsStatusResponse && Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType && Enumerations\ResponseStatus::PREAUTH === $oResponse->StatusOrIndex +// && (Enumerations\ResponseStatus::PREAUTH === $oResponse->StatusOrIndex || Enumerations\ResponseStatus::BYE === $oResponse->StatusOrIndex) ) { break; } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/NamespaceResult.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/NamespaceResult.php index 73ad92e89..f92b39a80 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/NamespaceResult.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/NamespaceResult.php @@ -15,42 +15,71 @@ namespace MailSo\Imap; * @category MailSo * @package Imap */ -class NamespaceResult +class NamespaceResult implements \JsonSerializable { - // prefix => separator - private array $namespaces = [ -// '' => '.', // default -// 'virtual.' => '.', -// 'shared.' => '.', -// etc. - ]; + public array + $aPersonal = [], + $aOtherUsers = [], + $aShared = []; function __construct(Response $oImapResponse) { - // * NAMESPACE (("" ".")("virtual." ".")) (("shared." ".")) NIL\r\n - $i = 1; - while (isset($oImapResponse->ResponseList[++$i])) { - $entries = $oImapResponse->ResponseList[$i]; - if ($entries) { - foreach ($entries as $entry) { - if (\is_array($entry) && 2 <= \count($entry)) { - $this->namespaces[$entry[0]] = $entry[1]; - } + if (!empty($oImapResponse->ResponseList[2])) { + foreach ($oImapResponse->ResponseList[2] as $entry) { + if (\is_array($entry) && 2 <= \count($entry)) { + $this->aPersonal[] = [ + 'prefix' => \array_shift($entry), + 'separator' => \array_shift($entry), + 'extension' => $entry + ]; + } + } + } + if (!empty($oImapResponse->ResponseList[3])) { + foreach ($oImapResponse->ResponseList[3] as $entry) { + if (\is_array($entry) && 2 <= \count($entry)) { + $this->aOtherUsers[] = [ + 'prefix' => \array_shift($entry), + 'separator' => \array_shift($entry), + 'extension' => $entry + ]; + } + } + } + if (!empty($oImapResponse->ResponseList[4])) { + foreach ($oImapResponse->ResponseList[4] as $entry) { + if (\is_array($entry) && 2 <= \count($entry)) { + $this->aShared[] = [ + 'prefix' => \array_shift($entry), + 'separator' => \array_shift($entry), + 'extension' => $entry + ]; } } } } - public function GetPrivateNamespace() : string + public function GetPersonalPrefix() : string { - $sName = ''; - if (isset($oImapResponse->ResponseList[2][0][0])) { - $sName = $oImapResponse->ResponseList[2][0][0]; - $sSeparator = $oImapResponse->ResponseList[2][0][1]; - if ('INBOX'.$sSeparator === \substr(\strtoupper($sName), 0, 6)) { - $sName = 'INBOX'.$sSeparator.\substr($sName, 6); + $sPrefix = ''; + if (isset($this->aPersonal[0])) { + $sPrefix = $this->aPersonal[0]['prefix']; + $sSeparator = $this->aPersonal[0]['separator']; + if ('INBOX'.$sSeparator === \substr(\strtoupper($sPrefix), 0, 6)) { + $sPrefix = 'INBOX'.$sSeparator.\substr($sPrefix, 6); }; } - return $sName; + return $sPrefix; + } + + #[\ReturnTypeWillChange] + public function jsonSerialize() + { + return array( + '@Object' => 'Object/Namespaces', + 'personal' => $this->aPersonal, + 'users' => $this->aOtherUsers, + 'shared' => $this->aShared, + ); } } 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 e92db6b26..9728589df 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 @@ -55,7 +55,24 @@ trait Folders $HideUnsubscribed = (bool) $oSettingsLocal->GetConf('HideUnsubscribed', $HideUnsubscribed); } + $oNamespaces = $this->ImapClient()->GetNamespaces(); $oFolderCollection = $this->MailClient()->Folders('', '*', $HideUnsubscribed); + if (isset($oNamespaces->aOtherUsers[0])) { + $oCollection = $this->MailClient()->Folders($oNamespaces->aOtherUsers[0]['prefix'], '*', $HideUnsubscribed); + if ($oCollection) { + foreach ($oCollection as $oFolder) { + $oFolderCollection[$oFolder->FullName] = $oFolder; + } + } + } + if (isset($oNamespaces->aShared[0])) { + $oCollection = $this->MailClient()->Folders($oNamespaces->aShared[0]['prefix'], '*', $HideUnsubscribed); + if ($oCollection) { + foreach ($oCollection as $oFolder) { + $oFolderCollection[$oFolder->FullName] = $oFolder; + } + } + } if ($oFolderCollection) { $aQuota = null; @@ -77,7 +94,8 @@ trait Folders array( 'quotaUsage' => $aQuota ? $aQuota[0] * 1024 : null, 'quotaLimit' => $aQuota ? $aQuota[1] * 1024 : null, - 'namespace' => $this->ImapClient()->GetPrivateNamespace(), + 'namespace' => $oNamespaces->GetPersonalPrefix(), + 'namespaces' => $oNamespaces, 'capabilities' => $aCapabilities ) );