Bug 1518025 - Implemented handling of catchAll mail identities. r=mkmelin
This commit is contained in:
Родитель
6fb2796590
Коммит
9a2f04b0d6
|
@ -475,6 +475,7 @@ function openNewMessage() {
|
|||
Ci.nsIMsgCompType.New,
|
||||
Ci.nsIMsgCompFormat.Default,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
},
|
||||
|
|
|
@ -87,6 +87,7 @@ function writeNewMessageDock() {
|
|||
Ci.nsIMsgCompType.New,
|
||||
Ci.nsIMsgCompFormat.Default,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(", ");
|
||||
|
|
|
@ -83,6 +83,7 @@ async function openComposeWindow(relatedMessageId, type, details, extension) {
|
|||
type,
|
||||
0,
|
||||
hdrIdentity,
|
||||
null,
|
||||
null
|
||||
);
|
||||
return newWindowPromise;
|
||||
|
|
|
@ -195,6 +195,7 @@ var EmailAccountProvisioner = {
|
|||
Ci.nsIMsgCompType.New,
|
||||
Ci.nsIMsgCompFormat.Default,
|
||||
account.defaultIdentity,
|
||||
null,
|
||||
null
|
||||
);
|
||||
});
|
||||
|
|
|
@ -319,7 +319,7 @@ function msgHdrsArchive(msgHdrs) {
|
|||
msgHdrs.filter(
|
||||
x =>
|
||||
!msgHdrIsArchive(x) &&
|
||||
getMail3Pane().getIdentityForHeader(x).archiveEnabled
|
||||
getMail3Pane().getIdentityForHeader(x)[0].archiveEnabled
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
<!ENTITY name.accesskey "Y">
|
||||
<!ENTITY email.label "Email Address:">
|
||||
<!ENTITY email.accesskey "E">
|
||||
<!ENTITY catchAll.accesskey "D">
|
||||
<!ENTITY replyTo.label "Reply-to Address:">
|
||||
<!ENTITY replyTo.accesskey "s">
|
||||
<!ENTITY replyTo.placeholder "Recipients will reply to this other address">
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <test@example.com>",
|
||||
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;
|
||||
});
|
|
@ -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", [ "…"])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
<html:input id="identity.email"
|
||||
type="email"
|
||||
class="uri-element input-inline"
|
||||
oninput="updateCatchAllDomain();"
|
||||
aria-labelledby="identity.email.label"/>
|
||||
|
||||
</html:td>
|
||||
|
@ -168,6 +169,14 @@
|
|||
<html:fieldset>
|
||||
<html:legend>&privateData.label;</html:legend>
|
||||
|
||||
<hbox align="center" class="input-container">
|
||||
<checkbox id="identity.catchAll"
|
||||
accesskey="&catchAll.accesskey;"
|
||||
style="width:100%;"/>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<label value="&smtpName.label;"
|
||||
control="identity.smtpServerKey"
|
||||
accesskey="&smtpName.accesskey;"/>
|
||||
|
|
|
@ -23,6 +23,7 @@ function onInit(aPageId, aServerId) {
|
|||
document.title = titleValue;
|
||||
|
||||
setupSignatureItems();
|
||||
updateCatchAllDomain();
|
||||
}
|
||||
|
||||
function onPreInit(account, accountValues) {
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
wsm_persist="true"
|
||||
prefstring="mail.identity.%identitykey%.useremail"
|
||||
class="uri-element input-inline"
|
||||
oninput="updateCatchAllDomain();"
|
||||
aria-labelledby="identity.email.label"/>
|
||||
</html:td>
|
||||
</html:tr>
|
||||
|
@ -167,6 +168,17 @@
|
|||
|
||||
<separator class="thin"/>
|
||||
|
||||
<hbox align="center" class="input-container">
|
||||
<checkbox id="identity.catchAll"
|
||||
wsm_persist="true"
|
||||
prefattribute="value"
|
||||
accesskey="&catchAll.accesskey;"
|
||||
style="width:100%;"
|
||||
prefstring="mail.identity.%identitykey%.catchAll"/>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<hbox align="center">
|
||||
<label value="&smtpName.label;" control="identity.smtpServerKey"
|
||||
accesskey="&smtpName.accesskey;"/>
|
||||
|
|
|
@ -40,6 +40,11 @@ interface nsIMsgIdentity : nsISupports {
|
|||
*/
|
||||
attribute ACString email;
|
||||
|
||||
/**
|
||||
* Do we use multiple EMail addresses (like Catch-All) with this identity?
|
||||
*/
|
||||
attribute boolean catchAll;
|
||||
|
||||
/**
|
||||
* Formats fullName and email into the proper string to use as sender:
|
||||
* name <email>
|
||||
|
|
|
@ -139,6 +139,7 @@ NS_IMPL_IDPREF_STR(EscapedVCard, "escapedVCard")
|
|||
NS_IMPL_IDPREF_STR(SmtpServerKey, "smtpServer")
|
||||
NS_IMPL_IDPREF_WSTR(FullName, "fullName")
|
||||
NS_IMPL_IDPREF_STR(Email, "useremail")
|
||||
NS_IMPL_IDPREF_BOOL(CatchAll, "catchAll")
|
||||
NS_IMPL_IDPREF_WSTR(Label, "label")
|
||||
NS_IMPL_IDPREF_STR(ReplyTo, "reply_to")
|
||||
NS_IMPL_IDPREF_WSTR(Organization, "organization")
|
||||
|
@ -501,6 +502,7 @@ nsMsgIdentity::Copy(nsIMsgIdentity *identity) {
|
|||
|
||||
COPY_IDENTITY_BOOL_VALUE(identity, GetComposeHtml, SetComposeHtml)
|
||||
COPY_IDENTITY_STR_VALUE(identity, GetEmail, SetEmail)
|
||||
COPY_IDENTITY_BOOL_VALUE(identity, GetCatchAll, SetCatchAll)
|
||||
COPY_IDENTITY_WSTR_VALUE(identity, GetLabel, SetLabel)
|
||||
COPY_IDENTITY_STR_VALUE(identity, GetReplyTo, SetReplyTo)
|
||||
COPY_IDENTITY_WSTR_VALUE(identity, GetFullName, SetFullName)
|
||||
|
|
|
@ -26,6 +26,7 @@ interface nsIMsgComposeService : nsISupports {
|
|||
in MSG_ComposeType type,
|
||||
in MSG_ComposeFormat format,
|
||||
in nsIMsgIdentity identity,
|
||||
in AUTF8String from,
|
||||
in nsIMsgWindow aMsgWindow);
|
||||
|
||||
/**
|
||||
|
|
|
@ -350,7 +350,7 @@ MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION NS_IMETHODIMP
|
|||
nsMsgComposeService::OpenComposeWindow(
|
||||
const char *msgComposeWindowURL, nsIMsgDBHdr *origMsgHdr,
|
||||
const char *originalMsgURI, MSG_ComposeType type, MSG_ComposeFormat format,
|
||||
nsIMsgIdentity *aIdentity, nsIMsgWindow *aMsgWindow) {
|
||||
nsIMsgIdentity *aIdentity, const nsACString &from, nsIMsgWindow *aMsgWindow) {
|
||||
nsresult rv;
|
||||
|
||||
// Check for any reply type that wants to ignore the quote.
|
||||
|
@ -443,6 +443,7 @@ nsMsgComposeService::OpenComposeWindow(
|
|||
} else {
|
||||
pMsgComposeParams->SetOriginalMsgURI(originalMsgURI);
|
||||
pMsgComposeParams->SetOrigMsgHdr(origMsgHdr);
|
||||
pMsgCompFields->SetFrom(NS_ConvertUTF8toUTF16(from));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -344,6 +344,7 @@ function openComposeWindowForRSSArticle(
|
|||
aType,
|
||||
aFormat,
|
||||
aIdentity,
|
||||
null,
|
||||
aMsgWindow
|
||||
);
|
||||
} else {
|
||||
|
@ -411,6 +412,7 @@ function openComposeWindowForRSSArticle(
|
|||
aType,
|
||||
aFormat,
|
||||
aIdentity,
|
||||
null,
|
||||
aMsgWindow
|
||||
);
|
||||
}
|
||||
|
@ -427,6 +429,7 @@ function openComposeWindowForRSSArticle(
|
|||
aType,
|
||||
aFormat,
|
||||
aIdentity,
|
||||
null,
|
||||
aMsgWindow
|
||||
);
|
||||
}
|
||||
|
|
|
@ -876,6 +876,9 @@ pref("mail.compose.dontWarnMail2Newsgroup", false);
|
|||
// Attach http image resources to composed messages.
|
||||
pref("mail.compose.attach_http_images", false);
|
||||
|
||||
// Additional headers to check to find the right sender if catchAll is active.
|
||||
pref("mail.compose.catchAllHeaders", "envelope-to, x-original-to");
|
||||
|
||||
// these prefs (in minutes) are here to help QA test this feature
|
||||
// "mail.purge.min_delay", never purge a junk folder more than once every 480 minutes (60 mins/hour * 8 hours)
|
||||
// "mail.purge.timer_interval", fire the purge timer every 5 minutes, starting 5 minutes after we load accounts
|
||||
|
|
|
@ -90,7 +90,7 @@ function goOpenNewMessage()
|
|||
msgComposeService.OpenComposeWindow(null, null, null,
|
||||
Ci.nsIMsgCompType.New,
|
||||
Ci.nsIMsgCompFormat.Default,
|
||||
null, null);
|
||||
null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -193,12 +193,12 @@ function ComposeMessage(type, format, folder, messageArray)
|
|||
NewMessageToSelectedAddresses(type, format, identity);
|
||||
else
|
||||
msgComposeService.OpenComposeWindow(null, null, null, type,
|
||||
format, identity, msgWindow);
|
||||
format, identity, null, msgWindow);
|
||||
return;
|
||||
case msgComposeType.NewsPost:
|
||||
// dump("OpenComposeWindow with " + identity + " and " + newsgroup + "\n");
|
||||
msgComposeService.OpenComposeWindow(null, null, newsgroup, type,
|
||||
format, identity, msgWindow);
|
||||
format, identity, null, msgWindow);
|
||||
return;
|
||||
case msgComposeType.ForwardAsAttachment:
|
||||
if (messageArray && messageArray.length)
|
||||
|
@ -208,7 +208,7 @@ function ComposeMessage(type, format, folder, messageArray)
|
|||
// subjects from the URIs.
|
||||
hdr = messageArray.length > 1 ? null : messenger.msgHdrFromURI(messageArray[0]);
|
||||
msgComposeService.OpenComposeWindow(null, hdr, messageArray.join(','),
|
||||
type, format, identity, msgWindow);
|
||||
type, format, identity, null, msgWindow);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
|
@ -230,7 +230,7 @@ function ComposeMessage(type, format, folder, messageArray)
|
|||
format, identity, msgWindow);
|
||||
else
|
||||
msgComposeService.OpenComposeWindow(null, hdr, messageUri, type,
|
||||
format, identity, msgWindow);
|
||||
format, identity, null, msgWindow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,5 +25,5 @@ function goOpenNewMessage()
|
|||
.OpenComposeWindow(null, null, null,
|
||||
Ci.nsIMsgCompType.New,
|
||||
Ci.nsIMsgCompFormat.Default,
|
||||
null, null);
|
||||
null, null, null);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче