Backed out 4 changesets (bug 1514522, bug 1500105, bug 1511571, bug 1515903) for breaking account creation, bug 1516134. a=backout THUNDERBIRD_65_0b1_BUILD5 THUNDERBIRD_65_0b1_RELEASE
authorJorg K <jorgk@jorgk.com>
Sat, 22 Dec 2018 21:56:21 +0100
changeset 33050 195a2aef72e1ab507c07ca93e703600b4b09c3b3
parent 33049 ffdb14a414dd1a326a85870b100f442e0a58de0a
child 33051 84b08b96490f60725939d82ba4177d908e358554
push id2352
push usermozilla@jorgk.com
push dateSat, 22 Dec 2018 20:57:02 +0000
treeherdercomm-beta@195a2aef72e1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1514522, 1500105, 1511571, 1515903, 1516134
backs out44241fb0b16211fe4e3cbe66c7689e9c742e9730
886ee22a3f85d1a7f55c7fa1e5813470be99d88a
dacb68554465e5daf329f5f9502932c0bd5f62af
60a1cefdf2afe240abc3558542a8237276e7f000
Backed out 4 changesets (bug 1514522, bug 1500105, bug 1511571, bug 1515903) for breaking account creation, bug 1516134. a=backout Backed out changeset 44241fb0b162 (bug 1514522) Backed out changeset 886ee22a3f85 (bug 1515903) Backed out changeset dacb68554465 (bug 1511571) Backed out changeset 60a1cefdf2af (bug 1500105)
mail/components/accountcreation/content/.eslintrc.js
mail/components/accountcreation/content/accountConfig.js
mail/components/accountcreation/content/createInBackend.js
mail/components/accountcreation/content/emailWizard.js
mail/components/accountcreation/content/emailWizard.xul
mail/components/accountcreation/content/exchangeAutoDiscover.js
mail/components/accountcreation/content/fetchConfig.js
mail/components/accountcreation/content/fetchhttp.js
mail/components/accountcreation/content/guessConfig.js
mail/components/accountcreation/content/readFromXML.js
mail/components/accountcreation/content/sanitizeDatatypes.js
mail/components/accountcreation/content/util.js
mail/components/accountcreation/content/verifyConfig.js
mail/components/accountcreation/jar.mn
mail/locales/en-US/chrome/messenger/accountCreation.dtd
mail/locales/en-US/chrome/messenger/accountCreation.properties
mail/locales/en-US/chrome/messenger/accountCreationModel.properties
mail/themes/linux/mail/accountCreation.css
mail/themes/osx/mail/accountCreation.css
mail/themes/shared/jar.inc.mn
mail/themes/shared/mail/accountCreation.css
mail/themes/windows/mail/accountCreation.css
mailnews/mailnews.js
--- a/mail/components/accountcreation/content/.eslintrc.js
+++ b/mail/components/accountcreation/content/.eslintrc.js
@@ -1,24 +1,22 @@
 "use strict";
 
 module.exports = {
   "globals": {
     "Abortable": true,
     "AccountConfig": true,
-    "AddonInstaller": true,
     "BadCertHandler": true,
     "CancelledException": true,
     "Exception": true,
     "FetchHTTP": true,
     "Log4Moz": true,
     "MailServices": true,
     "NewMailAccountProvisioner": true,
     "NotReached": true,
-    "PriorityOrderAbortable": true,
     "Services": true,
     "SuccessiveAbortable": true,
     "TimeoutAbortable": true,
     "UserCancelledException": true,
     "alertPrompt": true,
     "assert": true,
     "checkIncomingServerAlreadyExists": true,
     "checkOutgoingServerAlreadyExists": true,
@@ -26,17 +24,16 @@ module.exports = {
     "createAccountInBackend": true,
     "ddump": true,
     "debugObject": true,
     "deepCopy": true,
     "errorWithDebug": true,
     "fetchConfigForMX": true,
     "fetchConfigFromDB": true,
     "fetchConfigFromDisk": true,
-    "fetchConfigFromExchange": true,
     "fetchConfigFromISP": true,
     "getStringBundle": true,
     "guessConfig": true,
     "isLegalHostName": true,
     "isLegalHostNameOrIP": true,
     "isLegalIPAddress": true,
     "isLegalIPv4Address": true,
     "isLegalIPv6Address": true,
--- a/mail/components/accountcreation/content/accountConfig.js
+++ b/mail/components/accountcreation/content/accountConfig.js
@@ -63,17 +63,17 @@ AccountConfig.prototype =
   // { Array of Strings }
   domains: null,
 
   /**
    * Factory function for incoming and incomingAlternatives
    */
   createNewIncoming() {
     return {
-      // { String-enum: "pop3", "imap", "nntp", "exchange" }
+      // { 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 }
@@ -107,21 +107,16 @@ AccountConfig.prototype =
       // 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,
-
-      // for Microsoft Exchange servers. Optional.
-      owaURL: null,
-      ewsURL: null,
-      easURL: null,
     };
   },
   /**
    * Factory function for outgoing and outgoingAlternatives
    */
   createNewOutgoing() {
     return {
       type: "smtp",
@@ -140,95 +135,45 @@ AccountConfig.prototype =
       // nsISmtpServer.key
       existingServerKey: null,
       // user display value for existingServerKey
       existingServerLabel: null,
     };
   },
 
   /**
-   * The configuration needs an addon to handle the account type.
-   * The addon needs to be installed before the account can be created
-   * in the backend.
-   * You can choose one, if there are several addons in the list.
-   * (Optional)
-   *
-   * Array of:
-   * {
-   *   id: "owl@example.com" {string},
-   *
-   *   // already localized string
-   *   name: "Owl" {string},
-   *
-   *   // already localized string
-   *   description: "A third party addon that allows you to connect to Exchange servers" {string}
-   *
-   *   // Minimal version of the addon. Needed in case the addon is already installed,
-   *   // to verify that the installed version is sufficient.
-   *   // The XPI URL below must satisfy this.
-   *   // Must satisfy <https://developer.mozilla.org/en-US/docs/Mozilla/Toolkit_version_format>
-   *   minVersion: "0.2" {string}
-   *
-   *   xpiURL: "https://live.thunderbird.net/autoconfig/owl.xpi" {URL},
-   *   websiteURL: "https://www.beonex.com/owl/" {URL},
-   *   icon32: "https://www.beonex.com/owl/owl-32x32.png" {URL},
-   *
-   *   useType : {
-   *     // Type shown as radio button to user in the config result.
-   *     // Users won't understand OWA vs. EWS vs. EAS etc., so this is an abstraction
-   *     // from the end user perspective.
-   *     generalType: "exchange" {string},
-   *
-   *     // Protocol
-   *     // Independent of the addon
-   *     protocolType: "owa" {string},
-   *
-   *     // Account type in the Thunderbird backend.
-   *     // What nsIMsgAccount.type will be set to when creating the account.
-   *     // This is specific to the addon.
-   *     addonAccountType: "owl-owa" {string},
-   *   }
-   * }
-   */
-  addons: null,
-
-  /**
    * Returns a deep copy of this object,
    * i.e. modifying the copy will not affect the original object.
    */
   copy() {
     // Workaround: deepCopy() fails to preserve base obj (instanceof)
     var result = new AccountConfig();
-    for (let prop in this) {
+    for (var prop in this)
       result[prop] = deepCopy(this[prop]);
-    }
 
     return result;
   },
-
   isComplete() {
     return (!!this.incoming.hostname && !!this.incoming.port &&
          !!this.incoming.socketType && !!this.incoming.auth &&
          !!this.incoming.username &&
          (!!this.outgoing.existingServerKey ||
-          this.outgoing.useGlobalPreferredServer ||
           (!!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()
-AccountConfig.kSourceExchange = 4; // from Microsoft Exchange AutoDiscover
 
 
 /**
  * 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 @)
--- a/mail/components/accountcreation/content/createInBackend.js
+++ b/mail/components/accountcreation/content/createInBackend.js
@@ -1,31 +1,32 @@
 /* -*- 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/. */
 
-
-ChromeUtils.import("resource:///modules/MailServices.jsm");
-ChromeUtils.import("resource://gre/modules/Services.jsm");
-/* eslint-disable complexity */
-
 /**
  * Takes an |AccountConfig| JS object and creates that account in the
  * Thunderbird backend (which also writes it to prefs).
  *
- * @param {AccountConfig} config - The account to create
- * @return {nsIMsgAccount} - the newly created account
+ * @param config {AccountConfig} The account to create
+ *
+ * @return - the account created.
  */
+
+ChromeUtils.import("resource:///modules/MailServices.jsm");
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+/* eslint-disable complexity */
 function createAccountInBackend(config) {
   // incoming server
   let inServer = MailServices.accounts.createIncomingServer(
       config.incoming.username,
       config.incoming.hostname,
-      config.incoming.type);
+      sanitize.enum(config.incoming.type, ["pop3", "imap", "nntp"]));
   inServer.port = config.incoming.port;
   inServer.authMethod = config.incoming.auth;
   inServer.password = config.incoming.password;
   if (config.rememberPassword && config.incoming.password.length)
     rememberPassword(inServer, config.incoming.password);
 
   if (inServer.authMethod == Ci.nsMsgAuthMethod.OAuth2) {
     inServer.setCharValue("oauth2.scope", config.oauthSettings.scope);
@@ -248,25 +249,25 @@ function rememberPassword(server, passwo
  *     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,
-        incoming.type,
+        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,
-          incoming.type,
+          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.
--- a/mail/components/accountcreation/content/emailWizard.js
+++ b/mail/components/accountcreation/content/emailWizard.js
@@ -31,20 +31,17 @@ ChromeUtils.import("resource:///modules/
  * - 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,20}|\d{1,3}(?:\.\d{1,3}){3})(?::\d+)?$/i;
 
 if (typeof gEmailWizardLogger == "undefined") {
   ChromeUtils.import("resource:///modules/gloda/log4moz.js");
-  var gEmailWizardLogger = Log4Moz.getConfiguredLogger("mail.setup");
-  gEmailWizardLogger.level = Log4Moz.Level.Info;
-  gEmailWizardLogger.addAppender(new Log4Moz.ConsoleAppender(new Log4Moz.BasicFormatter())); // browser console
-  gEmailWizardLogger.addAppender(new Log4Moz.DumpAppender(new Log4Moz.BasicFormatter())); // stdout
+  var gEmailWizardLogger = Log4Moz.getConfiguredLogger("mail.wizard");
 }
 
 var gStringsBundle;
 var gMessengerBundle;
 var gBrandShortName;
 
 /**
 TODO for bug 549045:
@@ -111,22 +108,16 @@ function setText(id, value) {
     throw new NotReached("XUL element type not supported");
   }
 }
 
 function setLabelFromStringBundle(elementID, stringName) {
   e(elementID).label = gMessengerBundle.getString(stringName);
 }
 
-function removeChildNodes(el) {
-  while (el.hasChildNodes()) {
-    el.lastChild.remove();
-  }
-}
-
 function EmailConfigWizard() {
   this._init();
 }
 EmailConfigWizard.prototype =
 {
   _init() {
     gEmailWizardLogger.info("Initializing setup wizard");
     this._abortable = null;
@@ -294,44 +285,41 @@ EmailConfigWizard.prototype =
 
       _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("provisioner_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("provisioner_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");
-      _hide("provisioner_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");
@@ -351,48 +339,45 @@ EmailConfigWizard.prototype =
       _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;
-      _hide("provisioner_button");
       _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");
-      _hide("provisioner_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");
       }
-      _hide("provisioner_button");
     }
     window.sizeToContent();
   },
 
   /**
    * Start from beginning with possibly new email address.
    */
   onStartOver() {
@@ -537,90 +522,81 @@ EmailConfigWizard.prototype =
 
   // --------------
   // Detection step
 
   /**
    * Try to find an account configuration for this email address.
    * This is the function which runs the autoconfig.
    */
-  findConfig(domain, emailAddress) {
+  findConfig(domain, email) {
     gEmailWizardLogger.info("findConfig()");
     if (this._abortable) {
       this.onStop();
     }
     this.switchToMode("find-config");
-    this.startSpinner("looking_up_settings");
-
+    this.startSpinner("looking_up_settings_disk");
     var self = this;
-    var call = null;
-    var fetch = null;
-
-    var priority = this._abortable = new PriorityOrderAbortable(
-      function(config, call) { // success
+    this._abortable = fetchConfigFromDisk(domain,
+      function(config) { // success
         self._abortable = null;
-        self.removeStatusLines();
-        self.stopSpinner(call.foundMsg);
         self.foundConfig(config);
+        self.stopSpinner("found_settings_disk");
       },
-      function(e) { // all failed
-        self._abortable = null;
-        self.removeStatusLines();
+      function(e) { // fetchConfigFromDisk failed
         if (e instanceof CancelledException) {
           return;
         }
-
-        // guess config
-        let initialConfig = new AccountConfig();
-        self._prefillConfig(initialConfig);
-        self._guessConfig(domain, initialConfig);
+        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);
+                  });
+              });
+          });
       });
-    priority.addOneFinishedObserver(call => this.updateStatusLine(call));
-
-    try {
-      call = priority.addCall();
-      this.addStatusLine("looking_up_settings_disk", call);
-      call.foundMsg = "found_settings_disk";
-      fetch = fetchConfigFromDisk(domain,
-        call.successCallback(), call.errorCallback());
-      call.setAbortable(fetch);
-
-      call = priority.addCall();
-      this.addStatusLine("looking_up_settings_isp", call);
-      call.foundMsg = "found_settings_isp";
-      fetch = fetchConfigFromISP(domain, emailAddress,
-        call.successCallback(), call.errorCallback());
-      call.setAbortable(fetch);
-
-      call = priority.addCall();
-      this.addStatusLine("looking_up_settings_db", call);
-      call.foundMsg = "found_settings_db";
-      fetch = fetchConfigFromDB(domain,
-        call.successCallback(), call.errorCallback());
-      call.setAbortable(fetch);
-
-      call = priority.addCall();
-      this.addStatusLine("looking_up_settings_mx", call);
-      call.foundMsg = "found_settings_db";
-      fetch = fetchConfigForMX(domain,
-        call.successCallback(), call.errorCallback());
-      call.setAbortable(fetch);
-
-      call = priority.addCall();
-      this.addStatusLine("looking_up_settings_exchange", call);
-      call.foundMsg = "found_settings_exchange";
-      fetch = fetchConfigFromExchange(domain, emailAddress, self._password,
-        call.successCallback(), call.errorCallback());
-      call.setAbortable(fetch);
-
-    } catch (e) { // e.g. when entering an invalid domain like "c@c.-com"
-      this.showErrorMsg(e);
-      this.removeStatusLines();
-      this.onStop();
-    }
   },
 
   /**
    * Just a continuation of findConfig()
    */
   _guessConfig(domain, initialConfig) {
     this.startSpinner("looking_up_settings_guess");
     var self = this;
@@ -649,26 +625,29 @@ EmailConfigWizard.prototype =
   },
 
   /**
    * When findConfig() was successful, it calls this.
    * This displays the config to the user.
    */
   foundConfig(config) {
     gEmailWizardLogger.info("foundConfig()");
-    gEmailWizardLogger.info(debugObject(config, "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(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.
@@ -719,321 +698,142 @@ EmailConfigWizard.prototype =
   },
 
   showErrorStatus(actionStrName) {
     e("status_area").setAttribute("status", "error");
     gEmailWizardLogger.warn("status error " + actionStrName);
     this._showStatusTitle(actionStrName);
   },
 
-  showErrorMsg(errorMsg) {
-    gEmailWizardLogger.warn("error " + errorMsg);
-    e("status_area").setAttribute("status", "error");
-    e("status_msg").textContent = errorMsg;
-  },
-
   _showStatusTitle(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);
   },
 
-  // UI to show status updates in parallel
-
-  addStatusLine(msgID, call) {
-    _show("status-lines");
-    var statusLine = document.createElement("hbox");
-    e("status-lines").appendChild(statusLine);
-    statusLine.classList.add("status-line");
-    var statusDescr = document.createElement("description");
-    statusDescr.classList.add("status_msg");
-    statusLine.appendChild(statusDescr);
-    var statusImg = document.createElement("vbox");
-    statusImg.classList.add("status-img");
-    statusImg.setAttribute("pack", "start");
-    statusLine.appendChild(statusImg);
-    let msg = msgID;
-    try {
-      msg = gStringsBundle.getFormattedString(msgID, [gBrandShortName]);
-    } catch (e) {
-      console.error(e);
-    }
-    statusDescr.textContent = msg;
-    call.statusLine = statusLine;
-    statusLine.setAttribute("status", "loading");
-  },
-
-  updateStatusLine(call) {
-    console.log("update status line for call " + call.position);
-    let line = [...document.querySelectorAll("#status-lines > .status-line")]
-      .find(line => line == call.statusLine);
-    if (!line) {
-      return;
-    }
-    if (!call.finished) {
-      line.setAttribute("status", "loading");
-    } else if (!call.succeeded) {
-      line.setAttribute("status", "failed");
-    } else {
-      line.setAttribute("status", "succeeded");
-    }
-  },
-
-  removeStatusLines() {
-    removeChildNodes(e("status-lines"));
-    _hide("status-lines");
-  },
-
   // -----------
   // 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(config) {
     assert(config instanceof AccountConfig);
     this._currentConfig = config;
     var configFilledIn = this.getConcreteConfig();
 
-    // IMAP / POP3 server type radio buttons
-    let alternatives = config.incomingAlternatives.filter(alt =>
-        (alt.type == "imap" || alt.type == "pop3" || alt.type == "exchange") &&
-        alt.type != config.incoming.type
-      );
-    let alternative = alternatives[0];
-    if (alternative) {
-      _show("result_servertype");
-      _hide("result_select_imap");
-      _hide("result_select_pop3");
-      _hide("result_select_exchange");
-      _show("result_select_" + alternative.type);
-      _show("result_select_" + config.incoming.type);
-      e("result_select_" + alternative.type).configIncoming = alternative;
-      e("result_select_" + config.incoming.type).configIncoming =
-          config.incoming;
-      e("result_servertype").value = config.incoming.type;
-    } else {
-      _hide("result_servertype");
-    }
-
-    if (config.incoming.type == "exchange") {
-      _hide("result_hostnames");
-      _show("result_exchange");
-      _disable("create_button");
-      removeChildNodes(e("result_addon_install_rows"));
-      this.switchToMode("result");
-
-      let hostnameE = e("result_exchange_hostname");
-      _makeHostDisplayString(config.incoming, hostnameE);
-      hostnameE.querySelector(".ssl").hidden = true; // it's always SSL, so just clutter
-      hostnameE.querySelector(".protocolType").hidden = true; // already have a nicer label
-
-      (async () => {
-        for (let addon of config.addons) {
-          let installer = new AddonInstaller(addon);
-          addon.isInstalled = await installer.isInstalled();
-        }
-        let installedAddon = config.addons.find(addon => addon.isInstalled);
-        if (installedAddon) {
-          _hide("result_addon_intro");
-          _hide("result_addon_install");
-          _enable("create_button");
-          this.onCreate = () => { // TODO
-            this._currentConfig.incoming.type = installedAddon.useType.addonAccountType;
-            this.validateAndFinish();
-          };
-        } else {
-          _hide("status_area");
-          _show("result_addon_intro");
-          var msg = gStringsBundle.getString("addon-intro");
-          if (!config.incomingAlternatives.find(alt => (alt.type == "imap" || alt.type == "pop3"))) {
-            msg = gStringsBundle.getString("no-open-protocols") + " " + msg;
-          }
-          setText("result_addon_intro", msg);
-
-          let containerE = e("result_addon_install_rows");
-          for (let addon of config.addons) {
-            // Creates
-            // <row>
-            //   <image src="https://live.thunderbird.net/owl32.png" />
-            //   <label class="text-link" href="https://live.thunderbird.net/owl">
-            //     A third party addon that ...
-            //   </label>
-            //   <button
-            //     class="larger-button"
-            //     orient="vertical" crop="right"
-            //     label="Install"
-            //     oncommand="…" />
-            // </row>
-            let addonE = document.createElement("row");
-            let iconE = document.createElement("image");
-            let descrE = document.createElement("label"); // must be <label> to be clickable
-            let buttonE = document.createElement("button");
-            addonE.appendChild(iconE);
-            addonE.appendChild(descrE);
-            addonE.appendChild(buttonE);
-            containerE.appendChild(addonE);
-            addonE.setAttribute("align", "center");
-            iconE.classList.add("icon");
-            if (addon.icon32) {
-              iconE.setAttribute("src", addon.icon32);
-            }
-            descrE.classList.add("text-link");
-            descrE.setAttribute("href", addon.websiteURL);
-            descrE.textContent = addon.description;
-            buttonE.classList.add("larger-button");
-            buttonE.setAttribute("orient", "vertical");
-            buttonE.setAttribute("crop", "right");
-            buttonE.setAttribute("label", gStringsBundle.getString("addonInstallShortLabel"));
-            buttonE.setAttribute("oncommand", "gEmailConfigWizard.addonInstall(this.addon);");
-            buttonE.addon = addon;
-          }
-          _show("result_addon_install");
-          _disable("create_button");
-        }
-
-        window.sizeToContent();
-      })();
-      return;
-    }
-
-    _show("result_hostnames");
-    _hide("result_exchange");
-    _enable("create_button");
-
     var unknownString = gStringsBundle.getString("resultUnknown");
 
-    function _makeHostDisplayString(server, descrE) {
+    function _makeHostDisplayString(server, stringName) {
       let type = gStringsBundle.getString(sanitize.translate(server.type,
-          { imap: "resultIMAP", pop3: "resultPOP3", smtp: "resultSMTP", exchange: "resultExchange" }),
+          { imap: "resultIMAP", pop3: "resultPOP3", smtp: "resultSMTP" }),
           unknownString);
-      let domain = Services.eTLD.getBaseDomainFromHost(server.hostname);
-      let host = server.hostname.substr(0, server.hostname.length - domain.length);
-      let port = (isStandardPort(server.port) ? "" : ":" + server.port);
+      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.
-
-      function _addComponent(text, className) {
-        let textE = document.createElement("label");
-        textE.classList.add(className);
-        textE.textContent = text;
-        descrE.appendChild(textE);
-      }
-      removeChildNodes(descrE);
-      _addComponent(type, "protocolType");
-      _addComponent(host, "host-without-domain");
-      _addComponent(domain, "domain");
-      _addComponent(port, "port");
-      _addComponent(ssl, "ssl");
-      _addComponent(certStatus, "certStatus");
-
-      if (server.socketType != 2 && server.socketType != 3) { // not SSL/STARTTLS
-        descrE.querySelector(".ssl").classList.add("insecure");
-      }
-      if (server.badCert) {
-        descrE.querySelector(".certStatus").classList.add("insecure");
-      }
+      return gStringsBundle.getFormattedString(stringName,
+          [ type, host, ssl, certStatus ]);
     }
 
+    var incomingResult = unknownString;
     if (configFilledIn.incoming.hostname) {
-      _makeHostDisplayString(configFilledIn.incoming, e("result-incoming"));
+      incomingResult = _makeHostDisplayString(configFilledIn.incoming,
+          "resultIncoming");
     }
 
+    var outgoingResult = unknownString;
     if (!config.outgoing.existingServerKey) {
       if (configFilledIn.outgoing.hostname) {
-        _makeHostDisplayString(configFilledIn.outgoing, e("result-outgoing"));
+        outgoingResult = _makeHostDisplayString(configFilledIn.outgoing,
+            "resultOutgoing");
       }
     } else {
-      // setText() would confuse _makeHostDisplayString() when clearing the child nodes
-      e("result-outgoing").appendChild(document.createTextNode(
-        gStringsBundle.getString("resultOutgoingExisting")));
+      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.
    */
-  onResultServerTypeChanged() {
+  onResultIMAPOrPOP3() {
     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 = e("result_servertype").selectedItem.configIncoming;
+    config.incoming = radiogroup.selectedItem.configIncoming;
     // remove newly selected server from list of alternatives
-    config.incomingAlternatives = config.incomingAlternatives.filter(alt =>
-      alt != config.incoming);
+    config.incomingAlternatives = config.incomingAlternatives.filter(
+        function(e) { return e != config.incoming; });
     this.displayConfigResult(config);
   },
 
-  /**
-   * Install the addon
-   * Called when user clicks [Install] button.
-   *
-   * @param {AddonInfo} addon - @see AccountConfig.addons
-   */
-  async addonInstall(addon) {
-    _hide("result_addon_install");
-    _hide("result_addon_intro");
-    _disable("create_button");
-    _show("status_area");
-    this.startSpinner("addonInstallStarted");
-
-    try {
-      var installer = this._abortable = new AddonInstaller(addon);
-      await installer.install();
-
-      this._abortable = null;
-      this.stopSpinner("addonInstallSuccess");
-      _enable("create_button");
-
-      this._currentConfig.incoming.type = addon.useType.addonAccountType;
-      this.validateAndFinish();
-    } catch (e) {
-      this.showErrorMsg(e + "");
-      _show("result_addon_install");
-    }
-  },
-
-
   // ----------------
   // 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
@@ -1345,18 +1145,20 @@ EmailConfigWizard.prototype =
   /**
    * Sets the prefilled values of the port fields.
    * Filled statically with the standard ports for the given protocol,
    * plus "Auto".
    */
   fillPortDropdown(protocolType) {
     var menu = e(protocolType == "smtp" ? "outgoing_port" : "incoming_port");
 
-    // menulist.removeAllItems() is nice, but "nicely" clears the user value, too
-    removeChildNodes(menu.menupopup);
+    // 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
     }
   },
@@ -1719,39 +1521,35 @@ EmailConfigWizard.prototype =
         self._currentConfig.incoming.username = successfulConfig.incoming.username;
         self._currentConfig.outgoing.username = successfulConfig.outgoing.username;
 
         // We loaded dynamic client registration, fill this data back in to the
         // config set.
         if (successfulConfig.oauthSettings)
           self._currentConfig.oauthSettings = successfulConfig.oauthSettings;
 
-        self.finish(configFilledIn);
+        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(concreteConfig) {
+  finish() {
     gEmailWizardLogger.info("creating account in backend");
-    var account = createAccountInBackend(concreteConfig);
-
-    // Trigger first login, to get folder structure, show account, etc..
-    account.incomingServer.rootFolder.getNewMessages(null, null);
-
+    createAccountInBackend(this.getConcreteConfig());
     window.close();
   },
 };
 
 var gEmailConfigWizard = new EmailConfigWizard();
 
 function serverMatches(a, b) {
   return a.type == b.type &&
@@ -1760,21 +1558,18 @@ function serverMatches(a, b) {
          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
-_gStandardPorts.exchange = [ 443 ];
 var _gAllStandardPorts = _gStandardPorts.smtp
-    .concat(_gStandardPorts.imap)
-    .concat(_gStandardPorts.pop3)
-    .concat(_gStandardPorts.exchange);
+    .concat(_gStandardPorts.imap).concat(_gStandardPorts.pop3);
 
 function isStandardPort(port) {
   return _gAllStandardPorts.includes(port);
 }
 
 function getStandardPorts(protocolType) {
   return _gStandardPorts[protocolType];
 }
@@ -1828,17 +1623,17 @@ SecurityWarningDialog.prototype =
     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.addThisServer) {
+    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);
--- a/mail/components/accountcreation/content/emailWizard.xul
+++ b/mail/components/accountcreation/content/emailWizard.xul
@@ -48,18 +48,16 @@
           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/exchangeAutoDiscover.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();"/>
@@ -198,75 +196,55 @@
                     label="&rememberPassword.label;"
                     accesskey="&rememberPassword.accesskey;"
                     checked="true"/>
         </row>
       </rows>
     </grid>
     <spacer flex="1" />
 
-    <hbox id="status_area" flex="1">
+     <hbox id="status_area" flex="1">
       <vbox id="status_img_before" pack="start"/>
       <description id="status_msg">&#160;</description>
               <!-- Include 160 = nbsp, to make the element occupy the
                    full height, for at least one line. With a normal space,
                    it does not have sufficient height. -->
       <vbox id="status_img_after" pack="start"/>
     </hbox>
-    <vbox id="status-lines"/>
 
     <groupbox id="result_area" hidden="true">
-      <radiogroup id="result_servertype" orient="horizontal">
-        <radio id="result_select_imap" label="&imapLong.label;" value="imap"
-               oncommand="gEmailConfigWizard.onResultServerTypeChanged();"/>
-        <radio id="result_select_pop3" label="&pop3Long.label;" value="pop3"
-               oncommand="gEmailConfigWizard.onResultServerTypeChanged();"/>
-        <radio id="result_select_exchange" label="&exchange.label;" value="exchange"
-               oncommand="gEmailConfigWizard.onResultServerTypeChanged();"/>
+      <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 id="result_hostnames">
+      <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" class="result-host-info" disabled="true" flex="1"/>
+            <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" class="result-host-info" disabled="true" flex="1"/>
+            <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>
-      <vbox id="result_exchange" hidden="true">
-        <hbox id="result_exchange_hostname_container" align="center">
-          <label class="textbox-label" value="&exchange-hostname.label;"
-                 control="result_exchange_hostname"/>
-          <textbox id="result_exchange_hostname" class="result-host-info" disabled="true" flex="1"/>
-        </hbox>
-        <description id="result_addon_intro"/>
-        <grid id="result_addon_install">
-          <columns>
-            <column id="result_addon_install_column_icon" pack="start" align="center" />
-            <column id="result_addon_install_column_link" pack="start" align="center" />
-            <column id="result_addon_install_column_button" pack="start" align="center" />
-          </columns>
-          <rows id="result_addon_install_rows">
-          </rows>
-        </grid>
-      </vbox>
     </groupbox>
 
     <groupbox id="manual-edit_area" hidden="true">
       <grid>
         <columns>
           <column/><!-- row label, e.g. "incoming" -->
           <column/><!-- protocol, e.g. "IMAP" -->
           <column/><!-- hostname / username -->
deleted file mode 100644
--- a/mail/components/accountcreation/content/exchangeAutoDiscover.js
+++ /dev/null
@@ -1,411 +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/. */
-
-ChromeUtils.import("resource://gre/modules/Services.jsm");
-ChromeUtils.import("resource:///modules/JXON.js");
-ChromeUtils.defineModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
-/* eslint-disable complexity, no-lonely-if */
-
-/**
- * Tries to get a configuration from an MS Exchange server
- * using Microsoft AutoDiscover protocol.
- *
- * 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 {string} domain - The domain part of the user's email address
- * @param {string} emailAddress - The user's email address
- * @param {string} password - The user's password for that email address
- * @param {Function(config {AccountConfig})} successCallback - A callback that
- *         will be called when we could retrieve a configuration.
- *         The AccountConfig object will be passed in as first parameter.
- * @param {Function(ex)} errorCallback - 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 parameter will be an exception object or error string.
- */
-function fetchConfigFromExchange(domain, emailAddress, password,
-                                 successCallback, errorCallback) {
-  assert(typeof(successCallback) == "function");
-  assert(typeof(errorCallback) == "function");
-  if (!Services.prefs.getBoolPref(
-      "mailnews.auto_config.fetchFromExchange.enabled", true)) {
-    errorCallback("Exchange AutoDiscover disabled per user preference");
-    return new Abortable();
-  }
-
-  // <https://technet.microsoft.com/en-us/library/bb124251(v=exchg.160).aspx#Autodiscover%20services%20in%20Outlook>
-  // <https://docs.microsoft.com/en-us/previous-versions/office/developer/exchange-server-interoperability-guidance/hh352638(v%3Dexchg.140)>
-  let url1 = "https://" + sanitize.hostname(domain) +
-             "/autodiscover/autodiscover.xml";
-  let url2 = "https://autodiscover." + sanitize.hostname(domain) +
-             "/autodiscover/autodiscover.xml";
-  let url3 = "http://autodiscover." + sanitize.hostname(domain) +
-             "/autodiscover/autodiscover.xml"; // needed by email hosters
-  let body =
-    `<?xml version="1.0" encoding="utf-8"?>
-    <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
-      <Request>
-        <EMailAddress>${emailAddress}</EMailAddress>
-        <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
-      </Request>
-    </Autodiscover>`;
-  let callArgs = {
-    uploadBody: body,
-    post: true,
-    headers: {
-      // outlook.com needs this exact string, with space and lower case "utf".
-      // Compare bug 1454325 comment 15.
-      "Content-Type": "text/xml; charset=utf-8",
-    },
-    username: emailAddress,
-    password,
-    // url3 is HTTP (not HTTPS), so suppress password. Even MS spec demands so.
-    requireSecureAuth: true,
-    allowAuthPrompt: false,
-  };
-  let call;
-  let fetch;
-  let fetch3;
-
-  let successive = new SuccessiveAbortable();
-  let priority = new PriorityOrderAbortable(
-    function(xml, call) { // success
-      readAutoDiscoverResponse(xml, successive, password, function(config) {
-        successive.current = getAddonsList(config, successCallback, errorCallback);
-      }, errorCallback);
-    },
-    errorCallback); // all failed
-
-  call = priority.addCall();
-  fetch = new FetchHTTP(url1, callArgs,
-    call.successCallback(), call.errorCallback());
-  fetch.start();
-  call.setAbortable(fetch);
-
-  call = priority.addCall();
-  fetch = new FetchHTTP(url2, callArgs,
-    call.successCallback(), call.errorCallback());
-  fetch.start();
-  call.setAbortable(fetch);
-
-  call = priority.addCall();
-  fetch3 = new FetchHTTP(url3, callArgs,
-    call.successCallback(), call.errorCallback());
-  fetch3.start();
-  call.setAbortable(fetch3);
-
-  // url3 is an HTTP URL that will redirect to the real one, usually a HTTPS
-  // URL of the hoster. XMLHttpRequest unfortunately loses the call
-  // parameters, drops the auth, drops the body, and turns POST into GET,
-  // which cause the call to fail, but FetchHTTP fixes this and automatically
-  // repeats the call. We need that, otherwise the whole AutoDiscover
-  // mechanism doesn't work.
-
-  successive.current = priority;
-  return successive;
-}
-
-var gLoopCounter = 0;
-
-/**
- * @param {JXON} xml - The Exchange server AutoDiscover response
- * @param {Function(config {AccountConfig})} successCallback - @see accountConfig.js
- */
-function readAutoDiscoverResponse(autoDiscoverXML,
-  successive, password, successCallback, errorCallback) {
-  assert(successive instanceof SuccessiveAbortable);
-  assert(typeof(successCallback) == "function");
-  assert(typeof(errorCallback) == "function");
-
-  // redirect to other email address
-  if ("Action" in autoDiscoverXML.Autodiscover.Response &&
-      "Redirect" in autoDiscoverXML.Autodiscover.Response.Action) {
-    // <https://docs.microsoft.com/en-us/previous-versions/office/developer/exchange-server-interoperability-guidance/hh352638(v%3Dexchg.140)>
-    let redirectEmailAddress = sanitize.emailAddress(
-        autoDiscoverXML.Autodiscover.Response.Action.Redirect);
-    let domain = redirectEmailAddress.split("@").pop();
-    if (++gLoopCounter > 2) {
-      throw new Exception("Too many redirects in XML response");
-    }
-    successive.current = fetchConfigFromExchange(domain,
-      redirectEmailAddress, password,
-      successCallback, errorCallback);
-  }
-
-  let config = readAutoDiscoverXML(autoDiscoverXML);
-
-  if (config.isComplete()) {
-    successCallback(config);
-  } else {
-    errorCallback(new Exception("No valid configs found in AutoDiscover XML"));
-  }
-}
-
-/**
- * @param {JXON} xml - The Exchange server AutoDiscover response
- * @returns {AccountConfig} - @see accountConfig.js
- *
- * @see <https://www.msxfaq.de/exchange/autodiscover/autodiscover_xml.htm>
- */
-function readAutoDiscoverXML(autoDiscoverXML) {
-  if (typeof(autoDiscoverXML) != "object" ||
-      !("Autodiscover" in autoDiscoverXML) ||
-      !("Response" in autoDiscoverXML.Autodiscover) ||
-      !("Account" in autoDiscoverXML.Autodiscover.Response) ||
-      !("Protocol" in autoDiscoverXML.Autodiscover.Response.Account)) {
-    let stringBundle = getStringBundle(
-      "chrome://messenger/locale/accountCreationModel.properties");
-    throw new Exception(stringBundle.GetStringFromName("no_autodiscover.error"));
-  }
-  var xml = autoDiscoverXML.Autodiscover.Response.Account;
-
-  function array_or_undef(value) {
-    return value === undefined ? [] : value;
-  }
-
-  var config = new AccountConfig();
-  config.source = AccountConfig.kSourceExchange;
-  config.incoming.username = "%EMAILADDRESS%";
-  config.incoming.socketType = 2; // only https supported
-  config.incoming.port = 443;
-  config.incoming.auth = Ci.nsMsgAuthMethod.passwordCleartext;
-  config.incoming.authAlternatives = [ Ci.nsMsgAuthMethod.OAuth2 ];
-  config.oauthSettings = {};
-  config.outgoing.addThisServer = false;
-  config.outgoing.useGlobalPreferredServer = true;
-
-  for (let protocolX of array_or_undef(xml.$Protocol)) {
-    try {
-      let type = sanitize.enum(protocolX.Type,
-                               ["WEB", "EXHTTP", "EXCH", "EXPR", "POP3", "IMAP", "SMTP"],
-                               "unknown");
-      if (type == "WEB") {
-        let urlsX;
-        if ("External" in protocolX) {
-          urlsX = protocolX.External;
-        } else if ("Internal" in protocolX) {
-          urlsX = protocolX.Internal;
-        }
-        if (urlsX) {
-          config.incoming.owaURL = sanitize.url(urlsX.OWAUrl.value);
-          if (!config.incoming.ewsURL &&
-              "Protocol" in urlsX &&
-              "ASUrl" in urlsX.Protocol) {
-            config.incoming.ewsURL = sanitize.url(urlsX.Protocol.ASUrl);
-          }
-          config.incoming.type = "exchange";
-          let parsedURL = new URL(config.incoming.owaURL);
-          config.incoming.hostname = sanitize.hostname(parsedURL.hostname);
-          if (parsedURL.port) {
-            config.incoming.port =  sanitize.integer(parsedURL.port);
-          }
-        }
-      } else if (type == "EXHTTP" || type == "EXCH") {
-        config.incoming.ewsURL = sanitize.url(protocolX.EwsUrl);
-        if (!config.incoming.ewsURL) {
-          config.incoming.ewsURL = sanitize.url(protocolX.ASUrl);
-        }
-        config.incoming.type = "exchange";
-        let parsedURL = new URL(config.incoming.ewsURL);
-        config.incoming.hostname = sanitize.hostname(parsedURL.hostname);
-        if (parsedURL.port) {
-          config.incoming.port =  sanitize.integer(parsedURL.port);
-        }
-      } else if (type == "POP3" || type == "IMAP" || type == "SMTP") {
-        let server;
-        if (type == "SMTP") {
-          server = config.createNewOutgoing();
-        } else {
-          server = config.createNewIncoming();
-        }
-
-        server.type = sanitize.translate(type, { POP3: "pop3", IMAP: "imap", SMTP: "smtp" });
-        server.hostname = sanitize.hostname(protocolX.Server);
-        server.port = sanitize.integer(protocolX.Port);
-        server.socketType = 1; // plain
-        if ("SSL" in protocolX &&
-            sanitize.enum(protocolX.SSL, ["on", "off"]) == "on") {
-          // SSL is too unspecific. Do they mean STARTTLS or normal TLS?
-          // For now, assume normal TLS, unless it's a standard plain port.
-          switch (server.port) {
-            case 143: // IMAP standard
-            case 110: // POP3 standard
-            case 25:  // SMTP standard
-            case 587: // SMTP standard
-              server.socketType = 3; // STARTTLS
-              break;
-            case 993: // IMAP SSL
-            case 995: // POP3 SSL
-            case 465: // SMTP SSL
-            default: // if non-standard port, assume normal TLS, not STARTTLS
-              server.socketType = 2; // normal TLS
-              break;
-          }
-        }
-        if ("SPA" in protocolX &&
-            sanitize.enum(protocolX.SPA, ["on", "off"]) == "on") {
-          // Secure Password Authentication = NTLM or GSSAPI/Kerberos
-          server.auth = 8; // secure (not really, but this is MS...)
-        }
-        if ("LoginName" in protocolX) {
-          server.username = sanitize.nonemptystring(protocolX.LoginName);
-        } else {
-          server.username = "%EMAILADDRESS%";
-        }
-
-        if (type == "SMTP") {
-          if (!config.outgoing.hostname) {
-            config.outgoing = server;
-          } else {
-            config.outgoingAlternatives.push(server);
-          }
-        } else {
-          if (!config.incoming.hostname) {
-            config.incoming = server;
-          } else {
-            config.incomingAlternatives.push(server);
-          }
-        }
-      }
-
-      // else unknown or unsupported protocol
-
-    } catch (e) { logException(e); }
-  }
-
-  // OAuth2 settings, so that createInBackend() doesn't bail out
-  if (config.incoming.owaURL || config.incoming.ewsURL) {
-    config.oauthSettings = {
-      issuer: config.incoming.hostname,
-      scope: config.incoming.owaURL || config.incoming.ewsURL,
-    };
-  }
-
-  return config;
-}
-
-/**
- * Ask server which addons can handle this config.
- * @param {AccountConfig} config
- * @param {Function(config {AccountConfig})} successCallback
- * @returns {Abortable}
- */
-function getAddonsList(config, successCallback, errorCallback) {
-  let url = Services.prefs.getCharPref("mailnews.auto_config.addons_url");
-  if (!url) {
-    errorCallback(new Exception("no URL for addons list configured"));
-    return new Abortable();
-  }
-  let fetch = new FetchHTTP(url, { allowCache: true }, function(json) {
-    let addons = readAddonsJSON(json);
-    addons = addons.filter(addon => {
-      // Find types matching the current config.
-      // Pick the first in the list as the preferred one and
-      // tell the UI to use that one.
-      addon.useType = addon.supportedTypes.find(type =>
-        config.incoming.owaURL && type.protocolType == "owa" ||
-        config.incoming.ewsURL && type.protocolType == "ews" ||
-        config.incoming.easURL && type.protocolType == "eas");
-      return !!addon.useType;
-    });
-    if (addons.length == 0) {
-      errorCallback(new Exception("Config found, but no addons known to handle the config"));
-      return;
-    }
-    config.addons = addons;
-    successCallback(config);
-  }, errorCallback);
-  fetch.start();
-  return fetch;
-}
-
-/**
- * This reads the addons list JSON and makes security validations,
- * e.g. that the URLs are not chrome: URLs, which could lead to exploits.
- * It also chooses the right language etc..
- *
- * @param {JSON} json - the addons.json file contents
- * @returns {Array of AddonInfo} - @see AccountConfig.addons
- *
- * accountTypes are listed in order of decreasing preference.
- * Languages are 2-letter codes. If a language is not available,
- * the first name or description will be used.
- *
- * Parse e.g.
-[
-  {
-    "id": "owl@beonex.com",
-    "name": {
-      "en": "Owl",
-      "de": "Eule"
-    },
-    "description": {
-      "en": "Owl is a paid third-party addon that allows you to access your email account on Exchange servers. See the website for prices.",
-      "de": "Eule ist eine Erweiterung von einem Drittanbieter, die Ihnen erlaubt, Exchange-Server zu benutzen. Sie ist kostenpflichtig. Die Preise finden Sie auf der Website."
-    },
-    "minVersion": "0.2",
-    "xpiURL": "http://www.beonex.com/owl/latest.xpi",
-    "websiteURL": "http://www.beonex.com/owl/",
-    "icon32": "http://www.beonex.com/owl/owl-32.png",
-    "accountTypes": [
-      {
-        "generalType": "exchange",
-        "protocolType": "owa",
-        "addonAccountType": "owl-owa"
-      },
-      {
-        "generalType": "exchange",
-        "protocolType": "eas",
-        "addonAccountType": "owl-eas"
-      }
-    ]
-  }
-]
- */
-function readAddonsJSON(json) {
-  let addons = [];
-  function ensureArray(value) {
-    return Array.isArray(value) ? value : [];
-  }
-  let xulLocale = Services.locale.requestedLocale;
-  let locale = xulLocale ? xulLocale.substring(0, 5) : "default";
-  for (let addonJSON of ensureArray(json)) {
-    try {
-      let addon = {
-        id: addonJSON.id,
-        minVersion: addonJSON.minVersion,
-        xpiURL: sanitize.url(addonJSON.xpiURL),
-        websiteURL: sanitize.url(addonJSON.websiteURL),
-        icon32: addonJSON.icon32 ? sanitize.url(addonJSON.icon32) : null,
-        supportedTypes: [],
-      };
-      assert(new URL(addon.xpiURL).protocol == "https:", "XPI download URL needs to be https");
-      addon.name = (locale in addonJSON.name) ?
-        addonJSON.name[locale] : addonJSON.name[0];
-      addon.description = (locale in addonJSON.description) ?
-        addonJSON.description[locale] : addonJSON.description[0];
-      for (let typeJSON of ensureArray(addonJSON.accountTypes)) {
-        try {
-          addon.supportedTypes.push({
-            generalType: sanitize.alphanumdash(typeJSON.generalType),
-            protocolType: sanitize.alphanumdash(typeJSON.protocolType),
-            addonAccountType: sanitize.alphanumdash(typeJSON.addonAccountType),
-          });
-        } catch (e) {
-          ddump(e);
-        }
-      }
-      addons.push(addon);
-    } catch (e) {
-      ddump(e);
-    }
-  }
-  return addons;
-}
--- a/mail/components/accountcreation/content/fetchConfig.js
+++ b/mail/components/accountcreation/content/fetchConfig.js
@@ -1,32 +1,33 @@
 /* -*- 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/. */
 
-ChromeUtils.import("resource:///modules/MailServices.jsm");
-ChromeUtils.import("resource://gre/modules/Services.jsm");
-ChromeUtils.import("resource:///modules/JXON.js");
-
 /**
  * Tries to find a configuration for this ISP on the local harddisk, in the
  * application install directory's "isp" subdirectory.
  * Params @see fetchConfigFromISP()
  */
+
+ChromeUtils.import("resource:///modules/MailServices.jsm");
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+ChromeUtils.import("resource:///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");
 
       if (!configLocation.exists() || !configLocation.isReadable()) {
-        errorCallback(new Exception("local file not found"));
+        errorCallback("local file not found");
         return;
       }
       var contents =
         readURLasUTF8(Services.io.newFileURI(configLocation));
       let domParser = new DOMParser();
       successCallback(readFromXML(JXON.build(
         domParser.parseFromString(contents, "text/xml"))));
     } catch (e) { errorCallback(e); }
@@ -52,80 +53,88 @@ function fetchConfigFromDisk(domain, suc
  *         for this domain at this location),
  *         so do not unconditionally show this to the user.
  *         The first parameter will be an exception object or error string.
  */
 function fetchConfigFromISP(domain, emailAddress, successCallback,
                             errorCallback) {
   if (!Services.prefs.getBoolPref(
       "mailnews.auto_config.fetchFromISP.enabled")) {
-    errorCallback(new Exception("ISP fetch disabled per user preference"));
-    return new Abortable();
+    errorCallback("ISP fetch disabled per user preference");
+    return null;
   }
 
   let url1 = "http://autoconfig." + sanitize.hostname(domain) +
              "/mail/config-v1.1.xml";
   // .well-known/ <http://tools.ietf.org/html/draft-nottingham-site-meta-04>
   let url2 = "http://" + sanitize.hostname(domain) +
              "/.well-known/autoconfig/mail/config-v1.1.xml";
-  let callArgs = {
-    urlArgs: {
-      emailaddress: emailAddress,
-    },
-  };
+  let sucAbortable = new SuccessiveAbortable();
+  var time = Date.now();
+  var urlArgs = { emailaddress: emailAddress };
   if (!Services.prefs.getBoolPref(
       "mailnews.auto_config.fetchFromISP.sendEmailAddress")) {
-    delete callArgs.urlArgs.emailaddress;
+    delete urlArgs.emailaddress;
   }
-  let call;
-  let fetch;
-
-  let priority = new PriorityOrderAbortable(
-      xml => successCallback(readFromXML(xml)),
-      errorCallback);
+  let fetch1 = new FetchHTTP(url1, urlArgs, false,
+    function(result) {
+      successCallback(readFromXML(result));
+    },
+    function(e1) { // fetch1 failed
+      ddump("fetchisp 1 <" + url1 + "> took " + (Date.now() - time) +
+          "ms and failed with " + e1);
+      time = Date.now();
+      if (e1 instanceof CancelledException) {
+        errorCallback(e1);
+        return;
+      }
 
-  call = priority.addCall();
-  fetch = new FetchHTTP(url1, callArgs,
-      call.successCallback(), call.errorCallback());
-  call.setAbortable(fetch);
-  fetch.start();
-
-  call = priority.addCall();
-  fetch = new FetchHTTP(url2, callArgs,
-      call.successCallback(), call.errorCallback());
-  call.setAbortable(fetch);
-  fetch.start();
-
-  return priority;
+      let fetch2 = new FetchHTTP(url2, urlArgs, false,
+        function(result) {
+          successCallback(readFromXML(result));
+        },
+        function(e2) {
+          ddump("fetchisp 2 <" + url2 + "> took " + (Date.now() - time) +
+              "ms and failed with " + e2);
+          // return the error for the primary call,
+          // unless the fetch was cancelled
+          errorCallback(e2 instanceof CancelledException ? e2 : e1);
+        });
+      sucAbortable.current = fetch2;
+      fetch2.start();
+    });
+  sucAbortable.current = fetch1;
+  fetch1.start();
+  return sucAbortable;
 }
 
 /**
  * Tries to get a configuration for this ISP from a central database at
  * Mozilla servers.
  * Params @see fetchConfigFromISP()
  */
+
 function fetchConfigFromDB(domain, successCallback, errorCallback) {
   let url = Services.prefs.getCharPref("mailnews.auto_config_url");
-  if (!url) {
-    errorCallback(new Exception("no URL for ISP DB configured"));
-    return new Abortable();
-  }
   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);
 
-  let fetch = new FetchHTTP(url, {},
-    function(result) {
-      successCallback(readFromXML(result));
-    },
-    errorCallback);
+  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
  * receiving mail for this domain. Then it takes the domain of that
  * server, and does another lookup (in ISPDB and possible at ISP autoconfig
@@ -152,17 +161,17 @@ function fetchConfigForMX(domain, succes
   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(new Exception("MX lookup would be no different from domain"));
+        errorCallback("MX lookup would be no different from domain");
         return;
       }
       sucAbortable.current = fetchConfigFromDB(sld, successCallback,
                                                errorCallback);
     },
     errorCallback);
   return sucAbortable;
 }
@@ -188,32 +197,30 @@ function fetchConfigForMX(domain, succes
  *   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(new Exception("no URL for MX service configured"));
-    return new Abortable();
-  }
+  if (!url)
+    errorCallback("no URL for MX service configured");
   url += domain;
 
-  let fetch = new FetchHTTP(url, {},
+  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(new Exception("no MX found"));
+        errorCallback("no MX found");
         return;
       }
       successCallback(first);
     },
     errorCallback);
   fetch.start();
   return fetch;
 }
--- a/mail/components/accountcreation/content/fetchhttp.js
+++ b/mail/components/accountcreation/content/fetchhttp.js
@@ -15,241 +15,139 @@
  * but not for bigger file downloads.
  */
 
 ChromeUtils.import("resource:///modules/JXON.js");
 
 /**
  * Set up a fetch.
  *
- * @param {string} url - URL of the server function.
+ * @param url {String}   URL of the server function.
  *    ATTENTION: The caller needs to make sure that the URL is secure to call.
- * @param {Object} args - Additional parameters as properties, see below
+ * @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 {Function({string} result)} successCallback
+ * @param successCallback {Function(result {String})}
  *   Called when the server call worked (no errors).
  *   |result| will contain the body of the HTTP response, as string.
- * @param {Function(ex)} errorCallback
+ * @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
- *
- * The following optional parameters are supported as properties of the |args| object:
- *
- * @param {Object, associative array} urlArgs - 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 {Object, associative array} headers - HTTP headers to be added
- *   to the HTTP request.
- *   { foo: "blub blub" } will add HTTP header "Foo: Blub blub".
- *   The values will be passed verbatim.
- * @param {boolean} post - 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.
- *   Default is GET.
- * @param {Object, associative array} bodyFormArgs - Like urlArgs,
+ */
+/* 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 {Object} uploadBody - Arbitrary object, which to use as
+ * @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 JXON is supported
+ *   Only supported object types, currently only E4X is supported
  *   (sending XML).
  *   Usually, you have nothing to upload, so just pass |null|.
- *   Only supported object types, currently supported:
- *   JXON -> sending XML
- *   JS object -> sending JSON
- *   string -> sending text/plain
- *   If you want to override the body mimetype, set header Content-Type below.
- *   Usually, you have nothing to upload, so just leave it at |null|.
- *   Default |null|.
- * @param {boolean} allowCache (default true)
- * @param {string} username (default null = no authentication)
- * @param {string} password (default null = no authentication)
- * @param {boolean} allowAuthPrompt (default true)
- * @param {boolean} requireSecureAuth (default false)
- *   Ignore the username and password unless we are using https:
- *   This also applies to both https: to http: and http: to https: redirects.
  */
-function FetchHTTP(url, args, successCallback, errorCallback) {
+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 (!args) {
-    args = {};
-  }
-  if (!args.urlArgs) {
-    args.urlArgs = {};
-  }
-  if (!args.headers) {
-    args.headers = {};
-  }
+  if (!urlArgs)
+    urlArgs = {};
 
-  this._args = args;
-  this._args.post = sanitize.boolean(args.post || false); // default false
-  this._args.allowCache = "allowCache" in args ? sanitize.boolean(args.allowCache) : true; // default true
-  this._args.allowAuthPrompt = sanitize.boolean(args.allowAuthPrompt || false); // default false
-  this._args.requireSecureAuth = sanitize.boolean(args.requireSecureAuth || false); // default false
+  this._urlArgs = urlArgs;
+  this._post = sanitize.boolean(post);
   this._successCallback = successCallback;
   this._errorCallback = errorCallback;
-  this._logger = Log4Moz.getConfiguredLogger("mail.setup");
-  this._logger.info("Requesting <" + url + ">");
 }
 FetchHTTP.prototype =
 {
   __proto__: Abortable.prototype,
   _url: null, // URL as passed to ctor, without arguments
-  _args: null,
+  _urlArgs: null,
+  _post: null,
   _successCallback: null,
   _errorCallback: null,
   _request: null, // the XMLHttpRequest object
   result: null,
 
   start() {
-    let url = this._url;
-    for (let name in this._args.urlArgs) {
+    var url = this._url;
+    for (var name in this._urlArgs) {
       url += (!url.includes("?") ? "?" : "&") +
-             name + "=" + encodeURIComponent(this._args.urlArgs[name]);
+              name + "=" + encodeURIComponent(this._urlArgs[name]);
     }
     this._request = new XMLHttpRequest();
     let request = this._request;
-    request.mozBackgroundRequest = !this._args.allowAuthPrompt;
-    let username = null, password = null;
-    if (url.startsWith("https:") || !this._args.requireSecureAuth) {
-      username = this._args.username;
-      password = this._args.password;
-    }
-    request.open(this._args.post ? "POST" : "GET", url, true, username, password);
+    request.open(this._post ? "POST" : "GET", url);
     request.channel.loadGroup = null;
-    request.timeout = 5000; // 5 seconds
     // 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"); }
 
-    if (!this._args.allowCache) {
-      // Disable Mozilla HTTP cache
-      request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
-    }
-
-    // body
-    let mimetype = null;
-    let body = this._args.uploadBody;
-    if (typeof(body) == "object" && "nodeType" in body) {
-      // XML
-      mimetype = "text/xml; charset=UTF-8";
-      body = new XMLSerializer().serializeToString(body);
-    } else if (typeof(body) == "object") {
-      // JSON
-      mimetype = "text/json; charset=UTF-8";
-      body = JSON.stringify(body);
-    } else if (typeof(body) == "string") {
-      // Plaintext
-      // You can override the mimetype with { headers: {"Content-Type" : "text/foo" } }
-      mimetype = "text/plain; charset=UTF-8";
-      // body already set above
-    } else if (this._args.bodyFormArgs) {
-      mimetype = "application/x-www-form-urlencoded; charset=UTF-8";
-      body = "";
-      for (let name in this._args.bodyFormArgs) {
-        body += (body ? "&" : "") + name + "=" +
-            encodeURIComponent(this._args.bodyFormArgs[name]);
-      }
-    }
-    if (body) {
-      this._logger.info("with body:\n" + body);
-    }
-
-    // Headers
-    if (mimetype && !("Content-Type" in this._args.headers)) {
-      request.setRequestHeader("Content-Type", mimetype);
-    }
-    if (username && password) {
-      // workaround, because open(..., username, password) does not work.
-      request.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password));
-    }
-    for (let name in this._args.headers) {
-      request.setRequestHeader(name, this._args.headers[name]);
-      if (name == "Cookie") {
-        // Websites are not allowed to set this, but chrome is.
-        // Nevertheless, the cookie lib later overwrites our header.
-        // request.channel.setCookie(this._args.headers[name]); -- crashes
-        // So, deactivate that Firefox cookie lib.
-        request.channel.loadFlags |= Ci.nsIRequest.LOAD_ANONYMOUS;
-      }
-    }
-    this._logger.info(debugObject(this._args, "args"));
-
     var me = this;
     request.onload = function() { me._response(true); };
     request.onerror = function() { me._response(false); };
-    request.ontimeout = function() { me._response(false); };
-    request.send(body);
-    // Store the original stack so we can use it if there is an exception
-    this._callStack = Error().stack;
+    request.send(null);
   },
   _response(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") {
-          // XML
           this.result = JXON.build(this._request.responseXML);
-        } else if (mimetype == "text/json" ||
-                   mimetype == "application/json") {
-          // JSON
-          this.result = JSON.parse(this._request.responseText);
         } else {
-          // Plaintext (fallback)
           // 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 if (this._args.username &&
-               this._request.responseURL.replace(/\/\/.*@/, "//") != this._url &&
-               this._request.responseURL.startsWith(this._args.requireSecureAuth ? "https" : "http") &&
-               !this._isRetry) {
-      // Redirects lack auth, see <https://stackoverflow.com/a/28411170>
-      this._logger.info("Call to <" + this._url + "> was redirected to <" + this._request.responseURL + ">, and failed. Re-trying the new URL with authentication again.");
-      this._url = this._request.responseURL;
-      this._isRetry = true;
-      this.start();
-      return;
     } else {
       success = false;
       try {
         errorCode = this._request.status;
         errorStr = this._request.statusText;
       } catch (e) {
         // If we can't resolve the hostname in DNS etc., .statusText throws
         errorCode = -2;
@@ -261,33 +159,30 @@ FetchHTTP.prototype =
     }
 
     // Callbacks
     if (success) {
       try {
         this._successCallback(this.result);
       } catch (e) {
         logException(e);
-        e.stack = this._callStack;
         this._error(e);
       }
     } else if (exStored) {
       this._error(exStored);
     } else {
-      // Put the caller's stack into the exception
-      let e = new ServerException(errorStr, errorCode, this._url);
-      e.stack = this._callStack;
-      this._error(e);
+      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);
     }
@@ -341,8 +236,9 @@ UserCancelledException.prototype.constru
 
 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;
+
--- a/mail/components/accountcreation/content/guessConfig.js
+++ b/mail/components/accountcreation/content/guessConfig.js
@@ -57,31 +57,27 @@ function guessConfig(domain, progressCal
                      resultConfig, which) {
   assert(typeof(progressCallback) == "function", "need progressCallback");
   assert(typeof(successCallback) == "function", "need successCallback");
   assert(typeof(errorCallback) == "function", "need errorCallback");
 
   // Servers that we know enough that they support OAuth2 do not need guessing.
   if (resultConfig.incoming.auth == Ci.nsMsgAuthMethod.OAuth2) {
     successCallback(resultConfig);
-    return new Abortable();
+    return null;
   }
 
   if (!resultConfig)
     resultConfig = new AccountConfig();
   resultConfig.source = AccountConfig.kSourceGuess;
 
-  if (!which) {
-    which = "both";
-  }
-
   if (!Services.prefs.getBoolPref(
       "mailnews.auto_config.guess.enabled")) {
     errorCallback("Guessing config disabled per user preference");
-    return new Abortable();
+    return null;
   }
 
   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");
@@ -104,17 +100,17 @@ function guessConfig(domain, progressCal
       hostname: "mail." + domain,
       username: resultConfig.identity.emailAddress,
       type: "pop3",
       port: 110,
       socketType: 3,
       auth: Ci.nsMsgAuthMethod.passwordCleartext,
     });
     successCallback(resultConfig);
-    return new Abortable();
+    return null;
   }
   var progress = function(thisTry) {
     progressCallback(protocolToString(thisTry.protocol), thisTry.hostname,
                      thisTry.port, sslConvertToSocketType(thisTry.ssl), false,
                      resultConfig);
   };
 
   var updateConfig = function(config) {
@@ -147,17 +143,17 @@ function guessConfig(domain, progressCal
         try {
           errorCallback(e);
         } catch (e) { errorInCallback(e); }
       }
 
     }
   };
 
-  var logger = Log4Moz.getConfiguredLogger("mail.setup");
+  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
--- a/mail/components/accountcreation/content/readFromXML.js
+++ b/mail/components/accountcreation/content/readFromXML.js
@@ -1,30 +1,30 @@
 /* -*- 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/. */
 
-ChromeUtils.import("resource:///modules/hostnameUtils.jsm");
-/* eslint-disable complexity */
-
 /**
  * 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
  */
+ChromeUtils.import("resource:///modules/hostnameUtils.jsm");
+
+/* eslint-disable complexity */
 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)) {
--- a/mail/components/accountcreation/content/sanitizeDatatypes.js
+++ b/mail/components/accountcreation/content/sanitizeDatatypes.js
@@ -100,31 +100,18 @@ var sanitize =
 
     return str.toLowerCase();
   },
   /**
    * A non-chrome URL that's safe to request.
    */
   url(unchecked) {
     var str = this.string(unchecked);
-
-    // DANGER ZONE: data:text/javascript or data:text/html can contain
-    // JavaScript code, run in the caller's security context, and might allow
-    // arbitrary code execution, so these must be prevented at all costs.
-    // PNG and JPEG data: URLs are fine.  But SVG is again dangerous,
-    // it can contain javascript, so it would create a critical security hole.
-    // Talk to BenB or bz before relaxing *any* of the checks in this function.
-    if (str.startsWith("data:image/png;") ||
-        str.startsWith("data:image/jpeg;")) {
-      return new URL(str).href;
-    }
-
-    if (!str.startsWith("http:") && !str.startsWith("https:")) {
+    if (!str.startsWith("http") && !str.startsWith("https"))
       throw new MalformedException("url_scheme.error", unchecked);
-    }
 
     var uri;
     try {
       uri = Services.io.newURI(str);
       uri = uri.QueryInterface(Ci.nsIURL);
     } catch (e) {
       throw new MalformedException("url_parsing.error", unchecked);
     }
--- a/mail/components/accountcreation/content/util.js
+++ b/mail/components/accountcreation/content/util.js
@@ -3,53 +3,49 @@
  * 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
  */
 
 ChromeUtils.import("resource:///modules/errUtils.js");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
-/* eslint-disable spaced-comment */
-
-
-/////////////////////////////////////////
-// Low level, basic functions
 
 function assert(test, errorMsg) {
   if (!test)
     throw new NotReached(errorMsg ? errorMsg :
           "Programming bug. Assertion failed, see log.");
 }
 
 function makeCallback(obj, func) {
   return func.bind(obj);
 }
 
+
 /**
  * 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.
- *
- * @see |TimeoutAbortable|
  */
 function runAsync(func) {
-  return setTimeout(func, 0);
+  setTimeout(func, 0);
 }
 
+
 /**
  * @param uriStr {String}
  * @result {nsIURI}
  */
 function makeNSIURI(uriStr) {
   return Services.io.newURI(uriStr);
 }
 
+
 /**
  * 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");
@@ -109,19 +105,16 @@ function getStringBundle(bundleURI) {
     return Services.strings.createBundle(bundleURI);
   } catch (e) {
     throw new Exception("Failed to get stringbundle URI <" + bundleURI +
                         ">. Error: " + e);
   }
 }
 
 
-/////////////////////////////////////////
-// Exception
-
 function Exception(msg) {
   this._message = msg;
   this.stack = Components.stack.formattedStack;
 }
 Exception.prototype =
 {
   get message() {
     return this._message;
@@ -134,426 +127,75 @@ Exception.prototype =
 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;
 
-
-/////////////////////////////////////////
-// Abortable
-
 /**
  * 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(e) {
+  cancel() {
   },
 };
 
-function CancelledException(msg) {
-  Exception.call(this, msg);
-}
-CancelledException.prototype = Object.create(Exception.prototype);
-CancelledException.prototype.constructor = CancelledException;
-
 /**
  * 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); // call super constructor
+  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); // call super constructor
+  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.
- */
+// 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;
-  },
+  get current() { return this._current; },
   set current(abortable) {
     assert(abortable instanceof Abortable || abortable == null,
         "need an Abortable object (or null)");
     this._current = abortable;
   },
