You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1106 lines
32 KiB
1106 lines
32 KiB
// --------------------------------------------------------------------------------
|
|
// 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
|