]> git.saurik.com Git - apple/xnu.git/blob - osfmk/UserNotification/KUNCUserNotifications.c
xnu-201.14.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 * 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