Added: support all namespaces

This commit is contained in:
the-djmaze 2024-02-13 02:05:38 +01:00
parent de7e9d86d3
commit 304c67534b
5 changed files with 102 additions and 62 deletions

View file

@ -574,8 +574,8 @@ trait Folders
} }
} }
} }
/*
// ACL RIGHTS=texk // RFC 4314
if ($this->hasCapability('ACL') || $this->CapabilityValue('RIGHTS')) { if ($this->hasCapability('ACL') || $this->CapabilityValue('RIGHTS')) {
foreach ($oFolderCollection as $oFolder) { foreach ($oFolderCollection as $oFolder) {
if ($oFolder->Selectable()) try { if ($oFolder->Selectable()) try {
@ -586,7 +586,7 @@ trait Folders
} }
} }
} }
*/
if (!$bInbox && !$sParentFolderName && !isset($oFolderCollection['INBOX'])) { if (!$bInbox && !$sParentFolderName && !isset($oFolderCollection['INBOX'])) {
$oFolderCollection['INBOX'] = new Folder('INBOX', $sDelimiter); $oFolderCollection['INBOX'] = new Folder('INBOX', $sDelimiter);
} }

View file

@ -24,9 +24,11 @@ trait Metadata
* Dovecot 2.2+ supports fetching all METADATA at once (wildcard). * 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. * RFC 5464 doesn't specify this, but its earlier draft did, and Kolab uses it.
*/ */
private ?array $allMetadata = null;
public function getAllMetadata() : array public function getAllMetadata() : array
{ {
$aReturn = array(); if (null === $this->allMetadata) {
$this->allMetadata = array();
try { try {
$arguments = [ $arguments = [
'(DEPTH infinity)', '(DEPTH infinity)',
@ -44,13 +46,14 @@ trait Metadata
for ($i = 0; $i < $c; $i += 2) { for ($i = 0; $i < $c; $i += 2) {
$aMetadata[$oResponse->ResponseList[3][$i]] = $oResponse->ResponseList[3][$i+1]; $aMetadata[$oResponse->ResponseList[3][$i]] = $oResponse->ResponseList[3][$i+1];
} }
$aReturn[$this->toUTF8($oResponse->ResponseList[2])] = $aMetadata; $this->allMetadata[$this->toUTF8($oResponse->ResponseList[2])] = $aMetadata;
} }
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
//\SnappyMail\Log::warning('IMAP', $e->getMessage()); //\SnappyMail\Log::warning('IMAP', $e->getMessage());
} }
return $aReturn; }
return $this->allMetadata;
} }
public function getMetadata(string $sFolderName, array $aEntries, array $aOptions = []) : array public function getMetadata(string $sFolderName, array $aEntries, array $aOptions = []) : array

View file

@ -363,7 +363,7 @@ class ImapClient extends \MailSo\Net\NetClient
* @throws \MailSo\Net\Exceptions\* * @throws \MailSo\Net\Exceptions\*
* @throws \MailSo\Imap\Exceptions\* * @throws \MailSo\Imap\Exceptions\*
*/ */
public function GetNamespace() : ?NamespaceResult public function GetNamespaces() : ?NamespaceResult
{ {
if (!$this->hasCapability('NAMESPACE')) { if (!$this->hasCapability('NAMESPACE')) {
return null; 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 * RFC 7889
* APPENDLIMIT=<number> indicates that the IMAP server has the same upload limit for all mailboxes. * APPENDLIMIT=<number> 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 if ($oResponse->IsStatusResponse
&& Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType && Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
&& Enumerations\ResponseStatus::PREAUTH === $oResponse->StatusOrIndex && Enumerations\ResponseStatus::PREAUTH === $oResponse->StatusOrIndex
// && (Enumerations\ResponseStatus::PREAUTH === $oResponse->StatusOrIndex || Enumerations\ResponseStatus::BYE === $oResponse->StatusOrIndex)
) { ) {
break; break;
} }

View file

@ -15,42 +15,71 @@ namespace MailSo\Imap;
* @category MailSo * @category MailSo
* @package Imap * @package Imap
*/ */
class NamespaceResult class NamespaceResult implements \JsonSerializable
{ {
// prefix => separator public array
private array $namespaces = [ $aPersonal = [],
// '' => '.', // default $aOtherUsers = [],
// 'virtual.' => '.', $aShared = [];
// 'shared.' => '.',
// etc.
];
function __construct(Response $oImapResponse) function __construct(Response $oImapResponse)
{ {
// * NAMESPACE (("" ".")("virtual." ".")) (("shared." ".")) NIL\r\n if (!empty($oImapResponse->ResponseList[2])) {
$i = 1; foreach ($oImapResponse->ResponseList[2] as $entry) {
while (isset($oImapResponse->ResponseList[++$i])) {
$entries = $oImapResponse->ResponseList[$i];
if ($entries) {
foreach ($entries as $entry) {
if (\is_array($entry) && 2 <= \count($entry)) { if (\is_array($entry) && 2 <= \count($entry)) {
$this->namespaces[$entry[0]] = $entry[1]; $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 = ''; $sPrefix = '';
if (isset($oImapResponse->ResponseList[2][0][0])) { if (isset($this->aPersonal[0])) {
$sName = $oImapResponse->ResponseList[2][0][0]; $sPrefix = $this->aPersonal[0]['prefix'];
$sSeparator = $oImapResponse->ResponseList[2][0][1]; $sSeparator = $this->aPersonal[0]['separator'];
if ('INBOX'.$sSeparator === \substr(\strtoupper($sName), 0, 6)) { if ('INBOX'.$sSeparator === \substr(\strtoupper($sPrefix), 0, 6)) {
$sName = 'INBOX'.$sSeparator.\substr($sName, 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,
);
} }
} }

View file

@ -55,7 +55,24 @@ trait Folders
$HideUnsubscribed = (bool) $oSettingsLocal->GetConf('HideUnsubscribed', $HideUnsubscribed); $HideUnsubscribed = (bool) $oSettingsLocal->GetConf('HideUnsubscribed', $HideUnsubscribed);
} }
$oNamespaces = $this->ImapClient()->GetNamespaces();
$oFolderCollection = $this->MailClient()->Folders('', '*', $HideUnsubscribed); $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) { if ($oFolderCollection) {
$aQuota = null; $aQuota = null;
@ -77,7 +94,8 @@ trait Folders
array( array(
'quotaUsage' => $aQuota ? $aQuota[0] * 1024 : null, 'quotaUsage' => $aQuota ? $aQuota[0] * 1024 : null,
'quotaLimit' => $aQuota ? $aQuota[1] * 1024 : null, 'quotaLimit' => $aQuota ? $aQuota[1] * 1024 : null,
'namespace' => $this->ImapClient()->GetPrivateNamespace(), 'namespace' => $oNamespaces->GetPersonalPrefix(),
'namespaces' => $oNamespaces,
'capabilities' => $aCapabilities 'capabilities' => $aCapabilities
) )
); );