// -------------------------------------------------------------------------------- // Ixpbase.cpp // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved // Steven J. Bailey // -------------------------------------------------------------------------------- #include "pch.hxx" #include "dllmain.h" #include "ixpbase.h" #include "imnact.h" #include "ixputil.h" #include "sicily.h" #include "resource.h" #include "demand.h" #include "shlwapi.h" // -------------------------------------------------------------------------------- // CIxpBase::CIxpBase // -------------------------------------------------------------------------------- CIxpBase::CIxpBase(IXPTYPE ixptype) : m_ixptype(ixptype) { m_fBusy = FALSE; m_status = IXP_DISCONNECTED; m_cRef = 1; m_pszResponse = NULL; m_uiResponse = 0; m_hrResponse = S_OK; m_pLogFile = NULL; m_pSocket = NULL; m_pCallback = NULL; ZeroMemory(&m_rServer, sizeof(m_rServer)); m_fConnectAuth = FALSE; m_fConnectTLS = FALSE; m_fCommandLogging = FALSE; m_fAuthenticated = FALSE; InitializeCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CIxpBase::~CIxpBase // -------------------------------------------------------------------------------- CIxpBase::~CIxpBase(void) { Reset(); DeleteCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CIxpBase::Reset // -------------------------------------------------------------------------------- void CIxpBase::Reset(void) { EnterCriticalSection(&m_cs); m_fBusy = FALSE; m_status = IXP_DISCONNECTED; SafeMemFree(m_pszResponse); m_uiResponse = 0; m_hrResponse = S_OK; SafeRelease(m_pLogFile); if (NULL != m_pSocket) { m_pSocket->Close(); SafeRelease(m_pSocket); } SafeRelease(m_pCallback); ZeroMemory(&m_rServer, sizeof(m_rServer)); m_fConnectAuth = FALSE; m_fConnectTLS = FALSE; m_fCommandLogging = FALSE; m_fAuthenticated = FALSE; LeaveCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CIxpBase::IsState // -------------------------------------------------------------------------------- STDMETHODIMP CIxpBase::IsState(IXPISSTATE isstate) { // Locals HRESULT hr=S_FALSE; // Thread Safety EnterCriticalSection(&m_cs); #if 0 // Initialized if (NULL == m_pSocket || NULL == m_pCallback) { hr = TrapError(IXP_E_NOT_INIT); goto exit; } #endif // Handle IsType switch(isstate) { // Are we connected case IXP_IS_CONNECTED: hr = (IXP_DISCONNECTED == m_status) ? S_FALSE : S_OK; break; // Are we busy case IXP_IS_BUSY: hr = (TRUE == m_fBusy) ? S_OK : S_FALSE; break; // Are we busy case IXP_IS_READY: hr = (FALSE == m_fBusy) ? S_OK : S_FALSE; break; // Have we been authenticated yet case IXP_IS_AUTHENTICATED: hr = (TRUE == m_fAuthenticated) ? S_OK : S_FALSE; break; // Unhandled ixpistype default: IxpAssert(FALSE); break; } // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CIxpBase::OnPrompt // -------------------------------------------------------------------------------- int CIxpBase::OnPrompt(HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType) { // $$BUGBUG$$ Need to return an error if (NULL == m_pCallback) return TrapError(IXP_E_NOT_INIT); // Call the callback return m_pCallback->OnPrompt(hrError, pszText, pszCaption, uType, this); } // -------------------------------------------------------------------------------- // CIxpBase::OnError // -------------------------------------------------------------------------------- void CIxpBase::OnError(HRESULT hrResult, LPSTR pszProblem) { // Locals IXPRESULT rIxpResult; // No Callback if (NULL == m_pCallback) return; // Zero It ZeroMemory(&rIxpResult, sizeof(IXPRESULT)); // Save current state rIxpResult.hrResult = hrResult; rIxpResult.pszResponse = PszDupA(m_pszResponse); rIxpResult.uiServerError = m_uiResponse; rIxpResult.hrServerError = m_hrResponse; rIxpResult.dwSocketError = m_pSocket->GetLastError(); rIxpResult.pszProblem = PszDupA(pszProblem); if (m_pLogFile && pszProblem) { // Locals char szErrorTxt[1024]; // Build the Error wnsprintf(szErrorTxt, ARRAYSIZE(szErrorTxt), "ERROR: \"%.900s\", hr=%lu", pszProblem, hrResult); // Write the error m_pLogFile->WriteLog(LOGFILE_DB, szErrorTxt); } // Tell the watchdog to take a nap m_pSocket->StopWatchDog(); // Give to callback m_pCallback->OnError(m_status, &rIxpResult, this); // Start the watchdog and wait for normal socket activity m_pSocket->StartWatchDog(); // Free stuff SafeMemFree(rIxpResult.pszResponse); SafeMemFree(rIxpResult.pszProblem); } // -------------------------------------------------------------------------------- // CIxpBase::OnStatus // -------------------------------------------------------------------------------- void CIxpBase::OnStatus(IXPSTATUS ixpstatus) { // Save new Status m_status = ixpstatus; if (IXP_AUTHORIZED == ixpstatus) m_fAuthenticated = TRUE; else if (IXP_DISCONNECTED == ixpstatus || IXP_DISCONNECTING == ixpstatus) m_fAuthenticated = FALSE; // Give Status to callback if (m_pCallback) m_pCallback->OnStatus(ixpstatus, this); // If we're informing caller that we're authorized, head immediately to IXP_CONNECTED // UNLESS m_status is changed: this indicates state change (eg, disconnect) during callback if (IXP_AUTHORIZED == ixpstatus && IXP_AUTHORIZED == m_status) { m_status = IXP_CONNECTED; if (m_pCallback) m_pCallback->OnStatus(IXP_CONNECTED, this); } } // -------------------------------------------------------------------------------- // CIxpBase::HrEnterBusy // -------------------------------------------------------------------------------- HRESULT CIxpBase::HrEnterBusy(void) { // Locals HRESULT hr=S_OK; // Thread Safety EnterCriticalSection(&m_cs); // Initialized if (NULL == m_pSocket || NULL == m_pCallback) { hr = TrapError(IXP_E_NOT_INIT); goto exit; } // Not Ready if (TRUE == m_fBusy) { hr = TrapError(IXP_E_BUSY); goto exit; } // Start WatchDog m_pSocket->StartWatchDog(); // Busy m_fBusy = TRUE; exit: // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CIxpBase::LeaveBusy // -------------------------------------------------------------------------------- void CIxpBase::LeaveBusy(void) { // Thread Safety EnterCriticalSection(&m_cs); // Start WatchDog if (NULL != m_pSocket) { m_pSocket->StopWatchDog(); } // Busy m_fBusy = FALSE; // Thread Safety LeaveCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CIxpBase::HandsOffCallback // -------------------------------------------------------------------------------- STDMETHODIMP CIxpBase::HandsOffCallback(void) { // Locals HRESULT hr=S_OK; // Thread Safety EnterCriticalSection(&m_cs); // No current callback if (NULL == m_pCallback) { hr = TrapError(S_FALSE); goto exit; } // Release it SafeRelease(m_pCallback); exit: // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CIxpBase::OnInitNew // -------------------------------------------------------------------------------- HRESULT CIxpBase::OnInitNew(LPSTR pszProtocol, LPSTR pszLogFilePath, DWORD dwShareMode, ITransportCallback *pCallback) { // Locals HRESULT hr=S_OK; // check params if (NULL == pCallback || NULL == pszProtocol) return TrapError(E_INVALIDARG); // Thread Safety EnterCriticalSection(&m_cs); // Not connected if (IXP_DISCONNECTED != m_status) { hr = TrapError(IXP_E_ALREADY_CONNECTED); goto exit; } // release current objects Reset(); ResetBase(); // open log file if (pszLogFilePath) { // create the log file CreateLogFile(g_hInst, pszLogFilePath, pszProtocol, DONT_TRUNCATE, &m_pLogFile, dwShareMode); } // Create the socket m_pSocket = new CAsyncConn(m_pLogFile, (IAsyncConnCB *)this, (IAsyncConnPrompt *)this); if (NULL == m_pSocket) { hr = TrapError(E_OUTOFMEMORY); goto exit; } // Add Ref callback m_pCallback = pCallback; m_pCallback->AddRef(); exit: // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CIxpBase::GetServerInfo // -------------------------------------------------------------------------------- STDMETHODIMP CIxpBase::GetServerInfo(LPINETSERVER pInetServer) { // check params if (NULL == pInetServer) return TrapError(E_INVALIDARG); // Thread Safety EnterCriticalSection(&m_cs); // Copy Server information CopyMemory(pInetServer, &m_rServer, sizeof(INETSERVER)); // Thread Safety LeaveCriticalSection(&m_cs); // Done return S_OK; } // -------------------------------------------------------------------------------- // CIxpBase::Disconnect // -------------------------------------------------------------------------------- STDMETHODIMP CIxpBase::Disconnect(void) { // Locals HRESULT hr=S_OK; // Thread Safety EnterCriticalSection(&m_cs); // No socket... if (NULL == m_pSocket) { hr = TrapError(IXP_E_NOT_INIT); goto exit; } // Not connected if (IXP_DISCONNECTED == m_status) { hr = TrapError(IXP_E_NOT_CONNECTED); goto exit; } // Disconnecting OnStatus(IXP_DISCONNECTING); // State DoQuit(); exit: // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CIxpBase::DropConnection // -------------------------------------------------------------------------------- STDMETHODIMP CIxpBase::DropConnection(void) { // Locals HRESULT hr=S_OK; // Thread Safety EnterCriticalSection(&m_cs); // No socket... if (NULL == m_pSocket) { hr = TrapError(IXP_E_NOT_INIT); goto exit; } // Already IXP_DISCONNECTED if (IXP_DISCONNECTED != m_status) { // State OnStatus(IXP_DISCONNECTING); // Done CHECKHR(hr = m_pSocket->Close()); } exit: // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CIxpBase::InetServerFromAccount // -------------------------------------------------------------------------------- STDMETHODIMP CIxpBase::InetServerFromAccount(IImnAccount *pAccount, LPINETSERVER pInetServer) { // Locals HRESULT hr=S_OK; DWORD fAlwaysPromptPassword=FALSE; // check params if (NULL == pAccount || NULL == pInetServer) return TrapError(E_INVALIDARG); // ZeroInit ZeroMemory(pInetServer, sizeof(INETSERVER)); // Get the account name hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, pInetServer->szAccount, ARRAYSIZE(pInetServer->szAccount)); if (FAILED(hr)) { hr = TrapError(IXP_E_INVALID_ACCOUNT); goto exit; } // Get the RAS connectoid if (FAILED(pAccount->GetPropSz(AP_RAS_CONNECTOID, pInetServer->szConnectoid, ARRAYSIZE(pInetServer->szConnectoid)))) *pInetServer->szConnectoid = '\0'; // Connection Type Assert(sizeof(pInetServer->rasconntype) == sizeof(DWORD)); if (FAILED(pAccount->GetPropDw(AP_RAS_CONNECTION_TYPE, (DWORD *)&pInetServer->rasconntype))) pInetServer->rasconntype = RAS_CONNECT_LAN; // Connection Flags // IXP_SMTP if (IXP_SMTP == m_ixptype) { // Locals SMTPAUTHTYPE authtype; // Get Server Name hr = pAccount->GetPropSz(AP_SMTP_SERVER, pInetServer->szServerName, sizeof(pInetServer->szServerName)); if (FAILED(hr)) { hr = TrapError(IXP_E_INVALID_ACCOUNT); goto exit; } // SSL Assert(sizeof(pInetServer->fSSL) == sizeof(DWORD)); pAccount->GetPropDw(AP_SMTP_SSL, (DWORD *)&pInetServer->fSSL); // Sicily Assert(sizeof(authtype) == sizeof(DWORD)); if (FAILED(pAccount->GetPropDw(AP_SMTP_USE_SICILY, (DWORD *)&authtype))) authtype = SMTP_AUTH_NONE; if (SMTP_AUTH_NONE != authtype) { pInetServer->dwFlags |= ISF_QUERYAUTHSUPPORT; } // SMTP_AUTH_USE_POP3ORIMAP_SETTINGS if (SMTP_AUTH_USE_POP3ORIMAP_SETTINGS == authtype) { // Locals DWORD dwServers; DWORD dw; BOOL fIMAP; // Get Server Types if (FAILED(pAccount->GetServerTypes(&dwServers))) { hr = TrapError(IXP_E_INVALID_ACCOUNT); goto exit; } // fIMAP fIMAP = (ISFLAGSET(dwServers, SRV_IMAP)) ? TRUE : FALSE; // Using DPA if (SUCCEEDED(pAccount->GetPropDw(fIMAP ? AP_IMAP_USE_SICILY : AP_POP3_USE_SICILY, &dw)) && dw) pInetServer->fTrySicily = TRUE; // Get default username and password pAccount->GetPropSz(fIMAP ? AP_IMAP_USERNAME : AP_POP3_USERNAME, pInetServer->szUserName, sizeof(pInetServer->szUserName)); if (FAILED(pAccount->GetPropDw(fIMAP ? AP_IMAP_PROMPT_PASSWORD : AP_POP3_PROMPT_PASSWORD, &fAlwaysPromptPassword)) || FALSE == fAlwaysPromptPassword) { pAccount->GetPropSz(fIMAP ? AP_IMAP_PASSWORD : AP_POP3_PASSWORD, pInetServer->szPassword, sizeof(pInetServer->szPassword)); } if (!pInetServer->fTrySicily && fAlwaysPromptPassword) pInetServer->dwFlags|=ISF_ALWAYSPROMPTFORPASSWORD; } // SMTP_AUTH_USE_SMTP_SETTINGS else if (SMTP_AUTH_USE_SMTP_SETTINGS == authtype) { pInetServer->fTrySicily = TRUE; pAccount->GetPropSz(AP_SMTP_USERNAME, pInetServer->szUserName, sizeof(pInetServer->szUserName)); if (FAILED(pAccount->GetPropDw(AP_SMTP_PROMPT_PASSWORD, &fAlwaysPromptPassword)) || FALSE == fAlwaysPromptPassword) { pAccount->GetPropSz(AP_SMTP_PASSWORD, pInetServer->szPassword, sizeof(pInetServer->szPassword)); } if (fAlwaysPromptPassword) pInetServer->dwFlags|=ISF_ALWAYSPROMPTFORPASSWORD; } // Handle Authenticatin type else if (SMTP_AUTH_SICILY == authtype) pInetServer->fTrySicily = TRUE; // Port if (FAILED(pAccount->GetPropDw(AP_SMTP_PORT, &pInetServer->dwPort))) pInetServer->dwPort = DEFAULT_SMTP_PORT; // Timeout pAccount->GetPropDw(AP_SMTP_TIMEOUT, &pInetServer->dwTimeout); if (0 == pInetServer->dwTimeout) pInetServer->dwTimeout = 30; // Use STARTTLS? if ((FALSE != pInetServer->fSSL) && (DEFAULT_SMTP_PORT == pInetServer->dwPort)) pInetServer->dwFlags|=ISF_SSLONSAMEPORT; } // IXP_POP3 else if (IXP_POP3 == m_ixptype) { // Get Server Name hr = pAccount->GetPropSz(AP_POP3_SERVER, pInetServer->szServerName, sizeof(pInetServer->szServerName)); if (FAILED(hr)) { hr = TrapError(IXP_E_INVALID_ACCOUNT); goto exit; } // Password if (FAILED(pAccount->GetPropDw(AP_POP3_PROMPT_PASSWORD, &fAlwaysPromptPassword)) || FALSE == fAlwaysPromptPassword) pAccount->GetPropSz(AP_POP3_PASSWORD, pInetServer->szPassword, sizeof(pInetServer->szPassword)); // SSL Assert(sizeof(pInetServer->fSSL) == sizeof(DWORD)); pAccount->GetPropDw(AP_POP3_SSL, (DWORD *)&pInetServer->fSSL); // Sicily Assert(sizeof(pInetServer->fTrySicily) == sizeof(DWORD)); pAccount->GetPropDw(AP_POP3_USE_SICILY, (DWORD *)&pInetServer->fTrySicily); if (!pInetServer->fTrySicily && fAlwaysPromptPassword) pInetServer->dwFlags|=ISF_ALWAYSPROMPTFORPASSWORD; // Port if (FAILED(pAccount->GetPropDw(AP_POP3_PORT, &pInetServer->dwPort))) pInetServer->dwPort = 110; // User Name pAccount->GetPropSz(AP_POP3_USERNAME, pInetServer->szUserName, sizeof(pInetServer->szUserName)); // Timeout pAccount->GetPropDw(AP_POP3_TIMEOUT, &pInetServer->dwTimeout); } // IXP_IMAP else if (IXP_IMAP == m_ixptype) { // User name, password and server hr = pAccount->GetPropSz(AP_IMAP_USERNAME, pInetServer->szUserName, ARRAYSIZE(pInetServer->szUserName)); if (FAILED(hr)) pInetServer->szUserName[0] = '\0'; // If this is incorrect, we will re-prompt user hr = pAccount->GetPropDw(AP_IMAP_PROMPT_PASSWORD, &fAlwaysPromptPassword); if (FAILED(hr) || FALSE == fAlwaysPromptPassword) { hr = pAccount->GetPropSz(AP_IMAP_PASSWORD, pInetServer->szPassword, ARRAYSIZE(pInetServer->szPassword)); if (FAILED(hr)) pInetServer->szPassword[0] = '\0'; // If this is incorrect, we will re-prompt user } if (FAILED(hr = pAccount->GetPropSz(AP_IMAP_SERVER, pInetServer->szServerName, ARRAYSIZE(pInetServer->szServerName)))) goto exit; // We NEED to have a server name, so fail this function Assert(*pInetServer->szServerName); // Da port if (FAILED(hr = pAccount->GetPropDw(AP_IMAP_PORT, &pInetServer->dwPort))) pInetServer->dwPort = 143; // Default port number // Convert DWORD to boolean Assert(sizeof(pInetServer->fSSL) == sizeof(DWORD)); hr = pAccount->GetPropDw(AP_IMAP_SSL, (DWORD *)&pInetServer->fSSL); if (FAILED(hr)) pInetServer->fSSL = FALSE; // Default this value Assert(sizeof(pInetServer->fTrySicily) == sizeof(DWORD)); hr = pAccount->GetPropDw(AP_IMAP_USE_SICILY, (DWORD *)&pInetServer->fTrySicily); if (FAILED(hr)) pInetServer->fTrySicily = FALSE; // Default this value if (!pInetServer->fTrySicily && fAlwaysPromptPassword) pInetServer->dwFlags|=ISF_ALWAYSPROMPTFORPASSWORD; // Get the timeout hr = pAccount->GetPropDw(AP_IMAP_TIMEOUT, &pInetServer->dwTimeout); if (FAILED(hr)) pInetServer->dwTimeout = 30; // Default this value // If we've reached this point, we may have a failed HRESULT, but since we // must have defaulted the value, we should return success. hr = S_OK; } // IXP_NNTP else if (IXP_NNTP == m_ixptype) { // Get the server name hr = pAccount->GetPropSz(AP_NNTP_SERVER, pInetServer->szServerName, sizeof(pInetServer->szServerName)); if (FAILED(hr)) { hr = TrapError(IXP_E_INVALID_ACCOUNT); goto exit; } // Password if (FAILED(pAccount->GetPropDw(AP_NNTP_PROMPT_PASSWORD, &fAlwaysPromptPassword)) || FALSE == fAlwaysPromptPassword) pAccount->GetPropSz(AP_NNTP_PASSWORD, pInetServer->szPassword, sizeof(pInetServer->szPassword)); // SSL Assert(sizeof(pInetServer->fSSL) == sizeof(DWORD)); pAccount->GetPropDw(AP_NNTP_SSL, (DWORD *)&pInetServer->fSSL); // Sicily Assert(sizeof(pInetServer->fTrySicily) == sizeof(DWORD)); pAccount->GetPropDw(AP_NNTP_USE_SICILY, (DWORD *)&pInetServer->fTrySicily); if (!pInetServer->fTrySicily && fAlwaysPromptPassword) pInetServer->dwFlags|=ISF_ALWAYSPROMPTFORPASSWORD; // Port if (FAILED(pAccount->GetPropDw(AP_NNTP_PORT, &pInetServer->dwPort))) pInetServer->dwPort = 119; // User Name pAccount->GetPropSz(AP_NNTP_USERNAME, pInetServer->szUserName, sizeof(pInetServer->szUserName)); // Timeout pAccount->GetPropDw(AP_NNTP_TIMEOUT, &pInetServer->dwTimeout); } // Fix timeout if (pInetServer->dwTimeout < 30) pInetServer->dwTimeout = 30; exit: // Done return hr; } // -------------------------------------------------------------------------------- // CIxpBase::Connect // -------------------------------------------------------------------------------- STDMETHODIMP CIxpBase::Connect(LPINETSERVER pInetServer, boolean fAuthenticate, boolean fCommandLogging) { // Locals HRESULT hr=S_OK; BOOL fSecureSocket = FALSE; BOOL fConnectTLS = FALSE; // check params if (NULL == pInetServer || FIsEmptyA(pInetServer->szServerName) || pInetServer->dwPort == 0) return TrapError(E_INVALIDARG); // Thread Safety EnterCriticalSection(&m_cs); // not init if (NULL == m_pSocket || NULL == m_pCallback) { hr = TrapError(IXP_E_NOT_INIT); goto exit; } // busy if (IXP_DISCONNECTED != m_status) { hr = TrapError(IXP_E_ALREADY_CONNECTED); goto exit; } // Initialize Winsock CHECKHR(hr = HrInitializeWinsock()); // invalid sicily params if (pInetServer->fTrySicily && !FIsSicilyInstalled()) { hr = TrapError(IXP_E_LOAD_SICILY_FAILED); goto exit; } // Copy Server information CopyMemory(&m_rServer, pInetServer, sizeof(INETSERVER)); // Reset current ResetBase(); // Do we really want to connect to SMTP securely if (FALSE != m_rServer.fSSL) { // Do we want to connect to SMTP via a secure socket? fSecureSocket = (0 == (m_rServer.dwFlags & ISF_SSLONSAMEPORT)); // Do we want to use STARTTLS to get the secure connection? fConnectTLS = (0 != (m_rServer.dwFlags & ISF_SSLONSAMEPORT)); Assert(fSecureSocket != fConnectTLS); } // Get connection info needed to init async socket hr = m_pSocket->HrInit(m_rServer.szServerName, m_rServer.dwPort, fSecureSocket, m_rServer.dwTimeout); if (FAILED(hr)) { hr = TrapError(IXP_E_SOCKET_INIT_ERROR); goto exit; } // Finding Host Progress OnStatus(IXP_FINDINGHOST); // Connect to server hr = m_pSocket->Connect(); if (FAILED(hr)) { hr = TrapError(IXP_E_SOCKET_CONNECT_ERROR); goto exit; } // Were busy m_fBusy = TRUE; // Start WatchDog m_pSocket->StartWatchDog(); // Authenticate m_fConnectAuth = fAuthenticate; m_fConnectTLS = fConnectTLS; m_fCommandLogging = fCommandLogging; exit: // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CIxpBase::GetIXPType // -------------------------------------------------------------------------------- STDMETHODIMP_(IXPTYPE) CIxpBase::GetIXPType(void) { return m_ixptype; } // -------------------------------------------------------------------------------- // CIxpBase::OnConnected // -------------------------------------------------------------------------------- void CIxpBase::OnConnected(void) { OnStatus(IXP_CONNECTED); } // -------------------------------------------------------------------------------- // CIxpBase::OnDisconnected // -------------------------------------------------------------------------------- void CIxpBase::OnDisconnected(void) { LeaveBusy(); OnStatus(IXP_DISCONNECTED); } // -------------------------------------------------------------------------------- // CIxpBase::OnNotify // -------------------------------------------------------------------------------- void CIxpBase::OnNotify(ASYNCSTATE asOld, ASYNCSTATE asNew, ASYNCEVENT ae) { // Enter Critical Section EnterCriticalSection(&m_cs); switch(ae) { // -------------------------------------------------------------------------------- case AE_LOOKUPDONE: if (AS_DISCONNECTED == asNew) { char szFmt[CCHMAX_STRINGRES]; char szFailureText[CCHMAX_STRINGRES]; LoadString(g_hLocRes, idsHostNotFoundFmt, szFmt, ARRAYSIZE(szFmt)); wnsprintf(szFailureText, ARRAYSIZE(szFailureText), szFmt, m_rServer.szServerName); OnError(IXP_E_CANT_FIND_HOST, szFailureText); OnDisconnected(); } else OnStatus(IXP_CONNECTING); break; // -------------------------------------------------------------------------------- case AE_CONNECTDONE: if (AS_DISCONNECTED == asNew) { char szFailureText[CCHMAX_STRINGRES]; LoadString(g_hLocRes, idsFailedToConnect, szFailureText, ARRAYSIZE(szFailureText)); OnError(IXP_E_FAILED_TO_CONNECT, szFailureText); OnDisconnected(); } else if (AS_HANDSHAKING == asNew) { OnStatus(IXP_SECURING); } else OnConnected(); break; // -------------------------------------------------------------------------------- case AE_TIMEOUT: // Tell the watch dog to take nap m_pSocket->StopWatchDog(); // Provide the client with a change to continue, or abort if (m_pCallback && m_pCallback->OnTimeout(&m_rServer.dwTimeout, this) == S_OK) { // Start the watchdog and wait for normal socket activity m_pSocket->StartWatchDog(); } // Otherwise, if we are connected else { // Drop the connection now DropConnection(); } break; // -------------------------------------------------------------------------------- case AE_CLOSE: if (AS_RECONNECTING != asNew && IXP_AUTHRETRY != m_status) { if (IXP_DISCONNECTING != m_status && IXP_DISCONNECTED != m_status) { char szFailureText[CCHMAX_STRINGRES]; if (AS_HANDSHAKING == asOld) { LoadString(g_hLocRes, idsFailedToConnectSecurely, szFailureText, ARRAYSIZE(szFailureText)); OnError(IXP_E_SECURE_CONNECT_FAILED, szFailureText); } else { LoadString(g_hLocRes, idsUnexpectedTermination, szFailureText, ARRAYSIZE(szFailureText)); OnError(IXP_E_CONNECTION_DROPPED, szFailureText); } } OnDisconnected(); } break; } // Leave Critical Section LeaveCriticalSection(&m_cs); } // ------------------------------------------------------------------------------------ // CIxpBase::HrReadLine // ------------------------------------------------------------------------------------ HRESULT CIxpBase::HrReadLine(LPSTR *ppszLine, INT *pcbLine, BOOL *pfComplete) { // Locals HRESULT hr = E_INVALIDARG; // check params IxpAssert(ppszLine && pcbLine && pfComplete); if (!ppszLine || !pcbLine || !pfComplete) goto exit; // Init *ppszLine = NULL; *pcbLine = 0; // Read the line hr = m_pSocket->ReadLine(ppszLine, pcbLine); // Incomplete line - wait for next AE_RECV if (IXP_E_INCOMPLETE == hr) { hr = S_OK; *pfComplete = FALSE; goto exit; } // Otherwise, if failure... else if (FAILED(hr)) { hr = TrapError(IXP_E_SOCKET_READ_ERROR); goto exit; } // Complete *pfComplete = TRUE; // Log it if (m_pLogFile) m_pLogFile->WriteLog(LOGFILE_RX, (*ppszLine)); // StripCRLF StripCRLF((*ppszLine), (ULONG *)pcbLine); exit: // Done return hr; } // ------------------------------------------------------------------------------------ // CIxpBase::HrSendLine // ------------------------------------------------------------------------------------ HRESULT CIxpBase::HrSendLine(LPSTR pszLine) { // Locals HRESULT hr=S_OK; int iSent; // Check Params Assert(m_pSocket && pszLine && pszLine[lstrlen(pszLine)-1] == '\n'); // Reset Last Response SafeMemFree(m_pszResponse); m_hrResponse = S_OK; m_uiResponse = 0; // Add Detail if (m_fCommandLogging && m_pCallback) m_pCallback->OnCommand(CMD_SEND, pszLine, S_OK, this); // Log it if (m_pLogFile) m_pLogFile->WriteLog(LOGFILE_TX, pszLine); // Send it hr = m_pSocket->SendBytes(pszLine, lstrlen(pszLine), &iSent); if (FAILED(hr) && hr != IXP_E_WOULD_BLOCK) { hr = TrapError(IXP_E_SOCKET_WRITE_ERROR); goto exit; } // Success hr = S_OK; exit: // Done return hr; } // ------------------------------------------------------------------------------------ // CIxpBase::HrSendCommand // ------------------------------------------------------------------------------------ HRESULT CIxpBase::HrSendCommand(LPSTR pszCommand, LPSTR pszParameters, BOOL fDoBusy) { // Locals HRESULT hr=S_OK; LPSTR pszLine=NULL; // check params if (NULL == pszCommand) return TrapError(E_INVALIDARG); // Thread Safety EnterCriticalSection(&m_cs); // Busy... if (fDoBusy) { CHECKHR(hr = HrEnterBusy()); } // Allocate if parameters if (pszParameters) { // Allocate Command Line DWORD cchSize = (lstrlen(pszCommand) + lstrlen(pszParameters) + 5); pszLine = PszAlloc(cchSize); if (NULL == pszLine) { hr = TrapError(E_OUTOFMEMORY); goto exit; } // Make Line wnsprintf(pszLine, cchSize, "%s %s\r\n", pszCommand, pszParameters); // Send CHECKHR(hr = HrSendLine(pszLine)); } // Ohterwise, just send the command else { Assert(pszCommand[lstrlen(pszCommand)-1] == '\n'); CHECKHR(hr = HrSendLine(pszCommand)); } exit: // Failure if (fDoBusy && FAILED(hr)) LeaveBusy(); // Cleanup SafeMemFree(pszLine); // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CIxpBase::GetStatus // -------------------------------------------------------------------------------- STDMETHODIMP CIxpBase::GetStatus(IXPSTATUS *pCurrentStatus) { if (NULL == pCurrentStatus) return E_INVALIDARG; *pCurrentStatus = m_status; return S_OK; } // GetStatus