toolkit/mozapps/extensions/internal/PluginProvider.jsm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 "use strict";
michael@0 6
michael@0 7 const Cc = Components.classes;
michael@0 8 const Ci = Components.interfaces;
michael@0 9 const Cu = Components.utils;
michael@0 10
michael@0 11 this.EXPORTED_SYMBOLS = [];
michael@0 12
michael@0 13 Cu.import("resource://gre/modules/AddonManager.jsm");
michael@0 14 Cu.import("resource://gre/modules/Services.jsm");
michael@0 15
michael@0 16 const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/extensions.properties";
michael@0 17 const STRING_TYPE_NAME = "type.%ID%.name";
michael@0 18 const LIST_UPDATED_TOPIC = "plugins-list-updated";
michael@0 19
michael@0 20 Cu.import("resource://gre/modules/Log.jsm");
michael@0 21 const LOGGER_ID = "addons.plugins";
michael@0 22
michael@0 23 // Create a new logger for use by the Addons Plugin Provider
michael@0 24 // (Requires AddonManager.jsm)
michael@0 25 let logger = Log.repository.getLogger(LOGGER_ID);
michael@0 26
michael@0 27 function getIDHashForString(aStr) {
michael@0 28 // return the two-digit hexadecimal code for a byte
michael@0 29 function toHexString(charCode)
michael@0 30 ("0" + charCode.toString(16)).slice(-2);
michael@0 31
michael@0 32 let hasher = Cc["@mozilla.org/security/hash;1"].
michael@0 33 createInstance(Ci.nsICryptoHash);
michael@0 34 hasher.init(Ci.nsICryptoHash.MD5);
michael@0 35 let stringStream = Cc["@mozilla.org/io/string-input-stream;1"].
michael@0 36 createInstance(Ci.nsIStringInputStream);
michael@0 37 stringStream.data = aStr ? aStr : "null";
michael@0 38 hasher.updateFromStream(stringStream, -1);
michael@0 39
michael@0 40 // convert the binary hash data to a hex string.
michael@0 41 let binary = hasher.finish(false);
michael@0 42 let hash = [toHexString(binary.charCodeAt(i)) for (i in binary)].join("").toLowerCase();
michael@0 43 return "{" + hash.substr(0, 8) + "-" +
michael@0 44 hash.substr(8, 4) + "-" +
michael@0 45 hash.substr(12, 4) + "-" +
michael@0 46 hash.substr(16, 4) + "-" +
michael@0 47 hash.substr(20) + "}";
michael@0 48 }
michael@0 49
michael@0 50 var PluginProvider = {
michael@0 51 // A dictionary mapping IDs to names and descriptions
michael@0 52 plugins: null,
michael@0 53
michael@0 54 startup: function PL_startup() {
michael@0 55 Services.obs.addObserver(this, LIST_UPDATED_TOPIC, false);
michael@0 56 Services.obs.addObserver(this, AddonManager.OPTIONS_NOTIFICATION_DISPLAYED, false);
michael@0 57 },
michael@0 58
michael@0 59 /**
michael@0 60 * Called when the application is shutting down. Only necessary for tests
michael@0 61 * to be able to simulate a shutdown.
michael@0 62 */
michael@0 63 shutdown: function PL_shutdown() {
michael@0 64 this.plugins = null;
michael@0 65 Services.obs.removeObserver(this, AddonManager.OPTIONS_NOTIFICATION_DISPLAYED);
michael@0 66 Services.obs.removeObserver(this, LIST_UPDATED_TOPIC);
michael@0 67 },
michael@0 68
michael@0 69 observe: function(aSubject, aTopic, aData) {
michael@0 70 switch (aTopic) {
michael@0 71 case AddonManager.OPTIONS_NOTIFICATION_DISPLAYED:
michael@0 72 this.getAddonByID(aData, function PL_displayPluginInfo(plugin) {
michael@0 73 if (!plugin)
michael@0 74 return;
michael@0 75
michael@0 76 let libLabel = aSubject.getElementById("pluginLibraries");
michael@0 77 libLabel.textContent = plugin.pluginLibraries.join(", ");
michael@0 78
michael@0 79 let typeLabel = aSubject.getElementById("pluginMimeTypes"), types = [];
michael@0 80 for (let type of plugin.pluginMimeTypes) {
michael@0 81 let extras = [type.description.trim(), type.suffixes].
michael@0 82 filter(function(x) x).join(": ");
michael@0 83 types.push(type.type + (extras ? " (" + extras + ")" : ""));
michael@0 84 }
michael@0 85 typeLabel.textContent = types.join(",\n");
michael@0 86 });
michael@0 87 break;
michael@0 88 case LIST_UPDATED_TOPIC:
michael@0 89 if (this.plugins)
michael@0 90 this.updatePluginList();
michael@0 91 break;
michael@0 92 }
michael@0 93 },
michael@0 94
michael@0 95 /**
michael@0 96 * Creates a PluginWrapper for a plugin object.
michael@0 97 */
michael@0 98 buildWrapper: function PL_buildWrapper(aPlugin) {
michael@0 99 return new PluginWrapper(aPlugin.id,
michael@0 100 aPlugin.name,
michael@0 101 aPlugin.description,
michael@0 102 aPlugin.tags);
michael@0 103 },
michael@0 104
michael@0 105 /**
michael@0 106 * Called to get an Addon with a particular ID.
michael@0 107 *
michael@0 108 * @param aId
michael@0 109 * The ID of the add-on to retrieve
michael@0 110 * @param aCallback
michael@0 111 * A callback to pass the Addon to
michael@0 112 */
michael@0 113 getAddonByID: function PL_getAddon(aId, aCallback) {
michael@0 114 if (!this.plugins)
michael@0 115 this.buildPluginList();
michael@0 116
michael@0 117 if (aId in this.plugins)
michael@0 118 aCallback(this.buildWrapper(this.plugins[aId]));
michael@0 119 else
michael@0 120 aCallback(null);
michael@0 121 },
michael@0 122
michael@0 123 /**
michael@0 124 * Called to get Addons of a particular type.
michael@0 125 *
michael@0 126 * @param aTypes
michael@0 127 * An array of types to fetch. Can be null to get all types.
michael@0 128 * @param callback
michael@0 129 * A callback to pass an array of Addons to
michael@0 130 */
michael@0 131 getAddonsByTypes: function PL_getAddonsByTypes(aTypes, aCallback) {
michael@0 132 if (aTypes && aTypes.indexOf("plugin") < 0) {
michael@0 133 aCallback([]);
michael@0 134 return;
michael@0 135 }
michael@0 136
michael@0 137 if (!this.plugins)
michael@0 138 this.buildPluginList();
michael@0 139
michael@0 140 let results = [];
michael@0 141
michael@0 142 for (let id in this.plugins) {
michael@0 143 this.getAddonByID(id, function(aAddon) {
michael@0 144 results.push(aAddon);
michael@0 145 });
michael@0 146 }
michael@0 147
michael@0 148 aCallback(results);
michael@0 149 },
michael@0 150
michael@0 151 /**
michael@0 152 * Called to get Addons that have pending operations.
michael@0 153 *
michael@0 154 * @param aTypes
michael@0 155 * An array of types to fetch. Can be null to get all types
michael@0 156 * @param aCallback
michael@0 157 * A callback to pass an array of Addons to
michael@0 158 */
michael@0 159 getAddonsWithOperationsByTypes: function PL_getAddonsWithOperationsByTypes(aTypes, aCallback) {
michael@0 160 aCallback([]);
michael@0 161 },
michael@0 162
michael@0 163 /**
michael@0 164 * Called to get the current AddonInstalls, optionally restricting by type.
michael@0 165 *
michael@0 166 * @param aTypes
michael@0 167 * An array of types or null to get all types
michael@0 168 * @param aCallback
michael@0 169 * A callback to pass the array of AddonInstalls to
michael@0 170 */
michael@0 171 getInstallsByTypes: function PL_getInstallsByTypes(aTypes, aCallback) {
michael@0 172 aCallback([]);
michael@0 173 },
michael@0 174
michael@0 175 /**
michael@0 176 * Builds a list of the current plugins reported by the plugin host
michael@0 177 *
michael@0 178 * @return a dictionary of plugins indexed by our generated ID
michael@0 179 */
michael@0 180 getPluginList: function PL_getPluginList() {
michael@0 181 let tags = Cc["@mozilla.org/plugin/host;1"].
michael@0 182 getService(Ci.nsIPluginHost).
michael@0 183 getPluginTags({});
michael@0 184
michael@0 185 let list = {};
michael@0 186 let seenPlugins = {};
michael@0 187 for (let tag of tags) {
michael@0 188 if (!(tag.name in seenPlugins))
michael@0 189 seenPlugins[tag.name] = {};
michael@0 190 if (!(tag.description in seenPlugins[tag.name])) {
michael@0 191 let plugin = {
michael@0 192 id: getIDHashForString(tag.name + tag.description),
michael@0 193 name: tag.name,
michael@0 194 description: tag.description,
michael@0 195 tags: [tag]
michael@0 196 };
michael@0 197
michael@0 198 seenPlugins[tag.name][tag.description] = plugin;
michael@0 199 list[plugin.id] = plugin;
michael@0 200 }
michael@0 201 else {
michael@0 202 seenPlugins[tag.name][tag.description].tags.push(tag);
michael@0 203 }
michael@0 204 }
michael@0 205
michael@0 206 return list;
michael@0 207 },
michael@0 208
michael@0 209 /**
michael@0 210 * Builds the list of known plugins from the plugin host
michael@0 211 */
michael@0 212 buildPluginList: function PL_buildPluginList() {
michael@0 213 this.plugins = this.getPluginList();
michael@0 214 },
michael@0 215
michael@0 216 /**
michael@0 217 * Updates the plugins from the plugin host by comparing the current plugins
michael@0 218 * to the last known list sending out any necessary API notifications for
michael@0 219 * changes.
michael@0 220 */
michael@0 221 updatePluginList: function PL_updatePluginList() {
michael@0 222 let newList = this.getPluginList();
michael@0 223
michael@0 224 let lostPlugins = [this.buildWrapper(this.plugins[id])
michael@0 225 for each (id in Object.keys(this.plugins)) if (!(id in newList))];
michael@0 226 let newPlugins = [this.buildWrapper(newList[id])
michael@0 227 for each (id in Object.keys(newList)) if (!(id in this.plugins))];
michael@0 228 let matchedIDs = [id for each (id in Object.keys(newList)) if (id in this.plugins)];
michael@0 229
michael@0 230 // The plugin host generates new tags for every plugin after a scan and
michael@0 231 // if the plugin's filename has changed then the disabled state won't have
michael@0 232 // been carried across, send out notifications for anything that has
michael@0 233 // changed (see bug 830267).
michael@0 234 let changedWrappers = [];
michael@0 235 for (let id of matchedIDs) {
michael@0 236 let oldWrapper = this.buildWrapper(this.plugins[id]);
michael@0 237 let newWrapper = this.buildWrapper(newList[id]);
michael@0 238
michael@0 239 if (newWrapper.isActive != oldWrapper.isActive) {
michael@0 240 AddonManagerPrivate.callAddonListeners(newWrapper.isActive ?
michael@0 241 "onEnabling" : "onDisabling",
michael@0 242 newWrapper, false);
michael@0 243 changedWrappers.push(newWrapper);
michael@0 244 }
michael@0 245 }
michael@0 246
michael@0 247 // Notify about new installs
michael@0 248 for (let plugin of newPlugins) {
michael@0 249 AddonManagerPrivate.callInstallListeners("onExternalInstall", null,
michael@0 250 plugin, null, false);
michael@0 251 AddonManagerPrivate.callAddonListeners("onInstalling", plugin, false);
michael@0 252 }
michael@0 253
michael@0 254 // Notify for any plugins that have vanished.
michael@0 255 for (let plugin of lostPlugins)
michael@0 256 AddonManagerPrivate.callAddonListeners("onUninstalling", plugin, false);
michael@0 257
michael@0 258 this.plugins = newList;
michael@0 259
michael@0 260 // Signal that new installs are complete
michael@0 261 for (let plugin of newPlugins)
michael@0 262 AddonManagerPrivate.callAddonListeners("onInstalled", plugin);
michael@0 263
michael@0 264 // Signal that enables/disables are complete
michael@0 265 for (let wrapper of changedWrappers) {
michael@0 266 AddonManagerPrivate.callAddonListeners(wrapper.isActive ?
michael@0 267 "onEnabled" : "onDisabled",
michael@0 268 wrapper);
michael@0 269 }
michael@0 270
michael@0 271 // Signal that uninstalls are complete
michael@0 272 for (let plugin of lostPlugins)
michael@0 273 AddonManagerPrivate.callAddonListeners("onUninstalled", plugin);
michael@0 274 }
michael@0 275 };
michael@0 276
michael@0 277 /**
michael@0 278 * The PluginWrapper wraps a set of nsIPluginTags to provide the data visible to
michael@0 279 * public callers through the API.
michael@0 280 */
michael@0 281 function PluginWrapper(aId, aName, aDescription, aTags) {
michael@0 282 let safedesc = aDescription.replace(/<\/?[a-z][^>]*>/gi, " ");
michael@0 283 let homepageURL = null;
michael@0 284 if (/<A\s+HREF=[^>]*>/i.test(aDescription))
michael@0 285 homepageURL = /<A\s+HREF=["']?([^>"'\s]*)/i.exec(aDescription)[1];
michael@0 286
michael@0 287 this.__defineGetter__("id", function() aId);
michael@0 288 this.__defineGetter__("type", function() "plugin");
michael@0 289 this.__defineGetter__("name", function() aName);
michael@0 290 this.__defineGetter__("creator", function() null);
michael@0 291 this.__defineGetter__("description", function() safedesc);
michael@0 292 this.__defineGetter__("version", function() aTags[0].version);
michael@0 293 this.__defineGetter__("homepageURL", function() homepageURL);
michael@0 294
michael@0 295 this.__defineGetter__("isActive", function() !aTags[0].blocklisted && !aTags[0].disabled);
michael@0 296 this.__defineGetter__("appDisabled", function() aTags[0].blocklisted);
michael@0 297
michael@0 298 this.__defineGetter__("userDisabled", function() {
michael@0 299 if (aTags[0].disabled)
michael@0 300 return true;
michael@0 301
michael@0 302 if ((Services.prefs.getBoolPref("plugins.click_to_play") && aTags[0].clicktoplay) ||
michael@0 303 this.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE ||
michael@0 304 this.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE)
michael@0 305 return AddonManager.STATE_ASK_TO_ACTIVATE;
michael@0 306
michael@0 307 return false;
michael@0 308 });
michael@0 309
michael@0 310 this.__defineSetter__("userDisabled", function(aVal) {
michael@0 311 let previousVal = this.userDisabled;
michael@0 312 if (aVal === previousVal)
michael@0 313 return aVal;
michael@0 314
michael@0 315 for (let tag of aTags) {
michael@0 316 if (aVal === true)
michael@0 317 tag.enabledState = Ci.nsIPluginTag.STATE_DISABLED;
michael@0 318 else if (aVal === false)
michael@0 319 tag.enabledState = Ci.nsIPluginTag.STATE_ENABLED;
michael@0 320 else if (aVal == AddonManager.STATE_ASK_TO_ACTIVATE)
michael@0 321 tag.enabledState = Ci.nsIPluginTag.STATE_CLICKTOPLAY;
michael@0 322 }
michael@0 323
michael@0 324 // If 'userDisabled' was 'true' and we're going to a state that's not
michael@0 325 // that, we're enabling, so call those listeners.
michael@0 326 if (previousVal === true && aVal !== true) {
michael@0 327 AddonManagerPrivate.callAddonListeners("onEnabling", this, false);
michael@0 328 AddonManagerPrivate.callAddonListeners("onEnabled", this);
michael@0 329 }
michael@0 330
michael@0 331 // If 'userDisabled' was not 'true' and we're going to a state where
michael@0 332 // it is, we're disabling, so call those listeners.
michael@0 333 if (previousVal !== true && aVal === true) {
michael@0 334 AddonManagerPrivate.callAddonListeners("onDisabling", this, false);
michael@0 335 AddonManagerPrivate.callAddonListeners("onDisabled", this);
michael@0 336 }
michael@0 337
michael@0 338 // If the 'userDisabled' value involved AddonManager.STATE_ASK_TO_ACTIVATE,
michael@0 339 // call the onPropertyChanged listeners.
michael@0 340 if (previousVal == AddonManager.STATE_ASK_TO_ACTIVATE ||
michael@0 341 aVal == AddonManager.STATE_ASK_TO_ACTIVATE) {
michael@0 342 AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["userDisabled"]);
michael@0 343 }
michael@0 344
michael@0 345 return aVal;
michael@0 346 });
michael@0 347
michael@0 348
michael@0 349 this.__defineGetter__("blocklistState", function() {
michael@0 350 let bs = Cc["@mozilla.org/extensions/blocklist;1"].
michael@0 351 getService(Ci.nsIBlocklistService);
michael@0 352 return bs.getPluginBlocklistState(aTags[0]);
michael@0 353 });
michael@0 354
michael@0 355 this.__defineGetter__("blocklistURL", function() {
michael@0 356 let bs = Cc["@mozilla.org/extensions/blocklist;1"].
michael@0 357 getService(Ci.nsIBlocklistService);
michael@0 358 return bs.getPluginBlocklistURL(aTags[0]);
michael@0 359 });
michael@0 360
michael@0 361 this.__defineGetter__("size", function() {
michael@0 362 function getDirectorySize(aFile) {
michael@0 363 let size = 0;
michael@0 364 let entries = aFile.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
michael@0 365 let entry;
michael@0 366 while ((entry = entries.nextFile)) {
michael@0 367 if (entry.isSymlink() || !entry.isDirectory())
michael@0 368 size += entry.fileSize;
michael@0 369 else
michael@0 370 size += getDirectorySize(entry);
michael@0 371 }
michael@0 372 entries.close();
michael@0 373 return size;
michael@0 374 }
michael@0 375
michael@0 376 let size = 0;
michael@0 377 let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
michael@0 378 for (let tag of aTags) {
michael@0 379 file.initWithPath(tag.fullpath);
michael@0 380 if (file.isDirectory())
michael@0 381 size += getDirectorySize(file);
michael@0 382 else
michael@0 383 size += file.fileSize;
michael@0 384 }
michael@0 385 return size;
michael@0 386 });
michael@0 387
michael@0 388 this.__defineGetter__("pluginLibraries", function() {
michael@0 389 let libs = [];
michael@0 390 for (let tag of aTags)
michael@0 391 libs.push(tag.filename);
michael@0 392 return libs;
michael@0 393 });
michael@0 394
michael@0 395 this.__defineGetter__("pluginFullpath", function() {
michael@0 396 let paths = [];
michael@0 397 for (let tag of aTags)
michael@0 398 paths.push(tag.fullpath);
michael@0 399 return paths;
michael@0 400 })
michael@0 401
michael@0 402 this.__defineGetter__("pluginMimeTypes", function() {
michael@0 403 let types = [];
michael@0 404 for (let tag of aTags) {
michael@0 405 let mimeTypes = tag.getMimeTypes({});
michael@0 406 let mimeDescriptions = tag.getMimeDescriptions({});
michael@0 407 let extensions = tag.getExtensions({});
michael@0 408 for (let i = 0; i < mimeTypes.length; i++) {
michael@0 409 let type = {};
michael@0 410 type.type = mimeTypes[i];
michael@0 411 type.description = mimeDescriptions[i];
michael@0 412 type.suffixes = extensions[i];
michael@0 413
michael@0 414 types.push(type);
michael@0 415 }
michael@0 416 }
michael@0 417 return types;
michael@0 418 });
michael@0 419
michael@0 420 this.__defineGetter__("installDate", function() {
michael@0 421 let date = 0;
michael@0 422 for (let tag of aTags) {
michael@0 423 date = Math.max(date, tag.lastModifiedTime);
michael@0 424 }
michael@0 425 return new Date(date);
michael@0 426 });
michael@0 427
michael@0 428 this.__defineGetter__("scope", function() {
michael@0 429 let path = aTags[0].fullpath;
michael@0 430 // Plugins inside the application directory are in the application scope
michael@0 431 let dir = Services.dirsvc.get("APlugns", Ci.nsIFile);
michael@0 432 if (path.startsWith(dir.path))
michael@0 433 return AddonManager.SCOPE_APPLICATION;
michael@0 434
michael@0 435 // Plugins inside the profile directory are in the profile scope
michael@0 436 dir = Services.dirsvc.get("ProfD", Ci.nsIFile);
michael@0 437 if (path.startsWith(dir.path))
michael@0 438 return AddonManager.SCOPE_PROFILE;
michael@0 439
michael@0 440 // Plugins anywhere else in the user's home are in the user scope,
michael@0 441 // but not all platforms have a home directory.
michael@0 442 try {
michael@0 443 dir = Services.dirsvc.get("Home", Ci.nsIFile);
michael@0 444 if (path.startsWith(dir.path))
michael@0 445 return AddonManager.SCOPE_USER;
michael@0 446 } catch (e if (e.result && e.result == Components.results.NS_ERROR_FAILURE)) {
michael@0 447 // Do nothing: missing "Home".
michael@0 448 }
michael@0 449
michael@0 450 // Any other locations are system scope
michael@0 451 return AddonManager.SCOPE_SYSTEM;
michael@0 452 });
michael@0 453
michael@0 454 this.__defineGetter__("pendingOperations", function() {
michael@0 455 return AddonManager.PENDING_NONE;
michael@0 456 });
michael@0 457
michael@0 458 this.__defineGetter__("operationsRequiringRestart", function() {
michael@0 459 return AddonManager.OP_NEEDS_RESTART_NONE;
michael@0 460 });
michael@0 461
michael@0 462 this.__defineGetter__("permissions", function() {
michael@0 463 let permissions = 0;
michael@0 464 if (!this.appDisabled) {
michael@0 465
michael@0 466 if (this.userDisabled !== true)
michael@0 467 permissions |= AddonManager.PERM_CAN_DISABLE;
michael@0 468
michael@0 469 let blocklistState = this.blocklistState;
michael@0 470 let isCTPBlocklisted =
michael@0 471 (blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE ||
michael@0 472 blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE);
michael@0 473
michael@0 474 if (this.userDisabled !== AddonManager.STATE_ASK_TO_ACTIVATE &&
michael@0 475 (Services.prefs.getBoolPref("plugins.click_to_play") ||
michael@0 476 isCTPBlocklisted)) {
michael@0 477 permissions |= AddonManager.PERM_CAN_ASK_TO_ACTIVATE;
michael@0 478 }
michael@0 479
michael@0 480 if (this.userDisabled !== false && !isCTPBlocklisted) {
michael@0 481 permissions |= AddonManager.PERM_CAN_ENABLE;
michael@0 482 }
michael@0 483 }
michael@0 484 return permissions;
michael@0 485 });
michael@0 486 }
michael@0 487
michael@0 488 PluginWrapper.prototype = {
michael@0 489 optionsType: AddonManager.OPTIONS_TYPE_INLINE_INFO,
michael@0 490 optionsURL: "chrome://mozapps/content/extensions/pluginPrefs.xul",
michael@0 491
michael@0 492 get updateDate() {
michael@0 493 return this.installDate;
michael@0 494 },
michael@0 495
michael@0 496 get isCompatible() {
michael@0 497 return true;
michael@0 498 },
michael@0 499
michael@0 500 get isPlatformCompatible() {
michael@0 501 return true;
michael@0 502 },
michael@0 503
michael@0 504 get providesUpdatesSecurely() {
michael@0 505 return true;
michael@0 506 },
michael@0 507
michael@0 508 get foreignInstall() {
michael@0 509 return true;
michael@0 510 },
michael@0 511
michael@0 512 isCompatibleWith: function(aAppVerison, aPlatformVersion) {
michael@0 513 return true;
michael@0 514 },
michael@0 515
michael@0 516 findUpdates: function(aListener, aReason, aAppVersion, aPlatformVersion) {
michael@0 517 if ("onNoCompatibilityUpdateAvailable" in aListener)
michael@0 518 aListener.onNoCompatibilityUpdateAvailable(this);
michael@0 519 if ("onNoUpdateAvailable" in aListener)
michael@0 520 aListener.onNoUpdateAvailable(this);
michael@0 521 if ("onUpdateFinished" in aListener)
michael@0 522 aListener.onUpdateFinished(this);
michael@0 523 }
michael@0 524 };
michael@0 525
michael@0 526 AddonManagerPrivate.registerProvider(PluginProvider, [
michael@0 527 new AddonManagerPrivate.AddonType("plugin", URI_EXTENSION_STRINGS,
michael@0 528 STRING_TYPE_NAME,
michael@0 529 AddonManager.VIEW_TYPE_LIST, 6000,
michael@0 530 AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE)
michael@0 531 ]);

mercurial