home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 October / PCWorld_2005-10_cd.bin / komunikace / netscape / nsb-install-8-0.exe / components / nsUpdateService.js < prev    next >
Text File  |  2005-07-29  |  74KB  |  1,942 lines

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