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