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