]> git.saurik.com Git - apple/cf.git/blame - CFUserNotification.c
CF-635.15.tar.gz
[apple/cf.git] / CFUserNotification.c
CommitLineData
9ce05555 1/*
8ca704e1 2 * Copyright (c) 2011 Apple Inc. All rights reserved.
9ce05555
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
9ce05555
A
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 */
f64f9b69 23
9ce05555 24/* CFUserNotification.c
8ca704e1
A
25 Copyright (c) 2000-2011, Apple Inc. All rights reserved.
26 Original Author: Doug Davidson
27 Responsibility: Kevin Perry
9ce05555
A
28*/
29
30#include <CoreFoundation/CFUserNotification.h>
31#include <CoreFoundation/CFPropertyList.h>
32#include <CoreFoundation/CFNumber.h>
9ce05555
A
33#include <CoreFoundation/CFRunLoop.h>
34#include "CFInternal.h"
bd5b749c
A
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>
9ce05555 45
bd5b749c 46#define CFUserNotificationLog(alertHeader, alertMessage) CFLog(3, CFSTR("%@: %@"), alertHeader, alertMessage);
9ce05555
A
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")
bd5b749c 77CONST_STRING_DECL(kCFUserNotificationKeyboardTypesKey, "KeyboardTypes")
cf7d2af9
A
78CONST_STRING_DECL(kCFUserNotificationAlertTopMostKey, "AlertTopMost") // boolean value
79
9ce05555
A
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);
bd5b749c 99 CFStringAppendFormat(result, NULL, CFSTR("<CFUserNotification %p>"), cf);
9ce05555
A
100 return result;
101}
102
9ce05555
A
103#define MAX_STRING_LENGTH PATH_MAX
104#define MAX_STRING_COUNT 16
105#define MAX_PORT_NAME_LENGTH 63
9ce05555
A
106#define NOTIFICATION_PORT_NAME_SUFFIX ".session."
107#define MESSAGE_TIMEOUT 100
bd5b749c
A
108#if DEPLOYMENT_TARGET_MACOSX
109#define NOTIFICATION_PORT_NAME "com.apple.UNCUserNotification"
cf7d2af9 110#elif DEPLOYMENT_TARGET_EMBEDDED
bd5b749c
A
111#define NOTIFICATION_PORT_NAME "com.apple.SBUserNotification"
112#else
113#error Unknown or unspecified DEPLOYMENT_TARGET
114#endif
9ce05555 115
9ce05555 116
d8925383
A
117static void __CFUserNotificationDeallocate(CFTypeRef cf);
118
9ce05555
A
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
131__private_extern__ void __CFUserNotificationInitialize(void) {
132 __kCFUserNotificationTypeID = _CFRuntimeRegisterClass(&__CFUserNotificationClass);
133}
134
135CFTypeID CFUserNotificationGetTypeID(void) {
bd5b749c 136 if (_kCFRuntimeNotATypeID == __kCFUserNotificationTypeID) __CFUserNotificationInitialize();
9ce05555
A
137 return __kCFUserNotificationTypeID;
138}
139
d8925383
A
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
9ce05555
A
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;
bd5b749c 211 char namebuffer[MAX_PORT_NAME_LENGTH + 1];
cf7d2af9 212
bd5b749c 213 strlcpy(namebuffer, NOTIFICATION_PORT_NAME, sizeof(namebuffer));
9ce05555 214 if (sessionID) {
cf7d2af9
A
215 char sessionid[MAX_PORT_NAME_LENGTH + 1];
216 CFIndex len = MAX_PORT_NAME_LENGTH - sizeof(NOTIFICATION_PORT_NAME) - sizeof(NOTIFICATION_PORT_NAME_SUFFIX);
bd5b749c 217 CFStringGetBytes(sessionID, CFRangeMake(0, CFStringGetLength(sessionID)), kCFStringEncodingUTF8, 0, false, (uint8_t *)sessionid, len, &size);
cf7d2af9
A
218 sessionid[len - 1] = '\0';
219 strlcat(namebuffer, NOTIFICATION_PORT_NAME_SUFFIX, sizeof(namebuffer));
220 strlcat(namebuffer, sessionid, sizeof(namebuffer));
9ce05555
A
221 }
222
223 retval = task_get_bootstrap_port(mach_task_self(), &bootstrapPort);
bd5b749c 224 if (ERR_SUCCESS == retval && MACH_PORT_NULL != bootstrapPort) retval = bootstrap_look_up2(bootstrapPort, namebuffer, &serverPort, 0, 0);
9ce05555
A
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));
8ca704e1 231 msg = (mach_msg_base_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0);
9ce05555
A
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, 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));
bd5b749c 242 //CFShow(CFStringCreateWithBytes(kCFAllocatorSystemDefault, (UInt8 *)msg + sizeof(mach_msg_base_t), CFDataGetLength(data), kCFStringEncodingUTF8, false));
9ce05555 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);
8ca704e1 244 CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg);
9ce05555
A
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
260CFUserNotificationRef CFUserNotificationCreate(CFAllocatorRef allocator, CFTimeInterval timeout, CFOptionFlags flags, SInt32 *error, CFDictionaryRef dictionary) {
bd5b749c 261 CHECK_FOR_FORK();
9ce05555
A
262 CFUserNotificationRef userNotification = NULL;
263 SInt32 retval = ERR_SUCCESS;
264 static uint16_t tokenCounter = 0;
cf7d2af9 265 SInt32 token = ((getpid() << 16) | (tokenCounter++));
9ce05555
A
266 CFStringRef sessionID = (dictionary ? CFDictionaryGetValue(dictionary, kCFUserNotificationSessionIDKey) : NULL);
267 mach_port_t replyPort = MACH_PORT_NULL;
268
269 if (!allocator) allocator = __CFGetDefaultAllocator();
9ce05555
A
270 retval = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &replyPort);
271 if (ERR_SUCCESS == retval && MACH_PORT_NULL != replyPort) retval = _CFUserNotificationSendRequest(allocator, sessionID, replyPort, token, timeout, flags, dictionary);
272 if (ERR_SUCCESS == retval) {
bd5b749c 273 userNotification = (CFUserNotificationRef)_CFRuntimeCreateInstance(allocator, CFUserNotificationGetTypeID(), sizeof(struct __CFUserNotification) - sizeof(CFRuntimeBase), NULL);
9ce05555
A
274 if (userNotification) {
275 userNotification->_replyPort = replyPort;
276 userNotification->_token = token;
277 userNotification->_timeout = timeout;
278 userNotification->_requestFlags = flags;
279 userNotification->_responseFlags = 0;
280 userNotification->_sessionID = NULL;
281 userNotification->_responseDictionary = NULL;
282 userNotification->_machPort = NULL;
283 userNotification->_callout = NULL;
284 if (sessionID) userNotification->_sessionID = CFStringCreateCopy(allocator, sessionID);
285 } else {
286 retval = unix_err(ENOMEM);
287 }
288 } else {
289 if (dictionary) CFUserNotificationLog(CFDictionaryGetValue(dictionary, kCFUserNotificationAlertHeaderKey), CFDictionaryGetValue(dictionary, kCFUserNotificationAlertMessageKey));
290 }
291 if (ERR_SUCCESS != retval && MACH_PORT_NULL != replyPort) mach_port_destroy(mach_task_self(), replyPort);
292 if (error) *error = retval;
293 return userNotification;
294}
295
296static void _CFUserNotificationMachPortCallBack(CFMachPortRef port, void *m, CFIndex size, void *info) {
297 CFUserNotificationRef userNotification = (CFUserNotificationRef)info;
298 mach_msg_base_t *msg = (mach_msg_base_t *)m;
299 CFOptionFlags responseFlags = msg->header.msgh_id;
d8925383 300 if (msg->header.msgh_size > sizeof(mach_msg_base_t)) {
bd5b749c 301 CFDataRef responseData = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)msg + sizeof(mach_msg_base_t), msg->header.msgh_size - sizeof(mach_msg_base_t));
d8925383 302 if (responseData) {
bd5b749c 303 userNotification->_responseDictionary = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, responseData, kCFPropertyListImmutable, NULL);
d8925383
A
304 CFRelease(responseData);
305 }
9ce05555
A
306 }
307 CFMachPortInvalidate(userNotification->_machPort);
308 CFRelease(userNotification->_machPort);
309 userNotification->_machPort = NULL;
310 mach_port_destroy(mach_task_self(), userNotification->_replyPort);
311 userNotification->_replyPort = MACH_PORT_NULL;
312 userNotification->_callout(userNotification, responseFlags);
313}
314
315SInt32 CFUserNotificationReceiveResponse(CFUserNotificationRef userNotification, CFTimeInterval timeout, CFOptionFlags *responseFlags) {
bd5b749c 316 CHECK_FOR_FORK();
9ce05555
A
317 SInt32 retval = ERR_SUCCESS;
318 mach_msg_timeout_t msgtime = (timeout > 0.0 && 1000.0 * timeout < INT_MAX) ? (mach_msg_timeout_t)(1000.0 * timeout) : 0;
319 mach_msg_base_t *msg = NULL;
320 CFIndex size = MAX_STRING_COUNT * MAX_STRING_LENGTH;
321 CFDataRef responseData;
322
323 if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) {
8ca704e1 324 msg = (mach_msg_base_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0);
cf7d2af9 325 if (__CFOASafe) __CFSetLastAllocationEventName(msg, "CFUserNotification (temp)");
9ce05555
A
326 if (msg) {
327 memset(msg, 0, size);
328 msg->header.msgh_size = size;
329 if (msgtime > 0) {
330 retval = mach_msg((mach_msg_header_t *)msg, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, size, userNotification->_replyPort, msgtime, MACH_PORT_NULL);
331 } else {
332 retval = mach_msg((mach_msg_header_t *)msg, MACH_RCV_MSG, 0, size, userNotification->_replyPort, 0, MACH_PORT_NULL);
333 }
334 if (ERR_SUCCESS == retval) {
335 if (responseFlags) *responseFlags = msg->header.msgh_id;
d8925383 336 if (msg->header.msgh_size > sizeof(mach_msg_base_t)) {
bd5b749c 337 responseData = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)msg + sizeof(mach_msg_base_t), msg->header.msgh_size - sizeof(mach_msg_base_t));
d8925383 338 if (responseData) {
bd5b749c 339 userNotification->_responseDictionary = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, responseData, kCFPropertyListImmutable, NULL);
d8925383
A
340 CFRelease(responseData);
341 }
9ce05555
A
342 }
343 if (userNotification->_machPort) {
344 CFMachPortInvalidate(userNotification->_machPort);
345 CFRelease(userNotification->_machPort);
346 userNotification->_machPort = NULL;
347 }
348 mach_port_destroy(mach_task_self(), userNotification->_replyPort);
349 userNotification->_replyPort = MACH_PORT_NULL;
350 }
8ca704e1 351 CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg);
9ce05555
A
352 } else {
353 retval = unix_err(ENOMEM);
354 }
355 }
356 return retval;
357}
358
359CFStringRef CFUserNotificationGetResponseValue(CFUserNotificationRef userNotification, CFStringRef key, CFIndex idx) {
bd5b749c 360 CHECK_FOR_FORK();
9ce05555
A
361 CFStringRef retval = NULL;
362 CFTypeRef value = NULL;
363 if (userNotification && userNotification->_responseDictionary) {
364 value = CFDictionaryGetValue(userNotification->_responseDictionary, key);
365 if (CFGetTypeID(value) == CFStringGetTypeID()) {
cf7d2af9 366 if (0 == idx) retval = (CFStringRef)value;
9ce05555 367 } else if (CFGetTypeID(value) == CFArrayGetTypeID()) {
cf7d2af9 368 if (0 <= idx && idx < CFArrayGetCount((CFArrayRef)value)) retval = (CFStringRef)CFArrayGetValueAtIndex((CFArrayRef)value, idx);
9ce05555
A
369 }
370 }
371 return retval;
372}
373
374CFDictionaryRef CFUserNotificationGetResponseDictionary(CFUserNotificationRef userNotification) {
bd5b749c 375 CHECK_FOR_FORK();
9ce05555
A
376 return userNotification ? userNotification->_responseDictionary : NULL;
377}
378
379SInt32 CFUserNotificationUpdate(CFUserNotificationRef userNotification, CFTimeInterval timeout, CFOptionFlags flags, CFDictionaryRef dictionary) {
bd5b749c 380 CHECK_FOR_FORK();
9ce05555 381 SInt32 retval = ERR_SUCCESS;
cf7d2af9 382 if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) retval = _CFUserNotificationSendRequest(CFGetAllocator(userNotification), userNotification->_sessionID, userNotification->_replyPort, userNotification->_token, timeout, flags|kCFUserNotificationUpdateFlag, dictionary);
9ce05555
A
383 return retval;
384}
385
386SInt32 CFUserNotificationCancel(CFUserNotificationRef userNotification) {
bd5b749c 387 CHECK_FOR_FORK();
9ce05555 388 SInt32 retval = ERR_SUCCESS;
cf7d2af9 389 if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) retval = _CFUserNotificationSendRequest(CFGetAllocator(userNotification), userNotification->_sessionID, userNotification->_replyPort, userNotification->_token, 0, kCFUserNotificationCancelFlag, NULL);
9ce05555
A
390 return retval;
391}
392
393CFRunLoopSourceRef CFUserNotificationCreateRunLoopSource(CFAllocatorRef allocator, CFUserNotificationRef userNotification, CFUserNotificationCallBack callout, CFIndex order) {
bd5b749c 394 CHECK_FOR_FORK();
9ce05555
A
395 CFRunLoopSourceRef source = NULL;
396 if (userNotification && callout && !userNotification->_machPort && MACH_PORT_NULL != userNotification->_replyPort) {
397 CFMachPortContext context = {0, userNotification, NULL, NULL, NULL};
cf7d2af9 398 userNotification->_machPort = CFMachPortCreateWithPort(CFGetAllocator(userNotification), (mach_port_t)userNotification->_replyPort, _CFUserNotificationMachPortCallBack, &context, NULL);
9ce05555
A
399 }
400 if (userNotification && userNotification->_machPort) {
401 source = CFMachPortCreateRunLoopSource(allocator, userNotification->_machPort, order);
402 userNotification->_callout = callout;
403 }
404 return source;
405}
406
407SInt32 CFUserNotificationDisplayNotice(CFTimeInterval timeout, CFOptionFlags flags, CFURLRef iconURL, CFURLRef soundURL, CFURLRef localizationURL, CFStringRef alertHeader, CFStringRef alertMessage, CFStringRef defaultButtonTitle) {
bd5b749c 408 CHECK_FOR_FORK();
9ce05555
A
409 CFUserNotificationRef userNotification;
410 SInt32 retval = ERR_SUCCESS;
bd5b749c 411 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
9ce05555
A
412 if (iconURL) CFDictionaryAddValue(dict, kCFUserNotificationIconURLKey, iconURL);
413 if (soundURL) CFDictionaryAddValue(dict, kCFUserNotificationSoundURLKey, soundURL);
414 if (localizationURL) CFDictionaryAddValue(dict, kCFUserNotificationLocalizationURLKey, localizationURL);
415 if (alertHeader) CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, alertHeader);
416 if (alertMessage) CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, alertMessage);
417 if (defaultButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, defaultButtonTitle);
bd5b749c 418 userNotification = CFUserNotificationCreate(kCFAllocatorSystemDefault, timeout, flags, &retval, dict);
9ce05555
A
419 if (userNotification) CFRelease(userNotification);
420 CFRelease(dict);
421 return retval;
422}
423
bd5b749c 424
9ce05555 425CF_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) {
bd5b749c 426 CHECK_FOR_FORK();
9ce05555
A
427 CFUserNotificationRef userNotification;
428 SInt32 retval = ERR_SUCCESS;
bd5b749c 429 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
9ce05555
A
430 if (iconURL) CFDictionaryAddValue(dict, kCFUserNotificationIconURLKey, iconURL);
431 if (soundURL) CFDictionaryAddValue(dict, kCFUserNotificationSoundURLKey, soundURL);
432 if (localizationURL) CFDictionaryAddValue(dict, kCFUserNotificationLocalizationURLKey, localizationURL);
433 if (alertHeader) CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, alertHeader);
434 if (alertMessage) CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, alertMessage);
435 if (defaultButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, defaultButtonTitle);
436 if (alternateButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationAlternateButtonTitleKey, alternateButtonTitle);
437 if (otherButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationOtherButtonTitleKey, otherButtonTitle);
bd5b749c 438 userNotification = CFUserNotificationCreate(kCFAllocatorSystemDefault, timeout, flags, &retval, dict);
9ce05555
A
439 if (userNotification) {
440 retval = CFUserNotificationReceiveResponse(userNotification, timeout, responseFlags);
441 if (MACH_RCV_TIMED_OUT == retval) {
442 retval = CFUserNotificationCancel(userNotification);
443 if (responseFlags) *responseFlags = kCFUserNotificationCancelResponse;
444 }
445 CFRelease(userNotification);
446 }
447 CFRelease(dict);
448 return retval;
449}
450
9ce05555
A
451#undef MAX_STRING_LENGTH
452#undef MAX_STRING_COUNT
453#undef NOTIFICATION_PORT_NAME
9ce05555 454#undef MESSAGE_TIMEOUT
bd5b749c
A
455#undef MAX_PORT_NAME_LENGTH
456#undef NOTIFICATION_PORT_NAME_SUFFIX
9ce05555 457