Part of Bug 758326 - Port bug 481815 - Provide a Windows service to update applications without asking Administrator password. r=Standard8,ui-review=bwinton
authorNomis101@web.de
Mon, 04 Jun 2012 15:03:22 +0100
changeset 12322 981ac3d7e71438e2c9bf9a8c030ded796c8fbd99
parent 12321 9b6d79b4c4cf20538bc05e432e72ed714f4d8ff5
child 12323 9db1e7ed1ad9844c226ff4fb11547e69cf8c375d
push id599
push usermconley@mozilla.com
push dateMon, 16 Jul 2012 20:33:12 +0000
treeherdercomm-beta@c3489d5b7b65 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersStandard8
bugs758326, 481815
Part of Bug 758326 - Port bug 481815 - Provide a Windows service to update applications without asking Administrator password. r=Standard8,ui-review=bwinton
config/autoconf.mk.in
configure.in
mail/Makefile.in
mail/app/profile/all-thunderbird.js
mail/base/content/aboutDialog.js
mail/components/preferences/advanced.js
mail/components/preferences/advanced.xul
mail/confvars.sh
mail/installer/package-manifest.in
mail/installer/removed-files.in
mail/installer/windows/Makefile.in
mail/installer/windows/nsis/defines.nsi.in
mail/installer/windows/nsis/installer.nsi
mail/installer/windows/nsis/maintenanceservice_installer.nsi
mail/installer/windows/nsis/shared.nsh
mail/installer/windows/nsis/uninstaller.nsi
mail/locales/en-US/chrome/messenger/preferences/advanced.dtd
mail/locales/en-US/installer/custom.properties
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -17,16 +17,18 @@ SUNBIRD_VERSION = @SUNBIRD_VERSION@
 SEAMONKEY_VERSION	= @SEAMONKEY_VERSION@
 
 MOZ_BUILD_APP = @MOZ_BUILD_APP@
 MOZ_APP_NAME	= @MOZ_APP_NAME@
 MOZ_APP_DISPLAYNAME = @MOZ_APP_DISPLAYNAME@
 MOZ_APP_VERSION = @MOZ_APP_VERSION@
 MOZ_APP_MAXVERSION = @MOZ_APP_MAXVERSION@
 MOZ_MACBUNDLE_NAME= @MOZ_MACBUNDLE_NAME@
+MAR_CHANNEL_ID = @MAR_CHANNEL_ID@
+ACCEPTED_MAR_CHANNEL_IDS = @ACCEPTED_MAR_CHANNEL_IDS@
 
 MOZ_PKG_SPECIAL = @MOZ_PKG_SPECIAL@
 
 prefix		= @prefix@
 exec_prefix	= @exec_prefix@
 bindir		= @bindir@
 includedir	= @includedir@/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
 libdir		= @libdir@
@@ -82,16 +84,18 @@ MOZ_CALENDAR	= @MOZ_CALENDAR@
 MOZ_PLAINTEXT_EDITOR_ONLY = @MOZ_PLAINTEXT_EDITOR_ONLY@
 MOZ_COMPOSER = @MOZ_COMPOSER@
 ENABLE_TESTS	= @ENABLE_TESTS@
 IBMBIDI = @IBMBIDI@
 MOZ_UNIVERSALCHARDET = @MOZ_UNIVERSALCHARDET@
 ACCESSIBILITY = @ACCESSIBILITY@
 MOZ_LDAP_XPCOM = @MOZ_LDAP_XPCOM@
 MOZ_BRANDING_DIRECTORY = @MOZ_BRANDING_DIRECTORY@
+MOZ_MAINTENANCE_SERVICE	= @MOZ_MAINTENANCE_SERVICE@
+MOZ_VERIFY_MAR_SIGNATURE	= @MOZ_VERIFY_MAR_SIGNATURE@
 MOZ_UPDATER	= @MOZ_UPDATER@
 MOZ_UPDATE_CHANNEL = @MOZ_UPDATE_CHANNEL@
 MOZ_UPDATE_PACKAGING	= @MOZ_UPDATE_PACKAGING@
 MOZ_NO_ACTIVEX_SUPPORT = @MOZ_NO_ACTIVEX_SUPPORT@
 MOZ_SPELLCHECK = @MOZ_SPELLCHECK@
 MOZ_PROFILELOCKING = @MOZ_PROFILELOCKING@
 MOZ_FEEDS = @MOZ_FEEDS@
 MOZ_PLACES = @MOZ_PLACES@
--- a/configure.in
+++ b/configure.in
@@ -5331,16 +5331,50 @@ AC_MSG_RESULT([$TAR])
 AC_SUBST(TAR)
 
 AC_MSG_CHECKING([for wget])
 AC_CHECK_PROGS(WGET, wget, "")
 AC_MSG_RESULT([$WGET])
 AC_SUBST(WGET)
 
 dnl ========================================================
+dnl Maintenance Service
+dnl ========================================================
+
+MOZ_ARG_ENABLE_BOOL(maintenance-service,
+[  --enable-maintenance-service       Enable building of maintenanceservice],
+    MOZ_MAINTENANCE_SERVICE=1,
+    MOZ_MAINTENANCE_SERVICE= )
+
+if test -n "$MOZ_MAINTENANCE_SERVICE"; then
+  if test "$OS_ARCH" = "WINNT"; then
+    AC_DEFINE(MOZ_MAINTENANCE_SERVICE)
+  else
+    AC_MSG_ERROR([Can only build with --enable-maintenance-service with a Windows target])
+  fi
+fi
+
+dnl ========================================================
+dnl Verify MAR signatures
+dnl ========================================================
+
+MOZ_ARG_ENABLE_BOOL(verify-mar,
+[  --enable-verify-mar     Enable verifying MAR signatures],
+    MOZ_VERIFY_MAR_SIGNATURE=1,
+    MOZ_VERIFY_MAR_SIGNATURE= )
+
+if test -n "$MOZ_VERIFY_MAR_SIGNATURE"; then
+  if test "$OS_ARCH" = "WINNT"; then
+    AC_DEFINE(MOZ_VERIFY_MAR_SIGNATURE)
+  else
+    AC_MSG_ERROR([Can only build with --enable-verify-mar with a Windows target])
+  fi
+fi
+
+dnl ========================================================
 dnl Updater
 dnl ========================================================
 
 MOZ_ARG_DISABLE_BOOL(updater,
 [  --disable-updater       Disable building of updater],
     MOZ_UPDATER=,
     MOZ_UPDATER=1 )
 AC_SUBST(MOZ_UPDATER)
@@ -6734,16 +6768,18 @@ AC_SUBST(MOZ_PROFILELOCKING)
 
 AC_SUBST(ENABLE_TESTS)
 AC_SUBST(IBMBIDI)
 AC_SUBST(MOZ_UNIVERSALCHARDET)
 AC_SUBST(ACCESSIBILITY)
 AC_SUBST(MOZ_SPELLCHECK)
 AC_SUBST(MOZ_USER_DIR)
 AC_SUBST(MOZ_CRASHREPORTER)
+AC_SUBST(MOZ_MAINTENANCE_SERVICE)
+AC_SUBST(MOZ_VERIFY_MAR_SIGNATURE)
 AC_SUBST(MOZ_ANGLE)
 AC_SUBST(MOZ_DIRECTX_SDK_PATH)
 AC_SUBST(MOZ_DIRECTX_SDK_CPU_SUFFIX)
 AC_SUBST(MOZ_D3DX9_VERSION)
 AC_SUBST(MOZ_D3DX9_CAB)
 AC_SUBST(MOZ_D3DCOMPILER_CAB)
 AC_SUBST(MOZ_D3DX9_DLL)
 AC_SUBST(MOZ_D3DCOMPILER_DLL)
@@ -6803,16 +6839,18 @@ if test -z "$IS_ALPHA"; then
 else
   MOZ_APP_MAXVERSION=$MOZ_APP_VERSION
 fi
 
 AC_SUBST(MOZ_APP_NAME)
 AC_SUBST(MOZ_APP_DISPLAYNAME)
 AC_SUBST(MOZ_APP_VERSION)
 AC_SUBST(MOZ_APP_MAXVERSION)
