From 70e3e6423e805542fccf5b6e48cbc529d0a73bab Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Fri, 3 Jun 2022 13:47:04 +0200 Subject: [PATCH] Added message tags toggle for #419 --- dev/App/User.js | 6 +- dev/Common/Folders.js | 10 +-- dev/Model/FolderCollection.js | 67 ++++++++++--------- dev/Model/Message.js | 49 +++++++++++++- dev/Model/MessageCollection.js | 7 +- dev/Settings/User/Folders.js | 2 +- dev/Stores/User/Messagelist.js | 34 +++++----- dev/Styles/User/MessageView.less | 2 +- dev/View/Popup/FolderClear.js | 4 +- dev/View/User/MailBox/MessageList.js | 4 +- .../MailSo/Imap/Commands/Folders.php | 19 ++++-- .../Enumerations/FolderResponseStatus.php | 2 + .../MailSo/Imap/Enumerations/MessageFlag.php | 2 +- .../MailSo/Imap/FolderInformation.php | 26 ++++--- .../libraries/MailSo/Imap/Traits/Status.php | 13 +++- .../app/libraries/MailSo/Mail/MailClient.php | 45 ++++++------- .../MailSo/Mail/MessageCollection.php | 18 ----- .../libraries/RainLoop/Actions/Messages.php | 5 ++ .../templates/Views/User/MailMessageView.html | 12 +++- 19 files changed, 197 insertions(+), 130 deletions(-) diff --git a/dev/App/User.js b/dev/App/User.js index b511af26d..960850a83 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -229,11 +229,11 @@ export class AppUser extends AbstractApp { setFolderHash(result.Folder, result.Hash); - folderFromCache.messageCountAll(result.totalEmails); + folderFromCache.totalEmails(result.totalEmails); - let unreadCountChange = (folderFromCache.messageCountUnread() !== result.unreadEmails); + let unreadCountChange = (folderFromCache.unreadEmails() !== result.unreadEmails); - folderFromCache.messageCountUnread(result.unreadEmails); + folderFromCache.unreadEmails(result.unreadEmails); if (unreadCountChange) { MessageFlagsCache.clearFolder(folderFromCache.fullName); diff --git a/dev/Common/Folders.js b/dev/Common/Folders.js index 72089ec3d..7ca52a6cd 100644 --- a/dev/Common/Folders.js +++ b/dev/Common/Folders.js @@ -38,13 +38,13 @@ fetchFolderInformation = (fCallback, folder, list = []) => { if (!fetch) { list.forEach(messageListItem => { - if (!MessageFlagsCache.getFor(messageListItem.folder, messageListItem.uid)) { + if (!MessageFlagsCache.getFor(folder, messageListItem.uid)) { uids.push(messageListItem.uid); } if (messageListItem.threads.length) { messageListItem.threads.forEach(uid => { - if (!MessageFlagsCache.getFor(messageListItem.folder, uid)) { + if (!MessageFlagsCache.getFor(folder, uid)) { uids.push(uid); } }); @@ -148,11 +148,11 @@ folderInformationMultiply = (boot = false) => { setFolderHash(item.Folder, item.Hash); - folder.messageCountAll(item.totalEmails); + folder.totalEmails(item.totalEmails); - let unreadCountChange = folder.messageCountUnread() !== item.unreadEmails; + let unreadCountChange = folder.unreadEmails() !== item.unreadEmails; - folder.messageCountUnread(item.unreadEmails); + folder.unreadEmails(item.unreadEmails); if (unreadCountChange) { MessageFlagsCache.clearFolder(folder.fullName); diff --git a/dev/Model/FolderCollection.js b/dev/Model/FolderCollection.js index 87008f314..ea9742dae 100644 --- a/dev/Model/FolderCollection.js +++ b/dev/Model/FolderCollection.js @@ -163,11 +163,11 @@ export class FolderCollectionModel extends AbstractCollectionModel } if (null != oFolder.totalEmails) { - oCacheFolder.messageCountAll(oFolder.totalEmails); + oCacheFolder.totalEmails(oFolder.totalEmails); } if (null != oFolder.unreadEmails) { - oCacheFolder.messageCountUnread(oFolder.unreadEmails); + oCacheFolder.unreadEmails(oFolder.unreadEmails); } return oCacheFolder; @@ -258,8 +258,8 @@ export class FolderModel extends AbstractModel { nameForEdit: '', errorMsg: '', - privateMessageCountAll: 0, - privateMessageCountUnread: 0, + totalEmailsValue: 0, + unreadEmailsValue: 0, kolabType: null, @@ -272,6 +272,33 @@ export class FolderModel extends AbstractModel { this.subFolders = ko.observableArray(new FolderCollectionModel); this.actionBlink = ko.observable(false).extend({ falseTimeout: 1000 }); + + this.totalEmails = koComputable({ + read: this.totalEmailsValue, + write: (iValue) => { + if (isPosNumeric(iValue)) { + this.totalEmailsValue(iValue); + } else { + this.totalEmailsValue.valueHasMutated(); + } + } + }) + .extend({ notify: 'always' }); + + this.unreadEmails = koComputable({ + read: this.unreadEmailsValue, + write: (value) => { + if (isPosNumeric(value)) { + this.unreadEmailsValue(value); + } else { + this.unreadEmailsValue.valueHasMutated(); + } + } + }) + .extend({ notify: 'always' }); + + this.flags = ko.observableArray(); + this.permanentFlags = ko.observableArray(); } /** @@ -302,30 +329,6 @@ export class FolderModel extends AbstractModel { type && 'mail' != type && folder.kolabType(type); - folder.messageCountAll = koComputable({ - read: folder.privateMessageCountAll, - write: (iValue) => { - if (isPosNumeric(iValue)) { - folder.privateMessageCountAll(iValue); - } else { - folder.privateMessageCountAll.valueHasMutated(); - } - } - }) - .extend({ notify: 'always' }); - - folder.messageCountUnread = koComputable({ - read: folder.privateMessageCountUnread, - write: (value) => { - if (isPosNumeric(value)) { - folder.privateMessageCountUnread(value); - } else { - folder.privateMessageCountUnread.valueHasMutated(); - } - } - }) - .extend({ notify: 'always' }); - folder.addComputables({ isInbox: () => FolderType.Inbox === folder.type(), @@ -371,8 +374,8 @@ export class FolderModel extends AbstractModel { hidden: () => !folder.selectable() && (folder.isSystemFolder() | !folder.hasVisibleSubfolders()), printableUnreadCount: () => { - const count = folder.messageCountAll(), - unread = folder.messageCountUnread(), + const count = folder.totalEmails(), + unread = folder.unreadEmails(), type = folder.type(); if (count) { @@ -412,7 +415,7 @@ export class FolderModel extends AbstractModel { return ''; }, - hasUnreadMessages: () => 0 < folder.messageCountUnread() && folder.printableUnreadCount(), + hasUnreadMessages: () => 0 < folder.unreadEmails() && folder.printableUnreadCount(), hasSubscribedUnreadMessagesSubfolders: () => !!folder.subFolders().find( @@ -427,7 +430,7 @@ export class FolderModel extends AbstractModel { edited: value => value && folder.nameForEdit(folder.name()), - messageCountUnread: unread => { + unreadEmails: unread => { if (FolderType.Inbox === folder.type()) { fireEvent('mailbox.inbox-unread-count', unread); } diff --git a/dev/Model/Message.js b/dev/Model/Message.js index e78859acf..1037d7952 100644 --- a/dev/Model/Message.js +++ b/dev/Model/Message.js @@ -18,6 +18,8 @@ import { AbstractModel } from 'Knoin/AbstractModel'; import PreviewHTML from 'Html/PreviewMessage.html'; +import Remote from 'Remote/User/Fetch'; + const // eslint-disable-next-line max-len url = /(^|[\s\n]|\/?>)(https:\/\/[-A-Z0-9+\u0026\u2019#/%?=()~_|!:,.;]*[-A-Z0-9+\u0026#/%=~()_|])/gi, @@ -32,6 +34,25 @@ const return result; }, + toggleTag = (message, keyword) => { + const lower = keyword.toLowerCase(), + isSet = message.flags().includes(lower); + Remote.request('MessageSetKeyword', iError => { + if (!iError) { + if (isSet) { + message.flags.remove(lower); + } else { + message.flags.push(lower); + } + } + }, { + Folder: message.folder, + Uids: message.uid, + Keyword: keyword, + SetAction: isSet ? 0 : 1 + }) + }, + replyHelper = (emails, unic, localEmails) => { emails.forEach(email => { if (undefined === unic[email.email]) { @@ -91,6 +112,14 @@ export class MessageModel extends AbstractModel { this.unsubsribeLinks = ko.observableArray(); this.flags = ko.observableArray(); + const ignoredTags = [ + '$sent', + '$signed', + '$error', + '$queued', + '$forwarded' + ]; + this.addComputables({ attachmentIconClass: () => FileInfo.getAttachmentsIconClass(this.attachments()), threadsLen: () => this.threads().length, @@ -107,7 +136,25 @@ export class MessageModel extends AbstractModel { ('\\' == value[0] || '$forwarded' == value) ? '' : '' + i18n('MESSAGE_TAGS/'+value,0,value) + '' - ).join(' ') + ).join(' '), + + tagOptions: () => { + const tagOptions = []; + FolderUserStore.currentFolder().permanentFlags.forEach(value => { + let lower = value.toLowerCase(); + if ('\\' != value[0] && !ignoredTags.includes(lower)) { + tagOptions.push({ + css: 'msgflag-' + lower, + value: value, + checked: this.flags().includes(lower), + label: i18n('MESSAGE_TAGS/'+lower, 0, lower), + toggle: (/*obj*/) => toggleTag(this, value) + }); + } + }); + return tagOptions + } + }); } diff --git a/dev/Model/MessageCollection.js b/dev/Model/MessageCollection.js index 97acf38e5..8f05bc0a4 100644 --- a/dev/Model/MessageCollection.js +++ b/dev/Model/MessageCollection.js @@ -16,15 +16,16 @@ export class MessageCollectionModel extends AbstractCollectionModel this.Filtered this.Folder this.FolderHash - this.Limit + this.FolderInfo this.totalEmails this.unreadEmails this.MessageResultCount + this.UidNext + this.ThreadUid this.NewMessages this.Offset + this.Limit this.Search - this.ThreadUid - this.UidNext } */ diff --git a/dev/Settings/User/Folders.js b/dev/Settings/User/Folders.js index b7f503f25..5e4b097c6 100644 --- a/dev/Settings/User/Folders.js +++ b/dev/Settings/User/Folders.js @@ -125,7 +125,7 @@ export class UserSettingsFolders /*extends AbstractViewSettings*/ { && folderToRemove.canBeDeleted() && folderToRemove.askDelete() ) { - if (0 < folderToRemove.privateMessageCountAll()) { + if (0 < folderToRemove.totalEmails()) { // FolderUserStore.folderListError(getNotification(Notification.CantDeleteNonEmptyFolder)); folderToRemove.errorMsg(getNotification(Notification.CantDeleteNonEmptyFolder)); } else { diff --git a/dev/Stores/User/Messagelist.js b/dev/Stores/User/Messagelist.js index 9463e762d..dde63b8c1 100644 --- a/dev/Stores/User/Messagelist.js +++ b/dev/Stores/User/Messagelist.js @@ -186,27 +186,29 @@ MessagelistUserStore.reload = (bDropPagePosition = false, bDropCurrenFolderCache let unreadCountChange = false; const - folder = getFolderFromCacheList(collection.Folder); - + folder = getFolderFromCacheList(collection.Folder), + folderInfo = collection.FolderInfo; if (folder && !bCached) { folder.expires = Date.now(); setFolderHash(collection.Folder, collection.FolderHash); - if (null != collection.totalEmails) { - folder.messageCountAll(collection.totalEmails); + if (null != folderInfo.totalEmails) { + folder.totalEmails(folderInfo.totalEmails); } - if (null != collection.unreadEmails) { - if (pInt(folder.messageCountUnread()) !== pInt(collection.unreadEmails)) { + if (null != folderInfo.unreadEmails) { + if (pInt(folder.unreadEmails()) !== pInt(folderInfo.unreadEmails)) { unreadCountChange = true; MessageFlagsCache.clearFolder(folder.fullName); } - - folder.messageCountUnread(collection.unreadEmails); + folder.unreadEmails(folderInfo.unreadEmails); } - MessagelistUserStore.initUidNextAndNewMessages(folder.fullName, collection.UidNext, collection.NewMessages); + folder.flags(folderInfo.Flags); + folder.permanentFlags(folderInfo.PermanentFlags); + + MessagelistUserStore.initUidNextAndNewMessages(folder.fullName, folderInfo.UidNext, collection.NewMessages); } MessagelistUserStore.count(collection.MessageResultCount); @@ -280,7 +282,7 @@ MessagelistUserStore.setAction = (sFolderFullName, iSetAction, messages) => { folder = getFolderFromCacheList(sFolderFullName); if (folder) { - folder.messageCountUnread(folder.messageCountUnread() - alreadyUnread + length); + folder.unreadEmails(folder.unreadEmails() - alreadyUnread + length); } Remote.request('MessageSetSeen', null, { @@ -335,13 +337,13 @@ MessagelistUserStore.removeMessagesFromList = ( messages.forEach(item => item && item.isUnseen() && ++unseenCount); if (fromFolder && !copy) { - fromFolder.messageCountAll( - 0 <= fromFolder.messageCountAll() - uidForRemove.length ? fromFolder.messageCountAll() - uidForRemove.length : 0 + fromFolder.totalEmails( + 0 <= fromFolder.totalEmails() - uidForRemove.length ? fromFolder.totalEmails() - uidForRemove.length : 0 ); if (0 < unseenCount) { - fromFolder.messageCountUnread( - 0 <= fromFolder.messageCountUnread() - unseenCount ? fromFolder.messageCountUnread() - unseenCount : 0 + fromFolder.unreadEmails( + 0 <= fromFolder.unreadEmails() - unseenCount ? fromFolder.unreadEmails() - unseenCount : 0 ); } } @@ -351,9 +353,9 @@ MessagelistUserStore.removeMessagesFromList = ( unseenCount = 0; } - toFolder.messageCountAll(toFolder.messageCountAll() + uidForRemove.length); + toFolder.totalEmails(toFolder.totalEmails() + uidForRemove.length); if (0 < unseenCount) { - toFolder.messageCountUnread(toFolder.messageCountUnread() + unseenCount); + toFolder.unreadEmails(toFolder.unreadEmails() + unseenCount); } toFolder.actionBlink(true); diff --git a/dev/Styles/User/MessageView.less b/dev/Styles/User/MessageView.less index bdbdbd5c2..e376fc409 100644 --- a/dev/Styles/User/MessageView.less +++ b/dev/Styles/User/MessageView.less @@ -93,7 +93,7 @@ html.rl-no-preview-pane { .messageTags { margin-top: 6px; } - .messageTags * * { + .messageTags span span { border: 1px solid #808080; padding: 2px; } diff --git a/dev/View/Popup/FolderClear.js b/dev/View/Popup/FolderClear.js index 388b0a0d6..50ba247b3 100644 --- a/dev/View/Popup/FolderClear.js +++ b/dev/View/Popup/FolderClear.js @@ -43,8 +43,8 @@ export class FolderClearPopupView extends AbstractViewPopup { this.clearingProcess(true); - folderToClear.messageCountAll(0); - folderToClear.messageCountUnread(0); + folderToClear.totalEmails(0); + folderToClear.unreadEmails(0); setFolderHash(folderToClear.fullName, ''); diff --git a/dev/View/User/MailBox/MessageList.js b/dev/View/User/MailBox/MessageList.js index b49fd1dc9..6c1d6265a 100644 --- a/dev/View/User/MailBox/MessageList.js +++ b/dev/View/User/MailBox/MessageList.js @@ -487,9 +487,9 @@ export class MailMessageList extends AbstractViewRight { }); if (iThreadUid) { - folder.messageCountUnread(Math.max(0, folder.messageCountUnread() - cnt)); + folder.unreadEmails(Math.max(0, folder.unreadEmails() - cnt)); } else { - folder.messageCountUnread(0); + folder.unreadEmails(0); } MessageFlagsCache.clearFolder(sFolderFullName); 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 573634157..7b988da92 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 @@ -103,13 +103,16 @@ trait Folders * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception + * + * https://datatracker.ietf.org/doc/html/rfc9051#section-6.3.11 */ public function FolderStatus(string $sFolderName) : FolderInformation { $aStatusItems = array( FolderResponseStatus::MESSAGES, FolderResponseStatus::UNSEEN, - FolderResponseStatus::UIDNEXT + FolderResponseStatus::UIDNEXT, + FolderResponseStatus::UIDVALIDITY ); if ($this->IsSupported('CONDSTORE')) { $aStatusItems[] = FolderResponseStatus::HIGHESTMODSEQ; @@ -121,10 +124,14 @@ trait Folders $aStatusItems[] = FolderResponseStatus::MAILBOXID; /* } else if ($this->IsSupported('X-DOVECOT')) { - $aFetchItems[] = 'X-GUID'; + $aStatusItems[] = 'X-GUID'; */ } - +/* // STATUS SIZE can take a significant amount of time, therefore not active + if ($this->IsSupported('IMAP4rev2')) { + $aStatusItems[] = FolderResponseStatus::SIZE; + } +*/ $oFolderInfo = $this->oCurrentFolderInfo; $bReselect = false; $bWritable = false; @@ -276,6 +283,9 @@ trait Folders * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception + * + * REQUIRED IMAP4rev2 untagged responses: FLAGS, EXISTS, LIST + * REQUIRED IMAP4rev2 OK untagged responses: PERMANENTFLAGS, UIDNEXT, UIDVALIDITY */ protected function selectOrExamineFolder(string $sFolderName, bool $bIsWritable, bool $bReSelectSameFolders) : FolderInformation { @@ -345,9 +355,6 @@ trait Folders // $oResult->IsWritable = true; } else if ('NOMODSEQ' === $key) { // https://datatracker.ietf.org/doc/html/rfc4551#section-3.1.2 - } else if ('MAILBOXID' === $key) { - // https://www.rfc-editor.org/rfc/rfc8474#section-4.2 - $oResult->MAILBOXID = $oResponse->OptionalResponse[1]; } } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/FolderResponseStatus.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/FolderResponseStatus.php index 6377e96f9..eaabe002e 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/FolderResponseStatus.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/FolderResponseStatus.php @@ -30,4 +30,6 @@ abstract class FolderResponseStatus const APPENDLIMIT = 'APPENDLIMIT'; // RFC 8474 const MAILBOXID = 'MAILBOXID'; + // RFC 9051 IMAP4rev2 + const SIZE = 'SIZE'; } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/MessageFlag.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/MessageFlag.php index e8539d377..798a3412a 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/MessageFlag.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/MessageFlag.php @@ -30,7 +30,7 @@ abstract class MessageFlag // https://datatracker.ietf.org/doc/html/rfc3503 MDNSENT = '$MDNSent', // https://datatracker.ietf.org/doc/html/rfc8457 - DRAFT = '$Important', + IMPORTANT = '$Important', // https://datatracker.ietf.org/doc/html/rfc5788 FORWARDED = '$Forwarded', // https://datatracker.ietf.org/doc/html/rfc9051#section-2.3.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 b5fe6a367..0db148dd9 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 @@ -62,19 +62,27 @@ class FolderInformation implements \JsonSerializable public function jsonSerialize() { - return array( + $result = array( 'id' => $this->MAILBOXID, 'Name' => $this->FolderName, 'Flags' => $this->Flags, 'PermanentFlags' => $this->PermanentFlags, -/* - 'totalEmails' => $this->MESSAGES, - 'unreadEmails' => $this->UNSEEN, - 'UidNext' => $this->UIDNEXT, - 'UidValidity' => $this->UIDVALIDITY, - 'Highestmodseq' => $this->HIGHESTMODSEQ, - 'Appendlimit' => $this->APPENDLIMIT, -*/ + 'UidNext' => $this->UIDNEXT, + 'UidValidity' => $this->UIDVALIDITY ); + if (isset($this->MESSAGES)) { + $result['totalEmails'] = $this->MESSAGES; + $result['unreadEmails'] = $this->UNSEEN; + } + if (isset($this->HIGHESTMODSEQ)) { + $result['Highestmodseq'] = $this->HIGHESTMODSEQ; + } + if (isset($this->HIGHESTMODSEQ)) { + $result['Appendlimit'] = $this->APPENDLIMIT; + } + if (isset($this->SIZE)) { + $result['Size'] = $this->SIZE; + } + return $result; } } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Traits/Status.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Traits/Status.php index 814093894..36ec68828 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Traits/Status.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Traits/Status.php @@ -83,7 +83,14 @@ trait Status * This response also occurs as a result of a CREATE, SELECT or EXAMINE command. * @var string */ - $MAILBOXID; + $MAILBOXID, + + /** + * RFC 9051 + * The total size of the mailbox in octets. + * @var int + */ + $SIZE; public function getStatusItems() : array { @@ -150,7 +157,9 @@ trait Status } // SELECT or EXAMINE command else if (\is_numeric($oResponse->ResponseList[1]) && \is_string($oResponse->ResponseList[2])) { - $bResult = $this->setStatus($oResponse->ResponseList[2], $oResponse->ResponseList[1]); + if ('UNSEEN' !== $oResponse->ResponseList[2]) { + $bResult |= $this->setStatus($oResponse->ResponseList[2], $oResponse->ResponseList[1]); + } } } 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 367f7190a..4916729f3 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 @@ -131,8 +131,7 @@ class MailClient public function MessageSetFlag(string $sFolderName, SequenceSet $oRange, string $sMessageFlag, bool $bSetAction = true, bool $bSkipUnsupportedFlag = false) : void { if (\count($oRange)) { - $oFolderInfo = $this->oImapClient->FolderSelect($sFolderName); - if ($oFolderInfo->IsFlagSupported($sMessageFlag)) { + if ($this->oImapClient->FolderSelect($sFolderName)->IsFlagSupported($sMessageFlag)) { $sStoreAction = $bSetAction ? StoreAction::ADD_FLAGS_SILENT : StoreAction::REMOVE_FLAGS_SILENT; $this->oImapClient->MessageStoreFlag($oRange, array($sMessageFlag), $sStoreAction); } else if (!$bSkipUnsupportedFlag) { @@ -522,11 +521,11 @@ class MailClient public function FolderInformation(string $sFolderName, int $iPrevUidNext = 0, SequenceSet $oRange = null) : array { list($iCount, $iUnseenCount, $iUidNext, $iHighestModSeq, $iAppendLimit, $sMailboxId) = $this->initFolderValues($sFolderName); +// $oInfo = $this->oImapClient->FolderSelect($sFolderName); $aFlags = array(); if ($oRange && \count($oRange)) { $oInfo = $this->oImapClient->FolderExamine($sFolderName); - // $oInfo->PermanentFlags $aFetchResponse = $this->oImapClient->Fetch(array( FetchType::UID, @@ -545,14 +544,16 @@ class MailClient return array( 'Folder' => $sFolderName, - 'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUidNext, $iHighestModSeq), 'totalEmails' => $iCount, 'unreadEmails' => $iUnseenCount, 'UidNext' => $iUidNext, - 'MessagesFlags' => $aFlags, 'HighestModSeq' => $iHighestModSeq, 'AppendLimit' => $iAppendLimit, 'MailboxId' => $sMailboxId, +// 'Flags' => $oInfo->Flags, +// 'PermanentFlags' => $oInfo->PermanentFlags, + 'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUidNext, $iHighestModSeq), + 'MessagesFlags' => $aFlags, 'NewMessages' => $this->getFolderNextMessageInformation($sFolderName, $iPrevUidNext, $iUidNext) ); } @@ -823,21 +824,20 @@ class MailClient $sSearch = \trim($oParams->sSearch); - list($iMessageRealCount, $iMessageUnseenCount, $iUidNext, $iHighestModSeq) = $this->initFolderValues($oParams->sFolderName); - - // Don't use FolderExamine, else PERMANENTFLAGS is empty - $oInfo = $this->oImapClient->FolderSelect($oParams->sFolderName); - $oMessageCollection = new MessageCollection; $oMessageCollection->FolderName = $oParams->sFolderName; - $oMessageCollection->FolderInfo = $oInfo; $oMessageCollection->Offset = $oParams->iOffset; $oMessageCollection->Limit = $oParams->iLimit; $oMessageCollection->Search = $sSearch; $oMessageCollection->ThreadUid = $oParams->iThreadUid; $oMessageCollection->Filtered = '' !== \MailSo\Config::$MessageListPermanentFilter; - $oMessageCollection->totalEmails = $iMessageRealCount; - $oMessageCollection->unreadEmails = $iMessageUnseenCount; + + list($iMessageRealCount, $iMessageUnseenCount, $iUidNext, $iHighestModSeq) = $this->initFolderValues($oParams->sFolderName); + // Don't use FolderExamine, else PERMANENTFLAGS is empty in Dovecot + $oInfo = $this->oImapClient->FolderSelect($oParams->sFolderName); + $oInfo->UNSEEN = $iMessageUnseenCount; + $oInfo->HIGHESTMODSEQ = $iHighestModSeq; + $oMessageCollection->FolderInfo = $oInfo; $aUids = array(); $aAllThreads = []; @@ -858,14 +858,14 @@ class MailClient } $oMessageCollection->FolderHash = $this->GenerateFolderHash( - $oParams->sFolderName, $iMessageRealCount, $iUidNext, $iHighestModSeq); - - $oMessageCollection->UidNext = $iUidNext; + $oParams->sFolderName, $iMessageRealCount, $iUidNext, $oInfo->HIGHESTMODSEQ ?: 0 + ); if (!$oParams->iThreadUid) { $oMessageCollection->NewMessages = $this->getFolderNextMessageInformation( - $oParams->sFolderName, $oParams->iPrevUidNext, $iUidNext); + $oParams->sFolderName, $oParams->iPrevUidNext, $iUidNext + ); } $bSearch = false; @@ -1256,17 +1256,13 @@ class MailClient */ public function FolderClear(string $sFolderFullName) : self { - $oFolderInformation = $this->oImapClient->FolderSelect($sFolderFullName); - if (0 < $oFolderInformation->MESSAGES) - { + if (0 < $this->oImapClient->FolderSelect($sFolderFullName)->MESSAGES) { $this->oImapClient->MessageStoreFlag(new SequenceSet('1:*', false), array(MessageFlag::DELETED), StoreAction::ADD_FLAGS_SILENT ); - $this->oImapClient->FolderExpunge(); } - return $this; } @@ -1275,13 +1271,10 @@ class MailClient */ public function FolderSubscribe(string $sFolderFullName, bool $bSubscribe) : self { - if (!\strlen($sFolderFullName)) - { + if (!\strlen($sFolderFullName)) { throw new \MailSo\Base\Exceptions\InvalidArgumentException; } - $this->oImapClient->{$bSubscribe ? 'FolderSubscribe' : 'FolderUnsubscribe'}($sFolderFullName); - return $this; } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MessageCollection.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MessageCollection.php index 39833a73c..3cb2e990e 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MessageCollection.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MessageCollection.php @@ -22,16 +22,6 @@ class MessageCollection extends \MailSo\Base\Collection */ public $FolderHash = ''; - /** - * @var int - */ - public $totalEmails = 0; - - /** - * @var int - */ - public $unreadEmails = 0; - /** * @var int */ @@ -57,11 +47,6 @@ class MessageCollection extends \MailSo\Base\Collection */ public $Search = ''; - /** - * @var int - */ - public $UidNext = 0; - /** * @var int */ @@ -95,13 +80,10 @@ class MessageCollection extends \MailSo\Base\Collection public function jsonSerialize() { return array_merge(parent::jsonSerialize(), array( - 'totalEmails' => $this->totalEmails, - 'unreadEmails' => $this->unreadEmails, 'MessageResultCount' => $this->MessageResultCount, 'Folder' => $this->FolderName, 'FolderHash' => $this->FolderHash, 'FolderInfo' => $this->FolderInfo, - 'UidNext' => $this->UidNext, 'ThreadUid' => $this->ThreadUid, 'NewMessages' => $this->NewMessages, 'Filtered' => $this->Filtered, diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php index e2829feaf..c53f34942 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php @@ -411,6 +411,11 @@ trait Messages return $this->messageSetFlag(MessageFlag::FLAGGED, __FUNCTION__, true); } + public function DoMessageSetKeyword() : array + { + return $this->messageSetFlag($this->GetActionParam('Keyword', ''), __FUNCTION__, true); + } + /** * @throws \MailSo\Base\Exceptions\Exception */ diff --git a/snappymail/v/0.0.0/app/templates/Views/User/MailMessageView.html b/snappymail/v/0.0.0/app/templates/Views/User/MailMessageView.html index 3d6298e5c..2d049c08a 100644 --- a/snappymail/v/0.0.0/app/templates/Views/User/MailMessageView.html +++ b/snappymail/v/0.0.0/app/templates/Views/User/MailMessageView.html @@ -66,7 +66,7 @@ -