home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 233 / Computer Shopper 233 / ComputerShopperDVD233.iso / Toolkit / Internet / Firefox / Firefox Setup 2.0.0.3.exe / nonlocalized / components / nsPostUpdateWin.js < prev    next >
Encoding:
Text File  |  2007-03-10  |  21.7 KB  |  723 lines

  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Mozilla Public License Version
  6.  * 1.1 (the "License"); you may not use this file except in compliance with
  7.  * the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/MPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is the Update Service.
  16.  *
  17.  * The Initial Developer of the Original Code is Google Inc.
  18.  * Portions created by the Initial Developer are Copyright (C) 2005
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *  Darin Fisher <darin@meer.net> (original author)
  23.  *
  24.  * Alternatively, the contents of this file may be used under the terms of
  25.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  26.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27.  * in which case the provisions of the GPL or the LGPL are applicable instead
  28.  * of those above. If you wish to allow use of your version of this file only
  29.  * under the terms of either the GPL or the LGPL, and not to allow others to
  30.  * use your version of this file under the terms of the MPL, indicate your
  31.  * decision by deleting the provisions above and replace them with the notice
  32.  * and other provisions required by the GPL or the LGPL. If you do not delete
  33.  * the provisions above, a recipient may use your version of this file under
  34.  * the terms of any one of the MPL, the GPL or the LGPL.
  35.  *
  36.  * ***** END LICENSE BLOCK ***** */
  37.  
  38. /**
  39.  * This file contains an implementation of nsIRunnable, which may be invoked
  40.  * to perform post-update modifications to the windows registry and uninstall
  41.  * logs required to complete an update of the application.  This code is very
  42.  * specific to the xpinstall wizard for windows.
  43.  */
  44.  
  45. const URI_BRAND_PROPERTIES     = "chrome://branding/locale/brand.properties";
  46.  
  47. const KEY_APPDIR          = "XCurProcD";
  48. const KEY_TMPDIR          = "TmpD";
  49. const KEY_LOCALDATA       = "DefProfLRt";
  50. const KEY_PROGRAMFILES    = "ProgF";
  51. const KEY_UAPPDATA        = "UAppData";
  52.  
  53. // see prio.h
  54. const PR_RDONLY      = 0x01;
  55. const PR_WRONLY      = 0x02;
  56. const PR_APPEND      = 0x10;
  57.  
  58. const PERMS_FILE     = 0644;
  59. const PERMS_DIR      = 0700;
  60.  
  61. const nsIWindowsRegKey = Components.interfaces.nsIWindowsRegKey;
  62.  
  63. var gConsole = null;
  64. var gAppUpdateLogPostUpdate = false;
  65.  
  66. //-----------------------------------------------------------------------------
  67.  
  68. /**
  69.  * Console logging support
  70.  */
  71. function LOG(s) {
  72.   if (gAppUpdateLogPostUpdate) {
  73.     dump("*** PostUpdateWin: " + s + "\n");
  74.     gConsole.logStringMessage(s);
  75.   }
  76. }
  77.  
  78. /**
  79.  * This function queries the XPCOM directory service.
  80.  */
  81. function getFile(key) {
  82.   var dirSvc =
  83.       Components.classes["@mozilla.org/file/directory_service;1"].
  84.       getService(Components.interfaces.nsIProperties);
  85.   return dirSvc.get(key, Components.interfaces.nsIFile);
  86. }
  87.  
  88. /**
  89.  * Return the full path given a relative path and a base directory.
  90.  */
  91. function getFileRelativeTo(dir, relPath) {
  92.   var file = dir.clone().QueryInterface(Components.interfaces.nsILocalFile);
  93.   file.setRelativeDescriptor(dir, relPath);
  94.   return file;
  95. }
  96.  
  97. /**
  98.  * Creates a new file object given a native file path.
  99.  * @param   path
  100.  *          The native file path.
  101.  * @return  nsILocalFile object for the given native file path.
  102.  */
  103. function newFile(path) {
  104.   var file = Components.classes["@mozilla.org/file/local;1"]
  105.                        .createInstance(Components.interfaces.nsILocalFile);
  106.   file.initWithPath(path);
  107.   return file;
  108. }
  109.  
  110. /**
  111.  * This function returns a file input stream.
  112.  */
  113. function openFileInputStream(file) {
  114.   var stream =
  115.       Components.classes["@mozilla.org/network/file-input-stream;1"].
  116.       createInstance(Components.interfaces.nsIFileInputStream);
  117.   stream.init(file, PR_RDONLY, 0, 0);
  118.   return stream;
  119. }
  120.  
  121. /**
  122.  * This function returns a file output stream.
  123.  */
  124. function openFileOutputStream(file, flags) {
  125.   var stream =
  126.       Components.classes["@mozilla.org/network/file-output-stream;1"].
  127.       createInstance(Components.interfaces.nsIFileOutputStream);
  128.   stream.init(file, flags, 0644, 0);
  129.   return stream;
  130. }
  131.  
  132. //-----------------------------------------------------------------------------
  133.  
  134. const PREFIX_FILE = "File: ";
  135.  
  136. function InstallLogWriter() {
  137. }
  138. InstallLogWriter.prototype = {
  139.   _outputStream: null,  // nsIOutputStream to the install wizard log file
  140.  
  141.   /**
  142.    * Write a single line to the output stream.
  143.    */
  144.   _writeLine: function(s) {
  145.     s = s + "\r\n";
  146.     this._outputStream.write(s, s.length);
  147.   },
  148.  
  149.   /**
  150.    * This function creates an empty uninstall update log file if it doesn't
  151.    * exist and returns a reference to the resulting nsIFile.
  152.    */
  153.   _getUninstallLogFile: function() {
  154.     var file = getFile(KEY_APPDIR); 
  155.     file.append("uninstall");
  156.     if (!file.exists())
  157.       return null;
  158.  
  159.     file.append("uninstall.log");
  160.     if (!file.exists())
  161.       file.create(Components.interfaces.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
  162.  
  163.     return file;
  164.   },
  165.  
  166.   /**
  167.    * Return the update.log file.  Use last-update.log file in case the
  168.    * updates/0 directory has already been cleaned out (see bug 311302).
  169.    */
  170.   _getUpdateLogFile: function() {
  171.     function appendUpdateLogPath(root) {
  172.       var file = root.clone();
  173.       file.append("updates");
  174.       file.append("0");
  175.       file.append("update.log");
  176.       if (file.exists())
  177.         return file;
  178.  
  179.       file = root; 
  180.       file.append("updates");
  181.       file.append("last-update.log");
  182.       if (file.exists())
  183.         return file;
  184.  
  185.       return null;
  186.     }
  187.  
  188.     // See the local appdata first if app dir is under Program Files.
  189.     var file = null;
  190.     var updRoot = getFile(KEY_APPDIR); 
  191.     var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"]
  192.                                 .getService(Components.interfaces.nsIProperties);
  193.     // Fallback to previous behavior since getting ProgF
  194.     // (e.g. KEY_PROGRAMFILES) may fail on Win9x.
  195.     try {
  196.       var programFilesDir = fileLocator.get(KEY_PROGRAMFILES,
  197.           Components.interfaces.nsILocalFile);
  198.       if (programFilesDir.contains(updRoot, true)) {
  199.         var relativePath = updRoot.QueryInterface(Components.interfaces.nsILocalFile).
  200.             getRelativeDescriptor(programFilesDir);
  201.         var userLocalDir = fileLocator.get(KEY_LOCALDATA,
  202.             Components.interfaces.nsILocalFile).parent;
  203.         updRoot.setRelativeDescriptor(userLocalDir, relativePath);
  204.         file = appendUpdateLogPath(updRoot);
  205.  
  206.         // When updating from Fx 2.0.0.1 to 2.0.0.3 (or later) on Vista,
  207.         // we will have to see also user app data (see bug 351949).
  208.         if (!file)
  209.           file = appendUpdateLogPath(getFile(KEY_UAPPDATA));
  210.       }
  211.     }
  212.     catch (e) {}
  213.  
  214.     // See the app dir if not found or app dir is out of Program Files.
  215.     if (!file)
  216.       file = appendUpdateLogPath(getFile(KEY_APPDIR));
  217.  
  218.     return file;
  219.   },
  220.  
  221.   /**
  222.    * Read update.log to extract information about files that were
  223.    * newly added for this update.
  224.    */
  225.   _readUpdateLog: function(logFile, entries) {
  226.     var stream;
  227.     try {
  228.       stream = openFileInputStream(logFile).
  229.           QueryInterface(Components.interfaces.nsILineInputStream);
  230.  
  231.       var line = {};
  232.       while (stream.readLine(line)) {
  233.         var data = line.value.split(" ");
  234.         if (data[0] == "EXECUTE" && data[1] == "ADD") {
  235.           // The uninstaller requires the path separator to be "\" and
  236.           // relative paths to start with a "\".
  237.           var relPath = "\\" + data[2].replace(/\//g, "\\");
  238.           entries[relPath] = null;
  239.         }
  240.       }
  241.     } finally {
  242.       if (stream)
  243.         stream.close();
  244.     }
  245.   },
  246.  
  247.   /**
  248.    * Read install_wizard log files to extract information about files that were
  249.    * previously added by the xpinstall installer and software update.
  250.    */
  251.   _readXPInstallLog: function(logFile, entries) {
  252.     var stream;
  253.     try {
  254.       stream = openFileInputStream(logFile).
  255.           QueryInterface(Components.interfaces.nsILineInputStream);
  256.  
  257.       function fixPath(path, offset) {
  258.         return path.substr(offset).replace(appDirPath, "");
  259.       }
  260.  
  261.       var appDir = getFile(KEY_APPDIR);
  262.       var appDirPath = appDir.path;
  263.       var line = {};
  264.       while (stream.readLine(line)) {
  265.         var entry = line.value;
  266.         // This works with both the entries from xpinstall (e.g. Installing: )
  267.         // and from update (e.g. installing: )
  268.         var searchStr = "nstalling: ";
  269.         var index = entry.indexOf(searchStr);
  270.         if (index != -1) {
  271.           entries[fixPath(entry, index + searchStr.length)] = null;
  272.           continue;
  273.         }
  274.  
  275.         searchStr = "Replacing: ";
  276.         index = entry.indexOf(searchStr);
  277.         if (index != -1) {
  278.           entries[fixPath(entry, index + searchStr.length)] = null;
  279.           continue;
  280.         }
  281.  
  282.         searchStr = "Windows Shortcut: ";
  283.         index = entry.indexOf(searchStr);
  284.         if (index != -1) {
  285.           entries[fixPath(entry + ".lnk", index + searchStr.length)] = null;
  286.           continue;
  287.         }
  288.       }
  289.     } finally {
  290.       if (stream)
  291.         stream.close();
  292.     }
  293.   },
  294.  
  295.   _readUninstallLog: function(logFile, entries) {
  296.     var stream;
  297.     try {
  298.       stream = openFileInputStream(logFile).
  299.           QueryInterface(Components.interfaces.nsILineInputStream);
  300.  
  301.       var line = {};
  302.       var searchStr = "File: ";
  303.       while (stream.readLine(line)) {
  304.         var index = line.value.indexOf(searchStr);
  305.         if (index != -1) {
  306.           var str = line.value.substr(index + searchStr.length);
  307.           entries.push(str);
  308.         }
  309.       }
  310.     } finally {
  311.       if (stream)
  312.         stream.close();
  313.     }
  314.   },
  315.  
  316.   /**
  317.    * This function initializes the log writer and is responsible for
  318.    * translating 'update.log' and the 'install_wizard' logs to the NSIS format.
  319.    */
  320.   begin: function() {
  321.     var updateLog = this._getUpdateLogFile();
  322.     if (!updateLog)
  323.       return;
  324.  
  325.     var newEntries = { };
  326.     this._readUpdateLog(updateLog, newEntries);
  327.  
  328.     try {
  329.       const nsIDirectoryEnumerator = Components.interfaces.nsIDirectoryEnumerator;
  330.       const nsILocalFile = Components.interfaces.nsILocalFile;
  331.       var prefixWizLog = "install_wizard";
  332.       var uninstallDir = getFile(KEY_APPDIR); 
  333.       uninstallDir.append("uninstall");
  334.       var entries = uninstallDir.directoryEntries.QueryInterface(nsIDirectoryEnumerator);
  335.       while (true) {
  336.         var wizLog = entries.nextFile;
  337.         if (!wizLog)
  338.           break;
  339.         if (wizLog instanceof nsILocalFile && !wizLog.isDirectory() &&
  340.             wizLog.leafName.indexOf(prefixWizLog) == 0) {
  341.           this._readXPInstallLog(wizLog, newEntries);
  342.           wizLog.remove(false);
  343.         }
  344.       }
  345.     }
  346.     catch (e) {}
  347.     if (entries)
  348.       entries.close();
  349.  
  350.     var uninstallLog = this._getUninstallLogFile();
  351.     var oldEntries = [];
  352.     this._readUninstallLog(uninstallLog, oldEntries);
  353.  
  354.     // Prevent writing duplicate entries in the log file
  355.     for (var relPath in newEntries) {
  356.       if (oldEntries.indexOf(relPath) != -1)
  357.         delete newEntries[relPath];
  358.     }
  359.  
  360.     if (newEntries.length == 0)
  361.       return;
  362.  
  363.     // since we are not running with elevated privs, we can't write out
  364.     // the log file (at least, not on Vista).  So, write the output to
  365.     // temp, and then later, we'll pass the file (gCopiedLog) to
  366.     // the post update clean up process, which can copy it to
  367.     // the desired location (because it will have elevated privs)
  368.     gCopiedLog = getFile(KEY_TMPDIR);
  369.     gCopiedLog.append("uninstall");
  370.     gCopiedLog.createUnique(gCopiedLog.DIRECTORY_TYPE, PERMS_DIR);
  371.     if (uninstallLog)
  372.       uninstallLog.copyTo(gCopiedLog, "uninstall.log");
  373.     gCopiedLog.append("uninstall.log");
  374.     
  375.     LOG("uninstallLog = " + uninstallLog.path);
  376.     LOG("copiedLog = " + gCopiedLog.path);
  377.     
  378.     if (!gCopiedLog.exists())
  379.       gCopiedLog.create(Components.interfaces.nsILocalFile.NORMAL_FILE_TYPE, 
  380.                         PERMS_FILE);
  381.       
  382.     this._outputStream =
  383.         openFileOutputStream(gCopiedLog, PR_WRONLY | PR_APPEND);
  384.  
  385.     // The NSIS uninstaller deletes all directories where the installer has
  386.     // added a file if the directory is empty after the files have been removed
  387.     // so there is no need to log directories.
  388.     for (var relPath in newEntries)
  389.       this._writeLine(PREFIX_FILE + relPath);
  390.   },
  391.  
  392.   end: function() {
  393.     if (!this._outputStream)
  394.       return;
  395.     this._outputStream.close();
  396.     this._outputStream = null;
  397.   }
  398. };
  399.  
  400. var installLogWriter;
  401. var gCopiedLog;
  402.  
  403. //-----------------------------------------------------------------------------
  404.  
  405. /**
  406.  * A thin wrapper around nsIWindowsRegKey
  407.  * note, only the "read" methods are exposed.  If you want to write
  408.  * to the registry on Vista, you need to be a priveleged app.
  409.  * We've moved that code into the uninstaller.
  410.  */
  411. function RegKey() {
  412.   // Internally, we may pass parameters to this constructor.
  413.   if (arguments.length == 3) {
  414.     this._key = arguments[0];
  415.     this._root = arguments[1];
  416.     this._path = arguments[2];
  417.   } else {
  418.     this._key =
  419.         Components.classes["@mozilla.org/windows-registry-key;1"].
  420.         createInstance(nsIWindowsRegKey);
  421.   }
  422. }
  423. RegKey.prototype = {
  424.   _key: null,
  425.   _root: null,
  426.   _path: null,
  427.  
  428.   ACCESS_READ:  nsIWindowsRegKey.ACCESS_READ,
  429.  
  430.   ROOT_KEY_CURRENT_USER: nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
  431.   ROOT_KEY_LOCAL_MACHINE: nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
  432.   ROOT_KEY_CLASSES_ROOT: nsIWindowsRegKey.ROOT_KEY_CLASSES_ROOT,
  433.   
  434.   close: function() {
  435.     this._key.close();
  436.     this._root = null;
  437.     this._path = null;
  438.   },
  439.  
  440.   open: function(rootKey, path, mode) {
  441.     this._key.open(rootKey, path, mode);
  442.     this._root = rootKey;
  443.     this._path = path;
  444.   },
  445.  
  446.   openChild: function(path, mode) {
  447.     var child = this._key.openChild(path, mode);
  448.     return new RegKey(child, this._root, this._path + "\\" + path);
  449.   },
  450.  
  451.   readStringValue: function(name) {
  452.     return this._key.readStringValue(name);
  453.   },
  454.  
  455.   hasValue: function(name) {
  456.     return this._key.hasValue(name);
  457.   },
  458.  
  459.   hasChild: function(name) {
  460.     return this._key.hasChild(name);
  461.   },
  462.  
  463.   get childCount() {
  464.     return this._key.childCount;
  465.   },
  466.  
  467.   getChildName: function(index) {
  468.     return this._key.getChildName(index);
  469.   },
  470.  
  471.   toString: function() {
  472.     var root;
  473.     switch (this._root) {
  474.     case this.ROOT_KEY_CLASSES_ROOT:
  475.       root = "HKEY_KEY_CLASSES_ROOT";
  476.       break;
  477.     case this.ROOT_KEY_LOCAL_MACHINE:
  478.       root = "HKEY_LOCAL_MACHINE";
  479.       break;
  480.     case this.ROOT_KEY_CURRENT_USER:
  481.       root = "HKEY_CURRENT_USER";
  482.       break;
  483.     default:
  484.       LOG("unknown root key");
  485.       return "";
  486.     }
  487.     return root + "\\" + this._path;
  488.   }
  489. };
  490.  
  491. /**
  492.  * This method walks the registry looking for the registry keys of
  493.  * the previous version of the application.
  494.  */
  495. function haveOldInstall(key, brandFullName, version) {
  496.   var ourInstallDir = getFile(KEY_APPDIR);
  497.   var result = false;
  498.   var childKey, productKey, mainKey;
  499.   try {
  500.     for (var i = 0; i < key.childCount; ++i) {
  501.       var childName = key.getChildName(i);
  502.       childKey = key.openChild(childName, key.ACCESS_READ);
  503.       if (childKey.hasValue("CurrentVersion")) {
  504.         for (var j = 0; j < childKey.childCount; ++j) {
  505.           var productVer = childKey.getChildName(j); 
  506.           productKey = childKey.openChild(productVer, key.ACCESS_READ);
  507.           if (productKey.hasChild("Main")) {
  508.             mainKey = productKey.openChild("Main", key.ACCESS_READ);
  509.             var installDir = mainKey.readStringValue("Install Directory");
  510.             mainKey.close();
  511.             LOG("old install? " + installDir + " vs " + ourInstallDir.path);
  512.             LOG("old install? " + childName + " vs " + brandFullName);
  513.             LOG("old install? " + productVer.split(" ")[0] + " vs " + version);
  514.             if (newFile(installDir).equals(ourInstallDir) &&
  515.                 (childName != brandFullName ||
  516.                 productVer.split(" ")[0] != version)) {
  517.               result = true;
  518.             }
  519.           }
  520.           productKey.close();
  521.           if (result)
  522.             break;
  523.         }
  524.       }
  525.       childKey.close();
  526.       if (result)
  527.         break;
  528.     }
  529.   } catch (e) {
  530.     result = false;
  531.     if (childKey)
  532.       childKey.close();
  533.     if (productKey)
  534.       productKey.close();
  535.     if (mainKey)
  536.       mainKey.close();
  537.   }
  538.   return result;
  539. }
  540.  
  541. function checkRegistry()
  542. {
  543.   // XXX todo
  544.   // this is firefox specific
  545.   // figure out what to do about tbird and sunbird, etc   
  546.   LOG("checkRegistry");
  547.  
  548.   var result = false;
  549.   try {
  550.     var key = new RegKey();
  551.     key.open(RegKey.prototype.ROOT_KEY_CLASSES_ROOT, "FirefoxHTML\\shell\\open\\command", key.ACCESS_READ);
  552.     var commandKey = key.readStringValue("");
  553.     LOG("commandKey = " + commandKey);
  554.     // if "-requestPending" is not found, we need to do the cleanup
  555.     result = (commandKey.indexOf("-requestPending") == -1);
  556.   } catch (e) {
  557.     LOG("failed to open command key for FirefoxHTML: " + e);
  558.   }
  559.   key.close();
  560.   return result;
  561. }
  562.  
  563. function checkOldInstall(rootKey, vendorShortName, brandFullName, version)
  564. {
  565.   var key = new RegKey();
  566.   var result = false;
  567.  
  568.   try {
  569.     key.open(rootKey, "SOFTWARE\\" + vendorShortName, key.ACCESS_READ);
  570.     LOG("checkOldInstall: " + key + " " + brandFullName + " " + version);
  571.     result = haveOldInstall(key, brandFullName, version);
  572.   } catch (e) {
  573.     LOG("failed trying to find old install: " + e);
  574.   }
  575.   key.close();
  576.   return result;
  577. }
  578.  
  579. //-----------------------------------------------------------------------------
  580.  
  581. function nsPostUpdateWin() {
  582.   gConsole = Components.classes["@mozilla.org/consoleservice;1"]
  583.                        .getService(Components.interfaces.nsIConsoleService);
  584.   var prefs = Components.classes["@mozilla.org/preferences-service;1"].
  585.               getService(Components.interfaces.nsIPrefBranch);
  586.   try {
  587.     gAppUpdateLogPostUpdate = prefs.getBoolPref("app.update.log.all");
  588.   }
  589.   catch (ex) {
  590.   }
  591.   try {
  592.     if (!gAppUpdateLogPostUpdate) 
  593.       gAppUpdateLogPostUpdate = prefs.getBoolPref("app.update.log.PostUpdate");
  594.   }
  595.   catch (ex) {
  596.   }
  597. }
  598.  
  599. nsPostUpdateWin.prototype = {
  600.   QueryInterface: function(iid) {
  601.     if (iid.equals(Components.interfaces.nsIRunnable) ||
  602.         iid.equals(Components.interfaces.nsISupports))
  603.       return this;
  604.     throw Components.results.NS_ERROR_NO_INTERFACE;
  605.   },
  606.  
  607.   run: function() {
  608.     try {
  609.       installLogWriter = new InstallLogWriter();
  610.       try {
  611.         installLogWriter.begin();
  612.       } finally {
  613.         installLogWriter.end();
  614.         installLogWriter = null;
  615.       }
  616.     } catch (e) {
  617.       LOG(e);
  618.     } 
  619.     
  620.     var app =
  621.       Components.classes["@mozilla.org/xre/app-info;1"].
  622.         getService(Components.interfaces.nsIXULAppInfo).
  623.         QueryInterface(Components.interfaces.nsIXULRuntime);
  624.  
  625.     var sbs =
  626.       Components.classes["@mozilla.org/intl/stringbundle;1"].
  627.       getService(Components.interfaces.nsIStringBundleService);
  628.     var brandBundle = sbs.createBundle(URI_BRAND_PROPERTIES);
  629.  
  630.     var vendorShortName;
  631.     try {
  632.       // The Thunderbird vendorShortName is "Mozilla Thunderbird", but we
  633.       // just want "Thunderbird", so allow it to be overridden in prefs.
  634.  
  635.       var prefs =
  636.         Components.classes["@mozilla.org/preferences-service;1"].
  637.         getService(Components.interfaces.nsIPrefBranch);
  638.  
  639.       vendorShortName = prefs.getCharPref("app.update.vendorName.override");
  640.     }
  641.     catch (e) {
  642.       vendorShortName = brandBundle.GetStringFromName("vendorShortName");
  643.     }
  644.     var brandFullName = brandBundle.GetStringFromName("brandFullName");
  645.  
  646.     if (!gCopiedLog && 
  647.         !checkRegistry() &&
  648.         !checkOldInstall(RegKey.prototype.ROOT_KEY_LOCAL_MACHINE, 
  649.                          vendorShortName, brandFullName, app.version) &&
  650.         !checkOldInstall(RegKey.prototype.ROOT_KEY_CURRENT_USER, 
  651.                          vendorShortName, brandFullName, app.version)) {
  652.       LOG("nothing to do, so don't launch the helper");
  653.       return;
  654.     }
  655.  
  656.     try {
  657.       var winAppHelper = 
  658.         app.QueryInterface(Components.interfaces.nsIWinAppHelper);
  659.  
  660.       // note, gCopiedLog could be null
  661.       if (gCopiedLog)
  662.         LOG("calling postUpdate with: " + gCopiedLog.path);
  663.       else
  664.         LOG("calling postUpdate without a log");
  665.  
  666.       winAppHelper.postUpdate(gCopiedLog);
  667.     } catch (e) {
  668.       LOG("failed to launch the helper to do the post update cleanup: " + e); 
  669.     }
  670.   }
  671. };
  672.  
  673. //-----------------------------------------------------------------------------
  674.  
  675. var gModule = {
  676.   registerSelf: function(compMgr, fileSpec, location, type) {
  677.     compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  678.     
  679.     for (var key in this._objects) {
  680.       var obj = this._objects[key];
  681.       compMgr.registerFactoryLocation(obj.CID, obj.className, obj.contractID,
  682.                                       fileSpec, location, type);
  683.     }
  684.   },
  685.   
  686.   getClassObject: function(compMgr, cid, iid) {
  687.     if (!iid.equals(Components.interfaces.nsIFactory))
  688.       throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  689.  
  690.     for (var key in this._objects) {
  691.       if (cid.equals(this._objects[key].CID))
  692.         return this._objects[key].factory;
  693.     }
  694.     
  695.     throw Components.results.NS_ERROR_NO_INTERFACE;
  696.   },
  697.   
  698.   _makeFactory: #1= function(ctor) {
  699.     function ci(outer, iid) {
  700.       if (outer != null)
  701.         throw Components.results.NS_ERROR_NO_AGGREGATION;
  702.       return (new ctor()).QueryInterface(iid);
  703.     } 
  704.     return { createInstance: ci };
  705.   },
  706.   
  707.   _objects: {
  708.     manager: { CID        : Components.ID("{d15b970b-5472-40df-97e8-eb03a04baa82}"),
  709.                contractID : "@mozilla.org/updates/post-update;1",
  710.                className  : "nsPostUpdateWin",
  711.                factory    : #1#(nsPostUpdateWin)
  712.              },
  713.   },
  714.   
  715.   canUnload: function(compMgr) {
  716.     return true;
  717.   }
  718. };
  719.  
  720. function NSGetModule(compMgr, fileSpec) {
  721.   return gModule;
  722. }
  723.