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