]> git.saurik.com Git - apple/mdnsresponder.git/blame - mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
mDNSResponder-765.50.9.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
9f221bca 6 Copyright: (c) Copyright 2005-2011 Apple Inc. All rights reserved.
7cb34e5c 7
9f221bca 8 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
7cb34e5c
A
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
9f221bca 22 Apple Inc. may be used to endorse or promote products derived from the
7cb34e5c
A
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;
9f221bca 99 char decodedDomainString[kDNSServiceMaxDomainName] = "\0";
7cb34e5c
A
100 char nextLabel[256] = "\0";
101 char * buffer = (char *)replyDomain;
102
103 while (*buffer) {
104 buffer = (char *)GetNextLabel(buffer, nextLabel);
105 strcat(decodedDomainString, nextLabel);
106 strcat(decodedDomainString, ".");
107 }
108
109 // Remove trailing dot from domain name.
110 decodedDomainString[strlen(decodedDomainString)-1] = '\0';
111
112 domainString = [[[NSString alloc] initWithUTF8String:(const char *)decodedDomainString] autorelease];
113
114 if (enumType & kDNSServiceFlagsRegistrationDomains) {
115 domainArray = [me registrationDataSource];
116 domainComboBox = [me regDomainsComboBox];
7cb34e5c
A
117 } else {
118 domainArray = [me browseDataSource];
119 domainComboBox = [me browseDomainsComboBox];
120 defaultBrowseDomainsArray = [me defaultBrowseDomainsArray];
121 }
122
123 if (flags & kDNSServiceFlagsAdd) {
124 [domainArray removeObject:domainString]; // How can I check if an object is in the array?
125 [domainArray addObject:domainString];
126 if ((flags & kDNSServiceFlagsDefault) && (enumType & kDNSServiceFlagsRegistrationDomains)) {
127 [me setDefaultRegDomain:domainString];
128 if ([[domainComboBox stringValue] length] == 0) [domainComboBox setStringValue:domainString];
129 } else if ((flags & kDNSServiceFlagsDefault) && !(enumType & kDNSServiceFlagsRegistrationDomains)) {
130 [defaultBrowseDomainsArray removeObject:domainString];
131 [defaultBrowseDomainsArray addObject:domainString];
132 }
133 }
134
135 if (moreComing == NO) {
136 [domainArray sortUsingFunction:MyArrayCompareFunction context:nil];
137 [domainComboBox reloadData];
138 }
139}
140
141
67c8f8a1 142static void
7cb34e5c
A
143browseDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
144 DNSServiceErrorType errorCode, const char *replyDomain, void *context)
145{
146 ServiceDomainEnumReply(sdRef, flags, interfaceIndex, errorCode, replyDomain, context, kDNSServiceFlagsBrowseDomains);
147}
148
149
67c8f8a1 150static void
7cb34e5c
A
151registrationDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
152 DNSServiceErrorType errorCode, const char *replyDomain, void *context)
153{
154 ServiceDomainEnumReply(sdRef, flags, interfaceIndex, errorCode, replyDomain, context, kDNSServiceFlagsRegistrationDomains);
155}
156
157
158
159static void
160MyDNSServiceCleanUp(MyDNSServiceState * query)
161{
162 /* Remove the CFRunLoopSource from the current run loop. */
163 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), query->source, kCFRunLoopCommonModes);
164 CFRelease(query->source);
165
166 /* Invalidate the CFSocket. */
167 CFSocketInvalidate(query->socket);
168 CFRelease(query->socket);
169
170 /* Workaround that gives time to CFSocket's select thread so it can remove the socket from its FD set
171 before we close the socket by calling DNSServiceRefDeallocate. <rdar://problem/3585273> */
172 usleep(1000);
173
174 /* Terminate the connection with the mDNSResponder daemon, which cancels the query. */
175 DNSServiceRefDeallocate(query->service);
176}
177
178
179
180static void
181MySocketReadCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void * data, void * info)
182{
183 #pragma unused(s)
184 #pragma unused(type)
185 #pragma unused(address)
186 #pragma unused(data)
187
188 DNSServiceErrorType err;
189
190 MyDNSServiceState * query = (MyDNSServiceState *)info; // context passed in to CFSocketCreateWithNative().
191 assert(query != NULL);
192
193 /* Read a reply from the mDNSResponder. */
194 err= DNSServiceProcessResult(query->service);
195 if (err != kDNSServiceErr_NoError) {
196 fprintf(stderr, "DNSServiceProcessResult returned %d\n", err);
197
198 /* Terminate the query operation and release the CFRunLoopSource and CFSocket. */
199 MyDNSServiceCleanUp(query);
200 }
201}
202
203
204
67c8f8a1 205static void
7cb34e5c
A
206MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
207{
208 CFSocketNativeHandle sock;
209 CFOptionFlags sockFlags;
210 CFSocketContext context = { 0, query, NULL, NULL, NULL }; // Use MyDNSServiceState as context data.
211
212 /* Access the underlying Unix domain socket to communicate with the mDNSResponder daemon. */
213 sock = DNSServiceRefSockFD(query->service);
214 assert(sock != -1);
215
216 /* Create a CFSocket using the Unix domain socket. */
217 query->socket = CFSocketCreateWithNative(NULL, sock, kCFSocketReadCallBack, MySocketReadCallback, &context);
218 assert(query->socket != NULL);
219
220 /* Prevent CFSocketInvalidate from closing DNSServiceRef's socket. */
221 sockFlags = CFSocketGetSocketFlags(query->socket);
222 CFSocketSetSocketFlags(query->socket, sockFlags & (~kCFSocketCloseOnInvalidate));
223
224 /* Create a CFRunLoopSource from the CFSocket. */
225 query->source = CFSocketCreateRunLoopSource(NULL, query->socket, 0);
226 assert(query->source != NULL);
227
228 /* Add the CFRunLoopSource to the current run loop. */
229 CFRunLoopAddSource(CFRunLoopGetCurrent(), query->source, kCFRunLoopCommonModes);
230}
231
232
233
234-(void)updateStatusImageView
235{
236 int value = [self statusForHostName:currentHostName];
237 if (value == 0) [statusImageView setImage:successImage];
238 else if (value > 0) [statusImageView setImage:inprogressImage];
239 else [statusImageView setImage:failureImage];
240}
241
242
243- (void)watchForPreferenceChanges
244{
245 SCDynamicStoreContext context = { 0, self, NULL, NULL, NULL };
246 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("watchForPreferenceChanges"), NetworkChanged, &context);
247 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
248 CFRunLoopSourceRef rls;
249
250 assert(store != NULL);
251 assert(keys != NULL);
252
253 CFArrayAppendValue(keys, SC_DYNDNS_STATE_KEY);
254 CFArrayAppendValue(keys, SC_DYNDNS_SETUP_KEY);
255
256 (void)SCDynamicStoreSetNotificationKeys(store, keys, NULL);
257
258 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
259 assert(rls != NULL);
260
261 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopCommonModes);
9f221bca 262 CFRelease(rls);
7cb34e5c
A
263
264 CFRelease(keys);
265 CFRelease(store);
266}
267
268
269-(int)statusForHostName:(NSString * )domain
270{
271 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("statusForHostName"), NULL, NULL);
272 NSString *lowercaseDomain = [domain lowercaseString];
273 int status = 1;
274
275 assert(store != NULL);
276
277 NSDictionary *dynamicDNS = (NSDictionary *)SCDynamicStoreCopyValue(store, SC_DYNDNS_STATE_KEY);
278 if (dynamicDNS) {
279 NSDictionary *hostNames = [dynamicDNS objectForKey:(NSString *)SC_DYNDNS_HOSTNAMES_KEY];
280 NSDictionary *infoDict = [hostNames objectForKey:lowercaseDomain];
281 if (infoDict) status = [[infoDict objectForKey:(NSString*)SC_DYNDNS_STATUS_KEY] intValue];
282 CFRelease(dynamicDNS);
283 }
284 CFRelease(store);
285
286 return status;
287}
288
289
290- (void)startDomainBrowsing
291{
292 DNSServiceFlags flags;
293 OSStatus err = noErr;
294
295 flags = kDNSServiceFlagsRegistrationDomains;
296 err = DNSServiceEnumerateDomains(&regQuery.service, flags, 0, registrationDomainReply, (void *)self);
297 if (err == kDNSServiceErr_NoError) MyDNSServiceAddServiceToRunLoop(&regQuery);
298
299 flags = kDNSServiceFlagsBrowseDomains;
300 err = DNSServiceEnumerateDomains(&browseQuery.service, flags, 0, browseDomainReply, (void *)self);
301 if (err == kDNSServiceErr_NoError) MyDNSServiceAddServiceToRunLoop(&browseQuery);
302}
303
304
305-(void)readPreferences
306{
307 NSDictionary *origDict;
308 NSArray *regDomainArray;
309 NSArray *hostArray;
310
311 if (currentRegDomain) [currentRegDomain release];
312 if (currentBrowseDomainsArray) [currentBrowseDomainsArray release];
313 if (currentHostName) [currentHostName release];
314
315 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("com.apple.preference.bonjour"), NULL, NULL);
316 origDict = (NSDictionary *)SCDynamicStoreCopyValue(store, SC_DYNDNS_SETUP_KEY);
317
318 regDomainArray = [origDict objectForKey:(NSString *)SC_DYNDNS_REGDOMAINS_KEY];
319 if (regDomainArray && [regDomainArray count] > 0) {
320 currentRegDomain = [[[regDomainArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY] copy];
321 currentWideAreaState = [[[regDomainArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_ENABLED_KEY] intValue];
322 } else {
323 currentRegDomain = [[NSString alloc] initWithString:@""];
324 currentWideAreaState = NO;
325 }
326
327 currentBrowseDomainsArray = [[origDict objectForKey:(NSString *)SC_DYNDNS_BROWSEDOMAINS_KEY] retain];
328
329 hostArray = [origDict objectForKey:(NSString *)SC_DYNDNS_HOSTNAMES_KEY];
330 if (hostArray && [hostArray count] > 0) {
331 currentHostName = [[[hostArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY] copy];
332 } else {
333 currentHostName = [[NSString alloc] initWithString:@""];
334 }
335
9f221bca
A
336 if (origDict) CFRelease((CFDictionaryRef)origDict);
337 if (store) CFRelease(store);
7cb34e5c
A
338}
339
340
4a95efb2 341- (void)tableViewSelectionDidChange:(NSNotification *)notification
7cb34e5c
A
342{
343 [removeBrowseDomainButton setEnabled:[[notification object] numberOfSelectedRows]];
344}
345
346
4a95efb2 347- (void)setBrowseDomainsComboBox
7cb34e5c
A
348{
349 NSString * domain = nil;
350
351 if ([defaultBrowseDomainsArray count] > 0) {
352 NSEnumerator * arrayEnumerator = [defaultBrowseDomainsArray objectEnumerator];
67c8f8a1 353 while ((domain = [arrayEnumerator nextObject]) != NULL) {
7cb34e5c
A
354 if ([self domainAlreadyInList:domain] == NO) break;
355 }
356 }
357 if (domain) [browseDomainsComboBox setStringValue:domain];
358 else [browseDomainsComboBox setStringValue:@""];
359}
360
361
4a95efb2 362- (IBAction)addBrowseDomainClicked:(id)sender
7cb34e5c
A
363{
364 [self setBrowseDomainsComboBox];
365
366 [NSApp beginSheet:addBrowseDomainWindow modalForWindow:mainWindow modalDelegate:self
367 didEndSelector:@selector(addBrowseDomainSheetDidEnd:returnCode:contextInfo:) contextInfo:sender];
368
369 [browseDomainList deselectAll:sender];
370 [self updateApplyButtonState];
371}
372
373
4a95efb2 374- (IBAction)removeBrowseDomainClicked:(id)sender
7cb34e5c 375{
67c8f8a1 376 (void)sender; // Unused
7cb34e5c
A
377 int selectedBrowseDomain = [browseDomainList selectedRow];
378 [browseDomainsArray removeObjectAtIndex:selectedBrowseDomain];
379 [browseDomainList reloadData];
380 [self updateApplyButtonState];
381}
382
383
4a95efb2 384- (IBAction)enableBrowseDomainClicked:(id)sender
7cb34e5c
A
385{
386 NSTableView *tableView = sender;
387 NSMutableDictionary *browseDomainDict;
388 int value;
389
390 browseDomainDict = [[browseDomainsArray objectAtIndex:[tableView clickedRow]] mutableCopy];
391 value = [[browseDomainDict objectForKey:(NSString *)SC_DYNDNS_ENABLED_KEY] intValue];
392 [browseDomainDict setObject:[[[NSNumber alloc] initWithInt:(!value)] autorelease] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
393 [browseDomainsArray replaceObjectAtIndex:[tableView clickedRow] withObject:browseDomainDict];
394 [tableView reloadData];
395 [self updateApplyButtonState];
9f221bca 396 [browseDomainDict release];
7cb34e5c
A
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];
9f221bca
A
684 if ((currentHostName && ([hostNameString compare:currentHostName] != NSOrderedSame)) ||
685 (currentRegDomain && ([regDomainString compare:currentRegDomain] != NSOrderedSame) && ([wideAreaCheckBox state])) ||
7cb34e5c
A
686 (currentHostName == nil && ([hostNameString length]) > 0) ||
687 (currentRegDomain == nil && ([regDomainString length]) > 0) ||
688 (currentWideAreaState != [wideAreaCheckBox state]) ||
689 (hostNameSharedSecretValue != nil) ||
690 (regSharedSecretValue != nil) ||
691 (browseDomainsArray && [browseDomainsArray isEqualToArray:currentBrowseDomainsArray] == NO))
692 {
693 [self enableApplyButton];
694 } else {
695 [self disableApplyButton];
696 }
697}
698
699
700
4a95efb2 701- (void)controlTextDidChange:(NSNotification *)notification
7cb34e5c 702{
67c8f8a1 703 (void)notification; // Unused
7cb34e5c
A
704 [self updateApplyButtonState];
705}
706
707
708
4a95efb2 709- (IBAction)comboAction:(id)sender
7cb34e5c 710{
67c8f8a1 711 (void)sender; // Unused
7cb34e5c
A
712 [self updateApplyButtonState];
713}
714
715
030b743d 716- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)ind
7cb34e5c
A
717{
718 NSString *domain = nil;
030b743d
A
719 if ([aComboBox isEqualTo:browseDomainsComboBox]) domain = [browseDataSource objectAtIndex:ind];
720 else if ([aComboBox isEqualTo:regDomainsComboBox]) domain = [registrationDataSource objectAtIndex:ind];
7cb34e5c
A
721 return domain;
722}
723
724
725
726- (int)numberOfItemsInComboBox:(NSComboBox *)aComboBox
727{
728 int count = 0;
729 if ([aComboBox isEqualTo:browseDomainsComboBox]) count = [browseDataSource count];
730 else if ([aComboBox isEqualTo:regDomainsComboBox]) count = [registrationDataSource count];
731 return count;
732}
733
734
735- (NSMutableArray *)browseDataSource
736{
737 return browseDataSource;
738}
739
740
741- (NSMutableArray *)registrationDataSource
742{
743 return registrationDataSource;
744}
745
746
747- (NSComboBox *)browseDomainsComboBox
748{
749 return browseDomainsComboBox;
750}
751
752
753- (NSComboBox *)regDomainsComboBox
754{
755 return regDomainsComboBox;
756}
757
758
759- (NSString *)currentRegDomain
760{
761 return currentRegDomain;
762}
763
764
765- (NSMutableArray *)defaultBrowseDomainsArray
766{
767 return defaultBrowseDomainsArray;
768}
769
770
771- (NSArray *)currentBrowseDomainsArray
772{
773 return currentBrowseDomainsArray;
774}
775
776
777- (NSString *)currentHostName
778{
779 return currentHostName;
780}
781
782
783- (NSString *)defaultRegDomain
784{
785 return defaultRegDomain;
786}
787
788
789- (void)setDefaultRegDomain:(NSString *)domain
790{
791 [defaultRegDomain release];
792 defaultRegDomain = domain;
793 [defaultRegDomain retain];
794}
795
796
797- (void)didSelect
798{
799 [super didSelect];
800 mainWindow = [[self mainView] window];
801}
802
803
804- (void)mainViewDidLoad
805{
806 [comboAuthButton setString:"system.preferences"];
807 [comboAuthButton setDelegate:self];
808 [comboAuthButton updateStatus:nil];
809 [comboAuthButton setAutoupdate:YES];
810}
811
812
813
814- (IBAction)applyClicked:(id)sender
815{
67c8f8a1 816 (void)sender; // Unused
7cb34e5c
A
817 [self applyCurrentState];
818}
819
820
821- (void)applyCurrentState
822{
823 [self validateTextFields];
824
825 if (toolInstalled == YES) {
826 [self savePreferences];
827 [self disableApplyButton];
828 [mainWindow makeFirstResponder:nil];
829 }
830}
831
832
833- (void)enableApplyButton
834{
835 [applyButton setEnabled:YES];
836 [revertButton setEnabled:YES];
837 prefsNeedUpdating = YES;
838}
839
840
841- (void)disableApplyButton
842{
843 [applyButton setEnabled:NO];
844 [revertButton setEnabled:NO];
845 prefsNeedUpdating = NO;
846}
847
848
849- (void)toggleWideAreaBonjour:(BOOL)state
850{
851 [wideAreaCheckBox setState:state];
852 [regDomainsComboBox setEnabled:state];
853 [registrationSharedSecretButton setEnabled:state];
854}
855
856
4a95efb2 857- (IBAction)revertClicked:(id)sender
7cb34e5c
A
858{
859 [self restorePreferences];
860 [browseDomainList deselectAll:sender];
861 [mainWindow makeFirstResponder:nil];
862}
863
864
865- (void)restorePreferences
866{
867 [self setupInitialValues];
868}
869
870
871- (void)savePanelWillClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
872{
67c8f8a1 873 (void)sheet; // Unused
7cb34e5c
A
874 DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)contextInfo;
875
876 if (returnCode == NSAlertDefaultReturn) {
877 [me applyCurrentState];
878 } else if (returnCode == NSAlertAlternateReturn ) {
879 [me restorePreferences];
880 }
881
882 [me enableControls];
883 [me replyToShouldUnselect:(returnCode != NSAlertOtherReturn)];
884}
885
886
887-(SecKeychainItemRef)copyKeychainItemforDomain:(NSString *)domain
888{
889 const char * serviceName = [domain UTF8String];
890 UInt32 type = 'ddns';
891 UInt32 typeLength = sizeof(type);
892
893 SecKeychainAttribute attrs[] = { { kSecServiceItemAttr, strlen(serviceName), (char *)serviceName },
894 { kSecTypeItemAttr, typeLength, (UInt32 *)&type } };
895
896 SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
897 SecKeychainSearchRef searchRef;
898 SecKeychainItemRef itemRef = NULL;
899 OSStatus err;
900
901 err = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributes, &searchRef);
902 if (err == noErr) {
903 err = SecKeychainSearchCopyNext(searchRef, &itemRef);
904 if (err != noErr) itemRef = NULL;
905 }
906 return itemRef;
907}
908
909
910-(NSString *)sharedSecretKeyName:(NSString * )domain
911{
912 SecKeychainItemRef itemRef = NULL;
913 NSString *keyName = nil;
914 OSStatus err;
915
916 err = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
917 assert(err == noErr);
918
919 itemRef = [self copyKeychainItemforDomain:[domain lowercaseString]];
920 if (itemRef) {
921 UInt32 tags[1];
922 SecKeychainAttributeInfo attrInfo;
923 SecKeychainAttributeList *attrList = NULL;
924 SecKeychainAttribute attribute;
67c8f8a1 925 unsigned int i;
7cb34e5c
A
926
927 tags[0] = kSecAccountItemAttr;
928 attrInfo.count = 1;
929 attrInfo.tag = tags;
930 attrInfo.format = NULL;
931
932 err = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, &attrList, NULL, NULL);
933 if (err == noErr) {
934 for (i = 0; i < attrList->count; i++) {
935 attribute = attrList->attr[i];
936 if (attribute.tag == kSecAccountItemAttr) {
937 keyName = [[NSString alloc] initWithBytes:attribute.data length:attribute.length encoding:NSUTF8StringEncoding];
938 break;
939 }
940 }
941 if (attrList) (void)SecKeychainItemFreeAttributesAndData(attrList, NULL);
942 }
943 CFRelease(itemRef);
944 }
9f221bca 945 return [keyName autorelease];
7cb34e5c
A
946}
947
948
949-(NSString *)domainForHostName:(NSString *)hostNameString
950{
951 NSString * domainName = nil;
952 char text[64];
953 char * ptr = NULL;
954
955 ptr = (char *)[hostNameString UTF8String];
956 if (ptr) {
957 ptr = (char *)GetNextLabel(ptr, text);
958 domainName = [[NSString alloc] initWithUTF8String:(const char *)ptr];
959 }
960 return ([domainName autorelease]);
961}
962
963
964- (NSData *)dataForDomain:(NSString *)domainName isEnabled:(BOOL)enabled
965{
966 NSMutableArray *domainsArray;
967 NSMutableDictionary *domainDict = nil;
968
969 if (domainName && [domainName length] > 0) {
970 domainDict= [[[NSMutableDictionary alloc] initWithCapacity:2] autorelease];
971 [domainDict setObject:domainName forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
972 [domainDict setObject:[[[NSNumber alloc] initWithBool:enabled] autorelease] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
973 }
974 domainsArray = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
975 if (domainDict) [domainsArray addObject:domainDict];
976 return [NSArchiver archivedDataWithRootObject:domainsArray];
977}
978
979
980- (NSData *)dataForDomainArray:(NSArray *)domainArray
981{
982 return [NSArchiver archivedDataWithRootObject:domainArray];
983}
984
985
986- (NSData *)dataForSharedSecret:(NSString *)secret domain:(NSString *)domainName key:(NSString *)keyName
987{
988 NSMutableDictionary *sharedSecretDict = [[[NSMutableDictionary alloc] initWithCapacity:3] autorelease];
989 [sharedSecretDict setObject:secret forKey:(NSString *)SC_DYNDNS_SECRET_KEY];
990 [sharedSecretDict setObject:[domainName lowercaseString] forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
991 [sharedSecretDict setObject:keyName forKey:(NSString *)SC_DYNDNS_KEYNAME_KEY];
992 return [NSArchiver archivedDataWithRootObject:sharedSecretDict];
993}
994
995
996-(void)savePreferences
997{
998 NSString *hostNameString = [hostName stringValue];
7cb34e5c
A
999 NSString *regDomainString = [regDomainsComboBox stringValue];
1000 NSString *tempHostNameSharedSecretName = hostNameSharedSecretName;
1001 NSString *tempRegSharedSecretName = regSharedSecretName;
1002 NSData *browseDomainData = nil;
1003 BOOL regSecretWasSet = NO;
1004 BOOL hostSecretWasSet = NO;
1005 OSStatus err = noErr;
1006
1007 hostNameString = [self trimCharactersFromDomain:hostNameString];
7cb34e5c
A
1008 regDomainString = [self trimCharactersFromDomain:regDomainString];
1009 tempHostNameSharedSecretName = [self trimCharactersFromDomain:tempHostNameSharedSecretName];
1010 tempRegSharedSecretName = [self trimCharactersFromDomain:tempRegSharedSecretName];
1011
1012 [hostName setStringValue:hostNameString];
1013 [regDomainsComboBox setStringValue:regDomainString];
1014
1015 // Convert Shared Secret account names to lowercase.
1016 tempHostNameSharedSecretName = [tempHostNameSharedSecretName lowercaseString];
1017 tempRegSharedSecretName = [tempRegSharedSecretName lowercaseString];
1018
1019 // Save hostname shared secret.
1020 if ([hostNameSharedSecretName length] > 0 && ([hostNameSharedSecretValue length] > 0)) {
1021 SetKeyForDomain((CFDataRef)[self dataForSharedSecret:hostNameSharedSecretValue domain:hostNameString key:tempHostNameSharedSecretName]);
1022 [hostNameSharedSecretValue release];
1023 hostNameSharedSecretValue = nil;
1024 hostSecretWasSet = YES;
1025 }
1026
1027 // Save registration domain shared secret.
1028 if (([regSharedSecretName length] > 0) && ([regSharedSecretValue length] > 0)) {
1029 SetKeyForDomain((CFDataRef)[self dataForSharedSecret:regSharedSecretValue domain:regDomainString key:tempRegSharedSecretName]);
1030 [regSharedSecretValue release];
1031 regSharedSecretValue = nil;
1032 regSecretWasSet = YES;
1033 }
1034
1035 // Save hostname.
1036 if ((currentHostName == NULL) || [currentHostName compare:hostNameString] != NSOrderedSame) {
1037 err = WriteHostname((CFDataRef)[self dataForDomain:hostNameString isEnabled:YES]);
4a95efb2 1038 if (err != noErr) NSLog(@"WriteHostname returned %d\n", (int32_t)err);
7cb34e5c
A
1039 currentHostName = [hostNameString copy];
1040 } else if (hostSecretWasSet) {
1041 WriteHostname((CFDataRef)[self dataForDomain:@"" isEnabled:NO]);
1042 usleep(200000); // Temporary hack
1043 if ([currentHostName length] > 0) WriteHostname((CFDataRef)[self dataForDomain:(NSString *)currentHostName isEnabled:YES]);
1044 }
1045
1046 // Save browse domain.
1047 if (browseDomainsArray && [browseDomainsArray isEqualToArray:currentBrowseDomainsArray] == NO) {
1048 browseDomainData = [self dataForDomainArray:browseDomainsArray];
1049 err = WriteBrowseDomain((CFDataRef)browseDomainData);
4a95efb2 1050 if (err != noErr) NSLog(@"WriteBrowseDomain returned %d\n", (int32_t)err);
7cb34e5c
A
1051 currentBrowseDomainsArray = [browseDomainsArray copy];
1052 }
1053
1054 // Save registration domain.
1055 if ((currentRegDomain == NULL) || ([currentRegDomain compare:regDomainString] != NSOrderedSame) || (currentWideAreaState != [wideAreaCheckBox state])) {
1056
1057 err = WriteRegistrationDomain((CFDataRef)[self dataForDomain:regDomainString isEnabled:[wideAreaCheckBox state]]);
4a95efb2 1058 if (err != noErr) NSLog(@"WriteRegistrationDomain returned %d\n", (int32_t)err);
7cb34e5c
A
1059
1060 if (currentRegDomain) CFRelease(currentRegDomain);
1061 currentRegDomain = [regDomainString copy];
1062
1063 if ([currentRegDomain length] > 0) {
1064 currentWideAreaState = [wideAreaCheckBox state];
1065 [registrationDataSource removeObject:regDomainString];
1066 [registrationDataSource addObject:currentRegDomain];
1067 [registrationDataSource sortUsingFunction:MyArrayCompareFunction context:nil];
1068 [regDomainsComboBox reloadData];
1069 } else {
1070 currentWideAreaState = NO;
1071 [self toggleWideAreaBonjour:NO];
1072 if (defaultRegDomain != nil) [regDomainsComboBox setStringValue:defaultRegDomain];
1073 }
1074 } else if (regSecretWasSet) {
1075 WriteRegistrationDomain((CFDataRef)[self dataForDomain:@"" isEnabled:NO]);
1076 usleep(200000); // Temporary hack
1077 if ([currentRegDomain length] > 0) WriteRegistrationDomain((CFDataRef)[self dataForDomain:currentRegDomain isEnabled:currentWideAreaState]);
1078 }
1079}
1080
1081
1082- (NSPreferencePaneUnselectReply)shouldUnselect
1083{
1084#if 1
1085 if (prefsNeedUpdating == YES) {
1086
1087 [self disableControls];
1088
1089 NSBeginAlertSheet(
1090 @"Apply Configuration Changes?",
1091 @"Apply",
1092 @"Don't Apply",
1093 @"Cancel",
1094 mainWindow,
1095 self,
1096 @selector( savePanelWillClose:returnCode:contextInfo: ),
1097 NULL,
1098 (void *) self, // sender,
1099 @"" );
1100 return NSUnselectLater;
1101 }
1102#endif
1103
1104 return NSUnselectNow;
1105}
1106
1107
1108-(void)disableControls
1109{
1110 [hostName setEnabled:NO];
1111 [hostNameSharedSecretButton setEnabled:NO];
1112 [browseDomainsComboBox setEnabled:NO];
1113 [applyButton setEnabled:NO];
1114 [revertButton setEnabled:NO];
1115 [wideAreaCheckBox setEnabled:NO];
1116 [regDomainsComboBox setEnabled:NO];
1117 [registrationSharedSecretButton setEnabled:NO];
1118 [statusImageView setEnabled:NO];
1119
1120 browseDomainListEnabled = NO;
1121 [browseDomainList deselectAll:self];
1122 [browseDomainList setEnabled:NO];
1123
1124 [addBrowseDomainButton setEnabled:NO];
1125 [removeBrowseDomainButton setEnabled:NO];
1126}
1127
1128
4a95efb2 1129- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
7cb34e5c 1130{
67c8f8a1
A
1131 (void)row; // Unused
1132 (void)tableView; // Unused
7cb34e5c
A
1133 return browseDomainListEnabled;
1134}
1135
1136
1137-(void)enableControls
1138{
1139 [hostName setEnabled:YES];
1140 [hostNameSharedSecretButton setEnabled:YES];
1141 [browseDomainsComboBox setEnabled:YES];
1142 [wideAreaCheckBox setEnabled:YES];
1143 [registrationSharedSecretButton setEnabled:YES];
1144 [self toggleWideAreaBonjour:[wideAreaCheckBox state]];
1145 [statusImageView setEnabled:YES];
1146 [addBrowseDomainButton setEnabled:YES];
1147
1148 [browseDomainList setEnabled:YES];
1149 [browseDomainList deselectAll:self];
1150 browseDomainListEnabled = YES;
1151
1152 [removeBrowseDomainButton setEnabled:[browseDomainList numberOfSelectedRows]];
1153 [applyButton setEnabled:prefsNeedUpdating];
1154 [revertButton setEnabled:prefsNeedUpdating];
1155}
1156
1157
1158- (void)authorizationViewDidAuthorize:(SFAuthorizationView *)view
1159{
67c8f8a1 1160 (void)view; // Unused
7cb34e5c
A
1161 [self enableControls];
1162}
1163
1164
1165- (void)authorizationViewDidDeauthorize:(SFAuthorizationView *)view
1166{
67c8f8a1 1167 (void)view; // Unused
7cb34e5c
A
1168 [self disableControls];
1169}
1170
67c8f8a1
A
1171@end
1172
1173
1174// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
1175// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
1176// To expand "version" to its value before making the string, use STRINGIFY(version) instead
1177#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
1178#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
1179
1180// NOT static -- otherwise the compiler may optimize it out
1181// The "@(#) " pattern is a special prefix the "what" command looks for
1182const char VersionString_SCCS[] = "@(#) Bonjour Preference Pane " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
c9d2d929 1183
32bb7e43 1184#if _BUILDING_XCODE_PROJECT_
67c8f8a1
A
1185// If the process crashes, then this string will be magically included in the automatically-generated crash log
1186const char *__crashreporter_info__ = VersionString_SCCS + 5;
1187asm(".desc ___crashreporter_info__, 0x10");
32bb7e43 1188#endif