Bug 616542 - Shorten file path length of mochitest; r=ted
[gecko.git] / browser / components / nsBrowserContentHandler.js
blobc44584acb6bcf597def3d1ca159d0aecd24a6ec8
1 # ***** BEGIN LICENSE BLOCK *****
2 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 # The contents of this file are subject to the Mozilla Public License Version
5 # 1.1 (the "License"); you may not use this file except in compliance with
6 # the License. You may obtain a copy of the License at
7 # http://www.mozilla.org/MPL/
9 # Software distributed under the License is distributed on an "AS IS" basis,
10 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 # for the specific language governing rights and limitations under the
12 # License.
14 # The Original Code is the Mozilla Firefox browser.
16 # The Initial Developer of the Original Code is
17 # Benjamin Smedberg <benjamin@smedbergs.us>
19 # Portions created by the Initial Developer are Copyright (C) 2004
20 # the Initial Developer. All Rights Reserved.
22 # Contributor(s):
23 #   Robert Strong <robert.bugzilla@gmail.com>
25 # Alternatively, the contents of this file may be used under the terms of
26 # either the GNU General Public License Version 2 or later (the "GPL"), or
27 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 # in which case the provisions of the GPL or the LGPL are applicable instead
29 # of those above. If you wish to allow use of your version of this file only
30 # under the terms of either the GPL or the LGPL, and not to allow others to
31 # use your version of this file under the terms of the MPL, indicate your
32 # decision by deleting the provisions above and replace them with the notice
33 # and other provisions required by the GPL or the LGPL. If you do not delete
34 # the provisions above, a recipient may use your version of this file under
35 # the terms of any one of the MPL, the GPL or the LGPL.
37 # ***** END LICENSE BLOCK *****
39 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
40 Components.utils.import("resource://gre/modules/Services.jsm");
42 const nsISupports            = Components.interfaces.nsISupports;
44 const nsIBrowserDOMWindow    = Components.interfaces.nsIBrowserDOMWindow;
45 const nsIBrowserHandler      = Components.interfaces.nsIBrowserHandler;
46 const nsIBrowserHistory      = Components.interfaces.nsIBrowserHistory;
47 const nsIChannel             = Components.interfaces.nsIChannel;
48 const nsICommandLine         = Components.interfaces.nsICommandLine;
49 const nsICommandLineHandler  = Components.interfaces.nsICommandLineHandler;
50 const nsIContentHandler      = Components.interfaces.nsIContentHandler;
51 const nsIDocShellTreeItem    = Components.interfaces.nsIDocShellTreeItem;
52 const nsIDOMChromeWindow     = Components.interfaces.nsIDOMChromeWindow;
53 const nsIDOMWindow           = Components.interfaces.nsIDOMWindow;
54 const nsIFileURL             = Components.interfaces.nsIFileURL;
55 const nsIHttpProtocolHandler = Components.interfaces.nsIHttpProtocolHandler;
56 const nsIInterfaceRequestor  = Components.interfaces.nsIInterfaceRequestor;
57 const nsINetUtil             = Components.interfaces.nsINetUtil;
58 const nsIPrefBranch          = Components.interfaces.nsIPrefBranch;
59 const nsIPrefLocalizedString = Components.interfaces.nsIPrefLocalizedString;
60 const nsISupportsString      = Components.interfaces.nsISupportsString;
61 const nsIURIFixup            = Components.interfaces.nsIURIFixup;
62 const nsIWebNavigation       = Components.interfaces.nsIWebNavigation;
63 const nsIWindowMediator      = Components.interfaces.nsIWindowMediator;
64 const nsIWindowWatcher       = Components.interfaces.nsIWindowWatcher;
65 const nsIWebNavigationInfo   = Components.interfaces.nsIWebNavigationInfo;
66 const nsIBrowserSearchService = Components.interfaces.nsIBrowserSearchService;
67 const nsICommandLineValidator = Components.interfaces.nsICommandLineValidator;
68 const nsIXULAppInfo          = Components.interfaces.nsIXULAppInfo;
70 const NS_BINDING_ABORTED = Components.results.NS_BINDING_ABORTED;
71 const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001;
72 const NS_ERROR_ABORT = Components.results.NS_ERROR_ABORT;
74 const URI_INHERITS_SECURITY_CONTEXT = nsIHttpProtocolHandler
75                                         .URI_INHERITS_SECURITY_CONTEXT;
77 function shouldLoadURI(aURI) {
78   if (aURI && !aURI.schemeIs("chrome"))
79     return true;
81   dump("*** Preventing external load of chrome: URI into browser window\n");
82   dump("    Use -chrome <uri> instead\n");
83   return false;
86 function resolveURIInternal(aCmdLine, aArgument) {
87   var uri = aCmdLine.resolveURI(aArgument);
89   if (!(uri instanceof nsIFileURL)) {
90     return uri;
91   }
93   try {
94     if (uri.file.exists())
95       return uri;
96   }
97   catch (e) {
98     Components.utils.reportError(e);
99   }
101   // We have interpreted the argument as a relative file URI, but the file
102   // doesn't exist. Try URI fixup heuristics: see bug 290782.
104   try {
105     var urifixup = Components.classes["@mozilla.org/docshell/urifixup;1"]
106                              .getService(nsIURIFixup);
108     uri = urifixup.createFixupURI(aArgument, 0);
109   }
110   catch (e) {
111     Components.utils.reportError(e);
112   }
114   return uri;
117 const OVERRIDE_NONE        = 0;
118 const OVERRIDE_NEW_PROFILE = 1;
119 const OVERRIDE_NEW_MSTONE  = 2;
120 const OVERRIDE_NEW_BUILD_ID = 3;
122  * Determines whether a home page override is needed.
123  * Returns:
124  *  OVERRIDE_NEW_PROFILE if this is the first run with a new profile.
125  *  OVERRIDE_NEW_MSTONE if this is the first run with a build with a different
126  *                      Gecko milestone (i.e. right after an upgrade).
127  *  OVERRIDE_NEW_BUILD_ID if this is the first run with a new build ID of the
128  *                        same Gecko milestone (i.e. after a nightly upgrade).
129  *  OVERRIDE_NONE otherwise.
130  */
131 function needHomepageOverride(prefb) {
132   var savedmstone = null;
133   try {
134     savedmstone = prefb.getCharPref("browser.startup.homepage_override.mstone");
135   } catch (e) {}
137   if (savedmstone == "ignore")
138     return OVERRIDE_NONE;
140   var mstone = Components.classes["@mozilla.org/network/protocol;1?name=http"]
141                          .getService(nsIHttpProtocolHandler).misc;
143   var savedBuildID = null;
144   try {
145     savedBuildID = prefb.getCharPref("browser.startup.homepage_override.buildID");
146   } catch (e) {}
148   var buildID =  Components.classes["@mozilla.org/xre/app-info;1"]
149                            .getService(nsIXULAppInfo).platformBuildID;
151   if (mstone != savedmstone) {
152     // Bug 462254. Previous releases had a default pref to suppress the EULA
153     // agreement if the platform's installer had already shown one. Now with
154     // about:rights we've removed the EULA stuff and default pref, but we need
155     // a way to make existing profiles retain the default that we removed.
156     if (savedmstone)
157       prefb.setBoolPref("browser.rights.3.shown", true);
158     
159     prefb.setCharPref("browser.startup.homepage_override.mstone", mstone);
160     prefb.setCharPref("browser.startup.homepage_override.buildID", buildID);
161     return (savedmstone ? OVERRIDE_NEW_MSTONE : OVERRIDE_NEW_PROFILE);
162   }
164   if (buildID != savedBuildID) {
165     prefb.setCharPref("browser.startup.homepage_override.buildID", buildID);
166     return OVERRIDE_NEW_BUILD_ID;
167   }
169   return OVERRIDE_NONE;
173  * Gets the override page for the first run after the application has been
174  * updated.
175  * @param  defaultOverridePage
176  *         The default override page.
177  * @return The override page.
178  */
179 function getPostUpdateOverridePage(defaultOverridePage) {
180   var um = Components.classes["@mozilla.org/updates/update-manager;1"]
181                      .getService(Components.interfaces.nsIUpdateManager);
182   try {
183     // If the updates.xml file is deleted then getUpdateAt will throw.
184     var update = um.getUpdateAt(0)
185                    .QueryInterface(Components.interfaces.nsIPropertyBag);
186   } catch (e) {
187     // This should never happen.
188     Components.utils.reportError("Unable to find update: " + e);
189     return defaultOverridePage;
190   }
192   let actions = update.getProperty("actions");
193   // When the update doesn't specify actions fallback to the original behavior
194   // of displaying the default override page.
195   if (!actions)
196     return defaultOverridePage;
198   // The existence of silent or the non-existence of showURL in the actions both
199   // mean that an override page should not be displayed.
200   if (actions.indexOf("silent") != -1 || actions.indexOf("showURL") == -1)
201     return "";
203   return update.getProperty("openURL") || defaultOverridePage;
206 // Copies a pref override file into the user's profile pref-override folder,
207 // and then tells the pref service to reload its default prefs.
208 function copyPrefOverride() {
209   try {
210     var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"]
211                                 .getService(Components.interfaces.nsIProperties);
212     const NS_APP_EXISTING_PREF_OVERRIDE = "ExistingPrefOverride";
213     var prefOverride = fileLocator.get(NS_APP_EXISTING_PREF_OVERRIDE,
214                                        Components.interfaces.nsIFile);
215     if (!prefOverride.exists())
216       return; // nothing to do
218     const NS_APP_PREFS_OVERRIDE_DIR     = "PrefDOverride";
219     var prefOverridesDir = fileLocator.get(NS_APP_PREFS_OVERRIDE_DIR,
220                                            Components.interfaces.nsIFile);
222     // Check for any existing pref overrides, and remove them if present
223     var existingPrefOverridesFile = prefOverridesDir.clone();
224     existingPrefOverridesFile.append(prefOverride.leafName);
225     if (existingPrefOverridesFile.exists())
226       existingPrefOverridesFile.remove(false);
228     prefOverride.copyTo(prefOverridesDir, null);
230     // Now that we've installed the new-profile pref override file,
231     // re-read the default prefs.
232     var prefSvcObs = Components.classes["@mozilla.org/preferences-service;1"]
233                                .getService(Components.interfaces.nsIObserver);
234     prefSvcObs.observe(null, "reload-default-prefs", null);
235   } catch (ex) {
236     Components.utils.reportError(ex);
237   }
240 // Flag used to indicate that the arguments to openWindow can be passed directly.
241 const NO_EXTERNAL_URIS = 1;
243 function openWindow(parent, url, target, features, args, noExternalArgs) {
244   var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
245                          .getService(nsIWindowWatcher);
247   if (noExternalArgs == NO_EXTERNAL_URIS) {
248     // Just pass in the defaultArgs directly
249     var argstring;
250     if (args) {
251       argstring = Components.classes["@mozilla.org/supports-string;1"]
252                             .createInstance(nsISupportsString);
253       argstring.data = args;
254     }
256     return wwatch.openWindow(parent, url, target, features, argstring);
257   }
258   
259   // Pass an array to avoid the browser "|"-splitting behavior.
260   var argArray = Components.classes["@mozilla.org/supports-array;1"]
261                     .createInstance(Components.interfaces.nsISupportsArray);
263   // add args to the arguments array
264   var stringArgs = null;
265   if (args instanceof Array) // array
266     stringArgs = args;
267   else if (args) // string
268     stringArgs = [args];
270   if (stringArgs) {
271     // put the URIs into argArray
272     var uriArray = Components.classes["@mozilla.org/supports-array;1"]
273                        .createInstance(Components.interfaces.nsISupportsArray);
274     stringArgs.forEach(function (uri) {
275       var sstring = Components.classes["@mozilla.org/supports-string;1"]
276                               .createInstance(nsISupportsString);
277       sstring.data = uri;
278       uriArray.AppendElement(sstring);
279     });
280     argArray.AppendElement(uriArray);
281   } else {
282     argArray.AppendElement(null);
283   }
285   // Pass these as null to ensure that we always trigger the "single URL"
286   // behavior in browser.js's BrowserStartup (which handles the window
287   // arguments)
288   argArray.AppendElement(null); // charset
289   argArray.AppendElement(null); // referer
290   argArray.AppendElement(null); // postData
291   argArray.AppendElement(null); // allowThirdPartyFixup
293   return wwatch.openWindow(parent, url, target, features, argArray);
296 function openPreferences() {
297   var features = "chrome,titlebar,toolbar,centerscreen,dialog=no";
298   var url = "chrome://browser/content/preferences/preferences.xul";
300   var win = getMostRecentWindow("Browser:Preferences");
301   if (win) {
302     win.focus();
303   } else {
304     openWindow(null, url, "_blank", features);
305   }
308 function getMostRecentWindow(aType) {
309   var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
310                      .getService(nsIWindowMediator);
311   return wm.getMostRecentWindow(aType);
314 // this returns the most recent non-popup browser window
315 function getMostRecentBrowserWindow() {
316   var browserGlue = Components.classes["@mozilla.org/browser/browserglue;1"]
317                               .getService(Components.interfaces.nsIBrowserGlue);
318   return browserGlue.getMostRecentBrowserWindow();
321 function doSearch(searchTerm, cmdLine) {
322   var ss = Components.classes["@mozilla.org/browser/search-service;1"]
323                      .getService(nsIBrowserSearchService);
325   var submission = ss.defaultEngine.getSubmission(searchTerm);
327   // fill our nsISupportsArray with uri-as-wstring, null, null, postData
328   var sa = Components.classes["@mozilla.org/supports-array;1"]
329                      .createInstance(Components.interfaces.nsISupportsArray);
331   var wuri = Components.classes["@mozilla.org/supports-string;1"]
332                        .createInstance(Components.interfaces.nsISupportsString);
333   wuri.data = submission.uri.spec;
335   sa.AppendElement(wuri);
336   sa.AppendElement(null);
337   sa.AppendElement(null);
338   sa.AppendElement(submission.postData);
340   // XXXbsmedberg: use handURIToExistingBrowser to obey tabbed-browsing
341   // preferences, but need nsIBrowserDOMWindow extensions
343   var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
344                          .getService(nsIWindowWatcher);
346   return wwatch.openWindow(null, gBrowserContentHandler.chromeURL,
347                            "_blank",
348                            "chrome,dialog=no,all" +
349                            gBrowserContentHandler.getFeatures(cmdLine),
350                            sa);
353 function nsBrowserContentHandler() {
355 nsBrowserContentHandler.prototype = {
356   classID: Components.ID("{5d0ce354-df01-421a-83fb-7ead0990c24e}"),
358   _xpcom_factory: {
359     createInstance: function bch_factory_ci(outer, iid) {
360       if (outer)
361         throw Components.results.NS_ERROR_NO_AGGREGATION;
362       return gBrowserContentHandler.QueryInterface(iid);
363     }
364   },
366   /* helper functions */
368   mChromeURL : null,
370   get chromeURL() {
371     if (this.mChromeURL) {
372       return this.mChromeURL;
373     }
375     var prefb = Components.classes["@mozilla.org/preferences-service;1"]
376                           .getService(nsIPrefBranch);
377     this.mChromeURL = prefb.getCharPref("browser.chromeURL");
379     return this.mChromeURL;
380   },
382   /* nsISupports */
383   QueryInterface : XPCOMUtils.generateQI([nsICommandLineHandler,
384                                           nsIBrowserHandler,
385                                           nsIContentHandler,
386                                           nsICommandLineValidator]),
388   /* nsICommandLineHandler */
389   handle : function bch_handle(cmdLine) {
390     if (cmdLine.handleFlag("browser", false)) {
391       // Passing defaultArgs, so use NO_EXTERNAL_URIS
392       openWindow(null, this.chromeURL, "_blank",
393                  "chrome,dialog=no,all" + this.getFeatures(cmdLine),
394                  this.defaultArgs, NO_EXTERNAL_URIS);
395       cmdLine.preventDefault = true;
396     }
398     try {
399       var remoteCommand = cmdLine.handleFlagWithParam("remote", true);
400     }
401     catch (e) {
402       throw NS_ERROR_ABORT;
403     }
405     if (remoteCommand != null) {
406       try {
407         var a = /^\s*(\w+)\(([^\)]*)\)\s*$/.exec(remoteCommand);
408         var remoteVerb;
409         if (a) {
410           remoteVerb = a[1].toLowerCase();
411           var remoteParams = [];
412           var sepIndex = a[2].lastIndexOf(",");
413           if (sepIndex == -1)
414             remoteParams[0] = a[2];
415           else {
416             remoteParams[0] = a[2].substring(0, sepIndex);
417             remoteParams[1] = a[2].substring(sepIndex + 1);
418           }
419         }
421         switch (remoteVerb) {
422         case "openurl":
423         case "openfile":
424           // openURL(<url>)
425           // openURL(<url>,new-window)
426           // openURL(<url>,new-tab)
428           // First param is the URL, second param (if present) is the "target"
429           // (tab, window)
430           var url = remoteParams[0];
431           var target = nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW;
432           if (remoteParams[1]) {
433             var targetParam = remoteParams[1].toLowerCase()
434                                              .replace(/^\s*|\s*$/g, "");
435             if (targetParam == "new-tab")
436               target = nsIBrowserDOMWindow.OPEN_NEWTAB;
437             else if (targetParam == "new-window")
438               target = nsIBrowserDOMWindow.OPEN_NEWWINDOW;
439             else {
440               // The "target" param isn't one of our supported values, so
441               // assume it's part of a URL that contains commas.
442               url += "," + remoteParams[1];
443             }
444           }
446           var uri = resolveURIInternal(cmdLine, url);
447           handURIToExistingBrowser(uri, target, cmdLine);
448           break;
450         case "xfedocommand":
451           // xfeDoCommand(openBrowser)
452           if (remoteParams[0].toLowerCase() != "openbrowser")
453             throw NS_ERROR_ABORT;
455           // Passing defaultArgs, so use NO_EXTERNAL_URIS
456           openWindow(null, this.chromeURL, "_blank",
457                      "chrome,dialog=no,all" + this.getFeatures(cmdLine),
458                      this.defaultArgs, NO_EXTERNAL_URIS);
459           break;
461         default:
462           // Somebody sent us a remote command we don't know how to process:
463           // just abort.
464           throw "Unknown remote command.";
465         }
467         cmdLine.preventDefault = true;
468       }
469       catch (e) {
470         Components.utils.reportError(e);
471         // If we had a -remote flag but failed to process it, throw
472         // NS_ERROR_ABORT so that the xremote code knows to return a failure
473         // back to the handling code.
474         throw NS_ERROR_ABORT;
475       }
476     }
478     var uriparam;
479     try {
480       while ((uriparam = cmdLine.handleFlagWithParam("new-window", false))) {
481         var uri = resolveURIInternal(cmdLine, uriparam);
482         if (!shouldLoadURI(uri))
483           continue;
484         openWindow(null, this.chromeURL, "_blank",
485                    "chrome,dialog=no,all" + this.getFeatures(cmdLine),
486                    uri.spec);
487         cmdLine.preventDefault = true;
488       }
489     }
490     catch (e) {
491       Components.utils.reportError(e);
492     }
494     try {
495       while ((uriparam = cmdLine.handleFlagWithParam("new-tab", false))) {
496         var uri = resolveURIInternal(cmdLine, uriparam);
497         handURIToExistingBrowser(uri, nsIBrowserDOMWindow.OPEN_NEWTAB, cmdLine);
498         cmdLine.preventDefault = true;
499       }
500     }
501     catch (e) {
502       Components.utils.reportError(e);
503     }
505     var chromeParam = cmdLine.handleFlagWithParam("chrome", false);
506     if (chromeParam) {
508       // Handle the old preference dialog URL separately (bug 285416)
509       if (chromeParam == "chrome://browser/content/pref/pref.xul") {
510         openPreferences();
511         cmdLine.preventDefault = true;
512       } else try {
513         // only load URIs which do not inherit chrome privs
514         var features = "chrome,dialog=no,all" + this.getFeatures(cmdLine);
515         var uri = resolveURIInternal(cmdLine, chromeParam);
516         var netutil = Components.classes["@mozilla.org/network/util;1"]
517                                 .getService(nsINetUtil);
518         if (!netutil.URIChainHasFlags(uri, URI_INHERITS_SECURITY_CONTEXT)) {
519           openWindow(null, uri.spec, "_blank", features);
520           cmdLine.preventDefault = true;
521         }
522       }
523       catch (e) {
524         Components.utils.reportError(e);
525       }
526     }
527     if (cmdLine.handleFlag("preferences", false)) {
528       openPreferences();
529       cmdLine.preventDefault = true;
530     }
531     if (cmdLine.handleFlag("silent", false))
532       cmdLine.preventDefault = true;
533     if (cmdLine.findFlag("private-toggle", false) >= 0)
534       cmdLine.preventDefault = true;
536     var searchParam = cmdLine.handleFlagWithParam("search", false);
537     if (searchParam) {
538       doSearch(searchParam, cmdLine);
539       cmdLine.preventDefault = true;
540     }
542     var fileParam = cmdLine.handleFlagWithParam("file", false);
543     if (fileParam) {
544       var file = cmdLine.resolveFile(fileParam);
545       var ios = Components.classes["@mozilla.org/network/io-service;1"]
546                           .getService(Components.interfaces.nsIIOService);
547       var uri = ios.newFileURI(file);
548       openWindow(null, this.chromeURL, "_blank", 
549                  "chrome,dialog=no,all" + this.getFeatures(cmdLine),
550                  uri.spec);
551       cmdLine.preventDefault = true;
552     }
554 #ifdef XP_WIN
555     // Handle "? searchterm" for Windows Vista start menu integration
556     for (var i = cmdLine.length - 1; i >= 0; --i) {
557       var param = cmdLine.getArgument(i);
558       if (param.match(/^\? /)) {
559         cmdLine.removeArguments(i, i);
560         cmdLine.preventDefault = true;
562         searchParam = param.substr(2);
563         doSearch(searchParam, cmdLine);
564       }
565     }
566 #endif
567   },
569   helpInfo : "  -browser           Open a browser window.\n" +
570              "  -new-window  <url> Open <url> in a new window.\n" +
571              "  -new-tab     <url> Open <url> in a new tab.\n" +
572 #ifdef XP_WIN
573              "  -preferences       Open Options dialog.\n" +
574 #else
575              "  -preferences       Open Preferences dialog.\n" +
576 #endif
577              "  -search     <term> Search <term> with your default search engine.\n",
579   /* nsIBrowserHandler */
581   get defaultArgs() {
582     var prefb = Components.classes["@mozilla.org/preferences-service;1"]
583                           .getService(nsIPrefBranch);
585     var overridePage = "";
586     var haveUpdateSession = false;
587     try {
588       let override = needHomepageOverride(prefb);
589       if (override != OVERRIDE_NONE) {
590         // Setup the default search engine to about:home page.
591         AboutHomeUtils.loadDefaultSearchEngine();
592         AboutHomeUtils.loadSnippetsURL();
594         switch (override) {
595           case OVERRIDE_NEW_PROFILE:
596             // New profile.
597             overridePage = Services.urlFormatter.formatURLPref("startup.homepage_welcome_url");
598             break;
599           case OVERRIDE_NEW_MSTONE:
600             // Existing profile, new milestone build.
601             copyPrefOverride();
603             // Check whether we have a session to restore. If we do, we assume
604             // that this is an "update" session.
605             var ss = Components.classes["@mozilla.org/browser/sessionstartup;1"]
606                                .getService(Components.interfaces.nsISessionStartup);
607             haveUpdateSession = ss.doRestore();
608             overridePage = Services.urlFormatter.formatURLPref("startup.homepage_override_url");
609             if (prefb.prefHasUserValue("app.update.postupdate"))
610               overridePage = getPostUpdateOverridePage(overridePage);
611             break;
612         }
613       }
614       else {
615         // No need to override homepage, but update snippets url if the pref has
616         // been manually changed.
617         if (Services.prefs.prefHasUserValue(AboutHomeUtils.SNIPPETS_URL_PREF)) {
618           AboutHomeUtils.loadSnippetsURL();
619         }
620       }
621     } catch (ex) {}
623     // formatURLPref might return "about:blank" if getting the pref fails
624     if (overridePage == "about:blank")
625       overridePage = "";
627     var startPage = "";
628     try {
629       var choice = prefb.getIntPref("browser.startup.page");
630       if (choice == 1 || choice == 3)
631         startPage = this.startPage;
632     } catch (e) {
633       Components.utils.reportError(e);
634     }
636     if (startPage == "about:blank")
637       startPage = "";
639     // Only show the startPage if we're not restoring an update session.
640     if (overridePage && startPage && !haveUpdateSession)
641       return overridePage + "|" + startPage;
643     return overridePage || startPage || "about:blank";
644   },
646   get startPage() {
647     var uri = Services.prefs.getComplexValue("browser.startup.homepage",
648                                              nsIPrefLocalizedString).data;
649     if (!uri) {
650       Services.prefs.clearUserPref("browser.startup.homepage");
651       uri = Services.prefs.getComplexValue("browser.startup.homepage",
652                                            nsIPrefLocalizedString).data;
653     }
654     return uri;
655   },
657   mFeatures : null,
659   getFeatures : function bch_features(cmdLine) {
660     if (this.mFeatures === null) {
661       this.mFeatures = "";
663       try {
664         var width = cmdLine.handleFlagWithParam("width", false);
665         var height = cmdLine.handleFlagWithParam("height", false);
667         if (width)
668           this.mFeatures += ",width=" + width;
669         if (height)
670           this.mFeatures += ",height=" + height;
671       }
672       catch (e) {
673       }
674     }
676     return this.mFeatures;
677   },
679   /* nsIContentHandler */
681   handleContent : function bch_handleContent(contentType, context, request) {
682     try {
683       var webNavInfo = Components.classes["@mozilla.org/webnavigation-info;1"]
684                                  .getService(nsIWebNavigationInfo);
685       if (!webNavInfo.isTypeSupported(contentType, null)) {
686         throw NS_ERROR_WONT_HANDLE_CONTENT;
687       }
688     } catch (e) {
689       throw NS_ERROR_WONT_HANDLE_CONTENT;
690     }
692     request.QueryInterface(nsIChannel);
693     handURIToExistingBrowser(request.URI,
694       nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, null);
695     request.cancel(NS_BINDING_ABORTED);
696   },
698   /* nsICommandLineValidator */
699   validate : function bch_validate(cmdLine) {
700     // Other handlers may use osint so only handle the osint flag if the url
701     // flag is also present and the command line is valid.
702     var osintFlagIdx = cmdLine.findFlag("osint", false);
703     var urlFlagIdx = cmdLine.findFlag("url", false);
704     if (urlFlagIdx > -1 && (osintFlagIdx > -1 ||
705         cmdLine.state == nsICommandLine.STATE_REMOTE_EXPLICIT)) {
706       var urlParam = cmdLine.getArgument(urlFlagIdx + 1);
707       if (cmdLine.length != urlFlagIdx + 2 || /firefoxurl:/.test(urlParam))
708         throw NS_ERROR_ABORT;
709       cmdLine.handleFlag("osint", false)
710     }
711   },
713 var gBrowserContentHandler = new nsBrowserContentHandler();
715 function handURIToExistingBrowser(uri, location, cmdLine)
717   if (!shouldLoadURI(uri))
718     return;
720   var navWin = getMostRecentBrowserWindow();
721   if (!navWin) {
722     // if we couldn't load it in an existing window, open a new one
723     openWindow(null, gBrowserContentHandler.chromeURL, "_blank",
724                "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine),
725                uri.spec);
726     return;
727   }
729   var navNav = navWin.QueryInterface(nsIInterfaceRequestor)
730                      .getInterface(nsIWebNavigation);
731   var rootItem = navNav.QueryInterface(nsIDocShellTreeItem).rootTreeItem;
732   var rootWin = rootItem.QueryInterface(nsIInterfaceRequestor)
733                         .getInterface(nsIDOMWindow);
734   var bwin = rootWin.QueryInterface(nsIDOMChromeWindow).browserDOMWindow;
735   bwin.openURI(uri, null, location,
736                nsIBrowserDOMWindow.OPEN_EXTERNAL);
739 function nsDefaultCommandLineHandler() {
742 nsDefaultCommandLineHandler.prototype = {
743   classID: Components.ID("{47cd0651-b1be-4a0f-b5c4-10e5a573ef71}"),
745   /* nsISupports */
746   QueryInterface : function dch_QI(iid) {
747     if (!iid.equals(nsISupports) &&
748         !iid.equals(nsICommandLineHandler))
749       throw Components.results.NS_ERROR_NO_INTERFACE;
751     return this;
752   },
754   // List of uri's that were passed via the command line without the app
755   // running and have already been handled. This is compared against uri's
756   // opened using DDE on Win32 so we only open one of the requests.
757   _handledURIs: [ ],
758 #ifdef XP_WIN
759   _haveProfile: false,
760 #endif
762   /* nsICommandLineHandler */
763   handle : function dch_handle(cmdLine) {
764     var urilist = [];
766 #ifdef XP_WIN
767     // If we don't have a profile selected yet (e.g. the Profile Manager is
768     // displayed) we will crash if we open an url and then select a profile. To
769     // prevent this handle all url command line flags and set the command line's
770     // preventDefault to true to prevent the display of the ui. The initial
771     // command line will be retained when nsAppRunner calls LaunchChild though
772     // urls launched after the initial launch will be lost.
773     if (!this._haveProfile) {
774       try {
775         // This will throw when a profile has not been selected.
776         var fl = Components.classes["@mozilla.org/file/directory_service;1"]
777                            .getService(Components.interfaces.nsIProperties);
778         var dir = fl.get("ProfD", Components.interfaces.nsILocalFile);
779         this._haveProfile = true;
780       }
781       catch (e) {
782         while ((ar = cmdLine.handleFlagWithParam("url", false))) { }
783         cmdLine.preventDefault = true;
784       }
785     }
786 #endif
788     try {
789       var ar;
790       while ((ar = cmdLine.handleFlagWithParam("url", false))) {
791         var found = false;
792         var uri = resolveURIInternal(cmdLine, ar);
793         // count will never be greater than zero except on Win32.
794         var count = this._handledURIs.length;
795         for (var i = 0; i < count; ++i) {
796           if (this._handledURIs[i].spec == uri.spec) {
797             this._handledURIs.splice(i, 1);
798             found = true;
799             cmdLine.preventDefault = true;
800             break;
801           }
802         }
803         if (!found) {
804           urilist.push(uri);
805           // The requestpending command line flag is only used on Win32.
806           if (cmdLine.handleFlag("requestpending", false) &&
807               cmdLine.state == nsICommandLine.STATE_INITIAL_LAUNCH)
808             this._handledURIs.push(uri)
809         }
810       }
811     }
812     catch (e) {
813       Components.utils.reportError(e);
814     }
816     count = cmdLine.length;
818     for (i = 0; i < count; ++i) {
819       var curarg = cmdLine.getArgument(i);
820       if (curarg.match(/^-/)) {
821         Components.utils.reportError("Warning: unrecognized command line flag " + curarg + "\n");
822         // To emulate the pre-nsICommandLine behavior, we ignore
823         // the argument after an unrecognized flag.
824         ++i;
825       } else {
826         try {
827           urilist.push(resolveURIInternal(cmdLine, curarg));
828         }
829         catch (e) {
830           Components.utils.reportError("Error opening URI '" + curarg + "' from the command line: " + e + "\n");
831         }
832       }
833     }
835     if (urilist.length) {
836       if (cmdLine.state != nsICommandLine.STATE_INITIAL_LAUNCH &&
837           urilist.length == 1) {
838         // Try to find an existing window and load our URI into the
839         // current tab, new tab, or new window as prefs determine.
840         try {
841           handURIToExistingBrowser(urilist[0], nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, cmdLine);
842           return;
843         }
844         catch (e) {
845         }
846       }
848       var URLlist = urilist.filter(shouldLoadURI).map(function (u) u.spec);
849       if (URLlist.length) {
850         openWindow(null, gBrowserContentHandler.chromeURL, "_blank",
851                    "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine),
852                    URLlist);
853       }
855     }
856     else if (!cmdLine.preventDefault) {
857       // Passing defaultArgs, so use NO_EXTERNAL_URIS
858       openWindow(null, gBrowserContentHandler.chromeURL, "_blank",
859                  "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine),
860                  gBrowserContentHandler.defaultArgs, NO_EXTERNAL_URIS);
861     }
862   },
864   helpInfo : "",
867 let AboutHomeUtils = {
868   SNIPPETS_URL_PREF: "browser.aboutHomeSnippets.updateUrl",
869   get _storage() {
870     let aboutHomeURI = Services.io.newURI("moz-safe-about:home", null, null);
871     let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"].
872                     getService(Components.interfaces.nsIScriptSecurityManager).
873                     getCodebasePrincipal(aboutHomeURI);
874     let dsm = Components.classes["@mozilla.org/dom/storagemanager;1"].
875               getService(Components.interfaces.nsIDOMStorageManager);
876     return dsm.getLocalStorageForPrincipal(principal, "");
877   },
879   loadDefaultSearchEngine: function AHU_loadDefaultSearchEngine()
880   {
881     let defaultEngine = Services.search.originalDefaultEngine;
882     let submission = defaultEngine.getSubmission("_searchTerms_");
883     if (submission.postData)
884       throw new Error("Home page does not support POST search engines.");
885     let engine = {
886       name: defaultEngine.name
887     , searchUrl: submission.uri.spec
888     }
889     this._storage.setItem("search-engine", JSON.stringify(engine));
890   },
892   loadSnippetsURL: function AHU_loadSnippetsURL()
893   {
894     const STARTPAGE_VERSION = 1;
895     let updateURL = Services.prefs
896                             .getCharPref(this.SNIPPETS_URL_PREF)
897                             .replace("%STARTPAGE_VERSION%", STARTPAGE_VERSION);
898     updateURL = Services.urlFormatter.formatURL(updateURL);
899     this._storage.setItem("snippets-update-url", updateURL);
900   },
903 var components = [nsBrowserContentHandler, nsDefaultCommandLineHandler];
904 var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);