michael@0: # This Source Code Form is subject to the terms of the Mozilla Public michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: # file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: michael@0: Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Components.utils.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", michael@0: "resource://gre/modules/PrivateBrowsingUtils.jsm"); michael@0: XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow", michael@0: "resource:///modules/RecentWindow.jsm"); michael@0: michael@0: const nsISupports = Components.interfaces.nsISupports; michael@0: michael@0: const nsIBrowserDOMWindow = Components.interfaces.nsIBrowserDOMWindow; michael@0: const nsIBrowserHandler = Components.interfaces.nsIBrowserHandler; michael@0: const nsIBrowserHistory = Components.interfaces.nsIBrowserHistory; michael@0: const nsIChannel = Components.interfaces.nsIChannel; michael@0: const nsICommandLine = Components.interfaces.nsICommandLine; michael@0: const nsICommandLineHandler = Components.interfaces.nsICommandLineHandler; michael@0: const nsIContentHandler = Components.interfaces.nsIContentHandler; michael@0: const nsIDocShellTreeItem = Components.interfaces.nsIDocShellTreeItem; michael@0: const nsIDOMChromeWindow = Components.interfaces.nsIDOMChromeWindow; michael@0: const nsIDOMWindow = Components.interfaces.nsIDOMWindow; michael@0: const nsIFileURL = Components.interfaces.nsIFileURL; michael@0: const nsIInterfaceRequestor = Components.interfaces.nsIInterfaceRequestor; michael@0: const nsINetUtil = Components.interfaces.nsINetUtil; michael@0: const nsIPrefBranch = Components.interfaces.nsIPrefBranch; michael@0: const nsIPrefLocalizedString = Components.interfaces.nsIPrefLocalizedString; michael@0: const nsISupportsString = Components.interfaces.nsISupportsString; michael@0: const nsIURIFixup = Components.interfaces.nsIURIFixup; michael@0: const nsIWebNavigation = Components.interfaces.nsIWebNavigation; michael@0: const nsIWindowMediator = Components.interfaces.nsIWindowMediator; michael@0: const nsIWindowWatcher = Components.interfaces.nsIWindowWatcher; michael@0: const nsIWebNavigationInfo = Components.interfaces.nsIWebNavigationInfo; michael@0: const nsIBrowserSearchService = Components.interfaces.nsIBrowserSearchService; michael@0: const nsICommandLineValidator = Components.interfaces.nsICommandLineValidator; michael@0: michael@0: const NS_BINDING_ABORTED = Components.results.NS_BINDING_ABORTED; michael@0: const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001; michael@0: const NS_ERROR_ABORT = Components.results.NS_ERROR_ABORT; michael@0: michael@0: const URI_INHERITS_SECURITY_CONTEXT = Components.interfaces.nsIHttpProtocolHandler michael@0: .URI_INHERITS_SECURITY_CONTEXT; michael@0: michael@0: function shouldLoadURI(aURI) { michael@0: if (aURI && !aURI.schemeIs("chrome")) michael@0: return true; michael@0: michael@0: dump("*** Preventing external load of chrome: URI into browser window\n"); michael@0: dump(" Use -chrome instead\n"); michael@0: return false; michael@0: } michael@0: michael@0: function resolveURIInternal(aCmdLine, aArgument) { michael@0: var uri = aCmdLine.resolveURI(aArgument); michael@0: var urifixup = Components.classes["@mozilla.org/docshell/urifixup;1"] michael@0: .getService(nsIURIFixup); michael@0: michael@0: if (!(uri instanceof nsIFileURL)) { michael@0: return urifixup.createFixupURI(aArgument, michael@0: urifixup.FIXUP_FLAG_FIX_SCHEME_TYPOS); michael@0: } michael@0: michael@0: try { michael@0: if (uri.file.exists()) michael@0: return uri; michael@0: } michael@0: catch (e) { michael@0: Components.utils.reportError(e); michael@0: } michael@0: michael@0: // We have interpreted the argument as a relative file URI, but the file michael@0: // doesn't exist. Try URI fixup heuristics: see bug 290782. michael@0: michael@0: try { michael@0: uri = urifixup.createFixupURI(aArgument, 0); michael@0: } michael@0: catch (e) { michael@0: Components.utils.reportError(e); michael@0: } michael@0: michael@0: return uri; michael@0: } michael@0: michael@0: var gFirstWindow = false; michael@0: michael@0: const OVERRIDE_NONE = 0; michael@0: const OVERRIDE_NEW_PROFILE = 1; michael@0: const OVERRIDE_NEW_MSTONE = 2; michael@0: const OVERRIDE_NEW_BUILD_ID = 3; michael@0: /** michael@0: * Determines whether a home page override is needed. michael@0: * Returns: michael@0: * OVERRIDE_NEW_PROFILE if this is the first run with a new profile. michael@0: * OVERRIDE_NEW_MSTONE if this is the first run with a build with a different michael@0: * Gecko milestone (i.e. right after an upgrade). michael@0: * OVERRIDE_NEW_BUILD_ID if this is the first run with a new build ID of the michael@0: * same Gecko milestone (i.e. after a nightly upgrade). michael@0: * OVERRIDE_NONE otherwise. michael@0: */ michael@0: function needHomepageOverride(prefb) { michael@0: var savedmstone = null; michael@0: try { michael@0: savedmstone = prefb.getCharPref("browser.startup.homepage_override.mstone"); michael@0: } catch (e) {} michael@0: michael@0: if (savedmstone == "ignore") michael@0: return OVERRIDE_NONE; michael@0: michael@0: var mstone = Services.appinfo.platformVersion; michael@0: michael@0: var savedBuildID = null; michael@0: try { michael@0: savedBuildID = prefb.getCharPref("browser.startup.homepage_override.buildID"); michael@0: } catch (e) {} michael@0: michael@0: var buildID = Services.appinfo.platformBuildID; michael@0: michael@0: if (mstone != savedmstone) { michael@0: // Bug 462254. Previous releases had a default pref to suppress the EULA michael@0: // agreement if the platform's installer had already shown one. Now with michael@0: // about:rights we've removed the EULA stuff and default pref, but we need michael@0: // a way to make existing profiles retain the default that we removed. michael@0: if (savedmstone) michael@0: prefb.setBoolPref("browser.rights.3.shown", true); michael@0: michael@0: prefb.setCharPref("browser.startup.homepage_override.mstone", mstone); michael@0: prefb.setCharPref("browser.startup.homepage_override.buildID", buildID); michael@0: return (savedmstone ? OVERRIDE_NEW_MSTONE : OVERRIDE_NEW_PROFILE); michael@0: } michael@0: michael@0: if (buildID != savedBuildID) { michael@0: prefb.setCharPref("browser.startup.homepage_override.buildID", buildID); michael@0: return OVERRIDE_NEW_BUILD_ID; michael@0: } michael@0: michael@0: return OVERRIDE_NONE; michael@0: } michael@0: michael@0: /** michael@0: * Gets the override page for the first run after the application has been michael@0: * updated. michael@0: * @param defaultOverridePage michael@0: * The default override page. michael@0: * @return The override page. michael@0: */ michael@0: function getPostUpdateOverridePage(defaultOverridePage) { michael@0: var um = Components.classes["@mozilla.org/updates/update-manager;1"] michael@0: .getService(Components.interfaces.nsIUpdateManager); michael@0: try { michael@0: // If the updates.xml file is deleted then getUpdateAt will throw. michael@0: var update = um.getUpdateAt(0) michael@0: .QueryInterface(Components.interfaces.nsIPropertyBag); michael@0: } catch (e) { michael@0: // This should never happen. michael@0: Components.utils.reportError("Unable to find update: " + e); michael@0: return defaultOverridePage; michael@0: } michael@0: michael@0: let actions = update.getProperty("actions"); michael@0: // When the update doesn't specify actions fallback to the original behavior michael@0: // of displaying the default override page. michael@0: if (!actions) michael@0: return defaultOverridePage; michael@0: michael@0: // The existence of silent or the non-existence of showURL in the actions both michael@0: // mean that an override page should not be displayed. michael@0: if (actions.indexOf("silent") != -1 || actions.indexOf("showURL") == -1) michael@0: return ""; michael@0: michael@0: return update.getProperty("openURL") || defaultOverridePage; michael@0: } michael@0: michael@0: // Flag used to indicate that the arguments to openWindow can be passed directly. michael@0: const NO_EXTERNAL_URIS = 1; michael@0: michael@0: function openWindow(parent, url, target, features, args, noExternalArgs) { michael@0: var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] michael@0: .getService(nsIWindowWatcher); michael@0: michael@0: if (noExternalArgs == NO_EXTERNAL_URIS) { michael@0: // Just pass in the defaultArgs directly michael@0: var argstring; michael@0: if (args) { michael@0: argstring = Components.classes["@mozilla.org/supports-string;1"] michael@0: .createInstance(nsISupportsString); michael@0: argstring.data = args; michael@0: } michael@0: michael@0: return wwatch.openWindow(parent, url, target, features, argstring); michael@0: } michael@0: michael@0: // Pass an array to avoid the browser "|"-splitting behavior. michael@0: var argArray = Components.classes["@mozilla.org/supports-array;1"] michael@0: .createInstance(Components.interfaces.nsISupportsArray); michael@0: michael@0: // add args to the arguments array michael@0: var stringArgs = null; michael@0: if (args instanceof Array) // array michael@0: stringArgs = args; michael@0: else if (args) // string michael@0: stringArgs = [args]; michael@0: michael@0: if (stringArgs) { michael@0: // put the URIs into argArray michael@0: var uriArray = Components.classes["@mozilla.org/supports-array;1"] michael@0: .createInstance(Components.interfaces.nsISupportsArray); michael@0: stringArgs.forEach(function (uri) { michael@0: var sstring = Components.classes["@mozilla.org/supports-string;1"] michael@0: .createInstance(nsISupportsString); michael@0: sstring.data = uri; michael@0: uriArray.AppendElement(sstring); michael@0: }); michael@0: argArray.AppendElement(uriArray); michael@0: } else { michael@0: argArray.AppendElement(null); michael@0: } michael@0: michael@0: // Pass these as null to ensure that we always trigger the "single URL" michael@0: // behavior in browser.js's gBrowserInit.onLoad (which handles the window michael@0: // arguments) michael@0: argArray.AppendElement(null); // charset michael@0: argArray.AppendElement(null); // referer michael@0: argArray.AppendElement(null); // postData michael@0: argArray.AppendElement(null); // allowThirdPartyFixup michael@0: michael@0: return wwatch.openWindow(parent, url, target, features, argArray); michael@0: } michael@0: michael@0: function openPreferences() { michael@0: if (Services.prefs.getBoolPref("browser.preferences.inContent")) { michael@0: var sa = Components.classes["@mozilla.org/supports-array;1"] michael@0: .createInstance(Components.interfaces.nsISupportsArray); michael@0: michael@0: var wuri = Components.classes["@mozilla.org/supports-string;1"] michael@0: .createInstance(Components.interfaces.nsISupportsString); michael@0: wuri.data = "about:preferences"; michael@0: michael@0: sa.AppendElement(wuri); michael@0: michael@0: var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] michael@0: .getService(nsIWindowWatcher); michael@0: michael@0: wwatch.openWindow(null, gBrowserContentHandler.chromeURL, michael@0: "_blank", michael@0: "chrome,dialog=no,all", michael@0: sa); michael@0: } else { michael@0: var features = "chrome,titlebar,toolbar,centerscreen,dialog=no"; michael@0: var url = "chrome://browser/content/preferences/preferences.xul"; michael@0: michael@0: var win = getMostRecentWindow("Browser:Preferences"); michael@0: if (win) { michael@0: win.focus(); michael@0: } else { michael@0: openWindow(null, url, "_blank", features); michael@0: } michael@0: } michael@0: } michael@0: michael@0: function getMostRecentWindow(aType) { michael@0: var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] michael@0: .getService(nsIWindowMediator); michael@0: return wm.getMostRecentWindow(aType); michael@0: } michael@0: michael@0: function doSearch(searchTerm, cmdLine) { michael@0: var ss = Components.classes["@mozilla.org/browser/search-service;1"] michael@0: .getService(nsIBrowserSearchService); michael@0: michael@0: var submission = ss.defaultEngine.getSubmission(searchTerm); michael@0: michael@0: // fill our nsISupportsArray with uri-as-wstring, null, null, postData michael@0: var sa = Components.classes["@mozilla.org/supports-array;1"] michael@0: .createInstance(Components.interfaces.nsISupportsArray); michael@0: michael@0: var wuri = Components.classes["@mozilla.org/supports-string;1"] michael@0: .createInstance(Components.interfaces.nsISupportsString); michael@0: wuri.data = submission.uri.spec; michael@0: michael@0: sa.AppendElement(wuri); michael@0: sa.AppendElement(null); michael@0: sa.AppendElement(null); michael@0: sa.AppendElement(submission.postData); michael@0: michael@0: // XXXbsmedberg: use handURIToExistingBrowser to obey tabbed-browsing michael@0: // preferences, but need nsIBrowserDOMWindow extensions michael@0: michael@0: var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] michael@0: .getService(nsIWindowWatcher); michael@0: michael@0: return wwatch.openWindow(null, gBrowserContentHandler.chromeURL, michael@0: "_blank", michael@0: "chrome,dialog=no,all" + michael@0: gBrowserContentHandler.getFeatures(cmdLine), michael@0: sa); michael@0: } michael@0: michael@0: function nsBrowserContentHandler() { michael@0: } michael@0: nsBrowserContentHandler.prototype = { michael@0: classID: Components.ID("{5d0ce354-df01-421a-83fb-7ead0990c24e}"), michael@0: michael@0: _xpcom_factory: { michael@0: createInstance: function bch_factory_ci(outer, iid) { michael@0: if (outer) michael@0: throw Components.results.NS_ERROR_NO_AGGREGATION; michael@0: return gBrowserContentHandler.QueryInterface(iid); michael@0: } michael@0: }, michael@0: michael@0: /* helper functions */ michael@0: michael@0: mChromeURL : null, michael@0: michael@0: get chromeURL() { michael@0: if (this.mChromeURL) { michael@0: return this.mChromeURL; michael@0: } michael@0: michael@0: var prefb = Components.classes["@mozilla.org/preferences-service;1"] michael@0: .getService(nsIPrefBranch); michael@0: this.mChromeURL = prefb.getCharPref("browser.chromeURL"); michael@0: michael@0: return this.mChromeURL; michael@0: }, michael@0: michael@0: /* nsISupports */ michael@0: QueryInterface : XPCOMUtils.generateQI([nsICommandLineHandler, michael@0: nsIBrowserHandler, michael@0: nsIContentHandler, michael@0: nsICommandLineValidator]), michael@0: michael@0: /* nsICommandLineHandler */ michael@0: handle : function bch_handle(cmdLine) { michael@0: if (cmdLine.handleFlag("browser", false)) { michael@0: // Passing defaultArgs, so use NO_EXTERNAL_URIS michael@0: openWindow(null, this.chromeURL, "_blank", michael@0: "chrome,dialog=no,all" + this.getFeatures(cmdLine), michael@0: this.defaultArgs, NO_EXTERNAL_URIS); michael@0: cmdLine.preventDefault = true; michael@0: } michael@0: michael@0: try { michael@0: var remoteCommand = cmdLine.handleFlagWithParam("remote", true); michael@0: } michael@0: catch (e) { michael@0: throw NS_ERROR_ABORT; michael@0: } michael@0: michael@0: if (remoteCommand != null) { michael@0: try { michael@0: var a = /^\s*(\w+)\(([^\)]*)\)\s*$/.exec(remoteCommand); michael@0: var remoteVerb; michael@0: if (a) { michael@0: remoteVerb = a[1].toLowerCase(); michael@0: var remoteParams = []; michael@0: var sepIndex = a[2].lastIndexOf(","); michael@0: if (sepIndex == -1) michael@0: remoteParams[0] = a[2]; michael@0: else { michael@0: remoteParams[0] = a[2].substring(0, sepIndex); michael@0: remoteParams[1] = a[2].substring(sepIndex + 1); michael@0: } michael@0: } michael@0: michael@0: switch (remoteVerb) { michael@0: case "openurl": michael@0: case "openfile": michael@0: // openURL() michael@0: // openURL(,new-window) michael@0: // openURL(,new-tab) michael@0: michael@0: // First param is the URL, second param (if present) is the "target" michael@0: // (tab, window) michael@0: var url = remoteParams[0]; michael@0: var target = nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW; michael@0: if (remoteParams[1]) { michael@0: var targetParam = remoteParams[1].toLowerCase() michael@0: .replace(/^\s*|\s*$/g, ""); michael@0: if (targetParam == "new-tab") michael@0: target = nsIBrowserDOMWindow.OPEN_NEWTAB; michael@0: else if (targetParam == "new-window") michael@0: target = nsIBrowserDOMWindow.OPEN_NEWWINDOW; michael@0: else { michael@0: // The "target" param isn't one of our supported values, so michael@0: // assume it's part of a URL that contains commas. michael@0: url += "," + remoteParams[1]; michael@0: } michael@0: } michael@0: michael@0: var uri = resolveURIInternal(cmdLine, url); michael@0: handURIToExistingBrowser(uri, target, cmdLine); michael@0: break; michael@0: michael@0: case "xfedocommand": michael@0: // xfeDoCommand(openBrowser) michael@0: if (remoteParams[0].toLowerCase() != "openbrowser") michael@0: throw NS_ERROR_ABORT; michael@0: michael@0: // Passing defaultArgs, so use NO_EXTERNAL_URIS michael@0: openWindow(null, this.chromeURL, "_blank", michael@0: "chrome,dialog=no,all" + this.getFeatures(cmdLine), michael@0: this.defaultArgs, NO_EXTERNAL_URIS); michael@0: break; michael@0: michael@0: default: michael@0: // Somebody sent us a remote command we don't know how to process: michael@0: // just abort. michael@0: throw "Unknown remote command."; michael@0: } michael@0: michael@0: cmdLine.preventDefault = true; michael@0: } michael@0: catch (e) { michael@0: Components.utils.reportError(e); michael@0: // If we had a -remote flag but failed to process it, throw michael@0: // NS_ERROR_ABORT so that the xremote code knows to return a failure michael@0: // back to the handling code. michael@0: throw NS_ERROR_ABORT; michael@0: } michael@0: } michael@0: michael@0: var uriparam; michael@0: try { michael@0: while ((uriparam = cmdLine.handleFlagWithParam("new-window", false))) { michael@0: var uri = resolveURIInternal(cmdLine, uriparam); michael@0: if (!shouldLoadURI(uri)) michael@0: continue; michael@0: openWindow(null, this.chromeURL, "_blank", michael@0: "chrome,dialog=no,all" + this.getFeatures(cmdLine), michael@0: uri.spec); michael@0: cmdLine.preventDefault = true; michael@0: } michael@0: } michael@0: catch (e) { michael@0: Components.utils.reportError(e); michael@0: } michael@0: michael@0: try { michael@0: while ((uriparam = cmdLine.handleFlagWithParam("new-tab", false))) { michael@0: var uri = resolveURIInternal(cmdLine, uriparam); michael@0: handURIToExistingBrowser(uri, nsIBrowserDOMWindow.OPEN_NEWTAB, cmdLine); michael@0: cmdLine.preventDefault = true; michael@0: } michael@0: } michael@0: catch (e) { michael@0: Components.utils.reportError(e); michael@0: } michael@0: michael@0: var chromeParam = cmdLine.handleFlagWithParam("chrome", false); michael@0: if (chromeParam) { michael@0: michael@0: // Handle old preference dialog URLs. michael@0: if (chromeParam == "chrome://browser/content/pref/pref.xul" || michael@0: (Services.prefs.getBoolPref("browser.preferences.inContent") && michael@0: chromeParam == "chrome://browser/content/preferences/preferences.xul")) { michael@0: openPreferences(); michael@0: cmdLine.preventDefault = true; michael@0: } else try { michael@0: // only load URIs which do not inherit chrome privs michael@0: var features = "chrome,dialog=no,all" + this.getFeatures(cmdLine); michael@0: var uri = resolveURIInternal(cmdLine, chromeParam); michael@0: var netutil = Components.classes["@mozilla.org/network/util;1"] michael@0: .getService(nsINetUtil); michael@0: if (!netutil.URIChainHasFlags(uri, URI_INHERITS_SECURITY_CONTEXT)) { michael@0: openWindow(null, uri.spec, "_blank", features); michael@0: cmdLine.preventDefault = true; michael@0: } michael@0: } michael@0: catch (e) { michael@0: Components.utils.reportError(e); michael@0: } michael@0: } michael@0: if (cmdLine.handleFlag("preferences", false)) { michael@0: openPreferences(); michael@0: cmdLine.preventDefault = true; michael@0: } michael@0: if (cmdLine.handleFlag("silent", false)) michael@0: cmdLine.preventDefault = true; michael@0: michael@0: try { michael@0: var privateWindowParam = cmdLine.handleFlagWithParam("private-window", false); michael@0: if (privateWindowParam) { michael@0: var uri = resolveURIInternal(cmdLine, privateWindowParam); michael@0: handURIToExistingBrowser(uri, nsIBrowserDOMWindow.OPEN_NEWTAB, cmdLine, true); michael@0: cmdLine.preventDefault = true; michael@0: } michael@0: } catch (e if e.result == Components.results.NS_ERROR_INVALID_ARG) { michael@0: // NS_ERROR_INVALID_ARG is thrown when flag exists, but has no param. michael@0: if (cmdLine.handleFlag("private-window", false)) { michael@0: openWindow(null, this.chromeURL, "_blank", michael@0: "chrome,dialog=no,private,all" + this.getFeatures(cmdLine), michael@0: "about:privatebrowsing"); michael@0: cmdLine.preventDefault = true; michael@0: } michael@0: } michael@0: michael@0: var searchParam = cmdLine.handleFlagWithParam("search", false); michael@0: if (searchParam) { michael@0: doSearch(searchParam, cmdLine); michael@0: cmdLine.preventDefault = true; michael@0: } michael@0: michael@0: // The global PB Service consumes this flag, so only eat it in per-window michael@0: // PB builds. michael@0: if (cmdLine.handleFlag("private", false)) { michael@0: PrivateBrowsingUtils.enterTemporaryAutoStartMode(); michael@0: } michael@0: michael@0: var fileParam = cmdLine.handleFlagWithParam("file", false); michael@0: if (fileParam) { michael@0: var file = cmdLine.resolveFile(fileParam); michael@0: var ios = Components.classes["@mozilla.org/network/io-service;1"] michael@0: .getService(Components.interfaces.nsIIOService); michael@0: var uri = ios.newFileURI(file); michael@0: openWindow(null, this.chromeURL, "_blank", michael@0: "chrome,dialog=no,all" + this.getFeatures(cmdLine), michael@0: uri.spec); michael@0: cmdLine.preventDefault = true; michael@0: } michael@0: michael@0: #ifdef XP_WIN michael@0: // Handle "? searchterm" for Windows Vista start menu integration michael@0: for (var i = cmdLine.length - 1; i >= 0; --i) { michael@0: var param = cmdLine.getArgument(i); michael@0: if (param.match(/^\? /)) { michael@0: cmdLine.removeArguments(i, i); michael@0: cmdLine.preventDefault = true; michael@0: michael@0: searchParam = param.substr(2); michael@0: doSearch(searchParam, cmdLine); michael@0: } michael@0: } michael@0: #endif michael@0: }, michael@0: michael@0: helpInfo : " -browser Open a browser window.\n" + michael@0: " -new-window Open in a new window.\n" + michael@0: " -new-tab Open in a new tab.\n" + michael@0: #ifdef XP_WIN michael@0: " -preferences Open Options dialog.\n" + michael@0: #else michael@0: " -preferences Open Preferences dialog.\n" + michael@0: #endif michael@0: " -search Search with your default search engine.\n", michael@0: michael@0: /* nsIBrowserHandler */ michael@0: michael@0: get defaultArgs() { michael@0: var prefb = Components.classes["@mozilla.org/preferences-service;1"] michael@0: .getService(nsIPrefBranch); michael@0: michael@0: if (!gFirstWindow) { michael@0: gFirstWindow = true; michael@0: if (PrivateBrowsingUtils.isInTemporaryAutoStartMode) { michael@0: return "about:privatebrowsing"; michael@0: } michael@0: } michael@0: michael@0: var overridePage = ""; michael@0: var willRestoreSession = false; michael@0: try { michael@0: // Read the old value of homepage_override.mstone before michael@0: // needHomepageOverride updates it, so that we can later add it to the michael@0: // URL if we do end up showing an overridePage. This makes it possible michael@0: // to have the overridePage's content vary depending on the version we're michael@0: // upgrading from. michael@0: let old_mstone = "unknown"; michael@0: try { michael@0: old_mstone = Services.prefs.getCharPref("browser.startup.homepage_override.mstone"); michael@0: } catch (ex) {} michael@0: let override = needHomepageOverride(prefb); michael@0: if (override != OVERRIDE_NONE) { michael@0: switch (override) { michael@0: case OVERRIDE_NEW_PROFILE: michael@0: // New profile. michael@0: overridePage = Services.urlFormatter.formatURLPref("startup.homepage_welcome_url"); michael@0: break; michael@0: case OVERRIDE_NEW_MSTONE: michael@0: // Check whether we will restore a session. If we will, we assume michael@0: // that this is an "update" session. This does not take crashes michael@0: // into account because that requires waiting for the session file michael@0: // to be read. If a crash occurs after updating, before restarting, michael@0: // we may open the startPage in addition to restoring the session. michael@0: var ss = Components.classes["@mozilla.org/browser/sessionstartup;1"] michael@0: .getService(Components.interfaces.nsISessionStartup); michael@0: willRestoreSession = ss.isAutomaticRestoreEnabled(); michael@0: michael@0: overridePage = Services.urlFormatter.formatURLPref("startup.homepage_override_url"); michael@0: if (prefb.prefHasUserValue("app.update.postupdate")) michael@0: overridePage = getPostUpdateOverridePage(overridePage); michael@0: michael@0: overridePage = overridePage.replace("%OLD_VERSION%", old_mstone); michael@0: break; michael@0: } michael@0: } michael@0: } catch (ex) {} michael@0: michael@0: // formatURLPref might return "about:blank" if getting the pref fails michael@0: if (overridePage == "about:blank") michael@0: overridePage = ""; michael@0: michael@0: var startPage = ""; michael@0: try { michael@0: var choice = prefb.getIntPref("browser.startup.page"); michael@0: if (choice == 1 || choice == 3) michael@0: startPage = this.startPage; michael@0: } catch (e) { michael@0: Components.utils.reportError(e); michael@0: } michael@0: michael@0: if (startPage == "about:blank") michael@0: startPage = ""; michael@0: michael@0: // Only show the startPage if we're not restoring an update session. michael@0: if (overridePage && startPage && !willRestoreSession) michael@0: return overridePage + "|" + startPage; michael@0: michael@0: return overridePage || startPage || "about:blank"; michael@0: }, michael@0: michael@0: get startPage() { michael@0: var uri = Services.prefs.getComplexValue("browser.startup.homepage", michael@0: nsIPrefLocalizedString).data; michael@0: if (!uri) { michael@0: Services.prefs.clearUserPref("browser.startup.homepage"); michael@0: uri = Services.prefs.getComplexValue("browser.startup.homepage", michael@0: nsIPrefLocalizedString).data; michael@0: } michael@0: return uri; michael@0: }, michael@0: michael@0: mFeatures : null, michael@0: michael@0: getFeatures : function bch_features(cmdLine) { michael@0: if (this.mFeatures === null) { michael@0: this.mFeatures = ""; michael@0: michael@0: try { michael@0: var width = cmdLine.handleFlagWithParam("width", false); michael@0: var height = cmdLine.handleFlagWithParam("height", false); michael@0: michael@0: if (width) michael@0: this.mFeatures += ",width=" + width; michael@0: if (height) michael@0: this.mFeatures += ",height=" + height; michael@0: } michael@0: catch (e) { michael@0: } michael@0: michael@0: // The global PB Service consumes this flag, so only eat it in per-window michael@0: // PB builds. michael@0: if (PrivateBrowsingUtils.isInTemporaryAutoStartMode) { michael@0: this.mFeatures = ",private"; michael@0: } michael@0: } michael@0: michael@0: return this.mFeatures; michael@0: }, michael@0: michael@0: /* nsIContentHandler */ michael@0: michael@0: handleContent : function bch_handleContent(contentType, context, request) { michael@0: try { michael@0: var webNavInfo = Components.classes["@mozilla.org/webnavigation-info;1"] michael@0: .getService(nsIWebNavigationInfo); michael@0: if (!webNavInfo.isTypeSupported(contentType, null)) { michael@0: throw NS_ERROR_WONT_HANDLE_CONTENT; michael@0: } michael@0: } catch (e) { michael@0: throw NS_ERROR_WONT_HANDLE_CONTENT; michael@0: } michael@0: michael@0: request.QueryInterface(nsIChannel); michael@0: handURIToExistingBrowser(request.URI, michael@0: nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, null); michael@0: request.cancel(NS_BINDING_ABORTED); michael@0: }, michael@0: michael@0: /* nsICommandLineValidator */ michael@0: validate : function bch_validate(cmdLine) { michael@0: // Other handlers may use osint so only handle the osint flag if the url michael@0: // flag is also present and the command line is valid. michael@0: var osintFlagIdx = cmdLine.findFlag("osint", false); michael@0: var urlFlagIdx = cmdLine.findFlag("url", false); michael@0: if (urlFlagIdx > -1 && (osintFlagIdx > -1 || michael@0: cmdLine.state == nsICommandLine.STATE_REMOTE_EXPLICIT)) { michael@0: var urlParam = cmdLine.getArgument(urlFlagIdx + 1); michael@0: if (cmdLine.length != urlFlagIdx + 2 || /firefoxurl:/.test(urlParam)) michael@0: throw NS_ERROR_ABORT; michael@0: cmdLine.handleFlag("osint", false) michael@0: } michael@0: }, michael@0: }; michael@0: var gBrowserContentHandler = new nsBrowserContentHandler(); michael@0: michael@0: function handURIToExistingBrowser(uri, location, cmdLine, forcePrivate) michael@0: { michael@0: if (!shouldLoadURI(uri)) michael@0: return; michael@0: michael@0: // Unless using a private window is forced, open external links in private michael@0: // windows only if we're in perma-private mode. michael@0: var allowPrivate = forcePrivate || PrivateBrowsingUtils.permanentPrivateBrowsing; michael@0: var navWin = RecentWindow.getMostRecentBrowserWindow({private: allowPrivate}); michael@0: if (!navWin) { michael@0: // if we couldn't load it in an existing window, open a new one michael@0: var features = "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine); michael@0: if (forcePrivate) { michael@0: features += ",private"; michael@0: } michael@0: openWindow(null, gBrowserContentHandler.chromeURL, "_blank", features, uri.spec); michael@0: return; michael@0: } michael@0: michael@0: var navNav = navWin.QueryInterface(nsIInterfaceRequestor) michael@0: .getInterface(nsIWebNavigation); michael@0: var rootItem = navNav.QueryInterface(nsIDocShellTreeItem).rootTreeItem; michael@0: var rootWin = rootItem.QueryInterface(nsIInterfaceRequestor) michael@0: .getInterface(nsIDOMWindow); michael@0: var bwin = rootWin.QueryInterface(nsIDOMChromeWindow).browserDOMWindow; michael@0: bwin.openURI(uri, null, location, michael@0: nsIBrowserDOMWindow.OPEN_EXTERNAL); michael@0: } michael@0: michael@0: function nsDefaultCommandLineHandler() { michael@0: } michael@0: michael@0: nsDefaultCommandLineHandler.prototype = { michael@0: classID: Components.ID("{47cd0651-b1be-4a0f-b5c4-10e5a573ef71}"), michael@0: michael@0: /* nsISupports */ michael@0: QueryInterface : function dch_QI(iid) { michael@0: if (!iid.equals(nsISupports) && michael@0: !iid.equals(nsICommandLineHandler)) michael@0: throw Components.results.NS_ERROR_NO_INTERFACE; michael@0: michael@0: return this; michael@0: }, michael@0: michael@0: #ifdef XP_WIN michael@0: _haveProfile: false, michael@0: #endif michael@0: michael@0: /* nsICommandLineHandler */ michael@0: handle : function dch_handle(cmdLine) { michael@0: var urilist = []; michael@0: michael@0: #ifdef XP_WIN michael@0: // If we don't have a profile selected yet (e.g. the Profile Manager is michael@0: // displayed) we will crash if we open an url and then select a profile. To michael@0: // prevent this handle all url command line flags and set the command line's michael@0: // preventDefault to true to prevent the display of the ui. The initial michael@0: // command line will be retained when nsAppRunner calls LaunchChild though michael@0: // urls launched after the initial launch will be lost. michael@0: if (!this._haveProfile) { michael@0: try { michael@0: // This will throw when a profile has not been selected. michael@0: var fl = Components.classes["@mozilla.org/file/directory_service;1"] michael@0: .getService(Components.interfaces.nsIProperties); michael@0: var dir = fl.get("ProfD", Components.interfaces.nsILocalFile); michael@0: this._haveProfile = true; michael@0: } michael@0: catch (e) { michael@0: while ((ar = cmdLine.handleFlagWithParam("url", false))) { } michael@0: cmdLine.preventDefault = true; michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: try { michael@0: var ar; michael@0: while ((ar = cmdLine.handleFlagWithParam("url", false))) { michael@0: var uri = resolveURIInternal(cmdLine, ar); michael@0: urilist.push(uri); michael@0: } michael@0: } michael@0: catch (e) { michael@0: Components.utils.reportError(e); michael@0: } michael@0: michael@0: count = cmdLine.length; michael@0: michael@0: for (i = 0; i < count; ++i) { michael@0: var curarg = cmdLine.getArgument(i); michael@0: if (curarg.match(/^-/)) { michael@0: Components.utils.reportError("Warning: unrecognized command line flag " + curarg + "\n"); michael@0: // To emulate the pre-nsICommandLine behavior, we ignore michael@0: // the argument after an unrecognized flag. michael@0: ++i; michael@0: } else { michael@0: try { michael@0: urilist.push(resolveURIInternal(cmdLine, curarg)); michael@0: } michael@0: catch (e) { michael@0: Components.utils.reportError("Error opening URI '" + curarg + "' from the command line: " + e + "\n"); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (urilist.length) { michael@0: if (cmdLine.state != nsICommandLine.STATE_INITIAL_LAUNCH && michael@0: urilist.length == 1) { michael@0: // Try to find an existing window and load our URI into the michael@0: // current tab, new tab, or new window as prefs determine. michael@0: try { michael@0: handURIToExistingBrowser(urilist[0], nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, cmdLine); michael@0: return; michael@0: } michael@0: catch (e) { michael@0: } michael@0: } michael@0: michael@0: var URLlist = urilist.filter(shouldLoadURI).map(function (u) u.spec); michael@0: if (URLlist.length) { michael@0: openWindow(null, gBrowserContentHandler.chromeURL, "_blank", michael@0: "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine), michael@0: URLlist); michael@0: } michael@0: michael@0: } michael@0: else if (!cmdLine.preventDefault) { michael@0: // Passing defaultArgs, so use NO_EXTERNAL_URIS michael@0: openWindow(null, gBrowserContentHandler.chromeURL, "_blank", michael@0: "chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine), michael@0: gBrowserContentHandler.defaultArgs, NO_EXTERNAL_URIS); michael@0: } michael@0: }, michael@0: michael@0: helpInfo : "", michael@0: }; michael@0: michael@0: var components = [nsBrowserContentHandler, nsDefaultCommandLineHandler]; michael@0: this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);