]> git.saurik.com Git - apple/mdnsresponder.git/blobdiff - mDNSWindows/ControlPanel/ConfigPropertySheet.cpp
mDNSResponder-107.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / ControlPanel / ConfigPropertySheet.cpp
diff --git a/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp b/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp
new file mode 100755 (executable)
index 0000000..07160cf
--- /dev/null
@@ -0,0 +1,578 @@
+/*
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+$Log: ConfigPropertySheet.cpp,v $
+Revision 1.3  2005/03/03 19:55:22  shersche
+<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
+
+
+*/
+
+#include "ConfigPropertySheet.h"
+#include <WinServices.h>
+#include <process.h>
+
+// Custom events
+
+#define WM_DATAREADY           ( WM_USER + 0x100 )
+#define WM_REGISTRYCHANGED     ( WM_USER + 0x101 )
+
+
+IMPLEMENT_DYNCREATE(CConfigPropertySheet, CPropertySheet)
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::CConfigPropertySheet
+//---------------------------------------------------------------------------------------------------------------------------
+
+CConfigPropertySheet::CConfigPropertySheet()
+:
+       CPropertySheet(),
+       m_browseDomainsRef( NULL ),
+       m_regDomainsRef( NULL ),
+       m_thread( NULL ),
+       m_threadExited( NULL )
+{
+       AddPage(&m_firstPage);
+       AddPage(&m_secondPage);
+       AddPage(&m_thirdPage);
+
+       InitializeCriticalSection( &m_lock );
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::~CConfigPropertySheet
+//---------------------------------------------------------------------------------------------------------------------------
+
+CConfigPropertySheet::~CConfigPropertySheet()
+{
+       DeleteCriticalSection( &m_lock );
+}
+
+
+BEGIN_MESSAGE_MAP(CConfigPropertySheet, CPropertySheet)
+       //{{AFX_MSG_MAP(CConfigPropertySheet)
+       //}}AFX_MSG_MAP
+       ON_MESSAGE( WM_DATAREADY, OnDataReady )
+       ON_MESSAGE( WM_REGISTRYCHANGED, OnRegistryChanged )
+END_MESSAGE_MAP()
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::OnInitDialog
+//---------------------------------------------------------------------------------------------------------------------------
+
+BOOL
+CConfigPropertySheet::OnInitDialog()
+{
+       OSStatus err;
+
+       BOOL b = CPropertySheet::OnInitDialog();
+
+       err = SetupBrowsing();
+       require_noerr( err, exit );
+
+       err = SetupRegistryNotifications();
+       require_noerr( err, exit );     
+
+exit:
+
+       return b;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::OnCommand
+//---------------------------------------------------------------------------------------------------------------------------
+
+BOOL
+CConfigPropertySheet::OnCommand(WPARAM wParam, LPARAM lParam)
+{
+   // Check if OK or Cancel was hit
+
+   if ( ( wParam == ID_WIZFINISH ) || ( wParam == IDOK ) || ( wParam == IDCANCEL ) ) 
+   {
+      OnEndDialog();
+   }
+
+   return CPropertySheet::OnCommand(wParam, lParam);
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::OnDataReady
+//---------------------------------------------------------------------------------------------------------------------------
+
+LONG
+CConfigPropertySheet::OnDataReady(WPARAM inWParam, LPARAM inLParam)
+{
+       if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
+       {
+               dlog( kDebugLevelError, "OnSocket: window error\n" );
+       }
+       else
+       {
+               SOCKET sock = (SOCKET) inWParam;
+
+               if ( m_browseDomainsRef && DNSServiceRefSockFD( m_browseDomainsRef ) == (int) sock )
+               {
+                       DNSServiceProcessResult( m_browseDomainsRef );
+               }
+               else if ( m_regDomainsRef && DNSServiceRefSockFD( m_regDomainsRef ) == (int) sock )
+               {
+                       DNSServiceProcessResult( m_regDomainsRef );
+               }
+       }
+
+       return 0;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::OnRegistryChanged
+//---------------------------------------------------------------------------------------------------------------------------
+
+afx_msg LONG
+CConfigPropertySheet::OnRegistryChanged( WPARAM inWParam, LPARAM inLParam )
+{
+       DEBUG_UNUSED( inWParam );
+       DEBUG_UNUSED( inLParam );
+
+       if ( GetActivePage() == &m_firstPage )
+       {
+               m_firstPage.OnRegistryChanged();
+       }
+
+       return 0;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::OnEndDialog
+//---------------------------------------------------------------------------------------------------------------------------
+
+void
+CConfigPropertySheet::OnEndDialog()
+{
+       OSStatus err;
+
+       err = TearDownRegistryNotifications();
+       check_noerr( err );
+
+       err = TearDownBrowsing();
+       check_noerr( err );
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::SetupBrowsing
+//---------------------------------------------------------------------------------------------------------------------------
+
+OSStatus
+CConfigPropertySheet::SetupBrowsing()
+{
+       OSStatus err;
+
+       // Start browsing for browse domains
+
+       err = DNSServiceEnumerateDomains( &m_browseDomainsRef, kDNSServiceFlagsBrowseDomains, 0, BrowseDomainsReply, this );
+       require_noerr( err, exit );
+
+       err = WSAAsyncSelect( DNSServiceRefSockFD( m_browseDomainsRef ), m_hWnd, WM_DATAREADY, FD_READ|FD_CLOSE );
+       require_noerr( err, exit );
+
+       // Start browsing for registration domains
+
+       err = DNSServiceEnumerateDomains( &m_regDomainsRef, kDNSServiceFlagsRegistrationDomains, 0, RegDomainsReply, this );
+       require_noerr( err, exit );
+
+       err = WSAAsyncSelect( DNSServiceRefSockFD( m_regDomainsRef ), m_hWnd, WM_DATAREADY, FD_READ|FD_CLOSE );
+       require_noerr( err, exit );
+
+exit:
+
+       if ( err )
+       {
+               TearDownBrowsing();
+       }
+
+       return err;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::TearDownBrowsing
+//---------------------------------------------------------------------------------------------------------------------------
+
+OSStatus
+CConfigPropertySheet::TearDownBrowsing()
+{
+       OSStatus err = kNoErr;
+
+       if ( m_browseDomainsRef )
+       {
+               err = WSAAsyncSelect( DNSServiceRefSockFD( m_browseDomainsRef ), m_hWnd, 0, 0 );
+               check_noerr( err );
+
+               DNSServiceRefDeallocate( m_browseDomainsRef );
+       
+               m_browseDomainsRef = NULL;
+       }
+
+       if ( m_regDomainsRef )
+       {
+               err = WSAAsyncSelect( DNSServiceRefSockFD( m_regDomainsRef ), m_hWnd, 0, 0 );
+               check_noerr( err );
+
+               DNSServiceRefDeallocate( m_regDomainsRef );
+       
+               m_regDomainsRef = NULL;
+       }
+
+       return err;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::SetupRegistryNotifications
+//---------------------------------------------------------------------------------------------------------------------------
+
+OSStatus
+CConfigPropertySheet::SetupRegistryNotifications()
+{
+       unsigned int    threadId;
+       OSStatus                err;
+
+       check( m_threadExited == NULL );
+       check( m_thread == NULL );
+
+       err = RegCreateKey( HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\" kServiceName L"\\Parameters\\DynDNS\\State\\Hostnames", &m_statusKey );
+       require_noerr( err, exit );
+       
+       m_threadExited = CreateEvent( NULL, FALSE, FALSE, NULL );
+       err = translate_errno( m_threadExited, (OSStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+       // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time 
+       // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
+       
+       m_thread = (HANDLE) _beginthreadex_compat( NULL, 0, WatchRegistry, this, 0, &threadId );
+       err = translate_errno( m_thread, (OSStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+exit:
+
+       if ( err )
+       {
+               TearDownRegistryNotifications();
+       }
+
+       return err;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::TearDownRegistryNotifications
+//---------------------------------------------------------------------------------------------------------------------------
+
+OSStatus
+CConfigPropertySheet::TearDownRegistryNotifications()
+{
+       OSStatus err = kNoErr;
+
+       if ( m_statusKey )
+       {
+               EnterCriticalSection( &m_lock );
+
+               RegCloseKey( m_statusKey );
+               m_statusKey = NULL;
+
+               LeaveCriticalSection( &m_lock );
+       }
+
+       if ( m_threadExited )
+       {
+               err = WaitForSingleObject( m_threadExited, 5 * 1000 );
+               require_noerr( err, exit );
+       }
+
+exit:
+
+       if ( m_threadExited )
+       {
+               CloseHandle( m_threadExited );
+               m_threadExited = NULL;
+       }
+
+       if ( m_thread )
+       {
+               CloseHandle( m_thread );
+               m_thread = NULL;
+       }
+
+       return err;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::DecodeDomainName
+//---------------------------------------------------------------------------------------------------------------------------
+
+OSStatus
+CConfigPropertySheet::DecodeDomainName( const char * raw, CString & decoded )
+{
+       char nextLabel[128] = "\0";
+       char decodedDomainString[kDNSServiceMaxDomainName];
+    char * buffer = (char *) raw;
+    int labels = 0, i;
+    char text[64];
+       const char *label[128];
+       OSStatus        err;
+    
+       // Initialize
+
+       decodedDomainString[0] = '\0';
+
+    // Count the labels
+
+       while ( *buffer )
+       {
+               label[labels++] = buffer;
+               buffer = (char *) GetNextLabel(buffer, text);
+    }
+        
+    buffer = (char*) raw;
+
+    for (i = 0; i < labels; i++)
+       {
+               buffer = (char *)GetNextLabel(buffer, nextLabel);
+        strcat(decodedDomainString, nextLabel);
+        strcat(decodedDomainString, ".");
+    }
+    
+    // Remove trailing dot from domain name.
+    
+       decodedDomainString[ strlen( decodedDomainString ) - 1 ] = '\0';
+
+       // Convert to Unicode
+
+       err = UTF8StringToStringObject( decodedDomainString, decoded );
+
+       return err;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::GetNextLabel
+//---------------------------------------------------------------------------------------------------------------------------
+
+const char*
+CConfigPropertySheet::GetNextLabel( const char * cstr, char label[64] )
+{
+       char *ptr = label;
+       while (*cstr && *cstr != '.')                                                           // While we have characters in the label...
+               {
+               char c = *cstr++;
+               if (c == '\\')
+                       {
+                       c = *cstr++;
+                       if (isdigit(cstr[-1]) && isdigit(cstr[0]) && isdigit(cstr[1]))
+                               {
+                               int v0 = cstr[-1] - '0';                                                // then interpret as three-digit decimal
+                               int v1 = cstr[ 0] - '0';
+                               int v2 = cstr[ 1] - '0';
+                               int val = v0 * 100 + v1 * 10 + v2;
+                               if (val <= 255) { c = (char)val; cstr += 2; }   // If valid three-digit decimal value, use it
+                               }
+                       }
+               *ptr++ = c;
+               if (ptr >= label+64) return(NULL);
+               }
+       if (*cstr) cstr++;                                                                                      // Skip over the trailing dot (if present)
+       *ptr++ = 0;
+       return(cstr);
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::BrowseDomainsReply
+//---------------------------------------------------------------------------------------------------------------------------
+
+void DNSSD_API
+CConfigPropertySheet::BrowseDomainsReply
+                                                       (
+                                                       DNSServiceRef                   sdRef,
+                                                       DNSServiceFlags                 flags,
+                                                       uint32_t                                interfaceIndex,
+                                                       DNSServiceErrorType             errorCode,
+                                                       const char                      *       replyDomain,
+                                                       void                            *       context
+                                                       )
+{
+       CConfigPropertySheet    *       self = reinterpret_cast<CConfigPropertySheet*>(context);
+       CString                                         decoded;
+       OSStatus                                        err;
+
+       DEBUG_UNUSED( sdRef );
+       DEBUG_UNUSED( interfaceIndex );
+
+       if ( errorCode )
+       {
+               goto exit;
+       }
+
+       check( replyDomain );
+       
+       // Ignore local domains
+
+       if ( strcmp( replyDomain, "local." ) == 0 )
+       {
+               goto exit;
+       }
+
+
+
+       err = self->DecodeDomainName( replyDomain, decoded );
+       require_noerr( err, exit );
+
+       // Remove trailing '.'
+
+       decoded.TrimRight( '.' );
+
+       if ( flags & kDNSServiceFlagsAdd )
+       {
+               self->m_browseDomains.push_back( decoded );
+       }
+       else
+       {
+               self->m_browseDomains.remove( decoded );
+       }
+
+exit:
+
+       return;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::RegDomainsReply
+//---------------------------------------------------------------------------------------------------------------------------
+
+void DNSSD_API
+CConfigPropertySheet::RegDomainsReply
+                                                       (
+                                                       DNSServiceRef                   sdRef,
+                                                       DNSServiceFlags                 flags,
+                                                       uint32_t                                interfaceIndex,
+                                                       DNSServiceErrorType             errorCode,
+                                                       const char                      *       replyDomain,
+                                                       void                            *       context
+                                                       )
+{
+       CConfigPropertySheet    *       self = reinterpret_cast<CConfigPropertySheet*>(context);
+       CString                                         decoded;
+       OSStatus                                        err;
+
+       DEBUG_UNUSED( sdRef );
+       DEBUG_UNUSED( interfaceIndex );
+
+       if ( errorCode )
+       {
+               goto exit;
+       }
+
+       check( replyDomain );
+       
+       // Ignore local domains
+
+       if ( strcmp( replyDomain, "local." ) == 0 )
+       {
+               goto exit;
+       }
+
+       err = self->DecodeDomainName( replyDomain, decoded );
+       require_noerr( err, exit );
+
+       // Remove trailing '.'
+
+       decoded.TrimRight( '.' );
+
+       if ( flags & kDNSServiceFlagsAdd )
+       {
+               if ( self->GetActivePage() == &self->m_secondPage )
+               {
+                       self->m_secondPage.OnAddRegistrationDomain( decoded );
+               }
+
+               self->m_regDomains.push_back( decoded );
+       }
+       else
+       {
+               if ( self->GetActivePage() == &self->m_secondPage )
+               {
+                       self->m_secondPage.OnRemoveRegistrationDomain( decoded );
+               }
+
+               self->m_regDomains.remove( decoded );
+       }
+
+exit:
+
+       return;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CConfigPropertySheet::WatchRegistry
+//---------------------------------------------------------------------------------------------------------------------------
+
+unsigned WINAPI
+CConfigPropertySheet::WatchRegistry ( LPVOID inParam )
+{
+       bool done = false;
+
+       CConfigPropertySheet * self = reinterpret_cast<CConfigPropertySheet*>(inParam);
+       check( self );
+
+       while ( !done )
+       {
+               RegNotifyChangeKeyValue( self->m_statusKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, NULL, FALSE );
+
+               EnterCriticalSection( &self->m_lock );
+
+               done = ( self->m_statusKey == NULL ) ? true : false;
+
+               if ( !done )
+               {
+                       self->PostMessage( WM_REGISTRYCHANGED, 0, 0 );
+               }
+
+               LeaveCriticalSection( &self->m_lock );
+       }
+
+       SetEvent( self->m_threadExited );
+
+       return 0;
+}