]>
Commit | Line | Data |
---|---|---|
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 | 57 | static NSInteger |
7cb34e5c A |
58 | MyArrayCompareFunction(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 | 64 | static NSInteger |
7cb34e5c A |
65 | MyDomainArrayCompareFunction(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 |
74 | static 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 | ||
85 | static 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 | 142 | static void |
7cb34e5c A |
143 | browseDomainReply(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 | 150 | static void |
7cb34e5c A |
151 | registrationDomainReply(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 | ||
159 | static void | |
160 | MyDNSServiceCleanUp(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 | ||
180 | static void | |
181 | MySocketReadCallback(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 | 205 | static void |
7cb34e5c A |
206 | MyDNSServiceAddServiceToRunLoop(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(®Query.service, flags, 0, registrationDomainReply, (void *)self); | |
297 | if (err == kDNSServiceErr_NoError) MyDNSServiceAddServiceToRunLoop(®Query); | |
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 | |
1182 | const 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 |
1186 | const char *__crashreporter_info__ = VersionString_SCCS + 5; | |
1187 | asm(".desc ___crashreporter_info__, 0x10"); | |
32bb7e43 | 1188 | #endif |