mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-28 11:39:21 +03:00
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:
parent
8799cd3e8d
commit
54896bf044
18 changed files with 419 additions and 468 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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: () => {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue