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.
2320 lines
68 KiB
2320 lines
68 KiB
// --------------------------------------------------------------------------------
|
|
// Ixppop3.cpp
|
|
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
|
|
// Steven J. Bailey
|
|
// --------------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "dllmain.h"
|
|
#include "ixppop3.h"
|
|
#include "asynconn.h"
|
|
#include "ixputil.h"
|
|
#include "strconst.h"
|
|
#include <shlwapi.h>
|
|
#include <ntverp.h>
|
|
#include "demand.h"
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Usefule C++ pointer casting
|
|
// --------------------------------------------------------------------------------
|
|
#define POP3THISIXP ((IPOP3Transport *)(CIxpBase *)this)
|
|
#define STR_HOTMAILAUTH "Outlook Express V" VER_PRODUCTVERSION_STR
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// FreeAuthInfo
|
|
// --------------------------------------------------------------------------------
|
|
void FreeAuthInfo(LPAUTHINFO pAuth)
|
|
{
|
|
for (UINT i=0; i<pAuth->cAuthToken; i++)
|
|
{
|
|
ZeroMemory(pAuth->rgpszAuthTokens[i], sizeof(pAuth->rgpszAuthTokens[i][0]) * lstrlen(pAuth->rgpszAuthTokens[i]));
|
|
SafeMemFree(pAuth->rgpszAuthTokens[i]);
|
|
}
|
|
pAuth->iAuthToken = pAuth->cAuthToken = 0;
|
|
if (pAuth->pPackages && pAuth->cPackages)
|
|
{
|
|
SSPIFreePackages(&pAuth->pPackages, pAuth->cPackages);
|
|
pAuth->pPackages = NULL;
|
|
pAuth->cPackages = 0;
|
|
}
|
|
SSPIFreeContext(&pAuth->rSicInfo);
|
|
ZeroMemory(pAuth, sizeof(*pAuth));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::CPOP3Transport
|
|
// --------------------------------------------------------------------------------
|
|
CPOP3Transport::CPOP3Transport(void) : CIxpBase(IXP_POP3)
|
|
{
|
|
DllAddRef();
|
|
ZeroMemory(&m_rInfo, sizeof(POP3INFO));
|
|
m_rInfo.rAuth.authstate = AUTH_NONE;
|
|
m_command = POP3_NONE;
|
|
m_fHotmail = FALSE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::~CPOP3Transport
|
|
// --------------------------------------------------------------------------------
|
|
CPOP3Transport::~CPOP3Transport(void)
|
|
{
|
|
ResetBase();
|
|
DllRelease();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::ResetBase
|
|
// --------------------------------------------------------------------------------
|
|
void CPOP3Transport::ResetBase(void)
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
FreeAuthInfo(&m_rInfo.rAuth);
|
|
SafeMemFree(m_rInfo.prgMarked);
|
|
ZeroMemory(&m_rInfo, sizeof(m_rInfo));
|
|
m_command = POP3_NONE;
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::QueryInterface
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Bad param
|
|
if (ppv == NULL)
|
|
{
|
|
hr = TrapError(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
// Init
|
|
*ppv=NULL;
|
|
|
|
// IID_IUnknown
|
|
if (IID_IUnknown == riid)
|
|
*ppv = ((IUnknown *)(IPOP3Transport *)this);
|
|
|
|
// IID_IInternetTransport
|
|
else if (IID_IInternetTransport == riid)
|
|
*ppv = ((IInternetTransport *)(CIxpBase *)this);
|
|
|
|
// IID_IPOP3Transport
|
|
else if (IID_IPOP3Transport == riid)
|
|
*ppv = (IPOP3Transport *)this;
|
|
|
|
// If not null, addref it and return
|
|
if (NULL != *ppv)
|
|
{
|
|
((LPUNKNOWN)*ppv)->AddRef();
|
|
goto exit;
|
|
}
|
|
|
|
// No Interface
|
|
hr = TrapError(E_NOINTERFACE);
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::AddRef
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CPOP3Transport::AddRef(void)
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::Release
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CPOP3Transport::Release(void)
|
|
{
|
|
if (0 != --m_cRef)
|
|
return m_cRef;
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::InitNew
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::InitNew(LPSTR pszLogFilePath, IPOP3Callback *pCallback)
|
|
{
|
|
// Call Base Class
|
|
return CIxpBase::OnInitNew("POP3", pszLogFilePath, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
(ITransportCallback *)pCallback);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::HandsOffCallback
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::HandsOffCallback(void)
|
|
{
|
|
return CIxpBase::HandsOffCallback();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::GetStatus
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::GetStatus(IXPSTATUS *pCurrentStatus)
|
|
{
|
|
return CIxpBase::GetStatus(pCurrentStatus);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::InetServerFromAccount
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::InetServerFromAccount(IImnAccount *pAccount, LPINETSERVER pInetServer)
|
|
{
|
|
return CIxpBase::InetServerFromAccount(pAccount, pInetServer);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::Connect
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::Connect(LPINETSERVER pInetServer, boolean fAuthenticate, boolean fCommandLogging)
|
|
{
|
|
// Does user want us to always prompt for his password? Prompt him here to avoid
|
|
// inactivity timeouts while the prompt is up, unless a password was supplied
|
|
if (ISFLAGSET(pInetServer->dwFlags, ISF_ALWAYSPROMPTFORPASSWORD) &&
|
|
'\0' == pInetServer->szPassword[0])
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (NULL != m_pCallback)
|
|
hr = m_pCallback->OnLogonPrompt(pInetServer, POP3THISIXP);
|
|
|
|
if (NULL == m_pCallback || S_OK != hr)
|
|
return IXP_E_USER_CANCEL;
|
|
}
|
|
|
|
return CIxpBase::Connect(pInetServer, fAuthenticate, fCommandLogging);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::DropConnection
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::DropConnection(void)
|
|
{
|
|
return CIxpBase::DropConnection();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::Disconnect
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::Disconnect(void)
|
|
{
|
|
return CIxpBase::Disconnect();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::IsState
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::IsState(IXPISSTATE isstate)
|
|
{
|
|
return CIxpBase::IsState(isstate);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::GetServerInfo
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::GetServerInfo(LPINETSERVER pInetServer)
|
|
{
|
|
return CIxpBase::GetServerInfo(pInetServer);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::GetIXPType
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(IXPTYPE) CPOP3Transport::GetIXPType(void)
|
|
{
|
|
return CIxpBase::GetIXPType();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::OnEnterBusy
|
|
// --------------------------------------------------------------------------------
|
|
void CPOP3Transport::OnEnterBusy(void)
|
|
{
|
|
IxpAssert(m_command == POP3_NONE);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::OnLeaveBusy
|
|
// --------------------------------------------------------------------------------
|
|
void CPOP3Transport::OnLeaveBusy(void)
|
|
{
|
|
m_command = POP3_NONE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::OnConnected
|
|
// --------------------------------------------------------------------------------
|
|
void CPOP3Transport::OnConnected(void)
|
|
{
|
|
m_command = POP3_BANNER;
|
|
CIxpBase::OnConnected();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::OnDisconnect
|
|
// --------------------------------------------------------------------------------
|
|
void CPOP3Transport::OnDisconnected(void)
|
|
{
|
|
ResetBase();
|
|
CIxpBase::OnDisconnected();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::OnNotify
|
|
// --------------------------------------------------------------------------------
|
|
void CPOP3Transport::OnNotify(ASYNCSTATE asOld, ASYNCSTATE asNew, ASYNCEVENT ae)
|
|
{
|
|
// Enter Critical Section
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Handle Event
|
|
switch(ae)
|
|
{
|
|
// --------------------------------------------------------------------------------
|
|
case AE_RECV:
|
|
OnSocketReceive();
|
|
break;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
default:
|
|
CIxpBase::OnNotify(asOld, asNew, ae);
|
|
break;
|
|
}
|
|
|
|
// Leave Critical Section
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::OnSocketReceive
|
|
// --------------------------------------------------------------------------------
|
|
void CPOP3Transport::OnSocketReceive(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr;
|
|
|
|
// Enter Critical Section
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Handle Current pop3 state
|
|
switch(m_command)
|
|
{
|
|
// --------------------------------------------------------------------------------
|
|
case POP3_BANNER:
|
|
// Read Server Response...
|
|
hr = HrGetResponse();
|
|
if (IXP_E_INCOMPLETE == hr)
|
|
goto exit;
|
|
|
|
// Detect if the banner had the word hotmail in it
|
|
Assert(m_pszResponse);
|
|
m_fHotmail = (NULL == m_pszResponse || NULL == StrStrIA(m_pszResponse, "hotmail")) ? FALSE : TRUE;
|
|
|
|
// Dispatch the response
|
|
DispatchResponse(hr);
|
|
|
|
// Authorizing
|
|
if (m_fConnectAuth)
|
|
StartLogon();
|
|
|
|
// Ohterwise were connected
|
|
else
|
|
{
|
|
m_command = POP3_CONNECTED;
|
|
DispatchResponse(S_OK);
|
|
}
|
|
|
|
// Not yet auth'ed
|
|
m_fAuthenticated = FALSE;
|
|
break;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
case POP3_USER:
|
|
// Read Server Response...
|
|
hr = HrGetResponse();
|
|
if (IXP_E_INCOMPLETE == hr)
|
|
goto exit;
|
|
|
|
// Dispatch the response
|
|
DispatchResponse(FAILED(hr) ? IXP_E_POP3_INVALID_USER_NAME : S_OK);
|
|
|
|
// Authorizing
|
|
if (m_fConnectAuth)
|
|
{
|
|
// Retry logon
|
|
if (FAILED(hr))
|
|
LogonRetry(IXP_E_POP3_INVALID_USER_NAME);
|
|
|
|
// otherwise send the password
|
|
else
|
|
{
|
|
hr = CommandPASS(m_rServer.szPassword);
|
|
if (FAILED(hr))
|
|
{
|
|
OnError(hr);
|
|
DropConnection();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
case POP3_PASS:
|
|
// Read Server Response...
|
|
hr = HrGetResponse();
|
|
if (IXP_E_INCOMPLETE == hr)
|
|
goto exit;
|
|
|
|
// Dispatch the response
|
|
DispatchResponse(FAILED(hr) ? IXP_E_POP3_INVALID_PASSWORD : S_OK);
|
|
|
|
// Authorizing
|
|
if (m_fConnectAuth)
|
|
{
|
|
// Retry if failed
|
|
if (FAILED(hr))
|
|
LogonRetry(IXP_E_POP3_INVALID_PASSWORD);
|
|
|
|
// Otherwise, we're authorized
|
|
else
|
|
{
|
|
OnStatus(IXP_AUTHORIZED);
|
|
m_fConnectAuth = FALSE;
|
|
m_command = POP3_CONNECTED;
|
|
DispatchResponse(S_OK);
|
|
}
|
|
}
|
|
break;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
case POP3_AUTH:
|
|
// If hotmail, then, we've identified ourselves, so lets send the user command
|
|
if (m_fHotmail)
|
|
{
|
|
// Read Server Response...
|
|
hr = HrGetResponse();
|
|
if (IXP_E_INCOMPLETE == hr)
|
|
goto exit;
|
|
|
|
// Issue the user command
|
|
hr = CommandUSER(m_rServer.szUserName);
|
|
if (FAILED(hr))
|
|
{
|
|
OnError(hr);
|
|
DropConnection();
|
|
}
|
|
}
|
|
|
|
// Otherwise, lets continue DPA auth
|
|
else if (m_rInfo.rAuth.authstate != AUTH_ENUMPACKS_DATA)
|
|
{
|
|
// Read Server Response...
|
|
hr = HrGetResponse();
|
|
if (IXP_E_INCOMPLETE == hr)
|
|
goto exit;
|
|
|
|
// Authenticating
|
|
if (m_fConnectAuth)
|
|
{
|
|
ResponseAUTH(hr);
|
|
}
|
|
else
|
|
{
|
|
// Dispatch the response
|
|
DispatchResponse(hr);
|
|
}
|
|
}
|
|
|
|
// Otherwise, handle resposne
|
|
else
|
|
{
|
|
// no HrGetResponse() because we are getting list data
|
|
ResponseAUTH(0);
|
|
}
|
|
break;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
case POP3_STAT:
|
|
ResponseSTAT();
|
|
break;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
case POP3_NOOP:
|
|
// Read Server Response...
|
|
hr = HrGetResponse();
|
|
if (IXP_E_INCOMPLETE == hr)
|
|
goto exit;
|
|
|
|
// Dispatch the response
|
|
DispatchResponse(hr, TRUE);
|
|
break;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
case POP3_UIDL:
|
|
case POP3_LIST:
|
|
ResponseGenericList();
|
|
break;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
case POP3_DELE:
|
|
ResponseDELE();
|
|
break;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
case POP3_RETR:
|
|
case POP3_TOP:
|
|
ResponseGenericRetrieve();
|
|
break;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
case POP3_QUIT:
|
|
// Read Server Response...
|
|
hr = HrGetResponse();
|
|
if (IXP_E_INCOMPLETE == hr)
|
|
goto exit;
|
|
|
|
// Dispatch the response
|
|
DispatchResponse(hr, FALSE);
|
|
|
|
// Drop the socket
|
|
m_pSocket->Close();
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::DispatchResponse
|
|
// ------------------------------------------------------------------------------------
|
|
void CPOP3Transport::DispatchResponse(HRESULT hrResult, BOOL fDone, LPPOP3RESPONSE pResponse)
|
|
{
|
|
// Locals
|
|
POP3RESPONSE rResponse;
|
|
|
|
// If a response was passed in, use it...
|
|
if (pResponse)
|
|
CopyMemory(&rResponse, pResponse, sizeof(POP3RESPONSE));
|
|
else
|
|
ZeroMemory(&rResponse, sizeof(POP3RESPONSE));
|
|
|
|
// Set the HRESULT
|
|
rResponse.command = m_command;
|
|
rResponse.rIxpResult.hrResult = hrResult;
|
|
rResponse.rIxpResult.pszResponse = m_pszResponse;
|
|
rResponse.rIxpResult.uiServerError = m_uiResponse;
|
|
rResponse.rIxpResult.hrServerError = m_hrResponse;
|
|
rResponse.rIxpResult.dwSocketError = m_pSocket->GetLastError();
|
|
rResponse.rIxpResult.pszProblem = NULL;
|
|
rResponse.fDone = fDone;
|
|
rResponse.pTransport = this;
|
|
|
|
// If Done...
|
|
if (fDone)
|
|
{
|
|
// No current command
|
|
m_command = POP3_NONE;
|
|
|
|
// Leave Busy State
|
|
LeaveBusy();
|
|
}
|
|
|
|
// Give the Response to the client
|
|
if (m_pCallback)
|
|
((IPOP3Callback *)m_pCallback)->OnResponse(&rResponse);
|
|
|
|
// Reset Last Response
|
|
SafeMemFree(m_pszResponse);
|
|
m_hrResponse = S_OK;
|
|
m_uiResponse = 0;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPOP3Transport::HrGetResponse
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPOP3Transport::HrGetResponse(void)
|
|
{
|
|
// Locals
|
|
INT cbLine;
|
|
BOOL fComplete;
|
|
|
|
// Clear current response
|
|
IxpAssert(m_pszResponse == NULL && m_hrResponse == S_OK);
|
|
|
|
// Set m_hrResponse
|
|
m_hrResponse = S_OK;
|
|
|
|
// Read Line
|
|
m_hrResponse = HrReadLine(&m_pszResponse, &cbLine, &fComplete);
|
|
if (FAILED(m_hrResponse))
|
|
goto exit;
|
|
|
|
// If not complete
|
|
if (!fComplete)
|
|
goto exit;
|
|
|
|
// - Response
|
|
if ('+' != m_pszResponse[0])
|
|
{
|
|
m_hrResponse = TrapError(IXP_E_POP3_RESPONSE_ERROR);
|
|
if (m_pCallback && m_fCommandLogging)
|
|
m_pCallback->OnCommand(CMD_RESP, m_pszResponse, m_hrResponse, POP3THISIXP);
|
|
goto exit;
|
|
}
|
|
|
|
// Don't log UIDL or LIST response lines...
|
|
else if (m_pCallback && m_fCommandLogging)
|
|
m_pCallback->OnCommand(CMD_RESP, m_pszResponse, S_OK, POP3THISIXP);
|
|
|
|
exit:
|
|
// Exit
|
|
return m_hrResponse;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::StartLogon
|
|
// ------------------------------------------------------------------------------------
|
|
void CPOP3Transport::StartLogon(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr;
|
|
|
|
// Progress
|
|
OnStatus(IXP_AUTHORIZING);
|
|
|
|
// If Not Using Sicily or its not installed, then send USER command
|
|
if (FALSE == m_rServer.fTrySicily || FALSE == FIsSicilyInstalled())
|
|
{
|
|
// If Hotmail, send the AUTH OutlookExpress command
|
|
if (m_fHotmail)
|
|
{
|
|
// Otherwise, send AUTH enumpacks command
|
|
hr = CommandAUTH(STR_HOTMAILAUTH);
|
|
if (FAILED(hr))
|
|
{
|
|
OnError(hr);
|
|
DropConnection();
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
// Issue the user command
|
|
hr = CommandUSER(m_rServer.szUserName);
|
|
if (FAILED(hr))
|
|
{
|
|
OnError(hr);
|
|
DropConnection();
|
|
}
|
|
}
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
// Turn Off HOtmail
|
|
m_fHotmail = FALSE;
|
|
|
|
// Otherwise, send AUTH enumpacks command
|
|
hr = CommandAUTH((LPSTR)"");
|
|
if (FAILED(hr))
|
|
{
|
|
OnError(hr);
|
|
DropConnection();
|
|
}
|
|
|
|
// Otherwise, set the state
|
|
m_rInfo.rAuth.authstate = AUTH_ENUMPACKS;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::LogonRetry
|
|
// ------------------------------------------------------------------------------------
|
|
void CPOP3Transport::LogonRetry(HRESULT hrLogon)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Give logon failed status
|
|
// OnError(hrLogon);
|
|
|
|
// Auth Retry
|
|
OnStatus(IXP_AUTHRETRY);
|
|
|
|
// Enter Auth Retry State
|
|
m_pSocket->Close();
|
|
|
|
// Logon
|
|
if (NULL == m_pCallback || m_pCallback->OnLogonPrompt(&m_rServer, POP3THISIXP) != S_OK)
|
|
{
|
|
// Go to terminal state, were done.
|
|
OnDisconnected();
|
|
return;
|
|
}
|
|
|
|
// Finding Host Progress
|
|
OnStatus(IXP_FINDINGHOST);
|
|
|
|
// Connect to server
|
|
hr = m_pSocket->Connect();
|
|
if (FAILED(hr))
|
|
{
|
|
OnError(TrapError(IXP_E_SOCKET_CONNECT_ERROR));
|
|
OnDisconnected();
|
|
return;
|
|
}
|
|
|
|
// Start WatchDog
|
|
m_pSocket->StartWatchDog();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::ResponseAUTH
|
|
// ------------------------------------------------------------------------------------
|
|
void CPOP3Transport::ResponseAUTH(HRESULT hrResponse)
|
|
{
|
|
// Locals
|
|
HRESULT hr;
|
|
BOOL fPackageInstalled;
|
|
SSPIBUFFER Negotiate;
|
|
SSPIBUFFER Challenge;
|
|
SSPIBUFFER Response;
|
|
ULONG i;
|
|
|
|
// We better be in sicily
|
|
Assert(FIsSicilyInstalled());
|
|
|
|
// If we just started enumerating packages...
|
|
if (m_rInfo.rAuth.authstate == AUTH_ENUMPACKS)
|
|
{
|
|
// Free old tokens
|
|
for (i=0; i<m_rInfo.rAuth.cAuthToken; i++)
|
|
{
|
|
ZeroMemory(m_rInfo.rAuth.rgpszAuthTokens[i], sizeof(m_rInfo.rAuth.rgpszAuthTokens[i][0]) * lstrlen(m_rInfo.rAuth.rgpszAuthTokens[i]));
|
|
SafeMemFree(m_rInfo.rAuth.rgpszAuthTokens[i]);
|
|
}
|
|
m_rInfo.rAuth.iAuthToken = m_rInfo.rAuth.cAuthToken = 0;
|
|
|
|
if (SUCCEEDED(hrResponse))
|
|
{
|
|
m_rInfo.rAuth.authstate = AUTH_ENUMPACKS_DATA;
|
|
goto EnumData;
|
|
}
|
|
|
|
OnError(IXP_E_SICILY_LOGON_FAILED);
|
|
hr = CommandQUIT();
|
|
if (FAILED(hr))
|
|
DropConnection();
|
|
return;
|
|
}
|
|
|
|
else if (m_rInfo.rAuth.authstate == AUTH_ENUMPACKS_DATA)
|
|
{
|
|
EnumData:
|
|
int cbLine;
|
|
BOOL fComplete;
|
|
|
|
// Clear Response
|
|
SafeMemFree(m_pszResponse);
|
|
m_uiResponse = 0;
|
|
m_hrResponse = S_OK;
|
|
|
|
// Read a blob of lines
|
|
while (m_rInfo.rAuth.cAuthToken < MAX_AUTH_TOKENS)
|
|
{
|
|
// Read the line
|
|
hr = HrReadLine(&m_pszResponse, &cbLine, &fComplete);
|
|
if (FAILED(hr))
|
|
{
|
|
OnError(hr);
|
|
DropConnection();
|
|
}
|
|
|
|
// If not complete
|
|
if (!fComplete)
|
|
return;
|
|
|
|
// Add Detail
|
|
if (m_pCallback && m_fCommandLogging)
|
|
m_pCallback->OnCommand(CMD_RESP, m_pszResponse, S_OK, POP3THISIXP);
|
|
|
|
// StripCRLF
|
|
StripCRLF(m_pszResponse, (ULONG *)&cbLine);
|
|
|
|
// If its a dot, were done
|
|
if (*m_pszResponse == '.')
|
|
break;
|
|
|
|
m_rInfo.rAuth.rgpszAuthTokens[m_rInfo.rAuth.cAuthToken++] = m_pszResponse;
|
|
}
|
|
|
|
if (!m_rInfo.rAuth.cAuthToken)
|
|
{
|
|
OnError(IXP_E_SICILY_LOGON_FAILED);
|
|
hr = CommandQUIT();
|
|
if (FAILED(hr))
|
|
DropConnection();
|
|
return;
|
|
}
|
|
|
|
// Free current packages...
|
|
if (m_rInfo.rAuth.pPackages && m_rInfo.rAuth.cPackages)
|
|
{
|
|
SSPIFreePackages(&m_rInfo.rAuth.pPackages, m_rInfo.rAuth.cPackages);
|
|
m_rInfo.rAuth.pPackages = NULL;
|
|
m_rInfo.rAuth.cPackages = 0;
|
|
}
|
|
|
|
// Get installed security packages
|
|
if (FAILED(SSPIGetPackages(&m_rInfo.rAuth.pPackages, &m_rInfo.rAuth.cPackages)))
|
|
{
|
|
OnError(IXP_E_LOAD_SICILY_FAILED);
|
|
hr = CommandQUIT();
|
|
if (FAILED(hr))
|
|
DropConnection();
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Otherwise, we must have just tryed a package
|
|
else if (m_rInfo.rAuth.authstate == AUTH_TRYING_PACKAGE)
|
|
{
|
|
// Stop the WatchDog
|
|
m_pSocket->StopWatchDog();
|
|
|
|
// If Success Response
|
|
if (SUCCEEDED(hrResponse))
|
|
{
|
|
// Do Sicily Logon
|
|
Assert(m_rInfo.rAuth.iAuthToken < m_rInfo.rAuth.cAuthToken);
|
|
|
|
if (SUCCEEDED(SSPILogon(&m_rInfo.rAuth.rSicInfo, m_rInfo.rAuth.fRetryPackage, SSPI_BASE64, m_rInfo.rAuth.rgpszAuthTokens[m_rInfo.rAuth.iAuthToken], &m_rServer, m_pCallback)))
|
|
{
|
|
if (m_rInfo.rAuth.fRetryPackage)
|
|
{
|
|
// Don't retry again
|
|
m_rInfo.rAuth.fRetryPackage = FALSE;
|
|
}
|
|
|
|
// Get negotiation string
|
|
if (SUCCEEDED(SSPIGetNegotiate(&m_rInfo.rAuth.rSicInfo, &Negotiate)))
|
|
{
|
|
// Send AUTH Respons
|
|
if (SUCCEEDED(HrSendSicilyString(Negotiate.szBuffer)))
|
|
{
|
|
m_rInfo.rAuth.authstate = AUTH_NEGO_RESP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HrCancelAuthInProg();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HrCancelAuthInProg();
|
|
}
|
|
|
|
// Start the WatchDog
|
|
m_pSocket->StartWatchDog();
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
// That failed, free sicinfo and go on with life
|
|
SSPIFreeContext(&m_rInfo.rAuth.rSicInfo);
|
|
|
|
// Goto Next Package
|
|
m_rInfo.rAuth.iAuthToken++;
|
|
}
|
|
|
|
// Otherwise, we got a response from a negotiation string
|
|
else if (m_rInfo.rAuth.authstate == AUTH_NEGO_RESP)
|
|
{
|
|
// Start the WatchDog
|
|
m_pSocket->StopWatchDog();
|
|
|
|
// Succeeded Response
|
|
if (SUCCEEDED(hrResponse))
|
|
{
|
|
// Set Chal String - skip over "+ "
|
|
SSPISetBuffer(m_pszResponse + 2, SSPI_STRING, 0, &Challenge);
|
|
|
|
// Get response from challenge
|
|
if (SUCCEEDED(SSPIResponseFromChallenge(&m_rInfo.rAuth.rSicInfo, &Challenge, &Response)))
|
|
{
|
|
// Send AUTH Respons
|
|
if (SUCCEEDED(HrSendSicilyString(Response.szBuffer)))
|
|
{
|
|
// if we need to continue, we keep the state the same
|
|
// else we transition to the AUTH_RESP_RESP state.
|
|
if (!Response.fContinue)
|
|
m_rInfo.rAuth.authstate = AUTH_RESP_RESP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HrCancelAuthInProg();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// retry current package, with prompt
|
|
m_rInfo.rAuth.fRetryPackage = TRUE;
|
|
|
|
Assert(m_rInfo.rAuth.iAuthToken < m_rInfo.rAuth.cAuthToken);
|
|
hr = CommandAUTH(m_rInfo.rAuth.rgpszAuthTokens[m_rInfo.rAuth.iAuthToken]);
|
|
if (FAILED(hr))
|
|
{
|
|
OnError(hr);
|
|
DropConnection();
|
|
return;
|
|
}
|
|
|
|
// We are in the TRYING_PACKAGE state
|
|
m_rInfo.rAuth.authstate = AUTH_TRYING_PACKAGE;
|
|
|
|
SSPIFreeContext(&m_rInfo.rAuth.rSicInfo);
|
|
}
|
|
|
|
// Start the WatchDog
|
|
m_pSocket->StartWatchDog();
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
// Otherwise, we got a response from a challenge response string
|
|
else if (m_rInfo.rAuth.authstate == AUTH_RESP_RESP)
|
|
{
|
|
// If that succeeded
|
|
if (SUCCEEDED(hrResponse))
|
|
{
|
|
// We will free the context, but keep the credential handle
|
|
SSPIReleaseContext(&m_rInfo.rAuth.rSicInfo);
|
|
|
|
// Connected (Authorized) state
|
|
OnStatus(IXP_AUTHORIZED);
|
|
m_fConnectAuth = FALSE;
|
|
m_command = POP3_CONNECTED;
|
|
DispatchResponse(S_OK);
|
|
|
|
}
|
|
else
|
|
{
|
|
// retry current package, with prompt
|
|
m_rInfo.rAuth.fRetryPackage = TRUE;
|
|
|
|
Assert(m_rInfo.rAuth.iAuthToken < m_rInfo.rAuth.cAuthToken);
|
|
hr = CommandAUTH(m_rInfo.rAuth.rgpszAuthTokens[m_rInfo.rAuth.iAuthToken]);
|
|
if (FAILED(hr))
|
|
{
|
|
OnError(hr);
|
|
DropConnection();
|
|
return;
|
|
}
|
|
|
|
// We are in the TRYING_PACKAGE state
|
|
m_rInfo.rAuth.authstate = AUTH_TRYING_PACKAGE;
|
|
|
|
SSPIFreeContext(&m_rInfo.rAuth.rSicInfo);
|
|
}
|
|
return;
|
|
}
|
|
else if (m_rInfo.rAuth.authstate == AUTH_CANCELED)
|
|
{
|
|
SSPIFreeContext(&m_rInfo.rAuth.rSicInfo);
|
|
|
|
// Goto Next Package
|
|
m_rInfo.rAuth.iAuthToken++;
|
|
}
|
|
|
|
|
|
// Loop through the auth tokens, and try to authenticate with each one in order
|
|
while(m_rInfo.rAuth.iAuthToken < m_rInfo.rAuth.cAuthToken)
|
|
{
|
|
// We will handle basic authentication
|
|
if (lstrcmpi(m_rInfo.rAuth.rgpszAuthTokens[m_rInfo.rAuth.iAuthToken], "BASIC") != 0)
|
|
{
|
|
// Package not installed ?
|
|
fPackageInstalled=FALSE;
|
|
for (i=0; i<m_rInfo.rAuth.cPackages; i++)
|
|
{
|
|
// Null Package ??
|
|
if (!m_rInfo.rAuth.pPackages[i].pszName)
|
|
continue;
|
|
|
|
// Is this the package I am looking for
|
|
if (lstrcmpi(m_rInfo.rAuth.pPackages[i].pszName, m_rInfo.rAuth.rgpszAuthTokens[m_rInfo.rAuth.iAuthToken]) == 0)
|
|
{
|
|
fPackageInstalled = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Package not installed ?
|
|
if (fPackageInstalled)
|
|
{
|
|
m_rInfo.rAuth.fRetryPackage = FALSE;
|
|
|
|
// If the package has a realm, send digest, otherwise, send normal
|
|
hr = CommandAUTH(m_rInfo.rAuth.rgpszAuthTokens[m_rInfo.rAuth.iAuthToken]);
|
|
if (FAILED(hr))
|
|
{
|
|
OnError(hr);
|
|
DropConnection();
|
|
return;
|
|
}
|
|
|
|
// We are in the TRYING_PACKAGE state
|
|
m_rInfo.rAuth.authstate = AUTH_TRYING_PACKAGE;
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Goto Next Package String
|
|
m_rInfo.rAuth.iAuthToken++;
|
|
}
|
|
|
|
// If we make it here, we have exhausted all packages, so it is time
|
|
// to report an error and drop the connection
|
|
OnError(IXP_E_SICILY_LOGON_FAILED);
|
|
hr = CommandQUIT();
|
|
if (FAILED(hr))
|
|
DropConnection();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::HrSendSicilyString
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPOP3Transport::HrSendSicilyString(LPSTR pszData)
|
|
{
|
|
// Locals
|
|
LPSTR pszLine=NULL;
|
|
HRESULT hr=S_OK;
|
|
|
|
// Check Param
|
|
Assert(pszData);
|
|
|
|
// Allocate a line
|
|
DWORD cchSize = (lstrlen(pszData) + 5);
|
|
pszLine = PszAllocA(cchSize * sizeof(pszLine[0]));
|
|
if (NULL == pszLine)
|
|
{
|
|
hr = TrapError(E_OUTOFMEMORY);
|
|
return hr;
|
|
}
|
|
|
|
// Make Line
|
|
wnsprintf(pszLine, cchSize, "%s\r\n", pszData);
|
|
|
|
// Send the lin
|
|
hr = HrSendLine(pszLine);
|
|
ZeroMemory(pszLine, cchSize * sizeof(pszLine[0]));
|
|
SafeMemFree(pszLine);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::CommandAUTH
|
|
// ------------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::CommandAUTH(LPSTR pszAuthType)
|
|
{
|
|
// check params
|
|
if (NULL == pszAuthType)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Do the command
|
|
HRESULT hr = HrSendCommand((LPSTR)POP3_AUTH_STR, pszAuthType, !m_fConnectAuth);
|
|
if (SUCCEEDED(hr))
|
|
m_command = POP3_AUTH;
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::HrCancelAuthInProg
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPOP3Transport::HrCancelAuthInProg()
|
|
{
|
|
// Locals
|
|
HRESULT hr;
|
|
|
|
// Send *, quit and die if it fails
|
|
hr = HrSendCommand((LPSTR)POP3_AUTH_CANCEL_STR, NULL, FALSE);
|
|
if (FAILED(hr))
|
|
{
|
|
OnError(hr);
|
|
DropConnection();
|
|
}
|
|
else
|
|
{
|
|
// New state
|
|
m_command = POP3_AUTH;
|
|
m_rInfo.rAuth.authstate = AUTH_CANCELED;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::CommandUSER
|
|
// ------------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::CommandUSER(LPSTR pszUserName)
|
|
{
|
|
// check params
|
|
if (NULL == pszUserName)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Do the command
|
|
HRESULT hr = HrSendCommand((LPSTR)POP3_USER_STR, pszUserName);
|
|
if (SUCCEEDED(hr))
|
|
m_command = POP3_USER;
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::CommandPASS
|
|
// ------------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::CommandPASS(LPSTR pszPassword)
|
|
{
|
|
// check params
|
|
if (NULL == pszPassword)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Do the command
|
|
HRESULT hr = HrSendCommand((LPSTR)POP3_PASS_STR, pszPassword);
|
|
if (SUCCEEDED(hr))
|
|
m_command = POP3_PASS;
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::CommandSTAT
|
|
// ------------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::CommandSTAT(void)
|
|
{
|
|
// Send Command
|
|
HRESULT hr = HrSendCommand((LPSTR)POP3_STAT_STR, NULL);
|
|
if (SUCCEEDED(hr))
|
|
m_command = POP3_STAT;
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::DoQuit
|
|
// ------------------------------------------------------------------------------------
|
|
void CPOP3Transport::DoQuit(void)
|
|
{
|
|
CommandQUIT();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::CommandQUIT
|
|
// ------------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::CommandQUIT(void)
|
|
{
|
|
// Send Command
|
|
OnStatus(IXP_DISCONNECTING);
|
|
HRESULT hr = HrSendCommand((LPSTR)POP3_QUIT_STR, NULL);
|
|
if (SUCCEEDED(hr))
|
|
m_command = POP3_QUIT;
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::CommandRSET
|
|
// ------------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::CommandRSET(void)
|
|
{
|
|
// Send Command
|
|
HRESULT hr = HrSendCommand((LPSTR)POP3_RSET_STR, NULL);
|
|
if (SUCCEEDED(hr))
|
|
m_command = POP3_RSET;
|
|
return hr;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::CommandNOOP
|
|
// ------------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::CommandNOOP(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
SYSTEMTIME stNow;
|
|
FILETIME ftNow;
|
|
static FILETIME ftNext = { 0, 0 };
|
|
LARGE_INTEGER liNext;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Checks for need for NOOP
|
|
GetSystemTime (&stNow);
|
|
SystemTimeToFileTime (&stNow, &ftNow);
|
|
if (CompareFileTime (&ftNow, &ftNext) < 0)
|
|
goto exit;
|
|
|
|
// Sets the next NOOP time (+60 seconds)
|
|
liNext.HighPart = ftNow.dwHighDateTime;
|
|
liNext.LowPart = ftNow.dwLowDateTime;
|
|
liNext.QuadPart += 600000000i64;
|
|
ftNext.dwHighDateTime = liNext.HighPart;
|
|
ftNext.dwLowDateTime = liNext.LowPart;
|
|
|
|
// Send Command
|
|
hr = HrSendCommand((LPSTR)POP3_NOOP_STR, NULL);
|
|
if (SUCCEEDED(hr))
|
|
m_command = POP3_NOOP;
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::CommandLIST
|
|
// ------------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::CommandLIST(POP3CMDTYPE cmdtype, DWORD dwPopId)
|
|
{
|
|
// Issue complex command
|
|
return HrComplexCommand(POP3_LIST, cmdtype, dwPopId, 0);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::CommandTOP
|
|
// ------------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::CommandTOP (POP3CMDTYPE cmdtype, DWORD dwPopId, DWORD cPreviewLines)
|
|
{
|
|
// Issue complex command
|
|
return HrComplexCommand(POP3_TOP, cmdtype, dwPopId, cPreviewLines);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::CommandUIDL
|
|
// ------------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::CommandUIDL(POP3CMDTYPE cmdtype, DWORD dwPopId)
|
|
{
|
|
// Issue complex command
|
|
return HrComplexCommand(POP3_UIDL, cmdtype, dwPopId, 0);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::CommandDELE
|
|
// ------------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::CommandDELE(POP3CMDTYPE cmdtype, DWORD dwPopId)
|
|
{
|
|
// Issue complex command
|
|
return HrComplexCommand(POP3_DELE, cmdtype, dwPopId, 0);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::CommandRETR
|
|
// ------------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::CommandRETR(POP3CMDTYPE cmdtype, DWORD dwPopId)
|
|
{
|
|
// Issue complex command
|
|
return HrComplexCommand(POP3_RETR, cmdtype, dwPopId, 0);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::MarkItem
|
|
// ------------------------------------------------------------------------------------
|
|
STDMETHODIMP CPOP3Transport::MarkItem(POP3MARKTYPE marktype, DWORD dwPopId, boolean fMarked)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG i;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// No stat yet...
|
|
if (FALSE == m_rInfo.fStatDone)
|
|
{
|
|
hr = TrapError(IXP_E_POP3_NEED_STAT);
|
|
goto exit;
|
|
}
|
|
|
|
// No Messages...
|
|
if (0 == m_rInfo.cMarked || NULL == m_rInfo.prgMarked)
|
|
{
|
|
hr = TrapError(IXP_E_POP3_NO_MESSAGES);
|
|
goto exit;
|
|
}
|
|
|
|
// Bad PopId
|
|
if (0 == dwPopId || dwPopId > m_rInfo.cMarked)
|
|
{
|
|
hr = TrapError(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
// Message Index
|
|
i = dwPopId - 1;
|
|
|
|
// Handle Mark Type
|
|
switch(marktype)
|
|
{
|
|
// Mark for Top
|
|
case POP3_MARK_FOR_TOP:
|
|
if (fMarked)
|
|
FLAGSET(m_rInfo.prgMarked[i], POP3_MARK_FOR_TOP);
|
|
else
|
|
FLAGCLEAR(m_rInfo.prgMarked[i], POP3_MARK_FOR_TOP);
|
|
break;
|
|
|
|
// Mark for Retrieval
|
|
case POP3_MARK_FOR_RETR:
|
|
if (fMarked)
|
|
FLAGSET(m_rInfo.prgMarked[i], POP3_MARK_FOR_RETR);
|
|
else
|
|
FLAGCLEAR(m_rInfo.prgMarked[i], POP3_MARK_FOR_RETR);
|
|
break;
|
|
|
|
// Mark for Delete
|
|
case POP3_MARK_FOR_DELE:
|
|
if (fMarked)
|
|
FLAGSET(m_rInfo.prgMarked[i], POP3_MARK_FOR_DELE);
|
|
else
|
|
FLAGCLEAR(m_rInfo.prgMarked[i], POP3_MARK_FOR_DELE);
|
|
break;
|
|
|
|
// Mark for UIDL
|
|
case POP3_MARK_FOR_UIDL:
|
|
if (fMarked)
|
|
FLAGSET(m_rInfo.prgMarked[i], POP3_MARK_FOR_UIDL);
|
|
else
|
|
FLAGCLEAR(m_rInfo.prgMarked[i], POP3_MARK_FOR_UIDL);
|
|
break;
|
|
|
|
// Mark for List
|
|
case POP3_MARK_FOR_LIST:
|
|
if (fMarked)
|
|
FLAGSET(m_rInfo.prgMarked[i], POP3_MARK_FOR_LIST);
|
|
else
|
|
FLAGCLEAR(m_rInfo.prgMarked[i], POP3_MARK_FOR_LIST);
|
|
break;
|
|
|
|
// E_INVALIDARG
|
|
default:
|
|
hr = TrapError(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::HrComplexCommand
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPOP3Transport::HrComplexCommand(POP3COMMAND command, POP3CMDTYPE cmdtype, DWORD dwPopId, ULONG cPreviewLines)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cMarked;
|
|
BOOL fDone;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// go Busy
|
|
CHECKHR(hr = HrEnterBusy());
|
|
|
|
// Save top preview lines
|
|
m_rInfo.cPreviewLines = cPreviewLines;
|
|
|
|
// Save command type
|
|
m_rInfo.cmdtype = cmdtype;
|
|
|
|
// Locals
|
|
switch(cmdtype)
|
|
{
|
|
// Single command
|
|
case POP3CMD_GET_POPID:
|
|
|
|
// Bad PopId
|
|
if (0 == dwPopId)
|
|
{
|
|
hr = TrapError(IXP_E_POP3_POPID_OUT_OF_RANGE);
|
|
goto exit;
|
|
}
|
|
|
|
// Have we done a stat command
|
|
if (m_rInfo.fStatDone && dwPopId > m_rInfo.cMarked)
|
|
{
|
|
hr = TrapError(IXP_E_POP3_POPID_OUT_OF_RANGE);
|
|
goto exit;
|
|
}
|
|
|
|
// Save as Current
|
|
m_rInfo.dwPopIdCurrent = dwPopId;
|
|
|
|
// Do the command
|
|
CHECKHR(hr = HrCommandGetPopId(command, dwPopId));
|
|
|
|
// Done
|
|
break;
|
|
|
|
// Get marked items
|
|
case POP3CMD_GET_MARKED:
|
|
|
|
// No stat yet...
|
|
if (FALSE == m_rInfo.fStatDone)
|
|
{
|
|
hr = TrapError(IXP_E_POP3_NEED_STAT);
|
|
goto exit;
|
|
}
|
|
|
|
// No Messages...
|
|
if (0 == m_rInfo.cMarked || NULL == m_rInfo.prgMarked)
|
|
{
|
|
hr = TrapError(IXP_E_POP3_NO_MESSAGES);
|
|
goto exit;
|
|
}
|
|
|
|
// Are there any messages mared for this command...
|
|
cMarked = CountMarked(command);
|
|
if (0 == cMarked)
|
|
{
|
|
hr = TrapError(IXP_E_POP3_NO_MARKED_MESSAGES);
|
|
goto exit;
|
|
}
|
|
|
|
// Init Marked State
|
|
m_rInfo.dwPopIdCurrent = 0;
|
|
|
|
// Do next marked...
|
|
CHECKHR(hr = HrCommandGetNext(command, &fDone));
|
|
IxpAssert(fDone == FALSE);
|
|
|
|
// Done
|
|
break;
|
|
|
|
// Multiple commands or a list operation
|
|
case POP3CMD_GET_ALL:
|
|
|
|
// Do the command
|
|
CHECKHR(hr = HrCommandGetAll(command));
|
|
|
|
// done
|
|
break;
|
|
|
|
// E_INVALIDARG
|
|
default:
|
|
hr = TrapError(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
// Failure
|
|
if (FAILED(hr))
|
|
LeaveBusy();
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::HrCommandGetPopId
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPOP3Transport::HrCommandGetPopId(POP3COMMAND command, DWORD dwPopId)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szPopId[30];
|
|
|
|
// Handle command type
|
|
IxpAssert(dwPopId == m_rInfo.dwPopIdCurrent);
|
|
switch(command)
|
|
{
|
|
case POP3_DELE:
|
|
wnsprintf(szPopId, ARRAYSIZE(szPopId), "%d", dwPopId);
|
|
CHECKHR(hr = HrSendCommand((LPSTR)POP3_DELE_STR, szPopId, FALSE));
|
|
m_command = POP3_DELE;
|
|
break;
|
|
|
|
case POP3_RETR:
|
|
ZeroMemory(&m_rInfo.rFetch, sizeof(FETCHINFO));
|
|
wnsprintf(szPopId, ARRAYSIZE(szPopId), "%d", dwPopId);
|
|
CHECKHR(hr = HrSendCommand((LPSTR)POP3_RETR_STR, szPopId, FALSE));
|
|
m_command = POP3_RETR;
|
|
break;
|
|
|
|
case POP3_TOP:
|
|
ZeroMemory(&m_rInfo.rFetch, sizeof(FETCHINFO));
|
|
wnsprintf(szPopId, ARRAYSIZE(szPopId), "%d %d", dwPopId, m_rInfo.cPreviewLines);
|
|
CHECKHR(hr = HrSendCommand((LPSTR)POP3_TOP_STR, szPopId, FALSE));
|
|
m_command = POP3_TOP;
|
|
break;
|
|
|
|
case POP3_LIST:
|
|
m_rInfo.cList = 0;
|
|
wnsprintf(szPopId, ARRAYSIZE(szPopId), "%d", dwPopId);
|
|
CHECKHR(hr = HrSendCommand((LPSTR)POP3_LIST_STR, szPopId, FALSE));
|
|
m_command = POP3_LIST;
|
|
break;
|
|
|
|
case POP3_UIDL:
|
|
m_rInfo.cList = 0;
|
|
wnsprintf(szPopId, ARRAYSIZE(szPopId), "%d", dwPopId);
|
|
CHECKHR(hr = HrSendCommand((LPSTR)POP3_UIDL_STR, szPopId, FALSE));
|
|
m_command = POP3_UIDL;
|
|
break;
|
|
|
|
default:
|
|
hr = TrapError(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::DwGetCommandMarkedFlag
|
|
// ------------------------------------------------------------------------------------
|
|
DWORD CPOP3Transport::DwGetCommandMarkedFlag(POP3COMMAND command)
|
|
{
|
|
DWORD dw;
|
|
|
|
switch(command)
|
|
{
|
|
case POP3_LIST:
|
|
dw = POP3_MARK_FOR_LIST;
|
|
break;
|
|
|
|
case POP3_DELE:
|
|
dw = POP3_MARK_FOR_DELE;
|
|
break;
|
|
|
|
case POP3_RETR:
|
|
dw = POP3_MARK_FOR_RETR;
|
|
break;
|
|
|
|
case POP3_TOP:
|
|
dw = POP3_MARK_FOR_TOP;
|
|
break;
|
|
|
|
case POP3_UIDL:
|
|
dw = POP3_MARK_FOR_UIDL;
|
|
break;
|
|
|
|
default:
|
|
IxpAssert(FALSE);
|
|
dw = 0;
|
|
break;
|
|
}
|
|
|
|
return dw;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::CountMarked
|
|
// ------------------------------------------------------------------------------------
|
|
ULONG CPOP3Transport::CountMarked(POP3COMMAND command)
|
|
{
|
|
// Locals
|
|
DWORD dw = 0;
|
|
ULONG c=0,
|
|
i;
|
|
|
|
// Check some stuff
|
|
IxpAssert(m_rInfo.cMarked && m_rInfo.prgMarked);
|
|
|
|
// Handle Command type
|
|
dw = DwGetCommandMarkedFlag(command);
|
|
if (0 == dw)
|
|
return 0;
|
|
|
|
// Count
|
|
for (i=0; i<m_rInfo.cMarked; i++)
|
|
if (dw & m_rInfo.prgMarked[i])
|
|
c++;
|
|
|
|
// Done
|
|
return c;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::HrCommandGetNext
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPOP3Transport::HrCommandGetNext(POP3COMMAND command, BOOL *pfDone)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szPopId[30];
|
|
DWORD dw;
|
|
ULONG i;
|
|
|
|
// check params
|
|
IxpAssert(pfDone && m_rInfo.dwPopIdCurrent <= m_rInfo.cMarked);
|
|
|
|
// Init - Assume were done
|
|
*pfDone = TRUE;
|
|
|
|
// Doing all
|
|
if (POP3CMD_GET_ALL == m_rInfo.cmdtype)
|
|
{
|
|
// Done
|
|
IxpAssert(m_rInfo.fStatDone == TRUE);
|
|
if (m_rInfo.dwPopIdCurrent == m_rInfo.cMarked)
|
|
goto exit;
|
|
|
|
// Next Message..
|
|
m_rInfo.dwPopIdCurrent++;
|
|
*pfDone = FALSE;
|
|
CHECKHR(hr = HrCommandGetPopId(command, m_rInfo.dwPopIdCurrent));
|
|
}
|
|
|
|
// Doing Marked
|
|
else
|
|
{
|
|
// Check Parms
|
|
IxpAssert(POP3CMD_GET_MARKED == m_rInfo.cmdtype);
|
|
|
|
// Get marked flag
|
|
dw = DwGetCommandMarkedFlag(command);
|
|
if (0 == dw)
|
|
{
|
|
hr = TrapError(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
// Step Over Last Marked Item
|
|
m_rInfo.dwPopIdCurrent++;
|
|
|
|
// Start comparing at iCurrent
|
|
for (i=m_rInfo.dwPopIdCurrent-1; i<m_rInfo.cMarked; i++)
|
|
{
|
|
// Is this item marked...
|
|
if (dw & m_rInfo.prgMarked[i])
|
|
{
|
|
// Send Command
|
|
m_rInfo.dwPopIdCurrent = i + 1;
|
|
*pfDone = FALSE;
|
|
CHECKHR(hr = HrCommandGetPopId(command, m_rInfo.dwPopIdCurrent));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::HrCommandGetAll
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPOP3Transport::HrCommandGetAll(POP3COMMAND command)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szPopId[30];
|
|
BOOL fDone;
|
|
|
|
// Init current
|
|
m_rInfo.dwPopIdCurrent = 0;
|
|
|
|
// POP3_LIST
|
|
if (POP3_LIST == command)
|
|
{
|
|
m_rInfo.cList = 0;
|
|
CHECKHR(hr = HrSendCommand((LPSTR)POP3_LIST_ALL_STR, NULL, FALSE));
|
|
m_command = POP3_LIST;
|
|
}
|
|
|
|
// POP3_UIDL
|
|
else if (POP3_UIDL == command)
|
|
{
|
|
m_rInfo.cList = 0;
|
|
CHECKHR(hr = HrSendCommand((LPSTR)POP3_UIDL_ALL_STR, NULL, FALSE));
|
|
m_command = POP3_UIDL;
|
|
}
|
|
|
|
// Otherwise, we better have done the stat command
|
|
else
|
|
{
|
|
// No stat yet...
|
|
if (FALSE == m_rInfo.fStatDone)
|
|
{
|
|
hr = TrapError(IXP_E_POP3_NEED_STAT);
|
|
goto exit;
|
|
}
|
|
|
|
// No Messages...
|
|
if (0 == m_rInfo.cMarked || NULL == m_rInfo.prgMarked)
|
|
{
|
|
hr = TrapError(IXP_E_POP3_NO_MESSAGES);
|
|
goto exit;
|
|
}
|
|
|
|
// Next Command
|
|
CHECKHR(hr = HrCommandGetNext(command, &fDone));
|
|
IxpAssert(fDone == FALSE);
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::ResponseSTAT
|
|
// ------------------------------------------------------------------------------------
|
|
void CPOP3Transport::ResponseSTAT(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD cMessages=0,
|
|
cbMessages=0;
|
|
LPSTR pszPart1=NULL,
|
|
pszPart2=NULL;
|
|
POP3RESPONSE rResponse;
|
|
|
|
// Read Server Response...
|
|
hr = HrGetResponse();
|
|
if (IXP_E_INCOMPLETE == hr)
|
|
return;
|
|
|
|
// Init Response
|
|
ZeroMemory(&rResponse, sizeof(POP3RESPONSE));
|
|
|
|
// Parse the response
|
|
CHECKHR(hr = HrSplitPop3Response(m_pszResponse, &pszPart1, &pszPart2));
|
|
|
|
// Convert
|
|
IxpAssert(pszPart1 && pszPart2);
|
|
cMessages = StrToInt(pszPart1);
|
|
cbMessages = StrToInt(pszPart2);
|
|
|
|
// Are there messages
|
|
if (FALSE == m_rInfo.fStatDone && cMessages > 0)
|
|
{
|
|
// Set Number of messages
|
|
IxpAssert(m_rInfo.prgMarked == NULL);
|
|
m_rInfo.cMarked = cMessages;
|
|
|
|
// Allocate message array
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&m_rInfo.prgMarked, sizeof(DWORD) * m_rInfo.cMarked));
|
|
|
|
// Zero
|
|
ZeroMemory(m_rInfo.prgMarked, sizeof(DWORD) * m_rInfo.cMarked);
|
|
}
|
|
|
|
// Success
|
|
m_rInfo.fStatDone = TRUE;
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pszPart1);
|
|
SafeMemFree(pszPart2);
|
|
|
|
// Build Response
|
|
rResponse.fValidInfo = TRUE;
|
|
rResponse.rStatInfo.cMessages = cMessages;
|
|
rResponse.rStatInfo.cbMessages = cbMessages;
|
|
DispatchResponse(hr, TRUE, &rResponse);
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::HrSplitPop3Response
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPOP3Transport::HrSplitPop3Response(LPSTR pszLine, LPSTR *ppszPart1, LPSTR *ppszPart2)
|
|
{
|
|
// Locals
|
|
LPSTR psz,
|
|
pszStart;
|
|
CHAR ch;
|
|
HRESULT hr=IXP_E_POP3_PARSE_FAILURE;
|
|
|
|
// No Response...
|
|
IxpAssert(pszLine && pszLine[0] != '-' && ppszPart1 && ppszPart2);
|
|
if (NULL == pszLine)
|
|
goto exit;
|
|
|
|
// Parse: '+OK' 432 1234
|
|
psz = PszSkipWhiteA(pszLine);
|
|
if ('\0' == *psz)
|
|
goto exit;
|
|
|
|
// Parse response token
|
|
pszStart = psz;
|
|
if ('+' == *pszLine)
|
|
{
|
|
// Parse: '+OK' 432 1234
|
|
psz = PszScanToWhiteA(psz);
|
|
if ('\0' == *psz)
|
|
goto exit;
|
|
|
|
#ifdef DEBUG
|
|
IxpAssert(' ' == *psz);
|
|
*psz = '\0';
|
|
IxpAssert(lstrcmpi(pszStart, "+OK") == 0);
|
|
*psz = ' ';
|
|
#endif
|
|
|
|
// Parse: +OK '432' 1234
|
|
psz = PszSkipWhiteA(psz);
|
|
if ('\0' == *psz)
|
|
goto exit;
|
|
}
|
|
|
|
// Parse: +OK '432' 1234
|
|
pszStart = psz;
|
|
psz = PszScanToWhiteA(psz);
|
|
if ('\0' == *psz)
|
|
goto exit;
|
|
|
|
// Get Message Count
|
|
*psz = '\0';
|
|
*ppszPart1 = PszDupA(pszStart);
|
|
*psz = ' ';
|
|
|
|
// Parse: +OK 432 '1234'
|
|
psz = PszSkipWhiteA(psz);
|
|
if ('\0' == *psz)
|
|
{
|
|
// Raid 28435 - Outlook needs INETCOMM to accept empty UIDL responses
|
|
*ppszPart2 = PszDupA(c_szEmpty);
|
|
hr = S_OK;
|
|
goto exit;
|
|
}
|
|
|
|
// Parse: +OK 432 1234
|
|
pszStart = psz;
|
|
psz = PszScanToWhiteA(psz);
|
|
|
|
// Get Message Count
|
|
ch = *psz;
|
|
*psz = '\0';
|
|
*ppszPart2 = PszDupA(pszStart);
|
|
*psz = ch;
|
|
|
|
// Success
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::ResponseGenericList
|
|
// ------------------------------------------------------------------------------------
|
|
void CPOP3Transport::ResponseGenericList(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr;
|
|
INT cbLine;
|
|
BOOL fDone,
|
|
fComplete;
|
|
LPSTR pszPart1=NULL,
|
|
pszPart2=NULL;
|
|
POP3RESPONSE rResponse;
|
|
|
|
// Same response as single LIST x command, but then get next
|
|
if (POP3CMD_GET_MARKED == m_rInfo.cmdtype || POP3CMD_GET_POPID == m_rInfo.cmdtype)
|
|
{
|
|
// Read Server Response...
|
|
hr = HrGetResponse();
|
|
if (IXP_E_INCOMPLETE == hr)
|
|
goto exit;
|
|
|
|
// Otherwise, if failure...
|
|
else if (FAILED(hr))
|
|
{
|
|
DispatchResponse(hr, TRUE);
|
|
goto exit;
|
|
}
|
|
|
|
// Get the two parts from the line
|
|
hr = HrSplitPop3Response(m_pszResponse, &pszPart1, &pszPart2);
|
|
if (FAILED(hr))
|
|
{
|
|
DispatchResponse(hr, TRUE);
|
|
goto exit;
|
|
}
|
|
|
|
// Init Response
|
|
ZeroMemory(&rResponse, sizeof(POP3RESPONSE));
|
|
|
|
// POP3_LIST
|
|
if (POP3_LIST == m_command)
|
|
{
|
|
rResponse.fValidInfo = TRUE;
|
|
rResponse.rListInfo.dwPopId = StrToInt(pszPart1);
|
|
rResponse.rListInfo.cbSize = StrToInt(pszPart2);
|
|
IxpAssert(rResponse.rListInfo.dwPopId == m_rInfo.dwPopIdCurrent);
|
|
}
|
|
|
|
// POP3_UIDL
|
|
else
|
|
{
|
|
rResponse.fValidInfo = TRUE;
|
|
rResponse.rUidlInfo.dwPopId = StrToInt(pszPart1);
|
|
rResponse.rUidlInfo.pszUidl = pszPart2;
|
|
IxpAssert(rResponse.rUidlInfo.dwPopId == m_rInfo.dwPopIdCurrent);
|
|
}
|
|
|
|
// Do Next
|
|
if (POP3CMD_GET_MARKED == m_rInfo.cmdtype)
|
|
{
|
|
// Give the response
|
|
DispatchResponse(S_OK, FALSE, &rResponse);
|
|
|
|
// Do the next marked list item
|
|
hr = HrCommandGetNext(m_command, &fDone);
|
|
if (FAILED(hr))
|
|
{
|
|
DispatchResponse(hr, TRUE);
|
|
goto exit;
|
|
}
|
|
|
|
// Done Response
|
|
if (fDone)
|
|
DispatchResponse(S_OK, TRUE);
|
|
}
|
|
|
|
// Dispatch Done or single item response
|
|
else
|
|
DispatchResponse(S_OK, TRUE, &rResponse);
|
|
}
|
|
|
|
// Full LIST response
|
|
else if (POP3CMD_GET_ALL == m_rInfo.cmdtype)
|
|
{
|
|
// First call...
|
|
if (m_rInfo.dwPopIdCurrent == 0)
|
|
{
|
|
// Read Server Response...
|
|
hr = HrGetResponse();
|
|
if (IXP_E_INCOMPLETE == hr)
|
|
goto exit;
|
|
|
|
// Otherwise, if failure...
|
|
else if (FAILED(hr))
|
|
{
|
|
DispatchResponse(hr, TRUE);
|
|
goto exit;
|
|
}
|
|
|
|
// Current
|
|
m_rInfo.dwPopIdCurrent = 1;
|
|
}
|
|
|
|
// Clear Response
|
|
SafeMemFree(m_pszResponse);
|
|
m_uiResponse = 0;
|
|
m_hrResponse = S_OK;
|
|
|
|
// Read a blob of lines
|
|
while(1)
|
|
{
|
|
// Read Line
|
|
hr = HrReadLine(&m_pszResponse, &cbLine, &fComplete);
|
|
if (FAILED(hr))
|
|
{
|
|
DispatchResponse(hr, TRUE);
|
|
goto exit;
|
|
}
|
|
|
|
// If not complete
|
|
if (!fComplete)
|
|
goto exit;
|
|
|
|
// Add Detail
|
|
if (m_pCallback && m_fCommandLogging)
|
|
m_pCallback->OnCommand(CMD_RESP, m_pszResponse, S_OK, POP3THISIXP);
|
|
|
|
// If its a dot, were done
|
|
if (*m_pszResponse == '.')
|
|
{
|
|
// If we haven't done a stat yet, we can use these totals...
|
|
IxpAssert(m_rInfo.fStatDone ? m_rInfo.cList == m_rInfo.cMarked : TRUE);
|
|
if (FALSE == m_rInfo.fStatDone && m_rInfo.cList > 0)
|
|
{
|
|
// Have I build my internal array of messages yet...
|
|
IxpAssert(m_rInfo.prgMarked == NULL);
|
|
m_rInfo.cMarked = m_rInfo.cList;
|
|
|
|
// Allocate message array
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&m_rInfo.prgMarked, sizeof(DWORD) * m_rInfo.cMarked));
|
|
|
|
// Zero
|
|
ZeroMemory(m_rInfo.prgMarked, sizeof(DWORD) * m_rInfo.cMarked);
|
|
}
|
|
|
|
// Were Done
|
|
DispatchResponse(S_OK, TRUE);
|
|
|
|
// Stat Done
|
|
m_rInfo.fStatDone = TRUE;
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
|
|
// Get the two parts from the line
|
|
hr = HrSplitPop3Response(m_pszResponse, &pszPart1, &pszPart2);
|
|
if (FAILED(hr))
|
|
{
|
|
DispatchResponse(hr, TRUE);
|
|
goto exit;
|
|
}
|
|
|
|
// Init Response
|
|
ZeroMemory(&rResponse, sizeof(POP3RESPONSE));
|
|
|
|
// POP3_LIST
|
|
if (POP3_LIST == m_command)
|
|
{
|
|
rResponse.fValidInfo = TRUE;
|
|
rResponse.rListInfo.dwPopId = StrToInt(pszPart1);
|
|
rResponse.rListInfo.cbSize = StrToInt(pszPart2);
|
|
}
|
|
|
|
// POP3_UIDL
|
|
else
|
|
{
|
|
rResponse.fValidInfo = TRUE;
|
|
rResponse.rUidlInfo.dwPopId = StrToInt(pszPart1);
|
|
rResponse.rUidlInfo.pszUidl = pszPart2;
|
|
IxpAssert(rResponse.rUidlInfo.dwPopId == m_rInfo.dwPopIdCurrent);
|
|
}
|
|
|
|
// Count the number of messages
|
|
m_rInfo.cList++;
|
|
|
|
// Dispatch the response
|
|
DispatchResponse(S_OK, FALSE, &rResponse);
|
|
m_rInfo.dwPopIdCurrent++;
|
|
|
|
// Cleanup
|
|
SafeMemFree(pszPart1);
|
|
SafeMemFree(pszPart2);
|
|
|
|
// Clear Response
|
|
SafeMemFree(m_pszResponse);
|
|
m_uiResponse = 0;
|
|
m_hrResponse = S_OK;
|
|
}
|
|
}
|
|
|
|
// Otherwise failure...
|
|
else
|
|
{
|
|
IxpAssert(FALSE);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pszPart1);
|
|
SafeMemFree(pszPart2);
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::FEndRetrRecvHeader
|
|
// ------------------------------------------------------------------------------------
|
|
BOOL CPOP3Transport::FEndRetrRecvHeader(LPSTR pszLines, ULONG cbRead)
|
|
{
|
|
// If we see CRLFCRLF
|
|
if (StrStr(pszLines, "\r\n\r\n"))
|
|
return TRUE;
|
|
|
|
// Otherwise, did last block end with a CRLF and this block begins with a crlf
|
|
else if (cbRead >= 2 &&
|
|
m_rInfo.rFetch.fLastLineCRLF &&
|
|
pszLines[0] == '\r' &&
|
|
pszLines[1] == '\n')
|
|
return TRUE;
|
|
|
|
// Header is not done
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::ResponseGenericRetrieve
|
|
// ------------------------------------------------------------------------------------
|
|
void CPOP3Transport::ResponseGenericRetrieve(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPSTR pszLines=NULL;
|
|
INT cbRead,
|
|
cLines;
|
|
ULONG cbSubtract;
|
|
BOOL fDone,
|
|
fMessageDone;
|
|
POP3RESPONSE rResponse;
|
|
|
|
// First call...
|
|
if (FALSE == m_rInfo.rFetch.fGotResponse)
|
|
{
|
|
// Read Server Response...
|
|
hr = HrGetResponse();
|
|
if (IXP_E_INCOMPLETE == hr)
|
|
goto exit;
|
|
|
|
// Otherwise, if failure...
|
|
else if (FAILED(hr))
|
|
{
|
|
FillRetrieveResponse(&rResponse, NULL, 0, &fMessageDone);
|
|
DispatchResponse(hr, TRUE, &rResponse);
|
|
goto exit;
|
|
}
|
|
|
|
// Current
|
|
m_rInfo.rFetch.fGotResponse = TRUE;
|
|
}
|
|
|
|
// While there are lines to read...
|
|
hr = m_pSocket->ReadLines(&pszLines, &cbRead, &cLines);
|
|
|
|
// Incomplete data available...
|
|
if (IXP_E_INCOMPLETE == hr)
|
|
goto exit;
|
|
|
|
// Or if we failed...
|
|
else if (FAILED(hr))
|
|
{
|
|
FillRetrieveResponse(&rResponse, NULL, 0, &fMessageDone);
|
|
DispatchResponse(hr, TRUE, &rResponse);
|
|
goto exit;
|
|
}
|
|
|
|
// Are we receiving the header...
|
|
if (FALSE == m_rInfo.rFetch.fHeader)
|
|
{
|
|
// Test for end of header found
|
|
if (FEndRetrRecvHeader(pszLines, cbRead))
|
|
m_rInfo.rFetch.fHeader = TRUE;
|
|
|
|
// $$BUG$$ Our good buddies on Exchange produced the following message:
|
|
//
|
|
// To: XXXXXXXXXXXXXXXXXXX
|
|
// From: XXXXXXXXXXXXXXXXX
|
|
// Subject: XXXXXXXXXXXXXX
|
|
// .
|
|
//
|
|
// As you can see there is not CRLFCRLF following the last header line which is very
|
|
// illegal. This message caused us to hange because we never saw the end of the header.
|
|
// So this is why I also test for the end of the body...
|
|
else if (FEndRetrRecvBody(pszLines, cbRead, &cbSubtract))
|
|
{
|
|
cbRead -= cbSubtract;
|
|
m_rInfo.rFetch.fHeader = TRUE;
|
|
m_rInfo.rFetch.fBody = TRUE;
|
|
}
|
|
|
|
// Otherwise, did this block end with a crlf
|
|
else if (cbRead >= 2 && pszLines[cbRead - 1] == '\n' && pszLines[cbRead - 2] == '\r')
|
|
m_rInfo.rFetch.fLastLineCRLF = TRUE;
|
|
else
|
|
m_rInfo.rFetch.fLastLineCRLF = FALSE;
|
|
}
|
|
|
|
// Also check to see if body was received in same set of lines
|
|
if (TRUE == m_rInfo.rFetch.fHeader)
|
|
{
|
|
// Test for end of header found
|
|
if (FEndRetrRecvBody(pszLines, cbRead, &cbSubtract))
|
|
{
|
|
cbRead -= cbSubtract;
|
|
m_rInfo.rFetch.fBody = TRUE;
|
|
}
|
|
|
|
// Otherwise, check for line ending with crlf
|
|
else if (cbRead >= 2 && pszLines[cbRead - 1] == '\n' && pszLines[cbRead - 2] == '\r')
|
|
m_rInfo.rFetch.fLastLineCRLF = TRUE;
|
|
else
|
|
m_rInfo.rFetch.fLastLineCRLF = FALSE;
|
|
}
|
|
|
|
// Count bytes downloaded on this fetch
|
|
m_rInfo.rFetch.cbSoFar += cbRead;
|
|
|
|
// UnStuff
|
|
UnStuffDotsFromLines(pszLines, &cbRead);
|
|
|
|
// Fill the response
|
|
FillRetrieveResponse(&rResponse, pszLines, cbRead, &fMessageDone);
|
|
|
|
// Dispatch This Resposne...
|
|
if (POP3CMD_GET_POPID == m_rInfo.cmdtype)
|
|
DispatchResponse(S_OK, fMessageDone, &rResponse);
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
// Check command type
|
|
IxpAssert(POP3CMD_GET_MARKED == m_rInfo.cmdtype || POP3CMD_GET_ALL == m_rInfo.cmdtype);
|
|
|
|
// Dispatch current response
|
|
DispatchResponse(S_OK, FALSE, &rResponse);
|
|
|
|
// If done with current message...
|
|
if (fMessageDone)
|
|
{
|
|
// Get Next
|
|
hr = HrCommandGetNext(m_command, &fDone);
|
|
if (FAILED(hr))
|
|
{
|
|
DispatchResponse(hr, TRUE);
|
|
goto exit;
|
|
}
|
|
|
|
// If Done
|
|
if (fDone)
|
|
DispatchResponse(S_OK, TRUE);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pszLines);
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::FillRetrieveResponse
|
|
// ------------------------------------------------------------------------------------
|
|
void CPOP3Transport::FillRetrieveResponse(LPPOP3RESPONSE pResponse, LPSTR pszLines, ULONG cbRead,
|
|
BOOL *pfMessageDone)
|
|
{
|
|
// Clear Response
|
|
ZeroMemory(pResponse, sizeof(POP3RESPONSE));
|
|
|
|
// POP3_TOP
|
|
if (POP3_TOP == m_command)
|
|
{
|
|
// Build Response
|
|
pResponse->fValidInfo = TRUE;
|
|
pResponse->rTopInfo.dwPopId = m_rInfo.dwPopIdCurrent;
|
|
pResponse->rTopInfo.cPreviewLines = m_rInfo.cPreviewLines;
|
|
pResponse->rTopInfo.cbSoFar = m_rInfo.rFetch.cbSoFar;
|
|
pResponse->rTopInfo.pszLines = pszLines;
|
|
pResponse->rTopInfo.cbLines = cbRead;
|
|
pResponse->rTopInfo.fHeader = m_rInfo.rFetch.fHeader;
|
|
pResponse->rTopInfo.fBody = m_rInfo.rFetch.fBody;
|
|
*pfMessageDone = (m_rInfo.rFetch.fHeader && m_rInfo.rFetch.fBody);
|
|
}
|
|
|
|
// POP3_RETR
|
|
else
|
|
{
|
|
IxpAssert(POP3_RETR == m_command);
|
|
pResponse->fValidInfo = TRUE;
|
|
pResponse->rRetrInfo.fHeader = m_rInfo.rFetch.fHeader;
|
|
pResponse->rRetrInfo.fBody = m_rInfo.rFetch.fBody;
|
|
pResponse->rRetrInfo.dwPopId = m_rInfo.dwPopIdCurrent;
|
|
pResponse->rRetrInfo.cbSoFar = m_rInfo.rFetch.cbSoFar;
|
|
pResponse->rRetrInfo.pszLines = pszLines;
|
|
pResponse->rRetrInfo.cbLines = cbRead;
|
|
*pfMessageDone = (m_rInfo.rFetch.fHeader && m_rInfo.rFetch.fBody);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPOP3Transport::ResponseDELE
|
|
// ------------------------------------------------------------------------------------
|
|
void CPOP3Transport::ResponseDELE(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
BOOL fDone;
|
|
POP3RESPONSE rResponse;
|
|
|
|
// Read Server Response...
|
|
hr = HrGetResponse();
|
|
if (IXP_E_INCOMPLETE == hr)
|
|
goto exit;
|
|
|
|
// Otherwise, if failure...
|
|
else if (FAILED(hr))
|
|
{
|
|
DispatchResponse(hr, TRUE);
|
|
goto exit;
|
|
}
|
|
|
|
// Clear Response
|
|
ZeroMemory(&rResponse, sizeof(POP3RESPONSE));
|
|
rResponse.fValidInfo = TRUE;
|
|
rResponse.dwPopId = m_rInfo.dwPopIdCurrent;
|
|
|
|
// Dispatch This Resposne...
|
|
if (POP3CMD_GET_POPID == m_rInfo.cmdtype)
|
|
DispatchResponse(S_OK, TRUE, &rResponse);
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
// Check command type
|
|
IxpAssert(POP3CMD_GET_MARKED == m_rInfo.cmdtype || POP3CMD_GET_ALL == m_rInfo.cmdtype);
|
|
|
|
// Dispatch current response
|
|
DispatchResponse(S_OK, FALSE, &rResponse);
|
|
|
|
// Get Next
|
|
hr = HrCommandGetNext(m_command, &fDone);
|
|
if (FAILED(hr))
|
|
{
|
|
DispatchResponse(hr, TRUE);
|
|
goto exit;
|
|
}
|
|
|
|
// If Done
|
|
if (fDone)
|
|
DispatchResponse(S_OK, TRUE);
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return;
|
|
}
|
|
|