// --srowlst.cpp---------------------------------------------------------------
//
// Implementation of classes CSROWNODE and CSROWLST.
//
// Copyright (C) Microsoft Corp., 1986-1996. All rights reserved.
//
//-----------------------------------------------------------------------------
#include "edk.h"
#include "srowlst.h"
// ROWLIST allocation helper macro for IExchangeModifyTable interface.
#defineCbNewROWLIST(_centries)(offsetof(ROWLIST,aEntries) + \
(_centries)*sizeof(ROWENTRY))
// $--CSROWNODE::CSROWNODE-----------------------------------------------------
//
// DESCRIPTION:CSROWNODE constructor.
//
// INPUT:
//
//[lpSRow]-- Ptr to SRow for the CSROWNODE to be constructed.
//
// RETURNS:Nothing.
//
//-----------------------------------------------------------------------------
CSROWNODE::CSROWNODE(
INLPSRowlpSRow // row set ptr
)
{
DEBUGPRIVATE("CSROWNODE::CSROWNODE()\n");
m_pNxt =NULL;
m_pPrv =NULL;
m_SRow =*lpSRow;
}
// $--CSROWNODE::~CSROWNODE----------------------------------------------------
//
// DESCRIPTION:CSROWNODE destructor.
//
// INPUT:None.
//
// RETURNS:Nothing.
//
//-----------------------------------------------------------------------------
CSROWNODE::~CSROWNODE()
{
DEBUGPRIVATE("CSROWNODE::~CSROWNODE()\n");
MAPIFREEBUFFER(m_SRow.lpProps);
}
// $--CSROWLST::CSROWLST-------------------------------------------------------
//
// DESCRIPTION:CSROWLST constructor.
//
// INPUT:None.
//
// RETURNS:Nothing.
//
//-----------------------------------------------------------------------------
CSROWLST::CSROWLST()
{
DEBUGPRIVATE("CSROWLST::CSROWLST()\n");
m_cNodes =0;
m_lPos =ACL_PAST_END;
m_pCurNode =NULL;
m_pLstHd =NULL;
}
// $--CSROWLST::~CSROWLST------------------------------------------------------
//
// DESCRIPTION:CSROWLST destructor.
//
// INPUT:None.
//
// RETURNS:Nothing.
//
//-----------------------------------------------------------------------------
CSROWLST::~CSROWLST()
{
CSROWNODE *pNode =NULL;
DEBUGPRIVATE("CSROWLST::~CSROWLST()\n");
while (m_pLstHd != NULL)
{
pNode = m_pLstHd;
m_pLstHd = m_pLstHd->m_pNxt;
delete pNode;
}
}
// $--CSROWLST::HrInitialize---------------------------------------------------
//
// DESCRIPTION:Initialize an CSROWLST. An SRowSet is stored in the CSROWLST.
//The SROWNODES are ordered according to the order they are
//found in the table. Upon completion of this method, either
//successful or unsuccessful, all storage associated with lpRows
//has either been reassigned to the CSROWLST, or has been
//deallocated.
//
// INPUT:
//
//[lpRows]-- Ptr to SRowSet to use in initializing the CSROWLST.
//
// RETURNS:NOERROR on success;
// E_INVALIDARG if bad input,
// E_FAIL otherwise
//
// Warning:lpRows is NO LONGER VALID after calling this function and
//should NOT be used or deallocated!
//
//---------------------------------------------------------------------------
HRESULT
CSROWLST::HrInitialize(// RETURNS: HRESULT
INLPSRowSetlpRows // row set ptr
)
{
HRESULThr =NOERROR;
ULONGi =0;
CSROWNODE *pCurNode =NULL;
CSROWNODE *pNewNode =NULL;
ULONGulCurSeqNo =0;
ULONGulNewSeqNo =0;
DEBUGPRIVATE("CSROWLST::HrInitialize()\n");
// Verify that all rows have the proper number of properties.
for (i = 0; i < lpRows->cRows; i++)
{
if (lpRows->aRow[i].cValues < C_ACLPROPS)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}
// Now add the SRow's in the SRowSet to the row list.
for (i = 0; i < lpRows->cRows; i++)
{
pNewNode = new CSROWNODE(&lpRows->aRow[i]);
if (pNewNode == NULL)
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}
// The lpProps storage no longer belongs to the SRowSet, so:
lpRows->aRow[i].cValues = 0;
lpRows->aRow[i].lpProps = NULL;
AddToDLLTail(pNewNode, m_pLstHd);
m_cNodes++;
}
if (m_cNodes > 0)
{
m_lPos = 0;
m_pCurNode = m_pLstHd;
}
cleanup:
FREEPROWS(lpRows);
RETURN(hr);
}
// $--CSROWLST::HrDelete----------------------------------------------------
//
// DESCRIPTION:Delete the current record.
//
// INPUT:None.
//
// RETURNS:NOERROR on success;
//E_FAIL if current cursor value is ACL_PAST_END.
//
//-----------------------------------------------------------------------------
HRESULT
CSROWLST::HrDelete(VOID)// RETURNS: HRESULT
{
HRESULThr =NOERROR;
CSROWNODE *pNode =NULL;
DEBUGPRIVATE("CSROWLST::HrDelete()\n");
hr = HrRemoveFromLst(&pNode);
if (FAILED(hr))
goto cleanup;
delete pNode;
cleanup:
RETURN(hr);
}
// $--CSROWLST::HrInsert----------------------------------------------------
//
// DESCRIPTION:Insert a new CSROWNODE before the current record and advance
//the cursor.
//
// INPUT:
//
//[lpSRow]-- Ptr to SRow for the CSROWNODE to be inserted.
//
// RETURNS:NOERROR on success;
// E_INVALIDARG if bad input;
// E_FAIL otherwise;
//
// Notes:The cursor is advanced only if it is not at ACL_PAST_END.
//E_FAIL is returned if there is already an entry for the
//user.
//
//-----------------------------------------------------------------------------
HRESULT
CSROWLST::HrInsert(// RETURNS: HRESULT
INLPSRowlpSRow // row set ptr
)
{
HRESULThr =NOERROR;
CSROWNODE *pNewNode =NULL;
DEBUGPRIVATE("CSROWLST::HrInsert()\n");
if (m_cNodes == EDK_MAX_QUERY_ROWS)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
{
CSROWNODE *pNode =m_pLstHd;
while (pNode != NULL)
{
if (!stricmp(lpSRow->lpProps[I_MEMBER_NAME].Value.lpszA,
pNode->m_SRow.lpProps[I_MEMBER_NAME].Value.lpszA))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
pNode = pNode->m_pNxt;
}
}
pNewNode = new CSROWNODE(lpSRow);
if (pNewNode == NULL)
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}
if (m_pCurNode == m_pLstHd)// Covers empty list and insertion at head.
{
AddToDLLHead(pNewNode, m_pLstHd);
}
else if (m_pCurNode == NULL)// Covers insertion at tail.
{
AddToDLLTail(pNewNode, m_pLstHd);
}
else// Covers all other cases.
{
// It is important to store the previous node ptr in a separate
// location because m_pCurNode->m_pPrv gets stomped on in
// InsertIntoDLL().
CSROWNODE *pPrvNode = m_pCurNode->m_pPrv;
InsertIntoDLL(pNewNode, m_pLstHd, pPrvNode);
}
m_cNodes++;
if (m_lPos != ACL_PAST_END)
m_lPos++;
// Note that m_pCurNode does not change regardless of the insertion point.
cleanup:
RETURN(hr);
}
// $--CSROWLST::HrRemoveFromLst------------------------------------------------
//
// DESCRIPTION:Remove the current record from the list and make it available
//to the caller. The caller is responsible for deleting the
//record when he no longer needs it.
//
// OUTPUT:
//
//[ppRemovedNode]-- Ptr that will be set to removed node on successful
// return.
//
// RETURNS:NOERROR on success;
//E_FAIL if current cursor value is ACL_PAST_END.
//
//-----------------------------------------------------------------------------
HRESULT
CSROWLST::HrRemoveFromLst(
OUTCSROWNODE * *ppRemovedNode
)
{
HRESULThr =NOERROR;
CSROWNODE *pNode =NULL;
DEBUGPRIVATE("CSROWLST::HrRemoveFromLst()\n");
*ppRemovedNode = NULL;
if (m_lPos == ACL_PAST_END)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
pNode = m_pCurNode;
m_pCurNode = m_pCurNode->m_pNxt;
if (m_pCurNode == NULL)
m_lPos = ACL_PAST_END;
RmFromDLL(pNode, m_pLstHd);
m_cNodes--;
*ppRemovedNode = pNode;
cleanup:
RETURN(hr);
}
// $--CSROWLST::SetCursor------------------------------------------------------
//
// DESCRIPTION:Standard C++ set member function which sets the current
//cursor position.
//
// INPUT:
//
//[lPos]-- New cursor position. If < 0 or past end of list, then the
// new cursor positon will be set to ACL_PAST_END.
//
// RETURNS:The new cursor position.
//
//---------------------------------------------------------------------------
LONG
CSROWLST::SetCursor(// RETURNS: LONG
INLONGlPos// cursor position
)
{
DEBUGPRIVATE("CSROWLST::SetCursor()\n");
if (lPos >= 0 && lPos < (LONG) m_cNodes)
{
if (m_lPos == ACL_PAST_END || m_lPos > lPos)
{
m_pCurNode = m_pLstHd;
m_lPos = 0;
}
while (m_lPos < lPos)
{
m_pCurNode = m_pCurNode->m_pNxt;
m_lPos++;
}
}
else
{
m_lPos =ACL_PAST_END;
m_pCurNode =NULL;
}
return m_lPos;
}
// $--CSROWLST::HrWriteToTable-------------------------------------------------
//
// DESCRIPTION:Write the contents of the CSROWLST to an EXCHANGEMODIFYTABLE.
//
// INPUT:
//
//[lpExchTbl]-- Ptr to the EXCHANGEMODIFYTABLE that will be rewritten based
// on the contents of the CSROWLST.
//
// RETURNS:NOERROR on success;
// E_INVALIDARG if bad input;
// E_FAIL otherwise.
//
//---------------------------------------------------------------------------
HRESULT
CSROWLST::HrWriteToTable(// RETURNS: HRESULT
INLPEXCHANGEMODIFYTABLElpExchTbl // Exchange modify tbl i/f ptr
)
{
HRESULThr =NOERROR;
LPROWENTRYlpRowEntry =NULL;
LPROWLISTlpRowList =NULL;
CSROWNODE *pNode =NULL;
DEBUGPRIVATE("CSROWLST::HrWriteToTable()\n");
// Make a ROWLIST for use with the IExchangeModifyTable interface. We
// explicitly call MAPIAllocateBuffer() here due to the size vagaries
// of MAPI structures. In writing to the table, we have to drop off
// the PR_MEMBER_NAME property, which we have conveniently placed last
// in the SPropValue array.
hr = MAPIAllocateBuffer(CbNewROWLIST(m_cNodes), (LPVOID FAR *)&lpRowList);
if (FAILED(hr))
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}
lpRowList->cEntries = m_cNodes;
pNode = m_pLstHd;
lpRowEntry = lpRowList->aEntries;
while (pNode != NULL)
{
lpRowEntry->ulRowFlags =ROW_ADD;
lpRowEntry->cValues =pNode->m_SRow.cValues - 1;//drop member name
lpRowEntry->rgPropVals =pNode->m_SRow.lpProps;
lpRowEntry++;
pNode = pNode->m_pNxt;
}
// Modify the entire table.
hr = lpExchTbl->ModifyTable(ROWLIST_REPLACE, lpRowList);
if (FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
cleanup:
// Deallocate the ROWLIST (not including the SPropValue ptrs, since they
// still actually belong to the CSROWLST).
MAPIFREEBUFFER(lpRowList);
RETURN(hr);
}