+AC_SUBST(MAR_CHANNEL_ID)
+AC_SUBST(ACCEPTED_MAR_CHANNEL_IDS)
 AC_SUBST(FIREFOX_VERSION)
 AC_SUBST(THUNDERBIRD_VERSION)
 AC_SUBST(SUNBIRD_VERSION)
 AC_SUBST(SEAMONKEY_VERSION)
 
 AC_SUBST(MOZ_PKG_SPECIAL)
 
 AC_SUBST(MAIL_PKG_SHARED)
--- a/mail/Makefile.in
+++ b/mail/Makefile.in
@@ -29,9 +29,12 @@ endif
 
 include $(topsrcdir)/config/rules.mk
 
 ifeq ($(OS_ARCH),WINNT)
 # For Windows build the uninstaller during the application build since the
 # uninstaller is included with the application for mar file generation.
 libs::
 	$(MAKE) -C installer/windows uninstaller
+ifdef MOZ_MAINTENANCE_SERVICE
+	$(MAKE) -C installer/windows maintenanceservice_installer
 endif
+endif
\ No newline at end of file
--- a/mail/app/profile/all-thunderbird.js
+++ b/mail/app/profile/all-thunderbird.js
@@ -79,16 +79,21 @@ pref("app.update.idletime", 60);
 
 // Whether or not we show a dialog box informing the user that the update was
 // successfully applied. This is off in Firefox by default since we show a 
 // upgrade start page instead! Other apps may wish to show this UI, and supply
 // a whatsNewURL field in their brand.properties that contains a link to a page
 // which tells users what's new in this new update.
 pref("app.update.showInstalledUI", false);
 
+// Whether or not to attempt using the service for updates.
+#ifdef MOZ_MAINTENANCE_SERVICE
+pref("app.update.service.enabled", true);
+#endif
+
 // Release notes URL
 pref("app.releaseNotesURL", "http://live.mozillamessaging.com/%APP%/releasenotes?locale=%LOCALE%&version=%VERSION%&os=%OS%&buildid=%APPBUILDID%");
 
 // Base URL for web-based support pages.
 pref("app.support.baseURL", "http://support.live.mozillamessaging.com/%LOCALE%/%APP%/%APPBUILDID%/");
 
 // Controls enabling of the extension system logging (can reduce performance)
 pref("extensions.logging.enabled", false);
