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.
 
 
 
 
 
 

2449 lines
66 KiB

///////////////////////////////////////////////////////////////////////////////
//
// Criteria.cpp
//
///////////////////////////////////////////////////////////////////////////////
#include <pch.hxx>
#include "criteria.h"
#include "ruleutil.h"
#include <xpcomm.h>
#include <flagconv.h>
#include <bodyutil.h>
#include <demand.h>
static const int CRIT_GROW = 16;
BOOL FMatchCritItem(CRIT_ITEM * pItem, LPCSTR pszAcct, MESSAGEINFO * pMsgInfo,
IMessageFolder * pFolder, IMimePropertySet * pIMPropSet,
IMimeMessage * pIMMsg, ULONG cbMsgSize);
BOOL FCritLoad_Account(IStream * pIStm, PROPVARIANT * ppropvar);
BOOL FCritSave_Account(IStream * pIStm, PROPVARIANT * ppropvar);
BOOL FCritLoad_Default(IStream * pIStm, PROPVARIANT * ppropvar);
BOOL FCritSave_Default(IStream * pIStm, PROPVARIANT * ppropvar);
DWORD DwGetFlagsFromMessage(IMimeMessage * pIMMsg);
///////////////////////////////////////////////////////////////////////////////
//
// HrCreateCriteria
//
// This creates a criteria container.
//
// ppICriteria - pointer to return the criteria container
//
// Returns: S_OK, on success
// E_OUTOFMEMORY, if can't create the Criteria object
//
///////////////////////////////////////////////////////////////////////////////
HRESULT HrCreateCriteria(IOECriteria ** ppICriteria)
{
COECriteria * pCriteria = NULL;
HRESULT hr = S_OK;
// Check the incoming params
if (NULL == ppICriteria)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize outgoing params
*ppICriteria = NULL;
// Create the rules manager object
pCriteria = new COECriteria;
if (NULL == pCriteria)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Get the rules manager interface
hr = pCriteria->QueryInterface(IID_IOECriteria, (void **) ppICriteria);
if (FAILED(hr))
{
goto exit;
}
pCriteria = NULL;
// Set the proper return value
hr = S_OK;
exit:
if (NULL != pCriteria)
{
delete pCriteria;
}
return hr;
}
COECriteria::~COECriteria()
{
AssertSz(m_cRef == 0, "Somebody still has a hold of us!!");
Reset();
}
STDMETHODIMP_(ULONG) COECriteria::AddRef()
{
return ::InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) COECriteria::Release()
{
LONG cRef = 0;
cRef = ::InterlockedDecrement(&m_cRef);
if (0 == cRef)
{
delete this;
return cRef;
}
return cRef;
}
STDMETHODIMP COECriteria::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_IOECriteria))
{
*ppvObject = static_cast<IOECriteria *>(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 COECriteria::Reset(void)
{
HRESULT hr = S_OK;
// See if there is something to do
if (0 == m_cItems)
{
Assert(NULL == m_rgItems);
hr = S_OK;
goto exit;
}
RuleUtil_HrFreeCriteriaItem(m_rgItems, m_cItems);
SafeMemFree(m_rgItems);
m_cItems = 0;
m_cItemsAlloc = 0;
exit:
return hr;
}
STDMETHODIMP COECriteria::GetState(DWORD * pdwState)
{
HRESULT hr = S_OK;
DWORD dwState = CRIT_STATE_NULL;
ULONG ulIndex = 0;
// Check incoming params
if (NULL == pdwState)
{
hr = E_INVALIDARG;
goto exit;
}
// Init the outgoing param
*pdwState = CRIT_STATE_NULL;
// See if there is something to do
if (0 == m_cItems)
{
Assert(NULL == m_rgItems);
hr = S_OK;
goto exit;
}
// Walk through the actions to figure out the state
for (ulIndex = 0; ulIndex < m_cItems; ulIndex++)
{
if ((CRIT_TYPE_SECURE == m_rgItems[ulIndex].type) ||
(CRIT_TYPE_BODY == m_rgItems[ulIndex].type) ||
(CRIT_TYPE_ATTACH == m_rgItems[ulIndex].type))
{
dwState = CRIT_STATE_ALL;
}
else if (CRIT_STATE_ALL != dwState)
{
dwState = CRIT_STATE_HEADER;
}
}
// Set the outgoing param
*pdwState = dwState;
// Set the proper return value
hr = S_OK;
exit:
return hr;
}
STDMETHODIMP COECriteria::GetCriteria(DWORD dwFlags, PCRIT_ITEM * ppItem, ULONG * pcItem)
{
HRESULT hr = S_OK;
CRIT_ITEM * pItemNew = NULL;
// Check incoming params
if ((NULL == ppItem) || (0 != dwFlags))
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the out params
*ppItem = NULL;
if (NULL != pcItem)
{
*pcItem = 0;
}
// If we don't have any criteria, then return
if (0 == m_cItems)
{
hr = E_FAIL;
goto exit;
}
// Allocate space for the criteria
hr = RuleUtil_HrDupCriteriaItem(m_rgItems, m_cItems, &pItemNew);
if (FAILED(hr))
{
goto exit;
}
// Save the criteria
*ppItem = pItemNew;
pItemNew = NULL;
if (NULL != pcItem)
{
*pcItem = m_cItems;
}
exit:
RuleUtil_HrFreeCriteriaItem(pItemNew, m_cItems);
SafeMemFree(pItemNew);
return hr;
}
STDMETHODIMP COECriteria::SetCriteria(DWORD dwFlags, CRIT_ITEM * pItem, ULONG cItem)
{
HRESULT hr = S_OK;
CRIT_ITEM * pItemNew = NULL;
// Check incoming params
if ((NULL == pItem) || (0 == cItem) || (0 != dwFlags))
{
hr = E_INVALIDARG;
goto exit;
}
// If we have any criteria already, then reset
if (0 != m_cItems)
{
Reset();
}
// Allocate space for the criteria
hr = RuleUtil_HrDupCriteriaItem(pItem, cItem, &pItemNew);
if (FAILED(hr))
{
goto exit;
}
// Save the criteria
m_rgItems = pItemNew;
pItemNew = NULL;
m_cItems = cItem;
m_cItemsAlloc = cItem;
exit:
RuleUtil_HrFreeCriteriaItem(pItemNew, cItem);
SafeMemFree(pItemNew);
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// ValidateCriteria
//
// This verifies each of the criteria values
//
// Returns: S_OK, if the criteria were valid
// S_FALSE, otherwise
//
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP COECriteria::Validate(DWORD dwFlags)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
LPSTR pszText = NULL;
IImnAccount * pAccount = NULL;
FOLDERINFO Folder = {0};
LPTSTR pszWalk = NULL;
ULONG cchText = 0;
RULEFOLDERDATA * prfdData = NULL;
// If we don't have any criteria, then we must be valid
if (0 == m_cItems)
{
hr = S_OK;
goto exit;
}
for (ulIndex = 0; ulIndex < m_cItems; ulIndex++)
{
if (0 != (m_rgItems[ulIndex].dwFlags & ~(CRIT_FLAG_INVERT | CRIT_FLAG_MULTIPLEAND)))
{
hr = S_FALSE;
goto exit;
}
switch(m_rgItems[ulIndex].type)
{
case CRIT_TYPE_NEWSGROUP:
if ((VT_BLOB != m_rgItems[ulIndex].propvar.vt) ||
(0 == m_rgItems[ulIndex].propvar.blob.cbSize))
{
hr = S_FALSE;
goto exit;
}
// Make life simpler
prfdData = (RULEFOLDERDATA *) (m_rgItems[ulIndex].propvar.blob.pBlobData);
// Validate the rule folder data
if (S_OK != RuleUtil_HrValidateRuleFolderData(prfdData))
{
hr = S_FALSE;
goto exit;
}
// Does the folder exist
hr = g_pStore->GetFolderInfo(prfdData->idFolder, &Folder);
if (FAILED(hr))
{
hr = S_FALSE;
goto exit;
}
// Are we subscribed?
if (0 == (Folder.dwFlags & FOLDER_SUBSCRIBED))
{
hr = S_FALSE;
goto exit;
}
break;
case CRIT_TYPE_ALL:
case CRIT_TYPE_JUNK:
case CRIT_TYPE_READ:
case CRIT_TYPE_REPLIES:
case CRIT_TYPE_DOWNLOADED:
case CRIT_TYPE_DELETED:
case CRIT_TYPE_ATTACH:
case CRIT_TYPE_FLAGGED:
if (VT_EMPTY != m_rgItems[ulIndex].propvar.vt)
{
hr = S_FALSE;
goto exit;
}
break;
case CRIT_TYPE_SUBJECT:
case CRIT_TYPE_BODY:
case CRIT_TYPE_TO:
case CRIT_TYPE_CC:
case CRIT_TYPE_TOORCC:
case CRIT_TYPE_FROM:
if ((VT_BLOB != m_rgItems[ulIndex].propvar.vt) ||
(0 == m_rgItems[ulIndex].propvar.blob.cbSize) ||
(NULL == m_rgItems[ulIndex].propvar.blob.pBlobData) ||
('\0' == m_rgItems[ulIndex].propvar.blob.pBlobData[0]))
{
hr = S_FALSE;
goto exit;
}
// Spin through each item making sure it is perfect
cchText = 0;
for (pszWalk = (LPTSTR) m_rgItems[ulIndex].propvar.blob.pBlobData;
'\0' != pszWalk[0]; pszWalk += lstrlen(pszWalk) + 1)
{
cchText += lstrlen(pszWalk) + 1;
}
// For the terminator
if ('\0' == pszWalk[0])
{
cchText++;
}
if ('\0' == pszWalk[1])
{
cchText++;
}
if (cchText != m_rgItems[ulIndex].propvar.blob.cbSize)
{
hr = S_FALSE;
goto exit;
}
break;
case CRIT_TYPE_SIZE:
case CRIT_TYPE_THREADSTATE:
case CRIT_TYPE_LINES:
case CRIT_TYPE_PRIORITY:
case CRIT_TYPE_AGE:
case CRIT_TYPE_SECURE:
if (VT_UI4 != m_rgItems[ulIndex].propvar.vt)
{
hr = S_FALSE;
goto exit;
}
break;
case CRIT_TYPE_ACCOUNT:
if ((VT_LPSTR != m_rgItems[ulIndex].propvar.vt) ||
(NULL == m_rgItems[ulIndex].propvar.pszVal))
{
hr = S_FALSE;
goto exit;
}
Assert(g_pAcctMan);
if (FAILED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, m_rgItems[ulIndex].propvar.pszVal, &pAccount)))
{
hr = S_FALSE;
goto exit;
}
SafeRelease(pAccount);
break;
case CRIT_TYPE_SENDER:
{
LPWSTR pwszText = NULL,
pwszVal = NULL;
if ((VT_LPSTR != m_rgItems[ulIndex].propvar.vt) ||
(NULL == m_rgItems[ulIndex].propvar.pszVal))
{
AssertSz(VT_LPWSTR != m_rgItems[ulIndex].propvar.vt, "We are getting UNICODE here.");
hr = S_FALSE;
goto exit;
}
// Verify the email string
pwszVal = PszToUnicode(CP_ACP, m_rgItems[ulIndex].propvar.pszVal);
if (!pwszVal)
{
hr = S_FALSE;
goto exit;
}
hr = RuleUtil_HrParseEmailString(pwszVal, 0, &pwszText, NULL);
MemFree(pwszText);
MemFree(pwszVal);
if (FAILED(hr))
{
hr = S_FALSE;
goto exit;
}
break;
}
default:
hr = S_FALSE;
goto exit;
break;
}
}
// If we got here, then we must be AOK
hr = S_OK;
exit:
g_pStore->FreeRecord(&Folder);
SafeRelease(pAccount);
return hr;
}
STDMETHODIMP COECriteria::AppendCriteria(DWORD dwFlags, CRIT_LOGIC logic,
CRIT_ITEM * pItem, ULONG cItem, ULONG * pcItemAppended)
{
HRESULT hr = S_OK;
CRIT_ITEM * pItemNew = NULL;
// Check incoming parameters
if ((0 != dwFlags) || (CRIT_LOGIC_NULL == logic) || (NULL == pItem) || (0 == cItem))
{
hr = E_INVALIDARG;
goto exit;
}
// Let's init our outgoing parameters
if (NULL != pcItemAppended)
{
*pcItemAppended = 0;
}
// Do we have to add more items?
if (m_cItems == m_cItemsAlloc)
{
hr = HrRealloc((LPVOID *) &m_rgItems, sizeof(CRIT_ITEM) * (m_cItemsAlloc + CRIT_GROW));
if (FAILED(hr))
{
goto exit;
}
ZeroMemory(m_rgItems + m_cItemsAlloc, sizeof(CRIT_ITEM) * CRIT_GROW);
m_cItemsAlloc += CRIT_GROW;
}
// Let's duplicate the items that need to be added
hr = RuleUtil_HrDupCriteriaItem(pItem, cItem, &pItemNew);
if (FAILED(hr))
{
goto exit;
}
// Let's add them to the criteria array
if (0 != m_cItems)
{
m_rgItems[m_cItems - 1].logic = logic;
}
CopyMemory(m_rgItems + m_cItems, pItemNew, sizeof(CRIT_ITEM) * cItem);
m_cItems += cItem;
// Set the proper outgoing parameter
if (NULL != pcItemAppended)
{
*pcItemAppended = cItem;
}
// Set the proper return value
hr = S_OK;
exit:
SafeMemFree(pItemNew);
return hr;
}
STDMETHODIMP COECriteria::MatchMessage(LPCSTR pszAcct, MESSAGEINFO * pMsgInfo, IMessageFolder * pFolder,
IMimePropertySet * pIMPropSet, IMimeMessage * pIMMsg, ULONG cbMsgSize)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
BOOL fResult = FALSE;
BOOL fResultNew = FALSE;
CRIT_LOGIC logic;
// Check incoming parameters
if (((NULL == pMsgInfo) && (NULL == pIMPropSet)) || (0 == cbMsgSize))
{
hr = E_INVALIDARG;
goto exit;
}
// Let's go through the criteria and see if we match
fResult = FALSE;
logic = CRIT_LOGIC_OR;
for (ulIndex = 0; ulIndex < m_cItems; ulIndex++)
{
// Call matching function for this criteria item
fResultNew = FMatchCritItem(&(m_rgItems[ulIndex]), pszAcct, pMsgInfo, pFolder, pIMPropSet, pIMMsg, cbMsgSize);
// Slap it together with the old result
if (CRIT_LOGIC_AND == logic)
{
fResult = (fResult && fResultNew);
}
else
{
Assert(CRIT_LOGIC_OR == logic);
fResult = (fResult || fResultNew);
}
// Save of the next logical operation
logic = m_rgItems[ulIndex].logic;
}
// Set the proper return value
hr = (FALSE != fResult) ? S_OK : S_FALSE;
exit:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// LoadReg
//
// This loads in the criteria from the registry. It loads in the criteria
// order from the Order value. The string contains space delimitied values
// and each value contains the subkey name for each criterion. Each criterion
// is loaded in the order that is contained in the Order value. The criterion
// are loaded with the Criterion Type and Logical Operator. The Criterion Value
// Type is loaded if it exists. If a Criterion Value Type exists, then the
// corresponding Criterion Value is loaded in.
//
// pszRegPath - the path to load the criteria from
//
// Returns: S_OK, if the criteria was loaded without problems
// E_OUTOFMEMORY, if we couldn't allocate memory to hold the criteria
// E_FAIL, otherwise
//
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP COECriteria::LoadReg(LPCSTR pszRegPath)
{
HRESULT hr = S_OK;
LONG lErr = 0;
HKEY hkeyRoot = NULL;
ULONG cbData = 0;
LPSTR pszOrder = NULL;
ULONG cOrder = 0;
LPSTR pszWalk = NULL;
CRIT_ITEM * pItems = NULL;
LPSTR pszNext = NULL;
ULONG ulOrder = 0;
HKEY hkeyCriteria = NULL;
CRIT_TYPE typeCrit;
CRIT_LOGIC logicCrit;
PROPVARIANT propvar;
DWORD dwType = 0;
BYTE * pbData = NULL;
DWORD dwFlags = CRIT_FLAG_DEFAULT;
// Check incoming param
if (NULL == pszRegPath)
{
hr = E_INVALIDARG;
goto exit;
}
// Should we fail if we're already loaded?
AssertSz(0 == (m_dwState & CRIT_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 criteria order
hr = RuleUtil_HrGetRegValue(hkeyRoot, c_szCriteriaOrder, NULL, (BYTE **) &pszOrder, &cbData);
if (FAILED(hr))
{
goto exit;
}
// Make sure we actually have something to load
if ('\0' == *pszOrder)
{
AssertSz(FALSE, "The order string for the criteria is mis-formatted in the registry");
hr = E_FAIL;
goto exit;
}
// Convert the criteria string to a more useful format
pszWalk = pszOrder;
cOrder = 1;
for (pszWalk = StrStr(pszOrder, g_szSpace); NULL != pszWalk; pszWalk = StrStr(pszWalk, g_szSpace))
{
// Terminate the order item
*pszWalk = '\0';
pszWalk++;
cOrder++;
}
// Allocate the space to hold all the criteria
hr = HrAlloc((void **) &pItems, cOrder * sizeof(CRIT_ITEM));
if (FAILED(hr))
{
goto exit;
}
// Initialize it to a known value
ZeroMemory(pItems, cOrder * sizeof(CRIT_ITEM));
// For each criteria in the order string
pszWalk = pszOrder;
for (ulOrder = 0, pszWalk = pszOrder; ulOrder < cOrder; ulOrder++, pszWalk += lstrlen(pszWalk) + 1)
{
// Open up the criteria reg key
lErr = RegOpenKeyEx(hkeyRoot, pszWalk, 0, KEY_READ, &hkeyCriteria);
if (ERROR_SUCCESS != lErr)
{
AssertSz(FALSE, "Part of the criteria is mis-formatted in the registry");
hr = E_FAIL;
goto exit;
}
// Get the criteria type
cbData = sizeof(typeCrit);
lErr = RegQueryValueEx(hkeyCriteria, c_szCriteriaType, 0, NULL,
(BYTE *) &(typeCrit), &cbData);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Get the criteria logicial op
cbData = sizeof(logicCrit);
lErr = RegQueryValueEx(hkeyCriteria, c_szCriteriaLogic, 0, NULL,
(BYTE *) &(logicCrit), &cbData);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Get the criteria flags
cbData = sizeof(dwFlags);
lErr = RegQueryValueEx(hkeyCriteria, c_szCriteriaFlags, 0, NULL,
(BYTE *) &(dwFlags), &cbData);
if ((ERROR_SUCCESS != lErr) && (ERROR_FILE_NOT_FOUND != lErr))
{
hr = E_FAIL;
goto exit;
}
// If it didn't exist then assign it to the default
if (ERROR_FILE_NOT_FOUND == lErr)
{
dwFlags = CRIT_FLAG_DEFAULT;
}
// Initialize the new space to a known value
ZeroMemory(&propvar, sizeof(propvar));
// Does a criteria value type exist
lErr = RegQueryValueEx(hkeyCriteria, c_szCriteriaValueType, 0, NULL, NULL, &cbData);
if ((ERROR_SUCCESS == lErr) && (0 != cbData))
{
// Load the criteria value in
cbData = sizeof(dwType);
lErr = RegQueryValueEx(hkeyCriteria, c_szCriteriaValueType, 0, NULL,
(BYTE *) &dwType, &cbData);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
propvar.vt = (VARTYPE) dwType;
switch (propvar.vt)
{
case VT_UI4:
// Get the criteria value
cbData = sizeof(propvar.ulVal);
lErr = RegQueryValueEx(hkeyCriteria, c_szCriteriaValue, 0, NULL,
(BYTE * ) &(propvar.ulVal), &cbData);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
break;
case VT_LPSTR:
case VT_BLOB:
// Get the criteria value
hr = RuleUtil_HrGetRegValue(hkeyCriteria, c_szCriteriaValue, NULL, (BYTE **) &pbData, &cbData);
if (FAILED(hr))
{
goto exit;
}
// Save the space so we can free it
if (VT_LPSTR == propvar.vt)
{
propvar.pszVal = (LPSTR) pbData;
}
else
{
propvar.blob.cbSize = cbData;
propvar.blob.pBlobData = pbData;
}
pbData = NULL;
break;
default:
AssertSz(FALSE, "Why are we loading in a invalid criteria type?");
hr = E_FAIL;
goto exit;
break;
}
}
// Save the value into the criteria array
pItems[ulOrder].type = typeCrit;
pItems[ulOrder].dwFlags = dwFlags;
pItems[ulOrder].logic = logicCrit;
pItems[ulOrder].propvar = propvar;
// Close the criteria
SideAssert(ERROR_SUCCESS == RegCloseKey(hkeyCriteria));
hkeyCriteria = NULL;
}
// Free up the current criteria
SafeMemFree(m_rgItems);
// Save the new values
m_rgItems = pItems;
pItems = NULL;
m_cItems = cOrder;
// Make sure we clear the dirty bit
m_dwState &= ~CRIT_STATE_DIRTY;
// Note that we have been loaded
m_dwState |= CRIT_STATE_LOADED;
// Set the return value
hr = S_OK;
exit:
SafeMemFree(pbData);
RuleUtil_HrFreeCriteriaItem(pItems, cOrder);
SafeMemFree(pItems);
SafeMemFree(pszOrder);
if (NULL != hkeyCriteria)
{
RegCloseKey(hkeyCriteria);
}
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return hr;
}
STDMETHODIMP COECriteria::SaveReg(LPCSTR pszRegPath, BOOL fClearDirty)
{
HRESULT hr = S_OK;
LONG lErr = 0;
HKEY hkeyRoot = NULL;
DWORD dwDisp = 0;
LPSTR pszOrder = NULL;
ULONG ulIndex = 0;
CRIT_ITEM * pItem = NULL;
CHAR rgchTag[CCH_CRIT_ORDER];
HKEY hkeyCriteria = NULL;
ULONG cbData = 0;
BYTE * pbData = NULL;
// Check incoming param
if (NULL == pszRegPath)
{
hr = E_INVALIDARG;
goto exit;
}
// If there's nothing to save, then fail
if (NULL == m_rgItems)
{
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);
Assert(m_cItems < CRIT_COUNT_MAX);
// Allocate space to hold the order
DWORD cchSize = (m_cItems * CCH_CRIT_ORDER);
hr = HrAlloc((void **) &pszOrder, cchSize * sizeof(*pszOrder));
if (FAILED(hr))
{
goto exit;
}
pszOrder[0] = '\0';
// Write out each of the criteria
for (ulIndex = 0, pItem = m_rgItems; ulIndex < m_cItems; ulIndex++, pItem++)
{
// Get the new criteria tag
wnsprintf(rgchTag, ARRAYSIZE(rgchTag), "%03X", ulIndex);
// Add the new tag to the order
if (0 != ulIndex)
{
StrCatBuff(pszOrder, g_szSpace, cchSize);
}
StrCatBuff(pszOrder, rgchTag, cchSize);
// Create the new criteria
lErr = RegCreateKeyEx(hkeyRoot, rgchTag, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyCriteria, &dwDisp);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
Assert(REG_CREATED_NEW_KEY == dwDisp);
// Write out the criteria type
lErr = RegSetValueEx(hkeyCriteria, c_szCriteriaType, 0, REG_DWORD,
(BYTE *) &(pItem->type), sizeof(pItem->type));
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Write out the criteria logicial op
lErr = RegSetValueEx(hkeyCriteria, c_szCriteriaLogic, 0, REG_DWORD,
(BYTE *) &(pItem->logic), sizeof(pItem->logic));
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Write out the criteria flags
lErr = RegSetValueEx(hkeyCriteria, c_szCriteriaFlags, 0, REG_DWORD,
(BYTE *) &(pItem->dwFlags), sizeof(pItem->dwFlags));
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Do we have a criteria value?
if (VT_EMPTY != pItem->propvar.vt)
{
// Write out the criteria value type
dwDisp = pItem->propvar.vt;
lErr = RegSetValueEx(hkeyCriteria, c_szCriteriaValueType, 0, REG_DWORD, (BYTE *) &dwDisp, sizeof(dwDisp));
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Write out the criteria value
switch (pItem->propvar.vt)
{
case VT_UI4:
dwDisp = REG_DWORD;
pbData = (BYTE * ) &(pItem->propvar.ulVal);
cbData = sizeof(pItem->propvar.ulVal);
break;
case VT_LPSTR:
dwDisp = REG_SZ;
pbData = (BYTE * ) (pItem->propvar.pszVal);
cbData = lstrlen(pItem->propvar.pszVal) + 1;
break;
case VT_BLOB:
dwDisp = REG_BINARY;
pbData = pItem->propvar.blob.pBlobData;
cbData = pItem->propvar.blob.cbSize;
break;
default:
AssertSz(FALSE, "Why are we trying to save in a invalid criteria type?");
hr = E_FAIL;
goto exit;
break;
}
// Write out the criteria value
lErr = RegSetValueEx(hkeyCriteria, c_szCriteriaValue, 0, dwDisp, pbData, cbData);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
}
// Close the criteria
SideAssert(ERROR_SUCCESS == RegCloseKey(hkeyCriteria));
hkeyCriteria = NULL;
}
// Write out the order string.
lErr = RegSetValueEx(hkeyRoot, c_szCriteriaOrder, 0, REG_SZ,
(BYTE *) pszOrder, lstrlen(pszOrder) + 1);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
// Should we clear the dirty bit?
if (FALSE != fClearDirty)
{
m_dwState &= ~CRIT_STATE_DIRTY;
}
// Set the return value
hr = S_OK;
exit:
if (NULL != hkeyCriteria)
{
RegCloseKey(hkeyCriteria);
}
SafeMemFree(pszOrder);
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return hr;
}
STDMETHODIMP COECriteria::Clone(IOECriteria ** ppICriteria)
{
HRESULT hr = S_OK;
COECriteria * pCriteria = NULL;
// Check incoming params
if (NULL == ppICriteria)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the outgoing params
*ppICriteria = NULL;
// Create a new criteria
pCriteria = new COECriteria;
if (NULL == pCriteria)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Copy over the list of criteria
hr = pCriteria->SetCriteria(0, m_rgItems, m_cItems);
if (FAILED(hr))
{
goto exit;
}
// Get the criteria interface
hr = pCriteria->QueryInterface(IID_IOECriteria, (void **) ppICriteria);
if (FAILED(hr))
{
goto exit;
}
pCriteria = NULL;
// Set the proper return value
hr = S_OK;
exit:
if (NULL != pCriteria)
{
delete pCriteria;
}
return hr;
}
STDMETHODIMP COECriteria::GetClassID(CLSID * pclsid)
{
HRESULT hr = S_OK;
if (NULL == pclsid)
{
hr = E_INVALIDARG;
goto exit;
}
*pclsid = CLSID_OECriteria;
// Set the proper return value
hr = S_OK;
exit:
return hr;
}
STDMETHODIMP COECriteria::IsDirty(void)
{
HRESULT hr = S_OK;
hr = (CRIT_STATE_DIRTY == (m_dwState & CRIT_STATE_DIRTY)) ? S_OK : S_FALSE;
return hr;
}
STDMETHODIMP COECriteria::Load(IStream * pStm)
{
HRESULT hr = S_OK;
ULONG cbData = 0;
ULONG cbRead = 0;
DWORD dwData = 0;
ULONG cItems = 0;
CRIT_ITEM * pItems = NULL;
ULONG ulIndex = 0;
CRIT_ITEM * pItem = NULL;
CRIT_TYPE typeCrit;
CRIT_LOGIC logicCrit;
DWORD dwFlags = CRIT_FLAG_DEFAULT;
PROPVARIANT propvar = {0};
BYTE * pbData = 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 != CRIT_VERSION))
{
hr = E_FAIL;
goto exit;
}
// Get the number of criteria
hr = pStm->Read(&cItems, sizeof(cItems), &cbRead);
if (FAILED(hr))
{
goto exit;
}
if ((cbRead != sizeof(cItems)) || (0 == cItems))
{
hr = E_FAIL;
goto exit;
}
// Allocate space to hold all the criteria
hr = HrAlloc( (void **) &pItems, cItems * sizeof(*pItems));
if (FAILED(hr))
{
goto exit;
}
// Initialize the criteria to a known value
ZeroMemory(pItems, cItems * sizeof(*pItems));
// for each criteria
for (ulIndex = 0, pItem = pItems; ulIndex < cItems; ulIndex++, pItem++)
{
// Read in the criteria type
hr = pStm->Read(&typeCrit, sizeof(typeCrit), &cbRead);
if ((FAILED(hr)) || (cbRead != sizeof(typeCrit)))
{
hr = E_FAIL;
goto exit;
}
// Read in the criteria logical op
hr = pStm->Read(&logicCrit, sizeof(logicCrit), &cbRead);
if ((FAILED(hr)) || (cbRead != sizeof(logicCrit)))
{
hr = E_FAIL;
goto exit;
}
// Read in the criteria flags
hr = pStm->Read(&dwFlags, sizeof(dwFlags), &cbRead);
if ((FAILED(hr)) || (cbRead != sizeof(dwFlags)))
{
hr = E_FAIL;
goto exit;
}
// Read in the proper criteria value
switch(typeCrit)
{
case CRIT_TYPE_ACCOUNT:
if (FALSE == FCritLoad_Account(pStm, &propvar))
{
hr = E_FAIL;
goto exit;
}
break;
default:
if (FALSE == FCritLoad_Default(pStm, &propvar))
{
hr = E_FAIL;
goto exit;
}
break;
}
// Assign the values
pItem->type = typeCrit;
pItem->logic = logicCrit;
pItem->dwFlags = dwFlags;
pItem->propvar = propvar;
ZeroMemory(&propvar, sizeof(propvar));
}
// Free up the current criteria
SafeMemFree(m_rgItems);
// Save the new values
m_rgItems = pItems;
pItems = NULL;
m_cItems = cItems;
// Make sure we clear the dirty bit
m_dwState &= ~CRIT_STATE_DIRTY;
// Note that we have been loaded
m_dwState |= CRIT_STATE_LOADED;
// Set the return value
hr = S_OK;
exit:
RuleUtil_HrFreeCriteriaItem(pItems, cItems);
SafeMemFree(pItems);
PropVariantClear(&propvar);
return hr;
}
STDMETHODIMP COECriteria::Save(IStream * pStm, BOOL fClearDirty)
{
HRESULT hr = S_OK;
ULONG cbData = 0;
ULONG cbWritten = 0;
DWORD dwData = 0;
ULONG ulIndex = 0;
CRIT_ITEM * pItem = NULL;
BYTE * pbData = NULL;
// Check incoming param
if (NULL == pStm)
{
hr = E_INVALIDARG;
goto exit;
}
// Write out the version
dwData = CRIT_VERSION;
hr = pStm->Write(&dwData, sizeof(dwData), &cbWritten);
if (FAILED(hr))
{
goto exit;
}
Assert(cbWritten == sizeof(dwData));
// Write out the count of criteria
hr = pStm->Write(&m_cItems, sizeof(m_cItems), &cbWritten);
if (FAILED(hr))
{
goto exit;
}
Assert(cbWritten == sizeof(m_cItems));
// Loop through each of the criteria
for (ulIndex = 0, pItem = m_rgItems; ulIndex < m_cItems; ulIndex++, pItem++)
{
// Write out the criteria type
hr = pStm->Write(&(pItem->type), sizeof(pItem->type), &cbWritten);
if (FAILED(hr))
{
goto exit;
}
Assert(cbWritten == sizeof(pItem->type));
// Write out the criteria logical op
hr = pStm->Write(&(pItem->logic), sizeof(pItem->logic), &cbWritten);
if (FAILED(hr))
{
goto exit;
}
Assert(cbWritten == sizeof(pItem->logic));
// Write out the criteria flags
hr = pStm->Write(&(pItem->dwFlags), sizeof(pItem->dwFlags), &cbWritten);
if (FAILED(hr))
{
goto exit;
}
Assert(cbWritten == sizeof(pItem->dwFlags));
// Write out the proper criteria value
switch(pItem->type)
{
case CRIT_TYPE_ACCOUNT:
if (FALSE == FCritSave_Account(pStm, &(pItem->propvar)))
{
hr = E_FAIL;
goto exit;
}
break;
default:
if (FALSE == FCritSave_Default(pStm, &(pItem->propvar)))
{
hr = E_FAIL;
goto exit;
}
break;
}
}
// Should we clear out the dirty bit
if (FALSE != fClearDirty)
{
m_dwState &= ~CRIT_STATE_DIRTY;
}
// Set the return value
hr = S_OK;
exit:
return hr;
}
BOOL CritFunc_Query(CRIT_ITEM * pItem, LPCSTR pszQuery, IMimePropertySet * pIMPropSet);
BOOL CritFunc_Text(CRIT_ITEM * pItem, LPSTR pszText);
BOOL CritFunc_Sender(CRIT_ITEM * pItem, LPSTR pszAddr);
BOOL CritFunc_Priority(CRIT_ITEM * pItem, WORD wPriority);
BOOL CritFunc_Secure(CRIT_ITEM * pItem, DWORD dwFlags);
BOOL CritFunc_Age(CRIT_ITEM * pItem, FILETIME * pftSent);
BOOL CritFunc_Body(CRIT_ITEM * pItem, IMimeMessage * pIMMsg);
BOOL _FMatchBlobString(CRIT_ITEM * pItem, LPSTR pszText);
BOOL _FQueryBlobString(CRIT_ITEM * pItem, LPCSTR pszQuery, IMimePropertySet * pIMPropSet);
BOOL FMatchCritItem(CRIT_ITEM * pItem, LPCSTR pszAcct, MESSAGEINFO * pMsgInfo,
IMessageFolder * pFolder, IMimePropertySet * pIMPropSet,
IMimeMessage * pIMMsg, ULONG cbMsgSize)
{
BOOL fRet = FALSE;
ULONG ulIndex = 0;
PROPVARIANT propvar = {0};
ADDRESSLIST addrList = {0};
FOLDERID idFolder = 0;
RULEFOLDERDATA * prfdData = NULL;
Assert((NULL != pItem) && ((NULL != pMsgInfo) || (NULL != pIMPropSet)) && (0 != cbMsgSize))
switch (pItem->type)
{
case CRIT_TYPE_ALL:
Assert(VT_EMPTY == pItem->propvar.vt);
fRet = TRUE;
break;
case CRIT_TYPE_ACCOUNT:
Assert(VT_LPSTR == pItem->propvar.vt);
fRet = FALSE;
if ((NULL != pszAcct) && (NULL != pItem->propvar.pszVal))
{
fRet = (0 == lstrcmpi(pItem->propvar.pszVal, pszAcct));
}
break;
case CRIT_TYPE_NEWSGROUP:
Assert(VT_BLOB == pItem->propvar.vt);
fRet = FALSE;
if ((NULL != pFolder) && (0 != pItem->propvar.blob.cbSize))
{
// Make life simpler
prfdData = (RULEFOLDERDATA *) (pItem->propvar.blob.pBlobData);
// Validate the rule folder data
if (S_OK != RuleUtil_HrValidateRuleFolderData(prfdData))
{
fRet = FALSE;
}
else if (SUCCEEDED(pFolder->GetFolderId(&idFolder)))
{
fRet = (idFolder == prfdData->idFolder);
}
}
break;
case CRIT_TYPE_SIZE:
Assert(VT_UI4 == pItem->propvar.vt);
// Set the size of the message to Kilobytes
cbMsgSize = cbMsgSize / 1024;
fRet = (cbMsgSize > pItem->propvar.ulVal);
break;
case CRIT_TYPE_LINES:
Assert(VT_UI4 == pItem->propvar.vt);
fRet = FALSE;
if (NULL != pMsgInfo)
{
fRet = (pMsgInfo->cLines > pItem->propvar.ulVal);
}
break;
case CRIT_TYPE_AGE:
Assert(VT_UI4 == pItem->propvar.vt);
fRet = FALSE;
if (NULL != pMsgInfo)
{
fRet = CritFunc_Age(pItem, &(pMsgInfo->ftSent));
}
else if ((NULL != pIMPropSet) && (SUCCEEDED(pIMPropSet->GetProp(PIDTOSTR(PID_ATT_SENTTIME), 0, &propvar))))
{
fRet = CritFunc_Age(pItem, &(propvar.filetime));
}
break;
case CRIT_TYPE_ATTACH:
Assert(VT_EMPTY == pItem->propvar.vt);
fRet = TRUE;
if (NULL != pMsgInfo)
{
fRet = (0 != (pMsgInfo->dwFlags & ARF_HASATTACH));
}
else if (NULL != pIMMsg)
{
fRet = (0 != (DwGetFlagsFromMessage(pIMMsg) & ARF_HASATTACH));
}
break;
case CRIT_TYPE_PRIORITY:
Assert(VT_UI4 == pItem->propvar.vt);
fRet = FALSE;
if (NULL != pMsgInfo)
{
fRet = CritFunc_Priority(pItem, pMsgInfo->wPriority);
}
else if ((NULL != pIMPropSet) && (SUCCEEDED(pIMPropSet->GetProp(PIDTOSTR(PID_ATT_PRIORITY), 0, &propvar))))
{
fRet = CritFunc_Priority(pItem, (WORD) (propvar.ulVal));
}
break;
case CRIT_TYPE_SECURE:
Assert(VT_UI4 == pItem->propvar.vt);
fRet = FALSE;
if (NULL != pMsgInfo)
{
fRet = CritFunc_Secure(pItem, pMsgInfo->dwFlags);
}
else if (NULL != pIMMsg)
{
fRet = CritFunc_Secure(pItem, DwGetFlagsFromMessage(pIMMsg));
}
break;
case CRIT_TYPE_TOORCC:
Assert(VT_BLOB == pItem->propvar.vt);
fRet = FALSE;
if (NULL != pIMPropSet)
{
fRet = _FQueryBlobString(pItem, PIDTOSTR(PID_HDR_TO), pIMPropSet);
if (((0 != (pItem->dwFlags & CRIT_FLAG_INVERT)) && (FALSE != fRet)) ||
((0 == (pItem->dwFlags & CRIT_FLAG_INVERT)) && (FALSE == fRet)))
{
fRet = _FQueryBlobString(pItem, PIDTOSTR(PID_HDR_CC), pIMPropSet);
}
}
break;
case CRIT_TYPE_SENDER:
Assert(VT_LPSTR == pItem->propvar.vt);
fRet = FALSE;
if ((NULL == pItem->propvar.pszVal) || ('\0' == pItem->propvar.pszVal[0]))
{
Assert(FALSE);
}
else if (S_OK == RuleUtil_HrMatchSender(pItem->propvar.pszVal, pMsgInfo, pIMMsg, pIMPropSet))
{
fRet = TRUE;
}
break;
case CRIT_TYPE_SUBJECT:
Assert(VT_BLOB == pItem->propvar.vt);
fRet = FALSE;
if ((0 == pItem->propvar.blob.cbSize) ||
(NULL == pItem->propvar.blob.pBlobData) ||
('\0' == pItem->propvar.blob.pBlobData[0]))
{
Assert(FALSE);
fRet = FALSE;
}
else if ((NULL != pMsgInfo) && (NULL != pMsgInfo->pszSubject))
{
fRet = _FMatchBlobString(pItem, pMsgInfo->pszSubject);
}
else
{
fRet = _FQueryBlobString(pItem, PIDTOSTR(PID_HDR_SUBJECT), pIMPropSet);
}
break;
case CRIT_TYPE_BODY:
Assert(VT_BLOB == pItem->propvar.vt);
fRet = FALSE;
if ((0 == pItem->propvar.blob.cbSize) ||
(NULL == pItem->propvar.blob.pBlobData) ||
('\0' == pItem->propvar.blob.pBlobData[0]))
{
Assert(FALSE);
fRet = FALSE;
}
else if (NULL != pIMMsg)
{
fRet = CritFunc_Body(pItem, pIMMsg);
}
break;
case CRIT_TYPE_FROM:
Assert(VT_BLOB == pItem->propvar.vt);
fRet = FALSE;
if ((0 == pItem->propvar.blob.cbSize) ||
(NULL == pItem->propvar.blob.pBlobData) ||
('\0' == pItem->propvar.blob.pBlobData[0]))
{
Assert(FALSE);
fRet = FALSE;
}
else if ((NULL != pMsgInfo) && (NULL != pMsgInfo->pszFromHeader))
{
fRet = _FMatchBlobString(pItem, pMsgInfo->pszFromHeader);
}
else
{
fRet = _FQueryBlobString(pItem, PIDTOSTR(PID_HDR_FROM), pIMPropSet);
}
break;
case CRIT_TYPE_TO:
Assert(VT_BLOB == pItem->propvar.vt);
fRet = FALSE;
if ((0 == pItem->propvar.blob.cbSize) ||
(NULL == pItem->propvar.blob.pBlobData) ||
('\0' == pItem->propvar.blob.pBlobData[0]))
{
Assert(FALSE);
fRet = FALSE;
}
else
{
fRet = _FQueryBlobString(pItem, PIDTOSTR(PID_HDR_TO), pIMPropSet);
}
break;
case CRIT_TYPE_CC:
Assert(VT_BLOB == pItem->propvar.vt);
fRet = FALSE;
if ((0 == pItem->propvar.blob.cbSize) ||
(NULL == pItem->propvar.blob.pBlobData) ||
('\0' == pItem->propvar.blob.pBlobData[0]))
{
Assert(FALSE);
fRet = FALSE;
}
else
{
fRet = _FQueryBlobString(pItem, PIDTOSTR(PID_HDR_CC), pIMPropSet);
}
break;
default:
fRet = FALSE;
break;
}
PropVariantClear(&propvar);
return fRet;
}
BOOL CritFunc_Query(CRIT_ITEM * pItem, LPCSTR pszQuery, IMimePropertySet * pIMPropSet)
{
BOOL fRet = FALSE;
LPSTR pszWalk = NULL;
LPSTR pszAddr = NULL;
LPSTR pszTerm = NULL;
HRESULT hr = S_OK;
if (NULL == pIMPropSet)
{
fRet = FALSE;
goto exit;
}
// Dup the string
pszAddr = PszDupA(pItem->propvar.pszVal);
if (NULL == pszAddr)
{
fRet = FALSE;
goto exit;
}
pszWalk = pszAddr;
pszTerm = pszWalk;
while (NULL != pszTerm)
{
pszTerm = StrStr(pszWalk, g_szComma);
if (NULL != pszTerm)
{
pszTerm[0] = '\0';
}
fRet = (S_OK == pIMPropSet->QueryProp(pszQuery, pszWalk, TRUE, FALSE));
if (FALSE == fRet)
{
break;
}
pszWalk = pszWalk + lstrlen(pszWalk) + 1;
}
exit:
SafeMemFree(pszAddr);
return fRet;
}
BOOL CritFunc_Priority(CRIT_ITEM * pItem, WORD wPriority)
{
BOOL fRet = FALSE;
Assert(NULL != pItem);
Assert(VT_UI4 == pItem->propvar.vt);
if (CRIT_DATA_HIPRI == pItem->propvar.ulVal)
{
fRet = (wPriority == (WORD) IMSG_PRI_HIGH);
}
else if (CRIT_DATA_LOPRI == pItem->propvar.ulVal)
{
fRet = (wPriority == (WORD) IMSG_PRI_LOW);
}
else
{
fRet = (wPriority == (WORD) IMSG_PRI_NORMAL);
}
return fRet;
}
BOOL CritFunc_Secure(CRIT_ITEM * pItem, DWORD dwFlags)
{
BOOL fRet = FALSE;
Assert(NULL != pItem);
Assert(VT_UI4 == pItem->propvar.vt);
// Should we be checking signed messages
if (0 != (pItem->propvar.ulVal & CRIT_DATA_SIGNEDSECURE))
{
fRet = (0 != (dwFlags & ARF_SIGNED));
}
else if (0 != (pItem->propvar.ulVal & CRIT_DATA_ENCRYPTSECURE))
// Should we be checking encrypted messages
{
fRet = (0 != (dwFlags & ARF_ENCRYPTED));
}
else
{
fRet = (0 == (dwFlags & (ARF_ENCRYPTED | ARF_SIGNED)));
}
return fRet;
}
BOOL CritFunc_Age(CRIT_ITEM * pItem, FILETIME * pftSent)
{
BOOL fRet = FALSE;
SYSTEMTIME sysTime = {0};
FILETIME ftTime = {0};
ULONG ulSeconds;
Assert(VT_UI4 == pItem->propvar.vt);
if ((NULL == pftSent) || ((0 == pftSent->dwLowDateTime) && (0 == pftSent->dwHighDateTime)))
{
fRet = FALSE;
goto exit;
}
// Get the current time
GetSystemTime(&sysTime);
SystemTimeToFileTime(&sysTime, &ftTime);
ulSeconds = UlDateDiff(pftSent, &ftTime);
fRet = ((ulSeconds / SECONDS_INA_DAY) > pItem->propvar.ulVal);
exit:
return fRet;
}
BOOL CritFunc_Sender(CRIT_ITEM * pItem, LPSTR pszAddr)
{
BOOL fRet = FALSE;
ULONG cchVal = 0;
ULONG cchEmail = 0;
CHAR chTest = 0;
Assert(VT_LPSTR == pItem->propvar.vt);
// Check to make sure that there's something to match
if ((NULL == pszAddr) || ('\0' == pszAddr[0]))
{
fRet = FALSE;
goto exit;
}
// Check to see if it is an address
if (NULL != StrStr(pItem->propvar.pszVal, "@"))
{
fRet = (0 == lstrcmpi(pItem->propvar.pszVal, pszAddr));
}
else
{
cchVal = lstrlen(pItem->propvar.pszVal);
cchEmail = lstrlen(pszAddr);
if (cchVal <= cchEmail)
{
fRet = (0 == lstrcmpi(pItem->propvar.pszVal, pszAddr + (cchEmail - cchVal)));
if ((FALSE != fRet) && (cchVal != cchEmail))
{
chTest = *(pszAddr + (cchEmail - cchVal - 1));
if (('@' != chTest) && ('.' != chTest))
{
fRet = FALSE;
}
}
}
}
exit:
return fRet;
}
BOOL _FMatchBlobString(CRIT_ITEM * pItem, LPSTR pszText)
{
BOOL fRet = FALSE;
LPSTR pszWalk = NULL;
// Walk each of the strings looking for a match
for (pszWalk = (LPSTR) (pItem->propvar.blob.pBlobData); '\0' != pszWalk[0];
pszWalk = pszWalk + lstrlen(pszWalk) + 1)
{
// Do the comparison
fRet = (NULL != StrStrI(pszText, pszWalk));
// If we are doing an AND of the multiple criteria
if (0 != (pItem->dwFlags & CRIT_FLAG_MULTIPLEAND))
{
// if we don't have a match, then we're done
if (FALSE == fRet)
{
break;
}
}
else
{
// if we do have a match, then we're done
if (FALSE != fRet)
{
break;
}
}
}
// Invert the result if needed
if (0 != (pItem->dwFlags & CRIT_FLAG_INVERT))
{
fRet = !fRet;
}
return fRet;
}
BOOL _FQueryBlobString(CRIT_ITEM * pItem, LPCSTR pszQuery, IMimePropertySet * pIMPropSet)
{
BOOL fRet = FALSE;
LPSTR pszWalk = NULL;
if (NULL == pIMPropSet)
{
fRet = FALSE;
goto exit;
}
// Walk each of the strings looking for a match
for (pszWalk = (LPSTR) (pItem->propvar.blob.pBlobData); '\0' != pszWalk[0];
pszWalk = pszWalk + lstrlen(pszWalk) + 1)
{
// Do the comparison
fRet = (S_OK == pIMPropSet->QueryProp(pszQuery, pszWalk, TRUE, FALSE));
// If we are doing an AND of the multiple criteria
if (0 != (pItem->dwFlags & CRIT_FLAG_MULTIPLEAND))
{
// if we don't have a match, then we're done
if (FALSE == fRet)
{
break;
}
}
else
{
// if we do have a match, then we're done
if (FALSE != fRet)
{
break;
}
}
}
// Invert the result if needed
if (0 != (pItem->dwFlags & CRIT_FLAG_INVERT))
{
fRet = !fRet;
}
exit:
return fRet;
}
BOOL CritFunc_Text(CRIT_ITEM * pItem, LPSTR pszText)
{
BOOL fRet = FALSE;
LPSTR pszWalk = NULL;
LPSTR pszAddr = NULL;
LPSTR pszTerm = NULL;
// Dup the string
pszAddr = PszDupA(pItem->propvar.pszVal);
if (NULL == pszAddr)
{
fRet = FALSE;
goto exit;
}
pszWalk = pszAddr;
pszTerm = pszWalk;
while (NULL != pszTerm)
{
pszTerm = StrStr(pszWalk, g_szComma);
if (NULL != pszTerm)
{
pszTerm[0] = '\0';
}
fRet = (NULL != StrStrI(pszText, pszWalk));
if (FALSE == fRet)
{
break;
}
pszWalk = pszWalk + lstrlen(pszWalk) + 1;
}
exit:
SafeMemFree(pszAddr);
return fRet;
}
BOOL CritFunc_Body(CRIT_ITEM * pItem, IMimeMessage * pIMMsg)
{
BOOL fRet = FALSE;
LPSTR pszWalk = NULL;
IStream * pStream = NULL;
IStream * pStreamHtml = NULL;
pszWalk = (LPTSTR) (pItem->propvar.blob.pBlobData);
if (NULL == pszWalk)
{
fRet = FALSE;
goto exit;
}
// Try to Get the Plain Text Stream
if (FAILED(pIMMsg->GetTextBody(TXT_PLAIN, IET_DECODED, &pStream, NULL)))
{
// Try to get the HTML stream and convert it to text...
if (SUCCEEDED(pIMMsg->GetTextBody(TXT_HTML, IET_DECODED, &pStreamHtml, NULL)))
{
if (FAILED(HrConvertHTMLToPlainText(pStreamHtml, &pStream, CF_TEXT)))
{
fRet = FALSE;
goto exit;
}
}
}
if (NULL == pStream)
{
fRet = FALSE;
goto exit;
}
for (; '\0' != pszWalk[0]; pszWalk += lstrlen(pszWalk) + 1)
{
fRet = StreamSubStringMatch(pStream, pszWalk);
// If we are doing an AND of the multiple criteria
if (0 != (pItem->dwFlags & CRIT_FLAG_MULTIPLEAND))
{
// if we don't have a match, then we're done
if (FALSE == fRet)
{
break;
}
}
else
{
// if we do have a match, then we're done
if (FALSE != fRet)
{
break;
}
}
}
// Invert the result if needed
if (0 != (pItem->dwFlags & CRIT_FLAG_INVERT))
{
fRet = !fRet;
}
exit:
SafeRelease(pStreamHtml);
SafeRelease(pStream);
return fRet;
}
BOOL FCrit_GetAcctInfo(DWORD dwServerTypes, DWORD * pdwServerType, DWORD * pdwPropTag)
{
BOOL fRet = FALSE;
Assert((NULL != pdwServerType) && (NULL != pdwPropTag));
// Figure out the type of the account
// and the server property
if (0 != (dwServerTypes & SRV_NNTP))
{
*pdwServerType = SRV_NNTP;
*pdwPropTag = AP_NNTP_SERVER;
}
else if (0 != (dwServerTypes & SRV_IMAP))
{
*pdwServerType = SRV_IMAP;
*pdwPropTag = AP_IMAP_SERVER;
}
else if (0 != (dwServerTypes & SRV_POP3))
{
*pdwServerType = SRV_POP3;
*pdwPropTag = AP_POP3_SERVER;
}
else if (0 != (dwServerTypes & SRV_HTTPMAIL))
{
*pdwServerType = SRV_HTTPMAIL;
*pdwPropTag = AP_HTTPMAIL_SERVER;
}
else
{
Assert(FALSE);
fRet = FALSE;
goto exit;
}
// Set the return value
fRet = TRUE;
exit:
return fRet;
}
BOOL FCritLoad_Account(IStream * pIStm, PROPVARIANT * ppropvar)
{
BOOL fRet = FALSE;
HRESULT hr = S_OK;
DWORD dwData = 0;
DWORD dwPropTag = 0;
ULONG cbRead = 0;
BYTE * pbData = NULL;
ULONG cbData = 0;
IImnEnumAccounts * pIEnumAcct = NULL;
IImnAccount * pAccount = NULL;
CHAR szAccount[CCHMAX_SERVER_NAME];
LPSTR pszAcct = NULL;
BOOL fFound = FALSE;
// Check the incoming params
if ((NULL == pIStm) || (NULL == ppropvar))
{
fRet = FALSE;
goto exit;
}
// Initialize the outgoing param
ZeroMemory(ppropvar, sizeof(*ppropvar));
// Read in the account server type
hr = pIStm->Read(&dwData, sizeof(dwData), &cbRead);
if ((FAILED(hr)) || (cbRead != sizeof(dwData)))
{
fRet = FALSE;
goto exit;
}
// Figure out the type of the account
// and the server property
fRet = FCrit_GetAcctInfo(dwData, &dwData, &dwPropTag);
if (FALSE == fRet)
{
goto exit;
}
// Get the size of the server name
hr = pIStm->Read(&cbData, sizeof(cbData), &cbRead);
if ((FAILED(hr)) || (cbRead != sizeof(cbData)))
{
fRet = FALSE;
goto exit;
}
// Allocate the space to hold the server name
hr = HrAlloc((VOID **) &pbData, cbData);
if (FAILED(hr))
{
fRet = FALSE;
goto exit;
}
// Read in the server name
hr = pIStm->Read(pbData, cbData, &cbRead);
if ((FAILED(hr)) || (cbRead != cbData))
{
fRet = FALSE;
goto exit;
}
// Get an account enumerator
Assert(g_pAcctMan);
if (FAILED(g_pAcctMan->Enumerate(dwData, &pIEnumAcct)))
{
fRet = FALSE;
goto exit;
}
// Search each account for the server name
while(SUCCEEDED(pIEnumAcct->GetNext(&pAccount)))
{
// We can get back NULL accounts
if (NULL == pAccount)
{
break;
}
// Get the server name
if (FAILED(pAccount->GetPropSz(dwPropTag, szAccount, sizeof(szAccount))))
{
SafeRelease(pAccount);
continue;
}
// Do we have a match?
if (0 == lstrcmpi(szAccount, (LPSTR) pbData))
{
fFound = TRUE;
break;
}
// We have a match
// Release it
SafeRelease(pAccount);
}
// Did we find anything?
if (FALSE == fFound)
{
fRet = FALSE;
goto exit;
}
// Get the account
if (FAILED(pAccount->GetPropSz(AP_ACCOUNT_ID, szAccount, sizeof(szAccount))))
{
fRet = FALSE;
goto exit;
}
// Save off the account ID
pszAcct = PszDupA(szAccount);
if (NULL == pszAcct)
{
fRet = FALSE;
goto exit;
}
// Set the outgoing param
ppropvar->vt = VT_LPSTR;
ppropvar->pszVal = pszAcct;
pszAcct = NULL;
// Set the return value
fRet = TRUE;
exit:
SafeMemFree(pszAcct);
SafeRelease(pAccount);
SafeRelease(pIEnumAcct);
SafeMemFree(pbData);
return fRet;
}
BOOL FCritSave_Account(IStream * pIStm, PROPVARIANT * ppropvar)
{
BOOL fRet = FALSE;
HRESULT hr = S_OK;
IImnAccount * pAccount = NULL;
DWORD dwServerTypes = 0;
DWORD dwPropTag = 0;
LPSTR pszServer = NULL;
ULONG cbWritten = 0;
ULONG cbData = 0;
// Check the incoming params
if ((NULL == pIStm) || (NULL == ppropvar))
{
fRet = FALSE;
goto exit;
}
Assert(g_pAcctMan);
if (FAILED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, ppropvar->pszVal, &pAccount)))
{
fRet = FALSE;
goto exit;
}
// Get the server type
if (FAILED(pAccount->GetServerTypes(&dwServerTypes)))
{
fRet = FALSE;
goto exit;
}
// Figure out the type of the account
// and the server property
fRet = FCrit_GetAcctInfo(dwServerTypes, &dwServerTypes, &dwPropTag);
if (FALSE == fRet)
{
goto exit;
}
// Allocate space to hold the server name
if (FAILED(HrAlloc((void **) &pszServer, CCHMAX_SERVER_NAME + 1)))
{
fRet = FALSE;
goto exit;
}
// Get the server name
if (FAILED(pAccount->GetPropSz(dwPropTag, pszServer, CCHMAX_SERVER_NAME)))
{
fRet = FALSE;
goto exit;
}
// Write out the server type
hr = pIStm->Write(&(dwServerTypes), sizeof(dwServerTypes), &cbWritten);
if (FAILED(hr))
{
fRet = FALSE;
goto exit;
}
Assert(cbWritten == sizeof(dwServerTypes));
// Write out the count of chars in the name
cbData = lstrlen(pszServer) + 1;
hr = pIStm->Write(&cbData, sizeof(cbData), &cbWritten);
if (FAILED(hr))
{
fRet = TRUE;
goto exit;
}
Assert(cbWritten == sizeof(cbData));
// Write out the server name
hr = pIStm->Write((BYTE *) pszServer, cbData, &cbWritten);
if (FAILED(hr))
{
fRet = TRUE;
goto exit;
}
Assert(cbWritten == cbData);
// Set the return value
fRet = TRUE;
exit:
SafeMemFree(pszServer);
SafeRelease(pAccount);
return fRet;
}
BOOL FCritLoad_Default(IStream * pIStm, PROPVARIANT * ppropvar)
{
BOOL fRet = FALSE;
HRESULT hr = S_OK;
DWORD dwData = 0;
ULONG cbRead = 0;
BYTE * pbData = NULL;
ULONG cbData = 0;
// Check the incoming params
if ((NULL == pIStm) || (NULL == ppropvar))
{
fRet = FALSE;
goto exit;
}
// Initialize the outgoing param
ZeroMemory(ppropvar, sizeof(*ppropvar));
// Read in the criteria value type
hr = pIStm->Read(&dwData, sizeof(dwData), &cbRead);
if ((FAILED(hr)) || (cbRead != sizeof(dwData)))
{
fRet = FALSE;
goto exit;
}
// Do we have any more data to get
if (dwData != VT_EMPTY)
{
ppropvar->vt = (VARTYPE) dwData;
// Get the size of the criteria value
hr = pIStm->Read(&cbData, sizeof(cbData), &cbRead);
if ((FAILED(hr)) || (cbRead != sizeof(cbData)))
{
fRet = FALSE;
goto exit;
}
// Allocate space to hold the criteria value data
switch (ppropvar->vt)
{
case VT_UI4:
pbData = (BYTE * ) &(ppropvar->ulVal);
break;
case VT_BLOB:
case VT_LPSTR:
// Allocate the space to hold the data
hr = HrAlloc((void **) &pbData, cbData);
if (FAILED(hr))
{
fRet = FALSE;
goto exit;
}
// Make sure we don't lose the allocated memory
if (VT_LPSTR == ppropvar->vt)
{
ppropvar->pszVal = (LPSTR) pbData;
}
else
{
ppropvar->blob.cbSize = cbData;
ppropvar->blob.pBlobData = pbData;
}
break;
default:
AssertSz(FALSE, "Why are we trying to save in a invalid criteria type?");
fRet = FALSE;
goto exit;
break;
}
// Read in the criteria value
hr = pIStm->Read(pbData, cbData, &cbRead);
if ((FAILED(hr)) || (cbRead != cbData))
{
fRet = FALSE;
goto exit;
}
}
// Set the return value
fRet = TRUE;
exit:
return fRet;
}
BOOL FCritSave_Default(IStream * pIStm, PROPVARIANT * ppropvar)
{
BOOL fRet = FALSE;
HRESULT hr = S_OK;
DWORD dwData = 0;
ULONG cbWritten = 0;
BYTE * pbData = NULL;
ULONG cbData = 0;
// Check the incoming params
if ((NULL == pIStm) || (NULL == ppropvar))
{
fRet = FALSE;
goto exit;
}
// Write out the value type
dwData = ppropvar->vt;
hr = pIStm->Write(&(dwData), sizeof(dwData), &cbWritten);
if (FAILED(hr))
{
fRet = FALSE;
goto exit;
}
Assert(cbWritten == sizeof(dwData));
// We don't have to save out the criteria value
// if we don't have one
if (VT_EMPTY == ppropvar->vt)
{
fRet = TRUE;
goto exit;
}
// Figure out the size of the criteria value
switch (ppropvar->vt)
{
case VT_UI4:
pbData = (BYTE * ) &(ppropvar->ulVal);
cbData = sizeof(ppropvar->ulVal);
break;
case VT_LPSTR:
pbData = (BYTE * ) (ppropvar->pszVal);
cbData = lstrlen(ppropvar->pszVal) + 1;
break;
case VT_BLOB:
pbData = ppropvar->blob.pBlobData;
cbData = ppropvar->blob.cbSize;
break;
default:
AssertSz(FALSE, "Why are we trying to save in a invalid criteria type?");
fRet = FALSE;
goto exit;
break;
}
// Write out the criteria value size
hr = pIStm->Write(&cbData, sizeof(cbData), &cbWritten);
if (FAILED(hr))
{
fRet = TRUE;
goto exit;
}
Assert(cbWritten == sizeof(cbData));
// Write out the criteria value
hr = pIStm->Write(pbData, cbData, &cbWritten);
if (FAILED(hr))
{
fRet = TRUE;
goto exit;
}
Assert(cbWritten == cbData);
// Set the return value
fRet = TRUE;
exit:
return fRet;
}
DWORD DwGetFlagsFromMessage(IMimeMessage * pIMMsg)
{
DWORD dwFlags = 0;
DWORD dwImf = 0;
Assert(NULL != pIMMsg);
if (SUCCEEDED(pIMMsg->GetFlags(&dwImf)))
{
dwFlags = ConvertIMFFlagsToARF(dwImf);
}
return dwFlags;
}