Bug 490141 - "[autoconfig] doesn't start detection from my suggested server settings" [r=bienvenu,sr=Standard8]
authorBlake Winton <bwinton@latte.ca>
Tue, 07 Jul 2009 22:39:54 +0100
changeset 3035 4f6ab99f4b723b2c7c16ac4a02bd5d75af72fc2e
parent 3034 910203c1faf99707667d3bbeb1d34843cecaed8a
child 3036 8b921b3250e6d112e2f087bdaec50cb2bc81b7c0
push idunknown
push userunknown
push dateunknown
reviewersbienvenu, Standard8
bugs490141
Bug 490141 - "[autoconfig] doesn't start detection from my suggested server settings" [r=bienvenu,sr=Standard8]
mailnews/base/prefs/resources/content/accountcreation/guessConfig.js
mailnews/base/test/unit/test_autoconfigUtils.js
mailnews/base/util/Makefile.in
mailnews/base/util/autoconfigUtils.jsm
--- a/mailnews/base/prefs/resources/content/accountcreation/guessConfig.js
+++ b/mailnews/base/prefs/resources/content/accountcreation/guessConfig.js
@@ -35,34 +35,20 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 var gOverrideService = Cc["@mozilla.org/security/certoverride;1"]
                        .getService(Ci.nsICertOverrideService);
 Cu.import("resource://app/modules/gloda/log4moz.js");
-
-// Protocol Types
-const UNKNOWN = -1;
-const IMAP = 0;
-const POP = 1;
-const SMTP = 2;
-// Security Types
-const NONE = 0; // no encryption
-//1 would be "TLS if available"
-const TLS = 2; // STARTTLS
-const SSL = 3; // SSL / TLS
+Cu.import("resource://gre/modules/autoconfigUtils.jsm");
 
 const TIMEOUT =  10; // in seconds
 
-let IMAP4_CMDS = ["1 CAPABILITY\r\n", "2 LOGOUT\r\n"];
-let POP3_CMDS  = ["CAPA\r\n", "QUIT\r\n"];
-let SMTP_CMDS = ["EHLO\r\n", "QUIT\r\n"];
-
 // This is a bit ugly - we set outgoingDone to false
 // when emailWizard.js cancels the outgoing probe because the user picked
 // an outoing server. It does this by poking the probeAbortable object,
 // so we need outgoingDone to have global scope.
 var outgoingDone = false;
 
 /**
  * Try to guess the config, by:
@@ -330,16 +316,18 @@ function ConvertSocketTypeToSSL(socketTy
 {
   switch (socketType) {
     case 1:
       return NONE;
     case 2:
       return SSL;
     case 3:
       return TLS;
+    default:
+      return UNKNOWN;
   }
 }
 
 function protocolToString(type)
 {
   if (type == IMAP)
     return "imap";
   if (type == POP)
@@ -359,16 +347,17 @@ function protocolToString(type)
  * @param errorCallback {function(ex)} Called when we could not find a config
  * @param progressCallback { function(hostname, port) } Called when we tried
  *    (will try?) a new hostname and port
  */
 function HostDetector(progressCallback, successCallback, errorCallback)
 {
   this._init(progressCallback, successCallback, errorCallback);
 }
+
 HostDetector.prototype =
 {
   _loggerName : "hostdetector",
 
   _init : function HostDetector_init(progressCallback, successCallback,
                                      errorCallback)
   {
     this.mSuccessCallback = successCallback;
@@ -379,17 +368,17 @@ HostDetector.prototype =
     this._cancel = false;
     this._caller = null;
     this._result = null;
     this._tryIndex = 0;
     this._hostsToTry = new Array;
     this._gotCertError = false;
   },
 
-  _initLogging: function ()
+  _initLogging : function ()
   {
     this._log = Log4Moz.getConfiguredLogger(this._loggerName);
     this._log.info("Initializing " + this._loggerName + ' logger');
   },
 
   // TODO we could make all host/port combinations run in parallel, store their
   // results in an array, and as soon as one finishes successfully and all
   // higher-priority ones have failed, abort all lower-priority ones.
@@ -626,92 +615,26 @@ IncomingHostDetector.prototype =
       }
       this._hostsToTry.push("mail." + this.host);
       this._hostsToTry.push(this.host);
     }
     this._hostIndex = 0;
     this._tryNextHost();
   },
 
