diff --git a/dev/Common/Enums.js b/dev/Common/Enums.js index faf45d482..d2e5cffba 100644 --- a/dev/Common/Enums.js +++ b/dev/Common/Enums.js @@ -304,7 +304,7 @@ 'EqualTo': 'EqualTo', 'NotEqualTo': 'NotEqualTo' }; - + /** * @enum {string} */ diff --git a/dev/Model/Filter.js b/dev/Model/Filter.js index 4845ce01b..f4ce8a11c 100644 --- a/dev/Model/Filter.js +++ b/dev/Model/Filter.js @@ -23,6 +23,8 @@ this.enabled = ko.observable(true); + this.id = ''; + this.name = ko.observable(''); this.name.error = ko.observable(false); this.name.focused = ko.observable(false); @@ -33,6 +35,7 @@ // Actions this.actionValue = ko.observable(''); this.actionMarkAsRead = ko.observable(false); + this.actionSkipOthers = ko.observable(false); this.actionType = ko.observable(Enums.FiltersAction.Move); @@ -74,18 +77,27 @@ _.extend(FilterModel.prototype, AbstractModel.prototype); + FilterModel.prototype.generateID = function () + { + this.id = Utils.fakeMd5(); + }; + FilterModel.prototype.toJson = function () { return { + 'ID': this.id, 'Enabled': this.enabled(), 'Name': this.name(), 'ConditionsType': this.conditionsType(), 'Conditions': _.map(this.conditions(), function (oItem) { return oItem.toJson(); }), - 'ActionMarkAsRead': this.actionMarkAsRead(), + 'ActionValue': this.actionValue(), - 'ActionType': this.actionType() + 'ActionType': this.actionType(), + + 'MarkAsRead': this.actionMarkAsRead() ? '1' : '0', + 'SkipOthers': this.actionSkipOthers() ? '1' : '0' }; }; @@ -105,6 +117,7 @@ var bResult = false; if (oItem && 'Object/Filter' === oItem['@Object']) { + this.ID = Utils.pString(oItem['ID']); this.name(Utils.pString(oItem['Name'])); bResult = true; @@ -117,6 +130,8 @@ { var oClone = new FilterModel(); + oClone.ID = this.ID; + oClone.enabled(this.enabled()); oClone.name(this.name()); @@ -125,6 +140,8 @@ oClone.conditionsType(this.conditionsType()); oClone.actionMarkAsRead(this.actionMarkAsRead()); + oClone.actionSkipOthers(this.actionSkipOthers()); + oClone.actionValue(this.actionValue()); oClone.actionType(this.actionType()); diff --git a/dev/Model/FilterCondition.js b/dev/Model/FilterCondition.js index 4f6660d5c..b3239a309 100644 --- a/dev/Model/FilterCondition.js +++ b/dev/Model/FilterCondition.js @@ -13,7 +13,6 @@ ; /** - * @param {*} oKoList * @constructor */ function FilterConditionModel() diff --git a/dev/Model/Message.js b/dev/Model/Message.js index f9061c895..1ae8201f6 100644 --- a/dev/Model/Message.js +++ b/dev/Model/Message.js @@ -22,8 +22,8 @@ ; /** - * @constructor - */ + * @constructor + */ function MessageModel() { AbstractModel.call(this, 'MessageModel'); @@ -91,9 +91,9 @@ case 'doc': sClass = 'icon-file-text'; break; - // case 'pdf': - // sClass = 'icon-file-pdf'; - // break; +// case 'pdf': +// sClass = 'icon-file-pdf'; +// break; } } return sClass; @@ -144,16 +144,21 @@ return 0 === this.parentUid() && 0 < iCount ? iCount + 1 : ''; }, this); - this.regDisposables([this.attachmentIconClass, this.fullFormatDateValue, this.threadsLenResult]); + this.isImportant = ko.computed(function () { + return Enums.MessagePriority.High === this.priority(); + }, this); + + this.regDisposables([this.attachmentIconClass, this.fullFormatDateValue, + this.threadsLenResult, this.isImportant]); } _.extend(MessageModel.prototype, AbstractModel.prototype); /** - * @static - * @param {AjaxJsonMessage} oJsonMessage - * @return {?MessageModel} - */ + * @static + * @param {AjaxJsonMessage} oJsonMessage + * @return {?MessageModel} + */ MessageModel.newInstanceFromJson = function (oJsonMessage) { var oMessageModel = new MessageModel(); @@ -161,29 +166,29 @@ }; /** - * @static - * @param {number} iTimeStampInUTC - * @return {string} - */ + * @static + * @param {number} iTimeStampInUTC + * @return {string} + */ MessageModel.calculateFullFromatDateValue = function (iTimeStampInUTC) { return 0 < iTimeStampInUTC ? moment.unix(iTimeStampInUTC).format('LLL') : ''; }; /** - * @static - * @param {Array} aEmail - * @param {boolean=} bFriendlyView - * @param {boolean=} bWrapWithLink = false - * @return {string} - */ + * @static + * @param {Array} aEmail + * @param {boolean=} bFriendlyView + * @param {boolean=} bWrapWithLink = false + * @return {string} + */ MessageModel.emailsToLine = function (aEmail, bFriendlyView, bWrapWithLink) { var aResult = [], iIndex = 0, iLen = 0 - ; + ; if (Utils.isNonEmptyArray(aEmail)) { @@ -197,17 +202,17 @@ }; /** - * @static - * @param {Array} aEmail - * @return {string} - */ + * @static + * @param {Array} aEmail + * @return {string} + */ MessageModel.emailsToLineClear = function (aEmail) { var aResult = [], iIndex = 0, iLen = 0 - ; + ; if (Utils.isNonEmptyArray(aEmail)) { @@ -224,10 +229,10 @@ }; /** - * @static - * @param {?Array} aJsonEmails - * @return {Array.} - */ + * @static + * @param {?Array} aJsonEmails + * @return {Array.} + */ MessageModel.initEmailsFromJson = function (aJsonEmails) { var @@ -235,7 +240,7 @@ iLen = 0, oEmailModel = null, aResult = [] - ; + ; if (Utils.isNonEmptyArray(aJsonEmails)) { @@ -253,101 +258,101 @@ }; /** - * @static - * @param {Array.} aMessageEmails - * @param {Object} oLocalUnic - * @param {Array} aLocalEmails - */ + * @static + * @param {Array.} aMessageEmails + * @param {Object} oLocalUnic + * @param {Array} aLocalEmails + */ MessageModel.replyHelper = function (aMessageEmails, oLocalUnic, aLocalEmails) { - if (aMessageEmails && 0 < aMessageEmails.length) - { - var - iIndex = 0, - iLen = aMessageEmails.length - ; + if (aMessageEmails && 0 < aMessageEmails.length) + { + var + iIndex = 0, + iLen = aMessageEmails.length + ; - for (; iIndex < iLen; iIndex++) - { - if (Utils.isUnd(oLocalUnic[aMessageEmails[iIndex].email])) - { - oLocalUnic[aMessageEmails[iIndex].email] = true; - aLocalEmails.push(aMessageEmails[iIndex]); - } - } - } + for (; iIndex < iLen; iIndex++) + { + if (Utils.isUnd(oLocalUnic[aMessageEmails[iIndex].email])) + { + oLocalUnic[aMessageEmails[iIndex].email] = true; + aLocalEmails.push(aMessageEmails[iIndex]); + } + } + } }; MessageModel.prototype.clear = function () { - this.folderFullNameRaw = ''; - this.uid = ''; - this.hash = ''; - this.requestHash = ''; - this.subject(''); - this.subjectPrefix(''); - this.subjectSuffix(''); - this.size(0); - this.dateTimeStampInUTC(0); - this.priority(Enums.MessagePriority.Normal); + this.folderFullNameRaw = ''; + this.uid = ''; + this.hash = ''; + this.requestHash = ''; + this.subject(''); + this.subjectPrefix(''); + this.subjectSuffix(''); + this.size(0); + this.dateTimeStampInUTC(0); + this.priority(Enums.MessagePriority.Normal); - this.proxy = false; + this.proxy = false; - this.fromEmailString(''); - this.fromClearEmailString(''); - this.toEmailsString(''); - this.toClearEmailsString(''); - this.senderEmailsString(''); - this.senderClearEmailsString(''); + this.fromEmailString(''); + this.fromClearEmailString(''); + this.toEmailsString(''); + this.toClearEmailsString(''); + this.senderEmailsString(''); + this.senderClearEmailsString(''); - this.emails = []; + this.emails = []; - this.from = []; - this.to = []; - this.cc = []; - this.bcc = []; - this.replyTo = []; - this.deliveredTo = []; + this.from = []; + this.to = []; + this.cc = []; + this.bcc = []; + this.replyTo = []; + this.deliveredTo = []; - this.newForAnimation(false); + this.newForAnimation(false); - this.deleted(false); - this.unseen(false); - this.flagged(false); - this.answered(false); - this.forwarded(false); - this.isReadReceipt(false); + this.deleted(false); + this.unseen(false); + this.flagged(false); + this.answered(false); + this.forwarded(false); + this.isReadReceipt(false); - this.selected(false); - this.checked(false); - this.hasAttachments(false); - this.attachmentsMainType(''); + this.selected(false); + this.checked(false); + this.hasAttachments(false); + this.attachmentsMainType(''); - this.body = null; - this.isHtml(false); - this.hasImages(false); - this.attachments([]); + this.body = null; + this.isHtml(false); + this.hasImages(false); + this.attachments([]); - this.isPgpSigned(false); - this.isPgpEncrypted(false); - this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.None); - this.pgpSignedVerifyUser(''); + this.isPgpSigned(false); + this.isPgpEncrypted(false); + this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.None); + this.pgpSignedVerifyUser(''); - this.priority(Enums.MessagePriority.Normal); - this.readReceipt(''); - this.aDraftInfo = []; - this.sMessageId = ''; - this.sInReplyTo = ''; - this.sReferences = ''; + this.priority(Enums.MessagePriority.Normal); + this.readReceipt(''); + this.aDraftInfo = []; + this.sMessageId = ''; + this.sInReplyTo = ''; + this.sReferences = ''; - this.parentUid(0); - this.threads([]); - this.threadsLen(0); - this.hasUnseenSubMessage(false); - this.hasFlaggedSubMessage(false); + this.parentUid(0); + this.threads([]); + this.threadsLen(0); + this.hasUnseenSubMessage(false); + this.hasFlaggedSubMessage(false); - this.lastInCollapsedThread(false); - this.lastInCollapsedThreadLoading(false); + this.lastInCollapsedThread(false); + this.lastInCollapsedThreadLoading(false); }; /** @@ -374,737 +379,748 @@ }; /** - * @param {AjaxJsonMessage} oJsonMessage - * @return {boolean} - */ + * @param {AjaxJsonMessage} oJsonMessage + * @return {boolean} + */ MessageModel.prototype.initByJson = function (oJsonMessage) { - var bResult = false; - if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object']) - { - this.folderFullNameRaw = oJsonMessage.Folder; - this.uid = oJsonMessage.Uid; - this.hash = oJsonMessage.Hash; - this.requestHash = oJsonMessage.RequestHash; + var + bResult = false, + iPriority = Enums.MessagePriority.Normal + ; - this.proxy = !!oJsonMessage.ExternalProxy; + if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object']) + { + iPriority = Utils.pInt(oJsonMessage.Priority); + this.priority(-1 < Utils.inArray(iPriority, [Enums.MessagePriority.High, Enums.MessagePriority.Low]) ? + iPriority : Enums.MessagePriority.Normal); - this.size(Utils.pInt(oJsonMessage.Size)); + this.folderFullNameRaw = oJsonMessage.Folder; + this.uid = oJsonMessage.Uid; + this.hash = oJsonMessage.Hash; + this.requestHash = oJsonMessage.RequestHash; - this.from = MessageModel.initEmailsFromJson(oJsonMessage.From); - this.to = MessageModel.initEmailsFromJson(oJsonMessage.To); - this.cc = MessageModel.initEmailsFromJson(oJsonMessage.Cc); - this.bcc = MessageModel.initEmailsFromJson(oJsonMessage.Bcc); - this.replyTo = MessageModel.initEmailsFromJson(oJsonMessage.ReplyTo); - this.deliveredTo = MessageModel.initEmailsFromJson(oJsonMessage.DeliveredTo); + this.proxy = !!oJsonMessage.ExternalProxy; - this.subject(oJsonMessage.Subject); - if (Utils.isArray(oJsonMessage.SubjectParts)) - { - this.subjectPrefix(oJsonMessage.SubjectParts[0]); - this.subjectSuffix(oJsonMessage.SubjectParts[1]); - } - else - { - this.subjectPrefix(''); - this.subjectSuffix(this.subject()); - } + this.size(Utils.pInt(oJsonMessage.Size)); - this.dateTimeStampInUTC(Utils.pInt(oJsonMessage.DateTimeStampInUTC)); - this.hasAttachments(!!oJsonMessage.HasAttachments); - this.attachmentsMainType(oJsonMessage.AttachmentsMainType); + this.from = MessageModel.initEmailsFromJson(oJsonMessage.From); + this.to = MessageModel.initEmailsFromJson(oJsonMessage.To); + this.cc = MessageModel.initEmailsFromJson(oJsonMessage.Cc); + this.bcc = MessageModel.initEmailsFromJson(oJsonMessage.Bcc); + this.replyTo = MessageModel.initEmailsFromJson(oJsonMessage.ReplyTo); + this.deliveredTo = MessageModel.initEmailsFromJson(oJsonMessage.DeliveredTo); - this.fromEmailString(MessageModel.emailsToLine(this.from, true)); - this.fromClearEmailString(MessageModel.emailsToLineClear(this.from)); - this.toEmailsString(MessageModel.emailsToLine(this.to, true)); - this.toClearEmailsString(MessageModel.emailsToLineClear(this.to)); + this.subject(oJsonMessage.Subject); + if (Utils.isArray(oJsonMessage.SubjectParts)) + { + this.subjectPrefix(oJsonMessage.SubjectParts[0]); + this.subjectSuffix(oJsonMessage.SubjectParts[1]); + } + else + { + this.subjectPrefix(''); + this.subjectSuffix(this.subject()); + } - this.parentUid(Utils.pInt(oJsonMessage.ParentThread)); - this.threads(Utils.isArray(oJsonMessage.Threads) ? oJsonMessage.Threads : []); - this.threadsLen(Utils.pInt(oJsonMessage.ThreadsLen)); + this.dateTimeStampInUTC(Utils.pInt(oJsonMessage.DateTimeStampInUTC)); + this.hasAttachments(!!oJsonMessage.HasAttachments); + this.attachmentsMainType(oJsonMessage.AttachmentsMainType); - this.initFlagsByJson(oJsonMessage); - this.computeSenderEmail(); + this.fromEmailString(MessageModel.emailsToLine(this.from, true)); + this.fromClearEmailString(MessageModel.emailsToLineClear(this.from)); + this.toEmailsString(MessageModel.emailsToLine(this.to, true)); + this.toClearEmailsString(MessageModel.emailsToLineClear(this.to)); - bResult = true; - } + this.parentUid(Utils.pInt(oJsonMessage.ParentThread)); + this.threads(Utils.isArray(oJsonMessage.Threads) ? oJsonMessage.Threads : []); + this.threadsLen(Utils.pInt(oJsonMessage.ThreadsLen)); - return bResult; + this.initFlagsByJson(oJsonMessage); + this.computeSenderEmail(); + + bResult = true; + } + + return bResult; }; /** - * @param {AjaxJsonMessage} oJsonMessage - * @return {boolean} - */ + * @param {AjaxJsonMessage} oJsonMessage + * @return {boolean} + */ MessageModel.prototype.initUpdateByMessageJson = function (oJsonMessage) { - var - bResult = false, - Data = require('Storage/User/Data'), - iPriority = Enums.MessagePriority.Normal - ; + var + bResult = false, + Data = require('Storage/User/Data'), + iPriority = Enums.MessagePriority.Normal + ; - if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object']) - { - iPriority = Utils.pInt(oJsonMessage.Priority); - this.priority(-1 < Utils.inArray(iPriority, [Enums.MessagePriority.High, Enums.MessagePriority.Low]) ? - iPriority : Enums.MessagePriority.Normal); + if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object']) + { + iPriority = Utils.pInt(oJsonMessage.Priority); + this.priority(-1 < Utils.inArray(iPriority, [Enums.MessagePriority.High, Enums.MessagePriority.Low]) ? + iPriority : Enums.MessagePriority.Normal); - this.aDraftInfo = oJsonMessage.DraftInfo; + this.aDraftInfo = oJsonMessage.DraftInfo; - this.sMessageId = oJsonMessage.MessageId; - this.sInReplyTo = oJsonMessage.InReplyTo; - this.sReferences = oJsonMessage.References; + this.sMessageId = oJsonMessage.MessageId; + this.sInReplyTo = oJsonMessage.InReplyTo; + this.sReferences = oJsonMessage.References; - this.proxy = !!oJsonMessage.ExternalProxy; + this.proxy = !!oJsonMessage.ExternalProxy; - if (Data.capaOpenPGP()) - { - this.isPgpSigned(!!oJsonMessage.PgpSigned); - this.isPgpEncrypted(!!oJsonMessage.PgpEncrypted); - } + if (Data.capaOpenPGP()) + { + this.isPgpSigned(!!oJsonMessage.PgpSigned); + this.isPgpEncrypted(!!oJsonMessage.PgpEncrypted); + } - this.hasAttachments(!!oJsonMessage.HasAttachments); - this.attachmentsMainType(oJsonMessage.AttachmentsMainType); + this.hasAttachments(!!oJsonMessage.HasAttachments); + this.attachmentsMainType(oJsonMessage.AttachmentsMainType); - this.foundedCIDs = Utils.isArray(oJsonMessage.FoundedCIDs) ? oJsonMessage.FoundedCIDs : []; - this.attachments(this.initAttachmentsFromJson(oJsonMessage.Attachments)); + this.foundedCIDs = Utils.isArray(oJsonMessage.FoundedCIDs) ? oJsonMessage.FoundedCIDs : []; + this.attachments(this.initAttachmentsFromJson(oJsonMessage.Attachments)); - this.readReceipt(oJsonMessage.ReadReceipt || ''); + this.readReceipt(oJsonMessage.ReadReceipt || ''); - this.computeSenderEmail(); + this.computeSenderEmail(); - bResult = true; - } + bResult = true; + } - return bResult; + return bResult; }; /** - * @param {(AjaxJsonAttachment|null)} oJsonAttachments - * @return {Array} - */ + * @param {(AjaxJsonAttachment|null)} oJsonAttachments + * @return {Array} + */ MessageModel.prototype.initAttachmentsFromJson = function (oJsonAttachments) { - var - iIndex = 0, - iLen = 0, - oAttachmentModel = null, - aResult = [] - ; + var + iIndex = 0, + iLen = 0, + oAttachmentModel = null, + aResult = [] + ; - if (oJsonAttachments && 'Collection/AttachmentCollection' === oJsonAttachments['@Object'] && - Utils.isNonEmptyArray(oJsonAttachments['@Collection'])) - { - for (iIndex = 0, iLen = oJsonAttachments['@Collection'].length; iIndex < iLen; iIndex++) - { - oAttachmentModel = AttachmentModel.newInstanceFromJson(oJsonAttachments['@Collection'][iIndex]); - if (oAttachmentModel) - { - if ('' !== oAttachmentModel.cidWithOutTags && 0 < this.foundedCIDs.length && - 0 <= Utils.inArray(oAttachmentModel.cidWithOutTags, this.foundedCIDs)) - { - oAttachmentModel.isLinked = true; - } + if (oJsonAttachments && 'Collection/AttachmentCollection' === oJsonAttachments['@Object'] && + Utils.isNonEmptyArray(oJsonAttachments['@Collection'])) + { + for (iIndex = 0, iLen = oJsonAttachments['@Collection'].length; iIndex < iLen; iIndex++) + { + oAttachmentModel = AttachmentModel.newInstanceFromJson(oJsonAttachments['@Collection'][iIndex]); + if (oAttachmentModel) + { + if ('' !== oAttachmentModel.cidWithOutTags && 0 < this.foundedCIDs.length && + 0 <= Utils.inArray(oAttachmentModel.cidWithOutTags, this.foundedCIDs)) + { + oAttachmentModel.isLinked = true; + } - aResult.push(oAttachmentModel); - } - } - } + aResult.push(oAttachmentModel); + } + } + } - return aResult; + return aResult; }; /** - * @param {AjaxJsonMessage} oJsonMessage - * @return {boolean} - */ + * @param {AjaxJsonMessage} oJsonMessage + * @return {boolean} + */ MessageModel.prototype.initFlagsByJson = function (oJsonMessage) { - var bResult = false; + var bResult = false; - if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object']) - { - this.unseen(!oJsonMessage.IsSeen); - this.flagged(!!oJsonMessage.IsFlagged); - this.answered(!!oJsonMessage.IsAnswered); - this.forwarded(!!oJsonMessage.IsForwarded); - this.isReadReceipt(!!oJsonMessage.IsReadReceipt); + if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object']) + { + this.unseen(!oJsonMessage.IsSeen); + this.flagged(!!oJsonMessage.IsFlagged); + this.answered(!!oJsonMessage.IsAnswered); + this.forwarded(!!oJsonMessage.IsForwarded); + this.isReadReceipt(!!oJsonMessage.IsReadReceipt); - bResult = true; - } + bResult = true; + } - return bResult; + return bResult; }; /** - * @param {boolean} bFriendlyView - * @param {boolean=} bWrapWithLink = false - * @return {string} - */ + * @param {boolean} bFriendlyView + * @param {boolean=} bWrapWithLink = false + * @return {string} + */ MessageModel.prototype.fromToLine = function (bFriendlyView, bWrapWithLink) { - return MessageModel.emailsToLine(this.from, bFriendlyView, bWrapWithLink); + return MessageModel.emailsToLine(this.from, bFriendlyView, bWrapWithLink); }; /** - * @param {boolean} bFriendlyView - * @param {boolean=} bWrapWithLink = false - * @return {string} - */ + * @param {boolean} bFriendlyView + * @param {boolean=} bWrapWithLink = false + * @return {string} + */ MessageModel.prototype.toToLine = function (bFriendlyView, bWrapWithLink) { - return MessageModel.emailsToLine(this.to, bFriendlyView, bWrapWithLink); + return MessageModel.emailsToLine(this.to, bFriendlyView, bWrapWithLink); }; /** - * @param {boolean} bFriendlyView - * @param {boolean=} bWrapWithLink = false - * @return {string} - */ + * @param {boolean} bFriendlyView + * @param {boolean=} bWrapWithLink = false + * @return {string} + */ MessageModel.prototype.ccToLine = function (bFriendlyView, bWrapWithLink) { - return MessageModel.emailsToLine(this.cc, bFriendlyView, bWrapWithLink); + return MessageModel.emailsToLine(this.cc, bFriendlyView, bWrapWithLink); }; /** - * @param {boolean} bFriendlyView - * @param {boolean=} bWrapWithLink = false - * @return {string} - */ + * @param {boolean} bFriendlyView + * @param {boolean=} bWrapWithLink = false + * @return {string} + */ MessageModel.prototype.bccToLine = function (bFriendlyView, bWrapWithLink) { - return MessageModel.emailsToLine(this.bcc, bFriendlyView, bWrapWithLink); + return MessageModel.emailsToLine(this.bcc, bFriendlyView, bWrapWithLink); }; /** - * @return string - */ + * @return string + */ MessageModel.prototype.lineAsCcc = function () { - var aResult = []; - if (this.deleted()) - { - aResult.push('deleted'); - } - if (this.selected()) - { - aResult.push('selected'); - } - if (this.checked()) - { - aResult.push('checked'); - } - if (this.flagged()) - { - aResult.push('flagged'); - } - if (this.unseen()) - { - aResult.push('unseen'); - } - if (this.answered()) - { - aResult.push('answered'); - } - if (this.forwarded()) - { - aResult.push('forwarded'); - } - if (this.focused()) - { - aResult.push('focused'); - } - if (this.hasAttachments()) - { - aResult.push('withAttachments'); - switch (this.attachmentsMainType()) - { - case 'image': - aResult.push('imageOnlyAttachments'); - break; - case 'archive': - aResult.push('archiveOnlyAttachments'); - break; - } - } - if (this.newForAnimation()) - { - aResult.push('new'); - } - if ('' === this.subject()) - { - aResult.push('emptySubject'); - } - if (0 < this.parentUid()) - { - aResult.push('hasParentMessage'); - } - if (0 < this.threadsLen() && 0 === this.parentUid()) - { - aResult.push('hasChildrenMessage'); - } - if (this.hasUnseenSubMessage()) - { - aResult.push('hasUnseenSubMessage'); - } - if (this.hasFlaggedSubMessage()) - { - aResult.push('hasFlaggedSubMessage'); - } + var aResult = []; + if (this.deleted()) + { + aResult.push('deleted'); + } + if (this.selected()) + { + aResult.push('selected'); + } + if (this.checked()) + { + aResult.push('checked'); + } + if (this.flagged()) + { + aResult.push('flagged'); + } + if (this.unseen()) + { + aResult.push('unseen'); + } + if (this.answered()) + { + aResult.push('answered'); + } + if (this.forwarded()) + { + aResult.push('forwarded'); + } + if (this.focused()) + { + aResult.push('focused'); + } + if (this.hasAttachments()) + { + aResult.push('withAttachments'); + switch (this.attachmentsMainType()) + { + case 'image': + aResult.push('imageOnlyAttachments'); + break; + case 'archive': + aResult.push('archiveOnlyAttachments'); + break; + } + } + if (this.newForAnimation()) + { + aResult.push('new'); + } + if ('' === this.subject()) + { + aResult.push('emptySubject'); + } + if (0 < this.parentUid()) + { + aResult.push('hasParentMessage'); + } + if (0 < this.threadsLen() && 0 === this.parentUid()) + { + aResult.push('hasChildrenMessage'); + } + if (this.hasUnseenSubMessage()) + { + aResult.push('hasUnseenSubMessage'); + } + if (this.hasFlaggedSubMessage()) + { + aResult.push('hasFlaggedSubMessage'); + } - return aResult.join(' '); + return aResult.join(' '); }; /** - * @return {boolean} - */ + * @return {boolean} + */ MessageModel.prototype.hasVisibleAttachments = function () { - return !!_.find(this.attachments(), function (oAttachment) { - return !oAttachment.isLinked; - }); + return !!_.find(this.attachments(), function (oAttachment) { + return !oAttachment.isLinked; + }); }; /** - * @param {string} sCid - * @return {*} - */ + * @param {string} sCid + * @return {*} + */ MessageModel.prototype.findAttachmentByCid = function (sCid) { - var - oResult = null, - aAttachments = this.attachments() - ; + var + oResult = null, + aAttachments = this.attachments() + ; - if (Utils.isNonEmptyArray(aAttachments)) - { - sCid = sCid.replace(/^<+/, '').replace(/>+$/, ''); - oResult = _.find(aAttachments, function (oAttachment) { - return sCid === oAttachment.cidWithOutTags; - }); - } + if (Utils.isNonEmptyArray(aAttachments)) + { + sCid = sCid.replace(/^<+/, '').replace(/>+$/, ''); + oResult = _.find(aAttachments, function (oAttachment) { + return sCid === oAttachment.cidWithOutTags; + }); + } - return oResult || null; + return oResult || null; }; /** - * @param {string} sContentLocation - * @return {*} - */ + * @param {string} sContentLocation + * @return {*} + */ MessageModel.prototype.findAttachmentByContentLocation = function (sContentLocation) { - var - oResult = null, - aAttachments = this.attachments() - ; + var + oResult = null, + aAttachments = this.attachments() + ; - if (Utils.isNonEmptyArray(aAttachments)) - { - oResult = _.find(aAttachments, function (oAttachment) { - return sContentLocation === oAttachment.contentLocation; - }); - } + if (Utils.isNonEmptyArray(aAttachments)) + { + oResult = _.find(aAttachments, function (oAttachment) { + return sContentLocation === oAttachment.contentLocation; + }); + } - return oResult || null; + return oResult || null; }; /** - * @return {string} - */ + * @return {string} + */ MessageModel.prototype.messageId = function () { - return this.sMessageId; + return this.sMessageId; }; /** - * @return {string} - */ + * @return {string} + */ MessageModel.prototype.inReplyTo = function () { - return this.sInReplyTo; + return this.sInReplyTo; }; /** - * @return {string} - */ + * @return {string} + */ MessageModel.prototype.references = function () { - return this.sReferences; + return this.sReferences; }; /** - * @return {string} - */ + * @return {string} + */ MessageModel.prototype.fromAsSingleEmail = function () { - return Utils.isArray(this.from) && this.from[0] ? this.from[0].email : ''; + return Utils.isArray(this.from) && this.from[0] ? this.from[0].email : ''; }; /** - * @return {string} - */ + * @return {string} + */ MessageModel.prototype.viewLink = function () { - return Links.messageViewLink(this.requestHash); + return Links.messageViewLink(this.requestHash); }; /** - * @return {string} - */ + * @return {string} + */ MessageModel.prototype.downloadLink = function () { - return Links.messageDownloadLink(this.requestHash); + return Links.messageDownloadLink(this.requestHash); }; /** - * @param {Object} oExcludeEmails - * @return {Array} - */ + * @param {Object} oExcludeEmails + * @return {Array} + */ MessageModel.prototype.replyEmails = function (oExcludeEmails) { - var - aResult = [], - oUnic = Utils.isUnd(oExcludeEmails) ? {} : oExcludeEmails - ; + var + aResult = [], + oUnic = Utils.isUnd(oExcludeEmails) ? {} : oExcludeEmails + ; - MessageModel.replyHelper(this.replyTo, oUnic, aResult); - if (0 === aResult.length) - { - MessageModel.replyHelper(this.from, oUnic, aResult); - } + MessageModel.replyHelper(this.replyTo, oUnic, aResult); + if (0 === aResult.length) + { + MessageModel.replyHelper(this.from, oUnic, aResult); + } - return aResult; + return aResult; }; /** - * @param {Object} oExcludeEmails - * @return {Array.} - */ + * @param {Object} oExcludeEmails + * @return {Array.} + */ MessageModel.prototype.replyAllEmails = function (oExcludeEmails) { - var - aToResult = [], - aCcResult = [], - oUnic = Utils.isUnd(oExcludeEmails) ? {} : oExcludeEmails - ; + var + aToResult = [], + aCcResult = [], + oUnic = Utils.isUnd(oExcludeEmails) ? {} : oExcludeEmails + ; - MessageModel.replyHelper(this.replyTo, oUnic, aToResult); - if (0 === aToResult.length) - { - MessageModel.replyHelper(this.from, oUnic, aToResult); - } + MessageModel.replyHelper(this.replyTo, oUnic, aToResult); + if (0 === aToResult.length) + { + MessageModel.replyHelper(this.from, oUnic, aToResult); + } - MessageModel.replyHelper(this.to, oUnic, aToResult); - MessageModel.replyHelper(this.cc, oUnic, aCcResult); + MessageModel.replyHelper(this.to, oUnic, aToResult); + MessageModel.replyHelper(this.cc, oUnic, aCcResult); - return [aToResult, aCcResult]; + return [aToResult, aCcResult]; }; /** - * @return {string} - */ + * @return {string} + */ MessageModel.prototype.textBodyToString = function () { - return this.body ? this.body.html() : ''; + return this.body ? this.body.html() : ''; }; /** - * @return {string} - */ + * @return {string} + */ MessageModel.prototype.attachmentsToStringLine = function () { - var aAttachLines = _.map(this.attachments(), function (oItem) { - return oItem.fileName + ' (' + oItem.friendlySize + ')'; - }); + var aAttachLines = _.map(this.attachments(), function (oItem) { + return oItem.fileName + ' (' + oItem.friendlySize + ')'; + }); - return aAttachLines && 0 < aAttachLines.length ? aAttachLines.join(', ') : ''; + return aAttachLines && 0 < aAttachLines.length ? aAttachLines.join(', ') : ''; }; /** - * @return {Object} - */ + * @return {Object} + */ MessageModel.prototype.getDataForWindowPopup = function () { - return { - 'popupFrom': this.fromToLine(false), - 'popupTo': this.toToLine(false), - 'popupCc': this.ccToLine(false), - 'popupBcc': this.bccToLine(false), - 'popupSubject': this.subject(), - 'popupIsHtml': this.isHtml(), - 'popupDate': this.fullFormatDateValue(), - 'popupAttachments': this.attachmentsToStringLine(), - 'popupBody': this.textBodyToString() - }; + return { + 'popupFrom': this.fromToLine(false), + 'popupTo': this.toToLine(false), + 'popupCc': this.ccToLine(false), + 'popupBcc': this.bccToLine(false), + 'popupSubject': this.subject(), + 'popupIsHtml': this.isHtml(), + 'popupDate': this.fullFormatDateValue(), + 'popupAttachments': this.attachmentsToStringLine(), + 'popupBody': this.textBodyToString() + }; }; /** - * @param {boolean=} bPrint = false - */ + * @param {boolean=} bPrint = false + */ MessageModel.prototype.viewPopupMessage = function (bPrint) { - Utils.windowPopupKnockout(this.getDataForWindowPopup(), 'PopupsWindowSimpleMessage', this.subject(), function (oPopupWin) { - if (oPopupWin && oPopupWin.document && oPopupWin.document.body) - { - $('img.lazy', oPopupWin.document.body).each(function (iIndex, oImg) { + Utils.windowPopupKnockout(this.getDataForWindowPopup(), 'PopupsWindowSimpleMessage', + this.subject(), function (oPopupWin) + { + if (oPopupWin && oPopupWin.document && oPopupWin.document.body) + { + $('img.lazy', oPopupWin.document.body).each(function (iIndex, oImg) { - var - $oImg = $(oImg), - sOrig = $oImg.data('original'), - sSrc = $oImg.attr('src') - ; + var + $oImg = $(oImg), + sOrig = $oImg.data('original'), + sSrc = $oImg.attr('src') + ; - if (0 <= iIndex && sOrig && !sSrc) - { - $oImg.attr('src', sOrig); - } - }); + if (0 <= iIndex && sOrig && !sSrc) + { + $oImg.attr('src', sOrig); + } + }); - if (bPrint) - { - window.setTimeout(function () { - oPopupWin.print(); - }, 100); - } - } - }); + if (bPrint) + { + window.setTimeout(function () { + oPopupWin.print(); + }, 100); + } + } + }); }; MessageModel.prototype.printMessage = function () { - this.viewPopupMessage(true); + this.viewPopupMessage(true); }; /** - * @returns {string} - */ + * @returns {string} + */ MessageModel.prototype.generateUid = function () { - return this.folderFullNameRaw + '/' + this.uid; + return this.folderFullNameRaw + '/' + this.uid; }; /** - * @param {MessageModel} oMessage - * @return {MessageModel} - */ + * @param {MessageModel} oMessage + * @return {MessageModel} + */ MessageModel.prototype.populateByMessageListItem = function (oMessage) { - this.folderFullNameRaw = oMessage.folderFullNameRaw; - this.uid = oMessage.uid; - this.hash = oMessage.hash; - this.requestHash = oMessage.requestHash; - this.subject(oMessage.subject()); - this.subjectPrefix(this.subjectPrefix()); - this.subjectSuffix(this.subjectSuffix()); + this.folderFullNameRaw = oMessage.folderFullNameRaw; + this.uid = oMessage.uid; + this.hash = oMessage.hash; + this.requestHash = oMessage.requestHash; + this.subject(oMessage.subject()); + this.subjectPrefix(this.subjectPrefix()); + this.subjectSuffix(this.subjectSuffix()); - this.size(oMessage.size()); - this.dateTimeStampInUTC(oMessage.dateTimeStampInUTC()); - this.priority(oMessage.priority()); + this.size(oMessage.size()); + this.dateTimeStampInUTC(oMessage.dateTimeStampInUTC()); + this.priority(oMessage.priority()); - this.proxy = oMessage.proxy; + this.proxy = oMessage.proxy; - this.fromEmailString(oMessage.fromEmailString()); - this.fromClearEmailString(oMessage.fromClearEmailString()); - this.toEmailsString(oMessage.toEmailsString()); - this.toClearEmailsString(oMessage.toClearEmailsString()); + this.fromEmailString(oMessage.fromEmailString()); + this.fromClearEmailString(oMessage.fromClearEmailString()); + this.toEmailsString(oMessage.toEmailsString()); + this.toClearEmailsString(oMessage.toClearEmailsString()); - this.emails = oMessage.emails; + this.emails = oMessage.emails; - this.from = oMessage.from; - this.to = oMessage.to; - this.cc = oMessage.cc; - this.bcc = oMessage.bcc; - this.replyTo = oMessage.replyTo; - this.deliveredTo = oMessage.deliveredTo; + this.from = oMessage.from; + this.to = oMessage.to; + this.cc = oMessage.cc; + this.bcc = oMessage.bcc; + this.replyTo = oMessage.replyTo; + this.deliveredTo = oMessage.deliveredTo; - this.unseen(oMessage.unseen()); - this.flagged(oMessage.flagged()); - this.answered(oMessage.answered()); - this.forwarded(oMessage.forwarded()); - this.isReadReceipt(oMessage.isReadReceipt()); + this.unseen(oMessage.unseen()); + this.flagged(oMessage.flagged()); + this.answered(oMessage.answered()); + this.forwarded(oMessage.forwarded()); + this.isReadReceipt(oMessage.isReadReceipt()); - this.selected(oMessage.selected()); - this.checked(oMessage.checked()); - this.hasAttachments(oMessage.hasAttachments()); - this.attachmentsMainType(oMessage.attachmentsMainType()); + this.priority(oMessage.priority()); - this.moment(oMessage.moment()); + this.selected(oMessage.selected()); + this.checked(oMessage.checked()); + this.hasAttachments(oMessage.hasAttachments()); + this.attachmentsMainType(oMessage.attachmentsMainType()); - this.body = null; + this.moment(oMessage.moment()); - this.priority(Enums.MessagePriority.Normal); - this.aDraftInfo = []; - this.sMessageId = ''; - this.sInReplyTo = ''; - this.sReferences = ''; + this.body = null; - this.parentUid(oMessage.parentUid()); - this.threads(oMessage.threads()); - this.threadsLen(oMessage.threadsLen()); + this.aDraftInfo = []; + this.sMessageId = ''; + this.sInReplyTo = ''; + this.sReferences = ''; - this.computeSenderEmail(); + this.parentUid(oMessage.parentUid()); + this.threads(oMessage.threads()); + this.threadsLen(oMessage.threadsLen()); - return this; + this.computeSenderEmail(); + + return this; }; MessageModel.prototype.showExternalImages = function (bLazy) { - if (this.body && this.body.data('rl-has-images')) - { - var sAttr = ''; - bLazy = Utils.isUnd(bLazy) ? false : bLazy; + if (this.body && this.body.data('rl-has-images')) + { + var sAttr = ''; + bLazy = Utils.isUnd(bLazy) ? false : bLazy; - this.hasImages(false); - this.body.data('rl-has-images', false); + this.hasImages(false); + this.body.data('rl-has-images', false); - sAttr = this.proxy ? 'data-x-additional-src' : 'data-x-src'; - $('[' + sAttr + ']', this.body).each(function () { - if (bLazy && $(this).is('img')) - { - $(this) - .addClass('lazy') - .attr('data-original', $(this).attr(sAttr)) - .removeAttr(sAttr) - ; - } - else - { - $(this).attr('src', $(this).attr(sAttr)).removeAttr(sAttr); - } - }); + sAttr = this.proxy ? 'data-x-additional-src' : 'data-x-src'; + $('[' + sAttr + ']', this.body).each(function () { + if (bLazy && $(this).is('img')) + { + $(this) + .addClass('lazy') + .attr('data-original', $(this).attr(sAttr)) + .removeAttr(sAttr) + ; + } + else + { + $(this).attr('src', $(this).attr(sAttr)).removeAttr(sAttr); + } + }); - sAttr = this.proxy ? 'data-x-additional-style-url' : 'data-x-style-url'; - $('[' + sAttr + ']', this.body).each(function () { - var sStyle = Utils.trim($(this).attr('style')); - sStyle = '' === sStyle ? '' : (';' === sStyle.substr(-1) ? sStyle + ' ' : sStyle + '; '); - $(this).attr('style', sStyle + $(this).attr(sAttr)).removeAttr(sAttr); - }); + sAttr = this.proxy ? 'data-x-additional-style-url' : 'data-x-style-url'; + $('[' + sAttr + ']', this.body).each(function () { + var sStyle = Utils.trim($(this).attr('style')); + sStyle = '' === sStyle ? '' : (';' === sStyle.substr(-1) ? sStyle + ' ' : sStyle + '; '); + $(this).attr('style', sStyle + $(this).attr(sAttr)).removeAttr(sAttr); + }); - if (bLazy) - { - $('img.lazy', this.body).addClass('lazy-inited').lazyload({ - 'threshold' : 400, - 'effect' : 'fadeIn', - 'skip_invisible' : false, - 'container': $('.RL-MailMessageView .messageView .messageItem .content')[0] - }); + if (bLazy) + { + $('img.lazy', this.body).addClass('lazy-inited').lazyload({ + 'threshold': 400, + 'effect': 'fadeIn', + 'skip_invisible': false, + 'container': $('.RL-MailMessageView .messageView .messageItem .content')[0] + }); - Globals.$win.resize(); - } + Globals.$win.resize(); + } - Utils.windowResize(500); - } + Utils.windowResize(500); + } }; MessageModel.prototype.showInternalImages = function (bLazy) { - if (this.body && !this.body.data('rl-init-internal-images')) - { - this.body.data('rl-init-internal-images', true); + if (this.body && !this.body.data('rl-init-internal-images')) + { + this.body.data('rl-init-internal-images', true); - bLazy = Utils.isUnd(bLazy) ? false : bLazy; + bLazy = Utils.isUnd(bLazy) ? false : bLazy; - var self = this; + var self = this; - $('[data-x-src-cid]', this.body).each(function () { + $('[data-x-src-cid]', this.body).each(function () { - var oAttachment = self.findAttachmentByCid($(this).attr('data-x-src-cid')); - if (oAttachment && oAttachment.download) - { - if (bLazy && $(this).is('img')) - { - $(this) - .addClass('lazy') - .attr('data-original', oAttachment.linkPreview()); - } - else - { - $(this).attr('src', oAttachment.linkPreview()); - } - } - }); + var oAttachment = self.findAttachmentByCid($(this).attr('data-x-src-cid')); + if (oAttachment && oAttachment.download) + { + if (bLazy && $(this).is('img')) + { + $(this) + .addClass('lazy') + .attr('data-original', oAttachment.linkPreview()); + } + else + { + $(this).attr('src', oAttachment.linkPreview()); + } + } + }); - $('[data-x-src-location]', this.body).each(function () { + $('[data-x-src-location]', this.body).each(function () { - var oAttachment = self.findAttachmentByContentLocation($(this).attr('data-x-src-location')); - if (!oAttachment) - { - oAttachment = self.findAttachmentByCid($(this).attr('data-x-src-location')); - } + var oAttachment = self.findAttachmentByContentLocation($(this).attr('data-x-src-location')); + if (!oAttachment) + { + oAttachment = self.findAttachmentByCid($(this).attr('data-x-src-location')); + } - if (oAttachment && oAttachment.download) - { - if (bLazy && $(this).is('img')) - { - $(this) - .addClass('lazy') - .attr('data-original', oAttachment.linkPreview()); - } - else - { - $(this).attr('src', oAttachment.linkPreview()); - } - } - }); + if (oAttachment && oAttachment.download) + { + if (bLazy && $(this).is('img')) + { + $(this) + .addClass('lazy') + .attr('data-original', oAttachment.linkPreview()); + } + else + { + $(this).attr('src', oAttachment.linkPreview()); + } + } + }); - $('[data-x-style-cid]', this.body).each(function () { + $('[data-x-style-cid]', this.body).each(function () { - var - sStyle = '', - sName = '', - oAttachment = self.findAttachmentByCid($(this).attr('data-x-style-cid')) - ; + var + sStyle = '', + sName = '', + oAttachment = self.findAttachmentByCid($(this).attr('data-x-style-cid')) + ; - if (oAttachment && oAttachment.linkPreview) - { - sName = $(this).attr('data-x-style-cid-name'); - if ('' !== sName) - { - sStyle = Utils.trim($(this).attr('style')); - sStyle = '' === sStyle ? '' : (';' === sStyle.substr(-1) ? sStyle + ' ' : sStyle + '; '); - $(this).attr('style', sStyle + sName + ': url(\'' + oAttachment.linkPreview() + '\')'); - } - } - }); + if (oAttachment && oAttachment.linkPreview) + { + sName = $(this).attr('data-x-style-cid-name'); + if ('' !== sName) + { + sStyle = Utils.trim($(this).attr('style')); + sStyle = '' === sStyle ? '' : (';' === sStyle.substr(-1) ? sStyle + ' ' : sStyle + '; '); + $(this).attr('style', sStyle + sName + ': url(\'' + oAttachment.linkPreview() + '\')'); + } + } + }); - if (bLazy) - { - (function ($oImg, oContainer) { - _.delay(function () { - $oImg.addClass('lazy-inited').lazyload({ - 'threshold' : 400, - 'effect' : 'fadeIn', - 'skip_invisible' : false, - 'container': oContainer - }); - }, 300); - }($('img.lazy', self.body), $('.RL-MailMessageView .messageView .messageItem .content')[0])); - } + if (bLazy) + { + (function ($oImg, oContainer) { + _.delay(function () { + $oImg.addClass('lazy-inited').lazyload({ + 'threshold': 400, + 'effect': 'fadeIn', + 'skip_invisible': false, + 'container': oContainer + }); + }, 300); + }($('img.lazy', self.body), $('.RL-MailMessageView .messageView .messageItem .content')[0])); + } - Utils.windowResize(500); - } + Utils.windowResize(500); + } }; MessageModel.prototype.storeDataToDom = function () { - if (this.body) - { - this.body.data('rl-is-html', !!this.isHtml()); - this.body.data('rl-has-images', !!this.hasImages()); + if (this.body) + { + this.body.data('rl-is-html', !!this.isHtml()); + this.body.data('rl-has-images', !!this.hasImages()); - this.body.data('rl-plain-raw', this.plainRaw); + this.body.data('rl-plain-raw', this.plainRaw); - var Data = require('Storage/User/Data'); - if (Data.capaOpenPGP()) - { - this.body.data('rl-plain-pgp-signed', !!this.isPgpSigned()); - this.body.data('rl-plain-pgp-encrypted', !!this.isPgpEncrypted()); - this.body.data('rl-pgp-verify-status', this.pgpSignedVerifyStatus()); - this.body.data('rl-pgp-verify-user', this.pgpSignedVerifyUser()); - } - } + var Data = require('Storage/User/Data'); + if (Data.capaOpenPGP()) + { + this.body.data('rl-plain-pgp-signed', !!this.isPgpSigned()); + this.body.data('rl-plain-pgp-encrypted', !!this.isPgpEncrypted()); + this.body.data('rl-pgp-verify-status', this.pgpSignedVerifyStatus()); + this.body.data('rl-pgp-verify-user', this.pgpSignedVerifyUser()); + } + } }; MessageModel.prototype.storePgpVerifyDataToDom = function () @@ -1146,155 +1162,155 @@ MessageModel.prototype.verifyPgpSignedClearMessage = function () { - if (this.isPgpSigned()) - { - var - aRes = [], - mPgpMessage = null, - Data = require('Storage/User/Data'), - sFrom = this.from && this.from[0] && this.from[0].email ? this.from[0].email : '', - aPublicKeys = Data.findPublicKeysByEmail(sFrom), - oValidKey = null, - oValidSysKey = null, - sPlain = '' - ; + if (this.isPgpSigned()) + { + var + aRes = [], + mPgpMessage = null, + Data = require('Storage/User/Data'), + sFrom = this.from && this.from[0] && this.from[0].email ? this.from[0].email : '', + aPublicKeys = Data.findPublicKeysByEmail(sFrom), + oValidKey = null, + oValidSysKey = null, + sPlain = '' + ; - this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Error); - this.pgpSignedVerifyUser(''); + this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Error); + this.pgpSignedVerifyUser(''); - try - { - mPgpMessage = Data.openpgp.cleartext.readArmored(this.plainRaw); - if (mPgpMessage && mPgpMessage.getText) - { - this.pgpSignedVerifyStatus( - aPublicKeys.length ? Enums.SignedVerifyStatus.Unverified : Enums.SignedVerifyStatus.UnknownPublicKeys); + try + { + mPgpMessage = Data.openpgp.cleartext.readArmored(this.plainRaw); + if (mPgpMessage && mPgpMessage.getText) + { + this.pgpSignedVerifyStatus( + aPublicKeys.length ? Enums.SignedVerifyStatus.Unverified : Enums.SignedVerifyStatus.UnknownPublicKeys); - aRes = mPgpMessage.verify(aPublicKeys); - if (aRes && 0 < aRes.length) - { - oValidKey = _.find(aRes, function (oItem) { - return oItem && oItem.keyid && oItem.valid; - }); + aRes = mPgpMessage.verify(aPublicKeys); + if (aRes && 0 < aRes.length) + { + oValidKey = _.find(aRes, function (oItem) { + return oItem && oItem.keyid && oItem.valid; + }); - if (oValidKey) - { - oValidSysKey = Data.findPublicKeyByHex(oValidKey.keyid.toHex()); - if (oValidSysKey) - { - sPlain = mPgpMessage.getText(); + if (oValidKey) + { + oValidSysKey = Data.findPublicKeyByHex(oValidKey.keyid.toHex()); + if (oValidSysKey) + { + sPlain = mPgpMessage.getText(); - this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Success); - this.pgpSignedVerifyUser(oValidSysKey.user); + this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Success); + this.pgpSignedVerifyUser(oValidSysKey.user); - sPlain = - Globals.$div.empty().append( - $('
').text(sPlain)
-								   ).html()
-							   ;
+								sPlain =
+									Globals.$div.empty().append(
+									$('
').text(sPlain)
+									).html()
+									;
 
-							   Globals.$div.empty();
+								Globals.$div.empty();
 
-							   this.replacePlaneTextBody(sPlain);
-						   }
-					   }
-				   }
-			   }
-		   }
-		   catch (oExc) {}
+								this.replacePlaneTextBody(sPlain);
+							}
+						}
+					}
+				}
+			}
+			catch (oExc) {}
 
