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