Windows2003-3790/inetcore/outlookexpress/mailnews/spooler/imaptask.cpp
2020-09-30 16:53:55 +02:00

500 lines
16 KiB
C++

//***************************************************************************
// IMAP4 Spooler Task Object
// Written by Raymond Cheng, 6/27/97
//***************************************************************************
//---------------------------------------------------------------------------
// Includes
//---------------------------------------------------------------------------
#include "pch.hxx"
#include "resource.h"
#include "imaptask.h"
#include "imnact.h"
#include "conman.h"
#include "imapfmgr.h"
#include "thormsgs.h"
#include "imaputil.h"
#include "xpcomm.h"
#include "ourguid.h"
//---------------------------------------------------------------------------
// Functions
//---------------------------------------------------------------------------
//***************************************************************************
// Function: CIMAPTask (Constructor)
//***************************************************************************
CIMAPTask::CIMAPTask(void)
{
m_lRefCount = 1;
m_pBindContext = NULL;
m_pSpoolerUI = NULL;
m_szAccountName[0] = '\0';
m_pszFolder = NULL;
m_pIMAPFolderMgr = NULL;
m_hwnd = NULL;
m_CurrentEID = 0;
m_fFailuresEncountered = FALSE;
m_dwTotalTicks = 0;
m_dwFlags = 0;
} // CIMAPTask (constructor)
//***************************************************************************
// Function: ~CIMAPTask (Destructor)
//***************************************************************************
CIMAPTask::~CIMAPTask(void)
{
if (NULL != m_pIMAPFolderMgr) {
m_pIMAPFolderMgr->Close();
m_pIMAPFolderMgr->Release();
}
if (NULL != m_pSpoolerUI)
m_pSpoolerUI->Release();
if (NULL != m_pBindContext)
m_pBindContext->Release();
if (NULL != m_hwnd)
DestroyWindow(m_hwnd);
} // ~CIMAPTask (destructor)
//***************************************************************************
// Function: QueryInterface
//
// Purpose:
// Read the Win32SDK OLE Programming References (Interfaces) about the
// IUnknown::QueryInterface function for details. This function returns a
// pointer to the requested interface.
//
// Arguments:
// REFIID iid [in] - an IID identifying the interface to return.
// void **ppvObject [out] - if successful, this function returns a pointer
// to the requested interface in this argument.
//
// Returns:
// HRESULT indicating success or failure.
//***************************************************************************
HRESULT STDMETHODCALLTYPE CIMAPTask::QueryInterface(REFIID iid, void **ppvObject)
{
HRESULT hrResult;
Assert(m_lRefCount > 0);
Assert(NULL != ppvObject);
// Init variables, arguments
hrResult = E_NOINTERFACE;
if (NULL == ppvObject)
goto exit;
*ppvObject = NULL;
// Find a ptr to the interface
if (IID_IUnknown == iid) {
*ppvObject = (IUnknown *) this;
((IUnknown *) this)->AddRef();
}
if (IID_ISpoolerTask == iid) {
*ppvObject = (ISpoolerTask *) this;
((ISpoolerTask *) this)->AddRef();
}
// If we returned an interface, return success
if (NULL != *ppvObject)
hrResult = S_OK;
exit:
return hrResult;
} // QueryInterface
//***************************************************************************
// Function: AddRef
//
// Purpose:
// This function should be called whenever someone makes a copy of a
// pointer to this object. It bumps the reference count so that we know
// there is one more pointer to this object, and thus we need one more
// release before we delete ourselves.
//
// Returns:
// A ULONG representing the current reference count. Although technically
// our reference count is signed, we should never return a negative number,
// anyways.
//***************************************************************************
ULONG STDMETHODCALLTYPE CIMAPTask::AddRef(void)
{
Assert(m_lRefCount > 0);
m_lRefCount += 1;
DOUT ("CIMAPTask::AddRef, returned Ref Count=%ld", m_lRefCount);
return m_lRefCount;
} // AddRef
//***************************************************************************
// Function: Release
//
// Purpose:
// This function should be called when a pointer to this object is to
// go out of commission. It knocks the reference count down by one, and
// automatically deletes the object if we see that nobody has a pointer
// to this object.
//
// Returns:
// A ULONG representing the current reference count. Although technically
// our reference count is signed, we should never return a negative number,
// anyways.
//***************************************************************************
ULONG STDMETHODCALLTYPE CIMAPTask::Release(void)
{
Assert(m_lRefCount > 0);
m_lRefCount -= 1;
DOUT("CIMAPTask::Release, returned Ref Count = %ld", m_lRefCount);
if (0 == m_lRefCount) {
delete this;
return 0;
}
else
return m_lRefCount;
} // Release
static const char c_szIMAPTask[] = "IMAP Task";
//***************************************************************************
// Function: Init
// Purpose: ISpoolerTask implementation.
//***************************************************************************
HRESULT STDMETHODCALLTYPE CIMAPTask::Init(DWORD dwFlags,
ISpoolerBindContext *pBindCtx)
{
WNDCLASSEX wc;
HRESULT hrResult;
Assert(m_lRefCount > 0);
Assert(NULL != pBindCtx);
// Initialize variables
hrResult = S_OK;
// Save pBindCtx to module var
m_pBindContext = pBindCtx;
pBindCtx->AddRef();
m_dwFlags = dwFlags;
// Create a hidden window to process WM_IMAP_* messages
wc.cbSize = sizeof(WNDCLASSEX);
if (!GetClassInfoEx(g_hInst, c_szIMAPTask, &wc)) {
wc.style = 0;
wc.lpfnWndProc = IMAPTaskWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInst;
wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = c_szIMAPTask;
wc.hIcon = NULL;
wc.hIconSm = NULL;
RegisterClassEx(&wc);
}
m_hwnd = CreateWindow(c_szIMAPTask, NULL, WS_POPUP, 10, 10, 10, 10,
GetDesktopWindow(), NULL, g_hInst, this);
if (NULL == m_hwnd) {
hrResult = E_OUTOFMEMORY;
goto exit;
}
exit:
return hrResult;
} // Init
//***************************************************************************
// Function: BuildEvents
// Purpose: ISpoolerTask implementation.
// Arguments:
// LPCTSTR pszFolder [in] - currently this argument is taken to mean the
// currently selected IMAP folder. Set this argument to NULL if no
// IMAP folder is currently selected. This argument is used to avoid
// polling the currently selected folder for its unread count.
//***************************************************************************
HRESULT STDMETHODCALLTYPE CIMAPTask::BuildEvents(ISpoolerUI *pSpoolerUI,
IImnAccount *pAccount,
LPCTSTR pszFolder)
{
HRESULT hrResult;
char szFmt[CCHMAX_STRINGRES], szEventDescription[CCHMAX_STRINGRES];
EVENTID eidThrowaway;
Assert(m_lRefCount > 0);
Assert(NULL != pSpoolerUI);
Assert(NULL != pAccount);
// Copy spooler UI pointer
m_pSpoolerUI = pSpoolerUI;
pSpoolerUI->AddRef();
// Find and save account name
hrResult = pAccount->GetPropSz(AP_ACCOUNT_NAME, m_szAccountName,
sizeof(m_szAccountName));
if (FAILED(hrResult))
goto exit;
// Keep ptr to current folder name (we want to SKIP it during unread poll!)
m_pszFolder = pszFolder;
#ifndef WIN16 // No RAS support in Win16
// Create and initialize CIMAPFolderMgr to poll unread
hrResult = g_pConMan->CanConnect(m_szAccountName);
if (FAILED(hrResult))
goto exit;
#endif
m_pIMAPFolderMgr = new CIMAPFolderMgr(m_hwnd);
if (NULL == m_pIMAPFolderMgr) {
hrResult = E_OUTOFMEMORY;
goto exit;
}
hrResult = m_pIMAPFolderMgr->HrInit(m_szAccountName, 'i', fCREATE_FLDR_CACHE);
if (FAILED(hrResult))
goto exit;
m_pIMAPFolderMgr->SetOnlineOperation(TRUE);
m_pIMAPFolderMgr->SetUIMode(!(m_dwFlags & DELIVER_BACKGROUND));
// This CIMAPFolderMgr is ready. Register our one and only event
LoadString(g_hLocRes, IDS_SPS_POP3CHECKING, szFmt, ARRAYSIZE(szFmt));
wnsprintf(szEventDescription, ARRAYSIZE(szEventDescription), szFmt, m_szAccountName);
hrResult = m_pBindContext->RegisterEvent(szEventDescription, this, NULL,
pAccount, &eidThrowaway);
if (SUCCEEDED(hrResult))
TaskUtil_CheckForPasswordPrompt(pAccount, SRV_IMAP, m_pSpoolerUI);
exit:
return hrResult;
} // BuildEvents
//***************************************************************************
// Function: Execute
// Purpose: ISpoolerTask implementation.
//***************************************************************************
HRESULT STDMETHODCALLTYPE CIMAPTask::Execute(EVENTID eid, DWORD dwTwinkie)
{
HRESULT hrResult;
char szFmt[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
Assert(m_lRefCount > 0);
Assert(NULL == dwTwinkie); // I'm not currently using this
// Initialize progress indication
m_pSpoolerUI->SetProgressRange(1);
LoadString(g_hLocRes, IDS_SPS_POP3CHECKING, szFmt, ARRAYSIZE(szFmt));
wnsprintf(szBuf, ARRAYSIZE(szBuf), szFmt, m_szAccountName);
m_pSpoolerUI->SetGeneralProgress(szBuf);
m_pSpoolerUI->SetAnimation(idanDownloadNews, TRUE);
// Start the unread count poll
Assert(NULL != m_pIMAPFolderMgr);
hrResult = m_pIMAPFolderMgr->PollUnreadCounts(m_hwnd, m_pszFolder);
if (FAILED(hrResult))
goto exit;
m_CurrentEID = eid;
exit:
return hrResult;
} // Execute
//***************************************************************************
// Function: ShowProperties
// Purpose: ISpoolerTask implementation.
//***************************************************************************
HRESULT STDMETHODCALLTYPE CIMAPTask::ShowProperties(HWND hwndParent,
EVENTID eid,
DWORD dwTwinkie)
{
Assert(m_lRefCount > 0);
return E_NOTIMPL;
} // ShowProperties
//***************************************************************************
// Function: GetExtendedDetails
// Purpose: ISpoolerTask implementation.
//***************************************************************************
HRESULT STDMETHODCALLTYPE CIMAPTask::GetExtendedDetails(EVENTID eid,
DWORD dwTwinkie,
LPSTR *ppszDetails)
{
Assert(m_lRefCount > 0);
return E_NOTIMPL;
} // GetExtendedDetails
//***************************************************************************
// Function: Cancel
// Purpose: ISpoolerTask implementation.
//***************************************************************************
HRESULT STDMETHODCALLTYPE CIMAPTask::Cancel(void)
{
Assert(m_lRefCount > 0);
return m_pIMAPFolderMgr->Disconnect();
} // Cancel
//***************************************************************************
// Function: IsDialogMessage
// Purpose: ISpoolerTask implementation.
//***************************************************************************
HRESULT STDMETHODCALLTYPE CIMAPTask::IsDialogMessage(LPMSG pMsg)
{
Assert(m_lRefCount > 0);
return S_FALSE;
} // IsDialogMessage
//***************************************************************************
// Function: OnFlagsChanged
// Purpose: ISpoolerTask implementation.
//***************************************************************************
HRESULT STDMETHODCALLTYPE CIMAPTask::OnFlagsChanged(DWORD dwFlags)
{
Assert(m_lRefCount > 0);
m_dwFlags = dwFlags;
if (m_pIMAPFolderMgr)
m_pIMAPFolderMgr->SetUIMode(!(m_dwFlags & DELIVER_BACKGROUND));
return S_OK;
} // OnFlagsChanged
//***************************************************************************
// Function: IMAPTaskWndProc
//
// Purpose:
// This function handles WM_IMAP_* messages which result from polling for
// unread counts on the IMAP server. The various WM_IMAP_* messages are
// translated into spooler UI events to inform the user of the progress of
// the operation.
//***************************************************************************
LRESULT CALLBACK CIMAPTask::IMAPTaskWndProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
CIMAPTask *pThis = (CIMAPTask *) GetProp(hwnd, _T("this"));
switch (uMsg) {
case WM_CREATE:
pThis = (CIMAPTask *) ((LPCREATESTRUCT)lParam)->lpCreateParams;
SetProp(hwnd, _T("this"), (LPVOID) pThis);
return 0;
case WM_IMAP_ERROR: {
HRESULT hrResult;
LPSTR pszErrorStr;
pThis->m_fFailuresEncountered = TRUE;
hrResult = ImapUtil_WMIMAPERRORToString(lParam, &pszErrorStr, NULL);
if (FAILED(hrResult)) {
AssertSz(FALSE, "Could not construct full error str for WM_IMAP_ERROR");
pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID,
((INETMAILERROR *)lParam)->pszMessage);
}
else {
pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID,
pszErrorStr);
MemFree(pszErrorStr);
}
return 0;
} // case WM_IMAP_ERROR
case WM_IMAP_SIMPLEERROR: {
char sz[CCHMAX_STRINGRES];
pThis->m_fFailuresEncountered = TRUE;
Assert(0 == HIWORD(lParam)); // Can't handle two text strings
LoadString(g_hLocRes, LOWORD(lParam), sz, ARRAYSIZE(sz));
pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID, sz);
} // case WM_IMAP_SIMPLEERROR
return 0;
case WM_IMAP_POLLUNREAD_DONE: {
HRESULT hrResult;
EVENTCOMPLETEDSTATUS ecs;
Assert((0 == wParam || 1 == wParam) && 0 == lParam);
ecs = EVENT_SUCCEEDED; // Let's be optimistic
if (pThis->m_fFailuresEncountered) {
char sz[CCHMAX_STRINGRES], szFmt[CCHMAX_STRINGRES];
LoadString(g_hLocRes, idsIMAPPollUnreadFailuresFmt, szFmt, ARRAYSIZE(szFmt));
wnsprintf(sz, ARRAYSIZE(sz), szFmt, pThis->m_szAccountName);
pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID, sz);
ecs = EVENT_WARNINGS;
}
if (0 == wParam)
ecs = EVENT_FAILED;
hrResult = pThis->m_pBindContext->EventDone(pThis->m_CurrentEID, ecs);
Assert(SUCCEEDED(hrResult));
return 0;
} // case WM_IMAP_POLLUNREAD_DONE
case WM_IMAP_POLLUNREAD_TICK:
Assert(0 == lParam);
if (0 == wParam)
pThis->m_fFailuresEncountered = TRUE;
else if (1 == wParam) {
char sz[CCHMAX_STRINGRES], szFmt[CCHMAX_STRINGRES];
LoadString(g_hLocRes, idsIMAPPollUnreadIMAP4Fmt, szFmt, ARRAYSIZE(szFmt));
wnsprintf(sz, ARRAYSIZE(sz), szFmt, pThis->m_szAccountName);
pThis->m_fFailuresEncountered = TRUE;
pThis->m_pSpoolerUI->InsertError(pThis->m_CurrentEID, sz);
}
else {
Assert(2 == wParam);
if (pThis->m_dwTotalTicks > 0)
pThis->m_pSpoolerUI->IncrementProgress(1);
}
return 0;
case WM_IMAP_POLLUNREAD_TOTAL:
Assert(0 == lParam);
pThis->m_dwTotalTicks = wParam;
pThis->m_pSpoolerUI->SetProgressRange(wParam);
return 0;
} // switch (uMsg)
// If we reached this point, we didn't process the msg: DefWindowProc it
return DefWindowProc(hwnd, uMsg, wParam, lParam);
} // IMAPTaskWndProc