From f8b794ec1cb4e93fb0d8831b29bd3ea0b80de0b7 Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 13 Mar 2023 11:49:40 +0100 Subject: [PATCH] Prevent folder/messages flags conflict by using the right name `attributes` for Folders --- dev/Model/FolderCollection.js | 25 ++++++------- dev/Settings/User/Folders.js | 2 +- dev/Stores/User/Messagelist.js | 3 +- plugins/mailbox-detect/index.php | 14 ++++---- .../MailSo/Imap/Commands/Folders.php | 7 ++-- .../app/libraries/MailSo/Imap/Folder.php | 35 ++++++++----------- .../MailSo/Imap/FolderInformation.php | 11 ++++-- 7 files changed, 48 insertions(+), 49 deletions(-) diff --git a/dev/Model/FolderCollection.js b/dev/Model/FolderCollection.js index 87cfc34e2..d66d70428 100644 --- a/dev/Model/FolderCollection.js +++ b/dev/Model/FolderCollection.js @@ -169,22 +169,22 @@ export class FolderCollectionModel extends AbstractCollectionModel break; } // Flags - if (oFolder.flags.includes('\\sentmail')) { + if (oFolder.attributes.includes('\\sentmail')) { role = 'sent'; } - if (oFolder.flags.includes('\\spam')) { + if (oFolder.attributes.includes('\\spam')) { role = 'junk'; } - if (oFolder.flags.includes('\\bin')) { + if (oFolder.attributes.includes('\\bin')) { role = 'trash'; } - if (oFolder.flags.includes('\\important')) { + if (oFolder.attributes.includes('\\important')) { role = 'important'; } - if (oFolder.flags.includes('\\starred')) { + if (oFolder.attributes.includes('\\starred')) { role = 'flagged'; } - if (oFolder.flags.includes('\\all') || oFolder.flags.includes('\\allmail')) { + if (oFolder.attributes.includes('\\all') || oFolder.flags.includes('\\allmail')) { role = 'all'; } } @@ -228,7 +228,7 @@ export class FolderCollectionModel extends AbstractCollectionModel name: name, fullName: parentName, delimiter: delimiter, - flags: ['\\nonexistent'] + attributes: ['\\nonexistent'] }); setFolder(pfolder); result.splice(i, 0, pfolder); @@ -330,7 +330,8 @@ export class FolderModel extends AbstractModel { tagsAllowed: false }); - this.flags = ko.observableArray(); + this.attributes = ko.observableArray(); + // For messages this.permanentFlags = ko.observableArray(); this.addSubscribables({ @@ -379,7 +380,7 @@ export class FolderModel extends AbstractModel { isFlagged: () => FolderUserStore.currentFolder() === this && MessagelistUserStore.listSearch().includes('flagged'), -// isSubscribed: () => this.flags().includes('\\subscribed'), +// isSubscribed: () => this.attributes().includes('\\subscribed'), hasVisibleSubfolders: () => !!this.subFolders().find(folder => folder.visible()), @@ -536,9 +537,9 @@ export class FolderModel extends AbstractModel { path.pop(); folder.parentName = path.join(folder.delimiter); - folder.isSubscribed(folder.flags.includes('\\subscribed')); - folder.exists = !folder.flags.includes('\\nonexistent'); - folder.selectable(folder.exists && !folder.flags.includes('\\noselect')); + folder.isSubscribed(folder.attributes.includes('\\subscribed')); + folder.exists = !folder.attributes.includes('\\nonexistent'); + folder.selectable(folder.exists && !folder.attributes.includes('\\noselect')); type && 'mail' != type && folder.kolabType(type); } diff --git a/dev/Settings/User/Folders.js b/dev/Settings/User/Folders.js index 89fc7fc9e..a7cb877c2 100644 --- a/dev/Settings/User/Folders.js +++ b/dev/Settings/User/Folders.js @@ -85,7 +85,7 @@ export class UserSettingsFolders /*extends AbstractViewSettings*/ { folder: folderToRemove.fullName }).then( () => { -// folderToRemove.flags.push('\\nonexistent'); +// folderToRemove.attributes.push('\\nonexistent'); folderToRemove.selectable(false); // folderToRemove.isSubscribed(false); // folderToRemove.checkable(false); diff --git a/dev/Stores/User/Messagelist.js b/dev/Stores/User/Messagelist.js index 850dde67e..27325021b 100644 --- a/dev/Stores/User/Messagelist.js +++ b/dev/Stores/User/Messagelist.js @@ -223,8 +223,7 @@ MessagelistUserStore.reload = (bDropPagePosition = false, bDropCurrentFolderCach folder.unreadEmails(folderInfo.unreadEmails); } - folder.flags(folderInfo.flags); - let flags = folderInfo.permanentFlags; + let flags = folderInfo.permanentFlags || []; if (flags.includes('\\*')) { let i = 6; while (--i) { diff --git a/plugins/mailbox-detect/index.php b/plugins/mailbox-detect/index.php index 574bca0ca..04ffe68d0 100644 --- a/plugins/mailbox-detect/index.php +++ b/plugins/mailbox-detect/index.php @@ -9,9 +9,9 @@ class MailboxDetectPlugin extends \RainLoop\Plugins\AbstractPlugin NAME = 'MailboxDetect', AUTHOR = 'SnappyMail', URL = 'https://snappymail.eu/', - VERSION = '2.5', - RELEASE = '2023-02-21', - REQUIRED = '2.26.3', + VERSION = '2.6', + RELEASE = '2023-03-13', + REQUIRED = '2.27.0', CATEGORY = 'General', LICENSE = 'MIT', DESCRIPTION = 'Autodetect system folders and/or create them when needed'; @@ -74,13 +74,13 @@ class MailboxDetectPlugin extends \RainLoop\Plugins\AbstractPlugin $sDelimiter || ($sDelimiter = $folder['delimiter']); if ($folder['role']) { $roles[$folder['role']] = true; - } else if (\in_array('\\sentmail', $folder['flags'])) { + } else if (\in_array('\\sentmail', $folder['attributes'])) { $found['sent'][] = $i; - } else if (\in_array('\\spam', $folder['flags'])) { + } else if (\in_array('\\spam', $folder['attributes'])) { $found['junk'][] = $i; - } else if (\in_array('\\bin', $folder['flags'])) { + } else if (\in_array('\\bin', $folder['attributes'])) { $found['trash'][] = $i; - } else if (\in_array('\\starred', $folder['flags'])) { + } else if (\in_array('\\starred', $folder['attributes'])) { $found['flagged'][] = $i; } else { // Kolab 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 29490f17b..2d4938f67 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 @@ -424,7 +424,8 @@ trait Folders else if (\count($oResponse->ResponseList) > 2 && 'FLAGS' === $oResponse->ResponseList[1] && \is_array($oResponse->ResponseList[2])) { - $oResult->Flags = \array_map('\\MailSo\\Base\\Utils::Utf7ModifiedToUtf8', $oResponse->ResponseList[2]); + // These could be not permanent, so we don't use them +// $oResult->Flags = \array_map('\\MailSo\\Base\\Utils::Utf7ModifiedToUtf8', $oResponse->ResponseList[2]); } } } @@ -529,14 +530,14 @@ trait Folders /** * $oResponse->ResponseList[0] = * * $oResponse->ResponseList[1] = LIST (all) | LSUB (subscribed) - * $oResponse->ResponseList[2] = Flags + * $oResponse->ResponseList[2] = Attribute flags * $oResponse->ResponseList[3] = Delimiter * $oResponse->ResponseList[4] = FullName */ if (isset($oFolderCollection[$sFullName])) { $oFolder = $oFolderCollection[$sFullName]; $oFolder->setDelimiter($oResponse->ResponseList[3]); - $oFolder->setFlags($oResponse->ResponseList[2]); + $oFolder->setAttributes($oResponse->ResponseList[2]); } else { $oFolder = new Folder($sFullName, $oResponse->ResponseList[3], $oResponse->ResponseList[2]); $oFolderCollection[$sFullName] = $oFolder; 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 c0b42ac8d..e53fb887d 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 @@ -24,7 +24,7 @@ class Folder implements \JsonSerializable private ?string $sDelimiter; - private array $aFlagsLowerCase; + private array $aAttributes; /** * RFC 5464 @@ -34,31 +34,31 @@ class Folder implements \JsonSerializable /** * @throws \InvalidArgumentException */ - function __construct(string $sFullName, string $sDelimiter = null, array $aFlags = array()) + function __construct(string $sFullName, string $sDelimiter = null, array $aAttributes = array()) { if (!\strlen($sFullName)) { throw new \InvalidArgumentException; } $this->FullName = $sFullName; $this->setDelimiter($sDelimiter); - $this->setFlags($aFlags); + $this->setAttributes($aAttributes); /* // RFC 5738 - if (\in_array('\\noutf8', $this->aFlagsLowerCase)) { + if (\in_array('\\noutf8', $this->aAttributes)) { } - if (\in_array('\\utf8only', $this->aFlagsLowerCase)) { + if (\in_array('\\utf8only', $this->aAttributes)) { } */ } - public function setFlags(array $aFlags) : void + public function setAttributes(array $aAttributes) : void { - $this->aFlagsLowerCase = \array_map('mb_strtolower', $aFlags); + $this->aAttributes = \array_map('mb_strtolower', $aAttributes); } public function setSubscribed() : void { - $this->aFlagsLowerCase = \array_unique(\array_merge($this->aFlagsLowerCase, ['\\subscribed'])); + $this->aAttributes = \array_unique(\array_merge($this->aAttributes, ['\\subscribed'])); } public function setDelimiter(?string $sDelimiter) : void @@ -81,25 +81,20 @@ class Folder implements \JsonSerializable return $this->sDelimiter; } - public function FlagsLowerCase() : array - { - return $this->aFlagsLowerCase; - } - public function Selectable() : bool { - return !\in_array('\\noselect', $this->aFlagsLowerCase) - && !\in_array('\\nonexistent', $this->aFlagsLowerCase); + return !\in_array('\\noselect', $this->aAttributes) + && !\in_array('\\nonexistent', $this->aAttributes); } public function IsSubscribed() : bool { - return \in_array('\\subscribed', $this->aFlagsLowerCase); + return \in_array('\\subscribed', $this->aAttributes); } public function IsInbox() : bool { - return 'INBOX' === \strtoupper($this->FullName) || \in_array('\\inbox', $this->aFlagsLowerCase); + return 'INBOX' === \strtoupper($this->FullName) || \in_array('\\inbox', $this->aAttributes); } public function SetMetadata(string $sName, string $sData) : void @@ -137,7 +132,7 @@ class Folder implements \JsonSerializable '\\junk', // '\\spam' '\\sent', // '\\sentmail' '\\trash', // '\\bin' - ], $this->aFlagsLowerCase); + ], $this->aAttributes); if ($match) { $role = \array_shift($match); } @@ -162,9 +157,7 @@ class Folder implements \JsonSerializable 'name' => $this->Name(), 'fullName' => $this->FullName, 'delimiter' => (string) $this->sDelimiter, - 'flags' => $this->aFlagsLowerCase, -// 'extended' => $aExtended, -// 'permanentFlags' => $this->PermanentFlags, + 'attributes' => $this->aAttributes, 'metadata' => $this->aMetadata, 'uidNext' => $this->UIDNEXT, // https://datatracker.ietf.org/doc/html/rfc8621#section-2 diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/FolderInformation.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/FolderInformation.php index 745e00c90..a26eab696 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/FolderInformation.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/FolderInformation.php @@ -23,11 +23,14 @@ class FolderInformation implements \JsonSerializable /** * Message flags + * https://www.rfc-editor.org/rfc/rfc3501#section-7.2.6 + * These could be not permanent so we don't use them */ public array $Flags = array(); /** * NOTE: Empty when FolderExamine is used + * https://www.rfc-editor.org/rfc/rfc3501#page-64 */ public array $PermanentFlags = array(); @@ -39,9 +42,9 @@ class FolderInformation implements \JsonSerializable public function IsFlagSupported(string $sFlag) : bool { - return \in_array('\\*', $this->PermanentFlags) || - \in_array($sFlag, $this->PermanentFlags) || - \in_array($sFlag, $this->Flags); + return \in_array('\\*', $this->PermanentFlags) + || \in_array($sFlag, $this->PermanentFlags); +// || \in_array($sFlag, $this->Flags); } #[\ReturnTypeWillChange] @@ -69,9 +72,11 @@ class FolderInformation implements \JsonSerializable if ($this->etag) { $result['etag'] = $this->etag; } +/* if ($this->Flags) { $result['flags'] = $this->Flags; } +*/ if ($this->PermanentFlags) { $result['permanentFlags'] = $this->PermanentFlags; }