Remove most DoFolders loops as they are not used.

And move system folder detection/autocreate to MailboxDetectPlugin because it is hardly used.
And by using mailbox.role the default system folder detection is only using (IMAP and JMAP) RFC standards.
This commit is contained in:
the-djmaze 2022-12-15 13:49:39 +01:00
parent 8799cd3e8d
commit 54896bf044
18 changed files with 419 additions and 468 deletions

View file

@ -6,7 +6,6 @@ import { mailToHelper, setLayoutResizer, dropdownsDetectVisibility } from 'Commo
import {
FolderType,
SetSystemFoldersNotification,
ClientSideKeyNameFolderListSize
} from 'Common/EnumsUser';
@ -101,27 +100,27 @@ export class AppUser extends AbstractApp {
*/
moveMessagesToFolderType(iFolderType, sFromFolderFullName, oUids, bDelete) {
let oMoveFolder = null,
nSetSystemFoldersNotification = null;
nSetSystemFoldersNotification = 0;
switch (iFolderType) {
case FolderType.Spam:
case FolderType.Junk:
oMoveFolder = getFolderFromCacheList(FolderUserStore.spamFolder());
nSetSystemFoldersNotification = SetSystemFoldersNotification.Spam;
nSetSystemFoldersNotification = iFolderType;
bDelete = bDelete || UNUSED_OPTION_VALUE === FolderUserStore.spamFolder();
break;
case FolderType.NotSpam:
case FolderType.Inbox:
oMoveFolder = getFolderFromCacheList(getFolderInboxName());
break;
case FolderType.Trash:
oMoveFolder = getFolderFromCacheList(FolderUserStore.trashFolder());
nSetSystemFoldersNotification = SetSystemFoldersNotification.Trash;
nSetSystemFoldersNotification = iFolderType;
bDelete = bDelete || UNUSED_OPTION_VALUE === FolderUserStore.trashFolder()
|| sFromFolderFullName === FolderUserStore.spamFolder()
|| sFromFolderFullName === FolderUserStore.trashFolder();
break;
case FolderType.Archive:
oMoveFolder = getFolderFromCacheList(FolderUserStore.archiveFolder());
nSetSystemFoldersNotification = SetSystemFoldersNotification.Archive;
nSetSystemFoldersNotification = iFolderType;
bDelete = bDelete || UNUSED_OPTION_VALUE === FolderUserStore.archiveFolder();
break;
// no default

View file

@ -4,14 +4,27 @@
* @enum {number}
*/
export const FolderType = {
User: 0,
Inbox: 1,
Sent: 2,
Drafts: 3,
Spam: 4, // JUNK
Junk: 4, // Spam
Trash: 5,
Archive: 6,
NotSpam: 80
Archive: 6
/*
IMPORTANT : 10;
FLAGGED : 11;
ALL : 13;
// TODO: SnappyMail
TEMPLATES : 19;
// Kolab
CONFIGURATION : 20;
CALENDAR : 21;
CONTACTS : 22;
TASKS : 23;
NOTES : 24;
FILES : 25;
JOURNAL : 26;
*/
};
/**
@ -41,18 +54,6 @@ export const ComposeType = {
EditAsNew: 6
};
/**
* @enum {number}
*/
export const SetSystemFoldersNotification = {
None: 0,
Sent: 1,
Draft: 2,
Spam: 3,
Trash: 4,
Archive: 5
};
/**
* @enum {number}
*/

View file

@ -37,7 +37,7 @@ const
Inbox: 0,
Sent: 0,
Drafts: 0,
Spam: 0,
Junk: 0, // Spam
Trash: 0,
Archive: 0
},
@ -62,7 +62,7 @@ const
case FolderType.Trash:
case FolderType.Archive:
return i18n('FOLDER_LIST/' + getKeyByValue(FolderType, type).toUpperCase() + '_NAME');
case FolderType.Spam:
case FolderType.Junk:
return i18n('GLOBAL/SPAM');
// no default
}
@ -104,11 +104,11 @@ export class FolderCollectionModel extends AbstractCollectionModel
/*
constructor() {
super();
this.CountRec
this.Namespace;
this.Optimized
this.SystemFolders
this.Capabilities
this.quotaUsage;
this.quotaLimit;
this.namespace;
this.optimized
this.capabilities
}
*/
@ -118,16 +118,13 @@ export class FolderCollectionModel extends AbstractCollectionModel
*/
static reviveFromJson(object) {
const expandedFolders = Local.get(ClientSideKeyNameExpandedFolders);
if (object?.SystemFolders) {
forEachObjectEntry(SystemFolders, key =>
SystemFolders[key] = SettingsGet(key+'Folder') || object.SystemFolders[FolderType[key]]
);
}
forEachObjectEntry(SystemFolders, (key, value) =>
value || (SystemFolders[key] = SettingsGet(key+'Folder'))
);
const result = super.reviveFromJson(object, oFolder => {
let oCacheFolder = getFolderFromCacheList(oFolder.FullName),
type = FolderType[getKeyByValue(SystemFolders, oFolder.FullName)];
let oCacheFolder = getFolderFromCacheList(oFolder.FullName);
if (oCacheFolder) {
// oCacheFolder.revivePropertiesFromJson(oFolder);
if (oFolder.Hash) {
@ -143,17 +140,59 @@ export class FolderCollectionModel extends AbstractCollectionModel
oCacheFolder = FolderModel.reviveFromJson(oFolder);
if (!oCacheFolder)
return null;
if (1 == type) {
oCacheFolder.type(type);
setFolderInboxName(oFolder.FullName);
}
setFolder(oCacheFolder);
}
if (1 < type) {
oCacheFolder.type(type);
// JMAP RFC 8621
let role = oFolder.role;
/*
if (!role) {
// Kolab
let type = oFolder.metadata[FolderMetadataKeys.KolabFolderType]
|| oFolder.metadata[FolderMetadataKeys.KolabFolderTypeShared];
switch (type) {
case 'mail.inbox':
case 'mail.drafts':
role = type.replace('mail.', '');
break;
// case 'mail.outbox':
case 'mail.sentitems':
role = 'sent';
break;
case 'mail.junkemail':
role = 'spam';
break;
case 'mail.wastebasket':
role = 'trash';
break;
}
// Flags
if (oFolder.Flags.includes('\\sentmail')) {
role = 'sent';
}
if (oFolder.Flags.includes('\\spam')) {
role = 'junk';
}
if (oFolder.Flags.includes('\\bin')) {
role = 'trash';
}
if (oFolder.Flags.includes('\\important')) {
role = 'important';
}
if (oFolder.Flags.includes('\\starred')) {
role = 'flagged';
}
if (oFolder.Flags.includes('\\all') || oFolder.Flags.includes('\\allmail')) {
role = 'all';
}
}
*/
if (role) {
role = role[0].toUpperCase() + role.slice(1);
SystemFolders[role] || (SystemFolders[role] = oFolder.FullName);
}
oCacheFolder.type(FolderType[getKeyByValue(SystemFolders, oFolder.FullName)] || 0);
oCacheFolder.collapsed(!expandedFolders
|| !isArray(expandedFolders)
@ -162,12 +201,43 @@ export class FolderCollectionModel extends AbstractCollectionModel
return oCacheFolder;
});
result.CountRec = result.length;
setFolderInboxName(SystemFolders.Inbox);
let i = result.length;
if (i) {
sortFolders(result);
try {
while (i--) {
let folder = result[i], parent = getFolderFromCacheList(folder.parentName);
if (!parent) {
// Create NonExistent parent folders
let delimiter = folder.delimiter;
if (delimiter) {
let parents = folder.fullName.split(delimiter);
parents.pop();
while (parents.length) {
let parentName = parents.join(delimiter),
name = parents.pop(),
pfolder = getFolderFromCacheList(parentName);
if (!pfolder) {
pfolder = FolderModel.reviveFromJson({
'@Object': 'Object/Folder',
Name: name,
FullName: parentName,
Delimiter: delimiter,
Exists: false,
isSubscribed: false,
Flags: ['\\nonexistent']
});
setFolder(pfolder);
result.splice(i, 0, pfolder);
++i;
}
}
parent = getFolderFromCacheList(folder.parentName);
}
}
if (parent) {
parent.subFolders.unshift(folder);
result.splice(i,1);
@ -187,7 +257,7 @@ export class FolderCollectionModel extends AbstractCollectionModel
if (!(
SettingsGet('SentFolder') +
SettingsGet('DraftsFolder') +
SettingsGet('SpamFolder') +
SettingsGet('JunkFolder') +
SettingsGet('TrashFolder') +
SettingsGet('ArchiveFolder')
)
@ -197,21 +267,21 @@ export class FolderCollectionModel extends AbstractCollectionModel
FolderUserStore.folderList(this);
FolderUserStore.namespace = this.Namespace;
FolderUserStore.namespace = this.namespace;
// 'THREAD=REFS', 'THREAD=REFERENCES', 'THREAD=ORDEREDSUBJECT'
AppUserStore.threadsAllowed(!!(
Settings.app('useImapThread') && this.Capabilities.some(capa => capa.startsWith('THREAD='))
Settings.app('useImapThread') && this.capabilities.some(capa => capa.startsWith('THREAD='))
));
FolderUserStore.folderListOptimized(!!this.Optimized);
// FolderUserStore.folderListOptimized(!!this.optimized);
FolderUserStore.quotaUsage(this.quotaUsage);
FolderUserStore.quotaLimit(this.quotaLimit);
FolderUserStore.capabilities(this.Capabilities);
FolderUserStore.capabilities(this.capabilities);
FolderUserStore.sentFolder(normalizeFolder(SystemFolders.Sent));
FolderUserStore.draftsFolder(normalizeFolder(SystemFolders.Drafts));
FolderUserStore.spamFolder(normalizeFolder(SystemFolders.Spam));
FolderUserStore.spamFolder(normalizeFolder(SystemFolders.Junk));
FolderUserStore.trashFolder(normalizeFolder(SystemFolders.Trash));
FolderUserStore.archiveFolder(normalizeFolder(SystemFolders.Archive));
@ -238,7 +308,8 @@ export class FolderModel extends AbstractModel {
addObservablesTo(this, {
name: '',
type: FolderType.User,
type: 0,
role: null,
selectable: false,
focused: false,
@ -345,9 +416,9 @@ export class FolderModel extends AbstractModel {
}
),
canBeEdited: () => FolderType.User === folder.type() && folder.exists/* && folder.selectable()*/,
canBeEdited: () => !folder.type() && folder.exists/* && folder.selectable()*/,
isSystemFolder: () => FolderType.User !== folder.type()
isSystemFolder: () => folder.type()
| (FolderUserStore.allowKolab() && !!folder.kolabType() & !SettingsUserStore.unhideKolabFolders()),
canBeSelected: () => folder.selectable() && !folder.isSystemFolder(),
@ -363,7 +434,7 @@ export class FolderModel extends AbstractModel {
* Or when all below conditions are true:
* - selectable()
* - isSubscribed() OR hideUnsubscribed = false
* - FolderType.User
* - 0 == type()
* - not kolabType()
*/
visible: () => {

View file

@ -117,7 +117,7 @@ FolderUserStore = new class {
const
subscribeRemoveSystemFolder = observable => {
observable.subscribe(() => getFolderFromCacheList(observable())?.type(FolderType.User), self, 'beforeChange');
observable.subscribe(() => getFolderFromCacheList(observable())?.type(0), self, 'beforeChange');
},
fSetSystemFolderType = type => value => getFolderFromCacheList(value)?.type(type);
@ -130,7 +130,7 @@ FolderUserStore = new class {
addSubscribablesTo(self, {
sentFolder: fSetSystemFolderType(FolderType.Sent),
draftsFolder: fSetSystemFolderType(FolderType.Drafts),
spamFolder: fSetSystemFolderType(FolderType.Spam),
spamFolder: fSetSystemFolderType(FolderType.Junk),
trashFolder: fSetSystemFolderType(FolderType.Trash),
archiveFolder: fSetSystemFolderType(FolderType.Archive)
});

View file

@ -8,7 +8,7 @@ import {
import {
ComposeType,
EditorDefaultType,
SetSystemFoldersNotification
FolderType
} from 'Common/EnumsUser';
import { pInt, isArray, arrayLength } from 'Common/Utils';
@ -444,7 +444,7 @@ export class ComposePopupView extends AbstractViewPopup {
}
if (!sSentFolder) {
showScreenPopup(FolderSystemPopupView, [SetSystemFoldersNotification.Sent]);
showScreenPopup(FolderSystemPopupView, [FolderType.Sent]);
} else try {
this.sendError(false);
this.sending(true);
@ -501,7 +501,7 @@ export class ComposePopupView extends AbstractViewPopup {
saveCommand() {
if (FolderUserStore.draftsFolderNotEnabled()) {
showScreenPopup(FolderSystemPopupView, [SetSystemFoldersNotification.Draft]);
showScreenPopup(FolderSystemPopupView, [FolderType.Drafts]);
} else {
this.savedError(false);
this.saving(true);

View file

@ -1,7 +1,7 @@
import ko from 'ko';
import { koComputable, addSubscribablesTo } from 'External/ko';
import { SetSystemFoldersNotification } from 'Common/EnumsUser';
import { FolderType } from 'Common/EnumsUser';
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
import { defaultOptionsAfterRender } from 'Common/Utils';
import { folderListOptionsBuilder } from 'Common/Folders';
@ -47,24 +47,24 @@ export class FolderSystemPopupView extends AbstractViewPopup {
}
/**
* @param {number=} notificationType = SetSystemFoldersNotification.None
* @param {number=} notificationType = 0
*/
onShow(notificationType = SetSystemFoldersNotification.None) {
onShow(notificationType = 0) {
let notification = '', prefix = 'POPUPS_SYSTEM_FOLDERS/NOTIFICATION_';
switch (notificationType) {
case SetSystemFoldersNotification.Sent:
case FolderType.Sent:
notification = i18n(prefix + 'SENT');
break;
case SetSystemFoldersNotification.Draft:
case FolderType.Drafts:
notification = i18n(prefix + 'DRAFTS');
break;
case SetSystemFoldersNotification.Spam:
case FolderType.Junk:
notification = i18n(prefix + 'SPAM');
break;
case SetSystemFoldersNotification.Trash:
case FolderType.Trash:
notification = i18n(prefix + 'TRASH');
break;
case SetSystemFoldersNotification.Archive:
case FolderType.Archive:
notification = i18n(prefix + 'ARCHIVE');
break;
// no default

View file

@ -364,11 +364,11 @@ export class MailMessageList extends AbstractViewRight {
}
spamCommand() {
moveMessagesToFolderType(FolderType.Spam);
moveMessagesToFolderType(FolderType.Junk);
}
notSpamCommand() {
moveMessagesToFolderType(FolderType.NotSpam);
moveMessagesToFolderType(FolderType.Inbox);
}
moveCommand(vm, event) {

View file

@ -220,8 +220,8 @@ export class MailMessageView extends AbstractViewRight {
this.deleteCommand = createCommandActionHelper(FolderType.Trash);
this.deleteWithoutMoveCommand = createCommandActionHelper(FolderType.Trash, true);
this.archiveCommand = createCommandActionHelper(FolderType.Archive);
this.spamCommand = createCommandActionHelper(FolderType.Spam);
this.notSpamCommand = createCommandActionHelper(FolderType.NotSpam);
this.spamCommand = createCommandActionHelper(FolderType.Junk);
this.notSpamCommand = createCommandActionHelper(FolderType.Inbox);
decorateKoCommands(this, {
editCommand: self => self.messageVisibility(),