]> git.saurik.com Git - apple/xnu.git/blob - osfmk/UserNotification/KUNCUserNotifications.c
8ad946ec3c1c8613445a66c32ba2ac32b0381ca1
[apple/xnu.git] / osfmk / UserNotification / KUNCUserNotifications.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <mach/port.h>
25 #include <mach/message.h>
26 #include <mach/kern_return.h>
27 #include <mach/host_priv.h>
28
29 #include <kern/kern_types.h>
30 #include <kern/kalloc.h>
31 #include <kern/host.h>
32 #include <kern/ipc_kobject.h>
33
34 #include <ipc/ipc_port.h>
35
36 #include <UserNotification/UNDTypes.h>
37 #include <UserNotification/UNDRequest.h>
38 #include <UserNotification/UNDReplyServer.h>
39 #include <UserNotification/KUNCUserNotifications.h>
40
41 #ifdef KERNEL_CF
42 // external
43 #include <IOKit/IOCFSerialize.h>
44 #include <IOKit/IOCFUnserialize.h>
45 #endif
46
47 /*
48 * DEFINES AND STRUCTURES
49 */
50
51 struct UNDReply {
52 decl_mutex_data(,lock) /* UNDReply lock */
53 int userLandNotificationKey;
54 KUNCUserNotificationCallBack callback;
55 boolean_t inprogress;
56 ipc_port_t self_port; /* Our port */
57 };
58
59 #define UNDReply_lock(reply) mutex_lock(&reply->lock)
60 #define UNDReply_lock_try(reply) mutex_lock_try(&(reply)->lock)
61 #define UNDReply_unlock(reply) mutex_unlock(&(reply)->lock)
62
63 /* forward declarations */
64 void UNDReply_deallocate(
65 UNDReplyRef reply);
66
67
68 void
69 UNDReply_deallocate(
70 UNDReplyRef reply)
71 {
72 ipc_port_t port;
73
74 UNDReply_lock(reply);
75 port = reply->self_port;
76 assert(IP_VALID(port));
77 ipc_kobject_set(port, IKO_NULL, IKOT_NONE);
78 reply->self_port = IP_NULL;
79 UNDReply_unlock(reply);
80
81 ipc_port_dealloc_kernel(port);
82 kfree(reply, sizeof(struct UNDReply));
83 return;
84 }
85
86 static UNDServerRef
87 UNDServer_reference(void)
88 {
89 UNDServerRef UNDServer;
90 kern_return_t kr;
91
92 kr = host_get_user_notification_port(host_priv_self(), &UNDServer);
93 assert(kr == KERN_SUCCESS);
94 return UNDServer;
95 }
96
97 static void
98 UNDServer_deallocate(
99 UNDServerRef UNDServer)
100 {
101 if (IP_VALID(UNDServer))
102 ipc_port_release_send(UNDServer);
103 }
104
105 /*
106 * UND Mig Callbacks
107 */
108
109 kern_return_t
110 UNDAlertCompletedWithResult_rpc (
111 UNDReplyRef reply,
112 int result,
113 xmlData_t keyRef, /* raw XML bytes */
114 mach_msg_type_number_t keyLen)
115 {
116 #ifdef KERNEL_CF
117 CFStringRef xmlError = NULL;
118 CFDictionaryRef dict = NULL;
119 #else
120 const void *dict = (const void *)keyRef;
121 #endif
122
123 if (reply == UND_REPLY_NULL || !reply->inprogress)
124 return KERN_INVALID_ARGUMENT;
125
126 /*
127 * JMM - No C vesion of the Unserialize code in-kernel
128 * and no C type for a CFDictionary either. For now,
129 * just pass the raw keyRef through.
130 */
131 #ifdef KERNEL_CF
132 if (keyRef && keyLen) {
133 dict = IOCFUnserialize(keyRef, NULL, NULL, &xmlError);
134 }
135
136 if (xmlError) {
137 CFShow(xmlError);
138 CFRelease(xmlError);
139 }
140 #endif /* KERNEL_CF */
141
142 if (reply->callback) {
143 (reply->callback)((KUNCUserNotificationID) reply, result, dict);
144 }
145
146 UNDReply_lock(reply);
147 reply->inprogress = FALSE;
148 reply->userLandNotificationKey = -1;
149 UNDReply_unlock(reply);
150 UNDReply_deallocate(reply);
151 return KERN_SUCCESS;
152 }
153
154 /*
155 * Routine: UNDNotificationCreated_rpc
156 *
157 * Intermediate routine. Allows the kernel mechanism
158 * to be informed that the notification request IS
159 * being processed by the user-level daemon, and how
160 * to identify that request.
161 */
162 kern_return_t
163 UNDNotificationCreated_rpc (
164 UNDReplyRef reply,
165 int userLandNotificationKey)
166 {
167 if (reply == UND_REPLY_NULL)
168 return KERN_INVALID_ARGUMENT;
169
170 UNDReply_lock(reply);
171 if (reply->inprogress || reply->userLandNotificationKey != -1) {
172 UNDReply_unlock(reply);
173 return KERN_INVALID_ARGUMENT;
174 }
175 reply->userLandNotificationKey = userLandNotificationKey;
176 UNDReply_unlock(reply);
177 return KERN_SUCCESS;
178 }
179
180 /*
181 * KUNC Functions
182 */
183
184
185 KUNCUserNotificationID
186 KUNCGetNotificationID()
187 {
188 UNDReplyRef reply;
189
190 reply = (UNDReplyRef) kalloc(sizeof(struct UNDReply));
191 if (reply != UND_REPLY_NULL) {
192 reply->self_port = ipc_port_alloc_kernel();
193 if (reply->self_port == IP_NULL) {
194 kfree(reply, sizeof(struct UNDReply));
195 reply = UND_REPLY_NULL;
196 } else {
197 mutex_init(&reply->lock, 0);
198 reply->userLandNotificationKey = -1;
199 reply->inprogress = FALSE;
200 ipc_kobject_set(reply->self_port,
201 (ipc_kobject_t)reply,
202 IKOT_UND_REPLY);
203 }
204 }
205 return (KUNCUserNotificationID) reply;
206 }
207
208
209 kern_return_t KUNCExecute(char executionPath[1024], int uid, int gid)
210 {
211
212 UNDServerRef UNDServer;
213
214 UNDServer = UNDServer_reference();
215 if (IP_VALID(UNDServer)) {
216 kern_return_t kr;
217 kr = UNDExecute_rpc(UNDServer, executionPath, uid, gid);
218 UNDServer_deallocate(UNDServer);
219 return kr;
220 }
221 return MACH_SEND_INVALID_DEST;
222 }
223
224 kern_return_t KUNCUserNotificationCancel(
225 KUNCUserNotificationID id)
226 {
227 UNDReplyRef reply = (UNDReplyRef)id;
228 kern_return_t kr;
229 int ulkey;
230
231 if (reply == UND_REPLY_NULL)
232 return KERN_INVALID_ARGUMENT;
233
234 UNDReply_lock(reply);
235 if (!reply->inprogress) {
236 UNDReply_unlock(reply);
237 return KERN_INVALID_ARGUMENT;
238 }
239
240 reply->inprogress = FALSE;
241 if ((ulkey = reply->userLandNotificationKey) != 0) {
242 UNDServerRef UNDServer;
243
244 reply->userLandNotificationKey = 0;
245 UNDReply_unlock(reply);
246
247 UNDServer = UNDServer_reference();
248 if (IP_VALID(UNDServer)) {
249 kr = UNDCancelNotification_rpc(UNDServer,ulkey);
250 UNDServer_deallocate(UNDServer);
251 } else
252 kr = MACH_SEND_INVALID_DEST;
253 } else {
254 UNDReply_unlock(reply);
255 kr = KERN_SUCCESS;
256 }
257 UNDReply_deallocate(reply);
258 return kr;
259 }
260
261 kern_return_t
262 KUNCUserNotificationDisplayNotice(
263 int noticeTimeout,
264 unsigned flags,
265 char *iconPath,
266 char *soundPath,
267 char *localizationPath,
268 char *alertHeader,
269 char *alertMessage,
270 char *defaultButtonTitle)
271 {
272 UNDServerRef UNDServer;
273
274 UNDServer = UNDServer_reference();
275 if (IP_VALID(UNDServer)) {
276 kern_return_t kr;
277 kr = UNDDisplayNoticeSimple_rpc(UNDServer,
278 noticeTimeout,
279 flags,
280 iconPath,
281 soundPath,
282 localizationPath,
283 alertHeader,
284 alertMessage,
285 defaultButtonTitle);
286 UNDServer_deallocate(UNDServer);
287 return kr;
288 }
289 return MACH_SEND_INVALID_DEST;
290 }
291
292 kern_return_t
293 KUNCUserNotificationDisplayAlert(
294 int alertTimeout,
295 unsigned flags,
296 char *iconPath,
297 char *soundPath,
298 char *localizationPath,
299 char *alertHeader,
300 char *alertMessage,
301 char *defaultButtonTitle,
302 char *alternateButtonTitle,
303 char *otherButtonTitle,
304 unsigned *responseFlags)
305 {
306 UNDServerRef UNDServer;
307
308 UNDServer = UNDServer_reference();
309 if (IP_VALID(UNDServer)) {
310 kern_return_t kr;
311 kr = UNDDisplayAlertSimple_rpc(UNDServer,
312 alertTimeout,
313 flags,
314 iconPath,
315 soundPath,
316 localizationPath,
317 alertHeader,
318 alertMessage,
319 defaultButtonTitle,
320 alternateButtonTitle,
321 otherButtonTitle,
322 responseFlags);
323 UNDServer_deallocate(UNDServer);
324 return kr;
325 }
326 return MACH_SEND_INVALID_DEST;
327 }
328
329 kern_return_t
330 KUNCUserNotificationDisplayFromBundle(
331 KUNCUserNotificationID id,
332 char *bundlePath,
333 char *fileName,
334 char *fileExtension,
335 char *messageKey,
336 char *tokenString,
337 KUNCUserNotificationCallBack callback,
338 __unused int contextKey)
339 {
340 UNDReplyRef reply = (UNDReplyRef)id;
341 UNDServerRef UNDServer;
342 ipc_port_t reply_port;
343
344 if (reply == UND_REPLY_NULL)
345 return KERN_INVALID_ARGUMENT;
346 UNDReply_lock(reply);
347 if (reply->inprogress == TRUE || reply->userLandNotificationKey != -1) {
348 UNDReply_unlock(reply);
349 return KERN_INVALID_ARGUMENT;
350 }
351 reply->inprogress = TRUE;
352 reply->callback = callback;
353 reply_port = ipc_port_make_send(reply->self_port);
354 UNDReply_unlock(reply);
355
356 UNDServer = UNDServer_reference();
357 if (IP_VALID(UNDServer)) {
358 kern_return_t kr;
359
360 kr = UNDDisplayCustomFromBundle_rpc(UNDServer,
361 reply_port,
362 bundlePath,
363 fileName,
364 fileExtension,
365 messageKey,
366 tokenString);
367 UNDServer_deallocate(UNDServer);
368 return kr;
369 }
370 return MACH_SEND_INVALID_DEST;
371 }
372
373 /*
374 * Routine: convert_port_to_UNDReply
375 *
376 * MIG helper routine to convert from a mach port to a
377 * UNDReply object.
378 *
379 * Assumptions:
380 * Nothing locked.
381 */
382 UNDReplyRef
383 convert_port_to_UNDReply(
384 ipc_port_t port)
385 {
386 if (IP_VALID(port)) {
387 UNDReplyRef reply;
388
389 ip_lock(port);
390 if (!ip_active(port) || (ip_kotype(port) != IKOT_UND_REPLY)) {
391 ip_unlock(port);
392 return UND_REPLY_NULL;
393 }
394 reply = (UNDReplyRef) port->ip_kobject;
395 assert(reply != UND_REPLY_NULL);
396 ip_unlock(port);
397 return reply;
398 }
399 return UND_REPLY_NULL;
400 }
401
402 /*
403 * User interface for setting the host UserNotification Daemon port.
404 */
405
406 kern_return_t
407 host_set_UNDServer(
408 host_priv_t host_priv,
409 UNDServerRef server)
410 {
411 return (host_set_user_notification_port(host_priv, server));
412 }
413
414 /*
415 * User interface for retrieving the UserNotification Daemon port.
416 */
417
418 kern_return_t
419 host_get_UNDServer(
420 host_priv_t host_priv,
421 UNDServerRef *serverp)
422 {
423 return (host_get_user_notification_port(host_priv, serverp));
424 }