-		   this.storePgpVerifyDataToDom();
-	   }
+			this.storePgpVerifyDataToDom();
+		}
 	};
 
 	MessageModel.prototype.decryptPgpEncryptedMessage = function (sPassword)
 	{
-	   if (this.isPgpEncrypted())
-	   {
-		   var
-			   aRes = [],
-			   mPgpMessage = null,
-			   mPgpMessageDecrypted = null,
-			   Data = require('Storage/User/Data'),
-			   sFrom = this.from && this.from[0] && this.from[0].email ? this.from[0].email : '',
-			   aPublicKey = Data.findPublicKeysByEmail(sFrom),
-			   oPrivateKey = Data.findSelfPrivateKey(sPassword),
-			   oValidKey = null,
-			   oValidSysKey = null,
-			   sPlain = ''
-		   ;
+		if (this.isPgpEncrypted())
+		{
+			var
+				aRes = [],
+				mPgpMessage = null,
+				mPgpMessageDecrypted = null,
+				Data = require('Storage/User/Data'),
+				sFrom = this.from && this.from[0] && this.from[0].email ? this.from[0].email : '',
+				aPublicKey = Data.findPublicKeysByEmail(sFrom),
+				oPrivateKey = Data.findSelfPrivateKey(sPassword),
+				oValidKey = null,
+				oValidSysKey = null,
+				sPlain = ''
+			;
 
-		   this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Error);
-		   this.pgpSignedVerifyUser('');
+			this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Error);
+			this.pgpSignedVerifyUser('');
 
-		   if (!oPrivateKey)
-		   {
-			   this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.UnknownPrivateKey);
-		   }
+			if (!oPrivateKey)
+			{
+				this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.UnknownPrivateKey);
+			}
 
