Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1270 lines
28 KiB

///////////////////////////////////////////////////////////////////////////////
//
// Rule.cpp
//
///////////////////////////////////////////////////////////////////////////////
#include <pch.hxx>
#include "rule.h"
#include "strconst.h"
#include "goptions.h"
#include "criteria.h"
#include "actions.h"
#include "ruleutil.h"
///////////////////////////////////////////////////////////////////////////////
//
// HrCreateRule
//
// This creates a rule.
//
// ppIRule - pointer to return the rule
//
// Returns: S_OK, on success
// E_OUTOFMEMORY, if can't create the Rule object
//
///////////////////////////////////////////////////////////////////////////////
HRESULT HrCreateRule(IOERule ** ppIRule)
{
COERule * pRule = NULL;
HRESULT hr = S_OK;
// Check the incoming params
if (NULL == ppIRule)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize outgoing params
*ppIRule = NULL;
// Create the rules manager object
pRule = new COERule;
if (NULL == pRule)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Get the rules manager interface
hr = pRule->QueryInterface(IID_IOERule, (void **) ppIRule);
if (FAILED(hr))
{
goto exit;
}
pRule = NULL;
// Set the proper return value
hr = S_OK;
exit:
if (NULL != pRule)
{
delete pRule;
}
return hr;
}
COERule::COERule()
{
m_cRef = 0;
m_dwState = RULE_STATE_NULL;
m_pszName = NULL;
m_pICrit = NULL;
m_pIAct = NULL;
m_dwVersion = 0;
}
COERule::~COERule()
{
ULONG ulIndex = 0;
AssertSz(m_cRef == 0, "Somebody still has a hold of us!!");
SafeMemFree(m_pszName);
SafeRelease(m_pICrit);
SafeRelease(m_pIAct);
}
STDMETHODIMP_(ULONG) COERule::AddRef()
{
return ::InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) COERule::Release()
{
LONG cRef = 0;
cRef = ::InterlockedDecrement(&m_cRef);
if (0 == cRef)
{
delete this;
return cRef;
}
return cRef;
}
STDMETHODIMP COERule::QueryInterface(REFIID riid, void ** ppvObject)
{
HRESULT hr = S_OK;
// Check the incoming params
if (NULL == ppvObject)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize outgoing param
*ppvObject = NULL;
if ((riid == IID_IUnknown) || (riid == IID_IOERule))
{
*ppvObject = static_cast<IOERule *>(this);
}
else if ((riid == IID_IPersistStream) || (riid == IID_IPersist))
{
*ppvObject = static_cast<IPersistStream *>(this);
}
else
{
hr = E_NOINTERFACE;
goto exit;
}
reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();
hr = S_OK;
exit:
return hr;
}
STDMETHODIMP COERule::Reset(void)
{
HRESULT hr = S_OK;
LPSTR pszKeyPath = NULL;
LPCSTR pszKeyStart = NULL;
// Release the criteria
SafeRelease(m_pICrit);
// Release the actions
SafeRelease(m_pIAct);
// Free up the rule name
SafeMemFree(m_pszName);
// Set the current state
m_dwState |= RULE_STATE_INIT;
// Clear the dirty bit
m_dwState &= ~RULE_STATE_DIRTY;
// Set the return value
hr = S_OK;
return hr;
}
STDMETHODIMP COERule::GetState(DWORD * pdwState)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
// Check incoming params
if (NULL == pdwState)
{
hr = E_INVALIDARG;
goto exit;
}
// If we're not enabled
if ((0 != (m_dwState & RULE_STATE_DISABLED)) || (0 != (m_dwState & RULE_STATE_INVALID)))
{
*pdwState = RULE_STATE_NULL;
}
else
{
*pdwState = m_dwState;
}
// Set the proper return value
hr = S_OK;
exit:
return hr;
}
STDMETHODIMP COERule::Validate(DWORD dwFlags)
{
HRESULT hr = S_OK;
BOOL fValid = FALSE;
// If we don't have a criteria or actions object then we fail
if ((NULL == m_pICrit) || (NULL == m_pIAct))
{
hr = E_FAIL;
goto exit;
}
// Validate the criteria
hr = m_pICrit->Validate(dwFlags);
if (FAILED(hr))
{
goto exit;
}
fValid = TRUE;
if (S_OK != hr)
{
fValid = FALSE;
}
// Validate the actions
hr = m_pIAct->Validate(dwFlags);
if (FAILED(hr))
{
goto exit;
}
if (S_OK != hr)
{
fValid = FALSE;
}
// If the rule is invalid, make sure we disable it
if (FALSE == fValid)
{
m_dwState |= RULE_STATE_INVALID;
}
else
{
m_dwState &= ~RULE_STATE_INVALID;
}
// Set the proper return value
hr = fValid ? S_OK : S_FALSE;
exit:
return hr;
}
STDMETHODIMP COERule::GetProp(RULE_PROP prop, DWORD dwFlags, PROPVARIANT * pvarResult)
{
HRESULT hr = S_OK;
LPSTR pszName = NULL;
CRIT_ITEM * pCrit = NULL;
ACT_ITEM * pAct = NULL;
ULONG cItem = 0;
// Check incoming params
if (NULL == pvarResult)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize outgoing params
ZeroMemory(pvarResult, sizeof(*pvarResult));
switch(prop)
{
case RULE_PROP_NAME:
if (NULL == m_pszName)
{
pszName = PszDupA("");
}
else
{
pszName = PszDupA(m_pszName);
}
pvarResult->vt = VT_LPSTR;
pvarResult->pszVal = pszName;
pszName = NULL;
break;
case RULE_PROP_DISABLED:
pvarResult->vt = VT_BOOL;
pvarResult->boolVal = !!(m_dwState & RULE_STATE_DISABLED);
break;
case RULE_PROP_VERSION:
pvarResult->vt = VT_UI4;
pvarResult->ulVal = m_dwVersion;
break;
case RULE_PROP_CRITERIA:
if (NULL == m_pICrit)
{
cItem = 0;
pCrit = NULL;
}
else
{
hr = m_pICrit->GetCriteria(0, &pCrit, &cItem);
if (FAILED(hr))
{
goto exit;
}
}
pvarResult->vt = VT_BLOB;
pvarResult->blob.cbSize = cItem * sizeof(CRIT_ITEM);
pvarResult->blob.pBlobData = (BYTE *) pCrit;
pCrit = NULL;
break;
case RULE_PROP_ACTIONS:
if (NULL == m_pIAct)
{
cItem = 0;
pAct = NULL;
}
else
{
hr = m_pIAct->GetActions(0, &pAct, &cItem);
if (FAILED(hr))
{
goto exit;
}
}
pvarResult->vt = VT_BLOB;
pvarResult->blob.cbSize = cItem * sizeof(ACT_ITEM);
pvarResult->blob.pBlobData = (BYTE *) pAct;
pAct = NULL;
break;
default:
hr = E_INVALIDARG;
goto exit;
}
// Set the return value
hr = S_OK;
exit:
SafeMemFree(pszName);
RuleUtil_HrFreeCriteriaItem(pCrit, cItem);
SafeMemFree(pCrit);
RuleUtil_HrFreeActionsItem(pAct, cItem);
SafeMemFree(pAct);
return hr;
}
STDMETHODIMP COERule::SetProp(RULE_PROP prop, DWORD dwFlags, PROPVARIANT * pvarResult)
{
HRESULT hr = S_OK;
LPSTR pszName = NULL;
DWORD dwState = 0;
ULONG cItems = 0;
// Check incoming params
if (NULL == pvarResult)
{
hr = E_INVALIDARG;
goto exit;
}
switch(prop)
{
case RULE_PROP_NAME:
if ((VT_LPSTR != pvarResult->vt) || (NULL == pvarResult->pszVal))
{
hr = E_INVALIDARG;
goto exit;
}
// Create a new copy
pszName = PszDupA(pvarResult->pszVal);
if (NULL == pszName)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Free up any old value
SafeMemFree(m_pszName);
// Set the new value
m_pszName = pszName;
pszName = NULL;
break;
case RULE_PROP_DISABLED:
if (VT_BOOL != pvarResult->vt)
{
hr = E_INVALIDARG;
goto exit;
}
// Set the new value
if (FALSE != !!(pvarResult->boolVal))
{
m_dwState |= RULE_STATE_DISABLED;
}
else
{
Assert(0 == (m_dwState & RULE_STATE_INVALID));
m_dwState &= ~RULE_STATE_DISABLED;
}
break;
case RULE_PROP_VERSION:
if (VT_UI4 != pvarResult->vt)
{
hr = E_INVALIDARG;
goto exit;
}
// Set the new value
m_dwVersion = pvarResult->ulVal;
break;
case RULE_PROP_CRITERIA:
if ((VT_BLOB != pvarResult->vt) || (0 == pvarResult->blob.cbSize) ||
(NULL == pvarResult->blob.pBlobData))
{
hr = E_INVALIDARG;
goto exit;
}
if (NULL == m_pICrit)
{
hr = HrCreateCriteria(&m_pICrit);
if (FAILED(hr))
{
goto exit;
}
}
cItems = pvarResult->blob.cbSize / sizeof(CRIT_ITEM);
Assert(cItems * sizeof(CRIT_ITEM) == pvarResult->blob.cbSize);
hr = m_pICrit->SetCriteria(0, (CRIT_ITEM *) pvarResult->blob.pBlobData, cItems);
if (FAILED(hr))
{
goto exit;
}
hr = m_pICrit->GetState(&dwState);
if (FAILED(hr))
{
goto exit;
}
m_dwState = (m_dwState & ~CRIT_STATE_MASK) | (dwState & CRIT_STATE_MASK);
break;
case RULE_PROP_ACTIONS:
if ((VT_BLOB != pvarResult->vt) || (0 == pvarResult->blob.cbSize) ||
(NULL == pvarResult->blob.pBlobData))
{
hr = E_INVALIDARG;
goto exit;
}
if (NULL == m_pIAct)
{
hr = HrCreateActions(&m_pIAct);
if (FAILED(hr))
{
goto exit;
}
}
cItems = pvarResult->blob.cbSize / sizeof(ACT_ITEM);
Assert(cItems * sizeof(ACT_ITEM) == pvarResult->blob.cbSize);
hr = m_pIAct->SetActions(0, (ACT_ITEM *) pvarResult->blob.pBlobData, cItems);
if (FAILED(hr))
{
goto exit;
}
hr = m_pIAct->GetState(&dwState);
if (FAILED(hr))
{
goto exit;
}
m_dwState = (m_dwState & ~ACT_STATE_MASK) | (dwState & ACT_STATE_MASK);
break;
default:
hr = E_INVALIDARG;
goto exit;
}
// Mark the rule as dirty
m_dwState |= RULE_STATE_DIRTY;
// Set the return value
hr = S_OK;
exit:
SafeMemFree(pszName);
return hr;
}
STDMETHODIMP COERule::Evaluate(LPCSTR pszAcct, MESSAGEINFO * pMsgInfo, IMessageFolder * pFolder,
IMimePropertySet * pIMPropSet, IMimeMessage * pIMMsg, ULONG cbMsgSize,
ACT_ITEM ** ppActions, ULONG * pcActions)
{
HRESULT hr = S_OK;
ACT_ITEM * pAct = NULL;
ULONG cAct = 0;
// Check incoming variables
if (((NULL == pMsgInfo) && (NULL == pIMPropSet)) || (0 == cbMsgSize) ||
(NULL == ppActions) || (NULL == pcActions))
{
hr = E_INVALIDARG;
goto exit;
}
// Set outgoing params to default
*ppActions = NULL;
*pcActions = 0;
// If we don't have a criteria or actions object then we fail
if ((NULL == m_pICrit) || (NULL == m_pIAct))
{
hr = S_FALSE;
goto exit;
}
// If we ain't valid then we can just bail
if (0 != (m_dwState & RULE_STATE_INVALID))
{
hr = S_FALSE;
goto exit;
}
// Do we match??
hr = m_pICrit->MatchMessage(pszAcct, pMsgInfo, pFolder, pIMPropSet, pIMMsg, cbMsgSize);
if (FAILED(hr))
{
goto exit;
}
// If we didn't match then just return
if (S_FALSE == hr)
{
goto exit;
}
// Grab the actions and return them to the caller
hr = m_pIAct->GetActions(0, &pAct, &cAct);
if (FAILED(hr))
{
goto exit;
}
// Set the outgoing parameters
*ppActions = pAct;
pAct = NULL;
*pcActions = cAct;
// Set proper return value
hr = S_OK;
exit:
RuleUtil_HrFreeActionsItem(pAct, cAct);
SafeMemFree(pAct);
return hr;
}
STDMETHODIMP COERule::LoadReg(LPCSTR pszRegPath)
{
HRESULT hr = S_OK;
LONG lErr = 0;
HKEY hkeyRoot = NULL;
ULONG cbData = 0;
ULONG cbRead = 0;
DWORD dwData = 0;
LPSTR pszName = NULL;
BOOL fDisabled = FALSE;
IOECriteria * pICriteria = NULL;
IOEActions * pIActions = NULL;
LPSTR pszRegPathNew = NULL;
ULONG cchRegPath = 0;
DWORD dwState = 0;
// Check incoming param
if (NULL == pszRegPath)
{
hr = E_INVALIDARG;
goto exit;
}
// Should we fail if we're already loaded?
AssertSz(0 == (m_dwState & RULE_STATE_LOADED), "We're already loaded!!!");
// Open the reg key from the path
lErr = AthUserOpenKey(pszRegPath, KEY_ALL_ACCESS, &hkeyRoot);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Get the rule name
hr = RuleUtil_HrGetRegValue(hkeyRoot, c_szRuleName, NULL, (BYTE **) &pszName, NULL);
if (FAILED(hr))
{
SafeMemFree(pszName);
}
// Get the enabled state
cbData = sizeof(dwData);
lErr = RegQueryValueEx(hkeyRoot, c_szRuleEnabled, 0, NULL, (BYTE *) &dwData, &cbData);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
Assert(cbData == sizeof(dwData));
fDisabled = ! (BOOL) dwData;
// Get the version of the rule
cbData = sizeof(dwData);
lErr = RegQueryValueEx(hkeyRoot, c_szRulesVersion, 0, NULL, (BYTE *) &dwData, &cbData);
if ((ERROR_SUCCESS != lErr) && (ERROR_FILE_NOT_FOUND != lErr))
{
hr = E_FAIL;
goto exit;
}
if (ERROR_FILE_NOT_FOUND == lErr)
{
dwData = 0;
lErr = RegSetValueEx(hkeyRoot, c_szRulesVersion, 0, REG_DWORD, (CONST BYTE *) &dwData, sizeof(dwData));
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
}
m_dwVersion = dwData;
// Allocate space to hold the new reg path
cchRegPath = lstrlen(pszRegPath);
Assert(lstrlen(c_szRuleCriteria) >= lstrlen(c_szRuleActions));
DWORD cchSize = (cchRegPath + lstrlen(c_szRuleCriteria) + 2);
if (FAILED(HrAlloc((void **) &pszRegPathNew, cchSize)))
{
goto exit;
}
// Build reg path to criteria
StrCpyN(pszRegPathNew, pszRegPath, cchSize);
if ('\\' != pszRegPath[cchRegPath])
{
StrCatBuff(pszRegPathNew, g_szBackSlash, cchSize);
cchRegPath++;
}
StrCatBuff(pszRegPathNew, c_szRuleCriteria, cchSize);
// Create a new criteria object
hr = HrCreateCriteria(&pICriteria);
if (FAILED(hr))
{
goto exit;
}
// Get the criteria
hr = pICriteria->LoadReg(pszRegPathNew);
if (FAILED(hr))
{
goto exit;
}
// Get the state of the criteria
hr = pICriteria->GetState(&dwState);
if (FAILED(hr))
{
goto exit;
}
m_dwState = (m_dwState & ~CRIT_STATE_MASK) | (dwState & CRIT_STATE_MASK);
// Build reg path to actions
StrCpyN(pszRegPathNew + cchRegPath, c_szRuleActions, (cchSize - cchRegPath));
// Create a new actions object
hr = HrCreateActions(&pIActions);
if (FAILED(hr))
{
goto exit;
}
// Get the actions
hr = pIActions->LoadReg(pszRegPathNew);
if (FAILED(hr))
{
goto exit;
}
// Get the state of the actions
hr = pIActions->GetState(&dwState);
if (FAILED(hr))
{
goto exit;
}
m_dwState = (m_dwState & ~ACT_STATE_MASK) | (dwState & ACT_STATE_MASK);
// Free up the current values
SafeMemFree(m_pszName);
SafeRelease(m_pICrit);
SafeRelease(m_pIAct);
// Save the new values
m_pszName = pszName;
pszName = NULL;
if (FALSE == fDisabled)
{
m_dwState &= ~RULE_STATE_DISABLED;
}
else
{
m_dwState |= RULE_STATE_DISABLED;
}
m_pICrit = pICriteria;
pICriteria = NULL;
m_pIAct = pIActions;
pIActions = NULL;
// Make sure we clear the dirty bit
m_dwState &= ~RULE_STATE_DIRTY;
// Note that we have been loaded
m_dwState |= RULE_STATE_LOADED;
// Set the return value
hr = S_OK;
exit:
SafeMemFree(pszRegPathNew);
SafeRelease(pIActions);
SafeRelease(pICriteria);
SafeMemFree(pszName);
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return hr;
}
STDMETHODIMP COERule::SaveReg(LPCSTR pszRegPath, BOOL fClearDirty)
{
HRESULT hr = S_OK;
LONG lErr = 0;
HKEY hkeyRoot = NULL;
DWORD dwDisp = 0;
DWORD dwData = 0;
LPSTR pszRegPathNew = NULL;
ULONG cchRegPath = 0;
// Check incoming param
if (NULL == pszRegPath)
{
hr = E_INVALIDARG;
goto exit;
}
// Can't save out a rule if we don't have criteria or actions
// or a rule name
if ((NULL == m_pICrit) || (NULL == m_pIAct))
{
hr = E_FAIL;
goto exit;
}
// Let's make sure we clear out the key first
AthUserDeleteKey(pszRegPath);
// Create the reg key from the path
lErr = AthUserCreateKey(pszRegPath, KEY_ALL_ACCESS, &hkeyRoot, &dwDisp);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
Assert(REG_CREATED_NEW_KEY == dwDisp);
// Write out the rule name
if (NULL != m_pszName)
{
lErr = RegSetValueEx(hkeyRoot, c_szRuleName, 0, REG_SZ,
(BYTE *) m_pszName, lstrlen(m_pszName) + 1);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
}
// Write out the disabled state
dwData = !(m_dwState & RULE_STATE_DISABLED);
lErr = RegSetValueEx(hkeyRoot, c_szRuleEnabled, 0, REG_DWORD,
(BYTE *) &dwData, sizeof(dwData));
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Allocate space to hold the new reg path
cchRegPath = lstrlen(pszRegPath);
Assert(lstrlen(c_szRuleCriteria) >= lstrlen(c_szRuleActions));
DWORD cchSize = (cchRegPath + lstrlen(c_szRuleCriteria) + 2);
if (FAILED(HrAlloc((void **) &pszRegPathNew, cchSize)))
{
goto exit;
}
// Build reg path to criteria
StrCpyN(pszRegPathNew, pszRegPath, cchSize);
if ('\\' != pszRegPath[cchRegPath])
{
StrCatBuff(pszRegPathNew, g_szBackSlash, cchSize);
cchRegPath++;
}
StrCatBuff(pszRegPathNew, c_szRuleCriteria, cchSize);
// Write out the criteria
hr = m_pICrit->SaveReg(pszRegPathNew, fClearDirty);
if (FAILED(hr))
{
goto exit;
}
// Build reg path to actions
StrCpyN(pszRegPathNew + cchRegPath, c_szRuleActions, (cchSize - cchRegPath));
// Write out the actions
hr = m_pIAct->SaveReg(pszRegPathNew, fClearDirty);
if (FAILED(hr))
{
goto exit;
}
// Bump up the version
if (0 != (m_dwState & RULE_STATE_DIRTY))
{
m_dwVersion++;
}
lErr = RegSetValueEx(hkeyRoot, c_szRulesVersion, 0, REG_DWORD, (BYTE *) &m_dwVersion, sizeof(m_dwVersion));
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Should we clear the dirty bit?
if (FALSE != fClearDirty)
{
m_dwState &= ~RULE_STATE_DIRTY;
}
// Set the return value
hr = S_OK;
exit:
SafeMemFree(pszRegPathNew);
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return hr;
}
STDMETHODIMP COERule::Clone(IOERule ** ppIRule)
{
HRESULT hr = S_OK;
COERule * pRule = NULL;
// Check incoming params
if (NULL == ppIRule)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the outgoing params
*ppIRule = NULL;
// Create a new rule
pRule = new COERule;
if (NULL == pRule)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Copy over the rule name
if (NULL != m_pszName)
{
pRule->m_pszName = PszDupA(m_pszName);
if (NULL == pRule->m_pszName)
{
hr = E_OUTOFMEMORY;
goto exit;
}
}
// Copy over the enabled state
pRule->m_dwState = m_dwState;
// Copy over the version
pRule->m_dwVersion = m_dwVersion;
// Clone the criteria
if (FAILED(m_pICrit->Clone(&(pRule->m_pICrit))))
{
goto exit;
}
// Clone the actions
if (FAILED(m_pIAct->Clone(&(pRule->m_pIAct))))
{
goto exit;
}
// Get the rule interface
hr = pRule->QueryInterface(IID_IOERule, (void **) ppIRule);
if (FAILED(hr))
{
goto exit;
}
pRule = NULL;
// Set the proper return value
hr = S_OK;
exit:
if (NULL != pRule)
{
delete pRule;
}
return hr;
}
STDMETHODIMP COERule::GetClassID(CLSID * pclsid)
{
HRESULT hr = S_OK;
if (NULL == pclsid)
{
hr = E_INVALIDARG;
goto exit;
}
*pclsid = CLSID_OERule;
// Set the proper return value
hr = S_OK;
exit:
return hr;
}
STDMETHODIMP COERule::IsDirty(void)
{
HRESULT hr = S_OK;
hr = (RULE_STATE_DIRTY == (m_dwState & RULE_STATE_DIRTY)) ? S_OK : S_FALSE;
return hr;
}
STDMETHODIMP COERule::Load(IStream * pStm)
{
HRESULT hr = S_OK;
ULONG cbData = 0;
ULONG cbRead = 0;
DWORD dwData = 0;
LPSTR pszName = NULL;
BOOL fDisabled = FALSE;
IOECriteria * pICriteria = NULL;
IPersistStream * pIPStm = NULL;
IOEActions * pIActions = NULL;
// Check incoming param
if (NULL == pStm)
{
hr = E_INVALIDARG;
goto exit;
}
// Verify we have the correct version
hr = pStm->Read(&dwData, sizeof(dwData), &cbRead);
if (FAILED(hr))
{
goto exit;
}
if ((cbRead != sizeof(dwData)) || (dwData != RULE_VERSION))
{
hr = E_FAIL;
goto exit;
}
// Get the size of the rule name
hr = pStm->Read(&cbData, sizeof(cbData), &cbRead);
if (FAILED(hr))
{
goto exit;
}
if (cbRead != sizeof(cbData))
{
hr = E_FAIL;
goto exit;
}
if (0 != cbData)
{
// Allocate space to hold the rule name
hr = HrAlloc((void **) &pszName, cbData);
if (FAILED(hr))
{
goto exit;
}
// Get the rule name
hr = pStm->Read(pszName, cbData, &cbRead);
if (FAILED(hr))
{
goto exit;
}
if (cbRead != cbData)
{
hr = E_FAIL;
goto exit;
}
}
// Get the enabled state
hr = pStm->Read(&dwData, sizeof(dwData), &cbRead);
if (FAILED(hr))
{
goto exit;
}
if (cbRead != sizeof(dwData))
{
hr = E_FAIL;
goto exit;
}
fDisabled = ! (BOOL) dwData;
// Create a new criteria object
hr = HrCreateCriteria(&pICriteria);
if (FAILED(hr))
{
goto exit;
}
// Get the persistance interface for the criteria
hr = pICriteria->QueryInterface(IID_IPersistStream, (void **) &pIPStm);
if (FAILED(hr))
{
goto exit;
}
// Get the criteria
hr = pIPStm->Load(pStm);
if (FAILED(hr))
{
goto exit;
}
// Create a new actions object
hr = HrCreateActions(&pIActions);
if (FAILED(hr))
{
goto exit;
}
// Get the persistance interface for the actions
pIPStm->Release();
pIPStm = NULL;
hr = pIActions->QueryInterface(IID_IPersistStream, (void **) &pIPStm);
if (FAILED(hr))
{
goto exit;
}
// Get the actions
hr = pIPStm->Load(pStm);
if (FAILED(hr))
{
goto exit;
}
// Free up the current values
SafeMemFree(m_pszName);
SafeRelease(m_pICrit);
SafeRelease(m_pIAct);
// Save the new values
m_pszName = pszName;
pszName = NULL;
if (FALSE == fDisabled)
{
m_dwState &= ~RULE_STATE_DISABLED;
}
else
{
m_dwState |= RULE_STATE_DISABLED;
}
m_pICrit = pICriteria;
pICriteria = NULL;
m_pIAct = pIActions;
pIActions = NULL;
// Make sure we clear the dirty bit
m_dwState &= ~RULE_STATE_DIRTY;
// Note that we have been loaded
m_dwState |= RULE_STATE_LOADED;
// Set the return value
hr = S_OK;
exit:
SafeRelease(pIActions);
SafeRelease(pICriteria);
SafeRelease(pIPStm);
SafeMemFree(pszName);
return hr;
}
STDMETHODIMP COERule::Save(IStream * pStm, BOOL fClearDirty)
{
HRESULT hr = S_OK;
ULONG cbData = 0;
ULONG cbWritten = 0;
DWORD dwData = 0;
ULONG ulIndex = 0;
IPersistStream * pIPStm = NULL;
// Check incoming param
if (NULL == pStm)
{
hr = E_INVALIDARG;
goto exit;
}
// Can't write out a rule if we don't have criteria or actions
// or a rule name
if ((NULL == m_pICrit) || (NULL == m_pIAct))
{
hr = E_FAIL;
goto exit;
}
// Write out the version
dwData = RULE_VERSION;
hr = pStm->Write(&dwData, sizeof(dwData), &cbWritten);
if (FAILED(hr))
{
goto exit;
}
Assert(cbWritten == sizeof(dwData));
// Write out the size of the rule name
if (NULL != m_pszName)
{
cbData = lstrlen(m_pszName) + 1;
}
else
{
cbData = 0;
}
hr = pStm->Write(&cbData, sizeof(cbData), &cbWritten);
if (FAILED(hr))
{
goto exit;
}
Assert(cbWritten == sizeof(cbData));
if (NULL != m_pszName)
{
// Write out the rule name
hr = pStm->Write(m_pszName, cbData, &cbWritten);
if (FAILED(hr))
{
goto exit;
}
Assert(cbWritten == cbData);
}
// Write out the enabled state
dwData = !(m_dwState & RULE_STATE_DISABLED);
hr = pStm->Write(&dwData, sizeof(dwData), &cbWritten);
if (FAILED(hr))
{
goto exit;
}
Assert(cbWritten == sizeof(dwData));
// Get the persistance interface for the criteria
hr = m_pICrit->QueryInterface(IID_IPersistStream, (void **) &pIPStm);
if (FAILED(hr))
{
goto exit;
}
// Write out the criteria
hr = pIPStm->Save(pStm, fClearDirty);
if (FAILED(hr))
{
goto exit;
}
// Get the persistance interface for the actions
pIPStm->Release();
pIPStm = NULL;
hr = m_pIAct->QueryInterface(IID_IPersistStream, (void **) &pIPStm);
if (FAILED(hr))
{
goto exit;
}
// Write out the actions
hr = pIPStm->Save(pStm, fClearDirty);
if (FAILED(hr))
{
goto exit;
}
// Should we clear out the dirty bit
if (FALSE != fClearDirty)
{
m_dwState &= ~RULE_STATE_DIRTY;
}
// Set the return value
hr = S_OK;
exit:
SafeRelease(pIPStm);
return hr;
}