summaryrefslogtreecommitdiff
path: root/mailnews
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2021-10-21 13:00:16 -0400
committerMatt A. Tobin <email@mattatobin.com>2021-10-21 13:00:34 -0400
commit1c05565e168719d0a00e95e7afbd049413275f08 (patch)
tree0e200388901934755eab7c1f2cf2cf819c5fdee9 /mailnews
parenta82a18718dd6391108b5d3587364cff57db06b71 (diff)
downloadaura-central-1c05565e168719d0a00e95e7afbd049413275f08.tar.gz
Issue %3025 - Part 2: Remove HYPE_ICEDOVE and Baby Mode Account Creation
Diffstat (limited to 'mailnews')
-rw-r--r--mailnews/base/content/msgAccountCentral.xul34
-rw-r--r--mailnews/base/prefs/content/AccountManager.xul36
-rw-r--r--mailnews/base/prefs/content/AccountWizard.xul6
-rw-r--r--mailnews/base/prefs/content/accountcreation/MyBadCertHandler.js41
-rw-r--r--mailnews/base/prefs/content/accountcreation/accountConfig.js261
-rw-r--r--mailnews/base/prefs/content/accountcreation/createInBackend.js337
-rw-r--r--mailnews/base/prefs/content/accountcreation/emailWizard.js1976
-rw-r--r--mailnews/base/prefs/content/accountcreation/emailWizard.xul497
-rw-r--r--mailnews/base/prefs/content/accountcreation/fetchConfig.js237
-rw-r--r--mailnews/base/prefs/content/accountcreation/fetchhttp.js264
-rw-r--r--mailnews/base/prefs/content/accountcreation/guessConfig.js1192
-rw-r--r--mailnews/base/prefs/content/accountcreation/readFromXML.js243
-rw-r--r--mailnews/base/prefs/content/accountcreation/sanitizeDatatypes.js205
-rw-r--r--mailnews/base/prefs/content/accountcreation/util.js304
-rw-r--r--mailnews/base/prefs/content/accountcreation/verifyConfig.js353
-rw-r--r--mailnews/jar.mn14
16 files changed, 0 insertions, 6000 deletions
diff --git a/mailnews/base/content/msgAccountCentral.xul b/mailnews/base/content/msgAccountCentral.xul
index c1a43b035..f4ea19f49 100644
--- a/mailnews/base/content/msgAccountCentral.xul
+++ b/mailnews/base/content/msgAccountCentral.xul
@@ -153,46 +153,12 @@
<spacer id="CreateAccount.spacer" flex="1" collapsed="true"/>
<row id="CreateAccount" class="acctCentralRow" collapsed="true">
<hbox>
-#if defined(MOZ_THUNDERBIRD) && defined(HYPE_ICEDOVE)
- <label class="acctCentralText"
- value="&newAcct.label;"
- chromedir="&locale.dir;"/>
-#else
<label class="acctCentralText acctCentralLinkText"
value="&newAcctLink.label;"
chromedir="&locale.dir;"
onclick="CreateNewAccount();"/>
-#endif
</hbox>
</row>
-#if defined(MOZ_THUNDERBIRD) && defined(HYPE_ICEDOVE)
- <row id="CreateAccounts" class="acctCentralRow" collapsed="true">
- <vbox id="CreateAccountsList">
- <label id="CreateAccountMail"
- class="acctCentralNewAcctText acctCentralLinkText"
- value="&emailSectionHdr.label;"
- chromedir="&locale.dir;"
- onclick="CreateNewAccountTB('mail');"/>
- <label id="CreateAccountNewsgroups"
- class="acctCentralNewAcctText acctCentralLinkText"
- value="&newsSectionHdr.label;"
- chromedir="&locale.dir;"
- onclick="CreateNewAccountTB('newsgroups');"/>
- <label id="CreateAccountRSS"
- class="acctCentralNewAcctText acctCentralLinkText"
- value="&feedsSectionHdr.label;"
- chromedir="&locale.dir;"
- onclick="CreateNewAccountTB('feeds');"/>
-#ifdef HAVE_MOVEMAIL
- <label id="CreateAccountMovemail"
- class="acctCentralNewAcctText acctCentralLinkText"
- value="&movemail.label;"
- chromedir="&locale.dir;"
- onclick="CreateNewAccountTB('movemail');"/>
-#endif
- </vbox>
- </row>
-#endif
<spacer id="AccountsSection.spacer" class="big" flex="5" collapsed="true"/>
diff --git a/mailnews/base/prefs/content/AccountManager.xul b/mailnews/base/prefs/content/AccountManager.xul
index a14156b32..44c65ec4d 100644
--- a/mailnews/base/prefs/content/AccountManager.xul
+++ b/mailnews/base/prefs/content/AccountManager.xul
@@ -35,41 +35,6 @@
<treechildren id="account-tree-children"/>
</tree>
-#if defined(MOZ_THUNDERBIRD) && defined(HYPE_ICEDOVE)
- <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="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;"/>
@@ -79,7 +44,6 @@
<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"/>
diff --git a/mailnews/base/prefs/content/AccountWizard.xul b/mailnews/base/prefs/content/AccountWizard.xul
index 9d825084b..816f030d8 100644
--- a/mailnews/base/prefs/content/AccountWizard.xul
+++ b/mailnews/base/prefs/content/AccountWizard.xul
@@ -10,11 +10,7 @@
<wizard id="AccountWizard" title="&windowTitle.label;"
onwizardcancel="return onCancel();"
onwizardfinish="return FinishAccount();"
-#if defined(MOZ_THUNDERBIRD) && defined(HYPE_ICEDOVE)
- 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">
@@ -43,11 +39,9 @@
<label control="acctyperadio">&accountTypeDirections.label;</label>
<separator/>
<radiogroup id="acctyperadio" >
-#if !defined(MOZ_THUNDERBIRD) || !defined(HYPE_ICEDOVE)
<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"
diff --git a/mailnews/base/prefs/content/accountcreation/MyBadCertHandler.js b/mailnews/base/prefs/content/accountcreation/MyBadCertHandler.js
deleted file mode 100644
index 9f4c5034e..000000000
--- a/mailnews/base/prefs/content/accountcreation/MyBadCertHandler.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- 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;
- }
-};
diff --git a/mailnews/base/prefs/content/accountcreation/accountConfig.js b/mailnews/base/prefs/content/accountcreation/accountConfig.js
deleted file mode 100644
index 752c72624..000000000
--- a/mailnews/base/prefs/content/accountcreation/accountConfig.js
+++ /dev/null
@@ -1,261 +0,0 @@
-/* -*- 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,
-#ifdef MOZ_MAILNEWS_OAUTH2
- // OAuth2 configuration, if needed.
- oauthSettings : null,
-#endif
- // 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;
-}
diff --git a/mailnews/base/prefs/content/accountcreation/createInBackend.js b/mailnews/base/prefs/content/accountcreation/createInBackend.js
deleted file mode 100644
index cd984fd3c..000000000
--- a/mailnews/base/prefs/content/accountcreation/createInBackend.js
+++ /dev/null
@@ -1,337 +0,0 @@
-/* -*- 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);
-
-#ifdef MOZ_MAILNEWS_OAUTH2
- if (inServer.authMethod == Ci.nsMsgAuthMethod.OAuth2) {
- inServer.setCharValue("oauth2.scope", config.oauthSettings.scope);
- inServer.setCharValue("oauth2.issuer", config.oauthSettings.issuer);
- }
-#endif
-
- // 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);
- }
-
-#ifdef MOZ_MAILNEWS_OAUTH2
- 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);
- }
-#endif
-
- 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); }
-}
diff --git a/mailnews/base/prefs/content/accountcreation/emailWizard.js b/mailnews/base/prefs/content/accountcreation/emailWizard.js
deleted file mode 100644
index 2e4a44e2a..000000000
--- a/mailnews/base/prefs/content/accountcreation/emailWizard.js
+++ /dev/null
@@ -1,1976 +0,0 @@
-/* -*- 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");
-Components.utils.import("resource:///modules/hostnameUtils.jsm");
-#ifdef MOZ_MAILNEWS_OAUTH2
-Components.utils.import("resource://gre/modules/OAuth2Providers.jsm");
-#endif
-
-/**
- * This is the dialog opened by menu File | New account | Mail... .
- *
- * It gets the user's realname, email address and password,
- * and tries to automatically configure the account from that,
- * using various mechanisms. If all fails, the user can enter/edit
- * the config, then we create the account.
- *
- * Steps:
- * - User enters realname, email address and password
- * - check for config files on disk
- * (shipping with Thunderbird, for enterprise deployments)
- * - (if fails) try to get the config file from the ISP via a
- * fixed URL on the domain of the email address
- * - (if fails) try to get the config file from our own database
- * at MoMo servers, maintained by the community
- * - (if fails) try to guess the config, by guessing hostnames,
- * probing ports, checking config via server's CAPS line etc..
- * - verify the setup, by trying to login to the configured servers
- * - let user verify and maybe edit the server names and ports
- * - If user clicks OK, create the account
- */
-
-
-// from http://xyfer.blogspot.com/2005/01/javascript-regexp-email-validator.html
-var emailRE = /^[-_a-z0-9\'+*$^&%=~!?{}]+(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*@(?:[-a-z0-9.]+\.[a-z]{2,6}|\d{1,3}(?:\.\d{1,3}){3})(?::\d+)?$/i;
-
-if (typeof gEmailWizardLogger == "undefined") {
- Cu.import("resource:///modules/gloda/log4moz.js");
- var gEmailWizardLogger = Log4Moz.getConfiguredLogger("mail.wizard");
-}
-
-var gStringsBundle;
-var gMessengerBundle;
-var gBrandShortName;
-
-/*********************
-TODO for bug 549045
-- autodetect protocol
-Polish
-- reformat code style to match
-<https://developer.mozilla.org/En/Mozilla_Coding_Style_Guide#Control_Structures>
-- bold status
-- remove status when user edited in manual edit
-- add and adapt test from bug 534588
-Bugs
-- SSL cert errors
- - invalid cert (hostname mismatch) doesn't trigger warning dialog as it should
- - accept self-signed cert (e.g. imap.mail.ru) doesn't work
- (works without my patch),
- verifyConfig.js line 124 has no inServer, for whatever reason,
- although I didn't change verifyConfig.js at all
- (the change you see in that file is irrelevant: that was an attempt to fix
- the bug and clean up the code).
-- Set radio IMAP vs. POP3, see TODO in code
-Things to test (works for me):
-- state transitions, buttons enable, status msgs
- - stop button
- - showes up again after stopping detection and restarting it
- - when stopping [retest]: buttons proper?
- - enter nonsense domain. guess fails, (so automatically) manual,
- change domain to real one (not in DB), guess succeeds.
- former bug: goes to manual first shortly, then to result
-**********************/
-
-// To debug, set mail.wizard.logging.dump (or .console)="All"
-
-function e(elementID)
-{
- return document.getElementById(elementID);
-};
-
-function _hide(id)
-{
- e(id).hidden = true;
-}
-
-function _show(id)
-{
- e(id).hidden = false;
-}
-
-function _enable(id)
-{
- e(id).disabled = false;
-}
-
-function _disable(id)
-{
- e(id).disabled = true;
-}
-
-function setText(id, value)
-{
- var element = e(id);
- assert(element, "setText() on non-existant element ID");
-
- if (element.localName == "textbox" || element.localName == "label") {
- element.value = value;
- } else if (element.localName == "description") {
- element.textContent = value;
- } else {
- throw new NotReached("XUL element type not supported");
- }
-}
-
-function setLabelFromStringBundle(elementID, stringName)
-{
- e(elementID).label = gMessengerBundle.getString(stringName);
-};
-
-function EmailConfigWizard()
-{
- this._init();
-}
-EmailConfigWizard.prototype =
-{
- _init : function EmailConfigWizard__init()
- {
- gEmailWizardLogger.info("Initializing setup wizard");
- this._abortable = null;
- },
-
- onLoad : function()
- {
- /**
- * this._currentConfig is the config we got either from the XML file or
- * from guessing or from the user. Unless it's from the user, it contains
- * placeholders like %EMAILLOCALPART% in username and other fields.
- *
- * The config here must retain these placeholders, to be able to
- * adapt when the user enters a different realname, or password or
- * email local part. (A change of the domain name will trigger a new
- * detection anyways.)
- * That means, before you actually use the config (e.g. to create an
- * account or to show it to the user), you need to run replaceVariables().
- */
- this._currentConfig = null;
-
- let userFullname;
- try {
- let userInfo = Cc["@mozilla.org/userinfo;1"].getService(Ci.nsIUserInfo);
- userFullname = userInfo.fullname;
- } catch(e) {
- // nsIUserInfo may not be implemented on all platforms, and name might
- // not be avaialble even if it is.
- }
-
- this._domain = "";
- this._email = "";
- this._realname = (userFullname) ? userFullname : "";
- e("realname").value = this._realname;
- this._password = "";
- this._okCallback = null;
-
- if (window.arguments && window.arguments[0]) {
- if (window.arguments[0].msgWindow) {
- this._parentMsgWindow = window.arguments[0].msgWindow;
- }
- if (window.arguments[0].okCallback) {
- this._okCallback = window.arguments[0].okCallback;
- }
- }
-
- gEmailWizardLogger.info("Email account setup dialog loaded.");
-
- gStringsBundle = e("strings");
- gMessengerBundle = e("bundle_messenger");
- gBrandShortName = e("bundle_brand").getString("brandShortName");
-
- setLabelFromStringBundle("in-authMethod-password-cleartext",
- "authPasswordCleartextViaSSL"); // will warn about insecure later
- setLabelFromStringBundle("in-authMethod-password-encrypted",
- "authPasswordEncrypted");
- setLabelFromStringBundle("in-authMethod-kerberos", "authKerberos");
- setLabelFromStringBundle("in-authMethod-ntlm", "authNTLM");
-#ifdef MOZ_MAILNEWS_OAUTH2
- setLabelFromStringBundle("in-authMethod-oauth2", "authOAuth2");
-#endif
- setLabelFromStringBundle("out-authMethod-no", "authNo");
- setLabelFromStringBundle("out-authMethod-password-cleartext",
- "authPasswordCleartextViaSSL"); // will warn about insecure later
- setLabelFromStringBundle("out-authMethod-password-encrypted",
- "authPasswordEncrypted");
- setLabelFromStringBundle("out-authMethod-kerberos", "authKerberos");
- setLabelFromStringBundle("out-authMethod-ntlm", "authNTLM");
-#ifdef MOZ_MAILNEWS_OAUTH2
- setLabelFromStringBundle("out-authMethod-oauth2", "authOAuth2");
-#endif
-
- e("incoming_port").value = gStringsBundle.getString("port_auto");
- this.fillPortDropdown("smtp");
-
- // If the account provisioner is preffed off, don't display
- // the account provisioner button.
- if (!Services.prefs.getBoolPref("mail.provider.enabled"))
- _hide("provisioner_button");
-
- // Populate SMTP server dropdown with already configured SMTP servers from
- // other accounts.
- var menulist = e("outgoing_hostname");
- let smtpServers = MailServices.smtp.servers;
- while (smtpServers.hasMoreElements()) {
- let server = smtpServers.getNext().QueryInterface(Ci.nsISmtpServer);
- let label = server.displayname;
- let key = server.key;
- if (MailServices.smtp.defaultServer &&
- MailServices.smtp.defaultServer.key == key) {
- label += " " + gStringsBundle.getString("default_server_tag");
- }
- let menuitem = menulist.appendItem(label, key, ""); // label,value,descr
- menuitem.serverKey = key;
- }
- // Add the entry for the new host to the menulist
- let menuitem = menulist.insertItemAt(0, "", "-new-"); // pos,label,value
- menuitem.serverKey = null;
-
- // admin-locked prefs hurray
- if (!Services.prefs.getBoolPref("signon.rememberSignons")) {
- let rememberPasswordE = e("remember_password");
- rememberPasswordE.checked = false;
- rememberPasswordE.disabled = true;
- }
-
- // First, unhide the main window areas, and store the width,
- // so that we don't resize wildly when we unhide areas.
- // switchToMode() will then hide the unneeded parts again.
- // We will add some leeway of 10px, in case some of the <description>s wrap,
- // e.g. outgoing username != incoming username.
- _show("status_area");
- _show("result_area");
- _hide("manual-edit_area");
- window.sizeToContent();
- e("mastervbox").setAttribute("style",
- "min-width: " + document.width + "px; " +
- "min-height: " + (document.height + 10) + "px;");
-
- this.switchToMode("start");
- e("realname").select();
- },
-
- /**
- * Changes the window configuration to the different modes we have.
- * Shows/hides various window parts and buttons.
- * @param modename {String-enum}
- * "start" : Just the realname, email address, password fields
- * "find-config" : detection step, adds the progress message/spinner
- * "result" : We found a config and display it to the user.
- * The user may create the account.
- * "manual-edit" : The user wants (or needs) to manually enter their
- * the server hostname and other settings. We'll use them as provided.
- * Additionally, there are the following sub-modes which can be entered after
- * you entered the main mode:
- * "manual-edit-have-hostname" : user entered a hostname for both servers
- * that we can use
- * "manual-edit-testing" : User pressed the [Re-test] button and
- * we're currently detecting the "Auto" values
- * "manual-edit-complete" : user entered (or we tested) all necessary
- * values, and we're ready to create to account
- * Currently, this doesn't cover the warning dialogs etc.. It may later.
- */
- switchToMode : function(modename)
- {
- if (modename == this._currentModename) {
- return;
- }
- this._currentModename = modename;
- gEmailWizardLogger.info("switching to UI mode " + modename)
-
- //_show("initialSettings"); always visible
- //_show("cancel_button"); always visible
- if (modename == "start") {
- _hide("status_area");
- _hide("result_area");
- _hide("manual-edit_area");
-
- _show("next_button");
- _disable("next_button"); // will be enabled by code
- _hide("half-manual-test_button");
- _hide("create_button");
- _hide("stop_button");
- _hide("manual-edit_button");
- _hide("advanced-setup_button");
- } else if (modename == "find-config") {
- _show("status_area");
- _hide("result_area");
- _hide("manual-edit_area");
-
- _show("next_button");
- _disable("next_button");
- _hide("half-manual-test_button");
- _hide("create_button");
- _show("stop_button");
- this.onStop = this.onStopFindConfig;
- _show("manual-edit_button");
- _hide("advanced-setup_button");
- } else if (modename == "result") {
- _show("status_area");
- _show("result_area");
- _hide("manual-edit_area");
-
- _hide("next_button");
- _hide("half-manual-test_button");
- _show("create_button");
- _enable("create_button");
- _hide("stop_button");
- _show("manual-edit_button");
- _hide("advanced-setup_button");
- } else if (modename == "manual-edit") {
- _show("status_area");
- _hide("result_area");
- _show("manual-edit_area");
-
- _hide("next_button");
- _show("half-manual-test_button");
- _disable("half-manual-test_button");
- _show("create_button");
- _disable("create_button");
- _hide("stop_button");
- _hide("manual-edit_button");
- _show("advanced-setup_button");
- _disable("advanced-setup_button");
- } else if (modename == "manual-edit-have-hostname") {
- _show("status_area");
- _hide("result_area");
- _show("manual-edit_area");
- _hide("manual-edit_button");
- _hide("next_button");
- _show("create_button");
-
- _show("half-manual-test_button");
- _enable("half-manual-test_button");
- _disable("create_button");
- _hide("stop_button");
- _show("advanced-setup_button");
- _disable("advanced-setup_button");
- } else if (modename == "manual-edit-testing") {
- _show("status_area");
- _hide("result_area");
- _show("manual-edit_area");
- _hide("manual-edit_button");
- _hide("next_button");
- _show("create_button");
-
- _show("half-manual-test_button");
- _disable("half-manual-test_button");
- _disable("create_button");
- _show("stop_button");
- this.onStop = this.onStopHalfManualTesting;
- _show("advanced-setup_button");
- _disable("advanced-setup_button");
- } else if (modename == "manual-edit-complete") {
- _show("status_area");
- _hide("result_area");
- _show("manual-edit_area");
- _hide("manual-edit_button");
- _hide("next_button");
- _show("create_button");
-
- _show("half-manual-test_button");
- _enable("half-manual-test_button");
- _enable("create_button");
- _hide("stop_button");
- _show("advanced-setup_button");
- _enable("advanced-setup_button");
- } else {
- throw new NotReached("unknown mode");
- }
- // If we're offline, we're going to disable the create button, but enable
- // the advanced config button if we have a current config.
- if (Services.io.offline) {
- if (this._currentConfig != null) {
- _show("advanced-setup_button");
- _enable("advanced-setup_button");
- _hide("half-manual-test_button");
- _hide("create_button");
- _hide("manual-edit_button");
- }
- }
- window.sizeToContent();
- },
-
- /**
- * Start from beginning with possibly new email address.
- */
- onStartOver : function() {
- this._currentConfig = null;
- if (this._abortable) {
- this.onStop();
- }
- this.switchToMode("start");
- },
-
- getConcreteConfig : function()
- {
- var result = this._currentConfig.copy();
- replaceVariables(result, this._realname, this._email, this._password);
- result.rememberPassword = e("remember_password").checked &&
- !!this._password;
- return result;
- },
-
- /*
- * This checks if the email address is at least possibly valid, meaning it
- * has an '@' before the last char.
- */
- validateEmailMinimally : function(emailAddr)
- {
- let atPos = emailAddr.lastIndexOf("@");
- return atPos > 0 && atPos + 1 < emailAddr.length;
- },
-
- /*
- * This checks if the email address is syntactically valid,
- * as far as we can determine. We try hard to make full checks.
- *
- * OTOH, we have a very small chance of false negatives,
- * because the RFC822 address spec is insanely complicated,
- * but rarely needed, so when this here fails, we show an error message,
- * but don't stop the user from continuing.
- * In contrast, if validateEmailMinimally() fails, we stop the user.
- */
- validateEmail : function(emailAddr)
- {
- return emailRE.test(emailAddr);
- },
-
- /**
- * onInputEmail and onInputRealname are called on input = keypresses, and
- * enable/disable the next button based on whether there's a semi-proper
- * e-mail address and non-blank realname to start with.
- *
- * A change to the email address also automatically restarts the
- * whole process.
- */
- onInputEmail : function()
- {
- this._email = e("email").value;
- this.onStartOver();
- this.checkStartDone();
- },
- onInputRealname : function()
- {
- this._realname = e("realname").value;
- this.checkStartDone();
- },
-
- onInputPassword : function()
- {
- this._password = e("password").value;
- },
-
- /**
- * This does very little other than to check that a name was entered at all
- * Since this is such an insignificant test we should be using a very light
- * or even jovial warning.
- */
- onBlurRealname : function()
- {
- let realnameEl = e("realname");
- if (this._realname) {
- this.clearError("nameerror");
- _show("nametext");
- realnameEl.removeAttribute("error");
- // bug 638790: don't show realname error until user enter an email address
- } else if (this.validateEmailMinimally(this._email)) {
- _hide("nametext");
- this.setError("nameerror", "please_enter_name");
- realnameEl.setAttribute("error", "true");
- }
- },
-
- /**
- * This check is only done as an informative warning.
- * We don't want to block the person, if they've entered an email address
- * that doesn't conform to our regex.
- */
- onBlurEmail : function()
- {
- if (!this._email) {
- return;
- }
- var emailEl = e("email");
- if (this.validateEmail(this._email)) {
- this.clearError("emailerror");
- emailEl.removeAttribute("error");
- this.onBlurRealname();
- } else {
- this.setError("emailerror", "double_check_email");
- emailEl.setAttribute("error", "true");
- }
- },
-
- /**
- * If the user just tabbed through the password input without entering
- * anything, set the type back to text so we don't wind up showing the
- * emptytext as bullet characters.
- */
- onBlurPassword : function()
- {
- if (!this._password) {
- e("password").type = "text";
- }
- },
-
- /**
- * @see onBlurPassword()
- */
- onFocusPassword : function()
- {
- e("password").type = "password";
- },
-
- /**
- * Check whether the user entered the minimum of information
- * needed to leave the "start" mode (entering of name, email, pw)
- * and is allowed to proceed to detection step.
- */
- checkStartDone : function()
- {
- if (this.validateEmailMinimally(this._email) &&
- this._realname) {
- this._domain = this._email.split("@")[1].toLowerCase();
- _enable("next_button");
- } else {
- _disable("next_button");
- }
- },
-
- /**
- * When the [Continue] button is clicked, we move from the initial account
- * information stage to using that information to configure account details.
- */
- onNext : function()
- {
- this.findConfig(this._domain, this._email);
- },
-
-
- /////////////////////////////////////////////////////////////////
- // Detection step
-
- /**
- * Try to find an account configuration for this email address.
- * This is the function which runs the autoconfig.
- */
- findConfig : function(domain, email)
- {
- gEmailWizardLogger.info("findConfig()");
- if (this._abortable) {
- this.onStop();
- }
- this.switchToMode("find-config");
- this.startSpinner("looking_up_settings_disk");
- var self = this;
- this._abortable = fetchConfigFromDisk(domain,
- function(config) // success
- {
- self._abortable = null;
- self.foundConfig(config);
- self.stopSpinner("found_settings_disk");
- },
- function(e) // fetchConfigFromDisk failed
- {
- if (e instanceof CancelledException) {
- return;
- }
- gEmailWizardLogger.info("fetchConfigFromDisk failed: " + e);
- self.startSpinner("looking_up_settings_isp");
- self._abortable = fetchConfigFromISP(domain, email,
- function(config) // success
- {
- self._abortable = null;
- self.foundConfig(config);
- self.stopSpinner("found_settings_isp");
- },
- function(e) // fetchConfigFromISP failed
- {
- if (e instanceof CancelledException) {
- return;
- }
- gEmailWizardLogger.info("fetchConfigFromISP failed: " + e);
- logException(e);
- self.startSpinner("looking_up_settings_db");
- self._abortable = fetchConfigFromDB(domain,
- function(config) // success
- {
- self._abortable = null;
- self.foundConfig(config);
- self.stopSpinner("found_settings_db");
- },
- function(e) // fetchConfigFromDB failed
- {
- if (e instanceof CancelledException) {
- return;
- }
- logException(e);
- gEmailWizardLogger.info("fetchConfigFromDB failed: " + e);
- self.startSpinner("looking_up_settings_db");
- self._abortable = fetchConfigForMX(domain,
- function(config) // success
- {
- self._abortable = null;
- self.foundConfig(config);
- self.stopSpinner("found_settings_db");
- },
- function(e) // fetchConfigForMX failed
- {
- if (e instanceof CancelledException) {
- return;
- }
- logException(e);
- gEmailWizardLogger.info("fetchConfigForMX failed: " + e);
- var initialConfig = new AccountConfig();
- self._prefillConfig(initialConfig);
- self._guessConfig(domain, initialConfig);
- });
- });
- });
- });
- },
-
- /**
- * Just a continuation of findConfig()
- */
- _guessConfig : function(domain, initialConfig)
- {
- this.startSpinner("looking_up_settings_guess")
- var self = this;
- self._abortable = guessConfig(domain,
- function(type, hostname, port, ssl, done, config) // progress
- {
- var msg = hostname + ":" + port + " ssl=" + ssl + " " +
- type + ": progress callback";
- gEmailWizardLogger.info(msg);
- },
- function(config) // success
- {
- self._abortable = null;
- self.foundConfig(config);
- self.stopSpinner(Services.io.offline ?
- "guessed_settings_offline" : "found_settings_guess");
- window.sizeToContent();
- },
- function(e, config) // guessconfig failed
- {
- if (e instanceof CancelledException) {
- return;
- }
- self._abortable = null;
- gEmailWizardLogger.info("guessConfig failed: " + e);
- self.showErrorStatus("failed_to_find_settings");
- self.editConfigDetails();
- },
- initialConfig, "both");
- },
-
- /**
- * When findConfig() was successful, it calls this.
- * This displays the config to the user.
- */
- foundConfig : function(config)
- {
- gEmailWizardLogger.info("foundConfig()");
- assert(config instanceof AccountConfig,
- "BUG: Arg 'config' needs to be an AccountConfig object");
-
- this._haveValidConfigForDomain = this._email.split("@")[1];
-
- if (!this._realname || !this._email) {
- return;
- }
- this._foundConfig2(config);
- },
-
- // Continuation of foundConfig2() after custom fields.
- _foundConfig2 : function(config)
- {
- this.displayConfigResult(config);
- },
-
- /**
- * [Stop] button click handler.
- * This allows the user to abort any longer operation, esp. network activity.
- * We currently have 3 such cases here:
- * 1. findConfig(), i.e. fetch config from DB, guessConfig etc.
- * 2. onHalfManualTest(), i.e. the [Retest] button in manual config.
- * 3. verifyConfig() - We can't stop this yet, so irrelevant here currently.
- * Given that these need slightly different actions, this function will be set
- * to a function (i.e. overwritten) by whoever enables the stop button.
- *
- * We also call this from the code when the user started a different action
- * without explicitly clicking [Stop] for the old one first.
- */
- onStop : function()
- {
- throw new NotReached("onStop should be overridden by now");
- },
- _onStopCommon : function()
- {
- if (!this._abortable) {
- throw new NotReached("onStop called although there's nothing to stop");
- }
- gEmailWizardLogger.info("onStop cancelled _abortable");
- this._abortable.cancel(new UserCancelledException());
- this._abortable = null;
- this.stopSpinner();
- },
- onStopFindConfig : function()
- {
- this._onStopCommon();
- this.switchToMode("start");
- this.checkStartDone();
- },
- onStopHalfManualTesting : function()
- {
- this._onStopCommon();
- this.validateManualEditComplete();
- },
-
-
-
- ///////////////////////////////////////////////////////////////////
- // status area
-
- startSpinner : function(actionStrName)
- {
- e("status_area").setAttribute("status", "loading");
- gEmailWizardLogger.warn("spinner start " + actionStrName);
- this._showStatusTitle(actionStrName);
- },
-
- stopSpinner : function(actionStrName)
- {
- e("status_area").setAttribute("status", "result");
- _hide("stop_button");
- this._showStatusTitle(actionStrName);
- gEmailWizardLogger.warn("all spinner stop " + actionStrName);
- },
-
- showErrorStatus : function(actionStrName)
- {
- e("status_area").setAttribute("status", "error");
- gEmailWizardLogger.warn("status error " + actionStrName);
- this._showStatusTitle(actionStrName);
- },
-
- _showStatusTitle : function(msgName)
- {
- let msg = " "; // assure height. Do via min-height in CSS, for 2 lines?
- try {
- if (msgName) {
- msg = gStringsBundle.getFormattedString(msgName, [gBrandShortName]);
- }
- } catch(ex) {
- gEmailWizardLogger.error("missing string for " + msgName);
- msg = msgName + " (missing string in translation!)";
- }
-
- e("status_msg").textContent = msg;
- gEmailWizardLogger.info("status msg: " + msg);
- },
-
-
-
- /////////////////////////////////////////////////////////////////
- // Result area
-
- /**
- * Displays a (probed) config to the user,
- * in the result config details area.
- *
- * @param config {AccountConfig} The config to present to user
- */
- displayConfigResult : function(config)
- {
- assert(config instanceof AccountConfig);
- this._currentConfig = config;
- var configFilledIn = this.getConcreteConfig();
-
- var unknownString = gStringsBundle.getString("resultUnknown");
-
- function _makeHostDisplayString(server, stringName)
- {
- let type = gStringsBundle.getString(sanitize.translate(server.type,
- { imap : "resultIMAP", pop3 : "resultPOP3", smtp : "resultSMTP" }),
- unknownString);
- let host = server.hostname +
- (isStandardPort(server.port) ? "" : ":" + server.port);
- let ssl = gStringsBundle.getString(sanitize.translate(server.socketType,
- { 1 : "resultNoEncryption", 2 : "resultSSL", 3 : "resultSTARTTLS" }),
- unknownString);
- let certStatus = gStringsBundle.getString(server.badCert ?
- "resultSSLCertWeak" : "resultSSLCertOK");
- // TODO: we should really also display authentication method here.
- return gStringsBundle.getFormattedString(stringName,
- [ type, host, ssl, certStatus ]);
- };
-
- var incomingResult = unknownString;
- if (configFilledIn.incoming.hostname) {
- incomingResult = _makeHostDisplayString(configFilledIn.incoming,
- "resultIncoming");
- }
-
- var outgoingResult = unknownString;
- if (!config.outgoing.existingServerKey) {
- if (configFilledIn.outgoing.hostname) {
- outgoingResult = _makeHostDisplayString(configFilledIn.outgoing,
- "resultOutgoing");
- }
- } else {
- outgoingResult = gStringsBundle.getString("resultOutgoingExisting");
- }
-
- var usernameResult;
- if (configFilledIn.incoming.username == configFilledIn.outgoing.username) {
- usernameResult = gStringsBundle.getFormattedString("resultUsernameBoth",
- [ configFilledIn.incoming.username || unknownString ]);
- } else {
- usernameResult = gStringsBundle.getFormattedString(
- "resultUsernameDifferent",
- [ configFilledIn.incoming.username || unknownString,
- configFilledIn.outgoing.username || unknownString ]);
- }
-
- setText("result-incoming", incomingResult);
- setText("result-outgoing", outgoingResult);
- setText("result-username", usernameResult);
-
- gEmailWizardLogger.info(debugObject(config, "config"));
- // IMAP / POP dropdown
- var lookForAltType =
- config.incoming.type == "imap" ? "pop3" : "imap";
- var alternative = null;
- for (let i = 0; i < config.incomingAlternatives.length; i++) {
- let alt = config.incomingAlternatives[i];
- if (alt.type == lookForAltType) {
- alternative = alt;
- break;
- }
- }
- if (alternative) {
- _show("result_imappop");
- e("result_select_" + alternative.type).configIncoming = alternative;
- e("result_select_" + config.incoming.type).configIncoming =
- config.incoming;
- e("result_imappop").value =
- config.incoming.type == "imap" ? 1 : 2;
- } else {
- _hide("result_imappop");
- }
-
- this.switchToMode("result");
- },
-
- /**
- * Handle the user switching between IMAP and POP3 settings using the
- * radio buttons.
- *
- * Note: This function must only be called by user action, not by setting
- * the value or selectedItem or selectedIndex of the radiogroup!
- * This is why we use the oncommand attribute of the radio elements
- * instead of the onselect attribute of the radiogroup.
- */
- onResultIMAPOrPOP3 : function()
- {
- var config = this._currentConfig;
- var radiogroup = e("result_imappop");
- // add current server as best alternative to start of array
- config.incomingAlternatives.unshift(config.incoming);
- // use selected server (stored as special property on the <radio> node)
- config.incoming = radiogroup.selectedItem.configIncoming;
- // remove newly selected server from list of alternatives
- config.incomingAlternatives = config.incomingAlternatives.filter(
- function(e) { return e != config.incoming; });
- this.displayConfigResult(config);
- },
-
-
-
- /////////////////////////////////////////////////////////////////
- // Manual Edit area
-
- /**
- * Gets the values from the user in the manual edit area.
- *
- * Realname and password are not part of that area and still
- * placeholders, but hostname and username are concrete and
- * no placeholders anymore.
- */
- getUserConfig : function()
- {
- var config = this.getConcreteConfig();
- if (!config) {
- config = new AccountConfig();
- }
- config.source = AccountConfig.kSourceUser;
-
- // Incoming server
- try {
- var inHostnameField = e("incoming_hostname");
- config.incoming.hostname = sanitize.hostname(inHostnameField.value);
- inHostnameField.value = config.incoming.hostname;
- } catch (e) { gEmailWizardLogger.warn(e); }
- try {
- config.incoming.port = sanitize.integerRange(e("incoming_port").value,
- kMinPort, kMaxPort);
- } catch (e) {
- config.incoming.port = undefined; // incl. default "Auto"
- }
- config.incoming.type = sanitize.translate(e("incoming_protocol").value,
- { 1: "imap", 2 : "pop3", 0 : null });
- config.incoming.socketType = sanitize.integer(e("incoming_ssl").value);
- config.incoming.auth = sanitize.integer(e("incoming_authMethod").value);
- config.incoming.username = e("incoming_username").value;
-
- // Outgoing server
-
- // Did the user select one of the already configured SMTP servers from the
- // drop-down list? If so, use it.
- var outHostnameCombo = e("outgoing_hostname");
- var outMenuitem = outHostnameCombo.selectedItem;
- if (outMenuitem && outMenuitem.serverKey) {
- config.outgoing.existingServerKey = outMenuitem.serverKey;
- config.outgoing.existingServerLabel = outMenuitem.label;
- config.outgoing.addThisServer = false;
- config.outgoing.useGlobalPreferredServer = false;
- } else {
- config.outgoing.existingServerKey = null;
- config.outgoing.addThisServer = true;
- config.outgoing.useGlobalPreferredServer = false;
-
- try {
- config.outgoing.hostname = sanitize.hostname(
- outHostnameCombo.inputField.value);
- outHostnameCombo.inputField.value = config.outgoing.hostname;
- } catch (e) { gEmailWizardLogger.warn(e); }
- try {
- config.outgoing.port = sanitize.integerRange(e("outgoing_port").value,
- kMinPort, kMaxPort);
- } catch (e) {
- config.outgoing.port = undefined; // incl. default "Auto"
- }
- config.outgoing.socketType = sanitize.integer(e("outgoing_ssl").value);
- config.outgoing.auth = sanitize.integer(e("outgoing_authMethod").value);
- }
- config.outgoing.username = e("outgoing_username").value;
-
- return config;
- },
-
- /**
- * [Manual Config] button click handler. This turns the config details area
- * into an editable form and makes the (Go) button appear. The edit button
- * should only be available after the config probing is completely finished,
- * replacing what was the (Stop) button.
- */
- onManualEdit : function()
- {
- if (this._abortable) {
- this.onStop();
- }
- this.editConfigDetails();
- },
-
- /**
- * Setting the config details form so it can be edited. We also disable
- * (and hide) the create button during this time because we don't know what
- * might have changed. The function called from the button that restarts
- * the config check should be enabling the config button as needed.
- */
- editConfigDetails : function()
- {
- gEmailWizardLogger.info("manual edit");
-
- if (!this._currentConfig) {
- this._currentConfig = new AccountConfig();
- this._currentConfig.incoming.type = "imap";
- this._currentConfig.incoming.username = "%EMAILLOCALPART%";
- this._currentConfig.outgoing.username = "%EMAILLOCALPART%";
- this._currentConfig.incoming.hostname = ".%EMAILDOMAIN%";
- this._currentConfig.outgoing.hostname = ".%EMAILDOMAIN%";
- }
- // Although we go manual, and we need to display the concrete username,
- // however the realname and password is not part of manual config and
- // must stay a placeholder in _currentConfig. @see getUserConfig()
-
- this._fillManualEditFields(this.getConcreteConfig());
-
- // _fillManualEditFields() indirectly calls validateManualEditComplete(),
- // but it's important to not forget it in case the code is rewritten,
- // so calling it explicitly again. Doesn't do harm, speed is irrelevant.
- this.validateManualEditComplete();
- },
-
- /**
- * Fills the manual edit textfields with the provided config.
- * @param config {AccountConfig} The config to present to user
- */
- _fillManualEditFields : function(config)
- {
- assert(config instanceof AccountConfig);
-
- // incoming server
- e("incoming_protocol").value = sanitize.translate(config.incoming.type,
- { "imap" : 1, "pop3" : 2 }, 1);
- e("incoming_hostname").value = config.incoming.hostname;
- e("incoming_ssl").value = sanitize.enum(config.incoming.socketType,
- [ 0, 1, 2, 3 ], 0);
- e("incoming_authMethod").value = sanitize.enum(config.incoming.auth,
-#ifdef MOZ_MAILNEWS_OAUTH2
- [ 0, 3, 4, 5, 6, 10 ], 0);
-#else
- [ 0, 3, 4, 5, 6 ], 0);
-#endif
- e("incoming_username").value = config.incoming.username;
- if (config.incoming.port) {
- e("incoming_port").value = config.incoming.port;
- } else {
- this.adjustIncomingPortToSSLAndProtocol(config);
- }
- this.fillPortDropdown(config.incoming.type);
-
-#ifdef MOZ_MAILNEWS_OAUTH2
- // If the hostname supports OAuth2 and imap is enabled, enable OAuth2.
- let iDetails = OAuth2Providers.getHostnameDetails(config.incoming.hostname);
- gEmailWizardLogger.info("OAuth2 details for incoming hostname " +
- config.incoming.hostname + " is " + iDetails);
- e("in-authMethod-oauth2").hidden = !(iDetails && e("incoming_protocol").value == 1);
- if (!e("in-authMethod-oauth2").hidden) {
- config.oauthSettings = {};
- [config.oauthSettings.issuer, config.oauthSettings.scope] = iDetails;
- // oauthsettings are not stored nor changable in the user interface, so just
- // store them in the base configuration.
- this._currentConfig.oauthSettings = config.oauthSettings;
- }
-#endif
-
- // outgoing server
- e("outgoing_hostname").value = config.outgoing.hostname;
- e("outgoing_username").value = config.outgoing.username;
- // While sameInOutUsernames is true we synchronize values of incoming
- // and outgoing username.
- this.sameInOutUsernames = true;
- e("outgoing_ssl").value = sanitize.enum(config.outgoing.socketType,
- [ 0, 1, 2, 3 ], 0);
- e("outgoing_authMethod").value = sanitize.enum(config.outgoing.auth,
- [ 0, 1, 3, 4, 5, 6, 10 ], 0);
- if (config.outgoing.port) {
- e("outgoing_port").value = config.outgoing.port;
- } else {
- this.adjustOutgoingPortToSSLAndProtocol(config);
- }
-
-#ifdef MOZ_MAILNEWS_OAUTH2
- // If the hostname supports OAuth2 and imap is enabled, enable OAuth2.
- let oDetails = OAuth2Providers.getHostnameDetails(config.outgoing.hostname);
- gEmailWizardLogger.info("OAuth2 details for outgoing hostname " +
- config.outgoing.hostname + " is " + oDetails);
- e("out-authMethod-oauth2").hidden = !oDetails;
- if (!e("out-authMethod-oauth2").hidden) {
- config.oauthSettings = {};
- [config.oauthSettings.issuer, config.oauthSettings.scope] = oDetails;
- // oauthsettings are not stored nor changable in the user interface, so just
- // store them in the base configuration.
- this._currentConfig.oauthSettings = config.oauthSettings;
- }
-#endif
-
- // populate fields even if existingServerKey, in case user changes back
- if (config.outgoing.existingServerKey) {
- let menulist = e("outgoing_hostname");
- // We can't use menulist.value = config.outgoing.existingServerKey
- // because would overwrite the text field, so have to do it manually:
- let menuitems = menulist.menupopup.childNodes;
- for (let menuitem of menuitems) {
- if (menuitem.serverKey == config.outgoing.existingServerKey) {
- menulist.selectedItem = menuitem;
- break;
- }
- }
- }
- this.onChangedOutgoingDropdown(); // show/hide outgoing port, SSL, ...
- },
-
- /**
- * Automatically fill port field in manual edit,
- * unless user entered a non-standard port.
- * @param config {AccountConfig}
- */
- adjustIncomingPortToSSLAndProtocol : function(config)
- {
- var autoPort = gStringsBundle.getString("port_auto");
- var incoming = config.incoming;
- // we could use getHostEntry() here, but that API is bad, so don't bother
- var newInPort = undefined;
- if (!incoming.port || isStandardPort(incoming.port)) {
- if (incoming.type == "imap") {
- if (incoming.socketType == 1 || incoming.socketType == 3) {
- newInPort = 143;
- } else if (incoming.socketType == 2) { // Normal SSL
- newInPort = 993;
- } else { // auto
- newInPort = autoPort;
- }
- } else if (incoming.type == "pop3") {
- if (incoming.socketType == 1 || incoming.socketType == 3) {
- newInPort = 110;
- } else if (incoming.socketType == 2) { // Normal SSLs
- newInPort = 995;
- } else { // auto
- newInPort = autoPort;
- }
- }
- }
- if (newInPort != undefined) {
- e("incoming_port").value = newInPort;
- e("incoming_authMethod").value = 0; // auto
- }
- },
-
- /**
- * @see adjustIncomingPortToSSLAndProtocol()
- */
- adjustOutgoingPortToSSLAndProtocol : function(config)
- {
- var autoPort = gStringsBundle.getString("port_auto");
- var outgoing = config.outgoing;
- var newOutPort = undefined;
- if (!outgoing.port || isStandardPort(outgoing.port)) {
- if (outgoing.socketType == 1 || outgoing.socketType == 3) {
- // standard port is 587 *or* 25, so set to auto
- // unless user or config already entered one of these two ports.
- if (outgoing.port != 25 && outgoing.port != 587) {
- newOutPort = autoPort;
- }
- } else if (outgoing.socketType == 2) { // Normal SSL
- newOutPort = 465;
- } else { // auto
- newOutPort = autoPort;
- }
- }
- if (newOutPort != undefined) {
- e("outgoing_port").value = newOutPort;
- e("outgoing_authMethod").value = 0; // auto
- }
- },
-
- /**
- * If the user changed the port manually, adjust the SSL value,
- * (only) if the new port is impossible with the old SSL value.
- * @param config {AccountConfig}
- */
- adjustIncomingSSLToPort : function(config)
- {
- var incoming = config.incoming;
- var newInSocketType = undefined;
- if (!incoming.port || // auto
- !isStandardPort(incoming.port)) {
- return;
- }
- if (incoming.type == "imap") {
- // normal SSL impossible
- if (incoming.port == 143 && incoming.socketType == 2) {
- newInSocketType = 0; // auto
- // must be normal SSL
- } else if (incoming.port == 993 && incoming.socketType != 2) {
- newInSocketType = 2;
- }
- } else if (incoming.type == "pop3") {
- // normal SSL impossible
- if (incoming.port == 110 && incoming.socketType == 2) {
- newInSocketType = 0; // auto
- // must be normal SSL
- } else if (incoming.port == 995 && incoming.socketType != 2) {
- newInSocketType = 2;
- }
- }
- if (newInSocketType != undefined) {
- e("incoming_ssl").value = newInSocketType;
- e("incoming_authMethod").value = 0; // auto
- }
- },
-
- /**
- * @see adjustIncomingSSLToPort()
- */
- adjustOutgoingSSLToPort : function(config)
- {
- var outgoing = config.outgoing;
- var newOutSocketType = undefined;
- if (!outgoing.port || // auto
- !isStandardPort(outgoing.port)) {
- return;
- }
- // normal SSL impossible
- if ((outgoing.port == 587 || outgoing.port == 25) &&
- outgoing.socketType == 2) {
- newOutSocketType = 0; // auto
- // must be normal SSL
- } else if (outgoing.port == 465 && outgoing.socketType != 2) {
- newOutSocketType = 2;
- }
- if (newOutSocketType != undefined) {
- e("outgoing_ssl").value = newOutSocketType;
- e("outgoing_authMethod").value = 0; // auto
- }
- },
-
- /**
- * Sets the prefilled values of the port fields.
- * Filled statically with the standard ports for the given protocol,
- * plus "Auto".
- */
- fillPortDropdown : function(protocolType)
- {
- var menu = e(protocolType == "smtp" ? "outgoing_port" : "incoming_port");
-
- // menulist.removeAllItems() is nice, but nicely clears the user value, too
- var popup = menu.menupopup;
- while (popup.hasChildNodes())
- popup.lastChild.remove();
-
- // add standard ports
- var autoPort = gStringsBundle.getString("port_auto");
- menu.appendItem(autoPort, autoPort, ""); // label,value,descr
- for (let port of getStandardPorts(protocolType)) {
- menu.appendItem(port, port, ""); // label,value,descr
- }
- },
-
- onChangedProtocolIncoming : function()
- {
- var config = this.getUserConfig();
- this.adjustIncomingPortToSSLAndProtocol(config);
- this.fillPortDropdown(config.incoming.type);
- this.onChangedManualEdit();
- },
- onChangedPortIncoming : function()
- {
- gEmailWizardLogger.info("incoming port changed");
- this.adjustIncomingSSLToPort(this.getUserConfig());
- this.onChangedManualEdit();
- },
- onChangedPortOutgoing : function()
- {
- gEmailWizardLogger.info("outgoing port changed");
- this.adjustOutgoingSSLToPort(this.getUserConfig());
- this.onChangedManualEdit();
- },
- onChangedSSLIncoming : function()
- {
- this.adjustIncomingPortToSSLAndProtocol(this.getUserConfig());
- this.onChangedManualEdit();
- },
- onChangedSSLOutgoing : function()
- {
- this.adjustOutgoingPortToSSLAndProtocol(this.getUserConfig());
- this.onChangedManualEdit();
- },
- onChangedInAuth : function()
- {
- this.onChangedManualEdit();
- },
- onChangedOutAuth : function(aSelectedAuth)
- {
- if (aSelectedAuth) {
- e("outgoing_label").hidden = e("outgoing_username").hidden =
- (aSelectedAuth.id == "out-authMethod-no");
- }
- this.onChangedManualEdit();
- },
- onInputInUsername : function()
- {
- if (this.sameInOutUsernames)
- e("outgoing_username").value = e("incoming_username").value;
- this.onChangedManualEdit();
- },
- onInputOutUsername : function()
- {
- this.sameInOutUsernames = false;
- this.onChangedManualEdit();
- },
- onInputHostname : function()
- {
- this.onChangedManualEdit();
- },
-
- /**
- * Sets the label of the first entry of the dropdown which represents
- * the new outgoing server.
- */
- onOpenOutgoingDropdown : function()
- {
- var menulist = e("outgoing_hostname");
- // If the menulist is not editable, there is nothing to update
- // and menulist.inputField does not even exist.
- if (!menulist.editable)
- return;
-
- var menuitem = menulist.getItemAtIndex(0);
- assert(!menuitem.serverKey, "I wanted the special item for the new host");
- menuitem.label = menulist.inputField.value;
- },
-
- /**
- * User selected an existing SMTP server (or deselected it).
- * This changes only the UI. The values are read in getUserConfig().
- */
- onChangedOutgoingDropdown : function()
- {
- var menulist = e("outgoing_hostname");
- var menuitem = menulist.selectedItem;
- if (menuitem && menuitem.serverKey) {
- // an existing server has been selected from the dropdown
- menulist.editable = false;
- _hide("outgoing_port");
- _hide("outgoing_ssl");
- _hide("outgoing_authMethod");
- } else {
- // new server, with hostname, port etc.
- menulist.editable = true;
- _show("outgoing_port");
- _show("outgoing_ssl");
- _show("outgoing_authMethod");
- }
-
- this.onChangedManualEdit();
- },
-
- onChangedManualEdit : function()
- {
- if (this._abortable) {
- this.onStop();
- }
- this.validateManualEditComplete();
- },
-
- /**
- * This enables the buttons which allow the user to proceed
- * once he has entered enough information.
- *
- * We can easily and fairly surely autodetect everything apart from the
- * hostname (and username). So, once the user has entered
- * proper hostnames, change to "manual-edit-have-hostname" mode
- * which allows to press [Re-test], which starts the detection
- * of the other values.
- * Once the user has entered (or we detected) all values, he may
- * do [Create Account] (tests login and if successful creates the account)
- * or [Advanced Setup] (goes to Account Manager). Esp. in the latter case,
- * we will not second-guess his setup and just to as told, so here we make
- * sure that he at least entered all values.
- */
- validateManualEditComplete : function()
- {
- // getUserConfig() is expensive, but still OK, not a problem
- var manualConfig = this.getUserConfig();
- this._currentConfig = manualConfig;
- if (manualConfig.isComplete()) {
- this.switchToMode("manual-edit-complete");
- } else if (!!manualConfig.incoming.hostname &&
- !!manualConfig.outgoing.hostname) {
- this.switchToMode("manual-edit-have-hostname");
- } else {
- this.switchToMode("manual-edit");
- }
- },
-
- /**
- * [Switch to provisioner] button click handler. Always active, allows
- * one to switch to the account provisioner screen.
- */
- onSwitchToProvisioner : function ()
- {
- // We have to close this window first, otherwise msgNewMailAccount
- // in accountUtils.js will think that this window still
- // exists when it's called from the account provisioner window.
- // This is because the account provisioner window is modal,
- // and therefore blocks. Therefore, we override the _okCallback
- // with a function that spawns the account provisioner, and then
- // close the window.
- this._okCallback = function() {
- NewMailAccountProvisioner(window.arguments[0].msgWindow, window.arguments[0].extraData);
- }
- window.close();
- },
-
- /**
- * [Advanced Setup...] button click handler
- * Only active in manual edit mode, and goes straight into
- * Account Settings (pref UI) dialog. Requires a backend account,
- * which requires proper hostname, port and protocol.
- */
- onAdvancedSetup : function()
- {
- assert(this._currentConfig instanceof AccountConfig);
- let configFilledIn = this.getConcreteConfig();
-
- if (checkIncomingServerAlreadyExists(configFilledIn)) {
- alertPrompt(gStringsBundle.getString("error_creating_account"),
- gStringsBundle.getString("incoming_server_exists"));
- return;
- }
-
- gEmailWizardLogger.info("creating account in backend");
- let newAccount = createAccountInBackend(configFilledIn);
-
- let existingAccountManager = Services.wm
- .getMostRecentWindow("mailnews:accountmanager");
- if (existingAccountManager) {
- existingAccountManager.focus();
- } else {
- window.openDialog("chrome://messenger/content/AccountManager.xul",
- "AccountManager", "chrome,centerscreen,modal,titlebar",
- { server: newAccount.incomingServer,
- selectPage: "am-server.xul" });
- }
- window.close();
- },
-
- /**
- * [Re-test] button click handler.
- * Restarts the config guessing process after a person editing the server
- * fields.
- * It's called "half-manual", because we take the user-entered values
- * as given and will not second-guess them, to respect the user wishes.
- * (Yes, Sir! Will do as told!)
- * The values that the user left empty or on "Auto" will be guessed/probed
- * here. We will also check that the user-provided values work.
- */
- onHalfManualTest : function()
- {
- var newConfig = this.getUserConfig();
- gEmailWizardLogger.info(debugObject(newConfig, "manualConfigToTest"));
- this.startSpinner("looking_up_settings_halfmanual");
- this.switchToMode("manual-edit-testing");
- // if (this._userPickedOutgoingServer) TODO
- var self = this;
- this._abortable = guessConfig(this._domain,
- function(type, hostname, port, ssl, done, config) // progress
- {
- gEmailWizardLogger.info("progress callback host " + hostname +
- " port " + port + " type " + type);
- },
- function(config) // success
- {
- self._abortable = null;
- self._fillManualEditFields(config);
- self.switchToMode("manual-edit-complete");
- self.stopSpinner("found_settings_halfmanual");
- },
- function(e, config) // guessconfig failed
- {
- if (e instanceof CancelledException) {
- return;
- }
- self._abortable = null;
- gEmailWizardLogger.info("guessConfig failed: " + e);
- self.showErrorStatus("failed_to_find_settings");
- self.switchToMode("manual-edit-have-hostname");
- },
- newConfig,
- newConfig.outgoing.existingServerKey ? "incoming" : "both");
- },
-
-
-
- /////////////////////////////////////////////////////////////////
- // UI helper functions
-
- _prefillConfig : function(initialConfig)
- {
- var emailsplit = this._email.split("@");
- assert(emailsplit.length > 1);
- var emaillocal = sanitize.nonemptystring(emailsplit[0]);
- initialConfig.incoming.username = emaillocal;
- initialConfig.outgoing.username = emaillocal;
- return initialConfig;
- },
-
- clearError : function(which)
- {
- _hide(which);
- _hide(which + "icon");
- e(which).textContent = "";
- },
-
- setError : function(which, msg_name)
- {
- try {
- _show(which);
- _show(which + "icon");
- e(which).textContent = gStringsBundle.getString(msg_name);
- window.sizeToContent();
- } catch (ex) { alertPrompt("missing error string", msg_name); }
- },
-
-
-
- /////////////////////////////////////////////////////////////////
- // Finish & dialog close functions
-
- onKeyDown : function(event)
- {
- let key = event.keyCode;
- if (key == 27) { // Escape key
- this.onCancel();
- return true;
- }
- if (key == 13) { // OK key
- let buttons = [
- { id: "next_button", action: makeCallback(this, this.onNext) },
- { id: "create_button", action: makeCallback(this, this.onCreate) },
- { id: "half-manual-test_button",
- action: makeCallback(this, this.onHalfManualTest) },
- ];
- for (let button of buttons) {
- button.e = e(button.id);
- if (button.e.hidden || button.e.disabled) {
- continue;
- }
- button.action();
- return true;
- }
- }
- return false;
- },
-
- onCancel : function()
- {
- window.close();
- // The window onclose handler will call onWizardShutdown for us.
- },
-
- onWizardShutdown : function()
- {
- if (this._abortable) {
- this._abortable.cancel(new UserCancelledException());
- }
-
- if (this._okCallback) {
- this._okCallback();
- }
- gEmailWizardLogger.info("Shutting down email config dialog");
- },
-
-
- onCreate : function()
- {
- try {
- gEmailWizardLogger.info("Create button clicked");
-
- var configFilledIn = this.getConcreteConfig();
- var self = this;
- // If the dialog is not needed, it will go straight to OK callback
- gSecurityWarningDialog.open(this._currentConfig, configFilledIn, true,
- function() // on OK
- {
- self.validateAndFinish(configFilledIn);
- },
- function() {}); // on cancel, do nothing
- } catch (ex) {
- gEmailWizardLogger.error("Error creating account. ex=" + ex +
- ", stack=" + ex.stack);
- alertPrompt(gStringsBundle.getString("error_creating_account"), ex);
- }
- },
-
- // called by onCreate()
- validateAndFinish : function()
- {
- var configFilledIn = this.getConcreteConfig();
-
- if (checkIncomingServerAlreadyExists(configFilledIn)) {
- alertPrompt(gStringsBundle.getString("error_creating_account"),
- gStringsBundle.getString("incoming_server_exists"));
- return;
- }
-
- if (configFilledIn.outgoing.addThisServer) {
- let existingServer = checkOutgoingServerAlreadyExists(configFilledIn);
- if (existingServer) {
- configFilledIn.outgoing.addThisServer = false;
- configFilledIn.outgoing.existingServerKey = existingServer.key;
- }
- }
-
- // TODO use a UI mode (switchToMode()) for verfication, too.
- // But we need to go back to the previous mode, because we might be in
- // "result" or "manual-edit-complete" mode.
- _disable("create_button");
- _disable("half-manual-test_button");
- _disable("advanced-setup_button");
- // no stop button: backend has no ability to stop :-(
- var self = this;
- this.startSpinner("checking_password");
- // logic function defined in verifyConfig.js
- verifyConfig(
- configFilledIn,
- // guess login config?
- configFilledIn.source != AccountConfig.kSourceXML,
- // TODO Instead, the following line would be correct, but I cannot use it,
- // because some other code doesn't adhere to the expectations/specs.
- // Find out what it was and fix it.
- //concreteConfig.source == AccountConfig.kSourceGuess,
- this._parentMsgWindow,
- function(successfulConfig) // success
- {
- self.stopSpinner(successfulConfig.incoming.password ?
- "password_ok" : null);
-
- // the auth might have changed, so we
- // should back-port it to the current config.
- self._currentConfig.incoming.auth = successfulConfig.incoming.auth;
- self._currentConfig.outgoing.auth = successfulConfig.outgoing.auth;
- self._currentConfig.incoming.username = successfulConfig.incoming.username;
- self._currentConfig.outgoing.username = successfulConfig.outgoing.username;
-
-#ifdef MOZ_MAILNEWS_OAUTH2
- // We loaded dynamic client registration, fill this data back in to the
- // config set.
- if (successfulConfig.oauthSettings)
- self._currentConfig.oauthSettings = successfulConfig.oauthSettings;
-#endif
-
- self.finish();
- },
- function(e) // failed
- {
- self.showErrorStatus("config_unverifiable");
- // TODO bug 555448: wrong error msg, there may be a 1000 other
- // reasons why this failed, and this is misleading users.
- self.setError("passworderror", "user_pass_invalid");
- // TODO use switchToMode(), see above
- // give user something to proceed after fixing
- _enable("create_button");
- // hidden in non-manual mode, so it's fine to enable
- _enable("half-manual-test_button");
- _enable("advanced-setup_button");
- });
- },
-
- finish : function()
- {
- gEmailWizardLogger.info("creating account in backend");
- createAccountInBackend(this.getConcreteConfig());
- window.close();
- },
-};
-
-var gEmailConfigWizard = new EmailConfigWizard();
-
-function serverMatches(a, b)
-{
- return a.type == b.type &&
- a.hostname == b.hostname &&
- a.port == b.port &&
- a.socketType == b.socketType &&
- a.auth == b.auth;
-}
-
-var _gStandardPorts = {};
-_gStandardPorts["imap"] = [ 143, 993 ];
-_gStandardPorts["pop3"] = [ 110, 995 ];
-_gStandardPorts["smtp"] = [ 587, 25, 465 ]; // order matters
-var _gAllStandardPorts = _gStandardPorts["smtp"]
- .concat(_gStandardPorts["imap"]).concat(_gStandardPorts["pop3"]);
-
-function isStandardPort(port)
-{
- return _gAllStandardPorts.indexOf(port) != -1;
-}
-
-function getStandardPorts(protocolType)
-{
- return _gStandardPorts[protocolType];
-}
-
-
-/**
- * Warning dialog, warning user about lack of, or inappropriate, encryption.
- *
- * This is effectively a separate dialog, but implemented as part of
- * this dialog. It works by hiding the main dialog part and unhiding
- * the this part, and vice versa, and resizing the dialog.
- */
-function SecurityWarningDialog()
-{
- this._acknowledged = new Array();
-}
-SecurityWarningDialog.prototype =
-{
- /**
- * {Array of {(incoming or outgoing) server part of {AccountConfig}}
- * A list of the servers for which we already showed this dialog and the
- * user approved the configs. For those, we won't show the warning again.
- * (Make sure to store a copy in case the underlying object is changed.)
- */
- _acknowledged : null,
-
- _inSecurityBad: 0x0001,
- _inCertBad: 0x0010,
- _outSecurityBad: 0x0100,
- _outCertBad: 0x1000,
-
- /**
- * Checks whether we need to warn about this config.
- *
- * We (currently) warn if
- * - the mail travels unsecured (no SSL/STARTTLS)
- * - the SSL certificate is not proper
- * - (We don't warn about unencrypted passwords specifically,
- * because they'd be encrypted with SSL and without SSL, we'd
- * warn anyways.)
- *
- * We may not warn despite these conditions if we had shown the
- * warning for that server before and the user acknowledged it.
- * (Given that this dialog object is static/global and persistent,
- * we can store that approval state here in this object.)
- *
- * @param configSchema @see open()
- * @param configFilledIn @see open()
- * @returns {Boolean} true when the dialog should be shown
- * (call open()). if false, the dialog can and should be skipped.
- */
- needed : function(configSchema, configFilledIn)
- {
- assert(configSchema instanceof AccountConfig);
- assert(configFilledIn instanceof AccountConfig);
- assert(configSchema.isComplete());
- assert(configFilledIn.isComplete());
-
- var incomingBad = ((configFilledIn.incoming.socketType > 1) ? 0 : this._inSecurityBad) |
- ((configFilledIn.incoming.badCert) ? this._inCertBad : 0);
- var outgoingBad = 0;
- if (!configFilledIn.outgoing.existingServerKey) {
- outgoingBad = ((configFilledIn.outgoing.socketType > 1) ? 0 : this._outSecurityBad) |
- ((configFilledIn.outgoing.badCert) ? this._outCertBad : 0);
- }
-
- if (incomingBad > 0) {
- if (this._acknowledged.some(
- function(ackServer) {
- return serverMatches(ackServer, configFilledIn.incoming);
- }))
- incomingBad = 0;
- }
- if (outgoingBad > 0) {
- if (this._acknowledged.some(
- function(ackServer) {
- return serverMatches(ackServer, configFilledIn.outgoing);
- }))
- outgoingBad = 0;
- }
-
- return incomingBad | outgoingBad;
- },
-
- /**
- * Opens the dialog, fills it with values, and shows it to the user.
- *
- * The function is async: it returns immediately, and when the user clicks
- * OK or Cancel, the callbacks are called. There the callers proceed as
- * appropriate.
- *
- * @param configSchema The config, with placeholders not replaced yet.
- * This object may be modified to store the user's confirmations, but
- * currently that's not the case.
- * @param configFilledIn The concrete config with placeholders replaced.
- * @param onlyIfNeeded {Boolean} If there is nothing to warn about,
- * call okCallback() immediately (and sync).
- * @param okCallback {function(config {AccountConfig})}
- * Called when the user clicked OK and approved the config including
- * the warnings. |config| is without placeholders replaced.
- * @param cancalCallback {function()}
- * Called when the user decided to heed the warnings and not approve.
- */
- open : function(configSchema, configFilledIn, onlyIfNeeded,
- okCallback, cancelCallback)
- {
- assert(typeof(okCallback) == "function");
- assert(typeof(cancelCallback) == "function");
- // needed() also checks the parameters
- var needed = this.needed(configSchema, configFilledIn);
- if ((needed == 0) && onlyIfNeeded) {
- okCallback();
- return;
- }
-
- assert(needed > 0 , "security dialog opened needlessly");
- this._currentConfigFilledIn = configFilledIn;
- this._okCallback = okCallback;
- this._cancelCallback = cancelCallback;
- var incoming = configFilledIn.incoming;
- var outgoing = configFilledIn.outgoing;
-
- _hide("mastervbox");
- _show("warningbox");
- // reset dialog, in case we've shown it before
- e("acknowledge_warning").checked = false;
- _disable("iknow");
- e("incoming_technical").removeAttribute("expanded");
- e("incoming_details").setAttribute("collapsed", true);
- e("outgoing_technical").removeAttribute("expanded");
- e("outgoing_details").setAttribute("collapsed", true);
-
- if (needed & this._inSecurityBad) {
- setText("warning_incoming", gStringsBundle.getFormattedString(
- "cleartext_warning", [incoming.hostname]));
- setText("incoming_details", gStringsBundle.getString(
- "cleartext_details"));
- _show("incoming_box");
- } else if (needed & this._inCertBad) {
- setText("warning_incoming", gStringsBundle.getFormattedString(
- "selfsigned_warning", [incoming.hostname]));
- setText("incoming_details", gStringsBundle.getString(
- "selfsigned_details"));
- _show("incoming_box");
- } else {
- _hide("incoming_box");
- }
-
- if (needed & this._outSecurityBad) {
- setText("warning_outgoing", gStringsBundle.getFormattedString(
- "cleartext_warning", [outgoing.hostname]));
- setText("outgoing_details", gStringsBundle.getString(
- "cleartext_details"));
- _show("outgoing_box");
- } else if (needed & this._outCertBad) {
- setText("warning_outgoing", gStringsBundle.getFormattedString(
- "selfsigned_warning", [outgoing.hostname]));
- setText("outgoing_details", gStringsBundle.getString(
- "selfsigned_details"));
- _show("outgoing_box");
- } else {
- _hide("outgoing_box");
- }
- _show("acknowledge_warning");
- assert(!e("incoming_box").hidden || !e("outgoing_box").hidden,
- "warning dialog shown for unknown reason");
-
- window.sizeToContent();
- },
-
- toggleDetails : function (id)
- {
- let details = e(id + "_details");
- let tech = e(id + "_technical");
- if (details.getAttribute("collapsed")) {
- details.removeAttribute("collapsed");
- tech.setAttribute("expanded", true);
- } else {
- details.setAttribute("collapsed", true);
- tech.removeAttribute("expanded");
- }
- },
-
- /**
- * user checked checkbox that he understood it and wishes
- * to ignore the warning.
- */
- toggleAcknowledge : function()
- {
- if (e("acknowledge_warning").checked) {
- _enable("iknow");
- } else {
- _disable("iknow");
- }
- },
-
- /**
- * [Cancel] button pressed. Get me out of here!
- */
- onCancel : function()
- {
- _hide("warningbox");
- _show("mastervbox");
- window.sizeToContent();
-
- this._cancelCallback();
- },
-
- /**
- * [OK] button pressed.
- * Implies that the user toggled the acknowledge checkbox,
- * i.e. approved the config and ignored the warnings,
- * otherwise the button would have been disabled.
- */
- onOK : function()
- {
- assert(e("acknowledge_warning").checked);
-
- var overrideOK = this.showCertOverrideDialog(this._currentConfigFilledIn);
- if (!overrideOK) {
- this.onCancel();
- return;
- }
-
- // need filled in, in case hostname is placeholder
- var storeConfig = this._currentConfigFilledIn.copy();
- this._acknowledged.push(storeConfig.incoming);
- this._acknowledged.push(storeConfig.outgoing);
-
- _show("mastervbox");
- _hide("warningbox");
- window.sizeToContent();
-
- this._okCallback();
- },
-
- /**
- * Shows a(nother) dialog which allows the user to see and override
- * (manually accept) a bad certificate. It also optionally adds it
- * permanently to the "good certs" store of NSS in the profile.
- * Only shows the dialog, if there are bad certs. Otherwise, it's a no-op.
- *
- * The dialog is the standard PSM cert override dialog.
- *
- * @param config {AccountConfig} concrete
- * @returns true, if all certs are fine or the user accepted them.
- * false, if the user cancelled.
- *
- * static function
- * sync function: blocks until the dialog is closed.
- */
- showCertOverrideDialog : function(config)
- {
- if (config.incoming.socketType > 1 && // SSL or STARTTLS
- config.incoming.badCert) {
- var params = {
- exceptionAdded : false,
- prefetchCert : true,
- location : config.incoming.targetSite,
- };
- window.openDialog("chrome://pippki/content/exceptionDialog.xul",
- "","chrome,centerscreen,modal", params);
- if (params.exceptionAdded) { // set by dialog
- config.incoming.badCert = false;
- } else {
- return false;
- }
- }
- if (!config.outgoing.existingServerKey) {
- if (config.outgoing.socketType > 1 && // SSL or STARTTLS
- config.outgoing.badCert) {
- var params = {
- exceptionAdded : false,
- prefetchCert : true,
- location : config.outgoing.targetSite,
- };
- window.openDialog("chrome://pippki/content/exceptionDialog.xul",
- "","chrome,centerscreen,modal", params);
- if (params.exceptionAdded) { // set by dialog
- config.outgoing.badCert = false;
- } else {
- return false;
- }
- }
- }
- return true;
- },
-}
-var gSecurityWarningDialog = new SecurityWarningDialog();
diff --git a/mailnews/base/prefs/content/accountcreation/emailWizard.xul b/mailnews/base/prefs/content/accountcreation/emailWizard.xul
deleted file mode 100644
index 261545671..000000000
--- a/mailnews/base/prefs/content/accountcreation/emailWizard.xul
+++ /dev/null
@@ -1,497 +0,0 @@
-<?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"/>
-#ifdef MOZ_MAILNEWS_OAUTH2
- <menuitem id="in-authMethod-oauth2" value="10" hidden="true"/>
-#endif
- </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"/>
-#ifdef MOZ_MAILNEWS_OAUTH2
- <menuitem id="out-authMethod-oauth2" value="10" hidden="true"/>
-#endif
- </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>
diff --git a/mailnews/base/prefs/content/accountcreation/fetchConfig.js b/mailnews/base/prefs/content/accountcreation/fetchConfig.js
deleted file mode 100644
index 2fe604e69..000000000
--- a/mailnews/base/prefs/content/accountcreation/fetchConfig.js
+++ /dev/null
@@ -1,237 +0,0 @@
-/* -*- 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 conf1 = "autoconfig." + sanitize.hostname(domain) +
- "/mail/config-v1.1.xml";
- // .well-known/ <http://tools.ietf.org/html/draft-nottingham-site-meta-04>
- let conf2 = sanitize.hostname(domain) +
- "/.well-known/autoconfig/mail/config-v1.1.xml";
- // This list is sorted by decreasing priority
- var urls = ["https://" + conf1, "https://" + conf2];
- if (!Services.prefs.getBoolPref("mailnews.auto_config.fetchFromISP.sslOnly")) {
- urls.push("http://" + conf1, "http://" + conf2);
- }
- let sucAbortable = new SuccessiveAbortable();
- var urlArgs = { emailaddress: emailAddress };
- if (!Services.prefs.getBoolPref(
- "mailnews.auto_config.fetchFromISP.sendEmailAddress")) {
- delete urlArgs.emailaddress;
- }
- var time;
-
- let success = function(result) {
- successCallback(readFromXML(result));
- };
-
- let error = function(i, e) {
- ddump("fetchisp " + i + " <" + urls[i] + "> took " +
- (Date.now() - time) + "ms and failed with " + e);
-
- if (i == urls.length - 1 || // implies all fetches failed
- e instanceof CancelledException) {
- errorCallback(e);
- return;
- }
- let fetch = new FetchHTTP(urls[i + 1], urlArgs, false, success,
- function(e) { error(i + 1, e) });
- sucAbortable.current = fetch;
- time = Date.now();
- fetch.start();
- };
-
- let fetch = new FetchHTTP(urls[0], urlArgs, false, success,
- function(e) { error(0, e) });
- sucAbortable.current = fetch;
- time = Date.now();
- fetch.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;
-}
diff --git a/mailnews/base/prefs/content/accountcreation/fetchhttp.js b/mailnews/base/prefs/content/accountcreation/fetchhttp.js
deleted file mode 100644
index d2323f7b6..000000000
--- a/mailnews/base/prefs/content/accountcreation/fetchhttp.js
+++ /dev/null
@@ -1,264 +0,0 @@
-/* -*- 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;
- errorCode = this._request.status;
- if (errorCode == 0) {
- errorStr = getStringBundle(
- "chrome://messenger/locale/accountCreationUtil.properties")
- .GetStringFromName("cannot_contact_server.error");
- ddump(errorStr);
- } else {
- errorStr = this._request.statusText;
- }
- }
-
- // 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;
-
diff --git a/mailnews/base/prefs/content/accountcreation/guessConfig.js b/mailnews/base/prefs/content/accountcreation/guessConfig.js
deleted file mode 100644
index 6ba9f1dfb..000000000
--- a/mailnews/base/prefs/content/accountcreation/guessConfig.js
+++ /dev/null
@@ -1,1192 +0,0 @@
-/* -*- 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/. */
-
-Cu.import("resource:///modules/gloda/log4moz.js");
-Cu.import("resource://gre/modules/Services.jsm");
-
-// This is a bit ugly - we set outgoingDone to false
-// when emailWizard.js cancels the outgoing probe because the user picked
-// an outoing server. It does this by poking the probeAbortable object,
-// so we need outgoingDone to have global scope.
-var outgoingDone = false;
-
-/**
- * Try to guess the config, by:
- * - guessing hostnames (pop3.<domain>, pop.<domain>, imap.<domain>,
- * mail.<domain> etc.)
- * - probing known ports (for IMAP, POP3 etc., with SSL, STARTTLS etc.)
- * - opening a connection via the right protocol and checking the
- * protocol-specific CAPABILITIES like that the server returns.
- *
- * Final verification is not done here, but in verifyConfig().
- *
- * This function is async.
- * @param domain {String} the domain part of the email address
- * @param progressCallback {function(type, hostname, port, ssl, done)}
- * Called when we try a new hostname/port.
- * type {String-enum} @see AccountConfig type - "imap", "pop3", "smtp"
- * hostname {String}
- * port {Integer}
- * socketType {Integer-enum} @see AccountConfig.incoming.socketType
- * 1 = plain, 2 = SSL, 3 = STARTTLS
- * done {Boolean} false, if we start probing this host/port, true if we're
- * done and the host is good. (there is no notification when a host is
- * bad, we'll just tell about the next host tried)
- * @param successCallback {function(config {AccountConfig})}
- * Called when we could guess the config.
- * 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 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.
- * @param resultConfig {AccountConfig} (optional)
- * A config which may be partially filled in. If so, it will be used as base
- * for the guess.
- * @param which {String-enum} (optional) "incoming", "outgoing", or "both".
- * Default "both". Whether to guess only the incoming or outgoing server.
- * @result {Abortable} Allows you to cancel the guess
- */
-function guessConfig(domain, progressCallback, successCallback, errorCallback,
- resultConfig, which)
-{
- assert(typeof(progressCallback) == "function", "need progressCallback");
- assert(typeof(successCallback) == "function", "need successCallback");
- assert(typeof(errorCallback) == "function", "need errorCallback");
-
-#ifdef MOZ_MAILNEWS_OAUTH2
- // Servers that we know enough that they support OAuth2 do not need guessing.
- if (resultConfig.incoming.auth == Ci.nsMsgAuthMethod.OAuth2) {
- successCallback(resultConfig);
- return null;
- }
-#endif
-
- if (!resultConfig)
- resultConfig = new AccountConfig();
- resultConfig.source = AccountConfig.kSourceGuess;
-
- if (!Services.prefs.getBoolPref(
- "mailnews.auto_config.guess.enabled")) {
- errorCallback("Guessing config disabled per user preference");
- return;
- }
-
- var incomingHostDetector = null;
- var outgoingHostDetector = null;
- var incomingEx = null; // if incoming had error, store ex here
- var outgoingEx = null; // if incoming had error, store ex here
- var incomingDone = (which == "outgoing");
- var outgoingDone = (which == "incoming");
- // If we're offline, we're going to pick the most common settings.
- // (Not the "best" settings, but common).
- if (Services.io.offline)
- {
- resultConfig.source = AccountConfig.kSourceUser;
- resultConfig.incoming.hostname = "mail." + domain;
- resultConfig.incoming.username = resultConfig.identity.emailAddress;
- resultConfig.outgoing.username = resultConfig.identity.emailAddress;
- resultConfig.incoming.type = "imap";
- resultConfig.incoming.port = 143;
- resultConfig.incoming.socketType = 3; // starttls
- resultConfig.incoming.auth = Ci.nsMsgAuthMethod.passwordCleartext;
- resultConfig.outgoing.hostname = "smtp." + domain;
- resultConfig.outgoing.socketType = 1;
- resultConfig.outgoing.port = 587;
- resultConfig.outgoing.auth = Ci.nsMsgAuthMethod.passwordCleartext;
- resultConfig.incomingAlternatives.push({
- hostname: "mail." + domain,
- username: resultConfig.identity.emailAddress,
- type: "pop3",
- port: 110,
- socketType: 3,
- auth: Ci.nsMsgAuthMethod.passwordCleartext
- });
- successCallback(resultConfig);
- return null;
- }
- var progress = function(thisTry)
- {
- progressCallback(protocolToString(thisTry.protocol), thisTry.hostname,
- thisTry.port, sslConvertToSocketType(thisTry.ssl), false,
- resultConfig);
- };
-
- var updateConfig = function(config)
- {
- resultConfig = config;
- };
-
- var errorInCallback = function(e)
- {
- // The caller's errorCallback threw.
- // hopefully shouldn't happen for users.
- alertPrompt("Error in errorCallback for guessConfig()", e);
- };
-
- var checkDone = function()
- {
- if (incomingEx)
- {
- try {
- errorCallback(incomingEx, resultConfig);
- } catch (e) { errorInCallback(e); }
- return;
- }
- if (outgoingEx)
- {
- try {
- errorCallback(outgoingEx, resultConfig);
- } catch (e) { errorInCallback(e); }
- return;
- }
- if (incomingDone && outgoingDone)
- {
- try {
- successCallback(resultConfig);
- } catch (e) {
- try {
- errorCallback(e);
- } catch (e) { errorInCallback(e); }
- }
- return;
- }
- };
-
- var logger = Log4Moz.getConfiguredLogger("mail.wizard");
- var HostTryToAccountServer = function(thisTry, server)
- {
- server.type = protocolToString(thisTry.protocol);
- server.hostname = thisTry.hostname;
- server.port = thisTry.port;
- server.socketType = sslConvertToSocketType(thisTry.ssl);
- server.auth = chooseBestAuthMethod(thisTry.authMethods);
- server.authAlternatives = thisTry.authMethods;
- // TODO
- // cert is also bad when targetSite is set. (Same below for incoming.)
- // Fix SSLErrorHandler and security warning dialog in emailWizard.js.
- server.badCert = thisTry.selfSignedCert;
- server.targetSite = thisTry.targetSite;
- logger.info("CHOOSING " + server.type + " "+ server.hostname + ":" +
- server.port + ", auth method " + server.auth + " " +
- server.authAlternatives.join(",") + ", SSL " + server.socketType +
- (server.badCert ? " (bad cert!)" : ""));
- };
-
- var outgoingSuccess = function(thisTry, alternativeTries)
- {
- assert(thisTry.protocol == SMTP, "I only know SMTP for outgoing");
- // Ensure there are no previously saved outgoing errors, if we've got
- // success here.
- outgoingEx = null;
- HostTryToAccountServer(thisTry, resultConfig.outgoing);
-
- for (let alternativeTry of alternativeTries)
- {
- // resultConfig.createNewOutgoing(); misses username etc., so copy
- let altServer = deepCopy(resultConfig.outgoing);
- HostTryToAccountServer(alternativeTry, altServer);
- assert(resultConfig.outgoingAlternatives);
- resultConfig.outgoingAlternatives.push(altServer);
- }
-
- progressCallback(resultConfig.outgoing.type,
- resultConfig.outgoing.hostname, resultConfig.outgoing.port,
- resultConfig.outgoing.socketType, true, resultConfig);
- outgoingDone = true;
- checkDone();
- };
-
- var incomingSuccess = function(thisTry, alternativeTries)
- {
- // Ensure there are no previously saved incoming errors, if we've got
- // success here.
- incomingEx = null;
- HostTryToAccountServer(thisTry, resultConfig.incoming);
-
- for (let alternativeTry of alternativeTries)
- {
- // resultConfig.createNewIncoming(); misses username etc., so copy
- let altServer = deepCopy(resultConfig.incoming);
- HostTryToAccountServer(alternativeTry, altServer);
- assert(resultConfig.incomingAlternatives);
- resultConfig.incomingAlternatives.push(altServer);
- }
-
- progressCallback(resultConfig.incoming.type,
- resultConfig.incoming.hostname, resultConfig.incoming.port,
- resultConfig.incoming.socketType, true, resultConfig);
- incomingDone = true;
- checkDone();
- };
-
- var incomingError = function(ex)
- {
- incomingEx = ex;
- checkDone();
- incomingHostDetector.cancel(new CancelOthersException());
- outgoingHostDetector.cancel(new CancelOthersException());
- };
-
- var outgoingError = function(ex)
- {
- outgoingEx = ex;
- checkDone();
- incomingHostDetector.cancel(new CancelOthersException());
- outgoingHostDetector.cancel(new CancelOthersException());
- };
-
- incomingHostDetector = new IncomingHostDetector(progress, incomingSuccess,
- incomingError);
- outgoingHostDetector = new OutgoingHostDetector(progress, outgoingSuccess,
- outgoingError);
- if (which == "incoming" || which == "both")
- {
- incomingHostDetector.start(resultConfig.incoming.hostname ?
- resultConfig.incoming.hostname : domain,
- !!resultConfig.incoming.hostname, resultConfig.incoming.type,
- resultConfig.incoming.port, resultConfig.incoming.socketType);
- }
- if (which == "outgoing" || which == "both")
- {
- outgoingHostDetector.start(resultConfig.outgoing.hostname ?
- resultConfig.outgoing.hostname : domain,
- !!resultConfig.outgoing.hostname, "smtp",
- resultConfig.outgoing.port, resultConfig.outgoing.socketType);
- }
-
- return new GuessAbortable(incomingHostDetector, outgoingHostDetector,
- updateConfig);
-}
-
-function GuessAbortable(incomingHostDetector, outgoingHostDetector,
- updateConfig)
-{
- Abortable.call(this);
- this._incomingHostDetector = incomingHostDetector;
- this._outgoingHostDetector = outgoingHostDetector;
- this._updateConfig = updateConfig;
-}
-GuessAbortable.prototype = Object.create(Abortable.prototype);
-GuessAbortable.prototype.constructor = GuessAbortable;
-GuessAbortable.prototype.cancel = function(ex)
-{
- this._incomingHostDetector.cancel(ex);
- this._outgoingHostDetector.cancel(ex);
-};
-
-//////////////////////////////////////////////////////////////////////////////
-// Implementation
-//
-// Objects, functions and constants that follow are not to be used outside
-// this file.
-
-var kNotTried = 0;
-var kOngoing = 1;
-var kFailed = 2;
-var kSuccess = 3;
-
-/**
- * Internal object holding one server that we should try or did try.
- * Used as |thisTry|.
- *
- * Note: The consts it uses for protocol and ssl are defined towards the end
- * of this file and not the same as those used in AccountConfig (type,
- * socketType). (fix this)
- */
-function HostTry()
-{
-}
-HostTry.prototype =
-{
- // IMAP, POP or SMTP
- protocol : UNKNOWN,
- // {String}
- hostname : undefined,
- // {Integer}
- port : undefined,
- // NONE, SSL or TLS
- ssl : UNKNOWN,
- // {String} what to send to server
- commands : null,
- // {Integer-enum} kNotTried, kOngoing, kFailed or kSuccess
- status : kNotTried,
- // {Abortable} allows to cancel the socket comm
- abortable : null,
-
- // {Array of {Integer-enum}} @see _advertisesAuthMethods() result
- // Info about the server, from the protocol and SSL chat
- authMethods : null,
- // {String} Whether the SSL cert is not from a proper CA
- selfSignedCert : false,
- // {String} Which host the SSL cert is made for, if not hostname.
- // If set, this is an SSL error.
- targetSite : null,
-};
-
-/**
- * When the success or errorCallbacks are called to abort the other requests
- * which happened in parallel, this ex is used as param for cancel(), so that
- * the cancel doesn't trigger another callback.
- */
-function CancelOthersException()
-{
- CancelledException.call(this, "we're done, cancelling the other probes");
-}
-CancelOthersException.prototype = Object.create(CancelledException.prototype);
-CancelOthersException.prototype.constructor = CancelOthersException;
-
-/**
- * @param successCallback {function(result {HostTry}, alts {Array of HostTry})}
- * Called when the config is OK
- * |result| is the most preferred server.
- * |alts| currently exists only for |IncomingHostDetector| and contains
- * some servers of the other type (POP3 instead of IMAP), if available.
- * @param errorCallback {function(ex)} Called when we could not find a config
- * @param progressCallback { function(server {HostTry}) } Called when we tried
- * (will try?) a new hostname and port
- */
-function HostDetector(progressCallback, successCallback, errorCallback)
-{
- this.mSuccessCallback = successCallback;
- this.mProgressCallback = progressCallback;
- this.mErrorCallback = errorCallback;
- this._cancel = false;
- // {Array of {HostTry}}, ordered by decreasing preference
- this._hostsToTry = new Array();
-
- // init logging
- this._log = Log4Moz.getConfiguredLogger("mail.wizard");
- this._log.info("created host detector");
-}
-
-HostDetector.prototype =
-{
- cancel : function(ex)
- {
- this._cancel = true;
- // We have to actively stop the network calls, as they may result in
- // callbacks e.g. to the cert handler. If the dialog is gone by the time
- // this happens, the javascript stack is horked.
- for (let i = 0; i < this._hostsToTry.length; i++)
- {
- let thisTry = this._hostsToTry[i]; // {HostTry}
- if (thisTry.abortable)
- thisTry.abortable.cancel(ex);
- thisTry.status = kFailed; // or don't set? Maybe we want to continue.
- }
- if (ex instanceof CancelOthersException)
- return;
- if (!ex)
- ex = new CancelledException();
- this.mErrorCallback(ex);
- },
-
- /**
- * Start the detection
- *
- * @param domain {String} to be used as base for guessing.
- * Should be a domain (e.g. yahoo.co.uk).
- * If hostIsPrecise == true, it should be a full hostname
- * @param hostIsPrecise {Boolean} (default false) use only this hostname,
- * do not guess hostnames.
- * @param type {String-enum}@see AccountConfig type
- * (Optional. default, 0, undefined, null = guess it)
- * @param port {Integer} (Optional. default, 0, undefined, null = guess it)
- * @param socketType {Integer-enum}@see AccountConfig socketType
- * (Optional. default, 0, undefined, null = guess it)
- */
- start : function(domain, hostIsPrecise, type, port, socketType)
- {
- domain = domain.replace(/\s*/g, ""); // Remove whitespace
- if (!hostIsPrecise)
- hostIsPrecise = false;
- var protocol = sanitize.translate(type,
- { "imap" : IMAP, "pop3" : POP, "smtp" : SMTP }, UNKNOWN);
- if (!port)
- port = UNKNOWN;
- var ssl_only = Services.prefs.getBoolPref("mailnews.auto_config.guess.sslOnly");
- var ssl = ConvertSocketTypeToSSL(socketType);
- this._cancel = false;
- this._log.info("doing auto detect for protocol " + protocol +
- ", domain " + domain + ", (exactly: " + hostIsPrecise +
- "), port " + port + ", ssl " + ssl);
-
- // fill this._hostsToTry
- this._hostsToTry = [];
- var hostnamesToTry = [];
- // if hostIsPrecise is true, it's because that's what the user input
- // explicitly, and we'll just try it, nothing else.
- if (hostIsPrecise)
- hostnamesToTry.push(domain);
- else
- hostnamesToTry = this._hostnamesToTry(protocol, domain);
-
- for (let i = 0; i < hostnamesToTry.length; i++)
- {
- let hostname = hostnamesToTry[i];
- let hostEntries = this._portsToTry(hostname, protocol, ssl, port);
- for (let j = 0; j < hostEntries.length; j++)
- {
- let hostTry = hostEntries[j]; // from getHostEntry()
- if (ssl_only && hostTry.ssl == NONE)
- continue;
- hostTry.hostname = hostname;
- hostTry.status = kNotTried;
- hostTry.desc = hostTry.hostname + ":" + hostTry.port +
- " ssl=" + hostTry.ssl + " " +
- protocolToString(hostTry.protocol);
- this._hostsToTry.push(hostTry);
- }
- }
-
- this._hostsToTry = sortTriesByPreference(this._hostsToTry);
- this._tryAll();
- },
-
- // We make all host/port combinations run in parallel, store their
- // results in an array, and as soon as one finishes successfully and all
- // higher-priority ones have failed, we abort all lower-priority ones.
-
- _tryAll : function()
- {
- if (this._cancel)
- return;
- var me = this;
- var timeout = Services.prefs.getIntPref("mailnews.auto_config.guess.timeout");
- // We assume we'll resolve the same proxy for all tries, and
- // proceed to use the first resolved proxy for all tries. This
- // assumption is generally sound, but not always: mechanisms like
- // the pref network.proxy.no_proxies_on can make imap.domain and
- // pop.domain resolve differently.
- doProxy(this._hostsToTry[0].hostname, function(proxy) {
- for (let i = 0; i < me._hostsToTry.length; i++) {
- let thisTry = me._hostsToTry[i]; // {HostTry}
- if (thisTry.status != kNotTried)
- continue;
- me._log.info(thisTry.desc + ": initializing probe...");
- if (i == 0) // showing 50 servers at once is pointless
- me.mProgressCallback(thisTry);
-
- thisTry.abortable = SocketUtil(
- thisTry.hostname, thisTry.port, thisTry.ssl,
- thisTry.commands, timeout, proxy,
- new SSLErrorHandler(thisTry, me._log),
- function(wiredata) // result callback
- {
- if (me._cancel)
- return; // don't use response anymore
- me.mProgressCallback(thisTry);
- me._processResult(thisTry, wiredata);
- me._checkFinished();
- },
- function(e) // error callback
- {
- if (me._cancel)
- return; // who set cancel to true already called mErrorCallback()
- me._log.warn(thisTry.desc + ": " + e);
- thisTry.status = kFailed;
- me._checkFinished();
- }
- );
- thisTry.status = kOngoing;
- }
- });
- },
-
- /**
- * @param thisTry {HostTry}
- * @param wiredata {Array of {String}} what the server returned
- * in response to our protocol chat
- */
- _processResult : function(thisTry, wiredata)
- {
- if (thisTry._gotCertError)
- {
- if (thisTry._gotCertError == Ci.nsICertOverrideService.ERROR_MISMATCH)
- {
- thisTry._gotCertError = 0;
- thisTry.status = kFailed;
- return;
- }
-
- if (thisTry._gotCertError == Ci.nsICertOverrideService.ERROR_UNTRUSTED ||
- thisTry._gotCertError == Ci.nsICertOverrideService.ERROR_TIME)
- {
- this._log.info(thisTry.desc + ": TRYING AGAIN, hopefully with exception recorded");
- thisTry._gotCertError = 0;
- thisTry.selfSignedCert = true; // _next_ run gets this exception
- thisTry.status = kNotTried; // try again (with exception)
- this._tryAll();
- return;
- }
- }
-
- if (wiredata == null || wiredata === undefined)
- {
- this._log.info(thisTry.desc + ": no data");
- thisTry.status = kFailed;
- return;
- }
- this._log.info(thisTry.desc + ": wiredata: " + wiredata.join(""));
- thisTry.authMethods =
- this._advertisesAuthMethods(thisTry.protocol, wiredata);
- if (thisTry.ssl == TLS && !this._hasTLS(thisTry, wiredata))
- {
- this._log.info(thisTry.desc + ": STARTTLS wanted, but not offered");
- thisTry.status = kFailed;
- return;
- }
- this._log.info(thisTry.desc + ": success" +
- (thisTry.selfSignedCert ? " (selfSignedCert)" : ""));
- thisTry.status = kSuccess;
-
- if (thisTry.selfSignedCert) { // eh, ERROR_UNTRUSTED or ERROR_TIME
- // We clear the temporary override now after success. If we clear it
- // earlier we get into an infinite loop, probably because the cert
- // remembering is temporary and the next try gets a new connection which
- // isn't covered by that temporariness.
- this._log.info(thisTry.desc + ": clearing validity override for " +
- thisTry.hostname);
- Cc["@mozilla.org/security/certoverride;1"]
- .getService(Ci.nsICertOverrideService)
- .clearValidityOverride(thisTry.hostname, thisTry.port);
- }
- },
-
- _checkFinished : function()
- {
- var successfulTry = null;
- var successfulTryAlternative = null; // POP3
- var unfinishedBusiness = false;
- // this._hostsToTry is ordered by decreasing preference
- for (let i = 0; i < this._hostsToTry.length; i++)
- {
- let thisTry = this._hostsToTry[i];
- if (thisTry.status == kNotTried || thisTry.status == kOngoing)
- unfinishedBusiness = true;
- // thisTry is good, and all higher preference tries failed, so use this
- else if (thisTry.status == kSuccess && !unfinishedBusiness)
- {
- if (!successfulTry)
- {
- successfulTry = thisTry;
- if (successfulTry.protocol == SMTP)
- break;
- }
- else if (successfulTry.protocol != thisTry.protocol)
- {
- successfulTryAlternative = thisTry;
- break;
- }
- }
- }
- if (successfulTry && (successfulTryAlternative || !unfinishedBusiness))
- {
- this.mSuccessCallback(successfulTry,
- successfulTryAlternative ? [ successfulTryAlternative ] : []);
- this.cancel(new CancelOthersException());
- }
- else if (!unfinishedBusiness) // all failed
- {
- this._log.info("ran out of options");
- var errorMsg = getStringBundle(
- "chrome://messenger/locale/accountCreationModel.properties")
- .GetStringFromName("cannot_find_server.error");
- this.mErrorCallback(new Exception(errorMsg));
- // no need to cancel, all failed
- }
- // else let ongoing calls continue
- },
-
-
- /**
- * Which auth mechanism the server claims to support.
- * (That doesn't necessarily reflect reality, it is more an upper bound.)
- *
- * @param protocol {Integer-enum} IMAP, POP or SMTP
- * @param capaResponse {Array of {String}} on the wire data
- * that the server returned. May be the full exchange or just capa.
- * @returns {Array of {Integer-enum} values for AccountConfig.incoming.auth
- * (or outgoing), in decreasing order of preference.
- * E.g. [ 5, 4 ] for a server that supports only Kerberos and
- * encrypted passwords.
- */
- _advertisesAuthMethods : function(protocol, capaResponse)
- {
- // for imap, capabilities include e.g.:
- // "AUTH=CRAM-MD5", "AUTH=NTLM", "AUTH=GSSAPI", "AUTH=MSN"
- // for pop3, the auth mechanisms are returned in capa as the following:
- // "CRAM-MD5", "NTLM", "MSN", "GSSAPI"
- // For smtp, EHLO will return AUTH and then a list of the
- // mechanism(s) supported, e.g.,
- // AUTH LOGIN NTLM MSN CRAM-MD5 GSSAPI
- var result = new Array();
- var line = capaResponse.join("\n").toUpperCase();
- var prefix = "";
- if (protocol == POP)
- prefix = "";
- else if (protocol == IMAP)
- prefix = "AUTH=";
- else if (protocol == SMTP)
- prefix = "AUTH.*";
- else
- throw NotReached("must pass protocol");
- // add in decreasing order of preference
- if (new RegExp(prefix + "GSSAPI").test(line))
- result.push(Ci.nsMsgAuthMethod.GSSAPI);
- if (new RegExp(prefix + "CRAM-MD5").test(line))
- result.push(Ci.nsMsgAuthMethod.passwordEncrypted);
- if (new RegExp(prefix + "(NTLM|MSN)").test(line))
- result.push(Ci.nsMsgAuthMethod.NTLM);
- if (protocol != IMAP || !line.includes("LOGINDISABLED"))
- result.push(Ci.nsMsgAuthMethod.passwordCleartext);
- return result;
- },
-
- _hasTLS : function(thisTry, wiredata)
- {
- var capa = thisTry.protocol == POP ? "STLS" : "STARTTLS";
- return thisTry.ssl == TLS &&
- wiredata.join("").toUpperCase().includes(capa);
- },
-}
-
-/**
- * @param authMethods @see return value of _advertisesAuthMethods()
- * Note: the returned auth method will be removed from the array.
- * @return one of them, the preferred one
- * Note: this might be Kerberos, which might not actually work,
- * so you might need to try the others, too.
- */
-function chooseBestAuthMethod(authMethods)
-{
- if (!authMethods || !authMethods.length)
- return Ci.nsMsgAuthMethod.passwordCleartext;
- return authMethods.shift(); // take first (= most preferred)
-}
-
-
-function IncomingHostDetector(
- progressCallback, successCallback, errorCallback)
-{
- HostDetector.call(this, progressCallback, successCallback, errorCallback);
-}
-IncomingHostDetector.prototype =
-{
- __proto__: HostDetector.prototype,
- _hostnamesToTry : function(protocol, domain)
- {
- var hostnamesToTry = [];
- if (protocol != POP)
- hostnamesToTry.push("imap." + domain);
- if (protocol != IMAP)
- {
- hostnamesToTry.push("pop3." + domain);
- hostnamesToTry.push("pop." + domain);
- }
- hostnamesToTry.push("mail." + domain);
- hostnamesToTry.push(domain);
- return hostnamesToTry;
- },
- _portsToTry : getIncomingTryOrder,
-}
-
-function OutgoingHostDetector(
- progressCallback, successCallback, errorCallback)
-{
- HostDetector.call(this, progressCallback, successCallback, errorCallback);
-}
-OutgoingHostDetector.prototype =
-{
- __proto__: HostDetector.prototype,
- _hostnamesToTry : function(protocol, domain)
- {
- var hostnamesToTry = [];
- hostnamesToTry.push("smtp." + domain);
- hostnamesToTry.push("mail." + domain);
- hostnamesToTry.push(domain);
- return hostnamesToTry;
- },
- _portsToTry : getOutgoingTryOrder,
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Encode protocol ports and order of preference
-
-// Protocol Types
-var UNKNOWN = -1;
-var IMAP = 0;
-var POP = 1;
-var SMTP = 2;
-// Security Types
-var NONE = 0; // no encryption
-//1 would be "TLS if available"
-var TLS = 2; // STARTTLS
-var SSL = 3; // SSL / TLS
-
-var IMAP_PORTS = {}
-IMAP_PORTS[NONE] = 143;
-IMAP_PORTS[TLS] = 143;
-IMAP_PORTS[SSL] = 993;
-
-var POP_PORTS = {}
-POP_PORTS[NONE] = 110;
-POP_PORTS[TLS] = 110;
-POP_PORTS[SSL] = 995;
-
-var SMTP_PORTS = {}
-SMTP_PORTS[NONE] = 587;
-SMTP_PORTS[TLS] = 587;
-SMTP_PORTS[SSL] = 465;
-
-var CMDS = {}
-CMDS[IMAP] = ["1 CAPABILITY\r\n", "2 LOGOUT\r\n"];
-CMDS[POP] = ["CAPA\r\n", "QUIT\r\n"];
-CMDS[SMTP] = ["EHLO we-guess.mozilla.org\r\n", "QUIT\r\n"];
-
-/**
- * Sort by preference of SSL, IMAP etc.
- * @param tries {Array of {HostTry}}
- * @returns {Array of {HostTry}}
- */
-function sortTriesByPreference(tries)
-{
- return tries.sort(function __sortByPreference(a, b)
- {
- // -1 = a is better; 1 = b is better; 0 = equal
- // Prefer SSL/TLS above all else
- if (a.ssl != NONE && b.ssl == NONE)
- return -1;
- if (b.ssl != NONE && a.ssl == NONE)
- return 1;
- // Prefer IMAP over POP
- if (a.protocol == IMAP && b.protocol == POP)
- return -1;
- if (b.protocol == IMAP && a.protocol == POP)
- return 1;
- // For hostnames, leave existing sorting, as in _hostnamesToTry()
- // For ports, leave existing sorting, as in getOutgoingTryOrder()
- return 0;
- });
-};
-
-// TODO prefer SSL over STARTTLS,
-// either in sortTriesByPreference or in getIncomingTryOrder() (and outgoing)
-
-/**
- * @returns {Array of {HostTry}}
- */
-function getIncomingTryOrder(host, protocol, ssl, port)
-{
- var lowerCaseHost = host.toLowerCase();
-
- if (protocol == UNKNOWN &&
- (lowerCaseHost.startsWith("pop.") || lowerCaseHost.startsWith("pop3.")))
- protocol = POP;
- else if (protocol == UNKNOWN && lowerCaseHost.startsWith("imap."))
- protocol = IMAP;
-
- if (protocol != UNKNOWN) {
- if (ssl == UNKNOWN)
- return [getHostEntry(protocol, TLS, port),
- //getHostEntry(protocol, SSL, port),
- getHostEntry(protocol, NONE, port)];
- return [getHostEntry(protocol, ssl, port)];
- }
- if (ssl == UNKNOWN)
- return [getHostEntry(IMAP, TLS, port),
- //getHostEntry(IMAP, SSL, port),
- getHostEntry(POP, TLS, port),
- //getHostEntry(POP, SSL, port),
- getHostEntry(IMAP, NONE, port),
- getHostEntry(POP, NONE, port)];
- return [getHostEntry(IMAP, ssl, port),
- getHostEntry(POP, ssl, port)];
-};
-
-/**
- * @returns {Array of {HostTry}}
- */
-function getOutgoingTryOrder(host, protocol, ssl, port)
-{
- assert(protocol == SMTP, "need SMTP as protocol for outgoing");
- if (ssl == UNKNOWN)
- {
- if (port == UNKNOWN)
- // neither SSL nor port known
- return [getHostEntry(SMTP, TLS, UNKNOWN),
- getHostEntry(SMTP, TLS, 25),
- //getHostEntry(SMTP, SSL, UNKNOWN),
- getHostEntry(SMTP, NONE, UNKNOWN),
- getHostEntry(SMTP, NONE, 25)];
- // port known, SSL not
- return [getHostEntry(SMTP, TLS, port),
- //getHostEntry(SMTP, SSL, port),
- getHostEntry(SMTP, NONE, port)];
- }
- // SSL known, port not
- if (port == UNKNOWN)
- {
- if (ssl == SSL)
- return [getHostEntry(SMTP, SSL, UNKNOWN)];
- else // TLS or NONE
- return [getHostEntry(SMTP, ssl, UNKNOWN),
- getHostEntry(SMTP, ssl, 25)];
- }
- // SSL and port known
- return [getHostEntry(SMTP, ssl, port)];
-};
-
-/**
- * @returns {HostTry} with proper default port and commands,
- * but without hostname.
- */
-function getHostEntry(protocol, ssl, port)
-{
- if (!port || port == UNKNOWN) {
- switch (protocol) {
- case POP:
- port = POP_PORTS[ssl];
- break;
- case IMAP:
- port = IMAP_PORTS[ssl];
- break;
- case SMTP:
- port = SMTP_PORTS[ssl];
- break;
- default:
- throw new NotReached("unsupported protocol " + protocol);
- }
- }
-
- var r = new HostTry();
- r.protocol = protocol;
- r.ssl = ssl;
- r.port = port;
- r.commands = CMDS[protocol];
- return r;
-};
-
-
-// Convert consts from those used here to those from AccountConfig
-// TODO adjust consts to match AccountConfig
-
-// here -> AccountConfig
-function sslConvertToSocketType(ssl)
-{
- if (ssl == NONE)
- return 1;
- if (ssl == SSL)
- return 2;
- if (ssl == TLS)
- return 3;
- throw new NotReached("unexpected SSL type");
-}
-
-// AccountConfig -> here
-function ConvertSocketTypeToSSL(socketType)
-{
- if (socketType == 1)
- return NONE;
- if (socketType == 2)
- return SSL;
- if (socketType == 3)
- return TLS;
- return UNKNOWN;
-}
-
-// here -> AccountConfig
-function protocolToString(type)
-{
- if (type == IMAP)
- return "imap";
- if (type == POP)
- return "pop3";
- if (type == SMTP)
- return "smtp";
- throw new NotReached("unexpected protocol");
-}
-
-
-
-/////////////////////////////////////////////////////////
-// SSL cert error handler
-
-/**
- * Called by MyBadCertHandler.js, which called by PSM
- * to tell us about SSL certificate errors.
- * @param thisTry {HostTry}
- * @param logger {Log4Moz logger}
- */
-function SSLErrorHandler(thisTry, logger)
-{
- this._try = thisTry;
- this._log = logger;
- // _ gotCertError will be set to an error code (one of those defined in
- // nsICertOverrideService)
- this._gotCertError = 0;
-}
-SSLErrorHandler.prototype =
-{
- processCertError : function(socketInfo, status, targetSite)
- {
- this._log.error("Got Cert error for "+ targetSite);
-
- if (!status)
- return true;
-
- let cert = status.QueryInterface(Ci.nsISSLStatus).serverCert;
- let flags = 0;
-
- let parts = targetSite.split(":");
- let host = parts[0];
- let port = parts[1];
-
- /* The following 2 cert problems are unfortunately common:
- * 1) hostname mismatch:
- * user is custeromer at a domain hoster, he owns yourname.org,
- * and the IMAP server is imap.hoster.com (but also reachable as
- * imap.yourname.org), and has a cert for imap.hoster.com.
- * 2) self-signed:
- * a company has an internal IMAP server, and it's only for
- * 30 employees, and they didn't want to buy a cert, so
- * they use a self-signed cert.
- *
- * We would like the above to pass, somehow, with user confirmation.
- * The following case should *not* pass:
- *
- * 1) MITM
- * User has @gmail.com, and an attacker is between the user and
- * the Internet and runs a man-in-the-middle (MITM) attack.
- * Attacker controls DNS and sends imap.gmail.com to his own
- * imap.attacker.com. He has either a valid, CA-issued
- * cert for imap.attacker.com, or a self-signed cert.
- * Of course, attacker.com could also be legit-sounding gmailservers.com.
- *
- * What makes it dangerous is that we (!) propose the server to the user,
- * and he cannot judge whether imap.gmailservers.com is correct or not,
- * and he will likely approve it.
- */
-
- if (status.isDomainMismatch) {
- this._try._gotCertError = Ci.nsICertOverrideService.ERROR_MISMATCH;
- flags |= Ci.nsICertOverrideService.ERROR_MISMATCH;
- }
- else if (status.isUntrusted) { // e.g. self-signed
- this._try._gotCertError = Ci.nsICertOverrideService.ERROR_UNTRUSTED;
- flags |= Ci.nsICertOverrideService.ERROR_UNTRUSTED;
- }
- else if (status.isNotValidAtThisTime) {
- this._try._gotCertError = Ci.nsICertOverrideService.ERROR_TIME;
- flags |= Ci.nsICertOverrideService.ERROR_TIME;
- }
- else {
- this._try._gotCertError = -1; // other
- }
-
- /* We will add a temporary cert exception here, so that
- * we can continue and connect and try.
- * But we will remove it again as soon as we close the
- * connection, in _processResult().
- * _gotCertError will serve as the marker that we
- * have to clear the override later.
- *
- * In verifyConfig(), before we send the password, we *must*
- * get another cert exception, this time with dialog to the user
- * so that he gets informed about this and can make a choice.
- */
-
- this._try.targetSite = targetSite;
- Cc["@mozilla.org/security/certoverride;1"]
- .getService(Ci.nsICertOverrideService)
- .rememberValidityOverride(host, port, cert, flags,
- true); // temporary override
- this._log.warn("!! Overrode bad cert temporarily " + host + " " + port +
- " flags=" + flags + "\n");
- return true;
- },
-}
-
-
-
-//////////////////////////////////////////////////////////////////
-// Socket Util
-
-
-/**
- * @param hostname {String} The DNS hostname to connect to.
- * @param port {Integer} The numberic port to connect to on the host.
- * @param ssl {Integer} SSL, TLS or NONE
- * @param commands {Array of String}: protocol commands
- * to send to the server.
- * @param timeout {Integer} seconds to wait for a server response, then cancel.
- * @param proxy {nsIProxyInfo} The proxy to use (or null to not use any).
- * @param sslErrorHandler {SSLErrorHandler}
- * @param resultCallback {function(wiredata)} This function will
- * be called with the result string array from the server
- * or null if no communication occurred.
- * @param errorCallback {function(e)}
- */
-function SocketUtil(hostname, port, ssl, commands, timeout, proxy,
- sslErrorHandler, resultCallback, errorCallback)
-{
- assert(commands && commands.length, "need commands");
-
- var index = 0; // commands[index] is next to send to server
- var initialized = false;
- var aborted = false;
-
- function _error(e)
- {
- if (aborted)
- return;
- aborted = true;
- errorCallback(e);
- }
-
- function timeoutFunc()
- {
- if (!initialized)
- _error("timeout");
- }
-
- // In case DNS takes too long or does not resolve or another blocking
- // issue occurs before the timeout can be set on the socket, this
- // ensures that the listener callback will be fired in a timely manner.
- // XXX There might to be some clean up needed after the timeout is fired
- // for socket and io resources.
-
- // The timeout value plus 2 seconds
- setTimeout(timeoutFunc, (timeout * 1000) + 2000);
-
- var transportService = Cc["@mozilla.org/network/socket-transport-service;1"]
- .getService(Ci.nsISocketTransportService);
-
- // @see NS_NETWORK_SOCKET_CONTRACTID_PREFIX
- var socketTypeName = ssl == SSL ? "ssl" : (ssl == TLS ? "starttls" : null);
- var transport = transportService.createTransport([socketTypeName],
- ssl == NONE ? 0 : 1,
- hostname, port, proxy);
-
- transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT, timeout);
- transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_READ_WRITE, timeout);
- try {
- transport.securityCallbacks = new BadCertHandler(sslErrorHandler);
- } catch (e) {
- _error(e);
- }
- var outstream = transport.openOutputStream(0, 0, 0);
- var stream = transport.openInputStream(0, 0, 0);
- var instream = Cc["@mozilla.org/scriptableinputstream;1"]
- .createInstance(Ci.nsIScriptableInputStream);
- instream.init(stream);
-
- var dataListener =
- {
- data : new Array(),
- onStartRequest: function(request, context)
- {
- try {
- initialized = true;
- if (!aborted)
- {
- // Send the first request
- let outputData = commands[index++];
- outstream.write(outputData, outputData.length);
- }
- } catch (e) { _error(e); }
- },
- onStopRequest: function(request, context, status)
- {
- try {
- instream.close();
- outstream.close();
- resultCallback(this.data.length ? this.data : null);
- } catch (e) { _error(e); }
- },
- onDataAvailable: function(request, context, inputStream, offset, count)
- {
- try {
- if (!aborted)
- {
- let inputData = instream.read(count);
- this.data.push(inputData);
- if (index < commands.length)
- {
- // Send the next request to the server.
- let outputData = commands[index++];
- outstream.write(outputData, outputData.length);
- }
- }
- } catch (e) { _error(e); }
- }
- };
-
- try {
- var pump = Cc["@mozilla.org/network/input-stream-pump;1"]
- .createInstance(Ci.nsIInputStreamPump);
-
- pump.init(stream, -1, -1, 0, 0, false);
- pump.asyncRead(dataListener, null);
- return new SocketAbortable(transport);
- } catch (e) { _error(e); }
- return null;
-}
-
-function SocketAbortable(transport)
-{
- Abortable.call(this);
- assert(transport instanceof Ci.nsITransport, "need transport");
- this._transport = transport;
-}
-SocketAbortable.prototype = Object.create(Abortable.prototype);
-SocketAbortable.prototype.constructor = UserCancelledException;
-SocketAbortable.prototype.cancel = function(ex)
-{
- try {
- this._transport.close(Components.results.NS_ERROR_ABORT);
- } catch (e) {
- ddump("canceling socket failed: " + e);
- }
-}
-
-/**
- * Resolve a proxy for some domain and expose it via a callback.
- *
- * @param hostname {String} The hostname which a proxy will be resolved for
- * @param resultCallback {function(proxyInfo)}
- * Called after the proxy has been resolved for hostname.
- * proxy {nsIProxyInfo} The resolved proxy, or null if none were found
- * for hostname
- */
-function doProxy(hostname, resultCallback) {
- // This implements the nsIProtocolProxyCallback interface:
- function ProxyResolveCallback() { }
- ProxyResolveCallback.prototype = {
- onProxyAvailable(req, uri, proxy, status) {
- // Anything but a SOCKS proxy will be unusable for email.
- if (proxy != null && proxy.type != "socks" &&
- proxy.type != "socks4") {
- proxy = null;
- }
- resultCallback(proxy);
- },
- };
- var proxyService = Cc["@mozilla.org/network/protocol-proxy-service;1"]
- .getService(Ci.nsIProtocolProxyService);
- // Use some arbitrary scheme just because it is required...
- var uri = Services.io.newURI("http://" + hostname);
- // ... we'll ignore it any way. We prefer SOCKS since that's the
- // only thing we can use for email protocols.
- var proxyFlags = Ci.nsIProtocolProxyService.RESOLVE_IGNORE_URI_SCHEME |
- Ci.nsIProtocolProxyService.RESOLVE_PREFER_SOCKS_PROXY;
- if (Services.prefs.getBoolPref("network.proxy.socks_remote_dns")) {
- proxyFlags |= Ci.nsIProtocolProxyService.RESOLVE_ALWAYS_TUNNEL;
- }
- proxyService.asyncResolve(uri, proxyFlags, new ProxyResolveCallback());
-}
diff --git a/mailnews/base/prefs/content/accountcreation/readFromXML.js b/mailnews/base/prefs/content/accountcreation/readFromXML.js
deleted file mode 100644
index 4ef13ec1d..000000000
--- a/mailnews/base/prefs/content/accountcreation/readFromXML.js
+++ /dev/null
@@ -1,243 +0,0 @@
-/* -*- 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,
-#ifdef MOZ_MAILNEWS_OAUTH2
- "OAuth2" : Ci.nsMsgAuthMethod.OAuth2
-#endif
- });
- 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,
-#ifdef MOZ_MAILNEWS_OAUTH2
- "OAuth2" : Ci.nsMsgAuthMethod.OAuth2,
-#endif
- });
-
- 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;
-}
diff --git a/mailnews/base/prefs/content/accountcreation/sanitizeDatatypes.js b/mailnews/base/prefs/content/accountcreation/sanitizeDatatypes.js
deleted file mode 100644
index 3c927a1af..000000000
--- a/mailnews/base/prefs/content/accountcreation/sanitizeDatatypes.js
+++ /dev/null
@@ -1,205 +0,0 @@
-/* -*- 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);
- Exception.call(this, msg);
-}
-MalformedException.prototype = Object.create(Exception.prototype);
-MalformedException.prototype.constructor = MalformedException;
-
diff --git a/mailnews/base/prefs/content/accountcreation/util.js b/mailnews/base/prefs/content/accountcreation/util.js
deleted file mode 100644
index 44c22ac45..000000000
--- a/mailnews/base/prefs/content/accountcreation/util.js
+++ /dev/null
@@ -1,304 +0,0 @@
-/* -*- 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_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
- 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);
-}
diff --git a/mailnews/base/prefs/content/accountcreation/verifyConfig.js b/mailnews/base/prefs/content/accountcreation/verifyConfig.js
deleted file mode 100644
index 073487ba9..000000000
--- a/mailnews/base/prefs/content/accountcreation/verifyConfig.js
+++ /dev/null
@@ -1,353 +0,0 @@
-/* -*- 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");
-#ifdef MOZ_MAILNEWS_OAUTH2
-Components.utils.import("resource://gre/modules/OAuth2Providers.jsm");
-#endif
-
-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 {
-#ifdef MOZ_MAILNEWS_OAUTH2
- // 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)
-#else
- if (inServer.password)
-#endif
- 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;
- }
-}
diff --git a/mailnews/jar.mn b/mailnews/jar.mn
index 8b850ecb9..3d5ba7534 100644
--- a/mailnews/jar.mn
+++ b/mailnews/jar.mn
@@ -65,20 +65,6 @@ messenger.jar:
* content/messenger/smtpEditOverlay.js (base/prefs/content/smtpEditOverlay.js)
content/messenger/removeAccount.xul (base/prefs/content/removeAccount.xul)
content/messenger/removeAccount.js (base/prefs/content/removeAccount.js)
-#if defined(MOZ_THUNDERBIRD) && defined(HYPE_ICEDOVE)
-* content/messenger/accountcreation/accountConfig.js (base/prefs/content/accountcreation/accountConfig.js)
-* content/messenger/accountcreation/createInBackend.js (base/prefs/content/accountcreation/createInBackend.js)
-* content/messenger/accountcreation/emailWizard.js (base/prefs/content/accountcreation/emailWizard.js)
-* content/messenger/accountcreation/emailWizard.xul (base/prefs/content/accountcreation/emailWizard.xul)
- content/messenger/accountcreation/fetchConfig.js (base/prefs/content/accountcreation/fetchConfig.js)
- content/messenger/accountcreation/fetchhttp.js (base/prefs/content/accountcreation/fetchhttp.js)
-* content/messenger/accountcreation/guessConfig.js (base/prefs/content/accountcreation/guessConfig.js)
- content/messenger/accountcreation/MyBadCertHandler.js (base/prefs/content/accountcreation/MyBadCertHandler.js)
-* content/messenger/accountcreation/readFromXML.js (base/prefs/content/accountcreation/readFromXML.js)
- content/messenger/accountcreation/sanitizeDatatypes.js (base/prefs/content/accountcreation/sanitizeDatatypes.js)
- content/messenger/accountcreation/util.js (base/prefs/content/accountcreation/util.js)
-* content/messenger/accountcreation/verifyConfig.js (base/prefs/content/accountcreation/verifyConfig.js)
-#endif
content/messenger/msgSynchronize.xul (base/content/msgSynchronize.xul)
content/messenger/msgSynchronize.js (base/content/msgSynchronize.js)
content/messenger/folderProps.xul (base/content/folderProps.xul)