]>
Commit | Line | Data |
---|---|---|
7cb34e5c A |
1 | /* |
2 | File: DNSServiceDiscoveryPref.m | |
3 | ||
4 | Abstract: System Preference Pane for Dynamic DNS and Wide-Area DNS Service Discovery | |
5 | ||
6 | Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved. | |
7 | ||
8 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. | |
9 | ("Apple") in consideration of your agreement to the following terms, and your | |
10 | use, installation, modification or redistribution of this Apple software | |
11 | constitutes acceptance of these terms. If you do not agree with these terms, | |
12 | please do not use, install, modify or redistribute this Apple software. | |
13 | ||
14 | In consideration of your agreement to abide by the following terms, and subject | |
15 | to these terms, Apple grants you a personal, non-exclusive license, under Apple's | |
16 | copyrights in this original Apple software (the "Apple Software"), to use, | |
17 | reproduce, modify and redistribute the Apple Software, with or without | |
18 | modifications, in source and/or binary forms; provided that if you redistribute | |
19 | the Apple Software in its entirety and without modifications, you must retain | |
20 | this notice and the following text and disclaimers in all such redistributions of | |
21 | the Apple Software. Neither the name, trademarks, service marks or logos of | |
22 | Apple Computer, Inc. may be used to endorse or promote products derived from the | |
23 | Apple Software without specific prior written permission from Apple. Except as | |
24 | expressly stated in this notice, no other rights or licenses, express or implied, | |
25 | are granted by Apple herein, including but not limited to any patent rights that | |
26 | may be infringed by your derivative works or by other works in which the Apple | |
27 | Software may be incorporated. | |
28 | ||
29 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO | |
30 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED | |
31 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
32 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN | |
33 | COMBINATION WITH YOUR PRODUCTS. | |
34 | ||
35 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR | |
36 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | |
37 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
38 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION | |
39 | OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT | |
40 | (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN | |
41 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
42 | ||
43 | Change History (most recent first): | |
67c8f8a1 | 44 | |
7cb34e5c | 45 | $Log: DNSServiceDiscoveryPref.m,v $ |
32bb7e43 A |
46 | Revision 1.16 2008/09/15 23:52:30 cheshire |
47 | <rdar://problem/6218902> mDNSResponder-177 fails to compile on Linux with .desc pseudo-op | |
48 | Made __crashreporter_info__ symbol conditional, so we only use it for OS X build | |
49 | ||
50 | Revision 1.15 2008/08/18 17:57:04 mcguire | |
51 | <rdar://problem/6156209> build error | |
52 | ||
53 | Revision 1.14 2008/07/18 17:39:14 cheshire | |
54 | If NSInteger is not defined (indicated by lack of definition for NSINTEGER_DEFINED) | |
55 | then #define "NSInteger" to be "int" like it used to be | |
56 | ||
57 | Revision 1.13 2008/07/01 01:40:01 mcguire | |
58 | <rdar://problem/5823010> 64-bit fixes | |
59 | ||
60 | Revision 1.12 2008/05/08 00:46:38 cheshire | |
61 | <rdar://problem/5919272> GetNextLabel insufficiently defensive | |
62 | User shared copy of GetNextLabel in ClientCommon.c instead of having a local copy here | |
63 | ||
030b743d A |
64 | Revision 1.11 2007/11/30 23:42:09 cheshire |
65 | Fixed compile warning: declaration of 'index' shadows a global declaration | |
66 | ||
67c8f8a1 A |
67 | Revision 1.10 2007/09/18 19:09:02 cheshire |
68 | <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings | |
69 | ||
70 | Revision 1.9 2007/02/09 00:39:06 cheshire | |
71 | Fix compile warnings | |
72 | ||
73 | Revision 1.8 2006/08/14 23:15:47 cheshire | |
74 | Tidy up Change History comment | |
75 | ||
76 | Revision 1.7 2006/07/14 03:59:14 cheshire | |
77 | Fix compile warnings: 'sortUsingFunction:context:' comparison function needs to return int | |
78 | ||
7cb34e5c A |
79 | Revision 1.6 2005/02/26 00:44:24 cheshire |
80 | Restore default reg domain if user deletes text and clicks "apply" | |
81 | ||
82 | Revision 1.5 2005/02/25 02:29:28 cheshire | |
83 | Show yellow dot for "update in progress" | |
84 | ||
85 | Revision 1.4 2005/02/16 00:18:33 cheshire | |
86 | Bunch o' fixes | |
87 | ||
88 | Revision 1.3 2005/02/10 22:35:20 cheshire | |
89 | <rdar://problem/3727944> Update name | |
90 | ||
91 | Revision 1.2 2005/02/08 01:32:05 cheshire | |
92 | Add trimCharactersFromDomain routine to strip leading and trailing | |
93 | white space and punctuation from user-entered fields. | |
94 | ||
95 | Revision 1.1 2005/02/05 01:59:19 cheshire | |
96 | Add Preference Pane to facilitate testing of DDNS & wide-area features | |
97 | ||
98 | */ | |
99 | ||
100 | #import "DNSServiceDiscoveryPref.h" | |
101 | #import "ConfigurationAuthority.h" | |
102 | #import "PrivilegedOperations.h" | |
103 | #import <unistd.h> | |
104 | ||
32bb7e43 A |
105 | #include "../../Clients/ClientCommon.h" |
106 | ||
107 | #ifndef NSINTEGER_DEFINED | |
108 | #define NSInteger int | |
109 | #endif | |
110 | ||
7cb34e5c A |
111 | @implementation DNSServiceDiscoveryPref |
112 | ||
32bb7e43 | 113 | static NSComparisonResult |
7cb34e5c A |
114 | MyArrayCompareFunction(id val1, id val2, void *context) |
115 | { | |
67c8f8a1 | 116 | (void)context; // Unused |
7cb34e5c A |
117 | return CFStringCompare((CFStringRef)val1, (CFStringRef)val2, kCFCompareCaseInsensitive); |
118 | } | |
119 | ||
120 | ||
32bb7e43 | 121 | static NSComparisonResult |
7cb34e5c A |
122 | MyDomainArrayCompareFunction(id val1, id val2, void *context) |
123 | { | |
67c8f8a1 | 124 | (void)context; // Unused |
7cb34e5c A |
125 | NSString *domain1 = [val1 objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY]; |
126 | NSString *domain2 = [val2 objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY]; | |
127 | return CFStringCompare((CFStringRef)domain1, (CFStringRef)domain2, kCFCompareCaseInsensitive); | |
128 | } | |
129 | ||
130 | ||
7cb34e5c A |
131 | static void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context) |
132 | { | |
67c8f8a1 A |
133 | (void)store; // Unused |
134 | (void)changedKeys; // Unused | |
7cb34e5c A |
135 | DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)context; |
136 | assert(me != NULL); | |
137 | ||
138 | [me setupInitialValues]; | |
139 | } | |
140 | ||
141 | ||
142 | static void ServiceDomainEnumReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, | |
143 | DNSServiceErrorType errorCode, const char *replyDomain, void *context, DNSServiceFlags enumType) | |
144 | { | |
67c8f8a1 A |
145 | (void)sdRef; // Unused |
146 | (void)interfaceIndex; // Unused | |
147 | (void)errorCode; // Unused | |
7cb34e5c A |
148 | if (strcmp(replyDomain, "local.") == 0) return; // local domain is not interesting |
149 | ||
150 | DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)context; | |
151 | BOOL moreComing = (BOOL)(flags & kDNSServiceFlagsMoreComing); | |
152 | NSMutableArray * domainArray; | |
153 | NSMutableArray * defaultBrowseDomainsArray = nil; | |
154 | NSComboBox * domainComboBox; | |
155 | NSString * domainString; | |
156 | NSString * currentDomain = nil; | |
157 | char decodedDomainString[kDNSServiceMaxDomainName] = "\0"; | |
158 | char nextLabel[256] = "\0"; | |
159 | char * buffer = (char *)replyDomain; | |
160 | ||
161 | while (*buffer) { | |
162 | buffer = (char *)GetNextLabel(buffer, nextLabel); | |
163 | strcat(decodedDomainString, nextLabel); | |
164 | strcat(decodedDomainString, "."); | |
165 | } | |
166 | ||
167 | // Remove trailing dot from domain name. | |
168 | decodedDomainString[strlen(decodedDomainString)-1] = '\0'; | |
169 | ||
170 | domainString = [[[NSString alloc] initWithUTF8String:(const char *)decodedDomainString] autorelease]; | |
171 | ||
172 | if (enumType & kDNSServiceFlagsRegistrationDomains) { | |
173 | domainArray = [me registrationDataSource]; | |
174 | domainComboBox = [me regDomainsComboBox]; | |
175 | currentDomain = [me currentRegDomain]; | |
176 | } else { | |
177 | domainArray = [me browseDataSource]; | |
178 | domainComboBox = [me browseDomainsComboBox]; | |
179 | defaultBrowseDomainsArray = [me defaultBrowseDomainsArray]; | |
180 | } | |
181 | ||
182 | if (flags & kDNSServiceFlagsAdd) { | |
183 | [domainArray removeObject:domainString]; // How can I check if an object is in the array? | |
184 | [domainArray addObject:domainString]; | |
185 | if ((flags & kDNSServiceFlagsDefault) && (enumType & kDNSServiceFlagsRegistrationDomains)) { | |
186 | [me setDefaultRegDomain:domainString]; | |
187 | if ([[domainComboBox stringValue] length] == 0) [domainComboBox setStringValue:domainString]; | |
188 | } else if ((flags & kDNSServiceFlagsDefault) && !(enumType & kDNSServiceFlagsRegistrationDomains)) { | |
189 | [defaultBrowseDomainsArray removeObject:domainString]; | |
190 | [defaultBrowseDomainsArray addObject:domainString]; | |
191 | } | |
192 | } | |
193 | ||
194 | if (moreComing == NO) { | |
195 | [domainArray sortUsingFunction:MyArrayCompareFunction context:nil]; | |
196 | [domainComboBox reloadData]; | |
197 | } | |
198 | } | |
199 | ||
200 | ||
67c8f8a1 | 201 | static void |
7cb34e5c A |
202 | browseDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, |
203 | DNSServiceErrorType errorCode, const char *replyDomain, void *context) | |
204 | { | |
205 | ServiceDomainEnumReply(sdRef, flags, interfaceIndex, errorCode, replyDomain, context, kDNSServiceFlagsBrowseDomains); | |
206 | } | |
207 | ||
208 | ||
67c8f8a1 | 209 | static void |
7cb34e5c A |
210 | registrationDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, |
211 | DNSServiceErrorType errorCode, const char *replyDomain, void *context) | |
212 | { | |
213 | ServiceDomainEnumReply(sdRef, flags, interfaceIndex, errorCode, replyDomain, context, kDNSServiceFlagsRegistrationDomains); | |
214 | } | |
215 | ||
216 | ||
217 | ||
218 | static void | |
219 | MyDNSServiceCleanUp(MyDNSServiceState * query) | |
220 | { | |
221 | /* Remove the CFRunLoopSource from the current run loop. */ | |
222 | CFRunLoopRemoveSource(CFRunLoopGetCurrent(), query->source, kCFRunLoopCommonModes); | |
223 | CFRelease(query->source); | |
224 | ||
225 | /* Invalidate the CFSocket. */ | |
226 | CFSocketInvalidate(query->socket); | |
227 | CFRelease(query->socket); | |
228 | ||
229 | /* Workaround that gives time to CFSocket's select thread so it can remove the socket from its FD set | |
230 | before we close the socket by calling DNSServiceRefDeallocate. <rdar://problem/3585273> */ | |
231 | usleep(1000); | |
232 | ||
233 | /* Terminate the connection with the mDNSResponder daemon, which cancels the query. */ | |
234 | DNSServiceRefDeallocate(query->service); | |
235 | } | |
236 | ||
237 | ||
238 | ||
239 | static void | |
240 | MySocketReadCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void * data, void * info) | |
241 | { | |
242 | #pragma unused(s) | |
243 | #pragma unused(type) | |
244 | #pragma unused(address) | |
245 | #pragma unused(data) | |
246 | ||
247 | DNSServiceErrorType err; | |
248 | ||
249 | MyDNSServiceState * query = (MyDNSServiceState *)info; // context passed in to CFSocketCreateWithNative(). | |
250 | assert(query != NULL); | |
251 | ||
252 | /* Read a reply from the mDNSResponder. */ | |
253 | err= DNSServiceProcessResult(query->service); | |
254 | if (err != kDNSServiceErr_NoError) { | |
255 | fprintf(stderr, "DNSServiceProcessResult returned %d\n", err); | |
256 | ||
257 | /* Terminate the query operation and release the CFRunLoopSource and CFSocket. */ | |
258 | MyDNSServiceCleanUp(query); | |
259 | } | |
260 | } | |
261 | ||
262 | ||
263 | ||
67c8f8a1 | 264 | static void |
7cb34e5c A |
265 | MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) |
266 | { | |
267 | CFSocketNativeHandle sock; | |
268 | CFOptionFlags sockFlags; | |
269 | CFSocketContext context = { 0, query, NULL, NULL, NULL }; // Use MyDNSServiceState as context data. | |
270 | ||
271 | /* Access the underlying Unix domain socket to communicate with the mDNSResponder daemon. */ | |
272 | sock = DNSServiceRefSockFD(query->service); | |
273 | assert(sock != -1); | |
274 | ||
275 | /* Create a CFSocket using the Unix domain socket. */ | |
276 | query->socket = CFSocketCreateWithNative(NULL, sock, kCFSocketReadCallBack, MySocketReadCallback, &context); | |
277 | assert(query->socket != NULL); | |
278 | ||
279 | /* Prevent CFSocketInvalidate from closing DNSServiceRef's socket. */ | |
280 | sockFlags = CFSocketGetSocketFlags(query->socket); | |
281 | CFSocketSetSocketFlags(query->socket, sockFlags & (~kCFSocketCloseOnInvalidate)); | |
282 | ||
283 | /* Create a CFRunLoopSource from the CFSocket. */ | |
284 | query->source = CFSocketCreateRunLoopSource(NULL, query->socket, 0); | |
285 | assert(query->source != NULL); | |
286 | ||
287 | /* Add the CFRunLoopSource to the current run loop. */ | |
288 | CFRunLoopAddSource(CFRunLoopGetCurrent(), query->source, kCFRunLoopCommonModes); | |
289 | } | |
290 | ||
291 | ||
292 | ||
293 | -(void)updateStatusImageView | |
294 | { | |
295 | int value = [self statusForHostName:currentHostName]; | |
296 | if (value == 0) [statusImageView setImage:successImage]; | |
297 | else if (value > 0) [statusImageView setImage:inprogressImage]; | |
298 | else [statusImageView setImage:failureImage]; | |
299 | } | |
300 | ||
301 | ||
302 | - (void)watchForPreferenceChanges | |
303 | { | |
304 | SCDynamicStoreContext context = { 0, self, NULL, NULL, NULL }; | |
305 | SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("watchForPreferenceChanges"), NetworkChanged, &context); | |
306 | CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |
307 | CFRunLoopSourceRef rls; | |
308 | ||
309 | assert(store != NULL); | |
310 | assert(keys != NULL); | |
311 | ||
312 | CFArrayAppendValue(keys, SC_DYNDNS_STATE_KEY); | |
313 | CFArrayAppendValue(keys, SC_DYNDNS_SETUP_KEY); | |
314 | ||
315 | (void)SCDynamicStoreSetNotificationKeys(store, keys, NULL); | |
316 | ||
317 | rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0); | |
318 | assert(rls != NULL); | |
319 | ||
320 | CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopCommonModes); | |
321 | ||
322 | CFRelease(keys); | |
323 | CFRelease(store); | |
324 | } | |
325 | ||
326 | ||
327 | -(int)statusForHostName:(NSString * )domain | |
328 | { | |
329 | SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("statusForHostName"), NULL, NULL); | |
330 | NSString *lowercaseDomain = [domain lowercaseString]; | |
331 | int status = 1; | |
332 | ||
333 | assert(store != NULL); | |
334 | ||
335 | NSDictionary *dynamicDNS = (NSDictionary *)SCDynamicStoreCopyValue(store, SC_DYNDNS_STATE_KEY); | |
336 | if (dynamicDNS) { | |
337 | NSDictionary *hostNames = [dynamicDNS objectForKey:(NSString *)SC_DYNDNS_HOSTNAMES_KEY]; | |
338 | NSDictionary *infoDict = [hostNames objectForKey:lowercaseDomain]; | |
339 | if (infoDict) status = [[infoDict objectForKey:(NSString*)SC_DYNDNS_STATUS_KEY] intValue]; | |
340 | CFRelease(dynamicDNS); | |
341 | } | |
342 | CFRelease(store); | |
343 | ||
344 | return status; | |
345 | } | |
346 | ||
347 | ||
348 | - (void)startDomainBrowsing | |
349 | { | |
350 | DNSServiceFlags flags; | |
351 | OSStatus err = noErr; | |
352 | ||
353 | flags = kDNSServiceFlagsRegistrationDomains; | |
354 | err = DNSServiceEnumerateDomains(®Query.service, flags, 0, registrationDomainReply, (void *)self); | |
355 | if (err == kDNSServiceErr_NoError) MyDNSServiceAddServiceToRunLoop(®Query); | |
356 | ||
357 | flags = kDNSServiceFlagsBrowseDomains; | |
358 | err = DNSServiceEnumerateDomains(&browseQuery.service, flags, 0, browseDomainReply, (void *)self); | |
359 | if (err == kDNSServiceErr_NoError) MyDNSServiceAddServiceToRunLoop(&browseQuery); | |
360 | } | |
361 | ||
362 | ||
363 | -(void)readPreferences | |
364 | { | |
365 | NSDictionary *origDict; | |
366 | NSArray *regDomainArray; | |
367 | NSArray *hostArray; | |
368 | ||
369 | if (currentRegDomain) [currentRegDomain release]; | |
370 | if (currentBrowseDomainsArray) [currentBrowseDomainsArray release]; | |
371 | if (currentHostName) [currentHostName release]; | |
372 | ||
373 | SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("com.apple.preference.bonjour"), NULL, NULL); | |
374 | origDict = (NSDictionary *)SCDynamicStoreCopyValue(store, SC_DYNDNS_SETUP_KEY); | |
375 | ||
376 | regDomainArray = [origDict objectForKey:(NSString *)SC_DYNDNS_REGDOMAINS_KEY]; | |
377 | if (regDomainArray && [regDomainArray count] > 0) { | |
378 | currentRegDomain = [[[regDomainArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY] copy]; | |
379 | currentWideAreaState = [[[regDomainArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_ENABLED_KEY] intValue]; | |
380 | } else { | |
381 | currentRegDomain = [[NSString alloc] initWithString:@""]; | |
382 | currentWideAreaState = NO; | |
383 | } | |
384 | ||
385 | currentBrowseDomainsArray = [[origDict objectForKey:(NSString *)SC_DYNDNS_BROWSEDOMAINS_KEY] retain]; | |
386 | ||
387 | hostArray = [origDict objectForKey:(NSString *)SC_DYNDNS_HOSTNAMES_KEY]; | |
388 | if (hostArray && [hostArray count] > 0) { | |
389 | currentHostName = [[[hostArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY] copy]; | |
390 | } else { | |
391 | currentHostName = [[NSString alloc] initWithString:@""]; | |
392 | } | |
393 | ||
394 | [origDict release]; | |
395 | CFRelease(store); | |
396 | } | |
397 | ||
398 | ||
399 | - (void)tableViewSelectionDidChange:(NSNotification *)notification; | |
400 | { | |
401 | [removeBrowseDomainButton setEnabled:[[notification object] numberOfSelectedRows]]; | |
402 | } | |
403 | ||
404 | ||
405 | - (void)setBrowseDomainsComboBox; | |
406 | { | |
407 | NSString * domain = nil; | |
408 | ||
409 | if ([defaultBrowseDomainsArray count] > 0) { | |
410 | NSEnumerator * arrayEnumerator = [defaultBrowseDomainsArray objectEnumerator]; | |
67c8f8a1 | 411 | while ((domain = [arrayEnumerator nextObject]) != NULL) { |
7cb34e5c A |
412 | if ([self domainAlreadyInList:domain] == NO) break; |
413 | } | |
414 | } | |
415 | if (domain) [browseDomainsComboBox setStringValue:domain]; | |
416 | else [browseDomainsComboBox setStringValue:@""]; | |
417 | } | |
418 | ||
419 | ||
420 | - (IBAction)addBrowseDomainClicked:(id)sender; | |
421 | { | |
422 | [self setBrowseDomainsComboBox]; | |
423 | ||
424 | [NSApp beginSheet:addBrowseDomainWindow modalForWindow:mainWindow modalDelegate:self | |
425 | didEndSelector:@selector(addBrowseDomainSheetDidEnd:returnCode:contextInfo:) contextInfo:sender]; | |
426 | ||
427 | [browseDomainList deselectAll:sender]; | |
428 | [self updateApplyButtonState]; | |
429 | } | |
430 | ||
431 | ||
432 | - (IBAction)removeBrowseDomainClicked:(id)sender; | |
433 | { | |
67c8f8a1 | 434 | (void)sender; // Unused |
7cb34e5c A |
435 | int selectedBrowseDomain = [browseDomainList selectedRow]; |
436 | [browseDomainsArray removeObjectAtIndex:selectedBrowseDomain]; | |
437 | [browseDomainList reloadData]; | |
438 | [self updateApplyButtonState]; | |
439 | } | |
440 | ||
441 | ||
442 | - (IBAction)enableBrowseDomainClicked:(id)sender; | |
443 | { | |
444 | NSTableView *tableView = sender; | |
445 | NSMutableDictionary *browseDomainDict; | |
446 | int value; | |
447 | ||
448 | browseDomainDict = [[browseDomainsArray objectAtIndex:[tableView clickedRow]] mutableCopy]; | |
449 | value = [[browseDomainDict objectForKey:(NSString *)SC_DYNDNS_ENABLED_KEY] intValue]; | |
450 | [browseDomainDict setObject:[[[NSNumber alloc] initWithInt:(!value)] autorelease] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY]; | |
451 | [browseDomainsArray replaceObjectAtIndex:[tableView clickedRow] withObject:browseDomainDict]; | |
452 | [tableView reloadData]; | |
453 | [self updateApplyButtonState]; | |
454 | } | |
455 | ||
456 | ||
457 | ||
32bb7e43 | 458 | - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView; |
7cb34e5c | 459 | { |
67c8f8a1 | 460 | (void)tableView; // Unused |
7cb34e5c A |
461 | int numberOfRows = 0; |
462 | ||
463 | if (browseDomainsArray) { | |
464 | numberOfRows = [browseDomainsArray count]; | |
465 | } | |
466 | return numberOfRows; | |
467 | } | |
468 | ||
469 | ||
67c8f8a1 | 470 | - (void)tabView:(NSTabView *)xtabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem; |
7cb34e5c | 471 | { |
67c8f8a1 A |
472 | (void)xtabView; // Unused |
473 | (void)tabViewItem; // Unused | |
7cb34e5c A |
474 | [browseDomainList deselectAll:self]; |
475 | [mainWindow makeFirstResponder:nil]; | |
476 | } | |
477 | ||
478 | ||
32bb7e43 | 479 | - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row; |
7cb34e5c | 480 | { |
67c8f8a1 | 481 | (void)tableView; // Unused |
7cb34e5c A |
482 | NSDictionary *browseDomainDict; |
483 | id value = nil; | |
484 | ||
485 | if (browseDomainsArray) { | |
486 | browseDomainDict = [browseDomainsArray objectAtIndex:row]; | |
487 | if (browseDomainDict) { | |
488 | if ([[tableColumn identifier] isEqualTo:(NSString *)SC_DYNDNS_ENABLED_KEY]) { | |
489 | value = [browseDomainDict objectForKey:(NSString *)SC_DYNDNS_ENABLED_KEY]; | |
490 | } else if ([[tableColumn identifier] isEqualTo:(NSString *)SC_DYNDNS_DOMAIN_KEY]) { | |
491 | value = [browseDomainDict objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY]; | |
492 | } | |
493 | } | |
494 | } | |
495 | return value; | |
496 | } | |
497 | ||
498 | ||
499 | - (void)setupInitialValues | |
500 | { | |
501 | [self readPreferences]; | |
502 | ||
503 | if (currentHostName) { | |
504 | [hostName setStringValue:currentHostName]; | |
505 | [self updateStatusImageView]; | |
506 | } | |
507 | ||
508 | if (browseDomainsArray) { | |
509 | [browseDomainsArray release]; | |
510 | browseDomainsArray = nil; | |
511 | } | |
512 | ||
513 | if (currentBrowseDomainsArray) { | |
514 | browseDomainsArray = [currentBrowseDomainsArray mutableCopy]; | |
515 | if (browseDomainsArray) { | |
516 | [browseDomainsArray sortUsingFunction:MyDomainArrayCompareFunction context:nil]; | |
517 | if ([browseDomainsArray isEqualToArray:currentBrowseDomainsArray] == NO) { | |
518 | OSStatus err = WriteBrowseDomain((CFDataRef)[self dataForDomainArray:browseDomainsArray]); | |
519 | if (err != noErr) NSLog(@"WriteBrowseDomain returned %d\n", err); | |
520 | [currentBrowseDomainsArray release]; | |
521 | currentBrowseDomainsArray = [browseDomainsArray copy]; | |
522 | } | |
523 | } | |
524 | } else { | |
525 | browseDomainsArray = nil; | |
526 | } | |
527 | [browseDomainList reloadData]; | |
528 | ||
529 | if (currentRegDomain && ([currentRegDomain length] > 0)) { | |
530 | [regDomainsComboBox setStringValue:currentRegDomain]; | |
531 | [registrationDataSource removeObject:currentRegDomain]; | |
532 | [registrationDataSource addObject:currentRegDomain]; | |
533 | [registrationDataSource sortUsingFunction:MyArrayCompareFunction context:nil]; | |
534 | [regDomainsComboBox reloadData]; | |
535 | } | |
536 | ||
537 | if (currentWideAreaState) { | |
538 | [self toggleWideAreaBonjour:YES]; | |
539 | } else { | |
540 | [self toggleWideAreaBonjour:NO]; | |
541 | } | |
542 | ||
543 | if (hostNameSharedSecretValue) { | |
544 | [hostNameSharedSecretValue release]; | |
545 | hostNameSharedSecretValue = nil; | |
546 | } | |
547 | ||
548 | if (regSharedSecretValue) { | |
549 | [regSharedSecretValue release]; | |
550 | regSharedSecretValue = nil; | |
551 | } | |
552 | ||
553 | [self updateApplyButtonState]; | |
554 | [mainWindow makeFirstResponder:nil]; | |
555 | [browseDomainList deselectAll:self]; | |
556 | [removeBrowseDomainButton setEnabled:NO]; | |
557 | } | |
558 | ||
559 | ||
560 | ||
561 | - (void)awakeFromNib | |
562 | { | |
563 | OSStatus err; | |
564 | ||
565 | prefsNeedUpdating = NO; | |
566 | toolInstalled = NO; | |
567 | browseDomainListEnabled = NO; | |
568 | defaultRegDomain = nil; | |
569 | currentRegDomain = nil; | |
570 | currentBrowseDomainsArray = nil; | |
571 | currentHostName = nil; | |
572 | hostNameSharedSecretValue = nil; | |
573 | regSharedSecretValue = nil; | |
574 | browseDomainsArray = nil; | |
575 | justStartedEditing = YES; | |
576 | currentWideAreaState = NO; | |
577 | NSString *successPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"success" ofType:@"tiff"]; | |
578 | NSString *inprogressPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"inprogress" ofType:@"tiff"]; | |
579 | NSString *failurePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"failure" ofType:@"tiff"]; | |
580 | ||
581 | registrationDataSource = [[NSMutableArray alloc] init]; | |
582 | browseDataSource = [[NSMutableArray alloc] init]; | |
583 | defaultBrowseDomainsArray = [[NSMutableArray alloc] init]; | |
584 | successImage = [[NSImage alloc] initWithContentsOfFile:successPath]; | |
585 | inprogressImage = [[NSImage alloc] initWithContentsOfFile:inprogressPath]; | |
586 | failureImage = [[NSImage alloc] initWithContentsOfFile:failurePath]; | |
587 | ||
588 | [tabView selectFirstTabViewItem:self]; | |
589 | [self setupInitialValues]; | |
590 | [self startDomainBrowsing]; | |
591 | [self watchForPreferenceChanges]; | |
592 | ||
7cb34e5c A |
593 | InitConfigAuthority(); |
594 | err = EnsureToolInstalled(); | |
595 | if (err == noErr) toolInstalled = YES; | |
32bb7e43 | 596 | else { long int tmp = err; fprintf(stderr, "EnsureToolInstalled returned %ld\n", tmp); } |
7cb34e5c A |
597 | |
598 | } | |
599 | ||
600 | ||
601 | - (IBAction)closeMyCustomSheet:(id)sender | |
602 | { | |
603 | BOOL result = [sender isEqualTo:browseOKButton] || [sender isEqualTo:secretOKButton]; | |
604 | ||
605 | if (result) [NSApp endSheet:[sender window] returnCode:NSOKButton]; | |
606 | else [NSApp endSheet:[sender window] returnCode:NSCancelButton]; | |
607 | } | |
608 | ||
609 | ||
610 | - (void)sharedSecretSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo | |
611 | { | |
612 | NSButton * button = (NSButton *)contextInfo; | |
613 | [sheet orderOut:self]; | |
614 | [self enableControls]; | |
615 | ||
616 | if (returnCode == NSOKButton) { | |
617 | if ([button isEqualTo:hostNameSharedSecretButton]) { | |
618 | hostNameSharedSecretName = [[NSString alloc] initWithString:[sharedSecretName stringValue]]; | |
619 | hostNameSharedSecretValue = [[NSString alloc] initWithString:[sharedSecretValue stringValue]]; | |
620 | } else { | |
621 | regSharedSecretName = [[NSString alloc] initWithString:[sharedSecretName stringValue]]; | |
622 | regSharedSecretValue = [[NSString alloc] initWithString:[sharedSecretValue stringValue]]; | |
623 | } | |
624 | [self updateApplyButtonState]; | |
625 | } | |
626 | [sharedSecretValue setStringValue:@""]; | |
627 | } | |
628 | ||
629 | ||
630 | - (BOOL)domainAlreadyInList:(NSString *)domainString | |
631 | { | |
632 | if (browseDomainsArray) { | |
633 | NSDictionary *domainDict; | |
634 | NSString *domainName; | |
635 | NSEnumerator *arrayEnumerator = [browseDomainsArray objectEnumerator]; | |
67c8f8a1 | 636 | while ((domainDict = [arrayEnumerator nextObject]) != NULL) { |
7cb34e5c A |
637 | domainName = [domainDict objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY]; |
638 | if ([domainString caseInsensitiveCompare:domainName] == NSOrderedSame) return YES; | |
639 | } | |
640 | } | |
641 | return NO; | |
642 | } | |
643 | ||
644 | ||
645 | - (NSString *)trimCharactersFromDomain:(NSString *)domain | |
646 | { | |
647 | NSMutableCharacterSet * trimSet = [[[NSCharacterSet whitespaceCharacterSet] mutableCopy] autorelease]; | |
648 | [trimSet formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]]; | |
649 | return [domain stringByTrimmingCharactersInSet:trimSet]; | |
650 | } | |
651 | ||
652 | ||
653 | - (void)addBrowseDomainSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo | |
654 | { | |
67c8f8a1 | 655 | (void)contextInfo; // Unused |
7cb34e5c A |
656 | [sheet orderOut:self]; |
657 | [self enableControls]; | |
658 | ||
659 | if (returnCode == NSOKButton) { | |
660 | NSString * newBrowseDomainString = [self trimCharactersFromDomain:[browseDomainsComboBox stringValue]]; | |
661 | NSMutableDictionary *newBrowseDomainDict; | |
662 | ||
663 | if (browseDomainsArray == nil) browseDomainsArray = [[NSMutableArray alloc] initWithCapacity:0]; | |
664 | if ([self domainAlreadyInList:newBrowseDomainString] == NO) { | |
665 | newBrowseDomainDict = [[[NSMutableDictionary alloc] initWithCapacity:2] autorelease]; | |
666 | ||
667 | [newBrowseDomainDict setObject:newBrowseDomainString forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY]; | |
668 | [newBrowseDomainDict setObject:[[[NSNumber alloc] initWithBool:YES] autorelease] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY]; | |
669 | ||
670 | [browseDomainsArray addObject:newBrowseDomainDict]; | |
671 | [browseDomainsArray sortUsingFunction:MyDomainArrayCompareFunction context:nil]; | |
672 | [browseDomainList reloadData]; | |
673 | [self updateApplyButtonState]; | |
674 | } | |
675 | } | |
676 | } | |
677 | ||
678 | ||
679 | -(void)validateTextFields | |
680 | { | |
681 | [hostName validateEditing]; | |
682 | [browseDomainsComboBox validateEditing]; | |
683 | [regDomainsComboBox validateEditing]; | |
684 | } | |
685 | ||
686 | ||
687 | - (IBAction)changeButtonPressed:(id)sender | |
688 | { | |
689 | NSString * keyName; | |
690 | ||
691 | [self disableControls]; | |
692 | [self validateTextFields]; | |
693 | [mainWindow makeFirstResponder:nil]; | |
694 | [browseDomainList deselectAll:sender]; | |
695 | ||
696 | if ([sender isEqualTo:hostNameSharedSecretButton]) { | |
697 | if (hostNameSharedSecretValue) { | |
698 | [sharedSecretValue setStringValue:hostNameSharedSecretValue]; | |
67c8f8a1 | 699 | } else if ((keyName = [self sharedSecretKeyName:[hostName stringValue]]) != NULL) { |
7cb34e5c A |
700 | [sharedSecretName setStringValue:keyName]; |
701 | [sharedSecretValue setStringValue:@"****************"]; | |
702 | } else { | |
703 | [sharedSecretName setStringValue:[hostName stringValue]]; | |
704 | [sharedSecretValue setStringValue:@""]; | |
705 | } | |
706 | ||
707 | } else { | |
708 | if (regSharedSecretValue) { | |
709 | [sharedSecretValue setStringValue:regSharedSecretValue]; | |
67c8f8a1 | 710 | } else if ((keyName = [self sharedSecretKeyName:[regDomainsComboBox stringValue]]) != NULL) { |
7cb34e5c A |
711 | [sharedSecretName setStringValue:keyName]; |
712 | [sharedSecretValue setStringValue:@"****************"]; | |
713 | } else { | |
714 | [sharedSecretName setStringValue:[regDomainsComboBox stringValue]]; | |
715 | [sharedSecretValue setStringValue:@""]; | |
716 | } | |
717 | } | |
718 | ||
719 | [sharedSecretWindow resignFirstResponder]; | |
720 | ||
721 | if ([[sharedSecretName stringValue] length] > 0) [sharedSecretWindow makeFirstResponder:sharedSecretValue]; | |
722 | else [sharedSecretWindow makeFirstResponder:sharedSecretName]; | |
723 | ||
724 | [NSApp beginSheet:sharedSecretWindow modalForWindow:mainWindow modalDelegate:self | |
725 | didEndSelector:@selector(sharedSecretSheetDidEnd:returnCode:contextInfo:) contextInfo:sender]; | |
726 | } | |
727 | ||
728 | ||
729 | - (IBAction)wideAreaCheckBoxChanged:(id)sender | |
730 | { | |
731 | [self toggleWideAreaBonjour:[sender state]]; | |
732 | [self updateApplyButtonState]; | |
733 | [mainWindow makeFirstResponder:nil]; | |
734 | } | |
735 | ||
736 | ||
737 | - (void)updateApplyButtonState | |
738 | { | |
739 | NSString *hostNameString = [hostName stringValue]; | |
740 | NSString *regDomainString = [regDomainsComboBox stringValue]; | |
741 | ||
742 | NSComparisonResult hostNameResult = [hostNameString compare:currentHostName]; | |
743 | NSComparisonResult regDomainResult = [regDomainString compare:currentRegDomain]; | |
744 | ||
745 | if ((currentHostName && (hostNameResult != NSOrderedSame)) || | |
746 | (currentRegDomain && (regDomainResult != NSOrderedSame) && ([wideAreaCheckBox state])) || | |
747 | (currentHostName == nil && ([hostNameString length]) > 0) || | |
748 | (currentRegDomain == nil && ([regDomainString length]) > 0) || | |
749 | (currentWideAreaState != [wideAreaCheckBox state]) || | |
750 | (hostNameSharedSecretValue != nil) || | |
751 | (regSharedSecretValue != nil) || | |
752 | (browseDomainsArray && [browseDomainsArray isEqualToArray:currentBrowseDomainsArray] == NO)) | |
753 | { | |
754 | [self enableApplyButton]; | |
755 | } else { | |
756 | [self disableApplyButton]; | |
757 | } | |
758 | } | |
759 | ||
760 | ||
761 | ||
762 | - (void)controlTextDidChange:(NSNotification *)notification; | |
763 | { | |
67c8f8a1 | 764 | (void)notification; // Unused |
7cb34e5c A |
765 | [self updateApplyButtonState]; |
766 | } | |
767 | ||
768 | ||
769 | ||
770 | - (IBAction)comboAction:(id)sender; | |
771 | { | |
67c8f8a1 | 772 | (void)sender; // Unused |
7cb34e5c A |
773 | [self updateApplyButtonState]; |
774 | } | |
775 | ||
776 | ||
030b743d | 777 | - (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)ind |
7cb34e5c A |
778 | { |
779 | NSString *domain = nil; | |
030b743d A |
780 | if ([aComboBox isEqualTo:browseDomainsComboBox]) domain = [browseDataSource objectAtIndex:ind]; |
781 | else if ([aComboBox isEqualTo:regDomainsComboBox]) domain = [registrationDataSource objectAtIndex:ind]; | |
7cb34e5c A |
782 | return domain; |
783 | } | |
784 | ||
785 | ||
786 | ||
787 | - (int)numberOfItemsInComboBox:(NSComboBox *)aComboBox | |
788 | { | |
789 | int count = 0; | |
790 | if ([aComboBox isEqualTo:browseDomainsComboBox]) count = [browseDataSource count]; | |
791 | else if ([aComboBox isEqualTo:regDomainsComboBox]) count = [registrationDataSource count]; | |
792 | return count; | |
793 | } | |
794 | ||
795 | ||
796 | - (NSMutableArray *)browseDataSource | |
797 | { | |
798 | return browseDataSource; | |
799 | } | |
800 | ||
801 | ||
802 | - (NSMutableArray *)registrationDataSource | |
803 | { | |
804 | return registrationDataSource; | |
805 | } | |
806 | ||
807 | ||
808 | - (NSComboBox *)browseDomainsComboBox | |
809 | { | |
810 | return browseDomainsComboBox; | |
811 | } | |
812 | ||
813 | ||
814 | - (NSComboBox *)regDomainsComboBox | |
815 | { | |
816 | return regDomainsComboBox; | |
817 | } | |
818 | ||
819 | ||
820 | - (NSString *)currentRegDomain | |
821 | { | |
822 | return currentRegDomain; | |
823 | } | |
824 | ||
825 | ||
826 | - (NSMutableArray *)defaultBrowseDomainsArray | |
827 | { | |
828 | return defaultBrowseDomainsArray; | |
829 | } | |
830 | ||
831 | ||
832 | - (NSArray *)currentBrowseDomainsArray | |
833 | { | |
834 | return currentBrowseDomainsArray; | |
835 | } | |
836 | ||
837 | ||
838 | - (NSString *)currentHostName | |
839 | { | |
840 | return currentHostName; | |
841 | } | |
842 | ||
843 | ||
844 | - (NSString *)defaultRegDomain | |
845 | { | |
846 | return defaultRegDomain; | |
847 | } | |
848 | ||
849 | ||
850 | - (void)setDefaultRegDomain:(NSString *)domain | |
851 | { | |
852 | [defaultRegDomain release]; | |
853 | defaultRegDomain = domain; | |
854 | [defaultRegDomain retain]; | |
855 | } | |
856 | ||
857 | ||
858 | - (void)didSelect | |
859 | { | |
860 | [super didSelect]; | |
861 | mainWindow = [[self mainView] window]; | |
862 | } | |
863 | ||
864 | ||
865 | - (void)mainViewDidLoad | |
866 | { | |
867 | [comboAuthButton setString:"system.preferences"]; | |
868 | [comboAuthButton setDelegate:self]; | |
869 | [comboAuthButton updateStatus:nil]; | |
870 | [comboAuthButton setAutoupdate:YES]; | |
871 | } | |
872 | ||
873 | ||
874 | ||
875 | - (IBAction)applyClicked:(id)sender | |
876 | { | |
67c8f8a1 | 877 | (void)sender; // Unused |
7cb34e5c A |
878 | [self applyCurrentState]; |
879 | } | |
880 | ||
881 | ||
882 | - (void)applyCurrentState | |
883 | { | |
884 | [self validateTextFields]; | |
885 | ||
886 | if (toolInstalled == YES) { | |
887 | [self savePreferences]; | |
888 | [self disableApplyButton]; | |
889 | [mainWindow makeFirstResponder:nil]; | |
890 | } | |
891 | } | |
892 | ||
893 | ||
894 | - (void)enableApplyButton | |
895 | { | |
896 | [applyButton setEnabled:YES]; | |
897 | [revertButton setEnabled:YES]; | |
898 | prefsNeedUpdating = YES; | |
899 | } | |
900 | ||
901 | ||
902 | - (void)disableApplyButton | |
903 | { | |
904 | [applyButton setEnabled:NO]; | |
905 | [revertButton setEnabled:NO]; | |
906 | prefsNeedUpdating = NO; | |
907 | } | |
908 | ||
909 | ||
910 | - (void)toggleWideAreaBonjour:(BOOL)state | |
911 | { | |
912 | [wideAreaCheckBox setState:state]; | |
913 | [regDomainsComboBox setEnabled:state]; | |
914 | [registrationSharedSecretButton setEnabled:state]; | |
915 | } | |
916 | ||
917 | ||
918 | - (IBAction)revertClicked:(id)sender; | |
919 | { | |
920 | [self restorePreferences]; | |
921 | [browseDomainList deselectAll:sender]; | |
922 | [mainWindow makeFirstResponder:nil]; | |
923 | } | |
924 | ||
925 | ||
926 | - (void)restorePreferences | |
927 | { | |
928 | [self setupInitialValues]; | |
929 | } | |
930 | ||
931 | ||
932 | - (void)savePanelWillClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo | |
933 | { | |
67c8f8a1 | 934 | (void)sheet; // Unused |
7cb34e5c A |
935 | DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)contextInfo; |
936 | ||
937 | if (returnCode == NSAlertDefaultReturn) { | |
938 | [me applyCurrentState]; | |
939 | } else if (returnCode == NSAlertAlternateReturn ) { | |
940 | [me restorePreferences]; | |
941 | } | |
942 | ||
943 | [me enableControls]; | |
944 | [me replyToShouldUnselect:(returnCode != NSAlertOtherReturn)]; | |
945 | } | |
946 | ||
947 | ||
948 | -(SecKeychainItemRef)copyKeychainItemforDomain:(NSString *)domain | |
949 | { | |
950 | const char * serviceName = [domain UTF8String]; | |
951 | UInt32 type = 'ddns'; | |
952 | UInt32 typeLength = sizeof(type); | |
953 | ||
954 | SecKeychainAttribute attrs[] = { { kSecServiceItemAttr, strlen(serviceName), (char *)serviceName }, | |
955 | { kSecTypeItemAttr, typeLength, (UInt32 *)&type } }; | |
956 | ||
957 | SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs }; | |
958 | SecKeychainSearchRef searchRef; | |
959 | SecKeychainItemRef itemRef = NULL; | |
960 | OSStatus err; | |
961 | ||
962 | err = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributes, &searchRef); | |
963 | if (err == noErr) { | |
964 | err = SecKeychainSearchCopyNext(searchRef, &itemRef); | |
965 | if (err != noErr) itemRef = NULL; | |
966 | } | |
967 | return itemRef; | |
968 | } | |
969 | ||
970 | ||
971 | -(NSString *)sharedSecretKeyName:(NSString * )domain | |
972 | { | |
973 | SecKeychainItemRef itemRef = NULL; | |
974 | NSString *keyName = nil; | |
975 | OSStatus err; | |
976 | ||
977 | err = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); | |
978 | assert(err == noErr); | |
979 | ||
980 | itemRef = [self copyKeychainItemforDomain:[domain lowercaseString]]; | |
981 | if (itemRef) { | |
982 | UInt32 tags[1]; | |
983 | SecKeychainAttributeInfo attrInfo; | |
984 | SecKeychainAttributeList *attrList = NULL; | |
985 | SecKeychainAttribute attribute; | |
67c8f8a1 | 986 | unsigned int i; |
7cb34e5c A |
987 | |
988 | tags[0] = kSecAccountItemAttr; | |
989 | attrInfo.count = 1; | |
990 | attrInfo.tag = tags; | |
991 | attrInfo.format = NULL; | |
992 | ||
993 | err = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, &attrList, NULL, NULL); | |
994 | if (err == noErr) { | |
995 | for (i = 0; i < attrList->count; i++) { | |
996 | attribute = attrList->attr[i]; | |
997 | if (attribute.tag == kSecAccountItemAttr) { | |
998 | keyName = [[NSString alloc] initWithBytes:attribute.data length:attribute.length encoding:NSUTF8StringEncoding]; | |
999 | break; | |
1000 | } | |
1001 | } | |
1002 | if (attrList) (void)SecKeychainItemFreeAttributesAndData(attrList, NULL); | |
1003 | } | |
1004 | CFRelease(itemRef); | |
1005 | } | |
1006 | return keyName; | |
1007 | } | |
1008 | ||
1009 | ||
1010 | -(NSString *)domainForHostName:(NSString *)hostNameString | |
1011 | { | |
1012 | NSString * domainName = nil; | |
1013 | char text[64]; | |
1014 | char * ptr = NULL; | |
1015 | ||
1016 | ptr = (char *)[hostNameString UTF8String]; | |
1017 | if (ptr) { | |
1018 | ptr = (char *)GetNextLabel(ptr, text); | |
1019 | domainName = [[NSString alloc] initWithUTF8String:(const char *)ptr]; | |
1020 | } | |
1021 | return ([domainName autorelease]); | |
1022 | } | |
1023 | ||
1024 | ||
1025 | - (NSData *)dataForDomain:(NSString *)domainName isEnabled:(BOOL)enabled | |
1026 | { | |
1027 | NSMutableArray *domainsArray; | |
1028 | NSMutableDictionary *domainDict = nil; | |
1029 | ||
1030 | if (domainName && [domainName length] > 0) { | |
1031 | domainDict= [[[NSMutableDictionary alloc] initWithCapacity:2] autorelease]; | |
1032 | [domainDict setObject:domainName forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY]; | |
1033 | [domainDict setObject:[[[NSNumber alloc] initWithBool:enabled] autorelease] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY]; | |
1034 | } | |
1035 | domainsArray = [[[NSMutableArray alloc] initWithCapacity:1] autorelease]; | |
1036 | if (domainDict) [domainsArray addObject:domainDict]; | |
1037 | return [NSArchiver archivedDataWithRootObject:domainsArray]; | |
1038 | } | |
1039 | ||
1040 | ||
1041 | - (NSData *)dataForDomainArray:(NSArray *)domainArray | |
1042 | { | |
1043 | return [NSArchiver archivedDataWithRootObject:domainArray]; | |
1044 | } | |
1045 | ||
1046 | ||
1047 | - (NSData *)dataForSharedSecret:(NSString *)secret domain:(NSString *)domainName key:(NSString *)keyName | |
1048 | { | |
1049 | NSMutableDictionary *sharedSecretDict = [[[NSMutableDictionary alloc] initWithCapacity:3] autorelease]; | |
1050 | [sharedSecretDict setObject:secret forKey:(NSString *)SC_DYNDNS_SECRET_KEY]; | |
1051 | [sharedSecretDict setObject:[domainName lowercaseString] forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY]; | |
1052 | [sharedSecretDict setObject:keyName forKey:(NSString *)SC_DYNDNS_KEYNAME_KEY]; | |
1053 | return [NSArchiver archivedDataWithRootObject:sharedSecretDict]; | |
1054 | } | |
1055 | ||
1056 | ||
1057 | -(void)savePreferences | |
1058 | { | |
1059 | NSString *hostNameString = [hostName stringValue]; | |
1060 | NSString *browseDomainString = [browseDomainsComboBox stringValue]; | |
1061 | NSString *regDomainString = [regDomainsComboBox stringValue]; | |
1062 | NSString *tempHostNameSharedSecretName = hostNameSharedSecretName; | |
1063 | NSString *tempRegSharedSecretName = regSharedSecretName; | |
1064 | NSData *browseDomainData = nil; | |
1065 | BOOL regSecretWasSet = NO; | |
1066 | BOOL hostSecretWasSet = NO; | |
1067 | OSStatus err = noErr; | |
1068 | ||
1069 | hostNameString = [self trimCharactersFromDomain:hostNameString]; | |
1070 | browseDomainString = [self trimCharactersFromDomain:browseDomainString]; | |
1071 | regDomainString = [self trimCharactersFromDomain:regDomainString]; | |
1072 | tempHostNameSharedSecretName = [self trimCharactersFromDomain:tempHostNameSharedSecretName]; | |
1073 | tempRegSharedSecretName = [self trimCharactersFromDomain:tempRegSharedSecretName]; | |
1074 | ||
1075 | [hostName setStringValue:hostNameString]; | |
1076 | [regDomainsComboBox setStringValue:regDomainString]; | |
1077 | ||
1078 | // Convert Shared Secret account names to lowercase. | |
1079 | tempHostNameSharedSecretName = [tempHostNameSharedSecretName lowercaseString]; | |
1080 | tempRegSharedSecretName = [tempRegSharedSecretName lowercaseString]; | |
1081 | ||
1082 | // Save hostname shared secret. | |
1083 | if ([hostNameSharedSecretName length] > 0 && ([hostNameSharedSecretValue length] > 0)) { | |
1084 | SetKeyForDomain((CFDataRef)[self dataForSharedSecret:hostNameSharedSecretValue domain:hostNameString key:tempHostNameSharedSecretName]); | |
1085 | [hostNameSharedSecretValue release]; | |
1086 | hostNameSharedSecretValue = nil; | |
1087 | hostSecretWasSet = YES; | |
1088 | } | |
1089 | ||
1090 | // Save registration domain shared secret. | |
1091 | if (([regSharedSecretName length] > 0) && ([regSharedSecretValue length] > 0)) { | |
1092 | SetKeyForDomain((CFDataRef)[self dataForSharedSecret:regSharedSecretValue domain:regDomainString key:tempRegSharedSecretName]); | |
1093 | [regSharedSecretValue release]; | |
1094 | regSharedSecretValue = nil; | |
1095 | regSecretWasSet = YES; | |
1096 | } | |
1097 | ||
1098 | // Save hostname. | |
1099 | if ((currentHostName == NULL) || [currentHostName compare:hostNameString] != NSOrderedSame) { | |
1100 | err = WriteHostname((CFDataRef)[self dataForDomain:hostNameString isEnabled:YES]); | |
1101 | if (err != noErr) NSLog(@"WriteHostname returned %d\n", err); | |
1102 | currentHostName = [hostNameString copy]; | |
1103 | } else if (hostSecretWasSet) { | |
1104 | WriteHostname((CFDataRef)[self dataForDomain:@"" isEnabled:NO]); | |
1105 | usleep(200000); // Temporary hack | |
1106 | if ([currentHostName length] > 0) WriteHostname((CFDataRef)[self dataForDomain:(NSString *)currentHostName isEnabled:YES]); | |
1107 | } | |
1108 | ||
1109 | // Save browse domain. | |
1110 | if (browseDomainsArray && [browseDomainsArray isEqualToArray:currentBrowseDomainsArray] == NO) { | |
1111 | browseDomainData = [self dataForDomainArray:browseDomainsArray]; | |
1112 | err = WriteBrowseDomain((CFDataRef)browseDomainData); | |
1113 | if (err != noErr) NSLog(@"WriteBrowseDomain returned %d\n", err); | |
1114 | currentBrowseDomainsArray = [browseDomainsArray copy]; | |
1115 | } | |
1116 | ||
1117 | // Save registration domain. | |
1118 | if ((currentRegDomain == NULL) || ([currentRegDomain compare:regDomainString] != NSOrderedSame) || (currentWideAreaState != [wideAreaCheckBox state])) { | |
1119 | ||
1120 | err = WriteRegistrationDomain((CFDataRef)[self dataForDomain:regDomainString isEnabled:[wideAreaCheckBox state]]); | |
1121 | if (err != noErr) NSLog(@"WriteRegistrationDomain returned %d\n", err); | |
1122 | ||
1123 | if (currentRegDomain) CFRelease(currentRegDomain); | |
1124 | currentRegDomain = [regDomainString copy]; | |
1125 | ||
1126 | if ([currentRegDomain length] > 0) { | |
1127 | currentWideAreaState = [wideAreaCheckBox state]; | |
1128 | [registrationDataSource removeObject:regDomainString]; | |
1129 | [registrationDataSource addObject:currentRegDomain]; | |
1130 | [registrationDataSource sortUsingFunction:MyArrayCompareFunction context:nil]; | |
1131 | [regDomainsComboBox reloadData]; | |
1132 | } else { | |
1133 | currentWideAreaState = NO; | |
1134 | [self toggleWideAreaBonjour:NO]; | |
1135 | if (defaultRegDomain != nil) [regDomainsComboBox setStringValue:defaultRegDomain]; | |
1136 | } | |
1137 | } else if (regSecretWasSet) { | |
1138 | WriteRegistrationDomain((CFDataRef)[self dataForDomain:@"" isEnabled:NO]); | |
1139 | usleep(200000); // Temporary hack | |
1140 | if ([currentRegDomain length] > 0) WriteRegistrationDomain((CFDataRef)[self dataForDomain:currentRegDomain isEnabled:currentWideAreaState]); | |
1141 | } | |
1142 | } | |
1143 | ||
1144 | ||
1145 | - (NSPreferencePaneUnselectReply)shouldUnselect | |
1146 | { | |
1147 | #if 1 | |
1148 | if (prefsNeedUpdating == YES) { | |
1149 | ||
1150 | [self disableControls]; | |
1151 | ||
1152 | NSBeginAlertSheet( | |
1153 | @"Apply Configuration Changes?", | |
1154 | @"Apply", | |
1155 | @"Don't Apply", | |
1156 | @"Cancel", | |
1157 | mainWindow, | |
1158 | self, | |
1159 | @selector( savePanelWillClose:returnCode:contextInfo: ), | |
1160 | NULL, | |
1161 | (void *) self, // sender, | |
1162 | @"" ); | |
1163 | return NSUnselectLater; | |
1164 | } | |
1165 | #endif | |
1166 | ||
1167 | return NSUnselectNow; | |
1168 | } | |
1169 | ||
1170 | ||
1171 | -(void)disableControls | |
1172 | { | |
1173 | [hostName setEnabled:NO]; | |
1174 | [hostNameSharedSecretButton setEnabled:NO]; | |
1175 | [browseDomainsComboBox setEnabled:NO]; | |
1176 | [applyButton setEnabled:NO]; | |
1177 | [revertButton setEnabled:NO]; | |
1178 | [wideAreaCheckBox setEnabled:NO]; | |
1179 | [regDomainsComboBox setEnabled:NO]; | |
1180 | [registrationSharedSecretButton setEnabled:NO]; | |
1181 | [statusImageView setEnabled:NO]; | |
1182 | ||
1183 | browseDomainListEnabled = NO; | |
1184 | [browseDomainList deselectAll:self]; | |
1185 | [browseDomainList setEnabled:NO]; | |
1186 | ||
1187 | [addBrowseDomainButton setEnabled:NO]; | |
1188 | [removeBrowseDomainButton setEnabled:NO]; | |
1189 | } | |
1190 | ||
1191 | ||
32bb7e43 | 1192 | - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row; |
7cb34e5c | 1193 | { |
67c8f8a1 A |
1194 | (void)row; // Unused |
1195 | (void)tableView; // Unused | |
7cb34e5c A |
1196 | return browseDomainListEnabled; |
1197 | } | |
1198 | ||
1199 | ||
1200 | -(void)enableControls | |
1201 | { | |
1202 | [hostName setEnabled:YES]; | |
1203 | [hostNameSharedSecretButton setEnabled:YES]; | |
1204 | [browseDomainsComboBox setEnabled:YES]; | |
1205 | [wideAreaCheckBox setEnabled:YES]; | |
1206 | [registrationSharedSecretButton setEnabled:YES]; | |
1207 | [self toggleWideAreaBonjour:[wideAreaCheckBox state]]; | |
1208 | [statusImageView setEnabled:YES]; | |
1209 | [addBrowseDomainButton setEnabled:YES]; | |
1210 | ||
1211 | [browseDomainList setEnabled:YES]; | |
1212 | [browseDomainList deselectAll:self]; | |
1213 | browseDomainListEnabled = YES; | |
1214 | ||
1215 | [removeBrowseDomainButton setEnabled:[browseDomainList numberOfSelectedRows]]; | |
1216 | [applyButton setEnabled:prefsNeedUpdating]; | |
1217 | [revertButton setEnabled:prefsNeedUpdating]; | |
1218 | } | |
1219 | ||
1220 | ||
1221 | - (void)authorizationViewDidAuthorize:(SFAuthorizationView *)view | |
1222 | { | |
67c8f8a1 | 1223 | (void)view; // Unused |
7cb34e5c A |
1224 | [self enableControls]; |
1225 | } | |
1226 | ||
1227 | ||
1228 | - (void)authorizationViewDidDeauthorize:(SFAuthorizationView *)view | |
1229 | { | |
67c8f8a1 | 1230 | (void)view; // Unused |
7cb34e5c A |
1231 | [self disableControls]; |
1232 | } | |
1233 | ||
67c8f8a1 A |
1234 | @end |
1235 | ||
1236 | ||
1237 | // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion | |
1238 | // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4" | |
1239 | // To expand "version" to its value before making the string, use STRINGIFY(version) instead | |
1240 | #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s | |
1241 | #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) | |
1242 | ||
1243 | // NOT static -- otherwise the compiler may optimize it out | |
1244 | // The "@(#) " pattern is a special prefix the "what" command looks for | |
1245 | const char VersionString_SCCS[] = "@(#) Bonjour Preference Pane " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; | |
c9d2d929 | 1246 | |
32bb7e43 | 1247 | #if _BUILDING_XCODE_PROJECT_ |
67c8f8a1 A |
1248 | // If the process crashes, then this string will be magically included in the automatically-generated crash log |
1249 | const char *__crashreporter_info__ = VersionString_SCCS + 5; | |
1250 | asm(".desc ___crashreporter_info__, 0x10"); | |
32bb7e43 | 1251 | #endif |