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