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