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