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