1/* 2 * Copyright (c) 2014 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-2013, 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 48enum { 49 kCFUserNotificationCancelFlag = (1 << 3), 50 kCFUserNotificationUpdateFlag = (1 << 4) 51}; 52 53CONST_STRING_DECL(kCFUserNotificationTokenKey, "Token") 54CONST_STRING_DECL(kCFUserNotificationTimeoutKey, "Timeout") 55CONST_STRING_DECL(kCFUserNotificationFlagsKey, "Flags") 56CONST_STRING_DECL(kCFUserNotificationIconPathKey, "IconPath") 57CONST_STRING_DECL(kCFUserNotificationSoundPathKey, "SoundPath") 58CONST_STRING_DECL(kCFUserNotificationLocalizationPathKey, "LocalizationPath") 59CONST_STRING_DECL(kCFUserNotificationAlertSourceKey, "AlertSource") 60CONST_STRING_DECL(kCFUserNotificationTextFieldLabelsKey, "TextFieldTitles") 61CONST_STRING_DECL(kCFUserNotificationCheckBoxLabelsKey, "CheckBoxTitles") 62CONST_STRING_DECL(kCFUserNotificationIconURLKey, "IconURL") 63CONST_STRING_DECL(kCFUserNotificationSoundURLKey, "SoundURL") 64CONST_STRING_DECL(kCFUserNotificationLocalizationURLKey, "LocalizationURL") 65CONST_STRING_DECL(kCFUserNotificationAlertHeaderKey, "AlertHeader") 66CONST_STRING_DECL(kCFUserNotificationAlertMessageKey, "AlertMessage") 67CONST_STRING_DECL(kCFUserNotificationDefaultButtonTitleKey, "DefaultButtonTitle") 68CONST_STRING_DECL(kCFUserNotificationAlternateButtonTitleKey, "AlternateButtonTitle") 69CONST_STRING_DECL(kCFUserNotificationOtherButtonTitleKey, "OtherButtonTitle") 70CONST_STRING_DECL(kCFUserNotificationProgressIndicatorValueKey, "ProgressIndicatorValue") 71CONST_STRING_DECL(kCFUserNotificationSessionIDKey, "SessionID") 72CONST_STRING_DECL(kCFUserNotificationPopUpTitlesKey, "PopUpTitles") 73CONST_STRING_DECL(kCFUserNotificationTextFieldTitlesKey, "TextFieldTitles") 74CONST_STRING_DECL(kCFUserNotificationCheckBoxTitlesKey, "CheckBoxTitles") 75CONST_STRING_DECL(kCFUserNotificationTextFieldValuesKey, "TextFieldValues") 76CONST_STRING_DECL(kCFUserNotificationPopUpSelectionKey, "PopUpSelection") 77CONST_STRING_DECL(kCFUserNotificationKeyboardTypesKey, "KeyboardTypes") 78CONST_STRING_DECL(kCFUserNotificationAlertTopMostKey, "AlertTopMost") // boolean value 79 80 81static CFTypeID __kCFUserNotificationTypeID = _kCFRuntimeNotATypeID; 82 83struct __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 96static 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 117static void __CFUserNotificationDeallocate(CFTypeRef cf); 118 119static 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 131CF_PRIVATE void __CFUserNotificationInitialize(void) { 132 __kCFUserNotificationTypeID = _CFRuntimeRegisterClass(&__CFUserNotificationClass); 133} 134 135CFTypeID CFUserNotificationGetTypeID(void) { 136 if (_kCFRuntimeNotATypeID == __kCFUserNotificationTypeID) __CFUserNotificationInitialize(); 137 return __kCFUserNotificationTypeID; 138} 139 140static void __CFUserNotificationDeallocate(CFTypeRef cf) { 141 CFUserNotificationRef userNotification = (CFUserNotificationRef)cf; 142 if (userNotification->_machPort) { 143 CFMachPortInvalidate(userNotification->_machPort); 144 CFRelease(userNotification->_machPort); 145 } else if (MACH_PORT_NULL != userNotification->_replyPort) { 146 mach_port_destroy(mach_task_self(), userNotification->_replyPort); 147 } 148 if (userNotification->_sessionID) CFRelease(userNotification->_sessionID); 149 if (userNotification->_responseDictionary) CFRelease(userNotification->_responseDictionary); 150} 151 152static void _CFUserNotificationAddToDictionary(const void *key, const void *value, void *context) { 153 if (CFGetTypeID(key) == CFStringGetTypeID()) CFDictionarySetValue((CFMutableDictionaryRef)context, key, value); 154} 155 156static CFDictionaryRef _CFUserNotificationModifiedDictionary(CFAllocatorRef allocator, CFDictionaryRef dictionary, SInt32 token, SInt32 timeout, CFStringRef source) { 157 CFMutableDictionaryRef md = CFDictionaryCreateMutable(allocator, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 158 CFNumberRef tokenNumber = CFNumberCreate(allocator, kCFNumberSInt32Type, &token); 159 CFNumberRef timeoutNumber = CFNumberCreate(allocator, kCFNumberSInt32Type, &timeout); 160 CFURLRef url = NULL; 161 CFStringRef path = NULL; 162 163 if (dictionary) CFDictionaryApplyFunction(dictionary, _CFUserNotificationAddToDictionary, md); 164 if (source) CFDictionaryAddValue(md, kCFUserNotificationAlertSourceKey, source); 165 if (tokenNumber) { 166 CFDictionaryAddValue(md, kCFUserNotificationTokenKey, tokenNumber); 167 CFRelease(tokenNumber); 168 } 169 if (timeoutNumber) { 170 CFDictionaryAddValue(md, kCFUserNotificationTimeoutKey, timeoutNumber); 171 CFRelease(timeoutNumber); 172 } 173 174 url = CFDictionaryGetValue(md, kCFUserNotificationIconURLKey); 175 if (url && CFGetTypeID((CFTypeRef)url) == CFURLGetTypeID()) { 176 url = CFURLCopyAbsoluteURL(url); 177 CFDictionaryRemoveValue(md, kCFUserNotificationIconURLKey); 178 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); 179 CFDictionaryAddValue(md, kCFUserNotificationIconPathKey, path); 180 CFRelease(url); 181 CFRelease(path); 182 } 183 url = CFDictionaryGetValue(md, kCFUserNotificationSoundURLKey); 184 if (url && CFGetTypeID((CFTypeRef)url) == CFURLGetTypeID()) { 185 url = CFURLCopyAbsoluteURL(url); 186 CFDictionaryRemoveValue(md, kCFUserNotificationSoundURLKey); 187 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); 188 CFDictionaryAddValue(md, kCFUserNotificationSoundPathKey, path); 189 CFRelease(url); 190 CFRelease(path); 191 } 192 url = CFDictionaryGetValue(md, kCFUserNotificationLocalizationURLKey); 193 if (url && CFGetTypeID((CFTypeRef)url) == CFURLGetTypeID()) { 194 url = CFURLCopyAbsoluteURL(url); 195 CFDictionaryRemoveValue(md, kCFUserNotificationLocalizationURLKey); 196 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); 197 CFDictionaryAddValue(md, kCFUserNotificationLocalizationPathKey, path); 198 CFRelease(url); 199 CFRelease(path); 200 } 201 return md; 202} 203 204static SInt32 _CFUserNotificationSendRequest(CFAllocatorRef allocator, CFStringRef sessionID, mach_port_t replyPort, SInt32 token, CFTimeInterval timeout, CFOptionFlags flags, CFDictionaryRef dictionary) { 205 CFDictionaryRef modifiedDictionary = NULL; 206 SInt32 retval = ERR_SUCCESS, itimeout = (timeout > 0.0 && timeout < INT_MAX) ? (SInt32)timeout : 0; 207 CFDataRef data; 208 mach_msg_base_t *msg = NULL; 209 mach_port_t bootstrapPort = MACH_PORT_NULL, serverPort = MACH_PORT_NULL; 210 CFIndex size; 211 char namebuffer[MAX_PORT_NAME_LENGTH + 1]; 212 213 strlcpy(namebuffer, NOTIFICATION_PORT_NAME, sizeof(namebuffer)); 214 if (sessionID) { 215 char sessionid[MAX_PORT_NAME_LENGTH + 1]; 216 CFIndex len = MAX_PORT_NAME_LENGTH - sizeof(NOTIFICATION_PORT_NAME) - sizeof(NOTIFICATION_PORT_NAME_SUFFIX); 217 CFStringGetBytes(sessionID, CFRangeMake(0, CFStringGetLength(sessionID)), kCFStringEncodingUTF8, 0, false, (uint8_t *)sessionid, len, &size); 218 sessionid[len - 1] = '\0'; 219 strlcat(namebuffer, NOTIFICATION_PORT_NAME_SUFFIX, sizeof(namebuffer)); 220 strlcat(namebuffer, sessionid, sizeof(namebuffer)); 221 } 222 223 retval = task_get_bootstrap_port(mach_task_self(), &bootstrapPort); 224 if (ERR_SUCCESS == retval && MACH_PORT_NULL != bootstrapPort) retval = bootstrap_look_up2(bootstrapPort, namebuffer, &serverPort, 0, 0); 225 if (ERR_SUCCESS == retval && MACH_PORT_NULL != serverPort) { 226 modifiedDictionary = _CFUserNotificationModifiedDictionary(allocator, dictionary, token, itimeout, _CFProcessNameString()); 227 if (modifiedDictionary) { 228 data = CFPropertyListCreateXMLData(allocator, modifiedDictionary); 229 if (data) { 230 size = sizeof(mach_msg_base_t) + ((CFDataGetLength(data) + 3) & (~0x3)); 231 msg = (mach_msg_base_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0); 232 if (__CFOASafe) __CFSetLastAllocationEventName(msg, "CFUserNotification (temp)"); 233 if (msg) { 234 memset(msg, 0, size); 235 msg->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, (replyPort == MACH_PORT_NULL) ? 0 : MACH_MSG_TYPE_MAKE_SEND_ONCE); 236 msg->header.msgh_size = size; 237 msg->header.msgh_remote_port = serverPort; 238 msg->header.msgh_local_port = replyPort; 239 msg->header.msgh_id = flags; 240 msg->body.msgh_descriptor_count = 0; 241 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (uint8_t *)msg + sizeof(mach_msg_base_t)); 242 //CFShow(CFStringCreateWithBytes(kCFAllocatorSystemDefault, (UInt8 *)msg + sizeof(mach_msg_base_t), CFDataGetLength(data), kCFStringEncodingUTF8, false)); 243 retval = mach_msg((mach_msg_header_t *)msg, MACH_SEND_MSG|MACH_SEND_TIMEOUT, size, 0, MACH_PORT_NULL, MESSAGE_TIMEOUT, MACH_PORT_NULL); 244 CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); 245 } else { 246 retval = unix_err(ENOMEM); 247 } 248 CFRelease(data); 249 } else { 250 retval = unix_err(ENOMEM); 251 } 252 CFRelease(modifiedDictionary); 253 } else { 254 retval = unix_err(ENOMEM); 255 } 256 } 257 return retval; 258} 259 260static SInt32 _getNextToken() { 261 static uint16_t tokenCounter = 0; 262 SInt32 token = ((getpid() << 16) | (tokenCounter++)); 263 return token; 264} 265 266CFUserNotificationRef CFUserNotificationCreate(CFAllocatorRef allocator, CFTimeInterval timeout, CFOptionFlags flags, SInt32 *error, CFDictionaryRef dictionary) { 267 CHECK_FOR_FORK(); 268 CFUserNotificationRef userNotification = NULL; 269 SInt32 retval = ERR_SUCCESS; 270 SInt32 token = _getNextToken(); 271 CFStringRef sessionID = (dictionary ? CFDictionaryGetValue(dictionary, kCFUserNotificationSessionIDKey) : NULL); 272 mach_port_t replyPort = MACH_PORT_NULL; 273 274 if (!allocator) allocator = __CFGetDefaultAllocator(); 275 retval = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &replyPort); 276 if (ERR_SUCCESS == retval && MACH_PORT_NULL != replyPort) retval = _CFUserNotificationSendRequest(allocator, sessionID, replyPort, token, timeout, flags, dictionary); 277 if (ERR_SUCCESS == retval) { 278 userNotification = (CFUserNotificationRef)_CFRuntimeCreateInstance(allocator, CFUserNotificationGetTypeID(), sizeof(struct __CFUserNotification) - sizeof(CFRuntimeBase), NULL); 279 if (userNotification) { 280 userNotification->_replyPort = replyPort; 281 userNotification->_token = token; 282 userNotification->_timeout = timeout; 283 userNotification->_requestFlags = flags; 284 userNotification->_responseFlags = 0; 285 userNotification->_sessionID = NULL; 286 userNotification->_responseDictionary = NULL; 287 userNotification->_machPort = NULL; 288 userNotification->_callout = NULL; 289 if (sessionID) userNotification->_sessionID = CFStringCreateCopy(allocator, sessionID); 290 } else { 291 retval = unix_err(ENOMEM); 292 } 293 } else { 294 if (dictionary) CFUserNotificationLog(CFDictionaryGetValue(dictionary, kCFUserNotificationAlertHeaderKey), CFDictionaryGetValue(dictionary, kCFUserNotificationAlertMessageKey)); 295 } 296 if (ERR_SUCCESS != retval && MACH_PORT_NULL != replyPort) mach_port_destroy(mach_task_self(), replyPort); 297 if (error) *error = retval; 298 return userNotification; 299} 300 301static void _CFUserNotificationMachPortCallBack(CFMachPortRef port, void *m, CFIndex size, void *info) { 302 CFUserNotificationRef userNotification = (CFUserNotificationRef)info; 303 mach_msg_base_t *msg = (mach_msg_base_t *)m; 304 CFOptionFlags responseFlags = msg->header.msgh_id; 305 if (msg->header.msgh_size > sizeof(mach_msg_base_t)) { 306 CFDataRef responseData = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)msg + sizeof(mach_msg_base_t), msg->header.msgh_size - sizeof(mach_msg_base_t)); 307 if (responseData) { 308 userNotification->_responseDictionary = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, responseData, kCFPropertyListImmutable, NULL); 309 CFRelease(responseData); 310 } 311 } 312 CFMachPortInvalidate(userNotification->_machPort); 313 CFRelease(userNotification->_machPort); 314 userNotification->_machPort = NULL; 315 mach_port_destroy(mach_task_self(), userNotification->_replyPort); 316 userNotification->_replyPort = MACH_PORT_NULL; 317 userNotification->_callout(userNotification, responseFlags); 318} 319 320SInt32 CFUserNotificationReceiveResponse(CFUserNotificationRef userNotification, CFTimeInterval timeout, CFOptionFlags *responseFlags) { 321 CHECK_FOR_FORK(); 322 SInt32 retval = ERR_SUCCESS; 323 mach_msg_timeout_t msgtime = (timeout > 0.0 && 1000.0 * timeout < INT_MAX) ? (mach_msg_timeout_t)(1000.0 * timeout) : 0; 324 mach_msg_base_t *msg = NULL; 325 CFIndex size = MAX_STRING_COUNT * MAX_STRING_LENGTH; 326 CFDataRef responseData; 327 328 if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) { 329 msg = (mach_msg_base_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0); 330 if (__CFOASafe) __CFSetLastAllocationEventName(msg, "CFUserNotification (temp)"); 331 if (msg) { 332 memset(msg, 0, size); 333 msg->header.msgh_size = size; 334 if (msgtime > 0) { 335 retval = mach_msg((mach_msg_header_t *)msg, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, size, userNotification->_replyPort, msgtime, MACH_PORT_NULL); 336 } else { 337 retval = mach_msg((mach_msg_header_t *)msg, MACH_RCV_MSG, 0, size, userNotification->_replyPort, 0, MACH_PORT_NULL); 338 } 339 if (ERR_SUCCESS == retval) { 340 if (responseFlags) *responseFlags = msg->header.msgh_id; 341 if (msg->header.msgh_size > sizeof(mach_msg_base_t)) { 342 responseData = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)msg + sizeof(mach_msg_base_t), msg->header.msgh_size - sizeof(mach_msg_base_t)); 343 if (responseData) { 344 userNotification->_responseDictionary = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, responseData, kCFPropertyListImmutable, NULL); 345 CFRelease(responseData); 346 } 347 } 348 if (userNotification->_machPort) { 349 CFMachPortInvalidate(userNotification->_machPort); 350 CFRelease(userNotification->_machPort); 351 userNotification->_machPort = NULL; 352 } 353 mach_port_destroy(mach_task_self(), userNotification->_replyPort); 354 userNotification->_replyPort = MACH_PORT_NULL; 355 } 356 CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); 357 } else { 358 retval = unix_err(ENOMEM); 359 } 360 } 361 return retval; 362} 363 364CFStringRef CFUserNotificationGetResponseValue(CFUserNotificationRef userNotification, CFStringRef key, CFIndex idx) { 365 CHECK_FOR_FORK(); 366 CFStringRef retval = NULL; 367 CFTypeRef value = NULL; 368 if (userNotification && userNotification->_responseDictionary) { 369 value = CFDictionaryGetValue(userNotification->_responseDictionary, key); 370 if (CFGetTypeID(value) == CFStringGetTypeID()) { 371 if (0 == idx) retval = (CFStringRef)value; 372 } else if (CFGetTypeID(value) == CFArrayGetTypeID()) { 373 if (0 <= idx && idx < CFArrayGetCount((CFArrayRef)value)) retval = (CFStringRef)CFArrayGetValueAtIndex((CFArrayRef)value, idx); 374 } 375 } 376 return retval; 377} 378 379CFDictionaryRef CFUserNotificationGetResponseDictionary(CFUserNotificationRef userNotification) { 380 CHECK_FOR_FORK(); 381 return userNotification ? userNotification->_responseDictionary : NULL; 382} 383 384SInt32 CFUserNotificationUpdate(CFUserNotificationRef userNotification, CFTimeInterval timeout, CFOptionFlags flags, CFDictionaryRef dictionary) { 385 CHECK_FOR_FORK(); 386 SInt32 retval = ERR_SUCCESS; 387 if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) { 388 // 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. 389 retval = _CFUserNotificationSendRequest(CFGetAllocator(userNotification), userNotification->_sessionID, MACH_PORT_NULL, userNotification->_token, timeout, flags|kCFUserNotificationUpdateFlag, dictionary); 390 } 391 return retval; 392} 393 394SInt32 CFUserNotificationCancel(CFUserNotificationRef userNotification) { 395 CHECK_FOR_FORK(); 396 SInt32 retval = ERR_SUCCESS; 397 if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) { 398 // 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. 399 retval = _CFUserNotificationSendRequest(CFGetAllocator(userNotification), userNotification->_sessionID, MACH_PORT_NULL, userNotification->_token, 0, kCFUserNotificationCancelFlag, NULL); 400 } 401 return retval; 402} 403 404CFRunLoopSourceRef CFUserNotificationCreateRunLoopSource(CFAllocatorRef allocator, CFUserNotificationRef userNotification, CFUserNotificationCallBack callout, CFIndex order) { 405 CHECK_FOR_FORK(); 406 CFRunLoopSourceRef source = NULL; 407 if (userNotification && callout && !userNotification->_machPort && MACH_PORT_NULL != userNotification->_replyPort) { 408 CFMachPortContext context = {0, userNotification, NULL, NULL, NULL}; 409 userNotification->_machPort = CFMachPortCreateWithPort(CFGetAllocator(userNotification), (mach_port_t)userNotification->_replyPort, _CFUserNotificationMachPortCallBack, &context, NULL); 410 } 411 if (userNotification && userNotification->_machPort) { 412 source = CFMachPortCreateRunLoopSource(allocator, userNotification->_machPort, order); 413 userNotification->_callout = callout; 414 } 415 return source; 416} 417 418SInt32 CFUserNotificationDisplayNotice(CFTimeInterval timeout, CFOptionFlags flags, CFURLRef iconURL, CFURLRef soundURL, CFURLRef localizationURL, CFStringRef alertHeader, CFStringRef alertMessage, CFStringRef defaultButtonTitle) { 419 CHECK_FOR_FORK(); 420 SInt32 retval = ERR_SUCCESS; 421 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 422 if (iconURL) CFDictionaryAddValue(dict, kCFUserNotificationIconURLKey, iconURL); 423 if (soundURL) CFDictionaryAddValue(dict, kCFUserNotificationSoundURLKey, soundURL); 424 if (localizationURL) CFDictionaryAddValue(dict, kCFUserNotificationLocalizationURLKey, localizationURL); 425 if (alertHeader) CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, alertHeader); 426 if (alertMessage) CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, alertMessage); 427 if (defaultButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, defaultButtonTitle); 428 retval = _CFUserNotificationSendRequest(__CFGetDefaultAllocator(), NULL, MACH_PORT_NULL, _getNextToken(), timeout, flags, dict); 429 if (ERR_SUCCESS != retval) { 430 CFUserNotificationLog(alertHeader, alertMessage); 431 } 432 CFRelease(dict); 433 return retval; 434} 435 436 437CF_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) { 438 CHECK_FOR_FORK(); 439 CFUserNotificationRef userNotification; 440 SInt32 retval = ERR_SUCCESS; 441 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 442 if (iconURL) CFDictionaryAddValue(dict, kCFUserNotificationIconURLKey, iconURL); 443 if (soundURL) CFDictionaryAddValue(dict, kCFUserNotificationSoundURLKey, soundURL); 444 if (localizationURL) CFDictionaryAddValue(dict, kCFUserNotificationLocalizationURLKey, localizationURL); 445 if (alertHeader) CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, alertHeader); 446 if (alertMessage) CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, alertMessage); 447 if (defaultButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, defaultButtonTitle); 448 if (alternateButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationAlternateButtonTitleKey, alternateButtonTitle); 449 if (otherButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationOtherButtonTitleKey, otherButtonTitle); 450 userNotification = CFUserNotificationCreate(kCFAllocatorSystemDefault, timeout, flags, &retval, dict); 451 if (userNotification) { 452 retval = CFUserNotificationReceiveResponse(userNotification, timeout, responseFlags); 453 if (MACH_RCV_TIMED_OUT == retval) { 454 retval = CFUserNotificationCancel(userNotification); 455 if (responseFlags) *responseFlags = kCFUserNotificationCancelResponse; 456 } 457 CFRelease(userNotification); 458 } 459 CFRelease(dict); 460 return retval; 461} 462 463#undef MAX_STRING_LENGTH 464#undef MAX_STRING_COUNT 465#undef NOTIFICATION_PORT_NAME 466#undef MESSAGE_TIMEOUT 467#undef MAX_PORT_NAME_LENGTH 468#undef NOTIFICATION_PORT_NAME_SUFFIX 469 470