1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is DesktopNotification.
15 : *
16 : * The Initial Developer of the Original Code is Mozilla Foundation
17 : * Portions created by the Initial Developer are Copyright (C) 2010
18 : * the Initial Developer. All Rights Reserved.
19 : *
20 : * Contributor(s):
21 : * Doug Turner <dougt@dougt.org> (Original Author)
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either the GNU General Public License Version 2 or later (the "GPL"), or
25 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #include "nsDesktopNotification.h"
38 :
39 : #include "nsContentPermissionHelper.h"
40 : #include "nsXULAppAPI.h"
41 :
42 : #include "mozilla/dom/PBrowserChild.h"
43 : #include "TabChild.h"
44 : #include "mozilla/Preferences.h"
45 :
46 : using namespace mozilla;
47 : using namespace mozilla::dom;
48 :
49 : /* ------------------------------------------------------------------------ */
50 : /* AlertServiceObserver */
51 : /* ------------------------------------------------------------------------ */
52 :
53 0 : NS_IMPL_ISUPPORTS1(AlertServiceObserver, nsIObserver)
54 :
55 : /* ------------------------------------------------------------------------ */
56 : /* nsDesktopNotification */
57 : /* ------------------------------------------------------------------------ */
58 :
59 : void
60 0 : nsDOMDesktopNotification::PostDesktopNotification()
61 : {
62 0 : nsCOMPtr<nsIAlertsService> alerts = do_GetService("@mozilla.org/alerts-service;1");
63 0 : if (!alerts)
64 : return;
65 :
66 0 : if (!mObserver)
67 0 : mObserver = new AlertServiceObserver(this);
68 :
69 0 : alerts->ShowAlertNotification(mIconURL, mTitle, mDescription,
70 : true,
71 0 : EmptyString(),
72 : mObserver,
73 0 : EmptyString());
74 : }
75 :
76 : DOMCI_DATA(DesktopNotification, nsDOMDesktopNotification)
77 :
78 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMDesktopNotification)
79 :
80 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMDesktopNotification, nsDOMEventTargetHelper)
81 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnClickCallback)
82 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnCloseCallback)
83 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
84 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMDesktopNotification, nsDOMEventTargetHelper)
85 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnClickCallback)
86 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnCloseCallback)
87 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
88 :
89 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMDesktopNotification)
90 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDesktopNotification)
91 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMDesktopNotification)
92 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DesktopNotification)
93 0 : NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
94 :
95 0 : NS_IMPL_ADDREF_INHERITED(nsDOMDesktopNotification, nsDOMEventTargetHelper)
96 0 : NS_IMPL_RELEASE_INHERITED(nsDOMDesktopNotification, nsDOMEventTargetHelper)
97 :
98 0 : nsDOMDesktopNotification::nsDOMDesktopNotification(const nsAString & title,
99 : const nsAString & description,
100 : const nsAString & iconURL,
101 : nsPIDOMWindow *aWindow,
102 : nsIURI* uri)
103 : : mTitle(title)
104 : , mDescription(description)
105 : , mIconURL(iconURL)
106 : , mURI(uri)
107 : , mAllow(false)
108 0 : , mShowHasBeenCalled(false)
109 : {
110 0 : BindToOwner(aWindow);
111 0 : if (Preferences::GetBool("notification.disabled", false)) {
112 0 : return;
113 : }
114 :
115 : // If we are in testing mode (running mochitests, for example)
116 : // and we are suppose to allow requests, then just post an allow event.
117 0 : if (Preferences::GetBool("notification.prompt.testing", false) &&
118 0 : Preferences::GetBool("notification.prompt.testing.allow", true)) {
119 0 : mAllow = true;
120 0 : return;
121 : }
122 :
123 0 : nsRefPtr<nsDesktopNotificationRequest> request = new nsDesktopNotificationRequest(this);
124 :
125 : // if we are in the content process, then remote it to the parent.
126 0 : if (XRE_GetProcessType() == GeckoProcessType_Content) {
127 :
128 : // if for some reason mOwner is null, just silently
129 : // bail. The user will not see a notification, and that
130 : // is fine.
131 0 : if (!GetOwner())
132 : return;
133 :
134 : // because owner implements nsITabChild, we can assume that it is
135 : // the one and only TabChild for this docshell.
136 0 : TabChild* child = GetTabChildFrom(GetOwner()->GetDocShell());
137 :
138 : // Retain a reference so the object isn't deleted without IPDL's knowledge.
139 : // Corresponding release occurs in DeallocPContentPermissionRequest.
140 0 : nsRefPtr<nsDesktopNotificationRequest> copy = request;
141 :
142 0 : nsCString type = NS_LITERAL_CSTRING("desktop-notification");
143 0 : child->SendPContentPermissionRequestConstructor(copy.forget().get(), type, IPC::URI(mURI));
144 :
145 0 : request->Sendprompt();
146 : return;
147 : }
148 :
149 : // otherwise, dispatch it
150 0 : NS_DispatchToMainThread(request);
151 :
152 : }
153 :
154 0 : nsDOMDesktopNotification::~nsDOMDesktopNotification()
155 : {
156 0 : if (mObserver) {
157 0 : mObserver->Disconnect();
158 : }
159 0 : }
160 :
161 : void
162 0 : nsDOMDesktopNotification::DispatchNotificationEvent(const nsString& aName)
163 : {
164 0 : if (NS_FAILED(CheckInnerWindowCorrectness())) {
165 0 : return;
166 : }
167 :
168 0 : nsCOMPtr<nsIDOMEvent> event;
169 0 : nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), nsnull, nsnull);
170 0 : if (NS_SUCCEEDED(rv)) {
171 : // it doesn't bubble, and it isn't cancelable
172 0 : rv = event->InitEvent(aName, false, false);
173 0 : if (NS_SUCCEEDED(rv)) {
174 0 : nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
175 0 : privateEvent->SetTrusted(true);
176 0 : DispatchDOMEvent(nsnull, event, nsnull, nsnull);
177 : }
178 : }
179 : }
180 :
181 : void
182 0 : nsDOMDesktopNotification::SetAllow(bool aAllow)
183 : {
184 0 : mAllow = aAllow;
185 :
186 : // if we have called Show() already, lets go ahead and post a notification
187 0 : if (mShowHasBeenCalled && aAllow)
188 0 : PostDesktopNotification();
189 0 : }
190 :
191 : void
192 0 : nsDOMDesktopNotification::HandleAlertServiceNotification(const char *aTopic)
193 : {
194 0 : if (NS_FAILED(CheckInnerWindowCorrectness()))
195 0 : return;
196 :
197 0 : if (!strcmp("alertclickcallback", aTopic)) {
198 0 : DispatchNotificationEvent(NS_LITERAL_STRING("click"));
199 0 : } else if (!strcmp("alertfinished", aTopic)) {
200 0 : DispatchNotificationEvent(NS_LITERAL_STRING("close"));
201 : }
202 : }
203 :
204 : NS_IMETHODIMP
205 0 : nsDOMDesktopNotification::Show()
206 : {
207 0 : mShowHasBeenCalled = true;
208 :
209 0 : if (!mAllow)
210 0 : return NS_OK;
211 :
212 0 : PostDesktopNotification();
213 0 : return NS_OK;
214 : }
215 :
216 : NS_IMETHODIMP
217 0 : nsDOMDesktopNotification::GetOnclick(nsIDOMEventListener * *aOnclick)
218 : {
219 0 : return GetInnerEventListener(mOnClickCallback, aOnclick);
220 : }
221 :
222 0 : NS_IMETHODIMP nsDOMDesktopNotification::SetOnclick(nsIDOMEventListener * aOnclick)
223 : {
224 0 : return RemoveAddEventListener(NS_LITERAL_STRING("click"),
225 : mOnClickCallback,
226 0 : aOnclick);
227 : }
228 :
229 : NS_IMETHODIMP
230 0 : nsDOMDesktopNotification::GetOnclose(nsIDOMEventListener * *aOnclose)
231 : {
232 0 : return GetInnerEventListener(mOnCloseCallback, aOnclose);
233 : }
234 :
235 0 : NS_IMETHODIMP nsDOMDesktopNotification::SetOnclose(nsIDOMEventListener * aOnclose)
236 : {
237 0 : return RemoveAddEventListener(NS_LITERAL_STRING("close"),
238 : mOnCloseCallback,
239 0 : aOnclose);
240 : }
241 :
242 : /* ------------------------------------------------------------------------ */
243 : /* nsDesktopNotificationCenter */
244 : /* ------------------------------------------------------------------------ */
245 :
246 : DOMCI_DATA(DesktopNotificationCenter, nsDesktopNotificationCenter)
247 :
248 0 : NS_INTERFACE_MAP_BEGIN(nsDesktopNotificationCenter)
249 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDesktopNotificationCenter)
250 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMDesktopNotificationCenter)
251 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DesktopNotificationCenter)
252 0 : NS_INTERFACE_MAP_END
253 :
254 0 : NS_IMPL_ADDREF(nsDesktopNotificationCenter)
255 0 : NS_IMPL_RELEASE(nsDesktopNotificationCenter)
256 :
257 : NS_IMETHODIMP
258 0 : nsDesktopNotificationCenter::CreateNotification(const nsAString & title,
259 : const nsAString & description,
260 : const nsAString & iconURL,
261 : nsIDOMDesktopNotification **aResult)
262 : {
263 0 : NS_ENSURE_STATE(mOwner);
264 : nsRefPtr<nsIDOMDesktopNotification> notification = new nsDOMDesktopNotification(title,
265 : description,
266 : iconURL,
267 : mOwner,
268 0 : mURI);
269 0 : notification.forget(aResult);
270 0 : return NS_OK;
271 : }
272 :
273 :
274 : /* ------------------------------------------------------------------------ */
275 : /* nsDesktopNotificationRequest */
276 : /* ------------------------------------------------------------------------ */
277 :
278 0 : NS_IMPL_ISUPPORTS2(nsDesktopNotificationRequest,
279 : nsIContentPermissionRequest,
280 : nsIRunnable)
281 :
282 : NS_IMETHODIMP
283 0 : nsDesktopNotificationRequest::GetUri(nsIURI * *aRequestingURI)
284 : {
285 0 : if (!mDesktopNotification)
286 0 : return NS_ERROR_NOT_INITIALIZED;
287 :
288 0 : NS_IF_ADDREF(*aRequestingURI = mDesktopNotification->mURI);
289 0 : return NS_OK;
290 : }
291 :
292 : NS_IMETHODIMP
293 0 : nsDesktopNotificationRequest::GetWindow(nsIDOMWindow * *aRequestingWindow)
294 : {
295 0 : if (!mDesktopNotification)
296 0 : return NS_ERROR_NOT_INITIALIZED;
297 :
298 : nsCOMPtr<nsIDOMWindow> window =
299 0 : do_QueryInterface(mDesktopNotification->GetOwner());
300 0 : NS_IF_ADDREF(*aRequestingWindow = window);
301 0 : return NS_OK;
302 : }
303 :
304 : NS_IMETHODIMP
305 0 : nsDesktopNotificationRequest::GetElement(nsIDOMElement * *aElement)
306 : {
307 0 : return NS_ERROR_FAILURE;
308 : }
309 :
310 : NS_IMETHODIMP
311 0 : nsDesktopNotificationRequest::Cancel()
312 : {
313 0 : mDesktopNotification->SetAllow(false);
314 0 : mDesktopNotification = nsnull;
315 0 : return NS_OK;
316 : }
317 :
318 : NS_IMETHODIMP
319 0 : nsDesktopNotificationRequest::Allow()
320 : {
321 0 : mDesktopNotification->SetAllow(true);
322 0 : mDesktopNotification = nsnull;
323 0 : return NS_OK;
324 : }
325 :
326 : NS_IMETHODIMP
327 0 : nsDesktopNotificationRequest::GetType(nsACString & aType)
328 : {
329 0 : aType = "desktop-notification";
330 0 : return NS_OK;
331 4392 : }
332 :
|