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