2 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: ConfigPropertySheet.cpp,v $
26 Revision 1.4 2005/10/05 20:46:50 herscher
27 <rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
29 Revision 1.3 2005/03/03 19:55:22 shersche
30 <rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
35 #include "ConfigPropertySheet.h"
36 #include <WinServices.h>
41 #define WM_DATAREADY ( WM_USER + 0x100 )
42 #define WM_REGISTRYCHANGED ( WM_USER + 0x101 )
45 IMPLEMENT_DYNCREATE(CConfigPropertySheet
, CPropertySheet
)
48 //---------------------------------------------------------------------------------------------------------------------------
49 // CConfigPropertySheet::CConfigPropertySheet
50 //---------------------------------------------------------------------------------------------------------------------------
52 CConfigPropertySheet::CConfigPropertySheet()
55 m_browseDomainsRef( NULL
),
56 m_regDomainsRef( NULL
),
58 m_threadExited( NULL
)
60 AddPage(&m_firstPage
);
61 AddPage(&m_secondPage
);
62 AddPage(&m_thirdPage
);
64 InitializeCriticalSection( &m_lock
);
68 //---------------------------------------------------------------------------------------------------------------------------
69 // CConfigPropertySheet::~CConfigPropertySheet
70 //---------------------------------------------------------------------------------------------------------------------------
72 CConfigPropertySheet::~CConfigPropertySheet()
74 DeleteCriticalSection( &m_lock
);
78 BEGIN_MESSAGE_MAP(CConfigPropertySheet
, CPropertySheet
)
79 //{{AFX_MSG_MAP(CConfigPropertySheet)
81 ON_MESSAGE( WM_DATAREADY
, OnDataReady
)
82 ON_MESSAGE( WM_REGISTRYCHANGED
, OnRegistryChanged
)
86 //---------------------------------------------------------------------------------------------------------------------------
87 // CConfigPropertySheet::OnInitDialog
88 //---------------------------------------------------------------------------------------------------------------------------
91 CConfigPropertySheet::OnInitDialog()
95 BOOL b
= CPropertySheet::OnInitDialog();
97 err
= SetupBrowsing();
98 require_noerr( err
, exit
);
100 err
= SetupRegistryNotifications();
101 require_noerr( err
, exit
);
109 //---------------------------------------------------------------------------------------------------------------------------
110 // CConfigPropertySheet::OnCommand
111 //---------------------------------------------------------------------------------------------------------------------------
114 CConfigPropertySheet::OnCommand(WPARAM wParam
, LPARAM lParam
)
116 // Check if OK or Cancel was hit
118 if ( ( wParam
== ID_WIZFINISH
) || ( wParam
== IDOK
) || ( wParam
== IDCANCEL
) )
123 return CPropertySheet::OnCommand(wParam
, lParam
);
127 //---------------------------------------------------------------------------------------------------------------------------
128 // CConfigPropertySheet::OnDataReady
129 //---------------------------------------------------------------------------------------------------------------------------
132 CConfigPropertySheet::OnDataReady(WPARAM inWParam
, LPARAM inLParam
)
134 if (WSAGETSELECTERROR(inLParam
) && !(HIWORD(inLParam
)))
136 dlog( kDebugLevelError
, "OnSocket: window error\n" );
140 SOCKET sock
= (SOCKET
) inWParam
;
142 if ( m_browseDomainsRef
&& DNSServiceRefSockFD( m_browseDomainsRef
) == (int) sock
)
144 DNSServiceProcessResult( m_browseDomainsRef
);
146 else if ( m_regDomainsRef
&& DNSServiceRefSockFD( m_regDomainsRef
) == (int) sock
)
148 DNSServiceProcessResult( m_regDomainsRef
);
156 //---------------------------------------------------------------------------------------------------------------------------
157 // CConfigPropertySheet::OnRegistryChanged
158 //---------------------------------------------------------------------------------------------------------------------------
161 CConfigPropertySheet::OnRegistryChanged( WPARAM inWParam
, LPARAM inLParam
)
163 DEBUG_UNUSED( inWParam
);
164 DEBUG_UNUSED( inLParam
);
166 if ( GetActivePage() == &m_firstPage
)
168 m_firstPage
.OnRegistryChanged();
175 //---------------------------------------------------------------------------------------------------------------------------
176 // CConfigPropertySheet::OnEndDialog
177 //---------------------------------------------------------------------------------------------------------------------------
180 CConfigPropertySheet::OnEndDialog()
184 err
= TearDownRegistryNotifications();
187 err
= TearDownBrowsing();
192 //---------------------------------------------------------------------------------------------------------------------------
193 // CConfigPropertySheet::SetupBrowsing
194 //---------------------------------------------------------------------------------------------------------------------------
197 CConfigPropertySheet::SetupBrowsing()
201 // Start browsing for browse domains
203 err
= DNSServiceEnumerateDomains( &m_browseDomainsRef
, kDNSServiceFlagsBrowseDomains
, 0, BrowseDomainsReply
, this );
204 require_noerr( err
, exit
);
206 err
= WSAAsyncSelect( DNSServiceRefSockFD( m_browseDomainsRef
), m_hWnd
, WM_DATAREADY
, FD_READ
|FD_CLOSE
);
207 require_noerr( err
, exit
);
209 // Start browsing for registration domains
211 err
= DNSServiceEnumerateDomains( &m_regDomainsRef
, kDNSServiceFlagsRegistrationDomains
, 0, RegDomainsReply
, this );
212 require_noerr( err
, exit
);
214 err
= WSAAsyncSelect( DNSServiceRefSockFD( m_regDomainsRef
), m_hWnd
, WM_DATAREADY
, FD_READ
|FD_CLOSE
);
215 require_noerr( err
, exit
);
228 //---------------------------------------------------------------------------------------------------------------------------
229 // CConfigPropertySheet::TearDownBrowsing
230 //---------------------------------------------------------------------------------------------------------------------------
233 CConfigPropertySheet::TearDownBrowsing()
235 OSStatus err
= kNoErr
;
237 if ( m_browseDomainsRef
)
239 err
= WSAAsyncSelect( DNSServiceRefSockFD( m_browseDomainsRef
), m_hWnd
, 0, 0 );
242 DNSServiceRefDeallocate( m_browseDomainsRef
);
244 m_browseDomainsRef
= NULL
;
247 if ( m_regDomainsRef
)
249 err
= WSAAsyncSelect( DNSServiceRefSockFD( m_regDomainsRef
), m_hWnd
, 0, 0 );
252 DNSServiceRefDeallocate( m_regDomainsRef
);
254 m_regDomainsRef
= NULL
;
261 //---------------------------------------------------------------------------------------------------------------------------
262 // CConfigPropertySheet::SetupRegistryNotifications
263 //---------------------------------------------------------------------------------------------------------------------------
266 CConfigPropertySheet::SetupRegistryNotifications()
268 unsigned int threadId
;
271 check( m_threadExited
== NULL
);
272 check( m_thread
== NULL
);
274 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode L
"\\DynDNS\\State\\Hostnames", &m_statusKey
);
275 require_noerr( err
, exit
);
277 m_threadExited
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
278 err
= translate_errno( m_threadExited
, (OSStatus
) GetLastError(), kUnknownErr
);
279 require_noerr( err
, exit
);
281 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
282 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
284 m_thread
= (HANDLE
) _beginthreadex_compat( NULL
, 0, WatchRegistry
, this, 0, &threadId
);
285 err
= translate_errno( m_thread
, (OSStatus
) GetLastError(), kUnknownErr
);
286 require_noerr( err
, exit
);
292 TearDownRegistryNotifications();
299 //---------------------------------------------------------------------------------------------------------------------------
300 // CConfigPropertySheet::TearDownRegistryNotifications
301 //---------------------------------------------------------------------------------------------------------------------------
304 CConfigPropertySheet::TearDownRegistryNotifications()
306 OSStatus err
= kNoErr
;
310 EnterCriticalSection( &m_lock
);
312 RegCloseKey( m_statusKey
);
315 LeaveCriticalSection( &m_lock
);
318 if ( m_threadExited
)
320 err
= WaitForSingleObject( m_threadExited
, 5 * 1000 );
321 require_noerr( err
, exit
);
326 if ( m_threadExited
)
328 CloseHandle( m_threadExited
);
329 m_threadExited
= NULL
;
334 CloseHandle( m_thread
);
342 //---------------------------------------------------------------------------------------------------------------------------
343 // CConfigPropertySheet::DecodeDomainName
344 //---------------------------------------------------------------------------------------------------------------------------
347 CConfigPropertySheet::DecodeDomainName( const char * raw
, CString
& decoded
)
349 char nextLabel
[128] = "\0";
350 char decodedDomainString
[kDNSServiceMaxDomainName
];
351 char * buffer
= (char *) raw
;
354 const char *label
[128];
359 decodedDomainString
[0] = '\0';
365 label
[labels
++] = buffer
;
366 buffer
= (char *) GetNextLabel(buffer
, text
);
369 buffer
= (char*) raw
;
371 for (i
= 0; i
< labels
; i
++)
373 buffer
= (char *)GetNextLabel(buffer
, nextLabel
);
374 strcat(decodedDomainString
, nextLabel
);
375 strcat(decodedDomainString
, ".");
378 // Remove trailing dot from domain name.
380 decodedDomainString
[ strlen( decodedDomainString
) - 1 ] = '\0';
382 // Convert to Unicode
384 err
= UTF8StringToStringObject( decodedDomainString
, decoded
);
390 //---------------------------------------------------------------------------------------------------------------------------
391 // CConfigPropertySheet::GetNextLabel
392 //---------------------------------------------------------------------------------------------------------------------------
395 CConfigPropertySheet::GetNextLabel( const char * cstr
, char label
[64] )
398 while (*cstr
&& *cstr
!= '.') // While we have characters in the label...
404 if (isdigit(cstr
[-1]) && isdigit(cstr
[0]) && isdigit(cstr
[1]))
406 int v0
= cstr
[-1] - '0'; // then interpret as three-digit decimal
407 int v1
= cstr
[ 0] - '0';
408 int v2
= cstr
[ 1] - '0';
409 int val
= v0
* 100 + v1
* 10 + v2
;
410 if (val
<= 255) { c
= (char)val
; cstr
+= 2; } // If valid three-digit decimal value, use it
414 if (ptr
>= label
+64) return(NULL
);
416 if (*cstr
) cstr
++; // Skip over the trailing dot (if present)
422 //---------------------------------------------------------------------------------------------------------------------------
423 // CConfigPropertySheet::BrowseDomainsReply
424 //---------------------------------------------------------------------------------------------------------------------------
427 CConfigPropertySheet::BrowseDomainsReply
430 DNSServiceFlags flags
,
431 uint32_t interfaceIndex
,
432 DNSServiceErrorType errorCode
,
433 const char * replyDomain
,
437 CConfigPropertySheet
* self
= reinterpret_cast<CConfigPropertySheet
*>(context
);
441 DEBUG_UNUSED( sdRef
);
442 DEBUG_UNUSED( interfaceIndex
);
449 check( replyDomain
);
451 // Ignore local domains
453 if ( strcmp( replyDomain
, "local." ) == 0 )
460 err
= self
->DecodeDomainName( replyDomain
, decoded
);
461 require_noerr( err
, exit
);
463 // Remove trailing '.'
465 decoded
.TrimRight( '.' );
467 if ( flags
& kDNSServiceFlagsAdd
)
469 self
->m_browseDomains
.push_back( decoded
);
473 self
->m_browseDomains
.remove( decoded
);
482 //---------------------------------------------------------------------------------------------------------------------------
483 // CConfigPropertySheet::RegDomainsReply
484 //---------------------------------------------------------------------------------------------------------------------------
487 CConfigPropertySheet::RegDomainsReply
490 DNSServiceFlags flags
,
491 uint32_t interfaceIndex
,
492 DNSServiceErrorType errorCode
,
493 const char * replyDomain
,
497 CConfigPropertySheet
* self
= reinterpret_cast<CConfigPropertySheet
*>(context
);
501 DEBUG_UNUSED( sdRef
);
502 DEBUG_UNUSED( interfaceIndex
);
509 check( replyDomain
);
511 // Ignore local domains
513 if ( strcmp( replyDomain
, "local." ) == 0 )
518 err
= self
->DecodeDomainName( replyDomain
, decoded
);
519 require_noerr( err
, exit
);
521 // Remove trailing '.'
523 decoded
.TrimRight( '.' );
525 if ( flags
& kDNSServiceFlagsAdd
)
527 if ( self
->GetActivePage() == &self
->m_secondPage
)
529 self
->m_secondPage
.OnAddRegistrationDomain( decoded
);
532 self
->m_regDomains
.push_back( decoded
);
536 if ( self
->GetActivePage() == &self
->m_secondPage
)
538 self
->m_secondPage
.OnRemoveRegistrationDomain( decoded
);
541 self
->m_regDomains
.remove( decoded
);
550 //---------------------------------------------------------------------------------------------------------------------------
551 // CConfigPropertySheet::WatchRegistry
552 //---------------------------------------------------------------------------------------------------------------------------
555 CConfigPropertySheet::WatchRegistry ( LPVOID inParam
)
559 CConfigPropertySheet
* self
= reinterpret_cast<CConfigPropertySheet
*>(inParam
);
564 RegNotifyChangeKeyValue( self
->m_statusKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, NULL
, FALSE
);
566 EnterCriticalSection( &self
->m_lock
);
568 done
= ( self
->m_statusKey
== NULL
) ? true : false;
572 self
->PostMessage( WM_REGISTRYCHANGED
, 0, 0 );
575 LeaveCriticalSection( &self
->m_lock
);
578 SetEvent( self
->m_threadExited
);