1 # -*- Mode
: C
++; tab
-width
: 8; indent
-tabs
-mode
: nil
; c
-basic
-offset
: 2 -*- */
2 # ***** BEGIN LICENSE BLOCK
*****
3 # Version
: MPL
1.1/GPL 2.0/LGPL
2.1
5 # The contents
of this file are subject to the Mozilla Public License Version
6 # 1.1 (the
"License"); you may not
use this file except
in compliance
with
7 # the License
. You may obtain a copy
of the License at
8 # http
://www.mozilla.org/MPL/
10 # Software distributed under the License is distributed on an
"AS IS" basis
,
11 # WITHOUT WARRANTY OF ANY KIND
, either express or implied
. See the License
12 # for the specific language governing rights and limitations under the
15 # The Original Code is the Web Content Converter System
.
17 # The Initial Developer
of the Original Code is Google Inc
.
18 # Portions created by the Initial Developer are
Copyright (C
) 2006
19 # the Initial Developer
. All Rights Reserved
.
22 # Ben Goodger
<beng
@google
.com
>
23 # Asaf Romano
<mano
@mozilla
.com
>
24 # Dan Mosedale
<dmose
@mozilla
.org
>
26 # Alternatively
, the contents
of this file may be used under the terms
of
27 # either the GNU General Public License Version
2 or
later (the
"GPL"), or
28 # the GNU Lesser General Public License Version
2.1 or
later (the
"LGPL"),
29 # in which
case the provisions
of the GPL or the LGPL are applicable instead
30 # of those above
. If you wish to allow
use of your version
of this file only
31 # under the terms
of either the GPL or the LGPL
, and not to allow others to
32 # use your version
of this file under the terms
of the MPL
, indicate your
33 # decision by deleting the provisions above and replace them
with the notice
34 # and other provisions required by the GPL or the LGPL
. If you
do not
delete
35 # the provisions above
, a recipient may
use your version
of this file under
36 # the terms
of any one
of the MPL
, the GPL or the LGPL
.
38 # ***** END LICENSE BLOCK
***** */
40 Components
.utils
.import("resource://gre/modules/XPCOMUtils.jsm");
42 const Cc
= Components
.classes
;
43 const Ci
= Components
.interfaces
;
44 const Cr
= Components
.results
;
47 dump("*** " + str
+ "\n");
50 const WCCR_CONTRACTID
= "@mozilla.org/embeddor.implemented/web-content-handler-registrar;1";
51 const WCCR_CLASSID
= Components
.ID("{792a7e82-06a0-437c-af63-b2d12e808acc}");
52 const WCCR_CLASSNAME
= "Web Content Handler Registrar";
54 const WCC_CLASSID
= Components
.ID("{db7ebf28-cc40-415f-8a51-1b111851df1e}");
55 const WCC_CLASSNAME
= "Web Service Handler";
57 const TYPE_MAYBE_FEED
= "application/vnd.mozilla.maybe.feed";
58 const TYPE_ANY
= "*/*";
60 const PREF_CONTENTHANDLERS_AUTO
= "browser.contentHandlers.auto.";
61 const PREF_CONTENTHANDLERS_BRANCH
= "browser.contentHandlers.types.";
62 const PREF_SELECTED_WEB
= "browser.feeds.handlers.webservice";
63 const PREF_SELECTED_ACTION
= "browser.feeds.handler";
64 const PREF_SELECTED_READER
= "browser.feeds.handler.default";
65 const PREF_HANDLER_EXTERNAL_PREFIX
= "network.protocol-handler.external";
66 const PREF_ALLOW_DIFFERENT_HOST
= "gecko.handlerService.allowRegisterFromDifferentHost";
68 const STRING_BUNDLE_URI
= "chrome://browser/locale/feeds/subscribe.properties";
70 const NS_ERROR_MODULE_DOM
= 2152923136;
71 const NS_ERROR_DOM_SYNTAX_ERR
= NS_ERROR_MODULE_DOM
+ 12;
73 function WebContentConverter() {
75 WebContentConverter
.prototype = {
76 convert
: function WCC_convert() { },
77 asyncConvertData
: function WCC_asyncConvertData() { },
78 onDataAvailable
: function WCC_onDataAvailable() { },
79 onStopRequest
: function WCC_onStopRequest() { },
81 onStartRequest
: function WCC_onStartRequest(request
, context
) {
84 getService(Ci
.nsIWebContentConverterService
);
85 wccr
.loadPreferredHandler(request
);
88 QueryInterface
: function WCC_QueryInterface(iid
) {
89 if (iid
.equals(Ci
.nsIStreamConverter
) ||
90 iid
.equals(Ci
.nsIStreamListener
) ||
91 iid
.equals(Ci
.nsISupports
))
93 throw Cr
.NS_ERROR_NO_INTERFACE
;
97 var WebContentConverterFactory
= {
98 createInstance
: function WCCF_createInstance(outer
, iid
) {
100 throw Cr
.NS_ERROR_NO_AGGREGATION
;
101 return new WebContentConverter().QueryInterface(iid
);
104 QueryInterface
: function WCC_QueryInterface(iid
) {
105 if (iid
.equals(Ci
.nsIFactory
) ||
106 iid
.equals(Ci
.nsISupports
))
108 throw Cr
.NS_ERROR_NO_INTERFACE
;
112 function ServiceInfo(contentType
, uri
, name
) {
113 this._contentType
= contentType
;
117 ServiceInfo
.prototype = {
128 equals
: function SI_equals(aHandlerApp
) {
130 throw Cr
.NS_ERROR_NULL_POINTER
;
132 if (aHandlerApp
instanceof Ci
.nsIWebContentHandlerInfo
&&
133 aHandlerApp
.contentType
== this.contentType
&&
134 aHandlerApp
.uri
== this.uri
)
141 * See nsIWebContentHandlerInfo
144 return this._contentType
;
148 * See nsIWebContentHandlerInfo
155 * See nsIWebContentHandlerInfo
157 getHandlerURI
: function SI_getHandlerURI(uri
) {
158 return this._uri
.replace(/%s/gi, encodeURIComponent(uri
));
161 QueryInterface
: function SI_QueryInterface(iid
) {
162 if (iid
.equals(Ci
.nsIWebContentHandlerInfo
) ||
163 iid
.equals(Ci
.nsISupports
))
165 throw Cr
.NS_ERROR_NO_INTERFACE
;
169 function WebContentConverterRegistrar() {
170 this._contentTypes
= { };
171 this._autoHandleContentTypes
= { };
174 WebContentConverterRegistrar
.prototype = {
176 var sb
= Cc
["@mozilla.org/intl/stringbundle;1"].
177 getService(Ci
.nsIStringBundleService
).
178 createBundle(STRING_BUNDLE_URI
);
179 delete WebContentConverterRegistrar
.prototype.stringBundle
;
180 return WebContentConverterRegistrar
.prototype.stringBundle
= sb
;
183 _getFormattedString
: function WCCR__getFormattedString(key
, params
) {
184 return this.stringBundle
.formatStringFromName(key
, params
, params
.length
);
187 _getString
: function WCCR_getString(key
) {
188 return this.stringBundle
.GetStringFromName(key
);
192 * See nsIWebContentConverterService
195 function WCCR_getAutoHandler(contentType
) {
196 contentType
= this._resolveContentType(contentType
);
197 if (contentType
in this._autoHandleContentTypes
)
198 return this._autoHandleContentTypes
[contentType
];
203 * See nsIWebContentConverterService
206 function WCCR_setAutoHandler(contentType
, handler
) {
207 if (handler
&& !this._typeIsRegistered(contentType
, handler
.uri
))
208 throw Cr
.NS_ERROR_NOT_AVAILABLE
;
210 contentType
= this._resolveContentType(contentType
);
211 this._setAutoHandler(contentType
, handler
);
214 Cc
["@mozilla.org/preferences-service;1"].
215 getService(Ci
.nsIPrefService
);
216 var autoBranch
= ps
.getBranch(PREF_CONTENTHANDLERS_AUTO
);
218 autoBranch
.setCharPref(contentType
, handler
.uri
);
219 else if (autoBranch
.prefHasUserValue(contentType
))
220 autoBranch
.clearUserPref(contentType
);
222 ps
.savePrefFile(null);
226 * Update the internal data structure (not persistent)
229 function WCCR__setAutoHandler(contentType
, handler
) {
231 this._autoHandleContentTypes
[contentType
] = handler
;
232 else if (contentType
in this._autoHandleContentTypes
)
233 delete this._autoHandleContentTypes
[contentType
];
237 * See nsIWebContentConverterService
239 getWebContentHandlerByURI
:
240 function WCCR_getWebContentHandlerByURI(contentType
, uri
) {
241 var handlers
= this.getContentHandlers(contentType
, { });
242 for (var i
= 0; i
< handlers
.length
; ++i
) {
243 if (handlers
[i
].uri
== uri
)
250 * See nsIWebContentConverterService
252 loadPreferredHandler
:
253 function WCCR_loadPreferredHandler(request
) {
254 var channel
= request
.QueryInterface(Ci
.nsIChannel
);
255 var contentType
= this._resolveContentType(channel
.contentType
);
256 var handler
= this.getAutoHandler(contentType
);
258 request
.cancel(Cr
.NS_ERROR_FAILURE
);
261 channel
.notificationCallbacks
.getInterface(Ci
.nsIWebNavigation
);
262 webNavigation
.loadURI(handler
.getHandlerURI(channel
.URI
.spec
),
263 Ci
.nsIWebNavigation
.LOAD_FLAGS_NONE
,
269 * See nsIWebContentConverterService
271 removeProtocolHandler
:
272 function WCCR_removeProtocolHandler(aProtocol
, aURITemplate
) {
273 var eps
= Cc
["@mozilla.org/uriloader/external-protocol-service;1"].
274 getService(Ci
.nsIExternalProtocolService
);
275 var handlerInfo
= eps
.getProtocolHandlerInfo(aProtocol
);
276 var handlers
= handlerInfo
.possibleApplicationHandlers
;
277 for (let i
= 0; i
< handlers
.length
; i
++) {
278 try { // We only want to test web handlers
279 let handler
= handlers
.queryElementAt(i
, Ci
.nsIWebHandlerApp
);
280 if (handler
.uriTemplate
== aURITemplate
) {
281 handlers
.removeElementAt(i
);
282 var hs
= Cc
["@mozilla.org/uriloader/handler-service;1"].
283 getService(Ci
.nsIHandlerService
);
284 hs
.store(handlerInfo
);
287 } catch (e
) { /* it wasn't a web handler */ }
292 * See nsIWebContentConverterService
294 removeContentHandler
:
295 function WCCR_removeContentHandler(contentType
, uri
) {
296 function notURI(serviceInfo
) {
297 return serviceInfo
.uri
!= uri
;
300 if (contentType
in this._contentTypes
) {
301 this._contentTypes
[contentType
] =
302 this._contentTypes
[contentType
].filter(notURI
);
310 "application/rss+xml": TYPE_MAYBE_FEED
,
311 "application/atom+xml": TYPE_MAYBE_FEED
,
315 * These are types for which there is a separate content converter aside
316 * from our built in generic one. We should not automatically register
317 * a factory for creating a converter for these types.
320 "application/vnd.mozilla.maybe.feed": true,
324 * Determines the "internal" content type based on the _mappings.
326 * @returns The resolved contentType value.
329 function WCCR__resolveContentType(contentType
) {
330 if (contentType
in this._mappings
)
331 return this._mappings
[contentType
];
335 _makeURI: function(aURL
, aOriginCharset
, aBaseURI
) {
336 var ioService
= Components
.classes
["@mozilla.org/network/io-service;1"]
337 .getService(Components
.interfaces
.nsIIOService
);
338 return ioService
.newURI(aURL
, aOriginCharset
, aBaseURI
);
342 function WCCR_checkAndGetURI(aURIString
, aContentWindow
)
345 var uri
= this._makeURI(aURIString
);
347 // not supposed to throw according to spec
351 // For security reasons we reject non-http(s) urls (see bug 354316),
352 // we may need to revise this once we support more content types
353 // XXX this should be a "security exception" according to spec, but that
354 // isn't defined yet.
355 if (uri
.scheme
!= "http" && uri
.scheme
!= "https")
356 throw("Permission denied to add " + uri
.spec
+ " as a content or protocol handler");
358 // We also reject handlers registered from a different host (see bug 402287)
359 // The pref allows us to test the feature
360 var pb
= Cc
["@mozilla.org/preferences-service;1"].getService(Ci
.nsIPrefBranch
);
361 if ((!pb
.prefHasUserValue(PREF_ALLOW_DIFFERENT_HOST
) ||
362 !pb
.getBoolPref(PREF_ALLOW_DIFFERENT_HOST
)) &&
363 aContentWindow
.location
.hostname
!= uri
.host
)
364 throw("Permission denied to add " + uri
.spec
+ " as a content or protocol handler");
366 // If the uri doesn't contain '%s', it won't be a good handler
367 if (uri
.spec
.indexOf("%s") < 0)
368 throw NS_ERROR_DOM_SYNTAX_ERR
;
374 * Determines if a web handler is already registered.
377 * The scheme of the web handler we are checking for.
378 * @param aURITemplate
379 * The URI template that the handler uses to handle the protocol.
380 * @return true if it is already registered, false otherwise.
382 _protocolHandlerRegistered
:
383 function WCCR_protocolHandlerRegistered(aProtocol
, aURITemplate
) {
384 var eps
= Cc
["@mozilla.org/uriloader/external-protocol-service;1"].
385 getService(Ci
.nsIExternalProtocolService
);
386 var handlerInfo
= eps
.getProtocolHandlerInfo(aProtocol
);
387 var handlers
= handlerInfo
.possibleApplicationHandlers
;
388 for (let i
= 0; i
< handlers
.length
; i
++) {
389 try { // We only want to test web handlers
390 let handler
= handlers
.queryElementAt(i
, Ci
.nsIWebHandlerApp
);
391 if (handler
.uriTemplate
== aURITemplate
)
393 } catch (e
) { /* it wasn't a web handler */ }
399 * See nsIWebContentHandlerRegistrar
401 registerProtocolHandler
:
402 function WCCR_registerProtocolHandler(aProtocol
, aURIString
, aTitle
, aContentWindow
) {
403 LOG("registerProtocolHandler(" + aProtocol
+ "," + aURIString
+ "," + aTitle
+ ")");
405 // First, check to make sure this isn't already handled internally (we don't
406 // want to let them take over, say "chrome").
407 var ios
= Cc
["@mozilla.org/network/io-service;1"].
408 getService(Ci
.nsIIOService
);
409 var handler
= ios
.getProtocolHandler(aProtocol
);
410 if (!(handler
instanceof Ci
.nsIExternalProtocolHandler
)) {
411 // This is handled internally, so we don't want them to register
412 // XXX this should be a "security exception" according to spec, but that
413 // isn't defined yet.
414 throw("Permission denied to add " + aURIString
+ "as a protocol handler");
417 // check if it is in the black list
418 var pb
= Cc
["@mozilla.org/preferences-service;1"].getService(Ci
.nsIPrefBranch
);
421 allowed
= pb
.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX
+ "." + aProtocol
);
424 allowed
= pb
.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX
+ "-default");
427 // XXX this should be a "security exception" according to spec
428 throw("Not allowed to register a protocol handler for " + aProtocol
);
431 var uri
= this._checkAndGetURI(aURIString
, aContentWindow
);
433 var buttons
, message
;
434 if (this._protocolHandlerRegistered(aProtocol
, uri
.spec
))
435 message
= this._getFormattedString("protocolHandlerRegistered",
436 [aTitle
, aProtocol
]);
438 // Now Ask the user and provide the proper callback
439 message
= this._getFormattedString("addProtocolHandler",
440 [aTitle
, uri
.host
, aProtocol
]);
441 var fis
= Cc
["@mozilla.org/browser/favicon-service;1"].
442 getService(Ci
.nsIFaviconService
);
443 var notificationIcon
= fis
.getFaviconLinkForIcon(uri
);
444 var notificationValue
= "Protocol Registration: " + aProtocol
;
446 label
: this._getString("addProtocolHandlerAddButton"),
447 accessKey
: this._getString("addHandlerAddButtonAccesskey"),
448 protocolInfo
: { protocol
: aProtocol
, uri
: uri
.spec
, name
: aTitle
},
451 function WCCR_addProtocolHandlerButtonCallback(aNotification
, aButtonInfo
) {
452 var protocol
= aButtonInfo
.protocolInfo
.protocol
;
453 var uri
= aButtonInfo
.protocolInfo
.uri
;
454 var name
= aButtonInfo
.protocolInfo
.name
;
456 var handler
= Cc
["@mozilla.org/uriloader/web-handler-app;1"].
457 createInstance(Ci
.nsIWebHandlerApp
);
459 handler
.uriTemplate
= uri
;
461 var eps
= Cc
["@mozilla.org/uriloader/external-protocol-service;1"].
462 getService(Ci
.nsIExternalProtocolService
);
463 var handlerInfo
= eps
.getProtocolHandlerInfo(protocol
);
464 handlerInfo
.possibleApplicationHandlers
.appendElement(handler
, false);
466 // Since the user has agreed to add a new handler, chances are good
467 // that the next time they see a handler of this type, they're going
468 // to want to use it. Reset the handlerInfo to ask before the next
470 handlerInfo
.alwaysAskBeforeHandling
= true;
472 var hs
= Cc
["@mozilla.org/uriloader/handler-service;1"].
473 getService(Ci
.nsIHandlerService
);
474 hs
.store(handlerInfo
);
477 buttons
= [addButton
];
480 var browserWindow
= this._getBrowserWindowForContentWindow(aContentWindow
);
481 var browserElement
= this._getBrowserForContentWindow(browserWindow
, aContentWindow
);
482 var notificationBox
= browserWindow
.getBrowser().getNotificationBox(browserElement
);
483 notificationBox
.appendNotification(message
,
486 notificationBox
.PRIORITY_INFO_LOW
,
491 * See nsIWebContentHandlerRegistrar
492 * If a DOM window is provided, then the request came from content, so we
493 * prompt the user to confirm the registration.
495 registerContentHandler
:
496 function WCCR_registerContentHandler(aContentType
, aURIString
, aTitle
, aContentWindow
) {
497 LOG("registerContentHandler(" + aContentType
+ "," + aURIString
+ "," + aTitle
+ ")");
499 // We only support feed types at present.
500 // XXX this should be a "security exception" according to spec, but that
501 // isn't defined yet.
502 var contentType
= this._resolveContentType(aContentType
);
503 if (contentType
!= TYPE_MAYBE_FEED
)
506 if (aContentWindow
) {
507 var uri
= this._checkAndGetURI(aURIString
, aContentWindow
);
509 var browserWindow
= this._getBrowserWindowForContentWindow(aContentWindow
);
510 var browserElement
= this._getBrowserForContentWindow(browserWindow
, aContentWindow
);
511 var notificationBox
= browserWindow
.getBrowser().getNotificationBox(browserElement
);
512 this._appendFeedReaderNotification(uri
, aTitle
, notificationBox
);
515 this._registerContentHandler(contentType
, aURIString
, aTitle
);
519 * Returns the browser chrome window in which the content window is in
521 _getBrowserWindowForContentWindow
:
522 function WCCR__getBrowserWindowForContentWindow(aContentWindow
) {
523 return aContentWindow
.QueryInterface(Ci
.nsIInterfaceRequestor
)
524 .getInterface(Ci
.nsIWebNavigation
)
525 .QueryInterface(Ci
.nsIDocShellTreeItem
)
527 .QueryInterface(Ci
.nsIInterfaceRequestor
)
528 .getInterface(Ci
.nsIDOMWindow
)
533 * Returns the <xul:browser> element associated with the given content
536 * @param aBrowserWindow
537 * The browser window in which the content window is in.
538 * @param aContentWindow
539 * The content window. It's possible to pass a child content window
540 * (i.e. the content window of a frame/iframe).
542 _getBrowserForContentWindow
:
543 function WCCR__getBrowserForContentWindow(aBrowserWindow
, aContentWindow
) {
544 // This depends on pseudo APIs of browser.js and tabbrowser.xml
545 aContentWindow
= aContentWindow
.top
;
546 var browsers
= aBrowserWindow
.getBrowser().browsers
;
547 for (var i
= 0; i
< browsers
.length
; ++i
) {
548 if (browsers
[i
].contentWindow
== aContentWindow
)
554 * Appends a notifcation for the given feed reader details.
556 * The notification could be either a pseudo-dialog which lets
557 * the user to add the feed reader:
558 * [ [icon] Add %feed-reader-name% (%feed-reader-host%) as a Feed Reader? (Add) [x] ]
560 * or a simple message for the case where the feed reader is already registered:
561 * [ [icon] %feed-reader-name% is already registered as a Feed Reader [x] ]
563 * A new notification isn't appended if the given notificationbox has a
564 * notification for the same feed reader.
567 * The url of the feed reader as a nsIURI object
569 * The feed reader name as it was passed to registerContentHandler
570 * @param aNotificationBox
571 * The notification box to which a notification might be appended
572 * @return true if a notification has been appended, false otherwise.
574 _appendFeedReaderNotification
:
575 function WCCR__appendFeedReaderNotification(aURI
, aName
, aNotificationBox
) {
576 var uriSpec
= aURI
.spec
;
577 var notificationValue
= "feed reader notification: " + uriSpec
;
578 var notificationIcon
= aURI
.prePath
+ "/favicon.ico";
580 // Don't append a new notification if the notificationbox
581 // has a notification for the given feed reader already
582 if (aNotificationBox
.getNotificationWithValue(notificationValue
))
585 var buttons
, message
;
586 if (this.getWebContentHandlerByURI(TYPE_MAYBE_FEED
, uriSpec
))
587 message
= this._getFormattedString("handlerRegistered", [aName
]);
589 message
= this._getFormattedString("addHandler", [aName
, aURI
.host
]);
593 label
: self
._getString("addHandlerAddButton"),
594 accessKey
: self
._getString("addHandlerAddButtonAccesskey"),
595 feedReaderInfo
: { uri
: uriSpec
, name
: aName
},
599 function WCCR__addFeedReaderButtonCallback(aNotification
, aButtonInfo
) {
600 var uri
= aButtonInfo
.feedReaderInfo
.uri
;
601 var name
= aButtonInfo
.feedReaderInfo
.name
;
602 var outer
= aButtonInfo
._outer
;
604 // The reader could have been added from another window mean while
605 if (!outer
.getWebContentHandlerByURI(TYPE_MAYBE_FEED
, uri
))
606 outer
._registerContentHandler(TYPE_MAYBE_FEED
, uri
, name
);
608 // avoid reference cycles
609 aButtonInfo
._outer
= null;
614 buttons
= [addButton
];
617 aNotificationBox
.appendNotification(message
,
620 aNotificationBox
.PRIORITY_INFO_LOW
,
626 * Save Web Content Handler metadata to persistent preferences.
628 * The content Type being handled
630 * The uri of the web service
632 * The human readable name of the web service
634 * This data is stored under:
636 * browser.contentHandlers.type0 = content/type
637 * browser.contentHandlers.uri0 = http://www.foo.com/q=%s
638 * browser.contentHandlers.title0 = Foo 2.0alphr
640 _saveContentHandlerToPrefs
:
641 function WCCR__saveContentHandlerToPrefs(contentType
, uri
, title
) {
643 Cc
["@mozilla.org/preferences-service;1"].
644 getService(Ci
.nsIPrefService
);
646 var typeBranch
= null;
649 ps
.getBranch(PREF_CONTENTHANDLERS_BRANCH
+ i
+ ".");
651 typeBranch
.getCharPref("type");
660 typeBranch
.setCharPref("type", contentType
);
662 Cc
["@mozilla.org/pref-localizedstring;1"].
663 createInstance(Ci
.nsIPrefLocalizedString
);
665 typeBranch
.setComplexValue("uri", Ci
.nsIPrefLocalizedString
, pls
);
667 typeBranch
.setComplexValue("title", Ci
.nsIPrefLocalizedString
, pls
);
669 ps
.savePrefFile(null);
674 * Determines if there is a type with a particular uri registered for the
675 * specified content type already.
677 * The content type that the uri handles
681 _typeIsRegistered
: function WCCR__typeIsRegistered(contentType
, uri
) {
682 if (!(contentType
in this._contentTypes
))
685 var services
= this._contentTypes
[contentType
];
686 for (var i
= 0; i
< services
.length
; ++i
) {
687 // This uri has already been registered
688 if (services
[i
].uri
== uri
)
695 * Gets a stream converter contract id for the specified content type.
697 * The source content type for the conversion.
698 * @returns A contract id to construct a converter to convert between the
699 * contentType and *\/*.
701 _getConverterContractID
: function WCCR__getConverterContractID(contentType
) {
702 const template
= "@mozilla.org/streamconv;1?from=%s&to=*/*";
703 return template
.replace(/%s/, contentType
);
707 * Register a web service handler for a content type.
710 * the content type being handled
712 * the URI of the web service
714 * the human readable name of the web service
716 _registerContentHandler
:
717 function WCCR__registerContentHandler(contentType
, uri
, title
) {
718 this._updateContentTypeHandlerMap(contentType
, uri
, title
);
719 this._saveContentHandlerToPrefs(contentType
, uri
, title
);
721 if (contentType
== TYPE_MAYBE_FEED
) {
722 // Make the new handler the last-selected reader in the preview page
723 // and make sure the preview page is shown the next time a feed is visited
724 var pb
= Cc
["@mozilla.org/preferences-service;1"].
725 getService(Ci
.nsIPrefService
).getBranch(null);
726 pb
.setCharPref(PREF_SELECTED_READER
, "web");
729 Cc
["@mozilla.org/supports-string;1"].
730 createInstance(Ci
.nsISupportsString
);
731 supportsString
.data
= uri
;
732 pb
.setComplexValue(PREF_SELECTED_WEB
, Ci
.nsISupportsString
,
734 pb
.setCharPref(PREF_SELECTED_ACTION
, "ask");
735 this._setAutoHandler(TYPE_MAYBE_FEED
, null);
740 * Update the content type -> handler map. This mapping is not persisted, use
741 * registerContentHandler or _saveContentHandlerToPrefs for that purpose.
743 * The content Type being handled
745 * The uri of the web service
747 * The human readable name of the web service
749 _updateContentTypeHandlerMap
:
750 function WCCR__updateContentTypeHandlerMap(contentType
, uri
, title
) {
751 if (!(contentType
in this._contentTypes
))
752 this._contentTypes
[contentType
] = [];
754 // Avoid adding duplicates
755 if (this._typeIsRegistered(contentType
, uri
))
758 this._contentTypes
[contentType
].push(new ServiceInfo(contentType
, uri
, title
));
760 if (!(contentType
in this._blockedTypes
)) {
761 var converterContractID
= this._getConverterContractID(contentType
);
762 var cr
= Components
.manager
.QueryInterface(Ci
.nsIComponentRegistrar
);
763 cr
.registerFactory(WCC_CLASSID
, WCC_CLASSNAME
, converterContractID
,
764 WebContentConverterFactory
);
769 * See nsIWebContentConverterService
772 function WCCR_getContentHandlers(contentType
, countRef
) {
774 if (!(contentType
in this._contentTypes
))
777 var handlers
= this._contentTypes
[contentType
];
778 countRef
.value
= handlers
.length
;
783 * See nsIWebContentConverterService
785 resetHandlersForType
:
786 function WCCR_resetHandlersForType(contentType
) {
787 // currently unused within the tree, so only useful for extensions; previous
788 // impl. was buggy (and even infinite-looped!), so I argue that this is a
789 // definite improvement
790 throw Cr
.NS_ERROR_NOT_IMPLEMENTED
;
794 * Registers a handler from the settings on a preferences branch.
797 * an nsIPrefBranch containing "type", "uri", and "title" preferences
798 * corresponding to the content handler to be registered
800 _registerContentHandlerWithBranch: function(branch
) {
802 * Since we support up to six predefined readers, we need to handle gaps
803 * better, since the first branch with user-added values will be .6
805 * How we deal with that is to check to see if there's no prefs in the
806 * branch and stop cycling once that's true. This doesn't fix the case
807 * where a user manually removes a reader, but that's not supported yet!
809 var vals
= branch
.getChildList("", {});
810 if (vals
.length
== 0)
814 var type
= branch
.getCharPref("type");
815 var uri
= branch
.getComplexValue("uri", Ci
.nsIPrefLocalizedString
).data
;
816 var title
= branch
.getComplexValue("title",
817 Ci
.nsIPrefLocalizedString
).data
;
818 this._updateContentTypeHandlerMap(type
, uri
, title
);
821 // do nothing, the next branch might have values
826 * Load the auto handler, content handler and protocol tables from
829 _init
: function WCCR__init() {
831 Cc
["@mozilla.org/preferences-service;1"].
832 getService(Ci
.nsIPrefService
);
834 var kids
= ps
.getBranch(PREF_CONTENTHANDLERS_BRANCH
)
835 .getChildList("", {});
837 // first get the numbers of the providers by getting all ###.uri prefs
839 for (var i
= 0; i
< kids
.length
; i
++) {
840 var match
= /^(\d+)\.uri$/.exec(kids
[i
]);
847 // sort them, to get them back in order
848 nums
.sort(function(a
, b
) {return a
- b
;});
851 for (var i
= 0; i
< nums
.length
; i
++) {
852 var branch
= ps
.getBranch(PREF_CONTENTHANDLERS_BRANCH
+ nums
[i
] + ".");
853 this._registerContentHandlerWithBranch(branch
);
856 // We need to do this _after_ registering all of the available handlers,
857 // so that getWebContentHandlerByURI can return successfully.
859 var autoBranch
= ps
.getBranch(PREF_CONTENTHANDLERS_AUTO
);
860 var childPrefs
= autoBranch
.getChildList("", { });
861 for (var i
= 0; i
< childPrefs
.length
; ++i
) {
862 var type
= childPrefs
[i
];
863 var uri
= autoBranch
.getCharPref(type
);
865 var handler
= this.getWebContentHandlerByURI(type
, uri
);
866 this._setAutoHandler(type
, handler
);
871 // No auto branch yet, that's fine
872 //LOG("WCCR.init: There is no auto branch, benign");
879 observe
: function WCCR_observe(subject
, topic
, data
) {
881 Cc
["@mozilla.org/observer-service;1"].
882 getService(Ci
.nsIObserverService
);
885 os
.addObserver(this, "browser-ui-startup-complete", false);
887 case "browser-ui-startup-complete":
888 os
.removeObserver(this, "browser-ui-startup-complete");
897 createInstance
: function WCCR_createInstance(outer
, iid
) {
899 throw Cr
.NS_ERROR_NO_AGGREGATION
;
900 return this.QueryInterface(iid
);
906 getInterfaces
: function WCCR_getInterfaces(countRef
) {
908 [Ci
.nsIWebContentConverterService
, Ci
.nsIWebContentHandlerRegistrar
,
909 Ci
.nsIObserver
, Ci
.nsIClassInfo
, Ci
.nsIFactory
, Ci
.nsISupports
];
910 countRef
.value
= interfaces
.length
;
913 getHelperForLanguage
: function WCCR_getHelperForLanguage(language
) {
916 contractID
: WCCR_CONTRACTID
,
917 classDescription
: WCCR_CLASSNAME
,
918 classID
: WCCR_CLASSID
,
919 implementationLanguage
: Ci
.nsIProgrammingLanguage
.JAVASCRIPT
,
920 flags
: Ci
.nsIClassInfo
.DOM_OBJECT
,
925 QueryInterface
: XPCOMUtils
.generateQI(
926 [Ci
.nsIWebContentConverterService
,
927 Ci
.nsIWebContentHandlerRegistrar
,
933 _xpcom_categories
: [{
934 category
: "app-startup",
939 function NSGetModule(cm
, file
) {
940 return XPCOMUtils
.generateModule([WebContentConverterRegistrar
]);
943 #include
../../../../toolkit
/content/debug.js