2010-04-05 18:09:52 +00:00
|
|
|
/*
|
|
|
|
# ***** BEGIN LICENSE BLOCK *****
|
|
|
|
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
#
|
|
|
|
# The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
# 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
# the License. You may obtain a copy of the License at
|
|
|
|
# http://www.mozilla.org/MPL/
|
|
|
|
#
|
|
|
|
# Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
# for the specific language governing rights and limitations under the
|
|
|
|
# License.
|
|
|
|
#
|
|
|
|
# The Original Code is the Extension Manager.
|
|
|
|
#
|
|
|
|
# The Initial Developer of the Original Code is
|
|
|
|
# the Mozilla Foundation.
|
|
|
|
# Portions created by the Initial Developer are Copyright (C) 2010
|
|
|
|
# the Initial Developer. All Rights Reserved.
|
|
|
|
#
|
|
|
|
# Contributor(s):
|
|
|
|
# Dave Townsend <dtownsend@oxymoronical.com>
|
|
|
|
#
|
|
|
|
# Alternatively, the contents of this file may be used under the terms of
|
|
|
|
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
# in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
# of those above. If you wish to allow use of your version of this file only
|
|
|
|
# under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
# use your version of this file under the terms of the MPL, indicate your
|
|
|
|
# decision by deleting the provisions above and replace them with the notice
|
|
|
|
# and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
# the provisions above, a recipient may use your version of this file under
|
|
|
|
# the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
#
|
|
|
|
# ***** END LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
const Cc = Components.classes;
|
|
|
|
const Ci = Components.interfaces;
|
|
|
|
|
|
|
|
var EXPORTED_SYMBOLS = [];
|
|
|
|
|
|
|
|
Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
2010-04-26 17:48:27 +00:00
|
|
|
Components.utils.import("resource://gre/modules/Services.jsm");
|
2010-04-05 18:09:52 +00:00
|
|
|
|
2010-04-26 19:14:19 +00:00
|
|
|
["LOG", "WARN", "ERROR"].forEach(function(aName) {
|
|
|
|
this.__defineGetter__(aName, function() {
|
|
|
|
Components.utils.import("resource://gre/modules/AddonLogging.jsm");
|
2010-04-05 18:09:52 +00:00
|
|
|
|
2010-04-26 19:14:19 +00:00
|
|
|
LogManager.getLogger("addons.plugins", this);
|
|
|
|
return this[aName];
|
|
|
|
});
|
|
|
|
}, this);
|
2010-04-05 18:09:52 +00:00
|
|
|
|
2011-04-19 21:53:07 +00:00
|
|
|
function getIDHashForString(aStr) {
|
|
|
|
// return the two-digit hexadecimal code for a byte
|
|
|
|
function toHexString(charCode)
|
|
|
|
("0" + charCode.toString(16)).slice(-2);
|
|
|
|
|
|
|
|
let hasher = Cc["@mozilla.org/security/hash;1"].
|
|
|
|
createInstance(Ci.nsICryptoHash);
|
|
|
|
hasher.init(Ci.nsICryptoHash.MD5);
|
|
|
|
let stringStream = Cc["@mozilla.org/io/string-input-stream;1"].
|
|
|
|
createInstance(Ci.nsIStringInputStream);
|
|
|
|
stringStream.data = aStr ? aStr : "null";
|
|
|
|
hasher.updateFromStream(stringStream, -1);
|
|
|
|
|
|
|
|
// convert the binary hash data to a hex string.
|
|
|
|
let binary = hasher.finish(false);
|
|
|
|
let hash = [toHexString(binary.charCodeAt(i)) for (i in binary)].join("").toLowerCase();
|
|
|
|
return "{" + hash.substr(0, 8) + "-" +
|
|
|
|
hash.substr(8, 4) + "-" +
|
|
|
|
hash.substr(12, 4) + "-" +
|
|
|
|
hash.substr(16, 4) + "-" +
|
|
|
|
hash.substr(20) + "}";
|
|
|
|
}
|
|
|
|
|
2010-04-05 18:09:52 +00:00
|
|
|
var PluginProvider = {
|
|
|
|
// A dictionary mapping IDs to names and descriptions
|
|
|
|
plugins: null,
|
|
|
|
|
2011-04-19 21:53:07 +00:00
|
|
|
/**
|
|
|
|
* Called when the application is shutting down. Only necessary for tests
|
|
|
|
* to be able to simulate a shutdown.
|
|
|
|
*/
|
|
|
|
shutdown: function PL_shutdown() {
|
|
|
|
this.plugins = null;
|
|
|
|
},
|
|
|
|
|
2010-04-05 18:09:52 +00:00
|
|
|
/**
|
|
|
|
* Called to get an Addon with a particular ID.
|
2010-04-28 16:42:07 +00:00
|
|
|
*
|
|
|
|
* @param aId
|
|
|
|
* The ID of the add-on to retrieve
|
|
|
|
* @param aCallback
|
|
|
|
* A callback to pass the Addon to
|
2010-04-05 18:09:52 +00:00
|
|
|
*/
|
2010-04-26 17:49:19 +00:00
|
|
|
getAddonByID: function PL_getAddon(aId, aCallback) {
|
2010-04-05 18:09:52 +00:00
|
|
|
if (!this.plugins)
|
|
|
|
this.buildPluginList();
|
|
|
|
|
2010-04-28 16:42:07 +00:00
|
|
|
if (aId in this.plugins) {
|
|
|
|
let name = this.plugins[aId].name;
|
|
|
|
let description = this.plugins[aId].description;
|
2011-04-19 21:53:07 +00:00
|
|
|
let tags = this.plugins[aId].tags;
|
2010-04-05 18:09:52 +00:00
|
|
|
|
2011-04-19 21:53:07 +00:00
|
|
|
aCallback(new PluginWrapper(aId, name, description, tags));
|
2010-04-05 18:09:52 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-04-28 16:42:07 +00:00
|
|
|
aCallback(null);
|
2010-04-05 18:09:52 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called to get Addons of a particular type.
|
2010-04-28 16:42:07 +00:00
|
|
|
*
|
|
|
|
* @param aTypes
|
|
|
|
* An array of types to fetch. Can be null to get all types.
|
|
|
|
* @param callback
|
|
|
|
* A callback to pass an array of Addons to
|
2010-04-05 18:09:52 +00:00
|
|
|
*/
|
2010-04-28 16:42:07 +00:00
|
|
|
getAddonsByTypes: function PL_getAddonsByTypes(aTypes, aCallback) {
|
|
|
|
if (aTypes && aTypes.indexOf("plugin") < 0) {
|
|
|
|
aCallback([]);
|
2010-04-05 18:09:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.plugins)
|
|
|
|
this.buildPluginList();
|
|
|
|
|
|
|
|
let results = [];
|
|
|
|
|
|
|
|
for (let id in this.plugins) {
|
2010-04-26 17:49:19 +00:00
|
|
|
this.getAddonByID(id, function(aAddon) {
|
2010-04-28 16:42:07 +00:00
|
|
|
results.push(aAddon);
|
2010-04-05 18:09:52 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2010-04-28 16:42:07 +00:00
|
|
|
aCallback(results);
|
2010-04-05 18:09:52 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called to get Addons that have pending operations.
|
2010-04-28 16:42:07 +00:00
|
|
|
*
|
|
|
|
* @param aTypes
|
|
|
|
* An array of types to fetch. Can be null to get all types
|
|
|
|
* @param aCallback
|
|
|
|
* A callback to pass an array of Addons to
|
2010-04-05 18:09:52 +00:00
|
|
|
*/
|
2010-04-26 17:49:19 +00:00
|
|
|
getAddonsWithOperationsByTypes: function PL_getAddonsWithOperationsByTypes(aTypes, aCallback) {
|
2010-04-28 16:42:07 +00:00
|
|
|
aCallback([]);
|
2010-04-05 18:09:52 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called to get the current AddonInstalls, optionally restricting by type.
|
2010-04-28 16:42:07 +00:00
|
|
|
*
|
|
|
|
* @param aTypes
|
|
|
|
* An array of types or null to get all types
|
|
|
|
* @param aCallback
|
|
|
|
* A callback to pass the array of AddonInstalls to
|
2010-04-05 18:09:52 +00:00
|
|
|
*/
|
2010-04-26 17:49:19 +00:00
|
|
|
getInstallsByTypes: function PL_getInstallsByTypes(aTypes, aCallback) {
|
2010-04-28 16:42:07 +00:00
|
|
|
aCallback([]);
|
2010-04-05 18:09:52 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
buildPluginList: function PL_buildPluginList() {
|
|
|
|
let tags = Cc["@mozilla.org/plugin/host;1"].
|
|
|
|
getService(Ci.nsIPluginHost).
|
|
|
|
getPluginTags({});
|
|
|
|
|
|
|
|
this.plugins = {};
|
2011-04-19 21:53:07 +00:00
|
|
|
let plugins = {};
|
2010-04-28 16:42:07 +00:00
|
|
|
tags.forEach(function(aTag) {
|
2011-04-19 21:53:07 +00:00
|
|
|
if (!(aTag.name in plugins))
|
|
|
|
plugins[aTag.name] = {};
|
|
|
|
if (!(aTag.description in plugins[aTag.name])) {
|
|
|
|
let plugin = {
|
2010-04-28 16:42:07 +00:00
|
|
|
name: aTag.name,
|
2011-04-19 21:53:07 +00:00
|
|
|
description: aTag.description,
|
|
|
|
tags: [aTag]
|
2010-04-05 18:09:52 +00:00
|
|
|
};
|
2011-04-19 21:53:07 +00:00
|
|
|
|
|
|
|
let id = getIDHashForString(aTag.name + aTag.description);
|
|
|
|
|
|
|
|
plugins[aTag.name][aTag.description] = plugin;
|
|
|
|
this.plugins[id] = plugin;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
plugins[aTag.name][aTag.description].tags.push(aTag);
|
2010-04-05 18:09:52 +00:00
|
|
|
}
|
|
|
|
}, this);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The PluginWrapper wraps a set of nsIPluginTags to provide the data visible to
|
|
|
|
* public callers through the API.
|
|
|
|
*/
|
2010-04-28 16:42:07 +00:00
|
|
|
function PluginWrapper(aId, aName, aDescription, aTags) {
|
|
|
|
let safedesc = aDescription.replace(/<\/?[a-z][^>]*>/gi, " ");
|
2010-04-05 18:09:52 +00:00
|
|
|
let homepageURL = null;
|
2010-04-28 16:42:07 +00:00
|
|
|
if (/<A\s+HREF=[^>]*>/i.test(aDescription))
|
|
|
|
homepageURL = /<A\s+HREF=["']?([^>"'\s]*)/i.exec(aDescription)[1];
|
2010-04-05 18:09:52 +00:00
|
|
|
|
2010-04-28 16:42:07 +00:00
|
|
|
this.__defineGetter__("id", function() aId);
|
2010-04-05 18:09:52 +00:00
|
|
|
this.__defineGetter__("type", function() "plugin");
|
2010-04-28 16:42:07 +00:00
|
|
|
this.__defineGetter__("name", function() aName);
|
2010-08-24 01:04:06 +00:00
|
|
|
this.__defineGetter__("creator", function() null);
|
2010-04-05 18:09:52 +00:00
|
|
|
this.__defineGetter__("description", function() safedesc);
|
2010-04-28 16:42:07 +00:00
|
|
|
this.__defineGetter__("version", function() aTags[0].version);
|
2010-04-05 18:09:52 +00:00
|
|
|
this.__defineGetter__("homepageURL", function() homepageURL);
|
|
|
|
|
2010-04-28 16:42:07 +00:00
|
|
|
this.__defineGetter__("isActive", function() !aTags[0].blocklisted && !aTags[0].disabled);
|
|
|
|
this.__defineGetter__("appDisabled", function() aTags[0].blocklisted);
|
|
|
|
this.__defineGetter__("userDisabled", function() aTags[0].disabled);
|
|
|
|
this.__defineSetter__("userDisabled", function(aVal) {
|
|
|
|
if (aTags[0].disabled == aVal)
|
2010-04-05 18:09:52 +00:00
|
|
|
return;
|
|
|
|
|
2010-04-28 16:42:07 +00:00
|
|
|
aTags.forEach(function(aTag) {
|
|
|
|
aTag.disabled = aVal;
|
2010-04-05 18:09:52 +00:00
|
|
|
});
|
2010-04-28 16:42:07 +00:00
|
|
|
AddonManagerPrivate.callAddonListeners(aVal ? "onDisabling" : "onEnabling", this, false);
|
|
|
|
AddonManagerPrivate.callAddonListeners(aVal ? "onDisabled" : "onEnabled", this);
|
|
|
|
return aVal;
|
2010-04-05 18:09:52 +00:00
|
|
|
});
|
|
|
|
|
2010-04-26 17:48:27 +00:00
|
|
|
this.__defineGetter__("blocklistState", function() {
|
|
|
|
let bs = Cc["@mozilla.org/extensions/blocklist;1"].
|
|
|
|
getService(Ci.nsIBlocklistService);
|
|
|
|
return bs.getPluginBlocklistState(aTags[0]);
|
|
|
|
});
|
|
|
|
|
2010-07-02 14:48:41 +00:00
|
|
|
this.__defineGetter__("size", function() {
|
|
|
|
function getDirectorySize(aFile) {
|
|
|
|
let size = 0;
|
|
|
|
let entries = aFile.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
|
|
|
|
let entry;
|
|
|
|
while (entry = entries.nextFile) {
|
|
|
|
if (entry.isSymlink() || !entry.isDirectory())
|
|
|
|
size += entry.fileSize;
|
|
|
|
else
|
|
|
|
size += getDirectorySize(entry);
|
|
|
|
}
|
|
|
|
entries.close();
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
let size = 0;
|
|
|
|
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
|
|
|
aTags.forEach(function(aTag) {
|
|
|
|
file.initWithPath(aTag.fullpath);
|
|
|
|
if (file.isDirectory())
|
|
|
|
size += getDirectorySize(file);
|
|
|
|
else
|
|
|
|
size += file.fileSize;
|
|
|
|
});
|
|
|
|
return size;
|
|
|
|
});
|
|
|
|
|
2010-06-29 18:08:44 +00:00
|
|
|
this.__defineGetter__("installDate", function() {
|
|
|
|
let date = 0;
|
|
|
|
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
|
|
|
aTags.forEach(function(aTag) {
|
|
|
|
file.initWithPath(aTag.fullpath);
|
|
|
|
date = Math.max(date, file.lastModifiedTime);
|
|
|
|
});
|
|
|
|
return new Date(date);
|
|
|
|
});
|
|
|
|
|
2010-04-26 17:48:27 +00:00
|
|
|
this.__defineGetter__("scope", function() {
|
|
|
|
let path = aTags[0].fullpath;
|
|
|
|
// Plugins inside the application directory are in the application scope
|
|
|
|
let dir = Services.dirsvc.get("APlugns", Ci.nsILocalFile);
|
|
|
|
if (path.substring(0, dir.path.length) == dir.path)
|
|
|
|
return AddonManager.SCOPE_APPLICATION;
|
|
|
|
|
|
|
|
// Plugins inside the profile directory are in the profile scope
|
|
|
|
dir = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
|
|
|
|
if (path.substring(0, dir.path.length) == dir.path)
|
|
|
|
return AddonManager.SCOPE_PROFILE;
|
|
|
|
|
|
|
|
// Plugins anywhere else in the user's home are in the user scope
|
|
|
|
dir = Services.dirsvc.get("Home", Ci.nsILocalFile);
|
|
|
|
if (path.substring(0, dir.path.length) == dir.path)
|
|
|
|
return AddonManager.SCOPE_USER;
|
|
|
|
|
|
|
|
// Any other locations are system scope
|
|
|
|
return AddonManager.SCOPE_SYSTEM;
|
|
|
|
});
|
|
|
|
|
2010-04-05 18:09:52 +00:00
|
|
|
this.__defineGetter__("pendingOperations", function() {
|
2010-07-26 17:34:06 +00:00
|
|
|
return AddonManager.PENDING_NONE;
|
|
|
|
});
|
|
|
|
|
|
|
|
this.__defineGetter__("operationsRequiringRestart", function() {
|
|
|
|
return AddonManager.OP_NEEDS_RESTART_NONE;
|
2010-04-05 18:09:52 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
this.__defineGetter__("permissions", function() {
|
|
|
|
let permissions = 0;
|
|
|
|
if (!this.appDisabled) {
|
|
|
|
if (this.userDisabled)
|
|
|
|
permissions |= AddonManager.PERM_CAN_ENABLE;
|
|
|
|
else
|
|
|
|
permissions |= AddonManager.PERM_CAN_DISABLE;
|
|
|
|
}
|
|
|
|
return permissions;
|
|
|
|
});
|
2010-04-26 17:48:27 +00:00
|
|
|
}
|
2010-04-05 18:09:52 +00:00
|
|
|
|
2010-04-26 17:48:27 +00:00
|
|
|
PluginWrapper.prototype = {
|
2010-06-29 18:08:44 +00:00
|
|
|
get updateDate() {
|
|
|
|
return this.installDate;
|
|
|
|
},
|
|
|
|
|
2010-04-26 17:48:27 +00:00
|
|
|
get isCompatible() {
|
|
|
|
return true;
|
|
|
|
},
|
2010-04-05 18:09:52 +00:00
|
|
|
|
2010-07-01 18:37:32 +00:00
|
|
|
get isPlatformCompatible() {
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
2010-04-26 17:48:27 +00:00
|
|
|
get providesUpdatesSecurely() {
|
|
|
|
return true;
|
|
|
|
},
|
2010-04-05 18:09:52 +00:00
|
|
|
|
2010-04-26 17:48:27 +00:00
|
|
|
isCompatibleWith: function(aAppVerison, aPlatformVersion) {
|
|
|
|
return true;
|
2010-04-05 18:09:52 +00:00
|
|
|
},
|
|
|
|
|
2010-04-26 17:48:27 +00:00
|
|
|
findUpdates: function(aListener, aReason, aAppVersion, aPlatformVersion) {
|
|
|
|
if ("onNoCompatibilityUpdateAvailable" in aListener)
|
|
|
|
aListener.onNoCompatibilityUpdateAvailable(this);
|
|
|
|
if ("onNoUpdateAvailable" in aListener)
|
|
|
|
aListener.onNoUpdateAvailable(this);
|
|
|
|
if ("onUpdateFinished" in aListener)
|
|
|
|
aListener.onUpdateFinished(this);
|
2010-04-05 18:09:52 +00:00
|
|
|
}
|
2010-04-26 17:48:27 +00:00
|
|
|
};
|
2010-04-05 18:09:52 +00:00
|
|
|
|
|
|
|
AddonManagerPrivate.registerProvider(PluginProvider);
|