RULECLSI.CPP

// --ruleclsi.cpp------------------------------------------------------------- 
//
// Implementation file for the CIExchangeFolderRules programmer interface
//class.
//
// The CFolderRules class is the controlling class. It controls the
// CIExchangeFolderRules class (which implements the IExchangeFolderRules
// programatic interface defined in rulecls.h and which this file
// implements).
//
// Copyright (C) Microsoft Corp. 1986-1996, All rights reserved.
//
// ---------------------------------------------------------------------------

#include "edk.h"
#include "srowlst.h"
#include "ruleclsf.h"
#include "ruleclsi.chk"

// IUnknown Methods --
// Let the controlling parent object handle all of these!

// $--CIExchangeFolderRules::QueryInterface------------------------------------
//
// DESCRIPTION:Return ptr to object which implements the desired
//interface, if this object supports the interface.
//
//Implemented via the parent object's (CFolderRules')
//QueryInterface.
//
// INPUT:
//
// [riid]-- Reference to interface identifier of desired interface.
//
// OUTPUT:
//
// [ppvObj]-- Pointer to object which supports interface. NULL if none.
//
// RETURNS:NOERRORif successful;
//E_INVALIDARGif bad input;
//E_NOINTERFACEif interface not supported.
//
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderRules::QueryInterface(// RETURNS: HRESULT
INREFIIDriid, // interface ID reference
OUTLPVOID FAR *ppvObj // ptr to interface ptr
)
{
HRESULThr =NOERROR;

DEBUGPUBLIC("CIExchangeFolderRules::QueryInterface().\n");

hr = CHK_CIExchangeFolderRules_QueryInterface(riid, ppvObj);

if (FAILED(hr))
RETURN(hr);

ASSERT_READ_PTR_OR_NULL(m_pFR, sizeof(CFolderRules FAR *),
"Bad m_pFR");

// Let parent controlling object handle this. (Let it do all
// parameter checking also!)

hr = m_pFR->QueryInterface(riid, ppvObj);

RETURN(hr);
}


// $--CIExchangeFolderRules::AddRef--------------------------------------------
//
// DESCRIPTION:Increment this object's reference count.
//
//Implemented via the parent object's (CFolderRules') AddRef().
//
// INPUT:None.
//
// RETURNS:New reference count.
//
//-----------------------------------------------------------------------------

STDMETHODIMP_(ULONG)
CIExchangeFolderRules::AddRef()// RETURNS: ULONG
{
ULONGulRefCount =0;

DEBUGPUBLIC("CIExchangeFolderRules::AddRef().\n");

ASSERT_READ_PTR_OR_NULL(m_pFR, sizeof(CFolderRules FAR *),
"Bad m_pFR");

// Let parent controlling object handle this.

ulRefCount = m_pFR->AddRef();

return ulRefCount;
}


// $--CIExchangeFolderRules::Release-------------------------------------------
//
// DESCRIPTION:Decrement this object's reference count.
//
//Implemented via the parent object's (CFolderRules')
//Release().
//
// INPUT:None.
//
// RETURNS:New reference count.
//
//-----------------------------------------------------------------------------

STDMETHODIMP_(ULONG)
CIExchangeFolderRules::Release() // RETURNS: ULONG
{
ULONGulRefCount =0;

DEBUGPUBLIC("CIExchangeFolderRules::Release().\n");

ASSERT_READ_PTR_OR_NULL(m_pFR, sizeof(CFolderRules FAR *),
"Bad m_pFR");

// Let parent controlling object handle this.

ulRefCount = m_pFR->Release();

return ulRefCount;
}

//
// Methods unique to the IExchangeFolderRules interface.
//

