CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / browser / components / nsBrowserContentHandler.js
blobd5c6fe4678866093aecf2f885969546d6d269be2
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 nsICategoryManager = Components.interfaces.nsICategoryManager;
66 const nsIWebNavigationInfo = Components.interfaces.nsIWebNavigationInfo;
67 const nsIBrowserSearchService = Components.interfaces.nsIBrowserSearchService;
68 const nsICommandLineValidator = Components.interfaces.nsICommandLineValidator;
69 const nsIXULAppInfo = Components.interfaces.nsIXULAppInfo;
71 const NS_BINDING_ABORTED = Components.results.NS_BINDING_ABORTED;
72 const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001;
73 const NS_ERROR_ABORT = Components.results.NS_ERROR_ABORT;
75 const URI_INHERITS_SECURITY_CONTEXT = nsIHttpProtocolHandler
76 .URI_INHERITS_SECURITY_CONTEXT;
78 function shouldLoadURI(aURI) {
79 if (aURI && !aURI.schemeIs("chrome"))
80 return true;
82 dump("*** Preventing external load of chrome: URI into browser window\n");
83 dump(" Use -chrome <uri> instead\n");
84 return false;
87 function resolveURIInternal(aCmdLine, aArgument) {
88 var uri = aCmdLine.resolveURI(aArgument);
90 if (!(uri instanceof nsIFileURL)) {
91 return uri;
94 try {
95 if (uri.file.exists())
96 return uri;
98 catch (e) {
99 Components.utils.reportError(e);
102 // We have interpreted the argument as a relative file URI, but the file
103 // doesn't exist. Try URI fixup heuristics: see bug 290782.
105 try {
106 var urifixup = Components.classes["@mozilla.org/docshell/urifixup;1"]
107 .getService(nsIURIFixup);
109 uri = urifixup.createFixupURI(aArgument, 0);
111 catch (e) {
112 Components.utils.reportError(e);
115 return uri;
118 const OVERRIDE_NONE = 0;
119 const OVERRIDE_NEW_PROFILE = 1;
120 const OVERRIDE_NEW_MSTONE = 2;
121 const OVERRIDE_NEW_BUILD_ID = 3;
123 * Determines whether a home page override is needed.
124 * Returns:
125 * OVERRIDE_NEW_PROFILE if this is the first run with a new profile.
126 * OVERRIDE_NEW_MSTONE if this is the first run with a build with a different
127 * Gecko milestone (i.e. right after an upgrade).
128 * OVERRIDE_NEW_BUILD_ID if this is the first run with a new build ID of the
129 * same Gecko milestone (i.e. after a nightly upgrade).
130 * OVERRIDE_NONE otherwise.
132 function needHomepageOverride(prefb) {
133 var savedmstone = null;
134 try {
135 savedmstone = prefb.getCharPref("browser.startup.homepage_override.mstone");
136 } catch (e) {}
138 if (savedmstone == "ignore")
139 return OVERRIDE_NONE;
141 var mstone = Components.classes["@mozilla.org/network/protocol;1?name=http"]
142 .getService(nsIHttpProtocolHandler).misc;
144 var savedBuildID = null;
145 try {
146 savedBuildID = prefb.getCharPref("browser.startup.homepage_override.buildID");
147 } catch (e) {}
149 var buildID = Components.classes["@mozilla.org/xre/app-info;1"]
150 .getService(nsIXULAppInfo).platformBuildID;
152 if (mstone != savedmstone) {
153 // Bug 462254. Previous releases had a default pref to suppress the EULA
154 // agreement if the platform's installer had already shown one. Now with
155 // about:rights we've removed the EULA stuff and default pref, but we need
156 // a way to make existing profiles retain the default that we removed.
157 if (savedmstone)
158 prefb.setBoolPref("browser.rights.3.shown", true);
160 prefb.setCharPref("browser.startup.homepage_override.mstone", mstone);
161 prefb.setCharPref("browser.startup.homepage_override.buildID", buildID);
162 return (savedmstone ? OVERRIDE_NEW_MSTONE : OVERRIDE_NEW_PROFILE);
165 if (buildID != savedBuildID) {
166 prefb.setCharPref("browser.startup.homepage_override.buildID", buildID);
167 return OVERRIDE_NEW_BUILD_ID;
170 return OVERRIDE_NONE;
174 * Gets the override page for the first run after the application has been
175 * updated.
176 * @param defaultOverridePage
177 * The default override page.
178 * @return The override page.
180 function getPostUpdateOverridePage(defaultOverridePage) {
181 var um = Components.classes["@mozilla.org/updates/update-manager;1"]
182 .getService(Components.interfaces.nsIUpdateManager);
183 try {
184 // If the updates.xml file is deleted then getUpdateAt will throw.
185 var update = um.getUpdateAt(0)
186 .QueryInterface(Components.interfaces.nsIPropertyBag);
187 } catch (e) {
188 // This should never happen.
189 Components.utils.reportError("Unable to find update: " + e);
190 return defaultOverridePage;
193 let actions = update.getProperty("actions");
194 // When the update doesn't specify actions fallback to the original behavior
195 // of displaying the default override page.
196 if (!actions)
197 return defaultOverridePage;
199 // The existence of silent or the non-existence of showURL in the actions both
200 // mean that an override page should not be displayed.
201 if (actions.indexOf("silent") != -1 || actions.indexOf("showURL") == -1)
202 return "";
204 return update.getProperty("openURL") || defaultOverridePage;
207 // Copies a pref override file into the user's profile pref-override folder,
208 // and then tells the pref service to reload its default prefs.
209 function copyPrefOverride() {
210 try {
211 var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"]
212 .getService(Components.interfaces.nsIProperties);
213 const NS_APP_EXISTING_PREF_OVERRIDE = "ExistingPrefOverride";
214 var prefOverride = fileLocator.get(NS_APP_EXISTING_PREF_OVERRIDE,
215 Components.interfaces.nsIFile);
216 if (!prefOverride.exists())
217 return; // nothing to do
219 const NS_APP_PREFS_OVERRIDE_DIR = "PrefDOverride";
220 var prefOverridesDir = fileLocator.get(NS_APP_PREFS_OVERRIDE_DIR,
221 Components.interfaces.nsIFile);
223 // Check for any existing pref overrides, and remove them if present
224 var existingPrefOverridesFile = prefOverridesDir.clone();
225 existingPrefOverridesFile.append(prefOverride.leafName);
226 if (existingPrefOverridesFile.exists())
227 existingPrefOverridesFile.remove(false);
229 prefOverride.copyTo(prefOverridesDir, null);
231 // Now that we've installed the new-profile pref override file,
232 // re-read the default prefs.
233 var prefSvcObs = Components.classes["@mozilla.org/preferences-service;1"]
234 .getService(Components.interfaces.nsIObserver);
235 prefSvcObs.observe(null, "reload-default-prefs", null);
236 } catch (ex) {
237 Components.utils.reportError(ex);
241 // Flag used to indicate that the arguments to openWindow can be passed directly.
242 const NO_EXTERNAL_URIS = 1;
244 function openWindow(parent, url, target, features, args, noExternalArgs) {
245 var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
246 .getService(nsIWindowWatcher);
248 if (noExternalArgs == NO_EXTERNAL_URIS) {
249 // Just pass in the defaultArgs directly
250 var argstring;
251 if (args) {
252 argstring = Components.classes["@mozilla.org/supports-string;1"]
253 .createInstance(nsISupportsString);
254 argstring.data = args;
257 return wwatch.openWindow(parent, url, target, features, argstring);
260 // Pass an array to avoid the browser "|"-splitting behavior.
261 var argArray = Components.classes["@mozilla.org/supports-array;1"]
262 .createInstance(Components.interfaces.nsISupportsArray);
264 // add args to the arguments array
265 var stringArgs = null;
266 if (args instanceof Array) // array
267 stringArgs = args;
268 else if (args) // string
269 stringArgs = [args];
271 if (stringArgs) {
272 // put the URIs into argArray
273 var uriArray = Components.classes["@mozilla.org/supports-array;1"]
274 .createInstance(Components.interfaces.nsISupportsArray);
275 stringArgs.forEach(function (uri) {
276 var sstring = Components.classes["@mozilla.org/supports-string;1"]
277 .createInstance(nsISupportsString);
278 sstring.data = uri;
279 uriArray.AppendElement(sstring);
281 argArray.AppendElement(uriArray);
282 } else {
283 argArray.AppendElement(null);
286 // Pass these as null to ensure that we always trigger the "single URL"
287 // behavior in browser.js's BrowserStartup (which handles the window
288 // arguments)
289 argArray.AppendElement(null); // charset
290 argArray.AppendElement(null); // referer
291 argArray.AppendElement(null); // postData
292 argArray.AppendElement(null); // allowThirdPartyFixup
294 return wwatch.openWindow(parent, url, target, features, argArray);
297 function openPreferences() {
298 var features = "chrome,titlebar,toolbar,centerscreen,dialog=no";
299 var url = "chrome://browser/content/preferences/preferences.xul";
301 var win = getMostRecentWindow("Browser:Preferences");
302 if (win) {
303 win.focus();
304 } else {
305 openWindow(null, url, "_blank", features);
309 function getMostRecentWindow(aType) {
310 var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
311 .getService(nsIWindowMediator);
312 return wm.getMostRecentWindow(aType);
315 // this returns the most recent non-popup browser window
316 function getMostRecentBrowserWindow() {
317 var browserGlue = Components.classes["@mozilla.org/browser/browserglue;1"]
318 .getService(Components.interfaces.nsIBrowserGlue);
319 return browserGlue.getMostRecentBrowserWindow();
322 function doSearch(searchTerm, cmdLine) {
323 var ss = Components.classes["@mozilla.org/browser/search-service;1"]
324 .getService(nsIBrowserSearchService);
326 var submission = ss.defaultEngine.getSubmission(searchTerm);
328 // fill our nsISupportsArray with uri-as-wstring, null, null, postData
329 var sa = Components.classes["@mozilla.org/supports-array;1"]
330 .createInstance(Components.interfaces.nsISupportsArray);
332 var wuri = Components.classes["@mozilla.org/supports-string;1"]
333 .createInstance(Components.interfaces.nsISupportsString);
334 wuri.data = submission.uri.spec;
336 sa.AppendElement(wuri);
337 sa.AppendElement(null);
338 sa.AppendElement(null);
339 sa.AppendElement(submission.postData);
341 // XXXbsmedberg: use handURIToExistingBrowser to obey tabbed-browsing
342 // preferences, but need nsIBrowserDOMWindow extensions
344 var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
345 .getService(nsIWindowWatcher);
347 return wwatch.openWindow(null, gBrowserContentHandler.chromeURL,
348 "_blank",
349 "chrome,dialog=no,all" +
350 gBrowserContentHandler.getFeatures(cmdLine),
351 sa);
354 function nsBrowserContentHandler() {
356 nsBrowserContentHandler.prototype = {
357 classID: Components.ID("{5d0ce354-df01-421a-83fb-7ead0990c24e}"),
359 _xpcom_factory: {
360 createInstance: function bch_factory_ci(outer, iid) {
361 if (outer)
362 throw Components.results.NS_ERROR_NO_AGGREGATION;
363 return gBrowserContentHandler.QueryInterface(iid);
367 /* helper functions */
369 mChromeURL : null,
371 get chromeURL() {
372 if (this.mChromeURL) {
373 return this.mChromeURL;
376 var prefb = Components.classes["@mozilla.org/preferences-service;1"]
377 .getService(nsIPrefBranch);
378 this.mChromeURL = prefb.getCharPref("browser.chromeURL");
380 return this.mChromeURL;
383 /* nsISupports */
384 QueryInterface : XPCOMUtils.generateQI([nsICommandLineHandler,
385 nsIBrowserHandler,
386 nsIContentHandler,
387 nsICommandLineValidator]),
389 /* nsICommandLineHandler */
390 handle : function bch_handle(cmdLine) {
391 if (cmdLine.handleFlag("browser", false)) {
392 // Passing defaultArgs, so use NO_EXTERNAL_URIS
393 openWindow(null, this.chromeURL, "_blank",
394 "chrome,dialog=no,all" + this.getFeatures(cmdLine),
395 this.defaultArgs, NO_EXTERNAL_URIS);
396 cmdLine.preventDefault = true;
399 try {
400 var remoteCommand = cmdLine.handleFlagWithParam("remote", true);
402 catch (e) {
403 throw NS_ERROR_ABORT;
406 if (remoteCommand != null) {
407 try {
408 var a = /^\s*(\w+)\(([^\)]*)\)\s*$/.exec(remoteCommand);
409 var remoteVerb;
410 if (a) {
411 remoteVerb = a[1].toLowerCase();
412 var remoteParams = [];
413 var sepIndex = a[2].lastIndexOf(",");
414 if (sepIndex == -1)
415 remoteParams[0] = a[2];
416 else {
417 remoteParams[0] = a[2].substring(0, sepIndex);
418 remoteParams[1] = a[2].substring(sepIndex + 1);
422 switch (remoteVerb) {
423 case "openurl":
424 case "openfile":
425 // openURL(<url>)
426 // openURL(<url>,new-window)
427 // openURL(<url>,new-tab)
429 // First param is the URL, second param (if present) is the "target"
430 // (tab, window)
431 var url = remoteParams[0];
432 var target = nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW;
433 if (remoteParams[1]) {
434 var targetParam = remoteParams[1].toLowerCase()
435 .replace(/^\s*|\s*$/g, "");
436 if (targetParam == "new-tab")
437 target = nsIBrowserDOMWindow.OPEN_NEWTAB;
438 else if (targetParam == "new-window")
439 target = nsIBrowserDOMWindow.OPEN_NEWWINDOW;
440 else {
441 // The "target" param isn't one of our supported values, so
442 // assume it's part of a URL that contains commas.
443 url += "," + remoteParams[1];
447 var uri = resolveURIInternal(cmdLine, url);
448 handURIToExistingBrowser(uri, target, cmdLine);
449 break;
451 case "xfedocommand":
452 // xfeDoCommand(openBrowser)
453 if (remoteParams[0].toLowerCase() != "openbrowser")
454 throw NS_ERROR_ABORT;
456 // Passing defaultArgs, so use NO_EXTERNAL_URIS
457 openWindow(null, this.chromeURL, "_blank",
458 "chrome,dialog=no,all" + this.getFeatures(cmdLine),
459 this.defaultArgs, NO_EXTERNAL_URIS);
460 break;
462 default:
463 // Somebody sent us a remote command we don't know how to process:
464 // just abort.
465 throw "Unknown remote command.";
468 cmdLine.preventDefault = true;
470 catch (e) {
471 Components.utils.reportError(e);
472 // If we had a -remote flag but failed to process it, throw
473 // NS_ERROR_ABORT so that the xremote code knows to return a failure
474 // back to the handling code.
475 throw NS_ERROR_ABORT;
479 var uriparam;
480 try {
481 while ((uriparam = cmdLine.handleFlagWithParam("new-window", false))) {
482 var uri = resolveURIInternal(cmdLine, uriparam);
483 if (!shouldLoadURI(uri))
484 continue;
485 openWindow(null, this.chromeURL, "_blank",
486 "chrome,dialog=no,all" + this.getFeatures(cmdLine),
487 uri.spec);
488 cmdLine.preventDefault = true;
491 catch (e) {
492 Components.utils.reportError(e);
495 try {
496 while ((uriparam = cmdLine.handleFlagWithParam("new-tab", false))) {
497 var uri = resolveURIInternal(cmdLine, uriparam);
498 handURIToExistingBrowser(uri, nsIBrowserDOMWindow.OPEN_NEWTAB, cmdLine);
499 cmdLine.preventDefault = true;
502 catch (e) {
503 Components.utils.reportError(e);
506 var chromeParam = cmdLine.handleFlagWithParam("chrome", false);
507 if (chromeParam) {
509 // Handle the old preference dialog URL separately (bug 285416)
510 if (chromeParam == "chrome://browser/content/pref/pref.xul") {
511 openPreferences();
512 cmdLine.preventDefault = true;
513 } else try {
514 // only load URIs which do not inherit chrome privs
515 var features = "chrome,dialog=no,all" + this.getFeatures(cmdLine);
516 var uri = resolveURIInternal(cmdLine, chromeParam);
517 var netutil = Components.classes["@mozilla.org/network/util;1"]
518 .getService(nsINetUtil);
519 if (!netutil.URIChainHasFlags(uri, URI_INHERITS_SECURITY_CONTEXT)) {
520 openWindow(null, uri.spec, "_blank", features);
521 cmdLine.preventDefault = true;
524 catch (e) {
525 Components.utils.reportError(e);
528 if (cmdLine.handleFlag("preferences", false)) {
529 openPreferences();
530 cmdLine.preventDefault = true;
532 if (cmdLine.handleFlag("silent", false))
533 cmdLine.preventDefault = true;
534 if (cmdLine.findFlag("private-toggle", false) >= 0)
535 cmdLine.preventDefault = true;
537 var searchParam = cmdLine.handleFlagWithParam("search", false);
538 if (searchParam) {
539 doSearch(searchParam, cmdLine);
540 cmdLine.preventDefault = true;
543 var fileParam = cmdLine.handleFlagWithParam("file", false);
544 if (fileParam) {
545 var file = cmdLine.resolveFile(fileParam);
546 var ios = Components.classes["@mozilla.org/network/io-service;1"]
547 .getService(Components.interfaces.nsIIOService);
548 var uri = ios.newFileURI(file);
549 openWindow(null, this.chromeURL, "_blank",
550 "chrome,dialog=no,all" + this.getFeatures(cmdLine),
551 uri.spec);
552 cmdLine.preventDefault = true;
555 #ifdef XP_WIN
556 // Handle "? searchterm" for Windows Vista start menu integration
557 for (var i = cmdLine.length - 1; i >= 0; --i) {
558 var param = cmdLine.getArgument(i);
559 if (param.match(/^\? /)) {
560 cmdLine.removeArguments(i, i);
561 cmdLine.preventDefault = true;
563 searchParam = param.substr(2);
564 doSearch(searchParam, cmdLine);
567 #endif
570 helpInfo : " -browser Open a browser window.\n",
572 /* nsIBrowserHandler */
574 get defaultArgs() {
575 var prefb = Components.classes["@mozilla.org/preferences-service;1"]
576 .getService(nsIPrefBranch);
578 var overridePage = "";
579 var haveUpdateSession = false;
580 try {
581 let override = needHomepageOverride(prefb);
582 if (override != OVERRIDE_NONE) {
583 // Setup the default search engine to about:home page.
584 AboutHomeUtils.loadDefaultSearchEngine();
585 AboutHomeUtils.loadSnippetsURL();
587 switch (override) {
588 case OVERRIDE_NEW_PROFILE:
589 // New profile.
590 overridePage = Services.urlFormatter.formatURLPref("startup.homepage_welcome_url");
591 break;
592 case OVERRIDE_NEW_MSTONE:
593 // Existing profile, new milestone build.
594 copyPrefOverride();
596 // Check whether we have a session to restore. If we do, we assume
597 // that this is an "update" session.
598 var ss = Components.classes["@mozilla.org/browser/sessionstartup;1"]
599 .getService(Components.interfaces.nsISessionStartup);
600 haveUpdateSession = ss.doRestore();
601 overridePage = Services.urlFormatter.formatURLPref("startup.homepage_override_url");
602 if (prefb.prefHasUserValue("app.update.postupdate"))
603 overridePage = getPostUpdateOverridePage(overridePage);
604 break;
607 else {
608 // No need to override homepage, but update snippets url if the pref has
609 // been manually changed.
610 if (Services.prefs.prefHasUserValue(AboutHomeUtils.SNIPPETS_URL_PREF)) {
611 AboutHomeUtils.loadSnippetsURL();
614 } catch (ex) {}
616 // formatURLPref might return "about:blank" if getting the pref fails
617 if (overridePage == "about:blank")
618 overridePage = "";
620 var startPage = "";
621 try {
622 var choice = prefb.getIntPref("browser.startup.page");
623 if (choice == 1 || choice == 3)
624 startPage = this.startPage;
626 if (choice == 2)
627 startPage = Components.classes["@mozilla.org/browser/global-history;2"]
628 .getService(nsIBrowserHistory).lastPageVisited;
629 } catch (e) {
630 Components.utils.reportError(e);
633 if (startPage == "about:blank")
634 startPage = "";
636 // Only show the startPage if we're not restoring an update session.
637 if (overridePage && startPage && !haveUpdateSession)
638 return overridePage + "|" + startPage;
640 return overridePage || startPage || "about:blank";
643 get startPage() {
644 var prefb = Components.classes["@mozilla.org/preferences-service;1"]
645 .getService(nsIPrefBranch);
647 var uri = prefb.getComplexValue("browser.startup.homepage",
648 nsIPrefLocalizedString).data;
650 if (!uri) {
651 prefb.clearUserPref("browser.startup.homepage");
652 uri = prefb.getComplexValue("browser.startup.homepage",
653 nsIPrefLocalizedString).data;
656 var count;
657 try {
658 count = prefb.getIntPref("browser.startup.homepage.count");
660 catch (e) {
661 return uri;
664 for (var i = 1; i < count; ++i) {
665 try {
666 var page = prefb.getComplexValue("browser.startup.homepage." + i,
667 nsIPrefLocalizedString).data;
668 uri += "\n" + page;
670 catch (e) {
674 return uri;
677 mFeatures : null,
679 getFeatures : function bch_features(cmdLine) {
680 if (this.mFeatures === null) {
681 this.mFeatures = "";
683 try {
684 var width = cmdLine.handleFlagWithParam("width", false);
685 var height = cmdLine.handleFlagWithParam("height", false);
687 if (width)
688 this.mFeatures += ",width=" + width;
689 if (height)
690 this.mFeatures += ",height=" + height;
692 catch (e) {
696 return this.mFeatures;
699 /* nsIContentHandler */
701 handleContent : function bch_handleContent(contentType, context, request) {
702 try {
703 var webNavInfo = Components.classes["@mozilla.org/webnavigation-info;1"]
704 .getService(nsIWebNavigationInfo);
705 if (!webNavInfo.isTypeSupported(contentType, null)) {
706 throw NS_ERROR_WONT_HANDLE_CONTENT;
708 } catch (e) {
709 throw NS_ERROR_WONT_HANDLE_CONTENT;
712 request.QueryInterface(nsIChannel);
713 handURIToExistingBrowser(request.URI,
714 nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, null);
715 request.cancel(NS_BINDING_ABORTED);
718 /* nsICommandLineValidator */
719 validate : function bch_validate(cmdLine) {
720 // Other handlers may use osint so only handle the osint flag if the url
721 // flag is also present and the command line is valid.
722 var osintFlagIdx = cmdLine.findFlag("osint", false);
723 var urlFlagIdx = cmdLine.findFlag("url", false);
724 if (urlFlagIdx > -1 && (osintFlagIdx > -1 ||
725 cmdLine.state == nsICommandLine.STATE_REMOTE_EXPLICIT)) {
726 var urlParam = cmdLine.getArgument(urlFlagIdx + 1);
727 if (cmdLine.length != urlFlagIdx + 2 || /firefoxurl:/.test(urlParam))
728 throw NS_ERROR_ABORT;
729 cmdLine.handleFlag("osint", false)
733 var gBrowserContentHandler = new nsBrowserContentHandler();
735 const CONTRACTID_PREFIX = "@mozilla.org/uriloader/content-handler;1?type=";
737 function handURIToExistingBrowser(uri, location, cmdLine)
739 if (!shouldLoadURI(uri))
740 return;
742 var navWin = getMostRecentBrowserWindow();
743 if (!navWin) {
744 // if we couldn't load it in an existing window, open a new one
745 openWindow(null, gBrowserContentHandler.chromeURL, "_blank",
746 "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine),
747 uri.spec);
748 return;
751 var navNav = navWin.QueryInterface(nsIInterfaceRequestor)
752 .getInterface(nsIWebNavigation);
753 var rootItem = navNav.QueryInterface(nsIDocShellTreeItem).rootTreeItem;
754 var rootWin = rootItem.QueryInterface(nsIInterfaceRequestor)
755 .getInterface(nsIDOMWindow);
756 var bwin = rootWin.QueryInterface(nsIDOMChromeWindow).browserDOMWindow;
757 bwin.openURI(uri, null, location,
758 nsIBrowserDOMWindow.OPEN_EXTERNAL);
761 function nsDefaultCommandLineHandler() {
764 nsDefaultCommandLineHandler.prototype = {
765 classID: Components.ID("{47cd0651-b1be-4a0f-b5c4-10e5a573ef71}"),
767 /* nsISupports */
768 QueryInterface : function dch_QI(iid) {
769 if (!iid.equals(nsISupports) &&
770 !iid.equals(nsICommandLineHandler))
771 throw Components.results.NS_ERROR_NO_INTERFACE;
773 return this;
776 // List of uri's that were passed via the command line without the app
777 // running and have already been handled. This is compared against uri's
778 // opened using DDE on Win32 so we only open one of the requests.
779 _handledURIs: [ ],
780 #ifdef XP_WIN
781 _haveProfile: false,
782 #endif
784 /* nsICommandLineHandler */
785 handle : function dch_handle(cmdLine) {
786 var urilist = [];
788 #ifdef XP_WIN
789 // If we don't have a profile selected yet (e.g. the Profile Manager is
790 // displayed) we will crash if we open an url and then select a profile. To
791 // prevent this handle all url command line flags and set the command line's
792 // preventDefault to true to prevent the display of the ui. The initial
793 // command line will be retained when nsAppRunner calls LaunchChild though
794 // urls launched after the initial launch will be lost.
795 if (!this._haveProfile) {
796 try {
797 // This will throw when a profile has not been selected.
798 var fl = Components.classes["@mozilla.org/file/directory_service;1"]
799 .getService(Components.interfaces.nsIProperties);
800 var dir = fl.get("ProfD", Components.interfaces.nsILocalFile);
801 this._haveProfile = true;
803 catch (e) {
804 while ((ar = cmdLine.handleFlagWithParam("url", false))) { }
805 cmdLine.preventDefault = true;
808 #endif
810 try {
811 var ar;
812 while ((ar = cmdLine.handleFlagWithParam("url", false))) {
813 var found = false;
814 var uri = resolveURIInternal(cmdLine, ar);
815 // count will never be greater than zero except on Win32.
816 var count = this._handledURIs.length;
817 for (var i = 0; i < count; ++i) {
818 if (this._handledURIs[i].spec == uri.spec) {
819 this._handledURIs.splice(i, 1);
820 found = true;
821 cmdLine.preventDefault = true;
822 break;
825 if (!found) {
826 urilist.push(uri);
827 // The requestpending command line flag is only used on Win32.
828 if (cmdLine.handleFlag("requestpending", false) &&
829 cmdLine.state == nsICommandLine.STATE_INITIAL_LAUNCH)
830 this._handledURIs.push(uri)
834 catch (e) {
835 Components.utils.reportError(e);
838 count = cmdLine.length;
840 for (i = 0; i < count; ++i) {
841 var curarg = cmdLine.getArgument(i);
842 if (curarg.match(/^-/)) {
843 Components.utils.reportError("Warning: unrecognized command line flag " + curarg + "\n");
844 // To emulate the pre-nsICommandLine behavior, we ignore
845 // the argument after an unrecognized flag.
846 ++i;
847 } else {
848 try {
849 urilist.push(resolveURIInternal(cmdLine, curarg));
851 catch (e) {
852 Components.utils.reportError("Error opening URI '" + curarg + "' from the command line: " + e + "\n");
857 if (urilist.length) {
858 if (cmdLine.state != nsICommandLine.STATE_INITIAL_LAUNCH &&
859 urilist.length == 1) {
860 // Try to find an existing window and load our URI into the
861 // current tab, new tab, or new window as prefs determine.
862 try {
863 handURIToExistingBrowser(urilist[0], nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, cmdLine);
864 return;
866 catch (e) {
870 var URLlist = urilist.filter(shouldLoadURI).map(function (u) u.spec);
871 if (URLlist.length) {
872 openWindow(null, gBrowserContentHandler.chromeURL, "_blank",
873 "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine),
874 URLlist);
878 else if (!cmdLine.preventDefault) {
879 // Passing defaultArgs, so use NO_EXTERNAL_URIS
880 openWindow(null, gBrowserContentHandler.chromeURL, "_blank",
881 "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine),
882 gBrowserContentHandler.defaultArgs, NO_EXTERNAL_URIS);
886 helpInfo : "",
889 let AboutHomeUtils = {
890 SNIPPETS_URL_PREF: "browser.aboutHomeSnippets.updateUrl",
891 get _storage() {
892 let aboutHomeURI = Services.io.newURI("moz-safe-about:home", null, null);
893 let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"].
894 getService(Components.interfaces.nsIScriptSecurityManager).
895 getCodebasePrincipal(aboutHomeURI);
896 let dsm = Components.classes["@mozilla.org/dom/storagemanager;1"].
897 getService(Components.interfaces.nsIDOMStorageManager);
898 return dsm.getLocalStorageForPrincipal(principal, "");
901 loadDefaultSearchEngine: function AHU_loadDefaultSearchEngine()
903 let defaultEngine = Services.search.originalDefaultEngine;
904 let submission = defaultEngine.getSubmission("_searchTerms_");
905 if (submission.postData)
906 throw new Error("Home page does not support POST search engines.");
907 let engine = {
908 name: defaultEngine.name
909 , searchUrl: submission.uri.spec
911 this._storage.setItem("search-engine", JSON.stringify(engine));
914 loadSnippetsURL: function AHU_loadSnippetsURL()
916 const STARTPAGE_VERSION = 1;
917 let updateURL = Services.prefs
918 .getCharPref(this.SNIPPETS_URL_PREF)
919 .replace("%STARTPAGE_VERSION%", STARTPAGE_VERSION);
920 updateURL = Services.urlFormatter.formatURL(updateURL);
921 this._storage.setItem("snippets-update-url", updateURL);
925 var components = [nsBrowserContentHandler, nsDefaultCommandLineHandler];
926 var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);