-  cancel(e) {
-    if (this._current) {
-      this._current.cancel(e);
-    }
-  },
-};
-
-/**
- * Allows you to make several network calls in parallel.
- */
-function ParallelAbortable() {
-  Abortable.call(this); // call super constructor
-  // { Array of ParallelCall }
-  this._calls = [];
-  // { Array of Function }
-  this._finishedObservers = [];
-}
-ParallelAbortable.prototype = {
-  __proto__: Abortable.prototype,
-  /**
-   * @returns {Array of ParallelCall}
-   */
-  get results() {
-    return this._calls;
-  },
-  /**
-   * @returns {ParallelCall}
-   */
-  addCall() {
-    let call = new ParallelCall(this);
-    call.position = this._calls.length;
-    this._calls.push(call);
-    return call;
-  },
-  /**
-   * Observers will be called once one of the functions
-   * finishes, i.e. returns successfully or fails.
-   * @param {Function({ParallelCall} call)} func
-   */
-  addOneFinishedObserver(func) {
-    assert(typeof(func) == "function");
-    this._finishedObservers.push(func);
-  },
-  /**
-   * Will be called once *all* of the functions finished,
-   * It gives you a list of all functions that succeeded or failed,
-   * respectively.
-   * @param {Function(
-   *    {Array of ParallelCall} succeeded,
-   *    {Array of ParallelCall} failed
-   *   )} func
-   */
-  addAllFinishedObserver(func) {
-    assert(typeof(func) == "function");
-    this.addOneFinishedObserver(() => {
-      if (this._calls.some(call => !call.finished)) {
-        return;
-      }
-      let succeeded = this._calls.filter(call => call.succeeded);
-      let failed = this._calls.filter(call => !call.succeeded);
-      func(succeeded, failed);
-    });
-  },
-  _notifyFinished(call) {
-    for (let observer of this._finishedObservers) {
-      try {
-        observer(call);
-      } catch (e) {
-        console.error(e);
-      }
-    }
-  },
-  cancel(e) {
-    for (let call of this._calls) {
-      if (!call.finished && call.callerAbortable) {
-        call.callerAbortable.cancel(e);
-      }
-    }
-  },
-};
-
-/**
- * Returned by ParallelAbortable.addCall().
- * Do not create this object directly
- * @param {ParallelAbortable} parallelAbortable - The controlling ParallelAbortable
- */
-function ParallelCall(parallelAbortable) {
-  assert(parallelAbortable instanceof ParallelAbortable);
-  // {ParallelAbortable} the parent
-  this._parallelAbortable = parallelAbortable;
-  // {Abortable} Abortable of the caller function that should run in parallel
-  this.callerAbortable = null;
-  // {Integer} the order in which the function was added, and its priority
-  this.position = null;
-  // {boolean} false = running, pending, false = success or failure
-  this.finished = false;
-  // {boolean} if finished: true = returned with success, false = returned with error
-  this.succeeded = false;
-  // {Exception} if failed: the error or exception that the caller function returned
-  this.e = null;
-  // {Object} if succeeded: the result of the caller function
-  this.result = null;
-
-  this._time = Date.now();
-}
-ParallelCall.prototype = {
-  /**
-   * Returns a successCallback(result) function that you pass
-   * to your function that runs in parallel.
-   * @returns {Function(result)} successCallback
-   */
-  successCallback() {
-    return result => {
-      ddump("call " + this.position + " took " + (Date.now() - this._time) + "ms and succeeded" +
-          (this.callerAbortable && this.callerAbortable._url ? " at <" + this.callerAbortable._url + ">" : ""));
-      this.result = result;
-      this.finished = true;
-      this.succeeded = true;
-      this._parallelAbortable._notifyFinished(this);
-    };
-  },
-  /**
-   * Returns an errorCallback(e) function that you pass
-   * to your function that runs in parallel.
-   * @returns {Function(e)} errorCallback
-   */
-  errorCallback() {
-    return e => {
-      ddump("call " + this.position + " took " + (Date.now() - this._time) + "ms and failed with " + e +
-          (this.callerAbortable && this.callerAbortable._url ? " at <" + this.callerAbortable._url + ">" : ""));
-      this.e = e;
-      this.finished = true;
-      this.succeeded = false;
-      this._parallelAbortable._notifyFinished(this);
-    };
-  },
-  /**
-   * Call your function that needs to run in parallel
-   * and pass the resulting |Abortable| of your function here.
-   * @param {Abortable} abortable
-   */
-  setAbortable(abortable) {
-    assert(abortable instanceof Abortable);
-    this.callerAbortable = abortable;
+  cancel() {
+    if (this._current)
+      this._current.cancel();
   },
 };
 
-/**
- * Runs several calls in parallel.
- * Returns the result of the "highest" priority call that succeeds.
- * Unlike Promise.race(), does not return the fastest,
- * but the first in the order they were added.
- * So, the order in which the calls were added determines their priority,
- * with the first to be added being the most desirable.
- *
- * E.g. the first failed, the second is pending, the third succeeded, and the forth is pending.
- * It aborts the forth (because the third succeeded), and it waits for the second to return.
- * If the second succeeds, it is the result, otherwise the third is the result.
- *
- * @param {Function(
- *     {Object} result - Result of winner call
- *     {ParallelCall} call - Winner call info
- *   )} successCallback -  A call returned successfully
- * @param {Function(e)} errorCallback - All functions failed. The exception is from the first one.
- */
-function PriorityOrderAbortable(successCallback, errorCallback) {
-  assert(typeof(successCallback) == "function");
-  assert(typeof(errorCallback) == "function");
-  ParallelAbortable.call(this); // call super constructor
-
-  this.addOneFinishedObserver(finishedCall => {
-    let haveHigherPending = false;
-    let haveHigherSuccess = false;
-    for (let call of this._calls) {
-      if (!call.finished) {
-        if (haveHigherSuccess) {
-          // abort
-          if (call.callerAbortable) {
-            call.callerAbortable.cancel(NoLongerNeededException("Another higher call succeeded"));
-          }
-          continue;
-        }
-        // it's pending. ignore it for now and wait.
-        haveHigherPending = true;
-        continue;
-      }
-      if (!call.succeeded) {
-        // it failed. ignore it.
-        continue;
-      }
-      if (haveHigherSuccess) {
-        // another successful call was higher. ignore it.
-        continue;
-      }
-      haveHigherSuccess = true;
-      if (!haveHigherPending) {
-        // this is the winner
-        try {
-          successCallback(call.result, call);
-        } catch (e) {
-          console.error(e);
-          // if the handler failed with this data, treat this call as failed
-          call.e = e;
-          call.succeeded = false;
-          haveHigherSuccess = false;
-        }
-      }
-    }
-    if (!haveHigherPending && !haveHigherSuccess) {
-      // all failed
-      errorCallback(this._calls[0].e);
-    }
-  });
-}
-PriorityOrderAbortable.prototype = Object.create(ParallelAbortable.prototype);
-PriorityOrderAbortable.prototype.constructor = PriorityOrderAbortable;
-
-function NoLongerNeededException(msg) {
-  CancelledException.call(this, msg);
-}
-NoLongerNeededException.prototype = Object.create(CancelledException.prototype);
-NoLongerNeededException.prototype.constructor = NoLongerNeededException;
-
-
-/////////////////////////////////////////
-// High level features
-
-/**
- * Allows you to install an addon.
- *
- * Example:
- * var installer = new AddonInstaller({ xpiURL : "https://...xpi", id: "...", ...});
- * installer.install();
- *
- * @param {Object} args - Contains parameters:
- * @param {string} name (Optional) - Name of the addon (not important)
- * @param {string} id (Optional) - Addon ID
- * If you pass an ID, and the addon is already installed (and the version matches),
- * then install() will do nothing.
- * After the XPI is downloaded, the ID will be verified. If it doesn't match, the
- * install will fail.
- * If you don't pass an ID, these checks will be skipped and the addon be installed
- * unconditionally.
- * It is recommended to pass at least an ID, because it can confuse some addons
- * to be reloaded at runtime.
- * @param {string} minVersion (Optional) - Minimum version of the addon
- * If you pass a minVersion (in addition to ID), and the installed addon is older than this,
- * the install will be done anyway. If the downloaded addon has a lower version,
- * the install will fail.
- * If you do not pass a minVersion, there will be no version check.
- * @param {URL} xpiURL - Where to download the XPI from
- */
-function AddonInstaller(args) {
-  Abortable.call(this);
-  this._name = sanitize.label(args.name);
-  this._id = sanitize.string(args.id);
-  this._minVersion = sanitize.string(args.minVersion);
-  this._url = sanitize.url(args.xpiURL);
-}
-AddonInstaller.prototype = Object.create(Abortable.prototype);
-AddonInstaller.prototype.constructor = AddonInstaller;
-
-/**
- * Checks whether the passed-in addon matches the
- * id and minVersion requested by the caller.
- * @param {nsIAddon} addon
- * @returns {Boolean} is OK
- */
-AddonInstaller.prototype.matches = function(addon) {
-  return !this._id || (this._id == addon.id &&
-    (!this._minVersion || Services.vc.compare(addon.version, this._minVersion) >= 0));
-};
-
-/**
- * Start the installation
- * @throws Exception in case of failure
- */
-AddonInstaller.prototype.install = async function() {
-  if (await this.isInstalled()) {
-    return;
-  }
-  await this._installDirect();
-};
-
-/**
- * Checks whether we already have an addon installed that matches the
- * id and minVersion requested by the caller.
- * @returns {boolean} is already installed and enabled
- */
-AddonInstaller.prototype.isInstalled = async function() {
-  if (!this._id) {
-    return false;
-  }
-  var addon = await AddonManager.getAddonByID(this._id);
-  return addon && this.matches(addon) && addon.isActive;
-};
-
-/**
- * Downloads and installs the addon.
- * The downloaded XPI will be checked using prompt().
- */
-AddonInstaller.prototype._installDirect = async function() {
-  var installer = this._installer = await AddonManager.getInstallForURL(
-    this._url, "application/x-xpinstall", null, this._name);
-  installer.promptHandler = makeCallback(this, this.prompt);
-  await installer.install(); // throws, if failed
-
-  var addon = await AddonManager.getAddonByID(this._id);
-  await addon.enable();
-
-  // Wait for addon startup code to finish
-  // Fixes: verify password fails with NOT_AVAILABLE in createIncomingServer()
-  if ("startupPromise" in addon) {
-    await addon.startupPromise;
-  }
-  let wait = ms => new Promise(resolve => setTimeout(resolve, ms));
-  await wait(1000);
-};
-
-/**
- * Install confirmation. You may override this, if needed.
- * @throws Exception If you want to cancel install, then throw an exception.
- */
-AddonInstaller.prototype.prompt = async function(info) {
-  if (!this.matches(info.addon)) {
-    // happens only when we got the wrong XPI
-    throw new Exception("The downloaded addon XPI does not match the minimum requirements");
-  }
-};
-
-AddonInstaller.prototype.cancel = function() {
-  if (this._installer) {
-    try {
-      this._installer.cancel();
-    } catch (e) { // if install failed
-      ddump(e);
-    }
-  }
-};
-
-/////////////////////////////////////////
-// Debug output
-
 function deepCopy(org) {
   if (typeof(org) == "undefined")
     return undefined;
   if (org == null)
     return null;
   if (typeof(org) == "string")
     return org;
   if (typeof(org) == "number")
@@ -572,22 +214,18 @@ function deepCopy(org) {
     result = [];
   for (var prop in org)
     result[prop] = deepCopy(org[prop]);
   return result;
 }
 
 if (typeof gEmailWizardLogger == "undefined") {
   ChromeUtils.import("resource:///modules/gloda/log4moz.js");
-  var gEmailWizardLogger = Log4Moz.getConfiguredLogger("mail.setup");
-  gEmailWizardLogger.level = Log4Moz.Level.Info;
-  gEmailWizardLogger.addAppender(new Log4Moz.ConsoleAppender(new Log4Moz.BasicFormatter())); // browser console
-  gEmailWizardLogger.addAppender(new Log4Moz.DumpAppender(new Log4Moz.BasicFormatter())); // stdout
+  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)
--- a/mail/components/accountcreation/content/verifyConfig.js
+++ b/mail/components/accountcreation/content/verifyConfig.js
@@ -1,21 +1,13 @@
 /* -*- 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/. */
 
-ChromeUtils.import("resource:///modules/MailServices.jsm");
-ChromeUtils.import("resource:///modules/OAuth2Providers.jsm");
-
-if (typeof gEmailWizardLogger == "undefined") {
-  ChromeUtils.import("resource:///modules/gloda/log4moz.js");
-  var gEmailWizardLogger = Log4Moz.getConfiguredLogger("mail.wizard");
-}
-
 /**
  * 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
  *
@@ -31,37 +23,48 @@ if (typeof gEmailWizardLogger == "undefi
  *   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.
  */
+
+ChromeUtils.import("resource:///modules/MailServices.jsm");
+ChromeUtils.import("resource:///modules/OAuth2Providers.jsm");
+
+if (typeof gEmailWizardLogger == "undefined") {
+  ChromeUtils.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,
-                                           config.incoming.type,
+                                           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,
-                                               config.incoming.type);
+                                               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;
--- a/mail/components/accountcreation/jar.mn
+++ b/mail/components/accountcreation/jar.mn
@@ -2,17 +2,16 @@
 # 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/.
 
 messenger.jar:
   content/messenger/accountcreation/accountConfig.js      (content/accountConfig.js)
   content/messenger/accountcreation/createInBackend.js    (content/createInBackend.js)
   content/messenger/accountcreation/emailWizard.js        (content/emailWizard.js)
   content/messenger/accountcreation/emailWizard.xul       (content/emailWizard.xul)
-  content/messenger/accountcreation/exchangeAutoDiscover.js        (content/exchangeAutoDiscover.js)
   content/messenger/accountcreation/fetchConfig.js        (content/fetchConfig.js)
   content/messenger/accountcreation/fetchhttp.js          (content/fetchhttp.js)
   content/messenger/accountcreation/guessConfig.js        (content/guessConfig.js)
   content/messenger/accountcreation/MyBadCertHandler.js   (content/MyBadCertHandler.js)
   content/messenger/accountcreation/readFromXML.js        (content/readFromXML.js)
   content/messenger/accountcreation/sanitizeDatatypes.js  (content/sanitizeDatatypes.js)
   content/messenger/accountcreation/util.js               (content/util.js)
   content/messenger/accountcreation/verifyConfig.js       (content/verifyConfig.js)
--- a/mail/locales/en-US/chrome/messenger/accountCreation.dtd
+++ b/mail/locales/en-US/chrome/messenger/accountCreation.dtd
@@ -25,30 +25,25 @@
 <!ENTITY incoming.label                  "Incoming:">
 <!ENTITY outgoing.label                  "Outgoing:">
 <!ENTITY username.label                  "Username:">
 <!ENTITY hostname.label                  "Server hostname">
 <!ENTITY port.label                      "Port">
 <!ENTITY ssl.label                       "SSL">
 <!ENTITY auth.label                      "Authentication">
 <!ENTITY imap.label                      "IMAP">
-<!ENTITY pop3.label                      "POP3">
-<!-- LOCALIZATION NOTE(exchange.label): Do not translate Exchange, it is a product name. -->
-<!ENTITY exchange.label                  "Exchange">
+<!ENTITY pop3.label                       "POP3">
 <!ENTITY smtp.label                      "SMTP">
 <!ENTITY autodetect.label                "Autodetect">
 <!-- LOCALIZATION NOTE(noEncryption.label): Neither SSL/TLS nor STARTTLS.
      Transmission of emails in cleartext over the Internet. -->
 <!ENTITY noEncryption.label              "None">
 <!ENTITY starttls.label                  "STARTTLS">
 <!ENTITY sslTls.label                    "SSL/TLS">
 
-<!-- LOCALIZATION NOTE(exchange-hostname.label): Do not translate Exchange, it is a product name. -->
-<!ENTITY exchange-hostname.label         "Exchange server:">
-
 <!ENTITY advancedSetup.label             "Advanced config">
 <!ENTITY advancedSetup.accesskey         "A">
 <!ENTITY cancel.label                    "Cancel">
 <!ENTITY cancel.accesskey                "a">
 <!ENTITY continue.label                  "Continue">
 <!ENTITY continue.accesskey              "C">
 <!ENTITY stop.label                      "Stop">
 <!ENTITY stop.accesskey                  "S">
--- a/mail/locales/en-US/chrome/messenger/accountCreation.properties
+++ b/mail/locales/en-US/chrome/messenger/accountCreation.properties
@@ -13,37 +13,29 @@ cleartext_details=Insecure mail servers 
 # LOCALIZATION NOTE(default_server_tag): Used to indicate the default smtp server in the server dropdown list.
 default_server_tag= (default)
 # LOCALIZATION NOTE(port_auto): It must be short (4-5 characters max.).
 # Content of server port field (usually a number), used when the user didn't
 # enter anything yet and we'll automatically detect it later.
 port_auto=Auto
 
 # config titles
-looking_up_settings=Looking up configuration…
 # LOCALIZATION NOTE(looking_up_settings_disk): Referring to Thunderbird installation folder on user's harddisk. %1$S will be the brandShortName.
 looking_up_settings_disk=Looking up configuration: %1$S installation
 looking_up_settings_isp=Looking up configuration: Email provider
 # LOCALIZATION NOTE(looking_up_settings_db): Do not translate or replace Mozilla. It stands for the public project mozilla.org, not Mozilla Corporation. The database is a generic, public domain facility usable by any client.
 looking_up_settings_db=Looking up configuration: Mozilla ISP database
-looking_up_settings_mx=Looking up configuration: Incoming mail domain
-# LOCALIZATION NOTE(looking_up_settings_exchange): Exchange is a product name
-looking_up_settings_exchange=Looking up configuration: Exchange server
 # LOCALIZATION NOTE(looking_up_settings_guess): We are checking common server names like pop., pop3., smtp., mail., without knowing whether they exist or really serve this email account. If a server responds, we try to talk to it via POP/IMAP/SMTP protocols and query its capabilities. If that succeeds, we assume we found a configuration. Of course, it may still be wrong, but it often works.
 looking_up_settings_guess=Looking up configuration: Trying common server names
 looking_up_settings_halfmanual=Looking up configuration: Probing server
 # LOCALIZATION NOTE(found_settings_disk): Referring to Thunderbird installation folder on user's harddisk. %1$S will be the brandShortName.
 found_settings_disk=Configuration found on %1$S installation
 found_settings_isp=Configuration found at email provider
 # LOCALIZATION NOTE(found_settings_db): Do not translate or replace Mozilla. It stands for the public project mozilla.org, not Mozilla Corporation. The database is a generic, public domain facility usable by any client.
 found_settings_db=Configuration found in Mozilla ISP database
-# LOCALIZATION NOTE(found_settings_exchange): Microsoft Exchange is a product name.
-found_settings_exchange=Configuration found for a Microsoft Exchange server
-no-open-protocols=This email server unfortunately does not support open protocols.
-addon-intro=A third-party add-on can allow you to access your email account on this server:
 # LOCALIZATION NOTE(found_settings_guess): We tried common mail server names and we found a mail server and talked to it and it responded properly, so we think we found a suitable configuration, but we are only about 80% certain that it is the correct setting for this email address. There's a chance that email address may not actually be served by this server and it won't work, or that there is a better server.
 found_settings_guess=Configuration found by trying common server names
 found_settings_halfmanual=The following settings were found by probing the given server
 # LOCALIZATION NOTE(failed_to_find_settings): %1$S will be the brandShortName.
 failed_to_find_settings=%1$S failed to find the settings for your email account.
 manually_edit_config=Editing Config
 # LOCALIZATION NOTE(guessed_settings_offline) User is offline, so we just took a wild guess and the user will have to enter the right settings.
 guessed_settings_offline=You are offline. We guessed some settings but you will need to enter the right settings.
@@ -60,43 +52,49 @@ guessing_from_email=guessing configuration…
 config_details_found=Your configuration details have been found!
 config_unverifiable=Configuration could not be verified — is the username or password wrong?
 incoming_found_specify_outgoing=Your incoming server configuration details have been found, please specify the sending hostname.
 outgoing_found_specify_incoming=Your outgoing server configuration details have been found, please specify the receiving hostname.
 please_enter_missing_hostnames=Could not guess settings — please enter missing hostnames.
 incoming_failed_trying_outgoing=Could not automatically configure incoming server, still trying for outgoing server.
 outgoing_failed_trying_incoming=Could not automatically configure outgoing server, still trying for incoming server.
 checking_password=Checking password…
-password_ok=Password OK
+password_ok=Password ok!
 user_pass_invalid=Username or password invalid
 check_server_details=Checking server details
 check_in_server_details=Checking incoming server details
 check_out_server_details=Checking outgoing server details
 
 error_creating_account=Error Creating Account
 incoming_server_exists=Incoming server already exists.
 
 please_enter_name=Please enter your name.
 double_check_email=Double-check this email address!
 
-# add-on install
-addonInstallStarted=Downloading and installing add-on…
-addonInstallSuccess=Successfully installed the add-on.
-# LOCALIZATION NOTE(addonInstallLabel): %1$S will be the add-on name
-addonInstallShortLabel=Install
-
 #config result display
 # LOCALIZATION NOTE(resultUnknown): Displayed instead of resultIncoming,
 # resultOutgoing or resultUsername when we don't have a proper value.
 resultUnknown=Unknown
+# LOCALIZATION NOTE(resultIncoming):
+# %1$S will be replaced with either resultIMAP, resultPOP3 or resultSMTP.
+# %2$S will be replaced with the server hostname
+#   with possibly a port appended as ":"+port.
+#   The domain part may be made bold.
+# %3$S will be replaced with either resultNoEncryption or resultSSL or
+#    resultSTARTTLS.
+# %4$S will be replaced with either resultSSLCertWeak or resultSSLCertOK
+#    (which should normally be empty)
+# You may adjust the strings to be a real sentence.
+resultIncoming=%1$S, %2$S, %3$S%4$S
+# LOCALIZATION NOTE(resultOutgoing): see resultIncoming
+resultOutgoing=%1$S, %2$S, %3$S%4$S
 resultOutgoingExisting=Use existing outgoing SMTP server
 resultIMAP=IMAP
 resultPOP3=POP3
 resultSMTP=SMTP
-resultExchange=Exchange
 # LOCALIZATION NOTE(resultNoEncryption): Neither SSL/TLS nor STARTTLS. Transmission of emails in cleartext over the Internet.
 resultNoEncryption=No Encryption
 resultSSL=SSL
 resultSTARTTLS=STARTTLS
 # LOCALIZATION NOTE(resultSSLCertWeak): \u0020 is just a space
 resultSSLCertWeak=\u0020(Warning: Could not verify server)
 resultSSLCertOK=
 resultUsernameBoth=%1$S
--- a/mail/locales/en-US/chrome/messenger/accountCreationModel.properties
+++ b/mail/locales/en-US/chrome/messenger/accountCreationModel.properties
@@ -8,13 +8,11 @@
 
 # readFromXML.js
 no_emailProvider.error=The config file XML does not contain an email account configuration.
 outgoing_not_smtp.error=The outgoing server must be of type SMTP
 
 # verifyConfig.js
 cannot_login.error=Unable to log in at server. Probably wrong configuration, username or password.
 
+
 # guessConfig.js
 cannot_find_server.error=Can't find a server
-
-# exchangeAutoDiscover.js
-no_autodiscover.error=The Exchange AutoDiscover XML is invalid.
--- a/mail/themes/linux/mail/accountCreation.css
+++ b/mail/themes/linux/mail/accountCreation.css
@@ -1,14 +1,12 @@
 /* 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/. */
 
-@import url("chrome://messenger/skin/shared/accountCreation.css");
-
 /* ::::: BUTTONS ::::: */
 
 .important-button {
   font-weight: bold;
 }
 
 .errordescription {
   color: InfoText;
@@ -239,8 +237,24 @@ textbox.port[disabled="true"] {
 
 #outgoing_server_area {
   padding-top: 2px;
 }
 
 #incoming_protocol[disabled="true"] {
   padding-left: 5px;
 }
+
+#initialSettings, #status_area {
+  margin-bottom: 1em;
+}
+
+#result_area, #result_imappop {
+  margin-bottom: 1.5em;
+}
+
+#manual-edit_area {
+  margin-bottom: 2em;
+}
+
+#status_msg {
+  min-height: 2em;
+}
--- a/mail/themes/osx/mail/accountCreation.css
+++ b/mail/themes/osx/mail/accountCreation.css
@@ -1,14 +1,12 @@
 /* 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/. */
 
