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.
3649 lines
110 KiB
3649 lines
110 KiB
// --------------------------------------------------------------------------------
|
|
// Pop3task.cpp
|
|
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
|
|
// Steven J. Bailey
|
|
// --------------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "pop3task.h"
|
|
#include "resource.h"
|
|
#include "xputil.h"
|
|
#include "goptions.h"
|
|
#include "strconst.h"
|
|
#include "mimeutil.h"
|
|
#include "shlwapi.h"
|
|
#include "shlwapip.h"
|
|
#include "options.h"
|
|
#include "xpcomm.h"
|
|
#include "ourguid.h"
|
|
#include "msgfldr.h"
|
|
#include "storecb.h"
|
|
#include "mailutil.h"
|
|
#include "ruleutil.h"
|
|
#include "demand.h"
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Debug Modifiers
|
|
// --------------------------------------------------------------------------------
|
|
#ifdef DEBUG
|
|
BOOL g_fUidlByTop = FALSE;
|
|
BOOL g_fFailTopCommand = FALSE;
|
|
LONG g_ulFailNumber=-1;
|
|
#endif
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// ISLASTPOPID
|
|
// --------------------------------------------------------------------------------
|
|
#define ISLASTPOPID(_dwPopId) \
|
|
(_dwPopId == m_rTable.cItems)
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// ISVALIDPOPID
|
|
// --------------------------------------------------------------------------------
|
|
#define ISVALIDPOPID(_dwPopId) \
|
|
(_dwPopId - 1 < m_rTable.cItems)
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// ITEMFROMPOPID
|
|
// --------------------------------------------------------------------------------
|
|
#define ITEMFROMPOPID(_dwPopId) \
|
|
(&m_rTable.prgItem[_dwPopId - 1])
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::CPop3Task
|
|
// --------------------------------------------------------------------------------
|
|
CPop3Task::CPop3Task(void)
|
|
{
|
|
m_cRef = 1;
|
|
m_dwFlags = 0;
|
|
m_dwState = 0;
|
|
m_dwExpireDays = 0;
|
|
m_pSpoolCtx = NULL;
|
|
m_pAccount = NULL;
|
|
m_pTransport = NULL;
|
|
m_pUI = NULL;
|
|
m_pIExecRules = NULL;
|
|
m_pIRuleSender = NULL;
|
|
m_pIRuleJunk = NULL;
|
|
m_pInbox = NULL;
|
|
m_pOutbox = NULL;
|
|
m_eidEvent = 0;
|
|
m_pUidlCache = NULL;
|
|
m_uidlsupport = UIDL_SUPPORT_NONE;
|
|
m_dwProgressMax = 0;
|
|
m_dwProgressCur = 0;
|
|
m_wProgress = 0;
|
|
m_eidEvent = 0;
|
|
m_hrResult = S_OK;
|
|
m_pStream = NULL;
|
|
m_state = POP3STATE_NONE;
|
|
m_hwndTimeout = NULL;
|
|
m_pLogFile = NULL;
|
|
m_pSmartLog = NULL;
|
|
*m_szAccountId = '\0';
|
|
ZeroMemory(&m_rMetrics, sizeof(POP3METRICS));
|
|
ZeroMemory(&m_rFolder, sizeof(POP3FOLDERINFO));
|
|
ZeroMemory(&m_rTable, sizeof(POP3ITEMTABLE));
|
|
ZeroMemory(&m_rServer, sizeof(INETSERVER));
|
|
InitializeCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::~CPop3Task
|
|
// --------------------------------------------------------------------------------
|
|
CPop3Task::~CPop3Task(void)
|
|
{
|
|
ZeroMemory(&m_rServer, sizeof(m_rServer)); // Done for security.
|
|
|
|
// Reset the Object
|
|
_ResetObject(TRUE);
|
|
|
|
// Kill the critical section
|
|
DeleteCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_ResetObject
|
|
// --------------------------------------------------------------------------------
|
|
void CPop3Task::_ResetObject(BOOL fDeconstruct)
|
|
{
|
|
// Release Folder Objects
|
|
_ReleaseFolderObjects();
|
|
|
|
// Make sure the transport is disconnect
|
|
if (m_pTransport)
|
|
{
|
|
m_pTransport->Release();
|
|
m_pTransport = NULL;
|
|
}
|
|
|
|
// Release the Outbox
|
|
SafeRelease(m_pAccount);
|
|
SafeRelease(m_pInbox);
|
|
SafeRelease(m_pOutbox);
|
|
SafeRelease(m_pIExecRules);
|
|
SafeRelease(m_pIRuleSender);
|
|
SafeRelease(m_pIRuleJunk);
|
|
SafeRelease(m_pSpoolCtx);
|
|
SafeRelease(m_pUI);
|
|
SafeRelease(m_pUidlCache);
|
|
SafeRelease(m_pStream);
|
|
SafeRelease(m_pLogFile);
|
|
|
|
// Kill the log file
|
|
_FreeSmartLog();
|
|
|
|
// Free the event table elements
|
|
_FreeItemTableElements();
|
|
|
|
// Deconstructing
|
|
if (fDeconstruct)
|
|
{
|
|
// Free Event Table
|
|
SafeMemFree(m_rTable.prgItem);
|
|
}
|
|
|
|
// Otherwise, reset some vars
|
|
else
|
|
{
|
|
// Reset total byte count
|
|
m_dwFlags = 0;
|
|
m_dwState = 0;
|
|
m_dwExpireDays = 0;
|
|
m_eidEvent = 0;
|
|
m_wProgress = 0;
|
|
m_uidlsupport = UIDL_SUPPORT_NONE;
|
|
m_state = POP3STATE_NONE;
|
|
ZeroMemory(&m_rFolder, sizeof(POP3FOLDERINFO));
|
|
ZeroMemory(&m_rMetrics, sizeof(POP3METRICS));
|
|
ZeroMemory(&m_rServer, sizeof(INETSERVER));
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_ReleaseFolderObjects
|
|
// --------------------------------------------------------------------------------
|
|
void CPop3Task::_ReleaseFolderObjects(void)
|
|
{
|
|
// m_rFolder should have been release
|
|
_CloseFolder();
|
|
|
|
// Force Inbox Rules to release folder objects
|
|
if (m_pIExecRules)
|
|
{
|
|
m_pIExecRules->ReleaseObjects();
|
|
}
|
|
|
|
// Download only locks the inbox
|
|
SafeRelease(m_pInbox);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_FreeItemTableElements
|
|
// --------------------------------------------------------------------------------
|
|
void CPop3Task::_FreeItemTableElements(void)
|
|
{
|
|
// Loop the table of events
|
|
for (ULONG i=0; i<m_rTable.cItems; i++)
|
|
{
|
|
// Free pszForwardTo
|
|
SafeMemFree(m_rTable.prgItem[i].pszUidl);
|
|
RuleUtil_HrFreeActionsItem(m_rTable.prgItem[i].pActList, m_rTable.prgItem[i].cActList);
|
|
SafeMemFree(m_rTable.prgItem[i].pActList);
|
|
}
|
|
|
|
// No Events
|
|
m_rTable.cItems = 0;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::QueryInterface
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPop3Task::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;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::CPop3Task
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CPop3Task::AddRef(void)
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
ULONG cRef = ++m_cRef;
|
|
LeaveCriticalSection(&m_cs);
|
|
return cRef;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::CPop3Task
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CPop3Task::Release(void)
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
ULONG cRef = --m_cRef;
|
|
LeaveCriticalSection(&m_cs);
|
|
if (0 != cRef)
|
|
return cRef;
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::Init
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPop3Task::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;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::BuildEvents
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPop3Task::BuildEvents(ISpoolerUI *pSpoolerUI, IImnAccount *pAccount, FOLDERID idFolder)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD dw;
|
|
CHAR szAccountName[CCHMAX_ACCOUNT_NAME];
|
|
CHAR szRes[CCHMAX_RES];
|
|
CHAR szMessage[CCHMAX_RES + CCHMAX_ACCOUNT_NAME];
|
|
LPSTR pszLogFile=NULL;
|
|
DWORD dwState;
|
|
PROPVARIANT propvar = {0};
|
|
|
|
// 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_pInbox && 0 == m_rTable.cItems);
|
|
|
|
// Save the UI Object
|
|
m_pUI = pSpoolerUI;
|
|
m_pUI->AddRef();
|
|
|
|
// Release current Account
|
|
m_pAccount = pAccount;
|
|
m_pAccount->AddRef();
|
|
|
|
// Leave mail on server
|
|
if (SUCCEEDED(m_pAccount->GetPropDw(AP_POP3_LEAVE_ON_SERVER, &dw)) && TRUE == dw)
|
|
FLAGSET(m_dwState, POP3STATE_LEAVEONSERVER);
|
|
|
|
// Delete Expire
|
|
if (SUCCEEDED(m_pAccount->GetPropDw(AP_POP3_REMOVE_EXPIRED, &dw)) && TRUE == dw)
|
|
FLAGSET(m_dwState, POP3STATE_DELETEEXPIRED);
|
|
|
|
// Days to Expire
|
|
if (FAILED(m_pAccount->GetPropDw(AP_POP3_EXPIRE_DAYS, &m_dwExpireDays)))
|
|
m_dwExpireDays = 5;
|
|
|
|
// Delete From Server when deleted from Deleted Items Folder...
|
|
if (SUCCEEDED(m_pAccount->GetPropDw(AP_POP3_REMOVE_DELETED, &dw)) && TRUE == dw)
|
|
FLAGSET(m_dwState, POP3STATE_SYNCDELETED);
|
|
|
|
// Get the inbox rules object
|
|
Assert(g_pRulesMan);
|
|
CHECKHR(hr = g_pRulesMan->ExecRules(EXECF_ALL, RULE_TYPE_MAIL, &m_pIExecRules));
|
|
|
|
// Get the block sender rule
|
|
Assert(NULL == m_pIRuleSender);
|
|
(VOID) g_pRulesMan->GetRule(RULEID_SENDERS, RULE_TYPE_MAIL, 0, &m_pIRuleSender);
|
|
|
|
// Only use it if it there and enabled
|
|
if (NULL != m_pIRuleSender)
|
|
{
|
|
if (FAILED(m_pIRuleSender->GetProp(RULE_PROP_DISABLED, 0, &propvar)))
|
|
{
|
|
m_pIRuleSender->Release();
|
|
m_pIRuleSender = NULL;
|
|
}
|
|
else
|
|
{
|
|
Assert(VT_BOOL == propvar.vt);
|
|
if (FALSE != propvar.boolVal)
|
|
{
|
|
m_pIRuleSender->Release();
|
|
m_pIRuleSender = NULL;
|
|
}
|
|
|
|
PropVariantClear(&propvar);
|
|
}
|
|
}
|
|
|
|
Assert(NULL == m_pIRuleJunk);
|
|
(VOID) g_pRulesMan->GetRule(RULEID_JUNK, RULE_TYPE_MAIL, 0, &m_pIRuleJunk);
|
|
|
|
// Only use it if it enabled
|
|
if (NULL != m_pIRuleJunk)
|
|
{
|
|
if (FAILED(m_pIRuleJunk->GetProp(RULE_PROP_DISABLED, 0, &propvar)))
|
|
{
|
|
m_pIRuleJunk->Release();
|
|
m_pIRuleJunk = NULL;
|
|
}
|
|
else
|
|
{
|
|
Assert(VT_BOOL == propvar.vt);
|
|
if (FALSE != propvar.boolVal)
|
|
{
|
|
m_pIRuleJunk->Release();
|
|
m_pIRuleJunk = NULL;
|
|
}
|
|
|
|
PropVariantClear(&propvar);
|
|
}
|
|
}
|
|
|
|
// Predownload rules
|
|
CHECKHR(hr = m_pIExecRules->GetState(&dwState));
|
|
|
|
// Do we have server actions to do?
|
|
if (0 != (dwState & ACT_STATE_SERVER))
|
|
FLAGSET(m_dwState, POP3STATE_PDR);
|
|
|
|
// No Post Download Rules
|
|
if ((0 == (dwState & (ACT_STATE_LOCAL|CRIT_STATE_ALL))) &&
|
|
(NULL == m_pIRuleSender) &&
|
|
(NULL == m_pIRuleJunk))
|
|
FLAGSET(m_dwState, POP3STATE_NOPOSTRULES);
|
|
|
|
// No Body Rules
|
|
if ((ISFLAGSET(dwState, CRIT_STATE_ALL)) || (NULL != m_pIRuleJunk))
|
|
FLAGSET(m_dwState, POP3STATE_BODYRULES);
|
|
|
|
// Get the outbox
|
|
CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreOutbox, (LPVOID *)&m_pOutbox));
|
|
|
|
// Get a pop3 log file
|
|
m_pSpoolCtx->BindToObject(IID_CPop3LogFile, (LPVOID *)&m_pLogFile);
|
|
|
|
// Get Account Id
|
|
CHECKHR(hr = m_pAccount->GetPropSz(AP_ACCOUNT_NAME, szAccountName, ARRAYSIZE(szAccountName)));
|
|
|
|
// Register Event - Get new messages from '%s'.
|
|
LOADSTRING(IDS_SPS_POP3EVENT, szRes);
|
|
|
|
// Format the String
|
|
wnsprintf(szMessage, ARRAYSIZE(szMessage), szRes, szAccountName);
|
|
|
|
// Register for the event...
|
|
CHECKHR(hr = m_pSpoolCtx->RegisterEvent(szMessage, (ISpoolerTask *)this, POP3EVENT_DOWNLOADMAIL, m_pAccount, &m_eidEvent));
|
|
|
|
exit:
|
|
// Failure
|
|
if (FAILED(hr))
|
|
{
|
|
_CatchResult(hr);
|
|
_ResetObject(FALSE);
|
|
}
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_DoSmartLog
|
|
// --------------------------------------------------------------------------------
|
|
void CPop3Task::_DoSmartLog(IMimeMessage *pMessage)
|
|
{
|
|
// Don't make the function call if this is null...
|
|
Assert(m_pSmartLog && m_pSmartLog->pStmFile && m_pSmartLog->pszProperty && m_pSmartLog->pszValue && pMessage);
|
|
|
|
// Do a query property...
|
|
if (lstrcmpi("all", m_pSmartLog->pszProperty) == 0 || S_OK == pMessage->QueryProp(m_pSmartLog->pszProperty, m_pSmartLog->pszValue, TRUE, FALSE))
|
|
{
|
|
// Locals
|
|
LPSTR psz=NULL;
|
|
PROPVARIANT rVariant;
|
|
IStream *pStream=NULL;
|
|
|
|
// Get IAT_FROM
|
|
if (FAILED(pMessage->GetAddressFormat(IAT_FROM, AFT_DISPLAY_BOTH, &psz)))
|
|
{
|
|
// Try IAT_SENDER
|
|
pMessage->GetAddressFormat(IAT_SENDER, AFT_DISPLAY_BOTH, &psz);
|
|
}
|
|
|
|
// Write the Sender
|
|
if (psz)
|
|
{
|
|
// Write It
|
|
SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(psz, lstrlen(psz), NULL)));
|
|
|
|
// Free psz
|
|
SafeMemFree(psz);
|
|
}
|
|
|
|
// Otherwise, write Unknown
|
|
else
|
|
{
|
|
CHAR sz[255];
|
|
LoadString(g_hLocRes, idsUnknown, sz, ARRAYSIZE(sz));
|
|
SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(sz, lstrlen(sz), NULL)));
|
|
}
|
|
|
|
// Write a tab
|
|
SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL)));
|
|
|
|
// Get IAT_CC
|
|
if (SUCCEEDED(pMessage->GetAddressFormat(IAT_CC, AFT_DISPLAY_BOTH, &psz)))
|
|
{
|
|
// Write It
|
|
SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(psz, lstrlen(psz), NULL)));
|
|
|
|
// Free psz
|
|
SafeMemFree(psz);
|
|
}
|
|
|
|
// Write a tab
|
|
SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL)));
|
|
|
|
// Lets write the X-Mailer just to be a nice guy
|
|
rVariant.vt = VT_LPSTR;
|
|
if (SUCCEEDED(pMessage->GetProp(PIDTOSTR(PID_HDR_XMAILER), 0, &rVariant)))
|
|
{
|
|
// Write It
|
|
SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(rVariant.pszVal, lstrlen(rVariant.pszVal), NULL)));
|
|
|
|
// Free psz
|
|
SafeMemFree(rVariant.pszVal);
|
|
}
|
|
|
|
// Write a tab
|
|
SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL)));
|
|
|
|
// Lets write the X-MimeOLE just to be a nice guy
|
|
rVariant.vt = VT_LPSTR;
|
|
if (SUCCEEDED(pMessage->GetProp("X-MimeOLE", 0, &rVariant)))
|
|
{
|
|
// Write It
|
|
SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(rVariant.pszVal, lstrlen(rVariant.pszVal), NULL)));
|
|
|
|
// Free psz
|
|
SafeMemFree(rVariant.pszVal);
|
|
}
|
|
|
|
// Write a tab
|
|
SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL)));
|
|
|
|
// Lets write the Subject just to be a nice guy
|
|
rVariant.vt = VT_LPSTR;
|
|
if (SUCCEEDED(pMessage->GetProp(PIDTOSTR(PID_HDR_DATE), 0, &rVariant)))
|
|
{
|
|
// Write It
|
|
SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(rVariant.pszVal, lstrlen(rVariant.pszVal), NULL)));
|
|
|
|
// Free psz
|
|
SafeMemFree(rVariant.pszVal);
|
|
}
|
|
|
|
// Write a tab
|
|
SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL)));
|
|
|
|
// Lets write the Subject just to be a nice guy
|
|
rVariant.vt = VT_LPSTR;
|
|
if (SUCCEEDED(pMessage->GetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &rVariant)))
|
|
{
|
|
// Write It
|
|
SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(rVariant.pszVal, lstrlen(rVariant.pszVal), NULL)));
|
|
|
|
// Free psz
|
|
SafeMemFree(rVariant.pszVal);
|
|
}
|
|
|
|
// Write a tab
|
|
SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL)));
|
|
|
|
// Write the first line of the message body
|
|
if (FAILED(pMessage->GetTextBody(TXT_PLAIN, IET_DECODED, &pStream, NULL)))
|
|
{
|
|
// Try to get the HTML body
|
|
if (FAILED(pMessage->GetTextBody(TXT_HTML, IET_DECODED, &pStream, NULL)))
|
|
pStream = NULL;
|
|
}
|
|
|
|
// Did we find a stream
|
|
if (pStream)
|
|
{
|
|
// Locals
|
|
BYTE rgBuffer[1048];
|
|
ULONG cbRead;
|
|
ULONG i;
|
|
ULONG cGood=0;
|
|
|
|
// Read a buffer
|
|
if (SUCCEEDED(pStream->Read(rgBuffer, sizeof(rgBuffer), &cbRead)))
|
|
{
|
|
// Write until we hit a \r or \n
|
|
for (i=0; i<cbRead; i++)
|
|
{
|
|
// End of line
|
|
if ('\r' == rgBuffer[i] || '\n' == rgBuffer[i])
|
|
{
|
|
// If we found 3 or more non-space chars, we found the first line
|
|
if (cGood > 3)
|
|
break;
|
|
|
|
// Otherwise, continue...
|
|
else
|
|
{
|
|
rgBuffer[i] = ' ';
|
|
cGood = 0;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Replace Tabs with spaces so that it doesn't mess up tab delimited file
|
|
if ('\t' == rgBuffer[i])
|
|
rgBuffer[i] = ' ';
|
|
|
|
// If not a space
|
|
if (FALSE == FIsSpaceA((LPSTR)(rgBuffer + i)))
|
|
cGood++;
|
|
}
|
|
|
|
// Write the character
|
|
m_pSmartLog->pStmFile->Write(rgBuffer, ((i > 0) ? i - 1 : i), NULL);
|
|
}
|
|
|
|
// Free psz
|
|
SafeRelease(pStream);
|
|
}
|
|
|
|
// Write a tab
|
|
SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(g_szCRLF, lstrlen(g_szCRLF), NULL)));
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_FreeSmartLog
|
|
// --------------------------------------------------------------------------------
|
|
void CPop3Task::_FreeSmartLog(void)
|
|
{
|
|
if (m_pSmartLog)
|
|
{
|
|
SafeMemFree(m_pSmartLog->pszAccount);
|
|
SafeMemFree(m_pSmartLog->pszProperty);
|
|
SafeMemFree(m_pSmartLog->pszValue);
|
|
SafeMemFree(m_pSmartLog->pszLogFile);
|
|
SafeRelease(m_pSmartLog->pStmFile);
|
|
g_pMalloc->Free(m_pSmartLog);
|
|
m_pSmartLog = NULL;
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_ReadSmartLogEntry
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_ReadSmartLogEntry(HKEY hKey, LPCSTR pszKey, LPSTR *ppszValue)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cb;
|
|
|
|
// Read the pszKey
|
|
if (RegQueryValueEx(hKey, pszKey, NULL, NULL, NULL, &cb) != ERROR_SUCCESS)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Allocate
|
|
cb++;
|
|
CHECKALLOC(*ppszValue = PszAllocA(cb));
|
|
|
|
// Read the pszKey
|
|
if (RegQueryValueEx(hKey, pszKey, NULL, NULL, (LPBYTE)*ppszValue, &cb) != ERROR_SUCCESS)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_InitializeSmartLog
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_InitializeSmartLog(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
HKEY hKey=NULL;
|
|
ULARGE_INTEGER uliPos = {0,0};
|
|
LARGE_INTEGER liOrigin = {0,0};
|
|
|
|
// Get Advanced Logging Information
|
|
if (AthUserOpenKey(c_szRegPathSmartLog, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Allocate smart log
|
|
CHECKALLOC(m_pSmartLog = (LPSMARTLOGINFO)g_pMalloc->Alloc(sizeof(SMARTLOGINFO)));
|
|
|
|
// Zero Init
|
|
ZeroMemory(m_pSmartLog, sizeof(SMARTLOGINFO));
|
|
|
|
// Read the Account
|
|
CHECKHR(hr = _ReadSmartLogEntry(hKey, "Account", &m_pSmartLog->pszAccount));
|
|
|
|
// Read the Property
|
|
CHECKHR(hr = _ReadSmartLogEntry(hKey, "Property", &m_pSmartLog->pszProperty));
|
|
|
|
// Read the ContainsValue
|
|
CHECKHR(hr = _ReadSmartLogEntry(hKey, "ContainsValue", &m_pSmartLog->pszValue));
|
|
|
|
// Read the LogFile
|
|
CHECKHR(hr = _ReadSmartLogEntry(hKey, "LogFile", &m_pSmartLog->pszLogFile));
|
|
|
|
// Open the logfile
|
|
CHECKHR(hr = OpenFileStream(m_pSmartLog->pszLogFile, OPEN_ALWAYS, GENERIC_WRITE | GENERIC_READ, &m_pSmartLog->pStmFile));
|
|
|
|
// Seek to the end
|
|
CHECKHR(hr = m_pSmartLog->pStmFile->Seek(liOrigin, STREAM_SEEK_END, &uliPos));
|
|
|
|
exit:
|
|
// Failure
|
|
if (FAILED(hr))
|
|
_FreeSmartLog();
|
|
|
|
// Cleanup
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::Execute
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPop3Task::Execute(EVENTID eid, DWORD_PTR dwTwinkie)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szRes[CCHMAX_RES];
|
|
CHAR szBuf[CCHMAX_RES + CCHMAX_SERVER_NAME];
|
|
DWORD cb;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Check State
|
|
Assert(eid == m_eidEvent && m_pAccount && m_pUI);
|
|
|
|
// Create the Transport Object
|
|
CHECKHR(hr = CreatePOP3Transport(&m_pTransport));
|
|
|
|
// Init the Transport
|
|
CHECKHR(hr = m_pTransport->InitNew(NULL, (IPOP3Callback *)this));
|
|
|
|
// Fill an INETSERVER structure from the account object
|
|
CHECKHR(hr = m_pTransport->InetServerFromAccount(m_pAccount, &m_rServer));
|
|
|
|
// Get Account Id
|
|
CHECKHR(hr = m_pAccount->GetPropSz(AP_ACCOUNT_ID, m_szAccountId, ARRAYSIZE(m_szAccountId)));
|
|
|
|
// Always connect using the most recently supplied password from the user
|
|
hr = GetPassword(m_rServer.dwPort, m_rServer.szServerName, m_rServer.szUserName,
|
|
m_rServer.szPassword, sizeof(m_rServer.szPassword));
|
|
|
|
// 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 (m_pUI && ISFLAGSET(m_rServer.dwFlags, ISF_ALWAYSPROMPTFORPASSWORD) && FAILED(hr))
|
|
{
|
|
m_pUI->ShowWindow(SW_SHOW);
|
|
}
|
|
|
|
// Get Smart Logging INformation
|
|
_InitializeSmartLog();
|
|
|
|
// Set the animation
|
|
m_pUI->SetAnimation(idanInbox, 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, POP3STATE_EXECUTEFAILED);
|
|
_CatchResult(hr);
|
|
|
|
// Tell the transport to release my callback: otherwise I leak
|
|
SideAssert(m_pTransport->HandsOffCallback() == S_OK);
|
|
}
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CPop3Task::CancelEvent(EVENTID eid, DWORD_PTR dwTwinkie)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::OnTimeout
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPop3Task::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, "POP3", 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;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::OnLogonPrompt
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPop3Task::OnLogonPrompt(LPINETSERVER pInetServer, IInternetTransport *pTransport)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_FALSE;
|
|
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_POP3_USERNAME,
|
|
AP_POP3_PASSWORD, AP_POP3_PROMPT_PASSWORD, TRUE);
|
|
|
|
// Cache the password for this session
|
|
if (S_OK == hr)
|
|
SavePassword(pInetServer->dwPort, pInetServer->szServerName,
|
|
pInetServer->szUserName, pInetServer->szPassword);
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
ZeroMemory(szPassword, sizeof(szPassword)); // Done for security.
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::OnPrompt
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(INT) CPop3Task::OnPrompt(HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType, IInternetTransport *pTransport)
|
|
{
|
|
// Locals
|
|
HWND hwnd;
|
|
INT nAnswer;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// 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;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::OnError
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPop3Task::OnError(IXPSTATUS ixpstatus, LPIXPRESULT pResult, IInternetTransport *pTransport)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Invalid State
|
|
Assert(m_pUI);
|
|
|
|
// Insert Error Into UI
|
|
_CatchResult(POP3_NONE, pResult);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::OnCommand
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPop3Task::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;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_CatchResult
|
|
// --------------------------------------------------------------------------------
|
|
TASKRESULTTYPE CPop3Task::_CatchResult(HRESULT hr)
|
|
{
|
|
// Locals
|
|
IXPRESULT rResult;
|
|
|
|
// Build an IXPRESULT
|
|
ZeroMemory(&rResult, sizeof(IXPRESULT));
|
|
rResult.hrResult = hr;
|
|
|
|
// Get the SMTP Result Type
|
|
return _CatchResult(POP3_NONE, &rResult);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_CatchResult
|
|
// --------------------------------------------------------------------------------
|
|
TASKRESULTTYPE CPop3Task::_CatchResult(POP3COMMAND command, LPIXPRESULT pResult)
|
|
{
|
|
// Locals
|
|
HWND hwndParent;
|
|
TASKRESULTTYPE tyTaskResult=TASKRESULT_FAILURE;
|
|
|
|
// If Succeeded
|
|
if (SUCCEEDED(pResult->hrResult))
|
|
return TASKRESULT_SUCCESS;
|
|
|
|
// Get Window
|
|
if (FAILED(m_pUI->GetWindow(&hwndParent)))
|
|
hwndParent = NULL;
|
|
|
|
// Process generic protocol errro
|
|
tyTaskResult = TaskUtil_FBaseTransportError(IXP_POP3, m_eidEvent, pResult, &m_rServer, NULL, m_pUI,
|
|
!ISFLAGSET(m_dwFlags, DELIVER_NOUI), hwndParent);
|
|
|
|
// Save Result
|
|
m_hrResult = pResult->hrResult;
|
|
|
|
// If Task Failure, drop the connection
|
|
if (NULL != m_pTransport)
|
|
m_pTransport->DropConnection();
|
|
|
|
// Return Result
|
|
return tyTaskResult;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::OnStatus
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPop3Task::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)
|
|
{
|
|
// Locals
|
|
BOOL fWarning=FALSE;
|
|
|
|
// Note that OnDisconnect was called
|
|
FLAGSET(m_dwState, POP3STATE_ONDISCONNECT);
|
|
|
|
// If a UIDL Sync is in progress, then return now...
|
|
if (POP3STATE_UIDLSYNC == m_state)
|
|
goto exit;
|
|
|
|
// Kill the timeout dialog
|
|
if (m_hwndTimeout)
|
|
{
|
|
DestroyWindow(m_hwndTimeout);
|
|
m_hwndTimeout = NULL;
|
|
}
|
|
|
|
// Cache Cleanup
|
|
_CleanupUidlCache();
|
|
|
|
// Reset the progress
|
|
// m_pUI->SetProgressRange(100);
|
|
|
|
// State
|
|
m_state = POP3STATE_NONE;
|
|
|
|
// Set the animation
|
|
m_pUI->SetAnimation(idanInbox, FALSE);
|
|
|
|
// Infinite Loop
|
|
if (m_rMetrics.cInfiniteLoopAutoGens)
|
|
{
|
|
// Load the Warning
|
|
CHAR szRes[CCHMAX_RES];
|
|
LOADSTRING(idsReplyForwardLoop, szRes);
|
|
|
|
// Format the Error
|
|
CHAR szMsg[CCHMAX_RES + CCHMAX_ACCOUNT_NAME + CCHMAX_SERVER_NAME + CCHMAX_RES];
|
|
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rMetrics.cInfiniteLoopAutoGens, m_rServer.szAccount, m_rServer.szServerName);
|
|
|
|
// Insert the warning
|
|
m_pUI->InsertError(m_eidEvent, szMsg);
|
|
|
|
// Warning
|
|
fWarning = TRUE;
|
|
}
|
|
|
|
// Nothing to download
|
|
if (ISFLAGSET(m_dwState, POP3STATE_CANCELPENDING))
|
|
tyEventStatus = EVENT_CANCELED;
|
|
else if (FAILED(m_hrResult) || (m_rMetrics.cDownloaded == 0 && m_rMetrics.cDownload > 0))
|
|
tyEventStatus = EVENT_FAILED;
|
|
else if (!ISFLAGSET(m_dwState, POP3STATE_LOGONSUCCESS))
|
|
tyEventStatus = EVENT_WARNINGS;
|
|
else if (m_rMetrics.cDownloaded && m_rMetrics.cDownload && m_rMetrics.cDownloaded < m_rMetrics.cDownload)
|
|
tyEventStatus = EVENT_WARNINGS;
|
|
else if (fWarning)
|
|
tyEventStatus = EVENT_WARNINGS;
|
|
|
|
// Result
|
|
m_pSpoolCtx->Notify(DELIVERY_NOTIFY_RESULT, tyEventStatus);
|
|
|
|
// Success and messages were downloaded
|
|
if (EVENT_FAILED != tyEventStatus && m_rMetrics.cDownloaded && m_rMetrics.cPartials)
|
|
{
|
|
// Sitch Partials
|
|
_HrStitchPartials();
|
|
}
|
|
|
|
// Notify
|
|
m_pSpoolCtx->Notify(DELIVERY_NOTIFY_COMPLETE, m_rMetrics.cDownloaded);
|
|
|
|
// Tell the transport to release my callback
|
|
SideAssert(m_pTransport->HandsOffCallback() == S_OK);
|
|
|
|
// This task is complete
|
|
if (!ISFLAGSET(m_dwState, POP3STATE_EXECUTEFAILED))
|
|
m_pSpoolCtx->EventDone(m_eidEvent, tyEventStatus);
|
|
}
|
|
|
|
// Authorizing
|
|
else if (ixpstatus == IXP_AUTHORIZING)
|
|
m_pSpoolCtx->Notify(DELIVERY_NOTIFY_AUTHORIZING, 0);
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_CleanupUidlCache
|
|
// --------------------------------------------------------------------------------
|
|
void CPop3Task::_CleanupUidlCache(void)
|
|
{
|
|
// Locals
|
|
ULONG i;
|
|
UIDLRECORD UidlInfo={0};
|
|
LPPOP3ITEM pItem;
|
|
|
|
// No Cache Objects
|
|
if (NULL == m_pUidlCache)
|
|
return;
|
|
|
|
// Count the number of messages we will have to get a top for
|
|
for (i=0; i<m_rTable.cItems; i++)
|
|
{
|
|
// Readability
|
|
pItem = &m_rTable.prgItem[i];
|
|
|
|
// Delete the Cached Uidl
|
|
if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DELETED) && ISFLAGSET(pItem->dwFlags, POP3ITEM_DELETECACHEDUIDL))
|
|
{
|
|
// No UIDL
|
|
if (pItem->pszUidl)
|
|
{
|
|
// Set Search Info
|
|
UidlInfo.pszUidl = pItem->pszUidl;
|
|
UidlInfo.pszServer = m_rServer.szServerName;
|
|
UidlInfo.pszAccountId = m_szAccountId;
|
|
|
|
// Set Props on the cached uidl message
|
|
m_pUidlCache->DeleteRecord(&UidlInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove all traces of if the account from the uid cache
|
|
if (ISFLAGSET(m_dwState, POP3STATE_CLEANUPCACHE))
|
|
{
|
|
// Locaks
|
|
HROWSET hRowset=NULL;
|
|
|
|
// Create a rowset
|
|
if (SUCCEEDED(m_pUidlCache->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset)))
|
|
{
|
|
// Delete Enumeration
|
|
while (S_OK == m_pUidlCache->QueryRowset(hRowset, 1, (LPVOID *)&UidlInfo, NULL))
|
|
{
|
|
// Delete this puppy ?
|
|
if (lstrcmpi(UidlInfo.pszServer, m_rServer.szServerName) == 0 &&
|
|
UidlInfo.pszAccountId != NULL &&
|
|
lstrcmpi(UidlInfo.pszAccountId, m_szAccountId) == 0)
|
|
{
|
|
// Delete this record
|
|
m_pUidlCache->DeleteRecord(&UidlInfo);
|
|
}
|
|
|
|
// Free
|
|
m_pUidlCache->FreeRecord(&UidlInfo);
|
|
}
|
|
|
|
// Purge everthing that matches this
|
|
m_pUidlCache->CloseRowset(&hRowset);
|
|
}
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::OnResponse
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPop3Task::OnResponse(LPPOP3RESPONSE pResponse)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Testing UIDL Command
|
|
if (m_uidlsupport == UIDL_SUPPORT_TESTING_UIDL_COMMAND && POP3_UIDL == pResponse->command)
|
|
{
|
|
#ifdef DEBUG
|
|
pResponse->rIxpResult.hrResult = g_fUidlByTop ? E_FAIL : pResponse->rIxpResult.hrResult;
|
|
#endif
|
|
// Failure ?
|
|
if (FAILED(pResponse->rIxpResult.hrResult))
|
|
{
|
|
// Set Specific Progress
|
|
//CHAR szRes[CCHMAX_RES];
|
|
//LOADSTRING(IDS_SPS_POP3UIDL_UIDL, szRes);
|
|
//m_pUI->SetSpecificProgress(szRes);
|
|
|
|
// Try to top command
|
|
_CatchResult(m_pTransport->CommandTOP(POP3CMD_GET_POPID, 1, 0));
|
|
|
|
// Testing by top command
|
|
m_uidlsupport = UIDL_SUPPORT_TESTING_TOP_COMMAND;
|
|
}
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
// State
|
|
m_state = POP3STATE_GETTINGUIDLS;
|
|
|
|
// Using the UIDL command
|
|
m_uidlsupport = UIDL_SUPPORT_USE_UIDL_COMMAND;
|
|
|
|
// Set Specific Progress
|
|
//CHAR szRes[CCHMAX_RES];
|
|
//LOADSTRING(IDS_SPS_POP3UIDL_UIDL, szRes);
|
|
//m_pUI->SetSpecificProgress(szRes);
|
|
|
|
// Issue full UIDL command
|
|
_CatchResult(m_pTransport->CommandUIDL(POP3CMD_GET_ALL, 0));
|
|
}
|
|
|
|
// Done
|
|
goto exit;
|
|
}
|
|
|
|
// Testing Top Command
|
|
else if (m_uidlsupport == UIDL_SUPPORT_TESTING_TOP_COMMAND && POP3_TOP == pResponse->command)
|
|
{
|
|
#ifdef DEBUG
|
|
pResponse->rIxpResult.hrResult = g_fFailTopCommand ? E_FAIL : pResponse->rIxpResult.hrResult;
|
|
#endif
|
|
// Failure ?
|
|
if (FAILED(pResponse->rIxpResult.hrResult))
|
|
{
|
|
// Disable the leave on server option in the account
|
|
m_pAccount->SetPropDw(AP_POP3_LEAVE_ON_SERVER, FALSE);
|
|
|
|
// Save the Changed
|
|
m_pAccount->SaveChanges();
|
|
|
|
// Failure
|
|
_CatchResult(SP_E_CANTLEAVEONSERVER);
|
|
|
|
// Done
|
|
goto exit;
|
|
}
|
|
|
|
// Using the UIDL command
|
|
else
|
|
{
|
|
// State
|
|
m_state = POP3STATE_GETTINGUIDLS;
|
|
|
|
// Set this and fall through to the switch...
|
|
m_uidlsupport = UIDL_SUPPORT_USE_TOP_COMMAND;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (POP3_RETR == pResponse->command && TRUE == pResponse->fDone && (ULONG)g_ulFailNumber == pResponse->rRetrInfo.dwPopId)
|
|
pResponse->rIxpResult.hrResult = E_FAIL;
|
|
#endif
|
|
|
|
// If Succeeded
|
|
if (FAILED(pResponse->rIxpResult.hrResult))
|
|
{
|
|
// Get Window
|
|
HWND hwndParent;
|
|
if (FAILED(m_pUI->GetWindow(&hwndParent)))
|
|
hwndParent = NULL;
|
|
|
|
// Dont drop if working on POP3_PASS or POP3_USER
|
|
if (POP3_PASS == pResponse->command || POP3_USER == pResponse->command)
|
|
{
|
|
// Log an Error ? If the user's password is not empty or they have fSavePassword enabled
|
|
TaskUtil_FBaseTransportError(IXP_POP3, m_eidEvent, &pResponse->rIxpResult, &m_rServer, NULL, m_pUI, !ISFLAGSET(m_dwFlags, DELIVER_NOUI), hwndParent);
|
|
|
|
// Done
|
|
goto exit;
|
|
}
|
|
|
|
// Command base Failure
|
|
else if (POP3_RETR == pResponse->command)
|
|
{
|
|
// Message Number %d could not be retrieved."
|
|
CHAR szRes[CCHMAX_RES];
|
|
LoadString(g_hLocRes, IDS_SP_E_RETRFAILED, szRes, ARRAYSIZE(szRes));
|
|
|
|
// Format the Error
|
|
CHAR szMsg[CCHMAX_RES + CCHMAX_RES];
|
|
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, pResponse->rRetrInfo.dwPopId);
|
|
|
|
// Fill the IXPRESULT
|
|
IXPRESULT rResult;
|
|
CopyMemory(&rResult, &pResponse->rIxpResult, sizeof(IXPRESULT));
|
|
rResult.pszProblem = szMsg;
|
|
rResult.hrResult = SP_E_POP3_RETR;
|
|
|
|
// Insert the Error
|
|
TaskUtil_FBaseTransportError(IXP_POP3, m_eidEvent, &rResult, &m_rServer, NULL, m_pUI, !ISFLAGSET(m_dwFlags, DELIVER_NOUI), hwndParent);
|
|
|
|
// Close Current Folder
|
|
_CloseFolder();
|
|
|
|
// Retrieve the next message
|
|
_CatchResult(_HrRetrieveNextMessage(pResponse->rRetrInfo.dwPopId));
|
|
|
|
// Done
|
|
goto exit;
|
|
}
|
|
|
|
// Default Error Handler
|
|
else if (TASKRESULT_SUCCESS != _CatchResult(pResponse->command, &pResponse->rIxpResult))
|
|
goto exit;
|
|
}
|
|
|
|
// Handle Command Type
|
|
switch(pResponse->command)
|
|
{
|
|
case POP3_CONNECTED:
|
|
// Notify
|
|
m_pSpoolCtx->Notify(DELIVERY_NOTIFY_CHECKING, 0);
|
|
|
|
// Logon Success
|
|
FLAGSET(m_dwState, POP3STATE_LOGONSUCCESS);
|
|
|
|
// Issue the STAT command
|
|
_CatchResult(m_pTransport->CommandSTAT());
|
|
break;
|
|
|
|
case POP3_STAT:
|
|
// Process the StatCommand
|
|
_CatchResult(_HrOnStatResponse(pResponse));
|
|
break;
|
|
|
|
case POP3_LIST:
|
|
// Process the List Command
|
|
_CatchResult(_HrOnListResponse(pResponse));
|
|
break;
|
|
|
|
case POP3_UIDL:
|
|
// Process the Uidl Command
|
|
_CatchResult(_HrOnUidlResponse(pResponse));
|
|
break;
|
|
|
|
case POP3_TOP:
|
|
// Process the Top Command
|
|
_CatchResult(_HrOnTopResponse(pResponse));
|
|
break;
|
|
|
|
case POP3_RETR:
|
|
// Process Retreive Response
|
|
_CatchResult(_HrOnRetrResponse(pResponse));
|
|
break;
|
|
|
|
case POP3_DELE:
|
|
// Process Delete Response
|
|
_CatchResult(_HrDeleteNextMessage(pResponse->dwPopId));
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_HrLockUidlCache
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrLockUidlCache(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// No Cache yet ?
|
|
if (NULL == m_pUidlCache)
|
|
{
|
|
// Lets the the UID Cache
|
|
CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CUidlCache, (LPVOID *)&m_pUidlCache));
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_HrOnStatResponse
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrOnStatResponse(LPPOP3RESPONSE pResponse)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szRes[CCHMAX_RES];
|
|
CHAR szSize[CCHMAX_RES];
|
|
CHAR szMsg[CCHMAX_RES + CCHMAX_ACCOUNT_NAME + CCHMAX_RES];
|
|
BOOL fFound;
|
|
|
|
// Progress
|
|
LOADSTRING(IDS_SPS_POP3CHECKING, szRes);
|
|
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rServer.szAccount);
|
|
m_pUI->SetGeneralProgress(szMsg);
|
|
|
|
// Update Event Status
|
|
LOADSTRING(IDS_SPS_POP3TOTAL, szRes);
|
|
StrFormatByteSizeA(pResponse->rStatInfo.cbMessages, szSize, ARRAYSIZE(szSize));
|
|
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rServer.szAccount, pResponse->rStatInfo.cMessages, szSize);
|
|
m_pUI->UpdateEventState(m_eidEvent, -1, szMsg, NULL);
|
|
|
|
// No New Messages ?
|
|
if (0 == pResponse->rStatInfo.cMessages)
|
|
{
|
|
m_pTransport->Disconnect();
|
|
goto exit;
|
|
}
|
|
|
|
// Save total byte count
|
|
m_rMetrics.cbTotal = pResponse->rStatInfo.cbMessages;
|
|
|
|
// Assume no clean cache
|
|
FLAGCLEAR(m_dwState, POP3STATE_CLEANUPCACHE);
|
|
|
|
// If Leave on Server, return TRUE
|
|
if (ISFLAGSET(m_dwState, POP3STATE_LEAVEONSERVER))
|
|
{
|
|
// Lock the tree
|
|
CHECKHR(hr = _HrLockUidlCache());
|
|
|
|
// We will need to get the uidls
|
|
FLAGSET(m_dwState, POP3STATE_GETUIDLS);
|
|
}
|
|
|
|
// Okay, we may still need to get the uidls if
|
|
else
|
|
{
|
|
// Locals
|
|
UIDLRECORD UidlInfo={0};
|
|
HROWSET hRowset=NULL;
|
|
|
|
// Lock the tree
|
|
CHECKHR(hr = _HrLockUidlCache());
|
|
|
|
// Create a Rowset
|
|
CHECKHR(hr = m_pUidlCache->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset));
|
|
|
|
// Delete Enumeration
|
|
while (S_OK == m_pUidlCache->QueryRowset(hRowset, 1, (LPVOID *)&UidlInfo, NULL))
|
|
{
|
|
// Delete this puppy ?
|
|
if (lstrcmpi(UidlInfo.pszServer, m_rServer.szServerName) == 0 &&
|
|
UidlInfo.pszAccountId != NULL &&
|
|
lstrcmpi(UidlInfo.pszAccountId, m_szAccountId) == 0)
|
|
{
|
|
// Get Uidls from the server
|
|
FLAGSET(m_dwState, POP3STATE_GETUIDLS);
|
|
|
|
// Cleanup the uidl cache when complete
|
|
FLAGSET(m_dwState, POP3STATE_CLEANUPCACHE);
|
|
|
|
// Free
|
|
m_pUidlCache->FreeRecord(&UidlInfo);
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
|
|
// Free
|
|
m_pUidlCache->FreeRecord(&UidlInfo);
|
|
}
|
|
|
|
// Purge everthing that matches this
|
|
m_pUidlCache->CloseRowset(&hRowset);
|
|
}
|
|
|
|
// Allocate the Item Table
|
|
CHECKALLOC(m_rTable.prgItem = (LPPOP3ITEM)g_pMalloc->Alloc(sizeof(POP3ITEM) * pResponse->rStatInfo.cMessages));
|
|
|
|
// Set Counts
|
|
m_rTable.cAlloc = m_rTable.cItems = pResponse->rStatInfo.cMessages;
|
|
|
|
// Zeroinit Array
|
|
ZeroMemory(m_rTable.prgItem, sizeof(POP3ITEM) * pResponse->rStatInfo.cMessages);
|
|
|
|
// Initialize Progress
|
|
m_dwProgressMax = m_rTable.cItems;
|
|
|
|
// If we need to get the UIDL list, lets test for it...
|
|
if (ISFLAGSET(m_dwState, POP3STATE_GETUIDLS))
|
|
m_dwProgressMax += (m_rTable.cItems * 4);
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
// Release the Uidl Cache Lock
|
|
SafeRelease(m_pUidlCache);
|
|
}
|
|
|
|
// Progress Current
|
|
m_dwProgressCur = 0;
|
|
|
|
// Predownload rules increases mprogress
|
|
if (ISFLAGSET(m_dwState, POP3STATE_PDR))
|
|
m_dwProgressMax += m_rTable.cItems;
|
|
|
|
// Set Specific Progress
|
|
LOADSTRING(IDS_SPS_POP3STAT, szRes);
|
|
m_pUI->SetSpecificProgress(szRes);
|
|
|
|
// Set the uidl command to see if the user supports it
|
|
CHECKHR(hr = m_pTransport->CommandLIST(POP3CMD_GET_ALL, 0));
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_HrOnTopResponse
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrOnTopResponse(LPPOP3RESPONSE pResponse)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD dwPopId=pResponse->rTopInfo.dwPopId;
|
|
LPPOP3ITEM pItem;
|
|
IMimePropertySet *pHeader=NULL;
|
|
CHAR szRes[CCHMAX_RES];
|
|
CHAR szMsg[CCHMAX_RES+CCHMAX_RES];
|
|
|
|
// Validate the Item
|
|
Assert(ISVALIDPOPID(dwPopId));
|
|
|
|
// Get the current item
|
|
pItem = ITEMFROMPOPID(dwPopId);
|
|
|
|
// We should assume that were downloading this item at this point
|
|
Assert(ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD));
|
|
|
|
// No stream yet ?
|
|
if (NULL == m_pStream)
|
|
{
|
|
// Create a Stream
|
|
CHECKHR(hr = MimeOleCreateVirtualStream(&m_pStream));
|
|
}
|
|
|
|
// If this infor is valid
|
|
if (TRUE == pResponse->fValidInfo)
|
|
{
|
|
// Write the data into the stream
|
|
CHECKHR(hr = m_pStream->Write(pResponse->rTopInfo.pszLines, pResponse->rTopInfo.cbLines, NULL));
|
|
}
|
|
|
|
// Is the command done ?
|
|
if (TRUE == pResponse->fDone)
|
|
{
|
|
// Commit the stream
|
|
CHECKHR(hr = m_pStream->Commit(STGC_DEFAULT));
|
|
|
|
// Getting UIDL
|
|
if (POP3STATE_GETTINGUIDLS == m_state)
|
|
{
|
|
// Better not have a uidl yet
|
|
Assert(NULL == pItem->pszUidl);
|
|
|
|
// Increment Progress
|
|
m_dwProgressCur+=2;
|
|
|
|
// Set Specific Progress
|
|
//LOADSTRING(IDS_SPS_POP3UIDL_TOP, szRes);
|
|
//wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, dwPopId, m_rTable.cItems);
|
|
//m_pUI->SetSpecificProgress(szMsg);
|
|
|
|
// Get Uidl From HeaderStream
|
|
CHECKHR(hr = _HrGetUidlFromHeaderStream(m_pStream, &pItem->pszUidl, &pHeader));
|
|
}
|
|
|
|
// Otherwise, just increment one
|
|
else
|
|
m_dwProgressCur++;
|
|
|
|
// Show Progress
|
|
_DoProgress();
|
|
|
|
// If we plan on downloading this thing
|
|
if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD) && ISFLAGSET(m_dwState, POP3STATE_PDR))
|
|
{
|
|
// Check Inbox Rule for this item
|
|
_ComputeItemInboxRule(pItem, m_pStream, pHeader, NULL, TRUE);
|
|
}
|
|
|
|
// Release the current stream
|
|
SafeRelease(m_pStream);
|
|
|
|
// Totally Done ?
|
|
if (ISLASTPOPID(dwPopId))
|
|
{
|
|
// Start the download process
|
|
CHECKHR(hr = _HrStartDownloading());
|
|
}
|
|
|
|
// Otherwise, lets get the top of the next item
|
|
else if (POP3STATE_GETTINGUIDLS == m_state)
|
|
{
|
|
// Next Top
|
|
CHECKHR(hr = m_pTransport->CommandTOP(POP3CMD_GET_POPID, dwPopId + 1, 0));
|
|
}
|
|
|
|
// Otherwise, find next message marked for download to check against predownload rules
|
|
else
|
|
{
|
|
// NextTopForInboxRule
|
|
CHECKHR(hr = _HrNextTopForInboxRule(dwPopId));
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pHeader);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_HrOnUidlResponse
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrOnUidlResponse(LPPOP3RESPONSE pResponse)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD dwPopId=pResponse->rUidlInfo.dwPopId;
|
|
LPPOP3ITEM pItem;
|
|
CHAR szRes[CCHMAX_RES];
|
|
CHAR szMsg[CCHMAX_RES + CCHMAX_RES];
|
|
|
|
// Is the command done ?
|
|
if (TRUE == pResponse->fDone)
|
|
{
|
|
// If there are pre-download rules that are not size only, get all the tops
|
|
if (ISFLAGSET(m_dwState, POP3STATE_PDR))
|
|
{
|
|
// Clear the state
|
|
m_state = POP3STATE_NONE;
|
|
|
|
// NextTopForInboxRule
|
|
CHECKHR(hr = _HrStartServerSideRules());
|
|
}
|
|
|
|
// Otherwise, do the list command
|
|
else
|
|
{
|
|
// Start the download process
|
|
CHECKHR(hr = _HrStartDownloading());
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
// Make Sure PopId is on current iitem
|
|
Assert(ISVALIDPOPID(dwPopId) && pResponse->rUidlInfo.pszUidl);
|
|
|
|
// Get Current Item
|
|
pItem = ITEMFROMPOPID(dwPopId);
|
|
|
|
// Duplicate the Uidl
|
|
CHECKALLOC(pItem->pszUidl = PszDupA(pResponse->rUidlInfo.pszUidl));
|
|
|
|
// Increment Progress
|
|
m_dwProgressCur+=1;
|
|
|
|
// Do progress
|
|
_DoProgress();
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_HrOnListResponse
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrOnListResponse(LPPOP3RESPONSE pResponse)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD dwPopId=pResponse->rListInfo.dwPopId;
|
|
LPPOP3ITEM pItem;
|
|
|
|
// Is the command done ?
|
|
if (TRUE == pResponse->fDone)
|
|
{
|
|
// If we need to get the UIDL list, lets test for it...
|
|
if (ISFLAGSET(m_dwState, POP3STATE_GETUIDLS))
|
|
{
|
|
// Set the uidl command to see if the user supports it
|
|
CHECKHR(hr = m_pTransport->CommandUIDL(POP3CMD_GET_POPID, 1));
|
|
|
|
// Set State
|
|
m_uidlsupport = UIDL_SUPPORT_TESTING_UIDL_COMMAND;
|
|
}
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
// Predownload rules increases mprogress
|
|
if (ISFLAGSET(m_dwState, POP3STATE_PDR))
|
|
{
|
|
// Clear the state
|
|
m_state = POP3STATE_NONE;
|
|
|
|
// NextTopForInboxRule
|
|
CHECKHR(hr = _HrStartServerSideRules());
|
|
}
|
|
|
|
// Otherwise, do the list command
|
|
else
|
|
{
|
|
// Start the download process
|
|
CHECKHR(hr = _HrStartDownloading());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
// Make Sure PopId is on current iitem
|
|
if(!ISVALIDPOPID(dwPopId))
|
|
return(E_FAIL);
|
|
|
|
// Get Current Item
|
|
pItem = ITEMFROMPOPID(dwPopId);
|
|
|
|
// Duplicate the Uidl
|
|
pItem->cbSize = pResponse->rListInfo.cbSize;
|
|
|
|
// Assume we will download it
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD | POP3ITEM_DELETEOFFSERVER);
|
|
|
|
// Increment Progress
|
|
m_dwProgressCur++;
|
|
|
|
// Do progress
|
|
_DoProgress();
|
|
|
|
// This yields so that other threads can execute
|
|
//Sleep(0);
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_HrStartDownloading
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrStartDownloading(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG i;
|
|
CHAR szRes[CCHMAX_RES];
|
|
CHAR szSize1[CCHMAX_RES];
|
|
CHAR szSize2[CCHMAX_RES];
|
|
CHAR szMsg[CCHMAX_RES + CCHMAX_ACCOUNT_NAME + CCHMAX_RES];
|
|
|
|
// State
|
|
Assert(m_rMetrics.cLeftByRule == 0 && m_rMetrics.cDownload == 0 && m_rMetrics.cDelete == 0 && m_rMetrics.cbDownload == 0);
|
|
|
|
// If we got uidls, then lets do the cache compare lookup
|
|
if (!ISFLAGSET(m_dwState, POP3STATE_PDR) && ISFLAGSET(m_dwState, POP3STATE_GETUIDLS))
|
|
{
|
|
// Returns FALSE if user cancel
|
|
CHECKHR(hr = _HrDoUidlSynchronize());
|
|
}
|
|
|
|
// Compute number of new messages to download
|
|
for (i=0; i<m_rTable.cItems; i++)
|
|
{
|
|
// Download ?
|
|
if (ISFLAGSET(m_rTable.prgItem[i].dwFlags, POP3ITEM_DOWNLOAD))
|
|
{
|
|
// Increment total number of bytes we will download
|
|
m_rMetrics.cbDownload += m_rTable.prgItem[i].cbSize;
|
|
|
|
// Increment count of messages we will download
|
|
m_rMetrics.cDownload++;
|
|
|
|
// Set running total in pop3 item
|
|
m_rTable.prgItem[i].dwProgressCur = m_rMetrics.cbDownload;
|
|
}
|
|
|
|
// Count Left By Rule in case we don't download anything
|
|
else if (ISFLAGSET(m_rTable.prgItem[i].dwFlags, POP3ITEM_LEFTBYRULE))
|
|
m_rMetrics.cLeftByRule++;
|
|
|
|
// Delete
|
|
if (ISFLAGSET(m_rTable.prgItem[i].dwFlags, POP3ITEM_DELETEOFFSERVER))
|
|
{
|
|
// Number of messages we will delete
|
|
m_rMetrics.cDelete++;
|
|
}
|
|
}
|
|
|
|
// Update Event Status
|
|
LOADSTRING(IDS_SPS_POP3NEW, szRes);
|
|
StrFormatByteSizeA(m_rMetrics.cbDownload, szSize1, ARRAYSIZE(szSize1));
|
|
StrFormatByteSizeA(m_rMetrics.cbTotal, szSize2, ARRAYSIZE(szSize2));
|
|
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rServer.szAccount, m_rMetrics.cDownload, szSize1, m_rTable.cItems, szSize2);
|
|
m_pUI->UpdateEventState(m_eidEvent, -1, szMsg, NULL);
|
|
|
|
// New Messages ?
|
|
if (m_rMetrics.cDownload > 0)
|
|
{
|
|
// Setup Progress
|
|
m_rMetrics.iCurrent = 0;
|
|
m_wProgress = 0;
|
|
m_dwProgressCur = 0;
|
|
m_dwProgressMax = m_rMetrics.cbDownload;
|
|
m_pUI->SetProgressRange(100);
|
|
m_rMetrics.cLeftByRule = 0;
|
|
|
|
// Notify
|
|
m_pSpoolCtx->Notify(DELIVERY_NOTIFY_RECEIVING, 0);
|
|
|
|
// State
|
|
m_state = POP3STATE_DOWNLOADING;
|
|
|
|
// Open the Inbox
|
|
Assert(NULL == m_pInbox);
|
|
CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreInbox, (LPVOID *)&m_pInbox));
|
|
|
|
// Download the Next Message
|
|
CHECKHR(hr = _HrRetrieveNextMessage(0));
|
|
}
|
|
|
|
// Otherwise if cDelete
|
|
else if (m_rMetrics.cDelete > 0)
|
|
{
|
|
// Delete the Next Message
|
|
CHECKHR(hr = _HrStartDeleteCycle());
|
|
}
|
|
|
|
// Otherwise, disconnect
|
|
else
|
|
{
|
|
// Disconnect
|
|
CHECKHR(hr = m_pTransport->Disconnect());
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_DoProgress
|
|
// --------------------------------------------------------------------------------
|
|
void CPop3Task::_DoProgress(void)
|
|
{
|
|
// Compute Current Progress Index
|
|
WORD wProgress;
|
|
if (m_dwProgressMax > 0)
|
|
wProgress = (WORD)((m_dwProgressCur * 100) / m_dwProgressMax);
|
|
else
|
|
wProgress = 0;
|
|
|
|
// Only if greater than
|
|
if (wProgress > m_wProgress)
|
|
{
|
|
// Compute Delta
|
|
WORD wDelta = wProgress - m_wProgress;
|
|
|
|
// Progress Delta
|
|
if (wDelta > 0)
|
|
{
|
|
// Incremenet Progress
|
|
m_pUI->IncrementProgress(wDelta);
|
|
|
|
// Increment my wProgress
|
|
m_wProgress += wDelta;
|
|
|
|
// Don't go above 100
|
|
if (m_wProgress > 100)
|
|
m_wProgress = 100;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_HrGetUidlFromHeaderStream
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrGetUidlFromHeaderStream(IStream *pStream, LPSTR *ppszUidl, IMimePropertySet **ppHeader)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
IMimePropertySet *pHeader=NULL;
|
|
|
|
// Invalid Arg
|
|
Assert(pStream && ppszUidl);
|
|
|
|
// Init
|
|
*ppszUidl = NULL;
|
|
*ppHeader = NULL;
|
|
|
|
// Rewind Header Stream
|
|
CHECKHR(hr = HrRewindStream(pStream));
|
|
|
|
// Load the header
|
|
CHECKHR(hr = MimeOleCreatePropertySet(NULL, &pHeader));
|
|
|
|
// Load the header
|
|
CHECKHR(hr = pHeader->Load(pStream));
|
|
|
|
// Get the message Id...
|
|
if (FAILED(MimeOleGetPropA(pHeader, PIDTOSTR(PID_HDR_MESSAGEID), NOFLAGS, ppszUidl)))
|
|
{
|
|
// Try to use the received headers...
|
|
MimeOleGetPropA(pHeader, PIDTOSTR(PID_HDR_RECEIVED), NOFLAGS, ppszUidl);
|
|
}
|
|
|
|
// Returen the Header ?
|
|
*ppHeader = pHeader;
|
|
pHeader = NULL;
|
|
|
|
exit:
|
|
// Release the text stream
|
|
SafeRelease(pHeader);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_HrDoUidlSynchronize
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrDoUidlSynchronize(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPPOP3ITEM pItem;
|
|
ULONG i,j;
|
|
|
|
#ifdef DEBUG
|
|
DWORD dwTick = GetTickCount();
|
|
#endif
|
|
|
|
// Uidl Sync
|
|
m_state = POP3STATE_UIDLSYNC;
|
|
|
|
// Compute number of new messages to download
|
|
for (i=0,j=0; i<m_rTable.cItems; i++,j++)
|
|
{
|
|
// Readability
|
|
pItem = &m_rTable.prgItem[i];
|
|
|
|
// Get Uidl Falgs
|
|
_GetItemFlagsFromUidl(pItem);
|
|
|
|
// Progress
|
|
m_dwProgressCur+=3;
|
|
|
|
// Do Progress
|
|
_DoProgress();
|
|
|
|
// Pump Message
|
|
if (j >= 10)
|
|
{
|
|
//Sleep(0);
|
|
m_pSpoolCtx->PumpMessages();
|
|
j = 0;
|
|
}
|
|
|
|
// Cancel
|
|
if (ISFLAGSET(m_dwState, POP3STATE_CANCELPENDING))
|
|
{
|
|
// Change State
|
|
m_state = POP3STATE_NONE;
|
|
|
|
// Drop the connection
|
|
if (m_pTransport)
|
|
m_pTransport->DropConnection();
|
|
|
|
// User Cancel
|
|
hr = IXP_E_USER_CANCEL;
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
|
|
// OnDisconnect has been called
|
|
if (ISFLAGSET(m_dwState, POP3STATE_ONDISCONNECT))
|
|
{
|
|
// Change State
|
|
m_state = POP3STATE_NONE;
|
|
|
|
// Fake the call to OnStatus
|
|
OnStatus(IXP_DISCONNECTED, NULL);
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Uidl Sync
|
|
m_state = POP3STATE_NONE;
|
|
|
|
// Cool tracing
|
|
#ifdef DEBUG
|
|
DebugTrace("CPop3Task::_HrDoUidlSynchronize took %d Milli-Seconds\n", GetTickCount() - dwTick);
|
|
#endif // DEBUG
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_GetItemFlagsFromUidl
|
|
// --------------------------------------------------------------------------------
|
|
void CPop3Task::_GetItemFlagsFromUidl(LPPOP3ITEM pItem)
|
|
{
|
|
// Locals
|
|
UIDLRECORD rUidlInfo={0};
|
|
|
|
// Invalid Arg
|
|
Assert(pItem && m_pUidlCache);
|
|
|
|
// If we are already not going to download this item, then return
|
|
if (!ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD))
|
|
return;
|
|
|
|
// If there is no UIDL, we will download it...
|
|
if (NULL == pItem->pszUidl || '\0' == *pItem->pszUidl)
|
|
return;
|
|
|
|
// If not leaving on server, mark for delete
|
|
if (ISFLAGSET(m_dwState, POP3STATE_LEAVEONSERVER))
|
|
FLAGCLEAR(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER);
|
|
|
|
// Set Search Info
|
|
rUidlInfo.pszUidl = pItem->pszUidl;
|
|
rUidlInfo.pszServer = m_rServer.szServerName;
|
|
rUidlInfo.pszAccountId = m_szAccountId;
|
|
|
|
// This yields so that other threads can execute
|
|
//Sleep(0);
|
|
|
|
// Exist - if not, lets download it...
|
|
if (DB_S_NOTFOUND == m_pUidlCache->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &rUidlInfo, NULL))
|
|
{
|
|
if (ISFLAGSET(m_dwState, POP3STATE_LEAVEONSERVER))
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_CACHEUIDL);
|
|
return;
|
|
}
|
|
|
|
// Don't download it again
|
|
FLAGCLEAR(pItem->dwFlags, POP3ITEM_DOWNLOAD | POP3ITEM_DELETEOFFSERVER);
|
|
|
|
// If the message has been download, lets decide if we should delete it
|
|
if (rUidlInfo.fDownloaded)
|
|
{
|
|
// Expired or deleted from client, or remove when deleted from delete items folder.
|
|
if (!ISFLAGSET(m_dwState, POP3STATE_LEAVEONSERVER) || _FUidlExpired(&rUidlInfo) ||
|
|
(ISFLAGSET(m_dwState, POP3STATE_SYNCDELETED) && rUidlInfo.fDeleted))
|
|
{
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_DELETECACHEDUIDL);
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER);
|
|
}
|
|
}
|
|
|
|
// Free The Dude
|
|
m_pUidlCache->FreeRecord(&rUidlInfo);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_FUidlExpired
|
|
// ------------------------------------------------------------------------------------
|
|
BOOL CPop3Task::_FUidlExpired(LPUIDLRECORD pUidlInfo)
|
|
{
|
|
// Locals
|
|
SYSTEMTIME st;
|
|
FILETIME ft;
|
|
ULONG ulSeconds;
|
|
|
|
// If not expiring, return FALSE
|
|
if (!ISFLAGSET(m_dwState, POP3STATE_DELETEEXPIRED))
|
|
return FALSE;
|
|
|
|
// Get Current Time
|
|
GetSystemTime(&st);
|
|
SystemTimeToFileTime(&st, &ft);
|
|
|
|
// Convert st to seconds since Jan 1, 1996
|
|
ulSeconds = UlDateDiff(&pUidlInfo->ftDownload, &ft);
|
|
|
|
// Greater than expire days
|
|
if ((ulSeconds / SECONDS_INA_DAY) >= m_dwExpireDays)
|
|
return TRUE;
|
|
|
|
// Done
|
|
return FALSE;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_ComputeItemInboxRule
|
|
// ------------------------------------------------------------------------------------
|
|
void CPop3Task::_ComputeItemInboxRule(LPPOP3ITEM pItem, LPSTREAM pStream,
|
|
IMimePropertySet *pHeaderIn, IMimeMessage * pIMMsg, BOOL fServerRules)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
IMimePropertySet *pHeader=NULL;
|
|
ACT_ITEM *pActions=NULL;
|
|
ULONG cActions=0;
|
|
|
|
// We should not have checked the inbox rule for this item yet
|
|
Assert(m_pIExecRules && pItem && (pStream || pHeaderIn || pIMMsg));
|
|
Assert(ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD) && !ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE));
|
|
|
|
// We've checked this inbox rule
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE);
|
|
|
|
// Assume we don't find an inbox rule for this item
|
|
FLAGCLEAR(pItem->dwFlags, POP3ITEM_HASINBOXRULE);
|
|
|
|
// Header was passed in ?
|
|
if (pHeaderIn)
|
|
{
|
|
pHeader = pHeaderIn;
|
|
pHeader->AddRef();
|
|
}
|
|
|
|
// Do we already have a Mime message?
|
|
else if (pIMMsg)
|
|
{
|
|
CHECKHR(hr = pIMMsg->BindToObject(HBODY_ROOT, IID_IMimePropertySet, (LPVOID *)&pHeader));
|
|
}
|
|
|
|
// Otherwise, load the stream in to a header
|
|
else
|
|
{
|
|
// Rewind Header Stream
|
|
CHECKHR(hr = HrRewindStream(pStream));
|
|
|
|
// Load the header
|
|
CHECKHR(hr = MimeOleCreatePropertySet(NULL, &pHeader));
|
|
|
|
// Load the header
|
|
CHECKHR(hr = pHeader->Load(pStream));
|
|
}
|
|
|
|
// Check the inbox rule
|
|
|
|
// If we have pre-download rules,
|
|
if ((FALSE != fServerRules) && ISFLAGSET(m_dwState, POP3STATE_PDR))
|
|
{
|
|
// Check to see if we have any actions
|
|
hr = m_pIExecRules->ExecuteRules(ERF_ONLYSERVER | ERF_SKIPPARTIALS, m_szAccountId, NULL, NULL, pHeader, NULL, pItem->cbSize, &pActions, &cActions);
|
|
|
|
// If we don't have any actions, or
|
|
// this isn't a server side rule
|
|
if ((S_OK != hr) ||
|
|
((ACT_TYPE_DONTDOWNLOAD != pActions[0].type) && (ACT_TYPE_DELETESERVER != pActions[0].type)))
|
|
{
|
|
// Make sure we can check rules again
|
|
FLAGCLEAR(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE);
|
|
hr = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
// _OnKnownRuleActions
|
|
_OnKnownRuleActions(pItem, pActions, cActions, fServerRules);
|
|
}
|
|
}
|
|
// If we don't have pre-download rules, then check rules normally.
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
|
|
// Do block sender first
|
|
if (m_pIRuleSender)
|
|
{
|
|
hr = m_pIRuleSender->Evaluate(m_szAccountId, NULL, NULL, pHeader, pIMMsg, pItem->cbSize, &pActions, &cActions);
|
|
}
|
|
|
|
// If we aren't blocking the sender
|
|
if (S_OK != hr)
|
|
{
|
|
hr = m_pIExecRules->ExecuteRules(ERF_SKIPPARTIALS, m_szAccountId, NULL, NULL, pHeader, pIMMsg, pItem->cbSize, &pActions, &cActions);
|
|
}
|
|
|
|
// If we don't have a rule match
|
|
if ((S_OK != hr) && (NULL != m_pIRuleJunk))
|
|
{
|
|
hr = m_pIRuleJunk->Evaluate(m_szAccountId, NULL, NULL, pHeader, pIMMsg, pItem->cbSize, &pActions, &cActions);
|
|
}
|
|
|
|
// Did we have some actions to perform...
|
|
if (S_OK == hr)
|
|
{
|
|
// This item has an inbox rule
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE);
|
|
|
|
// Save off the actions list
|
|
pItem->pActList = pActions;
|
|
pActions = NULL;
|
|
pItem->cActList = cActions;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
RuleUtil_HrFreeActionsItem(pActions, cActions);
|
|
SafeMemFree(pActions);
|
|
SafeRelease(pHeader);
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_OnKnownRuleActions
|
|
// ------------------------------------------------------------------------------------
|
|
void CPop3Task::_OnKnownRuleActions(LPPOP3ITEM pItem, ACT_ITEM * pActions, ULONG cActions, BOOL fServerRules)
|
|
{
|
|
// This item has an inbox rule
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE);
|
|
|
|
// If Action is to delete off sever
|
|
if ((FALSE != fServerRules) && (1 == cActions))
|
|
{
|
|
if (ACT_TYPE_DELETESERVER == pActions->type)
|
|
{
|
|
// Don't Cache the UIDL
|
|
FLAGCLEAR(pItem->dwFlags, POP3ITEM_DELETECACHEDUIDL | POP3ITEM_CACHEUIDL | POP3ITEM_DOWNLOAD);
|
|
|
|
// Delete off the server
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER | POP3ITEM_DELEBYRULE);
|
|
}
|
|
|
|
// Otherwise, don't download the message
|
|
else if (ACT_TYPE_DONTDOWNLOAD == pActions->type)
|
|
{
|
|
// Download It and Don't download it and delete it
|
|
FLAGCLEAR(pItem->dwFlags, POP3ITEM_DOWNLOAD | POP3ITEM_DELETEOFFSERVER);
|
|
|
|
// Set the Flag
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_LEFTBYRULE);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_HrStartServerSideRules
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrStartServerSideRules(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG i;
|
|
|
|
// If we got uidls, then lets do the cache compare lookup
|
|
if (ISFLAGSET(m_dwState, POP3STATE_GETUIDLS))
|
|
{
|
|
// Returns FALSE if user cancel
|
|
CHECKHR(hr = _HrDoUidlSynchronize());
|
|
}
|
|
|
|
// Check State
|
|
m_rMetrics.cTopMsgs = 0;
|
|
m_rMetrics.iCurrent = 0;
|
|
|
|
// Count the number of messages we will have to get a top for
|
|
for (i=0; i<m_rTable.cItems; i++)
|
|
{
|
|
if (ISFLAGSET(m_rTable.prgItem[i].dwFlags, POP3ITEM_DOWNLOAD))
|
|
m_rMetrics.cTopMsgs++;
|
|
}
|
|
|
|
// Adjust progress
|
|
m_dwProgressMax -= m_rTable.cItems;
|
|
|
|
// Add m_rMetrics.cTopMsgs back onto m_dwProgressMax
|
|
m_dwProgressMax += m_rMetrics.cTopMsgs;
|
|
|
|
// Do the first one
|
|
CHECKHR(hr = _HrNextTopForInboxRule(0));
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_HrNextTopForInboxRule
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrNextTopForInboxRule(DWORD dwPopIdCurrent)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szRes[CCHMAX_RES];
|
|
CHAR szMsg[CCHMAX_RES+CCHMAX_RES];
|
|
|
|
// State should be none
|
|
Assert(POP3STATE_NONE == m_state);
|
|
|
|
// Increment iCurrent
|
|
m_rMetrics.iCurrent++;
|
|
|
|
// Set Specific Progress
|
|
//LOADSTRING(IDS_SPS_PREDOWNRULES, szRes);
|
|
//wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rMetrics.iCurrent, m_rMetrics.cTopMsgs);
|
|
//m_pUI->SetSpecificProgress(szMsg);
|
|
|
|
// Loop until we find the next message that we are downloading
|
|
while(1)
|
|
{
|
|
// Incremenet dwPopIdCurrent
|
|
dwPopIdCurrent++;
|
|
|
|
// Last PopId, start the download
|
|
if (dwPopIdCurrent > m_rTable.cItems)
|
|
{
|
|
// Start the download process
|
|
CHECKHR(hr = _HrStartDownloading());
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
|
|
// If we are still downloading this item
|
|
if (ISFLAGSET(m_rTable.prgItem[dwPopIdCurrent - 1].dwFlags, POP3ITEM_DOWNLOAD))
|
|
{
|
|
// Try to top command
|
|
CHECKHR(hr = m_pTransport->CommandTOP(POP3CMD_GET_POPID, dwPopIdCurrent, 0));
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_HrRetrieveNextMessage
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrRetrieveNextMessage(DWORD dwPopIdCurrent)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szRes[CCHMAX_RES];
|
|
CHAR szMsg[CCHMAX_RES + CCHMAX_RES];
|
|
LPPOP3ITEM pItem;
|
|
|
|
// Cancel Pending...
|
|
if (ISFLAGSET(m_dwState, POP3STATE_CANCELPENDING))
|
|
{
|
|
// Start the Delete Cycle
|
|
CHECKHR(hr = _HrStartDeleteCycle());
|
|
|
|
// Done
|
|
goto exit;
|
|
}
|
|
|
|
// Adjust progress
|
|
if (dwPopIdCurrent > 0)
|
|
{
|
|
// Get current item
|
|
pItem = ITEMFROMPOPID(dwPopIdCurrent);
|
|
Assert(ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD));
|
|
|
|
// Adjust progress Cur
|
|
m_dwProgressCur = pItem->dwProgressCur;
|
|
|
|
// Do progress
|
|
_DoProgress();
|
|
}
|
|
|
|
// Loop until we find the next message that we are downloading
|
|
while(1)
|
|
{
|
|
// Incremenet dwPopIdCurrent
|
|
dwPopIdCurrent++;
|
|
|
|
// Last PopId, start the download
|
|
if (dwPopIdCurrent > m_rTable.cItems)
|
|
{
|
|
// Start the download process
|
|
CHECKHR(hr = _HrStartDeleteCycle());
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
|
|
// Readability
|
|
pItem = ITEMFROMPOPID(dwPopIdCurrent);
|
|
|
|
// Download this message ?
|
|
if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD))
|
|
{
|
|
// Increment m_rMetrics.iCurrent
|
|
m_rMetrics.iCurrent++;
|
|
|
|
// Status
|
|
LOADSTRING(idsInetMailRecvStatus, szRes);
|
|
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rMetrics.iCurrent, m_rMetrics.cDownload);
|
|
m_pUI->SetSpecificProgress(szMsg);
|
|
|
|
// Retrieve this item
|
|
CHECKHR(hr = m_pTransport->CommandRETR(POP3CMD_GET_POPID, dwPopIdCurrent));
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
|
|
// Count Number of items left by rule
|
|
else if (ISFLAGSET(pItem->dwFlags, POP3ITEM_LEFTBYRULE))
|
|
m_rMetrics.cLeftByRule++;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_HrOnRetrResponse
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrOnRetrResponse(LPPOP3RESPONSE pResponse)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD dwPopId=pResponse->rRetrInfo.dwPopId;
|
|
LPPOP3ITEM pItem;
|
|
|
|
// Get Current Item
|
|
pItem = ITEMFROMPOPID(dwPopId);
|
|
|
|
// Validate the item
|
|
Assert(ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD));
|
|
|
|
// Valid info
|
|
if (TRUE == pResponse->fValidInfo)
|
|
{
|
|
// Progress...
|
|
m_dwProgressCur += pResponse->rRetrInfo.cbLines;
|
|
|
|
// Don't let progress grow beyond what we estimated the ceiling for this message
|
|
if (m_dwProgressCur > pItem->dwProgressCur)
|
|
m_dwProgressCur = pItem->dwProgressCur;
|
|
|
|
// Show Progress
|
|
_DoProgress();
|
|
|
|
// Do we have a destination yet ?
|
|
if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DESTINATIONKNOWN))
|
|
{
|
|
// We better have a stream
|
|
Assert(m_rFolder.pStream && m_rFolder.pFolder);
|
|
|
|
// Simply write the data
|
|
CHECKHR(hr = m_rFolder.pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL));
|
|
}
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
// If there are no inbox rules
|
|
if (ISFLAGSET(m_dwState, POP3STATE_NOPOSTRULES))
|
|
{
|
|
// Use the Inbox
|
|
CHECKHR(hr = _HrOpenFolder(m_pInbox));
|
|
|
|
// Destination is known
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_DESTINATIONKNOWN);
|
|
|
|
// Simply write the data
|
|
CHECKHR(hr = m_rFolder.pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL));
|
|
}
|
|
|
|
// else if we have only body rules...
|
|
else if (ISFLAGSET(m_dwState, POP3STATE_BODYRULES))
|
|
{
|
|
// No stream yet ?
|
|
if (NULL == m_pStream)
|
|
{
|
|
// Create a Stream
|
|
CHECKHR(hr = MimeOleCreateVirtualStream(&m_pStream));
|
|
}
|
|
|
|
// Simply write the data
|
|
CHECKHR(hr = m_pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL));
|
|
}
|
|
|
|
// Otherwise...
|
|
else
|
|
{
|
|
// Have I checked the inbox rule for this item yet ?
|
|
if (!ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE))
|
|
{
|
|
// No stream yet ?
|
|
if (NULL == m_pStream)
|
|
{
|
|
// Create a Stream
|
|
CHECKHR(hr = MimeOleCreateVirtualStream(&m_pStream));
|
|
}
|
|
|
|
// Simply write the data
|
|
CHECKHR(hr = m_pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL));
|
|
|
|
// If I have the header, check the inbox rule
|
|
if (TRUE == pResponse->rRetrInfo.fHeader)
|
|
{
|
|
// Commit the stream
|
|
CHECKHR(hr = m_pStream->Commit(STGC_DEFAULT));
|
|
|
|
// Check Inbox Rule for this item
|
|
_ComputeItemInboxRule(pItem, m_pStream, NULL, NULL, FALSE);
|
|
}
|
|
}
|
|
|
|
// Have I checked the inbox rule for this item yet ?
|
|
if (ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE))
|
|
{
|
|
// Locals
|
|
IMessageFolder *pFolder;
|
|
|
|
// We must have the header
|
|
IxpAssert(pResponse->rRetrInfo.fHeader);
|
|
|
|
// Did we find an Inbox Rule
|
|
if (ISFLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE) && S_OK == _GetMoveFolder(pItem, &pFolder))
|
|
{
|
|
// Use the Inbox
|
|
CHECKHR(hr = _HrOpenFolder(pFolder));
|
|
}
|
|
|
|
// No Move To, just use the inbox
|
|
else
|
|
{
|
|
// Use the Inbox
|
|
CHECKHR(hr = _HrOpenFolder(m_pInbox));
|
|
}
|
|
|
|
// Destination is known
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_DESTINATIONKNOWN);
|
|
|
|
// If m_pStream, then copy this to the folder
|
|
if (m_pStream)
|
|
{
|
|
// Rewind the stream
|
|
CHECKHR(hr = HrRewindStream(m_pStream));
|
|
|
|
// Copy this stream to the folder
|
|
CHECKHR(hr = HrCopyStream(m_pStream, m_rFolder.pStream, NULL));
|
|
|
|
// Relase m_pStream
|
|
SafeRelease(m_pStream);
|
|
}
|
|
|
|
// Otherwise, store the data into the folder
|
|
else
|
|
{
|
|
IxpAssert(FALSE);
|
|
// Simply write the data
|
|
CHECKHR(hr = m_rFolder.pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Done ?
|
|
if (TRUE == pResponse->fDone)
|
|
{
|
|
// Finish this message download
|
|
CHECKHR(hr = _HrFinishMessageDownload(dwPopId));
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_HrFinishMessageDownload
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrFinishMessageDownload(DWORD dwPopId)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
IMimeMessage *pMessage=NULL;
|
|
PROPVARIANT rUserData;
|
|
LPPOP3ITEM pItem;
|
|
SYSTEMTIME st;
|
|
UIDLRECORD rUidlInfo={0};
|
|
MESSAGEID idMessage;
|
|
DWORD dwMsgFlags;
|
|
IMessageFolder *pFolder;
|
|
ULONG ulIndex = 0;
|
|
IStream * pIStm = NULL;
|
|
BOOL fDelete=FALSE;
|
|
|
|
// Get Current Item
|
|
pItem = ITEMFROMPOPID(dwPopId);
|
|
|
|
// Create a New Mail Message
|
|
CHECKHR(hr = HrCreateMessage(&pMessage));
|
|
|
|
// Has Body rules
|
|
if (ISFLAGSET(m_dwState, POP3STATE_BODYRULES))
|
|
{
|
|
// I should not have checked for a rule yet
|
|
IxpAssert(!ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE) && !ISFLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE));
|
|
|
|
// Better have a current folder
|
|
Assert(m_pStream);
|
|
|
|
// Check Params
|
|
CHECKHR(hr = m_pStream->Commit(STGC_DEFAULT));
|
|
|
|
pIStm = m_pStream;
|
|
}
|
|
else
|
|
{
|
|
// Better have a current folder
|
|
Assert(m_rFolder.pStream);
|
|
|
|
// Check Params
|
|
CHECKHR(hr = m_rFolder.pStream->Commit(STGC_DEFAULT));
|
|
|
|
// Change the Lock Type
|
|
CHECKHR(hr = m_rFolder.pFolder->ChangeStreamLock(m_rFolder.pStream, ACCESS_READ));
|
|
|
|
pIStm = m_rFolder.pStream;
|
|
}
|
|
|
|
// Rewind
|
|
CHECKHR(hr = HrRewindStream(pIStm));
|
|
|
|
// Stream in
|
|
CHECKHR(hr = pMessage->Load(pIStm));
|
|
|
|
// Count Partials
|
|
if (S_OK == pMessage->IsContentType(HBODY_ROOT, STR_CNT_MESSAGE, STR_SUB_PARTIAL))
|
|
m_rMetrics.cPartials++;
|
|
|
|
// Save Server
|
|
rUserData.vt = VT_LPSTR;
|
|
rUserData.pszVal = m_rServer.szServerName;
|
|
pMessage->SetProp(PIDTOSTR(PID_ATT_SERVER), NOFLAGS, &rUserData);
|
|
|
|
// Save Account Name
|
|
rUserData.vt = VT_LPSTR;
|
|
rUserData.pszVal = m_rServer.szAccount;
|
|
pMessage->SetProp(STR_ATT_ACCOUNTNAME, NOFLAGS, &rUserData);
|
|
|
|
// Save Account Name
|
|
rUserData.vt = VT_LPSTR;
|
|
rUserData.pszVal = m_szAccountId;
|
|
pMessage->SetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &rUserData);
|
|
|
|
// Save UIDL
|
|
if (pItem->pszUidl)
|
|
{
|
|
rUserData.vt = VT_LPSTR;
|
|
rUserData.pszVal = pItem->pszUidl;
|
|
pMessage->SetProp(PIDTOSTR(PID_ATT_UIDL), NOFLAGS, &rUserData);
|
|
}
|
|
|
|
// Save User Name
|
|
rUserData.vt = VT_LPSTR;
|
|
rUserData.pszVal = m_rServer.szUserName;
|
|
pMessage->SetProp(PIDTOSTR(PID_ATT_USERNAME), NOFLAGS, &rUserData);
|
|
|
|
// Initialize dwMsgFlags
|
|
dwMsgFlags = ARF_RECEIVED;
|
|
|
|
// Has Body rules
|
|
if (ISFLAGSET(m_dwState, POP3STATE_BODYRULES))
|
|
{
|
|
// I should not have checked for a rule yet
|
|
IxpAssert(!ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE) && !ISFLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE));
|
|
|
|
// Compute the inbox rule
|
|
_ComputeItemInboxRule(pItem, NULL, NULL, pMessage, FALSE);
|
|
|
|
// Did we find an Inbox Rule
|
|
if (ISFLAGCLEAR(pItem->dwFlags, POP3ITEM_HASINBOXRULE) || (S_OK != _GetMoveFolder(pItem, &pFolder)))
|
|
{
|
|
pFolder = m_pInbox;
|
|
}
|
|
|
|
// Destination is known
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_DESTINATIONKNOWN);
|
|
}
|
|
else
|
|
{
|
|
pFolder = m_rFolder.pFolder;
|
|
}
|
|
|
|
// Store the message into the folder
|
|
IF_FAILEXIT(hr = pFolder->SaveMessage(&idMessage, SAVE_MESSAGE_GENID, dwMsgFlags, pIStm, pMessage, NOSTORECALLBACK));
|
|
|
|
// Success
|
|
m_rFolder.fCommitted = TRUE;
|
|
|
|
// This message was successfully downloaded
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOADED);
|
|
|
|
// Do PostDownloadRule
|
|
_DoPostDownloadActions(pItem, idMessage, pFolder, pMessage, &fDelete);
|
|
|
|
// Release Folder Object
|
|
SafeRelease(m_rFolder.pStream);
|
|
|
|
// Relase m_pStream
|
|
SafeRelease(m_pStream);
|
|
|
|
// Release the Folder
|
|
SafeRelease(m_rFolder.pFolder);
|
|
|
|
// Clear the folder infor Struct
|
|
ZeroMemory(&m_rFolder, sizeof(POP3FOLDERINFO));
|
|
|
|
// If going to delete it...
|
|
if (fDelete)
|
|
{
|
|
// Mark it for deletion
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER);
|
|
|
|
// We will store its uidl, but lets delete it later
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_DELETECACHEDUIDL);
|
|
}
|
|
|
|
// Cached the UIDL for this message ?
|
|
if (ISFLAGSET(pItem->dwFlags, POP3ITEM_CACHEUIDL))
|
|
{
|
|
// Should have a pszUidl
|
|
Assert(pItem->pszUidl && m_pUidlCache);
|
|
|
|
// Don't fault
|
|
if (pItem->pszUidl)
|
|
{
|
|
// Set Key
|
|
GetSystemTime(&st);
|
|
SystemTimeToFileTime(&st, &rUidlInfo.ftDownload);
|
|
rUidlInfo.fDownloaded = TRUE;
|
|
rUidlInfo.fDeleted = FALSE;
|
|
rUidlInfo.pszUidl = pItem->pszUidl;
|
|
rUidlInfo.pszServer = m_rServer.szServerName;
|
|
rUidlInfo.pszAccountId = m_szAccountId;
|
|
|
|
// Set Propgs
|
|
m_pUidlCache->InsertRecord(&rUidlInfo);
|
|
}
|
|
}
|
|
|
|
// Successful download
|
|
m_rMetrics.cDownloaded++;
|
|
|
|
// Do smart log
|
|
if (m_pSmartLog && (lstrcmpi(m_pSmartLog->pszAccount, m_rServer.szAccount) == 0 || lstrcmpi("All", m_pSmartLog->pszAccount) == 0))
|
|
_DoSmartLog(pMessage);
|
|
|
|
// Retrieve the next message
|
|
CHECKHR(hr = _HrRetrieveNextMessage(dwPopId));
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pMessage);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_DoPostDownloadActions
|
|
// ------------------------------------------------------------------------------------
|
|
void CPop3Task::_DoPostDownloadActions(LPPOP3ITEM pItem, MESSAGEID idMessage,
|
|
IMessageFolder *pFolder, IMimeMessage *pMessage, BOOL *pfDeleteOffServer)
|
|
{
|
|
// Locals
|
|
HRESULT hr;
|
|
MESSAGEINFO Message = {0};
|
|
HWND hwnd = NULL;
|
|
|
|
// Finish Applying the inbox rules
|
|
if (!ISFLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Get Window
|
|
if (FAILED(m_pUI->GetWindow(&hwnd)))
|
|
hwnd = NULL;
|
|
|
|
// Set the Id
|
|
Message.idMessage = idMessage;
|
|
|
|
// Get the message
|
|
hr = pFolder->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &Message, NULL);
|
|
if (FAILED(hr) || DB_S_NOTFOUND == hr)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if (FAILED(RuleUtil_HrApplyActions(hwnd, m_pIExecRules, &Message, pFolder, pMessage, 0, pItem->pActList,
|
|
pItem->cActList, &(m_rMetrics.cInfiniteLoopAutoGens), pfDeleteOffServer)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
// Free
|
|
if (NULL != pFolder)
|
|
{
|
|
pFolder->FreeRecord(&Message);
|
|
}
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_HrOpenFolder
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrOpenFolder(IMessageFolder *pFolder)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Current folder better be empty
|
|
Assert(NULL == m_rFolder.pFolder && NULL == m_rFolder.pStream && 0 == m_rFolder.faStream);
|
|
|
|
// Bad Arguments
|
|
if (NULL == pFolder)
|
|
{
|
|
Assert(FALSE);
|
|
return TrapError(E_INVALIDARG);
|
|
}
|
|
|
|
// Save the folder
|
|
m_rFolder.pFolder = pFolder;
|
|
|
|
// AddRef
|
|
m_rFolder.pFolder->AddRef();
|
|
|
|
// Get a stream from the
|
|
CHECKHR(hr = m_rFolder.pFolder->CreateStream(&m_rFolder.faStream));
|
|
|
|
// Open the Stream
|
|
CHECKHR(hr = m_rFolder.pFolder->OpenStream(ACCESS_WRITE, m_rFolder.faStream, &m_rFolder.pStream));
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_CloseFolder
|
|
// ------------------------------------------------------------------------------------
|
|
void CPop3Task::_CloseFolder(void)
|
|
{
|
|
// Release the Stream
|
|
SafeRelease(m_rFolder.pStream);
|
|
|
|
// Release the reference to the stream. If the stream was reused,
|
|
// it's refCount was incremented down below
|
|
if (m_rFolder.faStream != 0)
|
|
{
|
|
// Must have a folder
|
|
Assert(m_rFolder.pFolder);
|
|
|
|
// Delete the Stream
|
|
SideAssert(SUCCEEDED(m_rFolder.pFolder->DeleteStream(m_rFolder.faStream)));
|
|
|
|
// Nill
|
|
m_rFolder.faStream = 0;
|
|
}
|
|
|
|
// AddRef
|
|
SafeRelease(m_rFolder.pFolder);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::_HrStartDeleteCycle
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrStartDeleteCycle(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG i;
|
|
LPPOP3ITEM pItem;
|
|
|
|
// Release Folder Objects
|
|
_ReleaseFolderObjects();
|
|
|
|
// Check State
|
|
m_rMetrics.cDelete = 0;
|
|
m_rMetrics.iCurrent = 0;
|
|
|
|
// Count the number of messages we will have to get a top for
|
|
for (i=0; i<m_rTable.cItems; i++)
|
|
{
|
|
// Readability
|
|
pItem = &m_rTable.prgItem[i];
|
|
|
|
// If it was marked for download, and we didn't download it, don't delete it
|
|
if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD) && !ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOADED))
|
|
FLAGCLEAR(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER);
|
|
|
|
// Is it marked for delete ?
|
|
else if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER))
|
|
m_rMetrics.cDelete++;
|
|
}
|
|
|
|
// Nothing to delete
|
|
if (0 == m_rMetrics.cDelete)
|
|
{
|
|
// Disconnect
|
|
m_pTransport->Disconnect();
|
|
|
|
// Done
|
|
goto exit;
|
|
}
|
|
|
|
// Setup Progress
|
|
m_rMetrics.iCurrent = 0;
|
|
m_wProgress = 0;
|
|
m_dwProgressCur = 0;
|
|
m_dwProgressMax = m_rMetrics.cDelete;
|
|
m_pUI->SetProgressRange(100);
|
|
|
|
// State
|
|
m_state = POP3STATE_DELETING;
|
|
|
|
// Do the first one
|
|
CHECKHR(hr = _HrDeleteNextMessage(0));
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_HrDeleteNextMessage
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrDeleteNextMessage(DWORD dwPopIdCurrent)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szRes[CCHMAX_RES];
|
|
CHAR szMsg[CCHMAX_RES + CCHMAX_RES];
|
|
LPPOP3ITEM pItem;
|
|
|
|
// Mark as deleted
|
|
if (dwPopIdCurrent > 0)
|
|
{
|
|
// Get the item
|
|
pItem = ITEMFROMPOPID(dwPopIdCurrent);
|
|
|
|
// Mark as deleted
|
|
FLAGSET(pItem->dwFlags, POP3ITEM_DELETED);
|
|
}
|
|
|
|
// Loop until we find the next message that we are downloading
|
|
while(1)
|
|
{
|
|
// Incremenet dwPopIdCurrent
|
|
dwPopIdCurrent++;
|
|
|
|
// Last PopId, start the download
|
|
if (dwPopIdCurrent > m_rTable.cItems)
|
|
{
|
|
// Disconnect
|
|
m_pTransport->Disconnect();
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
|
|
// Readability
|
|
pItem = ITEMFROMPOPID(dwPopIdCurrent);
|
|
|
|
// Download this message ?
|
|
if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER))
|
|
{
|
|
// Increment m_rMetrics.iCurrent
|
|
m_rMetrics.iCurrent++;
|
|
|
|
// Status
|
|
//LOADSTRING(IDS_SPS_POP3DELE, szRes);
|
|
//wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rMetrics.iCurrent, m_rMetrics.cDelete);
|
|
//m_pUI->SetSpecificProgress(szMsg);
|
|
|
|
// Retrieve this item
|
|
CHECKHR(hr = m_pTransport->CommandDELE(POP3CMD_GET_POPID, dwPopIdCurrent));
|
|
|
|
// Count number of items deleted by rule
|
|
if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DELEBYRULE))
|
|
m_rMetrics.cDeleByRule++;
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_HrBuildFolderPartialMsgs
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrBuildFolderPartialMsgs(IMessageFolder *pFolder, LPPARTIALMSG *ppPartialMsgs,
|
|
ULONG *pcPartialMsgs, ULONG *pcTotalParts)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPPARTIALMSG pPartialMsgs=NULL;
|
|
ULONG cPartialMsgs=0,
|
|
iPartialMsg,
|
|
iMsgPart,
|
|
i,
|
|
cTotalParts=0;
|
|
ULONG cAlloc=0;
|
|
MESSAGEINFO MsgInfo={0};
|
|
HROWSET hRowset=NULL;
|
|
BOOL fKnownPartialId;
|
|
|
|
// Check Params
|
|
Assert(pFolder && ppPartialMsgs && pcPartialMsgs);
|
|
|
|
// Init
|
|
*ppPartialMsgs = NULL;
|
|
*pcPartialMsgs = 0;
|
|
*pcTotalParts = 0;
|
|
|
|
// Create a Rowset
|
|
CHECKHR(hr = pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset));
|
|
|
|
// Loop
|
|
while (S_OK == pFolder->QueryRowset(hRowset, 1, (LPVOID *)&MsgInfo, NULL))
|
|
{
|
|
// Is this a partial, i.e. does it have a partial id...
|
|
if (!FIsEmptyA(MsgInfo.pszPartialId))
|
|
{
|
|
// Assume we don't know th id
|
|
fKnownPartialId = FALSE;
|
|
|
|
// See if I know this partial id
|
|
for (iPartialMsg=0; iPartialMsg<cPartialMsgs; iPartialMsg++)
|
|
{
|
|
if (lstrcmp(MsgInfo.pszPartialId, pPartialMsgs[iPartialMsg].pszId) == 0)
|
|
{
|
|
fKnownPartialId = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Did we know this message...
|
|
if (fKnownPartialId == FALSE)
|
|
{
|
|
// Realloc my array ?
|
|
if (cPartialMsgs + 1 >= cAlloc)
|
|
{
|
|
// Realloc the array
|
|
if (!MemRealloc((LPVOID *)&pPartialMsgs, (cAlloc + 20) * sizeof(PARTIALMSG)))
|
|
{
|
|
hr = TrapError(hrMemory);
|
|
goto exit;
|
|
}
|
|
|
|
// Zero Init
|
|
ZeroMemory(pPartialMsgs + cAlloc, 20 * sizeof(PARTIALMSG));
|
|
|
|
// Realloc
|
|
cAlloc += 20;
|
|
}
|
|
|
|
// Set index into partial msgs lsit
|
|
iPartialMsg = cPartialMsgs;
|
|
|
|
// Set some stuff
|
|
if (MsgInfo.pszAcctName)
|
|
StrCpyN(pPartialMsgs[iPartialMsg].szAccount, MsgInfo.pszAcctName, ARRAYSIZE(pPartialMsgs[iPartialMsg].szAccount));
|
|
pPartialMsgs[iPartialMsg].pszId = PszDupA(MsgInfo.pszPartialId);
|
|
pPartialMsgs[iPartialMsg].cTotalParts = LOWORD(MsgInfo.dwPartial);
|
|
|
|
// Increment number of known partial messages
|
|
cPartialMsgs++;
|
|
}
|
|
|
|
// Otherwise, we know the partial id already...
|
|
else
|
|
{
|
|
// See if this message details the total number of parts
|
|
if (pPartialMsgs[iPartialMsg].cTotalParts == 0)
|
|
pPartialMsgs[iPartialMsg].cTotalParts = LOWORD(MsgInfo.dwPartial);
|
|
}
|
|
|
|
// Can I add one more msgpart into this list
|
|
if (pPartialMsgs[iPartialMsg].cMsgParts + 1 >= pPartialMsgs[iPartialMsg].cAlloc)
|
|
{
|
|
// Realloc the array
|
|
if (!MemRealloc((LPVOID *)&pPartialMsgs[iPartialMsg].pMsgParts, (pPartialMsgs[iPartialMsg].cAlloc + 20) * sizeof(MSGPART)))
|
|
{
|
|
hr = TrapError(hrMemory);
|
|
goto exit;
|
|
}
|
|
|
|
// Zero Init
|
|
ZeroMemory(pPartialMsgs[iPartialMsg].pMsgParts + pPartialMsgs[iPartialMsg].cAlloc, 20 * sizeof(MSGPART));
|
|
|
|
// Realloc
|
|
pPartialMsgs[iPartialMsg].cAlloc += 20;
|
|
}
|
|
|
|
// Set Message Part
|
|
iMsgPart = pPartialMsgs[iPartialMsg].cMsgParts;
|
|
|
|
// Set Message Info
|
|
pPartialMsgs[iPartialMsg].pMsgParts[iMsgPart].iPart = HIWORD(MsgInfo.dwPartial);
|
|
pPartialMsgs[iPartialMsg].pMsgParts[iMsgPart].msgid = MsgInfo.idMessage;
|
|
//pPartialMsgs[iPartialMsg].pMsgParts[iMsgPart].phi = phi;
|
|
//phi = NULL;
|
|
|
|
// Increment the number of parts in the list
|
|
pPartialMsgs[iPartialMsg].cMsgParts++;
|
|
}
|
|
|
|
// Free
|
|
pFolder->FreeRecord(&MsgInfo);
|
|
}
|
|
|
|
// Lets sort the list by pszId
|
|
for (i=0; i<cPartialMsgs; i++)
|
|
{
|
|
if (pPartialMsgs[i].pMsgParts && pPartialMsgs[i].cMsgParts > 0)
|
|
_QSortMsgParts(pPartialMsgs[i].pMsgParts, 0, pPartialMsgs[i].cMsgParts-1);
|
|
cTotalParts += pPartialMsgs[i].cMsgParts;
|
|
}
|
|
|
|
// Success
|
|
*pcPartialMsgs = cPartialMsgs;
|
|
*ppPartialMsgs = pPartialMsgs;
|
|
*pcTotalParts = cTotalParts;
|
|
|
|
exit:
|
|
// Cleanup
|
|
if (pFolder)
|
|
{
|
|
pFolder->CloseRowset(&hRowset);
|
|
pFolder->FreeRecord(&MsgInfo);
|
|
}
|
|
|
|
// If We failed, free stuff
|
|
if (FAILED(hr))
|
|
{
|
|
_FreePartialMsgs(pPartialMsgs, cPartialMsgs);
|
|
SafeMemFree(pPartialMsgs);
|
|
*ppPartialMsgs = NULL;
|
|
*pcPartialMsgs = 0;
|
|
*pcTotalParts = 0;
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_QSortMsgParts
|
|
// ------------------------------------------------------------------------------------
|
|
void CPop3Task::_QSortMsgParts(LPMSGPART pMsgParts, LONG left, LONG right)
|
|
{
|
|
register long i, j;
|
|
WORD k;
|
|
MSGPART y;
|
|
|
|
i = left;
|
|
j = right;
|
|
k = pMsgParts[(left + right) / 2].iPart;
|
|
|
|
do
|
|
{
|
|
while(pMsgParts[i].iPart < k && i < right)
|
|
i++;
|
|
while (pMsgParts[j].iPart > k && j > left)
|
|
j--;
|
|
|
|
if (i <= j)
|
|
{
|
|
CopyMemory(&y, &pMsgParts[i], sizeof(MSGPART));
|
|
CopyMemory(&pMsgParts[i], &pMsgParts[j], sizeof(MSGPART));
|
|
CopyMemory(&pMsgParts[j], &y, sizeof(MSGPART));
|
|
i++; j--;
|
|
}
|
|
|
|
} while (i <= j);
|
|
|
|
if (left < j)
|
|
_QSortMsgParts(pMsgParts, left, j);
|
|
if (i < right)
|
|
_QSortMsgParts(pMsgParts, i, right);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_FreePartialMsgs
|
|
// ------------------------------------------------------------------------------------
|
|
void CPop3Task::_FreePartialMsgs(LPPARTIALMSG pPartialMsgs, ULONG cPartialMsgs)
|
|
{
|
|
// Locals
|
|
ULONG i, j;
|
|
|
|
// Nothing to free
|
|
if (pPartialMsgs == NULL)
|
|
return;
|
|
|
|
// Loop the array
|
|
for (i=0; i<cPartialMsgs; i++)
|
|
{
|
|
SafeMemFree(pPartialMsgs[i].pszId);
|
|
#if 0
|
|
for (j=0; j<pPartialMsgs[i].cMsgParts; j++)
|
|
{
|
|
FreeHeaderInfo(pPartialMsgs[i].pMsgParts[j].phi);
|
|
}
|
|
#endif
|
|
SafeMemFree(pPartialMsgs[i].pMsgParts);
|
|
}
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_HrStitchPartials
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_HrStitchPartials(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
IMessageFolder *pInbox=NULL,
|
|
*pDeletedItems=NULL;
|
|
LPPARTIALMSG pPartialMsgs=NULL;
|
|
ULONG cPartialMsgs=0,
|
|
i,
|
|
j,
|
|
cbCacheInfo,
|
|
cErrors=0,
|
|
cTotalParts;
|
|
IMimeMessageParts *pParts=NULL;
|
|
LPMSGPART pMsgParts;
|
|
IMimeMessage *pMailMsg=NULL,
|
|
*pMailMsgSingle=NULL;
|
|
TCHAR szRes[255];
|
|
PROPVARIANT rUserData;
|
|
ULONG cCombined=0;
|
|
MESSAGEIDLIST List;
|
|
HWND hwnd;
|
|
|
|
// Progress
|
|
AthLoadString(idsStitchingMessages, szRes, ARRAYSIZE(szRes));
|
|
m_pUI->SetSpecificProgress(szRes);
|
|
m_pUI->SetAnimation(idanDecode, TRUE);
|
|
m_pUI->SetProgressRange(100);
|
|
|
|
// Get Window
|
|
if (FAILED(m_pUI->GetWindow(&hwnd)))
|
|
hwnd = NULL;
|
|
|
|
// open the inbox
|
|
CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreInbox, (LPVOID *)&pInbox));
|
|
|
|
// deleted items folder
|
|
CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreDeleted, (LPVOID *)&pDeletedItems));
|
|
|
|
// Get array of message parts in this folder
|
|
CHECKHR(hr = _HrBuildFolderPartialMsgs(pInbox, &pPartialMsgs, &cPartialMsgs, &cTotalParts));
|
|
|
|
// If nothing, were done
|
|
if (pPartialMsgs == NULL || cPartialMsgs == 0)
|
|
goto exit;
|
|
|
|
// Setup Progress
|
|
m_rMetrics.iCurrent = 0;
|
|
m_wProgress = 0;
|
|
m_dwProgressCur = 0;
|
|
m_dwProgressMax = cTotalParts;
|
|
|
|
// Loop through partial messages list
|
|
for (i=0; i<cPartialMsgs; i++)
|
|
{
|
|
// If we don't know all of the parts yet, continue
|
|
if (pPartialMsgs[i].cTotalParts == 0)
|
|
continue;
|
|
|
|
// Or we don't have all of the parts yet...
|
|
if (pPartialMsgs[i].cTotalParts != pPartialMsgs[i].cMsgParts)
|
|
continue;
|
|
|
|
// Lets create a mail message list
|
|
Assert(pParts == NULL);
|
|
|
|
// Create Parts Object
|
|
CHECKHR(hr = MimeOleCreateMessageParts(&pParts));
|
|
|
|
// Set pMsgParts
|
|
pMsgParts = pPartialMsgs[i].pMsgParts;
|
|
|
|
// Ok, lets build a message list by opening the messages up out of the store...
|
|
for (j=0; j<pPartialMsgs[i].cMsgParts; j++)
|
|
{
|
|
// Progress
|
|
if (j > 0)
|
|
{
|
|
m_dwProgressCur++;
|
|
_DoProgress();
|
|
}
|
|
|
|
// Open this message
|
|
if (FAILED(pInbox->OpenMessage(pMsgParts[j].msgid, NOFLAGS, &pMailMsg, NOSTORECALLBACK)))
|
|
{
|
|
cErrors++;
|
|
hr = TrapError(E_FAIL);
|
|
goto NextPartialMessage;
|
|
}
|
|
|
|
// Add into pmml
|
|
pParts->AddPart(pMailMsg);
|
|
|
|
// Release It
|
|
SafeRelease(pMailMsg);
|
|
}
|
|
|
|
// Create a new message to combine everyting into
|
|
Assert(pMailMsgSingle == NULL);
|
|
|
|
// Create a Message
|
|
hr = pParts->CombineParts(&pMailMsgSingle);
|
|
if (FAILED(hr))
|
|
{
|
|
cErrors++;
|
|
TrapError(hr);
|
|
goto NextPartialMessage;
|
|
}
|
|
|
|
// Set Account
|
|
HrSetAccount(pMailMsgSingle, pPartialMsgs[i].szAccount);
|
|
|
|
// Set Combined Flag
|
|
rUserData.vt = VT_UI4;
|
|
rUserData.ulVal = MESSAGE_COMBINED;
|
|
pMailMsgSingle->SetProp(PIDTOSTR(PID_ATT_COMBINED), NOFLAGS, &rUserData);
|
|
|
|
// Save the message
|
|
hr = pMailMsgSingle->Commit(0);
|
|
if (FAILED(hr))
|
|
{
|
|
cErrors++;
|
|
TrapError(hr);
|
|
goto NextPartialMessage;
|
|
}
|
|
|
|
// Save It
|
|
hr = pInbox->SaveMessage(NULL, SAVE_MESSAGE_GENID, ARF_RECEIVED, 0, pMailMsgSingle, NOSTORECALLBACK);
|
|
if (FAILED(hr))
|
|
{
|
|
cErrors++;
|
|
TrapError(hr);
|
|
goto NextPartialMessage;
|
|
}
|
|
|
|
// Ok, now lets move those original messages to the deleted items folder...
|
|
for (j=0; j<pPartialMsgs[i].cMsgParts; j++)
|
|
{
|
|
// Setup the msgidlsit
|
|
List.cMsgs = 1;
|
|
List.prgidMsg = &pMsgParts[j].msgid;
|
|
|
|
// Move msgid to deleted items folder
|
|
CopyMessagesProgress(hwnd, pInbox, pDeletedItems, COPY_MESSAGE_MOVE, &List, NULL);
|
|
}
|
|
|
|
// Count Combined
|
|
cCombined++;
|
|
|
|
// Cleanup
|
|
NextPartialMessage:
|
|
SafeRelease(pMailMsg);
|
|
SafeRelease(pMailMsgSingle);
|
|
SafeRelease(pParts);
|
|
}
|
|
|
|
// If I combined parts, apply inbox rules to the inbox
|
|
if (cCombined)
|
|
{
|
|
// Apply to the inbox
|
|
RuleUtil_HrApplyRulesToFolder(RULE_APPLY_PARTIALS, 0, m_pIExecRules, pInbox, NULL, NULL);
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
m_pUI->SetSpecificProgress(c_szEmpty);
|
|
m_pUI->SetProgressRange(100);
|
|
SafeRelease(pInbox);
|
|
SafeRelease(pDeletedItems);
|
|
SafeRelease(pParts);
|
|
SafeRelease(pMailMsg);
|
|
SafeRelease(pMailMsgSingle);
|
|
_FreePartialMsgs(pPartialMsgs, cPartialMsgs);
|
|
SafeMemFree(pPartialMsgs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// CPop3Task::_GetMoveFolder
|
|
// ------------------------------------------------------------------------------------
|
|
HRESULT CPop3Task::_GetMoveFolder(LPPOP3ITEM pItem, IMessageFolder ** ppFolder)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IMessageFolder * pFolder = NULL;
|
|
ULONG ulIndex = 0;
|
|
FOLDERID idFolder = FOLDERID_INVALID;
|
|
FOLDERINFO infoFolder = {0};
|
|
SPECIALFOLDER tySpecial = FOLDER_NOTSPECIAL;
|
|
RULEFOLDERDATA * prfdData = NULL;
|
|
|
|
// Check incoming params
|
|
if ((NULL == pItem) || (NULL == ppFolder))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize the outgoing param
|
|
*ppFolder = NULL;
|
|
|
|
// Search for a Move actions
|
|
for (ulIndex = 0; ulIndex < pItem->cActList; ulIndex++)
|
|
{
|
|
switch (pItem->pActList[ulIndex].type)
|
|
{
|
|
case ACT_TYPE_MOVE:
|
|
Assert(VT_BLOB == pItem->pActList[ulIndex].propvar.vt);
|
|
if ((0 != pItem->pActList[ulIndex].propvar.blob.cbSize) && (NULL != pItem->pActList[ulIndex].propvar.blob.pBlobData))
|
|
{
|
|
// Make life simpler
|
|
prfdData = (RULEFOLDERDATA *) (pItem->pActList[ulIndex].propvar.blob.pBlobData);
|
|
|
|
// Validate the rule folder data
|
|
if (S_OK == RuleUtil_HrValidateRuleFolderData(prfdData))
|
|
{
|
|
idFolder = prfdData->idFolder;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ACT_TYPE_DELETE:
|
|
case ACT_TYPE_JUNKMAIL:
|
|
Assert(VT_EMPTY == pItem->pActList[ulIndex].propvar.vt);
|
|
|
|
tySpecial = (ACT_TYPE_JUNKMAIL == pItem->pActList[ulIndex].type) ? FOLDER_JUNK : FOLDER_DELETED;
|
|
|
|
hr = g_pStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, tySpecial, &infoFolder);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;;
|
|
}
|
|
|
|
idFolder = infoFolder.idFolder;
|
|
break;
|
|
}
|
|
|
|
// Are we through?
|
|
if (idFolder != FOLDERID_INVALID)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Did we find anything?
|
|
if (ulIndex >= pItem->cActList)
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
// Get the message folder
|
|
hr = m_pIExecRules->GetRuleFolder(idFolder, (DWORD_PTR *) (&pFolder));
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Use the new folder
|
|
*ppFolder = pFolder;
|
|
pFolder = NULL;
|
|
|
|
// NULL out the actions
|
|
pItem->pActList[ulIndex].type = ACT_TYPE_NULL;
|
|
|
|
// Set the return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
SafeRelease(pFolder);
|
|
g_pStore->FreeRecord(&infoFolder);
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::Cancel
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPop3Task::Cancel(void)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Canceled
|
|
FLAGSET(m_dwState, POP3STATE_CANCELPENDING);
|
|
|
|
// Am I in a state where I can drop the connection???
|
|
if (POP3STATE_UIDLSYNC != m_state)
|
|
{
|
|
if (POP3STATE_UIDLSYNC != m_state && POP3STATE_DOWNLOADING != m_state && POP3STATE_DELETING != m_state)
|
|
{
|
|
// Simply drop the connection
|
|
//If a dialer UI is not dismissed, before changing the identities or shutting down OE,
|
|
//the transport object would not have been created. This happens only when the dialer UI is not
|
|
//modal to the window. Right now IE dialer is modal and MSN dialer is not.
|
|
//See Bug# 53679
|
|
|
|
if (m_pTransport)
|
|
m_pTransport->DropConnection();
|
|
}
|
|
|
|
// Otherwise, let the state handle the disconnect
|
|
else
|
|
{
|
|
// Finishing last message...
|
|
m_pUI->SetSpecificProgress(MAKEINTRESOURCE(idsSpoolerDisconnect));
|
|
}
|
|
}
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::OnTimeoutResponse
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPop3Task::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)
|
|
{
|
|
// Canceled
|
|
FLAGSET(m_dwState, POP3STATE_CANCELPENDING);
|
|
|
|
// Report error and drop connection
|
|
_CatchResult(IXP_E_TIMEOUT);
|
|
}
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::IsDialogMessage
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPop3Task::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;
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPop3Task::OnFlagsChanged
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPop3Task::OnFlagsChanged(DWORD dwFlags)
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
m_dwFlags = dwFlags;
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
return (S_OK);
|
|
}
|