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