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