WebContentConverter.js
Go to the documentation of this file.
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
4 #
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/
9 #
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.
14 #
15 # The Original Code is the Web Content Converter System.
16 #
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.
20 #
21 # Contributor(s):
22 # Ben Goodger <beng@google.com>
23 # Asaf Romano <mano@mozilla.com>
24 # Dan Mosedale <dmose@mozilla.org>
25 #
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.
37 #
38 # ***** END LICENSE BLOCK ***** */
39 
40 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
41 
42 const Cc = Components.classes;
43 const Ci = Components.interfaces;
44 const Cr = Components.results;
45 
46 function LOG(str) {
47  dump("*** " + str + "\n");
48 }
49 
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";
53 
54 const WCC_CLASSID = Components.ID("{db7ebf28-cc40-415f-8a51-1b111851df1e}");
55 const WCC_CLASSNAME = "Web Service Handler";
56 
57 const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
58 const TYPE_ANY = "*/*";
59 
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";
67 
68 const STRING_BUNDLE_URI = "chrome://browser/locale/feeds/subscribe.properties";
69 
70 const NS_ERROR_MODULE_DOM = 2152923136;
72 
73 function WebContentConverter() {
74 }
75 WebContentConverter.prototype = {
76  convert: function WCC_convert() { },
77  asyncConvertData: function WCC_asyncConvertData() { },
78  onDataAvailable: function WCC_onDataAvailable() { },
79  onStopRequest: function WCC_onStopRequest() { },
80 
81  onStartRequest: function WCC_onStartRequest(request, context) {
82  var wccr =
84  getService(Ci.nsIWebContentConverterService);
85  wccr.loadPreferredHandler(request);
86  },
87 
88  QueryInterface: function WCC_QueryInterface(iid) {
89  if (iid.equals(Ci.nsIStreamConverter) ||
90  iid.equals(Ci.nsIStreamListener) ||
91  iid.equals(Ci.nsISupports))
92  return this;
93  throw Cr.NS_ERROR_NO_INTERFACE;
94  }
95 };
96 
98  createInstance: function WCCF_createInstance(outer, iid) {
99  if (outer != null)
100  throw Cr.NS_ERROR_NO_AGGREGATION;
101  return new WebContentConverter().QueryInterface(iid);
102  },
103 
104  QueryInterface: function WCC_QueryInterface(iid) {
105  if (iid.equals(Ci.nsIFactory) ||
106  iid.equals(Ci.nsISupports))
107  return this;
108  throw Cr.NS_ERROR_NO_INTERFACE;
109  }
110 };
111 
112 function ServiceInfo(contentType, uri, name) {
113  this._contentType = contentType;
114  this._uri = uri;
115  this._name = name;
116 }
117 ServiceInfo.prototype = {
121  get name() {
122  return this._name;
123  },
124 
128  equals: function SI_equals(aHandlerApp) {
129  if (!aHandlerApp)
130  throw Cr.NS_ERROR_NULL_POINTER;
131 
132  if (aHandlerApp instanceof Ci.nsIWebContentHandlerInfo &&
133  aHandlerApp.contentType == this.contentType &&
134  aHandlerApp.uri == this.uri)
135  return true;
136 
137  return false;
138  },
139 
143  get contentType() {
144  return this._contentType;
145  },
146 
150  get uri() {
151  return this._uri;
152  },
153 
157  getHandlerURI: function SI_getHandlerURI(uri) {
158  return this._uri.replace(/%s/gi, encodeURIComponent(uri));
159  },
160 
161  QueryInterface: function SI_QueryInterface(iid) {
162  if (iid.equals(Ci.nsIWebContentHandlerInfo) ||
163  iid.equals(Ci.nsISupports))
164  return this;
165  throw Cr.NS_ERROR_NO_INTERFACE;
166  }
167 };
168 
170  this._contentTypes = { };
171  this._autoHandleContentTypes = { };
172 }
173 
174 WebContentConverterRegistrar.prototype = {
175  get stringBundle() {
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;
181  },
182 
183  _getFormattedString: function WCCR__getFormattedString(key, params) {
184  return this.stringBundle.formatStringFromName(key, params, params.length);
185  },
186 
187  _getString: function WCCR_getString(key) {
188  return this.stringBundle.GetStringFromName(key);
189  },
190 
194  getAutoHandler:
195  function WCCR_getAutoHandler(contentType) {
196  contentType = this._resolveContentType(contentType);
197  if (contentType in this._autoHandleContentTypes)
198  return this._autoHandleContentTypes[contentType];
199  return null;
200  },
201 
205  setAutoHandler:
206  function WCCR_setAutoHandler(contentType, handler) {
207  if (handler && !this._typeIsRegistered(contentType, handler.uri))
208  throw Cr.NS_ERROR_NOT_AVAILABLE;
209 
210  contentType = this._resolveContentType(contentType);
211  this._setAutoHandler(contentType, handler);
212 
213  var ps =
214  Cc["@mozilla.org/preferences-service;1"].
215  getService(Ci.nsIPrefService);
216  var autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
217  if (handler)
218  autoBranch.setCharPref(contentType, handler.uri);
219  else if (autoBranch.prefHasUserValue(contentType))
220  autoBranch.clearUserPref(contentType);
221 
222  ps.savePrefFile(null);
223  },
224 
228  _setAutoHandler:
229  function WCCR__setAutoHandler(contentType, handler) {
230  if (handler)
231  this._autoHandleContentTypes[contentType] = handler;
232  else if (contentType in this._autoHandleContentTypes)
233  delete this._autoHandleContentTypes[contentType];
234  },
235 
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)
244  return handlers[i];
245  }
246  return null;
247  },
248 
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);
257  if (handler) {
258  request.cancel(Cr.NS_ERROR_FAILURE);
259 
260  var webNavigation =
261  channel.notificationCallbacks.getInterface(Ci.nsIWebNavigation);
262  webNavigation.loadURI(handler.getHandlerURI(channel.URI.spec),
263  Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
264  null, null, null);
265  }
266  },
267 
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);
285  return;
286  }
287  } catch (e) { /* it wasn't a web handler */ }
288  }
289  },
290 
294  removeContentHandler:
295  function WCCR_removeContentHandler(contentType, uri) {
296  function notURI(serviceInfo) {
297  return serviceInfo.uri != uri;
298  }
299 
300  if (contentType in this._contentTypes) {
301  this._contentTypes[contentType] =
302  this._contentTypes[contentType].filter(notURI);
303  }
304  },
305 
309  _mappings: {
310  "application/rss+xml": TYPE_MAYBE_FEED,
311  "application/atom+xml": TYPE_MAYBE_FEED,
312  },
313 
319  _blockedTypes: {
320  "application/vnd.mozilla.maybe.feed": true,
321  },
322 
328  _resolveContentType:
329  function WCCR__resolveContentType(contentType) {
330  if (contentType in this._mappings)
331  return this._mappings[contentType];
332  return contentType;
333  },
334 
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);
339  },
340 
341  _checkAndGetURI:
342  function WCCR_checkAndGetURI(aURIString, aContentWindow)
343  {
344  try {
345  var uri = this._makeURI(aURIString);
346  } catch (ex) {
347  // not supposed to throw according to spec
348  return;
349  }
350 
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");
357 
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");
365 
366  // If the uri doesn't contain '%s', it won't be a good handler
367  if (uri.spec.indexOf("%s") < 0)
369 
370  return uri;
371  },
372 
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)
392  return true;
393  } catch (e) { /* it wasn't a web handler */ }
394  }
395  return false;
396  },
397 
401  registerProtocolHandler:
402  function WCCR_registerProtocolHandler(aProtocol, aURIString, aTitle, aContentWindow) {
403  LOG("registerProtocolHandler(" + aProtocol + "," + aURIString + "," + aTitle + ")");
404 
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");
415  }
416 
417  // check if it is in the black list
418  var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
419  var allowed;
420  try {
421  allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "." + aProtocol);
422  }
423  catch (e) {
424  allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "-default");
425  }
426  if (!allowed) {
427  // XXX this should be a "security exception" according to spec
428  throw("Not allowed to register a protocol handler for " + aProtocol);
429  }
430 
431  var uri = this._checkAndGetURI(aURIString, aContentWindow);
432 
433  var buttons, message;
434  if (this._protocolHandlerRegistered(aProtocol, uri.spec))
435  message = this._getFormattedString("protocolHandlerRegistered",
436  [aTitle, aProtocol]);
437  else {
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;
445  var addButton = {
446  label: this._getString("addProtocolHandlerAddButton"),
447  accessKey: this._getString("addHandlerAddButtonAccesskey"),
448  protocolInfo: { protocol: aProtocol, uri: uri.spec, name: aTitle },
449 
450  callback:
451  function WCCR_addProtocolHandlerButtonCallback(aNotification, aButtonInfo) {
452  var protocol = aButtonInfo.protocolInfo.protocol;
453  var uri = aButtonInfo.protocolInfo.uri;
454  var name = aButtonInfo.protocolInfo.name;
455 
456  var handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
457  createInstance(Ci.nsIWebHandlerApp);
458  handler.name = name;
459  handler.uriTemplate = uri;
460 
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);
465 
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
469  // use.
470  handlerInfo.alwaysAskBeforeHandling = true;
471 
472  var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
473  getService(Ci.nsIHandlerService);
474  hs.store(handlerInfo);
475  }
476  };
477  buttons = [addButton];
478  }
479 
480  var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow);
481  var browserElement = this._getBrowserForContentWindow(browserWindow, aContentWindow);
482  var notificationBox = browserWindow.getBrowser().getNotificationBox(browserElement);
483  notificationBox.appendNotification(message,
484  notificationValue,
485  notificationIcon,
486  notificationBox.PRIORITY_INFO_LOW,
487  buttons);
488  },
489 
495  registerContentHandler:
496  function WCCR_registerContentHandler(aContentType, aURIString, aTitle, aContentWindow) {
497  LOG("registerContentHandler(" + aContentType + "," + aURIString + "," + aTitle + ")");
498 
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)
504  return;
505 
506  if (aContentWindow) {
507  var uri = this._checkAndGetURI(aURIString, aContentWindow);
508 
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);
513  }
514  else
515  this._registerContentHandler(contentType, aURIString, aTitle);
516  },
517 
521  _getBrowserWindowForContentWindow:
522  function WCCR__getBrowserWindowForContentWindow(aContentWindow) {
523  return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
524  .getInterface(Ci.nsIWebNavigation)
525  .QueryInterface(Ci.nsIDocShellTreeItem)
526  .rootTreeItem
527  .QueryInterface(Ci.nsIInterfaceRequestor)
528  .getInterface(Ci.nsIDOMWindow)
529  .wrappedJSObject;
530  },
531 
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)
549  return browsers[i];
550  }
551  },
552 
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";
579 
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))
583  return false;
584 
585  var buttons, message;
586  if (this.getWebContentHandlerByURI(TYPE_MAYBE_FEED, uriSpec))
587  message = this._getFormattedString("handlerRegistered", [aName]);
588  else {
589  message = this._getFormattedString("addHandler", [aName, aURI.host]);
590  var self = this;
591  var addButton = {
592  _outer: self,
593  label: self._getString("addHandlerAddButton"),
594  accessKey: self._getString("addHandlerAddButtonAccesskey"),
595  feedReaderInfo: { uri: uriSpec, name: aName },
596 
597  /* static */
598  callback:
599  function WCCR__addFeedReaderButtonCallback(aNotification, aButtonInfo) {
600  var uri = aButtonInfo.feedReaderInfo.uri;
601  var name = aButtonInfo.feedReaderInfo.name;
602  var outer = aButtonInfo._outer;
603 
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);
607 
608  // avoid reference cycles
609  aButtonInfo._outer = null;
610 
611  return false;
612  }
613  };
614  buttons = [addButton];
615  }
616 
617  aNotificationBox.appendNotification(message,
618  notificationValue,
619  notificationIcon,
620  aNotificationBox.PRIORITY_INFO_LOW,
621  buttons);
622  return true;
623  },
624 
640  _saveContentHandlerToPrefs:
641  function WCCR__saveContentHandlerToPrefs(contentType, uri, title) {
642  var ps =
643  Cc["@mozilla.org/preferences-service;1"].
644  getService(Ci.nsIPrefService);
645  var i = 0;
646  var typeBranch = null;
647  while (true) {
648  typeBranch =
649  ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + i + ".");
650  try {
651  typeBranch.getCharPref("type");
652  ++i;
653  }
654  catch (e) {
655  // No more handlers
656  break;
657  }
658  }
659  if (typeBranch) {
660  typeBranch.setCharPref("type", contentType);
661  var pls =
662  Cc["@mozilla.org/pref-localizedstring;1"].
663  createInstance(Ci.nsIPrefLocalizedString);
664  pls.data = uri;
665  typeBranch.setComplexValue("uri", Ci.nsIPrefLocalizedString, pls);
666  pls.data = title;
667  typeBranch.setComplexValue("title", Ci.nsIPrefLocalizedString, pls);
668 
669  ps.savePrefFile(null);
670  }
671  },
672 
681  _typeIsRegistered: function WCCR__typeIsRegistered(contentType, uri) {
682  if (!(contentType in this._contentTypes))
683  return false;
684 
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)
689  return true;
690  }
691  return false;
692  },
693 
701  _getConverterContractID: function WCCR__getConverterContractID(contentType) {
702  const template = "@mozilla.org/streamconv;1?from=%s&to=*/*";
703  return template.replace(/%s/, contentType);
704  },
705 
716  _registerContentHandler:
717  function WCCR__registerContentHandler(contentType, uri, title) {
718  this._updateContentTypeHandlerMap(contentType, uri, title);
719  this._saveContentHandlerToPrefs(contentType, uri, title);
720 
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");
727 
728  var supportsString =
729  Cc["@mozilla.org/supports-string;1"].
730  createInstance(Ci.nsISupportsString);
731  supportsString.data = uri;
732  pb.setComplexValue(PREF_SELECTED_WEB, Ci.nsISupportsString,
733  supportsString);
734  pb.setCharPref(PREF_SELECTED_ACTION, "ask");
735  this._setAutoHandler(TYPE_MAYBE_FEED, null);
736  }
737  },
738 
749  _updateContentTypeHandlerMap:
750  function WCCR__updateContentTypeHandlerMap(contentType, uri, title) {
751  if (!(contentType in this._contentTypes))
752  this._contentTypes[contentType] = [];
753 
754  // Avoid adding duplicates
755  if (this._typeIsRegistered(contentType, uri))
756  return;
757 
758  this._contentTypes[contentType].push(new ServiceInfo(contentType, uri, title));
759 
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);
765  }
766  },
767 
771  getContentHandlers:
772  function WCCR_getContentHandlers(contentType, countRef) {
773  countRef.value = 0;
774  if (!(contentType in this._contentTypes))
775  return [];
776 
777  var handlers = this._contentTypes[contentType];
778  countRef.value = handlers.length;
779  return handlers;
780  },
781 
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;
791  },
792 
800  _registerContentHandlerWithBranch: function(branch) {
809  var vals = branch.getChildList("", {});
810  if (vals.length == 0)
811  return;
812 
813  try {
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);
819  }
820  catch(ex) {
821  // do nothing, the next branch might have values
822  }
823  },
824 
829  _init: function WCCR__init() {
830  var ps =
831  Cc["@mozilla.org/preferences-service;1"].
832  getService(Ci.nsIPrefService);
833 
834  var kids = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH)
835  .getChildList("", {});
836 
837  // first get the numbers of the providers by getting all ###.uri prefs
838  var nums = [];
839  for (var i = 0; i < kids.length; i++) {
840  var match = /^(\d+)\.uri$/.exec(kids[i]);
841  if (!match)
842  continue;
843  else
844  nums.push(match[1]);
845  }
846 
847  // sort them, to get them back in order
848  nums.sort(function(a, b) {return a - b;});
849 
850  // now register them
851  for (var i = 0; i < nums.length; i++) {
852  var branch = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + nums[i] + ".");
853  this._registerContentHandlerWithBranch(branch);
854  }
855 
856  // We need to do this _after_ registering all of the available handlers,
857  // so that getWebContentHandlerByURI can return successfully.
858  try {
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);
864  if (uri) {
865  var handler = this.getWebContentHandlerByURI(type, uri);
866  this._setAutoHandler(type, handler);
867  }
868  }
869  }
870  catch (e) {
871  // No auto branch yet, that's fine
872  //LOG("WCCR.init: There is no auto branch, benign");
873  }
874  },
875 
879  observe: function WCCR_observe(subject, topic, data) {
880  var os =
881  Cc["@mozilla.org/observer-service;1"].
882  getService(Ci.nsIObserverService);
883  switch (topic) {
884  case "app-startup":
885  os.addObserver(this, "browser-ui-startup-complete", false);
886  break;
887  case "browser-ui-startup-complete":
888  os.removeObserver(this, "browser-ui-startup-complete");
889  this._init();
890  break;
891  }
892  },
893 
897  createInstance: function WCCR_createInstance(outer, iid) {
898  if (outer != null)
899  throw Cr.NS_ERROR_NO_AGGREGATION;
900  return this.QueryInterface(iid);
901  },
902 
906  getInterfaces: function WCCR_getInterfaces(countRef) {
907  var interfaces =
908  [Ci.nsIWebContentConverterService, Ci.nsIWebContentHandlerRegistrar,
909  Ci.nsIObserver, Ci.nsIClassInfo, Ci.nsIFactory, Ci.nsISupports];
910  countRef.value = interfaces.length;
911  return interfaces;
912  },
913  getHelperForLanguage: function WCCR_getHelperForLanguage(language) {
914  return null;
915  },
919  implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
920  flags: Ci.nsIClassInfo.DOM_OBJECT,
921 
925  QueryInterface: XPCOMUtils.generateQI(
926  [Ci.nsIWebContentConverterService,
927  Ci.nsIWebContentHandlerRegistrar,
928  Ci.nsIObserver,
929  Ci.nsIClassInfo,
930  Ci.nsIFactory,
931  Ci.nsISupports]),
932 
934  category: "app-startup",
935  service: true
936  }]
937 };
938 
939 function NSGetModule(cm, file) {
940  return XPCOMUtils.generateModule([WebContentConverterRegistrar]);
941 }
942 
943 #include ../../../../toolkit/content/debug.js
944 
const WCCR_CLASSNAME
const WCCR_CONTRACTID
function WebContentConverterRegistrar()
const NS_ERROR_DOM_SYNTAX_ERR
var wccr
Definition: FeedWriter.js:1042
nsString encodeURIComponent(const nsString &c)
const WCC_CLASSNAME
id service()
const TYPE_ANY
sbDeviceFirmwareAutoCheckForUpdate prototype flags
function ServiceInfo(contentType, uri, name)
sbDeviceFirmwareAutoCheckForUpdate prototype contractID
const Cc
const NS_ERROR_MODULE_DOM
sidebarFactory createInstance
Definition: nsSidebar.js:351
sbOSDControlService prototype QueryInterface
var handlers
Definition: FeedWriter.js:1044
sbDeviceFirmwareAutoCheckForUpdate prototype classDescription
const PREF_SELECTED_ACTION
var ioService
var language
Definition: Info.js:44
getService(Ci.sbIFaceplateManager)
sbDeviceFirmwareAutoCheckForUpdate prototype getHelperForLanguage
function d(s)
this _contentSandbox label
Definition: FeedWriter.js:814
function LOG(str)
const PREF_SELECTED_READER
var WebContentConverterFactory
const PREF_CONTENTHANDLERS_AUTO
const WCC_CLASSID
function WebContentConverter()
grep callback
const PREF_SELECTED_WEB
ExtensionSchemeMatcher prototype match
GstMessage * message
return null
Definition: FeedWriter.js:1143
const TYPE_MAYBE_FEED
var os
_updateCookies aName
var uri
Definition: FeedWriter.js:1135
const WCCR_CLASSID
const STRING_BUNDLE_URI
const PREF_HANDLER_EXTERNAL_PREFIX
const Ci
var cr
observe topic
Definition: FeedWriter.js:1326
sbDeviceFirmwareAutoCheckForUpdate prototype classID
var ios
Definition: head_feeds.js:5
sbWindowsAutoPlayServiceCfg _xpcom_categories
sbDeviceFirmwareAutoCheckForUpdate prototype getInterfaces
sbDeviceFirmwareAutoCheckForUpdate prototype interfaces
classDescription implementationLanguage
Definition: FeedWriter.js:1427
observe data
Definition: FeedWriter.js:1329
const Cr
const PREF_CONTENTHANDLERS_BRANCH
_getSelectedPageStyle s i
GstMessage gpointer data sbGStreamerMessageHandler * handler
var cm
const PREF_ALLOW_DIFFERENT_HOST
var file
sbDeviceFirmwareAutoCheckForUpdate prototype observe