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.
4197 lines
136 KiB
4197 lines
136 KiB
/*
|
|
* h t t p s e r v . cpp
|
|
*
|
|
* Author: Greg Friedman
|
|
*
|
|
* Purpose: Derives from IMessageServer to implement HTTPMail-specific
|
|
* store communication.
|
|
*
|
|
* Copyright (C) Microsoft Corp. 1998.
|
|
*/
|
|
|
|
#include "pch.hxx"
|
|
#include "httpserv.h"
|
|
#include "httputil.h"
|
|
#include "storutil.h"
|
|
#include "serverq.h"
|
|
#include "tmap.h"
|
|
#include "acctcach.h"
|
|
#include "urlmon.h"
|
|
#include "useragnt.h"
|
|
#include "spoolapi.h"
|
|
#include "demand.h"
|
|
|
|
#define CCHMAX_RES 255
|
|
|
|
static const char s_szHTTPMailServerWndClass[] = "HTTPMailWndClass";
|
|
|
|
#define AssertSingleThreaded AssertSz(m_dwThreadId == GetCurrentThreadId(), "Multi-threading makes me sad.")
|
|
|
|
// explicit template instantiations
|
|
template class TMap<FOLDERID, CSimpleString>;
|
|
template class TPair<FOLDERID, CSimpleString>;
|
|
|
|
const UINT WM_HTTP_BEGIN_OP = WM_USER;
|
|
|
|
// SOT_SYNCING_STORE
|
|
static const HTTPSTATEFUNCS c_rgpfnSyncStore[] =
|
|
{
|
|
{ &CHTTPMailServer::Connect, NULL },
|
|
{ &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
|
|
{ &CHTTPMailServer::ListFolders, &CHTTPMailServer::HandleListFolders },
|
|
{ &CHTTPMailServer::PurgeFolders, NULL }
|
|
};
|
|
|
|
// SOT_SYNC_FOLDER
|
|
static const HTTPSTATEFUNCS c_rgpfnSyncFolder[] =
|
|
{
|
|
{ &CHTTPMailServer::Connect, NULL },
|
|
{ &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
|
|
{ &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
|
|
{ &CHTTPMailServer::PurgeFolders, NULL },
|
|
{ &CHTTPMailServer::BuildFolderUrl, NULL },
|
|
{ &CHTTPMailServer::ListHeaders, &CHTTPMailServer::HandleListHeaders },
|
|
{ &CHTTPMailServer::PurgeMessages, NULL },
|
|
{ &CHTTPMailServer::ResetMessageCounts, NULL }
|
|
};
|
|
|
|
// SOT_GET_MESSAGE
|
|
static const HTTPSTATEFUNCS c_rgpfnGetMessage[] =
|
|
{
|
|
{ &CHTTPMailServer::Connect, NULL },
|
|
{ &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
|
|
{ &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
|
|
{ &CHTTPMailServer::PurgeFolders, NULL },
|
|
{ &CHTTPMailServer::BuildFolderUrl, NULL },
|
|
{ &CHTTPMailServer::GetMessage, &CHTTPMailServer::HandleGetMessage }
|
|
};
|
|
|
|
// SOT_CREATE_FOLDER
|
|
static const HTTPSTATEFUNCS c_rgpfnCreateFolder[] =
|
|
{
|
|
{ &CHTTPMailServer::Connect, NULL },
|
|
{ &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
|
|
{ &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
|
|
{ &CHTTPMailServer::PurgeFolders, NULL },
|
|
{ &CHTTPMailServer::CreateFolder, &CHTTPMailServer::HandleCreateFolder }
|
|
};
|
|
|
|
// SOT_RENAME_FOLDER
|
|
static const HTTPSTATEFUNCS c_rgpfnRenameFolder[] =
|
|
{
|
|
{ &CHTTPMailServer::Connect, NULL },
|
|
{ &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
|
|
{ &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
|
|
{ &CHTTPMailServer::PurgeFolders, NULL },
|
|
{ &CHTTPMailServer::RenameFolder, &CHTTPMailServer::HandleRenameFolder }
|
|
};
|
|
|
|
// SOT_DELETE_FOLDER
|
|
static const HTTPSTATEFUNCS c_rgpfnDeleteFolder[] =
|
|
{
|
|
{ &CHTTPMailServer::Connect, NULL },
|
|
{ &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
|
|
{ &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
|
|
{ &CHTTPMailServer::PurgeFolders, NULL },
|
|
{ &CHTTPMailServer::DeleteFolder, &CHTTPMailServer::HandleDeleteFolder }
|
|
};
|
|
|
|
// SOT_SET_MESSAGEFLAGS
|
|
static const HTTPSTATEFUNCS c_rgpfnSetMessageFlags[] =
|
|
{
|
|
{ &CHTTPMailServer::Connect, NULL },
|
|
{ &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
|
|
{ &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
|
|
{ &CHTTPMailServer::PurgeFolders, NULL },
|
|
{ &CHTTPMailServer::BuildFolderUrl, NULL },
|
|
{ &CHTTPMailServer::SetMessageFlags, &CHTTPMailServer::HandleMemberErrors},
|
|
{ &CHTTPMailServer::ApplyFlagsToStore, NULL }
|
|
};
|
|
|
|
// SOT_DELETING_MESSAGES
|
|
static const HTTPSTATEFUNCS c_rgpfnDeleteMessages[] =
|
|
{
|
|
{ &CHTTPMailServer::Connect, NULL },
|
|
{ &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
|
|
{ &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
|
|
{ &CHTTPMailServer::PurgeFolders, NULL },
|
|
{ &CHTTPMailServer::BuildFolderUrl, NULL },
|
|
{ &CHTTPMailServer::DeleteMessages, &CHTTPMailServer::HandleMemberErrors },
|
|
{ &CHTTPMailServer::DeleteFallbackToMove, &CHTTPMailServer::HandleDeleteFallbackToMove },
|
|
{ &CHTTPMailServer::PurgeDeletedFromStore, NULL }
|
|
};
|
|
|
|
// SOT_PUT_MESSAGE
|
|
static const HTTPSTATEFUNCS c_rgpfnPutMessage[] =
|
|
{
|
|
{ &CHTTPMailServer::Connect, NULL },
|
|
{ &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
|
|
{ &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
|
|
{ &CHTTPMailServer::PurgeFolders, NULL },
|
|
{ &CHTTPMailServer::PutMessage, &CHTTPMailServer::HandlePutMessage },
|
|
{ &CHTTPMailServer::AddPutMessage, NULL }
|
|
};
|
|
|
|
// SOT_COPYMOVE_MESSAGES (copying or moving one message)
|
|
static const HTTPSTATEFUNCS c_rgpfnCopyMoveMessage[] =
|
|
{
|
|
{ &CHTTPMailServer::Connect, NULL },
|
|
{ &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
|
|
{ &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
|
|
{ &CHTTPMailServer::PurgeFolders, NULL },
|
|
{ &CHTTPMailServer::BuildFolderUrl, NULL },
|
|
{ &CHTTPMailServer::CopyMoveMessage, &CHTTPMailServer::HandleCopyMoveMessage }
|
|
};
|
|
|
|
// SOT_COPYMOVE_MESSAGES (moving multiple messages)
|
|
static const HTTPSTATEFUNCS c_rgpfnBatchCopyMoveMessages[] =
|
|
{
|
|
{ &CHTTPMailServer::Connect, NULL },
|
|
{ &CHTTPMailServer::GetMsgFolderRoot, &CHTTPMailServer::HandleGetMsgFolderRoot },
|
|
{ &CHTTPMailServer::AutoListFolders, &CHTTPMailServer::HandleListFolders },
|
|
{ &CHTTPMailServer::PurgeFolders, NULL },
|
|
{ &CHTTPMailServer::BuildFolderUrl, NULL },
|
|
{ &CHTTPMailServer::BatchCopyMoveMessages, &CHTTPMailServer::HandleBatchCopyMoveMessages},
|
|
{ &CHTTPMailServer::FinalizeBatchCopyMove, NULL }
|
|
};
|
|
|
|
// SOT_GET_ADURL (gets ad url from Hotmail)
|
|
static const HTTPSTATEFUNCS c_rgpfnGetAdUrl[] =
|
|
{
|
|
{ &CHTTPMailServer::Connect, NULL },
|
|
{ &CHTTPMailServer::GetAdBarUrlFromServer, NULL }
|
|
};
|
|
|
|
|
|
// SOT_GET_HTTP_MINPOLLINGINTERVAL (gets Minimum polling interval from http server)
|
|
static const HTTPSTATEFUNCS c_rgpfnGetMinPollingInterval[] =
|
|
{
|
|
{ &CHTTPMailServer::Connect, NULL },
|
|
{ &CHTTPMailServer::GetMinPollingInterval, NULL }
|
|
};
|
|
|
|
class CFolderList
|
|
{
|
|
public:
|
|
// Public factory function.
|
|
static HRESULT Create(IMessageStore *pStore, FOLDERID idRoot, CFolderList **ppFolderList);
|
|
|
|
private:
|
|
// Constructor is private. Use "Create" to instantiate.
|
|
CFolderList();
|
|
~CFolderList();
|
|
|
|
private:
|
|
// unimplemented copy constructor/assignment operator
|
|
CFolderList(const CFolderList& other);
|
|
CFolderList& operator=(const CFolderList& other);
|
|
|
|
public:
|
|
ULONG AddRef(void);
|
|
ULONG Release(void);
|
|
|
|
FOLDERID FindAndRemove(LPSTR pszUrlComponent, DWORD *pcMessages, DWORD *pcUnread);
|
|
FOLDERID FindAndRemove(SPECIALFOLDER tySpecial, DWORD *pcMessages, DWORD *pcUnread);
|
|
|
|
void PurgeRemainingFromStore(void);
|
|
private:
|
|
typedef struct tagFOLDERLISTNODE
|
|
{
|
|
LPSTR pszUrlComponent;
|
|
FLDRFLAGS dwFlags;
|
|
FOLDERID idFolder;
|
|
SPECIALFOLDER tySpecial;
|
|
DWORD cMessages;
|
|
DWORD cUnread;
|
|
tagFOLDERLISTNODE *pflnNext;
|
|
} FOLDERLISTNODE, *LPFOLDERLISTNODE;
|
|
|
|
LPFOLDERLISTNODE _AllocNode(void)
|
|
{
|
|
LPFOLDERLISTNODE pflnNode = new FOLDERLISTNODE;
|
|
if (pflnNode)
|
|
{
|
|
pflnNode->pszUrlComponent = NULL;
|
|
pflnNode->dwFlags = 0;
|
|
pflnNode->idFolder = FOLDERID_INVALID;
|
|
pflnNode->tySpecial = FOLDER_NOTSPECIAL;
|
|
pflnNode->cMessages = 0;
|
|
pflnNode->cUnread = 0;
|
|
pflnNode->pflnNext = NULL;
|
|
}
|
|
return pflnNode;
|
|
}
|
|
|
|
HRESULT HrInitialize(IMessageStore *pStore, FOLDERID idRoot);
|
|
|
|
void _FreeNode(LPFOLDERLISTNODE pflnNode)
|
|
{
|
|
if (pflnNode)
|
|
{
|
|
SafeMemFree(pflnNode->pszUrlComponent);
|
|
delete pflnNode;
|
|
}
|
|
}
|
|
|
|
void _FreeList(void);
|
|
|
|
private:
|
|
ULONG m_cRef;
|
|
IMessageStore *m_pStore;
|
|
LPFOLDERLISTNODE m_pflnList;
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// CFolderList::Create
|
|
//----------------------------------------------------------------------
|
|
|
|
HRESULT CFolderList::Create(IMessageStore *pStore, FOLDERID idRoot, CFolderList **ppFolderList)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CFolderList *pFolderList = NULL;
|
|
|
|
if (NULL == pStore || FOLDERID_INVALID == idRoot || NULL == ppFolderList)
|
|
{
|
|
hr = TraceResult(E_INVALIDARG);
|
|
goto exit;
|
|
}
|
|
|
|
*ppFolderList = NULL;
|
|
pFolderList = new CFolderList();
|
|
if (!pFolderList)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
IF_FAILEXIT(hr = pFolderList->HrInitialize(pStore, idRoot));
|
|
|
|
*ppFolderList = pFolderList;
|
|
pFolderList = NULL;
|
|
|
|
exit:
|
|
|
|
SafeRelease(pFolderList);
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CFolderList::CFolderList
|
|
//----------------------------------------------------------------------
|
|
CFolderList::CFolderList(void) :
|
|
m_cRef(1),
|
|
m_pStore(NULL),
|
|
m_pflnList(NULL)
|
|
{
|
|
// nothing to do
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CFolderList::~CFolderList
|
|
//----------------------------------------------------------------------
|
|
CFolderList::~CFolderList(void)
|
|
{
|
|
_FreeList();
|
|
SafeRelease(m_pStore);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CFolderList::AddRef
|
|
//----------------------------------------------------------------------
|
|
ULONG CFolderList::AddRef(void)
|
|
{
|
|
return (++m_cRef);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CFolderList::Release
|
|
//----------------------------------------------------------------------
|
|
ULONG CFolderList::Release(void)
|
|
{
|
|
if (0 == --m_cRef)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
else
|
|
return m_cRef;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CFolderList::_FreeList
|
|
//----------------------------------------------------------------------
|
|
void CFolderList::_FreeList(void)
|
|
{
|
|
LPFOLDERLISTNODE pflnDeleteMe;
|
|
|
|
while (m_pflnList)
|
|
{
|
|
pflnDeleteMe = m_pflnList;
|
|
m_pflnList = m_pflnList->pflnNext;
|
|
|
|
_FreeNode(pflnDeleteMe);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CFolderList::HrInitialize
|
|
//----------------------------------------------------------------------
|
|
HRESULT CFolderList::HrInitialize(IMessageStore *pStore, FOLDERID idRoot)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
IEnumerateFolders *pFldrEnum = NULL;
|
|
FOLDERINFO fi;
|
|
FOLDERLISTNODE flnDummyHead= { NULL, 0, 0, NULL };
|
|
LPFOLDERLISTNODE pflnTail = &flnDummyHead;
|
|
LPFOLDERLISTNODE pflnNewNode = NULL;
|
|
|
|
if (NULL == pStore)
|
|
{
|
|
hr = TraceResult(E_INVALIDARG);
|
|
return hr;
|
|
}
|
|
|
|
if (NULL != m_pflnList)
|
|
{
|
|
hr = TraceResult(ERROR_ALREADY_INITIALIZED);
|
|
return hr;
|
|
}
|
|
|
|
m_pStore = pStore;
|
|
m_pStore->AddRef();
|
|
|
|
// this function assumes that the folder list is flat.
|
|
// it needs to be modified to support a hierarchical store.
|
|
|
|
IF_FAILEXIT(hr = pStore->EnumChildren(idRoot, FALSE, &pFldrEnum));
|
|
|
|
pFldrEnum->Reset();
|
|
|
|
// build a linked list of folder nodes
|
|
while (S_OK == pFldrEnum->Next(1, &fi, NULL))
|
|
{
|
|
pflnNewNode = _AllocNode();
|
|
if (NULL == pflnNewNode)
|
|
{
|
|
hr = TraceResult(E_OUTOFMEMORY);
|
|
pStore->FreeRecord(&fi);
|
|
_FreeList();
|
|
goto exit;
|
|
}
|
|
|
|
pflnNewNode->pszUrlComponent = PszDupA(fi.pszUrlComponent);
|
|
pflnNewNode->dwFlags = fi.dwFlags;
|
|
pflnNewNode->idFolder = fi.idFolder;
|
|
pflnNewNode->tySpecial = fi.tySpecial;
|
|
pflnNewNode->cMessages = fi.cMessages;
|
|
pflnNewNode->cUnread = fi.cUnread;
|
|
|
|
pflnTail->pflnNext = pflnNewNode;
|
|
pflnTail = pflnNewNode;
|
|
pflnNewNode = NULL;
|
|
|
|
pStore->FreeRecord(&fi);
|
|
}
|
|
|
|
m_pflnList = flnDummyHead.pflnNext;
|
|
|
|
exit:
|
|
ReleaseObj(pFldrEnum);
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CFolderList::FindAndRemove
|
|
//----------------------------------------------------------------------
|
|
FOLDERID CFolderList::FindAndRemove(LPSTR pszUrlComponent,
|
|
DWORD *pcMessages,
|
|
DWORD *pcUnread)
|
|
{
|
|
LPFOLDERLISTNODE pflnPrev = NULL;
|
|
LPFOLDERLISTNODE pflnCur = m_pflnList;
|
|
FOLDERID idFound = FOLDERID_INVALID;
|
|
|
|
if (NULL == pszUrlComponent)
|
|
return FOLDERID_INVALID;
|
|
|
|
if (pcMessages)
|
|
*pcMessages = 0;
|
|
if (pcUnread)
|
|
*pcUnread = 0;
|
|
|
|
while (pflnCur)
|
|
{
|
|
if ((NULL != pflnCur->pszUrlComponent) && (0 == lstrcmp(pflnCur->pszUrlComponent, pszUrlComponent)))
|
|
{
|
|
if (NULL == pflnPrev)
|
|
m_pflnList = pflnCur->pflnNext;
|
|
else
|
|
pflnPrev->pflnNext = pflnCur->pflnNext;
|
|
|
|
idFound = pflnCur->idFolder;
|
|
if (pcMessages)
|
|
*pcMessages = pflnCur->cMessages;
|
|
if (pcUnread)
|
|
*pcUnread = pflnCur->cUnread;
|
|
|
|
_FreeNode(pflnCur);
|
|
break;
|
|
}
|
|
|
|
pflnPrev = pflnCur;
|
|
pflnCur = pflnCur->pflnNext;
|
|
}
|
|
|
|
return idFound;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CFolderList::FindAndRemove
|
|
//----------------------------------------------------------------------
|
|
FOLDERID CFolderList::FindAndRemove(SPECIALFOLDER tySpecial,
|
|
DWORD *pcMessages,
|
|
DWORD *pcUnread)
|
|
{
|
|
LPFOLDERLISTNODE pflnPrev = NULL;
|
|
LPFOLDERLISTNODE pflnCur = m_pflnList;
|
|
FOLDERID idFound = FOLDERID_INVALID;
|
|
|
|
if (FOLDER_NOTSPECIAL == tySpecial)
|
|
return FOLDERID_INVALID;
|
|
|
|
if (pcMessages)
|
|
*pcMessages = 0;
|
|
if (pcUnread)
|
|
*pcUnread = 0;
|
|
|
|
while (pflnCur)
|
|
{
|
|
if (pflnCur->tySpecial == tySpecial)
|
|
{
|
|
if (NULL == pflnPrev)
|
|
m_pflnList = pflnCur->pflnNext;
|
|
else
|
|
pflnPrev->pflnNext = pflnCur->pflnNext;
|
|
|
|
idFound = pflnCur->idFolder;
|
|
if (pcMessages)
|
|
*pcMessages = pflnCur->cMessages;
|
|
if (pcUnread)
|
|
*pcUnread = pflnCur->cUnread;
|
|
|
|
_FreeNode(pflnCur);
|
|
break;
|
|
}
|
|
|
|
pflnPrev = pflnCur;
|
|
pflnCur = pflnCur->pflnNext;
|
|
}
|
|
|
|
return idFound;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CFolderList::PurgeRemainingFromStore
|
|
//----------------------------------------------------------------------
|
|
void CFolderList::PurgeRemainingFromStore(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPFOLDERLISTNODE pflnCur = m_pflnList;
|
|
LPFOLDERLISTNODE pflnDeleteMe = NULL;
|
|
|
|
// take ownership of the list
|
|
m_pflnList = NULL;
|
|
|
|
while (pflnCur)
|
|
{
|
|
m_pStore->DeleteFolder(pflnCur->idFolder, DELETE_FOLDER_DELETESPECIAL | DELETE_FOLDER_NOTRASHCAN, NULL);
|
|
pflnDeleteMe = pflnCur;
|
|
pflnCur = pflnCur->pflnNext;
|
|
|
|
_FreeNode(pflnDeleteMe);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// FreeNewMessageInfo
|
|
//----------------------------------------------------------------------
|
|
static void __cdecl FreeNewMessageInfo(LPVOID pnmi)
|
|
{
|
|
Assert(NULL != pnmi);
|
|
|
|
SafeMemFree(((LPNEWMESSAGEINFO)pnmi)->pszUrlComponent);
|
|
|
|
MemFree(pnmi);
|
|
}
|
|
|
|
#ifndef NOHTTPMAIL
|
|
|
|
//----------------------------------------------------------------------
|
|
// CreateHTTPMailStore (factory function)
|
|
//----------------------------------------------------------------------
|
|
HRESULT CreateHTTPMailStore(IUnknown *pUnkOuter, IUnknown **ppUnknown)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Trace
|
|
TraceCall("CreateHTTPMailStore");
|
|
|
|
// Invalid Args
|
|
Assert(NULL != ppUnknown);
|
|
if (NULL == ppUnknown)
|
|
return E_INVALIDARG;
|
|
|
|
// Initialize
|
|
*ppUnknown = NULL;
|
|
|
|
// Create me
|
|
CHTTPMailServer *pNew = new CHTTPMailServer();
|
|
if (NULL == pNew)
|
|
return TraceResult(E_OUTOFMEMORY);
|
|
|
|
// Cast to unknown
|
|
//*ppUnknown = SAFECAST(pNew, IMessageServer *);
|
|
|
|
hr = CreateServerQueue(pNew, (IMessageServer **)ppUnknown);
|
|
pNew->Release(); // Since we're not returning this ptr, bump down refcount
|
|
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::CHTTPMailServer
|
|
//----------------------------------------------------------------------
|
|
CHTTPMailServer::CHTTPMailServer(void) :
|
|
m_cRef(1),
|
|
m_hwnd(NULL),
|
|
m_pStore(NULL),
|
|
m_pFolder(NULL),
|
|
m_pTransport(NULL),
|
|
m_pszFldrLeafName(NULL),
|
|
m_pszMsgFolderRoot(NULL),
|
|
m_idServer(FOLDERID_INVALID),
|
|
m_idFolder(FOLDERID_INVALID),
|
|
m_tySpecialFolder(FOLDER_NOTSPECIAL),
|
|
m_pszFolderUrl(NULL),
|
|
m_fConnected(FALSE),
|
|
m_pTransport2(NULL),
|
|
m_pAccount(NULL)
|
|
{
|
|
_FreeOperation(FALSE);
|
|
|
|
ZeroMemory(&m_rInetServerInfo, sizeof(INETSERVER));
|
|
|
|
m_szAccountName[0] = '\0';
|
|
m_szAccountId[0] = '\0';
|
|
|
|
m_op.pszAdUrl = NULL;
|
|
|
|
#ifdef DEBUG
|
|
m_dwThreadId = GetCurrentThreadId();
|
|
#endif // DEBUG
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::~CHTTPMailServer
|
|
//----------------------------------------------------------------------
|
|
CHTTPMailServer::~CHTTPMailServer(void)
|
|
{
|
|
// Close the window
|
|
if ((NULL != m_hwnd) && (FALSE != IsWindow(m_hwnd)))
|
|
SendMessage(m_hwnd, WM_CLOSE, 0, 0);
|
|
|
|
ZeroMemory(&m_rInetServerInfo, sizeof(m_rInetServerInfo)); // Done for security
|
|
|
|
SafeRelease(m_pStore);
|
|
SafeRelease(m_pFolder);
|
|
SafeRelease(m_pTransport);
|
|
SafeRelease(m_pTransport2);
|
|
SafeRelease(m_pAccount);
|
|
|
|
SafeMemFree(m_pszFldrLeafName);
|
|
SafeMemFree(m_pszMsgFolderRoot);
|
|
SafeMemFree(m_pszFolderUrl);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// IUnknown Members
|
|
//----------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::QueryInterface
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
TraceCall("CHTTPMailServer::QueryInterface");
|
|
|
|
if (NULL == ppv)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
if (IID_IUnknown == riid || IID_IMessageServer == riid)
|
|
*ppv = (IMessageServer *)this;
|
|
else if (IID_ITransportCallback == riid)
|
|
*ppv = (ITransportCallback *)this;
|
|
else if (IID_IHTTPMailCallback == riid)
|
|
*ppv = (IHTTPMailCallback *)this;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
hr = E_NOINTERFACE;
|
|
goto exit;
|
|
}
|
|
|
|
// the interface was found. addref it
|
|
((IUnknown *)*ppv)->AddRef();
|
|
|
|
exit:
|
|
// done
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::AddRef
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CHTTPMailServer::AddRef(void)
|
|
{
|
|
TraceCall("CHTTPMailServer::AddRef");
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::AddRef
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CHTTPMailServer::Release(void)
|
|
{
|
|
TraceCall("CHTTPMailServer::Release");
|
|
ULONG cRef = InterlockedDecrement(&m_cRef);
|
|
|
|
Assert(((LONG)cRef) >= 0);
|
|
if (0 == cRef)
|
|
delete this;
|
|
return cRef;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// IMessageServer Members
|
|
//----------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::Initialize
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::Initialize( IMessageStore *pStore,
|
|
FOLDERID idStoreRoot,
|
|
IMessageFolder *pFolder,
|
|
FOLDERID idFolder)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
FOLDERINFO fi;
|
|
|
|
AssertSingleThreaded;
|
|
|
|
if (NULL == pStore || FOLDERID_INVALID == idStoreRoot)
|
|
return TraceResult(E_INVALIDARG);
|
|
|
|
if (!_CreateWnd())
|
|
return E_FAIL;
|
|
|
|
m_idServer = idStoreRoot;
|
|
m_idFolder = idFolder;
|
|
|
|
ReplaceInterface(m_pFolder, pFolder);
|
|
ReplaceInterface(m_pStore, pStore);
|
|
|
|
if (FAILED(hr = m_pStore->GetFolderInfo(idStoreRoot, &fi)))
|
|
goto exit;
|
|
|
|
Assert(!!(fi.dwFlags & FOLDER_SERVER));
|
|
StrCpyN(m_szAccountId, fi.pszAccountId, ARRAYSIZE(m_szAccountId));
|
|
|
|
m_pStore->FreeRecord(&fi);
|
|
|
|
// if we were passed a valid folder id, check to see if this folder is special?
|
|
// we might get passed a bad folder id when we are syncing the store.
|
|
if (FOLDERID_INVALID != idFolder)
|
|
{
|
|
if (FAILED(hr = m_pStore->GetFolderInfo(idFolder, &fi)))
|
|
goto exit;
|
|
|
|
m_tySpecialFolder = fi.tySpecial;
|
|
m_pStore->FreeRecord(&fi);
|
|
}
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CHTTPMailServer::ResetFolder( IMessageFolder *pFolder,
|
|
FOLDERID idFolder)
|
|
{
|
|
return(E_NOTIMPL);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::SetIdleCallback
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::SetIdleCallback(IStoreCallback *pDefaultCallback)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::SynchronizeFolder
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::SynchronizeFolder(
|
|
SYNCFOLDERFLAGS dwFlags,
|
|
DWORD cHeaders,
|
|
IStoreCallback *pCallback)
|
|
{
|
|
TraceCall("CHTTPMailServer::SynchronizeFolder");
|
|
|
|
AssertSingleThreaded;
|
|
Assert(NULL != pCallback);
|
|
Assert(SOT_INVALID == m_op.tyOperation);
|
|
Assert(NULL != m_pStore);
|
|
|
|
if (NULL == pCallback)
|
|
return E_INVALIDARG;
|
|
|
|
m_op.tyOperation = SOT_SYNC_FOLDER;
|
|
m_op.iState = 0;
|
|
m_op.pfnState = c_rgpfnSyncFolder;
|
|
m_op.cState = ARRAYSIZE(c_rgpfnSyncFolder);
|
|
m_op.dwSyncFlags = dwFlags;
|
|
m_op.pCallback = pCallback;
|
|
m_op.pCallback->AddRef();
|
|
|
|
return _BeginDeferredOperation();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::GetMessage
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::GetMessage(
|
|
MESSAGEID idMessage,
|
|
IStoreCallback *pCallback)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
TraceCall("CHTTPMailServer::GetMessage");
|
|
|
|
AssertSingleThreaded;
|
|
Assert(NULL != pCallback);
|
|
Assert(SOT_INVALID == m_op.tyOperation);
|
|
Assert(NULL != m_pStore);
|
|
|
|
if (NULL == pCallback)
|
|
return E_INVALIDARG;
|
|
|
|
if (FAILED(hr = CreatePersistentWriteStream(m_pFolder, &m_op.pMessageStream, &m_op.faStream)))
|
|
goto exit;
|
|
|
|
m_op.tyOperation = SOT_GET_MESSAGE;
|
|
m_op.pfnState = c_rgpfnGetMessage;
|
|
m_op.iState = 0;
|
|
m_op.cState = ARRAYSIZE(c_rgpfnGetMessage);
|
|
m_op.pCallback = pCallback;
|
|
m_op.pCallback->AddRef();
|
|
m_op.idMessage = idMessage;
|
|
|
|
hr = _BeginDeferredOperation();
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::PutMessage
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::PutMessage(
|
|
FOLDERID idFolder,
|
|
MESSAGEFLAGS dwFlags,
|
|
LPFILETIME pftReceived,
|
|
IStream *pStream,
|
|
IStoreCallback *pCallback)
|
|
{
|
|
TraceCall("CHTTPMailServer::PutMessage");
|
|
|
|
AssertSingleThreaded;
|
|
Assert(NULL != pCallback);
|
|
Assert(SOT_INVALID == m_op.tyOperation);
|
|
Assert(NULL != m_pStore);
|
|
|
|
if (NULL == pStream || NULL == pCallback)
|
|
return E_INVALIDARG;
|
|
|
|
if (FOLDER_MSNPROMO == m_tySpecialFolder)
|
|
return SP_E_HTTP_CANTMODIFYMSNFOLDER;
|
|
|
|
m_op.tyOperation = SOT_PUT_MESSAGE;
|
|
m_op.pfnState = c_rgpfnPutMessage;
|
|
m_op.iState = 0;
|
|
m_op.cState = ARRAYSIZE(c_rgpfnPutMessage);
|
|
m_op.pCallback = pCallback;
|
|
m_op.pCallback->AddRef();
|
|
m_op.idFolder = idFolder;
|
|
m_op.pMessageStream = pStream;
|
|
m_op.pMessageStream->AddRef();
|
|
m_op.dwMsgFlags = dwFlags;
|
|
|
|
return _BeginDeferredOperation();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::CopyMessages
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::CopyMessages(
|
|
IMessageFolder *pDest,
|
|
COPYMESSAGEFLAGS dwOptions,
|
|
LPMESSAGEIDLIST pList,
|
|
LPADJUSTFLAGS pFlags,
|
|
IStoreCallback *pCallback)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
FOLDERID idFolder;
|
|
FOLDERINFO fi = {0};
|
|
LPFOLDERINFO pfiFree = NULL;
|
|
|
|
|
|
TraceCall("CHTTPMailServer::CopyMessages");
|
|
|
|
if (NULL == pDest)
|
|
return E_INVALIDARG;
|
|
|
|
Assert(NULL != m_pStore);
|
|
|
|
// disallow moving or copying into the msn promo folder
|
|
IF_FAILEXIT(hr = pDest->GetFolderId(&idFolder));
|
|
IF_FAILEXIT(hr = m_pStore->GetFolderInfo(idFolder, &fi));
|
|
|
|
pfiFree = &fi;
|
|
|
|
if (FOLDER_MSNPROMO == fi.tySpecial)
|
|
{
|
|
hr = TraceResult(SP_E_HTTP_CANTMODIFYMSNFOLDER);
|
|
goto exit;
|
|
}
|
|
// convert moves out of the promo folder into copies
|
|
if (FOLDER_MSNPROMO == m_tySpecialFolder)
|
|
dwOptions = (dwOptions & ~COPY_MESSAGE_MOVE);
|
|
|
|
hr = _DoCopyMoveMessages(SOT_COPYMOVE_MESSAGE, pDest, dwOptions, pList, pCallback);
|
|
exit:
|
|
if (NULL != pfiFree)
|
|
m_pStore->FreeRecord(pfiFree);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::DeleteMessages
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::DeleteMessages(DELETEMESSAGEFLAGS dwOptions,
|
|
LPMESSAGEIDLIST pList,
|
|
IStoreCallback *pCallback)
|
|
{
|
|
TraceCall("CHTTPMailServer::DeleteMessages");
|
|
|
|
AssertSingleThreaded;
|
|
Assert(NULL == pList || pList->cMsgs > 0);
|
|
Assert(SOT_INVALID == m_op.tyOperation);
|
|
Assert(NULL != m_pStore);
|
|
|
|
// we don't allow messages to be deleted out of the msnpromo folder
|
|
if (FOLDER_MSNPROMO == m_tySpecialFolder)
|
|
{
|
|
// this is a hack. we test this flag to determine that the
|
|
//operation is being performed as the last phase of a move
|
|
// into a local folder. when this is the case, we fail
|
|
// silently.
|
|
if (!!(DELETE_MESSAGE_MAYIGNORENOTRASH & dwOptions))
|
|
return S_OK;
|
|
else
|
|
return SP_E_HTTP_CANTMODIFYMSNFOLDER;
|
|
}
|
|
|
|
if ((NULL !=pList && 0 == pList->cMsgs) || NULL == pCallback)
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = S_OK;
|
|
IMessageFolder *pDeletedItems = NULL;
|
|
|
|
m_op.dwDelMsgFlags = dwOptions;
|
|
|
|
// if the current folder is the deleted items folder, then delete the
|
|
// messages, otherwise move them to deleted items
|
|
if (FOLDER_DELETED != m_tySpecialFolder && !(dwOptions & DELETE_MESSAGE_NOTRASHCAN))
|
|
{
|
|
// find the deleted items folder
|
|
if (SUCCEEDED(m_pStore->OpenSpecialFolder(m_idServer, NULL, FOLDER_DELETED, &pDeletedItems)) && NULL != pDeletedItems)
|
|
{
|
|
hr = _DoCopyMoveMessages(SOT_DELETING_MESSAGES, pDeletedItems, COPY_MESSAGE_MOVE, pList, pCallback);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// handle the case where the messages are not in the deleted items folder
|
|
// if pList is null, apply the operation to the entire folder
|
|
if (NULL != pList)
|
|
hr = CloneMessageIDList(pList, &m_op.pIDList);
|
|
else
|
|
hr = m_pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &m_op.hRowSet);
|
|
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
m_op.tyOperation = SOT_DELETING_MESSAGES;
|
|
m_op.pfnState = c_rgpfnDeleteMessages;
|
|
m_op.iState = 0;
|
|
m_op.cState = ARRAYSIZE(c_rgpfnDeleteMessages);
|
|
m_op.pCallback = pCallback;
|
|
m_op.pCallback->AddRef();
|
|
|
|
hr = _BeginDeferredOperation();
|
|
|
|
exit:
|
|
SafeRelease(pDeletedItems);
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::SetMessageFlags
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::SetMessageFlags(
|
|
LPMESSAGEIDLIST pList,
|
|
LPADJUSTFLAGS pFlags,
|
|
SETMESSAGEFLAGSFLAGS dwFlags,
|
|
IStoreCallback *pCallback)
|
|
{
|
|
TraceCall("CHTTPMailServer::SetMessageFlags");
|
|
|
|
AssertSingleThreaded;
|
|
Assert(NULL == pList || pList->cMsgs > 0);
|
|
Assert(NULL != pCallback);
|
|
Assert(m_op.tyOperation == SOT_INVALID);
|
|
Assert(m_pStore != NULL);
|
|
|
|
if ((NULL !=pList && 0 == pList->cMsgs) || NULL == pFlags || NULL == pCallback)
|
|
return E_INVALIDARG;
|
|
|
|
// the only remote flag supported by httpmail is the "read" flag
|
|
// it is an error to attempt to set or unset any other flag
|
|
Assert(0 == (pFlags->dwRemove & ~ARF_READ));
|
|
Assert(0 == (pFlags->dwAdd & ~ARF_READ));
|
|
Assert((ARF_READ == (ARF_READ & pFlags->dwRemove)) || (ARF_READ == (ARF_READ & pFlags->dwAdd)));
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// if pList is null, apply the operation to the entire folder
|
|
if (NULL != pList)
|
|
hr = CloneMessageIDList(pList, &m_op.pIDList);
|
|
else
|
|
hr = m_pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &m_op.hRowSet);
|
|
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
m_op.tyOperation = SOT_SET_MESSAGEFLAGS;
|
|
m_op.pfnState = c_rgpfnSetMessageFlags;
|
|
m_op.cState = ARRAYSIZE(c_rgpfnSetMessageFlags);
|
|
m_op.iState = 0;
|
|
m_op.pCallback = pCallback;
|
|
m_op.pCallback->AddRef();
|
|
m_op.fMarkRead = !!(pFlags->dwAdd & ARF_READ);
|
|
m_op.dwSetFlags = dwFlags;
|
|
|
|
return _BeginDeferredOperation();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::GetServerMessageFlags
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::GetServerMessageFlags(MESSAGEFLAGS *pFlags)
|
|
{
|
|
if (NULL == pFlags)
|
|
return E_INVALIDARG;
|
|
|
|
*pFlags = ARF_READ;
|
|
return S_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::SynchronizeStore
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::SynchronizeStore(
|
|
FOLDERID idParent,
|
|
SYNCSTOREFLAGS dwFlags,
|
|
IStoreCallback *pCallback)
|
|
{
|
|
TraceCall("CHTTPMailServer::SynchronizeStore");
|
|
|
|
AssertSingleThreaded;
|
|
Assert(pCallback != NULL);
|
|
Assert(m_op.tyOperation == SOT_INVALID);
|
|
Assert(m_pStore != NULL);
|
|
|
|
if (NULL == pCallback)
|
|
return E_INVALIDARG;
|
|
|
|
m_op.tyOperation = SOT_SYNCING_STORE;
|
|
m_op.pfnState = c_rgpfnSyncStore;
|
|
m_op.iState = 0;
|
|
m_op.cState = ARRAYSIZE(c_rgpfnSyncStore);
|
|
m_op.pCallback = pCallback;
|
|
m_op.pCallback->AddRef();
|
|
|
|
return _BeginDeferredOperation();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::CreateFolder
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::CreateFolder(
|
|
FOLDERID idParent,
|
|
SPECIALFOLDER tySpecial,
|
|
LPCSTR pszName,
|
|
FLDRFLAGS dwFlags,
|
|
IStoreCallback *pCallback)
|
|
{
|
|
TraceCall("CHTTPMailServer::CreateFolder");
|
|
|
|
AssertSingleThreaded;
|
|
Assert(NULL != pCallback);
|
|
Assert(m_op.tyOperation == SOT_INVALID);
|
|
Assert(NULL != m_pStore);
|
|
|
|
// why would we be called to create a special folder?
|
|
Assert(FOLDER_NOTSPECIAL == tySpecial);
|
|
|
|
if (NULL == pCallback || NULL == pszName)
|
|
return E_INVALIDARG;
|
|
|
|
// hotmail doesn't support hierarchical folders.
|
|
Assert(m_idServer == idParent);
|
|
if (m_idServer != idParent)
|
|
return E_FAIL;
|
|
|
|
m_op.pszFolderName = PszDupA(pszName);
|
|
if (NULL == m_op.pszFolderName)
|
|
return E_OUTOFMEMORY;
|
|
|
|
m_op.tyOperation = SOT_CREATE_FOLDER;
|
|
m_op.pfnState = c_rgpfnCreateFolder;
|
|
m_op.iState = 0;
|
|
m_op.cState = ARRAYSIZE(c_rgpfnCreateFolder);
|
|
m_op.pCallback = pCallback;
|
|
m_op.pCallback->AddRef();
|
|
m_op.dwFldrFlags = dwFlags;
|
|
|
|
return _BeginDeferredOperation();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::MoveFolder
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::MoveFolder(FOLDERID idFolder, FOLDERID idParentNew, IStoreCallback *pCallback)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::RenameFolder
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::RenameFolder(FOLDERID idFolder,
|
|
LPCSTR pszName,
|
|
IStoreCallback *pCallback)
|
|
{
|
|
TraceCall("CHTTPMailServer::RenameFolder");
|
|
|
|
AssertSingleThreaded;
|
|
Assert(NULL != pCallback);
|
|
Assert(SOT_INVALID == m_op.tyOperation);
|
|
Assert(NULL != m_pStore);
|
|
Assert(NULL != pszName);
|
|
|
|
// don't allow the user to rename the promo folder
|
|
if (FOLDER_MSNPROMO == m_tySpecialFolder)
|
|
return SP_E_HTTP_CANTMODIFYMSNFOLDER;
|
|
|
|
if (NULL == pszName || NULL == pCallback)
|
|
return E_INVALIDARG;
|
|
|
|
m_op.pszFolderName = PszDupA(pszName);
|
|
if (NULL == m_op.pszFolderName)
|
|
{
|
|
TraceResult(E_OUTOFMEMORY);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
m_op.idFolder = idFolder;
|
|
|
|
m_op.tyOperation = SOT_RENAME_FOLDER;
|
|
m_op.iState = 0;
|
|
m_op.pfnState = c_rgpfnRenameFolder;
|
|
m_op.cState = ARRAYSIZE(c_rgpfnRenameFolder);
|
|
m_op.pCallback = pCallback;
|
|
m_op.pCallback->AddRef();
|
|
|
|
return _BeginDeferredOperation();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::DeleteFolder
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::DeleteFolder(FOLDERID idFolder,
|
|
DELETEFOLDERFLAGS dwFlags,
|
|
IStoreCallback *pCallback)
|
|
{
|
|
TraceCall("CHTTPMailServer::DeleteFolder");
|
|
|
|
AssertSingleThreaded;
|
|
Assert(NULL != pCallback);
|
|
Assert(SOT_INVALID == m_op.tyOperation);
|
|
Assert(NULL != m_pStore);
|
|
Assert(FOLDERID_INVALID != idFolder);
|
|
|
|
// don't allow the user to delete the msn promo folder
|
|
if (FOLDER_MSNPROMO == m_tySpecialFolder)
|
|
return SP_E_HTTP_CANTMODIFYMSNFOLDER;
|
|
|
|
// we don't support hierarchical folders - if we are asked to delete
|
|
// the children of a folder, just return immediately
|
|
if (!!(DELETE_FOLDER_CHILDRENONLY & dwFlags))
|
|
return S_OK;
|
|
|
|
if (NULL == pCallback || FOLDERID_INVALID == idFolder)
|
|
return E_INVALIDARG;
|
|
|
|
m_op.idFolder = idFolder;
|
|
|
|
m_op.tyOperation = SOT_DELETE_FOLDER;
|
|
m_op.iState = 0;
|
|
m_op.pfnState = c_rgpfnDeleteFolder;
|
|
m_op.cState = ARRAYSIZE(c_rgpfnDeleteFolder);
|
|
m_op.pCallback = pCallback;
|
|
m_op.pCallback->AddRef();
|
|
|
|
return _BeginDeferredOperation();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::SubscribeToFolder
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::SubscribeToFolder(FOLDERID idFolder, BOOL fSubscribe, IStoreCallback *pCallback)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::Close
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::Close(DWORD dwFlags)
|
|
{
|
|
// if we are processing a command, cancel it
|
|
Cancel(CT_CANCEL);
|
|
|
|
if (dwFlags & MSGSVRF_DROP_CONNECTION)
|
|
_SetConnected(FALSE);
|
|
|
|
if (dwFlags & MSGSVRF_HANDS_OFF_SERVER)
|
|
{
|
|
if (m_pTransport)
|
|
{
|
|
m_pTransport->DropConnection();
|
|
m_pTransport->HandsOffCallback();
|
|
m_pTransport->Release();
|
|
m_pTransport = NULL;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::GetFolderCounts
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::GetFolderCounts(FOLDERID idFolder, IStoreCallback *pCallback)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::GetNewGroups
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::GetNewGroups(LPSYSTEMTIME pSysTime, IStoreCallback *pCallback)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::OnLogonPrompt
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::OnLogonPrompt(
|
|
LPINETSERVER pInetServer,
|
|
IInternetTransport *pTransport)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPSTR pszCachedPassword = NULL;
|
|
INETSERVER rInetServer;
|
|
|
|
TraceCall("CHTTPMailServer::OnLogonPrompt");
|
|
|
|
AssertSingleThreaded;
|
|
Assert(pInetServer != NULL);
|
|
Assert(pTransport != NULL);
|
|
Assert(m_op.tyOperation != SOT_INVALID);
|
|
Assert(m_op.pCallback != NULL);
|
|
|
|
// pull password out of the cache
|
|
GetAccountPropStrA(m_szAccountId, CAP_PASSWORD, &pszCachedPassword);
|
|
if (NULL != pszCachedPassword && 0 != lstrcmp(pszCachedPassword, pInetServer->szPassword))
|
|
{
|
|
StrCpyN(pInetServer->szPassword, pszCachedPassword, ARRAYSIZE(pInetServer->szPassword));
|
|
goto exit;
|
|
}
|
|
|
|
hr = m_op.pCallback->OnLogonPrompt(pInetServer, IXP_HTTPMail);
|
|
if (S_OK == hr)
|
|
{
|
|
// cache the password
|
|
HrCacheAccountPropStrA(m_szAccountId, CAP_PASSWORD, pInetServer->szPassword);
|
|
|
|
// copy the new username and password into our local server info
|
|
StrCpyN(m_rInetServerInfo.szPassword, pInetServer->szPassword, ARRAYSIZE(m_rInetServerInfo.szPassword));
|
|
StrCpyN(m_rInetServerInfo.szUserName, pInetServer->szUserName, ARRAYSIZE(m_rInetServerInfo.szUserName));
|
|
}
|
|
|
|
exit:
|
|
SafeMemFree(pszCachedPassword);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::OnPrompt
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP_(INT) CHTTPMailServer::OnPrompt(
|
|
HRESULT hrError,
|
|
LPCTSTR pszText,
|
|
LPCTSTR pszCaption,
|
|
UINT uType,
|
|
IInternetTransport *pTransport)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::OnStatus
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::OnStatus(
|
|
IXPSTATUS ixpstatus,
|
|
IInternetTransport *pTransport)
|
|
{
|
|
// Stack
|
|
TraceCall("CHTTPMailServer::OnStatus");
|
|
|
|
AssertSingleThreaded;
|
|
|
|
// If we were disconnected, then clean up some internal state.
|
|
if (IXP_DISCONNECTED == ixpstatus)
|
|
{
|
|
if (m_op.tyOperation != SOT_INVALID)
|
|
{
|
|
Assert(m_op.pCallback != NULL);
|
|
|
|
if (m_op.fCancel && !m_op.fNotifiedComplete)
|
|
{
|
|
IXPRESULT rIxpResult;
|
|
|
|
// Fake an IXPRESULT
|
|
ZeroMemory(&rIxpResult, sizeof(rIxpResult));
|
|
rIxpResult.hrResult = STORE_E_OPERATION_CANCELED;
|
|
|
|
// Return meaningful error information
|
|
_FillStoreError(&m_op.error, &rIxpResult);
|
|
Assert(STORE_E_OPERATION_CANCELED == m_op.error.hrResult);
|
|
|
|
m_op.fNotifiedComplete = TRUE;
|
|
m_op.pCallback->OnComplete(m_op.tyOperation, m_op.error.hrResult, NULL, &m_op.error);
|
|
_FreeOperation();
|
|
}
|
|
}
|
|
|
|
m_fConnected = FALSE;
|
|
}
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::OnError
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::OnError(
|
|
IXPSTATUS ixpstatus,
|
|
LPIXPRESULT pIxpResult,
|
|
IInternetTransport *pTransport)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::OnProgress
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::OnProgress(
|
|
DWORD dwIncrement,
|
|
DWORD dwCurrent,
|
|
DWORD dwMaximum,
|
|
IInternetTransport *pTransport)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::OnCommand
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::OnCommand(
|
|
CMDTYPE cmdtype,
|
|
LPSTR pszLine,
|
|
HRESULT hrResponse,
|
|
IInternetTransport *pTransport)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::OnTimeout
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::OnTimeout(
|
|
DWORD *pdwTimeout,
|
|
IInternetTransport *pTransport)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::OnResponse
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::OnResponse(
|
|
LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrResponse;
|
|
HRESULT hrSaved;
|
|
BOOL fInvokeResponseHandler = TRUE;
|
|
|
|
AssertSingleThreaded;
|
|
|
|
Assert(SOT_INVALID != m_op.tyOperation);
|
|
|
|
if (!m_op.fCancel && !m_op.fNotifiedComplete &&
|
|
(SOT_GET_ADURL == m_op.tyOperation || SOT_GET_HTTP_MINPOLLINGINTERVAL == m_op.tyOperation))
|
|
{
|
|
STOREOPERATIONINFO StoreInfo = {0};
|
|
|
|
m_op.fNotifiedComplete = TRUE;
|
|
|
|
if (SOT_GET_ADURL == m_op.tyOperation)
|
|
{
|
|
StoreInfo.pszUrl = pResponse->rGetPropInfo.pszProp;
|
|
|
|
pResponse->rGetPropInfo.pszProp = NULL;
|
|
}
|
|
|
|
if (SOT_GET_HTTP_MINPOLLINGINTERVAL == m_op.tyOperation)
|
|
{
|
|
StoreInfo.dwMinPollingInterval = pResponse->rGetPropInfo.dwProp;
|
|
}
|
|
|
|
m_op.pCallback->OnComplete(m_op.tyOperation, pResponse->rIxpResult.hrResult, &StoreInfo, NULL);
|
|
_FreeOperation();
|
|
|
|
MemFree(StoreInfo.pszUrl);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (FAILED(pResponse->rIxpResult.hrResult))
|
|
{
|
|
Assert(pResponse->fDone);
|
|
|
|
// Hotmail hack. Hotmail does not support deleting message. This interferes with operations
|
|
// such as moving messages from a hotmail folder into the local store. we attempt to send
|
|
// a delete to the server, since we don't know whether or not the server supports the command.
|
|
// if it fails, we check the delete messages flag to determine if we are allowed to fallback
|
|
// to a move operation.
|
|
if (SOT_DELETING_MESSAGES == m_op.tyOperation &&
|
|
(HTTPMAIL_DELETE == pResponse->command || HTTPMAIL_BDELETE == pResponse->command) &&
|
|
IXP_E_HTTP_METHOD_NOT_ALLOW == pResponse->rIxpResult.hrResult &&
|
|
FOLDER_DELETED != m_tySpecialFolder &&
|
|
!!(m_op.dwDelMsgFlags & DELETE_MESSAGE_MAYIGNORENOTRASH))
|
|
{
|
|
m_op.fFallbackToMove = TRUE;
|
|
fInvokeResponseHandler = FALSE;
|
|
// cache the fact that this acct doesn't support msg delete so we don't
|
|
// have to go through this nonsense again
|
|
HrCacheAccountPropStrA(m_szAccountId, CAP_HTTPNOMESSAGEDELETES, "TRUE");
|
|
}
|
|
else
|
|
{
|
|
hrSaved = pResponse->rIxpResult.hrResult;
|
|
|
|
if (IXP_E_HTTP_ROOT_PROP_NOT_FOUND == hrSaved)
|
|
pResponse->rIxpResult.hrResult = SP_E_HTTP_SERVICEDOESNTWORK;
|
|
else if ((HTTPMAIL_DELETE == pResponse->command || HTTPMAIL_BDELETE == pResponse->command) && IXP_E_HTTP_METHOD_NOT_ALLOW == hrSaved)
|
|
pResponse->rIxpResult.hrResult = SP_E_HTTP_NODELETESUPPORT;
|
|
|
|
_FillStoreError(&m_op.error, &pResponse->rIxpResult);
|
|
|
|
pResponse->rIxpResult.hrResult = hrSaved;
|
|
|
|
if (!m_op.fNotifiedComplete)
|
|
{
|
|
m_op.fNotifiedComplete = TRUE;
|
|
m_op.pCallback->OnComplete(m_op.tyOperation, m_op.error.hrResult, NULL, &m_op.error);
|
|
_FreeOperation();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
Assert(NULL != m_op.pfnState[m_op.iState].pfnResp);
|
|
|
|
// by default, state advances occur when the the response indicates
|
|
// that io is done. response functions can override this behavior
|
|
// by setting fStateWillAdvance to FALSE to maintain the current state.
|
|
m_op.fStateWillAdvance = pResponse->fDone;
|
|
|
|
// invoke the response function
|
|
if (fInvokeResponseHandler)
|
|
hr = (this->*(m_op.pfnState[m_op.iState].pfnResp))(pResponse);
|
|
|
|
cleanup:
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
if (_FConnected())
|
|
{
|
|
m_pTransport->DropConnection();
|
|
m_pTransport->HandsOffCallback();
|
|
SafeRelease(m_pTransport);
|
|
}
|
|
|
|
if (!m_op.fNotifiedComplete)
|
|
{
|
|
m_op.fNotifiedComplete = TRUE;
|
|
m_op.pCallback->OnComplete(m_op.tyOperation, hr, NULL, NULL);
|
|
|
|
_FreeOperation();
|
|
}
|
|
}
|
|
else if (SUCCEEDED(hr) && m_op.fStateWillAdvance)
|
|
{
|
|
m_op.iState++;
|
|
_DoOperation();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::GetParentWindow
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::GetParentWindow(HWND *phwndParent)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
AssertSingleThreaded;
|
|
|
|
if (m_op.tyOperation != SOT_INVALID && NULL != m_op.pCallback)
|
|
hr = m_op.pCallback->GetParentWindow(0, phwndParent);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// IOperationCancel Members
|
|
//----------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::Cancel
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CHTTPMailServer::Cancel(CANCELTYPE tyCancel)
|
|
{
|
|
if (m_op.tyOperation != SOT_INVALID)
|
|
{
|
|
m_op.fCancel = TRUE;
|
|
_Disconnect();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer Implementation
|
|
//----------------------------------------------------------------------
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPMailServer::_CreateWnd
|
|
// --------------------------------------------------------------------------------
|
|
BOOL CHTTPMailServer::_CreateWnd()
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
IxpAssert(!m_hwnd);
|
|
if (m_hwnd)
|
|
return TRUE;
|
|
|
|
if (!GetClassInfo(g_hInst, s_szHTTPMailServerWndClass, &wc))
|
|
{
|
|
wc.style = 0;
|
|
wc.lpfnWndProc = CHTTPMailServer::_WndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = g_hInst;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = NULL;
|
|
wc.hbrBackground = NULL;
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = s_szHTTPMailServerWndClass;
|
|
|
|
RegisterClass(&wc);
|
|
}
|
|
|
|
m_hwnd = CreateWindowEx(WS_EX_TOPMOST,
|
|
s_szHTTPMailServerWndClass,
|
|
s_szHTTPMailServerWndClass,
|
|
WS_POPUP,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
NULL,
|
|
NULL,
|
|
g_hInst,
|
|
(LPVOID)this);
|
|
|
|
return (NULL != m_hwnd);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CHTTPMailServer::_WndProc
|
|
// --------------------------------------------------------------------------------
|
|
LRESULT CALLBACK CHTTPMailServer::_WndProc(HWND hwnd,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
CHTTPMailServer *pThis = (CHTTPMailServer*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
LRESULT lr = 0;
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_NCCREATE:
|
|
IxpAssert(!pThis);
|
|
pThis = (CHTTPMailServer*)((LPCREATESTRUCT)lParam)->lpCreateParams;
|
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pThis);
|
|
lr = DefWindowProc(hwnd, msg, wParam, lParam);
|
|
break;
|
|
|
|
case WM_HTTP_BEGIN_OP:
|
|
IxpAssert(pThis);
|
|
pThis->_DoOperation();
|
|
break;
|
|
|
|
default:
|
|
lr = DefWindowProc(hwnd, msg, wParam, lParam);
|
|
break;
|
|
}
|
|
|
|
return lr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_BeginDeferredOperation
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::_BeginDeferredOperation(void)
|
|
{
|
|
return (PostMessage(m_hwnd, WM_HTTP_BEGIN_OP, 0, 0) ? E_PENDING : E_FAIL);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::HandleGetMsgFolderRoot
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::HandleGetMsgFolderRoot(LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
Assert(HTTPMAIL_GETPROP == pResponse->command);
|
|
Assert(NULL == m_pszMsgFolderRoot);
|
|
Assert(HTTPMAIL_PROP_MSGFOLDERROOT == pResponse->rGetPropInfo.type);
|
|
|
|
if (NULL == pResponse->rGetPropInfo.pszProp)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
m_pszMsgFolderRoot = pResponse->rGetPropInfo.pszProp;
|
|
pResponse->rGetPropInfo.pszProp = NULL;
|
|
|
|
// add it to the account data cache
|
|
HrCacheAccountPropStrA(m_szAccountId, CAP_HTTPMAILMSGFOLDERROOT, m_pszMsgFolderRoot);
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::HandleListFolders
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::HandleListFolders(LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SPECIALFOLDER tySpecial = FOLDER_NOTSPECIAL;
|
|
FOLDERINFO fiNewFolder;
|
|
FOLDERID idFound = FOLDERID_INVALID;
|
|
LPHTTPMEMBERINFOLIST pMemberList = &pResponse->rMemberInfoList;
|
|
LPHTTPMEMBERINFO pMemberInfo;
|
|
CHAR szUrlComponent[MAX_PATH];
|
|
DWORD dwUrlComponentLen;
|
|
CHAR szSpecialFolder[CCHMAX_STRINGRES];
|
|
DWORD cMessages;
|
|
DWORD cUnread;
|
|
FOLDERINFO fi = {0};
|
|
|
|
for (ULONG ulIndex = 0; ulIndex < pMemberList->cMemberInfo; ++ulIndex)
|
|
{
|
|
idFound = FOLDERID_INVALID;
|
|
|
|
pMemberInfo = &pMemberList->prgMemberInfo[ulIndex];
|
|
|
|
// skip anything that isn't a folder
|
|
if (!pMemberInfo->fIsFolder)
|
|
continue;
|
|
|
|
dwUrlComponentLen = ARRAYSIZE(szUrlComponent);
|
|
IF_FAILEXIT(hr = Http_NameFromUrl(pMemberInfo->pszHref, szUrlComponent, &dwUrlComponentLen));
|
|
|
|
// [shaheedp] Bug# 84477
|
|
// If szUrlComponent is null, then we should not be adding this folder to the store.
|
|
if (!(*szUrlComponent))
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
|
|
// if we've found a reserved folder, translate the httpmail
|
|
// special folder constant into the equivalent oe store
|
|
// special folder type.
|
|
|
|
tySpecial = _TranslateHTTPSpecialFolderType(pMemberInfo->tySpecial);
|
|
if (FOLDER_NOTSPECIAL != tySpecial)
|
|
idFound = m_op.pFolderList->FindAndRemove(tySpecial, &cMessages, &cUnread);
|
|
|
|
// if the folder wasn't found, try to find it by name
|
|
if (FOLDERID_INVALID == idFound)
|
|
{
|
|
idFound = m_op.pFolderList->FindAndRemove(szUrlComponent, &cMessages, &cUnread);
|
|
|
|
// if it still wasn't found, then add it
|
|
if (FOLDERID_INVALID == idFound)
|
|
{
|
|
// fill in the folderinfo
|
|
ZeroMemory(&fiNewFolder, sizeof(FOLDERINFO));
|
|
fiNewFolder.idParent = m_idServer;
|
|
fiNewFolder.tySpecial = tySpecial;
|
|
fiNewFolder.tyFolder = FOLDER_HTTPMAIL;
|
|
fiNewFolder.pszName = pMemberInfo->pszDisplayName;
|
|
if (FOLDER_NOTSPECIAL != tySpecial)
|
|
{
|
|
if (_LoadSpecialFolderName(tySpecial, szSpecialFolder, sizeof(szSpecialFolder)))
|
|
fiNewFolder.pszName = szSpecialFolder;
|
|
}
|
|
|
|
fiNewFolder.pszUrlComponent = szUrlComponent;
|
|
fiNewFolder.dwFlags = (FOLDER_SUBSCRIBED | FOLDER_NOCHILDCREATE);
|
|
|
|
// message counts
|
|
fiNewFolder.cMessages = pMemberInfo->dwVisibleCount;
|
|
fiNewFolder.cUnread = pMemberInfo->dwUnreadCount;
|
|
|
|
if (tySpecial == FOLDER_INBOX)
|
|
fiNewFolder.dwFlags |= FOLDER_DOWNLOADALL;
|
|
|
|
// Add the folder to the store
|
|
IF_FAILEXIT(hr = m_pStore->CreateFolder(NOFLAGS, &fiNewFolder, NULL));
|
|
}
|
|
}
|
|
|
|
// if the folder was found, update its message counts
|
|
if (FOLDERID_INVALID != idFound)
|
|
{
|
|
if (SUCCEEDED(hr = m_pStore->GetFolderInfo(idFound, &fi)))
|
|
{
|
|
BOOL bUpdate = FALSE;
|
|
|
|
// only update folders that changed. always update the MSN_PROMO folder.
|
|
|
|
// [shaheedp] Bug# 84477
|
|
// If the folder's pszUrlComponent was null or it is different, then reset it.
|
|
if ((fi.pszUrlComponent == NULL) ||
|
|
(lstrcmpi(fi.pszUrlComponent, szUrlComponent)))
|
|
{
|
|
bUpdate = TRUE;
|
|
fi.pszUrlComponent = szUrlComponent;
|
|
}
|
|
|
|
if ((FOLDER_MSNPROMO == tySpecial) ||
|
|
(cMessages != pMemberInfo->dwVisibleCount) ||
|
|
(cUnread != pMemberInfo->dwUnreadCount))
|
|
{
|
|
|
|
fi.cMessages = pMemberInfo->dwVisibleCount;
|
|
|
|
// special handling for the promo folder - messages on the
|
|
// server are never marked unread.
|
|
if (FOLDER_MSNPROMO == fi.tySpecial)
|
|
{
|
|
// we attempt to approximate the number of unread msgs in
|
|
// the promo folder. we assume that the server will not track
|
|
// the read/unread state of promo messages. we figure out how
|
|
// many messages were read before we got the new counts, and
|
|
// subtract that number from the current number of visible
|
|
// messages to get the unread count. this number will not always
|
|
// be accurate, but since all we know is the counts, and we
|
|
// don't know how the count changed (additions vs deletions),
|
|
// this is the best we can do and it always errors on the side
|
|
// of a too-small count to avoid bothering the user with
|
|
// unread counts when no unread msgs exist.
|
|
DWORD dwReadMessages = cMessages - cUnread;
|
|
|
|
if (fi.cMessages > dwReadMessages)
|
|
fi.cUnread = fi.cMessages - dwReadMessages;
|
|
else
|
|
fi.cUnread = 0;
|
|
}
|
|
else
|
|
fi.cUnread = pMemberInfo->dwUnreadCount;
|
|
|
|
if (cMessages != fi.cMessages || cUnread != fi.cUnread)
|
|
bUpdate = TRUE;
|
|
|
|
}
|
|
|
|
if (bUpdate)
|
|
m_pStore->UpdateRecord(&fi);
|
|
|
|
m_pStore->FreeRecord(&fi);
|
|
}
|
|
}
|
|
|
|
// if we are syncing the store, notify the client of our progress
|
|
if (SOT_SYNCING_STORE == m_op.tyOperation && NULL != m_op.pCallback)
|
|
m_op.pCallback->OnProgress(
|
|
SOT_SYNCING_STORE,
|
|
0,
|
|
0,
|
|
m_rInetServerInfo.szServerName);
|
|
}
|
|
|
|
IF_FAILEXIT(hr = m_pAccount->SetPropSz(AP_HTTPMAIL_ROOTTIMESTAMP, pMemberList->pszRootTimeStamp));
|
|
IF_FAILEXIT(hr = m_pAccount->SetPropSz(AP_HTTPMAIL_ROOTINBOXTIMESTAMP, pMemberList->pszFolderTimeStamp));
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::HandleGetMessage
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::HandleGetMessage(LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr;
|
|
|
|
IF_FAILEXIT(hr = m_op.pMessageStream->Write(
|
|
pResponse->rGetInfo.pvBody,
|
|
pResponse->rGetInfo.cbIncrement,
|
|
NULL));
|
|
|
|
|
|
if (m_op.pCallback && pResponse->rGetInfo.cbTotal > 0)
|
|
{
|
|
m_op.pCallback->OnProgress(m_op.tyOperation,
|
|
pResponse->rGetInfo.cbCurrent,
|
|
pResponse->rGetInfo.cbTotal,
|
|
NULL);
|
|
}
|
|
|
|
// if not done yet, bail out
|
|
if (!pResponse->fDone)
|
|
goto exit;
|
|
|
|
// we're done...write the stream out
|
|
hr = Http_SetMessageStream(m_pFolder, m_op.idMessage, m_op.pMessageStream, &m_op.faStream, FALSE);
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_DoOperation
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::_DoOperation(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
STOREOPERATIONINFO soi = { sizeof(STOREOPERATIONINFO), MESSAGEID_INVALID };
|
|
STOREOPERATIONINFO *psoi = NULL;
|
|
BOOL fCallComplete = TRUE;
|
|
|
|
if (m_op.tyOperation == SOT_INVALID)
|
|
return E_FAIL;
|
|
|
|
Assert(m_op.tyOperation != SOT_INVALID);
|
|
Assert(m_op.pfnState != NULL);
|
|
Assert(m_op.cState > 0);
|
|
Assert(m_op.iState <= m_op.cState);
|
|
|
|
if (m_op.iState == 0)
|
|
{
|
|
if (m_op.tyOperation == SOT_GET_MESSAGE)
|
|
{
|
|
// provide message id on get message start
|
|
soi.idMessage = m_op.idMessage;
|
|
psoi = &soi;
|
|
}
|
|
|
|
if (m_op.tyOperation == SOT_GET_ADURL)
|
|
m_op.pszAdUrl = NULL;
|
|
|
|
m_op.pCallback->OnBegin(m_op.tyOperation, psoi, (IOperationCancel *)this);
|
|
}
|
|
|
|
while (m_op.iState < m_op.cState)
|
|
{
|
|
hr = (this->*(m_op.pfnState[m_op.iState].pfnOp))();
|
|
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
m_op.iState++;
|
|
}
|
|
|
|
if ((m_op.iState == m_op.cState) || (FAILED(hr) && hr != E_PENDING))
|
|
{
|
|
LPSTOREERROR perr = NULL;
|
|
|
|
// provide message id
|
|
if (m_op.tyOperation == SOT_PUT_MESSAGE && MESSAGEID_INVALID != m_op.idPutMessage)
|
|
{
|
|
soi.idMessage = m_op.idPutMessage;
|
|
psoi = &soi;
|
|
}
|
|
|
|
switch (m_op.tyOperation)
|
|
{
|
|
case SOT_GET_ADURL:
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
psoi = &soi;
|
|
psoi->pszUrl = m_op.pszAdUrl;
|
|
}
|
|
else
|
|
{
|
|
psoi = NULL;
|
|
fCallComplete = FALSE;
|
|
}
|
|
|
|
perr = NULL;
|
|
break;
|
|
}
|
|
|
|
case SOT_GET_HTTP_MINPOLLINGINTERVAL:
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
psoi = &soi;
|
|
psoi->dwMinPollingInterval = m_op.dwMinPollingInterval;
|
|
}
|
|
else
|
|
{
|
|
psoi = NULL;
|
|
fCallComplete = FALSE;
|
|
|
|
}
|
|
|
|
perr = NULL;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
if (FAILED(hr))
|
|
{
|
|
IXPRESULT rIxpResult;
|
|
|
|
// Fake an IXPRESULT
|
|
ZeroMemory(&rIxpResult, sizeof(rIxpResult));
|
|
rIxpResult.hrResult = hr;
|
|
|
|
// Return meaningful error information
|
|
_FillStoreError(&m_op.error, &rIxpResult);
|
|
Assert(m_op.error.hrResult == hr);
|
|
}
|
|
else
|
|
m_op.error.hrResult = hr;
|
|
|
|
if (!m_op.fNotifiedComplete)
|
|
perr = &m_op.error;
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (!m_op.fNotifiedComplete && fCallComplete)
|
|
{
|
|
m_op.fNotifiedComplete = TRUE;
|
|
m_op.pCallback->OnComplete(m_op.tyOperation, hr, psoi, perr);
|
|
_FreeOperation();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_FreeOperation
|
|
//----------------------------------------------------------------------
|
|
void CHTTPMailServer::_FreeOperation(BOOL fValidState)
|
|
{
|
|
if (fValidState)
|
|
{
|
|
if (m_op.pCallback != NULL)
|
|
m_op.pCallback->Release();
|
|
if (m_op.pFolderList != NULL)
|
|
m_op.pFolderList->Release();
|
|
if (m_op.pMessageFolder)
|
|
m_op.pMessageFolder->Release();
|
|
|
|
SafeMemFree(m_op.pszProblem);
|
|
|
|
if (0 != m_op.faStream)
|
|
{
|
|
Assert(m_pFolder);
|
|
m_pFolder->DeleteStream(m_op.faStream);
|
|
}
|
|
if (m_op.pMessageStream)
|
|
m_op.pMessageStream->Release();
|
|
if (m_op.pmapMessageId)
|
|
delete m_op.pmapMessageId;
|
|
if (m_op.psaNewMessages)
|
|
delete m_op.psaNewMessages;
|
|
|
|
if (m_op.pPropPatchRequest)
|
|
m_op.pPropPatchRequest->Release();
|
|
|
|
SafeMemFree(m_op.pszDestFolderUrl);
|
|
SafeMemFree(m_op.pszDestUrl);
|
|
|
|
SafeMemFree(m_op.pIDList);
|
|
if (NULL != m_op.hRowSet)
|
|
m_pFolder->CloseRowset(&m_op.hRowSet);
|
|
|
|
SafeMemFree(m_op.pszFolderName);
|
|
|
|
if (m_op.pTargets)
|
|
Http_FreeTargetList(m_op.pTargets);
|
|
|
|
SafeMemFree(m_op.pszAdUrl);
|
|
|
|
}
|
|
|
|
ZeroMemory(&m_op, sizeof(HTTPOPERATION));
|
|
|
|
m_op.tyOperation = SOT_INVALID;
|
|
m_op.idPutMessage = MESSAGEID_INVALID;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::Connect
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::Connect()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
INETSERVER rInetServerInfo;
|
|
BOOL fInetInit = FALSE;
|
|
LPSTR pszCache = NULL;
|
|
|
|
AssertSingleThreaded;
|
|
Assert(m_op.pCallback != NULL);
|
|
|
|
if (!m_pAccount)
|
|
{
|
|
IF_FAILEXIT(hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, m_szAccountId, &m_pAccount));
|
|
IF_FAILEXIT(hr = _LoadAccountInfo(m_pAccount));
|
|
}
|
|
|
|
if (_FConnected())
|
|
{
|
|
Assert(m_pTransport != NULL);
|
|
|
|
IF_FAILEXIT(hr = m_pTransport->InetServerFromAccount(m_pAccount, &rInetServerInfo));
|
|
|
|
// compare the current account from the account whose data we saved.
|
|
// if the account has changed, drop the connection, and reconnect
|
|
Assert(m_rInetServerInfo.szServerName[0] != 0);
|
|
if (m_rInetServerInfo.rasconntype == rInetServerInfo.rasconntype &&
|
|
m_rInetServerInfo.dwPort == rInetServerInfo.dwPort &&
|
|
m_rInetServerInfo.fSSL == rInetServerInfo.fSSL &&
|
|
m_rInetServerInfo.fTrySicily == rInetServerInfo.fTrySicily &&
|
|
m_rInetServerInfo.dwTimeout == rInetServerInfo.dwTimeout &&
|
|
0 == lstrcmp(m_rInetServerInfo.szUserName, rInetServerInfo.szUserName) &&
|
|
('\0' == rInetServerInfo.szPassword[0] ||
|
|
0 == lstrcmp(m_rInetServerInfo.szPassword, rInetServerInfo.szPassword)) &&
|
|
0 == lstrcmp(m_rInetServerInfo.szServerName, rInetServerInfo.szServerName) &&
|
|
0 == lstrcmp(m_rInetServerInfo.szConnectoid, rInetServerInfo.szConnectoid))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
fInetInit = TRUE;
|
|
|
|
// synchronously drop the connection
|
|
m_pTransport->DropConnection();
|
|
}
|
|
|
|
hr = m_op.pCallback->CanConnect(m_szAccountId, NOFLAGS);
|
|
if (S_OK != hr)
|
|
{
|
|
if (hr == S_FALSE)
|
|
hr = HR_E_USER_CANCEL_CONNECT;
|
|
goto exit;
|
|
}
|
|
|
|
|
|
if (NULL == m_pTransport)
|
|
IF_FAILEXIT(hr = _LoadTransport());
|
|
|
|
// initialize the server info if we haven't already
|
|
if (!fInetInit)
|
|
IF_FAILEXIT(hr = m_pTransport->InetServerFromAccount(m_pAccount, &m_rInetServerInfo));
|
|
else
|
|
CopyMemory(&m_rInetServerInfo, &rInetServerInfo, sizeof(INETSERVER));
|
|
|
|
GetAccountPropStrA(m_szAccountId, CAP_PASSWORD, &pszCache);
|
|
if (NULL != pszCache)
|
|
{
|
|
StrCpyN(m_rInetServerInfo.szPassword, pszCache, sizeof(m_rInetServerInfo.szPassword));
|
|
SafeMemFree(pszCache);
|
|
}
|
|
|
|
// connect to the server. the transport won't actually connect until
|
|
// a command is issued.
|
|
IF_FAILEXIT(hr = m_pTransport->Connect(&m_rInetServerInfo, TRUE, FALSE));
|
|
|
|
_SetConnected(TRUE);
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::GetMsgFolderRoot
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::GetMsgFolderRoot(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// bail if we've already got it
|
|
if (NULL != m_pszMsgFolderRoot)
|
|
goto exit;
|
|
|
|
// try to pull it out of the account data cache
|
|
if (GetAccountPropStrA(m_szAccountId, CAP_HTTPMAILMSGFOLDERROOT, &m_pszMsgFolderRoot))
|
|
goto exit;
|
|
|
|
if (SUCCEEDED(hr = m_pTransport->GetProperty(HTTPMAIL_PROP_MSGFOLDERROOT, &m_pszMsgFolderRoot)))
|
|
{
|
|
Assert(NULL != m_pszMsgFolderRoot);
|
|
if (NULL == m_pszMsgFolderRoot)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// add it to the account data cache
|
|
HrCacheAccountPropStrA(m_szAccountId, CAP_HTTPMAILMSGFOLDERROOT, m_pszMsgFolderRoot);
|
|
}
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::BuildFolderUrl
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::BuildFolderUrl(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
FOLDERINFO fi;
|
|
LPFOLDERINFO fiFree = NULL;
|
|
|
|
// just bail if we've already got it
|
|
if (NULL != m_pszFolderUrl)
|
|
goto exit;
|
|
|
|
Assert(NULL != m_pszMsgFolderRoot);
|
|
if (NULL == m_pszMsgFolderRoot)
|
|
{
|
|
hr = TraceResult(E_UNEXPECTED);
|
|
goto exit;
|
|
}
|
|
|
|
if (FAILED(hr = m_pStore->GetFolderInfo(m_idFolder, &fi)))
|
|
goto exit;
|
|
|
|
fiFree = &fi;
|
|
|
|
Assert(fi.pszUrlComponent);
|
|
hr = _BuildUrl(fi.pszUrlComponent, NULL, &m_pszFolderUrl);
|
|
|
|
exit:
|
|
if (fiFree)
|
|
m_pStore->FreeRecord(fiFree);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::ListFolders
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::ListFolders(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CHAR szRootTimeStamp[CCHMAX_RES];
|
|
CHAR szInboxTimeStamp[CCHMAX_RES];
|
|
|
|
Assert(NULL == m_op.pFolderList);
|
|
|
|
// cache a value that the account has been synced.
|
|
HrCacheAccountPropStrA(m_szAccountId, CAP_HTTPAUTOSYNCEDFOLDERS, c_szTrue);
|
|
|
|
// build the folder list
|
|
IF_FAILEXIT(hr = CFolderList::Create(m_pStore, m_idServer, &m_op.pFolderList));
|
|
|
|
hr = m_pAccount->GetPropSz(AP_HTTPMAIL_ROOTTIMESTAMP, szRootTimeStamp, ARRAYSIZE(szRootTimeStamp));
|
|
if (FAILED(hr))
|
|
*szRootTimeStamp = 0;
|
|
|
|
hr = m_pAccount->GetPropSz(AP_HTTPMAIL_ROOTINBOXTIMESTAMP, szInboxTimeStamp, ARRAYSIZE(szInboxTimeStamp));
|
|
if (FAILED(hr))
|
|
*szInboxTimeStamp = 0;
|
|
|
|
// execute the listfolders command
|
|
IF_FAILEXIT(hr = m_pTransport2->RootMemberInfo(m_pszMsgFolderRoot, HTTP_MEMBERINFO_FOLDERPROPS,
|
|
1, FALSE, 0, szRootTimeStamp, szInboxTimeStamp));
|
|
|
|
hr = E_PENDING;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::AutoListFolders
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::AutoListFolders(void)
|
|
{
|
|
LPSTR pszAutoSynced = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
// look for a cached property that indicates that the folder list
|
|
// for this server has been synchronized at least once this session
|
|
if (GetAccountPropStrA(m_szAccountId, CAP_HTTPAUTOSYNCEDFOLDERS, &pszAutoSynced))
|
|
goto exit;
|
|
|
|
// initiate the sync
|
|
hr = ListFolders();
|
|
|
|
exit:
|
|
SafeMemFree(pszAutoSynced);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::ListHeaders
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::ListHeaders(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TABLEINDEX index;
|
|
CHAR szTimeStamp[CCHMAX_RES];
|
|
|
|
Assert(NULL != m_pszFolderUrl);
|
|
Assert(NULL != m_pTransport);
|
|
Assert(NULL != m_pStore);
|
|
Assert(NULL == m_op.psaNewMessages);
|
|
|
|
// look for an index on pszMessageID
|
|
if ( FAILED(m_pFolder->GetIndexInfo(IINDEX_HTTPURL, NULL, &index)) ||
|
|
(CompareTableIndexes(&index, &g_HttpUrlIndex) != S_OK) )
|
|
{
|
|
// the index didn't exist - create it
|
|
IF_FAILEXIT(hr = m_pFolder->ModifyIndex(IINDEX_HTTPURL, NULL, &g_HttpUrlIndex));
|
|
}
|
|
|
|
IF_FAILEXIT(hr = _CreateMessageIDMap(&m_op.pmapMessageId));
|
|
|
|
IF_FAILEXIT(hr = CSortedArray::Create(NULL, FreeNewMessageInfo, &m_op.psaNewMessages));
|
|
|
|
hr = m_pAccount->GetPropSz(AP_HTTPMAIL_INBOXTIMESTAMP, szTimeStamp, ARRAYSIZE(szTimeStamp));
|
|
if (FAILED(hr))
|
|
*szTimeStamp = 0;
|
|
|
|
// For now we are passing in null folder name. This is meant for future purposes.
|
|
IF_FAILEXIT(hr = m_pTransport2->FolderMemberInfo(m_pszFolderUrl, HTTP_MEMBERINFO_MESSAGEPROPS,
|
|
1, FALSE, 0, szTimeStamp, NULL));
|
|
|
|
hr = E_PENDING;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::HandleListHeaders
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::HandleListHeaders(LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPHTTPMEMBERINFOLIST pMemberList = &pResponse->rMemberInfoList;
|
|
LPHTTPMEMBERINFO pMemberInfo;
|
|
TPair<CSimpleString, MARKEDMESSAGE> *pFoundPair = NULL;
|
|
CSimpleString ss;
|
|
char szUrlComponent[MAX_PATH];
|
|
DWORD dwUrlComponentLen;
|
|
|
|
Assert(NULL != m_op.pmapMessageId);
|
|
|
|
for (ULONG ulIndex = 0; ulIndex < pMemberList->cMemberInfo; ++ulIndex)
|
|
{
|
|
pMemberInfo = &pMemberList->prgMemberInfo[ulIndex];
|
|
|
|
// skip folders
|
|
if (pMemberInfo->fIsFolder)
|
|
continue;
|
|
|
|
dwUrlComponentLen = MAX_PATH;
|
|
if (FAILED(hr = Http_NameFromUrl(pMemberInfo->pszHref, szUrlComponent, &dwUrlComponentLen)))
|
|
goto exit;
|
|
|
|
// look for the message by its server-assigned id in the local map
|
|
if (FAILED(hr = ss.SetString(szUrlComponent)))
|
|
goto exit;
|
|
|
|
pFoundPair = m_op.pmapMessageId->Find(ss);
|
|
|
|
// if the message was found, synchronize its read state, otherwise
|
|
// add the new message to the store
|
|
if (pFoundPair)
|
|
{
|
|
pFoundPair->m_value.fMarked = TRUE;
|
|
|
|
// if not syncing the msn promo folder, adopt the server's read state
|
|
if (FOLDER_MSNPROMO != m_tySpecialFolder)
|
|
{
|
|
if ((!!(pFoundPair->m_value.dwFlags & ARF_READ)) != pMemberInfo->fRead)
|
|
hr = _MarkMessageRead(pFoundPair->m_value.idMessage, pMemberInfo->fRead);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (FAILED(hr = Http_AddMessageToFolder(m_pFolder,
|
|
m_szAccountId,
|
|
pMemberInfo,
|
|
FOLDER_DRAFT == m_tySpecialFolder ? ARF_UNSENT : NOFLAGS,
|
|
pMemberInfo->pszHref,
|
|
NULL)))
|
|
{
|
|
if (DB_E_DUPLICATE == hr)
|
|
hr = S_OK;
|
|
else
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// update our message and unread message counts
|
|
m_op.cMessages++;
|
|
|
|
// if syncing the promo folder, no headers on the server will
|
|
// ever appear to be read.
|
|
if (FOLDER_MSNPROMO == m_tySpecialFolder)
|
|
{
|
|
if (!pFoundPair || !(pFoundPair->m_value.dwFlags & ARF_READ))
|
|
m_op.cUnread++;
|
|
}
|
|
else if (!pMemberInfo->fRead)
|
|
m_op.cUnread++;
|
|
}
|
|
|
|
if (pMemberList->pszFolderTimeStamp)
|
|
{
|
|
IF_FAILEXIT(hr = m_pAccount->SetPropSz(AP_HTTPMAIL_INBOXTIMESTAMP, pMemberList->pszFolderTimeStamp));
|
|
}
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_Disconnect
|
|
//----------------------------------------------------------------------
|
|
void CHTTPMailServer::_Disconnect(void)
|
|
{
|
|
if (m_pTransport)
|
|
m_pTransport->DropConnection();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_BuildUrl
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::_BuildUrl(LPCSTR pszFolderComponent,
|
|
LPCSTR pszNameComponent,
|
|
LPSTR *ppszUrl)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD cchMsgFolderRoot = 0;
|
|
DWORD cchFolderComponent = 0;
|
|
DWORD cchNameComponent = 0;
|
|
DWORD cchWritten = 0;
|
|
LPSTR pszUrl = NULL;
|
|
CHAR chSlash = '/';
|
|
|
|
Assert(NULL != m_pszMsgFolderRoot);
|
|
Assert(NULL != ppszUrl);
|
|
|
|
*ppszUrl = NULL;
|
|
|
|
if (NULL == m_pszMsgFolderRoot)
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto exit;
|
|
}
|
|
|
|
cchMsgFolderRoot = lstrlen(m_pszMsgFolderRoot);
|
|
if (pszFolderComponent)
|
|
cchFolderComponent = lstrlen(pszFolderComponent);
|
|
if (pszNameComponent)
|
|
cchNameComponent = lstrlen(pszNameComponent);
|
|
|
|
// add three bytes - two for trailing slashes and one for the eos
|
|
if (!MemAlloc((void **)&pszUrl, cchMsgFolderRoot + cchFolderComponent + cchNameComponent + 3))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
*ppszUrl = pszUrl;
|
|
|
|
CopyMemory(pszUrl, m_pszMsgFolderRoot, cchMsgFolderRoot);
|
|
cchWritten = cchMsgFolderRoot;
|
|
// make sure the msg folder root is terminated with a '/'
|
|
if (chSlash != pszUrl[cchWritten - 1])
|
|
pszUrl[cchWritten++] = chSlash;
|
|
|
|
if (cchFolderComponent)
|
|
{
|
|
CopyMemory(&pszUrl[cchWritten], pszFolderComponent, cchFolderComponent);
|
|
cchWritten += cchFolderComponent;
|
|
if (chSlash != pszUrl[cchWritten - 1])
|
|
pszUrl[cchWritten++] = chSlash;
|
|
}
|
|
|
|
if (cchNameComponent)
|
|
{
|
|
CopyMemory(&pszUrl[cchWritten], pszNameComponent, cchNameComponent);
|
|
cchWritten += cchNameComponent;
|
|
}
|
|
|
|
// null terminate the string
|
|
pszUrl[cchWritten] = 0;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_BuildMessageUrl
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::_BuildMessageUrl(LPCSTR pszFolderUrl,
|
|
LPSTR pszNameComponent,
|
|
LPSTR *ppszUrl)
|
|
{
|
|
DWORD cchFolderUrlLen;
|
|
DWORD cchNameComponentLen;
|
|
|
|
if (NULL != ppszUrl)
|
|
*ppszUrl = NULL;
|
|
|
|
if (NULL == pszFolderUrl || NULL == pszNameComponent || NULL == ppszUrl)
|
|
return E_INVALIDARG;
|
|
|
|
cchFolderUrlLen = lstrlen(pszFolderUrl);
|
|
cchNameComponentLen = lstrlen(pszNameComponent);
|
|
|
|
// allocate two extra bytes - one for the '/' delimeter and one for the eos
|
|
DWORD cchTotal = (cchFolderUrlLen + cchNameComponentLen + 2);
|
|
if (!MemAlloc((void **)ppszUrl, cchTotal * sizeof((*ppszUrl)[0])))
|
|
return E_OUTOFMEMORY;
|
|
|
|
if ('/' == pszFolderUrl[cchFolderUrlLen - 1])
|
|
wnsprintf(*ppszUrl, cchTotal, "%s%s", pszFolderUrl, pszNameComponent);
|
|
else
|
|
wnsprintf(*ppszUrl, cchTotal, "%s/%s", pszFolderUrl, pszNameComponent);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_MarkMessageRead
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::_MarkMessageRead(MESSAGEID id, BOOL fRead)
|
|
{
|
|
HRESULT hr;
|
|
MESSAGEINFO mi = {0};
|
|
BOOL fFoundRecord = FALSE;
|
|
|
|
ZeroMemory(&mi, sizeof(MESSAGEINFO));
|
|
mi.idMessage = id;
|
|
|
|
// find the message in the database
|
|
if (FAILED(hr = GetMessageInfo(m_pFolder, id, &mi)))
|
|
goto exit;
|
|
|
|
fFoundRecord = TRUE;
|
|
|
|
if (fRead)
|
|
mi.dwFlags |= ARF_READ;
|
|
else
|
|
mi.dwFlags &= ~ARF_READ;
|
|
|
|
hr = m_pFolder->UpdateRecord(&mi);
|
|
|
|
exit:
|
|
if (fFoundRecord)
|
|
m_pFolder->FreeRecord(&mi);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::CreateFolder
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::CreateFolder(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CHAR szEncodedName[MAX_PATH];
|
|
DWORD cb = sizeof(szEncodedName);
|
|
|
|
Assert(NULL != m_pTransport);
|
|
Assert(NULL != m_op.pszFolderName);
|
|
|
|
IF_FAILEXIT(hr = UrlEscapeA(m_op.pszFolderName,
|
|
szEncodedName,
|
|
&cb,
|
|
URL_ESCAPE_UNSAFE | URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY));
|
|
|
|
IF_FAILEXIT(hr = _BuildUrl(szEncodedName, NULL, &m_op.pszDestFolderUrl));
|
|
|
|
IF_FAILEXIT(hr = m_pTransport->CommandMKCOL(m_op.pszDestFolderUrl, 0));
|
|
|
|
hr = E_PENDING;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::RenameFolder
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::RenameFolder(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
FOLDERINFO fi = {0};
|
|
LPFOLDERINFO pfiFree = NULL;
|
|
LPSTR pszSourceUrl = NULL;
|
|
LPSTR pszDestUrl = NULL;
|
|
CHAR szEncodedName[MAX_PATH];
|
|
DWORD cb = sizeof(szEncodedName);
|
|
|
|
// build the source url
|
|
IF_FAILEXIT(hr = m_pStore->GetFolderInfo(m_op.idFolder, &fi));
|
|
|
|
pfiFree = &fi;
|
|
|
|
IF_FAILEXIT(hr = _BuildUrl(fi.pszUrlComponent, NULL, &pszSourceUrl));
|
|
|
|
// escape the new folder name
|
|
IF_FAILEXIT(hr = UrlEscapeA(m_op.pszFolderName,
|
|
szEncodedName,
|
|
&cb,
|
|
URL_ESCAPE_UNSAFE | URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY));
|
|
|
|
// build the destination url
|
|
IF_FAILEXIT(hr = _BuildUrl(szEncodedName, NULL, &pszDestUrl));
|
|
|
|
// send the MOVE command to the transport
|
|
IF_FAILEXIT(hr = m_pTransport->CommandMOVE(pszSourceUrl, pszDestUrl, TRUE, 0));
|
|
|
|
hr = E_PENDING;
|
|
|
|
exit:
|
|
if (pfiFree)
|
|
m_pStore->FreeRecord(pfiFree);
|
|
SafeMemFree(pszSourceUrl);
|
|
SafeMemFree(pszDestUrl);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::DeleteFolder
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::DeleteFolder(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
FOLDERINFO fi = {0};
|
|
LPFOLDERINFO pfiFree = NULL;
|
|
LPSTR pszUrl = NULL;
|
|
|
|
// build the folder's url
|
|
if (FAILED(hr = m_pStore->GetFolderInfo(m_op.idFolder, &fi)))
|
|
goto exit;
|
|
|
|
pfiFree = &fi;
|
|
|
|
if (FAILED(hr = _BuildUrl(fi.pszUrlComponent, NULL, &pszUrl)))
|
|
goto exit;
|
|
|
|
// send the delete command to the transport
|
|
hr = m_pTransport->CommandDELETE(pszUrl, 0);
|
|
if (SUCCEEDED(hr))
|
|
hr = E_PENDING;
|
|
|
|
exit:
|
|
if (pfiFree)
|
|
m_pStore->FreeRecord(pfiFree);
|
|
SafeMemFree(pszUrl);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::HandleCreateFolder
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::HandleCreateFolder(LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
FOLDERINFO fi;
|
|
CHAR szUrlComponent[MAX_PATH];
|
|
DWORD dwUrlComponentLen = MAX_PATH;
|
|
HRESULT hr = pResponse->rIxpResult.hrResult;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// if the server specified a location, use it. otherwise, use
|
|
// the url that we included in the request
|
|
if (NULL != pResponse->rMkColInfo.pszLocation)
|
|
IF_FAILEXIT(hr = Http_NameFromUrl(pResponse->rMkColInfo.pszLocation, szUrlComponent, &dwUrlComponentLen));
|
|
else
|
|
IF_FAILEXIT(hr = Http_NameFromUrl(m_op.pszDestFolderUrl, szUrlComponent, &dwUrlComponentLen));
|
|
|
|
// [shaheedp] Bug# 84477
|
|
// If szUrlComponent is null, then we should not be adding this folder to the store.
|
|
if (!(*szUrlComponent))
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
ZeroMemory(&fi, sizeof(FOLDERINFO));
|
|
|
|
fi.idParent = m_idServer;
|
|
fi.tySpecial = FOLDER_NOTSPECIAL;
|
|
fi.tyFolder = FOLDER_HTTPMAIL;
|
|
fi.pszName = m_op.pszFolderName;
|
|
fi.pszUrlComponent = szUrlComponent;
|
|
fi.dwFlags = (FOLDER_SUBSCRIBED | FOLDER_NOCHILDCREATE);
|
|
|
|
m_pStore->CreateFolder(NOFLAGS, &fi, NULL);
|
|
}
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::HandleRenameFolder
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::HandleRenameFolder(LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
char szUrlComponent[MAX_PATH];
|
|
DWORD dwUrlComponentLen = MAX_PATH;
|
|
FOLDERINFO fi = {0};
|
|
LPFOLDERINFO pfiFree = NULL;
|
|
|
|
// REVIEW: if the server doesn't return a response, return an error
|
|
Assert(NULL != pResponse->rCopyMoveInfo.pszLocation);
|
|
if (NULL != pResponse->rCopyMoveInfo.pszLocation)
|
|
{
|
|
if (FAILED(hr = Http_NameFromUrl(pResponse->rCopyMoveInfo.pszLocation, szUrlComponent, &dwUrlComponentLen)))
|
|
goto exit;
|
|
|
|
if (FAILED(hr = m_pStore->GetFolderInfo(m_op.idFolder, &fi)))
|
|
goto exit;
|
|
|
|
pfiFree = &fi;
|
|
|
|
fi.pszName = m_op.pszFolderName;
|
|
fi.pszUrlComponent = szUrlComponent;
|
|
|
|
hr = m_pStore->UpdateRecord(&fi);
|
|
}
|
|
|
|
exit:
|
|
if (NULL != pfiFree)
|
|
m_pStore->FreeRecord(pfiFree);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::HandleDeleteFolder
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::HandleDeleteFolder(LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
return m_pStore->DeleteFolder(m_op.idFolder, DELETE_FOLDER_NOTRASHCAN, NULL);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::PurgeFolders
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::PurgeFolders(void)
|
|
{
|
|
// the folder list will be null if we didn't need
|
|
// to do an auto-sync
|
|
if (NULL != m_op.pFolderList)
|
|
m_op.pFolderList->PurgeRemainingFromStore();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::PurgeMessages
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::PurgeMessages(void)
|
|
{
|
|
TPair<CSimpleString, MARKEDMESSAGE> *pPair;
|
|
MESSAGEID idMessage = MESSAGEID_INVALID;
|
|
MESSAGEIDLIST rIdList = { 1, 1, &idMessage };
|
|
Assert(NULL != m_op.pmapMessageId);
|
|
|
|
long lMapLength = m_op.pmapMessageId->GetLength();
|
|
for (long lIndex = 0; lIndex < lMapLength; lIndex++)
|
|
{
|
|
pPair = m_op.pmapMessageId->GetItemAt(lIndex);
|
|
if (NULL != pPair && !pPair->m_value.fMarked)
|
|
{
|
|
idMessage = pPair->m_value.idMessage;
|
|
m_pFolder->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &rIdList, NULL, NULL /* m_op.pCallback */);
|
|
}
|
|
}
|
|
|
|
// don't need the map anymore
|
|
SafeDelete(m_op.pmapMessageId);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::ResetMessageCounts
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::ResetMessageCounts(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
FOLDERINFO fi;
|
|
LPFOLDERINFO pfiFree = NULL;
|
|
|
|
// find the folder
|
|
IF_FAILEXIT(hr = m_pStore->GetFolderInfo(m_idFolder, &fi));
|
|
|
|
pfiFree = &fi;
|
|
|
|
// update the counts
|
|
if (fi.cMessages != m_op.cMessages || fi.cUnread != m_op.cUnread)
|
|
{
|
|
fi.cMessages = m_op.cMessages;
|
|
fi.cUnread = m_op.cUnread;
|
|
}
|
|
|
|
hr = m_pStore->UpdateRecord(&fi);
|
|
|
|
exit:
|
|
if (pfiFree)
|
|
m_pStore->FreeRecord(pfiFree);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::GetMessage
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::GetMessage(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
MESSAGEINFO mi = {0};
|
|
BOOL fFoundRecord = FALSE;
|
|
LPCSTR rgszAcceptTypes[] = { c_szAcceptTypeRfc822, c_szAcceptTypeWildcard, NULL };
|
|
LPSTR pszUrl = NULL;
|
|
TCHAR szRes[CCHMAX_STRINGRES];
|
|
|
|
// pull the message info out of the store
|
|
if (FAILED(hr = GetMessageInfo(m_pFolder, m_op.idMessage, &mi)))
|
|
goto exit;
|
|
|
|
fFoundRecord = TRUE;
|
|
Assert(mi.pszUrlComponent);
|
|
|
|
if (FAILED(hr =_BuildMessageUrl(m_pszFolderUrl, mi.pszUrlComponent, &pszUrl)))
|
|
goto exit;
|
|
|
|
AthLoadString(idsRequestingArt, szRes, ARRAYSIZE(szRes));
|
|
|
|
if (m_op.pCallback)
|
|
m_op.pCallback->OnProgress(m_op.tyOperation, 0, 0, szRes);
|
|
|
|
if (FAILED(hr = m_pTransport->CommandGET(pszUrl, rgszAcceptTypes, FALSE, 0)))
|
|
goto exit;
|
|
|
|
hr = E_PENDING;
|
|
|
|
exit:
|
|
if (fFoundRecord)
|
|
m_pFolder->FreeRecord(&mi);
|
|
|
|
SafeMemFree(pszUrl);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::CreateSetFlagsRequest
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::CreateSetFlagsRequest(void)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = CoCreateInstance(CLSID_IPropPatchRequest, NULL, CLSCTX_INPROC_SERVER, IID_IPropPatchRequest, (LPVOID *)&m_op.pPropPatchRequest);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
if (m_op.fMarkRead)
|
|
hr = m_op.pPropPatchRequest->SetProperty(DAVNAMESPACE_HTTPMAIL, "read", "1");
|
|
else
|
|
hr = m_op.pPropPatchRequest->SetProperty(DAVNAMESPACE_HTTPMAIL, "read", "0");
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::SetMessageFlags
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::SetMessageFlags(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPHTTPTARGETLIST pTargets = NULL;
|
|
LPSTR pszMessageUrl = NULL;
|
|
ADJUSTFLAGS af;
|
|
|
|
af.dwAdd = m_op.fMarkRead ? ARF_READ : 0;
|
|
af.dwRemove = !m_op.fMarkRead ? ARF_READ : 0;
|
|
|
|
// if we have a rowset, we shouldn't have an ID List.
|
|
Assert(NULL == m_op.hRowSet || NULL == m_op.pIDList);
|
|
IF_FAILEXIT(hr = _HrBuildMapAndTargets(m_op.pIDList, m_op.hRowSet, &af, m_op.dwSetFlags, &m_op.pmapMessageId, &pTargets));
|
|
|
|
// if the folder is the msnpromo folder, advance to the next state.
|
|
// don't actually send the command to the server
|
|
if (FOLDER_MSNPROMO == m_tySpecialFolder)
|
|
goto exit;
|
|
|
|
// if there is only one target, build a complete url for the target
|
|
// and invoke the non-batch version of the command. if there are no targets,
|
|
// return S_OK, and don't send any commands to the xport
|
|
if (1 == pTargets->cTarget)
|
|
{
|
|
IF_FAILEXIT(hr = _BuildMessageUrl(m_pszFolderUrl, const_cast<char *>(pTargets->prgTarget[0]), &pszMessageUrl));
|
|
IF_FAILEXIT(hr = m_pTransport->MarkRead(pszMessageUrl, NULL, m_op.fMarkRead, 0));
|
|
|
|
hr = E_PENDING;
|
|
}
|
|
else if (pTargets->cTarget > 0)
|
|
{
|
|
IF_FAILEXIT(hr = m_pTransport->MarkRead(m_pszFolderUrl, pTargets, m_op.fMarkRead, 0));
|
|
|
|
hr = E_PENDING;
|
|
}
|
|
|
|
exit:
|
|
if (pTargets)
|
|
Http_FreeTargetList(pTargets);
|
|
SafeMemFree(pszMessageUrl);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::ApplyFlagsToStore
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::ApplyFlagsToStore(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TPair<CSimpleString, MARKEDMESSAGE> *pPair;
|
|
long lMapLength = m_op.pmapMessageId->GetLength();
|
|
ADJUSTFLAGS af;
|
|
BOOL fFoundMarked = FALSE;
|
|
long lIndex;
|
|
|
|
af.dwAdd = m_op.fMarkRead ? ARF_READ : 0;
|
|
af.dwRemove = !m_op.fMarkRead ? ARF_READ : 0;
|
|
|
|
// if the operation was requested on the entire folder,
|
|
// check to see if anything failed. if it did, then
|
|
// build up an IDList so we can mark only the msgs that
|
|
// were successfully modified
|
|
if (NULL != m_op.hRowSet)
|
|
{
|
|
Assert(NULL == m_op.pIDList);
|
|
for (lIndex = 0; lIndex < lMapLength && !fFoundMarked; lIndex++)
|
|
{
|
|
pPair = m_op.pmapMessageId->GetItemAt(lIndex);
|
|
Assert(NULL != pPair);
|
|
if (pPair && pPair->m_value.fMarked)
|
|
fFoundMarked = TRUE;
|
|
}
|
|
|
|
// if no messages were marked, apply the operation to the entire folder
|
|
if (!fFoundMarked)
|
|
{
|
|
hr = m_pFolder->SetMessageFlags(NULL, &af, NULL, NULL);
|
|
// we're done
|
|
goto exit;
|
|
}
|
|
|
|
// if one or more msgs were marked, allocate an idlist
|
|
if (fFoundMarked)
|
|
{
|
|
// allocate the list structure
|
|
if (!MemAlloc((void **)&m_op.pIDList, sizeof(MESSAGEIDLIST)))
|
|
{
|
|
hr = TrapError(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
ZeroMemory(m_op.pIDList, sizeof(MESSAGEIDLIST));
|
|
|
|
// allocate storage
|
|
if (!MemAlloc((void **)&m_op.pIDList->prgidMsg, sizeof(MESSAGEID) * lMapLength))
|
|
{
|
|
hr = TrapError(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
m_op.pIDList->cAllocated = lMapLength;
|
|
m_op.pIDList->cMsgs = 0;
|
|
}
|
|
}
|
|
|
|
|
|
// we need to apply the setflags operation to the local store. we
|
|
// can't just pass the message id list that we got originally,
|
|
// because some of the operation may have failed. instead, we
|
|
// rebuild the id list (in place, since we know the successful
|
|
// operations will never outnumber the attempted operations),
|
|
// and send that into the store
|
|
Assert(NULL != m_op.pIDList);
|
|
Assert(NULL != m_op.pmapMessageId);
|
|
Assert(m_op.pIDList->cMsgs >= (DWORD)lMapLength);
|
|
|
|
m_op.pIDList->cMsgs = 0;
|
|
|
|
for (lIndex = 0; lIndex < lMapLength; lIndex++)
|
|
{
|
|
pPair = m_op.pmapMessageId->GetItemAt(lIndex);
|
|
Assert(NULL != pPair);
|
|
// if the item isn't marked, then it was successfully modified
|
|
if (pPair && !pPair->m_value.fMarked)
|
|
m_op.pIDList->prgidMsg[m_op.pIDList->cMsgs++] = pPair->m_value.idMessage;
|
|
}
|
|
|
|
// if the resulting id list contains at least one message, perform the operation
|
|
if (m_op.pIDList->cMsgs > 0)
|
|
hr = m_pFolder->SetMessageFlags(m_op.pIDList, &af, NULL, NULL);
|
|
|
|
// todo: alert user if the operation failed in part
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::HandleMemberErrors
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::HandleMemberErrors(LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPHTTPMEMBERERROR pme = NULL;
|
|
CHAR szUrlComponent[MAX_PATH];
|
|
DWORD dwComponentBytes;
|
|
CSimpleString ss;
|
|
TPair<CSimpleString, MARKEDMESSAGE> *pFoundPair = NULL;
|
|
|
|
// loop through the response looking for errors. we ignore
|
|
// per-item success.
|
|
|
|
for (DWORD dw = 0; dw < pResponse->rMemberErrorList.cMemberError; dw++)
|
|
{
|
|
pme = &pResponse->rMemberErrorList.prgMemberError[dw];
|
|
|
|
if (SUCCEEDED(pme->hrResult))
|
|
continue;
|
|
|
|
Assert(NULL != pme->pszHref);
|
|
if (NULL == pme->pszHref)
|
|
continue;
|
|
|
|
dwComponentBytes = ARRAYSIZE(szUrlComponent);
|
|
if (FAILED(Http_NameFromUrl(pme->pszHref, szUrlComponent, &dwComponentBytes)))
|
|
continue;
|
|
|
|
IF_FAILEXIT(hr = ss.SetString(szUrlComponent));
|
|
|
|
// find and mark the found message
|
|
pFoundPair = m_op.pmapMessageId->Find(ss);
|
|
Assert(NULL != pFoundPair);
|
|
if (NULL != pFoundPair)
|
|
pFoundPair->m_value.fMarked = TRUE;
|
|
}
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::DeleteMessages
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::DeleteMessages(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPSTR pszMessageUrl = NULL;
|
|
LPSTR pszNoDeleteSupport = NULL;
|
|
|
|
// if we have a rowset, we shouldn't have an ID List
|
|
Assert(NULL == m_op.hRowSet || NULL == m_op.pIDList);
|
|
IF_FAILEXIT(hr = _HrBuildMapAndTargets(m_op.pIDList, m_op.hRowSet, NULL, 0, &m_op.pmapMessageId, &m_op.pTargets));
|
|
|
|
// look for an already cached property that indicates that the server
|
|
// isn't going to support deleting messages (Hotmail doesn't)
|
|
if (GetAccountPropStrA(m_szAccountId, CAP_HTTPNOMESSAGEDELETES, &pszNoDeleteSupport))
|
|
{
|
|
if (!!(DELETE_MESSAGE_MAYIGNORENOTRASH & m_op.dwDelMsgFlags))
|
|
m_op.fFallbackToMove = TRUE;
|
|
else
|
|
hr = SP_E_HTTP_NODELETESUPPORT;
|
|
goto exit;
|
|
}
|
|
|
|
// if there is only one target, build a complete url for the target,
|
|
// and call the non-batch version of the command. if there are no targets,
|
|
// return S_OK and don't issue any commands
|
|
if (!m_op.pTargets)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
if (1 == m_op.pTargets->cTarget)
|
|
{
|
|
IF_FAILEXIT(hr = _BuildMessageUrl(m_pszFolderUrl, const_cast<char *>(m_op.pTargets->prgTarget[0]), &pszMessageUrl));
|
|
IF_FAILEXIT(hr = m_pTransport->CommandDELETE(pszMessageUrl, 0));
|
|
}
|
|
else
|
|
IF_FAILEXIT(hr = m_pTransport->CommandBDELETE(m_pszFolderUrl, m_op.pTargets, 0));
|
|
|
|
hr = E_PENDING;
|
|
|
|
exit:
|
|
SafeMemFree(pszNoDeleteSupport);
|
|
SafeMemFree(pszMessageUrl);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::DeleteFallbackToMove
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::DeleteFallbackToMove(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IMessageFolder *pDeletedItems = NULL;
|
|
|
|
if (!m_op.fFallbackToMove)
|
|
goto exit;
|
|
|
|
// find the deleted items folder
|
|
IF_FAILEXIT(hr = m_pStore->OpenSpecialFolder(m_idServer, NULL, FOLDER_DELETED, &pDeletedItems));
|
|
if (NULL == pDeletedItems)
|
|
{
|
|
hr = TraceResult(IXP_E_HTTP_NOT_FOUND);
|
|
goto exit;
|
|
}
|
|
|
|
IF_FAILEXIT(hr = pDeletedItems->GetFolderId(&m_op.idFolder));
|
|
|
|
Assert(NULL == m_op.pMessageFolder);
|
|
|
|
// should already have a targets list by this point
|
|
Assert(NULL != m_op.pTargets);
|
|
|
|
m_op.pMessageFolder = pDeletedItems;
|
|
pDeletedItems = NULL;
|
|
|
|
m_op.dwOptions = COPY_MESSAGE_MOVE;
|
|
|
|
if (1 == m_op.pTargets->cTarget)
|
|
hr = CopyMoveMessage();
|
|
else
|
|
hr = BatchCopyMoveMessages();
|
|
|
|
exit:
|
|
SafeRelease(pDeletedItems);
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::HandleDeleteFallbackToMove
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::HandleDeleteFallbackToMove(LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (1 == m_op.pTargets->cTarget)
|
|
hr = HandleCopyMoveMessage(pResponse);
|
|
else
|
|
hr = HandleBatchCopyMoveMessages(pResponse);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::PutMessage
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::PutMessage(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
FOLDERINFO fi;
|
|
LPFOLDERINFO pfiFree = NULL;
|
|
|
|
IF_FAILEXIT(hr = m_pStore->GetFolderInfo(m_op.idFolder, &fi));
|
|
|
|
pfiFree = &fi;
|
|
|
|
IF_FAILEXIT(hr = _BuildUrl(fi.pszUrlComponent, NULL, &m_op.pszDestFolderUrl));
|
|
|
|
IF_FAILEXIT(hr = m_pTransport->CommandPOST(m_op.pszDestFolderUrl, m_op.pMessageStream, c_szAcceptTypeRfc822, 0));
|
|
|
|
hr = E_PENDING;
|
|
|
|
exit:
|
|
//SafeMemFree(pv);
|
|
|
|
if (pfiFree)
|
|
m_pStore->FreeRecord(pfiFree);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::BatchCopyMoveMessages
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::BatchCopyMoveMessages(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
FOLDERINFO fi = {0};
|
|
LPFOLDERINFO pfiFree = NULL;
|
|
|
|
// build the destination folder urls
|
|
IxpAssert(NULL == m_op.pszDestFolderUrl);
|
|
|
|
if (FAILED(hr = m_pStore->GetFolderInfo(m_op.idFolder, &fi)))
|
|
{
|
|
TraceResult(hr);
|
|
goto exit;
|
|
}
|
|
|
|
pfiFree = &fi;
|
|
|
|
if (FAILED(hr = _BuildUrl(fi.pszUrlComponent, NULL, &m_op.pszDestFolderUrl)))
|
|
goto exit;
|
|
|
|
Assert(NULL == m_op.pTargets || m_op.fFallbackToMove);
|
|
|
|
// build the target list and the message id map
|
|
if (NULL == m_op.pTargets)
|
|
IF_FAILEXIT(hr = _HrBuildMapAndTargets(m_op.pIDList, NULL, NULL, 0, &m_op.pmapMessageId, &m_op.pTargets));
|
|
|
|
if (!!(m_op.dwOptions & COPY_MESSAGE_MOVE))
|
|
hr = m_pTransport->CommandBMOVE(m_pszFolderUrl, m_op.pTargets, m_op.pszDestFolderUrl, NULL, TRUE, 0);
|
|
else
|
|
hr = m_pTransport->CommandBCOPY(m_pszFolderUrl, m_op.pTargets, m_op.pszDestFolderUrl, NULL, TRUE, 0);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = E_PENDING;
|
|
|
|
exit:
|
|
if (pfiFree)
|
|
m_pStore->FreeRecord(pfiFree);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::CopyMoveMessage
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::CopyMoveMessage(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
FOLDERINFO fi = {0};
|
|
LPFOLDERINFO pfiFree = NULL;
|
|
|
|
// build the destination folder urls
|
|
IxpAssert(NULL == m_op.pszDestFolderUrl);
|
|
|
|
if (FAILED(hr = m_pStore->GetFolderInfo(m_op.idFolder, &fi)))
|
|
{
|
|
TraceResult(hr);
|
|
goto exit;
|
|
}
|
|
|
|
pfiFree = &fi;
|
|
|
|
if (FAILED(hr = _BuildUrl(fi.pszUrlComponent, NULL, &m_op.pszDestFolderUrl)))
|
|
goto exit;
|
|
|
|
hr = _CopyMoveNextMessage();
|
|
|
|
exit:
|
|
if (pfiFree)
|
|
m_pStore->FreeRecord(pfiFree);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::FinalizeBatchCopyMove
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::FinalizeBatchCopyMove(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (NOFLAGS != m_op.dwCopyMoveErrorFlags)
|
|
{
|
|
hr = E_FAIL;
|
|
|
|
if (HTTPCOPYMOVE_OUTOFSPACE == m_op.dwCopyMoveErrorFlags)
|
|
m_op.pszProblem = AthLoadString(idsHttpBatchCopyNoStorage, NULL, 0);
|
|
else
|
|
m_op.pszProblem = AthLoadString(idsHttpBatchCopyErrors, NULL , 0);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::PurgeDeletedFromStore
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::PurgeDeletedFromStore(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TPair<CSimpleString, MARKEDMESSAGE> *pPair;
|
|
long lMapLength = m_op.pmapMessageId->GetLength();
|
|
BOOL fFoundMarked = FALSE;
|
|
long lIndex;
|
|
|
|
if (m_op.fFallbackToMove)
|
|
goto exit;
|
|
|
|
// if the operation was requested on the entire folder,
|
|
// check to see if anything failed. if it did, then build
|
|
// up an IDList so we can mark only the msgs that were
|
|
// successfully modified
|
|
if (NULL != m_op.hRowSet)
|
|
{
|
|
Assert(NULL == m_op.pIDList);
|
|
for (lIndex = 0; lIndex < lMapLength && !fFoundMarked; lIndex++)
|
|
{
|
|
pPair = m_op.pmapMessageId->GetItemAt(lIndex);
|
|
Assert(NULL != pPair);
|
|
if (pPair && pPair->m_value.fMarked)
|
|
fFoundMarked = TRUE;
|
|
}
|
|
|
|
// if no messages were marked, apply the operation to the entire folder
|
|
if (!fFoundMarked)
|
|
{
|
|
hr = m_pFolder->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, NULL, NULL, NULL);
|
|
// we're done
|
|
goto exit;
|
|
}
|
|
|
|
// if one or more msgs were marked, allocate an idlist
|
|
if (fFoundMarked)
|
|
{
|
|
// allocate the list structure
|
|
if (!MemAlloc((void **)&m_op.pIDList, sizeof(MESSAGEIDLIST)))
|
|
{
|
|
hr = TrapError(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
ZeroMemory(m_op.pIDList, sizeof(MESSAGEIDLIST));
|
|
|
|
// allocate storage
|
|
if (!MemAlloc((void **)&m_op.pIDList->prgidMsg, sizeof(MESSAGEID) * lMapLength))
|
|
{
|
|
hr = TrapError(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
m_op.pIDList->cAllocated = lMapLength;
|
|
m_op.pIDList->cMsgs = 0;
|
|
}
|
|
}
|
|
|
|
// apply the delete operation to the local store. we can't just pass
|
|
// the message id list that we got originally, because some of the operation
|
|
// may have failed. instead, we rebuild the id list (in place, since we know
|
|
// the successful operations will never outnumber the attempted operations,
|
|
// and send that to the store.
|
|
Assert(NULL != m_op.pIDList);
|
|
Assert(NULL != m_op.pmapMessageId);
|
|
Assert(m_op.pIDList->cMsgs >= (DWORD)lMapLength);
|
|
|
|
// set the idlist count to 0. we will re-populate the
|
|
// idlist with ids from the messageID map. We know that
|
|
// the idlist is the same size as the map, so there won't
|
|
// be an overflow problem.
|
|
m_op.pIDList->cMsgs = 0;
|
|
|
|
for (lIndex = 0; lIndex < lMapLength; lIndex++)
|
|
{
|
|
pPair = m_op.pmapMessageId->GetItemAt(lIndex);
|
|
Assert(NULL != pPair);
|
|
// if the item isn't marked, then it was successfully modified
|
|
if (pPair && !pPair->m_value.fMarked)
|
|
m_op.pIDList->prgidMsg[m_op.pIDList->cMsgs++] = pPair->m_value.idMessage;
|
|
}
|
|
|
|
// if the resulting id list contains at least one message, perform the operation
|
|
if (m_op.pIDList->cMsgs > 0)
|
|
hr = m_pFolder->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, m_op.pIDList, NULL, NULL);
|
|
|
|
// todo: alert user if the operation failed in part
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::HandlePutMessage
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::HandlePutMessage(LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!pResponse->fDone && m_op.pCallback)
|
|
{
|
|
m_op.pCallback->OnProgress(m_op.tyOperation,
|
|
pResponse->rPostInfo.cbCurrent,
|
|
pResponse->rPostInfo.cbTotal,
|
|
NULL);
|
|
}
|
|
|
|
if (pResponse->fDone)
|
|
{
|
|
Assert(NULL != pResponse->rPostInfo.pszLocation);
|
|
if (NULL == pResponse->rPostInfo.pszLocation)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// assume ownership of the location url
|
|
m_op.pszDestUrl = pResponse->rPostInfo.pszLocation;
|
|
pResponse->rPostInfo.pszLocation = NULL;
|
|
}
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::AddPutMessage
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::AddPutMessage()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IMessageFolder *pFolder = NULL;
|
|
MESSAGEID idMessage;
|
|
MESSAGEFLAGS dwFlags;
|
|
|
|
// adopt some of the flags of the message we are putting
|
|
dwFlags = m_op.dwMsgFlags & (ARF_READ | ARF_SIGNED | ARF_ENCRYPTED | ARF_HASATTACH | ARF_VOICEMAIL);
|
|
|
|
if (!!(m_op.dwMsgFlags & ARF_UNSENT) || FOLDER_DRAFT == m_tySpecialFolder)
|
|
dwFlags |= ARF_UNSENT;
|
|
|
|
IF_FAILEXIT(hr = m_pStore->OpenFolder(m_op.idFolder, NULL, NOFLAGS, &pFolder));
|
|
|
|
IF_FAILEXIT(hr = Http_AddMessageToFolder(pFolder, m_szAccountId, NULL, dwFlags, m_op.pszDestUrl, &idMessage));
|
|
|
|
IF_FAILEXIT(hr = Http_SetMessageStream(pFolder, idMessage, m_op.pMessageStream, NULL, TRUE));
|
|
|
|
m_op.idPutMessage = idMessage;
|
|
|
|
exit:
|
|
SafeRelease(pFolder);
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::HandleBatchCopyMoveMessages
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::HandleBatchCopyMoveMessages(LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CHAR szUrlComponent[MAX_PATH];
|
|
DWORD dwComponentBytes;
|
|
LPHTTPMAILBCOPYMOVE pCopyMove;
|
|
CSimpleString ss;
|
|
TPair<CSimpleString, MARKEDMESSAGE> *pFoundPair = NULL;
|
|
HLOCK hLockNotify = NULL;
|
|
BOOL fDeleteOriginal = !!(m_op.dwOptions & COPY_MESSAGE_MOVE);
|
|
|
|
// This forces all notifications to be queued (this is good since you do segmented deletes)
|
|
m_pFolder->LockNotify(0, &hLockNotify);
|
|
|
|
for (DWORD dw = 0; dw < pResponse->rBCopyMoveList.cBCopyMove; dw++)
|
|
{
|
|
pCopyMove = &pResponse->rBCopyMoveList.prgBCopyMove[dw];
|
|
|
|
if (FAILED(pCopyMove->hrResult))
|
|
{
|
|
if (IXP_E_HTTP_INSUFFICIENT_STORAGE == pCopyMove->hrResult)
|
|
m_op.dwCopyMoveErrorFlags |= HTTPCOPYMOVE_OUTOFSPACE;
|
|
else
|
|
m_op.dwCopyMoveErrorFlags |= HTTPCOPYMOVE_ERROR;
|
|
continue;
|
|
}
|
|
|
|
Assert(NULL != pCopyMove->pszHref);
|
|
if (pCopyMove->pszHref)
|
|
{
|
|
dwComponentBytes = ARRAYSIZE(szUrlComponent);
|
|
if (FAILED(Http_NameFromUrl(pCopyMove->pszHref, szUrlComponent, &dwComponentBytes)))
|
|
continue;
|
|
|
|
if (FAILED(ss.SetString(szUrlComponent)))
|
|
goto exit;
|
|
|
|
pFoundPair = m_op.pmapMessageId->Find(ss);
|
|
Assert(NULL != pFoundPair);
|
|
|
|
if (NULL == pFoundPair)
|
|
continue;
|
|
|
|
// move the message and, if the move succeeds, mark the success
|
|
if (SUCCEEDED(_CopyMoveLocalMessage(pFoundPair->m_value.idMessage, m_op.pMessageFolder, pCopyMove->pszLocation, fDeleteOriginal)))
|
|
pFoundPair->m_value.fMarked = TRUE;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
m_pFolder->UnlockNotify(&hLockNotify);
|
|
|
|
m_op.lIndex += pResponse->rBCopyMoveList.cBCopyMove;
|
|
if (m_op.pCallback)
|
|
m_op.pCallback->OnProgress(m_op.tyOperation, m_op.lIndex + 1, m_op.pmapMessageId->GetLength(), NULL);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::HandleCopyMessage
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::HandleCopyMoveMessage(LPHTTPMAILRESPONSE pResponse)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL fDeleteOriginal = !!(m_op.dwOptions & COPY_MESSAGE_MOVE);
|
|
|
|
hr = _CopyMoveLocalMessage(m_op.pIDList->prgidMsg[m_op.dwIndex - 1],
|
|
m_op.pMessageFolder,
|
|
pResponse->rCopyMoveInfo.pszLocation,
|
|
fDeleteOriginal);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_CopyMoveLocalMessage
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::_CopyMoveLocalMessage(MESSAGEID idMessage,
|
|
IMessageFolder* pDestFolder,
|
|
LPSTR pszUrl,
|
|
BOOL fMoveSource)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
MESSAGEINFO miSource, miDest;
|
|
char szUrlComponent[MAX_PATH];
|
|
DWORD dwUrlComponentLen = MAX_PATH;
|
|
IStream *pStream = NULL;
|
|
LPMESSAGEINFO pmiFreeSource = NULL;
|
|
MESSAGEIDLIST rIdList = { 1, 1, &idMessage };
|
|
|
|
ZeroMemory(&miDest, sizeof(MESSAGEINFO));
|
|
|
|
if (FAILED(hr = GetMessageInfo(m_pFolder, idMessage, &miSource)))
|
|
goto exit;
|
|
|
|
pmiFreeSource = &miSource;
|
|
|
|
// get the store to generate an id
|
|
if (FAILED(hr = pDestFolder->GenerateId((DWORD *)&miDest.idMessage)))
|
|
goto exit;
|
|
|
|
// if the response specified a destination, use it. otherwise, assume
|
|
// that the url component did not change
|
|
if (pszUrl)
|
|
{
|
|
if (FAILED(hr = Http_NameFromUrl(pszUrl, szUrlComponent, &dwUrlComponentLen)))
|
|
goto exit;
|
|
}
|
|
else if (miSource.pszUrlComponent)
|
|
{
|
|
StrCpyN(szUrlComponent, miSource.pszUrlComponent, ARRAYSIZE(szUrlComponent));
|
|
}
|
|
|
|
miDest.dwFlags = miSource.dwFlags;
|
|
miDest.dwFlags &= ~(ARF_HASBODY | ARF_DELETED_OFFLINE);
|
|
miDest.pszSubject = miSource.pszSubject;
|
|
miDest.pszNormalSubj = miSource.pszNormalSubj;
|
|
miDest.pszDisplayFrom = miSource.pszDisplayFrom;
|
|
miDest.ftReceived = miSource.ftReceived;
|
|
miDest.pszUrlComponent = szUrlComponent;
|
|
miDest.pszEmailTo = miSource.pszEmailTo;
|
|
|
|
// add it to the database
|
|
if (FAILED(hr = m_op.pMessageFolder->InsertRecord(&miDest)))
|
|
goto exit;
|
|
|
|
// normalize the result code
|
|
hr = S_OK;
|
|
|
|
if (0 != miSource.faStream)
|
|
{
|
|
FILEADDRESS faDst;
|
|
IStream *pStmDst;
|
|
|
|
Assert(!!(miSource.dwFlags & ARF_HASBODY));
|
|
|
|
if (FAILED(hr = m_pFolder->CopyStream(m_op.pMessageFolder, miSource.faStream, &faDst)))
|
|
goto exit;
|
|
|
|
if (FAILED(hr = m_op.pMessageFolder->OpenStream(ACCESS_READ, faDst, &pStmDst)))
|
|
goto exit;
|
|
|
|
if (FAILED(hr = m_op.pMessageFolder->SetMessageStream(miDest.idMessage, pStmDst)))
|
|
{
|
|
pStmDst->Release();
|
|
goto exit;
|
|
}
|
|
|
|
pStmDst->Release();
|
|
}
|
|
|
|
if (fMoveSource)
|
|
hr = m_pFolder->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &rIdList, NULL, NULL);
|
|
|
|
exit:
|
|
SafeRelease(pStream);
|
|
if (NULL != pmiFreeSource)
|
|
m_pFolder->FreeRecord(pmiFreeSource);
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_CopyMoveNextMessage
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::_CopyMoveNextMessage(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
MESSAGEINFO mi = {0};
|
|
MESSAGEINFO *pmiFree = NULL;
|
|
char szUrlComponent[MAX_PATH];
|
|
DWORD dwUrlComponentLen = MAX_PATH;
|
|
LPSTR pszSourceUrl = NULL;
|
|
LPSTR pszDestUrl = NULL;
|
|
|
|
// return success when the index meets the count
|
|
if (m_op.dwIndex == m_op.pIDList->cMsgs)
|
|
goto exit;
|
|
|
|
if (FAILED(hr = GetMessageInfo(m_pFolder, m_op.pIDList->prgidMsg[m_op.dwIndex], &mi)))
|
|
goto exit;
|
|
|
|
pmiFree = &mi;
|
|
|
|
++m_op.dwIndex;
|
|
|
|
Assert(mi.pszUrlComponent);
|
|
if (NULL == mi.pszUrlComponent)
|
|
{
|
|
hr = ERROR_INTERNET_INVALID_URL;
|
|
goto exit;
|
|
}
|
|
|
|
// build the source url
|
|
if (FAILED(hr = _BuildMessageUrl(m_pszFolderUrl, mi.pszUrlComponent, &pszSourceUrl)))
|
|
goto exit;
|
|
|
|
// build the destination url
|
|
if (FAILED(hr = _BuildMessageUrl(m_op.pszDestFolderUrl, mi.pszUrlComponent, &pszDestUrl)))
|
|
goto exit;
|
|
|
|
if (!!(m_op.dwOptions & COPY_MESSAGE_MOVE))
|
|
hr = m_pTransport->CommandMOVE(pszSourceUrl, pszDestUrl, TRUE, 0);
|
|
else
|
|
hr = m_pTransport->CommandCOPY(pszSourceUrl, pszDestUrl, TRUE, 0);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = E_PENDING;
|
|
|
|
exit:
|
|
if (NULL != pmiFree)
|
|
m_pFolder->FreeRecord(pmiFree);
|
|
SafeMemFree(pszSourceUrl);
|
|
SafeMemFree(pszDestUrl);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_DoCopyMoveMessages
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::_DoCopyMoveMessages(STOREOPERATIONTYPE sot,
|
|
IMessageFolder *pDest,
|
|
COPYMESSAGEFLAGS dwOptions,
|
|
LPMESSAGEIDLIST pList,
|
|
IStoreCallback *pCallback)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
AssertSingleThreaded;
|
|
|
|
Assert(NULL == pList || pList->cMsgs > 0);
|
|
Assert(SOT_INVALID == m_op.tyOperation);
|
|
Assert(NULL != m_pStore);
|
|
|
|
if ((NULL == pList) || (0 == pList->cMsgs) || (NULL == pDest) || (NULL == pCallback))
|
|
return E_INVALIDARG;
|
|
|
|
if (FAILED(hr = pDest->GetFolderId(&m_op.idFolder)))
|
|
goto exit;
|
|
|
|
if (FAILED(hr = CloneMessageIDList(pList, &m_op.pIDList)))
|
|
{
|
|
m_op.idFolder = FOLDERID_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
m_op.tyOperation = sot;
|
|
|
|
if (1 == pList->cMsgs)
|
|
{
|
|
m_op.pfnState = c_rgpfnCopyMoveMessage;
|
|
m_op.cState = ARRAYSIZE(c_rgpfnCopyMoveMessage);
|
|
}
|
|
else
|
|
{
|
|
m_op.pfnState = c_rgpfnBatchCopyMoveMessages;
|
|
m_op.cState = ARRAYSIZE(c_rgpfnBatchCopyMoveMessages);
|
|
}
|
|
|
|
m_op.dwOptions = dwOptions;
|
|
m_op.iState = 0;
|
|
m_op.pCallback = pCallback;
|
|
m_op.pCallback->AddRef();
|
|
|
|
m_op.pMessageFolder = pDest;
|
|
m_op.pMessageFolder->AddRef();
|
|
|
|
hr = _BeginDeferredOperation();
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_LoadAccountInfo
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::_LoadAccountInfo(IImnAccount *pAcct)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
FOLDERINFO fi;
|
|
FOLDERINFO *pfiFree = NULL;;
|
|
|
|
Assert(NULL != pAcct);
|
|
Assert(FOLDERID_INVALID != m_idServer);
|
|
Assert(NULL != m_pStore);
|
|
Assert(NULL != g_pAcctMan);
|
|
|
|
// free data associated with the account. if we connected to
|
|
// a transport, and then disconnected, we might be reconnecting
|
|
// with stale data left around.
|
|
SafeMemFree(m_pszFldrLeafName);
|
|
|
|
IF_FAILEXIT(hr = m_pStore->GetFolderInfo(m_idServer, &fi));
|
|
|
|
pfiFree = &fi;
|
|
|
|
m_pszFldrLeafName = PszDupA(fi.pszName);
|
|
if (NULL == m_pszFldrLeafName)
|
|
{
|
|
hr = TraceResult(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
// failure of the account name is recoverable
|
|
pAcct->GetPropSz(AP_ACCOUNT_NAME, m_szAccountName, sizeof(m_szAccountName));
|
|
|
|
exit:
|
|
if (pfiFree)
|
|
m_pStore->FreeRecord(pfiFree);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_LoadTransport
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::_LoadTransport(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
char szLogFilePath[MAX_PATH];
|
|
char *pszLogFilePath = NULL;
|
|
LPSTR pszUserAgent = NULL;
|
|
|
|
Assert(NULL == m_pTransport);
|
|
|
|
// Create and initialize HTTPMail transport
|
|
hr = CoCreateInstance(CLSID_IHTTPMailTransport, NULL, CLSCTX_INPROC_SERVER, IID_IHTTPMailTransport, (LPVOID *)&m_pTransport);
|
|
if (FAILED(hr))
|
|
{
|
|
TraceResult(hr);
|
|
goto exit;
|
|
}
|
|
|
|
IF_FAILEXIT(hr = m_pTransport->QueryInterface(IID_IHTTPMailTransport2, (LPVOID*)&m_pTransport2));
|
|
|
|
// check if logging is enabled
|
|
if (DwGetOption(OPT_MAIL_LOGHTTPMAIL))
|
|
{
|
|
char szDirectory[MAX_PATH];
|
|
char szLogFileName[MAX_PATH];
|
|
|
|
DWORD cb;
|
|
|
|
*szDirectory = 0;
|
|
|
|
// get the log filename
|
|
cb = GetOption(OPT_MAIL_HTTPMAILLOGFILE, szLogFileName, sizeof(szLogFileName) / sizeof(TCHAR));
|
|
if (0 == cb)
|
|
{
|
|
// push the defaults into the registry
|
|
StrCpyN(szLogFileName, c_szDefaultHTTPMailLog, ARRAYSIZE(szLogFileName));
|
|
SetOption(OPT_MAIL_HTTPMAILLOGFILE,
|
|
(void *)c_szDefaultHTTPMailLog,
|
|
lstrlen(c_szDefaultHTTPMailLog) + sizeof(TCHAR),
|
|
NULL,
|
|
0);
|
|
}
|
|
|
|
m_pStore->GetDirectory(szDirectory, ARRAYSIZE(szDirectory));
|
|
PathCombineA(szLogFilePath, szDirectory, szLogFileName);
|
|
|
|
pszLogFilePath = szLogFilePath;
|
|
}
|
|
|
|
pszUserAgent = GetOEUserAgentString();
|
|
if (FAILED(hr = m_pTransport->InitNew(pszUserAgent, pszLogFilePath, this)))
|
|
{
|
|
TraceResult(hr);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
SafeMemFree(pszUserAgent);
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_TranslateHTTPSpecialFolderType
|
|
//----------------------------------------------------------------------
|
|
SPECIALFOLDER CHTTPMailServer::_TranslateHTTPSpecialFolderType(HTTPMAILSPECIALFOLDER tySpecial)
|
|
{
|
|
SPECIALFOLDER tyOESpecial;
|
|
|
|
switch (tySpecial)
|
|
{
|
|
case HTTPMAIL_SF_INBOX:
|
|
tyOESpecial = FOLDER_INBOX;
|
|
break;
|
|
|
|
case HTTPMAIL_SF_DELETEDITEMS:
|
|
tyOESpecial = FOLDER_DELETED;
|
|
break;
|
|
|
|
case HTTPMAIL_SF_DRAFTS:
|
|
tyOESpecial = FOLDER_DRAFT;
|
|
break;
|
|
|
|
case HTTPMAIL_SF_OUTBOX:
|
|
tyOESpecial = FOLDER_OUTBOX;
|
|
break;
|
|
|
|
case HTTPMAIL_SF_SENTITEMS:
|
|
tyOESpecial = FOLDER_SENT;
|
|
break;
|
|
|
|
case HTTPMAIL_SF_MSNPROMO:
|
|
tyOESpecial = FOLDER_MSNPROMO;
|
|
break;
|
|
|
|
case HTTPMAIL_SF_BULKMAIL:
|
|
tyOESpecial = FOLDER_BULKMAIL;
|
|
break;
|
|
|
|
default:
|
|
tyOESpecial = FOLDER_NOTSPECIAL;
|
|
break;
|
|
}
|
|
|
|
return tyOESpecial;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_LoadSpecialFolderName
|
|
//----------------------------------------------------------------------
|
|
BOOL CHTTPMailServer::_LoadSpecialFolderName(SPECIALFOLDER tySpecial,
|
|
LPSTR pszName,
|
|
DWORD cbBuffer)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
UINT uID;
|
|
|
|
switch (tySpecial)
|
|
{
|
|
case FOLDER_INBOX:
|
|
uID = idsInbox;
|
|
break;
|
|
|
|
case FOLDER_DELETED:
|
|
uID = idsDeletedItems;
|
|
break;
|
|
|
|
case FOLDER_DRAFT:
|
|
uID = idsDraft;
|
|
break;
|
|
|
|
case FOLDER_OUTBOX:
|
|
uID = idsOutbox;
|
|
break;
|
|
|
|
case FOLDER_SENT:
|
|
uID = idsSentItems;
|
|
break;
|
|
|
|
case FOLDER_MSNPROMO:
|
|
uID = idsMsnPromo;
|
|
break;
|
|
|
|
case FOLDER_BULKMAIL:
|
|
uID = idsJunkFolderName;
|
|
break;
|
|
|
|
default:
|
|
fResult = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (fResult && (0 == LoadString(g_hLocRes, uID, pszName, cbBuffer)))
|
|
fResult = FALSE;
|
|
|
|
return fResult;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_CreateMessageIDMap
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::_CreateMessageIDMap(TMap<CSimpleString, MARKEDMESSAGE> **ppMap)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TMap<CSimpleString, MARKEDMESSAGE> *pMap = NULL;
|
|
HROWSET hRowSet = NULL;
|
|
MESSAGEINFO mi;
|
|
CSimpleString ss;
|
|
MARKEDMESSAGE markedID = { 0, 0, FALSE };
|
|
|
|
if (NULL == m_pStore || NULL == ppMap)
|
|
return E_INVALIDARG;
|
|
|
|
*ppMap = NULL;
|
|
|
|
pMap = new TMap<CSimpleString, MARKEDMESSAGE>;
|
|
if (NULL == pMap)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
ZeroMemory(&mi, sizeof(MESSAGEINFO));
|
|
|
|
if (FAILED(hr = m_pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowSet)))
|
|
goto exit;
|
|
|
|
// iterate through the messages
|
|
while (S_OK == m_pFolder->QueryRowset(hRowSet, 1, (LPVOID *)&mi, NULL))
|
|
{
|
|
// add the message's info to the map
|
|
markedID.idMessage = mi.idMessage;
|
|
markedID.dwFlags = mi.dwFlags;
|
|
|
|
hr = ss.SetString(mi.pszUrlComponent);
|
|
if (FAILED(hr))
|
|
{
|
|
m_pFolder->FreeRecord(&mi);
|
|
goto exit;
|
|
}
|
|
|
|
hr = pMap->Add(ss, markedID);
|
|
|
|
// Free
|
|
m_pFolder->FreeRecord(&mi);
|
|
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
}
|
|
|
|
// the map was built successfully
|
|
*ppMap = pMap;
|
|
pMap = NULL;
|
|
|
|
exit:
|
|
if (NULL != hRowSet)
|
|
m_pFolder->CloseRowset(&hRowSet);
|
|
|
|
if (NULL != pMap)
|
|
delete pMap;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_HrBuildMapAndTargets
|
|
//----------------------------------------------------------------------
|
|
HRESULT CHTTPMailServer::_HrBuildMapAndTargets(LPMESSAGEIDLIST pList,
|
|
HROWSET hRowSet,
|
|
LPADJUSTFLAGS pFlags,
|
|
SETMESSAGEFLAGSFLAGS dwFlags,
|
|
TMap<CSimpleString, MARKEDMESSAGE> **ppMap,
|
|
LPHTTPTARGETLIST *ppTargets)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TMap<CSimpleString, MARKEDMESSAGE> *pMap = NULL;
|
|
LPHTTPTARGETLIST pTargets = NULL;
|
|
MESSAGEINFO mi = { 0 };
|
|
LPMESSAGEINFO pmiFree = NULL;
|
|
CSimpleString ss;
|
|
MARKEDMESSAGE markedID = { 0, 0, FALSE };
|
|
BOOL fSkipRead = (pFlags && !!(pFlags->dwAdd & ARF_READ));
|
|
BOOL fSkipUnread = (pFlags && !!(pFlags->dwRemove & ARF_READ));
|
|
DWORD cMsgs;
|
|
DWORD dwIndex = 0;
|
|
|
|
if ((NULL == pList && NULL == hRowSet) || NULL == ppMap || NULL == ppTargets)
|
|
return E_INVALIDARG;
|
|
|
|
// expect either a list or a rowset, but not both
|
|
Assert(NULL == pList || NULL == hRowSet);
|
|
|
|
// if using a rowset, determine the rowcount
|
|
if (NULL != hRowSet)
|
|
{
|
|
IF_FAILEXIT(hr = m_pFolder->GetRecordCount(0, &cMsgs));
|
|
|
|
// seek the first row
|
|
IF_FAILEXIT(hr = m_pFolder->SeekRowset(hRowSet, SEEK_ROWSET_BEGIN, 0, NULL));
|
|
}
|
|
else
|
|
cMsgs = pList->cMsgs;
|
|
|
|
*ppMap = NULL;
|
|
*ppTargets = NULL;
|
|
|
|
pMap = new TMap<CSimpleString, MARKEDMESSAGE>;
|
|
if (NULL == pMap)
|
|
{
|
|
hr = TrapError(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
if (!MemAlloc((void **)&pTargets, sizeof(HTTPTARGETLIST)))
|
|
{
|
|
hr = TrapError(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
pTargets->cTarget = 0;
|
|
pTargets->prgTarget = NULL;
|
|
|
|
// allocate enough space for all of the targets
|
|
if (!MemAlloc((void **)&pTargets->prgTarget, sizeof(LPCSTR) * cMsgs))
|
|
{
|
|
hr = TrapError(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
ZeroMemory(pTargets->prgTarget, sizeof(LPCSTR) * cMsgs);
|
|
|
|
while (TRUE)
|
|
{
|
|
// fetch the next message
|
|
if (NULL != pList)
|
|
{
|
|
if (dwIndex == pList->cMsgs)
|
|
break;
|
|
|
|
hr = GetMessageInfo(m_pFolder, pList->prgidMsg[dwIndex++], &mi);
|
|
|
|
// if the record wasn't found, just skip it
|
|
if (DB_E_NOTFOUND == hr)
|
|
goto next;
|
|
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// bail out if the number of targets is the same as the rowcount
|
|
// we expected. this will prevent us from overflowing the target
|
|
// array if the rowcount changes while we are building up our target
|
|
// list.
|
|
if (pTargets->cTarget == cMsgs)
|
|
break;
|
|
|
|
if (S_OK != m_pFolder->QueryRowset(hRowSet, 1, (LPVOID *)&mi, NULL))
|
|
break;
|
|
}
|
|
|
|
pmiFree = &mi;
|
|
|
|
// respect control flags, if they exist
|
|
if (0 == (dwFlags & SET_MESSAGE_FLAGS_FORCE) && ((fSkipRead && !!(mi.dwFlags & ARF_READ)) || (fSkipUnread && !(mi.dwFlags & ARF_READ))))
|
|
goto next;
|
|
|
|
Assert(NULL != mi.pszUrlComponent);
|
|
if (NULL == mi.pszUrlComponent)
|
|
{
|
|
hr = TrapError(ERROR_INTERNET_INVALID_URL);
|
|
goto exit;
|
|
}
|
|
|
|
// add the url component to the target list
|
|
pTargets->prgTarget[pTargets->cTarget] = PszDupA(mi.pszUrlComponent);
|
|
if (NULL == pTargets->prgTarget[pTargets->cTarget])
|
|
{
|
|
hr = TrapError(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
pTargets->cTarget++;
|
|
|
|
// add the url and the message id to the map
|
|
markedID.idMessage = mi.idMessage;
|
|
markedID.dwFlags = mi.dwFlags;
|
|
|
|
if (FAILED(hr = ss.SetString(mi.pszUrlComponent)))
|
|
goto exit;
|
|
|
|
if (FAILED(hr = pMap->Add(ss, markedID)))
|
|
goto exit;
|
|
|
|
next:
|
|
if (pmiFree)
|
|
{
|
|
m_pFolder->FreeRecord(pmiFree);
|
|
pmiFree = NULL;
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
|
|
*ppMap = pMap;
|
|
pMap = NULL;
|
|
|
|
*ppTargets = pTargets;
|
|
pTargets = NULL;
|
|
|
|
exit:
|
|
if (pmiFree)
|
|
m_pFolder->FreeRecord(pmiFree);
|
|
|
|
if (pTargets)
|
|
Http_FreeTargetList(pTargets);
|
|
|
|
SafeDelete(pMap);
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CHTTPMailServer::_FillStoreError
|
|
//----------------------------------------------------------------------
|
|
void CHTTPMailServer::_FillStoreError(LPSTOREERROR pErrorInfo,
|
|
IXPRESULT *pResult)
|
|
{
|
|
TraceCall("CHTTPMailServer::FillStoreError");
|
|
|
|
Assert(m_cRef >= 0); // Can be called during destruction
|
|
Assert(NULL != pErrorInfo);
|
|
|
|
//TODO: Fill in pszFolder
|
|
|
|
// Fill out the STOREERROR structure
|
|
ZeroMemory(pErrorInfo, sizeof(*pErrorInfo));
|
|
if (IXP_E_USER_CANCEL == pResult->hrResult)
|
|
pErrorInfo->hrResult = STORE_E_OPERATION_CANCELED;
|
|
else
|
|
pErrorInfo->hrResult = pResult->hrResult;
|
|
pErrorInfo->uiServerError = pResult->uiServerError;
|
|
pErrorInfo->hrServerError = pResult->hrServerError;
|
|
pErrorInfo->dwSocketError = pResult->dwSocketError;
|
|
pErrorInfo->pszProblem = (NULL != m_op.pszProblem) ? m_op.pszProblem : pResult->pszProblem;
|
|
pErrorInfo->pszDetails = pResult->pszResponse;
|
|
pErrorInfo->pszAccount = m_rInetServerInfo.szAccount;
|
|
pErrorInfo->pszServer = m_rInetServerInfo.szServerName;
|
|
pErrorInfo->pszFolder = NULL;
|
|
pErrorInfo->pszUserName = m_rInetServerInfo.szUserName;
|
|
pErrorInfo->pszProtocol = "HTTPMail";
|
|
pErrorInfo->pszConnectoid = m_rInetServerInfo.szConnectoid;
|
|
pErrorInfo->rasconntype = m_rInetServerInfo.rasconntype;
|
|
pErrorInfo->ixpType = IXP_HTTPMail;
|
|
pErrorInfo->dwPort = m_rInetServerInfo.dwPort;
|
|
pErrorInfo->fSSL = m_rInetServerInfo.fSSL;
|
|
pErrorInfo->fTrySicily = m_rInetServerInfo.fTrySicily;
|
|
pErrorInfo->dwFlags = 0;
|
|
}
|
|
|
|
STDMETHODIMP CHTTPMailServer::GetAdBarUrl(IStoreCallback *pCallback)
|
|
{
|
|
TraceCall("CHTTPMailServer::GetAdBarUrl");
|
|
|
|
AssertSingleThreaded;
|
|
Assert(NULL != pCallback);
|
|
Assert(SOT_INVALID == m_op.tyOperation);
|
|
Assert(NULL != m_pStore);
|
|
|
|
if (NULL == pCallback)
|
|
return E_INVALIDARG;
|
|
|
|
m_op.tyOperation = SOT_GET_ADURL;
|
|
m_op.iState = 0;
|
|
m_op.pfnState = c_rgpfnGetAdUrl;
|
|
m_op.cState = ARRAYSIZE(c_rgpfnGetAdUrl);
|
|
m_op.pCallback = pCallback;
|
|
m_op.pCallback->AddRef();
|
|
|
|
return _BeginDeferredOperation();
|
|
|
|
}
|
|
|
|
HRESULT CHTTPMailServer::GetAdBarUrlFromServer()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPSTR pszUrl = NULL;
|
|
|
|
hr = m_pTransport->GetProperty(HTTPMAIL_PROP_ADBAR, &pszUrl);
|
|
|
|
if (hr == S_OK)
|
|
m_op.pszAdUrl = pszUrl;
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
STDMETHODIMP CHTTPMailServer::GetMinPollingInterval(IStoreCallback *pCallback)
|
|
{
|
|
TraceCall("CHTTPMailServer::GetMinPollingInterval");
|
|
|
|
AssertSingleThreaded;
|
|
Assert(NULL != pCallback);
|
|
Assert(SOT_INVALID == m_op.tyOperation);
|
|
Assert(NULL != m_pStore);
|
|
|
|
if (NULL == pCallback)
|
|
return E_INVALIDARG;
|
|
|
|
m_op.tyOperation = SOT_GET_HTTP_MINPOLLINGINTERVAL;
|
|
m_op.iState = 0;
|
|
m_op.pfnState = c_rgpfnGetMinPollingInterval;
|
|
m_op.cState = ARRAYSIZE(c_rgpfnGetMinPollingInterval);
|
|
m_op.pCallback = pCallback;
|
|
m_op.pCallback->AddRef();
|
|
|
|
return _BeginDeferredOperation();
|
|
|
|
}
|
|
|
|
HRESULT CHTTPMailServer::GetMinPollingInterval()
|
|
{
|
|
DWORD dwDone = FALSE;
|
|
DWORD dwPollingInterval = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = m_pTransport->GetPropertyDw(HTTPMAIL_PROP_MAXPOLLINGINTERVAL, &dwPollingInterval);
|
|
|
|
if (hr == S_OK)
|
|
m_op.dwMinPollingInterval = dwPollingInterval;
|
|
|
|
return hr;
|
|
}
|