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