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