Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2472 lines
67 KiB

//--------------------------------------------------------------------------
// ISTORE.CPP
//--------------------------------------------------------------------------
#include "pch.hxx"
#include "istore.h"
#include "instance.h"
#include "ourguid.h"
#include "msgfldr.h"
#include "flagconv.h"
#include "storutil.h"
#include "notify.h"
//--------------------------------------------------------------------------
// Flag Conversion functions
//--------------------------------------------------------------------------
DWORD DwConvertSCFStoMSG(DWORD dwSCFS);
DWORD DwConvertMSGtoARF(DWORD dwMSG);
DWORD DwConvertARFtoMSG(DWORD dwARF);
DWORD DwConvertMSGtoIMAP(DWORD dwMSG);
//--------------------------------------------------------------------------
// DwConvertMSGtoARF
//--------------------------------------------------------------------------
DWORD DwConvertMSGtoARF(DWORD dwMSG)
{
register DWORD dwRet = 0;
if (dwMSG & MSG_UNSENT)
dwRet |= ARF_UNSENT;
if (0 == (dwMSG & MSG_UNREAD))
dwRet |= ARF_READ;
if (dwMSG & MSG_NOSECUI)
dwRet |= ARF_NOSECUI;
if (dwMSG & MSG_SUBMITTED)
dwRet |= ARF_SUBMITTED;
if (dwMSG & MSG_RECEIVED)
dwRet |= ARF_RECEIVED;
if (dwMSG & MSG_NEWSMSG)
dwRet |= ARF_NEWSMSG;
if (dwMSG & MSG_REPLIED)
dwRet |= ARF_REPLIED;
if (dwMSG & MSG_FORWARDED)
dwRet |= ARF_FORWARDED;
if (dwMSG & MSG_RCPTSENT)
dwRet |= ARF_RCPTSENT;
if (dwMSG & MSG_FLAGGED)
dwRet |= ARF_FLAGGED;
if (dwMSG & MSG_VOICEMAIL)
dwRet |= ARF_VOICEMAIL;
return dwRet;
}
//--------------------------------------------------------------------------
// DwConvertARFtoMSG
//--------------------------------------------------------------------------
DWORD DwConvertARFtoMSG(DWORD dwARF)
{
register DWORD dwRet = 0;
if (dwARF & ARF_UNSENT)
dwRet |= MSG_UNSENT;
if (0 == (dwARF & ARF_READ))
dwRet |= MSG_UNREAD;
if (dwARF & ARF_NOSECUI)
dwRet |= MSG_NOSECUI;
if (dwARF & ARF_SUBMITTED)
dwRet |= MSG_SUBMITTED;
if (dwARF & ARF_RECEIVED)
dwRet |= MSG_RECEIVED;
if (dwARF & ARF_NEWSMSG)
dwRet |= MSG_NEWSMSG;
if (dwARF & ARF_REPLIED)
dwRet |= MSG_REPLIED;
if (dwARF & ARF_FORWARDED)
dwRet |= MSG_FORWARDED;
if (dwARF & ARF_RCPTSENT)
dwRet |= MSG_RCPTSENT;
if (dwARF & ARF_FLAGGED)
dwRet |= MSG_FLAGGED;
if (dwARF & ARF_VOICEMAIL)
dwRet |= MSG_VOICEMAIL;
return dwRet;
}
//--------------------------------------------------------------------------
// CreateInstance_StoreNamespace
//--------------------------------------------------------------------------
HRESULT CreateInstance_StoreNamespace(IUnknown *pUnkOuter, IUnknown **ppUnknown)
{
// Locals
HRESULT hr=S_OK;
CStoreNamespace *pNew=NULL;
// Trace
TraceCall("CreateInstance_StoreNamespace");
// Invalid Arg
Assert(NULL != ppUnknown && NULL == pUnkOuter);
// Create
IF_NULLEXIT(pNew = new CStoreNamespace);
// Return the Innter
*ppUnknown = SAFECAST(pNew, IStoreNamespace *);
exit:
// Done
return(hr);
}
//--------------------------------------------------------------------------
// FldInfoToFolderProps
//--------------------------------------------------------------------------
HRESULT FldInfoToFolderProps(LPFOLDERINFO pInfo, LPFOLDERPROPS pProps)
{
// Locals
HRESULT hr=S_OK;
ULONG cbSize;
IEnumerateFolders *pEnum=NULL;
// Stack...
TraceCall("FldInfoToFolderProps");
// Invalid ARg
Assert(pInfo && pProps);
// Bad version
if (sizeof(FOLDERPROPS) != pProps->cbSize)
{
AssertSz(FALSE, "Invalid - un-supported version.");
return TraceResult(MSOEAPI_E_INVALID_STRUCT_SIZE);
}
// Save Size
cbSize = pProps->cbSize;
// ZeroInit
ZeroMemory(pProps, sizeof(FOLDERPROPS));
// Copy the properties
pProps->cbSize = cbSize;
pProps->dwFolderId = pInfo->idFolder;
pProps->cUnread = pInfo->cUnread;
pProps->cMessage = pInfo->cMessages;
StrCpyN(pProps->szName, pInfo->pszName, ARRAYSIZE(pProps->szName));
// Map the special folder type
if (FOLDER_NOTSPECIAL == pInfo->tySpecial)
pProps->sfType = -1;
else
pProps->sfType = (pInfo->tySpecial - 1);
// Enumerate Subscribed Children
IF_FAILEXIT(hr = g_pStore->EnumChildren(pInfo->idFolder, TRUE, &pEnum));
// Count
if (FAILED(pEnum->Count((LPDWORD)&pProps->cSubFolders)))
pProps->cSubFolders = 0;
exit:
// Cleanup
SafeRelease(pEnum);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// MsgInfoToMessageProps
//--------------------------------------------------------------------------
HRESULT MsgInfoToMessageProps(BOOL fFast, LPMESSAGEINFO pMsgInfo, LPMESSAGEPROPS pProps)
{
// Locals
ULONG cbSize;
LPBYTE pbOffsets;
// Stack
TraceCall("MsgInfoToMessageProps");
// Invalid Arg
Assert(pMsgInfo && pProps);
// Bad version
if (sizeof(MESSAGEPROPS) != pProps->cbSize)
{
AssertSz(FALSE, "Invalid - un-supported version.");
return TraceResult(MSOEAPI_E_INVALID_STRUCT_SIZE);
}
// Save Size
cbSize = pProps->cbSize;
// ZeroInit
ZeroMemory(pProps, sizeof(MESSAGEPROPS));
// If Not Fast
if (FALSE == fFast)
{
// Message Size
pProps->cbMessage = pMsgInfo->cbMessage;
// Priority
pProps->priority = (IMSGPRIORITY)pMsgInfo->wPriority;
// Subject
pProps->pszSubject = pMsgInfo->pszSubject;
// Display To
pProps->pszDisplayTo = pMsgInfo->pszDisplayTo;
// Dislay From
pProps->pszDisplayFrom = pMsgInfo->pszDisplayFrom;
// Normalized Subject
pProps->pszNormalSubject = pMsgInfo->pszNormalSubj;
// Received Time
pProps->ftReceived = pMsgInfo->ftReceived;
// Sent Time
pProps->ftSent = pMsgInfo->ftSent;
// Set dwFlags
if (ISFLAGSET(pMsgInfo->dwFlags, ARF_VOICEMAIL))
FLAGSET(pProps->dwFlags, IMF_VOICEMAIL);
if (ISFLAGSET(pMsgInfo->dwFlags, ARF_NEWSMSG))
FLAGSET(pProps->dwFlags, IMF_NEWS);
// Dup the memory
pbOffsets = (LPBYTE)g_pMalloc->Alloc(pMsgInfo->Offsets.cbSize);
// If that worked
if (pbOffsets)
{
// Copy the offsets
CopyMemory(pbOffsets, pMsgInfo->Offsets.pBlobData, pMsgInfo->Offsets.cbSize);
// Create the Offset Table
pProps->pStmOffsetTable = new CByteStream(pbOffsets, pMsgInfo->Offsets.cbSize);
}
// Better have an offset table
AssertSz(pProps->pStmOffsetTable, "There is no offset table for this message.");
}
// Reset the Size
pProps->cbSize = cbSize;
// Store the MessageId
pProps->dwMessageId = pMsgInfo->idMessage;
// Store the Language
pProps->dwLanguage = pMsgInfo->wLanguage;
// Convert ARF_ to MSG_
pProps->dwState = DwConvertARFtoMSG(pMsgInfo->dwFlags);
// Store the Memory
pProps->dwReserved = (DWORD_PTR)pMsgInfo->pAllocated;
// pProps owns *ppHeader
ZeroMemory(pMsgInfo, sizeof(MESSAGEINFO));
// Done
return(S_OK);
}
//--------------------------------------------------------------------------
// CStoreNamespace::CStoreNamespace
//--------------------------------------------------------------------------
CStoreNamespace::CStoreNamespace(void)
{
TraceCall("CStoreNamespace::CStoreNamespace");
g_pInstance->DllAddRef();
m_cRef = 1;
m_cNotify = 0;
m_prghwndNotify = NULL;
m_fRegistered = FALSE;
m_hInitRef = NULL;
InitializeCriticalSection(&m_cs);
}
//--------------------------------------------------------------------------
// CStoreNamespace::~CStoreNamespace
//--------------------------------------------------------------------------
CStoreNamespace::~CStoreNamespace(void)
{
TraceCall("CStoreNamespace::~CStoreNamespace");
SafeMemFree(m_prghwndNotify);
if (m_fRegistered)
g_pStore->UnregisterNotify((IDatabaseNotify *)this);
DeleteCriticalSection(&m_cs);
g_pInstance->DllRelease();
CoDecrementInit("CStoreNamespace::Initialize", &m_hInitRef);
}
//--------------------------------------------------------------------------
// CStoreNamespace::AddRef
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CStoreNamespace::AddRef(void)
{
TraceCall("CStoreNamespace::AddRef");
return InterlockedIncrement(&m_cRef);
}
//--------------------------------------------------------------------------
// CStoreNamespace::Release
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CStoreNamespace::Release(void)
{
TraceCall("CStoreNamespace::Release");
LONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef)
delete this;
return (ULONG)cRef;
}
//--------------------------------------------------------------------------
// CStoreNamespace::QueryInterface
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::QueryInterface(REFIID riid, LPVOID *ppv)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("CStoreNamespace::QueryInterface");
// Find IID
if (IID_IUnknown == riid)
*ppv = (IUnknown *)(IStoreNamespace *)this;
else if (IID_IStoreNamespace == riid)
*ppv = (IStoreNamespace *)this;
else if (IID_IStoreCallback == riid)
*ppv = (IStoreCallback *)this;
else if (IID_IDatabaseNotify == riid)
*ppv = (IDatabaseNotify *)this;
else
{
*ppv = NULL;
hr = TraceResult(E_NOINTERFACE);
goto exit;
}
// AddRef It
((IUnknown *)*ppv)->AddRef();
exit:
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::Initialize
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::Initialize(HWND hwndOwner, DWORD dwFlags)
{
// Locals
HRESULT hr=S_OK;
DWORD dwStart=MSOEAPI_START_COMOBJECT;
// Stack
TraceCall("CStoreNamespace::Initialize");
// Thread Safety
EnterCriticalSection(&m_cs);
// Already Initialized
if (NULL != m_hInitRef)
{
TraceInfo("IStoreNamespace::Initialize has been called more than once.");
goto exit;
}
// Not Current Identity
if (!ISFLAGSET(dwFlags, NAMESPACE_INITIALIZE_CURRENTIDENTITY))
{
// Use Default Identity, must be MS Phone
FLAGSET(dwStart, MSOEAPI_START_DEFAULTIDENTITY);
}
// Initialize the store directory
IF_FAILEXIT(hr = CoIncrementInit("CStoreNamespace::Initialize", dwStart | MSOEAPI_START_STOREVALIDNODELETE, NULL, &m_hInitRef));
// Better Have g_pStore
Assert(g_pStore);
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::GetDirectory
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::GetDirectory(LPSTR pszPath, DWORD cchMaxPath)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("CStoreNamespace::GetDirectory");
// Invalid Arg
if (NULL == pszPath)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// Get the directory
IF_FAILEXIT(hr = GetStoreRootDirectory(pszPath, cchMaxPath));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::OpenSpecialFolder
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::OpenSpecialFolder(LONG sfType, DWORD dwReserved,
IStoreFolder **ppFolder)
{
// Locals
HRESULT hr=S_OK;
IMessageFolder *pFolder=NULL;
CStoreFolder *pComFolder=NULL;
// Stack
TraceCall("CStoreNamespace::OpenSpecialFolder");
// Invalid Arg
if (sfType <= -1 || sfType >= (FOLDER_MAX - 1) || 0 != dwReserved || NULL == ppFolder)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Init
*ppFolder = NULL;
// Thread Safety
EnterCriticalSection(&m_cs);
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// Ask the store to do the work
IF_FAILEXIT(hr = g_pStore->OpenSpecialFolder(FOLDERID_LOCAL_STORE, NULL, (BYTE)(sfType + 1), &pFolder));
// Create an IStoreFolder
IF_NULLEXIT(pComFolder = new CStoreFolder(pFolder, this));
// Return it
*ppFolder = (IStoreFolder *)pComFolder;
(*ppFolder)->AddRef();
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Cleanup
SafeRelease(pFolder);
SafeRelease(pComFolder);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::OpenFolder
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::OpenFolder(FOLDERID dwFolderId, DWORD dwReserved,
IStoreFolder **ppFolder)
{
// Locals
HRESULT hr=S_OK;
IMessageFolder *pFolder=NULL;
CStoreFolder *pComFolder=NULL;
// Stack
TraceCall("CStoreNamespace::OpenFolder");
// Invalid Arg
if (FOLDERID_INVALID == dwFolderId || 0 != dwReserved || NULL == ppFolder)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Init
*ppFolder = NULL;
// Thread Safety
EnterCriticalSection(&m_cs);
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// Open the folder
IF_FAILEXIT(hr = g_pStore->OpenFolder(dwFolderId, NULL, NOFLAGS, &pFolder));
// Create an IStoreFolder
IF_NULLEXIT(pComFolder = new CStoreFolder(pFolder, this));
// Return it
*ppFolder = (IStoreFolder *)pComFolder;
(*ppFolder)->AddRef();
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Cleanup
SafeRelease(pFolder);
SafeRelease(pComFolder);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::CreateFolder
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::CreateFolder(FOLDERID dwParentId, LPCSTR pszName,
DWORD dwReserved, LPFOLDERID pdwFolderId)
{
// Locals
HRESULT hr=S_OK;
FOLDERINFO Folder;
// Stack
TraceCall("CStoreNamespace::CreateFolder");
// Invalid Arg
if (FOLDERID_INVALID == dwParentId || NULL == pszName || 0 != dwReserved || NULL == pdwFolderId)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Adjust the Parent
if (dwParentId == FOLDERID_ROOT)
dwParentId = FOLDERID_LOCAL_STORE;
// Init
*pdwFolderId = FOLDERID_INVALID;
// Thread Safety
EnterCriticalSection(&m_cs);
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// Setup a Folder Info
ZeroMemory(&Folder, sizeof(FOLDERINFO));
Folder.idParent = dwParentId;
Folder.pszName = (LPSTR)pszName;
Folder.dwFlags = FOLDER_SUBSCRIBED;
// Create a folder
IF_FAILEXIT(hr = g_pStore->CreateFolder(NOFLAGS, &Folder, (IStoreCallback *)this));
// Return the Id
*pdwFolderId = Folder.idFolder;
// Sucess
hr = S_OK;
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::RenameFolder
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::RenameFolder(FOLDERID dwFolderId, DWORD dwReserved, LPCSTR pszNewName)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("CStoreNamespace::RenameFolder");
// Invalid Arg
if (FOLDERID_INVALID == dwFolderId || 0 != dwReserved || NULL == pszNewName)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// Create a folder
IF_FAILEXIT(hr = g_pStore->RenameFolder(dwFolderId, pszNewName, NOFLAGS, (IStoreCallback *)this));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::MoveFolder
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::MoveFolder(FOLDERID dwFolderId, FOLDERID dwParentId, DWORD dwReserved)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("CStoreNamespace::MoveFolder");
// Invalid Arg
if (FOLDERID_INVALID == dwFolderId || FOLDERID_INVALID == dwParentId || 0 != dwReserved)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Adjust the Parent
if (dwParentId == FOLDERID_ROOT)
dwParentId = FOLDERID_LOCAL_STORE;
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// Move the folder
IF_FAILEXIT(hr = g_pStore->MoveFolder(dwFolderId, dwParentId, NOFLAGS, (IStoreCallback *)this));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::DeleteFolder
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::DeleteFolder(FOLDERID dwFolderId, DWORD dwReserved)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("CStoreNamespace::DeleteFolder");
// Invalid Arg
if (FOLDERID_INVALID == dwFolderId)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// Delete the folder
IF_FAILEXIT(hr = g_pStore->DeleteFolder(dwFolderId, DELETE_FOLDER_RECURSIVE, (IStoreCallback *)this));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::GetFolderProps
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::GetFolderProps(FOLDERID dwFolderId, DWORD dwReserved,
LPFOLDERPROPS pProps)
{
// Locals
HRESULT hr=S_OK;
FOLDERINFO Folder={0};
// Stack
TraceCall("CStoreNamespace::GetFolderProps");
// Invalid Arg
if (FOLDERID_INVALID == dwFolderId || 0 != dwReserved || NULL == pProps)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Adjust the Parent
if (dwFolderId == FOLDERID_ROOT)
dwFolderId = FOLDERID_LOCAL_STORE;
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// Save the structure size
IF_FAILEXIT(hr = g_pStore->GetFolderInfo(dwFolderId, &Folder));
// FolderInfoToProps
IF_FAILEXIT(hr = FldInfoToFolderProps(&Folder, pProps));
exit:
// Cleanup
g_pStore->FreeRecord(&Folder);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::CopyMoveMessages
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::CopyMoveMessages(IStoreFolder *pSource, IStoreFolder *pDest,
LPMESSAGEIDLIST pMsgIdList, DWORD dwFlags, DWORD dwFlagsRemove,IProgressNotify *pProgress)
{
// Locals
HRESULT hr=S_OK;
ADJUSTFLAGS AdjustFlags;
DWORD dwArfRemoveFlags;
CStoreFolder *pComSource=NULL;
CStoreFolder *pComDest=NULL;
IMessageFolder *pActSource=NULL;
IMessageFolder *pActDest=NULL;
// Stack
TraceCall("CStoreNamespace::CopyMoveMessages");
// Invalid Arg
if (NULL == pSource || NULL == pDest || NULL == pMsgIdList)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// Get Actual Soruce Local Store Folder
IF_FAILEXIT(hr = pSource->QueryInterface(IID_CStoreFolder, (LPVOID *)&pComSource));
IF_FAILEXIT(hr = pComSource->GetMessageFolder(&pActSource));
// Get Actual Destination Local Store Folder
IF_FAILEXIT(hr = pDest->QueryInterface(IID_CStoreFolder, (LPVOID *)&pComDest));
IF_FAILEXIT(hr = pComDest->GetMessageFolder(&pActDest));
// Convert dwFlagsRemove to ARF Flags...
dwArfRemoveFlags = DwConvertMSGtoARF(dwFlagsRemove);
// Adjust Flags
AdjustFlags.dwAdd = 0;
AdjustFlags.dwRemove = dwArfRemoveFlags;
// Do the Copy or Move
IF_FAILEXIT(hr = pActSource->CopyMessages(pActDest, dwFlags, pMsgIdList, &AdjustFlags, NULL, (IStoreCallback *)this));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Cleanup
SafeRelease(pComSource);
SafeRelease(pComDest);
SafeRelease(pActSource);
SafeRelease(pActDest);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::RegisterNotification
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::RegisterNotification(DWORD dwReserved, HWND hwnd)
{
// Locals
HRESULT hr=S_OK;
DWORD i;
BOOL fFoundEmpty=FALSE;
// Stack
TraceCall("CStoreNamespace::RegisterNotification");
// Invalid Arg
if (0 != dwReserved || NULL == hwnd || FALSE == IsWindow(hwnd))
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// Try to Find an Empty Spot in m_prghwndNotify
for (i=0; i<m_cNotify; i++)
{
// Empty
if (NULL == m_prghwndNotify[i])
{
// Use It
m_prghwndNotify[i] = hwnd;
// Found Empty
fFoundEmpty = TRUE;
// Done
break;
}
}
// Didn't Find an Empty slot ?
if (FALSE == fFoundEmpty)
{
// Add hwnd into the Array
IF_FAILEXIT(hr = HrRealloc((LPVOID *)&m_prghwndNotify, (m_cNotify + 1) * sizeof(HWND)));
// Store the hwnd
m_prghwndNotify[m_cNotify] = hwnd;
// Increment Count
m_cNotify++;
}
// Am I registered yet?
if (FALSE == m_fRegistered)
{
// Register
IF_FAILEXIT(hr = g_pStore->RegisterNotify(IINDEX_SUBSCRIBED, REGISTER_NOTIFY_NOADDREF, 0, (IDatabaseNotify *)this));
// We are Registered
m_fRegistered = TRUE;
}
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::UnregisterNotification
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::UnregisterNotification(DWORD dwReserved, HWND hwnd)
{
// Locals
HRESULT hr=S_OK;
DWORD i;
// Stack
TraceCall("CStoreNamespace::UnregisterNotification");
// Invalid Arg
if (0 != dwReserved || NULL == hwnd || FALSE == IsWindow(hwnd))
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// Try to Find an Empty Spot in m_prghwndNotify
for (i=0; i<m_cNotify; i++)
{
// Empty
if (hwnd == m_prghwndNotify[i])
{
// Use It
m_prghwndNotify[i] = NULL;
// Done
break;
}
}
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::OnNotify
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::OnTransaction(HTRANSACTION hTransaction,
DWORD_PTR dwCookie, IDatabase *pDB)
{
// Locals
HRESULT hr=S_OK;
DWORD iNotify;
FOLDERINFO Folder1={0};
FOLDERINFO Folder2={0};
ORDINALLIST Ordinals;
TRANSACTIONTYPE tyTransaction;
FOLDERNOTIFYEX SendBase;
INDEXORDINAL iIndex;
LPFOLDERNOTIFYEX pSend=NULL;
// Trace
TraceCall("CStoreNamespace::OnNotify");
// Thread Safety
EnterCriticalSection(&m_cs);
// Loop through info structures
while (hTransaction)
{
// Get Transact
IF_FAILEXIT(hr = pDB->GetTransaction(&hTransaction, &tyTransaction, &Folder1, &Folder2, &iIndex, &Ordinals));
// Only send notifications about local folders
if (Folder1.tyFolder == FOLDER_LOCAL)
{
// Zero
ZeroMemory(&SendBase, sizeof(FOLDERNOTIFYEX));
// TRANSACTION_INSERT
if (TRANSACTION_INSERT == tyTransaction)
{
SendBase.type = NEW_FOLDER;
SendBase.idFolderNew = Folder1.idFolder;
}
// TRANSACTION_UPDATE
else if (TRANSACTION_UPDATE == tyTransaction)
{
// Set Old and New
SendBase.idFolderOld = Folder1.idFolder;
SendBase.idFolderNew = Folder2.idFolder;
// Was this a rename
if (lstrcmp(Folder1.pszName, Folder2.pszName) != 0)
SendBase.type = RENAME_FOLDER;
// Move
else if (Folder1.idParent != Folder2.idParent)
SendBase.type = MOVE_FOLDER;
// Unread Change
else if (Folder1.cUnread != Folder2.cUnread)
SendBase.type = UNREAD_CHANGE;
// Flag Change
else if (Folder1.dwFlags != Folder2.dwFlags)
SendBase.type = UPDATEFLAG_CHANGE;
// Otherwise, generic catch all
else
SendBase.type = FOLDER_PROPS_CHANGED;
}
// TRANSACTION_DELETE
else if (TRANSACTION_DELETE == tyTransaction)
{
SendBase.type = DELETE_FOLDER;
SendBase.idFolderNew = Folder1.idFolder;
}
// Loop through the Notifications
for (iNotify=0; iNotify<m_cNotify; iNotify++)
{
// Do we have a window /
if (m_prghwndNotify[iNotify])
{
// Is a valid window ?
if (IsWindow(m_prghwndNotify[iNotify]))
{
// Allocate a FolderNotifyEx
IF_NULLEXIT(pSend = (LPFOLDERNOTIFYEX)g_pMalloc->Alloc(sizeof(FOLDERNOTIFYEX)));
// Copy the Base
CopyMemory(pSend, &SendBase, sizeof(FOLDERNOTIFYEX));
// Send It
SendMessage(m_prghwndNotify[iNotify], WM_FOLDERNOTIFY, 0, (LPARAM)pSend);
// Don't Free It
pSend = NULL;
}
// Don't try this window again
else
m_prghwndNotify[iNotify] = NULL;
}
}
}
}
exit:
// Cleanup
SafeMemFree(pSend);
// Free Records
g_pStore->FreeRecord(&Folder1);
g_pStore->FreeRecord(&Folder2);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(S_OK);
}
//--------------------------------------------------------------------------
// CStoreNamespace::CompactAll (1 = Fail with no UI)
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::CompactAll(DWORD dwReserved)
{
// Locals
HRESULT hr=S_OK;
DWORD dwRecurse=RECURSE_ONLYSUBSCRIBED | RECURSE_SUBFOLDERS;
// Stack
TraceCall("CStoreNamespace::UnregisterNotification");
// Invalid Arg
if (0 != dwReserved && 1 != dwReserved)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// No UI
if (1 == dwReserved)
FLAGSET(dwRecurse, RECURSE_NOUI);
// Do the compaction
IF_FAILEXIT(hr = CompactFolders(NULL, dwRecurse, FOLDERID_LOCAL_STORE));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::GetFirstSubFolder
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::GetFirstSubFolder(FOLDERID dwFolderId,
LPFOLDERPROPS pProps, LPHENUMSTORE phEnum)
{
// Locals
HRESULT hr=S_OK;
FOLDERINFO Folder={0};
IEnumerateFolders *pEnum=NULL;
// Stack
TraceCall("CStoreNamespace::GetFirstSubFolder");
// Invalid Arg
if (NULL == pProps || NULL == phEnum)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// INit
*phEnum = NULL;
// Thread Safety
EnterCriticalSection(&m_cs);
// Adjust the Parent
if (dwFolderId == FOLDERID_ROOT)
dwFolderId = FOLDERID_LOCAL_STORE;
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// Create Enumerator
IF_FAILEXIT(hr = g_pStore->EnumChildren(dwFolderId, TRUE, &pEnum));
// Pluck off the first item
IF_FAILEXIT(hr = pEnum->Next(1, &Folder, NULL));
// Done ?
if (S_FALSE == hr)
goto exit;
// Copy Folder Properties
IF_FAILEXIT(hr = FldInfoToFolderProps(&Folder, pProps));
// Set return
*phEnum = (HENUMSTORE)pEnum;
// Don't Free
pEnum = NULL;
exit:
// Failed Cleanup
g_pStore->FreeRecord(&Folder);
SafeRelease(pEnum);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::GetNextSubFolder
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::GetNextSubFolder(HENUMSTORE hEnum, LPFOLDERPROPS pProps)
{
// Locals
HRESULT hr=S_OK;
FOLDERINFO Folder={0};
IEnumerateFolders *pEnum=(IEnumerateFolders *)hEnum;
// Stack
TraceCall("CStoreNamespace::GetNextSubFolder");
// Invalid Arg
if (NULL == hEnum || INVALID_HANDLE_VALUE_16 == hEnum || NULL == pProps)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// Pluck off the next item
IF_FAILEXIT(hr = pEnum->Next(1, &Folder, NULL));
// Done ?
if (S_FALSE == hr)
goto exit;
// Copy Folder Properties
IF_FAILEXIT(hr = FldInfoToFolderProps(&Folder, pProps));
exit:
// Cleanup
g_pStore->FreeRecord(&Folder);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreNamespace::GetSubFolderClose
//--------------------------------------------------------------------------
STDMETHODIMP CStoreNamespace::GetSubFolderClose(HENUMSTORE hEnum)
{
// Locals
HRESULT hr=S_OK;
IEnumerateFolders *pEnum=(IEnumerateFolders *)hEnum;
// Stack
TraceCall("CStoreNamespace::GetSubFolderClose");
// Invalid Arg
if (NULL == hEnum || INVALID_HANDLE_VALUE_16 == hEnum)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Not initialized
if (NULL == m_hInitRef)
{
hr = TraceResult(MSOEAPI_E_STORE_INITIALIZE);
goto exit;
}
// Renum pEnum
SafeRelease(pEnum);
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::CStoreFolder
//--------------------------------------------------------------------------
CStoreFolder::CStoreFolder(IMessageFolder *pFolder, CStoreNamespace *pNamespace)
: m_pFolder(pFolder), m_pNamespace(pNamespace)
{
TraceCall("CStoreFolder::CStoreFolder");
Assert(m_pNamespace && m_pFolder);
g_pInstance->DllAddRef();
m_cRef = 1;
m_hwndNotify = NULL;
m_pFolder->AddRef();
m_pNamespace->AddRef();
m_pFolder->GetFolderId(&m_idFolder);
InitializeCriticalSection(&m_cs);
}
//--------------------------------------------------------------------------
// CStoreFolder::CStoreFolder
//--------------------------------------------------------------------------
CStoreFolder::~CStoreFolder(void)
{
TraceCall("CStoreFolder::~CStoreFolder");
SafeRelease(m_pFolder);
SafeRelease(m_pNamespace);
DeleteCriticalSection(&m_cs);
g_pInstance->DllRelease();
}
//--------------------------------------------------------------------------
// CStoreFolder::QueryInterface
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::QueryInterface(REFIID riid, LPVOID *ppv)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("CStoreNamespace::QueryInterface");
// Find IID
if (IID_IUnknown == riid)
*ppv = (IUnknown *)(IStoreFolder *)this;
else if (IID_IStoreFolder == riid)
*ppv = (IStoreFolder *)this;
else if (IID_CStoreFolder == riid)
*ppv = (CStoreFolder *)this;
else if (IID_IStoreCallback == riid)
*ppv = (IStoreCallback *)this;
else if (IID_IDatabaseNotify == riid)
*ppv = (IDatabaseNotify *)this;
else
{
*ppv = NULL;
hr = TraceResult(E_NOINTERFACE);
goto exit;
}
// AddRef It
((IUnknown *)*ppv)->AddRef();
exit:
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::AddRef
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CStoreFolder::AddRef(void)
{
TraceCall("CStoreFolder::AddRef");
return InterlockedIncrement(&m_cRef);
}
//--------------------------------------------------------------------------
// CStoreFolder::Release
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CStoreFolder::Release(void)
{
TraceCall("CStoreFolder::Release");
LONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef)
delete this;
return (ULONG)cRef;
}
//--------------------------------------------------------------------------
// CStoreFolder::GetFolderProps
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::GetFolderProps(DWORD dwReserved, LPFOLDERPROPS pProps)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("CStoreFolder::GetFolderProps");
// Invalid Arg
if (0 != dwReserved || NULL == pProps)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// Call through namespace
IF_FAILEXIT(hr = m_pNamespace->GetFolderProps(m_idFolder, 0, pProps));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::DeleteMessages
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::DeleteMessages(LPMESSAGEIDLIST pMsgIdList, DWORD dwReserved,
IProgressNotify *pProgress)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("CStoreFolder::DeleteMessages");
// Invalid Arg
if (NULL == pMsgIdList || NULL == pMsgIdList->prgidMsg || 0 != dwReserved)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// Delete me some messages
IF_FAILEXIT(hr = m_pFolder->DeleteMessages(DELETE_MESSAGE_NOPROMPT, pMsgIdList, NULL, (IStoreCallback *)this));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::SetLanguage
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::SetLanguage(DWORD dwLanguage, DWORD dwReserved, LPMESSAGEIDLIST pMsgIdList)
{
// Locals
HRESULT hr=S_OK;
MESSAGEINFO MsgInfo={0};
ULONG i;
// Stack
TraceCall("CStoreFolder::SetLanguage");
// Invalid Arg
if (0 != dwReserved || NULL == pMsgIdList || NULL == pMsgIdList->prgidMsg)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// Loop through the message ids
for (i=0; i<pMsgIdList->cMsgs; i++)
{
// Initialize MsgInfo with the Id
MsgInfo.idMessage = pMsgIdList->prgidMsg[i];
// Find the Row
IF_FAILEXIT(hr = m_pFolder->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &MsgInfo, NULL));
// If Not found
if (DB_S_FOUND == hr)
{
// Return the Language
MsgInfo.wLanguage = (WORD)dwLanguage;
// Update the Record
IF_FAILEXIT(hr = m_pFolder->UpdateRecord(&MsgInfo));
// Free It
m_pFolder->FreeRecord(&MsgInfo);
}
}
exit:
// Cleanup
m_pFolder->FreeRecord(&MsgInfo);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::MarkMessagesAsRead
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::MarkMessagesAsRead(BOOL fRead, DWORD dwReserved, LPMESSAGEIDLIST pMsgIdList)
{
// Locals
HRESULT hr=S_OK;
ADJUSTFLAGS AdjustFlags={0};
// Stack
TraceCall("CStoreFolder::MarkMessagesAsRead");
// Invalid Arg
if (0 != dwReserved || NULL == pMsgIdList || NULL == pMsgIdList->prgidMsg)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// Setup AdjustFlags
if (fRead)
AdjustFlags.dwAdd = ARF_READ;
else
AdjustFlags.dwRemove = ARF_READ;
// Mark messages as read
IF_FAILEXIT(hr = m_pFolder->SetMessageFlags(pMsgIdList, &AdjustFlags, NULL, (IStoreCallback *)this));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::SetFlags
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::SetFlags(LPMESSAGEIDLIST pMsgIdList, DWORD dwState,
DWORD dwStatemask, LPDWORD prgdwNewFlags)
{
// Locals
HRESULT hr=S_OK;
ADJUSTFLAGS AdjustFlags={0};
DWORD dwArfState=DwConvertMSGtoARF(dwState);
DWORD dwArfStateMask=DwConvertMSGtoARF(dwStatemask);
MESSAGEINFO MsgInfo={0};
// Stack
TraceCall("CStoreFolder::SetFlags");
// Invalid Arg
if (NULL == pMsgIdList || NULL == pMsgIdList->prgidMsg)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// Setup Adjust Flags
AdjustFlags.dwAdd = (dwArfState & dwArfStateMask);
// Mark messages as read
IF_FAILEXIT(hr = m_pFolder->SetMessageFlags(pMsgIdList, &AdjustFlags, NULL, (IStoreCallback *)this));
// Convert prgdwNewFlags to MSG_xxx Flags
if (prgdwNewFlags)
{
// Loop through the message ids
for (ULONG i=0; i<pMsgIdList->cMsgs; i++)
{
// Initialize MsgInfo with the Id
MsgInfo.idMessage = pMsgIdList->prgidMsg[i];
// Find the Row
IF_FAILEXIT(hr = m_pFolder->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &MsgInfo, NULL));
// If Not found
if (DB_S_FOUND == hr)
{
// Return the Flags
prgdwNewFlags[i] = DwConvertARFtoMSG(MsgInfo.dwFlags);
// Free It
m_pFolder->FreeRecord(&MsgInfo);
}
}
}
exit:
// Cleanup
m_pFolder->FreeRecord(&MsgInfo);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::OpenMessage
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::OpenMessage(MESSAGEID dwMessageId, REFIID riid, LPVOID *ppvObject)
{
// Locals
HRESULT hr=S_OK;
MESSAGEINFO MsgInfo={0};
IStream *pStream=NULL;
IMimeMessage *pMessage=NULL;
// Stack
TraceCall("CStoreFolder::OpenMessage");
// Invalid Arg
if (MESSAGEID_INVALID == dwMessageId || NULL == ppvObject || (IID_IStream != riid && IID_IMimeMessage != riid))
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Init
*ppvObject = NULL;
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// Streamout
// [PaulHi] 6/11/99 Raid 69317
// This is a security hole. We can't export a public method that allows anyone
// to open and read a secure message.
IF_FAILEXIT(hr = m_pFolder->OpenMessage(dwMessageId, OPEN_MESSAGE_SECURE/*NOFLAGS*/, &pMessage, (IStoreCallback *)this));
// User just wants a stream out...
if (IID_IStream == riid)
{
// Streamout
IF_FAILEXIT(hr = pMessage->GetMessageSource(&pStream, NOFLAGS));
// Set Return
*ppvObject = pStream;
// AddRef It
pStream->AddRef();
}
// Otherwise, user wants an IMimeMessage
else
{
// Set Return
*ppvObject = pMessage;
// AddRef It
pMessage->AddRef();
}
exit:
// Cleanup
m_pFolder->FreeRecord(&MsgInfo);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Cleanup
SafeRelease(pStream);
SafeRelease(pMessage);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::SaveMessage
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::SaveMessage(REFIID riid, LPVOID pvObject, DWORD dwMsgFlags,
LPMESSAGEID pdwMessageId)
{
// Locals
HRESULT hr=S_OK;
IMimeMessage *pMessage=NULL;
IStream *pStream=NULL;
IStream *pStmSource=NULL;
MESSAGEID dwMessageId=MESSAGEID_INVALID;
// Stack
TraceCall("CStoreFolder::SaveMessage");
// Invalid Arg
if ((IID_IStream != riid && IID_IMimeMessage != riid) || NULL == pvObject)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// Creates me a stream to put the message in...
IF_FAILEXIT(hr = CreateStream(NULL, 0, &pStream, &dwMessageId));
// If they gave me a stream, I need to create an IMimeMessage
if (IID_IStream == riid)
{
// Cast to a IStream
pStmSource = (IStream *)pvObject;
// AddRef
pStmSource->AddRef();
}
// Otherwise, the user gave me a message
else
{
// Cast to a message
pMessage = (IMimeMessage *)pvObject;
// AddRef since we release in cleanup
IF_FAILEXIT(hr = pMessage->GetMessageSource(&pStmSource, 0));
}
// Copy pvObject to pStream
IF_FAILEXIT(hr = HrCopyStream(pStmSource, pStream, NULL));
// Commit the stream
IF_FAILEXIT(hr = pStream->Commit(STGC_DEFAULT));
// Creates me a stream to put the message in...
IF_FAILEXIT(hr = CommitStream(NULL, 0, dwMsgFlags, pStream, dwMessageId, pMessage));
// Return the message id
if (pdwMessageId)
*pdwMessageId = dwMessageId;
// We commited
dwMessageId = MESSAGEID_INVALID;
SafeRelease(pStream);
exit:
// If we didn't commit
if (FAILED(hr) && MESSAGEID_INVALID != dwMessageId && pStream)
CommitStream(NULL, COMMITSTREAM_REVERT, 0, pStream, dwMessageId, NULL);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Cleanup
SafeRelease(pStream);
SafeRelease(pStmSource);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::CreateStream
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::CreateStream(HBATCHLOCK hBatchLock, DWORD dwReserved,
IStream **ppStream, LPMESSAGEID pdwMessageId)
{
// Locals
HRESULT hr=S_OK;
FILEADDRESS faStream;
// Stack
TraceCall("CStoreFolder::CreateStream");
// Invalid Arg
if (0 != dwReserved || NULL == ppStream || NULL == pdwMessageId)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Init
*ppStream = NULL;
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// Generate a message Id
IF_FAILEXIT(hr = m_pFolder->GenerateId((LPDWORD)pdwMessageId));
// Create a Stream
IF_FAILEXIT(hr = m_pFolder->CreateStream(&faStream));
// Open the Stream
IF_FAILEXIT(hr = m_pFolder->OpenStream(ACCESS_WRITE, faStream, ppStream));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::CommitStream
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::CommitStream(HBATCHLOCK hBatchLock, DWORD dwFlags,
DWORD dwMsgFlags, IStream *pStream, MESSAGEID dwMessageId,
IMimeMessage *pMessage)
{
// Locals
HRESULT hr=S_OK;
DWORD dwImfFlags;
DWORD dwArfFlags=DwConvertMSGtoARF(dwMsgFlags);
IDatabaseStream *pDBStream=NULL;
// Stack
TraceCall("CStoreFolder::CommitStream");
// Validate
Assert(hBatchLock == (HBATCHLOCK)this);
// Invalid Arg
if (NULL == pStream || MESSAGEID_INVALID == dwMessageId)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// Determine if this is an ObjectDB Stream
IF_FAILEXIT(hr = pStream->QueryInterface(IID_IDatabaseStream, (LPVOID *)&pDBStream));
// If no stream, this must be a failure
if (ISFLAGSET(dwFlags, COMMITSTREAM_REVERT))
{
// Locals
FILEADDRESS faStream;
// Get the Address
IF_FAILEXIT(hr = pDBStream->GetFileAddress(&faStream));
// Delete the Stream
IF_FAILEXIT(hr = m_pFolder->DeleteStream(faStream));
// Done
goto exit;
}
// Convert the Stream to a REad lock
IF_FAILEXIT(hr = m_pFolder->ChangeStreamLock(pDBStream, ACCESS_READ));
// If the user did not passin an IMimeMessage
if (NULL == pMessage)
{
// Create a message object
IF_FAILEXIT(hr = MimeOleCreateMessage(NULL, &pMessage));
// Lets rewind the stream
IF_FAILEXIT(hr = HrRewindStream(pStream));
// Load the message object with the stream
IF_FAILEXIT(hr = pMessage->Load(pStream));
}
else
pMessage->AddRef();
// Get message flags
pMessage->GetFlags(&dwImfFlags);
if (ISFLAGSET(dwImfFlags, IMF_VOICEMAIL))
FLAGSET(dwArfFlags, ARF_VOICEMAIL);
// Insert the message
IF_FAILEXIT(hr = m_pFolder->SaveMessage(&dwMessageId, NOFLAGS, dwArfFlags, pDBStream, pMessage, (IStoreCallback *)this));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Cleanup
SafeRelease(pMessage);
SafeRelease(pDBStream);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::BatchLock
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::BatchLock(DWORD dwReserved, LPHBATCHLOCK phBatchLock)
{
// Just a simple test
*phBatchLock = (HBATCHLOCK)this;
// Done
return(S_OK);
}
//--------------------------------------------------------------------------
// CStoreFolder::BatchFlush
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::BatchFlush(DWORD dwReserved, HBATCHLOCK hBatchLock)
{
// Just a simple test
Assert(hBatchLock == (HBATCHLOCK)this);
// Done
return(S_OK);
}
//--------------------------------------------------------------------------
// CStoreFolder::BatchUnlock
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::BatchUnlock(DWORD dwReserved, HBATCHLOCK hBatchLock)
{
// Just a simple test
Assert(hBatchLock == (HBATCHLOCK)this);
// Done
return(S_OK);
}
//--------------------------------------------------------------------------
// CStoreFolder::RegisterNotification
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::RegisterNotification(DWORD dwReserved, HWND hwnd)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("CStoreFolder::RegisterNotification");
// Invalid Arg
if (0 != dwReserved || NULL == hwnd || FALSE == IsWindow(hwnd))
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// Somebody is already registered
if (m_hwndNotify)
{
hr = TraceResult(E_FAIL);
goto exit;
}
// Register for notify on the folder
IF_FAILEXIT(hr = m_pFolder->RegisterNotify(IINDEX_PRIMARY, REGISTER_NOTIFY_NOADDREF, NOTIFY_FOLDER, (IDatabaseNotify *)this));
// Register for notify on the store
IF_FAILEXIT(hr = g_pStore->RegisterNotify(IINDEX_SUBSCRIBED, REGISTER_NOTIFY_NOADDREF, NOTIFY_STORE, (IDatabaseNotify *)this));
// Hold Onto hwnd
m_hwndNotify = hwnd;
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::UnregisterNotification
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::UnregisterNotification(DWORD dwReserved, HWND hwnd)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("CStoreFolder::UnregisterNotification");
// Invalid Arg
if (0 != dwReserved || NULL == hwnd || FALSE == IsWindow(hwnd))
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// Nobody is registered
if (NULL == m_hwndNotify)
{
hr = TraceResult(E_FAIL);
goto exit;
}
// Kill It
m_hwndNotify = NULL;
// Register for notify
IF_FAILEXIT(hr = g_pStore->UnregisterNotify((IDatabaseNotify *)this));
// Register for notify
IF_FAILEXIT(hr = m_pFolder->UnregisterNotify((IDatabaseNotify *)this));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::Compact
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::Compact(DWORD dwReserved)
{
// Locals
HRESULT hr=S_OK;
DWORD dwRecurse=RECURSE_ONLYSUBSCRIBED | RECURSE_INCLUDECURRENT;
// Stack
TraceCall("CStoreFolder::Compact");
// Invalid Arg
if (0 != dwReserved && 1 != dwReserved)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// No UI
if (1 == dwReserved)
FLAGSET(dwRecurse, RECURSE_NOUI);
// Compact
IF_FAILEXIT(hr = CompactFolders(NULL, dwRecurse, m_idFolder));
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::GetMessageProps
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::GetMessageProps(MESSAGEID dwMessageId, DWORD dwFlags, LPMESSAGEPROPS pProps)
{
// Locals
HRESULT hr=S_OK;
MESSAGEINFO MsgInfo={0};
// Stack
TraceCall("CStoreFolder::GetMessageProps");
// Invalid Arg
if (MESSAGEID_INVALID == dwMessageId || NULL == pProps)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// Set Id
MsgInfo.idMessage = dwMessageId;
// Find dwMessageId
IF_FAILEXIT(hr = m_pFolder->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &MsgInfo, NULL));
// Not Found
if (DB_S_NOTFOUND == hr)
{
hr = TraceResult(E_FAIL);
goto exit;
}
// Copy message header to message props
IF_FAILEXIT(hr = MsgInfoToMessageProps(ISFLAGSET(dwFlags, MSGPROPS_FAST), &MsgInfo, pProps));
exit:
// Cleanup
m_pFolder->FreeRecord(&MsgInfo);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::FreeMessageProps
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::FreeMessageProps(LPMESSAGEPROPS pProps)
{
// Locals
DWORD cbSize;
MESSAGEINFO MsgInfo;
// Stack
TraceCall("CStoreFolder::FreeMessageProps");
// Invalid Arg
if (NULL == pProps)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Bad version
if (sizeof(MESSAGEPROPS) != pProps->cbSize)
{
AssertSz(FALSE, "Invalid - un-supported version.");
return TraceResult(MSOEAPI_E_INVALID_STRUCT_SIZE);
}
// Save Size
cbSize = pProps->cbSize;
// Free the elements
if (pProps->dwReserved && m_pFolder)
{
// Store the Pointer
MsgInfo.pAllocated = (LPBYTE)pProps->dwReserved;
// Free It
m_pFolder->FreeRecord(&MsgInfo);
}
// Free the STream
SafeRelease(pProps->pStmOffsetTable);
// ZeroInit
ZeroMemory(pProps, sizeof(MESSAGEPROPS));
pProps->cbSize = cbSize;
// Done
return(S_OK);
}
//--------------------------------------------------------------------------
// CStoreFolder::GetMessageFolder
//--------------------------------------------------------------------------
HRESULT CStoreFolder::GetMessageFolder(IMessageFolder **ppFolder)
{
// Stack
TraceCall("CStoreFolder::GetMessageFolder");
// Invalid Arg
Assert(ppFolder)
// Thread Safety
EnterCriticalSection(&m_cs);
// Retrun
*ppFolder = m_pFolder;
(*ppFolder)->AddRef();
// Done
return(S_OK);
}
//--------------------------------------------------------------------------
// CStoreFolder::GetFirstMessage
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::GetFirstMessage(DWORD dwFlags, DWORD dwMsgFlags, MESSAGEID dwMsgIdFirst,
LPMESSAGEPROPS pProps, LPHENUMSTORE phEnum)
{
// Locals
HRESULT hr=S_OK;
DWORD dwArfFlags=DwConvertMSGtoARF(dwMsgFlags);
HROWSET hRowset=NULL;
MESSAGEINFO MsgInfo={0};
// Stack
TraceCall("CStoreFolder::GetFirstMessage");
// Invalid Arg
if (NULL == pProps || NULL == phEnum)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// Create a Rowset
IF_FAILEXIT(hr = m_pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset));
// Loop..
IF_FAILEXIT(hr = m_pFolder->QueryRowset(hRowset, 1, (LPVOID *)&MsgInfo, NULL));
// If Nothing found
if (S_FALSE == hr)
{
hr = TraceResult(E_FAIL);
goto exit;
}
// MsgInfoToMessageProps
IF_FAILEXIT(hr = MsgInfoToMessageProps(ISFLAGSET(dwFlags, MSGPROPS_FAST), &MsgInfo, pProps));
// Return the Handle
*phEnum = (HENUMSTORE)hRowset;
exit:
// Failure
if (FAILED(hr))
m_pFolder->CloseRowset(&hRowset);
// Cleanup
m_pFolder->FreeRecord(&MsgInfo);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::GetNextMessage
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::GetNextMessage(HENUMSTORE hEnum, DWORD dwFlags, LPMESSAGEPROPS pProps)
{
// Locals
HRESULT hr=S_OK;
HROWSET hRowset=(HROWSET)hEnum;
MESSAGEINFO MsgInfo={0};
// Stack
TraceCall("CStoreFolder::GetNextMessage");
// Invalid Arg
if (NULL == hEnum || INVALID_HANDLE_VALUE_16 == hEnum || NULL == pProps)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Thread Safety
EnterCriticalSection(&m_cs);
// Validate State
Assert(m_pNamespace && m_pFolder);
// Loop..
IF_FAILEXIT(hr = m_pFolder->QueryRowset(hRowset, 1, (LPVOID *)&MsgInfo, NULL));
// If Nothing found
if (S_FALSE == hr)
goto exit;
// MsgInfoToMessageProps
IF_FAILEXIT(hr = MsgInfoToMessageProps(ISFLAGSET(dwFlags, MSGPROPS_FAST), &MsgInfo, pProps));
exit:
// Cleanup
m_pFolder->FreeRecord(&MsgInfo);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CStoreFolder::GetMessageClose
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::GetMessageClose(HENUMSTORE hEnum)
{
// Locals
HROWSET hRowset=(HROWSET)hEnum;
// Invalid Arg
if (NULL == hEnum || INVALID_HANDLE_VALUE_16 == hEnum)
{
AssertSz(FALSE, "Invalid Arguments");
return TraceResult(E_INVALIDARG);
}
// Close the Rowset
m_pFolder->CloseRowset(&hRowset);
// Done
return(S_OK);
}
//--------------------------------------------------------------------------
// CStoreFolder::OnNotify
//--------------------------------------------------------------------------
STDMETHODIMP CStoreFolder::OnTransaction(HTRANSACTION hTransaction,
DWORD_PTR dwCookie, IDatabase *pDB)
{
// Locals
HRESULT hr=S_OK;
TRANSACTIONTYPE tyTransaction;
ORDINALLIST Ordinals;
MESSAGEINFO Message1={0};
MESSAGEINFO Message2={0};
FOLDERINFO Folder1={0};
FOLDERINFO Folder2={0};
UINT msg=0;
WPARAM wParam=0;
LPARAM lParam=0;
INDEXORDINAL iIndex;
// Trace
TraceCall("CStoreFolder::OnNotify");
// Thread Safety
EnterCriticalSection(&m_cs);
// Notify on the Folder
if (NOTIFY_FOLDER == dwCookie)
{
// Loop through the Notification Info
while (hTransaction)
{
// Get Transact Info
IF_FAILEXIT(hr = pDB->GetTransaction(&hTransaction, &tyTransaction, &Message1, &Message2, &iIndex, &Ordinals));
// TRANSACTION_INSERT
if (TRANSACTION_INSERT == tyTransaction)
{
msg = WM_NEWMSGS;
wParam = (WPARAM)Message1.idMessage;
}
// TRANSACTION_UPDATE
else if (TRANSACTION_UPDATE == tyTransaction)
{
// Unread State Change ?
if (ISFLAGSET(Message1.dwFlags, ARF_READ) != ISFLAGSET(Message2.dwFlags, ARF_READ))
{
// Set w and l param
wParam = (WPARAM)&Message2.idMessage;
lParam = 1;
// Marked as Read
if (ISFLAGSET(Message2.dwFlags, ARF_READ))
msg = WM_MARKEDASREAD;
else
msg = WM_MARKEDASUNREAD;
}
}
// TRANSACTION_DELETE
else if (TRANSACTION_DELETE == tyTransaction)
{
// Allocate a message id
LPMESSAGEID pidMessage = (LPMESSAGEID)g_pMalloc->Alloc(sizeof(MESSAGEID));
// If that worked
if (pidMessage)
{
msg = WM_DELETEMSGS;
*pidMessage = Message1.idMessage;
wParam = (WPARAM)pidMessage;
lParam = 1;
}
}
// Do we have a message?
if (IsWindow(m_hwndNotify))
{
// Send Delete Folder Notification
SendMessage(m_hwndNotify, msg, wParam, lParam);
}
}
}
// Otherwise, store notification
else
{
// Must be a store notification
Assert(NOTIFY_STORE == dwCookie);
// Loop through the Notification Info
while (hTransaction)
{
// Get Transact Info
IF_FAILEXIT(hr = pDB->GetTransaction(&hTransaction, &tyTransaction, &Folder1, &Folder2, &iIndex, &Ordinals));
// Only Reporting Delete folder Notifications
if (TRANSACTION_DELETE == tyTransaction)
{
// Send Delete Folder Notification
PostMessage(m_hwndNotify, WM_DELETEFOLDER, (WPARAM)Folder1.idFolder, 0);
}
}
}
exit:
// Cleanup
g_pStore->FreeRecord(&Folder1);
g_pStore->FreeRecord(&Folder2);
m_pFolder->FreeRecord(&Message1);
m_pFolder->FreeRecord(&Message2);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return(S_OK);
}