From 9a2f04b0d6fb28b5e92b9c7d2e03469a03f56c66 Mon Sep 17 00:00:00 2001 From: rene Date: Sun, 31 May 2020 13:53:23 +0300 Subject: [PATCH] Bug 1518025 - Implemented handling of catchAll mail identities. r=mkmelin --- .../lightning/content/lightning-item-panel.js | 1 + mail/base/content/folderDisplay.js | 2 +- mail/base/content/macMessengerMenu.js | 1 + mail/base/content/mail3PaneWindowCommands.js | 2 +- mail/base/content/mailCommands.js | 130 ++++++++-- mail/base/content/mailWindowOverlay.js | 2 +- mail/base/modules/MailUtils.jsm | 62 +++-- mail/base/modules/MessageArchiver.jsm | 2 +- .../compose/content/MsgComposeCommands.js | 14 +- .../extensions/parent/ext-compose.js | 1 + .../content/accountProvisioner.js | 1 + .../content/modules/stdlib/msgHdrUtils.jsm | 2 +- .../en-US/chrome/messenger/am-main.dtd | 1 + .../en-US/chrome/messenger/prefs.properties | 3 + mail/test/browser/composition/browser.ini | 1 + .../composition/browser_replyCatchAll.js | 227 ++++++++++++++++++ .../base/prefs/content/am-identity-edit.js | 31 +++ .../base/prefs/content/am-identity-edit.xhtml | 9 + mailnews/base/prefs/content/am-main.js | 1 + mailnews/base/prefs/content/am-main.xhtml | 12 + mailnews/base/public/nsIMsgIdentity.idl | 5 + mailnews/base/util/nsMsgIdentity.cpp | 2 + .../compose/public/nsIMsgComposeService.idl | 1 + mailnews/compose/src/nsMsgComposeService.cpp | 3 +- .../newsblog/content/newsblogOverlay.js | 3 + mailnews/mailnews.js | 3 + suite/browser/mailNavigatorOverlay.js | 2 +- suite/mailnews/content/mailCommands.js | 8 +- suite/mailnews/content/mailOverlay.js | 2 +- 29 files changed, 483 insertions(+), 51 deletions(-) create mode 100644 mail/test/browser/composition/browser_replyCatchAll.js diff --git a/calendar/lightning/content/lightning-item-panel.js b/calendar/lightning/content/lightning-item-panel.js index bfddf79974..0a7c1c9e8a 100644 --- a/calendar/lightning/content/lightning-item-panel.js +++ b/calendar/lightning/content/lightning-item-panel.js @@ -475,6 +475,7 @@ function openNewMessage() { Ci.nsIMsgCompType.New, Ci.nsIMsgCompFormat.Default, null, + null, null ); } diff --git a/mail/base/content/folderDisplay.js b/mail/base/content/folderDisplay.js index e2d2aa3b93..f0c919580f 100644 --- a/mail/base/content/folderDisplay.js +++ b/mail/base/content/folderDisplay.js @@ -2296,7 +2296,7 @@ FolderDisplayWidget.prototype = { // Either we've selected a small number of messages or we just can't // fast-path the result; examine all the messages. return this.selectedMessages.every(function(msg) { - let identity = MailUtils.getIdentityForHeader(msg); + let [identity] = MailUtils.getIdentityForHeader(msg); return Boolean(identity && identity.archiveEnabled); }); }, diff --git a/mail/base/content/macMessengerMenu.js b/mail/base/content/macMessengerMenu.js index abf43166d3..0267aaa8f4 100644 --- a/mail/base/content/macMessengerMenu.js +++ b/mail/base/content/macMessengerMenu.js @@ -87,6 +87,7 @@ function writeNewMessageDock() { Ci.nsIMsgCompType.New, Ci.nsIMsgCompFormat.Default, null, + null, null ); } diff --git a/mail/base/content/mail3PaneWindowCommands.js b/mail/base/content/mail3PaneWindowCommands.js index 220b989831..949b60d6b4 100644 --- a/mail/base/content/mail3PaneWindowCommands.js +++ b/mail/base/content/mail3PaneWindowCommands.js @@ -1328,7 +1328,7 @@ function IsSendUnsentMsgsEnabled(unsentMsgsFolder) { let identity; let folders = GetSelectedMsgFolders(); if (folders.length > 0) { - identity = MailUtils.getIdentityForServer(folders[0].server); + [identity] = MailUtils.getIdentityForServer(folders[0].server); } if (!identity) { diff --git a/mail/base/content/mailCommands.js b/mail/base/content/mailCommands.js index b58544d307..83c87e37bb 100644 --- a/mail/base/content/mailCommands.js +++ b/mail/base/content/mailCommands.js @@ -158,7 +158,7 @@ function ComposeMessage(type, format, folder, messageArray) { identity = folder.customIdentity; if (!identity) { - identity = MailUtils.getIdentityForServer(server); + [identity] = MailUtils.getIdentityForServer(server); } // dump("identity = " + identity + "\n"); } @@ -179,6 +179,7 @@ function ComposeMessage(type, format, folder, messageArray) { type, format, identity, + null, msgWindow ); return; @@ -191,6 +192,7 @@ function ComposeMessage(type, format, folder, messageArray) { type, format, identity, + null, msgWindow ); return; @@ -210,6 +212,7 @@ function ComposeMessage(type, format, folder, messageArray) { type, format, identity, + null, msgWindow ); } @@ -242,24 +245,115 @@ function ComposeMessage(type, format, folder, messageArray) { ); } else { // Replies come here. - let hdrIdentity = MailUtils.getIdentityForHeader( - hdr, - type, - findDeliveredToIdentityEmail(hdr) - ); - if (ignoreQuote) { - type += msgComposeType.ReplyIgnoreQuote; + let useCatchAll = false; + // Check if we are using catchAll on any identity. If current + // folder has some customIdentity set, ignore catchAll settings. + if (!(hdr.folder && hdr.folder.customIdentity)) { + useCatchAll = MailServices.accounts.allIdentities.some( + identity => identity.catchAll + ); } - MailServices.compose.OpenComposeWindow( - null, - hdr, - messageUri, - type, - format, - hdrIdentity, - msgWindow - ); + if (useCatchAll) { + // If we use catchAll, we need to get all headers + // MsgHdr retrieval is asynchronous, do everything in the callback. + MsgHdrToMimeMessage( + hdr, + null, + function(hdr, aMimeMsg) { + let catchAllHeaders = Services.prefs.getStringPref( + "mail.compose.catchAllHeaders" + ).split(",").map(header => header.toLowerCase().trim()); + // Collect probable senders addresses from given headers. + let collectedHeaderAddresses = ""; + for (let header of catchAllHeaders) { + if (aMimeMsg.has(header)) { + for (let mimeMsgHeader of aMimeMsg.headers[header]) { + collectedHeaderAddresses += + MailServices.headerParser + .parseEncodedHeaderW(mimeMsgHeader) + .toString() + ","; + } + } + } + + let [identity, matchingHint] = MailUtils.getIdentityForHeader( + hdr, + type, + collectedHeaderAddresses + ); + + // The found identity might have no catchAll enabled. + if ( + identity.catchAll && + matchingHint + ) { + // If name is not set in matchingHint, search trough other hints. + if ( + matchingHint.email && + !matchingHint.name + ) { + let hints = MailServices.headerParser.makeFromDisplayAddress( + hdr.recipients + + "," + + hdr.ccList + + "," + + collectedHeaderAddresses + ); + for (let hint of hints) { + if ( + hint.name && + hint.email.toLowerCase() == + matchingHint.email.toLowerCase() + ) { + matchingHint = MailServices.headerParser.makeMailboxObject( + hint.name, + matchingHint.email + ); + break; + } + } + } + } else { + matchingHint = MailServices.headerParser.makeMailboxObject( + "", + "" + ); + } + + // Now open compose window and use matching hint as reply sender. + MailServices.compose.OpenComposeWindow( + null, + hdr, + messageUri, + type, + format, + identity, + matchingHint.toString(), + msgWindow + ); + }, + true, + { saneBodySize: true, partsOnDemand: true } + ); + } else { + // Fall back to traditional behavior. + let [hdrIdentity] = MailUtils.getIdentityForHeader( + hdr, + type, + findDeliveredToIdentityEmail(hdr) + ); + MailServices.compose.OpenComposeWindow( + null, + hdr, + messageUri, + type, + format, + hdrIdentity, + null, + msgWindow + ); + } } } } @@ -391,7 +485,7 @@ saveAsUrlListener.prototype = { function SaveAsTemplate(uri) { if (uri) { let hdr = messenger.msgHdrFromURI(uri); - let identity = MailUtils.getIdentityForHeader( + let [identity] = MailUtils.getIdentityForHeader( hdr, Ci.nsIMsgCompType.Template ); diff --git a/mail/base/content/mailWindowOverlay.js b/mail/base/content/mailWindowOverlay.js index e6aea8af65..029b6d4f81 100644 --- a/mail/base/content/mailWindowOverlay.js +++ b/mail/base/content/mailWindowOverlay.js @@ -1658,7 +1658,7 @@ function IsReplyAllEnabled() { } // Check to see if my email address is in the list of addresses. - let myIdentity = MailUtils.getIdentityForHeader(msgHdr); + let [myIdentity] = MailUtils.getIdentityForHeader(msgHdr); let myEmail = myIdentity ? myIdentity.email : null; // We aren't guaranteed to have an email address, so guard against that. let imInAddresses = diff --git a/mail/base/modules/MailUtils.jsm b/mail/base/modules/MailUtils.jsm index fde62ee11f..8c2310c7db 100644 --- a/mail/base/modules/MailUtils.jsm +++ b/mail/base/modules/MailUtils.jsm @@ -420,30 +420,51 @@ var MailUtils = { * account as last choice. This is useful when all default account as last * choice. This is useful when all identities are passed in. Otherwise, use * the first entity in the list. + * @returns {Array} - An array of two elements, [identity, matchingHint]. + * identity is an nsIMsgIdentity and matchingHint is a string. */ getBestIdentity(identities, optionalHint, useDefault = false) { let identityCount = identities.length; if (identityCount < 1) { - return null; + return [ null, null ]; } - // If we have more than one identity and a hint to help us pick one. - if (identityCount > 1 && optionalHint) { - // Normalize case on the optional hint to improve our chances of - // finding a match. - optionalHint = optionalHint.toLowerCase(); - let hints = optionalHint.toLowerCase().split(","); + // If we have a hint to help us pick one identity, search for a match. + // Even if we only have one identity, check which hint might match. + if (optionalHint) { + let hints = MailServices.headerParser.makeFromDisplayAddress( + optionalHint + ); - for (let i = 0; i < hints.length; i++) { + for (let hint of hints) { for (let identity of identities) { if (!identity.email) { continue; } - if ( - hints[i].trim() == identity.email.toLowerCase() || - hints[i].includes("<" + identity.email.toLowerCase() + ">") - ) { - return identity; + if (hint.email.toLowerCase() == identity.email.toLowerCase()) { + return [ identity, hint ]; + } + } + } + + // Lets search again, this time for a matching domain if + // catchAll is enabled. + for (let hint of hints) { + let hintParts = hint.email.split("@"); + if (hintParts.length != 2) { + continue; + } + let hintDomain = hintParts[1].trim().toLowerCase(); + for (let identity of identities) { + if (!identity.email || !identity.catchAll) { + continue; + } + let emailParts = identity.email.split("@"); + if (emailParts.length != 2) { + continue; + } + if (hintDomain == emailParts[1].trim().toLowerCase()) { + return [ identity, hint ]; } } } @@ -453,11 +474,11 @@ var MailUtils = { if (useDefault) { let defaultAccount = MailServices.accounts.defaultAccount; if (defaultAccount && defaultAccount.defaultIdentity) { - return defaultAccount.defaultIdentity; + return [ defaultAccount.defaultIdentity, null ]; } } - return identities[0]; + return [ identities[0], null ]; }, getIdentityForServer(server, optionalHint) { @@ -469,16 +490,19 @@ var MailUtils = { * Get the identity for the given header. * @param hdr nsIMsgHdr message header * @param type nsIMsgCompType compose type the identity is used for. + * @returns {Array} - An array of two elements, [identity, matchingHint]. + * identity is an nsIMsgIdentity and matchingHint is a string. */ getIdentityForHeader(hdr, type, hint = "") { let server = null; let identity = null; + let matchingHint = null; let folder = hdr.folder; if (folder) { server = folder.server; identity = folder.customIdentity; if (identity) { - return identity; + return [identity, null]; } } @@ -506,17 +530,17 @@ var MailUtils = { } if (server) { - identity = this.getIdentityForServer(server, hintForIdentity); + [identity, matchingHint] = this.getIdentityForServer(server, hintForIdentity); } if (!identity) { - identity = this.getBestIdentity( + [identity, matchingHint] = this.getBestIdentity( MailServices.accounts.allIdentities, hintForIdentity, true ); } - return identity; + return [identity, matchingHint]; }, getInboxFolder(server) { diff --git a/mail/base/modules/MessageArchiver.jsm b/mail/base/modules/MessageArchiver.jsm index 2ec9dfe93e..7ceb297342 100644 --- a/mail/base/modules/MessageArchiver.jsm +++ b/mail/base/modules/MessageArchiver.jsm @@ -45,7 +45,7 @@ MessageArchiver.prototype = { let archiveGranularity; let archiveKeepFolderStructure; - let identity = MailUtils.getIdentityForHeader(msgHdr); + let [identity] = MailUtils.getIdentityForHeader(msgHdr); if (!identity || msgHdr.folder.server.type == "rss") { // If no identity, or a server (RSS) which doesn't have an identity // and doesn't want the default unrelated identity value, figure diff --git a/mail/components/compose/content/MsgComposeCommands.js b/mail/components/compose/content/MsgComposeCommands.js index 6ce3a956f8..32b567a9cf 100644 --- a/mail/components/compose/content/MsgComposeCommands.js +++ b/mail/components/compose/content/MsgComposeCommands.js @@ -1458,6 +1458,7 @@ function goOpenNewMessage(aEvent) { Ci.nsIMsgCompType.New, msgCompFormat, identity, + null, null ); } @@ -3492,8 +3493,17 @@ function ComposeStartup(aParams) { // Here we set the From from the original message, be it a draft or another // message, for example a template, we want to "edit as new". - // Only do this if the message is our own draft or template. - if (params.composeFields.creatorIdentityKey && params.composeFields.from) { + // Only do this if the message is our own draft or template or any type of reply. + if ( + params.composeFields.from && + (params.composeFields.creatorIdentityKey || + gComposeType == Ci.nsIMsgCompType.Reply || + gComposeType == Ci.nsIMsgCompType.ReplyAll || + gComposeType == Ci.nsIMsgCompType.ReplyToSender || + gComposeType == Ci.nsIMsgCompType.ReplyToGroup || + gComposeType == Ci.nsIMsgCompType.ReplyToSenderAndGroup || + gComposeType == Ci.nsIMsgCompType.ReplyToList) + ) { let from = MailServices.headerParser .parseEncodedHeader(params.composeFields.from, null) .join(", "); diff --git a/mail/components/extensions/parent/ext-compose.js b/mail/components/extensions/parent/ext-compose.js index 1c0f1ae6f5..739aecd092 100644 --- a/mail/components/extensions/parent/ext-compose.js +++ b/mail/components/extensions/parent/ext-compose.js @@ -83,6 +83,7 @@ async function openComposeWindow(relatedMessageId, type, details, extension) { type, 0, hdrIdentity, + null, null ); return newWindowPromise; diff --git a/mail/components/newmailaccount/content/accountProvisioner.js b/mail/components/newmailaccount/content/accountProvisioner.js index 8135b4c032..ce22129617 100644 --- a/mail/components/newmailaccount/content/accountProvisioner.js +++ b/mail/components/newmailaccount/content/accountProvisioner.js @@ -195,6 +195,7 @@ var EmailAccountProvisioner = { Ci.nsIMsgCompType.New, Ci.nsIMsgCompFormat.Default, account.defaultIdentity, + null, null ); }); diff --git a/mail/extensions/openpgp/content/modules/stdlib/msgHdrUtils.jsm b/mail/extensions/openpgp/content/modules/stdlib/msgHdrUtils.jsm index 4abee63b75..b5f3a727eb 100644 --- a/mail/extensions/openpgp/content/modules/stdlib/msgHdrUtils.jsm +++ b/mail/extensions/openpgp/content/modules/stdlib/msgHdrUtils.jsm @@ -319,7 +319,7 @@ function msgHdrsArchive(msgHdrs) { msgHdrs.filter( x => !msgHdrIsArchive(x) && - getMail3Pane().getIdentityForHeader(x).archiveEnabled + getMail3Pane().getIdentityForHeader(x)[0].archiveEnabled ) ); } diff --git a/mail/locales/en-US/chrome/messenger/am-main.dtd b/mail/locales/en-US/chrome/messenger/am-main.dtd index a2e3af87ed..998333e340 100644 --- a/mail/locales/en-US/chrome/messenger/am-main.dtd +++ b/mail/locales/en-US/chrome/messenger/am-main.dtd @@ -13,6 +13,7 @@ + diff --git a/mail/locales/en-US/chrome/messenger/prefs.properties b/mail/locales/en-US/chrome/messenger/prefs.properties index 6b0f15d17e..90c312b9a9 100644 --- a/mail/locales/en-US/chrome/messenger/prefs.properties +++ b/mail/locales/en-US/chrome/messenger/prefs.properties @@ -70,6 +70,9 @@ identityDialogTitleEdit=Edit %S identity-edit-req=You must specify a valid email address for this identity. identity-edit-req-title=Error Creating Identity +## LOCALIZATION NOTE (identityCatchAll): %S is the domain part of the email address +identityCatchAll=Reply from this identity when a message does not match any other identity and the recipient matches %S + ## LOCALIZATION NOTE (identity-delete-confirm): %S is the identity name # and should be put on a new line. The new line is produced with the "\n" string. identity-delete-confirm=Are you sure you want to delete the identity\n%S? diff --git a/mail/test/browser/composition/browser.ini b/mail/test/browser/composition/browser.ini index 1e864ec031..1364382c33 100644 --- a/mail/test/browser/composition/browser.ini +++ b/mail/test/browser/composition/browser.ini @@ -71,6 +71,7 @@ reason = See bug 1413851. [browser_newmsgComposeIdentity.js] [browser_replyAddresses.js] skip-if = debug # Bug 1601591 +[browser_replyCatchAll.js] [browser_replyFormatFlowed.js] [browser_replyMultipartCharset.js] skip-if = debug # Bug 1606542 diff --git a/mail/test/browser/composition/browser_replyCatchAll.js b/mail/test/browser/composition/browser_replyCatchAll.js new file mode 100644 index 0000000000..ae9c546744 --- /dev/null +++ b/mail/test/browser/composition/browser_replyCatchAll.js @@ -0,0 +1,227 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Tests that reply messages use the correct identity and sender dependent + * on the catchAll setting. + */ + +"use strict"; + +var { + close_compose_window, + open_compose_with_reply, +} = ChromeUtils.import("resource://testing-common/mozmill/ComposeHelpers.jsm"); +var { + add_message_to_folder, + assert_selected_and_displayed, + be_in_folder, + create_message, + mc, + press_delete, + select_click_row, +} = ChromeUtils.import( + "resource://testing-common/mozmill/FolderDisplayHelpers.jsm" +); +var { + assert_notification_displayed, + wait_for_notification_to_show, +} = ChromeUtils.import( + "resource://testing-common/mozmill/NotificationBoxHelpers.jsm" +); + +var { Assert } = ChromeUtils.import("resource://testing-common/Assert.jsm"); + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +var i = 0; + +var myIdentityEmail1 = "me@example.com"; +var myIdentityEmail2 = "otherme@example.net"; +var myAdditionalEmail3 = "alsome@example.net"; +var notMyEmail = "otherme@example.org"; + +var identity1; +var identity2; + +var gAccount; +var gFolder; + +add_task(function setupModule(module) { + requestLongerTimeout(4); + + // Now set up an account with some identities. + let acctMgr = MailServices.accounts; + gAccount = acctMgr.createAccount(); + gAccount.incomingServer = acctMgr.createIncomingServer( + "nobody", + "Reply Identity Testing", + "pop3" + ); + + gFolder = gAccount.incomingServer.rootFolder + .QueryInterface(Ci.nsIMsgLocalMailFolder) + .createLocalSubfolder("Msgs4Reply"); + + identity1 = acctMgr.createIdentity(); + identity1.email = myIdentityEmail1; + gAccount.addIdentity(identity1); + + identity2 = acctMgr.createIdentity(); + identity2.email = myIdentityEmail2; + gAccount.addIdentity(identity2); +}); + +/** + * Create and select a new message to do a reply with. + */ +function create_replyMsg(aTo, aEnvelopeTo) { + let msg0 = create_message({ + from: "Tester ", + to: aTo, + subject: "test", + clobberHeaders: { + "envelope-to": aEnvelopeTo + }, + }); + add_message_to_folder(gFolder, msg0); + + be_in_folder(gFolder); + let msg = select_click_row(i++); + assert_selected_and_displayed(mc, msg); +} + +/** + * all the tests + */ +add_task(function test_reply_identity_selection() { + + let tests = [ + // No catchAll, 'From' will be set to recipient. + { + to: myIdentityEmail2, envelopeTo: myIdentityEmail2, + catchAllId1: false, catchAllId2: false, + replyIdKey: identity2.key, replyIdFrom: myIdentityEmail2, warning: false + }, + // No catchAll, 'From' will be set to second id's email (without name). + { + to: "Mr.X <" + myIdentityEmail2 + ">", envelopeTo: "", + catchAllId1: false, catchAllId2: false, + replyIdKey: identity2.key, replyIdFrom: myIdentityEmail2, warning: false + }, + // With catchAll, 'From' will be set to senders address (with name). + { + to: "Mr.X <" + myIdentityEmail2 + ">", envelopeTo: "", + catchAllId1: false, catchAllId2: true, + replyIdKey: identity2.key, replyIdFrom: "Mr.X <" + myIdentityEmail2 + ">", + warning: false + }, + // With catchAll, 'From' will be set to senders address (with name). + { + to: myIdentityEmail2, envelopeTo: "Mr.X <" + myIdentityEmail2 + ">", + catchAllId1: false, catchAllId2: true, + replyIdKey: identity2.key, replyIdFrom: "Mr.X <" + myIdentityEmail2 + ">", + warning: false + }, + // With catchAll, 'From' will be set to second id's email. + { + to: myIdentityEmail2, envelopeTo: myAdditionalEmail3, + catchAllId1: false, catchAllId2: true, + replyIdKey: identity2.key, replyIdFrom: myIdentityEmail2, warning: false + }, + // With catchAll, 'From' will be set to myAdditionalEmail3. + { + to: notMyEmail, envelopeTo: myAdditionalEmail3, + catchAllId1: false, catchAllId2: true, + replyIdKey: identity2.key, replyIdFrom: myAdditionalEmail3, + warning: true + }, + // Without catchAll, mail to another recipient. + { + to: notMyEmail, envelopeTo: "", + catchAllId1: false, catchAllId2: false, + replyIdKey: identity1.key, replyIdFrom: myIdentityEmail1, + warning: false + }, + // With catchAll, mail to another recipient (domain not matching). + { + to: notMyEmail, envelopeTo: "", + catchAllId1: true, catchAllId2: true, + replyIdKey: identity1.key, replyIdFrom: myIdentityEmail1, + warning: false + }, + ]; + + for (let test of tests) { + test.replyIndex = create_replyMsg(test.to, test.envelopeTo); + + identity1.catchAll = test.catchAllId1; + identity2.catchAll = test.catchAllId2; + + let cwc = open_compose_with_reply(); + + checkCompIdentity( + cwc, + test.replyIdKey, + test.replyIdFrom + ); + + if (test.warning) { + wait_for_notification_to_show( + cwc, + "compose-notification-bottom", + "identityWarning" + ); + } else { + assert_notification_displayed( + cwc, + "compose-notification-bottom", + "identityWarning", + false + ); + } + + close_compose_window(cwc, false); + } +}); + +/** + * Helper to check that a suitable From identity was set up in the given + * composer window. + * + * @param cwc Compose window controller. + * @param aIdentityKey The key of the expected identity. + * @param aFrom The expected displayed From address. + */ +function checkCompIdentity(cwc, aIdentityKey, aFrom) { + Assert.equal( + cwc.window.getCurrentIdentityKey(), + aIdentityKey, + "The From identity is not correctly selected" + ); + Assert.equal( + cwc.window.document.getElementById("msgIdentity").value, + aFrom, + "The From value was initialized to an unexpected value" + ); +} + +registerCleanupFunction(function teardownModule(module) { + be_in_folder(gFolder); + let count; + while ((count = gFolder.getTotalMessages(false)) > 0) { + press_delete(); + mc.waitFor(() => gFolder.getTotalMessages(false) < count); + } + + gAccount.removeIdentity(identity2); + + // The last identity of an account can't be removed so clear all its prefs + // which effectively destroys it. + identity1.clearAllValues(); + MailServices.accounts.removeAccount(gAccount); + gAccount = null; +}); diff --git a/mailnews/base/prefs/content/am-identity-edit.js b/mailnews/base/prefs/content/am-identity-edit.js index 52d844db18..62662972cf 100644 --- a/mailnews/base/prefs/content/am-identity-edit.js +++ b/mailnews/base/prefs/content/am-identity-edit.js @@ -51,6 +51,8 @@ function initIdentityValues(identity) { if (identity) { document.getElementById("identity.fullName").value = identity.fullName; document.getElementById("identity.email").value = identity.email; + document.getElementById("identity.catchAll").checked = + identity.catchAll; document.getElementById("identity.replyTo").value = identity.replyTo; document.getElementById("identity.organization").value = identity.organization; @@ -83,6 +85,7 @@ function initIdentityValues(identity) { } setupSignatureItems(); + updateCatchAllDomain(); } function initCopiesAndFolder(identity) { @@ -235,6 +238,9 @@ function saveIdentitySettings(identity) { } identity.fullName = document.getElementById("identity.fullName").value; identity.email = document.getElementById("identity.email").value; + identity.catchAll = document.getElementById( + "identity.catchAll" + ).checked; identity.replyTo = document.getElementById("identity.replyTo").value; identity.organization = document.getElementById( "identity.organization" @@ -505,3 +511,28 @@ function editCurrentSMTP() { loadSMTPServerList ); } + +function updateCatchAllDomain() { + let emailAddress = document.getElementById("identity.email").value; + let atPos = emailAddress.lastIndexOf("@"); + let catchAllElem = document.getElementById("identity.catchAll"); + let prefBundle = document.getElementById("bundle_prefs"); + // If email address contains some domain part, use this in the checkbox + // description. Else disable the whole field and reset catchAll option. + if (atPos > 0 && atPos + 1 < emailAddress.length) { + catchAllElem.setAttribute("disabled", "false"); + catchAllElem.setAttribute( + "label", + prefBundle.getFormattedString("identityCatchAll", [ + emailAddress.substr(atPos + 1), + ]) + ); + } else { + catchAllElem.setAttribute("disabled", "true"); + catchAllElem.checked = false; + catchAllElem.setAttribute( + "label", + prefBundle.getFormattedString("identityCatchAll", [ "…"]) + ); + } +} diff --git a/mailnews/base/prefs/content/am-identity-edit.xhtml b/mailnews/base/prefs/content/am-identity-edit.xhtml index 5151df0755..3331398b0c 100644 --- a/mailnews/base/prefs/content/am-identity-edit.xhtml +++ b/mailnews/base/prefs/content/am-identity-edit.xhtml @@ -87,6 +87,7 @@ @@ -168,6 +169,14 @@ &privateData.label; + + + + + +