-@import url("chrome://messenger/skin/shared/accountCreation.css");
-
 /* Missing:
  * .important-button
  */
 
 .errordescription {
   padding-inline-start: 3px;
   margin-top: 3px;
 }
@@ -222,8 +220,24 @@ menulist {
 
 textbox.port[disabled="true"] {
   padding-top: 4px;
 }
 
 #incoming_protocol[disabled="true"] {
   padding-left: 5px;
 }
+
+#initialSettings, #status_area {
+  margin-bottom: 1em;
+}
+
+#result_area, #result_imappop {
+  margin-bottom: 1.5em;
+}
+
+#manual-edit_area {
+  margin-bottom: 2em;
+}
+
+#status_msg {
+  min-height: 2em;
+}
--- a/mail/themes/shared/jar.inc.mn
+++ b/mail/themes/shared/jar.inc.mn
@@ -78,17 +78,16 @@
   skin/classic/messenger/icons/starred.svg                    (../shared/mail/icons/starred.svg)
   skin/classic/messenger/icons/sticky.svg                     (../shared/mail/icons/sticky.svg)
   skin/classic/messenger/icons/stop.svg                       (../shared/mail/icons/stop.svg)
   skin/classic/messenger/icons/tag.svg                        (../shared/mail/icons/tag.svg)
   skin/classic/messenger/icons/thread-col.svg                 (../shared/mail/icons/thread-col.svg)
   skin/classic/messenger/icons/timeline.svg                   (../shared/mail/icons/timeline.svg)
   skin/classic/messenger/icons/toolbarbutton-arrow.svg        (../shared/mail/icons/toolbarbutton-arrow.svg)
   skin/classic/messenger/icons/waiting.svg                    (../shared/mail/icons/waiting.svg)
