diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index fe871d1060ed..5f18e2d85d65 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -134,7 +134,6 @@ @BINPATH@/components/directory.xpt @BINPATH@/components/docshell.xpt @BINPATH@/components/dom.xpt -@BINPATH@/components/dom_apps.xpt @BINPATH@/components/dom_base.xpt @BINPATH@/components/dom_battery.xpt @BINPATH@/components/dom_canvas.xpt @@ -374,8 +373,6 @@ #endif @BINPATH@/components/TelemetryPing.js @BINPATH@/components/TelemetryPing.manifest -@BINPATH@/components/Webapps.js -@BINPATH@/components/Webapps.manifest ; Modules @BINPATH@/modules/* diff --git a/dom/Makefile.in b/dom/Makefile.in index bcc9c58edc43..62c97c715934 100644 --- a/dom/Makefile.in +++ b/dom/Makefile.in @@ -66,7 +66,6 @@ DIRS = \ interfaces/notification \ interfaces/svg \ interfaces/smil \ - interfaces/apps \ $(NULL) DIRS += \ diff --git a/dom/base/Makefile.in b/dom/base/Makefile.in index 0fb5b1cbc8c1..a4d715ff0268 100644 --- a/dom/base/Makefile.in +++ b/dom/base/Makefile.in @@ -52,13 +52,7 @@ EXTRA_PP_COMPONENTS = \ ConsoleAPI.manifest \ $(NULL) -EXTRA_COMPONENTS = \ - Webapps.js \ - Webapps.manifest \ - $(NULL) - EXTRA_JS_MODULES = ConsoleAPIStorage.jsm \ - Webapps.jsm \ $(NULL) XPIDLSRCS = \ diff --git a/dom/base/Webapps.js b/dom/base/Webapps.js deleted file mode 100644 index f18a48bd238b..000000000000 --- a/dom/base/Webapps.js +++ /dev/null @@ -1,347 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Open Web Apps. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Fabrice Desré - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; -const Cr = Components.results; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -function WebappsRegistry() { - this.messages = ["Webapps:Install:Return:OK", "Webapps:Install:Return:KO", - "Webapps:Uninstall:Return:OK", "Webapps:Uninstall:Return:KO", - "Webapps:Enumerate:Return:OK", "Webapps:Enumerate:Return:KO"]; - - this.mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsIFrameMessageManager); - - this.messages.forEach((function(msgName) { - this.mm.addMessageListener(msgName, this); - }).bind(this)); - - this._window = null; - this._id = this._getRandomId(); - this._callbacks = []; -} - -WebappsRegistry.prototype = { - _onerror: null, - _oninstall: null, - _onuninstall: null, - - /** from https://developer.mozilla.org/en/OpenWebApps/The_Manifest - * only the name property is mandatory - */ - checkManifest: function(aManifest, aInstallOrigin) { - // TODO : check for install_allowed_from - if (aManifest.name == undefined) - return false; - - if (aManifest.installs_allowed_from) { - ok = false; - aManifest.installs_allowed_from.forEach(function(aOrigin) { - if (aOrigin == "*" || aOrigin == aInstallOrigin) - ok = true; - }); - return ok; - } - return true; - }, - - getCallbackId: function(aCallback) { - let id = "id" + this._getRandomId(); - this._callbacks[id] = aCallback; - return id; - }, - - getCallback: function(aId) { - return this._callbacks[aId]; - }, - - removeCallback: function(aId) { - if (this._callbacks[aId]) - delete this._callbacks[aId]; - }, - - _getRandomId: function() { - return Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString(); - }, - - _convertAppsArray: function(aApps) { - let apps = new Array(); - for (let i = 0; i < aApps.length; i++) { - let app = aApps[i]; - apps.push(new WebappsApplication(app.origin, app.manifest, app.receipt, app.installOrigin, app.installTime)); - } - return apps; - }, - - set oninstall(aCallback) { - if (this.hasPrivileges) - this._oninstall = aCallback; - else - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; - }, - - set onuninstall(aCallback) { - if (this.hasPrivileges) - this._onuninstall = aCallback; - else - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; - }, - - set onerror(aCallback) { - this._onerror = aCallback; - }, - - receiveMessage: function(aMessage) { - let msg = aMessage.json; - if (!(msg.oid == this._id || aMessage.name == "Webapps:Install:Return:OK" || aMessage.name == "Webapps:Uninstall:Return:OK")) - return - let app = msg.app; - let cb; - switch (aMessage.name) { - case "Webapps:Install:Return:OK": - if (this._oninstall) - this._oninstall.handleEvent(new WebappsApplication(app.origin, app.manifest, app.receipt, - app.installOrigin, app.installTime)); - break; - case "Webapps:Install:Return:KO": - if (this._onerror) - this._onerror.handleEvent(new RegistryError(Ci.nsIDOMApplicationRegistryError.DENIED)); - break; - case "Webapps:Uninstall:Return:OK": - if (this._onuninstall) - this._onuninstall.handleEvent(new WebappsApplication(msg.origin, null, null, null, 0)); - break; - case "Webapps:Uninstall:Return:KO": - if (this._onerror) - this._onerror.handleEvent(new RegistryError(Ci.nsIDOMApplicationRegistryError.PERMISSION_DENIED)); - break; - case "Webapps:Enumerate:Return:OK": - cb = this.getCallback(msg.callbackID); - if (cb.success) { - let apps = this._convertAppsArray(msg.apps); - cb.success.handleEvent(apps, apps.length); - } - break; - case "Webapps:Enumerate:Return:KO": - cb = this.getCallback(msg.callbackID); - if (cb.error) - cb.error.handleEvent(new RegistryError(Ci.nsIDOMApplicationRegistryError.PERMISSION_DENIED)); - break; - } - this.removeCallback(msg.callbackID); - }, - - _fireError: function(aCode) { - if (!this._onerror) - return; - this._onerror.handleEvent(new RegistryError(aCode)); - }, - - _getOrigin: function(aURL) { - let uri = Services.io.newURI(aURL, null, null); - return uri.prePath; - }, - - // nsIDOMApplicationRegistry implementation - - install: function(aURL, aReceipt) { - let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); - xhr.open("GET", aURL, true); - - xhr.addEventListener("load", (function() { - if (xhr.status == 200) { - try { - let installOrigin = this._getOrigin(this._window.location.href); - let manifest = JSON.parse(xhr.responseText, installOrigin); - if (!this.checkManifest(manifest, installOrigin)) { - this._fireError(Ci.nsIDOMApplicationRegistryError.INVALID_MANIFEST); - } else { - this.mm.sendAsyncMessage("Webapps:Install", { app: { installOrigin: installOrigin, - origin: this._getOrigin(aURL), - manifest: manifest, - receipt: aReceipt }, - from: this._window.location.href, - oid: this._id }); - } - } catch(e) { - this._fireError(Ci.nsIDOMApplicationRegistryError.MANIFEST_PARSE_ERROR); - } - } - else { - this._fireError(Ci.nsIDOMApplicationRegistryError.MANIFEST_URL_ERROR); - } - }).bind(this), false); - - xhr.addEventListener("error", (function() { - this._fireError(Ci.nsIDOMApplicationRegistryError.NETWORK_ERROR); - }).bind(this), false); - - xhr.send(null); - }, - - uninstall: function(aOrigin) { - if (this.hasPrivileges) - this.mm.sendAsyncMessage("Webapps:Uninstall", { from: this._window.location.href, - origin: aOrigin, - oid: this._id }); - else - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; - }, - - launch: function(aOrigin) { - this.mm.sendAsyncMessage("Webapps:Launch", { origin: aOrigin, - from: this._window.location.href}); - }, - - enumerate: function(aSuccess, aError) { - this.mm.sendAsyncMessage("Webapps:Enumerate", { from: this._window.location.href, - origin: this._getOrigin(this._window.location.href), - oid: this._id, - callbackID: this.getCallbackId({ success: aSuccess, error: aError }) }); - }, - - handleEvent: function(aEvent) { - if (aEvent.type == "unload") { - // remove all callbacks and event handlers so we don't call anything on a cleared scope - try { - this._oninstall = null; - this._onuninstall = null; - this._onerror = null; - this._callbacks = []; - } catch(e) { - dump("WebappsRegistry error:" + e + "\n"); - } - } - }, - - // nsIDOMGlobalPropertyInitializer implementation - init: function(aWindow) { - dump("DOMApplicationRegistry::init() " + aWindow + "\n"); - this._window = aWindow; - this._window.addEventListener("unload", this, false); - this._window.appId = this._id; - let from = Services.io.newURI(this._window.location.href, null, null); - let perm = Services.perms.testExactPermission(from, "webapps-manage"); - - //only pages with perm set and chrome or about pages can uninstall, enumerate all set oninstall an onuninstall - this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION || from.schemeIs("chrome") || from.schemeIs("about"); - }, - - classID: Components.ID("{fff440b3-fae2-45c1-bf03-3b5a2e432270}"), - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMApplicationRegistry, Ci.nsIDOMGlobalPropertyInitializer]), - - classInfo: XPCOMUtils.generateCI({classID: Components.ID("{fff440b3-fae2-45c1-bf03-3b5a2e432270}"), - contractID: "@mozilla.org/webapps;1", - interfaces: [Ci.nsIDOMApplicationRegistry], - flags: Ci.nsIClassInfo.DOM_OBJECT, - classDescription: "Webapps Registry"}) -} - -function WebappsApplication(aOrigin, aManifest, aReceipt, aInstallOrigin, aInstallTime) { - this._origin = aOrigin; - this._manifest = aManifest; - this._receipt = aReceipt; - this._installOrigin = aInstallOrigin; - this._installTime = aInstallTime; -} - -WebappsApplication.prototype = { - _origin: null, - _manifest: null, - _receipt: null, - _installOrigin: null, - _installTime: 0, - - get origin() { - return this._origin; - }, - - get manifest() { - return this._manifest; - }, - - get receipt() { - return this._receipt; - }, - - get installOrigin() { - return this._installOrigin; - }, - - get installTime() { - return this._installTime; - }, - - classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"), - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMApplication]), - - classInfo: XPCOMUtils.generateCI({classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"), - contractID: "@mozilla.org/webapps/application;1", - interfaces: [Ci.nsIDOMApplication], - flags: Ci.nsIClassInfo.DOM_OBJECT, - classDescription: "Webapps Application"}) -} - -function RegistryError(aCode) { - this._code = aCode; -} - -RegistryError.prototype = { - _code: null, - - get code() { - return this._code; - }, - - classID: Components.ID("{b4937718-11a3-400b-a69f-ab442a418569}"), - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMApplicationRegistryError]), - - classInfo: XPCOMUtils.generateCI({classID: Components.ID("{b4937718-11a3-400b-a69f-ab442a418569}"), - contractID: "@mozilla.org/webapps/error;1", - interfaces: [Ci.nsIDOMApplicationRegistryError], - flags: Ci.nsIClassInfo.DOM_OBJECT, - classDescription: "Webapps Registry Error"}) -} - -const NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsRegistry, WebappsApplication, RegistryError]); - diff --git a/dom/base/Webapps.jsm b/dom/base/Webapps.jsm deleted file mode 100644 index a216057f7e59..000000000000 --- a/dom/base/Webapps.jsm +++ /dev/null @@ -1,380 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Mobile Browser. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Fabrice Desré - * Mark Finkle - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -const Cu = Components.utils; -const Cc = Components.classes; -const Ci = Components.interfaces; - -let EXPORTED_SYMBOLS = ["DOMApplicationRegistry", "DOMApplicationManifest"]; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -XPCOMUtils.defineLazyGetter(this, "NetUtil", function() { - Cu.import("resource://gre/modules/NetUtil.jsm"); - return NetUtil; -}); - -let DOMApplicationRegistry = { - appsDir: null, - appsFile: null, - webapps: { }, - - init: function() { - this.mm = Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIFrameMessageManager); - let messages = ["Webapps:Install", "Webapps:Uninstall", - "Webapps:Enumerate", "Webapps:Launch"]; - - messages.forEach((function(msgName) { - this.mm.addMessageListener(msgName, this); - }).bind(this)); - - let file = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("ProfD", Ci.nsIFile); - file.append("webapps"); - if (!file.exists() || !file.isDirectory()) { - file.create(Ci.nsIFile.DIRECTORY_TYPE, 0700); - } - this.appsDir = file; - this.appsFile = file.clone(); - this.appsFile.append("webapps.json"); - if (!this.appsFile.exists()) - return; - - try { - let channel = NetUtil.newChannel(this.appsFile); - channel.contentType = "application/json"; - let self = this; - NetUtil.asyncFetch(channel, function(aStream, aResult) { - if (!Components.isSuccessCode(aResult)) { - Cu.reportError("DOMApplicationRegistry: Could not read from json file " + this.appsFile.path); - return; - } - - // Read json file into a string - let data = null; - try { - self.webapps = JSON.parse(NetUtil.readInputStreamToString(aStream, aStream.available()) || ""); - aStream.close(); - } catch (ex) { - Cu.reportError("DOMApplicationRegistry: Could not parse JSON: " + ex); - } - }); - } catch (ex) { - Cu.reportError("DOMApplicationRegistry: Could not read from " + aFile.path + " : " + ex); - } - }, - - receiveMessage: function(aMessage) { - let msg = aMessage.json; - let from = Services.io.newURI(msg.from, null, null); - let perm = Services.perms.testExactPermission(from, "webapps-manage"); - - //only pages with perm set and chrome or about pages can uninstall, enumerate all set oninstall an onuninstall - let hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION || from.schemeIs("chrome") || from.schemeIs("about"); - - switch (aMessage.name) { - case "Webapps:Install": - // always ask for UI to install - Services.obs.notifyObservers(this, "webapps-ask-install", JSON.stringify(msg)); - break; - case "Webapps:Uninstall": - if (hasPrivileges) - this.uninstall(msg); - break; - case "Webapps:Launch": - Services.obs.notifyObservers(this, "webapps-launch", JSON.stringify(msg)); - break; - case "Webapps:Enumerate": - if (hasPrivileges) - this.enumerateAll(msg) - else - this.enumerate(msg); - break; - } - }, - - _writeFile: function ss_writeFile(aFile, aData, aCallbak) { - // Initialize the file output stream. - let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); - ostream.init(aFile, 0x02 | 0x08 | 0x20, 0600, ostream.DEFER_OPEN); - - // Obtain a converter to convert our data to a UTF-8 encoded input stream. - let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter); - converter.charset = "UTF-8"; - - // Asynchronously copy the data to the file. - let istream = converter.convertToInputStream(aData); - NetUtil.asyncCopy(istream, ostream, function(rc) { - if (aCallbak) - aCallbak(); - }); - }, - - // clones a app object, without the manifest - _cloneAppObject: function(aApp) { - let clone = { - installOrigin: aApp.installOrigin, - origin: aApp.origin, - receipt: aApp.receipt, - installTime: aApp.installTime - }; - return clone; - }, - - denyInstall: function(aData) { - this.mm.sendAsyncMessage("Webapps:Install:Return:KO", aData); - }, - - confirmInstall: function(aData) { - let app = aData.app; - let id = this._appId(app.origin); - - // install an application again is considered as an update - if (id) { - let dir = this.appsDir.clone(); - dir.append(id); - try { - dir.remove(true); - } catch(e) { - } - } - else { - let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); - id = uuidGenerator.generateUUID().toString(); - } - - let dir = this.appsDir.clone(); - dir.append(id); - dir.create(Ci.nsIFile.DIRECTORY_TYPE, 0700); - - let manFile = dir.clone(); - manFile.append("manifest.json"); - this._writeFile(manFile, JSON.stringify(app.manifest)); - - this.webapps[id] = this._cloneAppObject(app); - delete this.webapps[id].manifest; - this.webapps[id].installTime = (new Date()).getTime() - - this._writeFile(this.appsFile, JSON.stringify(this.webapps), (function() { - this.mm.sendAsyncMessage("Webapps:Install:Return:OK", aData); - }).bind(this)); - }, - - _appId: function(aURI) { - for (let id in this.webapps) { - if (this.webapps[id].origin == aURI) - return id; - } - return null; - }, - - _readManifest: function(aId) { - let file = this.appsDir.clone(); - file.append(aId); - file.append("manifest.json"); - let data = ""; - let fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream); - var cstream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(Ci.nsIConverterInputStream); - fstream.init(file, -1, 0, 0); - cstream.init(fstream, "UTF-8", 0, 0); - let (str = {}) { - let read = 0; - do { - read = cstream.readString(0xffffffff, str); // read as much as we can and put it in str.value - data += str.value; - } while (read != 0); - } - cstream.close(); // this closes fstream - try { - return JSON.parse(data); - } catch(e) { - return null; - } - }, - - uninstall: function(aData) { - for (let id in this.webapps) { - let app = this.webapps[id]; - if (app.origin == aData.origin) { - delete this.webapps[id]; - this._writeFile(this.appsFile, JSON.stringify(this.webapps)); - let dir = this.appsDir.clone(); - dir.append(id); - try { - dir.remove(true); - } catch (e) { - } - this.mm.sendAsyncMessage("Webapps:Uninstall:Return:OK", aData); - } - } - }, - - enumerate: function(aData) { - aData.apps = []; - - let id = this._appId(aData.origin); - // if it's an app, add itself to the result - if (id) { - let app = this._cloneAppObject(this.webapps[id]); - app.manifest = this._readManifest(id); - aData.apps.push(app); - } - - // check if it's a store. - let isStore = false; - for (id in this.webapps) { - let app = this._cloneAppObject(this.webapps[id]); - if (app.installOrigin == aData.origin) { - isStore = true; - break; - } - } - - // add all the apps from this store - if (isStore) { - for (id in this.webapps) { - let app = this._cloneAppObject(this.webapps[id]); - if (app.installOrigin == aData.origin) { - app.manifest = this._readManifest(id); - aData.apps.push(app); - } - } - } - - this.mm.sendAsyncMessage("Webapps:Enumerate:Return:OK", aData); - }, - - denyEnumerate: function(aData) { - this.mm.sendAsyncMessage("Webapps:Enumerate:Return:KO", aData); - }, - - enumerateAll: function(aData) { - aData.apps = []; - - for (id in this.webapps) { - let app = this._cloneAppObject(this.webapps[id]); - app.manifest = this._readManifest(id); - aData.apps.push(app); - } - - this.mm.sendAsyncMessage("Webapps:Enumerate:Return:OK", aData); - }, - - getManifestFor: function(aOrigin) { - let id = this._appId(aOrigin); - if (!id) - return null; - return this._readManifest(id); - } -}; - -/** - * Helper object to access manifest information with locale support - */ -DOMApplicationManifest = function(aManifest, aOrigin) { - this._origin = Services.io.newURI(aOrigin, null, null); - this._manifest = aManifest; - let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry) - .QueryInterface(Ci.nsIToolkitChromeRegistry); - let locale = chrome.getSelectedLocale("browser").toLowerCase(); - this._localeRoot = this._manifest; - - if (this._manifest.locales && this._manifest.locales[locale]) { - this._localeRoot = this._manifest.locales[locale]; - } - else if (this._manifest.locales) { - // try with the language part of the locale ("en" for en-GB) only - let lang = locale.split('-')[0]; - if (land != locale && this._manifest.locales[lang]) - this._localeRoot = this._manifest.locales[lang]; - } -} - -DOMApplicationManifest.prototype = { - _localeProp: function(aProp) { - if (this._localeRoot[aProp] != undefined) - return this._localeRoot[aProp]; - return this._manifest[aProp]; - }, - - get name() { - return this._localeProp("name"); - }, - - get description() { - return this._localeProp("description"); - }, - - get version() { - return this._localeProp("version"); - }, - - get launch_path() { - return this._localeProp("launch_path"); - }, - - get developer() { - return this._localeProp("developer"); - }, - - get icons() { - return this._localeProp("icons"); - }, - - iconURLForSize: function(aSize) { - let icons = this._localeProp("icons"); - if (!icons) - return null; - let dist = 100000; - let icon = null; - for (let size in icons) { - let iSize = parseInt(size); - if (Math.abs(iSize - aSize) < dist) { - icon = this._origin.resolve(icons[size]); - dist = Math.abs(iSize - aSize); - } - } - return icon; - }, - - fullLaunchPath: function() { - let launchPath = this._localeProp("launch_path"); - return this._origin.resolve(launchPath ? launchPath : ""); - } -} - -DOMApplicationRegistry.init(); diff --git a/dom/base/Webapps.manifest b/dom/base/Webapps.manifest deleted file mode 100644 index e1bf05ae57c7..000000000000 --- a/dom/base/Webapps.manifest +++ /dev/null @@ -1,10 +0,0 @@ -# Webapps.js -component {fff440b3-fae2-45c1-bf03-3b5a2e432270} Webapps.js -contract @mozilla.org/webapps;1 {fff440b3-fae2-45c1-bf03-3b5a2e432270} -category JavaScript-navigator-property mozApps @mozilla.org/webapps;1 - -component {723ed303-7757-4fb0-b261-4f78b1f6bd22} Webapps.js -contract @mozilla.org/webapps/application;1 {723ed303-7757-4fb0-b261-4f78b1f6bd22} - -component {b4937718-11a3-400b-a69f-ab442a418569} Webapps.js -contract @mozilla.org/webapps/error;1 {b4937718-11a3-400b-a69f-ab442a418569} diff --git a/dom/interfaces/apps/nsIDOMApplicationRegistry.idl b/dom/interfaces/apps/nsIDOMApplicationRegistry.idl deleted file mode 100644 index 8fe57a7992bf..000000000000 --- a/dom/interfaces/apps/nsIDOMApplicationRegistry.idl +++ /dev/null @@ -1,91 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is web apps. - * - * The Initial Developer of the Original Code is Mozilla Foundation - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Andreas Gal (Original Author) - * Fabrice Desré - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "domstubs.idl" - -//interface nsIArray; - -[scriptable, uuid(e0c271cb-266b-48c9-a7e4-96590b445c26)] -interface nsIDOMApplicationRegistryError : nsISupports -{ - const unsigned short DENIED = 1; - const unsigned short PERMISSION_DENIED = 2; - const unsigned short MANIFEST_URL_ERROR = 3; - const unsigned short NETWORK_ERROR = 4; - const unsigned short MANIFEST_PARSE_ERROR = 5; - const unsigned short INVALID_MANIFEST = 6; - - readonly attribute short code; -}; - -[scriptable, uuid(a6856a3d-dece-43ce-89b9-72dba07f4246)] -interface nsIDOMApplication : nsISupports -{ - readonly attribute jsval manifest; - readonly attribute DOMString receipt; - readonly attribute DOMString origin; - readonly attribute DOMString installOrigin; - readonly attribute unsigned long installTime; -}; - -[scriptable, function, uuid(be170df5-9154-463b-9197-10a6195eba52)] -interface nsIDOMApplicationRegistryEnumerateCallback : nsISupports -{ - void handleEvent([array, size_is(count)] in nsIDOMApplication apps, - in unsigned long count); -}; - -[scriptable, function, uuid(ae0ed33d-35cf-443a-837b-a6cebf16bd49)] -interface nsIDOMApplicationRegistryErrorCallback : nsISupports -{ - void handleEvent(in nsIDOMApplicationRegistryError error); -}; - -[scriptable, uuid(4070ea6f-dca1-4052-8bc6-7a9bcfc314ac)] -interface nsIDOMApplicationRegistry : nsISupports -{ - void install(in DOMString manifestUrl, - [optional] in DOMString receipt); - void uninstall(in DOMString origin); - void enumerate(in nsIDOMApplicationRegistryEnumerateCallback success, - [optional] in nsIDOMApplicationRegistryErrorCallback error); - void launch(in DOMString origin); - - attribute nsIDOMEventListener oninstall; - attribute nsIDOMEventListener onuninstall; - attribute nsIDOMEventListener onerror; -}; diff --git a/dom/interfaces/base/Makefile.in b/dom/interfaces/base/Makefile.in index 6db3e981e18e..8f35131893b7 100644 --- a/dom/interfaces/base/Makefile.in +++ b/dom/interfaces/base/Makefile.in @@ -57,7 +57,7 @@ SDK_XPIDLSRCS = \ XPIDLSRCS = \ nsIFrameRequestCallback.idl \ nsIBrowserDOMWindow.idl \ - nsIContentPermissionPrompt.idl \ + nsIContentPermissionPrompt.idl \ nsIContentPrefService.idl \ nsIContentURIGrouper.idl \ nsIDOMClientInformation.idl \ diff --git a/layout/printing/nsPrintData.cpp b/layout/printing/nsPrintData.cpp index 29ecae1efb8a..5247090e78bd 100644 --- a/layout/printing/nsPrintData.cpp +++ b/layout/printing/nsPrintData.cpp @@ -134,7 +134,7 @@ nsPrintData::~nsPrintData() void nsPrintData::OnStartPrinting() { if (!mOnStartSent) { - DoOnProgressChange(0, 0, true, nsIWebProgressListener::STATE_START|nsIWebProgressListener::STATE_IS_DOCUMENT|nsIWebProgressListener::STATE_IS_NETWORK); + DoOnProgressChange(0, 0, true, nsIWebProgressListener::STATE_START|nsIWebProgressListener::STATE_IS_DOCUMENT); mOnStartSent = true; } } @@ -142,18 +142,19 @@ void nsPrintData::OnStartPrinting() void nsPrintData::OnEndPrinting() { DoOnProgressChange(100, 100, true, nsIWebProgressListener::STATE_STOP|nsIWebProgressListener::STATE_IS_DOCUMENT); - DoOnProgressChange(100, 100, true, nsIWebProgressListener::STATE_STOP|nsIWebProgressListener::STATE_IS_NETWORK); } void -nsPrintData::DoOnProgressChange(PRInt32 aProgress, +nsPrintData::DoOnProgressChange(PRInt32 aProgess, PRInt32 aMaxProgress, bool aDoStartStop, PRInt32 aFlag) { + if (aProgess == 0) return; + for (PRInt32 i=0;iOnProgressChange(nsnull, nsnull, aProgress, aMaxProgress, aProgress, aMaxProgress); + wpl->OnProgressChange(nsnull, nsnull, aProgess, aMaxProgress, aProgess, aMaxProgress); if (aDoStartStop) { wpl->OnStateChange(nsnull, nsnull, aFlag, 0); } diff --git a/layout/printing/nsPrintData.h b/layout/printing/nsPrintData.h index 1c795a9bfa74..9a1543e88646 100644 --- a/layout/printing/nsPrintData.h +++ b/layout/printing/nsPrintData.h @@ -85,7 +85,7 @@ public: // Listener Helper Methods void OnEndPrinting(); void OnStartPrinting(); - void DoOnProgressChange(PRInt32 aProgress, + void DoOnProgressChange(PRInt32 aProgess, PRInt32 aMaxProgress, bool aDoStartStop, PRInt32 aFlag); diff --git a/mobile/xul/installer/package-manifest.in b/mobile/xul/installer/package-manifest.in index e284387564e0..b7b45aba7a11 100644 --- a/mobile/xul/installer/package-manifest.in +++ b/mobile/xul/installer/package-manifest.in @@ -277,6 +277,7 @@ @BINPATH@/components/xuldoc.xpt @BINPATH@/components/xultmpl.xpt @BINPATH@/components/zipwriter.xpt +@BINPATH@/components/openwebapps.xpt ; JavaScript components @BINPATH@/components/ConsoleAPI.manifest @@ -330,6 +331,7 @@ @BINPATH@/components/amContentHandler.js @BINPATH@/components/amWebInstallListener.js @BINPATH@/components/nsBlocklistService.js +@BINPATH@/components/OpenWebapps.manifest #ifdef MOZ_UPDATER @BINPATH@/components/nsUpdateService.manifest @@ -605,6 +607,7 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@ @BINPATH@/components/PromptService.js @BINPATH@/components/SessionStore.js @BINPATH@/components/Sidebar.js +@BINPATH@/components/OpenWebapps.js #ifdef MOZ_SAFE_BROWSING @BINPATH@/components/SafeBrowsing.js #endif diff --git a/toolkit/Makefile.in b/toolkit/Makefile.in index 8ba03f2a46c0..442c73a0d2a4 100644 --- a/toolkit/Makefile.in +++ b/toolkit/Makefile.in @@ -56,6 +56,7 @@ PARALLEL_DIRS = \ mozapps/plugins \ mozapps/shared \ mozapps/update \ + mozapps/webapps \ obsolete \ profile \ themes \ diff --git a/dom/interfaces/apps/Makefile.in b/toolkit/mozapps/webapps/Makefile.in similarity index 79% rename from dom/interfaces/apps/Makefile.in rename to toolkit/mozapps/webapps/Makefile.in index 9b8dc3c81cba..51cdd1790821 100644 --- a/dom/interfaces/apps/Makefile.in +++ b/toolkit/mozapps/webapps/Makefile.in @@ -11,14 +11,14 @@ # for the specific language governing rights and limitations under the # License. # -# The Original Code is web apps. +# The Original Code is the Open Web Apps. # -# The Initial Developer of the Original Code is Mozilla Foundation -# Portions created by the Initial Developer are Copyright (C) 2011 +# The Initial Developer of the Original Code is Ben Goodger. +# Portions created by the Initial Developer are Copyright (C) 2004 # the Initial Developer. All Rights Reserved. # # Contributor(s): -# Andreas Gal +# Fabrice Desré # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or @@ -34,20 +34,24 @@ # # ***** END LICENSE BLOCK ***** - -DEPTH = ../../.. -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -MODULE = dom -XPIDL_MODULE = dom_apps -GRE_MODULE = 1 +MODULE = openwebapps -XPIDLSRCS = \ - nsIDOMApplicationRegistry.idl \ - $(NULL) +XPIDLSRCS = OpenWebapps.idl + +EXTRA_COMPONENTS += \ + OpenWebapps.js \ + OpenWebapps.manifest \ + $(NULL) + +EXTRA_JS_MODULES = \ + OpenWebapps.jsm \ + $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/toolkit/mozapps/webapps/OpenWebapps.idl b/toolkit/mozapps/webapps/OpenWebapps.idl new file mode 100644 index 000000000000..1823f58878d1 --- /dev/null +++ b/toolkit/mozapps/webapps/OpenWebapps.idl @@ -0,0 +1,118 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Open Web Apps. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Fabrice Desré + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// IDL for https://developer.mozilla.org/en/OpenWebApps/The_JavaScript_API + +#include "nsISupports.idl" + +[scriptable, uuid(3b937eb5-679b-41e9-aefa-543849fa61dd)] +interface nsIOpenWebappsApplication : nsISupports { + attribute jsval manifest; + attribute DOMString origin; + attribute jsval install_data; + attribute DOMString install_origin; + attribute unsigned long install_time; +}; + +[scriptable, function, uuid(fa3ac1bb-ad7d-44d7-8585-9ecdf3782d65)] +interface nsIOpenWebappsSuccessInstalled : nsISupports { + void handle(in nsIOpenWebappsApplication application); +}; + +[scriptable, function, uuid(a8a83f45-4cbe-4806-b867-017554e30bd4)] +interface nsIOpenWebappsSuccessList : nsISupports { + void handle([array, size_is(count)] in nsIOpenWebappsApplication apps, + in unsigned long count); +}; + +[scriptable, function, uuid(75e44e3f-ccda-4497-af68-8abd3f5e1d7b)] +interface nsIOpenWebappsError : nsISupports { + attribute DOMString code; + attribute DOMString message; +}; + +[scriptable, function, uuid(8b29495e-a5e4-4e76-9af8-0f6fe97b8959)] +interface nsIOpenWebappsErrorCB : nsISupports { + void handle(in nsIOpenWebappsError error); +}; + +[scriptable, function, uuid(b86669ab-6a36-4ceb-a4bf-a980dd496144)] +interface nsIOpenWebappsSuccessEmpty : nsISupports { + void handle(); +}; + +[scriptable, function, uuid(a458afcf-eee9-42fb-bd90-75d5e41c0d9e)] +interface nsIOpenWebappsChangeCallback : nsISupports { + // what is either "add" when new apps are added to the repository, or + // "remove" when they are deleted. + void update(in DOMString what, [array, size_is(count)] in nsIOpenWebappsApplication apps, + in unsigned long count); +}; + +[scriptable, uuid(f3ec76a6-abca-4d90-b8c9-e221033068ef)] +interface nsIOpenWebappsMgmt : nsISupports { + void launch(in DOMString origin, + [optional] in nsIOpenWebappsSuccessEmpty onsuccess, + [optional] in nsIOpenWebappsErrorCB onerror); + + void list(in nsIOpenWebappsSuccessList onsuccess, + [optional] in nsIOpenWebappsErrorCB onerror); + + void uninstall(in DOMString origin, + in nsIOpenWebappsSuccessEmpty onsuccess, + [optional] in nsIOpenWebappsErrorCB onerror); + + long watchUpdates(in nsIOpenWebappsChangeCallback callback); + + void clearWatch(in long watchId); +}; + +[scriptable, uuid(cecd9de7-ea4e-45fd-8a01-a5861d9109ab)] +interface nsIOpenWebapps : nsISupports { + void install(in DOMString manifestURI, + [optional] in jsval install_data, + [optional] in nsIOpenWebappsSuccessEmpty onsuccess, + [optional] in nsIOpenWebappsErrorCB onerror); + + void amInstalled(in nsIOpenWebappsSuccessInstalled onsuccess, + [optional] in nsIOpenWebappsErrorCB onerror); + + void getInstalledBy(in nsIOpenWebappsSuccessList onsuccess, + [optional] in nsIOpenWebappsErrorCB onerror); + + readonly attribute nsIOpenWebappsMgmt mgmt; +}; diff --git a/toolkit/mozapps/webapps/OpenWebapps.js b/toolkit/mozapps/webapps/OpenWebapps.js new file mode 100644 index 000000000000..8a2a06b7ec82 --- /dev/null +++ b/toolkit/mozapps/webapps/OpenWebapps.js @@ -0,0 +1,296 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Open Web Apps. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Fabrice Desré + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +function OpenWebapps() { + this.messages = ["OpenWebapps:InstallDone", "OpenWebapps:InstallAborted", "OpenWebapps:GetInstalledBy:Return", + "OpenWebapps:AmInstalled:Return", "OpenWebapps:MgmtLaunch:Return", "OpenWebapps:MgmtList:Return", + "OpenWebapps:MgmtUninstall:Return"]; + + this.mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender); + + this.messages.forEach((function(msgName) { + this.mm.addMessageListener(msgName, this); + }).bind(this)); + + this._callbacks = []; + this._window = null; + this._watchId = 0; +} + +OpenWebapps.prototype = { + + /** from https://developer.mozilla.org/en/OpenWebApps/The_Manifest + * only the name property is mandatory + */ + checkManifest: function(aManifest) { + return ("name" in aManifest); + }, + + getCallbackId: function(aCallback) { + let id = "id" + this._getRandomId(); + this._callbacks[id] = aCallback; + return id; + }, + + getCallback: function(aId) { + return this._callbacks[aId]; + }, + + removeCallback: function(aId) { + if (this._callbacks[aId]) + delete this._callbacks[aId]; + }, + + _getRandomId: function() { + return Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString(); + }, + + _convertAppsArray: function(aApps) { + let apps = new Array(); + for (let i = 0; i < aApps.length; i++) { + let app = aApps[i]; + let xapp = Cc["@mozilla.org/openwebapps/application;1"].createInstance(Ci.nsIOpenWebappsApplication); + xapp.origin = app.origin; + xapp.manifest = app.manifest; + xapp.install_data = app.install_data; + xapp.install_origin = app.install_origin; + xapp.install_time = app.install_time; + apps.push(xapp); + } + return apps; + }, + + receiveMessage: function(aMessage) { + let msg = aMessage.json; + let callbacks = this.getCallback(msg.callbackID); + + // if we have no such callback and this is not a broadcast message, bail out + if (!callbacks && aMessage.name != "OpenWebapps:InstallDone" + && aMessage.name != "OpenWebapps:MgmtUninstall:Return") + return; + + switch(aMessage.name) { + case "OpenWebapps:InstallAborted" : + if (callbacks.error) + callbacks.error.handle({ code: "denied", message: "User denied installation" }); + break; + case "OpenWebapps:InstallDone" : + if (callbacks && callbacks.success) + callbacks.success.handle(); + this._onInstalled([msg.app]); + break; + case "OpenWebapps:GetInstalledBy:Return": + if (callbacks && callbacks.success) { + let apps = this._convertAppsArray(msg.apps); + callbacks.success.handle(apps, apps.length); + } + break; + case "OpenWebapps:AmInstalled:Return": + if (callbacks.success) + callbacks.success.handle(msg.installed ? msg.app : null); + break; + case "OpenWebapps:MgmtLaunch:Return": + if (msg.ok && callbacks && callbacks.success) + callbacks.success.handle(); + else if (!msg.ok && callbacks.error) + callbacks.error.handle({ code: "noSuchApp", message: "Unable to launch application"}); + break; + case "OpenWebapps:MgmtList:Return": + if (msg.ok && callbacks && callbacks.success) { + let apps = this._convertAppsArray(msg.apps); + callbacks.success.handle(apps, apps.length); + } + else if (!msg.ok && callbacks && callbacks.error) { + callbacks.error.handle({ code: "noAppList", message: "Unable to get application list"}); + } + break; + case "OpenWebapps:MgmtUninstall:Return": + if (msg.ok) { + if (callbacks && callbacks.success) + callbacks.success.handle(); + this._onUninstalled([msg.app]); + } + else if (!msg.ok && callbacks.error) + callbacks.error.handle({ code: "noSuchApp", message: "Unable to uninstall application"}); + break; + } + this.removeCallback(msg.callbackID); + }, + + // nsIOpenWebapps implementation + + install: function(aURL, aInstallData, aSuccess, aError) { + let self = this; + + let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); + xhr.open("GET", aURL, true); + + xhr.addEventListener("load", function() { + if (xhr.status == 200) { + try { + let manifest = JSON.parse(xhr.responseText); + if (!self.checkManifest(manifest)) { + if (aError) + aError.handle({ code: "invalidManifest", message: "Invalid manifest" }); + } else { + self.mm.sendAsyncMessage("OpenWebapps:Install", { storeURI: self._window.location.href, manifestURI: aURL, manifest: xhr.responseText, + installData: aInstallData, callbackID: self.getCallbackId({ success: aSuccess, error: aError }) }); + } + } catch(e) { + if (aError) + aError.handle({ code: "manifestParseError", message: "Unable to parse the manifest" }); + } + } + else if (aError) { + aError.handle({ code: "networkError", message: "Unable to retrieve manifest" }); + } + }, false); + + xhr.addEventListener("error", function() { + if (aError) + aError.handle({ code: "networkError", message: "Unable to retrieve manifest" }); + }, false); + + xhr.send(null); + }, + + amInstalled: function(aSuccess, aError) { + this.mm.sendAsyncMessage("OpenWebapps:AmInstalled", { appURI: this._window.location.href, callbackID: this.getCallbackId({ success: aSuccess, error: aError }) }); + }, + + getInstalledBy: function(aSuccess, aError) { + this.mm.sendAsyncMessage("OpenWebapps:GetInstalledBy", { storeURI: this._window.location.href, callbackID: this.getCallbackId({ success: aSuccess, error: aError }) }); + }, + + // nsIOpenWebappsMgmt implementation + launch: function(aOrigin, aSuccess, aError) { + this.mm.sendAsyncMessage("OpenWebapps:MgmtLaunch", { origin: aOrigin, callbackID: this.getCallbackId({ success: aSuccess, error: aError }) }); + }, + + list: function(aSuccess, aError) { + this.mm.sendAsyncMessage("OpenWebapps:MgmtList", { from: this._window.location.href, callbackID: this.getCallbackId({ success: aSuccess, error: aError }) }); + }, + + uninstall: function(aOrigin, aSuccess, aError) { + this.mm.sendAsyncMessage("OpenWebapps:MgmtUninstall", { from: this._window.location.href, origin: aOrigin, callbackID: this.getCallbackId({ success: aSuccess, error: aError }) }); + }, + + _onRepoChange: function(aWhat, aApps) { + for (let prop in this._callbacks) { + if (this._callbacks[prop].isWatch) { + let apps = this._convertAppsArray(aApps); + this._callbacks[prop].callback.update(aWhat, apps, apps.length); + } + } + }, + + _onInstalled: function(aApps) { + this._onRepoChange("add", aApps); + }, + + _onUninstalled: function(aApps) { + this._onRepoChange("remove", aApps); + }, + + watchUpdates: function(aCallback) { + this._watchId++; + this._callbacks["_watch" + this._getRandomId()] = { isWatch: true, callback: aCallback }; + return this._watchId; + }, + + clearWatch: function(aWatchId) { + this.removeCallback("_watch" + aWatchId); + }, + + handleEvent: function(aEvent) { + if (aEvent.type == "unload") { + // remove all callbacks so we don't call anything on a cleared scope + this._callbacks = []; + } + }, + + // nsIDOMGlobalPropertyInitializer implementation + init: function(aWindow) { + this._window = aWindow; + this._window.addEventListener("unload", this, false); + }, + + get mgmt() { + return this.QueryInterface(Ci.nsIOpenWebappsMgmt); + }, + + classID: Components.ID("{d8fd4d63-27ea-47b9-a931-481214bb8b5b}"), + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIOpenWebapps, Ci.nsIOpenWebappsMgmt, Ci.nsIDOMGlobalPropertyInitializer]), + + classInfo: XPCOMUtils.generateCI({classID: Components.ID("{d8fd4d63-27ea-47b9-a931-481214bb8b5b}"), + contractID: "@mozilla.org/openwebapps;1", + interfaces: [Ci.nsIOpenWebapps], + flags: Ci.nsIClassInfo.DOM_OBJECT, + classDescription: "OpenWebapps"}) +} + +function OpenWebappsApplication() { +} + +OpenWebappsApplication.prototype = { + origin: null, + manifest: null, + install_data: null, + install_origin: null, + install_time: 0, + + classID: Components.ID("{34456347-0792-45a4-8eb1-7b5f94f2d700}"), + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIOpenWebappsApplication]), + + classInfo: XPCOMUtils.generateCI({classID: Components.ID("{34456347-0792-45a4-8eb1-7b5f94f2d700}"), + contractID: "@mozilla.org/openwebapps/application;1", + interfaces: [Ci.nsIOpenWebappsApplication], + flags: Ci.nsIClassInfo.DOM_OBJECT, + classDescription: "OpenWebapps Application"}) +} + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([OpenWebapps, OpenWebappsApplication]); + diff --git a/toolkit/mozapps/webapps/OpenWebapps.jsm b/toolkit/mozapps/webapps/OpenWebapps.jsm new file mode 100644 index 000000000000..4e1c64eed8a8 --- /dev/null +++ b/toolkit/mozapps/webapps/OpenWebapps.jsm @@ -0,0 +1,260 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Mobile Browser. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Fabrice Desré + * Mark Finkle + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; + +let EXPORTED_SYMBOLS = ["OpenWebapps"]; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +XPCOMUtils.defineLazyGetter(this, "NetUtil", function() { + Cu.import("resource://gre/modules/NetUtil.jsm"); + return NetUtil; +}); + +let OpenWebapps = { + appsDir: null, + appsFile: null, + webapps: { }, + + init: function() { + let file = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("ProfD", Ci.nsIFile); + file.append("webapps"); + if (!file.exists() || !file.isDirectory()) { + file.create(Ci.nsIFile.DIRECTORY_TYPE, 0700); + } + this.appsDir = file; + this.appsFile = file.clone(); + this.appsFile.append("webapps.json"); + if (!this.appsFile.exists()) + return; + + try { + let channel = NetUtil.newChannel(this.appsFile); + channel.contentType = "application/json"; + let self = this; + NetUtil.asyncFetch(channel, function(aStream, aResult) { + if (!Components.isSuccessCode(aResult)) { + Cu.reportError("OpenWebappsSupport: Could not read from json file " + this.appsFile.path); + return; + } + + // Read json file into a string + let data = null; + try { + self.webapps = JSON.parse(NetUtil.readInputStreamToString(aStream, aStream.available()) || ""); + aStream.close(); + } catch (ex) { + Cu.reportError("OpenWebsappsStore: Could not parse JSON: " + ex); + } + }); + } catch (ex) { + Cu.reportError("OpenWebappsSupport: Could not read from " + aFile.path + " : " + ex); + } + }, + + _writeFile: function ss_writeFile(aFile, aData) { + // Initialize the file output stream. + let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); + ostream.init(aFile, 0x02 | 0x08 | 0x20, 0600, ostream.DEFER_OPEN); + + // Obtain a converter to convert our data to a UTF-8 encoded input stream. + let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter); + converter.charset = "UTF-8"; + + // Asynchronously copy the data to the file. + let istream = converter.convertToInputStream(aData); + NetUtil.asyncCopy(istream, ostream, function(rc) { + // nothing to do + }); + }, + + install: function(aApplication) { + let id = this._appId(aApplication.appURI); + + // install an application again is considered as an update + if (id) { + let dir = this.appsDir.clone(); + dir.append(id); + try { + dir.remove(true); + } catch(e) { + } + } + else { + let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); + id = uuidGenerator.generateUUID().toString(); + } + + let dir = this.appsDir.clone(); + dir.append(id); + dir.create(Ci.nsIFile.DIRECTORY_TYPE, 0700); + + let manFile = dir.clone(); + manFile.append("manifest.json"); + this._writeFile(manFile, JSON.stringify(aApplication.manifest)); + + this.webapps[id] = { + title: aApplication.title, + storeURI: aApplication.storeURI, + appURI: aApplication.appURI, + installData: aApplication.installData, + installTime: (new Date()).getTime() + }; + this._writeFile(this.appsFile, JSON.stringify(this.webapps)); + + // now save the icon as icon.png in the app directory + let iconURI = aApplication.iconURI ? aApplication.iconURI : "chrome://browser/skin/images/homescreen-default-hdpi.png"; + let iconFile = dir.clone(); + iconFile.append("icon.png"); + let uri = Services.io.newURI(iconURI, null, null); + let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist); + persist.persistFlags = persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES | persist.PERSIST_FLAGS_BYPASS_CACHE; + persist.saveURI(uri, null, null, null, "", iconFile); + }, + + _appId: function(aURI) { + for (let id in this.webapps) { + if (this.webapps[id].appURI == aURI) + return id; + } + return null; + }, + + _readManifest: function(aId) { + let file = this.appsDir.clone(); + file.append(aId); + file.append("manifest.json"); + let data = ""; + let fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream); + var cstream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(Ci.nsIConverterInputStream); + fstream.init(file, -1, 0, 0); + cstream.init(fstream, "UTF-8", 0, 0); + let (str = {}) { + let read = 0; + do { + read = cstream.readString(0xffffffff, str); // read as much as we can and put it in str.value + data += str.value; + } while (read != 0); + } + cstream.close(); // this closes fstream + try { + return JSON.parse(data); + } catch(e) { + return null; + } + }, + + amInstalled: function(aURI) { + for (let id in this.webapps) { + let app = this.webapps[id]; + if (app.appURI == aURI) { + return { origin: app.appURI, + install_origin: app.storeURI, + install_data: app.installData, + install_time: app.installTime, + manifest: this._readManifest(id) }; + } + } + return null; + }, + + getInstalledBy: function(aStoreURI) { + let res = []; + for (let id in this.webapps) { + let app = this.webapps[id]; + if (app.storeURI == aStoreURI) + res.push({ origin: app.appURI, + install_origin: app.storeURI, + install_data: app.installData, + install_time: app.installTime, + manifest: this._readManifest(id) }); + } + return res; + }, + + mgmtList: function() { + let res = new Array(); + for (let id in this.webapps) { + let app = this.webapps[id]; + res.push({ origin: app.appURI, + install_origin: app.storeURI, + install_data: app.installData, + install_time: app.installTime, + manifest: this._readManifest(id) }); + } + return res; + }, + + mgmtLaunch: function(aOrigin) { + for (let id in this.webapps) { + let app = this.webapps[id]; + app.manifest = this._readManifest(id); + if (app.appURI == aOrigin) { + let browserWin = Services.wm.getMostRecentWindow("navigator:browser"); + let uri = Services.io.newURI(aOrigin + (app.manifest.launch_path ? app.manifest.launch_path : ""), null, null); + browserWin.browserDOMWindow.openURI(uri, null, browserWin.OPEN_APPTAB, Ci.nsIBrowserDOMWindow.OPEN_NEW); + return true; + } + } + return false; + }, + + mgmtUninstall: function(aOrigin) { + for (let id in this.webapps) { + let app = this.webapps[id]; + if (app.appURI == aOrigin) { + delete this.webapps[id]; + this._writeFile(this.appsFile, JSON.stringify(this.webapps)); + let dir = this.appsDir.clone(); + dir.append(id); + try { + dir.remove(true); + } catch (e) { + } + return true; + } + } + return false; + } +}; + +OpenWebapps.init(); + diff --git a/toolkit/mozapps/webapps/OpenWebapps.manifest b/toolkit/mozapps/webapps/OpenWebapps.manifest new file mode 100644 index 000000000000..ce3a11d79054 --- /dev/null +++ b/toolkit/mozapps/webapps/OpenWebapps.manifest @@ -0,0 +1,8 @@ +# OpenWebapps.js +component {d8fd4d63-27ea-47b9-a931-481214bb8b5b} OpenWebapps.js +contract @mozilla.org/openwebapps;1 {d8fd4d63-27ea-47b9-a931-481214bb8b5b} +category JavaScript-navigator-property mozApps @mozilla.org/openwebapps;1 + +component {34456347-0792-45a4-8eb1-7b5f94f2d700} OpenWebapps.js +contract @mozilla.org/openwebapps/application;1 {34456347-0792-45a4-8eb1-7b5f94f2d700} +