home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 December / PCWorld_2005-12_cd.bin / komunikace / netscape / nsb-install-8-0.exe / components / nsUpdateService.js < prev    next >
Text File  |  2005-10-12  |  75KB  |  1,964 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 Ben Goodger.
  18.  * Portions created by the Initial Developer are Copyright (C) 2004
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *  Ben Goodger <ben@bengoodger.com>
  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. const PREF_APP_ID                           = "app.id";
  39. const PREF_APP_VERSION                      = "app.version";
  40. const PREF_SAFETYNET_VERSION                                = "safetynet.version";
  41. const PREF_UPDATE_APP_ENABLED               = "app.update.enabled";
  42. const PREF_UPDATE_APP_AUTOUPDATEENABLED     = "app.update.autoUpdateEnabled";
  43. const PREF_UPDATE_APP_URI                   = "app.update.url";
  44. const PREF_UPDATE_APP_UPDATESAVAILABLE      = "app.update.updatesAvailable";
  45. const PREF_UPDATE_APP_INTERVAL              = "app.update.interval";
  46. const PREF_UPDATE_APP_LASTUPDATEDATE        = "app.update.lastUpdateDate";
  47. const PREF_UPDATE_APP_PERFORMED             = "app.update.performed";
  48.  
  49. //    MERC BILL - NEW OPTIONS
  50. const PREF_UPDATE_APP_AUTOINSTALL     = "update.autoInstallUpdates";
  51. const PREF_UPDATE_EXTENSIONS_AUTOINSTALL     = "update.autoDownloadInstallUpdatesToExtension";
  52.  
  53. //const PREF_UPDATE_NOTIFYDOWNLOADED_UPDATES     = "update.notifyOfDownloadedUpdates";
  54. //const PREF_UPDATE_NOTIFYAVAILABLE_UPDATES     = "update.notifyOfAvailableUpdates";
  55. //    END MERC
  56.  
  57. const PREF_UPDATE_EXTENSIONS_ENABLED            = "extensions.update.enabled";
  58. const PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED  = "extensions.update.autoUpdateEnabled";
  59. const PREF_UPDATE_EXTENSIONS_AUTOUPDATE         = "extensions.update.autoUpdate";
  60. const PREF_UPDATE_EXTENSIONS_COUNT              = "extensions.update.count";
  61. const PREF_UPDATE_EXTENSIONS_INTERVAL           = "extensions.update.interval";
  62. const PREF_UPDATE_EXTENSIONS_LASTUPDATEDATE     = "extensions.update.lastUpdateDate";
  63. const PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD = "extensions.update.severity.threshold";
  64.  
  65. const PREF_UPDATE_INTERVAL                  = "update.interval";
  66. const PREF_UPDATE_SEVERITY                  = "update.severity";
  67. const PREF_UPDATE_SHOW_SLIDING_NOTIFICATION = "update.showSlidingNotification";
  68.  
  69. const PREF_SILENT_UPDATE_ENABLED                        = "silent.update.enabled";
  70. const PREF_SILENT_UPDATE_INTERVAL                        = "silent.update.interval";
  71. const PREF_SILENT_UPDATE_LASTUPDATEDATE            = "silent.update.lastUpdateDate";
  72.  
  73. const nsIExtensionManager = Components.interfaces.nsIExtensionManager;
  74. const nsIUpdateService    = Components.interfaces.nsIUpdateService;
  75. const nsIUpdateItem       = Components.interfaces.nsIUpdateItem;
  76.  
  77. const UPDATED_EXTENSIONS  = 0x01;
  78. const UPDATED_APP         = 0x02;
  79. const UPDATED_SILENT      = 0x04;
  80.  
  81. function APP_NS(aProperty)
  82. {
  83.   return "http://www.mozilla.org/2004/app-rdf#" + aProperty;
  84. }
  85.  
  86. function SILENT_NS(aProperty)
  87. {
  88.   return "http://www.mozilla.org/2004/silent-rdf#" + aProperty;
  89. }
  90.  
  91. function getOSKey()
  92. {
  93.   return "windows";
  94. }
  95.  
  96. function stackTraceFunctionFormat(aFunctionName)
  97. {
  98.   var classDelimiter = aFunctionName.indexOf("_");
  99.   var className = aFunctionName.substr(0, classDelimiter);
  100.   if (!className)
  101.     className == "<global>";
  102.   var functionName = aFunctionName.substr(classDelimiter + 1, aFunctionName.length);
  103.   if (!functionName)
  104.     functionName == "<anonymous>";
  105.   return className + "::" + functionName;
  106. }
  107.  
  108. function stackTrace(aArguments, aMaxCount)
  109. {
  110.   dump("=[STACKTRACE]=====================================================\n");
  111.   dump("*** at: " + stackTraceFunctionFormat(aArguments.callee.name) + "()\n");
  112.   var temp = aArguments.callee.caller;
  113.   var count = 0;
  114.   while (temp) {
  115.     dump("***     " + stackTraceFunctionFormat(temp.name) + ")\n");
  116.     temp = temp.arguments.callee.caller;
  117.     if (aMaxCount > 0 && ++count == aMaxCount)
  118.       break;
  119.   }
  120.   dump("==================================================================\n");
  121. }
  122.  
  123. var gPref   = null;
  124. var gOS     = null;
  125. var gRDF    = null;
  126. var gSiteControls = null;
  127.  
  128. function nsUpdateService()
  129. {
  130.   //dump("\n\n**** Starting update service...\n\n");
  131.   gPref = Components.classes["@mozilla.org/preferences-service;1"]
  132.                     .getService(Components.interfaces.nsIPrefBranch);
  133.   gOS   = Components.classes["@mozilla.org/observer-service;1"]
  134.                     .getService(Components.interfaces.nsIObserverService);
  135.   gRDF  = Components.classes["@mozilla.org/rdf/rdf-service;1"]
  136.                     .getService(Components.interfaces.nsIRDFService);
  137.   gSiteControls = Components.classes["@mozilla.org/browser/sitecontrols-service;1"]
  138.                                       .getService(Components.interfaces.nsISiteControlsService);
  139.  
  140.   this.watchForUpdates();
  141.  
  142.   var pbi = gPref.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
  143.   pbi.addObserver(PREF_UPDATE_APP_AUTOUPDATEENABLED, this, false);
  144.   pbi.addObserver(PREF_UPDATE_APP_ENABLED, this, false);
  145.   pbi.addObserver(PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED, this, false);
  146.   pbi.addObserver(PREF_UPDATE_EXTENSIONS_ENABLED, this, false);
  147.   pbi.addObserver(PREF_UPDATE_INTERVAL, this, false);
  148.   pbi.addObserver(PREF_UPDATE_APP_INTERVAL, this, false);
  149.   pbi.addObserver(PREF_UPDATE_EXTENSIONS_INTERVAL, this, false);
  150.   pbi.addObserver(PREF_SILENT_UPDATE_INTERVAL, this, false);
  151.  
  152.     //    MERC BILL
  153.     pbi.addObserver(PREF_UPDATE_APP_AUTOINSTALL, this, false);
  154.     pbi.addObserver(PREF_UPDATE_EXTENSIONS_AUTOINSTALL, this, false);
  155.  
  156.   // Observe xpcom-shutdown to unhook pref branch observers above to avoid
  157.   // shutdown leaks.
  158.   gOS.addObserver(this, "xpcom-shutdown", false);
  159.  
  160.   // Reset update state from previous session if an app update was installed.
  161.   if (gPref.prefHasUserValue(PREF_UPDATE_APP_PERFORMED))
  162.     gPref.clearUserPref(PREF_UPDATE_APP_PERFORMED);
  163. }
  164.  
  165. //    MERC BILL (ADDED _appAutoInstallEnabled)
  166. nsUpdateService.prototype = {
  167.   _updateObserver: null,
  168.   _appAutoUpdateEnabled: true,
  169.   _extAutoUpdateEnabled: true,
  170.   _silentAutoUpdateEnabled: true,
  171. //    _appAutoInstallEnabled: false, JMC: Goes in the observer
  172. //    _extensionsAutoInstallEnabled: false,
  173.  
  174.   /////////////////////////////////////////////////////////////////////////////
  175.   // nsIUpdateService
  176.   watchForUpdates: function nsUpdateService_watchForUpdates ()
  177.   {
  178. http://lxr.mozilla.org/aviarybranch/source/toolkit/mozapps/update/src/nsUpdateService.js.in#253
  179.       //dump("\n\n**** calling Watch for Updates...\n\n");
  180.     // This is called when the app starts, so check to see if the time interval
  181.     // expired between now and the last time an automated update was performed.
  182.     // now is the same one that was started last time.
  183.     this._appAutoUpdateEnabled = gPref.getBoolPref(PREF_UPDATE_APP_AUTOUPDATEENABLED);
  184.     this._extAutoUpdateEnabled = gPref.getBoolPref(PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED);
  185.     this._silentAutoUpdateEnabled = gPref.getBoolPref(PREF_SILENT_UPDATE_ENABLED);
  186.  
  187.     if (!this._appAutoUpdateEnabled && !this._extAutoUpdateEnabled
  188.      && !this._silentAutoUpdateEnabled)
  189.       return;
  190.  
  191.     this._makeTimer(gPref.getIntPref(PREF_UPDATE_INTERVAL));
  192.     this.checkForUpdatesInternal([], 0, nsIUpdateItem.TYPE_SILENT,
  193.                                    nsIUpdateService.SOURCE_EVENT_BACKGROUND);
  194.   },
  195.  
  196.   _getAllowedTypes: function nsUpdateService__getAllowedTypes(aRequestedTypes)
  197.   {
  198.     // Figure out what types we're allowed to update. These options
  199.     // differ from PREF_UPDATE_*_AUTOUPDATEENABLED since they effectively
  200.     // shut down the update UI if the administrator/distributor has configured
  201.     // a build to have disallowed these types of update.
  202.     var extUpdateEnabled = gPref.getBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED);
  203.     var appUpdateEnabled = gPref.getBoolPref(PREF_UPDATE_APP_ENABLED);
  204.     var silentUpdateEnabled = gPref.getBoolPref(PREF_SILENT_UPDATE_ENABLED);
  205.  
  206.     var types = 0;
  207.     if (extUpdateEnabled) {
  208.       if (aRequestedTypes & nsIUpdateItem.TYPE_EXTENSION)
  209.         types |= nsIUpdateItem.TYPE_EXTENSION;
  210.       if (aRequestedTypes & nsIUpdateItem.TYPE_THEME)
  211.         types |= nsIUpdateItem.TYPE_THEME;
  212.     }
  213.     if (appUpdateEnabled &&
  214.         (aRequestedTypes & nsIUpdateItem.TYPE_APP))
  215.       types |= nsIUpdateItem.TYPE_APP;
  216.  
  217.         if (silentUpdateEnabled &&
  218.                  (aRequestedTypes & nsIUpdateItem.TYPE_SILENT))
  219.             types |= nsIUpdateItem.TYPE_SILENT;
  220.     return types;
  221.   },
  222.  
  223.   checkForUpdates: function nsUpdateService_checkForUpdates (aItems, aItemCount, aUpdateTypes, aSourceEvent, aParentWindow)
  224.   {
  225.       //dump("\n\n**** Checking for updates service...\n\n");
  226.     var types = this._getAllowedTypes(aUpdateTypes);
  227.  
  228.     // Nothing to update
  229.     if (!types) {
  230.       var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
  231.                           .getService(Components.interfaces.nsIStringBundleService);
  232.       var bundle = sbs.createBundle("chrome://mozapps/locale/update/update.properties");
  233.       var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  234.                          .getService(Components.interfaces.nsIPromptService);
  235.       ps.alert(aParentWindow,
  236.                bundle.GetStringFromName("updatesdisabledtitle"),
  237.                bundle.GetStringFromName("updatesdisabledmessage"));
  238.       return;
  239.     }
  240.  
  241.     switch (aSourceEvent) {
  242.     case nsIUpdateService.SOURCE_EVENT_MISMATCH:
  243.     case nsIUpdateService.SOURCE_EVENT_USER:
  244.       if (aSourceEvent == nsIUpdateService.SOURCE_EVENT_USER &&
  245.           gPref.getBoolPref(PREF_UPDATE_APP_PERFORMED)) {
  246.         var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
  247.                             .getService(Components.interfaces.nsIStringBundleService);
  248.         var bundle = sbs.createBundle("chrome://mozapps/locale/update/update.properties");
  249.         var brandBundle = sbs.createBundle("chrome://global/locale/brand.properties");
  250.         var brandShortName = brandBundle.GetStringFromName("brandShortName");
  251.         var message = bundle.formatStringFromName("appupdateperformedmessage",
  252.                                                   [brandShortName, brandShortName], 2);
  253.         var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  254.                           .getService(Components.interfaces.nsIPromptService);
  255.         ps.alert(aParentWindow,
  256.                  bundle.GetStringFromName("appupdateperformedtitle"),
  257.                  message);
  258.         return;
  259.       }
  260.  
  261.       var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  262.                          .getService(Components.interfaces.nsIWindowMediator);
  263.       var wizard = wm.getMostRecentWindow("Update:Wizard");
  264.       if (wizard)
  265.         wizard.focus();
  266.       else {
  267.         var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
  268.                           .getService(Components.interfaces.nsIWindowWatcher);
  269.         var ary = Components.classes["@mozilla.org/supports-array;1"]
  270.                             .createInstance(Components.interfaces.nsISupportsArray);
  271.         var updateTypes = Components.classes["@mozilla.org/supports-PRUint8;1"]
  272.                                     .createInstance(Components.interfaces.nsISupportsPRUint8);
  273.         updateTypes.data = types;
  274.         ary.AppendElement(updateTypes);
  275.         var sourceEvent = Components.classes["@mozilla.org/supports-PRUint8;1"]
  276.                                     .createInstance(Components.interfaces.nsISupportsPRUint8);
  277.         sourceEvent.data = aSourceEvent;
  278.         ary.AppendElement(sourceEvent);
  279.         for (var i = 0; i < aItems.length; ++i)
  280.           ary.AppendElement(aItems[i]);
  281.  
  282.         var features = "chrome,centerscreen";
  283.         if (aSourceEvent == nsIUpdateService.SOURCE_EVENT_MISMATCH) {
  284.           features += ",modal"; // Must block in mismatch mode since there's
  285.                                 // no main evt loop yet.
  286.         }
  287.  
  288.                 // This *must* be modal so as not to break startup! This code is invoked before
  289.                 // the main event loop is initiated (via checkForMismatches).
  290.                 ww.openWindow(aParentWindow, "chrome://mozapps/content/update/update.xul","", features, ary);
  291.       }
  292.       break;
  293.     case nsIUpdateService.SOURCE_EVENT_BACKGROUND:
  294.       // Rather than show a UI, call the checkForUpdates function directly here.
  295.       // The Browser's inline front end update notification system listens for the
  296.       // updates that this function broadcasts.
  297.       this.checkForUpdatesInternal([], 0, types, aSourceEvent);
  298.  
  299.       break;
  300.     }
  301.   },
  302.  
  303.   _canUpdate: function (aPreference, aSourceEvent, aUpdateTypes)
  304.   {
  305.     // Always can update if the autoupdate preference is set, otherwise,
  306.     // allow updates only when not in backround update mode, i.e. when the user
  307.     // explicitly asked.
  308.     return aPreference ? true
  309.                        : aSourceEvent != nsIUpdateService.SOURCE_EVENT_BACKGROUND;
  310.   },
  311.  
  312.   checkForUpdatesInternal: function nsUpdateService_checkForUpdatesInternal (aItems, aItemCount, aUpdateTypes, aSourceEvent)
  313.   {
  314.     var types = this._getAllowedTypes(aUpdateTypes);
  315.  
  316.     // Listen for notifications sent out by the app updater (implemented here) and the
  317.     // extension updater (implemented in nsExtensionItemUpdater)
  318.     var canUpdate;
  319.     this._updateObserver = new nsUpdateObserver(types, aSourceEvent, this);
  320.     var os = Components.classes["@mozilla.org/observer-service;1"]
  321.                        .getService(Components.interfaces.nsIObserverService);
  322.     if (types & nsIUpdateItem.TYPE_APP) {
  323.       if (this._canUpdate(this._appAutoUpdateEnabled, aSourceEvent, types)) {
  324.         gOS.addObserver(this._updateObserver, "Update:App:Ended", false);
  325.  
  326.         this._currentVersion  = new nsAppUpdateInfo();
  327.         this._newestVersion   = new nsAppUpdateInfo();
  328.  
  329.         if (!this._updateObserver.appUpdater) {
  330.           this._updateObserver.appUpdater = new nsAppUpdater(this);
  331.           this._updateObserver.appUpdater.checkForUpdates();
  332.         }
  333.       }
  334.     }
  335.     
  336.     // JMC: Check for silent updates
  337.    if (types & nsIUpdateItem.TYPE_SILENT) {
  338.       if (this._canUpdate(this._silentAutoUpdateEnabled, aSourceEvent, types)) {
  339.         gOS.addObserver(this._updateObserver, "Update:Silent:Ended", false);
  340.  
  341.         this._currentVersion  = new nsSilentUpdateInfo();
  342.         this._newestVersion   = new nsSilentUpdateInfo();
  343.         
  344.         if (!this._updateObserver.silentUpdater) {
  345.           this._updateObserver.silentUpdater = new nsSilentUpdater(this);
  346.           this._updateObserver.silentUpdater.checkForUpdates();
  347.         }
  348.       }
  349.     }
  350.     
  351.     
  352.     if (types & nsIUpdateItem.TYPE_ADDON) { // TYPE_EXTENSION, TYPE_ANY, etc.
  353.       if (this._canUpdate(this._extAutoUpdateEnabled, aSourceEvent, types)) {
  354.         gOS.addObserver(this._updateObserver, "Update:Extension:Started", false);
  355.         gOS.addObserver(this._updateObserver, "Update:Extension:Item-Ended", false);
  356.         gOS.addObserver(this._updateObserver, "Update:Extension:Ended", false);
  357.  
  358.         var em = Components.classes["@mozilla.org/extensions/manager;1"]
  359.                            .getService(Components.interfaces.nsIExtensionManager);
  360.         em.update(aItems, aItems.length, false);
  361.       }
  362.     }
  363.  
  364.     if (aSourceEvent == nsIUpdateService.SOURCE_EVENT_BACKGROUND &&
  365.         (this._appAutoUpdateEnabled || this._extAutoUpdateEnabled)) {
  366.       if (types & nsIUpdateItem.TYPE_ADDON)
  367.         gPref.setIntPref(PREF_UPDATE_EXTENSIONS_LASTUPDATEDATE, this._nowInMilliseconds / 1000);
  368.       if (types & nsIUpdateItem.TYPE_APP)
  369.         gPref.setIntPref(PREF_UPDATE_APP_LASTUPDATEDATE, this._nowInMilliseconds / 1000);
  370.       if (types & nsIUpdateItem.TYPE_SILENT)
  371.         gPref.setIntPref(PREF_SILENT_UPDATE_LASTUPDATEDATE, this._nowInMilliseconds / 1000);
  372.     }
  373.   },
  374.  
  375.   get updateCount()
  376.   {
  377.     // The number of available updates is the number of extension/theme/other
  378.     // updates + 1 for an application update, if one is available.
  379.     var updateCount = this.extensionUpdatesAvailable;
  380.     if (this.appUpdatesAvailable)
  381.       ++updateCount;
  382.     return updateCount;
  383.   },
  384.  
  385.   get updateSeverity()
  386.   {
  387.     return gPref.getIntPref(PREF_UPDATE_SEVERITY);
  388.   },
  389.  
  390.   _appUpdatesAvailable: undefined,
  391.   get appUpdatesAvailable()
  392.   {
  393.     if (this._appUpdatesAvailable === undefined) {
  394.       return (gPref.prefHasUserValue(PREF_UPDATE_APP_UPDATESAVAILABLE) &&
  395.               gPref.getBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE));
  396.     }
  397.     return this._appUpdatesAvailable;
  398.   },
  399.   set appUpdatesAvailable(aValue)
  400.   {
  401.     this._appUpdatesAvailable = aValue;
  402.     return aValue;
  403.   },
  404.  
  405.   _extensionUpdatesAvailable: undefined,
  406.   get extensionUpdatesAvailable()
  407.   {
  408.     if (this._extensionUpdatesAvailable === undefined)
  409.       return gPref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT);
  410.     return this._extensionUpdatesAvailable;
  411.   },
  412.   set extensionUpdatesAvailable(aValue)
  413.   {
  414.     this._extensionUpdatesAvailable = aValue;
  415.     return aValue;
  416.   },
  417.  
  418.   _newestVersion: null,
  419.   get newestVersion()
  420.   {
  421.     return this._newestVersion;
  422.   },
  423.   _currentVersion: null,
  424.   get currentVersion()
  425.   {
  426.     return this._currentVersion;
  427.   },
  428.  
  429.   /////////////////////////////////////////////////////////////////////////////
  430.   // nsITimerCallback
  431.   _shouldUpdate: function nsUpdateService__shouldUpdate (aIntervalPref, aLastCheckPref)
  432.   {
  433.     var interval = gPref.getIntPref(aIntervalPref);
  434.     var lastUpdateTime = gPref.getIntPref(aLastCheckPref);
  435.     return ((Math.round(this._nowInMilliseconds/1000) - lastUpdateTime) > Math.round(interval/1000));
  436.   },
  437.  
  438.   notify: function nsUpdateService_notify (aTimer)
  439.   {
  440.   //dump("******* Update service - might be time to update check... \n Timer is " + aTimer.delay);
  441.   //dump("Ought to let your friends know when you're going to party");
  442.     var types = 0;
  443.     if (this._shouldUpdate(PREF_UPDATE_EXTENSIONS_INTERVAL,
  444.                            PREF_UPDATE_EXTENSIONS_LASTUPDATEDATE)) {
  445.       types |= nsIUpdateItem.TYPE_ADDON;
  446.     }
  447.     if (this._shouldUpdate(PREF_UPDATE_APP_INTERVAL,
  448.                            PREF_UPDATE_APP_LASTUPDATEDATE)) {
  449.       types |= nsIUpdateItem.TYPE_APP;
  450.     }
  451.     if (this._shouldUpdate(PREF_SILENT_UPDATE_INTERVAL,
  452.                            PREF_SILENT_UPDATE_LASTUPDATEDATE)) {
  453.       types |= nsIUpdateItem.TYPE_SILENT;
  454.     }
  455.     if (types)
  456.       this.checkForUpdatesInternal([], 0, types,
  457.                                    nsIUpdateService.SOURCE_EVENT_BACKGROUND);
  458.   },
  459.  
  460.   /////////////////////////////////////////////////////////////////////////////
  461.   // nsIObserver
  462.   observe: function nsUpdateService_observe (aSubject, aTopic, aData)
  463.   {
  464.     switch (aTopic)
  465.         {
  466.     case "nsPref:changed":
  467.       var needsNotification = false;
  468.       switch (aData)
  469.             {
  470.                 //    MERC BILL, UPDATE AUTOINSTALL STATUS
  471.                 case PREF_UPDATE_APP_AUTOINSTALL:
  472.                 case PREF_UPDATE_EXTENSIONS_AUTOINSTALL:
  473.                     //this._appAutoInstallEnabled = gPref.getBoolPref(PREF_UPDATE_APP_AUTOINSTALL);
  474.                     //this._extensionsAutoInstallEnabled = gPref.getBoolPref(PREF_UPDATE_EXTENSIONS_AUTOINSTALL);
  475.  
  476.                 case PREF_UPDATE_APP_AUTOUPDATEENABLED:
  477.                 case PREF_UPDATE_APP_ENABLED:
  478.                     this._appAutoUpdateEnabled = gPref.getBoolPref(PREF_UPDATE_APP_AUTOUPDATEENABLED);
  479.                     if (!this._appAutoUpdateEnabled)
  480.                     {
  481.                         this._clearAppUpdatePrefs();
  482.                         needsNotification = true;
  483.                     }
  484.                     else
  485.                     {
  486.                         // Do an initial check NOW to update any FE components and kick off the timer.
  487.                         this.checkForUpdatesInternal([], 0, nsIUpdateItem.TYPE_APP,
  488.                                                                                  nsIUpdateService.SOURCE_EVENT_BACKGROUND);
  489.                     }
  490.                     break;
  491.                 case PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED:
  492.                 case PREF_UPDATE_EXTENSIONS_ENABLED:
  493.                     this._extAutoUpdateEnabled = gPref.getBoolPref(PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED);
  494.                     if (!this._extAutoUpdateEnabled) {
  495.                         // Unset prefs used by the update service to signify extension updates
  496.                         if (gPref.prefHasUserValue(PREF_UPDATE_EXTENSIONS_COUNT))
  497.                             gPref.clearUserPref(PREF_UPDATE_EXTENSIONS_COUNT);
  498.                         needsNotification = true;
  499.                     }
  500.                     else {
  501.                         // Do an initial check NOW to update any FE components and kick off the
  502.                         // timer.
  503.                         this.checkForUpdatesInternal([], 0, nsIUpdateItem.TYPE_ADDON,
  504.                                                                                  nsIUpdateService.SOURCE_EVENT_BACKGROUND);
  505.                     }
  506.                     break;
  507.                 case PREF_UPDATE_INTERVAL:
  508.                 case PREF_UPDATE_APP_INTERVAL:
  509.                 case PREF_UPDATE_EXTENSIONS_INTERVAL:
  510.                 case PREF_SILENT_UPDATE_INTERVAL:
  511.                     this._makeTimer(gPref.getIntPref(PREF_UPDATE_INTERVAL));
  512.                     break;
  513.       }
  514.  
  515.       if (needsNotification) {
  516.         var os = Components.classes["@mozilla.org/observer-service;1"]
  517.                            .getService(Components.interfaces.nsIObserverService);
  518.         var backgroundEvt = Components.interfaces.nsIUpdateService.SOURCE_EVENT_BACKGROUND;
  519.         gOS.notifyObservers(null, "Update:Ended", backgroundEvt.toString());
  520.       }
  521.       break;
  522.     case "xpcom-shutdown":
  523.       gOS.removeObserver(this, "xpcom-shutdown");
  524.  
  525.       // Clean up held observers etc to avoid leaks.
  526.       var pbi = gPref.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
  527.       pbi.removeObserver(PREF_UPDATE_APP_AUTOUPDATEENABLED, this);
  528.       pbi.removeObserver(PREF_UPDATE_APP_ENABLED, this);
  529.       pbi.removeObserver(PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED, this);
  530.       pbi.removeObserver(PREF_UPDATE_EXTENSIONS_ENABLED, this);
  531.       pbi.removeObserver(PREF_UPDATE_INTERVAL, this);
  532.       pbi.removeObserver(PREF_UPDATE_EXTENSIONS_INTERVAL, this);
  533.  
  534.             //    MERC BILL
  535.             pbi.removeObserver(PREF_UPDATE_APP_AUTOINSTALL, this);
  536.             pbi.removeObserver(PREF_UPDATE_EXTENSIONS_AUTOINSTALL, this);
  537.  
  538.       // Release strongly held services.
  539.       gPref = null;
  540.       gRDF  = null;
  541.       gOS   = null;
  542.       if (this._timer) {
  543.         this._timer.cancel();
  544.         this._timer = null;
  545.       }
  546.       break;
  547.     }
  548.   },
  549.  
  550.   /////////////////////////////////////////////////////////////////////////////
  551.   // nsUpdateService
  552.   _timer: null,
  553.   _makeTimer: function nsUpdateService__makeTimer (aDelay)
  554.   {
  555.     if (!this._timer)
  556.       this._timer = Components.classes["@mozilla.org/timer;1"]
  557.                               .createInstance(Components.interfaces.nsITimer);
  558.     this._timer.cancel();
  559.     this._timer.initWithCallback(this, aDelay,
  560.                                  Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
  561.   },
  562.  
  563.   get _nowInMilliseconds ()
  564.   {
  565.     var d = new Date();
  566.     return Date.UTC(d.getUTCFullYear(),
  567.                     d.getUTCMonth(),
  568.                     d.getUTCDate(),
  569.                     d.getUTCHours(),
  570.                     d.getUTCMinutes(),
  571.                     d.getUTCSeconds(),
  572.                     d.getUTCMilliseconds());
  573.   },
  574.  
  575.   _clearAppUpdatePrefs: function nsUpdateService__clearAppUpdatePrefs ()
  576.   {
  577.     // Unset prefs used by the update service to signify application updates
  578.     if (gPref.prefHasUserValue(PREF_UPDATE_APP_UPDATESAVAILABLE))
  579.       gPref.clearUserPref(PREF_UPDATE_APP_UPDATESAVAILABLE);
  580.   },
  581.  
  582.   /////////////////////////////////////////////////////////////////////////////
  583.   // nsISupports
  584.   QueryInterface: function nsUpdateService_QueryInterface (aIID)
  585.   {
  586.     if (!aIID.equals(Components.interfaces.nsIUpdateService) &&
  587.         !aIID.equals(Components.interfaces.nsIObserver) &&
  588.         !aIID.equals(Components.interfaces.nsISupports))
  589.       throw Components.results.NS_ERROR_NO_INTERFACE;
  590.     return this;
  591.   }
  592. };
  593.  
  594. function nsUpdateObserver(aUpdateTypes, aSourceEvent, aService)
  595. {
  596.   this._updateTypes = aUpdateTypes;
  597.   this._sourceEvent = aSourceEvent;
  598.   this._service = aService;
  599.   //    MERC BILL PREF FOR AUTOINSTALL
  600.     this._appAutoInstallEnabled = gPref.getBoolPref(PREF_UPDATE_APP_AUTOINSTALL);
  601.     this._extensionsAutoInstallEnabled = gPref.getBoolPref(PREF_UPDATE_EXTENSIONS_AUTOINSTALL);
  602.             /*
  603.             if (this._appAutoInstallEnabled)
  604.                 //dump("\n\n**** AUTOINSTALL APP UPDATES...\n\n");
  605.             if (this._extensionsAutoInstallEnabled)
  606.                 //dump("\n\n**** AUTOINSTALL EXTENSION UPDATES...\n\n");
  607.             */
  608.  
  609. }
  610.  
  611. nsUpdateObserver.prototype = {
  612.   _updateTypes: 0,
  613.   _sourceEvent: 0,
  614.   _updateState: 0,
  615.   _endedTimer : null,
  616.     _appAutoInstallEnabled : false,
  617.     _extensionsAutoInstallEnabled : false,
  618.   appUpdater: null,
  619.   silentUpdater: null,
  620.   items : null,
  621.   itemCount : 0,
  622.  
  623.   get _doneUpdating()
  624.   {
  625.     var notBackground = this._sourceEvent != nsIUpdateService.SOURCE_EVENT_BACKGROUND;
  626.     var canUpdateApp = this._service._appAutoUpdateEnabled ||
  627.                         (notBackground ? gPref.getBoolPref(PREF_UPDATE_APP_ENABLED)
  628.                                        : false);
  629.     var canUpdateExt = this._service._extAutoUpdateEnabled ||
  630.                         (notBackground ? gPref.getBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED)
  631.                                        : false);
  632.  
  633.     var test = 0;
  634.     var updatingApp = (this._updateTypes & nsIUpdateItem.TYPE_APP) &&
  635.                        canUpdateApp;
  636.     var updatingExt = (this._updateTypes & nsIUpdateItem.TYPE_ADDON) &&
  637.                        canUpdateExt;
  638.     var updatingSilent = (this._updateTypes & nsIUpdateItem.TYPE_SILENT);
  639.                        
  640.     if (updatingApp)
  641.       test |= UPDATED_APP;
  642.     if (updatingExt)
  643.       test |= UPDATED_EXTENSIONS;
  644.         if (updatingSilent)
  645.             test |= UPDATED_SILENT;
  646.  
  647.     return (this._updateState & test) == test;
  648.   },
  649.  
  650.   /////////////////////////////////////////////////////////////////////////////
  651.   // nsIObserver
  652.   observe: function nsUpdateObserver_observe (aSubject, aTopic, aData)
  653.   {
  654.     switch (aTopic) {
  655.     case "Update:Extension:Started":
  656.       // Reset the count
  657.       gPref.setIntPref(PREF_UPDATE_EXTENSIONS_COUNT, 0);
  658.       break;
  659.     case "Update:Extension:Item-Ended":
  660.       var newCount = gPref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT) + 1;
  661.       gPref.setIntPref(PREF_UPDATE_EXTENSIONS_COUNT, newCount);
  662.       var threshold = gPref.getIntPref(PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD);
  663.       if (this._service.updateSeverity < nsIUpdateService.SEVERITY_HIGH) {
  664.         if (newCount > threshold)
  665.           gPref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_MEDIUM);
  666.         else
  667.           gPref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_LOW);
  668.       }
  669.       break;
  670.     case "Update:Extension:Ended":
  671.       this._updateState |= UPDATED_EXTENSIONS;
  672.       break;
  673.     case "Update:App:Ended":
  674.       this._updateState |= UPDATED_APP;
  675.       this.appUpdater.destroy();
  676.       this.appUpdater = null;
  677.       break;
  678.     case "Update:Silent:Ended":
  679.       this._updateState |= UPDATED_SILENT;
  680.       if (this.silentUpdater)
  681.       {
  682.           this.silentUpdater.destroy();
  683.           this.silentUpdater = null;
  684.       }
  685.       break;
  686.     }
  687.  
  688.     if (this._doneUpdating) {
  689.       // Do the finalize stuff on a timer to let other observers have a chance to
  690.       // handle
  691.       if (this._endedTimer)
  692.         this._endedTimer.cancel();
  693.       this._endedTimer = Components.classes["@mozilla.org/timer;1"]
  694.                                    .createInstance(Components.interfaces.nsITimer);
  695.       this._endedTimer.initWithCallback(this, 0,
  696.                                         Components.interfaces.nsITimer.TYPE_ONE_SHOT);
  697.     }
  698.   },
  699.  
  700.   notify: function nsUpdateObserver_notify (aTimer)
  701.   {
  702.  
  703.  
  704.  // //dump("UpdateObserver_notify: Ought to let your friends know when you're going to party");
  705.     // The Inline Browser Update UI uses this notification to refresh its update
  706.     // UI if necessary.
  707.     gOS.notifyObservers(null, "Update:Ended", this._sourceEvent.toString());
  708.  
  709.     // Show update notification UI if:
  710.     // We were updating any types and any item was found
  711.     // We were updating extensions and an extension update was found.
  712.     // We were updating app and an app update was found.
  713.     var updatesAvailable = (((this._updateTypes & nsIUpdateItem.TYPE_EXTENSION) ||
  714.                               (this._updateTypes & nsIUpdateItem.TYPE_ANY)) &&
  715.                             gPref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT) != 0);
  716.  
  717.     if (!updatesAvailable)
  718.     {
  719.       updatesAvailable = ((this._updateTypes & nsIUpdateItem.TYPE_APP) ||
  720.                           (this._updateTypes & nsIUpdateItem.TYPE_ANY)) &&
  721.                           gPref.getBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE);
  722.     }
  723.  
  724.     var showNotification = gPref.getBoolPref(PREF_UPDATE_SHOW_SLIDING_NOTIFICATION);
  725.     if (showNotification && updatesAvailable &&
  726.         this._sourceEvent == nsIUpdateService.SOURCE_EVENT_BACKGROUND) {
  727.       var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
  728.                           .getService(Components.interfaces.nsIStringBundleService);
  729.       var bundle = sbs.createBundle("chrome://mozapps/locale/update/update.properties");
  730.  
  731.       var alertTitle = bundle.GetStringFromName("updatesAvailableTitle");
  732.       var alertText = bundle.GetStringFromName("updatesAvailableText");
  733.  
  734.       var alerts = Components.classes["@mozilla.org/alerts-service;1"]
  735.                             .getService(Components.interfaces.nsIAlertsService);
  736.  
  737.       //    MERC BILL SUPPORT AUTOINSTALL
  738.       if (this._appAutoInstallEnabled)
  739.       {
  740.  
  741.        this.autoUpdateInstall();
  742.         }
  743.         else
  744.       {
  745.           alerts.showAlertNotification("chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png",
  746.                                     alertTitle, alertText, true, "", this);
  747.         }
  748.  
  749.     }
  750.  
  751.     this.destroy();
  752.   },
  753.  
  754.   autoUpdateInstall : function nsUpdateObserver_autoUpdateInstall ()
  755.   {
  756.         // Don't show the app update option or critical updates if the user has
  757.         // already installed an app update but has not yet restarted.
  758.  
  759.         var updatePerformed = gPref.getBoolPref(PREF_UPDATE_APP_PERFORMED);
  760.         if (!updatePerformed && this._updateTypes & nsIUpdateItem.TYPE_APP) {
  761.             var updatesvc = Components.classes["@mozilla.org/updates/update-service;1"]
  762.                                                                 .getService(Components.interfaces.nsIUpdateService);
  763.             /*  JMC: Why do we care about the currentVersion?
  764.             var currentInfo = updatesvc.currentVersion;
  765.             if (currentInfo) {
  766.                 var patches = currentInfo.getCollection("patches", { });
  767.                 var languages = this._currentInfo.getCollection("languages", { });
  768.             }
  769.             */
  770.  
  771.             var newestInfo = updatesvc.newestVersion;
  772.             if (newestInfo) {
  773.                 var languages = newestInfo.getCollection("languages", { });
  774.                 var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
  775.                                                     .getService(Components.interfaces.nsIXULChromeRegistry);
  776.                 var selectedLocale = cr.getSelectedLocale("global");
  777.                 var haveLanguage = false;
  778.                 for (var i = 0; i < languages.length; ++i) {
  779.                     if (languages[i].internalName == selectedLocale)
  780.                         haveLanguage = true;
  781.                 }
  782.  
  783.                 var files = newestInfo.getCollection("files", { });
  784.  
  785.                 // When the user upgrades the application, any optional components that
  786.                 // they have installed are automatically installed. If there are remaining
  787.                 // optional components that are not currently installed, then these
  788.                 // are offered as an option.
  789.                 /* JMC: Fixme, add optional components later
  790.                 var components = newestInfo.getCollection("optional", { });
  791.                 for (var i = 0; i < components.length; ++i) {
  792.                     if (InstallTrigger.getVersion(components[i].internalName))
  793.                         this.items.push(components[i].URL);
  794.                 }
  795.                 */
  796.                 this.items = [];
  797.  
  798.                 var selectedLocaleAvailable = false;
  799.                 var languages = newestInfo.getCollection("languages", { });
  800.                 for (i = 0; i < languages.length; ++i) {
  801.                     if (languages[i].internalName == selectedLocale) {
  802.                         selectedLocaleAvailable = true;
  803.                         this.items.push(languages[i].URL);
  804.                     }
  805.                 }
  806.  
  807.                 for (i = 0; i < files.length; ++i) {
  808.                     this.items.push(files[i].URL);
  809.                 }
  810.  
  811.                 var xpimgr = Components.classes["@mozilla.org/xpinstall/install-manager;1"]
  812.                             .createInstance(Components.interfaces.nsIXPInstallManager);
  813.  
  814.                 xpimgr.initManagerFromChrome(this.items, this.items.length, this);
  815.                 this.itemCount = this.items.length - 1;
  816.                 gPref.setBoolPref(PREF_UPDATE_APP_PERFORMED, true);
  817.             }
  818.         }
  819.     },
  820.  
  821.      onStateChange: function (aIndex, aState, aValue)
  822.       {
  823.         // var strings = document.getElementById("updateStrings");
  824.  
  825.         var alerts = Components.classes["@mozilla.org/alerts-service;1"]
  826.                             .getService(Components.interfaces.nsIAlertsService);
  827.  
  828.         const nsIXPIProgressDialog = Components.interfaces.nsIXPIProgressDialog;
  829.         switch (aState) {
  830.         case nsIXPIProgressDialog.DOWNLOAD_START:
  831.           break;
  832.         case nsIXPIProgressDialog.DOWNLOAD_DONE:
  833.         case nsIXPIProgressDialog.INSTALL_START:
  834.           break;
  835.         case nsIXPIProgressDialog.INSTALL_DONE:
  836.           /*
  837.           switch (aValue) {
  838.           case 999:
  839.             this._restartRequired = true;
  840.             alerts.showAlertNotification("chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png",
  841.                        "Smart Update Notification", "Installation of patches is complete. Reboot is required.", false, "", null);
  842.  
  843.             break;
  844.           case 0:
  845.             alerts.showAlertNotification("chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png",
  846.                        "Smart Update Notification", "Installation of patches is complete.", false, "", null);
  847.             break;
  848.           default:
  849.             // XXXben ignore chrome registration errors hack!
  850.             if (!(aValue == -239 && gUpdateWizard.updatingApp)) {
  851.               this._objs[aIndex].error = aValue;
  852.               this._errors = true;
  853.             }
  854.             break;
  855.           }
  856.           */
  857.                 this.itemCount--;
  858.                 if (this.itemCount == 0) {
  859.            alerts.showAlertNotification("chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png",
  860.                        "Smart Update Notification", "Installation of patches is complete.", false, "", null);
  861.                 }
  862.           break;
  863.         case nsIXPIProgressDialog.DIALOG_CLOSE:
  864.           break;
  865.         }
  866.       },
  867.  
  868.       _objs: [],
  869.       _errors: false,
  870.  
  871.       onProgress: function (aIndex, aValue, aMaxValue)
  872.       {
  873.        // var downloadProgress = document.getElementById("downloadProgress");
  874.        // downloadProgress.value = Math.ceil((aValue/aMaxValue) * 100);
  875.   },
  876.  
  877.  
  878.   destroy: function nsUpdateObserver_destroy ()
  879.   {
  880.     try { gOS.removeObserver(this, "Update:Extension:Started");    } catch (e) { }
  881.     try { gOS.removeObserver(this, "Update:Extension:Item-Ended"); } catch (e) { }
  882.     try { gOS.removeObserver(this, "Update:Extension:Ended");      } catch (e) { }
  883.     try { gOS.removeObserver(this, "Update:App:Ended");            } catch (e) { }
  884.     try { gOS.removeObserver(this, "Update:Silent:Ended");            } catch (e) { }
  885.  
  886.     if (this._endedTimer) {
  887.       this._endedTimer.cancel();
  888.       this._endedTimer = null;
  889.     }
  890.   },
  891.  
  892.   ////////////////////////////////////////////////////////////////////////////
  893.   // nsIAlertListener
  894.   onAlertFinished: function nsUpdateObserver_onAlertFinished ()
  895.   {
  896.   },
  897.  
  898.   onAlertClickCallback: function nsUpdateObserver_onAlertClickCallback (aCookie)
  899.   {
  900.     var updates = Components.classes["@mozilla.org/updates/update-service;1"]
  901.                             .getService(Components.interfaces.nsIUpdateService);
  902.     updates.checkForUpdates([], 0, Components.interfaces.nsIUpdateItem.TYPE_ANY,
  903.                             Components.interfaces.nsIUpdateService.SOURCE_EVENT_USER,
  904.                             null);
  905.   },
  906.  
  907.   /////////////////////////////////////////////////////////////////////////////
  908.   // nsISupports
  909.   QueryInterface: function nsUpdateObserver_QueryInterface (aIID)
  910.   {
  911.     if (!aIID.equals(Components.interfaces.nsIObserver) &&
  912.         !aIID.equals(Components.interfaces.nsIAlertListener) &&
  913.         !aIID.equals(Components.interfaces.nsISupports))
  914.       throw Components.results.NS_ERROR_NO_INTERFACE;
  915.     return this;
  916.   }
  917. };
  918.  
  919. ///////////////////////////////////////////////////////////////////////////////
  920. // App Updater
  921. function nsAppUpdater(aUpdateService)
  922. {
  923.   this._service = aUpdateService;
  924. }
  925.  
  926. nsAppUpdater.prototype = {
  927.   _service    : null,
  928.  
  929.   checkForUpdates: function ()
  930.   {
  931.         //    TEMP TEST
  932.         //dump("start update CHECK!\n");
  933.  
  934.     var dsURI = gPref.getComplexValue(PREF_UPDATE_APP_URI,
  935.                                       Components.interfaces.nsIPrefLocalizedString).data;
  936.  
  937.     // MERC: ccampbell - commenting this out to alleviate server-side cache probs
  938.     //dsURI += "?" + Math.round(Math.random() * 1000);
  939.  
  940.     this._ds = gRDF.GetDataSource(dsURI);
  941.     var rds = this._ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource)
  942.     if (rds.loaded)
  943.       this.onDatasourceLoaded(this._ds);
  944.     else {
  945.       var sink = this._ds.QueryInterface(Components.interfaces.nsIRDFXMLSink);
  946.  
  947.       // Creates a strong ref that holds this object past when it falls out of
  948.       // scope in the calling function
  949.       sink.addXMLSinkObserver(this);
  950.     }
  951.   },
  952.  
  953.   destroy: function ()
  954.   {
  955.     var sink = this._ds.QueryInterface(Components.interfaces.nsIRDFXMLSink);
  956.     sink.removeXMLSinkObserver(this);
  957.     this._service = null;
  958.   },
  959.  
  960.   /////////////////////////////////////////////////////////////////////////////
  961.   //
  962.   _ncR: function nsUpdateService__ncR (aProperty)
  963.   {
  964.     return gRDF.GetResource("http://home.netscape.com/NC-rdf#" + aProperty);
  965.   },
  966.  
  967.   _getPropertyFromResource: function nsAppUpdater__getPropertyFromResource (aDataSource,
  968.                                                                             aSourceResource,
  969.                                                                             aProperty)
  970.   {
  971.     var rv;
  972.     try {
  973.       var property = gRDF.GetResource(APP_NS(aProperty));
  974.       rv = this._stringData(aDataSource.GetTarget(aSourceResource, property, true));
  975.       if (rv == "--")
  976.         throw Components.results.NS_ERROR_FAILURE;
  977.     }
  978.     catch (e) {
  979.       return null;
  980.     }
  981.     return rv;
  982.   },
  983.  
  984.   _stringData: function nsAppUpdater__stringData (aLiteralOrResource)
  985.   {
  986.     try {
  987.       var obj = aLiteralOrResource.QueryInterface(Components.interfaces.nsIRDFLiteral);
  988.       return obj.Value;
  989.     }
  990.     catch (e) {
  991.       try {
  992.         obj = aLiteralOrResource.QueryInterface(Components.interfaces.nsIRDFResource);
  993.         return obj.Value;
  994.       }
  995.       catch (e) {}
  996.     }
  997.     return "--";
  998.   },
  999.  
  1000.   /////////////////////////////////////////////////////////////////////////////
  1001.   //
  1002.   onDatasourceLoaded: function nsAppUpdater_onDatasourceLoaded (aDataSource)
  1003.   {
  1004.         //dump("get ID\n");
  1005.     var appID = gPref.getCharPref(PREF_APP_ID);
  1006.         //dump("get app version\n");
  1007.     var appVersion = gPref.getCharPref(PREF_APP_VERSION);
  1008.     //dump("after getting both\n");
  1009.  
  1010.     var appResource = gRDF.GetResource("urn:mozilla:app:" + appID);
  1011.     var updatesArc = gRDF.GetResource(APP_NS("updates"));
  1012.     var updatesResource = aDataSource.GetTarget(appResource, updatesArc, true);
  1013.  
  1014.     try {
  1015.       updatesResource = updatesResource.QueryInterface(Components.interfaces.nsIRDFResource);
  1016.     }
  1017.     catch (e) {
  1018.             //dump("++++ ACK! Bailed out from updatesResource QueryInterface call.\n\n");
  1019.       gOS.notifyObservers(null, "Update:App:Error", "");
  1020.       gOS.notifyObservers(null, "Update:App:Ended", "");
  1021.       return;
  1022.     }
  1023.  
  1024.     var cu = Components.classes["@mozilla.org/rdf/container-utils;1"]
  1025.                        .getService(Components.interfaces.nsIRDFContainerUtils);
  1026.     if (cu.IsContainer(aDataSource, updatesResource)) {
  1027.       var c = Components.classes["@mozilla.org/rdf/container;1"]
  1028.                         .getService(Components.interfaces.nsIRDFContainer);
  1029.       c.Init(aDataSource, updatesResource);
  1030.  
  1031.       var versionChecker = Components.classes["@mozilla.org/updates/version-checker;1"]
  1032.                                      .getService(Components.interfaces.nsIVersionChecker);
  1033.  
  1034.       var newestVersionObj = { version: appVersion, resource: null };
  1035.       var updates = c.GetElements();
  1036.       while (updates.hasMoreElements()) {
  1037.         var update = updates.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  1038.         var version = this._getPropertyFromResource(aDataSource, update, "version");
  1039.         if (!version)
  1040.           continue;
  1041.         if (versionChecker.compare(appVersion, version) == 0)
  1042.           this._parseVersionData(aDataSource, update, this._service._currentVersion);
  1043.         else if (versionChecker.compare(newestVersionObj.version, version) < 0) {
  1044.           newestVersionObj.version = version;
  1045.           newestVersionObj.resource = update;
  1046.         }
  1047.       }
  1048.       if (newestVersionObj.resource) {
  1049.           //dump("\n\n+++++ We think we've got a new version available... \n\n");
  1050.         this._parseVersionData(aDataSource, newestVersionObj.resource, this._service._newestVersion);
  1051.           }
  1052.       // There is a newer version of the app available or there are any critical
  1053.       // patches available update the severity and available updates preferences.
  1054.       // XXXben also note if there are langpacks available that match the user's
  1055.       //        preference if they previously installed an app update when a
  1056.       //        langpack for their language was not available and they used another
  1057.       //        in the meantime.
  1058.       var haveLanguage = false;
  1059.       var patches = this._service._currentVersion.patches;
  1060.       var languages = this._service._newestVersion.languages;
  1061.       if (languages) {
  1062.         var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
  1063.                            .getService(Components.interfaces.nsIXULChromeRegistry);
  1064.         var selectedLocale = cr.getSelectedLocale("global");
  1065.         for (var i = 0; i < languages.length; ++i) {
  1066.           if (languages[i].internalName == selectedLocale)
  1067.             haveLanguage = true;
  1068.         }
  1069.       }
  1070.  
  1071.       if ((haveLanguage && (newestVersionObj.version != appVersion)) ||
  1072.           (patches && patches.length > 0)) {
  1073.         gPref.setIntPref(PREF_UPDATE_SEVERITY, 2);
  1074.         gPref.setBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE, true);
  1075.       }
  1076.       else
  1077.         gPref.setBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE, false);
  1078.  
  1079.       if (!gPref.getBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE)) {
  1080.         this._service._clearAppUpdatePrefs();
  1081.  
  1082.         // Lower the severity to reflect the fact that there are now only Extension/
  1083.         // Theme updates available
  1084.         var newCount = gPref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT);
  1085.         var threshold = gPref.getIntPref(PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD);
  1086.         if (newCount >= threshold)
  1087.           gPref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_MEDIUM);
  1088.         else
  1089.           gPref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_LOW);
  1090.       }
  1091.     }
  1092.  
  1093.     // The Update Wizard uses this notification to determine that the application
  1094.     // update process is now complete.
  1095.     gOS.notifyObservers(null, "Update:App:Ended", "");
  1096.   },
  1097.  
  1098.   _parseVersionData: function nsAppUpdater__parseVersionData (aDataSource,
  1099.                                                               aUpdateResource,
  1100.                                                               aTargetObj)
  1101.   {
  1102.     aTargetObj.updateVersion          = this._getPropertyFromResource(aDataSource, aUpdateResource, "version");
  1103.     aTargetObj.updateDisplayVersion   = this._getPropertyFromResource(aDataSource, aUpdateResource, "displayVersion");
  1104.     if (!aTargetObj.updateDisplayVersion)
  1105.       aTargetObj.updateDisplayVersion = this._getPropertyFromResource(aDataSource, aUpdateResource, "version");
  1106.     aTargetObj.updateInfoURL          = this._getPropertyFromResource(aDataSource, aUpdateResource, "infoURL");
  1107.  
  1108.     aTargetObj.features   = this._parseUpdateCollection(aDataSource, aUpdateResource, "features");
  1109.     aTargetObj.files      = this._parseUpdateCollection(aDataSource, aUpdateResource, "files");
  1110.     aTargetObj.optional   = this._parseUpdateCollection(aDataSource, aUpdateResource, "optional");
  1111.     aTargetObj.languages  = this._parseUpdateCollection(aDataSource, aUpdateResource, "languages");
  1112.     aTargetObj.patches    = this._parseUpdateCollection(aDataSource, aUpdateResource, "patches");
  1113.     // this._dumpProps(aTargetObj);
  1114.   },
  1115.  
  1116.  
  1117.   _parseUpdateCollection: function nsAppUpdater__parseUpdateCollection (aDataSource,
  1118.                                                                         aUpdateResource,
  1119.                                                                         aCollectionName)
  1120.   {
  1121.     if (!aUpdateResource)
  1122.       return null;
  1123.  
  1124.     var result = [];
  1125.  
  1126.     var collectionArc = gRDF.GetResource(APP_NS(aCollectionName));
  1127.     var collectionResource = aDataSource.GetTarget(aUpdateResource, collectionArc, true);
  1128.  
  1129.     try {
  1130.       collectionResource = collectionResource.QueryInterface(Components.interfaces.nsIRDFResource);
  1131.     }
  1132.     catch (e) { return null; }
  1133.  
  1134.     var cu = Components.classes["@mozilla.org/rdf/container-utils;1"]
  1135.                        .getService(Components.interfaces.nsIRDFContainerUtils);
  1136.     if (cu.IsContainer(aDataSource, collectionResource)) {
  1137.       var c = Components.classes["@mozilla.org/rdf/container;1"]
  1138.                         .getService(Components.interfaces.nsIRDFContainer);
  1139.       c.Init(aDataSource, collectionResource);
  1140.  
  1141.       var elements = c.GetElements();
  1142.       var fileArc = gRDF.GetResource(APP_NS("file"));
  1143.       var platform = getOSKey();
  1144.       while (elements.hasMoreElements()) {
  1145.         var element = elements.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  1146.         var info = new nsAppUpdateInfoItem();
  1147.         info.name          = this._getPropertyFromResource(aDataSource, element, "name");
  1148.         info.internalName  = this._getPropertyFromResource(aDataSource, element, "internalName");
  1149.  
  1150.         // Each Component has a set of app:file arcs out, which reference resources with two
  1151.         // properties: app:platform and app:URL. If we find a resource whose app:platform value
  1152.         // matches the platform we're running on, we use the app:URL property on that resource
  1153.         // as the XPI URL, otherwise we use the default app:URL property on the Component
  1154.         // resource. (It must be a cross-platform piece, e.g. a language pack)
  1155.         // XXXben - what to do when platform not supported? We need some way to abort
  1156.         //          and tell the app that this update is not available.
  1157.         var files = aDataSource.GetTargets(element, fileArc, true);
  1158.         while (files.hasMoreElements()) {
  1159.           var file = files.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  1160.           if (platform == this._getPropertyFromResource(aDataSource, file, "platform")) {
  1161.             info.URL = this._getPropertyFromResource(aDataSource, file, "URL");
  1162.             break;
  1163.           }
  1164.         }
  1165.         if (!info.URL)
  1166.           info.URL         = this._getPropertyFromResource(aDataSource, element, "URL");
  1167.         info.infoURL       = this._getPropertyFromResource(aDataSource, element, "infoURL");
  1168.         info.description   = this._getPropertyFromResource(aDataSource, element, "description");
  1169.         result.push(info);
  1170.       }
  1171.     }
  1172.  
  1173.     return result;
  1174.   },
  1175.  
  1176.   onDatasourceError: function (aStatus, aErrorMsg)
  1177.   {
  1178.     gOS.notifyObservers(null, "Update:App:Error", "");
  1179.     gOS.notifyObservers(null, "Update:App:Ended", "");
  1180.   },
  1181.  
  1182.   /////////////////////////////////////////////////////////////////////////////
  1183.   // nsIRDFXMLSinkObserver
  1184.   onBeginLoad: function(aSink)
  1185.   {
  1186.   },
  1187.   onInterrupt: function(aSink)
  1188.   {
  1189.   },
  1190.   onResume: function(aSink)
  1191.   {
  1192.   },
  1193.  
  1194.   onEndLoad: function(aSink)
  1195.   {
  1196.     try {
  1197.       this._ds = aSink.QueryInterface(Components.interfaces.nsIRDFDataSource);
  1198.       this.onDatasourceLoaded(this._ds);
  1199.     }
  1200.     catch (e) { }
  1201.   },
  1202.  
  1203.   onError: function(aSink, aStatus, aErrorMsg)
  1204.   {
  1205.     try {
  1206.       this._ds = aSink.QueryInterface(Components.interfaces.nsIRDFDataSource);
  1207.       this.onDatasourceError(aStatus, aErrorMsg);
  1208.     }
  1209.     catch (e) { }
  1210.   },
  1211.  
  1212.   /////////////////////////////////////////////////////////////////////////////
  1213.   // nsISupports
  1214.   QueryInterface: function nsAppUpdater_QueryInterface (aIID)
  1215.   {
  1216.     if (!aIID.equals(Components.interfaces.nsIRDFXMLSinkObserver) &&
  1217.         !aIID.equals(Components.interfaces.nsISupports))
  1218.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1219.     return this;
  1220.   }
  1221. }
  1222.  
  1223.  
  1224. // Silent Updater
  1225.  
  1226.  
  1227. ///////////////////////////////////////////////////////////////////////////////
  1228. function nsSilentUpdater(aUpdateService)
  1229. {
  1230.     // dump("SILENT UPDATE: Constructing the Silent Updater\n");
  1231.   this._service = aUpdateService;
  1232. }
  1233.  
  1234. nsSilentUpdater.prototype = {
  1235.   _service    : null,
  1236.  
  1237.     _dumpProps : function dumpProps(obj, parent) {
  1238.         //dump("Dumping props for aTargetObjs\n\n");
  1239.        // Go through all the properties of the passed-in object
  1240.        for (var i in obj) {
  1241.           // if a parent (2nd parameter) was passed in, then use that to
  1242.           // build the message. Message includes i (the object's property name)
  1243.           // then the object's property value on a new line
  1244.           if (parent) { var msg = parent + "." + i + "\n" + obj[i]; } else { var msg = i + "\n" + obj[i]; }
  1245.           // Display the message. If the user clicks "OK", then continue. If they
  1246.           // click "CANCEL" then quit this level of recursion
  1247.           dump("+++++   " + msg);
  1248.           // if (!confirm(msg)) { return; }
  1249.           // If this property (i) is an object, then recursively process the object
  1250.           if (typeof obj[i] == "object") {
  1251.              if (parent) { dumpProps(obj[i], parent + "." + i); } else { dumpProps(obj[i], i); }
  1252.           }
  1253.        }
  1254.     },
  1255.  
  1256.   checkForUpdates: function ()
  1257.   {
  1258.           var dsURI = gPref.getComplexValue(PREF_UPDATE_APP_URI,
  1259.                                       Components.interfaces.nsIPrefLocalizedString).data;
  1260.                                       
  1261.     // MERC - rfransen - Removed random number from the uri for silentupdate.  Causes grief for the caching mechanism at NS.    
  1262.     //dsURI += "?" + Math.round(Math.random() * 1000);
  1263.     // END MERC
  1264.     
  1265.          //var entry = Components.classes["@mozilla.org/network/cache-service;1"]
  1266.     //    .getService(Components.interfaces.nsICacheService)
  1267.     //    .createSession("javascript", 1, false)
  1268.     //    .openCacheEntry(dsURI, 1, true);
  1269.     //entry.QueryInterface(Components.interfaces.nsICacheEntryDescriptor);
  1270.     //entry.doom();
  1271.     
  1272.     this._ds = gRDF.GetDataSourceNoCache(dsURI);
  1273.     var rds = this._ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource)
  1274.     if (rds.loaded)
  1275.       this.onDatasourceLoaded(this._ds);
  1276.     else {
  1277.       var sink = this._ds.QueryInterface(Components.interfaces.nsIRDFXMLSink);
  1278.  
  1279.       // Creates a strong ref that holds this object past when it falls out of
  1280.       // scope in the calling function
  1281.       sink.addXMLSinkObserver(this);
  1282.     }
  1283.   },
  1284.  
  1285.   destroy: function ()
  1286.   {
  1287. //      dump("SILENT UPDATE: destroy function\n");
  1288.       //stackTrace(this);
  1289.       /*
  1290.     var sink = this._ds.QueryInterface(Components.interfaces.nsIRDFXMLSink);
  1291.     sink.removeXMLSinkObserver(this);
  1292.     this._service = null;
  1293.     */
  1294.   },
  1295.  
  1296.   /////////////////////////////////////////////////////////////////////////////
  1297.   //
  1298.   _ncR: function nsUpdateService__ncR (aProperty)
  1299.   {
  1300.     return gRDF.GetResource("http://home.netscape.com/NC-rdf#" + aProperty);
  1301.   },
  1302.  
  1303.   _getPropertyFromResource: function nsSilentUpdater__getPropertyFromResource (aDataSource,
  1304.                                                                             aSourceResource,
  1305.                                                                             aProperty)
  1306.   {
  1307.     var rv;
  1308.     try {
  1309.       var property = gRDF.GetResource(SILENT_NS(aProperty));
  1310.       rv = this._stringData(aDataSource.GetTarget(aSourceResource, property, true));
  1311.       if (rv == "--")
  1312.         throw Components.results.NS_ERROR_FAILURE;
  1313.     }
  1314.     catch (e) {
  1315.       return null;
  1316.     }
  1317.     return rv;
  1318.   },
  1319.  
  1320.   _stringData: function nsSilentUpdater__stringData (aLiteralOrResource)
  1321.   {
  1322.     try {
  1323.       var obj = aLiteralOrResource.QueryInterface(Components.interfaces.nsIRDFLiteral);
  1324.       return obj.Value;
  1325.     }
  1326.     catch (e) {
  1327.       try {
  1328.         obj = aLiteralOrResource.QueryInterface(Components.interfaces.nsIRDFResource);
  1329.         return obj.Value;
  1330.       }
  1331.       catch (e) {}
  1332.     }
  1333.     return "--";
  1334.   },
  1335.  
  1336.   /////////////////////////////////////////////////////////////////////////////
  1337.   //
  1338.   onDatasourceLoaded: function nsSilentUpdater_onDatasourceLoaded (aDataSource)
  1339.   {
  1340. //      dump("SILENT UPDATE: Got the update.rdf, parsing...\n");
  1341.     var silentVersion = gPref.getCharPref(PREF_SAFETYNET_VERSION);
  1342.  
  1343.     var silentResource = gRDF.GetResource("urn:netscape:silent");
  1344.     var updatesArc = gRDF.GetResource(SILENT_NS("updates"));
  1345.     var updatesResource = aDataSource.GetTarget(silentResource, updatesArc, true);
  1346.  
  1347.     try {
  1348.       updatesResource = updatesResource.QueryInterface(Components.interfaces.nsIRDFResource);
  1349.     }
  1350.     catch (e) {
  1351.             //dump("++++ ACK! Bailed out from updatesResource QueryInterface call.\n\n");
  1352.       gOS.notifyObservers(null, "Update:Silent:Error", "");
  1353.       gOS.notifyObservers(null, "Update:Silent:Ended", "");
  1354.       return;
  1355.     }
  1356.  
  1357.     var cu = Components.classes["@mozilla.org/rdf/container-utils;1"]
  1358.                        .getService(Components.interfaces.nsIRDFContainerUtils);
  1359.     if (cu.IsContainer(aDataSource, updatesResource)) {
  1360.       var c = Components.classes["@mozilla.org/rdf/container;1"]
  1361.                         .getService(Components.interfaces.nsIRDFContainer);
  1362.       c.Init(aDataSource, updatesResource);
  1363.  
  1364.       var versionChecker = Components.classes["@mozilla.org/updates/version-checker;1"]
  1365.                                      .getService(Components.interfaces.nsIVersionChecker);
  1366.  
  1367.       var newestVersionObj = { version: silentVersion, resource: null };
  1368.       var biggestMinorObj =  { version: silentVersion, resource: null };
  1369.       var updates = c.GetElements();
  1370.       while (updates.hasMoreElements()) {
  1371.         var update = updates.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  1372.         var version = this._getPropertyFromResource(aDataSource, update, "version");
  1373.         if (!version)
  1374.           continue;
  1375.           
  1376.         if (versionChecker.compare(silentVersion, version) == 0)
  1377.           this._parseVersionData(aDataSource, update, this._service._currentVersion);
  1378.         else if (versionChecker.compare(newestVersionObj.version, version) < 0) {
  1379.           newestVersionObj.version = version;
  1380.           newestVersionObj.resource = update;
  1381.         }
  1382.         if (versionChecker.biggestMinor(silentVersion, version)) {
  1383.             biggestMinorObj.version = version;
  1384.             biggestMinorObj.resource = update;
  1385.         }                
  1386.       }
  1387.       var files;      
  1388.       if (biggestMinorObj.resource) {
  1389. //              dump("SILENT UPDATE: Got a patch, gonna install it...\n");
  1390.           this._parseVersionData(aDataSource, biggestMinorObj.resource, this._service._newestVersion);        
  1391.                 // files = this._service._newestVersion.patches;
  1392.                 // Because we're only patching, we're not guaranteed to be the newest
  1393.                 // So update again right away
  1394.                 if (biggestMinorObj.version != newestVersionObj.version)
  1395.                 {
  1396.                     gPref.setIntPref(PREF_SILENT_UPDATE_LASTUPDATEDATE, 0); // JMC : doublecheck this?
  1397.                 }
  1398.                 files = this._service._newestVersion.getCollection("patches", { });
  1399.                 if (files)
  1400.           {
  1401.               this.items = [];
  1402.                     for (i = 0; i < files.length; ++i) {
  1403.                         this.items.push(files[i].URL);
  1404.     //                  dump("SILENT UPDATE: Pushing " + files[i].URL + " into the URL list...\n");
  1405.                     }
  1406.               }
  1407.       } else if (newestVersionObj.resource) {
  1408. //              dump("SILENT UPDATE: Got a new version, gonna install it...\n");
  1409.         this._parseVersionData(aDataSource, newestVersionObj.resource, this._service._newestVersion);
  1410.        // this._service._newestVersion.files;
  1411. //       dump("Dumping properties of _newestVersion\n");
  1412. //       this._dumpProps(this._service._newestVersion);
  1413.              files = this._service._newestVersion.getCollection("files", { });
  1414.  
  1415.           if (files)
  1416.           {
  1417.               this.items = [];
  1418.                     for (i = 0; i < files.length; ++i) {
  1419.                         this.items.push(files[i].URL);
  1420.     //                  dump("SILENT UPDATE: Pushing " + files[i].URL + " into the URL list...\n");
  1421.                     }            
  1422.               }
  1423.         }
  1424.     
  1425.         if (this.items)
  1426.         {
  1427.                     var xpimgr = Components.classes["@mozilla.org/xpinstall/install-manager;1"]
  1428.                                 .createInstance(Components.interfaces.nsIXPInstallManager);
  1429.                     xpimgr.initManagerFromChrome(this.items, this.items.length, this);    
  1430.             }
  1431.         }
  1432.     // The Update Wizard uses this notification to determine that the application
  1433.     // update process is now complete.
  1434.     gOS.notifyObservers(null, "Update:Silent:Ended", "");
  1435.   },
  1436.  
  1437.   _parseVersionData: function nsSilentUpdater__parseVersionData (aDataSource,
  1438.                                                               aUpdateResource,
  1439.                                                               aTargetObj)
  1440.   {
  1441. //      dump ("SILENT UPDATE: in the parseVersionData function, with the " + aTargetObj + " target object\n");
  1442.     aTargetObj.updateVersion          = this._getPropertyFromResource(aDataSource, aUpdateResource, "version");
  1443.     aTargetObj.files      = this._parseUpdateCollection(aDataSource, aUpdateResource, "files");
  1444.     aTargetObj.patches      = this._parseUpdateCollection(aDataSource, aUpdateResource, "patches");
  1445.   },
  1446.  
  1447.   _parseUpdateCollection: function nsSilentUpdater__parseUpdateCollection (aDataSource,
  1448.                                                                         aUpdateResource,
  1449.                                                                         aCollectionName)
  1450.   {
  1451. //      dump("SILENT UPDATE: in parseUpdateCollection with a resource of \n");
  1452.     if (!aUpdateResource)
  1453.       return null;
  1454.  
  1455.     var result = [];
  1456.  
  1457.     var collectionArc = gRDF.GetResource(SILENT_NS(aCollectionName));
  1458.     var collectionResource = aDataSource.GetTarget(aUpdateResource, collectionArc, true);
  1459.  
  1460.     try {
  1461.       collectionResource = collectionResource.QueryInterface(Components.interfaces.nsIRDFResource);
  1462.     }
  1463.     catch (e) { return null; }
  1464.  
  1465.     var cu = Components.classes["@mozilla.org/rdf/container-utils;1"]
  1466.                        .getService(Components.interfaces.nsIRDFContainerUtils);
  1467.     if (cu.IsContainer(aDataSource, collectionResource)) {
  1468.       var c = Components.classes["@mozilla.org/rdf/container;1"]
  1469.                         .getService(Components.interfaces.nsIRDFContainer);
  1470.       c.Init(aDataSource, collectionResource);
  1471.  
  1472.       var elements = c.GetElements();
  1473.       var fileArc = gRDF.GetResource(SILENT_NS("file"));
  1474.       var platform = getOSKey();
  1475.       while (elements.hasMoreElements()) {
  1476.         var element = elements.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  1477.         var info = new nsSilentUpdateInfoItem();
  1478.         info.name          = this._getPropertyFromResource(aDataSource, element, "name");
  1479.         info.internalName  = this._getPropertyFromResource(aDataSource, element, "internalName");
  1480.  
  1481.         // Each Component has a set of app:file arcs out, which reference resources with two
  1482.         // properties: app:platform and app:URL. If we find a resource whose app:platform value
  1483.         // matches the platform we're running on, we use the app:URL property on that resource
  1484.         // as the XPI URL, otherwise we use the default app:URL property on the Component
  1485.         // resource. (It must be a cross-platform piece, e.g. a language pack)
  1486.         // XXXben - what to do when platform not supported? We need some way to abort
  1487.         //          and tell the app that this update is not available.
  1488.         var files = aDataSource.GetTargets(element, fileArc, true);
  1489.         while (files.hasMoreElements()) {
  1490.           var file = files.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  1491.           if (platform == this._getPropertyFromResource(aDataSource, file, "platform")) {
  1492.             info.URL = this._getPropertyFromResource(aDataSource, file, "URL");
  1493.             break;
  1494.           }
  1495.         }
  1496.         if (!info.URL)
  1497.           info.URL         = this._getPropertyFromResource(aDataSource, element, "URL");
  1498.         info.infoURL       = this._getPropertyFromResource(aDataSource, element, "infoURL");
  1499.         info.description   = this._getPropertyFromResource(aDataSource, element, "description");
  1500.         result.push(info);
  1501.       }
  1502.     }
  1503.  
  1504.     return result;
  1505.   },
  1506.  
  1507.   onDatasourceError: function (aStatus, aErrorMsg)
  1508.   {
  1509.     gOS.notifyObservers(null, "Update:Silent:Error", "");
  1510.     gOS.notifyObservers(null, "Update:Silent:Ended", "");
  1511.   },
  1512.  
  1513.   /////////////////////////////////////////////////////////////////////////////
  1514.   // nsIRDFXMLSinkObserver
  1515.   onBeginLoad: function(aSink) {  },
  1516.   onInterrupt: function(aSink)  {  },
  1517.   onResume: function(aSink)  {  },
  1518.   onEndLoad: function(aSink)
  1519.   {
  1520.     try {
  1521.       this._ds = aSink.QueryInterface(Components.interfaces.nsIRDFDataSource);
  1522.       this.onDatasourceLoaded(this._ds);
  1523.     }
  1524.     catch (e) { }
  1525.   },
  1526.  
  1527.   onError: function(aSink, aStatus, aErrorMsg)
  1528.   {
  1529.     try {
  1530.       this._ds = aSink.QueryInterface(Components.interfaces.nsIRDFDataSource);
  1531.       this.onDatasourceError(aStatus, aErrorMsg);
  1532.     }
  1533.     catch (e) { }
  1534.   },
  1535.   
  1536.    onStateChange: function (aIndex, aState, aValue)
  1537.       {
  1538.     //      dump("SILENT UPDATE: onStateChange observer of the XPInstall process\n");
  1539.         const nsIXPIProgressDialog = Components.interfaces.nsIXPIProgressDialog;
  1540.         switch (aState) {
  1541.         case nsIXPIProgressDialog.DOWNLOAD_START:
  1542.           break;
  1543.         case nsIXPIProgressDialog.DOWNLOAD_DONE:
  1544.         case nsIXPIProgressDialog.INSTALL_START:
  1545.           break;
  1546.         case nsIXPIProgressDialog.INSTALL_DONE:
  1547.             // Set pref to installed version number
  1548.     //          dump("SILENT UPDATE: setting version pref to " + this._service._newestVersion.updateVersion  + "\n");
  1549.            gPref.setCharPref(PREF_SAFETYNET_VERSION, this._service._newestVersion.updateVersion);
  1550.                 gSiteControls.pollForNewTrustData();            
  1551.             break;
  1552.       }
  1553.       
  1554.     },
  1555.     
  1556.       _objs: [],
  1557.       _errors: false,
  1558.  
  1559.       onProgress: function (aIndex, aValue, aMaxValue)
  1560.       {
  1561.       },
  1562.  
  1563.   /////////////////////////////////////////////////////////////////////////////
  1564.   // nsISupports
  1565.   QueryInterface: function nsSilentUpdater_QueryInterface (aIID)
  1566.   {
  1567.     if (!aIID.equals(Components.interfaces.nsIObserver) &&
  1568.             !aIID.equals(Components.interfaces.nsIRDFXMLSinkObserver) &&
  1569.         !aIID.equals(Components.interfaces.nsISupports))
  1570.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1571.     return this;
  1572.   }
  1573. }
  1574.  
  1575. // End Silent Updater
  1576.  
  1577. function UpdateItem ()
  1578. {
  1579. }
  1580.  
  1581. UpdateItem.prototype = {
  1582.   init: function UpdateItem_init (aID,
  1583.                                   aVersion,
  1584.                                   aMinAppVersion,
  1585.                                   aMaxAppVersion,
  1586.                                   aName,
  1587.                                   aRow,
  1588.                                   aXPIURL,
  1589.                                   aIconURL,
  1590.                                   aUpdateRDF,
  1591.                                   aType)
  1592.   {
  1593.     this._id            = aID;
  1594.     this._version       = aVersion;
  1595.     this._minAppVersion = aMinAppVersion;
  1596.     this._maxAppVersion = aMaxAppVersion;
  1597.     this._name          = aName;
  1598.     this._row           = aRow;
  1599.     this._xpiURL        = aXPIURL;
  1600.     this._iconURL       = aIconURL;
  1601.     this._updateRDF     = aUpdateRDF;
  1602.     this._type          = aType;
  1603.   },
  1604.  
  1605.   get id()            { return this._id;            },
  1606.   get version()       { return this._version;       },
  1607.   get minAppVersion() { return this._minAppVersion; },
  1608.   get maxAppVersion() { return this._maxAppVersion; },
  1609.   get name()          { return this._name;          },
  1610.   get row()           { return this._row;           },
  1611.   get xpiURL()        { return this._xpiURL;        },
  1612.   get iconURL()       { return this._iconURL        },
  1613.   get updateRDF()     { return this._updateRDF;     },
  1614.   get type()          { return this._type;          },
  1615.  
  1616.   get objectSource()
  1617.   {
  1618.     return { id             : this._id,
  1619.              version        : this._version,
  1620.              minAppVersion  : this._minAppVersion,
  1621.              maxAppVersion  : this._maxAppVersion,
  1622.              name           : this._name,
  1623.              row            : this._row,
  1624.              xpiURL         : this._xpiURL,
  1625.              iconURL        : this._iconURL,
  1626.              updateRDF      : this._updateRDF,
  1627.              type           : this._type
  1628.            }.toSource();
  1629.   },
  1630.  
  1631.   /////////////////////////////////////////////////////////////////////////////
  1632.   // nsISupports
  1633.   QueryInterface: function UpdateItem_QueryInterface (aIID)
  1634.   {
  1635.     if (!aIID.equals(Components.interfaces.nsIUpdateItem) &&
  1636.         !aIID.equals(Components.interfaces.nsISupports))
  1637.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1638.     return this;
  1639.   }
  1640. };
  1641.  
  1642. function nsAppUpdateInfoItem ()
  1643. {
  1644. }
  1645. nsAppUpdateInfoItem.prototype = {
  1646.   internalName: "",
  1647.   name        : "",
  1648.   URL         : "",
  1649.   infoURL     : "",
  1650.  
  1651.   /////////////////////////////////////////////////////////////////////////////
  1652.   // nsISupports
  1653.   QueryInterface: function nsAppUpdater_QueryInterface (aIID)
  1654.   {
  1655.     if (!aIID.equals(Components.interfaces.nsIAppUpdateInfo) &&
  1656.         !aIID.equals(Components.interfaces.nsISupports))
  1657.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1658.     return this;
  1659.   }
  1660. };
  1661.  
  1662. function nsSilentUpdateInfoItem ()
  1663. {
  1664. }
  1665. nsSilentUpdateInfoItem.prototype = {
  1666.   internalName: "",
  1667.   name        : "",
  1668.   URL         : "",
  1669.   infoURL     : "",
  1670.  
  1671.   /////////////////////////////////////////////////////////////////////////////
  1672.   // nsISupports
  1673.   QueryInterface: function nsSilentUpdater_QueryInterface (aIID)
  1674.   {
  1675.     if (!aIID.equals(Components.interfaces.nsISilentUpdateInfo) &&
  1676.         !aIID.equals(Components.interfaces.nsISupports))
  1677.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1678.     return this;
  1679.   }
  1680. };
  1681.  
  1682. function nsAppUpdateInfo ()
  1683. {
  1684. }
  1685. nsAppUpdateInfo.prototype = {
  1686.   updateVersion       : "",
  1687.   updateDisplayVersion: "",
  1688.   updateInfoURL       : "",
  1689.  
  1690.   features  : [],
  1691.   files     : [],
  1692.   optional  : [],
  1693.   languages : [],
  1694.   patches   : [],
  1695.  
  1696.   getCollection: function (aCollectionName, aItemCount)
  1697.   {
  1698.     var collection = aCollectionName in this ? this[aCollectionName] : null;
  1699.     aItemCount.value = collection ? collection.length : 0;
  1700.     return collection;
  1701.   },
  1702.  
  1703.   /////////////////////////////////////////////////////////////////////////////
  1704.   // nsISupports
  1705.   QueryInterface: function nsAppUpdater_QueryInterface (aIID)
  1706.   {
  1707.     if (!aIID.equals(Components.interfaces.nsIAppUpdateInfoCollection) &&
  1708.         !aIID.equals(Components.interfaces.nsISupports))
  1709.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1710.     return this;
  1711.   }
  1712. };
  1713.  
  1714.  
  1715. function nsSilentUpdateInfo ()
  1716. {
  1717. }
  1718. nsSilentUpdateInfo.prototype = {
  1719.   updateVersion       : "",
  1720.   updateDisplayVersion: "",
  1721.   updateInfoURL       : "",
  1722.  
  1723.   features  : [],
  1724.   files     : [],
  1725.   patches   : [],
  1726.  
  1727.   getCollection: function (aCollectionName, aItemCount)
  1728.   {
  1729.     var collection = aCollectionName in this ? this[aCollectionName] : null;
  1730.     aItemCount.value = collection ? collection.length : 0;
  1731.     return collection;
  1732.   },
  1733.  
  1734.   /////////////////////////////////////////////////////////////////////////////
  1735.   // nsISupports
  1736.   QueryInterface: function nsSilentUpdater_QueryInterface (aIID)
  1737.   {
  1738.     if (!aIID.equals(Components.interfaces.nsISilentUpdateInfoCollection) &&
  1739.         !aIID.equals(Components.interfaces.nsISupports))
  1740.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1741.     return this;
  1742.   }
  1743. };
  1744.  
  1745. function Version(aMajor, aMinor, aRelease, aBuild, aPlus)
  1746. {
  1747.   this.major    = aMajor    || 0;
  1748.   this.minor    = aMinor    || 0;
  1749.   this.release  = aRelease  || 0;
  1750.   this.build    = aBuild    || 0;
  1751.   this.plus     = aPlus     || 0;
  1752. }
  1753.  
  1754. Version.prototype = {
  1755.   toString: function Version_toString()
  1756.   {
  1757.     return this.major + "." + this.minor + "." + this.subminor + "." + this.release + (this.plus ? "+" : "");
  1758.   },
  1759.  
  1760.   compare: function (aVersion)
  1761.   {
  1762.     var fields = ["major", "minor", "release", "build", "plus"];
  1763.  
  1764.     for (var i = 0; i < fields.length; ++i) {
  1765.       var field = fields[i];
  1766.       if (aVersion[field] > this[field])
  1767.         return -1;
  1768.       else if (aVersion[field] < this[field])
  1769.         return 1;
  1770.     }
  1771.     return 0;
  1772.   }
  1773. }
  1774.  
  1775. function nsVersionChecker()
  1776. {
  1777. }
  1778.  
  1779. nsVersionChecker.prototype = {
  1780.   /////////////////////////////////////////////////////////////////////////////
  1781.   // nsIVersionChecker
  1782.  
  1783.   // -ve      if B is newer
  1784.   // equal    if A == B
  1785.   // +ve      if A is newer
  1786.   compare: function nsVersionChecker_compare (aVersionA, aVersionB)
  1787.   {
  1788.     var a = this._decomposeVersion(aVersionA);
  1789.     var b = this._decomposeVersion(aVersionB);
  1790.  
  1791.     return a.compare(b);
  1792.   },
  1793.  
  1794.     biggestMinor: function nsVersionChecker_biggestMinor (aVersionA, aVersionB)
  1795.     {
  1796.         var a = this._decomposeVersion(aVersionA);
  1797.     var b = this._decomposeVersion(aVersionB);
  1798.     
  1799.     if ((a.major == b.major) && (a.minor == b.minor))
  1800.       {
  1801.           // This handles the case when the browser is at a build earlier in the same day
  1802.           // as the patch
  1803.           // ie a=current safetynet version = 2005.8.23.11
  1804.           //    b=latest patch version      = 2005.8.23.12
  1805.           if ((a.release == b.release) && (a.build < b.build))
  1806.           {
  1807.               // Patch!!
  1808.               return true;
  1809.           }
  1810.           // This handles the case when the browser is at the previous days latest build
  1811.           // ie a=current safetynet version = 2005.8.23.23
  1812.           //    b=latest patch version      = 2005.8.24.12
  1813.           else if (a.build == 23) // last build of the day, look for tomorrow's latest
  1814.             {
  1815.                 if (a.release == (b.release - 1))
  1816.                 {
  1817.                     // Patch!!
  1818.                     return true;
  1819.                 }                
  1820.             }
  1821.         }
  1822.         // This isn't a version we need to patch with.
  1823.         return false;
  1824.     },
  1825.  
  1826.   _decomposeVersion: function nsVersionChecker__decomposeVersion (aVersion)
  1827.   {
  1828.       var plus = 0;
  1829.     if (aVersion.charAt(aVersion.length-1) == "+") {
  1830.       aVersion = aVersion.substr(0, aVersion.length-1);
  1831.       plus = 1;
  1832.     }
  1833.  
  1834.     var parts = aVersion.split(".");
  1835.  
  1836.         return new Version(this._getValidInt(parts[0]),
  1837.                        this._getValidInt(parts[1]),
  1838.                        this._getValidInt(parts[2]),
  1839.                        this._getValidInt(parts[3]),
  1840.                        plus);
  1841.   },
  1842.  
  1843.   _getValidInt: function nsVersionChecker__getValidInt (aPartString)
  1844.   {
  1845.     var integer = parseInt(aPartString);
  1846.     if (isNaN(integer))
  1847.       return 0;
  1848.     return integer;
  1849.   },
  1850.  
  1851.   isValidVersion: function nsVersionChecker_isValidVersion (aVersion)
  1852.   {
  1853.     var parts = aVersion.split(".");
  1854.     if (parts.length == 0)
  1855.       return false;
  1856.     for (var i = 0; i < parts.length; ++i) {
  1857.       var part = parts[i];
  1858.       if (i == parts.length - 1) {
  1859.         if (part.lastIndexOf("+") != -1)
  1860.           parts[i] = part.substr(0, part.length - 1);
  1861.       }
  1862.       var integer = parseInt(part);
  1863.       if (isNaN(integer))
  1864.         return false;
  1865.     }
  1866.     return true;
  1867.   },
  1868.  
  1869.   /////////////////////////////////////////////////////////////////////////////
  1870.   // nsISupports
  1871.   QueryInterface: function nsVersionChecker_QueryInterface (aIID)
  1872.   {
  1873.     if (!aIID.equals(Components.interfaces.nsIVersionChecker) &&
  1874.         !aIID.equals(Components.interfaces.nsISupports))
  1875.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1876.     return this;
  1877.   }
  1878. };
  1879.  
  1880. var gModule = {
  1881.   _firstTime: true,
  1882.  
  1883.   registerSelf: function (aComponentManager, aFileSpec, aLocation, aType)
  1884.   {
  1885.     if (this._firstTime) {
  1886.       this._firstTime = false;
  1887.       throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
  1888.     }
  1889.     aComponentManager = aComponentManager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  1890.  
  1891.     for (var key in this._objects) {
  1892.       var obj = this._objects[key];
  1893.       aComponentManager.registerFactoryLocation(obj.CID, obj.className, obj.contractID,
  1894.                                                 aFileSpec, aLocation, aType);
  1895.     }
  1896.   },
  1897.  
  1898.   getClassObject: function (aComponentManager, aCID, aIID)
  1899.   {
  1900.     if (!aIID.equals(Components.interfaces.nsIFactory))
  1901.       throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  1902.  
  1903.     for (var key in this._objects) {
  1904.       if (aCID.equals(this._objects[key].CID))
  1905.         return this._objects[key].factory;
  1906.     }
  1907.  
  1908.     throw Components.results.NS_ERROR_NO_INTERFACE;
  1909.   },
  1910.  
  1911.   _objects: {
  1912.     manager: { CID: Components.ID("{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}"),
  1913.                contractID: "@mozilla.org/updates/update-service;1",
  1914.                className: "Update Service",
  1915.                factory: {
  1916.                           createInstance: function (aOuter, aIID)
  1917.                           {
  1918.                             if (aOuter != null)
  1919.                               throw Components.results.NS_ERROR_NO_AGGREGATION;
  1920.  
  1921.                             return (new nsUpdateService()).QueryInterface(aIID);
  1922.                           }
  1923.                         }
  1924.              },
  1925.     version: { CID: Components.ID("{9408E0A5-509E-45E7-80C1-0F35B99FF7A9}"),
  1926.                contractID: "@mozilla.org/updates/version-checker;1",
  1927.                className: "Version Checker",
  1928.                factory: {
  1929.                           createInstance: function (aOuter, aIID)
  1930.                           {
  1931.                             if (aOuter != null)
  1932.                               throw Components.results.NS_ERROR_NO_AGGREGATION;
  1933.  
  1934.                             return (new nsVersionChecker()).QueryInterface(aIID);
  1935.                           }
  1936.                         }
  1937.              },
  1938.     item:    { CID: Components.ID("{F3294B1C-89F4-46F8-98A0-44E1EAE92518}"),
  1939.                contractID: "@mozilla.org/updates/item;1",
  1940.                className: "Extension Item",
  1941.                factory: {
  1942.                           createInstance: function (aOuter, aIID)
  1943.                           {
  1944.                             if (aOuter != null)
  1945.                               throw Components.results.NS_ERROR_NO_AGGREGATION;
  1946.  
  1947.                             return new UpdateItem().QueryInterface(aIID);
  1948.                           }
  1949.                         }
  1950.              }
  1951.    },
  1952.  
  1953.   canUnload: function (aComponentManager)
  1954.   {
  1955.     return true;
  1956.   }
  1957. };
  1958.  
  1959. function NSGetModule(compMgr, fileSpec)
  1960. {
  1961.   return gModule;
  1962. }
  1963.  
  1964.