generic version checking service, support custom update urls

This commit is contained in:
ben%bengoodger.com 2004-05-03 06:32:10 +00:00
parent 1c4ef3efa1
commit 20d9dc35fe
7 changed files with 386 additions and 233 deletions

View File

@ -91,7 +91,7 @@ nsInstallLogBase.prototype = {
//
function nsInstallLogWriter(aExtensionID, aIsProfile)
{
this._isProfile = aIsProfile; // XXXben
this._isProfile = aIsProfile;
this._uninstallLog = getDir(aIsProfile ? "ProfD" : "ProfD",
["extensions", aExtensionID, "uninstall"]); // XXXben XCurProcDir
this._uninstallLog.append("uninstall.log");
@ -137,7 +137,7 @@ nsInstallLogWriter.prototype = {
//
function nsInstallLogReader(aExtensionID, aIsProfile, aListener)
{
this._isProfile = aIsProfile; // XXXben
this._isProfile = aIsProfile;
this.uninstallLog = getDir(aIsProfile ? "ProfD" : "ProfD",
["extensions", aExtensionID, "uninstall"]); // XXXben XCurProcDir
this.uninstallLog.append("uninstall.log");
@ -357,7 +357,7 @@ nsExtensionInstaller.prototype = {
type = this._writer.CHROME_TYPE_PACKAGE;
}
else if (aChromeType.EqualsNode(this._provTypeSkin)) {
cr.installSkin(fileURL, this._isProfile);
cr.installSkin(fileURL, this._isProfile, true); // Extension skins can execute scripts
type = this._writer.CHROME_TYPE_SKIN;
}
else if (aChromeType.EqualsNode(this._provTypeLocale)) {
@ -382,6 +382,10 @@ nsExtensionInstaller.prototype = {
}
};
///////////////////////////////////////////////////////////////////////////////
//
// nsExtensionUninstaller
//
function nsExtensionUninstaller(aExtensionDS)
{
this._cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
@ -460,154 +464,6 @@ nsExtensionUninstaller.prototype = {
}
};
///////////////////////////////////////////////////////////////////////////////
//
// nsVersionChecker
//
function VersionChecker(aExtensionResource, aAppID, aAppVersion, aDataSource)
{
this._extensionResource = aExtensionResource;
this._appID = aAppID;
this._appVersion = aAppVersion;
this._ds = aDataSource;
}
VersionChecker.prototype = {
get isCompatible ()
{
var targets = this._ds.GetTargets(this._extensionResource, this._ds._emR("targetApplication"), true);
while (targets.hasMoreElements()) {
var targetAppString = targets.getNext().QueryInterface(Components.interfaces.nsIRDFLiteral);
var versionParts = targetAppString.Value.split(",");
if (versionParts[0] == this._appID) {
var minRequiredVersionStr = versionParts[1];
var maxRequiredVersionStr = versionParts[2];
var power = this._getLargestPower([this._appVersion,
minRequiredVersionStr,
maxRequiredVersionStr]);
var minRequiredVersion = this._parseVersion(minRequiredVersionStr, power);
var maxRequiredVersion = this._parseVersion(maxRequiredVersionStr, power);
var appVersion = this._parseVersion(this._appVersion, power);
return (appVersion >= minRequiredVersion &&
appVersion <= maxRequiredVersion);
}
}
return false;
},
// Convert a version string into an integer value
_parseVersion: function (aVersion, aPower)
{
var parts = aVersion.split(".");
var version = 0;
if (aPower == 0)
aPower = parts.length;
for (var i = 0; i < parts.length; ++i) {
var token = parts[i];
if (token.charAt(token.length-1) == "+") {
token = token.substr(0, token.lastIndexOf("+"));
version += 1;
if (token.length == 0)
continue;
}
version += parseInt(token) * Math.pow(10, aPower - i);
}
return version;
},
_parsePower: function (aVersion)
{
return aVersion.split(".").length;
},
_getLargestPower: function (aVersionArray)
{
var biggestPower = 0;
for (var i = 0; i < aVersionArray.length; ++i) {
var power = this._parsePower(aVersionArray[i]);
if (power > biggestPower)
biggestPower = power;
}
return biggestPower;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// nsJarFileExtractor
//
function nsJarFileExtractor(aXPIFile, aTargetDir)
{
this._xpiFile = aXPIFile.path;
this._targetDir = aTargetDir.path;
// this._proxyObject(Components, Components.interfaces.nsIXPCComponents, "_components");
/*
this._proxyObject(aXPIFile, Components.interfaces.nsIFile, "_xpiFile");
this._proxyObject(aTargetDir, Components.interfaces.nsIFile, "_targetDir");
*/
}
nsJarFileExtractor.prototype = {
// proxied objects
_xpiFile: null,
_targetDir: null,
_components: null,
_proxyObject: function (aObject, aIID, aTarget)
{
const nsIEventQueueService = Components.interfaces.nsIEventQueueService;
var eqService = Components.classes["@mozilla.org/event-queue-service;1"]
.getService(nsIEventQueueService);
var uiQ = eqService.getSpecialEventQueue(nsIEventQueueService.UI_THREAD_EVENT_QUEUE);
var proxyObjectManager = Components.classes["@mozilla.org/xpcomproxy;1"]
.getService(Components.interfaces.nsIProxyObjectManager);
const PROXY_SYNC = 0x01;
const PROXY_ALWAYS = 0x04;
this[aTarget] = proxyObjectManager.getProxyForObject(uiQ, aIID, aObject,
PROXY_SYNC | PROXY_ALWAYS);
},
extract: function ()
{
const nsIThread = Components.interfaces.nsIThread;
var thread = Components.classes["@mozilla.org/thread;1"]
.createInstance(nsIThread);
thread.init(this, 0, nsIThread.PRIORITY_NORMAL,
nsIThread.SCOPE_GLOBAL,
nsIThread.STATE_JOINABLE);
},
/////////////////////////////////////////////////////////////////////////////
// nsIRunnable
run: function ()
{
dump("*** RUNNING THREAD\n");
/*
var xpiFile = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
xpiFile.initWithPath(this._xpiFile);
var targetDir = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
targetDir.initWithPath(this._targetDir);
var zipReader = Components.classes["@mozilla.org/libjar/zip-reader;1"]
.createInstance(Components.interfaces.nsIZipReader);
zipReader.init(xpiFile);
var entries = zipReader.findEntries("*");
while (entries.hasMoreElements()) {
var entry = entries.getNext().QueryInterface(Components.interfaces.nsIZipEntry);
dump("*** zip entry = " + entry.name + "\n");
}
*/
}
};
///////////////////////////////////////////////////////////////////////////////
//
// nsExtensionManager
@ -910,9 +766,12 @@ nsExtensionManager.prototype = {
.getService(Components.interfaces.nsIRDFService);
var manifestRoot = rdf.GetResource("urn:mozilla:extension:manifest");
var id = rdf.GetResource(EM_NS("id"));
// XXXben - do version check
var idLiteral = aDataSource.GetTarget(manifestRoot, id, true);
return idLiteral.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
// Check the target application range specified by the extension metadata.
if (this._ds.isCompatible(aDataSource, id)) {
var idLiteral = aDataSource.GetTarget(manifestRoot, id, true);
return idLiteral.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
}
return null;
},
_stageExtensionXPI: function (aZipReader, aExtensionID, aInstallProfile)
@ -1042,6 +901,10 @@ nsExtensionManager.prototype = {
}
};
///////////////////////////////////////////////////////////////////////////////
//
// nsExtensionItemUpdater
//
function nsExtensionItemUpdater(aItems, aTargetAppID, aTargetAppVersion)
{
this._items = aItems;
@ -1069,6 +932,27 @@ nsExtensionItemUpdater.prototype = {
var wsdlURI = pref.getComplexValue(PREF_UPDATE_EXT_WSDL_URI,
Components.interfaces.nsIPrefLocalizedString).data;
wspFactory.createProxyAsync(wsdlURI, "VersionCheck", "", true, this);
for (var i = 0; i < this._items.length; ++i) {
var e = this._items[i];
if (e.updateRDF) {
var dsURI = e.updateRDF;
dsURI = dsURI.replace(/%ITEM_ID%/g, e.id);
dsURI = dsURI.replace(/%ITEM_VERSION%/g, e.version);
dsURI = dsURI.replace(/%APP_ID%/g, this._appID);
dsURI = dsURI.replace(/%APP_VERSION%/g, this._appVersion);
var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
.getService(Components.interfaces.nsIRDFService);
var ds = rdf.GetDataSource(dsURI);
var rds = ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource)
if (rds.loaded)
this.onDatasourceLoaded(ds);
else {
var sink = ds.QueryInterface(Components.interfaces.nsIRDFXMLSink);
sink.addXMLSinkObserver(new nsExtensionUpdateXMLRDFDSObserver(this, e));
}
}
}
},
/////////////////////////////////////////////////////////////////////////////
@ -1079,8 +963,10 @@ nsExtensionItemUpdater.prototype = {
{
for (var i = 0; i < this._items.length; ++i) {
var e = this._items[i];
this._os.notifyObservers(null, "Update:Extension:Item-Started", e.name + " " + e.version);
this._proxy.getNewestExtension(eval(e.objectSource), this._appID, this._appVersion);
if (!e.updateRDF) {
this._os.notifyObservers(null, "Update:Extension:Item-Started", e.name + " " + e.version);
this._proxy.getNewestExtension(eval(e.objectSource), this._appID, this._appVersion);
}
}
},
@ -1098,20 +984,69 @@ nsExtensionItemUpdater.prototype = {
this._os.notifyObservers(aResult, "Update:Extension:Item-Error", aMessage);
},
onDatasourceLoaded: function (aDatasource, aExtension)
{
///////////////////////////////////////////////////////////////////////////
// The extension update RDF file looks something like this:
// <RDF:Description about="urn:mozilla:extension:{EXTENSION GUID}">
// <em:version>5.0</em:version>
// <em:updateLink><XPI URL></em:updateLink>
// </RDF:Description>
// Parse the response RDF
var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
.getService(Components.interfaces.nsIRDFService);
var versionArc = rdf.GetResource(EM_NS("version"));
var updateLinkArc = rdf.GetResource(EM_NS("updateLink"));
var extensionRes = rdf.GetResource("urn:mozilla:extension:" + aExtension.id);
var version = aDatasource.GetTarget(extensionRes, versionArc, true);
version = version.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
var updateLink = aDatasource.GetTarget(extensionRes, updateLinkArc, true);
updateLink = updateLink.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
// Check to see if this is a newer version.
var versionChecker = Components.classes["@mozilla.org/updates/version-checker;1"]
.getService(Components.interfaces.nsIVersionChecker);
if (versionChecker.compare(aExtension.version, version) < 0) {
// Construct an update item and pass it to observers.
var item = Components.classes["@mozilla.org/updates/item;1"]
.createInstance(Components.interfaces.nsIUpdateItem);
item.init(aExtension.id, version, aExtension.name, -1, updateLink, "", "",
Components.interfaces.TYPE_EXTENSION); // XXXben
this._os.notifyObservers(item, "Update:Extension:Item-Ended", "");
++this._updateCount;
}
this._checkForDone();
},
onDatasourceError: function (aExtension)
{
// XXXben - some way of indicating an error in the update process
this._checkForDone();
},
getNewestExtensionCallback: function (aResult)
{
var item = aResult;
dump("*** result = " + item.toSource() + "\n");
try {
item.name.toString(); // XXXben This is a lame hack to cause an exception to be
// thrown for null values when there is no newer extension
// or something else bad happens on the server that we
// don't recognize.
this._os.notifyObservers(aResult, "Update:Extension:Item-Ended", "goat");
this._os.notifyObservers(aResult, "Update:Extension:Item-Ended", "");
++this._updateCount;
}
catch (e) {
}
this._checkForDone();
},
_checkForDone: function ()
{
if (--this._count == 0) {
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
@ -1132,6 +1067,50 @@ nsExtensionItemUpdater.prototype = {
}
};
function nsExtensionUpdateXMLRDFDSObserver(aUpdater, aExtension)
{
this._updater = aUpdater;
this._extension = aExtension;
}
nsExtensionUpdateXMLRDFDSObserver.prototype =
{
_updater : null,
_extension : null,
/////////////////////////////////////////////////////////////////////////////
// nsIRDFXMLSinkObserver
onBeginLoad: function(aSink)
{
},
onInterrupt: function(aSink)
{
},
onResume: function(aSink)
{
},
onEndLoad: function(aSink)
{
aSink.removeXMLSinkObserver(this);
var ds = aSink.QueryInterface(Components.interfaces.nsIRDFDataSource);
this._updater.onDatasourceLoaded(ds, this._extension);
},
onError: function(aSink, aStatus, aErrorMsg)
{
aSink.removeXMLSinkObserver(this);
this._updater.onDatasourceError(this._extension);
}
};
///////////////////////////////////////////////////////////////////////////////
//
// nsExtensionsDataSource
//
function nsExtensionsDataSource()
{
this._rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
@ -1160,6 +1139,29 @@ nsExtensionsDataSource.prototype = {
{
return aResourceURI.substr("urn:mozilla:extension:".length, aResourceURI.length);
},
isCompatible: function (aDS, aExtensionID)
{
var r = this._rdf.GetResource("urn:mozilla:extension:" + aExtensionID);
var targets = aDS.GetTargets(r, this._emR("targetApplication"), true);
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
var appVersion = pref.getCharPref(PREF_EM_APP_VERSION);
var appID = pref.getCharPref(PREF_EM_APP_ID);
while (targets.hasMoreElements()) {
var targetApp = targets.getNext().QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
var versionParts = targetApp.split(",");
if (versionParts[0] == appID) {
var versionChecker = Components.classes["@mozilla.org/updates/version-checker;1"]
.getService(Components.interfaces.nsIVersionChecker);
return ((versionChecker.compare(appVersion, versionParts[1]) >= 0) &&
(versionChecker.compare(appVersion, versionParts[2]) <= 0));
}
}
return false;
},
getIncompatibleItemList: function (aAppID, aAppVersion)
{
@ -1172,14 +1174,13 @@ nsExtensionsDataSource.prototype = {
var elements = ctr.GetElements();
while (elements.hasMoreElements()) {
var e = elements.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
var checker = new VersionChecker(e, aAppID, aAppVersion, this);
if (!checker.isCompatible) {
var id = this._stripPrefix(e.Value);
var id = this._stripPrefix(e.Value);
if (!this.isCompatible(this, id)) {
var item = Components.classes["@mozilla.org/updates/item;1"]
.createInstance(Components.interfaces.nsIUpdateItem);
item.init(id, this.getExtensionProperty(id, "version"),
this.getExtensionProperty(id, "name"),
-1, "", "",
-1, "", "", this.getExtensionProperty(id, "updateURL"),
Components.interfaces.nsIUpdateItem.TYPE_EXTENSION); // XXXben
items.push(item);
}
@ -1195,7 +1196,8 @@ nsExtensionsDataSource.prototype = {
.createInstance(Components.interfaces.nsIUpdateItem);
item.init(aItemID, this.getExtensionProperty(aItemID, "version"),
this.getExtensionProperty(aItemID, "name"),
-1, "", "", aType);
-1, "", "", this.getExtensionProperty(aItemID, "updateURL"),
aType);
items.push(item);
}
else {
@ -1211,7 +1213,8 @@ nsExtensionsDataSource.prototype = {
.createInstance(Components.interfaces.nsIUpdateItem);
item.init(id, this.getExtensionProperty(id, "version"),
this.getExtensionProperty(id, "name"),
-1, "", "", aType);
-1, "", "",
this.getExtensionProperty(id, "updateURL"), aType);
items.push(item);
}
}
@ -1351,11 +1354,28 @@ nsExtensionsDataSource.prototype = {
var extension = this._rdf.GetResource("urn:mozilla:extension:" + aExtensionID);
ctr.RemoveElement(extension, true);
// Clean the extension resource
this._removeExtensionMetadata(aExtensionID);
this.setExtensionProperty(aExtensionID, this._emR("toBeUninstalled"),
this._emL("true"),
this.isProfileExtension(aExtensionID));
},
_removeExtensionMetadata: function (aExtensionID)
{
var extension = this._rdf.GetResource("urn:mozilla:extension:" + aExtensionID);
var isProfile = this.isProfileExtension(aExtensionID);
var ds = isProfile ? this._profileExtensions : this._appExtensions;
var arcs = ds.ArcLabelsOut(extension);
while (arcs.hasMoreElements()) {
var arc = arcs.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
var value = ds.GetTarget(extension, arc, true);
if (value)
ds.Unassert(extension, arc, value);
}
},
loadExtensions: function (aProfile)
{
var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);

View File

@ -171,3 +171,77 @@ nsExtensionUpdater2.prototype = {
return updateURL;
},
///////////////////////////////////////////////////////////////////////////////
//
// nsJarFileExtractor
//
function nsJarFileExtractor(aXPIFile, aTargetDir)
{
this._xpiFile = aXPIFile.path;
this._targetDir = aTargetDir.path;
// this._proxyObject(Components, Components.interfaces.nsIXPCComponents, "_components");
/*
this._proxyObject(aXPIFile, Components.interfaces.nsIFile, "_xpiFile");
this._proxyObject(aTargetDir, Components.interfaces.nsIFile, "_targetDir");
*/
}
nsJarFileExtractor.prototype = {
// proxied objects
_xpiFile: null,
_targetDir: null,
_components: null,
_proxyObject: function (aObject, aIID, aTarget)
{
const nsIEventQueueService = Components.interfaces.nsIEventQueueService;
var eqService = Components.classes["@mozilla.org/event-queue-service;1"]
.getService(nsIEventQueueService);
var uiQ = eqService.getSpecialEventQueue(nsIEventQueueService.UI_THREAD_EVENT_QUEUE);
var proxyObjectManager = Components.classes["@mozilla.org/xpcomproxy;1"]
.getService(Components.interfaces.nsIProxyObjectManager);
const PROXY_SYNC = 0x01;
const PROXY_ALWAYS = 0x04;
this[aTarget] = proxyObjectManager.getProxyForObject(uiQ, aIID, aObject,
PROXY_SYNC | PROXY_ALWAYS);
},
extract: function ()
{
const nsIThread = Components.interfaces.nsIThread;
var thread = Components.classes["@mozilla.org/thread;1"]
.createInstance(nsIThread);
thread.init(this, 0, nsIThread.PRIORITY_NORMAL,
nsIThread.SCOPE_GLOBAL,
nsIThread.STATE_JOINABLE);
},
/////////////////////////////////////////////////////////////////////////////
// nsIRunnable
run: function ()
{
dump("*** RUNNING THREAD\n");
/*
var xpiFile = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
xpiFile.initWithPath(this._xpiFile);
var targetDir = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
targetDir.initWithPath(this._targetDir);
var zipReader = Components.classes["@mozilla.org/libjar/zip-reader;1"]
.createInstance(Components.interfaces.nsIZipReader);
zipReader.init(xpiFile);
var entries = zipReader.findEntries("*");
while (entries.hasMoreElements()) {
var entry = entries.getNext().QueryInterface(Components.interfaces.nsIZipEntry);
dump("*** zip entry = " + entry.name + "\n");
}
*/
}
};

View File

@ -45,6 +45,7 @@ const nsIExtensionManager = Components.interfaces.nsIExtensionMana
const PREF_APP_ID = "app.id";
const PREF_UPDATE_APP_UPDATESAVAILABLE = "update.app.updatesAvailable";
const PREF_UPDATE_EXTENSIONS_ENABLED = "update.extensions.enabled";
var gSourceEvent = null;
var gUpdateTypes = null;
@ -74,7 +75,7 @@ var gUpdateWizard = {
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
this.shouldSuggestAutoChecking = (gSourceEvent == nsIUpdateService.SOURCE_EVENT_MISMATCH) &&
!pref.getBoolPref("update.extensions.enabled");
!pref.getBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED);
if (gSourceEvent == nsIUpdateService.SOURCE_EVENT_USER) {
document.getElementById("mismatch").setAttribute("next", "checking");
@ -262,7 +263,7 @@ var gUpdatePage = {
item.init(appID, updates.appUpdateVersion,
brandShortName, -1, updates.appUpdateURL,
"chrome://mozapps/skin/update/icon32.png",
nsIUpdateItem.TYPE_APP);
"", nsIUpdateItem.TYPE_APP);
gUpdateWizard.itemsToUpdate.splice(0, 0, item);
}
break;
@ -427,6 +428,11 @@ var gInstallingPage = {
};
var gErrorsPage = {
onPageShow: function ()
{
document.documentElement.getButton("finish").focus();
},
onShowErrors: function ()
{
openDialog("chrome://mozapps/content/update/errors.xul", "",
@ -435,7 +441,6 @@ var gErrorsPage = {
};
var gFinishedPage = {
onPageShow: function ()
{
gUpdateWizard.setButtonLabels(null, true, null, true, null, true);
@ -464,6 +469,24 @@ var gFinishedPage = {
}
};
var gNoUpdatesPage = {
onPageShow: function (aEvent)
{
gUpdateWizard.setButtonLabels(null, true, null, true, null, true);
document.documentElement.getButton("finish").focus();
if (gSourceEvent == nsIUpdateService.SOURCE_EVENT_MISMATCH) {
document.getElementById("introUser").hidden = true;
document.getElementById("introMismatch").hidden = false;
document.getElementById("mismatchNoUpdates").hidden = false;
if (gUpdateWizard.shouldSuggestAutoChecking) {
document.getElementById("mismatchIncompatibleRemaining").hidden = true;
document.getElementById("mismatchIncompatibleRemaining2").hidden = false;
document.getElementById("mismatchFinishedEnableChecking").hidden = false;
}
}
}
};
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# Version: MPL 1.1/GPL 2.0/LGPL 2.1

View File

@ -94,10 +94,28 @@
</wizardpage>
<wizardpage id="noupdates" pageid="noupdates" next="finished"
<wizardpage id="noupdates" pageid="noupdates"
label="&noupdates.title;"
onpageshow="gNoUpdatesPage.onPageShow();"
onpageadvanced="gNoUpdatesPage.onPageAdvanced();">
onpageshow="gNoUpdatesPage.onPageShow();">
<label id="introUser">&noupdates.intro.user.label;</label>
<label id="introMismatch" hidden="true">&noupdates.intro.mismatch.label;</label>
<separator/>
<vbox id="mismatchNoUpdates" hidden="true">
<description id="mismatchIncompatibleRemaining" flex="1">
&noupdates.intro2.mismatch.label;
</description>
<description id="mismatchIncompatibleRemaining2" flex="1" hidden="true">
&noupdates.intro3.mismatch.label;
</description>
<separator class="thin"/>
<vbox align="left">
<checkbox label="&noupdates.enableChecking.label;"
id="mismatchFinishedEnableChecking" hidden="true"
oncommand="gUpdateWizard.shouldAutoCheck = this.checked;"/>
</vbox>
</vbox>
</wizardpage>
<wizardpage id="found" pageid="found" next="installing"

View File

@ -22,10 +22,6 @@
<!ENTITY noupdates.title "No Updates Found">
<!ENTITY noupdates.intro.user.label "&brandShortName; was not able to find any available updates.">
<!ENTITY noupdates.intro2.user.label "&brandShortName; will check periodically and inform you when
updates become available.">
<!ENTITY noupdates.intro3.user.label "&brandShortName; can check periodically and inform you when
updates become available.">
<!ENTITY noupdates.intro.mismatch.label "&brandShortName; was not able to find any available updates -
compatible versions may not be available at this time.">

View File

@ -49,6 +49,7 @@ interface nsIUpdateItem : nsISupports
readonly attribute long row;
readonly attribute wstring updateURL;
readonly attribute wstring iconURL;
readonly attribute wstring updateRDF;
const unsigned short TYPE_ANY = 0x01;
const unsigned short TYPE_APP = 0x02;
@ -62,7 +63,7 @@ interface nsIUpdateItem : nsISupports
void init(in string aID, in string aVersion, in wstring aName,
in long aRow, in wstring aUpdateURL, in wstring aIconURL,
in long aType);
in wstring aUpdateRDF, in long aType);
readonly attribute wstring objectSource;
};
@ -94,3 +95,12 @@ interface nsIUpdateService : nsISupports
readonly attribute wstring appUpdateURL;
};
[scriptable, uuid(22d35700-5765-42e1-914b-a0da7c911a8c)]
interface nsIVersionChecker : nsISupports
{
// -ve if B is newer
// equal if A == B
// +ve if A is newer
long compare(in string aVersionA, in string aVersionB);
};

View File

@ -154,11 +154,7 @@ nsBackgroundUpdateService.prototype = {
os.addObserver(this._updateObserver, "Update:Extension:Ended", false);
os.addObserver(this._updateObserver, "Update:App:Ended", false);
var appUpdatesEnabled = this._pref.getBoolPref(PREF_UPDATE_APP_ENABLED);
var extUpdatesEnabled = this._pref.getBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED);
if (appUpdatesEnabled && ((aUpdateTypes == nsIUpdateItem.TYPE_ANY) ||
(aUpdateTypes == nsIUpdateItem.TYPE_APP))) {
if ((aUpdateTypes == nsIUpdateItem.TYPE_ANY) || (aUpdateTypes == nsIUpdateItem.TYPE_APP)) {
var dsURI = this._pref.getComplexValue(PREF_UPDATE_APP_URI,
Components.interfaces.nsIPrefLocalizedString).data;
var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
@ -172,7 +168,7 @@ nsBackgroundUpdateService.prototype = {
sink.addXMLSinkObserver(new nsAppUpdateXMLRDFDSObserver(this));
}
}
if (extUpdatesEnabled && (aUpdateTypes != nsIUpdateItem.TYPE_APP)) {
if (aUpdateTypes != nsIUpdateItem.TYPE_APP) {
var em = Components.classes["@mozilla.org/extensions/manager;1"]
.getService(Components.interfaces.nsIExtensionManager);
em.update(aItems, aItems.length);
@ -215,8 +211,9 @@ nsBackgroundUpdateService.prototype = {
// do update checking here, parsing something like this format:
var version = this._getProperty(aDataSource, appID, "version");
var checker = new VersionChecker(appVersion, version);
if (checker.isNewer) {
var versionChecker = Components.classes["@mozilla.org/updates/version-checker;1"]
.getService(Components.interfaces.nsIVersionChecker);
if (versionChecker.compare(appVersion, version) < 0) {
pref.setCharPref(PREF_UPDATE_APP_UPDATEVERSION, version);
var severity = this._getProperty(aDataSource, appID, "severity");
@ -336,11 +333,9 @@ nsUpdateObserver.prototype = {
this._updateTypes == nsIUpdateItem.TYPE_APP;
var updatingExt = this._updateTypes != nsIUpdateItem.TYPE_APP;
if (this._pref.getBoolPref(PREF_UPDATE_APP_ENABLED) &&
updatingApp)
if (updatingApp)
test |= UPDATED_APP;
if (this._pref.getBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED) &&
updatingExt)
if (updatingExt)
test |= UPDATED_EXTENSIONS;
return (this._updateState & test) == test;
@ -419,7 +414,7 @@ function UpdateItem ()
}
UpdateItem.prototype = {
init: function (aID, aVersion, aName, aRow, aUpdateURL, aIconURL, aType)
init: function (aID, aVersion, aName, aRow, aUpdateURL, aIconURL, aUpdateRDF, aType)
{
this._id = aID;
this._version = aVersion;
@ -427,6 +422,7 @@ UpdateItem.prototype = {
this._row = aRow;
this._updateURL = aUpdateURL;
this._iconURL = aIconURL;
this._updateRDF = aUpdateRDF;
this._type = aType;
},
@ -436,6 +432,7 @@ UpdateItem.prototype = {
get row() { return this._row; },
get updateURL() { return this._updateURL; },
get iconURL() { return this._iconURL },
get updateRDF() { return this._updateRDF; },
get type() { return this._type; },
get objectSource()
@ -456,67 +453,66 @@ UpdateItem.prototype = {
}
};
// XXXben I would actually like to replace this with something more generic
// like what samir has in nsUpdateNotifier.js
function VersionChecker(aCurrentAppVer, aUpdateAppVer)
function nsVersionChecker()
{
this._currAppVer = aCurrentAppVer;
this._nextAppVer = aUpdateAppVer;
}
VersionChecker.prototype = {
currAppVersion: 0,
nextAppversion: 0,
get isNewer ()
nsVersionChecker.prototype = {
/////////////////////////////////////////////////////////////////////////////
// nsIVersionChecker
// -ve if B is newer
// equal if A == B
// +ve if A is newer
compare: function (aVersionA, aVersionB)
{
var power = this._getLargestPower([this._currAppVer, this._nextAppVer]);
this.currAppVersion = this._parseVersion(this._currAppVer, power);
this.nextAppVersion = this._parseVersion(this._nextAppVer, power);
return this.nextAppVersion > this.currAppVersion;
var a = this._decomposeVersion(aVersionA);
var b = this._decomposeVersion(aVersionB);
return a - b;
},
// Convert a version string into an integer value
_parseVersion: function (aVersion, aPower)
// Version strings get translated into a "score" that indicates how new
// the product is.
//
// a.b.c+ -> a*1000 + b*100 + c*10 + 1*[+]
// i.e 0.6.1+ = 6 * 100 + 1 * 10 = 611.
_decomposeVersion: function (aVersion)
{
var parts = aVersion.split(".");
var version = 0;
if (aPower == 0)
aPower = parts.length;
var result = 0;
if (aVersion.charAt(aVersion.length-1) == "+") {
aVersion = aVersion.substr(0, aVersion.length-1);
result += 1;
}
for (var i = 0; i < parts.length; ++i) {
var token = parts[i];
if (token.charAt(token.length-1) == "+") {
token = token.substr(0, token.lastIndexOf("+"));
version += 1;
if (token.length == 0)
continue;
}
version += parseInt(token) * Math.pow(10, aPower - i);
}
return version;
var parts = aVersion.split(".");
result += this._getValidInt(parts[0]) * 1000;
result += this._getValidInt(parts[1]) * 100;
result += this._getValidInt(parts[2]) * 10;
return result;
},
_parsePower: function (aVersion)
_getValidInt: function (aPartString)
{
return aVersion.split(".").length;
var integer = parseInt(aPartString);
if (isNaN(integer))
return 0;
return integer;
},
_getLargestPower: function (aVersionArray)
/////////////////////////////////////////////////////////////////////////////
// nsISupports
QueryInterface: function (aIID)
{
var biggestPower = 0;
for (var i = 0; i < aVersionArray.length; ++i) {
var power = this._parsePower(aVersionArray[i]);
if (power > biggestPower)
biggestPower = power;
}
return biggestPower;
if (!aIID.equals(Components.interfaces.nsIVersionChecker) &&
!aIID.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
}
};
var gUpdateService = null;
var gUpdateService = null;
var gVersionChecker = null;
var gModule = {
_firstTime: true,
@ -552,7 +548,7 @@ var gModule = {
_objects: {
manager: { CID: Components.ID("{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}"),
contractID: "@mozilla.org/updates/update-service;1",
className: "Background Update Service",
className: "Update Service",
factory: {
createInstance: function (aOuter, aIID)
{
@ -566,6 +562,22 @@ var gModule = {
}
}
},
version: { CID: Components.ID("{9408E0A5-509E-45E7-80C1-0F35B99FF7A9}"),
contractID: "@mozilla.org/updates/version-checker;1",
className: "Version Checker",
factory: {
createInstance: function (aOuter, aIID)
{
if (aOuter != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
if (!gVersionChecker)
gVersionChecker = new nsVersionChecker();
return gVersionChecker.QueryInterface(aIID);
}
}
},
item: { CID: Components.ID("{F3294B1C-89F4-46F8-98A0-44E1EAE92518}"),
contractID: "@mozilla.org/updates/item;1",
className: "Extension Item",