generic version checking service, support custom update urls

This commit is contained in:
ben%bengoodger.com 2004-05-03 06:32:10 +00:00
Родитель ab8ff1f170
Коммит 3d5ea95a77
7 изменённых файлов: 312 добавлений и 406 удалений

Просмотреть файл

@ -91,7 +91,7 @@ nsInstallLogBase.prototype = {
// //
function nsInstallLogWriter(aExtensionID, aIsProfile) function nsInstallLogWriter(aExtensionID, aIsProfile)
{ {
this._isProfile = aIsProfile; // XXXben this._isProfile = aIsProfile;
this._uninstallLog = getDir(aIsProfile ? "ProfD" : "ProfD", this._uninstallLog = getDir(aIsProfile ? "ProfD" : "ProfD",
["extensions", aExtensionID, "uninstall"]); // XXXben XCurProcDir ["extensions", aExtensionID, "uninstall"]); // XXXben XCurProcDir
this._uninstallLog.append("uninstall.log"); this._uninstallLog.append("uninstall.log");
@ -137,7 +137,7 @@ nsInstallLogWriter.prototype = {
// //
function nsInstallLogReader(aExtensionID, aIsProfile, aListener) function nsInstallLogReader(aExtensionID, aIsProfile, aListener)
{ {
this._isProfile = aIsProfile; // XXXben this._isProfile = aIsProfile;
this.uninstallLog = getDir(aIsProfile ? "ProfD" : "ProfD", this.uninstallLog = getDir(aIsProfile ? "ProfD" : "ProfD",
["extensions", aExtensionID, "uninstall"]); // XXXben XCurProcDir ["extensions", aExtensionID, "uninstall"]); // XXXben XCurProcDir
this.uninstallLog.append("uninstall.log"); this.uninstallLog.append("uninstall.log");
@ -357,7 +357,7 @@ nsExtensionInstaller.prototype = {
type = this._writer.CHROME_TYPE_PACKAGE; type = this._writer.CHROME_TYPE_PACKAGE;
} }
else if (aChromeType.EqualsNode(this._provTypeSkin)) { 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; type = this._writer.CHROME_TYPE_SKIN;
} }
else if (aChromeType.EqualsNode(this._provTypeLocale)) { else if (aChromeType.EqualsNode(this._provTypeLocale)) {
@ -382,6 +382,10 @@ nsExtensionInstaller.prototype = {
} }
}; };
///////////////////////////////////////////////////////////////////////////////
//
// nsExtensionUninstaller
//
function nsExtensionUninstaller(aExtensionDS) function nsExtensionUninstaller(aExtensionDS)
{ {
this._cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"] 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 // nsExtensionManager
@ -910,9 +766,12 @@ nsExtensionManager.prototype = {
.getService(Components.interfaces.nsIRDFService); .getService(Components.interfaces.nsIRDFService);
var manifestRoot = rdf.GetResource("urn:mozilla:extension:manifest"); var manifestRoot = rdf.GetResource("urn:mozilla:extension:manifest");
var id = rdf.GetResource(EM_NS("id")); var id = rdf.GetResource(EM_NS("id"));
// XXXben - do version check // Check the target application range specified by the extension metadata.
if (this._ds.isCompatible(aDataSource, id)) {
var idLiteral = aDataSource.GetTarget(manifestRoot, id, true); var idLiteral = aDataSource.GetTarget(manifestRoot, id, true);
return idLiteral.QueryInterface(Components.interfaces.nsIRDFLiteral).Value; return idLiteral.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
}
return null;
}, },
_stageExtensionXPI: function (aZipReader, aExtensionID, aInstallProfile) _stageExtensionXPI: function (aZipReader, aExtensionID, aInstallProfile)
@ -1042,6 +901,10 @@ nsExtensionManager.prototype = {
} }
}; };
///////////////////////////////////////////////////////////////////////////////
//
// nsExtensionItemUpdater
//
function nsExtensionItemUpdater(aItems, aTargetAppID, aTargetAppVersion) function nsExtensionItemUpdater(aItems, aTargetAppID, aTargetAppVersion)
{ {
this._items = aItems; this._items = aItems;
@ -1069,6 +932,27 @@ nsExtensionItemUpdater.prototype = {
var wsdlURI = pref.getComplexValue(PREF_UPDATE_EXT_WSDL_URI, var wsdlURI = pref.getComplexValue(PREF_UPDATE_EXT_WSDL_URI,
Components.interfaces.nsIPrefLocalizedString).data; Components.interfaces.nsIPrefLocalizedString).data;
wspFactory.createProxyAsync(wsdlURI, "VersionCheck", "", true, this); 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,9 +963,11 @@ nsExtensionItemUpdater.prototype = {
{ {
for (var i = 0; i < this._items.length; ++i) { for (var i = 0; i < this._items.length; ++i) {
var e = this._items[i]; var e = this._items[i];
if (!e.updateRDF) {
this._os.notifyObservers(null, "Update:Extension:Item-Started", e.name + " " + e.version); this._os.notifyObservers(null, "Update:Extension:Item-Started", e.name + " " + e.version);
this._proxy.getNewestExtension(eval(e.objectSource), this._appID, this._appVersion); 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); 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) getNewestExtensionCallback: function (aResult)
{ {
var item = aResult; var item = aResult;
dump("*** result = " + item.toSource() + "\n");
try { try {
item.name.toString(); // XXXben This is a lame hack to cause an exception to be 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 // thrown for null values when there is no newer extension
// or something else bad happens on the server that we // or something else bad happens on the server that we
// don't recognize. // don't recognize.
this._os.notifyObservers(aResult, "Update:Extension:Item-Ended", "goat"); this._os.notifyObservers(aResult, "Update:Extension:Item-Ended", "");
++this._updateCount; ++this._updateCount;
} }
catch (e) { catch (e) {
} }
this._checkForDone();
},
_checkForDone: function ()
{
if (--this._count == 0) { if (--this._count == 0) {
var pref = Components.classes["@mozilla.org/preferences-service;1"] var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch); .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() function nsExtensionsDataSource()
{ {
this._rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"] this._rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
@ -1161,6 +1140,29 @@ nsExtensionsDataSource.prototype = {
return aResourceURI.substr("urn:mozilla:extension:".length, aResourceURI.length); 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) getIncompatibleItemList: function (aAppID, aAppVersion)
{ {
var items = []; var items = [];
@ -1172,14 +1174,13 @@ nsExtensionsDataSource.prototype = {
var elements = ctr.GetElements(); var elements = ctr.GetElements();
while (elements.hasMoreElements()) { while (elements.hasMoreElements()) {
var e = elements.getNext().QueryInterface(Components.interfaces.nsIRDFResource); 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"] var item = Components.classes["@mozilla.org/updates/item;1"]
.createInstance(Components.interfaces.nsIUpdateItem); .createInstance(Components.interfaces.nsIUpdateItem);
item.init(id, this.getExtensionProperty(id, "version"), item.init(id, this.getExtensionProperty(id, "version"),
this.getExtensionProperty(id, "name"), this.getExtensionProperty(id, "name"),
-1, "", "", -1, "", "", this.getExtensionProperty(id, "updateURL"),
Components.interfaces.nsIUpdateItem.TYPE_EXTENSION); // XXXben Components.interfaces.nsIUpdateItem.TYPE_EXTENSION); // XXXben
items.push(item); items.push(item);
} }
@ -1195,7 +1196,8 @@ nsExtensionsDataSource.prototype = {
.createInstance(Components.interfaces.nsIUpdateItem); .createInstance(Components.interfaces.nsIUpdateItem);
item.init(aItemID, this.getExtensionProperty(aItemID, "version"), item.init(aItemID, this.getExtensionProperty(aItemID, "version"),
this.getExtensionProperty(aItemID, "name"), this.getExtensionProperty(aItemID, "name"),
-1, "", "", aType); -1, "", "", this.getExtensionProperty(aItemID, "updateURL"),
aType);
items.push(item); items.push(item);
} }
else { else {
@ -1211,7 +1213,8 @@ nsExtensionsDataSource.prototype = {
.createInstance(Components.interfaces.nsIUpdateItem); .createInstance(Components.interfaces.nsIUpdateItem);
item.init(id, this.getExtensionProperty(id, "version"), item.init(id, this.getExtensionProperty(id, "version"),
this.getExtensionProperty(id, "name"), this.getExtensionProperty(id, "name"),
-1, "", "", aType); -1, "", "",
this.getExtensionProperty(id, "updateURL"), aType);
items.push(item); items.push(item);
} }
} }
@ -1351,11 +1354,28 @@ nsExtensionsDataSource.prototype = {
var extension = this._rdf.GetResource("urn:mozilla:extension:" + aExtensionID); var extension = this._rdf.GetResource("urn:mozilla:extension:" + aExtensionID);
ctr.RemoveElement(extension, true); ctr.RemoveElement(extension, true);
// Clean the extension resource
this._removeExtensionMetadata(aExtensionID);
this.setExtensionProperty(aExtensionID, this._emR("toBeUninstalled"), this.setExtensionProperty(aExtensionID, this._emR("toBeUninstalled"),
this._emL("true"), this._emL("true"),
this.isProfileExtension(aExtensionID)); 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) loadExtensions: function (aProfile)
{ {
var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties); var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);

Просмотреть файл

@ -1,173 +0,0 @@
// XXXben - this is not used by anything, it's just a backup of some code I did have in nsExtensionManager.js.in
function nsExtensionUpdater2(aExtensions,
aTargetAppID, aTargetAppVersion)
{
this._extensions = aExtensions;
this._count = aExtensions.length;
this._appID = aTargetAppID;
this._appVersion = aTargetAppVersion;
this._os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
}
nsExtensionUpdater2.prototype = {
_extensionSchemaType: null,
loadSchema: function ()
{
function SchemaLoaderListener(aUpdater)
{
this._updater = aUpdater;
}
SchemaLoaderListener.prototype = {
onLoad: function (aSchema)
{
dump("*** schema loaded = " + aSchema + "\n");
var count = aSchema.typeCount;
for (var i = 0; i < count; ++i) {
var type = aSchema.getTypeByIndex(i);
dump("*** schema type = " + type.name + "\n");
}
this._updater._extensionSchemaType = aSchema.getTypeByName("Extension");
this._updater._schemaLoaded();
},
onError: function (aStatus, aMessage)
{
dump("*** schema load error " + aStatus + ", msg = " + aMessage + "\n");
}
};
var schemaLoader = Components.classes["@mozilla.org/xmlextras/schemas/schemaloader;1"]
.createInstance(Components.interfaces.nsISchemaLoader);
var schemaLoaderListener = new SchemaLoaderListener(this);
schemaLoader.loadAsync("http://www.bengoodger.com/software/mb/umo/types.xsd",
schemaLoaderListener);
},
_schemaLoaded: function ()
{
var call = Components.classes["@mozilla.org/xmlextras/soap/call;1"]
.createInstance(Components.interfaces.nsISOAPCall);
call.transportURI = "http://localhost:8080/axis/services/VersionCheck";
for (var i = 0; i < this._extensions.length; ++i) {
var e = this._extensions[i];
var params = [this._createParam("in0", e, this._extensionSchemaType),
this._createParam("in1", this._appID, null),
this._createParam("in2", this._appVersion, null)];
call.encode(0, "getNewestExtension", "urn:VersionCheck", 0, null, params.length, params);
var response = call.invoke();
dump("*** response = " + response + "\n");
var count = { };
var params;
response.getParameters(false, count, params);
dump("*** params = " + count.value + "\n");
for (var j = 0; j < count.value; ++j) {
var param = params[j];
dump("*** param = " + param.name + ", parm = " + param + ", element = " + param.element + ", value = " + param.value + "\n");
// var v = param.value.QueryInterface(Components.interfaces.nsIVariant);
}
}
},
_walkKids: function (e)
{
for (var i = 0; i < e.childNodes.length; ++i) {
var kid = e.childNodes[i];
dump("<" + kid.nodeName);
for (var k = 0; k < kid.attributes.length; ++k)
dump(" " + kid.attributes[k] + "=" + kid.getAttribute(kid.attributes[k]));
if (kid.hasChildNodes()) {
this._walkKids(kid);
dump("</" + kid.nodeName);
}
else
dump(">");
}
},
_createParam: function (aParamName, aParamValue, aParamSchemaType)
{
var param = Components.classes["@mozilla.org/xmlextras/soap/parameter;1"]
.createInstance(Components.interfaces.nsISOAPParameter);
param.name = aParamName;
param.namespaceURI = "urn:VersionCheck";
if (aParamSchemaType)
param.schemaType = aParamSchemaType;
param.value = aParamValue;
return param;
},
};
// this will come back later when we do custom update urls
getUpdateURLs: function (aExtensionID)
{
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
var appID = pref.getCharPref(PREF_EM_APP_ID);
var urls = [];
if (aExtensionID) {
var updateURL = this._getUpdateURLInternal(aExtensionID);
updateURL = updateURL.replace(/%APP%/g, escape(appID));
updateURL = updateURL.replace(/%ITEM%/g, escape(aExtensionID));
urls.push(updateURL);
}
else {
var ctr = Components.classes["@mozilla.org/rdf/container;1"]
.createInstance(Components.interfaces.nsIRDFContainer);
ctr.Init(this, this._rdf.GetResource("urn:mozilla:extension:root"));
var urlHash = { };
var e = ctr.GetElements();
while (e.hasMoreElements()) {
var r = e.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
var extensionID = r.Value.substr("urn:mozilla:extension:".length, r.Value.length);
var updateURL = this._getUpdateURLInternal(extensionID);
if (!(updateURL in urlHash))
urlHash[updateURL] = [];
urlHash[updateURL].push(extensionID);
}
for (var url in urlHash) {
var guidString = "";
var urlCount = urlHash[url].length;
for (var i = 0; i < urlCount; ++i)
guidString += escape(urlHash[url][i] + (i < urlCount - 1 ? "," : ""));
url = url.replace(/%APP%/g, appID);
url = url.replace(/%ITEM%/g, guidString);
urls.push(url);
}
}
return urls;
},
_getUpdateURLInternal: function (aExtensionID)
{
var updateURL;
var extension = this._rdf.GetResource("urn:mozilla:extension:" + aExtensionID);
if (this.hasArcOut(extension, this._emR("updateURL"))) {
updateURL = this.GetTarget(extension, this._emR("updateURL"), true);
if (updateURL)
updateURL = updateURL.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
}
if (!updateURL) {
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
updateURL = pref.getCharPref(PREF_EM_DEFAULTUPDATEURL);
}
return updateURL;
},

Просмотреть файл

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

Просмотреть файл

@ -94,10 +94,28 @@
</wizardpage> </wizardpage>
<wizardpage id="noupdates" pageid="noupdates" next="finished" <wizardpage id="noupdates" pageid="noupdates"
label="&noupdates.title;" label="&noupdates.title;"
onpageshow="gNoUpdatesPage.onPageShow();" onpageshow="gNoUpdatesPage.onPageShow();">
onpageadvanced="gNoUpdatesPage.onPageAdvanced();"> <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>
<wizardpage id="found" pageid="found" next="installing" <wizardpage id="found" pageid="found" next="installing"

Просмотреть файл

@ -22,10 +22,6 @@
<!ENTITY noupdates.title "No Updates Found"> <!ENTITY noupdates.title "No Updates Found">
<!ENTITY noupdates.intro.user.label "&brandShortName; was not able to find any available updates."> <!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 - <!ENTITY noupdates.intro.mismatch.label "&brandShortName; was not able to find any available updates -
compatible versions may not be available at this time."> compatible versions may not be available at this time.">

Просмотреть файл

@ -49,6 +49,7 @@ interface nsIUpdateItem : nsISupports
readonly attribute long row; readonly attribute long row;
readonly attribute wstring updateURL; readonly attribute wstring updateURL;
readonly attribute wstring iconURL; readonly attribute wstring iconURL;
readonly attribute wstring updateRDF;
const unsigned short TYPE_ANY = 0x01; const unsigned short TYPE_ANY = 0x01;
const unsigned short TYPE_APP = 0x02; const unsigned short TYPE_APP = 0x02;
@ -62,7 +63,7 @@ interface nsIUpdateItem : nsISupports
void init(in string aID, in string aVersion, in wstring aName, void init(in string aID, in string aVersion, in wstring aName,
in long aRow, in wstring aUpdateURL, in wstring aIconURL, in long aRow, in wstring aUpdateURL, in wstring aIconURL,
in long aType); in wstring aUpdateRDF, in long aType);
readonly attribute wstring objectSource; readonly attribute wstring objectSource;
}; };
@ -94,3 +95,12 @@ interface nsIUpdateService : nsISupports
readonly attribute wstring appUpdateURL; 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);
};

Просмотреть файл

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