home *** CD-ROM | disk | FTP | other *** search
/ Freelog 112 / FreelogNo112-NovembreDecembre2012.iso / Multimedia / Songbird / Songbird_2.0.0-2311_windows-i686-msvc8.exe / components / nsBrowserGlue.js < prev    next >
Text File  |  2012-06-08  |  50KB  |  1,189 lines

  1. /*
  2. //@line 44 "/e/builds/nightly/release/sb_win32bot03_release/build/dependencies/vendor/mozbrowser/components/nsBrowserGlue.js"
  3. */
  4.  
  5. const Ci = Components.interfaces;
  6. const Cc = Components.classes;
  7. const Cr = Components.results;
  8. const Cu = Components.utils;
  9.  
  10. const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  11.  
  12. Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  13. // XXX Songbird: distribution file moved from its old location
  14. // Cu.import("resource:///modules/distribution.js");
  15. Cu.import("resource://app/jsmodules/Distribution.jsm");
  16.  
  17. const PREF_EM_NEW_ADDONS_LIST = "extensions.newAddons";
  18. const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
  19. const PREF_PLUGINS_UPDATEURL  = "plugins.update.url";
  20.  
  21. // Check to see if bookmarks need backing up once per
  22. // day on 1 hour idle.
  23. const BOOKMARKS_ARCHIVE_IDLE_TIME = 60 * 60;
  24.  
  25. // Backup bookmarks once every 24 hours.
  26. const BOOKMARKS_ARCHIVE_INTERVAL = 86400 * 1000;
  27.  
  28. // Factory object
  29. const BrowserGlueServiceFactory = {
  30.   _instance: null,
  31.   createInstance: function (outer, iid) 
  32.   {
  33.     if (outer != null)
  34.       throw Components.results.NS_ERROR_NO_AGGREGATION;
  35.     return this._instance == null ?
  36.       this._instance = new BrowserGlue() : this._instance;
  37.   }
  38. };
  39.  
  40. // Constructor
  41.  
  42. function BrowserGlue() {
  43.  
  44.   this.__defineGetter__("_prefs", function() {
  45.     delete this._prefs;
  46.     return this._prefs = Cc["@mozilla.org/preferences-service;1"].
  47.                          getService(Ci.nsIPrefBranch);
  48.   });
  49.  
  50.   this.__defineGetter__("_bundleService", function() {
  51.     delete this._bundleService;
  52.     return this._bundleService = Cc["@mozilla.org/intl/stringbundle;1"].
  53.                                  getService(Ci.nsIStringBundleService);
  54.   });
  55.  
  56.   this.__defineGetter__("_idleService", function() {
  57.     delete this._idleService;
  58.     return this._idleService = Cc["@mozilla.org/widget/idleservice;1"].
  59.                            getService(Ci.nsIIdleService);
  60.   });
  61.  
  62.   this.__defineGetter__("_observerService", function() {
  63.     delete this._observerService;
  64.     return this._observerService = Cc['@mozilla.org/observer-service;1'].
  65.                                    getService(Ci.nsIObserverService);
  66.   });
  67.  
  68.   this.__defineGetter__("_distributionCustomizer", function() {
  69.     delete this._distributionCustomizer;
  70.     // XXX Songbird: allow not having a distribution customizer
  71.     return this._distributionCustomizer = ("function" == typeof(DistributionCustomizer) ? new DistributionCustomizer() : null);
  72.   });
  73.  
  74.   this._init();
  75. }
  76.  
  77. //@line 123 "/e/builds/nightly/release/sb_win32bot03_release/build/dependencies/vendor/mozbrowser/components/nsBrowserGlue.js"
  78.  
  79. BrowserGlue.prototype = {
  80.   
  81.   _saveSession: false,
  82.  
  83.   _setPrefToSaveSession: function()
  84.   {
  85.     this._prefs.setBoolPref("browser.sessionstore.resume_session_once", true);
  86.  
  87.     // This method can be called via [NSApplication terminate:] on Mac, which
  88.     // ends up causing prefs not to be flushed to disk, so we need to do that
  89.     // explicitly here. See bug 497652.
  90.     this._prefs.QueryInterface(Ci.nsIPrefService).savePrefFile(null);
  91.   },
  92.  
  93.   // nsIObserver implementation 
  94.   observe: function(subject, topic, data) 
  95.   {
  96.     switch(topic) {
  97.       case "xpcom-shutdown":
  98.         this._dispose();
  99.         break;
  100.       case "prefservice:after-app-defaults":
  101.         this._onAppDefaults();
  102.         break;
  103.       case "final-ui-startup":
  104.         this._onProfileStartup();
  105.         break;
  106.       case "sessionstore-windows-restored":
  107.         this._onBrowserStartup();
  108.         break;
  109.       case "browser:purge-session-history":
  110.         // reset the console service's error buffer
  111.         const cs = Cc["@mozilla.org/consoleservice;1"].
  112.                    getService(Ci.nsIConsoleService);
  113.         cs.logStringMessage(null); // clear the console (in case it's open)
  114.         cs.reset();
  115.         break;
  116.       case "quit-application-requested":
  117.         this._onQuitRequest(subject, data);
  118.         break;
  119.       case "quit-application-granted":
  120.         if (this._saveSession) {
  121.           this._setPrefToSaveSession();
  122.         }
  123.         // Everything that uses Places during shutdown should be here, since
  124.         // on quit-application Places database connection will be closed
  125.         // and history synchronization could fail.
  126.         this._onProfileShutdown();
  127.         break;
  128. //@line 174 "/e/builds/nightly/release/sb_win32bot03_release/build/dependencies/vendor/mozbrowser/components/nsBrowserGlue.js"
  129.       case "browser-lastwindow-close-requested":
  130.         // The application is not actually quitting, but the last full browser
  131.         // window is about to be closed.
  132.         this._onQuitRequest(subject, "lastwindow");
  133.         break;
  134.       case "browser-lastwindow-close-granted":
  135.         if (this._saveSession)
  136.           this._setPrefToSaveSession();
  137.         break;
  138. //@line 184 "/e/builds/nightly/release/sb_win32bot03_release/build/dependencies/vendor/mozbrowser/components/nsBrowserGlue.js"
  139.       case "session-save":
  140.         this._setPrefToSaveSession();
  141.         subject.QueryInterface(Ci.nsISupportsPRBool);
  142.         subject.data = true;
  143.         break;
  144.       case "places-init-complete":
  145.         this._initPlaces();
  146.         this._observerService.removeObserver(this, "places-init-complete");
  147.         // no longer needed, since history was initialized completely.
  148.         this._observerService.removeObserver(this, "places-database-locked");
  149.  
  150.         // Now apply distribution customized bookmarks.
  151.         // This should always run after Places initialization.
  152.         this._distributionCustomizer.applyBookmarks();
  153.         break;
  154.       case "places-database-locked":
  155.         this._isPlacesDatabaseLocked = true;
  156.         // stop observing, so further attempts to load history service
  157.         // do not show the prompt.
  158.         this._observerService.removeObserver(this, "places-database-locked");
  159.         break;
  160.       case "idle":
  161.         if (this._idleService.idleTime > BOOKMARKS_ARCHIVE_IDLE_TIME * 1000) {
  162.           // Back up bookmarks.
  163.           this._archiveBookmarks();
  164.         }
  165.         break;
  166.       case "distribution-customization-complete":
  167.         this._observerService
  168.             .removeObserver(this, "distribution-customization-complete");
  169.         // Customization has finished, we don't need the customizer anymore.
  170.         delete this._distributionCustomizer;
  171.         break;
  172.     }
  173.   }, 
  174.  
  175.   // initialization (called on application startup) 
  176.   _init: function() 
  177.   {
  178.     // observer registration
  179.     const osvr = this._observerService;
  180.     osvr.addObserver(this, "xpcom-shutdown", false);
  181.     osvr.addObserver(this, "prefservice:after-app-defaults", false);
  182.     osvr.addObserver(this, "final-ui-startup", false);
  183.     osvr.addObserver(this, "sessionstore-windows-restored", false);
  184.     osvr.addObserver(this, "browser:purge-session-history", false);
  185.     osvr.addObserver(this, "quit-application-requested", false);
  186.     osvr.addObserver(this, "quit-application-granted", false);
  187. //@line 233 "/e/builds/nightly/release/sb_win32bot03_release/build/dependencies/vendor/mozbrowser/components/nsBrowserGlue.js"
  188.     osvr.addObserver(this, "browser-lastwindow-close-requested", false);
  189.     osvr.addObserver(this, "browser-lastwindow-close-granted", false);
  190. //@line 236 "/e/builds/nightly/release/sb_win32bot03_release/build/dependencies/vendor/mozbrowser/components/nsBrowserGlue.js"
  191.     osvr.addObserver(this, "session-save", false);
  192.     osvr.addObserver(this, "places-init-complete", false);
  193.     osvr.addObserver(this, "places-database-locked", false);
  194.     osvr.addObserver(this, "distribution-customization-complete", false);
  195.   },
  196.  
  197.   // cleanup (called on application shutdown)
  198.   _dispose: function() 
  199.   {
  200.     // observer removal 
  201.     const osvr = this._observerService;
  202.     osvr.removeObserver(this, "xpcom-shutdown");
  203.     osvr.removeObserver(this, "prefservice:after-app-defaults");
  204.     osvr.removeObserver(this, "final-ui-startup");
  205.     osvr.removeObserver(this, "sessionstore-windows-restored");
  206.     osvr.removeObserver(this, "browser:purge-session-history");
  207.     osvr.removeObserver(this, "quit-application-requested");
  208. //@line 254 "/e/builds/nightly/release/sb_win32bot03_release/build/dependencies/vendor/mozbrowser/components/nsBrowserGlue.js"
  209.     osvr.removeObserver(this, "browser-lastwindow-close-requested");
  210.     osvr.removeObserver(this, "browser-lastwindow-close-granted");
  211. //@line 257 "/e/builds/nightly/release/sb_win32bot03_release/build/dependencies/vendor/mozbrowser/components/nsBrowserGlue.js"
  212.     osvr.removeObserver(this, "quit-application-granted");
  213.     osvr.removeObserver(this, "session-save");
  214.   },
  215.  
  216.   _onAppDefaults: function()
  217.   {
  218.     // apply distribution customizations (prefs)
  219.     // other customizations are applied in _onProfileStartup()
  220.     // XXX Songbird: allow not having a distribution customizer
  221.     if (this._distributionCustomizer)
  222.       this._distributionCustomizer.applyPrefDefaults();
  223.   },
  224.  
  225.   // profile startup handler (contains profile initialization routines)
  226.   _onProfileStartup: function() 
  227.   {
  228.     this.Sanitizer.onStartup();
  229.     // check if we're in safe mode
  230.     var app = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).
  231.               QueryInterface(Ci.nsIXULRuntime);
  232.     if (app.inSafeMode) {
  233.       var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
  234.                getService(Ci.nsIWindowWatcher);
  235.       ww.openWindow(null, "chrome://browser/content/safeMode.xul", 
  236.                     "_blank", "chrome,centerscreen,modal,resizable=no", null);
  237.     }
  238.  
  239.     // apply distribution customizations
  240.     // prefs are applied in _onAppDefaults()
  241.     // XXX Songbird: allow not having a distribution customizer
  242.     if (this._distributionCustomizer)
  243.       this._distributionCustomizer.applyCustomizations();
  244.  
  245.     // handle any UI migration
  246.     this._migrateUI();
  247.  
  248.     this._observerService.notifyObservers(null, "browser-ui-startup-complete", "");
  249.   },
  250.  
  251.   // profile shutdown handler (contains profile cleanup routines)
  252.   _onProfileShutdown: function() 
  253.   {
  254. //@line 311 "/e/builds/nightly/release/sb_win32bot03_release/build/dependencies/vendor/mozbrowser/components/nsBrowserGlue.js"
  255.     this._shutdownPlaces();
  256.     this._idleService.removeIdleObserver(this, BOOKMARKS_ARCHIVE_IDLE_TIME);
  257.     this.Sanitizer.onShutdown();
  258.   },
  259.  
  260.   // Browser startup complete. All initial windows have opened.
  261.   _onBrowserStartup: function()
  262.   {
  263.     // Show about:rights notification, if needed.
  264.     if (this._shouldShowRights())
  265.       this._showRightsNotification();
  266.  
  267.     // If new add-ons were installed during startup open the add-ons manager.
  268.     if (this._prefs.prefHasUserValue(PREF_EM_NEW_ADDONS_LIST)) {
  269.       var args = Cc["@mozilla.org/supports-array;1"].
  270.                  createInstance(Ci.nsISupportsArray);
  271.       var str = Cc["@mozilla.org/supports-string;1"].
  272.                 createInstance(Ci.nsISupportsString);
  273.       str.data = "";
  274.       args.AppendElement(str);
  275.       var str = Cc["@mozilla.org/supports-string;1"].
  276.                 createInstance(Ci.nsISupportsString);
  277.       str.data = this._prefs.getCharPref(PREF_EM_NEW_ADDONS_LIST);
  278.       args.AppendElement(str);
  279.       const EMURL = "chrome://mozapps/content/extensions/extensions.xul";
  280.       const EMFEATURES = "chrome,menubar,extra-chrome,toolbar,dialog=no,resizable";
  281.       var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
  282.                getService(Ci.nsIWindowWatcher);
  283.       ww.openWindow(null, EMURL, "_blank", EMFEATURES, args);
  284.       this._prefs.clearUserPref(PREF_EM_NEW_ADDONS_LIST);
  285.     }
  286.  
  287.     // Load the "more info" page for a locked places.sqlite
  288.     // This property is set earlier in the startup process:
  289.     // nsPlacesDBFlush loads after profile-after-change and initializes
  290.     // the history service, which sends out places-database-locked
  291.     // which sets this property.
  292.     if (this._isPlacesDatabaseLocked) {
  293.       this._showPlacesLockedNotificationBox();
  294.     }
  295.  
  296.     // If there are plugins installed that are outdated, and the user hasn't
  297.     // been warned about them yet, open the plugins update page.
  298.     if (this._prefs.getBoolPref(PREF_PLUGINS_NOTIFYUSER))
  299.       this._showPluginUpdatePage();
  300.   },
  301.  
  302.   _onQuitRequest: function(aCancelQuit, aQuitType)
  303.   {
  304.     // If user has already dismissed quit request, then do nothing
  305.     if ((aCancelQuit instanceof Ci.nsISupportsPRBool) && aCancelQuit.data)
  306.       return;
  307.  
  308.     var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
  309.              getService(Ci.nsIWindowMediator);
  310.  
  311.     var windowcount = 0;
  312.     var pagecount = 0;
  313.     var browserEnum = wm.getEnumerator("navigator:browser");
  314.     while (browserEnum.hasMoreElements()) {
  315.       windowcount++;
  316.  
  317.       var browser = browserEnum.getNext();
  318.       var tabbrowser = browser.document.getElementById("content");
  319.       if (tabbrowser)
  320.         pagecount += tabbrowser.browsers.length;
  321.     }
  322.  
  323.     this._saveSession = false;
  324.     if (pagecount < 2)
  325.       return;
  326.  
  327.     if (aQuitType != "restart")
  328.       aQuitType = "quit";
  329.  
  330.     var showPrompt = true;
  331.     try {
  332.       // browser.warnOnQuit is a hidden global boolean to override all quit prompts
  333.       // browser.warnOnRestart specifically covers app-initiated restarts where we restart the app
  334.       // browser.tabs.warnOnClose is the global "warn when closing multiple tabs" pref
  335.  
  336.       var sessionWillBeSaved = this._prefs.getIntPref("browser.startup.page") == 3 ||
  337.                                this._prefs.getBoolPref("browser.sessionstore.resume_session_once");
  338.       if (sessionWillBeSaved || !this._prefs.getBoolPref("browser.warnOnQuit"))
  339.         showPrompt = false;
  340.       else if (aQuitType == "restart")
  341.         showPrompt = this._prefs.getBoolPref("browser.warnOnRestart");
  342.       else
  343.         showPrompt = this._prefs.getBoolPref("browser.tabs.warnOnClose");
  344.     } catch (ex) {}
  345.  
  346.     // Never show a prompt inside the private browsing mode
  347.     // XXX Songbird: allow not having private browsing support
  348.     var inPrivateBrowsing = false;
  349.     if ("@mozilla.org/privatebrowsing;1" in Cc) {
  350.       inPrivateBrowsing = Cc["@mozilla.org/privatebrowsing;1"].
  351.                           getService(Ci.nsIPrivateBrowsingService).
  352.                           privateBrowsingEnabled;
  353.     }
  354.     if (!showPrompt || inPrivateBrowsing)
  355.       return false;
  356.  
  357.     var quitBundle = this._bundleService.createBundle("chrome://browser/locale/quitDialog.properties");
  358.     var brandBundle = this._bundleService.createBundle("chrome://branding/locale/brand.properties");
  359.  
  360.     var appName = brandBundle.GetStringFromName("brandShortName");
  361.     var quitDialogTitle = quitBundle.formatStringFromName(aQuitType + "DialogTitle",
  362.                                                           [appName], 1);
  363.  
  364.     var message;
  365.     if (aQuitType == "restart")
  366.       message = quitBundle.formatStringFromName("messageRestart",
  367.                                                 [appName], 1);
  368.     else if (windowcount == 1)
  369.       message = quitBundle.formatStringFromName("messageNoWindows",
  370.                                                 [appName], 1);
  371.     else
  372.       message = quitBundle.formatStringFromName("message",
  373.                                                 [appName], 1);
  374.  
  375.     var promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"].
  376.                         getService(Ci.nsIPromptService);
  377.  
  378.     var flags = promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0 +
  379.                 promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_1 +
  380.                 promptService.BUTTON_POS_0_DEFAULT;
  381.  
  382.     var neverAsk = {value:false};
  383.     var button0Title, button2Title;
  384.     var button1Title = quitBundle.GetStringFromName("cancelTitle");
  385.     var neverAskText = quitBundle.GetStringFromName("neverAsk");
  386.  
  387.     if (aQuitType == "restart")
  388.       button0Title = quitBundle.GetStringFromName("restartTitle");
  389.     else {
  390.       flags += promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_2;
  391.       button0Title = quitBundle.GetStringFromName("saveTitle");
  392.       button2Title = quitBundle.GetStringFromName("quitTitle");
  393.     }
  394.  
  395.     var mostRecentBrowserWindow = wm.getMostRecentWindow("navigator:browser");
  396.     var buttonChoice =
  397.       promptService.confirmEx(mostRecentBrowserWindow, quitDialogTitle, message,
  398.                               flags, button0Title, button1Title, button2Title,
  399.                               neverAskText, neverAsk);
  400.  
  401.     switch (buttonChoice) {
  402.     case 2: // Quit
  403.       if (neverAsk.value)
  404.         this._prefs.setBoolPref("browser.tabs.warnOnClose", false);
  405.       break;
  406.     case 1: // Cancel
  407.       aCancelQuit.QueryInterface(Ci.nsISupportsPRBool);
  408.       aCancelQuit.data = true;
  409.       break;
  410.     case 0: // Save & Quit
  411.       this._saveSession = true;
  412.       if (neverAsk.value) {
  413.         if (aQuitType == "restart")
  414.           this._prefs.setBoolPref("browser.warnOnRestart", false);
  415.         else {
  416.           // always save state when shutting down
  417.           this._prefs.setIntPref("browser.startup.page", 3);
  418.         }
  419.       }
  420.       break;
  421.     }
  422.   },
  423.  
  424.   /*
  425.    * _shouldShowRights - Determines if the user should be shown the
  426.    * about:rights notification. The notification should *not* be shown if
  427.    * we've already shown the current version, or if the override pref says to
  428.    * never show it. The notification *should* be shown if it's never been seen
  429.    * before, if a newer version is available, or if the override pref says to
  430.    * always show it.
  431.    */
  432.   _shouldShowRights : function () {
  433.     // Look for an unconditional override pref. If set, do what it says.
  434.     // (true --> never show, false --> always show)
  435.     try {
  436.       return !this._prefs.getBoolPref("browser.rights.override");
  437.     } catch (e) { }
  438.     // Ditto, for the legacy EULA pref.
  439.     try {
  440.       return !this._prefs.getBoolPref("browser.EULA.override");
  441.     } catch (e) { }
  442.  
  443. //@line 500 "/e/builds/nightly/release/sb_win32bot03_release/build/dependencies/vendor/mozbrowser/components/nsBrowserGlue.js"
  444.     // Non-official builds shouldn't shouldn't show the notification.
  445.     return false;
  446. //@line 503 "/e/builds/nightly/release/sb_win32bot03_release/build/dependencies/vendor/mozbrowser/components/nsBrowserGlue.js"
  447.  
  448.     // Look to see if the user has seen the current version or not.
  449.     var currentVersion = this._prefs.getIntPref("browser.rights.version");
  450.     try {
  451.       return !this._prefs.getBoolPref("browser.rights." + currentVersion + ".shown");
  452.     } catch (e) { }
  453.  
  454.     // Legacy: If the user accepted a EULA, we won't annoy them with the
  455.     // equivalent about:rights page until the version changes.
  456.     try {
  457.       return !this._prefs.getBoolPref("browser.EULA." + currentVersion + ".accepted");
  458.     } catch (e) { }
  459.  
  460.     // We haven't shown the notification before, so do so now.
  461.     return true;
  462.   },
  463.  
  464.   _showRightsNotification : function () {
  465.     // Stick the notification onto the selected tab of the active browser window.
  466.     var win = this.getMostRecentBrowserWindow();
  467.     var browser = win.gBrowser; // for closure in notification bar callback
  468.     var notifyBox = browser.getNotificationBox();
  469.  
  470.     var brandBundle  = this._bundleService.createBundle("chrome://branding/locale/brand.properties");
  471.     var rightsBundle = this._bundleService.createBundle("chrome://global/locale/aboutRights.properties");
  472.  
  473.     var buttonLabel      = rightsBundle.GetStringFromName("buttonLabel");
  474.     var buttonAccessKey  = rightsBundle.GetStringFromName("buttonAccessKey");
  475.     var productName      = brandBundle.GetStringFromName("brandFullName");
  476.     var notifyRightsText = rightsBundle.formatStringFromName("notifyRightsText", [productName], 1);
  477.     
  478.     var buttons = [
  479.                     {
  480.                       label:     buttonLabel,
  481.                       accessKey: buttonAccessKey,
  482.                       popup:     null,
  483.                       callback: function(aNotificationBar, aButton) {
  484.                         browser.selectedTab = browser.addTab("about:rights");
  485.                       }
  486.                     }
  487.                   ];
  488.  
  489.     // Set pref to indicate we've shown the notification.
  490.     var currentVersion = this._prefs.getIntPref("browser.rights.version");
  491.     this._prefs.setBoolPref("browser.rights." + currentVersion + ".shown", true);
  492.  
  493.     var box = notifyBox.appendNotification(notifyRightsText, "about-rights", null, notifyBox.PRIORITY_INFO_LOW, buttons);
  494.     box.persistence = 3; // arbitrary number, just so bar sticks around for a bit
  495.   },
  496.   
  497.   _showPluginUpdatePage : function () {
  498.     this._prefs.setBoolPref(PREF_PLUGINS_NOTIFYUSER, false);
  499.  
  500.     var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].
  501.                     getService(Ci.nsIURLFormatter);
  502.     var updateUrl = formatter.formatURLPref(PREF_PLUGINS_UPDATEURL);
  503.  
  504.     var win = this.getMostRecentBrowserWindow();
  505.     var browser = win.gBrowser;
  506.     browser.selectedTab = browser.addTab(updateUrl);
  507.   },
  508.  
  509.   // returns the (cached) Sanitizer constructor
  510.   get Sanitizer() 
  511.   {
  512.     if(typeof(Sanitizer) != "function") { // we should dynamically load the script
  513.       Cc["@mozilla.org/moz/jssubscript-loader;1"].
  514.       getService(Ci.mozIJSSubScriptLoader).
  515.       loadSubScript("chrome://browser/content/sanitize.js", null);
  516.     }
  517.     return Sanitizer;
  518.   },
  519.  
  520.   /**
  521.    * Initialize Places
  522.    * - imports the bookmarks html file if bookmarks database is empty, try to
  523.    *   restore bookmarks from a JSON backup if the backend indicates that the
  524.    *   database was corrupt.
  525.    *
  526.    * These prefs can be set up by the frontend:
  527.    *
  528.    * WARNING: setting these preferences to true will overwite existing bookmarks
  529.    *
  530.    * - browser.places.importBookmarksHTML
  531.    *   Set to true will import the bookmarks.html file from the profile folder.
  532.    * - browser.places.smartBookmarksVersion
  533.    *   Set during HTML import to indicate that Smart Bookmarks were created.
  534.    *   Set to -1 to disable Smart Bookmarks creation.
  535.    *   Set to 0 to restore current Smart Bookmarks.
  536.    * - browser.bookmarks.restore_default_bookmarks
  537.    *   Set to true by safe-mode dialog to indicate we must restore default
  538.    *   bookmarks.
  539.    */
  540.   _initPlaces: function bg__initPlaces() {
  541.     // XXX Songbird: Songbird does not use Places
  542.     return;
  543.  
  544.     // We must instantiate the history service since it will tell us if we
  545.     // need to import or restore bookmarks due to first-run, corruption or
  546.     // forced migration (due to a major schema change).
  547.     var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
  548.                   getService(Ci.nsINavHistoryService);
  549.  
  550.     // If the database is corrupt or has been newly created we should
  551.     // import bookmarks.
  552.     var databaseStatus = histsvc.databaseStatus;
  553.     var importBookmarks = databaseStatus == histsvc.DATABASE_STATUS_CREATE ||
  554.                           databaseStatus == histsvc.DATABASE_STATUS_CORRUPT;
  555.  
  556.     if (databaseStatus == histsvc.DATABASE_STATUS_CREATE) {
  557.       // If the database has just been created, but we already have any
  558.       // bookmark, this is not the initial import.  This can happen after a
  559.       // migration from a different browser since migrators run before us.
  560.       // In such a case we should not import, unless some pref has been set.
  561.       var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
  562.                   getService(Ci.nsINavBookmarksService);
  563.       if (bmsvc.getIdForItemAt(bmsvc.bookmarksMenuFolder, 0) != -1 ||
  564.           bmsvc.getIdForItemAt(bmsvc.toolbarFolder, 0) != -1)
  565.         importBookmarks = false;
  566.     }
  567.  
  568.     // Check if user or an extension has required to import bookmarks.html
  569.     var importBookmarksHTML = false;
  570.     try {
  571.       importBookmarksHTML =
  572.         this._prefs.getBoolPref("browser.places.importBookmarksHTML");
  573.       if (importBookmarksHTML)
  574.         importBookmarks = true;
  575.     } catch(ex) {}
  576.  
  577.     // Check if Safe Mode or the user has required to restore bookmarks from
  578.     // default profile's bookmarks.html
  579.     var restoreDefaultBookmarks = false;
  580.     try {
  581.       restoreDefaultBookmarks =
  582.         this._prefs.getBoolPref("browser.bookmarks.restore_default_bookmarks");
  583.       if (restoreDefaultBookmarks) {
  584.         // Ensure that we already have a bookmarks backup for today
  585.         this._archiveBookmarks();
  586.         importBookmarks = true;
  587.       }
  588.     } catch(ex) {}
  589.  
  590.     // If the user did not require to restore default bookmarks, or import
  591.     // from bookmarks.html, we will try to restore from JSON
  592.     if (importBookmarks && !restoreDefaultBookmarks && !importBookmarksHTML) {
  593.       // get latest JSON backup
  594.       Cu.import("resource://gre/modules/utils.js");
  595.       var bookmarksBackupFile = PlacesUtils.getMostRecentBackup();
  596.       if (bookmarksBackupFile && bookmarksBackupFile.leafName.match("\.json$")) {
  597.         // restore from JSON backup
  598.         PlacesUtils.restoreBookmarksFromJSONFile(bookmarksBackupFile);
  599.         importBookmarks = false;
  600.       }
  601.       else {
  602.         // We have created a new database but we don't have any backup available
  603.         importBookmarks = true;
  604.         var dirService = Cc["@mozilla.org/file/directory_service;1"].
  605.                          getService(Ci.nsIProperties);
  606.         var bookmarksHTMLFile = dirService.get("BMarks", Ci.nsILocalFile);
  607.         if (bookmarksHTMLFile.exists()) {
  608.           // If bookmarks.html is available in current profile import it...
  609.           importBookmarksHTML = true;
  610.         }
  611.         else {
  612.           // ...otherwise we will restore defaults
  613.           restoreDefaultBookmarks = true;
  614.         }
  615.       }
  616.     }
  617.  
  618.     if (!importBookmarks) {
  619.       // Call it here for Fx3 profiles created before the Places folder
  620.       // has been added, otherwise it's called during import.
  621.       this.ensurePlacesDefaultQueriesInitialized();
  622.     }
  623.     else {
  624.       // ensurePlacesDefaultQueriesInitialized() is called by import.
  625.       // Don't try to recreate smart bookmarks if autoExportHTML is true or
  626.       // smart bookmarks are disabled.
  627.       var autoExportHTML = false;
  628.       try {
  629.         autoExportHTML = this._prefs.getBoolPref("browser.bookmarks.autoExportHTML");
  630.       } catch(ex) {}
  631.       var smartBookmarksVersion = 0;
  632.       try {
  633.         smartBookmarksVersion = this._prefs.getIntPref("browser.places.smartBookmarksVersion");
  634.       } catch(ex) {}
  635.       if (!autoExportHTML && smartBookmarksVersion != -1)
  636.         this._prefs.setIntPref("browser.places.smartBookmarksVersion", 0);
  637.  
  638.       // Get bookmarks.html file location
  639.       var dirService = Cc["@mozilla.org/file/directory_service;1"].
  640.                        getService(Ci.nsIProperties);
  641.  
  642.       var bookmarksFile = null;
  643.       if (restoreDefaultBookmarks) {
  644.         // User wants to restore bookmarks.html file from default profile folder
  645.         bookmarksFile = dirService.get("profDef", Ci.nsILocalFile);
  646.         bookmarksFile.append("bookmarks.html");
  647.       }
  648.       else
  649.         bookmarksFile = dirService.get("BMarks", Ci.nsILocalFile);
  650.  
  651.       if (bookmarksFile.exists()) {
  652.         // import the file
  653.         try {
  654.           var importer = Cc["@mozilla.org/browser/places/import-export-service;1"].
  655.                          getService(Ci.nsIPlacesImportExportService);
  656.           importer.importHTMLFromFile(bookmarksFile, true /* overwrite existing */);
  657.         } catch (err) {
  658.           // Report the error, but ignore it.
  659.           Cu.reportError("Bookmarks.html file could be corrupt. " + err);
  660.         }
  661.       }
  662.       else
  663.         Cu.reportError("Unable to find bookmarks.html file.");
  664.  
  665.       // Reset preferences, so we won't try to import again at next run
  666.       if (importBookmarksHTML)
  667.         this._prefs.setBoolPref("browser.places.importBookmarksHTML", false);
  668.       if (restoreDefaultBookmarks)
  669.         this._prefs.setBoolPref("browser.bookmarks.restore_default_bookmarks",
  670.                                 false);
  671.     }
  672.  
  673.     // Initialize bookmark archiving on idle.
  674.     // Once a day, either on idle or shutdown, bookmarks are backed up.
  675.     this._idleService.addIdleObserver(this, BOOKMARKS_ARCHIVE_IDLE_TIME);
  676.   },
  677.  
  678.   /**
  679.    * Places shut-down tasks
  680.    * - back up and archive bookmarks
  681.    * - export bookmarks as HTML, if so configured
  682.    *
  683.    * Note: quit-application-granted notification is received twice
  684.    *       so replace this method with a no-op when first called.
  685.    */
  686.   _shutdownPlaces: function bg__shutdownPlaces() {
  687.     // Backup and archive Places bookmarks.
  688.     this._archiveBookmarks();
  689.  
  690.     // Backup bookmarks to bookmarks.html to support apps that depend
  691.     // on the legacy format.
  692.     var autoExportHTML = false;
  693.     try {
  694.       autoExportHTML = this._prefs.getBoolPref("browser.bookmarks.autoExportHTML");
  695.     } catch(ex) {
  696.       Components.utils.reportError(ex);
  697.     }
  698.  
  699.     if (autoExportHTML) {
  700.       Cc["@mozilla.org/browser/places/import-export-service;1"].
  701.         getService(Ci.nsIPlacesImportExportService).
  702.         backupBookmarksFile();
  703.     }
  704.   },
  705.  
  706.   /**
  707.    * Back up and archive bookmarks
  708.    */
  709.   _archiveBookmarks: function nsBrowserGlue__archiveBookmarks() {
  710.     Cu.import("resource://gre/modules/utils.js");
  711.  
  712.     var lastBackup = PlacesUtils.getMostRecentBackup();
  713.  
  714.     // Backup bookmarks if there aren't any backups or 
  715.     // they haven't been backed up in the last 24 hrs.
  716.     if (!lastBackup ||
  717.         Date.now() - lastBackup.lastModifiedTime > BOOKMARKS_ARCHIVE_INTERVAL) {
  718.       var maxBackups = 5;
  719.       try {
  720.         maxBackups = this._prefs.getIntPref("browser.bookmarks.max_backups");
  721.       } catch(ex) {}
  722.  
  723.       PlacesUtils.archiveBookmarksFile(maxBackups, false /* don't force */);
  724.     }
  725.   },
  726.  
  727.   /**
  728.    * Show the notificationBox for a locked places database.
  729.    */
  730.   _showPlacesLockedNotificationBox: function nsBrowserGlue__showPlacesLockedNotificationBox() {
  731.     var brandBundle  = this._bundleService.createBundle("chrome://branding/locale/brand.properties");
  732.     var applicationName = brandBundle.GetStringFromName("brandShortName");
  733.     var placesBundle = this._bundleService.createBundle("chrome://browser/locale/places/places.properties");
  734.     var title = placesBundle.GetStringFromName("lockPrompt.title");
  735.     var text = placesBundle.formatStringFromName("lockPrompt.text", [applicationName], 1);
  736.     var buttonText = placesBundle.GetStringFromName("lockPromptInfoButton.label");
  737.     var accessKey = placesBundle.GetStringFromName("lockPromptInfoButton.accessKey");
  738.  
  739.     var helpTopic = "places-locked";
  740.     var url = Cc["@mozilla.org/toolkit/URLFormatterService;1"].
  741.               getService(Components.interfaces.nsIURLFormatter).
  742.               formatURLPref("app.support.baseURL");
  743.     url += helpTopic;
  744.  
  745.     var browser = this.getMostRecentBrowserWindow().gBrowser;
  746.  
  747.     var buttons = [
  748.                     {
  749.                       label:     buttonText,
  750.                       accessKey: accessKey,
  751.                       popup:     null,
  752.                       callback:  function(aNotificationBar, aButton) {
  753.                         browser.selectedTab = browser.addTab(url);
  754.                       }
  755.                     }
  756.                   ];
  757.  
  758.     var notifyBox = browser.getNotificationBox();
  759.     var box = notifyBox.appendNotification(text, title, null,
  760.                                            notifyBox.PRIORITY_CRITICAL_MEDIUM,
  761.                                            buttons);
  762.     box.persistence = -1; // Until user closes it
  763.   },
  764.  
  765.   _migrateUI: function bg__migrateUI() {
  766.     var migration = 0;
  767.     try {
  768.       migration = this._prefs.getIntPref("browser.migration.version");
  769.     } catch(ex) {}
  770.  
  771.     if (migration == 0) {
  772.       // this code should always migrate pre-FF3 profiles to the current UI state
  773.  
  774.       // grab the localstore.rdf and make changes needed for new UI
  775.       this._rdf = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
  776.       this._dataSource = this._rdf.GetDataSource("rdf:local-store");
  777.       this._dirty = false;
  778.  
  779.       let currentsetResource = this._rdf.GetResource("currentset");
  780.       let toolbars = ["nav-bar", "toolbar-menubar", "PersonalToolbar"];
  781.       for (let i = 0; i < toolbars.length; i++) {
  782.         let toolbar = this._rdf.GetResource("chrome://browser/content/browser.xul#" + toolbars[i]);
  783.         let currentset = this._getPersist(toolbar, currentsetResource);
  784.         if (!currentset) {
  785.           // toolbar isn't customized
  786.           if (i == 0)
  787.             // new button is in the defaultset, nothing to migrate
  788.             break;
  789.           continue;
  790.         }
  791.         if (/(?:^|,)unified-back-forward-button(?:$|,)/.test(currentset))
  792.           // new button is already there, nothing to migrate
  793.           break;
  794.         if (/(?:^|,)back-button(?:$|,)/.test(currentset)) {
  795.           let newset = currentset.replace(/(^|,)back-button($|,)/,
  796.                                           "$1unified-back-forward-button,back-button$2")
  797.           this._setPersist(toolbar, currentsetResource, newset);
  798.           // done migrating
  799.           break;
  800.         }
  801.       }
  802.  
  803.       // force the RDF to be saved
  804.       if (this._dirty)
  805.         this._dataSource.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush();
  806.  
  807.       // free up the RDF service
  808.       this._rdf = null;
  809.       this._dataSource = null;
  810.  
  811.       // update the migration version
  812.       this._prefs.setIntPref("browser.migration.version", 1);
  813.     }
  814.   },
  815.  
  816.   _getPersist: function bg__getPersist(aSource, aProperty) {
  817.     var target = this._dataSource.GetTarget(aSource, aProperty, true);
  818.     if (target instanceof Ci.nsIRDFLiteral)
  819.       return target.Value;
  820.     return null;
  821.   },
  822.  
  823.   _setPersist: function bg__setPersist(aSource, aProperty, aTarget) {
  824.     this._dirty = true;
  825.     try {
  826.       var oldTarget = this._dataSource.GetTarget(aSource, aProperty, true);
  827.       if (oldTarget) {
  828.         if (aTarget)
  829.           this._dataSource.Change(aSource, aProperty, oldTarget, this._rdf.GetLiteral(aTarget));
  830.         else
  831.           this._dataSource.Unassert(aSource, aProperty, oldTarget);
  832.       }
  833.       else {
  834.         this._dataSource.Assert(aSource, aProperty, this._rdf.GetLiteral(aTarget), true);
  835.       }
  836.     }
  837.     catch(ex) {}
  838.   },
  839.  
  840.   // ------------------------------
  841.   // public nsIBrowserGlue members
  842.   // ------------------------------
  843.   
  844.   sanitize: function(aParentWindow) 
  845.   {
  846.     this.Sanitizer.sanitize(aParentWindow);
  847.   },
  848.  
  849.   ensurePlacesDefaultQueriesInitialized: function() {
  850.     // This is actual version of the smart bookmarks, must be increased every
  851.     // time smart bookmarks change.
  852.     // When adding a new smart bookmark below, its newInVersion property must
  853.     // be set to the version it has been added in, we will compare its value
  854.     // to users' smartBookmarksVersion and add new smart bookmarks without
  855.     // recreating old deleted ones.
  856.     const SMART_BOOKMARKS_VERSION = 2;
  857.     const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark";
  858.     const SMART_BOOKMARKS_PREF = "browser.places.smartBookmarksVersion";
  859.  
  860.     // XXX should this be a pref?  see bug #399268
  861.     const MAX_RESULTS = 10;
  862.  
  863.     // get current smart bookmarks version
  864.     // By default, if the pref is not set up, we must create Smart Bookmarks
  865.     var smartBookmarksCurrentVersion = 0;
  866.     try {
  867.       smartBookmarksCurrentVersion = this._prefs.getIntPref(SMART_BOOKMARKS_PREF);
  868.     } catch(ex) { /* no version set, new profile */ }
  869.  
  870.     // bail out if we don't have to create or update Smart Bookmarks
  871.     if (smartBookmarksCurrentVersion == -1 ||
  872.         smartBookmarksCurrentVersion >= SMART_BOOKMARKS_VERSION)
  873.       return;
  874.  
  875.     var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
  876.                 getService(Ci.nsINavBookmarksService);
  877.     var annosvc = Cc["@mozilla.org/browser/annotation-service;1"].
  878.                   getService(Ci.nsIAnnotationService);
  879.  
  880.     var callback = {
  881.       _uri: function(aSpec) {
  882.         return Cc["@mozilla.org/network/io-service;1"].
  883.                getService(Ci.nsIIOService).
  884.                newURI(aSpec, null, null);
  885.       },
  886.  
  887.       runBatched: function() {
  888.         var smartBookmarks = [];
  889.         var bookmarksMenuIndex = 0;
  890.         var bookmarksToolbarIndex = 0;
  891.  
  892.         var placesBundle = Cc["@mozilla.org/intl/stringbundle;1"].
  893.                            getService(Ci.nsIStringBundleService).
  894.                            createBundle("chrome://browser/locale/places/places.properties");
  895.  
  896.         // MOST VISITED
  897.         var smart = {queryId: "MostVisited", // don't change this
  898.                      itemId: null,
  899.                      title: placesBundle.GetStringFromName("mostVisitedTitle"),
  900.                      uri: this._uri("place:redirectsMode=" +
  901.                                     Ci.nsINavHistoryQueryOptions.REDIRECTS_MODE_TARGET +
  902.                                     "&sort=" +
  903.                                     Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING +
  904.                                     "&maxResults=" + MAX_RESULTS),
  905.                      parent: bmsvc.toolbarFolder,
  906.                      position: bookmarksToolbarIndex++,
  907.                      newInVersion: 1 };
  908.         smartBookmarks.push(smart);
  909.  
  910.         // RECENTLY BOOKMARKED
  911.         smart = {queryId: "RecentlyBookmarked", // don't change this
  912.                  itemId: null,
  913.                  title: placesBundle.GetStringFromName("recentlyBookmarkedTitle"),
  914.                  uri: this._uri("place:folder=BOOKMARKS_MENU" +
  915.                                 "&folder=UNFILED_BOOKMARKS" +
  916.                                 "&folder=TOOLBAR" +
  917.                                 "&queryType=" +
  918.                                 Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS +
  919.                                 "&sort=" +
  920.                                 Ci.nsINavHistoryQueryOptions.SORT_BY_DATEADDED_DESCENDING +
  921.                                 "&excludeItemIfParentHasAnnotation=livemark%2FfeedURI" +
  922.                                 "&maxResults=" + MAX_RESULTS +
  923.                                 "&excludeQueries=1"),
  924.                  parent: bmsvc.bookmarksMenuFolder,
  925.                  position: bookmarksMenuIndex++,
  926.                  newInVersion: 1 };
  927.         smartBookmarks.push(smart);
  928.  
  929.         // RECENT TAGS
  930.         smart = {queryId: "RecentTags", // don't change this
  931.                  itemId: null,
  932.                  title: placesBundle.GetStringFromName("recentTagsTitle"),
  933.                  uri: this._uri("place:"+
  934.                     "type=" +
  935.                     Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_QUERY +
  936.                     "&sort=" +
  937.                     Ci.nsINavHistoryQueryOptions.SORT_BY_LASTMODIFIED_DESCENDING +
  938.                     "&maxResults=" + MAX_RESULTS),
  939.                  parent: bmsvc.bookmarksMenuFolder,
  940.                  position: bookmarksMenuIndex++,
  941.                  newInVersion: 1 };
  942.         smartBookmarks.push(smart);
  943.  
  944.         var smartBookmarkItemIds = annosvc.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO, {});
  945.         // Set current itemId, parent and position if Smart Bookmark exists,
  946.         // we will use these informations to create the new version at the same
  947.         // position.
  948.         for each(var itemId in smartBookmarkItemIds) {
  949.           var queryId = annosvc.getItemAnnotation(itemId, SMART_BOOKMARKS_ANNO);
  950.           for (var i = 0; i < smartBookmarks.length; i++){
  951.             if (smartBookmarks[i].queryId == queryId) {
  952.               smartBookmarks[i].found = true;
  953.               smartBookmarks[i].itemId = itemId;
  954.               smartBookmarks[i].parent = bmsvc.getFolderIdForItem(itemId);
  955.               smartBookmarks[i].position = bmsvc.getItemIndex(itemId);
  956.               // remove current item, since it will be replaced
  957.               bmsvc.removeItem(itemId);
  958.               break;
  959.             }
  960.             // We don't remove old Smart Bookmarks because user could still
  961.             // find them useful, or could have personalized them.
  962.             // Instead we remove the Smart Bookmark annotation.
  963.             if (i == smartBookmarks.length - 1)
  964.               annosvc.removeItemAnnotation(itemId, SMART_BOOKMARKS_ANNO);
  965.           }
  966.         }
  967.  
  968.         // create smart bookmarks
  969.         for each(var smartBookmark in smartBookmarks) {
  970.           // We update or create only changed or new smart bookmarks.
  971.           // Also we respect user choices, so we won't try to create a smart
  972.           // bookmark if it has been removed.
  973.           if (smartBookmarksCurrentVersion > 0 &&
  974.               smartBookmark.newInVersion <= smartBookmarksCurrentVersion &&
  975.               !smartBookmark.found)
  976.             continue;
  977.  
  978.           smartBookmark.itemId = bmsvc.insertBookmark(smartBookmark.parent,
  979.                                                       smartBookmark.uri,
  980.                                                       smartBookmark.position,
  981.                                                       smartBookmark.title);
  982.           annosvc.setItemAnnotation(smartBookmark.itemId,
  983.                                     SMART_BOOKMARKS_ANNO, smartBookmark.queryId,
  984.                                     0, annosvc.EXPIRE_NEVER);
  985.         }
  986.         
  987.         // If we are creating all Smart Bookmarks from ground up, add a
  988.         // separator below them in the bookmarks menu.
  989.         if (smartBookmarksCurrentVersion == 0 &&
  990.             smartBookmarkItemIds.length == 0)
  991.           bmsvc.insertSeparator(bmsvc.bookmarksMenuFolder, bookmarksMenuIndex);
  992.       }
  993.     };
  994.  
  995.     try {
  996.       bmsvc.runInBatchMode(callback, null);
  997.     }
  998.     catch(ex) {
  999.       Components.utils.reportError(ex);
  1000.     }
  1001.     finally {
  1002.       this._prefs.setIntPref(SMART_BOOKMARKS_PREF, SMART_BOOKMARKS_VERSION);
  1003.       this._prefs.QueryInterface(Ci.nsIPrefService).savePrefFile(null);
  1004.     }
  1005.   },
  1006.  
  1007. //@line 1066 "/e/builds/nightly/release/sb_win32bot03_release/build/dependencies/vendor/mozbrowser/components/nsBrowserGlue.js"
  1008.  
  1009.   // this returns the most recent non-popup browser window
  1010.   getMostRecentBrowserWindow : function ()
  1011.   {
  1012.     var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
  1013.              getService(Components.interfaces.nsIWindowMediator);
  1014.  
  1015. //@line 1088 "/e/builds/nightly/release/sb_win32bot03_release/build/dependencies/vendor/mozbrowser/components/nsBrowserGlue.js"
  1016.     var windowList = wm.getZOrderDOMWindowEnumerator("navigator:browser", true);
  1017.     if (!windowList.hasMoreElements())
  1018.       return null;
  1019.  
  1020.     var win = windowList.getNext();
  1021.     while (win.document.documentElement.getAttribute("chromehidden")) {
  1022.       if (!windowList.hasMoreElements())
  1023.         return null;
  1024.  
  1025.       win = windowList.getNext();
  1026.     }
  1027. //@line 1100 "/e/builds/nightly/release/sb_win32bot03_release/build/dependencies/vendor/mozbrowser/components/nsBrowserGlue.js"
  1028.  
  1029.     return win;
  1030.   },
  1031.  
  1032.  
  1033.   // for XPCOM
  1034.   classDescription: "Firefox Browser Glue Service",
  1035.   classID:          Components.ID("{eab9012e-5f74-4cbc-b2b5-a590235513cc}"),
  1036.   contractID:       "@mozilla.org/browser/browserglue;1",
  1037.  
  1038.   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
  1039.                                          Ci.nsISupportsWeakReference,
  1040.                                          Ci.nsIBrowserGlue]),
  1041.  
  1042.   // redefine the default factory for XPCOMUtils
  1043.   _xpcom_factory: BrowserGlueServiceFactory,
  1044.  
  1045.   // get this contractID registered for certain categories via XPCOMUtils
  1046.   _xpcom_categories: [
  1047.     // make BrowserGlue a startup observer
  1048.     { category: "app-startup", service: true },
  1049.     { /* when component registration *didn't* run (i.e. second run), we need
  1050.        * to get invoked via this topic to be able to apply the default prefs
  1051.        * before the chrome registry initializes
  1052.        */
  1053.       category: "prefservice:after-app-defaults", service: true }
  1054.   ]
  1055. }
  1056.  
  1057. function GeolocationPrompt() {}
  1058.  
  1059. GeolocationPrompt.prototype = {
  1060.   classDescription: "Geolocation Prompting Component",
  1061.   classID:          Components.ID("{C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5}"),
  1062.   contractID:       "@mozilla.org/geolocation/prompt;1",
  1063.  
  1064.   QueryInterface: XPCOMUtils.generateQI([Ci.nsIGeolocationPrompt]),
  1065.  
  1066.   prompt: function(request) {
  1067.     var pm = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
  1068.  
  1069.     var result = pm.testExactPermission(request.requestingURI, "geo");
  1070.  
  1071.     if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
  1072.       request.allow();
  1073.       return;
  1074.     }
  1075.     
  1076.     if (result == Ci.nsIPermissionManager.DENY_ACTION) {
  1077.       request.cancel();
  1078.       return;
  1079.     }
  1080.  
  1081.     function setPagePermission(uri, allow) {
  1082.       if (allow == true)
  1083.         pm.add(uri, "geo", Ci.nsIPermissionManager.ALLOW_ACTION);
  1084.       else
  1085.         pm.add(uri, "geo", Ci.nsIPermissionManager.DENY_ACTION);
  1086.     }
  1087.  
  1088.     function getChromeWindow(aWindow) {
  1089.       var chromeWin = aWindow 
  1090.         .QueryInterface(Ci.nsIInterfaceRequestor)
  1091.         .getInterface(Ci.nsIWebNavigation)
  1092.         .QueryInterface(Ci.nsIDocShellTreeItem)
  1093.         .rootTreeItem
  1094.         .QueryInterface(Ci.nsIInterfaceRequestor)
  1095.         .getInterface(Ci.nsIDOMWindow)
  1096.         .QueryInterface(Ci.nsIDOMChromeWindow);
  1097.       return chromeWin;
  1098.     }
  1099.  
  1100.     var requestingWindow = request.requestingWindow.top;
  1101.     var chromeWindowObject = getChromeWindow(requestingWindow).wrappedJSObject;
  1102.     var tabbrowser = chromeWindowObject.gBrowser;
  1103.     var browser = tabbrowser.getBrowserForDocument(requestingWindow.document);
  1104.     var notificationBox = tabbrowser.getNotificationBox(browser);
  1105.  
  1106.     var notification = notificationBox.getNotificationWithValue("geolocation");
  1107.     if (!notification) {
  1108.       var bundleService = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
  1109.       var browserBundle = bundleService.createBundle("chrome://browser/locale/browser.properties");
  1110.  
  1111.       var buttons = [{
  1112.               label: browserBundle.GetStringFromName("geolocation.shareLocation"),
  1113.               accessKey: browserBundle.GetStringFromName("geolocation.shareLocation.accesskey"),
  1114.               callback: function(notification) {
  1115.                   var elements = notification.getElementsByClassName("rememberChoice");
  1116.                   if (elements.length && elements[0].checked)
  1117.                       setPagePermission(request.requestingURI, true);
  1118.                   request.allow(); 
  1119.               },
  1120.           },
  1121.           {
  1122.               label: browserBundle.GetStringFromName("geolocation.dontShareLocation"),
  1123.               accessKey: browserBundle.GetStringFromName("geolocation.dontShareLocation.accesskey"),
  1124.               callback: function(notification) {
  1125.                   var elements = notification.getElementsByClassName("rememberChoice");
  1126.                   if (elements.length && elements[0].checked)
  1127.                       setPagePermission(request.requestingURI, false);
  1128.                   request.cancel();
  1129.               },
  1130.           }];
  1131.       
  1132.       var message = browserBundle.formatStringFromName("geolocation.siteWantsToKnow",
  1133.                                                        [request.requestingURI.host], 1);      
  1134.  
  1135.       var newBar = notificationBox.appendNotification(message,
  1136.                                                       "geolocation",
  1137.                                                       "chrome://browser/skin/Geo.png",
  1138.                                                       notificationBox.PRIORITY_INFO_HIGH,
  1139.                                                       buttons);
  1140.  
  1141.       // For whatever reason, if we do this immediately
  1142.       // (eg, without the setTimeout), the "link"
  1143.       // element does not show up in the notification
  1144.       // bar.
  1145.       function geolocation_hacks_to_notification () {
  1146.  
  1147.         // Never show a remember checkbox inside the private browsing mode
  1148.         // XXX Songbird: allow not having private browsing support
  1149.         var inPrivateBrowsing = false;
  1150.         if ("@mozilla.org/privatebrowsing;1" in Cc) {
  1151.           inPrivateBrowsing = Cc["@mozilla.org/privatebrowsing;1"].
  1152.                               getService(Ci.nsIPrivateBrowsingService).
  1153.                               privateBrowsingEnabled;
  1154.         }
  1155.         if (!inPrivateBrowsing) {
  1156.           var checkbox = newBar.ownerDocument.createElementNS(XULNS, "checkbox");
  1157.           checkbox.className = "rememberChoice";
  1158.           checkbox.setAttribute("label", browserBundle.GetStringFromName("geolocation.remember"));
  1159.           checkbox.setAttribute("accesskey", browserBundle.GetStringFromName("geolocation.remember.accesskey"));
  1160.           newBar.appendChild(checkbox);
  1161.         }
  1162.  
  1163.         var link = newBar.ownerDocument.createElementNS(XULNS, "label");
  1164.         link.className = "text-link";
  1165.         link.setAttribute("value", browserBundle.GetStringFromName("geolocation.learnMore"));
  1166.  
  1167.         var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].getService(Ci.nsIURLFormatter);
  1168.         link.href = formatter.formatURLPref("browser.geolocation.warning.infoURL");
  1169.  
  1170.         var description = newBar.ownerDocument.getAnonymousElementByAttribute(newBar, "anonid", "messageText");
  1171.         description.appendChild(link);
  1172.       };
  1173.  
  1174.       chromeWindowObject.setTimeout(geolocation_hacks_to_notification, 0);
  1175.  
  1176.     }
  1177.   },
  1178. };
  1179.  
  1180.  
  1181. //module initialization
  1182. function NSGetModule(aCompMgr, aFileSpec) {
  1183.   /* on runs with component registration (e.g. safe mode), we need to manually
  1184.    * load the default prefs in order to happen before the chrome registry loads
  1185.    */
  1186.   BrowserGlueServiceFactory.createInstance(null)._onAppDefaults();
  1187.   return XPCOMUtils.generateModule([BrowserGlue, GeolocationPrompt]);
  1188. }
  1189.