SROWLST.CPP

// --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);
}