1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 Change History (most recent first):
19 $Log: ConfigPropertySheet.cpp,v $
20 Revision 1.5 2006/08/14 23:25:28 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
23 Revision 1.4 2005/10/05 20:46:50 herscher
24 <rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
26 Revision 1.3 2005/03/03 19:55:22 shersche
27 <rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
32 #include "ConfigPropertySheet.h"
33 #include <WinServices.h>
38 #define WM_DATAREADY ( WM_USER + 0x100 )
39 #define WM_REGISTRYCHANGED ( WM_USER + 0x101 )
42 IMPLEMENT_DYNCREATE(CConfigPropertySheet
, CPropertySheet
)
45 //---------------------------------------------------------------------------------------------------------------------------
46 // CConfigPropertySheet::CConfigPropertySheet
47 //---------------------------------------------------------------------------------------------------------------------------
49 CConfigPropertySheet::CConfigPropertySheet()
52 m_browseDomainsRef( NULL
),
53 m_regDomainsRef( NULL
),
55 m_threadExited( NULL
)
57 AddPage(&m_firstPage
);
58 AddPage(&m_secondPage
);
59 AddPage(&m_thirdPage
);
61 InitializeCriticalSection( &m_lock
);
65 //---------------------------------------------------------------------------------------------------------------------------
66 // CConfigPropertySheet::~CConfigPropertySheet
67 //---------------------------------------------------------------------------------------------------------------------------
69 CConfigPropertySheet::~CConfigPropertySheet()
71 DeleteCriticalSection( &m_lock
);
75 BEGIN_MESSAGE_MAP(CConfigPropertySheet
, CPropertySheet
)
76 //{{AFX_MSG_MAP(CConfigPropertySheet)
78 ON_MESSAGE( WM_DATAREADY
, OnDataReady
)
79 ON_MESSAGE( WM_REGISTRYCHANGED
, OnRegistryChanged
)
83 //---------------------------------------------------------------------------------------------------------------------------
84 // CConfigPropertySheet::OnInitDialog
85 //---------------------------------------------------------------------------------------------------------------------------
88 CConfigPropertySheet::OnInitDialog()
92 BOOL b
= CPropertySheet::OnInitDialog();
94 err
= SetupBrowsing();
95 require_noerr( err
, exit
);
97 err
= SetupRegistryNotifications();
98 require_noerr( err
, exit
);
106 //---------------------------------------------------------------------------------------------------------------------------
107 // CConfigPropertySheet::OnCommand
108 //---------------------------------------------------------------------------------------------------------------------------
111 CConfigPropertySheet::OnCommand(WPARAM wParam
, LPARAM lParam
)
113 // Check if OK or Cancel was hit
115 if ( ( wParam
== ID_WIZFINISH
) || ( wParam
== IDOK
) || ( wParam
== IDCANCEL
) )
120 return CPropertySheet::OnCommand(wParam
, lParam
);
124 //---------------------------------------------------------------------------------------------------------------------------
125 // CConfigPropertySheet::OnDataReady
126 //---------------------------------------------------------------------------------------------------------------------------
129 CConfigPropertySheet::OnDataReady(WPARAM inWParam
, LPARAM inLParam
)
131 if (WSAGETSELECTERROR(inLParam
) && !(HIWORD(inLParam
)))
133 dlog( kDebugLevelError
, "OnSocket: window error\n" );
137 SOCKET sock
= (SOCKET
) inWParam
;
139 if ( m_browseDomainsRef
&& DNSServiceRefSockFD( m_browseDomainsRef
) == (int) sock
)
141 DNSServiceProcessResult( m_browseDomainsRef
);
143 else if ( m_regDomainsRef
&& DNSServiceRefSockFD( m_regDomainsRef
) == (int) sock
)
145 DNSServiceProcessResult( m_regDomainsRef
);
153 //---------------------------------------------------------------------------------------------------------------------------
154 // CConfigPropertySheet::OnRegistryChanged
155 //---------------------------------------------------------------------------------------------------------------------------
158 CConfigPropertySheet::OnRegistryChanged( WPARAM inWParam
, LPARAM inLParam
)
160 DEBUG_UNUSED( inWParam
);
161 DEBUG_UNUSED( inLParam
);
163 if ( GetActivePage() == &m_firstPage
)
165 m_firstPage
.OnRegistryChanged();
172 //---------------------------------------------------------------------------------------------------------------------------
173 // CConfigPropertySheet::OnEndDialog
174 //---------------------------------------------------------------------------------------------------------------------------
177 CConfigPropertySheet::OnEndDialog()
181 err
= TearDownRegistryNotifications();
184 err
= TearDownBrowsing();
189 //---------------------------------------------------------------------------------------------------------------------------
190 // CConfigPropertySheet::SetupBrowsing
191 //---------------------------------------------------------------------------------------------------------------------------
194 CConfigPropertySheet::SetupBrowsing()
198 // Start browsing for browse domains
200 err
= DNSServiceEnumerateDomains( &m_browseDomainsRef
, kDNSServiceFlagsBrowseDomains
, 0, BrowseDomainsReply
, this );
201 require_noerr( err
, exit
);
203 err
= WSAAsyncSelect( DNSServiceRefSockFD( m_browseDomainsRef
), m_hWnd
, WM_DATAREADY
, FD_READ
|FD_CLOSE
);
204 require_noerr( err
, exit
);
206 // Start browsing for registration domains
208 err
= DNSServiceEnumerateDomains( &m_regDomainsRef
, kDNSServiceFlagsRegistrationDomains
, 0, RegDomainsReply
, this );
209 require_noerr( err
, exit
);
211 err
= WSAAsyncSelect( DNSServiceRefSockFD( m_regDomainsRef
), m_hWnd
, WM_DATAREADY
, FD_READ
|FD_CLOSE
);
212 require_noerr( err
, exit
);
225 //---------------------------------------------------------------------------------------------------------------------------
226 // CConfigPropertySheet::TearDownBrowsing
227 //---------------------------------------------------------------------------------------------------------------------------
230 CConfigPropertySheet::TearDownBrowsing()
232 OSStatus err
= kNoErr
;
234 if ( m_browseDomainsRef
)
236 err
= WSAAsyncSelect( DNSServiceRefSockFD( m_browseDomainsRef
), m_hWnd
, 0, 0 );
239 DNSServiceRefDeallocate( m_browseDomainsRef
);
241 m_browseDomainsRef
= NULL
;
244 if ( m_regDomainsRef
)
246 err
= WSAAsyncSelect( DNSServiceRefSockFD( m_regDomainsRef
), m_hWnd
, 0, 0 );
249 DNSServiceRefDeallocate( m_regDomainsRef
);
251 m_regDomainsRef
= NULL
;
258 //---------------------------------------------------------------------------------------------------------------------------
259 // CConfigPropertySheet::SetupRegistryNotifications
260 //---------------------------------------------------------------------------------------------------------------------------
263 CConfigPropertySheet::SetupRegistryNotifications()
265 unsigned int threadId
;
268 check( m_threadExited
== NULL
);
269 check( m_thread
== NULL
);
271 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode L
"\\DynDNS\\State\\Hostnames", &m_statusKey
);
272 require_noerr( err
, exit
);
274 m_threadExited
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
275 err
= translate_errno( m_threadExited
, (OSStatus
) GetLastError(), kUnknownErr
);
276 require_noerr( err
, exit
);
278 // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time
279 // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
281 m_thread
= (HANDLE
) _beginthreadex_compat( NULL
, 0, WatchRegistry
, this, 0, &threadId
);
282 err
= translate_errno( m_thread
, (OSStatus
) GetLastError(), kUnknownErr
);
283 require_noerr( err
, exit
);
289 TearDownRegistryNotifications();
296 //---------------------------------------------------------------------------------------------------------------------------
297 // CConfigPropertySheet::TearDownRegistryNotifications
298 //---------------------------------------------------------------------------------------------------------------------------
301 CConfigPropertySheet::TearDownRegistryNotifications()
303 OSStatus err
= kNoErr
;
307 EnterCriticalSection( &m_lock
);
309 RegCloseKey( m_statusKey
);
312 LeaveCriticalSection( &m_lock
);
315 if ( m_threadExited
)
317 err
= WaitForSingleObject( m_threadExited
, 5 * 1000 );
318 require_noerr( err
, exit
);
323 if ( m_threadExited
)
325 CloseHandle( m_threadExited
);
326 m_threadExited
= NULL
;
331 CloseHandle( m_thread
);
339 //---------------------------------------------------------------------------------------------------------------------------
340 // CConfigPropertySheet::DecodeDomainName
341 //---------------------------------------------------------------------------------------------------------------------------
344 CConfigPropertySheet::DecodeDomainName( const char * raw
, CString
& decoded
)
346 char nextLabel
[128] = "\0";
347 char decodedDomainString
[kDNSServiceMaxDomainName
];
348 char * buffer
= (char *) raw
;
351 const char *label
[128];
356 decodedDomainString
[0] = '\0';
362 label
[labels
++] = buffer
;
363 buffer
= (char *) GetNextLabel(buffer
, text
);
366 buffer
= (char*) raw
;
368 for (i
= 0; i
< labels
; i
++)
370 buffer
= (char *)GetNextLabel(buffer
, nextLabel
);
371 strcat(decodedDomainString
, nextLabel
);
372 strcat(decodedDomainString
, ".");
375 // Remove trailing dot from domain name.
377 decodedDomainString
[ strlen( decodedDomainString
) - 1 ] = '\0';
379 // Convert to Unicode
381 err
= UTF8StringToStringObject( decodedDomainString
, decoded
);
387 //---------------------------------------------------------------------------------------------------------------------------
388 // CConfigPropertySheet::GetNextLabel
389 //---------------------------------------------------------------------------------------------------------------------------
392 CConfigPropertySheet::GetNextLabel( const char * cstr
, char label
[64] )
395 while (*cstr
&& *cstr
!= '.') // While we have characters in the label...
401 if (isdigit(cstr
[-1]) && isdigit(cstr
[0]) && isdigit(cstr
[1]))
403 int v0
= cstr
[-1] - '0'; // then interpret as three-digit decimal
404 int v1
= cstr
[ 0] - '0';
405 int v2
= cstr
[ 1] - '0';
406 int val
= v0
* 100 + v1
* 10 + v2
;
407 if (val
<= 255) { c
= (char)val
; cstr
+= 2; } // If valid three-digit decimal value, use it
411 if (ptr
>= label
+64) return(NULL
);
413 if (*cstr
) cstr
++; // Skip over the trailing dot (if present)
419 //---------------------------------------------------------------------------------------------------------------------------
420 // CConfigPropertySheet::BrowseDomainsReply
421 //---------------------------------------------------------------------------------------------------------------------------
424 CConfigPropertySheet::BrowseDomainsReply
427 DNSServiceFlags flags
,
428 uint32_t interfaceIndex
,
429 DNSServiceErrorType errorCode
,
430 const char * replyDomain
,
434 CConfigPropertySheet
* self
= reinterpret_cast<CConfigPropertySheet
*>(context
);
438 DEBUG_UNUSED( sdRef
);
439 DEBUG_UNUSED( interfaceIndex
);
446 check( replyDomain
);
448 // Ignore local domains
450 if ( strcmp( replyDomain
, "local." ) == 0 )
457 err
= self
->DecodeDomainName( replyDomain
, decoded
);
458 require_noerr( err
, exit
);
460 // Remove trailing '.'
462 decoded
.TrimRight( '.' );
464 if ( flags
& kDNSServiceFlagsAdd
)
466 self
->m_browseDomains
.push_back( decoded
);
470 self
->m_browseDomains
.remove( decoded
);
479 //---------------------------------------------------------------------------------------------------------------------------
480 // CConfigPropertySheet::RegDomainsReply
481 //---------------------------------------------------------------------------------------------------------------------------
484 CConfigPropertySheet::RegDomainsReply
487 DNSServiceFlags flags
,
488 uint32_t interfaceIndex
,
489 DNSServiceErrorType errorCode
,
490 const char * replyDomain
,
494 CConfigPropertySheet
* self
= reinterpret_cast<CConfigPropertySheet
*>(context
);
498 DEBUG_UNUSED( sdRef
);
499 DEBUG_UNUSED( interfaceIndex
);
506 check( replyDomain
);
508 // Ignore local domains
510 if ( strcmp( replyDomain
, "local." ) == 0 )
515 err
= self
->DecodeDomainName( replyDomain
, decoded
);
516 require_noerr( err
, exit
);
518 // Remove trailing '.'
520 decoded
.TrimRight( '.' );
522 if ( flags
& kDNSServiceFlagsAdd
)
524 if ( self
->GetActivePage() == &self
->m_secondPage
)
526 self
->m_secondPage
.OnAddRegistrationDomain( decoded
);
529 self
->m_regDomains
.push_back( decoded
);
533 if ( self
->GetActivePage() == &self
->m_secondPage
)
535 self
->m_secondPage
.OnRemoveRegistrationDomain( decoded
);
538 self
->m_regDomains
.remove( decoded
);
547 //---------------------------------------------------------------------------------------------------------------------------
548 // CConfigPropertySheet::WatchRegistry
549 //---------------------------------------------------------------------------------------------------------------------------
552 CConfigPropertySheet::WatchRegistry ( LPVOID inParam
)
556 CConfigPropertySheet
* self
= reinterpret_cast<CConfigPropertySheet
*>(inParam
);
561 RegNotifyChangeKeyValue( self
->m_statusKey
, TRUE
, REG_NOTIFY_CHANGE_LAST_SET
, NULL
, FALSE
);
563 EnterCriticalSection( &self
->m_lock
);
565 done
= ( self
->m_statusKey
== NULL
) ? true : false;
569 self
->PostMessage( WM_REGISTRYCHANGED
, 0, 0 );
572 LeaveCriticalSection( &self
->m_lock
);
575 SetEvent( self
->m_threadExited
);