Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / browser / components / feeds / src / FeedConverter.js
blobcd192906f223cdac6250fc5b84ae4bf4ff5cdb8f
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
13 # License.
15 # The Original Code is the Feed Stream Converter.
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.
21 # Contributor(s):
22 # Ben Goodger <beng@google.com>
23 # Jeff Walden <jwalden+code@mit.edu>
24 # Will Guaraldi <will.guaraldi@pculture.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 const Cc = Components.classes;
41 const Ci = Components.interfaces;
42 const Cr = Components.results;
44 function LOG(str) {
45 dump("*** " + str + "\n");
48 const FC_CLASSID = Components.ID("{229fa115-9412-4d32-baf3-2fc407f76fb1}");
49 const FC_CLASSNAME = "Feed Stream Converter";
50 const FS_CLASSID = Components.ID("{2376201c-bbc6-472f-9b62-7548040a61c6}");
51 const FS_CLASSNAME = "Feed Result Service";
52 const FS_CONTRACTID = "@mozilla.org/browser/feeds/result-service;1";
53 const FPH_CONTRACTID = "@mozilla.org/network/protocol;1?name=feed";
54 const FPH_CLASSID = Components.ID("{4f91ef2e-57ba-472e-ab7a-b4999e42d6c0}");
55 const FPH_CLASSNAME = "Feed Protocol Handler";
56 const PCPH_CONTRACTID = "@mozilla.org/network/protocol;1?name=pcast";
57 const PCPH_CLASSID = Components.ID("{1c31ed79-accd-4b94-b517-06e0c81999d5}");
58 const PCPH_CLASSNAME = "Podcast Protocol Handler";
60 const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
61 const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
62 const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
63 const TYPE_ANY = "*/*";
65 const FEEDHANDLER_URI = "about:feeds";
67 const PREF_SELECTED_APP = "browser.feeds.handlers.application";
68 const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
69 const PREF_SELECTED_ACTION = "browser.feeds.handler";
70 const PREF_SELECTED_READER = "browser.feeds.handler.default";
72 const PREF_VIDEO_SELECTED_APP = "browser.videoFeeds.handlers.application";
73 const PREF_VIDEO_SELECTED_WEB = "browser.videoFeeds.handlers.webservice";
74 const PREF_VIDEO_SELECTED_ACTION = "browser.videoFeeds.handler";
75 const PREF_VIDEO_SELECTED_READER = "browser.videoFeeds.handler.default";
77 const PREF_AUDIO_SELECTED_APP = "browser.audioFeeds.handlers.application";
78 const PREF_AUDIO_SELECTED_WEB = "browser.audioFeeds.handlers.webservice";
79 const PREF_AUDIO_SELECTED_ACTION = "browser.audioFeeds.handler";
80 const PREF_AUDIO_SELECTED_READER = "browser.audioFeeds.handler.default";
82 function getPrefAppForType(t) {
83 switch (t) {
84 case Ci.nsIFeed.TYPE_VIDEO:
85 return PREF_VIDEO_SELECTED_APP;
87 case Ci.nsIFeed.TYPE_AUDIO:
88 return PREF_AUDIO_SELECTED_APP;
90 default:
91 return PREF_SELECTED_APP;
95 function getPrefWebForType(t) {
96 switch (t) {
97 case Ci.nsIFeed.TYPE_VIDEO:
98 return PREF_VIDEO_SELECTED_WEB;
100 case Ci.nsIFeed.TYPE_AUDIO:
101 return PREF_AUDIO_SELECTED_WEB;
103 default:
104 return PREF_SELECTED_WEB;
108 function getPrefActionForType(t) {
109 switch (t) {
110 case Ci.nsIFeed.TYPE_VIDEO:
111 return PREF_VIDEO_SELECTED_ACTION;
113 case Ci.nsIFeed.TYPE_AUDIO:
114 return PREF_AUDIO_SELECTED_ACTION;
116 default:
117 return PREF_SELECTED_ACTION;
121 function getPrefReaderForType(t) {
122 switch (t) {
123 case Ci.nsIFeed.TYPE_VIDEO:
124 return PREF_VIDEO_SELECTED_READER;
126 case Ci.nsIFeed.TYPE_AUDIO:
127 return PREF_AUDIO_SELECTED_READER;
129 default:
130 return PREF_SELECTED_READER;
134 function safeGetCharPref(pref, defaultValue) {
135 var prefs =
136 Cc["@mozilla.org/preferences-service;1"].
137 getService(Ci.nsIPrefBranch);
138 try {
139 return prefs.getCharPref(pref);
141 catch (e) {
143 return defaultValue;
146 function FeedConverter() {
148 FeedConverter.prototype = {
150 * This is the downloaded text data for the feed.
152 _data: null,
155 * This is the object listening to the conversion, which is ultimately the
156 * docshell for the load.
158 _listener: null,
161 * Records if the feed was sniffed
163 _sniffed: false,
166 * See nsIStreamConverter.idl
168 canConvert: function FC_canConvert(sourceType, destinationType) {
169 // We only support one conversion.
170 return destinationType == TYPE_ANY && ((sourceType == TYPE_MAYBE_FEED) ||
171 (sourceType == TYPE_MAYBE_VIDEO) ||
172 (sourceType == TYPE_MAYBE_AUDIO));
176 * See nsIStreamConverter.idl
178 convert: function FC_convert(sourceStream, sourceType, destinationType,
179 context) {
180 throw Cr.NS_ERROR_NOT_IMPLEMENTED;
184 * See nsIStreamConverter.idl
186 asyncConvertData: function FC_asyncConvertData(sourceType, destinationType,
187 listener, context) {
188 this._listener = listener;
192 * Whether or not the preview page is being forced.
194 _forcePreviewPage: false,
196 /**
197 * Release our references to various things once we're done using them.
199 _releaseHandles: function FC__releaseHandles() {
200 this._listener = null;
201 this._request = null;
202 this._processor = null;
206 * See nsIFeedResultListener.idl
208 handleResult: function FC_handleResult(result) {
209 // Feeds come in various content types, which our feed sniffer coerces to
210 // the maybe.feed type. However, feeds are used as a transport for
211 // different data types, e.g. news/blogs (traditional feed), video/audio
212 // (podcasts) and photos (photocasts, photostreams). Each of these is
213 // different in that there's a different class of application suitable for
214 // handling feeds of that type, but without a content-type differentiation
215 // it is difficult for us to disambiguate.
217 // The other problem is that if the user specifies an auto-action handler
218 // for one feed application, the fact that the content type is shared means
219 // that all other applications will auto-load with that handler too,
220 // regardless of the content-type.
222 // This means that content-type alone is not enough to determine whether
223 // or not a feed should be auto-handled. This means that for feeds we need
224 // to always use this stream converter, even when an auto-action is
225 // specified, not the basic one provided by WebContentConverter. This
226 // converter needs to consume all of the data and parse it, and based on
227 // that determination make a judgement about type.
229 // Since there are no content types for this content, and I'm not going to
230 // invent any, the upshot is that while a user can set an auto-handler for
231 // generic feed content, the system will prevent them from setting an auto-
232 // handler for other stream types. In those cases, the user will always see
233 // the preview page and have to select a handler. We can guess and show
234 // a client handler, but will not be able to show web handlers for those
235 // types.
237 // If this is just a feed, not some kind of specialized application, then
238 // auto-handlers can be set and we should obey them.
239 try {
240 var feedService =
241 Cc["@mozilla.org/browser/feeds/result-service;1"].
242 getService(Ci.nsIFeedResultService);
243 if (!this._forcePreviewPage && result.doc) {
244 var feed = result.doc.QueryInterface(Ci.nsIFeed);
245 var handler = safeGetCharPref(getPrefActionForType(feed.type), "ask");
247 if (handler != "ask") {
248 if (handler == "reader")
249 handler = safeGetCharPref(getPrefReaderForType(feed.type), "bookmarks");
250 switch (handler) {
251 case "web":
252 var wccr =
253 Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
254 getService(Ci.nsIWebContentConverterService);
255 if ((feed.type == Ci.nsIFeed.TYPE_FEED &&
256 wccr.getAutoHandler(TYPE_MAYBE_FEED)) ||
257 (feed.type == Ci.nsIFeed.TYPE_VIDEO &&
258 wccr.getAutoHandler(TYPE_MAYBE_VIDEO_FEED)) ||
259 (feed.type == Ci.nsIFeed.TYPE_AUDIO &&
260 wccr.getAutoHandler(TYPE_MAYBE_AUDIO_FEED))) {
261 wccr.loadPreferredHandler(this._request);
262 return;
264 break;
266 default:
267 LOG("unexpected handler: " + handler);
268 // fall through -- let feed service handle error
269 case "bookmarks":
270 case "client":
271 try {
272 var title = feed.title ? feed.title.plainText() : "";
273 var desc = feed.subtitle ? feed.subtitle.plainText() : "";
274 feedService.addToClientReader(result.uri.spec, title, desc, feed.type);
275 return;
276 } catch(ex) { /* fallback to preview mode */ }
281 var ios =
282 Cc["@mozilla.org/network/io-service;1"].
283 getService(Ci.nsIIOService);
284 var chromeChannel;
286 // show the feed page if it wasn't sniffed and we have a document,
287 // or we have a document, title, and link or id
288 if (result.doc && (!this._sniffed ||
289 (result.doc.title && (result.doc.link || result.doc.id)))) {
291 // If there was no automatic handler, or this was a podcast,
292 // photostream or some other kind of application, we must always
293 // show the preview page.
295 // Store the result in the result service so that the display
296 // page can access it.
298 feedService.addFeedResult(result);
300 // Now load the actual XUL document.
301 var chromeURI = ios.newURI(FEEDHANDLER_URI, null, null);
302 chromeChannel = ios.newChannelFromURI(chromeURI, null);
303 chromeChannel.originalURI = result.uri;
305 else
306 chromeChannel = ios.newChannelFromURI(result.uri, null);
308 chromeChannel.loadGroup = this._request.loadGroup;
309 chromeChannel.asyncOpen(this._listener, null);
311 finally {
312 this._releaseHandles();
317 * See nsIStreamListener.idl
319 onDataAvailable: function FC_onDataAvailable(request, context, inputStream,
320 sourceOffset, count) {
321 if (this._processor)
322 this._processor.onDataAvailable(request, context, inputStream,
323 sourceOffset, count);
327 * See nsIRequestObserver.idl
329 onStartRequest: function FC_onStartRequest(request, context) {
330 var channel = request.QueryInterface(Ci.nsIChannel);
332 // Check for a header that tells us there was no sniffing
333 // The value doesn't matter.
334 try {
335 var httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
336 var noSniff = httpChannel.getResponseHeader("X-Moz-Is-Feed");
338 catch (ex) {
339 this._sniffed = true;
342 this._request = request;
344 // Save and reset the forced state bit early, in case there's some kind of
345 // error.
346 var feedService =
347 Cc["@mozilla.org/browser/feeds/result-service;1"].
348 getService(Ci.nsIFeedResultService);
349 this._forcePreviewPage = feedService.forcePreviewPage;
350 feedService.forcePreviewPage = false;
352 // Parse feed data as it comes in
353 this._processor =
354 Cc["@mozilla.org/feed-processor;1"].
355 createInstance(Ci.nsIFeedProcessor);
356 this._processor.listener = this;
357 this._processor.parseAsync(null, channel.URI);
359 this._processor.onStartRequest(request, context);
363 * See nsIRequestObserver.idl
365 onStopRequest: function FC_onStopReqeust(request, context, status) {
366 if (this._processor)
367 this._processor.onStopRequest(request, context, status);
371 * See nsISupports.idl
373 QueryInterface: function FC_QueryInterface(iid) {
374 if (iid.equals(Ci.nsIFeedResultListener) ||
375 iid.equals(Ci.nsIStreamConverter) ||
376 iid.equals(Ci.nsIStreamListener) ||
377 iid.equals(Ci.nsIRequestObserver)||
378 iid.equals(Ci.nsISupports))
379 return this;
380 throw Cr.NS_ERROR_NO_INTERFACE;
384 var FeedConverterFactory = {
385 createInstance: function FS_createInstance(outer, iid) {
386 if (outer != null)
387 throw Cr.NS_ERROR_NO_AGGREGATION;
388 return new FeedConverter().QueryInterface(iid);
391 QueryInterface: function FS_QueryInterface(iid) {
392 if (iid.equals(Ci.nsIFactory) ||
393 iid.equals(Ci.nsISupports))
394 return this;
395 throw Cr.NS_ERROR_NO_INTERFACE;
400 * Keeps parsed FeedResults around for use elsewhere in the UI after the stream
401 * converter completes.
403 var FeedResultService = {
406 * A URI spec -> [nsIFeedResult] hash. We have to keep a list as the
407 * value in case the same URI is requested concurrently.
409 _results: { },
412 * See nsIFeedResultService.idl
414 forcePreviewPage: false,
417 * See nsIFeedResultService.idl
419 addToClientReader: function FRS_addToClientReader(spec, title, subtitle, feedType) {
420 var prefs =
421 Cc["@mozilla.org/preferences-service;1"].
422 getService(Ci.nsIPrefBranch);
424 var handler = safeGetCharPref(getPrefActionForType(feedType), "bookmarks");
425 if (handler == "ask" || handler == "reader")
426 handler = safeGetCharPref(getPrefReaderForType(feedType), "bookmarks");
428 switch (handler) {
429 case "client":
430 var clientApp = prefs.getComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile);
432 // For the benefit of applications that might know how to deal with more
433 // URLs than just feeds, send feed: URLs in the following format:
435 // http urls: replace scheme with feed, e.g.
436 // http://foo.com/index.rdf -> feed://foo.com/index.rdf
437 // other urls: prepend feed: scheme, e.g.
438 // https://foo.com/index.rdf -> feed:https://foo.com/index.rdf
439 var ios =
440 Cc["@mozilla.org/network/io-service;1"].
441 getService(Ci.nsIIOService);
442 var feedURI = ios.newURI(spec, null, null);
443 if (feedURI.schemeIs("http")) {
444 feedURI.scheme = "feed";
445 spec = feedURI.spec;
447 else
448 spec = "feed:" + spec;
450 // Retrieving the shell service might fail on some systems, most
451 // notably systems where GNOME is not installed.
452 try {
453 var ss =
454 Cc["@mozilla.org/browser/shell-service;1"].
455 getService(Ci.nsIShellService);
456 ss.openApplicationWithURI(clientApp, spec);
457 } catch(e) {
458 // If we couldn't use the shell service, fallback to using a
459 // nsIProcess instance
460 var p =
461 Cc["@mozilla.org/process/util;1"].
462 createInstance(Ci.nsIProcess);
463 p.init(clientApp);
464 p.run(false, [spec], 1);
466 break;
468 default:
469 // "web" should have been handled elsewhere
470 LOG("unexpected handler: " + handler);
471 // fall through
472 case "bookmarks":
473 var wm =
474 Cc["@mozilla.org/appshell/window-mediator;1"].
475 getService(Ci.nsIWindowMediator);
476 var topWindow = wm.getMostRecentWindow("navigator:browser");
477 topWindow.PlacesCommandHook.addLiveBookmark(spec, title, subtitle);
478 break;
483 * See nsIFeedResultService.idl
485 addFeedResult: function FRS_addFeedResult(feedResult) {
486 NS_ASSERT(feedResult.uri != null, "null URI!");
487 NS_ASSERT(feedResult.uri != null, "null feedResult!");
488 var spec = feedResult.uri.spec;
489 if(!this._results[spec])
490 this._results[spec] = [];
491 this._results[spec].push(feedResult);
495 * See nsIFeedResultService.idl
497 getFeedResult: function RFS_getFeedResult(uri) {
498 NS_ASSERT(uri != null, "null URI!");
499 var resultList = this._results[uri.spec];
500 for (var i in resultList) {
501 if (resultList[i].uri == uri)
502 return resultList[i];
504 return null;
508 * See nsIFeedResultService.idl
510 removeFeedResult: function FRS_removeFeedResult(uri) {
511 NS_ASSERT(uri != null, "null URI!");
512 var resultList = this._results[uri.spec];
513 if (!resultList)
514 return;
515 var deletions = 0;
516 for (var i = 0; i < resultList.length; ++i) {
517 if (resultList[i].uri == uri) {
518 delete resultList[i];
519 ++deletions;
523 // send the holes to the end
524 resultList.sort();
525 // and trim the list
526 resultList.splice(resultList.length - deletions, deletions);
527 if (resultList.length == 0)
528 delete this._results[uri.spec];
531 createInstance: function FRS_createInstance(outer, iid) {
532 if (outer != null)
533 throw Cr.NS_ERROR_NO_AGGREGATION;
534 return this.QueryInterface(iid);
537 QueryInterface: function FRS_QueryInterface(iid) {
538 if (iid.equals(Ci.nsIFeedResultService) ||
539 iid.equals(Ci.nsIFactory) ||
540 iid.equals(Ci.nsISupports))
541 return this;
542 throw Cr.NS_ERROR_NOT_IMPLEMENTED;
547 * A protocol handler that attempts to deal with the variant forms of feed:
548 * URIs that are actually either http or https.
550 function FeedProtocolHandler(scheme) {
551 this._scheme = scheme;
552 var ios =
553 Cc["@mozilla.org/network/io-service;1"].
554 getService(Ci.nsIIOService);
555 this._http = ios.getProtocolHandler("http");
557 FeedProtocolHandler.prototype = {
558 _scheme: "",
559 get scheme() {
560 return this._scheme;
563 get protocolFlags() {
564 return this._http.protocolFlags;
567 get defaultPort() {
568 return this._http.defaultPort;
571 allowPort: function FPH_allowPort(port, scheme) {
572 return this._http.allowPort(port, scheme);
575 newURI: function FPH_newURI(spec, originalCharset, baseURI) {
576 // See bug 408599 - feed URIs can be either standard URLs of the form
577 // feed://example.com, in which case the real protocol is http, or nested
578 // URIs of the form feed:realscheme:. When realscheme is either http or
579 // https, we deal with the way that creates a standard URL with the
580 // realscheme as the host by unmangling in newChannel; for others, we fail
581 // rather than let it wind up loading something like www.realscheme.com//foo
583 const feedSlashes = "feed://";
584 const feedHttpSlashes = "feed:http://";
585 const feedHttpsSlashes = "feed:https://";
586 const NS_ERROR_MALFORMED_URI = 0x804B000A;
588 if (spec.substr(0, feedSlashes.length) != feedSlashes &&
589 spec.substr(0, feedHttpSlashes.length) != feedHttpSlashes &&
590 spec.substr(0, feedHttpsSlashes.length) != feedHttpsSlashes)
591 throw NS_ERROR_MALFORMED_URI;
593 var uri =
594 Cc["@mozilla.org/network/standard-url;1"].
595 createInstance(Ci.nsIStandardURL);
596 uri.init(Ci.nsIStandardURL.URLTYPE_STANDARD, 80, spec, originalCharset,
597 baseURI);
598 return uri;
601 newChannel: function FPH_newChannel(aUri) {
602 var ios =
603 Cc["@mozilla.org/network/io-service;1"].
604 getService(Ci.nsIIOService);
605 // feed: URIs either start feed://, in which case the real scheme is http:
606 // or feed:http(s)://, (which by now we've changed to feed://realscheme//)
607 var feedSpec = aUri.spec;
608 const httpsChunk = "feed://https//";
609 const httpChunk = "feed://http//";
610 if (feedSpec.substr(0, httpsChunk.length) == httpsChunk)
611 feedSpec = "https://" + feedSpec.substr(httpsChunk.length);
612 else if (feedSpec.substr(0, httpChunk.length) == httpChunk)
613 feedSpec = "http://" + feedSpec.substr(httpChunk.length);
614 else
615 feedSpec = feedSpec.replace(/^feed/, "http");
617 var uri = ios.newURI(feedSpec, aUri.originCharset, null);
618 var channel =
619 ios.newChannelFromURI(uri, null).QueryInterface(Ci.nsIHttpChannel);
620 // Set this so we know this is supposed to be a feed
621 channel.setRequestHeader("X-Moz-Is-Feed", "1", false);
622 channel.originalURI = aUri;
623 return channel;
626 QueryInterface: function FPH_QueryInterface(iid) {
627 if (iid.equals(Ci.nsIProtocolHandler) ||
628 iid.equals(Ci.nsISupports))
629 return this;
630 throw Cr.NS_ERROR_NO_INTERFACE;
634 var Module = {
635 QueryInterface: function M_QueryInterface(iid) {
636 if (iid.equals(Ci.nsIModule) ||
637 iid.equals(Ci.nsISupports))
638 return this;
639 throw Cr.NS_ERROR_NO_INTERFACE;
642 getClassObject: function M_getClassObject(cm, cid, iid) {
643 if (!iid.equals(Ci.nsIFactory))
644 throw Cr.NS_ERROR_NOT_IMPLEMENTED;
646 if (cid.equals(FS_CLASSID))
647 return FeedResultService;
648 if (cid.equals(FPH_CLASSID))
649 return new GenericComponentFactory(FeedProtocolHandler, "feed");
650 if (cid.equals(PCPH_CLASSID))
651 return new GenericComponentFactory(FeedProtocolHandler, "pcast");
652 if (cid.equals(FC_CLASSID))
653 return new GenericComponentFactory(FeedConverter);
655 throw Cr.NS_ERROR_NO_INTERFACE;
658 registerSelf: function M_registerSelf(cm, file, location, type) {
659 var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
661 cr.registerFactoryLocation(FS_CLASSID, FS_CLASSNAME, FS_CONTRACTID,
662 file, location, type);
663 cr.registerFactoryLocation(FPH_CLASSID, FPH_CLASSNAME, FPH_CONTRACTID,
664 file, location, type);
665 cr.registerFactoryLocation(PCPH_CLASSID, PCPH_CLASSNAME, PCPH_CONTRACTID,
666 file, location, type);
668 // The feed converter is always attached, since parsing must be done to
669 // determine whether or not auto-handling can occur.
670 const converterPrefix = "@mozilla.org/streamconv;1?from=";
671 var converterContractID =
672 converterPrefix + TYPE_MAYBE_FEED + "&to=" + TYPE_ANY;
673 cr.registerFactoryLocation(FC_CLASSID, FC_CLASSNAME, converterContractID,
674 file, location, type);
676 converterContractID =
677 converterPrefix + TYPE_MAYBE_VIDEO_FEED + "&to=" + TYPE_ANY;
678 cr.registerFactoryLocation(FC_CLASSID, FC_CLASSNAME, converterContractID,
679 file, location, type);
681 converterContractID =
682 converterPrefix + TYPE_MAYBE_AUDIO_FEED + "&to=" + TYPE_ANY;
683 cr.registerFactoryLocation(FC_CLASSID, FC_CLASSNAME, converterContractID,
684 file, location, type);
687 unregisterSelf: function M_unregisterSelf(cm, location, type) {
688 var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
689 cr.unregisterFactoryLocation(FPH_CLASSID, location);
690 cr.unregisterFactoryLocation(PCPH_CLASSID, location);
693 canUnload: function M_canUnload(cm) {
694 return true;
698 function NSGetModule(cm, file) {
699 return Module;
702 #include ../../../../toolkit/content/debug.js
703 #include GenericFactory.js