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