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.
2207 lines
63 KiB
2207 lines
63 KiB
// --------------------------------------------------------------------------------
|
|
// Smtptask.cpp
|
|
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
|
|
// Steven J. Bailey
|
|
// --------------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "smtptask.h"
|
|
#include "mimeutil.h"
|
|
#include "goptions.h"
|
|
#include "strconst.h"
|
|
#include "xputil.h"
|
|
#include "resource.h"
|
|
#include "shlwapip.h"
|
|
#include "spoolui.h"
|
|
#include "thormsgs.h"
|
|
#include "flagconv.h"
|
|
#include "ourguid.h"
|
|
#include "msgfldr.h"
|
|
#include "storecb.h"
|
|
#include "demand.h"
|
|
#include "taskutil.h"
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Data Types
|
|
// --------------------------------------------------------------------------------
|
|
typedef enum tagSMTPEVENTTYPE
|
|
{
|
|
EVENT_SMTP,
|
|
EVENT_IMAPUPLOAD
|
|
} SMTPEVENTTYPE;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CURRENTSMTPEVENT
|
|
// --------------------------------------------------------------------------------
|
|
#define CURRENTSMTPEVENT(_rTable) (&_rTable.prgEvent[_rTable.iEvent])
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageIdStream::CMessageIdStream
|
|
// --------------------------------------------------------------------------------
|
|
CMessageIdStream::CMessageIdStream(IStream *pStream) : m_pStream(pStream)
|
|
{
|
|
// Reference count
|
|
m_cRef = 1;
|
|
|
|
// Addref the source stream
|
|
m_pStream->AddRef();
|
|
|
|
// Format the string
|
|
ULONG cchPrefix = wnsprintf(m_szMessageId, ARRAYSIZE(m_szMessageId), "%s: ", STR_HDR_MESSAGEID);
|
|
|
|
// Generate a message Id
|
|
if (FAILED(MimeOleGenerateMID(m_szMessageId + cchPrefix, sizeof(m_szMessageId) - cchPrefix, FALSE)))
|
|
{
|
|
Assert(FALSE);
|
|
*m_szMessageId = '\0';
|
|
m_cchMessageId = 0;
|
|
}
|
|
|
|
// Otherwise, fixup the message id so that <mid>\r\n
|
|
else
|
|
{
|
|
StrCatBuff(m_szMessageId, "\r\n", ARRAYSIZE(m_szMessageId));
|
|
m_cchMessageId = lstrlen(m_szMessageId);
|
|
}
|
|
|
|
// Iniailize Index
|
|
m_cbIndex = 0;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageIdStream::Seek
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageIdStream::Seek(LARGE_INTEGER liMove, DWORD dwOrigin, ULARGE_INTEGER *pulNew)
|
|
{
|
|
// Only supported case
|
|
if (STREAM_SEEK_SET != dwOrigin && 0 != liMove.LowPart && 0 != liMove.HighPart && 0 != m_cbIndex)
|
|
{
|
|
Assert(FALSE);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// Otheriwse, set new position
|
|
else if (pulNew)
|
|
{
|
|
pulNew->HighPart = 0;
|
|
pulNew->LowPart = 0;
|
|
}
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageIdStream::Read
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageIdStream::Read(LPVOID pv, ULONG cbWanted, ULONG *pcbRead)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Reading from m_szMessageId ?
|
|
if (m_cbIndex < m_cchMessageId)
|
|
{
|
|
// Compute amount I can read from m_cchMessageId
|
|
ULONG cbReadMsgId = min(m_cchMessageId - m_cbIndex, cbWanted);
|
|
|
|
// Init pcbRead
|
|
if (pcbRead)
|
|
*pcbRead = 0;
|
|
|
|
// If we have some ?
|
|
if (cbReadMsgId)
|
|
{
|
|
// Copy memory
|
|
CopyMemory(pv, m_szMessageId + m_cbIndex, cbReadMsgId);
|
|
|
|
// Increment index
|
|
m_cbIndex += cbReadMsgId;
|
|
}
|
|
|
|
// If there is still some left to read...
|
|
if (cbReadMsgId < cbWanted)
|
|
hr = m_pStream->Read(((LPBYTE)pv + cbReadMsgId), cbWanted - cbReadMsgId, pcbRead);
|
|
|
|
// Fixup pcbRead
|
|
if (pcbRead)
|
|
(*pcbRead) += cbReadMsgId;
|
|
}
|
|
|
|
// Otherwise, read from source stream
|
|
else
|
|
hr = m_pStream->Read(pv, cbWanted, pcbRead);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::CSmtpTask
|
|
// --------------------------------------------------------------------------------
|
|
CSmtpTask::CSmtpTask(void)
|
|
{
|
|
m_cRef = 1;
|
|
m_dwFlags = 0;
|
|
m_pSpoolCtx = NULL;
|
|
m_pAccount = NULL;
|
|
m_pTransport = NULL;
|
|
m_pOutbox = NULL;
|
|
m_pSentItems = NULL;
|
|
m_cbTotal = 0;
|
|
m_cbSent = 0;
|
|
m_wProgress = 0;
|
|
m_idEvent = INVALID_EVENT;
|
|
m_idEventUpload = INVALID_EVENT;
|
|
m_pUI = NULL;
|
|
m_dwState = 0;
|
|
m_pAdrEnum = NULL;
|
|
m_hwndTimeout = NULL;
|
|
m_pLogFile = NULL;
|
|
ZeroMemory(&m_rServer, sizeof(INETSERVER));
|
|
ZeroMemory(&m_rTable, sizeof(SMTPEVENTTABLE));
|
|
ZeroMemory(&m_rList, sizeof(MESSAGEIDLIST));
|
|
m_pCancel = NULL;
|
|
m_tyOperation = SOT_INVALID;
|
|
InitializeCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::~CSmtpTask
|
|
// --------------------------------------------------------------------------------
|
|
CSmtpTask::~CSmtpTask(void)
|
|
{
|
|
// Reset the Object
|
|
_ResetObject(TRUE);
|
|
|
|
// Kill the critical section
|
|
DeleteCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_ResetObject
|
|
// --------------------------------------------------------------------------------
|
|
void CSmtpTask::_ResetObject(BOOL fDeconstruct)
|
|
{
|
|
// Make sure the transport is disconnect
|
|
if (m_pTransport)
|
|
{
|
|
m_pTransport->Release();
|
|
m_pTransport = NULL;
|
|
}
|
|
|
|
// Release the Outbox
|
|
SafeRelease(m_pAccount);
|
|
SafeRelease(m_pOutbox);
|
|
SafeRelease(m_pSentItems);
|
|
SafeRelease(m_pAdrEnum);
|
|
SafeRelease(m_pSpoolCtx);
|
|
SafeRelease(m_pUI);
|
|
SafeRelease(m_pLogFile);
|
|
SafeRelease(m_pCancel);
|
|
SafeMemFree(m_rList.prgidMsg);
|
|
ZeroMemory(&m_rList, sizeof(MESSAGEIDLIST));
|
|
|
|
// Free the event table elements
|
|
_FreeEventTableElements();
|
|
|
|
// Deconstructing
|
|
if (fDeconstruct)
|
|
{
|
|
// Free Event Table
|
|
SafeMemFree(m_rTable.prgEvent);
|
|
}
|
|
|
|
// Otherwise, reset some vars
|
|
else
|
|
{
|
|
// Reset total byte count
|
|
m_cbTotal = 0;
|
|
m_idEvent = INVALID_EVENT;
|
|
m_cbSent = 0;
|
|
m_wProgress = 0;
|
|
ZeroMemory(&m_rServer, sizeof(INETSERVER));
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::Init
|
|
// --------------------------------------------------------------------------------
|
|
void CSmtpTask::_FreeEventTableElements(void)
|
|
{
|
|
// Loop the table of events
|
|
for (ULONG i=0; i<m_rTable.cEvents; i++)
|
|
{
|
|
// Release the Message
|
|
SafeRelease(m_rTable.prgEvent[i].pMessage);
|
|
}
|
|
|
|
// No Events
|
|
m_rTable.cEvents = 0;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::QueryInterface
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CSmtpTask::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 if (IID_ITimeoutCallback == riid)
|
|
*ppv = (ITimeoutCallback *) this;
|
|
else if (IID_ITransportCallbackService == riid)
|
|
*ppv = (ITransportCallbackService *) this;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
hr = TrapError(E_NOINTERFACE);
|
|
goto exit;
|
|
}
|
|
|
|
// AddRef It
|
|
((IUnknown *)*ppv)->AddRef();
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::CSmtpTask
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CSmtpTask::AddRef(void)
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
ULONG cRef = ++m_cRef;
|
|
LeaveCriticalSection(&m_cs);
|
|
return cRef;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::CSmtpTask
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CSmtpTask::Release(void)
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
ULONG cRef = --m_cRef;
|
|
LeaveCriticalSection(&m_cs);
|
|
if (0 != cRef)
|
|
return cRef;
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::Init
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CSmtpTask::Init(DWORD dwFlags, ISpoolerBindContext *pBindCtx)
|
|
{
|
|
// Invalid Arg
|
|
if (NULL == pBindCtx)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Reset this object
|
|
_ResetObject(FALSE);
|
|
|
|
// 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;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::BuildEvents
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CSmtpTask::BuildEvents(ISpoolerUI *pSpoolerUI, IImnAccount *pAccount, FOLDERID idFolder)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD fSplitMsgs;
|
|
FOLDERINFO Folder;
|
|
FOLDERID id;
|
|
DWORD cbMaxPart;
|
|
CHAR szRes[255];
|
|
CHAR szMessage[255];
|
|
CHAR szAccount[CCHMAX_ACCOUNT_NAME];
|
|
CHAR szDefault[CCHMAX_ACCOUNT_NAME];
|
|
MESSAGEINFO MsgInfo={0};
|
|
HROWSET hRowset=NULL;
|
|
|
|
// Invalid Arg
|
|
if (NULL == pSpoolerUI || NULL == pAccount)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Validate State
|
|
Assert(NULL == m_pTransport && NULL == m_pAccount && NULL == m_pOutbox && 0 == m_rTable.cEvents);
|
|
Assert(NULL == m_pSentItems);
|
|
|
|
// Save the UI Object
|
|
m_pUI = pSpoolerUI;
|
|
m_pUI->AddRef();
|
|
|
|
// Release current Account
|
|
m_pAccount = pAccount;
|
|
m_pAccount->AddRef();
|
|
|
|
// Get the Account Name
|
|
CHECKHR(hr = m_pAccount->GetPropSz(AP_ACCOUNT_NAME, szAccount, ARRAYSIZE(szAccount)));
|
|
|
|
// Split Messages ?
|
|
if (FAILED(m_pAccount->GetPropDw(AP_SMTP_SPLIT_MESSAGES, &fSplitMsgs)))
|
|
fSplitMsgs = FALSE;
|
|
|
|
// Split Size
|
|
if (FAILED(m_pAccount->GetPropDw(AP_SMTP_SPLIT_SIZE, &cbMaxPart)))
|
|
{
|
|
fSplitMsgs = FALSE;
|
|
cbMaxPart = 0;
|
|
}
|
|
|
|
// Else, convert cbMaxPart for kilobytes to bytes
|
|
else
|
|
cbMaxPart *= 1024;
|
|
|
|
// Get the default Account
|
|
if (SUCCEEDED(g_pAcctMan->GetDefaultAccountName(ACCT_MAIL, szDefault, ARRAYSIZE(szDefault))))
|
|
{
|
|
if (lstrcmpi(szDefault, szAccount) == 0)
|
|
FLAGSET(m_dwState, SMTPSTATE_DEFAULT);
|
|
}
|
|
|
|
// Get the outbox
|
|
CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreOutbox, (LPVOID *)&m_pOutbox));
|
|
|
|
// Create a Rowset
|
|
CHECKHR(hr = m_pOutbox->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset));
|
|
|
|
// Loop
|
|
while (S_OK == m_pOutbox->QueryRowset(hRowset, 1, (LPVOID *)&MsgInfo, NULL))
|
|
{
|
|
// Process Store Header
|
|
CHECKHR(hr = _HrAppendOutboxMessage(szAccount, &MsgInfo, fSplitMsgs, cbMaxPart));
|
|
|
|
// Free Current
|
|
m_pOutbox->FreeRecord(&MsgInfo);
|
|
}
|
|
|
|
// If no messages, were done
|
|
if (0 == m_rTable.cEvents)
|
|
goto exit;
|
|
|
|
// Get a SMTP log file
|
|
m_pSpoolCtx->BindToObject(IID_CSmtpLogFile, (LPVOID *)&m_pLogFile);
|
|
|
|
// Format the string
|
|
LOADSTRING(IDS_SPS_SMTPEVENT, szRes);
|
|
|
|
// Build the message
|
|
wnsprintf(szMessage, ARRAYSIZE(szMessage), szRes, m_rTable.cEvents, szAccount);
|
|
|
|
// Register the event
|
|
CHECKHR(hr = m_pSpoolCtx->RegisterEvent(szMessage, (ISpoolerTask *)this, EVENT_SMTP, m_pAccount, &m_idEvent));
|
|
|
|
// Get SentItems
|
|
if (DwGetOption(OPT_SAVESENTMSGS))
|
|
{
|
|
// Get Sent Items Folder
|
|
CHECKHR(hr = TaskUtil_OpenSentItemsFolder(m_pAccount, &m_pSentItems));
|
|
|
|
// Get the Folder Id
|
|
m_pSentItems->GetFolderId(&id);
|
|
|
|
// Get the folder information
|
|
CHECKHR(hr = g_pStore->GetFolderInfo(id, &Folder));
|
|
|
|
// If not a local folder, then we will need to do an upload
|
|
if (Folder.tyFolder != FOLDER_LOCAL)
|
|
{
|
|
// Get event string
|
|
LOADSTRING(IDS_SPS_MOVEEVENT, szRes);
|
|
|
|
// Format the message
|
|
wnsprintf(szMessage, ARRAYSIZE(szMessage), szRes, szAccount);
|
|
|
|
// Register Upload Event
|
|
CHECKHR(hr = m_pSpoolCtx->RegisterEvent(szMessage, (ISpoolerTask *)this, EVENT_IMAPUPLOAD, m_pAccount, &m_idEventUpload));
|
|
}
|
|
|
|
// Free the Record
|
|
g_pStore->FreeRecord(&Folder);
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
if (m_pOutbox)
|
|
{
|
|
m_pOutbox->CloseRowset(&hRowset);
|
|
m_pOutbox->FreeRecord(&MsgInfo);
|
|
}
|
|
|
|
// Failure
|
|
if (FAILED(hr))
|
|
{
|
|
_CatchResult(hr, IXP_SMTP);
|
|
_ResetObject(FALSE);
|
|
}
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_HrAppendEventTable
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CSmtpTask::_HrAppendEventTable(LPSMTPEVENTINFO *ppEvent)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Add an item to the event list
|
|
if (m_rTable.cEvents + 1 > m_rTable.cAlloc)
|
|
{
|
|
// Realloc the table
|
|
CHECKHR(hr = HrRealloc((LPVOID *)&m_rTable.prgEvent, sizeof(SMTPEVENTINFO) * (m_rTable.cAlloc + 10)));
|
|
|
|
// Increment cAlloc
|
|
m_rTable.cAlloc += 10;
|
|
}
|
|
|
|
// Readability
|
|
*ppEvent = &m_rTable.prgEvent[m_rTable.cEvents];
|
|
|
|
// ZeroInit
|
|
ZeroMemory(*ppEvent, sizeof(SMTPEVENTINFO));
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_HrAppendOutboxMessage
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CSmtpTask::_HrAppendOutboxMessage(LPCSTR pszAccount, LPMESSAGEINFO pMsgInfo,
|
|
BOOL fSplitMsgs, DWORD cbMaxPart)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPSMTPEVENTINFO pEvent;
|
|
IImnAccount *pAccount=NULL;
|
|
|
|
// Invalid Arg
|
|
Assert(pszAccount && pMsgInfo);
|
|
|
|
// Has this message been submitted and is it a mail message
|
|
if((pMsgInfo->dwFlags & (ARF_SUBMITTED | ARF_NEWSMSG)) != ARF_SUBMITTED)
|
|
goto exit;
|
|
|
|
// Empty Account Name
|
|
if (NULL == pMsgInfo->pszAcctId || FAILED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pMsgInfo->pszAcctId, &pAccount)))
|
|
{
|
|
// Not the Default Account
|
|
if (!ISFLAGSET(m_dwState, SMTPSTATE_DEFAULT) || ISFLAGSET(m_dwFlags, DELIVER_NOUI))
|
|
goto exit;
|
|
|
|
// Have I asked the user if they want to use the default account
|
|
if (!ISFLAGSET(m_dwState, SMTPSTATE_ASKEDDEFAULT))
|
|
{
|
|
// Get hwndParent
|
|
HWND hwndParent;
|
|
if (FAILED(m_pUI->GetWindow(&hwndParent)))
|
|
hwndParent = NULL;
|
|
|
|
// Message
|
|
if (AthMessageBoxW(hwndParent, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(IDS_SPS_SMTPUSEDEFAULT), NULL, MB_YESNO|MB_ICONEXCLAMATION ) == IDYES)
|
|
FLAGSET(m_dwState, SMTPSTATE_USEDEFAULT);
|
|
else
|
|
goto exit;
|
|
|
|
// I've Asked, don't ask again
|
|
FLAGSET(m_dwState, SMTPSTATE_ASKEDDEFAULT);
|
|
}
|
|
|
|
// Not using default
|
|
else if (!ISFLAGSET(m_dwState, SMTPSTATE_USEDEFAULT))
|
|
goto exit;
|
|
}
|
|
|
|
// Use this account
|
|
else if (lstrcmpi(pMsgInfo->pszAcctName, pszAccount) != 0)
|
|
goto exit;
|
|
|
|
// Split the Message ?
|
|
if (TRUE == fSplitMsgs && pMsgInfo->cbMessage >= cbMaxPart)
|
|
{
|
|
// Make sure the total number of messages is less than 100
|
|
if (100 <= (pMsgInfo->cbMessage / cbMaxPart))
|
|
{
|
|
HWND hwndParent;
|
|
CHAR rgchBuff[CCHMAX_STRINGRES + 20];
|
|
CHAR rgchRes[CCHMAX_STRINGRES];
|
|
DWORD cbMaxPartCount;
|
|
|
|
// Figure out the new message part size
|
|
cbMaxPartCount = pMsgInfo->cbMessage / 100;
|
|
|
|
// Round the new message part size to the
|
|
// closest power of 2
|
|
if (0x80000000 <= cbMaxPartCount)
|
|
{
|
|
// Can't round up any higher
|
|
cbMaxPart = cbMaxPartCount;
|
|
}
|
|
else
|
|
{
|
|
cbMaxPart = 1;
|
|
do
|
|
{
|
|
cbMaxPart *= 2;
|
|
} while ( 0 != (cbMaxPartCount /= 2));
|
|
}
|
|
|
|
// Get the UI window
|
|
if (FAILED(m_pUI->GetWindow(&hwndParent)))
|
|
hwndParent = NULL;
|
|
|
|
if (NULL == AthLoadString(idsErrTooManySplitMsgs, rgchRes, sizeof(rgchRes)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
// Display the warning string
|
|
wnsprintf(rgchBuff, ARRAYSIZE(rgchBuff), rgchRes, cbMaxPart / 1024);
|
|
if (AthMessageBox(hwndParent, MAKEINTRESOURCE(idsAthenaMail), rgchBuff, NULL, MB_YESNO|MB_ICONEXCLAMATION ) != IDYES)
|
|
goto exit;
|
|
}
|
|
|
|
// Split and Add the message
|
|
CHECKHR(hr = _HrAppendSplitMessage(pMsgInfo, cbMaxPart));
|
|
}
|
|
|
|
// Otherwise, simply add the message as normal
|
|
else
|
|
{
|
|
// Append the Table
|
|
CHECKHR(hr = _HrAppendEventTable(&pEvent));
|
|
|
|
// Save the store message id
|
|
pEvent->idMessage = pMsgInfo->idMessage;
|
|
|
|
// Save Message Size + 100 which is the average MID that is added on
|
|
pEvent->cbEvent = pMsgInfo->cbMessage;
|
|
|
|
// Increment total send byte count
|
|
m_cbTotal += pEvent->cbEvent;
|
|
|
|
// Running Sent Total
|
|
pEvent->cbSentTotal = m_cbTotal;
|
|
|
|
// Increment Number of event
|
|
m_rTable.cEvents++;
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pAccount);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_HrAppendSplitMessage
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CSmtpTask::_HrAppendSplitMessage(LPMESSAGEINFO pMsgInfo, DWORD cbMaxPart)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG c;
|
|
ULONG iPart=1;
|
|
ULONG cParts;
|
|
IMimeMessage *pMessage=NULL;
|
|
IMimeMessage *pMsgPart=NULL;
|
|
IMimeMessageParts *pParts=NULL;
|
|
IMimeEnumMessageParts *pEnum=NULL;
|
|
LPSMTPEVENTINFO pEvent;
|
|
|
|
// Invalid Arg
|
|
Assert(pMsgInfo);
|
|
|
|
// Lets open the message from the Outbox
|
|
CHECKHR(hr = _HrOpenMessage(pMsgInfo->idMessage, &pMessage));
|
|
|
|
// Split the message
|
|
CHECKHR(hr = pMessage->SplitMessage(cbMaxPart, &pParts));
|
|
|
|
// Get Total Parts
|
|
CHECKHR(hr = pParts->CountParts(&cParts));
|
|
|
|
// Walk the list of messages
|
|
CHECKHR(hr = pParts->EnumParts(&pEnum));
|
|
|
|
// Walk the parts and add them into the event list
|
|
while(SUCCEEDED(pEnum->Next(1, &pMsgPart, &c)) && 1 == c)
|
|
{
|
|
// Append the Table
|
|
CHECKHR(hr = _HrAppendEventTable(&pEvent));
|
|
|
|
// Event Type
|
|
FLAGSET(pEvent->dwFlags, SMTPEVENT_SPLITPART);
|
|
|
|
// Split Information
|
|
pEvent->iPart = iPart;
|
|
pEvent->cParts = cParts;
|
|
pEvent->cbParts = pMsgInfo->cbMessage;
|
|
|
|
// Save the message part
|
|
pEvent->pMessage = pMsgPart;
|
|
pMsgPart = NULL;
|
|
|
|
// Save Message Size
|
|
pEvent->pMessage->GetMessageSize(&pEvent->cbEvent, 0);
|
|
|
|
// Increment total send byte count
|
|
m_cbTotal += pEvent->cbEvent;
|
|
|
|
// Running Sent Total
|
|
pEvent->cbSentTotal = m_cbTotal;
|
|
|
|
// Increment Number of event
|
|
m_rTable.cEvents++;
|
|
|
|
// Increment iPart
|
|
iPart++;
|
|
}
|
|
|
|
// Have the last split message free the header info
|
|
pEvent->idMessage = pMsgInfo->idMessage;
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pMessage);
|
|
SafeRelease(pParts);
|
|
SafeRelease(pMsgPart);
|
|
SafeRelease(pEnum);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CSmtpTask::_HrOpenMessage
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CSmtpTask::_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;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::Execute
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CSmtpTask::Execute(EVENTID eid, DWORD_PTR dwTwinkie)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// What is the event type
|
|
if (EVENT_SMTP == dwTwinkie)
|
|
{
|
|
// Better not have a transport yet...
|
|
Assert(NULL == m_pTransport);
|
|
|
|
// Create the Transport Object
|
|
CHECKHR(hr = CreateSMTPTransport(&m_pTransport));
|
|
|
|
// Init the Transport
|
|
CHECKHR(hr = m_pTransport->InitNew(NULL, (ISMTPCallback *)this));
|
|
|
|
// Fill an INETSERVER structure from the account object
|
|
CHECKHR(hr = m_pTransport->InetServerFromAccount(m_pAccount, &m_rServer));
|
|
|
|
// Use IP Address for HELO command ?
|
|
if (DwGetOption(OPT_SMTPUSEIPFORHELO))
|
|
FLAGSET(m_rServer.dwFlags, ISF_SMTP_USEIPFORHELO);
|
|
|
|
// 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) && FAILED(GetPassword(m_rServer.dwPort, m_rServer.szServerName, m_rServer.szUserName, NULL, 0)))
|
|
m_pUI->ShowWindow(SW_SHOW);
|
|
|
|
// Execute SMTP Event
|
|
hr = _ExecuteSMTP(eid, dwTwinkie);
|
|
}
|
|
|
|
// Otherwise, do IMAP Event
|
|
else if (EVENT_IMAPUPLOAD == dwTwinkie)
|
|
hr = _ExecuteUpload(eid, dwTwinkie);
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CSmtpTask::CancelEvent(EVENTID eid, DWORD_PTR dwTwinkie)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_ExecuteSMTP
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CSmtpTask::_ExecuteSMTP(EVENTID eid, DWORD_PTR dwTwinkie)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szRes[CCHMAX_RES];
|
|
CHAR szBuf[CCHMAX_RES + CCHMAX_SERVER_NAME];
|
|
DWORD cb;
|
|
|
|
// I only handle on event
|
|
Assert(m_pAccount && m_idEvent == eid && m_pUI && m_pTransport && m_rTable.cEvents > 0);
|
|
|
|
// 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);
|
|
|
|
// Connect
|
|
CHECKHR(hr = m_pTransport->Connect(&m_rServer, TRUE, TRUE));
|
|
|
|
exit:
|
|
// Failure
|
|
if (FAILED(hr))
|
|
{
|
|
FLAGSET(m_dwState, SMTPSTATE_EXECUTEFAILED);
|
|
_CatchResult(hr, IXP_SMTP);
|
|
|
|
// Hands Off my callback: otherwise we leak like a stuck pig
|
|
SideAssert(m_pTransport->HandsOffCallback() == S_OK);
|
|
}
|
|
|
|
return hr;
|
|
} // _ExecuteSMTP
|
|
|
|
HRESULT CSmtpTask::_ExecuteUpload(EVENTID eid, DWORD_PTR dwTwinkie)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ADJUSTFLAGS Flags;
|
|
|
|
// I only handle on event
|
|
Assert(m_pAccount && m_idEventUpload == eid && m_pUI && m_pTransport && m_rTable.cEvents > 0);
|
|
|
|
// Invalid State
|
|
Assert(m_pOutbox);
|
|
Assert(m_pSentItems != NULL);
|
|
|
|
// Are the Ids
|
|
if (m_rList.cMsgs)
|
|
{
|
|
// Setup Flags
|
|
Flags.dwAdd = ARF_READ;
|
|
Flags.dwRemove = ARF_SUBMITTED | ARF_UNSENT;
|
|
|
|
// Move the message from the sent items folder
|
|
hr = m_pOutbox->CopyMessages(m_pSentItems, COPY_MESSAGE_MOVE, &m_rList, &Flags, NULL, this);
|
|
Assert(FAILED(hr));
|
|
if (hr == E_PENDING)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
IXPTYPE ixpType;
|
|
|
|
FLAGSET(m_dwState, SMTPSTATE_EXECUTEFAILED);
|
|
|
|
// Remap the Error Result
|
|
hr = TrapError(SP_E_CANT_MOVETO_SENTITEMS);
|
|
|
|
// Show an error in the spooler dialog
|
|
ixpType = m_pTransport->GetIXPType();
|
|
_CatchResult(hr, ixpType);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
} // _ExecuteSMTP
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::OnTimeout
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CSmtpTask::OnTimeout(DWORD *pdwTimeout, IInternetTransport *pTransport)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Is there currently a timeout dialog
|
|
if (m_hwndTimeout)
|
|
{
|
|
// Set foreground
|
|
SetForegroundWindow(m_hwndTimeout);
|
|
}
|
|
else
|
|
{
|
|
// Not suppose to be showing UI ?
|
|
if (ISFLAGSET(m_dwFlags, DELIVER_NOUI))
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
// Do Timeout Dialog
|
|
m_hwndTimeout = TaskUtil_HwndOnTimeout(m_rServer.szServerName, m_rServer.szAccount, "SMTP", m_rServer.dwTimeout, (ITimeoutCallback *) this);
|
|
|
|
// Couldn't create the dialog
|
|
if (NULL == m_hwndTimeout)
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Always tell the transport to keep on trucking
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::OnLogonPrompt
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CSmtpTask::OnLogonPrompt(LPINETSERVER pInetServer, IInternetTransport *pTransport)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_FALSE;
|
|
SMTPAUTHTYPE authtype;
|
|
char szPassword[CCHMAX_PASSWORD];
|
|
|
|
// Check if we have a cached password that's different from current password
|
|
hr = GetPassword(pInetServer->dwPort, pInetServer->szServerName, pInetServer->szUserName,
|
|
szPassword, sizeof(szPassword));
|
|
if (SUCCEEDED(hr) && 0 != lstrcmp(szPassword, pInetServer->szPassword))
|
|
{
|
|
StrCpyN(pInetServer->szPassword, szPassword, ARRAYSIZE(pInetServer->szPassword));
|
|
ZeroMemory(szPassword, sizeof(szPassword)); // Done for security.
|
|
return S_OK;
|
|
}
|
|
|
|
hr = S_FALSE; // Re-initialize
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// NOERRORS...
|
|
if (ISFLAGSET(m_dwFlags, DELIVER_NOUI))
|
|
goto exit;
|
|
|
|
// TaskUtil_OnLogonPrompt
|
|
hr = TaskUtil_OnLogonPrompt(m_pAccount, m_pUI, NULL, pInetServer, AP_SMTP_USERNAME,
|
|
AP_SMTP_PASSWORD, AP_SMTP_PROMPT_PASSWORD, FALSE);
|
|
|
|
// Cache the password if the user slected ok
|
|
if (S_OK == hr)
|
|
{
|
|
// Save the password
|
|
SavePassword(pInetServer->dwPort, pInetServer->szServerName,
|
|
pInetServer->szUserName, pInetServer->szPassword);
|
|
|
|
// Lets switch the account to using the logon information...
|
|
authtype = SMTP_AUTH_USE_SMTP_SETTINGS;
|
|
m_pAccount->SetPropDw(AP_SMTP_USE_SICILY, (DWORD)authtype);
|
|
|
|
// Save the changes
|
|
m_pAccount->SaveChanges();
|
|
}
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
ZeroMemory(szPassword, sizeof(szPassword)); // Done for security.
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::OnPrompt
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(INT) CSmtpTask::OnPrompt(HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType, IInternetTransport *pTransport)
|
|
{
|
|
// Locals
|
|
HWND hwnd;
|
|
INT nAnswer;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Raid 55082 - SPOOLER: SPA/SSL auth to NNTP does not display cert warning and fails.
|
|
#if 0
|
|
if (!!(m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)))
|
|
return(0);
|
|
#endif
|
|
|
|
// Invalid State
|
|
Assert(m_pUI);
|
|
|
|
// Get Window
|
|
if (FAILED(m_pUI->GetWindow(&hwnd)))
|
|
hwnd = NULL;
|
|
|
|
// I assume this is a critical prompt, so I will not check for no UI mode
|
|
nAnswer = MessageBox(hwnd, pszText, pszCaption, uType);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return nAnswer;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::OnStatus
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CSmtpTask::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)
|
|
{
|
|
// Kill the timeout dialog
|
|
if (m_hwndTimeout)
|
|
{
|
|
DestroyWindow(m_hwndTimeout);
|
|
m_hwndTimeout = NULL;
|
|
}
|
|
|
|
// _OnDisconnectComplete
|
|
HRESULT hrDisconnect = _OnDisconnectComplete();
|
|
|
|
// Reset the progress
|
|
// m_pUI->SetProgressRange(100);
|
|
|
|
// Set the animation
|
|
m_pUI->SetAnimation(idanOutbox, FALSE);
|
|
|
|
// Determine
|
|
if (ISFLAGSET(m_dwState, SMTPSTATE_CANCELED))
|
|
tyEventStatus = EVENT_CANCELED;
|
|
else if (m_rTable.cCompleted == 0 && m_rTable.cEvents > 0)
|
|
tyEventStatus = EVENT_FAILED;
|
|
else if (m_rTable.cCompleted && m_rTable.cEvents && m_rTable.cCompleted < m_rTable.cEvents)
|
|
tyEventStatus = EVENT_WARNINGS;
|
|
else if (FAILED(hrDisconnect))
|
|
tyEventStatus = EVENT_WARNINGS;
|
|
|
|
// Result
|
|
m_pSpoolCtx->Notify(DELIVERY_NOTIFY_RESULT, tyEventStatus);
|
|
|
|
// Result
|
|
m_pSpoolCtx->Notify(DELIVERY_NOTIFY_COMPLETE, 0);
|
|
|
|
// Hands Off my callback
|
|
if (m_pTransport)
|
|
SideAssert(m_pTransport->HandsOffCallback() == S_OK);
|
|
|
|
// This task is complete
|
|
if (!ISFLAGSET(m_dwState, SMTPSTATE_EXECUTEFAILED))
|
|
m_pSpoolCtx->EventDone(m_idEvent, tyEventStatus);
|
|
}
|
|
|
|
// Authorizing
|
|
else if (ixpstatus == IXP_AUTHORIZING)
|
|
m_pSpoolCtx->Notify(DELIVERY_NOTIFY_AUTHORIZING, 0);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::OnError
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CSmtpTask::OnError(IXPSTATUS ixpstatus, LPIXPRESULT pResult, IInternetTransport *pTransport)
|
|
{
|
|
INETSERVER rServer;
|
|
HRESULT hrResult;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Invalid State
|
|
Assert(m_pUI);
|
|
|
|
// Insert Error Into UI
|
|
if (m_pTransport)
|
|
{
|
|
hrResult = pTransport->GetServerInfo(&rServer);
|
|
if (FAILED(hrResult))
|
|
CopyMemory(&rServer, &m_rServer, sizeof(rServer));
|
|
}
|
|
|
|
_CatchResult(pResult, &rServer, IXP_SMTP);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::OnCommand
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CSmtpTask::OnCommand(CMDTYPE cmdtype, LPSTR pszLine, HRESULT hrResponse, IInternetTransport *pTransport)
|
|
{
|
|
// Logging
|
|
if (m_pLogFile && pszLine)
|
|
{
|
|
// Response
|
|
if (CMD_RESP == cmdtype)
|
|
m_pLogFile->WriteLog(LOGFILE_RX, pszLine);
|
|
|
|
// Send
|
|
else if (CMD_SEND == cmdtype)
|
|
m_pLogFile->WriteLog(LOGFILE_TX, pszLine);
|
|
}
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_CatchResult
|
|
// --------------------------------------------------------------------------------
|
|
TASKRESULTTYPE CSmtpTask::_CatchResult(HRESULT hr, IXPTYPE ixpType)
|
|
{
|
|
// Locals
|
|
IXPRESULT rResult;
|
|
|
|
// Build an IXPRESULT
|
|
ZeroMemory(&rResult, sizeof(IXPRESULT));
|
|
rResult.hrResult = hr;
|
|
|
|
// Get the SMTP Result Type
|
|
return _CatchResult(&rResult, &m_rServer, ixpType);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_CatchResult
|
|
// --------------------------------------------------------------------------------
|
|
TASKRESULTTYPE CSmtpTask::_CatchResult(LPIXPRESULT pResult, INETSERVER *pServer, IXPTYPE ixpType)
|
|
{
|
|
// Locals
|
|
HWND hwndParent;
|
|
TASKRESULTTYPE tyTaskResult=TASKRESULT_FAILURE;
|
|
LPSTR pszSubject=NULL;
|
|
|
|
// If Succeeded
|
|
if (SUCCEEDED(pResult->hrResult))
|
|
return TASKRESULT_SUCCESS;
|
|
|
|
// Is there is a current event, get the subject
|
|
if (m_rTable.prgEvent && m_rTable.prgEvent[m_rTable.iEvent].pMessage)
|
|
{
|
|
// Get the subject
|
|
if (FAILED(MimeOleGetBodyPropA(m_rTable.prgEvent[m_rTable.iEvent].pMessage, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &pszSubject)))
|
|
pszSubject = NULL;
|
|
}
|
|
|
|
// Get Window
|
|
if (NULL == m_pUI || FAILED(m_pUI->GetWindow(&hwndParent)))
|
|
hwndParent = NULL;
|
|
|
|
// Process generic protocol errro
|
|
tyTaskResult = TaskUtil_FBaseTransportError(ixpType, m_idEvent, pResult, pServer, 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)))
|
|
{
|
|
// Roast the current connection
|
|
m_pTransport->DropConnection();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cleanup
|
|
SafeMemFree(pszSubject);
|
|
|
|
// Return Result
|
|
return tyTaskResult;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_DoProgress
|
|
// --------------------------------------------------------------------------------
|
|
void CSmtpTask::_DoProgress(void)
|
|
{
|
|
// Locals
|
|
WORD wProgress;
|
|
WORD wDelta;
|
|
LPSMTPEVENTINFO pEvent;
|
|
|
|
// Invalid Arg
|
|
Assert(m_cbTotal > 0 && m_pUI);
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::OnResponse
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CSmtpTask::OnResponse(LPSMTPRESPONSE pResponse)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
if (pResponse)
|
|
{
|
|
// Handle the Error
|
|
if (TASKRESULT_SUCCESS != _CatchResult(&pResponse->rIxpResult, &m_rServer, IXP_SMTP))
|
|
goto exit;
|
|
|
|
// Handle Command Type
|
|
switch(pResponse->command)
|
|
{
|
|
case SMTP_CONNECTED:
|
|
// CommandRSET
|
|
_CatchResult(_HrOnConnected(), IXP_SMTP);
|
|
|
|
// Done
|
|
break;
|
|
|
|
case SMTP_RSET:
|
|
// Progress
|
|
_DoProgress();
|
|
|
|
// Send the current message
|
|
_CatchResult(_HrStartCurrentEvent(), IXP_SMTP);
|
|
|
|
// Done
|
|
break;
|
|
|
|
case SMTP_MAIL:
|
|
// Reset the address enumerator
|
|
Assert(m_pAdrEnum);
|
|
m_pAdrEnum->Reset();
|
|
|
|
// CommandRCPT
|
|
_CatchResult(_HrCommandRCPT(), IXP_SMTP);
|
|
|
|
// Done
|
|
break;
|
|
|
|
case SMTP_RCPT:
|
|
// CommandRCPT -> CommandDATA
|
|
_CatchResult(_HrCommandRCPT(), IXP_SMTP);
|
|
|
|
// Done
|
|
break;
|
|
|
|
case SMTP_DATA:
|
|
// Send the data stream
|
|
_CatchResult(_HrSendDataStream(), IXP_SMTP);
|
|
|
|
// Done
|
|
break;
|
|
|
|
case SMTP_SEND_STREAM:
|
|
// Increment Current Progress
|
|
_OnStreamProgress(&pResponse->rStreamInfo);
|
|
|
|
// Done
|
|
break;
|
|
|
|
case SMTP_DOT:
|
|
// Finish the Current Event
|
|
_CatchResult(_HrFinishCurrentEvent(S_OK), IXP_SMTP);
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_HrOnConnected
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CSmtpTask::_HrOnConnected(void)
|
|
{
|
|
// Locals
|
|
CHAR szRes[CCHMAX_RES];
|
|
CHAR szMsg[CCHMAX_RES+CCHMAX_RES];
|
|
|
|
// Progress
|
|
LOADSTRING(IDS_SPS_SMTPPROGGEN, szRes);
|
|
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rServer.szAccount);
|
|
|
|
// Set General Progress
|
|
m_pUI->SetGeneralProgress(szMsg);
|
|
|
|
// Progress
|
|
_DoProgress();
|
|
|
|
// Notify
|
|
m_pSpoolCtx->Notify(DELIVERY_NOTIFY_SENDING, 0);
|
|
|
|
// Send the current message
|
|
_CatchResult(_HrStartCurrentEvent(), IXP_SMTP);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_HrStartCurrentEvent
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CSmtpTask::_HrStartCurrentEvent(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPSMTPEVENTINFO pEvent;
|
|
IMimeAddressTable *pAddrTable=NULL;
|
|
CHAR szRes[CCHMAX_RES];
|
|
CHAR szMsg[CCHMAX_RES + CCHMAX_ACCOUNT_NAME];
|
|
|
|
// Invalid Arg
|
|
Assert(m_rTable.iEvent < m_rTable.cEvents);
|
|
|
|
// Get the current event
|
|
pEvent = CURRENTSMTPEVENT(m_rTable);
|
|
|
|
// Is this a partial message
|
|
if (ISFLAGSET(pEvent->dwFlags, SMTPEVENT_SPLITPART))
|
|
{
|
|
LOADSTRING(IDS_SPS_SMTPPROGRESS_SPLIT, szRes);
|
|
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rTable.iEvent + 1, m_rTable.cEvents, pEvent->iPart, pEvent->cParts);
|
|
}
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
LOADSTRING(IDS_SPS_SMTPPROGRESS, szRes);
|
|
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rTable.iEvent + 1, m_rTable.cEvents);
|
|
}
|
|
|
|
// Set Specific Progress
|
|
m_pUI->SetSpecificProgress(szMsg);
|
|
|
|
// If mail is coming from the outbox
|
|
if (!ISFLAGSET(pEvent->dwFlags, SMTPEVENT_SPLITPART))
|
|
{
|
|
// Open Store Message
|
|
if (FAILED(_HrOpenMessage(pEvent->idMessage, &pEvent->pMessage)))
|
|
{
|
|
hr = TrapError(SP_E_SMTP_CANTOPENMESSAGE);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// We better have a message object at this point
|
|
else if (NULL == pEvent->pMessage)
|
|
{
|
|
Assert(FALSE);
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Catch Result
|
|
CHECKHR(hr = _HrCommandMAIL());
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pAddrTable);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CSmtpTask::_HrCommandMAIL
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CSmtpTask::_HrCommandMAIL(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
HRESULT hrFind;
|
|
IMimeAddressTable *pAdrTable=NULL;
|
|
ADDRESSPROPS rAddress;
|
|
ULONG c;
|
|
LPSMTPEVENTINFO pEvent;
|
|
|
|
// Get the current smtp event
|
|
pEvent = CURRENTSMTPEVENT(m_rTable);
|
|
|
|
// Init
|
|
ZeroMemory(&rAddress, sizeof(ADDRESSPROPS));
|
|
|
|
// Check State
|
|
Assert(m_pTransport && pEvent->pMessage);
|
|
|
|
// Release Current Enumerator
|
|
SafeRelease(m_pAdrEnum);
|
|
|
|
// Get the Sender...
|
|
CHECKHR(hr = pEvent->pMessage->GetAddressTable(&pAdrTable));
|
|
|
|
// Get Enumerator
|
|
CHECKHR(hr = pAdrTable->EnumTypes(IAT_KNOWN, IAP_ADRTYPE | IAP_EMAIL, &m_pAdrEnum));
|
|
|
|
// Loop Enumerator
|
|
while (SUCCEEDED(m_pAdrEnum->Next(1, &rAddress, &c)) && c == 1)
|
|
{
|
|
// Not IAT_FROM
|
|
if (NULL == rAddress.pszEmail || IAT_FROM != rAddress.dwAdrType)
|
|
{
|
|
g_pMoleAlloc->FreeAddressProps(&rAddress);
|
|
continue;
|
|
}
|
|
|
|
// Send the command
|
|
CHECKHR(hr = m_pTransport->CommandMAIL(rAddress.pszEmail));
|
|
|
|
// Done
|
|
goto exit;
|
|
}
|
|
|
|
// No Sender
|
|
hr = TrapError(IXP_E_SMTP_NO_SENDER);
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pAdrTable);
|
|
g_pMoleAlloc->FreeAddressProps(&rAddress);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CSmtpTask::_HrCommandRCPT
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CSmtpTask::_HrCommandRCPT(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD dwAdrType;
|
|
DWORD c;
|
|
LPSTR pszEmail=NULL;
|
|
ADDRESSPROPS rAddress;
|
|
LPSMTPEVENTINFO pEvent;
|
|
|
|
// Get the current smtp event
|
|
pEvent = CURRENTSMTPEVENT(m_rTable);
|
|
|
|
// Init
|
|
ZeroMemory(&rAddress, sizeof(ADDRESSPROPS));
|
|
|
|
// Check State
|
|
Assert(m_pAdrEnum && m_pTransport && pEvent->pMessage);
|
|
|
|
// Walk the enumerator for the next recipient
|
|
while (SUCCEEDED(m_pAdrEnum->Next(1, &rAddress, &c)) && c == 1)
|
|
{
|
|
// Get Type
|
|
if (rAddress.pszEmail && ISFLAGSET(IAT_RECIPS, rAddress.dwAdrType))
|
|
{
|
|
// Send the command
|
|
CHECKHR(hr = m_pTransport->CommandRCPT(rAddress.pszEmail));
|
|
|
|
// Count Recipients
|
|
pEvent->cRecipients++;
|
|
|
|
// Done
|
|
goto exit;
|
|
}
|
|
|
|
// Release
|
|
g_pMoleAlloc->FreeAddressProps(&rAddress);
|
|
}
|
|
|
|
// Release the Enumerator
|
|
SafeRelease(m_pAdrEnum);
|
|
|
|
// No Recipients
|
|
if (0 == pEvent->cRecipients)
|
|
{
|
|
hr = TrapError(IXP_E_SMTP_NO_RECIPIENTS);
|
|
goto exit;
|
|
}
|
|
|
|
// Send the Data Command
|
|
CHECKHR(hr = m_pTransport->CommandDATA());
|
|
|
|
exit:
|
|
// Cleanup
|
|
g_pMoleAlloc->FreeAddressProps(&rAddress);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_HrSendDataStream
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CSmtpTask::_HrSendDataStream(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPSTREAM pStream=NULL;
|
|
LPSTREAM pStmActual;
|
|
LPSTR pszBCC=NULL;
|
|
LPSTR pszTo=NULL;
|
|
LPSTR pszMessageId=NULL;
|
|
LPSMTPEVENTINFO pEvent;
|
|
CMessageIdStream *pStmWrapper=NULL;
|
|
|
|
// Get the current smtp event
|
|
pEvent = CURRENTSMTPEVENT(m_rTable);
|
|
|
|
// Check State
|
|
Assert(m_pTransport && pEvent->pMessage);
|
|
|
|
// See if BCC is set
|
|
if (SUCCEEDED(MimeOleGetBodyPropA(pEvent->pMessage, HBODY_ROOT, PIDTOSTR(PID_HDR_BCC), NOFLAGS, &pszBCC)))
|
|
{
|
|
// Locals
|
|
LPSTR pszToAppend=NULL;
|
|
|
|
// RAID-20750 - If the to line is not set, then we will set it to "Undisclosed Recipient"
|
|
// or the SMTP gateways will put the BCC into the to line.
|
|
if (FAILED(MimeOleGetBodyPropA(pEvent->pMessage, HBODY_ROOT, PIDTOSTR(PID_HDR_TO), NOFLAGS, &pszTo)))
|
|
{
|
|
// Raid-9691: We were just putting <Undiscolsed Recipient>, which was an illegal email address (bad for Exchange Server)
|
|
pszToAppend = "To: <Undisclosed-Recipient:;>\r\n";
|
|
}
|
|
|
|
// Raid-2705: If this fails, just get the message source
|
|
if (FAILED(MimeOleStripHeaders(pEvent->pMessage, HBODY_ROOT, STR_HDR_BCC, pszToAppend, &pStream)))
|
|
{
|
|
// Get Message Stream
|
|
CHECKHR(hr = pEvent->pMessage->GetMessageSource(&pStream, 0));
|
|
}
|
|
}
|
|
|
|
// Otherwise, just get the message source
|
|
else
|
|
{
|
|
// Get Message Stream
|
|
CHECKHR(hr = pEvent->pMessage->GetMessageSource(&pStream, 0));
|
|
}
|
|
|
|
// Lets see if the message has a message-id already
|
|
if (FAILED(MimeOleGetBodyPropA(pEvent->pMessage, HBODY_ROOT, PIDTOSTR(PID_HDR_MESSAGEID), NOFLAGS, &pszMessageId)))
|
|
{
|
|
// Create a wrapper for this stream that will output the messageid
|
|
CHECKALLOC(pStmWrapper = new CMessageIdStream(pStream));
|
|
|
|
// Adjust pEvent->cbEvent
|
|
pEvent->cbEvent += pStmWrapper->CchMessageId();
|
|
|
|
// Increment total
|
|
m_cbTotal += pStmWrapper->CchMessageId();
|
|
|
|
// Increment pEvent->cbSentTotal
|
|
pEvent->cbSentTotal += pStmWrapper->CchMessageId();
|
|
|
|
// Reset pStream
|
|
pStmActual = (IStream *)pStmWrapper;
|
|
}
|
|
else
|
|
pStmActual = pStream;
|
|
|
|
// Send the stream
|
|
CHECKHR(hr = m_pTransport->SendDataStream(pStmActual, pEvent->cbEvent));
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pStream);
|
|
SafeRelease(pStmWrapper);
|
|
SafeMemFree(pszBCC);
|
|
SafeMemFree(pszTo);
|
|
SafeMemFree(pszMessageId);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_OnStreamProgress
|
|
// --------------------------------------------------------------------------------
|
|
void CSmtpTask::_OnStreamProgress(LPSMTPSTREAM pInfo)
|
|
{
|
|
// Locals
|
|
LPSMTPEVENTINFO pEvent;
|
|
|
|
// Get the current smtp event
|
|
pEvent = CURRENTSMTPEVENT(m_rTable);
|
|
|
|
// Increment Status
|
|
pEvent->cbEventSent += pInfo->cbIncrement;
|
|
Assert(pEvent->cbEventSent == pInfo->cbCurrent);
|
|
|
|
// Increment total sent
|
|
m_cbSent += pInfo->cbIncrement;
|
|
|
|
// Do Progress
|
|
_DoProgress();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_HrFinishCurrentEvent
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CSmtpTask::_HrFinishCurrentEvent(HRESULT hrResult)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPSMTPEVENTINFO pEvent;
|
|
|
|
// Get the current smtp event
|
|
pEvent = CURRENTSMTPEVENT(m_rTable);
|
|
|
|
// Save the Event Result
|
|
pEvent->hrResult = hrResult;
|
|
|
|
// If the Event Failed...
|
|
if (FAILED(pEvent->hrResult))
|
|
{
|
|
// If this message was part of a split group, skip all pars in this group
|
|
if (ISFLAGSET(pEvent->dwFlags, SMTPEVENT_SPLITPART))
|
|
{
|
|
// Compute Next Event
|
|
ULONG iNextEvent = m_rTable.iEvent + (pEvent->cParts - pEvent->iPart) + 1;
|
|
|
|
// Increment to last part
|
|
while(m_rTable.iEvent < iNextEvent && m_rTable.iEvent < m_rTable.cEvents)
|
|
{
|
|
// Goto next event
|
|
m_rTable.iEvent++;
|
|
|
|
// Fail this event
|
|
_CatchResult(SP_E_SENDINGSPLITGROUP, IXP_SMTP);
|
|
|
|
// Fixup m_cbSent to be correct
|
|
m_cbSent = m_rTable.prgEvent[m_rTable.iEvent].cbSentTotal;
|
|
|
|
// Update progress
|
|
_DoProgress();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
// Mark the event as complete
|
|
FLAGSET(pEvent->dwFlags, SMTPEVENT_COMPLETE);
|
|
|
|
// Increment number of completed events
|
|
m_rTable.cCompleted++;
|
|
}
|
|
|
|
// Go to next message
|
|
CHECKHR(hr = _HrStartNextEvent());
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_HrStartNextEvent
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CSmtpTask::_HrStartNextEvent(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Fixup m_cbSent to be correct
|
|
m_cbSent = m_rTable.prgEvent[m_rTable.iEvent].cbSentTotal;
|
|
|
|
// Are we done yet ?
|
|
if (m_rTable.iEvent + 1 == m_rTable.cEvents)
|
|
{
|
|
// Update progress
|
|
_DoProgress();
|
|
|
|
// Disconnect from the server
|
|
CHECKHR(hr = m_pTransport->Disconnect());
|
|
}
|
|
|
|
// Oterhwise, Increment Event and send rset
|
|
else
|
|
{
|
|
// Next Event
|
|
m_rTable.iEvent++;
|
|
|
|
// Update progress
|
|
_DoProgress();
|
|
|
|
// Send Reset Command
|
|
CHECKHR(hr = m_pTransport->CommandRSET());
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::_OnDisconnectComplete
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CSmtpTask::_OnDisconnectComplete(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
PDWORD_PTR prgdwIds=NULL;
|
|
DWORD cIds=0;
|
|
DWORD cIdsAlloc=0;
|
|
DWORD i;
|
|
LPSMTPEVENTINFO pEvent;
|
|
ADJUSTFLAGS Flags;
|
|
|
|
// Invalid State
|
|
Assert(m_pOutbox);
|
|
|
|
// Walk through the list of events
|
|
for (i=0; i<m_rTable.cEvents; i++)
|
|
{
|
|
// Readability
|
|
pEvent = &m_rTable.prgEvent[i];
|
|
|
|
// If this event was in the outbox
|
|
if (0 != pEvent->idMessage && ISFLAGSET(pEvent->dwFlags, SMTPEVENT_COMPLETE))
|
|
{
|
|
// Insert into my array of message ids
|
|
if (cIds + 1 > cIdsAlloc)
|
|
{
|
|
// Realloc
|
|
CHECKHR(hr = HrRealloc((LPVOID *)&prgdwIds, sizeof(DWORD) * (cIdsAlloc + 10)));
|
|
|
|
// Increment cIdsAlloc
|
|
cIdsAlloc += 10;
|
|
}
|
|
|
|
// Set Message Id
|
|
prgdwIds[cIds++] = (DWORD_PTR)pEvent->idMessage;
|
|
}
|
|
}
|
|
|
|
// Setup List
|
|
m_rList.cMsgs = cIds;
|
|
m_rList.prgidMsg = (LPMESSAGEID)prgdwIds;
|
|
prgdwIds = NULL;
|
|
|
|
if (m_rList.cMsgs)
|
|
{
|
|
Flags.dwAdd = ARF_READ;
|
|
Flags.dwRemove = ARF_SUBMITTED | ARF_UNSENT;
|
|
|
|
if (m_idEventUpload == INVALID_EVENT)
|
|
{
|
|
if (DwGetOption(OPT_SAVESENTMSGS))
|
|
{
|
|
Assert(m_pSentItems != NULL);
|
|
|
|
// Move the message from the sent items folder
|
|
CHECKHR(hr = m_pOutbox->CopyMessages(m_pSentItems, COPY_MESSAGE_MOVE, &m_rList, &Flags, NULL, NOSTORECALLBACK));
|
|
}
|
|
else
|
|
{
|
|
// Delete the messages
|
|
CHECKHR(hr = m_pOutbox->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &m_rList, NULL, NOSTORECALLBACK));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Raid-7639: OE sends message over and over when runs out of disk space.
|
|
m_pOutbox->SetMessageFlags(&m_rList, &Flags, NULL, NOSTORECALLBACK);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(prgdwIds);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::Cancel
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CSmtpTask::Cancel(void)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Cancelled
|
|
FLAGSET(m_dwState, SMTPSTATE_CANCELED);
|
|
|
|
// Simply drop the connection
|
|
if (m_pTransport)
|
|
m_pTransport->DropConnection();
|
|
|
|
if (m_pCancel != NULL)
|
|
m_pCancel->Cancel(CT_ABORT);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::OnTimeoutResponse
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CSmtpTask::OnTimeoutResponse(TIMEOUTRESPONSE eResponse)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Should have a handle to the timeout window
|
|
Assert(m_hwndTimeout);
|
|
|
|
// No timeout window handle
|
|
m_hwndTimeout = NULL;
|
|
|
|
// Stop ?
|
|
if (TIMEOUT_RESPONSE_STOP == eResponse)
|
|
{
|
|
// Cancelled
|
|
FLAGSET(m_dwState, SMTPSTATE_CANCELED);
|
|
|
|
// Report error and drop connection
|
|
_CatchResult(IXP_E_TIMEOUT, IXP_SMTP);
|
|
}
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::IsDialogMessage
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CSmtpTask::IsDialogMessage(LPMSG pMsg)
|
|
{
|
|
HRESULT hr=S_FALSE;
|
|
EnterCriticalSection(&m_cs);
|
|
if (m_hwndTimeout && IsWindow(m_hwndTimeout))
|
|
hr = (TRUE == ::IsDialogMessage(m_hwndTimeout, pMsg)) ? S_OK : S_FALSE;
|
|
LeaveCriticalSection(&m_cs);
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CSmtpTask::OnFlagsChanged
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CSmtpTask::OnFlagsChanged(DWORD dwFlags)
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
m_dwFlags = dwFlags;
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CSmtpTask::OnBegin(STOREOPERATIONTYPE tyOperation, STOREOPERATIONINFO *pOpInfo, IOperationCancel *pCancel)
|
|
{
|
|
char szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
|
|
|
|
// Hold onto this
|
|
Assert(m_tyOperation == SOT_INVALID);
|
|
|
|
if (pCancel)
|
|
{
|
|
m_pCancel = pCancel;
|
|
m_pCancel->AddRef();
|
|
}
|
|
m_tyOperation = tyOperation;
|
|
|
|
// Set the animation
|
|
m_pUI->SetAnimation(idanOutbox, TRUE);
|
|
|
|
// Setup Progress Meter
|
|
m_pUI->SetProgressRange(100);
|
|
|
|
m_wProgress = 0;
|
|
|
|
LOADSTRING(IDS_SPS_MOVEPROGRESS, szRes);
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, 1, m_rList.cMsgs);
|
|
|
|
m_pUI->SetSpecificProgress(szBuf);
|
|
|
|
// Party On
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CSmtpTask::OnProgress(STOREOPERATIONTYPE tyOperation, DWORD dwCurrent, DWORD dwMax, LPCSTR pszStatus)
|
|
{
|
|
char szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
|
|
WORD wProgress, wDelta;
|
|
|
|
// NOTE: that you can get more than one type of value for tyOperation.
|
|
// Most likely, you will get SOT_CONNECTION_STATUS and then the
|
|
// operation that you might expect. See HotStore.idl and look for
|
|
// the STOREOPERATION enumeration type for more info.
|
|
|
|
if (tyOperation == SOT_CONNECTION_STATUS)
|
|
{
|
|
// Connecting to ...
|
|
LoadString(g_hLocRes, idsInetMailConnectingHost, szRes, ARRAYSIZE(szRes));
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_rServer.szAccount);
|
|
m_pUI->SetGeneralProgress(szBuf);
|
|
}
|
|
else if (tyOperation == SOT_COPYMOVE_MESSAGE)
|
|
{
|
|
// Compute Current Progress Index
|
|
wProgress = (WORD)((dwCurrent * 100) / dwMax);
|
|
|
|
// 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);
|
|
}
|
|
|
|
if (dwCurrent < dwMax)
|
|
{
|
|
LOADSTRING(IDS_SPS_MOVEPROGRESS, szRes);
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, dwCurrent + 1, dwMax);
|
|
|
|
// Set Specific Progress
|
|
m_pUI->SetSpecificProgress(szBuf);
|
|
}
|
|
}
|
|
|
|
// Done
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CSmtpTask::OnTimeout(LPINETSERVER pServer, LPDWORD pdwTimeout, IXPTYPE ixpServerType)
|
|
{
|
|
// Is there currently a timeout dialog
|
|
if (m_hwndTimeout)
|
|
{
|
|
// Set foreground
|
|
SetForegroundWindow(m_hwndTimeout);
|
|
}
|
|
else
|
|
{
|
|
LPCSTR pszProtocol;
|
|
|
|
// Not suppose to be showing UI ?
|
|
if (ISFLAGSET(m_dwFlags, DELIVER_NOUI))
|
|
return(S_FALSE);
|
|
|
|
// Do Timeout Dialog
|
|
GetProtocolString(&pszProtocol, ixpServerType);
|
|
if (pServer)
|
|
{
|
|
m_hwndTimeout = TaskUtil_HwndOnTimeout(pServer->szServerName, pServer->szAccount,
|
|
pszProtocol, pServer->dwTimeout, (ITimeoutCallback *) this);
|
|
|
|
// Couldn't create the dialog
|
|
if (NULL == m_hwndTimeout)
|
|
return(S_FALSE);
|
|
}
|
|
}
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CSmtpTask::CanConnect(LPCSTR pszAccountId, DWORD dwFlags)
|
|
{
|
|
HWND hwnd;
|
|
BOOL fPrompt = TRUE;
|
|
|
|
if (m_pUI)
|
|
m_pUI->GetWindow(&hwnd);
|
|
else
|
|
hwnd = NULL;
|
|
|
|
// Call into general CanConnect Utility
|
|
if ((m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)) || (dwFlags & CC_FLAG_DONTPROMPT))
|
|
fPrompt = FALSE;
|
|
|
|
return CallbackCanConnect(pszAccountId, hwnd, fPrompt);
|
|
}
|
|
|
|
STDMETHODIMP CSmtpTask::OnLogonPrompt(LPINETSERVER pServer, IXPTYPE ixpServerType)
|
|
{
|
|
HWND hwnd;
|
|
|
|
if (m_hwndTimeout)
|
|
{
|
|
DestroyWindow(m_hwndTimeout);
|
|
m_hwndTimeout = NULL;
|
|
}
|
|
|
|
if (!!(m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)))
|
|
return(E_FAIL);
|
|
|
|
if (m_pUI)
|
|
m_pUI->GetWindow(&hwnd);
|
|
else
|
|
hwnd = NULL;
|
|
|
|
// Call into general OnLogonPrompt Utility
|
|
return CallbackOnLogonPrompt(hwnd, pServer, ixpServerType);
|
|
}
|
|
|
|
STDMETHODIMP CSmtpTask::OnComplete(STOREOPERATIONTYPE tyOperation, HRESULT hrComplete,
|
|
LPSTOREOPERATIONINFO pOpInfo, LPSTOREERROR pErrorInfo)
|
|
{
|
|
HRESULT hr;
|
|
char szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES * 2], szSubject[64];
|
|
EVENTCOMPLETEDSTATUS tyEventStatus;
|
|
|
|
if (m_hwndTimeout)
|
|
{
|
|
DestroyWindow(m_hwndTimeout);
|
|
m_hwndTimeout = NULL;
|
|
}
|
|
|
|
IxpAssert(m_tyOperation != SOT_INVALID);
|
|
if (m_tyOperation != tyOperation)
|
|
return(S_OK);
|
|
|
|
Assert(tyOperation == SOT_COPYMOVE_MESSAGE);
|
|
|
|
// Figure out if we succeeded or failed
|
|
if (FAILED(hrComplete))
|
|
{
|
|
Assert(m_pUI);
|
|
|
|
if (NULL != pErrorInfo)
|
|
{
|
|
IXPRESULT ixpResult;
|
|
INETSERVER rServer;
|
|
char szProblem[CCHMAX_STRINGRES];
|
|
int iLen;
|
|
|
|
// Prepend sent items text error text to supplied problem
|
|
Assert(tyOperation == SOT_COPYMOVE_MESSAGE);
|
|
iLen = LoadString(g_hLocRes, IDS_SP_E_CANT_MOVETO_SENTITEMS, szProblem, sizeof(szProblem));
|
|
if (iLen < sizeof(szProblem) - 1)
|
|
{
|
|
szProblem[iLen] = ' ';
|
|
iLen += 1;
|
|
szProblem[iLen] = '\0';
|
|
}
|
|
if (NULL != pErrorInfo->pszProblem)
|
|
StrCpyN(szProblem + iLen, pErrorInfo->pszProblem, ARRAYSIZE(szProblem) - iLen);
|
|
|
|
TaskUtil_SplitStoreError(&ixpResult, &rServer, pErrorInfo);
|
|
ixpResult.pszProblem = szProblem;
|
|
|
|
_CatchResult(&ixpResult, &rServer, pErrorInfo->ixpType);
|
|
}
|
|
else
|
|
{
|
|
// Remap the Error Result
|
|
hr = TrapError(SP_E_CANT_MOVETO_SENTITEMS);
|
|
|
|
// Show an error in the spooler dialog
|
|
_CatchResult(hr, IXP_IMAP); // Without a STOREERROR, we just have to guess
|
|
}
|
|
}
|
|
|
|
m_pUI->SetAnimation(idanOutbox, FALSE);
|
|
|
|
if (ISFLAGSET(m_dwState, SMTPSTATE_CANCELED))
|
|
tyEventStatus = EVENT_CANCELED;
|
|
else if (SUCCEEDED(hrComplete))
|
|
tyEventStatus = EVENT_SUCCEEDED;
|
|
else
|
|
tyEventStatus = EVENT_FAILED;
|
|
|
|
// Result
|
|
m_pSpoolCtx->Notify(DELIVERY_NOTIFY_RESULT, tyEventStatus);
|
|
|
|
// Result
|
|
m_pSpoolCtx->Notify(DELIVERY_NOTIFY_COMPLETE, 0);
|
|
|
|
m_pSpoolCtx->EventDone(m_idEventUpload, tyEventStatus);
|
|
|
|
// Release your cancel object
|
|
SafeRelease(m_pCancel);
|
|
m_tyOperation = SOT_INVALID;
|
|
|
|
// Done
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CSmtpTask::OnPrompt(HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType, INT *piUserResponse)
|
|
{
|
|
HWND hwnd;
|
|
|
|
// Close any timeout dialog, if present
|
|
if (m_hwndTimeout)
|
|
{
|
|
DestroyWindow(m_hwndTimeout);
|
|
m_hwndTimeout = NULL;
|
|
}
|
|
|
|
// Raid 55082 - SPOOLER: SPA/SSL auth to NNTP does not display cert warning and fails.
|
|
#if 0
|
|
if (!!(m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)))
|
|
return(E_FAIL);
|
|
#endif
|
|
|
|
if (m_pUI)
|
|
m_pUI->GetWindow(&hwnd);
|
|
else
|
|
hwnd = NULL;
|
|
|
|
// Call into my swanky utility
|
|
return CallbackOnPrompt(hwnd, hrError, pszText, pszCaption, uType, piUserResponse);
|
|
}
|