michael@0: /* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ 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 michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: const {classes: Cc, interfaces: Ci, utils: Cu} = Components; michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: michael@0: XPCOMUtils.defineLazyModuleGetter(this, "getFrameWorkerHandle", "resource://gre/modules/FrameWorker.jsm"); michael@0: XPCOMUtils.defineLazyModuleGetter(this, "openChatWindow", "resource://gre/modules/MozSocialAPI.jsm"); michael@0: michael@0: this.EXPORTED_SYMBOLS = ["WorkerAPI"]; michael@0: michael@0: this.WorkerAPI = function WorkerAPI(provider, port) { michael@0: if (!port) michael@0: throw new Error("Can't initialize WorkerAPI with a null port"); michael@0: michael@0: this._provider = provider; michael@0: this._port = port; michael@0: this._port.onmessage = this._handleMessage.bind(this); michael@0: michael@0: // Send an "intro" message so the worker knows this is the port michael@0: // used for the api. michael@0: // later we might even include an API version - version 0 for now! michael@0: this._port.postMessage({topic: "social.initialize"}); michael@0: } michael@0: michael@0: WorkerAPI.prototype = { michael@0: terminate: function terminate() { michael@0: this._port.close(); michael@0: }, michael@0: michael@0: _handleMessage: function _handleMessage(event) { michael@0: let {topic, data} = event.data; michael@0: let handler = this.handlers[topic]; michael@0: if (!handler) { michael@0: Cu.reportError("WorkerAPI: topic doesn't have a handler: '" + topic + "'"); michael@0: return; michael@0: } michael@0: try { michael@0: handler.call(this, data); michael@0: } catch (ex) { michael@0: Cu.reportError("WorkerAPI: failed to handle message '" + topic + "': " + ex + "\n" + ex.stack); michael@0: } michael@0: }, michael@0: michael@0: handlers: { michael@0: "social.manifest-get": function(data) { michael@0: // retreive the currently installed manifest from firefox michael@0: this._port.postMessage({topic: "social.manifest", data: this._provider.manifest}); michael@0: }, michael@0: "social.manifest-set": function(data) { michael@0: // the provider will get reloaded as a result of this call michael@0: let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService; michael@0: let origin = this._provider.origin; michael@0: SocialService.updateProvider(origin, data); michael@0: }, michael@0: "social.reload-worker": function(data) { michael@0: this._provider.reload(); michael@0: }, michael@0: "social.user-profile": function (data) { michael@0: this._provider.updateUserProfile(data); michael@0: }, michael@0: "social.ambient-notification": function (data) { michael@0: this._provider.setAmbientNotification(data); michael@0: }, michael@0: "social.cookies-get": function(data) { michael@0: // We don't want to trust provider.origin etc, just incase the provider michael@0: // redirected away or something else bad is going on. So we want to michael@0: // reach into the Worker's document and fetch the actual cookies it has. michael@0: // We need to do this via our own message dance. michael@0: let port = this._port; michael@0: let whandle = getFrameWorkerHandle(this._provider.workerURL, null); michael@0: whandle.port.close(); michael@0: whandle._worker.browserPromise.then(browser => { michael@0: let mm = browser.messageManager; michael@0: mm.addMessageListener("frameworker:cookie-get-response", function _onCookieResponse(msg) { michael@0: mm.removeMessageListener("frameworker:cookie-get-response", _onCookieResponse); michael@0: let cookies = msg.json.split(";"); michael@0: let results = []; michael@0: cookies.forEach(function(aCookie) { michael@0: let [name, value] = aCookie.split("="); michael@0: if (name || value) { michael@0: results.push({name: unescape(name.trim()), michael@0: value: value ? unescape(value.trim()) : ""}); michael@0: } michael@0: }); michael@0: port.postMessage({topic: "social.cookies-get-response", michael@0: data: results}); michael@0: }); michael@0: mm.sendAsyncMessage("frameworker:cookie-get"); michael@0: }); michael@0: }, michael@0: 'social.request-chat': function(data) { michael@0: openChatWindow(null, this._provider, data); michael@0: }, michael@0: 'social.notification-create': function(data) { michael@0: if (!Services.prefs.getBoolPref("social.toast-notifications.enabled")) michael@0: return; michael@0: michael@0: let port = this._port; michael@0: let provider = this._provider; michael@0: let {id, type, icon, body, action, actionArgs} = data; michael@0: let alertsService = Cc["@mozilla.org/alerts-service;1"] michael@0: .getService(Ci.nsIAlertsService); michael@0: function listener(subject, topic, data) { michael@0: if (topic === "alertclickcallback") { michael@0: // we always post back the click michael@0: port.postMessage({topic: "social.notification-action", michael@0: data: {id: id, michael@0: action: action, michael@0: actionArgs: actionArgs}}); michael@0: switch (action) { michael@0: case "link": michael@0: // if there is a url, make it open a tab michael@0: if (actionArgs.toURL) { michael@0: let uriToOpen = provider.resolveUri(actionArgs.toURL); michael@0: // Bug 815970 - facebook gives us http:// links even though michael@0: // the origin is https:// - so we perform a fixup here. michael@0: let pUri = Services.io.newURI(provider.origin, null, null); michael@0: if (uriToOpen.scheme != pUri.scheme) michael@0: uriToOpen.scheme = pUri.scheme; michael@0: if (provider.isSameOrigin(uriToOpen)) { michael@0: let xulWindow = Services.wm.getMostRecentWindow("navigator:browser"); michael@0: xulWindow.openUILinkIn(uriToOpen.spec, "tab"); michael@0: } else { michael@0: Cu.reportError("Not opening notification link " + actionArgs.toURL michael@0: + " as not in provider origin"); michael@0: } michael@0: } michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: alertsService.showAlertNotification(icon, michael@0: this._provider.name, // title michael@0: body, michael@0: !!action, // text clickable if an michael@0: // action was provided. michael@0: null, michael@0: listener, michael@0: type); michael@0: }, michael@0: } michael@0: }