webmail: fix using the compose window/popup after saving a draft message failed

we kept the "save draft" promise, and would wait for it again for other
operations (eg close, save again, send), which wouldn't make progress.

can easily be reproduced by saving a message with a control character in an
address or the subject. saving the draft will fail.

for issue #256 by ally9335, thanks for reporting
This commit is contained in:
Mechiel Lukkien
2024-11-28 17:22:01 +01:00
parent bd693805fd
commit ee48cf0dfd
2 changed files with 21 additions and 12 deletions

View File

@ -2581,7 +2581,7 @@ const compose = (opts, listMailboxes) => {
let draftSaveTimer = 0;
let draftSavePromise = Promise.resolve(0);
let draftLastText = opts.body;
const draftCancelSave = () => {
const draftCancelSaveTimer = () => {
if (draftSaveTimer) {
window.clearTimeout(draftSaveTimer);
draftSaveTimer = 0;
@ -2598,7 +2598,7 @@ const compose = (opts, listMailboxes) => {
}, 60 * 1000);
};
const draftSave = async () => {
draftCancelSave();
draftCancelSaveTimer();
let replyTo = '';
if (replytoViews && replytoViews.length === 1 && replytoViews[0].input.value) {
replyTo = replytoViews[0].input.value;
@ -2619,7 +2619,12 @@ const compose = (opts, listMailboxes) => {
throw new Error('no designated drafts mailbox');
}
draftSavePromise = client.MessageCompose(cm, mbdrafts.ID);
draftMessageID = await draftSavePromise;
try {
draftMessageID = await draftSavePromise;
}
finally {
draftSavePromise = Promise.resolve(0);
}
draftLastText = cm.TextBody;
};
// todo future: on visibilitychange with visibilityState "hidden", use navigator.sendBeacon to save latest modified draft message?
@ -2630,7 +2635,7 @@ const compose = (opts, listMailboxes) => {
// triggered. But we still have the beforeunload handler that checks for
// unsavedChanges to protect the user in such cases.
const cmdClose = async () => {
draftCancelSave();
draftCancelSaveTimer();
await draftSavePromise;
if (unsavedChanges()) {
const action = await new Promise((resolve) => {
@ -2664,12 +2669,12 @@ const compose = (opts, listMailboxes) => {
composeView = null;
};
const cmdSave = async () => {
draftCancelSave();
draftCancelSaveTimer();
await draftSavePromise;
await withStatus('Saving draft', draftSave());
};
const submit = async (archive) => {
draftCancelSave();
draftCancelSaveTimer();
await draftSavePromise;
const files = await new Promise((resolve, reject) => {
const l = [];