2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
27 _SCDNotifierAdd(SCDSessionRef session
, CFStringRef key
, int regexOptions
)
29 SCDSessionPrivateRef sessionPrivate
= (SCDSessionPrivateRef
)session
;
31 SCDLog(LOG_DEBUG
, CFSTR("_SCDNotifierAdd:"));
32 SCDLog(LOG_DEBUG
, CFSTR(" key = %@"), key
);
33 SCDLog(LOG_DEBUG
, CFSTR(" regexOptions = %0o"), regexOptions
);
35 if ((session
== NULL
) || (sessionPrivate
->server
== MACH_PORT_NULL
)) {
36 return SCD_NOSESSION
; /* you can't do anything with a closed session */
40 * add new key after checking if key has already been defined
42 if (regexOptions
& kSCDRegexKey
) {
43 if (CFSetContainsValue(sessionPrivate
->reKeys
, key
))
44 return SCD_EXISTS
; /* sorry, key already exists in notifier list */
45 CFSetAddValue(sessionPrivate
->reKeys
, key
); /* add key to this sessions notifier list */
47 if (CFSetContainsValue(sessionPrivate
->keys
, key
))
48 return SCD_EXISTS
; /* sorry, key already exists in notifier list */
49 CFSetAddValue(sessionPrivate
->keys
, key
); /* add key to this sessions notifier list */
52 if (regexOptions
& kSCDRegexKey
) {
53 CFStringRef sessionKey
;
56 CFMutableDataRef regexData
;
62 CFMutableDictionaryRef newInfo
;
64 CFMutableArrayRef newRKeys
;
66 CFMutableArrayRef newRData
;
69 * We are adding a regex key. As such, we need to flag
70 * any keys currently in the cache.
73 /* 1. Extract a C String version of the key pattern string. */
75 regexStrLen
= CFStringGetLength(key
) + 1;
76 regexStr
= CFAllocatorAllocate(NULL
, regexStrLen
, 0);
77 if (!CFStringGetCString(key
,
80 kCFStringEncodingMacRoman
)) {
81 SCDLog(LOG_DEBUG
, CFSTR("CFStringGetCString: could not convert regex key to C string"));
82 CFAllocatorDeallocate(NULL
, regexStr
);
86 /* 2. Compile the regular expression from the pattern string. */
88 regexData
= CFDataCreateMutable(NULL
, sizeof(regex_t
));
89 CFDataSetLength(regexData
, sizeof(regex_t
));
90 reError
= regcomp((regex_t
*)CFDataGetBytePtr(regexData
),
93 CFAllocatorDeallocate(NULL
, regexStr
);
95 reErrStrLen
= regerror(reError
,
96 (regex_t
*)CFDataGetBytePtr(regexData
),
99 SCDLog(LOG_DEBUG
, CFSTR("regcomp() key: %s"), reErrBuf
);
100 CFRelease(regexData
);
105 * 3. Iterate over the current keys and add this session as a "watcher"
106 * for any key already defined in the cache.
109 context
.session
= sessionPrivate
;
110 context
.preg
= (regex_t
*)CFDataGetBytePtr(regexData
);
111 CFDictionaryApplyFunction(cacheData
,
112 (CFDictionaryApplierFunction
)_addRegexWatcherByKey
,
116 * 4. We also need to save this key and the associated regex data
117 * for any subsequent additions.
119 sessionKey
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%d"), sessionPrivate
->server
);
121 info
= CFDictionaryGetValue(sessionData
, sessionKey
);
123 newInfo
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
125 newInfo
= CFDictionaryCreateMutable(NULL
,
127 &kCFTypeDictionaryKeyCallBacks
,
128 &kCFTypeDictionaryValueCallBacks
);
131 rKeys
= CFDictionaryGetValue(newInfo
, kSCDRegexKeys
);
132 if ((rKeys
== NULL
) ||
133 (CFArrayContainsValue(rKeys
,
134 CFRangeMake(0, CFArrayGetCount(rKeys
)),
136 rData
= CFDictionaryGetValue(newInfo
, kSCDRegexData
);
138 newRKeys
= CFArrayCreateMutableCopy(NULL
, 0, rKeys
);
139 newRData
= CFArrayCreateMutableCopy(NULL
, 0, rData
);
141 newRKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
142 newRData
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
145 /* save the regex key */
146 CFArrayAppendValue(newRKeys
, key
);
147 CFDictionarySetValue(newInfo
, kSCDRegexKeys
, newRKeys
);
149 /* ...and the compiled expression */
150 CFArrayAppendValue(newRData
, regexData
);
151 CFDictionarySetValue(newInfo
, kSCDRegexData
, newRData
);
153 CFDictionarySetValue(sessionData
, sessionKey
, newInfo
);
156 CFRelease(sessionKey
);
158 CFNumberRef sessionNum
;
161 * We are watching a specific key. As such, update the
162 * cache to mark our interest in any changes.
164 sessionNum
= CFNumberCreate(NULL
, kCFNumberIntType
, &sessionPrivate
->server
);
165 _addWatcher(sessionNum
, key
);
166 CFRelease(sessionNum
);
174 _notifyadd(mach_port_t server
,
175 xmlData_t keyRef
, /* raw XML bytes */
176 mach_msg_type_number_t keyLen
,
181 kern_return_t status
;
182 serverSessionRef mySession
= getSession(server
);
183 CFDataRef xmlKey
; /* key (XML serialized) */
184 CFStringRef key
; /* key (un-serialized) */
185 CFStringRef xmlError
;
187 SCDLog(LOG_DEBUG
, CFSTR("Add notification key for this session."));
188 SCDLog(LOG_DEBUG
, CFSTR(" server = %d"), server
);
190 /* un-serialize the key */
191 xmlKey
= CFDataCreate(NULL
, keyRef
, keyLen
);
192 status
= vm_deallocate(mach_task_self(), (vm_address_t
)keyRef
, keyLen
);
193 if (status
!= KERN_SUCCESS
) {
194 SCDLog(LOG_DEBUG
, CFSTR("vm_deallocate(): %s"), mach_error_string(status
));
195 /* non-fatal???, proceed */
197 key
= CFPropertyListCreateFromXMLData(NULL
,
199 kCFPropertyListImmutable
,
203 SCDLog(LOG_DEBUG
, CFSTR("CFPropertyListCreateFromXMLData() key: %s"), xmlError
);
204 *scd_status
= SCD_FAILED
;
208 *scd_status
= _SCDNotifierAdd(mySession
->session
, key
, regexOptions
);