// Copyright (c) 1995, Microsoft Corporation, all rights reserved // // pbook.c // Remote Access Common Dialog APIs // RasPhonebookDlg APIs // // 06/20/95 Steve Cobb #include "rasdlgp.h" // Our private header #include // FileOpen dialog #include // Common dialog resource constants #include // Shortcut file library #define WM_RASEVENT (WM_USER+987) #define WM_NOUSERTIMEOUT (WM_USER+988) #define RAS_SC_IS_BAD_PIN(_err) \ (((_err) == SCARD_W_WRONG_CHV) || ((_err) == SCARD_E_INVALID_CHV)) // In no-user mode this is updated on every mouse or keyboard event by our // window hook. The monitor thread notices and resets it's inactivity // timeout. // DWORD g_cInput = 0; //---------------------------------------------------------------------------- // Help maps //---------------------------------------------------------------------------- static DWORD g_adwDuHelp[] = { CID_DU_ST_Entries, HID_DU_LB_Entries, CID_DU_LB_Entries, HID_DU_LB_Entries, CID_DU_PB_New, HID_DU_PB_New, CID_DU_PB_More, HID_DU_PB_More, CID_DU_PB_Dial, HID_DU_PB_Dial, CID_DU_PB_Close, HID_DU_PB_Close, 0, 0 }; //---------------------------------------------------------------------------- // Local datatypes //---------------------------------------------------------------------------- // Phonebook dialog argument block. // typedef struct _DUARGS { // Caller's arguments to the RAS API. Outputs in 'pApiArgs' are visible // to the API which has the address of same. 'PszPhonebook' is updated if // user changes the phonebook on the Preferences->PhoneList page, though // API is unaware of this. // LPTSTR pszPhonebook; LPTSTR pszEntry; RASPBDLG* pApiArgs; // RAS API return value. Set true if a connection is established within // the dialog. // BOOL fApiResult; } DUARGS; typedef struct _DUCONTEXT { LPTSTR pszPhonebookPath; PBENTRY *pEntry; } DUCONTEXT; // Dial-Up Networking dialog context block. // typedef struct _DUINFO { // Caller's arguments to the RAS API. // DUARGS* pArgs; // Handle of this dialog and some of it's controls. // HWND hwndDlg; HWND hwndPbNew; HWND hwndPbProperties; HWND hwndLbEntries; HWND hwndPbDial; // Global user preference settings read from the Registry. // PBUSER user; // Phonebook settings read from the phonebook file. // PBFILE file; // No logged on user information retrieved via callback. // RASNOUSER* pNoUser; // Set if in "no user before logon" mode. Always the same as the // RASPBDFLAG but here for convenience. // BOOL fNoUser; // Window hooks used to detect user input in the thread. Used only when // 'fNoUser' is set. // HHOOK hhookKeyboard; HHOOK hhookMouse; // TAPI session handle. // HLINEAPP hlineapp; // Handle of the RAS connection associated with the current entry or NULL // if none. // HRASCONN hrasconn; // Connect monitor objects. // HANDLE hThread; HANDLE hEvent; BOOL fAbortMonitor; } DUINFO; //---------------------------------------------------------------------------- // Local prototypes (alphabetically) //---------------------------------------------------------------------------- BOOL DuCommand( IN DUINFO* pInfo, IN WORD wNotification, IN WORD wId, IN HWND hwndCtrl ); VOID DuCreateShortcut( IN DUINFO* pInfo ); LRESULT CALLBACK DuCreateShortcutCallWndRetProc( int code, WPARAM wparam, LPARAM lparam ); INT_PTR CALLBACK DuDlgProc( IN HWND hwnd, IN UINT unMsg, IN WPARAM wparam, IN LPARAM lparam ); VOID DuDeleteSelectedEntry( IN DUINFO* pInfo ); VOID DuDialSelectedEntry( IN DUINFO* pInfo ); VOID DuEditSelectedEntry( IN DUINFO* pInfo ); VOID DuEditSelectedLocation( IN DUINFO* pInfo ); DWORD DuFillLocationList( IN DUINFO* pInfo ); VOID DuFillPreview( IN DUINFO* pInfo ); DWORD DuGetEntry( DUINFO* pInfo, DUCONTEXT* pContext ); TCHAR* DuGetPreview( IN DUINFO* pInfo ); DWORD DuHandleConnectFailure( IN DUINFO* pInfo, IN RASDIALDLG* pDialInfo); VOID DuHangUpSelectedEntry( IN DUINFO* pInfo ); BOOL DuInit( IN HWND hwndDlg, IN DUARGS* pArgs ); LRESULT CALLBACK DuInputHook( IN int nCode, IN WPARAM wparam, IN LPARAM lparam ); LRESULT APIENTRY DuLbEntriesProc( IN HWND hwnd, IN UINT unMsg, IN WPARAM wparam, IN LPARAM lparam ); VOID DuLocationChange( IN DUINFO* pInfo ); DWORD DuMonitorThread( LPVOID pThreadArg ); VOID DuNewEntry( IN DUINFO* pInfo, IN BOOL fClone ); VOID DuOperatorDial( IN DUINFO* pInfo ); LRESULT APIENTRY DuPbMoreProc( IN HWND hwnd, IN UINT unMsg, IN WPARAM wparam, IN LPARAM lparam ); VOID DuPopupMoreMenu( IN DUINFO* pInfo ); VOID DuPreferences( IN DUINFO* pInfo, IN BOOL fLogon ); VOID DuSetup( IN DUINFO* pInfo ); VOID DuStatus( IN DUINFO* pInfo ); VOID DuTerm( IN HWND hwndDlg ); VOID DuUpdateConnectStatus( IN DUINFO* pInfo ); VOID DuUpdateLbEntries( IN DUINFO* pInfo, IN TCHAR* pszEntry ); VOID DuUpdatePreviewAndLocationState( IN DUINFO* pInfo ); VOID DuUpdateTitle( IN DUINFO* pInfo ); VOID DuWriteShortcutFile( IN HWND hwnd, IN TCHAR* pszRnkPath, IN TCHAR* pszPbkPath, IN TCHAR* pszEntry ); DWORD DwGetEapLogonInfo( VOID *pv, EAPLOGONINFO **ppEapLogonInfo ); VOID WINAPI RasPbDlgCallbackThunk( ULONG_PTR ulpId, DWORD dwEvent, LPWSTR pszEntry, LPVOID pArgs ); //---------------------------------------------------------------------------- // External entry points //---------------------------------------------------------------------------- BOOL APIENTRY RasPhonebookDlgA( IN LPSTR lpszPhonebook, IN LPSTR lpszEntry, IN OUT LPRASPBDLGA lpInfo ) // Win32 ANSI entrypoint that displays the Dial-Up Networking dialog, i.e. // the RAS phonebook. 'LpszPhonebook' is the full path the phonebook or // NULL indicating the default phonebook. 'LpszEntry' is the entry to // highlight on entry or NULL to highlight the first entry in the list. // 'LpInfo' is caller's additional input/output parameters. // // Returns true if user establishes a connection, false otherwise. // { WCHAR* pszPhonebookW; WCHAR* pszEntryW; RASPBDLGW infoW; BOOL fStatus; TRACE( "RasPhonebookDlgA" ); if (!lpInfo) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } if (lpInfo->dwSize != sizeof(RASPBDLGA)) { lpInfo->dwError = ERROR_INVALID_SIZE; return FALSE; } // Thunk "A" arguments to "W" arguments. // if (lpszPhonebook) { pszPhonebookW = StrDupTFromAUsingAnsiEncoding( lpszPhonebook ); if (!pszPhonebookW) { lpInfo->dwError = ERROR_NOT_ENOUGH_MEMORY; return FALSE; } } else { pszPhonebookW = NULL; } if (lpszEntry) { pszEntryW = StrDupTFromAUsingAnsiEncoding( lpszEntry ); if (!pszEntryW) { Free0( pszPhonebookW ); lpInfo->dwError = ERROR_NOT_ENOUGH_MEMORY; return FALSE; } } else { pszEntryW = NULL; } // Take advantage of the structures currently having the same size and // layout. Only the callback is different. // ASSERT( sizeof(RASPBDLGA) == sizeof(RASPBDLGW) ); CopyMemory( &infoW, lpInfo, sizeof(infoW) ); if (lpInfo->pCallback) { infoW.dwCallbackId = (ULONG_PTR)lpInfo; infoW.pCallback = RasPbDlgCallbackThunk; } infoW.reserved2 = lpInfo->reserved2; // Thunk to the equivalent "W" API. // fStatus = RasPhonebookDlgW( pszPhonebookW, pszEntryW, &infoW ); Free0( pszPhonebookW ); Free0( pszEntryW ); return fStatus; } VOID WINAPI RasPbDlgCallbackThunk( ULONG_PTR ulpId, DWORD dwEvent, LPWSTR pszEntry, LPVOID pArgs ) // This thunks "W" callbacks to API caller's "A" callback. // { CHAR* pszEntryA; VOID* pArgsA; RASPBDLGA* pInfo; RASNOUSERA nuA; if (dwEvent == RASPBDEVENT_NoUser || dwEvent == RASPBDEVENT_NoUserEdit) { RASNOUSERW* pnuW = (RASNOUSERW* )pArgs; ASSERT( pnuW ); ZeroMemory( &nuA, sizeof(nuA) ); nuA.dwSize = sizeof(nuA); nuA.dwFlags = pnuW->dwFlags; nuA.dwTimeoutMs = pnuW->dwTimeoutMs; StrCpyAFromW(nuA.szUserName, pnuW->szUserName, UNLEN + 1); StrCpyAFromW(nuA.szPassword, pnuW->szPassword, UNLEN + 1); StrCpyAFromW(nuA.szDomain, pnuW->szDomain, UNLEN + 1); pArgsA = &nuA; } else { pArgsA = NULL; } pszEntryA = StrDupAFromT( pszEntry ); pInfo = (RASPBDLGA* )ulpId; pInfo->pCallback( pInfo->dwCallbackId, dwEvent, pszEntryA, pArgsA ); Free0( pszEntryA ); if (dwEvent == RASPBDEVENT_NoUser || dwEvent == RASPBDEVENT_NoUserEdit) { RASNOUSERW* pnuW = (RASNOUSERW* )pArgs; pnuW->dwFlags = nuA.dwFlags; pnuW->dwTimeoutMs = nuA.dwTimeoutMs; StrCpyWFromA(pnuW->szUserName, nuA.szUserName, UNLEN + 1); StrCpyWFromA(pnuW->szPassword, nuA.szPassword, UNLEN + 1); StrCpyWFromA(pnuW->szDomain, nuA.szDomain, UNLEN + 1); ZeroMemory( nuA.szPassword, PWLEN ); } } BOOL APIENTRY RasPhonebookDlgW( IN LPWSTR lpszPhonebook, IN LPWSTR lpszEntry, IN OUT LPRASPBDLGW lpInfo ) // Win32 Unicode entrypoint that displays the Dial-Up Networking dialog, // i.e. the RAS phonebook. 'LpszPhonebook' is the full path the phonebook // or NULL indicating the default phonebook. 'LpszEntry' is the entry to // highlight on entry or NULL to highlight the first entry in the list. // 'LpInfo' is caller's additional input/output parameters. // // Returns true if user establishes a connection, false otherwise. // { INT_PTR nStatus; DUARGS args; TRACE( "RasPhonebookDlgW" ); if (!lpInfo) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } if (lpInfo->dwSize != sizeof(RASPBDLGW)) { lpInfo->dwError = ERROR_INVALID_SIZE; return FALSE; } // Initialize OUT parameters. // lpInfo->dwError = 0; // Initialize dialog argument block. // args.pszPhonebook = lpszPhonebook; args.pszEntry = lpszEntry; args.pApiArgs = lpInfo; args.fApiResult = FALSE; // Run the dialog. // nStatus = DialogBoxParam( g_hinstDll, MAKEINTRESOURCE( DID_DU_DialUpNetworking ), lpInfo->hwndOwner, DuDlgProc, (LPARAM )&args ); if (nStatus == -1) { ErrorDlg( lpInfo->hwndOwner, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL ); lpInfo->dwError = ERROR_UNKNOWN; args.fApiResult = FALSE; } return args.fApiResult; } //---------------------------------------------------------------------------- // Dial-Up Networking dialog // Listed alphabetically following dialog proc //---------------------------------------------------------------------------- INT_PTR CALLBACK DuDlgProc( IN HWND hwnd, IN UINT unMsg, IN WPARAM wparam, IN LPARAM lparam ) // DialogProc callback for the Dial-Up Networking dialog, i.e. the // phonebook dialog. Parameters and return value are as described for // standard windows 'DialogProc's. // { #if 0 TRACE4( "DuDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)", (DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam ); #endif switch (unMsg) { case WM_INITDIALOG: { return DuInit( hwnd, (DUARGS* )lparam ); } case WM_HELP: case WM_CONTEXTMENU: { ContextHelp( g_adwDuHelp, hwnd, unMsg, wparam, lparam ); return TRUE; } case WM_COMMAND: { DUINFO* pInfo = (DUINFO* )GetWindowLongPtr( hwnd, DWLP_USER ); ASSERT( pInfo ); return DuCommand( pInfo, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam ); } case WM_RASEVENT: { DUINFO* pInfo = (DUINFO* )GetWindowLongPtr( hwnd, DWLP_USER ); ASSERT( pInfo ); DuUpdateConnectStatus( pInfo ); break; } case WM_NOUSERTIMEOUT: { DUINFO* pInfo; ULONG ulCallbacksActive; TRACE( "CancelOwnedWindows" ); CancelOwnedWindows( hwnd ); TRACE( "CancelOwnedWindows done" ); ulCallbacksActive = CallbacksActive( 1, NULL ); if (ulCallbacksActive > 0) { TRACE1( "NoUser timeout stall, n=%d", ulCallbacksActive ); PostMessage( hwnd, WM_NOUSERTIMEOUT, wparam, lparam ); return TRUE; } pInfo = (DUINFO* )GetWindowLongPtr( hwnd, DWLP_USER ); if (pInfo) { pInfo->pArgs->pApiArgs->dwError = STATUS_TIMEOUT; } EndDialog( hwnd, TRUE ); CallbacksActive( 0, NULL ); break; } case WM_DESTROY: { DuTerm( hwnd ); /* //We have to wait for Deonb to return us the IID_Dun1 icon //For whistler bug 372078 381099 //Icon returned by GetCurrentIconEntryType() has to be destroyed { HICON hIcon=NULL; //hIcon = (HICON) GetWindowLongPtr(hwnd, GWLP_USERDATA); hIcon = GetProp( hwnd, TEXT("TweakTitleBar_Icon")); ASSERT(hIcon); if( hIcon ) { DestroyIcon(hIcon); } else { TRACE("DuDlgProc:Destroy Icon failed"); } } */ break; } } return FALSE; } BOOL DuCommand( IN DUINFO* pInfo, IN WORD wNotification, IN WORD wId, IN HWND hwndCtrl ) // Called on WM_COMMAND. 'PInfo' is the dialog context. 'WNotification' // is the notification code of the command. 'wId' is the control/menu // identifier of the command. 'HwndCtrl' is the control window handle of // the command. // // Returns true if processed message, false otherwise. // { TRACE3( "DuCommand(n=%d,i=%d,c=$%x)", (DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl ); switch (wId) { case CID_DU_PB_Dial: { if (pInfo->hrasconn) { DuHangUpSelectedEntry( pInfo ); } else { DuDialSelectedEntry( pInfo ); } return TRUE; } case CID_DU_PB_New: { DuNewEntry( pInfo, FALSE ); return TRUE; } case CID_DU_PB_More: { DuEditSelectedEntry( pInfo ); return TRUE; } case CID_DU_LB_Entries: { if (wNotification == CBN_SELCHANGE) { PBENTRY *pEntry; DWORD dwErr = SUCCESS; DUCONTEXT *pContext; pContext = (DUCONTEXT *) ComboBox_GetItemDataPtr( pInfo->hwndLbEntries, ComboBox_GetCurSel(pInfo->hwndLbEntries)); ASSERT(NULL != pContext); if(NULL == pContext) { return TRUE; } // // Update the phonebook information // dwErr = DuGetEntry(pInfo, pContext); if(ERROR_SUCCESS == dwErr) { ComboBox_SetItemData( pInfo->hwndLbEntries, ComboBox_GetCurSel(pInfo->hwndLbEntries), pContext); } else { ComboBox_DeleteString( pInfo->hwndLbEntries, ComboBox_GetCurSel(pInfo->hwndLbEntries) ); } DuUpdateConnectStatus( pInfo ); return TRUE; } break; } case IDCANCEL: case CID_DU_PB_Close: { EndDialog( pInfo->hwndDlg, TRUE ); return TRUE; } } return FALSE; } VOID DuDialSelectedEntry( IN DUINFO* pInfo ) // Called when user presses the "Dial" button. // { DWORD dwErr; BOOL fConnected; BOOL fAutoLogon; TCHAR* pszEbNumber; TCHAR* pszEbPreview; TCHAR* pszOrgPreview; TCHAR* pszOverride; TCHAR* pszEntryName; RASDIALDLG info; INTERNALARGS iargs; PBENTRY* pEntry; DTLNODE *pdtlnode; PBFILE file; DUCONTEXT *pContext; TRACE( "DuDialSelectedEntry" ); // Look up the selected entry. // pContext = (DUCONTEXT *) ComboBox_GetItemDataPtr( pInfo->hwndLbEntries, ComboBox_GetCurSel(pInfo->hwndLbEntries)); if (!pContext) { MsgDlg( pInfo->hwndDlg, SID_NoEntrySelected, NULL ); SetFocus( pInfo->hwndPbNew ); return; } pEntry = pContext->pEntry; if (!pEntry) { MsgDlg( pInfo->hwndDlg, SID_NoEntrySelected, NULL ); SetFocus( pInfo->hwndPbNew ); return; } pszOverride = NULL; pszOrgPreview = NULL; pszEbPreview = NULL; pszEbNumber = NULL; // Set up API argument block. // ZeroMemory( &info, sizeof(info) ); info.dwSize = sizeof(info); info.hwndOwner = pInfo->hwndDlg; // The secret hack to share information already loaded with the entry API. // ZeroMemory( &iargs, sizeof(iargs) ); iargs.pFile = &pInfo->file; iargs.pUser = &pInfo->user; iargs.pNoUser = pInfo->pNoUser; iargs.fNoUser = pInfo->fNoUser; iargs.fForceCloseOnDial = (pInfo->pArgs->pApiArgs->dwFlags & RASPBDFLAG_ForceCloseOnDial); iargs.pvEapInfo = NULL; if(0 != pInfo->pArgs->pApiArgs->reserved2) { DWORD retcode; EAPLOGONINFO *pEapInfo = NULL; retcode = DwGetEapLogonInfo( (VOID *) pInfo->pArgs->pApiArgs->reserved2, &pEapInfo); if(SUCCESS == retcode) { iargs.pvEapInfo = (VOID *) pEapInfo; } } iargs.fMoveOwnerOffDesktop = (iargs.fForceCloseOnDial || pInfo->user.fCloseOnDial); info.reserved = (ULONG_PTR ) &iargs; // Call the Win32 API to run the connect status dialog. Make a copy of // the entry name and auto-logon flag first, because RasDialDlg may // re-read the entry node to pick up RASAPI changes. // pszEntryName = StrDup( pEntry->pszEntryName ); fAutoLogon = pEntry->fAutoLogon; TRACEW1( "RasDialDlg,o=\"%s\"", (pszOverride) ? pszOverride : TEXT("") ); fConnected = RasDialDlg( pContext->pszPhonebookPath, pEntry->pszEntryName, pszOverride, &info ); TRACE1( "RasDialDlg=%d", fConnected ); Free0( pszEbPreview ); Free0( pszOrgPreview ); if(NULL != iargs.pvEapInfo) { Free0(iargs.pvEapInfo); iargs.pvEapInfo = NULL; } if (fConnected) { pInfo->pArgs->fApiResult = TRUE; if (pInfo->pArgs->pApiArgs->pCallback) { RASPBDLGFUNCW pfunc = pInfo->pArgs->pApiArgs->pCallback; if (pInfo->pNoUser && iargs.fNoUserChanged && fAutoLogon) { // Whistler bug 254385 encode password when not being used // Need to Decode password before callback function // Assumed password was encoded previously by DuInit() // DecodePassword( pInfo->pNoUser->szPassword ); TRACE( "Callback(NoUserEdit)" ); pfunc( pInfo->pArgs->pApiArgs->dwCallbackId, RASPBDEVENT_NoUserEdit, NULL, pInfo->pNoUser ); TRACE( "Callback(NoUserEdit) done" ); EncodePassword( pInfo->pNoUser->szPassword ); } TRACE( "Callback(DialEntry)" ); pfunc( pInfo->pArgs->pApiArgs->dwCallbackId, RASPBDEVENT_DialEntry, pszEntryName, NULL ); TRACE( "Callback(DialEntry) done" ); } if (pInfo->user.fCloseOnDial || (pInfo->pArgs->pApiArgs->dwFlags & RASPBDFLAG_ForceCloseOnDial)) { EndDialog( pInfo->hwndDlg, TRUE ); } } else { DuHandleConnectFailure(pInfo, &info); } if (pInfo->pNoUser && !pInfo->hThread) { TRACE( "Taking shortcut to exit" ); return; } // Reload the list even if the Dial was cancelled as user may have changed // the current PBENTRY with the Properties button on the dialer which // commits changes even if user cancels the dial itself. See bug 363710. // DuUpdateLbEntries( pInfo, pszEntryName ); SetFocus( pInfo->hwndLbEntries ); Free0( pszEntryName ); } VOID DuEditSelectedEntry( IN DUINFO* pInfo ) // Called when user selects "Edit entry" from the menu. 'PInfo' is the // dialog context. 'PszEntry' is the name of the entry to edit. // { BOOL fOk; RASENTRYDLG info; INTERNALARGS iargs; PBENTRY* pEntry; LPTSTR pszEntryName; DTLNODE *pdtlnode; PBFILE file; DWORD dwErr; DUCONTEXT *pContext; INT iSel; TRACE( "DuEditSelectedEntry" ); // Look up the selected entry. // iSel = ComboBox_GetCurSel( pInfo->hwndLbEntries ); if (iSel < 0) { return; } pContext = (DUCONTEXT * )ComboBox_GetItemDataPtr( pInfo->hwndLbEntries, iSel ); ASSERT(NULL != pContext); if(NULL == pContext) { return; } ASSERT(NULL != pContext->pszPhonebookPath); pEntry = pContext->pEntry; if (!pEntry) { MsgDlg( pInfo->hwndDlg, SID_NoEntrySelected, NULL ); SetFocus( pInfo->hwndPbNew ); return; } // Set up API argument block. // ZeroMemory( &info, sizeof(info) ); info.dwSize = sizeof(info); info.hwndOwner = pInfo->hwndDlg; { RECT rect; info.dwFlags = RASEDFLAG_PositionDlg; GetWindowRect( pInfo->hwndDlg, &rect ); info.xDlg = rect.left + DXSHEET; info.yDlg = rect.top + DYSHEET; } // The secret hack to share information already loaded with the entry API. // ZeroMemory( &iargs, sizeof(iargs) ); iargs.pFile = &pInfo->file; iargs.pUser = &pInfo->user; iargs.pNoUser = pInfo->pNoUser; iargs.fNoUser = pInfo->fNoUser; info.reserved = (ULONG_PTR ) &iargs; // Call the Win32 API to run the entry property sheet. // TRACE( "RasEntryDlg" ); fOk = RasEntryDlg( pContext->pszPhonebookPath, pEntry->pszEntryName, &info ); TRACE1( "RasEntryDlg=%d", fOk ); if (pInfo->pNoUser && !pInfo->hThread) { TRACE( "Taking shortcut to exit" ); return; } if (fOk) { TRACEW1( "OK pressed,e=\"%s\"", info.szEntry ); if (pInfo->pArgs->pApiArgs->pCallback) { RASPBDLGFUNCW pfunc = pInfo->pArgs->pApiArgs->pCallback; TRACE( "Callback(EditEntry)" ); pfunc( pInfo->pArgs->pApiArgs->dwCallbackId, RASPBDEVENT_AddEntry, info.szEntry, NULL ); TRACE( "Callback(EditEntry) done" ); } DuUpdateLbEntries( pInfo, info.szEntry ); SetFocus( pInfo->hwndLbEntries ); } else { TRACE( "Cancel pressed or error" ); } } // // Helper function called by DuDialSelectedEntry to handle errors // returned from RasDialDlgW // DWORD DuHandleConnectFailure( IN DUINFO* pInfo, IN RASDIALDLG* pDialInfo) { TRACE3( "DuHandleConnectFailure: nu=%x, r2=%x, de=%x", (pInfo->pNoUser), (pInfo->pArgs->pApiArgs->reserved2), (pDialInfo->dwError)); // XP: 384968 // // Handle the bad-PIN error from winlogon // // Normally, the smart card PIN is gotten by calling EAP-TLS's identity // api. This API raises UI and validates the PIN entered. // // During winlogon, however, the smart card PIN is passed to us from GINA. // In this case it is not validated until we call EAP API's. (actually, // it's until we call the eap identity api with RAS_EAP_FLAG_LOGON. // This flag tells EAP not to raise any UI but instead to use the info // passed from GINA) // // GINA is not able to validate the PIN itself because it does not call any // CAPI's directly. Oh well. // // If RasDialDlg returns a bad pin error, then we should gracefully fail // back to winlogon. // if ((pInfo->pNoUser) && // called by winlogon (pInfo->pArgs->pApiArgs->reserved2) && // for smart card (RAS_SC_IS_BAD_PIN(pDialInfo->dwError))) // but pin is bad { pInfo->pArgs->pApiArgs->dwError = pDialInfo->dwError; EndDialog( pInfo->hwndDlg, TRUE ); } return NO_ERROR; } VOID DuHangUpSelectedEntry( IN DUINFO* pInfo ) // Hang up the selected entry after confirming with user. 'Pinfo' is the // dialog context block. // { DWORD dwErr; PBENTRY* pEntry; INT iSel; INT nResponse; MSGARGS msgargs; LPTSTR pszEntryName; DTLNODE *pdtlnode; DUCONTEXT *pContext; TRACE( "DuHangUpSelectedEntry" ); // Look up the selected entry. // iSel = ComboBox_GetCurSel( pInfo->hwndLbEntries ); ASSERT( iSel >= 0 ); pContext = (DUCONTEXT * )ComboBox_GetItemDataPtr( pInfo->hwndLbEntries, iSel ); ASSERT(NULL != pContext); if (!pContext) { MsgDlg( pInfo->hwndDlg, SID_NoEntrySelected, NULL ); SetFocus( pInfo->hwndPbNew ); return; } pEntry = pContext->pEntry; ASSERT( pEntry ); if (!pEntry) { MsgDlg( pInfo->hwndDlg, SID_NoEntrySelected, NULL ); SetFocus( pInfo->hwndPbNew ); return; } ZeroMemory( &msgargs, sizeof(msgargs) ); msgargs.apszArgs[ 0 ] = pEntry->pszEntryName; msgargs.dwFlags = MB_YESNO | MB_ICONEXCLAMATION; nResponse = MsgDlg( pInfo->hwndDlg, SID_ConfirmHangUp, &msgargs ); if (nResponse == IDYES) { ASSERT( g_pRasHangUp ); TRACE( "RasHangUp" ); dwErr = g_pRasHangUp( pInfo->hrasconn ); TRACE1( "RasHangUp=%d", dwErr ); if ( dwErr == ERROR_HANGUP_FAILED ) { MsgDlg( pInfo->hwndDlg, SID_CantHangUpRouter, NULL ); } } } BOOL DuInit( IN HWND hwndDlg, IN DUARGS* pArgs ) // Called on WM_INITDIALOG. 'hwndDlg' is the handle of the phonebook // dialog window. 'pArgs' points at caller's arguments as passed to the // API (or thunk). // // Return false if focus was set, true otherwise, i.e. as defined for // WM_INITDIALOG. // { DWORD dwErr; DWORD dwThreadId; DWORD dwReadPbkFlags = 0; DUINFO* pInfo; TRACE( "DuInit" ); // Allocate the dialog context block. Initialize minimally for proper // cleanup, then attach to the dialog window. // { pInfo = Malloc( sizeof(*pInfo) ); if (!pInfo) { ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL ); pArgs->pApiArgs->dwError = ERROR_NOT_ENOUGH_MEMORY; EndDialog( hwndDlg, TRUE ); return TRUE; } ZeroMemory( pInfo, sizeof(*pInfo) ); pInfo->file.hrasfile = -1; SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo ); TRACE( "Context set" ); } pInfo->pArgs = pArgs; pInfo->hwndDlg = hwndDlg; // Position the dialog per caller's instructions. // PositionDlg( hwndDlg, pArgs->pApiArgs->dwFlags & RASPBDFLAG_PositionDlg, pArgs->pApiArgs->xDlg, pArgs->pApiArgs->yDlg ); // Load RAS DLL entrypoints which starts RASMAN, if necessary. There must // be no API calls that require RASAPI32 or RASMAN prior to this point. // dwErr = LoadRas( g_hinstDll, hwndDlg ); if (dwErr != 0) { ErrorDlg( hwndDlg, SID_OP_LoadRas, dwErr, NULL ); pArgs->pApiArgs->dwError = dwErr; EndDialog( hwndDlg, TRUE ); return TRUE; } if(0 != (pArgs->pApiArgs->dwFlags & RASPBDFLAG_NoUser)) { // Popup TAPI's "first location" dialog if they are uninitialized. // dwErr = TapiNoLocationDlg( g_hinstDll, &pInfo->hlineapp, hwndDlg ); if (dwErr != 0) { // Error here is treated as a "cancel" per bug 288385. // pArgs->pApiArgs->dwError = 0; EndDialog( hwndDlg, TRUE ); return TRUE; } } pInfo->hwndLbEntries = GetDlgItem( hwndDlg, CID_DU_LB_Entries ); ASSERT( pInfo->hwndLbEntries ); pInfo->hwndPbDial = GetDlgItem( hwndDlg, CID_DU_PB_Dial ); ASSERT( pInfo->hwndPbDial ); pInfo->hwndPbNew = GetDlgItem( hwndDlg, CID_DU_PB_New ); ASSERT( pInfo->hwndPbNew ); pInfo->hwndPbProperties = GetDlgItem( hwndDlg, CID_DU_PB_More ); ASSERT( pInfo->hwndPbProperties ); pInfo->fNoUser = (pArgs->pApiArgs->dwFlags & RASPBDFLAG_NoUser ); // Setting this global flag indicates that WinHelp will not work in the // current mode. See common\uiutil\ui.c. We assume here that only the // WinLogon process makes use of this. // { extern BOOL g_fNoWinHelp; g_fNoWinHelp = pInfo->fNoUser; } // Read user preferences from registry. // dwErr = g_pGetUserPreferences( NULL, &pInfo->user, pInfo->fNoUser ? UPM_Logon : UPM_Normal); if (dwErr != 0) { // // The following free causes a crash in DuTerm. This context will be // freed in DuTerm - raos. // // Free( pInfo ); ErrorDlg( hwndDlg, SID_OP_LoadPrefs, dwErr, NULL ); EndDialog( hwndDlg, TRUE ); return TRUE; } // Load and parse phonebook file. // if (pInfo->fNoUser) { dwReadPbkFlags |= RPBF_NoUser; } dwErr = ReadPhonebookFile( pArgs->pszPhonebook, &pInfo->user, NULL, dwReadPbkFlags, &pInfo->file ); if (dwErr != 0) { // The following free causes a crash in DuTerm. This context will be // freed in DuTerm - raos. // // Free( pInfo ); ErrorDlg( hwndDlg, SID_OP_LoadPhonebook, dwErr, NULL ); EndDialog( hwndDlg, TRUE ); return TRUE; } if (pArgs->pApiArgs->pCallback && !pArgs->pszPhonebook) { RASPBDLGFUNCW pfunc = pInfo->pArgs->pApiArgs->pCallback; // Tell user the path to the default phonebook file. // TRACE( "Callback(EditGlobals)" ); pfunc( pInfo->pArgs->pApiArgs->dwCallbackId, RASPBDEVENT_EditGlobals, pInfo->file.pszPath, NULL ); TRACE( "Callback(EditGlobals) done" ); } if (pInfo->fNoUser) { // Retrieve logon information from caller via callback. // if (pArgs->pApiArgs->pCallback) { RASPBDLGFUNCW pfunc = pArgs->pApiArgs->pCallback; pInfo->pNoUser = Malloc( sizeof(RASNOUSERW) ); if (pInfo->pNoUser) { ZeroMemory( pInfo->pNoUser, sizeof(*pInfo->pNoUser) ); pInfo->pNoUser->dwSize = sizeof(*pInfo->pNoUser); TRACE( "Callback(NoUser)" ); pfunc( pInfo->pArgs->pApiArgs->dwCallbackId, RASPBDEVENT_NoUser, NULL, pInfo->pNoUser ); TRACE1( "Callback(NoUser) done,to=%d", pInfo->pNoUser->dwTimeoutMs ); TRACEW1( "U=%s",pInfo->pNoUser->szUserName ); TRACEW1( "D=%s",pInfo->pNoUser->szDomain ); // Whistler bug 254385 encode password when not being used // Assumed password was not encoded during callback // EncodePassword( pInfo->pNoUser->szPassword ); // Install input detection hooks. // if (pInfo->pNoUser->dwTimeoutMs > 0) { pInfo->hhookMouse = SetWindowsHookEx( WH_MOUSE, DuInputHook, g_hinstDll, GetCurrentThreadId() ); pInfo->hhookKeyboard = SetWindowsHookEx( WH_KEYBOARD, DuInputHook, g_hinstDll, GetCurrentThreadId() ); } } } if (!pInfo->user.fAllowLogonPhonebookEdits) { // Disable new button. See also similar logic for the Properties // button occurs in DuUpdateLbEntries. // EnableWindow( pInfo->hwndPbNew, FALSE ); } } // Load the list of phonebook entries and set selection. // DuUpdateLbEntries( pInfo, pInfo->pArgs->pszEntry ); if (!pInfo->pArgs->pszEntry) { if (ComboBox_GetCount( pInfo->hwndLbEntries ) > 0) { ComboBox_SetCurSelNotify( pInfo->hwndLbEntries, 0 ); } } // Update the title to reflect the phonebook mode. // DuUpdateTitle( pInfo ); // Adjust the title bar widgets and create the wizard bitmap. // TweakTitleBar( hwndDlg ); AddContextHelpButton( hwndDlg ); // Start the connect monitor. // if ((pInfo->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL )) && (pInfo->hThread = CreateThread( NULL, 0, DuMonitorThread, (LPVOID )pInfo, 0, (LPDWORD )&dwThreadId ))) { ASSERT( g_pRasConnectionNotification ); TRACE( "RasConnectionNotification" ); dwErr = g_pRasConnectionNotification( INVALID_HANDLE_VALUE, pInfo->hEvent, RASCN_Connection | RASCN_Disconnection ); TRACE1( "RasConnectionNotification=%d", dwErr ); } else TRACE( "Monitor DOA" ); if (ComboBox_GetCount( pInfo->hwndLbEntries ) == 0) { // The phonebook is empty. // if (pInfo->fNoUser && !pInfo->user.fAllowLogonPhonebookEdits ) { // Tell the user you can't create an entry or locations during // startup. // MsgDlg( hwndDlg, SID_EmptyLogonPb, NULL ); EndDialog( hwndDlg, TRUE ); return TRUE; } else { if(pInfo->fNoUser) { dwErr = TapiNoLocationDlg( g_hinstDll, &pInfo->hlineapp, hwndDlg ); if (dwErr != 0) { // Error here is treated as a "cancel" per bug 288385. // pArgs->pApiArgs->dwError = 0; EndDialog( hwndDlg, TRUE ); return TRUE; } } // Tell the user, then automatically start him into adding a new // entry. Set initial focus to "New" button first, in case user // cancels out. // SetFocus( pInfo->hwndPbNew ); MsgDlg( hwndDlg, SID_EmptyPhonebook, NULL ); DuNewEntry( pInfo, FALSE ); } } else { // Set initial focus to the non-empty entry listbox. // SetFocus( pInfo->hwndLbEntries ); } return FALSE; } LRESULT CALLBACK DuInputHook( IN int nCode, IN WPARAM wparam, IN LPARAM lparam ) // Standard Win32 'MouseProc' or 'KeyboardProc' callback. For our simple // processing we can take advantage of them having identical arguments and // 'nCode' definitions. // { if (nCode == HC_ACTION) { ++g_cInput; } return 0; } VOID DuNewEntry( IN DUINFO* pInfo, IN BOOL fClone ) // Called when user presses the "New" button or "Clone" menu item. // 'PInfo' is the dialog context. 'FClone' is set to clone the selected // entry, otherwise an empty entry is created. // { BOOL fOk; TCHAR* pszEntry; RASENTRYDLG info; INTERNALARGS iargs; PBENTRY* pEntry; TRACE1( "DuNewEntry(f=%d)", fClone ); ZeroMemory( &info, sizeof(info) ); info.dwSize = sizeof(info); info.hwndOwner = pInfo->hwndDlg; if (fClone) { DUCONTEXT *pContext; // Look up the selected entry. // pContext = (DUCONTEXT* )ComboBox_GetItemDataPtr( pInfo->hwndLbEntries, ComboBox_GetCurSel( pInfo->hwndLbEntries ) ); if (!pContext) { MsgDlg( pInfo->hwndDlg, SID_NoEntrySelected, NULL ); SetFocus( pInfo->hwndPbNew ); return; } pEntry = pContext->pEntry; if (!pEntry) { MsgDlg( pInfo->hwndDlg, SID_NoEntrySelected, NULL ); SetFocus( pInfo->hwndPbNew ); return; } pszEntry = pEntry->pszEntryName; info.dwFlags = RASEDFLAG_CloneEntry; } else { pszEntry = NULL; info.dwFlags = RASEDFLAG_NewEntry; } { RECT rect; GetWindowRect( pInfo->hwndDlg, &rect ); info.dwFlags += RASEDFLAG_PositionDlg; info.xDlg = rect.left + DXSHEET; info.yDlg = rect.top + DYSHEET; } // The secret hack to share information already loaded with the entry API. // ZeroMemory( &iargs, sizeof(iargs) ); iargs.pFile = &pInfo->file; iargs.pUser = &pInfo->user; iargs.pNoUser = pInfo->pNoUser; iargs.fNoUser = pInfo->fNoUser; info.reserved = (ULONG_PTR ) &iargs; // Call the Win32 API to run the add entry wizard. // TRACE( "RasEntryDlg" ); fOk = RasEntryDlg( pInfo->pArgs->pszPhonebook, pszEntry, &info ); TRACE1( "RasEntryDlg=%d", fOk ); if (pInfo->pNoUser && !pInfo->hThread) { TRACE( "Taking shortcut to exit" ); return; } if (fOk) { TRACEW1( "OK pressed, e=\"%s\"", info.szEntry ); if (pInfo->pArgs->pApiArgs->pCallback) { RASPBDLGFUNCW pfunc = pInfo->pArgs->pApiArgs->pCallback; TRACE( "Callback(AddEntry)" ); pfunc( pInfo->pArgs->pApiArgs->dwCallbackId, RASPBDEVENT_AddEntry, info.szEntry, NULL ); TRACE( "Callback(AddEntry) done" ); } DuUpdateLbEntries( pInfo, info.szEntry ); Button_MakeDefault( pInfo->hwndDlg, pInfo->hwndPbDial ); SetFocus( pInfo->hwndLbEntries ); } else { TRACE( "Cancel pressed or error" ); } } VOID DuUpdateConnectStatus( IN DUINFO* pInfo ) // Called to update connect status of the selected entry and the text of // the Dial/HangUp button. 'PInfo' is the dialog context block. // { TCHAR* pszPhonebook; TCHAR* pszEntry; INT iSel; TCHAR* psz; DUCONTEXT *pContext; TRACE( "DuUpdateConnectStatus" ); // pszPhonebook = pInfo->file.pszPath; iSel = ComboBox_GetCurSel( pInfo->hwndLbEntries ); if (iSel < 0) { return; } pContext = (DUCONTEXT *) ComboBox_GetItemDataPtr( pInfo->hwndLbEntries, iSel); ASSERT(NULL != pContext); pszEntry = ComboBox_GetPsz( pInfo->hwndLbEntries, iSel ); pInfo->hrasconn = HrasconnFromEntry( pContext->pszPhonebookPath, pszEntry ); psz = PszFromId( g_hinstDll, (pInfo->hrasconn) ? SID_DU_HangUp : SID_DU_Dial ); if (psz) { SetWindowText( pInfo->hwndPbDial, psz ); Free( psz ); } } VOID DuUpdateLbEntries( IN DUINFO* pInfo, IN TCHAR* pszEntry ) // Update the contents of the entry listbox and set the selection to // 'pszEntry'. If there are entries the Properties button is enabled, // otherwise it is disabled. 'PInfo' is the dialog context. // { DTLNODE* pNode; RASENTRYNAME *pRasEntryNames = NULL; DWORD cEntries = 0; DWORD cb; DWORD dwErr; DWORD i; RASENTRYNAME ren; DUCONTEXT *pContext; INT iSel; TRACE( "DuUpdateLbEntries" ); iSel = -1; ComboBox_ResetContent( pInfo->hwndLbEntries ); cb = ren.dwSize = sizeof(RASENTRYNAME); // // Enumerate entries across all phonebooks. Fix for bug 206467 // dwErr = g_pRasEnumEntries(NULL, pInfo->pArgs->pszPhonebook, &ren, &cb, &cEntries); if( ( (ERROR_BUFFER_TOO_SMALL == dwErr) || (SUCCESS == dwErr)) && (cb >= sizeof(RASENTRYNAME))) { pRasEntryNames = (RASENTRYNAME *) Malloc(cb); if(NULL == pRasEntryNames) { // Nothing else can be done in this case // goto done; } pRasEntryNames->dwSize = sizeof(RASENTRYNAME); dwErr = g_pRasEnumEntries(NULL, pInfo->pArgs->pszPhonebook, pRasEntryNames, &cb, &cEntries); if(dwErr) { goto done; } } else { goto done; } for(i = 0; i < cEntries; i++) { pContext = (DUCONTEXT *) Malloc(sizeof(DUCONTEXT)); if(NULL == pContext) { dwErr = GetLastError(); goto done; } ZeroMemory(pContext, sizeof(DUCONTEXT)); pContext->pszPhonebookPath = StrDup( pRasEntryNames[i].szPhonebookPath ); ComboBox_AddItem(pInfo->hwndLbEntries, pRasEntryNames[i].szEntryName, pContext); } if (ComboBox_GetCount( pInfo->hwndLbEntries ) >= 0) { if (pszEntry) { // Select entry specified by API caller. // iSel = ComboBox_FindStringExact( pInfo->hwndLbEntries, -1, pszEntry ); } if (iSel < 0) { // Entry not found so default to first item selected. // iSel = 0; } if(ComboBox_GetCount(pInfo->hwndLbEntries) > 0) { ComboBox_SetCurSelNotify( pInfo->hwndLbEntries, iSel ); } } done: // Enable/disable Properties button based on existence of an entry. See // bug 313037. // if (ComboBox_GetCurSel( pInfo->hwndLbEntries ) >= 0 && (!pInfo->fNoUser || pInfo->user.fAllowLogonPhonebookEdits)) { EnableWindow( pInfo->hwndPbProperties, TRUE ); } else { if (GetFocus() == pInfo->hwndPbProperties) { SetFocus( pInfo->hwndPbDial ); } EnableWindow( pInfo->hwndPbProperties, FALSE ); } ComboBox_AutoSizeDroppedWidth( pInfo->hwndLbEntries ); Free0(pRasEntryNames); } VOID DuUpdateTitle( IN DUINFO* pInfo ) // Called to update the dialog title to reflect the current phonebook. // 'PInfo' is the dialog context. // { TCHAR szBuf[ 256 ]; TCHAR* psz; psz = PszFromId( g_hinstDll, SID_PopupTitle ); if (psz) { lstrcpyn( szBuf, psz, sizeof(szBuf) / sizeof(TCHAR) ); Free( psz ); } else { *szBuf = TEXT('0'); } if (pInfo->pArgs->pszPhonebook || pInfo->user.dwPhonebookMode != PBM_System) { INT iSel; iSel = ComboBox_GetCurSel(pInfo->hwndLbEntries); if (iSel >= 0) { DUCONTEXT *pContext; pContext = (DUCONTEXT *) ComboBox_GetItemDataPtr( pInfo->hwndLbEntries, iSel); ASSERT( pContext ); if(NULL != pContext) { lstrcat( szBuf, TEXT(" - ") ); lstrcat( szBuf, StripPath( pContext->pszPhonebookPath ) ); } } } SetWindowText( pInfo->hwndDlg, szBuf ); } VOID DuTerm( IN HWND hwndDlg ) // Called on WM_DESTROY. 'HwndDlg' is that handle of the dialog window. // { DUINFO* pInfo; DWORD i; DWORD cEntries; TRACE( "DuTerm" ); pInfo = (DUINFO* )GetWindowLongPtr( hwndDlg, DWLP_USER ); if (pInfo) { // Close ReceiveMonitorThread resources. // if (pInfo->hThread) { TRACE( "Set abort event" ); // Tell thread to wake up and quit... // pInfo->fAbortMonitor = TRUE; CloseHandle( pInfo->hThread ); // Don't SetEvent before closing the thread handle. On // multi-proc systems, the thread will exit so fast (and // set hThread to NULL) that CloseHandle will then close // an invalid handle. // SetEvent( pInfo->hEvent ); // ...and wait for that to happen. A message API (such as // PeekMessage) must be called to prevent the thread-to-thread // SendMessage in the thread from blocking. // { MSG msg; TRACE( "Termination spin..." ); for (;;) { PeekMessage( &msg, hwndDlg, 0, 0, PM_NOREMOVE ); if (!pInfo->hThread) { break; } Sleep( 500L ); } TRACE( "Termination spin ends" ); } } if (pInfo->hEvent) { CloseHandle( pInfo->hEvent ); } if (pInfo->pNoUser) { // Don't leave caller's password floating around in memory. // ZeroMemory( pInfo->pNoUser->szPassword, PWLEN * sizeof(TCHAR) ); Free( pInfo->pNoUser ); // Uninstall input event hooks. // if (pInfo->hhookMouse) { UnhookWindowsHookEx( pInfo->hhookMouse ); } if (pInfo->hhookKeyboard) { UnhookWindowsHookEx( pInfo->hhookKeyboard ); } } else if ((pInfo->pArgs->pApiArgs->dwFlags & RASPBDFLAG_UpdateDefaults) && pInfo->hwndLbEntries && pInfo->user.fInitialized) { INT iSel; RECT rect; // Caller said to update default settings so save the name of the // selected entry and the current window position. // iSel = ComboBox_GetCurSel( pInfo->hwndLbEntries ); if (iSel >= 0) { DUCONTEXT *pContext; PBENTRY* pEntry; pContext = (DUCONTEXT* )ComboBox_GetItemDataPtr( pInfo->hwndLbEntries, iSel ); if( (NULL != pContext) && (NULL != (pEntry = pContext->pEntry))) { Free0( pInfo->user.pszDefaultEntry ); pInfo->user.pszDefaultEntry = StrDup( pEntry->pszEntryName ); } } if (!SetOffDesktop( pInfo->hwndDlg, SOD_GetOrgRect, &rect )) { GetWindowRect( pInfo->hwndDlg, &rect ); } pInfo->user.dwXPhonebook = rect.left; pInfo->user.dwYPhonebook = rect.top; pInfo->user.fDirty = TRUE; g_pSetUserPreferences( NULL, &pInfo->user, pInfo->fNoUser ? UPM_Logon : UPM_Normal ); } if(NULL != pInfo->hwndLbEntries) { DUCONTEXT *pContext; cEntries = ComboBox_GetCount(pInfo->hwndLbEntries); // // Free the context stored in the list box // for(i = 0; i < cEntries; i++) { pContext = ComboBox_GetItemDataPtr( pInfo->hwndLbEntries, i); if(NULL != pContext) { Free0(pContext->pszPhonebookPath); } Free0(pContext); } } TapiShutdown( pInfo->hlineapp ); ClosePhonebookFile( &pInfo->file ); DestroyUserPreferences( &pInfo->user ); Free( pInfo ); } } DWORD DuMonitorThread( LPVOID pThreadArg ) // The "main" of the "connect monitor" thread. This thread simply // converts Win32 RasConnectionNotification events int WM_RASEVENT style // notfications. // { DUINFO* pInfo; DWORD dwErr; DWORD dwTimeoutMs; DWORD dwQuitTick; DWORD cInput = 0; TRACE( "DuMonitor starting" ); pInfo = (DUINFO* )pThreadArg; if (pInfo->pNoUser && pInfo->pNoUser->dwTimeoutMs != 0) { TRACE( "DuMonitor quit timer set" ); dwTimeoutMs = 5000L; dwQuitTick = GetTickCount() + pInfo->pNoUser->dwTimeoutMs; cInput = g_cInput; } else { dwTimeoutMs = INFINITE; dwQuitTick = 0; } // Trigger the event so the other thread has the correct state as of the // monitor starting. // SetEvent( pInfo->hEvent ); for (;;) { dwErr = WaitForSingleObject( pInfo->hEvent, dwTimeoutMs ); if (pInfo->fAbortMonitor) { break; } if (dwErr == WAIT_TIMEOUT) { if (g_cInput > cInput) { TRACE( "Input restarts timer" ); cInput = g_cInput; dwQuitTick = GetTickCount() + pInfo->pNoUser->dwTimeoutMs; } else if (GetTickCount() >= dwQuitTick) { TRACE( "/DuMonitor SendMessage(WM_NOUSERTIMEOUT)" ); SendMessage( pInfo->hwndDlg, WM_NOUSERTIMEOUT, 0, 0 ); TRACE( "\\DuMonitor SendMessage(WM_NOUSERTIMEOUT) done" ); break; } } else { TRACE( "/DuMonitor SendMessage(WM_RASEVENT)" ); SendMessage( pInfo->hwndDlg, WM_RASEVENT, 0, 0 ); TRACE( "\\DuMonitor SendMessage(WM_RASEVENT) done" ); } } // This clues the other thread that all interesting work has been done. // pInfo->hThread = NULL; TRACE( "DuMonitor terminating" ); return 0; } DWORD DuGetEntry( DUINFO* pInfo, DUCONTEXT* pContext ) { DWORD dwErr = ERROR_SUCCESS; DWORD dwReadPbkFlags = 0; LPTSTR pszEntryName; DTLNODE *pdtlnode; PBFILE file; ASSERT(NULL != pContext); pContext->pEntry = NULL; pszEntryName = ComboBox_GetPsz(pInfo->hwndLbEntries, ComboBox_GetCurSel(pInfo->hwndLbEntries)); if (pInfo->fNoUser) { dwReadPbkFlags |= RPBF_NoUser; } if( (NULL != pInfo->file.pszPath) && (0 == lstrcmpi(pContext->pszPhonebookPath, pInfo->file.pszPath))) { // // We already have the phonebook file open // pdtlnode = EntryNodeFromName( pInfo->file.pdtllistEntries, pszEntryName); ASSERT(NULL != pdtlnode); } else { // // phonebook file changed. So close the existing phone // book file and open the one in which the entry // belongs // if(NULL != pInfo->file.pszPath) { ClosePhonebookFile(&pInfo->file); } dwErr = GetPbkAndEntryName(pContext->pszPhonebookPath, pszEntryName, dwReadPbkFlags, &file, &pdtlnode); if(dwErr) { goto done; } ASSERT(NULL != pdtlnode); CopyMemory(&pInfo->file, &file, sizeof(PBFILE)); } if (pdtlnode) { pContext->pEntry = (PBENTRY *) DtlGetData(pdtlnode); } else { dwErr = ERROR_CANNOT_FIND_PHONEBOOK_ENTRY; } done: return dwErr; } DWORD DwGetEapLogonInfo( VOID *pv, EAPLOGONINFO **ppEapLogonInfo ) { EAPLOGONINFO *pEapLogonInfo = NULL; DWORD retcode = SUCCESS; struct EAPINFO { DWORD dwSizeofEapInfo; PBYTE pbEapInfo; DWORD dwSizeofPINInfo; PBYTE pbPINInfo; }; struct EAPINFO *pEapInfo = (struct EAPINFO *) pv; DWORD dwSize; if(NULL == pv) { retcode = E_INVALIDARG; goto done; } dwSize = sizeof(EAPLOGONINFO) + pEapInfo->dwSizeofEapInfo + pEapInfo->dwSizeofPINInfo; pEapLogonInfo = (EAPLOGONINFO *) Malloc(dwSize); if(NULL == pEapLogonInfo) { retcode = GetLastError(); TRACE1("Failed to Allocate EapLogonInfo. rc=0x%x", retcode); goto done; } ZeroMemory(pEapLogonInfo, dwSize); // // Set up the fields in pEapLogonInfo by // flattening out the information passed // in. // pEapLogonInfo->dwSize = dwSize; pEapLogonInfo->dwLogonInfoSize = pEapInfo->dwSizeofEapInfo; pEapLogonInfo->dwOffsetLogonInfo = FIELD_OFFSET(EAPLOGONINFO, abdata); memcpy( pEapLogonInfo->abdata, pEapInfo->pbEapInfo, pEapInfo->dwSizeofEapInfo); pEapLogonInfo->dwPINInfoSize = pEapInfo->dwSizeofPINInfo; pEapLogonInfo->dwOffsetPINInfo = FIELD_OFFSET(EAPLOGONINFO, abdata) + pEapInfo->dwSizeofEapInfo; memcpy( (PBYTE) ((PBYTE) pEapLogonInfo + pEapLogonInfo->dwOffsetPINInfo), pEapInfo->pbPINInfo, pEapInfo->dwSizeofPINInfo); done: *ppEapLogonInfo = pEapLogonInfo; return retcode; }