michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: const Cc = Components.classes; michael@0: const Ci = Components.interfaces; michael@0: const Cu = Components.utils; michael@0: const Cr = Components.results; michael@0: michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: Cu.import("resource://gre/modules/DOMRequestHelper.jsm"); michael@0: Cu.import("resource://gre/modules/AppsUtils.jsm"); michael@0: Cu.import("resource://gre/modules/BrowserElementPromptService.jsm"); michael@0: michael@0: XPCOMUtils.defineLazyServiceGetter(this, "cpmm", michael@0: "@mozilla.org/childprocessmessagemanager;1", michael@0: "nsIMessageSender"); michael@0: michael@0: function convertAppsArray(aApps, aWindow) { michael@0: let apps = new aWindow.Array(); michael@0: for (let i = 0; i < aApps.length; i++) { michael@0: let app = aApps[i]; michael@0: apps.push(createApplicationObject(aWindow, app)); michael@0: } michael@0: michael@0: return apps; michael@0: } michael@0: michael@0: function WebappsRegistry() { michael@0: } michael@0: michael@0: WebappsRegistry.prototype = { michael@0: __proto__: DOMRequestIpcHelper.prototype, michael@0: michael@0: receiveMessage: function(aMessage) { michael@0: let msg = aMessage.json; michael@0: if (msg.oid != this._id) michael@0: return michael@0: let req = this.getRequest(msg.requestID); michael@0: if (!req) michael@0: return; michael@0: let app = msg.app; michael@0: switch (aMessage.name) { michael@0: case "Webapps:Install:Return:OK": michael@0: this.removeMessageListeners("Webapps:Install:Return:KO"); michael@0: Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app)); michael@0: cpmm.sendAsyncMessage("Webapps:Install:Return:Ack", michael@0: { manifestURL : app.manifestURL }); michael@0: break; michael@0: case "Webapps:Install:Return:KO": michael@0: this.removeMessageListeners(aMessage.name); michael@0: Services.DOMRequest.fireError(req, msg.error || "DENIED"); michael@0: break; michael@0: case "Webapps:GetSelf:Return:OK": michael@0: this.removeMessageListeners(aMessage.name); michael@0: if (msg.apps.length) { michael@0: app = msg.apps[0]; michael@0: Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app)); michael@0: } else { michael@0: Services.DOMRequest.fireSuccess(req, null); michael@0: } michael@0: break; michael@0: case "Webapps:CheckInstalled:Return:OK": michael@0: this.removeMessageListeners(aMessage.name); michael@0: Services.DOMRequest.fireSuccess(req, msg.app); michael@0: break; michael@0: case "Webapps:GetInstalled:Return:OK": michael@0: this.removeMessageListeners(aMessage.name); michael@0: Services.DOMRequest.fireSuccess(req, convertAppsArray(msg.apps, this._window)); michael@0: break; michael@0: } michael@0: this.removeRequest(msg.requestID); michael@0: }, michael@0: michael@0: _getOrigin: function(aURL) { michael@0: let uri = Services.io.newURI(aURL, null, null); michael@0: return uri.prePath; michael@0: }, michael@0: michael@0: // Checks that the URL scheme is appropriate (http or https) and michael@0: // asynchronously fire an error on the DOM Request if it isn't. michael@0: _validateURL: function(aURL, aRequest) { michael@0: let uri; michael@0: let res; michael@0: michael@0: try { michael@0: uri = Services.io.newURI(aURL, null, null); michael@0: if (uri.schemeIs("http") || uri.schemeIs("https")) { michael@0: res = uri.spec; michael@0: } michael@0: } catch(e) { michael@0: Services.DOMRequest.fireErrorAsync(aRequest, "INVALID_URL"); michael@0: return false; michael@0: } michael@0: michael@0: // The scheme is incorrect, fire DOMRequest error. michael@0: if (!res) { michael@0: Services.DOMRequest.fireErrorAsync(aRequest, "INVALID_URL"); michael@0: return false; michael@0: } michael@0: michael@0: return uri.spec; michael@0: }, michael@0: michael@0: // Checks that we run as a foreground page, and fire an error on the michael@0: // DOM Request if we aren't. michael@0: _ensureForeground: function(aRequest) { michael@0: let docShell = this._window.QueryInterface(Ci.nsIInterfaceRequestor) michael@0: .getInterface(Ci.nsIWebNavigation) michael@0: .QueryInterface(Ci.nsIDocShell); michael@0: if (docShell.isActive) { michael@0: return true; michael@0: } michael@0: michael@0: Services.DOMRequest.fireErrorAsync(aRequest, "BACKGROUND_APP"); michael@0: return false; michael@0: }, michael@0: michael@0: _prepareInstall: function(aURL, aRequest, aParams, isPackage) { michael@0: let installURL = this._window.location.href; michael@0: let requestID = this.getRequestId(aRequest); michael@0: let receipts = (aParams && aParams.receipts && michael@0: Array.isArray(aParams.receipts)) ? aParams.receipts michael@0: : []; michael@0: let categories = (aParams && aParams.categories && michael@0: Array.isArray(aParams.categories)) ? aParams.categories michael@0: : []; michael@0: michael@0: let principal = this._window.document.nodePrincipal; michael@0: michael@0: return { app: { michael@0: installOrigin: this._getOrigin(installURL), michael@0: origin: this._getOrigin(aURL), michael@0: manifestURL: aURL, michael@0: receipts: receipts, michael@0: categories: categories michael@0: }, michael@0: michael@0: from: installURL, michael@0: oid: this._id, michael@0: requestID: requestID, michael@0: appId: principal.appId, michael@0: isBrowser: principal.isInBrowserElement, michael@0: isPackage: isPackage michael@0: }; michael@0: }, michael@0: michael@0: // mozIDOMApplicationRegistry implementation michael@0: michael@0: install: function(aURL, aParams) { michael@0: let request = this.createRequest(); michael@0: michael@0: let uri = this._validateURL(aURL, request); michael@0: michael@0: if (uri && this._ensureForeground(request)) { michael@0: this.addMessageListeners("Webapps:Install:Return:KO"); michael@0: cpmm.sendAsyncMessage("Webapps:Install", michael@0: this._prepareInstall(uri, request, aParams, false)); michael@0: } michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: getSelf: function() { michael@0: let request = this.createRequest(); michael@0: this.addMessageListeners("Webapps:GetSelf:Return:OK"); michael@0: cpmm.sendAsyncMessage("Webapps:GetSelf", { origin: this._getOrigin(this._window.location.href), michael@0: appId: this._window.document.nodePrincipal.appId, michael@0: oid: this._id, michael@0: requestID: this.getRequestId(request) }); michael@0: return request; michael@0: }, michael@0: michael@0: checkInstalled: function(aManifestURL) { michael@0: let manifestURL = Services.io.newURI(aManifestURL, null, this._window.document.baseURIObject); michael@0: this._window.document.nodePrincipal.checkMayLoad(manifestURL, true, false); michael@0: michael@0: let request = this.createRequest(); michael@0: michael@0: this.addMessageListeners("Webapps:CheckInstalled:Return:OK"); michael@0: cpmm.sendAsyncMessage("Webapps:CheckInstalled", { origin: this._getOrigin(this._window.location.href), michael@0: manifestURL: manifestURL.spec, michael@0: oid: this._id, michael@0: requestID: this.getRequestId(request) }); michael@0: return request; michael@0: }, michael@0: michael@0: getInstalled: function() { michael@0: let request = this.createRequest(); michael@0: this.addMessageListeners("Webapps:GetInstalled:Return:OK"); michael@0: cpmm.sendAsyncMessage("Webapps:GetInstalled", { origin: this._getOrigin(this._window.location.href), michael@0: oid: this._id, michael@0: requestID: this.getRequestId(request) }); michael@0: return request; michael@0: }, michael@0: michael@0: get mgmt() { michael@0: if (!this.hasMgmtPrivilege) { michael@0: return null; michael@0: } michael@0: michael@0: if (!this._mgmt) michael@0: this._mgmt = new WebappsApplicationMgmt(this._window); michael@0: return this._mgmt; michael@0: }, michael@0: michael@0: uninit: function() { michael@0: this._mgmt = null; michael@0: cpmm.sendAsyncMessage("Webapps:UnregisterForMessages", michael@0: ["Webapps:Install:Return:OK"]); michael@0: }, michael@0: michael@0: installPackage: function(aURL, aParams) { michael@0: let request = this.createRequest(); michael@0: michael@0: let uri = this._validateURL(aURL, request); michael@0: michael@0: if (uri && this._ensureForeground(request)) { michael@0: this.addMessageListeners("Webapps:Install:Return:KO"); michael@0: cpmm.sendAsyncMessage("Webapps:InstallPackage", michael@0: this._prepareInstall(uri, request, aParams, true)); michael@0: } michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: // nsIDOMGlobalPropertyInitializer implementation michael@0: init: function(aWindow) { michael@0: this.initDOMRequestHelper(aWindow, "Webapps:Install:Return:OK"); michael@0: michael@0: let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor) michael@0: .getInterface(Ci.nsIDOMWindowUtils); michael@0: this._id = util.outerWindowID; michael@0: cpmm.sendAsyncMessage("Webapps:RegisterForMessages", michael@0: { messages: ["Webapps:Install:Return:OK"]}); michael@0: michael@0: let principal = aWindow.document.nodePrincipal; michael@0: let perm = Services.perms michael@0: .testExactPermissionFromPrincipal(principal, "webapps-manage"); michael@0: michael@0: // Only pages with the webapps-manage permission set can get access to michael@0: // the mgmt object. michael@0: this.hasMgmtPrivilege = perm == Ci.nsIPermissionManager.ALLOW_ACTION; michael@0: }, michael@0: michael@0: classID: Components.ID("{fff440b3-fae2-45c1-bf03-3b5a2e432270}"), michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, michael@0: Ci.nsIObserver, michael@0: Ci.mozIDOMApplicationRegistry, michael@0: Ci.mozIDOMApplicationRegistry2, michael@0: Ci.nsIDOMGlobalPropertyInitializer]), michael@0: michael@0: classInfo: XPCOMUtils.generateCI({classID: Components.ID("{fff440b3-fae2-45c1-bf03-3b5a2e432270}"), michael@0: contractID: "@mozilla.org/webapps;1", michael@0: interfaces: [Ci.mozIDOMApplicationRegistry, michael@0: Ci.mozIDOMApplicationRegistry2], michael@0: flags: Ci.nsIClassInfo.DOM_OBJECT, michael@0: classDescription: "Webapps Registry"}) michael@0: } michael@0: michael@0: /** michael@0: * mozIDOMApplication object michael@0: */ michael@0: michael@0: // A simple cache for the wrapped manifests. michael@0: let manifestCache = { michael@0: _cache: { }, michael@0: michael@0: // Gets an entry from the cache, and populates the cache if needed. michael@0: get: function mcache_get(aManifestURL, aManifest, aWindow, aInnerWindowID) { michael@0: if (!(aManifestURL in this._cache)) { michael@0: this._cache[aManifestURL] = { }; michael@0: } michael@0: michael@0: let winObjs = this._cache[aManifestURL]; michael@0: if (!(aInnerWindowID in winObjs)) { michael@0: winObjs[aInnerWindowID] = Cu.cloneInto(aManifest, aWindow); michael@0: } michael@0: michael@0: return winObjs[aInnerWindowID]; michael@0: }, michael@0: michael@0: // Invalidates an entry in the cache. michael@0: evict: function mcache_evict(aManifestURL, aInnerWindowID) { michael@0: if (aManifestURL in this._cache) { michael@0: let winObjs = this._cache[aManifestURL]; michael@0: if (aInnerWindowID in winObjs) { michael@0: delete winObjs[aInnerWindowID]; michael@0: } michael@0: michael@0: if (Object.keys(winObjs).length == 0) { michael@0: delete this._cache[aManifestURL]; michael@0: } michael@0: } michael@0: }, michael@0: michael@0: observe: function(aSubject, aTopic, aData) { michael@0: // Clear the cache on memory pressure. michael@0: this._cache = { }; michael@0: }, michael@0: michael@0: init: function() { michael@0: Services.obs.addObserver(this, "memory-pressure", false); michael@0: } michael@0: }; michael@0: michael@0: function createApplicationObject(aWindow, aApp) { michael@0: let app = Cc["@mozilla.org/webapps/application;1"].createInstance(Ci.mozIDOMApplication); michael@0: app.wrappedJSObject.init(aWindow, aApp); michael@0: return app; michael@0: } michael@0: michael@0: function WebappsApplication() { michael@0: this.wrappedJSObject = this; michael@0: } michael@0: michael@0: WebappsApplication.prototype = { michael@0: __proto__: DOMRequestIpcHelper.prototype, michael@0: michael@0: init: function(aWindow, aApp) { michael@0: this._window = aWindow; michael@0: let principal = this._window.document.nodePrincipal; michael@0: this._appStatus = principal.appStatus; michael@0: this.origin = aApp.origin; michael@0: this._manifest = aApp.manifest; michael@0: this._updateManifest = aApp.updateManifest; michael@0: this.manifestURL = aApp.manifestURL; michael@0: this.receipts = aApp.receipts; michael@0: this.installOrigin = aApp.installOrigin; michael@0: this.installTime = aApp.installTime; michael@0: this.installState = aApp.installState || "installed"; michael@0: this.removable = aApp.removable; michael@0: this.lastUpdateCheck = aApp.lastUpdateCheck ? aApp.lastUpdateCheck michael@0: : Date.now(); michael@0: this.updateTime = aApp.updateTime ? aApp.updateTime michael@0: : aApp.installTime; michael@0: this.progress = NaN; michael@0: this.downloadAvailable = aApp.downloadAvailable; michael@0: this.downloading = aApp.downloading; michael@0: this.readyToApplyDownload = aApp.readyToApplyDownload; michael@0: this.downloadSize = aApp.downloadSize || 0; michael@0: michael@0: this._onprogress = null; michael@0: this._ondownloadsuccess = null; michael@0: this._ondownloaderror = null; michael@0: this._ondownloadavailable = null; michael@0: this._ondownloadapplied = null; michael@0: michael@0: this._downloadError = null; michael@0: michael@0: this.initDOMRequestHelper(aWindow, [ michael@0: { name: "Webapps:CheckForUpdate:Return:KO", weakRef: true }, michael@0: { name: "Webapps:Connect:Return:OK", weakRef: true }, michael@0: { name: "Webapps:Connect:Return:KO", weakRef: true }, michael@0: { name: "Webapps:FireEvent", weakRef: true }, michael@0: { name: "Webapps:GetConnections:Return:OK", weakRef: true }, michael@0: { name: "Webapps:UpdateState", weakRef: true } michael@0: ]); michael@0: michael@0: cpmm.sendAsyncMessage("Webapps:RegisterForMessages", { michael@0: messages: ["Webapps:FireEvent", michael@0: "Webapps:UpdateState"], michael@0: app: { michael@0: id: this.id, michael@0: manifestURL: this.manifestURL, michael@0: installState: this.installState, michael@0: downloading: this.downloading michael@0: } michael@0: }); michael@0: }, michael@0: michael@0: get manifest() { michael@0: return manifestCache.get(this.manifestURL, michael@0: this._manifest, michael@0: this._window, michael@0: this.innerWindowID); michael@0: }, michael@0: michael@0: get updateManifest() { michael@0: return this.updateManifest = michael@0: this._updateManifest ? Cu.cloneInto(this._updateManifest, this._window) michael@0: : null; michael@0: }, michael@0: michael@0: set onprogress(aCallback) { michael@0: this._onprogress = aCallback; michael@0: }, michael@0: michael@0: get onprogress() { michael@0: return this._onprogress; michael@0: }, michael@0: michael@0: set ondownloadsuccess(aCallback) { michael@0: this._ondownloadsuccess = aCallback; michael@0: }, michael@0: michael@0: get ondownloadsuccess() { michael@0: return this._ondownloadsuccess; michael@0: }, michael@0: michael@0: set ondownloaderror(aCallback) { michael@0: this._ondownloaderror = aCallback; michael@0: }, michael@0: michael@0: get ondownloaderror() { michael@0: return this._ondownloaderror; michael@0: }, michael@0: michael@0: set ondownloadavailable(aCallback) { michael@0: this._ondownloadavailable = aCallback; michael@0: }, michael@0: michael@0: get ondownloadavailable() { michael@0: return this._ondownloadavailable; michael@0: }, michael@0: michael@0: set ondownloadapplied(aCallback) { michael@0: this._ondownloadapplied = aCallback; michael@0: }, michael@0: michael@0: get ondownloadapplied() { michael@0: return this._ondownloadapplied; michael@0: }, michael@0: michael@0: get downloadError() { michael@0: return new this._window.DOMError(this._downloadError || ''); michael@0: }, michael@0: michael@0: download: function() { michael@0: cpmm.sendAsyncMessage("Webapps:Download", michael@0: { manifestURL: this.manifestURL }); michael@0: }, michael@0: michael@0: cancelDownload: function() { michael@0: cpmm.sendAsyncMessage("Webapps:CancelDownload", michael@0: { manifestURL: this.manifestURL }); michael@0: }, michael@0: michael@0: checkForUpdate: function() { michael@0: let request = this.createRequest(); michael@0: michael@0: cpmm.sendAsyncMessage("Webapps:CheckForUpdate", michael@0: { manifestURL: this.manifestURL, michael@0: oid: this._id, michael@0: requestID: this.getRequestId(request) }); michael@0: return request; michael@0: }, michael@0: michael@0: launch: function(aStartPoint) { michael@0: let request = this.createRequest(); michael@0: this.addMessageListeners(["Webapps:Launch:Return:OK", michael@0: "Webapps:Launch:Return:KO"]); michael@0: cpmm.sendAsyncMessage("Webapps:Launch", { origin: this.origin, michael@0: manifestURL: this.manifestURL, michael@0: startPoint: aStartPoint || "", michael@0: oid: this._id, michael@0: timestamp: Date.now(), michael@0: requestID: this.getRequestId(request) }); michael@0: return request; michael@0: }, michael@0: michael@0: clearBrowserData: function() { michael@0: let request = this.createRequest(); michael@0: let browserChild = michael@0: BrowserElementPromptService.getBrowserElementChildForWindow(this._window); michael@0: if (browserChild) { michael@0: this.addMessageListeners("Webapps:ClearBrowserData:Return"); michael@0: browserChild.messageManager.sendAsyncMessage( michael@0: "Webapps:ClearBrowserData", michael@0: { manifestURL: this.manifestURL, michael@0: oid: this._id, michael@0: requestID: this.getRequestId(request) } michael@0: ); michael@0: } else { michael@0: Services.DOMRequest.fireErrorAsync(request, "NO_CLEARABLE_BROWSER"); michael@0: } michael@0: return request; michael@0: }, michael@0: michael@0: connect: function(aKeyword, aRules) { michael@0: return this.createPromise(function (aResolve, aReject) { michael@0: cpmm.sendAsyncMessage("Webapps:Connect", michael@0: { keyword: aKeyword, michael@0: rules: aRules, michael@0: manifestURL: this.manifestURL, michael@0: outerWindowID: this._id, michael@0: requestID: this.getPromiseResolverId({ michael@0: resolve: aResolve, michael@0: reject: aReject michael@0: })}); michael@0: }.bind(this)); michael@0: }, michael@0: michael@0: getConnections: function() { michael@0: return this.createPromise(function (aResolve, aReject) { michael@0: cpmm.sendAsyncMessage("Webapps:GetConnections", michael@0: { manifestURL: this.manifestURL, michael@0: outerWindowID: this._id, michael@0: requestID: this.getPromiseResolverId({ michael@0: resolve: aResolve, michael@0: reject: aReject michael@0: })}); michael@0: }.bind(this)); michael@0: }, michael@0: michael@0: addReceipt: function(receipt) { michael@0: let request = this.createRequest(); michael@0: michael@0: this.addMessageListeners(["Webapps:AddReceipt:Return:OK", michael@0: "Webapps:AddReceipt:Return:KO"]); michael@0: michael@0: cpmm.sendAsyncMessage("Webapps:AddReceipt", { manifestURL: this.manifestURL, michael@0: receipt: receipt, michael@0: oid: this._id, michael@0: requestID: this.getRequestId(request) }); michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: removeReceipt: function(receipt) { michael@0: let request = this.createRequest(); michael@0: michael@0: this.addMessageListeners(["Webapps:RemoveReceipt:Return:OK", michael@0: "Webapps:RemoveReceipt:Return:KO"]); michael@0: michael@0: cpmm.sendAsyncMessage("Webapps:RemoveReceipt", { manifestURL: this.manifestURL, michael@0: receipt: receipt, michael@0: oid: this._id, michael@0: requestID: this.getRequestId(request) }); michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: replaceReceipt: function(oldReceipt, newReceipt) { michael@0: let request = this.createRequest(); michael@0: michael@0: this.addMessageListeners(["Webapps:ReplaceReceipt:Return:OK", michael@0: "Webapps:ReplaceReceipt:Return:KO"]); michael@0: michael@0: cpmm.sendAsyncMessage("Webapps:ReplaceReceipt", { manifestURL: this.manifestURL, michael@0: newReceipt: newReceipt, michael@0: oldReceipt: oldReceipt, michael@0: oid: this._id, michael@0: requestID: this.getRequestId(request) }); michael@0: michael@0: return request; michael@0: }, michael@0: michael@0: uninit: function() { michael@0: this._onprogress = null; michael@0: cpmm.sendAsyncMessage("Webapps:UnregisterForMessages", [ michael@0: "Webapps:FireEvent", michael@0: "Webapps:UpdateState" michael@0: ]); michael@0: michael@0: manifestCache.evict(this.manifestURL, this.innerWindowID); michael@0: }, michael@0: michael@0: _fireEvent: function(aName) { michael@0: let handler = this["_on" + aName]; michael@0: if (handler) { michael@0: let event = new this._window.MozApplicationEvent(aName, { michael@0: application: this michael@0: }); michael@0: try { michael@0: handler.handleEvent(event); michael@0: } catch (ex) { michael@0: dump("Event handler expection " + ex + "\n"); michael@0: } michael@0: } michael@0: }, michael@0: michael@0: _updateState: function(aMsg) { michael@0: if (aMsg.app) { michael@0: for (let prop in aMsg.app) { michael@0: this[prop] = aMsg.app[prop]; michael@0: } michael@0: } michael@0: michael@0: if (aMsg.error) { michael@0: this._downloadError = aMsg.error; michael@0: } michael@0: michael@0: if (aMsg.manifest) { michael@0: this._manifest = aMsg.manifest; michael@0: manifestCache.evict(this.manifestURL, this.innerWindowID); michael@0: } michael@0: }, michael@0: michael@0: receiveMessage: function(aMessage) { michael@0: let msg = aMessage.json; michael@0: let req; michael@0: if (aMessage.name == "Webapps:Connect:Return:OK" || michael@0: aMessage.name == "Webapps:Connect:Return:KO" || michael@0: aMessage.name == "Webapps:GetConnections:Return:OK") { michael@0: req = this.takePromiseResolver(msg.requestID); michael@0: } else { michael@0: req = this.takeRequest(msg.requestID); michael@0: } michael@0: michael@0: // ondownload* callbacks should be triggered on all app instances michael@0: if ((msg.oid != this._id || !req) && michael@0: aMessage.name !== "Webapps:FireEvent" && michael@0: aMessage.name !== "Webapps:UpdateState") { michael@0: return; michael@0: } michael@0: michael@0: switch (aMessage.name) { michael@0: case "Webapps:Launch:Return:KO": michael@0: this.removeMessageListeners(["Webapps:Launch:Return:OK", michael@0: "Webapps:Launch:Return:KO"]); michael@0: Services.DOMRequest.fireError(req, "APP_INSTALL_PENDING"); michael@0: break; michael@0: case "Webapps:Launch:Return:OK": michael@0: this.removeMessageListeners(["Webapps:Launch:Return:OK", michael@0: "Webapps:Launch:Return:KO"]); michael@0: Services.DOMRequest.fireSuccess(req, null); michael@0: break; michael@0: case "Webapps:CheckForUpdate:Return:KO": michael@0: Services.DOMRequest.fireError(req, msg.error); michael@0: break; michael@0: case "Webapps:FireEvent": michael@0: if (msg.manifestURL != this.manifestURL) { michael@0: return; michael@0: } michael@0: michael@0: // The parent might ask childs to trigger more than one event in one michael@0: // shot, so in order to avoid needless IPC we allow an array for the michael@0: // 'eventType' IPC message field. michael@0: if (!Array.isArray(msg.eventType)) { michael@0: msg.eventType = [msg.eventType]; michael@0: } michael@0: michael@0: msg.eventType.forEach((aEventType) => { michael@0: if ("_on" + aEventType in this) { michael@0: this._fireEvent(aEventType); michael@0: } else { michael@0: dump("Unsupported event type " + aEventType + "\n"); michael@0: } michael@0: }); michael@0: michael@0: if (req) { michael@0: Services.DOMRequest.fireSuccess(req, this.manifestURL); michael@0: } michael@0: break; michael@0: case "Webapps:UpdateState": michael@0: if (msg.manifestURL != this.manifestURL) { michael@0: return; michael@0: } michael@0: michael@0: this._updateState(msg); michael@0: break; michael@0: case "Webapps:ClearBrowserData:Return": michael@0: this.removeMessageListeners(aMessage.name); michael@0: Services.DOMRequest.fireSuccess(req, null); michael@0: break; michael@0: case "Webapps:Connect:Return:OK": michael@0: let messagePorts = []; michael@0: msg.messagePortIDs.forEach((aPortID) => { michael@0: let port = new this._window.MozInterAppMessagePort(aPortID); michael@0: messagePorts.push(port); michael@0: }); michael@0: req.resolve(messagePorts); michael@0: break; michael@0: case "Webapps:Connect:Return:KO": michael@0: req.reject("No connections registered"); michael@0: break; michael@0: case "Webapps:GetConnections:Return:OK": michael@0: let connections = []; michael@0: msg.connections.forEach((aConnection) => { michael@0: let connection = michael@0: new this._window.MozInterAppConnection(aConnection.keyword, michael@0: aConnection.pubAppManifestURL, michael@0: aConnection.subAppManifestURL); michael@0: connections.push(connection); michael@0: }); michael@0: req.resolve(connections); michael@0: break; michael@0: case "Webapps:AddReceipt:Return:OK": michael@0: this.removeMessageListeners(["Webapps:AddReceipt:Return:OK", michael@0: "Webapps:AddReceipt:Return:KO"]); michael@0: this.receipts = msg.receipts; michael@0: Services.DOMRequest.fireSuccess(req, null); michael@0: break; michael@0: case "Webapps:AddReceipt:Return:KO": michael@0: this.removeMessageListeners(["Webapps:AddReceipt:Return:OK", michael@0: "Webapps:AddReceipt:Return:KO"]); michael@0: Services.DOMRequest.fireError(req, msg.error); michael@0: break; michael@0: case "Webapps:RemoveReceipt:Return:OK": michael@0: this.removeMessageListeners(["Webapps:RemoveReceipt:Return:OK", michael@0: "Webapps:RemoveReceipt:Return:KO"]); michael@0: this.receipts = msg.receipts; michael@0: Services.DOMRequest.fireSuccess(req, null); michael@0: break; michael@0: case "Webapps:RemoveReceipt:Return:KO": michael@0: this.removeMessageListeners(["Webapps:RemoveReceipt:Return:OK", michael@0: "Webapps:RemoveReceipt:Return:KO"]); michael@0: Services.DOMRequest.fireError(req, msg.error); michael@0: break; michael@0: case "Webapps:ReplaceReceipt:Return:OK": michael@0: this.removeMessageListeners(["Webapps:ReplaceReceipt:Return:OK", michael@0: "Webapps:ReplaceReceipt:Return:KO"]); michael@0: this.receipts = msg.receipts; michael@0: Services.DOMRequest.fireSuccess(req, null); michael@0: break; michael@0: case "Webapps:ReplaceReceipt:Return:KO": michael@0: this.removeMessageListeners(["Webapps:ReplaceReceipt:Return:OK", michael@0: "Webapps:ReplaceReceipt:Return:KO"]); michael@0: Services.DOMRequest.fireError(req, msg.error); michael@0: break; michael@0: } michael@0: }, michael@0: michael@0: classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"), michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMApplication, michael@0: Ci.nsISupportsWeakReference, michael@0: Ci.nsIObserver]), michael@0: michael@0: classInfo: XPCOMUtils.generateCI({classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"), michael@0: contractID: "@mozilla.org/webapps/application;1", michael@0: interfaces: [Ci.mozIDOMApplication], michael@0: flags: Ci.nsIClassInfo.DOM_OBJECT, michael@0: classDescription: "Webapps Application"}) michael@0: } michael@0: michael@0: /** michael@0: * mozIDOMApplicationMgmt object michael@0: */ michael@0: function WebappsApplicationMgmt(aWindow) { michael@0: this.initDOMRequestHelper(aWindow, ["Webapps:GetAll:Return:OK", michael@0: "Webapps:GetAll:Return:KO", michael@0: "Webapps:Uninstall:Return:OK", michael@0: "Webapps:Uninstall:Broadcast:Return:OK", michael@0: "Webapps:Uninstall:Return:KO", michael@0: "Webapps:Install:Return:OK", michael@0: "Webapps:GetNotInstalled:Return:OK"]); michael@0: michael@0: cpmm.sendAsyncMessage("Webapps:RegisterForMessages", michael@0: { michael@0: messages: ["Webapps:Install:Return:OK", michael@0: "Webapps:Uninstall:Return:OK", michael@0: "Webapps:Uninstall:Broadcast:Return:OK"] michael@0: } michael@0: ); michael@0: michael@0: this._oninstall = null; michael@0: this._onuninstall = null; michael@0: } michael@0: michael@0: WebappsApplicationMgmt.prototype = { michael@0: __proto__: DOMRequestIpcHelper.prototype, michael@0: __exposedProps__: { michael@0: applyDownload: "r", michael@0: getAll: "r", michael@0: getNotInstalled: "r", michael@0: oninstall: "rw", michael@0: onuninstall: "rw" michael@0: }, michael@0: michael@0: uninit: function() { michael@0: this._oninstall = null; michael@0: this._onuninstall = null; michael@0: cpmm.sendAsyncMessage("Webapps:UnregisterForMessages", michael@0: ["Webapps:Install:Return:OK", michael@0: "Webapps:Uninstall:Return:OK", michael@0: "Webapps:Uninstall:Broadcast:Return:OK"]); michael@0: }, michael@0: michael@0: applyDownload: function(aApp) { michael@0: if (!aApp.readyToApplyDownload) { michael@0: return; michael@0: } michael@0: michael@0: cpmm.sendAsyncMessage("Webapps:ApplyDownload", michael@0: { manifestURL: aApp.manifestURL }); michael@0: }, michael@0: michael@0: uninstall: function(aApp) { michael@0: dump("-- webapps.js uninstall " + aApp.manifestURL + "\n"); michael@0: let request = this.createRequest(); michael@0: cpmm.sendAsyncMessage("Webapps:Uninstall", { origin: aApp.origin, michael@0: manifestURL: aApp.manifestURL, michael@0: oid: this._id, michael@0: requestID: this.getRequestId(request) }); michael@0: return request; michael@0: }, michael@0: michael@0: getAll: function() { michael@0: let request = this.createRequest(); michael@0: cpmm.sendAsyncMessage("Webapps:GetAll", { oid: this._id, michael@0: requestID: this.getRequestId(request) }); michael@0: return request; michael@0: }, michael@0: michael@0: getNotInstalled: function() { michael@0: let request = this.createRequest(); michael@0: cpmm.sendAsyncMessage("Webapps:GetNotInstalled", { oid: this._id, michael@0: requestID: this.getRequestId(request) }); michael@0: return request; michael@0: }, michael@0: michael@0: get oninstall() { michael@0: return this._oninstall; michael@0: }, michael@0: michael@0: get onuninstall() { michael@0: return this._onuninstall; michael@0: }, michael@0: michael@0: set oninstall(aCallback) { michael@0: this._oninstall = aCallback; michael@0: }, michael@0: michael@0: set onuninstall(aCallback) { michael@0: this._onuninstall = aCallback; michael@0: }, michael@0: michael@0: receiveMessage: function(aMessage) { michael@0: var msg = aMessage.json; michael@0: let req = this.getRequest(msg.requestID); michael@0: // We want Webapps:Install:Return:OK and Webapps:Uninstall:Broadcast:Return:OK michael@0: // to be broadcasted to all instances of mozApps.mgmt. michael@0: if (!((msg.oid == this._id && req) || michael@0: aMessage.name == "Webapps:Install:Return:OK" || michael@0: aMessage.name == "Webapps:Uninstall:Broadcast:Return:OK")) { michael@0: return; michael@0: } michael@0: switch (aMessage.name) { michael@0: case "Webapps:GetAll:Return:OK": michael@0: Services.DOMRequest.fireSuccess(req, convertAppsArray(msg.apps, this._window)); michael@0: break; michael@0: case "Webapps:GetAll:Return:KO": michael@0: Services.DOMRequest.fireError(req, "DENIED"); michael@0: break; michael@0: case "Webapps:GetNotInstalled:Return:OK": michael@0: Services.DOMRequest.fireSuccess(req, convertAppsArray(msg.apps, this._window)); michael@0: break; michael@0: case "Webapps:Install:Return:OK": michael@0: if (this._oninstall) { michael@0: let app = msg.app; michael@0: let event = new this._window.MozApplicationEvent("applicationinstall", michael@0: { application : createApplicationObject(this._window, app) }); michael@0: this._oninstall.handleEvent(event); michael@0: } michael@0: break; michael@0: case "Webapps:Uninstall:Broadcast:Return:OK": michael@0: if (this._onuninstall) { michael@0: let detail = { michael@0: manifestURL: msg.manifestURL, michael@0: origin: msg.origin michael@0: }; michael@0: let event = new this._window.MozApplicationEvent("applicationuninstall", michael@0: { application : createApplicationObject(this._window, detail) }); michael@0: this._onuninstall.handleEvent(event); michael@0: } michael@0: break; michael@0: case "Webapps:Uninstall:Return:OK": michael@0: Services.DOMRequest.fireSuccess(req, msg.origin); michael@0: break; michael@0: case "Webapps:Uninstall:Return:KO": michael@0: Services.DOMRequest.fireError(req, "NOT_INSTALLED"); michael@0: break; michael@0: } michael@0: if (aMessage.name !== "Webapps:Uninstall:Broadcast:Return:OK") { michael@0: this.removeRequest(msg.requestID); michael@0: } michael@0: }, michael@0: michael@0: classID: Components.ID("{8c1bca96-266f-493a-8d57-ec7a95098c15}"), michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMApplicationMgmt, michael@0: Ci.nsISupportsWeakReference, michael@0: Ci.nsIObserver]), michael@0: michael@0: classInfo: XPCOMUtils.generateCI({classID: Components.ID("{8c1bca96-266f-493a-8d57-ec7a95098c15}"), michael@0: contractID: "@mozilla.org/webapps/application-mgmt;1", michael@0: interfaces: [Ci.mozIDOMApplicationMgmt], michael@0: flags: Ci.nsIClassInfo.DOM_OBJECT, michael@0: classDescription: "Webapps Application Mgmt"}) michael@0: } michael@0: michael@0: manifestCache.init(); michael@0: michael@0: this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsRegistry, michael@0: WebappsApplication]);