--- a/mail/base/content/aboutDialog.js
+++ b/mail/base/content/aboutDialog.js
@@ -169,19 +169,23 @@ function appUpdater()
 
 appUpdater.prototype =
 {
   // true when there is an update check in progress.
   isChecking: false,
 
   // true when there is an update already staged / ready to be applied.
   get isPending() {
-    if (this.update)
-      return this.update.state == "pending";
-    return this.um.activeUpdate && this.um.activeUpdate.state == "pending";
+    if (this.update) {
+      return this.update.state == "pending" || 
+             this.update.state == "pending-service";
+    }
+    return this.um.activeUpdate &&
+           (this.um.activeUpdate.state == "pending" ||
+            this.um.activeUpdate.state == "pending-service");
   },
 
   // true when there is an update download in progress.
   get isDownloading() {
     if (this.update)
       return this.update.state == "downloading";
     return this.um.activeUpdate &&
            this.um.activeUpdate.state == "downloading";
--- a/mail/components/preferences/advanced.js
+++ b/mail/components/preferences/advanced.js
@@ -226,16 +226,36 @@ var gAdvancedPane = {
     var autoPref = document.getElementById("app.update.auto");
     var modePref = document.getElementById("app.update.mode");
 
     var warnIncompatible = document.getElementById("warnIncompatible");
 
     var disable = enabledPref.locked || !enabledPref.value || autoPref.locked ||
                   !autoPref.value || modePref.locked;
     warnIncompatible.disabled = disable;
+
+#ifdef MOZ_MAINTENANCE_SERVICE
+    // Check to see if the maintenance service is installed.
+    // If it is don't show the preference at all.
+    var installed;
+    try {
+      Components.utils.reportError("0");
+      var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
+                .createInstance(Components.interfaces.nsIWindowsRegKey);
+      wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
+               "SOFTWARE\\Mozilla\\MaintenanceService",
+               wrk.ACCESS_READ | wrk.WOW64_64);
+      installed = wrk.readIntValue("Installed");
+      wrk.close();
+    } catch(e) {
+    }
+    if (installed != 1) {
+      document.getElementById("useService").hidden = true;
+    }
+#endif
   },
 
   /**
    * app.update.mode is a three state integer preference, and we have to 
    * express all three values in a single checkbox:
    * "Warn me if this will disable extensions or themes"
    * Preference Value         Checkbox State    Meaning
    * 0                        Unchecked         Do not warn
--- a/mail/components/preferences/advanced.xul
+++ b/mail/components/preferences/advanced.xul
@@ -91,16 +91,22 @@
                             gAdvancedPane.updateModeItems();"/>
       <preference id="app.update.auto" name="app.update.auto" type="bool"
                   onchange="gAdvancedPane.updateAutoItems(); gAdvancedPane.updateModeItems();"/>
       <preference id="app.update.mode" name="app.update.mode" type="int"
                   onchange="gAdvancedPane.updateModeItems();"/>
       <preference id="app.update.disable_button.showUpdateHistory"
                   name="app.update.disable_button.showUpdateHistory"
                   type="bool"/>
+
+#ifdef MOZ_MAINTENANCE_SERVICE
+      <preference id="app.update.service.enabled"
+                  name="app.update.service.enabled"
+                  type="bool"/>
+#endif
 #endif
       <preference id="extensions.update.enabled" name="extensions.update.enabled" type="bool"
                   onchange="gAdvancedPane.updateAddonUpdateUI();"/>
       <!-- Certificates tab -->
       <preference id="security.default_personal_cert"
                   name="security.default_personal_cert"
                   type="string"/>
       <preference id="security.disable_button.openCertManager"
@@ -353,16 +359,23 @@
           </radiogroup>
           <separator/>
           <hbox>
             <button id="showUpdateHistory"
                     label="&showUpdates.label;" accesskey="&showUpdates.accesskey;"
                     preference="app.update.disable_button.showUpdateHistory"
                     oncommand="gAdvancedPane.showUpdates();"/>
           </hbox>
+
+#ifdef MOZ_MAINTENANCE_SERVICE
+            <checkbox id="useService"
+                      label="&useService.label;"
+                      accesskey="&useService.accesskey;"
+                      preference="app.update.service.enabled"/>
+#endif
 #endif
         </tabpanel>
 
         <!-- Certificates -->
         <tabpanel orient="vertical">
           <description id="CertSelectionDesc" control="certSelection">&certSelection.description;</description>
 
           <!--
--- a/mail/confvars.sh
+++ b/mail/confvars.sh
@@ -8,22 +8,35 @@ MOZ_UPDATER=1
 MOZ_THUNDERBIRD=1
 MOZ_CHROME_FILE_FORMAT=omni
 MOZ_NO_ACTIVEX_SUPPORT=1
 MOZ_ACTIVEX_SCRIPTING_SUPPORT=
 if [ "$COMM_BUILD" ]; then
   MOZ_LDAP_XPCOM=1
 fi
 MOZ_COMPOSER=1
+if test "$OS_ARCH" = "WINNT"; then
+  if ! test "$HAVE_64BIT_OS"; then
+    MOZ_VERIFY_MAR_SIGNATURE=1
+    MOZ_MAINTENANCE_SERVICE=1
+  fi
+fi
+
 MOZ_SAFE_BROWSING=1
 MOZ_MORK=1
 if test -z "$MOZ_INCOMPLETE_EXTERNAL_LINKAGE"; then
 MOZ_APP_COMPONENT_LIBS="xpautocomplete mailcomps $MAIL_COMPONENT $LDAP_COMPONENT $MORK_COMPONENT"
 MOZ_APP_COMPONENT_MODULES="MODULE(xpAutoComplete) MODULE(nsMailCompsModule) $MAIL_MODULE $LDAP_MODULE $MORK_MODULE"
 MOZ_APP_EXTRA_LIBS="$LDAP_LIBS"
 fi
 
 MOZ_APP_VERSION_TXT=${_topsrcdir}/$MOZ_BUILD_APP/config/version.txt
 MOZ_APP_VERSION=`cat $MOZ_APP_VERSION_TXT`
 THUNDERBIRD_VERSION=$MOZ_APP_VERSION
 
 MOZ_BRANDING_DIRECTORY=mail/branding/nightly
 MOZ_OFFICIAL_BRANDING_DIRECTORY=other-licenses/branding/thunderbird
+# This should usually be the same as the value MAR_CHANNEL_ID.
+# If more than one ID is needed, then you should use a comma separated list
+# of values.
+ACCEPTED_MAR_CHANNEL_IDS=thunderbird-comm-central
+# The MAR_CHANNEL_ID must not contain the following 3 characters: ",\t "
+MAR_CHANNEL_ID=thunderbird-comm-central
--- a/mail/installer/package-manifest.in
+++ b/mail/installer/package-manifest.in
@@ -109,16 +109,17 @@
 [mail]
 #ifndef XP_UNIX
 @BINPATH@/@MOZ_APP_NAME@.exe
 #else
 @BINPATH@/@MOZ_APP_NAME@-bin
 @BINPATH@/@MOZ_APP_NAME@
 #endif
 @BINPATH@/application.ini
+@BINPATH@/update-settings.ini
 @BINPATH@/blocklist.xml
 @BINPATH@/platform.ini
 #ifdef XP_OS2
 @BINPATH@/@DLL_PREFIX@mozsqlt3@DLL_SUFFIX@
 #else
 @BINPATH@/@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@
 #endif
 #ifdef UNIX_BUT_NOT_MAC
@@ -710,16 +711,23 @@
 
 ; [Updater]
 #ifdef XP_MACOSX
 @BINPATH@/updater.app/
 #else
 @BINPATH@/updater@BIN_SUFFIX@
 #endif
 
+; [MaintenanceService]
+;
+#ifdef MOZ_MAINTENANCE_SERVICE
+@BINPATH@/maintenanceservice.exe
+@BINPATH@/maintenanceservice_installer.exe
+#endif
+
 ; [crash reporter]
 #ifdef XP_MACOSX
 @BINPATH@/crashreporter.app/
 #else
 #ifndef XP_OS2
 @BINPATH@/crashreporter@BIN_SUFFIX@
 @BINPATH@/crashreporter.ini
 #ifdef XP_UNIX
--- a/mail/installer/removed-files.in
+++ b/mail/installer/removed-files.in
@@ -1174,8 +1174,12 @@ components/xmlextras.xpt
     components/filepicker.xpt
     components/toolkitremote.xpt
     components/websrvcs.xpt
   #endif
 #endif
 # ****************************************************************************
 # * End of XPTs at the time we started linking them on Linux and Mac.        *
 # ****************************************************************************
+#ifndef MOZ_MAINTENANCE_SERVICE
+maintenanceservice.exe
+maintenanceservice_installer.exe
+#endif
\ No newline at end of file
--- a/mail/installer/windows/Makefile.in
+++ b/mail/installer/windows/Makefile.in
@@ -24,16 +24,23 @@ endif
 
 INSTALLER_FILES = \
 	app.tag \
 	nsis/installer.nsi \
 	nsis/uninstaller.nsi \
 	nsis/shared.nsh \
 	$(NULL)
 
+ifdef MOZ_MAINTENANCE_SERVICE
+INSTALLER_FILES += \
+	nsis/maintenanceservice_installer.nsi \
+	$(NULL)
+endif
+
+
 BRANDING_FILES = \
 	branding.nsi \
 	wizHeader.bmp \
 	wizHeaderRTL.bmp \
 	wizWatermark.bmp \
 	$(NULL)
 
 DEFINES += \
@@ -56,16 +63,27 @@ uninstaller::
 	$(INSTALL) $(addprefix $(srcdir)/,$(INSTALLER_FILES)) $(CONFIG_DIR)
 	$(INSTALL) $(addprefix $(DIST)/branding/,$(BRANDING_FILES)) $(CONFIG_DIR)
 	$(PYTHON) $(MOZILLA_SRCDIR)/config/Preprocessor.py -Fsubstitution $(DEFINES) $(ACDEFINES) \
 	  $(srcdir)/nsis/defines.nsi.in > $(CONFIG_DIR)/defines.nsi
 	$(PYTHON) $(MOZILLA_SRCDIR)/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py \
 	  --preprocess-locale $(MOZILLA_SRCDIR) \
 	  $(call EXPAND_LOCALE_SRCDIR,mail/locales)/installer $(AB_CD) $(CONFIG_DIR)
 
+# For building the maintenanceservice installer
+ifdef MOZ_MAINTENANCE_SERVICE
+maintenanceservice_installer::
+	$(INSTALL) $(addprefix $(srcdir)/,$(INSTALLER_FILES)) $(CONFIG_DIR)
+	$(PYTHON) $(MOZILLA_SRCDIR)/config/Preprocessor.py -Fsubstitution $(DEFINES) $(ACDEFINES) \
+	  $(srcdir)/nsis/defines.nsi.in > $(CONFIG_DIR)/defines.nsi
+	$(PYTHON) $(MOZILLA_SRCDIR)/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py \
+	  --preprocess-locale $(MOZILLA_SRCDIR) \
+	  $(call EXPAND_LOCALE_SRCDIR,mail/locales)/installer $(AB_CD) $(CONFIG_DIR)
+endif
+
 $(CONFIG_DIR)/setup.exe::
 	$(RM) -r $(CONFIG_DIR) && mkdir $(CONFIG_DIR)
 	$(INSTALL) $(addprefix $(srcdir)/,$(INSTALLER_FILES)) $(CONFIG_DIR)
 	$(INSTALL) $(addprefix $(DIST)/branding/,$(BRANDING_FILES)) $(CONFIG_DIR)
 	$(PYTHON) $(MOZILLA_SRCDIR)/config/Preprocessor.py -Fsubstitution $(DEFINES) $(ACDEFINES) \
 	  $(srcdir)/nsis/defines.nsi.in > $(CONFIG_DIR)/defines.nsi
 	$(PYTHON) $(MOZILLA_SRCDIR)/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py \
 	  --preprocess-locale $(MOZILLA_SRCDIR) \
--- a/mail/installer/windows/nsis/defines.nsi.in
+++ b/mail/installer/windows/nsis/defines.nsi.in
@@ -18,16 +18,19 @@
 !define AppRegNameNews        "Thunderbird (News)"
 
 !define ClientsRegName        "Mozilla Thunderbird"
 
 !define BrandShortName        "@MOZ_APP_DISPLAYNAME@"
 !define PreReleaseSuffix      "@PRE_RELEASE_SUFFIX@"
 !define BrandFullName         "${BrandFullNameInternal}${PreReleaseSuffix}"
 
+!define CERTIFICATE_NAME      "Mozilla Corporation"
+!define CERTIFICATE_ISSUER    "Thawte Code Signing CA - G2"
+
 # NO_INSTDIR_FROM_REG is defined for pre-releases which have a PreReleaseSuffix
 # (e.g. Alpha X, Beta X, etc.) to prevent finding a non-default installation
 # directory in the registry and using that as the default. This prevents
 # Beta releases built with official branding from finding an existing install
 # of an official release and defaulting to its installation directory.
 !if "@PRE_RELEASE_SUFFIX@" != ""
 !define NO_INSTDIR_FROM_REG
 !endif
@@ -38,16 +41,20 @@
 !define HAVE_64BIT_OS
 !define ARCH "x64"
 !define MinSupportedVer "Microsoft Windows Vista x64"
 #else
 !define ARCH "x86"
 !define MinSupportedVer "Microsoft Windows XP SP2"
 #endif
 
+#ifdef MOZ_MAINTENANCE_SERVICE
+!define MOZ_MAINTENANCE_SERVICE
+#endif
+
 # File details shared by both the installer and uninstaller
 VIProductVersion "1.0.0.0"
 VIAddVersionKey "ProductName"     "${BrandShortName}"
 VIAddVersionKey "CompanyName"     "${CompanyName}"
 #ifdef MOZ_OFFICIAL_BRANDING
 VIAddVersionKey "LegalTrademarks" "${BrandShortName} is a Trademark of The Mozilla Foundation."
 #endif
 VIAddVersionKey "LegalCopyright"  "${CompanyName}"
--- a/mail/installer/windows/nsis/installer.nsi
+++ b/mail/installer/windows/nsis/installer.nsi
@@ -1,17 +1,19 @@
 # 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/.
 
 # Required Plugins:
-# AppAssocReg http://nsis.sourceforge.net/Application_Association_Registration_plug-in
-# CityHash    http://mxr.mozilla.org/mozilla-central/source/other-licenses/nsis/Contrib/CityHash
-# ShellLink   http://nsis.sourceforge.net/ShellLink_plug-in
-# UAC         http://nsis.sourceforge.net/UAC_plug-in
+# AppAssocReg    http://nsis.sourceforge.net/Application_Association_Registration_plug-in
+# ApplicationID  http://nsis.sourceforge.net/ApplicationID_plug-in
+# CityHash       http://mxr.mozilla.org/mozilla-central/source/other-licenses/nsis/Contrib/CityHash
+# ShellLink      http://nsis.sourceforge.net/ShellLink_plug-in
+# UAC            http://nsis.sourceforge.net/UAC_plug-in
+# ServicesHelper Mozilla specific plugin that is located in /other-licenses/nsis
 
 ; Set verbosity to 3 (e.g. no script) to lessen the noise in the build logs
 !verbose 3
 
 ; 7-Zip provides better compression than the lzma from NSIS so we add the files
 ; uncompressed and use 7-Zip to create a SFX archive of it
 SetDatablockOptimize on
 SetCompress off
@@ -21,16 +23,17 @@ RequestExecutionLevel user
 
 !addplugindir ./
 
 Var TmpVal
 Var InstallType
 Var AddStartMenuSC
 Var AddQuickLaunchSC
 Var AddDesktopSC
+Var InstallMaintenanceService
 Var PageName
 
 ; By defining NO_STARTMENU_DIR an installer that doesn't provide an option for
 ; an application's Start Menu PROGRAMS directory and doesn't define the
 ; StartMenuDir variable can use the common InstallOnInitCommon macro.
 !define NO_STARTMENU_DIR
 
 ; On Vista and above attempt to elevate Standard Users in addition to users that
@@ -70,16 +73,17 @@ VIAddVersionKey "OriginalFilename" "setu
 !insertmacro ChangeMUIHeaderImage
 !insertmacro CheckForFilesInUse
 !insertmacro CleanUpdatesDir
 !insertmacro CopyFilesFromDir
 !insertmacro GetPathFromString
 !insertmacro GetParent
 !insertmacro InitHashAppModelId
 !insertmacro IsHandlerForInstallDir
+!insertmacro IsUserAdmin
 !insertmacro LogDesktopShortcut
 !insertmacro LogQuickLaunchShortcut
 !insertmacro LogStartMenuShortcut
 !insertmacro ManualCloseAppPrompt
 !insertmacro RegCleanMain
 !insertmacro RegCleanUninstall
 !insertmacro SetBrandNameVars
 !insertmacro UpdateShortcutAppModelIDs
@@ -138,16 +142,21 @@ ShowInstDetails nevershow
 Page custom preOptions leaveOptions
 
 ; Select Install Directory Page
 !define MUI_PAGE_CUSTOMFUNCTION_PRE preDirectory
 !define MUI_PAGE_CUSTOMFUNCTION_LEAVE leaveDirectory
 !define MUI_DIRECTORYPAGE_VERIFYONLEAVE
 !insertmacro MUI_PAGE_DIRECTORY
 
+; Custom Components Page
+!ifdef MOZ_MAINTENANCE_SERVICE
+Page custom preComponents leaveComponents
+!endif
+
 ; Custom Shortcuts Page
 Page custom preShortcuts leaveShortcuts
 
 ; Custom Summary Page
 Page custom preSummary leaveSummary
 
 ; Install Files Page
 !insertmacro MUI_PAGE_INSTFILES
@@ -349,16 +358,47 @@ Section "-Application" APP_IDX
     ${If} $AddQuickLaunchSC == 1
     ${OrIf} $AddDesktopSC == 1
       WriteRegDWORD HKLM "$0" "IconsVisible" 1
     ${Else}
       WriteRegDWORD HKLM "$0" "IconsVisible" 0
     ${EndIf}
   ${EndIf}
 
+!ifdef MOZ_MAINTENANCE_SERVICE
+  ; If the maintenance service page was displayed then a value was already 
+  ; explicitly selected for installing the maintenance service and 
+  ; and so InstallMaintenanceService will already be 0 or 1.
+  ; If the maintenance service page was not displayed then 
+  ; InstallMaintenanceService will be equal to "".
+  ${If} $InstallMaintenanceService == ""
+    Call IsUserAdmin
+    Pop $R0
+    ${If} $R0 == "true"
+    ; Only proceed if we have HKLM write access
+    ${AndIf} $TmpVal == "HKLM"
+    ; On Windows 2000 we do not install the maintenance service.
+    ${AndIf} ${AtLeastWinXP}
+      ; The user is an admin so we should default to install service yes
+      StrCpy $InstallMaintenanceService "1"
+    ${Else}
+      ; The user is not admin so we should default to install service no
+      StrCpy $InstallMaintenanceService "0"
+    ${EndIf}
+  ${EndIf}
+
+  ${If} $InstallMaintenanceService == "1"
+    ; The user wants to install the maintenance service, so execute
+    ; the pre-packaged maintenance service installer. 
+    ; This option can only be turned on if the user is an admin so there
+    ; is no need to use ExecShell w/ verb runas to enforce elevated.
+    nsExec::Exec "$INSTDIR\maintenanceservice_installer.exe" 
+  ${EndIf}
+!endif
+
   ; These need special handling on uninstall since they may be overwritten by
   ; an install into a different location.
   StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\App Paths\${FileMainEXE}"
   ${WriteRegStr2} $TmpVal "$0" "" "$INSTDIR\${FileMainEXE}" 0
   ${WriteRegStr2} $TmpVal "$0" "Path" "$INSTDIR" 0
 
   ; Create shortcuts
   ${LogHeader} "Adding Shortcuts"
@@ -392,17 +432,17 @@ Section "-Application" APP_IDX
   ; maintenance for the unelevated user context in case that is different than
   ; the current user.
   ClearErrors
   ${GetParameters} $0
   ${GetOptions} "$0" "/UAC:" $0
   ${Unless} ${Errors}
     GetFunctionAddress $0 FixShortcutAppModelIDs
     UAC::ExecCodeSegment $0
-  ${EndIf}
+  ${EndUnless}
 
   ; UAC only allows elevating to an Admin account so there is no need to add
   ; the Start Menu or Desktop shortcuts from the original unelevated process
   ; since this will either add it for the user if unelevated or All Users if
   ; elevated.
   ${If} $AddStartMenuSC == 1
     CreateShortCut "$SMPROGRAMS\${BrandFullName}.lnk" "$INSTDIR\${FileMainEXE}" \
                    "" "$INSTDIR\${FileMainEXE}" 0
@@ -440,16 +480,23 @@ Section "-Application" APP_IDX
       ; It is not possible to add a log entry from the unelevated process so
       ; add the log entry without the path since there is no simple way to know
       ; the correct full path.
       ${LogMsg} "Added Quick Launch Shortcut: ${BrandFullName}.lnk"
       GetFunctionAddress $0 AddQuickLaunchShortcut
       UAC::ExecCodeSegment $0
     ${EndIf}
   ${EndIf}
+
+!ifdef MOZ_MAINTENANCE_SERVICE
+  ${If} $TmpVal == "HKLM"
+    ; Add the registry keys for allowed certificates.
+    ${AddMaintCertKeys}
+  ${EndIf}
+!endif
 SectionEnd
 
 ; Cleanup operations to perform at the end of the installation.
 Section "-InstallEndCleanup"
   SetDetailsPrint both
   DetailPrint "$(STATUS_CLEANUP)"
   SetDetailsPrint none
 
@@ -742,16 +789,68 @@ Function leaveShortcuts
   ${MUI_INSTALLOPTIONS_READ} $AddStartMenuSC "shortcuts.ini" "Field 3" "State"
   ${MUI_INSTALLOPTIONS_READ} $AddQuickLaunchSC "shortcuts.ini" "Field 4" "State"
 
   ${If} $InstallType == ${INSTALLTYPE_CUSTOM}
     Call CheckExistingInstall
   ${EndIf}
 FunctionEnd
 
+!ifdef MOZ_MAINTENANCE_SERVICE
+Function preComponents
+  ; If the service already exists, don't show this page
+  ServicesHelper::IsInstalled "MozillaMaintenance"
+  Pop $R9
+  ${If} $R9 == 1
+    ; The service already exists so don't show this page.
+    Abort
+  ${EndIf}
+
+  ; On Windows 2000 we do not install the maintenance service.
+  ${Unless} ${AtLeastWinXP}
+    Abort
+  ${EndUnless}
+
+  ; Don't show the custom components page if the
+  ; user is not an admin
+  Call IsUserAdmin
+  Pop $R9
+  ${If} $R9 != "true"
+    Abort
+  ${EndIf}
+
+  ; Only show the maintenance service page if we have write access to HKLM
+  ClearErrors
+  WriteRegStr HKLM "Software\Mozilla" \
+              "${BrandShortName}InstallerTest" "Write Test"
+  ${If} ${Errors}
+    ClearErrors
+    Abort
+  ${Else}
+    DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"
+  ${EndIf}
+
+  StrCpy $PageName "Components"
+  ${CheckCustomCommon}
+  !insertmacro MUI_HEADER_TEXT "$(COMPONENTS_PAGE_TITLE)" "$(COMPONENTS_PAGE_SUBTITLE)"
+  !insertmacro MUI_INSTALLOPTIONS_DISPLAY "components.ini"
+FunctionEnd
+
+Function leaveComponents
+  ${MUI_INSTALLOPTIONS_READ} $0 "components.ini" "Settings" "State"
+  ${If} $0 != 0
+    Abort
+  ${EndIf}
+  ${MUI_INSTALLOPTIONS_READ} $InstallMaintenanceService "components.ini" "Field 2" "State"
+  ${If} $InstallType == ${INSTALLTYPE_CUSTOM}
+    Call CheckExistingInstall
+  ${EndIf}
+FunctionEnd
+!endif
+
 Function preSummary
   StrCpy $PageName "Summary"
   ; Setup the summary.ini file for the Custom Summary Page
   WriteINIStr "$PLUGINSDIR\summary.ini" "Settings" NumFields "3"
 
   WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Type   "label"
   WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Text   "$(SUMMARY_INSTALLED_TO)"
   WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Left   "0"
@@ -849,16 +948,17 @@ Function .onInit
   StrCpy $PageName ""
   StrCpy $LANGUAGE 0
   ${SetBrandNameVars} "$EXEDIR\core\distribution\setup.ini"
 
   ${InstallOnInitCommon} "$(WARN_MIN_SUPPORTED_OS_MSG)"
 
   !insertmacro InitInstallOptionsFile "options.ini"
   !insertmacro InitInstallOptionsFile "shortcuts.ini"
+  !insertmacro InitInstallOptionsFile "components.ini"
   !insertmacro InitInstallOptionsFile "summary.ini"
 
   ClearErrors
   ${If} ${AtLeastWinVista}
     WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" "Write Test"
   ${EndIf}
   ${If} ${Errors}
     ; Setup the options.ini file for the Custom Options Page without the option
@@ -884,80 +984,99 @@ Function .onInit
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Text   "$(OPTIONS_SUMMARY)"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Left   "0"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Right  "-1"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Top    "0"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Bottom "10"
 
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Type   "RadioButton"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Text   "$(OPTION_STANDARD_RADIO)"
-  WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Left   "15"
+  WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Left   "0"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Right  "-1"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Top    "25"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Bottom "35"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" State  "1"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Flags  "GROUP"
 
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Type   "RadioButton"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Text   "$(OPTION_CUSTOM_RADIO)"
-  WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Left   "15"
+  WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Left   "0"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Right  "-1"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Top    "55"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Bottom "65"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" State  "0"
 
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Type   "label"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Text   "$(OPTION_STANDARD_DESC)"
-  WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Left   "30"
+  WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Left   "15"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Right  "-1"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Top    "37"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Bottom "57"
 
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Type   "label"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Text   "$(OPTION_CUSTOM_DESC)"
-  WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Left   "30"
+  WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Left   "15"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Right  "-1"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Top    "67"
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Bottom "87"
 
   ; Setup the shortcuts.ini file for the Custom Shortcuts Page
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Settings" NumFields "4"
 
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Type   "label"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Text   "$(CREATE_ICONS_DESC)"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Left   "0"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Right  "-1"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Top    "5"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Bottom "15"
 
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Type   "checkbox"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Text   "$(ICONS_DESKTOP)"
-  WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Left   "15"
+  WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Left   "0"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Right  "-1"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Top    "20"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Bottom "30"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" State  "1"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Flags  "GROUP"
 
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Type   "checkbox"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Text   "$(ICONS_STARTMENU)"
-  WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Left   "15"
+  WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Left   "0"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Right  "-1"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Top    "40"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Bottom "50"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" State  "1"
 
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Type   "checkbox"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Text   "$(ICONS_QUICKLAUNCH)"
-  WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Left   "15"
+  WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Left   "0"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Right  "-1"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Top    "60"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Bottom "70"
   WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" State  "1"
 
+  ; Setup the components.ini file for the Components Page
+  WriteINIStr "$PLUGINSDIR\components.ini" "Settings" NumFields "2"
+
+  WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Type   "label"
+  WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Text   "$(OPTIONAL_COMPONENTS_DESC)"
+  WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Left   "0"
+  WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Right  "-1"
+  WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Top    "5"
+  WriteINIStr "$PLUGINSDIR\components.ini" "Field 1" Bottom "15"
+
+  WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Type   "checkbox"
+  WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Text   "$(MAINTENANCE_SERVICE_CHECKBOX_DESC)"
+  WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Left   "0"
+  WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Right  "-1"
+  WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Top    "20"
+  WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Bottom "30"
+  WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" State  "1"
+  WriteINIStr "$PLUGINSDIR\components.ini" "Field 2" Flags  "GROUP"
+
   ; There must always be a core directory.
   ${GetSize} "$EXEDIR\core\" "/S=0K" $R5 $R7 $R8
   ; Add 1024 Kb to the diskspace requirement since the installer makes a copy
   ; of the MAPI dll's (around 20 Kb)... also, see Bug 434338.
   IntOp $R5 $R5 + 1024
   SectionSetSize ${APP_IDX} $R5
 
   ; Initialize $hHeaderBitmap to prevent redundant changing of the bitmap if
new file mode 100644
--- /dev/null
+++ b/mail/installer/windows/nsis/maintenanceservice_installer.nsi
@@ -0,0 +1,255 @@
+# 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/.
+
+; Set verbosity to 3 (e.g. no script) to lessen the noise in the build logs
+!verbose 3
+
+; 7-Zip provides better compression than the lzma from NSIS so we add the files
+; uncompressed and use 7-Zip to create a SFX archive of it
+SetDatablockOptimize on
+SetCompress off
+CRCCheck on
+
+RequestExecutionLevel admin
+!addplugindir ./
+
+; Variables
+Var TempMaintServiceName
+Var BrandFullNameDA
+Var BrandFullName
+
+; Other included files may depend upon these includes!
+; The following includes are provided by NSIS.
+!include FileFunc.nsh
+!include LogicLib.nsh
+!include MUI.nsh
+!include WinMessages.nsh
+!include WinVer.nsh
+!include WordFunc.nsh
+
+!insertmacro GetOptions
+!insertmacro GetParameters
+!insertmacro GetSize
+
+; The test slaves use this fallback key to run tests.
+; And anyone that wants to run tests themselves should already have 
+; this installed.
+!define FallbackKey \
+  "SOFTWARE\Mozilla\MaintenanceService\3932ecacee736d366d6436db0f55bce4"
+
+!define CompanyName "Mozilla Corporation"
+!define BrandFullNameInternal ""
+
+; The following includes are custom.
+!include defines.nsi
+; We keep defines.nsi defined so that we get other things like 
+; the version number, but we redefine BrandFullName
+!define MaintFullName "Mozilla Maintenance Service"
+!undef BrandFullName
+!define BrandFullName "${MaintFullName}"
+
+!include common.nsh
+!include locales.nsi
+
+VIAddVersionKey "FileDescription" "${MaintFullName} Installer"
+VIAddVersionKey "OriginalFilename" "maintenanceservice_installer.exe"
+
+Name "${MaintFullName}"
+OutFile "maintenanceservice_installer.exe"
+
+; Get installation folder from registry if available
+InstallDirRegKey HKLM "Software\Mozilla\MaintenanceService" ""
+
+SetOverwrite on
+
+!define MaintUninstallKey \
+ "Software\Microsoft\Windows\CurrentVersion\Uninstall\MozillaMaintenanceService"
+
+; The HAVE_64BIT_OS define also means that we have an x64 build,
+; not just an x64 OS.
+!ifdef HAVE_64BIT_OS
+  ; See below, we actually abort the install for x64 builds currently.
+  InstallDir "$PROGRAMFILES64\${MaintFullName}\"
+!else
+  InstallDir "$PROGRAMFILES32\${MaintFullName}\"
+!endif
+ShowUnInstDetails nevershow
+
+################################################################################
+# Modern User Interface - MUI
+
+!define MUI_ICON setup.ico
+!define MUI_UNICON setup.ico
+!define MUI_WELCOMEPAGE_TITLE_3LINES
+!define MUI_UNWELCOMEFINISHPAGE_BITMAP wizWatermark.bmp
+
+;Interface Settings
+!define MUI_ABORTWARNING
+
+; Uninstaller Pages
+!insertmacro MUI_UNPAGE_CONFIRM
+!insertmacro MUI_UNPAGE_INSTFILES
+
+################################################################################
+# Language
+
+!insertmacro MOZ_MUI_LANGUAGE 'baseLocale'
+!verbose push
+!verbose 3
+!include "overrideLocale.nsh"
+!include "customLocale.nsh"
+!verbose pop
+
+; Set this after the locale files to override it if it is in the locale
+; using " " for BrandingText will hide the "Nullsoft Install System..." branding
+BrandingText " "
+
+Function .onInit
+  SetSilent silent
+!ifdef HAVE_64BIT_OS
+  ; We plan to eventually enable 64bit native builds to use the maintenance
+  ; service, but for the initial release, to reduce testing and development,
+  ; 64-bit builds will not install the maintenanceservice.
+  Abort
+!endif
+
+  ; On Windows 2000 we do not install the maintenance service.
+  ; We won't run this installer from the parent installer, but just in case 
+  ; someone tries to execute it on Windows 2000...
+  ${Unless} ${AtLeastWinXP}
+    Abort
+  ${EndUnless}
+FunctionEnd
+
+Function un.onInit
+  StrCpy $BrandFullNameDA "${MaintFullName}"
+  StrCpy $BrandFullName "${MaintFullName}"
+FunctionEnd
+
+Section "MaintenanceService"
+  AllowSkipFiles off
+
+  CreateDirectory $INSTDIR
+  SetOutPath $INSTDIR
+
+  ; If the service already exists, then it will be stopped when upgrading it
+  ; via the maintenanceservice_tmp.exe command executed below.
+  ; The maintenanceservice_tmp.exe command will rename the file to
+  ; maintenanceservice.exe if maintenanceservice_tmp.exe is newer.
+  ; If the service does not exist yet, we install it and drop the file on
+  ; disk as maintenanceservice.exe directly.
+  StrCpy $TempMaintServiceName "maintenanceservice.exe"
+  IfFileExists "$INSTDIR\maintenanceservice.exe" 0 skipAlreadyExists
+    StrCpy $TempMaintServiceName "maintenanceservice_tmp.exe"
+  skipAlreadyExists:
+
+  ; We always write out a copy and then decide whether to install it or 
+  ; not via calling its 'install' cmdline which works by version comparison.
+  CopyFiles "$EXEDIR\maintenanceservice.exe" "$INSTDIR\$TempMaintServiceName"
+
+  ; The updater.ini file is only used when performing an install or upgrade,
+  ; and only if that install or upgrade is successful.  If an old updater.ini
+  ; happened to be copied into the maintenance service installation directory
+  ; but the service was not newer, the updater.ini file would be unused.
+  ; It is used to fill the description of the service on success.
+  CopyFiles "$EXEDIR\updater.ini" "$INSTDIR\updater.ini"
+
+  ; Install the application maintenance service.
+  ; If a service already exists, the command line parameter will stop the
+  ; service and only install itself if it is newer than the already installed
+  ; service.  If successful it will remove the old maintenanceservice.exe
+  ; and replace it with maintenanceservice_tmp.exe.
+  ClearErrors
+  ${GetParameters} $0
+  ${GetOptions} "$0" "/Upgrade" $0
+  ${If} ${Errors}
+    nsExec::Exec '"$INSTDIR\$TempMaintServiceName" install'
+  ${Else}
+    ; The upgrade cmdline is the same as install except
+    ; It will fail if the service isn't already installed.
+    nsExec::Exec '"$INSTDIR\$TempMaintServiceName" upgrade'
+  ${EndIf}
+
+  WriteUninstaller "$INSTDIR\Uninstall.exe"
+  WriteRegStr HKLM "${MaintUninstallKey}" "DisplayName" "${MaintFullName}"
+  WriteRegStr HKLM "${MaintUninstallKey}" "UninstallString" \
+                   '"$INSTDIR\uninstall.exe"'
+  WriteRegStr HKLM "${MaintUninstallKey}" "DisplayIcon" \
+                   "$INSTDIR\Uninstall.exe,0"
+  WriteRegStr HKLM "${MaintUninstallKey}" "DisplayVersion" "${AppVersion}"
+  WriteRegStr HKLM "${MaintUninstallKey}" "Publisher" "Mozilla"
+  WriteRegStr HKLM "${MaintUninstallKey}" "Comments" \
+                   "${BrandFullName} ${AppVersion} (${ARCH} ${AB_CD})"
+  WriteRegDWORD HKLM "${MaintUninstallKey}" "NoModify" 1
+  ${GetSize} "$INSTDIR" "/S=0K" $R2 $R3 $R4
+  WriteRegDWORD HKLM "${MaintUninstallKey}" "EstimatedSize" $R2
+
+  ; Write out that a maintenance service was attempted.
+  ; We do this because on upgrades we will check this value and we only
+  ; want to install once on the first upgrade to maintenance service.
+  ; Also write out that we are currently installed, preferences will check
+  ; this value to determine if we should show the service update pref.
+  ; Since the Maintenance service can be installed either x86 or x64,
+  ; always use the 64-bit registry for checking if an attempt was made.
+  ${If} ${RunningX64}
+    SetRegView 64
+  ${EndIf}
+  WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Attempted" 1
+  WriteRegDWORD HKLM "Software\Mozilla\MaintenanceService" "Installed" 1
+
+  ; Included here for debug purposes only.  
+  ; These keys are used to bypass the installation dir is a valid installation
+  ; check from the service so that tests can be run.
+  ; WriteRegStr HKLM "${FallbackKey}\0" "name" "Mozilla Corporation"
+  ; WriteRegStr HKLM "${FallbackKey}\0" "issuer" "Thawte Code Signing CA - G2"
+  ${If} ${RunningX64}
+    SetRegView lastused
+  ${EndIf}
+SectionEnd
+
+; By renaming before deleting we improve things slightly in case
+; there is a file in use error. In this case a new install can happen.
+Function un.RenameDelete
+  Pop $9
+  ; If the .moz-delete file already exists previously, delete it
+  ; If it doesn't exist, the call is ignored.
+  ; We don't need to pass /REBOOTOK here since it was already marked that way
+  ; if it exists.
+  Delete "$9.moz-delete"
+  Rename "$9" "$9.moz-delete"
+  ${If} ${Errors}
+    Delete /REBOOTOK "$9"
+  ${Else} 
+    Delete /REBOOTOK "$9.moz-delete"
+  ${EndIf}
+  ClearErrors
+FunctionEnd
+
+Section "Uninstall"
+  ; Delete the service so that no updates will be attempted
+  nsExec::Exec '"$INSTDIR\maintenanceservice.exe" uninstall'
+
+  Push "$INSTDIR\updater.ini"
+  Call un.RenameDelete
+  Push "$INSTDIR\maintenanceservice.exe"
+  Call un.RenameDelete
+  Push "$INSTDIR\maintenanceservice_tmp.exe"
+  Call un.RenameDelete
+  Push "$INSTDIR\maintenanceservice.old"
+  Call un.RenameDelete
+  Push "$INSTDIR\Uninstall.exe"
+  Call un.RenameDelete
+  RMDir /REBOOTOK "$INSTDIR"
+
+  DeleteRegKey HKLM "${MaintUninstallKey}"
+
+  ${If} ${RunningX64}
+    SetRegView 64
+  ${EndIf}
+  DeleteRegValue HKLM "Software\Mozilla\MaintenanceService" "Installed"
+  DeleteRegKey HKLM "${FallbackKey}\"
+  ${If} ${RunningX64}
+    SetRegView lastused
+  ${EndIf}
+SectionEnd
--- a/mail/installer/windows/nsis/shared.nsh
+++ b/mail/installer/windows/nsis/shared.nsh
@@ -78,16 +78,55 @@
 
   ${SetAppKeys}
   ${SetUninstallKeys}
 
   ; Remove files that may be left behind by the application in the
   ; VirtualStore directory.
   ${CleanVirtualStore}
 
+!ifdef MOZ_MAINTENANCE_SERVICE
+  Call IsUserAdmin
+  Pop $R0
+  ${If} $R0 == "true"
+  ; Only proceed if we have HKLM write access
+  ${AndIf} $TmpVal == "HKLM"
+  ; On Windows 2000 we do not install the maintenance service.
+  ${AndIf} ${AtLeastWinXP}
+    ; Add the registry keys for allowed certificates.
+    ${AddMaintCertKeys}
+
+    ; We check to see if the maintenance service install was already attempted.
+    ; Since the Maintenance service can be installed either x86 or x64,
+    ; always use the 64-bit registry for checking if an attempt was made.
+    SetRegView 64
+    ReadRegDWORD $5 HKLM "Software\Mozilla\MaintenanceService" "Attempted"
+    ClearErrors
+    SetRegView lastused
+
+    ; If the maintenance service is already installed, do nothing.
+    ; The maintenance service will launch:
+    ; maintenanceservice_installer.exe /Upgrade to upgrade the maintenance
+    ; service if necessary.   If the update was done from updater.exe without 
+    ; the service (i.e. service is failing), updater.exe will do the update of 
+    ; the service.  The reasons we do not do it here is because we don't want 
+    ; to have to prompt for limited user accounts when the service isn't used 
+    ; and we currently call the PostUpdate twice, once for the user and once
+    ; for the SYSTEM account.  Also, this would stop the maintenance service
+    ; and we need a return result back to the service when run that way.
+    ${If} $5 == ""
+      ; An install of maintenance service was never attempted.
+      ; We call ExecShell (which is ShellExecute) with the verb "runas"
+      ; to ask for elevation if the user isn't already elevated.  If the user 
+      ; is already elevated it will just launch the program.
+      ExecShell "runas" "$INSTDIR\maintenanceservice_installer.exe"
+    ${EndIf}
+  ${EndIf}
+!endif
+
   ; Remove talkback if it is present (remove after bug 386760 is fixed)
   ${If} ${FileExists} "$INSTDIR\extensions\talkback@mozilla.org\"
     RmDir /r "$INSTDIR\extensions\talkback@mozilla.org\"
   ${EndIf}
 !macroend
 !define PostUpdate "!insertmacro PostUpdate"
 
 !macro SetAsDefaultAppGlobal
@@ -395,48 +434,62 @@
 !macroend
 !define SetAppKeys "!insertmacro SetAppKeys"
 
 ; Add uninstall registry entries. This macro tests for write access to determine
 ; if the uninstall keys should be added to HKLM or HKCU.
 !macro SetUninstallKeys
   StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\Uninstall\${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})"
 
+  StrCpy $2 ""
+  ClearErrors
   WriteRegStr HKLM "$0" "${BrandShortName}InstallerTest" "Write Test"
   ${If} ${Errors}
-    StrCpy $1 "HKCU"
-    SetShellVarContext current  ; Set SHCTX to the current user (e.g. HKCU)
+    ; If the uninstall keys already exist in HKLM don't create them in HKCU
+    ClearErrors
+    ReadRegStr $2 "HKLM" $0 "DisplayName"
+    ${If} $2 == ""
+      ; Otherwise we don't have any keys for this product in HKLM so proceeed
+      ; to create them in HKCU.  Better handling for this will be done in:
+      ; Bug 711044 - Better handling for 2 uninstall icons
+      StrCpy $1 "HKCU"
+      SetShellVarContext current  ; Set SHCTX to the current user (e.g. HKCU)
+    ${EndIf}
+    ClearErrors
   ${Else}
     StrCpy $1 "HKLM"
     SetShellVarContext all     ; Set SHCTX to all users (e.g. HKLM)
     DeleteRegValue HKLM "$0" "${BrandShortName}InstallerTest"
   ${EndIf}
 
-  ${GetLongPath} "$INSTDIR" $8
+  ${If} $2 == ""
+    ${GetLongPath} "$INSTDIR" $8
+
 
-  ; Write the uninstall registry keys
-  ${WriteRegStr2} $1 "$0" "Comments" "${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})" 0
-  ${WriteRegStr2} $1 "$0" "DisplayIcon" "$8\${FileMainEXE},0" 0
-  ${WriteRegStr2} $1 "$0" "DisplayName" "${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})" 0
-  ${WriteRegStr2} $1 "$0" "DisplayVersion" "${AppVersion}" 0
-  ${WriteRegStr2} $1 "$0" "InstallLocation" "$8" 0
-  ${WriteRegStr2} $1 "$0" "Publisher" "Mozilla" 0
-  ${WriteRegStr2} $1 "$0" "UninstallString" "$8\uninstall\helper.exe" 0
-  ${WriteRegStr2} $1 "$0" "URLInfoAbout" "${URLInfoAbout}" 0
-  ${WriteRegStr2} $1 "$0" "URLUpdateInfo" "${URLUpdateInfo}" 0
-  ${WriteRegDWORD2} $1 "$0" "NoModify" 1 0
-  ${WriteRegDWORD2} $1 "$0" "NoRepair" 1 0
+    ; Write the uninstall registry keys
+    ${WriteRegStr2} $1 "$0" "Comments" "${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})" 0
+    ${WriteRegStr2} $1 "$0" "DisplayIcon" "$8\${FileMainEXE},0" 0
+    ${WriteRegStr2} $1 "$0" "DisplayName" "${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})" 0
+    ${WriteRegStr2} $1 "$0" "DisplayVersion" "${AppVersion}" 0
+    ${WriteRegStr2} $1 "$0" "InstallLocation" "$8" 0
+    ${WriteRegStr2} $1 "$0" "Publisher" "Mozilla" 0
+    ${WriteRegStr2} $1 "$0" "UninstallString" "$8\uninstall\helper.exe" 0
+    ${WriteRegStr2} $1 "$0" "URLInfoAbout" "${URLInfoAbout}" 0
+    ${WriteRegStr2} $1 "$0" "URLUpdateInfo" "${URLUpdateInfo}" 0
+    ${WriteRegDWORD2} $1 "$0" "NoModify" 1 0
+    ${WriteRegDWORD2} $1 "$0" "NoRepair" 1 0
 
-  ${GetSize} "$8" "/S=0K" $R2 $R3 $R4
-  ${WriteRegDWORD2} $1 "$0" "EstimatedSize" $R2 0
+    ${GetSize} "$8" "/S=0K" $R2 $R3 $R4
+    ${WriteRegDWORD2} $1 "$0" "EstimatedSize" $R2 0
 
-  ${If} "$TmpVal" == "HKLM"
-    SetShellVarContext all     ; Set SHCTX to all users (e.g. HKLM)
-  ${Else}
-    SetShellVarContext current  ; Set SHCTX to the current user (e.g. HKCU)
+    ${If} "$TmpVal" == "HKLM"
+      SetShellVarContext all     ; Set SHCTX to all users (e.g. HKLM)
+    ${Else}
+      SetShellVarContext current  ; Set SHCTX to the current user (e.g. HKCU)
+    ${EndIf}
   ${EndIf}
 !macroend
 !define SetUninstallKeys "!insertmacro SetUninstallKeys"
 
 ; Updates protocol handlers if their registry open command value is for this
 ; install location (uses SHCTX)
 !macro UpdateProtocolHandlers
   ; Store the command to open the app with an url in a register for easy access.
@@ -483,16 +536,45 @@
 
   ${IsHandlerForInstallDir} "nntp" $R9
   ${If} "$R9" == "true"
     ${AddHandlerValues} "SOFTWARE\Classes\nntp" "$2" "$8,0" "" "" ""
   ${EndIf}
 !macroend
 !define UpdateProtocolHandlers "!insertmacro UpdateProtocolHandlers"
 
+!ifdef MOZ_MAINTENANCE_SERVICE
+; Adds maintenance service certificate keys for the install dir.
+; For the cert to work, it must also be signed by a trusted cert for the user.
+!macro AddMaintCertKeys
+  Push $R0
+  ; Allow main Mozilla cert information for updates
+  ; This call will push the needed key on the stack
+  ServicesHelper::PathToUniqueRegistryPath "$INSTDIR"
+  Pop $R0
+  ${If} $R0 != ""
+    ; More than one certificate can be specified in a different subfolder
+    ; for example: $R0\1, but each individual binary can be signed
+    ; with at most one certificate.  A fallback certificate can only be used
+    ; if the binary is replaced with a different certificate.
+    ; We always use the 64bit registry for certs.
+    ; This call is ignored on 32-bit systems.
+    SetRegView 64
+    DeleteRegKey HKLM "$R0"
+    WriteRegStr HKLM "$R0\0" "name" "${CERTIFICATE_NAME}"
+    WriteRegStr HKLM "$R0\0" "issuer" "${CERTIFICATE_ISSUER}"
+    SetRegView lastused
+    ClearErrors
+  ${EndIf} 
+  ; Restore the previously used value back
+  Pop $R0
+!macroend
+!define AddMaintCertKeys "!insertmacro AddMaintCertKeys"
+!endif
+
 ; Removes various registry entries for reasons noted below (does not use SHCTX).
 !macro RemoveDeprecatedKeys
   StrCpy $0 "SOFTWARE\Classes"
 
   ; remove DI and SOC from the .eml class if it exists and contains
   ; thunderbird.exe
   ClearErrors
   ReadRegStr $1 HKLM "$0\.eml\shell\open\command" ""
--- a/mail/installer/windows/nsis/uninstaller.nsi
+++ b/mail/installer/windows/nsis/uninstaller.nsi
@@ -24,16 +24,17 @@ RequestExecutionLevel user
 ; On Vista and above attempt to elevate Standard Users in addition to users that
 ; are a member of the Administrators group.
 !define NONADMIN_ELEVATE
 
 ; prevents compiling of the reg write logging.
 !define NO_LOG
 
 Var TmpVal
+Var MaintCertKey
 
 ; Other included files may depend upon these includes!
 ; The following includes are provided by NSIS.
 !include FileFunc.nsh
 !include LogicLib.nsh
 !include MUI.nsh
 !include WinMessages.nsh
 !include WinVer.nsh
@@ -63,16 +64,17 @@ VIAddVersionKey "OriginalFilename" "help
 
 !insertmacro AddHandlerValues
 !insertmacro CleanVirtualStore
 !insertmacro ElevateUAC
 !insertmacro GetLongPath
 !insertmacro GetPathFromString
 !insertmacro InitHashAppModelId
 !insertmacro IsHandlerForInstallDir
+!insertmacro IsUserAdmin
 !insertmacro LogDesktopShortcut
 !insertmacro LogQuickLaunchShortcut
 !insertmacro LogStartMenuShortcut
 !insertmacro RegCleanMain
 !insertmacro RegCleanUninstall
 !insertmacro SetBrandNameVars
 !insertmacro UnloadUAC
 !insertmacro UpdateShortcutAppModelIDs
@@ -337,16 +339,31 @@ Section "Uninstall"
       FileClose $0
     ${EndUnless}
   ${EndIf}
 
   ; Refresh desktop icons otherwise the start menu internet item won't be
   ; removed and other ugly things will happen like recreation of the app's
   ; clients registry key by the OS under some conditions.
   System::Call "shell32::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)"
+
+!ifdef MOZ_MAINTENANCE_SERVICE
+  ; Get the path the allowed cert is at and remove it
+  ; Keep this block of code last since it modfies the reg view
+  ServicesHelper::PathToUniqueRegistryPath "$INSTDIR"
+  Pop $MaintCertKey
+  ${If} $MaintCertKey != ""
+    ; We always use the 64bit registry for certs
+    ; This call is ignored on 32-bit systems.
+    SetRegView 64
+    DeleteRegKey HKLM "$MaintCertKey\"
+    SetRegView lastused
+  ${EndIf}
+!endif
+
 SectionEnd
 
 ################################################################################
 # Helper Functions
 
 ; Don't setup the survey controls, functions, etc. when the application has
 ; defined NO_UNINSTALL_SURVEY
 !ifndef NO_UNINSTALL_SURVEY
--- a/mail/locales/en-US/chrome/messenger/preferences/advanced.dtd
+++ b/mail/locales/en-US/chrome/messenger/preferences/advanced.dtd
@@ -66,16 +66,19 @@
 <!ENTITY modeAskMe.accesskey            "m">
 <!ENTITY modeAutomatic.label            "Automatically download and install the update">
 <!ENTITY modeAutomatic.accesskey        "d">
 <!ENTITY modeAutoAddonWarn.label        "Warn me if this will disable any of my add-ons">
 <!ENTITY modeAutoAddonWarn.accesskey    "W">
 <!ENTITY showUpdates.label              "Show Update History">
 <!ENTITY showUpdates.accesskey          "S">
 
+<!ENTITY useService.label                "Use a background service to install updates">
+<!ENTITY useService.accesskey            "b">
+
 <!-- Networking and Disk Space -->
 <!ENTITY showSettings.label            "Settings…">
 <!ENTITY showSettings.accesskey        "S">
 <!ENTITY proxiesConfigure.label        "Configure how &brandShortName; connects to the Internet">
 <!ENTITY connectionsInfo.caption       "Connection">
 <!ENTITY offlineInfo.caption           "Offline">
 <!ENTITY offlineInfo.label             "Configure offline settings">
 <!ENTITY showOffline.label             "Offline…">
--- a/mail/locales/en-US/installer/custom.properties
+++ b/mail/locales/en-US/installer/custom.properties
@@ -21,16 +21,20 @@
 REG_APP_DESC=$BrandShortName is a full-featured email application. $BrandShortName supports IMAP and POP mail protocols, as well as HTML mail formatting. Built-in junk mail controls, RSS capabilities, powerful quick search, spell check as you type, global inbox, and advanced message filtering round out $BrandShortName's modern feature set.
 CONTEXT_OPTIONS=$BrandShortName &Options
 CONTEXT_SAFE_MODE=$BrandShortName &Safe Mode
 OPTIONS_PAGE_TITLE=Setup Type
 OPTIONS_PAGE_SUBTITLE=Choose setup options
 OPTIONS_MAKE_DEFAULT=&Use $BrandShortName as my default mail application
 SHORTCUTS_PAGE_TITLE=Set Up Shortcuts
 SHORTCUTS_PAGE_SUBTITLE=Create Program Icons
+COMPONENTS_PAGE_TITLE=Set Up Optional Components
+COMPONENTS_PAGE_SUBTITLE=Optional Recommended Components
+OPTIONAL_COMPONENTS_DESC=The Maintenance Service will allow you to update $BrandShortName silently in the background.
+MAINTENANCE_SERVICE_CHECKBOX_DESC=Install &Maintenance Service
 SUMMARY_PAGE_TITLE=Summary
 SUMMARY_PAGE_SUBTITLE=Ready to start installing $BrandShortName
 SUMMARY_INSTALLED_TO=$BrandShortName will be installed to the following location:
 SUMMARY_REBOOT_REQUIRED_INSTALL=A restart of your computer may be required to complete the installation.
 SUMMARY_REBOOT_REQUIRED_UNINSTALL=A restart of your computer may be required to complete the uninstall.
 SUMMARY_MAKE_DEFAULT=$BrandShortName will be set as your default mail application.
 SUMMARY_CLICK=Click Install to continue.
 SURVEY_TEXT=&Tell us what you thought of $BrandShortName