-		   try
-		   {
-			   mPgpMessage = Data.openpgp.message.readArmored(this.plainRaw);
-			   if (mPgpMessage && oPrivateKey && mPgpMessage.decrypt)
-			   {
-				   this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Unverified);
+			try
+			{
+				mPgpMessage = Data.openpgp.message.readArmored(this.plainRaw);
+				if (mPgpMessage && oPrivateKey && mPgpMessage.decrypt)
+				{
+					this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Unverified);
 
-				   mPgpMessageDecrypted = mPgpMessage.decrypt(oPrivateKey);
-				   if (mPgpMessageDecrypted)
-				   {
-					   aRes = mPgpMessageDecrypted.verify(aPublicKey);
-					   if (aRes && 0 < aRes.length)
-					   {
-						   oValidKey = _.find(aRes, function (oItem) {
-							   return oItem && oItem.keyid && oItem.valid;
-						   });
+					mPgpMessageDecrypted = mPgpMessage.decrypt(oPrivateKey);
+					if (mPgpMessageDecrypted)
+					{
+						aRes = mPgpMessageDecrypted.verify(aPublicKey);
+						if (aRes && 0 < aRes.length)
+						{
+							oValidKey = _.find(aRes, function (oItem) {
+								return oItem && oItem.keyid && oItem.valid;
+							});
 
-						   if (oValidKey)
-						   {
-							   oValidSysKey = Data.findPublicKeyByHex(oValidKey.keyid.toHex());
-							   if (oValidSysKey)
-							   {
-								   this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Success);
-								   this.pgpSignedVerifyUser(oValidSysKey.user);
-							   }
-						   }
-					   }
+							if (oValidKey)
+							{
+								oValidSysKey = Data.findPublicKeyByHex(oValidKey.keyid.toHex());
+								if (oValidSysKey)
+								{
+									this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Success);
+									this.pgpSignedVerifyUser(oValidSysKey.user);
+								}
+							}
+						}
 
-					   sPlain = mPgpMessageDecrypted.getText();
+						sPlain = mPgpMessageDecrypted.getText();
 
-					   sPlain =
-						   Globals.$div.empty().append(
-							   $('
').text(sPlain)
-						   ).html()
-					   ;
+						sPlain =
+							Globals.$div.empty().append(
+							$('
').text(sPlain)
+							).html()
+							;
 
-					   Globals.$div.empty();
+						Globals.$div.empty();
 
-					   this.replacePlaneTextBody(sPlain);
-				   }
-			   }
-		   }
-		   catch (oExc) {}
+						this.replacePlaneTextBody(sPlain);
+					}
+				}
+			}
+			catch (oExc) {}
 
