AddOnUtils.jsm
Go to the documentation of this file.
1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 :miv */
3 /*
4 //
5 // BEGIN SONGBIRD GPL
6 //
7 // This file is part of the Songbird web player.
8 //
9 // Copyright(c) 2005-2008 POTI, Inc.
10 // http://songbirdnest.com
11 //
12 // This file may be licensed under the terms of of the
13 // GNU General Public License Version 2 (the "GPL").
14 //
15 // Software distributed under the License is distributed
16 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
17 // express or implied. See the GPL for the specific language
18 // governing rights and limitations.
19 //
20 // You should have received a copy of the GPL along with this
21 // program. If not, go to http://www.gnu.org/licenses/gpl.html
22 // or write to the Free Software Foundation, Inc.,
23 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 //
25 // END SONGBIRD GPL
26 //
27 */
28 
34 //------------------------------------------------------------------------------
35 //
36 // Add-on utilities configuration.
37 //
38 //------------------------------------------------------------------------------
39 
40 EXPORTED_SYMBOLS = [ "AddOnBundleLoader" ];
41 
42 //
43 // addOnBundleURLPref Preference with the add-on bundle URL.
44 // addOnBundleDataLoadTimeout Timeout in milliseconds for loading the add-on
45 // bundle data.
46 // addOnBundleCacheFileName Add-on bundle cache file name.
47 //
48 
50  addOnBundleURLPref: "songbird.url.firstrun",
51  addOnBundleBlacklistPref: "songbird.recommended_addons.update.blacklist",
52  addOnBundleDataLoadTimeout: 15000,
53  addOnBundleCacheFileName: "recommendedAddOnBundle.xml"
54 };
55 
56 
57 //------------------------------------------------------------------------------
58 //
59 // Add-on utilities imported services.
60 //
61 //------------------------------------------------------------------------------
62 
63 Components.utils.import("resource://app/jsmodules/RDFHelper.jsm");
64 
65 
66 //------------------------------------------------------------------------------
67 //
68 // Add-on utilities defs.
69 //
70 //------------------------------------------------------------------------------
71 
72 const Cc = Components.classes;
73 const Ci = Components.interfaces;
74 const Cr = Components.results;
75 const Cu = Components.utils;
76 
77 const DEFAULT_IO_FLAGS = -1;
79 
80 
81 //------------------------------------------------------------------------------
82 //
83 // Add-on bundle loader services.
84 //
85 // These services may be used to load add-on bundles.
86 //
87 //------------------------------------------------------------------------------
88 
94 {
95 }
96 
97 
102 AddOnBundleLoader.addInstalledAddOnsToBlacklist =
103  function AddOnBundleLoader_addInstalledAddOnsToBlacklist() {
104  // Get the list of installed add-ons.
105  var installedAddOnList = RDFHelper.help("rdf:addon-metadata",
106  "urn:songbird:addon:root",
107  RDFHelper.DEFAULT_RDF_NAMESPACES);
108 
109  // Add each installed add-on to the blacklist.
110  for (var i = 0; i < installedAddOnList.length; i++) {
111  this.addAddOnToBlacklist(installedAddOnList[i].id);
112  }
113 }
114 
115 
122 AddOnBundleLoader.addAddOnToBlacklist =
123  function AddOnBundleLoader_addAddOnToBlacklist(aAddOnID) {
124  // Do nothing if no ID.
125  if (!aAddOnID)
126  return;
127 
128  // Get the add-on blacklist.
129  var Application = Cc["@mozilla.org/fuel/application;1"]
130  .getService(Ci.fuelIApplication);
131  var blacklist =
132  Application.prefs.getValue(AddOnUtilsCfg.addOnBundleBlacklistPref, "");
133  if (blacklist.length > 0)
134  blacklist = blacklist.split(",");
135  else
136  blacklist = [];
137 
138  // Do nothing if add-on is already in the blacklist.
139  for (var i = 0; i < blacklist.length; i++) {
140  if (blacklist[i] == aAddOnID)
141  return;
142  }
143 
144  // Add the add-on to the blacklist.
145  blacklist.push(aAddOnID);
146  Application.prefs.setValue(AddOnUtilsCfg.addOnBundleBlacklistPref,
147  blacklist.join(","));
148 }
149 
150 
151 // Define the class.
152 AddOnBundleLoader.prototype = {
153  // Set the constructor.
155 
156 
157  //
158  // Public object fields.
159  //
160  // filterInstalledAddOns Filter out from the add-on bundle the set of
161  // already installed add-ons.
162  // filterBlacklistedAddOns Filter out from the add-on bundle the set of
163  // blacklisted add-ons.
164  // readFromCache If true, read add-on bundle from cache.
165  // addOnBundle Loaded add-on bundle.
166  // complete True if add-on bundle loading is complete.
167  // result Result of add-on bundle loading. A value of
168  // Cr.NS_OK indicates a successful load.
169  //
170 
171  filterInstalledAddOns: false,
172  filterBlacklistedAddOns: false,
173  readFromCache: false,
174  addOnBundle: null,
175  complete: false,
176  result: Cr.NS_OK,
177 
178 
179  //
180  // Internal object fields.
181  //
182  // _cfg Configuration settings.
183  // _completionCallback Completion callback function.
184  // _cancelled True if add-on loading was cancelled.
185  //
186 
187  _cfg: AddOnUtilsCfg,
188  _completionCallback: null,
189  _cancelled: false,
190 
191 
192  //----------------------------------------------------------------------------
193  //
194  // Public services.
195  //
196  //----------------------------------------------------------------------------
197 
206  start: function AddOnBundleLoader_start(aCompletionCallback) {
207  this._completionCallback = aCompletionCallback;
208  this._loadAddOnBundle();
209  },
210 
211 
216  cancel: function AddOnBundleLoader_cancel() {
217  //XXXeps a way should be provided to cancel the bundle loading.
218  // Mark add-on bundle loading as cancelled.
219  this._cancelled = true;
220 
221  // Clear object references.
222  this.addOnBundle = null;
223  this._completionCallback = null;
224  },
225 
226 
227  //----------------------------------------------------------------------------
228  //
229  // Add-on bundle update service sbIBundleDataListener services.
230  //
231  //----------------------------------------------------------------------------
232 
240  onDownloadComplete: function AddOnBundleLoader_onDownloadComplete(aBundle) {
241  this.complete = true;
242  this._loadAddOnBundle();
243  },
244 
245 
253  onError: function AddOnBundleLoader_onDownloadComplete_onError(aBundle) {
254  this.result = Cr.NS_ERROR_FAILURE;
255  this.complete = true;
256  this._loadAddOnBundle();
257  },
258 
259 
260  //----------------------------------------------------------------------------
261  //
262  // Internal services.
263  //
264  //----------------------------------------------------------------------------
265 
270  _loadAddOnBundle: function AddOnBundleLoader__loadAddOnBundle() {
271  // Do nothing if add-on bundle loading has been cancelled.
272  if (this._cancelled)
273  return;
274 
275  // Start loading the add-on bundle data.
276  if (!this.addOnBundle) {
277  // Set up the add-on bundle for loading.
278  this.addOnBundle = Cc["@songbirdnest.com/Songbird/Bundle;1"]
279  .createInstance(Ci.sbIBundle);
280  this.addOnBundle.bundleId = "firstrun";
281 
282  // Start loading the add-on bundle data.
283  if (this.readFromCache)
284  this._readAddOnBundleFromCache();
285  else
286  this._readAddOnBundleFromServer();
287  }
288 
289  // Do nothing more until bundle loading is complete.
290  if (!this.complete)
291  return;
292 
293  // Post-process the add-on bundle.
294  if (Components.isSuccessCode(this.result)) {
295  // Write the add-on bundle to the add-on bundle cache file.
296  if (!this.readFromCache)
297  this._writeAddOnBundleToCache();
298 
299  // If filtering out blacklisted add-ons, remove them.
300  if (this.filterBlacklistedAddOns)
301  this._removeBlacklistedAddOns();
302 
303  // If filtering out installed add-ons, remove them.
304  if (this.filterInstalledAddOns)
305  this._removeInstalledAddOns();
306  }
307 
308  // Call the completion callback function.
309  if (this._completionCallback)
310  this._completionCallback(this);
311  },
312 
313 
318  _readAddOnBundleFromServer:
319  function AddOnBundleLoader__readAddOnBundleFromServer() {
320  // Set the add-on bundle URL.
321  var Application = Cc["@mozilla.org/fuel/application;1"]
322  .getService(Ci.fuelIApplication);
323  this.addOnBundle.bundleURL = Application.prefs.getValue
324  (this._cfg.addOnBundleURLPref,
325  "default");
326 
327  // Start loading the add-on bundle data and listen for add-on bundle events.
328  try {
329  this.addOnBundle.addBundleDataListener(this);
330  this.addOnBundle.retrieveBundleData
331  (this._cfg.addOnBundleDataLoadTimeout);
332  } catch (ex) {
333  // Report the exception as an error.
334  Cu.reportError(ex);
335 
336  // Indicate that the add-on bundle loading failed.
337  this.result = Cr.NS_ERROR_FAILURE;
338  this.complete = true;
339  }
340  },
341 
342 
347  _readAddOnBundleFromCache:
348  function AddOnBundleLoader__readAddOnBundleFromCache() {
349  // Get the recommended add-on bundle cache file.
350  var recommendedAddOnBundleFile = this._getRecommendedAddOnCacheFile();
351 
352  // Check if cache file exists.
353  if (!recommendedAddOnBundleFile.exists()) {
354  this.result = Cr.NS_ERROR_FAILURE;
355  this.complete = true;
356  }
357 
358  // Set the add-on bundle URL.
359  var ioService = Cc["@mozilla.org/network/io-service;1"]
360  .getService(Ci.nsIIOService);
361  var fileURI = ioService.newFileURI(recommendedAddOnBundleFile);
362  this.addOnBundle.bundleURL = fileURI.spec;
363 
364  // Load the add-on bundle data.
365  try {
366  this.addOnBundle.retrieveLocalBundleData();
367  this.complete = true;
368  } catch (ex) {
369  // Report the exception as an error.
370  Cu.reportError(ex);
371 
372  // Indicate that the add-on bundle loading failed.
373  this.result = Cr.NS_ERROR_FAILURE;
374  this.complete = true;
375  }
376  },
377 
378 
383  _writeAddOnBundleToCache:
384  function AddOnBundleLoader__writeAddOnBundleToCache() {
385  // Get the recommended add-on bundle cache file.
386  var recommendedAddOnBundleFile = this._getRecommendedAddOnCacheFile();
387 
388  // Open an output stream to the file.
389  var outputStream = Cc["@mozilla.org/network/file-output-stream;1"]
390  .createInstance(Ci.nsIFileOutputStream);
391  outputStream.init(recommendedAddOnBundleFile,
394  0);
395 
396  // Write the add-on bundle data to the file.
397  try {
398  outputStream.write(this.addOnBundle.bundleDataText,
399  this.addOnBundle.bundleDataText.length);
400  } catch (ex) {
401  Cu.reportError(ex);
402  } finally {
403  outputStream.close();
404  }
405  },
406 
407 
414  _getRecommendedAddOnCacheFile:
415  function AddOnBundleLoader__getRecommendedAddOnCacheFile() {
416  // Get the recommended add-on bundle cache file.
417  var recommendedAddOnBundleFile =
418  Cc["@mozilla.org/file/directory_service;1"]
419  .getService(Ci.nsIProperties)
420  .get("ProfD", Ci.nsIFile);
421  recommendedAddOnBundleFile.append(this._cfg.addOnBundleCacheFileName);
422 
423  return recommendedAddOnBundleFile;
424  },
425 
426 
431  _removeInstalledAddOns: function AddOnBundleLoader__removeInstalledAddOns() {
432  // Get the list of installed add-ons.
433  var installedAddOnList = RDFHelper.help("rdf:addon-metadata",
434  "urn:songbird:addon:root",
435  RDFHelper.DEFAULT_RDF_NAMESPACES);
436 
437  // Create a table of installed add-ons, indexed by add-on ID.
438  var installedAddOnTable = {};
439  for (var i = 0; i < installedAddOnList.length; i++) {
440  var installedAddOn = installedAddOnList[i];
441  installedAddOnTable[installedAddOn.id] = installedAddOn;
442  }
443 
444  // Remove bundle add-ons that are already installed.
445  var extensionCount = this.addOnBundle.bundleExtensionCount;
446  for (var i = extensionCount - 1; i >= 0; i--) {
447  // Get the bundle add-on ID.
448  var addOnID = this.addOnBundle.getExtensionAttribute(i, "id");
449 
450  // Remove bundle add-on if it's already installed.
451  if (installedAddOnTable[addOnID])
452  this.addOnBundle.removeExtension(i);
453  }
454  },
455 
456 
461  _removeBlacklistedAddOns:
462  function AddOnBundleLoader__removeBlacklistedAddOns() {
463  // Get the add-on blacklist.
464  var Application = Cc["@mozilla.org/fuel/application;1"]
465  .getService(Ci.fuelIApplication);
466  var blacklist =
467  Application.prefs.getValue(this._cfg.addOnBundleBlacklistPref, "");
468  if (blacklist.length > 0)
469  blacklist = blacklist.split(",");
470  else
471  blacklist = [];
472 
473  // Create a table of blacklisted add-ons, indexed by add-on ID.
474  var blacklistedAddOnTable = {};
475  for (var i = 0; i < blacklist.length; i++) {
476  var blacklistedAddOnID = blacklist[i];
477  blacklistedAddOnTable[blacklistedAddOnID] = true;
478  }
479 
480  // Remove bundle add-ons that are blacklisted.
481  var extensionCount = this.addOnBundle.bundleExtensionCount;
482  for (var i = extensionCount - 1; i >= 0; i--) {
483  // Get the bundle add-on ID.
484  var addOnID = this.addOnBundle.getExtensionAttribute(i, "id");
485 
486  // Remove bundle add-on if it's blacklisted.
487  if (blacklistedAddOnTable[addOnID])
488  this.addOnBundle.removeExtension(i);
489  }
490  }
491 }
492 
function start(ch)
const Cu
Definition: AddOnUtils.jsm:75
var Application
Definition: sbAboutDRM.js:37
const DEFAULT_PERMISSIONS
Definition: AddOnUtils.jsm:78
var ioService
const Cc
Definition: AddOnUtils.jsm:72
function RDFHelper(aRdf, aDatasource, aResource, aNamespaces)
Definition: RDFHelper.jsm:61
DataRemote prototype constructor
const Ci
Definition: AddOnUtils.jsm:73
return null
Definition: FeedWriter.js:1143
var AddOnUtilsCfg
Definition: AddOnUtils.jsm:49
const DEFAULT_IO_FLAGS
Definition: AddOnUtils.jsm:77
EXPORTED_SYMBOLS
Definition: AddOnUtils.jsm:40
const Cr
Definition: AddOnUtils.jsm:74
_getSelectedPageStyle s i
function AddOnBundleLoader()
Definition: AddOnUtils.jsm:93