!import
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is the Mozilla browser.
15 *
16 * The Initial Developer of the Original Code is Mozilla.
17 * Portions created by the Initial Developer are Copyright (C) 2007
18 * the Initial Developer. All Rights Reserved.
19 *
20 * Contributor(s):
21 * Myk Melez <myk@mozilla.org>
22 * Dan Mosedale <dmose@mozilla.org>
23 * Florian Queze <florian@queze.net>
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
36 *
37 * ***** END LICENSE BLOCK ***** */
38
39 const Ci = Components.interfaces;
40 const Cc = Components.classes;
41 const Cu = Components.utils;
42 const Cr = Components.results;
43
44
45 const CLASS_MIMEINFO = "mimetype";
46 const CLASS_PROTOCOLINFO = "scheme";
47
48
49 // namespace prefix
50 const NC_NS = "http://home.netscape.com/NC-rdf#";
51
52 // the most recent default handlers that have been injected. Note that
53 // this is used to construct an RDF resource, which needs to have NC_NS
54 // prepended, since that hasn't been done yet
55 const DEFAULT_HANDLERS_VERSION = "defaultHandlersVersion";
56
57 // type list properties
58
59 const NC_MIME_TYPES = NC_NS + "MIME-types";
60 const NC_PROTOCOL_SCHEMES = NC_NS + "Protocol-Schemes";
61
62 // content type ("type") properties
63
64 // nsIHandlerInfo::type
65 const NC_VALUE = NC_NS + "value";
66 const NC_DESCRIPTION = NC_NS + "description";
67
68 // additional extensions
69 const NC_FILE_EXTENSIONS = NC_NS + "fileExtensions";
70
71 // references nsIHandlerInfo record
72 const NC_HANDLER_INFO = NC_NS + "handlerProp";
73
74 // handler info ("info") properties
75
76 // nsIHandlerInfo::preferredAction
77 const NC_SAVE_TO_DISK = NC_NS + "saveToDisk";
78 const NC_HANDLE_INTERNALLY = NC_NS + "handleInternal";
79 const NC_USE_SYSTEM_DEFAULT = NC_NS + "useSystemDefault";
80
81 // nsIHandlerInfo::alwaysAskBeforeHandling
82 const NC_ALWAYS_ASK = NC_NS + "alwaysAsk";
83
84 // references nsIHandlerApp records
85 const NC_PREFERRED_APP = NC_NS + "externalApplication";
86 const NC_POSSIBLE_APP = NC_NS + "possibleApplication";
87
88 // handler app ("handler") properties
89
90 // nsIHandlerApp::name
91 const NC_PRETTY_NAME = NC_NS + "prettyName";
92
93 // nsILocalHandlerApp::executable
94 const NC_PATH = NC_NS + "path";
95
96 // nsIWebHandlerApp::uriTemplate
97 const NC_URI_TEMPLATE = NC_NS + "uriTemplate";
98
99
100 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
101
102
HandlerService
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
103 function HandlerService() {
104 this._init();
105 }
106
107 HandlerService.prototype = {
108 //**************************************************************************//
109 // XPCOM Plumbing
110
111 classDescription: "Handler Service",
112 classID: Components.ID("{32314cc8-22f7-4f7f-a645-1a45453ba6a6}"),
113 contractID: "@mozilla.org/uriloader/handler-service;1",
114 QueryInterface: XPCOMUtils.generateQI([Ci.nsIHandlerService]),
115
116
117 //**************************************************************************//
118 // Initialization & Destruction
119
HS__init
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
120 _init: function HS__init() {
121 // Observe profile-before-change so we can switch to the datasource
122 // in the new profile when the user changes profiles.
123 this._observerSvc.addObserver(this, "profile-before-change", false);
124
125 // Observe xpcom-shutdown so we can remove these observers
126 // when the application shuts down.
127 this._observerSvc.addObserver(this, "xpcom-shutdown", false);
128
129 // Observe profile-do-change so that non-default profiles get upgraded too
130 this._observerSvc.addObserver(this, "profile-do-change", false);
131
132 // do any necessary updating of the datastore
133 this._updateDB();
134 },
135
HS__updateDB
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
136 _updateDB: function HS__updateDB() {
137 try {
138 var defaultHandlersVersion = this._datastoreDefaultHandlersVersion;
139 } catch(ex) {
140 // accessing the datastore failed, we can't update anything
141 return;
142 }
143
144 try {
145 // if we don't have the current version of the default prefs for
146 // this locale, inject any new default handers into the datastore
147 if (defaultHandlersVersion < this._prefsDefaultHandlersVersion) {
148
149 // set the new version first so that if we recurse we don't
150 // call _injectNewDefaults several times
151 this._datastoreDefaultHandlersVersion =
152 this._prefsDefaultHandlersVersion;
153 this._injectNewDefaults();
154 }
155 } catch (ex) {
156 // if injecting the defaults failed, set the version back to the
157 // previous value
158 this._datastoreDefaultHandlersVersion = defaultHandlersVersion;
159 }
160 },
161
get__currentLocale
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
162 get _currentLocale() {
163 var chromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"].
164 getService(Ci.nsIXULChromeRegistry);
165 var currentLocale = chromeRegistry.getSelectedLocale("global");
166 return currentLocale;
167 },
168
HS__destroy
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
169 _destroy: function HS__destroy() {
170 this._observerSvc.removeObserver(this, "profile-before-change");
171 this._observerSvc.removeObserver(this, "xpcom-shutdown");
172 this._observerSvc.removeObserver(this, "profile-do-change");
173
174 // XXX Should we also null references to all the services that get stored
175 // by our memoizing getters in the Convenience Getters section?
176 },
177
HS__onProfileChange
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
178 _onProfileChange: function HS__onProfileChange() {
179 // Lose our reference to the datasource so we reacquire it
180 // from the new profile the next time we need it.
181 this.__ds = null;
182 },
183
HS__isInHandlerArray
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
184 _isInHandlerArray: function HS__isInHandlerArray(aArray, aHandler) {
185 var enumerator = aArray.enumerate();
186 while (enumerator.hasMoreElements()) {
187 let handler = enumerator.getNext();
188 handler.QueryInterface(Ci.nsIHandlerApp);
189 if (handler.equals(aHandler))
190 return true;
191 }
192
193 return false;
194 },
195
196 // note that this applies to the current locale only
get__datastoreDefaultHandlersVersion
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
197 get _datastoreDefaultHandlersVersion() {
198 var version = this._getValue("urn:root", NC_NS + this._currentLocale +
199 "_" + DEFAULT_HANDLERS_VERSION);
200
201 return version ? version : -1;
202 },
203
set__datastoreDefaultHandlersVersion
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
204 set _datastoreDefaultHandlersVersion(aNewVersion) {
205 return this._setLiteral("urn:root", NC_NS + this._currentLocale + "_" +
206 DEFAULT_HANDLERS_VERSION, aNewVersion);
207 },
208
get__prefsDefaultHandlersVersion
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
209 get _prefsDefaultHandlersVersion() {
210 // get handler service pref branch
211 var prefSvc = Cc["@mozilla.org/preferences-service;1"].
212 getService(Ci.nsIPrefService);
213 var handlerSvcBranch = prefSvc.getBranch("gecko.handlerService.");
214
215 // get the version of the preferences for this locale
216 return Number(handlerSvcBranch.
217 getComplexValue("defaultHandlersVersion",
218 Ci.nsIPrefLocalizedString).data);
219 },
220
HS__injectNewDefaults
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
221 _injectNewDefaults: function HS__injectNewDefaults() {
222 // get handler service pref branch
223 var prefSvc = Cc["@mozilla.org/preferences-service;1"].
224 getService(Ci.nsIPrefService);
225
226 let schemesPrefBranch = prefSvc.getBranch("gecko.handlerService.schemes.");
227 let schemePrefList = schemesPrefBranch.getChildList("", {});
228
229 var schemes = {};
230
231 // read all the scheme prefs into a hash
232 for each (var schemePrefName in schemePrefList) {
233
234 let [scheme, handlerNumber, attribute] = schemePrefName.split(".");
235
236 try {
237 var attrData =
238 schemesPrefBranch.getComplexValue(schemePrefName,
239 Ci.nsIPrefLocalizedString).data;
240 if (!(scheme in schemes))
241 schemes[scheme] = {};
242
243 if (!(handlerNumber in schemes[scheme]))
244 schemes[scheme][handlerNumber] = {};
245
246 schemes[scheme][handlerNumber][attribute] = attrData;
247 } catch (ex) {}
248 }
249
250 let protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
251 getService(Ci.nsIExternalProtocolService);
252 for (var scheme in schemes) {
253
254 // This clause is essentially a reimplementation of
255 // nsIExternalProtocolHandlerService.getProtocolHandlerInfo().
256 // Necessary because calling that from here would make XPConnect barf
257 // when getService tried to re-enter the constructor for this
258 // service.
259 let osDefaultHandlerFound = {};
260 let protoInfo = protoSvc.getProtocolHandlerInfoFromOS(scheme,
261 osDefaultHandlerFound);
262
263 if (this.exists(protoInfo))
264 this.fillHandlerInfo(protoInfo, null);
265 else
266 protoSvc.setProtocolHandlerDefaults(protoInfo,
267 osDefaultHandlerFound.value);
268
269 // cache the possible handlers to avoid extra xpconnect traversals.
270 let possibleHandlers = protoInfo.possibleApplicationHandlers;
271
272 for each (var handlerPrefs in schemes[scheme]) {
273
274 let handlerApp = Cc["@mozilla.org/uriloader/web-handler-app;1"].
275 createInstance(Ci.nsIWebHandlerApp);
276
277 handlerApp.uriTemplate = handlerPrefs.uriTemplate;
278 handlerApp.name = handlerPrefs.name;
279
280 if (!this._isInHandlerArray(possibleHandlers, handlerApp)) {
281 possibleHandlers.appendElement(handlerApp, false);
282 }
283 }
284
285 this.store(protoInfo);
286 }
287 },
288
289 //**************************************************************************//
290 // nsIObserver
291
HS__observe
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
292 observe: function HS__observe(subject, topic, data) {
293 switch(topic) {
294 case "profile-before-change":
295 this._onProfileChange();
296 break;
297 case "xpcom-shutdown":
298 this._destroy();
299 break;
300 case "profile-do-change":
301 this._updateDB();
302 break;
303 }
304 },
305
306
307 //**************************************************************************//
308 // nsIHandlerService
309
HS_enumerate
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
310 enumerate: function HS_enumerate() {
311 var handlers = Cc["@mozilla.org/array;1"].
312 createInstance(Ci.nsIMutableArray);
313 this._appendHandlers(handlers, CLASS_MIMEINFO);
314 this._appendHandlers(handlers, CLASS_PROTOCOLINFO);
315 return handlers.enumerate();
316 },
317
HS_fillHandlerInfo
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
318 fillHandlerInfo: function HS_fillHandlerInfo(aHandlerInfo, aOverrideType) {
319 var type = aOverrideType || aHandlerInfo.type;
320 var typeID = this._getTypeID(this._getClass(aHandlerInfo), type);
321
322 // Determine whether or not information about this handler is available
323 // in the datastore by looking for its "value" property, which stores its
324 // type and should always be present.
325 if (!this._hasValue(typeID, NC_VALUE))
326 throw Cr.NS_ERROR_NOT_AVAILABLE;
327
328 // Retrieve the human-readable description of the type.
329 if (this._hasValue(typeID, NC_DESCRIPTION))
330 aHandlerInfo.description = this._getValue(typeID, NC_DESCRIPTION);
331
332 // Note: for historical reasons, we don't actually check that the type
333 // record has a "handlerProp" property referencing the info record. It's
334 // unclear whether or not we should start doing this check; perhaps some
335 // legacy datasources don't have such references.
336 var infoID = this._getInfoID(this._getClass(aHandlerInfo), type);
337
338 aHandlerInfo.preferredAction = this._retrievePreferredAction(infoID);
339
340 var preferredHandlerID =
341 this._getPreferredHandlerID(this._getClass(aHandlerInfo), type);
342
343 // Retrieve the preferred handler.
344 // Note: for historical reasons, we don't actually check that the info
345 // record has an "externalApplication" property referencing the preferred
346 // handler record. It's unclear whether or not we should start doing
347 // this check; perhaps some legacy datasources don't have such references.
348 aHandlerInfo.preferredApplicationHandler =
349 this._retrieveHandlerApp(preferredHandlerID);
350
351 // Fill the array of possible handlers with the ones in the datastore.
352 this._fillPossibleHandlers(infoID,
353 aHandlerInfo.possibleApplicationHandlers,
354 aHandlerInfo.preferredApplicationHandler);
355
356 // If we have an "always ask" flag stored in the RDF, always use its
357 // value. Otherwise, use the default value stored in the pref service.
358 var alwaysAsk;
359 if (this._hasValue(infoID, NC_ALWAYS_ASK)) {
360 alwaysAsk = (this._getValue(infoID, NC_ALWAYS_ASK) != "false");
361 } else {
362 var prefSvc = Cc["@mozilla.org/preferences-service;1"].
363 getService(Ci.nsIPrefService);
364 var prefBranch = prefSvc.getBranch("network.protocol-handler.");
365 try {
366 alwaysAsk = prefBranch.getBoolPref("warn-external." + type);
367 } catch (e) {
368 // will throw if pref didn't exist.
369 try {
370 alwaysAsk = prefBranch.getBoolPref("warn-external-default");
371 } catch (e) {
372 // Nothing to tell us what to do, so be paranoid and prompt.
373 alwaysAsk = true;
374 }
375 }
376 }
377 aHandlerInfo.alwaysAskBeforeHandling = alwaysAsk;
378
379 // If the object represents a MIME type handler, then also retrieve
380 // any file extensions.
381 if (aHandlerInfo instanceof Ci.nsIMIMEInfo)
382 for each (let fileExtension in this._retrieveFileExtensions(typeID))
383 aHandlerInfo.appendExtension(fileExtension);
384 },
385
HS_store
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
386 store: function HS_store(aHandlerInfo) {
387 // FIXME: when we switch from RDF to something with transactions (like
388 // SQLite), enclose the following changes in a transaction so they all
389 // get rolled back if any of them fail and we don't leave the datastore
390 // in an inconsistent state.
391
392 this._ensureRecordsForType(aHandlerInfo);
393 this._storePreferredAction(aHandlerInfo);
394 this._storePreferredHandler(aHandlerInfo);
395 this._storePossibleHandlers(aHandlerInfo);
396 this._storeAlwaysAsk(aHandlerInfo);
397
398 // Write the changes to the database immediately so we don't lose them
399 // if the application crashes.
400 if (this._ds instanceof Ci.nsIRDFRemoteDataSource)
401 this._ds.Flush();
402 },
403
HS_exists
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
404 exists: function HS_exists(aHandlerInfo) {
405 var found;
406
407 try {
408 var typeID = this._getTypeID(this._getClass(aHandlerInfo), aHandlerInfo.type);
409 found = this._hasLiteralAssertion(typeID, NC_VALUE, aHandlerInfo.type);
410 } catch (e) {
411 // If the RDF threw (eg, corrupt file), treat as non-existent.
412 found = false;
413 }
414
415 return found;
416 },
417
HS_remove
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
418 remove: function HS_remove(aHandlerInfo) {
419 var preferredHandlerID =
420 this._getPreferredHandlerID(this._getClass(aHandlerInfo), aHandlerInfo.type);
421 this._removeAssertions(preferredHandlerID);
422
423 var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type);
424
425 // Get a list of possible handlers. After we have removed the info record,
426 // we'll check if any other info records reference these handlers, and we'll
427 // remove the handler records that aren't referenced by other info records.
428 var possibleHandlerIDs = [];
429 var possibleHandlerTargets = this._getTargets(infoID, NC_POSSIBLE_APP);
430 while (possibleHandlerTargets.hasMoreElements()) {
431 let possibleHandlerTarget = possibleHandlerTargets.getNext();
432 // Note: possibleHandlerTarget should always be an nsIRDFResource.
433 // The conditional is just here in case of a corrupt RDF datasource.
434 if (possibleHandlerTarget instanceof Ci.nsIRDFResource)
435 possibleHandlerIDs.push(possibleHandlerTarget.ValueUTF8);
436 }
437
438 // Remove the info record.
439 this._removeAssertions(infoID);
440
441 // Now that we've removed the info record, remove any possible handlers
442 // that aren't referenced by other info records.
443 for each (let possibleHandlerID in possibleHandlerIDs)
444 if (!this._existsResourceTarget(NC_POSSIBLE_APP, possibleHandlerID))
445 this._removeAssertions(possibleHandlerID);
446
447 var typeID = this._getTypeID(this._getClass(aHandlerInfo), aHandlerInfo.type);
448 this._removeAssertions(typeID);
449
450 // Now that there's no longer a handler for this type, remove the type
451 // from the list of types for which there are known handlers.
452 var typeList = this._ensureAndGetTypeList(this._getClass(aHandlerInfo));
453 var type = this._rdf.GetResource(typeID);
454 var typeIndex = typeList.IndexOf(type);
455 if (typeIndex != -1)
456 typeList.RemoveElementAt(typeIndex, true);
457
458 // Write the changes to the database immediately so we don't lose them
459 // if the application crashes.
460 // XXX If we're removing a bunch of handlers at once, will flushing
461 // after every removal cause a significant performance hit?
462 if (this._ds instanceof Ci.nsIRDFRemoteDataSource)
463 this._ds.Flush();
464 },
465
HS_getTypeFromExtension
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
466 getTypeFromExtension: function HS_getTypeFromExtension(aFileExtension) {
467 var fileExtension = aFileExtension.toLowerCase();
468 var typeID;
469
470 if (this._existsLiteralTarget(NC_FILE_EXTENSIONS, fileExtension))
471 typeID = this._getSourceForLiteral(NC_FILE_EXTENSIONS, fileExtension);
472
473 if (typeID && this._hasValue(typeID, NC_VALUE)) {
474 let type = this._getValue(typeID, NC_VALUE);
475 if (type == "")
476 throw Cr.NS_ERROR_FAILURE;
477 return type;
478 }
479
480 return "";
481 },
482
483
484 //**************************************************************************//
485 // Retrieval Methods
486
487 /**
488 * Retrieve the preferred action for the info record with the given ID.
489 *
490 * @param aInfoID {string} the info record ID
491 *
492 * @returns {integer} the preferred action enumeration value
493 */
HS__retrievePreferredAction
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
494 _retrievePreferredAction: function HS__retrievePreferredAction(aInfoID) {
495 if (this._getValue(aInfoID, NC_SAVE_TO_DISK) == "true")
496 return Ci.nsIHandlerInfo.saveToDisk;
497
498 if (this._getValue(aInfoID, NC_USE_SYSTEM_DEFAULT) == "true")
499 return Ci.nsIHandlerInfo.useSystemDefault;
500
501 if (this._getValue(aInfoID, NC_HANDLE_INTERNALLY) == "true")
502 return Ci.nsIHandlerInfo.handleInternal;
503
504 return Ci.nsIHandlerInfo.useHelperApp;
505 },
506
507 /**
508 * Fill an array of possible handlers with the handlers for the given info ID.
509 *
510 * @param aInfoID {string} the ID of the info record
511 * @param aPossibleHandlers {nsIMutableArray} the array of possible handlers
512 * @param aPreferredHandler {nsIHandlerApp} the preferred handler, if any
513 */
HS__fillPossibleHandlers
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
514 _fillPossibleHandlers: function HS__fillPossibleHandlers(aInfoID,
515 aPossibleHandlers,
516 aPreferredHandler) {
517 // The set of possible handlers should include the preferred handler,
518 // but legacy datastores (from before we added possible handlers) won't
519 // include the preferred handler, so check if it's included as we build
520 // the list of handlers, and, if it's not included, add it to the list.
521 if (aPreferredHandler)
522 aPossibleHandlers.appendElement(aPreferredHandler, false);
523
524 var possibleHandlerTargets = this._getTargets(aInfoID, NC_POSSIBLE_APP);
525
526 while (possibleHandlerTargets.hasMoreElements()) {
527 let possibleHandlerTarget = possibleHandlerTargets.getNext();
528 if (!(possibleHandlerTarget instanceof Ci.nsIRDFResource))
529 continue;
530
531 let possibleHandlerID = possibleHandlerTarget.ValueUTF8;
532 let possibleHandler = this._retrieveHandlerApp(possibleHandlerID);
533 if (possibleHandler && (!aPreferredHandler ||
534 !possibleHandler.equals(aPreferredHandler)))
535 aPossibleHandlers.appendElement(possibleHandler, false);
536 }
537 },
538
539 /**
540 * Retrieve the handler app object with the given ID.
541 *
542 * @param aHandlerAppID {string} the ID of the handler app to retrieve
543 *
544 * @returns {nsIHandlerApp} the handler app, if any; otherwise null
545 */
HS__retrieveHandlerApp
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
546 _retrieveHandlerApp: function HS__retrieveHandlerApp(aHandlerAppID) {
547 var handlerApp;
548
549 // If it has a path, it's a local handler; otherwise, it's a web handler.
550 if (this._hasValue(aHandlerAppID, NC_PATH)) {
551 let executable =
552 this._getFileWithPath(this._getValue(aHandlerAppID, NC_PATH));
553 if (!executable)
554 return null;
555
556 handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
557 createInstance(Ci.nsILocalHandlerApp);
558 handlerApp.executable = executable;
559 }
560 else if (this._hasValue(aHandlerAppID, NC_URI_TEMPLATE)) {
561 let uriTemplate = this._getValue(aHandlerAppID, NC_URI_TEMPLATE);
562 if (!uriTemplate)
563 return null;
564
565 handlerApp = Cc["@mozilla.org/uriloader/web-handler-app;1"].
566 createInstance(Ci.nsIWebHandlerApp);
567 handlerApp.uriTemplate = uriTemplate;
568 }
569 else
570 return null;
571
572 handlerApp.name = this._getValue(aHandlerAppID, NC_PRETTY_NAME);
573
574 return handlerApp;
575 },
576
577 /*
578 * Retrieve file extensions, if any, for the MIME type with the given type ID.
579 *
580 * @param aTypeID {string} the type record ID
581 */
HS__retrieveFileExtensions
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
582 _retrieveFileExtensions: function HS__retrieveFileExtensions(aTypeID) {
583 var fileExtensions = [];
584
585 var fileExtensionTargets = this._getTargets(aTypeID, NC_FILE_EXTENSIONS);
586
587 while (fileExtensionTargets.hasMoreElements()) {
588 let fileExtensionTarget = fileExtensionTargets.getNext();
589 if (fileExtensionTarget instanceof Ci.nsIRDFLiteral &&
590 fileExtensionTarget.Value != "")
591 fileExtensions.push(fileExtensionTarget.Value);
592 }
593
594 return fileExtensions;
595 },
596
597 /**
598 * Get the file with the given path. This is not as simple as merely
599 * initializing a local file object with the path, because the path might be
600 * relative to the current process directory, in which case we have to
601 * construct a path starting from that directory.
602 *
603 * @param aPath {string} a path to a file
604 *
605 * @returns {nsILocalFile} the file, or null if the file does not exist
606 */
HS__getFileWithPath
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
607 _getFileWithPath: function HS__getFileWithPath(aPath) {
608 var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
609
610 try {
611 file.initWithPath(aPath);
612
613 if (file.exists())
614 return file;
615 }
616 catch(ex) {
617 // Note: for historical reasons, we don't actually check to see
618 // if the exception is NS_ERROR_FILE_UNRECOGNIZED_PATH, which is what
619 // nsILocalFile::initWithPath throws when a path is relative.
620
621 file = this._dirSvc.get("XCurProcD", Ci.nsIFile);
622
623 try {
624 file.append(aPath);
625 if (file.exists())
626 return file;
627 }
628 catch(ex) {}
629 }
630
631 return null;
632 },
633
634
635 //**************************************************************************//
636 // Storage Methods
637
HS__storePreferredAction
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
638 _storePreferredAction: function HS__storePreferredAction(aHandlerInfo) {
639 var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type);
640
641 switch(aHandlerInfo.preferredAction) {
642 case Ci.nsIHandlerInfo.saveToDisk:
643 this._setLiteral(infoID, NC_SAVE_TO_DISK, "true");
644 this._removeTarget(infoID, NC_HANDLE_INTERNALLY);
645 this._removeTarget(infoID, NC_USE_SYSTEM_DEFAULT);
646 break;
647
648 case Ci.nsIHandlerInfo.handleInternally:
649 this._setLiteral(infoID, NC_HANDLE_INTERNALLY, "true");
650 this._removeTarget(infoID, NC_SAVE_TO_DISK);
651 this._removeTarget(infoID, NC_USE_SYSTEM_DEFAULT);
652 break;
653
654 case Ci.nsIHandlerInfo.useSystemDefault:
655 this._setLiteral(infoID, NC_USE_SYSTEM_DEFAULT, "true");
656 this._removeTarget(infoID, NC_SAVE_TO_DISK);
657 this._removeTarget(infoID, NC_HANDLE_INTERNALLY);
658 break;
659
660 // This value is indicated in the datastore either by the absence of
661 // the three properties or by setting them all "false". Of these two
662 // options, the former seems preferable, because it reduces the size
663 // of the RDF file and thus the amount of stuff we have to parse.
664 case Ci.nsIHandlerInfo.useHelperApp:
665 default:
666 this._removeTarget(infoID, NC_SAVE_TO_DISK);
667 this._removeTarget(infoID, NC_HANDLE_INTERNALLY);
668 this._removeTarget(infoID, NC_USE_SYSTEM_DEFAULT);
669 break;
670 }
671 },
672
HS__storePreferredHandler
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
673 _storePreferredHandler: function HS__storePreferredHandler(aHandlerInfo) {
674 var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type);
675 var handlerID =
676 this._getPreferredHandlerID(this._getClass(aHandlerInfo), aHandlerInfo.type);
677
678 var handler = aHandlerInfo.preferredApplicationHandler;
679
680 if (handler) {
681 this._storeHandlerApp(handlerID, handler);
682
683 // Make this app be the preferred app for the handler info.
684 //
685 // Note: nsExternalHelperAppService::FillContentHandlerProperties ignores
686 // this setting and instead identifies the preferred app as the resource
687 // whose URI follows the pattern urn:<class>:externalApplication:<type>.
688 // But the old downloadactions.js code used to set this property, so just
689 // in case there is still some code somewhere that relies on its presence,
690 // we set it here.
691 this._setResource(infoID, NC_PREFERRED_APP, handlerID);
692 }
693 else {
694 // There isn't a preferred handler. Remove the existing record for it,
695 // if any.
696 this._removeTarget(infoID, NC_PREFERRED_APP);
697 this._removeAssertions(handlerID);
698 }
699 },
700
701 /**
702 * Store the list of possible handler apps for the content type represented
703 * by the given handler info object.
704 *
705 * @param aHandlerInfo {nsIHandlerInfo} the handler info object
706 */
HS__storePossibleHandlers
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
707 _storePossibleHandlers: function HS__storePossibleHandlers(aHandlerInfo) {
708 var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type);
709
710 // First, retrieve the set of handler apps currently stored for the type,
711 // keeping track of their IDs in a hash that we'll use to determine which
712 // ones are no longer valid and should be removed.
713 var currentHandlerApps = {};
714 var currentHandlerTargets = this._getTargets(infoID, NC_POSSIBLE_APP);
715 while (currentHandlerTargets.hasMoreElements()) {
716 let handlerApp = currentHandlerTargets.getNext();
717 if (handlerApp instanceof Ci.nsIRDFResource) {
718 let handlerAppID = handlerApp.ValueUTF8;
719 currentHandlerApps[handlerAppID] = true;
720 }
721 }
722
723 // Next, store any new handler apps.
724 var newHandlerApps =
725 aHandlerInfo.possibleApplicationHandlers.enumerate();
726 while (newHandlerApps.hasMoreElements()) {
727 let handlerApp =
728 newHandlerApps.getNext().QueryInterface(Ci.nsIHandlerApp);
729 let handlerAppID = this._getPossibleHandlerAppID(handlerApp);
730 if (!this._hasResourceAssertion(infoID, NC_POSSIBLE_APP, handlerAppID)) {
731 this._storeHandlerApp(handlerAppID, handlerApp);
732 this._addResourceAssertion(infoID, NC_POSSIBLE_APP, handlerAppID);
733 }
734 delete currentHandlerApps[handlerAppID];
735 }
736
737 // Finally, remove any old handler apps that aren't being used anymore,
738 // and if those handler apps aren't being used by any other type either,
739 // then completely remove their record from the datastore so we don't
740 // leave it clogged up with information about handler apps we don't care
741 // about anymore.
742 for (let handlerAppID in currentHandlerApps) {
743 this._removeResourceAssertion(infoID, NC_POSSIBLE_APP, handlerAppID);
744 if (!this._existsResourceTarget(NC_POSSIBLE_APP, handlerAppID))
745 this._removeAssertions(handlerAppID);
746 }
747 },
748
749 /**
750 * Store the given handler app.
751 *
752 * Note: the reason this method takes the ID of the handler app in a param
753 * is that the ID is different than it usually is when the handler app
754 * in question is a preferred handler app, so this method can't just derive
755 * the ID of the handler app by calling _getPossibleHandlerAppID, its callers
756 * have to do that for it.
757 *
758 * @param aHandlerAppID {string} the ID of the handler app to store
759 * @param aHandlerApp {nsIHandlerApp} the handler app to store
760 */
HS__storeHandlerApp
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
761 _storeHandlerApp: function HS__storeHandlerApp(aHandlerAppID, aHandlerApp) {
762 aHandlerApp.QueryInterface(Ci.nsIHandlerApp);
763 this._setLiteral(aHandlerAppID, NC_PRETTY_NAME, aHandlerApp.name);
764
765 // In the case of the preferred handler, the handler ID could have been
766 // used to refer to a different kind of handler in the past (i.e. either
767 // a local hander or a web handler), so if the new handler is a local
768 // handler, then we remove any web handler properties and vice versa.
769 // This is unnecessary but harmless for possible handlers.
770
771 if (aHandlerApp instanceof Ci.nsILocalHandlerApp) {
772 this._setLiteral(aHandlerAppID, NC_PATH, aHandlerApp.executable.path);
773 this._removeTarget(aHandlerAppID, NC_URI_TEMPLATE);
774 }
775 else {
776 aHandlerApp.QueryInterface(Ci.nsIWebHandlerApp);
777 this._setLiteral(aHandlerAppID, NC_URI_TEMPLATE, aHandlerApp.uriTemplate);
778 this._removeTarget(aHandlerAppID, NC_PATH);
779 }
780 },
781
HS__storeAlwaysAsk
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
782 _storeAlwaysAsk: function HS__storeAlwaysAsk(aHandlerInfo) {
783 var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type);
784 this._setLiteral(infoID,
785 NC_ALWAYS_ASK,
786 aHandlerInfo.alwaysAskBeforeHandling ? "true" : "false");
787 },
788
789
790 //**************************************************************************//
791 // Convenience Getters
792
793 // Observer Service
794 __observerSvc: null,
get__observerSvc
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
795 get _observerSvc() {
796 if (!this.__observerSvc)
797 this.__observerSvc =
798 Cc["@mozilla.org/observer-service;1"].
799 getService(Ci.nsIObserverService);
800 return this.__observerSvc;
801 },
802
803 // Directory Service
804 __dirSvc: null,
get__dirSvc
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
805 get _dirSvc() {
806 if (!this.__dirSvc)
807 this.__dirSvc =
808 Cc["@mozilla.org/file/directory_service;1"].
809 getService(Ci.nsIProperties);
810 return this.__dirSvc;
811 },
812
813 // MIME Service
814 __mimeSvc: null,
get__mimeSvc
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
815 get _mimeSvc() {
816 if (!this.__mimeSvc)
817 this.__mimeSvc =
818 Cc["@mozilla.org/mime;1"].
819 getService(Ci.nsIMIMEService);
820 return this.__mimeSvc;
821 },
822
823 // Protocol Service
824 __protocolSvc: null,
get__protocolSvc
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
825 get _protocolSvc() {
826 if (!this.__protocolSvc)
827 this.__protocolSvc =
828 Cc["@mozilla.org/uriloader/external-protocol-service;1"].
829 getService(Ci.nsIExternalProtocolService);
830 return this.__protocolSvc;
831 },
832
833 // RDF Service
834 __rdf: null,
get__rdf
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
835 get _rdf() {
836 if (!this.__rdf)
837 this.__rdf = Cc["@mozilla.org/rdf/rdf-service;1"].
838 getService(Ci.nsIRDFService);
839 return this.__rdf;
840 },
841
842 // RDF Container Utils
843 __containerUtils: null,
get__containerUtils
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
844 get _containerUtils() {
845 if (!this.__containerUtils)
846 this.__containerUtils = Cc["@mozilla.org/rdf/container-utils;1"].
847 getService(Ci.nsIRDFContainerUtils);
848 return this.__containerUtils;
849 },
850
851 // RDF datasource containing content handling config (i.e. mimeTypes.rdf)
852 __ds: null,
get__ds
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
853 get _ds() {
854 if (!this.__ds) {
855 var file = this._dirSvc.get("UMimTyp", Ci.nsIFile);
856 // FIXME: make this a memoizing getter if we use it anywhere else.
857 var ioService = Cc["@mozilla.org/network/io-service;1"].
858 getService(Ci.nsIIOService);
859 var fileHandler = ioService.getProtocolHandler("file").
860 QueryInterface(Ci.nsIFileProtocolHandler);
861 this.__ds =
862 this._rdf.GetDataSourceBlocking(fileHandler.getURLSpecFromFile(file));
863 }
864
865 return this.__ds;
866 },
867
868
869 //**************************************************************************//
870 // Datastore Utils
871
872 /**
873 * Get the string identifying whether this is a MIME or a protocol handler.
874 * This string is used in the URI IDs of various RDF properties.
875 *
876 * @param aHandlerInfo {nsIHandlerInfo} the handler for which to get the class
877 *
878 * @returns {string} the class
879 */
HS__getClass
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
880 _getClass: function HS__getClass(aHandlerInfo) {
881 if (aHandlerInfo instanceof Ci.nsIMIMEInfo)
882 return CLASS_MIMEINFO;
883 else
884 return CLASS_PROTOCOLINFO;
885 },
886
887 /**
888 * Return the unique identifier for a content type record, which stores
889 * the value field plus a reference to the content type's handler info record.
890 *
891 * |urn:<class>:<type>|
892 *
893 * XXX: should this be a property of nsIHandlerInfo?
894 *
895 * @param aClass {string} the class (CLASS_MIMEINFO or CLASS_PROTOCOLINFO)
896 * @param aType {string} the type (a MIME type or protocol scheme)
897 *
898 * @returns {string} the ID
899 */
HS__getTypeID
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
900 _getTypeID: function HS__getTypeID(aClass, aType) {
901 return "urn:" + aClass + ":" + aType;
902 },
903
904 /**
905 * Return the unique identifier for a handler info record, which stores
906 * the preferredAction and alwaysAsk fields plus a reference to the preferred
907 * handler app. Roughly equivalent to the nsIHandlerInfo interface.
908 *
909 * |urn:<class>:handler:<type>|
910 *
911 * FIXME: the type info record should be merged into the type record,
912 * since there's a one to one relationship between them, and this record
913 * merely stores additional attributes of a content type.
914 *
915 * @param aClass {string} the class (CLASS_MIMEINFO or CLASS_PROTOCOLINFO)
916 * @param aType {string} the type (a MIME type or protocol scheme)
917 *
918 * @returns {string} the ID
919 */
HS__getInfoID
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
920 _getInfoID: function HS__getInfoID(aClass, aType) {
921 return "urn:" + aClass + ":handler:" + aType;
922 },
923
924 /**
925 * Return the unique identifier for a preferred handler record, which stores
926 * information about the preferred handler for a given content type, including
927 * its human-readable name and the path to its executable (for a local app)
928 * or its URI template (for a web app).
929 *
930 * |urn:<class>:externalApplication:<type>|
931 *
932 * XXX: should this be a property of nsIHandlerApp?
933 *
934 * FIXME: this should be an arbitrary ID, and we should retrieve it from
935 * the datastore for a given content type via the NC:ExternalApplication
936 * property rather than looking for a specific ID, so a handler doesn't
937 * have to change IDs when it goes from being a possible handler to being
938 * the preferred one (once we support possible handlers).
939 *
940 * @param aClass {string} the class (CLASS_MIMEINFO or CLASS_PROTOCOLINFO)
941 * @param aType {string} the type (a MIME type or protocol scheme)
942 *
943 * @returns {string} the ID
944 */
HS__getPreferredHandlerID
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
945 _getPreferredHandlerID: function HS__getPreferredHandlerID(aClass, aType) {
946 return "urn:" + aClass + ":externalApplication:" + aType;
947 },
948
949 /**
950 * Return the unique identifier for a handler app record, which stores
951 * information about a possible handler for one or more content types,
952 * including its human-readable name and the path to its executable (for a
953 * local app) or its URI template (for a web app).
954 *
955 * Note: handler app IDs for preferred handlers are different. For those,
956 * see the _getPreferredHandlerID method.
957 *
958 * @param aHandlerApp {nsIHandlerApp} the handler app object
959 */
HS__getPossibleHandlerAppID
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
960 _getPossibleHandlerAppID: function HS__getPossibleHandlerAppID(aHandlerApp) {
961 var handlerAppID = "urn:handler:";
962
963 if (aHandlerApp instanceof Ci.nsILocalHandlerApp)
964 handlerAppID += "local:" + aHandlerApp.executable.path;
965 else {
966 aHandlerApp.QueryInterface(Ci.nsIWebHandlerApp);
967 handlerAppID += "web:" + aHandlerApp.uriTemplate;
968 }
969
970 return handlerAppID;
971 },
972
973 /**
974 * Get the list of types for the given class, creating the list if it doesn't
975 * already exist. The class can be either CLASS_MIMEINFO or CLASS_PROTOCOLINFO
976 * (i.e. the result of a call to _getClass).
977 *
978 * |urn:<class>s|
979 * |urn:<class>s:root|
980 *
981 * @param aClass {string} the class for which to retrieve a list of types
982 *
983 * @returns {nsIRDFContainer} the list of types
984 */
HS__ensureAndGetTypeList
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
985 _ensureAndGetTypeList: function HS__ensureAndGetTypeList(aClass) {
986 var source = this._rdf.GetResource("urn:" + aClass + "s");
987 var property =
988 this._rdf.GetResource(aClass == CLASS_MIMEINFO ? NC_MIME_TYPES
989 : NC_PROTOCOL_SCHEMES);
990 var target = this._rdf.GetResource("urn:" + aClass + "s:root");
991
992 // Make sure we have an arc from the source to the target.
993 if (!this._ds.HasAssertion(source, property, target, true))
994 this._ds.Assert(source, property, target, true);
995
996 // Make sure the target is a container.
997 if (!this._containerUtils.IsContainer(this._ds, target))
998 this._containerUtils.MakeSeq(this._ds, target);
999
1000 // Get the type list as an RDF container.
1001 var typeList = Cc["@mozilla.org/rdf/container;1"].
1002 createInstance(Ci.nsIRDFContainer);
1003 typeList.Init(this._ds, target);
1004
1005 return typeList;
1006 },
1007
1008 /**
1009 * Make sure there are records in the datasource for the given content type
1010 * by creating them if they don't already exist. We have to do this before
1011 * storing any specific data, because we can't assume the presence
1012 * of the records (the nsIHandlerInfo object might have been created
1013 * from the OS), and the records have to all be there in order for the helper
1014 * app service to properly construct an nsIHandlerInfo object for the type.
1015 *
1016 * Based on old downloadactions.js::_ensureMIMERegistryEntry.
1017 *
1018 * @param aHandlerInfo {nsIHandlerInfo} the type to make sure has a record
1019 */
HS__ensureRecordsForType
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1020 _ensureRecordsForType: function HS__ensureRecordsForType(aHandlerInfo) {
1021 // Get the list of types.
1022 var typeList = this._ensureAndGetTypeList(this._getClass(aHandlerInfo));
1023
1024 // If there's already a record in the datastore for this type, then we
1025 // don't need to do anything more.
1026 var typeID = this._getTypeID(this._getClass(aHandlerInfo), aHandlerInfo.type);
1027 var type = this._rdf.GetResource(typeID);
1028 if (typeList.IndexOf(type) != -1)
1029 return;
1030
1031 // Create a basic type record for this type.
1032 typeList.AppendElement(type);
1033 this._setLiteral(typeID, NC_VALUE, aHandlerInfo.type);
1034
1035 // Create a basic info record for this type.
1036 var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type);
1037 this._setLiteral(infoID, NC_ALWAYS_ASK, "false");
1038 this._setResource(typeID, NC_HANDLER_INFO, infoID);
1039 // XXX Shouldn't we set preferredAction to useSystemDefault?
1040 // That's what it is if there's no record in the datastore; why should it
1041 // change to useHelperApp just because we add a record to the datastore?
1042
1043 // Create a basic preferred handler record for this type.
1044 // XXX Not sure this is necessary, since preferred handlers are optional,
1045 // and nsExternalHelperAppService::FillHandlerInfoForTypeFromDS doesn't seem
1046 // to require the record , but downloadactions.js::_ensureMIMERegistryEntry
1047 // used to create it, so we'll do the same.
1048 var preferredHandlerID =
1049 this._getPreferredHandlerID(this._getClass(aHandlerInfo), aHandlerInfo.type);
1050 this._setLiteral(preferredHandlerID, NC_PATH, "");
1051 this._setResource(infoID, NC_PREFERRED_APP, preferredHandlerID);
1052 },
1053
1054 /**
1055 * Append known handlers of the given class to the given array. The class
1056 * can be either CLASS_MIMEINFO or CLASS_PROTOCOLINFO.
1057 *
1058 * @param aHandlers {array} the array of handlers to append to
1059 * @param aClass {string} the class for which to append handlers
1060 */
HS__appendHandlers
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1061 _appendHandlers: function HS__appendHandlers(aHandlers, aClass) {
1062 var typeList = this._ensureAndGetTypeList(aClass);
1063 var enumerator = typeList.GetElements();
1064
1065 while (enumerator.hasMoreElements()) {
1066 var element = enumerator.getNext();
1067
1068 // This should never happen. If it does, that means our datasource
1069 // is corrupted with type list entries that point to literal values
1070 // instead of resources. If it does happen, let's just do our best
1071 // to recover by ignoring this entry and moving on to the next one.
1072 if (!(element instanceof Ci.nsIRDFResource))
1073 continue;
1074
1075 // Get the value of the element's NC:value property, which contains
1076 // the MIME type or scheme for which we're retrieving a handler info.
1077 var type = this._getValue(element.ValueUTF8, NC_VALUE);
1078 if (!type)
1079 continue;
1080
1081 var handler;
1082 if (typeList.Resource.ValueUTF8 == "urn:mimetypes:root")
1083 handler = this._mimeSvc.getFromTypeAndExtension(type, null);
1084 else
1085 handler = this._protocolSvc.getProtocolHandlerInfo(type);
1086
1087 aHandlers.appendElement(handler, false);
1088 }
1089 },
1090
1091 /**
1092 * Whether or not a property of an RDF source has a value.
1093 *
1094 * @param sourceURI {string} the URI of the source
1095 * @param propertyURI {string} the URI of the property
1096 * @returns {boolean} whether or not the property has a value
1097 */
HS__hasValue
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1098 _hasValue: function HS__hasValue(sourceURI, propertyURI) {
1099 var source = this._rdf.GetResource(sourceURI);
1100 var property = this._rdf.GetResource(propertyURI);
1101 return this._ds.hasArcOut(source, property);
1102 },
1103
1104 /**
1105 * Get the value of a property of an RDF source.
1106 *
1107 * @param sourceURI {string} the URI of the source
1108 * @param propertyURI {string} the URI of the property
1109 * @returns {string} the value of the property
1110 */
HS__getValue
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1111 _getValue: function HS__getValue(sourceURI, propertyURI) {
1112 var source = this._rdf.GetResource(sourceURI);
1113 var property = this._rdf.GetResource(propertyURI);
1114
1115 var target = this._ds.GetTarget(source, property, true);
1116
1117 if (!target)
1118 return null;
1119
1120 if (target instanceof Ci.nsIRDFResource)
1121 return target.ValueUTF8;
1122
1123 if (target instanceof Ci.nsIRDFLiteral)
1124 return target.Value;
1125
1126 return null;
1127 },
1128
1129 /**
1130 * Get all targets for the property of an RDF source.
1131 *
1132 * @param sourceURI {string} the URI of the source
1133 * @param propertyURI {string} the URI of the property
1134 *
1135 * @returns {nsISimpleEnumerator} an enumerator of targets
1136 */
HS__getTargets
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1137 _getTargets: function HS__getTargets(sourceURI, propertyURI) {
1138 var source = this._rdf.GetResource(sourceURI);
1139 var property = this._rdf.GetResource(propertyURI);
1140
1141 return this._ds.GetTargets(source, property, true);
1142 },
1143
1144 /**
1145 * Set a property of an RDF source to a literal value.
1146 *
1147 * @param sourceURI {string} the URI of the source
1148 * @param propertyURI {string} the URI of the property
1149 * @param value {string} the literal value
1150 */
HS__setLiteral
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1151 _setLiteral: function HS__setLiteral(sourceURI, propertyURI, value) {
1152 var source = this._rdf.GetResource(sourceURI);
1153 var property = this._rdf.GetResource(propertyURI);
1154 var target = this._rdf.GetLiteral(value);
1155
1156 this._setTarget(source, property, target);
1157 },
1158
1159 /**
1160 * Set a property of an RDF source to a resource target.
1161 *
1162 * @param sourceURI {string} the URI of the source
1163 * @param propertyURI {string} the URI of the property
1164 * @param targetURI {string} the URI of the target
1165 */
HS__setResource
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1166 _setResource: function HS__setResource(sourceURI, propertyURI, targetURI) {
1167 var source = this._rdf.GetResource(sourceURI);
1168 var property = this._rdf.GetResource(propertyURI);
1169 var target = this._rdf.GetResource(targetURI);
1170
1171 this._setTarget(source, property, target);
1172 },
1173
1174 /**
1175 * Assert an arc into the RDF datasource if there is no arc with the given
1176 * source and property; otherwise, if there is already an existing arc,
1177 * change it to point to the given target. _setLiteral and _setResource
1178 * call this after converting their string arguments into resources
1179 * and literals, and most callers should call one of those two methods
1180 * instead of this one.
1181 *
1182 * @param source {nsIRDFResource} the source
1183 * @param property {nsIRDFResource} the property
1184 * @param target {nsIRDFNode} the target
1185 */
HS__setTarget
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1186 _setTarget: function HS__setTarget(source, property, target) {
1187 if (this._ds.hasArcOut(source, property)) {
1188 var oldTarget = this._ds.GetTarget(source, property, true);
1189 this._ds.Change(source, property, oldTarget, target);
1190 }
1191 else
1192 this._ds.Assert(source, property, target, true);
1193 },
1194
1195 /**
1196 * Assert that a property of an RDF source has a resource target.
1197 *
1198 * The difference between this method and _setResource is that this one adds
1199 * an assertion even if one already exists, which allows its callers to make
1200 * sets of assertions (i.e. to set a property to multiple targets).
1201 *
1202 * @param sourceURI {string} the URI of the source
1203 * @param propertyURI {string} the URI of the property
1204 * @param targetURI {string} the URI of the target
1205 */
HS__addResourceAssertion
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1206 _addResourceAssertion: function HS__addResourceAssertion(sourceURI,
1207 propertyURI,
1208 targetURI) {
1209 var source = this._rdf.GetResource(sourceURI);
1210 var property = this._rdf.GetResource(propertyURI);
1211 var target = this._rdf.GetResource(targetURI);
1212
1213 this._ds.Assert(source, property, target, true);
1214 },
1215
1216 /**
1217 * Remove an assertion with a resource target.
1218 *
1219 * @param sourceURI {string} the URI of the source
1220 * @param propertyURI {string} the URI of the property
1221 * @param targetURI {string} the URI of the target
1222 */
HS__removeResourceAssertion
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1223 _removeResourceAssertion: function HS__removeResourceAssertion(sourceURI,
1224 propertyURI,
1225 targetURI) {
1226 var source = this._rdf.GetResource(sourceURI);
1227 var property = this._rdf.GetResource(propertyURI);
1228 var target = this._rdf.GetResource(targetURI);
1229
1230 this._ds.Unassert(source, property, target);
1231 },
1232
1233 /**
1234 * Whether or not a property of an RDF source has a given resource target.
1235 *
1236 * @param sourceURI {string} the URI of the source
1237 * @param propertyURI {string} the URI of the property
1238 * @param targetURI {string} the URI of the target
1239 *
1240 * @returns {boolean} whether or not there is such an assertion
1241 */
HS__hasResourceAssertion
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1242 _hasResourceAssertion: function HS__hasResourceAssertion(sourceURI,
1243 propertyURI,
1244 targetURI) {
1245 var source = this._rdf.GetResource(sourceURI);
1246 var property = this._rdf.GetResource(propertyURI);
1247 var target = this._rdf.GetResource(targetURI);
1248
1249 return this._ds.HasAssertion(source, property, target, true);
1250 },
1251
1252 /**
1253 * Whether or not a property of an RDF source has a given literal value.
1254 *
1255 * @param sourceURI {string} the URI of the source
1256 * @param propertyURI {string} the URI of the property
1257 * @param value {string} the literal value
1258 *
1259 * @returns {boolean} whether or not there is such an assertion
1260 */
HS__hasLiteralAssertion
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1261 _hasLiteralAssertion: function HS__hasLiteralAssertion(sourceURI,
1262 propertyURI,
1263 value) {
1264 var source = this._rdf.GetResource(sourceURI);
1265 var property = this._rdf.GetResource(propertyURI);
1266 var target = this._rdf.GetLiteral(value);
1267
1268 return this._ds.HasAssertion(source, property, target, true);
1269 },
1270
1271 /**
1272 * Whether or not there is an RDF source that has the given property set to
1273 * the given literal value.
1274 *
1275 * @param propertyURI {string} the URI of the property
1276 * @param value {string} the literal value
1277 *
1278 * @returns {boolean} whether or not there is a source
1279 */
HS__existsLiteralTarget
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1280 _existsLiteralTarget: function HS__existsLiteralTarget(propertyURI, value) {
1281 var property = this._rdf.GetResource(propertyURI);
1282 var target = this._rdf.GetLiteral(value);
1283
1284 return this._ds.hasArcIn(target, property);
1285 },
1286
1287 /**
1288 * Get the source for a property set to a given literal value.
1289 *
1290 * @param propertyURI {string} the URI of the property
1291 * @param value {string} the literal value
1292 */
HS__getSourceForLiteral
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1293 _getSourceForLiteral: function HS__getSourceForLiteral(propertyURI, value) {
1294 var property = this._rdf.GetResource(propertyURI);
1295 var target = this._rdf.GetLiteral(value);
1296
1297 var source = this._ds.GetSource(property, target, true);
1298 if (source)
1299 return source.ValueUTF8;
1300
1301 return null;
1302 },
1303
1304 /**
1305 * Whether or not there is an RDF source that has the given property set to
1306 * the given resource target.
1307 *
1308 * @param propertyURI {string} the URI of the property
1309 * @param targetURI {string} the URI of the target
1310 *
1311 * @returns {boolean} whether or not there is a source
1312 */
HS__existsResourceTarget
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1313 _existsResourceTarget: function HS__existsResourceTarget(propertyURI,
1314 targetURI) {
1315 var property = this._rdf.GetResource(propertyURI);
1316 var target = this._rdf.GetResource(targetURI);
1317
1318 return this._ds.hasArcIn(target, property);
1319 },
1320
1321 /**
1322 * Remove a property of an RDF source.
1323 *
1324 * @param sourceURI {string} the URI of the source
1325 * @param propertyURI {string} the URI of the property
1326 */
HS__removeTarget
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1327 _removeTarget: function HS__removeTarget(sourceURI, propertyURI) {
1328 var source = this._rdf.GetResource(sourceURI);
1329 var property = this._rdf.GetResource(propertyURI);
1330
1331 if (this._ds.hasArcOut(source, property)) {
1332 var target = this._ds.GetTarget(source, property, true);
1333 this._ds.Unassert(source, property, target);
1334 }
1335 },
1336
1337 /**
1338 * Remove all assertions about a given RDF source.
1339 *
1340 * Note: not recursive. If some assertions point to other resources,
1341 * and you want to remove assertions about those resources too, you need
1342 * to do so manually.
1343 *
1344 * @param sourceURI {string} the URI of the source
1345 */
HS__removeAssertions
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1346 _removeAssertions: function HS__removeAssertions(sourceURI) {
1347 var source = this._rdf.GetResource(sourceURI);
1348 var properties = this._ds.ArcLabelsOut(source);
1349
1350 while (properties.hasMoreElements()) {
1351 let property = properties.getNext();
1352 let targets = this._ds.GetTargets(source, property, true);
1353 while (targets.hasMoreElements()) {
1354 let target = targets.getNext();
1355 this._ds.Unassert(source, property, target);
1356 }
1357 }
1358 }
1359
1360 };
1361
1362
1363 //****************************************************************************//
1364 // More XPCOM Plumbing
1365
NSGetModule
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1366 function NSGetModule(compMgr, fileSpec) {
1367 return XPCOMUtils.generateModule([HandlerService]);
1368 }