diff --git a/dev/Model/AbstractCollection.js b/dev/Model/AbstractCollection.js index 9ec8c08bf..375c3a070 100644 --- a/dev/Model/AbstractCollection.js +++ b/dev/Model/AbstractCollection.js @@ -25,7 +25,6 @@ export class AbstractCollectionModel extends Array if (json) { if ('Collection/'+this.name.replace('Model', '') === json['@Object']) { Object.entries(json).forEach(([key, value]) => '@' !== key[0] && (result[key] = value)); -// json[@Count] json = json['@Collection']; } if (isArray(json)) { diff --git a/dev/Model/FolderCollection.js b/dev/Model/FolderCollection.js index 4c63a83dd..b6105e87c 100644 --- a/dev/Model/FolderCollection.js +++ b/dev/Model/FolderCollection.js @@ -1,7 +1,7 @@ import { AbstractCollectionModel } from 'Model/AbstractCollection'; import { UNUSED_OPTION_VALUE } from 'Common/Consts'; -import { isArray, pInt, getKeyByValue } from 'Common/Utils'; +import { isArray, getKeyByValue } from 'Common/Utils'; import { ClientSideKeyName, FolderType, FolderMetadataKeys } from 'Common/EnumsUser'; import * as Cache from 'Common/Cache'; import { Settings, SettingsGet } from 'Common/Globals'; @@ -113,10 +113,7 @@ export class FolderCollectionModel extends AbstractCollectionModel } storeIt() { - const cnt = pInt(this.CountRec); - - FolderUserStore.displaySpecSetting(0 >= cnt - || Math.max(10, Math.min(100, pInt(Settings.app('folderSpecLimit')))) < cnt); + FolderUserStore.displaySpecSetting(Settings.app('folderSpecLimit') < this.CountRec); if (SystemFolders && !('' + @@ -214,7 +211,7 @@ export class FolderModel extends AbstractModel { selected: false, edited: false, subscribed: true, - checkable: false, + checkable: false, // Check for new messages deleteAccess: false, nameForEdit: '', diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Base/Collection.php b/snappymail/v/0.0.0/app/libraries/MailSo/Base/Collection.php index 488fd3b5a..6ea389829 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Base/Collection.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Base/Collection.php @@ -17,9 +17,9 @@ namespace MailSo\Base; */ abstract class Collection extends \ArrayObject implements \JsonSerializable { - function __construct($input = array(), int $flags = 0, string $iterator_class = "ArrayIterator") + function __construct($input = array(), int $flags = 0, string $iterator_class = 'ArrayIterator') { - parent::__construct(); + parent::__construct(/*[], $flags, $iterator_class*/); foreach ($input as $item) { $this->append($item); } @@ -79,7 +79,6 @@ abstract class Collection extends \ArrayObject implements \JsonSerializable $aNames = \explode('\\', \get_class($this)); return array( '@Object' => 'Collection/' . \end($aNames), - '@Count' => $this->count(), '@Collection' => $this->getArrayCopy() ); } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ResponseCollection.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ResponseCollection.php index de7bfa2eb..82bb62f7e 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ResponseCollection.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ResponseCollection.php @@ -67,7 +67,9 @@ class ResponseCollection extends \MailSo\Base\Collection } if (\is_array($aList) && \count($aList)) { - return \array_map('strtoupper', $aList); + $aList = \array_map('strtoupper', $aList); + \sort($aList); + return $aList; } } return null; diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php index d7e45f2b0..aa22bc354 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php @@ -17,34 +17,12 @@ namespace MailSo\Mail; */ class FolderCollection extends \MailSo\Base\Collection { - /** - * @var string - */ - public $Namespace = ''; - - /** - * @var string - */ - public $FoldersHash = ''; - - /** - * @var bool - */ - public $IsThreadsSupported = false; - /** * @var bool */ public $Optimized = false; - /** - * @var array - */ - public $SystemFolders = array(); - - public $quotaUsage = 0; - public $quotaLimit = 0; - public $capabilities = array(); + public $TotalCount = 0; public function append($oFolder, bool $bToTop = false) : void { @@ -54,45 +32,20 @@ class FolderCollection extends \MailSo\Base\Collection public function GetByFullName(string $sFullName) : ?Folder { - $mResult = null; - foreach ($this as $oFolder) - { - if ($oFolder->FullName() === $sFullName) - { - $mResult = $oFolder; - break; + foreach ($this as $oFolder) { + if ($oFolder->FullName() === $sFullName) { + return $oFolder; } - else if ($oFolder->HasSubFolders()) - { + + if ($oFolder->HasSubFolders()) { $mResult = $oFolder->SubFolders(true)->GetByFullName($sFullName); - if ($mResult) - { - break; + if ($mResult) { + return $mResult; } } } - return $mResult; - } - - public function CountRec() : int - { - $iResult = $this->Count(); - foreach ($this as $oFolder) - { - if ($oFolder) - { - $oSub = $oFolder->SubFolders(); - $iResult += $oSub ? $oSub->CountRec() : 0; - } - } - - return $iResult; - } - - public function GetNamespace() : string - { - return $this->Namespace; + return null; } public function FindDelimiter() : string @@ -108,18 +61,11 @@ class FolderCollection extends \MailSo\Base\Collection return $oFolder ? $oFolder->Delimiter() : '/'; } - public function SetNamespace(string $sNamespace) : self - { - $this->Namespace = $sNamespace; - - return $this; - } - public function AddWithPositionSearch(Folder $oMailFolder) : void { foreach ($this as $oItemFolder) { - if (0 === \strpos($oMailFolder->FullName(), $oItemFolder->FullName().$oItemFolder->Delimiter())) + if (\str_starts_with($oMailFolder->FullName(), $oItemFolder->FullName().$oItemFolder->Delimiter())) { $oItemFolder->SubFolders(true)->AddWithPositionSearch($oMailFolder); return; @@ -128,19 +74,4 @@ class FolderCollection extends \MailSo\Base\Collection $this->append($oMailFolder); } - - public function jsonSerialize() - { - return \array_merge(parent::jsonSerialize(), array( - 'Namespace' => $this->GetNamespace(), - 'FoldersHash' => $this->FoldersHash ?: '', - 'IsThreadsSupported' => $this->IsThreadsSupported, - 'quotaUsage' => $this->quotaUsage, - 'quotaLimit' => $this->quotaLimit, - 'Optimized' => $this->Optimized, - 'CountRec' => $this->CountRec(), - 'SystemFolders' => empty($this->SystemFolders) ? null : $this->SystemFolders, - 'Capabilities' => \array_values($this->capabilities) - )); - } } 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 ad3e34625..c233bdb70 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 @@ -61,6 +61,11 @@ class MailClient return $this->oImapClient->IsLoggined(); } + public function Capabilities() : array + { + return $this->oImapClient->Capability(); + } + private function getEnvelopeOrHeadersRequestStringForSimpleList() : string { return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( @@ -1204,12 +1209,8 @@ class MailClient public function Folders(string $sParent, string $sListPattern, bool $bUseListSubscribeStatus, int $iOptimizationLimit, bool $bUseListStatus) : ?FolderCollection { - $aCapabilities = \array_filter($this->oImapClient->Capability(), function($item){ - return !\preg_match('/^(IMAP|AUTH|LOGIN|SASL)/', $item); - }); - $aImapSubscribedFoldersHelper = null; - if (\in_array('LIST-EXTENDED', $aCapabilities)) { + if ($this->oImapClient->IsSupported('LIST-EXTENDED')) { $bUseListSubscribeStatus = false; } else if ($bUseListSubscribeStatus) { //\error_log('RFC5258 not supported, using LSUB'); @@ -1228,13 +1229,7 @@ class MailClient } } - $bUseListStatus = $bUseListStatus && \in_array('LIST-STATUS', $aCapabilities); - if (!$bUseListStatus) { - $key = \array_search('LIST-STATUS', $aCapabilities); - if (false !== $key) { - unset($aCapabilities[$key]); - } - } + $bUseListStatus = $bUseListStatus && $this->oImapClient->IsSupported('LIST-STATUS'); $aFolders = $bUseListStatus ? $this->oImapClient->FolderStatusList($sParent, $sListPattern) @@ -1244,9 +1239,7 @@ class MailClient } $oFolderCollection = new FolderCollection; - $oFolderCollection->IsThreadsSupported = $this->IsThreadsSupported(); $oFolderCollection->Optimized = 10 < $iOptimizationLimit && \count($aFolders) > $iOptimizationLimit; - $oFolderCollection->capabilities = $aCapabilities; $sINBOX = 'INBOX'; $aSortedByLenImapFolders = array(); @@ -1303,7 +1296,11 @@ class MailClient $aSortedByLenImapFolders["\x00".$sINBOX] = $aSortedByLenImapFolders[$sINBOX]; unset($aSortedByLenImapFolders[$sINBOX]); } - +/* + // TODO: use active language + $collator = new \Collator('en_US'); + \uksort($aSortedByLenImapFolders, static fn($a, $b) => $collator->compare($a, $b)); +*/ \uksort($aSortedByLenImapFolders, 'strnatcasecmp'); foreach ($aSortedByLenImapFolders as $oMailFolder) @@ -1311,13 +1308,9 @@ class MailClient $oFolderCollection->AddWithPositionSearch($oMailFolder); } - unset($aSortedByLenImapFolders); + $oFolderCollection->TotalCount = \count($aSortedByLenImapFolders); - $oNamespace = $this->oImapClient->GetNamespace(); - if ($oNamespace) - { - $oFolderCollection->SetNamespace($oNamespace->GetPersonalNamespace()); - } + unset($aSortedByLenImapFolders); return $oFolderCollection; } @@ -1530,6 +1523,12 @@ class MailClient return $this; } + public function GetNamespace() : string + { + $oNamespace = $this->oImapClient->GetNamespace(); + return $oNamespace ? $oNamespace->GetPersonalNamespace() : ''; + } + /** * RFC 5464 */ 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 4a4579ec6..ad61d5e11 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 @@ -12,27 +12,11 @@ trait Folders private function getFolderCollection(bool $HideUnsubscribed) : ?\MailSo\Mail\FolderCollection { - $oFolderCollection = $this->MailClient()->Folders('', '*', + return $this->MailClient()->Folders('', '*', $HideUnsubscribed, (int) $this->Config()->Get('labs', 'imap_folder_list_limit', 200), (bool) $this->Config()->Get('labs', 'imap_use_list_status', true) ); - - if ($oFolderCollection) { - $oAccount = $this->getAccountFromToken(); - if ($this->GetCapa(false, Capa::QUOTA, $oAccount)) { - try { -// $aQuota = $this->MailClient()->Quota(); - $aQuota = $this->MailClient()->QuotaRoot(); - $oFolderCollection->quotaUsage = $aQuota ? $aQuota[0] * 1024 : null; - $oFolderCollection->quotaLimit = $aQuota ? $aQuota[1] * 1024 : null; - } catch (\Throwable $oException) { - // ignore - } - } - } - - return $oFolderCollection; } public function DoFolders() : array @@ -49,13 +33,14 @@ trait Folders if ($oFolderCollection) { + $sNamespace = $this->MailClient()->GetNamespace(); + $this->Plugins()->RunHook('filter.folders-post', array($oAccount, $oFolderCollection)); $oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount); $aSystemFolders = array(); $this->recFoldersTypes($oAccount, $oFolderCollection, $aSystemFolders); - $oFolderCollection->SystemFolders = $aSystemFolders; if (!$this->Config()->Get('labs', 'use_imap_sort', true)) { $oFolderCollection->capabilities = \array_filter($oFolderCollection->capabilities, function($item){ @@ -67,8 +52,7 @@ trait Folders { $bDoItAgain = false; - $sNamespace = $oFolderCollection->GetNamespace(); - $sParent = empty($sNamespace) ? '' : \substr($sNamespace, 0, -1); + $sParent = \substr($sNamespace, 0, -1); $sDelimiter = $oFolderCollection->FindDelimiter(); @@ -157,17 +141,49 @@ trait Folders { $aSystemFolders = array(); $this->recFoldersTypes($oAccount, $oFolderCollection, $aSystemFolders); - $oFolderCollection->SystemFolders = $aSystemFolders; } } } if ($oFolderCollection) { - $oFolderCollection->FoldersHash = \md5(\implode("\x0", $this->recFoldersNames($oFolderCollection))); - } + $this->Plugins()->RunHook('filter.folders-complete', array($oAccount, $oFolderCollection)); - $this->Plugins()->RunHook('filter.folders-complete', array($oAccount, $oFolderCollection)); + $aQuota = null; + if ($this->GetCapa(false, Capa::QUOTA, $this->getAccountFromToken())) { + try { +// $aQuota = $this->MailClient()->Quota(); + $aQuota = $this->MailClient()->QuotaRoot(); + } catch (\Throwable $oException) { + // ignore + } + } + + $aCapabilities = \array_filter($this->MailClient()->Capabilities(), function($item){ + return !\preg_match('/^(IMAP|AUTH|LOGIN|SASL)/', $item); + }); + if (!$this->Config()->Get('labs', 'imap_use_list_status', true)) { + $key = \array_search('LIST-STATUS', $aCapabilities); + if (false !== $key) { + unset($aCapabilities[$key]); + } + } + + $oFolderCollection = \array_merge( + $oFolderCollection->jsonSerialize(), + array( + 'quotaUsage' => $aQuota ? $aQuota[0] * 1024 : null, + 'quotaLimit' => $aQuota ? $aQuota[1] * 1024 : null, + 'Namespace' => $sNamespace, + 'FoldersHash' => \md5(\implode("\x0", $this->recFoldersNames($oFolderCollection))), + 'IsThreadsSupported' => $this->MailClient()->IsThreadsSupported(), + 'Optimized' => $oFolderCollection->Optimized, + 'CountRec' => $oFolderCollection->TotalCount, + 'SystemFolders' => empty($aSystemFolders) ? null : $aSystemFolders, + 'Capabilities' => \array_values($aCapabilities) + ) + ); + } } return $this->DefaultResponse(__FUNCTION__, $oFolderCollection);