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: "use strict"; michael@0: michael@0: /* static functions */ michael@0: const DEBUG = false; michael@0: michael@0: function debug(aStr) { michael@0: if (DEBUG) michael@0: dump("AlarmsManager: " + aStr + "\n"); michael@0: } michael@0: michael@0: const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; 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: michael@0: const ALARMSMANAGER_CONTRACTID = "@mozilla.org/alarmsManager;1"; michael@0: const ALARMSMANAGER_CID = Components.ID("{fea1e884-9b05-11e1-9b64-87a7016c3860}"); michael@0: const nsIDOMMozAlarmsManager = Ci.nsIDOMMozAlarmsManager; michael@0: const nsIClassInfo = Ci.nsIClassInfo; michael@0: michael@0: function AlarmsManager() michael@0: { michael@0: debug("Constructor"); michael@0: } michael@0: michael@0: AlarmsManager.prototype = { michael@0: michael@0: __proto__: DOMRequestIpcHelper.prototype, michael@0: michael@0: classID : ALARMSMANAGER_CID, michael@0: michael@0: QueryInterface : XPCOMUtils.generateQI([nsIDOMMozAlarmsManager, michael@0: Ci.nsIDOMGlobalPropertyInitializer, michael@0: Ci.nsISupportsWeakReference, michael@0: Ci.nsIObserver]), michael@0: michael@0: classInfo : XPCOMUtils.generateCI({ classID: ALARMSMANAGER_CID, michael@0: contractID: ALARMSMANAGER_CONTRACTID, michael@0: classDescription: "AlarmsManager", michael@0: interfaces: [nsIDOMMozAlarmsManager], michael@0: flags: nsIClassInfo.DOM_OBJECT }), michael@0: michael@0: add: function add(aDate, aRespectTimezone, aData) { michael@0: debug("add()"); michael@0: michael@0: if (!this._manifestURL) { michael@0: debug("Cannot add alarms for non-installed apps."); michael@0: throw Components.results.NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (!aDate) { michael@0: throw Components.results.NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: let isIgnoreTimezone = true; michael@0: switch (aRespectTimezone) { michael@0: case "honorTimezone": michael@0: isIgnoreTimezone = false; michael@0: break; michael@0: michael@0: case "ignoreTimezone": michael@0: isIgnoreTimezone = true; michael@0: break; michael@0: michael@0: default: michael@0: throw Components.results.NS_ERROR_INVALID_ARG; michael@0: break; michael@0: } michael@0: michael@0: // Run JSON.stringify() in the sand box with the principal of the calling michael@0: // web page to ensure no cross-origin object is involved. A "Permission michael@0: // Denied" error will be thrown in case of privilege violation. michael@0: let sandbox = new Cu.Sandbox(this._window.document.nodePrincipal); michael@0: sandbox.data = aData; michael@0: let data = Cu.evalInSandbox("JSON.stringify(data)", sandbox); michael@0: let request = this.createRequest(); michael@0: this._cpmm.sendAsyncMessage( michael@0: "AlarmsManager:Add", michael@0: { requestId: this.getRequestId(request), michael@0: date: aDate, michael@0: ignoreTimezone: isIgnoreTimezone, michael@0: data: JSON.parse(data), michael@0: pageURL: this._pageURL, michael@0: manifestURL: this._manifestURL } michael@0: ); michael@0: return request; michael@0: }, michael@0: michael@0: remove: function remove(aId) { michael@0: debug("remove()"); michael@0: michael@0: this._cpmm.sendAsyncMessage( michael@0: "AlarmsManager:Remove", michael@0: { id: aId, manifestURL: this._manifestURL } michael@0: ); michael@0: }, michael@0: michael@0: getAll: function getAll() { michael@0: debug("getAll()"); michael@0: michael@0: let request = this.createRequest(); michael@0: this._cpmm.sendAsyncMessage( michael@0: "AlarmsManager:GetAll", michael@0: { requestId: this.getRequestId(request), manifestURL: this._manifestURL } michael@0: ); michael@0: return request; michael@0: }, michael@0: michael@0: receiveMessage: function receiveMessage(aMessage) { michael@0: debug("receiveMessage(): " + aMessage.name); michael@0: michael@0: let json = aMessage.json; michael@0: let request = this.getRequest(json.requestId); michael@0: michael@0: if (!request) { michael@0: debug("No request stored! " + json.requestId); michael@0: return; michael@0: } michael@0: michael@0: switch (aMessage.name) { michael@0: case "AlarmsManager:Add:Return:OK": michael@0: Services.DOMRequest.fireSuccess(request, json.id); michael@0: break; michael@0: michael@0: case "AlarmsManager:GetAll:Return:OK": michael@0: // We don't need to expose everything to the web content. michael@0: let alarms = []; michael@0: json.alarms.forEach(function trimAlarmInfo(aAlarm) { michael@0: let alarm = { "id": aAlarm.id, michael@0: "date": aAlarm.date, michael@0: "respectTimezone": aAlarm.ignoreTimezone ? michael@0: "ignoreTimezone" : "honorTimezone", michael@0: "data": aAlarm.data }; michael@0: alarms.push(alarm); michael@0: }); michael@0: Services.DOMRequest.fireSuccess(request, michael@0: Cu.cloneInto(alarms, this._window)); michael@0: break; michael@0: michael@0: case "AlarmsManager:Add:Return:KO": michael@0: Services.DOMRequest.fireError(request, json.errorMsg); michael@0: break; michael@0: michael@0: case "AlarmsManager:GetAll:Return:KO": michael@0: Services.DOMRequest.fireError(request, json.errorMsg); michael@0: break; michael@0: michael@0: default: michael@0: debug("Wrong message: " + aMessage.name); michael@0: break; michael@0: } michael@0: this.removeRequest(json.requestId); michael@0: }, michael@0: michael@0: // nsIDOMGlobalPropertyInitializer implementation michael@0: init: function init(aWindow) { michael@0: debug("init()"); michael@0: michael@0: // Set navigator.mozAlarms to null. michael@0: if (!Services.prefs.getBoolPref("dom.mozAlarms.enabled")) { michael@0: return null; michael@0: } michael@0: michael@0: // Only pages with perm set can use the alarms. michael@0: let principal = aWindow.document.nodePrincipal; michael@0: let perm = michael@0: Services.perms.testExactPermissionFromPrincipal(principal, "alarms"); michael@0: if (perm != Ci.nsIPermissionManager.ALLOW_ACTION) { michael@0: return null; michael@0: } michael@0: michael@0: // SystemPrincipal documents do not have any origin. michael@0: // Reject them for now. michael@0: if (!principal.URI) { michael@0: return null; michael@0: } michael@0: michael@0: this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"] michael@0: .getService(Ci.nsISyncMessageSender); michael@0: michael@0: // Add the valid messages to be listened. michael@0: this.initDOMRequestHelper(aWindow, ["AlarmsManager:Add:Return:OK", michael@0: "AlarmsManager:Add:Return:KO", michael@0: "AlarmsManager:GetAll:Return:OK", michael@0: "AlarmsManager:GetAll:Return:KO"]); michael@0: michael@0: // Get the manifest URL if this is an installed app michael@0: let appsService = Cc["@mozilla.org/AppsService;1"] michael@0: .getService(Ci.nsIAppsService); michael@0: this._pageURL = principal.URI.spec; michael@0: this._manifestURL = appsService.getManifestURLByLocalId(principal.appId); michael@0: this._window = aWindow; michael@0: }, michael@0: michael@0: // Called from DOMRequestIpcHelper. michael@0: uninit: function uninit() { michael@0: debug("uninit()"); michael@0: }, michael@0: } michael@0: michael@0: this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AlarmsManager])