1158 lines
35 KiB
C++
1158 lines
35 KiB
C++
// --------------------------------------------------------------------------------
|
|
// h t t p t a s k . h
|
|
// Copyright (c)1998 Microsoft Corporation, All Rights Reserved
|
|
// Greg S. Friedman
|
|
// --------------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "httptask.h"
|
|
#include "taskutil.h"
|
|
#include "acctcach.h"
|
|
#include "xputil.h"
|
|
#include "useragnt.h"
|
|
#include "..\http\httputil.h"
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Data Types
|
|
// --------------------------------------------------------------------------------
|
|
typedef enum tagHTTPEVENTTYPE
|
|
{
|
|
EVENT_HTTPSEND
|
|
} HTTPEVENTTYPE;
|
|
|
|
#define CURRENTHTTPEVENT ((LPHTTPEVENTINFO)m_psaEvents->GetItemAt(m_iEvent))
|
|
|
|
//----------------------------------------------------------------------
|
|
// FreeNewMessageInfo
|
|
//----------------------------------------------------------------------
|
|
static void __cdecl _FreeHTTPEventInfo(LPVOID pei)
|
|
{
|
|
Assert(NULL != pei);
|
|
SafeMemFree(pei);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::CHTTPTask
|
|
// --------------------------------------------------------------------------------
|
|
CHTTPTask::CHTTPTask(void) :
|
|
m_cRef(1),
|
|
m_dwFlags(NOFLAGS),
|
|
m_dwState(NOFLAGS),
|
|
m_cbTotal(0),
|
|
m_cbSent(0),
|
|
m_cbStart(0),
|
|
m_cCompleted(0),
|
|
m_wProgress(0),
|
|
m_pSpoolCtx(NULL),
|
|
m_pAccount(NULL),
|
|
m_pOutbox(NULL),
|
|
m_pSentItems(NULL),
|
|
m_psaEvents(NULL),
|
|
m_iEvent(0),
|
|
m_pszSubject(NULL),
|
|
m_pBody(NULL),
|
|
m_pTransport(NULL),
|
|
m_pUI(NULL),
|
|
m_idSendEvent(INVALID_EVENT),
|
|
m_pszAccountId(NULL),
|
|
m_pszSendMsgUrl(NULL)
|
|
{
|
|
InitializeCriticalSection(&m_cs);
|
|
|
|
ZeroMemory(&m_rServer, sizeof(m_rServer));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::~CHTTPTask
|
|
// --------------------------------------------------------------------------------
|
|
CHTTPTask::~CHTTPTask(void)
|
|
{
|
|
ZeroMemory(&m_rServer, sizeof(m_rServer)); // Done for security.
|
|
_Reset();
|
|
DeleteCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::QueryInterface
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::QueryInterface(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_IUnknown == riid)
|
|
*ppv = (IUnknown *)(ISpoolerTask *)this;
|
|
else if (IID_ISpoolerTask == riid)
|
|
*ppv = (ISpoolerTask *)this;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
hr = TrapError(E_NOINTERFACE);
|
|
goto exit;
|
|
}
|
|
|
|
// AddRef It
|
|
((IUnknown *)*ppv)->AddRef();
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::AddRef
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CHTTPTask::AddRef(void)
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::Release
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CHTTPTask::Release(void)
|
|
{
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef)
|
|
delete this;
|
|
return (ULONG)cRef;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// ISpoolerTask Methods
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::Init
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::Init(DWORD dwFlags, ISpoolerBindContext *pBindCtx)
|
|
{
|
|
// Invalid Arg
|
|
if (NULL == pBindCtx)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Save the Activity Flags - DELIVER_xxx
|
|
m_dwFlags = dwFlags;
|
|
|
|
// Hold onto the bind context
|
|
Assert(NULL == m_pSpoolCtx);
|
|
m_pSpoolCtx = pBindCtx;
|
|
m_pSpoolCtx->AddRef();
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::BuildEvents
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::BuildEvents(ISpoolerUI *pSpoolerUI,
|
|
IImnAccount *pAccount,
|
|
FOLDERID idFolder)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HROWSET hRowset=NULL;
|
|
MESSAGEINFO mi = {0};
|
|
CHAR szAccount[CCHMAX_ACCOUNT_NAME];
|
|
CHAR szAccountId[CCHMAX_ACCOUNT_NAME];
|
|
CHAR szMessage[255];
|
|
CHAR szRes[255];
|
|
FOLDERINFO fi = {0};
|
|
LPFOLDERINFO pfiFree = NULL;
|
|
LPSTR pszUserAgent = GetOEUserAgentString();
|
|
LPSTR pszCachedPass = NULL;
|
|
FOLDERID idServer;
|
|
|
|
// Invalid Arg
|
|
if (NULL == pSpoolerUI || NULL == pAccount)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
m_pUI = pSpoolerUI;
|
|
m_pUI->AddRef();
|
|
|
|
m_pAccount = pAccount;
|
|
m_pAccount->AddRef();
|
|
|
|
// Get the Account Name
|
|
CHECKHR(hr = m_pAccount->GetPropSz(AP_ACCOUNT_NAME, szAccount, ARRAYSIZE(szAccount)));
|
|
|
|
// Get the account ID
|
|
CHECKHR(hr = m_pAccount->GetPropSz(AP_ACCOUNT_ID, szAccountId, ARRAYSIZE(szAccountId)));
|
|
m_pszAccountId = PszDupA(szAccountId);
|
|
|
|
// Get the outbox
|
|
CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreOutbox, (LPVOID *)&m_pOutbox));
|
|
|
|
// Get the sent items. Don't fail if it doesn't exist.
|
|
if (DwGetOption(OPT_SAVESENTMSGS))
|
|
{
|
|
if (SUCCEEDED(g_pStore->FindServerId(m_pszAccountId, &idServer)))
|
|
g_pStore->OpenSpecialFolder(idServer, NULL, FOLDER_SENT, &m_pSentItems);
|
|
}
|
|
|
|
// Create a Rowset
|
|
CHECKHR(hr = m_pOutbox->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset));
|
|
|
|
// Loop
|
|
while (S_OK == m_pOutbox->QueryRowset(hRowset, 1, (LPVOID *)&mi, NULL))
|
|
{
|
|
CHECKHR(hr = _HrAppendOutboxMessage(szAccount, &mi));
|
|
|
|
// Free Current
|
|
m_pOutbox->FreeRecord(&mi);
|
|
}
|
|
|
|
if (NULL == m_psaEvents || 0 == m_psaEvents->GetLength())
|
|
goto exit;
|
|
|
|
// create the transport object
|
|
CHECKHR(hr = CoCreateInstance(CLSID_IHTTPMailTransport, NULL, CLSCTX_INPROC_SERVER, IID_IHTTPMailTransport, (LPVOID *)&m_pTransport));
|
|
|
|
// Init the Transport
|
|
CHECKHR(hr = m_pTransport->InitNew(pszUserAgent, NULL, this));
|
|
|
|
// Fill an INETSERVER structure from the account object
|
|
CHECKHR(hr = m_pTransport->InetServerFromAccount(m_pAccount, &m_rServer));
|
|
|
|
// looked for a cached password and, if one exists, use it
|
|
GetAccountPropStrA(m_pszAccountId, CAP_PASSWORD, &pszCachedPass);
|
|
if (NULL != pszCachedPass)
|
|
StrCpyN(m_rServer.szPassword, pszCachedPass, sizeof(m_rServer.szPassword));
|
|
|
|
// connect to the server. the transport won't
|
|
// actually connect until a command is issued
|
|
CHECKHR(hr = m_pTransport->Connect(&m_rServer, TRUE, FALSE));
|
|
|
|
LOADSTRING(IDS_SPS_SMTPEVENT, szRes);
|
|
wnsprintf(szMessage, ARRAYSIZE(szMessage), szRes, m_psaEvents->GetLength(), m_rServer.szAccount);
|
|
|
|
CHECKHR(hr = m_pSpoolCtx->RegisterEvent(szMessage, (ISpoolerTask *)this, EVENT_HTTPSEND, m_pAccount, &m_idSendEvent));
|
|
|
|
// If this account is set to always prompt for password and password isn't
|
|
// already cached, show UI so we can prompt user for password
|
|
if (ISFLAGSET(m_rServer.dwFlags, ISF_ALWAYSPROMPTFORPASSWORD) && NULL == pszCachedPass)
|
|
{
|
|
m_pUI->ShowWindow(SW_SHOW);
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pszUserAgent);
|
|
SafeMemFree(pszCachedPass);
|
|
|
|
if (m_pOutbox)
|
|
{
|
|
m_pOutbox->CloseRowset(&hRowset);
|
|
m_pOutbox->FreeRecord(&mi);
|
|
}
|
|
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::Execute
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::Execute(EVENTID eid, DWORD_PTR dwTwinkie)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
if (EVENT_HTTPSEND == dwTwinkie)
|
|
hr = _HrExecuteSend(eid, dwTwinkie);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::CancelEvent
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::CancelEvent(EVENTID eid, DWORD_PTR dwTwinkie)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::Cancel
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::Cancel(void)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
m_dwState |= HTTPSTATE_CANCELED;
|
|
|
|
// Simply drop the connection
|
|
if (m_pTransport)
|
|
m_pTransport->DropConnection();
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::IsDialogMessage
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::IsDialogMessage(LPMSG pMsg)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::OnFlagsChanged
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::OnFlagsChanged(DWORD dwFlags)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::OnLogonPrompt
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::OnLogonPrompt(
|
|
LPINETSERVER pInetServer,
|
|
IInternetTransport *pTransport)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPSTR pszCachedPass = NULL;
|
|
|
|
EnterCriticalSection(&m_cs);
|
|
// pull password out of the cache
|
|
GetAccountPropStrA(m_pszAccountId, CAP_PASSWORD, &pszCachedPass);
|
|
if (NULL != pszCachedPass && 0 != lstrcmp(pszCachedPass, pInetServer->szPassword))
|
|
{
|
|
StrCpyN(pInetServer->szPassword, pszCachedPass, ARRAYSIZE(pInetServer->szPassword));
|
|
goto exit;
|
|
}
|
|
|
|
if (ISFLAGSET(m_dwFlags, DELIVER_NOUI))
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
hr = TaskUtil_OnLogonPrompt(m_pAccount, m_pUI, NULL, pInetServer, AP_HTTPMAIL_USERNAME,
|
|
AP_HTTPMAIL_PASSWORD, AP_HTTPMAIL_PROMPT_PASSWORD, TRUE);
|
|
|
|
// cache the password
|
|
if (S_OK == hr)
|
|
HrCacheAccountPropStrA(m_pszAccountId, CAP_PASSWORD, pInetServer->szPassword);
|
|
|
|
exit:
|
|
LeaveCriticalSection(&m_cs);
|
|
SafeMemFree(pszCachedPass);
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::OnPrompt
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(INT) CHTTPTask::OnPrompt(
|
|
HRESULT hrError,
|
|
LPCTSTR pszText,
|
|
LPCTSTR pszCaption,
|
|
UINT uType,
|
|
IInternetTransport *pTransport)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::OnStatus
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::OnStatus(IXPSTATUS ixpstatus, IInternetTransport *pTransport)
|
|
{
|
|
// Locals
|
|
EVENTCOMPLETEDSTATUS tyEventStatus = EVENT_SUCCEEDED;
|
|
|
|
// Invalid State
|
|
Assert(m_pUI && m_pSpoolCtx);
|
|
if (!m_pUI || !m_pSpoolCtx)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Feed the the IXP status to the UI object
|
|
m_pUI->SetSpecificProgress(MAKEINTRESOURCE(XPUtil_StatusToString(ixpstatus)));
|
|
|
|
// Disconnected
|
|
if (ixpstatus == IXP_DISCONNECTED)
|
|
{
|
|
HRESULT hrDisconnect = _OnDisconnectComplete();
|
|
|
|
// TODO: update progress state and deal with errors
|
|
|
|
// Set the animation
|
|
m_pUI->SetAnimation(idanOutbox, FALSE);
|
|
|
|
if (!ISFLAGSET(m_dwState, HTTPSTATE_EVENTSUCCESS) || (NULL != m_cCompleted && m_cCompleted < m_psaEvents->GetLength()))
|
|
{
|
|
if (ISFLAGSET(m_dwState, HTTPSTATE_CANCELED))
|
|
tyEventStatus = EVENT_CANCELED;
|
|
else if (ISFLAGSET(m_dwState, HTTPSTATE_EVENTSUCCESS))
|
|
tyEventStatus = EVENT_WARNINGS;
|
|
else
|
|
tyEventStatus = EVENT_FAILED;
|
|
}
|
|
|
|
// Result
|
|
m_pSpoolCtx->Notify(DELIVERY_NOTIFY_RESULT, tyEventStatus);
|
|
|
|
// Result
|
|
m_pSpoolCtx->Notify(DELIVERY_NOTIFY_COMPLETE, 0);
|
|
|
|
// Hands Off my callback
|
|
SideAssert(m_pTransport->HandsOffCallback() == S_OK);
|
|
|
|
// This task is complete
|
|
m_pSpoolCtx->EventDone(m_idSendEvent, tyEventStatus);
|
|
}
|
|
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::OnError
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::OnError(
|
|
IXPSTATUS ixpstatus,
|
|
LPIXPRESULT pIxpResult,
|
|
IInternetTransport *pTransport)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::OnProgress
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::OnProgress(
|
|
DWORD dwIncrement,
|
|
DWORD dwCurrent,
|
|
DWORD dwMaximum,
|
|
IInternetTransport *pTransport)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::OnCommand
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::OnCommand(
|
|
CMDTYPE cmdtype,
|
|
LPSTR pszLine,
|
|
HRESULT hrResponse,
|
|
IInternetTransport *pTransport)
|
|
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::OnTimeout
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::OnTimeout(
|
|
DWORD *pdwTimeout,
|
|
IInternetTransport *pTransport)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// IHTTPMailCallback methods
|
|
// --------------------------------------------------------------------------------
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::OnResponse
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::OnResponse(LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrCatch;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// if the send message url couldn't be retrieved, convert the error into
|
|
// a more informative error code.
|
|
if (SP_E_HTTP_SERVICEDOESNTWORK == pResponse->rIxpResult.hrResult)
|
|
{
|
|
_CatchResult(SP_E_HTTP_NOSENDMSGURL);
|
|
goto exit;
|
|
}
|
|
|
|
// Handle the Error
|
|
if (TASKRESULT_SUCCESS != _CatchResult(&pResponse->rIxpResult))
|
|
goto exit;
|
|
|
|
switch (pResponse->command)
|
|
{
|
|
case HTTPMAIL_GETPROP:
|
|
if (SUCCEEDED(_HrAdoptSendMsgUrl(pResponse->rGetPropInfo.pszProp)))
|
|
{
|
|
pResponse->rGetPropInfo.pszProp = NULL;
|
|
// build the message and post it
|
|
hr = _HrPostCurrentMessage();
|
|
}
|
|
break;
|
|
|
|
case HTTPMAIL_SENDMESSAGE:
|
|
_UpdateSendMessageProgress(pResponse);
|
|
if (pResponse->fDone)
|
|
_CatchResult(_HrFinishCurrentEvent(S_OK, pResponse->rSendMessageInfo.pszLocation));
|
|
break;
|
|
|
|
default:
|
|
Assert(FALSE);
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::GetParentWindow
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPTask::GetParentWindow(HWND *phwndParent)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Private Implementation
|
|
// --------------------------------------------------------------------------------
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::_Reset
|
|
// --------------------------------------------------------------------------------
|
|
void CHTTPTask::_Reset(void)
|
|
{
|
|
SafeRelease(m_pSpoolCtx);
|
|
SafeRelease(m_pAccount);
|
|
SafeRelease(m_pOutbox);
|
|
SafeRelease(m_pSentItems);
|
|
|
|
delete m_psaEvents;
|
|
m_iEvent = 0;
|
|
|
|
SafeMemFree(m_pszSubject);
|
|
|
|
SafeRelease(m_pBody);
|
|
|
|
SafeRelease(m_pTransport);
|
|
SafeRelease(m_pUI);
|
|
|
|
SafeMemFree(m_pszAccountId);
|
|
SafeMemFree(m_pszSendMsgUrl);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::_CatchResult
|
|
// --------------------------------------------------------------------------------
|
|
TASKRESULTTYPE CHTTPTask::_CatchResult(HRESULT hr)
|
|
{
|
|
// Locals
|
|
IXPRESULT rResult;
|
|
|
|
// Build an IXPRESULT
|
|
ZeroMemory(&rResult, sizeof(rResult));
|
|
rResult.hrResult = hr;
|
|
|
|
// Get the HTTPMail Result Type
|
|
return _CatchResult(&rResult);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::_CatchResult
|
|
// --------------------------------------------------------------------------------
|
|
TASKRESULTTYPE CHTTPTask::_CatchResult(LPIXPRESULT pResult)
|
|
{
|
|
HWND hwndParent;
|
|
TASKRESULTTYPE tyTaskResult = TASKRESULT_FAILURE;
|
|
|
|
// If Succeeded
|
|
if (SUCCEEDED(pResult->hrResult))
|
|
return TASKRESULT_SUCCESS;
|
|
|
|
// Get Window
|
|
if (NULL == m_pUI || FAILED(m_pUI->GetWindow(&hwndParent)))
|
|
hwndParent = NULL;
|
|
|
|
// Process generic protocol error
|
|
tyTaskResult = TaskUtil_FBaseTransportError(IXP_HTTPMail, m_idSendEvent, pResult, &m_rServer, m_pszSubject, m_pUI,
|
|
!ISFLAGSET(m_dwFlags, DELIVER_NOUI), hwndParent);
|
|
|
|
// Have a Transport
|
|
if (m_pTransport)
|
|
{
|
|
// If Task Failure, drop the connection
|
|
if (TASKRESULT_FAILURE == tyTaskResult)
|
|
{
|
|
// Roast the current connection
|
|
m_pTransport->DropConnection();
|
|
}
|
|
|
|
// If Event Failure...
|
|
else if (TASKRESULT_EVENTFAILED == tyTaskResult)
|
|
{
|
|
// Goto Next Event
|
|
if (FAILED(_HrFinishCurrentEvent(pResult->hrResult, NULL)))
|
|
{
|
|
// Roast the current connection
|
|
m_pTransport->DropConnection();
|
|
}
|
|
}
|
|
}
|
|
|
|
return tyTaskResult;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::_HrAppendOutboxMessage
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CHTTPTask::_HrAppendOutboxMessage(LPCSTR pszAccount, LPMESSAGEINFO pmi)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IImnAccount *pAccount = NULL;
|
|
LPHTTPEVENTINFO pEvent = NULL;
|
|
|
|
Assert(NULL != pszAccount && NULL != pmi);
|
|
|
|
// handle empty account id
|
|
if (NULL == pmi->pszAcctId || FAILED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pmi->pszAcctId, &pAccount)))
|
|
{
|
|
// do some special junk with default accounts
|
|
goto exit;
|
|
}
|
|
else if (lstrcmpi(pmi->pszAcctName, pszAccount) != 0)
|
|
goto exit;
|
|
|
|
if (NULL == m_psaEvents)
|
|
CHECKHR(hr = CSortedArray::Create(NULL, _FreeHTTPEventInfo, &m_psaEvents));
|
|
|
|
// build the event object and append it into the event array
|
|
if (!MemAlloc((void **)&pEvent, sizeof(HTTPEVENTINFO)))
|
|
{
|
|
hr = TrapError(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
CHECKHR(hr = m_psaEvents->Add(pEvent));
|
|
|
|
pEvent->idMessage = pmi->idMessage;
|
|
pEvent->fComplete = FALSE;
|
|
|
|
m_cbTotal += (pmi->cbMessage + 175);
|
|
pEvent->cbSentTotal = m_cbTotal; // running total
|
|
|
|
pEvent = NULL;
|
|
|
|
exit:
|
|
SafeMemFree(pEvent);
|
|
SafeRelease(pAccount);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::_HrCreateSendProps
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CHTTPTask::_HrCreateSendProps(IMimeMessage *pMessage,
|
|
LPSTR *ppszFrom,
|
|
LPHTTPTARGETLIST *ppTargets)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IMimeAddressTable *pAdrTable = NULL;
|
|
IMimeEnumAddressTypes *pAdrEnum = NULL;
|
|
ADDRESSPROPS rAddress;
|
|
ULONG c;
|
|
LPSTR pszFrom = NULL;
|
|
LPSTR pszTemp = NULL;
|
|
LPHTTPTARGETLIST pTargets = NULL;
|
|
DWORD dwTargetCapacity = 0;
|
|
|
|
Assert(NULL != ppszFrom && NULL != ppTargets);
|
|
if (NULL == ppszFrom || NULL == ppTargets)
|
|
return E_INVALIDARG;
|
|
|
|
*ppszFrom = NULL;
|
|
*ppTargets = NULL;
|
|
|
|
// allocate a targetlist
|
|
if (!MemAlloc((void **)&pTargets, sizeof(HTTPTARGETLIST)))
|
|
{
|
|
hr = TraceResult(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
pTargets->cTarget = 0;
|
|
pTargets->prgTarget = NULL;
|
|
|
|
ZeroMemory(&rAddress, sizeof(rAddress));
|
|
|
|
// Get the recipients...
|
|
CHECKHR(hr = pMessage->GetAddressTable(&pAdrTable));
|
|
|
|
// Get Enumerator
|
|
CHECKHR(hr = pAdrTable->EnumTypes(IAT_KNOWN, IAP_ADRTYPE | IAP_EMAIL, &pAdrEnum));
|
|
|
|
// Walk the enumerator
|
|
while (SUCCEEDED(pAdrEnum->Next(1, &rAddress, &c)) && c == 1)
|
|
{
|
|
if (NULL != rAddress.pszEmail)
|
|
{
|
|
// Get Type
|
|
if (ISFLAGSET(IAT_RECIPS, rAddress.dwAdrType))
|
|
{
|
|
// copy the address
|
|
pszTemp = PszDupA(rAddress.pszEmail);
|
|
if (NULL == pszTemp)
|
|
{
|
|
hr = TraceResult(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
// add it to the collection of addresses we are building
|
|
if (pTargets->cTarget == dwTargetCapacity)
|
|
{
|
|
if (!MemRealloc((void **)&pTargets->prgTarget, (dwTargetCapacity + 4) * sizeof(LPSTR)))
|
|
{
|
|
hr = TraceResult(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
dwTargetCapacity += 4;
|
|
}
|
|
|
|
pTargets->prgTarget[pTargets->cTarget++] = pszTemp;
|
|
pszTemp = NULL;
|
|
|
|
}
|
|
else if (NULL == pszFrom && IAT_FROM == rAddress.dwAdrType)
|
|
{
|
|
pszFrom = PszDupA(rAddress.pszEmail);
|
|
if (NULL == pszFrom)
|
|
{
|
|
hr = TraceResult(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Release
|
|
g_pMoleAlloc->FreeAddressProps(&rAddress);
|
|
}
|
|
|
|
// success. transfer ownership of the params to the caller
|
|
*ppszFrom = pszFrom;
|
|
pszFrom = NULL;
|
|
*ppTargets = pTargets;
|
|
pTargets = NULL;
|
|
|
|
exit:
|
|
if (pTargets)
|
|
Http_FreeTargetList(pTargets);
|
|
SafeMemFree(pszTemp);
|
|
SafeRelease(pAdrTable);
|
|
SafeRelease(pAdrEnum);
|
|
SafeMemFree(pszFrom);
|
|
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CHTTPTask::_HrOpenMessage
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CHTTPTask::_HrOpenMessage(MESSAGEID idMessage, IMimeMessage **ppMessage)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Check Params
|
|
Assert(ppMessage && m_pOutbox);
|
|
|
|
// Init
|
|
*ppMessage = NULL;
|
|
|
|
// Stream in message
|
|
CHECKHR(hr = m_pOutbox->OpenMessage(idMessage, OPEN_MESSAGE_SECURE, ppMessage, NOSTORECALLBACK));
|
|
|
|
// remove an X-Unsent headers before sending
|
|
(*ppMessage)->DeleteBodyProp(HBODY_ROOT, PIDTOSTR(PID_HDR_XUNSENT));
|
|
|
|
exit:
|
|
// Failure
|
|
if (FAILED(hr))
|
|
SafeRelease((*ppMessage));
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::_HrPostCurrentMessage
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CHTTPTask::_HrPostCurrentMessage(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IMimeMessage *pMessage = NULL;
|
|
LPHTTPEVENTINFO pEvent = NULL;
|
|
CHAR szRes[CCHMAX_RES];
|
|
CHAR szMsg[CCHMAX_RES + CCHMAX_ACCOUNT_NAME];
|
|
LPSTR pszFrom = NULL;
|
|
LPHTTPTARGETLIST pTargets = NULL;
|
|
|
|
Assert(NULL != m_psaEvents);
|
|
Assert(m_iEvent <= m_psaEvents->GetLength());
|
|
|
|
pEvent = CURRENTHTTPEVENT;
|
|
Assert(NULL != pEvent);
|
|
|
|
LOADSTRING(IDS_SPS_SMTPPROGRESS, szRes);
|
|
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_iEvent + 1, m_psaEvents->GetLength());
|
|
|
|
// Set Specific Progress
|
|
m_pUI->SetSpecificProgress(szMsg);
|
|
|
|
// Open Store Message
|
|
if (FAILED(_HrOpenMessage(pEvent->idMessage, &pMessage)))
|
|
{
|
|
hr = TrapError(SP_E_SMTP_CANTOPENMESSAGE);
|
|
goto exit;
|
|
}
|
|
|
|
CHECKHR(hr = _HrCreateSendProps(pMessage, &pszFrom, &pTargets));
|
|
|
|
CHECKHR(hr = pMessage->GetMessageSource(&m_pBody, 0));
|
|
|
|
hr = m_pTransport->SendMessage(m_pszSendMsgUrl, pszFrom, pTargets, DwGetOption(OPT_SAVESENTMSGS), m_pBody, 0);
|
|
|
|
exit:
|
|
SafeRelease(pMessage);
|
|
SafeMemFree(pszFrom);
|
|
if (pTargets)
|
|
Http_FreeTargetList(pTargets);
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::_HrExecuteSend
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CHTTPTask::_HrExecuteSend(EVENTID eid, DWORD_PTR dwTwinkie)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPSTR pszSendMsgUrl = NULL;
|
|
CHAR szRes[CCHMAX_RES];
|
|
CHAR szBuf[CCHMAX_RES + CCHMAX_SERVER_NAME];
|
|
|
|
|
|
// Set the animation
|
|
m_pUI->SetAnimation(idanOutbox, TRUE);
|
|
|
|
// Setup Progress Meter
|
|
m_pUI->SetProgressRange(100);
|
|
|
|
// Connecting to ...
|
|
LoadString(g_hLocRes, idsInetMailConnectingHost, szRes, ARRAYSIZE(szRes));
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_rServer.szAccount);
|
|
m_pUI->SetGeneralProgress(szBuf);
|
|
|
|
// Notify
|
|
m_pSpoolCtx->Notify(DELIVERY_NOTIFY_CONNECTING, 0);
|
|
|
|
Assert(NULL == m_pszSendMsgUrl);
|
|
|
|
// look for the sendmsg url in the cache
|
|
if (!GetAccountPropStrA(m_pszAccountId, CAP_HTTPMAILSENDMSG, &m_pszSendMsgUrl))
|
|
{
|
|
hr = m_pTransport->GetProperty(HTTPMAIL_PROP_SENDMSG, &pszSendMsgUrl);
|
|
if (E_PENDING == hr)
|
|
{
|
|
hr = S_OK;
|
|
goto exit;
|
|
}
|
|
CHECKHR(hr);
|
|
CHECKHR(hr = _HrAdoptSendMsgUrl(pszSendMsgUrl));
|
|
}
|
|
|
|
Assert(NULL != m_pszSendMsgUrl);
|
|
|
|
CHECKHR(hr = _HrPostCurrentMessage());
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::_HrAdoptSendMsgUrl
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CHTTPTask::_HrAdoptSendMsgUrl(LPSTR pszSendMsgUrl)
|
|
{
|
|
Assert(NULL == m_pszSendMsgUrl);
|
|
|
|
if (NULL == pszSendMsgUrl)
|
|
return E_INVALIDARG;
|
|
|
|
m_pszSendMsgUrl = pszSendMsgUrl ;
|
|
|
|
// add it to the account data cache
|
|
HrCacheAccountPropStrA(m_pszAccountId, CAP_HTTPMAILSENDMSG, m_pszSendMsgUrl);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::_HrFinishCurrentEvent
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CHTTPTask::_HrFinishCurrentEvent(HRESULT hrResult, LPSTR pszLocationUrl)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
LPHTTPEVENTINFO pEvent;
|
|
MESSAGEID idMessage;
|
|
|
|
if (FAILED(hrResult))
|
|
goto exit;
|
|
|
|
// save in sent items
|
|
if (m_pSentItems && m_pBody && pszLocationUrl)
|
|
{
|
|
// add the message to the sent items folder
|
|
CHECKHR(hr = Http_AddMessageToFolder(m_pSentItems, m_pszAccountId, NULL, ARF_READ, pszLocationUrl, &idMessage));
|
|
|
|
// write the message body out
|
|
CHECKHR(hr = Http_SetMessageStream(m_pSentItems, idMessage, m_pBody, NULL, TRUE));
|
|
}
|
|
|
|
// Get the current http event
|
|
pEvent = CURRENTHTTPEVENT;
|
|
|
|
pEvent->fComplete = TRUE;
|
|
m_dwState |= HTTPSTATE_EVENTSUCCESS;
|
|
|
|
++m_cCompleted;
|
|
|
|
exit:
|
|
// go to the next event
|
|
hr = _HrStartNextEvent();
|
|
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::_HrStartNextEvent
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CHTTPTask::_HrStartNextEvent(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
|
|
// free the previous subject
|
|
SafeMemFree(m_pszSubject);
|
|
|
|
// free the previous body
|
|
SafeRelease(m_pBody);
|
|
|
|
// Fixup m_cbSent to be correct
|
|
m_cbSent = (CURRENTHTTPEVENT)->cbSentTotal;
|
|
m_cbStart = m_cbSent;
|
|
|
|
// Are we done yet ?
|
|
if (m_iEvent + 1 == m_psaEvents->GetLength())
|
|
{
|
|
// Update progress
|
|
_DoProgress();
|
|
|
|
// Disconnect from the server
|
|
CHECKHR(hr = m_pTransport->Disconnect());
|
|
}
|
|
|
|
// otherwise, increment the event count and send the next message
|
|
else
|
|
{
|
|
// Next Event
|
|
m_iEvent++;
|
|
|
|
// Update progress
|
|
//_DoProgress();
|
|
// Send Reset Command
|
|
hr = _HrPostCurrentMessage();
|
|
if (hr == E_PENDING)
|
|
hr = S_OK;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::_OnDisconnectComplete
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CHTTPTask::_OnDisconnectComplete(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
LPDWORD prgdwIds = NULL;
|
|
DWORD cIdsAlloc = 0;
|
|
DWORD i;
|
|
LPHTTPEVENTINFO pEvent;
|
|
ADJUSTFLAGS Flags;
|
|
DWORD cEvents;
|
|
MESSAGEIDLIST rList;
|
|
|
|
rList.cMsgs = 0;
|
|
rList.prgidMsg = NULL;
|
|
|
|
// Invalid State
|
|
Assert(m_pOutbox);
|
|
Assert(m_psaEvents);
|
|
|
|
cEvents = m_psaEvents->GetLength();
|
|
|
|
// Walk through the list of events
|
|
for (i=0; i < cEvents; i++)
|
|
{
|
|
// Readability
|
|
pEvent = (LPHTTPEVENTINFO)m_psaEvents->GetItemAt(i);
|
|
|
|
// If this event was in the outbox
|
|
if (0 != pEvent->idMessage && pEvent->fComplete)
|
|
{
|
|
// Insert into my array of message ids
|
|
if (rList.cMsgs + 1 > cIdsAlloc)
|
|
{
|
|
// Realloc
|
|
CHECKHR(hr = HrRealloc((LPVOID *)&rList.prgidMsg, sizeof(DWORD) * (cIdsAlloc + 10)));
|
|
|
|
// Increment cIdsAlloc
|
|
cIdsAlloc += 10;
|
|
}
|
|
|
|
// Set Message Id
|
|
rList.prgidMsg[rList.cMsgs++] = pEvent->idMessage;
|
|
}
|
|
}
|
|
|
|
if (rList.cMsgs)
|
|
{
|
|
Flags.dwAdd = ARF_READ;
|
|
Flags.dwRemove = ARF_SUBMITTED | ARF_UNSENT;
|
|
|
|
if (m_idSendEvent != INVALID_EVENT)
|
|
{
|
|
// Delete the messages.
|
|
// Messages are never copied to the local outbox for httpmail
|
|
CHECKHR(hr = m_pOutbox->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &rList, NULL, NOSTORECALLBACK));
|
|
}
|
|
else
|
|
{
|
|
// Raid-7639: OE sends message over and over when runs out of disk space.
|
|
m_pOutbox->SetMessageFlags(&rList, &Flags, NULL, NOSTORECALLBACK);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(rList.prgidMsg);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::_UpdateSendMessageProgress
|
|
// --------------------------------------------------------------------------------
|
|
void CHTTPTask::_UpdateSendMessageProgress(LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
// the transport is attempting to resend the stream..
|
|
// reset our progress indicator
|
|
if (pResponse->rSendMessageInfo.fResend)
|
|
{
|
|
m_cbSent = m_cbStart;
|
|
}
|
|
else
|
|
{
|
|
// Increment Status
|
|
m_cbSent += pResponse->rSendMessageInfo.cbIncrement;
|
|
}
|
|
|
|
// Do Progress
|
|
_DoProgress();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPTask::_DoProgress
|
|
// --------------------------------------------------------------------------------
|
|
void CHTTPTask::_DoProgress(void)
|
|
{
|
|
// Locals
|
|
WORD wProgress = 0;
|
|
WORD wDelta;
|
|
|
|
// Invalid Arg
|
|
Assert(m_cbTotal > 0 && m_pUI);
|
|
|
|
if (m_cbSent > 0)
|
|
{
|
|
// Compute Current Progress Index
|
|
wProgress = (WORD)((m_cbSent * 100) / m_cbTotal);
|
|
|
|
// Compute Delta
|
|
wDelta = wProgress - m_wProgress;
|
|
|
|
// Progress Delta
|
|
if (wDelta > 0)
|
|
{
|
|
// Incremenet Progress
|
|
m_pUI->IncrementProgress(wDelta);
|
|
|
|
// Increment my wProgress
|
|
m_wProgress += wDelta;
|
|
|
|
// Don't go over 100 percent
|
|
Assert(m_wProgress <= 100);
|
|
}
|
|
}
|
|
else if (m_wProgress != 0)
|
|
{
|
|
m_pUI->SetProgressPosition(0);
|
|
m_wProgress = 0;
|
|
}
|
|
}
|