2025-04-27 07:49:33 -04:00

1118 lines
31 KiB
C++

// --------------------------------------------------------------------------------
// Ixpurl.cpp
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
// Steven J. Bailey
// --------------------------------------------------------------------------------
#include "pch.hxx"
#include "dllmain.h"
#include "ixpurl.h"
#define _SHLWAPI_
#define NO_SHLWAPI_PATH
#include "shlwapi.h"
#undef NO_SHLWAPI_PATH
#include "shlwapip.h"
#include "strparse.h"
#include "bytestm.h"
#include "stmlock.h"
#include "wchar.h"
// --------------------------------------------------------------------------------
// IInternetMessageUrl_CreateInstance
// --------------------------------------------------------------------------------
HRESULT IInternetMessageUrl_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppUnknown)
{
// Invalid Arg
Assert(ppUnknown);
// Initialize
*ppUnknown = NULL;
// Create me
CInternetMessageUrl *pNew = new CInternetMessageUrl(pUnkOuter);
if (NULL == pNew)
return TrapError(E_OUTOFMEMORY);
// Return the Innter
*ppUnknown = pNew->GetInner();
// Done
return S_OK;
}
// --------------------------------------------------------------------------------
// CInternetMessageUrl::CInternetMessageUrl
// --------------------------------------------------------------------------------
CInternetMessageUrl::CInternetMessageUrl(IUnknown *pUnkOuter) : CPrivateUnknown(&m_cs, pUnkOuter)
{
DllAddRef();
m_pProtSink = NULL;
m_pBindInfo = NULL;
m_pszUrl = NULL;
m_hrResult = S_OK;
m_pszResult = NULL;
m_dwResult = 0;
ZeroMemory(&m_rSource, sizeof(PROTOCOLSOURCE));
ZeroMemory(&m_rDownload, sizeof(DOWNLOADSOURCE));
InitializeCriticalSection(&m_cs);
}
// --------------------------------------------------------------------------------
// CInternetMessageUrl::~CInternetMessageUrl
// --------------------------------------------------------------------------------
CInternetMessageUrl::~CInternetMessageUrl(void)
{
// These should have died in ::Terminate
Assert(NULL == m_pProtSink && NULL == m_pBindInfo && NULL == m_rDownload.pTransport);
// Release these objects anyways
SafeRelease(m_pProtSink);
SafeRelease(m_pBindInfo);
SafeRelease(m_rDownload.pTransport);
// Release LockBytes
SafeRelease(m_rSource.pLockBytes);
// Free Message Url
SafeMemFree(m_pszUrl);
SafeMemFree(m_pszResult);
SafeMemFree(m_rDownload.pszFolder);
SafeMemFree(m_rDownload.pszArticle);
// Kill CS
DeleteCriticalSection(&m_cs);
// Release the Dll
DllRelease();
}
// --------------------------------------------------------------------------------
// CInternetMessageUrl::PrivateQueryInterface
// --------------------------------------------------------------------------------
HRESULT CInternetMessageUrl::PrivateQueryInterface(REFIID riid, LPVOID *ppv)
{
// Locals
HRESULT hr=S_OK;
// check params
if (ppv == NULL)
return TrapError(E_INVALIDARG);
// Thread Safety
EnterCriticalSection(&m_cs);
// Find IID
if (IID_IOInetProtocol == riid)
*ppv = (IOInetProtocol *)this;
else if (IID_IOInetProtocolRoot == riid)
*ppv = (IOInetProtocolRoot *)this;
else if (IID_IServiceProvider == riid)
*ppv = (IServiceProvider *)this;
else if (IID_INNTPCallback == riid)
*ppv = (INNTPCallback *)this;
else if (IID_IPOP3Callback == riid)
*ppv = (IPOP3Callback *)this;
else if (IID_IIMAPCallback == riid)
*ppv = (IIMAPCallback *)this;
else
{
*ppv = NULL;
hr = TrapError(E_NOINTERFACE);
goto exit;
}
// AddRef It
((IUnknown *)*ppv)->AddRef();
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CInternetMessageUrl::Start (IOInetProtocol)
// --------------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::Start(LPCWSTR pwszUrl, IOInetProtocolSink *pProtSink,
IOInetBindInfo *pBindInfo, DWORD grfSTI, DWORD dwReserved)
{
// Locals
HRESULT hr=S_OK;
IStream *pStream=NULL;
LPSTR pszUrl=NULL;
// Invalid Args
if (NULL == pwszUrl || NULL == pProtSink || NULL == pBindInfo)
return TrapError(E_INVALIDARG);
// Thread Safety
EnterCriticalSection(&m_cs);
// We Better not have been Initialized Yet...
Assert(m_pProtSink == NULL && m_pBindInfo == NULL);
// Convert URL to MultiByte
CHECKALLOC(pszUrl = PszToANSI(CP_ACP, pwszUrl));
// Convert URL to MultiByte
CHECKALLOC(m_pszUrl = PszDupW(pwszUrl));
// unescape the URL string
CHECKHR(hr = UrlUnescapeInPlace(pszUrl, 0));
// Transport From Url
CHECKHR(hr = _HrTransportFromUrl(pszUrl));
// Assume the Sink (QueryService below depends on m_pProtSink)
m_pProtSink = pProtSink;
m_pProtSink->AddRef();
// Assume the BindInfo
m_pBindInfo = pBindInfo;
m_pBindInfo->AddRef();
// Seek If I can get a lockbytes from the QueryService
if (FAILED(QueryService(IID_IBindMessageStream, IID_IBindMessageStream, (LPVOID *)&pStream)))
{
// Create a Virtual Stream
CHECKHR(hr = MimeOleCreateVirtualStream(&pStream));
}
// Create a ILockBytes
CHECKALLOC(m_rSource.pLockBytes = new CStreamLockBytes(pStream));
// If IMAP
if (IXP_IMAP == m_rDownload.ixptype)
{
// Tell the Transport to connect
CHECKHR(hr = m_rDownload.pTransport->Connect(&m_rDownload.rServer, TRUE, FALSE));
}
// Otherwise
else
{
// Tell the Transport to connect
CHECKHR(hr = m_rDownload.pTransport->Connect(&m_rDownload.rServer, TRUE, TRUE));
}
// all went well, return E_PENDING to indicate we're going ASYNC
hr = E_PENDING;
exit:
// Cleanup
SafeRelease(pStream);
SafeMemFree(pszUrl);
// Failure
if (E_PENDING != hr && FAILED(hr))
{
// Tell the sink about my mime type
_OnFinished(hr);
// Release some objects
Terminate(0);
}
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// ----------------------------------------------------------------------------
// CInternetMessageUrl::_HrTransportFromUrl
// ----------------------------------------------------------------------------
HRESULT CInternetMessageUrl::_HrTransportFromUrl(LPCSTR pszUrl)
{
// Locals
HRESULT hr=S_OK;
CHAR szLogFile[MAX_PATH];
// Invalid ARg
Assert(pszUrl);
// Get Windows system Directory
GetSystemDirectory(szLogFile, MAX_PATH);
if (szLogFile[lstrlen(szLogFile) - 1] != '\\')
lstrcat(szLogFile, "\\Msgurlp.log");
else
lstrcat(szLogFile, "Msgurlp.log");
// We should not have been inited
Assert(NULL == m_rDownload.pTransport);
// Default Timeout
m_rDownload.rServer.dwTimeout = 30;
#ifdef DEBUG
m_rDownload.rServer.fTrySicily = TRUE;
#endif
// IXP_NNTP
if (StrCmpNI(pszUrl, "nntp:", 5) == 0)
{
// Set the source Type
m_rDownload.ixptype = IXP_NNTP;
// Create the NNTP Transport
CHECKHR(hr = CreateNNTPTransport(&m_rDownload.pIxpNntp));
// Init the Transport
CHECKHR(hr = m_rDownload.pIxpNntp->InitNew(szLogFile, (INNTPCallback *)this));
// Save IInternetTranport Interface
m_rDownload.pTransport = (IInternetTransport *)m_rDownload.pIxpNntp;
// Default Port
m_rDownload.rServer.dwPort = DEFAULT_NNTP_PORT;
}
// IXP_IMAP
else if (StrCmpNI(pszUrl, "imap:", 5) == 0)
{
// Set the ixp type
m_rDownload.ixptype = IXP_IMAP;
// Create the IMAP Transport
CHECKHR(hr = CreateIMAPTransport(&m_rDownload.pIxpImap));
// Init the Transport
CHECKHR(hr = m_rDownload.pIxpImap->InitNew(szLogFile, (IIMAPCallback *)this));
// Save IInternetTranport Interface
m_rDownload.pTransport = (IInternetTransport *)m_rDownload.pIxpImap;
// Default Port
m_rDownload.rServer.dwPort = DEFAULT_IMAP_PORT;
}
// IXP_POP3
else if (StrCmpNI(pszUrl, "pop3:", 5) == 0)
{
// Set the protocol type
m_rDownload.ixptype = IXP_POP3;
// Create the POP3 Transport
CHECKHR(hr = CreatePOP3Transport(&m_rDownload.pIxpPop3));
// Init the Transport
CHECKHR(hr = m_rDownload.pIxpPop3->InitNew(szLogFile, (IPOP3Callback *)this));
// Save IInternetTranport Interface
m_rDownload.pTransport = (IInternetTransport *)m_rDownload.pIxpPop3;
// Default Port
m_rDownload.rServer.dwPort = DEFAULT_POP3_PORT;
}
// Bad Protocol
else
{
hr = TrapError(E_FAIL);
goto exit;
}
// Crack the Message Url
CHECKHR(hr = _HrCrackMessageUrl(pszUrl));
exit:
// Done
return hr;
}
// ----------------------------------------------------------------------------
// CInternetMessageUrl::_HrCrackMessageUrl
// ----------------------------------------------------------------------------
HRESULT CInternetMessageUrl::_HrCrackMessageUrl(LPCSTR pszUrl)
{
// Locals
HRESULT hr=E_FAIL;
CStringParser cString;
CHAR chToken;
// Invalid Args
Assert(pszUrl && ':' == pszUrl[4]);
// Init the Parser
cString.Init(pszUrl, lstrlen(pszUrl), PSF_NOFRONTWS | PSF_NOTRAILWS);
// Bad Length
if (cString.GetLength() < 7)
return TrapError(E_FAIL);
// Parse
chToken = cString.ChParse(":");
if ('\0' == chToken)
goto exit;
// Bad Length
if (cString.CchValue() > 4)
return TrapError(E_FAIL);
// Skip Tokens
chToken = cString.ChSkip("\\/");
if ('\0' == chToken)
goto exit;
// Bad Length
if (cString.GetIndex() > 7)
return TrapError(E_FAIL);
// Skip Tokens
chToken = cString.ChParse(":\\/");
if ('\0' == chToken)
goto exit;
// This is the server name
lstrcpyn(m_rDownload.rServer.szServerName, cString.PszValue(), CCHMAX_SERVER_NAME);
// Extract Port Number
if (':' == chToken)
{
// Skip Tokens
chToken = cString.ChParse("\\/");
if ('\0' == chToken)
goto exit;
// Convert the port number
m_rDownload.rServer.dwPort = StrToInt(cString.PszValue());
}
// IXP_NNTP - nntp://<host>:<port>/<newsgroup-name>/<article-number>
if (IXP_NNTP == m_rDownload.ixptype)
{
// Skip Tokens
chToken = cString.ChParse("\\/");
if ('\0' == chToken)
goto exit;
// Save the News group Name
CHECKALLOC(m_rDownload.pszFolder = PszDupA(cString.PszValue()));
// Skip Tokens
chToken = cString.ChParse("\\/");
if (0 == cString.CchValue())
goto exit;
// Save the article number
CHECKALLOC(m_rDownload.pszArticle = PszDupA(cString.PszValue()));
}
// IXP_IMAP - nntp://<host>:<port>/<folder>/<uid>
else if (IXP_IMAP == m_rDownload.ixptype)
{
// Skip Tokens
chToken = cString.ChParse("\\/");
if ('\0' == chToken)
goto exit;
// Save the Folder Name
CHECKALLOC(m_rDownload.pszFolder = PszDupA(cString.PszValue()));
// Skip Tokens
chToken = cString.ChParse("\\/");
if (0 == cString.CchValue())
goto exit;
// Save the article number
m_rDownload.dwMessageId = StrToInt(cString.PszValue());
}
// IXP_POP3 - pop3://<host>:<port>/<popid>
else if (IXP_POP3 == m_rDownload.ixptype)
{
// Skip Tokens
chToken = cString.ChParse("\\/");
if (0 == cString.CchValue())
goto exit;
// Save the article number
m_rDownload.dwMessageId = StrToInt(cString.PszValue());
}
// Problems
else
{
Assert(FALSE);
goto exit;
}
// Success
hr = S_OK;
exit:
// Done
return TrapError(hr);
}
// --------------------------------------------------------------------------------
// CInternetMessageUrl::Continue (IOInetProtocol)
// --------------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::Continue(PROTOCOLDATA *pStateInfo)
{
// Locals
HRESULT hr=S_OK;
PROTOCOLDATA rProtocol;
// Thread Safety
EnterCriticalSection(&m_cs);
// Switch on the data
switch(pStateInfo->dwState)
{
case TRANSPORT_DISCONNECT:
// Not disconnected yet ?
if (m_rDownload.pTransport->IsState(IXP_IS_CONNECTED) == S_OK)
{
// Setup the Protocol Data
ZeroMemory(&rProtocol, sizeof(PROTOCOLDATA));
rProtocol.grfFlags = PI_FORCE_ASYNC;
rProtocol.dwState = DWLS_FINISHED;
// Switch State
m_pProtSink->Switch(&rProtocol);
// Pending
hr = E_PENDING;
}
// Otherwise, issue the final result
else
{
// Final Result
m_pProtSink->ReportResult(m_hrResult, m_dwResult, m_pszResult);
}
// Done
break;
}
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CInternetMessageUrl::Abort (IOInetProtocol)
// --------------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::Abort(HRESULT hrReason, DWORD dwOptions)
{
// Locals
HRESULT hr=S_OK;
// Thread Safety
EnterCriticalSection(&m_cs);
// _OnFinished
_OnFinished(IXP_E_USER_CANCEL);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CInternetMessageUrl::Terminate (IOInetProtocol)
// --------------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::Terminate(DWORD dwOptions)
{
// Thread Safety
EnterCriticalSection(&m_cs);
// Better not be connected
Assert(m_rDownload.pTransport->IsState(IXP_IS_CONNECTED) == S_FALSE);
// Release the Transport
SafeRelease(m_rDownload.pTransport);
// Release Objects
SafeRelease(m_pProtSink);
SafeRelease(m_pBindInfo);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return S_OK;
}
// --------------------------------------------------------------------------------
// CInternetMessageUrl::Suspend (IOInetProtocol)
// --------------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::Suspend(void)
{
return TrapError(E_NOTIMPL);
}
// --------------------------------------------------------------------------------
// CInternetMessageUrl::Resume (IOInetProtocol)
// --------------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::Resume(void)
{
return TrapError(E_NOTIMPL);
}
// --------------------------------------------------------------------------------
// CInternetMessageUrl::Read (IOInetProtocol)
// --------------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::Read(LPVOID pv,ULONG cb, ULONG *pcbRead)
{
// Locals
HRESULT hr=S_OK;
// Thread Safety
EnterCriticalSection(&m_cs);
// Call Utility Function
CHECKHR(hr = HrPluggableProtocolRead(&m_rSource, pv, cb, pcbRead));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CInternetMessageUrl::Seek (IOInetProtocol)
// --------------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNew)
{
// Locals
HRESULT hr=S_OK;
// Thread Safety
EnterCriticalSection(&m_cs);
// Call Utility Function
CHECKHR(hr = HrPluggableProtocolSeek(&m_rSource, dlibMove, dwOrigin, plibNew));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CInternetMessageUrl::LockRequest (IOInetProtocol)
// --------------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::LockRequest(DWORD dwOptions)
{
return S_OK;
}
// --------------------------------------------------------------------------------
// CInternetMessageUrl::UnlockRequest (IOInetProtocol)
// --------------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::UnlockRequest(void)
{
return S_OK;
}
// --------------------------------------------------------------------------------
// CInternetMessageUrl::QueryService (IServiceProvider)
// --------------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::QueryService(REFGUID rsid, REFIID riid, LPVOID *ppv)
{
// Locals
HRESULT hr=S_OK;
IServiceProvider *pSP=NULL;
// Invalid Arg
if (NULL == ppv)
return TrapError(E_INVALIDARG);
// Init
*ppv = NULL;
// Thread Safety
EnterCriticalSection(&m_cs);
// No Protocol Sink Yet ?
if (NULL == m_pProtSink)
{
hr = TrapError(E_FAIL);
goto exit;
}
// QI the Sink for the IServiceProvider
CHECKHR(hr = m_pProtSink->QueryInterface(IID_IServiceProvider, (LPVOID *)&pSP));
// Query Service the Service Provider
CHECKHR(hr = pSP->QueryService(rsid, riid, ppv));
exit:
// Cleanup
SafeRelease(pSP);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// ----------------------------------------------------------------------------
// CInternetMessageUrl::OnTimeout
// ----------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::OnTimeout(DWORD *pdwTimeout, IInternetTransport *pTransport)
{
// _OnFinished
_OnFinished(IXP_E_TIMEOUT);
// Done
return S_OK;
}
// ----------------------------------------------------------------------------
// CInternetMessageUrl::OnLogonPrompt
// ----------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::OnLogonPrompt(LPINETSERVER pInetServer, IInternetTransport *pTransport)
{
// Thread Safety
EnterCriticalSection(&m_cs);
// $$TODO$$ User Logon Prompt
lstrcpy(pInetServer->szUserName, "sbailey");
lstrcpy(pInetServer->szPassword, "password");
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return S_OK;
}
// ----------------------------------------------------------------------------
// CInternetMessageUrl::OnPrompt
// ----------------------------------------------------------------------------
STDMETHODIMP_(INT) CInternetMessageUrl::OnPrompt(HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType, IInternetTransport *pTransport)
{
// Thread Safety
EnterCriticalSection(&m_cs);
INT nAnswer = MessageBox(NULL, pszText, pszCaption, uType);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return nAnswer;
}
// ----------------------------------------------------------------------------
// CInternetMessageUrl::OnStatus
// ----------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::OnStatus(IXPSTATUS ixpstatus, IInternetTransport *pTransport)
{
// Locals
PROTOCOLDATA rProtocol;
// Thread Safety
EnterCriticalSection(&m_cs);
// Map IxpStatus to BINDSTATUS
switch(ixpstatus)
{
case IXP_FINDINGHOST:
m_pProtSink->ReportProgress(BINDSTATUS_FINDINGRESOURCE, m_pszUrl);
break;
case IXP_CONNECTING:
m_pProtSink->ReportProgress(BINDSTATUS_CONNECTING, m_pszUrl);
break;
case IXP_SECURING:
m_pProtSink->ReportProgress(BINDSTATUS_CONNECTING, m_pszUrl);
break;
case IXP_CONNECTED:
m_pProtSink->ReportProgress(BINDSTATUS_CONNECTING, m_pszUrl);
break;
case IXP_AUTHORIZING:
m_pProtSink->ReportProgress(BINDSTATUS_CONNECTING, m_pszUrl);
break;
case IXP_AUTHRETRY:
m_pProtSink->ReportProgress(BINDSTATUS_CONNECTING, m_pszUrl);
break;
case IXP_AUTHORIZED:
m_pProtSink->ReportProgress(BINDSTATUS_SENDINGREQUEST, m_pszUrl);
// Select the folder
if (IXP_IMAP == m_rDownload.ixptype)
{
// Issue Select
HRESULT hr = m_rDownload.pIxpImap->Select(TRX_IMAP_SELECT, 0, NULL, m_rDownload.pszFolder);
if (FAILED(hr))
{
_OnFinished(hr);
goto exit;
}
}
// Done
break;
case IXP_DISCONNECTED:
// Setup for the protocol switch
Assert(DWLS_FINISHED == m_state);
ZeroMemory(&rProtocol, sizeof(PROTOCOLDATA));
rProtocol.grfFlags = PI_FORCE_ASYNC;
rProtocol.dwState = DWLS_FINISHED;
// Switch State
m_pProtSink->Switch(&rProtocol);
break;
}
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return S_OK;
}
// ----------------------------------------------------------------------------
// CInternetMessageUrl::OnError
// ----------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::OnError(IXPSTATUS ixpstatus, LPIXPRESULT pResult, IInternetTransport *pTransport)
{
// _OnFinished
_OnFinished(pResult->hrResult, ixpstatus);
// Done
return S_OK;
}
// ----------------------------------------------------------------------------
// CInternetMessageUrl::OnCommand
// ----------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::OnCommand(CMDTYPE cmdtype, LPSTR pszLine, HRESULT hrResponse, IInternetTransport *pTransport)
{
#ifdef DEBUG
if (CMD_SEND == cmdtype)
DebugTrace("SEND (hr = %0X): %s", hrResponse, pszLine);
else
DebugTrace("RECV (hr = %0X): %s", hrResponse, pszLine);
// CR ?
if (pszLine[lstrlen(pszLine) - 1] != '\n')
DebugTrace("\n");
#endif
// Done
return S_OK;
}
// ----------------------------------------------------------------------------
// CInternetMessageUrl::OnResponse (NNTP)
// ----------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::OnResponse(LPNNTPRESPONSE pResponse)
{
// Switch on the Command
switch(pResponse->state)
{
case NS_IDLE:
break;
}
// Done
return S_OK;
}
// ----------------------------------------------------------------------------
// CInternetMessageUrl::OnResponse (POP3)
// ----------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::OnResponse(LPPOP3RESPONSE pResponse)
{
// Locals
HRESULT hr=S_OK;
// Thread Safety
EnterCriticalSection(&m_cs);
// Failure
if (FAILED(pResponse->rIxpResult.hrResult))
{
_OnFinished(pResponse->rIxpResult.hrResult);
goto exit;
}
// Switch on the Command
switch(pResponse->command)
{
case POP3_CONNECTED:
// Issue STAT Command
hr = m_rDownload.pIxpPop3->CommandSTAT();
if (FAILED(hr))
{
_OnFinished(hr);
goto exit;
}
// Done
break;
case POP3_STAT:
// Issue List Command for this popid
hr = m_rDownload.pIxpPop3->CommandLIST(POP3CMD_GET_POPID, m_rDownload.dwMessageId);
if (FAILED(hr))
{
_OnFinished(hr);
goto exit;
}
// Done
break;
case POP3_LIST:
// Save Message Size
Assert(pResponse->rListInfo.dwPopId == m_rDownload.dwMessageId);
// Save the size
m_rSource.cbTotalSize.QuadPart = pResponse->rListInfo.cbSize;
// Size is known
FLAGSET(m_rSource.dwFlags, INETPROT_TOTALSIZEKNOWN);
// Issue Retr Command for this popid
hr = m_rDownload.pIxpPop3->CommandRETR(POP3CMD_GET_POPID, m_rDownload.dwMessageId);
if (FAILED(hr))
{
_OnFinished(hr);
goto exit;
}
// Done
break;
case POP3_RETR:
// Deliver the Information
hr = _HrDispatchDataAvailable((LPBYTE)pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, pResponse->fDone);
if (FAILED(hr))
{
_OnFinished(hr);
goto exit;
}
// Done
break;
}
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// ----------------------------------------------------------------------------
// CInternetMessageUrl::OnResponse (IMAP)
// ----------------------------------------------------------------------------
STDMETHODIMP CInternetMessageUrl::OnResponse(const IMAP_RESPONSE *pResponse)
{
// Locals
HRESULT hr=S_OK;
CHAR szUID[50];
LPBYTE pbMessage=NULL;
ULONG cbMessage;
// Thread Safety
EnterCriticalSection(&m_cs);
// Switch on the Command
switch(pResponse->irtResponseType)
{
case irtUPDATE_MSG:
// Ignore it completely, we just care about the body
break;
case irtFETCH_BODY:
// Deliver the Information
hr = _HrDispatchDataAvailable((LPBYTE)pResponse->irdResponseData.pFetchBodyPart->pszData,
pResponse->irdResponseData.pFetchBodyPart->dwSizeOfData,
pResponse->irdResponseData.pFetchBodyPart->fDone);
if (FAILED(hr))
{
_OnFinished(hr);
goto exit;
}
// Done
break;
case irtCOMMAND_COMPLETION:
switch(pResponse->wParam)
{
case TRX_IMAP_FETCH:
// Failure
if (FAILED(pResponse->hrResult))
{
_OnFinished(pResponse->hrResult);
goto exit;
}
// Done
break;
case TRX_IMAP_SELECT:
// Failure
if (FAILED(pResponse->hrResult))
{
_OnFinished(pResponse->hrResult);
goto exit;
}
// Format UID
wsprintf(szUID, "%lu (RFC822)", m_rDownload.dwMessageId);
// Select the folder
hr = m_rDownload.pIxpImap->Fetch(TRX_IMAP_FETCH, 0, NULL, NULL, TRUE, szUID);
if (FAILED(hr))
{
_OnFinished(hr);
goto exit;
}
// Done
break;
}
// Done
break;
}
exit:
// Cleanup
SafeMemFree(pbMessage);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// ----------------------------------------------------------------------------
// CMessageDownload::_HrDispatchDataAvailable
// ----------------------------------------------------------------------------
HRESULT CInternetMessageUrl::_HrDispatchDataAvailable(LPBYTE pbData, ULONG cbData, BOOL fDone)
{
// Locals
HRESULT hr=S_OK;
DWORD grfBSCF;
ULONG cbWrote;
// First Notification
if (0 == m_rSource.offInternal.QuadPart)
{
// BindStatusCallback
grfBSCF = BSCF_FIRSTDATANOTIFICATION;
// Tell the sink about my mime type
m_pProtSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, L"message/rfc822");
}
// Last Notification
else if (fDone)
{
// Finished
FLAGSET(m_rSource.dwFlags, INETPROT_DOWNLOADED);
// BindStatusCallback
grfBSCF = BSCF_LASTDATANOTIFICATION;
}
// Intermediate Notification
else
grfBSCF = BSCF_INTERMEDIATEDATANOTIFICATION;
// Write it into m_pLockBytes
CHECKHR(hr = m_pLockBytes->WriteAt(m_rSource.offInternal, pbData, cbData, &cbWrote));
// Another type of failure
if (cbData != cbWrote)
{
hr = TrapError(E_FAIL);
goto exit;
}
// Increment m_offInternal
m_rSource.offInternal.QuadPart += cbWrote;
// Increment m_cbCurrent
if (m_rSource.offInternal.QuadPart + cbWrote > m_rSource.cbSize.QuadPart)
m_rSource.cbSize.QuadPart = m_rSource.offInternal.QuadPart + cbWrote;
// Increment Current
m_rSource.offInternal.QuadPart += cbWrote;
// Done ?
if (fDone)
{
// Close Connection
_OnFinished(S_OK);
}
// Report data to the sink
m_pProtSink->ReportData(grfBSCF, (ULONG)m_rSource.offInternal.QuadPart, (ULONG)m_rSource.cbSize.QuadPart);
exit:
// Done
return hr;
}
// ----------------------------------------------------------------------------
// CInternetMessageUrl::_OnFinished
// ----------------------------------------------------------------------------
void CInternetMessageUrl::_OnFinished(HRESULT hrResult, DWORD dwResult, LPCWSTR pszResult)
{
// Thread Safety
EnterCriticalSection(&m_cs);
// If Not Finished
if (DWLS_FINISHED != m_state)
{
// If Still Connected
Assert(m_rDownload.pTransport->IsState(IXP_IS_CONNECTED) == S_OK);
// Save the Result State
m_hrResult = hrResult;
// Safe Result
m_dwResult = dwResult;
// Safe pszResult
m_pszResult = PszDupW(pszResult);
// Finished
m_state = DWLS_FINISHED;
// Start Disconnect
if (FAILED(hrResult))
m_rDownload.pTransport->DropConnection();
// Graceful disconnect
else
m_rDownload.pTransport->Disconnect();
}
// Thread Safety
LeaveCriticalSection(&m_cs);
}