TVNODE.CPP

/////////////////////////////////////////////////////////////////////// 
//
// TVNODE.CPP
//
//
// Copyright 1986-1996 Microsoft Corporation. All Rights Reserved.
///////////////////////////////////////////////////////////////////////


#define STRICT
#include <windows.h>
#include <commctrl.h>
#include <mapix.h>
#include <mapiutil.h>
#include <mapidbg.h>
#include "lasterr.h"
#include "tvdlg.h"


LPSTR g_szNoFolderName = "<No Name>";

//
// CTVNode::CTVNode
//
CTVNode::CTVNode(LPSPropValue pval, ULONG cProps, LPMDB pmdb)
{
Assert(cProps == nhtProps);
Assert(pval);

m_pval = pval;

m_htiMe = NULL;

m_fKidsLoaded = FALSE;

m_pfld = NULL;

m_pNext = NULL;

m_pmdb = pmdb;
if(pmdb)
pmdb->AddRef();

}

//
// CTVNode::~CTVNode
//
CTVNode::~CTVNode()
{
MAPIFreeBuffer(m_pval);
UlRelease(m_pfld);
UlRelease(m_pmdb);
}


//
// CTVNode::HrExpand
//
// Put all kids of the given folder in the tree control
//
HRESULT CTVNode::HrExpand(CChsFldDlg * pCFDlg)
{
HRESULT hr;
LPMAPITABLE ptblHier = NULL;
LPSRowSet pRowSet = NULL;
UINT ind;

static SSortOrderSet sosName;

sosName.cSorts = 1;
sosName.cCategories = 0;
sosName.cExpanded = 0;
sosName.aSort[0].ulPropTag = PR_DISPLAY_NAME;
sosName.aSort[0].ulOrder = TABLE_SORT_ASCEND;


Assert(m_htiMe);

if(m_fKidsLoaded || !m_pval[iSubfldrs].Value.b)
return hrSuccess;

if(!m_pmdb)
{
// this node corresponds to the top level of a message store which has
// not been opend yet.
// m_pval[iEID] contains entry ID of the message store
//
hr = HrOpenMDB(pCFDlg);
if(FAILED(hr))
goto err;
}

Assert(m_pmdb);

if(!m_pfld)
{
hr = HrOpenFolder(pCFDlg);
if(FAILED(hr))
goto err;
}

Assert(m_pfld);

hr = m_pfld->GetHierarchyTable(MAPI_DEFERRED_ERRORS, &ptblHier);
if(HR_FAILED(hr))
{
pCFDlg->m_lsterr.HrSetLastError(hr, m_pfld);
pCFDlg->m_lsterr.ShowError(pCFDlg->hwDialog());

goto err;
}

hr = HrQueryAllRows(ptblHier, (LPSPropTagArray)&spthtProps, NULL, &sosName,
0, &pRowSet);
if(HR_FAILED(hr))
goto err;

if(0 == pRowSet->cRows)
{
m_pval[iSubfldrs].Value.b = FALSE;
goto err;
}

for(ind = 0; ind < pRowSet->cRows; ++ind)
{
LPSPropValue pval = pRowSet->aRow[ind].lpProps;

Assert(pRowSet->aRow[ind].cValues == nhtProps);
Assert(pval[iEID].ulPropTag == PR_ENTRYID);
Assert(pval[iDispName].ulPropTag == PR_DISPLAY_NAME);
Assert(pval[iSubfldrs].ulPropTag == PR_SUBFOLDERS);

LPTVNODE pNode = NULL;

hr = pCFDlg->HrCreateNode(pval, nhtProps, m_pmdb, &pNode);
if(hr)
goto err;

//this row will be freed in ~CTVNode
pRowSet->aRow[ind].cValues = 0;
pRowSet->aRow[ind].lpProps = NULL;

HTREEITEM hItem;

hItem = AddOneItem(m_htiMe, TVI_LAST, pCFDlg->IndClsdFld(),
pCFDlg->IndOpenFld(), pCFDlg->hwTreeCtl(), pNode,
pval[iSubfldrs].Value.b? 1: 0);
if(!hItem)
{
hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
goto err;
}

}

m_fKidsLoaded = TRUE;

err:
UlRelease(ptblHier);
FreeProws(pRowSet);

DebugTraceResult(CTVNode::HrExpand, hr);
return hr;
}

//
// CTVNode::HrOpenMDB
//
HRESULT CTVNode::HrOpenMDB(CChsFldDlg * pCFDlg)
{
HRESULT hr;
LPMDB pmdb = NULL;
LPSPropValue pvalIPM = NULL;
ULONG ulObjType;

Assert(m_pval[iEID].ulPropTag == PR_ENTRYID);

DebugTrace("ChsFld: Openning Msg Store: %s\n", GetName());

hr = pCFDlg->Session()->OpenMsgStore(0L, m_pval[iEID].Value.bin.cb,
(LPENTRYID)m_pval[iEID].Value.bin.lpb,
NULL, MAPI_BEST_ACCESS, &pmdb);
if(hr) //Display warning messages too
{
pCFDlg->m_lsterr.HrSetLastError(hr, pCFDlg->Session());
pCFDlg->m_lsterr.ShowError(pCFDlg->hwDialog());
}

if(HR_FAILED(hr))
goto err;

hr = HrGetOneProp(pmdb, PR_IPM_SUBTREE_ENTRYID, &pvalIPM);
if(hr)
{
pCFDlg->m_lsterr.HrSetLastError(hr, pmdb);
pCFDlg->m_lsterr.ShowError(pCFDlg->hwDialog());

goto err;
}

hr = pmdb->OpenEntry(pvalIPM->Value.bin.cb,
(LPENTRYID)pvalIPM->Value.bin.lpb,
NULL, MAPI_BEST_ACCESS | MAPI_DEFERRED_ERRORS,
&ulObjType, (LPUNKNOWN *) &m_pfld);
if(HR_FAILED(hr))
{
pCFDlg->m_lsterr.HrSetLastError(hr, pmdb);
pCFDlg->m_lsterr.ShowError(pCFDlg->hwDialog());

goto err;
}

Assert(MAPI_FOLDER == ulObjType);

/* if(pvalIPM->Value.bin.cb > m_pval[iEID].Value.bin.cb)
{
if(hr = MAPIAllocateMore(pvalIPM->Value.bin.cb,
m_pval, (LPVOID *)&m_pval[iEID].Value.bin.lpb))
goto err;

}

CopyMemory(m_pval[iEID].Value.bin.lpb, pvalIPM->Value.bin.lpb,
pvalIPM->Value.bin.cb);
m_pval[iEID].Value.bin.cb = pvalIPM->Value.bin.cb;*/

err:
if(HR_FAILED(hr))
{
UlRelease(pmdb);
UlRelease(m_pfld);
m_pfld = NULL;
}
else
{
m_pmdb = pmdb;
hr = hrSuccess; //don't return warnings
}

MAPIFreeBuffer(pvalIPM);

DebugTraceResult(CTVNode::HrOpenMDB, hr);
return hr;
}

//
// CTVNode::HrOpenFolder
//
HRESULT CTVNode::HrOpenFolder(CChsFldDlg * pCFDlg)
{
HRESULT hr;
ULONG ulObjType;

Assert(m_pval[iEID].ulPropTag == PR_ENTRYID);
Assert(m_pmdb);

// MAPI_MODIFY flag affects only IMAPIProp interface of the object.
// It does not guarantee permission to create subfolders.
hr = m_pmdb->OpenEntry(m_pval[iEID].Value.bin.cb,
(LPENTRYID)m_pval[iEID].Value.bin.lpb,
NULL, MAPI_BEST_ACCESS | MAPI_DEFERRED_ERRORS,
&ulObjType, (LPUNKNOWN *) &m_pfld);
if(HR_FAILED(hr))
{
pCFDlg->m_lsterr.HrSetLastError(hr, m_pmdb);
pCFDlg->m_lsterr.ShowError(pCFDlg->hwDialog());

goto err;
}

Assert(MAPI_FOLDER == ulObjType);
err:

DebugTraceResult(CTVNode::HrOpenFolder, hr);
return hr;

}

//
// CTVNode::HrGetFolder
//
// return folder interface for the node
HRESULT CTVNode::HrGetFolder(CChsFldDlg * pCFDlg,
LPMAPIFOLDER * ppfld, LPMDB *ppmdb)
{
HRESULT hr = hrSuccess;

Assert(pCFDlg);
Assert(ppfld);
Assert(ppmdb);


if(!m_pmdb)
{
hr = HrOpenMDB(pCFDlg);
if(FAILED(hr))
goto err;
}
Assert(m_pmdb);

if(!m_pfld)
{
Assert(!m_fKidsLoaded);

hr = HrOpenFolder(pCFDlg);
if(FAILED(hr))
goto err;

}
Assert(m_pfld);

*ppfld = m_pfld;
m_pfld->AddRef();

m_pmdb->AddRef();
*ppmdb = m_pmdb;

err:

DebugTraceResult(CTVNode::HrGetFolder, hr);
return hr;
}


