#include "wininetp.h" #include "autodial.h" #include "rashelp.h" #define TAPI_CURRENT_VERSION 0x00010004 #include void PostString(HWND hDlg, LPWSTR pszString); void GetDialErrorString(DWORD dwError, LPWSTR pszBuffer, DWORD dwLength); void SetDialError(HWND hDlg, DWORD dwError); UINT_PTR SendDialmonMessage( UINT uMessage, BOOL fPost ); // function prototype in inetcpl to launch connections tab typedef BOOL (WINAPI *LAUNCHCPL)(HWND); // // Globals // BOOL g_fRegisterWndProc = FALSE; #define REGSTR_DIAL_AUTOCONNECTW L"AutoConnect" typedef struct _tagRASCONNSTATEMAP { RASCONNSTATE rascs; UINT uResourceID; } RASCONNSTATEMAP; RASCONNSTATEMAP rgRasStates[] = { { RASCS_OpenPort, IDS_DIALING }, { RASCS_AllDevicesConnected, IDS_CONNECTED }, { RASCS_Authenticate, IDS_AUTHENTICATE }, { RASCS_Disconnected, IDS_DISCONNECTED }, { (RASCONNSTATE)0, 0 } }; PROPMAP g_PropertyMap[] = { {DIALPROP_USERNAME, PropUserName }, {DIALPROP_PASSWORD, PropPassword }, {DIALPROP_DOMAIN, PropDomain }, {DIALPROP_SAVEPASSWORD, PropSavePassword }, {DIALPROP_PHONENUMBER, PropPhoneNumber }, {DIALPROP_REDIALCOUNT, PropRedialCount }, {DIALPROP_REDIALINTERVAL, PropRedialInterval }, {DIALPROP_LASTERROR, PropLastError }, {DIALPROP_RESOLVEDPHONE, PropResolvedPhone } }; #define NUM_DIALPROPS (sizeof(g_PropertyMap) / sizeof(PROPMAP)) ////////////////////////////////////////////////////////////////////////////// // // CDialEngine implementation // ////////////////////////////////////////////////////////////////////////////// CDialEngine::CDialEngine() { m_cRef = 0; m_pdes = NULL; m_rcs = RASCS_Disconnected; m_fCurrentlyDialing = FALSE; memset(&m_rdp, 0, sizeof(m_rdp)); memset(&m_rcred, 0, sizeof(m_rcred)); m_fPassword = FALSE; m_fSavePassword = FALSE; m_dwError = 0; // must be initialized to zero -- RasDial will fail (!) if this is anything // other than 0 when passed in to receive conn handle!! m_hConn = NULL; m_rdp.dwSize = sizeof(m_rdp); EnsureRasLoaded(); if(FALSE == g_fRegisterWndProc) { // register window class for dialing engine WNDCLASS wc; memset(&wc, 0, sizeof(wc)); wc.lpfnWndProc = CDialEngine::EngineWndProc; wc.hInstance = GlobalDllHandle; wc.lpszClassName = "DialEngine"; RegisterClass(&wc); g_fRegisterWndProc = TRUE; } } CDialEngine::~CDialEngine() { SAFE_RELEASE(m_pdes); if(m_hwnd) { DestroyWindow(m_hwnd); } } // // IUnknown members // STDMETHODIMP_(ULONG) CDialEngine::AddRef(void) { return ++m_cRef; } STDMETHODIMP_(ULONG) CDialEngine::Release(void) { if( 0L != --m_cRef ) return m_cRef; delete this; return 0L; } STDMETHODIMP CDialEngine::QueryInterface(REFIID riid, void ** ppv) { *ppv = NULL; // Validate requested interface if ((IID_IUnknown == riid) || (IID_IDialEngine == riid)) { *ppv = (IDialEngine *)this; } else { return E_NOINTERFACE; } // Addref through the interface ((LPUNKNOWN)*ppv)->AddRef(); return S_OK; } // // IDialEngine members // STDMETHODIMP CDialEngine::Initialize( LPCWSTR pwzConnectoid, IDialEventSink *pIDES ) { DEBUG_ENTER((DBG_DIALUP, Dword, "CDialEngine::Initialize", "%#x (%Q), %#x", pwzConnectoid, pwzConnectoid, pIDES )); // save off stuff m_pdes = pIDES; m_pdes->AddRef(); StrCpyW(m_rdp.szEntryName, pwzConnectoid); m_rdp.dwSize = sizeof(m_rdp); // get stats from RAS RasEntryDialParamsHelp re; if(re.GetW(NULL, &m_rdp, &m_fPassword)) { DEBUG_LEAVE(E_INVALIDARG); return E_INVALIDARG; } if(IsOS(OS_WHISTLERORGREATER)) { // on whistler, use RasGetCredentials instead to preserve settings m_rcred.dwSize = sizeof(m_rcred); m_rcred.dwMask = RASCM_UserName | RASCM_Password; if(_RasGetCredentialsW(NULL, pwzConnectoid, &m_rcred)) { DEBUG_LEAVE(E_INVALIDARG); return E_INVALIDARG; } DEBUG_PRINT(DIALUP, INFO, ("Name=<%ws>, PW=<%ws>, dwMask=%x\n", m_rcred.szUserName, m_rcred.szPassword, m_rcred.dwMask)); m_fPassword = (m_rcred.dwMask & RASCM_Password) ? TRUE : FALSE; } // read redial properties GetRedialParameters((LPWSTR)pwzConnectoid, &m_dwTryTotal, &m_dwWaitTotal); m_dwTryCurrent = 0; m_dwWaitCurrent = 0; // register the ras message m_uRasMsg = RegisterWindowMessageA(RASDIALEVENT); if(0 == m_uRasMsg) m_uRasMsg = WM_RASDIALEVENT; // create the window to get ras callbacks. m_hwnd = CreateWindowA( "DialEngine", "DialEngine", WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GlobalDllHandle, NULL ); if(NULL == m_hwnd) { DEBUG_LEAVE(E_OUTOFMEMORY); return E_OUTOFMEMORY; } // tell window our this pointer SendMessage(m_hwnd, WM_USER, 0, (LPARAM)this); // get current connected state from RAS UpdateRasState(); DEBUG_LEAVE(S_OK); return S_OK; } STDMETHODIMP CDialEngine::GetProperty( LPCWSTR pwzProperty, LPWSTR pwzValue, DWORD dwBufSize ) { DEBUG_ENTER((DBG_DIALUP, Dword, "CDialEngine::GetProperty", "%#x (%Q), %#x, %#x", pwzProperty, pwzProperty, pwzValue, dwBufSize )); HRESULT hr = E_INVALIDARG; WCHAR * pwzSrc = NULL; RasEntryPropHelp *pre = new RasEntryPropHelp; switch(PropertyToOrdinal(pwzProperty)) { case PropUserName: pwzSrc = m_rdp.szUserName; break; case PropPassword: if(m_fPassword) { pwzSrc = m_rdp.szPassword; } else { hr = S_FALSE; } break; case PropDomain: pwzSrc = m_rdp.szDomain; break; case PropSavePassword: if(m_fSavePassword) { pwzSrc = L"TRUE"; } else { pwzSrc = L"FALSE"; } break; case PropResolvedPhone: if(ResolvePhoneNumber(pwzValue, dwBufSize)) { hr = S_OK; break; } // // failed to get nicely formatted phone number, fall through to basic one // case PropPhoneNumber: if (pre == NULL) { hr = E_OUTOFMEMORY; } else { pre->GetW(m_rdp.szEntryName); pwzSrc = pre->GetPhoneNumberW(); } break; case PropRedialCount: DEBUG_PRINT(DIALUP, INFO, ("Prop value = %d\n", m_dwTryTotal)); wnsprintfW(pwzValue, dwBufSize, L"%d", m_dwTryTotal); hr = S_OK; break; case PropRedialInterval: DEBUG_PRINT(DIALUP, INFO, ("Prop value = %d\n", m_dwWaitTotal)); wnsprintfW(pwzValue, dwBufSize, L"%d", m_dwWaitTotal); hr = S_OK; break; case PropLastError: GetDialErrorString(m_dwError, pwzValue, dwBufSize); DEBUG_PRINT(DIALUP, INFO, ("Prop value = %ws\n", pwzValue)); hr = S_OK; break; } if(pwzSrc) { DEBUG_PRINT(DIALUP, INFO, ("Prop value = %ws\n", pwzSrc)); StrCpyNW(pwzValue, pwzSrc, dwBufSize); hr = S_OK; } if (pre) delete pre; DEBUG_LEAVE(hr); return hr; } STDMETHODIMP CDialEngine::SetProperty( LPCWSTR pwzProperty, LPCWSTR pwzValue ) { DEBUG_ENTER((DBG_DIALUP, Dword, "CDialEngine::SetProperty", "%#x (%Q), %#x (%Q)", pwzProperty, pwzProperty, pwzValue, pwzValue )); HRESULT hr = E_INVALIDARG; WCHAR * pwzDest = NULL; DWORD dwMaxLength = 0; WCHAR wcNull = 0; // treat NULL values as emtpy values if(NULL == pwzValue) { pwzValue = &wcNull; } switch(PropertyToOrdinal(pwzProperty)) { case PropUserName: pwzDest = m_rdp.szUserName; dwMaxLength = UNLEN; if(IsOS(OS_WHISTLERORGREATER)) { StrCpyNW(m_rcred.szUserName, pwzValue, dwMaxLength); } break; case PropPassword: pwzDest = m_rdp.szPassword; dwMaxLength = PWLEN; m_fPassword = TRUE; if(IsOS(OS_WHISTLERORGREATER)) { StrCpyNW(m_rcred.szPassword, pwzValue, dwMaxLength); } break; case PropDomain: pwzDest = m_rdp.szDomain; dwMaxLength = DNLEN; break; case PropSavePassword: if(!StrCmpIW(pwzValue, L"TRUE")) { m_fSavePassword = TRUE; } else { m_fSavePassword = FALSE; } if(FALSE == m_fSavePassword) { m_fPassword = FALSE; } hr = S_OK; break; case PropPhoneNumber: pwzDest = m_rdp.szPhoneNumber; dwMaxLength = RAS_MaxPhoneNumber; break; case PropRedialCount: m_dwTryTotal = StrToIntW(pwzValue); if(0 == m_dwTryTotal) { m_dwTryTotal = DEFAULT_DIAL_ATTEMPTS; } hr = S_OK; break; case PropRedialInterval: m_dwWaitTotal = StrToIntW(pwzValue); if(0 == m_dwWaitTotal) { m_dwWaitTotal = DEFAULT_DIAL_INTERVAL; } hr = S_OK; break; default: hr = E_UNEXPECTED; break; } if(pwzDest) { StrCpyNW(pwzDest, pwzValue, dwMaxLength); hr = S_OK; } DEBUG_LEAVE(hr); return hr; } STDMETHODIMP CDialEngine::StartConnection() { DEBUG_ENTER((DBG_DIALUP, Dword, "CDialEngine::StartConnection", NULL )); m_dwTryCurrent++; m_pdes->OnEvent(DIALENG_RedialAttempt, m_dwTryCurrent); RasDialHelp RasDial(NULL, NULL, &m_rdp, 0xFFFFFFFF, m_hwnd, &m_hConn); if(0 != RasDial.GetError()) { // Clean up since RAS may return a connection anyway... CleanConnection(); m_dwError = ERROR_NO_CONNECTION; EndOfOperation(); DEBUG_PRINT(DIALUP, INFO, ("Bailing - RasDial error\n")); DEBUG_LEAVE(E_FAIL); return E_FAIL; } DEBUG_LEAVE(S_OK); return S_OK; } STDMETHODIMP CDialEngine::Dial() { DEBUG_ENTER((DBG_DIALUP, Dword, "CDialEngine::Dial", NULL )); HRESULT hr; if(m_fCurrentlyDialing) { DEBUG_PRINT(DIALUP, INFO, ("Bailing - m_fCurentlyDialing\n")); DEBUG_LEAVE(S_FALSE); return S_FALSE; } // find out if our connection state has changed in the mean time UpdateRasState(); // we have begun... m_fCurrentlyDialing = TRUE; if(m_rcs == RASCS_Connected) { DEBUG_PRINT(DIALUP, INFO, ("Bailing - already connected\n")); m_dwError = ERROR_SUCCESS; EndOfOperation(); DEBUG_LEAVE(S_FALSE); return S_FALSE; } m_dwError = 0; m_dwTryCurrent = 0; hr = StartConnection(); DEBUG_LEAVE(hr); return hr; } STDMETHODIMP CDialEngine::CleanConnection() { DEBUG_ENTER((DBG_DIALUP, Dword, "CDialEngine::CleanConnection", NULL )); HRESULT hr = S_FALSE; // make sure we see if we've connected in the mean time UpdateRasState(); DEBUG_PRINT(DIALUP, INFO, ("m_hConn=%x\n", m_hConn)); // hang up connection if we got one if(m_hConn) { HRASCONN hConn = m_hConn; m_hConn = NULL; _RasHangUp(hConn); hr = S_OK; } DEBUG_LEAVE(hr); return hr; } STDMETHODIMP CDialEngine::HangUp() { DEBUG_ENTER((DBG_DIALUP, Dword, "CDialEngine::HangUp", NULL )); HRESULT hr; // hang up or abort any pending dials hr = CleanConnection(); // make sure no pending timers if(m_uTimerId) { KillTimer(m_hwnd, m_uTimerId); m_uTimerId = 0; } // calling hangup causes ras events to end if(0 == m_dwError) { m_dwError = ERROR_USER_DISCONNECTION; } EndOfOperation(); DEBUG_LEAVE(hr); return hr; } STDMETHODIMP CDialEngine::GetConnectedState( DWORD *pdwState) { DEBUG_ENTER((DBG_DIALUP, Dword, "CDialEngine::GetConnectedState", NULL )); *pdwState = MapRCS(m_rcs); DEBUG_LEAVE(S_OK); return S_OK; } STDMETHODIMP CDialEngine::GetConnectHandle( DWORD_PTR *pdwHandle ) { DEBUG_ENTER((DBG_DIALUP, Dword, "CDialEngine::GetConnectHandle", NULL )); if(RASCS_Connected == m_rcs) { *pdwHandle = (DWORD_PTR)m_hConn; DEBUG_LEAVE(S_OK); return S_OK; } else { *pdwHandle = 0; DEBUG_LEAVE(S_FALSE); return S_FALSE; } } // // private members // LONG_PTR CALLBACK CDialEngine::EngineWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { DEBUG_ENTER((DBG_DIALUP, Dword, "CDialEngine::EngineWndProc", "%#x, %#x, %#x, %#x", hwnd, uMsg, wParam, lParam )); CDialEngine * peng = (CDialEngine *)GetWindowLongPtr(hwnd, GWLP_USERDATA); if(uMsg == WM_USER) { peng = (CDialEngine *)lParam; SetWindowLongPtr(hwnd, GWLP_USERDATA, (DWORD_PTR)peng); } else if(peng && uMsg == peng->m_uRasMsg) { peng->OnRasEvent((RASCONNSTATE)wParam, (DWORD)lParam); } else if(peng && uMsg == WM_TIMER) { peng->OnTimer(); } DEBUG_LEAVE(0); return DefWindowProc(hwnd, uMsg, wParam, lParam); } VOID CDialEngine::OnTimer() { DEBUG_ENTER((DBG_DIALUP, None, "CDialEngine::OnTimer", NULL )); if(0 == m_dwError) { m_dwWaitCurrent--; if(0 == m_dwWaitCurrent) { // kick off dial KillTimer(m_hwnd, m_uTimerId); m_uTimerId = 0; StartConnection(); } else { // update sink // m_pdes->OnEvent(DIALENG_RedialWait, m_dwWaitCurrent); } } DEBUG_LEAVE(0); } VOID CDialEngine::OnRasEvent( RASCONNSTATE rcs, DWORD dwError ) { DEBUG_ENTER((DBG_DIALUP, None, "CDialEngine::OnRasEvent", "%#x, %#x", (DWORD)rcs, dwError )); // save rasconnstate m_rcs = rcs; // forward event to UI object m_pdes->OnEvent(MapRCS(rcs), dwError); // handle the dial state if(dwError != SUCCESS) { // win95 returns this error if authentication failed. if(ERROR_UNKNOWN == dwError) dwError = ERROR_AUTHENTICATION_FAILURE; // save error if we don't already have one if(0 == m_dwError && dwError) { m_dwError = dwError; } // clean up connection CleanConnection(); switch(dwError) { case ERROR_AUTHENTICATION_FAILURE: memset(m_rdp.szPassword, 0, ARRAYSIZE(m_rdp.szPassword)); EndOfOperation(); break; case ERROR_USER_DISCONNECTION: // we hit cancel and called RasHangUp. Nothing to do here - // cancel code has cleaned up as necessary. EndOfOperation(); break; case ERROR_LINE_BUSY: case ERROR_NO_ANSWER: case ERROR_NO_CARRIER: if(m_dwTryCurrent < m_dwTryTotal) { m_dwError = 0; m_dwWaitCurrent = m_dwWaitTotal; m_uTimerId = SetTimer(m_hwnd, 1, 1000, NULL); m_pdes->OnEvent(DIALENG_RedialWait, m_dwWaitCurrent); break; } // fall through default: EndOfOperation(); } } else { // we're getting status if(rcs == RASCS_Connected) { // we're done m_dwError = ERROR_SUCCESS; EndOfOperation(); DEBUG_PRINT(DIALUP, INFO, ("Connected: m_fPassword=%B, m_fSavePassword=%B\n", m_fPassword, m_fSavePassword)); if(IsOS(OS_WHISTLERORGREATER)) { // delete/write/leave alone semantics // // m_fPassword m_fSavePassword result // T T Write password // F F Delete password // T F Leave password alone // F T Never happens if(!m_fPassword && !m_fSavePassword) { // delete case, only want password mask m_rcred.dwMask = 0; } if(m_fPassword == m_fSavePassword) { // write or delete case // always need password flag m_rcred.dwMask |= RASCM_Password; // write or delete, depend on m_fSavePassword DEBUG_PRINT(DIALUP, INFO, ("Name=<%ws>, PW=<%ws>, dwMask=%x\n", m_rcred.szUserName, m_rcred.szPassword, m_rcred.dwMask)); _RasSetCredentialsW(NULL, m_rdp.szEntryName, &m_rcred, !m_fSavePassword); } } else { if(m_fPassword == m_fSavePassword) { // save or delete password RasEntryDialParamsHelp re; re.SetW(NULL, &m_rdp, !m_fSavePassword); } } // inform dialmon that we've dialed SendDialmonMessage(WM_SET_CONNECTOID_NAME, TRUE); } } DEBUG_LEAVE(0); } DWORD CDialEngine::MapRCS(RASCONNSTATE rcs) { DEBUG_ENTER((DBG_DIALUP, Dword, "CDialEngine::MapRCS", "%#x", (DWORD)rcs )); DEBUG_LEAVE((DWORD)rcs); return (DWORD)rcs; } DIALPROP CDialEngine::PropertyToOrdinal(LPCWSTR pwzProperty) { long i; for(i=0; iOnEvent(DIALENG_OperationComplete, m_dwError); } DEBUG_LEAVE(0); } VOID FAR CALLBACK TapiCallback( DWORD hDevice, DWORD dwMsg, DWORD_PTR dwCallbackInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2, DWORD_PTR dwParam3 ) { } BOOL CDialEngine::ResolvePhoneNumber(LPWSTR pwzBuffer, DWORD dwLen) { char *pszTemp = NULL; WCHAR szCanonical[128]; CHAR szAnsiCanonical[128]; CHAR *pszResolved; long lErr, i; BOOL fResult = FALSE; RasEntryPropHelp *pre = new RasEntryPropHelp; if (pre == NULL) { goto Cleanup; } pszTemp = (char *) ALLOCATE_FIXED_MEMORY(4096); if (pszTemp == NULL) { goto Cleanup; } // look up RAS entry pre->GetW(m_rdp.szEntryName); if(pre->GetError()) { goto Cleanup; } if(pre->GetOptions() & RASEO_UseCountryAndAreaCodes) { PWSTR pszAreaCode = pre->GetAreaCodeW(); HLINEAPP hApp; DWORD dwNumDevs; // make TAPI canonical phone number wnsprintfW(szCanonical, 128, L"+%d (%ws) %ws", pre->GetCountryCode(), pszAreaCode ? pszAreaCode : L"", pre->GetPhoneNumberW()); // ask TAPI to translate it LPLINETRANSLATEOUTPUT lpOut = (LPLINETRANSLATEOUTPUT)pszTemp; lpOut->dwTotalSize = 4096; lErr = lineInitialize(&hApp, GlobalDllHandle, TapiCallback, "Wininet", &dwNumDevs); if(lErr) { goto Cleanup; } WideCharToMultiByte(CP_ACP, 0, szCanonical, -1, szAnsiCanonical, 128, NULL, NULL); lErr = lineTranslateAddress(hApp, 0, TAPI_CURRENT_VERSION, szAnsiCanonical, 0, 0, lpOut); if(lErr) { goto Cleanup; } pszResolved = (CHAR *)((char *)lpOut + lpOut->dwDisplayableStringOffset); i = MultiByteToWideChar(CP_ACP, 0, pszResolved, -1, pwzBuffer, dwLen); if(0 == i) { pwzBuffer[dwLen] = 0; // truncated - null terminate } } else { // TAPI resolution not turned on, just return straight phone number StrCpyNW(pwzBuffer, pre->GetPhoneNumberW(), dwLen); } fResult = TRUE; Cleanup: if (pre) delete pre; if (pszTemp) FREE_MEMORY(pszTemp); return fResult; } ////////////////////////////////////////////////////////////////////////////// // // CDialUI implementation // ////////////////////////////////////////////////////////////////////////////// CDialUI::CDialUI(HWND hwndParent) { m_cRef = 0; m_pEng = NULL; m_pdb = NULL; m_State = UISTATE_Interactive; m_fOfflineSemantics = FALSE; m_fSavePassword = FALSE; m_fPasswordChanged = FALSE; m_fAutoConnect = FALSE; m_fCDH = FALSE; m_fDialedCDH = FALSE; memset(&m_cdh, 0, sizeof(m_cdh)); if(hwndParent) { m_hwndParent = hwndParent; } else { m_hwndParent = GetDesktopWindow(); } } CDialUI::~CDialUI() { SAFE_RELEASE(m_pEng); SAFE_RELEASE(m_pdb); } // // IUnknown members // STDMETHODIMP_(ULONG) CDialUI::AddRef(void) { return ++m_cRef; } STDMETHODIMP_(ULONG) CDialUI::Release(void) { if( 0L != --m_cRef ) return m_cRef; delete this; return 0L; } STDMETHODIMP CDialUI::QueryInterface(REFIID riid, void ** ppv) { *ppv=NULL; // Validate requested interface if ((IID_IUnknown == riid) || (IID_IDialEventSink == riid)) { *ppv = (IDialEventSink *)this; } else { return E_NOINTERFACE; } // Addref through the interface ((LPUNKNOWN)*ppv)->AddRef(); return S_OK; } // // IDialUI members // DWORD CDialUI::StartDial( IN DIALSTATE *pDial, IN DWORD dwFlags ) // // { DEBUG_ENTER((DBG_DIALUP, Dword, "CDialUI::StartDial", "%#x, %#x", pDial, dwFlags )); DWORD dwSize, dwTemp, dwType; WCHAR szKey[MAX_PATH]; // save passed info m_dwFlags = dwFlags; m_pDial = pDial; m_pDial->dwResult = 0; // check for connect automatically dwSize = sizeof(DWORD); dwTemp = 0; GetConnKeyW(pDial->params.szEntryName, szKey, ARRAYSIZE(szKey)); if(0 == (dwFlags & INTERNET_DIAL_FORCE_PROMPT) && ERROR_SUCCESS == SHGetValueW(HKEY_CURRENT_USER, szKey, REGSTR_DIAL_AUTOCONNECTW, &dwType, &dwTemp, &dwSize) && dwTemp) { m_fAutoConnect = TRUE; } // // Get some UI going // ULONG_PTR uCookie = 0; SHActivateContext(&uCookie); if(-1 == DialogBoxParamWrapW(GlobalDllHandle, MAKEINTRESOURCEW(IDD_CONNECT_TO), m_hwndParent, CDialUI::DialogProc, (LPARAM)this)) { // couldn't create dialog for some reason - no mem? m_pDial->dwResult = ERROR_OUTOFMEMORY; } if (uCookie) { SHDeactivateContext(uCookie); } // prop odds and ends back to data so caller is happy if(!m_fCDH) { m_pDial->dwFlags = 0; if(m_fAutoConnect) { m_pDial->dwFlags |= CI_AUTO_CONNECT; } if(m_pEng) { m_pEng->GetConnectHandle((DWORD_PTR *)&m_pDial->hConn); } } else { m_pDial->hConn = (HRASCONN)CDH_HCONN; } // // Clean up // SAFE_RELEASE(m_pEng); DEBUG_LEAVE(m_pDial->dwResult); return m_pDial->dwResult; } STDMETHODIMP CDialUI::OnEvent( DWORD dwEvent, DWORD dwStatus ) { DEBUG_ENTER((DBG_DIALUP, Dword, "CDialUI::OnEvent", "%#x, %#x", dwEvent, dwStatus )); WCHAR pszText[128], pszTemplate[128]; INT idRes; // find string for this state (if any) for (int nIndex = 0; rgRasStates[nIndex].uResourceID != 0; nIndex++) { if ((RASCONNSTATE)dwEvent == rgRasStates[nIndex].rascs) { LoadStringWrapW(GlobalDllHandle, rgRasStates[nIndex].uResourceID, pszText, 128); PostString(m_hwnd, pszText); } } switch(dwEvent) { case DIALENG_RedialAttempt: case DIALENG_RedialWait: idRes = IDS_REDIAL_ATTEMPT; if(dwEvent == DIALENG_RedialWait) { idRes = IDS_REDIAL_WAIT; } LoadStringWrapW(GlobalDllHandle, idRes, pszTemplate, 128); wnsprintfW(pszText, ARRAYSIZE(pszText), pszTemplate, dwStatus); PostString(m_hwnd, pszText); break; case DIALENG_OperationComplete: m_pDial->dwResult = dwStatus; if(0 == dwStatus || m_State == UISTATE_Unattended) { EndDialog(m_hwnd, 0); } else { if(dwStatus) { // get an error - display it SetDialError(m_hwnd, dwStatus); } m_State = UISTATE_Interactive; FixUIComponents(); } break; } DEBUG_LEAVE(0); return NOERROR; } VOID CDialUI::FixUIComponents( ) { DEBUG_ENTER((DBG_DIALUP, None, "CDialUI::FixUIComponents", NULL )); WCHAR pszTemp[64]; int i; BOOL fActive = TRUE, fCanSave, fCDHActive = TRUE; TCHAR szUser[UNLEN+1]; DWORD dwLen = UNLEN; UINT uIDs[] = {IDC_CONN_TXT, IDC_CONN_LIST, ID_CONNECT, IDC_SETTINGS}; UINT uCDHIDs[] = {IDC_NAME_TXT, IDC_USER_NAME, IDC_PASSWORD_TXT, IDC_PASSWORD}; #define NUM_IDS (sizeof(uIDs) / sizeof(UINT)) #define NUM_CDH_IDS (sizeof(uCDHIDs) / sizeof(UINT)) // // fix cancel button // if(UISTATE_Dialing == m_State || UISTATE_Unattended == m_State || FALSE == m_fOfflineSemantics) { i = IDS_CANCEL; } else { i = IDS_WORK_OFFLINE; } LoadStringWrapW(GlobalDllHandle, i, pszTemp, MAX_PATH); SetWindowTextWrapW(GetDlgItem(m_hwnd, IDCANCEL), pszTemp); // // Fix focus // if(UISTATE_Dialing == m_State || UISTATE_Unattended == m_State) { SetFocus(GetDlgItem(m_hwnd, IDCANCEL)); fActive = FALSE; } // // Grey out appropriate stuff // for(i=0; iDial(); } else { OnCancel(); } } // make sure cancel button is correct FixUIComponents(); // Handle autoconnect if(m_fAutoConnect) { CheckDlgButton(m_hwnd, IDC_AUTOCONNECT, BST_CHECKED); OnConnect(); } DEBUG_LEAVE(0); } VOID CDialUI::OnSelChange() { DEBUG_ENTER((DBG_DIALUP, None, "CDialUI::OnSelChange", NULL )); int iSel; HWND hwndList = GetDlgItem(m_hwnd, IDC_CONN_LIST); // yank out new name iSel = ComboBox_GetCurSel(hwndList); if(CB_ERR == iSel) iSel = 0; SendMessageWrapW(hwndList, CB_GETLBTEXT, (WPARAM)iSel, (LPARAM)m_pDial->params.szEntryName); // Fill in props for new connection (will get new engine) GetProps(); DEBUG_LEAVE(0); } VOID CDialUI::OnConnect( ) { DEBUG_ENTER((DBG_DIALUP, None, "CDialUI::OnConnect", NULL )); // If we have a CDH, call it if(m_fCDH) { if(!CallCDH(m_hwnd, m_pDial->params.szEntryName, &m_cdh, 0, &(m_pDial->dwResult))) { // custom dial handler failed to handle dial request, bail out m_pDial->dwResult = ERROR_USER_DISCONNECTION; } m_fDialedCDH = TRUE; EndDialog(m_hwnd, 0); DEBUG_LEAVE(0); return; } else { // If we don't have an engine, repop conn list (may have been deleted) // and bail out of dial operation if(!m_pEng) { EnumerateConnectoids(); DEBUG_LEAVE(0); return; } // Save off properties SaveProps(); } // TODO grey stuff m_State = UISTATE_Dialing; FixUIComponents(); // Stick phone number in progress box WCHAR szString[256], szPhone[128]; LoadStringWrapW(GlobalDllHandle, IDS_DIALING, szString, 128); if(SUCCEEDED(m_pEng->GetProperty(DIALPROP_RESOLVEDPHONE, szPhone, 128))) { StrNCatW(szString, szPhone, 128); PostString(m_hwnd, szString); } // Start the dialing operation m_pEng->Dial(); DEBUG_LEAVE(0); } VOID CDialUI::OnCancel( ) { DEBUG_ENTER((DBG_DIALUP, None, "CDialUI::OnCancel", NULL )); switch(m_State) { case UISTATE_Interactive: // // exit the dialog box // m_pDial->dwResult = ERROR_USER_DISCONNECTION; EndDialog(m_hwnd, 0); break; case UISTATE_Unattended: case UISTATE_Dialing: // // cancel current dialing operation // if(m_pEng) { m_pEng->HangUp(); } m_pDial->dwResult = ERROR_USER_DISCONNECTION; // // If we were previous "unattended" we aren't any more // CheckDlgButton(m_hwnd, IDC_AUTOCONNECT, BST_UNCHECKED); m_fAutoConnect = FALSE; // // fix grey stuff // FixUIComponents(); break; } DEBUG_LEAVE(0); } INT_PTR CALLBACK CDialUI::DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { CDialUI * pui = (CDialUI *)GetWindowLongPtr(hwndDlg, DWLP_USER); switch(uMsg) { case WM_INITDIALOG: SetWindowLongPtr(hwndDlg, DWLP_USER, lParam); pui = (CDialUI *)lParam; pui->m_hwnd = hwndDlg; pui->OnInitDialog(); return TRUE; case WM_COMMAND: // handle combo box messages if(HIWORD(wParam) == CBN_SELCHANGE) { pui->OnSelChange(); break; } switch (LOWORD(wParam)) { case ID_CONNECT: pui->OnConnect(); break; case IDCANCEL: pui->OnCancel(); break; case IDC_SETTINGS: { HMODULE hInetcpl = LoadLibrary("inetcpl.cpl"); if(hInetcpl) { LAUNCHCPL cpl = (LAUNCHCPL)GetProcAddress(hInetcpl, "LaunchConnectionDialog"); if(cpl) { cpl(hwndDlg); // refresh to new default if any AUTODIAL config; memset(&config, 0, sizeof(config)); IsAutodialEnabled(NULL, &config); if(config.fEnabled) { if(config.fHasEntry) { StrCpyW(pui->m_pDial->params.szEntryName, config.pszEntryName); } // refresh settings pui->EnumerateConnectoids(); pui->GetProps(); } else { // nothing to dial... bail out right away. pui->OnCancel(); } } FreeLibrary(hInetcpl); } } break; case IDC_SAVE_PASSWORD: EnableWindow( GetDlgItem(hwndDlg, IDC_AUTOCONNECT), IsDlgButtonChecked(hwndDlg, IDC_SAVE_PASSWORD)); break; case IDC_PASSWORD: if(HIWORD(wParam) == EN_CHANGE) { pui->m_fPasswordChanged = TRUE; } break; } break; } return FALSE; } VOID CDialUI::EnumerateConnectoids( ) { DEBUG_ENTER((DBG_DIALUP, None, "CDialUI::EnumerateConnectoids", NULL )); HWND hwndCombo = GetDlgItem(m_hwnd, IDC_CONN_LIST); INET_ASSERT(hwndCombo); ComboBox_ResetContent(hwndCombo); EnsureRasLoaded(); DWORD dwEntries, dwRet; RasEnumHelp RasEnum; dwRet = RasEnum.GetError(); dwEntries = RasEnum.GetEntryCount(); if(ERROR_SUCCESS == dwRet) { // insert connectoid names from buffer into combo box DWORD i; for(i=0; iparams.szEntryName); if(CB_ERR == iSel) { iSel = 0; SendMessageWrapW(hwndCombo, CB_GETLBTEXT, (WPARAM)iSel, (LPARAM)m_pDial->params.szEntryName); } ComboBox_SetCurSel(hwndCombo, iSel); } DEBUG_LEAVE(0); } VOID CDialUI::GetProps( ) { DEBUG_ENTER((DBG_DIALUP, None, "CDialUI::GetProps", NULL )); WCHAR wzBuffer[256]; HRESULT hr; CDHINFO cdh; SAFE_RELEASE(m_pEng); // // Find out if new selection is a CDH // m_fCDH = IsCDH(m_pDial->params.szEntryName, &m_cdh); // // Query for properties for non-CDH connections // if(!m_fCDH && SUCCEEDED(InternetGetDialEngineW(m_pDial->params.szEntryName, (IDialEventSink *)this, &m_pEng))) { if(FAILED(m_pEng->GetProperty(DIALPROP_USERNAME, wzBuffer, 256))) { *wzBuffer = 0; } SetWindowTextWrapW(GetDlgItem(m_hwnd, IDC_USER_NAME), wzBuffer); m_fSavePassword = FALSE; hr = m_pEng->GetProperty(DIALPROP_PASSWORD, wzBuffer, 256); if(S_OK == hr) { m_fSavePassword = TRUE; } else // S_FALSE - no saved password, or error { *wzBuffer = 0; } SetWindowTextWrapW(GetDlgItem(m_hwnd, IDC_PASSWORD), wzBuffer); CheckDlgButton(m_hwnd, IDC_SAVE_PASSWORD, m_fSavePassword ? BST_CHECKED : BST_UNCHECKED); if(FAILED(m_pEng->GetProperty(DIALPROP_DOMAIN, wzBuffer, 256))) { *wzBuffer = 0; } SetWindowTextWrapW(GetDlgItem(m_hwnd, IDC_DOMAIN), wzBuffer); } // // fix UI based on connectoid type // FixUIComponents(); // reset password changed as setting it above will cause the window message m_fPasswordChanged = FALSE; DEBUG_LEAVE(0); } VOID CDialUI::SaveProps( ) { DEBUG_ENTER((DBG_DIALUP, None, "CDialUI::SaveProps", NULL )); WCHAR wzBuffer[256]; GetWindowTextWrapW(GetDlgItem(m_hwnd, IDC_USER_NAME), wzBuffer, 256); m_pEng->SetProperty(DIALPROP_USERNAME, wzBuffer); GetWindowTextWrapW(GetDlgItem(m_hwnd, IDC_DOMAIN), wzBuffer, 256); m_pEng->SetProperty(DIALPROP_DOMAIN, wzBuffer); m_fSavePassword = FALSE; if(BST_CHECKED == IsDlgButtonChecked(m_hwnd, IDC_SAVE_PASSWORD)) m_fSavePassword = TRUE; if(m_fPasswordChanged || FALSE == m_fSavePassword) { GetWindowTextWrapW(GetDlgItem(m_hwnd, IDC_PASSWORD), wzBuffer, 256); m_pEng->SetProperty(DIALPROP_PASSWORD, wzBuffer); m_pEng->SetProperty(DIALPROP_SAVEPASSWORD, m_fSavePassword ? L"TRUE" : L"FALSE"); m_fPasswordChanged = FALSE; } m_fAutoConnect = FALSE; if(BST_CHECKED == IsDlgButtonChecked(m_hwnd, IDC_AUTOCONNECT)) m_fAutoConnect = TRUE; DEBUG_LEAVE(0); } ////////////////////////////////////////////////////////////////////////////// // // Helper functions // ////////////////////////////////////////////////////////////////////////////// // // Add a string to the details edit box // void PostString(HWND hDlg, LPWSTR pszString) { HWND hwndEdit = GetDlgItem(hDlg, IDC_DETAILS_LIST); WCHAR szCR[] = L"\r\n"; // move caret to end SendMessageWrapW(hwndEdit, EM_SETSEL, 0, -1); SendMessageWrapW(hwndEdit, EM_SETSEL, -1, -1); // replace selection (nothing) with new string SendMessageWrapW(hwndEdit, EM_REPLACESEL, 0, (LPARAM)pszString); // move caret to end SendMessageWrapW(hwndEdit, EM_SETSEL, 0, -1); SendMessageWrapW(hwndEdit, EM_SETSEL, -1, -1); // replace selection (nothing) with CR SendMessageWrapW(hwndEdit, EM_REPLACESEL, 0, (LPARAM)szCR); // scroll to end SendMessageWrapW(hwndEdit, EM_SCROLLCARET, 0, 0); } #define RAS_BOGUS_AUTHFAILCODE_1 84 #define RAS_BOGUS_AUTHFAILCODE_2 74389484 DWORD RasErrorToIDS(DWORD dwErr) { if(dwErr==RAS_BOGUS_AUTHFAILCODE_1 || dwErr==RAS_BOGUS_AUTHFAILCODE_2) { return IDS_PPPRANDOMFAILURE; } if((dwErr>=653 && dwErr<=663) || (dwErr==667) || (dwErr>=669 && dwErr<=675)) { return IDS_MEDIAINIERROR; } switch(dwErr) { default: return IDS_PPPRANDOMFAILURE; case ERROR_LINE_BUSY: return IDS_PHONEBUSY; case ERROR_NO_ANSWER: return IDS_NOANSWER; case ERROR_NO_DIALTONE: return IDS_NODIALTONE; case ERROR_HARDWARE_FAILURE: // modem turned off case ERROR_PORT_ALREADY_OPEN: // procomm/hypertrm/RAS has COM port case ERROR_PORT_OR_DEVICE: // got this when hypertrm had the device open -- jmazner return IDS_NODEVICE; case ERROR_BUFFER_INVALID: // bad/empty rasdilap struct case ERROR_BUFFER_TOO_SMALL: // ditto? case ERROR_CANNOT_FIND_PHONEBOOK_ENTRY: // if connectoid name in registry is wrong case ERROR_INTERACTIVE_MODE: return IDS_TCPINSTALLERROR; case ERROR_AUTHENTICATION_FAILURE: // get this on actual CHAP reject return IDS_AUTHFAILURE; case ERROR_VOICE_ANSWER: case ERROR_NO_CARRIER: case ERROR_PPP_TIMEOUT: // get this on CHAP timeout case ERROR_REMOTE_DISCONNECTION: // Ascend drops connection on auth-fail case ERROR_AUTH_INTERNAL: // got this on random POP failure case ERROR_PROTOCOL_NOT_CONFIGURED: // get this if LCP fails case ERROR_PPP_NO_PROTOCOLS_CONFIGURED: // get this if IPCP addr download gives garbage return IDS_PPPRANDOMFAILURE; } return 0; } void GetDialErrorString(DWORD dwError, LPWSTR pszBuffer, DWORD dwLength) { DWORD dwRes; dwRes = RasErrorToIDS(dwError); if(dwRes) { // we have a resource - use it LoadStringWrapW(GlobalDllHandle, dwRes, pszBuffer, dwLength); } else { // couldn't get ras error, try system error if(0 == FormatMessageWrapW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, pszBuffer, dwLength, NULL)) { // couldn't get system error, get system error E_FAIL == Unknown error FormatMessageWrapW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, E_FAIL, 0, pszBuffer, dwLength, NULL); } } } void SetDialError(HWND hDlg, DWORD dwError) { WCHAR szBuf[200]; GetDialErrorString(dwError, szBuf, 200); PostString(hDlg, szBuf); } BOOL FindDialProvider( IN LPWSTR pwzConnectoid, IN LPWSTR pwzProviderType, OUT CLSID * pclsid ) // // FindDialProvider - find an engine, UI, or branding provider for a // specific connectoid // { DEBUG_ENTER((DBG_DIALUP, Bool, "FindDialProvider", "%#x (%Q), %#x (%Q), %#x", pwzConnectoid, pwzConnectoid, pwzProviderType, pwzProviderType, pclsid )); WCHAR szKey[MAX_PATH]; WCHAR szClsid[64]; DWORD dwSize; // get the key for the connectoid GetConnKeyW(pwzConnectoid, szKey, ARRAYSIZE(szKey)); // read the CLSID string dwSize = sizeof(szClsid); if(ERROR_SUCCESS != SHGetValueW( HKEY_CURRENT_USER, szKey, pwzProviderType, NULL, szClsid, &dwSize)) { // no provider specified DEBUG_PRINT(DIALUP, INFO, ("No provider found.\n")); DEBUG_LEAVE(FALSE); return FALSE; } // covert string to clsid if(FAILED(CLSIDFromString(szClsid, pclsid))) { DEBUG_PRINT(DIALUP, INFO, ("Unable to convert clsid.\n")); DEBUG_LEAVE(FALSE); return FALSE; } DEBUG_LEAVE(TRUE); return TRUE; } ////////////////////////////////////////////////////////////////////////////// // // Public APIs // ////////////////////////////////////////////////////////////////////////////// INTERNETAPI InternetGetDialEngineW( IN LPWSTR pwzConnectoid, IN IDialEventSink * pdes, OUT IDialEngine ** ppde ) { DEBUG_ENTER_API((DBG_DIALUP, Dword, "InternetGetDialEngineW", "%#x (%Q), %#x, %#x", pwzConnectoid, pwzConnectoid, pdes, ppde )); HRESULT hr; CLSID clsid; *ppde = NULL; // // find engine we're going to use // if(FindDialProvider(pwzConnectoid, L"DialEngine", &clsid)) { // engine specified, try to create it hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDialEngine, (void **)ppde); } if(NULL == *ppde) { // use default engine CDialEngine * pEngine = new CDialEngine(); if(pEngine) { hr = pEngine->QueryInterface(IID_IDialEngine, (void **)ppde); } else { hr = E_OUTOFMEMORY; } } if(SUCCEEDED(hr)) { hr = (*ppde)->Initialize(pwzConnectoid, pdes); if(FAILED(hr)) { (*ppde)->Release(); *ppde = NULL; } } DEBUG_LEAVE_API(hr); return hr; } #if 0 // // [darrenmi 4/14/00] cleaning up exports of incomplete feature // INTERNETAPI InternetGetDialBrandingW( IN LPWSTR pwzConnectoid, OUT IDialBranding ** ppdb ) { DEBUG_ENTER_API((DBG_DIALUP, Dword, "InternetGetDialBrandingW", "%#x (%Q), %#x", pwzConnectoid, pwzConnectoid, ppdb )); HRESULT hr = S_FALSE; CLSID clsid; *ppdb = NULL; // // find engine we're going to use // if(FindDialProvider(pwzConnectoid, L"DialBranding", &clsid)) { // engine specified, try to create it hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDialBranding, (void **)ppdb); } if(SUCCEEDED(hr)) { hr = (*ppdb)->Initialize(pwzConnectoid); if(FAILED(hr)) { (*ppdb)->Release(); *ppdb = NULL; } } DEBUG_LEAVE_API(hr); return hr; } #endif