-  skin/classic/messenger/shared/accountCreation.css           (../shared/mail/accountCreation.css)
   skin/classic/messenger/shared/accountProvisioner.css        (../shared/mail/accountProvisioner.css)
   skin/classic/messenger/shared/addressbook.css               (../shared/mail/addressbook.css)
   skin/classic/messenger/shared/compacttheme.css              (../shared/mail/compacttheme.css)
   skin/classic/messenger/shared/in-content/dialog.css         (../shared/mail/incontentprefs/dialog.css)
   skin/classic/messenger/shared/in-content/aboutPreferences.css (../shared/mail/incontentprefs/aboutPreferences.css)
   skin/classic/messenger/shared/in-content/account.svg        (../shared/mail/incontentprefs/account.svg)
   skin/classic/messenger/shared/in-content/advanced.svg       (../shared/mail/incontentprefs/advanced.svg)
   skin/classic/messenger/shared/in-content/attachment.svg     (../shared/mail/incontentprefs/attachment.svg)
deleted file mode 100644
--- a/mail/themes/shared/mail/accountCreation.css
+++ /dev/null
@@ -1,99 +0,0 @@
-#initialSettings {
-  margin-bottom: 1em;
-}
-
-#manual-edit_area {
-  margin-bottom: 2em;
-}
-
-/* status area */
-
-#status_msg {
-  min-height: 1.5em;
-}
-
-#status-lines {
-  -moz-box-pack: start;
-  -moz-box-flex: 10;
-  margin-left: 10em;
-}
-
-.status-line[status="loading"] .status-img {
-  background: url("chrome://global/skin/icons/loading.png") no-repeat;
-  width: 16px;
-  height: 16px;
-}
-
-.status-line[status="failed"] .status-img {
-  background: url("chrome://messenger/skin/icons/exclude.png") no-repeat;
-  width: 16px;
-  height: 16px;
-}
-
-.status-line[status="succeeded"] .status-img {
-  background: url("chrome://messenger/skin/icons/tick.png") no-repeat;
-  width: 16px;
-  height: 16px;
-}
-
-/* result area */
-
-#result_area {
-  margin-bottom: 1em;
-}
-
-textbox.result-host-info > label {
-  margin-left: 0px;
-  margin-right: 0px;
-}
-
-textbox.result-host-info > label.host-without-domain,
-textbox.result-host-info > label.ssl,
-textbox.result-host-info > label.certStatus {
-  margin-left: 0.4em;
-}
-
-textbox.result-host-info > label.domain {
-  font-weight: bold;
-}
-
-textbox.result-host-info > label.insecure {
-  color: red;
-  font-weight: bold;
-}
-
-#result_servertype {
-  margin-bottom: 1.5em;
-}
-
-#result_exchange_hostname_container {
-  margin-bottom: 0.5em;
-}
-
-#result_area description {
-  margin-top: 0px;
-  margin-bottom: 0px;
-}
-
-#result_addon_intro {
-  max-width: 40em;
-}
-
-#result_addon_install {
-  margin-top: 4px;
-}
-
-#result_addon_install image.icon {
-  width: 32px;
-  height: 32px;
-  margin-left: 0.4em;
-  margin-right: 0.4em;
-}
-
-#result_addon_install_column_link {
-  max-width: 30em;
-}
-
-#result_addon_install_column_button {
-  max-width: 10em;
-}
--- a/mail/themes/windows/mail/accountCreation.css
+++ b/mail/themes/windows/mail/accountCreation.css
@@ -1,14 +1,13 @@
 /* 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/. */
 
 @namespace html url("http://www.w3.org/1999/xhtml");
