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.
 
 
 
 
 
 

3044 lines
74 KiB

///////////////////////////////////////////////////////////////////////////////
//
// RulesMgr.cpp
//
///////////////////////////////////////////////////////////////////////////////
#include <pch.hxx>
#include "rulesmgr.h"
#include "ruleutil.h"
#include "rule.h"
#include "junkrule.h"
#include <msgfldr.h>
#include <goptions.h>
#include <instance.h>
#include "demand.h"
CRulesManager::CRulesManager() : m_cRef(0), m_dwState(STATE_LOADED_INIT),
m_pMailHead(NULL), m_pNewsHead(NULL), m_pFilterHead(NULL),
m_pIRuleSenderMail(NULL),m_pIRuleSenderNews(NULL),
m_pIRuleJunk(NULL)
{
// Thread Safety
InitializeCriticalSection(&m_cs);
}
CRulesManager::~CRulesManager()
{
AssertSz(m_cRef == 0, "Somebody still has a hold of us!!");
if (NULL != m_pMailHead)
{
_HrFreeRules(RULE_TYPE_MAIL);
}
if (NULL != m_pNewsHead)
{
_HrFreeRules(RULE_TYPE_NEWS);
}
if (NULL != m_pFilterHead)
{
_HrFreeRules(RULE_TYPE_FILTER);
}
SafeRelease(m_pIRuleSenderMail);
SafeRelease(m_pIRuleSenderNews);
SafeRelease(m_pIRuleJunk);
// Thread Safety
DeleteCriticalSection(&m_cs);
}
STDMETHODIMP_(ULONG) CRulesManager::AddRef()
{
return ::InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CRulesManager::Release()
{
LONG cRef = 0;
cRef = ::InterlockedDecrement(&m_cRef);
if (0 == cRef)
{
delete this;
return cRef;
}
return cRef;
}
STDMETHODIMP CRulesManager::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_IOERulesManager))
{
*ppvObject = static_cast<IOERulesManager *>(this);
}
else
{
hr = E_NOINTERFACE;
goto exit;
}
reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();
hr = S_OK;
exit:
return hr;
}
STDMETHODIMP CRulesManager::Initialize(DWORD dwFlags)
{
HRESULT hr = S_OK;
// Check the incoming params
if (0 != dwFlags)
{
hr = E_INVALIDARG;
goto exit;
}
// Set the proper return value
hr = S_OK;
exit:
return hr;
}
STDMETHODIMP CRulesManager::GetRule(RULEID ridRule, RULE_TYPE type, DWORD dwFlags, IOERule ** ppIRule)
{
HRESULT hr = S_OK;
RULENODE * pNodeWalk = NULL;
IOERule * pIRule = NULL;
// Thread Safety
EnterCriticalSection(&m_cs);
// Check the incoming params
if (RULEID_INVALID == ridRule)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the ougoing params
if (NULL != ppIRule)
{
*ppIRule = NULL;
}
// Check to see if we already loaded the rules
hr = _HrLoadRules(type);
if (FAILED(hr))
{
goto exit;
}
// Check the special types
if (RULEID_SENDERS == ridRule)
{
if (RULE_TYPE_MAIL == type)
{
pIRule = m_pIRuleSenderMail;
}
else if (RULE_TYPE_NEWS == type)
{
pIRule = m_pIRuleSenderNews;
}
else
{
hr = E_INVALIDARG;
goto exit;
}
}
else if (RULEID_JUNK == ridRule)
{
if (RULE_TYPE_MAIL != type)
{
hr = E_INVALIDARG;
goto exit;
}
pIRule = m_pIRuleJunk;
}
else
{
// Walk the proper list
if (RULE_TYPE_MAIL == type)
{
pNodeWalk = m_pMailHead;
}
else if (RULE_TYPE_NEWS == type)
{
pNodeWalk = m_pNewsHead;
}
else if (RULE_TYPE_FILTER == type)
{
pNodeWalk = m_pFilterHead;
}
else
{
hr = E_INVALIDARG;
goto exit;
}
for (; NULL != pNodeWalk; pNodeWalk = pNodeWalk->pNext)
{
if (ridRule == pNodeWalk->ridRule)
{
pIRule = pNodeWalk->pIRule;
break;
}
}
}
// Did we find something?
if (NULL == pIRule)
{
hr = E_FAIL;
goto exit;
}
// Set the outgoing param
if (NULL != ppIRule)
{
*ppIRule = pIRule;
(*ppIRule)->AddRef();
}
// Set the proper return value
hr = S_OK;
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
return hr;
}
STDMETHODIMP CRulesManager::FindRule(LPCSTR pszRuleName, RULE_TYPE type, IOERule ** ppIRule)
{
HRESULT hr = S_OK;
RULENODE * pNodeWalk = NULL;
PROPVARIANT propvar;
ZeroMemory(&propvar, sizeof(propvar));
// Thread Safety
EnterCriticalSection(&m_cs);
// Check the incoming params
if ((NULL == pszRuleName) || (NULL == ppIRule))
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the ougoing params
*ppIRule = NULL;
// Check to see if we already loaded the rules
hr = _HrLoadRules(type);
if (FAILED(hr))
{
goto exit;
}
// Walk the proper list
if (RULE_TYPE_MAIL == type)
{
pNodeWalk = m_pMailHead;
}
else if (RULE_TYPE_NEWS == type)
{
pNodeWalk = m_pNewsHead;
}
else if (RULE_TYPE_FILTER == type)
{
pNodeWalk = m_pFilterHead;
}
else
{
hr = E_INVALIDARG;
goto exit;
}
while (NULL != pNodeWalk)
{
// Check to see if the name of the rule is the same
hr = pNodeWalk->pIRule->GetProp(RULE_PROP_NAME , 0, &propvar);
if (FAILED(hr))
{
continue;
}
if (0 == lstrcmpi(propvar.pszVal, pszRuleName))
{
*ppIRule = pNodeWalk->pIRule;
(*ppIRule)->AddRef();
break;
}
// Move to the next one
PropVariantClear(&propvar);
pNodeWalk = pNodeWalk->pNext;
}
// Set the proper return value
if (NULL == pNodeWalk)
{
hr = E_FAIL;
}
else
{
hr = S_OK;
}
exit:
PropVariantClear(&propvar);
// Thread Safety
LeaveCriticalSection(&m_cs);
return hr;
}
STDMETHODIMP CRulesManager::GetRules(DWORD dwFlags, RULE_TYPE typeRule, RULEINFO ** ppinfoRule, ULONG * pcpinfoRule)
{
HRESULT hr = S_OK;
ULONG cpinfoRule = 0;
RULEINFO * pinfoRuleAlloc = NULL;
IOERule * pIRuleSender = NULL;
RULENODE * prnodeList = NULL;
RULENODE * prnodeWalk = NULL;
ULONG ulIndex = 0;
// Thread Safety
EnterCriticalSection(&m_cs);
// Check the incoming params
if (NULL == ppinfoRule)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the outgoing param
*ppinfoRule = NULL;
if (NULL != pcpinfoRule)
{
*pcpinfoRule = 0;
}
// Check to see if we already loaded the rules
hr = _HrLoadRules(typeRule);
if (FAILED(hr))
{
goto exit;
}
// Figure out which type of rules to work on
switch (typeRule)
{
case RULE_TYPE_MAIL:
prnodeList = m_pMailHead;
break;
case RULE_TYPE_NEWS:
prnodeList = m_pNewsHead;
break;
case RULE_TYPE_FILTER:
prnodeList = m_pFilterHead;
break;
default:
hr = E_INVALIDARG;
goto exit;
}
// Count the number of rules
prnodeWalk = prnodeList;
for (cpinfoRule = 0; NULL != prnodeWalk; prnodeWalk = prnodeWalk->pNext)
{
// Check to see if we should add this item
if (RULE_TYPE_FILTER == typeRule)
{
if (0 != (dwFlags & GETF_POP3))
{
if (RULEID_VIEW_DOWNLOADED == prnodeWalk->ridRule)
{
continue;
}
}
}
cpinfoRule++;
}
// Allocate space to hold the rules
if (0 != cpinfoRule)
{
hr = HrAlloc((VOID **) &pinfoRuleAlloc, cpinfoRule * sizeof(*pinfoRuleAlloc));
if (FAILED(hr))
{
goto exit;
}
// Initialize it to known values
ZeroMemory(pinfoRuleAlloc, cpinfoRule * sizeof(*pinfoRuleAlloc));
// Fill up the info
for (ulIndex = 0, prnodeWalk = prnodeList; NULL != prnodeWalk; prnodeWalk = prnodeWalk->pNext)
{
// Check to see if we should add this item
if (RULE_TYPE_FILTER == typeRule)
{
if (0 != (dwFlags & GETF_POP3))
{
if (RULEID_VIEW_DOWNLOADED == prnodeWalk->ridRule)
{
continue;
}
}
}
pinfoRuleAlloc[ulIndex].ridRule = prnodeWalk->ridRule;
pinfoRuleAlloc[ulIndex].pIRule = prnodeWalk->pIRule;
pinfoRuleAlloc[ulIndex].pIRule->AddRef();
ulIndex++;
}
}
// Set the outgoing values
*ppinfoRule = pinfoRuleAlloc;
pinfoRuleAlloc = NULL;
if (NULL != pcpinfoRule)
{
*pcpinfoRule = cpinfoRule;
}
// Set the proper return type
hr = S_OK;
exit:
SafeMemFree(pinfoRuleAlloc);
// Thread Safety
LeaveCriticalSection(&m_cs);
return S_OK;
}
STDMETHODIMP CRulesManager::SetRules(DWORD dwFlags, RULE_TYPE typeRule, RULEINFO * pinfoRule, ULONG cpinfoRule)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
IOERule * pIRuleSender = NULL;
// Thread Safety
EnterCriticalSection(&m_cs);
// Check the incoming params
if ((NULL == pinfoRule) && (0 != cpinfoRule))
{
hr = E_INVALIDARG;
goto exit;
}
// Check to see if we already loaded the rules
hr = _HrLoadRules(typeRule);
if (FAILED(hr))
{
goto exit;
}
// Do we have to free all the current rules
if (0 != (dwFlags & SETF_SENDER))
{
if (RULE_TYPE_MAIL == typeRule)
{
SafeRelease(m_pIRuleSenderMail);
m_pIRuleSenderMail = pinfoRule->pIRule;
if (NULL != m_pIRuleSenderMail)
{
m_pIRuleSenderMail->AddRef();
}
}
else if (RULE_TYPE_NEWS == typeRule)
{
SafeRelease(m_pIRuleSenderNews);
m_pIRuleSenderNews = pinfoRule->pIRule;
if (NULL != m_pIRuleSenderNews)
{
m_pIRuleSenderNews->AddRef();
}
}
else
{
hr = E_INVALIDARG;
goto exit;
}
}
else if (0 != (dwFlags & SETF_JUNK))
{
if (RULE_TYPE_MAIL != typeRule)
{
hr = E_INVALIDARG;
goto exit;
}
SafeRelease(m_pIRuleJunk);
m_pIRuleJunk = pinfoRule->pIRule;
if (NULL != m_pIRuleJunk)
{
m_pIRuleJunk->AddRef();
}
}
else
{
if (0 != (dwFlags & SETF_CLEAR))
{
_HrFreeRules(typeRule);
}
// for each new rule
for (ulIndex = 0; ulIndex < cpinfoRule; ulIndex++)
{
if (0 != (dwFlags & SETF_REPLACE))
{
// Add the rule to the list
hr = _HrReplaceRule(pinfoRule[ulIndex].ridRule, pinfoRule[ulIndex].pIRule, typeRule);
if (FAILED(hr))
{
goto exit;
}
}
else
{
// Add the rule to the list
hr = _HrAddRule(pinfoRule[ulIndex].ridRule, pinfoRule[ulIndex].pIRule, typeRule);
if (FAILED(hr))
{
goto exit;
}
}
}
}
// Save the rules
hr = _HrSaveRules(typeRule);
if (FAILED(hr))
{
goto exit;
}
if ((0 == (dwFlags & SETF_SENDER)) && (0 == (dwFlags & SETF_JUNK)))
{
// Fix up the rule ids
hr = _HrFixupRuleInfo(typeRule, pinfoRule, cpinfoRule);
if (FAILED(hr))
{
goto exit;
}
}
// Set the proper return value
hr = S_OK;
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
return hr;
}
STDMETHODIMP CRulesManager::EnumRules(DWORD dwFlags, RULE_TYPE type, IOEEnumRules ** ppIEnumRules)
{
HRESULT hr = S_OK;
CEnumRules * pEnumRules = NULL;
RULENODE rnode;
RULENODE * prnode = NULL;
IOERule * pIRuleSender = NULL;
// Thread Safety
EnterCriticalSection(&m_cs);
// Check the incoming params
if (NULL == ppIEnumRules)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize outgoing params
*ppIEnumRules = NULL;
// Check to see if we already loaded the rules
hr = _HrLoadRules(type);
if (FAILED(hr))
{
goto exit;
}
// Create the rules enumerator object
pEnumRules = new CEnumRules;
if (NULL == pEnumRules)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Initialize the rules enumerator
if (0 != (dwFlags & ENUMF_SENDER))
{
if (RULE_TYPE_MAIL == type)
{
pIRuleSender = m_pIRuleSenderMail;
}
else if (RULE_TYPE_NEWS == type)
{
pIRuleSender = m_pIRuleSenderNews;
}
else
{
hr = E_INVALIDARG;
goto exit;
}
if (NULL != pIRuleSender)
{
ZeroMemory(&rnode, sizeof(rnode));
rnode.pIRule = pIRuleSender;
prnode = &rnode;
}
else
{
prnode = NULL;
}
}
else
{
if (RULE_TYPE_MAIL == type)
{
prnode = m_pMailHead;
}
else if (RULE_TYPE_NEWS == type)
{
prnode = m_pNewsHead;
}
else if (RULE_TYPE_FILTER == type)
{
prnode = m_pFilterHead;
}
else
{
hr = E_INVALIDARG;
goto exit;
}
}
hr = pEnumRules->_HrInitialize(0, type, prnode);
if (FAILED(hr))
{
goto exit;
}
// Get the rules enumerator interface
hr = pEnumRules->QueryInterface(IID_IOEEnumRules, (void **) ppIEnumRules);
if (FAILED(hr))
{
goto exit;
}
pEnumRules = NULL;
hr = S_OK;
exit:
if (NULL != pEnumRules)
{
delete pEnumRules;
}
// Thread Safety
LeaveCriticalSection(&m_cs);
return hr;
}
STDMETHODIMP CRulesManager::ExecRules(DWORD dwFlags, RULE_TYPE type, IOEExecRules ** ppIExecRules)
{
HRESULT hr = S_OK;
CExecRules * pExecRules = NULL;
RULENODE rnode;
RULENODE * prnodeList = NULL;
// Thread Safety
EnterCriticalSection(&m_cs);
// Check the incoming params
if (NULL == ppIExecRules)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize outgoing params
*ppIExecRules = NULL;
// Check to see if we already loaded the rules
hr = _HrLoadRules(type);
if (FAILED(hr))
{
goto exit;
}
// Create the rules enumerator object
pExecRules = new CExecRules;
if (NULL == pExecRules)
{
hr = E_OUTOFMEMORY;
goto exit;
}
if (RULE_TYPE_MAIL == type)
{
prnodeList = m_pMailHead;
}
else if (RULE_TYPE_NEWS == type)
{
prnodeList = m_pNewsHead;
}
else
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the rules enumerator
hr = pExecRules->_HrInitialize(ERF_ONLY_ENABLED | ERF_ONLY_VALID, prnodeList);
if (FAILED(hr))
{
goto exit;
}
// Get the rules enumerator interface
hr = pExecRules->QueryInterface(IID_IOEExecRules, (void **) ppIExecRules);
if (FAILED(hr))
{
goto exit;
}
pExecRules = NULL;
hr = S_OK;
exit:
if (NULL != pExecRules)
{
delete pExecRules;
}
// Thread Safety
LeaveCriticalSection(&m_cs);
return hr;
}
STDMETHODIMP CRulesManager::ExecuteRules(RULE_TYPE typeRule, DWORD dwFlags, HWND hwndUI, IOEExecRules * pIExecRules,
MESSAGEINFO * pMsgInfo, IMessageFolder * pFolder, IMimeMessage * pIMMsg)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
RULENODE * prnodeHead = NULL;
PROPVARIANT propvar = {0};
ACT_ITEM * pActions = NULL;
ULONG cActions = 0;
ACT_ITEM * pActionsList = NULL;
ULONG cActionsList = 0;
ACT_ITEM * pActionsNew = NULL;
ULONG cActionsNew = 0;
BOOL fStopProcessing = FALSE;
BOOL fMatch = FALSE;
// Thread Safety
EnterCriticalSection(&m_cs);
// Check incoming params
if ((NULL == pIExecRules) || (NULL == pMsgInfo))
{
hr = E_INVALIDARG;
goto exit;
}
// Check to see if we already loaded the rules
hr = _HrLoadRules(typeRule);
if (FAILED(hr))
{
goto exit;
}
// Figure out which list to use
switch (typeRule)
{
case RULE_TYPE_MAIL:
prnodeHead = m_pMailHead;
break;
case RULE_TYPE_NEWS:
prnodeHead = m_pNewsHead;
break;
default:
Assert(FALSE);
hr = E_INVALIDARG;
goto exit;
}
// For each rule
for (; NULL != prnodeHead; prnodeHead = prnodeHead->pNext)
{
// Skip if we don't have a rule
if (NULL == prnodeHead)
{
continue;
}
// Skip if it isn't enabled
hr = prnodeHead->pIRule->GetProp(RULE_PROP_DISABLED, 0, &propvar);
Assert(VT_BOOL == propvar.vt);
if (FAILED(hr) || (FALSE != propvar.boolVal))
{
continue;
}
// Execute rule
hr = prnodeHead->pIRule->Evaluate(pMsgInfo->pszAcctId, pMsgInfo, pFolder,
NULL, pIMMsg, pMsgInfo->cbMessage, &pActions, &cActions);
if (FAILED(hr))
{
goto exit;
}
// Did we have a match
if (S_OK == hr)
{
// We've matched at least once
fMatch = TRUE;
// If these are server actions
if ((1 == cActions) && ((ACT_TYPE_DELETESERVER == pActions[ulIndex].type) ||
(ACT_TYPE_DONTDOWNLOAD == pActions[ulIndex].type)))
{
// If this is our only action
if (0 == cActionsList)
{
// Save the action
pActionsList = pActions;
pActions = NULL;
cActionsList = cActions;
// We are done
fStopProcessing = TRUE;
}
else
{
// We already have to do something with it
// so skip over this action
RuleUtil_HrFreeActionsItem(pActions, cActions);
SafeMemFree(pActions);
continue;
}
}
else
{
// Should we stop after merging these?
for (ulIndex = 0; ulIndex < cActions; ulIndex++)
{
if (ACT_TYPE_STOP == pActions[ulIndex].type)
{
fStopProcessing = TRUE;
break;
}
}
// Merge these items with the previous ones
hr = RuleUtil_HrMergeActions(pActionsList, cActionsList, pActions, cActions, &pActionsNew, &cActionsNew);
if (FAILED(hr))
{
goto exit;
}
// Free up the previous ones
RuleUtil_HrFreeActionsItem(pActionsList, cActionsList);
SafeMemFree(pActionsList);
RuleUtil_HrFreeActionsItem(pActions, cActions);
SafeMemFree(pActions);
// Save off the new ones
pActionsList = pActionsNew;
pActionsNew = NULL;
cActionsList = cActionsNew;
}
// Should we continue...
if (FALSE != fStopProcessing)
{
break;
}
}
}
// Apply the actions if need be
if ((FALSE != fMatch) && (NULL != pActionsList) && (0 != cActionsList))
{
if (FAILED(RuleUtil_HrApplyActions(hwndUI, pIExecRules, pMsgInfo, pFolder, pIMMsg,
(RULE_TYPE_MAIL != typeRule) ? DELETE_MESSAGE_NOTRASHCAN : 0, pActionsList, cActionsList, NULL, NULL)))
{
hr = E_FAIL;
goto exit;
}
}
// Set the return value
hr = (FALSE != fMatch) ? S_OK : S_FALSE;
exit:
// Thread Safety
RuleUtil_HrFreeActionsItem(pActionsNew, cActionsNew);
SafeMemFree(pActionsNew);
RuleUtil_HrFreeActionsItem(pActions, cActions);
SafeMemFree(pActions);
RuleUtil_HrFreeActionsItem(pActionsList, cActionsList);
SafeMemFree(pActionsList);
LeaveCriticalSection(&m_cs);
return hr;
}
HRESULT CRulesManager::_HrLoadRules(RULE_TYPE type)
{
HRESULT hr = S_OK;
LPCSTR pszSubKey = NULL;
LPSTR pszOrderAlloc = NULL;
LPSTR pszOrder = NULL;
LPSTR pszWalk = NULL;
HKEY hkeyRoot = NULL;
DWORD dwDisp = 0;
LONG lErr = 0;
ULONG cbData = 0;
IOERule * pIRule = NULL;
DWORD dwData = 0;
CHAR rgchRulePath[MAX_PATH];
ULONG cchRulePath = 0;
PROPVARIANT propvar = {0};
RULEID ridRule = RULEID_INVALID;
CHAR rgchTagBuff[CCH_INDEX_MAX + 2];
// Check to see if we're already initialized
if (RULE_TYPE_MAIL == type)
{
if (0 != (m_dwState & STATE_LOADED_MAIL))
{
hr = S_FALSE;
goto exit;
}
// Make sure we loaded the sender rules
_HrLoadSenders();
// Make sure we loaded the junk rule
if (0 != (g_dwAthenaMode & MODE_JUNKMAIL))
{
_HrLoadJunk();
}
// Set the key path
pszSubKey = c_szRulesMail;
}
else if (RULE_TYPE_NEWS == type)
{
if (0 != (m_dwState & STATE_LOADED_NEWS))
{
hr = S_FALSE;
goto exit;
}
// Make sure we loaded the sender rules
_HrLoadSenders();
// Set the key path
pszSubKey = c_szRulesNews;
}
else if (RULE_TYPE_FILTER == type)
{
if (0 != (m_dwState & STATE_LOADED_FILTERS))
{
hr = S_FALSE;
goto exit;
}
// Set the key path
pszSubKey = c_szRulesFilter;
}
else
{
hr = E_INVALIDARG;
goto exit;
}
// Check to see if the Rule node already exists
lErr = AthUserCreateKey(pszSubKey, KEY_ALL_ACCESS, &hkeyRoot, &dwDisp);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Check the current version
cbData = sizeof(dwData);
lErr = RegQueryValueEx(hkeyRoot, c_szRulesVersion, NULL, NULL, (BYTE *) &dwData, &cbData);
if (ERROR_SUCCESS != lErr)
{
// Push out the correct rules manager version
dwData = RULESMGR_VERSION;
lErr = RegSetValueEx(hkeyRoot, c_szRulesVersion, 0, REG_DWORD, (CONST BYTE *) &dwData, sizeof(dwData));
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
}
Assert(RULESMGR_VERSION == dwData);
// Create the default rules if needed
hr = RuleUtil_HrUpdateDefaultRules(type);
if (FAILED(hr))
{
goto exit;
}
// Figure out the size of the order
lErr = AthUserGetValue(pszSubKey, c_szRulesOrder, NULL, NULL, &cbData);
if ((ERROR_SUCCESS != lErr) && (ERROR_FILE_NOT_FOUND != lErr))
{
hr = E_FAIL;
goto exit;
}
if (ERROR_FILE_NOT_FOUND != lErr)
{
// Allocate the space to hold the order
hr = HrAlloc((void **) &pszOrderAlloc, cbData);
if (FAILED(hr))
{
goto exit;
}
// Get the order from the registry
lErr = AthUserGetValue(pszSubKey, c_szRulesOrder, NULL, (LPBYTE) pszOrderAlloc, &cbData);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Build up the rule registry path
StrCpyN(rgchRulePath, pszSubKey, ARRAYSIZE(rgchRulePath));
StrCatBuff(rgchRulePath, g_szBackSlash, ARRAYSIZE(rgchRulePath));
cchRulePath = lstrlen(rgchRulePath);
// Initialize the rule tag buffer
rgchTagBuff[0] = '0';
rgchTagBuff[1] = 'X';
// Parse the order string to create the rules
pszOrder = pszOrderAlloc;
while ('\0' != *pszOrder)
{
SafeRelease(pIRule);
// Create a new rule
hr = HrCreateRule(&pIRule);
if (FAILED(hr))
{
goto exit;
}
// Find the name of the new rule
pszWalk = StrStr(pszOrder, g_szSpace);
if (NULL != pszWalk)
{
*pszWalk = '\0';
pszWalk++;
}
// Build the path to the rule
StrCpyN(rgchRulePath + cchRulePath, pszOrder, ARRAYSIZE(rgchRulePath) - cchRulePath);
// Load the rule
hr = pIRule->LoadReg(rgchRulePath);
if (SUCCEEDED(hr))
{
// Build the correct hex string
StrCpyN(rgchTagBuff + 2, pszOrder, ARRAYSIZE(rgchTagBuff) - 2);
// Get the new rule handle
ridRule = ( ( RULEID ) 0);
SideAssert(FALSE != StrToIntEx(rgchTagBuff, STIF_SUPPORT_HEX, (INT *) &ridRule));
// Add the new rule to the manager
hr = _HrAddRule(ridRule, pIRule, type);
if (FAILED(hr))
{
goto exit;
}
}
// Move to the next item in the order
if (NULL == pszWalk)
{
pszOrder += lstrlen(pszOrder);
}
else
{
pszOrder = pszWalk;
}
}
}
// We've loaded the rules successfully
if (RULE_TYPE_MAIL == type)
{
m_dwState |= STATE_LOADED_MAIL;
}
else if (RULE_TYPE_NEWS == type)
{
m_dwState |= STATE_LOADED_NEWS;
}
else
{
m_dwState |= STATE_LOADED_FILTERS;
}
// Set the return value
hr = S_OK;
exit:
SafeMemFree(pszOrderAlloc);
SafeRelease(pIRule);
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return hr;
}
HRESULT CRulesManager::_HrLoadSenders(VOID)
{
HRESULT hr = S_OK;
HKEY hkeyRoot = NULL;
DWORD dwDisp = 0;
DWORD dwData = 0;
LONG lErr = 0;
ULONG cbData = 0;
IOERule * pIRule = NULL;
CHAR rgchSenderPath[MAX_PATH];
// Do we have anything to do?
if (0 != (m_dwState & STATE_LOADED_SENDERS))
{
hr = S_FALSE;
goto exit;
}
// Let's get access to the sender root key
lErr = AthUserCreateKey(c_szSenders, KEY_ALL_ACCESS, &hkeyRoot, &dwDisp);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Are the senders the correct version?
cbData = sizeof(dwData);
lErr = RegQueryValueEx(hkeyRoot, c_szSendersVersion, 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 = RULESMGR_VERSION;
cbData = sizeof(dwData);
lErr = RegSetValueEx(hkeyRoot, c_szSendersVersion, 0, REG_DWORD, (BYTE *) &dwData, cbData);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
}
Assert(dwData == RULESMGR_VERSION);
// Is there anything to do?
if (REG_CREATED_NEW_KEY != dwDisp)
{
// Create the path to the sender
StrCpyN(rgchSenderPath, c_szSenders, ARRAYSIZE(rgchSenderPath));
StrCatBuff(rgchSenderPath, g_szBackSlash, ARRAYSIZE(rgchSenderPath));
StrCatBuff(rgchSenderPath, c_szMailDir, ARRAYSIZE(rgchSenderPath));
// Create the mail sender rule
hr = RuleUtil_HrLoadSender(rgchSenderPath, 0, &pIRule);
if (FAILED(hr))
{
goto exit;
}
// Save the loaded rule
if (S_OK == hr)
{
m_pIRuleSenderMail = pIRule;
pIRule = NULL;
}
// Create the path to the sender
StrCpyN(rgchSenderPath, c_szSenders, ARRAYSIZE(rgchSenderPath));
StrCatBuff(rgchSenderPath, g_szBackSlash, ARRAYSIZE(rgchSenderPath));
StrCatBuff(rgchSenderPath, c_szNewsDir, ARRAYSIZE(rgchSenderPath));
// Create the news sender rule
hr = RuleUtil_HrLoadSender(rgchSenderPath, 0, &pIRule);
if (FAILED(hr))
{
goto exit;
}
// Save the loaded rule
if (S_OK == hr)
{
m_pIRuleSenderNews = pIRule;
pIRule = NULL;
}
}
// Note that we've loaded the senders
m_dwState |= STATE_LOADED_SENDERS;
// Set the return value
hr = S_OK;
exit:
SafeRelease(pIRule);
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return hr;
}
HRESULT CRulesManager::_HrLoadJunk(VOID)
{
HRESULT hr = S_OK;
HKEY hkeyRoot = NULL;
DWORD dwDisp = 0;
DWORD dwData = 0;
ULONG cbData = 0;
LONG lErr = 0;
IOERule * pIRule = NULL;
// Do we have anything to do?
if (0 != (m_dwState & STATE_LOADED_JUNK))
{
hr = S_FALSE;
goto exit;
}
// Let's get access to the Junk mail root key
lErr = AthUserCreateKey(c_szRulesJunkMail, KEY_ALL_ACCESS, &hkeyRoot, &dwDisp);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Is the junk mail the correct version?
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 = RULESMGR_VERSION;
cbData = sizeof(dwData);
lErr = RegSetValueEx(hkeyRoot, c_szRulesVersion, 0, REG_DWORD, (BYTE *) &dwData, cbData);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
}
Assert(dwData == RULESMGR_VERSION);
// Create the rule
hr = HrCreateJunkRule(&pIRule);
if (FAILED(hr))
{
goto exit;
}
// Load the junk rule
hr = pIRule->LoadReg(c_szRulesJunkMail);
if (FAILED(hr))
{
goto exit;
}
m_pIRuleJunk = pIRule;
pIRule = NULL;
// Note that we've loaded the junk rule
m_dwState |= STATE_LOADED_JUNK;
// Set the return value
hr = S_OK;
exit:
SafeRelease(pIRule);
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return hr;
}
HRESULT CRulesManager::_HrSaveRules(RULE_TYPE type)
{
HRESULT hr = S_OK;
LPCSTR pszRegPath = NULL;
DWORD dwData = 0;
LONG lErr = 0;
RULENODE * pRuleNode = NULL;
RULENODE * pNodeWalk = NULL;
ULONG cpIRule = 0;
LPSTR pszOrder = NULL;
HKEY hkeyRoot = NULL;
DWORD dwIndex = 0;
CHAR rgchOrder[CCH_INDEX_MAX];
ULONG cchOrder = 0;
CHAR rgchRulePath[MAX_PATH];
ULONG cchRulePath = 0;
BOOL fNewRule = FALSE;
ULONG ulRuleID = 0;
HKEY hkeyDummy = NULL;
LONG cSubKeys = 0;
// Make sure we loaded the sender rules
_HrSaveSenders();
// Make sure we loaded the junk rules
if (0 != (g_dwAthenaMode & MODE_JUNKMAIL))
{
_HrSaveJunk();
}
// Check to see if we have anything to save
if (RULE_TYPE_MAIL == type)
{
if (0 == (m_dwState & STATE_LOADED_MAIL))
{
hr = S_FALSE;
goto exit;
}
// Set the key path
pszRegPath = c_szRulesMail;
pRuleNode = m_pMailHead;
}
else if (RULE_TYPE_NEWS == type)
{
if (0 == (m_dwState & STATE_LOADED_NEWS))
{
hr = S_FALSE;
goto exit;
}
// Set the key path
pszRegPath = c_szRulesNews;
pRuleNode = m_pNewsHead;
}
else if (RULE_TYPE_FILTER == type)
{
if (0 == (m_dwState & STATE_LOADED_FILTERS))
{
hr = S_FALSE;
goto exit;
}
// Set the key path
pszRegPath = c_szRulesFilter;
pRuleNode = m_pFilterHead;
}
else
{
hr = E_INVALIDARG;
goto exit;
}
lErr = AthUserCreateKey(pszRegPath, KEY_ALL_ACCESS, &hkeyRoot, &dwData);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Save out the rules version
dwData = RULESMGR_VERSION;
lErr = RegSetValueEx(hkeyRoot, c_szRulesVersion, 0, REG_DWORD, (CONST BYTE *) &dwData, sizeof(dwData));
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Get the number of rules
cpIRule = 0;
for (pNodeWalk = pRuleNode; NULL != pNodeWalk; pNodeWalk = pNodeWalk->pNext)
{
cpIRule++;
}
// Allocate space to hold the order
DWORD cchSize = ((cpIRule * CCH_INDEX_MAX) + 1);
hr = HrAlloc((void **) &pszOrder, cchSize);
if (FAILED(hr))
{
goto exit;
}
pszOrder[0] = '\0';
// Delete all the old rules
lErr = SHQueryInfoKey(hkeyRoot, (LPDWORD) (&cSubKeys), NULL, NULL, NULL);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Delete all the old rules
for (cSubKeys--; cSubKeys >= 0; cSubKeys--)
{
cchOrder = sizeof(rgchOrder);
lErr = SHEnumKeyEx(hkeyRoot, cSubKeys, rgchOrder, &cchOrder);
if (ERROR_NO_MORE_ITEMS == lErr)
{
break;
}
if (ERROR_SUCCESS != lErr)
{
continue;
}
SHDeleteKey(hkeyRoot, rgchOrder);
}
// Delete the old order string
RegDeleteValue(hkeyRoot, c_szRulesOrder);
// Build up the rule registry path
StrCpyN(rgchRulePath, pszRegPath, ARRAYSIZE(rgchRulePath));
StrCatBuff(rgchRulePath, g_szBackSlash, ARRAYSIZE(rgchRulePath));
cchRulePath = lstrlen(rgchRulePath);
// Write out the rules with good tags
for (dwIndex = 0, pNodeWalk = pRuleNode; NULL != pNodeWalk; pNodeWalk = pNodeWalk->pNext, dwIndex++)
{
if (RULEID_INVALID == pNodeWalk->ridRule)
{
fNewRule = TRUE;
continue;
}
// Get a new index from the order
wnsprintf(rgchOrder, ARRAYSIZE(rgchOrder), "%03X", pNodeWalk->ridRule);
// Build the path to the rule
StrCpyN(rgchRulePath + cchRulePath, rgchOrder, ARRAYSIZE(rgchRulePath) - cchRulePath);
// Save the rule
hr = pNodeWalk->pIRule->SaveReg(rgchRulePath, TRUE);
if (FAILED(hr))
{
goto exit;
}
}
// Fill in the new tags
if (FALSE != fNewRule)
{
ulRuleID = 0;
// Write out the updated rule
for (dwIndex = 0, pNodeWalk = pRuleNode; NULL != pNodeWalk; pNodeWalk = pNodeWalk->pNext, dwIndex++)
{
if (RULEID_INVALID != pNodeWalk->ridRule)
{
continue;
}
// Find the first open entry
for (; ulRuleID < PtrToUlong(RULEID_JUNK); ulRuleID++)
{
// Get a new index from the order
wnsprintf(rgchOrder, ARRAYSIZE(rgchOrder), "%03X", ulRuleID);
lErr = RegOpenKeyEx(hkeyRoot, rgchOrder, 0, KEY_READ, &hkeyDummy);
if (ERROR_SUCCESS == lErr)
{
RegCloseKey(hkeyDummy);
}
else
{
break;
}
}
if (ERROR_FILE_NOT_FOUND != lErr)
{
hr = E_FAIL;
goto exit;
}
// Set the rule tag
pNodeWalk->ridRule = (RULEID) IntToPtr(ulRuleID);
// Build the path to the rule
StrCpyN(rgchRulePath + cchRulePath, rgchOrder, ARRAYSIZE(rgchRulePath) - cchRulePath);
// Save the rule
hr = pNodeWalk->pIRule->SaveReg(rgchRulePath, TRUE);
if (FAILED(hr))
{
goto exit;
}
}
}
// Write out the new order string
for (dwIndex = 0, pNodeWalk = pRuleNode; NULL != pNodeWalk; pNodeWalk = pNodeWalk->pNext, dwIndex++)
{
// Get a new index from the order
wnsprintf(rgchOrder, ARRAYSIZE(rgchOrder), "%03X", pNodeWalk->ridRule);
// Add rule to the order
if ('\0' != pszOrder[0])
{
StrCatBuff(pszOrder, g_szSpace, cchSize);
}
StrCatBuff(pszOrder, rgchOrder, cchSize);
}
// Save the order string
if (ERROR_SUCCESS != AthUserSetValue(pszRegPath, c_szRulesOrder, REG_SZ, (CONST BYTE *) pszOrder, lstrlen(pszOrder) + 1))
{
hr = E_FAIL;
goto exit;
}
// Set the return value
hr = S_OK;
exit:
SafeMemFree(pszOrder);
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return hr;
}
HRESULT CRulesManager::_HrSaveSenders(VOID)
{
HRESULT hr = S_OK;
DWORD dwData = 0;
LONG lErr = 0;
HKEY hkeyRoot = NULL;
DWORD dwIndex = 0;
CHAR rgchSenderPath[MAX_PATH];
// Check to see if we have anything to save
if (0 == (m_dwState & STATE_LOADED_SENDERS))
{
hr = S_FALSE;
goto exit;
}
lErr = AthUserCreateKey(c_szSenders, KEY_ALL_ACCESS, &hkeyRoot, &dwData);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Save out the senders version
dwData = RULESMGR_VERSION;
lErr = RegSetValueEx(hkeyRoot, c_szSendersVersion, 0, REG_DWORD, (CONST BYTE *) &dwData, sizeof(dwData));
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Delete the old sender list
SHDeleteKey(hkeyRoot, c_szMailDir);
// Build up the sender registry path
StrCpyN(rgchSenderPath, c_szSenders, ARRAYSIZE(rgchSenderPath));
StrCatBuff(rgchSenderPath, g_szBackSlash, ARRAYSIZE(rgchSenderPath));
StrCatBuff(rgchSenderPath, c_szMailDir, ARRAYSIZE(rgchSenderPath));
// Save the rule
if (NULL != m_pIRuleSenderMail)
{
hr = m_pIRuleSenderMail->SaveReg(rgchSenderPath, TRUE);
if (FAILED(hr))
{
goto exit;
}
}
// Delete the old sender list
SHDeleteKey(hkeyRoot, c_szNewsDir);
// Build up the sender registry path
StrCpyN(rgchSenderPath, c_szSenders, ARRAYSIZE(rgchSenderPath));
StrCatBuff(rgchSenderPath, g_szBackSlash, ARRAYSIZE(rgchSenderPath));
StrCatBuff(rgchSenderPath, c_szNewsDir, ARRAYSIZE(rgchSenderPath));
// Save the rule
if (NULL != m_pIRuleSenderNews)
{
hr = m_pIRuleSenderNews->SaveReg(rgchSenderPath, TRUE);
if (FAILED(hr))
{
goto exit;
}
}
// Set the return value
hr = S_OK;
exit:
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return hr;
}
HRESULT CRulesManager::_HrSaveJunk(VOID)
{
HRESULT hr = S_OK;
DWORD dwData = 0;
LONG lErr = 0;
HKEY hkeyRoot = NULL;
DWORD dwIndex = 0;
CHAR rgchSenderPath[MAX_PATH];
// Check to see if we have anything to save
if (0 == (m_dwState & STATE_LOADED_JUNK))
{
hr = S_FALSE;
goto exit;
}
lErr = AthUserCreateKey(c_szRulesJunkMail, KEY_ALL_ACCESS, &hkeyRoot, &dwData);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Save out the senders version
dwData = RULESMGR_VERSION;
lErr = RegSetValueEx(hkeyRoot, c_szRulesVersion, 0, REG_DWORD, (CONST BYTE *) &dwData, sizeof(dwData));
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Save the rule
if (NULL != m_pIRuleJunk)
{
hr = m_pIRuleJunk->SaveReg(c_szRulesJunkMail, TRUE);
if (FAILED(hr))
{
goto exit;
}
}
// Set the return value
hr = S_OK;
exit:
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return hr;
}
HRESULT CRulesManager::_HrFreeRules(RULE_TYPE type)
{
HRESULT hr = S_OK;
RULENODE * pNodeWalk = NULL;
RULENODE * pNodeNext = NULL;
// Initialize the params
if (RULE_TYPE_MAIL == type)
{
pNodeWalk = m_pMailHead;
pNodeNext = m_pMailHead;
}
else if (RULE_TYPE_NEWS == type)
{
pNodeWalk = m_pNewsHead;
pNodeNext = m_pNewsHead;
}
else if (RULE_TYPE_FILTER == type)
{
pNodeWalk = m_pFilterHead;
pNodeNext = m_pFilterHead;
}
else
{
hr = E_FAIL;
goto exit;
}
// Walk the list and free each item
while (NULL != pNodeWalk)
{
// Save off the next item
pNodeNext = pNodeWalk->pNext;
// Release the rule
AssertSz(NULL != pNodeWalk->pIRule, "Where the heck is the rule???");
pNodeWalk->pIRule->Release();
// Free up the node
delete pNodeWalk;
// Move to the next item
pNodeWalk = pNodeNext;
}
// Clear out the list head
if (RULE_TYPE_MAIL == type)
{
m_pMailHead = NULL;
}
else if (RULE_TYPE_NEWS == type)
{
m_pNewsHead = NULL;
}
else
{
m_pFilterHead = NULL;
}
exit:
// Set the return param
return hr;
}
HRESULT CRulesManager::_HrAddRule(RULEID ridRule, IOERule * pIRule, RULE_TYPE type)
{
HRESULT hr = S_OK;
RULENODE * pRuleNode = NULL;
RULENODE * pNodeWalk = NULL;
// Check incoming params
if (NULL == pIRule)
{
hr = E_INVALIDARG;
goto exit;
}
// Create a new rule node
pRuleNode = new RULENODE;
if (NULL == pRuleNode)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Initialize the node
pRuleNode->pNext = NULL;
pRuleNode->ridRule = ridRule;
pRuleNode->pIRule = pIRule;
pRuleNode->pIRule->AddRef();
// Add the node to the proper list
if (RULE_TYPE_MAIL == type)
{
pNodeWalk = m_pMailHead;
}
else if (RULE_TYPE_NEWS == type)
{
pNodeWalk = m_pNewsHead;
}
else
{
pNodeWalk = m_pFilterHead;
}
if (NULL == pNodeWalk)
{
if (RULE_TYPE_MAIL == type)
{
m_pMailHead = pRuleNode;
}
else if (RULE_TYPE_NEWS == type)
{
m_pNewsHead = pRuleNode;
}
else
{
m_pFilterHead = pRuleNode;
}
pRuleNode = NULL;
}
else
{
while (NULL != pNodeWalk->pNext)
{
pNodeWalk = pNodeWalk->pNext;
}
pNodeWalk->pNext = pRuleNode;
pRuleNode = NULL;
}
// Set return values
hr = S_OK;
exit:
if (NULL != pRuleNode)
{
pRuleNode->pIRule->Release();
delete pRuleNode;
}
return hr;
}
HRESULT CRulesManager::_HrReplaceRule(RULEID ridRule, IOERule * pIRule, RULE_TYPE type)
{
HRESULT hr = S_OK;
RULENODE * pNodeWalk = NULL;
RULENODE * pNodePrev = NULL;
// Nothing to do if we don't have a rule
if (NULL == pIRule)
{
hr = E_FAIL;
goto exit;
}
// Initialize the params
if (RULE_TYPE_MAIL == type)
{
pNodeWalk = m_pMailHead;
}
else if (RULE_TYPE_NEWS == type)
{
pNodeWalk = m_pNewsHead;
}
else
{
pNodeWalk = m_pFilterHead;
}
// Walk the list and free each item
for (; NULL != pNodeWalk; pNodeWalk = pNodeWalk->pNext)
{
if (pNodeWalk->ridRule == ridRule)
{
// We found it
break;
}
}
// Couldn't find the rule in the list
if (NULL == pNodeWalk)
{
hr = E_FAIL;
goto exit;
}
// Replace the rule
SafeRelease(pNodeWalk->pIRule);
pNodeWalk->pIRule = pIRule;
pNodeWalk->pIRule->AddRef();
// Set the return param
hr = S_OK;
exit:
return hr;
}
HRESULT CRulesManager::_HrRemoveRule(IOERule * pIRule, RULE_TYPE type)
{
HRESULT hr = S_OK;
RULENODE * pNodeWalk = NULL;
RULENODE * pNodePrev = NULL;
// Initialize the params
if (RULE_TYPE_MAIL == type)
{
pNodeWalk = m_pMailHead;
}
else if (RULE_TYPE_NEWS == type)
{
pNodeWalk = m_pNewsHead;
}
else
{
pNodeWalk = m_pFilterHead;
}
// Walk the list and free each item
pNodePrev = NULL;
while (NULL != pNodeWalk)
{
if (pNodeWalk->pIRule == pIRule)
{
// We found it
break;
}
// Save off the next item
pNodePrev = pNodeWalk;
// Move to the next item
pNodeWalk = pNodeWalk->pNext;
}
// Couldn't find the rule in the list
if (NULL == pNodeWalk)
{
hr = E_FAIL;
goto exit;
}
if (NULL == pNodePrev)
{
// Clear out the list head
if (RULE_TYPE_MAIL == type)
{
m_pMailHead = pNodeWalk->pNext;
}
else if (RULE_TYPE_NEWS == type)
{
m_pNewsHead = pNodeWalk->pNext;
}
else
{
m_pFilterHead = pNodeWalk->pNext;
}
}
else
{
pNodePrev->pNext = pNodeWalk->pNext;
}
// Free up the node
pNodeWalk->pIRule->Release();
pNodeWalk->pNext = NULL;
delete pNodeWalk;
// Set the return param
hr = S_OK;
exit:
return hr;
}
HRESULT CRulesManager::_HrFixupRuleInfo(RULE_TYPE typeRule, RULEINFO * pinfoRule, ULONG cpinfoRule)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
RULENODE * pNodeHead = NULL;
RULENODE * pNodeWalk = NULL;
// Check incoming args
if ((NULL == pinfoRule) && (0 != cpinfoRule))
{
hr = E_INVALIDARG;
goto exit;
}
// Walk the proper list
if (RULE_TYPE_MAIL == typeRule)
{
pNodeHead = m_pMailHead;
}
else if (RULE_TYPE_NEWS == typeRule)
{
pNodeHead = m_pNewsHead;
}
else if (RULE_TYPE_FILTER == typeRule)
{
pNodeHead = m_pFilterHead;
}
else
{
hr = E_INVALIDARG;
goto exit;
}
// Search the rule info list for an unknown ruleid
for (ulIndex = 0; ulIndex < cpinfoRule; ulIndex++)
{
// If the rule id is invalid try to find it
if (RULEID_INVALID == pinfoRule[ulIndex].ridRule)
{
for (pNodeWalk = pNodeHead; NULL != pNodeWalk; pNodeWalk = pNodeWalk->pNext)
{
// Check to see if the rule is the same
if (pNodeWalk->pIRule == pinfoRule[ulIndex].pIRule)
{
pinfoRule[ulIndex].ridRule = pNodeWalk->ridRule;
break;
}
}
if (NULL == pNodeWalk)
{
hr = E_FAIL;
goto exit;
}
}
}
// Set the return value
hr = S_OK;
exit:
return hr;
}
CEnumRules::CEnumRules()
{
m_cRef = 0;
m_pNodeHead = NULL;
m_pNodeCurr = NULL;
m_dwFlags = 0;
m_typeRule = RULE_TYPE_MAIL;
}
CEnumRules::~CEnumRules()
{
RULENODE * pNodeNext = NULL;
AssertSz(m_cRef == 0, "Somebody still has a hold of us!!");
// Walk the list and free each item
while (NULL != m_pNodeHead)
{
// Save off the next item
pNodeNext = m_pNodeHead->pNext;
// Release the rule
AssertSz(NULL != m_pNodeHead->pIRule, "Where the heck is the rule???");
m_pNodeHead->pIRule->Release();
// Free up the node
delete m_pNodeHead;
// Move to the next item
m_pNodeHead = pNodeNext;
}
}
STDMETHODIMP_(ULONG) CEnumRules::AddRef()
{
return ::InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CEnumRules::Release()
{
LONG cRef = 0;
cRef = ::InterlockedDecrement(&m_cRef);
if (0 == cRef)
{
delete this;
return cRef;
}
return cRef;
}
STDMETHODIMP CEnumRules::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_IOEEnumRules))
{
*ppvObject = static_cast<IOEEnumRules *>(this);
}
else
{
hr = E_NOINTERFACE;
goto exit;
}
reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();
hr = S_OK;
exit:
return hr;
}
STDMETHODIMP CEnumRules::Next(ULONG cpIRule, IOERule ** rgpIRule, ULONG * pcpIRuleFetched)
{
HRESULT hr = S_OK;
ULONG cpIRuleRet = 0;
// Check incoming params
if (NULL == rgpIRule)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize outgoing params
*rgpIRule = NULL;
if (NULL != pcpIRuleFetched)
{
*pcpIRuleFetched = 0;
}
// If we're at the end then just return
if (NULL == m_pNodeCurr)
{
hr = S_FALSE;
goto exit;
}
for (cpIRuleRet = 0; cpIRuleRet < cpIRule; cpIRuleRet++)
{
rgpIRule[cpIRuleRet] = m_pNodeCurr->pIRule;
(rgpIRule[cpIRuleRet])->AddRef();
m_pNodeCurr = m_pNodeCurr->pNext;
if (NULL == m_pNodeCurr)
{
cpIRuleRet++;
break;
}
}
// Set outgoing params
if (NULL != pcpIRuleFetched)
{
*pcpIRuleFetched = cpIRuleRet;
}
// Set return value
hr = (cpIRuleRet == cpIRule) ? S_OK : S_FALSE;
exit:
return hr;
}
STDMETHODIMP CEnumRules::Skip(ULONG cpIRule)
{
HRESULT hr = S_OK;
ULONG cpIRuleWalk = 0;
for (cpIRuleWalk = 0; cpIRuleWalk < cpIRule; cpIRuleWalk++)
{
if (NULL == m_pNodeCurr)
{
break;
}
m_pNodeCurr = m_pNodeCurr->pNext;
}
hr = (cpIRuleWalk == cpIRule) ? S_OK : S_FALSE;
return hr;
}
STDMETHODIMP CEnumRules::Reset(void)
{
HRESULT hr = S_OK;
m_pNodeCurr = m_pNodeHead;
return hr;
}
STDMETHODIMP CEnumRules::Clone(IOEEnumRules ** ppIEnumRules)
{
HRESULT hr = S_OK;
CEnumRules * pEnumRules = NULL;
// Check incoming params
if (NULL == ppIEnumRules)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize outgoing params
*ppIEnumRules = NULL;
pEnumRules = new CEnumRules;
if (NULL == pEnumRules)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Initialize the rules enumerator
hr = pEnumRules->_HrInitialize(m_dwFlags, m_typeRule, m_pNodeHead);
if (FAILED(hr))
{
goto exit;
}
// Set the state of the new one to match the current one
pEnumRules->m_pNodeCurr = m_pNodeHead;
// Get the rules enumerator interface
hr = pEnumRules->QueryInterface(IID_IOEEnumRules, (void **) ppIEnumRules);
if (FAILED(hr))
{
goto exit;
}
pEnumRules = NULL;
hr = S_OK;
exit:
if (NULL != pEnumRules)
{
delete pEnumRules;
}
return hr;
}
HRESULT CEnumRules::_HrInitialize(DWORD dwFlags, RULE_TYPE typeRule, RULENODE * pNodeHead)
{
HRESULT hr = S_OK;
RULENODE * pNodeNew = NULL;
RULENODE * pNodeWalk = NULL;
if (NULL == pNodeHead)
{
hr = S_FALSE;
goto exit;
}
m_dwFlags = dwFlags;
m_typeRule = typeRule;
for (pNodeWalk = m_pNodeHead; NULL != pNodeHead; pNodeHead = pNodeHead->pNext)
{
// Check to see if we should add this item
if (RULE_TYPE_FILTER == m_typeRule)
{
if (0 != (dwFlags & ENUMF_POP3))
{
if (RULEID_VIEW_DOWNLOADED == pNodeHead->ridRule)
{
continue;
}
}
}
pNodeNew = new RULENODE;
if (NULL == pNodeNew)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Initialize new node
pNodeNew->pNext = NULL;
pNodeNew->pIRule = pNodeHead->pIRule;
pNodeNew->pIRule->AddRef();
// Add the new node to the list
if (NULL == pNodeWalk)
{
m_pNodeHead = pNodeNew;
pNodeWalk = pNodeNew;
}
else
{
pNodeWalk->pNext = pNodeNew;
pNodeWalk = pNodeNew;
}
pNodeNew = NULL;
}
// Set the current to the front of the chain
m_pNodeCurr = m_pNodeHead;
// Set return value
hr = S_OK;
exit:
if (pNodeNew)
delete pNodeNew;
return hr;
}
// The Rule Executor object
CExecRules::~CExecRules()
{
RULENODE * pNodeNext = NULL;
AssertSz(m_cRef == 0, "Somebody still has a hold of us!!");
// Walk the list and free each item
while (NULL != m_pNodeHead)
{
// Save off the next item
pNodeNext = m_pNodeHead->pNext;
// Release the rule
AssertSz(NULL != m_pNodeHead->pIRule, "Where the heck is the rule???");
m_pNodeHead->pIRule->Release();
// Free up the node
delete m_pNodeHead;
// Move to the next item
m_pNodeHead = pNodeNext;
}
// Free up the cached objects
_HrReleaseFolderObjects();
_HrReleaseFileObjects();
_HrReleaseSoundFiles();
// Free the folder list
SafeMemFree(m_pRuleFolder);
m_cRuleFolderAlloc = 0;
// Free the file list
SafeMemFree(m_pRuleFile);
m_cRuleFileAlloc = 0;
// Free the file list
SafeMemFree(m_ppszSndFile);
m_cpszSndFileAlloc = 0;
}
STDMETHODIMP_(ULONG) CExecRules::AddRef()
{
return ::InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CExecRules::Release()
{
LONG cRef = 0;
cRef = ::InterlockedDecrement(&m_cRef);
if (0 == cRef)
{
delete this;
return cRef;
}
return cRef;
}
STDMETHODIMP CExecRules::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_IOEExecRules))
{
*ppvObject = static_cast<IOEExecRules *>(this);
}
else
{
hr = E_NOINTERFACE;
goto exit;
}
reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();
hr = S_OK;
exit:
return hr;
}
STDMETHODIMP CExecRules::GetState(DWORD * pdwState)
{
HRESULT hr = S_OK;
// Check incoming params
if (NULL == pdwState)
{
hr = E_INVALIDARG;
goto exit;
}
*pdwState = m_dwState;
hr = S_OK;
exit:
return hr;
}
STDMETHODIMP CExecRules::ExecuteRules(DWORD dwFlags, LPCSTR pszAcct, MESSAGEINFO * pMsgInfo,
IMessageFolder * pFolder, IMimePropertySet * pIMPropSet,
IMimeMessage * pIMMsg, ULONG cbMsgSize,
ACT_ITEM ** ppActions, ULONG * pcActions)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
RULENODE * pNodeWalk = NULL;
ACT_ITEM * pActions = NULL;
ULONG cActions = 0;
ACT_ITEM * pActionsList = NULL;
ULONG cActionsList = 0;
ACT_ITEM * pActionsNew = NULL;
ULONG cActionsNew = 0;
BOOL fStopProcessing = FALSE;
BOOL fMatch = FALSE;
DWORD dwState = 0;
// Check incoming params
if (((NULL == pMsgInfo) && (NULL == pIMPropSet)) ||
(0 == cbMsgSize) || (NULL == ppActions) || (NULL == pcActions))
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize outgoing param
*ppActions = NULL;
*pcActions = 0;
// Should we skip partial messages?
if ((NULL != pIMPropSet) &&
(S_OK == pIMPropSet->IsContentType(STR_CNT_MESSAGE, STR_SUB_PARTIAL)) &&
(0 != (dwFlags & ERF_SKIPPARTIALS)))
{
hr = S_FALSE;
goto exit;
}
// Walk the list of rules executing each one
pNodeWalk = m_pNodeHead;
while (NULL != pNodeWalk)
{
Assert(NULL != pNodeWalk->pIRule);
// If we are only checking server rules
// Bail if we need more information...
if (0 != (dwFlags & ERF_ONLYSERVER))
{
hr = pNodeWalk->pIRule->GetState(&dwState);
if (FAILED(hr))
{
goto exit;
}
// Do we need more information...
if (0 != (dwState & CRIT_STATE_ALL))
{
hr = S_FALSE;
break;
}
}
// Evaluate the rule
hr = pNodeWalk->pIRule->Evaluate(pszAcct, pMsgInfo, pFolder, pIMPropSet, pIMMsg, cbMsgSize, &pActions, &cActions);
if (FAILED(hr))
{
goto exit;
}
// Did we have a match
if (S_OK == hr)
{
// We've matched at least once
fMatch = TRUE;
ulIndex = 0;
// If these are server actions
if ((1 == cActions) && ((ACT_TYPE_DELETESERVER == pActions[ulIndex].type) ||
(ACT_TYPE_DONTDOWNLOAD == pActions[ulIndex].type)))
{
// If this is our only action
if (0 == cActionsList)
{
// Save the action
pActionsList = pActions;
pActions = NULL;
cActionsList = cActions;
// We are done
fStopProcessing = TRUE;
}
else
{
// We already have to do something with it
// so skip over this action
RuleUtil_HrFreeActionsItem(pActions, cActions);
SafeMemFree(pActions);
// Move to the next rule
pNodeWalk = pNodeWalk->pNext;
continue;
}
}
else
{
// Should we stop after merging these?
for (ulIndex = 0; ulIndex < cActions; ulIndex++)
{
if (ACT_TYPE_STOP == pActions[ulIndex].type)
{
fStopProcessing = TRUE;
break;
}
}
// Merge these items with the previous ones
hr = RuleUtil_HrMergeActions(pActionsList, cActionsList, pActions, cActions, &pActionsNew, &cActionsNew);
if (FAILED(hr))
{
goto exit;
}
// Free up the previous ones
RuleUtil_HrFreeActionsItem(pActionsList, cActionsList);
SafeMemFree(pActionsList);
RuleUtil_HrFreeActionsItem(pActions, cActions);
SafeMemFree(pActions);
// Save off the new ones
pActionsList = pActionsNew;
pActionsNew = NULL;
cActionsList = cActionsNew;
}
// Should we continue...
if (FALSE != fStopProcessing)
{
break;
}
}
// Move to the next rule
pNodeWalk = pNodeWalk->pNext;
}
// Set outgoing param
*ppActions = pActionsList;
pActionsList = NULL;
*pcActions = cActionsList;
// Set the return value
hr = (FALSE != fMatch) ? S_OK : S_FALSE;
exit:
RuleUtil_HrFreeActionsItem(pActionsNew, cActionsNew);
SafeMemFree(pActionsNew);
RuleUtil_HrFreeActionsItem(pActions, cActions);
SafeMemFree(pActions);
RuleUtil_HrFreeActionsItem(pActionsList, cActionsList);
SafeMemFree(pActionsList);
return hr;
}
STDMETHODIMP CExecRules::ReleaseObjects(VOID)
{
// Free up the folders
_HrReleaseFolderObjects();
// Free up the files
_HrReleaseFileObjects();
// Free up the sound files
_HrReleaseSoundFiles();
return S_OK;
}
STDMETHODIMP CExecRules::GetRuleFolder(FOLDERID idFolder, DWORD_PTR * pdwFolder)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
RULE_FOLDER * pRuleFolderWalk = NULL;
IMessageFolder *pFolder = NULL;
// Check incoming param
if ((FOLDERID_INVALID == idFolder) || (NULL == pdwFolder))
{
hr =E_INVALIDARG;
goto exit;
}
// Initialize outgoing param
*pdwFolder = NULL;
// Let's search for the folder
for (ulIndex = 0; ulIndex < m_cRuleFolder; ulIndex++)
{
pRuleFolderWalk = &(m_pRuleFolder[ulIndex]);
if (idFolder == pRuleFolderWalk->idFolder)
{
Assert(NULL != pRuleFolderWalk->pFolder);
break;
}
}
// If we didn't find it then let's open it and lock it...
if (ulIndex >= m_cRuleFolder)
{
// Do we need to alloc any more spaces
if (m_cRuleFolder >= m_cRuleFolderAlloc)
{
hr = HrRealloc((LPVOID *) &m_pRuleFolder, sizeof(*m_pRuleFolder) * (m_cRuleFolderAlloc + RULE_FOLDER_ALLOC));
if (FAILED(hr))
{
goto exit;
}
// Initialize the new rule folders
ZeroMemory(m_pRuleFolder + m_cRuleFolderAlloc, sizeof(*m_pRuleFolder) * RULE_FOLDER_ALLOC);
for (ulIndex = m_cRuleFolderAlloc; ulIndex < (m_cRuleFolderAlloc + RULE_FOLDER_ALLOC); ulIndex++)
{
m_pRuleFolder[ulIndex].idFolder = FOLDERID_INVALID;
}
m_cRuleFolderAlloc += RULE_FOLDER_ALLOC;
}
// Open the folder
hr = g_pStore->OpenFolder(idFolder, NULL, NOFLAGS, &pFolder);
if (FAILED(hr))
{
goto exit;
}
m_pRuleFolder[m_cRuleFolder].idFolder = idFolder;
m_pRuleFolder[m_cRuleFolder].pFolder = pFolder;
pFolder = NULL;
pRuleFolderWalk = &(m_pRuleFolder[m_cRuleFolder]);
m_cRuleFolder++;
}
*pdwFolder = (DWORD_PTR) (pRuleFolderWalk->pFolder);
// Set the proper return value
hr = S_OK;
exit:
if (NULL != pFolder)
pFolder->Release();
return hr;
}
STDMETHODIMP CExecRules::GetRuleFile(LPCSTR pszFile, IStream ** ppstmFile, DWORD * pdwType)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
RULE_FILE * pRuleFileWalk = NULL;
IStream * pIStmFile = NULL;
LPSTR pszExt = NULL;
DWORD dwType = RFT_FILE;
// Check incoming param
if ((NULL == pszFile) || (NULL == ppstmFile) || (NULL == pdwType))
{
hr =E_INVALIDARG;
goto exit;
}
// Initialize outgoing param
*ppstmFile = NULL;
*pdwType = NULL;
// Let's search for the file
for (ulIndex = 0; ulIndex < m_cRuleFile; ulIndex++)
{
pRuleFileWalk = &(m_pRuleFile[ulIndex]);
if (0 == lstrcmpi(pRuleFileWalk->pszFile, pszFile))
{
Assert(NULL != pRuleFileWalk->pstmFile);
break;
}
}
// If we didn't find it then let's open it...
if (ulIndex >= m_cRuleFile)
{
// Do we need to alloc any more space
if (m_cRuleFile >= m_cRuleFileAlloc)
{
hr = HrRealloc((LPVOID *) &m_pRuleFile, sizeof(*m_pRuleFile) * (m_cRuleFileAlloc + RULE_FILE_ALLOC));
if (FAILED(hr))
{
goto exit;
}
// Initialize the new rule file
ZeroMemory(m_pRuleFile + m_cRuleFileAlloc, sizeof(*m_pRuleFile) * RULE_FILE_ALLOC);
m_cRuleFileAlloc += RULE_FILE_ALLOC;
}
// Open a stream on the file
hr = CreateStreamOnHFile((LPTSTR) pszFile, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL, &pIStmFile);
if (FAILED(hr))
{
goto exit;
}
// Lets split the file name and get the extension
pszExt = PathFindExtension(pszFile);
if ((0 == lstrcmpi(pszExt, c_szHtmExt)) || (0 == lstrcmpi(pszExt, c_szHtmlExt)))
{
dwType = RFT_HTML;
}
// Text File...
else if (0 == lstrcmpi(pszExt, c_szTxtExt))
{
dwType = RFT_TEXT;
}
// Else .nws or .eml file...
else if ((0 == lstrcmpi(pszExt, c_szEmlExt)) || (0 == lstrcmpi(pszExt, c_szNwsExt)))
{
dwType = RFT_MESSAGE;
}
// Otherwise, its an attachment
else
{
dwType = RFT_FILE;
}
// Save off the info
m_pRuleFile[m_cRuleFile].pszFile = PszDupA(pszFile);
if (NULL == m_pRuleFile[m_cRuleFile].pszFile)
{
hr = E_OUTOFMEMORY;
goto exit;
}
m_pRuleFile[m_cRuleFile].pstmFile = pIStmFile;
pIStmFile = NULL;
m_pRuleFile[m_cRuleFile].dwType = dwType;
pRuleFileWalk = &(m_pRuleFile[m_cRuleFile]);
m_cRuleFile++;
}
*ppstmFile = pRuleFileWalk->pstmFile;
(*ppstmFile)->AddRef();
*pdwType = pRuleFileWalk->dwType;
// Set the proper return value
hr = S_OK;
exit:
SafeRelease(pIStmFile);
return hr;
}
STDMETHODIMP CExecRules::AddSoundFile(DWORD dwFlags, LPCSTR pszSndFile)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
// Check incoming param
if (NULL == pszSndFile)
{
hr = E_INVALIDARG;
goto exit;
}
// Let's search for the file
for (ulIndex = 0; ulIndex < m_cpszSndFile; ulIndex++)
{
Assert(NULL != m_ppszSndFile[ulIndex]);
if (0 == lstrcmpi(m_ppszSndFile[ulIndex], pszSndFile))
{
break;
}
}
// If we didn't find it then let's open it...
if (ulIndex >= m_cpszSndFile)
{
// Do we need to alloc any more space
if (m_cpszSndFile >= m_cpszSndFileAlloc)
{
hr = HrRealloc((LPVOID *) &m_ppszSndFile, sizeof(*m_ppszSndFile) * (m_cpszSndFileAlloc + SND_FILE_ALLOC));
if (FAILED(hr))
{
goto exit;
}
// Initialize the new rule file
ZeroMemory(m_ppszSndFile + m_cpszSndFileAlloc, sizeof(*m_ppszSndFile) * SND_FILE_ALLOC);
m_cpszSndFileAlloc += SND_FILE_ALLOC;
}
// Save off the info
m_ppszSndFile[m_cpszSndFile] = PszDupA(pszSndFile);
if (NULL == m_ppszSndFile[m_cpszSndFile])
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Should we play it?
if (0 != (dwFlags & ASF_PLAYIFNEW))
{
sndPlaySound(m_ppszSndFile[m_cpszSndFile], SND_NODEFAULT | SND_SYNC);
}
m_cpszSndFile++;
}
// Set the proper return value
hr = S_OK;
exit:
return hr;
}
STDMETHODIMP CExecRules::PlaySounds(DWORD dwFlags)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
// Let's search for the file
for (ulIndex = 0; ulIndex < m_cpszSndFile; ulIndex++)
{
Assert(NULL != m_ppszSndFile[ulIndex]);
sndPlaySound(m_ppszSndFile[ulIndex], SND_NODEFAULT | SND_SYNC);
}
return hr;
}
HRESULT CExecRules::_HrReleaseFolderObjects(VOID)
{
RULE_FOLDER * pRuleFolder = NULL;
ULONG ulIndex = 0;
for (ulIndex = 0; ulIndex < m_cRuleFolder; ulIndex++)
{
pRuleFolder = &(m_pRuleFolder[ulIndex]);
Assert(FOLDERID_INVALID != pRuleFolder->idFolder);
// If we have the folder opened then close it
SafeRelease(pRuleFolder->pFolder);
// Reset the folder list
pRuleFolder->idFolder = FOLDERID_INVALID;
}
// Let's clear out the number of messages
m_cRuleFolder = 0;
return S_OK;
}
HRESULT CExecRules::_HrReleaseFileObjects(VOID)
{
RULE_FILE * pRuleFile = NULL;
ULONG ulIndex = 0;
for (ulIndex = 0; ulIndex < m_cRuleFile; ulIndex++)
{
pRuleFile = &(m_pRuleFile[ulIndex]);
Assert(NULL != pRuleFile->pszFile);
// If we have the file opened then close it
SafeRelease(pRuleFile->pstmFile);
// Clear the file
SafeMemFree(pRuleFile->pszFile);
pRuleFile->dwType = RFT_FILE;
}
// Let's clear out the number of file
m_cRuleFile = 0;
return S_OK;
}
HRESULT CExecRules::_HrReleaseSoundFiles(VOID)
{
ULONG ulIndex = 0;
for (ulIndex = 0; ulIndex < m_cpszSndFile; ulIndex++)
{
Assert(NULL != m_ppszSndFile[ulIndex]);
// Clear the file
SafeMemFree(m_ppszSndFile[ulIndex]);
}
// Let's clear out the number of file
m_cpszSndFile = 0;
return S_OK;
}
HRESULT CExecRules::_HrInitialize(DWORD dwFlags, RULENODE * pNodeHead)
{
HRESULT hr = S_OK;
RULENODE * pNodeNew = NULL;
RULENODE * pNodeWalk = NULL;
DWORD dwState = 0;
PROPVARIANT propvar;
if (NULL == pNodeHead)
{
hr = S_FALSE;
goto exit;
}
for (pNodeWalk = m_pNodeHead; NULL != pNodeHead; pNodeHead = pNodeHead->pNext)
{
// Skip rules that are disabled
if (0 != (dwFlags & ERF_ONLY_ENABLED))
{
hr = pNodeHead->pIRule->GetProp(RULE_PROP_DISABLED, 0, &propvar);
Assert(VT_BOOL == propvar.vt);
if (FAILED(hr) || (FALSE != propvar.boolVal))
{
continue;
}
}
// Skip rules that are invalid
if (0 != (dwFlags & ERF_ONLY_VALID))
{
hr = pNodeHead->pIRule->Validate(dwFlags);
if (FAILED(hr) || (S_FALSE == hr))
{
continue;
}
}
pNodeNew = new RULENODE;
if (NULL == pNodeNew)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Initialize new node
pNodeNew->pNext = NULL;
pNodeNew->pIRule = pNodeHead->pIRule;
pNodeNew->pIRule->AddRef();
// Add the new node to the list
if (NULL == pNodeWalk)
{
m_pNodeHead = pNodeNew;
pNodeWalk = pNodeNew;
}
else
{
pNodeWalk->pNext = pNodeNew;
pNodeWalk = pNodeNew;
}
pNodeNew = NULL;
// Calculate state from message
if (SUCCEEDED(pNodeWalk->pIRule->GetState(&dwState)))
{
// Let's set the proper Criteria state
if ((m_dwState & CRIT_STATE_MASK) < (dwState & CRIT_STATE_MASK))
{
m_dwState = (m_dwState & ~CRIT_STATE_MASK) | (dwState & CRIT_STATE_MASK);
}
// Let's set the proper Action state
if (0 != (dwState & ACT_STATE_MASK))
{
m_dwState |= (dwState & ACT_STATE_MASK);
}
}
}
// Set return value
hr = S_OK;
exit:
if (pNodeNew)
delete pNodeNew;
return hr;
}