]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
55e303ae | 2 | * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. |
1c79356b A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
43866e37 | 6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
1c79356b | 7 | * |
43866e37 A |
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 | |
1c79356b A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
43866e37 A |
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. | |
1c79356b A |
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 | ||
1c79356b A |
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; | |
55e303ae | 67 | |
1c79356b A |
68 | UNDReply_lock(reply); |
69 | port = reply->self_port; | |
55e303ae | 70 | assert(IP_VALID(port)); |
1c79356b A |
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 | ||
55e303ae A |
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 | ||
1c79356b A |
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 | { | |
55e303ae A |
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; | |
1c79356b A |
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) { | |
55e303ae A |
236 | UNDServerRef UNDServer; |
237 | ||
1c79356b A |
238 | reply->userLandNotificationKey = 0; |
239 | UNDReply_unlock(reply); | |
55e303ae A |
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; | |
1c79356b A |
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 | { | |
55e303ae A |
266 | UNDServerRef UNDServer; |
267 | ||
268 | UNDServer = UNDServer_reference(); | |
269 | if (IP_VALID(UNDServer)) { | |
270 | kern_return_t kr; | |
271 | kr = UNDDisplayNoticeSimple_rpc(UNDServer, | |
1c79356b A |
272 | timeout, |
273 | flags, | |
274 | iconPath, | |
275 | soundPath, | |
276 | localizationPath, | |
277 | alertHeader, | |
278 | alertMessage, | |
279 | defaultButtonTitle); | |
55e303ae A |
280 | UNDServer_deallocate(UNDServer); |
281 | return kr; | |
282 | } | |
283 | return MACH_SEND_INVALID_DEST; | |
1c79356b A |
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 | { | |
55e303ae | 300 | UNDServerRef UNDServer; |
1c79356b | 301 | |
55e303ae A |
302 | UNDServer = UNDServer_reference(); |
303 | if (IP_VALID(UNDServer)) { | |
304 | kern_return_t kr; | |
305 | kr = UNDDisplayAlertSimple_rpc(UNDServer, | |
1c79356b A |
306 | timeout, |
307 | flags, | |
308 | iconPath, | |
309 | soundPath, | |
310 | localizationPath, | |
311 | alertHeader, | |
312 | alertMessage, | |
313 | defaultButtonTitle, | |
314 | alternateButtonTitle, | |
315 | otherButtonTitle, | |
316 | responseFlags); | |
55e303ae A |
317 | UNDServer_deallocate(UNDServer); |
318 | return kr; | |
319 | } | |
320 | return MACH_SEND_INVALID_DEST; | |
1c79356b A |
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; | |
55e303ae | 335 | UNDServerRef UNDServer; |
1c79356b | 336 | ipc_port_t reply_port; |
1c79356b A |
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 | ||
55e303ae A |
350 | UNDServer = UNDServer_reference(); |
351 | if (IP_VALID(UNDServer)) { | |
352 | kern_return_t kr; | |
353 | ||
354 | kr = UNDDisplayCustomFromBundle_rpc(UNDServer, | |
1c79356b A |
355 | reply_port, |
356 | bundlePath, | |
357 | fileName, | |
358 | fileExtension, | |
359 | messageKey, | |
360 | tokenString); | |
55e303ae A |
361 | UNDServer_deallocate(UNDServer); |
362 | return kr; | |
363 | } | |
364 | return MACH_SEND_INVALID_DEST; | |
1c79356b A |
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); | |
55e303ae | 391 | return reply; |
1c79356b A |
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 | { | |
55e303ae | 405 | return (host_set_user_notification_port(host_priv, server)); |
1c79356b A |
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, | |
55e303ae | 415 | UNDServerRef *serverp) |
1c79356b | 416 | { |
55e303ae | 417 | return (host_get_user_notification_port(host_priv, serverp)); |
1c79356b | 418 | } |