-		   this.storePgpVerifyDataToDom();
-	   }
+			this.storePgpVerifyDataToDom();
+		}
 	};
 
 	MessageModel.prototype.replacePlaneTextBody = function (sPlain)
 	{
-	   if (this.body)
-	   {
-		   this.body.html(sPlain).addClass('b-text-part plain');
-	   }
+		if (this.body)
+		{
+			this.body.html(sPlain).addClass('b-text-part plain');
+		}
 	};
 
 	/**
-	* @return {string}
-	*/
+	 * @return {string}
+	 */
 	MessageModel.prototype.flagHash = function ()
 	{
-	   return [this.deleted(), this.unseen(), this.flagged(), this.answered(), this.forwarded(),
-		   this.isReadReceipt()].join('');
+		return [this.deleted(), this.unseen(), this.flagged(), this.answered(), this.forwarded(),
+			this.isReadReceipt()].join('');
 	};
 
 	module.exports = MessageModel;
diff --git a/dev/Settings/User/Filters.js b/dev/Settings/User/Filters.js
index 0e1ceb99c..16609bc04 100644
--- a/dev/Settings/User/Filters.js
+++ b/dev/Settings/User/Filters.js
@@ -44,7 +44,7 @@
 			{'toggleSubscribeProperty': [this, 'deleteAccess']});
 
 		this.saveChanges = Utils.createCommand(this, function () {
-			
+
 			if (!this.filters.saving())
 			{
 				this.filters.saving(true);
@@ -70,8 +70,8 @@
 		});
 
 		this.filters.subscribe(function () {
-			this.haveChanges(true);	
-		}, this);		
+			this.haveChanges(true);
+		}, this);
 	}
 
 	FiltersUserSettings.prototype.scrollableOptions = function ()
