From f9cab004186edb425a9b88ad649726605080a17c Mon Sep 17 00:00:00 2001 From: Thomas Groman Date: Mon, 20 Apr 2020 20:49:37 -0700 Subject: move browser to webbrowser/ --- components/feeds/BrowserFeeds.manifest | 28 - components/feeds/FeedConverter.js | 591 --------- components/feeds/FeedWriter.js | 1397 -------------------- components/feeds/WebContentConverter.js | 927 ------------- components/feeds/content/subscribe.css | 7 - components/feeds/content/subscribe.js | 23 - components/feeds/content/subscribe.xhtml | 65 - components/feeds/content/subscribe.xml | 40 - components/feeds/jar.mn | 9 - components/feeds/moz.build | 33 - components/feeds/nsFeedSniffer.cpp | 363 ----- components/feeds/nsFeedSniffer.h | 37 - components/feeds/nsIFeedResultService.idl | 66 - .../feeds/nsIWebContentConverterRegistrar.idl | 117 -- 14 files changed, 3703 deletions(-) delete mode 100644 components/feeds/BrowserFeeds.manifest delete mode 100644 components/feeds/FeedConverter.js delete mode 100644 components/feeds/FeedWriter.js delete mode 100644 components/feeds/WebContentConverter.js delete mode 100644 components/feeds/content/subscribe.css delete mode 100644 components/feeds/content/subscribe.js delete mode 100644 components/feeds/content/subscribe.xhtml delete mode 100644 components/feeds/content/subscribe.xml delete mode 100644 components/feeds/jar.mn delete mode 100644 components/feeds/moz.build delete mode 100644 components/feeds/nsFeedSniffer.cpp delete mode 100644 components/feeds/nsFeedSniffer.h delete mode 100644 components/feeds/nsIFeedResultService.idl delete mode 100644 components/feeds/nsIWebContentConverterRegistrar.idl (limited to 'components/feeds') diff --git a/components/feeds/BrowserFeeds.manifest b/components/feeds/BrowserFeeds.manifest deleted file mode 100644 index a584323..0000000 --- a/components/feeds/BrowserFeeds.manifest +++ /dev/null @@ -1,28 +0,0 @@ -# WebappRT doesn't need these instructions, and they don't necessarily work -# with it, but it does use a GRE directory that the GRE shares with Firefox, -# so in order to prevent the instructions from being processed for WebappRT, -# we need to restrict them to the applications that depend on them, i.e.: -# -# b2g: {3c2e2abc-06d4-11e1-ac3b-374f68613e61} -# browser: {8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4} -# mobile/android: {aa3c5121-dab2-40e2-81ca-7ea25febc110} -# mobile/xul: {a23983c0-fd0e-11dc-95ff-0800200c9a66} -# -# In theory we should do this for all these instructions, but in practice it is -# sufficient to do it for the app-startup one, and the file is simpler that way. - -component {229fa115-9412-4d32-baf3-2fc407f76fb1} FeedConverter.js -contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1} -contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.video.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1} -contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.audio.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1} -component {2376201c-bbc6-472f-9b62-7548040a61c6} FeedConverter.js -contract @mozilla.org/browser/feeds/result-service;1 {2376201c-bbc6-472f-9b62-7548040a61c6} -component {4f91ef2e-57ba-472e-ab7a-b4999e42d6c0} FeedConverter.js -contract @mozilla.org/network/protocol;1?name=feed {4f91ef2e-57ba-472e-ab7a-b4999e42d6c0} -component {1c31ed79-accd-4b94-b517-06e0c81999d5} FeedConverter.js -contract @mozilla.org/network/protocol;1?name=pcast {1c31ed79-accd-4b94-b517-06e0c81999d5} -component {49bb6593-3aff-4eb3-a068-2712c28bd58e} FeedWriter.js -contract @mozilla.org/browser/feeds/result-writer;1 {49bb6593-3aff-4eb3-a068-2712c28bd58e} -component {792a7e82-06a0-437c-af63-b2d12e808acc} WebContentConverter.js -contract @mozilla.org/embeddor.implemented/web-content-handler-registrar;1 {792a7e82-06a0-437c-af63-b2d12e808acc} -category app-startup WebContentConverter service,@mozilla.org/embeddor.implemented/web-content-handler-registrar;1 application={3c2e2abc-06d4-11e1-ac3b-374f68613e61} application={8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4} application={aa3c5121-dab2-40e2-81ca-7ea25febc110} application={a23983c0-fd0e-11dc-95ff-0800200c9a66} diff --git a/components/feeds/FeedConverter.js b/components/feeds/FeedConverter.js deleted file mode 100644 index d0f5737..0000000 --- a/components/feeds/FeedConverter.js +++ /dev/null @@ -1,591 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/debug.js"); -Components.utils.import("resource://gre/modules/Services.jsm"); - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cr = Components.results; - -function LOG(str) { - dump("*** " + str + "\n"); -} - -const FS_CONTRACTID = "@mozilla.org/browser/feeds/result-service;1"; -const FPH_CONTRACTID = "@mozilla.org/network/protocol;1?name=feed"; -const PCPH_CONTRACTID = "@mozilla.org/network/protocol;1?name=pcast"; - -const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed"; -const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed"; -const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed"; -const TYPE_ANY = "*/*"; - -const PREF_SELECTED_APP = "browser.feeds.handlers.application"; -const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice"; -const PREF_SELECTED_ACTION = "browser.feeds.handler"; -const PREF_SELECTED_READER = "browser.feeds.handler.default"; - -const PREF_VIDEO_SELECTED_APP = "browser.videoFeeds.handlers.application"; -const PREF_VIDEO_SELECTED_WEB = "browser.videoFeeds.handlers.webservice"; -const PREF_VIDEO_SELECTED_ACTION = "browser.videoFeeds.handler"; -const PREF_VIDEO_SELECTED_READER = "browser.videoFeeds.handler.default"; - -const PREF_AUDIO_SELECTED_APP = "browser.audioFeeds.handlers.application"; -const PREF_AUDIO_SELECTED_WEB = "browser.audioFeeds.handlers.webservice"; -const PREF_AUDIO_SELECTED_ACTION = "browser.audioFeeds.handler"; -const PREF_AUDIO_SELECTED_READER = "browser.audioFeeds.handler.default"; - -function getPrefAppForType(t) { - switch (t) { - case Ci.nsIFeed.TYPE_VIDEO: - return PREF_VIDEO_SELECTED_APP; - - case Ci.nsIFeed.TYPE_AUDIO: - return PREF_AUDIO_SELECTED_APP; - - default: - return PREF_SELECTED_APP; - } -} - -function getPrefWebForType(t) { - switch (t) { - case Ci.nsIFeed.TYPE_VIDEO: - return PREF_VIDEO_SELECTED_WEB; - - case Ci.nsIFeed.TYPE_AUDIO: - return PREF_AUDIO_SELECTED_WEB; - - default: - return PREF_SELECTED_WEB; - } -} - -function getPrefActionForType(t) { - switch (t) { - case Ci.nsIFeed.TYPE_VIDEO: - return PREF_VIDEO_SELECTED_ACTION; - - case Ci.nsIFeed.TYPE_AUDIO: - return PREF_AUDIO_SELECTED_ACTION; - - default: - return PREF_SELECTED_ACTION; - } -} - -function getPrefReaderForType(t) { - switch (t) { - case Ci.nsIFeed.TYPE_VIDEO: - return PREF_VIDEO_SELECTED_READER; - - case Ci.nsIFeed.TYPE_AUDIO: - return PREF_AUDIO_SELECTED_READER; - - default: - return PREF_SELECTED_READER; - } -} - -function safeGetCharPref(pref, defaultValue) { - var prefs = - Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch); - try { - return prefs.getCharPref(pref); - } - catch (e) { - } - return defaultValue; -} - -function FeedConverter() { -} -FeedConverter.prototype = { - classID: Components.ID("{229fa115-9412-4d32-baf3-2fc407f76fb1}"), - - /** - * This is the downloaded text data for the feed. - */ - _data: null, - - /** - * This is the object listening to the conversion, which is ultimately the - * docshell for the load. - */ - _listener: null, - - /** - * Records if the feed was sniffed - */ - _sniffed: false, - - /** - * See nsIStreamConverter.idl - */ - convert: function FC_convert(sourceStream, sourceType, destinationType, - context) { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - }, - - /** - * See nsIStreamConverter.idl - */ - asyncConvertData: function FC_asyncConvertData(sourceType, destinationType, - listener, context) { - this._listener = listener; - }, - - /** - * Whether or not the preview page is being forced. - */ - _forcePreviewPage: false, - - /** - * Release our references to various things once we're done using them. - */ - _releaseHandles: function FC__releaseHandles() { - this._listener = null; - this._request = null; - this._processor = null; - }, - - /** - * See nsIFeedResultListener.idl - */ - handleResult: function FC_handleResult(result) { - // Feeds come in various content types, which our feed sniffer coerces to - // the maybe.feed type. However, feeds are used as a transport for - // different data types, e.g. news/blogs (traditional feed), video/audio - // (podcasts) and photos (photocasts, photostreams). Each of these is - // different in that there's a different class of application suitable for - // handling feeds of that type, but without a content-type differentiation - // it is difficult for us to disambiguate. - // - // The other problem is that if the user specifies an auto-action handler - // for one feed application, the fact that the content type is shared means - // that all other applications will auto-load with that handler too, - // regardless of the content-type. - // - // This means that content-type alone is not enough to determine whether - // or not a feed should be auto-handled. This means that for feeds we need - // to always use this stream converter, even when an auto-action is - // specified, not the basic one provided by WebContentConverter. This - // converter needs to consume all of the data and parse it, and based on - // that determination make a judgment about type. - // - // Since there are no content types for this content, and I'm not going to - // invent any, the upshot is that while a user can set an auto-handler for - // generic feed content, the system will prevent them from setting an auto- - // handler for other stream types. In those cases, the user will always see - // the preview page and have to select a handler. We can guess and show - // a client handler, but will not be able to show web handlers for those - // types. - // - // If this is just a feed, not some kind of specialized application, then - // auto-handlers can be set and we should obey them. - try { - var feedService = - Cc["@mozilla.org/browser/feeds/result-service;1"]. - getService(Ci.nsIFeedResultService); - if (!this._forcePreviewPage && result.doc) { - var feed = result.doc.QueryInterface(Ci.nsIFeed); - var handler = safeGetCharPref(getPrefActionForType(feed.type), "ask"); - - if (handler != "ask") { - if (handler == "reader") - handler = safeGetCharPref(getPrefReaderForType(feed.type), "bookmarks"); - switch (handler) { - case "web": - var wccr = - Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"]. - getService(Ci.nsIWebContentConverterService); - if ((feed.type == Ci.nsIFeed.TYPE_FEED && - wccr.getAutoHandler(TYPE_MAYBE_FEED)) || - (feed.type == Ci.nsIFeed.TYPE_VIDEO && - wccr.getAutoHandler(TYPE_MAYBE_VIDEO_FEED)) || - (feed.type == Ci.nsIFeed.TYPE_AUDIO && - wccr.getAutoHandler(TYPE_MAYBE_AUDIO_FEED))) { - wccr.loadPreferredHandler(this._request); - return; - } - break; - - default: - LOG("unexpected handler: " + handler); - // fall through -- let feed service handle error - case "bookmarks": - case "client": - try { - var title = feed.title ? feed.title.plainText() : ""; - var desc = feed.subtitle ? feed.subtitle.plainText() : ""; - feedService.addToClientReader(result.uri.spec, title, desc, feed.type); - return; - } catch(ex) { /* fallback to preview mode */ } - } - } - } - - var ios = - Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - var chromeChannel; - - // handling a redirect, hence forwarding the loadInfo from the old channel - // to the newchannel. - var oldChannel = this._request.QueryInterface(Ci.nsIChannel); - var loadInfo = oldChannel.loadInfo; - - // If there was no automatic handler, or this was a podcast, - // photostream or some other kind of application, show the preview page - // if the parser returned a document. - if (result.doc) { - - // Store the result in the result service so that the display - // page can access it. - feedService.addFeedResult(result); - - // Now load the actual XUL document. - var aboutFeedsURI = ios.newURI("about:feeds", null, null); - chromeChannel = ios.newChannelFromURIWithLoadInfo(aboutFeedsURI, loadInfo); - chromeChannel.originalURI = result.uri; - chromeChannel.owner = - Services.scriptSecurityManager.getNoAppCodebasePrincipal(aboutFeedsURI); - } else { - chromeChannel = ios.newChannelFromURIWithLoadInfo(result.uri, loadInfo); - } - - chromeChannel.loadGroup = this._request.loadGroup; - chromeChannel.asyncOpen2(this._listener); - } - finally { - this._releaseHandles(); - } - }, - - /** - * See nsIStreamListener.idl - */ - onDataAvailable: function FC_onDataAvailable(request, context, inputStream, - sourceOffset, count) { - if (this._processor) - this._processor.onDataAvailable(request, context, inputStream, - sourceOffset, count); - }, - - /** - * See nsIRequestObserver.idl - */ - onStartRequest: function FC_onStartRequest(request, context) { - var channel = request.QueryInterface(Ci.nsIChannel); - - // Check for a header that tells us there was no sniffing - // The value doesn't matter. - try { - var httpChannel = channel.QueryInterface(Ci.nsIHttpChannel); - // Make sure to check requestSucceeded before the potentially-throwing - // getResponseHeader. - if (!httpChannel.requestSucceeded) { - // Just give up, but don't forget to cancel the channel first! - request.cancel(Cr.NS_BINDING_ABORTED); - return; - } - var noSniff = httpChannel.getResponseHeader("X-Moz-Is-Feed"); - } - catch (ex) { - this._sniffed = true; - } - - this._request = request; - - // Save and reset the forced state bit early, in case there's some kind of - // error. - var feedService = - Cc["@mozilla.org/browser/feeds/result-service;1"]. - getService(Ci.nsIFeedResultService); - this._forcePreviewPage = feedService.forcePreviewPage; - feedService.forcePreviewPage = false; - - // Parse feed data as it comes in - this._processor = - Cc["@mozilla.org/feed-processor;1"]. - createInstance(Ci.nsIFeedProcessor); - this._processor.listener = this; - this._processor.parseAsync(null, channel.URI); - - this._processor.onStartRequest(request, context); - }, - - /** - * See nsIRequestObserver.idl - */ - onStopRequest: function FC_onStopRequest(request, context, status) { - if (this._processor) - this._processor.onStopRequest(request, context, status); - }, - - /** - * See nsISupports.idl - */ - QueryInterface: function FC_QueryInterface(iid) { - if (iid.equals(Ci.nsIFeedResultListener) || - iid.equals(Ci.nsIStreamConverter) || - iid.equals(Ci.nsIStreamListener) || - iid.equals(Ci.nsIRequestObserver)|| - iid.equals(Ci.nsISupports)) - return this; - throw Cr.NS_ERROR_NO_INTERFACE; - }, -}; - -/** - * Keeps parsed FeedResults around for use elsewhere in the UI after the stream - * converter completes. - */ -function FeedResultService() { -} - -FeedResultService.prototype = { - classID: Components.ID("{2376201c-bbc6-472f-9b62-7548040a61c6}"), - - /** - * A URI spec -> [nsIFeedResult] hash. We have to keep a list as the - * value in case the same URI is requested concurrently. - */ - _results: { }, - - /** - * See nsIFeedResultService.idl - */ - forcePreviewPage: false, - - /** - * See nsIFeedResultService.idl - */ - addToClientReader: function FRS_addToClientReader(spec, title, subtitle, feedType) { - var prefs = - Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch); - - var handler = safeGetCharPref(getPrefActionForType(feedType), "bookmarks"); - if (handler == "ask" || handler == "reader") - handler = safeGetCharPref(getPrefReaderForType(feedType), "bookmarks"); - - switch (handler) { - case "client": - var clientApp = prefs.getComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile); - - // For the benefit of applications that might know how to deal with more - // URLs than just feeds, send feed: URLs in the following format: - // - // http urls: replace scheme with feed, e.g. - // http://foo.com/index.rdf -> feed://foo.com/index.rdf - // other urls: prepend feed: scheme, e.g. - // https://foo.com/index.rdf -> feed:https://foo.com/index.rdf - var ios = - Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - var feedURI = ios.newURI(spec, null, null); - if (feedURI.schemeIs("http")) { - feedURI.scheme = "feed"; - spec = feedURI.spec; - } - else - spec = "feed:" + spec; - - // Retrieving the shell service might fail on some systems, most - // notably systems where GNOME is not installed. - try { - var ss = - Cc["@mozilla.org/browser/shell-service;1"]. - getService(Ci.nsIShellService); - ss.openApplicationWithURI(clientApp, spec); - } catch(e) { - // If we couldn't use the shell service, fallback to using a - // nsIProcess instance - var p = - Cc["@mozilla.org/process/util;1"]. - createInstance(Ci.nsIProcess); - p.init(clientApp); - p.run(false, [spec], 1); - } - break; - - default: - // "web" should have been handled elsewhere - LOG("unexpected handler: " + handler); - // fall through - case "bookmarks": - var wm = - Cc["@mozilla.org/appshell/window-mediator;1"]. - getService(Ci.nsIWindowMediator); - var topWindow = wm.getMostRecentWindow("navigator:browser"); - topWindow.PlacesCommandHook.addLiveBookmark(spec, title, subtitle); - break; - } - }, - - /** - * See nsIFeedResultService.idl - */ - addFeedResult: function FRS_addFeedResult(feedResult) { - NS_ASSERT(feedResult.uri != null, "null URI!"); - NS_ASSERT(feedResult.uri != null, "null feedResult!"); - var spec = feedResult.uri.spec; - if(!this._results[spec]) - this._results[spec] = []; - this._results[spec].push(feedResult); - }, - - /** - * See nsIFeedResultService.idl - */ - getFeedResult: function RFS_getFeedResult(uri) { - NS_ASSERT(uri != null, "null URI!"); - var resultList = this._results[uri.spec]; - for (var i in resultList) { - if (resultList[i].uri == uri) - return resultList[i]; - } - return null; - }, - - /** - * See nsIFeedResultService.idl - */ - removeFeedResult: function FRS_removeFeedResult(uri) { - NS_ASSERT(uri != null, "null URI!"); - var resultList = this._results[uri.spec]; - if (!resultList) - return; - var deletions = 0; - for (var i = 0; i < resultList.length; ++i) { - if (resultList[i].uri == uri) { - delete resultList[i]; - ++deletions; - } - } - - // send the holes to the end - resultList.sort(); - // and trim the list - resultList.splice(resultList.length - deletions, deletions); - if (resultList.length == 0) - delete this._results[uri.spec]; - }, - - createInstance: function FRS_createInstance(outer, iid) { - if (outer != null) - throw Cr.NS_ERROR_NO_AGGREGATION; - return this.QueryInterface(iid); - }, - - QueryInterface: function FRS_QueryInterface(iid) { - if (iid.equals(Ci.nsIFeedResultService) || - iid.equals(Ci.nsIFactory) || - iid.equals(Ci.nsISupports)) - return this; - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - }, -}; - -/** - * A protocol handler that attempts to deal with the variant forms of feed: - * URIs that are actually either http or https. - */ -function GenericProtocolHandler() { -} -GenericProtocolHandler.prototype = { - _init: function GPH_init(scheme) { - var ios = - Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - this._http = ios.getProtocolHandler("http"); - this._scheme = scheme; - }, - - get scheme() { - return this._scheme; - }, - - get protocolFlags() { - return this._http.protocolFlags; - }, - - get defaultPort() { - return this._http.defaultPort; - }, - - allowPort: function GPH_allowPort(port, scheme) { - return this._http.allowPort(port, scheme); - }, - - newURI: function GPH_newURI(spec, originalCharset, baseURI) { - // Feed URIs can be either nested URIs of the form feed:realURI (in which - // case we create a nested URI for the realURI) or feed://example.com, in - // which case we create a nested URI for the real protocol which is http. - - var scheme = this._scheme + ":"; - if (spec.substr(0, scheme.length) != scheme) - throw Cr.NS_ERROR_MALFORMED_URI; - - var prefix = spec.substr(scheme.length, 2) == "//" ? "http:" : ""; - var inner = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService).newURI(spec.replace(scheme, prefix), - originalCharset, baseURI); - var netutil = Cc["@mozilla.org/network/util;1"].getService(Ci.nsINetUtil); - const URI_INHERITS_SECURITY_CONTEXT = Ci.nsIProtocolHandler - .URI_INHERITS_SECURITY_CONTEXT; - if (netutil.URIChainHasFlags(inner, URI_INHERITS_SECURITY_CONTEXT)) - throw Cr.NS_ERROR_MALFORMED_URI; - - var uri = netutil.newSimpleNestedURI(inner); - uri.spec = inner.spec.replace(prefix, scheme); - return uri; - }, - - newChannel2: function GPH_newChannel(aUri, aLoadInfo) { - var inner = aUri.QueryInterface(Ci.nsINestedURI).innerURI; - var channel = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService). - newChannelFromURIWithLoadInfo(inner, aLoadInfo); - - if (channel instanceof Components.interfaces.nsIHttpChannel) - // Set this so we know this is supposed to be a feed - channel.setRequestHeader("X-Moz-Is-Feed", "1", false); - channel.originalURI = aUri; - return channel; - }, - - - QueryInterface: function GPH_QueryInterface(iid) { - if (iid.equals(Ci.nsIProtocolHandler) || - iid.equals(Ci.nsISupports)) - return this; - throw Cr.NS_ERROR_NO_INTERFACE; - } -}; - -function FeedProtocolHandler() { - this._init('feed'); -} -FeedProtocolHandler.prototype = new GenericProtocolHandler(); -FeedProtocolHandler.prototype.classID = Components.ID("{4f91ef2e-57ba-472e-ab7a-b4999e42d6c0}"); - -function PodCastProtocolHandler() { - this._init('pcast'); -} -PodCastProtocolHandler.prototype = new GenericProtocolHandler(); -PodCastProtocolHandler.prototype.classID = Components.ID("{1c31ed79-accd-4b94-b517-06e0c81999d5}"); - -var components = [FeedConverter, - FeedResultService, - FeedProtocolHandler, - PodCastProtocolHandler]; - - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components); diff --git a/components/feeds/FeedWriter.js b/components/feeds/FeedWriter.js deleted file mode 100644 index facde58..0000000 --- a/components/feeds/FeedWriter.js +++ /dev/null @@ -1,1397 +0,0 @@ -# -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -# 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/. - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cr = Components.results; -const Cu = Components.utils; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/NetUtil.jsm"); - -const FEEDWRITER_CID = Components.ID("{49bb6593-3aff-4eb3-a068-2712c28bd58e}"); -const FEEDWRITER_CONTRACTID = "@mozilla.org/browser/feeds/result-writer;1"; - -function LOG(str) { - var prefB = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch); - - var shouldLog = prefB.getBoolPref("feeds.log", false); - - if (shouldLog) - dump("*** Feeds: " + str + "\n"); -} - -/** - * Wrapper function for nsIIOService::newURI. - * @param aURLSpec - * The URL string from which to create an nsIURI. - * @returns an nsIURI object, or null if the creation of the URI failed. - */ -function makeURI(aURLSpec, aCharset) { - var ios = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - try { - return ios.newURI(aURLSpec, aCharset, null); - } catch (ex) { } - - return null; -} - -const XML_NS = "http://www.w3.org/XML/1998/namespace"; -const HTML_NS = "http://www.w3.org/1999/xhtml"; -const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; -const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed"; -const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed"; -const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed"; -const URI_BUNDLE = "chrome://browser/locale/feeds/subscribe.properties"; - -const PREF_SELECTED_APP = "browser.feeds.handlers.application"; -const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice"; -const PREF_SELECTED_ACTION = "browser.feeds.handler"; -const PREF_SELECTED_READER = "browser.feeds.handler.default"; - -const PREF_VIDEO_SELECTED_APP = "browser.videoFeeds.handlers.application"; -const PREF_VIDEO_SELECTED_WEB = "browser.videoFeeds.handlers.webservice"; -const PREF_VIDEO_SELECTED_ACTION = "browser.videoFeeds.handler"; -const PREF_VIDEO_SELECTED_READER = "browser.videoFeeds.handler.default"; - -const PREF_AUDIO_SELECTED_APP = "browser.audioFeeds.handlers.application"; -const PREF_AUDIO_SELECTED_WEB = "browser.audioFeeds.handlers.webservice"; -const PREF_AUDIO_SELECTED_ACTION = "browser.audioFeeds.handler"; -const PREF_AUDIO_SELECTED_READER = "browser.audioFeeds.handler.default"; - -const PREF_SHOW_FIRST_RUN_UI = "browser.feeds.showFirstRunUI"; - -const TITLE_ID = "feedTitleText"; -const SUBTITLE_ID = "feedSubtitleText"; - -function getPrefAppForType(t) { - switch (t) { - case Ci.nsIFeed.TYPE_VIDEO: - return PREF_VIDEO_SELECTED_APP; - - case Ci.nsIFeed.TYPE_AUDIO: - return PREF_AUDIO_SELECTED_APP; - - default: - return PREF_SELECTED_APP; - } -} - -function getPrefWebForType(t) { - switch (t) { - case Ci.nsIFeed.TYPE_VIDEO: - return PREF_VIDEO_SELECTED_WEB; - - case Ci.nsIFeed.TYPE_AUDIO: - return PREF_AUDIO_SELECTED_WEB; - - default: - return PREF_SELECTED_WEB; - } -} - -function getPrefActionForType(t) { - switch (t) { - case Ci.nsIFeed.TYPE_VIDEO: - return PREF_VIDEO_SELECTED_ACTION; - - case Ci.nsIFeed.TYPE_AUDIO: - return PREF_AUDIO_SELECTED_ACTION; - - default: - return PREF_SELECTED_ACTION; - } -} - -function getPrefReaderForType(t) { - switch (t) { - case Ci.nsIFeed.TYPE_VIDEO: - return PREF_VIDEO_SELECTED_READER; - - case Ci.nsIFeed.TYPE_AUDIO: - return PREF_AUDIO_SELECTED_READER; - - default: - return PREF_SELECTED_READER; - } -} - -/** - * Converts a number of bytes to the appropriate unit that results in a - * number that needs fewer than 4 digits - * - * @return a pair: [new value with 3 sig. figs., its unit] - */ -function convertByteUnits(aBytes) { - var units = ["bytes", "kilobyte", "megabyte", "gigabyte"]; - let unitIndex = 0; - - // convert to next unit if it needs 4 digits (after rounding), but only if - // we know the name of the next unit - while ((aBytes >= 999.5) && (unitIndex < units.length - 1)) { - aBytes /= 1024; - unitIndex++; - } - - // Get rid of insignificant bits by truncating to 1 or 0 decimal points - // 0 -> 0; 1.2 -> 1.2; 12.3 -> 12.3; 123.4 -> 123; 234.5 -> 235 - aBytes = aBytes.toFixed((aBytes > 0) && (aBytes < 100) ? 1 : 0); - - return [aBytes, units[unitIndex]]; -} - -function FeedWriter() {} -FeedWriter.prototype = { - _mimeSvc : Cc["@mozilla.org/mime;1"]. - getService(Ci.nsIMIMEService), - - _getPropertyAsBag: function FW__getPropertyAsBag(container, property) { - return container.fields.getProperty(property). - QueryInterface(Ci.nsIPropertyBag2); - }, - - _getPropertyAsString: function FW__getPropertyAsString(container, property) { - try { - return container.fields.getPropertyAsAString(property); - } - catch (e) { - } - return ""; - }, - - _setContentText: function FW__setContentText(id, text) { - this._contentSandbox.element = this._document.getElementById(id); - this._contentSandbox.textNode = text.createDocumentFragment(this._contentSandbox.element); - var codeStr = - "while (element.hasChildNodes()) " + - " element.removeChild(element.firstChild);" + - "element.appendChild(textNode);"; - if (text.base) { - this._contentSandbox.spec = text.base.spec; - codeStr += "element.setAttributeNS('" + XML_NS + "', 'base', spec);"; - } - Cu.evalInSandbox(codeStr, this._contentSandbox); - this._contentSandbox.element = null; - this._contentSandbox.textNode = null; - }, - - /** - * Safely sets the href attribute on an anchor tag, providing the URI - * specified can be loaded according to rules. - * @param element - * The element to set a URI attribute on - * @param attribute - * The attribute of the element to set the URI to, e.g. href or src - * @param uri - * The URI spec to set as the href - */ - _safeSetURIAttribute: - function FW__safeSetURIAttribute(element, attribute, uri) { - var secman = Cc["@mozilla.org/scriptsecuritymanager;1"]. - getService(Ci.nsIScriptSecurityManager); - const flags = Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL; - try { - secman.checkLoadURIStrWithPrincipal(this._feedPrincipal, uri, flags); - // checkLoadURIStrWithPrincipal will throw if the link URI should not be - // loaded, either because our feedURI isn't allowed to load it or per - // the rules specified in |flags|, so we'll never "linkify" the link... - } - catch (e) { - // Not allowed to load this link because secman.checkLoadURIStr threw - return; - } - - this._contentSandbox.element = element; - this._contentSandbox.uri = uri; - var codeStr = "element.setAttribute('" + attribute + "', uri);"; - Cu.evalInSandbox(codeStr, this._contentSandbox); - }, - - /** - * Use this sandbox to run any dom manipulation code on nodes which - * are already inserted into the content document. - */ - __contentSandbox: null, - get _contentSandbox() { - // This whole sandbox setup is totally archaic. It was introduced in bug - // 360529, presumably before the existence of a solid security membrane, - // since all of the manipulation of content here should be made safe by - // Xrays. - // Now that anonymous content is no longer content-accessible, manipulating - // the xml stylesheet content can't be done from content anymore. - // - // The right solution would be to rip out all of this sandbox junk and - // manipulate the DOM directly, but that would require a lot of rewriting. - // So, for now, we just give the sandbox an nsExpandedPrincipal with []. - // This has the effect of giving it Xrays, and making it same-origin with - // the XBL scope, thereby letting it manipulate anonymous content. - if (!this.__contentSandbox) - this.__contentSandbox = new Cu.Sandbox([this._window], - {sandboxName: 'FeedWriter'}); - - return this.__contentSandbox; - }, - - /** - * Calls doCommand for a given XUL element within the context of the - * content document. - * - * @param aElement - * the XUL element to call doCommand() on. - */ - _safeDoCommand: function FW___safeDoCommand(aElement) { - this._contentSandbox.element = aElement; - Cu.evalInSandbox("element.doCommand();", this._contentSandbox); - this._contentSandbox.element = null; - }, - - __faviconService: null, - get _faviconService() { - if (!this.__faviconService) - this.__faviconService = Cc["@mozilla.org/browser/favicon-service;1"]. - getService(Ci.nsIFaviconService); - - return this.__faviconService; - }, - - __bundle: null, - get _bundle() { - if (!this.__bundle) { - this.__bundle = Cc["@mozilla.org/intl/stringbundle;1"]. - getService(Ci.nsIStringBundleService). - createBundle(URI_BUNDLE); - } - return this.__bundle; - }, - - _getFormattedString: function FW__getFormattedString(key, params) { - return this._bundle.formatStringFromName(key, params, params.length); - }, - - _getString: function FW__getString(key) { - return this._bundle.GetStringFromName(key); - }, - - /* Magic helper methods to be used instead of xbl properties */ - _getSelectedItemFromMenulist: function FW__getSelectedItemFromList(aList) { - var node = aList.firstChild.firstChild; - while (node) { - if (node.localName == "menuitem" && node.getAttribute("selected") == "true") - return node; - - node = node.nextSibling; - } - - return null; - }, - - _setCheckboxCheckedState: function FW__setCheckboxCheckedState(aCheckbox, aValue) { - // see checkbox.xml, xbl bindings are not applied within the sandbox! - this._contentSandbox.checkbox = aCheckbox; - var codeStr; - var change = (aValue != (aCheckbox.getAttribute('checked') == 'true')); - if (aValue) - codeStr = "checkbox.setAttribute('checked', 'true'); "; - else - codeStr = "checkbox.removeAttribute('checked'); "; - - if (change) { - this._contentSandbox.document = this._document; - codeStr += "var event = document.createEvent('Events'); " + - "event.initEvent('CheckboxStateChange', true, true);" + - "checkbox.dispatchEvent(event);" - } - - Cu.evalInSandbox(codeStr, this._contentSandbox); - }, - - /** - * Returns a date suitable for displaying in the feed preview. - * If the date cannot be parsed, the return value is "false". - * @param dateString - * A date as extracted from a feed entry. (entry.updated) - */ - _parseDate: function FW__parseDate(dateString) { - // Convert the date into the user's local time zone - dateObj = new Date(dateString); - - // Make sure the date we're given is valid. - if (!dateObj.getTime()) - return false; - - var dateService = Cc["@mozilla.org/intl/scriptabledateformat;1"]. - getService(Ci.nsIScriptableDateFormat); - return dateService.FormatDateTime("", dateService.dateFormatLong, dateService.timeFormatNoSeconds, - dateObj.getFullYear(), dateObj.getMonth()+1, dateObj.getDate(), - dateObj.getHours(), dateObj.getMinutes(), dateObj.getSeconds()); - }, - - /** - * Returns the feed type. - */ - __feedType: null, - _getFeedType: function FW__getFeedType() { - if (this.__feedType != null) - return this.__feedType; - - try { - // grab the feed because it's got the feed.type in it. - var container = this._getContainer(); - var feed = container.QueryInterface(Ci.nsIFeed); - this.__feedType = feed.type; - return feed.type; - } catch (ex) { } - - return Ci.nsIFeed.TYPE_FEED; - }, - - /** - * Maps a feed type to a maybe-feed mimetype. - */ - _getMimeTypeForFeedType: function FW__getMimeTypeForFeedType() { - switch (this._getFeedType()) { - case Ci.nsIFeed.TYPE_VIDEO: - return TYPE_MAYBE_VIDEO_FEED; - - case Ci.nsIFeed.TYPE_AUDIO: - return TYPE_MAYBE_AUDIO_FEED; - - default: - return TYPE_MAYBE_FEED; - } - }, - - /** - * Writes the feed title into the preview document. - * @param container - * The feed container - */ - _setTitleText: function FW__setTitleText(container) { - if (container.title) { - var title = container.title.plainText(); - this._setContentText(TITLE_ID, container.title); - this._contentSandbox.document = this._document; - this._contentSandbox.title = title; - var codeStr = "document.title = title;" - Cu.evalInSandbox(codeStr, this._contentSandbox); - } - - var feed = container.QueryInterface(Ci.nsIFeed); - if (feed && feed.subtitle) - this._setContentText(SUBTITLE_ID, container.subtitle); - }, - - /** - * Writes the title image into the preview document if one is present. - * @param container - * The feed container - */ - _setTitleImage: function FW__setTitleImage(container) { - try { - var parts = container.image; - - // Set up the title image (supplied by the feed) - var feedTitleImage = this._document.getElementById("feedTitleImage"); - this._safeSetURIAttribute(feedTitleImage, "src", - parts.getPropertyAsAString("url")); - - // Set up the title image link - var feedTitleLink = this._document.getElementById("feedTitleLink"); - - var titleText = this._getFormattedString("linkTitleTextFormat", - [parts.getPropertyAsAString("title")]); - this._contentSandbox.feedTitleLink = feedTitleLink; - this._contentSandbox.titleText = titleText; - this._contentSandbox.feedTitleText = this._document.getElementById("feedTitleText"); - this._contentSandbox.titleImageWidth = parseInt(parts.getPropertyAsAString("width")) + 15; - - // Fix the margin on the main title, so that the image doesn't run over - // the underline - var codeStr = "feedTitleLink.setAttribute('title', titleText); " + - "feedTitleText.style.marginRight = titleImageWidth + 'px';"; - Cu.evalInSandbox(codeStr, this._contentSandbox); - this._contentSandbox.feedTitleLink = null; - this._contentSandbox.titleText = null; - this._contentSandbox.feedTitleText = null; - this._contentSandbox.titleImageWidth = null; - - this._safeSetURIAttribute(feedTitleLink, "href", - parts.getPropertyAsAString("link")); - } - catch (e) { - LOG("Failed to set Title Image (this is benign): " + e); - } - }, - - /** - * Writes all entries contained in the feed. - * @param container - * The container of entries in the feed - */ - _writeFeedContent: function FW__writeFeedContent(container) { - // Build the actual feed content - var feed = container.QueryInterface(Ci.nsIFeed); - if (feed.items.length == 0) - return; - - this._contentSandbox.feedContent = - this._document.getElementById("feedContent"); - - for (var i = 0; i < feed.items.length; ++i) { - var entry = feed.items.queryElementAt(i, Ci.nsIFeedEntry); - entry.QueryInterface(Ci.nsIFeedContainer); - - var entryContainer = this._document.createElementNS(HTML_NS, "div"); - entryContainer.className = "entry"; - - // If the entry has a title, make it a link - if (entry.title) { - var a = this._document.createElementNS(HTML_NS, "a"); - var span = this._document.createElementNS(HTML_NS, "span"); - a.appendChild(span); - if (entry.title.base) - span.setAttributeNS(XML_NS, "base", entry.title.base.spec); - span.appendChild(entry.title.createDocumentFragment(a)); - - // Entries are not required to have links, so entry.link can be null. - if (entry.link) - this._safeSetURIAttribute(a, "href", entry.link.spec); - - var title = this._document.createElementNS(HTML_NS, "h3"); - title.appendChild(a); - - var lastUpdated = this._parseDate(entry.updated); - if (lastUpdated) { - var dateDiv = this._document.createElementNS(HTML_NS, "div"); - dateDiv.className = "lastUpdated"; - dateDiv.textContent = lastUpdated; - title.appendChild(dateDiv); - } - - entryContainer.appendChild(title); - } - - var body = this._document.createElementNS(HTML_NS, "div"); - var summary = entry.summary || entry.content; - var docFragment = null; - if (summary) { - if (summary.base) - body.setAttributeNS(XML_NS, "base", summary.base.spec); - else - LOG("no base?"); - docFragment = summary.createDocumentFragment(body); - if (docFragment) - body.appendChild(docFragment); - - // If the entry doesn't have a title, append a # permalink - // See http://scripting.com/rss.xml for an example - if (!entry.title && entry.link) { - var a = this._document.createElementNS(HTML_NS, "a"); - a.appendChild(this._document.createTextNode("#")); - this._safeSetURIAttribute(a, "href", entry.link.spec); - body.appendChild(this._document.createTextNode(" ")); - body.appendChild(a); - } - - } - body.className = "feedEntryContent"; - entryContainer.appendChild(body); - - if (entry.enclosures && entry.enclosures.length > 0) { - var enclosuresDiv = this._buildEnclosureDiv(entry); - entryContainer.appendChild(enclosuresDiv); - } - - this._contentSandbox.entryContainer = entryContainer; - this._contentSandbox.clearDiv = - this._document.createElementNS(HTML_NS, "div"); - this._contentSandbox.clearDiv.style.clear = "both"; - - var codeStr = "feedContent.appendChild(entryContainer); " + - "feedContent.appendChild(clearDiv);" - Cu.evalInSandbox(codeStr, this._contentSandbox); - } - - this._contentSandbox.feedContent = null; - this._contentSandbox.entryContainer = null; - this._contentSandbox.clearDiv = null; - }, - - /** - * Takes a url to a media item and returns the best name it can come up with. - * Frequently this is the filename portion (e.g. passing in - * http://example.com/foo.mpeg would return "foo.mpeg"), but in more complex - * cases, this will return the entire url (e.g. passing in - * http://example.com/somedirectory/ would return - * http://example.com/somedirectory/). - * @param aURL - * The URL string from which to create a display name - * @returns a string - */ - _getURLDisplayName: function FW__getURLDisplayName(aURL) { - var url = makeURI(aURL); - url.QueryInterface(Ci.nsIURL); - if (url == null || url.fileName.length == 0) - return decodeURIComponent(aURL); - - return decodeURIComponent(url.fileName); - }, - - /** - * Takes a FeedEntry with enclosures, generates the HTML code to represent - * them, and returns that. - * @param entry - * FeedEntry with enclosures - * @returns element - */ - _buildEnclosureDiv: function FW__buildEnclosureDiv(entry) { - var enclosuresDiv = this._document.createElementNS(HTML_NS, "div"); - enclosuresDiv.className = "enclosures"; - - enclosuresDiv.appendChild(this._document.createTextNode(this._getString("mediaLabel"))); - - var roundme = function(n) { - return (Math.round(n * 100) / 100).toLocaleString(); - } - - for (var i_enc = 0; i_enc < entry.enclosures.length; ++i_enc) { - var enc = entry.enclosures.queryElementAt(i_enc, Ci.nsIWritablePropertyBag2); - - if (!(enc.hasKey("url"))) - continue; - - var enclosureDiv = this._document.createElementNS(HTML_NS, "div"); - enclosureDiv.setAttribute("class", "enclosure"); - - var mozicon = "moz-icon://.txt?size=16"; - var type_text = null; - var size_text = null; - - if (enc.hasKey("type")) { - type_text = enc.get("type"); - try { - var handlerInfoWrapper = this._mimeSvc.getFromTypeAndExtension(enc.get("type"), null); - - if (handlerInfoWrapper) - type_text = handlerInfoWrapper.description; - - if (type_text && type_text.length > 0) - mozicon = "moz-icon://goat?size=16&contentType=" + enc.get("type"); - - } catch (ex) { } - - } - - if (enc.hasKey("length") && /^[0-9]+$/.test(enc.get("length"))) { - var enc_size = convertByteUnits(parseInt(enc.get("length"))); - - var size_text = this._getFormattedString("enclosureSizeText", - [enc_size[0], this._getString(enc_size[1])]); - } - - var iconimg = this._document.createElementNS(HTML_NS, "img"); - iconimg.setAttribute("src", mozicon); - iconimg.setAttribute("class", "type-icon"); - enclosureDiv.appendChild(iconimg); - - enclosureDiv.appendChild(this._document.createTextNode( " " )); - - var enc_href = this._document.createElementNS(HTML_NS, "a"); - enc_href.appendChild(this._document.createTextNode(this._getURLDisplayName(enc.get("url")))); - this._safeSetURIAttribute(enc_href, "href", enc.get("url")); - enclosureDiv.appendChild(enc_href); - - if (type_text && size_text) - enclosureDiv.appendChild(this._document.createTextNode( " (" + type_text + ", " + size_text + ")")); - - else if (type_text) - enclosureDiv.appendChild(this._document.createTextNode( " (" + type_text + ")")) - - else if (size_text) - enclosureDiv.appendChild(this._document.createTextNode( " (" + size_text + ")")) - - enclosuresDiv.appendChild(enclosureDiv); - } - - return enclosuresDiv; - }, - - /** - * Gets a valid nsIFeedContainer object from the parsed nsIFeedResult. - * Displays error information if there was one. - * @param result - * The parsed feed result - * @returns A valid nsIFeedContainer object containing the contents of - * the feed. - */ - _getContainer: function FW__getContainer(result) { - var feedService = - Cc["@mozilla.org/browser/feeds/result-service;1"]. - getService(Ci.nsIFeedResultService); - - result = null; - try { - result = - feedService.getFeedResult(this._getOriginalURI(this._window)); - } - catch (e) { - // Ignore. - } - - if (!result) { - LOG("Subscribe Preview: feed not available?!"); - return null; - } - - if (result.bozo) { - LOG("Subscribe Preview: feed result is bozo?!"); - } - - try { - var container = result.doc; - } - catch (e) { - LOG("Subscribe Preview: no result.doc? Why didn't the original reload?"); - return null; - } - return container; - }, - - /** - * Get the human-readable display name of a file. This could be the - * application name. - * @param file - * A nsIFile to look up the name of - * @returns The display name of the application represented by the file. - */ - _getFileDisplayName: function FW__getFileDisplayName(file) { -#ifdef XP_WIN - if (file instanceof Ci.nsILocalFileWin) { - try { - return file.getVersionInfoField("FileDescription"); - } catch (e) {} - } -#endif -#ifdef XP_MACOSX - if (file instanceof Ci.nsILocalFileMac) { - try { - return file.bundleDisplayName; - } catch (e) {} - } -#endif - return file.leafName; - }, - - /** - * Helper method to set the selected application and system default - * reader menuitems details from a file object - * @param aMenuItem - * The menuitem on which the attributes should be set - * @param aFile - * The menuitem's associated file - */ - _initMenuItemWithFile: function(aMenuItem, aFile) { - this._contentSandbox.menuitem = aMenuItem; - this._contentSandbox.label = this._getFileDisplayName(aFile); - // For security reasons, access to moz-icon:file://... URIs is - // no longer allowed (indirect file system access from content). - // We use a dummy application instead to get a generic icon. - this._contentSandbox.image = "moz-icon://dummy.exe?size=16"; - var codeStr = "menuitem.setAttribute('label', label); " + - "menuitem.setAttribute('image', image);" - Cu.evalInSandbox(codeStr, this._contentSandbox); - }, - - /** - * Helper method to get an element in the XBL binding where the handler - * selection UI lives - */ - _getUIElement: function FW__getUIElement(id) { - return this._document.getAnonymousElementByAttribute( - this._document.getElementById("feedSubscribeLine"), "anonid", id); - }, - - /** - * Displays a prompt from which the user may choose a (client) feed reader. - * @param aCallback the callback method, passes in true if a feed reader was - * selected, false otherwise. - */ - _chooseClientApp: function FW__chooseClientApp(aCallback) { - try { - let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); - let fpCallback = function fpCallback_done(aResult) { - if (aResult == Ci.nsIFilePicker.returnOK) { - this._selectedApp = fp.file; - if (this._selectedApp) { - // XXXben - we need to compare this with the running instance - // executable just don't know how to do that via script - // XXXmano TBD: can probably add this to nsIShellService -#ifdef XP_WIN -#expand if (fp.file.leafName != "__MOZ_APP_NAME__.exe") { -#else -#ifdef XP_MACOSX -#expand if (fp.file.leafName != "__MOZ_MACBUNDLE_NAME__") { -#else -#expand if (fp.file.leafName != "__MOZ_APP_NAME__-bin") { -#endif -#endif - this._initMenuItemWithFile(this._contentSandbox.selectedAppMenuItem, - this._selectedApp); - - // Show and select the selected application menuitem - let codeStr = "selectedAppMenuItem.hidden = false;" + - "selectedAppMenuItem.doCommand();" - Cu.evalInSandbox(codeStr, this._contentSandbox); - if (aCallback) { - aCallback(true); - return; - } - } - } - } - if (aCallback) { - aCallback(false); - } - }.bind(this); - - fp.init(this._window, this._getString("chooseApplicationDialogTitle"), - Ci.nsIFilePicker.modeOpen); - fp.appendFilters(Ci.nsIFilePicker.filterApps); - fp.open(fpCallback); - } catch(ex) { - } - }, - - _setAlwaysUseCheckedState: function FW__setAlwaysUseCheckedState(feedType) { - var checkbox = this._getUIElement("alwaysUse"); - if (checkbox) { - var alwaysUse = false; - try { - var prefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch); - if (prefs.getCharPref(getPrefActionForType(feedType)) != "ask") - alwaysUse = true; - } - catch(ex) { } - this._setCheckboxCheckedState(checkbox, alwaysUse); - } - }, - - _setSubscribeUsingLabel: function FW__setSubscribeUsingLabel() { - var stringLabel = "subscribeFeedUsing"; - switch (this._getFeedType()) { - case Ci.nsIFeed.TYPE_VIDEO: - stringLabel = "subscribeVideoPodcastUsing"; - break; - - case Ci.nsIFeed.TYPE_AUDIO: - stringLabel = "subscribeAudioPodcastUsing"; - break; - } - - this._contentSandbox.subscribeUsing = - this._getUIElement("subscribeUsingDescription"); - this._contentSandbox.label = this._getString(stringLabel); - var codeStr = "subscribeUsing.setAttribute('value', label);" - Cu.evalInSandbox(codeStr, this._contentSandbox); - }, - - _setAlwaysUseLabel: function FW__setAlwaysUseLabel() { - var checkbox = this._getUIElement("alwaysUse"); - if (checkbox) { - if (this._handlersMenuList) { - var handlerName = this._getSelectedItemFromMenulist(this._handlersMenuList) - .getAttribute("label"); - var stringLabel = "alwaysUseForFeeds"; - switch (this._getFeedType()) { - case Ci.nsIFeed.TYPE_VIDEO: - stringLabel = "alwaysUseForVideoPodcasts"; - break; - - case Ci.nsIFeed.TYPE_AUDIO: - stringLabel = "alwaysUseForAudioPodcasts"; - break; - } - - this._contentSandbox.checkbox = checkbox; - this._contentSandbox.label = this._getFormattedString(stringLabel, [handlerName]); - - var codeStr = "checkbox.setAttribute('label', label);"; - Cu.evalInSandbox(codeStr, this._contentSandbox); - } - } - }, - - // nsIDomEventListener - handleEvent: function(event) { - if (event.target.ownerDocument != this._document) { - LOG("FeedWriter.handleEvent: Someone passed the feed writer as a listener to the events of another document!"); - return; - } - - if (event.type == "command") { - switch (event.target.getAttribute("anonid")) { - case "subscribeButton": - this.subscribe(); - break; - case "chooseApplicationMenuItem": - /* Bug 351263: Make sure to not steal focus if the "Choose - * Application" item is being selected with the keyboard. We do this - * by ignoring command events while the dropdown is closed (user - * arrowing through the combobox), but handling them while the - * combobox dropdown is open (user pressed enter when an item was - * selected). If we don't show the filepicker here, it will be shown - * when clicking "Subscribe Now". - */ - var popupbox = this._handlersMenuList.firstChild.boxObject; - if (popupbox.popupState == "hiding") { - this._chooseClientApp(function(aResult) { - if (!aResult) { - // Select the (per-prefs) selected handler if no application - // was selected - this._setSelectedHandler(this._getFeedType()); - } - }.bind(this)); - } - break; - default: - this._setAlwaysUseLabel(); - } - } - }, - - _setSelectedHandler: function FW__setSelectedHandler(feedType) { - var prefs = - Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch); - - var handler = prefs.getCharPref(getPrefReaderForType(feedType), "bookmarks"); - - switch (handler) { - case "web": { - if (this._handlersMenuList) { - var url; - try { - url = prefs.getComplexValue(getPrefWebForType(feedType), Ci.nsISupportsString).data; - } catch (ex) { - LOG("FeedWriter._setSelectedHandler: invalid or no handler in prefs"); - return; - } - var handlers = - this._handlersMenuList.getElementsByAttribute("webhandlerurl", url); - if (handlers.length == 0) { - LOG("FeedWriter._setSelectedHandler: selected web handler isn't in the menulist") - return; - } - - this._safeDoCommand(handlers[0]); - } - break; - } - case "client": { - try { - this._selectedApp = - prefs.getComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile); - } - catch(ex) { - this._selectedApp = null; - } - - if (this._selectedApp) { - this._initMenuItemWithFile(this._contentSandbox.selectedAppMenuItem, - this._selectedApp); - var codeStr = "selectedAppMenuItem.hidden = false; " + - "selectedAppMenuItem.doCommand(); "; - - // Only show the default reader menuitem if the default reader - // isn't the selected application - if (this._defaultSystemReader) { - var shouldHide = - this._defaultSystemReader.path == this._selectedApp.path; - codeStr += "defaultHandlerMenuItem.hidden = " + shouldHide + ";" - } - Cu.evalInSandbox(codeStr, this._contentSandbox); - break; - } - } - case "bookmarks": - default: { - var liveBookmarksMenuItem = this._getUIElement("liveBookmarksMenuItem"); - if (liveBookmarksMenuItem) - this._safeDoCommand(liveBookmarksMenuItem); - } - } - }, - - _initSubscriptionUI: function FW__initSubscriptionUI() { - var handlersMenuPopup = this._getUIElement("handlersMenuPopup"); - if (!handlersMenuPopup) - return; - - var feedType = this._getFeedType(); - var codeStr; - - // change the background - var header = this._document.getElementById("feedHeader"); - this._contentSandbox.header = header; - switch (feedType) { - case Ci.nsIFeed.TYPE_VIDEO: - codeStr = "header.className = 'videoPodcastBackground'; "; - break; - - case Ci.nsIFeed.TYPE_AUDIO: - codeStr = "header.className = 'audioPodcastBackground'; "; - break; - - default: - codeStr = "header.className = 'feedBackground'; "; - } - - var liveBookmarksMenuItem = this._getUIElement("liveBookmarksMenuItem"); - - // Last-selected application - var menuItem = liveBookmarksMenuItem.cloneNode(false); - menuItem.removeAttribute("selected"); - menuItem.setAttribute("anonid", "selectedAppMenuItem"); - menuItem.className = "menuitem-iconic selectedAppMenuItem"; - menuItem.setAttribute("handlerType", "client"); - try { - var prefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch); - this._selectedApp = prefs.getComplexValue(getPrefAppForType(feedType), - Ci.nsILocalFile); - - if (this._selectedApp.exists()) - this._initMenuItemWithFile(menuItem, this._selectedApp); - else { - // Hide the menuitem if the last selected application doesn't exist - menuItem.setAttribute("hidden", true); - } - } - catch(ex) { - // Hide the menuitem until an application is selected - menuItem.setAttribute("hidden", true); - } - this._contentSandbox.handlersMenuPopup = handlersMenuPopup; - this._contentSandbox.selectedAppMenuItem = menuItem; - - codeStr += "handlersMenuPopup.appendChild(selectedAppMenuItem); "; - - // List the default feed reader - try { - this._defaultSystemReader = Cc["@mozilla.org/browser/shell-service;1"]. - getService(Ci.nsIShellService). - defaultFeedReader; - menuItem = liveBookmarksMenuItem.cloneNode(false); - menuItem.removeAttribute("selected"); - menuItem.setAttribute("anonid", "defaultHandlerMenuItem"); - menuItem.className = "menuitem-iconic defaultHandlerMenuItem"; - menuItem.setAttribute("handlerType", "client"); - - this._initMenuItemWithFile(menuItem, this._defaultSystemReader); - - // Hide the default reader item if it points to the same application - // as the last-selected application - if (this._selectedApp && - this._selectedApp.path == this._defaultSystemReader.path) - menuItem.hidden = true; - } - catch(ex) { menuItem = null; /* no default reader */ } - - if (menuItem) { - this._contentSandbox.defaultHandlerMenuItem = menuItem; - codeStr += "handlersMenuPopup.appendChild(defaultHandlerMenuItem); "; - } - - // "Choose Application..." menuitem - menuItem = liveBookmarksMenuItem.cloneNode(false); - menuItem.removeAttribute("selected"); - menuItem.setAttribute("anonid", "chooseApplicationMenuItem"); - menuItem.className = "menuitem-iconic chooseApplicationMenuItem"; - menuItem.setAttribute("label", this._getString("chooseApplicationMenuItem")); - - this._contentSandbox.chooseAppMenuItem = menuItem; - codeStr += "handlersMenuPopup.appendChild(chooseAppMenuItem); "; - - // separator - this._contentSandbox.chooseAppSep = - menuItem = liveBookmarksMenuItem.nextSibling.cloneNode(false); - codeStr += "handlersMenuPopup.appendChild(chooseAppSep); "; - - Cu.evalInSandbox(codeStr, this._contentSandbox); - - // List of web handlers - var wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"]. - getService(Ci.nsIWebContentConverterService); - var handlers = wccr.getContentHandlers(this._getMimeTypeForFeedType(feedType)); - if (handlers.length != 0) { - for (var i = 0; i < handlers.length; ++i) { - if (!handlers[i].uri) { - LOG("Handler with name " + handlers[i].name + " has no URI!? Skipping..."); - continue; - } - menuItem = liveBookmarksMenuItem.cloneNode(false); - menuItem.removeAttribute("selected"); - menuItem.className = "menuitem-iconic"; - menuItem.setAttribute("label", handlers[i].name); - menuItem.setAttribute("handlerType", "web"); - menuItem.setAttribute("webhandlerurl", handlers[i].uri); - this._contentSandbox.menuItem = menuItem; - codeStr = "handlersMenuPopup.appendChild(menuItem);"; - Cu.evalInSandbox(codeStr, this._contentSandbox); - - this._setFaviconForWebReader(handlers[i].uri, menuItem); - } - this._contentSandbox.menuItem = null; - } - - this._setSelectedHandler(feedType); - - // "Subscribe using..." - this._setSubscribeUsingLabel(); - - // "Always use..." checkbox initial state - this._setAlwaysUseCheckedState(feedType); - this._setAlwaysUseLabel(); - - // We update the "Always use.." checkbox label whenever the selected item - // in the list is changed - handlersMenuPopup.addEventListener("command", this, false); - - // Set up the "Subscribe Now" button - this._getUIElement("subscribeButton") - .addEventListener("command", this, false); - - // first-run ui - var showFirstRunUI = prefs.getBoolPref(PREF_SHOW_FIRST_RUN_UI, true); - if (showFirstRunUI) { - var textfeedinfo1, textfeedinfo2; - switch (feedType) { - case Ci.nsIFeed.TYPE_VIDEO: - textfeedinfo1 = "feedSubscriptionVideoPodcast1"; - textfeedinfo2 = "feedSubscriptionVideoPodcast2"; - break; - case Ci.nsIFeed.TYPE_AUDIO: - textfeedinfo1 = "feedSubscriptionAudioPodcast1"; - textfeedinfo2 = "feedSubscriptionAudioPodcast2"; - break; - default: - textfeedinfo1 = "feedSubscriptionFeed1"; - textfeedinfo2 = "feedSubscriptionFeed2"; - } - - this._contentSandbox.feedinfo1 = - this._document.getElementById("feedSubscriptionInfo1"); - this._contentSandbox.feedinfo1Str = this._getString(textfeedinfo1); - this._contentSandbox.feedinfo2 = - this._document.getElementById("feedSubscriptionInfo2"); - this._contentSandbox.feedinfo2Str = this._getString(textfeedinfo2); - this._contentSandbox.header = header; - codeStr = "feedinfo1.textContent = feedinfo1Str; " + - "feedinfo2.textContent = feedinfo2Str; " + - "header.setAttribute('firstrun', 'true');" - Cu.evalInSandbox(codeStr, this._contentSandbox); - prefs.setBoolPref(PREF_SHOW_FIRST_RUN_UI, false); - } - }, - - /** - * Returns the original URI object of the feed and ensures that this - * component is only ever invoked from the preview document. - * @param aWindow - * The window of the document invoking the BrowserFeedWriter - */ - _getOriginalURI: function FW__getOriginalURI(aWindow) { - var chan = aWindow.QueryInterface(Ci.nsIInterfaceRequestor). - getInterface(Ci.nsIWebNavigation). - QueryInterface(Ci.nsIDocShell).currentDocumentChannel; - - var nullPrincipal = Cc["@mozilla.org/nullprincipal;1"]. - createInstance(Ci.nsIPrincipal); - - // this channel is not going to be openend, use a nullPrincipal - // and the most restrctive securityFlag. - let resolvedURI = NetUtil.newChannel({ - uri: "about:feeds", - loadingPrincipal: nullPrincipal, - securityFlags: Ci.nsILoadInfo.SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED, - contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER - }).URI; - - if (resolvedURI.equals(chan.URI)) - return chan.originalURI; - - return null; - }, - - _window: null, - _document: null, - _feedURI: null, - _feedPrincipal: null, - _handlersMenuList: null, - - // BrowserFeedWriter WebIDL methods - init: function FW_init(aWindow) { - var window = aWindow; - this._feedURI = this._getOriginalURI(window); - if (!this._feedURI) - return; - - this._window = window; - this._document = window.document; - this._document.getElementById("feedSubscribeLine").offsetTop; - this._handlersMenuList = this._getUIElement("handlersMenuList"); - - var secman = Cc["@mozilla.org/scriptsecuritymanager;1"]. - getService(Ci.nsIScriptSecurityManager); - this._feedPrincipal = secman.createCodebasePrincipal(this._feedURI, {}); - - LOG("Subscribe Preview: feed uri = " + this._window.location.href); - - // Set up the subscription UI - this._initSubscriptionUI(); - var prefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch); - prefs.addObserver(PREF_SELECTED_ACTION, this, false); - prefs.addObserver(PREF_SELECTED_READER, this, false); - prefs.addObserver(PREF_SELECTED_WEB, this, false); - prefs.addObserver(PREF_SELECTED_APP, this, false); - prefs.addObserver(PREF_VIDEO_SELECTED_ACTION, this, false); - prefs.addObserver(PREF_VIDEO_SELECTED_READER, this, false); - prefs.addObserver(PREF_VIDEO_SELECTED_WEB, this, false); - prefs.addObserver(PREF_VIDEO_SELECTED_APP, this, false); - - prefs.addObserver(PREF_AUDIO_SELECTED_ACTION, this, false); - prefs.addObserver(PREF_AUDIO_SELECTED_READER, this, false); - prefs.addObserver(PREF_AUDIO_SELECTED_WEB, this, false); - prefs.addObserver(PREF_AUDIO_SELECTED_APP, this, false); - }, - - writeContent: function FW_writeContent() { - if (!this._window) - return; - - try { - // Set up the feed content - var container = this._getContainer(); - if (!container) - return; - - this._setTitleText(container); - this._setTitleImage(container); - this._writeFeedContent(container); - } - finally { - this._removeFeedFromCache(); - } - }, - - close: function FW_close() { - this._getUIElement("handlersMenuPopup") - .removeEventListener("command", this, false); - this._getUIElement("subscribeButton") - .removeEventListener("command", this, false); - this._document = null; - this._window = null; - var prefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch); - prefs.removeObserver(PREF_SELECTED_ACTION, this); - prefs.removeObserver(PREF_SELECTED_READER, this); - prefs.removeObserver(PREF_SELECTED_WEB, this); - prefs.removeObserver(PREF_SELECTED_APP, this); - prefs.removeObserver(PREF_VIDEO_SELECTED_ACTION, this); - prefs.removeObserver(PREF_VIDEO_SELECTED_READER, this); - prefs.removeObserver(PREF_VIDEO_SELECTED_WEB, this); - prefs.removeObserver(PREF_VIDEO_SELECTED_APP, this); - - prefs.removeObserver(PREF_AUDIO_SELECTED_ACTION, this); - prefs.removeObserver(PREF_AUDIO_SELECTED_READER, this); - prefs.removeObserver(PREF_AUDIO_SELECTED_WEB, this); - prefs.removeObserver(PREF_AUDIO_SELECTED_APP, this); - - this._removeFeedFromCache(); - this.__faviconService = null; - this.__bundle = null; - this._feedURI = null; - this.__contentSandbox = null; - }, - - _removeFeedFromCache: function FW__removeFeedFromCache() { - if (this._feedURI) { - var feedService = Cc["@mozilla.org/browser/feeds/result-service;1"]. - getService(Ci.nsIFeedResultService); - feedService.removeFeedResult(this._feedURI); - this._feedURI = null; - } - }, - - subscribe: function FW_subscribe() { - var feedType = this._getFeedType(); - - // Subscribe to the feed using the selected handler and save prefs - var prefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch); - var defaultHandler = "reader"; - var useAsDefault = this._getUIElement("alwaysUse").getAttribute("checked"); - - var selectedItem = this._getSelectedItemFromMenulist(this._handlersMenuList); - let subscribeCallback = function() { - if (selectedItem.hasAttribute("webhandlerurl")) { - var webURI = selectedItem.getAttribute("webhandlerurl"); - prefs.setCharPref(getPrefReaderForType(feedType), "web"); - - var supportsString = Cc["@mozilla.org/supports-string;1"]. - createInstance(Ci.nsISupportsString); - supportsString.data = webURI; - prefs.setComplexValue(getPrefWebForType(feedType), Ci.nsISupportsString, - supportsString); - - var wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"]. - getService(Ci.nsIWebContentConverterService); - var handler = wccr.getWebContentHandlerByURI(this._getMimeTypeForFeedType(feedType), webURI); - if (handler) { - if (useAsDefault) { - wccr.setAutoHandler(this._getMimeTypeForFeedType(feedType), handler); - } - - this._window.location.href = handler.getHandlerURI(this._window.location.href); - } - } else { - switch (selectedItem.getAttribute("anonid")) { - case "selectedAppMenuItem": - prefs.setComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile, - this._selectedApp); - prefs.setCharPref(getPrefReaderForType(feedType), "client"); - break; - case "defaultHandlerMenuItem": - prefs.setComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile, - this._defaultSystemReader); - prefs.setCharPref(getPrefReaderForType(feedType), "client"); - break; - case "liveBookmarksMenuItem": - defaultHandler = "bookmarks"; - prefs.setCharPref(getPrefReaderForType(feedType), "bookmarks"); - break; - } - var feedService = Cc["@mozilla.org/browser/feeds/result-service;1"]. - getService(Ci.nsIFeedResultService); - - // Pull the title and subtitle out of the document - var feedTitle = this._document.getElementById(TITLE_ID).textContent; - var feedSubtitle = this._document.getElementById(SUBTITLE_ID).textContent; - feedService.addToClientReader(this._window.location.href, feedTitle, feedSubtitle, feedType); - } - - // If "Always use..." is checked, we should set PREF_*SELECTED_ACTION - // to either "reader" (If a web reader or if an application is selected), - // or to "bookmarks" (if the live bookmarks option is selected). - // Otherwise, we should set it to "ask" - if (useAsDefault) { - prefs.setCharPref(getPrefActionForType(feedType), defaultHandler); - } else { - prefs.setCharPref(getPrefActionForType(feedType), "ask"); - } - }.bind(this); - - // Show the file picker before subscribing if the - // choose application menuitem was chosen using the keyboard - if (selectedItem.getAttribute("anonid") == "chooseApplicationMenuItem") { - this._chooseClientApp(function(aResult) { - if (aResult) { - selectedItem = - this._getSelectedItemFromMenulist(this._handlersMenuList); - subscribeCallback(); - } - }.bind(this)); - } else { - subscribeCallback(); - } - }, - - // nsIObserver - observe: function FW_observe(subject, topic, data) { - if (!this._window) { - // this._window is null unless this.init was called with a trusted - // window object. - return; - } - - var feedType = this._getFeedType(); - - if (topic == "nsPref:changed") { - switch (data) { - case PREF_SELECTED_READER: - case PREF_SELECTED_WEB: - case PREF_SELECTED_APP: - case PREF_VIDEO_SELECTED_READER: - case PREF_VIDEO_SELECTED_WEB: - case PREF_VIDEO_SELECTED_APP: - case PREF_AUDIO_SELECTED_READER: - case PREF_AUDIO_SELECTED_WEB: - case PREF_AUDIO_SELECTED_APP: - this._setSelectedHandler(feedType); - break; - case PREF_SELECTED_ACTION: - case PREF_VIDEO_SELECTED_ACTION: - case PREF_AUDIO_SELECTED_ACTION: - this._setAlwaysUseCheckedState(feedType); - } - } - }, - - /** - * Sets the icon for the given web-reader item in the readers menu. - * The icon is fetched and stored through the favicon service. - * - * @param aReaderUrl - * the reader url. - * @param aMenuItem - * the reader item in the readers menulist. - * - * @note For privacy reasons we cannot set the image attribute directly - * to the icon url. See Bug 358878 for details. - */ - _setFaviconForWebReader: - function FW__setFaviconForWebReader(aReaderUrl, aMenuItem) { - var readerURI = makeURI(aReaderUrl); - if (!/^https?$/.test(readerURI.scheme)) { - // Don't try to get a favicon for non http(s) URIs. - return; - } - var faviconURI = makeURI(readerURI.prePath + "/favicon.ico"); - var self = this; - var usePrivateBrowsing = this._window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell) - .QueryInterface(Ci.nsILoadContext) - .usePrivateBrowsing; - var nullPrincipal = Cc["@mozilla.org/nullprincipal;1"] - .createInstance(Ci.nsIPrincipal); - this._faviconService.setAndFetchFaviconForPage(readerURI, faviconURI, false, - usePrivateBrowsing ? this._faviconService.FAVICON_LOAD_PRIVATE - : this._faviconService.FAVICON_LOAD_NON_PRIVATE, - function (aURI, aDataLen, aData, aMimeType) { - if (aDataLen > 0) { - var dataURL = "data:" + aMimeType + ";base64," + - btoa(String.fromCharCode.apply(null, aData)); - self._contentSandbox.menuItem = aMenuItem; - self._contentSandbox.dataURL = dataURL; - var codeStr = "menuItem.setAttribute('image', dataURL);"; - Cu.evalInSandbox(codeStr, self._contentSandbox); - self._contentSandbox.menuItem = null; - self._contentSandbox.dataURL = null; - } - }, nullPrincipal); - }, - - classID: FEEDWRITER_CID, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMEventListener, Ci.nsIObserver, - Ci.nsINavHistoryObserver, - Ci.nsIDOMGlobalPropertyInitializer]) -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FeedWriter]); diff --git a/components/feeds/WebContentConverter.js b/components/feeds/WebContentConverter.js deleted file mode 100644 index 42e2ede..0000000 --- a/components/feeds/WebContentConverter.js +++ /dev/null @@ -1,927 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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/. */ - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cr = Components.results; - -function LOG(str) { - dump("*** " + str + "\n"); -} - -const WCCR_CONTRACTID = "@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"; -const WCCR_CLASSID = Components.ID("{792a7e82-06a0-437c-af63-b2d12e808acc}"); - -const WCC_CLASSID = Components.ID("{db7ebf28-cc40-415f-8a51-1b111851df1e}"); -const WCC_CLASSNAME = "Web Service Handler"; - -const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed"; -const TYPE_ANY = "*/*"; -const TYPE_BLACKLIST = [ - "application/x-www-form-urlencoded", - "application/xhtml+xml", - "application/xml", - "application/mathml+xml", - "application/xslt+xml", - "application/x-xpinstall", - "image/gif", - "image/jpg", - "image/jpeg", - "image/png", - "image/x-png", - "image/webp", -#ifdef MOZ_JXR - "image/jxr", - "image/vnd.ms-photo", -#endif - "image/svg+xml", - "image/bmp", - "image/x-ms-bmp", - "image/icon", - "image/x-icon", - "image/vnd.microsoft.icon", - "multipart/x-mixed-replace", - "multipart/form-data", - "text/cache-manifest", - "text/css", - "text/xsl", - "text/html", - "text/ping", - "text/plain", - "text/xml", - "text/javascript", // To prevent malicious intent blocking scripting. - "text/ecmascript"]; - -const PREF_CONTENTHANDLERS_AUTO = "browser.contentHandlers.auto."; -const PREF_CONTENTHANDLERS_BRANCH = "browser.contentHandlers.types."; -const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice"; -const PREF_SELECTED_ACTION = "browser.feeds.handler"; -const PREF_SELECTED_READER = "browser.feeds.handler.default"; -const PREF_HANDLER_EXTERNAL_PREFIX = "network.protocol-handler.external"; -const PREF_ALLOW_DIFFERENT_HOST = "gecko.handlerService.allowRegisterFromDifferentHost"; - -const STRING_BUNDLE_URI = "chrome://browser/locale/feeds/subscribe.properties"; - -const NS_ERROR_MODULE_DOM = 2152923136; -const NS_ERROR_DOM_SYNTAX_ERR = NS_ERROR_MODULE_DOM + 12; - -function WebContentConverter() { -} -WebContentConverter.prototype = { - convert: function WCC_convert() { }, - asyncConvertData: function WCC_asyncConvertData() { }, - onDataAvailable: function WCC_onDataAvailable() { }, - onStopRequest: function WCC_onStopRequest() { }, - - onStartRequest: function WCC_onStartRequest(request, context) { - var wccr = - Cc[WCCR_CONTRACTID]. - getService(Ci.nsIWebContentConverterService); - wccr.loadPreferredHandler(request); - }, - - QueryInterface: function WCC_QueryInterface(iid) { - if (iid.equals(Ci.nsIStreamConverter) || - iid.equals(Ci.nsIStreamListener) || - iid.equals(Ci.nsISupports)) - return this; - throw Cr.NS_ERROR_NO_INTERFACE; - } -}; - -var WebContentConverterFactory = { - createInstance: function WCCF_createInstance(outer, iid) { - if (outer != null) - throw Cr.NS_ERROR_NO_AGGREGATION; - return new WebContentConverter().QueryInterface(iid); - }, - - QueryInterface: function WCC_QueryInterface(iid) { - if (iid.equals(Ci.nsIFactory) || - iid.equals(Ci.nsISupports)) - return this; - throw Cr.NS_ERROR_NO_INTERFACE; - } -}; - -function ServiceInfo(contentType, uri, name) { - this._contentType = contentType; - this._uri = uri; - this._name = name; -} -ServiceInfo.prototype = { - /** - * See nsIHandlerApp - */ - get name() { - return this._name; - }, - - /** - * See nsIHandlerApp - */ - equals: function SI_equals(aHandlerApp) { - if (!aHandlerApp) - throw Cr.NS_ERROR_NULL_POINTER; - - if (aHandlerApp instanceof Ci.nsIWebContentHandlerInfo && - aHandlerApp.contentType == this.contentType && - aHandlerApp.uri == this.uri) - return true; - - return false; - }, - - /** - * See nsIWebContentHandlerInfo - */ - get contentType() { - return this._contentType; - }, - - /** - * See nsIWebContentHandlerInfo - */ - get uri() { - return this._uri; - }, - - /** - * See nsIWebContentHandlerInfo - */ - getHandlerURI: function SI_getHandlerURI(uri) { - return this._uri.replace(/%s/gi, encodeURIComponent(uri)); - }, - - QueryInterface: function SI_QueryInterface(iid) { - if (iid.equals(Ci.nsIWebContentHandlerInfo) || - iid.equals(Ci.nsISupports)) - return this; - throw Cr.NS_ERROR_NO_INTERFACE; - } -}; - -function WebContentConverterRegistrar() { - this._contentTypes = { }; - this._autoHandleContentTypes = { }; -} - -WebContentConverterRegistrar.prototype = { - get stringBundle() { - var sb = Cc["@mozilla.org/intl/stringbundle;1"]. - getService(Ci.nsIStringBundleService). - createBundle(STRING_BUNDLE_URI); - delete WebContentConverterRegistrar.prototype.stringBundle; - return WebContentConverterRegistrar.prototype.stringBundle = sb; - }, - - _getFormattedString: function WCCR__getFormattedString(key, params) { - return this.stringBundle.formatStringFromName(key, params, params.length); - }, - - _getString: function WCCR_getString(key) { - return this.stringBundle.GetStringFromName(key); - }, - - /** - * See nsIWebContentConverterService - */ - getAutoHandler: - function WCCR_getAutoHandler(contentType) { - contentType = this._resolveContentType(contentType); - if (contentType in this._autoHandleContentTypes) - return this._autoHandleContentTypes[contentType]; - return null; - }, - - /** - * See nsIWebContentConverterService - */ - setAutoHandler: - function WCCR_setAutoHandler(contentType, handler) { - if (handler && !this._typeIsRegistered(contentType, handler.uri)) - throw Cr.NS_ERROR_NOT_AVAILABLE; - - contentType = this._resolveContentType(contentType); - this._setAutoHandler(contentType, handler); - - var ps = - Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefService); - var autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO); - if (handler) - autoBranch.setCharPref(contentType, handler.uri); - else if (autoBranch.prefHasUserValue(contentType)) - autoBranch.clearUserPref(contentType); - - ps.savePrefFile(null); - }, - - /** - * Update the internal data structure (not persistent) - */ - _setAutoHandler: - function WCCR__setAutoHandler(contentType, handler) { - if (handler) - this._autoHandleContentTypes[contentType] = handler; - else if (contentType in this._autoHandleContentTypes) - delete this._autoHandleContentTypes[contentType]; - }, - - /** - * See nsIWebContentConverterService - */ - getWebContentHandlerByURI: - function WCCR_getWebContentHandlerByURI(contentType, uri) { - var handlers = this.getContentHandlers(contentType, { }); - for (var i = 0; i < handlers.length; ++i) { - if (handlers[i].uri == uri) - return handlers[i]; - } - return null; - }, - - /** - * See nsIWebContentConverterService - */ - loadPreferredHandler: - function WCCR_loadPreferredHandler(request) { - var channel = request.QueryInterface(Ci.nsIChannel); - var contentType = this._resolveContentType(channel.contentType); - var handler = this.getAutoHandler(contentType); - if (handler) { - request.cancel(Cr.NS_ERROR_FAILURE); - - var webNavigation = - channel.notificationCallbacks.getInterface(Ci.nsIWebNavigation); - webNavigation.loadURI(handler.getHandlerURI(channel.URI.spec), - Ci.nsIWebNavigation.LOAD_FLAGS_NONE, - null, null, null); - } - }, - - /** - * See nsIWebContentConverterService - */ - removeProtocolHandler: - function WCCR_removeProtocolHandler(aProtocol, aURITemplate) { - var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"]. - getService(Ci.nsIExternalProtocolService); - var handlerInfo = eps.getProtocolHandlerInfo(aProtocol); - var handlers = handlerInfo.possibleApplicationHandlers; - for (let i = 0; i < handlers.length; i++) { - try { // We only want to test web handlers - let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp); - if (handler.uriTemplate == aURITemplate) { - handlers.removeElementAt(i); - var hs = Cc["@mozilla.org/uriloader/handler-service;1"]. - getService(Ci.nsIHandlerService); - hs.store(handlerInfo); - return; - } - } catch (e) { /* it wasn't a web handler */ } - } - }, - - /** - * See nsIWebContentConverterService - */ - removeContentHandler: - function WCCR_removeContentHandler(contentType, uri) { - function notURI(serviceInfo) { - return serviceInfo.uri != uri; - } - - if (contentType in this._contentTypes) { - this._contentTypes[contentType] = - this._contentTypes[contentType].filter(notURI); - } - }, - - /** - * - */ - _mappings: { - "application/rss+xml": TYPE_MAYBE_FEED, - "application/atom+xml": TYPE_MAYBE_FEED, - }, - - /** - * These are types for which there is a separate content converter aside - * from our built in generic one. We should not automatically register - * a factory for creating a converter for these types. - */ - _blockedTypes: { - "application/vnd.mozilla.maybe.feed": true, - }, - - /** - * Determines the "internal" content type based on the _mappings. - * @param contentType - * @returns The resolved contentType value. - */ - _resolveContentType: - function WCCR__resolveContentType(contentType) { - if (contentType in this._mappings) - return this._mappings[contentType]; - return contentType; - }, - - _makeURI: function(aURL, aOriginCharset, aBaseURI) { - var ioService = Components.classes["@mozilla.org/network/io-service;1"] - .getService(Components.interfaces.nsIIOService); - return ioService.newURI(aURL, aOriginCharset, aBaseURI); - }, - - _checkAndGetURI: - function WCCR_checkAndGetURI(aURIString, aContentWindow) - { - try { - let baseURI = aContentWindow.document.baseURIObject; - var uri = this._makeURI(aURIString, null, baseURI); - } catch (ex) { - // not supposed to throw according to spec - return; - } - - // For security reasons we reject non-http(s) urls (see bug 354316), - // we may need to revise this once we support more content types - // XXX this should be a "security exception" according to spec, but that - // isn't defined yet. - if (uri.scheme != "http" && uri.scheme != "https") - throw("Permission denied to add " + uri.spec + " as a content or protocol handler"); - - // We also reject handlers registered from a different host (see bug 402287) - // The pref allows us to test the feature - var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch); - if (!pb.getBoolPref(PREF_ALLOW_DIFFERENT_HOST) && - (!["http:", "https:"].includes(aContentWindow.location.protocol) || - aContentWindow.location.hostname != uri.host)) { - throw("Permission denied to add " + uri.spec + " as a content or protocol handler"); - } - - // If the uri doesn't contain '%s', it won't be a good handler - if (uri.spec.indexOf("%s") < 0) - throw NS_ERROR_DOM_SYNTAX_ERR; - - return uri; - }, - - /** - * Determines if a web handler is already registered. - * - * @param aProtocol - * The scheme of the web handler we are checking for. - * @param aURITemplate - * The URI template that the handler uses to handle the protocol. - * @return true if it is already registered, false otherwise. - */ - _protocolHandlerRegistered: - function WCCR_protocolHandlerRegistered(aProtocol, aURITemplate) { - var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"]. - getService(Ci.nsIExternalProtocolService); - var handlerInfo = eps.getProtocolHandlerInfo(aProtocol); - var handlers = handlerInfo.possibleApplicationHandlers; - for (let i = 0; i < handlers.length; i++) { - try { // We only want to test web handlers - let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp); - if (handler.uriTemplate == aURITemplate) - return true; - } catch (e) { /* it wasn't a web handler */ } - } - return false; - }, - - /** - * See nsIWebContentHandlerRegistrar - */ - registerProtocolHandler: - function WCCR_registerProtocolHandler(aProtocol, aURIString, aTitle, aContentWindow) { - LOG("registerProtocolHandler(" + aProtocol + "," + aURIString + "," + aTitle + ")"); - - var uri = this._checkAndGetURI(aURIString, aContentWindow); - - // If the protocol handler is already registered, just return early. - if (this._protocolHandlerRegistered(aProtocol, uri.spec)) { - return; - } - - var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow); - if (PrivateBrowsingUtils.isWindowPrivate(browserWindow)) { - // Inside the private browsing mode, we don't want to alert the user to save - // a protocol handler. We log it to the error console so that web developers - // would have some way to tell what's going wrong. - Cc["@mozilla.org/consoleservice;1"]. - getService(Ci.nsIConsoleService). - logStringMessage("Web page denied access to register a protocol handler inside private browsing mode"); - return; - } - - // First, check to make sure this isn't already handled internally (we don't - // want to let them take over, say "chrome"). - var ios = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - var handler = ios.getProtocolHandler(aProtocol); - if (!(handler instanceof Ci.nsIExternalProtocolHandler)) { - // This is handled internally, so we don't want them to register - // XXX this should be a "security exception" according to spec, but that - // isn't defined yet. - throw("Permission denied to add " + aURIString + "as a protocol handler"); - } - - // check if it is in the black list - var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch); - var allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "." + aProtocol, - pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "-default")); - if (!allowed) { - // XXX this should be a "security exception" according to spec - throw("Not allowed to register a protocol handler for " + aProtocol); - } - - // Now Ask the user and provide the proper callback - var message = this._getFormattedString("addProtocolHandler", - [aTitle, uri.host, aProtocol]); - - var notificationIcon = uri.prePath + "/favicon.ico"; - var notificationValue = "Protocol Registration: " + aProtocol; - var addButton = { - label: this._getString("addProtocolHandlerAddButton"), - accessKey: this._getString("addHandlerAddButtonAccesskey"), - protocolInfo: { protocol: aProtocol, uri: uri.spec, name: aTitle }, - - callback: - function WCCR_addProtocolHandlerButtonCallback(aNotification, aButtonInfo) { - var protocol = aButtonInfo.protocolInfo.protocol; - var uri = aButtonInfo.protocolInfo.uri; - var name = aButtonInfo.protocolInfo.name; - - var handler = Cc["@mozilla.org/uriloader/web-handler-app;1"]. - createInstance(Ci.nsIWebHandlerApp); - handler.name = name; - handler.uriTemplate = uri; - - var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"]. - getService(Ci.nsIExternalProtocolService); - var handlerInfo = eps.getProtocolHandlerInfo(protocol); - handlerInfo.possibleApplicationHandlers.appendElement(handler, false); - - // Since the user has agreed to add a new handler, chances are good - // that the next time they see a handler of this type, they're going - // to want to use it. Reset the handlerInfo to ask before the next - // use. - handlerInfo.alwaysAskBeforeHandling = true; - - var hs = Cc["@mozilla.org/uriloader/handler-service;1"]. - getService(Ci.nsIHandlerService); - hs.store(handlerInfo); - } - }; - var browserElement = this._getBrowserForContentWindow(browserWindow, aContentWindow); - var notificationBox = browserWindow.gBrowser.getNotificationBox(browserElement); - notificationBox.appendNotification(message, - notificationValue, - notificationIcon, - notificationBox.PRIORITY_INFO_LOW, - [addButton]); - }, - - /** - * See nsIWebContentHandlerRegistrar - * If a DOM window is provided, then the request came from content, so we - * prompt the user to confirm the registration. - */ - registerContentHandler: - function WCCR_registerContentHandler(aContentType, aURIString, aTitle, aContentWindow) { - LOG("registerContentHandler(" + aContentType + "," + aURIString + "," + aTitle + ")"); - - // Check against the type blacklist. - // XXX this should be a "security exception" according to spec, but that - // isn't defined yet. - var contentType = this._resolveContentType(aContentType); - for (let blacklistType of TYPE_BLACKLIST) { - if (contentType == blacklistType) { - console.error("Unable to register content handler for prohibited MIME type %s.", contentType); - return; - } - } - - if (aContentWindow) { - var uri = this._checkAndGetURI(aURIString, aContentWindow); - - var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow); - var browserElement = this._getBrowserForContentWindow(browserWindow, aContentWindow); - var notificationBox = browserWindow.gBrowser.getNotificationBox(browserElement); - this._appendFeedReaderNotification(uri, aTitle, notificationBox); - } - else - this._registerContentHandler(contentType, aURIString, aTitle); - }, - - /** - * Returns the browser chrome window in which the content window is in - */ - _getBrowserWindowForContentWindow: - function WCCR__getBrowserWindowForContentWindow(aContentWindow) { - return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShellTreeItem) - .rootTreeItem - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow) - .wrappedJSObject; - }, - - /** - * Returns the element associated with the given content - * window. - * - * @param aBrowserWindow - * The browser window in which the content window is in. - * @param aContentWindow - * The content window. It's possible to pass a child content window - * (i.e. the content window of a frame/iframe). - */ - _getBrowserForContentWindow: - function WCCR__getBrowserForContentWindow(aBrowserWindow, aContentWindow) { - // This depends on pseudo APIs of browser.js and tabbrowser.xml - aContentWindow = aContentWindow.top; - var browsers = aBrowserWindow.gBrowser.browsers; - for (var i = 0; i < browsers.length; ++i) { - if (browsers[i].contentWindow == aContentWindow) - return browsers[i]; - } - }, - - /** - * Appends a notifcation for the given feed reader details. - * - * The notification could be either a pseudo-dialog which lets - * the user to add the feed reader: - * [ [icon] Add %feed-reader-name% (%feed-reader-host%) as a Feed Reader? (Add) [x] ] - * - * or a simple message for the case where the feed reader is already registered: - * [ [icon] %feed-reader-name% is already registered as a Feed Reader [x] ] - * - * A new notification isn't appended if the given notificationbox has a - * notification for the same feed reader. - * - * @param aURI - * The url of the feed reader as a nsIURI object - * @param aName - * The feed reader name as it was passed to registerContentHandler - * @param aNotificationBox - * The notification box to which a notification might be appended - * @return true if a notification has been appended, false otherwise. - */ - _appendFeedReaderNotification: - function WCCR__appendFeedReaderNotification(aURI, aName, aNotificationBox) { - var uriSpec = aURI.spec; - var notificationValue = "feed reader notification: " + uriSpec; - var notificationIcon = aURI.prePath + "/favicon.ico"; - - // Don't append a new notification if the notificationbox - // has a notification for the given feed reader already - if (aNotificationBox.getNotificationWithValue(notificationValue)) - return false; - - var buttons, message; - if (this.getWebContentHandlerByURI(TYPE_MAYBE_FEED, uriSpec)) - message = this._getFormattedString("handlerRegistered", [aName]); - else { - message = this._getFormattedString("addHandler", [aName, aURI.host]); - var self = this; - var addButton = { - _outer: self, - label: self._getString("addHandlerAddButton"), - accessKey: self._getString("addHandlerAddButtonAccesskey"), - feedReaderInfo: { uri: uriSpec, name: aName }, - - /* static */ - callback: - function WCCR__addFeedReaderButtonCallback(aNotification, aButtonInfo) { - var uri = aButtonInfo.feedReaderInfo.uri; - var name = aButtonInfo.feedReaderInfo.name; - var outer = aButtonInfo._outer; - - // The reader could have been added from another window mean while - if (!outer.getWebContentHandlerByURI(TYPE_MAYBE_FEED, uri)) - outer._registerContentHandler(TYPE_MAYBE_FEED, uri, name); - - // avoid reference cycles - aButtonInfo._outer = null; - - return false; - } - }; - buttons = [addButton]; - } - - aNotificationBox.appendNotification(message, - notificationValue, - notificationIcon, - aNotificationBox.PRIORITY_INFO_LOW, - buttons); - return true; - }, - - /** - * Save Web Content Handler metadata to persistent preferences. - * @param contentType - * The content Type being handled - * @param uri - * The uri of the web service - * @param title - * The human readable name of the web service - * - * This data is stored under: - * - * browser.contentHandlers.type0 = content/type - * browser.contentHandlers.uri0 = http://www.foo.com/q=%s - * browser.contentHandlers.title0 = Foo 2.0alphr - */ - _saveContentHandlerToPrefs: - function WCCR__saveContentHandlerToPrefs(contentType, uri, title) { - var ps = - Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefService); - var i = 0; - var typeBranch = null; - while (true) { - typeBranch = - ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + i + "."); - try { - typeBranch.getCharPref("type"); - ++i; - } - catch (e) { - // No more handlers - break; - } - } - if (typeBranch) { - typeBranch.setCharPref("type", contentType); - var pls = - Cc["@mozilla.org/pref-localizedstring;1"]. - createInstance(Ci.nsIPrefLocalizedString); - pls.data = uri; - typeBranch.setComplexValue("uri", Ci.nsIPrefLocalizedString, pls); - pls.data = title; - typeBranch.setComplexValue("title", Ci.nsIPrefLocalizedString, pls); - - ps.savePrefFile(null); - } - }, - - /** - * Determines if there is a type with a particular uri registered for the - * specified content type already. - * @param contentType - * The content type that the uri handles - * @param uri - * The uri of the - */ - _typeIsRegistered: function WCCR__typeIsRegistered(contentType, uri) { - if (!(contentType in this._contentTypes)) - return false; - - var services = this._contentTypes[contentType]; - for (var i = 0; i < services.length; ++i) { - // This uri has already been registered - if (services[i].uri == uri) - return true; - } - return false; - }, - - /** - * Gets a stream converter contract id for the specified content type. - * @param contentType - * The source content type for the conversion. - * @returns A contract id to construct a converter to convert between the - * contentType and *\/*. - */ - _getConverterContractID: function WCCR__getConverterContractID(contentType) { - const template = "@mozilla.org/streamconv;1?from=%s&to=*/*"; - return template.replace(/%s/, contentType); - }, - - /** - * Register a web service handler for a content type. - * - * @param contentType - * the content type being handled - * @param uri - * the URI of the web service - * @param title - * the human readable name of the web service - */ - _registerContentHandler: - function WCCR__registerContentHandler(contentType, uri, title) { - this._updateContentTypeHandlerMap(contentType, uri, title); - this._saveContentHandlerToPrefs(contentType, uri, title); - - if (contentType == TYPE_MAYBE_FEED) { - // Make the new handler the last-selected reader in the preview page - // and make sure the preview page is shown the next time a feed is visited - var pb = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefService).getBranch(null); - pb.setCharPref(PREF_SELECTED_READER, "web"); - - var supportsString = - Cc["@mozilla.org/supports-string;1"]. - createInstance(Ci.nsISupportsString); - supportsString.data = uri; - pb.setComplexValue(PREF_SELECTED_WEB, Ci.nsISupportsString, - supportsString); - pb.setCharPref(PREF_SELECTED_ACTION, "ask"); - this._setAutoHandler(TYPE_MAYBE_FEED, null); - } - }, - - /** - * Update the content type -> handler map. This mapping is not persisted, use - * registerContentHandler or _saveContentHandlerToPrefs for that purpose. - * @param contentType - * The content Type being handled - * @param uri - * The uri of the web service - * @param title - * The human readable name of the web service - */ - _updateContentTypeHandlerMap: - function WCCR__updateContentTypeHandlerMap(contentType, uri, title) { - if (!(contentType in this._contentTypes)) - this._contentTypes[contentType] = []; - - // Avoid adding duplicates - if (this._typeIsRegistered(contentType, uri)) - return; - - this._contentTypes[contentType].push(new ServiceInfo(contentType, uri, title)); - - if (!(contentType in this._blockedTypes)) { - var converterContractID = this._getConverterContractID(contentType); - var cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); - cr.registerFactory(WCC_CLASSID, WCC_CLASSNAME, converterContractID, - WebContentConverterFactory); - } - }, - - /** - * See nsIWebContentConverterService - */ - getContentHandlers: - function WCCR_getContentHandlers(contentType, countRef) { - countRef.value = 0; - if (!(contentType in this._contentTypes)) - return []; - - var handlers = this._contentTypes[contentType]; - countRef.value = handlers.length; - return handlers; - }, - - /** - * See nsIWebContentConverterService - */ - resetHandlersForType: - function WCCR_resetHandlersForType(contentType) { - // currently unused within the tree, so only useful for extensions; previous - // impl. was buggy (and even infinite-looped!), so I argue that this is a - // definite improvement - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - }, - - /** - * Registers a handler from the settings on a preferences branch. - * - * @param branch - * an nsIPrefBranch containing "type", "uri", and "title" preferences - * corresponding to the content handler to be registered - */ - _registerContentHandlerWithBranch: function(branch) { - /** - * Since we support up to six predefined readers, we need to handle gaps - * better, since the first branch with user-added values will be .6 - * - * How we deal with that is to check to see if there's no prefs in the - * branch and stop cycling once that's true. This doesn't fix the case - * where a user manually removes a reader, but that's not supported yet! - */ - var vals = branch.getChildList(""); - if (vals.length == 0) - return; - - try { - var type = branch.getCharPref("type"); - var uri = branch.getComplexValue("uri", Ci.nsIPrefLocalizedString).data; - var title = branch.getComplexValue("title", - Ci.nsIPrefLocalizedString).data; - this._updateContentTypeHandlerMap(type, uri, title); - } - catch(ex) { - // do nothing, the next branch might have values - } - }, - - /** - * Load the auto handler, content handler and protocol tables from - * preferences. - */ - _init: function WCCR__init() { - var ps = - Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefService); - - var kids = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH) - .getChildList(""); - - // first get the numbers of the providers by getting all ###.uri prefs - var nums = []; - for (var i = 0; i < kids.length; i++) { - var match = /^(\d+)\.uri$/.exec(kids[i]); - if (!match) - continue; - else - nums.push(match[1]); - } - - // sort them, to get them back in order - nums.sort(function(a, b) {return a - b;}); - - // now register them - for (var i = 0; i < nums.length; i++) { - var branch = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + nums[i] + "."); - this._registerContentHandlerWithBranch(branch); - } - - // We need to do this _after_ registering all of the available handlers, - // so that getWebContentHandlerByURI can return successfully. - try { - var autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO); - var childPrefs = autoBranch.getChildList(""); - for (var i = 0; i < childPrefs.length; ++i) { - var type = childPrefs[i]; - var uri = autoBranch.getCharPref(type); - if (uri) { - var handler = this.getWebContentHandlerByURI(type, uri); - this._setAutoHandler(type, handler); - } - } - } - catch (e) { - // No auto branch yet, that's fine - //LOG("WCCR.init: There is no auto branch, benign"); - } - }, - - /** - * See nsIObserver - */ - observe: function WCCR_observe(subject, topic, data) { - var os = - Cc["@mozilla.org/observer-service;1"]. - getService(Ci.nsIObserverService); - switch (topic) { - case "app-startup": - os.addObserver(this, "browser-ui-startup-complete", false); - break; - case "browser-ui-startup-complete": - os.removeObserver(this, "browser-ui-startup-complete"); - this._init(); - break; - } - }, - - /** - * See nsIFactory - */ - createInstance: function WCCR_createInstance(outer, iid) { - if (outer != null) - throw Cr.NS_ERROR_NO_AGGREGATION; - return this.QueryInterface(iid); - }, - - classID: WCCR_CLASSID, - - /** - * See nsISupports - */ - QueryInterface: XPCOMUtils.generateQI( - [Ci.nsIWebContentConverterService, - Ci.nsIWebContentHandlerRegistrar, - Ci.nsIObserver, - Ci.nsIFactory]), - - _xpcom_categories: [{ - category: "app-startup", - service: true - }] -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebContentConverterRegistrar]); diff --git a/components/feeds/content/subscribe.css b/components/feeds/content/subscribe.css deleted file mode 100644 index bf2524d..0000000 --- a/components/feeds/content/subscribe.css +++ /dev/null @@ -1,7 +0,0 @@ -/* 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/. */ - -#feedSubscribeLine { - -moz-binding: url(subscribe.xml#feedreaderUI); -} diff --git a/components/feeds/content/subscribe.js b/components/feeds/content/subscribe.js deleted file mode 100644 index ab2eac4..0000000 --- a/components/feeds/content/subscribe.js +++ /dev/null @@ -1,23 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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 SubscribeHandler = { - /** - * The nsIFeedWriter object that produces the UI - */ - _feedWriter: null, - - init: function SH_init() { - this._feedWriter = new BrowserFeedWriter(); - }, - - writeContent: function SH_writeContent() { - this._feedWriter.writeContent(); - }, - - uninit: function SH_uninit() { - this._feedWriter.close(); - } -}; diff --git a/components/feeds/content/subscribe.xhtml b/components/feeds/content/subscribe.xhtml deleted file mode 100644 index 8ad069f..0000000 --- a/components/feeds/content/subscribe.xhtml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - %htmlDTD; - - %globalDTD; - - %feedDTD; -]> - - - - - - &feedPage.title; - - - - -
-
- - - -
-

