snappymail/dev/Stores/User/Message.js

722 lines
20 KiB
JavaScript
Raw Normal View History

import ko from 'ko';
import { Scope, Notification } from 'Common/Enums';
import { MessageSetAction } from 'Common/EnumsUser';
import { doc, elementById } from 'Common/Globals';
import { isNonEmptyArray, pInt, pString, addObservablesTo, addSubscribablesTo } from 'Common/Utils';
import { plainToHtml } from 'Common/UtilsUser';
import {
getFolderInboxName,
addNewMessageCache,
setFolderUidNext,
getFolderFromCacheList,
setFolderHash,
MessageFlagsCache,
addRequestedMessage,
clearNewMessageCache
} from 'Common/Cache';
import { mailBox } from 'Common/Links';
2019-07-05 03:19:24 +08:00
import { i18n, getNotification } from 'Common/Translator';
import { EmailCollectionModel } from 'Model/EmailCollection';
2019-07-05 03:19:24 +08:00
import { MessageModel } from 'Model/Message';
import { MessageCollectionModel } from 'Model/MessageCollection';
import { AppUserStore } from 'Stores/User/App';
import { AccountUserStore } from 'Stores/User/Account';
import { FolderUserStore } from 'Stores/User/Folder';
import { PgpUserStore } from 'Stores/User/Pgp';
import { SettingsUserStore } from 'Stores/User/Settings';
import { NotificationUserStore } from 'Stores/User/Notification';
import Remote from 'Remote/User/Fetch';
2020-08-07 22:28:30 +08:00
const
hcont = Element.fromHTML('<div area="hidden" style="position:absolute;left:-5000px"></div>'),
2020-08-27 21:45:47 +08:00
getRealHeight = el => {
hcont.innerHTML = el.outerHTML;
const result = hcont.clientHeight;
hcont.innerHTML = '';
2020-08-07 22:28:30 +08:00
return result;
},
/*eslint-disable max-len*/
url = /(^|[\s\n]|\/?>)(https:\/\/[-A-Z0-9+\u0026\u2019#/%?=()~_|!:,.;]*[-A-Z0-9+\u0026#/%=~()_|])/gi,
email = /(^|[\s\n]|\/?>)((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x21\x23-\x5b\x5d-\x7f]|\\[\x21\x23-\x5b\x5d-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x21-\x5a\x53-\x7f]|\\[\x21\x23-\x5b\x5d-\x7f])+)\]))/gi,
findEmailAndLinks = html => html
.replace(url, '$1<a href="$2" target="_blank">$2</a>')
.replace(email, '$1<a href="mailto:$2">$2</a>'),
isChecked = item => item.checked(),
// Removes background and color
// Many e-mails incorrectly only define one, not both
// And in dark theme mode this kills the readability
removeColors = html => {
let l;
do {
l = html.length;
html = html
.replace(/(<[^>]+[;"'])\s*background(-[a-z]+)?\s*:[^;"']+/gi, '$1')
.replace(/(<[^>]+[;"'])\s*color\s*:[^;"']+/gi, '$1')
.replace(/(<[^>]+)\s(bg)?color=("[^"]+"|'[^']+')/gi, '$1');
} while (l != html.length)
return html;
};
doc.body.append(hcont);
2020-08-07 22:28:30 +08:00
export const MessageUserStore = new class {
2019-07-05 03:19:24 +08:00
constructor() {
this.staticMessage = new MessageModel();
2015-02-22 06:00:51 +08:00
2021-03-12 23:54:37 +08:00
this.list = ko.observableArray().extend({ debounce: 0 });
2015-02-22 06:00:51 +08:00
addObservablesTo(this, {
2021-03-12 23:54:37 +08:00
listCount: 0,
listSearch: '',
listThreadUid: '',
listPage: 1,
listPageBeforeThread: 1,
listError: '',
listEndFolder: '',
listEndSearch: '',
listEndThreadUid: '',
listEndPage: 1,
listLoading: false,
listLoadingAnimation: false,
listIsNotCompleted: false,
listCompleteLoading: false,
2015-02-22 06:00:51 +08:00
2020-10-27 18:09:24 +08:00
selectorMessageSelected: null,
selectorMessageFocused: null,
2015-03-06 08:42:40 +08:00
2020-10-27 18:09:24 +08:00
// message viewer
message: null,
messageViewTrigger: false,
messageError: '',
2021-03-12 23:54:37 +08:00
messageLoading: false,
2020-10-27 18:09:24 +08:00
messageFullScreenMode: false,
2015-02-22 06:00:51 +08:00
// Cache mail bodies
2020-10-27 18:09:24 +08:00
messagesBodiesDom: null,
messageActiveDom: null
});
2015-02-22 06:00:51 +08:00
2021-03-12 23:54:37 +08:00
this.listDisableAutoSelect = ko.observable(false).extend({ falseTimeout: 500 });
2020-10-27 18:09:24 +08:00
2021-03-12 23:54:37 +08:00
// Computed Observables
2020-10-27 18:09:24 +08:00
2021-03-12 23:54:37 +08:00
this.listEndHash = ko.computed(
2019-07-05 03:19:24 +08:00
() =>
2021-03-12 23:54:37 +08:00
this.listEndFolder() +
2019-07-05 03:19:24 +08:00
'|' +
2021-03-12 23:54:37 +08:00
this.listEndSearch() +
2019-07-05 03:19:24 +08:00
'|' +
2021-03-12 23:54:37 +08:00
this.listEndThreadUid() +
2019-07-05 03:19:24 +08:00
'|' +
2021-03-12 23:54:37 +08:00
this.listEndPage()
);
2015-02-22 06:00:51 +08:00
2021-03-12 23:54:37 +08:00
this.listPageCount = ko.computed(() =>
Math.max(1, Math.ceil(this.listCount() / SettingsUserStore.messagesPerPage()))
);
2015-02-22 06:00:51 +08:00
this.mainMessageListSearch = ko.computed({
2021-03-12 23:54:37 +08:00
read: this.listSearch,
write: value =>
rl.route.setHash(
2021-03-12 23:54:37 +08:00
mailBox(FolderUserStore.currentFolderFullNameHash(), 1, value.toString().trim(), this.listThreadUid())
)
});
2015-02-22 06:00:51 +08:00
this.isMessageSelected = ko.computed(() => null !== this.message());
2015-02-22 06:00:51 +08:00
2021-03-12 23:54:37 +08:00
this.listChecked = ko
.computed(() => this.list.filter(isChecked))
2019-07-05 03:19:24 +08:00
.extend({ rateLimit: 0 });
2015-02-22 06:00:51 +08:00
this.hasCheckedMessages = ko
2021-03-12 23:54:37 +08:00
.computed(() => !!this.list.find(isChecked))
.extend({ rateLimit: 0 });
this.hasCheckedOrSelected = ko
.computed(() => !!(this.selectorMessageSelected()
|| this.selectorMessageFocused()
2021-03-12 23:54:37 +08:00
|| this.list.find(item => item.checked())))
.extend({ rateLimit: 50 });
2021-03-12 23:54:37 +08:00
this.listCheckedOrSelected = ko.computed(() => {
const
2016-12-15 05:56:17 +08:00
selectedMessage = this.selectorMessageSelected(),
2021-03-12 23:54:37 +08:00
focusedMessage = this.selectorMessageFocused(),
checked = this.list.filter(item => isChecked(item) || item === selectedMessage);
return checked.length ? checked : (focusedMessage ? [focusedMessage] : []);
2016-06-30 08:02:45 +08:00
});
2015-03-06 08:42:40 +08:00
2021-03-12 23:54:37 +08:00
this.listCheckedOrSelectedUidsWithSubMails = ko.computed(() => {
let result = [];
2021-03-12 23:54:37 +08:00
this.listCheckedOrSelected().forEach(message => {
result.push(message.uid);
if (1 < message.threadsLen()) {
result = result.concat(message.threads()).unique();
}
});
return result;
});
2021-03-12 23:54:37 +08:00
// Subscribers
2021-03-12 23:54:37 +08:00
let timer = 0, fn = this.listLoadingAnimation;
2015-02-22 06:00:51 +08:00
2021-03-16 18:38:40 +08:00
addSubscribablesTo(this, {
listCompleteLoading: value => {
if (value) {
fn(value);
} else if (fn()) {
clearTimeout(timer);
timer = setTimeout(() => {
fn(value);
timer = 0;
}, 700);
} else {
fn(value);
2015-02-22 06:00:51 +08:00
}
2021-03-16 18:38:40 +08:00
},
listLoading: value =>
this.listCompleteLoading(value || this.listIsNotCompleted()),
listIsNotCompleted: value =>
this.listCompleteLoading(value || this.listLoading()),
list:
(list => {
list.forEach(item =>
item && item.newForAnimation() && item.newForAnimation(false)
)
}).debounce(500),
message: message => {
if (message) {
if (!SettingsUserStore.usePreviewPane()) {
AppUserStore.focusedState(Scope.MessageView);
2021-03-16 18:38:40 +08:00
}
} else {
AppUserStore.focusedState(Scope.MessageList);
2021-03-16 18:38:40 +08:00
this.messageFullScreenMode(false);
this.hideMessageBodies();
}
},
2021-03-16 18:38:40 +08:00
listEndFolder: folder => {
const message = this.message();
if (message && folder && folder !== message.folder) {
this.message(null);
}
}
});
2021-03-12 23:54:37 +08:00
this.onMessageResponse = this.onMessageResponse.bind(this);
this.purgeMessageBodyCacheThrottle = this.purgeMessageBodyCache.throttle(30000);
}
2015-02-22 06:00:51 +08:00
purgeMessageBodyCache() {
const messagesDom = this.messagesBodiesDom(),
children = messagesDom && messagesDom.children;
if (children) {
while (15 < children.length) {
children[0].remove();
2015-02-22 06:00:51 +08:00
}
}
2016-06-30 08:02:45 +08:00
}
2015-02-22 06:00:51 +08:00
initUidNextAndNewMessages(folder, uidNext, newMessages) {
if (getFolderInboxName() === folder && uidNext) {
if (isNonEmptyArray(newMessages)) {
newMessages.forEach(item => addNewMessageCache(folder, item.Uid));
2016-06-30 08:02:45 +08:00
NotificationUserStore.playSoundNotification();
2015-02-22 06:00:51 +08:00
const len = newMessages.length;
2019-07-05 03:19:24 +08:00
if (3 < len) {
NotificationUserStore.displayDesktopNotification(
AccountUserStore.email(),
i18n('MESSAGE_LIST/NEW_MESSAGE_NOTIFICATION', {
'COUNT': len
}),
{ 'Url': mailBox(newMessages[0].Folder, 1) }
2015-02-22 06:00:51 +08:00
);
2019-07-05 03:19:24 +08:00
} else {
newMessages.forEach(item => {
NotificationUserStore.displayDesktopNotification(
EmailCollectionModel.reviveFromJson(item.From).toString(),
item.Subject,
2019-07-05 03:19:24 +08:00
{ 'Folder': item.Folder, 'Uid': item.Uid }
);
});
}
2015-02-22 06:00:51 +08:00
}
setFolderUidNext(folder, uidNext);
}
2016-06-30 08:02:45 +08:00
}
hideMessageBodies() {
const messagesDom = this.messagesBodiesDom();
messagesDom && Array.from(messagesDom.children).forEach(el => el.hidden = true);
}
2015-02-22 06:00:51 +08:00
/**
* @param {string} fromFolderFullNameRaw
* @param {Array} uidForRemove
* @param {string=} toFolderFullNameRaw = ''
2016-12-15 05:56:17 +08:00
* @param {boolean=} copy = false
*/
removeMessagesFromList(fromFolderFullNameRaw, uidForRemove, toFolderFullNameRaw = '', copy = false) {
uidForRemove = uidForRemove.map(mValue => pInt(mValue));
2019-07-05 03:19:24 +08:00
let unseenCount = 0,
2021-03-12 23:54:37 +08:00
messageList = this.list,
currentMessage = this.message();
const trashFolder = FolderUserStore.trashFolder(),
spamFolder = FolderUserStore.spamFolder(),
fromFolder = getFolderFromCacheList(fromFolderFullNameRaw),
toFolder = toFolderFullNameRaw ? getFolderFromCacheList(toFolderFullNameRaw) : null,
currentFolderFullNameRaw = FolderUserStore.currentFolderFullNameRaw(),
2019-07-05 03:19:24 +08:00
messages =
currentFolderFullNameRaw === fromFolderFullNameRaw
? messageList.filter(item => item && uidForRemove.includes(pInt(item.uid)))
2019-07-05 03:19:24 +08:00
: [];
messages.forEach(item => {
2020-10-23 21:15:54 +08:00
if (item && item.isUnseen()) {
++unseenCount;
}
});
2015-02-22 06:00:51 +08:00
2019-07-05 03:19:24 +08:00
if (fromFolder && !copy) {
fromFolder.messageCountAll(
0 <= fromFolder.messageCountAll() - uidForRemove.length ? fromFolder.messageCountAll() - uidForRemove.length : 0
);
2015-02-22 06:00:51 +08:00
2019-07-05 03:19:24 +08:00
if (0 < unseenCount) {
fromFolder.messageCountUnread(
0 <= fromFolder.messageCountUnread() - unseenCount ? fromFolder.messageCountUnread() - unseenCount : 0
);
}
2015-02-22 06:00:51 +08:00
}
2019-07-05 03:19:24 +08:00
if (toFolder) {
if (trashFolder === toFolder.fullNameRaw || spamFolder === toFolder.fullNameRaw) {
unseenCount = 0;
}
2015-06-05 02:02:31 +08:00
toFolder.messageCountAll(toFolder.messageCountAll() + uidForRemove.length);
2019-07-05 03:19:24 +08:00
if (0 < unseenCount) {
toFolder.messageCountUnread(toFolder.messageCountUnread() + unseenCount);
}
2015-02-22 06:00:51 +08:00
toFolder.actionBlink(true);
2015-02-22 06:00:51 +08:00
}
if (messages.length) {
2019-07-05 03:19:24 +08:00
if (copy) {
2021-03-12 23:54:37 +08:00
messages.forEach(item => item.checked(false));
2019-07-05 03:19:24 +08:00
} else {
2021-03-12 23:54:37 +08:00
this.listIsNotCompleted(true);
2015-02-22 06:00:51 +08:00
messages.forEach(item => {
2019-07-05 03:19:24 +08:00
if (currentMessage && currentMessage.hash === item.hash) {
currentMessage = null;
this.message(null);
}
2015-02-22 06:00:51 +08:00
item.deleted(true);
2016-06-30 08:02:45 +08:00
});
2015-02-22 06:00:51 +08:00
2021-03-12 23:54:37 +08:00
setTimeout(() => messages.forEach(item => messageList.remove(item)), 350);
}
}
2015-02-22 06:00:51 +08:00
if (fromFolderFullNameRaw) {
setFolderHash(fromFolderFullNameRaw, '');
}
2016-06-30 08:02:45 +08:00
if (toFolderFullNameRaw) {
setFolderHash(toFolderFullNameRaw, '');
}
2015-04-22 05:01:29 +08:00
2021-03-12 23:54:37 +08:00
if (this.listThreadUid()) {
2019-07-05 03:19:24 +08:00
if (
messageList.length &&
2021-03-12 23:54:37 +08:00
!!messageList.find(item => !!(item && item.deleted() && item.uid === this.listThreadUid()))
2019-07-05 03:19:24 +08:00
) {
const message = messageList.find(item => item && !item.deleted());
2021-03-12 23:54:37 +08:00
if (message && this.listThreadUid() !== pString(message.uid)) {
this.listThreadUid(pString(message.uid));
2015-04-22 05:01:29 +08:00
rl.route.setHash(
2019-07-05 03:19:24 +08:00
mailBox(
FolderUserStore.currentFolderFullNameHash(),
2021-03-12 23:54:37 +08:00
this.listPage(),
this.listSearch(),
this.listThreadUid()
2019-07-05 03:19:24 +08:00
),
true,
true
);
} else if (!message) {
2021-03-12 23:54:37 +08:00
if (1 < this.listPage()) {
this.listPage(this.listPage() - 1);
2019-07-05 03:19:24 +08:00
rl.route.setHash(
2019-07-05 03:19:24 +08:00
mailBox(
FolderUserStore.currentFolderFullNameHash(),
2021-03-12 23:54:37 +08:00
this.listPage(),
this.listSearch(),
this.listThreadUid()
2019-07-05 03:19:24 +08:00
),
true,
true
);
} else {
2021-03-12 23:54:37 +08:00
this.listThreadUid('');
2015-04-22 05:01:29 +08:00
rl.route.setHash(
2019-07-05 03:19:24 +08:00
mailBox(
FolderUserStore.currentFolderFullNameHash(),
2021-03-12 23:54:37 +08:00
this.listPageBeforeThread(),
this.listSearch()
2019-07-05 03:19:24 +08:00
),
true,
true
);
}
2015-04-22 05:01:29 +08:00
}
}
}
2016-06-30 08:02:45 +08:00
}
/**
* @param {Object} messageTextBody
*/
initBlockquoteSwitcher(messageTextBody) {
2020-08-27 21:45:47 +08:00
messageTextBody && messageTextBody.querySelectorAll('blockquote:not(.rl-bq-switcher)').forEach(node => {
if (node.textContent.trim() && !node.parentNode.closest('blockquote')) {
let h = node.clientHeight || getRealHeight(node);
if (0 === h || 100 < h) {
const el = Element.fromHTML('<span class="rlBlockquoteSwitcher">•••</span>');
2020-08-27 21:45:47 +08:00
node.classList.add('rl-bq-switcher','hidden-bq');
node.before(el);
el.addEventListener('click', () => node.classList.toggle('hidden-bq'));
}
}
2020-08-27 21:45:47 +08:00
});
2016-06-30 08:02:45 +08:00
}
/**
2016-12-15 05:56:17 +08:00
* @param {Object} messageTextBody
* @param {Object} message
*/
2016-12-15 05:56:17 +08:00
initOpenPgpControls(messageTextBody, message) {
2020-08-27 21:45:47 +08:00
messageTextBody && messageTextBody.querySelectorAll('.b-plain-openpgp:not(.inited)').forEach(node =>
PgpUserStore.initMessageBodyControls(node, message)
2020-08-27 21:45:47 +08:00
);
2016-06-30 08:02:45 +08:00
}
2015-04-07 03:32:19 +08:00
setMessage(data, cached) {
2019-07-05 03:19:24 +08:00
let isNew = false,
body = null,
2020-10-23 21:15:54 +08:00
json = data && data.Result,
id = '',
plain = '',
resultHtml = '',
pgpSigned = false,
messagesDom = this.messagesBodiesDom(),
selectedMessage = this.selectorMessageSelected(),
message = this.message();
2019-07-05 03:19:24 +08:00
if (
2020-10-23 21:15:54 +08:00
json &&
MessageModel.validJson(json) &&
2019-07-05 03:19:24 +08:00
message &&
2020-10-23 21:15:54 +08:00
message.folder === json.Folder
2019-07-05 03:19:24 +08:00
) {
const threads = message.threads();
2020-10-23 21:15:54 +08:00
if (message.uid !== json.Uid && 1 < threads.length && threads.includes(json.Uid)) {
message = MessageModel.reviveFromJson(json);
2019-07-05 03:19:24 +08:00
if (message) {
message.threads(threads);
MessageFlagsCache.initMessage(message);
2015-02-22 06:00:51 +08:00
this.message(this.staticMessage.populateByMessageListItem(message));
message = this.message();
2016-06-30 08:02:45 +08:00
isNew = true;
}
2016-06-30 08:02:45 +08:00
}
2015-02-22 06:00:51 +08:00
2020-10-23 21:15:54 +08:00
if (message && message.uid === json.Uid) {
this.messageError('');
2015-02-22 06:00:51 +08:00
2020-10-23 21:15:54 +08:00
if (cached) {
delete json.IsSeen;
delete json.IsFlagged;
delete json.IsAnswered;
delete json.IsForwarded;
delete json.IsReadReceipt;
delete json.IsDeleted;
}
2015-03-06 08:42:40 +08:00
2020-10-23 21:15:54 +08:00
message.revivePropertiesFromJson(json);
addRequestedMessage(message.folder, message.uid);
2019-07-05 03:19:24 +08:00
if (messagesDom) {
id = 'rl-mgs-' + message.hash.replace(/[^a-zA-Z0-9]/g, '');
2016-06-30 08:02:45 +08:00
const textBody = elementById(id);
2020-08-27 21:45:47 +08:00
if (textBody) {
message.body = textBody;
message.fetchDataFromDom();
messagesDom.append(textBody);
2020-08-27 21:45:47 +08:00
} else {
let isHtml = !!json.Html;
if (isHtml) {
2020-10-23 21:15:54 +08:00
resultHtml = json.Html.toString();
if (SettingsUserStore.removeColors()) {
resultHtml = removeColors(resultHtml);
}
2020-10-23 21:15:54 +08:00
} else if (json.Plain) {
resultHtml = plainToHtml(json.Plain.toString());
2015-02-22 06:00:51 +08:00
if ((message.isPgpSigned() || message.isPgpEncrypted()) && PgpUserStore.capaOpenPGP()) {
2020-10-23 21:15:54 +08:00
plain = pString(json.Plain);
2019-07-05 03:19:24 +08:00
const isPgpEncrypted = /---BEGIN PGP MESSAGE---/.test(plain);
if (!isPgpEncrypted) {
pgpSigned =
/-----BEGIN PGP SIGNED MESSAGE-----/.test(plain) && /-----BEGIN PGP SIGNATURE-----/.test(plain);
}
const pre = doc.createElement('pre');
2019-07-05 03:19:24 +08:00
if (pgpSigned && message.isPgpSigned()) {
2020-08-27 21:45:47 +08:00
pre.className = 'b-plain-openpgp signed';
pre.textContent = plain;
2019-07-05 03:19:24 +08:00
} else if (isPgpEncrypted && message.isPgpEncrypted()) {
2020-08-27 21:45:47 +08:00
pre.className = 'b-plain-openpgp encrypted';
pre.textContent = plain;
2019-07-05 03:19:24 +08:00
} else {
2020-08-27 21:45:47 +08:00
pre.innerHTML = resultHtml;
}
2020-08-27 21:45:47 +08:00
resultHtml = pre.outerHTML;
message.isPgpSigned(pgpSigned);
message.isPgpEncrypted(isPgpEncrypted);
2019-07-05 03:19:24 +08:00
} else {
resultHtml = '<pre>' + resultHtml + '</pre>';
2015-07-30 01:21:24 +08:00
}
2019-07-05 03:19:24 +08:00
} else {
resultHtml = '<pre>' + resultHtml + '</pre>';
2015-03-06 08:42:40 +08:00
}
2015-02-22 06:00:51 +08:00
body = Element.fromHTML('<div id="' + id + '" hidden="" class="b-text-part '
2020-08-27 21:45:47 +08:00
+ (isHtml ? 'html' : 'plain') + '">'
+ findEmailAndLinks(resultHtml)
+ '</div>');
2015-03-06 08:42:40 +08:00
// Drop Microsoft Office style properties
const rgbRE = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/g,
hex = n => ('0' + parseInt(n).toString(16)).slice(-2);
body.querySelectorAll('[style*=mso]').forEach(el =>
el.setAttribute('style', el.style.cssText.replace(rgbRE, (m,r,g,b) => '#' + hex(r) + hex(g) + hex(b)))
);
message.body = body;
message.isHtml(isHtml);
2020-10-23 21:15:54 +08:00
message.hasImages(!!json.HasExternals);
2015-03-06 08:42:40 +08:00
2020-08-27 21:45:47 +08:00
messagesDom.append(body);
2015-02-22 06:00:51 +08:00
message.storeDataInDom();
2015-02-22 06:00:51 +08:00
2020-10-23 21:15:54 +08:00
if (json.HasInternals) {
2020-08-27 21:45:47 +08:00
message.showInternalImages();
}
if (message.hasImages() && SettingsUserStore.showImages()) {
2020-08-27 21:45:47 +08:00
message.showExternalImages();
}
2015-02-22 06:00:51 +08:00
this.purgeMessageBodyCacheThrottle();
2016-06-30 08:02:45 +08:00
}
this.messageActiveDom(message.body);
2016-06-30 08:02:45 +08:00
this.hideMessageBodies();
2016-06-30 08:02:45 +08:00
2019-07-05 03:19:24 +08:00
if (body) {
this.initOpenPgpControls(body, message);
2016-06-30 08:02:45 +08:00
this.initBlockquoteSwitcher(body);
}
2015-03-06 08:42:40 +08:00
2020-08-27 21:45:47 +08:00
message.body.hidden = false;
}
2016-06-30 08:02:45 +08:00
MessageFlagsCache.initMessage(message);
2020-10-23 21:15:54 +08:00
if (message.isUnseen() || message.hasUnseenSubMessage()) {
rl.app.messageListAction(message.folder, MessageSetAction.SetSeen, [message]);
2016-06-30 08:02:45 +08:00
}
2019-07-05 03:19:24 +08:00
if (isNew) {
message = this.message();
2015-03-06 08:42:40 +08:00
2019-07-05 03:19:24 +08:00
if (
selectedMessage &&
message &&
2020-10-23 21:15:54 +08:00
(message.folder !== selectedMessage.folder || message.uid !== selectedMessage.uid)
2019-07-05 03:19:24 +08:00
) {
this.selectorMessageSelected(null);
2021-03-12 23:54:37 +08:00
if (1 === this.list.length) {
this.selectorMessageFocused(null);
}
2019-07-05 03:19:24 +08:00
} else if (!selectedMessage && message) {
2021-03-12 23:54:37 +08:00
selectedMessage = this.list.find(
subMessage =>
2019-07-05 03:19:24 +08:00
subMessage &&
2020-10-23 21:15:54 +08:00
subMessage.folder === message.folder &&
subMessage.uid === message.uid
);
2019-07-05 03:19:24 +08:00
if (selectedMessage) {
this.selectorMessageSelected(selectedMessage);
this.selectorMessageFocused(selectedMessage);
}
2015-02-22 06:00:51 +08:00
}
}
2015-03-06 08:42:40 +08:00
}
}
2016-06-30 08:02:45 +08:00
}
2015-02-22 06:00:51 +08:00
selectMessage(oMessage) {
2019-07-05 03:19:24 +08:00
if (oMessage) {
this.message(this.staticMessage.populateByMessageListItem(oMessage));
this.populateMessageBody(this.message());
2019-07-05 03:19:24 +08:00
} else {
this.message(null);
}
2016-06-30 08:02:45 +08:00
}
2015-03-06 08:42:40 +08:00
selectMessageByFolderAndUid(sFolder, sUid) {
2019-07-05 03:19:24 +08:00
if (sFolder && sUid) {
this.message(this.staticMessage.populateByMessageListItem(null));
2020-10-23 21:15:54 +08:00
this.message().folder = sFolder;
this.message().uid = sUid;
2015-07-07 02:46:44 +08:00
this.populateMessageBody(this.message());
2019-07-05 03:19:24 +08:00
} else {
this.message(null);
}
2016-06-30 08:02:45 +08:00
}
2015-07-07 02:46:44 +08:00
populateMessageBody(oMessage) {
2021-03-12 23:54:37 +08:00
if (oMessage) {
this.hideMessageBodies();
this.messageLoading(true);
Remote.message(this.onMessageResponse, oMessage.folder, oMessage.uid);
2015-03-06 08:42:40 +08:00
}
2016-06-30 08:02:45 +08:00
}
2015-02-22 06:00:51 +08:00
/**
* @param {string} sResult
* @param {FetchJsonDefaultResponse} oData
* @param {boolean} bCached
*/
onMessageResponse(iError, oData, bCached) {
if (!iError && oData && oData.Result) {
this.setMessage(oData, bCached);
} else if (Remote.ABORT !== iError) {
this.message(null);
2019-07-05 03:19:24 +08:00
this.messageError(
oData && oData.ErrorCode ? getNotification(oData.ErrorCode) : getNotification(Notification.UnknownError)
);
}
2021-03-12 23:54:37 +08:00
this.messageLoading(false);
2016-06-30 08:02:45 +08:00
}
/**
2016-12-15 05:56:17 +08:00
* @param {Array} list
* @returns {string}
*/
calculateMessageListHash(list) {
return list.map(message => '' + message.hash + '_' + message.threadsLen() + '_' + message.flagHash()).join(
2019-07-05 03:19:24 +08:00
'|'
);
}
2016-06-30 08:02:45 +08:00
setMessageList(data, cached) {
const collection = data && MessageCollectionModel.reviveFromJson(data.Result, cached);
if (collection) {
let unreadCountChange = false;
2015-02-22 06:00:51 +08:00
const iCount = collection.MessageResultCount,
iOffset = collection.Offset,
folder = getFolderFromCacheList(collection.Folder);
2015-02-22 06:00:51 +08:00
2019-07-05 03:19:24 +08:00
if (folder && !cached) {
folder.interval = Date.now();
setFolderHash(collection.Folder, collection.FolderHash);
if (null != collection.MessageCount) {
folder.messageCountAll(collection.MessageCount);
2016-06-30 08:02:45 +08:00
}
if (null != collection.MessageUnseenCount) {
if (pInt(folder.messageCountUnread()) !== pInt(collection.MessageUnseenCount)) {
unreadCountChange = true;
MessageFlagsCache.clearFolder(folder.fullNameRaw);
}
2015-02-22 06:00:51 +08:00
folder.messageCountUnread(collection.MessageUnseenCount);
}
2016-06-30 08:02:45 +08:00
this.initUidNextAndNewMessages(folder.fullNameRaw, collection.UidNext, collection.NewMessages);
}
2016-06-30 08:02:45 +08:00
2021-03-12 23:54:37 +08:00
this.listCount(iCount);
this.listSearch(pString(collection.Search));
this.listPage(Math.ceil(iOffset / SettingsUserStore.messagesPerPage() + 1));
this.listThreadUid(pString(data.Result.ThreadUid));
2015-02-22 06:00:51 +08:00
2021-03-12 23:54:37 +08:00
this.listEndFolder(collection.Folder);
this.listEndSearch(this.listSearch());
this.listEndThreadUid(this.listThreadUid());
this.listEndPage(this.listPage());
2015-02-22 06:00:51 +08:00
2021-03-12 23:54:37 +08:00
this.listDisableAutoSelect(true);
2015-03-06 08:42:40 +08:00
2021-03-12 23:54:37 +08:00
this.list(collection);
this.listIsNotCompleted(false);
2015-02-22 06:00:51 +08:00
clearNewMessageCache();
2015-02-22 06:00:51 +08:00
if (folder && (cached || unreadCountChange || SettingsUserStore.useThreads())) {
rl.app.folderInformation(folder.fullNameRaw, collection);
}
2019-07-05 03:19:24 +08:00
} else {
2021-03-12 23:54:37 +08:00
this.listCount(0);
this.list([]);
this.listError(getNotification(data && data.ErrorCode ? data.ErrorCode : Notification.CantGetMessageList));
2015-02-22 06:00:51 +08:00
}
2016-06-30 08:02:45 +08:00
}
};