sbAddonMetadata.js
Go to the documentation of this file.
1 
34 const CONTRACTID = "@mozilla.org/rdf/datasource;1?name=addon-metadata";
35 const CLASSNAME = "Songbird Addon Metadata Datasource";
36 const CID = Components.ID("{a1edd551-0f29-4ce9-aebc-92fbee77f37e}");
37 const IID = Components.interfaces.nsIRDFDataSource;
38 
39 const FILE_INSTALL_MANIFEST = "install.rdf";
40 const FILE_EXTENSIONS = "extensions.rdf";
41 const FILE_ADDONMETADATA = "addon-metadata.rdf";
42 
43 const PREF_LASTMODIFIED = "songbird.addonmetadata.lastModifiedTime";
44 
45 const KEY_PROFILEDIR = "ProfD";
46 
47 const RDFURI_INSTALL_MANIFEST_ROOT = "urn:mozilla:install-manifest";
48 const RDFURI_ADDON_ROOT = "urn:songbird:addon:root"
49 const PREFIX_ADDON_URI = "urn:songbird:addon:";
50 const PREFIX_NS_EM = "http://www.mozilla.org/2004/em-rdf#";
51 const PREFIX_NS_SONGBIRD = "http://www.songbirdnest.com/2007/addon-metadata-rdf#";
52 const PREFIX_ITEM_URI = "urn:mozilla:item:";
53 
54 function SONGBIRD_NS(property) {
55  return PREFIX_NS_SONGBIRD + property;
56 }
57 
58 function EM_NS(property) {
59  return PREFIX_NS_EM + property;
60 }
61 
62 function ADDON_NS(id) {
63  return PREFIX_ADDON_URI + id;
64 }
65 
66 function ITEM_NS(id) {
67  return PREFIX_ITEM_URI + id;
68 }
69 
70 
76 function AddonMetadata() {
77  //debug("\nAddonMetadata: constructed\n");
78 
79  this._RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"]
80  .getService(Components.interfaces.nsIRDFService);
81 
82  try {
83 
84  // If possible, load the cached datasource from disk.
85  // Otherwise rebuild it by reading the metadata from all addons
86  if (!this._loadDatasource() || this._isRebuildRequired()) {
87  //debug("AddonMetadata: rebuilding addon metadata datasource\n");
88  this._purgeDatasource();
89  this._buildDatasource();
90  }
91 
92  } catch (e) {
93  dump("AddonMetadata: Constructor Error: " + e.toString());
94  }
95 
96  var os = Components.classes["@mozilla.org/observer-service;1"]
97  .getService(Components.interfaces.nsIObserverService);
98  os.addObserver(this, "xpcom-shutdown", false);
99 };
100 
101 AddonMetadata.prototype = {
102 
104 
105  _RDF: null,
106  _datasource: null,
107 
108 
114  _isRebuildRequired: function _isRebuildRequired() {
115  var emDataFile = this._getProfileFile(FILE_EXTENSIONS);
116 
117  if (!emDataFile.exists()) {
118  //debug("AddonMetadata._isRebuildRequired: " + FILE_EXTENSIONS + " not found\n");
119  return true;
120  }
121 
122  var newLastModified = emDataFile.lastModifiedTime.toString();
123 
124  // When was the last time we noticed that extensions.rdf had been modified
125  var prefs = Components.classes["@mozilla.org/preferences-service;1"]
126  .getService(Components.interfaces.nsIPrefBranch);
127  var lastModified = 0;
128  try {
129  lastModified = prefs.getCharPref(PREF_LASTMODIFIED);
130  } catch (e) {}
131 
132  // If the extensions.rdf hasn't changed, then we don't need to rebuild
133  //debug("AddonMetadata._isRebuildRequired: " + lastModified + " == " + newLastModified + "\n");
134  if (lastModified == newLastModified) {
135  return false;
136  }
137 
138  // Store the new last modified time
139  prefs.setCharPref(PREF_LASTMODIFIED, newLastModified);
140 
141  //debug("AddonMetadata._isRebuildRequired: true\n");
142 
143  // Extensions.rdf has changed, so we will need to rebuild the addons datasource.
144  return true;
145  },
146 
147 
148 
153  _loadDatasource: function _loadDatasource() {
154  //debug("\nAddonMetadata: _loadDatasource \n");
155 
156  var file = this._getProfileFile(FILE_ADDONMETADATA);
157 
158  try {
159  this._datasource = this._getDatasource(file);
160  } catch (e) {
161  // Load did not go ok. Will need to rebuild
162  return false;
163  }
164 
165  if (!file.exists()) {
166  return false;
167  }
168 
169  return true;
170  },
171 
172 
173 
177  _purgeDatasource: function _purgeDatasource() {
178  //debug("\nAddonMetadata: _purgeDatasource \n");
179 
180  var file = this._getProfileFile(FILE_ADDONMETADATA);
181 
182  // Make sure the RDF service isn't caching our ds
183  this._RDF.UnregisterDataSource(this._datasource);
184 
185  // Kill the file
186  try {
187  if (file.exists()) {
188  file.remove(false);
189  }
190  } catch (e) {
191  debug("\nAddonMetadata: _purgeDatasource: Could not remove "
192  + "addon-metadata.rdf. Bad things may happen.\n");
193  }
194 
195  // Reload the datasource. Since the file no longer exists
196  // this will result in a new empty DS.
197  this._loadDatasource();
198  },
199 
200 
201 
202 
207  _getProfileFile: function _getProfileFile(filename) {
208  // get profile directory
209  var file = Components.classes["@mozilla.org/file/directory_service;1"]
210  .getService(Components.interfaces.nsIProperties)
211  .get("ProfD", Components.interfaces.nsIFile);
212  var localFile = file.QueryInterface(Components.interfaces.nsILocalFile);
213  localFile.appendRelativePath(filename)
214  return file;
215  },
216 
217 
218 
223  _buildDatasource: function _buildDatasource() {
224  //debug("\nAddonMetadata: _buildDatasource \n");
225 
226  // Make a container to list all installed extensions
227  var itemRoot = this._RDF.GetResource(RDFURI_ADDON_ROOT);
228  var cu = Components.classes["@mozilla.org/rdf/container-utils;1"]
229  .getService(Components.interfaces.nsIRDFContainerUtils);
230  var container = cu.MakeSeq(this._datasource, itemRoot);
231 
232  var extManager = Components.classes["@mozilla.org/extensions/manager;1"]
233  .getService(Components.interfaces.nsIExtensionManager);
234 
235  // Read the install.rdf for every addon
236  var addons = extManager.getItemList(Components.interfaces.nsIUpdateItem.TYPE_ADDON, {});
237  for (var i = 0; i < addons.length; i++)
238  {
239  var id = addons[i].id;
240 
241  // If the extension is disabled, do not include it in our datasource
242  if (this._isExtensionDisabled(id)) {
243  //debug("\nAddonMetadata: id {" + id + "} is disabled.\n");
244  continue;
245  }
246 
247  //debug("\nAddonMetadata: loading install.rdf for id {" + id + "}\n");
248 
249  var location = extManager.getInstallLocation(id);
250  var installManifestFile = location.getItemFile(id, FILE_INSTALL_MANIFEST);
251 
252  if (!installManifestFile.exists()) {
253  this._reportErrors(["install.rdf for id " + id + " was not found " +
254  "at location " + installManifestFile.path]);
255  }
256 
257  var manifestDS = this._getDatasource(installManifestFile);
258  var itemNode = this._RDF.GetResource(ADDON_NS(id));
259  // Copy the install.rdf metadata into the master datasource
260  this._copyManifest(itemNode, manifestDS);
261 
262  // Add the new install.rdf root to the list of extensions
263  container.AppendElement(itemNode);
264  }
265 
266  // Save changes
267  this._datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource)
268  .Flush();
269  //debug("\nAddonMetadata: _buildDatasource complete \n");
270  },
271 
272 
273 
277  _isExtensionDisabled: function _isExtensionDisabled(id) {
278  var item = this._RDF.GetResource(ITEM_NS(id));
279  var extManager = Components.classes["@mozilla.org/extensions/manager;1"]
280  .getService(Components.interfaces.nsIExtensionManager);
281  var userDisabled = this._RDF.GetResource(EM_NS("userDisabled"));
282  if (extManager.datasource.hasArcOut(item, userDisabled)) {
283  var target = extManager.datasource.GetTarget(item, userDisabled, true);
284  if (target instanceof Components.interfaces.nsIRDFLiteral){
285  target = target.QueryInterface(Components.interfaces.nsIRDFLiteral);
286  return target.Value == "true";
287  }
288  }
289  var appDisabled = this._RDF.GetResource(EM_NS("appDisabled"));
290  if (extManager.datasource.hasArcOut(item, appDisabled)) {
291  var target = extManager.datasource.GetTarget(item, appDisabled, true);
292  if (target instanceof Components.interfaces.nsIRDFLiteral){
293  target = target.QueryInterface(Components.interfaces.nsIRDFLiteral);
294  return target.Value == "true";
295  }
296  }
297  return false;
298  },
299 
300 
301 
306  _copyManifest: function _copyManifest(itemNode, manifestDS) {
307 
308  // Copy all resources from the manifest to the main DS
309  var resources = manifestDS.GetAllResources();
310  while (resources.hasMoreElements()) {
311  var resource = resources.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
312 
313  // Get all arcs out of the resource
314  var arcs = manifestDS.ArcLabelsOut(resource);
315  while (arcs.hasMoreElements()) {
316  var arc = arcs.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
317 
318  // For each arc, get all targets
319  var targets = manifestDS.GetTargets(resource, arc, true);
320  while (targets.hasMoreElements()) {
321  var target = targets.getNext().QueryInterface(Components.interfaces.nsIRDFNode);
322 
323  // If this resource is the manifest root, replace it
324  // with a resource representing the current addon
325  newResource = resource;
326  if (resource.Value == RDFURI_INSTALL_MANIFEST_ROOT) {
327  newResource = itemNode;
328  }
329 
330  // Otherwise, assert into the main ds
331  this._datasource.Assert(newResource, arc, target, true);
332  }
333  }
334  }
335  },
336 
337 
338 
339 
340 
347  _getDatasource: function _getDatasource(file) {
348  var ioServ = Components.classes["@mozilla.org/network/io-service;1"]
349  .getService(Components.interfaces.nsIIOService);
350  var fph = ioServ.getProtocolHandler("file")
351  .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
352 
353  var fileURL = fph.getURLSpecFromFile(file);
354  var ds = this._RDF.GetDataSourceBlocking(fileURL);
355 
356  return ds;
357  },
358 
359 
360 
361  _deinit: function _deinit() {
362  //debug("\nAddonMetadata: deinit\n");
363 
364  this._RDF = null;
365  this._datasource = null;
366  },
367 
368 
369 
370  // watch for XRE startup and shutdown messages
371  observe: function(subject, topic, data) {
372  var os = Components.classes["@mozilla.org/observer-service;1"]
373  .getService(Components.interfaces.nsIObserverService);
374  switch (topic) {
375  case "xpcom-shutdown":
376  os.removeObserver(this, "xpcom-shutdown");
377  this._deinit();
378  break;
379  }
380  },
381 
382 
383 
384  _reportErrors: function _reportErrors(errorList) {
385  var consoleService = Components.classes["@mozilla.org/consoleservice;1"].
386  getService(Components.interfaces.nsIConsoleService);
387  for (var i = 0; i < errorList.length; i++) {
388  consoleService.logStringMessage("Addon Metadata Reader: " + errorList[i]);
389  debug("AddonMetadataReader: " + errorList[i] + "\n");
390  }
391  },
392 
393 
394 
398  QueryInterface: function(iid) {
399  if (!iid.equals(IID) &&
400  !iid.equals(Components.interfaces.nsIObserver) &&
401  !iid.equals(Components.interfaces.nsISupports))
402  throw Components.results.NS_ERROR_NO_INTERFACE;
403 
404  // THIS IS SO WRONG!
405  // We can get away with it though since we really only want the datasource
406  // and never the object that builds it.
407  if (iid.equals(IID)) {
408  return this._datasource;
409  }
410 
411  return this;
412  }
413 }; // AddonMetadata.prototype
414 
415 
416 
417 
418 
419 
420 
426 var gModule = {
427  registerSelf: function(componentManager, fileSpec, location, type) {
428  componentManager = componentManager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
429  for (var key in this._objects) {
430  var obj = this._objects[key];
431  componentManager.registerFactoryLocation(obj.CID, obj.className, obj.contractID,
432  fileSpec, location, type);
433  }
434  },
435 
436  getClassObject: function(componentManager, cid, iid) {
437  if (!iid.equals(Components.interfaces.nsIFactory))
438  throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
439 
440  for (var key in this._objects) {
441  if (cid.equals(this._objects[key].CID))
442  return this._objects[key].factory;
443  }
444 
445  throw Components.results.NS_ERROR_NO_INTERFACE;
446  },
447 
448  _makeFactory: #1= function(ctor) {
449  function ci(outer, iid) {
450  if (outer != null)
451  throw Components.results.NS_ERROR_NO_AGGREGATION;
452  return (new ctor()).QueryInterface(iid);
453  }
454  return { createInstance: ci };
455  },
456 
457  _objects: {
458  AddonMetadata: { CID : CID,
461  factory : #1#(AddonMetadata)
462  },
463  },
464 
465  canUnload: function(componentManager) {
466  return true;
467  }
468 }; // gModule
469 
470 function NSGetModule(comMgr, fileSpec) {
471  return gModule;
472 } // NSGetModule
473 
474 
const PREF_LASTMODIFIED
const KEY_PROFILEDIR
const RDFURI_ADDON_ROOT
const FILE_EXTENSIONS
function SONGBIRD_NS(property)
menuItem id
Definition: FeedWriter.js:971
sbOSDControlService prototype className
SafebrowsingApplicationMod prototype registerSelf
for(let i=0;i< aHistory.count;i++)
function ITEM_NS(id)
sbDeviceFirmwareAutoCheckForUpdate prototype contractID
sidebarFactory createInstance
Definition: nsSidebar.js:351
sbOSDControlService prototype QueryInterface
const PREFIX_NS_EM
const CLASSNAME
getService(Ci.sbIFaceplateManager)
const CID
function ADDON_NS(id)
SafebrowsingApplicationMod prototype getClassObject
const CONTRACTID
function AddonMetadata()
DataRemote prototype constructor
const PREFIX_ITEM_URI
return null
Definition: FeedWriter.js:1143
const IID
var gModule
var os
var prefs
Definition: FeedWriter.js:1169
const FILE_ADDONMETADATA
function debug(aMsg)
const PREFIX_NS_SONGBIRD
if(DEBUG_DATAREMOTES)
observe topic
Definition: FeedWriter.js:1326
const FILE_INSTALL_MANIFEST
const RDFURI_INSTALL_MANIFEST_ROOT
observe data
Definition: FeedWriter.js:1329
function EM_NS(property)
_getSelectedPageStyle s i
function NSGetModule(comMgr, fileSpec)
var file
sbDeviceFirmwareAutoCheckForUpdate prototype observe