2 File: DNSServiceDiscoveryPref.m
4 Abstract: System Preference Pane for Dynamic DNS and Wide-Area DNS Service Discovery
6 Copyright: (c) Copyright 2005-2011 Apple Inc. All rights reserved.
8 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 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.
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 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.
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.
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.
44 #import "DNSServiceDiscoveryPref.h"
45 #import "CNDomainBrowserView.h"
46 #import "BonjourSCStore.h"
47 #import "BonjourPrefTool.h"
48 #import <Foundation/NSXPCConnection_Private.h>
50 #include "../../Clients/ClientCommon.h"
52 #pragma mark - BonjourPrefTool
55 DNSPrefTool_SetKeychainEntry(NSDictionary * secretDictionary)
57 __block OSStatus result;
58 BonjourPrefTool * prefTool;
60 NSXPCConnection * _connectionToTool = [[NSXPCConnection alloc] initWithServiceName:@"com.apple.preference.bonjour.tool"];
61 _connectionToTool.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(BonjourPrefToolProtocol)];
62 [_connectionToTool resume];
65 prefTool = [_connectionToTool remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
66 NSLog( @"Cannot connect to BonjourPrefTool: %@.", error);
70 prefTool = [_connectionToTool synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
71 NSLog( @"Cannot connect to BonjourPrefTool: %@.", error);
75 [prefTool setKeychainEntry: secretDictionary withStatus: ^(OSStatus status){
79 [_connectionToTool invalidate];
86 @implementation DNSServiceDiscoveryPref
89 MyArrayCompareFunction(id val1, id val2, void *context)
91 (void)context; // Unused
92 return CFStringCompare((CFStringRef)val1, (CFStringRef)val2, kCFCompareCaseInsensitive);
96 MyDomainArrayCompareFunction(id val1, id val2, void *context)
98 (void)context; // Unused
99 NSString *domain1 = [val1 objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
100 NSString *domain2 = [val2 objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
101 return CFStringCompare((CFStringRef)domain1, (CFStringRef)domain2, kCFCompareCaseInsensitive);
105 static void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
107 (void)store; // Unused
108 (void)changedKeys; // Unused
109 DNSServiceDiscoveryPref * me = (__bridge DNSServiceDiscoveryPref *)context;
112 [me setupInitialValues];
116 -(void)updateStatusImageView
118 int value = [self statusForHostName:currentHostName];
119 if (value == 0) [statusImageView setImage:successImage];
120 else if (value > 0) [statusImageView setImage:inprogressImage];
121 else [statusImageView setImage:failureImage];
125 - (void)watchForPreferenceChanges
127 SCDynamicStoreContext context = { 0, (__bridge void * _Nullable)(self), NULL, NULL, NULL };
128 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("watchForPreferenceChanges"), NetworkChanged, &context);
129 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
130 CFRunLoopSourceRef rls;
132 assert(store != NULL);
133 assert(keys != NULL);
135 CFArrayAppendValue(keys, SC_DYNDNS_STATE_KEY);
136 CFArrayAppendValue(keys, SC_DYNDNS_SETUP_KEY);
138 (void)SCDynamicStoreSetNotificationKeys(store, keys, NULL);
140 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
143 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopCommonModes);
151 -(int)statusForHostName:(NSString * )domain
153 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("statusForHostName"), NULL, NULL);
154 NSString *lowercaseDomain = [domain lowercaseString];
157 assert(store != NULL);
159 NSDictionary *dynamicDNS = (NSDictionary *)CFBridgingRelease(SCDynamicStoreCopyValue(store, SC_DYNDNS_STATE_KEY));
161 NSDictionary *hostNames = [dynamicDNS objectForKey:(NSString *)SC_DYNDNS_HOSTNAMES_KEY];
162 NSDictionary *infoDict = [hostNames objectForKey:lowercaseDomain];
163 if (infoDict) status = [[infoDict objectForKey:(NSString*)SC_DYNDNS_STATUS_KEY] intValue];
171 -(void)readPreferences
173 NSDictionary *origDict;
174 NSArray *regDomainArray;
177 if (currentRegDomain) currentRegDomain = nil;
178 if (currentBrowseDomainsArray) currentBrowseDomainsArray = nil;
179 if (currentHostName) currentHostName = nil;
181 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("com.apple.preference.bonjour"), NULL, NULL);
182 origDict = (NSDictionary *)CFBridgingRelease(SCDynamicStoreCopyValue(store, SC_DYNDNS_SETUP_KEY));
184 regDomainArray = [origDict objectForKey:(NSString *)SC_DYNDNS_REGDOMAINS_KEY];
185 if (regDomainArray && [regDomainArray count] > 0) {
186 currentRegDomain = [[[regDomainArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY] copy];
187 currentWideAreaState = [[[regDomainArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_ENABLED_KEY] intValue];
189 currentRegDomain = @"";
190 currentWideAreaState = NO;
193 currentBrowseDomainsArray = [origDict objectForKey:(NSString *)SC_DYNDNS_BROWSEDOMAINS_KEY];
195 hostArray = [origDict objectForKey:(NSString *)SC_DYNDNS_HOSTNAMES_KEY];
196 if (hostArray && [hostArray count] > 0) {
197 currentHostName = [[[hostArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY] copy];
199 currentHostName = @"";
202 if (store) CFRelease(store);
206 - (void)tableViewSelectionDidChange:(NSNotification *)notification
208 [removeBrowseDomainButton setEnabled:[[notification object] numberOfSelectedRows]];
212 - (IBAction)addBrowseDomainClicked:(id)sender
214 NSWindow * window = (([NSEvent modifierFlags] & NSAlternateKeyMask) == NSAlternateKeyMask) ? addBrowseDomainManualWindow : addBrowseDomainWindow;
215 [browseDomainTextField setStringValue: [NSString string]];
217 [self disableControls];
218 [NSApp beginSheet:window modalForWindow:mainWindow modalDelegate:self
219 didEndSelector:@selector(addBrowseDomainSheetDidEnd:returnCode:contextInfo:) contextInfo:(__bridge void * _Null_unspecified)(sender)];
221 [browseDomainList deselectAll:sender];
222 [self updateApplyButtonState];
226 - (IBAction)removeBrowseDomainClicked:(id)sender
228 (void)sender; // Unused
229 int selectedBrowseDomain = [browseDomainList selectedRow];
230 [browseDomainsArray removeObjectAtIndex:selectedBrowseDomain];
231 [browseDomainList reloadData];
232 [self updateApplyButtonState];
236 - (IBAction)enableBrowseDomainClicked:(id)sender
238 NSTableView *tableView = sender;
239 NSMutableDictionary *browseDomainDict;
242 browseDomainDict = [[browseDomainsArray objectAtIndex:[tableView clickedRow]] mutableCopy];
243 value = [[browseDomainDict objectForKey:(NSString *)SC_DYNDNS_ENABLED_KEY] intValue];
244 [browseDomainDict setObject:[NSNumber numberWithInt:(!value)] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
245 [browseDomainsArray replaceObjectAtIndex:[tableView clickedRow] withObject:browseDomainDict];
246 [tableView reloadData];
247 [self updateApplyButtonState];
252 - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
254 (void)tableView; // Unused
255 int numberOfRows = 0;
257 if (browseDomainsArray) {
258 numberOfRows = [browseDomainsArray count];
264 - (void)tabView:(NSTabView *)xtabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
266 (void)xtabView; // Unused
267 (void)tabViewItem; // Unused
268 [browseDomainList deselectAll:self];
269 [mainWindow makeFirstResponder:nil];
273 - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
275 (void)tableView; // Unused
276 NSDictionary *browseDomainDict;
279 if (browseDomainsArray) {
280 browseDomainDict = [browseDomainsArray objectAtIndex:row];
281 if (browseDomainDict) {
282 if ([[tableColumn identifier] isEqualTo:(NSString *)SC_DYNDNS_ENABLED_KEY]) {
283 value = [browseDomainDict objectForKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
284 } else if ([[tableColumn identifier] isEqualTo:(NSString *)SC_DYNDNS_DOMAIN_KEY]) {
285 value = [browseDomainDict objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
293 - (void)setupInitialValues
295 [self readPreferences];
297 if (currentHostName) {
298 [hostName setStringValue:currentHostName];
299 [self updateStatusImageView];
302 if (browseDomainsArray) {
303 browseDomainsArray = nil;
306 if (currentBrowseDomainsArray) {
307 browseDomainsArray = [currentBrowseDomainsArray mutableCopy];
308 if (browseDomainsArray) {
309 [browseDomainsArray sortUsingFunction:MyDomainArrayCompareFunction context:nil];
310 if ([browseDomainsArray isEqualToArray:currentBrowseDomainsArray] == NO) {
311 [BonjourSCStore setObject: browseDomainsArray forKey: (NSString *)SC_DYNDNS_BROWSEDOMAINS_KEY];
312 currentBrowseDomainsArray = [browseDomainsArray copy];
316 browseDomainsArray = nil;
318 [browseDomainList reloadData];
320 if (currentRegDomain && ([currentRegDomain length] > 0)) {
321 regDomainView.domain = currentRegDomain;
324 if (currentWideAreaState) {
325 [self toggleWideAreaBonjour:YES];
327 [self toggleWideAreaBonjour:NO];
330 if (hostNameSharedSecretValue) {
331 hostNameSharedSecretValue = nil;
334 if (regSharedSecretValue) {
335 regSharedSecretValue = nil;
338 [self updateApplyButtonState];
339 [mainWindow makeFirstResponder:nil];
340 [browseDomainList deselectAll:self];
341 [removeBrowseDomainButton setEnabled:NO];
348 prefsNeedUpdating = NO;
349 browseDomainListEnabled = NO;
350 defaultRegDomain = nil;
351 currentRegDomain = nil;
352 currentBrowseDomainsArray = nil;
353 currentHostName = nil;
354 hostNameSharedSecretValue = nil;
355 regSharedSecretValue = nil;
356 browseDomainsArray = nil;
357 currentWideAreaState = NO;
358 NSString *successPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"success" ofType:@"tiff"];
359 NSString *inprogressPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"inprogress" ofType:@"tiff"];
360 NSString *failurePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"failure" ofType:@"tiff"];
362 registrationDataSource = [[NSMutableArray alloc] init];
363 successImage = [[NSImage alloc] initWithContentsOfFile:successPath];
364 inprogressImage = [[NSImage alloc] initWithContentsOfFile:inprogressPath];
365 failureImage = [[NSImage alloc] initWithContentsOfFile:failurePath];
367 [tabView selectFirstTabViewItem:self];
368 [self setupInitialValues];
369 [self watchForPreferenceChanges];
376 [bonjourBrowserView startBrowse];
377 [registrationBrowserView startBrowse];
383 [super willUnselect];
384 [bonjourBrowserView stopBrowse];
385 [registrationBrowserView stopBrowse];
388 - (IBAction)closeMyCustomSheet:(id)sender
390 BOOL result = [sender tag];
392 if (result) [NSApp endSheet:[sender window] returnCode:NSOKButton];
393 else [NSApp endSheet:[sender window] returnCode:NSCancelButton];
397 - (void)sharedSecretSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
399 NSButton * button = (__bridge NSButton *)contextInfo;
400 [sheet orderOut:self];
401 [self enableControls];
403 if (returnCode == NSOKButton) {
404 if ([button isEqualTo:hostNameSharedSecretButton]) {
405 hostNameSharedSecretName = [[NSString alloc] initWithString:[sharedSecretName stringValue]];
406 hostNameSharedSecretValue = [[NSString alloc] initWithString:[sharedSecretValue stringValue]];
408 regSharedSecretName = [[NSString alloc] initWithString:[sharedSecretName stringValue]];
409 regSharedSecretValue = [[NSString alloc] initWithString:[sharedSecretValue stringValue]];
411 [self updateApplyButtonState];
413 [sharedSecretValue setStringValue:@""];
417 - (BOOL)domainAlreadyInList:(NSString *)domainString
419 if (browseDomainsArray) {
420 NSDictionary *domainDict;
421 NSString *domainName;
422 NSEnumerator *arrayEnumerator = [browseDomainsArray objectEnumerator];
423 while ((domainDict = [arrayEnumerator nextObject]) != NULL) {
424 domainName = [domainDict objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
425 if ([domainString caseInsensitiveCompare:domainName] == NSOrderedSame) return YES;
432 - (NSString *)trimCharactersFromDomain:(NSString *)domain
434 NSMutableCharacterSet * trimSet = [NSMutableCharacterSet whitespaceCharacterSet];
435 [trimSet formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];
436 return [domain stringByTrimmingCharactersInSet:trimSet];
440 - (void)addBrowseDomainSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
442 (void)contextInfo; // Unused
443 [sheet orderOut:self];
444 [self enableControls];
446 if (returnCode == NSOKButton) {
447 NSString * newBrowseDomainString;
448 if(sheet == addBrowseDomainManualWindow) newBrowseDomainString = [self trimCharactersFromDomain:[browseDomainTextField stringValue]];
449 else newBrowseDomainString = [self trimCharactersFromDomain:bonjourBrowserView.selectedDNSDomain];
450 NSMutableDictionary *newBrowseDomainDict;
451 if (browseDomainsArray == nil) browseDomainsArray = [[NSMutableArray alloc] initWithCapacity:0];
452 if ([self domainAlreadyInList:newBrowseDomainString] == NO) {
453 newBrowseDomainDict = [[NSMutableDictionary alloc] initWithCapacity:2];
455 [newBrowseDomainDict setObject:newBrowseDomainString forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
456 [newBrowseDomainDict setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
458 [browseDomainsArray addObject:newBrowseDomainDict];
459 [browseDomainsArray sortUsingFunction:MyDomainArrayCompareFunction context:nil];
460 [browseDomainList reloadData];
461 [self updateApplyButtonState];
466 -(void)validateTextFields
468 [hostName validateEditing];
469 [browseDomainTextField validateEditing];
473 - (IBAction)changeButtonPressed:(id)sender
477 [self disableControls];
478 [self validateTextFields];
479 [mainWindow makeFirstResponder:nil];
480 [browseDomainList deselectAll:sender];
482 if ([sender isEqualTo:hostNameSharedSecretButton]) {
483 if (hostNameSharedSecretValue) {
484 [sharedSecretValue setStringValue:hostNameSharedSecretValue];
485 } else if ((keyName = [self sharedSecretKeyName:[hostName stringValue]]) != NULL) {
486 [sharedSecretName setStringValue:keyName];
487 [sharedSecretValue setStringValue:@"****************"];
489 [sharedSecretName setStringValue:[hostName stringValue]];
490 [sharedSecretValue setStringValue:@""];
494 if (regSharedSecretValue) {
495 [sharedSecretValue setStringValue:regSharedSecretValue];
496 } else if ((keyName = [self sharedSecretKeyName:regDomainView.domain]) != NULL) {
497 [sharedSecretName setStringValue:keyName];
498 [sharedSecretValue setStringValue:@"****************"];
500 [sharedSecretName setStringValue:regDomainView.domain];
501 [sharedSecretValue setStringValue:@""];
505 [sharedSecretWindow resignFirstResponder];
507 if ([[sharedSecretName stringValue] length] > 0) [sharedSecretWindow makeFirstResponder:sharedSecretValue];
508 else [sharedSecretWindow makeFirstResponder:sharedSecretName];
510 [NSApp beginSheet:sharedSecretWindow modalForWindow:mainWindow modalDelegate:self
511 didEndSelector:@selector(sharedSecretSheetDidEnd:returnCode:contextInfo:) contextInfo:(__bridge void * _Null_unspecified)(sender)];
515 - (IBAction)selectWideAreaDomainButtonPressed:(id)sender
517 NSWindow * window = (([NSEvent modifierFlags] & NSAlternateKeyMask) == NSAlternateKeyMask) ? selectRegistrationDomainManualWindow : selectRegistrationDomainWindow;
518 regDomainTextField.stringValue = regDomainView.domain;
520 [self disableControls];
521 [NSApp beginSheet:window modalForWindow:mainWindow modalDelegate:self
522 didEndSelector:@selector(selectWideAreaDomainSheetDidEnd:returnCode:contextInfo:) contextInfo:(__bridge void * _Null_unspecified)(sender)];
524 [self updateApplyButtonState];
527 - (void)selectWideAreaDomainSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
529 (void)contextInfo; // Unused
530 [sheet orderOut:self];
531 [self enableControls];
533 if (returnCode == NSOKButton) {
534 NSString * newRegDomainString;
535 if(sheet == selectRegistrationDomainManualWindow) newRegDomainString = [self trimCharactersFromDomain:[regDomainTextField stringValue]];
536 else newRegDomainString = [self trimCharactersFromDomain:registrationBrowserView.selectedDNSDomain];
537 regDomainView.domain = newRegDomainString;
538 [self updateApplyButtonState];
542 - (IBAction)wideAreaCheckBoxChanged:(id)sender
544 [self toggleWideAreaBonjour:[sender state]];
545 [self updateApplyButtonState];
546 [mainWindow makeFirstResponder:nil];
551 - (void)updateApplyButtonState
553 NSString *hostNameString = [hostName stringValue];
554 NSString *regDomainString = regDomainView.domain;
555 if ((currentHostName && ([hostNameString compare:currentHostName] != NSOrderedSame)) ||
556 (currentRegDomain && ([regDomainString compare:currentRegDomain] != NSOrderedSame) && ([wideAreaCheckBox state])) ||
557 (currentHostName == nil && ([hostNameString length]) > 0) ||
558 (currentRegDomain == nil && ([regDomainString length]) > 0) ||
559 (currentWideAreaState != [wideAreaCheckBox state]) ||
560 (hostNameSharedSecretValue != nil) ||
561 (regSharedSecretValue != nil) ||
562 (browseDomainsArray && [browseDomainsArray isEqualToArray:currentBrowseDomainsArray] == NO))
564 [self enableApplyButton];
566 [self disableApplyButton];
571 - (void)controlTextDidChange:(NSNotification *)notification
573 (void)notification; // Unused
574 [self updateApplyButtonState];
578 - (NSMutableArray *)registrationDataSource
580 return registrationDataSource;
584 - (NSString *)currentRegDomain
586 return currentRegDomain;
590 - (NSArray *)currentBrowseDomainsArray
592 return currentBrowseDomainsArray;
596 - (NSString *)currentHostName
598 return currentHostName;
602 - (NSString *)defaultRegDomain
604 return defaultRegDomain;
608 - (void)setDefaultRegDomain:(NSString *)domain
610 defaultRegDomain = domain;
617 mainWindow = [[self mainView] window];
620 - (void)mainViewDidLoad
622 [comboAuthButton setString:"system.preferences"];
623 [comboAuthButton setDelegate:self];
624 [comboAuthButton setAutoupdate:YES];
625 [super mainViewDidLoad];
630 - (IBAction)applyClicked:(id)sender
632 (void)sender; // Unused
633 [self applyCurrentState];
637 - (void)applyCurrentState
639 [self validateTextFields];
640 [self savePreferences];
641 [self disableApplyButton];
642 [mainWindow makeFirstResponder:nil];
646 - (void)enableApplyButton
648 [applyButton setEnabled:YES];
649 [revertButton setEnabled:YES];
650 prefsNeedUpdating = YES;
654 - (void)disableApplyButton
656 [applyButton setEnabled:NO];
657 [revertButton setEnabled:NO];
658 prefsNeedUpdating = NO;
662 - (void)toggleWideAreaBonjour:(BOOL)state
664 [wideAreaCheckBox setState:state];
665 [registrationSelectButton setEnabled:state];
666 [registrationSharedSecretButton setEnabled:state];
670 - (IBAction)revertClicked:(id)sender
672 [self restorePreferences];
673 [browseDomainList deselectAll:sender];
674 [mainWindow makeFirstResponder:nil];
678 - (void)restorePreferences
680 [self setupInitialValues];
684 - (void)savePanelWillClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
686 (void)sheet; // Unused
687 DNSServiceDiscoveryPref * me = (__bridge DNSServiceDiscoveryPref *)contextInfo;
689 if (returnCode == NSAlertDefaultReturn) {
690 [me applyCurrentState];
691 } else if (returnCode == NSAlertAlternateReturn ) {
692 [me restorePreferences];
696 [me replyToShouldUnselect:(returnCode != NSAlertOtherReturn)];
700 -(SecKeychainItemRef)copyKeychainItemforDomain:(NSString *)domain
702 const char * serviceName = [domain UTF8String];
703 UInt32 type = 'ddns';
704 UInt32 typeLength = sizeof(type);
706 SecKeychainAttribute attrs[] = { { kSecServiceItemAttr, strlen(serviceName), (char *)serviceName },
707 { kSecTypeItemAttr, typeLength, (UInt32 *)&type } };
709 SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
710 SecKeychainSearchRef searchRef;
711 SecKeychainItemRef itemRef = NULL;
714 err = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributes, &searchRef);
716 err = SecKeychainSearchCopyNext(searchRef, &itemRef);
717 if (err != noErr) itemRef = NULL;
723 -(NSString *)sharedSecretKeyName:(NSString * )domain
725 SecKeychainItemRef itemRef = NULL;
726 NSString *keyName = nil;
729 err = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
730 assert(err == noErr);
732 itemRef = [self copyKeychainItemforDomain:[domain lowercaseString]];
735 SecKeychainAttributeInfo attrInfo;
736 SecKeychainAttributeList *attrList = NULL;
737 SecKeychainAttribute attribute;
740 tags[0] = kSecAccountItemAttr;
743 attrInfo.format = NULL;
745 err = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, &attrList, NULL, NULL);
747 for (i = 0; i < attrList->count; i++) {
748 attribute = attrList->attr[i];
749 if (attribute.tag == kSecAccountItemAttr) {
750 keyName = [[NSString alloc] initWithBytes:attribute.data length:attribute.length encoding:NSUTF8StringEncoding];
754 if (attrList) (void)SecKeychainItemFreeAttributesAndData(attrList, NULL);
762 -(NSString *)domainForHostName:(NSString *)hostNameString
764 NSString * domainName = nil;
768 ptr = (char *)[hostNameString UTF8String];
770 ptr = (char *)GetNextLabel(ptr, text);
771 domainName = [[NSString alloc] initWithUTF8String:(const char *)ptr];
777 - (NSData *)dataForDomain:(NSString *)domainName isEnabled:(BOOL)enabled
779 NSMutableArray *domainsArray;
780 NSMutableDictionary *domainDict = nil;
782 if (domainName && [domainName length] > 0) {
783 domainDict= [NSMutableDictionary dictionaryWithCapacity:2];
784 [domainDict setObject:domainName forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
785 [domainDict setObject:[NSNumber numberWithBool:enabled] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
787 domainsArray = [NSMutableArray arrayWithCapacity:1];
788 if (domainDict) [domainsArray addObject:domainDict];
789 return [NSArchiver archivedDataWithRootObject:domainsArray];
793 - (NSData *)dataForDomainArray:(NSArray *)domainArray
795 return [NSArchiver archivedDataWithRootObject:domainArray];
799 - (NSDictionary *)dictionaryForSharedSecret:(NSString *)secret domain:(NSString *)domainName key:(NSString *)keyName
801 NSMutableDictionary *sharedSecretDict = [NSMutableDictionary dictionaryWithCapacity:3];
802 [sharedSecretDict setObject:secret forKey:(NSString *)SC_DYNDNS_SECRET_KEY];
803 [sharedSecretDict setObject:[domainName lowercaseString] forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
804 [sharedSecretDict setObject:keyName forKey:(NSString *)SC_DYNDNS_KEYNAME_KEY];
805 return sharedSecretDict;
809 -(void)savePreferences
811 NSString *hostNameString = [hostName stringValue];
812 NSString *regDomainString = regDomainView.domain;
813 NSString *tempHostNameSharedSecretName = hostNameSharedSecretName;
814 NSString *tempRegSharedSecretName = regSharedSecretName;
815 BOOL regSecretWasSet = NO;
816 BOOL hostSecretWasSet = NO;
817 BOOL updateHostname = NO;
819 hostNameString = [self trimCharactersFromDomain:hostNameString];
820 regDomainString = [self trimCharactersFromDomain:regDomainString];
821 tempHostNameSharedSecretName = [self trimCharactersFromDomain:tempHostNameSharedSecretName];
822 tempRegSharedSecretName = [self trimCharactersFromDomain:tempRegSharedSecretName];
824 [hostName setStringValue:hostNameString];
825 regDomainView.domain = regDomainString;
827 // Convert Shared Secret account names to lowercase.
828 tempHostNameSharedSecretName = [tempHostNameSharedSecretName lowercaseString];
829 tempRegSharedSecretName = [tempRegSharedSecretName lowercaseString];
831 // Save hostname shared secret.
832 if ([hostNameSharedSecretName length] > 0 && ([hostNameSharedSecretValue length] > 0)) {
833 DNSPrefTool_SetKeychainEntry([self dictionaryForSharedSecret:hostNameSharedSecretValue domain:hostNameString key:tempHostNameSharedSecretName]);
834 hostNameSharedSecretValue = nil;
835 hostSecretWasSet = YES;
838 // Save registration domain shared secret.
839 if (([regSharedSecretName length] > 0) && ([regSharedSecretValue length] > 0)) {
840 DNSPrefTool_SetKeychainEntry([self dictionaryForSharedSecret:regSharedSecretValue domain:regDomainString key:tempRegSharedSecretName]);
841 regSharedSecretValue = nil;
842 regSecretWasSet = YES;
846 if ((currentHostName == NULL) || [currentHostName compare:hostNameString] != NSOrderedSame) {
847 currentHostName = [hostNameString copy];
848 updateHostname = YES;
849 } else if (hostSecretWasSet) {
850 currentHostName = @"";
851 updateHostname = YES;
854 if (updateHostname) {
855 [BonjourSCStore setObject: currentHostName.length ? @[@{
856 (NSString *)SC_DYNDNS_DOMAIN_KEY : currentHostName,
857 (NSString *)SC_DYNDNS_ENABLED_KEY : @YES
859 forKey: (NSString *)SC_DYNDNS_HOSTNAMES_KEY];
862 // Save browse domain.
863 if (browseDomainsArray && [browseDomainsArray isEqualToArray:currentBrowseDomainsArray] == NO) {
864 [BonjourSCStore setObject: browseDomainsArray forKey: (NSString *)SC_DYNDNS_BROWSEDOMAINS_KEY];
865 currentBrowseDomainsArray = [browseDomainsArray copy];
868 // Save registration domain.
869 if ((currentRegDomain == NULL) || ([currentRegDomain compare:regDomainString] != NSOrderedSame) || (currentWideAreaState != [wideAreaCheckBox state])) {
870 [BonjourSCStore setObject: @[@{
871 (NSString *)SC_DYNDNS_DOMAIN_KEY : regDomainString,
872 (NSString *)SC_DYNDNS_ENABLED_KEY : [wideAreaCheckBox state] ? @YES : @NO
874 forKey: (NSString *)SC_DYNDNS_REGDOMAINS_KEY];
875 currentRegDomain = [regDomainString copy];
877 if ([currentRegDomain length] > 0) {
878 currentWideAreaState = [wideAreaCheckBox state];
879 [registrationDataSource removeObject:regDomainString];
880 [registrationDataSource addObject:currentRegDomain];
881 [registrationDataSource sortUsingFunction:MyArrayCompareFunction context:nil];
882 // [regDomainsComboBox reloadData];
884 currentWideAreaState = NO;
885 [self toggleWideAreaBonjour:NO];
886 if (defaultRegDomain != nil) regDomainView.domain = defaultRegDomain;
888 } else if (regSecretWasSet) {
889 [BonjourSCStore setObject: @[@{
890 (NSString *)SC_DYNDNS_DOMAIN_KEY : @"",
891 (NSString *)SC_DYNDNS_ENABLED_KEY : @NO
893 forKey: (NSString *)SC_DYNDNS_REGDOMAINS_KEY];
894 if ([currentRegDomain length] > 0) {
895 [BonjourSCStore setObject: @[@{
896 (NSString *)SC_DYNDNS_DOMAIN_KEY : currentRegDomain,
897 (NSString *)SC_DYNDNS_ENABLED_KEY : currentWideAreaState ? @YES : @NO
899 forKey: (NSString *)SC_DYNDNS_REGDOMAINS_KEY];
905 - (NSPreferencePaneUnselectReply)shouldUnselect
908 if (prefsNeedUpdating == YES) {
910 [self disableControls];
913 @"Apply Configuration Changes?",
919 @selector( savePanelWillClose:returnCode:contextInfo: ),
921 (__bridge void *) self, // sender,
923 return NSUnselectLater;
927 return NSUnselectNow;
931 -(void)disableControls
933 [hostName setEnabled:NO];
934 [hostNameSharedSecretButton setEnabled:NO];
935 [applyButton setEnabled:NO];
936 [revertButton setEnabled:NO];
937 [wideAreaCheckBox setEnabled:NO];
938 [registrationSelectButton setEnabled: NO];
939 [registrationSharedSecretButton setEnabled:NO];
940 [statusImageView setEnabled:NO];
942 browseDomainListEnabled = NO;
943 [browseDomainList deselectAll:self];
944 [browseDomainList setEnabled:NO];
946 [addBrowseDomainButton setEnabled:NO];
947 [removeBrowseDomainButton setEnabled:NO];
951 - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
954 (void)tableView; // Unused
955 return browseDomainListEnabled;
959 -(void)enableControls
961 [hostName setEnabled:YES];
962 [hostNameSharedSecretButton setEnabled:YES];
963 [wideAreaCheckBox setEnabled:YES];
964 [registrationSelectButton setEnabled: YES];
965 [registrationSharedSecretButton setEnabled:YES];
966 [self toggleWideAreaBonjour:[wideAreaCheckBox state]];
967 [statusImageView setEnabled:YES];
968 [addBrowseDomainButton setEnabled:YES];
970 [browseDomainList setEnabled:YES];
971 [browseDomainList deselectAll:self];
972 browseDomainListEnabled = YES;
974 [removeBrowseDomainButton setEnabled:[browseDomainList numberOfSelectedRows]];
975 [applyButton setEnabled:prefsNeedUpdating];
976 [revertButton setEnabled:prefsNeedUpdating];
980 - (void)authorizationViewDidAuthorize:(SFAuthorizationView *)view
982 (void)view; // unused
983 [self enableControls];
987 - (void)authorizationViewDidDeauthorize:(SFAuthorizationView *)view
989 (void)view; // unused
990 [self disableControls];
996 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
997 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
998 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
999 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
1000 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
1002 // NOT static -- otherwise the compiler may optimize it out
1003 // The "@(#) " pattern is a special prefix the "what" command looks for
1004 const char VersionString_SCCS[] = "@(#) Bonjour Preference Pane " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
1006 #if _BUILDING_XCODE_PROJECT_
1007 // If the process crashes, then this string will be magically included in the automatically-generated crash log
1008 const char *__crashreporter_info__ = VersionString_SCCS + 5;
1009 asm(".desc ___crashreporter_info__, 0x10");