-  _tryHost : function()
-  {
+  _tryHost : function() {
     // If the protocol was specified, trust that.
     // Same for the port number.
+    // Ditto for the socketType.
     // Otherwise, if the hostname starts with pop try POP3 protocols first,
     // otherwise check IMAP4 protocols first.
 
-    var lowerCaseHost = this._host.toLowerCase();
-    if (this._specifiedProtocol == POP ||
-        !lowerCaseHost.indexOf("pop.") ||
-        !lowerCaseHost.indexOf("pop3."))
-    {
-      if (this._specifiedPort == UNKNOWN)
-      {
-        this.tryOrder = [
-              [POP, TLS, 110, POP3_CMDS],
-              [POP, SSL, 995, POP3_CMDS],
-              [POP, NONE, 110, POP3_CMDS]];
-      }
-      else
-      {
-        if (this._specifiedSSL == UNKNOWN)
-          this.tryOrder = [
-              [POP, TLS, this._specifiedPort, POP3_CMDS],
-              [POP, SSL, this._specifiedPort, POP3_CMDS],
-              [POP, NONE, this._specifiedPort, POP3_CMDS]];
-         else
-           this.tryOrder = [
-               [POP, this._specifiedSSL, this._specifiedPort, POP3_CMDS]];
-      }
-    }
-    else if ((this._specifiedProtocol == IMAP) ||
-             !lowerCaseHost.indexOf("imap."))
-    {
-      if (this._specifiedPort == UNKNOWN)
-      {
-        this.tryOrder = [
-            [IMAP, TLS, 143, IMAP4_CMDS],
-            [IMAP, SSL, 993, IMAP4_CMDS],
-            [IMAP, NONE, 143, IMAP4_CMDS]];
-      }
-      else
-      {
-        if (this._specifiedSSL == UNKNOWN)
-          this.tryOrder = [
-            [IMAP, TLS, this._specifiedPort, IMAP4_CMDS],
-            [IMAP, SSL, this._specifiedPort, IMAP4_CMDS],
-            [IMAP, NONE, this._specifiedPort, IMAP4_CMDS]];
-        else
-          this.tryOrder = [
-            [IMAP, this._specifiedSSL, this._specifiedPort, IMAP4_CMDS]];
-      }
-    }
-    else
-    {
-      if (this._specifiedPort == UNKNOWN)
-      {
-        this.tryOrder = [
-              [IMAP, TLS, 143, IMAP4_CMDS],
-              [IMAP, SSL, 993, IMAP4_CMDS],
-              [POP, TLS, 110, POP3_CMDS],
-              [POP, SSL, 995, POP3_CMDS],
-              [IMAP, NONE, 143, IMAP4_CMDS],
-              [POP, NONE, 110, POP3_CMDS]];
-      }
-      else
-      {
-        this.tryOrder = [
-              [IMAP, TLS, this._specifiedPort, IMAP4_CMDS],
-              [IMAP, SSL, this._specifiedPort, IMAP4_CMDS],
-              [POP, TLS, this._specifiedPort, POP3_CMDS],
-              [POP, SSL, this._specifiedPort, POP3_CMDS],
-              [IMAP, NONE, this._specifiedPort, IMAP4_CMDS],
-              [POP, NONE, this._specifiedPort, POP3_CMDS]];
-      }
-    }
+    this.tryOrder = getIncomingTryOrder(this._host, this._specifiedProtocol,
+                                        this._specifiedSSL,
+                                        this._specifiedPort);
     this._tryIndex = -1;
     this.keepTrying();
   }
 }
 
 function OutgoingHostDetector(progressCallback, successCallback, errorCallback)
 {
   this._init(progressCallback, successCallback, errorCallback);
@@ -754,30 +677,17 @@ OutgoingHostDetector.prototype =
       this._hostsToTry.push(this.host);
     }
     this._hostIndex = 0;
     this._tryNextHost();
   },
 
   _tryHost : function()
   {
-    if (this._specifiedPort == UNKNOWN)
-    {
-      this.tryOrder = [
-             [SMTP, TLS, 587, SMTP_CMDS],
-             [SMTP, SSL, 465, SMTP_CMDS],
-             [SMTP, TLS, 25, SMTP_CMDS],
-             [SMTP, NONE, 587, SMTP_CMDS],
-             [SMTP, NONE, 25, SMTP_CMDS]];
-    } else {
-      this.tryOrder = [
-             [SMTP, TLS, this._specifiedPort, SMTP_CMDS],
-             [SMTP, SSL, this._specifiedPort, SMTP_CMDS],
-             [SMTP, NONE, this._specifiedPort, SMTP_CMDS]];
-    }
+    this.tryOrder = getOutgoingTryOrder(this._specifiedPort)
     this._tryIndex = -1;
     this.keepTrying();
   }
 }
 
 function hasTLS(line, type)
 {
   return line.indexOf(type != POP ? "STARTTLS" : "STLS") != -1;
new file mode 100644
--- /dev/null
+++ b/mailnews/base/test/unit/test_autoconfigUtils.js
@@ -0,0 +1,306 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is autoconfig test code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Messaging.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Blake Winton <bwinton@latte.ca>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Test suite for the autoconfigUtils class
+ *
+ * Currently tested:
+ * - getHostEntry function.
+ * - getIncomingTryOrder function.
+ * - getOutgoingTryOrder function.
+ *
+ * TODO:
+ * - Test the returned CMDS.
+ * - Figure out what else to test.
+ */
+
+// Globals
+
+Components.utils.import("resource://gre/modules/autoconfigUtils.jsm");
+
+/*
+ * UTILITIES
+ */
+
+function assert(aBeTrue, aWhy)
+{
+  if (!aBeTrue)
+    do_throw(aWhy);
+};
+
+function assert_equal(aA, aB, aWhy)
+{
+  assert(aA == aB, aWhy + " (" + aA + " != " + aB + ").");
+};
+
+/**
+ * Test that two host entries are the same, ignoring the commands.
+ */
+function assert_equal_host_entries(aA, aB)
+{
+  assert_equal(aA[0], aB[0], "Protocols are different");
+  assert_equal(aA[1], aB[1], "Ssl values are different");
+  assert_equal(aA[2], aB[2], "Port values are different");
+};
+
+/**
+ * Assert that the list of tryOrders are the same.
+ */
+function assert_equal_try_orders(aA, aB)
+{
+  assert_equal(aA.length, aB.length, "tryOrders have different length");
+  for (let [i,subA] in Iterator(aA)) {
+    let subB = aB[i];
+    assert_equal_host_entries(subA, subB);
+  }
+};
+
+/**
+ * Check that the POP calculations are correct for a given host and
+ * protocol.
+ */
+function checkPop(host, protocol)
+{
+  // port == UNKNOWN
+    // [POP, TLS, 110], [POP, SSL, 995], [POP, NONE, 110]
+  // port != UNKNOWN
+    // ssl == UNKNOWN
+      // [POP, TLS, port], [POP, SSL, port], [POP, NONE, port]
+    // ssl != UNKNOWN
+      // [POP, ssl, port]
+  let ssl = UNKNOWN;
+  let port = UNKNOWN;
+  let tryOrder = getIncomingTryOrder(host, protocol, ssl, port);
+  assert_equal_try_orders(tryOrder,
+                          [[POP, TLS, 110],
+                           [POP, SSL, 995],
+                           [POP, NONE, 110]]);
+
+  ssl = TLS;
+  tryOrder = getIncomingTryOrder(host, protocol, ssl, port);
+  assert_equal_try_orders(tryOrder,
+                          [[POP, ssl, 110]]);
+
+  ssl = SSL;
+  tryOrder = getIncomingTryOrder(host, protocol, ssl, port);
+  assert_equal_try_orders(tryOrder,
+                          [[POP, ssl, 995]]);
+
+  ssl = NONE;
+  tryOrder = getIncomingTryOrder(host, protocol, ssl, port);
+  assert_equal_try_orders(tryOrder,
+                          [[POP, ssl, 110]]);
+
+  ssl = UNKNOWN;
+  port = 31337;
+  tryOrder = getIncomingTryOrder(host, protocol, ssl, port);
+  assert_equal_try_orders(tryOrder,
+                          [[POP, TLS, port],
+                           [POP, SSL, port],
+                           [POP, NONE, port]]);
+
+  for (ssl in [TLS, SSL, NONE]) {
+    tryOrder = getIncomingTryOrder(host, protocol, ssl, port);
+    assert_equal_try_orders(tryOrder,
+                            [[POP, ssl, port]]);
+  }
+};
+
+/**
+ * Check that the IMAP calculations are correct for a given host and
+ * protocol.
+ */
+function checkImap(host, protocol)
+{
+  // port == UNKNOWN
+    // [IMAP, TLS, 143], [IMAP, SSL, 993], [IMAP, NONE, 143]
+  // port != UNKNOWN
+    // ssl == UNKNONWN
+      // [IMAP, TLS, port], [IMAP, SSL, port], [IMAP, NONE, port]
+    // ssl != UNKNOWN
+     // [IMAP, ssl, port];
+
+  let ssl = UNKNOWN;
+  let port = UNKNOWN;
+  let tryOrder = getIncomingTryOrder(host, protocol, ssl, port);
+  assert_equal_try_orders(tryOrder,
+                          [[IMAP, TLS, 143],
+                           [IMAP, SSL, 993],
+                           [IMAP, NONE, 143]]);
+
+  ssl = TLS;
+  tryOrder = getIncomingTryOrder(host, protocol, ssl, port);
+  assert_equal_try_orders(tryOrder,
+                          [[IMAP, ssl, 143]]);
+
+  ssl = SSL;
+  tryOrder = getIncomingTryOrder(host, protocol, ssl, port);
+  assert_equal_try_orders(tryOrder,
+                          [[IMAP, ssl, 993]]);
+
+  ssl = NONE;
+  tryOrder = getIncomingTryOrder(host, protocol, ssl, port);
+  assert_equal_try_orders(tryOrder,
+                          [[IMAP, ssl, 143]]);
+
+  ssl = UNKNOWN;
+  port = 31337;
+  tryOrder = getIncomingTryOrder(host, protocol, ssl, port);
+  assert_equal_try_orders(tryOrder,
+                          [[IMAP, TLS, port],
+                           [IMAP, SSL, port],
+                           [IMAP, NONE, port]]);
+
+  for (ssl in [TLS, SSL, NONE]) {
+    tryOrder = getIncomingTryOrder(host, protocol, ssl, port);
+    assert_equal_try_orders(tryOrder,
+                            [[IMAP, ssl, port]]);
+  }
+};
+
+/*
+ * TESTS
+ */
+
+/**
+ * Test that getHostEntry returns the correct port numbers.
+ *
+ * TODO:
+ * - Test the returned commands as well.
+ */
+function test_getHostEntry()
+{
+  // IMAP port numbers.
+  assert_equal_host_entries(getHostEntry(IMAP, TLS, UNKNOWN),
+                            [IMAP, TLS, 143]);
+  assert_equal_host_entries(getHostEntry(IMAP, SSL, UNKNOWN),
+                            [IMAP, SSL, 993]);
+  assert_equal_host_entries(getHostEntry(IMAP, NONE, UNKNOWN),
+                            [IMAP, NONE, 143]);
+
+  // POP port numbers.
+  assert_equal_host_entries(getHostEntry(POP, TLS, UNKNOWN),
+                            [POP, TLS, 110]);
+  assert_equal_host_entries(getHostEntry(POP, SSL, UNKNOWN),
+                            [POP, SSL, 995]);
+  assert_equal_host_entries(getHostEntry(POP, NONE, UNKNOWN),
+                            [POP, NONE, 110]);
+
+  // SMTP port numbers.
+  assert_equal_host_entries(getHostEntry(SMTP, TLS, UNKNOWN),
+                            [SMTP, TLS, 587]);
+  assert_equal_host_entries(getHostEntry(SMTP, SSL, UNKNOWN),
+                            [SMTP, SSL, 465]);
+  assert_equal_host_entries(getHostEntry(SMTP, NONE, UNKNOWN),
+                            [SMTP, NONE, 25]);
+};
+
+/**
+ * Test the getIncomingTryOrder method.
+ */
+function test_getIncomingTryOrder()
+{
+  // protocol == POP || host starts with pop. || host starts with pop3.
+  checkPop( "latte.ca", POP );
+  checkPop( "pop.latte.ca", UNKNOWN );
+  checkPop( "pop3.latte.ca", UNKNOWN );
+  checkPop( "imap.latte.ca", POP );
+
+  // protocol == IMAP || host starts with imap.
+  checkImap( "latte.ca", IMAP );
+  checkImap( "imap.latte.ca", UNKNOWN );
+  checkImap( "pop.latte.ca", IMAP );
+
+  let host = "latte.ca";
+  let protocol = UNKNOWN;
+  let ssl = UNKNOWN;
+  let port = UNKNOWN;
+  let tryOrder = getIncomingTryOrder(host, protocol, ssl, port);
+  assert_equal_try_orders(tryOrder,
+                          [[IMAP, TLS, 143],
+                           [IMAP, SSL, 993],
+                           [POP, TLS, 110],
+                           [POP, SSL, 995],
+                           [IMAP, NONE, 143],
+                           [POP, NONE, 110]]);
+
+  host = "latte.ca";
+  protocol = UNKNOWN;
+  ssl = UNKNOWN;
+  port = 31337;
+  let tryOrder = getIncomingTryOrder(host, protocol, ssl, port);
+  assert_equal_try_orders(tryOrder,
+                          [[IMAP, TLS, port],
+                           [IMAP, SSL, port],
+                           [POP, TLS, port],
+                           [POP, SSL, port],
+                           [IMAP, NONE, port],
+                           [POP, NONE, port]]);
+};
+
+/**
+ * Test the getOutgoingTryOrder method.
+ */
+function test_getOutgoingTryOrder()
+{
+  let port = UNKNOWN;
+  let tryOrder = getOutgoingTryOrder(port);
+  assert_equal_try_orders(tryOrder,
+                          [[SMTP, TLS, 587],
+                           [SMTP, SSL, 465],
+                           [SMTP, TLS, 25],
+                           [SMTP, NONE, 587],
+                           [SMTP, NONE, 25]]);
+  port = 31337
+  tryOrder = getOutgoingTryOrder(port);
+  assert_equal_try_orders(tryOrder,
+                          [[SMTP, TLS, port],
+                           [SMTP, SSL, port],
+                           [SMTP, NONE, port]]);
+};
+
+function run_test()
+{
+  do_test_pending();
+
+  test_getHostEntry();
+  test_getIncomingTryOrder();
+  test_getOutgoingTryOrder();
+
+  do_test_finished();
+};
--- a/mailnews/base/util/Makefile.in
+++ b/mailnews/base/util/Makefile.in
@@ -127,16 +127,17 @@ EXPORTS		= \
 		nsMsgReadStateTxn.h \
 		$(NULL)
 
 EXTRA_JS_MODULES = \
 		folderUtils.jsm \
 		iteratorUtils.jsm \
 		jsTreeSelection.js \
 		traceHelper.js \
+		autoconfigUtils.jsm \
 		$(NULL)
 
 ifndef MOZ_STATIC_MAIL_BUILD
 
 ifdef MOZILLA_INTERNAL_API
 EXTRA_DSO_LDOPTS = \
 	$(LIBS_DIR) \
 	$(MOZDEPTH)/rdf/util/src/internal/$(LIB_PREFIX)rdfutil_s.$(LIB_SUFFIX) \
new file mode 100644
--- /dev/null
+++ b/mailnews/base/util/autoconfigUtils.jsm
@@ -0,0 +1,139 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is autoconfig code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Messaging.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Blake Winton <bwinton@latte.ca>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * This file contains helper methods for dealing with autoconfig.
+ */
+
+var EXPORTED_SYMBOLS = [
+  "UNKNOWN", "IMAP", "POP", "SMTP", "NONE", "TLS", "SSL",
+  "getHostEntry", "getIncomingTryOrder", "getOutgoingTryOrder"];
+
+// Protocol Types
+const UNKNOWN = -1;
+const IMAP = 0;
+const POP = 1;
+const SMTP = 2;
+// Security Types
+const NONE = 0; // no encryption
+//1 would be "TLS if available"
+const TLS = 2; // STARTTLS
+const SSL = 3; // SSL / TLS
+
+const IMAP4_CMDS = ["1 CAPABILITY\r\n", "2 LOGOUT\r\n"];
+const POP3_CMDS  = ["CAPA\r\n", "QUIT\r\n"];
+const SMTP_CMDS = ["EHLO\r\n", "QUIT\r\n"];
+
+const IMAP_PORTS = {}
+IMAP_PORTS[TLS]=143;
+IMAP_PORTS[SSL]=993;
+IMAP_PORTS[NONE]=143;
+
+const POP_PORTS = {}
+POP_PORTS[TLS]=110;
+POP_PORTS[SSL]=995;
+POP_PORTS[NONE]=110;
+
+const SMTP_PORTS = {}
+SMTP_PORTS[TLS]=587;
+SMTP_PORTS[SSL]=465;
+SMTP_PORTS[NONE]=25;
+
+const CMDS = {}
+CMDS[IMAP]=IMAP4_CMDS;
+CMDS[POP]=POP3_CMDS;
+CMDS[SMTP]=SMTP_CMDS;
+
+function getHostEntry(protocol, ssl, port)
+{
+  if (!port || port == UNKNOWN) {
+    switch (protocol) {
+      case POP:
+        port = POP_PORTS[ssl];
+        break;
+      case IMAP:
+        port = IMAP_PORTS[ssl];
+        break;
+      case SMTP:
+        port = SMTP_PORTS[ssl];
+        break;
+    }
+  }
+
+  return [protocol, ssl, port, CMDS[protocol]];
+};
+
+function getIncomingTryOrder(host, protocol, ssl, port)
+{
+  var lowerCaseHost = host.toLowerCase();
+
+  if (protocol == UNKNOWN &&
+      (!lowerCaseHost.indexOf("pop.") || !lowerCaseHost.indexOf("pop3.")))
+    protocol = POP;
+  else if (protocol == UNKNOWN && !lowerCaseHost.indexOf("imap."))
+    protocol = IMAP;
+
+  if (protocol != UNKNOWN) {
+    if (ssl == UNKNOWN)
+      return [getHostEntry(protocol, TLS, port),
+              getHostEntry(protocol, SSL, port),
+              getHostEntry(protocol, NONE, port)];
+    return [getHostEntry(protocol, ssl, port)];
+  }
+  if (ssl == UNKNOWN)
+    return [getHostEntry(IMAP, TLS, port),
+            getHostEntry(IMAP, SSL, port),
+            getHostEntry(POP, TLS, port),
+            getHostEntry(POP, SSL, port),
+            getHostEntry(IMAP, NONE, port),
+            getHostEntry(POP, NONE, port)];
+  return [getHostEntry(IMAP, ssl, port),
+          getHostEntry(POP, ssl, port)];
+};
+
+function getOutgoingTryOrder(port)
+{
+  if (port == UNKNOWN)
+    return [getHostEntry(SMTP, TLS, port),
+            getHostEntry(SMTP, SSL, port),
+            getHostEntry(SMTP, TLS, 25),
+            getHostEntry(SMTP, NONE, 587),
+            getHostEntry(SMTP, NONE, port)];
+  return [getHostEntry(SMTP, TLS, port),
+          getHostEntry(SMTP, SSL, port),
+          getHostEntry(SMTP, NONE, port)];
+};