-

-

-
-
-
- - diff --git a/components/feeds/content/subscribe.xml b/components/feeds/content/subscribe.xml deleted file mode 100644 index 949bcfd..0000000 --- a/components/feeds/content/subscribe.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - %feedDTD; -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/components/feeds/jar.mn b/components/feeds/jar.mn deleted file mode 100644 index f8896f8..0000000 --- a/components/feeds/jar.mn +++ /dev/null @@ -1,9 +0,0 @@ -# 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/. - -browser.jar: - content/browser/feeds/subscribe.xhtml (content/subscribe.xhtml) - content/browser/feeds/subscribe.js (content/subscribe.js) - content/browser/feeds/subscribe.xml (content/subscribe.xml) - content/browser/feeds/subscribe.css (content/subscribe.css) diff --git a/components/feeds/moz.build b/components/feeds/moz.build deleted file mode 100644 index 736920a..0000000 --- a/components/feeds/moz.build +++ /dev/null @@ -1,33 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -JAR_MANIFESTS += ['jar.mn'] - -XPIDL_SOURCES += [ - 'nsIFeedResultService.idl', - 'nsIWebContentConverterRegistrar.idl', -] - -XPIDL_MODULE = 'browser-feeds' - -SOURCES += ['nsFeedSniffer.cpp'] - -EXTRA_COMPONENTS += [ - 'BrowserFeeds.manifest', - 'FeedConverter.js', -] - -EXTRA_PP_COMPONENTS += [ - 'FeedWriter.js', - 'WebContentConverter.js', -] - -FINAL_LIBRARY = 'browsercomps' - -for var in ('MOZ_APP_NAME', 'MOZ_MACBUNDLE_NAME'): - DEFINES[var] = CONFIG[var] - -LOCAL_INCLUDES += ['../build'] diff --git a/components/feeds/nsFeedSniffer.cpp b/components/feeds/nsFeedSniffer.cpp deleted file mode 100644 index f314d3d..0000000 --- a/components/feeds/nsFeedSniffer.cpp +++ /dev/null @@ -1,363 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#include "nsFeedSniffer.h" - - -#include "nsNetCID.h" -#include "nsXPCOM.h" -#include "nsCOMPtr.h" -#include "nsStringStream.h" - -#include "nsBrowserCompsCID.h" - -#include "nsICategoryManager.h" -#include "nsIServiceManager.h" -#include "nsComponentManagerUtils.h" -#include "nsServiceManagerUtils.h" - -#include "nsIStreamConverterService.h" -#include "nsIStreamConverter.h" - -#include "nsIStreamListener.h" - -#include "nsIHttpChannel.h" -#include "nsIMIMEHeaderParam.h" - -#include "nsMimeTypes.h" -#include "nsIURI.h" -#include - -#define TYPE_ATOM "application/atom+xml" -#define TYPE_RSS "application/rss+xml" -#define TYPE_MAYBE_FEED "application/vnd.mozilla.maybe.feed" - -#define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#" -#define NS_RSS "http://purl.org/rss/1.0/" - -#define MAX_BYTES 512u - -NS_IMPL_ISUPPORTS(nsFeedSniffer, - nsIContentSniffer, - nsIStreamListener, - nsIRequestObserver) - -nsresult -nsFeedSniffer::ConvertEncodedData(nsIRequest* request, - const uint8_t* data, - uint32_t length) -{ - nsresult rv = NS_OK; - - mDecodedData = ""; - nsCOMPtr httpChannel(do_QueryInterface(request)); - if (!httpChannel) - return NS_ERROR_NO_INTERFACE; - - nsAutoCString contentEncoding; - httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"), - contentEncoding); - if (!contentEncoding.IsEmpty()) { - nsCOMPtr converterService(do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID)); - if (converterService) { - ToLowerCase(contentEncoding); - - nsCOMPtr converter; - rv = converterService->AsyncConvertData(contentEncoding.get(), - "uncompressed", this, nullptr, - getter_AddRefs(converter)); - NS_ENSURE_SUCCESS(rv, rv); - - converter->OnStartRequest(request, nullptr); - - nsCOMPtr rawStream = - do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID); - if (!rawStream) - return NS_ERROR_FAILURE; - - rv = rawStream->SetData((const char*)data, length); - NS_ENSURE_SUCCESS(rv, rv); - - rv = converter->OnDataAvailable(request, nullptr, rawStream, 0, length); - NS_ENSURE_SUCCESS(rv, rv); - - converter->OnStopRequest(request, nullptr, NS_OK); - } - } - return rv; -} - -template -static bool -StringBeginsWithLowercaseLiteral(nsAString& aString, - const char (&aSubstring)[N]) -{ - return StringHead(aString, N).LowerCaseEqualsLiteral(aSubstring); -} - -bool -HasAttachmentDisposition(nsIHttpChannel* httpChannel) -{ - if (!httpChannel) - return false; - - uint32_t disp; - nsresult rv = httpChannel->GetContentDisposition(&disp); - - if (NS_SUCCEEDED(rv) && disp == nsIChannel::DISPOSITION_ATTACHMENT) - return true; - - return false; -} - -/** - * @return the first occurrence of a character within a string buffer, - * or nullptr if not found - */ -static const char* -FindChar(char c, const char *begin, const char *end) -{ - for (; begin < end; ++begin) { - if (*begin == c) - return begin; - } - return nullptr; -} - -/** - * - * Determine if a substring is the "documentElement" in the document. - * - * All of our sniffed substrings: = end) - return false; - - // Check to see if the character following the '<' is either '?' or '!' - // (processing instruction or doctype or comment)... these are valid nodes - // to have in the prologue. - if (*start != '?' && *start != '!') - return false; - - // Now advance the iterator until the '>' (We do this because we don't want - // to sniff indicator substrings that are embedded within other nodes, e.g. - // comments: - start = FindChar('>', start, end); - if (!start) - return false; - - ++start; - } - return true; -} - -/** - * Determines whether or not a string exists as the root element in an XML data - * string buffer. - * @param dataString - * The data being sniffed - * @param substring - * The substring being tested for existence and root-ness. - * @returns true if the substring exists and is the documentElement, false - * otherwise. - */ -static bool -ContainsTopLevelSubstring(nsACString& dataString, const char *substring) -{ - int32_t offset = dataString.Find(substring); - if (offset == -1) - return false; - - const char *begin = dataString.BeginReading(); - - // Only do the validation when we find the substring. - return IsDocumentElement(begin, begin + offset); -} - -NS_IMETHODIMP -nsFeedSniffer::GetMIMETypeFromContent(nsIRequest* request, - const uint8_t* data, - uint32_t length, - nsACString& sniffedType) -{ - nsCOMPtr channel(do_QueryInterface(request)); - if (!channel) - return NS_ERROR_NO_INTERFACE; - - // Check that this is a GET request, since you can't subscribe to a POST... - nsAutoCString method; - channel->GetRequestMethod(method); - if (!method.EqualsLiteral("GET")) { - sniffedType.Truncate(); - return NS_OK; - } - - // We need to find out if this is a load of a view-source document. In this - // case we do not want to override the content type, since the source display - // does not need to be converted from feed format to XUL. More importantly, - // we don't want to change the content type from something - // nsContentDLF::CreateInstance knows about (e.g. application/xml, text/html - // etc) to something that only the application fe knows about (maybe.feed) - // thus deactivating syntax highlighting. - nsCOMPtr originalURI; - channel->GetOriginalURI(getter_AddRefs(originalURI)); - - nsAutoCString scheme; - originalURI->GetScheme(scheme); - if (scheme.EqualsLiteral("view-source")) { - sniffedType.Truncate(); - return NS_OK; - } - - // Check the Content-Type to see if it is set correctly. If it is set to - // something specific that we think is a reliable indication of a feed, don't - // bother sniffing since we assume the site maintainer knows what they're - // doing. - nsAutoCString contentType; - channel->GetContentType(contentType); - bool noSniff = contentType.EqualsLiteral(TYPE_RSS) || - contentType.EqualsLiteral(TYPE_ATOM); - - // Check to see if this was a feed request from the location bar or from - // the feed: protocol. This is also a reliable indication. - // The value of the header doesn't matter. - if (!noSniff) { - nsAutoCString sniffHeader; - nsresult foundHeader = - channel->GetRequestHeader(NS_LITERAL_CSTRING("X-Moz-Is-Feed"), - sniffHeader); - noSniff = NS_SUCCEEDED(foundHeader); - } - - if (noSniff) { - // check for an attachment after we have a likely feed. - if(HasAttachmentDisposition(channel)) { - sniffedType.Truncate(); - return NS_OK; - } - - // set the feed header as a response header, since we have good metadata - // telling us that the feed is supposed to be RSS or Atom - channel->SetResponseHeader(NS_LITERAL_CSTRING("X-Moz-Is-Feed"), - NS_LITERAL_CSTRING("1"), false); - sniffedType.AssignLiteral(TYPE_MAYBE_FEED); - return NS_OK; - } - - // Don't sniff arbitrary types. Limit sniffing to situations that - // we think can reasonably arise. - if (!contentType.EqualsLiteral(TEXT_HTML) && - !contentType.EqualsLiteral(APPLICATION_OCTET_STREAM) && - // Same criterion as XMLHttpRequest. Should we be checking for "+xml" - // and check for text/xml and application/xml by hand instead? - contentType.Find("xml") == -1) { - sniffedType.Truncate(); - return NS_OK; - } - - // Now we need to potentially decompress data served with - // Content-Encoding: gzip - nsresult rv = ConvertEncodedData(request, data, length); - if (NS_FAILED(rv)) - return rv; - - // We cap the number of bytes to scan at MAX_BYTES to prevent picking up - // false positives by accidentally reading document content, e.g. a "how to - // make a feed" page. - const char* testData; - if (mDecodedData.IsEmpty()) { - testData = (const char*)data; - length = std::min(length, MAX_BYTES); - } else { - testData = mDecodedData.get(); - length = std::min(mDecodedData.Length(), MAX_BYTES); - } - - // The strategy here is based on that described in: - // http://blogs.msdn.com/rssteam/articles/PublishersGuide.aspx - // for interoperarbility purposes. - - // Thus begins the actual sniffing. - nsDependentCSubstring dataString((const char*)testData, length); - - bool isFeed = false; - - // RSS 0.91/0.92/2.0 - isFeed = ContainsTopLevelSubstring(dataString, "(closure); - decodedData->Append(rawSegment, count); - *writeCount = count; - return NS_OK; -} - -NS_IMETHODIMP -nsFeedSniffer::OnDataAvailable(nsIRequest* request, nsISupports* context, - nsIInputStream* stream, uint64_t offset, - uint32_t count) -{ - uint32_t read; - return stream->ReadSegments(AppendSegmentToString, &mDecodedData, count, - &read); -} - -NS_IMETHODIMP -nsFeedSniffer::OnStopRequest(nsIRequest* request, nsISupports* context, - nsresult status) -{ - return NS_OK; -} diff --git a/components/feeds/nsFeedSniffer.h b/components/feeds/nsFeedSniffer.h deleted file mode 100644 index a0eb986..0000000 --- a/components/feeds/nsFeedSniffer.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - - -#include "nsIContentSniffer.h" -#include "nsIStreamListener.h" -#include "nsStringAPI.h" -#include "mozilla/Attributes.h" - -class nsFeedSniffer final : public nsIContentSniffer, - nsIStreamListener -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSICONTENTSNIFFER - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSISTREAMLISTENER - - static nsresult AppendSegmentToString(nsIInputStream* inputStream, - void* closure, - const char* rawSegment, - uint32_t toOffset, - uint32_t count, - uint32_t* writeCount); - -protected: - ~nsFeedSniffer() {} - - nsresult ConvertEncodedData(nsIRequest* request, const uint8_t* data, - uint32_t length); - -private: - nsCString mDecodedData; -}; - diff --git a/components/feeds/nsIFeedResultService.idl b/components/feeds/nsIFeedResultService.idl deleted file mode 100644 index cb0f332..0000000 --- a/components/feeds/nsIFeedResultService.idl +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#include "nsISupports.idl" -interface nsIURI; -interface nsIRequest; -interface nsIFeedResult; - -/** - * nsIFeedResultService provides a globally-accessible object for retrieving - * the results of feed processing. - */ -[scriptable, uuid(950a829e-c20e-4dc3-b447-f8b753ae54da)] -interface nsIFeedResultService : nsISupports -{ - /** - * When set to true, forces the preview page to be displayed, regardless - * of the user's preferences. - */ - attribute boolean forcePreviewPage; - - /** - * Adds a URI to the user's specified external feed handler, or live - * bookmarks. - * @param uri - * The uri of the feed to add. - * @param title - * The title of the feed to add. - * @param subtitle - * The subtitle of the feed to add. - * @param feedType - * The nsIFeed type of the feed. See nsIFeed.idl - */ - void addToClientReader(in AUTF8String uri, - in AString title, - in AString subtitle, - in unsigned long feedType); - - /** - * Registers a Feed Result object with a globally accessible service - * so that it can be accessed by a singleton method outside the usual - * flow of control in document loading. - * - * @param feedResult - * An object implementing nsIFeedResult representing the feed. - */ - void addFeedResult(in nsIFeedResult feedResult); - - /** - * Gets a Feed Handler object registered using addFeedResult. - * - * @param uri - * The URI of the feed a handler is being requested for - */ - nsIFeedResult getFeedResult(in nsIURI uri); - - /** - * Unregisters a Feed Handler object registered using addFeedResult. - * @param uri - * The feed URI the handler was registered under. This must be - * the same *instance* the feed was registered under. - */ - void removeFeedResult(in nsIURI uri); -}; diff --git a/components/feeds/nsIWebContentConverterRegistrar.idl b/components/feeds/nsIWebContentConverterRegistrar.idl deleted file mode 100644 index 08ce2f4..0000000 --- a/components/feeds/nsIWebContentConverterRegistrar.idl +++ /dev/null @@ -1,117 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#include "nsIMIMEInfo.idl" -#include "nsIWebContentHandlerRegistrar.idl" - -interface nsIRequest; - -[scriptable, uuid(eb361098-5158-4b21-8f98-50b445f1f0b2)] -interface nsIWebContentHandlerInfo : nsIHandlerApp -{ - /** - * The content type handled by the handler - */ - readonly attribute AString contentType; - - /** - * The uri of the handler, with an embedded %s where the URI of the loaded - * document will be encoded. - */ - readonly attribute AString uri; - - /** - * Gets the service URL Spec, with the loading document URI encoded in it. - * @param uri - * The URI of the document being loaded - * @returns The URI of the service with the loading document URI encoded in - * it. - */ - AString getHandlerURI(in AString uri); -}; - -[scriptable, uuid(de7cc06e-e778-45cb-b7db-7a114e1e75b1)] -interface nsIWebContentConverterService : nsIWebContentHandlerRegistrar -{ - /** - * Specifies the handler to be used to automatically handle all links of a - * certain content type from now on. - * @param contentType - * The content type to automatically load with the specified handler - * @param handler - * A web service handler. If this is null, no automatic action is - * performed and the user must choose. - * @throws NS_ERROR_NOT_AVAILABLE if the service refered to by |handler| is - * not already registered. - */ - void setAutoHandler(in AString contentType, in nsIWebContentHandlerInfo handler); - - /** - * Gets the auto handler specified for a particular content type - * @param contentType - * The content type to look up an auto handler for. - * @returns The web service handler that will automatically handle all - * documents of the specified type. null if there is no automatic - * handler. (Handlers may be registered, just none of them specified - * as "automatic"). - */ - nsIWebContentHandlerInfo getAutoHandler(in AString contentType); - - /** - * Gets a web handler for the specified service URI - * @param contentType - * The content type of the service being located - * @param uri - * The service URI of the handler to locate. - * @returns A web service handler that uses the specified uri. - */ - nsIWebContentHandlerInfo getWebContentHandlerByURI(in AString contentType, - in AString uri); - - /** - * Loads the preferred handler when content of a registered type is about - * to be loaded. - * @param request - * The nsIRequest for the load of the content - */ - void loadPreferredHandler(in nsIRequest request); - - /** - * Removes a registered protocol handler - * @param protocol - * The protocol scheme to remove a service handler for - * @param uri - * The uri of the service handler to remove - */ - void removeProtocolHandler(in AString protocol, in AString uri); - - /** - * Removes a registered content handler - * @param contentType - * The content type to remove a service handler for - * @param uri - * The uri of the service handler to remove - */ - void removeContentHandler(in AString contentType, in AString uri); - - /** - * Gets the list of content handlers for a particular type. - * @param contentType - * The content type to get handlers for - * @returns An array of nsIWebContentHandlerInfo objects - */ - void getContentHandlers(in AString contentType, - [optional] out unsigned long count, - [retval,array,size_is(count)] out nsIWebContentHandlerInfo handlers); - - /** - * Resets the list of available content handlers to the default set from - * the distribution. - * @param contentType - * The content type to reset handlers for - */ - void resetHandlersForType(in AString contentType); -}; - -- cgit v1.2.3