@@ -105,6 +105,7 @@
 			oNew = new FilterModel()
 		;
 
+		oNew.generateID();
 		require('Knoin/Knoin').showScreenPopup(
 			require('View/Popup/Filter'), [oNew, function  () {
 				self.filters.push(oNew);
diff --git a/dev/Storage/User/Remote.js b/dev/Storage/User/Remote.js
index 9ab486695..8f5d9f32c 100644
--- a/dev/Storage/User/Remote.js
+++ b/dev/Storage/User/Remote.js
@@ -493,9 +493,10 @@
 	 * @param {(Array|null)} aDraftInfo
 	 * @param {string} sInReplyTo
 	 * @param {string} sReferences
+	 * @param {boolean} bMarkAsImportant
 	 */
 	RemoteUserStorage.prototype.saveMessage = function (fCallback, sMessageFolder, sMessageUid, sDraftFolder,
-		sFrom, sTo, sCc, sBcc, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences)
+		sFrom, sTo, sCc, sBcc, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences, bMarkAsImportant)
 	{
 		this.defaultRequest(fCallback, 'SaveMessage', {
 			'MessageFolder': sMessageFolder,
@@ -511,6 +512,7 @@
 			'DraftInfo': aDraftInfo,
 			'InReplyTo': sInReplyTo,
 			'References': sReferences,
+			'MarkAsImportant': bMarkAsImportant ? '1' : '0',
 			'Attachments': aAttachments
 		}, Consts.Defaults.SaveMessageAjaxTimeout);
 	};
@@ -552,9 +554,11 @@
 	 * @param {string} sInReplyTo
 	 * @param {string} sReferences
 	 * @param {boolean} bRequestReadReceipt
+	 * @param {boolean} bMarkAsImportant
 	 */
 	RemoteUserStorage.prototype.sendMessage = function (fCallback, sMessageFolder, sMessageUid, sSentFolder,
-		sFrom, sTo, sCc, sBcc, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences, bRequestReadReceipt)
+		sFrom, sTo, sCc, sBcc, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences,
+		bRequestReadReceipt, bMarkAsImportant)
 	{
 		this.defaultRequest(fCallback, 'SendMessage', {
 			'MessageFolder': sMessageFolder,
@@ -571,6 +575,7 @@
 			'InReplyTo': sInReplyTo,
 			'References': sReferences,
 			'ReadReceiptRequest': bRequestReadReceipt ? '1' : '0',
+			'MarkAsImportant': bMarkAsImportant ? '1' : '0',
 			'Attachments': aAttachments
 		}, Consts.Defaults.SendMessageAjaxTimeout);
 	};
diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js
index eb27036ba..6ab63bca4 100644
--- a/dev/View/Popup/Compose.js
+++ b/dev/View/Popup/Compose.js
@@ -47,6 +47,8 @@
 
 		this.bCapaAdditionalIdentities = Settings.capa(Enums.Capa.AdditionalIdentities);
 
+		this.allowContacts = !!Settings.settingsGet('ContactsIsAllowed');
+
 		var
 			self = this,
 			fCcAndBccCheckHelper = function (aValue) {
@@ -76,6 +78,7 @@
 		this.isHtml = ko.observable(false);
 
 		this.requestReadReceipt = ko.observable(false);
+		this.markAsImportant = ko.observable(false);
 
 		this.sendError = ko.observable(false);
 		this.sendSuccessButSaveError = ko.observable(false);
@@ -298,7 +301,8 @@
 						this.aDraftInfo,
 						this.sInReplyTo,
 						this.sReferences,
-						this.requestReadReceipt()
+						this.requestReadReceipt(),
+						this.markAsImportant()
 					);
 				}
 			}
