Commit 69552d82 authored by Carsten Schoenert's avatar Carsten Schoenert
Browse files

New upstream version 78.10.2

parent f38d78f8
......@@ -50,6 +50,7 @@ support-files =
dummy_iframe_page.html
[browser_identity_UI.js]
[browser_identityBlock_flicker.js]
skip-if = true # bug 1667456 made this permafail, but it's a regression we'll accept on ESR
[browser_identityBlock_focus.js]
support-files = ../permissions/permissions.html
[browser_identityIcon_img_url.js]
......
---
GECKO_BASE_REPOSITORY: https://hg.mozilla.org/mozilla-unified
GECKO_HEAD_REPOSITORY: https://hg.mozilla.org/releases/mozilla-esr78
GECKO_HEAD_REF: FIREFOX_78_10_0esr_BUILD1
GECKO_HEAD_REV: 0dac34b853c6879d421456128afa3c4a5a4e86ff
GECKO_HEAD_REF: FIREFOX_78_10_1esr_BUILD1
GECKO_HEAD_REV: f685975ba5576001483e5521e06d5a0ccf9b5f54
### For comm-central
# GECKO_BASE_REPOSITORY: https://hg.mozilla.org/mozilla-unified
......
......@@ -199,7 +199,7 @@ var calendarController = {
return this.item_selected;
case "calendar_reload_remote_calendars":
return this.has_enabled_network_calendars && !this.offline;
return this.has_enabled_reloadable_calendars && !this.offline;
case "calendar_attendance_command": {
let attendSel = false;
if (this.todo_tasktree_focused) {
......@@ -570,15 +570,17 @@ var calendarController = {
/**
* Returns a boolean indicating whether there is at least one enabled
* calendar that requires network access.
* calendar that can be reloaded. Note: ICS calendars can have a network URL
* or a file URL, but both are reloadable.
*/
get has_enabled_network_calendars() {
get has_enabled_reloadable_calendars() {
return cal
.getCalendarManager()
.getCalendars()
.some(
calendar =>
!calendar.getProperty("disabled") && calendar.getProperty("requiresNetwork") !== false
!calendar.getProperty("disabled") &&
(calendar.type == "ics" || calendar.getProperty("requiresNetwork") !== false)
);
},
......
......@@ -15,6 +15,23 @@ var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
var { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
var gShutdownDetected = false;
/**
* Detects the "mail-unloading-messenger" notification to prevent snoozing items
* as well as closes this window when the main window is closed. Not doing so can
* cause data loss with CalStorageCalendar.
*/
var gShutdownObserver = {
observe() {
let windows = Array.from(Services.wm.getEnumerator("mail:3pane"));
if (windows.filter(win => !win.closed).length == 0) {
gShutdownDetected = true;
window.close();
}
},
};
addEventListener("DOMContentLoaded", () => {
document.getElementById("alarm-snooze-all-popup").addEventListener("snooze", event => {
snoozeAllItems(event.detail);
......@@ -133,6 +150,9 @@ function setupWindow() {
gRelativeDateUpdateTimer = setInterval(updateRelativeDates, 60 * 1000);
}, timeout);
// Configure the shutdown observer.
Services.obs.addObserver(gShutdownObserver, "mail-unloading-messenger");
// Give focus to the alarm richlist after onload completes. See bug 103197
setTimeout(onFocusWindow, 0);
}
......@@ -142,6 +162,12 @@ function setupWindow() {
* alarms and clean up the relative date update timer.
*/
function finishWindow() {
Services.obs.removeObserver(gShutdownObserver, "mail-unloading-messenger");
if (gShutdownDetected) {
return;
}
let alarmRichlist = document.getElementById("alarm-richlist");
if (alarmRichlist.children.length > 0) {
......@@ -153,6 +179,7 @@ function finishWindow() {
if (snoozePref <= 0) {
snoozePref = 5;
}
snoozeAllItems(snoozePref);
}
......
......@@ -30,3 +30,26 @@ section > .addon-detail-row-private-browsing,
.addon-detail-row-private-browsing + .addon-detail-row.addon-detail-help-row {
display: none;
}
/* Hide the options entry in the options menu, as we have a dedicated button */
addon-options panel-item[action="preferences"] {
display:none;
}
.extension-options-button {
min-width: auto;
min-height: auto;
width: 24px;
height: 24px;
margin: 0;
margin-inline-start: 8px;
-moz-context-properties: fill;
fill: currentColor;
background-image: url("chrome://messenger/skin/icons/developer.svg");
background-repeat: no-repeat;
background-position: center center;
/* Get the -badged ::after element in the right spot. */
padding: 1px;
display: flex;
justify-content: flex-end;
}
......@@ -73,6 +73,44 @@ XPCOMUtils.defineLazyModuleGetters(this, {
return _getScreenshotUrlForAddon(addon);
};
// Override parts of the addon-card customElement to be able
// to add a dedicated button for extension preferences.
await customElements.whenDefined("addon-card");
AddonCard.prototype.addOptionsButton = async function() {
let { addon, optionsButton } = this;
if (addon.type != "extension") {
return;
}
let addonOptionsButton = this.querySelector(".extension-options-button");
if (addon.isActive) {
if (!addon.optionsType) {
// Upon fresh install the manifest has not been parsed and optionsType
// is not known, manually trigger parsing.
let data = new ExtensionData(addon.getResourceURI());
await data.loadManifest();
}
if (addon.optionsType) {
if (!addonOptionsButton) {
addonOptionsButton = document.createElement("button");
addonOptionsButton.classList.add("extension-options-button");
addonOptionsButton.setAttribute("action", "preferences");
optionsButton.parentNode.insertBefore(
addonOptionsButton,
optionsButton
);
}
}
} else if (addonOptionsButton) {
addonOptionsButton.remove();
}
};
AddonCard.prototype._update = AddonCard.prototype.update;
AddonCard.prototype.update = function() {
this._update();
this.addOptionsButton();
};
// Override parts of the addon-permission-list customElement to be able
// to show the usage of Experiments in the permission list.
await customElements.whenDefined("addon-permissions-list");
......
......@@ -151,7 +151,8 @@ class PromptParent extends JSWindowActorParent {
try {
if (browser) {
browser.enterModalState();
// The compose editor does not support enter/leaveModalState.
browser.enterModalState?.();
PromptUtils.fireDialogEvent(win, "DOMWillOpenModalDialog", browser);
}
......@@ -168,7 +169,7 @@ class PromptParent extends JSWindowActorParent {
PromptUtils.propBagToObject(bag, args);
} finally {
if (browser) {
browser.leaveModalState();
browser.leaveModalState?.();
PromptUtils.fireDialogEvent(win, "DOMModalDialogClosed", browser);
}
}
......
......@@ -230,13 +230,15 @@ var snapshotFormatters = {
let fsType;
try {
fsType = AboutSupportPlatform.getFileSystemType(currProfD);
let bundle = Services.strings.createBundle(
"chrome://messenger/locale/aboutSupportMail.properties"
);
let fsText = bundle.GetStringFromName("fsType." + fsType);
let fsTextNode = document.createElement("span");
fsTextNode.textContent = fsText;
profElem.appendChild(fsTextNode);
if (fsType) {
let bundle = Services.strings.createBundle(
"chrome://messenger/locale/aboutSupportMail.properties"
);
let fsText = bundle.GetStringFromName("fsType." + fsType);
let fsTextNode = document.createElement("span");
fsTextNode.textContent = fsText;
profElem.appendChild(fsTextNode);
}
} catch (x) {
Cu.reportError(x);
}
......
......@@ -271,15 +271,17 @@ this.menus = class extends ExtensionAPI {
// eslint-disable-next-line no-undef
new ComposeAttachment(context, a).api()
);
}
withHandlingUserInput(context.contentWindow, () =>
fire.asyncWithoutClone(
Cu.cloneInto(info, context.cloneScope, {
cloneFunctions: true,
}),
Cu.cloneInto(tab, context.cloneScope)
)
);
);
} else {
withHandlingUserInput(context.contentWindow, () =>
fire.sync(info, tab)
);
}
};
let event = context.childManager.getParentEvent("menus.onClicked");
......
......@@ -1470,7 +1470,19 @@ function convertMailIdentity(account, identity) {
* Convert a folder URI to a human-friendly path.
* @return {String}
*/
function folderURIToPath(uri) {
function folderURIToPath(accountId, uri) {
let server = MailServices.accounts.getAccount(accountId).incomingServer;
let rootURI = server.rootFolder.URI;
if (rootURI == uri) {
return "/";
}
// The .URI property of an IMAP folder doesn't have %-encoded characters, but
// may include literal % chars. Services.io.newURI(uri) applies encodeURI to
// the returned filePath, but will not encode any literal % chars, which will
// cause decodeURIComponent to fail (bug 1707408).
if (server.type == "imap") {
return uri.substring(rootURI.length);
}
let path = Services.io.newURI(uri).filePath;
return path
.split("/")
......@@ -1540,7 +1552,7 @@ function convertFolder(folder, accountId) {
let folderObject = {
accountId,
name: folder.prettyName,
path: folderURIToPath(folder.URI),
path: folderURIToPath(accountId, folder.URI),
};
for (let [flag, typeName] of folderTypeMap.entries()) {
......
......@@ -207,12 +207,16 @@ this.messages = class extends ExtensionAPI {
);
},
async getFull(messageId) {
return new Promise(resolve => {
let mimeMsg = await new Promise(resolve => {
let msgHdr = messageTracker.getMessage(messageId);
MsgHdrToMimeMessage(msgHdr, null, (_msgHdr, mimeMsg) => {
resolve(convertMessagePart(mimeMsg));
resolve(mimeMsg);
});
});
if (!mimeMsg) {
throw new ExtensionError(`Error reading message ${messageId}`);
}
return convertMessagePart(mimeMsg);
},
async getRaw(messageId) {
let messenger = Cc["@mozilla.org/messenger;1"].createInstance(
......
......@@ -85,8 +85,8 @@ add_task(async function test_accounts() {
subFolders: [
{
accountId: account1Id,
name: "foo 'bar'(!)",
path: "/Trash/foo 'bar'(!)",
name: "%foo %test% 'bar'(!)+",
path: "/Trash/%foo %test% 'bar'(!)+",
},
{
accountId: account1Id,
......@@ -123,8 +123,8 @@ add_task(async function test_accounts() {
subFolders: [
{
accountId: account2Id,
name: "foo 'bar'(!)",
path: "/INBOX/foo 'bar'(!)",
name: "%foo %test% 'bar'(!)+",
path: "/INBOX/%foo %test% 'bar'(!)+",
},
{
accountId: account2Id,
......@@ -182,14 +182,14 @@ add_task(async function test_accounts() {
await extension.awaitMessage("create folders");
let inbox1 = [...account1.incomingServer.rootFolder.subFolders][0];
// Test our code can handle characters that might be escaped.
inbox1.createSubfolder("foo 'bar'(!)", null);
inbox1.createSubfolder("%foo %test% 'bar'(!)+", null);
inbox1.createSubfolder("Ϟ", null); // Test our code can handle unicode.
let inbox2 = [...account2.incomingServer.rootFolder.subFolders][0];
inbox2.QueryInterface(Ci.nsIMsgImapMailFolder).hierarchyDelimiter = "/";
// Test our code can handle characters that might be escaped.
inbox2.createSubfolder("foo 'bar'(!)", null);
await PromiseTestUtils.promiseFolderAdded("foo 'bar'(!)");
inbox2.createSubfolder("%foo %test% 'bar'(!)+", null);
await PromiseTestUtils.promiseFolderAdded("%foo %test% 'bar'(!)+");
inbox2.createSubfolder("Ϟ", null); // Test our code can handle unicode.
await PromiseTestUtils.promiseFolderAdded("Ϟ");
......
......@@ -198,7 +198,7 @@ tb.mails:
keyed: true
keys:
- 'signed-smime'
- 'signed-opengpg'
- 'signed-openpgp'
- 'encrypted-smime'
- 'encrypted-openpgp'
kind: uint
......
......@@ -789,7 +789,8 @@ async function reloadOpenPgpUI() {
let dateButton = document.createXULElement("button");
document.l10n.setAttributes(dateButton, "openpgp-key-man-change-expiry");
dateButton.addEventListener("command", () => {
dateButton.addEventListener("command", event => {
event.stopPropagation();
enigmailEditKeyDate(key);
});
dateButton.setAttribute("hidden", "true");
......@@ -908,7 +909,8 @@ async function reloadOpenPgpUI() {
let info = document.createXULElement("button");
info.classList.add("openpgp-image-btn", "openpgp-props-btn");
document.l10n.setAttributes(info, "openpgp-key-man-key-props");
info.addEventListener("command", () => {
info.addEventListener("command", event => {
event.stopPropagation();
enigmailKeyDetails(key.keyId);
});
......@@ -921,37 +923,43 @@ async function reloadOpenPgpUI() {
let copyItem = document.createXULElement("menuitem");
document.l10n.setAttributes(copyItem, "openpgp-key-copy-key");
copyItem.addEventListener("command", () => {
copyItem.addEventListener("command", event => {
event.stopPropagation();
openPgpCopyToClipboard(`0x${key.keyId}`);
});
let sendItem = document.createXULElement("menuitem");
document.l10n.setAttributes(sendItem, "openpgp-key-send-key");
sendItem.addEventListener("command", () => {
sendItem.addEventListener("command", event => {
event.stopPropagation();
openPgpSendKeyEmail(`0x${key.keyId}`);
});
let exportItem = document.createXULElement("menuitem");
document.l10n.setAttributes(exportItem, "openpgp-key-export-key");
exportItem.addEventListener("command", () => {
exportItem.addEventListener("command", event => {
event.stopPropagation();
openPgpExportPublicKey(`0x${key.keyId}`);
});
let backupItem = document.createXULElement("menuitem");
document.l10n.setAttributes(backupItem, "openpgp-key-backup-key");
backupItem.addEventListener("command", () => {
backupItem.addEventListener("command", event => {
event.stopPropagation();
openPgpExportSecretKey(`0x${key.keyId}`, `0x${key.fpr}`);
});
let revokeItem = document.createXULElement("menuitem");
document.l10n.setAttributes(revokeItem, "openpgp-key-man-revoke-key");
revokeItem.addEventListener("command", () => {
revokeItem.addEventListener("command", event => {
event.stopPropagation();
openPgpRevokeKey(key);
});
let deleteItem = document.createXULElement("menuitem");
document.l10n.setAttributes(deleteItem, "openpgp-delete-key");
deleteItem.addEventListener("command", () => {
deleteItem.addEventListener("command", event => {
event.stopPropagation();
enigmailDeleteKey(key);
});
......
......@@ -24,8 +24,8 @@ var { OpenPGPMasterpass } = ChromeUtils.import(
var { PgpSqliteDb2 } = ChromeUtils.import(
"chrome://openpgp/content/modules/sqliteDb.jsm"
);
var { uidHelper } = ChromeUtils.import(
"chrome://openpgp/content/modules/uidHelper.jsm"
const { EnigmailFuncs } = ChromeUtils.import(
"chrome://openpgp/content/modules/funcs.jsm"
);
var { GPGME } = ChromeUtils.import(
"chrome://openpgp/content/modules/GPGME.jsm"
......@@ -88,6 +88,12 @@ var RNP = {
keyObj.secretAvailable = this.getSecretAvailableFromHandle(handle);
if (keyObj.secretAvailable) {
keyObj.secretMaterial = RNPLib.isSecretKeyMaterialAvailable(handle);
} else {
keyObj.secretMaterial = false;
}
if (is_subkey) {
keyObj.type = "sub";
} else {
......@@ -192,83 +198,11 @@ var RNP = {
},
getProtectedKeysCount() {
let prot = 0;
let unprot = 0;
let iter = new RNPLib.rnp_identifier_iterator_t();
let grip = new ctypes.char.ptr();
if (
RNPLib.rnp_identifier_iterator_create(RNPLib.ffi, iter.address(), "grip")
) {
throw new Error("rnp_identifier_iterator_create failed");
}
while (!RNPLib.rnp_identifier_iterator_next(iter, grip.address())) {
if (grip.isNull()) {
break;
}
let handle = new RNPLib.rnp_key_handle_t();
if (RNPLib.rnp_locate_key(RNPLib.ffi, "grip", grip, handle.address())) {
throw new Error("rnp_locate_key failed");
}
if (this.getSecretAvailableFromHandle(handle)) {
let is_protected = new ctypes.bool();
if (RNPLib.rnp_key_is_protected(handle, is_protected.address())) {
throw new Error("rnp_key_is_protected failed");
}
if (is_protected.value) {
prot++;
} else {
unprot++;
}
}
RNPLib.rnp_key_handle_destroy(handle);
}
RNPLib.rnp_identifier_iterator_destroy(iter);
return [prot, unprot];
return RNPLib.getProtectedKeysCount();
},
async protectUnprotectedKeys() {
let iter = new RNPLib.rnp_identifier_iterator_t();
let grip = new ctypes.char.ptr();
let newPass = await OpenPGPMasterpass.retrieveOpenPGPPassword();
if (
RNPLib.rnp_identifier_iterator_create(RNPLib.ffi, iter.address(), "grip")
) {
throw new Error("rnp_identifier_iterator_create failed");
}
while (!RNPLib.rnp_identifier_iterator_next(iter, grip.address())) {
if (grip.isNull()) {
break;
}
let handle = new RNPLib.rnp_key_handle_t();
if (RNPLib.rnp_locate_key(RNPLib.ffi, "grip", grip, handle.address())) {
throw new Error("rnp_locate_key failed");
}
if (this.getSecretAvailableFromHandle(handle)) {
let is_protected = new ctypes.bool();
if (RNPLib.rnp_key_is_protected(handle, is_protected.address())) {
throw new Error("rnp_key_is_protected failed");
}
if (!is_protected.value) {
this.protectKeyWithSubKeys(handle, newPass);
}
}
RNPLib.rnp_key_handle_destroy(handle);
}
RNPLib.rnp_identifier_iterator_destroy(iter);
return RNPLib.protectUnprotectedKeys();
},
/* Some consumers want a different listing of keys, and expect
......@@ -392,11 +326,7 @@ var RNP = {
},
getSecretAvailableFromHandle(handle) {
let have_secret = new ctypes.bool();
if (RNPLib.rnp_key_have_secret(handle, have_secret.address())) {
throw new Error("rnp_key_have_secret failed");
}
return have_secret.value;
return RNPLib.getSecretAvailableFromHandle(handle);
},
// We already know sub_handle is a subkey
......@@ -997,7 +927,9 @@ var RNP = {
false
);
let max_out = encrypted.length * 10;
// Allow compressed encrypted messages, max factor 1200, up to 100 MiB.
const max_decrypted_message_size = 100 * 1024 * 1024;
let max_out = Math.min(encrypted.length * 1200, max_decrypted_message_size);
let output_to_memory = new RNPLib.rnp_output_t();
RNPLib.rnp_output_to_memory(output_to_memory.address(), max_out);
......@@ -1349,13 +1281,13 @@ var RNP = {
if (uid.type !== "uid") {
continue;
}
let split = {};
if (uidHelper.getPartsFromUidStr(uid.userId, split)) {
let uidEmail = split.email.toLowerCase();
if (uidEmail === fromLower) {
fromMatchesAnyUid = true;
break;
}
if (
EnigmailFuncs.getEmailFromUserID(uid.userId).toLowerCase() ===
fromLower
) {
fromMatchesAnyUid = true;
break;
}
}
......@@ -1786,28 +1718,6 @@ var RNP = {
return rv;
},
protectKeyWithSubKeys(handle, newPass) {
if (RNPLib.rnp_key_protect(handle, newPass, null, null, null, 0)) {
throw new Error("rnp_key_protect failed");
}
let sub_count = new ctypes.size_t();
if (RNPLib.rnp_key_get_subkey_count(handle, sub_count.address())) {
throw new Error("rnp_key_get_subkey_count failed");
}
for (let i = 0; i < sub_count.value; i++) {
let sub_handle = new RNPLib.rnp_key_handle_t();
if (RNPLib.rnp_key_get_subkey_at(handle, i, sub_handle.address())) {
throw new Error("rnp_key_get_subkey_at failed");
}
if (RNPLib.rnp_key_protect(sub_handle, newPass, null, null, null, 0)) {
throw new Error("rnp_key_protect failed");