1769 lines
48 KiB
C++
1769 lines
48 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) 1993-1998 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// MODULE: newstask.cpp
|
|
//
|
|
// PURPOSE: Implements a task object to take care of news posts.
|
|
//
|
|
|
|
#include "pch.hxx"
|
|
#include "resource.h"
|
|
#include "imagelst.h"
|
|
#include "storfldr.h"
|
|
#include "mimeutil.h"
|
|
#include "newstask.h"
|
|
#include "goptions.h"
|
|
#include "thormsgs.h"
|
|
#include "spoolui.h"
|
|
#include "xputil.h"
|
|
#include "ourguid.h"
|
|
#include "demand.h"
|
|
#include "msgfldr.h"
|
|
#include "taskutil.h"
|
|
#include <storsync.h>
|
|
#include <ntverp.h>
|
|
|
|
ASSERTDATA
|
|
|
|
const static char c_szThis[] = "this";
|
|
|
|
static const PFNSTATEFUNC g_rgpfnState[NTS_MAX] =
|
|
{
|
|
NULL, // Idle
|
|
NULL, // Connecting
|
|
&CNewsTask::Post_Init,
|
|
&CNewsTask::Post_NextMsg,
|
|
NULL, // Post_OnResp
|
|
&CNewsTask::Post_Dispose,
|
|
&CNewsTask::Post_Done,
|
|
&CNewsTask::NewMsg_Init,
|
|
&CNewsTask::NewMsg_NextGroup,
|
|
NULL, // NewMsg_OnResp
|
|
&CNewsTask::NewMsg_HttpSyncStore,
|
|
NULL, // NewMsg_OnHttpResp
|
|
&CNewsTask::NewMsg_Done
|
|
};
|
|
|
|
static const TCHAR c_szXNewsReader[] = "Microsoft Outlook Express " VER_PRODUCTVERSION_STRING;
|
|
|
|
//
|
|
// FUNCTION: CNewsTask::CNewsTask()
|
|
//
|
|
// PURPOSE: Initializes the member variables of the object.
|
|
//
|
|
CNewsTask::CNewsTask()
|
|
{
|
|
m_cRef = 1;
|
|
|
|
m_fInited = FALSE;
|
|
m_dwFlags = 0;
|
|
m_state = NTS_IDLE;
|
|
m_eidCur = 0;
|
|
m_pInfo = NULL;
|
|
m_fConnectFailed = FALSE;
|
|
m_szAccount[0] = 0;
|
|
m_szAccountId[0] = 0;
|
|
m_idAccount = FOLDERID_INVALID;
|
|
m_pAccount = NULL;
|
|
m_cEvents = 0;
|
|
m_fCancel = FALSE;
|
|
|
|
m_pBindCtx = NULL;
|
|
m_pUI = NULL;
|
|
|
|
m_pServer = NULL;
|
|
m_pOutbox = NULL;
|
|
m_pSent = NULL;
|
|
|
|
m_hwnd = 0;
|
|
|
|
m_cMsgsPost = 0;
|
|
m_cCurPost = 0;
|
|
m_cFailed = 0;
|
|
m_cCurParts = 0;
|
|
m_cPartsCompleted = 0;
|
|
m_fPartFailed = FALSE;
|
|
m_rgMsgInfo = NULL;
|
|
m_pSplitInfo = NULL;
|
|
|
|
m_cGroups = 0;
|
|
m_cCurGroup = -1;
|
|
m_rgidGroups = NULL;
|
|
m_dwNewInboxMsgs = 0;
|
|
|
|
m_pCancel = NULL;
|
|
m_hTimeout = NULL;
|
|
m_tyOperation = SOT_INVALID;
|
|
}
|
|
|
|
//
|
|
// FUNCTION: CNewsTask::~CNewsTask()
|
|
//
|
|
// PURPOSE: Frees any resources allocated during the life of the class.
|
|
//
|
|
CNewsTask::~CNewsTask()
|
|
{
|
|
DestroyWindow(m_hwnd);
|
|
|
|
FreeSplitInfo();
|
|
|
|
SafeMemFree(m_pInfo);
|
|
|
|
SafeRelease(m_pBindCtx);
|
|
SafeRelease(m_pUI);
|
|
SafeRelease(m_pAccount);
|
|
|
|
if (m_pServer)
|
|
{
|
|
m_pServer->Close(MSGSVRF_HANDS_OFF_SERVER);
|
|
m_pServer->Release();
|
|
}
|
|
|
|
Assert(NULL == m_pOutbox);
|
|
Assert(NULL == m_pSent);
|
|
|
|
SafeMemFree(m_rgMsgInfo);
|
|
|
|
CallbackCloseTimeout(&m_hTimeout);
|
|
SafeRelease(m_pCancel);
|
|
}
|
|
|
|
|
|
HRESULT CNewsTask::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
|
|
{
|
|
if (NULL == *ppvObj)
|
|
return (E_INVALIDARG);
|
|
|
|
*ppvObj = NULL;
|
|
|
|
if (IsEqualIID(riid, IID_IUnknown))
|
|
*ppvObj = (LPVOID)(ISpoolerTask *) this;
|
|
else if (IsEqualIID(riid, IID_ISpoolerTask))
|
|
*ppvObj = (LPVOID)(ISpoolerTask *) this;
|
|
else if (IsEqualIID(riid, IID_IStoreCallback))
|
|
*ppvObj = (LPVOID)(IStoreCallback *) this;
|
|
else if (IsEqualIID(riid, IID_ITimeoutCallback))
|
|
*ppvObj = (LPVOID)(ITimeoutCallback *) this;
|
|
|
|
if (NULL == *ppvObj)
|
|
return (E_NOINTERFACE);
|
|
|
|
AddRef();
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
ULONG CNewsTask::AddRef(void)
|
|
{
|
|
ULONG cRefT;
|
|
|
|
cRefT = ++m_cRef;
|
|
|
|
return (cRefT);
|
|
}
|
|
|
|
|
|
ULONG CNewsTask::Release(void)
|
|
{
|
|
ULONG cRefT;
|
|
|
|
cRefT = --m_cRef;
|
|
|
|
if (0 == cRefT)
|
|
delete this;
|
|
|
|
return (cRefT);
|
|
}
|
|
|
|
static const char c_szNewsTask[] = "News Task";
|
|
|
|
//
|
|
// FUNCTION: CNewsTask::Init()
|
|
//
|
|
// PURPOSE: Called by the spooler engine to tell us what type of task to
|
|
// execute and to provide us with a pointer to our bind context.
|
|
//
|
|
// PARAMETERS:
|
|
// <in> dwFlags - Flags to tell us what types of things to do
|
|
// <in> pBindCtx - Pointer to the bind context interface we are to use
|
|
//
|
|
// RETURN VALUE:
|
|
// E_INVALIDARG
|
|
// SP_E_ALREADYINITIALIZED
|
|
// S_OK
|
|
// E_OUTOFMEMORY
|
|
//
|
|
HRESULT CNewsTask::Init(DWORD dwFlags, ISpoolerBindContext *pBindCtx)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Validate the arguments
|
|
if (NULL == pBindCtx)
|
|
return (E_INVALIDARG);
|
|
|
|
// Check to see if we've been initialzed already
|
|
if (m_fInited)
|
|
{
|
|
hr = SP_E_ALREADYINITIALIZED;
|
|
goto exit;
|
|
}
|
|
|
|
// Copy the flags
|
|
m_dwFlags = dwFlags;
|
|
|
|
// Copy the bind context pointer
|
|
m_pBindCtx = pBindCtx;
|
|
m_pBindCtx->AddRef();
|
|
|
|
// Create the window
|
|
WNDCLASSEX wc;
|
|
|
|
wc.cbSize = sizeof(WNDCLASSEX);
|
|
if (!GetClassInfoEx(g_hInst, c_szNewsTask, &wc))
|
|
{
|
|
wc.style = 0;
|
|
wc.lpfnWndProc = TaskWndProc;
|
|
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_szNewsTask;
|
|
wc.hIcon = NULL;
|
|
wc.hIconSm = NULL;
|
|
|
|
RegisterClassEx(&wc);
|
|
}
|
|
|
|
m_hwnd = CreateWindow(c_szNewsTask, NULL, WS_POPUP, 10, 10, 10, 10,
|
|
GetDesktopWindow(), NULL, g_hInst, this);
|
|
if (!m_hwnd)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
m_fInited = TRUE;
|
|
|
|
exit:
|
|
return (hr);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: CNewsTask::BuildEvents()
|
|
//
|
|
// PURPOSE: This method is called by the spooler engine telling us to create
|
|
// and event list for the account specified.
|
|
//
|
|
// PARAMETERS:
|
|
// <in> pAccount - Account object to build the event list for
|
|
//
|
|
// RETURN VALUE:
|
|
// SP_E_UNINITALIZED
|
|
// E_INVALIDARG
|
|
// S_OK
|
|
//
|
|
HRESULT CNewsTask::BuildEvents(ISpoolerUI *pSpoolerUI, IImnAccount *pAccount, FOLDERID idFolder)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fIMAP;
|
|
BOOL fHttp;
|
|
FOLDERINFO fiFolderInfo;
|
|
DWORD dw = 0;
|
|
ULARGE_INTEGER uhLastFileTime64 = {0};
|
|
ULARGE_INTEGER uhCurFileTime64 = {0};
|
|
ULARGE_INTEGER uhMinPollingInterval64 = {0};
|
|
FILETIME CurFileTime = {0};
|
|
DWORD cb = 0;
|
|
|
|
Assert(pAccount != NULL);
|
|
Assert(pSpoolerUI != NULL);
|
|
Assert(m_fInited);
|
|
|
|
m_pAccount = pAccount;
|
|
m_pAccount->AddRef();
|
|
|
|
// Get the account name from the account object
|
|
if (FAILED(hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, m_szAccount, ARRAYSIZE(m_szAccount))))
|
|
return(hr);
|
|
|
|
// Get the account name from the account object
|
|
if (FAILED(hr = pAccount->GetPropSz(AP_ACCOUNT_ID, m_szAccountId, ARRAYSIZE(m_szAccountId))))
|
|
return(hr);
|
|
|
|
if (FAILED(hr = g_pStore->FindServerId(m_szAccountId, &m_idAccount)))
|
|
return(hr);
|
|
|
|
// Copy the UI object
|
|
m_pUI = pSpoolerUI;
|
|
m_pUI->AddRef();
|
|
|
|
// Create the server object
|
|
hr = g_pStore->GetFolderInfo(m_idAccount, &fiFolderInfo);
|
|
if (FAILED(hr))
|
|
return(hr);
|
|
|
|
fIMAP = (fiFolderInfo.tyFolder == FOLDER_IMAP);
|
|
fHttp = (fiFolderInfo.tyFolder == FOLDER_HTTPMAIL);
|
|
|
|
hr = CreateMessageServerType(fiFolderInfo.tyFolder, &m_pServer);
|
|
g_pStore->FreeRecord(&fiFolderInfo);
|
|
|
|
if (FAILED(hr))
|
|
return(hr);
|
|
|
|
hr = m_pServer->Initialize(g_pLocalStore, m_idAccount, NULL, FOLDERID_INVALID);
|
|
if (FAILED(hr))
|
|
return(hr);
|
|
|
|
if (!fIMAP & !fHttp)
|
|
{
|
|
// Add posts to upload
|
|
if (DELIVER_SEND & m_dwFlags)
|
|
InsertOutbox(m_szAccountId, pAccount);
|
|
}
|
|
|
|
if (fHttp)
|
|
{
|
|
if (!!(m_dwFlags & DELIVER_AT_INTERVALS))
|
|
{
|
|
//If this is background polling make sure that HTTP's maxpolling interval has elapsed before
|
|
//polling again.
|
|
|
|
cb = sizeof(uhMinPollingInterval64);
|
|
IF_FAILEXIT(hr = pAccount->GetProp(AP_HTTPMAIL_MINPOLLINGINTERVAL, (LPBYTE)&uhMinPollingInterval64, &cb));
|
|
|
|
cb = sizeof(uhLastFileTime64);
|
|
IF_FAILEXIT(hr = pAccount->GetProp(AP_HTTPMAIL_LASTPOLLEDTIME, (LPBYTE)&uhLastFileTime64, &cb));
|
|
|
|
GetSystemTimeAsFileTime(&CurFileTime);
|
|
uhCurFileTime64.QuadPart = CurFileTime.dwHighDateTime;
|
|
uhCurFileTime64.QuadPart = uhCurFileTime64.QuadPart << 32;
|
|
uhCurFileTime64.QuadPart += CurFileTime.dwLowDateTime;
|
|
|
|
//We do not want to do background polling if the last time we polled this http mail
|
|
//account was less than maximum polling interval specified by the server.
|
|
//We should only poll if the time elapsed is greater than or equal to the max polling interval
|
|
if ((uhCurFileTime64.QuadPart - uhLastFileTime64.QuadPart) < uhMinPollingInterval64.QuadPart)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
//Mark the last polled time.
|
|
hr = pAccount->SetProp(AP_HTTPMAIL_LASTPOLLEDTIME, (LPBYTE)&uhCurFileTime64, sizeof(uhCurFileTime64));
|
|
}
|
|
}
|
|
// Check for new msgs
|
|
if ((DELIVER_POLL & m_dwFlags) && (fIMAP || fHttp || !(m_dwFlags & DELIVER_NO_NEWSPOLL)))
|
|
{
|
|
if (ISFLAGSET(m_dwFlags, DELIVER_NOSKIP) ||
|
|
(!fIMAP && !fHttp && (FAILED(pAccount->GetPropDw(AP_NNTP_POLL, &dw)) || dw != 0)) ||
|
|
(fIMAP && (FAILED(pAccount->GetPropDw(AP_IMAP_POLL, &dw)) || dw != 0)) ||
|
|
(fHttp && (FAILED(pAccount->GetPropDw(AP_HTTPMAIL_POLL, &dw)) || dw != 0)))
|
|
{
|
|
InsertNewMsgs(m_szAccountId, pAccount, fHttp);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
return (hr);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: CNewsTask::Execute()
|
|
//
|
|
// PURPOSE: This signals our task to start executing an event.
|
|
//
|
|
// PARAMETERS:
|
|
// <in> pSpoolerUI - Pointer of the UI object we'll display progress through
|
|
// <in> eid - ID of the event to execute
|
|
// <in> dwTwinkie - Our extra information we associated with the event
|
|
//
|
|
// RETURN VALUE:
|
|
// SP_E_EXECUTING
|
|
// S_OK
|
|
// E_INVALIDARG
|
|
// SP_E_UNINITIALIZED
|
|
//
|
|
HRESULT CNewsTask::Execute(EVENTID eid, DWORD_PTR dwTwinkie)
|
|
{
|
|
TCHAR szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
|
|
|
|
// Make sure we're already idle
|
|
Assert(m_state == NTS_IDLE);
|
|
|
|
// Make sure we're initialized
|
|
Assert(m_fInited);
|
|
|
|
// Copy the event id and event info
|
|
m_eidCur = eid;
|
|
m_pInfo = (EVENTINFO *) dwTwinkie;
|
|
|
|
// Update the event UI to an executing state
|
|
Assert(m_pUI);
|
|
m_pUI->SetProgressRange(1);
|
|
|
|
// Set up the progress
|
|
AthLoadString(idsInetMailConnectingHost, szRes, ARRAYSIZE(szRes));
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_szAccount);
|
|
m_pUI->SetGeneralProgress(szBuf);
|
|
|
|
m_pUI->SetAnimation(idanDownloadNews, TRUE);
|
|
|
|
// Depending on the type of event, set the state machine info
|
|
switch (((EVENTINFO*) dwTwinkie)->type)
|
|
{
|
|
case EVENT_OUTBOX:
|
|
m_state = NTS_POST_INIT;
|
|
break;
|
|
|
|
case EVENT_NEWMSGS:
|
|
m_state = NTS_NEWMSG_INIT;
|
|
break;
|
|
}
|
|
|
|
PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT CNewsTask::CancelEvent(EVENTID eid, DWORD_PTR dwTwinkie)
|
|
{
|
|
// Make sure we're initialized
|
|
Assert(m_fInited);
|
|
|
|
Assert(dwTwinkie != 0);
|
|
MemFree((EVENTINFO *)dwTwinkie);
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
//
|
|
// FUNCTION: CNewsTask::ShowProperties
|
|
//
|
|
// PURPOSE: <???>
|
|
//
|
|
// PARAMETERS:
|
|
// <???>
|
|
//
|
|
// RETURN VALUE:
|
|
// <???>
|
|
//
|
|
// COMMENTS:
|
|
// <???>
|
|
//
|
|
HRESULT CNewsTask::ShowProperties(HWND hwndParent, EVENTID eid, DWORD_PTR dwTwinkie)
|
|
{
|
|
return (E_NOTIMPL);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: CNewsTask::GetExtendedDetails
|
|
//
|
|
// PURPOSE: <???>
|
|
//
|
|
// PARAMETERS:
|
|
// <???>
|
|
//
|
|
// RETURN VALUE:
|
|
// <???>
|
|
//
|
|
// COMMENTS:
|
|
// <???>
|
|
//
|
|
HRESULT CNewsTask::GetExtendedDetails(EVENTID eid, DWORD_PTR dwTwinkie,
|
|
LPSTR *ppszDetails)
|
|
{
|
|
return (E_NOTIMPL);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: CNewsTask::Cancel
|
|
//
|
|
// PURPOSE: <???>
|
|
//
|
|
// PARAMETERS:
|
|
// <???>
|
|
//
|
|
// RETURN VALUE:
|
|
// <???>
|
|
//
|
|
// COMMENTS:
|
|
// <???>
|
|
//
|
|
HRESULT CNewsTask::Cancel(void)
|
|
{
|
|
// this can happen if user cancels out of connect dlg
|
|
if (m_state == NTS_IDLE)
|
|
return(S_OK);
|
|
|
|
// Drop the server connection
|
|
if (m_pServer)
|
|
m_pServer->Close(MSGSVRF_DROP_CONNECTION);
|
|
|
|
m_fCancel = TRUE;
|
|
|
|
if (m_pInfo->type == EVENT_OUTBOX)
|
|
m_state = NTS_POST_END;
|
|
else
|
|
m_state = NTS_NEWMSG_END;
|
|
|
|
PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: CNewsTask::InsertOutbox()
|
|
//
|
|
// PURPOSE: Checks the outbox for news posts destine for this news account.
|
|
//
|
|
// PARAMETERS:
|
|
// <in> pszAcctId - ID of the account to check the outbox for.
|
|
//
|
|
// RETURN VALUE:
|
|
// E_UNEXECTED
|
|
// E_OUTOFMEMORY
|
|
// S_OK
|
|
//
|
|
HRESULT CNewsTask::InsertOutbox(LPTSTR pszAcctId, IImnAccount *pAccount)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IMessageFolder *pOutbox = NULL;
|
|
MESSAGEINFO MsgInfo={0};
|
|
HROWSET hRowset=NULL;
|
|
|
|
// Get the outbox
|
|
if (FAILED(hr = m_pBindCtx->BindToObject(IID_CLocalStoreOutbox, (LPVOID *) &pOutbox)))
|
|
goto exit;
|
|
|
|
// Loop through the outbox looking for posts to this server
|
|
m_cMsgsPost = 0;
|
|
|
|
// Create a Rowset
|
|
if (FAILED(hr = pOutbox->CreateRowset(IINDEX_PRIMARY, 0, &hRowset)))
|
|
goto exit;
|
|
|
|
// Get the first message
|
|
while (S_OK == pOutbox->QueryRowset(hRowset, 1, (void **)&MsgInfo, NULL))
|
|
{
|
|
// Has this message been submitted and is it a news message?
|
|
if ((MsgInfo.dwFlags & (ARF_SUBMITTED | ARF_NEWSMSG)) == (ARF_SUBMITTED | ARF_NEWSMSG))
|
|
{
|
|
// Is the account the same as the account we're looking for
|
|
if (MsgInfo.pszAcctId && 0 == lstrcmpi(MsgInfo.pszAcctId, pszAcctId))
|
|
m_cMsgsPost++;
|
|
}
|
|
|
|
// Free the header info
|
|
pOutbox->FreeRecord(&MsgInfo);
|
|
}
|
|
|
|
// Release Lock
|
|
pOutbox->CloseRowset(&hRowset);
|
|
|
|
// Good to go
|
|
hr = S_OK;
|
|
|
|
// If there were any messages then add the event
|
|
if (m_cMsgsPost)
|
|
{
|
|
EVENTINFO *pei = NULL;
|
|
TCHAR szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
|
|
EVENTID eid;
|
|
|
|
// Allocate a structure to set as our cookie
|
|
if (!MemAlloc((LPVOID*) &pei, sizeof(EVENTINFO)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
// Fill out the event info
|
|
pei->szGroup[0] = 0;
|
|
pei->type = EVENT_OUTBOX;
|
|
|
|
// Create the event description
|
|
AthLoadString(idsNewsTaskPost, szRes, ARRAYSIZE(szRes));
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_cMsgsPost, m_szAccount);
|
|
|
|
// Insert the event into the spooler
|
|
hr = m_pBindCtx->RegisterEvent(szBuf, this, (DWORD_PTR) pei, pAccount, &eid);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
m_cEvents++;
|
|
|
|
} // if (m_cMsgsPost)
|
|
|
|
exit:
|
|
// Release Lock
|
|
if (pOutbox)
|
|
pOutbox->CloseRowset(&hRowset);
|
|
SafeRelease(pOutbox);
|
|
return (hr);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: CNewsTask::TaskWndProc()
|
|
//
|
|
// PURPOSE: Hidden window that processes messages for this task.
|
|
//
|
|
LRESULT CALLBACK CNewsTask::TaskWndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
CNewsTask *pThis = (CNewsTask *) GetProp(hwnd, c_szThis);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_CREATE:
|
|
{
|
|
LPCREATESTRUCT pcs = (LPCREATESTRUCT) lParam;
|
|
pThis = (CNewsTask *) pcs->lpCreateParams;
|
|
SetProp(hwnd, c_szThis, (LPVOID) pThis);
|
|
return (0);
|
|
}
|
|
|
|
case NTM_NEXTSTATE:
|
|
if (pThis)
|
|
{
|
|
pThis->AddRef();
|
|
pThis->NextState();
|
|
pThis->Release();
|
|
}
|
|
return (0);
|
|
|
|
case WM_DESTROY:
|
|
RemoveProp(hwnd, c_szThis);
|
|
break;
|
|
}
|
|
|
|
return (DefWindowProc(hwnd, uMsg, wParam, lParam));
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: CNewsTask::Post_Init()
|
|
//
|
|
// PURPOSE: Called when we're in a NTS_POST_INIT state. The task is
|
|
// initialized to execute the posting event.
|
|
//
|
|
// RETURN VALUE:
|
|
// E_OUTOFMEMORY
|
|
// E_UNEXPECTED
|
|
// S_OK
|
|
//
|
|
HRESULT CNewsTask::Post_Init(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwCur = 0;
|
|
MESSAGEINFO MsgInfo={0};
|
|
HROWSET hRowset=NULL;
|
|
BOOL fInserted = FALSE;
|
|
TCHAR *pszAcctName = NULL;
|
|
|
|
// Open the outbox
|
|
Assert(m_pBindCtx);
|
|
if (FAILED(hr = m_pBindCtx->BindToObject(IID_CLocalStoreOutbox, (LPVOID *) &m_pOutbox)))
|
|
goto exit;
|
|
|
|
Assert(m_pSent == NULL);
|
|
|
|
// If we use sent items, get that pointer too
|
|
if (DwGetOption(OPT_SAVESENTMSGS))
|
|
{
|
|
if (FAILED(hr = TaskUtil_OpenSentItemsFolder(m_pAccount, &m_pSent)))
|
|
goto exit;
|
|
Assert(m_pSent != NULL);
|
|
}
|
|
|
|
// Allocate an array of header pointers for the messages we're going to post
|
|
if (!MemAlloc((LPVOID*) &m_rgMsgInfo, m_cMsgsPost * sizeof(MESSAGEINFO)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
// Zero out the array
|
|
ZeroMemory(m_rgMsgInfo, m_cMsgsPost * sizeof(MESSAGEINFO));
|
|
|
|
// Create Rowset
|
|
if (FAILED(hr = m_pOutbox->CreateRowset(IINDEX_PRIMARY, 0, &hRowset)))
|
|
goto exit;
|
|
|
|
// While we have stuff
|
|
while (S_OK == m_pOutbox->QueryRowset(hRowset, 1, (void **)&MsgInfo, NULL))
|
|
{
|
|
// Has this message been submitted and is it a news message?
|
|
if ((MsgInfo.dwFlags & (ARF_SUBMITTED | ARF_NEWSMSG)) == (ARF_SUBMITTED | ARF_NEWSMSG))
|
|
{
|
|
// Is the account the same as the account we're looking for
|
|
if (MsgInfo.pszAcctId && 0 == lstrcmpi(MsgInfo.pszAcctId, m_szAccountId))
|
|
{
|
|
if (NULL == pszAcctName && MsgInfo.pszAcctName)
|
|
pszAcctName = PszDup(MsgInfo.pszAcctName);
|
|
|
|
CopyMemory(&m_rgMsgInfo[dwCur++], &MsgInfo, sizeof(MESSAGEINFO));
|
|
ZeroMemory(&MsgInfo, sizeof(MESSAGEINFO));
|
|
}
|
|
}
|
|
|
|
if (dwCur >= (DWORD)m_cMsgsPost)
|
|
{
|
|
Assert(0);
|
|
break;
|
|
}
|
|
|
|
// Free the header info
|
|
m_pOutbox->FreeRecord(&MsgInfo);
|
|
}
|
|
|
|
// Release Lock
|
|
m_pOutbox->CloseRowset(&hRowset);
|
|
|
|
// Good to go
|
|
hr = S_OK;
|
|
|
|
//Assert(dwCur);
|
|
|
|
// Update the UI to an executing state
|
|
Assert(m_pUI);
|
|
|
|
// Set up the progress
|
|
TCHAR szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
|
|
AthLoadString(idsProgDLPostTo, szRes, ARRAYSIZE(szRes));
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, (LPTSTR) pszAcctName ? pszAcctName : "");
|
|
|
|
Assert(m_pUI);
|
|
m_pUI->SetGeneralProgress(szBuf);
|
|
m_pUI->SetProgressRange((WORD) m_cMsgsPost);
|
|
|
|
m_pUI->SetAnimation(idanOutbox, TRUE);
|
|
m_pBindCtx->Notify(DELIVERY_NOTIFY_SENDING_NEWS, 0);
|
|
|
|
// Reset the counter to post the first message
|
|
m_cCurPost = -1;
|
|
m_cFailed = 0;
|
|
m_state = NTS_POST_NEXT;
|
|
|
|
exit:
|
|
|
|
SafeMemFree(pszAcctName);
|
|
|
|
if (m_pOutbox)
|
|
m_pOutbox->CloseRowset(&hRowset);
|
|
|
|
// If something failed, then update the UI
|
|
if (FAILED(hr))
|
|
{
|
|
m_pUI->InsertError(m_eidCur, MAKEINTRESOURCE(idshrCantOpenOutbox));
|
|
m_cFailed = m_cMsgsPost;
|
|
|
|
// Move to a terminating state
|
|
m_state = NTS_POST_END;
|
|
}
|
|
|
|
PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
|
|
return (hr);
|
|
}
|
|
|
|
void CNewsTask::FreeSplitInfo()
|
|
{
|
|
if (m_pSplitInfo != NULL)
|
|
{
|
|
if (m_pSplitInfo->pEnumParts != NULL)
|
|
m_pSplitInfo->pEnumParts->Release();
|
|
if (m_pSplitInfo->pMsgParts != NULL)
|
|
m_pSplitInfo->pMsgParts->Release();
|
|
MemFree(m_pSplitInfo);
|
|
m_pSplitInfo = NULL;
|
|
}
|
|
}
|
|
|
|
HRESULT CNewsTask::Post_NextPart(void)
|
|
{
|
|
LPMIMEMESSAGE pMsgSplit;
|
|
HRESULT hr;
|
|
LPSTREAM pStream;
|
|
LPMESSAGEINFO pInfo;
|
|
DWORD dwLines;
|
|
char rgch[12];
|
|
PROPVARIANT rUserData;
|
|
|
|
Assert(m_pSplitInfo->pEnumParts != NULL);
|
|
|
|
pInfo = &m_rgMsgInfo[m_cCurPost];
|
|
|
|
hr = m_pSplitInfo->pEnumParts->Next(1, &pMsgSplit, NULL);
|
|
if (hr == S_OK)
|
|
{
|
|
Assert(pMsgSplit);
|
|
|
|
rUserData.vt = VT_LPSTR;
|
|
rUserData.pszVal = (LPSTR)pInfo->pszAcctName;
|
|
pMsgSplit->SetProp(STR_ATT_ACCOUNTNAME, 0, &rUserData);
|
|
rUserData.pszVal = pInfo->pszAcctId;;
|
|
pMsgSplit->SetProp(PIDTOSTR(PID_ATT_ACCOUNTID), 0, &rUserData);
|
|
|
|
// since this is a new message it doesn't have a line
|
|
// count yet, so we need to do it before we stick it
|
|
// in the outbox
|
|
HrComputeLineCount(pMsgSplit, &dwLines);
|
|
wnsprintf(rgch, ARRAYSIZE(rgch), "%d", dwLines);
|
|
MimeOleSetBodyPropA(pMsgSplit, HBODY_ROOT, PIDTOSTR(PID_HDR_LINES), NOFLAGS, rgch);
|
|
MimeOleSetBodyPropA(pMsgSplit, HBODY_ROOT, PIDTOSTR(PID_HDR_XNEWSRDR), NOFLAGS, c_szXNewsReader);
|
|
// Final Parameter: fSaveChange = TRUE since messsage is dirty
|
|
|
|
hr = pMsgSplit->GetMessageSource(&pStream, 0);
|
|
if (SUCCEEDED(hr) && pStream != NULL)
|
|
{
|
|
hr = m_pServer->PutMessage(m_pSplitInfo->idFolder, pInfo->dwFlags, &pInfo->ftReceived, pStream, this);
|
|
|
|
m_cCurParts++;
|
|
|
|
pStream->Release();
|
|
}
|
|
|
|
pMsgSplit->Release();
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
//
|
|
// FUNCTION: CNewsTask::Post_NextMsg()
|
|
//
|
|
// PURPOSE: Posts the next message in our outbox.
|
|
//
|
|
// RETURN VALUE:
|
|
// <???>
|
|
//
|
|
HRESULT CNewsTask::Post_NextMsg(void)
|
|
{
|
|
LPMESSAGEINFO pInfo;
|
|
FOLDERID idFolder;
|
|
char szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
|
|
DWORD dw, cbSize, cbMaxSendMsgSize;
|
|
IImnAccount *pAcct;
|
|
LPMIMEMESSAGE pMsg = 0;
|
|
HRESULT hr = S_OK;
|
|
IStream *pStream = NULL;
|
|
|
|
if (m_pSplitInfo != NULL)
|
|
{
|
|
hr = Post_NextPart();
|
|
Assert(hr != S_OK);
|
|
if (hr == E_PENDING)
|
|
{
|
|
m_state = NTS_POST_RESP;
|
|
return(S_OK);
|
|
}
|
|
|
|
FreeSplitInfo();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
m_cFailed++;
|
|
m_fPartFailed = TRUE;
|
|
}
|
|
|
|
Assert(m_pUI);
|
|
m_pUI->IncrementProgress(1);
|
|
PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
m_cCurPost++;
|
|
m_cCurParts = 0;
|
|
m_cPartsCompleted = 0;
|
|
m_fPartFailed = FALSE;
|
|
|
|
// Check to see if we're already done
|
|
if (m_cCurPost >= m_cMsgsPost)
|
|
{
|
|
// If so, move to a cleanup state
|
|
m_state = NTS_POST_END;
|
|
PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
|
|
return(S_OK);
|
|
}
|
|
|
|
// Update the progress UI
|
|
AthLoadString(idsProgDLPost, szRes, ARRAYSIZE(szRes));
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_cCurPost + 1, m_cMsgsPost);
|
|
|
|
Assert(m_pUI);
|
|
m_pUI->SetSpecificProgress(szBuf);
|
|
|
|
pInfo = &m_rgMsgInfo[m_cCurPost];
|
|
|
|
// Load the message stream from the store
|
|
if (SUCCEEDED(hr = m_pOutbox->OpenMessage(pInfo->idMessage, OPEN_MESSAGE_SECURE, &pMsg, this)))
|
|
{
|
|
hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pInfo->pszAcctId, &pAcct);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = g_pStore->FindServerId(pInfo->pszAcctId, &idFolder);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (SUCCEEDED(pAcct->GetPropDw(AP_NNTP_SPLIT_MESSAGES, &dw)) &&
|
|
dw != 0 &&
|
|
SUCCEEDED(pAcct->GetPropDw(AP_NNTP_SPLIT_SIZE, &dw)))
|
|
{
|
|
cbMaxSendMsgSize = dw;
|
|
}
|
|
else
|
|
{
|
|
cbMaxSendMsgSize = 0xffffffff;
|
|
}
|
|
|
|
SideAssert(pMsg->GetMessageSize(&cbSize, 0)==S_OK);
|
|
if (cbSize < (cbMaxSendMsgSize * 1024))
|
|
{
|
|
hr = pMsg->GetMessageSource(&pStream, 0);
|
|
if (SUCCEEDED(hr) && pStream != NULL)
|
|
{
|
|
hr = m_pServer->PutMessage(idFolder,
|
|
pInfo->dwFlags,
|
|
&pInfo->ftReceived,
|
|
pStream,
|
|
this);
|
|
m_cCurParts ++;
|
|
pStream->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Assert(m_pSplitInfo == NULL);
|
|
if (!MemAlloc((void **)&m_pSplitInfo, sizeof(SPLITMSGINFO)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory(m_pSplitInfo, sizeof(SPLITMSGINFO));
|
|
m_pSplitInfo->idFolder = idFolder;
|
|
|
|
hr = pMsg->SplitMessage(cbMaxSendMsgSize * 1024, &m_pSplitInfo->pMsgParts);
|
|
if (hr == S_OK)
|
|
{
|
|
hr = m_pSplitInfo->pMsgParts->EnumParts(&m_pSplitInfo->pEnumParts);
|
|
if (hr == S_OK)
|
|
{
|
|
hr = Post_NextPart();
|
|
}
|
|
}
|
|
|
|
if (hr != E_PENDING)
|
|
FreeSplitInfo();
|
|
}
|
|
}
|
|
}
|
|
|
|
pAcct->Release();
|
|
}
|
|
|
|
if (hr == E_PENDING)
|
|
{
|
|
m_state = NTS_POST_RESP;
|
|
hr = S_OK;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// If we get here, something failed.
|
|
m_cFailed++;
|
|
Assert(m_pUI);
|
|
m_pUI->IncrementProgress(1);
|
|
PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
|
|
|
|
exit:
|
|
SafeRelease(pMsg);
|
|
return (hr);
|
|
}
|
|
|
|
HRESULT CNewsTask::Post_Dispose()
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = DisposeOfPosting(m_rgMsgInfo[m_cCurPost].idMessage);
|
|
|
|
if (hr == E_PENDING)
|
|
return(S_OK);
|
|
|
|
// TODO: handle error
|
|
|
|
// Update the progress bar
|
|
Assert(m_pUI);
|
|
m_pUI->IncrementProgress(1);
|
|
|
|
// Move on to the next post
|
|
m_state = NTS_POST_NEXT;
|
|
PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
//
|
|
// FUNCTION: CNewsTask::Post_Done()
|
|
//
|
|
// PURPOSE: Allows the posting event to clean up and finalize the UI.
|
|
//
|
|
// RETURN VALUE:
|
|
// S_OK
|
|
//
|
|
HRESULT CNewsTask::Post_Done(void)
|
|
{
|
|
// Free the header array
|
|
if (m_rgMsgInfo && m_cMsgsPost)
|
|
{
|
|
for (LONG i=0; i<m_cMsgsPost; i++)
|
|
m_pOutbox->FreeRecord(&m_rgMsgInfo[i]);
|
|
MemFree(m_rgMsgInfo);
|
|
}
|
|
|
|
// Free the folder pointers we're hanging on to
|
|
SafeRelease(m_pOutbox);
|
|
SafeRelease(m_pSent);
|
|
|
|
// Tell the spooler we're done
|
|
Assert(m_pBindCtx);
|
|
m_pBindCtx->Notify(DELIVERY_NOTIFY_COMPLETE, m_dwNewInboxMsgs);
|
|
|
|
if (m_fCancel)
|
|
{
|
|
m_pBindCtx->EventDone(m_eidCur, EVENT_CANCELED);
|
|
m_fCancel = FALSE;
|
|
}
|
|
else if (m_cFailed == m_cMsgsPost)
|
|
m_pBindCtx->EventDone(m_eidCur, EVENT_FAILED);
|
|
else if (m_cFailed == 0)
|
|
m_pBindCtx->EventDone(m_eidCur, EVENT_SUCCEEDED);
|
|
else
|
|
m_pBindCtx->EventDone(m_eidCur, EVENT_WARNINGS);
|
|
|
|
m_cMsgsPost = 0;
|
|
m_cCurPost = 0;
|
|
m_cFailed = 0;
|
|
m_rgMsgInfo = NULL;
|
|
SafeMemFree(m_pInfo);
|
|
|
|
m_eidCur = 0;
|
|
|
|
m_cEvents--;
|
|
if (m_cEvents == 0 && m_pServer)
|
|
m_pServer->Close(MSGSVRF_DROP_CONNECTION);
|
|
|
|
m_state = NTS_IDLE;
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
HRESULT CNewsTask::DisposeOfPosting(MESSAGEID dwMsgID)
|
|
{
|
|
MESSAGEIDLIST MsgIdList;
|
|
ADJUSTFLAGS AdjustFlags;
|
|
HRESULT hrResult = E_FAIL;
|
|
|
|
MsgIdList.cAllocated = 0;
|
|
MsgIdList.cMsgs = 1;
|
|
MsgIdList.prgidMsg = &dwMsgID;
|
|
|
|
if (DwGetOption(OPT_SAVESENTMSGS))
|
|
{
|
|
// If we've reached this point, it's time to try local Sent Items folder
|
|
Assert(m_pSent != NULL);
|
|
|
|
// change msg flags first, so if copy fails, the user doesn't get
|
|
// messed up by us posting the message every time they do a send
|
|
AdjustFlags.dwRemove = ARF_SUBMITTED | ARF_UNSENT;
|
|
AdjustFlags.dwAdd = ARF_READ;
|
|
|
|
hrResult = m_pOutbox->SetMessageFlags(&MsgIdList, &AdjustFlags, NULL, NULL);
|
|
Assert(hrResult != E_PENDING);
|
|
if (SUCCEEDED(hrResult))
|
|
hrResult = m_pOutbox->CopyMessages(m_pSent, COPY_MESSAGE_MOVE, &MsgIdList, NULL, NULL, this);
|
|
}
|
|
else
|
|
{
|
|
// If we've reached this point, it's time to delete the message from the Outbox
|
|
hrResult = m_pOutbox->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &MsgIdList, NULL, this);
|
|
}
|
|
|
|
return hrResult;
|
|
}
|
|
|
|
//
|
|
// FUNCTION: CNewsTask::NextState()
|
|
//
|
|
// PURPOSE: Executes the function for the current state
|
|
//
|
|
void CNewsTask::NextState(void)
|
|
{
|
|
if (NULL != g_rgpfnState[m_state])
|
|
(this->*(g_rgpfnState[m_state]))();
|
|
}
|
|
|
|
HRESULT CNewsTask::InsertNewMsgs(LPSTR pszAccountId, IImnAccount *pAccount, BOOL fHttp)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG cSub = 0;
|
|
IEnumerateFolders *pEnum = NULL;
|
|
|
|
if (fHttp)
|
|
m_cGroups = 1;
|
|
else
|
|
{
|
|
// Load the sublist for this server
|
|
Assert(m_idAccount != FOLDERID_INVALID);
|
|
hr = g_pStore->EnumChildren(m_idAccount, TRUE, &pEnum);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
hr = pEnum->Count(&cSub);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
m_cGroups = (int)cSub;
|
|
}
|
|
|
|
// If there were any groups then add the event
|
|
if (m_cGroups)
|
|
{
|
|
EVENTINFO *pei;
|
|
char szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
|
|
EVENTID eid;
|
|
|
|
// Allocate a structure to set as our cookie
|
|
if (!MemAlloc((LPVOID*) &pei, sizeof(EVENTINFO)))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
// Fill out the event info
|
|
pei->szGroup[0] = 0;
|
|
pei->type = EVENT_NEWMSGS;
|
|
|
|
// Create the event description
|
|
AthLoadString(idsCheckNewMsgsServer, szRes, ARRAYSIZE(szRes));
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_szAccount);
|
|
|
|
// Insert the event into the spooler
|
|
hr = m_pBindCtx->RegisterEvent(szBuf, this, (DWORD_PTR) pei, pAccount, &eid);
|
|
m_cEvents++;
|
|
}
|
|
|
|
exit:
|
|
SafeRelease(pEnum);
|
|
return (hr);
|
|
}
|
|
|
|
|
|
HRESULT CNewsTask::NewMsg_InitHttp(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Set up the progress
|
|
TCHAR szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
|
|
AthLoadString(IDS_SPS_POP3CHECKING, szRes, ARRAYSIZE(szRes));
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, (LPTSTR) m_szAccount);
|
|
|
|
Assert(m_pUI);
|
|
m_pUI->SetGeneralProgress(szBuf);
|
|
m_pUI->SetProgressRange(1);
|
|
|
|
m_pUI->SetAnimation(idanInbox, TRUE);
|
|
m_pBindCtx->Notify(DELIVERY_NOTIFY_CHECKING, 0);
|
|
|
|
// set the to generate correct success/failure message
|
|
m_cGroups = 1;
|
|
|
|
m_state = NTS_NEWMSG_HTTPSYNCSTORE;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CNewsTask::NewMsg_Init(void)
|
|
{
|
|
const BOOL fDONT_INCLUDE_PARENT = FALSE;
|
|
const BOOL fSUBSCRIBED_ONLY = TRUE;
|
|
FOLDERINFO FolderInfo = {0};
|
|
HRESULT hr = S_OK;
|
|
DWORD dwAllocated;
|
|
DWORD dwUsed;
|
|
BOOL fImap = FALSE;
|
|
DWORD dwIncludeAll = 0;
|
|
DWORD dwDone = FALSE;
|
|
|
|
Assert(m_idAccount != FOLDERID_INVALID);
|
|
|
|
if (SUCCEEDED(g_pStore->GetFolderInfo(m_idAccount, &FolderInfo)))
|
|
{
|
|
// httpmail updates folder counts differently
|
|
if (FOLDER_HTTPMAIL == FolderInfo.tyFolder)
|
|
{
|
|
g_pStore->FreeRecord(&FolderInfo);
|
|
|
|
IF_FAILEXIT(hr = m_pAccount->GetPropDw(AP_HTTPMAIL_GOTPOLLINGINTERVAL, &dwDone));
|
|
if (!dwDone)
|
|
{
|
|
//We need to get the polling interval from the server
|
|
//This is an asynchrnous call. The value gets updated in OnComplete.
|
|
//Meanwhile we go ahead and poll for new messages
|
|
hr = m_pServer->GetMinPollingInterval((IStoreCallback*)this);
|
|
}
|
|
|
|
hr = NewMsg_InitHttp();
|
|
goto exit;
|
|
}
|
|
|
|
fImap = (FolderInfo.tyFolder == FOLDER_IMAP);
|
|
if (fImap)
|
|
{
|
|
if (FAILED(hr = m_pAccount->GetPropDw(AP_IMAP_POLL_ALL_FOLDERS, &dwIncludeAll)))
|
|
{
|
|
dwIncludeAll = 0;
|
|
}
|
|
}
|
|
|
|
g_pStore->FreeRecord(&FolderInfo);
|
|
}
|
|
|
|
if (fImap && (!dwIncludeAll))
|
|
{
|
|
dwUsed = 0;
|
|
if (FAILED(GetInboxId(g_pStore, m_idAccount, &m_rgidGroups, &dwUsed)))
|
|
goto exit;
|
|
}
|
|
else
|
|
{
|
|
// Get an array of all subscribed folders
|
|
hr = FlattenHierarchy(g_pStore, m_idAccount, fDONT_INCLUDE_PARENT,
|
|
fSUBSCRIBED_ONLY, &m_rgidGroups, &dwAllocated, &dwUsed);
|
|
if (FAILED(hr))
|
|
{
|
|
TraceResult(hr);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
m_cGroups = dwUsed;
|
|
|
|
// Set up the progress
|
|
TCHAR szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
|
|
AthLoadString(IDS_SPS_POP3CHECKING, szRes, ARRAYSIZE(szRes));
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, (LPTSTR) m_szAccount);
|
|
|
|
Assert(m_pUI);
|
|
m_pUI->SetGeneralProgress(szBuf);
|
|
m_pUI->SetProgressRange((WORD) m_cGroups);
|
|
|
|
if (fImap)
|
|
{
|
|
m_pUI->SetAnimation(idanInbox, TRUE);
|
|
m_pBindCtx->Notify(DELIVERY_NOTIFY_CHECKING, 0);
|
|
}
|
|
else
|
|
{
|
|
m_pUI->SetAnimation(idanDownloadNews, TRUE);
|
|
m_pBindCtx->Notify(DELIVERY_NOTIFY_CHECKING_NEWS, 0);
|
|
}
|
|
|
|
// Reset the counters for the first group
|
|
m_cCurGroup = -1;
|
|
m_cFailed = 0;
|
|
m_state = NTS_NEWMSG_NEXTGROUP;
|
|
|
|
exit:
|
|
// If something failed, update the UI
|
|
if (FAILED(hr))
|
|
{
|
|
m_pUI->InsertError(m_eidCur, MAKEINTRESOURCE(idsErrNewMsgsFailed));
|
|
m_cFailed = m_cGroups;
|
|
|
|
// Move to a terminating state
|
|
m_state = NTS_NEWMSG_END;
|
|
}
|
|
|
|
PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
|
|
return (hr);
|
|
}
|
|
|
|
HRESULT CNewsTask::NewMsg_NextGroup(void)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
do
|
|
{
|
|
FOLDERINFO info;
|
|
|
|
// Keep looping until we find a folder that's selectable and exists
|
|
m_cCurGroup++;
|
|
|
|
// Check to see if we're already done
|
|
if (m_cCurGroup >= m_cGroups)
|
|
{
|
|
m_state = NTS_NEWMSG_END;
|
|
hr = S_OK;
|
|
PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
|
|
break;
|
|
}
|
|
|
|
if (SUCCEEDED(hr = g_pStore->GetFolderInfo(m_rgidGroups[m_cCurGroup], &info)))
|
|
{
|
|
if (0 == (info.dwFlags & (FOLDER_NOSELECT | FOLDER_NONEXISTENT)))
|
|
{
|
|
// Update the progress UI
|
|
TCHAR szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
|
|
AthLoadString(idsLogCheckingNewMessages, szRes, ARRAYSIZE(szRes));
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, info.pszName);
|
|
|
|
g_pStore->FreeRecord(&info);
|
|
|
|
Assert(m_pUI);
|
|
m_pUI->SetSpecificProgress(szBuf);
|
|
|
|
// Send the group command to the server
|
|
if (E_PENDING == (hr = m_pServer->GetFolderCounts(m_rgidGroups[m_cCurGroup], (IStoreCallback *)this)))
|
|
{
|
|
m_state = NTS_NEWMSG_RESP;
|
|
hr = S_OK;
|
|
}
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
g_pStore->FreeRecord(&info);
|
|
}
|
|
}
|
|
} while (1);
|
|
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// If we get here, something failed
|
|
m_cFailed++;
|
|
Assert(m_pUI);
|
|
m_pUI->IncrementProgress(1);
|
|
PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
|
|
}
|
|
|
|
return (hr);
|
|
}
|
|
|
|
HRESULT CNewsTask::NewMsg_HttpSyncStore(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// send the command to the server
|
|
hr = m_pServer->SynchronizeStore(FOLDERID_INVALID, NOFLAGS, (IStoreCallback *)this);
|
|
if (E_PENDING == hr)
|
|
{
|
|
m_state = NTS_NEWMSG_HTTPRESP;
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CNewsTask::NewMsg_Done(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Free the group array
|
|
if (m_rgidGroups)
|
|
{
|
|
MemFree(m_rgidGroups);
|
|
m_rgidGroups = NULL;
|
|
}
|
|
|
|
SafeMemFree(m_pInfo);
|
|
|
|
// Tell the spooler we're done
|
|
Assert(m_pBindCtx);
|
|
m_pBindCtx->Notify(DELIVERY_NOTIFY_COMPLETE, m_dwNewInboxMsgs);
|
|
|
|
if (m_fCancel)
|
|
{
|
|
m_pBindCtx->EventDone(m_eidCur, EVENT_CANCELED);
|
|
m_fCancel = FALSE;
|
|
}
|
|
else if (m_cFailed == m_cGroups)
|
|
m_pBindCtx->EventDone(m_eidCur, EVENT_FAILED);
|
|
else if (m_cFailed == 0)
|
|
m_pBindCtx->EventDone(m_eidCur, EVENT_SUCCEEDED);
|
|
else
|
|
m_pBindCtx->EventDone(m_eidCur, EVENT_WARNINGS);
|
|
|
|
m_cGroups = 0;
|
|
m_cCurGroup = 0;
|
|
m_cFailed = 0;
|
|
m_dwNewInboxMsgs = 0;
|
|
|
|
m_eidCur = 0;
|
|
|
|
m_cEvents--;
|
|
if (m_cEvents == 0 && m_pServer)
|
|
m_pServer->Close(MSGSVRF_DROP_CONNECTION);
|
|
|
|
m_state = NTS_IDLE;
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CNewsTask::IsDialogMessage
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CNewsTask::IsDialogMessage(LPMSG pMsg)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CNewsTask::OnFlagsChanged(DWORD dwFlags)
|
|
{
|
|
m_dwFlags = dwFlags;
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CNewsTask::OnBegin(STOREOPERATIONTYPE tyOperation, STOREOPERATIONINFO *pOpInfo, IOperationCancel *pCancel)
|
|
{
|
|
// Hold onto this
|
|
Assert(m_tyOperation == SOT_INVALID);
|
|
|
|
if (pCancel)
|
|
{
|
|
m_pCancel = pCancel;
|
|
m_pCancel->AddRef();
|
|
}
|
|
m_tyOperation = tyOperation;
|
|
|
|
// Party On
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CNewsTask::OnProgress(STOREOPERATIONTYPE tyOperation, DWORD dwCurrent, DWORD dwMax, LPCSTR pszStatus)
|
|
{
|
|
// Close any timeout dialog, if present
|
|
CallbackCloseTimeout(&m_hTimeout);
|
|
|
|
// NOTE: that you can get more than one type of value for tyOperation.
|
|
// Most likely, you will get SOT_CONNECTION_STATUS and then the
|
|
// operation that you might expect. See HotStore.idl and look for
|
|
// the STOREOPERATION enumeration type for more info.
|
|
|
|
switch (tyOperation)
|
|
{
|
|
case SOT_NEW_MAIL_NOTIFICATION:
|
|
m_dwNewInboxMsgs = dwCurrent;
|
|
break;
|
|
}
|
|
|
|
// Done
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CNewsTask::OnTimeout(LPINETSERVER pServer, LPDWORD pdwTimeout, IXPTYPE ixpServerType)
|
|
{
|
|
if (!!(m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)))
|
|
return(E_FAIL);
|
|
|
|
// Display a timeout dialog
|
|
return CallbackOnTimeout(pServer, ixpServerType, *pdwTimeout, (ITimeoutCallback *)this, &m_hTimeout);
|
|
}
|
|
|
|
STDMETHODIMP CNewsTask::CanConnect(LPCSTR pszAccountId, DWORD dwFlags)
|
|
{
|
|
HWND hwnd;
|
|
BOOL fPrompt = TRUE;
|
|
|
|
if (m_pUI)
|
|
m_pUI->GetWindow(&hwnd);
|
|
else
|
|
hwnd = NULL;
|
|
|
|
// Call into general CanConnect Utility
|
|
if ((m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)) || (dwFlags & CC_FLAG_DONTPROMPT))
|
|
fPrompt = FALSE;
|
|
|
|
return CallbackCanConnect(pszAccountId, hwnd, fPrompt);
|
|
}
|
|
|
|
STDMETHODIMP CNewsTask::OnLogonPrompt(LPINETSERVER pServer, IXPTYPE ixpServerType)
|
|
{
|
|
HWND hwnd;
|
|
|
|
// Close any timeout dialog, if present
|
|
CallbackCloseTimeout(&m_hTimeout);
|
|
|
|
if (!!(m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)) &&
|
|
!(ISFLAGSET(pServer->dwFlags, ISF_ALWAYSPROMPTFORPASSWORD) &&
|
|
'\0' == pServer->szPassword[0]))
|
|
return(S_FALSE);
|
|
|
|
if (m_pUI)
|
|
m_pUI->GetWindow(&hwnd);
|
|
else
|
|
hwnd = NULL;
|
|
|
|
// Call into general OnLogonPrompt Utility
|
|
return CallbackOnLogonPrompt(hwnd, pServer, ixpServerType);
|
|
}
|
|
|
|
STDMETHODIMP CNewsTask::OnComplete(STOREOPERATIONTYPE tyOperation, HRESULT hrComplete,
|
|
LPSTOREOPERATIONINFO pOpInfo, LPSTOREERROR pErrorInfo)
|
|
{
|
|
char szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES * 2], szSubject[64];
|
|
NEWSTASKSTATE ntsNextState = NTS_MAX;
|
|
LPSTR pszSubject = NULL;
|
|
LPSTR pszOpDescription = NULL;
|
|
BOOL fInsertError = FALSE;
|
|
|
|
// Close any timeout dialog, if present
|
|
CallbackCloseTimeout(&m_hTimeout);
|
|
|
|
IxpAssert(m_tyOperation != SOT_INVALID);
|
|
if (m_tyOperation != tyOperation)
|
|
return(S_OK);
|
|
|
|
switch (tyOperation)
|
|
{
|
|
case SOT_PUT_MESSAGE:
|
|
m_cPartsCompleted ++;
|
|
|
|
// Figure out if we succeeded or failed
|
|
if (FAILED(hrComplete))
|
|
{
|
|
if (!m_fPartFailed )
|
|
{
|
|
Assert(m_pUI);
|
|
|
|
// Set us up to display the error
|
|
pszOpDescription = MAKEINTRESOURCE(idsNewsTaskPostError);
|
|
pszSubject = m_rgMsgInfo[m_cCurPost].pszSubject;
|
|
if (pszSubject == NULL || *pszSubject == 0)
|
|
{
|
|
AthLoadString(idsNoSubject, szSubject, ARRAYSIZE(szSubject));
|
|
pszSubject = szSubject;
|
|
}
|
|
fInsertError = TRUE;
|
|
|
|
m_cFailed++;
|
|
m_fPartFailed = TRUE;
|
|
}
|
|
}
|
|
|
|
if (m_cPartsCompleted == m_cCurParts)
|
|
{
|
|
if (m_fPartFailed)
|
|
{
|
|
// Update the progress bar
|
|
Assert(m_pUI);
|
|
m_pUI->IncrementProgress(1);
|
|
|
|
// Move on to the next post
|
|
ntsNextState = NTS_POST_NEXT;
|
|
}
|
|
else
|
|
{
|
|
ntsNextState = NTS_POST_DISPOSE;
|
|
}
|
|
}
|
|
|
|
break; // case SOT_PUT_MESSAGE
|
|
|
|
|
|
case SOT_UPDATE_FOLDER:
|
|
if (FAILED(hrComplete))
|
|
{
|
|
FOLDERINFO fiFolderInfo;
|
|
|
|
Assert(m_pUI);
|
|
|
|
LoadString(g_hLocRes, idsUnreadCountPollErrorFmt, szRes, sizeof(szRes));
|
|
if (SUCCEEDED(g_pStore->GetFolderInfo(m_rgidGroups[m_cCurGroup], &fiFolderInfo)))
|
|
{
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, fiFolderInfo.pszName);
|
|
g_pStore->FreeRecord(&fiFolderInfo);
|
|
}
|
|
else
|
|
{
|
|
LoadString(g_hLocRes, idsUnknown, szSubject, sizeof(szSubject));
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, szSubject);
|
|
}
|
|
pszOpDescription = szBuf;
|
|
fInsertError = TRUE;
|
|
|
|
m_cFailed++;
|
|
}
|
|
|
|
// Update the progress bar
|
|
m_pUI->IncrementProgress(1);
|
|
|
|
// Move on to the next group
|
|
ntsNextState = NTS_NEWMSG_NEXTGROUP;
|
|
|
|
break; // case SOT_UPDATE_FOLDER
|
|
|
|
case SOT_SYNCING_STORE:
|
|
if (( IXP_E_HTTP_NOT_MODIFIED != hrComplete) && (FAILED(hrComplete)))
|
|
{
|
|
LoadString(g_hLocRes, idsHttpPollFailed, szBuf, sizeof(szBuf));
|
|
pszOpDescription = szBuf;
|
|
fInsertError = TRUE;
|
|
|
|
m_cFailed++;
|
|
}
|
|
|
|
// update the progress bar
|
|
m_pUI->IncrementProgress(1);
|
|
|
|
// we're done
|
|
ntsNextState = NTS_NEWMSG_END;
|
|
|
|
break; // case SOT_SYNCING_STORE
|
|
|
|
case SOT_COPYMOVE_MESSAGE:
|
|
// Update the progress bar
|
|
Assert(m_pUI);
|
|
m_pUI->IncrementProgress(1);
|
|
|
|
// Move on to the next post
|
|
ntsNextState = NTS_POST_NEXT;
|
|
|
|
if (FAILED(hrComplete))
|
|
{
|
|
Assert(m_pUI);
|
|
|
|
pszOpDescription = MAKEINTRESOURCE(IDS_SP_E_CANT_MOVETO_SENTITEMS);
|
|
fInsertError = TRUE;
|
|
}
|
|
break; // case SOT_COPYMOVE_MESSAGE
|
|
|
|
case SOT_GET_HTTP_MINPOLLINGINTERVAL:
|
|
if (SUCCEEDED(hrComplete) && pOpInfo)
|
|
{
|
|
ULARGE_INTEGER uhMinPollingInterval64 = {0};
|
|
|
|
//Convert it to seconds.
|
|
uhMinPollingInterval64.QuadPart = pOpInfo->dwMinPollingInterval * 60;
|
|
|
|
//FILETIME is intervals of 100 nano seconds. Need to convert to 100 nanoseconds
|
|
uhMinPollingInterval64.QuadPart *= HUNDRED_NANOSECONDS;
|
|
|
|
m_pAccount->SetProp(AP_HTTPMAIL_MINPOLLINGINTERVAL, (LPBYTE)&uhMinPollingInterval64, sizeof(uhMinPollingInterval64));
|
|
|
|
m_pAccount->SetPropDw(AP_HTTPMAIL_GOTPOLLINGINTERVAL, TRUE);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
if (IXP_E_HTTP_NOT_MODIFIED == hrComplete)
|
|
{
|
|
hrComplete = S_OK;
|
|
fInsertError = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (FAILED(hrComplete))
|
|
{
|
|
Assert(m_pUI);
|
|
|
|
pszOpDescription = MAKEINTRESOURCE(idsGenericError);
|
|
fInsertError = TRUE;
|
|
|
|
m_cFailed++;
|
|
}
|
|
}
|
|
break; // default case
|
|
|
|
} // switch
|
|
|
|
if (fInsertError && NULL != pErrorInfo)
|
|
{
|
|
Assert(pErrorInfo->hrResult == hrComplete); // These two should not be different
|
|
TaskUtil_InsertTransportError(ISFLAGCLEAR(m_dwFlags, DELIVER_NOUI), m_pUI, m_eidCur,
|
|
pErrorInfo, pszOpDescription, pszSubject);
|
|
}
|
|
|
|
// Move on to next state
|
|
if (IXP_E_USER_CANCEL == hrComplete)
|
|
{
|
|
// User cancelled logon prompt, so just abort everything
|
|
Cancel();
|
|
}
|
|
else if (NTS_MAX != ntsNextState)
|
|
{
|
|
m_state = ntsNextState;
|
|
PostMessage(m_hwnd, NTM_NEXTSTATE, 0, 0);
|
|
}
|
|
|
|
// Release your cancel object
|
|
SafeRelease(m_pCancel);
|
|
m_tyOperation = SOT_INVALID;
|
|
|
|
// Done
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CNewsTask::OnPrompt(HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType, INT *piUserResponse)
|
|
{
|
|
HWND hwnd;
|
|
|
|
// Close any timeout dialog, if present
|
|
CallbackCloseTimeout(&m_hTimeout);
|
|
|
|
// Raid 55082 - SPOOLER: SPA/SSL auth to NNTP does not display cert warning and fails.
|
|
#if 0
|
|
if (!!(m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)))
|
|
return(E_FAIL);
|
|
#endif
|
|
|
|
if (m_pUI)
|
|
m_pUI->GetWindow(&hwnd);
|
|
else
|
|
hwnd = NULL;
|
|
|
|
// Call into my swanky utility
|
|
return CallbackOnPrompt(hwnd, hrError, pszText, pszCaption, uType, piUserResponse);
|
|
}
|
|
|
|
STDMETHODIMP CNewsTask::OnTimeoutResponse(TIMEOUTRESPONSE eResponse)
|
|
{
|
|
// Call into general timeout response utility
|
|
return CallbackOnTimeoutResponse(eResponse, m_pCancel, &m_hTimeout);
|
|
}
|
|
|
|
STDMETHODIMP CNewsTask::GetParentWindow(DWORD dwReserved, HWND *phwndParent)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (!!(m_dwFlags & (DELIVER_NOUI | DELIVER_BACKGROUND)))
|
|
return(E_FAIL);
|
|
|
|
if (m_pUI)
|
|
{
|
|
hr = m_pUI->GetWindow(phwndParent);
|
|
}
|
|
else
|
|
{
|
|
*phwndParent = NULL;
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return(hr);
|
|
}
|