@@ -334,7 +338,8 @@
 					this.prepearAttachmentsForSendOrSave(),
 					this.aDraftInfo,
 					this.sInReplyTo,
-					this.sReferences
+					this.sReferences,
+					this.markAsImportant()
 				);
 			}
 
@@ -354,6 +359,21 @@
 
 		}, this.canBeSendedOrSaved);
 
+		this.contactsCommand = Utils.createCommand(this, function () {
+
+			if (this.allowContacts)
+			{
+				this.skipCommand();
+
+				_.delay(function () {
+					kn.showScreenPopup(require('View/Popup/Contacts'), [true]);
+				}, 200);
+			}
+
+		}, function () {
+			return this.allowContacts;
+		});
+
 		Events.sub('interval.2m', function () {
 
 			if (this.modalVisibility() && !Data.draftFolderNotEnabled() && !this.isEmptyForm(false) &&
@@ -800,6 +820,10 @@
 					self.initOnShow(sType, oMessageOrArray, aToEmails, sCustomSubject, sCustomPlainText);
 				}, null, null, null, false]);
 			}
+			else if (aToEmails && 0 < aToEmails.length)
+			{
+				this.addEmailsToTo(aToEmails);
+			}
 		}
 		else
 		{
@@ -807,6 +831,23 @@
 		}
 	};
 
+	/**
+	 * @param {Array} aEmails
+	 */
+	ComposePopupView.prototype.addEmailsToTo = function (aEmails)
+	{
+		var
+			sTo = Utils.trim(this.to()),
+			aTo = []
+		;
+
+		aTo = _.uniq(_.compact(_.map(aEmails, function (oItem) {
+			return oItem ? oItem.toLine(false) : null;
+		})));
+
+		this.to(sTo + ('' === sTo ? '' : ', ') + Utils.trim(aTo.join(', ')));
+	};
+
 	/**
 	 * @param {string=} sType = Enums.ComposeType.Empty
 	 * @param {?MessageModel|Array=} oMessageOrArray = null
@@ -1826,6 +1867,7 @@
 		this.subject('');
 
 		this.requestReadReceipt(false);
+		this.markAsImportant(false);
 
 		this.aDraftInfo = null;
 		this.sInReplyTo = '';
diff --git a/dev/View/Popup/Contacts.js b/dev/View/Popup/Contacts.js
index b587d12ea..0fc80e4fa 100644
--- a/dev/View/Popup/Contacts.js
+++ b/dev/View/Popup/Contacts.js
@@ -46,6 +46,8 @@
 			}
 		;
 
+		this.bBackToCompose = false;
+
 		this.allowContactsSync = Data.allowContactsSync;
 		this.enableContactsSync = Data.enableContactsSync;
 		this.allowExport = !Globals.bMobileDevice;
@@ -261,8 +263,13 @@
 
 			if (Utils.isNonEmptyArray(aE))
 			{
+				self.bBackToCompose = false;
+
 				kn.hideScreenPopup(require('View/Popup/Contacts'));
-				kn.showScreenPopup(require('View/Popup/Compose'), [Enums.ComposeType.Empty, null, aE]);
+
+				_.delay(function () {
+					kn.showScreenPopup(require('View/Popup/Compose'), [Enums.ComposeType.Empty, null, aE]);
+				}, 200);
 			}
 
 		}, function () {
@@ -716,8 +723,10 @@
 		this.initUploader();
 	};
 
-	ContactsPopupView.prototype.onShow = function ()
+	ContactsPopupView.prototype.onShow = function (bBackToCompose)
 	{
+		this.bBackToCompose = Utils.isUnd(bBackToCompose) ? false : !!bBackToCompose;
+
 		kn.routeOff();
 		this.reloadContactList(true);
 	};
@@ -732,6 +741,13 @@
 
 		Utils.delegateRunOnDestroy(this.contacts());
 		this.contacts([]);
+
+		if (this.bBackToCompose)
+		{
+			this.bBackToCompose = false;
+			
+			kn.showScreenPopup(require('View/Popup/Compose'));
+		}
 	};
 
 	module.exports = ContactsPopupView;
diff --git a/dev/View/User/MailBox/MessageView.js b/dev/View/User/MailBox/MessageView.js
index 9366ed5f6..1b239c3a3 100644
--- a/dev/View/User/MailBox/MessageView.js
+++ b/dev/View/User/MailBox/MessageView.js
@@ -165,6 +165,7 @@
 		this.viewDownloadLink = ko.observable('');
 		this.viewUserPic = ko.observable(Consts.DataImages.UserDotPic);
 		this.viewUserPicVisible = ko.observable(false);
+		this.viewIsImportant = ko.observable(false);
 
 		this.viewPgpPassword = ko.observable('');
 		this.viewPgpSignedVerifyStatus = ko.computed(function () {
@@ -202,6 +203,7 @@
 				this.viewLineAsCcc(oMessage.lineAsCcc());
 				this.viewViewLink(oMessage.viewLink());
 				this.viewDownloadLink(oMessage.downloadLink());
+				this.viewIsImportant(oMessage.isImportant());
 
 				sLastEmail = oMessage.fromAsSingleEmail();
 				Cache.getUserPic(sLastEmail, function (sPic, $sEmail) {
diff --git a/rainloop/v/0.0.0/app/i18n/langs.ini b/rainloop/v/0.0.0/app/i18n/langs.ini
index bc4e4d36e..ea0dd27e0 100644
--- a/rainloop/v/0.0.0/app/i18n/langs.ini
+++ b/rainloop/v/0.0.0/app/i18n/langs.ini
@@ -82,6 +82,10 @@ LANG_KO_KR = "한국어"
 LANG_BG = "Български"
 LANG_BG_BG = "Български"
 
+LANG_VI = "Tiếng Việt"
+LANG_VI_VI = "Tiếng Việt"
+LANG_VI_VN = "Tiếng Việt"
+
 [LANGS_NAMES_EN]
 LANG_EN = "English"
 LANG_EN_US = "English (US)"
@@ -166,3 +170,7 @@ LANG_KO_KR = "Korean"
 
 LANG_BG = "Bulgarian"
 LANG_BG_BG = "Bulgarian"
+
+LANG_VI = "Vietnamese"
+LANG_VI_VI = "Vietnamese"
+LANG_VI_VN = "Vietnamese"
diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Actions.php b/rainloop/v/0.0.0/app/src/RainLoop/Actions.php
index c5a7f3ccf..f59c3576d 100644
--- a/rainloop/v/0.0.0/app/src/RainLoop/Actions.php
+++ b/rainloop/v/0.0.0/app/src/RainLoop/Actions.php
@@ -2751,12 +2751,12 @@ class Actions
 	 */
 	public function licenseHelper($sForce = false, $bLongCache = false, $iFastCacheTimeInMin = 10, $iLongCacheTimeInDays = 3)
 	{
-		$sDomain = APP_SITE;
+		$sDomain = \trim(APP_SITE);
 
 		$oCacher = $this->Cacher();
 		$oHttp = \MailSo\Base\Http::SingletonInstance();
 
-		if ($oHttp->CheckLocalhost($sDomain) || !$oCacher)
+		if (0 === \strlen($sDomain) || $oHttp->CheckLocalhost($sDomain) || !$oCacher)
 		{
 			return 'NO';
 		}
@@ -4761,6 +4761,7 @@ class Actions
 		$sSubject = $this->GetActionParam('Subject', '');
 		$bTextIsHtml = '1' === $this->GetActionParam('TextIsHtml', '0');
 		$bReadReceiptRequest = '1' === $this->GetActionParam('ReadReceiptRequest', '0');
+		$bMarkAsImportant = '1' === $this->GetActionParam('MarkAsImportant', '0');
 		$sText = $this->GetActionParam('Text', '');
 		$aAttachments = $this->GetActionParam('Attachments', null);
 
@@ -4801,6 +4802,11 @@ class Actions
 			$oMessage->SetReadReceipt($oAccount->Email());
 		}
 
