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