]> git.saurik.com Git - apple/cf.git/blob - AppServices.subproj/CFUserNotification.c
CF-299.tar.gz
[apple/cf.git] / AppServices.subproj / CFUserNotification.c
1 /*
2 * Copyright (c) 2003 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 /* CFUserNotification.c
26 Copyright 2000-2002, Apple, Inc. All rights reserved.
27 Responsibility: Doug Davidson
28 */
29
30 #include <CoreFoundation/CFUserNotification.h>
31 #include <CoreFoundation/CFPropertyList.h>
32 #include <CoreFoundation/CFNumber.h>
33 #include <CoreFoundation/CFMachPort.h>
34 #include <CoreFoundation/CFRunLoop.h>
35 #include "CFInternal.h"
36
37 #define __kCFLogUserNotification 20
38 #define CFUserNotificationLog(alertHeader, alertMessage) CFLog(__kCFLogUserNotification, CFSTR("%@: %@"), alertHeader, alertMessage);
39
40 enum {
41 kCFUserNotificationCancelFlag = (1 << 3),
42 kCFUserNotificationUpdateFlag = (1 << 4)
43 };
44
45 CONST_STRING_DECL(kCFUserNotificationTokenKey, "Token")
46 CONST_STRING_DECL(kCFUserNotificationTimeoutKey, "Timeout")
47 CONST_STRING_DECL(kCFUserNotificationFlagsKey, "Flags")
48 CONST_STRING_DECL(kCFUserNotificationIconPathKey, "IconPath")
49 CONST_STRING_DECL(kCFUserNotificationSoundPathKey, "SoundPath")
50 CONST_STRING_DECL(kCFUserNotificationLocalizationPathKey, "LocalizationPath")
51 CONST_STRING_DECL(kCFUserNotificationAlertSourceKey, "AlertSource")
52 CONST_STRING_DECL(kCFUserNotificationTextFieldLabelsKey, "TextFieldTitles")
53 CONST_STRING_DECL(kCFUserNotificationCheckBoxLabelsKey, "CheckBoxTitles")
54 CONST_STRING_DECL(kCFUserNotificationIconURLKey, "IconURL")
55 CONST_STRING_DECL(kCFUserNotificationSoundURLKey, "SoundURL")
56 CONST_STRING_DECL(kCFUserNotificationLocalizationURLKey, "LocalizationURL")
57 CONST_STRING_DECL(kCFUserNotificationAlertHeaderKey, "AlertHeader")
58 CONST_STRING_DECL(kCFUserNotificationAlertMessageKey, "AlertMessage")
59 CONST_STRING_DECL(kCFUserNotificationDefaultButtonTitleKey, "DefaultButtonTitle")
60 CONST_STRING_DECL(kCFUserNotificationAlternateButtonTitleKey, "AlternateButtonTitle")
61 CONST_STRING_DECL(kCFUserNotificationOtherButtonTitleKey, "OtherButtonTitle")
62 CONST_STRING_DECL(kCFUserNotificationProgressIndicatorValueKey, "ProgressIndicatorValue")
63 CONST_STRING_DECL(kCFUserNotificationSessionIDKey, "SessionID")
64 CONST_STRING_DECL(kCFUserNotificationPopUpTitlesKey, "PopUpTitles")
65 CONST_STRING_DECL(kCFUserNotificationTextFieldTitlesKey, "TextFieldTitles")
66 CONST_STRING_DECL(kCFUserNotificationCheckBoxTitlesKey, "CheckBoxTitles")
67 CONST_STRING_DECL(kCFUserNotificationTextFieldValuesKey, "TextFieldValues")
68 CONST_STRING_DECL(kCFUserNotificationPopUpSelectionKey, "PopUpSelection")
69
70 static CFTypeID __kCFUserNotificationTypeID = _kCFRuntimeNotATypeID;
71
72 struct __CFUserNotification {
73 CFRuntimeBase _base;
74 SInt32 _replyPort;
75 SInt32 _token;
76 CFTimeInterval _timeout;
77 CFOptionFlags _requestFlags;
78 CFOptionFlags _responseFlags;
79 CFStringRef _sessionID;
80 CFDictionaryRef _responseDictionary;
81 CFMachPortRef _machPort;
82 CFUserNotificationCallBack _callout;
83 };
84
85 static CFStringRef __CFUserNotificationCopyDescription(CFTypeRef cf) {
86 CFMutableStringRef result;
87 result = CFStringCreateMutable(CFGetAllocator(cf), 0);
88 CFStringAppendFormat(result, NULL, CFSTR("<CFUserNotification 0x%x>"), (UInt32)cf);
89 return result;
90 }
91
92 #if defined(__MACH__)
93
94 #include <stdlib.h>
95 #include <unistd.h>
96 #include <stdio.h>
97 #include <mach/mach.h>
98 #include <mach/error.h>
99 #include <servers/bootstrap.h>
100 #include <limits.h>
101 #include <errno.h>
102
103 #define MAX_STRING_LENGTH PATH_MAX
104 #define MAX_STRING_COUNT 16
105 #define MAX_PORT_NAME_LENGTH 63
106 #define NOTIFICATION_PORT_NAME "com.apple.UNCUserNotification"
107 #define NOTIFICATION_PORT_NAME_OLD "UNCUserNotification"
108 #define NOTIFICATION_PORT_NAME_SUFFIX ".session."
109 #define MESSAGE_TIMEOUT 100
110
111 static void __CFUserNotificationDeallocate(CFTypeRef cf) {
112 CFUserNotificationRef userNotification = (CFUserNotificationRef)cf;
113 if (userNotification->_machPort) {
114 CFMachPortInvalidate(userNotification->_machPort);
115 CFRelease(userNotification->_machPort);
116 } else if (MACH_PORT_NULL != userNotification->_replyPort) {
117 mach_port_destroy(mach_task_self(), userNotification->_replyPort);
118 }
119 if (userNotification->_sessionID) CFRelease(userNotification->_sessionID);
120 if (userNotification->_responseDictionary) CFRelease(userNotification->_responseDictionary);
121 }
122
123 #endif /* __MACH__ */
124
125 static const CFRuntimeClass __CFUserNotificationClass = {
126 0,
127 "CFUserNotification",
128 NULL, // init
129 NULL, // copy
130 __CFUserNotificationDeallocate,
131 NULL, // equal
132 NULL, // hash
133 NULL, //
134 __CFUserNotificationCopyDescription
135 };
136
137 __private_extern__ void __CFUserNotificationInitialize(void) {
138 __kCFUserNotificationTypeID = _CFRuntimeRegisterClass(&__CFUserNotificationClass);
139 }
140
141 CFTypeID CFUserNotificationGetTypeID(void) {
142 return __kCFUserNotificationTypeID;
143 }
144
145 #if defined(__MACH__)
146
147 static void _CFUserNotificationAddToDictionary(const void *key, const void *value, void *context) {
148 if (CFGetTypeID(key) == CFStringGetTypeID()) CFDictionarySetValue((CFMutableDictionaryRef)context, key, value);
149 }
150
151 static CFDictionaryRef _CFUserNotificationModifiedDictionary(CFAllocatorRef allocator, CFDictionaryRef dictionary, SInt32 token, SInt32 timeout, CFStringRef source) {
152 CFMutableDictionaryRef md = CFDictionaryCreateMutable(allocator, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
153 CFNumberRef tokenNumber = CFNumberCreate(allocator, kCFNumberSInt32Type, &token);
154 CFNumberRef timeoutNumber = CFNumberCreate(allocator, kCFNumberSInt32Type, &timeout);
155 CFURLRef url = NULL;
156 CFStringRef path = NULL;
157
158 if (dictionary) CFDictionaryApplyFunction(dictionary, _CFUserNotificationAddToDictionary, md);
159 if (source) CFDictionaryAddValue(md, kCFUserNotificationAlertSourceKey, source);
160 if (tokenNumber) {
161 CFDictionaryAddValue(md, kCFUserNotificationTokenKey, tokenNumber);
162 CFRelease(tokenNumber);
163 }
164 if (timeoutNumber) {
165 CFDictionaryAddValue(md, kCFUserNotificationTimeoutKey, timeoutNumber);
166 CFRelease(timeoutNumber);
167 }
168
169 url = CFDictionaryGetValue(md, kCFUserNotificationIconURLKey);
170 if (url && CFGetTypeID((CFTypeRef)url) == CFURLGetTypeID()) {
171 url = CFURLCopyAbsoluteURL(url);
172 CFDictionaryRemoveValue(md, kCFUserNotificationIconURLKey);
173 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
174 CFDictionaryAddValue(md, kCFUserNotificationIconPathKey, path);
175 CFRelease(url);
176 CFRelease(path);
177 }
178 url = CFDictionaryGetValue(md, kCFUserNotificationSoundURLKey);
179 if (url && CFGetTypeID((CFTypeRef)url) == CFURLGetTypeID()) {
180 url = CFURLCopyAbsoluteURL(url);
181 CFDictionaryRemoveValue(md, kCFUserNotificationSoundURLKey);
182 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
183 CFDictionaryAddValue(md, kCFUserNotificationSoundPathKey, path);
184 CFRelease(url);
185 CFRelease(path);
186 }
187 url = CFDictionaryGetValue(md, kCFUserNotificationLocalizationURLKey);
188 if (url && CFGetTypeID((CFTypeRef)url) == CFURLGetTypeID()) {
189 url = CFURLCopyAbsoluteURL(url);
190 CFDictionaryRemoveValue(md, kCFUserNotificationLocalizationURLKey);
191 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
192 CFDictionaryAddValue(md, kCFUserNotificationLocalizationPathKey, path);
193 CFRelease(url);
194 CFRelease(path);
195 }
196 return md;
197 }
198
199 static SInt32 _CFUserNotificationSendRequest(CFAllocatorRef allocator, CFStringRef sessionID, mach_port_t replyPort, SInt32 token, CFTimeInterval timeout, CFOptionFlags flags, CFDictionaryRef dictionary) {
200 CFDictionaryRef modifiedDictionary = NULL;
201 SInt32 retval = ERR_SUCCESS, itimeout = (timeout > 0.0 && timeout < INT_MAX) ? (SInt32)timeout : 0;
202 CFDataRef data;
203 mach_msg_base_t *msg = NULL;
204 mach_port_t bootstrapPort = MACH_PORT_NULL, serverPort = MACH_PORT_NULL;
205 CFIndex size;
206 char namebuffer[MAX_PORT_NAME_LENGTH + 1], oldnamebuffer[MAX_PORT_NAME_LENGTH + 1];
207 size_t namelen;
208
209 strcpy(namebuffer, NOTIFICATION_PORT_NAME);
210 strcpy(oldnamebuffer, NOTIFICATION_PORT_NAME_OLD);
211 if (sessionID) {
212 strcat(namebuffer, NOTIFICATION_PORT_NAME_SUFFIX);
213 namelen = strlen(namebuffer);
214 CFStringGetBytes(sessionID, CFRangeMake(0, CFStringGetLength(sessionID)), kCFStringEncodingUTF8, 0, false, namebuffer + namelen, MAX_PORT_NAME_LENGTH - namelen, &size);
215 namebuffer[namelen + size] = '\0';
216
217 strcat(oldnamebuffer, NOTIFICATION_PORT_NAME_SUFFIX);
218 namelen = strlen(oldnamebuffer);
219 CFStringGetBytes(sessionID, CFRangeMake(0, CFStringGetLength(sessionID)), kCFStringEncodingUTF8, 0, false, oldnamebuffer + namelen, MAX_PORT_NAME_LENGTH - namelen, &size);
220 oldnamebuffer[namelen + size] = '\0';
221 }
222
223 retval = task_get_bootstrap_port(mach_task_self(), &bootstrapPort);
224 if (ERR_SUCCESS == retval && MACH_PORT_NULL != bootstrapPort) retval = bootstrap_look_up(bootstrapPort, namebuffer, &serverPort);
225 if (ERR_SUCCESS != retval || MACH_PORT_NULL == serverPort) retval = bootstrap_look_up(bootstrapPort, oldnamebuffer, &serverPort);
226 if (ERR_SUCCESS == retval && MACH_PORT_NULL != serverPort) {
227 modifiedDictionary = _CFUserNotificationModifiedDictionary(allocator, dictionary, token, itimeout, _CFProcessNameString());
228 if (modifiedDictionary) {
229 data = CFPropertyListCreateXMLData(allocator, modifiedDictionary);
230 if (data) {
231 size = sizeof(mach_msg_base_t) + ((CFDataGetLength(data) + 3) & (~0x3));
232 msg = (mach_msg_base_t *)CFAllocatorAllocate(allocator, size, 0);
233 if (__CFOASafe) __CFSetLastAllocationEventName(msg, "CFUserNotification (temp)");
234 if (msg) {
235 memset(msg, 0, size);
236 msg->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
237 msg->header.msgh_size = size;
238 msg->header.msgh_remote_port = serverPort;
239 msg->header.msgh_local_port = replyPort;
240 msg->header.msgh_id = flags;
241 msg->body.msgh_descriptor_count = 0;
242 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (uint8_t *)msg + sizeof(mach_msg_base_t));
243 //CFShow(CFStringCreateWithBytes(NULL, (UInt8 *)msg + sizeof(mach_msg_base_t), CFDataGetLength(data), kCFStringEncodingUTF8, false));
244 retval = mach_msg((mach_msg_header_t *)msg, MACH_SEND_MSG|MACH_SEND_TIMEOUT, size, 0, MACH_PORT_NULL, MESSAGE_TIMEOUT, MACH_PORT_NULL);
245 CFAllocatorDeallocate(allocator, msg);
246 } else {
247 retval = unix_err(ENOMEM);
248 }
249 CFRelease(data);
250 } else {
251 retval = unix_err(ENOMEM);
252 }
253 CFRelease(modifiedDictionary);
254 } else {
255 retval = unix_err(ENOMEM);
256 }
257 }
258 return retval;
259 }
260
261 CFUserNotificationRef CFUserNotificationCreate(CFAllocatorRef allocator, CFTimeInterval timeout, CFOptionFlags flags, SInt32 *error, CFDictionaryRef dictionary) {
262 CFUserNotificationRef userNotification = NULL;
263 SInt32 retval = ERR_SUCCESS;
264 static uint16_t tokenCounter = 0;
265 SInt32 token = ((getpid()<<16) | (tokenCounter++));
266 CFStringRef sessionID = (dictionary ? CFDictionaryGetValue(dictionary, kCFUserNotificationSessionIDKey) : NULL);
267 mach_port_t replyPort = MACH_PORT_NULL;
268
269 if (!allocator) allocator = __CFGetDefaultAllocator();
270
271 retval = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &replyPort);
272 if (ERR_SUCCESS == retval && MACH_PORT_NULL != replyPort) retval = _CFUserNotificationSendRequest(allocator, sessionID, replyPort, token, timeout, flags, dictionary);
273 if (ERR_SUCCESS == retval) {
274 userNotification = (CFUserNotificationRef)_CFRuntimeCreateInstance(allocator, __kCFUserNotificationTypeID, sizeof(struct __CFUserNotification) - sizeof(CFRuntimeBase), NULL);
275 if (userNotification) {
276 userNotification->_replyPort = replyPort;
277 userNotification->_token = token;
278 userNotification->_timeout = timeout;
279 userNotification->_requestFlags = flags;
280 userNotification->_responseFlags = 0;
281 userNotification->_sessionID = NULL;
282 userNotification->_responseDictionary = NULL;
283 userNotification->_machPort = NULL;
284 userNotification->_callout = NULL;
285 if (sessionID) userNotification->_sessionID = CFStringCreateCopy(allocator, sessionID);
286 } else {
287 retval = unix_err(ENOMEM);
288 }
289 } else {
290 if (dictionary) CFUserNotificationLog(CFDictionaryGetValue(dictionary, kCFUserNotificationAlertHeaderKey), CFDictionaryGetValue(dictionary, kCFUserNotificationAlertMessageKey));
291 }
292 if (ERR_SUCCESS != retval && MACH_PORT_NULL != replyPort) mach_port_destroy(mach_task_self(), replyPort);
293 if (error) *error = retval;
294 return userNotification;
295 }
296
297 static void _CFUserNotificationMachPortCallBack(CFMachPortRef port, void *m, CFIndex size, void *info) {
298 CFUserNotificationRef userNotification = (CFUserNotificationRef)info;
299 mach_msg_base_t *msg = (mach_msg_base_t *)m;
300 CFOptionFlags responseFlags = msg->header.msgh_id;
301 CFDataRef responseData = CFDataCreate(NULL, (uint8_t *)msg + sizeof(mach_msg_base_t), msg->header.msgh_size - sizeof(mach_msg_base_t));
302 if (responseData) {
303 userNotification->_responseDictionary = CFPropertyListCreateFromXMLData(NULL, responseData, kCFPropertyListImmutable, NULL);
304 CFRelease(responseData);
305 }
306 CFMachPortInvalidate(userNotification->_machPort);
307 CFRelease(userNotification->_machPort);
308 userNotification->_machPort = NULL;
309 mach_port_destroy(mach_task_self(), userNotification->_replyPort);
310 userNotification->_replyPort = MACH_PORT_NULL;
311 userNotification->_callout(userNotification, responseFlags);
312 }
313
314 SInt32 CFUserNotificationReceiveResponse(CFUserNotificationRef userNotification, CFTimeInterval timeout, CFOptionFlags *responseFlags) {
315 SInt32 retval = ERR_SUCCESS;
316 mach_msg_timeout_t msgtime = (timeout > 0.0 && 1000.0 * timeout < INT_MAX) ? (mach_msg_timeout_t)(1000.0 * timeout) : 0;
317 mach_msg_base_t *msg = NULL;
318 CFIndex size = MAX_STRING_COUNT * MAX_STRING_LENGTH;
319 CFDataRef responseData;
320
321 if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) {
322 msg = (mach_msg_base_t *)CFAllocatorAllocate(CFGetAllocator(userNotification), size, 0);
323 if (__CFOASafe) __CFSetLastAllocationEventName(msg, "CFUserNotification (temp)");
324 if (msg) {
325 memset(msg, 0, size);
326 msg->header.msgh_size = size;
327 if (msgtime > 0) {
328 retval = mach_msg((mach_msg_header_t *)msg, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, size, userNotification->_replyPort, msgtime, MACH_PORT_NULL);
329 } else {
330 retval = mach_msg((mach_msg_header_t *)msg, MACH_RCV_MSG, 0, size, userNotification->_replyPort, 0, MACH_PORT_NULL);
331 }
332 if (ERR_SUCCESS == retval) {
333 if (responseFlags) *responseFlags = msg->header.msgh_id;
334 responseData = CFDataCreate(NULL, (uint8_t *)msg + sizeof(mach_msg_base_t), msg->header.msgh_size - sizeof(mach_msg_base_t));
335 if (responseData) {
336 userNotification->_responseDictionary = CFPropertyListCreateFromXMLData(NULL, responseData, kCFPropertyListImmutable, NULL);
337 CFRelease(responseData);
338 }
339 if (userNotification->_machPort) {
340 CFMachPortInvalidate(userNotification->_machPort);
341 CFRelease(userNotification->_machPort);
342 userNotification->_machPort = NULL;
343 }
344 mach_port_destroy(mach_task_self(), userNotification->_replyPort);
345 userNotification->_replyPort = MACH_PORT_NULL;
346 }
347 CFAllocatorDeallocate(CFGetAllocator(userNotification), msg);
348 } else {
349 retval = unix_err(ENOMEM);
350 }
351 }
352 return retval;
353 }
354
355 CFStringRef CFUserNotificationGetResponseValue(CFUserNotificationRef userNotification, CFStringRef key, CFIndex idx) {
356 CFStringRef retval = NULL;
357 CFTypeRef value = NULL;
358 if (userNotification && userNotification->_responseDictionary) {
359 value = CFDictionaryGetValue(userNotification->_responseDictionary, key);
360 if (CFGetTypeID(value) == CFStringGetTypeID()) {
361 if (0 == idx) {
362 retval = (CFStringRef)value;
363 }
364 } else if (CFGetTypeID(value) == CFArrayGetTypeID()) {
365 if (0 <= idx && idx < CFArrayGetCount((CFArrayRef)value)) {
366 retval = (CFStringRef)CFArrayGetValueAtIndex((CFArrayRef)value, idx);
367 }
368 }
369 }
370 return retval;
371 }
372
373 CFDictionaryRef CFUserNotificationGetResponseDictionary(CFUserNotificationRef userNotification) {
374 return userNotification ? userNotification->_responseDictionary : NULL;
375 }
376
377 SInt32 CFUserNotificationUpdate(CFUserNotificationRef userNotification, CFTimeInterval timeout, CFOptionFlags flags, CFDictionaryRef dictionary) {
378 SInt32 retval = ERR_SUCCESS;
379 if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) {
380 retval = _CFUserNotificationSendRequest(CFGetAllocator(userNotification), userNotification->_sessionID, userNotification->_replyPort, userNotification->_token, timeout, flags|kCFUserNotificationUpdateFlag, dictionary);
381 }
382 return retval;
383 }
384
385 SInt32 CFUserNotificationCancel(CFUserNotificationRef userNotification) {
386 SInt32 retval = ERR_SUCCESS;
387 if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) {
388 retval = _CFUserNotificationSendRequest(CFGetAllocator(userNotification), userNotification->_sessionID, userNotification->_replyPort, userNotification->_token, 0, kCFUserNotificationCancelFlag, NULL);
389 }
390 return retval;
391 }
392
393 CFRunLoopSourceRef CFUserNotificationCreateRunLoopSource(CFAllocatorRef allocator, CFUserNotificationRef userNotification, CFUserNotificationCallBack callout, CFIndex order) {
394 CFRunLoopSourceRef source = NULL;
395 if (userNotification && callout && !userNotification->_machPort && MACH_PORT_NULL != userNotification->_replyPort) {
396 CFMachPortContext context = {0, userNotification, NULL, NULL, NULL};
397 userNotification->_machPort = CFMachPortCreateWithPort(CFGetAllocator(userNotification), (mach_port_t)userNotification->_replyPort, _CFUserNotificationMachPortCallBack, &context, false);
398 }
399 if (userNotification && userNotification->_machPort) {
400 source = CFMachPortCreateRunLoopSource(allocator, userNotification->_machPort, order);
401 userNotification->_callout = callout;
402 }
403 return source;
404 }
405
406 SInt32 CFUserNotificationDisplayNotice(CFTimeInterval timeout, CFOptionFlags flags, CFURLRef iconURL, CFURLRef soundURL, CFURLRef localizationURL, CFStringRef alertHeader, CFStringRef alertMessage, CFStringRef defaultButtonTitle) {
407 CFUserNotificationRef userNotification;
408 SInt32 retval = ERR_SUCCESS;
409 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
410 if (iconURL) CFDictionaryAddValue(dict, kCFUserNotificationIconURLKey, iconURL);
411 if (soundURL) CFDictionaryAddValue(dict, kCFUserNotificationSoundURLKey, soundURL);
412 if (localizationURL) CFDictionaryAddValue(dict, kCFUserNotificationLocalizationURLKey, localizationURL);
413 if (alertHeader) CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, alertHeader);
414 if (alertMessage) CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, alertMessage);
415 if (defaultButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, defaultButtonTitle);
416 userNotification = CFUserNotificationCreate(NULL, timeout, flags, &retval, dict);
417 if (userNotification) CFRelease(userNotification);
418 CFRelease(dict);
419 return retval;
420 }
421
422 CF_EXPORT SInt32 CFUserNotificationDisplayAlert(CFTimeInterval timeout, CFOptionFlags flags, CFURLRef iconURL, CFURLRef soundURL, CFURLRef localizationURL, CFStringRef alertHeader, CFStringRef alertMessage, CFStringRef defaultButtonTitle, CFStringRef alternateButtonTitle, CFStringRef otherButtonTitle, CFOptionFlags *responseFlags) {
423 CFUserNotificationRef userNotification;
424 SInt32 retval = ERR_SUCCESS;
425 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
426 if (iconURL) CFDictionaryAddValue(dict, kCFUserNotificationIconURLKey, iconURL);
427 if (soundURL) CFDictionaryAddValue(dict, kCFUserNotificationSoundURLKey, soundURL);
428 if (localizationURL) CFDictionaryAddValue(dict, kCFUserNotificationLocalizationURLKey, localizationURL);
429 if (alertHeader) CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, alertHeader);
430 if (alertMessage) CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, alertMessage);
431 if (defaultButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, defaultButtonTitle);
432 if (alternateButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationAlternateButtonTitleKey, alternateButtonTitle);
433 if (otherButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationOtherButtonTitleKey, otherButtonTitle);
434 userNotification = CFUserNotificationCreate(NULL, timeout, flags, &retval, dict);
435 if (userNotification) {
436 retval = CFUserNotificationReceiveResponse(userNotification, timeout, responseFlags);
437 if (MACH_RCV_TIMED_OUT == retval) {
438 retval = CFUserNotificationCancel(userNotification);
439 if (responseFlags) *responseFlags = kCFUserNotificationCancelResponse;
440 }
441 CFRelease(userNotification);
442 }
443 CFRelease(dict);
444 return retval;
445 }
446
447 #else /* __MACH__ */
448
449 #warning CFUserNotification functions not fully implemented
450
451 void __CFUserNotificationDeallocate(CFTypeRef cf) {
452 }
453
454 CFUserNotificationRef CFUserNotificationCreate(CFAllocatorRef allocator, CFTimeInterval timeout, CFOptionFlags flags, SInt32 *error, CFDictionaryRef dictionary) {
455 CFUserNotificationLog(CFDictionaryGetValue(dictionary, kCFUserNotificationAlertHeaderKey), CFDictionaryGetValue(dictionary, kCFUserNotificationAlertMessageKey));
456 return NULL;
457 }
458
459 SInt32 CFUserNotificationReceiveResponse(CFUserNotificationRef userNotification, CFTimeInterval timeout, CFOptionFlags *responseFlags) {
460 return -1;
461 }
462
463 CFDictionaryRef CFUserNotificationCopyResponseDictionary(CFUserNotificationRef userNotification) {
464 return NULL;
465 }
466
467 SInt32 CFUserNotificationUpdate(CFUserNotificationRef userNotification, CFTimeInterval timeout, CFOptionFlags flags, CFDictionaryRef dictionary) {
468 return -1;
469 }
470
471 SInt32 CFUserNotificationCancel(CFUserNotificationRef userNotification) {
472 return -1;
473 }
474
475 CFRunLoopSourceRef CFUserNotificationCreateRunLoopSource(CFAllocatorRef allocator, CFUserNotificationRef userNotification, CFUserNotificationCallBack callout, CFIndex order) {
476 return NULL;
477 }
478
479 SInt32 CFUserNotificationDisplayNotice(CFTimeInterval timeout, CFOptionFlags flags, CFURLRef iconURL, CFURLRef soundURL, CFURLRef localizationURL, CFStringRef alertHeader, CFStringRef alertMessage, CFStringRef defaultButtonTitle) {
480 CFUserNotificationLog(alertHeader, alertMessage);
481 return -1;
482 }
483
484 SInt32 CFUserNotificationDisplayAlert(CFTimeInterval timeout, CFOptionFlags flags, CFURLRef iconURL, CFURLRef soundURL, CFURLRef localizationURL, CFStringRef alertHeader, CFStringRef alertMessage, CFStringRef defaultButtonTitle, CFStringRef alternateButtonTitle, CFStringRef otherButtonTitle, CFOptionFlags *responseFlags) {
485 CFUserNotificationLog(alertHeader, alertMessage);
486 return -1;
487 }
488
489 #endif /* __MACH__ */
490
491 #undef __kCFLogUserNotification
492 #undef CFUserNotificationLog
493 #undef MAX_STRING_LENGTH
494 #undef MAX_STRING_COUNT
495 #undef NOTIFICATION_PORT_NAME
496 #undef NOTIFICATION_PORT_NAME_OLD
497 #undef MESSAGE_TIMEOUT
498