Bug 776316 - Update to Mozmill 1.5.16. r=mozmill.
authorMike Conley <mconley@mozilla.com>
Tue, 24 Jul 2012 16:47:15 -0400
changeset 10722 16bca5fa8f0889bec716fccefeb847d2cae56ba7
parent 10721 927b4c1ae37690e20557f9407554e53171ef10dd
child 10723 c2c87f2fd5347f965872fd6986788c8a2b6e5fec
push id8082
push usermconley@mozilla.com
push dateTue, 24 Jul 2012 20:48:45 +0000
treeherdercomm-central@c2c87f2fd534 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmozmill
bugs776316
Bug 776316 - Update to Mozmill 1.5.16. r=mozmill.
mail/test/resources/jsbridge/jsbridge/__init__.py
mail/test/resources/jsbridge/jsbridge/extension/install.rdf
mail/test/resources/jsbridge/jsbridge/jsobjects.py
mail/test/resources/jsbridge/jsbridge/network.py
mail/test/resources/jsbridge/setup.py
mail/test/resources/mozmill/mozmill/__init__.py
mail/test/resources/mozmill/mozmill/extension/chrome.manifest
mail/test/resources/mozmill/mozmill/extension/content/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
mail/test/resources/mozmill/mozmill/extension/content/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
mail/test/resources/mozmill/mozmill/extension/content/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
mail/test/resources/mozmill/mozmill/extension/content/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
mail/test/resources/mozmill/mozmill/extension/content/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png
mail/test/resources/mozmill/mozmill/extension/content/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
mail/test/resources/mozmill/mozmill/extension/content/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
mail/test/resources/mozmill/mozmill/extension/content/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
mail/test/resources/mozmill/mozmill/extension/content/css/smoothness/images/ui-icons_222222_256x240.png
mail/test/resources/mozmill/mozmill/extension/content/css/smoothness/images/ui-icons_2e83ff_256x240.png
mail/test/resources/mozmill/mozmill/extension/content/css/smoothness/images/ui-icons_454545_256x240.png
mail/test/resources/mozmill/mozmill/extension/content/css/smoothness/images/ui-icons_888888_256x240.png
mail/test/resources/mozmill/mozmill/extension/content/css/smoothness/images/ui-icons_cd0a0a_256x240.png
mail/test/resources/mozmill/mozmill/extension/content/css/smoothness/jquery-ui-1.7.1.custom.css
mail/test/resources/mozmill/mozmill/extension/content/jquery/jquery-1.3.2.min.js
mail/test/resources/mozmill/mozmill/extension/content/jquery/jquery-ui-1.7.1.custom.min.js
mail/test/resources/mozmill/mozmill/extension/content/mozmill.xul
mail/test/resources/mozmill/mozmill/extension/content/overlay.js
mail/test/resources/mozmill/mozmill/extension/content/overlay.xul
mail/test/resources/mozmill/mozmill/extension/install.rdf
mail/test/resources/mozmill/mozmill/extension/locale/en-US/mozmill.dtd
mail/test/resources/mozmill/mozmill/extension/locale/en-US/overlay.dtd
mail/test/resources/mozmill/mozmill/extension/readme.txt
mail/test/resources/mozmill/mozmill/extension/resource/modules/frame.js
mail/test/resources/mozmill/mozmill/extension/resource/modules/init.js
mail/test/resources/mozmill/mozmill/extension/resource/stdlib/EventUtils.js
mail/test/resources/mozmill/mozmill/extension/resource/stdlib/httpd.js
mail/test/resources/mozmill/mozmill/extension/resource/stdlib/securable-module.js
mail/test/resources/mozmill/mozmill/extension/skin/overlay.css
mail/test/resources/mozmill/patches/httpd.patch
mail/test/resources/mozmill/scripts/sync_dependencies.py
mail/test/resources/mozmill/setup.py
mail/test/resources/mozmill/test/restart/test_user_restart/test5.js
mail/test/resources/mozrunner/mozrunner/__init__.py
mail/test/resources/mozrunner/mozrunner/killableprocess.py
mail/test/resources/mozrunner/mozrunner/winprocess.py
mail/test/resources/mozrunner/setup.py
--- a/mail/test/resources/jsbridge/jsbridge/__init__.py
+++ b/mail/test/resources/jsbridge/jsbridge/__init__.py
@@ -1,11 +1,45 @@
-# 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/.
+# ***** 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 Mozilla Corporation Code.
+# 
+# The Initial Developer of the Original Code is
+# Mikeal Rogers.
+# Portions created by the Initial Developer are Copyright (C) 2008 -2009
+# the Initial Developer. All Rights Reserved.
+# 
+# Contributor(s):
+#  Mikeal Rogers <mikeal.rogers@gmail.com>
+#  Henrik Skupin <hskupin@mozilla.com>
+# 
+# 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 *****
 
 import socket
 import os
 import copy
 import asyncore
 
 from time import sleep
 from network import Bridge, BackChannel, create_network
--- a/mail/test/resources/jsbridge/jsbridge/extension/install.rdf
+++ b/mail/test/resources/jsbridge/jsbridge/extension/install.rdf
@@ -1,61 +1,51 @@
 <?xml version="1.0"?>
 <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:em="http://www.mozilla.org/2004/em-rdf#">
    <Description about="urn:mozilla:install-manifest">
      <em:id>jsbridge@mozilla.com</em:id>
      <em:name>jsbridge</em:name>
-     <em:version>2.4.6</em:version>
+     <em:version>2.4.14</em:version>
      <em:creator>Mikeal Rogers</em:creator>
      <em:description>Python to JavaScript bridge</em:description>
      <em:unpack>true</em:unpack>
      <em:targetApplication>
        <!-- Firefox -->
        <Description>
          <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
-         <em:minVersion>3.5</em:minVersion>
-         <em:maxVersion>15.*</em:maxVersion>
+         <em:minVersion>4.0</em:minVersion>
+         <em:maxVersion>20.*</em:maxVersion>
        </Description>
      </em:targetApplication>
      <em:targetApplication>
        <!-- Thunderbird -->
        <Description>
          <em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
-         <em:minVersion>3.0a1pre</em:minVersion>
-         <em:maxVersion>15.*</em:maxVersion>
+         <em:minVersion>5.0</em:minVersion>
+         <em:maxVersion>20.*</em:maxVersion>
        </Description>
      </em:targetApplication>
      <em:targetApplication>
        <!-- Sunbird -->
        <Description>
          <em:id>{718e30fb-e89b-41dd-9da7-e25a45638b28}</em:id>
-         <em:minVersion>1.0b1pre</em:minVersion>
-         <em:maxVersion>1.0pre</em:maxVersion>
+         <em:minVersion>1.0b5</em:minVersion>
+         <em:maxVersion>1.6b1</em:maxVersion>
        </Description>
      </em:targetApplication>
      <em:targetApplication>
        <!-- SeaMonkey -->
        <Description>
          <em:id>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</em:id>
-         <em:minVersion>2.0a1</em:minVersion>
-         <em:maxVersion>15.*</em:maxVersion>
+         <em:minVersion>2.1</em:minVersion>
+         <em:maxVersion>2.16</em:maxVersion>
        </Description>
      </em:targetApplication>
-	   <em:targetApplication>
-	      <!-- Songbird -->
-	      <Description>
-	        <em:id>songbird@songbirdnest.com</em:id>
-	        <em:minVersion>0.3pre</em:minVersion>
-	        <em:maxVersion>2.*</em:maxVersion>
-	      </Description>
-	   </em:targetApplication>
-	   <em:targetApplication>
+     <em:targetApplication>
          <Description>
           <em:id>toolkit@mozilla.org</em:id>
-          <em:minVersion>1.9.1</em:minVersion>
-          <em:maxVersion>15.*</em:maxVersion>
+          <em:minVersion>2.0</em:minVersion>
+          <em:maxVersion>20.*</em:maxVersion>
          </Description>
      </em:targetApplication>
    </Description>
-
-
 </RDF>
--- a/mail/test/resources/jsbridge/jsbridge/jsobjects.py
+++ b/mail/test/resources/jsbridge/jsbridge/jsobjects.py
@@ -1,11 +1,44 @@
-# 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/.
+# ***** 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 Mozilla Corporation Code.
+#
+# The Initial Developer of the Original Code is
+# Mikeal Rogers.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Mikeal Rogers <mikeal.rogers@gmail.com>
+#
+# 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 *****
 
 def init_jsobject(cls, bridge, name, value, description=None):
     """Initialize a js object that is a subclassed base type; int, str, unicode, float."""
     obj = cls(value)
     obj._bridge_ = bridge
     obj._name_ = name
     obj._description_ = description
     return obj
--- a/mail/test/resources/jsbridge/jsbridge/network.py
+++ b/mail/test/resources/jsbridge/jsbridge/network.py
@@ -1,11 +1,44 @@
-# 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/.
+# ***** 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 Mozilla Corporation Code.
+#
+# The Initial Developer of the Original Code is
+# Mikeal Rogers.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Mikeal Rogers <mikeal.rogers@gmail.com>
+#
+# 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 *****
 
 import asyncore
 import socket
 import select
 import logging
 import uuid
 from time import sleep
 from threading import Thread
@@ -45,21 +78,22 @@ class Telnet(asyncore.dispatcher):
 
     def handle_write(self):
         sent = self.send(self.buffer)
         self.buffer = self.buffer[sent:]
         
     def read_all(self):
         import socket
         data = ''
-        while 1:
+        while self.connected:
             try:
                 data += self.recv(4096)
             except socket.error:
-                return data
+                break
+        return data
 
     def handle_read(self):
         self.data = self.read_all()
         self.process_read(self.data)
 
         
     read_callback = lambda self, data: None
 
--- a/mail/test/resources/jsbridge/setup.py
+++ b/mail/test/resources/jsbridge/setup.py
@@ -1,22 +1,55 @@
-# 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/.
+# ***** 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 Mozilla Corporation Code.
+#
+# The Initial Developer of the Original Code is
+# Mikeal Rogers.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Mikeal Rogers <mikeal.rogers@gmail.com>
+#
+# 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 *****
 
 import sys
 from setuptools import setup, find_packages
 
 desc = """Python to JavaScript bridge interface."""
 summ = """A powerful and extensible Python to JavaScript bridge interface."""
 
 PACKAGE_NAME = "jsbridge"
-PACKAGE_VERSION = "2.4.6"
+PACKAGE_VERSION = "2.4.14"
 
-requires = ['mozrunner == 2.5.7']
+requires = ['mozrunner == 2.5.13']
 
 if not sys.version.startswith('2.6'):
     requires.append('simplejson')
 
 setup(name=PACKAGE_NAME,
       version=PACKAGE_VERSION,
       description=desc,
       long_description=summ,
--- a/mail/test/resources/mozmill/mozmill/__init__.py
+++ b/mail/test/resources/mozmill/mozmill/__init__.py
@@ -1,21 +1,54 @@
-# 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/.
+# ***** 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 Mozilla Corporation Code.
+#
+# The Initial Developer of the Original Code is
+# Mikeal Rogers.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Mikeal Rogers <mikeal.rogers@gmail.com>
+#  Henrik Skupin <hskupin@mozilla.com>
+#  Clint Talbert <ctalbert@mozilla.com>
+#
+# 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 *****
 
 import copy
-import httplib
 import imp
 import os
 import socket
 import sys
 import traceback
-import urllib
-import urlparse
+import urllib2
 
 from datetime import datetime, timedelta
 import manifestparser
 
 try:
     import json
 except:
     import simplejson as json
@@ -412,37 +445,32 @@ class MozMill(object):
             return
 
         # report to CouchDB
         try:
             # Set the upload time of the report
             now = datetime.utcnow()
             results['time_upload'] = now.strftime("%Y-%m-%dT%H:%M:%SZ")
 
-            # Parse URL fragments and send data
-            url_fragments = urlparse.urlparse(report_url)
-            connection = httplib.HTTPConnection(url_fragments.netloc)
-            connection.request("POST", url_fragments.path, json.dumps(results),
-                               {"Content-type": "application/json"})
-        
+            # Send a POST request to the DB; the POST is implied by the body data
+            body = json.dumps(results)
+            request = urllib2.Request(report_url, body, {"Content-Type": "application/json"})
+
             # Get response which contains the id of the new document
-            response = connection.getresponse()
+            response = urllib2.urlopen(request)
             data = json.loads(response.read())
-            connection.close()
-
-            # Check if the report has been created
-            if not data['ok']:
-                print "Creating report document failed (%s)" % data
-                return data
 
             # Print document location to the console and return
             print "Report document created at '%s%s'" % (report_url, data['id'])
             return data
-        except Exception, e:
-            print "Sending results to '%s' failed (%s)." % (report_url, e)
+        except urllib2.HTTPError, e:
+            data = json.loads(e.read())
+            print "Sending results to '%s' failed (%s)." % (report_url, data['reason'])
+        except urllib2.URLError, e:
+            print "Sending results to '%s' failed (%s)." % (report_url, e.reason)
 
     def report(self, report_url):
         """print statistics and send the JSON report"""
         self.printStats()
 
         if report_url:
             results = self.get_report()
             return self.send_report(results, report_url)
@@ -701,34 +729,16 @@ class CLI(jsbridge.CLI):
         self.mozmill = self.mozmill_class(runner_class=mozrunner.FirefoxRunner,
                                           profile_class=mozrunner.FirefoxProfile,
                                           jsbridge_port=int(self.options.port),
                                           jsbridge_timeout=self.options.timeout,
                                           )
 
         self.tests = []
 
-        # read tests from manifests
-        if self.options.manifests:
-            manifest_parser = manifestparser.TestManifest(manifests=self.options.manifests)
-
-            self.tests.extend(manifest_parser.test_paths())
-
-        # expand user directory for individual tests
-        for test in self.options.test:
-            test = os.path.expanduser(test)
-            self.tests.append(test)
-                
-        # check existence for the tests
-        missing = [ test for test in self.tests
-                    if not os.path.exists(test) ]
-        if missing:
-            raise IOError("Not a valid test file/directory: %s" % ', '.join(["'%s'" % test for test in missing]))
-
-
         # setup log formatting
         self.mozmill.add_global_listener(LoggerListener())
         log_options = { 'format': "%(levelname)s | %(message)s",
                         'level': logging.CRITICAL }
         if self.options.showerrors:
             log_options['level'] = logging.ERROR
         if self.options.logfile:
             log_options['filename'] = self.options.logfile
@@ -740,16 +750,33 @@ class CLI(jsbridge.CLI):
 
     def get_profile(self, *args, **kwargs):
         profile = jsbridge.CLI.get_profile(self, *args, **kwargs)
         profile.install_addon(extension_path)
         return profile
 
     def run(self):
 
+        # read tests from manifests
+        if self.options.manifests:
+            manifest_parser = manifestparser.TestManifest(manifests=self.options.manifests)
+
+            self.tests.extend(manifest_parser.test_paths())
+
+        # expand user directory for individual tests
+        for test in self.options.test:
+            test = os.path.expanduser(test)
+            self.tests.append(test)
+                
+        # check existence for the tests
+        missing = [ test for test in self.tests
+                    if not os.path.exists(test) ]
+        if missing:
+            raise IOError("Not a valid test file/directory: %s" % ', '.join(["'%s'" % test for test in missing]))
+
         # create a Mozrunner
         runner = self.create_runner()
 
         runner.cmdargs.extend(self.options.appArgs)
 
         # make sure the application starts in the foreground
         if '-foreground' not in runner.cmdargs:
             runner.cmdargs.append('-foreground')
@@ -802,21 +829,27 @@ class CLI(jsbridge.CLI):
 class RestartCLI(CLI):
     mozmill_class = MozMillRestart
 
 
 class ThunderbirdCLI(CLI):
     profile_class = mozrunner.ThunderbirdProfile
     runner_class = mozrunner.ThunderbirdRunner
 
+class ThunderbirdRestartCLI(RestartCLI):
+    profile_class = mozrunner.ThunderbirdProfile
+    runner_class = mozrunner.ThunderbirdRunner
 
 def enum(*sequential, **named):
     enums = dict(zip(sequential, range(len(sequential))), **named)
     return type('Enum', (), enums)
 
 def cli():
     CLI().run()
 
 def tbird_cli():
     ThunderbirdCLI().run()
 
 def restart_cli():
     RestartCLI().run()
+
+def tbird_restart_cli():
+    ThunderbirdRestartCLI().run()
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
--- a/mail/test/resources/mozmill/mozmill/extension/content/overlay.js
+++ b/mail/test/resources/mozmill/mozmill/extension/content/overlay.js
@@ -1,11 +1,45 @@
-/* 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/. */
+/* ***** 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 Mozilla Corporation Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Adam Christian.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Adam Christian <adam.christian@gmail.com>
+ *  Mikeal Rogers <mikeal.rogers@gmail.com>
+ *
+ * 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 ***** */
 
 var mozmillInit = {}; Components.utils.import('resource://mozmill/modules/init.js', mozmillInit);
 
 var MozMill = {
   onLoad: function() {
     // initialization code
     this.initialized = true;
   },
old mode 100644
new mode 100755
old mode 100644
new mode 100755
--- a/mail/test/resources/mozmill/mozmill/extension/install.rdf
+++ b/mail/test/resources/mozmill/mozmill/extension/install.rdf
@@ -1,59 +1,51 @@
 <?xml version="1.0"?>
 <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:em="http://www.mozilla.org/2004/em-rdf#">
    <Description about="urn:mozilla:install-manifest">
      <em:id>mozmill@mozilla.com</em:id>
      <em:name>MozMill</em:name>
-     <em:version>1.5.6</em:version>
+     <em:version>1.5.16</em:version>
      <em:creator>Adam Christian</em:creator>
      <em:description>A testing extension based on the Windmill Testing Framework client source</em:description>
      <em:unpack>true</em:unpack>
      <em:targetApplication>
        <!-- Firefox -->
        <Description>
          <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
-         <em:minVersion>3.5</em:minVersion>
-         <em:maxVersion>15.*</em:maxVersion>
+         <em:minVersion>4.0</em:minVersion>
+         <em:maxVersion>20.*</em:maxVersion>
        </Description>
      </em:targetApplication>
      <em:targetApplication>
        <!-- Thunderbird -->
        <Description>
          <em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
-         <em:minVersion>3.0a1pre</em:minVersion>
-         <em:maxVersion>15.*</em:maxVersion>
+         <em:minVersion>5.0</em:minVersion>
+         <em:maxVersion>20.*</em:maxVersion>
        </Description>
      </em:targetApplication>
      <em:targetApplication>
        <!-- Sunbird -->
        <Description>
          <em:id>{718e30fb-e89b-41dd-9da7-e25a45638b28}</em:id>
-         <em:minVersion>0.6a1</em:minVersion>
-         <em:maxVersion>1.0pre</em:maxVersion>
+         <em:minVersion>1.0b5</em:minVersion>
+         <em:maxVersion>1.6b1</em:maxVersion>
        </Description>
      </em:targetApplication>
      <em:targetApplication>
        <!-- SeaMonkey -->
        <Description>
          <em:id>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</em:id>
-         <em:minVersion>2.0a1</em:minVersion>
-         <em:maxVersion>15.*</em:maxVersion>
+         <em:minVersion>2.1</em:minVersion>
+         <em:maxVersion>2.16</em:maxVersion>
        </Description>
      </em:targetApplication>
-	   <em:targetApplication>
-	      <!-- Songbird -->
-	      <Description>
-	        <em:id>songbird@songbirdnest.com</em:id>
-	        <em:minVersion>0.3pre</em:minVersion>
-	        <em:maxVersion>2.*</em:maxVersion>
-	      </Description>
-	   </em:targetApplication>
-	   <em:targetApplication>
+     <em:targetApplication>
          <Description>
           <em:id>toolkit@mozilla.org</em:id>
-          <em:minVersion>1.9.1</em:minVersion>
-          <em:maxVersion>15.*</em:maxVersion>
+          <em:minVersion>2.0</em:minVersion>
+          <em:maxVersion>20.*</em:maxVersion>
          </Description>
      </em:targetApplication>
    </Description>
 </RDF>
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
--- a/mail/test/resources/mozmill/mozmill/extension/resource/modules/frame.js
+++ b/mail/test/resources/mozmill/mozmill/extension/resource/modules/frame.js
@@ -34,17 +34,18 @@
 // the terms of any one of the MPL, the GPL or the LGPL.
 // 
 // ***** END LICENSE BLOCK *****
 
 var EXPORTED_SYMBOLS = ['loadFile','register_function','Collector','Runner','events', 
                         'jsbridge', 'runTestDirectory', 'runTestFile', 'log', 'getThread',
                         'timers', 'persisted'];
 
-var httpd = {};   Components.utils.import('resource://mozmill/stdlib/httpd.js', httpd);
+Components.utils.import('resource://mozmill/stdlib/httpd.js');
+
 var os = {};      Components.utils.import('resource://mozmill/stdlib/os.js', os);
 var strings = {}; Components.utils.import('resource://mozmill/stdlib/strings.js', strings);
 var arrays = {};  Components.utils.import('resource://mozmill/stdlib/arrays.js', arrays);
 var withs = {};   Components.utils.import('resource://mozmill/stdlib/withs.js', withs);
 var utils = {};   Components.utils.import('resource://mozmill/modules/utils.js', utils);
 var securableModule = {};
   Components.utils.import('resource://mozmill/stdlib/securable-module.js', securableModule);
 
@@ -64,17 +65,18 @@ var registeredFunctions = {};
 var persisted = {};
 
 arrayRemove = function(array, from, to) {
   var rest = array.slice((to || from) + 1 || array.length);
   array.length = from < 0 ? array.length + from : from;
   return array.push.apply(array, rest);
 };
 
-mozmill = undefined; elementslib = undefined;
+mozmill = undefined; elementslib = undefined; modules = undefined;
+
 var loadTestResources = function () {
   if (mozmill == undefined) {
     mozmill = {};
     Components.utils.import("resource://mozmill/modules/mozmill.js", mozmill);
   }
   if (elementslib == undefined) {
     elementslib = {};
     Components.utils.import("resource://mozmill/modules/elementslib.js", elementslib);
@@ -103,17 +105,22 @@ var loadFile = function(path, collector)
       defaultPrincipal: "system",
       globals : { mozmill: mozmill,
                   elementslib: elementslib,
                   persisted: persisted,
                   Cc: Components.classes,
                   Ci: Components.interfaces,
                   Cu: Components.utils }
     });
-    return loader.require(mod);
+    if (modules != undefined) {
+        loader.modules = modules;
+    }
+    var retval = loader.require(mod);
+    modules = loader.modules;
+    return retval;
   }
   
   if (collector != undefined) {
     collector.current_file = file;
     collector.current_path = path;
   }
   try {
     loader.loadSubScript(uri, module, "UTF-8");
@@ -318,18 +325,16 @@ try {
 
   aConsoleService.logStringMessage("jsbridge not available.");
 }
 
 if (jsbridge) {
   events.addListener('', function (name, obj) {jsbridge.fireEvent('mozmill.'+name, obj)} );
 }
 
-var http_server = httpd.getServer(43336);
-
 function Collector () {
   this.test_modules_by_filename = {};
   this.test_modules_by_name = {};
   this.requirements_run = {};
   this.all_requirements = [];
   this.loaded_directories = [];
   this.testing = [];
   this.httpd_started = false;
@@ -337,35 +342,55 @@ function Collector () {
   // var logging = {}; Components.utils.import('resource://mozmill/stdlib/logging.js', logging);
   // this.logger = new logging.Logger('Collector');
 }
 
 Collector.prototype.getModule = function (name) {
   return this.test_modules_by_name[name];
 }
 
+Collector.prototype.getServer = function (port, basePath) {
+  if (basePath) {
+    var lp = Cc["@mozilla.org/file/local;1"]
+             .createInstance(Ci.nsILocalFile);
+    lp.initWithPath(basePath);
+  }
+
+  var srv = new HttpServer();
+  if (lp) {
+    srv.registerDirectory("/", lp);
+  }
+
+  srv.registerContentType("sjs", "sjs");
+  srv.identity.setPrimary("http", "localhost", port);
+  srv._port = port;
+
+  return srv;
+}
+
 Collector.prototype.startHttpd = function () {
   while (this.httpd == undefined) {
     try {
+      var http_server = this.getServer(this.http_port);
       http_server.start(this.http_port);
       this.httpd = http_server;
-    } catch(e) { // Failure most likely due to port conflict
+    } catch (e) {
+      // Failure most likely due to port conflict
       this.http_port++;
-      http_server = httpd.getServer(this.http_port);
-    }; 
-    
-    
+    }
   }
 }
+
 Collector.prototype.stopHttpd = function () {
   if (this.httpd) {
     this.httpd.stop(function(){});  // Callback needed to pause execution until the server has been properly shutdown
     this.httpd = null;
   }
 }
+
 Collector.prototype.addHttpResource = function (directory, ns) {
   if (!this.httpd) {
     this.startHttpd();
   }
 
   if (!ns) {
     ns = '/';
   } else {
@@ -585,30 +610,31 @@ Runner.prototype._runTestModule = functi
       module[req] = this.collector.getModule(req);
     }
   }
 
   var attrs = [];
   for (var i in module) {
     attrs.push(i);
   }
-  
+
   events.setModule(module);
+  var observer = new AppQuitObserver();
+
   module.__status__ = 'running';
   if (module.__setupModule__) { 
     events.setState('setupModule');
     events.setTest(module.__setupModule__);
     this.wrapper(module.__setupModule__, module); 
     var setupModulePassed = (events.currentTest.__fails__.length == 0 && !events.currentTest.skipped);
     events.endTest(module.__setupModule__);
   } else {
     var setupModulePassed = true;
   }
   if (setupModulePassed) {
-    var observer = new AppQuitObserver();
     for (var i in module.__tests__) {
       events.appQuit = false;
       var test = module.__tests__[i];
       
       // TODO: introduce per-test timeout:
       // https://bugzilla.mozilla.org/show_bug.cgi?id=574871
 
       if (module.__setupTest__) { 
@@ -630,32 +656,35 @@ Runner.prototype._runTestModule = functi
       if (module.__teardownTest__) {
         events.setState('teardownTest'); 
         events.setTest(module.__teardownTest__);
         this.wrapper(module.__teardownTest__, test); 
         events.endTest(module.__teardownTest__);
       }
       events.endTest(test)
     }
-    observer.unregister();
   } else {
     for each(var test in module.__tests__) {
       events.setTest(test);
       events.skip("setupModule failed.");
       events.endTest(test);
     }
   }
   if (module.__teardownModule__) {
     events.setState('teardownModule');
     events.setTest(module.__teardownModule__);
     this.wrapper(module.__teardownModule__, module);
     events.endTest(module.__teardownModule__);
   }
+
+  observer.unregister();
+
   module.__status__ = 'done';
 }
+
 Runner.prototype.runTestModule = function (module) {
   if (module.__requirements__ != undefined && module.__force_skip__ == undefined) {
     if (!arrays.inArray(this.collector.loaded_directories, module.__root_path__)) {
       if (module.__root_path__ != undefined) {
         this.collector.initTestDirectory(module.__root_path__);
       }
     }
     var deps = this.getDependencies(module);
--- a/mail/test/resources/mozmill/mozmill/extension/resource/modules/init.js
+++ b/mail/test/resources/mozmill/mozmill/extension/resource/modules/init.js
@@ -1,11 +1,46 @@
-/* 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/. */
+/* ***** 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 Mozilla Corporation Code.
+ * 
+ * The Initial Developer of the Original Code is
+ * Adam Christian.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ * 
+ * Contributor(s):
+ *  Adam Christian <adam.christian@gmail.com>
+ *  Mikeal Rogers <mikeal.rogers@gmail.com>
+ *  Henrik Skupin <hskupin@mozilla.com>
+ * 
+ * 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 ***** */
 
 var EXPORTED_SYMBOLS = ["mozmill"];
   
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 var controller = Cu.import('resource://mozmill/modules/controller.js');
--- a/mail/test/resources/mozmill/mozmill/extension/resource/stdlib/EventUtils.js
+++ b/mail/test/resources/mozmill/mozmill/extension/resource/stdlib/EventUtils.js
@@ -1,14 +1,14 @@
 // Export all available functions for Mozmill
 var EXPORTED_SYMBOLS = ["sendMouseEvent", "sendChar", "sendString", "sendKey",
                         "synthesizeMouse", "synthesizeMouseScroll", "synthesizeKey",
                         "synthesizeMouseExpectEvent", "synthesizeKeyExpectEvent",
                         "synthesizeDragStart", "synthesizeDrop", "synthesizeText",
-                        "disableNonTestMouseEvents", "synthesizeComposition", 
+                        "disableNonTestMouseEvents", "synthesizeComposition",
                         "synthesizeQuerySelectedText", "synthesizeQueryTextContent",
                         "synthesizeQueryCaretRect", "synthesizeQueryTextRect",
                         "synthesizeQueryEditorRect", "synthesizeCharAtPoint",
                         "synthesizeSelectionSet"];
 
 /**
  * Get the array with available key events
  */
@@ -32,17 +32,17 @@ function getKeyEvent(aWindow) {
  * object with the properties set that the real mouse event object should
  * have. This includes the type of the mouse event.
  * E.g. to send an click event to the node with id 'node' you might do this:
  *
  * sendMouseEvent({type:'click'}, 'node');
  */
 function sendMouseEvent(aEvent, aTarget, aWindow) {
   if (['click', 'mousedown', 'mouseup', 'mouseover', 'mouseout'].indexOf(aEvent.type) == -1) {
-    throw new Error("sendMouseEvent doesn't know about event type '"+aEvent.type+"'");
+    throw new Error("sendMouseEvent doesn't know about event type '" + aEvent.type + "'");
   }
 
   if (!aWindow) {
     aWindow = window;
   }
 
   if (!(aTarget instanceof Element)) {
     aTarget = aWindow.document.getElementById(aTarget);
@@ -111,28 +111,29 @@ function sendChar(aChar, aTarget) {
 function sendString(aStr, aTarget) {
   for (var i = 0; i < aStr.length; ++i) {
     sendChar(aStr.charAt(i), aTarget);
   }
 }
 
 /**
  * Send the non-character key aKey to the node with id aTarget. If aTarget is
- * not provided, use "target".  The name of the key should be a lowercase
- * version of the part that comes after "DOM_VK_" in the KeyEvent constant
- * name for this key.  No modifiers are handled at this point.
+ * not provided, use "target".
+ * The name of the key should be the part that comes after "DOM_VK_" in the
+ *   KeyEvent constant name for this key.
+ * No modifiers are handled at this point.
  *
  * Returns true if the keypress event was accepted (no calls to preventDefault
  * or anything like that), false otherwise.
  */
 function sendKey(aKey, aTarget, aWindow) {
   if (!aWindow)
     aWindow = window;
 
-  keyName = "DOM_VK_" + aKey.toUpperCase();
+  var keyName = "DOM_VK_" + aKey.toUpperCase();
 
   if (!getKeyEvent(aWindow)[keyName]) {
     throw "Unknown key: " + keyName;
   }
 
   return __doEventDispatch(aTarget, 0, getKeyEvent(aWindow)[keyName], false);
 }
 
@@ -233,17 +234,17 @@ function synthesizeMouse(aTarget, aOffse
     var clickCount = aEvent.clickCount || 1;
     var modifiers = _parseModifiers(aEvent);
 
     var rect = aTarget.getBoundingClientRect();
 
     var left = rect.left + aOffsetX;
     var top = rect.top + aOffsetY;
 
-    if (aEvent.type) {
+    if (("type" in aEvent) && aEvent.type) {
       utils.sendMouseEvent(aEvent.type, left, top, button, clickCount, modifiers);
     }
     else {
       utils.sendMouseEvent("mousedown", left, top, button, clickCount, modifiers);
       utils.sendMouseEvent("mouseup", left, top, button, clickCount, modifiers);
     }
   }
 }
@@ -285,17 +286,17 @@ function synthesizeMouseScroll(aTarget, 
     var button = aEvent.button || 0;
     var modifiers = _parseModifiers(aEvent);
 
     var rect = aTarget.getBoundingClientRect();
 
     var left = rect.left;
     var top = rect.top;
 
-    var type = aEvent.type || "DOMMouseScroll";
+    var type = (("type" in aEvent) && aEvent.type) || "DOMMouseScroll";
     var axis = aEvent.axis || "vertical";
     var scrollFlags = (axis == "horizontal") ? kIsHorizontal : kIsVertical;
     if (aEvent.hasPixels) {
       scrollFlags |= kHasPixels;
     }
     utils.sendMouseScrollEvent(type, left + aOffsetX, top + aOffsetY, button,
                                scrollFlags, aEvent.delta, modifiers);
   }
@@ -327,25 +328,26 @@ function synthesizeKey(aKey, aEvent, aWi
     var keyCode = 0, charCode = 0;
     if (aKey.indexOf("VK_") == 0)
       keyCode = getKeyEvent(aWindow)["DOM_" + aKey];
     else
       charCode = aKey.charCodeAt(0);
 
     var modifiers = _parseModifiers(aEvent);
 
-    if (aEvent.type) {
-      utils.sendKeyEvent(aEvent.type, keyCode, charCode, modifiers);
-    }
-    else {
+    if (!("type" in aEvent) || !aEvent.type) {
+      // Send keydown + keypress + keyup events.
       var keyDownDefaultHappened =
           utils.sendKeyEvent("keydown", keyCode, charCode, modifiers);
       utils.sendKeyEvent("keypress", keyCode, charCode, modifiers,
                          !keyDownDefaultHappened);
       utils.sendKeyEvent("keyup", keyCode, charCode, modifiers);
+    } else {
+      // Send standalone event.
+      utils.sendKeyEvent(aEvent.type, keyCode, charCode, modifiers);
     }
   }
 }
 
 var _gSeenEvent = false;
 
 /**
  * Indicate that an event with an original target of aExpectedTarget and
@@ -693,18 +695,19 @@ function synthesizeText(aEvent, aWindow)
  * @param aWindow  Optional (If null, current |window| will be used)
  * @return         An nsIQueryContentEventResult object.  If this failed,
  *                 the result might be null.
  */
 function synthesizeQuerySelectedText(aWindow)
 {
   var utils = _getDOMWindowUtils(aWindow);
   if (!utils) {
-    return nsnull;
+    return null;
   }
+
   return utils.sendQueryContentEvent(utils.QUERY_SELECTED_TEXT, 0, 0, 0, 0);
 }
 
 /**
  * Synthesize a query text content event.
  *
  * @param aOffset  The character offset.  0 means the first character in the
  *                 selection root.
@@ -713,18 +716,19 @@ function synthesizeQuerySelectedText(aWi
  * @param aWindow  Optional (If null, current |window| will be used)
  * @return         An nsIQueryContentEventResult object.  If this failed,
  *                 the result might be null.
  */
 function synthesizeQueryTextContent(aOffset, aLength, aWindow)
 {
   var utils = _getDOMWindowUtils(aWindow);
   if (!utils) {
-    return nsnull;
+    return null;
   }
+
   return utils.sendQueryContentEvent(utils.QUERY_TEXT_CONTENT,
                                      aOffset, aLength, 0, 0);
 }
 
 /**
  * Synthesize a query caret rect event.
  *
  * @param aOffset  The caret offset.  0 means left side of the first character
@@ -732,18 +736,19 @@ function synthesizeQueryTextContent(aOff
  * @param aWindow  Optional (If null, current |window| will be used)
  * @return         An nsIQueryContentEventResult object.  If this failed,
  *                 the result might be null.
  */
 function synthesizeQueryCaretRect(aOffset, aWindow)
 {
   var utils = _getDOMWindowUtils(aWindow);
   if (!utils) {
-    return nsnull;
+    return null;
   }
+
   return utils.sendQueryContentEvent(utils.QUERY_CARET_RECT,
                                      aOffset, 0, 0, 0);
 }
 
 /**
  * Synthesize a query text rect event.
  *
  * @param aOffset  The character offset.  0 means the first character in the
@@ -753,52 +758,55 @@ function synthesizeQueryCaretRect(aOffse
  * @param aWindow  Optional (If null, current |window| will be used)
  * @return         An nsIQueryContentEventResult object.  If this failed,
  *                 the result might be null.
  */
 function synthesizeQueryTextRect(aOffset, aLength, aWindow)
 {
   var utils = _getDOMWindowUtils(aWindow);
   if (!utils) {
-    return nsnull;
+    return null;
   }
+
   return utils.sendQueryContentEvent(utils.QUERY_TEXT_RECT,
                                      aOffset, aLength, 0, 0);
 }
 
 /**
  * Synthesize a query editor rect event.
  *
  * @param aWindow  Optional (If null, current |window| will be used)
  * @return         An nsIQueryContentEventResult object.  If this failed,
  *                 the result might be null.
  */
 function synthesizeQueryEditorRect(aWindow)
 {
   var utils = _getDOMWindowUtils(aWindow);
   if (!utils) {
-    return nsnull;
+    return null;
   }
+
   return utils.sendQueryContentEvent(utils.QUERY_EDITOR_RECT, 0, 0, 0, 0);
 }
 
 /**
  * Synthesize a character at point event.
  *
  * @param aX, aY   The offset in the client area of the DOM window.
  * @param aWindow  Optional (If null, current |window| will be used)
  * @return         An nsIQueryContentEventResult object.  If this failed,
  *                 the result might be null.
  */
 function synthesizeCharAtPoint(aX, aY, aWindow)
 {
   var utils = _getDOMWindowUtils(aWindow);
   if (!utils) {
-    return nsnull;
+    return null;
   }
+
   return utils.sendQueryContentEvent(utils.QUERY_CHARACTER_AT_POINT,
                                      0, 0, aX, aY);
 }
 
 /**
  * Synthesize a selection set event.
  *
  * @param aOffset  The character offset.  0 means the first character in the
@@ -811,10 +819,11 @@ function synthesizeCharAtPoint(aX, aY, a
  * @return         True, if succeeded.  Otherwise false.
  */
 function synthesizeSelectionSet(aOffset, aLength, aReverse, aWindow)
 {
   var utils = _getDOMWindowUtils(aWindow);
   if (!utils) {
     return false;
   }
+
   return utils.sendSelectionSetEvent(aOffset, aLength, aReverse);
 }
--- a/mail/test/resources/mozmill/mozmill/extension/resource/stdlib/httpd.js
+++ b/mail/test/resources/mozmill/mozmill/extension/resource/stdlib/httpd.js
@@ -5,26 +5,46 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * An implementation of an HTTP server both as a loadable script and as an XPCOM
  * component.  See the accompanying README file for user documentation on
  * httpd.js.
  */
 
+const EXPORTED_SYMBOLS = [
+  "HTTP_400",
+  "HTTP_401",
+  "HTTP_402",
+  "HTTP_403",
+  "HTTP_404",
+  "HTTP_405",
+  "HTTP_406",
+  "HTTP_407",
+  "HTTP_408",
+  "HTTP_409",
+  "HTTP_410",
+  "HTTP_411",
+  "HTTP_412",
+  "HTTP_413",
+  "HTTP_414",
+  "HTTP_415",
+  "HTTP_417",
+  "HTTP_500",
+  "HTTP_501",
+  "HTTP_502",
+  "HTTP_503",
+  "HTTP_504",
+  "HTTP_505",
+  "HttpError",
+  "HttpServer",
+];
+
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
-var EXPORTED_SYMBOLS = ['getServer'];
-
-/**
- * Overwrite both dump functions because we do not wanna have this output for Mozmill
- */
-function dump() {}
-function dumpn() {}
-
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 const CC = Components.Constructor;
 
 const PR_UINT32_MAX = Math.pow(2, 32) - 1;
 
@@ -488,22 +508,22 @@ nsHttpServer.prototype =
       throw Cr.NS_ERROR_ALREADY_INITIALIZED;
 
     this._port = port;
     this._doQuit = this._socketClosed = false;
 
     this._host = host;
 
     // The listen queue needs to be long enough to handle
-    // network.http.max-connections-per-server concurrent connections,
+    // network.http.max-persistent-connections-per-server concurrent connections,
     // plus a safety margin in case some other process is talking to
     // the server as well.
     var prefs = getRootPrefBranch();
     var maxConnections =
-      prefs.getIntPref("network.http.max-connections-per-server") + 5;
+      prefs.getIntPref("network.http.max-persistent-connections-per-server") + 5;
 
     try
     {
       var loopback = true;
       if (this._host != "127.0.0.1" && this._host != "localhost") {
         var loopback = false;
       }
 
@@ -583,16 +603,24 @@ nsHttpServer.prototype =
   // see nsIHttpServer.registerPathHandler
   //
   registerPathHandler: function(path, handler)
   {
     this._handler.registerPathHandler(path, handler);
   },
 
   //
+  // see nsIHttpServer.registerPrefixHandler
+  //
+  registerPrefixHandler: function(prefix, handler)
+  {
+    this._handler.registerPrefixHandler(prefix, handler);
+  },
+
+  //
   // see nsIHttpServer.registerErrorHandler
   //
   registerErrorHandler: function(code, handler)
   {
     this._handler.registerErrorHandler(code, handler);
   },
 
   //
@@ -754,29 +782,34 @@ nsHttpServer.prototype =
     NS_ASSERT(this._connections[connection.number] === connection,
               "connection number mismatch?  " +
               this._connections[connection.number]);
     delete this._connections[connection.number];
 
     // Fire a pending server-stopped notification if it's our responsibility.
     if (!this._hasOpenConnections() && this._socketClosed)
       this._notifyStopped();
+    // Bug 508125: Add a GC here else we'll use gigabytes of memory running
+    // mochitests. We can't rely on xpcshell doing an automated GC, as that
+    // would interfere with testing GC stuff...
+    Components.utils.forceGC();
   },
 
   /**
    * Requests that the server be shut down when possible.
    */
   _requestQuit: function()
   {
     dumpn(">>> requesting a quit");
     dumpStack();
     this._doQuit = true;
   }
 };
 
+var HttpServer = nsHttpServer;
 
 //
 // RFC 2396 section 3.2.2:
 //
 // host        = hostname | IPv4address
 // hostname    = *( domainlabel "." ) toplabel [ "." ]
 // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
 // toplabel    = alpha | alpha *( alphanum | "-" ) alphanum
@@ -1601,25 +1634,31 @@ RequestReader.prototype =
     dumpn("*** _parseRequestLine('" + line + "')");
 
     var metadata = this._metadata;
 
     // clients and servers SHOULD accept any amount of SP or HT characters
     // between fields, even though only a single SP is required (section 19.3)
     var request = line.split(/[ \t]+/);
     if (!request || request.length != 3)
+    {
+      dumpn("*** No request in line");
       throw HTTP_400;
+    }
 
     metadata._method = request[0];
 
     // get the HTTP version
     var ver = request[2];
     var match = ver.match(/^HTTP\/(\d+\.\d+)$/);
     if (!match)
+    {
+      dumpn("*** No HTTP version in line");
       throw HTTP_400;
+    }
 
     // determine HTTP version
     try
     {
       metadata._httpVersion = new nsHttpVersion(match[1]);
       if (!metadata._httpVersion.atLeast(nsHttpVersion.HTTP_1_0))
         throw "unsupported HTTP version";
     }
@@ -1634,47 +1673,61 @@ RequestReader.prototype =
     var serverIdentity = this._connection.server.identity;
 
     var scheme, host, port;
 
     if (fullPath.charAt(0) != "/")
     {
       // No absolute paths in the request line in HTTP prior to 1.1
       if (!metadata._httpVersion.atLeast(nsHttpVersion.HTTP_1_1))
+      {
+        dumpn("*** Metadata version too low");
         throw HTTP_400;
+      }
 
       try
       {
         var uri = Cc["@mozilla.org/network/io-service;1"]
                     .getService(Ci.nsIIOService)
                     .newURI(fullPath, null, null);
         fullPath = uri.path;
         scheme = uri.scheme;
         host = metadata._host = uri.asciiHost;
         port = uri.port;
         if (port === -1)
         {
           if (scheme === "http")
+          {
             port = 80;
+          }
           else if (scheme === "https")
+          {
             port = 443;
+          }
           else
+          {
+            dumpn("*** Unknown scheme: " + scheme);
             throw HTTP_400;
+          }
         }
       }
       catch (e)
       {
         // If the host is not a valid host on the server, the response MUST be a
         // 400 (Bad Request) error message (section 5.2).  Alternately, the URI
         // is malformed.
+        dumpn("*** Threw when dealing with URI: " + e);
         throw HTTP_400;
       }
 
       if (!serverIdentity.has(scheme, host, port) || fullPath.charAt(0) != "/")
+      {
+        dumpn("*** serverIdentity unknown or path does not start with '/'");
         throw HTTP_400;
+      }
     }
 
     var splitter = fullPath.indexOf("?");
     if (splitter < 0)
     {
       // _queryString already set in ctor
       metadata._path = fullPath;
     }
@@ -1708,45 +1761,48 @@ RequestReader.prototype =
 
     var headers = this._metadata._headers;
     var lastName = this._lastHeaderName;
     var lastVal = this._lastHeaderValue;
 
     var line = {};
     while (true)
     {
+      dumpn("*** Last name: '" + lastName + "'");
+      dumpn("*** Last val: '" + lastVal + "'");
       NS_ASSERT(!((lastVal === undefined) ^ (lastName === undefined)),
                 lastName === undefined ?
                   "lastVal without lastName?  lastVal: '" + lastVal + "'" :
                   "lastName without lastVal?  lastName: '" + lastName + "'");
 
       if (!data.readLine(line))
       {
         // save any data we have from the header we might still be processing
         this._lastHeaderName = lastName;
         this._lastHeaderValue = lastVal;
         return false;
       }
 
       var lineText = line.value;
+      dumpn("*** Line text: '" + lineText + "'");
       var firstChar = lineText.charAt(0);
 
       // blank line means end of headers
       if (lineText == "")
       {
         // we're finished with the previous header
         if (lastName)
         {
           try
           {
             headers.setHeader(lastName, lastVal, true);
           }
           catch (e)
           {
-            dumpn("*** e == " + e);
+            dumpn("*** setHeader threw on last header, e == " + e);
             throw HTTP_400;
           }
         }
         else
         {
           // no headers in request -- valid for HTTP/1.0 requests
         }
 
@@ -1754,17 +1810,17 @@ RequestReader.prototype =
         this._state = READER_IN_BODY;
         return true;
       }
       else if (firstChar == " " || firstChar == "\t")
       {
         // multi-line header if we've already seen a header line
         if (!lastName)
         {
-          // we don't have a header to continue!
+          dumpn("We don't have a header to continue!");
           throw HTTP_400;
         }
 
         // append this line's text to the value; starts with SP/HT, so no need
         // for separating whitespace
         lastVal += lineText;
       }
       else
@@ -1773,25 +1829,25 @@ RequestReader.prototype =
         if (lastName)
         {
           try
           {
             headers.setHeader(lastName, lastVal, true);
           }
           catch (e)
           {
-            dumpn("*** e == " + e);
+            dumpn("*** setHeader threw on a header, e == " + e);
             throw HTTP_400;
           }
         }
 
         var colon = lineText.indexOf(":"); // first colon must be splitter
         if (colon < 1)
         {
-          // no colon or missing header field-name
+          dumpn("*** No colon or missing header field-name");
           throw HTTP_400;
         }
 
         // set header name, value (to be set in the next loop, usually)
         lastName = lineText.substring(0, colon);
         lastVal = lineText.substring(colon + 1);
       } // empty, continuation, start of header
     } // while (true)
@@ -1806,48 +1862,68 @@ const CR = 0x0D, LF = 0x0A;
  * Calculates the number of characters before the first CRLF pair in array, or
  * -1 if the array contains no CRLF pair.
  *
  * @param array : Array
  *   an array of numbers in the range [0, 256), each representing a single
  *   character; the first CRLF is the lowest index i where
  *   |array[i] == "\r".charCodeAt(0)| and |array[i+1] == "\n".charCodeAt(0)|,
  *   if such an |i| exists, and -1 otherwise
+ * @param start : uint
+ *   start index from which to begin searching in array
  * @returns int
  *   the index of the first CRLF if any were present, -1 otherwise
  */
-function findCRLF(array)
+function findCRLF(array, start)
 {
-  for (var i = array.indexOf(CR); i >= 0; i = array.indexOf(CR, i + 1))
+  for (var i = array.indexOf(CR, start); i >= 0; i = array.indexOf(CR, i + 1))
   {
     if (array[i + 1] == LF)
       return i;
   }
   return -1;
 }
 
 
 /**
  * A container which provides line-by-line access to the arrays of bytes with
  * which it is seeded.
  */
 function LineData()
 {
   /** An array of queued bytes from which to get line-based characters. */
   this._data = [];
+
+  /** Start index from which to search for CRLF. */
+  this._start = 0;
 }
 LineData.prototype =
 {
   /**
    * Appends the bytes in the given array to the internal data cache maintained
    * by this.
    */
   appendBytes: function(bytes)
   {
-    Array.prototype.push.apply(this._data, bytes);
+    var count = bytes.length;
+    var quantum = 262144; // just above half SpiderMonkey's argument-count limit
+    if (count < quantum)
+    {
+      Array.prototype.push.apply(this._data, bytes);
+      return;
+    }
+
+    // Large numbers of bytes may cause Array.prototype.push to be called with
+    // more arguments than the JavaScript engine supports.  In that case append
+    // bytes in fixed-size amounts until all bytes are appended.
+    for (var start = 0; start < count; start += quantum)
+    {
+      var slice = bytes.slice(start, Math.min(start + quantum, count));
+      Array.prototype.push.apply(this._data, slice);
+    }
   },
 
   /**
    * Removes and returns a line of data, delimited by CRLF, from this.
    *
    * @param out
    *   an object whose "value" property will be set to the first line of text
    *   present in this, sans CRLF, if this contains a full CRLF-delimited line
@@ -1855,33 +1931,48 @@ LineData.prototype =
    *   is undefined
    * @returns boolean
    *   true if a full line of data could be read from the data in this, false
    *   otherwise
    */
   readLine: function(out)
   {
     var data = this._data;
-    var length = findCRLF(data);
+    var length = findCRLF(data, this._start);
     if (length < 0)
+    {
+      this._start = data.length;
+
+      // But if our data ends in a CR, we have to back up one, because
+      // the first byte in the next packet might be an LF and if we
+      // start looking at data.length we won't find it.
+      if (data.length > 0 && data[data.length - 1] === CR)
+        --this._start;
+
       return false;
+    }
+
+    // Reset for future lines.
+    this._start = 0;
 
     //
     // We have the index of the CR, so remove all the characters, including
-    // CRLF, from the array with splice, and convert the removed array into the
-    // corresponding string, from which we then strip the trailing CRLF.
+    // CRLF, from the array with splice, and convert the removed array
+    // (excluding the trailing CRLF characters) into the corresponding string.
     //
-    // Getting the line in this matter acknowledges that substring is an O(1)
-    // operation in SpiderMonkey because strings are immutable, whereas two
-    // splices, both from the beginning of the data, are less likely to be as
-    // cheap as a single splice plus two extra character conversions.
-    //
-    var line = String.fromCharCode.apply(null, data.splice(0, length + 2));
-    out.value = line.substring(0, length);
-
+    var leading = data.splice(0, length + 2);
+    var quantum = 262144;
+    var line = "";
+    for (var start = 0; start < length; start += quantum)
+    {
+      var slice = leading.slice(start, Math.min(start + quantum, length));
+      line += String.fromCharCode.apply(null, slice);
+    }
+
+    out.value = line;
     return true;
   },
 
   /**
    * Removes the bytes currently within this and returns them in an array.
    *
    * @returns Array
    *   the bytes within this when this method is called
@@ -2143,17 +2234,26 @@ function ServerHandler(server)
 
   /**
    * Custom request handlers for the server in which this resides.  Path-handler
    * pairs are stored as property-value pairs in this property.
    *
    * @see ServerHandler.prototype._defaultPaths
    */
   this._overridePaths = {};
-  
+
+  /**
+   * Custom request handlers for the path prefixes on the server in which this
+   * resides.  Path-handler pairs are stored as property-value pairs in this
+   * property.
+   *
+   * @see ServerHandler.prototype._defaultPaths
+   */
+  this._overridePrefixes = {};
+
   /**
    * Custom request handlers for the error handlers in the server in which this
    * resides.  Path-handler pairs are stored as property-value pairs in this
    * property.
    *
    * @see ServerHandler.prototype._defaultErrors
    */
   this._overrideErrors = {};
@@ -2208,17 +2308,33 @@ ServerHandler.prototype =
         {
           // explicit paths first, then files based on existing directory mappings,
           // then (if the file doesn't exist) built-in server default paths
           dumpn("calling override for " + path);
           this._overridePaths[path](request, response);
         }
         else
         {
-          this._handleDefault(request, response);
+          var longestPrefix = "";
+          for (let prefix in this._overridePrefixes) {
+            if (prefix.length > longestPrefix.length &&
+                path.substr(0, prefix.length) == prefix)
+            {
+              longestPrefix = prefix;
+            }
+          }
+          if (longestPrefix.length > 0)
+          {
+            dumpn("calling prefix override for " + longestPrefix);
+            this._overridePrefixes[longestPrefix](request, response);
+          }
+          else
+          {
+            this._handleDefault(request, response);
+          }
         }
       }
       catch (e)
       {
         if (response.partiallySent())
         {
           response.abort(e);
           return;
@@ -2314,16 +2430,28 @@ ServerHandler.prototype =
     // XXX true path validation!
     if (path.charAt(0) != "/")
       throw Cr.NS_ERROR_INVALID_ARG;
 
     this._handlerToField(handler, this._overridePaths, path);
   },
 
   //
+  // see nsIHttpServer.registerPrefixHandler
+  //
+  registerPrefixHandler: function(path, handler)
+  {
+    // XXX true path validation!
+    if (path.charAt(0) != "/" || path.charAt(path.length - 1) != "/")
+      throw Cr.NS_ERROR_INVALID_ARG;
+
+    this._handlerToField(handler, this._overridePrefixes, path);
+  },
+
+  //
   // see nsIHttpServer.registerDirectory
   //
   registerDirectory: function(path, directory)
   {
     // strip off leading and trailing '/' so that we can use lastIndexOf when
     // determining exactly how a path maps onto a mapped directory --
     // conditional is required here to deal with "/".substring(1, 0) being
     // converted to "/".substring(0, 1) per the JS specification
@@ -2453,26 +2581,32 @@ ServerHandler.prototype =
 
     var start, end;
     if (metadata._httpVersion.atLeast(nsHttpVersion.HTTP_1_1) &&
         metadata.hasHeader("Range") &&
         this._getTypeFromFile(file) !== SJS_TYPE)
     {
       var rangeMatch = metadata.getHeader("Range").match(/^bytes=(\d+)?-(\d+)?$/);
       if (!rangeMatch)
+      {
+        dumpn("*** Range header bogosity: '" + metadata.getHeader("Range") + "'");
         throw HTTP_400;
+      }
 
       if (rangeMatch[1] !== undefined)
         start = parseInt(rangeMatch[1], 10);
 
       if (rangeMatch[2] !== undefined)
         end = parseInt(rangeMatch[2], 10);
 
       if (start === undefined && end === undefined)
+      {
+        dumpn("*** More Range header bogosity: '" + metadata.getHeader("Range") + "'");
         throw HTTP_400;
+      }
 
       // No start given, so the end is really the count of bytes from the
       // end of the file.
       if (start === undefined)
       {
         start = Math.max(0, file.fileSize - end);
         end   = file.fileSize - 1;
       }
@@ -2569,16 +2703,20 @@ ServerHandler.prototype =
         s.importFunction(function getObjectState(k, callback)
         {
           callback(self._getObjectState(k));
         });
         s.importFunction(function setObjectState(k, v)
         {
           self._setObjectState(k, v);
         });
+        s.importFunction(function registerPathHandler(p, h)
+        {
+          self.registerPathHandler(p, h);
+        });
 
         // Make it possible for sjs files to access their location
         this._setState(path, "__LOCATION__", file.path);
 
         try
         {
           // Alas, the line number in errors dumped to console when calling the
           // request handler is simply an offset from where we load the SJS file.
@@ -2873,16 +3011,17 @@ ServerHandler.prototype =
   {
     // decode and add underscores as necessary
     try
     {
       path = toInternalPath(path, true);
     }
     catch (e)
     {
+      dumpn("*** toInternalPath threw " + e);
       throw HTTP_400; // malformed path
     }
 
     // next, get the directory which contains this path
     var pathMap = this._pathDirectoryMap;
 
     // An example progression of tmp for a path "/foo/bar/baz/" might be:
     // "foo/bar/baz/", "foo/bar/baz", "foo/bar", "foo", ""
@@ -4564,17 +4703,20 @@ const headerUtils =
    *   if fieldName does not match the field-name production in RFC 2616
    * @returns string
    *   fieldName converted to lowercase if it is a valid header, for characters
    *   where case conversion is possible
    */
   normalizeFieldName: function(fieldName)
   {
     if (fieldName == "")
+    {
+      dumpn("*** Empty fieldName");
       throw Cr.NS_ERROR_INVALID_ARG;
+    }
 
     for (var i = 0, sz = fieldName.length; i < sz; i++)
     {
       if (!IS_TOKEN_ARRAY[fieldName.charCodeAt(i)])
       {
         dumpn(fieldName + " is not a valid header field name!");
         throw Cr.NS_ERROR_INVALID_ARG;
       }
@@ -4615,19 +4757,23 @@ const headerUtils =
     // SP before interpreting the field value or forwarding the message
     // downstream (section 4.2); we replace 1*LWS with a single SP
     var val = fieldValue.replace(/(?:(?:\r\n)?[ \t]+)+/g, " ");
 
     // remove leading/trailing LWS (which has been converted to SP)
     val = val.replace(/^ +/, "").replace(/ +$/, "");
 
     // that should have taken care of all CTLs, so val should contain no CTLs
+    dumpn("*** Normalized value: '" + val + "'");
     for (var i = 0, len = val.length; i < len; i++)
       if (isCTL(val.charCodeAt(i)))
+      {
+        dump("*** Char " + i + " has charcode " + val.charCodeAt(i));
         throw Cr.NS_ERROR_INVALID_ARG;
+      }
 
     // XXX disallows quoted-pair where CHAR is a CTL -- will not invalidly
     //     normalize, however, so this can be construed as a tightening of the
     //     spec and not entirely as a bug
     return val;
   }
 };
 
@@ -5081,20 +5227,18 @@ Request.prototype =
   {
     if (!this._bag)
       this._bag = new WritablePropertyBag();
   }
 };
 
 
 // XPCOM trappings
-if (XPCOMUtils.generateNSGetFactory)
-  var NSGetFactory = XPCOMUtils.generateNSGetFactory([nsHttpServer]);
-else
-  var NSGetModule = XPCOMUtils.generateNSGetModule([nsHttpServer]);
+
+var NSGetFactory = XPCOMUtils.generateNSGetFactory([nsHttpServer]);
 
 /**
  * Creates a new HTTP server listening for loopback traffic on the given port,
  * starts it, and runs the server until the server processes a shutdown request,
  * spinning an event loop so that events posted by the server's socket are
  * processed.
  *
  * This method is primarily intended for use in running this script from within
@@ -5142,25 +5286,8 @@ function server(port, basePath)
     thread.processNextEvent(true);
 
   // get rid of any pending requests
   while (thread.hasPendingEvents())
     thread.processNextEvent(true);
 
   DEBUG = false;
 }
-
-function getServer (port, basePath) {
-  if (basePath) {
-    var lp = Cc["@mozilla.org/file/local;1"]
-               .createInstance(Ci.nsILocalFile);
-    lp.initWithPath(basePath);
-   }
-
-   var srv = new nsHttpServer();
-   if (lp)
-     srv.registerDirectory("/", lp);
-   srv.registerContentType("sjs", SJS_TYPE);
-   srv.identity.setPrimary("http", "localhost", port);
-   srv._port = port;
-
-   return srv;
-}
--- a/mail/test/resources/mozmill/mozmill/extension/resource/stdlib/securable-module.js
+++ b/mail/test/resources/mozmill/mozmill/extension/resource/stdlib/securable-module.js
@@ -1,11 +1,43 @@
-/* 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/. */
+/* ***** 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 Jetpack.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * 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 ***** */
 
 (function(global) {
    const Cc = Components.classes;
    const Ci = Components.interfaces;
    const Cu = Components.utils;
    const Cr = Components.results;
 
    var exports = {};
old mode 100644
new mode 100755
deleted file mode 100644
--- a/mail/test/resources/mozmill/patches/httpd.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-diff --git a/mozmill/mozmill/extension/resource/stdlib/httpd.js b/mozmill/mozmill/extension/resource/stdlib/httpd.js
-index cf974b3..35a8d36 100644
---- a/mozmill/mozmill/extension/resource/stdlib/httpd.js
-+++ b/mozmill/mozmill/extension/resource/stdlib/httpd.js
-@@ -48,6 +48,14 @@
- 
- Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
- 
-+var EXPORTED_SYMBOLS = ['getServer'];
-+
-+/**
-+ * Overwrite both dump functions because we do not wanna have this output for Mozmill
-+ */
-+function dump() {}
-+function dumpn() {}
-+
- const Cc = Components.classes;
- const Ci = Components.interfaces;
- const Cr = Components.results;
-@@ -5173,3 +5181,20 @@ function server(port, basePath)
- 
-   DEBUG = false;
- }
-+
-+function getServer (port, basePath) {
-+  if (basePath) {
-+    var lp = Cc["@mozilla.org/file/local;1"]
-+               .createInstance(Ci.nsILocalFile);
-+    lp.initWithPath(basePath);
-+   }
-+
-+   var srv = new nsHttpServer();
-+   if (lp)
-+     srv.registerDirectory("/", lp);
-+   srv.registerContentType("sjs", SJS_TYPE);
-+   srv.identity.setPrimary("http", "localhost", port);
-+   srv._port = port;
-+
-+   return srv;
-+}
--- a/mail/test/resources/mozmill/scripts/sync_dependencies.py
+++ b/mail/test/resources/mozmill/scripts/sync_dependencies.py
@@ -1,30 +1,57 @@
-# 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/.
+# ***** 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 Mozilla Corporation Code.
+#
+# The Initial Developer of the Original Code is the Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2010
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Henrik Skupin <hskupin@gmail.com>
+#
+# 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 *****
 
 import os
 import subprocess
 import urllib
 
 abs_path = os.path.dirname(os.path.abspath(__file__))
 root_path = os.path.dirname(abs_path)
 
 # We need the latest version of Event Utils
 externalModules = [
     {   # EventUtils.js
         "url": "http://hg.mozilla.org/mozilla-central/raw-file/default/testing/mochitest/tests/SimpleTest/EventUtils.js",
         "path": "mozmill/extension/resource/stdlib/EventUtils.js",
         "patch": "patches/eventUtils.patch"
-    },
-    {   # httpd.js
-        "url": "http://hg.mozilla.org/mozilla-central/raw-file/default/netwerk/test/httpserver/httpd.js",
-        "path": "mozmill/extension/resource/stdlib/httpd.js",
-        "patch": "patches/httpd.patch"
     }
 ]
 
 
 # Change into the root folder to update and patch external modules correctly
 os.chdir(root_path)
 
 for module in externalModules:
--- a/mail/test/resources/mozmill/setup.py
+++ b/mail/test/resources/mozmill/setup.py
@@ -1,19 +1,52 @@
-# 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/.
+# ***** 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 Mozilla Corporation Code.
+#
+# The Initial Developer of the Original Code is
+# Mikeal Rogers.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Mikeal Rogers <mikeal.rogers@gmail.com>
+#
+# 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 *****
 
 from setuptools import setup, find_packages
 
 desc = """UI Automation tool for Mozilla applications."""
 summ = """A tool for full UI automation of Mozilla applications."""
 
 PACKAGE_NAME = "mozmill"
-PACKAGE_VERSION = "1.5.6"
+PACKAGE_VERSION = "1.5.16"
 
 setup(name=PACKAGE_NAME,
       version=PACKAGE_VERSION,
       description=desc,
       long_description=summ,
       author='Mozilla, Mikeal Rogers',
       author_email='mikeal.rogers@gmail.com',
       url='http://github.com/mozautomation/mozmill',
@@ -24,18 +57,18 @@ setup(name=PACKAGE_NAME,
       zip_safe=False,
       entry_points="""
           [console_scripts]
           mozmill = mozmill:cli
           mozmill-thunderbird = mozmill:tbird_cli
           mozmill-restart = mozmill:restart_cli
         """,
       platforms =['Any'],
-      install_requires = ['jsbridge == 2.4.6',
-                          'mozrunner == 2.5.7',
+      install_requires = ['jsbridge == 2.4.14',
+                          'mozrunner == 2.5.13',
                           'ManifestDestiny == 0.2.2'],
       classifiers=['Development Status :: 4 - Beta',
                    'Environment :: Console',
                    'Intended Audience :: Developers',
                    'License :: OSI Approved :: Apache Software License',
                    'Operating System :: OS Independent',
                    'Topic :: Software Development :: Libraries :: Python Modules',
                   ]
--- a/mail/test/resources/mozmill/test/restart/test_user_restart/test5.js
+++ b/mail/test/resources/mozmill/test/restart/test_user_restart/test5.js
@@ -1,12 +1,8 @@
-var setupModule = function(module) {
+var setupModule = function () {
   controller = mozmill.getBrowserController();
 }
 
-/**
- * This test should fail and then exit with a 'Disconnect Error: Application Unexpectedly Closed'
- */
-var testRestartAfterTimeout = function(){
+var teardownModule = function () {
   controller.startUserShutdown(1000, true);
-  controller.sleep(2000);
   controller.window.Application.restart();
 }
--- a/mail/test/resources/mozrunner/mozrunner/__init__.py
+++ b/mail/test/resources/mozrunner/mozrunner/__init__.py
@@ -1,11 +1,46 @@
-# 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/.
+# ***** 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 Mozilla Corporation Code.
+#
+# The Initial Developer of the Original Code is
+# Mikeal Rogers.
+# Portions created by the Initial Developer are Copyright (C) 2008-2009
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Mikeal Rogers <mikeal.rogers@gmail.com>
+#  Clint Talbert <ctalbert@mozilla.com>
+#  Henrik Skupin <hskupin@mozilla.com>
+#
+# 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 *****
 
 import os
 import sys
 import copy
 import tempfile
 import commands
 import zipfile
 import optparse
@@ -288,16 +323,18 @@ class FirefoxProfile(Profile):
                    # Don't install distribution add-ons from the app folder
                    'extensions.installDistroAddons' : False,
                    # Dont' run the add-on compatibility check during start-up
                    'extensions.showMismatchUI' : False,
                    # Don't automatically update add-ons
                    'extensions.update.enabled' : False,
                    # Don't open a dialog to show available add-on updates
                    'extensions.update.notifyUser' : False,
+                   # Enable test mode to run multiple tests in parallel
+                   'focusmanager.testmode' : True,
 
                    # Disable addon compatibility checks
                    'extensions.checkCompatibility' : False,
                    'extensions.checkCompatibility.4.0' : False,
                    'extensions.checkCompatibility.4.0b' : False,
                    'extensions.checkCompatibility.4.2' : False,
                    'extensions.checkCompatibility.4.2a' : False,
                    'extensions.checkCompatibility.4.2b' : False,
@@ -337,41 +374,40 @@ class ThunderbirdProfile(Profile):
                    'browser.sessionstore.resume_from_crash': False,
                    }
     names = ["thunderbird", "shredder"]
 
 
 class Runner(object):
     """Handles all running operations. Finds bins, runs and kills the process."""
 
-    def __init__(self, binary=None, profile=None, cmdargs=[], env=None, kp_kwargs={}):
+    def __init__(self, binary=None, profile=None, cmdargs=None, env=None, kp_kwargs={}):
 
         self.process_handler = None
 
         # find the binary
         if binary is None:
             self.binary = self.find_binary()
         elif sys.platform == 'darwin' and binary.find('Contents/MacOS/') == -1:
             self.binary = os.path.join(binary, 'Contents/MacOS/%s-bin' % self.names[0])
         else:
             self.binary = binary
         if not os.path.exists(self.binary):
             raise Exception("Binary path does not exist "+self.binary)
 
-        
         if sys.platform.startswith('linux') and self.binary.endswith('-bin'):
             dirname = os.path.dirname(self.binary)
             if os.environ.get('LD_LIBRARY_PATH', None):
                 os.environ['LD_LIBRARY_PATH'] = '%s:%s' % (os.environ['LD_LIBRARY_PATH'], dirname)
             else:
                 os.environ['LD_LIBRARY_PATH'] = dirname
 
         self.profile = profile
 
-        self.cmdargs = cmdargs
+        self.cmdargs = cmdargs or []
         if env is None:
             self.env = copy.copy(os.environ)
             self.env.update({'MOZ_NO_REMOTE':"1",})
         else:
             self.env = env
         self.kp_kwargs = kp_kwargs
 
     def find_binary(self):
--- a/mail/test/resources/mozrunner/mozrunner/killableprocess.py
+++ b/mail/test/resources/mozrunner/mozrunner/killableprocess.py
@@ -67,17 +67,20 @@ except ImportError:
             self.returncode = returncode
             self.cmd = cmd
         def __str__(self):
             return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
 
 mswindows = (sys.platform == "win32")
 
 if mswindows:
+    from ctypes import sizeof, addressof, c_ulong, byref, POINTER, WinError, c_longlong
     import winprocess
+    from qijo import JobObjectExtendedLimitInformation, JOBOBJECT_BASIC_LIMIT_INFORMATION,\
+    JOBOBJECT_EXTENDED_LIMIT_INFORMATION, IO_COUNTERS
 else:
     import signal
 
 def call(*args, **kwargs):
     waitargs = {}
     if "timeout" in kwargs:
         waitargs["timeout"] = kwargs.pop("timeout")
 
@@ -152,16 +155,44 @@ class Popen(subprocess.Popen):
             self._thread = ht
             self.pid = pid
             self.tid = tid
 
             if canCreateJob:
                 # We create a new job for this process, so that we can kill
                 # the process and any sub-processes 
                 self._job = winprocess.CreateJobObject()
+                # Allow subprocesses to break away from us - necessary for
+                # flash with protected mode
+                jbli = JOBOBJECT_BASIC_LIMIT_INFORMATION(
+                                c_longlong(0), # per process time limit (ignored)
+                                c_longlong(0), # per job user time limit (ignored)
+                                winprocess.JOB_OBJECT_LIMIT_BREAKAWAY_OK,
+                                0, # min working set (ignored)
+                                0, # max working set (ignored)
+                                0, # active process limit (ignored)
+                                None, # affinity (ignored)
+                                0, # Priority class (ignored)
+                                0, # Scheduling class (ignored)
+                                )
+
+                iocntr = IO_COUNTERS()
+                jeli = JOBOBJECT_EXTENDED_LIMIT_INFORMATION(
+                                jbli, # basic limit info struct
+                                iocntr,    # io_counters (ignored)
+                                0,    # process mem limit (ignored)
+                                0,    # job mem limit (ignored)
+                                0,    # peak process limit (ignored)
+                                0)    # peak job limit (ignored)
+
+                winprocess.SetInformationJobObject(self._job,
+                                JobObjectExtendedLimitInformation,
+                                addressof(jeli),
+                                sizeof(jeli)
+                                )
                 winprocess.AssignProcessToJobObject(self._job, int(hp))
             else:
                 self._job = None
 
             winprocess.ResumeThread(int(ht))
             ht.Close()
 
             if p2cread is not None:
@@ -184,16 +215,26 @@ class Popen(subprocess.Popen):
             self.returncode = 127    
         else:
             if group:
                 try:
                     os.killpg(self.pid, signal.SIGKILL)
                 except: pass
             else:
                 os.kill(self.pid, signal.SIGKILL)
+
+            # If we don't call os.wait() we end up with zombie processes
+            # see bug 658509, but it seems to traceback on linux
+            if sys.platform == "darwin":
+                try:
+                    os.wait()
+                except OSError, e:
+                    # The process doesn't exist anymore so we can ignore it
+                    pass
+
             self.returncode = -9
 
     def wait(self, timeout=None, group=True):
         """Wait for the process to terminate. Returns returncode attribute.
         If timeout seconds are reached and the process has not terminated,
         it will be forcefully killed. If timeout is -1, wait will not
         time out."""
         if timeout is not None:
--- a/mail/test/resources/mozrunner/mozrunner/winprocess.py
+++ b/mail/test/resources/mozrunner/mozrunner/winprocess.py
@@ -198,16 +198,32 @@ CREATE_UNICODE_ENVIRONMENT = 0x00000400
 JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800
 JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000
 
 # XXX these flags should be documented
 DEBUG_ONLY_THIS_PROCESS = 0x00000002
 DEBUG_PROCESS = 0x00000001
 DETACHED_PROCESS = 0x00000008
 
+# SetInformationJobObject
+SetInformationJobObjectProto = WINFUNCTYPE(BOOL, # Return Type
+                                           HANDLE, # Job Handle
+                                           DWORD, # Type of Class next param is
+                                           LPVOID, # Job Object Class
+                                           DWORD # Job Object Class Length
+                                          )
+SetInformationJobObjectProtoFlags = ((1, "hJob", None),
+                                     (1, "JobObjectInfoClass", None),
+                                     (1, "lpJobObjectInfo", None),
+                                     (1, "cbJobObjectInfoLength", 0))
+SetInformationJobObject = SetInformationJobObjectProto(("SetInformationJobObject",
+                                                        windll.kernel32),
+                                                        SetInformationJobObjectProtoFlags)
+SetInformationJobObject.errcheck = ErrCheckBool
+
 # CreateJobObject()
 
 CreateJobObjectProto = WINFUNCTYPE(HANDLE,             # Return type
                                    LPVOID,             # lpJobAttributes
                                    LPCWSTR             # lpName
                                    )
 
 CreateJobObjectFlags = ((1, "lpJobAttributes", None),
--- a/mail/test/resources/mozrunner/setup.py
+++ b/mail/test/resources/mozrunner/setup.py
@@ -1,19 +1,52 @@
-# 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/.
+# ***** 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 Mozilla Corporation Code.
+#
+# The Initial Developer of the Original Code is
+# Mikeal Rogers.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Mikeal Rogers <mikeal.rogers@gmail.com>
+#
+# 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 *****
 
 from setuptools import setup, find_packages
 import sys
 
 desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
 
 PACKAGE_NAME = "mozrunner"
-PACKAGE_VERSION = "2.5.7"
+PACKAGE_VERSION = "2.5.13"
 
 deps = []
 
 # we only support python 2 right now
 assert sys.version_info[0] == 2
 
 # version-dependent dependencies
 if sys.version_info[1] < 6: