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

396 lines
10 KiB
C++

//--------------------------------------------------------------------------
// EnumFold.cpp
//--------------------------------------------------------------------------
#include "pch.hxx"
#include "enumfold.h"
//--------------------------------------------------------------------------
// CFOLDER_FETCH
//--------------------------------------------------------------------------
#define CFOLDER_FETCH_MIN 5
#define CFOLDER_FETCH_MID 30
#define CFOLDER_FETCH_MAX 200
//--------------------------------------------------------------------------
// CEnumerateFolders::CEnumerateFolders
//--------------------------------------------------------------------------
CEnumerateFolders::CEnumerateFolders(void)
{
TraceCall("CEnumerateFolders::CEnumerateFolders");
m_cRef = 1;
m_pDB = NULL;
m_fSubscribed = FALSE;
m_idParent = FOLDERID_INVALID;
m_pStream = NULL;
m_cFolders = 0;
m_iFolder = 0;
}
//--------------------------------------------------------------------------
// CEnumerateFolders::~CEnumerateFolders
//--------------------------------------------------------------------------
CEnumerateFolders::~CEnumerateFolders(void)
{
TraceCall("CEnumerateFolders::~CEnumerateFolders");
_FreeFolderArray();
SafeRelease(m_pDB);
}
//--------------------------------------------------------------------------
// CEnumerateFolders::QueryInterface
//--------------------------------------------------------------------------
STDMETHODIMP CEnumerateFolders::QueryInterface(REFIID riid, LPVOID *ppv)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("CEnumerateFolders::QueryInterface");
// Find IID
if (IID_IUnknown == riid)
*ppv = (IUnknown *)this;
else if (IID_IEnumerateFolders == riid)
*ppv = (IEnumerateFolders *)this;
else
{
*ppv = NULL;
hr = TraceResult(E_NOINTERFACE);
goto exit;
}
// AddRef It
((IUnknown *)*ppv)->AddRef();
exit:
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CEnumerateFolders::AddRef
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CEnumerateFolders::AddRef(void)
{
TraceCall("CEnumerateFolders::AddRef");
return InterlockedIncrement(&m_cRef);
}
//--------------------------------------------------------------------------
// CEnumerateFolders::Release
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CEnumerateFolders::Release(void)
{
TraceCall("CEnumerateFolders::Release");
LONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef)
delete this;
return (ULONG)cRef;
}
//--------------------------------------------------------------------------
// CEnumerateFolders::_FreeFolderArray
//--------------------------------------------------------------------------
HRESULT CEnumerateFolders::_FreeFolderArray(void)
{
// Locals
HRESULT hr=S_OK;
FOLDERINFO Folder;
DWORD cbRead;
DWORD cbSeek;
// Trace
TraceCall("CEnumerateFolders::_FreeFolderArray");
// If we have a stream
if (NULL == m_pStream)
return(S_OK);
// Seek to next folder that should be read
cbSeek = (m_iFolder * sizeof(FOLDERINFO));
// Seek
IF_FAILEXIT(hr = HrStreamSeekSet(m_pStream, cbSeek));
// Read Folder Infos
while (S_OK == m_pStream->Read(&Folder, sizeof(FOLDERINFO), &cbRead) && cbRead)
{
// Free Folder Info
m_pDB->FreeRecord(&Folder);
}
exit:
// Reset
m_cFolders = m_iFolder = 0;
// Free
SafeRelease(m_pStream);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CEnumerateFolders::Initialize
//--------------------------------------------------------------------------
HRESULT CEnumerateFolders::Initialize(IDatabase *pDB, BOOL fSubscribed,
FOLDERID idParent)
{
// Locals
HRESULT hr=S_OK;
ROWORDINAL iFirstRow;
HLOCK hLock=NULL;
HROWSET hRowset=NULL;
FOLDERINFO Child={0};
FOLDERINFO rgFolder[CFOLDER_FETCH_MAX];
DWORD cWanted=CFOLDER_FETCH_MIN;
DWORD cFetched=0;
DWORD i;
INDEXORDINAL iIndex;
// Trace
TraceCall("CEnumerateFolders::Initialize");
// Invalid Args
Assert(pDB);
// Release Current m_pDB
SafeRelease(m_pDB);
m_pDB = pDB;
m_pDB->AddRef();
// Unlock
IF_FAILEXIT(hr = pDB->Lock(&hLock));
// Free Folder Array
_FreeFolderArray();
// Save Subscribed
m_fSubscribed = fSubscribed;
// Subscribed Stuff
iIndex = (fSubscribed ? IINDEX_SUBSCRIBED : IINDEX_ALL);
// Save parent
m_idParent = idParent;
// Set idParent
Child.idParent = idParent;
// Locate where the first record with idParent
IF_FAILEXIT(hr = m_pDB->FindRecord(iIndex, 1, &Child, &iFirstRow));
// Not Found
if (DB_S_NOTFOUND == hr)
{
hr = S_OK;
goto exit;
}
// Create a Stream
IF_FAILEXIT(hr = MimeOleCreateVirtualStream(&m_pStream));
// Write the Folder....
IF_FAILEXIT(hr = m_pStream->Write(&Child, sizeof(FOLDERINFO), NULL));
// One Folder
m_cFolders++;
// Don't Free Child
Child.pAllocated = NULL;
// Create a Rowset
IF_FAILEXIT(hr = m_pDB->CreateRowset(iIndex, NOFLAGS, &hRowset));
// Seek the rowset to the first row
if (FAILED(m_pDB->SeekRowset(hRowset, SEEK_ROWSET_BEGIN, iFirstRow, NULL)))
{
hr = S_OK;
goto exit;
}
// Loop and fetch all folders...
while (SUCCEEDED(m_pDB->QueryRowset(hRowset, cWanted, (LPVOID *)rgFolder, &cFetched)) && cFetched > 0)
{
// Write the Folder....
IF_FAILEXIT(hr = m_pStream->Write(rgFolder, sizeof(FOLDERINFO) * cFetched, NULL));
// Loop through cFetched
for (i=0; i<cFetched; i++)
{
// Done ?
if (rgFolder[i].idParent != m_idParent)
goto exit;
// Increment Folder Count
m_cFolders++;
}
// Adjust cWanted for Perf.
if (cWanted < CFOLDER_FETCH_MID && m_cFolders >= CFOLDER_FETCH_MID)
cWanted = CFOLDER_FETCH_MID;
if (cWanted < CFOLDER_FETCH_MAX && m_cFolders >= CFOLDER_FETCH_MAX)
cWanted = CFOLDER_FETCH_MAX;
}
exit:
// Commit
if (m_pStream)
{
// Commit
m_pStream->Commit(STGC_DEFAULT);
// Rewind
HrRewindStream(m_pStream);
}
// Close the Rowset
m_pDB->FreeRecord(&Child);
// Close the Rowset
m_pDB->CloseRowset(&hRowset);
// Unlock
m_pDB->Unlock(&hLock);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CEnumerateFolders::Next
//--------------------------------------------------------------------------
STDMETHODIMP CEnumerateFolders::Next(ULONG cWanted, LPFOLDERINFO prgInfo, ULONG *pcFetched)
{
// Locals
HRESULT hr=S_OK;
DWORD cFetched=0;
DWORD cbRead;
// Trace
TraceCall("CEnumerateFolders::Next");
// Initialize
if (pcFetched)
*pcFetched = 0;
// Get some Records
while (cFetched < cWanted && m_iFolder < m_cFolders)
{
// Read a Folder
IF_FAILEXIT(hr = m_pStream->Read(&prgInfo[cFetched], sizeof(FOLDERINFO), &cbRead));
// Validate
Assert(sizeof(FOLDERINFO) == cbRead && prgInfo[cFetched].idParent == m_idParent);
// Increment m_iFolder
m_iFolder++;
// Increment iFetch
cFetched++;
}
// Initialize
if (pcFetched)
*pcFetched = cFetched;
exit:
// Done
return(cFetched == cWanted) ? S_OK : S_FALSE;
}
//--------------------------------------------------------------------------
// CEnumerateFolders::Skip
//--------------------------------------------------------------------------
STDMETHODIMP CEnumerateFolders::Skip(ULONG cItems)
{
// Locals
HRESULT hr=S_OK;
DWORD i;
FOLDERINFO Folder;
// Trace
TraceCall("CEnumerateFolders::Skip");
// Loop...
for (i=0; i<cItems; i++)
{
// Next
IF_FAILEXIT(hr = Next(1, &Folder, NULL));
// Done
if (S_OK != hr)
break;
}
exit:
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CEnumerateFolders::Reset
//--------------------------------------------------------------------------
STDMETHODIMP CEnumerateFolders::Reset(void)
{
// Locals
HRESULT hr=S_OK;
// Trace
TraceCall("CEnumerateFolders::Reset");
// Initialize MySelf
IF_FAILEXIT(hr = Initialize(m_pDB, m_fSubscribed, m_idParent));
exit:
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CEnumerateFolders::Clone
//--------------------------------------------------------------------------
STDMETHODIMP CEnumerateFolders::Clone(IEnumerateFolders **ppEnum)
{
// Locals
HRESULT hr=S_OK;
CEnumerateFolders *pEnum=NULL;
// Trace
TraceCall("CEnumerateFolders::Clone");
// Allocate a New Enumerator
IF_NULLEXIT(pEnum = new CEnumerateFolders);
// Initialzie
IF_FAILEXIT(hr = pEnum->Initialize(m_pDB, m_fSubscribed, m_idParent));
// Return It
*ppEnum = (IEnumerateFolders *)pEnum;
// Don't Release It
pEnum = NULL;
exit:
// Cleanup
SafeRelease(pEnum);
// Done
return(hr);
}
//--------------------------------------------------------------------------
// CEnumerateFolders::Release
//--------------------------------------------------------------------------
STDMETHODIMP CEnumerateFolders::Count(ULONG *pcItems)
{
// Trace
TraceCall("CEnumerateFolders::Next");
// Return Folder count
*pcItems = m_cFolders;
// Done
return(S_OK);
}