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