Bug 1402550 - Enable saving an .eml file directly. r=mkmelin

- Fix `cmd_saveAsFile` for .eml files that have just been opened from the file system.
- Disable `cmd_saveAsTemplate` when such a message is displayed.
- When an attached .eml file is opened, try to preserve the filename in the URI (see bug 927640)

Based on https://github.com/Betterbird/thunderbird-patches/blob/main/128/bugs/927640-1402550-fix-saving-eml.patch, which is itself based on SeaMonkey code.

Differential Revision: https://phabricator.services.mozilla.com/D220719

--HG--
extra : amend_source : 5ffbc0fa2887431b173420fcbc7399ab72b76b55
This commit is contained in:
welpy-cw 2024-09-06 10:37:37 +12:00
Родитель de3bd1b3be
Коммит 3bdd1607d6
5 изменённых файлов: 126 добавлений и 2 удалений

Просмотреть файл

@ -484,10 +484,33 @@ function SubscribeOKCallback(changeTable) {
}
}
/**
* Save as file.
*
* @param {string[]} uris - URIs of files to save.
*/
function SaveAsFile(uris) {
const filenames = [];
for (const uri of uris) {
// Save an .eml files directly from its URL.
if (/type=application\/x-message-display$/.test(uri)) {
top.saveURL(
uri, // URL
null, // originalURL
"", // fileName (ignored)
null, // filePickerTitleKey
true, // shouldBypassCache
false, // skipPrompt
null, // referrerInfo
null, // cookieJarSettings
document, // sourceDocument
null, // isContentWindowPrivate,
Services.scriptSecurityManager.getSystemPrincipal() // principal
);
return;
}
const msgHdr =
MailServices.messageServiceFromURI(uri).messageURIToMsgHdr(uri);
const nameBase = GenerateFilenameFromMsgHdr(msgHdr);

Просмотреть файл

@ -537,8 +537,9 @@ var commandController = {
}
return false;
case "cmd_viewPageSource":
case "cmd_saveAsTemplate":
return numSelectedMessages == 1;
case "cmd_saveAsTemplate":
return numSelectedMessages == 1 && !isDummyMessage;
case "cmd_reply":
case "cmd_replySender":
case "cmd_replyall":

Просмотреть файл

@ -242,7 +242,16 @@ export class AttachmentInfo {
let tempFile = this.#temporaryFiles.get(url);
if (!tempFile?.exists()) {
tempFile = Services.dirsvc.get("TmpD", Ci.nsIFile);
tempFile.append("subPart.eml");
// Try to use the name of the attachment for the temporary file, so
// that the name is included in the URI of the message that is
// opened, and possibly saved as a file later by the user.
let sanitizedName = lazy.DownloadPaths.sanitize(this.name);
if (!sanitizedName) {
sanitizedName = "message.eml";
} else if (!/\.eml$/i.test(sanitizedName)) {
sanitizedName += ".eml";
}
tempFile.append(sanitizedName);
tempFile.createUnique(0, 0o600);
await saveToFile(tempFile.path, true);

Просмотреть файл

@ -202,6 +202,57 @@ add_task(async function test_forward_eml_catchall() {
await BrowserTestUtils.closeWindow(msgc); // close base .eml message
});
/**
* Test that saving an .eml opened from a file works.
*/
add_task(async function test_save_eml_as_file() {
const file = new FileUtils.File(getTestFilePath("data/testmsg.eml"));
const msgc = await open_message_from_file(file);
const pickerPromise = new Promise(resolve => {
SpecialPowers.MockFilePicker.init(window.browsingContext);
SpecialPowers.MockFilePicker.showCallback = picker => {
resolve(picker.defaultString);
return Ci.nsIFilePicker.returnOK;
};
});
EventUtils.synthesizeKey("s", { accelKey: true }, msgc);
Assert.equal(await pickerPromise, "testmsg.eml");
SpecialPowers.MockFilePicker.cleanup();
await BrowserTestUtils.closeWindow(msgc);
});
/**
* Test that an attached .eml that has been opened retains the correct filename
* when it is subsequently saved.
*/
add_task(async function test_save_eml_as_file() {
const file = new FileUtils.File(getTestFilePath("data/testmsg-nested.eml"));
const msgc = await open_message_from_file(file);
const aboutMessage = get_about_message(msgc);
const newWindowPromise = promise_new_window("mail:messageWindow");
await EventUtils.synthesizeMouseAtCenter(
aboutMessage.document.getElementById("attachmentName"),
{},
aboutMessage
);
const msgc2 = await newWindowPromise;
const pickerPromise = new Promise(resolve => {
SpecialPowers.MockFilePicker.init(window.browsingContext);
SpecialPowers.MockFilePicker.showCallback = picker => {
resolve(picker.defaultString);
return Ci.nsIFilePicker.returnOK;
};
});
EventUtils.synthesizeKey("s", { accelKey: true }, msgc2);
Assert.ok(
/that's why(-(\d)+)?\.eml/.test(await pickerPromise),
"Correct filename"
);
SpecialPowers.MockFilePicker.cleanup();
await BrowserTestUtils.closeWindow(msgc2);
await BrowserTestUtils.closeWindow(msgc);
});
/**
* Test that clicking on a 'mailto:' link in an .eml opens a compose window.
*/

Просмотреть файл

@ -0,0 +1,40 @@
Content-Type: multipart/mixed; boundary="------------86SaFvMNv7NcfmcG7KkR6fEI"
Message-ID: <69bfee4a-e114-4e84-8c4b-6dc7a983a58a@example.com>
Date: Tue, 3 Sep 2024 17:15:35 +0200
MIME-Version: 1.0
User-Agent: Mozilla Thunderbird
From: Marge <marge@example.com>
Subject: that's why
To: Homer <homer@example.com>
Content-Language: en-US
This is a multi-part message in MIME format.
--------------86SaFvMNv7NcfmcG7KkR6fEI
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
--------------86SaFvMNv7NcfmcG7KkR6fEI
Content-Type: message/rfc822; name=that's why.eml"
Content-Disposition: attachment; filename="that's why.eml"
Content-Transfer-Encoding: 7bit
Return-Path: <homer@example.com>
Received: from smtp.example.com (smtpu [10.0.0.52])
by storage (Cyrus v2.3.7-Invoca-RPM-2.3.7-1.1) with LMTPA;
Mon, 26 Dec 2011 20:49:16 +0200
Message-ID: <4EF8C1A5.1060708@example.com>
Date: Mon, 26 Dec 2011 20:49:09 +0200
From: Homer <homer@example.com>
MIME-Version: 1.0
To: Marge <marge@example.com>
Subject: why
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Because they're stupid, that's why. That's why everybody does everything!
-Homer
--------------86SaFvMNv7NcfmcG7KkR6fEI--