#include "precomp.h" #include "resource.h" #include "pfnwininet.h" #include "pfnsetupapi.h" #include "AutoConf.h" #include "ConfUtil.h" // File level globals CAutoConf * g_pAutoConf = NULL; void CAutoConf::DoIt( void ) { RegEntry re(POLICIES_KEY, HKEY_CURRENT_USER); if( !re.GetNumber(REGVAL_AUTOCONF_USE, DEFAULT_AUTOCONF_USE ) ) { TRACE_OUT(( TEXT("AutoConf: Not using autoconfiguration"))); return; } LPTSTR szAutoConfServer = re.GetString( REGVAL_AUTOCONF_CONFIGFILE ); if( NULL == szAutoConfServer ) { WARNING_OUT(( TEXT("AutoConf: AutoConf server is unset") )); DisplayErrMsg( IDS_AUTOCONF_SERVERNAME_MISSING ); return; } g_pAutoConf = new CAutoConf( szAutoConfServer ); ASSERT( g_pAutoConf ); if( !g_pAutoConf->OpenConnection() ) { WARNING_OUT(( TEXT("AutoConf: Connect to net failed") )); DisplayErrMsg( IDS_AUTOCONF_FAILED ); goto cleanup; } if( NULL == g_pAutoConf->m_hOpenUrl ) { WARNING_OUT(( TEXT("AutoConf: g_pAutoConf->m_hOpenUrl = NULL") )); DisplayErrMsg( IDS_AUTOCONF_FAILED ); goto cleanup; } if( FALSE == g_pAutoConf->GetFile() ) { WARNING_OUT(( TEXT("AutoConf: g_pAutoConf->GetFile() == FALSE") )); DisplayErrMsg( IDS_AUTOCONF_FAILED ); goto cleanup; } if( FALSE == g_pAutoConf->QueryData() ) { WARNING_OUT(( TEXT("AutoConf: g_pAutoConf->QueryData() == FALSE") )); DisplayErrMsg( IDS_AUTOCONF_FAILED ); goto cleanup; } if( FAILED( SETUPAPI::Init() ) ) { WARNING_OUT(( TEXT("AutoConf: Setupapi's failed to init") )); DisplayErrMsg( IDS_AUTOCONF_NEED_SETUPAPIS ); goto cleanup; } if( !g_pAutoConf->ParseFile() ) { WARNING_OUT(( TEXT("AutoConf: Could not parse inf file") )); DisplayErrMsg( IDS_AUTOCONF_PARSE_ERROR ); goto cleanup; } TRACE_OUT(( TEXT("AutoConf: FILE PARSED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") )); cleanup: delete g_pAutoConf; return; } CAutoConf::CAutoConf( LPTSTR szServer ) : m_szServer( szServer ), m_hInternet( NULL ), m_hOpenUrl( NULL ), m_dwGrab( 0 ), m_hInf( NULL ), m_hFile( INVALID_HANDLE_VALUE ), m_hEvent( NULL ) { ZeroMemory( m_szFile, CCHMAX( m_szFile ) ); m_hEvent = CreateEvent( NULL, TRUE, FALSE, TEXT( "NMAutoConf_WaitEvent" ) ); RegEntry re(POLICIES_KEY, HKEY_CURRENT_USER); m_dwTimeOut = re.GetNumber(REGVAL_AUTOCONF_TIMEOUT, DEFAULT_AUTOCONF_TIMEOUT ); } CAutoConf::~CAutoConf() { CloseInternet(); if( INVALID_HANDLE_VALUE != m_hFile ) { CloseHandle( m_hFile ); } DeleteFile( m_szFile ); if( NULL != m_hInf ) { SETUPAPI::SetupCloseInfFile( m_hInf ); } //WININET::DeInit(); //SETUPAPI::DeInit(); } BOOL CAutoConf::OpenConnection() { // ASSERT( phInternet ); if( FAILED( WININET::Init() ) ) { WARNING_OUT(( TEXT("AutoConf: WININET::Init failed") )); DisplayErrMsg( IDS_AUTOCONF_NO_WININET ); return FALSE; } ASSERT( NULL != m_szServer ); m_hInternet = WININET::InternetOpen( TEXT("NetMeeting"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, INTERNET_FLAG_ASYNC ); if( NULL == m_hInternet ) { WARNING_OUT(( TEXT( "AutoConf: InternetOpen failed" ) )); return FALSE; } if( INTERNET_INVALID_STATUS_CALLBACK == WININET::InternetSetStatusCallback( m_hInternet, (INTERNET_STATUS_CALLBACK) CAutoConf::InetCallback ) ) { WARNING_OUT(( TEXT("AutoConf: InternetSetStatusCallback failed") )); return FALSE; } m_hOpenUrl = WININET::InternetOpenUrl( m_hInternet, m_szServer, NULL, 0, INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RELOAD, AUTOCONF_CONTEXT_OPENURL ); if( NULL == m_hOpenUrl && ERROR_IO_PENDING != GetLastError() ) { WARNING_OUT(( TEXT("AutoConf: InternetOpenUrl failed") )); return FALSE; } if( WAIT_FAILED == WaitForSingleObject( m_hEvent, m_dwTimeOut ) ) { WARNING_OUT(( TEXT("AutoConf: InternetOpenUrl wait for handle failed") )); return FALSE; } return TRUE; } BOOL CAutoConf::ParseFile() { LPTSTR lstrInstallSection = TEXT("NetMtg.Install.NMRK"); m_hInf = SETUPAPI::SetupOpenInfFile( m_szFile, // name of the INF to open NULL, // optional, the class of the INF file INF_STYLE_WIN4, // specifies the style of the INF file NULL // optional, receives error information ); if( INVALID_HANDLE_VALUE == m_hInf ) { return false; } return SETUPAPI::SetupInstallFromInfSection( NULL, // optional, handle of a parent window m_hInf, // handle to the INF file lstrInstallSection, // name of the Install section SPINST_REGISTRY , // which lines to install from section NULL, // optional, key for registry installs NULL, // optional, path for source files 0, // optional, specifies copy behavior NULL, // optional, specifies callback routine NULL, // optional, callback routine context NULL, // optional, device information set NULL // optional, device info structure ); } BOOL CAutoConf::GetFile() { // ASSERT( INVALID_HANDLE_VALUE == m_hFile ); TCHAR szPath[ MAX_PATH ]; GetTempPath( CCHMAX( szPath ), // size, in characters, of the buffer szPath // pointer to buffer for temp. path ); GetTempFileName( szPath, // pointer to directory name for temporary file TEXT("NMA"), // pointer to filename prefix 0, // number used to create temporary filename m_szFile // pointer to buffer that receives the new filename ); m_hFile = CreateFile( m_szFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY /*| FILE_FLAG_DELETE_ON_CLOSE*/, NULL ); if( INVALID_HANDLE_VALUE == m_hFile ) { WARNING_OUT(( TEXT("AutoConf: AutoConfGetFile returned INVALID_HANDLE_VALUE") )); return FALSE; } return TRUE; } BOOL CAutoConf::QueryData() { ASSERT( NULL != m_hOpenUrl ); m_dwGrab = 0; if (!WININET::InternetQueryDataAvailable( m_hOpenUrl, &m_dwGrab, 0, 0 ) ) { if( ERROR_IO_PENDING != GetLastError() ) { WARNING_OUT(( TEXT("AutoConf: InternetQueryDataAvailable failed") )); return FALSE; } else if( WAIT_FAILED == WaitForSingleObject( m_hEvent, m_dwTimeOut ) ) { WARNING_OUT(( TEXT("AutoConf: InternetQueryDataAvailable wait for data failed") )); return FALSE; } } GrabData(); return TRUE; } BOOL CAutoConf::GrabData() { ASSERT( NULL != m_hOpenUrl ); ASSERT( INVALID_HANDLE_VALUE != m_hFile ); if( !m_dwGrab ) { TRACE_OUT(( TEXT("AutoConf: Finished Reading File") )); CloseHandle( m_hFile ); m_hFile = INVALID_HANDLE_VALUE; return TRUE; } DWORD dwRead; LPTSTR pInetBuffer = new TCHAR[ m_dwGrab + 1]; ASSERT( pInetBuffer ); if( !WININET::InternetReadFile( m_hOpenUrl, (void *)pInetBuffer, m_dwGrab, &dwRead ) )// && ERROR_IO_PENDING != GetLastError() ) { WARNING_OUT(( TEXT("AutoConf: InternetReadFile Failed") )); delete [] pInetBuffer; return FALSE; } else { pInetBuffer[ dwRead ] = '\0'; if( !WriteFile( m_hFile, pInetBuffer, dwRead, &m_dwGrab, NULL ) || dwRead != m_dwGrab ) { WARNING_OUT(( TEXT("AutoConf: WriteFile Failed") )); delete [] pInetBuffer; return FALSE; } } delete [] pInetBuffer; QueryData(); return TRUE; } void CAutoConf::CloseInternet() { HINTERNETKILL( m_hInternet ); HINTERNETKILL( m_hOpenUrl ); } VOID CALLBACK CAutoConf::InetCallback( HINTERNET hInternet, DWORD dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength ) { if( g_pAutoConf != NULL ) { switch( dwInternetStatus ) { case INTERNET_STATUS_REQUEST_COMPLETE: { TRACE_OUT(( TEXT("AutoConf: AutoConfInetCallback::INTERNET_STATUS_REQUEST_COMPLETE") )); if( AUTOCONF_CONTEXT_OPENURL == dwContext && g_pAutoConf->m_hOpenUrl == NULL ) { TRACE_OUT(( TEXT("AutoConf: InternetOpenUrl Finished") )); LPINTERNET_ASYNC_RESULT lpIAR = (LPINTERNET_ASYNC_RESULT)lpvStatusInformation; #ifndef _WIN64 g_pAutoConf->m_hOpenUrl = (HINTERNET)lpIAR->dwResult; #endif SetEvent( g_pAutoConf->m_hEvent ); } else { LPINTERNET_ASYNC_RESULT lpIAR = (LPINTERNET_ASYNC_RESULT)lpvStatusInformation; TRACE_OUT(( TEXT("AutoConf: QueryData returned") )); g_pAutoConf->m_dwGrab = (DWORD)lpIAR->dwResult; SetEvent( g_pAutoConf->m_hEvent ); } break; } #ifdef DEBUG case INTERNET_STATUS_CLOSING_CONNECTION: //Closing the connection to the server. The lpvStatusInformation parameter is NULL. TRACE_OUT(( TEXT("Closing connection\n") ) ); break; case INTERNET_STATUS_CONNECTED_TO_SERVER: //Successfully connected to the socket address (SOCKADDR) pointed to by lpvStatusInformation. TRACE_OUT(( TEXT("Connected to server") ) ); break; case INTERNET_STATUS_CONNECTING_TO_SERVER: //Connecting to the socket address (SOCKADDR) pointed to by lpvStatusInformation. TRACE_OUT(( TEXT("Connecting to server") ) ); break; case INTERNET_STATUS_CONNECTION_CLOSED: //Successfully closed the connection to the server. //The lpvStatusInformation parameter is NULL. TRACE_OUT(( TEXT("Connection Closed") ) ); break; case INTERNET_STATUS_HANDLE_CLOSING: //This handle value is now terminated. TRACE_OUT(( TEXT("Handle value terminated\n") ) ); break; case INTERNET_STATUS_HANDLE_CREATED: //Used by InternetConnect to indicate it has created the new handle. //This lets the application call InternetCloseHandle from another thread, //if the connect is taking too long. TRACE_OUT(( TEXT("Handle created\n") ) ); break; case INTERNET_STATUS_NAME_RESOLVED: //Successfully found the IP address of the name contained in lpvStatusInformation. TRACE_OUT(( TEXT("Resolved name of server") ) ); break; case INTERNET_STATUS_RECEIVING_RESPONSE: //Waiting for the server to respond to a request. //The lpvStatusInformation parameter is NULL. TRACE_OUT(( TEXT("Recieving response\n") ) ); break; case INTERNET_STATUS_REDIRECT: //An HTTP request is about to automatically redirect the request. //The lpvStatusInformation parameter points to the new URL. //At this point, the application can read any data returned by the server with the //redirect response, and can query the response headers. It can also cancel the operation //by closing the handle. This callback is not made if the original request specified //INTERNET_FLAG_NO_AUTO_REDIRECT. TRACE_OUT(( TEXT("Redirected to new server") ) ); break; case INTERNET_STATUS_REQUEST_SENT: //Successfully sent the information request to the server. //The lpvStatusInformation parameter points to a DWORD containing the number of bytes sent. TRACE_OUT(( TEXT("Sent %d bytes in request"), *((DWORD *)lpvStatusInformation) ) ); break; case INTERNET_STATUS_RESOLVING_NAME: //Looking up the IP address of the name contained in lpvStatusInformation. TRACE_OUT(( TEXT("Resolving name") ) ); break; case INTERNET_STATUS_RESPONSE_RECEIVED: //Successfully received a response from the server. //The lpvStatusInformation parameter points to a DWORD containing the number of bytes received. TRACE_OUT(( TEXT("Recieved %d bytes in response\n"), *((DWORD *)lpvStatusInformation) ) ); break; case INTERNET_STATUS_SENDING_REQUEST: //Sending the information request to the server. //The lpvStatusInformation parameter is NULL. TRACE_OUT(( TEXT("Sending request") ) ); break; #endif // DEBUG default: break; } } }