Skip to content

Commit

Permalink
webmail: fix using the compose window/popup after saving a draft mess…
Browse files Browse the repository at this point in the history
…age 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
  • Loading branch information
mjl- committed Nov 28, 2024
1 parent bd69380 commit ee48cf0
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 12 deletions.
17 changes: 11 additions & 6 deletions webmail/webmail.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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?
Expand All @@ -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) => {
Expand Down Expand Up @@ -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 = [];
Expand Down
16 changes: 10 additions & 6 deletions webmail/webmail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1464,7 +1464,7 @@ const compose = (opts: ComposeOptions, listMailboxes: listMailboxes) => {
let draftSavePromise = Promise.resolve(0)
let draftLastText = opts.body

const draftCancelSave = () => {
const draftCancelSaveTimer = () => {
if (draftSaveTimer) {
window.clearTimeout(draftSaveTimer)
draftSaveTimer = 0
Expand All @@ -1483,7 +1483,7 @@ const compose = (opts: ComposeOptions, listMailboxes: listMailboxes) => {
}

const draftSave = async () => {
draftCancelSave()
draftCancelSaveTimer()
let replyTo = ''
if (replytoViews && replytoViews.length === 1 && replytoViews[0].input.value) {
replyTo = replytoViews[0].input.value
Expand All @@ -1504,7 +1504,11 @@ const compose = (opts: ComposeOptions, listMailboxes: 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
}

Expand All @@ -1518,7 +1522,7 @@ const compose = (opts: ComposeOptions, listMailboxes: 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<string>((resolve) => {
Expand Down Expand Up @@ -1560,13 +1564,13 @@ const compose = (opts: ComposeOptions, listMailboxes: listMailboxes) => {
}

const cmdSave = async () => {
draftCancelSave()
draftCancelSaveTimer()
await draftSavePromise
await withStatus('Saving draft', draftSave())
}

const submit = async (archive: boolean) => {
draftCancelSave()
draftCancelSaveTimer()
await draftSavePromise

const files = await new Promise<api.File[]>((resolve, reject) => {
Expand Down

0 comments on commit ee48cf0

Please sign in to comment.