+		if ($bMarkAsImportant)
+		{
+			$oMessage->SetPriority(\MailSo\Mime\Enumerations\MessagePriority::HIGH);
+		}
+
 		$oMessage->SetSubject($sSubject);
 
 		$oToEmails = \MailSo\Mime\EmailCollection::NewInstance($sTo);
diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Classes/Filter.php b/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Classes/Filter.php
index 98700bdf1..c24fb1c77 100644
--- a/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Classes/Filter.php
+++ b/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Classes/Filter.php
@@ -150,7 +150,22 @@ class Filter
 	 */
 	public function FromJSON($aFilter)
 	{
-//		
+		if (\is_array($aFilter))
+		{
+			$this->sID = isset($aFilter['ID']) ? $aFilter['ID'] : '';
+			$this->sName = isset($aFilter['Name']) ? $aFilter['Name'] : '';
+
+			$this->sFilterRulesType = isset($aFilter['FilterRulesType']) ? $aFilter['FilterRulesType'] :
+				\RainLoop\Providers\Filters\Enumerations\FilterRulesType::ALL;
+
+			$this->sActionType = isset($aFilter['ActionType']) ? $aFilter['ActionType'] :
+				\RainLoop\Providers\Filters\Enumerations\ActionType::MOVE_TO;
+
+			$this->sActionValue = isset($aFilter['ActionValue']) ? $aFilter['ActionValue'] : '';
+
+			$this->bMarkAsRead = isset($aFilter['MarkAsRead']) ? $aFilter['MarkAsRead'] : false;
+			$this->bSkipOthers = isset($aFilter['SkipOthers']) ? $aFilter['SkipOthers'] : false;
+		}
 	}
 
 	/**
@@ -160,7 +175,15 @@ class Filter
 	 */
 	public function ToSimpleJSON($bAjax = false)
 	{
-		$aConditions = $this->Conditions();
+		$aConditions = array();
+		foreach ($this->Conditions() as $oItem)
+		{
+			if ($oItem)
+			{
+				$aConditions[] = $oItem->ToSimpleJSON($bAjax);
+			}
+		}
+
 		return array(
 			'ID' => $this->ID(),
 			'Name' => $this->Name(),
diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Classes/FilterCondition.php b/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Classes/FilterCondition.php
new file mode 100644
index 000000000..acb152936
--- /dev/null
+++ b/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Classes/FilterCondition.php
@@ -0,0 +1,90 @@
+Clear();
+	}
+
+	public function Clear()
+	{
+		$this->sField = \RainLoop\Providers\Filters\Enumerations\ConditionField::FROM;
+		$this->sType = \RainLoop\Providers\Filters\Enumerations\ConditionType::EQUAL_TO;
+		$this->sValue = '';
+	}
+
+	/**
+	 * @return string
+	 */
+	public function Field()
+	{
+		return $this->sField;
+	}
+
+	/**
+	 * @return string
+	 */
+	public function Type()
+	{
+		return $this->sType;
+	}
+
+	/**
+	 * @return string
+	 */
+	public function Value()
+	{
+		return $this->sValue;
+	}
+
+	/**
+	 * @param array $aFilter
+	 *
+	 * @return array
+	 */
+	public function FromJSON($aFilter)
+	{
+		if (\is_array($aFilter))
+		{
+			$this->sField = isset($aFilter['Field']) ? $aFilter['Field'] :
+				\RainLoop\Providers\Filters\Enumerations\ConditionField::FROM;
+
+			$this->sType = isset($aFilter['Type']) ? $aFilter['Type'] :
+				\RainLoop\Providers\Filters\Enumerations\ConditionType::EQUAL_TO;
+
+			$this->sValue = isset($aFilter['Value']) ? $aFilter['Value'] : '';
+		}
+	}
+
+	/**
+	 * @param bool $bAjax = false
+	 *
+	 * @return array
+	 */
+	public function ToSimpleJSON($bAjax = false)
+	{
+		return array(
+			'Field' => $this->Field(),
+			'Type' => $this->Type(),
+			'Value' => $this->Value()
+		);
+	}
+}
diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Enumerations/ConditionType.php b/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Enumerations/ConditionType.php
index 9c53b6a89..96b6c4113 100644
--- a/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Enumerations/ConditionType.php
+++ b/rainloop/v/0.0.0/app/src/RainLoop/Providers/Filters/Enumerations/ConditionType.php
@@ -8,4 +8,4 @@ class ConditionType
 	const NOT_EQUAL_TO = 'NotEqualTo';
 	const CONTAINS = 'Contains';
 	const NOT_CONTAINS = 'NotContains';
-}
\ No newline at end of file
+}
diff --git a/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItem.html b/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItem.html
index e5de80019..8fa820c69 100644
--- a/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItem.html
+++ b/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItem.html
@@ -37,8 +37,8 @@
 			
 		
 		
+ ! -
diff --git a/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItemNoPreviewPane.html b/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItemNoPreviewPane.html index a87e09391..a39da3a53 100644 --- a/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItemNoPreviewPane.html +++ b/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItemNoPreviewPane.html @@ -37,8 +37,8 @@
+ ! -
diff --git a/rainloop/v/0.0.0/app/templates/Views/User/MailMessageView.html b/rainloop/v/0.0.0/app/templates/Views/User/MailMessageView.html index 9e568fec2..c42dc28cf 100644 --- a/rainloop/v/0.0.0/app/templates/Views/User/MailMessageView.html +++ b/rainloop/v/0.0.0/app/templates/Views/User/MailMessageView.html @@ -195,6 +195,7 @@
+ !
diff --git a/rainloop/v/0.0.0/app/templates/Views/User/PopupsCompose.html b/rainloop/v/0.0.0/app/templates/Views/User/PopupsCompose.html index 21c4752ca..d06bdd784 100644 --- a/rainloop/v/0.0.0/app/templates/Views/User/PopupsCompose.html +++ b/rainloop/v/0.0.0/app/templates/Views/User/PopupsCompose.html @@ -50,6 +50,42 @@
+ +
 
+
+ + + +
+
 
@@ -115,29 +151,6 @@
- -
 
