]> git.saurik.com Git - apple/xnu.git/blame - osfmk/UserNotification/KUNCUserNotifications.c
xnu-517.tar.gz
[apple/xnu.git] / osfmk / UserNotification / KUNCUserNotifications.c
CommitLineData
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
50struct 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
62void
63UNDReply_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
80static UNDServerRef
81UNDServer_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
91static void
92UNDServer_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
103kern_return_t
104UNDAlertCompletedWithResult_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 */
156kern_return_t
157UNDNotificationCreated_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
179KUNCUserNotificationID
180KUNCGetNotificationID()
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
203kern_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
218kern_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
255kern_return_t
256KUNCUserNotificationDisplayNotice(
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
286kern_return_t
287KUNCUserNotificationDisplayAlert(
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
323kern_return_t
324KUNCUserNotificationDisplayFromBundle(
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 */
376UNDReplyRef
377convert_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
400kern_return_t
401host_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
412kern_return_t
413host_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}