diff options
Diffstat (limited to 'comm/suite/browser/nsBrowserContentHandler.js')
-rw-r--r-- | comm/suite/browser/nsBrowserContentHandler.js | 634 |
1 files changed, 634 insertions, 0 deletions
diff --git a/comm/suite/browser/nsBrowserContentHandler.js b/comm/suite/browser/nsBrowserContentHandler.js new file mode 100644 index 0000000000..5e6c37380f --- /dev/null +++ b/comm/suite/browser/nsBrowserContentHandler.js @@ -0,0 +1,634 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); + +const nsISupports = Ci.nsISupports; +const nsIBrowserDOMWindow = Ci.nsIBrowserDOMWindow; +const nsIBrowserHistory = Ci.nsIBrowserHistory; +const nsIBrowserSearchService = Ci.nsIBrowserSearchService; +const nsIChannel = Ci.nsIChannel; +const nsICommandLine = Ci.nsICommandLine; +const nsICommandLineHandler = Ci.nsICommandLineHandler; +const nsICommandLineValidator = Ci.nsICommandLineValidator; +const nsIComponentRegistrar = Ci.nsIComponentRegistrar; +const nsIContentHandler = Ci.nsIContentHandler; +const nsIDOMWindow = Ci.nsIDOMWindow; +const nsIFactory = Ci.nsIFactory; +const nsIFileURL = Ci.nsIFileURL; +const nsIHttpProtocolHandler = Ci.nsIHttpProtocolHandler; +const nsINetUtil = Ci.nsINetUtil; +const nsIPrefService = Ci.nsIPrefService; +const nsIPrefBranch = Ci.nsIPrefBranch; +const nsIPrefLocalizedString = Ci.nsIPrefLocalizedString; +const nsISupportsString = Ci.nsISupportsString; +const nsIWindowMediator = Ci.nsIWindowMediator; +const nsIWebNavigationInfo = Ci.nsIWebNavigationInfo; + +const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001; + +const URI_INHERITS_SECURITY_CONTEXT = nsIHttpProtocolHandler + .URI_INHERITS_SECURITY_CONTEXT; + +const NS_GENERAL_STARTUP_PREFIX = "@mozilla.org/commandlinehandler/general-startup;1?type="; + +function shouldLoadURI(aURI) +{ + if (aURI && !aURI.schemeIs("chrome")) + return true; + + dump("*** Preventing external load of chrome: URI into browser window\n"); + dump(" Use -chrome <uri> instead\n"); + return false; +} + +function resolveURIInternal(aCmdLine, aArgument) +{ + try { + var file = aCmdLine.resolveFile(aArgument); + if (file.exists()) { + return Services.io.newFileURI(file); + } + } catch (e) { + } + + // We have interpreted the argument as a relative file URI, but the file + // doesn't exist. Try URI fixup heuristics: see bug 290782. + + try { + return Services.uriFixup + .createFixupURI(aArgument, + Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP); + } catch (e) { + Cu.reportError(e); + } + + return null; +} + +function getHomePageGroup() +{ + var homePage = Services.prefs.getComplexValue("browser.startup.homepage", + nsIPrefLocalizedString).data; + + var count = 0; + try { + count = Services.prefs.getIntPref("browser.startup.homepage.count"); + } catch (e) { + } + + for (var i = 1; i < count; ++i) { + try { + homePage += '\n' + Services.prefs.getStringPref("browser.startup.homepage." + i); + } catch (e) { + } + } + return homePage; +} + +function needHomePageOverride() +{ + var savedmstone = null; + try { + savedmstone = Services.prefs.getCharPref("browser.startup.homepage_override.mstone"); + if (savedmstone == "ignore") + return false; + } catch (e) { + } + + var mstone = Cc["@mozilla.org/network/protocol;1?name=http"] + .getService(nsIHttpProtocolHandler).misc; + + if (mstone == savedmstone) + return false; + + Services.prefs.setCharPref("browser.startup.homepage_override.mstone", mstone); + + return true; +} + +function getURLToLoad() +{ + if (needHomePageOverride()) { + try { + return Services.urlFormatter.formatURLPref("startup.homepage_override_url"); + } catch (e) { + } + } + + try { + var ss = Cc["@mozilla.org/suite/sessionstartup;1"] + .getService(Ci.nsISessionStartup); + // return about:blank if we are restoring previous session + if (ss.doRestore()) + return "about:blank"; + } catch (e) { + } + + try { + var st = Cc["@mozilla.org/suite/sessionstore;1"] + .getService(Ci.nsISessionStore); + // return about:blank if the last window was closed and should be restored + if (st.doRestoreLastWindow()) + return "about:blank"; + } catch (e) { + } + + try { + switch (Services.prefs.getIntPref("browser.startup.page")) { + case 1: + return getHomePageGroup(); + + case 2: + return Services.prefs.getStringPref("browser.history.last_page_visited"); + } + } catch (e) { + } + + return "about:blank"; +} + +function openWindow(parent, url, features, arg) +{ + var argstring = Cc["@mozilla.org/supports-string;1"] + .createInstance(nsISupportsString); + argstring.data = arg; + return Services.ww.openWindow(parent, url, "", features, argstring); +} + +function openPreferences() +{ + var win = Services.wm.getMostRecentWindow("mozilla:preferences"); + if (win) + win.focus(); + else + openWindow(null, "chrome://communicator/content/pref/preferences.xul", + "chrome,titlebar,dialog=no,resizable", ""); +} + +function getBrowserURL() +{ + try { + return Services.prefs.getCharPref("browser.chromeURL"); + } catch (e) { + } + return "chrome://navigator/content/navigator.xul"; +} + +function handURIToExistingBrowser(aUri, aLocation, aFeatures, aTriggeringPrincipal) +{ + if (!shouldLoadURI(aUri)) + return; + + var navWin = Services.wm.getMostRecentWindow("navigator:browser"); + if (!navWin) { + // if we couldn't load it in an existing window, open a new one + openWindow(null, getBrowserURL(), aFeatures, aUri.spec); + return; + } + + navWin.browserDOMWindow.openURI(aUri, null, aLocation, + nsIBrowserDOMWindow.OPEN_EXTERNAL, + aTriggeringPrincipal); +} + +function doSearch(aSearchTerm, aFeatures) { + var submission = Services.search.defaultEngine.getSubmission(aSearchTerm); + + // fill our nsIMutableArray with uri-as-wstring, null, null, postData + var sa = Cc["@mozilla.org/array;1"] + .createInstance(Ci.nsIMutableArray); + + var uristring = Cc["@mozilla.org/supports-string;1"] + .createInstance(nsISupportsString); + uristring.data = submission.uri.spec; + + sa.appendElement(uristring); + sa.appendElement(null); + sa.appendElement(null); + sa.appendElement(submission.postData); + + // XXXbsmedberg: use handURIToExistingBrowser to obey tabbed-browsing + // preferences, but need nsIBrowserDOMWindow extensions + return Services.ww.openWindow(null, getBrowserURL(), "_blank", aFeatures, + sa); +} + +var nsBrowserContentHandler = { + get wrappedJSObject() { + return this; + }, + + /* nsISupports */ + QueryInterface: function QueryInterface(iid) { + if (iid.equals(nsISupports) || + iid.equals(nsICommandLineHandler) || + iid.equals(nsICommandLine) || + iid.equals(nsICommandLineValidator) || + iid.equals(nsIContentHandler) || + iid.equals(nsIFactory)) + return this; + + throw Cr.NS_ERROR_NO_INTERFACE; + }, + + _handledURI: null, + + /* nsICommandLineHandler */ + handle: function handle(cmdLine) { + var features = "chrome,all,dialog=no"; + try { + var width = cmdLine.handleFlagWithParam("width", false); + if (width != null) + features += ",width=" + width; + } catch (e) { + } + try { + var height = cmdLine.handleFlagWithParam("height", false); + if (height != null) + features += ",height=" + height; + } catch (e) { + } + + try { + var remote = cmdLine.handleFlagWithParam("remote", true); + if (/^\s*(\w+)\s*\(\s*([^\s,]+)\s*,?\s*([^\s]*)\s*\)\s*$/.test(remote)) { + switch (RegExp.$1.toLowerCase()) { + case "openurl": + case "openfile": + // openURL(<url>) + // openURL(<url>,new-window) + // openURL(<url>,new-tab) + + var uri = resolveURIInternal(cmdLine, RegExp.$2); + + var location = nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW; + if (RegExp.$3 == "new-window") + location = nsIBrowserDOMWindow.OPEN_NEWWINDOW; + else if (RegExp.$3 == "new-tab") + location = nsIBrowserDOMWindow.OPEN_NEWTAB; + + handURIToExistingBrowser(uri, location, features, + Services.scriptSecurityManager.getSystemPrincipal()); + break; + + case "mailto": + openWindow(null, "chrome://messenger/content/messengercompose/messengercompose.xul", features, RegExp.$2); + break; + + case "xfedocommand": + switch (RegExp.$2.toLowerCase()) { + case "openbrowser": + openWindow(null, getBrowserURL(), features, RegExp.$3 || getURLToLoad()); + break; + + case "openinbox": + openWindow(null, "chrome://messenger/content", features); + break; + + case "composemessage": + openWindow(null, "chrome://messenger/content/messengercompose/messengercompose.xul", features, RegExp.$3); + break; + + default: + throw Cr.NS_ERROR_ABORT; + } + break; + + default: + // Somebody sent us a remote command we don't know how to process: + // just abort. + throw Cr.NS_ERROR_ABORT; + } + + cmdLine.preventDefault = true; + } + } catch (e) { + // If we had a -remote flag but failed to process it, throw + // NS_ERROR_ABORT so that the xremote code knows to return a failure + // back to the handling code. + throw Cr.NS_ERROR_ABORT; + } + + try { + var browserParam = cmdLine.handleFlagWithParam("browser", false); + if (browserParam) { + openWindow(null, getBrowserURL(), features, browserParam); + cmdLine.preventDefault = true; + } + } catch (e) { + if (cmdLine.handleFlag("browser", false)) { + openWindow(null, getBrowserURL(), features, getURLToLoad()); + cmdLine.preventDefault = true; + } + } + + try { + var privateParam = cmdLine.handleFlagWithParam("private", false); + if (privateParam) { + openWindow(null, getBrowserURL(), "private," + features, privateParam); + cmdLine.preventDefault = true; + } + } catch (e) { + if (cmdLine.handleFlag("private", false)) { + openWindow(null, getBrowserURL(), "private," + features, "about:privatebrowsing"); + cmdLine.preventDefault = true; + } + } + + // If we don't have a profile selected yet (e.g. the Profile Manager is + // displayed) we will crash if we open an url and then select a profile. To + // prevent this handle all url command line flag and set the command line's + // preventDefault to true to prevent the display of the ui. The initial + // command line will be retained when nsAppRunner calls LaunchChild though + // urls launched after the initial launch will be lost. + try { + // This will throw when a profile has not been selected. + Services.dirsvc.get("ProfD", Ci.nsIFile); + } catch (e) { + cmdLine.preventDefault = true; + throw Cr.NS_ERROR_ABORT; + } + + try { + var urlParam = cmdLine.handleFlagWithParam("url", false); + if (urlParam) { + if (this._handledURI == urlParam) { + this._handledURI = null; + } else { + if (cmdLine.handleFlag("requestpending", false) && + cmdLine.state == nsICommandLine.STATE_INITIAL_LAUNCH) { + // A DDE request with the URL will follow and the DDE handling code + // will send it to the commandline handler via + // "mozilla -url http://www.foo.com". Store the URL so we can + // ignore this request later + this._handledURI = urlParam; + } + + urlParam = resolveURIInternal(cmdLine, urlParam); + handURIToExistingBrowser(urlParam, + nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, + features, + Services.scriptSecurityManager.getSystemPrincipal()); + } + cmdLine.preventDefault = true; + } + } catch (e) { + } + + var param; + try { + while ((param = cmdLine.handleFlagWithParam("new-window", false)) != null) { + var uri = resolveURIInternal(cmdLine, param); + handURIToExistingBrowser(uri, + nsIBrowserDOMWindow.OPEN_NEWWINDOW, + features, + Services.scriptSecurityManager.getSystemPrincipal()); + cmdLine.preventDefault = true; + } + } catch (e) { + } + + try { + while ((param = cmdLine.handleFlagWithParam("new-tab", false)) != null) { + var uri = resolveURIInternal(cmdLine, param); + handURIToExistingBrowser(uri, + nsIBrowserDOMWindow.OPEN_NEWTAB, + features, + Services.scriptSecurityManager.getSystemPrincipal()); + cmdLine.preventDefault = true; + } + } catch (e) { + } + + try { + var chromeParam = cmdLine.handleFlagWithParam("chrome", false); + if (chromeParam) { + // only load URIs which do not inherit chrome privs + var uri = resolveURIInternal(cmdLine, chromeParam); + if (!Services.netUtils.URIChainHasFlags(uri, URI_INHERITS_SECURITY_CONTEXT)) { + openWindow(null, uri.spec, features); + cmdLine.preventDefault = true; + } + } + } catch (e) { + } + + try { + var fileParam = cmdLine.handleFlagWithParam("file", false); + if (fileParam) { + fileParam = resolveURIInternal(cmdLine, fileParam); + handURIToExistingBrowser(fileParam, + nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, + features, + Services.scriptSecurityManager.getSystemPrincipal()); + cmdLine.preventDefault = true; + } + } catch (e) { + } + + var searchParam = cmdLine.handleFlagWithParam("search", false); + if (searchParam) { + doSearch(searchParam, features); + cmdLine.preventDefault = true; + } + + if (cmdLine.handleFlag("preferences", false)) { + openPreferences(); + cmdLine.preventDefault = true; + } + + if (cmdLine.handleFlag("silent", false)) + cmdLine.preventDefault = true; + + if (!cmdLine.preventDefault && cmdLine.length) { + var arg = cmdLine.getArgument(0); + if (!/^-/.test(arg)) { + try { + arg = resolveURIInternal(cmdLine, arg); + handURIToExistingBrowser(arg, + nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, + features, + Services.scriptSecurityManager.getSystemPrincipal()); + cmdLine.preventDefault = true; + } catch (e) { + } + } + } + + if (!cmdLine.preventDefault) { + this.realCmdLine = cmdLine; + + var prefBranch = Services.prefs.getBranch("general.startup."); + + var startupArray = prefBranch.getChildList(""); + + for (var i = 0; i < startupArray.length; ++i) { + this.currentArgument = startupArray[i]; + var contract = NS_GENERAL_STARTUP_PREFIX + this.currentArgument; + if (contract in Cc) { + // Ignore any exceptions - we can't do anything about them here. + try { + if (prefBranch.getBoolPref(this.currentArgument)) { + var handler = Cc[contract].getService(nsICommandLineHandler); + if (handler.wrappedJSObject) + handler.wrappedJSObject.handle(this); + else + handler.handle(this); + } + } catch (e) { + Cu.reportError(e); + } + } + } + + this.realCmdLine = null; + } + + if (!cmdLine.preventDefault) { + var homePage = getURLToLoad(); + if (!/\n/.test(homePage)) { + try { + let uri = Services.uriFixup.createFixupURI(homePage, 0); + handURIToExistingBrowser(uri, nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, features); + cmdLine.preventDefault = true; + } catch (e) { + } + } + + if (!cmdLine.preventDefault) { + openWindow(null, getBrowserURL(), features, homePage); + cmdLine.preventDefault = true; + } + } + + }, + + /* nsICommandLineValidator */ + validate: function validate(cmdLine) { + var osintFlagIdx = cmdLine.findFlag("osint", false); + + // If the osint flag is not present and we are not called by DDE then we're safe + if (cmdLine.state != nsICommandLine.STATE_REMOTE_EXPLICIT && + cmdLine.findFlag("osint", false) == -1) + return; + + // Other handlers may use osint so only handle the osint flag if a + // flag is also present and the command line is valid. + ["url", "news", "compose"].forEach(function(value) { + var flagIdx = cmdLine.findFlag(value, false); + + if (flagIdx > -1) { + var testExpr = new RegExp("seamonkey" + value + ":"); + if (cmdLine.length != flagIdx + 2 || + testExpr.test(cmdLine.getArgument(flagIdx + 1))) + throw Cr.NS_ERROR_ABORT; + cmdLine.handleFlag("osint", false); + } + }); + }, + + helpInfo: " -browser <url> Open a browser window.\n" + + " -private <url> Open a private window.\n" + + " -new-window <url> Open <url> in a new browser window.\n" + + " -new-tab <url> Open <url> in a new browser tab.\n" + + " -url <url> Open the specified url.\n" + + " -chrome <url> Open the specified chrome.\n" + + " -search <term> Search <term> with your default search engine.\n" + + " -preferences Open Preferences dialog.\n", + + /* nsICommandLine */ + length: 1, + + getArgument: function getArgument(index) { + if (index == 0) + return this.currentArgument; + + throw Cr.NS_ERROR_INVALID_ARG; + }, + + findFlag: function findFlag(flag, caseSensitive) { + if (caseSensitive) + return flag == this.currentArgument ? 0 : -1; + return flag.toLowerCase() == this.currentArgument.toLowerCase() ? 0 : -1; + }, + + removeArguments: function removeArguments(start, end) { + // do nothing + }, + + handleFlag: function handleFlag(flag, caseSensitive) { + if (caseSensitive) + return flag == this.currentArgument; + return flag.toLowerCase() == this.currentArgument.toLowerCase(); + }, + + handleFlagWithParam : function handleFlagWithParam(flag, caseSensitive) { + if (this.handleFlag(flag, caseSensitive)) + throw Cr.NS_ERROR_INVALID_ARG; + }, + + get state() { + return this.realCmdLine.state; + }, + + get preventDefault() { + return this.realCmdLine.preventDefault; + }, + + set preventDefault(preventDefault) { + return this.realCmdLine.preventDefault = preventDefault; + }, + + get workingDirectory() { + return this.realCmdLine.workingDirectory; + }, + + get windowContext() { + return this.realCmdLine.windowContext; + }, + + resolveFile: function resolveFile(arg) { + return this.realCmdLine.resolveFile(arg); + }, + + resolveURI: function resolveURI(arg) { + return this.realCmdLine.resolveURI(arg); + }, + + /* nsIContentHandler */ + handleContent: function handleContent(contentType, context, request) { + var webNavInfo = Cc["@mozilla.org/webnavigation-info;1"] + .getService(nsIWebNavigationInfo); + if (!webNavInfo.isTypeSupported(contentType, null)) + throw NS_ERROR_WONT_HANDLE_CONTENT; + + request.QueryInterface(nsIChannel); + handURIToExistingBrowser(request.URI, + nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, + "chrome,all,dialog=no", + request.loadInfo.triggeringPrincipal); + request.cancel(Cr.NS_BINDING_ABORTED); + }, + + /* nsIFactory */ + createInstance: function createInstance(outer, iid) { + if (outer != null) + throw Cr.NS_ERROR_NO_AGGREGATION; + + return this.QueryInterface(iid); + }, + + lockFactory: function lockFactory(lock) { + /* no-op */ + } +}; + +const BROWSER_CID = Components.ID("{c2343730-dc2c-11d3-98b3-001083010e9b}"); + +function NSGetFactory(cid) { + if (cid.number == BROWSER_CID) + return nsBrowserContentHandler; + throw Cr.NS_ERROR_FACTORY_NOT_REGISTERED; +} |