Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1

This commit is contained in:
Matt A. Tobin 2019-11-03 00:17:46 -04:00 • committed by Roy Tam
commit e400f4130a
1564 changed files with 510348 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,92 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/folderPane.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/AccountManager.dtd">
<dialog id="accountManager"
windowtype="mailnews:accountmanager"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&accountManagerTitle.label;"
style="&accountManager.size;"
persist="width height screenX screenY"
buttons="accept,cancel"
onload="onLoad(event);"
onunload="onUnload();"
ondialogaccept="return onAccept(true);">
<stringbundle id="bundle_brand" src="chrome://branding/locale/brand.properties"/>
<stringbundle id="bundle_prefs" src="chrome://messenger/locale/prefs.properties"/>
<script type="application/javascript" src="chrome://messenger/content/accountUtils.js"/>
<script type="application/javascript" src="chrome://messenger/content/am-prefs.js"/>
<script type="application/javascript" src="chrome://messenger/content/AccountManager.js"/>
<script type="application/javascript" src="chrome://messenger/content/am-help.js"/>
<script type="application/javascript" src="chrome://messenger/content/amUtils.js"/>
<hbox flex="1">
<vbox style="&accountTree.width;">
<tree flex="1" onselect="onAccountTreeSelect(null, null);" id="accounttree"
seltype="single" hidecolumnpicker="true">
<treecols>
<treecol id="AccountCol" flex="1" primary="true" hideheader="true"/>
</treecols>
<treechildren id="account-tree-children"/>
</tree>
#ifdef MOZ_THUNDERBIRD
<button id="accountActionsButton" type="menu"
label="&accountActionsButton.label;"
accesskey="&accountActionsButton.accesskey;">
<menupopup id="accountActionsDropdown"
onpopupshowing="initAccountActionsButtons(this);">
<menuitem id="accountActionsAddMailAccount"
label="&addMailAccountButton.label;"
accesskey="&addMailAccountButton.accesskey;"
prefstring="mail.disable_new_account_addition"
oncommand="AddMailAccount(event); event.stopPropagation();"/>
<menuitem id="accountActionsAddIMAccount"
label="&addIMAccountButton.label;"
accesskey="&addIMAccountButton.accesskey;"
prefstring="mail.disable_new_account_addition"
oncommand="AddIMAccount(event); event.stopPropagation();"/>
<menuitem id="accountActionsAddFeedAccount"
label="&addFeedAccountButton.label;"
accesskey="&addFeedAccountButton.accesskey;"
prefstring="mail.disable_new_account_addition"
oncommand="AddFeedAccount(event); event.stopPropagation();"/>
<menuitem id="accountActionsAddOtherAccount"
label="&addOtherAccountButton.label;"
accesskey="&addOtherAccountButton.accesskey;"
prefstring="mail.disable_new_account_addition"
oncommand="onAddAccount(event); event.stopPropagation();"/>
<menuseparator id="accountActionsDropdownSep1"/>
<menuitem id="accountActionsDropdownSetDefault"
label="&setDefaultButton.label;"
accesskey="&setDefaultButton.accesskey;"
prefstring="mail.disable_button.set_default_account"
oncommand="onSetDefault(event); event.stopPropagation();"/>
<menuitem id="accountActionsDropdownRemove"
label="&removeButton.label;"
accesskey="&removeButton.accesskey;"
prefstring="mail.disable_button.delete_account"
oncommand="onRemoveAccount(event); event.stopPropagation();"/>
</menupopup>
</button>
#else
<button label="&addAccountButton.label;" oncommand="onAddAccount(event);" id="addAccountButton"
prefstring="mail.disable_new_account_addition"
accesskey="&addAccountButton.accesskey;"/>
<button label="&setDefaultButton.label;" oncommand="onSetDefault(event);" disabled="true" id="setDefaultButton"
prefstring="mail.disable_button.set_default_account"
accesskey="&setDefaultButton.accesskey;"/>
<button disabled="true" label="&removeButton.label;" oncommand="onRemoveAccount(event);" id="removeButton"
prefstring="mail.disable_button.delete_account"
accesskey="&removeButton.accesskey;"/>
#endif
</vbox>
<iframe id="contentFrame" name="contentFrame" flex="1"/>
</hbox>
</dialog>

View file

@ -0,0 +1,992 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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/. */
/* the okCallback is used for sending a callback for the parent window */
var okCallback = null;
/* The account wizard creates new accounts */
/*
data flow into the account wizard like this:
For new accounts:
* pageData -> Array -> createAccount -> finishAccount
For accounts coming from the ISP setup:
* RDF -> Array -> pageData -> Array -> createAccount -> finishAccount
for "unfinished accounts"
* account -> Array -> pageData -> Array -> finishAccount
Where:
pageData - the actual pages coming out of the Widget State Manager
RDF - the ISP datasource
Array - associative array of attributes, that very closely
resembles the nsIMsgAccount/nsIMsgIncomingServer/nsIMsgIdentity
structure
createAccount() - creates an account from the above Array
finishAccount() - fills an existing account with data from the above Array
*/
/*
the account wizard path is something like:
accounttype -> identity -> server -> login -> accname -> done
\-> newsserver ----/
where the accounttype determines which path to take
(server vs. newsserver)
*/
Components.utils.import("resource:///modules/mailServices.js");
var contentWindow;
var gPageData;
var nsIMsgIdentity = Components.interfaces.nsIMsgIdentity;
var nsIMsgIncomingServer = Components.interfaces.nsIMsgIncomingServer;
var gPrefsBundle, gMessengerBundle;
// the current nsIMsgAccount
var gCurrentAccount;
// default account
var gDefaultAccount;
// the current associative array that
// will eventually be dumped into the account
var gCurrentAccountData;
// default picker mode for copies and folders
var gDefaultSpecialFolderPickerMode = "0";
// event handlers
function onAccountWizardLoad() {
gPrefsBundle = document.getElementById("bundle_prefs");
gMessengerBundle = document.getElementById("bundle_messenger");
if ("testingIspServices" in this) {
if ("SetCustomizedWizardDimensions" in this && testingIspServices()) {
SetCustomizedWizardDimensions();
}
}
/* We are checking here for the callback argument */
if (window.arguments && window.arguments[0]) {
if(window.arguments[0].okCallback )
{
//dump("There is okCallback");
top.okCallback = window.arguments[0].okCallback;
}
}
checkForInvalidAccounts();
try {
gDefaultAccount = MailServices.accounts.defaultAccount;
}
catch (ex) {
// no default account, this is expected the first time you launch mail
// on a new profile
gDefaultAccount = null;
}
// Set default value for global inbox checkbox
var checkGlobalInbox = document.getElementById("deferStorage");
try {
checkGlobalInbox.checked = Services.prefs.getBoolPref("mail.accountwizard.deferstorage");
} catch(e) {}
}
function onCancel()
{
if ("ActivationOnCancel" in this && ActivationOnCancel())
return false;
var firstInvalidAccount = getFirstInvalidAccount();
var closeWizard = true;
// if the user cancels the the wizard when it pops up because of
// an invalid account (example, a webmail account that activation started)
// we just force create it by setting some values and calling the FinishAccount()
// see bug #47521 for the full discussion
if (firstInvalidAccount) {
var pageData = GetPageData();
// set the fullName if it doesn't exist
if (!pageData.identity.fullName || !pageData.identity.fullName.value) {
setPageData(pageData, "identity", "fullName", "");
}
// set the email if it doesn't exist
if (!pageData.identity.email || !pageData.identity.email.value) {
setPageData(pageData, "identity", "email", "user@domain.invalid");
}
// call FinishAccount() and not onFinish(), since the "finish"
// button may be disabled
FinishAccount();
}
else {
// since this is not an invalid account
// really cancel if the user hits the "cancel" button
// if the length of the account list is less than 1, there are no accounts
if (MailServices.accounts.accounts.length < 1) {
let confirmMsg = gPrefsBundle.getString("cancelWizard");
let confirmTitle = gPrefsBundle.getString("accountWizard");
let result = Services.prompt.confirmEx(window, confirmTitle, confirmMsg,
(Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0) +
(Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_1),
gPrefsBundle.getString('WizardExit'),
gPrefsBundle.getString('WizardContinue'),
null, null, {value:0});
if (result == 1)
closeWizard = false;
}
if(top.okCallback && closeWizard) {
var state = false;
top.okCallback(state);
}
}
return closeWizard;
}
function FinishAccount()
{
try {
var pageData = GetPageData();
var accountData= gCurrentAccountData;
if (!accountData)
{
accountData = new Object;
// Time to set the smtpRequiresUsername attribute
if (!serverIsNntp(pageData))
accountData.smtpRequiresUsername = true;
}
// we may need local folders before account is "Finished"
// if it's a pop3 account which defers to Local Folders.
verifyLocalFoldersAccount();
PageDataToAccountData(pageData, accountData);
FixupAccountDataForIsp(accountData);
// we might be simply finishing another account
if (!gCurrentAccount)
gCurrentAccount = createAccount(accountData);
// transfer all attributes from the accountdata
finishAccount(gCurrentAccount, accountData);
setupCopiesAndFoldersServer(gCurrentAccount, getCurrentServerIsDeferred(pageData), accountData);
if (gCurrentAccount.incomingServer.canBeDefaultServer)
EnableCheckMailAtStartUpIfNeeded(gCurrentAccount);
if (!document.getElementById("downloadMsgs").hidden) {
// skip the default biff, we will load messages manually if needed
window.opener.gLoadStartFolder = false;
if (document.getElementById("downloadMsgs").checked) {
window.opener.gNewAccountToLoad = gCurrentAccount; // load messages for new POP account
}
}
// in case we crash, force us a save of the prefs file NOW
try {
MailServices.accounts.saveAccountInfo();
}
catch (ex) {
dump("Error saving account info: " + ex + "\n");
}
window.close();
if(top.okCallback)
{
var state = true;
//dump("finish callback");
top.okCallback(state);
}
}
catch(ex) {
dump("FinishAccount failed, " + ex +"\n");
}
}
// prepopulate pageData with stuff from accountData
// use: to prepopulate the wizard with account information
function AccountDataToPageData(accountData, pageData)
{
if (!accountData) {
dump("null account data! clearing..\n");
// handle null accountData as if it were an empty object
// so that we clear-out any old pagedata from a
// previous accountdata. The trick is that
// with an empty object, accountData.identity.slot is undefined,
// so this will clear out the prefill data in setPageData
accountData = new Object;
accountData.incomingServer = new Object;
accountData.identity = new Object;
accountData.smtp = new Object;
}
var server = accountData.incomingServer;
if (server.type == undefined) {
// clear out the old server data
//setPageData(pageData, "accounttype", "mailaccount", undefined);
// setPageData(pageData, "accounttype", "newsaccount", undefined);
setPageData(pageData, "server", "servertype", undefined);
setPageData(pageData, "server", "hostname", undefined);
}
else {
if (server.type == "nntp") {
setPageData(pageData, "accounttype", "newsaccount", true);
setPageData(pageData, "accounttype", "mailaccount", false);
setPageData(pageData, "newsserver", "hostname", server.hostName);
}
else {
setPageData(pageData, "accounttype", "mailaccount", true);
setPageData(pageData, "accounttype", "newsaccount", false);
setPageData(pageData, "server", "servertype", server.type);
setPageData(pageData, "server", "hostname", server.hostName);
}
setPageData(pageData, "accounttype", "otheraccount", false);
}
setPageData(pageData, "login", "username", server.username || "");
setPageData(pageData, "login", "password", server.password || "");
setPageData(pageData, "accname", "prettyName", server.prettyName || "");
setPageData(pageData, "accname", "userset", false);
setPageData(pageData, "ispdata", "supplied", false);
var identity;
if (accountData.identity) {
dump("This is an accountdata\n");
identity = accountData.identity;
}
else if (accountData.identities) {
identity = accountData.identities.queryElementAt(0, Components.interfaces.nsIMsgIdentity);
dump("this is an account, id= " + identity + "\n");
}
setPageData(pageData, "identity", "email", identity.email || "");
setPageData(pageData, "identity", "fullName", identity.fullName || "");
var smtp;
if (accountData.smtp) {
smtp = accountData.smtp;
setPageData(pageData, "server", "smtphostname", smtp.hostname);
setPageData(pageData, "login", "smtpusername", smtp.username);
}
}
// take data from each page of pageData and dump it into accountData
// use: to put results of wizard into a account-oriented object
function PageDataToAccountData(pageData, accountData)
{
if (!accountData.identity)
accountData.identity = new Object;
if (!accountData.incomingServer)
accountData.incomingServer = new Object;
if (!accountData.smtp)
accountData.smtp = new Object;
if (!accountData.pop3)
accountData.pop3 = new Object;
if (!accountData.imap)
accountData.imap = new Object;
var identity = accountData.identity;
var server = accountData.incomingServer;
var smtp = accountData.smtp;
var pop3 = accountData.pop3;
var imap = accountData.imap;
if (pageData.identity.email)
identity.email = pageData.identity.email.value;
if (pageData.identity.fullName)
identity.fullName = pageData.identity.fullName.value;
server.type = getCurrentServerType(pageData);
server.hostName = getCurrentHostname(pageData);
if (getCurrentServerIsDeferred(pageData))
{
try
{
let localFoldersServer = MailServices.accounts.localFoldersServer;
let localFoldersAccount = MailServices.accounts.FindAccountForServer(localFoldersServer);
pop3.deferredToAccount = localFoldersAccount.key;
pop3.deferGetNewMail = true;
server["ServerType-pop3"] = pop3;
}
catch (ex) {dump ("exception setting up deferred account" + ex);}
}
if (serverIsNntp(pageData)) {
// this stuff probably not relevant
dump("not setting username/password/etc\n");
}
else {
if (pageData.login) {
if (pageData.login.username)
server.username = pageData.login.username.value;
if (pageData.login.password)
server.password = pageData.login.password.value;
if (pageData.login.smtpusername)
smtp.username = pageData.login.smtpusername.value;
}
dump("pageData.server = " + pageData.server + "\n");
if (pageData.server) {
dump("pageData.server.smtphostname.value = " + pageData.server.smtphostname + "\n");
if (pageData.server.smtphostname &&
pageData.server.smtphostname.value)
smtp.hostname = pageData.server.smtphostname.value;
}
if (pageData.identity && pageData.identity.smtpServerKey)
identity.smtpServerKey = pageData.identity.smtpServerKey.value;
if (pageData.server.port &&
pageData.server.port.value)
{
if (server.type == 'imap')
{
imap.port = pageData.server.port.value;
server["ServerType-imap"] = imap;
}
else if (server.type == 'pop3')
{
pop3.port = pageData.server.port.value;
server["ServerType-pop3"] = pop3;
}
}
if (pageData.server.leaveMessagesOnServer &&
pageData.server.leaveMessagesOnServer.value)
{
pop3.leaveMessagesOnServer = pageData.server.leaveMessagesOnServer.value;
server["ServerType-pop3"] = pop3;
}
}
if (pageData.accname) {
if (pageData.accname.prettyName)
server.prettyName = pageData.accname.prettyName.value;
}
}
// given an accountData structure, create an account
// (but don't fill in any fields, that's for finishAccount()
function createAccount(accountData)
{
// Retrieve the server (data) from the account data.
var server = accountData.incomingServer;
// for news, username is always null
var username = (server.type == "nntp") ? null : server.username;
dump("MailServices.accounts.createIncomingServer(" +
username + ", " + server.hostName + ", " + server.type + ")\n");
// Create a (actual) server.
server = MailServices.accounts.createIncomingServer(username, server.hostName, server.type);
dump("MailServices.accounts.createAccount()\n");
// Create an account.
let account = MailServices.accounts.createAccount();
// only create an identity for this account if we really have one
// (use the email address as a check)
if (accountData.identity && accountData.identity.email)
{
dump("MailServices.accounts.createIdentity()\n");
// Create an identity.
let identity = MailServices.accounts.createIdentity();
// New nntp identities should use plain text by default;
// we want that GNKSA (The Good Net-Keeping Seal of Approval).
if (server.type == "nntp")
identity.composeHtml = false;
account.addIdentity(identity);
}
// we mark the server as invalid so that the account manager won't
// tell RDF about the new server - it's not quite finished getting
// set up yet, in particular, the deferred storage pref hasn't been set.
server.valid = false;
// Set the new account to use the new server.
account.incomingServer = server;
server.valid = true;
return account;
}
// given an accountData structure, copy the data into the
// given account, incoming server, and so forth
function finishAccount(account, accountData)
{
if (accountData.incomingServer) {
var destServer = account.incomingServer;
var srcServer = accountData.incomingServer;
copyObjectToInterface(destServer, srcServer, true);
// see if there are any protocol-specific attributes
// if so, we use the type to get the IID, QueryInterface
// as appropriate, then copy the data over
dump("srcServer.ServerType-" + srcServer.type + " = " +
srcServer["ServerType-" + srcServer.type] + "\n");
if (srcServer["ServerType-" + srcServer.type]) {
// handle server-specific stuff
var IID;
try {
IID = destServer.protocolInfo.serverIID;
} catch (ex) {
Components.utils.reportError("Could not get IID for " + srcServer.type + ": " + ex);
}
if (IID) {
destProtocolServer = destServer.QueryInterface(IID);
srcProtocolServer = srcServer["ServerType-" + srcServer.type];
dump("Copying over " + srcServer.type + "-specific data\n");
copyObjectToInterface(destProtocolServer, srcProtocolServer, false);
}
}
account.incomingServer.valid=true;
// hack to cause an account loaded notification now the server is valid
account.incomingServer = account.incomingServer;
}
// copy identity info
var destIdentity = account.identities.length ?
account.identities.queryElementAt(0, nsIMsgIdentity) :
null;
if (destIdentity) // does this account have an identity?
{
if (accountData.identity && accountData.identity.email) {
// fixup the email address if we have a default domain
var emailArray = accountData.identity.email.split('@');
if (emailArray.length < 2 && accountData.domain) {
accountData.identity.email += '@' + accountData.domain;
}
copyObjectToInterface(destIdentity, accountData.identity, true);
destIdentity.valid=true;
}
/**
* If signature file need to be set, get the path to the signature file.
* Signature files, if exist, are placed under default location. Get
* default files location for messenger using directory service. Signature
* file name should be extracted from the account data to build the complete
* path for signature file. Once the path is built, set the identity's signature pref.
*/
if (destIdentity.attachSignature)
{
var sigFileName = accountData.signatureFileName;
let sigFile = MailServices.mailSession.getDataFilesDir("messenger");
sigFile.append(sigFileName);
destIdentity.signature = sigFile;
}
if (accountData.smtp.hostname && !destIdentity.smtpServerKey)
{
// hostname + no key => create a new SMTP server.
let smtpServer = MailServices.smtp.createServer();
var isDefaultSmtpServer;
if (!MailServices.smtp.defaultServer.hostname) {
MailServices.smtp.defaultServer = smtpServer;
isDefaultSmtpServer = true;
}
copyObjectToInterface(smtpServer, accountData.smtp, false);
// If it's the default server we created, make the identity use
// "Use Default" by default.
destIdentity.smtpServerKey =
(isDefaultSmtpServer) ? "" : smtpServer.key;
}
} // if the account has an identity...
if (this.FinishAccountHook != undefined) {
FinishAccountHook(accountData.domain);
}
}
// Helper method used by copyObjectToInterface which attempts to set dest[attribute] as a generic
// attribute on the xpconnect object, src.
// This routine skips any attribute that begins with ServerType-
function setGenericAttribute(dest, src, attribute)
{
if (!(attribute.toLowerCase().startsWith("servertype-")) && src[attribute])
{
switch (typeof src[attribute])
{
case "string":
dest.setUnicharAttribute(attribute, src[attribute]);
break;
case "boolean":
dest.setBoolAttribute(attribute, src[attribute]);
break;
case "number":
dest.setIntAttribute(attribute, src[attribute]);
break;
default:
dump("Error: No Generic attribute " + attribute + " found for: " + dest + "\n");
break;
}
}
}
// copy over all attributes from dest into src that already exist in src
// the assumption is that src is an XPConnect interface full of attributes
// @param useGenericFallback if we can't set an attribute directly on src, then fall back
// and try setting it generically. This assumes that src supports setIntAttribute, setUnicharAttribute
// and setBoolAttribute.
function copyObjectToInterface(dest, src, useGenericFallback)
{
if (!dest) return;
if (!src) return;
var attribute;
for (attribute in src)
{
if (dest.__lookupSetter__(attribute))
{
if (dest[attribute] != src[attribute])
dest[attribute] = src[attribute];
}
else if (useGenericFallback) // fall back to setting the attribute generically
setGenericAttribute(dest, src, attribute);
} // for each attribute in src we want to copy
}
// check if there already is a "Local Folders"
// if not, create it.
function verifyLocalFoldersAccount()
{
var localMailServer = null;
try {
localMailServer = MailServices.accounts.localFoldersServer;
}
catch (ex) {
// dump("exception in findserver: " + ex + "\n");
localMailServer = null;
}
try {
if (!localMailServer)
{
// dump("Creating local mail account\n");
// creates a copy of the identity you pass in
MailServices.accounts.createLocalMailAccount();
try {
localMailServer = MailServices.accounts.localFoldersServer;
}
catch (ex) {
dump("error! we should have found the local mail server after we created it.\n");
localMailServer = null;
}
}
}
catch (ex) {dump("Error in verifyLocalFoldersAccount" + ex + "\n"); }
}
function setupCopiesAndFoldersServer(account, accountIsDeferred, accountData)
{
try {
var server = account.incomingServer;
// This function sets up the default send preferences. The send preferences
// go on identities, so there is no need to continue without any identities.
if (server.type == "rss" || account.identities.length == 0)
return false;
let identity = account.identities.queryElementAt(0, Components.interfaces.nsIMsgIdentity);
// For this server, do we default the folder prefs to this server, or to the "Local Folders" server
// If it's deferred, we use the local folders account.
var defaultCopiesAndFoldersPrefsToServer = !accountIsDeferred && server.defaultCopiesAndFoldersPrefsToServer;
var copiesAndFoldersServer = null;
if (defaultCopiesAndFoldersPrefsToServer)
{
copiesAndFoldersServer = server;
}
else
{
if (!MailServices.accounts.localFoldersServer)
{
dump("error! we should have a local mail server at this point\n");
return false;
}
copiesAndFoldersServer = MailServices.accounts.localFoldersServer;
}
setDefaultCopiesAndFoldersPrefs(identity, copiesAndFoldersServer, accountData);
} catch (ex) {
// return false (meaning we did not setupCopiesAndFoldersServer)
// on any error
dump("Error in setupCopiesAndFoldersServer: " + ex + "\n");
return false;
}
return true;
}
function setDefaultCopiesAndFoldersPrefs(identity, server, accountData)
{
var rootFolder = server.rootFolder;
// we need to do this or it is possible that the server's draft,
// stationery fcc folder will not be in rdf
//
// this can happen in a couple cases
// 1) the first account we create, creates the local mail. since
// local mail was just created, it obviously hasn't been opened,
// or in rdf..
// 2) the account we created is of a type where
// defaultCopiesAndFoldersPrefsToServer is true
// this since we are creating the server, it obviously hasn't been
// opened, or in rdf.
//
// this makes the assumption that the server's draft, stationery fcc folder
// are at the top level (ie subfolders of the root folder.) this works
// because we happen to be doing things that way, and if the user changes
// that, it will work because to change the folder, it must be in rdf,
// coming from the folder cache, in the worst case.
var msgFolder = rootFolder.QueryInterface(Components.interfaces.nsIMsgFolder);
/**
* When a new account is created, folders 'Sent', 'Drafts'
* and 'Templates' are not created then, but created on demand at runtime.
* But we do need to present them as possible choices in the Copies and Folders
* UI. To do that, folder URIs have to be created and stored in the prefs file.
* So, if there is a need to build special folders, append the special folder
* names and create right URIs.
*/
var folderDelim = "/";
/* we use internal names known to everyone like Sent, Templates and Drafts */
/* if folder names were already given in isp rdf, we use them,
otherwise we use internal names known to everyone like Sent, Templates and Drafts */
// Note the capital F, D and S!
var draftFolder = (accountData.identity && accountData.identity.DraftFolder ?
accountData.identity.DraftFolder : "Drafts");
var stationeryFolder = (accountData.identity && accountData.identity.StationeryFolder ?
accountData.identity.StationeryFolder : "Templates");
var fccFolder = (accountData.identity && accountData.identity.FccFolder ?
accountData.identity.FccFolder : "Sent");
identity.draftFolder = msgFolder.server.serverURI+ folderDelim + draftFolder;
identity.stationeryFolder = msgFolder.server.serverURI+ folderDelim + stationeryFolder;
identity.fccFolder = msgFolder.server.serverURI+ folderDelim + fccFolder;
// Note the capital F, D and S!
identity.fccFolderPickerMode = (accountData.identity &&
accountData.identity.FccFolder ? 1 : gDefaultSpecialFolderPickerMode);
identity.draftsFolderPickerMode = (accountData.identity &&
accountData.identity.DraftFolder ? 1 : gDefaultSpecialFolderPickerMode);
identity.tmplFolderPickerMode = (accountData.identity &&
accountData.identity.StationeryFolder ? 1 : gDefaultSpecialFolderPickerMode);
}
function AccountExists(userName, hostName, serverType)
{
return MailServices.accounts.findRealServer(userName, hostName, serverType, 0);
}
function getFirstInvalidAccount()
{
let invalidAccounts = getInvalidAccounts(MailServices.accounts.accounts);
if (invalidAccounts.length > 0)
return invalidAccounts[0];
else
return null;
}
function checkForInvalidAccounts()
{
var firstInvalidAccount = getFirstInvalidAccount();
if (firstInvalidAccount) {
var pageData = GetPageData();
dump("We have an invalid account, " + firstInvalidAccount + ", let's use that!\n");
gCurrentAccount = firstInvalidAccount;
// there's a possibility that the invalid account has ISP defaults
// as well.. so first pre-fill accountData with ISP info, then
// overwrite it with the account data
var identity =
firstInvalidAccount.identities.queryElementAt(0, nsIMsgIdentity);
var accountData = null;
// If there is a email address already provided, try to get to other ISP defaults.
// If not, get pre-configured data, if any.
if (identity.email) {
dump("Invalid account: trying to get ISP data for " + identity.email + "\n");
accountData = getIspDefaultsForEmail(identity.email);
dump("Invalid account: Got " + accountData + "\n");
// account -> accountData -> pageData
accountData = AccountToAccountData(firstInvalidAccount, accountData);
}
else {
accountData = getPreConfigDataForAccount(firstInvalidAccount);
}
AccountDataToPageData(accountData, pageData);
gCurrentAccountData = accountData;
setupWizardPanels();
// Set the page index to identity page.
document.documentElement.pageIndex = 1;
}
}
// Transfer all invalid account information to AccountData. Also, get those special
// preferences (not associated with any interfaces but preconfigurable via prefs or rdf files)
// like whether not the smtp server associated with this account requires
// a user name (mail.identity.<id_key>.smtpRequiresUsername) and the choice of skipping
// panels (mail.identity.<id_key>.wizardSkipPanels).
function getPreConfigDataForAccount(account)
{
var accountData = new Object;
accountData = new Object;
accountData.incomingServer = new Object;
accountData.identity = new Object;
accountData.smtp = new Object;
accountData = AccountToAccountData(account, null);
let identity = account.identities.queryElementAt(0, nsIMsgIdentity);
try {
var skipPanelsPrefStr = "mail.identity." + identity.key + ".wizardSkipPanels";
accountData.wizardSkipPanels = Services.prefs.getCharPref(skipPanelsPrefStr);
if (identity.smtpServerKey) {
let smtpServer = MailServices.smtp.getServerByKey(identity.smtpServerKey);
accountData.smtp = smtpServer;
var smtpRequiresUsername = false;
var smtpRequiresPrefStr = "mail.identity." + identity.key + ".smtpRequiresUsername";
smtpRequiresUsername = Services.prefs.getBoolPref(smtpRequiresPrefStr);
accountData.smtpRequiresUsername = smtpRequiresUsername;
}
}
catch(ex) {
// reached here as special identity pre-configuration prefs
// (wizardSkipPanels, smtpRequiresUsername) are not defined.
}
return accountData;
}
function AccountToAccountData(account, defaultAccountData)
{
dump("AccountToAccountData(" + account + ", " +
defaultAccountData + ")\n");
var accountData = defaultAccountData;
if (!accountData)
accountData = new Object;
accountData.incomingServer = account.incomingServer;
accountData.identity = account.identities.queryElementAt(0, nsIMsgIdentity);
accountData.smtp = MailServices.smtp.defaultServer;
return accountData;
}
// sets the page data, automatically creating the arrays as necessary
function setPageData(pageData, tag, slot, value) {
if (!pageData[tag]) pageData[tag] = [];
if (value == undefined) {
// clear out this slot
if (pageData[tag][slot]) delete pageData[tag][slot];
}
else {
// pre-fill this slot
if (!pageData[tag][slot]) pageData[tag][slot] = [];
pageData[tag][slot].id = slot;
pageData[tag][slot].value = value;
}
}
// value of checkbox on the first page
function serverIsNntp(pageData) {
if (pageData.accounttype.newsaccount)
return pageData.accounttype.newsaccount.value;
return false;
}
function getUsernameFromEmail(aEmail, aEnsureDomain)
{
var username = aEmail.substr(0, aEmail.indexOf("@"));
if (aEnsureDomain && gCurrentAccountData && gCurrentAccountData.domain)
username += '@' + gCurrentAccountData.domain;
return username;
}
function getCurrentUserName(pageData)
{
var userName = "";
if (pageData.login) {
if (pageData.login.username) {
userName = pageData.login.username.value;
}
}
if (userName == "") {
var email = pageData.identity.email.value;
userName = getUsernameFromEmail(email, false);
}
return userName;
}
function getCurrentServerType(pageData) {
var servertype = "pop3"; // hopefully don't resort to default!
if (serverIsNntp(pageData))
servertype = "nntp";
else if (pageData.server && pageData.server.servertype)
servertype = pageData.server.servertype.value;
return servertype;
}
function getCurrentServerIsDeferred(pageData) {
var serverDeferred = false;
if (getCurrentServerType(pageData) == "pop3" && pageData.server && pageData.server.deferStorage)
serverDeferred = pageData.server.deferStorage.value;
return serverDeferred;
}
function getCurrentHostname(pageData) {
if (serverIsNntp(pageData))
return pageData.newsserver.hostname.value;
else
return pageData.server.hostname.value;
}
function GetPageData()
{
if (!gPageData)
gPageData = new Object;
return gPageData;
}
function PrefillAccountForIsp(ispName)
{
dump("AccountWizard.prefillAccountForIsp(" + ispName + ")\n");
var ispData = getIspDefaultsForUri(ispName);
var pageData = GetPageData();
if (!ispData) {
SetCurrentAccountData(null);
return;
}
// prefill the rest of the wizard
dump("PrefillAccountForISP: filling with " + ispData + "\n");
SetCurrentAccountData(ispData);
AccountDataToPageData(ispData, pageData);
setPageData(pageData, "ispdata", "supplied", true);
}
// does any cleanup work for the the account data
// - sets the username from the email address if it's not already set
// - anything else?
function FixupAccountDataForIsp(accountData)
{
// no fixup for news
// setting the username does bad things
// see bugs #42105 and #154213
if (accountData.incomingServer.type == "nntp")
return;
var email = accountData.identity.email;
// The identity might not have an email address, which is what the rest of
// this function is looking for.
if (!email)
return;
// fix up the username
if (!accountData.incomingServer.username)
accountData.incomingServer.username =
getUsernameFromEmail(email, accountData.incomingServerUserNameRequiresDomain);
if (!accountData.smtp.username &&
accountData.smtpRequiresUsername) {
// fix for bug #107953
// if incoming hostname is same as smtp hostname
// use the server username (instead of the email username)
if (accountData.smtp.hostname == accountData.incomingServer.hostName &&
accountData.smtpUserNameRequiresDomain == accountData.incomingServerUserNameRequiresDomain)
accountData.smtp.username = accountData.incomingServer.username;
else
accountData.smtp.username = getUsernameFromEmail(email, accountData.smtpUserNameRequiresDomain);
}
}
function SetCurrentAccountData(accountData)
{
// dump("Setting current account data (" + gCurrentAccountData + ") to " + accountData + "\n");
gCurrentAccountData = accountData;
}
// flush the XUL cache - just for debugging purposes - not called
function onFlush() {
Services.prefs.setBoolPref("nglayout.debug.disable_xul_cache", true);
Services.prefs.setBoolPref("nglayout.debug.disable_xul_cache", false);
}
/** If there are no default accounts..
* this is will be the new default, so enable
* check for mail at startup
*/
function EnableCheckMailAtStartUpIfNeeded(newAccount)
{
// Check if default account exists and if that account is alllowed to be
// a default account. If no such account, make this one as the default account
// and turn on the new mail check at startup for the current account
if (!(gDefaultAccount && gDefaultAccount.incomingServer.canBeDefaultServer)) {
MailServices.accounts.defaultAccount = newAccount;
newAccount.incomingServer.loginAtStartUp = true;
newAccount.incomingServer.downloadOnBiff = true;
}
}
function SetSmtpRequiresUsernameAttribute(accountData)
{
// If this is the default server, time to set the smtp user name
// Set the generic attribute for requiring user name for smtp to true.
// ISPs can override the pref via rdf files.
if (!(gDefaultAccount && gDefaultAccount.incomingServer.canBeDefaultServer)) {
accountData.smtpRequiresUsername = true;
}
}
function setNextPage(currentPageId, nextPageId) {
var currentPage = document.getElementById(currentPageId);
currentPage.next = nextPageId;
}

View file

@ -0,0 +1,371 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/accountWizard.css" type="text/css"?>
<!DOCTYPE wizard SYSTEM "chrome://messenger/locale/AccountWizard.dtd">
<wizard id="AccountWizard" title="&windowTitle.label;"
onwizardcancel="return onCancel();"
onwizardfinish="return FinishAccount();"
#ifdef MOZ_THUNDERBIRD
onload="onAccountWizardLoad(); initAccountWizardTB(window.arguments);"
#else
onload="onAccountWizardLoad();"
#endif
style="&accountWizard.size;"
xmlns:nc="http://home.netscape.com/NC-rdf#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<stringbundle id="bundle_prefs" src="chrome://messenger/locale/prefs.properties"/>
<stringbundle id="bundle_messenger" src="chrome://messenger/locale/messenger.properties"/>
<script type="application/javascript" src="chrome://messenger/content/accountUtils.js"/>
<script type="application/javascript" src="chrome://messenger/content/amUtils.js"/>
<script type="application/javascript" src="chrome://messenger/content/AccountWizard.js"/>
<script type="application/javascript" src="chrome://messenger/content/ispUtils.js"/>
<script type="application/javascript" src="chrome://messenger/content/aw-accounttype.js"/>
<script type="application/javascript" src="chrome://messenger/content/aw-identity.js"/>
<script type="application/javascript" src="chrome://messenger/content/aw-incoming.js"/>
<script type="application/javascript" src="chrome://messenger/content/aw-outgoing.js"/>
<script type="application/javascript" src="chrome://messenger/content/aw-accname.js"/>
<script type="application/javascript" src="chrome://messenger/content/aw-done.js"/>
<!-- Account Type page : Displays choices of mail and news accounts that user can create -->
<wizardpage id="accounttype" pageid="accounttype"
label="&accountTypeTitle.label;"
onpageshow="document.documentElement.canAdvance = true;"
onpageadvanced="return acctTypePageUnload();">
<vbox flex="1">
<description>&accountSetupInfo2.label;</description>
<description>&accountTypeDesc2.label;</description>
<label control="acctyperadio">&accountTypeDirections.label;</label>
<separator/>
<radiogroup id="acctyperadio" >
#ifndef MOZ_THUNDERBIRD
<radio id="mailaccount" value="mailaccount"
label="&accountTypeMail.label;" accesskey="&accountTypeMail.accesskey;"
selected="true"/>
#endif
<vbox datasources="rdf:ispdefaults"
containment="http://home.netscape.com/NC-rdf#providers"
id="ispBox"
ref="NC:ispinfo">
<template>
<rule nc:wizardShow="true">
<radio uri="..."
value="rdf:http://home.netscape.com/NC-rdf#wizardShortName"
label="rdf:http://home.netscape.com/NC-rdf#wizardLongName"
accesskey="rdf:http://home.netscape.com/NC-rdf#wizardLongNameAccesskey"/>
</rule>
</template>
</vbox>
<radio id="newsaccount" value="newsaccount"
label="&accountTypeNews.label;" accesskey="&accountTypeNews.accesskey;"/>
</radiogroup>
</vbox>
</wizardpage>
<!-- Identity page : Collects user's full name and email address -->
<wizardpage id="identitypage" pageid="identitypage"
label="&identityTitle.label;"
onpageshow="return identityPageInit();"
onpageadvanced="return identityPageUnload();">
<vbox flex="1">
<description>&identityDesc.label;</description>
<separator/>
<description>&fullnameDesc.label; &fullnameExample.label;</description>
<separator class="thin"/>
<hbox align="center">
<label class="awIdentityLabel" value="&fullnameLabel.label;"
accesskey="&fullnameLabel.accesskey;" control="fullName"/>
<textbox mailtype="identity" wsm_persist="true" name="fullName" id="fullName" flex="1" oninput="identityPageValidate();"/>
</hbox>
<separator/>
<grid>
<columns>
<column flex="1"/>
</columns>
<rows>
<row>
<description id="emailDescText"/>
</row>
<separator class="thin"/>
<row>
<hbox align="center">
<label class="awIdentityLabel" id="emailFieldLabel" value="&emailLabel.label;"
accesskey="&emailLabel.accesskey;" control="email"/>
<hbox class="uri-element" align="center" flex="1">
<textbox wsm_persist="true" mailtype="identity" name="email"
oninput="identityPageValidate();"
id="email" flex="6" class="uri-element"/>
<label id="postEmailText"/>
</hbox>
</hbox>
</row>
</rows>
</grid>
</vbox>
</wizardpage>
<!-- Incoming page : User can choose to create mail account of his choice, POP3 or IMAP -->
<!-- Collects incoming server name and login name. -->
<!-- Login name is prefilled with user id from the email address provided in identity page -->
<!-- User can enter a login name here if it is different from the user id of his/her email address -->
<wizardpage id="incomingpage" pageid="incomingpage"
label="&incomingTitle.label;"
onpageshow="return incomingPageInit();"
onpageadvanced="return incomingPageUnload();">
<vbox flex="1">
<vbox id="serverTypeBox">
<label control="servertype">&incomingServerTypeDesc.label;</label>
<separator class="thin"/>
<hbox align="center" class="serverDataBox">
<!-- The initial value for the servertype radiogroup is set in onInit() -->
<radiogroup id="servertype" wsm_persist="true" orient="horizontal">
<radio group="servertype" value="pop3" id="pop3" label="&popType.label;"
wsm_persist="true" oncommand="setServerType();" accesskey="&popType.accesskey;"/>
<radio group="servertype" value="imap" id="imap" label="&imapType.label;"
wsm_persist="true" oncommand="setServerType();" accesskey="&imapType.accesskey;"/>
</radiogroup>
<label id="serverPortLabel" control="serverPort"
accesskey="&portNum.accesskey;"
value="&portNum.label;"/>
<textbox id="serverPort" type="number" size="3" max="65535"/>
<label id="defaultPortLabel" value="&defaultPortLabel.label;"/>
<label id="defaultPortValue" value="&defaultPortValue.label;"/>
</hbox>
<separator/>
</vbox>
<vbox id="incomingServerbox">
<description>&incomingServer.description;</description>
<hbox align="center" class="serverDataBox">
<label class="label, serverLabel"
value="&incomingServer.label;"
accesskey="&incomingServer.accesskey;"
control="incomingServer"/>
<textbox wsm_persist="true"
id="incomingServer"
flex="1"
class="uri-element"
oninput="incomingPageValidate();"/>
</hbox>
<hbox id="leaveMsgsOnSrvrBox" class="indent">
<checkbox id="leaveMessagesOnServer"
label="&leaveMsgsOnSrvr.label;"
accesskey="&leaveMsgsOnSrvr.accesskey;"
wsm_persist="true"
oncommand="setServerPrefs(this);"
checked="true"/>
</hbox>
<separator/>
</vbox>
<description>&incomingUsername.description;</description>
<separator class="thin"/>
<hbox align="center">
<label class="label"
value="&incomingUsername.label;"
style="width: 8em;"
accesskey="&incomingUsername.accesskey;"
control="username"/>
<textbox id="username"
wsm_persist="true"
flex="1"
oninput="incomingPageValidate();"/>
</hbox>
<vbox id="deferStorageBox">
<separator class="groove"/>
<description> &deferStorageDesc.label;</description>
<hbox>
<checkbox id="deferStorage"
label="&deferStorage.label;"
accesskey="&deferStorage.accesskey;"
checked="true"
wsm_persist="true"
oncommand="setServerPrefs(this);"/>
</hbox>
</vbox>
</vbox>
</wizardpage>
<!-- Outgoing page : Collects outgoing server name and login name. -->
<!-- Outgoing server name is collected if there isn't one already -->
<!-- Login name is prefilled with user id from the email address provided in identity page -->
<!-- User can enter a login name here if it is different from the user id of his/her email address -->
<wizardpage id="outgoingpage" pageid="outgoingpage"
label="&outgoingTitle.label;"
onpageshow="return outgoingPageInit();"
onpageadvanced="return outgoingPageUnload();">
<vbox flex="1">
<vbox id="noSmtp">
<description>&outgoingServer.description;</description>
<hbox align="center" class="serverDataBox">
<label class="label, serverLabel"
value="&outgoingServer.label;"
accesskey="&outgoingServer.accesskey;"
control="smtphostname"/>
<textbox id="smtphostname"
wsm_persist="true"
flex="1"
class="uri-element"
oninput="outgoingPageValidate();"/>
</hbox>
</vbox>
<vbox id="haveSmtp">
<description id="smtpStaticText1"
style="width: 200px;"
prefix="&haveSmtp1.prefix;"
suffix="&haveSmtp1.suffix3; &modifyOutgoing.suffix;">*</description>
</vbox>
<vbox id="loginSet1">
<description>&outgoingUsername.description;</description>
<separator class="thin"/>
<hbox align="center">
<label class="label"
value="&outgoingUsername.label;"
style="width: 8em;"
accesskey="&outgoingUsername.accesskey;"
control="smtpusername"/>
<textbox id="smtpusername" wsm_persist="true" flex="1"/>
</hbox>
</vbox>
<vbox id="loginSet2" hidden="true">
<description id="smtpStaticText2" style="width: 200px;" prefix="&haveSmtp2.prefix;"
suffix="&haveSmtp2.suffix3; &modifyOutgoing.suffix;">*</description>
</vbox>
<vbox id="loginSet3" hidden="true">
<description id="smtpStaticText3" style="width: 200px;" prefix="&haveSmtp3.prefix;"
suffix="&haveSmtp3.suffix3; &modifyOutgoing.suffix;">*</description>
</vbox>
</vbox>
</wizardpage>
<!-- News Server page : Collects the News groups server name -->
<wizardpage id="newsserver" pageid="newsserver"
label="&incomingTitle.label;"
onpageshow="return incomingPageInit();"
onpageadvanced="return incomingPageUnload();">
<vbox flex="1">
<description>&newsServerNameDesc.label;</description>
<separator class="thin"/>
<hbox align="center">
<label control="newsServer" value="&newsServerLabel.label;" accesskey="&newsServerLabel.accesskey;" style="width: 8em;"/>
<textbox id="newsServer"
wsm_persist="true"
flex="1"
class="uri-element"
oninput="incomingPageValidate();"/>
</hbox>
</vbox>
</wizardpage>
<!-- Account name page : User gets a choice to enter a pretty name for the account -->
<!-- Defaults : Mail account -> Email address, Newsgroup account -> Newsgroup server name -->
<wizardpage id="accnamepage" pageid="accnamepage"
label="&accnameTitle.label;"
onpageshow="return acctNamePageInit();"
onpageadvanced="return acctNamePageUnload();">
<vbox flex="1">
<description>&accnameDesc.label;</description>
<separator class="thin"/>
<hbox align="center">
<label class="label" value="&accnameLabel.label;" style="width: 8em;"
accesskey="&accnameLabel.accesskey;" control="prettyName"/>
<textbox id="prettyName" size="40" wsm_persist="true" flex="1" oninput="acctNamePageValidate();"/>
</hbox>
</vbox>
</wizardpage>
<!-- Done page : this page summarizes information collected to create a mail/news account -->
<wizardpage id="done" pageid="done"
label="&completionTitle.label;"
onpageshow="return donePageInit();">
<vbox flex="1">
<description>&completionText.label;</description>
<separator class="thin"/>
<grid>
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center" id="account.name">
<label class="label" flex="1" id="account.name.label" value="&accnameLabel.label;"/>
<label class="label" id="account.name.text"/>
</row>
<row align="center" id="identity.email">
<label class="label" flex="1" id="identity.email.label" value="&emailLabel.label;"/>
<label class="label" id="identity.email.text"/>
</row>
<row align="center" id="server.username">
<label class="label" flex="1" id="server.username.label" value="&incomingUsername.label;"/>
<label class="label" id="server.username.text"/>
</row>
<row align="center" id="server.name">
<label class="label" flex="1" id="server.name.label" value="&serverNamePrefix.label;"/>
<label class="label" id="server.name.text"/>
</row>
<row align="center" id="server.type">
<label class="label" flex="1" id="server.type.label" value="&serverTypePrefix.label;"/>
<label class="label" id="server.type.text"/>
</row>
<row align="center" id="server.port">
<label class="label" id="server.port.label" flex="1" value="&portNum.label;"/>
<label class="label" id="server.port.text"/>
</row>
<row align="center" id="newsServer.name">
<label class="label" flex="1" id="newsServer.name.label" value="&newsServerNamePrefix.label;"/>
<label class="label" id="newsServer.name.text"/>
</row>
<row align="center" id="smtpServer.username">
<label class="label" flex="1" id="smtpServer.username.label" value="&outgoingUsername.label;"/>
<label class="label" id="smtpServer.username.text"/>
</row>
<row align="center" id="smtpServer.name">
<label class="label" flex="1" id="smtpServer.name.label" value="&smtpServerNamePrefix.label;"/>
<label class="label" id="smtpServer.name.text"/>
</row>
</rows>
</grid>
<separator/>
<hbox id="downloadMsgsBox">
<checkbox id="downloadMsgs"
label="&downloadOnLogin.label;"
accesskey="&downloadOnLogin.accesskey;"
hidden="true"
checked="true"/>
</hbox>
<spacer flex="1"/>
#ifndef XP_MACOSX
<description>&clickFinish.label;</description>
#else
<description>&clickFinish.labelMac;</description>
#endif
</vbox>
</wizardpage>
<wizardpage id="ispPage1"/>
<wizardpage id="ispPage2"/>
<wizardpage id="ispPage3"/>
<wizardpage id="ispPage4"/>
<wizardpage id="ispPage5"/>
<wizardpage id="ispPage6"/>
<wizardpage id="ispPage7"/>
<wizardpage id="ispPage8"/>
<wizardpage id="ispPage9"/>
<wizardpage id="ispPage10"/>
<wizardpage id="ispPage11"/>
<wizardpage id="ispPage12"/>
<wizardpage id="ispPage13"/>
<wizardpage id="ispPage14"/>
<wizardpage id="ispPage15"/>
<wizardpage id="ispPage16"/>
</wizard>

View file

@ -0,0 +1,46 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
Components.utils.import("resource:///modules/hostnameUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource:///modules/mailServices.js");
var gSmtpServer;
function onLoad(event)
{
gSmtpServer = window.arguments[0].server;
initSmtpSettings(gSmtpServer);
}
function onAccept()
{
if (!isLegalHostNameOrIP(cleanUpHostName(gSmtpHostname.value))) {
let prefsBundle = document.getElementById("bundle_prefs");
let brandBundle = document.getElementById("bundle_brand");
let alertTitle = brandBundle.getString("brandShortName");
let alertMsg = prefsBundle.getString("enterValidServerName");
Services.prompt.alert(window, alertTitle, alertMsg);
window.arguments[0].result = false;
return false;
}
// If we didn't have an SMTP server to initialize with,
// we must be creating one.
try {
if (!gSmtpServer) {
gSmtpServer = MailServices.smtp.createServer();
window.arguments[0].addSmtpServer = gSmtpServer.key;
}
saveSmtpSettings(gSmtpServer);
} catch (ex) {
Components.utils.reportError("Error saving smtp server: " + ex);
}
window.arguments[0].result = true;
return true;
}

View file

@ -0,0 +1,28 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://messenger/skin/messenger.css" type="text/css"?>
<?xul-overlay href="chrome://messenger/content/smtpEditOverlay.xul"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/dialogs.css" type="text/css"?>
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/smtpEditOverlay.dtd">
<dialog title="&smtpEditTitle.label;"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="onLoad();"
ondialogaccept="return onAccept();">
<stringbundle id="bundle_prefs"
src="chrome://messenger/locale/prefs.properties"/>
<stringbundle id="bundle_brand"
src="chrome://branding/locale/brand.properties"/>
<stringbundle id="bundle_messenger"
src="chrome://messenger/locale/messenger.properties"/>
<script type="application/javascript"
src="chrome://messenger/content/SmtpServerEdit.js"/>
<vbox id="smtpServerEditor"/>
</dialog>

View file

@ -0,0 +1,462 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource:///modules/mailServices.js");
var gAnyValidIdentity = false; //If there are no valid identities for any account
// returns the first account with an invalid server or identity
var gNewAccountToLoad = null; // used to load new messages if we come from the mail3pane
function getInvalidAccounts(accounts)
{
let numAccounts = accounts.length;
let invalidAccounts = new Array;
let numIdentities = 0;
for (let i = 0; i < numAccounts; i++) {
let account = accounts.queryElementAt(i, Components.interfaces.nsIMsgAccount);
try {
if (!account.incomingServer.valid) {
invalidAccounts[invalidAccounts.length] = account;
// skip to the next account
continue;
}
} catch (ex) {
// this account is busted, just keep going
continue;
}
var identities = account.identities;
numIdentities = identities.length;
for (var j = 0; j < numIdentities; j++) {
let identity = identities.queryElementAt(j, Components.interfaces.nsIMsgIdentity);
if (identity.valid) {
gAnyValidIdentity = true;
}
else {
invalidAccounts[invalidAccounts.length] = account;
}
}
}
return invalidAccounts;
}
function showMailIntegrationDialog() {
const nsIShellService = Components.interfaces.nsIShellService;
try {
var shellService = Components.classes["@mozilla.org/suite/shell-service;1"]
.getService(nsIShellService);
var appTypesCheck = shellService.shouldBeDefaultClientFor &
(nsIShellService.MAIL | nsIShellService.NEWS);
// show the default client dialog only if we have at least one account,
// if we should check for the default client, and we want to check if we are
// the default for mail/news and are not the default client for mail/news
if (appTypesCheck && shellService.shouldCheckDefaultClient &&
!shellService.isDefaultClient(true, appTypesCheck))
window.openDialog("chrome://communicator/content/defaultClientDialog.xul",
"DefaultClient", "modal,centerscreen,chrome,resizable=no");
} catch (ex) {}
}
/**
* Verify that there is at least one account. If not, open a new account wizard.
*
* @param wizardCallback if the wizard is run, callback when it is done.
* @param needsIdentity True only when verifyAccounts is called from the
* compose window. This last condition is so that we open
* the account wizard if the user does not have any
* identities defined and tries to compose mail.
* @param wizardOpen optional param that allows the caller to specify a
* different method to open a wizard. The wizardOpen method
* takes wizardCallback as an argument. The wizardCallback
* doesn't take any arguments.
*/
function verifyAccounts(wizardCallback, needsIdentity, wizardOpen)
{
var openWizard = false;
var prefillAccount;
var state=true;
var ret = true;
try {
// migrate quoting preferences from global to per account. This function returns
// true if it had to migrate, which we will use to mean this is a just migrated
// or new profile
var newProfile = migrateGlobalQuotingPrefs(MailServices.accounts.allIdentities);
var accounts = MailServices.accounts.accounts;
// as long as we have some accounts, we're fine.
var accountCount = accounts.length;
var invalidAccounts = getInvalidAccounts(accounts);
if (invalidAccounts.length > 0 && invalidAccounts.length == accountCount) {
prefillAccount = invalidAccounts[0];
}
// if there are no accounts, or all accounts are "invalid"
// then kick off the account migration. Or if this is a new (to Mozilla) profile.
// MCD can set up accounts without the profile being used yet
if (newProfile) {
// check if MCD is configured. If not, say this is not a new profile
// so that we don't accidentally remigrate non MCD profiles.
var adminUrl;
try {
adminUrl = Services.prefs.getCharPref("autoadmin.global_config_url");
}
catch (ex) {}
if (!adminUrl)
newProfile = false;
}
if ((newProfile && !accountCount) || accountCount == invalidAccounts.length)
openWizard = true;
// openWizard is true if messenger migration returns some kind of
// error (including those cases where there is nothing to migrate).
// prefillAccount is non-null if there is at least one invalid account.
// gAnyValidIdentity is true when you've got at least one *valid*
// identity. Since local and RSS folders are identity-less accounts, if you
// only have one of those, it will be false.
// needsIdentity is true only when verifyAccounts is called from the
// compose window. This last condition is so that we open the account
// wizard if the user does not have any identities defined and tries to
// compose mail.
if (openWizard || prefillAccount || ((!gAnyValidIdentity) && needsIdentity))
{
if (wizardOpen != undefined)
wizardOpen(wizardCallback)
else
MsgAccountWizard(wizardCallback);
ret = false;
}
else
{
var localFoldersExists;
try
{
localFoldersExists = MailServices.accounts.localFoldersServer;
}
catch (ex)
{
localFoldersExists = false;
}
// we didn't create the MsgAccountWizard - we need to verify that local folders exists.
if (!localFoldersExists)
MailServices.accounts.createLocalMailAccount();
}
// This will do nothing on platforms without a shell service
const NS_SHELLSERVICE_CID = "@mozilla.org/suite/shell-service;1"
if (NS_SHELLSERVICE_CID in Components.classes)
{
// hack, set a time out to do this, so that the window can load first
setTimeout(showMailIntegrationDialog, 0);
}
return ret;
}
catch (ex) {
dump("error verifying accounts " + ex + "\n");
return false;
}
}
// we do this from a timer because if this is called from the onload=
// handler, then the parent window doesn't appear until after the wizard
// has closed, and this is confusing to the user
function MsgAccountWizard(wizardCallback)
{
setTimeout(function() { msgOpenAccountWizard(wizardCallback); }, 0);
}
/**
* Open the Old Mail Account Wizard, or focus it if it's already open.
*
* @param wizardCallback if the wizard is run, callback when it is done.
* @param type - optional account type token, for Tb.
* @see msgNewMailAccount below for the new implementation.
*/
function msgOpenAccountWizard(wizardCallback, type)
{
gNewAccountToLoad = null;
window.openDialog("chrome://messenger/content/AccountWizard.xul", "AccountWizard",
"chrome,modal,titlebar,centerscreen",
{okCallback: wizardCallback, acctType: type});
loadInboxForNewAccount();
// If we started with no servers at all and "smtp servers" list selected,
// refresh display somehow. Bug 58506.
// TODO Better fix: select newly created account (in all cases)
if (typeof(getCurrentAccount) == "function" && // in AccountManager, not menu
!getCurrentAccount())
selectServer(null, null);
}
function initAccountWizardTB(args) {
let type = args[0] && args[0].acctType;
let selType = type == "newsgroups" ? "newsaccount" :
type == "movemail" ? "Movemail" : null;
let accountwizard = document.getElementById("AccountWizard");
let acctyperadio = document.getElementById("acctyperadio");
let feedRadio = acctyperadio.querySelector("radio[value='Feeds']");
if (feedRadio)
feedRadio.remove();
if (selType) {
acctyperadio.selectedItem = acctyperadio.querySelector("radio[value='"+selType+"']");
accountwizard.advance("identitypage");
}
else
acctyperadio.selectedItem = acctyperadio.getItemAtIndex(0);
}
function AddFeedAccount() {
window.openDialog("chrome://messenger-newsblog/content/feedAccountWizard.xul",
"", "chrome,modal,titlebar,centerscreen");
}
/**
* Opens the account settings window on the specified account
* and page of settings. If the window is already open it is only focused.
*
* @param selectPage The xul file name for the viewing page or
* null for the account main page. Other pages are
* 'am-server.xul', 'am-copies.xul', 'am-offline.xul',
* 'am-addressing.xul', 'am-smtp.xul'
* @param aServer The server of the account to select. Optional.
*/
function MsgAccountManager(selectPage, aServer)
{
var existingAccountManager = Services.wm.getMostRecentWindow("mailnews:accountmanager");
if (existingAccountManager)
existingAccountManager.focus();
else {
if (!aServer) {
if (typeof GetSelectedMsgFolders === "function") {
let folders = GetSelectedMsgFolders();
if (folders.length > 0)
aServer = folders[0].server;
}
if (!aServer && (typeof GetDefaultAccountRootFolder === "function")) {
let folder = GetDefaultAccountRootFolder();
if (folder instanceof Components.interfaces.nsIMsgFolder)
aServer = folder.server;
}
}
window.openDialog("chrome://messenger/content/AccountManager.xul",
"AccountManager",
"chrome,centerscreen,modal,titlebar,resizable",
{ server: aServer, selectPage: selectPage });
}
}
function loadInboxForNewAccount()
{
// gNewAccountToLoad is set in the final screen of the Account Wizard if a POP account
// was created, the download messages box is checked, and the wizard was opened from the 3pane
if (gNewAccountToLoad) {
var rootMsgFolder = gNewAccountToLoad.incomingServer.rootMsgFolder;
const kInboxFlag = Components.interfaces.nsMsgFolderFlags.Inbox;
var inboxFolder = rootMsgFolder.getFolderWithFlags(kInboxFlag);
SelectFolder(inboxFolder.URI);
window.focus();
setTimeout(MsgGetMessage, 0);
gNewAccountToLoad = null;
}
}
// returns true if we migrated - it knows this because 4.x did not have the
// pref mailnews.quotingPrefs.version, so if it's not set, we're either
// migrating from 4.x, or a much older version of Mozilla.
function migrateGlobalQuotingPrefs(allIdentities)
{
// if reply_on_top and auto_quote exist then, if non-default
// migrate and delete, if default just delete.
var reply_on_top = 0;
var auto_quote = true;
var quotingPrefs = 0;
var migrated = false;
try {
quotingPrefs = Services.prefs.getIntPref("mailnews.quotingPrefs.version");
} catch (ex) {}
// If the quotingPrefs version is 0 then we need to migrate our preferences
if (quotingPrefs == 0) {
migrated = true;
try {
reply_on_top = Services.prefs.getIntPref("mailnews.reply_on_top");
auto_quote = Services.prefs.getBoolPref("mail.auto_quote");
} catch (ex) {}
if (!auto_quote || reply_on_top) {
let numIdentities = allIdentities.length;
var identity = null;
for (var j = 0; j < numIdentities; j++) {
identity = allIdentities.queryElementAt(j, Components.interfaces.nsIMsgIdentity);
if (identity.valid) {
identity.autoQuote = auto_quote;
identity.replyOnTop = reply_on_top;
}
}
}
Services.prefs.setIntPref("mailnews.quotingPrefs.version", 1);
}
return migrated;
}
// we do this from a timer because if this is called from the onload=
// handler, then the parent window doesn't appear until after the wizard
// has closed, and this is confusing to the user
function NewMailAccount(msgWindow, okCallback, extraData)
{
if (!msgWindow)
throw new Error("NewMailAccount must be given a msgWindow.");
// Populate the extra data.
if (!extraData)
extraData = {};
extraData.msgWindow = msgWindow;
let mail3Pane = Services.wm.getMostRecentWindow("mail:3pane");
if (!extraData.NewMailAccount)
extraData.NewMailAccount = NewMailAccount;
if (!extraData.msgNewMailAccount)
extraData.msgNewMailAccount = msgNewMailAccount;
if (!extraData.NewComposeMessage)
extraData.NewComposeMessage = mail3Pane.ComposeMessage;
if (!extraData.openAddonsMgr)
extraData.openAddonsMgr = mail3Pane.openAddonsMgr;
if (!extraData.okCallback)
extraData.okCallback = null;
if (!extraData.success)
extraData.success = false;
setTimeout(extraData.msgNewMailAccount, 0, msgWindow, okCallback, extraData);
}
function NewMailAccountProvisioner(aMsgWindow, args) {
if (!args)
args = {};
if (!aMsgWindow)
aMsgWindow = MailServices.mailSession.topmostMsgWindow;
args.msgWindow = aMsgWindow;
let mail3Pane = Services.wm.getMostRecentWindow("mail:3pane");
// If we couldn't find a 3pane, bail out.
if (!mail3Pane) {
Components.utils.reportError("Could not find a 3pane to connect to.");
return;
}
let tabmail = mail3Pane.document.getElementById("tabmail");
if (!tabmail) {
Components.utils.reportError("Could not find a tabmail in the 3pane!");
return;
}
// If there's already an accountProvisionerTab open, just focus it instead
// of opening a new dialog.
let apTab = tabmail.getTabInfoForCurrentOrFirstModeInstance(
tabmail.tabModes["accountProvisionerTab"]);
if (apTab) {
tabmail.switchToTab(apTab);
return;
}
// XXX make sure these are all defined in all contexts... to be on the safe
// side, just get a mail:3pane and borrow the functions from it?
if (!args.NewMailAccount)
args.NewMailAccount = NewMailAccount;
if (!args.msgNewMailAccount)
args.msgNewMailAccount = msgNewMailAccount;
if (!args.NewComposeMessage)
args.NewComposeMessage = mail3Pane.ComposeMessage;
if (!args.openAddonsMgr)
args.openAddonsMgr = mail3Pane.openAddonsMgr;
if (!args.okCallback)
args.okCallback = null;
let windowParams = "chrome,titlebar,centerscreen,width=640,height=480";
if (!args.success) {
args.success = false;
// If we're not opening up the success dialog, then our window should be
// modal.
windowParams = "modal," + windowParams;
}
// NOTE: If you're a developer, and you notice that the jQuery code in
// accountProvisioner.xhtml isn't throwing errors or warnings, that's due
// to bug 688273. Just make the window non-modal to get those errors and
// warnings back, and then clear this comment when bug 688273 is closed.
window.openDialog(
"chrome://messenger/content/newmailaccount/accountProvisioner.xhtml",
"AccountCreation",
windowParams,
args);
}
/**
* Open the New Mail Account Wizard, or focus it if it's already open.
*
* @param msgWindow a msgWindow for us to use to verify the accounts.
* @param okCallback an optional callback for us to call back to if
* everything's okay.
* @param extraData an optional param that allows us to pass data in and
* out. Used in the upcoming AccountProvisioner add-on.
* @see msgOpenAccountWizard above for the previous implementation.
*/
function msgNewMailAccount(msgWindow, okCallback, extraData)
{
if (!msgWindow)
throw new Error("msgNewMailAccount must be given a msgWindow.");
let existingWindow = Services.wm.getMostRecentWindow("mail:autoconfig");
if (existingWindow) {
existingWindow.focus();
} else {
// disabling modal for the time being, see 688273 REMOVEME
window.openDialog("chrome://messenger/content/accountcreation/emailWizard.xul",
"AccountSetup", "chrome,titlebar,centerscreen",
{msgWindow:msgWindow,
okCallback:okCallback,
extraData:extraData});
}
/*
// TODO: Enable this block of code once the dialog above is made modal.
// If we started with no servers at all and "smtp servers" list selected,
// refresh display somehow. Bug 58506.
// TODO Better fix: select newly created account (in all cases)
let existingAccountManager =
Services.wm.getMostRecentWindow("mailnews:accountmanager");
// in AccountManager, not menu
if (existingAccountManager && typeof(getCurrentAccount) == "function" &&
!getCurrentAccount()) {
selectServer(null, null);
}
*/
}

View file

@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/**
* This class implements nsIBadCertListener. It's job is to prevent "bad cert"
* security dialogs from being shown to the user. We call back to the
* 'callback' object's method "processCertError" so that it can deal with it as
* needed (in the case of autoconfig, setting up temporary overrides).
*/
function BadCertHandler(callback)
{
this._init(callback);
}
BadCertHandler.prototype =
{
_init: function(callback) {
this._callback = callback;
},
// Suppress any certificate errors
notifyCertProblem: function(socketInfo, status, targetSite) {
return this._callback.processCertError(socketInfo, status, targetSite);
},
// nsIInterfaceRequestor
getInterface: function(iid) {
return this.QueryInterface(iid);
},
// nsISupports
QueryInterface: function(iid) {
if (!iid.equals(Components.interfaces.nsIBadCertListener2) &&
!iid.equals(Components.interfaces.nsIInterfaceRequestor) &&
!iid.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};

View file

@ -0,0 +1,259 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/**
* This file creates the class AccountConfig, which is a JS object that holds
* a configuration for a certain account. It is *not* created in the backend
* yet (use aw-createAccount.js for that), and it may be incomplete.
*
* Several AccountConfig objects may co-exist, e.g. for autoconfig.
* One AccountConfig object is used to prefill and read the widgets
* in the Wizard UI.
* When we autoconfigure, we autoconfig writes the values into a
* new object and returns that, and the caller can copy these
* values into the object used by the UI.
*
* See also
* <https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat>
* for values stored.
*/
function AccountConfig()
{
this.incoming = this.createNewIncoming();
this.incomingAlternatives = [];
this.outgoing = this.createNewOutgoing();
this.outgoingAlternatives = [];
this.identity =
{
// displayed real name of user
realname : "%REALNAME%",
// email address of user, as shown in From of outgoing mails
emailAddress : "%EMAILADDRESS%",
};
this.inputFields = [];
this.domains = [];
};
AccountConfig.prototype =
{
// @see createNewIncoming()
incoming : null,
// @see createNewOutgoing()
outgoing : null,
/**
* Other servers which can be used instead of |incoming|,
* in order of decreasing preference.
* (|incoming| itself should not be included here.)
* { Array of incoming/createNewIncoming() }
*/
incomingAlternatives : null,
outgoingAlternatives : null,
// OAuth2 configuration, if needed.
oauthSettings : null,
// just an internal string to refer to this. Do not show to user.
id : null,
// who created the config.
// { one of kSource* }
source : 0,
displayName : null,
// { Array of { varname (value without %), displayName, exampleValue } }
inputFields : null,
// email address domains for which this config is applicable
// { Array of Strings }
domains : null,
/**
* Factory function for incoming and incomingAlternatives
*/
createNewIncoming : function()
{
return {
// { String-enum: "pop3", "imap", "nntp" }
type : null,
hostname : null,
// { Integer }
port : null,
// May be a placeholder (starts and ends with %). { String }
username : null,
password : null,
// { enum: 1 = plain, 2 = SSL/TLS, 3 = STARTTLS always, 0 = not inited }
// ('TLS when available' is insecure and not supported here)
socketType : 0,
/**
* true when the cert is invalid (and thus SSL useless), because it's
* 1) not from an accepted CA (including self-signed certs)
* 2) for a different hostname or
* 3) expired.
* May go back to false when user explicitly accepted the cert.
*/
badCert : false,
/**
* How to log in to the server: plaintext or encrypted pw, GSSAPI etc.
* Defined by Ci.nsMsgAuthMethod
* Same as server pref "authMethod".
*/
auth : 0,
/**
* Other auth methods that we think the server supports.
* They are ordered by descreasing preference.
* (|auth| itself is not included in |authAlternatives|)
* {Array of Ci.nsMsgAuthMethod} (same as .auth)
*/
authAlternatives : null,
// in minutes { Integer }
checkInterval : 10,
loginAtStartup : true,
// POP3 only:
// Not yet implemented. { Boolean }
useGlobalInbox : false,
leaveMessagesOnServer : true,
daysToLeaveMessagesOnServer : 14,
deleteByAgeFromServer : true,
// When user hits delete, delete from local store and from server
deleteOnServerWhenLocalDelete : true,
downloadOnBiff : true,
};
},
/**
* Factory function for outgoing and outgoingAlternatives
*/
createNewOutgoing : function()
{
return {
type : "smtp",
hostname : null,
port : null, // see incoming
username : null, // see incoming. may be null, if auth is 0.
password : null, // see incoming. may be null, if auth is 0.
socketType : 0, // see incoming
badCert : false, // see incoming
auth : 0, // see incoming
authAlternatives : null, // see incoming
addThisServer : true, // if we already have an SMTP server, add this
// if we already have an SMTP server, use it.
useGlobalPreferredServer : false,
// we should reuse an already configured SMTP server.
// nsISmtpServer.key
existingServerKey : null,
// user display value for existingServerKey
existingServerLabel : null,
};
},
/**
* Returns a deep copy of this object,
* i.e. modifying the copy will not affect the original object.
*/
copy : function()
{
// Workaround: deepCopy() fails to preserve base obj (instanceof)
var result = new AccountConfig();
for (var prop in this)
result[prop] = deepCopy(this[prop]);
return result;
},
isComplete : function()
{
return (!!this.incoming.hostname && !!this.incoming.port &&
!!this.incoming.socketType && !!this.incoming.auth &&
!!this.incoming.username &&
(!!this.outgoing.existingServerKey ||
(!!this.outgoing.hostname && !!this.outgoing.port &&
!!this.outgoing.socketType && !!this.outgoing.auth &&
!!this.outgoing.username)));
},
};
// enum consts
// .source
AccountConfig.kSourceUser = 1; // user manually entered the config
AccountConfig.kSourceXML = 2; // config from XML from ISP or Mozilla DB
AccountConfig.kSourceGuess = 3; // guessConfig()
/**
* Some fields on the account config accept placeholders (when coming from XML).
*
* These are the predefined ones
* * %EMAILADDRESS% (full email address of the user, usually entered by user)
* * %EMAILLOCALPART% (email address, part before @)
* * %EMAILDOMAIN% (email address, part after @)
* * %REALNAME%
* as well as those defined in account.inputFields.*.varname, with % added
* before and after.
*
* These must replaced with real values, supplied by the user or app,
* before the account is created. This is done here. You call this function once
* you have all the data - gathered the standard vars mentioned above as well as
* all listed in account.inputFields, and pass them in here. This function will
* insert them in the fields, returning a fully filled-out account ready to be
* created.
*
* @param account {AccountConfig}
* The account data to be modified. It may or may not contain placeholders.
* After this function, it should not contain placeholders anymore.
* This object will be modified in-place.
*
* @param emailfull {String}
* Full email address of this account, e.g. "joe@example.com".
* Empty of incomplete email addresses will/may be rejected.
*
* @param realname {String}
* Real name of user, as will appear in From of outgoing messages
*
* @param password {String}
* The password for the incoming server and (if necessary) the outgoing server
*/
function replaceVariables(account, realname, emailfull, password)
{
sanitize.nonemptystring(emailfull);
let emailsplit = emailfull.split("@");
assert(emailsplit.length == 2,
"email address not in expected format: must contain exactly one @");
let emaillocal = sanitize.nonemptystring(emailsplit[0]);
let emaildomain = sanitize.hostname(emailsplit[1]);
sanitize.label(realname);
sanitize.nonemptystring(realname);
let otherVariables = {};
otherVariables.EMAILADDRESS = emailfull;
otherVariables.EMAILLOCALPART = emaillocal;
otherVariables.EMAILDOMAIN = emaildomain;
otherVariables.REALNAME = realname;
if (password) {
account.incoming.password = password;
account.outgoing.password = password; // set member only if auth required?
}
account.incoming.username = _replaceVariable(account.incoming.username,
otherVariables);
account.outgoing.username = _replaceVariable(account.outgoing.username,
otherVariables);
account.incoming.hostname =
_replaceVariable(account.incoming.hostname, otherVariables);
if (account.outgoing.hostname) // will be null if user picked existing server.
account.outgoing.hostname =
_replaceVariable(account.outgoing.hostname, otherVariables);
account.identity.realname =
_replaceVariable(account.identity.realname, otherVariables);
account.identity.emailAddress =
_replaceVariable(account.identity.emailAddress, otherVariables);
account.displayName = _replaceVariable(account.displayName, otherVariables);
}
function _replaceVariable(variable, values)
{
let str = variable;
if (typeof(str) != "string")
return str;
for (let varname in values)
str = str.replace("%" + varname + "%", values[varname]);
return str;
}

View file

@ -0,0 +1,333 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/**
* Takes an |AccountConfig| JS object and creates that account in the
* Thunderbird backend (which also writes it to prefs).
*
* @param config {AccountConfig} The account to create
*
* @return - the account created.
*/
Components.utils.import("resource:///modules/mailServices.js");
Components.utils.import("resource://gre/modules/Services.jsm");
function createAccountInBackend(config)
{
// incoming server
let inServer = MailServices.accounts.createIncomingServer(
config.incoming.username,
config.incoming.hostname,
sanitize.enum(config.incoming.type, ["pop3", "imap", "nntp"]));
inServer.port = config.incoming.port;
inServer.authMethod = config.incoming.auth;
inServer.password = config.incoming.password;
if (config.rememberPassword && config.incoming.password.length)
rememberPassword(inServer, config.incoming.password);
if (inServer.authMethod == Ci.nsMsgAuthMethod.OAuth2) {
inServer.setCharValue("oauth2.scope", config.oauthSettings.scope);
inServer.setCharValue("oauth2.issuer", config.oauthSettings.issuer);
}
// SSL
if (config.incoming.socketType == 1) // plain
inServer.socketType = Ci.nsMsgSocketType.plain;
else if (config.incoming.socketType == 2) // SSL / TLS
inServer.socketType = Ci.nsMsgSocketType.SSL;
else if (config.incoming.socketType == 3) // STARTTLS
inServer.socketType = Ci.nsMsgSocketType.alwaysSTARTTLS;
//inServer.prettyName = config.displayName;
inServer.prettyName = config.identity.emailAddress;
inServer.doBiff = true;
inServer.biffMinutes = config.incoming.checkInterval;
const loginAtStartupPrefTemplate =
"mail.server.%serverkey%.login_at_startup";
var loginAtStartupPref =
loginAtStartupPrefTemplate.replace("%serverkey%", inServer.key);
Services.prefs.setBoolPref(loginAtStartupPref,
config.incoming.loginAtStartup);
if (config.incoming.type == "pop3")
{
const leaveOnServerPrefTemplate =
"mail.server.%serverkey%.leave_on_server";
const daysToLeaveOnServerPrefTemplate =
"mail.server.%serverkey%.num_days_to_leave_on_server";
const deleteFromServerPrefTemplate =
"mail.server.%serverkey%.delete_mail_left_on_server";
const deleteByAgeFromServerPrefTemplate =
"mail.server.%serverkey%.delete_by_age_from_server";
const downloadOnBiffPrefTemplate =
"mail.server.%serverkey%.download_on_biff";
var leaveOnServerPref =
leaveOnServerPrefTemplate.replace("%serverkey%", inServer.key);
var ageFromServerPref =
deleteByAgeFromServerPrefTemplate.replace("%serverkey%", inServer.key);
var daysToLeaveOnServerPref =
daysToLeaveOnServerPrefTemplate.replace("%serverkey%", inServer.key);
var deleteFromServerPref =
deleteFromServerPrefTemplate.replace("%serverkey%", inServer.key);
let downloadOnBiffPref =
downloadOnBiffPrefTemplate.replace("%serverkey%", inServer.key);
Services.prefs.setBoolPref(leaveOnServerPref,
config.incoming.leaveMessagesOnServer);
Services.prefs.setIntPref(daysToLeaveOnServerPref,
config.incoming.daysToLeaveMessagesOnServer);
Services.prefs.setBoolPref(deleteFromServerPref,
config.incoming.deleteOnServerWhenLocalDelete);
Services.prefs.setBoolPref(ageFromServerPref,
config.incoming.deleteByAgeFromServer);
Services.prefs.setBoolPref(downloadOnBiffPref,
config.incoming.downloadOnBiff);
}
inServer.valid = true;
let username = config.outgoing.auth > 1 ? config.outgoing.username : null;
let outServer = MailServices.smtp.findServer(username, config.outgoing.hostname);
assert(config.outgoing.addThisServer ||
config.outgoing.useGlobalPreferredServer ||
config.outgoing.existingServerKey,
"No SMTP server: inconsistent flags");
if (config.outgoing.addThisServer && !outServer)
{
outServer = MailServices.smtp.createServer();
outServer.hostname = config.outgoing.hostname;
outServer.port = config.outgoing.port;
outServer.authMethod = config.outgoing.auth;
if (config.outgoing.auth > 1)
{
outServer.username = username;
outServer.password = config.incoming.password;
if (config.rememberPassword && config.incoming.password.length)
rememberPassword(outServer, config.incoming.password);
}
if (outServer.authMethod == Ci.nsMsgAuthMethod.OAuth2) {
let pref = "mail.smtpserver." + outServer.key + ".";
Services.prefs.setCharPref(pref + "oauth2.scope",
config.oauthSettings.scope);
Services.prefs.setCharPref(pref + "oauth2.issuer",
config.oauthSettings.issuer);
}
if (config.outgoing.socketType == 1) // no SSL
outServer.socketType = Ci.nsMsgSocketType.plain;
else if (config.outgoing.socketType == 2) // SSL / TLS
outServer.socketType = Ci.nsMsgSocketType.SSL;
else if (config.outgoing.socketType == 3) // STARTTLS
outServer.socketType = Ci.nsMsgSocketType.alwaysSTARTTLS;
// API problem: <http://mxr.mozilla.org/seamonkey/source/mailnews/compose/public/nsISmtpServer.idl#93>
outServer.description = config.displayName;
if (config.password)
outServer.password = config.outgoing.password;
// If this is the first SMTP server, set it as default
if (!MailServices.smtp.defaultServer ||
!MailServices.smtp.defaultServer.hostname)
MailServices.smtp.defaultServer = outServer;
}
// identity
// TODO accounts without identity?
let identity = MailServices.accounts.createIdentity();
identity.fullName = config.identity.realname;
identity.email = config.identity.emailAddress;
// for new accounts, default to replies being positioned above the quote
// if a default account is defined already, take its settings instead
if (config.incoming.type == "imap" || config.incoming.type == "pop3")
{
identity.replyOnTop = 1;
// identity.sigBottom = false; // don't set this until Bug 218346 is fixed
if (MailServices.accounts.accounts.length &&
MailServices.accounts.defaultAccount)
{
let defAccount = MailServices.accounts.defaultAccount;
let defIdentity = defAccount.defaultIdentity;
if (defAccount.incomingServer.canBeDefaultServer &&
defIdentity && defIdentity.valid)
{
identity.replyOnTop = defIdentity.replyOnTop;
identity.sigBottom = defIdentity.sigBottom;
}
}
}
// due to accepted conventions, news accounts should default to plain text
if (config.incoming.type == "nntp")
identity.composeHtml = false;
identity.valid = true;
if (config.outgoing.existingServerKey)
identity.smtpServerKey = config.outgoing.existingServerKey;
else if (!config.outgoing.useGlobalPreferredServer)
identity.smtpServerKey = outServer.key;
// account and hook up
// Note: Setting incomingServer will cause the AccountManager to refresh
// itself, which could be a problem if we came from it and we haven't set
// the identity (see bug 521955), so make sure everything else on the
// account is set up before you set the incomingServer.
let account = MailServices.accounts.createAccount();
account.addIdentity(identity);
account.incomingServer = inServer;
if (inServer.canBeDefaultServer && (!MailServices.accounts.defaultAccount ||
!MailServices.accounts.defaultAccount
.incomingServer.canBeDefaultServer))
MailServices.accounts.defaultAccount = account;
verifyLocalFoldersAccount(MailServices.accounts);
setFolders(identity, inServer);
// save
MailServices.accounts.saveAccountInfo();
try {
Services.prefs.savePrefFile(null);
} catch (ex) {
ddump("Could not write out prefs: " + ex);
}
return account;
}
function setFolders(identity, server)
{
// TODO: support for local folders for global inbox (or use smart search
// folder instead)
var baseURI = server.serverURI + "/";
// Names will be localized in UI, not in folder names on server/disk
// TODO allow to override these names in the XML config file,
// in case e.g. Google or AOL use different names?
// Workaround: Let user fix it :)
var fccName = "Sent";
var draftName = "Drafts";
var templatesName = "Templates";
identity.draftFolder = baseURI + draftName;
identity.stationeryFolder = baseURI + templatesName;
identity.fccFolder = baseURI + fccName;
identity.fccFolderPickerMode = 0;
identity.draftsFolderPickerMode = 0;
identity.tmplFolderPickerMode = 0;
}
function rememberPassword(server, password)
{
if (server instanceof Components.interfaces.nsIMsgIncomingServer)
var passwordURI = server.localStoreType + "://" + server.hostName;
else if (server instanceof Components.interfaces.nsISmtpServer)
var passwordURI = "smtp://" + server.hostname;
else
throw new NotReached("Server type not supported");
let login = Cc["@mozilla.org/login-manager/loginInfo;1"]
.createInstance(Ci.nsILoginInfo);
login.init(passwordURI, null, passwordURI, server.username, password, "", "");
try {
Services.logins.addLogin(login);
} catch (e) {
if (e.message.includes("This login already exists")) {
// TODO modify
} else {
throw e;
}
}
}
/**
* Check whether the user's setup already has an incoming server
* which matches (hostname, port, username) the primary one
* in the config.
* (We also check the email address as username.)
*
* @param config {AccountConfig} filled in (no placeholders)
* @return {nsIMsgIncomingServer} If it already exists, the server
* object is returned.
* If it's a new server, |null| is returned.
*/
function checkIncomingServerAlreadyExists(config)
{
assert(config instanceof AccountConfig);
let incoming = config.incoming;
let existing = MailServices.accounts.findRealServer(incoming.username,
incoming.hostname,
sanitize.enum(incoming.type, ["pop3", "imap", "nntp"]),
incoming.port);
// if username does not have an '@', also check the e-mail
// address form of the name.
if (!existing && !incoming.username.includes("@"))
existing = MailServices.accounts.findRealServer(config.identity.emailAddress,
incoming.hostname,
sanitize.enum(incoming.type, ["pop3", "imap", "nntp"]),
incoming.port);
return existing;
};
/**
* Check whether the user's setup already has an outgoing server
* which matches (hostname, port, username) the primary one
* in the config.
*
* @param config {AccountConfig} filled in (no placeholders)
* @return {nsISmtpServer} If it already exists, the server
* object is returned.
* If it's a new server, |null| is returned.
*/
function checkOutgoingServerAlreadyExists(config)
{
assert(config instanceof AccountConfig);
let smtpServers = MailServices.smtp.servers;
while (smtpServers.hasMoreElements())
{
let existingServer = smtpServers.getNext()
.QueryInterface(Ci.nsISmtpServer);
// TODO check username with full email address, too, like for incoming
if (existingServer.hostname == config.outgoing.hostname &&
existingServer.port == config.outgoing.port &&
existingServer.username == config.outgoing.username)
return existingServer;
}
return null;
};
/**
* Check if there already is a "Local Folders". If not, create it.
* Copied from AccountWizard.js with minor updates.
*/
function verifyLocalFoldersAccount(am)
{
let localMailServer;
try {
localMailServer = am.localFoldersServer;
}
catch (ex) {
localMailServer = null;
}
try {
if (!localMailServer)
{
// creates a copy of the identity you pass in
am.createLocalMailAccount();
try {
localMailServer = am.localFoldersServer;
}
catch (ex) {
ddump("Error! we should have found the local mail server " +
"after we created it.");
}
}
}
catch (ex) { ddump("Error in verifyLocalFoldersAccount " + ex); }
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,493 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/accountCreation.css"
type="text/css"?>
<!DOCTYPE window [
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
<!ENTITY % acDTD SYSTEM "chrome://messenger/locale/accountCreation.dtd">
%acDTD;
]>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="autoconfigWizard"
windowtype="mail:autoconfig"
title="&autoconfigWizard.title;"
onload="gEmailConfigWizard.onLoad();"
onkeypress="gEmailConfigWizard.onKeyDown(event);"
onclose="gEmailConfigWizard.onWizardShutdown();"
onunload="gEmailConfigWizard.onWizardShutdown();"
>
<stringbundleset>
<stringbundle id="bundle_brand"
src="chrome://branding/locale/brand.properties"/>
<stringbundle id="strings"
src="chrome://messenger/locale/accountCreation.properties"/>
<stringbundle id="utilstrings"
src="chrome://messenger/locale/accountCreationUtil.properties"/>
<stringbundle id="bundle_messenger"
src="chrome://messenger/locale/messenger.properties"/>
</stringbundleset>
<script type="application/javascript"
src="chrome://messenger/content/accountcreation/util.js"/>
<script type="application/javascript"
src="chrome://messenger/content/accountcreation/accountConfig.js"/>
<script type="application/javascript"
src="chrome://messenger/content/accountcreation/emailWizard.js"/>
<script type="application/javascript"
src="chrome://messenger/content/accountcreation/sanitizeDatatypes.js"/>
<script type="application/javascript"
src="chrome://messenger/content/accountcreation/fetchhttp.js"/>
<script type="application/javascript"
src="chrome://messenger/content/accountcreation/readFromXML.js"/>
<script type="application/javascript"
src="chrome://messenger/content/accountcreation/guessConfig.js"/>
<script type="application/javascript"
src="chrome://messenger/content/accountcreation/verifyConfig.js"/>
<script type="application/javascript"
src="chrome://messenger/content/accountcreation/fetchConfig.js"/>
<script type="application/javascript"
src="chrome://messenger/content/accountcreation/createInBackend.js"/>
<script type="application/javascript"
src="chrome://messenger/content/accountcreation/MyBadCertHandler.js"/>
<script type="application/javascript"
src="chrome://messenger/content/accountUtils.js" />
<keyset id="mailKeys">
<key keycode="VK_ESCAPE" oncommand="window.close();"/>
</keyset>
<panel id="insecureserver-cleartext-panel" class="popup-panel">
<hbox>
<image class="insecureLarry"/>
<vbox flex="1">
<description class="title">&insecureServer.tooltip.title;</description>
<description class="details">
&insecureUnencrypted.description;</description>
</vbox>
</hbox>
</panel>
<panel id="insecureserver-selfsigned-panel" class="popup-panel">
<hbox>
<image class="insecureLarry"/>
<vbox flex="1">
<description class="title">&insecureServer.tooltip.title;</description>
<description class="details">
&insecureSelfSigned.description;</description>
</vbox>
</hbox>
</panel>
<panel id="secureserver-panel" class="popup-panel">
<hbox>
<image class="secureLarry"/>
<vbox flex="1">
<description class="title">&secureServer.description;</description>
</vbox>
</hbox>
</panel>
<tooltip id="insecureserver-cleartext">
<hbox>
<image class="insecureLarry"/>
<vbox>
<description class="title">&insecureServer.tooltip.title;</description>
<description class="details">
&insecureServer.tooltip.details;</description>
</vbox>
</hbox>
</tooltip>
<tooltip id="insecureserver-selfsigned">
<hbox>
<image class="insecureLarry"/>
<vbox>
<description class="title">&insecureServer.tooltip.title;</description>
<description class="details">
&insecureServer.tooltip.details;</description>
</vbox>
</hbox>
</tooltip>
<tooltip id="secureservertooltip">
<hbox>
<image class="secureLarry"/>
<description class="title">&secureServer.description;</description>
</hbox>
</tooltip>
<tooltip id="optional-password">
<description>&password.text;</description>
</tooltip>
<spacer id="fullwidth"/>
<vbox id="mastervbox" class="mastervbox" flex="1">
<grid id="initialSettings">
<columns>
<column/>
<column/>
<column/>
</columns>
<rows>
<row align="center">
<label accesskey="&name.accesskey;"
class="autoconfigLabel"
value="&name.label;"
control="realname"/>
<textbox id="realname"
class="padded"
placeholder="&name.placeholder;"
oninput="gEmailConfigWizard.onInputRealname();"
onblur="gEmailConfigWizard.onBlurRealname();"/>
<hbox>
<description id="nametext" class="initialDesc">&name.text;</description>
<image id="nameerroricon"
hidden="true"
class="warningicon"/>
<description id="nameerror" class="errordescription" hidden="true"/>
</hbox>
</row>
<row align="center">
<label accesskey="&email.accesskey;"
class="autoconfigLabel"
value="&email.label;"
control="email"/>
<textbox id="email"
class="padded uri-element"
placeholder="&email.placeholder;"
oninput="gEmailConfigWizard.onInputEmail();"
onblur="gEmailConfigWizard.onBlurEmail();"/>
<hbox>
<image id="emailerroricon"
hidden="true"
class="warningicon"/>
<description id="emailerror" class="errordescription" hidden="true"/>
</hbox>
</row>
<row align="center">
<!-- this starts out as text so the emptytext shows, but then
changes to type=password once it's not empty -->
<label accesskey="&password.accesskey;"
class="autoconfigLabel"
value="&password.label;"
control="password"
tooltip="optional-password"/>
<textbox id="password"
class="padded"
placeholder="&password.placeholder;"
type="text"
oninput="gEmailConfigWizard.onInputPassword();"
onfocus="gEmailConfigWizard.onFocusPassword();"
onblur="gEmailConfigWizard.onBlurPassword();"/>
<hbox>
<image id="passworderroricon"
hidden="true"
class="warningicon"/>
<description id="passworderror" class="errordescription" hidden="true"/>
</hbox>
</row>
<row align="center" pack="start">
<label class="autoconfigLabel"/>
<checkbox id="remember_password"
label="&rememberPassword.label;"
accesskey="&rememberPassword.accesskey;"
checked="true"/>
</row>
</rows>
</grid>
<spacer flex="1" />
<hbox id="status_area" flex="1">
<vbox id="status_img_before" pack="start"/>
<description id="status_msg">&#160;</description>
<!-- Include 160 = nbsp, to make the element occupy the
full height, for at least one line. With a normal space,
it does not have sufficient height. -->
<vbox id="status_img_after" pack="start"/>
</hbox>
<groupbox id="result_area" hidden="true">
<radiogroup id="result_imappop" orient="horizontal">
<radio id="result_select_imap" label="&imapLong.label;" value="1"
oncommand="gEmailConfigWizard.onResultIMAPOrPOP3();"/>
<radio id="result_select_pop3" label="&pop3Long.label;" value="2"
oncommand="gEmailConfigWizard.onResultIMAPOrPOP3();"/>
</radiogroup>
<grid>
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<label class="textbox-label" value="&incoming.label;"
control="result-incoming"/>
<textbox id="result-incoming" disabled="true" flex="1"/>
</row>
<row align="center">
<label class="textbox-label" value="&outgoing.label;"
control="result-outgoing"/>
<textbox id="result-outgoing" disabled="true" flex="1"/>
</row>
<row align="center">
<label class="textbox-label" value="&username.label;"
control="result-username"/>
<textbox id="result-username" disabled="true" flex="1"/>
</row>
</rows>
</grid>
</groupbox>
<groupbox id="manual-edit_area" hidden="true">
<grid>
<columns>
<column/><!-- row label, e.g. "incoming" -->
<column/><!-- protocol, e.g. "IMAP" -->
<column flex="1"/><!-- hostname / username -->
<column/><!-- port -->
<column/><!-- SSL -->
<column/><!-- auth method -->
</columns>
<rows>
<row id="labels_row" align="center">
<spacer/>
<spacer/>
<label value="&hostname.label;" class="columnHeader"/>
<label value="&port.label;" class="columnHeader"/>
<label value="&ssl.label;" class="columnHeader"/>
<label value="&auth.label;" class="columnHeader"/>
</row>
<row id="incoming_server_area">
<hbox align="center" pack="end">
<label class="textbox-label"
value="&incoming.label;"
control="incoming_hostname"/>
</hbox>
<menulist id="incoming_protocol"
oncommand="gEmailConfigWizard.onChangedProtocolIncoming();"
sizetopopup="always">
<menupopup>
<menuitem label="&imap.label;" value="1"/>
<menuitem label="&pop3.label;" value="2"/>
</menupopup>
</menulist>
<textbox id="incoming_hostname"
oninput="gEmailConfigWizard.onInputHostname();"
class="host uri-element"/>
<menulist id="incoming_port"
editable="true"
oninput="gEmailConfigWizard.onChangedPortIncoming();"
oncommand="gEmailConfigWizard.onChangedPortIncoming();"
class="port">
<menupopup/>
</menulist>
<menulist id="incoming_ssl"
class="security"
oncommand="gEmailConfigWizard.onChangedSSLIncoming();"
sizetopopup="always">
<menupopup>
<!-- values defined in nsMsgSocketType -->
<menuitem label="&autodetect.label;" value="0"/>
<menuitem label="&noEncryption.label;" value="1"/>
<menuitem label="&starttls.label;" value="3"/>
<menuitem label="&sslTls.label;" value="2"/>
</menupopup>
</menulist>
<menulist id="incoming_authMethod"
class="auth"
oncommand="gEmailConfigWizard.onChangedInAuth();"
sizetopopup="always">
<menupopup>
<menuitem label="&autodetect.label;" value="0"/>
<!-- values defined in nsMsgAuthMethod -->
<!-- labels set from messenger.properties
to avoid duplication -->
<menuitem id="in-authMethod-password-cleartext" value="3"/>
<menuitem id="in-authMethod-password-encrypted" value="4"/>
<menuitem id="in-authMethod-kerberos" value="5"/>
<menuitem id="in-authMethod-ntlm" value="6"/>
<menuitem id="in-authMethod-oauth2" value="10" hidden="true"/>
</menupopup>
</menulist>
</row>
<row id="outgoing_server_area" align="center">
<label class="textbox-label"
value="&outgoing.label;"
control="outgoing_hostname"/>
<label id="outgoing_protocol"
value="&smtp.label;"/>
<menulist id="outgoing_hostname"
editable="true"
sizetopopup="none"
oninput="gEmailConfigWizard.onInputHostname();"
oncommand="gEmailConfigWizard.onChangedOutgoingDropdown();"
onpopupshowing="gEmailConfigWizard.onOpenOutgoingDropdown();"
class="host uri-element">
<menupopup id="outgoing_hostname_popup"/>
</menulist>
<menulist id="outgoing_port"
editable="true"
oninput="gEmailConfigWizard.onChangedPortOutgoing();"
oncommand="gEmailConfigWizard.onChangedPortOutgoing();"
class="port">
<menupopup/>
</menulist>
<menulist id="outgoing_ssl"
class="security"
oncommand="gEmailConfigWizard.onChangedSSLOutgoing();"
sizetopopup="always">
<menupopup>
<!-- @see incoming -->
<menuitem label="&autodetect.label;" value="0"/>
<menuitem label="&noEncryption.label;" value="1"/>
<menuitem label="&starttls.label;" value="3"/>
<menuitem label="&sslTls.label;" value="2"/>
</menupopup>
</menulist>
<menulist id="outgoing_authMethod"
class="auth"
oncommand="gEmailConfigWizard.onChangedOutAuth(this.selectedItem);"
sizetopopup="always">
<menupopup>
<menuitem label="&autodetect.label;" value="0"/>
<!-- @see incoming -->
<menuitem id="out-authMethod-no" value="1"/>
<menuitem id="out-authMethod-password-cleartext" value="3"/>
<menuitem id="out-authMethod-password-encrypted" value="4"/>
<menuitem id="out-authMethod-kerberos" value="5"/>
<menuitem id="out-authMethod-ntlm" value="6"/>
<menuitem id="out-authMethod-oauth2" value="10" hidden="true"/>
</menupopup>
</menulist>
</row>
<row id="username_area" align="center">
<label class="textbox-label"
value="&username.label;"/>
<label class="columnHeader"
value="&incoming.label;"
control="incoming_username"/>
<textbox id="incoming_username"
oninput="gEmailConfigWizard.onInputInUsername();"
class="username"/>
<spacer/>
<label class="columnHeader"
id="outgoing_label"
value="&outgoing.label;"
control="outgoing_username"/>
<textbox id="outgoing_username"
oninput="gEmailConfigWizard.onInputOutUsername();"
class="username"/>
</row>
</rows>
</grid>
</groupbox>
<spacer flex="1" />
<hbox id="buttons_area">
<hbox id="left_buttons_area" align="center" pack="start">
<button id="provisioner_button"
label="&switch-to-provisioner.label;"
accesskey="&switch-to-provisioner.accesskey;"
class="larger-button"
oncommand="gEmailConfigWizard.onSwitchToProvisioner();"/>
<button id="manual-edit_button"
label="&manual-edit.label;"
accesskey="&manual-edit.accesskey;"
hidden="true"
oncommand="gEmailConfigWizard.onManualEdit();"/>
<button id="advanced-setup_button"
label="&advancedSetup.label;"
accesskey="&advancedSetup.accesskey;"
disabled="true"
hidden="true"
oncommand="gEmailConfigWizard.onAdvancedSetup();"/>
</hbox>
<spacer flex="1"/>
<hbox id="right_buttons_area" align="center" pack="end">
<button id="stop_button"
label="&stop.label;"
accesskey="&stop.accesskey;"
hidden="true"
oncommand="gEmailConfigWizard.onStop();"/>
<button id="cancel_button"
label="&cancel.label;"
accesskey="&cancel.accesskey;"
oncommand="gEmailConfigWizard.onCancel();"/>
<button id="half-manual-test_button"
label="&half-manual-test.label;"
accesskey="&half-manual-test.accesskey;"
hidden="true"
oncommand="gEmailConfigWizard.onHalfManualTest();"/>
<button id="next_button"
label="&continue.label;"
accesskey="&continue.accesskey;"
hidden="false"
oncommand="gEmailConfigWizard.onNext();"/>
<button id="create_button"
label="&doneAccount.label;"
accesskey="&doneAccount.accesskey;"
class="important-button"
hidden="true"
oncommand="gEmailConfigWizard.onCreate();"/>
</hbox>
</hbox>
</vbox>
<vbox id="warningbox" hidden="true" flex="1">
<hbox class="warning" flex="1">
<vbox class="larrybox">
<image id="insecure_larry" class="insecureLarry"/>
</vbox>
<vbox flex="1" class="warning_text">
<label class="warning-heading">&warning.label;</label>
<vbox id="incoming_box">
<hbox>
<label class="warning_settings" value="&incomingSettings.label;"/>
<description id="warning_incoming"/>
</hbox>
<label id="incoming_technical"
class="technical_details"
value="&technicaldetails.label;"
onclick="gSecurityWarningDialog.toggleDetails('incoming');"/>
<description id="incoming_details" collapsed="true"/>
</vbox>
<vbox id="outgoing_box">
<hbox>
<label class="warning_settings" value="&outgoingSettings.label;"/>
<description id="warning_outgoing"/>
</hbox>
<label id="outgoing_technical"
class="technical_details"
value="&technicaldetails.label;"
onclick="gSecurityWarningDialog.toggleDetails('outgoing');"/>
<description id="outgoing_details" collapsed="true"/>
</vbox>
<spacer flex="10"/>
<description id="findoutmore">
&contactYourProvider.description;</description>
<spacer flex="100"/>
<checkbox id="acknowledge_warning"
label="&confirmWarning.label;"
accesskey="&confirmWarning.accesskey;"
class="acknowledge_checkbox"
oncommand="gSecurityWarningDialog.toggleAcknowledge()"/>
<hbox>
<button id="getmeoutofhere"
label="&changeSettings.label;"
accesskey="&changeSettings.accesskey;"
oncommand="gSecurityWarningDialog.onCancel()"/>
<spacer flex="1"/>
<button id="iknow"
label="&doneAccount.label;"
accesskey="&doneAccount.accesskey;"
disabled="true"
oncommand="gSecurityWarningDialog.onOK()"/>
</hbox>
</vbox>
</hbox>
</vbox>
</window>

View file

@ -0,0 +1,240 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/**
* Tries to find a configuration for this ISP on the local harddisk, in the
* application install directory's "isp" subdirectory.
* Params @see fetchConfigFromISP()
*/
Components.utils.import("resource:///modules/mailServices.js");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/JXON.js");
function fetchConfigFromDisk(domain, successCallback, errorCallback)
{
return new TimeoutAbortable(runAsync(function()
{
try {
// <TB installdir>/isp/example.com.xml
var configLocation = Services.dirsvc.get("CurProcD", Ci.nsIFile);
configLocation.append("isp");
configLocation.append(sanitize.hostname(domain) + ".xml");
var contents =
readURLasUTF8(Services.io.newFileURI(configLocation));
let domParser = Cc["@mozilla.org/xmlextras/domparser;1"]
.createInstance(Ci.nsIDOMParser);
successCallback(readFromXML(JXON.build(
domParser.parseFromString(contents, "text/xml"))));
} catch (e) { errorCallback(e); }
}));
}
/**
* Tries to get a configuration from the ISP / mail provider directly.
*
* Disclaimers:
* - To support domain hosters, we cannot use SSL. That means we
* rely on insecure DNS and http, which means the results may be
* forged when under attack. The same is true for guessConfig(), though.
*
* @param domain {String} The domain part of the user's email address
* @param emailAddress {String} The user's email address
* @param successCallback {Function(config {AccountConfig}})} A callback that
* will be called when we could retrieve a configuration.
* The AccountConfig object will be passed in as first parameter.
* @param errorCallback {Function(ex)} A callback that
* will be called when we could not retrieve a configuration,
* for whatever reason. This is expected (e.g. when there's no config
* for this domain at this location),
* so do not unconditionally show this to the user.
* The first paramter will be an exception object or error string.
*/
function fetchConfigFromISP(domain, emailAddress, successCallback,
errorCallback)
{
if (!Services.prefs.getBoolPref(
"mailnews.auto_config.fetchFromISP.enabled")) {
errorCallback("ISP fetch disabled per user preference");
return;
}
let url1 = "http://autoconfig." + sanitize.hostname(domain) +
"/mail/config-v1.1.xml";
// .well-known/ <http://tools.ietf.org/html/draft-nottingham-site-meta-04>
let url2 = "http://" + sanitize.hostname(domain) +
"/.well-known/autoconfig/mail/config-v1.1.xml";
let sucAbortable = new SuccessiveAbortable();
var time = Date.now();
var urlArgs = { emailaddress: emailAddress };
if (!Services.prefs.getBoolPref(
"mailnews.auto_config.fetchFromISP.sendEmailAddress")) {
delete urlArgs.emailaddress;
}
let fetch1 = new FetchHTTP(url1, urlArgs, false,
function(result)
{
successCallback(readFromXML(result));
},
function(e1) // fetch1 failed
{
ddump("fetchisp 1 <" + url1 + "> took " + (Date.now() - time) +
"ms and failed with " + e1);
time = Date.now();
if (e1 instanceof CancelledException)
{
errorCallback(e1);
return;
}
let fetch2 = new FetchHTTP(url2, urlArgs, false,
function(result)
{
successCallback(readFromXML(result));
},
function(e2)
{
ddump("fetchisp 2 <" + url2 + "> took " + (Date.now() - time) +
"ms and failed with " + e2);
// return the error for the primary call,
// unless the fetch was cancelled
errorCallback(e2 instanceof CancelledException ? e2 : e1);
});
sucAbortable.current = fetch2;
fetch2.start();
});
sucAbortable.current = fetch1;
fetch1.start();
return sucAbortable;
}
/**
* Tries to get a configuration for this ISP from a central database at
* Mozilla servers.
* Params @see fetchConfigFromISP()
*/
function fetchConfigFromDB(domain, successCallback, errorCallback)
{
let url = Services.prefs.getCharPref("mailnews.auto_config_url");
domain = sanitize.hostname(domain);
// If we don't specify a place to put the domain, put it at the end.
if (!url.includes("{{domain}}"))
url = url + domain;
else
url = url.replace("{{domain}}", domain);
url = url.replace("{{accounts}}", MailServices.accounts.accounts.length);
if (!url.length)
return errorCallback("no fetch url set");
let fetch = new FetchHTTP(url, null, false,
function(result)
{
successCallback(readFromXML(result));
},
errorCallback);
fetch.start();
return fetch;
}
/**
* Does a lookup of DNS MX, to get the server who is responsible for
* recieving mail for this domain. Then it takes the domain of that
* server, and does another lookup (in ISPDB and possible at ISP autoconfig
* server) and if such a config is found, returns that.
*
* Disclaimers:
* - DNS is unprotected, meaning the results could be forged.
* The same is true for fetchConfigFromISP() and guessConfig(), though.
* - DNS MX tells us the incoming server, not the mailbox (IMAP) server.
* They are different. This mechnism is only an approximation
* for hosted domains (yourname.com is served by mx.hoster.com and
* therefore imap.hoster.com - that "therefore" is exactly the
* conclusional jump we make here.) and alternative domains
* (e.g. yahoo.de -> yahoo.com).
* - We make a look up for the base domain. E.g. if MX is
* mx1.incoming.servers.hoster.com, we look up hoster.com.
* Thanks to Services.eTLD, we also get bbc.co.uk right.
*
* Params @see fetchConfigFromISP()
*/
function fetchConfigForMX(domain, successCallback, errorCallback)
{
domain = sanitize.hostname(domain);
var sucAbortable = new SuccessiveAbortable();
var time = Date.now();
sucAbortable.current = getMX(domain,
function(mxHostname) // success
{
ddump("getmx took " + (Date.now() - time) + "ms");
let sld = Services.eTLD.getBaseDomainFromHost(mxHostname);
ddump("base domain " + sld + " for " + mxHostname);
if (sld == domain)
{
errorCallback("MX lookup would be no different from domain");
return;
}
sucAbortable.current = fetchConfigFromDB(sld, successCallback,
errorCallback);
},
errorCallback);
return sucAbortable;
}
/**
* Queries the DNS MX for the domain
*
* The current implementation goes to a web service to do the
* DNS resolve for us, because Mozilla unfortunately has no implementation
* to do it. That's just a workaround. Once bug 545866 is fixed, we make
* the DNS query directly on the client. The API of this function should not
* change then.
*
* Returns (in successCallback) the hostname of the MX server.
* If there are several entires with different preference values,
* only the most preferred (i.e. those with the lowest value)
* is returned. If there are several most preferred servers (i.e.
* round robin), only one of them is returned.
*
* @param domain @see fetchConfigFromISP()
* @param successCallback {function(hostname {String})
* Called when we found an MX for the domain.
* For |hostname|, see description above.
* @param errorCallback @see fetchConfigFromISP()
* @returns @see fetchConfigFromISP()
*/
function getMX(domain, successCallback, errorCallback)
{
domain = sanitize.hostname(domain);
let url = Services.prefs.getCharPref("mailnews.mx_service_url");
if (!url)
errorCallback("no URL for MX service configured");
url += domain;
let fetch = new FetchHTTP(url, null, false,
function(result)
{
// result is plain text, with one line per server.
// So just take the first line
ddump("MX query result: \n" + result + "(end)");
assert(typeof(result) == "string");
let first = result.split("\n")[0];
first.toLowerCase().replace(/[^a-z0-9\-_\.]*/g, "");
if (first.length == 0)
{
errorCallback("no MX found");
return;
}
successCallback(first);
},
errorCallback);
fetch.start();
return fetch;
}

View file

@ -0,0 +1,267 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/**
* This is a small wrapper around XMLHttpRequest, which solves various
* inadequacies of the API, e.g. error handling. It is entirely generic and
* can be used for purposes outside of even mail.
*
* It does not provide download progress, but assumes that the
* fetched resource is so small (<1 10 KB) that the roundtrip and
* response generation is far more significant than the
* download time of the response. In other words, it's fine for RPC,
* but not for bigger file downloads.
*/
Components.utils.import("resource://gre/modules/JXON.js");
/**
* Set up a fetch.
*
* @param url {String} URL of the server function.
* ATTENTION: The caller needs to make sure that the URL is secure to call.
* @param urlArgs {Object, associative array} Parameters to add
* to the end of the URL as query string. E.g.
* { foo: "bla", bar: "blub blub" } will add "?foo=bla&bar=blub%20blub"
* to the URL
* (unless the URL already has a "?", then it adds "&foo...").
* The values will be urlComponentEncoded, so pass them unencoded.
* @param post {Boolean} HTTP GET or POST
* Only influences the HTTP request method,
* i.e. first line of the HTTP request, not the body or parameters.
* Use POST when you modify server state,
* GET when you only request information.
*
* @param successCallback {Function(result {String})}
* Called when the server call worked (no errors).
* |result| will contain the body of the HTTP reponse, as string.
* @param errorCallback {Function(ex)}
* Called in case of error. ex contains the error
* with a user-displayable but not localized |.message| and maybe a
* |.code|, which can be either
* - an nsresult error code,
* - an HTTP result error code (0...1000) or
* - negative: 0...-100 :
* -2 = can't resolve server in DNS etc.
* -4 = response body (e.g. XML) malformed
*/
/* not yet supported:
* @param headers {Object, associative array} Like urlArgs,
* just that the params will be added as HTTP headers.
* { foo: "blub blub" } will add "Foo: Blub blub"
* The values will be urlComponentEncoded, apart from space,
* so pass them unencoded.
* @param headerArgs {Object, associative array} Like urlArgs,
* just that the params will be added as HTTP headers.
* { foo: "blub blub" } will add "X-Moz-Arg-Foo: Blub blub"
* The values will be urlComponentEncoded, apart from space,
* so pass them unencoded.
* @param bodyArgs {Object, associative array} Like urlArgs,
* just that the params will be sent x-url-encoded in the body,
* like a HTML form post.
* The values will be urlComponentEncoded, so pass them unencoded.
* This cannot be used together with |uploadBody|.
* @param uploadbody {Object} Arbitrary object, which to use as
* body of the HTTP request. Will also set the mimetype accordingly.
* Only supported object types, currently only E4X is supported
* (sending XML).
* Usually, you have nothing to upload, so just pass |null|.
*/
function FetchHTTP(url, urlArgs, post, successCallback, errorCallback)
{
assert(typeof(successCallback) == "function", "BUG: successCallback");
assert(typeof(errorCallback) == "function", "BUG: errorCallback");
this._url = sanitize.string(url);
if (!urlArgs)
urlArgs = {};
this._urlArgs = urlArgs;
this._post = sanitize.boolean(post);
this._successCallback = successCallback;
this._errorCallback = errorCallback;
}
FetchHTTP.prototype =
{
__proto__: Abortable.prototype,
_url : null, // URL as passed to ctor, without arguments
_urlArgs : null,
_post : null,
_successCallback : null,
_errorCallback : null,
_request : null, // the XMLHttpRequest object
result : null,
start : function()
{
var url = this._url;
for (var name in this._urlArgs)
{
url += (!url.includes("?") ? "?" : "&") +
name + "=" + encodeURIComponent(this._urlArgs[name]);
}
this._request = new XMLHttpRequest();
let request = this._request;
request.open(this._post ? "POST" : "GET", url);
request.channel.loadGroup = null;
// needs bug 407190 patch v4 (or higher) - uncomment if that lands.
// try {
// var channel = request.channel.QueryInterface(Ci.nsIHttpChannel2);
// channel.connectTimeout = 5;
// channel.requestTimeout = 5;
// } catch (e) { dump(e + "\n"); }
var me = this;
request.onload = function() { me._response(true); }
request.onerror = function() { me._response(false); }
request.send(null);
},
_response : function(success, exStored)
{
try
{
var errorCode = null;
var errorStr = null;
if (success && this._request.status >= 200 &&
this._request.status < 300) // HTTP level success
{
try
{
// response
var mimetype = this._request.getResponseHeader("Content-Type");
if (!mimetype)
mimetype = "";
mimetype = mimetype.split(";")[0];
if (mimetype == "text/xml" ||
mimetype == "application/xml" ||
mimetype == "text/rdf")
{
this.result = JXON.build(this._request.responseXML);
}
else
{
//ddump("mimetype: " + mimetype + " only supported as text");
this.result = this._request.responseText;
}
//ddump("result:\n" + this.result);
}
catch (e)
{
success = false;
errorStr = getStringBundle(
"chrome://messenger/locale/accountCreationUtil.properties")
.GetStringFromName("bad_response_content.error");
errorCode = -4;
}
}
else
{
success = false;
try
{
errorCode = this._request.status;
errorStr = this._request.statusText;
} catch (e) {
// If we can't resolve the hostname in DNS etc., .statusText throws
errorCode = -2;
errorStr = getStringBundle(
"chrome://messenger/locale/accountCreationUtil.properties")
.GetStringFromName("cannot_contact_server.error");
ddump(errorStr);
}
}
// Callbacks
if (success)
{
try {
this._successCallback(this.result);
} catch (e) {
logException(e);
this._error(e);
}
}
else if (exStored)
this._error(exStored);
else
this._error(new ServerException(errorStr, errorCode, this._url));
if (this._finishedCallback)
{
try {
this._finishedCallback(this);
} catch (e) {
logException(e);
this._error(e);
}
}
} catch (e) {
// error in our fetchhttp._response() code
logException(e);
this._error(e);
}
},
_error : function(e)
{
try {
this._errorCallback(e);
} catch (e) {
// error in errorCallback, too!
logException(e);
alertPrompt("Error in errorCallback for fetchhttp", e);
}
},
/**
* Call this between start() and finishedCallback fired.
*/
cancel : function(ex)
{
assert(!this.result, "Call already returned");
this._request.abort();
// Need to manually call error handler
// <https://bugzilla.mozilla.org/show_bug.cgi?id=218236#c11>
this._response(false, ex ? ex : new UserCancelledException());
},
/**
* Allows caller or lib to be notified when the call is done.
* This is useful to enable and disable a Cancel button in the UI,
* which allows to cancel the network request.
*/
setFinishedCallback : function(finishedCallback)
{
this._finishedCallback = finishedCallback;
}
}
function CancelledException(msg)
{
Exception.call(this, msg);
}
CancelledException.prototype = Object.create(Exception.prototype);
CancelledException.prototype.constructor = CancelledException;
function UserCancelledException(msg)
{
// The user knows they cancelled so I don't see a need
// for a message to that effect.
if (!msg)
msg = "User cancelled";
CancelledException.call(this, msg);
}
UserCancelledException.prototype = Object.create(CancelledException.prototype);
UserCancelledException.prototype.constructor = UserCancelledException;
function ServerException(msg, code, uri)
{
Exception.call(this, msg);
this.code = code;
this.uri = uri;
}
ServerException.prototype = Object.create(Exception.prototype);
ServerException.prototype.constructor = ServerException;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,238 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/**
* Takes an XML snipplet (as JXON) and reads the values into
* a new AccountConfig object.
* It does so securely (or tries to), by trying to avoid remote execution
* and similar holes which can appear when reading too naively.
* Of course it cannot tell whether the actual values are correct,
* e.g. it can't tell whether the host name is a good server.
*
* The XML format is documented at
* <https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat>
*
* @param clientConfigXML {JXON} The <clientConfig> node.
* @return AccountConfig object filled with the data from XML
*/
Components.utils.import("resource:///modules/hostnameUtils.jsm");
function readFromXML(clientConfigXML)
{
function array_or_undef(value) {
return value === undefined ? [] : value;
}
var exception;
if (typeof(clientConfigXML) != "object" ||
!("clientConfig" in clientConfigXML) ||
!("emailProvider" in clientConfigXML.clientConfig))
{
dump("client config xml = " + JSON.stringify(clientConfigXML) + "\n");
var stringBundle = getStringBundle(
"chrome://messenger/locale/accountCreationModel.properties");
throw stringBundle.GetStringFromName("no_emailProvider.error");
}
var xml = clientConfigXML.clientConfig.emailProvider;
var d = new AccountConfig();
d.source = AccountConfig.kSourceXML;
d.id = sanitize.hostname(xml["@id"]);
d.displayName = d.id;
try {
d.displayName = sanitize.label(xml.displayName);
} catch (e) { logException(e); }
for (var domain of xml.$domain)
{
try {
d.domains.push(sanitize.hostname(domain));
} catch (e) { logException(e); exception = e; }
}
if (d.domains.length == 0)
throw exception ? exception : "need proper <domain> in XML";
exception = null;
// incoming server
for (let iX of array_or_undef(xml.$incomingServer)) // input (XML)
{
let iO = d.createNewIncoming(); // output (object)
try {
// throws if not supported
iO.type = sanitize.enum(iX["@type"], ["pop3", "imap", "nntp"]);
iO.hostname = sanitize.hostname(iX.hostname);
iO.port = sanitize.integerRange(iX.port, kMinPort, kMaxPort);
// We need a username even for Kerberos, need it even internally.
iO.username = sanitize.string(iX.username); // may be a %VARIABLE%
if ("password" in iX) {
d.rememberPassword = true;
iO.password = sanitize.string(iX.password);
}
for (let iXsocketType of array_or_undef(iX.$socketType))
{
try {
iO.socketType = sanitize.translate(iXsocketType,
{ plain : 1, SSL: 2, STARTTLS: 3 });
break; // take first that we support
} catch (e) { exception = e; }
}
if (!iO.socketType)
throw exception ? exception : "need proper <socketType> in XML";
exception = null;
for (let iXauth of array_or_undef(iX.$authentication))
{
try {
iO.auth = sanitize.translate(iXauth,
{ "password-cleartext" : Ci.nsMsgAuthMethod.passwordCleartext,
// @deprecated TODO remove
"plain" : Ci.nsMsgAuthMethod.passwordCleartext,
"password-encrypted" : Ci.nsMsgAuthMethod.passwordEncrypted,
// @deprecated TODO remove
"secure" : Ci.nsMsgAuthMethod.passwordEncrypted,
"GSSAPI" : Ci.nsMsgAuthMethod.GSSAPI,
"NTLM" : Ci.nsMsgAuthMethod.NTLM,
"OAuth2" : Ci.nsMsgAuthMethod.OAuth2 });
break; // take first that we support
} catch (e) { exception = e; }
}
if (!iO.auth)
throw exception ? exception : "need proper <authentication> in XML";
exception = null;
// defaults are in accountConfig.js
if (iO.type == "pop3" && "pop3" in iX)
{
try {
if ("leaveMessagesOnServer" in iX.pop3)
iO.leaveMessagesOnServer =
sanitize.boolean(iX.pop3.leaveMessagesOnServer);
if ("daysToLeaveMessagesOnServer" in iX.pop3)
iO.daysToLeaveMessagesOnServer =
sanitize.integer(iX.pop3.daysToLeaveMessagesOnServer);
} catch (e) { logException(e); }
try {
if ("downloadOnBiff" in iX.pop3)
iO.downloadOnBiff = sanitize.boolean(iX.pop3.downloadOnBiff);
} catch (e) { logException(e); }
}
// processed successfully, now add to result object
if (!d.incoming.hostname) // first valid
d.incoming = iO;
else
d.incomingAlternatives.push(iO);
} catch (e) { exception = e; }
}
if (!d.incoming.hostname)
// throw exception for last server
throw exception ? exception : "Need proper <incomingServer> in XML file";
exception = null;
// outgoing server
for (let oX of array_or_undef(xml.$outgoingServer)) // input (XML)
{
let oO = d.createNewOutgoing(); // output (object)
try {
if (oX["@type"] != "smtp")
{
var stringBundle = getStringBundle(
"chrome://messenger/locale/accountCreationModel.properties");
throw stringBundle.GetStringFromName("outgoing_not_smtp.error");
}
oO.hostname = sanitize.hostname(oX.hostname);
oO.port = sanitize.integerRange(oX.port, kMinPort, kMaxPort);
for (let oXsocketType of array_or_undef(oX.$socketType))
{
try {
oO.socketType = sanitize.translate(oXsocketType,
{ plain : 1, SSL: 2, STARTTLS: 3 });
break; // take first that we support
} catch (e) { exception = e; }
}
if (!oO.socketType)
throw exception ? exception : "need proper <socketType> in XML";
exception = null;
for (let oXauth of array_or_undef(oX.$authentication))
{
try {
oO.auth = sanitize.translate(oXauth,
{ // open relay
"none" : Ci.nsMsgAuthMethod.none,
// inside ISP or corp network
"client-IP-address" : Ci.nsMsgAuthMethod.none,
// hope for the best
"smtp-after-pop" : Ci.nsMsgAuthMethod.none,
"password-cleartext" : Ci.nsMsgAuthMethod.passwordCleartext,
// @deprecated TODO remove
"plain" : Ci.nsMsgAuthMethod.passwordCleartext,
"password-encrypted" : Ci.nsMsgAuthMethod.passwordEncrypted,
// @deprecated TODO remove
"secure" : Ci.nsMsgAuthMethod.passwordEncrypted,
"GSSAPI" : Ci.nsMsgAuthMethod.GSSAPI,
"NTLM" : Ci.nsMsgAuthMethod.NTLM,
"OAuth2" : Ci.nsMsgAuthMethod.OAuth2,
});
break; // take first that we support
} catch (e) { exception = e; }
}
if (!oO.auth)
throw exception ? exception : "need proper <authentication> in XML";
exception = null;
if ("username" in oX ||
// if password-based auth, we need a username,
// so go there anyways and throw.
oO.auth == Ci.nsMsgAuthMethod.passwordCleartext ||
oO.auth == Ci.nsMsgAuthMethod.passwordEncrypted)
oO.username = sanitize.string(oX.username);
if ("password" in oX) {
d.rememberPassword = true;
oO.password = sanitize.string(oX.password);
}
try {
// defaults are in accountConfig.js
if ("addThisServer" in oX)
oO.addThisServer = sanitize.boolean(oX.addThisServer);
if ("useGlobalPreferredServer" in oX)
oO.useGlobalPreferredServer =
sanitize.boolean(oX.useGlobalPreferredServer);
} catch (e) { logException(e); }
// processed successfully, now add to result object
if (!d.outgoing.hostname) // first valid
d.outgoing = oO;
else
d.outgoingAlternatives.push(oO);
} catch (e) { logException(e); exception = e; }
}
if (!d.outgoing.hostname)
// throw exception for last server
throw exception ? exception : "Need proper <outgoingServer> in XML file";
exception = null;
d.inputFields = new Array();
for (let inputField of array_or_undef(xml.$inputField))
{
try {
var fieldset =
{
varname : sanitize.alphanumdash(inputField["@key"]).toUpperCase(),
displayName : sanitize.label(inputField["@label"]),
exampleValue : sanitize.label(inputField.value)
};
d.inputFields.push(fieldset);
} catch (e) { logException(e); } // for now, don't throw,
// because we don't support custom fields yet anyways.
}
return d;
}

View file

@ -0,0 +1,207 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/**
* This is a generic input validation lib. Use it when you process
* data from the network.
*
* Just a few functions which verify, for security purposes, that the
* input variables (strings, if nothing else is noted) are of the expected
* type and syntax.
*
* The functions take a string (unless noted otherwise) and return
* the expected datatype in JS types. If the value is not as expected,
* they throw exceptions.
*/
Components.utils.import("resource:///modules/hostnameUtils.jsm");
var sanitize =
{
integer : function(unchecked)
{
if (typeof(unchecked) == "number" && !isNaN(unchecked))
return unchecked;
var r = parseInt(unchecked);
if (isNaN(r))
throw new MalformedException("no_number.error", unchecked);
return r;
},
integerRange : function(unchecked, min, max)
{
var int = this.integer(unchecked);
if (int < min)
throw new MalformedException("number_too_small.error", unchecked);
if (int > max)
throw new MalformedException("number_too_large.error", unchecked);
return int;
},
boolean : function(unchecked)
{
if (typeof(unchecked) == "boolean")
return unchecked;
if (unchecked == "true")
return true;
if (unchecked == "false")
return false;
throw new MalformedException("boolean.error", unchecked);
},
string : function(unchecked)
{
return String(unchecked);
},
nonemptystring : function(unchecked)
{
if (!unchecked)
throw new MalformedException("string_empty.error", unchecked);
return this.string(unchecked);
},
/**
* Allow only letters, numbers, "-" and "_".
*
* Empty strings not allowed (good idea?).
*/
alphanumdash : function(unchecked)
{
var str = this.nonemptystring(unchecked);
if (!/^[a-zA-Z0-9\-\_]*$/.test(str))
throw new MalformedException("alphanumdash.error", unchecked);
return str;
},
/**
* DNS hostnames like foo.bar.example.com
* Allow only letters, numbers, "-" and "."
* Empty strings not allowed.
* Currently does not support IDN (international domain names).
*/
hostname : function(unchecked)
{
let str = cleanUpHostName(this.nonemptystring(unchecked));
// Allow placeholders. TODO move to a new hostnameOrPlaceholder()
// The regex is "anything, followed by one or more (placeholders than
// anything)". This doesn't catch the non-placeholder case, but that's
// handled down below.
if (/^[a-zA-Z0-9\-\.]*(%[A-Z0-9]+%[a-zA-Z0-9\-\.]*)+$/.test(str))
return str;
if (!isLegalHostNameOrIP(str))
throw new MalformedException("hostname_syntax.error", unchecked);
return str.toLowerCase();
},
/**
* A non-chrome URL that's safe to request.
*/
url : function (unchecked)
{
var str = this.string(unchecked);
if (!str.startsWith("http") && !str.startsWith("https"))
throw new MalformedException("url_scheme.error", unchecked);
var uri;
try {
uri = Services.io.newURI(str, null, null);
uri = uri.QueryInterface(Ci.nsIURL);
} catch (e) {
throw new MalformedException("url_parsing.error", unchecked);
}
if (uri.scheme != "http" && uri.scheme != "https")
throw new MalformedException("url_scheme.error", unchecked);
return uri.spec;
},
/**
* A value which should be shown to the user in the UI as label
*/
label : function(unchecked)
{
return this.string(unchecked);
},
/**
* Allows only certain values as input, otherwise throw.
*
* @param unchecked {Any} The value to check
* @param allowedValues {Array} List of values that |unchecked| may have.
* @param defaultValue {Any} (Optional) If |unchecked| does not match
* anything in |mapping|, a |defaultValue| can be returned instead of
* throwing an exception. The latter is the default and happens when
* no |defaultValue| is passed.
* @throws MalformedException
*/
enum : function(unchecked, allowedValues, defaultValue)
{
for (let allowedValue of allowedValues)
{
if (allowedValue == unchecked)
return allowedValue;
}
// value is bad
if (typeof(defaultValue) == "undefined")
throw new MalformedException("allowed_value.error", unchecked);
return defaultValue;
},
/**
* Like enum, allows only certain (string) values as input, but allows the
* caller to specify another value to return instead of the input value. E.g.,
* if unchecked == "foo", return 1, if unchecked == "bar", return 2,
* otherwise throw. This allows to translate string enums into integer enums.
*
* @param unchecked {Any} The value to check
* @param mapping {Object} Associative array. property name is the input
* value, property value is the output value. E.g. the example above
* would be: { foo: 1, bar : 2 }.
* Use quotes when you need freaky characters: "baz-" : 3.
* @param defaultValue {Any} (Optional) If |unchecked| does not match
* anything in |mapping|, a |defaultValue| can be returned instead of
* throwing an exception. The latter is the default and happens when
* no |defaultValue| is passed.
* @throws MalformedException
*/
translate : function(unchecked, mapping, defaultValue)
{
for (var inputValue in mapping)
{
if (inputValue == unchecked)
return mapping[inputValue];
}
// value is bad
if (typeof(defaultValue) == "undefined")
throw new MalformedException("allowed_value.error", unchecked);
return defaultValue;
}
};
function MalformedException(msgID, uncheckedBadValue)
{
var stringBundle = getStringBundle(
"chrome://messenger/locale/accountCreationUtil.properties");
var msg = stringBundle.GetStringFromName(msgID);
if (kDebug)
msg += " (bad value: " + new String(uncheckedBadValue) + ")";
Exception.call(this, msg);
}
MalformedException.prototype = Object.create(Exception.prototype);
MalformedException.prototype.constructor = MalformedException;

View file

@ -0,0 +1,304 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/**
* Some common, generic functions
*/
try {
var Cc = Components.classes;
var Ci = Components.interfaces;
} catch (e) { ddump(e); } // if already declared, as in xpcshell-tests
try {
var Cu = Components.utils;
} catch (e) { ddump(e); }
Cu.import("resource:///modules/errUtils.js");
Cu.import("resource://gre/modules/Services.jsm");
function assert(test, errorMsg)
{
if (!test)
throw new NotReached(errorMsg ? errorMsg :
"Programming bug. Assertion failed, see log.");
}
function makeCallback(obj, func)
{
return function()
{
return func.apply(obj, arguments);
}
}
/**
* Runs the given function sometime later
*
* Currently implemented using setTimeout(), but
* can later be replaced with an nsITimer impl,
* when code wants to use it in a module.
*/
function runAsync(func)
{
setTimeout(func, 0);
}
/**
* @param uriStr {String}
* @result {nsIURI}
*/
function makeNSIURI(uriStr)
{
return Services.io.newURI(uriStr, null, null);
}
/**
* Reads UTF8 data from a URL.
*
* @param uri {nsIURI} what you want to read
* @return {Array of String} the contents of the file, one string per line
*/
function readURLasUTF8(uri)
{
assert(uri instanceof Ci.nsIURI, "uri must be an nsIURI");
try {
let chan = Services.io.newChannelFromURI2(uri,
null,
Services.scriptSecurityManager.getSystemPrincipal(),
null,
Ci.nsILoadInfo.SEC_NORMAL,
Ci.nsIContentPolicy.TYPE_OTHER);
let is = Cc["@mozilla.org/intl/converter-input-stream;1"]
.createInstance(Ci.nsIConverterInputStream);
is.init(chan.open(), "UTF-8", 1024,
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
let content = "";
let strOut = new Object();
try {
while (is.readString(1024, strOut) != 0)
content += strOut.value;
// catch in outer try/catch
} finally {
is.close();
}
return content;
} catch (e) {
// TODO this has a numeric error message. We need to ship translations
// into human language.
throw e;
}
}
/**
* Takes a string (which is typically the content of a file,
* e.g. the result returned from readURLUTF8() ), and splits
* it into lines, and returns an array with one string per line
*
* Linebreaks are not contained in the result,,
* and all of \r\n, (Windows) \r (Mac) and \n (Unix) counts as linebreak.
*
* @param content {String} one long string with the whole file
* @return {Array of String} one string per line (no linebreaks)
*/
function splitLines(content)
{
content = content.replace("\r\n", "\n");
content = content.replace("\r", "\n");
return content.split("\n");
}
/**
* @param bundleURI {String} chrome URL to properties file
* @return nsIStringBundle
*/
function getStringBundle(bundleURI)
{
try {
return Services.strings.createBundle(bundleURI);
} catch (e) {
throw new Exception("Failed to get stringbundle URI <" + bundleURI +
">. Error: " + e);
}
}
function Exception(msg)
{
this._message = msg;
// get stack
try {
not.found.here += 1; // force a native exception ...
} catch (e) {
this.stack = e.stack; // ... to get the current stack
}
}
Exception.prototype =
{
get message()
{
return this._message;
},
toString : function()
{
return this._message;
}
}
function NotReached(msg)
{
Exception.call(this, msg); // call super constructor
logException(this);
}
// Make NotReached extend Exception.
NotReached.prototype = Object.create(Exception.prototype);
NotReached.prototype.constructor = NotReached;
/**
* A handle for an async function which you can cancel.
* The async function will return an object of this type (a subtype)
* and you can call cancel() when you feel like killing the function.
*/
function Abortable()
{
}
Abortable.prototype =
{
cancel : function()
{
}
}
/**
* Utility implementation, for allowing to abort a setTimeout.
* Use like: return new TimeoutAbortable(setTimeout(function(){ ... }, 0));
* @param setTimeoutID {Integer} Return value of setTimeout()
*/
function TimeoutAbortable(setTimeoutID)
{
Abortable.call(this, setTimeoutID); // call super constructor
this._id = setTimeoutID;
}
TimeoutAbortable.prototype = Object.create(Abortable.prototype);
TimeoutAbortable.prototype.constructor = TimeoutAbortable;
TimeoutAbortable.prototype.cancel = function() { clearTimeout(this._id); }
/**
* Utility implementation, for allowing to abort a setTimeout.
* Use like: return new TimeoutAbortable(setTimeout(function(){ ... }, 0));
* @param setIntervalID {Integer} Return value of setInterval()
*/
function IntervalAbortable(setIntervalID)
{
Abortable.call(this, setIntervalID); // call super constructor
this._id = setIntervalID;
}
IntervalAbortable.prototype = Object.create(Abortable.prototype);
IntervalAbortable.prototype.constructor = IntervalAbortable;
IntervalAbortable.prototype.cancel = function() { clearInterval(this._id); }
// Allows you to make several network calls, but return
// only one Abortable object.
function SuccessiveAbortable()
{
Abortable.call(this); // call super constructor
this._current = null;
}
SuccessiveAbortable.prototype = {
__proto__: Abortable.prototype,
get current() { return this._current; },
set current(abortable)
{
assert(abortable instanceof Abortable || abortable == null,
"need an Abortable object (or null)");
this._current = abortable;
},
cancel: function()
{
if (this._current)
this._current.cancel();
}
}
function deepCopy(org)
{
if (typeof(org) == "undefined")
return undefined;
if (org == null)
return null;
if (typeof(org) == "string")
return org;
if (typeof(org) == "number")
return org;
if (typeof(org) == "boolean")
return org == true;
if (typeof(org) == "function")
return org;
if (typeof(org) != "object")
throw "can't copy objects of type " + typeof(org) + " yet";
//TODO still instanceof org != instanceof copy
//var result = new org.constructor();
var result = new Object();
if (typeof(org.length) != "undefined")
var result = new Array();
for (var prop in org)
result[prop] = deepCopy(org[prop]);
return result;
}
if (typeof gEmailWizardLogger == "undefined") {
Cu.import("resource:///modules/gloda/log4moz.js");
var gEmailWizardLogger = Log4Moz.getConfiguredLogger("mail.wizard");
}
function ddump(text)
{
gEmailWizardLogger.info(text);
}
function debugObject(obj, name, maxDepth, curDepth)
{
if (curDepth == undefined)
curDepth = 0;
if (maxDepth != undefined && curDepth > maxDepth)
return "";
var result = "";
var i = 0;
for (let prop in obj)
{
i++;
try {
if (typeof(obj[prop]) == "object")
{
if (obj[prop] && obj[prop].length != undefined)
result += name + "." + prop + "=[probably array, length " +
obj[prop].length + "]\n";
else
result += name + "." + prop + "=[" + typeof(obj[prop]) + "]\n";
result += debugObject(obj[prop], name + "." + prop,
maxDepth, curDepth + 1);
}
else if (typeof(obj[prop]) == "function")
result += name + "." + prop + "=[function]\n";
else
result += name + "." + prop + "=" + obj[prop] + "\n";
} catch (e) {
result += name + "." + prop + "-> Exception(" + e + ")\n";
}
}
if (!i)
result += name + " is empty\n";
return result;
}
function alertPrompt(alertTitle, alertMsg)
{
Services.prompt.alert(window, alertTitle, alertMsg);
}

View file

@ -0,0 +1,347 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
/* 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/. */
/**
* This checks a given config, by trying a real connection and login,
* with username and password.
*
* TODO
* - give specific errors, bug 555448
* - return a working |Abortable| to allow cancel
*
* @param accountConfig {AccountConfig} The guessed account config.
* username, password, realname, emailaddress etc. are not filled out,
* but placeholders to be filled out via replaceVariables().
* @param alter {boolean}
* Try other usernames and login schemes, until login works.
* Warning: Modifies |accountConfig|.
*
* This function is async.
* @param successCallback function(accountConfig)
* Called when we could guess the config.
* For accountConfig, see below.
* @param errorCallback function(ex)
* Called when we could guess not the config, either
* because we have not found anything or
* because there was an error (e.g. no network connection).
* The ex.message will contain a user-presentable message.
*/
Components.utils.import("resource:///modules/mailServices.js");
Components.utils.import("resource://gre/modules/OAuth2Providers.jsm");
if (typeof gEmailWizardLogger == "undefined") {
Cu.import("resource:///modules/gloda/log4moz.js");
var gEmailWizardLogger = Log4Moz.getConfiguredLogger("mail.wizard");
}
function verifyConfig(config, alter, msgWindow, successCallback, errorCallback)
{
ddump(debugObject(config, "config", 3));
assert(config instanceof AccountConfig,
"BUG: Arg 'config' needs to be an AccountConfig object");
assert(typeof(alter) == "boolean");
assert(typeof(successCallback) == "function");
assert(typeof(errorCallback) == "function");
if (MailServices.accounts.findRealServer(config.incoming.username,
config.incoming.hostname,
sanitize.enum(config.incoming.type,
["pop3", "imap", "nntp"]),
config.incoming.port)) {
errorCallback("Incoming server exists");
return;
}
// incoming server
let inServer =
MailServices.accounts.createIncomingServer(config.incoming.username,
config.incoming.hostname,
sanitize.enum(config.incoming.type,
["pop3", "imap", "nntp"]));
inServer.port = config.incoming.port;
inServer.password = config.incoming.password;
if (config.incoming.socketType == 1) // plain
inServer.socketType = Ci.nsMsgSocketType.plain;
else if (config.incoming.socketType == 2) // SSL
inServer.socketType = Ci.nsMsgSocketType.SSL;
else if (config.incoming.socketType == 3) // STARTTLS
inServer.socketType = Ci.nsMsgSocketType.alwaysSTARTTLS;
gEmailWizardLogger.info("Setting incoming server authMethod to " +
config.incoming.auth);
inServer.authMethod = config.incoming.auth;
try {
// Lookup issuer if needed.
if (config.incoming.auth == Ci.nsMsgAuthMethod.OAuth2 ||
config.outgoing.auth == Ci.nsMsgAuthMethod.OAuth2) {
if (!config.oauthSettings)
config.oauthSettings = {};
if (!config.oauthSettings.issuer || !config.oauthSettings.scope) {
// lookup issuer or scope from hostname
let hostname = (config.incoming.auth == Ci.nsMsgAuthMethod.OAuth2) ?
config.incoming.hostname : config.outgoing.hostname;
let hostDetails = OAuth2Providers.getHostnameDetails(hostname);
if (hostDetails)
[config.oauthSettings.issuer, config.oauthSettings.scope] = hostDetails;
if (!config.oauthSettings.issuer || !config.oauthSettings.scope)
throw "Could not get issuer for oauth2 authentication";
}
gEmailWizardLogger.info("Saving oauth parameters for issuer " +
config.oauthSettings.issuer);
inServer.setCharValue("oauth2.scope", config.oauthSettings.scope);
inServer.setCharValue("oauth2.issuer", config.oauthSettings.issuer);
gEmailWizardLogger.info("OAuth2 issuer, scope is " +
config.oauthSettings.issuer + ", " + config.oauthSettings.scope);
}
if (inServer.password ||
inServer.authMethod == Ci.nsMsgAuthMethod.OAuth2)
verifyLogon(config, inServer, alter, msgWindow,
successCallback, errorCallback);
else {
// Avoid pref pollution, clear out server prefs.
MailServices.accounts.removeIncomingServer(inServer, true);
successCallback(config);
}
return;
}
catch (e) {
gEmailWizardLogger.error("ERROR: verify logon shouldn't have failed");
}
// Avoid pref pollution, clear out server prefs.
MailServices.accounts.removeIncomingServer(inServer, true);
errorCallback(e);
}
function verifyLogon(config, inServer, alter, msgWindow, successCallback,
errorCallback)
{
gEmailWizardLogger.info("verifyLogon for server at " + inServer.hostName);
// hack - save away the old callbacks.
let saveCallbacks = msgWindow.notificationCallbacks;
// set our own callbacks - this works because verifyLogon will
// synchronously create the transport and use the notification callbacks.
let listener = new urlListener(config, inServer, alter, msgWindow,
successCallback, errorCallback);
// our listener listens both for the url and cert errors.
msgWindow.notificationCallbacks = listener;
// try to work around bug where backend is clearing password.
try {
inServer.password = config.incoming.password;
let uri = inServer.verifyLogon(listener, msgWindow);
// clear msgWindow so url won't prompt for passwords.
uri.QueryInterface(Ci.nsIMsgMailNewsUrl).msgWindow = null;
}
catch (e) { gEmailWizardLogger.error("verifyLogon failed: " + e); throw e;}
finally {
// restore them
msgWindow.notificationCallbacks = saveCallbacks;
}
}
/**
* The url listener also implements nsIBadCertListener2. Its job is to prevent
* "bad cert" security dialogs from being shown to the user. Currently it puts
* up the cert override dialog, though we'd like to give the user more detailed
* information in the future.
*/
function urlListener(config, server, alter, msgWindow, successCallback,
errorCallback)
{
this.mConfig = config;
this.mServer = server;
this.mAlter = alter;
this.mSuccessCallback = successCallback;
this.mErrorCallback = errorCallback;
this.mMsgWindow = msgWindow;
this.mCertError = false;
this._log = Log4Moz.getConfiguredLogger("mail.wizard");
}
urlListener.prototype =
{
OnStartRunningUrl: function(aUrl)
{
this._log.info("Starting to test username");
this._log.info(" username=" + (this.mConfig.incoming.username !=
this.mConfig.identity.emailAddress) +
", have savedUsername=" +
(this.mConfig.usernameSaved ? "true" : "false"));
this._log.info(" authMethod=" + this.mServer.authMethod);
},
OnStopRunningUrl: function(aUrl, aExitCode)
{
this._log.info("Finished verifyConfig resulted in " + aExitCode);
if (Components.isSuccessCode(aExitCode))
{
this._cleanup();
this.mSuccessCallback(this.mConfig);
}
// Logon failed, and we aren't supposed to try other variations.
else if (!this.mAlter)
{
this._cleanup();
var errorMsg = getStringBundle(
"chrome://messenger/locale/accountCreationModel.properties")
.GetStringFromName("cannot_login.error");
this.mErrorCallback(new Exception(errorMsg));
}
// Try other variations, unless there's a cert error, in which
// case we'll see what the user chooses.
else if (!this.mCertError)
{
this.tryNextLogon()
}
},
tryNextLogon: function()
{
this._log.info("tryNextLogon()");
this._log.info(" username=" + (this.mConfig.incoming.username !=
this.mConfig.identity.emailAddress) +
", have savedUsername=" +
(this.mConfig.usernameSaved ? "true" : "false"));
this._log.info(" authMethod=" + this.mServer.authMethod);
// check if we tried full email address as username
if (this.mConfig.incoming.username != this.mConfig.identity.emailAddress)
{
this._log.info(" Changing username to email address.");
this.mConfig.usernameSaved = this.mConfig.incoming.username;
this.mConfig.incoming.username = this.mConfig.identity.emailAddress;
this.mConfig.outgoing.username = this.mConfig.identity.emailAddress;
this.mServer.username = this.mConfig.incoming.username;
this.mServer.password = this.mConfig.incoming.password;
verifyLogon(this.mConfig, this.mServer, this.mAlter, this.mMsgWindow,
this.mSuccessCallback, this.mErrorCallback);
return;
}
if (this.mConfig.usernameSaved)
{
this._log.info(" Re-setting username.");
// If we tried the full email address as the username, then let's go
// back to trying just the username before trying the other cases.
this.mConfig.incoming.username = this.mConfig.usernameSaved;
this.mConfig.outgoing.username = this.mConfig.usernameSaved;
this.mConfig.usernameSaved = null;
this.mServer.username = this.mConfig.incoming.username;
this.mServer.password = this.mConfig.incoming.password;
}
// sec auth seems to have failed, and we've tried both
// varieties of user name, sadly.
// So fall back to non-secure auth, and
// again try the user name and email address as username
assert(this.mConfig.incoming.auth == this.mServer.authMethod);
this._log.info(" Using SSL: " +
(this.mServer.socketType == Ci.nsMsgSocketType.SSL ||
this.mServer.socketType == Ci.nsMsgSocketType.alwaysSTARTTLS));
if (this.mConfig.incoming.authAlternatives &&
this.mConfig.incoming.authAlternatives.length)
// We may be dropping back to insecure auth methods here,
// which is not good. But then again, we already warned the user,
// if it is a config without SSL.
{
this._log.info(" auth alternatives = " +
this.mConfig.incoming.authAlternatives.join(","));
this._log.info(" Decreasing auth.");
this._log.info(" Have password: " +
(this.mServer.password ? "true" : "false"));
let brokenAuth = this.mConfig.incoming.auth;
// take the next best method (compare chooseBestAuthMethod() in guess)
this.mConfig.incoming.auth =
this.mConfig.incoming.authAlternatives.shift();
this.mServer.authMethod = this.mConfig.incoming.auth;
// Assume that SMTP server has same methods working as incoming.
// Broken assumption, but we currently have no SMTP verification.
// TODO implement real SMTP verification
if (this.mConfig.outgoing.auth == brokenAuth &&
this.mConfig.outgoing.authAlternatives.indexOf(
this.mConfig.incoming.auth) != -1)
this.mConfig.outgoing.auth = this.mConfig.incoming.auth;
this._log.info(" outgoing auth: " + this.mConfig.outgoing.auth);
verifyLogon(this.mConfig, this.mServer, this.mAlter, this.mMsgWindow,
this.mSuccessCallback, this.mErrorCallback);
return;
}
// Tried all variations we can. Give up.
this._log.info("Giving up.");
this._cleanup();
let errorMsg = getStringBundle(
"chrome://messenger/locale/accountCreationModel.properties")
.GetStringFromName("cannot_login.error");
this.mErrorCallback(new Exception(errorMsg));
return;
},
_cleanup : function()
{
try {
// Avoid pref pollution, clear out server prefs.
if (this.mServer) {
MailServices.accounts.removeIncomingServer(this.mServer, true);
this.mServer = null;
}
} catch (e) { this._log.error(e); }
},
// Suppress any certificate errors
notifyCertProblem: function(socketInfo, status, targetSite) {
this.mCertError = true;
this._log.error("cert error");
let self = this;
setTimeout(function () {
try {
self.informUserOfCertError(socketInfo, status, targetSite);
} catch (e) { logException(e); }
}, 0);
return true;
},
informUserOfCertError : function(socketInfo, status, targetSite) {
var params = {
exceptionAdded : false,
sslStatus : status,
prefetchCert : true,
location : targetSite,
};
window.openDialog("chrome://pippki/content/exceptionDialog.xul",
"","chrome,centerscreen,modal", params);
this._log.info("cert exception dialog closed");
this._log.info("cert exceptionAdded = " + params.exceptionAdded);
if (!params.exceptionAdded) {
this._cleanup();
let errorMsg = getStringBundle(
"chrome://messenger/locale/accountCreationModel.properties")
.GetStringFromName("cannot_login.error");
this.mErrorCallback(new Exception(errorMsg));
}
else {
// Retry the logon now that we've added the cert exception.
verifyLogon(this.mConfig, this.mServer, this.mAlter, this.mMsgWindow,
this.mSuccessCallback, this.mErrorCallback);
}
},
// nsIInterfaceRequestor
getInterface: function(iid) {
return this.QueryInterface(iid);
},
// nsISupports
QueryInterface: function(iid) {
if (!iid.equals(Components.interfaces.nsIBadCertListener2) &&
!iid.equals(Components.interfaces.nsIInterfaceRequestor) &&
!iid.equals(Components.interfaces.nsIUrlListener) &&
!iid.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
}

View file

@ -0,0 +1,79 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
function onLoad()
{
parent.onPanelLoaded('am-addressing.xul');
}
function onInit(aPageId, aServerId)
{
onInitCompositionAndAddressing();
}
function onInitCompositionAndAddressing()
{
LDAPenabling();
quoteEnabling();
}
function onEditDirectories()
{
window.openDialog("chrome://messenger/content/addressbook/pref-editdirectories.xul",
"editDirectories", "chrome,modal=yes,resizable=no", null);
}
function onPreInit(account, accountValues)
{
}
function LDAPenabling()
{
onCheckItem("identity.directoryServer", ["directories"]);
onCheckItem("editButton", ["directories"]);
}
function quoteEnabling()
{
var quotebox = document.getElementById("thenBox");
var placebox = document.getElementById("placeBox");
var quotecheck = document.getElementById("identity.autoQuote");
if (quotecheck.checked && !quotecheck.disabled &&
(document.getElementById("identity.replyOnTop").value == 1)) {
placebox.firstChild.removeAttribute("disabled");
placebox.lastChild.removeAttribute("disabled");
}
else {
placebox.firstChild.setAttribute("disabled", "true");
placebox.lastChild.setAttribute("disabled", "true");
}
if (quotecheck.checked && !quotecheck.disabled) {
quotebox.firstChild.removeAttribute("disabled");
quotebox.lastChild.removeAttribute("disabled");
}
else {
quotebox.firstChild.setAttribute("disabled", "true");
quotebox.lastChild.setAttribute("disabled", "true");
}
}
/**
* Open the Preferences dialog on the tab with Addressing options.
*/
function showGlobalAddressingPrefs()
{
openPrefsFromAccountManager("paneCompose", "addressingTab", null, "addressing_pane");
}
/**
* Open the Preferences dialog on the tab with Composing options.
*/
function showGlobalComposingPrefs()
{
openPrefsFromAccountManager("paneCompose", "generalTab", null, "composing_messages_pane");
}

View file

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xul-overlay href="chrome://messenger/content/am-addressingOverlay.xul"?>
<!DOCTYPE page SYSTEM "chrome://messenger/locale/am-addressing.dtd">
<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&addressing.label;"
onload="onLoad();">
<vbox flex="1" style="overflow: auto;">
<dialogheader title="&addressing.label;"/>
<vbox id="compositionAndAddressing"/>
</vbox>
</page>

View file

@ -0,0 +1,135 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/content/messenger.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
<!DOCTYPE overlay SYSTEM "chrome://messenger/locale/am-addressing.dtd">
<overlay xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://messenger/content/am-addressing.js"/>
<script type="application/javascript" src="chrome://messenger/content/amUtils.js"/>
<script type="application/javascript" src="chrome://messenger/content/am-prefs.js"/>
<vbox flex="1" id="compositionAndAddressing">
<stringbundle id="bundle_addressBook" src="chrome://messenger/locale/addressbook/addressBook.properties"/>
<groupbox>
<caption label="&compositionGroupTitle.label;"/>
<hbox align="center">
<checkbox wsm_persist="true" id="identity.composeHtml" label="&useHtml.label;"
accesskey="&useHtml.accesskey;"
prefattribute="value"
prefstring="mail.identity.%identitykey%.compose_html"/>
</hbox>
<separator class="thin"/>
<hbox align="center">
<checkbox wsm_persist="true" id="identity.autoQuote" label="&autoQuote.label;"
oncommand="quoteEnabling();" accesskey="&autoQuote.accesskey;"
pref="true" preftype="bool" prefattribute="value"
prefstring="mail.identity.%identitykey%.auto_quote"/>
</hbox>
<hbox class="indent" align="center" id="thenBox">
<label value="&then.label;" accesskey="&then.accesskey;" control="identity.replyOnTop"/>
<menulist wsm_persist="true" id="identity.replyOnTop" oncommand="quoteEnabling();"
pref="true" preftype="int" prefattribute="value"
prefstring="mail.identity.%identitykey%.reply_on_top">
<menupopup>
<menuitem value="1" label="&aboveQuote.label;"/>
<menuitem value="0" label="&belowQuote.label;"/>
<menuitem value="2" label="&selectAndQuote.label;"/>
</menupopup>
</menulist>
</hbox>
<hbox class="indent" align="center" id="placeBox">
<label value="&place.label;" accesskey="&place.accesskey;" control="identity.sig_bottom"/>
<menulist wsm_persist="true" id="identity.sig_bottom" genericattr="true"
pref="true" preftype="bool" prefattribute="value"
prefstring="mail.identity.%identitykey%.sig_bottom">
<menupopup>
<menuitem value="true" label="&belowText.label;"/>
<menuitem value="false" label="&aboveText.label;"/>
</menupopup>
</menulist>
</hbox>
<checkbox id="identity.sig_on_reply" wsm_persist="true"
label="&includeSigOnReply.label;"
accesskey="&includeSigOnReply.accesskey;"
preftype="bool" genericattr="true"
prefstring="mail.identity.%identitykey%.sig_on_reply"/>
<checkbox id="identity.sig_on_fwd" wsm_persist="true"
label="&includeSigOnForward.label;"
accesskey="&includeSigOnForward.accesskey;"
preftype="bool" genericattr="true"
prefstring="mail.identity.%identitykey%.sig_on_fwd"/>
<separator class="thin"/>
<hbox pack="start">
<button id="globalComposingPrefsLink"
label="&globalComposingPrefs.label;"
accesskey="&globalComposingPrefs.accesskey;"
oncommand="showGlobalComposingPrefs();"/>
</hbox>
</groupbox>
<separator class="thin"/>
<groupbox>
<caption label="&addressingGroupTitle.label;"/>
#ifndef MOZ_THUNDERBIRD
<hbox align="center">
<checkbox wsm_persist="true" id="identity.autocompleteToMyDomain"
label="&autocompleteToMyDomain.label;"
accesskey="&autocompleteToMyDomain.accesskey;"
prefattribute="value"
prefstring="mail.identity.%identitykey%.autocompleteToMyDomain"/>
</hbox>
<separator class="thin"/>
#endif
<label control="identity.overrideGlobal_Pref">&addressingText.label;</label>
<radiogroup id="identity.overrideGlobal_Pref" class="indent"
oncommand="LDAPenabling();" wsm_persist="true"
genericattr="true" preftype="bool"
prefstring="mail.identity.%identitykey%.overrideGlobal_Pref">
<radio value="false" label="&useGlobal.label;"
accesskey="&useGlobal.accesskey;"/>
<radio value="true" id="directories" label="&directories.label;"
accesskey="&directories.accesskey;"/>
<hbox class="indent">
<menulist id="identity.directoryServer"
wsm_persist="true" preftype="string"
prefstring="mail.identity.%identitykey%.directoryServer"
style="min-width: 16em;" aria-labelledby="directories">
<menupopup class="addrbooksPopup"
none="&directoriesNone.label;"
remoteonly="true" value="dirPrefId"/>
</menulist>
<button id="editButton" label="&editDirectories.label;"
accesskey="&editDirectories.accesskey;"
oncommand="onEditDirectories();"/>
</hbox>
</radiogroup>
<separator class="thin"/>
<hbox pack="start">
<button id="globalAddressingPrefsLink"
label="&globalAddressingPrefs.label;"
accesskey="&globalAddressingPrefs.accesskey;"
oncommand="showGlobalAddressingPrefs();"/>
</hbox>
</groupbox>
</vbox>
</overlay>

View file

@ -0,0 +1,69 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
var gIdentity = null;
/**
* Load the archive options dialog, set the radio/checkbox items to the
* appropriate values, and update the archive hierarchy example.
*/
function onLoadArchiveOptions() {
// extract the account
gIdentity = window.arguments[0];
let granularity = document.getElementById("archiveGranularity");
granularity.selectedIndex = gIdentity.archiveGranularity;
granularity.addEventListener("command", updateArchiveExample, false);
let kfs = document.getElementById("archiveKeepFolderStructure");
kfs.checked = gIdentity.archiveKeepFolderStructure;
kfs.addEventListener("command", updateArchiveExample, false);
updateArchiveExample();
}
/**
* Save the archive settings to the current identity.
*/
function onAcceptArchiveOptions() {
gIdentity.archiveGranularity =
document.getElementById("archiveGranularity").selectedIndex;
gIdentity.archiveKeepFolderStructure =
document.getElementById("archiveKeepFolderStructure").checked;
}
/**
* Update the example tree to show what the current options would look like.
*/
function updateArchiveExample() {
let granularity = document.getElementById("archiveGranularity").selectedIndex;
let kfs = document.getElementById("archiveKeepFolderStructure").checked;
let hierarchy = [ document.getElementsByClassName("root"),
document.getElementsByClassName("year"),
document.getElementsByClassName("month") ];
// First, show/hide the appropriate levels in the hierarchy and turn the
// necessary items into containers.
for (let i = 0; i < hierarchy.length; i++) {
for (let j = 0; j < hierarchy[i].length; j++) {
hierarchy[i][j].setAttribute("container", granularity > i);
hierarchy[i][j].setAttribute("open", granularity > i);
hierarchy[i][j].hidden = granularity < i;
}
}
// Next, handle the "keep folder structures" case by moving a tree item around
// and making sure its parent is a container.
let folders = document.getElementById("folders");
folders.hidden = !kfs;
if (kfs) {
let parent = hierarchy[granularity][0];
parent.setAttribute("container", true);
parent.setAttribute("open", true);
let treechildren = parent.children[1];
treechildren.appendChild(folders);
}
}

View file

@ -0,0 +1,99 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/messenger.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/folderPane.css" type="text/css"?>
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/am-archiveoptions.dtd" >
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="archive-options"
title="&dialogTitle.label;"
width="350" height="350"
persist="width height"
onload="onLoadArchiveOptions();"
ondialogaccept="onAcceptArchiveOptions();">
<script type="application/javascript" src="chrome://messenger/content/am-archiveoptions.js"/>
<vbox flex="1">
<label>&archiveGranularityPrefix.label;</label>
<radiogroup id="archiveGranularity">
<radio label="&archiveFlat.label;" accesskey="&archiveFlat.accesskey;"
class="indent"/>
<radio label="&archiveYearly.label;"
accesskey="&archiveYearly.accesskey;" class="indent"/>
<radio label="&archiveMonthly.label;"
accesskey="&archiveMonthly.accesskey;" class="indent"/>
</radiogroup>
<checkbox id="archiveKeepFolderStructure"
label="&keepFolderStructure.label;"
accesskey="&keepFolderStructure.accesskey;"/>
<groupbox flex="1">
<caption label="&archiveExample.label;"/>
<tree id="archiveTree" hidecolumnpicker="true" disabled="true" flex="1">
<treecols>
<treecol primary="true" hideheader="true" flex="1"
id="folderNameCol"/>
</treecols>
<treechildren>
<treeitem class="root">
<treerow>
<treecell properties="specialFolder-Archive"
label="&archiveFolderName.label;"/>
</treerow>
<treechildren>
<treeitem id="folders">
<treerow>
<treecell label="&inboxFolderName.label;"/>
</treerow>
</treeitem>
<treeitem class="year">
<treerow>
<treecell label="2010"/>
</treerow>
<treechildren>
<treeitem class="month">
<treerow>
<treecell label="2010-11"/>
</treerow>
<treechildren/>
</treeitem>
<treeitem class="month">
<treerow>
<treecell label="2010-12"/>
</treerow>
<treechildren/>
</treeitem>
</treechildren>
</treeitem>
<treeitem class="year">
<treerow>
<treecell label="2011"/>
</treerow>
<treechildren>
<treeitem class="month">
<treerow>
<treecell label="2011-01"/>
</treerow>
<treechildren/>
</treeitem>
<treeitem class="month">
<treerow>
<treecell label="2011-02"/>
</treerow>
<treechildren/>
</treeitem>
</treechildren>
</treeitem>
</treechildren>
</treeitem>
</treechildren>
</tree>
</groupbox>
</vbox>
</dialog>

View file

@ -0,0 +1,471 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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/. */
Components.utils.import("resource:///modules/MailUtils.js");
var gFccRadioElemChoice, gDraftsRadioElemChoice, gArchivesRadioElemChoice, gTmplRadioElemChoice;
var gFccRadioElemChoiceLocked, gDraftsRadioElemChoiceLocked, gArchivesRadioElemChoiceLocked, gTmplRadioElemChoiceLocked;
var gDefaultPickerMode = "1";
var gFccFolderWithDelim, gDraftsFolderWithDelim, gArchivesFolderWithDelim, gTemplatesFolderWithDelim;
var gAccount;
var gCurrentServerId;
function onPreInit(account, accountValues)
{
gAccount = account;
var type = parent.getAccountValue(account, accountValues, "server", "type", null, false);
hideShowControls(type);
}
/*
* Set the global radio element choices and initialize folder/account pickers.
* Also, initialize other UI elements (cc, bcc, fcc picker controller checkboxes).
*/
function onInit(aPageId, aServerId)
{
gCurrentServerId = aServerId;
onInitCopiesAndFolders();
}
function onInitCopiesAndFolders()
{
SetGlobalRadioElemChoices();
SetFolderDisplay(gFccRadioElemChoice, gFccRadioElemChoiceLocked,
"fcc",
"msgFccAccountPicker",
"identity.fccFolder",
"msgFccFolderPicker");
SetFolderDisplay(gArchivesRadioElemChoice, gArchivesRadioElemChoiceLocked,
"archive",
"msgArchivesAccountPicker",
"identity.archiveFolder",
"msgArchivesFolderPicker");
SetFolderDisplay(gDraftsRadioElemChoice, gDraftsRadioElemChoiceLocked,
"draft",
"msgDraftsAccountPicker",
"identity.draftFolder",
"msgDraftsFolderPicker");
SetFolderDisplay(gTmplRadioElemChoice, gTmplRadioElemChoiceLocked,
"tmpl",
"msgStationeryAccountPicker",
"identity.stationeryFolder",
"msgStationeryFolderPicker");
setupCcTextbox(true);
setupBccTextbox(true);
setupFccItems();
setupArchiveItems();
SetSpecialFolderNamesWithDelims();
}
// Initialize the picker mode choices (account/folder picker) into global vars
function SetGlobalRadioElemChoices()
{
var pickerModeElement = document.getElementById("identity.fccFolderPickerMode");
gFccRadioElemChoice = pickerModeElement.getAttribute("value");
gFccRadioElemChoiceLocked = pickerModeElement.getAttribute("disabled");
if (!gFccRadioElemChoice) gFccRadioElemChoice = gDefaultPickerMode;
pickerModeElement = document.getElementById("identity.archivesFolderPickerMode");
gArchivesRadioElemChoice = pickerModeElement.getAttribute("value");
gArchivesRadioElemChoiceLocked = pickerModeElement.getAttribute("disabled");
if (!gArchivesRadioElemChoice) gArchivesRadioElemChoice = gDefaultPickerMode;
pickerModeElement = document.getElementById("identity.draftsFolderPickerMode");
gDraftsRadioElemChoice = pickerModeElement.getAttribute("value");
gDraftsRadioElemChoiceLocked = pickerModeElement.getAttribute("disabled");
if (!gDraftsRadioElemChoice) gDraftsRadioElemChoice = gDefaultPickerMode;
pickerModeElement = document.getElementById("identity.tmplFolderPickerMode");
gTmplRadioElemChoice = pickerModeElement.getAttribute("value");
gTmplRadioElemChoiceLocked = pickerModeElement.getAttribute("disabled");
if (!gTmplRadioElemChoice) gTmplRadioElemChoice = gDefaultPickerMode;
}
/*
* Set Account and Folder elements based on the values read from
* preferences file. Default picker mode, if none specified at this stage, is
* set to 1 i.e., Other picker displaying the folder value read from the
* preferences file.
*/
function SetFolderDisplay(pickerMode, disableMode,
radioElemPrefix,
accountPickerId,
folderPickedField,
folderPickerId)
{
if (!pickerMode)
pickerMode = gDefaultPickerMode;
var selectAccountRadioId = radioElemPrefix + "_selectAccount";
var selectAccountRadioElem = document.getElementById(selectAccountRadioId);
var selectFolderRadioId = radioElemPrefix + "_selectFolder";
var selectFolderRadioElem = document.getElementById(selectFolderRadioId);
var accountPicker = document.getElementById(accountPickerId);
var folderPicker = document.getElementById(folderPickerId);
var rg = selectAccountRadioElem.radioGroup;
var folderPickedElement = document.getElementById(folderPickedField);
var uri = folderPickedElement.getAttribute("value");
// Get message folder from the given uri. Second argument (false) signifies
// that there is no need to check for the existence of special folders as
// these folders are created on demand at runtime in case of imap accounts.
// For POP3 accounts, special folders are created at the account creation time.
var msgFolder = MailUtils.getFolderForURI(uri, false);
InitFolderDisplay(msgFolder.server.rootFolder, accountPicker);
InitFolderDisplay(msgFolder, folderPicker);
switch (pickerMode)
{
case "0" :
rg.selectedItem = selectAccountRadioElem;
SetPickerEnabling(accountPickerId, folderPickerId);
break;
case "1" :
rg.selectedItem = selectFolderRadioElem;
SetPickerEnabling(folderPickerId, accountPickerId);
break;
default :
dump("Error in setting initial folder display on pickers\n");
break;
}
// Check to see if we need to lock page elements. Disable radio buttons
// and account/folder pickers when locked.
if (disableMode) {
selectAccountRadioElem.setAttribute("disabled","true");
selectFolderRadioElem.setAttribute("disabled","true");
accountPicker.setAttribute("disabled","true");
folderPicker.setAttribute("disabled","true");
}
}
// Initialize the folder display based on prefs values
function InitFolderDisplay(folder, folderPicker) {
folderPicker.menupopup.selectFolder(folder);
folderPicker.folder = folder;
}
/**
* Capture any menulist changes and update the folder property.
*
* @param aGroup the prefix for the menulist we're handling (e.g. "drafts")
* @param aType "Account" for the account picker or "Folder" for the folder
* picker
* @param aEvent the event that we're responding to
*/
function noteSelectionChange(aGroup, aType, aEvent)
{
var checkedElem = document.getElementById(aGroup+"_select"+aType);
var folder = aEvent.target._folder;
var modeValue = checkedElem.value;
var radioGroup = checkedElem.radioGroup.getAttribute("id");
var picker;
switch (radioGroup) {
case "doFcc" :
gFccRadioElemChoice = modeValue;
picker = document.getElementById("msgFcc"+aType+"Picker");
break;
case "messageArchives" :
gArchivesRadioElemChoice = modeValue;
picker = document.getElementById("msgArchives"+aType+"Picker");
updateArchiveHierarchyButton(folder);
break;
case "messageDrafts" :
gDraftsRadioElemChoice = modeValue;
picker = document.getElementById("msgDrafts"+aType+"Picker");
break;
case "messageTemplates" :
gTmplRadioElemChoice = modeValue;
picker = document.getElementById("msgStationery"+aType+"Picker");
break;
}
picker.folder = folder;
picker.menupopup.selectFolder(folder);
}
// Need to append special folders when account picker is selected.
// Create a set of global special folder vars to be suffixed to the
// server URI of the selected account.
function SetSpecialFolderNamesWithDelims()
{
var folderDelim = "/";
/* we use internal names known to everyone like "Sent", "Templates" and "Drafts" */
gFccFolderWithDelim = folderDelim + "Sent";
gArchivesFolderWithDelim = folderDelim + "Archives";
gDraftsFolderWithDelim = folderDelim + "Drafts";
gTemplatesFolderWithDelim = folderDelim + "Templates";
}
// Save all changes on this page
function onSave()
{
onSaveCopiesAndFolders();
}
function onSaveCopiesAndFolders()
{
SaveFolderSettings( gFccRadioElemChoice,
"doFcc",
gFccFolderWithDelim,
"msgFccAccountPicker",
"msgFccFolderPicker",
"identity.fccFolder",
"identity.fccFolderPickerMode" );
SaveFolderSettings( gArchivesRadioElemChoice,
"messageArchives",
gArchivesFolderWithDelim,
"msgArchivesAccountPicker",
"msgArchivesFolderPicker",
"identity.archiveFolder",
"identity.archivesFolderPickerMode" );
SaveFolderSettings( gDraftsRadioElemChoice,
"messageDrafts",
gDraftsFolderWithDelim,
"msgDraftsAccountPicker",
"msgDraftsFolderPicker",
"identity.draftFolder",
"identity.draftsFolderPickerMode" );
SaveFolderSettings( gTmplRadioElemChoice,
"messageTemplates",
gTemplatesFolderWithDelim,
"msgStationeryAccountPicker",
"msgStationeryFolderPicker",
"identity.stationeryFolder",
"identity.tmplFolderPickerMode" );
}
// Save folder settings and radio element choices
function SaveFolderSettings(radioElemChoice,
radioGroupId,
folderSuffix,
accountPickerId,
folderPickerId,
folderElementId,
folderPickerModeId)
{
var formElement = document.getElementById(folderElementId);
var uri;
if (radioElemChoice == "0" ||
!document.getElementById(folderPickerId).value) {
// Default or revert to default if no folder chosen.
radioElemChoice = "0";
uri = document.getElementById(accountPickerId).folder.URI;
if (uri) {
// Create Folder URI.
uri = uri + folderSuffix;
}
}
else if (radioElemChoice == "1") {
uri = document.getElementById(folderPickerId).folder.URI;
}
else {
dump ("Error saving folder preferences.\n");
return;
}
formElement.setAttribute("value", uri);
formElement = document.getElementById(folderPickerModeId);
formElement.setAttribute("value", radioElemChoice);
}
// Check the Fcc Self item and setup associated picker state
function setupFccItems()
{
var broadcaster = document.getElementById("broadcaster_doFcc");
var checked = document.getElementById("identity.doFcc").checked;
if (checked) {
broadcaster.removeAttribute("disabled");
switch (gFccRadioElemChoice) {
case "0" :
if (!gFccRadioElemChoiceLocked)
SetPickerEnabling("msgFccAccountPicker", "msgFccFolderPicker");
SetRadioButtons("fcc_selectAccount", "fcc_selectFolder");
break;
case "1" :
if (!gFccRadioElemChoiceLocked)
SetPickerEnabling("msgFccFolderPicker", "msgFccAccountPicker");
SetRadioButtons("fcc_selectFolder", "fcc_selectAccount");
break;
default :
dump("Error in setting Fcc elements.\n");
break;
}
}
else
broadcaster.setAttribute("disabled", "true");
}
// Disable CC textbox if CC checkbox is not checked
function setupCcTextbox(init)
{
var ccChecked = document.getElementById("identity.doCc").checked;
var ccTextbox = document.getElementById("identity.doCcList");
ccTextbox.disabled = !ccChecked;
if (ccChecked) {
if (ccTextbox.value == "") {
ccTextbox.value = document.getElementById("identity.email").value;
if (!init)
ccTextbox.select();
}
} else if ((ccTextbox.value == document.getElementById("identity.email").value) ||
(init && ccTextbox.getAttribute("value") == ""))
ccTextbox.value = "";
}
// Disable BCC textbox if BCC checkbox is not checked
function setupBccTextbox(init)
{
var bccChecked = document.getElementById("identity.doBcc").checked;
var bccTextbox = document.getElementById("identity.doBccList");
bccTextbox.disabled = !bccChecked;
if (bccChecked) {
if (bccTextbox.value == "") {
bccTextbox.value = document.getElementById("identity.email").value;
if (!init)
bccTextbox.select();
}
} else if ((bccTextbox.value == document.getElementById("identity.email").value) ||
(init && bccTextbox.getAttribute("value") == ""))
bccTextbox.value = "";
}
// Enable and disable pickers based on the radio element clicked
function SetPickerEnabling(enablePickerId, disablePickerId)
{
var activePicker = document.getElementById(enablePickerId);
activePicker.removeAttribute("disabled");
var inactivePicker = document.getElementById(disablePickerId);
inactivePicker.setAttribute("disabled", "true");
}
// Set radio element choices and picker states
function setPickersState(enablePickerId, disablePickerId, event)
{
SetPickerEnabling(enablePickerId, disablePickerId);
var radioElemValue = event.target.value;
switch (event.target.id) {
case "fcc_selectAccount":
case "fcc_selectFolder":
gFccRadioElemChoice = radioElemValue;
break;
case "archive_selectAccount":
case "archive_selectFolder":
gArchivesRadioElemChoice = radioElemValue;
updateArchiveHierarchyButton(document.getElementById(enablePickerId)
.folder);
break;
case "draft_selectAccount":
case "draft_selectFolder":
gDraftsRadioElemChoice = radioElemValue;
break;
case "tmpl_selectAccount":
case "tmpl_selectFolder":
gTmplRadioElemChoice = radioElemValue;
break;
default:
dump("Error in setting picker state.\n");
return;
}
}
// This routine is to restore the correct radio element
// state when the fcc self checkbox broadcasts the change
function SetRadioButtons(selectPickerId, unselectPickerId)
{
var activeRadioElem = document.getElementById(selectPickerId);
activeRadioElem.radioGroup.selectedItem = activeRadioElem;
}
/**
* Enable/disable the archive hierarchy button depending on what folder is
* currently selected (Gmail IMAP folders should have the button disabled, since
* changing the archive hierarchy does nothing there.
*
* @param archiveFolder the currently-selected folder to store archives in
*/
function updateArchiveHierarchyButton(archiveFolder) {
let isGmailImap = (archiveFolder.server.type == "imap" &&
archiveFolder.server.QueryInterface(
Components.interfaces.nsIImapIncomingServer)
.isGMailServer);
document.getElementById("archiveHierarchyButton").disabled = isGmailImap;
}
/**
* Enable or disable (as appropriate) the controls for setting archive options
*/
function setupArchiveItems() {
let broadcaster = document.getElementById("broadcaster_archiveEnabled");
let checked = document.getElementById("identity.archiveEnabled").checked;
let archiveFolder;
if (checked) {
broadcaster.removeAttribute("disabled");
switch (gArchivesRadioElemChoice) {
case "0":
if (!gArchivesRadioElemChoiceLocked)
SetPickerEnabling("msgArchivesAccountPicker", "msgArchivesFolderPicker");
SetRadioButtons("archive_selectAccount", "archive_selectFolder");
updateArchiveHierarchyButton(document.getElementById(
"msgArchivesAccountPicker").folder);
break;
case "1":
if (!gArchivesRadioElemChoiceLocked)
SetPickerEnabling("msgArchivesFolderPicker", "msgArchivesAccountPicker");
SetRadioButtons("archive_selectFolder", "archive_selectAccount");
updateArchiveHierarchyButton(document.getElementById(
"msgArchivesFolderPicker").folder);
break;
default:
dump("Error in setting Archive elements.\n");
return;
}
}
else
broadcaster.setAttribute("disabled", "true");
}
/**
* Open a dialog to edit the folder hierarchy used when archiving messages.
*/
function ChangeArchiveHierarchy() {
let identity = parent.gIdentity || parent.getCurrentAccount().defaultIdentity;
top.window.openDialog("chrome://messenger/content/am-archiveoptions.xul",
"", "centerscreen,chrome,modal,titlebar,resizable=yes",
identity);
return true;
}

View file

@ -0,0 +1,21 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xul-overlay href="chrome://messenger/content/am-copiesOverlay.xul"?>
<!DOCTYPE page SYSTEM "chrome://messenger/locale/am-copies.dtd">
<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&copyAndFolderTitle.label;"
onload="parent.onPanelLoaded('am-copies.xul');">
<vbox flex="1" style="overflow: auto;">
<script type="application/javascript" src="chrome://messenger/content/AccountManager.js"/>
<dialogheader title="&copyAndFolderTitle.label;"/>
<vbox id="copiesAndFolders"/>
</vbox>
</page>

View file

@ -0,0 +1,311 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/messenger.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/folderMenus.css" type="text/css"?>
<!DOCTYPE overlay [
<!ENTITY % copiesDTD SYSTEM "chrome://messenger/locale/am-copies.dtd">
%copiesDTD;
]>
<overlay xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://messenger/content/am-copies.js"/>
<script type="application/javascript" src="chrome://messenger/content/amUtils.js"/>
<vbox flex="1" id="copiesAndFolders">
<stringbundleset id="stringbundleset">
<stringbundle id="bundle_messenger" src="chrome://messenger/locale/messenger.properties"/>
</stringbundleset>
<broadcaster id="broadcaster_doFcc"/>
<broadcaster id="broadcaster_archiveEnabled"/>
<label hidden="true" wsm_persist="true" id="identity.fccFolder"
pref="true" preftype="string" prefattribute="value"
prefstring="mail.identity.%identitykey%.fcc_folder"/>
<label hidden="true" wsm_persist="true" id="identity.draftFolder"
pref="true" preftype="string" prefattribute="value"
prefstring="mail.identity.%identitykey%.draft_folder"/>
<label hidden="true" wsm_persist="true" id="identity.archiveFolder"
pref="true" preftype="string" prefattribute="value"
prefstring="mail.identity.%identitykey%.archive_folder"/>
<label hidden="true" wsm_persist="true" id="identity.stationeryFolder"
pref="true" preftype="string" prefattribute="value"
prefstring="mail.identity.%identitykey%.stationary_folder"/>
<label hidden="true" wsm_persist="true" id="identity.email"/>
<label hidden="true" wsm_persist="true" id="identity.fccFolderPickerMode"
pref="true" preftype="int" prefattribute="value"
prefstring="mail.identity.%identitykey%.fcc_folder_picker_mode"/>
<label hidden="true" wsm_persist="true" id="identity.draftsFolderPickerMode"
pref="true" preftype="int" prefattribute="value"
prefstring="mail.identity.%identitykey%.drafts_folder_picker_mode"/>
<label hidden="true" wsm_persist="true" id="identity.archivesFolderPickerMode"
pref="true" preftype="int" prefattribute="value"
prefstring="mail.identity.%identitykey%.archives_folder_picker_mode"/>
<label hidden="true" wsm_persist="true" id="identity.tmplFolderPickerMode"
pref="true" preftype="int" prefattribute="value"
prefstring="mail.identity.%identitykey%.tmpl_folder_picker_mode"/>
<groupbox id="copiesGroup">
<caption label="&sendingPrefix.label;"/>
<hbox align="center">
<checkbox wsm_persist="true" id="identity.doFcc" label="&fccMailFolder.label;"
accesskey="&fccMailFolder.accesskey;"
prefattribute="value"
prefstring="mail.identity.%identitykey%.fcc"
oncommand="setupFccItems();"/>
</hbox>
<radiogroup id="doFcc" aria-labelledby="identity.doFcc">
<grid class="specialFolderPickerGrid">
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<radio id="fcc_selectAccount"
value="0" label="&sentFolderOn.label;"
accesskey="&sentFolderOn.accesskey;"
oncommand="setPickersState('msgFccAccountPicker', 'msgFccFolderPicker', event)"
observes="broadcaster_doFcc"/>
<menulist id="msgFccAccountPicker"
class="folderMenuItem"
aria-labelledby="fcc_selectAccount"
observes="broadcaster_doFcc">
<menupopup id="msgFccAccountPopup" type="folder" mode="filing"
expandFolders="false"
oncommand="noteSelectionChange('fcc', 'Account', event)"/>
</menulist>
</row>
<row align="center">
<radio id="fcc_selectFolder"
value="1" label="&sentInOtherFolder.label;"
accesskey="&sentInOtherFolder.accesskey;"
oncommand="setPickersState('msgFccFolderPicker', 'msgFccAccountPicker', event)"
observes="broadcaster_doFcc"/>
<menulist id="msgFccFolderPicker"
class="folderMenuItem"
aria-labelledby="fcc_selectFolder"
displayformat="verbose"
observes="broadcaster_doFcc">
<menupopup id="msgFccFolderPopup" type="folder" mode="filing"
class="menulist-menupopup"
showFileHereLabel="true"
oncommand="noteSelectionChange('fcc', 'Folder', event)"/>
</menulist>
</row>
</rows>
</grid>
</radiogroup>
<hbox align="center" class="fccReplyFollowsParent" hidable="true" hidefor="nntp,rss">
<checkbox wsm_persist="true" id="identity.fccReplyFollowsParent"
label="&fccReplyFollowsParent.label;"
accesskey="&fccReplyFollowsParent.accesskey;"
prefattribute="value"
prefstring="mail.identity.%identitykey%.fcc_reply_follows_parent"
observes="broadcaster_doFcc"/>
</hbox>
<grid>
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<checkbox wsm_persist="true" id="identity.doCc" label="&ccAddress.label;"
accesskey="&ccAddress.accesskey;"
control="identity.doCcList"
oncommand="setupCcTextbox();"
prefattribute="value"
prefstring="mail.identity.%identitykey%.doCc"/>
<textbox wsm_persist="true" id="identity.doCcList" flex="1"
aria-labelledby="identity.doCc"
prefstring="mail.identity.%identitykey%.doCcList" class="uri-element"
placeholder="&ccAddressList.placeholder;"/>
</row>
<row align="center">
<checkbox wsm_persist="true" id="identity.doBcc" label="&bccAddress.label;"
accesskey="&bccAddress.accesskey;"
control="identity.doBccList"
oncommand="setupBccTextbox();"
prefattribute="value"
prefstring="mail.identity.%identitykey%.doBcc"/>
<textbox wsm_persist="true" id="identity.doBccList" flex="1"
aria-labelledby="identity.doBcc"
prefstring="mail.identity.%identitykey%.doBccList" class="uri-element"
placeholder="&bccAddressList.placeholder;"/>
</row>
</rows>
</grid>
</groupbox>
<groupbox id="archivesGroup">
<caption label="&archivesTitle.label;"/>
<hbox align="center">
<checkbox wsm_persist="true" id="identity.archiveEnabled"
label="&keepArchives.label;"
accesskey="&keepArchives.accesskey;"
prefattribute="value"
prefstring="mail.identity.%identitykey%.archive_enabled"
oncommand="setupArchiveItems();"/>
<spacer flex="1"/>
<button id="archiveHierarchyButton"
label="&archiveHierarchyButton.label;"
accesskey="&archiveHierarchyButton.accesskey;"
oncommand="ChangeArchiveHierarchy();"
observes="broadcaster_archiveEnabled"/>
</hbox>
<radiogroup id="messageArchives">
<grid class="specialFolderPickerGrid">
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<radio id="archive_selectAccount"
value="0" label="&archivesFolderOn.label;"
accesskey="&archivesFolderOn.accesskey;"
oncommand="setPickersState('msgArchivesAccountPicker', 'msgArchivesFolderPicker', event)"
observes="broadcaster_archiveEnabled"/>
<menulist id="msgArchivesAccountPicker"
class="folderMenuItem"
aria-labelledby="archive_selectAccount"
observes="broadcaster_archiveEnabled">
<menupopup id="msgArchivesAccountPopup" type="folder" mode="filing"
expandFolders="false"
oncommand="noteSelectionChange('archive', 'Account', event)"/>
</menulist>
</row>
<row align="center">
<radio id="archive_selectFolder"
value="1" label="&archiveInOtherFolder.label;"
accesskey="&archiveInOtherFolder.accesskey;"
oncommand="setPickersState('msgArchivesFolderPicker', 'msgArchivesAccountPicker', event)"
observes="broadcaster_archiveEnabled"/>
<menulist id="msgArchivesFolderPicker"
class="folderMenuItem"
aria-labelledby="archive_selectFolder"
displayformat="verbose"
observes="broadcaster_archiveEnabled">
<menupopup id="msgArchivesFolderPopup" type="folder" mode="filing"
class="menulist-menupopup"
showFileHereLabel="true"
oncommand="noteSelectionChange('archive', 'Folder', event)"/>
</menulist>
</row>
</rows>
</grid>
</radiogroup>
</groupbox>
<groupbox id="foldersGroup">
<caption label="&specialFolders.label;"/>
<hbox align="center">
<label value="&keepDrafts2.label;" control="messageDrafts"/>
</hbox>
<radiogroup id="messageDrafts">
<grid class="specialFolderPickerGrid">
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<radio id="draft_selectAccount"
oncommand="setPickersState('msgDraftsAccountPicker', 'msgDraftsFolderPicker', event)"
value="0" label="&draftsFolderOn.label;"
accesskey="&draftsFolderOn.accesskey;"/>
<menulist id="msgDraftsAccountPicker"
class="folderMenuItem"
aria-labelledby="draft_selectAccount">
<menupopup id="msgDraftAccountPopup" type="folder" mode="filing"
expandFolders="false"
oncommand="noteSelectionChange('draft', 'Account', event)"/>
</menulist>
</row>
<row align="center">
<radio id="draft_selectFolder"
oncommand="setPickersState('msgDraftsFolderPicker', 'msgDraftsAccountPicker', event)"
value="1" label="&draftInOtherFolder.label;"
accesskey="&draftInOtherFolder.accesskey;"/>
<menulist id="msgDraftsFolderPicker"
class="folderMenuItem"
aria-labelledby="draft_selectFolder"
displayformat="verbose">
<menupopup id="msgDraftFolderPopup" type="folder" mode="filing"
class="menulist-menupopup"
showFileHereLabel="true"
oncommand="noteSelectionChange('draft', 'Folder', event)"/>
</menulist>
</row>
</rows>
</grid>
</radiogroup>
<hbox align="center">
<label value="&keepTemplates.label;" control="messageTemplates"/>
</hbox>
<radiogroup id="messageTemplates">
<grid class="specialFolderPickerGrid">
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<radio id="tmpl_selectAccount"
oncommand="setPickersState('msgStationeryAccountPicker', 'msgStationeryFolderPicker', event)"
value="0" label="&templatesFolderOn.label;"
accesskey="&templatesFolderOn.accesskey;"/>
<menulist id="msgStationeryAccountPicker"
class="folderMenuItem"
aria-labelledby="tmpl_selectAccount">
<menupopup id="msgFccAccountPopup" type="folder" mode="filing"
expandFolders="false"
oncommand="noteSelectionChange('tmpl', 'Account', event)"/>
</menulist>
</row>
<row align="center">
<radio id="tmpl_selectFolder"
oncommand="setPickersState('msgStationeryFolderPicker', 'msgStationeryAccountPicker', event)"
value="1" label="&templateInOtherFolder.label;"
accesskey="&templateInOtherFolder.accesskey;"/>
<menulist id="msgStationeryFolderPicker"
class="folderMenuItem"
aria-labelledby="tmpl_selectFolder"
displayformat="verbose">
<menupopup id="msgTemplFolderPopup" type="folder" mode="filing"
class="menulist-menupopup"
showFileHereLabel="true"
oncommand="noteSelectionChange('tmpl', 'Folder', event)"/>
</menulist>
</row>
</rows>
</grid>
</radiogroup>
<hbox align="center">
<checkbox wsm_persist="true" id="identity.showSaveMsgDlg" label="&saveMessageDlg.label;"
accesskey="&saveMessageDlg.accesskey;"
prefattribute="value"
prefstring="mail.identity.%identitykey%.showSaveMsgDlg"/>
</hbox>
</groupbox>
</vbox>
</overlay>

View file

@ -0,0 +1,76 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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/. */
/**
* Key value pairs to derive the tag based on the page loaded.
* Each key is the page loaded when user clicks on one of the items on
* the accounttree of the AccountManager window.
* Value is a tag that is preset which will be used to display
* context sensitive help.
*/
var pageTagPairs = {
"chrome://messenger/content/am-main.xul": "mail_account_identity",
"chrome://messenger/content/am-server.xul": "mail",
"chrome://messenger/content/am-copies.xul": "mail_copies",
"chrome://messenger/content/am-addressing.xul": "mail_addressing_settings",
"chrome://messenger/content/am-junk.xul": "mail-account-junk",
"chrome://messenger/content/am-offline.xul": "mail-offline-accounts",
"chrome://messenger/content/am-smtp.xul": "mail_smtp",
"chrome://messenger/content/am-smime.xul": "mail_security_settings",
"chrome://messenger/content/am-serverwithnoidentities.xul": "mail_local_folders_settings",
"chrome://messenger/content/am-mdn.xul": "mail-account-receipts",
}
function doHelpButton()
{
// Get the URI of the page loaded in the AccountManager's content frame.
var pageSourceURI = contentFrame.location.href;
// Get the help tag corresponding to the page loaded.
var helpTag = pageTagPairs[pageSourceURI];
// If the help tag is generic or offline, check if there is a need to set tags per server type
if ((helpTag == "mail") || (helpTag == "mail-offline-accounts")) {
// Get server type, as we may need to set help tags per server type for some pages
var serverType = GetServerType();
/**
* Check the page to be loaded. Following pages needed to be presented with the
* help content that is based on server type. For any pages with such requirement
* do add comments here about the page and a new case statement for pageSourceURI
* switch.
* - server settings ("chrome://messenger/content/am-server.xul")
* - offline/diskspace settings ("chrome://messenger/content/am-offline.xul")
*/
switch (pageSourceURI) {
case "chrome://messenger/content/am-server.xul":
helpTag = "mail_server_" + serverType;
break;
case "chrome://messenger/content/am-offline.xul":
helpTag = "mail_offline_" + serverType;
break;
default :
break;
}
}
if ( helpTag )
openHelp(helpTag);
else
openHelp('mail');
}
/**
* Get server type of the seleted item
*/
function GetServerType()
{
var serverType = null;
var currentAccount = parent.getCurrentAccount();
if (currentAccount)
serverType = currentAccount.incomingServer.type;
return serverType;
}

View file

@ -0,0 +1,180 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
Components.utils.import("resource:///modules/iteratorUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
var gIdentityListBox; // the root <listbox> node
var gAddButton;
var gEditButton;
var gSetDefaultButton;
var gDeleteButton;
var gAccount = null; // the account we are showing the identities for
function onLoad()
{
gIdentityListBox = document.getElementById("identitiesList");
gAddButton = document.getElementById("cmd_add");
gEditButton = document.getElementById("cmd_edit");
gSetDefaultButton = document.getElementById("cmd_default");
gDeleteButton = document.getElementById("cmd_delete");
// extract the account
gAccount = window.arguments[0].account;
var accountName = window.arguments[0].accountName;
document.title = document.getElementById("bundle_prefs")
.getFormattedString("identity-list-title", [accountName]);
refreshIdentityList(0);
}
/**
* Rebuilds the listbox holding the list of identities.
*
* @param aSelectIndex Attempt to select the identity with this index.
*/
function refreshIdentityList(aSelectIndex)
{
// Remove all children.
while (gIdentityListBox.hasChildNodes())
gIdentityListBox.lastChild.remove();
// Build the list from the identities array.
let identities = gAccount.identities;
for (let identity in fixIterator(identities,
Components.interfaces.nsIMsgIdentity))
{
if (identity.valid)
{
let listitem = document.createElement("listitem");
listitem.setAttribute("label", identity.identityName);
listitem.setAttribute("key", identity.key);
gIdentityListBox.appendChild(listitem);
}
}
// Ensure one identity is always selected.
if (!aSelectIndex || aSelectIndex < 0)
aSelectIndex = 0;
else if (aSelectIndex >= gIdentityListBox.itemCount)
aSelectIndex = gIdentityListBox.itemCount - 1;
// This also fires the onselect event, which in turn calls updateButtons().
gIdentityListBox.selectedIndex = aSelectIndex;
}
/**
* Opens the identity editor dialog.
*
* @param identity the identity (if any) to load in the dialog
*/
function openIdentityEditor(identity)
{
let args = { identity: identity, account: gAccount, result: false };
let indexToSelect = identity ? gIdentityListBox.selectedIndex :
gIdentityListBox.itemCount;
window.openDialog("am-identity-edit.xul", "",
"chrome,modal,resizable,centerscreen", args);
if (args.result)
refreshIdentityList(indexToSelect);
}
function getSelectedIdentity()
{
if (gIdentityListBox.selectedItems.length != 1)
return null;
var identityKey = gIdentityListBox.selectedItems[0].getAttribute("key");
let identities = gAccount.identities;
for (let identity in fixIterator(identities,
Components.interfaces.nsIMsgIdentity))
{
if (identity.valid && identity.key == identityKey)
return identity;
}
return null; // no identity found
}
function onEdit(event)
{
var id = (event.target.localName == 'listbox') ? null : getSelectedIdentity();
openIdentityEditor(id);
}
/**
* Enable/disable buttons depending on number of identities and current selection.
*/
function updateButtons()
{
// In this listbox there should always be one item selected.
if (gIdentityListBox.selectedItems.length != 1 || gIdentityListBox.itemCount == 0) {
// But in case this is not met (e.g. there is no identity for some reason,
// or the list is being rebuilt), disable all buttons.
gEditButton.setAttribute("disabled", "true");
gDeleteButton.setAttribute("disabled", "true");
gSetDefaultButton.setAttribute("disabled", "true");
return;
}
gEditButton.setAttribute("disabled", "false");
gDeleteButton.setAttribute("disabled", (gIdentityListBox.itemCount <= 1) ? "true" : "false");
gSetDefaultButton.setAttribute("disabled", (gIdentityListBox.selectedIndex == 0) ? "true" : "false");
// The Add command is always enabled.
}
function onSetDefault(event)
{
let identity = getSelectedIdentity();
if (!identity)
return;
// If the first identity is selected, there is nothing to do.
if (gIdentityListBox.selectedIndex == 0)
return;
gAccount.defaultIdentity = identity;
// Rebuilt the identity list and select the moved identity again.
refreshIdentityList(0);
}
function onDelete(event)
{
if (gIdentityListBox.itemCount <= 1) // don't support deleting the last identity
return;
// get delete confirmation
let selectedIdentity = getSelectedIdentity();
let prefsBundle = document.getElementById("bundle_prefs");
let confirmTitle = prefsBundle.getFormattedString("identity-delete-confirm-title",
[window.arguments[0].accountName]);
let confirmText = prefsBundle.getFormattedString("identity-delete-confirm",
[selectedIdentity.identityName]);
let confirmButton = prefsBundle.getString("identity-delete-confirm-button");
if (Services.prompt.confirmEx(window, confirmTitle, confirmText,
(Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING) +
(Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_CANCEL),
confirmButton, null, null, null, {}))
return;
let selectedItemIndex = gIdentityListBox.selectedIndex;
gAccount.removeIdentity(selectedIdentity);
refreshIdentityList(selectedItemIndex);
}
function onOk()
{
window.arguments[0].result = true;
return true;
}

View file

@ -0,0 +1,67 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://messenger/skin/messenger.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
<!-- 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/. -->
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/am-identities-list.dtd">
<dialog
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="onLoad();"
buttons="accept"
buttonlabelaccept="&identitiesListClose.label;"
buttonaccesskeyaccept="&identitiesListClose.accesskey;"
ondialogaccept="return onOk();"
ondialogcancel="return onOk();"
style="width: 40em;">
<stringbundle id="bundle_prefs" src="chrome://messenger/locale/prefs.properties"/>
<script type="application/javascript"
src="chrome://messenger/content/am-identities-list.js"/>
<commandset>
<command id="cmd_add" oncommand="openIdentityEditor(null);"/>
<command id="cmd_edit" oncommand="onEdit(event);" disabled="true"/>
<command id="cmd_default" oncommand="onSetDefault(event);" disabled="true"/>
<command id="cmd_delete" oncommand="onDelete(event);" disabled="true"/>
</commandset>
<keyset>
<key keycode="VK_INSERT" command="cmd_add"/>
<key keycode="VK_DELETE" command="cmd_delete"/>
</keyset>
<label control="identitiesList">&identitiesListManageDesc.label;</label>
<separator class="thin"/>
<hbox flex="1">
<listbox id="identitiesList"
ondblclick="onEdit(event);"
onselect="updateButtons();"
seltype="single"
flex="1"
style="height: 0px;"/>
<vbox>
<button id="addButton"
command="cmd_add" label="&identitiesListAdd.label;"
accesskey="&identitiesListAdd.accesskey;"/>
<button id="editButton" disabled="true"
command="cmd_edit" label="&identitiesListEdit.label;"
accesskey="&identitiesListEdit.accesskey;"/>
<button id="setDefaultButton" disabled="true"
command="cmd_default" label="&identitiesListDefault.label;"
accesskey="&identitiesListDefault.accesskey;"/>
<button id="deleteButton" disabled="true"
command="cmd_delete" label="&identitiesListDelete.label;"
accesskey="&identitiesListDelete.accesskey;"/>
</vbox>
</hbox>
</dialog>

View file

@ -0,0 +1,405 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
Components.utils.import("resource:///modules/mailServices.js");
Components.utils.import("resource://gre/modules/Services.jsm");
var gIdentity = null; // the identity we are editing (may be null for a new identity)
var gAccount = null; // the account the identity is (or will be) associated with
function onLoadIdentityProperties()
{
// extract the account
gIdentity = window.arguments[0].identity;
gAccount = window.arguments[0].account;
let prefBundle = document.getElementById("bundle_prefs");
// Make the dialog the same height and 90% of the width of the main Account
// manager page when the Account manager is not maximized.
let accountDialog = Services.wm.getMostRecentWindow("mailnews:accountmanager")
.document;
if (accountDialog.documentElement.getAttribute("sizemode") != "maximized") {
document.getElementById("identityDialog").style.width =
accountDialog.getElementById("accountManager").clientWidth * 0.9 + "px";
document.getElementById("identityDialog").style.height =
accountDialog.getElementById("accountManager").clientHeight + "px";
}
if (gIdentity) {
let listName = gIdentity.identityName;
document.title = prefBundle
.getFormattedString("identityDialogTitleEdit", [listName]);
} else {
document.title = prefBundle.getString("identityDialogTitleAdd");
}
loadSMTPServerList();
initIdentityValues(gIdentity);
initCopiesAndFolder(gIdentity);
initCompositionAndAddressing(gIdentity);
}
// based on the values of gIdentity, initialize the identity fields we expose to the user
function initIdentityValues(identity)
{
function initSmtpServer(aServerKey) {
// Select a server in the SMTP server menulist by its key.
// The value of the identity.smtpServerKey is null when the
// "use default server" option is used so, if we get that passed in, select
// the useDefaultItem representing this option by using the value of "".
document.getElementById("identity.smtpServerKey").value = aServerKey || "";
}
if (identity)
{
document.getElementById('identity.fullName').value = identity.fullName;
document.getElementById('identity.email').value = identity.email;
document.getElementById('identity.replyTo').value = identity.replyTo;
document.getElementById('identity.organization').value = identity.organization;
document.getElementById('identity.attachSignature').checked = identity.attachSignature;
document.getElementById('identity.htmlSigText').value = identity.htmlSigText;
document.getElementById('identity.htmlSigFormat').checked = identity.htmlSigFormat;
if (identity.signature)
document.getElementById('identity.signature').value = identity.signature.path;
document.getElementById('identity.attachVCard').checked = identity.attachVCard;
document.getElementById('identity.escapedVCard').value = identity.escapedVCard;
initSmtpServer(identity.smtpServerKey);
// This field does not exist for the default identity shown in the am-main.xul pane.
let idLabel = document.getElementById("identity.label");
if (idLabel)
idLabel.value = identity.label;
}
else
{
// We're adding an identity, use the best default we have.
initSmtpServer(gAccount.defaultIdentity.smtpServerKey);
}
setupSignatureItems();
}
function initCopiesAndFolder(identity)
{
// if we are editing an existing identity, use it...otherwise copy our values from the default identity
var copiesAndFoldersIdentity = identity ? identity : gAccount.defaultIdentity;
document.getElementById('identity.fccFolder').value = copiesAndFoldersIdentity.fccFolder;
document.getElementById('identity.draftFolder').value = copiesAndFoldersIdentity.draftFolder;
document.getElementById('identity.archiveFolder').value = copiesAndFoldersIdentity.archiveFolder;
document.getElementById('identity.stationeryFolder').value = copiesAndFoldersIdentity.stationeryFolder;
document.getElementById('identity.fccFolderPickerMode').value = copiesAndFoldersIdentity.fccFolderPickerMode ? copiesAndFoldersIdentity.fccFolderPickerMode : 0;
document.getElementById('identity.draftsFolderPickerMode').value = copiesAndFoldersIdentity.draftsFolderPickerMode ? copiesAndFoldersIdentity.draftsFolderPickerMode : 0;
document.getElementById('identity.archivesFolderPickerMode').value = copiesAndFoldersIdentity.archivesFolderPickerMode ? copiesAndFoldersIdentity.archivesFolderPickerMode : 0;
document.getElementById('identity.tmplFolderPickerMode').value = copiesAndFoldersIdentity.tmplFolderPickerMode ? copiesAndFoldersIdentity.tmplFolderPickerMode : 0;
document.getElementById('identity.doCc').checked = copiesAndFoldersIdentity.doCc;
document.getElementById('identity.doCcList').value = copiesAndFoldersIdentity.doCcList;
document.getElementById('identity.doBcc').checked = copiesAndFoldersIdentity.doBcc;
document.getElementById('identity.doBccList').value = copiesAndFoldersIdentity.doBccList;
document.getElementById('identity.doFcc').checked = copiesAndFoldersIdentity.doFcc;
document.getElementById('identity.fccReplyFollowsParent').checked = copiesAndFoldersIdentity.fccReplyFollowsParent;
document.getElementById('identity.showSaveMsgDlg').checked = copiesAndFoldersIdentity.showSaveMsgDlg;
document.getElementById('identity.archiveEnabled').checked = copiesAndFoldersIdentity.archiveEnabled;
onInitCopiesAndFolders(); // am-copies.js method
}
function initCompositionAndAddressing(identity)
{
// if we are editing an existing identity, use it...otherwise copy our values from the default identity
var addressingIdentity = identity ? identity : gAccount.defaultIdentity;
document.getElementById('identity.directoryServer').value = addressingIdentity.directoryServer;
document.getElementById('identity.overrideGlobal_Pref').value = addressingIdentity.overrideGlobalPref;
let autoCompleteElement = document.getElementById('identity.autocompleteToMyDomain');
if (autoCompleteElement) // Thunderbird does not have this element.
autoCompleteElement.checked = addressingIdentity.autocompleteToMyDomain;
document.getElementById('identity.composeHtml').checked = addressingIdentity.composeHtml;
document.getElementById('identity.autoQuote').checked = addressingIdentity.autoQuote;
document.getElementById('identity.replyOnTop').value = addressingIdentity.replyOnTop;
document.getElementById('identity.sig_bottom').value = addressingIdentity.sigBottom;
document.getElementById('identity.sig_on_reply').checked = addressingIdentity.sigOnReply;
document.getElementById('identity.sig_on_fwd').checked = addressingIdentity.sigOnForward;
onInitCompositionAndAddressing(); // am-addressing.js method
}
function onOk()
{
if (!validEmailAddress())
return false;
// if we are adding a new identity, create an identity, set the fields and add it to the
// account.
if (!gIdentity)
{
// ask the account manager to create a new identity for us
gIdentity = MailServices.accounts.createIdentity();
// copy in the default identity settings so we inherit lots of stuff like the defaul drafts folder, etc.
gIdentity.copy(gAccount.defaultIdentity);
// assume the identity is valid by default?
gIdentity.valid = true;
// add the identity to the account
gAccount.addIdentity(gIdentity);
// now fall through to saveFields which will save our new values
}
// if we are modifying an existing identity, save the fields
saveIdentitySettings(gIdentity);
saveCopiesAndFolderSettings(gIdentity);
saveAddressingAndCompositionSettings(gIdentity);
window.arguments[0].result = true;
return true;
}
// returns false and prompts the user if
// the identity does not have an email address
function validEmailAddress()
{
var emailAddress = document.getElementById('identity.email').value;
// quickly test for an @ sign to test for an email address. We don't have
// to be anymore precise than that.
if (!emailAddress.includes("@"))
{
// alert user about an invalid email address
var prefBundle = document.getElementById("bundle_prefs");
Services.prompt.alert(window, prefBundle.getString("identity-edit-req-title"),
prefBundle.getString("identity-edit-req"));
return false;
}
return true;
}
function saveIdentitySettings(identity)
{
if (identity)
{
let idLabel = document.getElementById('identity.label');
if (idLabel)
identity.label = idLabel.value;
identity.fullName = document.getElementById('identity.fullName').value;
identity.email = document.getElementById('identity.email').value;
identity.replyTo = document.getElementById('identity.replyTo').value;
identity.organization = document.getElementById('identity.organization').value;
identity.attachSignature = document.getElementById('identity.attachSignature').checked;
identity.htmlSigText = document.getElementById('identity.htmlSigText').value;
identity.htmlSigFormat = document.getElementById('identity.htmlSigFormat').checked;
identity.attachVCard = document.getElementById('identity.attachVCard').checked;
identity.escapedVCard = document.getElementById('identity.escapedVCard').value;
identity.smtpServerKey = document.getElementById('identity.smtpServerKey').value;
var attachSignaturePath = document.getElementById('identity.signature').value;
identity.signature = null; // this is important so we don't accidentally inherit the default
if (attachSignaturePath)
{
// convert signature path back into a nsIFile
var sfile = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsIFile);
sfile.initWithPath(attachSignaturePath);
if (sfile.exists())
identity.signature = sfile;
}
}
}
function saveCopiesAndFolderSettings(identity)
{
onSaveCopiesAndFolders(); // am-copies.js routine
identity.fccFolder = document.getElementById('identity.fccFolder').value;
identity.draftFolder = document.getElementById('identity.draftFolder').value;
identity.archiveFolder = document.getElementById('identity.archiveFolder').value;
identity.stationeryFolder = document.getElementById('identity.stationeryFolder').value;
identity.fccFolderPickerMode = document.getElementById('identity.fccFolderPickerMode').value;
identity.draftsFolderPickerMode = document.getElementById('identity.draftsFolderPickerMode').value;
identity.archivesFolderPickerMode = document.getElementById('identity.archivesFolderPickerMode').value;
identity.tmplFolderPickerMode = document.getElementById('identity.tmplFolderPickerMode').value;
identity.doCc = document.getElementById('identity.doCc').checked;
identity.doCcList = document.getElementById('identity.doCcList').value;
identity.doBcc = document.getElementById('identity.doBcc').checked;
identity.doBccList = document.getElementById('identity.doBccList').value;
identity.doFcc = document.getElementById('identity.doFcc').checked;
identity.fccReplyFollowsParent = document.getElementById('identity.fccReplyFollowsParent').checked;
identity.showSaveMsgDlg = document.getElementById('identity.showSaveMsgDlg').checked;
identity.archiveEnabled = document.getElementById('identity.archiveEnabled').checked;
}
function saveAddressingAndCompositionSettings(identity)
{
identity.directoryServer = document.getElementById('identity.directoryServer').value;
identity.overrideGlobalPref = document.getElementById('identity.overrideGlobal_Pref').value == "true";
let autoCompleteElement = document.getElementById('identity.autocompleteToMyDomain');
if (autoCompleteElement) // Thunderbird does not have this element.
identity.autocompleteToMyDomain = autoCompleteElement.checked;
identity.composeHtml = document.getElementById('identity.composeHtml').checked;
identity.autoQuote = document.getElementById('identity.autoQuote').checked;
identity.replyOnTop = document.getElementById('identity.replyOnTop').value;
identity.sigBottom = document.getElementById('identity.sig_bottom').value == 'true';
identity.sigOnReply = document.getElementById('identity.sig_on_reply').checked;
identity.sigOnForward = document.getElementById('identity.sig_on_fwd').checked;
}
function selectFile()
{
const nsIFilePicker = Components.interfaces.nsIFilePicker;
var fp = Components.classes["@mozilla.org/filepicker;1"]
.createInstance(nsIFilePicker);
var prefBundle = document.getElementById("bundle_prefs");
var title = prefBundle.getString("choosefile");
fp.init(window, title, nsIFilePicker.modeOpen);
fp.appendFilters(nsIFilePicker.filterAll);
// Get current signature folder, if there is one.
// We can set that to be the initial folder so that users
// can maintain their signatures better.
var sigFolder = GetSigFolder();
if (sigFolder)
fp.displayDirectory = sigFolder;
var ret = fp.show();
if (ret == nsIFilePicker.returnOK) {
var folderField = document.getElementById("identity.signature");
folderField.value = fp.file.path;
}
}
function GetSigFolder()
{
var sigFolder = null;
try
{
var account = parent.getCurrentAccount();
var identity = account.defaultIdentity;
var signatureFile = identity.signature;
if (signatureFile)
{
signatureFile = signatureFile.QueryInterface(Components.interfaces.nsIFile);
sigFolder = signatureFile.parent;
if (!sigFolder.exists())
sigFolder = null;
}
}
catch (ex) {
dump("failed to get signature folder..\n");
}
return sigFolder;
}
// Signature textbox is active unless option to select from file is checked.
// If a signature is need to be attached, the associated items which
// displays the absolute path to the signature (in a textbox) and the way
// to select a new signature file (a button) are enabled. Otherwise, they
// are disabled. Check to see if the attachSignature is locked to block
// broadcasting events.
function setupSignatureItems()
{
var signature = document.getElementById("identity.signature");
var browse = document.getElementById("identity.sigbrowsebutton");
var htmlSigText = document.getElementById("identity.htmlSigText");
var htmlSigFormat = document.getElementById("identity.htmlSigFormat");
var attachSignature = document.getElementById("identity.attachSignature");
var checked = attachSignature.checked;
if (checked)
{
htmlSigText.setAttribute("disabled", "true");
htmlSigFormat.setAttribute("disabled", "true");
}
else
{
htmlSigText.removeAttribute("disabled");
htmlSigFormat.removeAttribute("disabled");
}
if (checked && !getAccountValueIsLocked(signature))
signature.removeAttribute("disabled");
else
signature.setAttribute("disabled", "true");
if (checked && !getAccountValueIsLocked(browse))
browse.removeAttribute("disabled");
else
browse.setAttribute("disabled", "true");
}
function editVCardCallback(escapedVCardStr)
{
var escapedVCard = document.getElementById("identity.escapedVCard");
escapedVCard.value = escapedVCardStr;
}
function editVCard()
{
var escapedVCard = document.getElementById("identity.escapedVCard");
// read vCard hidden value from UI
window.openDialog("chrome://messenger/content/addressbook/abNewCardDialog.xul",
"",
"chrome,modal,resizable=no,centerscreen",
{escapedVCardStr:escapedVCard.value, okCallback:editVCardCallback,
titleProperty:"editVCardTitle", hideABPicker:true});
}
function getAccountForFolderPickerState()
{
return gAccount;
}
/**
* Build the SMTP server list for display.
*/
function loadSMTPServerList()
{
var smtpServerList = document.getElementById("identity.smtpServerKey");
let servers = MailServices.smtp.servers;
let defaultServer = MailServices.smtp.defaultServer;
var smtpPopup = smtpServerList.menupopup;
while (smtpPopup.lastChild.nodeName != "menuseparator")
smtpPopup.lastChild.remove();
while (servers.hasMoreElements())
{
var server = servers.getNext();
if (server instanceof Components.interfaces.nsISmtpServer)
{
var serverName = "";
if (server.description)
serverName = server.description + ' - ';
else if (server.username)
serverName = server.username + ' - ';
serverName += server.hostname;
if (defaultServer.key == server.key)
serverName += " " + document.getElementById("bundle_messenger")
.getString("defaultServerTag");
smtpServerList.appendItem(serverName, server.key);
}
}
}

View file

@ -0,0 +1,154 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/messenger.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
<?xul-overlay href="chrome://messenger/content/am-copiesOverlay.xul"?>
<?xul-overlay href="chrome://messenger/content/am-addressingOverlay.xul"?>
<!DOCTYPE dialog [
<!ENTITY % identityEditDTD SYSTEM "chrome://messenger/locale/am-identity-edit.dtd" >
%identityEditDTD;
<!ENTITY % identityDTD SYSTEM "chrome://messenger/locale/am-main.dtd" >
%identityDTD;
]>
<dialog id="identityDialog"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="onLoadIdentityProperties();"
ondialogaccept="return onOk();"
style="&identityDialog.style;">
<stringbundle id="bundle_prefs"
src="chrome://messenger/locale/prefs.properties"/>
<stringbundle id="bundle_messenger"
src="chrome://messenger/locale/messenger.properties"/>
<script type="application/javascript"
src="chrome://messenger/content/am-prefs.js"/>
<script type="application/javascript"
src="chrome://messenger/content/am-identity-edit.js"/>
<broadcaster id="broadcaster_attachSignature"/>
<description flex="1">&identityListDesc.label;</description>
<separator class="thin"/>
<tabbox flex="1" style="overflow: auto;">
<tabs id="identitySettings">
<tab label="&settingsTab.label;"/>
<tab label="&copiesFoldersTab.label;"/>
<tab label="&addressingTab.label;"/>
</tabs>
<tabpanels id="identityTabsPanels" flex="1">
<!-- Identity Settings Tab -->
<vbox flex="1" name="settings">
<groupbox>
<caption label="&publicData.label;"/>
<grid>
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<label value="&name.label;" control="identity.fullName" accesskey="&name.accesskey;"/>
<textbox id="identity.fullName" size="30"/>
</row>
<row align="center">
<label value="&email.label;" control="identity.email" accesskey="&email.accesskey;"/>
<textbox id="identity.email" class="uri-element"/>
</row>
<row align="center">
<label value="&replyTo.label;" control="identity.replyTo" accesskey="&replyTo.accesskey;"/>
<textbox id="identity.replyTo" class="uri-element" placeholder="&replyTo.placeholder;"/>
</row>
<row align="center">
<label value="&organization.label;" control="identity.organization" accesskey="&organization.accesskey;"/>
<textbox id="identity.organization"/>
</row>
<separator class="thin"/>
<row align="center">
<label value="&signatureText.label;" control="identity.htmlSigText" accesskey="&signatureText.accesskey;"/>
<checkbox id="identity.htmlSigFormat" label="&signatureHtml.label;" accesskey="&signatureHtml.accesskey;"/>
</row>
</rows>
</grid>
<hbox class="indent" flex="1">
<textbox id="identity.htmlSigText" flex="1" multiline="true" wrap="off" rows="4" class="signatureBox"/>
</hbox>
<hbox align="center">
<checkbox id="identity.attachSignature" label="&signatureFile.label;" flex="1"
accesskey="&signatureFile.accesskey;"
oncommand="setupSignatureItems();"/>
</hbox>
<hbox align="center" class="indent">
<textbox id="identity.signature" datatype="nsIFile" flex="1" name="identity.signature"
aria-labelledby="identity.attachSignature"
observes="broadcaster_attachSignature" class="uri-element"/>
<button class="push" name="browse" label="&choose.label;"
accesskey="&choose.accesskey;"
oncommand="selectFile()"
observes="broadcaster_attachSignature"
id="identity.sigbrowsebutton"/>
</hbox>
<hbox align="center">
<checkbox id="identity.attachVCard" label="&attachVCard.label;" flex="1"
accesskey="&attachVCard.accesskey;"/>
<button class="push" name="editVCard" label="&editVCard.label;"
accesskey="&editVCard.accesskey;"
oncommand="editVCard()"/>
<label hidden="true" id="identity.escapedVCard"/>
</hbox>
</groupbox>
<groupbox>
<caption label="&privateData.label;"/>
<hbox align="center">
<label value="&smtpName.label;"
control="identity.smtpServerKey"
accesskey="&smtpName.accesskey;"/>
<menulist id="identity.smtpServerKey" flex="1">
<menupopup id="smtpPopup">
<menuitem value=""
label="&smtpDefaultServer.label;"
id="useDefaultItem"/>
<menuseparator/>
<!-- list will be inserted here -->
</menupopup>
</menulist>
</hbox>
<separator class="thin"/>
<hbox align="center">
<label value="&identityAlias.label;"
accesskey="&identityAlias.accesskey;"
control="identity.label"/>
<textbox id="identity.label" flex="1"/>
</hbox>
</groupbox>
<spacer flex="1"/>
</vbox>
<!-- Copies & Folders Tab -->
<vbox flex="1" name="copiesAndFolders" id="copiesAndFolders"/>
<!-- Composition & Addressing Tab -->
<vbox flex="1" name="composeAddressing" id="compositionAndAddressing"/>
</tabpanels>
</tabbox>
</dialog>

View file

@ -0,0 +1,296 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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/.
*/
Components.utils.import("resource:///modules/mailServices.js");
Components.utils.import("resource:///modules/iteratorUtils.jsm");
Components.utils.import("resource:///modules/MailUtils.js");
var gDeferredToAccount = "";
function onInit(aPageId, aServerId)
{
// manually adjust several pref UI elements
document.getElementById('server.spamLevel.visible').setAttribute("checked",
document.getElementById('server.spamLevel').value > 0);
let deferredToURI = null;
if (gDeferredToAccount)
deferredToURI = MailServices.accounts
.getAccount(gDeferredToAccount)
.incomingServer.serverURI;
let spamActionTargetAccountElement =
document.getElementById("server.spamActionTargetAccount");
let spamActionTargetFolderElement =
document.getElementById("server.spamActionTargetFolder");
let spamActionTargetAccount = spamActionTargetAccountElement.value;
let spamActionTargetFolder = spamActionTargetFolderElement.value;
let moveOnSpamCheckbox = document.getElementById("server.moveOnSpam");
let moveOnSpamValue = moveOnSpamCheckbox.checked;
// Check if there are any invalid junk targets and fix them.
[ spamActionTargetAccount, spamActionTargetFolder, moveOnSpamValue ] =
sanitizeJunkTargets(spamActionTargetAccount,
spamActionTargetFolder,
deferredToURI || aServerId,
document.getElementById("server.moveTargetMode").value,
MailUtils.getFolderForURI(aServerId, false).server.spamSettings,
moveOnSpamValue);
spamActionTargetAccountElement.value = spamActionTargetAccount;
spamActionTargetFolderElement.value = spamActionTargetFolder;
moveOnSpamCheckbox.checked = moveOnSpamValue;
let server = MailUtils.getFolderForURI(spamActionTargetAccount, false);
document.getElementById("actionAccountPopup").selectFolder(server);
let folder = MailUtils.getFolderForURI(spamActionTargetFolder, true);
document.getElementById("actionFolderPopup").selectFolder(folder);
var currentArray = [];
if (document.getElementById("server.useWhiteList").checked)
currentArray = document.getElementById("server.whiteListAbURI").value.split(" ");
// set up the whitelist UI
var wList = document.getElementById("whiteListAbURI");
// Ensure the whitelist is empty
for (let i = wList.itemCount - 1; i >= 0; i--) {
wList.removeItemAt(i);
}
// Populate the listbox with address books
let abItems = [];
for (let ab in fixIterator(MailServices.ab.directories,
Components.interfaces.nsIAbDirectory)) {
// We skip mailing lists and remote address books.
if (ab.isMailList || ab.isRemote)
continue;
abItems.push({ label: ab.dirName, URI: ab.URI });
}
// Sort the list
function sortFunc(a, b) {
return a.label.localeCompare(b.label);
}
abItems.sort(sortFunc);
// And then append each item to the listbox
for (let abItem of abItems) {
let item = wList.appendItem(abItem.label, abItem.URI);
item.setAttribute("type", "checkbox");
item.setAttribute("class", "listitem-iconic");
// Due to bug 448582, we have to use setAttribute to set the
// checked value of the listitem.
item.setAttribute("checked", currentArray.includes(abItem.URI));
}
// enable or disable the whitelist
onAdaptiveJunkToggle();
// set up trusted IP headers
var serverFilterList = document.getElementById("useServerFilterList");
serverFilterList.value =
document.getElementById("server.serverFilterName").value;
if (!serverFilterList.selectedItem)
serverFilterList.selectedIndex = 0;
// enable or disable the useServerFilter checkbox
onCheckItem("useServerFilterList", ["server.useServerFilter"]);
updateJunkTargetsAndRetention();
}
function onPreInit(account, accountValues)
{
if (getAccountValue(account, accountValues, "server", "type", null, false) == "pop3")
gDeferredToAccount = getAccountValue(account, accountValues,
"pop3", "deferredToAccount",
null, false);
buildServerFilterMenuList();
}
/**
* Called when someone checks or unchecks the adaptive junk mail checkbox.
* set the value of the hidden element accordingly
*
* @param aValue the boolean value of the checkbox
*/
function updateSpamLevel(aValue)
{
document.getElementById('server.spamLevel').value = aValue ? 100 : 0;
onAdaptiveJunkToggle();
}
/**
* Propagate changes to the server filter menu list back to
* our hidden wsm element.
*/
function onServerFilterListChange()
{
document.getElementById('server.serverFilterName').value =
document.getElementById("useServerFilterList").value;
}
/**
* Called when someone checks or unchecks the adaptive junk mail checkbox.
* We need to enable or disable the whitelist accordingly.
*/
function onAdaptiveJunkToggle()
{
onCheckItem("whiteListAbURI", ["server.spamLevel.visible"]);
onCheckItem("whiteListLabel", ["server.spamLevel.visible"]);
// Enable/disable individual listbox rows.
// Setting enable/disable on the parent listbox does not seem to work.
let wList = document.getElementById("whiteListAbURI");
let wListDisabled = wList.disabled;
for (let i = 0; i < wList.getRowCount(); i++) {
wList.getItemAtIndex(i).setAttribute("disabled", wListDisabled);
}
}
/**
* Called when someone checks or unchecks the "move new junk messages to"
* Enable/disable the radio group accordingly.
*/
function updateJunkTargetsAndRetention() {
onCheckItem("server.moveTargetMode", ["server.moveOnSpam"]);
updateJunkTargets();
onCheckItem("server.purgeSpam", ["server.moveOnSpam"]);
document.getElementById("purgeLabel").disabled =
document.getElementById("server.purgeSpam").disabled;
updateJunkRetention();
}
/**
* Enable/disable the folder pickers depending on which radio item is selected.
*/
function updateJunkTargets() {
onCheckItem("actionTargetAccount", ["server.moveOnSpam", "moveTargetMode0"]);
onCheckItem("actionTargetFolder", ["server.moveOnSpam", "moveTargetMode1"]);
}
/**
* Enable/disable the junk deletion interval depending on the state
* of the controlling checkbox.
*/
function updateJunkRetention() {
onCheckItem("server.purgeSpamInterval", ["server.purgeSpam", "server.moveOnSpam"]);
}
function onSave()
{
onSaveWhiteList();
}
/**
* Propagate changes to the whitelist menu list back to
* our hidden wsm element.
*/
function onSaveWhiteList()
{
var wList = document.getElementById("whiteListAbURI");
var wlArray = [];
for (var i = 0; i < wList.getRowCount(); i++)
{
// Due to bug 448582, do not trust any properties of the listitems
// as they may not return the right value or may even not exist.
// Always get the attributes only.
var wlNode = wList.getItemAtIndex(i);
if (wlNode.getAttribute("checked") == "true") {
let abURI = wlNode.getAttribute("value");
wlArray.push(abURI);
}
}
var wlValue = wlArray.join(" ");
document.getElementById("server.whiteListAbURI").setAttribute("value", wlValue);
document.getElementById("server.useWhiteList").checked = (wlValue != "");
}
/**
* Called when a new value is chosen in one of the junk target folder pickers.
* Sets the menu label according to the folder name.
*/
function onActionTargetChange(aEvent, aWSMElementId)
{
let folder = aEvent.target._folder;
document.getElementById(aWSMElementId).value = folder.URI;
document.getElementById("actionFolderPopup").selectFolder(folder);
}
/**
* Enumerates over the "ISPDL" directories, calling buildServerFilterListFromDir
* for each one.
*/
function buildServerFilterMenuList()
{
const KEY_ISP_DIRECTORY_LIST = "ISPDL";
let ispHeaderList = document.getElementById("useServerFilterList");
// Ensure the menulist is empty.
ispHeaderList.removeAllItems();
// Now walk through the isp directories looking for sfd files.
let ispDirectories = Services.dirsvc.get(KEY_ISP_DIRECTORY_LIST,
Components.interfaces.nsISimpleEnumerator);
let menuEntries = [];
while (ispDirectories.hasMoreElements())
{
let ispDirectory = ispDirectories.getNext()
.QueryInterface(Components.interfaces.nsIFile);
if (ispDirectory)
menuEntries.push.apply(menuEntries, buildServerFilterListFromDir(ispDirectory, menuEntries));
}
menuEntries.sort((a, b) => a.localeCompare(b));
for (let entry of menuEntries) {
ispHeaderList.appendItem(entry, entry);
}
}
/**
* Helper function called by buildServerFilterMenuList. Enumerates over the
* passed in directory looking for .sfd files. For each entry found, it gets
* appended to the menu list.
*
* @param aDir directory to look for .sfd files
* @param aExistingEntries Filter names already found.
*/
function buildServerFilterListFromDir(aDir, aExistingEntries)
{
let newEntries = [];
// Now iterate over each file in the directory looking for .sfd files.
const kSuffix = ".sfd";
let entries = aDir.directoryEntries
.QueryInterface(Components.interfaces.nsIDirectoryEnumerator);
while (entries.hasMoreElements()) {
let entry = entries.nextFile;
// we only care about files that end in .sfd
if (entry.isFile() && entry.leafName.endsWith(kSuffix)) {
let fileName = entry.leafName.slice(0, -kSuffix.length);
// If we've already added an item with this name, then don't add it again.
if (aExistingEntries.indexOf(fileName) == -1)
newEntries.push(fileName);
}
}
return newEntries;
}
/**
* Open the Preferences dialog on the Junk settings tab.
*/
function showGlobalJunkPrefs()
{
openPrefsFromAccountManager("paneSecurity", "junkTab", null, "junk_pane");
}

View file

@ -0,0 +1,232 @@
<?xml version="1.0"?>
<!-- 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/.
-->
<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/messenger.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/folderMenus.css" type="text/css"?>
<!DOCTYPE window [
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
<!ENTITY % junkMailDTD SYSTEM "chrome://messenger/locale/am-junk.dtd">
%junkMailDTD;
]>
<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:nc="http://home.netscape.com/NC-rdf#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
title="&junkSettings.label;"
onload="parent.onPanelLoaded('am-junk.xul');">
<vbox flex="1" style="overflow: auto;">
<script type="application/javascript" src="chrome://messenger/content/AccountManager.js"/>
<script type="application/javascript" src="chrome://messenger/content/am-junk.js"/>
<script type="application/javascript" src="chrome://messenger/content/am-prefs.js"/>
<script type="application/javascript" src="chrome://messenger/content/amUtils.js"/>
<stringbundle id="bundle_messenger" src="chrome://messenger/locale/messenger.properties"/>
<dialogheader title="&junkSettings.label;"/>
<groupbox>
<caption label="&junkClassification.label;"/>
<label hidden="true"
id="server.spamLevel"
wsm_persist="true"
pref="true"
preftype="int"
prefattribute="value"
genericattr="true"
prefstring="mail.server.%serverkey%.spamLevel"/>
<label hidden="true"
id="server.spamActionTargetAccount"
wsm_persist="true"
pref="true"
preftype="string"
prefattribute="value"
genericattr="true"
prefstring="mail.server.%serverkey%.spamActionTargetAccount"/>
<label hidden="true"
id="server.spamActionTargetFolder"
wsm_persist="true"
pref="true"
preftype="string"
prefattribute="value"
genericattr="true"
prefstring="mail.server.%serverkey%.spamActionTargetFolder"/>
<label hidden="true"
id="server.whiteListAbURI"
wsm_persist="true"
pref="true"
preftype="string"
prefattribute="value"
genericattr="true"
prefstring="mail.server.%serverkey%.whiteListAbURI"/>
<label hidden="true"
id="server.serverFilterName"
wsm_persist="true"
pref="true"
preftype="string"
prefattribute="value"
genericattr="true"
prefstring="mail.server.%serverkey%.serverFilterName"/>
<checkbox id="server.spamLevel.visible"
oncommand="updateSpamLevel(this.checked);"
accesskey="&level.accesskey;"
prefstring="mail.server.%serverkey%.spamLevel"
label="&level.label;"/>
<separator class="thin"/>
<description width="1">&trainingDescription.label;</description>
<separator class="thin"/>
<spacer height="3"/>
<vbox class="indent">
<checkbox hidden="true"
id="server.useWhiteList"
genericattr="true"
pref="true"
wsm_persist="true"
preftype="bool"
prefstring="mail.server.%serverkey%.useWhiteList"/>
<label id="whiteListLabel"
accesskey="&whitelistHeader.accesskey;"
control="whiteListAbURI">&whitelistHeader.label;</label>
<listbox id="whiteListAbURI" rows="5"/>
</vbox>
<separator/>
<vbox>
<hbox>
<checkbox id="server.useServerFilter"
label="&ispHeaders.label;"
accesskey="&ispHeaders.accesskey;"
genericattr="true"
pref="true"
wsm_persist="true"
preftype="bool"
oncommand="onCheckItem('useServerFilterList', [this.id]);"
prefstring="mail.server.%serverkey%.useServerFilter"/>
<menulist id="useServerFilterList"
oncommand="onServerFilterListChange();"
aria-labelledby="server.useServerFilter"/>
</hbox>
</vbox>
<separator class="thin"/>
<description width="1">&ispHeadersWarning.label;</description>
</groupbox>
<groupbox>
<caption label="&junkActions.label;"/>
<checkbox id="server.moveOnSpam"
label="&move.label;"
accesskey="&move.accesskey;"
oncommand="updateJunkTargetsAndRetention();"
wsm_persist="true"
pref="true"
preftype="bool"
genericattr="true"
prefstring="mail.server.%serverkey%.moveOnSpam"/>
<radiogroup id="server.moveTargetMode"
aria-labelledby="server.moveOnSpam"
prefstring="mail.server.%serverkey%.moveTargetMode"
wsm_persist="true"
pref="true"
preftype="int"
genericattr="true"
oncommand="updateJunkTargets();"
prefvalue="value">
<grid class="specialFolderPickerGrid indent">
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row>
<radio id="moveTargetMode0"
value="0"
label="&junkFolderOn.label;"
accesskey="&junkFolderOn.accesskey;"/>
<menulist id="actionTargetAccount"
class="folderMenuItem"
aria-labelledby="moveTargetMode0">
<menupopup id="actionAccountPopup"
type="folder"
class="menulist-menupopup"
expandFolders="false"
mode="filing"
oncommand="onActionTargetChange(event, 'server.spamActionTargetAccount');"/>
</menulist>
</row>
<row>
<radio id="moveTargetMode1"
value="1"
label="&otherFolder.label;"
accesskey="&otherFolder.accesskey;"/>
<menulist id="actionTargetFolder"
class="folderMenuItem"
aria-labelledby="moveTargetMode1"
displayformat="verbose">
<menupopup id="actionFolderPopup"
type="folder"
mode="junk"
showFileHereLabel="true"
oncommand="onActionTargetChange(event, 'server.spamActionTargetFolder');"/>
</menulist>
</row>
</rows>
</grid>
</radiogroup>
<hbox align="center" class="indent">
<checkbox id="server.purgeSpam"
genericattr="true"
pref="true"
wsm_persist="true"
preftype="bool"
prefstring="mail.server.%serverkey%.purgeSpam"
accesskey="&purge1.accesskey;"
oncommand="updateJunkRetention();"
label="&purge1.label;"/>
<textbox size="3"
type="number"
min="1"
id="server.purgeSpamInterval"
genericattr="true"
pref="true"
wsm_persist="true"
preftype="int"
aria-labelledby="server.purgeSpam server.purgeSpamInterval purgeLabel"
prefstring="mail.server.%serverkey%.purgeSpamInterval"/>
<label id="purgeLabel"
value="&purge2.label;"
control="server.purgeSpamInterval"/>
</hbox>
</groupbox>
<separator class="thin"/>
<hbox pack="start">
<button id="globalJunkPrefsLink"
label="&globalJunkPrefs.label;"
accesskey="&globalJunkPrefs.accesskey;"
oncommand="showGlobalJunkPrefs();"/>
</hbox>
</vbox>
</page>

View file

@ -0,0 +1,55 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
function onInit(aPageId, aServerId)
{
var accountName = document.getElementById("server.prettyName");
var title = document.getElementById("am-main-title");
var defaultTitle = title.getAttribute("defaultTitle");
var titleValue;
if(accountName.value)
titleValue = defaultTitle+" - <"+accountName.value+">";
else
titleValue = defaultTitle;
title.setAttribute("title",titleValue);
document.title = titleValue;
setupSignatureItems();
}
function onPreInit(account, accountValues)
{
loadSMTPServerList();
}
function manageIdentities()
{
// We want to save the current identity information before bringing up the multiple identities
// UI. This ensures that the changes are reflected in the identity list dialog
// onSave();
var account = parent.getCurrentAccount();
if (!account)
return;
var accountName = document.getElementById("server.prettyName").value;
var args = { account: account, accountName: accountName, result: false };
// save the current identity settings so they show up correctly
// if the user just changed them in the manage identities dialog
var identity = account.defaultIdentity;
saveIdentitySettings(identity);
window.openDialog("am-identities-list.xul", "", "chrome,modal,resizable=no,centerscreen", args);
if (args.result) {
// now re-initialize the default identity settings in case they changed
identity = account.defaultIdentity; // refetch the default identity in case it changed
initIdentityValues(identity);
}
}

View file

@ -0,0 +1,147 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
<!DOCTYPE page SYSTEM "chrome://messenger/locale/am-main.dtd" >
<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="parent.onPanelLoaded('am-main.xul');">
<vbox flex="1" style="overflow: auto;">
<stringbundle id="bundle_prefs" src="chrome://messenger/locale/prefs.properties"/>
<stringbundle id="bundle_messenger" src="chrome://messenger/locale/messenger.properties"/>
<script type="application/javascript" src="chrome://messenger/content/am-identity-edit.js"/>
<script type="application/javascript" src="chrome://messenger/content/am-main.js"/>
<script type="application/javascript" src="chrome://messenger/content/am-prefs.js"/>
<broadcaster id="broadcaster_attachSignature"/>
<dialogheader id="am-main-title" defaultTitle="&accountTitle.label;"/>
<hbox align="center">
<label value="&accountName.label;" control="server.prettyName"
accesskey="&accountName.accesskey;"/>
<textbox wsm_persist="true" size="30" id="server.prettyName"
prefstring="mail.server.%serverkey%.name"/>
</hbox>
<separator class="thin"/>
<groupbox style="width: 20em !important;" flex="1">
<caption label="&identityTitle.label;"/>
<description>&identityDesc.label;</description>
<separator class="thin"/>
<grid>
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<label value="&name.label;" control="identity.fullName"
accesskey="&name.accesskey;"/>
<textbox wsm_persist="true" id="identity.fullName" size="30"
prefstring="mail.identity.%identitykey%.fullName"/>
</row>
<row align="center">
<label value="&email.label;" control="identity.email"
accesskey="&email.accesskey;"/>
<textbox wsm_persist="true" id="identity.email"
prefstring="mail.identity.%identitykey%.useremail" class="uri-element"/>
</row>
<row align="center">
<label value="&replyTo.label;" control="identity.replyTo"
accesskey="&replyTo.accesskey;"/>
<textbox wsm_persist="true" id="identity.replyTo"
prefstring="mail.identity.%identitykey%.reply_to" class="uri-element"
placeholder="&replyTo.placeholder;"/>
</row>
<row align="center">
<label value="&organization.label;" control="identity.organization"
accesskey="&organization.accesskey;"/>
<textbox wsm_persist="true" id="identity.organization"
prefstring="mail.identity.%identitykey%.organization"/>
</row>
<separator class="thin"/>
<row align="center">
<label value="&signatureText.label;" control="identity.htmlSigText" accesskey="&signatureText.accesskey;"/>
<checkbox wsm_persist="true" id="identity.htmlSigFormat" label="&signatureHtml.label;"
prefattribute="value" accesskey="&signatureHtml.accesskey;"
prefstring="mail.identity.%identitykey%.htmlSigFormat"/>
</row>
</rows>
</grid>
<hbox class="indent" flex="1" style="min-height: 50px;">
<textbox wsm_persist="true" id="identity.htmlSigText" multiline="true" wrap="off" rows="4" flex="1"
prefstring="mail.identity.%identitykey%.htmlSigText" class="signatureBox"/>
</hbox>
<hbox align="center">
<checkbox wsm_persist="true" id="identity.attachSignature" label="&signatureFile.label;" flex="1"
accesskey="&signatureFile.accesskey;"
oncommand="setupSignatureItems();"
prefattribute="value"
prefstring="mail.identity.%identitykey%.attach_signature"/>
</hbox>
<hbox align="center" class="indent">
<textbox wsm_persist="true" id="identity.signature" datatype="nsIFile" flex="1" name="identity.signature"
aria-labelledby="identity.attachSignature"
observes="broadcaster_attachSignature"
prefstring="mail.identity.%identitykey%.sig_file" class="uri-element"/>
<button class="push" name="browse" label="&choose.label;"
accesskey="&choose.accesskey;"
oncommand="selectFile()"
observes="broadcaster_attachSignature"
wsm_persist="true" id="identity.sigbrowsebutton"
prefstring="mail.identity.%identitykey%.sigbrowse.disable"/>
</hbox>
<hbox align="center">
<checkbox wsm_persist="true" id="identity.attachVCard" label="&attachVCard.label;" flex="1"
accesskey="&attachVCard.accesskey;"
prefattribute="value"
prefstring="mail.identity.%identitykey%.attach_vcard"/>
<button class="push" name="editVCard" label="&editVCard.label;"
accesskey="&editVCard.accesskey;"
oncommand="editVCard()"/>
<label hidden="true" wsm_persist="true" id="identity.escapedVCard"
pref="true" preftype="string" prefattribute="value"
prefstring="mail.identity.%identitykey%.escapedVCard"/>
</hbox>
<separator class="thin"/>
<hbox align="center">
<label value="&smtpName.label;" control="identity.smtpServerKey"
accesskey="&smtpName.accesskey;"/>
<menulist wsm_persist="true" id="identity.smtpServerKey" flex="1"
pref="true" preftype="string" prefattribute="value"
prefstring="mail.identity.%identitykey%.smtpServer">
<menupopup id="smtpPopup">
<menuitem value="" label="&smtpDefaultServer.label;" id="useDefaultItem"/>
<menuseparator/>
<!-- list will be inserted here -->
</menupopup>
</menulist>
</hbox>
</groupbox>
<separator class="thin"/>
<hbox align="center">
<spacer flex="1"/>
<button label="&manageIdentities.label;" oncommand="manageIdentities(event);"
accesskey="&manageIdentities.accesskey;"
wsm_persist="true" id="identity.manageIdentitiesbutton"/>
</hbox>
<spacer flex="1"/>
</vbox>
</page>

View file

@ -0,0 +1,351 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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/. */
Components.utils.import("resource:///modules/iteratorUtils.jsm");
var gIncomingServer;
var gServerType;
var gImapIncomingServer;
var gPref = null;
var gLockedPref = null;
var gOfflineMap = null; // map of folder URLs to offline flags
function onInit(aPageId, aServerId)
{
onLockPreference();
// init values here
initServerSettings();
initRetentionSettings();
initDownloadSettings();
initOfflineSettings();
onCheckItem("offline.notDownloadMin", "offline.notDownload");
onCheckItem("nntp.downloadMsgMin", "nntp.downloadMsg");
onCheckItem("nntp.removeBodyMin", "nntp.removeBody");
onCheckKeepMsg();
}
function initOfflineSettings()
{
gOfflineMap = collectOfflineFolders();
}
function initServerSettings()
{
document.getElementById("offline.notDownload").checked = gIncomingServer.limitOfflineMessageSize;
document.getElementById("autosync.notDownload").checked = gIncomingServer.limitOfflineMessageSize;
if(gIncomingServer.maxMessageSize > 0)
document.getElementById("offline.notDownloadMin").value = gIncomingServer.maxMessageSize;
else
document.getElementById("offline.notDownloadMin").value = "50";
if(gServerType == "imap") {
gImapIncomingServer = gIncomingServer.QueryInterface(Components.interfaces.nsIImapIncomingServer);
document.getElementById("offline.folders").checked = gImapIncomingServer.offlineDownload;
}
}
function initRetentionSettings()
{
let retentionSettings = gIncomingServer.retentionSettings;
initCommonRetentionSettings(retentionSettings);
document.getElementById("nntp.removeBody").checked = retentionSettings.cleanupBodiesByDays;
document.getElementById("nntp.removeBodyMin").value =
(retentionSettings.daysToKeepBodies > 0) ? retentionSettings.daysToKeepBodies : 30;
}
function initDownloadSettings()
{
let downloadSettings = gIncomingServer.downloadSettings;
document.getElementById("nntp.downloadMsg").checked = downloadSettings.downloadByDate;
document.getElementById("nntp.notDownloadRead").checked = downloadSettings.downloadUnreadOnly;
document.getElementById("nntp.downloadMsgMin").value =
(downloadSettings.ageLimitOfMsgsToDownload > 0) ?
downloadSettings.ageLimitOfMsgsToDownload : 30;
// Figure out what the most natural division of the autosync pref into
// a value and an interval is.
let autosyncSelect = document.getElementById("autosyncSelect");
let autosyncInterval = document.getElementById("autosyncInterval");
let autosyncValue = document.getElementById("autosyncValue");
let autosyncPref = document.getElementById("imap.autoSyncMaxAgeDays");
let autosyncPrefValue = (autosyncPref.value == "") ? -1 :
parseInt(autosyncPref.value, 10);
// Clear the preference until we're done initializing.
autosyncPref.value = "";
if (autosyncPrefValue <= 0) {
// Special-case values <= 0 to have an interval of "All" and disabled
// controls for value and interval.
autosyncSelect.value = 0;
autosyncInterval.value = 1;
autosyncInterval.disabled = true;
autosyncValue.value = 30;
autosyncValue.disabled = true;
}
else {
// Otherwise, get the list of possible intervals, in order from
// largest to smallest.
let valuesToTest = [];
for (let i = autosyncInterval.itemCount - 1; i >= 0; i--)
valuesToTest.push(autosyncInterval.getItemAtIndex(i).value);
// and find the first one that divides the preference evenly.
for (let i in valuesToTest) {
if (!(autosyncPrefValue % valuesToTest[i])) {
autosyncSelect.value = 1;
autosyncInterval.value = valuesToTest[i];
autosyncValue.value = autosyncPrefValue / autosyncInterval.value;
break;
}
}
autosyncInterval.disabled = false;
autosyncValue.disabled = false;
}
autosyncPref.value = autosyncPrefValue;
}
function onPreInit(account, accountValues)
{
gServerType = getAccountValue(account, accountValues, "server", "type", null, false);
hideShowControls(gServerType);
gIncomingServer = account.incomingServer;
gIncomingServer.type = gServerType;
// 10 is OFFLINE_SUPPORT_LEVEL_REGULAR, see nsIMsgIncomingServer.idl
// currently, there is no offline without diskspace
var titleStringID = (gIncomingServer.offlineSupportLevel >= 10) ?
"prefPanel-synchronization" : "prefPanel-diskspace";
var prefBundle = document.getElementById("bundle_prefs");
var headertitle = document.getElementById("headertitle");
headertitle.setAttribute('title',prefBundle.getString(titleStringID));
document.title = prefBundle.getString(titleStringID);
if (gServerType == "pop3") {
var pop3Server = gIncomingServer.QueryInterface(Components.interfaces.nsIPop3IncomingServer);
// hide retention settings for deferred accounts
if (pop3Server.deferredToAccount.length) {
var retentionRadio = document.getElementById("retention.keepMsg");
retentionRadio.setAttribute("hidden", "true");
var retentionLabel = document.getElementById("retentionDescriptionPop");
retentionLabel.setAttribute("hidden", "true");
var applyToFlaggedCheckbox = document.getElementById("retention.applyToFlagged");
applyToFlaggedCheckbox.setAttribute("hidden", "true");
}
}
}
function onClickSelect()
{
top.window.openDialog("chrome://messenger/content/msgSelectOffline.xul", "", "centerscreen,chrome,modal,titlebar,resizable=yes");
return true;
}
/**
* Handle updates to the Autosync
*/
function onAutosyncChange()
{
let autosyncSelect = document.getElementById("autosyncSelect");
let autosyncInterval = document.getElementById("autosyncInterval");
let autosyncValue = document.getElementById("autosyncValue");
let autosyncPref = document.getElementById("imap.autoSyncMaxAgeDays");
// If we're not done initializing, don't do anything.
// (See initDownloadSettings() for more details.)
if (autosyncPref.value == "")
return;
// If the user selected the All option, disable the autosync and the
// textbox.
if (autosyncSelect.value == 0) {
autosyncPref.value = -1;
autosyncInterval.disabled = true;
autosyncValue.disabled = true;
return;
}
let max = 0x7FFFFFFF / (60 * 60 * 24 * autosyncInterval.value);
autosyncValue.setAttribute("max", max);
if (autosyncValue.value > max)
autosyncValue.value = Math.floor(max);
autosyncInterval.disabled = false;
autosyncValue.disabled = false;
autosyncPref.value = autosyncValue.value * autosyncInterval.value;
}
function onAutosyncNotDownload()
{
// This function is called when the autosync version of offline.notDownload
// is changed it simply copies the new checkbox value over to the element
// driving the preference.
document.getElementById("offline.notDownload").checked =
document.getElementById("autosync.notDownload").checked;
onCheckItem("offline.notDownloadMin", "offline.notDownload");
}
function onCancel()
{
// restore the offline flags for all folders
restoreOfflineFolders(gOfflineMap);
return true;
}
function onSave()
{
var downloadSettings =
Components.classes["@mozilla.org/msgDatabase/downloadSettings;1"]
.createInstance(Components.interfaces.nsIMsgDownloadSettings);
gIncomingServer.limitOfflineMessageSize = document.getElementById("offline.notDownload").checked;
gIncomingServer.maxMessageSize = document.getElementById("offline.notDownloadMin").value;
var retentionSettings = saveCommonRetentionSettings(gIncomingServer.retentionSettings);
retentionSettings.daysToKeepBodies = document.getElementById("nntp.removeBodyMin").value;
retentionSettings.cleanupBodiesByDays = document.getElementById("nntp.removeBody").checked;
downloadSettings.downloadByDate = document.getElementById("nntp.downloadMsg").checked;
downloadSettings.downloadUnreadOnly = document.getElementById("nntp.notDownloadRead").checked;
downloadSettings.ageLimitOfMsgsToDownload = document.getElementById("nntp.downloadMsgMin").value;
gIncomingServer.retentionSettings = retentionSettings;
gIncomingServer.downloadSettings = downloadSettings;
if (gImapIncomingServer) {
// Set the pref on the incomingserver, and set the flag on all folders.
gImapIncomingServer.offlineDownload = document.getElementById("offline.folders").checked;
}
}
// Does the work of disabling an element given the array which contains xul id/prefstring pairs.
// Also saves the id/locked state in an array so that other areas of the code can avoid
// stomping on the disabled state indiscriminately.
function disableIfLocked( prefstrArray )
{
if (!gLockedPref)
gLockedPref = new Array;
for (var i=0; i<prefstrArray.length; i++) {
var id = prefstrArray[i].id;
var element = document.getElementById(id);
if (gPref.prefIsLocked(prefstrArray[i].prefstring)) {
element.disabled = true;
gLockedPref[id] = true;
} else {
element.removeAttribute("disabled");
gLockedPref[id] = false;
}
}
}
// Disables xul elements that have associated preferences locked.
function onLockPreference()
{
var isDownloadLocked = false;
var isGetNewLocked = false;
var initPrefString = "mail.server";
var finalPrefString;
// This panel does not use the code in AccountManager.js to handle
// the load/unload/disable. keep in mind new prefstrings and changes
// to code in AccountManager, and update these as well.
var allPrefElements = [
{ prefstring:"limit_offline_message_size", id:"offline.notDownload"},
{ prefstring:"limit_offline_message_size", id:"autosync.notDownload"},
{ prefstring:"max_size", id:"offline.notDownloadMin"},
{ prefstring:"downloadUnreadOnly", id:"nntp.notDownloadRead"},
{ prefstring:"downloadByDate", id:"nntp.downloadMsg"},
{ prefstring:"ageLimit", id:"nntp.downloadMsgMin"},
{ prefstring:"retainBy", id:"retention.keepMsg"},
{ prefstring:"daysToKeepHdrs", id:"retention.keepOldMsgMin"},
{ prefstring:"numHdrsToKeep", id:"retention.keepNewMsgMin"},
{ prefstring:"daysToKeepBodies", id:"nntp.removeBodyMin"},
{ prefstring:"cleanupBodies", id:"nntp.removeBody" },
{ prefstring:"applyToFlagged", id:"retention.applyToFlagged"},
{ prefstring:"disable_button.selectFolder", id:"selectNewsgroupsButton"},
{ prefstring:"disable_button.selectFolder", id:"selectImapFoldersButton"}
];
finalPrefString = initPrefString + "." + gIncomingServer.key + ".";
gPref = Services.prefs.getBranch(finalPrefString);
disableIfLocked( allPrefElements );
}
function onCheckItem(changeElementId, checkElementId)
{
var element = document.getElementById(changeElementId);
var checked = document.getElementById(checkElementId).checked;
if(checked && !gLockedPref[checkElementId] ) {
element.removeAttribute("disabled");
}
else {
element.setAttribute("disabled", "true");
}
}
function toggleOffline()
{
let offline = document.getElementById("offline.folders").checked;
let allFolders = gIncomingServer.rootFolder.descendants;
for (let folder in fixIterator(allFolders, Components.interfaces.nsIMsgFolder)) {
if (offline)
folder.setFlag(Components.interfaces.nsMsgFolderFlags.Offline);
else
folder.clearFlag(Components.interfaces.nsMsgFolderFlags.Offline);
}
}
function collectOfflineFolders()
{
let offlineFolderMap = {};
let allFolders = gIncomingServer.rootFolder.descendants;
for (let folder in fixIterator(allFolders, Components.interfaces.nsIMsgFolder))
offlineFolderMap[folder.folderURL] = folder.getFlag(Components.interfaces.nsMsgFolderFlags.Offline);
return offlineFolderMap;
}
function restoreOfflineFolders(offlineFolderMap)
{
let allFolders = gIncomingServer.rootFolder.descendants;
for (let folder in fixIterator(allFolders, Components.interfaces.nsIMsgFolder)) {
if (offlineFolderMap[folder.folderURL])
folder.setFlag(Components.interfaces.nsMsgFolderFlags.Offline);
else
folder.clearFlag(Components.interfaces.nsMsgFolderFlags.Offline);
}
}
/**
* Checks if the user selected a permanent removal of messages from a server
* listed in the confirmfor attribute and warns about it.
*
* @param aRadio The radiogroup element containing the retention options.
*/
function warnServerRemove(aRadio)
{
let confirmFor = aRadio.getAttribute("confirmfor");
if (confirmFor && confirmFor.split(',').includes(gServerType) && aRadio.value != 1) {
let prefBundle = document.getElementById("bundle_prefs");
let title = prefBundle.getString("removeFromServerTitle");
let question = prefBundle.getString("removeFromServer");
if (!Services.prompt.confirm(window, title, question)) {
// If the user doesn't agree, fall back to not deleting anything.
aRadio.value = 1;
onCheckKeepMsg();
}
}
}

View file

@ -0,0 +1,158 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
<!DOCTYPE page SYSTEM "chrome://messenger/locale/am-offline.dtd">
<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="parent.onPanelLoaded('am-offline.xul');">
<vbox flex="1" style="overflow: auto;">
<stringbundle id="bundle_prefs" src="chrome://messenger/locale/prefs.properties"/>
<script type="application/javascript" src="chrome://messenger/content/AccountManager.js"/>
<script type="application/javascript" src="chrome://messenger/content/retention.js"/>
<script type="application/javascript" src="chrome://messenger/content/am-offline.js"/>
<label hidden="true" wsm_persist="true" id="server.type"/>
<label id="imap.autoSyncMaxAgeDays" hidden="true"
wsm_persist="true" preftype="int"
prefstring="mail.server.%serverkey%.autosync_max_age_days"/>
<dialogheader id="headertitle"/>
<groupbox id="offline.titlebox" hidefor="movemail,pop3,none,rss">
<caption label="&syncGroupTitle.label;"/>
<checkbox hidefor="movemail,pop3,nntp,none"
id="offline.folders" label="&allFoldersOffline.label;"
oncommand="toggleOffline()"
accesskey="&allFoldersOffline.accesskey;"/>
<separator class="thin" hidefor="movemail,pop3,nntp,none"/>
<hbox hidefor="movemail,pop3,nntp,none" align="right">
<button label="&offlineImapAdvancedOffline.label;" accesskey="&offlineImapAdvancedOffline.accesskey;"
oncommand="onClickSelect()" id="selectImapFoldersButton" class="selectForOfflineUseButton"/>
</hbox>
<hbox hidefor="movemail,pop3,imap,none" align="right">
<button label="&offlineSelectNntp.label;" accesskey="&offlineSelectNntp.accesskey;"
oncommand="onClickSelect()" id="selectNewsgroupsButton" class="selectForOfflineUseButton"/>
</hbox>
</groupbox>
<groupbox id="diskspace.titlebox">
<caption label="&diskspaceGroupTitle.label;" hidefor="movemail,pop3,none,rss"/>
<description hidefor="pop3,nntp,movemail,none,rss">&doNotDownloadImap.label;</description>
<description hidefor="pop3,imap,movemail,none,rss">&doNotDownloadNntp.label;</description>
<description hidefor="imap,nntp,none,rss">&doNotDownloadPop3Movemail.label;</description>
<!-- IMAP Autosync Preference -->
<radiogroup hidefor="pop3,nntp,movemail,none,rss" id="autosyncSelect" class="indent">
<radio id="useAutosync.AllMsg" value="0" accesskey="&allAutosync.accesskey;"
label="&allAutosync.label;" oncommand="onAutosyncChange();"/>
<hbox flex="1" align="center">
<radio id="useAutosync.ByAge" accesskey="&ageAutosync.accesskey;"
value="1" label="&ageAutosyncBefore.label;" oncommand="onAutosyncChange();"/>
<textbox id="autosyncValue" type="number" size="4" min="1"
class="autosync" onchange="onAutosyncChange();"
aria-labelledby="ageAutosyncBefore autosyncValue ageAutosyncMiddle autosyncInterval ageAutosyncAfter"/>
<label id="ageAutosyncMiddle" control="autosyncValue" value="&ageAutosyncMiddle.label;"/>
<menulist id="autosyncInterval" onselect="onAutosyncChange();">
<menupopup>
<menuitem label="&dayAgeInterval.label;" value="1"/>
<menuitem label="&weekAgeInterval.label;" value="7"/>
<menuitem label="&monthAgeInterval.label;" value="31"/>
<menuitem label="&yearAgeInterval.label;" value="365"/>
</menupopup>
</menulist>
<label id="ageAutosyncAfter" control="autosyncInterval" value="&ageAutosyncAfter.label;"/>
</hbox>
</radiogroup>
<hbox align="center" class="indent" hidefor="rss">
<checkbox hidefor="movemail,pop3,imap,none"
id="nntp.notDownloadRead" wsm_persist="true"
label="&nntpNotDownloadRead.label;"
accesskey="&nntpNotDownloadRead.accesskey;"/>
</hbox>
<hbox align="center" class="indent" hidefor="none,rss">
<checkbox wsm_persist="true" id="offline.notDownload" hidefor="imap"
label="&offlineNotDownload.label;"
accesskey="&offlineNotDownload.accesskey;"
oncommand="onCheckItem('offline.notDownloadMin', 'offline.notDownload');"/>
<checkbox wsm_persist="true" id="autosync.notDownload" hidefor="pop3,nntp,movemail"
label="&autosyncNotDownload.label;"
accesskey="&autosyncNotDownload.accesskey;"
oncommand="onAutosyncNotDownload();"/>
<textbox wsm_persist="true" id="offline.notDownloadMin"
type="number" min="1" increment="10" size="4" value="50"
aria-labelledby="offline.notDownload offline.notDownloadMin kbLabel"/>
<label value="&kb.label;" control="offline.notDownloadMin" id="kbLabel"/>
</hbox>
<hbox align="center" class="indent" hidefor="movemail,pop3,imap,none,rss">
<checkbox wsm_persist="true" id="nntp.downloadMsg"
label="&nntpDownloadMsg.label;"
accesskey="&nntpDownloadMsg.accesskey;"
oncommand="onCheckItem('nntp.downloadMsgMin', 'nntp.downloadMsg');"/>
<textbox wsm_persist="true" id="nntp.downloadMsgMin"
type="number" min="1" size="2" value="30"
aria-labelledby="nntp.downloadMsg nntp.downloadMsgMin daysOldLabel"/>
<label value="&daysOld.label;" control="nntp.downloadMsgMin"
id="daysOldLabel"/>
</hbox>
<vbox align="start">
<separator hidefor="none,rss"/>
<label id="retentionDescription" hidefor="imap,pop3" class="desc" control="retention.keepMsg">&retentionCleanup.label;</label>
<label id="retentionDescriptionImap" hidefor="movemail,pop3,nntp,none,rss" class="desc" control="retention.keepMsg">&retentionCleanupImap.label;</label>
<label id="retentionDescriptionPop" hidefor="movemail,imap,nntp,none,rss" class="desc" control="retention.keepMsg">&retentionCleanupPop.label;</label>
<radiogroup hidefor="" confirmfor="imap,pop3" id="retention.keepMsg" class="indent"
oncommand="warnServerRemove(this);">
<radio id="retention.keepAllMsg" value="1" accesskey="&retentionKeepAll.accesskey;"
label="&retentionKeepAll.label;" oncommand="onCheckKeepMsg();"/>
<hbox flex="1" align="center">
<radio id="retention.keepNewMsg" accesskey="&retentionKeepRecent.accesskey;"
value="3" label="&retentionKeepRecent.label;" oncommand="onCheckKeepMsg();"/>
<textbox id="retention.keepNewMsgMin"
type="number" min="1" increment="10" size="4" value="2000"
aria-labelledby="retention.keepNewMsg retention.keepNewMsgMin newMsgLabel"/>
<label value="&message.label;" control="retention.keepNewMsgMin" id="newMsgLabel"/>
</hbox>
<hbox flex="1" align="center">
<radio id="retention.keepOldMsg" accesskey="&retentionKeepMsg.accesskey;"
value="2" label="&retentionKeepMsg.label;" oncommand="onCheckKeepMsg();"/>
<textbox id="retention.keepOldMsgMin"
type="number" min="1" size="4" value="30"
aria-labelledby="retention.keepOldMsg retention.keepOldMsgMin oldMsgLabel"/>
<label value="&daysOld.label;" control="retention.keepOldMsgMin" id="oldMsgLabel"/>
</hbox>
</radiogroup>
<hbox align="center" class="indent">
<checkbox id="retention.applyToFlagged"
label="&retentionApplyToFlagged.label;" hidefor=""
accesskey="&retentionApplyToFlagged.accesskey;"
checked="true"/>
</hbox>
<hbox align="center" class="indent" hidefor="movemail,pop3,imap,none,rss">
<checkbox id="nntp.removeBody" accesskey="&nntpRemoveMsgBody.accesskey;"
label="&nntpRemoveMsgBody.label;" oncommand="onCheckItem('nntp.removeBodyMin','nntp.removeBody');"/>
<textbox id="nntp.removeBodyMin" size="2" value="30"
type="number" min="1"
aria-labelledby="nntp.removeBody nntp.removeBodyMin daysOldMsg"/>
<label value="&daysOld.label;" control="nntp.removeBodyMin" id="daysOldMsg"/>
</hbox>
</vbox>
</groupbox>
</vbox>
</page>

View file

@ -0,0 +1,114 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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/. */
/* functions for disabling front end elements when the appropriate
back-end preference is locked. */
Components.utils.import("resource://gre/modules/Services.jsm");
/**
* Prefs in MailNews require dynamic portions to indicate
* which of multiple servers or identities. This function
* takes a string and a xul element.
*
* @param aStr The string is a prefstring with a token %tokenname%.
* @param aElement The xul element has an attribute of name |tokenname|
* whose value is substituted into the string and returned
* by the function.
*
* Any tokens which do not have associated attribute value
* are not substituted, and left in the string as-is.
*/
function substPrefTokens(aStr, aElement)
{
let tokenpat = /%(\w+)%/;
let token;
let newprefstr = "";
let prefPartsArray = aStr.split(".");
/* here's a little loop that goes through
each part of the string separated by a dot, and
if any parts are of the form %string%, it will replace
them with the value of the attribute of that name from
the xul object */
for (let i = 0; i < prefPartsArray.length; i++) {
token = prefPartsArray[i].match(tokenpat);
if (token) { /* we've got a %% match */
if (token[1]) {
if (aElement[token[1]]) {
newprefstr += aElement[token[1]] + "."; // here's where we get the info
} else { /* all we got was this stinkin % */
newprefstr += prefPartsArray[i] + ".";
}
}
} else /* if (token) */ {
newprefstr += prefPartsArray[i] + ".";
}
}
newprefstr = newprefstr.slice(0, -1); // remove the last char, a dot
if (newprefstr.length <= 0)
newprefstr = null;
return newprefstr;
}
/**
* A simple function to check if a pref in an element is locked.
*
* @param aElement a xul element with the pref related attributes
* (pref, preftype, prefstring)
* @return whether the prefstring specified in that element is
* locked (true/false).
* If it does not have a valid prefstring, a false is returned.
*/
function getAccountValueIsLocked(aElement)
{
let prefstring = aElement.getAttribute("prefstring");
if (prefstring) {
let prefstr = substPrefTokens(prefstring, aElement);
// see if the prefstring is locked
if (prefstr)
return Services.prefs.prefIsLocked(prefstr);
}
return false;
}
/**
* Enables/disables element (slave) according to the checked state
* of another elements (masters).
*
* @param aChangeElementId Slave element which should be enabled
* if all the checkElementIDs are checked.
* Otherwise it gets disabled.
* @param aCheckElementIds An array of IDs of the master elements.
*
* See bug 728681 for the pattern on how this is used.
*/
function onCheckItem(aChangeElementId, aCheckElementIds)
{
let elementToControl = document.getElementById(aChangeElementId);
let disabled = false;
for (let notifyId of aCheckElementIds) {
let notifyElement = document.getElementById(notifyId);
let notifyElementState = null;
if ("checked" in notifyElement)
notifyElementState = notifyElement.checked;
else if ("selected" in notifyElement)
notifyElementState = notifyElement.selected;
else
Components.utils.reportError("Unknown type of control element: " + notifyElement.id);
if (!notifyElementState) {
disabled = true;
break;
}
}
if (!disabled && getAccountValueIsLocked(elementToControl))
disabled = true;
elementToControl.disabled = disabled;
}

View file

@ -0,0 +1,157 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
Components.utils.import("resource:///modules/mailServices.js");
Components.utils.import("resource://gre/modules/Services.jsm");
// pull stuff out of window.arguments
var gServerSettings = window.arguments[0];
var gFirstDeferredAccount;
// initialize the controls with the "gServerSettings" argument
var gControls;
function getControls()
{
if (!gControls)
gControls = document.getElementsByAttribute("amsa_persist", "true");
return gControls;
}
function getLocalFoldersAccount()
{
return MailServices.accounts
.FindAccountForServer(MailServices.accounts.localFoldersServer);
}
function onLoad()
{
var prettyName = gServerSettings.serverPrettyName;
if (prettyName)
document.getElementById("serverPrettyName").value =
document.getElementById("bundle_prefs")
.getFormattedString("forAccount", [prettyName]);
if (gServerSettings.serverType == "imap")
{
document.getElementById("pop3Panel").hidden = true;
}
else if (gServerSettings.serverType == "pop3")
{
document.getElementById("imapPanel").hidden = true;
let radioGroup = document.getElementById("folderStorage");
gFirstDeferredAccount = gServerSettings.deferredToAccount;
let folderPopup = document.getElementById("deferredServerPopup");
// The current account should not be shown in the folder picker
// of the "other account" option.
folderPopup._teardown();
folderPopup.setAttribute("excludeServers",
gServerSettings.account.incomingServer.key);
folderPopup._ensureInitialized();
if (gFirstDeferredAccount.length)
{
// The current account is deferred.
let account = MailServices.accounts.getAccount(gFirstDeferredAccount);
radioGroup.value = "otherAccount";
folderPopup.selectFolder(account.incomingServer.rootFolder);
}
else
{
// Current account is not deferred.
radioGroup.value = "currentAccount";
// If there are no suitable accounts to defer to, then the menulist is
// disabled by the picker with an appropriate message.
folderPopup.selectFolder();
if (gServerSettings.account.incomingServer.isDeferredTo) {
// Some other account already defers to this account
// therefore this one can't be deferred further.
radioGroup.disabled = true;
}
}
let picker = document.getElementById("deferredServerFolderPicker");
picker.disabled = radioGroup.selectedIndex != 1;
}
var controls = getControls();
for (var i = 0; i < controls.length; i++)
{
var slot = controls[i].id;
if (slot in gServerSettings)
{
if (controls[i].localName == "checkbox")
controls[i].checked = gServerSettings[slot];
else
controls[i].value = gServerSettings[slot];
}
}
}
function onOk()
{
// Handle account deferral settings for POP3 accounts.
if (gServerSettings.serverType == "pop3")
{
var radioGroup = document.getElementById("folderStorage");
var gPrefsBundle = document.getElementById("bundle_prefs");
let picker = document.getElementById("deferredServerFolderPicker");
// This account wasn't previously deferred, but is now deferred.
if (radioGroup.value != "currentAccount" && !gFirstDeferredAccount.length)
{
// If the user hasn't selected a folder, keep the default.
if (!picker.selectedItem)
return true;
var confirmDeferAccount =
gPrefsBundle.getString("confirmDeferAccountWarning");
var confirmTitle = gPrefsBundle.getString("confirmDeferAccountTitle");
if (!Services.prompt.confirm(window, confirmTitle, confirmDeferAccount))
return false;
}
switch (radioGroup.value)
{
case "currentAccount":
gServerSettings['deferredToAccount'] = "";
break;
case "otherAccount":
let server = picker.selectedItem._folder.server;
let account = MailServices.accounts.FindAccountForServer(server);
gServerSettings['deferredToAccount'] = account.key;
break;
}
}
// Save the controls back to the "gServerSettings" array.
var controls = getControls();
for (var i = 0; i < controls.length; i++)
{
var slot = controls[i].id;
if (slot in gServerSettings)
{
if (controls[i].localName == "checkbox")
gServerSettings[slot] = controls[i].checked;
else
gServerSettings[slot] = controls[i].value;
}
}
return true;
}
// Set radio element choices and picker states
function updateInboxAccount(enablePicker)
{
document.getElementById("deferredServerFolderPicker").disabled = !enablePicker;
document.getElementById("deferGetNewMail").disabled = !enablePicker;
}

View file

@ -0,0 +1,146 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/messenger.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/folderMenus.css" type="text/css"?>
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/am-server-advanced.dtd">
<dialog
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&serverAdvanced.label;"
buttons="accept,cancel"
onload="onLoad();"
ondialogaccept="return onOk();">
<script type="application/javascript"
src="chrome://messenger/content/am-server-advanced.js"/>
<stringbundle id="bundle_prefs"
src="chrome://messenger/locale/prefs.properties"/>
<label id="serverPrettyName"/>
<separator class="thin"/>
<!-- IMAP Panel -->
<vbox id="imapPanel">
<hbox align="center">
<label value="&serverDirectory.label;"
accesskey="&serverDirectory.accesskey;"
control="serverDirectory"/>
<textbox amsa_persist="true" id="serverDirectory"/>
</hbox>
<checkbox amsa_persist="true" id="usingSubscription"
label="&usingSubscription.label;"
accesskey="&usingSubscription.accesskey;"/>
<checkbox amsa_persist="true" id="dualUseFolders"
label="&dualUseFolders.label;"
accesskey="&dualUseFolders.accesskey;"/>
<separator class="groove"/>
<row>
<hbox align="center">
<label control="maximumConnectionsNumber"
value="&maximumConnectionsNumber.label;"
accesskey="&maximumConnectionsNumber.accesskey;"/>
<textbox amsa_persist="true" size="3" type="number"
min="1" max="1000" id="maximumConnectionsNumber"/>
</hbox>
</row>
<separator class="groove"/>
<description>&namespaceDesc.label;</description>
<grid>
<columns>
<column/>
<column/>
<column/>
</columns>
<rows>
<row align="center">
<separator class="indent"/>
<label control="personalNamespace" value="&personalNamespace.label;"
accesskey="&personalNamespace.accesskey;"/>
<textbox amsa_persist="true" id="personalNamespace" />
</row>
<row align="center">
<separator class="indent"/>
<label control="publicNamespace" value="&publicNamespace.label;"
accesskey="&publicNamespace.accesskey;"/>
<textbox amsa_persist="true" id="publicNamespace"/>
</row>
<row align="center">
<separator class="indent"/>
<label control="otherUsersNamespace" value="&otherUsersNamespace.label;"
accesskey="&otherUsersNamespace.accesskey;"/>
<textbox amsa_persist="true" id="otherUsersNamespace"/>
</row>
</rows>
</grid>
<grid>
<columns>
<column/>
<column/>
</columns>
<rows>
<row align="center">
<separator class="indent"/>
<checkbox amsa_persist="true" id="overrideNamespaces"
label="&overrideNamespaces.label;"
accesskey="&overrideNamespaces.accesskey;"/>
</row>
</rows>
</grid>
</vbox>
<!-- POP3 Panel -->
<vbox id="pop3Panel">
<label flex="1" control="folderStorage">&pop3DeferringDesc.label;</label>
<hbox align="center">
<radiogroup id="folderStorage"
orient="horizontal"
amsa_persist="true"
onselect="updateInboxAccount(this.selectedIndex == 1);">
<rows>
<row>
<radio id="deferToCurrentAccount"
value="currentAccount"
label="&accountInbox.label;"
accesskey="&accountInbox.accesskey;"/>
</row>
<row>
<vbox>
<hbox>
<radio id="deferToOtherAccount"
value="otherAccount"
label="&deferToServer.label;"
accesskey="&deferToServer.accesskey;">
</radio>
<menulist id="deferredServerFolderPicker"
class="folderMenuItem"
aria-labelledby="deferToServer">
<menupopup id="deferredServerPopup"
type="folder"
expandFolders="false"
mode="deferred"
oncommand="this.selectFolder(event.target._folder);"/>
</menulist>
</hbox>
<checkbox amsa_persist="true" id="deferGetNewMail"
label="&deferGetNewMail.label;" class="indent"
accesskey="&deferGetNewMail.accesskey;"/>
</vbox>
</row>
</rows>
</radiogroup>
</hbox>
</vbox>
</dialog>

View file

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
<!DOCTYPE page SYSTEM "chrome://messenger/locale/am-server-top.dtd" >
<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
</page>

View file

@ -0,0 +1,400 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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/. */
Components.utils.import("resource:///modules/iteratorUtils.jsm");
Components.utils.import("resource:///modules/MailUtils.js");
Components.utils.import("resource://gre/modules/Services.jsm");
var gServer;
function onSave()
{
let storeContractID = document.getElementById("server.storeTypeMenulist")
.selectedItem
.value;
document.getElementById("server.storeContractID")
.setAttribute("value", storeContractID);
}
function onInit(aPageId, aServerId)
{
initServerType();
onCheckItem("server.biffMinutes", ["server.doBiff"]);
onCheckItem("nntp.maxArticles", ["nntp.notifyOn"]);
setupMailOnServerUI();
setupFixedUI();
let serverType = document.getElementById("server.type").getAttribute("value");
if (serverType == "imap")
setupImapDeleteUI(aServerId);
// TLS Cert (External) and OAuth2 are only supported on IMAP.
document.getElementById("authMethod-oauth2").hidden = (serverType != "imap");
document.getElementById("authMethod-external").hidden = (serverType != "imap");
// "STARTTLS, if available" is vulnerable to MITM attacks so we shouldn't
// allow users to choose it anymore. Hide the option unless the user already
// has it set.
hideUnlessSelected(document.getElementById("connectionSecurityType-1"));
// UI for account store type.
let storeTypeElement = document.getElementById("server.storeTypeMenulist");
// set the menuitem to match the account
let currentStoreID = document.getElementById("server.storeContractID")
.getAttribute("value");
let targetItem = storeTypeElement.getElementsByAttribute("value", currentStoreID);
storeTypeElement.selectedItem = targetItem[0];
// disable store type change if store has already been used
storeTypeElement.setAttribute("disabled",
gServer.getBoolValue("canChangeStoreType") ? "false" : "true");
}
function onPreInit(account, accountValues)
{
var type = parent.getAccountValue(account, accountValues, "server", "type", null, false);
hideShowControls(type);
Services.obs.notifyObservers(null, "charsetmenu-selected", "other");
gServer = account.incomingServer;
if(!account.incomingServer.canEmptyTrashOnExit)
{
document.getElementById("server.emptyTrashOnExit").setAttribute("hidden", "true");
document.getElementById("imap.deleteModel.box").setAttribute("hidden", "true");
}
}
function initServerType()
{
var serverType = document.getElementById("server.type").getAttribute("value");
var propertyName = "serverType-" + serverType;
var messengerBundle = document.getElementById("bundle_messenger");
var verboseName = messengerBundle.getString(propertyName);
setDivText("servertype.verbose", verboseName);
secureSelect(true);
setLabelFromStringBundle("authMethod-no", "authNo");
setLabelFromStringBundle("authMethod-old", "authOld");
setLabelFromStringBundle("authMethod-kerberos", "authKerberos");
setLabelFromStringBundle("authMethod-external", "authExternal");
setLabelFromStringBundle("authMethod-ntlm", "authNTLM");
setLabelFromStringBundle("authMethod-oauth2", "authOAuth2");
setLabelFromStringBundle("authMethod-anysecure", "authAnySecure");
setLabelFromStringBundle("authMethod-any", "authAny");
setLabelFromStringBundle("authMethod-password-encrypted",
"authPasswordEncrypted");
//authMethod-password-cleartext already set in selectSelect()
// Hide deprecated/hidden auth options, unless selected
hideUnlessSelected(document.getElementById("authMethod-no"));
hideUnlessSelected(document.getElementById("authMethod-old"));
hideUnlessSelected(document.getElementById("authMethod-anysecure"));
hideUnlessSelected(document.getElementById("authMethod-any"));
}
function hideUnlessSelected(element)
{
element.hidden = !element.selected;
}
function setLabelFromStringBundle(elementID, stringName)
{
document.getElementById(elementID).label =
document.getElementById("bundle_messenger").getString(stringName);
}
function setDivText(divname, value)
{
var div = document.getElementById(divname);
if (!div)
return;
div.setAttribute("value", value);
}
function onAdvanced()
{
// Store the server type and, if an IMAP or POP3 server,
// the settings needed for the IMAP/POP3 tab into the array
var serverSettings = {};
var serverType = document.getElementById("server.type").getAttribute("value");
serverSettings.serverType = serverType;
serverSettings.serverPrettyName = gServer.prettyName;
serverSettings.account = top.getCurrentAccount();
if (serverType == "imap")
{
serverSettings.dualUseFolders = document.getElementById("imap.dualUseFolders").checked;
serverSettings.usingSubscription = document.getElementById("imap.usingSubscription").checked;
serverSettings.maximumConnectionsNumber = document.getElementById("imap.maximumConnectionsNumber").getAttribute("value");
// string prefs
serverSettings.personalNamespace = document.getElementById("imap.personalNamespace").getAttribute("value");
serverSettings.publicNamespace = document.getElementById("imap.publicNamespace").getAttribute("value");
serverSettings.serverDirectory = document.getElementById("imap.serverDirectory").getAttribute("value");
serverSettings.otherUsersNamespace = document.getElementById("imap.otherUsersNamespace").getAttribute("value");
serverSettings.overrideNamespaces = document.getElementById("imap.overrideNamespaces").checked;
}
else if (serverType == "pop3")
{
serverSettings.deferGetNewMail = document.getElementById("pop3.deferGetNewMail").checked;
serverSettings.deferredToAccount = document.getElementById("pop3.deferredToAccount").getAttribute("value");
}
window.openDialog("chrome://messenger/content/am-server-advanced.xul",
"_blank", "chrome,modal,titlebar", serverSettings);
if (serverType == "imap")
{
document.getElementById("imap.dualUseFolders").checked = serverSettings.dualUseFolders;
document.getElementById("imap.usingSubscription").checked = serverSettings.usingSubscription;
document.getElementById("imap.maximumConnectionsNumber").setAttribute("value", serverSettings.maximumConnectionsNumber);
// string prefs
document.getElementById("imap.personalNamespace").setAttribute("value", serverSettings.personalNamespace);
document.getElementById("imap.publicNamespace").setAttribute("value", serverSettings.publicNamespace);
document.getElementById("imap.serverDirectory").setAttribute("value", serverSettings.serverDirectory);
document.getElementById("imap.otherUsersNamespace").setAttribute("value", serverSettings.otherUsersNamespace);
document.getElementById("imap.overrideNamespaces").checked = serverSettings.overrideNamespaces;
}
else if (serverType == "pop3")
{
document.getElementById("pop3.deferGetNewMail").checked = serverSettings.deferGetNewMail;
document.getElementById("pop3.deferredToAccount").setAttribute("value", serverSettings.deferredToAccount);
let pop3Server = gServer.QueryInterface(Components.interfaces.nsIPop3IncomingServer);
// we're explicitly setting this so we'll go through the SetDeferredToAccount method
pop3Server.deferredToAccount = serverSettings.deferredToAccount;
// Setting the server to be deferred causes a rebuild of the account tree,
// losing the current selection. Reselect the current server again as it
// didn't really disappear.
parent.selectServer(parent.getCurrentAccount().incomingServer, parent.currentPageId);
// Iterate over all accounts to see if any of their junk targets are now
// invalid (pointed to the account that is now deferred).
// If any such target is found it is reset to a new safe folder
// (the deferred to account or Local Folders). If junk was really moved
// to that folder (moveOnSpam = true) then moving junk is disabled
// (so that the user notices it and checks the settings).
// This is the same sanitization as in am-junk.js, just applied to all POP accounts.
let deferredURI = serverSettings.deferredToAccount &&
MailServices.accounts.getAccount(serverSettings.deferredToAccount)
.incomingServer.serverURI;
for (let account in fixIterator(MailServices.accounts.accounts,
Components.interfaces.nsIMsgAccount)) {
let accountValues = parent.getValueArrayFor(account);
let type = parent.getAccountValue(account, accountValues, "server", "type",
null, false);
// Try to keep this list of account types not having Junk settings
// synchronized with the list in AccountManager.js.
if (type != "nntp" && type != "rss" && type != "im") {
let spamActionTargetAccount = parent.getAccountValue(account, accountValues,
"server", "spamActionTargetAccount", "string", true);
let spamActionTargetFolder = parent.getAccountValue(account, accountValues,
"server", "spamActionTargetFolder", "string", true);
let moveOnSpam = parent.getAccountValue(account, accountValues,
"server", "moveOnSpam", "bool", true);
// Check if there are any invalid junk targets and fix them.
[ spamActionTargetAccount, spamActionTargetFolder, moveOnSpam ] =
sanitizeJunkTargets(spamActionTargetAccount,
spamActionTargetFolder,
deferredURI || account.incomingServer.serverURI,
parent.getAccountValue(account, accountValues, "server", "moveTargetMode", "int", true),
account.incomingServer.spamSettings,
moveOnSpam);
parent.setAccountValue(accountValues, "server", "moveOnSpam", moveOnSpam);
parent.setAccountValue(accountValues, "server", "spamActionTargetAccount",
spamActionTargetAccount);
parent.setAccountValue(accountValues, "server", "spamActionTargetFolder",
spamActionTargetFolder);
}
}
}
}
function secureSelect(aLoading)
{
var socketType = document.getElementById("server.socketType").value;
var serverType = document.getElementById("server.type").value;
var defaultPort = gServer.protocolInfo.getDefaultServerPort(false);
var defaultPortSecure = gServer.protocolInfo.getDefaultServerPort(true);
var port = document.getElementById("server.port");
var portDefault = document.getElementById("defaultPort");
var prevDefaultPort = portDefault.value;
const Ci = Components.interfaces;
if (socketType == Ci.nsMsgSocketType.SSL) {
portDefault.value = defaultPortSecure;
if (port.value == "" || (!aLoading && port.value == defaultPort && prevDefaultPort != portDefault.value))
port.value = defaultPortSecure;
} else {
portDefault.value = defaultPort;
if (port.value == "" || (!aLoading && port.value == defaultPortSecure && prevDefaultPort != portDefault.value))
port.value = defaultPort;
}
// switch "insecure password" label
setLabelFromStringBundle("authMethod-password-cleartext",
socketType == Ci.nsMsgSocketType.SSL ||
socketType == Ci.nsMsgSocketType.alwaysSTARTTLS ?
"authPasswordCleartextViaSSL" : "authPasswordCleartextInsecurely");
}
function setupMailOnServerUI()
{
onCheckItem("pop3.deleteMailLeftOnServer", ["pop3.leaveMessagesOnServer"]);
setupAgeMsgOnServerUI();
}
function setupAgeMsgOnServerUI()
{
const kLeaveMsgsId = "pop3.leaveMessagesOnServer";
const kDeleteByAgeId = "pop3.deleteByAgeFromServer";
onCheckItem(kDeleteByAgeId, [kLeaveMsgsId]);
onCheckItem("daysEnd", [kLeaveMsgsId]);
onCheckItem("pop3.numDaysToLeaveOnServer", [kLeaveMsgsId, kDeleteByAgeId]);
}
function setupFixedUI()
{
var controls = [document.getElementById("fixedServerName"),
document.getElementById("fixedUserName"),
document.getElementById("fixedServerPort")];
var len = controls.length;
for (var i=0; i<len; i++) {
var fixedElement = controls[i];
var otherElement = document.getElementById(fixedElement.getAttribute("use"));
fixedElement.setAttribute("collapsed", "true");
otherElement.removeAttribute("collapsed");
}
}
function BrowseForNewsrc()
{
const nsIFilePicker = Components.interfaces.nsIFilePicker;
const nsIFile = Components.interfaces.nsIFile;
var newsrcTextBox = document.getElementById("nntp.newsrcFilePath");
var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
fp.init(window,
document.getElementById("browseForNewsrc").getAttribute("filepickertitle"),
nsIFilePicker.modeSave);
var currentNewsrcFile;
try {
currentNewsrcFile = Components.classes["@mozilla.org/file/local;1"]
.createInstance(nsIFile);
currentNewsrcFile.initWithPath(newsrcTextBox.value);
} catch (e) {
dump("Failed to create nsIFile instance for the current newsrc file.\n");
}
if (currentNewsrcFile) {
fp.displayDirectory = currentNewsrcFile.parent;
fp.defaultString = currentNewsrcFile.leafName;
}
fp.appendFilters(nsIFilePicker.filterAll);
if (fp.show() != nsIFilePicker.returnCancel)
newsrcTextBox.value = fp.file.path;
}
function setupImapDeleteUI(aServerId)
{
// read delete_model preference
var deleteModel = document.getElementById("imap.deleteModel").getAttribute("value");
selectImapDeleteModel(deleteModel);
// read trash_folder_name preference
var trashFolderName = getTrashFolderName();
// set folderPicker menulist
var trashPopup = document.getElementById("msgTrashFolderPopup");
trashPopup._teardown();
trashPopup._parentFolder = MailUtils.getFolderForURI(aServerId);
trashPopup._ensureInitialized();
// TODO: There is something wrong here, selectFolder() fails even if the
// folder does exist. Try to fix in bug 802609.
let trashFolder = MailUtils.getFolderForURI(aServerId + "/" + trashFolderName, false);
try {
trashPopup.selectFolder(trashFolder);
} catch(ex) {
trashPopup.parentNode.setAttribute("label", trashFolder.prettyName);
}
trashPopup.parentNode.folder = trashFolder;
}
function selectImapDeleteModel(choice)
{
// set deleteModel to selected mode
document.getElementById("imap.deleteModel").setAttribute("value", choice);
switch (choice)
{
case "0" : // markDeleted
// disable folderPicker
document.getElementById("msgTrashFolderPicker").setAttribute("disabled", "true");
break;
case "1" : // moveToTrashFolder
// enable folderPicker
document.getElementById("msgTrashFolderPicker").removeAttribute("disabled");
break;
case "2" : // deleteImmediately
// disable folderPicker
document.getElementById("msgTrashFolderPicker").setAttribute("disabled", "true");
break;
default :
dump("Error in enabling/disabling server.TrashFolderPicker\n");
break;
}
}
// Capture any menulist changes from folderPicker
function folderPickerChange(aEvent)
{
var folder = aEvent.target._folder;
var folderPath = getFolderPathFromRoot(folder);
// Set the value to be persisted.
document.getElementById("imap.trashFolderName")
.setAttribute("value", folderPath);
// Update the widget to show/do correct things even for subfolders.
var trashFolderPicker = document.getElementById("msgTrashFolderPicker");
trashFolderPicker.menupopup.selectFolder(folder);
}
/** Generate the relative folder path from the root. */
function getFolderPathFromRoot(folder)
{
var path = folder.name;
var parentFolder = folder.parent;
while (parentFolder && parentFolder != folder.rootFolder) {
path = parentFolder.name + "/" + path;
parentFolder = parentFolder.parent;
}
// IMAP Inbox URI's start with INBOX, not Inbox.
return path.replace(/^Inbox/, "INBOX");
}
// Get trash_folder_name from prefs
function getTrashFolderName()
{
var trashFolderName = document.getElementById("imap.trashFolderName").getAttribute("value");
// if the preference hasn't been set, set it to a sane default
if (!trashFolderName) {
trashFolderName = "Trash";
document.getElementById("imap.trashFolderName").setAttribute("value",trashFolderName);
}
return trashFolderName;
}

View file

@ -0,0 +1,468 @@
<?xml version="1.0"?>
<!--
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/. -->
<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/messenger.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/folderMenus.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/content/charsetList.css" type="text/css"?>
<!DOCTYPE page [
<!ENTITY % trashDTD SYSTEM "chrome://messenger/locale/am-server-top.dtd">
%trashDTD;
]>
<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&serverSettings.label;"
onload="parent.onPanelLoaded('am-server.xul');">
<vbox flex="1" style="overflow: auto;">
<script type="application/javascript" src="chrome://messenger/content/AccountManager.js"/>
<script type="application/javascript" src="chrome://messenger/content/am-server.js"/>
<script type="application/javascript" src="chrome://messenger/content/am-prefs.js"/>
<script type="application/javascript" src="chrome://messenger/content/amUtils.js"/>
<stringbundle id="bundle_messenger" src="chrome://messenger/locale/messenger.properties"/>
<label hidden="true" wsm_persist="true" id="server.type"/>
<label hidden="true"
wsm_persist="true"
preftype="string"
prefattribute="value"
prefstring="mail.server.%serverkey%.storeContractID"
genericattr="true"
id="server.storeContractID"/>
<dialogheader title="&serverSettings.label;"/>
<grid>
<columns>
<column/>
<column flex="1"/>
<column/>
</columns>
<rows>
<row align="center">
<label value="&serverType.label;"/>
<label id="servertype.verbose"/>
</row>
<row align="center">
<hbox>
<label value="&serverName.label;" accesskey="&serverName.accesskey;"
control="server.realHostName"/>
</hbox>
<hbox align="center">
<label id="fixedServerName" collapsed="true" use="server.realHostName"/>
<textbox wsm_persist="true"
size="20"
flex="1"
id="server.realHostName"
prefstring="mail.server.%serverkey%.realhostname"
class="uri-element"/>
</hbox>
<hbox align="center">
<label hidefor="movemail" value="&port.label;"
accesskey="&port.accesskey;" control="server.port"/>
<label id="fixedServerPort" hidefor="movemail"
collapsed="true" use="server.port"/>
<textbox wsm_persist="true" size="3" id="server.port"
preftype="int" hidefor="movemail"
prefstring="mail.server.%serverkey%.port"
type="number" min="1" max="65535" increment="1"/>
<label value="&serverPortDefault.label;" hidefor="movemail"/>
<label id="defaultPort" hidefor="movemail"/>
</hbox>
</row>
<row align="center">
<hbox align="center" hidefor="nntp">
<label value="&userName.label;"
accesskey="&userName.accesskey;"
control="server.realUsername"/>
</hbox>
<hbox align="center" hidefor="nntp">
<label id="fixedUserName" collapsed="true" use="server.realUsername"/>
<textbox wsm_persist="true"
size="20"
flex="1"
id="server.realUsername"
prefstring="mail.server.%serverkey%.realusername"/>
</hbox>
</row>
</rows>
</grid>
<separator class="thin"/>
<groupbox hidefor="movemail">
<caption label="&securitySettings.label;"/>
<grid flex="1">
<columns>
<column/>
<column/>
</columns>
<rows>
<row align="center">
<label value="&connectionSecurity.label;"
accesskey="&connectionSecurity.accesskey;"
control="server.socketType"/>
<menulist wsm_persist="true" id="server.socketType"
oncommand="secureSelect();">
<menupopup id="server.socketTypePopup">
<menuitem value="0" label="&connectionSecurityType-0.label;"/>
<menuitem id="connectionSecurityType-1"
value="1" label="&connectionSecurityType-1.label;"
disabled="true"/>
<menuitem value="2" label="&connectionSecurityType-2.label;"
hidefor="nntp"/>
<menuitem value="3" label="&connectionSecurityType-3.label;"/>
</menupopup>
</menulist>
</row>
<row align="center" hidefor="nntp,movemail">
<label value="&authMethod.label;"
accesskey="&authMethod.accesskey;"
control="server.authMethod"/>
<!-- same in smtpEditOverlay.xul/js -->
<menulist id="server.authMethod"
wsm_persist="true"
preftype="int" type="number"
prefstring="mail.server.%serverkey%.authMethod">
<menupopup id="server.authMethodPopup">
<menuitem id="authMethod-no" value="1"/>
<menuitem id="authMethod-old" value="2"/>
<menuitem id="authMethod-password-cleartext" value="3"/>
<menuitem id="authMethod-password-encrypted" value="4"/>
<menuitem id="authMethod-kerberos" value="5"/>
<menuitem id="authMethod-ntlm" value="6"/>
<menuitem id="authMethod-external" value="7"/>
<menuitem id="authMethod-oauth2" value="10"/>
<menuitem id="authMethod-anysecure" value="8"/>
<menuitem id="authMethod-any" value="9"/>
</menupopup>
</menulist>
</row>
</rows>
</grid>
</groupbox>
<groupbox>
<caption label="&serverSettings.label;"/>
<vbox align="start">
<checkbox wsm_persist="true"
id="server.loginAtStartUp"
label="&loginAtStartup.label;"
accesskey="&loginAtStartup.accesskey;"
prefattribute="value"
prefstring="mail.server.%serverkey%.login_at_startup"/>
</vbox>
<hbox align="center">
<checkbox wsm_persist="true"
id="server.doBiff"
label="&biffStart.label;"
accesskey="&biffStart.accesskey;"
oncommand="onCheckItem('server.biffMinutes', [this.id]);"
prefattribute="value"
prefstring="mail.server.%serverkey%.check_new_mail"/>
<textbox wsm_persist="true"
id="server.biffMinutes"
type="number"
size="3"
min="1"
increment="1"
aria-labelledby="server.doBiff server.biffMinutes biffEnd"
preftype="int"
prefstring="mail.server.%serverkey%.check_time"/>
<label id="biffEnd"
control="server.biffMinutes"
value="&biffEnd.label;"/>
</hbox>
<vbox align="start"
hidefor="pop3,nntp,movemail">
<checkbox wsm_persist="true"
id="imap.useIdle"
label="&useIdleNotifications.label;"
accesskey="&useIdleNotifications.accesskey;"
prefattribute="value"
prefstring="mail.server.%serverkey%.use_idle"/>
</vbox>
<!-- Necessary for POP3 and Movemail (Bug 480945) -->
<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=480945 -->
<vbox align="start" hidefor="imap,nntp">
<checkbox wsm_persist="true" id="server.downloadOnBiff"
label="&downloadOnBiff.label;" prefattribute="value"
accesskey="&downloadOnBiff.accesskey;"
prefstring="mail.server.%serverkey%.download_on_biff"/>
</vbox>
<!-- POP3 -->
<vbox align="start" hidefor="imap,nntp,movemail">
<checkbox wsm_persist="true" id="pop3.headersOnly"
label="&headersOnly.label;"
accesskey="&headersOnly.accesskey;"
prefattribute="value"
prefstring="mail.server.%serverkey%.headers_only"/>
<checkbox wsm_persist="true" id="pop3.leaveMessagesOnServer"
label="&leaveOnServer.label;" oncommand="setupMailOnServerUI();"
accesskey="&leaveOnServer.accesskey;"
prefattribute="value"
prefstring="mail.server.%serverkey%.leave_on_server"/>
<hbox align="center">
<checkbox wsm_persist="true" id="pop3.deleteByAgeFromServer" class="indent"
label="&deleteByAgeFromServer.label;" oncommand="setupAgeMsgOnServerUI();"
accesskey="&deleteByAgeFromServer.accesskey;"
prefattribute="value"
prefstring="mail.server.%serverkey%.delete_by_age_from_server"/>
<textbox wsm_persist="true" id="pop3.numDaysToLeaveOnServer" size="3"
aria-labelledby="pop3.deleteByAgeFromServer pop3.numDaysToLeaveOnServer daysEnd"
preftype="int" type="number" min="1" increment="1"
prefstring="mail.server.%serverkey%.num_days_to_leave_on_server"/>
<label id="daysEnd" control="pop3.numDaysToLeaveOnServer" value="&daysEnd.label;"/>
</hbox>
<checkbox wsm_persist="true" id="pop3.deleteMailLeftOnServer" class="indent"
label="&deleteOnServer2.label;"
accesskey="&deleteOnServer2.accesskey;"
prefattribute="value"
prefstring="mail.server.%serverkey%.delete_mail_left_on_server"/>
<!-- hidden elements for data transfer to and from advanced... dialog -->
<hbox flex="1" hidefor="imap,nntp,movemail" hidden="true">
<checkbox hidden="true" wsm_persist="true" id="pop3.deferGetNewMail"
prefattribute="value"
prefstring="mail.server.%serverkey%.deferGetNewMail"/>
<label hidden="true" wsm_persist="true" id="pop3.deferredToAccount"
prefattribute="value"
prefstring="mail.server.%serverkey%.deferredToAccount"/>
</hbox>
</vbox>
<!-- IMAP -->
<label hidden="true" wsm_persist="true" id="imap.trashFolderName"
prefattribute="value"
prefstring="mail.server.%serverkey%.trash_folder_name"/>
<hbox align="center" hidefor="pop3,nntp,movemail">
<label value="&deleteMessagePrefix.label;" align="left"
control="imap.deleteModel"/>
</hbox>
<vbox>
<hbox align="center"
id="imap.deleteModel.box"
hidefor="pop3,nntp,movemail"
flex="1">
<radiogroup id="imap.deleteModel"
wsm_persist="true"
oncommand="selectImapDeleteModel(this.value);"
prefstring="mail.server.%serverkey%.delete_model">
<grid class="specialFolderPickerGrid">
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<radio id="modelMoveToTrash"
value="1"
label="&modelMoveToTrash.label;"
accesskey="&modelMoveToTrash.accesskey;"/>
<menulist id="msgTrashFolderPicker" flex="1"
class="folderMenuItem"
maxwidth="300" crop="center"
aria-labelledby="modelMoveToTrash"
displayformat="verbose">
<menupopup id="msgTrashFolderPopup"
type="folder"
mode="filing"
showFileHereLabel="true"
oncommand="folderPickerChange(event);"/>
</menulist>
</row>
<row align="center">
<radio id="modelMarkDeleted"
value="0"
label="&modelMarkDeleted.label;"
accesskey="&modelMarkDeleted.accesskey;"/>
</row>
<row align="center">
<radio id="modelDeleteImmediately"
value="2"
label="&modelDeleteImmediately.label;"
accesskey="&modelDeleteImmediately.accesskey;"/>
</row>
</rows>
</grid>
</radiogroup>
</hbox>
<hbox pack="end">
<!-- This button should have identical attributes to the
server.popAdvancedButton except the hidefor attribute. -->
<button label="&advancedButton.label;"
accesskey="&advancedButton.accesskey;"
oncommand="onAdvanced();"
wsm_persist="true"
id="server.imapAdvancedButton"
prefstring="mail.server.%serverkey%.advanced.disable"
hidefor="pop3,nntp,movemail"/>
</hbox>
</vbox>
<!-- Advanced IMAP settings -->
<hbox flex="1" hidefor="pop3,nntp,movemail" hidden="true">
<checkbox hidden="true" wsm_persist="true" id="imap.dualUseFolders"
prefattribute="value"
prefstring="mail.server.%serverkey%.dual_use_folders"/>
<checkbox hidden="true" wsm_persist="true" id="imap.usingSubscription"
prefattribute="value"
prefstring="mail.server.%serverkey%.using_subscription"/>
<label hidden="true" wsm_persist="true" id="imap.maximumConnectionsNumber"/>
<label hidden="true" wsm_persist="true" id="imap.personalNamespace"/>
<label hidden="true" wsm_persist="true" id="imap.publicNamespace"/>
<label hidden="true" wsm_persist="true" id="imap.otherUsersNamespace"/>
<label hidden="true" wsm_persist="true" id="imap.serverDirectory"/>
<checkbox hidden="true" wsm_persist="true" id="imap.overrideNamespaces"
prefattribute="value"
prefstring="mail.server.%serverkey%.override_namespaces"/>
</hbox>
<!-- NNTP -->
<hbox hidefor="pop3,imap,movemail" align="center">
<checkbox wsm_persist="true" id="nntp.notifyOn"
label="&maxMessagesStart.label;"
accesskey="&maxMessagesStart.accesskey;"
oncommand="onCheckItem('nntp.maxArticles', [this.id]);"
prefattribute="value"
prefstring="mail.server.%serverkey%.notify.on"/>
<textbox wsm_persist="true" id="nntp.maxArticles"
type="number" size="4" min="1" increment="10"
aria-labelledby="nntp.notifyOn nntp.maxArticles maxMessagesEnd"
preftype="int"
prefstring="mail.server.%serverkey%.max_articles"/>
<label control="nntp.maxArticles" value="&maxMessagesEnd.label;" id="maxMessagesEnd"/>
</hbox>
<checkbox hidefor="pop3,imap,movemail" wsm_persist="true" id="nntp.pushAuth"
label="&alwaysAuthenticate.label;"
accesskey="&alwaysAuthenticate.accesskey;"
prefattribute="value"
prefstring="mail.server.%serverkey%.always_authenticate"/>
<!-- take out for now - bug 45079
<hbox flex="1" hidefor="pop3,imap,movemail">
<groupbox>
<caption class="header" label="&abbreviate.label;"/>
<radiogroup wsm_persist="true" id="nntp.abbreviate">
<radio value="true"
label="&abbreviateOn.label;"/>
<radio value="false"
label="&abbreviateOff.label;"/>
</radiogroup>
</groupbox>
</hbox>
-->
</groupbox>
<groupbox>
<caption label="&messageStorage.label;"/>
<hbox align="end">
<vbox align="start" flex="1" id="exitHandlingBox=">
<checkbox hidefor="pop3,nntp,movemail"
wsm_persist="true"
id="imap.cleanupInboxOnExit"
label="&expungeOnExit.label;"
accesskey="&expungeOnExit.accesskey;"
prefattribute="value"
prefstring="mail.server.%serverkey%.cleanup_inbox_on_exit"/>
<checkbox hidefor="nntp"
wsm_persist="true"
id="server.emptyTrashOnExit"
label="&emptyTrashOnExit.label;"
accesskey="&emptyTrashOnExit.accesskey;"
prefattribute="value"
prefstring="mail.server.%serverkey%.empty_trash_on_exit"/>
</vbox>
<button label="&advancedButton.label;"
accesskey="&advancedButton.accesskey;"
oncommand="onAdvanced();"
wsm_persist="true"
id="server.popAdvancedButton"
prefstring="mail.server.%serverkey%.advanced.disable"
hidefor="imap,nntp,movemail"/>
</hbox>
<hbox align="center">
<label value="&storeType.label;"
accesskey="&storeType.accesskey;"
control="server.storeTypeMenulist"/>
<menulist id="server.storeTypeMenulist">
<menupopup id="server.storeTypeMenupopup">
<menuitem id="server.mboxStore"
value="@mozilla.org/msgstore/berkeleystore;1"
label="&mboxStore2.label;"/>
<menuitem id="server.maildirStore"
value="@mozilla.org/msgstore/maildirstore;1"
label="&maildirStore.label;"/>
</menupopup>
</menulist>
</hbox>
<vbox hidefor="imap,pop3,movemail">
<label value="&newsrcFilePath.label;" control="nntp.newsrcFilePath"/>
<hbox align="center">
<textbox readonly="true"
wsm_persist="true"
flex="1"
id="nntp.newsrcFilePath"
datatype="nsIFile"
prefstring="mail.server.%serverkey%.newsrc.file"
class="uri-element"/>
<button id="browseForNewsrc"
label="&browseNewsrc.label;"
filepickertitle="&newsrcPicker.label;"
accesskey="&browseNewsrc.accesskey;"
oncommand="BrowseForNewsrc();"/>
</hbox>
</vbox>
<separator class="thin"/>
<vbox>
<label value="&localPath.label;" control="server.localPath"/>
<hbox align="center">
<textbox readonly="true"
wsm_persist="true"
flex="1"
id="server.localPath"
datatype="nsIFile"
prefstring="mail.server.%serverkey%.directory"
class="uri-element"/>
<button id="browseForLocalFolder"
label="&browseFolder.label;"
filepickertitle="&localFolderPicker.label;"
accesskey="&browseFolder.accesskey;"
oncommand="BrowseForLocalFolders();"/>
</hbox>
</vbox>
</groupbox>
<separator class="thin"/>
<hbox hidefor="imap,pop3,movemail" align="center" valign="middle" iscontrolcontainer="true">
<label value="&serverDefaultCharset2.label;" control="nntp.charset"/>
<menulist hidable="true"
type="charset"
hidefor="imap,pop3,movemail"
wsm_persist="true"
id="nntp.charset"
preftype="string"
prefstring="mail.server.%serverkey%.charset"/>
</hbox>
</vbox>
</page>

View file

@ -0,0 +1,34 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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/. */
var gServer;
function onInit(aPageId, aServerId) {
// UI for account store type
let storeTypeElement = document.getElementById("server.storeTypeMenulist");
// set the menuitem to match the account
let currentStoreID = document.getElementById("server.storeContractID")
.getAttribute("value");
let targetItem = storeTypeElement.getElementsByAttribute("value", currentStoreID);
storeTypeElement.selectedItem = targetItem[0];
// disable store type change if store has already been used
storeTypeElement.setAttribute("disabled",
gServer.getBoolValue("canChangeStoreType") ? "false" : "true");
}
function onPreInit(account, accountValues) {
gServer = account.incomingServer;
}
function onSave()
{
let storeContractID = document.getElementById("server.storeTypeMenulist")
.selectedItem
.value;
document.getElementById("server.storeContractID")
.setAttribute("value", storeContractID);
}

View file

@ -0,0 +1,77 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
<!DOCTYPE page [
<!ENTITY % accountNoIdentDTD SYSTEM "chrome://messenger/locale/am-serverwithnoidentities.dtd" >%accountNoIdentDTD;
<!ENTITY % accountServerTopDTD SYSTEM "chrome://messenger/locale/am-server-top.dtd">%accountServerTopDTD;
]>
<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&accountTitle.label;"
onload="parent.onPanelLoaded('am-serverwithnoidentities.xul');">
<script type="application/javascript" src="chrome://messenger/content/am-serverwithnoidentities.js"/>
<script type="application/javascript" src="chrome://messenger/content/amUtils.js"/>
<dialogheader title="&accountTitle.label;"/>
<label hidden="true"
wsm_persist="true"
preftype="string"
prefattribute="value"
prefstring="mail.server.%serverkey%.storeContractID"
genericattr="true"
id="server.storeContractID"/>
<description class="secDesc">&accountSettingsDesc.label;</description>
<hbox align="center">
<label value="&accountName.label;" control="server.prettyName"
accesskey="&accountName.accesskey;"/>
<textbox wsm_persist="true" size="30" id="server.prettyName"
prefstring="mail.server.%serverkey%.name"/>
</hbox>
<separator class="thin"/>
<groupbox>
<caption label="&messageStorage.label;"/>
<vbox align="start">
<checkbox wsm_persist="true" id="server.emptyTrashOnExit"
label="&emptyTrashOnExit.label;"
accesskey="&emptyTrashOnExit.accesskey;"
prefattribute="value"
prefstring="mail.server.%serverkey%.empty_trash_on_exit"/>
<hbox align="center">
<label value="&storeType.label;"
accesskey="&storeType.accesskey;"
control="server.storeTypeMenulist"/>
<menulist id="server.storeTypeMenulist">
<menupopup id="server.storeTypeMenupopup">
<menuitem id="server.mboxStore"
value="@mozilla.org/msgstore/berkeleystore;1"
label="&mboxStore2.label;"/>
<menuitem id="server.maildirStore"
value="@mozilla.org/msgstore/maildirstore;1"
label="&maildirStore.label;"/>
</menupopup>
</menulist>
</hbox>
</vbox>
<separator class="thin"/>
<label value="&localPath.label;" control="server.localPath"/>
<hbox align="center">
<textbox readonly="true" wsm_persist="true" flex="1" id="server.localPath" datatype="nsIFile"
prefstring="mail.server.%serverkey%.directory" class="uri-element"/>
<button id="browseForLocalFolder" label="&browseFolder.label;" filepickertitle="&localFolderPicker.label;"
accesskey="&browseFolder.accesskey;" oncommand="BrowseForLocalFolders()"/>
</hbox>
</groupbox>
</page>

View file

@ -0,0 +1,256 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource:///modules/mailServices.js");
var gSmtpServerListWindow =
{
mBundle: null,
mServerList: null,
mAddButton: null,
mEditButton: null,
mDeleteButton: null,
mSetDefaultServerButton: null,
onLoad: function()
{
parent.onPanelLoaded('am-smtp.xul');
this.mBundle = document.getElementById("bundle_messenger");
this.mServerList = document.getElementById("smtpList");
this.mAddButton = document.getElementById("addButton");
this.mEditButton = document.getElementById("editButton");
this.mDeleteButton = document.getElementById("deleteButton");
this.mSetDefaultServerButton = document.getElementById("setDefaultButton");
this.refreshServerList("", false);
this.updateButtons(this.getSelectedServer());
},
onSelectionChanged: function(aEvent)
{
if (this.mServerList.selectedItems.length <= 0)
return;
var server = this.getSelectedServer();
this.updateButtons(server);
this.updateServerInfoBox(server);
},
onDeleteServer: function (aEvent)
{
var server = this.getSelectedServer();
if (server)
{
// confirm deletion
let cancel = Services.prompt.confirmEx(window,
this.mBundle.getString('smtpServers-confirmServerDeletionTitle'),
this.mBundle.getFormattedString('smtpServers-confirmServerDeletion', [server.hostname], 1),
Services.prompt.STD_YES_NO_BUTTONS, null, null, null, null, { });
if (!cancel)
{
MailServices.smtp.deleteServer(server);
parent.replaceWithDefaultSmtpServer(server.key);
this.refreshServerList("", true);
}
}
},
onAddServer: function (aEvent)
{
this.openServerEditor(null);
},
onEditServer: function (aEvent)
{
if (this.mServerList.selectedItems.length <= 0)
return;
this.openServerEditor(this.getSelectedServer());
},
onSetDefaultServer: function(aEvent)
{
if (this.mServerList.selectedItems.length <= 0)
return;
MailServices.smtp.defaultServer = this.getSelectedServer();
this.refreshServerList(MailServices.smtp.defaultServer.key, true);
},
updateButtons: function(aServer)
{
// can't delete default server
if (MailServices.smtp.defaultServer == aServer)
{
this.mSetDefaultServerButton.setAttribute("disabled", "true");
this.mDeleteButton.setAttribute("disabled", "true");
}
else
{
this.mSetDefaultServerButton.removeAttribute("disabled");
this.mDeleteButton.removeAttribute("disabled");
}
if (this.mServerList.selectedItems.length == 0)
this.mEditButton.setAttribute("disabled", "true");
else
this.mEditButton.removeAttribute("disabled");
},
updateServerInfoBox: function(aServer)
{
var noneSelected = this.mBundle.getString("smtpServerList-NotSpecified");
document.getElementById('nameValue').value = aServer.hostname;
document.getElementById('descriptionValue').value = aServer.description || noneSelected;
document.getElementById('portValue').value = aServer.port;
document.getElementById('userNameValue').value = aServer.username || noneSelected;
document.getElementById('useSecureConnectionValue').value =
this.mBundle.getString("smtpServer-ConnectionSecurityType-" +
aServer.socketType);
const AuthMethod = Components.interfaces.nsMsgAuthMethod;
const SocketType = Components.interfaces.nsMsgSocketType;
var authStr = "";
switch (aServer.authMethod)
{
case AuthMethod.none:
authStr = "authNo";
break;
case AuthMethod.passwordEncrypted:
authStr = "authPasswordEncrypted";
break;
case AuthMethod.GSSAPI:
authStr = "authKerberos";
break;
case AuthMethod.NTLM:
authStr = "authNTLM";
break;
case AuthMethod.secure:
authStr = "authAnySecure";
break;
case AuthMethod.passwordCleartext:
authStr = (aServer.socketType == SocketType.SSL ||
aServer.socketType == SocketType.alwaysSTARTTLS)
? "authPasswordCleartextViaSSL"
: "authPasswordCleartextInsecurely";
break;
case AuthMethod.OAuth2:
authStr = "authOAuth2";
break;
default:
// leave empty
Components.utils.reportError("Warning: unknown value for smtpserver... authMethod: " +
aServer.authMethod);
}
if (authStr)
document.getElementById("authMethodValue").value =
this.mBundle.getString(authStr);
},
refreshServerList: function(aServerKeyToSelect, aFocusList)
{
// remove all children
while (this.mServerList.hasChildNodes())
this.mServerList.lastChild.remove();
this.fillSmtpServers(this.mServerList,
MailServices.smtp.servers,
MailServices.smtp.defaultServer);
if (aServerKeyToSelect)
this.setSelectedServer(this.mServerList.querySelector('[key="' + aServerKeyToSelect + '"]'));
else // select the default server
this.setSelectedServer(this.mServerList.querySelector('[default="true"]'));
if (aFocusList)
this.mServerList.focus();
},
fillSmtpServers: function(aListBox, aServers, aDefaultServer)
{
if (!aListBox || !aServers)
return;
while (aServers.hasMoreElements())
{
var server = aServers.getNext();
if (server instanceof Components.interfaces.nsISmtpServer)
{
var isDefault = (aDefaultServer.key == server.key);
var listitem = this.createSmtpListItem(server, isDefault);
aListBox.appendChild(listitem);
}
}
},
createSmtpListItem: function(aServer, aIsDefault)
{
var listitem = document.createElement("listitem");
var serverName = "";
if (aServer.description)
serverName = aServer.description + ' - ';
else if (aServer.username)
serverName = aServer.username + ' - ';
serverName += aServer.hostname;
if (aIsDefault)
{
serverName += " " + this.mBundle.getString("defaultServerTag");
listitem.setAttribute("default", "true");
}
listitem.setAttribute("label", serverName);
listitem.setAttribute("key", aServer.key);
listitem.setAttribute("class", "smtpServerListItem");
// give it some unique id
listitem.id = "smtpServer." + aServer.key;
return listitem;
},
openServerEditor: function(aServer)
{
var args = {server: aServer,
result: false,
addSmtpServer: ""};
window.openDialog("chrome://messenger/content/SmtpServerEdit.xul",
"smtpEdit", "chrome,titlebar,modal,centerscreen", args);
// now re-select the server which was just added
if (args.result)
this.refreshServerList(aServer ? aServer.key : args.addSmtpServer, true);
return args.result;
},
setSelectedServer: function(aServer)
{
if (!aServer)
return;
setTimeout(function(aServerList) {
aServerList.ensureElementIsVisible(aServer);
aServerList.selectItem(aServer);
}, 0, this.mServerList);
},
getSelectedServer: function()
{
if (this.mServerList.selectedItems.length == 0)
return null;
let serverKey = this.mServerList.selectedItems[0].getAttribute("key");
return MailServices.smtp.getServerByKey(serverKey);
}
};

View file

@ -0,0 +1,112 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
<!DOCTYPE page SYSTEM "chrome://messenger/locale/am-advanced.dtd">
<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&smtpServer.label;"
onload="gSmtpServerListWindow.onLoad();">
<script type="application/javascript"
src="chrome://messenger/content/amUtils.js"/>
<script type="application/javascript"
src="chrome://messenger/content/am-smtp.js"/>
<stringbundle id="bundle_messenger"
src="chrome://messenger/locale/messenger.properties"/>
<vbox flex="1" style="overflow: auto;">
<dialogheader title="&smtpServer.label;"/>
<label control="smtpList">&smtpDescription.label;</label>
<separator class="thin"/>
<hbox flex="1">
<listbox id="smtpList"
onselect="gSmtpServerListWindow.onSelectionChanged(event);"
ondblclick="gSmtpServerListWindow.onEditServer(event);"
flex="1"/>
<vbox>
<button id="addButton"
oncommand="gSmtpServerListWindow.onAddServer(event);"
label="&smtpListAdd.label;"
accesskey="&smtpListAdd.accesskey;"/>
<button id="editButton"
oncommand="gSmtpServerListWindow.onEditServer(event);"
label="&smtpListEdit.label;"
accesskey="&smtpListEdit.accesskey;"/>
<separator/>
<button id="deleteButton" disabled="true"
oncommand="gSmtpServerListWindow.onDeleteServer(event);"
label="&smtpListDelete.label;"
accesskey="&smtpListDelete.accesskey;"/>
<button id="setDefaultButton" disabled="true"
oncommand="gSmtpServerListWindow.onSetDefaultServer(event);"
label="&smtpListSetDefault.label;"
accesskey="&smtpListSetDefault.accesskey;"/>
</vbox>
</hbox>
<separator/>
<label class="header">&serverDetails.label;</label>
<hbox id="smtpServerInfoBox">
<stack flex="1" class="inset">
<spacer id="backgroundBox"/>
<grid>
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<hbox pack="end">
<label id="descriptionLabel"
value="&serverDescription.label;"
control="descriptionValue"/>
</hbox>
<textbox id="descriptionValue" readonly="true" class="plain"/>
</row>
<row align="center">
<hbox pack="end">
<label id="nameLabel" value="&serverName.label;" control="nameValue"/>
</hbox>
<textbox id="nameValue" readonly="true" class="plain"/>
</row>
<row align="center">
<hbox pack="end">
<label id="portLabel" value="&serverPort.label;" control="portValue"/>
</hbox>
<textbox id="portValue" readonly="true" class="plain"/>
</row>
<row align="center">
<hbox pack="end">
<label id="userNameLabel" value="&userName.label;" control="userNameValue"/>
</hbox>
<textbox id="userNameValue" readonly="true" class="plain"/>
</row>
<row align="center">
<hbox pack="end">
<label id="authMethodLabel" value="&authMethod.label;" control="authMethodValue"/>
</hbox>
<textbox id="authMethodValue" readonly="true" class="plain"/>
</row>
<row align="center">
<hbox pack="end">
<label id="connectionSecurityLabel" value="&connectionSecurity.label;"
control="useSecureConnectionValue"/>
</hbox>
<textbox id="useSecureConnectionValue" readonly="true" class="plain"/>
</row>
</rows>
</grid>
</stack>
</hbox>
<separator flex="1"/>
</vbox>
</page>

View file

@ -0,0 +1,205 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource:///modules/mailServices.js");
Components.utils.import("resource:///modules/MailUtils.js");
Components.utils.import("resource:///modules/iteratorUtils.jsm");
function BrowseForLocalFolders()
{
const nsIFilePicker = Components.interfaces.nsIFilePicker;
const nsIFile = Components.interfaces.nsIFile;
var currentFolderTextBox = document.getElementById("server.localPath");
var fp = Components.classes["@mozilla.org/filepicker;1"]
.createInstance(nsIFilePicker);
fp.init(window,
document.getElementById("browseForLocalFolder")
.getAttribute("filepickertitle"),
nsIFilePicker.modeGetFolder);
var currentFolder = Components.classes["@mozilla.org/file/local;1"]
.createInstance(nsIFile);
currentFolder.initWithPath(currentFolderTextBox.value);
fp.displayDirectory = currentFolder;
if (fp.show() != nsIFilePicker.returnOK)
return;
// Retrieve the selected folder.
let selectedFolder = fp.file;
// Check if the folder can be used for mail storage.
if (!top.checkDirectoryIsUsable(selectedFolder))
return;
currentFolderTextBox.value = selectedFolder.path;
}
/**
* Return server/folder name formatted with server name if needed.
*
* @param aTargetFolder nsIMsgFolder to format name for
* If target.isServer then only its name is returned.
* Otherwise return the name as "<foldername> on <servername>".
*/
function prettyFolderName(aTargetFolder)
{
if (aTargetFolder.isServer)
return aTargetFolder.prettyName;
return document.getElementById("bundle_messenger")
.getFormattedString("verboseFolderFormat",
[aTargetFolder.prettyName,
aTargetFolder.server.prettyName]);
}
/**
* Checks validity of junk target server name and folder.
*
* @param aTargetURI the URI specification to check
* @param aIsServer true if the URI specifies only a server (without folder)
*
* @return the value of aTargetURI if it is valid (usable), otherwise null
*/
function checkJunkTargetFolder(aTargetURI, aIsServer)
{
try {
// Does the target account exist?
let targetServer = MailUtils.getFolderForURI(aTargetURI + (aIsServer ? "/Junk" : ""),
!aIsServer).server;
// If the target server has deferred storage, Junk can't be stored into it.
if (targetServer.rootFolder != targetServer.rootMsgFolder)
return null;
} catch (e) {
return null;
}
return aTargetURI;
}
/**
* Finds a usable target for storing Junk mail.
* If the passed in server URI is not usable, choose Local Folders.
*
* @param aTargetURI the URI of a server or folder to try first
* @param aIsServer true if the URI specifies only a server (without folder)
*
* @return the server/folder URI of a usable target for storing Junk
*/
function chooseJunkTargetFolder(aTargetURI, aIsServer)
{
let server = null;
if (aTargetURI) {
server = MailUtils.getFolderForURI(aTargetURI, false).server;
if (!server.canCreateFoldersOnServer || !server.canSearchMessages ||
(server.rootFolder != server.rootMsgFolder))
server = null;
}
if (!server)
server = MailServices.accounts.localFoldersServer;
return server.serverURI + (!aIsServer ? "/Junk" : "");
}
/**
* Fixes junk target folders if they point to an invalid/unusable (e.g. deferred)
* folder/account. Only returns the new safe values. It is up to the caller
* to push them to the proper elements/prefs.
*
* @param aSpamActionTargetAccount The value of the server.*.spamActionTargetAccount pref value (URI).
* @param aSpamActionTargetFolder The value of the server.*.spamActionTargetFolder pref value (URI).
* @param aProposedTarget The URI of a new target to try.
* @param aMoveTargetModeValue The value of the server.*.moveTargetMode pref value (0/1).
* @param aServerSpamSettings The nsISpamSettings object of any server
* (used just for the MOVE_TARGET_MODE_* constants).
* @param aMoveOnSpam The server.*.moveOnSpam pref value (bool).
*
* @return an array containing:
* newTargetAccount new safe junk target account
* newTargetAccount new safe junk target folder
* newMoveOnSpam new moveOnSpam value
*/
function sanitizeJunkTargets(aSpamActionTargetAccount,
aSpamActionTargetFolder,
aProposedTarget,
aMoveTargetModeValue,
aServerSpamSettings,
aMoveOnSpam)
{
// Check if folder targets are valid.
aSpamActionTargetAccount = checkJunkTargetFolder(aSpamActionTargetAccount, true);
if (!aSpamActionTargetAccount) {
// If aSpamActionTargetAccount is not valid,
// reset to default behavior to NOT move junk messages...
if (aMoveTargetModeValue == aServerSpamSettings.MOVE_TARGET_MODE_ACCOUNT)
aMoveOnSpam = false;
// ... and find a good default target.
aSpamActionTargetAccount = chooseJunkTargetFolder(aProposedTarget, true);
}
aSpamActionTargetFolder = checkJunkTargetFolder(aSpamActionTargetFolder, false);
if (!aSpamActionTargetFolder) {
// If aSpamActionTargetFolder is not valid,
// reset to default behavior to NOT move junk messages...
if (aMoveTargetModeValue == aServerSpamSettings.MOVE_TARGET_MODE_FOLDER)
aMoveOnSpam = false;
// ... and find a good default target.
aSpamActionTargetFolder = chooseJunkTargetFolder(aProposedTarget, false);
}
return [ aSpamActionTargetAccount, aSpamActionTargetFolder, aMoveOnSpam ];
}
/**
* Opens Preferences (Options) dialog on the Advanced pane, General tab
* so that the user sees where the global receipts settings can be found.
*
* @param aTBPaneId Thunderbird pref paneID to open.
* @param aTBTabId Thunderbird tabID to open.
* @param aTBOtherArgs Other arguments to send to the pref tab.
* @param aSMPaneId Seamonkey pref pane to open.
*/
function openPrefsFromAccountManager(aTBPaneId, aTBTabId, aTBOtherArgs, aSMPaneId) {
let win = Services.wm.getMostRecentWindow("mail:3pane") ||
Services.wm.getMostRecentWindow("mail:messageWindow") ||
Services.wm.getMostRecentWindow("msgcompose");
if (!win)
return;
// If openOptionsDialog() exists, we are in Thunderbird.
if (typeof win.openOptionsDialog == "function")
win.openOptionsDialog(aTBPaneId, aTBTabId, aTBOtherArgs);
// If goPreferences() exists, we are in Seamonkey.
if (typeof win.goPreferences == "function")
win.goPreferences(aSMPaneId);
}
/**
* Check if the given account name already exists in any account.
*
* @param aAccountName The account name string to look for.
* @param aAccountKey Optional. The key of an account that is skipped when
* searching the name. If unset, do not skip any account.
*/
function accountNameExists(aAccountName, aAccountKey)
{
for (let account in fixIterator(MailServices.accounts.accounts,
Components.interfaces.nsIMsgAccount))
{
if (account.key != aAccountKey && account.incomingServer &&
aAccountName == account.incomingServer.prettyName) {
return true;
}
}
return false;
}

View file

@ -0,0 +1,73 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
var gPrefsBundle;
function acctNamePageValidate()
{
var accountname = document.getElementById("prettyName").value;
var canAdvance = accountname ? true : false;
// Check if this accountname already exists. If so, return false so that
// user can enter a different unique account name.
if (canAdvance && accountNameExists(accountname))
canAdvance = false;
document.documentElement.canAdvance = canAdvance;
}
function acctNamePageUnload() {
var pageData = parent.GetPageData();
// fix for bug #255473
// allow for multiple RSS accounts.
// if our isp.rdf file defines "wizardAutoGenerateUniqueHostname"
// we generate a unique hostname until we have one that doesn't exist
// for RSS accounts, in rss.rdf, userName, hostName and serverType
// default to the same thing, so we need to do this to allow for
// multiple RSS accounts. Note, they can all have the same pretty name.
if (gCurrentAccountData &&
gCurrentAccountData.wizardAutoGenerateUniqueHostname)
{
var serverType = parent.getCurrentServerType(pageData);
var userName = parent.getCurrentUserName(pageData);
var hostName = parent.getCurrentHostname(pageData);
var hostNamePref = hostName;
var i = 2;
while (parent.AccountExists(userName, hostName, serverType))
{
// If "Feeds" exists, try "Feeds-2", then "Feeds-3", etc.
hostName = hostNamePref + "-" + i;
i++;
}
setPageData(pageData, "server", "hostname", hostName);
}
var accountname = document.getElementById("prettyName").value;
setPageData(pageData, "accname", "prettyName", accountname);
// Set this to true so we know the user has set the name.
setPageData(pageData, "accname", "userset", true);
return true;
}
function acctNamePageInit()
{
gPrefsBundle = document.getElementById("bundle_prefs");
var accountNameInput = document.getElementById("prettyName");
if (accountNameInput.value=="") {
var pageData = parent.GetPageData();
var type = parent.getCurrentServerType(pageData);
var accountName;
if (gCurrentAccountData && gCurrentAccountData.wizardAccountName)
accountName = gCurrentAccountData.wizardAccountName;
else if (type == "nntp")
accountName = pageData.newsserver.hostname.value;
else
accountName = pageData.identity.email.value;
accountNameInput.value = accountName;
}
acctNamePageValidate();
}

View file

@ -0,0 +1,114 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
function setAccountTypeData()
{
var rg = document.getElementById("acctyperadio");
var selectedItemId = rg.selectedItem.id;
var mail = selectedItemId == "mailaccount";
var news = selectedItemId == "newsaccount";
var pageData = parent.GetPageData();
setPageData(pageData, "accounttype", "mailaccount", mail);
setPageData(pageData, "accounttype", "newsaccount", news);
// Other account type, e.g. Movemail
setPageData(pageData, "accounttype", "otheraccount", !(news || mail));
}
function acctTypePageUnload() {
gCurrentAccountData = null;
setAccountTypeData();
initializeIspData();
setupWizardPanels();
return true;
}
function setupWizardPanels() {
if (gCurrentAccountData && gCurrentAccountData.useOverlayPanels) {
if ("testingIspServices" in this) {
if ("SetPageMappings" in this && testingIspServices()) {
SetPageMappings(document.documentElement.currentPage.id, "done");
}
}
}
var pageData = parent.GetPageData();
// We default this to false, even though we could set it to true if we
// are going to display the page. However as the accname page will set
// it to true for us, we'll just default it to false and not work it out
// twice.
setPageData(pageData, "accname", "userset", false);
// If we need to skip wizardpanels, set the wizard to jump to the
// summary page i.e., last page. Otherwise, set the flow based
// on type of account (mail or news) user is creating.
var skipPanels = "";
try {
if (gCurrentAccountData.wizardSkipPanels)
skipPanels = gCurrentAccountData.wizardSkipPanels.toString().toLowerCase();
} catch(ex) {}
// "done" is the only required panel for all accounts. We used to require an identity panel but not anymore.
// initialize wizardPanels with the optional mail/news panels
var wizardPanels, i;
var isMailAccount = pageData.accounttype.mailaccount;
var isNewsAccount = pageData.accounttype.newsaccount;
if (skipPanels == "true") // Support old syntax of true/false for wizardSkipPanels
wizardPanels = new Array("identitypage");
else if (isMailAccount && isMailAccount.value)
wizardPanels = new Array("identitypage", "incomingpage", "outgoingpage", "accnamepage");
else if (isNewsAccount && isNewsAccount.value)
wizardPanels = new Array("identitypage", "newsserver", "accnamepage");
else { // An account created by an extension and XUL overlays
var button = document.getElementById("acctyperadio").selectedItem;
wizardPanels = button.value.split(/ *, */);
}
// Create a hash table of the panels to skip
var skipArray = skipPanels.split(",");
var skipHash = new Array();
for (i = 0; i < skipArray.length; i++)
skipHash[skipArray[i]] = skipArray[i];
// Remove skipped panels
i = 0;
while (i < wizardPanels.length) {
if (wizardPanels[i] in skipHash)
wizardPanels.splice(i, 1);
else
i++;
}
wizardPanels.push("done");
// Set up order of panels
for (i = 0; i < (wizardPanels.length-1); i++)
setNextPage(wizardPanels[i], wizardPanels[i+1]);
// make the account type page go to the very first of our approved wizard panels...this is usually going to
// be accounttype --> identitypage unless we were configured to skip the identity page
setNextPage("accounttype",wizardPanels[0]);
}
function initializeIspData()
{
let mailAccount = document.getElementById("mailaccount");
if (!mailAccount || !mailAccount.selected) {
parent.SetCurrentAccountData(null);
}
// now reflect the datasource up into the parent
var accountSelection = document.getElementById("acctyperadio");
var ispName = accountSelection.selectedItem.id;
dump("initializing ISP data for " + ispName + "\n");
if (!ispName || ispName == "") return;
parent.PrefillAccountForIsp(ispName);
}

View file

@ -0,0 +1,215 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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/. */
Components.utils.import("resource:///modules/mailServices.js");
var gPrefsBundle;
function donePageInit() {
var pageData = parent.GetPageData();
var currentAccountData = gCurrentAccountData;
if ("testingIspServices" in this) {
if (testingIspServices()) {
if ("setOtherISPServices" in this) {
setOtherISPServices();
}
if (currentAccountData && currentAccountData.useOverlayPanels && currentAccountData.createNewAccount) {
var backButton = document.documentElement.getButton("back");
backButton.setAttribute("disabled", true);
var cancelButton = document.documentElement.getButton("cancel");
cancelButton.setAttribute("disabled", true);
setPageData(pageData, "identity", "email", gEmailAddress);
setPageData(pageData, "identity", "fullName", gUserFullName);
setPageData(pageData, "login", "username", gScreenName);
}
}
}
gPrefsBundle = document.getElementById("bundle_prefs");
var showMailServerDetails = true;
if (currentAccountData) {
// find out if we need to hide server details
showMailServerDetails = currentAccountData.showServerDetailsOnWizardSummary;
// Change the username field description to email field label in aw-identity
if (currentAccountData.emailIDFieldTitle)
setUserNameDescField(currentAccountData.emailIDFieldTitle);
}
// Find out if we need to hide details for incoming servers
var hideIncoming = (gCurrentAccountData && gCurrentAccountData.wizardHideIncoming);
var email = "";
if (pageData.identity && pageData.identity.email) {
// fixup the email
email = pageData.identity.email.value;
if (email.split('@').length < 2 &&
currentAccountData &&
currentAccountData.domain)
email += "@" + currentAccountData.domain;
}
setDivTextFromForm("identity.email", email);
var userName="";
if (pageData.login && pageData.login.username)
userName = pageData.login.username.value;
if (!userName && email) {
if (currentAccountData && currentAccountData.incomingServerUserNameRequiresDomain == undefined)
currentAccountData.incomingServerUserNameRequiresDomain = false;
userName = getUsernameFromEmail(email, currentAccountData &&
currentAccountData.incomingServerUserNameRequiresDomain);
}
// Hide the "username" field if we don't want to show information
// on the incoming server.
setDivTextFromForm("server.username", hideIncoming ? null : userName);
var smtpUserName="";
if (pageData.login && pageData.login.smtpusername)
smtpUserName = pageData.login.smtpusername.value;
if (!smtpUserName && email)
smtpUserName = getUsernameFromEmail(email, currentAccountData &&
currentAccountData.smtpUserNameRequiresDomain);
setDivTextFromForm("smtpServer.username", smtpUserName);
if (pageData.accname && pageData.accname.prettyName) {
// If currentAccountData has a pretty name (e.g. news link or from
// isp data) only set the user name with the pretty name if the
// pretty name originally came from ispdata
if ((currentAccountData &&
currentAccountData.incomingServer.prettyName) &&
(pageData.ispdata &&
pageData.ispdata.supplied &&
pageData.ispdata.supplied.value))
{
// Get the polished account name - if the user has modified the
// account name then use that, otherwise use the userName.
pageData.accname.prettyName.value =
gPrefsBundle.getFormattedString("accountName",
[currentAccountData.incomingServer.prettyName,
(pageData.accname.userset && pageData.accname.userset.value) ? pageData.accname.prettyName.value : userName]);
}
// else just use the default supplied name
setDivTextFromForm("account.name", pageData.accname.prettyName.value);
} else {
setDivTextFromForm("account.name", "");
}
// Show mail servers (incoming&outgoing) details
// based on current account data. ISP can set
// rdf value of literal showServerDetailsOnWizardSummary
// to false to hide server details
if (showMailServerDetails && !serverIsNntp(pageData)) {
var incomingServerName="";
if (pageData.server && pageData.server.hostname) {
incomingServerName = pageData.server.hostname.value;
if (!incomingServerName &&
currentAccountData &&
currentAccountData.incomingServer.hostname)
incomingServerName = currentAccountData.incomingServer.hostName;
}
// Hide the incoming server name field if the user specified
// wizardHideIncoming in the ISP defaults file
setDivTextFromForm("server.name", hideIncoming ? null : incomingServerName);
setDivTextFromForm("server.port", pageData.server.port ? pageData.server.port.value : null);
var incomingServerType="";
if (pageData.server && pageData.server.servertype) {
incomingServerType = pageData.server.servertype.value;
if (!incomingServerType &&
currentAccountData &&
currentAccountData.incomingServer.type)
incomingServerType = currentAccountData.incomingServer.type;
}
setDivTextFromForm("server.type", incomingServerType.toUpperCase());
var smtpServerName="";
if (pageData.server && pageData.server.smtphostname) {
let smtpServer = MailServices.smtp.defaultServer;
smtpServerName = pageData.server.smtphostname.value;
if (!smtpServerName && smtpServer && smtpServer.hostname)
smtpServerName = smtpServer.hostname;
}
setDivTextFromForm("smtpServer.name", smtpServerName);
}
else {
setDivTextFromForm("server.name", null);
setDivTextFromForm("server.type", null);
setDivTextFromForm("server.port", null);
setDivTextFromForm("smtpServer.name", null);
}
if (serverIsNntp(pageData)) {
var newsServerName="";
if (pageData.newsserver && pageData.newsserver.hostname)
newsServerName = pageData.newsserver.hostname.value;
if (newsServerName) {
// No need to show username for news account
setDivTextFromForm("server.username", null);
}
setDivTextFromForm("newsServer.name", newsServerName);
setDivTextFromForm("server.port", null);
}
else {
setDivTextFromForm("newsServer.name", null);
}
var isPop = false;
if (pageData.server && pageData.server.servertype) {
isPop = (pageData.server.servertype.value == "pop3");
}
hideShowDownloadMsgsUI(isPop);
}
function hideShowDownloadMsgsUI(isPop)
{
// only show the "download messages now" UI
// if this is a pop account, we are online, and this was opened
// from the 3 pane
var downloadMsgs = document.getElementById("downloadMsgs");
if (isPop) {
if (!Services.io.offline) {
if (window.opener.location.href == "chrome://messenger/content/messenger.xul") {
downloadMsgs.hidden = false;
return;
}
}
}
// else hide it
downloadMsgs.hidden = true;
}
function setDivTextFromForm(divid, value) {
// collapse the row if the div has no value
var div = document.getElementById(divid);
if (!value) {
div.setAttribute("collapsed","true");
return;
}
else {
div.removeAttribute("collapsed");
}
// otherwise fill in the .text element
div = document.getElementById(divid+".text");
if (!div) return;
// set the value
div.setAttribute("value", value);
}
function setUserNameDescField(name)
{
if (name) {
var userNameField = document.getElementById("server.username.label");
userNameField.setAttribute("value", name);
}
}

View file

@ -0,0 +1,212 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
var gCurrentDomain;
var gPrefsBundle;
function identityPageValidate()
{
var canAdvance = false;
var name = document.getElementById("fullName").value;
let email = document.getElementById("email").value.trim();
if (name && email) {
canAdvance = gCurrentDomain ? emailNameIsLegal(email) : emailNameAndDomainAreLegal(email);
if (gCurrentDomain && canAdvance) {
// For prefilled ISP data we must check if the account already exists as
// there is no second chance. The email is the username since the user
// fills in [______]@example.com.
var pageData = parent.GetPageData();
var serverType = parent.getCurrentServerType(pageData);
var hostName = parent.getCurrentHostname(pageData);
var usernameWithDomain = email + "@" + gCurrentDomain;
if (parent.AccountExists(email, hostName, serverType) ||
parent.AccountExists(usernameWithDomain, hostName, serverType))
canAdvance = false;
}
}
document.documentElement.canAdvance = canAdvance;
}
function identityPageUnload()
{
var pageData = parent.GetPageData();
var name = document.getElementById("fullName").value;
let email = document.getElementById("email").value.trim();
setPageData(pageData, "identity", "fullName", name);
setPageData(pageData, "identity", "email", email);
return true;
}
// This is for the case when the code appends the domain
// unnecessarily.
// This simply gets rid of "@domain" from "foo@domain"
function fixPreFilledEmail()
{
var emailElement = document.getElementById("email");
var email = emailElement.value;
var emailArray = email.split('@');
if (gCurrentDomain) {
// check if user entered an @ sign even though we have a domain
if (emailArray.length >= 2) {
email = emailArray[0];
emailElement.value = email;
}
}
}
/**
* This function checks for common illegal characters.
* It shouldn't be too strict, since we do more extensive tests later.
*/
function emailNameIsLegal(aString)
{
return aString && !/[^!-?A-~]/.test(aString);
}
function emailNameAndDomainAreLegal(aString)
{
return /^[!-?A-~]+\@[A-Za-z0-9.-]+$/.test(aString);
}
function identityPageInit()
{
gCurrentDomain = null;
gPrefsBundle = document.getElementById("bundle_prefs");
clearEmailTextItems();
setEmailDescriptionText();
checkForDomain();
checkForFullName();
checkForEmail();
fixPreFilledEmail();
identityPageValidate();
}
function clearEmailTextItems()
{
var emailDescText = document.getElementById("emailDescText");
if (emailDescText.hasChildNodes())
emailDescText.firstChild.remove();
var postEmailText = document.getElementById("postEmailText");
postEmailText.setAttribute("value", "");
postEmailText.hidden = true;
}
// Use email example data that ISP has provided. ISP data, if avaialble
// for the choice user has made, will be read into CurrentAccountData.
// Default example data from properties will be used when the info is missing.
function setEmailDescriptionText()
{
var emailDescText = document.getElementById("emailDescText");
var emailFieldLabel = document.getElementById("emailFieldLabel");
var currentAccountData = parent.gCurrentAccountData;
var displayText = null;
var emailFieldLabelData = null;
var setDefaultEmailDescStrings = true;
// Set the default field label
emailFieldLabel.setAttribute("value", gPrefsBundle.getString("emailFieldText"));
// Get values for customized data from current account
if (currentAccountData)
{
var emailProvider = currentAccountData.emailProviderName;
var sampleEmail = currentAccountData.sampleEmail;
var sampleUserName = currentAccountData.sampleUserName;
var emailIDDesc = currentAccountData.emailIDDescription;
var emailIDTitle = currentAccountData.emailIDFieldTitle;
if (emailProvider &&
sampleEmail &&
sampleUserName &&
emailIDDesc &&
emailIDTitle)
{
// Get email description data
displayText = gPrefsBundle.getFormattedString("customizedEmailText",
[emailProvider,
emailIDDesc,
sampleEmail,
sampleUserName]);
// Set emailfield label
emailFieldLabelData = emailIDTitle;
emailFieldLabel.setAttribute("value", emailFieldLabelData);
// Need to display customized data. Turn off default settings.
setDefaultEmailDescStrings = false;
}
}
if (setDefaultEmailDescStrings)
{
// Check for obtained values and set with default values if needed
var username = gPrefsBundle.getString("exampleEmailUserName");
var domain = gPrefsBundle.getString("exampleEmailDomain");
displayText = gPrefsBundle.getFormattedString("defaultEmailText",
[username, domain]);
}
// Create a text nodes with text to be displayed
var emailDescTextNode = document.createTextNode(displayText);
// Display the dynamically generated text for email description
emailDescText.appendChild(emailDescTextNode);
}
// retrieve the current domain from the parent wizard window,
// and update the UI to add the @domain static text
function checkForDomain()
{
var accountData = parent.gCurrentAccountData;
if (!accountData || !accountData.domain)
return;
// save in global variable
gCurrentDomain = accountData.domain;
var postEmailText = document.getElementById("postEmailText");
postEmailText.setAttribute("value", "@" + gCurrentDomain);
postEmailText.hidden = false;
}
function checkForFullName() {
var name = document.getElementById("fullName");
if (name.value=="") {
try {
var userInfo = Components.classes["@mozilla.org/userinfo;1"].getService(Components.interfaces.nsIUserInfo);
name.value = userInfo.fullname;
}
catch (ex) {
// dump ("checkForFullName failed: " + ex + "\n");
}
}
}
function checkForEmail()
{
var email = document.getElementById("email");
var pageData = parent.GetPageData();
if (pageData && pageData.identity && pageData.identity.email) {
email.value = pageData.identity.email.value;
}
if (email.value=="") {
try {
var userInfo = Components.classes["@mozilla.org/userinfo;1"].getService(Components.interfaces.nsIUserInfo);
email.value = userInfo.emailAddress;
}
catch (ex) {
// dump ("checkForEmail failed: " + ex + "\n");
}
}
}

View file

@ -0,0 +1,176 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
Components.utils.import("resource:///modules/hostnameUtils.jsm");
var gOnMailServersPage;
var gOnNewsServerPage;
var gHideIncoming;
var gProtocolInfo = null;
function incomingPageValidate()
{
var canAdvance = true;
var hostName;
if (gOnMailServersPage) {
hostName = document.getElementById("incomingServer").value;
if (!gHideIncoming && !isLegalHostNameOrIP(cleanUpHostName(hostName)))
canAdvance = false;
}
if (gOnNewsServerPage) {
hostName = document.getElementById("newsServer").value;
if (!isLegalHostNameOrIP(cleanUpHostName(hostName)))
canAdvance = false;
}
if (canAdvance) {
var pageData = parent.GetPageData();
var serverType = parent.getCurrentServerType(pageData);
var username = document.getElementById("username").value;
if (gProtocolInfo && gProtocolInfo.requiresUsername && !username ||
parent.AccountExists(username, hostName, serverType))
canAdvance = false;
}
document.documentElement.canAdvance = canAdvance;
}
function incomingPageUnload()
{
var pageData = parent.GetPageData();
if (gOnMailServersPage) {
// If we have hidden the incoming server dialogs, we don't want
// to set the server to an empty value here
if (!gHideIncoming) {
var incomingServerName = document.getElementById("incomingServer");
setPageData(pageData, "server", "hostname", cleanUpHostName(incomingServerName.value));
}
var serverport = document.getElementById("serverPort").value;
setPageData(pageData, "server", "port", serverport);
var username = document.getElementById("username").value;
setPageData(pageData, "login", "username", username);
}
else if (gOnNewsServerPage) {
var newsServerName = document.getElementById("newsServer");
setPageData(pageData, "newsserver", "hostname", cleanUpHostName(newsServerName.value));
}
return true;
}
function incomingPageInit() {
gOnMailServersPage = (document.documentElement.currentPage.id == "incomingpage");
gOnNewsServerPage = (document.documentElement.currentPage.id == "newsserver");
if (gOnNewsServerPage)
{
var newsServer = document.getElementById("newsServer");
var pageData = parent.GetPageData();
try
{
newsServer.value = pageData.newsserver.hostname.value;
}
catch (ex){}
}
gHideIncoming = false;
if (gCurrentAccountData && gCurrentAccountData.wizardHideIncoming)
gHideIncoming = true;
var incomingServerbox = document.getElementById("incomingServerbox");
var serverTypeBox = document.getElementById("serverTypeBox");
if (incomingServerbox && serverTypeBox) {
if (gHideIncoming) {
incomingServerbox.setAttribute("hidden", "true");
serverTypeBox.setAttribute("hidden", "true");
}
else {
incomingServerbox.removeAttribute("hidden");
serverTypeBox.removeAttribute("hidden");
}
}
// Server type selection (pop3 or imap) is for mail accounts only
var pageData = parent.GetPageData();
var isMailAccount = pageData.accounttype.mailaccount.value;
var isOtherAccount = pageData.accounttype.otheraccount.value;
if (isMailAccount && !gHideIncoming) {
var serverTypeRadioGroup = document.getElementById("servertype");
/*
* Check to see if the radiogroup has any value. If there is no
* value, this must be the first time user visting this page in the
* account setup process. So, the default is set to pop3. If there
* is a value (it's used automatically), user has already visited
* page and server type selection is done. Once user visits the page,
* the server type value from then on will persist (whether the selection
* came from the default or the user action).
*/
if (!serverTypeRadioGroup.value) {
/*
* if server type was set to imap in isp data, then
* we preset the server type radio group accordingly,
* otherwise, use pop3 as the default.
*/
var serverTypeRadioItem = document.getElementById(pageData.server &&
pageData.server.servertype && pageData.server.servertype.value == "imap" ?
"imap" : "pop3");
serverTypeRadioGroup.selectedItem = serverTypeRadioItem; // Set pop3 server type as default selection
}
var leaveMessages = document.getElementById("leaveMessagesOnServer");
var deferStorage = document.getElementById("deferStorage");
setServerType();
setServerPrefs(leaveMessages);
setServerPrefs(deferStorage);
}
else if (isOtherAccount) {
document.getElementById("deferStorageBox").hidden = true;
}
if (pageData.server && pageData.server.hostname) {
var incomingServerTextBox = document.getElementById("incomingServer");
if (incomingServerTextBox && incomingServerTextBox.value == "")
incomingServerTextBox.value = pageData.server.hostname.value;
}
// pageData.server is not a real nsMsgIncomingServer so it does not have
// protocolInfo property implemented.
let type = parent.getCurrentServerType(pageData);
gProtocolInfo = Components.classes["@mozilla.org/messenger/protocol/info;1?type=" + type]
.getService(Components.interfaces.nsIMsgProtocolInfo);
var loginNameInput = document.getElementById("username");
if (loginNameInput.value == "") {
if (gProtocolInfo.requiresUsername) {
// since we require a username, use the uid from the email address
loginNameInput.value = parent.getUsernameFromEmail(pageData.identity.email.value, gCurrentAccountData &&
gCurrentAccountData.incomingServerUserNameRequiresDomain);
}
}
incomingPageValidate();
}
function setServerType()
{
var pageData = parent.GetPageData();
var serverType = document.getElementById("servertype").value;
var deferStorageBox = document.getElementById("deferStorageBox");
var leaveMessages = document.getElementById("leaveMsgsOnSrvrBox");
var port = serverType == "pop3" ? 110 : 143;
document.getElementById("serverPort").value = port;
document.getElementById("defaultPortValue").value = port;
deferStorageBox.hidden = serverType == "imap";
leaveMessages.hidden = serverType == "imap";
setPageData(pageData, "server", "servertype", serverType);
setPageData(pageData, "server", "port", port);
incomingPageValidate();
}
function setServerPrefs(aThis)
{
setPageData(parent.GetPageData(), "server", aThis.id, aThis.checked);
}

View file

@ -0,0 +1,151 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
Components.utils.import("resource:///modules/hostnameUtils.jsm");
Components.utils.import("resource:///modules/mailServices.js");
var gProtocolInfo = null;
var gPrefsBundle;
function outgoingPageValidate() {
let canAdvance = true;
let smtpServer = document.getElementById("smtphostname").value;
let usingDefaultSMTP = document.getElementById("noSmtp").hidden;
if (!usingDefaultSMTP && !isLegalHostNameOrIP(cleanUpHostName(smtpServer)))
canAdvance = false;
document.documentElement.canAdvance = canAdvance;
}
function outgoingPageUnload() {
var pageData = parent.GetPageData();
var username = document.getElementById("username").value;
let smtpserver = document.getElementById("smtphostname").value;
setPageData(pageData, "server", "smtphostname", cleanUpHostName(smtpserver));
// If SMTP username box is blank it is because the
// incoming and outgoing server names were the same,
// so set to be same as incoming username
var smtpusername = document.getElementById("smtpusername").value || username;
setPageData(pageData, "login", "smtpusername", smtpusername);
return true;
}
function outgoingPageInit() {
gPrefsBundle = document.getElementById("bundle_prefs");
var pageData = parent.GetPageData();
var smtpServer = null;
var smtpCreateNewServer = gCurrentAccountData && gCurrentAccountData.smtpCreateNewServer;
// Don't use the default smtp server if smtp server creation was explicitly
// requested in isp rdf.
// If we're reusing the default smtp we should not set the smtp hostname.
if (MailServices.smtp.defaultServer && !smtpCreateNewServer) {
smtpServer = MailServices.smtp.defaultServer;
setPageData(pageData, "identity", "smtpServerKey", "");
}
var noSmtpBox = document.getElementById("noSmtp");
var haveSmtpBox = document.getElementById("haveSmtp");
var boxToHide;
var boxToShow;
if (pageData.server && pageData.server.smtphostname && smtpCreateNewServer) {
var smtpTextBox = document.getElementById("smtphostname");
if (smtpTextBox && smtpTextBox.value == "")
smtpTextBox.value = pageData.server.smtphostname.value;
}
if (smtpServer && smtpServer.hostname) {
// we have a hostname, so modify and show the static text and
// store the value of the default smtp server in the textbox.
modifyStaticText(smtpServer.hostname, "1")
boxToShow = haveSmtpBox;
boxToHide = noSmtpBox;
}
else {
// no default hostname yet
boxToShow = noSmtpBox;
boxToHide = haveSmtpBox;
}
if (boxToHide)
boxToHide.setAttribute("hidden", "true");
if (boxToShow)
boxToShow.removeAttribute("hidden");
var smtpNameInput = document.getElementById("smtpusername");
smtpServer = MailServices.smtp.defaultServer;
if (smtpServer && smtpServer.hostname && smtpServer.username) {
// we have a default SMTP server, so modify and show the static text
// and store the username for the default server in the textbox.
modifyStaticText(smtpServer.username, "2")
hideShowLoginSettings(2, 1, 3);
smtpNameInput.value = smtpServer.username;
}
else {
// no default SMTP server yet, so need to compare
// incoming and outgoing server names
var smtpServerName = pageData.server.smtphostname.value;
var incomingServerName = pageData.server.hostname.value;
if (smtpServerName == incomingServerName) {
// incoming and outgoing server names are the same, so show
// the static text and make sure textbox blank for later tests.
modifyStaticText(smtpServerName, "3")
hideShowLoginSettings(3, 1, 2);
smtpNameInput.value = "";
}
else {
// incoming and outgoing server names are different, so set smtp
// username's textbox to be the same as incoming's one, unless already set.
hideShowLoginSettings(1, 2, 3);
smtpNameInput.value = smtpNameInput.value || loginNameInput.value;
}
}
outgoingPageValidate();
}
function modifyStaticText(smtpMod, smtpBox)
{
// modify the value in the smtp display if we already have a
// smtp server so that the single string displays the hostname
// or username for the smtp server.
var smtpStatic = document.getElementById("smtpStaticText"+smtpBox);
if (smtpStatic && smtpStatic.hasChildNodes())
smtpStatic.childNodes[0].nodeValue = smtpStatic.getAttribute("prefix") +
smtpMod + smtpStatic.getAttribute("suffix");
}
function hideShowLoginSettings(aEle, bEle, cEle)
{
document.getElementById("loginSet" + aEle).hidden = false;
document.getElementById("loginSet" + bEle).hidden = true;
document.getElementById("loginSet" + cEle).hidden = true;
}
var savedPassword="";
function onSavePassword(target) {
dump("savePassword changed! (" + target.checked + ")\n");
var passwordField = document.getElementById("server.password");
if (!passwordField) return;
if (target.checked) {
passwordField.removeAttribute("disabled");
passwordField.value = savedPassword;
}
else {
passwordField.setAttribute("disabled", "true");
savedPassword = passwordField.value;
passwordField.value = "";
}
}

View file

@ -0,0 +1,166 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
// using the rdf service extensively here
var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
// all the RDF resources we'll be retrieving
var NC = "http://home.netscape.com/NC-rdf#";
var Server = rdf.GetResource(NC + "Server");
var SmtpServer = rdf.GetResource(NC + "SmtpServer");
var ServerHost = rdf.GetResource(NC + "ServerHost");
var ServerType = rdf.GetResource(NC + "ServerType");
var PrefixIsUsername = rdf.GetResource(NC + "PrefixIsUsername");
var UseAuthenticatedSmtp= rdf.GetResource(NC + "UseAuthenticatedSmtp");
// this is possibly expensive, not sure what to do here
var ispDefaults;
var nsIRDFResource = Components.interfaces.nsIRDFResource;
var nsIRDFLiteral = Components.interfaces.nsIRDFLiteral;
var ispRoot = rdf.GetResource("NC:ispinfo");
// given an ISP's domain URI, look up all relevant information about it
function getIspDefaultsForUri(domainURI)
{
if (!ispDefaults)
ispDefaults = rdf.GetDataSource("rdf:ispdefaults");
var domainRes = rdf.GetResource(domainURI);
var result = dataSourceToObject(ispDefaults, domainRes);
if (!result) return null;
// The domainURI should be in the format domain:example.com. (Where
// example.com is the domain name to use for all email addresses). If
// it does not match this pattern, then it is possible no domain
// has been specified, so we should leave it uninitialized.
if (domainURI.startsWith("domain:")) {
// add this extra attribute which is the domain itself
var domainData = domainURI.split(':');
if (domainData.length > 1) {
// To faciltate distributing two different account types for one ISP,
// it's possible to add parameters to the domain URI
// - e.g. domain:example.com?type=imap.
// This is necessary so RDF doesn't think they're the same.
// Save the domain, but only the part up to the (possible) question mark.
result.domain = domainData[1].replace(/\?.*/, "");
}
}
return result;
}
// construct an ISP's domain URI based on it's domain
// (i.e. turns example.com -> domain:example.com)
function getIspDefaultsForDomain(domain) {
let domainURI = "domain:" + domain;
return getIspDefaultsForUri(domainURI);
}
// Given an email address (like "joe@example.com") look up
function getIspDefaultsForEmail(email) {
var emailData = getEmailInfo(email);
var ispData = null;
if (emailData)
ispData = getIspDefaultsForDomain(emailData.domain);
prefillIspData(ispData, email);
return ispData;
}
// given an email address, split it into username and domain
// return in an associative array
function getEmailInfo(email) {
if (!email) return null;
var result = new Object;
var emailData = email.split('@');
if (emailData.length != 2) {
dump("bad e-mail address!\n");
return null;
}
// all the variables we'll be returning
result.username = emailData[0];
result.domain = emailData[1];
return result;
}
function prefillIspData(ispData, email, fullName) {
if (!ispData) return;
// make sure these objects exist
if (!ispData.identity) ispData.identity = new Object;
if (!ispData.incomingServer) ispData.incomingServer = new Object;
// fill in e-mail if it's not already there
if (email && !ispData.identity.email)
ispData.identity.email = email;
var emailData = getEmailInfo(email);
if (emailData) {
// fill in the username (assuming the ISP doesn't prevent it)
if (!ispData.incomingServer.userName &&
!ispData.incomingServer.noDefaultUsername)
ispData.incomingServer.username = emailData.username;
}
}
// this function will extract an entire datasource into a giant
// associative array for easy retrieval from JS
var NClength = NC.length;
function dataSourceToObject(datasource, root)
{
var result = null;
var arcs = datasource.ArcLabelsOut(root);
while (arcs.hasMoreElements()) {
var arc = arcs.getNext().QueryInterface(nsIRDFResource);
var arcName = arc.Value;
arcName = arcName.substring(NClength, arcName.length);
if (!result) result = new Object;
var target = datasource.GetTarget(root, arc, true);
var value;
var targetHasChildren = false;
try {
target = target.QueryInterface(nsIRDFResource);
targetHasChildren = true;
} catch (ex) {
target = target.QueryInterface(nsIRDFLiteral);
}
if (targetHasChildren)
value = dataSourceToObject(datasource, target);
else {
value = target.Value;
// fixup booleans/numbers/etc
if (value == "true") value = true;
else if (value == "false") value = false;
else {
var num = Number(value);
if (!isNaN(num)) value = num;
}
}
// add this value
result[arcName] = value;
}
return result;
}

View file

@ -0,0 +1,156 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
Components.utils.import("resource:///modules/mailServices.js");
Components.utils.import("resource://gre/modules/Services.jsm");
var gServer;
var gDialog;
function onLoad(event) {
gServer = window.arguments[0].account.incomingServer;
gDialog = document.documentElement;
let bundle = document.getElementById("bundle_removeAccount");
let removeQuestion = bundle.getFormattedString("removeQuestion",
[gServer.prettyName]);
document.getElementById("accountName").textContent = removeQuestion;
// Allow to remove account data if it has a local storage.
let localDirectory = gServer.localPath;
if (localDirectory && localDirectory.exists()) {
localDirectory.normalize();
// Do not allow removal if localPath is outside of profile folder.
let profilePath = Services.dirsvc.get("ProfD", Components.interfaces.nsIFile);
profilePath.normalize();
// TODO: bug 77652, decide what to do for deferred accounts.
// And inform the user if the account localPath is outside the profile.
if ((gServer.isDeferredTo ||
(gServer instanceof Components.interfaces.nsIPop3IncomingServer &&
gServer.deferredToAccount)) ||
!profilePath.contains(localDirectory)) {
document.getElementById("removeData").disabled = true;
}
} else {
document.getElementById("removeDataPossibility").collapsed = true;
}
if (gServer.type == "im") {
let dataCheckbox = document.getElementById("removeData");
dataCheckbox.label = dataCheckbox.getAttribute("labelChat");
dataCheckbox.accessKey = dataCheckbox.getAttribute("accesskeyChat");
}
enableRemove();
window.sizeToContent();
}
function enableRemove() {
gDialog.getButton("accept").disabled =
(!document.getElementById("removeAccount").checked &&
!document.getElementById("removeData").checked);
}
/**
* Show the local directory.
*/
function openLocalDirectory() {
let nsLocalFile = Components.Constructor("@mozilla.org/file/local;1",
"nsILocalFile", "initWithPath");
let localDir = gServer.localPath.path;
try {
new nsLocalFile(localDir).reveal();
} catch(e) {
// Reveal may fail e.g. on Linux, then just show the path as a string.
document.getElementById("localDirectory").value = localDir;
document.getElementById("localDirectory").collapsed = false;
}
}
function showInfo() {
let descs = document.querySelectorAll("vbox.indent");
for (let desc of descs) {
desc.collapsed = false;
}
// TODO: bug 1238271, this should use showFor attributes if possible.
if (gServer.type == "imap" || gServer.type == "nntp") {
document.getElementById("serverAccount").collapsed = false;
} else if (gServer.type == "im") {
document.getElementById("chatAccount").collapsed = false;
} else {
document.getElementById("localAccount").collapsed = false;
}
window.sizeToContent();
gDialog.getButton("disclosure").disabled = true;
gDialog.getButton("disclosure").blur();
}
function removeAccount() {
let removeAccount = document.getElementById("removeAccount").checked;
let removeData = document.getElementById("removeData").checked;
try {
// Remove the requested account data.
if (removeAccount) {
// Remove account
// Need to save these before the account and its server is removed.
let serverUri = gServer.type + "://" + gServer.hostName;
let serverUsername = gServer.username;
MailServices.accounts.removeAccount(window.arguments[0].account, removeData);
window.arguments[0].result = true;
// Remove password information.
let logins = Services.logins.findLogins({}, serverUri, null, serverUri);
for (let i = 0; i < logins.length; i++) {
if (logins[i].username == serverUsername) {
Services.logins.removeLogin(logins[i]);
break;
}
}
} else if (removeData) {
// Remove files only.
// TODO: bug 1302193
window.arguments[0].result = false;
}
document.getElementById("status").selectedPanel =
document.getElementById("success");
} catch (ex) {
document.getElementById("status").selectedPanel =
document.getElementById("failure");
Components.utils.reportError("Failure to remove account: " + ex);
window.arguments[0].result = false;
}
}
function onAccept() {
// If Cancel is disabled, we already tried to remove the account
// and can only close the dialog.
if (gDialog.getButton("cancel").disabled)
return true;
gDialog.getButton("accept").disabled = true;
gDialog.getButton("cancel").disabled = true;
gDialog.getButton("disclosure").disabled = true;
// Change the "Remove" to an "OK" button by clearing the custom label.
gDialog.removeAttribute("buttonlabelaccept");
gDialog.removeAttribute("buttonaccesskeyaccept");
gDialog.getButton("accept").removeAttribute("label");
gDialog.getButton("accept").removeAttribute("accesskey");
gDialog.buttons = "accept";
document.getElementById("infoPane").selectedIndex = 1;
window.sizeToContent();
removeAccount();
gDialog.getButton("accept").disabled = false;
return false;
}

View file

@ -0,0 +1,87 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/messenger.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/dialogs.css" type="text/css"?>
<!DOCTYPE dialog [
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
<!ENTITY % removalDTD SYSTEM "chrome://messenger/locale/removeAccount.dtd">
%removalDTD;
]>
<dialog id="removeAccountDialog"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&dialogTitle;"
width="600"
buttons="accept,disclosure,cancel"
buttonlabelaccept="&removeButton.label;"
buttonaccesskeyaccept="&removeButton.accesskey;"
defaultButton="cancel"
onload="onLoad();"
ondialogdisclosure="showInfo();"
ondialogaccept="return onAccept();">
<stringbundle id="bundle_removeAccount"
src="chrome://messenger/locale/removeAccount.properties"/>
<script type="application/javascript"
src="chrome://messenger/content/removeAccount.js"/>
<deck id="infoPane">
<vbox flex="1">
<label id="accountName"></label>
<separator class="thin"/>
<checkbox id="removeAccount"
label="&removeAccount.label;"
checked="true"
disabled="true"
accesskey="&removeAccount.accesskey;"
oncommand="enableRemove();"/>
<vbox class="indent" collapsed="true">
<description>
&removeAccount.desc;
</description>
</vbox>
<vbox id="removeDataPossibility" collapsed="false">
<checkbox id="removeData"
label="&removeData.label;"
labelChat="&removeData.label;"
checked="false"
accesskey="&removeData.accesskey;"
accesskeyChat="&removeData.accesskey;"
oncommand="enableRemove();"/>
<vbox class="indent" collapsed="true">
<description id="localAccount" collapsed="true">
&removeDataLocalAccount.desc;
</description>
<description id="serverAccount" collapsed="true">
&removeDataServerAccount.desc;
</description>
<description id="chatAccount" collapsed="true">
&removeDataLocalAccount.desc;
</description>
<hbox align="center">
<button id="showLocalDirectory"
label="&showData.label;"
accesskey="&showData.accesskey;"
oncommand="openLocalDirectory();"/>
<label id="localDirectory" collapsed="true"/>
</hbox>
</vbox>
</vbox>
</vbox>
<vbox align="center">
<spacer flex="1"/>
<deck id="status">
<vbox align="center">
<label>&progressPending;</label>
<progressmeter mode="undetermined"/>
</vbox>
<label id="success">&progressSuccess;</label>
<label id="failure">&progressFailure;</label>
</deck>
<spacer flex="1"/>
</vbox>
</deck>
</dialog>

View file

@ -0,0 +1,182 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource:///modules/mailServices.js");
// be real hacky with document.getElementById until document.controls works
// with the new XUL widgets
var gSmtpUsername;
var gSmtpDescription;
var gSmtpUsernameLabel;
var gSmtpHostname;
var gSmtpPort;
var gSmtpAuthMethod;
var gSmtpSocketType;
var gPort;
var gDefaultPort;
var Ci = Components.interfaces;
function initSmtpSettings(server) {
gSmtpUsername = document.getElementById("smtp.username");
gSmtpDescription = document.getElementById("smtp.description");
gSmtpUsernameLabel = document.getElementById("smtp.username.label");
gSmtpHostname = document.getElementById("smtp.hostname");
gSmtpPort = document.getElementById("smtp.port");
gSmtpAuthMethod = document.getElementById("smtp.authMethod");
gSmtpSocketType = document.getElementById("smtp.socketType");
gDefaultPort = document.getElementById("smtp.defaultPort");
gPort = document.getElementById("smtp.port");
if (server) {
gSmtpHostname.value = server.hostname;
gSmtpDescription.value = server.description;
gSmtpPort.value = server.port;
gSmtpUsername.value = server.username;
gSmtpAuthMethod.value = server.authMethod;
gSmtpSocketType.value = (server.socketType < 4) ? server.socketType : 1;
} else {
// New server, load default values.
gSmtpAuthMethod.value = Services.prefs.getIntPref("mail.smtpserver.default.authMethod");
gSmtpSocketType.value = Services.prefs.getIntPref("mail.smtpserver.default.try_ssl");
}
// Although sslChanged will set a label for cleartext password,
// we need to use the long label so that we can size the dialog.
setLabelFromStringBundle("authMethod-no", "authNo");
setLabelFromStringBundle("authMethod-password-encrypted",
"authPasswordEncrypted");
setLabelFromStringBundle("authMethod-password-cleartext",
"authPasswordCleartextInsecurely");
setLabelFromStringBundle("authMethod-kerberos", "authKerberos");
setLabelFromStringBundle("authMethod-ntlm", "authNTLM");
setLabelFromStringBundle("authMethod-oauth2", "authOAuth2");
setLabelFromStringBundle("authMethod-anysecure", "authAnySecure");
setLabelFromStringBundle("authMethod-any", "authAny");
sizeToContent();
sslChanged(false);
authMethodChanged(false);
if (MailServices.smtp.defaultServer)
onLockPreference();
// Hide deprecated/hidden auth options, unless selected
hideUnlessSelected(document.getElementById("authMethod-anysecure"));
hideUnlessSelected(document.getElementById("authMethod-any"));
// "STARTTLS, if available" is vulnerable to MITM attacks so we shouldn't
// allow users to choose it anymore. Hide the option unless the user already
// has it set.
hideUnlessSelected(document.getElementById("connectionSecurityType-1"));
}
function hideUnlessSelected(element)
{
element.hidden = !element.selected;
}
function setLabelFromStringBundle(elementID, stringName)
{
document.getElementById(elementID).label =
document.getElementById("bundle_messenger").getString(stringName);
}
// Disables xul elements that have associated preferences locked.
function onLockPreference()
{
try {
let allPrefElements = {
hostname: gSmtpHostname,
description: gSmtpDescription,
port: gSmtpPort,
authMethod: gSmtpAuthMethod,
try_ssl: gSmtpSocketType
};
disableIfLocked(allPrefElements);
} catch (e) { // non-fatal
Components.utils.reportError("Error while getting locked prefs: " + e);
}
}
/**
* Does the work of disabling an element given the array which contains xul id/prefstring pairs.
*
* @param prefstrArray array of XUL elements to check
*
* TODO: try to merge this with disableIfLocked function in am-offline.js (bug 755885)
*/
function disableIfLocked(prefstrArray)
{
let finalPrefString = "mail.smtpserver." +
MailServices.smtp.defaultServer.key + ".";
let smtpPrefBranch = Services.prefs.getBranch(finalPrefString);
for (let prefstring in prefstrArray)
if (smtpPrefBranch.prefIsLocked(prefstring))
prefstrArray[prefstring].disabled = true;
}
function saveSmtpSettings(server)
{
//dump("Saving to " + server + "\n");
if (server) {
server.hostname = cleanUpHostName(gSmtpHostname.value);
server.description = gSmtpDescription.value;
server.port = gSmtpPort.value;
server.authMethod = gSmtpAuthMethod.value;
server.username = gSmtpUsername.value;
server.socketType = gSmtpSocketType.value;
}
}
function authMethodChanged(userAction)
{
var noUsername = gSmtpAuthMethod.value == Ci.nsMsgAuthMethod.none;
gSmtpUsername.disabled = noUsername;
gSmtpUsernameLabel.disabled = noUsername;
}
/**
* Resets the default port to SMTP or SMTPS, dependending on
* the |gSmtpSocketType| value, and sets the port to use to this default,
* if that's appropriate.
*
* @param userAction false for dialog initialization,
* true for user action.
*/
function sslChanged(userAction)
{
const DEFAULT_SMTP_PORT = "587";
const DEFAULT_SMTPS_PORT = "465";
var socketType = gSmtpSocketType.value;
var otherDefaultPort;
var prevDefaultPort = gDefaultPort.value;
if (socketType == Ci.nsMsgSocketType.SSL) {
gDefaultPort.value = DEFAULT_SMTPS_PORT;
otherDefaultPort = DEFAULT_SMTP_PORT;
} else {
gDefaultPort.value = DEFAULT_SMTP_PORT;
otherDefaultPort = DEFAULT_SMTPS_PORT;
}
// If the port is not set,
// or the user is causing the default port to change,
// and the port is set to the default for the other protocol,
// then set the port to the default for the new protocol.
if ((gPort.value == 0) ||
(userAction && (gDefaultPort.value != prevDefaultPort) &&
(gPort.value == otherDefaultPort)))
gPort.value = gDefaultPort.value;
// switch "insecure password" label
setLabelFromStringBundle("authMethod-password-cleartext",
socketType == Ci.nsMsgSocketType.SSL ||
socketType == Ci.nsMsgSocketType.alwaysSTARTTLS ?
"authPasswordCleartextViaSSL" : "authPasswordCleartextInsecurely");
}

View file

@ -0,0 +1,124 @@
<?xml version="1.0"?>
<!-- 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/. -->
<!DOCTYPE overlay SYSTEM "chrome://messenger/locale/smtpEditOverlay.dtd">
<overlay xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://messenger/content/smtpEditOverlay.js"/>
<vbox id="smtpServerEditor">
<groupbox>
<caption label="&settings.caption;"/>
<grid flex="1">
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<label value="&serverDescription.label;"
accesskey="&serverDescription.accesskey;"
control="smtp.description"/>
<textbox id="smtp.description"
flex="1"
preftype="string"
prefstring="mail.smtpserver.%serverkey%.description"/>
</row>
<row align="center">
<label value="&serverName.label;"
accesskey="&serverName.accesskey;"
control="smtp.hostname"/>
<textbox id="smtp.hostname"
flex="1"
preftype="string"
class="uri-element"
prefstring="mail.smtpserver.%serverkey%.hostname"/>
</row>
<row align="center">
<label value="&serverPort.label;"
accesskey="&serverPort.accesskey;"
control="smtp.port"/>
<hbox align="center">
<textbox id="smtp.port"
type="number"
min="0"
max="65535"
size="5"
preftype="int"
prefstring="mail.smtpserver.%serverkey%.port"/>
<label value="&serverPortDefault.label;"/>
<label id="smtp.defaultPort"/>
</hbox>
</row>
</rows>
</grid>
</groupbox>
<separator class="thin"/>
<groupbox>
<caption label="&security.caption;"/>
<grid flex="1">
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<label value="&connectionSecurity.label;"
accesskey="&connectionSecurity.accesskey;"
control="smtp.socketType"/>
<menulist id="smtp.socketType" oncommand="sslChanged(true);"
prefstring="mail.smtpserver.%serverkey%.try_ssl">
<menupopup id="smtp.socketTypePopup">
<menuitem value="0" label="&connectionSecurityType-0.label;"/>
<menuitem id="connectionSecurityType-1"
value="1" label="&connectionSecurityType-1.label;"
disabled="true" hidden="true"/>
<menuitem value="2" label="&connectionSecurityType-2.label;"/>
<menuitem value="3" label="&connectionSecurityType-3.label;"/>
</menupopup>
</menulist>
</row>
<row align="center">
<label value="&authMethod.label;"
accesskey="&authMethod.accesskey;"
control="server.authMethod"/>
<!-- same in am-server.xul/js -->
<menulist id="smtp.authMethod"
oncommand="authMethodChanged(true);"
wsm_persist="true"
preftype="int" type="number"
prefstring="mail.smtpserver.%serverkey%.authMethod">
<menupopup id="smtp.authMethodPopup">
<menuitem id="authMethod-no" value="1"/>
<menuitem id="authMethod-password-cleartext" value="3"/>
<menuitem id="authMethod-password-encrypted" value="4"/>
<menuitem id="authMethod-kerberos" value="5"/>
<menuitem id="authMethod-ntlm" value="6"/>
<menuitem id="authMethod-oauth2" value="10"/>
<menuitem id="authMethod-anysecure" value="8"/>
<menuitem id="authMethod-any" value="9"/>
</menupopup>
</menulist>
</row>
<row id="smtp.username.box" align="center">
<label id="smtp.username.label" value="&userName.label;"
accesskey="&userName.accesskey;"
control="smtp.username"/>
<textbox id="smtp.username" flex="1"
preftype="string"
prefstring="mail.smtpserver.%serverkey%.username"/>
</row>
</rows>
</grid>
</groupbox>
</vbox>
</overlay>