|
1 /* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=2 et sw=2 tw=80: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 "use strict"; |
|
8 |
|
9 const {classes: Cc, interfaces: Ci, utils: Cu} = Components; |
|
10 Cu.import("resource://gre/modules/Services.jsm"); |
|
11 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
12 |
|
13 XPCOMUtils.defineLazyModuleGetter(this, "getFrameWorkerHandle", "resource://gre/modules/FrameWorker.jsm"); |
|
14 XPCOMUtils.defineLazyModuleGetter(this, "openChatWindow", "resource://gre/modules/MozSocialAPI.jsm"); |
|
15 |
|
16 this.EXPORTED_SYMBOLS = ["WorkerAPI"]; |
|
17 |
|
18 this.WorkerAPI = function WorkerAPI(provider, port) { |
|
19 if (!port) |
|
20 throw new Error("Can't initialize WorkerAPI with a null port"); |
|
21 |
|
22 this._provider = provider; |
|
23 this._port = port; |
|
24 this._port.onmessage = this._handleMessage.bind(this); |
|
25 |
|
26 // Send an "intro" message so the worker knows this is the port |
|
27 // used for the api. |
|
28 // later we might even include an API version - version 0 for now! |
|
29 this._port.postMessage({topic: "social.initialize"}); |
|
30 } |
|
31 |
|
32 WorkerAPI.prototype = { |
|
33 terminate: function terminate() { |
|
34 this._port.close(); |
|
35 }, |
|
36 |
|
37 _handleMessage: function _handleMessage(event) { |
|
38 let {topic, data} = event.data; |
|
39 let handler = this.handlers[topic]; |
|
40 if (!handler) { |
|
41 Cu.reportError("WorkerAPI: topic doesn't have a handler: '" + topic + "'"); |
|
42 return; |
|
43 } |
|
44 try { |
|
45 handler.call(this, data); |
|
46 } catch (ex) { |
|
47 Cu.reportError("WorkerAPI: failed to handle message '" + topic + "': " + ex + "\n" + ex.stack); |
|
48 } |
|
49 }, |
|
50 |
|
51 handlers: { |
|
52 "social.manifest-get": function(data) { |
|
53 // retreive the currently installed manifest from firefox |
|
54 this._port.postMessage({topic: "social.manifest", data: this._provider.manifest}); |
|
55 }, |
|
56 "social.manifest-set": function(data) { |
|
57 // the provider will get reloaded as a result of this call |
|
58 let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService; |
|
59 let origin = this._provider.origin; |
|
60 SocialService.updateProvider(origin, data); |
|
61 }, |
|
62 "social.reload-worker": function(data) { |
|
63 this._provider.reload(); |
|
64 }, |
|
65 "social.user-profile": function (data) { |
|
66 this._provider.updateUserProfile(data); |
|
67 }, |
|
68 "social.ambient-notification": function (data) { |
|
69 this._provider.setAmbientNotification(data); |
|
70 }, |
|
71 "social.cookies-get": function(data) { |
|
72 // We don't want to trust provider.origin etc, just incase the provider |
|
73 // redirected away or something else bad is going on. So we want to |
|
74 // reach into the Worker's document and fetch the actual cookies it has. |
|
75 // We need to do this via our own message dance. |
|
76 let port = this._port; |
|
77 let whandle = getFrameWorkerHandle(this._provider.workerURL, null); |
|
78 whandle.port.close(); |
|
79 whandle._worker.browserPromise.then(browser => { |
|
80 let mm = browser.messageManager; |
|
81 mm.addMessageListener("frameworker:cookie-get-response", function _onCookieResponse(msg) { |
|
82 mm.removeMessageListener("frameworker:cookie-get-response", _onCookieResponse); |
|
83 let cookies = msg.json.split(";"); |
|
84 let results = []; |
|
85 cookies.forEach(function(aCookie) { |
|
86 let [name, value] = aCookie.split("="); |
|
87 if (name || value) { |
|
88 results.push({name: unescape(name.trim()), |
|
89 value: value ? unescape(value.trim()) : ""}); |
|
90 } |
|
91 }); |
|
92 port.postMessage({topic: "social.cookies-get-response", |
|
93 data: results}); |
|
94 }); |
|
95 mm.sendAsyncMessage("frameworker:cookie-get"); |
|
96 }); |
|
97 }, |
|
98 'social.request-chat': function(data) { |
|
99 openChatWindow(null, this._provider, data); |
|
100 }, |
|
101 'social.notification-create': function(data) { |
|
102 if (!Services.prefs.getBoolPref("social.toast-notifications.enabled")) |
|
103 return; |
|
104 |
|
105 let port = this._port; |
|
106 let provider = this._provider; |
|
107 let {id, type, icon, body, action, actionArgs} = data; |
|
108 let alertsService = Cc["@mozilla.org/alerts-service;1"] |
|
109 .getService(Ci.nsIAlertsService); |
|
110 function listener(subject, topic, data) { |
|
111 if (topic === "alertclickcallback") { |
|
112 // we always post back the click |
|
113 port.postMessage({topic: "social.notification-action", |
|
114 data: {id: id, |
|
115 action: action, |
|
116 actionArgs: actionArgs}}); |
|
117 switch (action) { |
|
118 case "link": |
|
119 // if there is a url, make it open a tab |
|
120 if (actionArgs.toURL) { |
|
121 let uriToOpen = provider.resolveUri(actionArgs.toURL); |
|
122 // Bug 815970 - facebook gives us http:// links even though |
|
123 // the origin is https:// - so we perform a fixup here. |
|
124 let pUri = Services.io.newURI(provider.origin, null, null); |
|
125 if (uriToOpen.scheme != pUri.scheme) |
|
126 uriToOpen.scheme = pUri.scheme; |
|
127 if (provider.isSameOrigin(uriToOpen)) { |
|
128 let xulWindow = Services.wm.getMostRecentWindow("navigator:browser"); |
|
129 xulWindow.openUILinkIn(uriToOpen.spec, "tab"); |
|
130 } else { |
|
131 Cu.reportError("Not opening notification link " + actionArgs.toURL |
|
132 + " as not in provider origin"); |
|
133 } |
|
134 } |
|
135 break; |
|
136 default: |
|
137 break; |
|
138 } |
|
139 } |
|
140 } |
|
141 alertsService.showAlertNotification(icon, |
|
142 this._provider.name, // title |
|
143 body, |
|
144 !!action, // text clickable if an |
|
145 // action was provided. |
|
146 null, |
|
147 listener, |
|
148 type); |
|
149 }, |
|
150 } |
|
151 } |