// $--CIExchangeFolderRules::HrDelete------------------------------------------
//
// DESCRIPTION:Delete the current record.
//
// INPUT:None.
//
// RETURNS:NOERRORif successful;
// E_FAILif cursor at RULE_PAST_END;
// E_OUTOFMEMORYif insufficient memory.
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderRules::HrDelete(VOID)// RETURNS: HRESULT
{
HRESULThr =NOERROR;
LPMAPITABLElpMapiTbl =NULL;
LPROWLISTlpRowList =NULL;
LPSRowSetlpRows =NULL;
CSROWNODE *pDeletedNode =NULL;

DEBUGPUBLIC("CIExchangeFolderRules::HrDelete().\n");

ASSERT_READ_PTR_OR_NULL(m_pFR, sizeof(CFolderRules FAR *), "Bad m_pFR.");

hr = m_pFR->m_SRowLst.HrRemoveFromLst(&pDeletedNode);

if (FAILED(hr))
goto cleanup;

if (m_pFR->m_SRowLst.GetNodeCount() +
m_pFR->m_SRowLst.GetOtherProvNodeCount() > 0)
{
hr = m_pFR->m_SRowLst.HrWriteToTable(m_pFR->m_lpExchTbl);
}
else
{
// Workaround BUGFIX for bug 2435. This code works around a problem
// in IExchangeModifyTable::ModifyTable() whereby a ROWLIST_REPLACE
// operation fails if the replacement table is empty. We should be
// able to remove this code once this problem is fixed in
// IExchangeModifyTable.

SizedSPropTagArray(1, rgPropTag) =
{
1,
{
PR_RULE_ID
}
};

// Get the PR_RULE_ID for the one remaining rule in the table.

hr = m_pFR->m_lpExchTbl->GetTable(0, &lpMapiTbl);

if (FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Select columns needed.

hr = lpMapiTbl->SetColumns((LPSPropTagArray)&rgPropTag, 0);

if (FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

hr = lpMapiTbl->QueryRows(1, 0, &lpRows);

if (FAILED(hr) || lpRows->cRows != 1)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Delete the rule.

hr = MAPIAllocateBuffer(CbNewROWLIST(1), (LPVOID FAR *)&lpRowList);

if (FAILED(hr))
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}

lpRowList->cEntries = 1;

lpRowList->aEntries[0].ulRowFlags =ROW_REMOVE;
lpRowList->aEntries[0].cValues =lpRows->aRow[0].cValues;
lpRowList->aEntries[0].rgPropVals =lpRows->aRow[0].lpProps;

// Remove the entry.

hr = m_pFR->m_lpExchTbl->ModifyTable(0, lpRowList);

if (FAILED(hr))
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
}

cleanup:

if (FAILED(hr) && pDeletedNode != NULL)
{
HRESULThrTmp = m_pFR->m_SRowLst.HrInsert(&pDeletedNode->m_SRow);

if (FAILED(hrTmp))
hr = HR_LOG(E_UNEXPECTED);
else
pDeletedNode->m_SRow.lpProps = NULL;
}

delete pDeletedNode;

MAPIFREEBUFFER(lpRowList);
FREEPROWS(lpRows);
ULRELEASE(lpMapiTbl);

RETURN(hr);
}


// $--CIExchangeFolderRules::HrDisable-----------------------------------------
//
// DESCRIPTION:Disable the current rule.
//
// INPUT:None.
//
// RETURNS:NOERRORif successful;
// E_FAILif cursor at RULE_PAST_END or corrupt data;
// E_OUTOFMEMORYif insufficient memory.
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderRules::HrDisable(VOID)// RETURNS: HRESULT
{
HRESULThr =NOERROR;
LONGlPrevState =0;
CSROWNODE *pNode =NULL;

DEBUGPUBLIC("CIExchangeFolderRules::HrDisable().\n");

ASSERT_READ_PTR_OR_NULL(m_pFR, sizeof(CFolderRules FAR *),
"Bad m_pFR.");

pNode = m_pFR->m_SRowLst.GetCurrentNode();

if (pNode == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if (pNode->m_SRow.cValues < C_RULEPROPS ||
pNode->m_SRow.lpProps[I_RULE_STATE].ulPropTag != PR_RULE_STATE)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Save the previous state in case the table write fails.

lPrevState = pNode->m_SRow.lpProps[I_RULE_STATE].Value.l;

// Note - Given the actual values for ST_ENABLED and ST_DISABLED, the
// following clearing AND setting of bits is really not necessary; however
// we do it this way in case the bits ever get redefined (currently
// ST_DISABLED == 0x0000).

pNode->m_SRow.lpProps[I_RULE_STATE].Value.l &= ~ST_ENABLED;
pNode->m_SRow.lpProps[I_RULE_STATE].Value.l |= ST_DISABLED;

hr = m_pFR->m_SRowLst.HrWriteToTable(m_pFR->m_lpExchTbl);

if (FAILED(hr))
{
// The table write failed, so reset the list to the previous value.

pNode->m_SRow.lpProps[I_RULE_STATE].Value.l = lPrevState;
goto cleanup;
}

cleanup:

RETURN(hr);
}


// $--CIExchangeFolderRules::HrEnable------------------------------------------
//
// DESCRIPTION:Enable the current rule.
//
// INPUT:None.
//
// RETURNS:NOERRORif successful;
// E_FAILif cursor at RULE_PAST_END or corrupt data;
// E_OUTOFMEMORYif insufficient memory.
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderRules::HrEnable(VOID)// RETURNS: HRESULT
{
HRESULThr =NOERROR;
LONGlPrevState =0;
CSROWNODE *pNode =NULL;

DEBUGPUBLIC("CIExchangeFolderRules::HrEnable().\n");

ASSERT_READ_PTR_OR_NULL(m_pFR, sizeof(CFolderRules FAR *),
"Bad m_pFR.");

pNode = m_pFR->m_SRowLst.GetCurrentNode();

if (pNode == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if (pNode->m_SRow.cValues < C_RULEPROPS ||
pNode->m_SRow.lpProps[I_RULE_STATE].ulPropTag != PR_RULE_STATE)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

// Save the previous state in case the table write fails.

lPrevState = pNode->m_SRow.lpProps[I_RULE_STATE].Value.l;

// Note - Given the actual values for ST_ENABLED and ST_DISABLED, the
// following clearing AND setting of bits is really not necessary; however
// we do it this way in case the bits ever get redefined (currently
// ST_DISABLED == 0x0000).

pNode->m_SRow.lpProps[I_RULE_STATE].Value.l &= ~ST_DISABLED;
pNode->m_SRow.lpProps[I_RULE_STATE].Value.l |= ST_ENABLED;

hr = m_pFR->m_SRowLst.HrWriteToTable(m_pFR->m_lpExchTbl);

if (FAILED(hr))
{
// The table write failed, so reset the list to the previous value.

pNode->m_SRow.lpProps[I_RULE_STATE].Value.l = lPrevState;
goto cleanup;
}

cleanup:

RETURN(hr);
}


// $--CIExchangeFolderRules::HrGet---------------------------------------------
//
// DESCRIPTION:Get the current record and advance the cursor.
//
// OUTPUT:
//
// [lplState]-- Rule state buffer.
// [lppRestriction]-- Restriction buffer.
// [lppActions]-- Actions buffer.
// [lplLevel]-- Rule level buffer.
// [lppszName]-- Rule name buffer.
//
//
// RETURNS:NOERRORif successful;
//E_INVALIDARGif bad input;
// E_FAILif cursor at RULE_PAST_END;
// E_OUTOFMEMORYif insufficient memory.
//
// Notes:Space for *lplState and *lplLevel is allocated by the user.
//Space for the other parameters is allocated by this method.
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderRules::HrGet(// RETURNS: HRESULT
OUTLPLONGlplState,// state ptr
OUTLPSRestriction FAR *lppRestriction, // restriction buffer ptr
OUTLPACTIONS FAR *lppActions,// actions buffer ptr
OUTLPLONGlplLevel,// level ptr
OUTLPSTR FAR *lppszName // rule name ptr
)
{
HRESULThr =NOERROR;
CSROWNODE *pNode =NULL;

DEBUGPUBLIC("CIExchangeFolderRules::HrGet().\n");

hr = CHK_CIExchangeFolderRules_HrGet(lplState,
lppRestriction,
lppActions,
lplLevel,
lppszName);
if (FAILED(hr))
RETURN(hr);

// Null the ptrs so we can free them on failure.

*lppRestriction =NULL;
*lppActions =NULL;
*lppszName =NULL;

ASSERT_READ_PTR_OR_NULL(m_pFR, sizeof(CFolderRules FAR *), "Bad m_pFR.");

pNode = m_pFR->m_SRowLst.GetCurrentNode();

if (pNode == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

if (pNode->m_SRow.cValues < C_RULEPROPS||
pNode->m_SRow.lpProps[I_RULE_SEQUENCE].ulPropTag !=
PR_RULE_SEQUENCE||
pNode->m_SRow.lpProps[I_RULE_STATE].ulPropTag !=
PR_RULE_STATE||
pNode->m_SRow.lpProps[I_RULE_CONDITION].ulPropTag !=
PR_RULE_CONDITION||
pNode->m_SRow.lpProps[I_RULE_ACTIONS].ulPropTag !=
PR_RULE_ACTIONS||
pNode->m_SRow.lpProps[I_RULE_LEVEL].ulPropTag !=
PR_RULE_LEVEL||
pNode->m_SRow.lpProps[I_RULE_NAME].ulPropTag !=
PR_RULE_NAME)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}

*lplState = pNode->m_SRow.lpProps[I_RULE_STATE].Value.l;

if (pNode->m_SRow.lpProps[I_RULE_CONDITION].Value.x != NULL)
{
hr = HrCopyRestriction((LPSRestriction)pNode->
m_SRow.lpProps[I_RULE_CONDITION].Value.x,
NULL,
lppRestriction);
if (FAILED(hr))
goto cleanup;
}

hr = HrCopyActions(
(LPACTIONS)pNode->m_SRow.lpProps[I_RULE_ACTIONS].Value.x,
NULL,
lppActions);

if (FAILED(hr))
goto cleanup;

*lplLevel = pNode->m_SRow.lpProps[I_RULE_LEVEL].Value.l;

if (pNode->m_SRow.lpProps[I_RULE_NAME].Value.lpszA != NULL)
{
ULONGcb = strlen(pNode->m_SRow.lpProps[I_RULE_NAME].Value.lpszA)
+ sizeof(char);

hr = MAPIAllocateBuffer(cb, (LPVOID FAR *)lppszName);

if (FAILED(hr))
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}

strcpy(*lppszName,
pNode->m_SRow.lpProps[I_RULE_NAME].Value.lpszA);
}

// Advance the cursor.

m_pFR->m_SRowLst.SetCursor(m_pFR->m_SRowLst.GetCursor() + 1);

cleanup:

if (FAILED(hr))
{
MAPIFREEBUFFER(*lppRestriction);
MAPIFREEBUFFER(*lppActions);
MAPIFREEBUFFER(*lppszName);
}

RETURN(hr);
}


// $--CIExchangeFolderRules::HrInsert------------------------------------------
//
// DESCRIPTION:Insert record before the current record and advance the cursor.
//
// INPUT:
//
// [lState]-- Rule state.
// [lpRestriction]-- Restriction.
// [lpActions]-- Actions.
// [lLevel]-- Rule level.
// [lpszRule]-- Rule name.
//
//
// RETURNS:NOERRORif successful;
//E_INVALIDARGif bad input;
// E_OUTOFMEMORYif memory problems;
// E_FAILotherwise.
//
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderRules::HrInsert(// RETURNS: HRESULT
INLONGlState, // rule state
INLPSRestrictionlpRestriction, // restriction ptr
INLPACTIONSlpActions, // actions ptr
INLONGlLevel,// rule level
INLPSTRlpszName// rule name
)
{
HRESULThr =NOERROR;
LPACTIONSlpActionsCopy =NULL;
LPSRestrictionlpRestrictionCopy =NULL;
LPSTRlpszNameCopy =NULL;
LONGlPosInsertion =RULE_PAST_END;
SRowsr = {0, C_RULEPROPS, NULL};

DEBUGPUBLIC("CIExchangeFolderRules::HrInsert().\n");

hr = CHK_CIExchangeFolderRules_HrInsert(lState,
lpRestriction,
lpActions,
lLevel,
lpszName);
if (FAILED(hr))
RETURN(hr);

ASSERT_READ_PTR_OR_NULL(m_pFR, sizeof(CFolderRules FAR *),
"Bad m_pFR.");

hr = MAPIAllocateBuffer(sizeof(SPropValue) * C_RULEPROPS,
(LPVOID FAR *)&sr.lpProps);
if (FAILED(hr))
{
hr = HR_LOG(E_OUTOFMEMORY);

goto cleanup;
}

memset(sr.lpProps, 0, sizeof(SPropValue) * C_RULEPROPS);

hr = HrCopyActions(lpActions, sr.lpProps, &lpActionsCopy);

if (FAILED(hr))
goto cleanup;

hr = HrCopyRestriction(lpRestriction, sr.lpProps, &lpRestrictionCopy);

if (FAILED(hr))
goto cleanup;

hr = MAPIAllocateMore(strlen(lpszName) + sizeof(char),
sr.lpProps,
(LPVOID FAR *)&lpszNameCopy);
if (FAILED(hr))
{
hr = HR_LOG(E_OUTOFMEMORY);

goto cleanup;
}

strcpy(lpszNameCopy, lpszName);

sr.lpProps[I_RULE_SEQUENCE].ulPropTag = PR_RULE_SEQUENCE;
sr.lpProps[I_RULE_SEQUENCE].Value.ul =0;
// SROWLST::Insert() resets value as appropriate.

sr.lpProps[I_RULE_STATE].ulPropTag =PR_RULE_STATE;
sr.lpProps[I_RULE_STATE].Value.l =lState;

sr.lpProps[I_RULE_CONDITION].ulPropTag =PR_RULE_CONDITION;
sr.lpProps[I_RULE_CONDITION].Value.ul =(ULONG)lpRestrictionCopy;

sr.lpProps[I_RULE_ACTIONS].ulPropTag =PR_RULE_ACTIONS;
sr.lpProps[I_RULE_ACTIONS].Value.ul =(ULONG)lpActionsCopy;

sr.lpProps[I_RULE_PROVIDER].ulPropTag =PR_RULE_PROVIDER;
sr.lpProps[I_RULE_PROVIDER].Value.lpszA =NULL;
// SROWLST::Insert() sets value as appropriate.

sr.lpProps[I_RULE_LEVEL].ulPropTag =PR_RULE_LEVEL;
sr.lpProps[I_RULE_LEVEL].Value.l =lLevel;

sr.lpProps[I_RULE_NAME].ulPropTag =PR_RULE_NAME;
sr.lpProps[I_RULE_NAME].Value.lpszA =lpszNameCopy;

// The following code determines the cursor value the newly inserted
// record will have. This is done so we can easily delete the
// record if the table write fails.

lPosInsertion = m_pFR->m_SRowLst.GetCursor();

if (lPosInsertion == RULE_PAST_END)
lPosInsertion = m_pFR->m_SRowLst.GetNodeCount();

hr = m_pFR->m_SRowLst.HrInsert(&sr);

if (FAILED(hr))
goto cleanup;

hr = m_pFR->m_SRowLst.HrWriteToTable(m_pFR->m_lpExchTbl);

if (FAILED(hr))
{
HRESULThrTmp =NOERROR;

// Delete the node from the list, since the table write failed.

m_pFR->m_SRowLst.SetCursor(lPosInsertion);

hrTmp = m_pFR->m_SRowLst.HrDelete();

if (FAILED(hrTmp))
hr = HR_LOG(E_UNEXPECTED);

// The memory allocated by this method was cleaned up when the
// node was deleted.

sr.lpProps = NULL;
goto cleanup;
}

cleanup:

if (FAILED(hr))
MAPIFREEBUFFER(sr.lpProps);

RETURN(hr);
}


// $--CIExchangeFolderRules::HrSeek--------------------------------------------
//
// DESCRIPTION:Set the current cursor position.
//
// INPUT:
//
// [lPos]-- New cursor position.
//
// RETURNS:NOERRORif successful;
//E_INVALIDARGif bad input.
//
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderRules::HrSeek(// RETURNS: HRESULT
INLONGlPos// cursor position
)
{
HRESULThr =NOERROR;

DEBUGPUBLIC("CIExchangeFolderRules::HrSeek().\n");

hr = CHK_CIExchangeFolderRules_HrSeek(lPos);

if (FAILED(hr))
RETURN(hr);

ASSERT_READ_PTR_OR_NULL(m_pFR, sizeof(CFolderRules FAR *), "Bad m_pFR.");

m_pFR->m_SRowLst.SetCursor(lPos);

RETURN(hr);
}


// $--CIExchangeFolderRules::HrTell--------------------------------------------
//
// DESCRIPTION:Return the current cursor position.
//
// OUTPUT:
//
// [plPos]-- Pointer for returning current cursor position.
//
// RETURNS:NOERRORif successful;
//E_INVALIDARGif bad input.
//
//-----------------------------------------------------------------------------

STDMETHODIMP
CIExchangeFolderRules::HrTell(// RETURNS: HRESULT
OUTLPLONGlplPos// cursor position ptr
)
{
HRESULThr =NOERROR;

DEBUGPUBLIC("CIExchangeFolderRules::HrTell().\n");

hr = CHK_CIExchangeFolderRules_HrTell(lplPos);

if (FAILED(hr))
RETURN(hr);

ASSERT_READ_PTR_OR_NULL(m_pFR, sizeof(CFolderRules FAR *), "Bad m_pFR.");

*lplPos = m_pFR->m_SRowLst.GetCursor();

RETURN(hr);
}