2 # ***** BEGIN LICENSE BLOCK *****
3 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 # The contents of this file are subject to the Mozilla Public License Version
6 # 1.1 (the "License"); you may not use this file except in compliance with
7 # the License. You may obtain a copy of the License at
8 # http://www.mozilla.org/MPL/
10 # Software distributed under the License is distributed on an "AS IS" basis,
11 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 # for the specific language governing rights and limitations under the
15 # The Original Code is the Extension Manager.
17 # The Initial Developer of the Original Code is
18 # the Mozilla Foundation.
19 # Portions created by the Initial Developer are Copyright (C) 2010
20 # the Initial Developer. All Rights Reserved.
23 # Dave Townsend <dtownsend@oxymoronical.com>
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.
37 # ***** END LICENSE BLOCK *****
40 const Cc = Components.classes;
41 const Ci = Components.interfaces;
43 var EXPORTED_SYMBOLS = [];
45 Components.utils.import("resource://gre/modules/AddonManager.jsm");
46 Components.utils.import("resource://gre/modules/Services.jsm");
48 ["LOG", "WARN", "ERROR"].forEach(function(aName) {
49 this.__defineGetter__(aName, function() {
50 Components.utils.import("resource://gre/modules/AddonLogging.jsm");
52 LogManager.getLogger("addons.plugins", this);
57 var PluginProvider = {
58 // A dictionary mapping IDs to names and descriptions
62 * Called to get an Addon with a particular ID.
65 * The ID of the add-on to retrieve
67 * A callback to pass the Addon to
69 getAddonByID: function PL_getAddon(aId, aCallback) {
71 this.buildPluginList();
73 if (aId in this.plugins) {
74 let name = this.plugins[aId].name;
75 let description = this.plugins[aId].description;
77 let tags = Cc["@mozilla.org/plugin/host;1"].
78 getService(Ci.nsIPluginHost).
81 tags.forEach(function(aTag) {
82 if (aTag.name == name && aTag.description == description)
86 aCallback(new PluginWrapper(aId, name, description, selected));
94 * Called to get Addons of a particular type.
97 * An array of types to fetch. Can be null to get all types.
99 * A callback to pass an array of Addons to
101 getAddonsByTypes: function PL_getAddonsByTypes(aTypes, aCallback) {
102 if (aTypes && aTypes.indexOf("plugin") < 0) {
108 this.buildPluginList();
112 for (let id in this.plugins) {
113 this.getAddonByID(id, function(aAddon) {
114 results.push(aAddon);
122 * Called to get Addons that have pending operations.
125 * An array of types to fetch. Can be null to get all types
127 * A callback to pass an array of Addons to
129 getAddonsWithOperationsByTypes: function PL_getAddonsWithOperationsByTypes(aTypes, aCallback) {
134 * Called to get the current AddonInstalls, optionally restricting by type.
137 * An array of types or null to get all types
139 * A callback to pass the array of AddonInstalls to
141 getInstallsByTypes: function PL_getInstallsByTypes(aTypes, aCallback) {
145 buildPluginList: function PL_buildPluginList() {
146 let tags = Cc["@mozilla.org/plugin/host;1"].
147 getService(Ci.nsIPluginHost).
152 tags.forEach(function(aTag) {
153 if (!(aTag.name in seen))
154 seen[aTag.name] = {};
155 if (!(aTag.description in seen[aTag.name])) {
156 let id = Cc["@mozilla.org/uuid-generator;1"].
157 getService(Ci.nsIUUIDGenerator).
161 description: aTag.description
163 seen[aTag.name][aTag.description] = true;
170 * The PluginWrapper wraps a set of nsIPluginTags to provide the data visible to
171 * public callers through the API.
173 function PluginWrapper(aId, aName, aDescription, aTags) {
174 let safedesc = aDescription.replace(/<\/?[a-z][^>]*>/gi, " ");
175 let homepageURL = null;
176 if (/<A\s+HREF=[^>]*>/i.test(aDescription))
177 homepageURL = /<A\s+HREF=["']?([^>"'\s]*)/i.exec(aDescription)[1];
179 this.__defineGetter__("id", function() aId);
180 this.__defineGetter__("type", function() "plugin");
181 this.__defineGetter__("name", function() aName);
182 this.__defineGetter__("creator", function() null);
183 this.__defineGetter__("description", function() safedesc);
184 this.__defineGetter__("version", function() aTags[0].version);
185 this.__defineGetter__("homepageURL", function() homepageURL);
187 this.__defineGetter__("isActive", function() !aTags[0].blocklisted && !aTags[0].disabled);
188 this.__defineGetter__("appDisabled", function() aTags[0].blocklisted);
189 this.__defineGetter__("userDisabled", function() aTags[0].disabled);
190 this.__defineSetter__("userDisabled", function(aVal) {
191 if (aTags[0].disabled == aVal)
194 aTags.forEach(function(aTag) {
195 aTag.disabled = aVal;
197 AddonManagerPrivate.callAddonListeners(aVal ? "onDisabling" : "onEnabling", this, false);
198 AddonManagerPrivate.callAddonListeners(aVal ? "onDisabled" : "onEnabled", this);
202 this.__defineGetter__("blocklistState", function() {
203 let bs = Cc["@mozilla.org/extensions/blocklist;1"].
204 getService(Ci.nsIBlocklistService);
205 return bs.getPluginBlocklistState(aTags[0]);
208 this.__defineGetter__("size", function() {
209 function getDirectorySize(aFile) {
211 let entries = aFile.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
213 while (entry = entries.nextFile) {
214 if (entry.isSymlink() || !entry.isDirectory())
215 size += entry.fileSize;
217 size += getDirectorySize(entry);
224 let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
225 aTags.forEach(function(aTag) {
226 file.initWithPath(aTag.fullpath);
227 if (file.isDirectory())
228 size += getDirectorySize(file);
230 size += file.fileSize;
235 this.__defineGetter__("installDate", function() {
237 let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
238 aTags.forEach(function(aTag) {
239 file.initWithPath(aTag.fullpath);
240 date = Math.max(date, file.lastModifiedTime);
242 return new Date(date);
245 this.__defineGetter__("scope", function() {
246 let path = aTags[0].fullpath;
247 // Plugins inside the application directory are in the application scope
248 let dir = Services.dirsvc.get("APlugns", Ci.nsILocalFile);
249 if (path.substring(0, dir.path.length) == dir.path)
250 return AddonManager.SCOPE_APPLICATION;
252 // Plugins inside the profile directory are in the profile scope
253 dir = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
254 if (path.substring(0, dir.path.length) == dir.path)
255 return AddonManager.SCOPE_PROFILE;
257 // Plugins anywhere else in the user's home are in the user scope
258 dir = Services.dirsvc.get("Home", Ci.nsILocalFile);
259 if (path.substring(0, dir.path.length) == dir.path)
260 return AddonManager.SCOPE_USER;
262 // Any other locations are system scope
263 return AddonManager.SCOPE_SYSTEM;
266 this.__defineGetter__("pendingOperations", function() {
267 return AddonManager.PENDING_NONE;
270 this.__defineGetter__("operationsRequiringRestart", function() {
271 return AddonManager.OP_NEEDS_RESTART_NONE;
274 this.__defineGetter__("permissions", function() {
276 if (!this.appDisabled) {
277 if (this.userDisabled)
278 permissions |= AddonManager.PERM_CAN_ENABLE;
280 permissions |= AddonManager.PERM_CAN_DISABLE;
286 PluginWrapper.prototype = {
288 return this.installDate;
295 get isPlatformCompatible() {
299 get providesUpdatesSecurely() {
303 isCompatibleWith: function(aAppVerison, aPlatformVersion) {
307 findUpdates: function(aListener, aReason, aAppVersion, aPlatformVersion) {
308 if ("onNoCompatibilityUpdateAvailable" in aListener)
309 aListener.onNoCompatibilityUpdateAvailable(this);
310 if ("onNoUpdateAvailable" in aListener)
311 aListener.onNoUpdateAvailable(this);
312 if ("onUpdateFinished" in aListener)
313 aListener.onUpdateFinished(this);
317 AddonManagerPrivate.registerProvider(PluginProvider);