]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2000 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 | UNDServerRef gUNDServer = UND_SERVER_NULL; | |
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 | UNDReply_lock(reply); | |
68 | port = reply->self_port; | |
69 | ipc_kobject_set(port, IKO_NULL, IKOT_NONE); | |
70 | reply->self_port = IP_NULL; | |
71 | UNDReply_unlock(reply); | |
72 | ||
73 | ipc_port_dealloc_kernel(port); | |
74 | kfree((vm_offset_t)reply, sizeof(struct UNDReply)); | |
75 | return; | |
76 | } | |
77 | ||
78 | /* | |
79 | * UND Mig Callbacks | |
80 | */ | |
81 | ||
82 | kern_return_t | |
83 | UNDAlertCompletedWithResult_rpc ( | |
84 | UNDReplyRef reply, | |
85 | int result, | |
86 | xmlData_t keyRef, /* raw XML bytes */ | |
87 | mach_msg_type_number_t keyLen) | |
88 | { | |
89 | #ifdef KERNEL_CF | |
90 | CFStringRef xmlError = NULL; | |
91 | CFDictionaryRef dict = NULL; | |
92 | #else | |
93 | void *dict = (void *)keyRef; | |
94 | #endif | |
95 | ||
96 | if (reply == UND_REPLY_NULL || !reply->inprogress) | |
97 | return KERN_INVALID_ARGUMENT; | |
98 | ||
99 | /* | |
100 | * JMM - No C vesion of the Unserialize code in-kernel | |
101 | * and no C type for a CFDictionary either. For now, | |
102 | * just pass the raw keyRef through. | |
103 | */ | |
104 | #ifdef KERNEL_CF | |
105 | if (keyRef && keyLen) { | |
106 | dict = IOCFUnserialize(keyRef, NULL, NULL, &xmlError); | |
107 | } | |
108 | ||
109 | if (xmlError) { | |
110 | CFShow(xmlError); | |
111 | CFRelease(xmlError); | |
112 | } | |
113 | #endif /* KERNEL_CF */ | |
114 | ||
115 | if (reply->callback) { | |
116 | (reply->callback)((KUNCUserNotificationID) reply, result, dict); | |
117 | } | |
118 | ||
119 | UNDReply_lock(reply); | |
120 | reply->inprogress = FALSE; | |
121 | reply->userLandNotificationKey = -1; | |
122 | UNDReply_unlock(reply); | |
123 | UNDReply_deallocate(reply); | |
124 | return KERN_SUCCESS; | |
125 | } | |
126 | ||
127 | /* | |
128 | * Routine: UNDNotificationCreated_rpc | |
129 | * | |
130 | * Intermediate routine. Allows the kernel mechanism | |
131 | * to be informed that the notification request IS | |
132 | * being processed by the user-level daemon, and how | |
133 | * to identify that request. | |
134 | */ | |
135 | kern_return_t | |
136 | UNDNotificationCreated_rpc ( | |
137 | UNDReplyRef reply, | |
138 | int userLandNotificationKey) | |
139 | { | |
140 | if (reply == UND_REPLY_NULL) | |
141 | return KERN_INVALID_ARGUMENT; | |
142 | ||
143 | UNDReply_lock(reply); | |
144 | if (reply->inprogress || reply->userLandNotificationKey != -1) { | |
145 | UNDReply_unlock(reply); | |
146 | return KERN_INVALID_ARGUMENT; | |
147 | } | |
148 | reply->userLandNotificationKey = userLandNotificationKey; | |
149 | UNDReply_unlock(reply); | |
150 | return KERN_SUCCESS; | |
151 | } | |
152 | ||
153 | /* | |
154 | * KUNC Functions | |
155 | */ | |
156 | ||
157 | ||
158 | KUNCUserNotificationID | |
159 | KUNCGetNotificationID() | |
160 | { | |
161 | UNDReplyRef reply; | |
162 | ||
163 | reply = (UNDReplyRef) kalloc(sizeof(struct UNDReply)); | |
164 | if (reply != UND_REPLY_NULL) { | |
165 | reply->self_port = ipc_port_alloc_kernel(); | |
166 | if (reply->self_port == IP_NULL) { | |
167 | kfree((vm_offset_t)reply, sizeof(struct UNDReply)); | |
168 | reply = UND_REPLY_NULL; | |
169 | } else { | |
170 | mutex_init(&reply->lock, ETAP_IO_UNDREPLY); | |
171 | reply->userLandNotificationKey = -1; | |
172 | reply->inprogress = FALSE; | |
173 | ipc_kobject_set(reply->self_port, | |
174 | (ipc_kobject_t)reply, | |
175 | IKOT_UND_REPLY); | |
176 | } | |
177 | } | |
178 | return (KUNCUserNotificationID) reply; | |
179 | } | |
180 | ||
181 | ||
182 | kern_return_t KUNCExecute(char executionPath[1024], int uid, int gid) | |
183 | { | |
184 | return UNDExecute_rpc(gUNDServer, executionPath, uid, gid); | |
185 | } | |
186 | ||
187 | kern_return_t KUNCUserNotificationCancel( | |
188 | KUNCUserNotificationID id) | |
189 | { | |
190 | UNDReplyRef reply = (UNDReplyRef)id; | |
191 | kern_return_t kr; | |
192 | int ulkey; | |
193 | ||
194 | if (reply == UND_REPLY_NULL) | |
195 | return KERN_INVALID_ARGUMENT; | |
196 | ||
197 | UNDReply_lock(reply); | |
198 | if (!reply->inprogress) { | |
199 | UNDReply_unlock(reply); | |
200 | return KERN_INVALID_ARGUMENT; | |
201 | } | |
202 | ||
203 | reply->inprogress = FALSE; | |
204 | if (ulkey = reply->userLandNotificationKey) { | |
205 | reply->userLandNotificationKey = 0; | |
206 | UNDReply_unlock(reply); | |
207 | kr = UNDCancelNotification_rpc(gUNDServer,ulkey); | |
208 | } else { | |
209 | UNDReply_unlock(reply); | |
210 | kr = KERN_SUCCESS; | |
211 | } | |
212 | UNDReply_deallocate(reply); | |
213 | return kr; | |
214 | } | |
215 | ||
216 | kern_return_t | |
217 | KUNCUserNotificationDisplayNotice( | |
218 | int timeout, | |
219 | unsigned flags, | |
220 | char *iconPath, | |
221 | char *soundPath, | |
222 | char *localizationPath, | |
223 | char *alertHeader, | |
224 | char *alertMessage, | |
225 | char *defaultButtonTitle) | |
226 | { | |
227 | kern_return_t kr; | |
228 | kr = UNDDisplayNoticeSimple_rpc(gUNDServer, | |
229 | timeout, | |
230 | flags, | |
231 | iconPath, | |
232 | soundPath, | |
233 | localizationPath, | |
234 | alertHeader, | |
235 | alertMessage, | |
236 | defaultButtonTitle); | |
237 | return kr; | |
238 | } | |
239 | ||
240 | kern_return_t | |
241 | KUNCUserNotificationDisplayAlert( | |
242 | int timeout, | |
243 | unsigned flags, | |
244 | char *iconPath, | |
245 | char *soundPath, | |
246 | char *localizationPath, | |
247 | char *alertHeader, | |
248 | char *alertMessage, | |
249 | char *defaultButtonTitle, | |
250 | char *alternateButtonTitle, | |
251 | char *otherButtonTitle, | |
252 | unsigned *responseFlags) | |
253 | { | |
254 | kern_return_t kr; | |
255 | ||
256 | kr = UNDDisplayAlertSimple_rpc(gUNDServer, | |
257 | timeout, | |
258 | flags, | |
259 | iconPath, | |
260 | soundPath, | |
261 | localizationPath, | |
262 | alertHeader, | |
263 | alertMessage, | |
264 | defaultButtonTitle, | |
265 | alternateButtonTitle, | |
266 | otherButtonTitle, | |
267 | responseFlags); | |
268 | return kr; | |
269 | } | |
270 | ||
271 | kern_return_t | |
272 | KUNCUserNotificationDisplayFromBundle( | |
273 | KUNCUserNotificationID id, | |
274 | char *bundlePath, | |
275 | char *fileName, | |
276 | char *fileExtension, | |
277 | char *messageKey, | |
278 | char *tokenString, | |
279 | KUNCUserNotificationCallBack callback, | |
280 | int contextKey) | |
281 | { | |
282 | UNDReplyRef reply = (UNDReplyRef)id; | |
283 | ipc_port_t reply_port; | |
284 | kern_return_t kr; | |
285 | ||
286 | if (reply == UND_REPLY_NULL) | |
287 | return KERN_INVALID_ARGUMENT; | |
288 | UNDReply_lock(reply); | |
289 | if (reply->inprogress == TRUE || reply->userLandNotificationKey != -1) { | |
290 | UNDReply_unlock(reply); | |
291 | return KERN_INVALID_ARGUMENT; | |
292 | } | |
293 | reply->inprogress == TRUE; | |
294 | reply->callback = callback; | |
295 | reply_port = ipc_port_make_send(reply->self_port); | |
296 | UNDReply_unlock(reply); | |
297 | ||
298 | kr = UNDDisplayCustomFromBundle_rpc(gUNDServer, | |
299 | reply_port, | |
300 | bundlePath, | |
301 | fileName, | |
302 | fileExtension, | |
303 | messageKey, | |
304 | tokenString); | |
305 | return kr; | |
306 | } | |
307 | ||
308 | /* | |
309 | * Routine: convert_port_to_UNDReply | |
310 | * | |
311 | * MIG helper routine to convert from a mach port to a | |
312 | * UNDReply object. | |
313 | * | |
314 | * Assumptions: | |
315 | * Nothing locked. | |
316 | */ | |
317 | UNDReplyRef | |
318 | convert_port_to_UNDReply( | |
319 | ipc_port_t port) | |
320 | { | |
321 | if (IP_VALID(port)) { | |
322 | UNDReplyRef reply; | |
323 | ||
324 | ip_lock(port); | |
325 | if (!ip_active(port) || (ip_kotype(port) != IKOT_UND_REPLY)) { | |
326 | ip_unlock(port); | |
327 | return UND_REPLY_NULL; | |
328 | } | |
329 | reply = (UNDReplyRef) port->ip_kobject; | |
330 | assert(reply != UND_REPLY_NULL); | |
331 | ip_unlock(port); | |
332 | } | |
333 | return UND_REPLY_NULL; | |
334 | } | |
335 | ||
336 | /* | |
337 | * User interface for setting the host UserNotification Daemon port. | |
338 | */ | |
339 | ||
340 | kern_return_t | |
341 | host_set_UNDServer( | |
342 | host_priv_t host_priv, | |
343 | UNDServerRef server) | |
344 | { | |
345 | ||
346 | if (host_priv == HOST_PRIV_NULL || server == UND_SERVER_NULL) | |
347 | return KERN_INVALID_ARGUMENT; | |
348 | if (gUNDServer != UND_SERVER_NULL) | |
349 | ipc_port_dealloc_kernel(gUNDServer); | |
350 | gUNDServer = server; | |
351 | return KERN_SUCCESS; | |
352 | } | |
353 | ||
354 | /* | |
355 | * User interface for retrieving the UserNotification Daemon port. | |
356 | */ | |
357 | ||
358 | kern_return_t | |
359 | host_get_UNDServer( | |
360 | host_priv_t host_priv, | |
361 | UNDServerRef *server) | |
362 | { | |
363 | if (host_priv == HOST_PRIV_NULL) | |
364 | return KERN_INVALID_ARGUMENT; | |
365 | *server = gUNDServer; | |
366 | return KERN_SUCCESS; | |
367 | } | |
368 |