Skip to content
Permalink
Browse files

BUG: Inline images corrupted when editing previously scheduled message

As per https://bugzilla.mozilla.org/show_bug.cgi?id=1389242, there is
currently a bug in Thunderbird: when editing a previously saved draft,
Thunderbird tells add-ons that the draft has finished being loaded
into the editor when in fact embedded images haven't finished loading
yet.

Since Send Later saves previously scheduled drafts immediately when
they start being edited to prevent them from being delivered on
schedule while they are being edited, this is problematic... If there
are any embedded images in the draft, they haven't been loaded yet, so
the saved draft gets corrupted.

This commit sets up a watcher in the background which keeps checking
the body of the message for up to two seconds (which should be more
than enough -- it usually doesn't take more than 10 to 20
milliseconds) for the embedded images to be finished loading, and
_then_ saves the draft.

This is a gross workaround, but I think it's the best we can do for
the time being.
  • Loading branch information
Jonathan Kamens
Jonathan Kamens committed Aug 11, 2017
1 parent 7275f1f commit 95010466da7f389419631e69894ea85d8a6c07fb
Showing with 85 additions and 3 deletions.
  1. +85 −3 chrome/content/composing.js
@@ -8,15 +8,97 @@ if (typeof(nsIMsgCompDeliverMode) == 'undefined')
nsIMsgCompDeliverMode = Components.interfaces.nsIMsgCompDeliverMode;

var Sendlater3Composing = {
composeListener: {
NotifyComposeBodyReady: function() {
// Unfortunately, the NotifyComposeBodyReady event lies nowadays -- the
// message body isn't actually ready when this event comes in, because
// inline images from the original message are still being loaded in the
// background. See https://bugzilla.mozilla.org/show_bug.cgi?id=1389242. As
// a workaround, we crib a bunch of code from MsgComposeCommands.js in the
// Thunderbird source tree to detect if we are still in the process of
// loading inline images, and if so, delay the save until that's finished.
// we check repeatedly for 2 seconds, and if we still haven't finished
// loading images at the end of 2 seconds we go ahead and do the save
// anyway, because it's important for us to cancel the scheduled send
// quickly, even if that means the inline images get screwed up in the
// draft. Note that they'll get fixed when the user finishes editing the
// draft and schedules or saves it.
tryToSave: function() {
doTheDarnSave = function() {
gContentChanged = true;
SaveAsDraft();
if (SL3U.getBoolPref("show_edit_alert")) {
SL3U.alert(window, null,
SL3U.PromptBundleGet("draftSaveWarning"));
}
},
};

try {
let tryToSaveCallback = null;
tryToSaveCallback = {
saveTimeout: 2000,
startTime: Date.now(),
waiting: false,
notify: function(timer) {
if (Date.now() - this.startTime > this.saveTimeout) {
sl3log.info("tryToSave: saving after 2-second timeout");
doTheDarnSave();
return;
}
if (! gOriginalMsgURI) {
sl3log.debug("tryToSave: no original URI, saving");
doTheDarnSave();
return;
}
let msgSvc = Components.classes["@mozilla.org/messenger;1"]
.createInstance(Components.interfaces.nsIMessenger)
.messageServiceFromURI(gOriginalMsgURI);
let originalMsgNeckoURI = {};
msgSvc.GetUrlForUri(
gOriginalMsgURI, originalMsgNeckoURI, null);
let spec = originalMsgNeckoURI.value.spec;
let count = 0;
let sampleUrl = null;
for (let img of GetCurrentEditor().document.images) {
if (img.src.startsWith(spec)) {
sampleUrl = img.src;
count++;
}
}
if (count == 0) {
sl3log.debug("tryToSave: no images to load, saving");
doTheDarnSave();
return;
}
let timeLeft = this.startTime + this.saveTimeout -
Date.now();
msg = "tryToSave: waiting for up to " + timeLeft + "ms " +
(this.waiting ? "more " : "") + "for " + count +
" inline images including " + sampleUrl + " to load";
if (! this.waiting) {
this.waiting = true;
sl3log.info(msg);
}
else {
sl3log.debug(msg);
}
timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
timer.initWithCallback(
tryToSaveCallback, 0,
Components.interfaces.nsITimer.type_ONE_SHOT);
return;
}
};
tryToSaveCallback.notify();
} catch (ex) {
sl3log.info("tryToSave: Error \"" + String(ex) + "\" waiting for " +
"inline images to load; saving immediately");
doTheDarnSave();
return;
}
},

composeListener: {
NotifyComposeBodyReady: function() { Sendlater3Composing.tryToSave(); },
NotifyComposeFieldsReady: function() {},
ComposeProcessDone: function() {},
SaveInFolderDone: function() {}

0 comments on commit 9501046

Please sign in to comment.