From 2ddf3e3249cfced9daaf5e0ed3ddca607374a2f9 Mon Sep 17 00:00:00 2001 From: "dmose@mozilla.org" Date: Thu, 6 Sep 2007 15:20:52 -0700 Subject: [PATCH] Inject default web-based protocol handlers into mimeTypes.rdf (bug 392978), r=myk, sr=biesi, a=mconnor --- browser/app/profile/firefox.js | 14 +++ uriloader/exthandler/nsHandlerService.js | 118 ++++++++++++++++++ .../tests/unit/test_handlerService.js | 18 ++- 3 files changed, 147 insertions(+), 3 deletions(-) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 7ef0af5ddae..1e835c12cee 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -496,6 +496,20 @@ pref("browser.contentHandlers.types.5.type", "application/vnd.mozilla.maybe.feed pref("browser.feeds.handler", "ask"); +// For now, this is living in content rather than in locales, as per Pike. +// Eventually it will get merged into region.properties; see bug 395277. +// +// At startup, if the handler service notices that the version number here +// is newer than the version number in the handler service datastore, it will +// add any handlers it finds in the prefs (as seeded by this file) to its +// datastore. +pref("gecko.handlerService.defaultHandlersVersion", "0"); +// +// The default set of web-based protocol handlers shown in the application +// selection dialog +pref("gecko.handlerService.schemes.webcal.0.name", "WebCal Test Handler"); +pref("gecko.handlerService.schemes.webcal.0.uriTemplate", "http://handler-test.mozilla.org/webcal?url=%s"); + #ifdef MOZ_SAFE_BROWSING // Safe browsing does nothing unless both these prefs are set. pref("browser.safebrowsing.enabled", true); diff --git a/uriloader/exthandler/nsHandlerService.js b/uriloader/exthandler/nsHandlerService.js index 13b17cac782..6709ba3782c 100755 --- a/uriloader/exthandler/nsHandlerService.js +++ b/uriloader/exthandler/nsHandlerService.js @@ -19,6 +19,7 @@ * * Contributor(s): * Myk Melez + * Dan Mosedale * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -47,6 +48,9 @@ const CLASS_PROTOCOLINFO = "scheme"; // namespace prefix const NC_NS = "http://home.netscape.com/NC-rdf#"; +// the most recent default handlers that have been injected +const NC_DEFAULT_HANDLERS_VERSION = NC_NS + "defaultHandlersVersion"; + // type list properties const NC_MIME_TYPES = NC_NS + "MIME-types"; @@ -118,11 +122,33 @@ HandlerService.prototype = { // Observe xpcom-shutdown so we can remove these observers // when the application shuts down. this._observerSvc.addObserver(this, "xpcom-shutdown", false); + + // Observe profile-do-change so that non-default profiles get upgraded too + this._observerSvc.addObserver(this, "profile-do-change", false); + + // do any necessary updating of the datastore + this._updateDB(); }, + _updateDB: function HS__updateDB() { + // if the default prefs have changed, inject any new default handers + // into the datastore + try { + if (this._datastoreDefaultHandlersVersion < + this._prefsDefaultHandlersVersion) { + this._injectNewDefaults(); + this._datastoreDefaultHandlersVersion = + this._prefsDefaultHandlersVersion; + } + } catch (ex) { + // if injecting the defaults failed, life goes on... + } + }, + _destroy: function HS__destroy() { this._observerSvc.removeObserver(this, "profile-before-change"); this._observerSvc.removeObserver(this, "xpcom-shutdown"); + this._observerSvc.removeObserver(this, "profile-do-change"); // XXX Should we also null references to all the services that get stored // by our memoizing getters in the Convenience Getters section? @@ -134,6 +160,95 @@ HandlerService.prototype = { this.__ds = null; }, + _isInHandlerArray: function HS__isInHandlerArray(aArray, aHandler) { + var enumerator = aArray.enumerate(); + while (enumerator.hasMoreElements()) { + let handler = enumerator.getNext(); + handler.QueryInterface(Ci.nsIHandlerApp); + if (handler.equals(aHandler)) + return true; + } + + return false; + }, + + get _datastoreDefaultHandlersVersion() { + var version = this._getValue("urn:root", NC_DEFAULT_HANDLERS_VERSION); + + version = version ? version : -1; + + return version; + }, + + set _datastoreDefaultHandlersVersion(aNewVersion) { + return this._setLiteral("urn:root", NC_DEFAULT_HANDLERS_VERSION, + aNewVersion); + }, + + get _prefsDefaultHandlersVersion() { + // get handler service pref branch + var prefSvc = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService); + var handlerSvcBranch = prefSvc.getBranch("gecko.handlerService."); + + // get the version of the preferences for this locale + var version = handlerSvcBranch.getComplexValue("defaultHandlersVersion", + Ci.nsISupportsString).data; + + return version; + }, + + _injectNewDefaults: function HS__injectNewDefaults() { + // get handler service pref branch + var prefSvc = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService); + + let schemesPrefBranch = prefSvc.getBranch("gecko.handlerService.schemes."); + let schemePrefList = schemesPrefBranch.getChildList("", {}); + + let protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"]. + getService(Ci.nsIExternalProtocolService); + + var schemes = {}; + + // read all the scheme prefs into a hash + for each (var schemePrefName in schemePrefList) { + + let [scheme, handlerNumber, attribute] = schemePrefName.split("."); + + if (!(scheme in schemes)) + schemes[scheme] = {}; + if (!(handlerNumber in schemes[scheme])) + schemes[scheme][handlerNumber] = {}; + + schemes[scheme][handlerNumber][attribute] = + schemesPrefBranch.getComplexValue(schemePrefName, + Ci.nsISupportsString).data; + } + + for (var scheme in schemes) { + + // get a protocol info object for that scheme and cache the possible + // handlers to avoid extra xpconnect traversals + let protoInfo = protoSvc.getProtocolHandlerInfo(scheme); + let possibleHandlers = protoInfo.possibleApplicationHandlers; + + for each (var handlerPrefs in schemes[scheme]) { + + let handlerApp = Cc["@mozilla.org/uriloader/web-handler-app;1"]. + createInstance(Ci.nsIWebHandlerApp); + + handlerApp.uriTemplate = handlerPrefs.uriTemplate; + handlerApp.name = handlerPrefs.name; + + if (!this._isInHandlerArray(possibleHandlers, handlerApp)) { + possibleHandlers.appendElement(handlerApp, false); + } + } + + this.store(protoInfo); + } + }, //**************************************************************************// // nsIObserver @@ -146,6 +261,9 @@ HandlerService.prototype = { case "xpcom-shutdown": this._destroy(); break; + case "profile-do-change": + this._updateDB(); + break; } }, diff --git a/uriloader/exthandler/tests/unit/test_handlerService.js b/uriloader/exthandler/tests/unit/test_handlerService.js index 1d374647202..8dda11cb522 100755 --- a/uriloader/exthandler/tests/unit/test_handlerService.js +++ b/uriloader/exthandler/tests/unit/test_handlerService.js @@ -19,6 +19,7 @@ * * Contributor(s): * Myk Melez + * Dan Mosedale * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -44,7 +45,11 @@ function run_test() { const mimeSvc = Cc["@mozilla.org/uriloader/external-helper-app-service;1"]. getService(Ci.nsIMIMEService); - + const prefSvc = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService); + + const rootPrefBranch = prefSvc.getBranch(""); + //**************************************************************************// // Sample Data @@ -141,11 +146,18 @@ function run_test() { do_check_false(handlerInfo.alwaysAskBeforeHandling); // Make sure the handler service's enumerate method lists all known handlers. - // FIXME: store and test enumeration of a protocol handler once bug 391150 - // gets fixed and we can actually retrieve a protocol handler. var handlerInfo2 = mimeSvc.getFromTypeAndExtension("nonexistent/type2", null); handlerSvc.store(handlerInfo2); var handlerTypes = ["nonexistent/type", "nonexistent/type2"]; + try { + // If we have a defaultHandlersVersion pref, then assume that we're in the + // firefox tree and that we'll also have an added webcal handler. + // Bug 395131 has been filed to make this test work more generically + // by providing our own prefs for this test rather than this icky + // special casing. + rootPrefBranch.getCharPref("gecko.handlerService.defaultHandlersVersion"); + handlerTypes.push("webcal"); + } catch (ex) {} var handlers = handlerSvc.enumerate(); while (handlers.hasMoreElements()) { var handler = handlers.getNext().QueryInterface(Ci.nsIHandlerInfo);