diff --git a/rainloop/v/0.0.0/langs/bg.ini b/rainloop/v/0.0.0/langs/bg.ini index 28b183aab..821be75e0 100644 --- a/rainloop/v/0.0.0/langs/bg.ini +++ b/rainloop/v/0.0.0/langs/bg.ini @@ -227,6 +227,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Заглавие" EMPTY_TO_ERROR_DESC = "Моля, изберте поне един получател" ATTACHMENTS_UPLOAD_ERROR_DESC = "Все още не са качени всички прикрепени файлове" BUTTON_REQUEST_READ_RECEIPT = "Поискайте разписка за прочитане на съобщението" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Да" diff --git a/rainloop/v/0.0.0/langs/de.ini b/rainloop/v/0.0.0/langs/de.ini index 173002120..ff6a435ee 100644 --- a/rainloop/v/0.0.0/langs/de.ini +++ b/rainloop/v/0.0.0/langs/de.ini @@ -226,6 +226,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Betreff" EMPTY_TO_ERROR_DESC = "Geben Sie bitte mindestens einen Empfänger an" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Empfangsbestätigung anfordern" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Ja" diff --git a/rainloop/v/0.0.0/langs/en.ini b/rainloop/v/0.0.0/langs/en.ini index e4e5bcbfe..f28756085 100644 --- a/rainloop/v/0.0.0/langs/en.ini +++ b/rainloop/v/0.0.0/langs/en.ini @@ -227,6 +227,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Subject" EMPTY_TO_ERROR_DESC = "Please specify at least one recipient" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Request a read receipt" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Yes" diff --git a/rainloop/v/0.0.0/langs/es.ini b/rainloop/v/0.0.0/langs/es.ini index b0a1c1b35..0d4ab8859 100644 --- a/rainloop/v/0.0.0/langs/es.ini +++ b/rainloop/v/0.0.0/langs/es.ini @@ -226,6 +226,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Asunto" EMPTY_TO_ERROR_DESC = "Por favor especifique al menos un destinatario" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Solicitar confirmación de lectura" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Sí" diff --git a/rainloop/v/0.0.0/langs/fr.ini b/rainloop/v/0.0.0/langs/fr.ini index a13d4df0c..f6e3189c4 100644 --- a/rainloop/v/0.0.0/langs/fr.ini +++ b/rainloop/v/0.0.0/langs/fr.ini @@ -226,6 +226,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Sujet" EMPTY_TO_ERROR_DESC = "Merci de spécifier au minimum un destinataire" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Demander une confirmation de lecture" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Oui" diff --git a/rainloop/v/0.0.0/langs/hu.ini b/rainloop/v/0.0.0/langs/hu.ini index e83ccee32..389ebde89 100644 --- a/rainloop/v/0.0.0/langs/hu.ini +++ b/rainloop/v/0.0.0/langs/hu.ini @@ -226,6 +226,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Tárgy" EMPTY_TO_ERROR_DESC = "Please specify at least one recipient" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Request a read receipt" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Igen" diff --git a/rainloop/v/0.0.0/langs/is.ini b/rainloop/v/0.0.0/langs/is.ini index b6352b7d5..7d5f6f96a 100644 --- a/rainloop/v/0.0.0/langs/is.ini +++ b/rainloop/v/0.0.0/langs/is.ini @@ -226,6 +226,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Viðfangsefni" EMPTY_TO_ERROR_DESC = "Vinsamlegast taktu fram að minnsta kosti einn viðtakanda" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Request a read receipt" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Yes" diff --git a/rainloop/v/0.0.0/langs/it.ini b/rainloop/v/0.0.0/langs/it.ini index 21d01971a..999872bb7 100644 --- a/rainloop/v/0.0.0/langs/it.ini +++ b/rainloop/v/0.0.0/langs/it.ini @@ -227,6 +227,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Oggetto" EMPTY_TO_ERROR_DESC = "Specifica almeno un destinatario" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Richiedi conferma di lettura" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Si" diff --git a/rainloop/v/0.0.0/langs/ja-jp.ini b/rainloop/v/0.0.0/langs/ja-jp.ini index 0e9041303..b1e5c8f29 100644 --- a/rainloop/v/0.0.0/langs/ja-jp.ini +++ b/rainloop/v/0.0.0/langs/ja-jp.ini @@ -226,6 +226,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Subject" EMPTY_TO_ERROR_DESC = "Please specify at least one recipient" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "開封確認を要求しますか?" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "はい" diff --git a/rainloop/v/0.0.0/langs/ko-kr.ini b/rainloop/v/0.0.0/langs/ko-kr.ini index 1f98a49be..832f2e923 100644 --- a/rainloop/v/0.0.0/langs/ko-kr.ini +++ b/rainloop/v/0.0.0/langs/ko-kr.ini @@ -226,6 +226,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "제목" EMPTY_TO_ERROR_DESC = "수신인을 한 명 이상 선택하세요" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Request a read receipt" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Yes" diff --git a/rainloop/v/0.0.0/langs/lt.ini b/rainloop/v/0.0.0/langs/lt.ini index bfb4d51fb..c2bad1aeb 100644 --- a/rainloop/v/0.0.0/langs/lt.ini +++ b/rainloop/v/0.0.0/langs/lt.ini @@ -227,6 +227,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Tema" EMPTY_TO_ERROR_DESC = "Prašome nurodyti bent vieną gavėją" ATTACHMENTS_UPLOAD_ERROR_DESC = "Dar ne visi priedai buvo įkelti" BUTTON_REQUEST_READ_RECEIPT = "Prašyti pranešti kada bus perskaitytas" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Taip" diff --git a/rainloop/v/0.0.0/langs/lv.ini b/rainloop/v/0.0.0/langs/lv.ini index 5bd3c6aec..3d989e8d8 100644 --- a/rainloop/v/0.0.0/langs/lv.ini +++ b/rainloop/v/0.0.0/langs/lv.ini @@ -226,6 +226,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Tēma" EMPTY_TO_ERROR_DESC = "Pievienojat vismaz vienu saņēmēju" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Request a read receipt" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Yes" diff --git a/rainloop/v/0.0.0/langs/nl.ini b/rainloop/v/0.0.0/langs/nl.ini index 2f73eb963..24150e117 100644 --- a/rainloop/v/0.0.0/langs/nl.ini +++ b/rainloop/v/0.0.0/langs/nl.ini @@ -226,6 +226,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Onderwerp" EMPTY_TO_ERROR_DESC = "Kies ten minste één ontvanger voordat u het bericht verstuurd" ATTACHMENTS_UPLOAD_ERROR_DESC = "Toevoegen van bijlage(n) is nog niet gereed" BUTTON_REQUEST_READ_RECEIPT = "Leesbevestiging vragen" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Ja" diff --git a/rainloop/v/0.0.0/langs/no.ini b/rainloop/v/0.0.0/langs/no.ini index c09a96efb..67cc3fb05 100644 --- a/rainloop/v/0.0.0/langs/no.ini +++ b/rainloop/v/0.0.0/langs/no.ini @@ -225,6 +225,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Emne" EMPTY_TO_ERROR_DESC = "Vennligst oppgi minst én mottaker" ATTACHMENTS_UPLOAD_ERROR_DESC = "Alle vedleggene er ikke lastet opp ennå" BUTTON_REQUEST_READ_RECEIPT = "Be om en lesebekreftelse når meldingen er lest" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Ja" diff --git a/rainloop/v/0.0.0/langs/pl.ini b/rainloop/v/0.0.0/langs/pl.ini index 2b56ea7a3..b102e72f2 100644 --- a/rainloop/v/0.0.0/langs/pl.ini +++ b/rainloop/v/0.0.0/langs/pl.ini @@ -227,6 +227,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Temat" EMPTY_TO_ERROR_DESC = "Wprowadź co najmniej jednego odbiorcę" ATTACHMENTS_UPLOAD_ERROR_DESC = "Nie przesłano jeszcze wszystkich załączników" BUTTON_REQUEST_READ_RECEIPT = "Żądaj potwierdzenia odbioru" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Tak" diff --git a/rainloop/v/0.0.0/langs/pt-br.ini b/rainloop/v/0.0.0/langs/pt-br.ini index bda2d6eb0..23778cb20 100644 --- a/rainloop/v/0.0.0/langs/pt-br.ini +++ b/rainloop/v/0.0.0/langs/pt-br.ini @@ -227,6 +227,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Assunto" EMPTY_TO_ERROR_DESC = "Por favor, especifique pelo menos um destinatário" ATTACHMENTS_UPLOAD_ERROR_DESC = "Alguns anexos ainda não foram completamente enviados" BUTTON_REQUEST_READ_RECEIPT = "Pedir recibo de leitura" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Sim" diff --git a/rainloop/v/0.0.0/langs/pt-pt.ini b/rainloop/v/0.0.0/langs/pt-pt.ini index 794da4691..7e1725c79 100644 --- a/rainloop/v/0.0.0/langs/pt-pt.ini +++ b/rainloop/v/0.0.0/langs/pt-pt.ini @@ -226,6 +226,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Assunto" EMPTY_TO_ERROR_DESC = "Por favor, especifique pelo menos um destinatário" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Pedir um recibo de leitura" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Sim" diff --git a/rainloop/v/0.0.0/langs/ro.ini b/rainloop/v/0.0.0/langs/ro.ini index b4129a36c..c6014ee64 100644 --- a/rainloop/v/0.0.0/langs/ro.ini +++ b/rainloop/v/0.0.0/langs/ro.ini @@ -225,6 +225,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Subiect" EMPTY_TO_ERROR_DESC = "Vă rugăm să specificați cel puțin un destinatar" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Cere confirmare de citire" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Da" diff --git a/rainloop/v/0.0.0/langs/ru.ini b/rainloop/v/0.0.0/langs/ru.ini index 2b8fe5f69..902544d4b 100644 --- a/rainloop/v/0.0.0/langs/ru.ini +++ b/rainloop/v/0.0.0/langs/ru.ini @@ -226,6 +226,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Тема" EMPTY_TO_ERROR_DESC = "Укажите как минимум одного получателя" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Запрос о прочтении письма" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Да" diff --git a/rainloop/v/0.0.0/langs/sk.ini b/rainloop/v/0.0.0/langs/sk.ini index ead861b5b..5e1f00864 100644 --- a/rainloop/v/0.0.0/langs/sk.ini +++ b/rainloop/v/0.0.0/langs/sk.ini @@ -226,6 +226,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Predmet" EMPTY_TO_ERROR_DESC = "Zadajte prosím aspoň jedného príjemcu" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Vyžiadať potvrdenie o prečítaní" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Áno" diff --git a/rainloop/v/0.0.0/langs/sv.ini b/rainloop/v/0.0.0/langs/sv.ini index e1758274c..0cc03e4c6 100644 --- a/rainloop/v/0.0.0/langs/sv.ini +++ b/rainloop/v/0.0.0/langs/sv.ini @@ -227,6 +227,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Ämne" EMPTY_TO_ERROR_DESC = "Ange minst en mottagare" ATTACHMENTS_UPLOAD_ERROR_DESC = "Alla bilagor är inte uppladddade än" BUTTON_REQUEST_READ_RECEIPT = "Begär mottagningskvitto" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Ja" diff --git a/rainloop/v/0.0.0/langs/tr.ini b/rainloop/v/0.0.0/langs/tr.ini index e5c5c2714..ba1f6dab2 100644 --- a/rainloop/v/0.0.0/langs/tr.ini +++ b/rainloop/v/0.0.0/langs/tr.ini @@ -227,6 +227,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Konu" EMPTY_TO_ERROR_DESC = "En az bir alıcı belirtin" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Okundu bilgisi iste" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Evet" diff --git a/rainloop/v/0.0.0/langs/ua.ini b/rainloop/v/0.0.0/langs/ua.ini index 7e05e5c17..a14b2a00f 100644 --- a/rainloop/v/0.0.0/langs/ua.ini +++ b/rainloop/v/0.0.0/langs/ua.ini @@ -226,6 +226,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "Тема" EMPTY_TO_ERROR_DESC = "Вкажіть як мінімум одного отримувача" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Запит про прочитання листа" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "Так" diff --git a/rainloop/v/0.0.0/langs/zh-cn.ini b/rainloop/v/0.0.0/langs/zh-cn.ini index 62226b90a..45e28dff9 100644 --- a/rainloop/v/0.0.0/langs/zh-cn.ini +++ b/rainloop/v/0.0.0/langs/zh-cn.ini @@ -226,6 +226,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "主题" EMPTY_TO_ERROR_DESC = "请至少选择一位接收人" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Request a read receipt" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "是" diff --git a/rainloop/v/0.0.0/langs/zh-tw.ini b/rainloop/v/0.0.0/langs/zh-tw.ini index 1284c09c9..12f1ea82d 100644 --- a/rainloop/v/0.0.0/langs/zh-tw.ini +++ b/rainloop/v/0.0.0/langs/zh-tw.ini @@ -227,6 +227,8 @@ FORWARD_MESSAGE_TOP_SUBJECT = "主題" EMPTY_TO_ERROR_DESC = "請至少選擇一位接收人" ATTACHMENTS_UPLOAD_ERROR_DESC = "Not all attachments have been uploaded yet" BUTTON_REQUEST_READ_RECEIPT = "Request a read receipt" +BUTTON_MARK_AS_IMPORTANT = "Mark as important" +BUTTON_OPEN_PGP = "OpenPGP (Plain Text Only)" [POPUPS_ASK] BUTTON_YES = "是"