diff options
author | Matt A. Tobin <email@mattatobin.com> | 2021-10-21 13:00:16 -0400 |
---|---|---|
committer | Matt A. Tobin <email@mattatobin.com> | 2021-10-21 13:00:34 -0400 |
commit | 1c05565e168719d0a00e95e7afbd049413275f08 (patch) | |
tree | 0e200388901934755eab7c1f2cf2cf819c5fdee9 /mailnews | |
parent | a82a18718dd6391108b5d3587364cff57db06b71 (diff) | |
download | aura-central-1c05565e168719d0a00e95e7afbd049413275f08.tar.gz |
Issue %3025 - Part 2: Remove HYPE_ICEDOVE and Baby Mode Account Creation
Diffstat (limited to 'mailnews')
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"> </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) |