Themes werden nicht installiert,es kommt folgende Fehlermeldung:
Firefox konnte das Add-on von folgender Adresse nicht installieren:
http://releases.mozilla.org/pub/mozilla.or…x-1.8.49-fx.jar
Grund: Bei der Installation ist ein unbekannter Fehler aufgetreten.
Schauen Sie in der Fehlerkonsole für weitere Informationen nach.
-203
Dies ist der Fehlercode:
/**
* Write the Extensions List
*/
_updateExtensionsManifest: function() {
// When an operation is performed that requires a component re-registration
// (extension enabled/disabled, installed, uninstalled), we must write the
// set of paths where extensions live so that the startup system can determine
// where additional components, preferences, chrome manifests etc live.
//
// To do this we obtain a list of active extensions and themes and write
// these to the extensions.ini file in the profile directory.
var validExtensions = this._getActiveItems(Ci.nsIUpdateItem.TYPE_ANY -
Ci.nsIUpdateItem.TYPE_THEME);
var validThemes = this._getActiveItems(Ci.nsIUpdateItem.TYPE_THEME);
var extensionsLocationsFile = getFile(KEY_PROFILEDIR, [FILE_EXTENSION_MANIFEST]);
var fos = openSafeFileOutputStream(extensionsLocationsFile);
var enabledItems = [];
var extensionSectionHeader = "[ExtensionDirs]\r\n";
fos.write(extensionSectionHeader, extensionSectionHeader.length);
for (var i = 0; i < validExtensions.length; ++i) {
var e = validExtensions[i];
var itemLocation = e.location.getItemLocation(e.id).QueryInterface(Ci.nsILocalFile);
var descriptor = getAbsoluteDescriptor(itemLocation);
var line = "Extension" + i + "=" + descriptor + "\r\n";
fos.write(line, line.length);
enabledItems.push(e.id + ":" + e.version);
}
var themeSectionHeader = "[ThemeDirs]\r\n";
fos.write(themeSectionHeader, themeSectionHeader.length);
for (i = 0; i < validThemes.length; ++i) {
var e = validThemes[i];
var itemLocation = e.location.getItemLocation(e.id).QueryInterface(Ci.nsILocalFile);
var descriptor = getAbsoluteDescriptor(itemLocation);
var line = "Extension" + i + "=" + descriptor + "\r\n";
fos.write(line, line.length);
enabledItems.push(e.id + ":" + e.version);
}
closeSafeFileOutputStream(fos);
// Cache the enabled list for annotating the crash report subsequently
gPref.setCharPref(PREF_EM_ENABLED_ITEMS, enabledItems.join(","));
},
/**
* Say whether or not the Extension List has changed (and thus whether or not
* the system will have to restart the next time it is started).
* Param val
* true if the Extension List has changed, false otherwise.
* @returns |val|
*/
set _extensionListChanged(val) {
// When an extension has an operation perform on it (e.g. install, upgrade,
// disable, etc.) we are responsible for creating the .autoreg file and
// nsAppRunner is responsible for removing it on restart. At some point it
// may make sense to be able to cancel a registration but for now we only
// create the file.
try {
var autoregFile = getFile(KEY_PROFILEDIR, [FILE_AUTOREG]);
if (val && !autoregFile.exists())
autoregFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
}
catch (e) {
}
return val;
},
/**
* Gathers data about an item specified by the supplied Install Manifest
* and determines whether or not it can be installed as-is. It makes this
* determination by validating the item's GUID, Version, and determining
* if it is compatible with this application.
* Param installManifest
* A nsIRDFDataSource representing the Install Manifest of the
* item to be installed.
* @return A JS Object with the following properties:
* "id" The GUID of the Item being installed.
* "version" The Version string of the Item being installed.
* "name" The Name of the Item being installed.
* "type" The nsIUpdateItem type of the Item being installed.
* "targetApps" An array of TargetApplication Info Objects
* with "id", "minVersion" and "maxVersion" properties,
* representing applications targeted by this item.
* "error" The result code:
* INSTALLERROR_SUCCESS
* no error, item can be installed
* INSTALLERROR_INVALID_GUID
* error, GUID is not well-formed
* INSTALLERROR_INVALID_VERSION
* error, Version is not well-formed
* INSTALLERROR_INCOMPATIBLE_VERSION
* error, item is not compatible with this version
* of the application.
* INSTALLERROR_INCOMPATIBLE_PLATFORM
* error, item is not compatible with the operating
* system or ABI the application was built for.
* INSTALLERROR_INSECURE_UPDATE
* error, item has no secure method of providing updates
* INSTALLERROR_BLOCKLISTED
* error, item is blocklisted
*/
_getInstallData: function(installManifest) {
var installData = { id : "",
version : "",
name : "",
type : 0,
error : INSTALLERROR_SUCCESS,
targetApps : [],
updateURL : "",
updateKey : "",
currentApp : null };
// Fetch properties from the Install Manifest
installData.id = getManifestProperty(installManifest, "id");
installData.version = getManifestProperty(installManifest, "version");
installData.name = getManifestProperty(installManifest, "name");
installData.type = getAddonTypeFromInstallManifest(installManifest);
installData.updateURL= getManifestProperty(installManifest, "updateURL");
installData.updateKey= getManifestProperty(installManifest, "updateKey");
/**
* Reads a property off a Target Application resource
* Param resource
* The RDF Resource for a Target Application
* Param property
* The property (less EM_NS) to read
* @returns The string literal value of the property.
*/
function readTAProperty(resource, property) {
return stringData(installManifest.GetTarget(resource, EM_R(property), true));
}
var targetApps = installManifest.GetTargets(gInstallManifestRoot,
EM_R("targetApplication"),
true);
while (targetApps.hasMoreElements()) {
var targetApp = targetApps.getNext();
if (targetApp instanceof Ci.nsIRDFResource) {
try {
var data = { id : readTAProperty(targetApp, "id"),
minVersion: readTAProperty(targetApp, "minVersion"),
maxVersion: readTAProperty(targetApp, "maxVersion") };
installData.targetApps.push(data);
if ((data.id == gApp.ID)
(data.id == TOOLKIT_ID) && !installData.currentApp)
installData.currentApp = data;
}
catch (e) {
continue;
}
}
}
// If the item specifies one or more target platforms, make sure our OS/ABI
// combination is in the list - otherwise, refuse to install the item.
var targetPlatforms = null;
try {
targetPlatforms = installManifest.GetTargets(gInstallManifestRoot,
EM_R("targetPlatform"),
true);
} catch(e) {
// No targetPlatform nodes, continue.
}
if (targetPlatforms != null && targetPlatforms.hasMoreElements()) {
var foundMatchingOS = false;
var foundMatchingOSAndABI = false;
var requireABICompatibility = false;
while (targetPlatforms.hasMoreElements()) {
var targetPlatform = stringData(targetPlatforms.getNext());
var os = targetPlatform.split("_")[0];
var index = targetPlatform.indexOf("_");
var abi = index != -1 ? targetPlatform.substr(index + 1) : null;
if (os == gOSTarget) {
foundMatchingOS = true;
// The presence of any ABI part after our OS means ABI is important.
if (abi != null) {
requireABICompatibility = true;
// If we don't know our ABI, we can't be compatible
if (abi == gXPCOMABI && abi != UNKNOWN_XPCOM_ABI) {
foundMatchingOSAndABI = true;
break;
}
}
}
}
if (!foundMatchingOS (requireABICompatibility && !foundMatchingOSAndABI)) {
installData.error = INSTALLERROR_INCOMPATIBLE_PLATFORM;
return installData;
}
}
// Validate the Item ID
if (!gIDTest.test(installData.id)) {
installData.error = INSTALLERROR_INVALID_GUID;
return installData;
}
// Check that the add-on provides a secure update method.
if (gCheckUpdateSecurity &&
installData.updateURL &&
installData.updateURL.substring(0, 6) != "https:" &&
!installData.updateKey) {
installData.error = INSTALLERROR_INSECURE_UPDATE;
return installData;
}
// Check that the target application range allows compatibility with the app
if (gCheckCompatibility &&
!this.datasource.isCompatible(installManifest, gInstallManifestRoot, undefined)) {
installData.error = INSTALLERROR_INCOMPATIBLE_VERSION;
return installData;
}
// Check if the item is blocklisted.
if (!gBlocklist)
gBlocklist = Cc["@http://mozilla.org/extensions/blocklist;1"].
getService(Ci.nsIBlocklistService);
if (gBlocklist.isAddonBlocklisted(installData.id, installData.version,
null, null))
installData.error = INSTALLERROR_BLOCKLISTED;
return installData;
},
/**
* Installs an item from a XPI/JAR file.
* This is the main entry point into the Install system from outside code
* (e.g. XPInstall).
* Param aXPIFile
* The file to install from.
* Param aInstallLocationKey
* The name of the Install Location where this item should be
* installed.
*/
installItemFromFile: function(xpiFile, installLocationKey) {
this.installItemFromFileInternal(xpiFile, installLocationKey, null);
// If there are no compatibility checks running and no downloads in
// progress then the install operations are complete.
if (this._compatibilityCheckCount == 0 && this._transactions.length == 0) {
for (var i = 0; i < this._installListeners.length; ++i)
this._installListeners[i].onInstallsCompleted();
}
},
/**
* Installs an item from a XPI/JAR file.
* Param aXPIFile
* The file to install from.
* Param aInstallLocationKey
* The name of the Install Location where this item should be
* installed.
* Param aInstallManifest
* An updated Install Manifest from the Version Update check.
* Can be null when invoked from callers other than the Version
* Update check.
*/
installItemFromFileInternal: function(aXPIFile, aInstallLocationKey, aInstallManifest) {
var em = this;
/**
* Gets the Install Location for an Item.
* Param itemID
* The GUID of the item to find an Install Location for.
* @return An object implementing nsIInstallLocation which represents the
* location where the specified item should be installed.
* This can be:
* 1. an object that corresponds to the location key supplied to
* |installItemFromFileInternal|,
* 2. the default install location (the App Profile Extensions Folder)
* if no location key was supplied, or the location key supplied
* was not in the set of registered locations
* 3. null, if the location selected by 1 or 2 above does not support
* installs from XPI/JAR files, or that location is not writable
* with the current access privileges.
*/
function getInstallLocation(itemID) {
// Here I use "upgrade" to mean "install a different version of an item".
var installLocation = em.getInstallLocation(itemID);
if (!installLocation) {
// This is not an "upgrade", since we don't have any location data for the
// extension ID specified - that is, it's not in our database.
// Caller supplied a key to a registered location, use that location
// for the installation
installLocation = InstallLocations.get(aInstallLocationKey);
if (installLocation) {
// If the specified location does not have a common metadata location
// (e.g. extensions have no common root, or other location specified
// by the location implementation) - e.g. for a Registry Key enumeration
// location - we cannot install or upgrade using a XPI file, probably
// because these application types will be handling upgrading themselves.
// Just bail.
if (!installLocation.location) {
LOG("Install Location \"" + installLocation.name + "\" does not support " +
"installation of items from XPI/JAR files. You must manage " +
"installation and update of these items yourself.");
installLocation = null;
}
}
else {
// In the absence of a preferred install location, just default to
// the App-Profile
installLocation = InstallLocations.get(KEY_APP_PROFILE);
}
}
else {
// This is an "upgrade", but not through the Update System, because the
// Update code will not let an extension with an incompatible target
// app version range through to this point. This is an "upgrade" in the
// sense that the user found a different version of an installed extension
// and installed it through the web interface, so we have metadata.
// If the location is different, return the preferred location rather than
// the location of the currently installed version, because we may be in
// the situation where an item is being installed into the global app
// dir when there's a version in the profile dir.
if (installLocation.name != aInstallLocationKey)
installLocation = InstallLocations.get(aInstallLocationKey);
}
if (!installLocation.canAccess) {
LOG("Install Location\"" + installLocation.name + "\" cannot be written " +
"to with your access privileges. Installation will not proceed.");
installLocation = null;
}
return installLocation;
}
/**
* Stages a XPI file in the default item location specified by other
* applications when they registered with XulRunner if the item's
* install manifest specified compatibility with them.
*/
function stageXPIForOtherApps(xpiFile, installData) {
for (var i = 0; i < installData.targetApps.length; ++i) {
var targetApp = installData.targetApps[i];
if (targetApp.id != gApp.ID && targetApp.id != TOOLKIT_ID) {
/* XXXben uncomment when this works!
var settingsThingy = Cc[].
getService(Ci.nsIXULRunnerSettingsThingy);
try {
var appPrefix = "SOFTWARE\\Mozilla\\XULRunner\\Applications\\";
var branch = settingsThingy.getBranch(appPrefix + targetApp.id);
var path = branch.getProperty("ExtensionsLocation");
var destination = Cc["@http://mozilla.org/file/local;1"].
createInstance(Ci.nsILocalFile);
destination.initWithPath(path);
xpiFile.copyTo(file, xpiFile.leafName);
}
catch (e) {
}
*/
}
}
}
/**
* Extracts and then starts the install for extensions / themes contained
* within a xpi.
*/
function installMultiXPI(xpiFile, installData) {
var fileURL = getURIFromFile(xpiFile).QueryInterface(Ci.nsIURL);
if (fileURL.fileExtension.toLowerCase() != "xpi") {
LOG("Invalid File Extension: Item: \"" + fileURL.fileName + "\" has an " +
"invalid file extension. Only xpi file extensions are allowed for " +
"multiple item packages.");
var bundle = BundleManager.getBundle(URI_EXTENSIONS_PROPERTIES);
showMessage("invalidFileExtTitle", [],
"invalidFileExtMessage", [installData.name,
fileURL.fileExtension,
bundle.GetStringFromName("type-" + installData.type)]);
return;
}
try {
var zipReader = getZipReaderForFile(xpiFile);
}
catch (e) {
LOG("installMultiXPI: failed to open xpi file: " + xpiFile.path);
throw e;
}
var searchForEntries = ["*.xpi", "*.jar"];
var files = [];
for (var i = 0; i < searchForEntries.length; ++i) {
var entries = zipReader.findEntries(searchForEntries[i]);
while (entries.hasMore()) {
var entryName = entries.getNext();
var target = getFile(KEY_TEMPDIR, [entryName]);
try {
target.createUnique(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
}
catch (e) {
LOG("installMultiXPI: failed to create target file for extraction " +
" file = " + target.path + ", exception = " + e + "\n");
}
zipReader.extract(entryName, target);
files.push(target);
}
}
zipReader.close();
if (files.length == 0) {
LOG("Multiple Item Package: Item: \"" + fileURL.fileName + "\" does " +
"not contain a valid package to install.");
var bundle = BundleManager.getBundle(URI_EXTENSIONS_PROPERTIES);
showMessage("missingPackageFilesTitle",
[bundle.GetStringFromName("type-" + installData.type)],
"missingPackageFilesMessage", [installData.name,
bundle.GetStringFromName("type-" + installData.type)]);
return;
}
for (i = 0; i < files.length; ++i) {
em.installItemFromFileInternal(files[i], aInstallLocationKey, null);
files[i].remove(false);
}
}
/**
* An observer for the Extension Update System.
* @constructor
*/
function IncompatibleObserver() {}
IncompatibleObserver.prototype = {
_xpi: null,
_installManifest: null,
/**
* Ask the Extension Update System if there are any version updates for
* this item that will allow it to be compatible with this version of
* the Application.
* Param item
* An nsIUpdateItem representing the item being installed.
* Param installManifest
* The Install Manifest datasource for the item.
* Param xpiFile
* The staged source XPI file that contains the item. Cleaned
* up by this process.
* Param installRDF
* The install.rdf file that was extracted from the xpi.
*/
checkForUpdates: function(item, installManifest, xpiFile) {
this._xpi = xpiFile;
this._installManifest = installManifest;
for (var i = 0; i < em._installListeners.length; ++i)
em._installListeners[i].onCompatibilityCheckStarted(item);
em._compatibilityCheckCount++;
em.update([item], 1, Ci.nsIExtensionManager.UPDATE_CHECK_COMPATIBILITY, this);
},
/**
* See nsIExtensionManager.idl
*/
onUpdateStarted: function() {
LOG("Phone Home Listener: Update Started");
},
/**
* See nsIExtensionManager.idl
*/
onUpdateEnded: function() {
LOG("Phone Home Listener: Update Ended");
},
/**
* See nsIExtensionManager.idl
*/
onAddonUpdateStarted: function(addon) {
if (!addon)
throw Cr.NS_ERROR_INVALID_ARG;
LOG("Phone Home Listener: Update For " + addon.id + " started");
em.datasource.addIncompatibleUpdateItem(addon.name, this._xpi.path,
addon.type, addon.version);
},
/**
* See nsIExtensionManager.idl
*/
onAddonUpdateEnded: function(addon, status) {
if (!addon)
throw Cr.NS_ERROR_INVALID_ARG;
LOG("Phone Home Listener: Update For " + addon.id + " ended, status = " + status);
em.datasource.removeDownload(this._xpi.path);
LOG("Version Check Phone Home Completed");
for (var i = 0; i < em._installListeners.length; ++i)
em._installListeners[i].onCompatibilityCheckEnded(addon, status);
// Only compatibility updates (e.g. STATUS_VERSIONINFO) are currently
// supported
if (status == Ci.nsIAddonUpdateCheckListener.STATUS_VERSIONINFO) {
em.datasource.setTargetApplicationInfo(addon.id,
addon.targetAppID,
addon.minAppVersion,
addon.maxAppVersion,
this._installManifest);
// Try and install again, but use the updated compatibility DB.
// This will send out an apropriate onInstallEnded notification for us.
em.installItemFromFileInternal(this._xpi, aInstallLocationKey,
this._installManifest);
// Add the updated compatibility info to the datasource if done
if (StartupCache.entries[aInstallLocationKey][addon.id].op == OP_NONE) {
em.datasource.setTargetApplicationInfo(addon.id,
addon.targetAppID,
addon.minAppVersion,
addon.maxAppVersion,
null);
}
else { // needs a restart
// Add updatedMinVersion and updatedMaxVersion so it can be used
// to update the datasource during the installation or upgrade.
em.datasource.setUpdatedTargetAppInfo(addon.id,
addon.targetAppID,
addon.minAppVersion,
addon.maxAppVersion,
null);
}
}
else {
em.datasource.removeDownload(this._xpi.path);
showIncompatibleError(installData);
LOG("Add-on " + addon.id + " is incompatible with " +
BundleManager.appName + " " + gApp.version + ", Toolkit " +
gApp.platformVersion + ". Remote compatibility check did not " +
"resolve this.");
for (var i = 0; i < em._installListeners.length; ++i)
em._installListeners[i].onInstallEnded(addon, INSTALLERROR_INCOMPATIBLE_VERSION);
// We are responsible for cleaning up this file!
InstallLocations.get(aInstallLocationKey).removeFile(this._xpi);
}
em._compatibilityCheckCount--;
// If there are no more compatibility checks running and no downloads in
// progress then the install operations are complete.
if (em._compatibilityCheckCount == 0 && em._transactions.length == 0) {
for (var i = 0; i < em._installListeners.length; ++i)
em._installListeners[i].onInstallsCompleted();
}
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAddonUpdateCheckListener])
}
var shouldPhoneHomeIfNecessary = false;
if (!aInstallManifest) {
// If we were not called with an Install Manifest, we were called from
// some other path than the Phone Home system, so we do want to phone
// home if the version is incompatible. As this is the first point in the
// install process we must notify observers here.
var addon = makeItem(getURIFromFile(aXPIFile).spec, "",
aInstallLocationKey, "", "", "",
getURIFromFile(aXPIFile).spec,
"", "", "", "", 0, gApp.id);
for (var i = 0; i < this._installListeners.length; ++i)
this._installListeners[i].onInstallStarted(addon);
shouldPhoneHomeIfNecessary = true;
var installManifest = null;
var installManifestFile = extractRDFFileToTempDir(aXPIFile,
FILE_INSTALL_MANIFEST,
true);
if (installManifestFile.exists()) {
installManifest = getInstallManifest(installManifestFile);
installManifestFile.remove(false);
}
if (!installManifest) {
LOG("The Install Manifest supplied by this item is not well-formed. " +
"Installation will not proceed.");
for (var i = 0; i < this._installListeners.length; ++i)
this._installListeners[i].onInstallEnded(addon, INSTALLERROR_INVALID_MANIFEST);
return;
}
}
else
installManifest = aInstallManifest;
var installData = this._getInstallData(installManifest);
// Recreate the add-on item with the full detail from the install manifest
addon = makeItem(installData.id, installData.version,
aInstallLocationKey,
installData.currentApp ? installData.currentApp.minVersion : "",
installData.currentApp ? installData.currentApp.maxVersion : "",
installData.name,
getURIFromFile(aXPIFile).spec,
"", /* XPI Update Hash */
"", /* Icon URL */
installData.updateURL "",
installData.updateKey "",
installData.type,
installData.currentApp ? installData.currentApp.id : "");
switch (installData.error) {
case INSTALLERROR_INCOMPATIBLE_VERSION:
// Since the caller cleans up |aXPIFile|, and we're not yet sure whether or
// not we need it (we may need it if a remote version bump that makes it
// compatible is discovered by the call home) - so we must stage it for
// later ourselves.
if (shouldPhoneHomeIfNecessary && installData.currentApp) {
var installLocation = getInstallLocation(installData.id, aInstallLocationKey);
if (!installLocation)
return;
var stagedFile = installLocation.stageFile(aXPIFile, installData.id);
(new IncompatibleObserver(this)).checkForUpdates(addon, installManifest,
stagedFile);
// Return early to prevent deletion of the install manifest file.
return;
}
else {
// XXXben Look up XULRunnerSettingsThingy to see if there is a registered
// app that can handle this item, if so just stage and don't show
// this error!
showIncompatibleError(installData);
LOG("Add-on " + installData.id + " is incompatible with " +
BundleManager.appName + " " + gApp.version + ", Toolkit " +
gApp.platformVersion + ". Remote compatibility check was not performed.");
}
break;
case INSTALLERROR_SUCCESS:
// Installation of multiple extensions / themes contained within a single xpi.
if (installData.type == Ci.nsIUpdateItem.TYPE_MULTI_XPI) {
installMultiXPI(aXPIFile, installData);
break;
}
// Stage the extension's XPI so it can be extracted at the next restart.
var installLocation = getInstallLocation(installData.id, aInstallLocationKey);
if (!installLocation) {
// No cleanup of any of the staged XPI files should be required here,
// because this should only ever fail on the first recurse through
// this function, BEFORE staging takes place... technically speaking
// a location could become readonly during the phone home process,
// but that's an edge case I don't care about.
for (var i = 0; i < this._installListeners.length; ++i)
this._installListeners[i].onInstallEnded(addon, INSTALLERROR_RESTRICTED);
return;
}
// Stage a copy of the XPI/JAR file for our own evil purposes...
stagedFile = installLocation.stageFile(aXPIFile, installData.id);
var restartRequired = this.installRequiresRestart(installData.id,
installData.type);
// Determine which configuration function to use based on whether or not
// there is data about this item in our datasource already - if there is
// we want to upgrade, otherwise we install fresh.
var ds = this.datasource;
if (installData.id in ds.visibleItems && ds.visibleItems[installData.id]) {
// We enter this function if any data corresponding to an existing GUID
// is found, regardless of its Install Location. We need to check before
// "upgrading" an item that Install Location of the new item is of equal
// or higher priority than the old item, to make sure the datasource only
// ever tracks metadata for active items.
var oldInstallLocation = this.getInstallLocation(installData.id);
if (oldInstallLocation.priority >= installLocation.priority) {
this._upgradeItem(installManifest, installData.id, installLocation,
installData.type);
if (!restartRequired) {
this._finalizeUpgrade(installData.id, installLocation);
this._finalizeInstall(installData.id, stagedFile);
}
}
}
else {
this._configureForthcomingItem(installManifest, installData.id,
installLocation, installData.type);
if (!restartRequired) {
this._finalizeInstall(installData.id, stagedFile);
if (installData.type == Ci.nsIUpdateItem.TYPE_THEME) {
var internalName = this.datasource.getItemProperty(installData.id, "internalName");
if (gPref.getBoolPref(PREF_EM_DSS_ENABLED)) {
gPref.setCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN, internalName);
}
else {
gPref.setBoolPref(PREF_DSS_SWITCHPENDING, true);
gPref.setCharPref(PREF_DSS_SKIN_TO_SELECT, internalName);
}
}
}
}
this._updateManifests(restartRequired);
break;
case INSTALLERROR_INVALID_GUID:
LOG("Invalid GUID: Item has GUID: \"" + installData.id + "\"" +
" which is not well-formed.");
var bundle = BundleManager.getBundle(URI_EXTENSIONS_PROPERTIES);
showMessage("incompatibleTitle",
[bundle.GetStringFromName("type-" + installData.type)],
"invalidGUIDMessage", [installData.name, installData.id]);
break;
case INSTALLERROR_INVALID_VERSION:
LOG("Invalid Version: Item: \"" + installData.id + "\" has version " +
installData.version + " which is not well-formed.");
var bundle = BundleManager.getBundle(URI_EXTENSIONS_PROPERTIES);
showMessage("incompatibleTitle",
[bundle.GetStringFromName("type-" + installData.type)],
"invalidVersionMessage", [installData.name, installData.version]);
break;
case INSTALLERROR_INCOMPATIBLE_PLATFORM:
const osABI = gOSTarget + "_" + gXPCOMABI;
LOG("Incompatible Platform: Item: \"" + installData.id + "\" is not " +
"compatible with '" + osABI + "'.");
var bundle = BundleManager.getBundle(URI_EXTENSIONS_PROPERTIES);
showMessage("incompatibleTitle",
[bundle.GetStringFromName("type-" + installData.type)],
"incompatiblePlatformMessage",
[installData.name, BundleManager.appName, osABI]);
break;
case INSTALLERROR_BLOCKLISTED:
LOG("Blocklisted Item: Item: \"" + installData.id + "\" version " +
installData.version + " was not installed.");
showBlocklistMessage([installData], true);
break;
case INSTALLERROR_INSECURE_UPDATE:
LOG("No secure updates: Item: \"" + installData.id + "\" version " +
installData.version + " was not installed.");
var bundle = BundleManager.getBundle(URI_EXTENSIONS_PROPERTIES);
showMessage("incompatibleTitle",
[bundle.GetStringFromName("type-" + installData.type)],
"insecureUpdateMessage", [installData.name]);
break;
default:
break;
}
// Check to see if this item supports other applications and in that case
// stage the the XPI file in the location specified by those applications.
stageXPIForOtherApps(aXPIFile, installData);
// The install of this item is complete, notify observers
for (var i = 0; i < this._installListeners.length; ++i)
this._installListeners[i].onInstallEnded(addon, installData.error);
},
/**
* Whether or not this type's installation/uninstallation requires
* the application to be restarted.
* Param id
* The GUID of the item
* Param type
* The nsIUpdateItem type of the item
* @returns true if installation of an item of this type requires a
* restart.
*/
installRequiresRestart: function(id, type) {
switch (type) {
case Ci.nsIUpdateItem.TYPE_THEME:
var internalName = this.datasource.getItemProperty(id, "internalName");
var needsRestart = false;
if (gPref.prefHasUserValue(PREF_DSS_SKIN_TO_SELECT))
needsRestart = internalName == gPref.getCharPref(PREF_DSS_SKIN_TO_SELECT);
if (!needsRestart &&
gPref.prefHasUserValue(PREF_GENERAL_SKINS_SELECTEDSKIN))
needsRestart = internalName == gPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
return needsRestart;
}
return ((type & Ci.nsIUpdateItem.TYPE_ADDON) > 0);
},
/**
* Perform initial configuration on an item that has just or will be
* installed. This inserts the item into the appropriate container in the
* datasource, so that the application UI shows the item even if it will
* not actually be installed until the next restart.
* Param installManifest
* The Install Manifest datasource that describes this item.
* Param id
* The GUID of this item.
* Param installLocation
* The Install Location where this item is installed.
* Param type
* The nsIUpdateItem type of this item.
*/
_configureForthcomingItem: function(installManifest, id, installLocation, type) {
var ds = this.datasource;
ds.updateVisibleList(id, installLocation.name, false);
var name = null;
var localized = findClosestLocalizedResource(installManifest, gInstallManifestRoot);
if (localized)
name = installManifest.GetTarget(localized, EM_R("name"), true);
else
name = EM_L(getManifestProperty(installManifest, "name"));
var props = { name : name,
version : EM_L(getManifestProperty(installManifest, "version")),
newVersion : EM_L(getManifestProperty(installManifest, "version")),
installLocation : EM_L(installLocation.name),
type : EM_I(type),
availableUpdateURL : null,
availableUpdateHash : null,
availableUpdateVersion: null,
availableUpdateInfo : null };
ds.setItemProperties(id, props);
ds.updateProperty(id, "availableUpdateURL");
this._setOp(id, OP_NEEDS_INSTALL);
// Insert it into the child list NOW rather than later because:
// - extensions installed using the command line need to be a member
// of a container during the install phase for the code to be able
// to identify profile vs. global
// - extensions installed through the UI should show some kind of
// feedback to indicate their presence is forthcoming (i.e. they
// will be available after a restart).
ds.insertItemIntoContainer(id);
this._notifyAction(id, EM_ITEM_INSTALLED);
},
/**
* Perform configuration on an item that has just or will be upgraded.
* Param installManifest
* The Install Manifest datasource that describes this item.
* Param itemID
* The GUID of this item.
* Param installLocation
* The Install Location where this item is installed.
* Param type
* The nsIUpdateItem type of this item.
*/
_upgradeItem: function (installManifest, id, installLocation, type) {
// Don't change any props that would need to be reset if the install fails.
// They will be reset as appropriate by the upgrade/install process.
var ds = this.datasource;
ds.updateVisibleList(id, installLocation.name, false);
var props = { installLocation : EM_L(installLocation.name),
type : EM_I(type),
newVersion : EM_L(getManifestProperty(installManifest, "version")),
availableUpdateURL : null,
availableUpdateHash : null,
availableUpdateVersion : null,
availableUpdateInfo : null };
ds.setItemProperties(id, props);
ds.updateProperty(id, "availableUpdateURL");
this._setOp(id, OP_NEEDS_UPGRADE);
this._notifyAction(id, EM_ITEM_UPGRADED);
},
/**
* Completes an Extension's installation.
* Param id
* The GUID of the Extension to install.
* Param file
* The XPI/JAR file to install from. If this is null, we try to
* determine the stage file location from the ID.
*/
_finalizeInstall: function(id, file) {
var ds = this.datasource;
var type = ds.getItemProperty(id, "type");
if (id == 0 id == -1) {
ds.removeCorruptItem(id);
return;
}
var installLocation = this.getInstallLocation(id);
if (!installLocation) {
// If the install location is null, that means we've reached the finalize
// state without the item ever having metadata added for it, which implies
// bogus data in the Startup Cache. Clear the entries and don't do anything
// else.
var entries = StartupCache.findEntries(id);
for (var i = 0; i < entries.length; ++i) {
var location = InstallLocations.get(entries[i].location);
StartupCache.clearEntry(location, id);
PendingOperations.clearItem(OP_NEEDS_INSTALL, id);
}
return;
}
var itemLocation = installLocation.getItemLocation(id);
if (!file && "stageFile" in installLocation)
file = installLocation.getStageFile(id);
// If |file| is null or does not exist, the installer assumes the item is
// a dropped-in directory.
var installer = new Installer(this.datasource, id, installLocation, type);
installer.installFromFile(file);
// If the file was staged, we must clean it up ourselves, otherwise the
// EM caller is responsible for doing so (e.g. XPInstall)
if (file)
installLocation.removeFile(file);
// Clear the op flag from the Startup Cache and Pending Operations sets
StartupCache.put(installLocation, id, OP_NONE, true);
PendingOperations.clearItem(OP_NEEDS_INSTALL, id);
},
/**
* Removes an item's metadata in preparation for an upgrade-install.
* Param id
* The GUID of the item to uninstall.
* Param installLocation
* The nsIInstallLocation of the item
*/
_finalizeUpgrade: function(id, installLocation) {
// Retrieve the item properties *BEFORE* we clean the resource!
var ds = this.datasource;
var stagedFile = null;
if ("getStageFile" in installLocation)
stagedFile = installLocation.getStageFile(id);
if (stagedFile)
var installRDF = extractRDFFileToTempDir(stagedFile, FILE_INSTALL_MANIFEST, true);
else
installRDF = installLocation.getItemFile(id, FILE_INSTALL_MANIFEST);
if (installRDF.exists()) {
var installManifest = getInstallManifest(installRDF);
if (installManifest) {
var type = getAddonTypeFromInstallManifest(installManifest);
var userDisabled = ds.getItemProperty(id, "userDisabled") == "true";
// Clean the item resource
ds.removeItemMetadata(id);
// Now set up the properties on the item to mimic an item in its
// "initial state" for installation.
this._configureForthcomingItem(installManifest, id, installLocation,
type);
if (userDisabled)
ds.setItemProperty(id, EM_R("userDisabled"), EM_L("true"));
}
if (stagedFile)
installRDF.remove(false);
}
// Clear the op flag from the Pending Operations set. Do NOT clear op flag in
// the startup cache since this may have been reset to OP_NEEDS_INSTALL by
// |_configureForthcomingItem|.
PendingOperations.clearItem(OP_NEEDS_UPGRADE, id);
},
/**
* Completes an item's uninstallation.
* Param id
* The GUID of the item to uninstall.
*/
_finalizeUninstall: function(id) {
var ds = this.datasource;
var installLocation = this.getInstallLocation(id);
if (!installLocation.itemIsManagedIndependently(id)) {
try {
// Having a callback that does nothing just causes the directory to be
// removed.
safeInstallOperation(id, installLocation,
{ data: null, callback: function() { } });
}
catch (e) {
ERROR("_finalizeUninstall: failed to remove directory for item: " + id +
" at Install Location: " + installLocation.name + ", rolling back uninstall");
var manifest = installLocation.getItemFile(id, "FILE_INSTALL_MANIFEST");
// If there is no manifest then either the rollback failed, or there was
// no manifest in the first place. Either way this item is now invalid
// and we shouldn't try to re-install it.
if (manifest.exists()) {
// Removal of the files failed, reset the uninstalled flag and rewrite
// the install manifests so this item's components are registered.
// Clear the op flag from the Startup Cache
StartupCache.put(installLocation, id, OP_NONE, true);
var restartRequired = this.installRequiresRestart(id, ds.getItemProperty(id, "type"))
this._updateManifests(restartRequired);
return;
}
}
}
else if (installLocation.name == KEY_APP_PROFILE
installLocation.name == KEY_APP_GLOBAL
installLocation.name == KEY_APP_SYSTEM_USER) {
// Check for a pointer file and remove it if it exists
var pointerFile = installLocation.location.clone();
pointerFile.append(id);
if (pointerFile.exists() && !pointerFile.isDirectory())
pointerFile.remove(false);
}
// Clean the item resource
ds.removeItemMetadata(id);
// Do this LAST since inferences are made about an item based on
// what container it's in.
ds.removeItemFromContainer(id);
// Clear the op flag from the Startup Cache and the Pending Operations set.
StartupCache.clearEntry(installLocation, id);
PendingOperations.clearItem(OP_NEEDS_UNINSTALL, id);
},
/**
* Uninstalls an item. If the uninstallation cannot be performed immediately
* it is scheduled for the next restart.
* Param id
* The GUID of the item to uninstall.
*/
uninstallItem: function(id) {
var ds = this.datasource;
ds.updateDownloadState(PREFIX_ITEM_URI + id, null);
if (!ds.isDownloadItem(id)) {
var opType = ds.getItemProperty(id, "opType");
var installLocation = this.getInstallLocation(id);
// Removes any staged xpis for this item.
if (opType == OP_NEEDS_UPGRADE opType == OP_NEEDS_INSTALL) {
var stageFile = installLocation.getStageFile(id);
if (stageFile)
installLocation.removeFile(stageFile);
}
// Addons with an opType of OP_NEEDS_INSTALL only have a staged xpi file
// and are removed immediately since the uninstall can't be canceled.
if (opType == OP_NEEDS_INSTALL) {
ds.removeItemMetadata(id);
ds.removeItemFromContainer(id);
ds.updateVisibleList(id, null, true);
StartupCache.clearEntry(installLocation, id);
this._updateManifests(false);
}
else {
if (opType == OP_NEEDS_UPGRADE)
ds.setItemProperty(id, "newVersion", null);
this._setOp(id, OP_NEEDS_UNINSTALL);
var type = ds.getItemProperty(id, "type");
var restartRequired = this.installRequiresRestart(id, type);
if (!restartRequired) {
this._finalizeUninstall(id);
this._updateManifests(restartRequired);
}
}
}
else {
// Bad download entry - uri is url, e.g. "http://www.foo.com/test.xpi"
// ... just remove it from the list.
ds.removeCorruptDLItem(id);
}
this._notifyAction(id, EM_ITEM_UNINSTALLED);
},
/* See nsIExtensionManager.idl */
cancelInstallItem: function(id) {
var ds = this.datasource;
var opType = ds.getItemProperty(id, "opType");
if (opType != OP_NEEDS_UPGRADE && opType != OP_NEEDS_INSTALL)
return;
ds.updateDownloadState(PREFIX_ITEM_URI + id, null);
var installLocation = this.getInstallLocation(id);
// Removes any staged xpis for this item.
var stageFile = installLocation.getStageFile(id);
if (stageFile)
installLocation.removeFile(stageFile);
// Addons with an opType of OP_NEEDS_INSTALL only have a staged xpi file
// and just need to be removed completely from the ds.
if (opType == OP_NEEDS_INSTALL) {
ds.removeItemMetadata(id);
ds.removeItemFromContainer(id);
ds.updateVisibleList(id, null, true);
StartupCache.clearEntry(installLocation, id);
this._updateManifests(false);
this._notifyAction(id, EM_ITEM_CANCEL);
}
else {
// Clear upgrade information and reset any request to enable/disable.
ds.setItemProperty(id, EM_R("newVersion"), null);
var appDisabled = ds.getItemProperty(id, "appDisabled");
var userDisabled = ds.getItemProperty(id, "userDisabled");
if (appDisabled == "true" appDisabled == OP_NONE && userDisabled == OP_NONE) {
this._setOp(id, OP_NONE);
this._notifyAction(id, EM_ITEM_CANCEL);
}
else if (appDisabled == OP_NEEDS_DISABLE userDisabled == OP_NEEDS_DISABLE) {
this._setOp(id, OP_NEEDS_DISABLE);
this._notifyAction(id, EM_ITEM_DISABLED);
}
else if (appDisabled == OP_NEEDS_ENABLE userDisabled == OP_NEEDS_ENABLE) {
this._setOp(id, OP_NEEDS_ENABLE);
this._notifyAction(id, EM_ITEM_ENABLED);
}
else {
this._setOp(id, OP_NONE);
this._notifyAction(id, EM_ITEM_CANCEL);
}
}
},
/**
* Cancels a pending uninstall of an item
* Param id
* The ID of the item.
*/
cancelUninstallItem: function(id) {
var ds = this.datasource;
var appDisabled = ds.getItemProperty(id, "appDisabled");
var userDisabled = ds.getItemProperty(id, "userDisabled");
if (appDisabled == "true" appDisabled == OP_NONE && userDisabled == OP_NONE) {
this._setOp(id, OP_NONE);
this._notifyAction(id, EM_ITEM_CANCEL);
}
else if (appDisabled == OP_NEEDS_DISABLE userDisabled == OP_NEEDS_DISABLE) {
this._setOp(id, OP_NEEDS_DISABLE);
this._notifyAction(id, EM_ITEM_DISABLED);
}
else if (appDisabled == OP_NEEDS_ENABLE userDisabled == OP_NEEDS_ENABLE) {
this._setOp(id, OP_NEEDS_ENABLE);
this._notifyAction(id, EM_ITEM_ENABLED);
}
else {
this._setOp(id, OP_NONE);
this._notifyAction(id, EM_ITEM_CANCEL);
}
},
/**
* Sets the pending operation for a visible item.
* Param id
* The GUID of the item
* Param op
* The name of the operation to be performed
*/
_setOp: function(id, op) {
var location = this.getInstallLocation(id);
StartupCache.put(location, id, op, true);
PendingOperations.addItem(op, { locationKey: location.name, id: id });
var ds = this.datasource;
if (op == OP_NEEDS_INSTALL op == OP_NEEDS_UPGRADE)
ds.updateDownloadState(PREFIX_ITEM_URI + id, "success");
ds.updateProperty(id, "opType");
ds.updateProperty(id, "updateable");
ds.updateProperty(id, "satisfiesDependencies");
var restartRequired = this.installRequiresRestart(id, ds.getItemProperty(id, "type"))
this._updateDependentItemsForID(id);
this._updateManifests(restartRequired);
},
/**
* Note on appDisabled and userDisabled property arcs.
* The appDisabled and userDisabled RDF property arcs are used to store
* the pending operation for app disabling and user disabling for an item as
* well as the user and app disabled status after the pending operation has
* been completed upon restart. When the appDisabled value changes the value
* of userDisabled is reset to prevent the state of widgets and status
* messages from being in an incorrect state.
*/
/**
* Enables an item for the application (e.g. the item satisfies all
* requirements like app compatibility for it to be enabled). The appDisabled
* property arc will be removed if the item will be app disabled on next
* restart to cancel the app disabled operation for the item otherwise the
* property value will be set to OP_NEEDS_ENABLE. The item's pending
* operations are then evaluated in order to set the operation to perform
* and notify the observers if the operation has been changed.
* See "Note on appDisabled and userDisabled property arcs" above.
* Param id
* The ID of the item to be enabled by the application.
*/
_appEnableItem: function(id) {
var ds = this.datasource;
var appDisabled = ds.getItemProperty(id, "appDisabled");
if (appDisabled == OP_NONE appDisabled == OP_NEEDS_ENABLE)
return;
var opType = ds.getItemProperty(id, "opType");
var userDisabled = ds.getItemProperty(id, "userDisabled");
// reset user disabled if it has a pending operation to prevent the ui
// state from getting confused as to an item's current state.
if (userDisabled == OP_NEEDS_DISABLE)
ds.setItemProperty(id, EM_R("userDisabled"), null);
else if (userDisabled == OP_NEEDS_ENABLE)
ds.setItemProperty(id, EM_R("userDisabled"), EM_L("true"));
if (appDisabled == OP_NEEDS_DISABLE)
ds.setItemProperty(id, EM_R("appDisabled"), null);
else if (appDisabled == "true")
ds.setItemProperty(id, EM_R("appDisabled"), EM_L(OP_NEEDS_ENABLE));
// Don't set a new operation when there is a pending uninstall operation.
if (opType == OP_NEEDS_UNINSTALL) {
this._updateDependentItemsForID(id);
return;
}
var operation, action;
// if this item is already enabled or user disabled don't set a pending
// operation - instead immediately enable it and reset the operation type
// if needed.
if (appDisabled == OP_NEEDS_DISABLE appDisabled == OP_NONE
userDisabled == "true") {
if (opType != OP_NONE) {
operation = OP_NONE;
action = EM_ITEM_CANCEL;
}
}
else {
if (opType != OP_NEEDS_ENABLE) {
operation = OP_NEEDS_ENABLE;
action = EM_ITEM_ENABLED;
}
}
if (action) {
this._setOp(id, operation);
this._notifyAction(id, action);
}
else {
ds.updateProperty(id, "satisfiesDependencies");
this._updateDependentItemsForID(id);
}
},
/**
* Disables an item for the application (e.g. the item doesn't satisfy all
* requirements like app compatibility for it to be enabled). The appDisabled
* property arc will be set to true if the item will be app enabled on next
* restart to cancel the app enabled operation for the item otherwise the
* property value will be set to OP_NEEDS_DISABLE. The item's pending
* operations are then evaluated in order to set the operation to perform
* and notify the observers if the operation has been changed.
* See "Note on appDisabled and userDisabled property arcs" above.
* Param id
* The ID of the item to be disabled by the application.
*/
_appDisableItem: function(id) {
var ds = this.datasource;
var appDisabled = ds.getItemProperty(id, "appDisabled");
if (appDisabled == "true" appDisabled == OP_NEEDS_DISABLE)
return;
var opType = ds.getItemProperty(id, "opType");
var userDisabled = ds.getItemProperty(id, "userDisabled");
// reset user disabled if it has a pending operation to prevent the ui
// state from getting confused as to an item's current state.
if (userDisabled == OP_NEEDS_DISABLE)
ds.setItemProperty(id, EM_R("userDisabled"), null);
else if (userDisabled == OP_NEEDS_ENABLE)
ds.setItemProperty(id, EM_R("userDisabled"), EM_L("true"));
if (appDisabled == OP_NEEDS_ENABLE userDisabled == OP_NEEDS_ENABLE
ds.getItemProperty(id, "userDisabled") == "true")
ds.setItemProperty(id, EM_R("appDisabled"), EM_L("true"));
else if (appDisabled == OP_NONE)
ds.setItemProperty(id, EM_R("appDisabled"), EM_L(OP_NEEDS_DISABLE));
// Don't set a new operation when there is a pending uninstall operation.
if (opType == OP_NEEDS_UNINSTALL) {
this._updateDependentItemsForID(id);
return;
}
var operation, action;
// if this item is already disabled don't set a pending operation - instead
// immediately disable it and reset the operation type if needed.
if (appDisabled == OP_NEEDS_ENABLE appDisabled == "true"
userDisabled == OP_NEEDS_ENABLE userDisabled == "true") {
if (opType != OP_NONE) {
operation = OP_NONE;
action = EM_ITEM_CANCEL;
}
}
else {
if (opType != OP_NEEDS_DISABLE) {
operation = OP_NEEDS_DISABLE;
action = EM_ITEM_DISABLED;
}
}
if (action) {
this._setOp(id, operation);
this._notifyAction(id, action);
}
else {
ds.updateProperty(id, "satisfiesDependencies");
this._updateDependentItemsForID(id);
}
},
/**
* Sets an item to be enabled by the user. If the item is already enabled this
* clears the needs-enable operation for the next restart.
* See "Note on appDisabled and userDisabled property arcs" above.
* Param id
* The ID of the item to be enabled by the user.
*/
enableItem: function(id) {
var ds = this.datasource;
var opType = ds.getItemProperty(id, "opType");
var appDisabled = ds.getItemProperty(id, "appDisabled");
var userDisabled = ds.getItemProperty(id, "userDisabled");
var operation, action;
// if this item is already enabled don't set a pending operation - instead
// immediately enable it and reset the operation type if needed.
if (appDisabled == OP_NONE &&
userDisabled == OP_NEEDS_DISABLE userDisabled == OP_NONE) {
if (userDisabled == OP_NEEDS_DISABLE)
ds.setItemProperty(id, EM_R("userDisabled"), null);
if (opType != OP_NONE) {
operation = OP_NONE;
action = EM_ITEM_CANCEL;
}
}
else {
if (userDisabled == "true")
ds.setItemProperty(id, EM_R("userDisabled"), EM_L(OP_NEEDS_ENABLE));
if (opType != OP_NEEDS_ENABLE) {
operation = OP_NEEDS_ENABLE;
action = EM_ITEM_ENABLED;
}
}
if (action) {
this._setOp(id, operation);
this._notifyAction(id, action);
}
else {
ds.updateProperty(id, "satisfiesDependencies");
this._updateDependentItemsForID(id);
}
},
/**
* Sets an item to be disabled by the user. If the item is already disabled
* this clears the needs-disable operation for the next restart.
* See "Note on appDisabled and userDisabled property arcs" above.
* Param id
* The ID of the item to be disabled by the user.
*/
disableItem: function(id) {
var ds = this.datasource;
var opType = ds.getItemProperty(id, "opType");
var appDisabled = ds.getItemProperty(id, "appDisabled");
var userDisabled = ds.getItemProperty(id, "userDisabled");
var operation, action;
// if this item is already disabled don't set a pending operation - instead
// immediately disable it and reset the operation type if needed.
if (userDisabled == OP_NEEDS_ENABLE userDisabled == "true"
appDisabled == OP_NEEDS_ENABLE) {
if (userDisabled != "true")
ds.setItemProperty(id, EM_R("userDisabled"), EM_L("true"));
if (opType != OP_NONE) {
operation = OP_NONE;
action = EM_ITEM_CANCEL;
}
}
else {
if (userDisabled == OP_NONE)
ds.setItemProperty(id, EM_R("userDisabled"), EM_L(OP_NEEDS_DISABLE));
if (opType != OP_NEEDS_DISABLE) {
operation = OP_NEEDS_DISABLE;
action = EM_ITEM_DISABLED;
}
}
if (action) {
this._setOp(id, operation);
this._notifyAction(id, action);
}
else {
ds.updateProperty(id, "satisfiesDependencies");
this._updateDependentItemsForID(id);
}
},
/**
* Determines whether an item should be disabled by the application.
* Param id
* The ID of the item to check
*/
_isUsableItem: function(id) {
var ds = this.datasource;
/* If we're not compatibility checking or if the item is compatible
* and if it isn't blocklisted and has all dependencies satisfied then
* proceed to the security check */
if ((!gCheckCompatibility ds.getItemProperty(id, "compatible") == "true") &&
ds.getItemProperty(id, "blocklisted") == "false" &&
ds.getItemProperty(id, "satisfiesDependencies") == "true") {
// appManaged items aren't updated so no need to check update security.
if (ds.getItemProperty(id, "appManaged") == "true")
return true;
/* If we are not ignoring update security then check that the item has
* a secure update mechanism */
return (!gCheckUpdateSecurity
ds.getItemProperty(id, "providesUpdatesSecurely") == "true");
}
return false;
},
/**
* Sets an item's dependent items disabled state for the app based on whether
* its dependencies are met and the item is compatible.
* Param id
* The ID of the item whose dependent items will be checked
*/
_updateDependentItemsForID: function(id) {
var ds = this.datasource;
var dependentItems = this.getDependentItemListForID(id, true, { });
for (var i = 0; i < dependentItems.length; ++i) {
var dependentID = dependentItems[i].id;
ds.updateProperty(dependentID, "satisfiesDependencies");
if (this._isUsableItem(dependentID))
this._appEnableItem(dependentID);
else
this._appDisableItem(dependentID);
}
},
/**
* Notify observers of a change to an item that has been requested by the
* user.
*/
_notifyAction: function(id, reason) {
gOS.notifyObservers(this.datasource.getItemForID(id),
EM_ACTION_REQUESTED_TOPIC, reason);
},
/**
* See nsIExtensionManager.idl
*/
update: function(items, itemCount, updateCheckType, listener) {
for (i = 0; i < itemCount; ++i) {
var currItem = items[i];
if (!currItem)
throw Cr.NS_ERROR_ILLEGAL_VALUE;
}
if (items.length == 0)
items = this.getItemList(Ci.nsIUpdateItem.TYPE_ANY, { });
var updater = new ExtensionItemUpdater(this);
updater.checkForUpdates(items, items.length, updateCheckType, listener);
},
/**
* Checks for changes to the blocklist using the local blocklist file,
* application disables / enables items that have been added / removed from
* the blocklist, and if there are additions to the blocklist this will
* inform the user by displaying a list of the items added.
*
* XXXrstrong - this method is not terribly useful and was added so we ca