-@import url("chrome://messenger/skin/shared/accountCreation.css");
 
 /* ::::: BUTTONS ::::: */
 
 .important-button {
   font-weight: bold;
 }
 
 /* Set the order of the buttons to: (stop|re-test), (continue|create account), cancel */
@@ -255,8 +254,24 @@ textbox.port[disabled="true"] {
 
 #outgoing_server_area {
   padding-top: 2px;
 }
 
 #incoming_protocol[disabled="true"] {
   padding-left: 6px;
 }
+
+#initialSettings, #status_area {
+  margin-bottom: 1em;
+}
+
+#result_area, #result_imappop {
+  margin-bottom: 1.5em;
+}
+
+#manual-edit_area {
+  margin-bottom: 2em;
+}
+
+#status_msg {
+  min-height: 2em;
+}
--- a/mailnews/mailnews.js
+++ b/mailnews/mailnews.js
@@ -894,31 +894,23 @@ pref("dom.max_chrome_script_run_time", 0
 // For the Empty Junk/Trash confirmation dialogs.
 pref("mailnews.emptyJunk.dontAskAgain", false);
 pref("mailnews.emptyTrash.dontAskAgain", false);
 
 // where to fetch auto config information from.
 pref("mailnews.auto_config_url", "https://live.thunderbird.net/autoconfig/v1.1/");
 // Added in bug 551519. Remove when bug 545866 is fixed.
 pref("mailnews.mx_service_url", "https://live.thunderbird.net/dns/mx/");
-// The list of addons which can handle certain account types
-pref("mailnews.auto_config.addons_url", "https://live.thunderbird.net/autoconfig/addons.json");
 // Allow to contact ISP (email address domain)
 // This happens via insecure means (HTTP), so the config cannot be trusted,
 // and also contains the email address
 pref("mailnews.auto_config.fetchFromISP.enabled", true);
 // Allow the fetch from ISP via HTTP, but not the email address
 pref("mailnews.auto_config.fetchFromISP.sendEmailAddress", true);
-// Allow the Microsoft Exchange AutoDiscover protocol.
-// This also sends the email address and password to the server,
-// which the protocol unfortunately requires in practice.
-pref("mailnews.auto_config.fetchFromExchange.enabled", true);
 pref("mailnews.auto_config.guess.enabled", true);
-// Work around bug 1454325 by disabling mimetype mungling in XmlHttpRequest
-pref("dom.xhr.standard_content_type_normalization", false);
 
 // -- Summary Database options
 // dontPreserveOnCopy: a space separated list of properties that are not
 //                     copied to the new nsIMsgHdr when a message is copied.
 //                     Allows extensions to control preservation of properties.
 pref("mailnews.database.summary.dontPreserveOnCopy",
   "account msgOffset threadParent msgThreadId statusOfset flags size numLines ProtoThreadFlags label gloda-id gloda-dirty storeToken");