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')) {
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);
}

View File

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

View File

@@ -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=<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
&& Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
&& Enumerations\ResponseStatus::PREAUTH === $oResponse->StatusOrIndex
// && (Enumerations\ResponseStatus::PREAUTH === $oResponse->StatusOrIndex || Enumerations\ResponseStatus::BYE === $oResponse->StatusOrIndex)
) {
break;
}

View File

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

View File

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