diff --git a/dev/App/User.js b/dev/App/User.js index 7469b3d24..7f58132c5 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -596,7 +596,7 @@ class AppUser extends AbstractApp { check = true; const flags = data.Result.Flags[uid]; storeMessageFlagsToCacheByFolderAndUid(folderFromCache.fullNameRaw, uid.toString(), [ - !flags.IsSeen, + !!flags.IsUnseen, !!flags.IsFlagged, !!flags.IsAnswered, !!flags.IsForwarded, diff --git a/dev/Common/Cache.js b/dev/Common/Cache.js index 64b222d50..bf8e39fc2 100644 --- a/dev/Common/Cache.js +++ b/dev/Common/Cache.js @@ -198,14 +198,14 @@ export function initMessageFlagsFromCache(message) { flags = getMessageFlagsFromCache(message.folderFullNameRaw, uid); if (flags && flags.length) { - message.flagged(!!flags[1]); + message.isFlagged(!!flags[1]); if (!message.isSimpleMessage) { - message.unseen(!!flags[0]); - message.answered(!!flags[2]); - message.forwarded(!!flags[3]); + message.isUnseen(!!flags[0]); + message.isAnswered(!!flags[2]); + message.isForwarded(!!flags[3]); message.isReadReceipt(!!flags[4]); - message.deletedMark(!!flags[5]); + message.isDeleted(!!flags[5]); } } @@ -238,12 +238,12 @@ export function initMessageFlagsFromCache(message) { export function storeMessageFlagsToCache(message) { if (message) { setMessageFlagsToCache(message.folderFullNameRaw, message.uid, [ - message.unseen(), - message.flagged(), - message.answered(), - message.forwarded(), + message.isUnseen(), + message.isFlagged(), + message.isAnswered(), + message.isForwarded(), message.isReadReceipt(), - message.deletedMark() + message.isDeleted() ]); } } diff --git a/dev/Knoin/AbstractModel.js b/dev/Knoin/AbstractModel.js index 72df00560..afb84793a 100644 --- a/dev/Knoin/AbstractModel.js +++ b/dev/Knoin/AbstractModel.js @@ -9,10 +9,14 @@ function typeCast(current, value) { switch (typeof current) { case 'boolean': return !!value; - case 'string': return null != value ? '' + value : ''; - case 'number': - value = parseInt(value, 10); - return (isNaN(value) || !isFinite(value)) ? 0 : value; + case 'number': return isFinite(value) ? parseFloat(value) : 0; + case 'string': return null != value ? '' + value : ''; + case 'object': + if (current.constructor.reviveFromJson) { + return current.constructor.reviveFromJson(value) || undefined; + } + if (!Array.isArray(current) || !Array.isArray(value)) + return undefined; } return value; } @@ -26,7 +30,7 @@ export class AbstractModel { constructor() { /* if (new.target === AbstractModel) { - throw new Error("Can't instantiate abstract class!"); + throw new Error("Can't instantiate AbstractModel!"); } this.sModelName = new.target.name; */ @@ -63,34 +67,53 @@ export class AbstractModel { */ static reviveFromJson(json) { let obj = this.validJson(json) ? new this() : null; + obj && obj.revivePropertiesFromJson(json); + return obj; + } + + revivePropertiesFromJson(json) { + let model = this.constructor; try { - obj && Object.entries(json).forEach(([key, value]) => { + if (!model.validJson(json)) { + return false; + } + Object.entries(json).forEach(([key, value]) => { if ('@' !== key[0]) { key = key[0].toLowerCase() + key.substr(1); - switch (typeof obj[key]) + switch (typeof this[key]) { case 'function': - if (ko.isObservable(obj[key]) && !ko.isObservableArray(obj[key])) { - obj[key](typeCast(obj[key](), value)); + if (ko.isObservable(this[key])) { + value = typeCast(this[key](), value); + if (undefined !== value) { + this[key](value); + break; + } +// console.log((typeof this[key]())+' '+(model.name)+'.'+key+' not revived'); } -// else { console.log('('+(typeof obj[key])+') '+key+' not revived'); } +// else console.log(model.name + '.' + key + ' is a function'); break; case 'boolean': - case 'string': case 'number': - obj[key] = typeCast(obj[key], value); - break; -// case 'undefined': -// default: -// console.log('('+(typeof obj[key])+') '+key+' not revived'); + case 'object': + case 'string': + value = typeCast(this[key], value); + if (undefined !== value) { + this[key] = value; + break; + } + // fall through + case 'undefined': + default: +// console.log((typeof this[key])+' '+(model.name)+'.'+key+' not revived'); } } }); } catch (e) { - console.log(this.name); + console.log(model.name); console.error(e); } - return obj; + return true; } } diff --git a/dev/Model/AbstractCollection.js b/dev/Model/AbstractCollection.js index 65a7f3d5a..285ec275f 100644 --- a/dev/Model/AbstractCollection.js +++ b/dev/Model/AbstractCollection.js @@ -1,15 +1,13 @@ export class AbstractCollectionModel extends Array { - constructor(props) { + constructor() { /* - if (new.target === Parent) { - throw new Error("Can't instantiate abstract class!"); + if (new.target === AbstractCollectionModel) { + throw new Error("Can't instantiate AbstractCollectionModel!"); } */ super(); - props && Object.entries(props).forEach(([key, value]) => '@' !== key[0] && (this[key] = value)); -// props[@Count] } /** @@ -18,18 +16,22 @@ export class AbstractCollectionModel extends Array * @returns {*CollectionModel} */ static reviveFromJson(json, itemCallback) { - // FolderCollectionModel => FolderCollection - // AttachmentCollectionModel => AttachmentCollection - // MessageCollectionModel => MessageCollection - if (json && 'Collection/'+this.name.replace('Model', '') === json['@Object'] - && Array.isArray(json['@Collection'])) { - const result = new this(json); - json['@Collection'].forEach(item => { - item && itemCallback && (item = itemCallback(item, result)); - item && result.push(item); - }); - return result; + if (json) { + const result = new this(); + 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 (Array.isArray(json)) { + json.forEach(item => { + item && itemCallback && (item = itemCallback(item, result)); + item && result.push(item); + }); + return result; + } } + return null; } } diff --git a/dev/Model/AttachmentCollection.js b/dev/Model/AttachmentCollection.js index 9fe193e10..36a97534b 100644 --- a/dev/Model/AttachmentCollection.js +++ b/dev/Model/AttachmentCollection.js @@ -10,16 +10,7 @@ export class AttachmentCollectionModel extends AbstractCollectionModel * @returns {AttachmentCollectionModel} */ static reviveFromJson(items) { - let cb = attachment => AttachmentModel.reviveFromJson(attachment), - result = super.reviveFromJson(items, cb); - if (!result) { - result = new AttachmentCollectionModel; - Array.isArray(items) && items.forEach(attachment => { - attachment = cb(attachment); - attachment && result.push(attachment); - }); - } - return result; + return super.reviveFromJson(items, attachment => AttachmentModel.reviveFromJson(attachment)); } /** diff --git a/dev/Model/EmailCollection.js b/dev/Model/EmailCollection.js index cd3b28782..a79feaa83 100644 --- a/dev/Model/EmailCollection.js +++ b/dev/Model/EmailCollection.js @@ -10,12 +10,7 @@ export class EmailCollectionModel extends AbstractCollectionModel * @returns {EmailCollectionModel} */ static reviveFromJson(items) { - let result = new EmailCollectionModel; - Array.isArray(items) && items.forEach(email => { - email = EmailModel.reviveFromJson(email); - email && result.push(email); - }); - return result; + return super.reviveFromJson(items, email => EmailModel.reviveFromJson(email)); } /** diff --git a/dev/Model/Folder.js b/dev/Model/Folder.js index f4473bcfe..7603e3dfd 100644 --- a/dev/Model/Folder.js +++ b/dev/Model/Folder.js @@ -5,6 +5,7 @@ import { isPosNumeric } from 'Common/UtilsUser'; import { i18n, trigger as translatorTrigger } from 'Common/Translator'; import { AbstractModel } from 'Knoin/AbstractModel'; +import { FolderCollectionModel } from 'Model/FolderCollection'; class FolderModel extends AbstractModel { constructor() { @@ -29,7 +30,7 @@ class FolderModel extends AbstractModel { this.edited = ko.observable(false); this.subScribed = ko.observable(true); this.checkable = ko.observable(false); - this.subFolders = ko.observableArray([]); + this.subFolders = ko.observableArray(new FolderCollectionModel); this.deleteAccess = ko.observable(false); this.actionBlink = ko.observable(false).extend({ falseTimeout: 1000 }); diff --git a/dev/Model/FolderCollection.js b/dev/Model/FolderCollection.js index 2f6f3b804..a72a8990a 100644 --- a/dev/Model/FolderCollection.js +++ b/dev/Model/FolderCollection.js @@ -47,6 +47,12 @@ export class FolderCollectionModel extends AbstractCollectionModel bDisplaySpecSetting = FolderStore.displaySpecSetting(); return super.reviveFromJson(object, (oFolder, self) => { let oCacheFolder = Cache.getFolderFromCacheList(oFolder.FullNameRaw); +/* + if (oCacheFolder) { + oFolder.SubFolders = FolderCollectionModel.reviveFromJson(oFolder.SubFolders); + oFolder.SubFolders && oCacheFolder.subFolders(oFolder.SubFolders); + } +*/ if (!oCacheFolder && (oCacheFolder = FolderModel.reviveFromJson(oFolder))) { if (oFolder.FullNameRaw == self.SystemFolders[ServerFolderType.INBOX]) { oCacheFolder.type(FolderType.Inbox); @@ -75,10 +81,6 @@ export class FolderCollectionModel extends AbstractCollectionModel oCacheFolder.messageCountUnread(oFolder.Extended.MessageUnseenCount); } } - - oFolder.SubFolders = FolderCollectionModel.reviveFromJson(oFolder.SubFolders); - oFolder.SubFolders && oCacheFolder.subFolders(oFolder.SubFolders); - } return oCacheFolder; }); diff --git a/dev/Model/Message.js b/dev/Model/Message.js index f2dc5ea65..e534fd731 100644 --- a/dev/Model/Message.js +++ b/dev/Model/Message.js @@ -3,13 +3,11 @@ import ko from 'ko'; import { MessagePriority, SignedVerifyStatus } from 'Common/Enums'; import { i18n } from 'Common/Translator'; -import { pInt } from 'Common/Utils'; import { encodeHtml } from 'Common/UtilsUser'; import { messageViewLink, messageDownloadLink } from 'Common/Links'; import FolderStore from 'Stores/User/Folder'; -import PgpStore from 'Stores/User/Pgp'; import { File } from 'Common/File'; import { AttachmentCollectionModel } from 'Model/AttachmentCollection'; @@ -40,22 +38,17 @@ class MessageModel extends AbstractModel { this.dateTimeStampInUTC = ko.observable(0); this.priority = ko.observable(MessagePriority.Normal); - this.fromEmailString = ko.observable(''); - this.fromClearEmailString = ko.observable(''); - this.toEmailsString = ko.observable(''); - this.toClearEmailsString = ko.observable(''); - this.senderEmailsString = ko.observable(''); this.senderClearEmailsString = ko.observable(''); this.newForAnimation = ko.observable(false); this.deleted = ko.observable(false); - this.deletedMark = ko.observable(false); - this.unseen = ko.observable(false); - this.flagged = ko.observable(false); - this.answered = ko.observable(false); - this.forwarded = ko.observable(false); + this.isDeleted = ko.observable(false); + this.isUnseen = ko.observable(false); + this.isFlagged = ko.observable(false); + this.isAnswered = ko.observable(false); + this.isForwarded = ko.observable(false); this.isReadReceipt = ko.observable(false); this.focused = ko.observable(false); @@ -91,52 +84,12 @@ class MessageModel extends AbstractModel { this.regDisposables([this.attachmentIconClass, this.threadsLen, this.isImportant]); } - /** - * @static - * @param {FetchJsonMessage} json - * @returns {?MessageModel} - */ - static reviveFromJson(json) { - const oMessageModel = super.reviveFromJson(json); - if (oMessageModel) { - oMessageModel.folderFullNameRaw = json.Folder; - - oMessageModel.from = EmailCollectionModel.reviveFromJson(json.From); - oMessageModel.to = EmailCollectionModel.reviveFromJson(json.To); - oMessageModel.cc = EmailCollectionModel.reviveFromJson(json.Cc); - oMessageModel.bcc = EmailCollectionModel.reviveFromJson(json.Bcc); - oMessageModel.replyTo = EmailCollectionModel.reviveFromJson(json.ReplyTo); - oMessageModel.deliveredTo = EmailCollectionModel.reviveFromJson(json.DeliveredTo); - oMessageModel.unsubsribeLinks = Array.isNotEmpty(json.UnsubsribeLinks) ? json.UnsubsribeLinks : []; - - if (isArray(json.SubjectParts)) { - oMessageModel.subjectPrefix(json.SubjectParts[0]); - oMessageModel.subjectSuffix(json.SubjectParts[1]); - } else { - oMessageModel.subjectPrefix(''); - oMessageModel.subjectSuffix(oMessageModel.subject()); - } - - oMessageModel.fromEmailString(oMessageModel.from.toString(true)); - oMessageModel.fromClearEmailString(oMessageModel.from.toStringClear()); - oMessageModel.toEmailsString(oMessageModel.to.toString(true)); - oMessageModel.toClearEmailsString(oMessageModel.to.toStringClear()); - - oMessageModel.threads(isArray(json.Threads) ? json.Threads : []); - - oMessageModel.setFromJson(json); - oMessageModel.initFlagsByJson(json); - oMessageModel.computeSenderEmail(); - } - return oMessageModel; - } - _reset() { - this.folderFullNameRaw = ''; + this.folder = ''; this.uid = ''; this.hash = ''; this.requestHash = ''; - this.proxy = false; + this.externalProxy = false; this.emails = []; this.from = new EmailCollectionModel; this.to = new EmailCollectionModel; @@ -146,10 +99,10 @@ class MessageModel extends AbstractModel { this.deliveredTo = new EmailCollectionModel; this.unsubsribeLinks = []; this.body = null; - this.aDraftInfo = []; - this.sMessageId = ''; - this.sInReplyTo = ''; - this.sReferences = ''; + this.draftInfo = []; + this.messageId = ''; + this.inReplyTo = ''; + this.references = ''; } clear() { @@ -161,21 +114,17 @@ class MessageModel extends AbstractModel { this.dateTimeStampInUTC(0); this.priority(MessagePriority.Normal); - this.fromEmailString(''); - this.fromClearEmailString(''); - this.toEmailsString(''); - this.toClearEmailsString(''); this.senderEmailsString(''); this.senderClearEmailsString(''); this.newForAnimation(false); this.deleted(false); - this.deletedMark(false); - this.unseen(false); - this.flagged(false); - this.answered(false); - this.forwarded(false); + this.isDeleted(false); + this.isUnseen(false); + this.isFlagged(false); + this.isAnswered(false); + this.isForwarded(false); this.isReadReceipt(false); this.selected(false); @@ -219,65 +168,34 @@ class MessageModel extends AbstractModel { } computeSenderEmail() { - const sentFolder = FolderStore.sentFolder(), - draftFolder = FolderStore.draftFolder(); - - this.senderEmailsString( - this.folderFullNameRaw === sentFolder || this.folderFullNameRaw === draftFolder - ? this.toEmailsString() - : this.fromEmailString() - ); - - this.senderClearEmailsString( - this.folderFullNameRaw === sentFolder || this.folderFullNameRaw === draftFolder - ? this.toClearEmailsString() - : this.fromClearEmailString() - ); - } - - setFromJson(json) { - let result = MessageModel.validJson(json); - if (result) { - let priority = pInt(json.Priority); - this.priority( - [MessagePriority.High, MessagePriority.Low].includes(priority) ? priority : MessagePriority.Normal - ); - - this.proxy = !!json.ExternalProxy; - - this.hasAttachments(!!json.HasAttachments); - this.attachmentsSpecData(isArray(json.AttachmentsSpecData) ? json.AttachmentsSpecData : []); - } - return result; + const list = [FolderStore.sentFolder(), FolderStore.draftFolder()].includes(this.folder) ? 'to' : 'from'; + this.senderEmailsString(this[list].toString(true)); + this.senderClearEmailsString(this[list].toStringClear()); } /** * @param {FetchJsonMessage} json * @returns {boolean} */ - initUpdateByMessageJson(json) { - let result = this.setFromJson(json); - if (result) { - this.aDraftInfo = json.DraftInfo; - - this.sMessageId = json.MessageId; - this.sInReplyTo = json.InReplyTo; - this.sReferences = json.References; - - if (PgpStore.capaOpenPGP()) { - this.isPgpSigned(!!json.PgpSigned); - this.isPgpEncrypted(!!json.PgpEncrypted); + revivePropertiesFromJson(json) { + if ('Priority' in json) { + let p = parseInt(json.Priority, 10); + json.Priority = MessagePriority.High == p || MessagePriority.Low == p ? p : MessagePriority.Normal; + } + if (super.revivePropertiesFromJson(json)) { + if (isArray(json.SubjectParts)) { + this.subjectPrefix(json.SubjectParts[0]); + this.subjectSuffix(json.SubjectParts[1]); + } else { + this.subjectPrefix(''); + this.subjectSuffix(this.subject()); } // this.foundedCIDs = isArray(json.FoundedCIDs) ? json.FoundedCIDs : []; // this.attachments(AttachmentCollectionModel.reviveFromJson(json.Attachments, this.foundedCIDs)); - this.attachments(AttachmentCollectionModel.reviveFromJson(json.Attachments)); - - this.readReceipt(json.ReadReceipt || ''); this.computeSenderEmail(); } - return result; } /** @@ -294,23 +212,6 @@ class MessageModel extends AbstractModel { return this.unsubsribeLinks && this.unsubsribeLinks.length ? this.unsubsribeLinks[0] || '' : ''; } - /** - * @param {FetchJsonMessage} json - * @returns {boolean} - */ - initFlagsByJson(json) { - let result = MessageModel.validJson(json); - if (result) { - this.unseen(!json.IsSeen); - this.flagged(!!json.IsFlagged); - this.answered(!!json.IsAnswered); - this.forwarded(!!json.IsForwarded); - this.isReadReceipt(!!json.IsReadReceipt); - this.deletedMark(!!json.IsDeleted); - } - return result; - } - /** * @param {boolean} friendlyView * @param {boolean=} wrapWithLink = false @@ -375,13 +276,13 @@ class MessageModel extends AbstractModel { let classes = []; Object.entries({ 'deleted': this.deleted(), - 'deleted-mark': this.deletedMark(), + 'deleted-mark': this.isDeleted(), 'selected': this.selected(), 'checked': this.checked(), - 'flagged': this.flagged(), - 'unseen': this.unseen(), - 'answered': this.answered(), - 'forwarded': this.forwarded(), + 'flagged': this.isFlagged(), + 'unseen': this.isUnseen(), + 'answered': this.isAnswered(), + 'forwarded': this.isForwarded(), 'focused': this.focused(), 'important': this.isImportant(), 'withAttachments': this.hasAttachments(), @@ -394,27 +295,6 @@ class MessageModel extends AbstractModel { return classes.join(' '); } - /** - * @returns {string} - */ - messageId() { - return this.sMessageId; - } - - /** - * @returns {string} - */ - inReplyTo() { - return this.sInReplyTo; - } - - /** - * @returns {string} - */ - references() { - return this.sReferences; - } - /** * @returns {string} */ @@ -522,7 +402,7 @@ class MessageModel extends AbstractModel { * @returns {string} */ generateUid() { - return this.folderFullNameRaw + '/' + this.uid; + return this.folder + '/' + this.uid; } /** @@ -531,7 +411,7 @@ class MessageModel extends AbstractModel { */ populateByMessageListItem(message) { if (message) { - this.folderFullNameRaw = message.folderFullNameRaw; + this.folder = message.folder; this.uid = message.uid; this.hash = message.hash; this.requestHash = message.requestHash; @@ -546,12 +426,7 @@ class MessageModel extends AbstractModel { this.dateTimeStampInUTC(message.dateTimeStampInUTC()); this.priority(message.priority()); - this.proxy = message.proxy; - - this.fromEmailString(message.fromEmailString()); - this.fromClearEmailString(message.fromClearEmailString()); - this.toEmailsString(message.toEmailsString()); - this.toClearEmailsString(message.toClearEmailsString()); + this.externalProxy = message.externalProxy; this.emails = message.emails; @@ -563,12 +438,12 @@ class MessageModel extends AbstractModel { this.deliveredTo = message.deliveredTo; this.unsubsribeLinks = message.unsubsribeLinks; - this.unseen(message.unseen()); - this.flagged(message.flagged()); - this.answered(message.answered()); - this.forwarded(message.forwarded()); + this.isUnseen(message.isUnseen()); + this.isFlagged(message.isFlagged()); + this.isAnswered(message.isAnswered()); + this.isForwarded(message.isForwarded()); this.isReadReceipt(message.isReadReceipt()); - this.deletedMark(message.deletedMark()); + this.isDeleted(message.isDeleted()); this.priority(message.priority()); @@ -580,10 +455,10 @@ class MessageModel extends AbstractModel { this.body = null; - this.aDraftInfo = []; - this.sMessageId = ''; - this.sInReplyTo = ''; - this.sReferences = ''; + this.draftInfo = []; + this.messageId = ''; + this.inReplyTo = ''; + this.references = ''; if (message) { this.threads(message.threads()); @@ -599,7 +474,7 @@ class MessageModel extends AbstractModel { this.hasImages(false); this.body.rlHasImages = false; - let body = this.body, attr = this.proxy ? 'data-x-additional-src' : 'data-x-src'; + let body = this.body, attr = this.externalProxy ? 'data-x-additional-src' : 'data-x-src'; body.querySelectorAll('[' + attr + ']').forEach(node => { if (node.matches('img')) { node.loading = 'lazy'; @@ -608,7 +483,7 @@ class MessageModel extends AbstractModel { node.removeAttribute('data-loaded'); }); - attr = this.proxy ? 'data-x-additional-style-url' : 'data-x-style-url'; + attr = this.externalProxy ? 'data-x-additional-style-url' : 'data-x-style-url'; body.querySelectorAll('[' + attr + ']').forEach(node => { node.setAttribute('style', ((node.getAttribute('style')||'') + ';' + node.getAttribute(attr)) @@ -691,11 +566,11 @@ class MessageModel extends AbstractModel { flagHash() { return [ this.deleted(), - this.deletedMark(), - this.unseen(), - this.flagged(), - this.answered(), - this.forwarded(), + this.isDeleted(), + this.isUnseen(), + this.isFlagged(), + this.isAnswered(), + this.isForwarded(), this.isReadReceipt() ].join(','); } diff --git a/dev/Model/MessageCollection.js b/dev/Model/MessageCollection.js index de5b4b384..d529c5601 100644 --- a/dev/Model/MessageCollection.js +++ b/dev/Model/MessageCollection.js @@ -38,7 +38,7 @@ export class MessageCollectionModel extends AbstractCollectionModel return super.reviveFromJson(object, message => { message = MessageModel.reviveFromJson(message); if (message) { - if (hasNewMessageAndRemoveFromCache(message.folderFullNameRaw, message.uid) && 5 >= newCount) { + if (hasNewMessageAndRemoveFromCache(message.folder, message.uid) && 5 >= newCount) { ++newCount; message.newForAnimation(true); } diff --git a/dev/Remote/User/Fetch.js b/dev/Remote/User/Fetch.js index e8d19222b..507dd7ccf 100644 --- a/dev/Remote/User/Fetch.js +++ b/dev/Remote/User/Fetch.js @@ -432,13 +432,13 @@ class RemoteUserFetch extends AbstractFetchRemote { if (Array.isNotEmpty(list)) { request = false; list.forEach(messageListItem => { - if (!getMessageFlagsFromCache(messageListItem.folderFullNameRaw, messageListItem.uid)) { + if (!getMessageFlagsFromCache(messageListItem.folder, messageListItem.uid)) { uids.push(messageListItem.uid); } if (messageListItem.threads().length) { messageListItem.threads().forEach(uid => { - if (!getMessageFlagsFromCache(messageListItem.folderFullNameRaw, uid)) { + if (!getMessageFlagsFromCache(messageListItem.folder, uid)) { uids.push(uid); } }); @@ -779,28 +779,28 @@ class RemoteUserFetch extends AbstractFetchRemote { folderDelete(sFolderFullNameRaw, fTrigger) { return this.postRequest('FolderDelete', fTrigger, { - 'Folder': sFolderFullNameRaw + Folder: sFolderFullNameRaw }); } folderCreate(sNewFolderName, sParentName, fTrigger) { return this.postRequest('FolderCreate', fTrigger, { - 'Folder': sNewFolderName, - 'Parent': sParentName + Folder: sNewFolderName, + Parent: sParentName }); } folderRename(sPrevFolderFullNameRaw, sNewFolderName, fTrigger) { return this.postRequest('FolderRename', fTrigger, { - 'Folder': sPrevFolderFullNameRaw, - 'NewFolderName': sNewFolderName + Folder: sPrevFolderFullNameRaw, + NewFolderName: sNewFolderName }); } attachmentsActions(sAction, aHashes, fTrigger) { return this.postRequest('AttachmentsActions', fTrigger, { - 'Do': sAction, - 'Hashes': aHashes + Do: sAction, + Hashes: aHashes }); } } diff --git a/dev/Stores/User/Message.js b/dev/Stores/User/Message.js index 52ace5a40..4eb3b96cc 100644 --- a/dev/Stores/User/Message.js +++ b/dev/Stores/User/Message.js @@ -205,7 +205,7 @@ class MessageUserStore { this.messageListEndFolder.subscribe(folder => { const message = this.message(); - if (message && folder && folder !== message.folderFullNameRaw) { + if (message && folder && folder !== message.folder) { this.message(null); } }); @@ -295,7 +295,7 @@ class MessageUserStore { : []; messages.forEach(item => { - if (item && item.unseen()) { + if (item && item.isUnseen()) { ++unseenCount; } }); @@ -442,6 +442,7 @@ class MessageUserStore { setMessage(data, cached) { let isNew = false, body = null, + json = data && data.Result, id = '', plain = '', resultHtml = '', @@ -451,14 +452,14 @@ class MessageUserStore { message = this.message(); if ( - data && - MessageModel.validJson(data.Result) && + json && + MessageModel.validJson(json) && message && - message.folderFullNameRaw === data.Result.Folder + message.folder === json.Folder ) { const threads = message.threads(); - if (message.uid !== data.Result.Uid && 1 < threads.length && threads.includes(data.Result.Uid)) { - message = MessageModel.reviveFromJson(data.Result); + if (message.uid !== json.Uid && 1 < threads.length && threads.includes(json.Uid)) { + message = MessageModel.reviveFromJson(json); if (message) { message.threads(threads); initMessageFlagsFromCache(message); @@ -470,16 +471,21 @@ class MessageUserStore { } } - if (message && message.uid === data.Result.Uid) { + if (message && message.uid === json.Uid) { this.messageError(''); - message.initUpdateByMessageJson(data.Result); - addRequestedMessage(message.folderFullNameRaw, message.uid); - - if (!cached) { - message.initFlagsByJson(data.Result); + if (cached) { + delete json.IsSeen; + delete json.IsFlagged; + delete json.IsAnswered; + delete json.IsForwarded; + delete json.IsReadReceipt; + delete json.IsDeleted; } + message.revivePropertiesFromJson(json); + addRequestedMessage(message.folder, message.uid); + if (messagesDom) { id = 'rl-mgs-' + message.hash.replace(/[^a-zA-Z0-9]/g, ''); @@ -490,15 +496,15 @@ class MessageUserStore { message.body = textBody; } else { let isHtml = false; - if (data.Result.Html) { + if (json.Html) { isHtml = true; - resultHtml = data.Result.Html.toString(); - } else if (data.Result.Plain) { + resultHtml = json.Html.toString(); + } else if (json.Plain) { isHtml = false; - resultHtml = plainToHtml(data.Result.Plain.toString()); + resultHtml = plainToHtml(json.Plain.toString()); if ((message.isPgpSigned() || message.isPgpEncrypted()) && PgpStore.capaOpenPGP()) { - plain = pString(data.Result.Plain); + plain = pString(json.Plain); const isPgpEncrypted = /---BEGIN PGP MESSAGE---/.test(plain); if (!isPgpEncrypted) { @@ -544,13 +550,13 @@ class MessageUserStore { message.body = body; message.isHtml(!!isHtml); - message.hasImages(!!data.Result.HasExternals); + message.hasImages(!!json.HasExternals); messagesDom.append(body); message.storeDataInDom(); - if (data.Result.HasInternals) { + if (json.HasInternals) { message.showInternalImages(); } @@ -575,8 +581,8 @@ class MessageUserStore { } initMessageFlagsFromCache(message); - if (message.unseen() || message.hasUnseenSubMessage()) { - rl.app.messageListAction(message.folderFullNameRaw, MessageSetAction.SetSeen, [message]); + if (message.isUnseen() || message.hasUnseenSubMessage()) { + rl.app.messageListAction(message.folder, MessageSetAction.SetSeen, [message]); } if (isNew) { @@ -585,7 +591,7 @@ class MessageUserStore { if ( selectedMessage && message && - (message.folderFullNameRaw !== selectedMessage.folderFullNameRaw || message.uid !== selectedMessage.uid) + (message.folder !== selectedMessage.folder || message.uid !== selectedMessage.uid) ) { this.selectorMessageSelected(null); if (1 === this.messageList().length) { @@ -595,7 +601,7 @@ class MessageUserStore { selectedMessage = this.messageList().find( subMessage => subMessage && - subMessage.folderFullNameRaw === message.folderFullNameRaw && + subMessage.folder === message.folder && subMessage.uid === message.uid ); @@ -621,7 +627,7 @@ class MessageUserStore { selectMessageByFolderAndUid(sFolder, sUid) { if (sFolder && sUid) { this.message(this.staticMessage.populateByMessageListItem(null)); - this.message().folderFullNameRaw = sFolder; + this.message().folder = sFolder; this.message().uid = sUid; this.populateMessageBody(this.message()); @@ -631,10 +637,8 @@ class MessageUserStore { } populateMessageBody(oMessage) { - if (oMessage) { - if (Remote.message(this.onMessageResponse, oMessage.folderFullNameRaw, oMessage.uid)) { - this.messageCurrentLoading(true); - } + if (oMessage && Remote.message(this.onMessageResponse, oMessage.folder, oMessage.uid)) { + this.messageCurrentLoading(true); } } diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js index 514b30f7c..094e787dc 100644 --- a/dev/View/Popup/Compose.js +++ b/dev/View/Popup/Compose.js @@ -643,7 +643,7 @@ class ComposePopupView extends AbstractViewNext { if (this.bFromDraft) { const message = MessageStore.message(); - if (message && this.draftFolder() === message.folderFullNameRaw && this.draftUid() === message.uid) { + if (message && this.draftFolder() === message.folder && this.draftUid() === message.uid) { MessageStore.message(null); } } @@ -905,7 +905,7 @@ class ComposePopupView extends AbstractViewNext { this.to(this.emailArrayToStringLineHelper(message.replyEmails(excludeEmail))); this.subject(replySubjectAdd('Re', sSubject)); this.prepareMessageAttachments(message, lineComposeType); - this.aDraftInfo = ['reply', message.uid, message.folderFullNameRaw]; + this.aDraftInfo = ['reply', message.uid, message.folder]; this.sInReplyTo = message.sMessageId; this.sReferences = (this.sInReplyTo + ' ' + message.sReferences).trim(); break; @@ -916,15 +916,15 @@ class ComposePopupView extends AbstractViewNext { this.cc(this.emailArrayToStringLineHelper(resplyAllParts[1])); this.subject(replySubjectAdd('Re', sSubject)); this.prepareMessageAttachments(message, lineComposeType); - this.aDraftInfo = ['reply', message.uid, message.folderFullNameRaw]; + this.aDraftInfo = ['reply', message.uid, message.folder]; this.sInReplyTo = message.sMessageId; - this.sReferences = (this.sInReplyTo + ' ' + message.references()).trim(); + this.sReferences = (this.sInReplyTo + ' ' + message.references).trim(); break; case ComposeType.Forward: this.subject(replySubjectAdd('Fwd', sSubject)); this.prepareMessageAttachments(message, lineComposeType); - this.aDraftInfo = ['forward', message.uid, message.folderFullNameRaw]; + this.aDraftInfo = ['forward', message.uid, message.folder]; this.sInReplyTo = message.sMessageId; this.sReferences = (this.sInReplyTo + ' ' + message.sReferences).trim(); break; @@ -932,7 +932,7 @@ class ComposePopupView extends AbstractViewNext { case ComposeType.ForwardAsAttachment: this.subject(replySubjectAdd('Fwd', sSubject)); this.prepareMessageAttachments(message, lineComposeType); - this.aDraftInfo = ['forward', message.uid, message.folderFullNameRaw]; + this.aDraftInfo = ['forward', message.uid, message.folder]; this.sInReplyTo = message.sMessageId; this.sReferences = (this.sInReplyTo + ' ' + message.sReferences).trim(); break; @@ -945,7 +945,7 @@ class ComposePopupView extends AbstractViewNext { this.bFromDraft = true; - this.draftFolder(message.folderFullNameRaw); + this.draftFolder(message.folder); this.draftUid(message.uid); this.subject(sSubject); diff --git a/dev/View/User/MailBox/MessageList.js b/dev/View/User/MailBox/MessageList.js index 22537ba12..5a663cec0 100644 --- a/dev/View/User/MailBox/MessageList.js +++ b/dev/View/User/MailBox/MessageList.js @@ -230,7 +230,7 @@ class MessageListMailBoxUserView extends AbstractViewNext { const sFolder = e.detail.Folder, sUid = e.detail.Uid; const message = this.messageList().find( - item => item && sFolder === item.folderFullNameRaw && sUid === item.uid + item => item && sFolder === item.folder && sUid === item.uid ); if ('INBOX' === sFolder) { @@ -503,11 +503,11 @@ class MessageListMailBoxUserView extends AbstractViewNext { folder = getFolderFromCacheList(sFolderFullNameRaw); if (folder) { MessageStore.messageList().forEach(message => { - if (message.unseen()) { + if (message.isUnseen()) { ++cnt; } - message.unseen(false); + message.isUnseen(false); uids.push(message.uid); }); @@ -529,11 +529,11 @@ class MessageListMailBoxUserView extends AbstractViewNext { folder = getFolderFromCacheList(sFolderFullNameRaw); if (folder) { MessageStore.messageList().forEach(message => { - if (!message.unseen()) { + if (!message.isUnseen()) { ++cnt; } - message.unseen(true); + message.isUnseen(true); uids.push(message.uid); }); @@ -605,14 +605,14 @@ class MessageListMailBoxUserView extends AbstractViewNext { const checkedUids = checked.map(message => message.uid); if (checkedUids.includes(currentMessage.uid)) { this.setAction( - currentMessage.folderFullNameRaw, - currentMessage.flagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, + currentMessage.folder, + currentMessage.isFlagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, checked ); } else { this.setAction( - currentMessage.folderFullNameRaw, - currentMessage.flagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, + currentMessage.folder, + currentMessage.isFlagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, [currentMessage] ); } @@ -623,15 +623,15 @@ class MessageListMailBoxUserView extends AbstractViewNext { const checked = this.messageListCheckedOrSelected(); if (checked.length) { if (undefined === bFlag) { - const flagged = checked.filter(message => message.flagged()); + const flagged = checked.filter(message => message.isFlagged()); this.setAction( - checked[0].folderFullNameRaw, + checked[0].folder, checked.length === flagged.length ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, checked ); } else { this.setAction( - checked[0].folderFullNameRaw, + checked[0].folder, !bFlag ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, checked ); @@ -643,15 +643,15 @@ class MessageListMailBoxUserView extends AbstractViewNext { const checked = this.messageListCheckedOrSelected(); if (checked.length) { if (undefined === seen) { - const unseen = checked.filter(message => message.unseen()); + const unseen = checked.filter(message => message.isUnseen()); this.setAction( - checked[0].folderFullNameRaw, + checked[0].folder, unseen.length ? MessageSetAction.SetSeen : MessageSetAction.UnsetSeen, checked ); } else { this.setAction( - checked[0].folderFullNameRaw, + checked[0].folder, seen ? MessageSetAction.SetSeen : MessageSetAction.UnsetSeen, checked ); @@ -875,12 +875,12 @@ class MessageListMailBoxUserView extends AbstractViewNext { prefetchNextTick() { if (ifvisible && !this.bPrefetch && !ifvisible.now() && this.viewModelVisible) { const message = this.messageList().find( - item => item && !hasRequestedMessage(item.folderFullNameRaw, item.uid) + item => item && !hasRequestedMessage(item.folder, item.uid) ); if (message) { this.bPrefetch = true; - addRequestedMessage(message.folderFullNameRaw, message.uid); + addRequestedMessage(message.folder, message.uid); Remote.message( (result, data) => { @@ -890,7 +890,7 @@ class MessageListMailBoxUserView extends AbstractViewNext { next && this.prefetchNextTick(); }, 1000); }, - message.folderFullNameRaw, + message.folder, message.uid ); } diff --git a/dev/View/User/MailBox/MessageView.js b/dev/View/User/MailBox/MessageView.js index b3ef6ec36..015613a89 100644 --- a/dev/View/User/MailBox/MessageView.js +++ b/dev/View/User/MailBox/MessageView.js @@ -60,7 +60,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext { const message = this.message(); if (message && this.allowMessageListActions) { this.message(null); - rl.app.deleteMessagesFromFolder(folderType, message.folderFullNameRaw, [message.uid], useFolder); + rl.app.deleteMessagesFromFolder(folderType, message.folder, [message.uid], useFolder); } }, this.messageVisibility); @@ -226,7 +226,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext { this.scrollMessageToTop(); } - this.viewFolder = message.folderFullNameRaw; + this.viewFolder = message.folder; this.viewUid = message.uid; this.viewHash = message.hash; this.viewSubject(message.subject()); @@ -245,7 +245,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext { this.viewUnsubscribeLink(message.getFirstUnsubsribeLink()); this.viewDownloadLink(message.downloadLink()); this.viewIsImportant(message.isImportant()); - this.viewIsFlagged(message.flagged()); + this.viewIsFlagged(message.isFlagged()); } else { this.viewFolder = ''; this.viewUid = ''; @@ -257,7 +257,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext { this.message.viewTrigger.subscribe(() => { const message = this.message(); - message ? this.viewIsFlagged(message.flagged()) : this.viewIsFlagged(false); + message ? this.viewIsFlagged(message.isFlagged()) : this.viewIsFlagged(false); }); this.fullScreenMode.subscribe(value => $htmlCL.toggle('rl-message-fullscreen', value)); @@ -467,8 +467,8 @@ class MessageViewMailBoxUserView extends AbstractViewNext { // eslint-disable-line prefer-arrow-callback const message = this.message(); message && rl.app.messageListAction( - message.folderFullNameRaw, - message.flagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, + message.folder, + message.isFlagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, [message] ); } @@ -479,7 +479,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext { const message = ko.dataFor(el); // eslint-disable-line no-invalid-this message && message.folder && message.uid && rl.app.messageListAction( message.folder, - message.flagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, + message.isFlagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag, [message] ); @@ -639,21 +639,21 @@ class MessageViewMailBoxUserView extends AbstractViewNext { * @returns {boolean} */ isDraftFolder() { - return MessageStore.message() && FolderStore.draftFolder() === MessageStore.message().folderFullNameRaw; + return MessageStore.message() && FolderStore.draftFolder() === MessageStore.message().folder; } /** * @returns {boolean} */ isSentFolder() { - return MessageStore.message() && FolderStore.sentFolder() === MessageStore.message().folderFullNameRaw; + return MessageStore.message() && FolderStore.sentFolder() === MessageStore.message().folder; } /** * @returns {boolean} */ isSpamFolder() { - return MessageStore.message() && FolderStore.spamFolder() === MessageStore.message().folderFullNameRaw; + return MessageStore.message() && FolderStore.spamFolder() === MessageStore.message().folder; } /** @@ -667,7 +667,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext { * @returns {boolean} */ isArchiveFolder() { - return MessageStore.message() && FolderStore.archiveFolder() === MessageStore.message().folderFullNameRaw; + return MessageStore.message() && FolderStore.archiveFolder() === MessageStore.message().folder; } /** @@ -762,7 +762,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext { if (oMessage && oMessage.readReceipt()) { Remote.sendReadReceiptMessage( ()=>{}, - oMessage.folderFullNameRaw, + oMessage.folder, oMessage.uid, oMessage.readReceipt(), i18n('READ_RECEIPT/SUBJECT', { 'SUBJECT': oMessage.subject() }), diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Message.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Message.php index 176c1626b..f3f2b8fc4 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Message.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Message.php @@ -255,12 +255,12 @@ class Message implements \JsonSerializable return $this->sPgpSignature; } - public function PgpSigned() : bool + public function isPgpSigned() : bool { return $this->bPgpSigned; } - public function PgpEncrypted() : bool + public function isPgpEncrypted() : bool { return $this->bPgpEncrypted; } @@ -420,11 +420,6 @@ class Message implements \JsonSerializable $this->aThreads = $aThreads; } - public function TextPartIsTrimmed() : bool - { - return $this->bTextPartIsTrimmed; - } - public static function NewFetchResponseInstance(string $sFolder, \MailSo\Imap\FetchResponse $oFetchResponse, ?\MailSo\Imap\BodyStructure $oBodyStructure = null) : self { return (new self)->InitByFetchResponse($sFolder, $oFetchResponse, $oBodyStructure); @@ -771,13 +766,13 @@ class Message implements \JsonSerializable 'Threads' => $this->Threads(), 'Sensitivity' => $this->Sensitivity(), 'UnsubsribeLinks' => $this->UnsubsribeLinks(), - 'ExternalProxy' => false, 'ReadReceipt' => '', 'HasAttachments' => $oAttachments ? 0 < $oAttachments->Count() : false, 'AttachmentsSpecData' => $oAttachments ? $oAttachments->SpecData() : array(), // Flags + 'IsUnseen' => \in_array('\\unseen', $aFlags) || !\in_array('\\seen', $aFlags), 'IsSeen' => \in_array('\\seen', $aFlags), 'IsFlagged' => \in_array('\\flagged', $aFlags), 'IsAnswered' => \in_array('\\answered', $aFlags), 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 343f715b7..d3c374490 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 @@ -372,6 +372,7 @@ trait Folders { $aLowerFlags = array_map('strtolower', $aFlags); $aInboxInformation['Flags'][$iUid] = array( + 'IsUnseen' => \in_array('\\unseen', $aLowerFlags) || !\in_array('\\seen', $aLowerFlags), 'IsSeen' => in_array('\\seen', $aLowerFlags), 'IsFlagged' => in_array('\\flagged', $aLowerFlags), 'IsAnswered' => in_array('\\answered', $aLowerFlags), diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php index f9328afd9..a5ae265d9 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Response.php @@ -195,6 +195,11 @@ trait Response { if (!($mResponse instanceof \JsonSerializable)) { + if (\is_object($mResponse)) + { + return '["'.\get_class($mResponse).'"]'; + } + if (\is_array($mResponse)) { foreach ($mResponse as $iKey => $oItem) @@ -203,11 +208,6 @@ trait Response } } - if (\is_object($mResponse)) - { - return '["'.\get_class($mResponse).'"]'; - } - return $mResponse; } @@ -256,8 +256,6 @@ trait Response $mResult['IsReadReceipt'] = true; } - $mResult['TextPartIsTrimmed'] = false; - if ('Message' === $sParent) { $oAttachments = /* @var \MailSo\Mail\AttachmentCollection */ $mResponse->Attachments(); @@ -323,10 +321,8 @@ trait Response $mResult['TextHash'] = \md5($mResult['Html'].$mResult['Plain']); - $mResult['TextPartIsTrimmed'] = $mResponse->TextPartIsTrimmed(); - - $mResult['PgpSigned'] = $mResponse->PgpSigned(); - $mResult['PgpEncrypted'] = $mResponse->PgpEncrypted(); + $mResult['isPgpSigned'] = $mResponse->isPgpSigned(); + $mResult['isPgpEncrypted'] = $mResponse->isPgpEncrypted(); $mResult['PgpSignature'] = $mResponse->PgpSignature(); unset($sHtml, $sPlain);