//
// CTVNode::HrNewFolder
//
// Create subfolder szFldName
//
HRESULT CTVNode::HrNewFolder(CChsFldDlg * pCFDlg,
LPSTR szFldName)
{
HRESULT hr;
LPMAPIFOLDER pfldNew = NULL;
LPTVNODE pNode = NULL;
LPSPropValue pval = NULL;
HTREEITEM hItem;

Assert(szFldName);
Assert(pCFDlg);


if(!m_pmdb)
{
hr = HrOpenMDB(pCFDlg);
if(FAILED(hr))
goto err;
}

Assert(m_pmdb);

if(!m_pfld)
{
hr = HrOpenFolder(pCFDlg);
if(FAILED(hr))
goto err;
}

Assert(m_pmdb);

hr = m_pfld->CreateFolder(FOLDER_GENERIC, szFldName, NULL,
NULL, 0, &pfldNew);
if(HR_FAILED(hr))
{
pCFDlg->m_lsterr.HrSetLastError(hr, m_pfld);
pCFDlg->m_lsterr.ShowError(pCFDlg->hwDialog());

goto err;
}

if(!m_pval[iSubfldrs].Value.b)
{
m_pval[iSubfldrs].Value.b = TRUE;

TV_ITEM tvI;

tvI.hItem = m_htiMe;
tvI.mask = TVIF_CHILDREN;
tvI.cChildren = 1;

TreeView_SetItem(pCFDlg->hwTreeCtl(), &tvI);
}

if(m_fKidsLoaded)
{
hr = MAPIAllocateBuffer(sizeof(SPropValue)* nhtProps, (LPVOID *)&pval);
if(hr)
goto err;

ZeroMemory(pval, sizeof(SPropValue) * nhtProps );

pval[iEID].ulPropTag = PR_ENTRYID;
pval[iDispName].ulPropTag = PR_DISPLAY_NAME;
pval[iSubfldrs].ulPropTag = PR_SUBFOLDERS;

pval[iSubfldrs].Value.b = FALSE;

int cb = lstrlen(szFldName) + 1;
hr = MAPIAllocateMore(cb, pval, (LPVOID *)&pval[iDispName].Value.lpszA);
if(hr)
goto err;

lstrcpy(pval[iDispName].Value.lpszA, szFldName);

hr = pCFDlg->HrCreateNode(pval, nhtProps, m_pmdb, &pNode);
if(HR_FAILED(hr))
goto err;

pval = NULL;

hItem = AddOneItem(m_htiMe, TVI_SORT, pCFDlg->IndClsdFld(),
pCFDlg->IndOpenFld(), pCFDlg->hwTreeCtl(), pNode, 0);
if(!hItem)
{
hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
goto err;
}

pNode->m_pfld = pfldNew;
pfldNew = NULL;

}

err:
MAPIFreeBuffer(pval);
UlRelease(pfldNew);

DebugTraceResult(CTVNode::HrNewFolder, hr);
return hr;
}

//
// CTVNode::Write
//
// Used in CChsFldDlg::HrSaveTreeState
void CTVNode::Write(BOOL fWrite, LONG iLevel, LPBYTE * ppb)
{
if(fWrite)
*((LONG *)*ppb) = iLevel;
*ppb += sizeof(LONG);

if(iLevel != 0)
{
ULONG cb = m_pval[iEID].Value.bin.cb;

if(fWrite)
*((ULONG *)*ppb) = cb;
*ppb += sizeof(ULONG);

if(fWrite)
CopyMemory(*ppb, m_pval[iEID].Value.bin.lpb, cb);
*ppb += Align4(cb);
}
else
{
Assert(m_pval[iDispName].Value.lpszA == g_szAllStores);
}

}

LPVOID CTVNode::operator new( size_t cb )
{
LPVOID pv;

if ( MAPIAllocateBuffer( (ULONG)cb, &pv ) )
pv = NULL;

return pv;
}

void CTVNode::operator delete( LPVOID pv )
{
MAPIFreeBuffer( pv );
}