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.
1335 lines
32 KiB
1335 lines
32 KiB
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// JunkRule.cpp
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <pch.hxx>
|
|
#include "junkrule.h"
|
|
#include "msoejunk.h"
|
|
#include "strconst.h"
|
|
#include "goptions.h"
|
|
#include "criteria.h"
|
|
#include "actions.h"
|
|
#include "ruleutil.h"
|
|
#include <ipab.h>
|
|
#include <shlwapip.h>
|
|
|
|
typedef HRESULT (WINAPI * TYP_HrCreateJunkFilter) (DWORD dwFlags, IOEJunkFilter ** ppIJunkFilter);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HrCreateJunkRule
|
|
//
|
|
// This creates a junk rule.
|
|
//
|
|
// ppIRule - pointer to return the junk rule
|
|
//
|
|
// Returns: S_OK, on success
|
|
// E_OUTOFMEMORY, if can't create the JunkRule object
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT HrCreateJunkRule(IOERule ** ppIRule)
|
|
{
|
|
COEJunkRule * pRule = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
// Check the incoming params
|
|
if (NULL == ppIRule)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize outgoing params
|
|
*ppIRule = NULL;
|
|
|
|
// Create the rules manager object
|
|
pRule = new COEJunkRule;
|
|
if (NULL == pRule)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
// Note that we have a reference
|
|
pRule->AddRef();
|
|
|
|
// Initialize the junk rule
|
|
hr = pRule->HrInit(c_szJunkDll, c_szJunkFile);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Get the rules manager interface
|
|
hr = pRule->QueryInterface(IID_IOERule, (void **) ppIRule);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Set the proper return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
SafeRelease(pRule);
|
|
return hr;
|
|
}
|
|
|
|
COEJunkRule::~COEJunkRule()
|
|
{
|
|
IUnknown * pIUnkOuter = NULL;
|
|
|
|
AssertSz(m_cRef == 0, "Somebody still has a hold of us!!");
|
|
|
|
// Prevent recursive destruction on the next
|
|
// AddRef/Release pair
|
|
if (NULL != m_pIAddrList)
|
|
{
|
|
m_cRef = 1;
|
|
|
|
// Counter the Release call in the creation function
|
|
pIUnkOuter = this;
|
|
pIUnkOuter->AddRef();
|
|
|
|
// Release the aggregated interface
|
|
m_pIAddrList->Release();
|
|
m_pIAddrList = NULL;
|
|
}
|
|
|
|
SafeRelease(m_pIUnkInner);
|
|
SafeRelease(m_pIJunkFilter);
|
|
SafeMemFree(m_pszJunkDll);
|
|
SafeMemFree(m_pszDataFile);
|
|
if (NULL != m_hinst)
|
|
{
|
|
FreeLibrary(m_hinst);
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) COEJunkRule::AddRef()
|
|
{
|
|
return ::InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) COEJunkRule::Release()
|
|
{
|
|
LONG cRef = 0;
|
|
|
|
cRef = ::InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef)
|
|
{
|
|
delete this;
|
|
return cRef;
|
|
}
|
|
|
|
return cRef;
|
|
}
|
|
|
|
STDMETHODIMP COEJunkRule::QueryInterface(REFIID riid, void ** ppvObject)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Check the incoming params
|
|
if (NULL == ppvObject)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize outgoing param
|
|
*ppvObject = NULL;
|
|
|
|
if ((riid == IID_IUnknown) || (riid == IID_IOERule))
|
|
{
|
|
*ppvObject = static_cast<IUnknown *>(this);
|
|
}
|
|
else if (riid == IID_IOERule)
|
|
{
|
|
*ppvObject = static_cast<IOERule *>(this);
|
|
}
|
|
else if (riid == IID_IOERuleAddrList)
|
|
{
|
|
*ppvObject = m_pIAddrList;
|
|
}
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
goto exit;
|
|
}
|
|
|
|
reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();
|
|
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEJunkRule::Reset(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Set the current state
|
|
m_dwState |= RULE_STATE_INIT;
|
|
|
|
// Clear the dirty bit
|
|
m_dwState &= ~RULE_STATE_DIRTY;
|
|
|
|
// Set the return value
|
|
hr = S_OK;
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEJunkRule::GetState(DWORD * pdwState)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG ulIndex = 0;
|
|
|
|
// Check incoming params
|
|
if (NULL == pdwState)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// If we're not enabled
|
|
if ((0 != (m_dwState & RULE_STATE_DISABLED)) || (0 != (m_dwState & RULE_STATE_INVALID)))
|
|
{
|
|
*pdwState = RULE_STATE_NULL;
|
|
}
|
|
else
|
|
{
|
|
*pdwState = CRIT_STATE_ALL | ACT_STATE_LOCAL;
|
|
}
|
|
|
|
// Set the proper return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEJunkRule::GetProp(RULE_PROP prop, DWORD dwFlags, PROPVARIANT * pvarResult)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TCHAR szRes[CCHMAX_STRINGRES];
|
|
LPSTR pszName = NULL;
|
|
CRIT_ITEM * pCrit = NULL;
|
|
ACT_ITEM * pAct = NULL;
|
|
ULONG cItem = 0;
|
|
|
|
// Check incoming params
|
|
if (NULL == pvarResult)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize outgoing params
|
|
ZeroMemory(pvarResult, sizeof(*pvarResult));
|
|
|
|
switch(prop)
|
|
{
|
|
case RULE_PROP_NAME:
|
|
// Get the name
|
|
szRes[0] = '\0';
|
|
LoadString(g_hLocRes, idsJunkMail, szRes, ARRAYSIZE(szRes));
|
|
|
|
pszName = PszDupA(szRes);
|
|
pvarResult->vt = VT_LPSTR;
|
|
pvarResult->pszVal = pszName;
|
|
pszName = NULL;
|
|
break;
|
|
|
|
case RULE_PROP_DISABLED:
|
|
pvarResult->vt = VT_BOOL;
|
|
pvarResult->boolVal = !!(m_dwState & RULE_STATE_DISABLED);
|
|
break;
|
|
|
|
case RULE_PROP_CRITERIA:
|
|
pCrit = new CRIT_ITEM;
|
|
if (NULL == pCrit)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
ZeroMemory(pCrit, sizeof(*pCrit));
|
|
|
|
pCrit->type = CRIT_TYPE_JUNK;
|
|
pCrit->logic = CRIT_LOGIC_AND;
|
|
pCrit->dwFlags = CRIT_FLAG_DEFAULT;
|
|
pCrit->propvar.vt = VT_EMPTY;
|
|
|
|
pvarResult->vt = VT_BLOB;
|
|
pvarResult->blob.cbSize = sizeof(CRIT_ITEM);
|
|
pvarResult->blob.pBlobData = (BYTE *) pCrit;
|
|
pCrit = NULL;
|
|
break;
|
|
|
|
case RULE_PROP_ACTIONS:
|
|
pAct = new ACT_ITEM;
|
|
if (NULL == pAct)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
hr = _HrGetDefaultActions(pAct, 1);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
pvarResult->vt = VT_BLOB;
|
|
pvarResult->blob.cbSize = sizeof(ACT_ITEM);
|
|
pvarResult->blob.pBlobData = (BYTE *) pAct;
|
|
pAct = NULL;
|
|
break;
|
|
|
|
case RULE_PROP_JUNKPCT:
|
|
pvarResult->vt = VT_UI4;
|
|
pvarResult->ulVal = m_dwJunkPct;
|
|
break;
|
|
|
|
case RULE_PROP_EXCPT_WAB:
|
|
pvarResult->vt = VT_BOOL;
|
|
pvarResult->boolVal = !!(0 != (m_dwState & RULE_STATE_EXCPT_WAB));
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Set the return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
SafeMemFree(pszName);
|
|
RuleUtil_HrFreeCriteriaItem(pCrit, 1);
|
|
SafeMemFree(pCrit);
|
|
RuleUtil_HrFreeActionsItem(pAct, cItem);
|
|
SafeMemFree(pAct);
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEJunkRule::SetProp(RULE_PROP prop, DWORD dwFlags, PROPVARIANT * pvarResult)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Check incoming params
|
|
if (NULL == pvarResult)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
switch(prop)
|
|
{
|
|
case RULE_PROP_DISABLED:
|
|
if (VT_BOOL != pvarResult->vt)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Set the new value
|
|
if (FALSE != !!(pvarResult->boolVal))
|
|
{
|
|
m_dwState |= RULE_STATE_DISABLED;
|
|
}
|
|
else
|
|
{
|
|
Assert(0 == (m_dwState & RULE_STATE_INVALID));
|
|
m_dwState &= ~RULE_STATE_DISABLED;
|
|
}
|
|
break;
|
|
|
|
case RULE_PROP_JUNKPCT:
|
|
if (VT_UI4 != pvarResult->vt)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Set the new value
|
|
m_dwJunkPct = pvarResult->ulVal;
|
|
break;
|
|
|
|
case RULE_PROP_EXCPT_WAB:
|
|
if (VT_BOOL != pvarResult->vt)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Set the new value
|
|
if (FALSE != !!(pvarResult->boolVal))
|
|
{
|
|
m_dwState |= RULE_STATE_EXCPT_WAB;
|
|
}
|
|
else
|
|
{
|
|
m_dwState &= ~RULE_STATE_EXCPT_WAB;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Mark the rule as dirty
|
|
m_dwState |= RULE_STATE_DIRTY;
|
|
|
|
// Set the return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEJunkRule::Evaluate(LPCSTR pszAcct, MESSAGEINFO * pMsgInfo, IMessageFolder * pFolder,
|
|
IMimePropertySet * pIMPropSet, IMimeMessage * pIMMsg, ULONG cbMsgSize,
|
|
ACT_ITEM ** ppActions, ULONG * pcActions)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DOUBLE dblProb = 0.0;
|
|
ACT_ITEM * pAct = NULL;
|
|
ULONG cAct = 0;
|
|
DWORD dwFlags = 0;
|
|
IMimeMessage * pIMMsgNew = NULL;
|
|
|
|
// Check incoming variables
|
|
if (((NULL == pMsgInfo) && (NULL == pIMPropSet)) || ((NULL == pIMMsg) && ((NULL == pMsgInfo) || (NULL == pFolder))) ||
|
|
(NULL == ppActions) || (NULL == pcActions))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Set outgoing params to default
|
|
*ppActions = NULL;
|
|
*pcActions = 0;
|
|
|
|
// Load up the junk mail filter
|
|
hr = _HrLoadJunkFilter();
|
|
if (FAILED(hr))
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
// Set the spam threshold
|
|
hr = _HrSetSpamThresh();
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if (NULL != pIMMsg)
|
|
{
|
|
// Hold onto the message
|
|
pIMMsgNew = pIMMsg;
|
|
pIMMsgNew->AddRef();
|
|
}
|
|
else
|
|
{
|
|
// Get the message
|
|
hr = pFolder->OpenMessage(pMsgInfo->idMessage, 0, &pIMMsgNew, NOSTORECALLBACK);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Do we need to see if this is in the WAB
|
|
if (0 != (m_dwState & RULE_STATE_EXCPT_WAB))
|
|
{
|
|
if (S_OK == _HrIsSenderInWAB(pIMMsgNew))
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Check to see if it's in the exceptions list
|
|
if (NULL != m_pIAddrList)
|
|
{
|
|
hr = m_pIAddrList->Match(RALF_MAIL, pMsgInfo, pIMMsgNew);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// If we found a match then we are done
|
|
if (S_OK == hr)
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Figure out the proper flags
|
|
hr = _HrGetSpamFlags(pszAcct, pIMMsgNew, &dwFlags);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Is it Spam?
|
|
hr = m_pIJunkFilter->CalcJunkProb(dwFlags, pIMPropSet, pIMMsgNew, &dblProb);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// If we didn't match then just return
|
|
if (S_FALSE == hr)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Create an action
|
|
pAct = new ACT_ITEM;
|
|
if (NULL == pAct)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
cAct = 1;
|
|
|
|
// Grab the actions and return them to the caller
|
|
hr = _HrGetDefaultActions(pAct, cAct);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Set the outgoing parameters
|
|
*ppActions = pAct;
|
|
pAct = NULL;
|
|
*pcActions = cAct;
|
|
|
|
// Set proper return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
RuleUtil_HrFreeActionsItem(pAct, cAct);
|
|
SafeMemFree(pAct);
|
|
SafeRelease(pIMMsgNew);
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEJunkRule::LoadReg(LPCSTR pszRegPath)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG lErr = 0;
|
|
HKEY hkeyRoot = NULL;
|
|
ULONG cbData = 0;
|
|
ULONG cbRead = 0;
|
|
DWORD dwData = 0;
|
|
BOOL fDisabled = FALSE;
|
|
LPSTR pszRegPathNew = NULL;
|
|
ULONG cchRegPath = 0;
|
|
|
|
// Check incoming param
|
|
if (NULL == pszRegPath)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Should we fail if we're already loaded?
|
|
AssertSz(0 == (m_dwState & RULE_STATE_LOADED), "We're already loaded!!!");
|
|
|
|
// Open the reg key from the path
|
|
lErr = AthUserOpenKey(pszRegPath, KEY_ALL_ACCESS, &hkeyRoot);
|
|
if (ERROR_SUCCESS != lErr)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Allocate space to hold the new reg path
|
|
cchRegPath = lstrlen(pszRegPath);
|
|
DWORD cchSize = (cchRegPath + lstrlen(c_szRulesExcpts) + 2);
|
|
if (FAILED(HrAlloc((void **) &pszRegPathNew, cchSize)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Build reg path to criteria
|
|
StrCpyN(pszRegPathNew, pszRegPath, cchSize);
|
|
if ('\\' != pszRegPath[cchRegPath])
|
|
{
|
|
StrCatBuff(pszRegPathNew, g_szBackSlash, cchSize);
|
|
cchRegPath++;
|
|
}
|
|
|
|
StrCatBuff(pszRegPathNew, c_szRulesExcpts, cchSize);
|
|
|
|
// Get the Exceptions List
|
|
hr = m_pIAddrList->LoadList(pszRegPathNew);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Get the enabled state
|
|
if (FALSE != DwGetOption(OPT_FILTERJUNK))
|
|
{
|
|
m_dwState &= ~RULE_STATE_DISABLED;
|
|
}
|
|
else
|
|
{
|
|
m_dwState |= RULE_STATE_DISABLED;
|
|
}
|
|
|
|
// Get the junk percent
|
|
m_dwJunkPct = DwGetOption(OPT_JUNKPCT);
|
|
|
|
// Get the WAB Exception state
|
|
if (FALSE != DwGetOption(OPT_EXCEPTIONS_WAB))
|
|
{
|
|
m_dwState |= RULE_STATE_EXCPT_WAB;
|
|
}
|
|
else
|
|
{
|
|
m_dwState &= ~RULE_STATE_EXCPT_WAB;
|
|
}
|
|
|
|
// Make sure we clear the dirty bit
|
|
m_dwState &= ~RULE_STATE_DIRTY;
|
|
|
|
// Note that we have been loaded
|
|
m_dwState |= RULE_STATE_LOADED;
|
|
|
|
// Set the return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
SafeMemFree(pszRegPathNew);
|
|
if (NULL != hkeyRoot)
|
|
{
|
|
RegCloseKey(hkeyRoot);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEJunkRule::SaveReg(LPCSTR pszRegPath, BOOL fClearDirty)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG lErr = 0;
|
|
HKEY hkeyRoot = NULL;
|
|
DWORD dwDisp = 0;
|
|
DWORD dwData = 0;
|
|
LPSTR pszRegPathNew = NULL;
|
|
ULONG cchRegPath = 0;
|
|
|
|
// Check incoming param
|
|
if (NULL == pszRegPath)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Can't save out a rule if we don't have criteria or actions
|
|
// or a rule name
|
|
if (NULL == m_pIAddrList)
|
|
{
|
|
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);
|
|
|
|
// Set the enabled state
|
|
SetDwOption(OPT_FILTERJUNK, (DWORD) !(0 != (m_dwState & RULE_STATE_DISABLED)), NULL, 0);
|
|
|
|
// Set the junk percent
|
|
SetDwOption(OPT_JUNKPCT, m_dwJunkPct, NULL, 0);
|
|
|
|
// Set the WAB Exception state
|
|
SetDwOption(OPT_EXCEPTIONS_WAB, (DWORD) (0 != (m_dwState & RULE_STATE_EXCPT_WAB)), NULL, 0);
|
|
|
|
// Allocate space to hold the new reg path
|
|
cchRegPath = lstrlen(pszRegPath);
|
|
DWORD cchSize = (cchRegPath + lstrlen(c_szRulesExcpts) + 2);
|
|
if (FAILED(HrAlloc((void **) &pszRegPathNew, cchSize)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Build reg path to criteria
|
|
StrCpyN(pszRegPathNew, pszRegPath, cchSize);
|
|
if ('\\' != pszRegPath[cchRegPath])
|
|
{
|
|
StrCatBuff(pszRegPathNew, g_szBackSlash, cchSize);
|
|
cchRegPath++;
|
|
}
|
|
|
|
StrCatBuff(pszRegPathNew, c_szRulesExcpts, cchSize);
|
|
|
|
// Write out the Exceptions List
|
|
hr = m_pIAddrList->SaveList(pszRegPathNew, fClearDirty);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Should we clear the dirty bit?
|
|
if (FALSE != fClearDirty)
|
|
{
|
|
m_dwState &= ~RULE_STATE_DIRTY;
|
|
}
|
|
|
|
// Set the return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
SafeMemFree(pszRegPathNew);
|
|
if (NULL != hkeyRoot)
|
|
{
|
|
RegCloseKey(hkeyRoot);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEJunkRule::Clone(IOERule ** ppIRule)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
COEJunkRule * pRule = NULL;
|
|
IOERuleAddrList * pIAddrList = NULL;
|
|
RULEADDRLIST * pralList = NULL;
|
|
ULONG cralList = 0;
|
|
|
|
// Check incoming params
|
|
if (NULL == ppIRule)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize the outgoing params
|
|
*ppIRule = NULL;
|
|
|
|
// Create a new rule
|
|
pRule = new COEJunkRule;
|
|
if (NULL == pRule)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
// Note that we have a reference
|
|
pRule->AddRef();
|
|
|
|
// Initialize the junk rule
|
|
hr = pRule->HrInit(c_szJunkDll, c_szJunkFile);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Set the WAB Exception state
|
|
if (0 != (m_dwState & RULE_STATE_DISABLED))
|
|
{
|
|
pRule->m_dwState |= RULE_STATE_DISABLED;
|
|
}
|
|
else
|
|
{
|
|
pRule->m_dwState &= ~RULE_STATE_DISABLED;
|
|
}
|
|
|
|
// Set the junk percent
|
|
pRule->m_dwJunkPct = m_dwJunkPct;
|
|
|
|
// Set the WAB Exception state
|
|
if (0 != (m_dwState & RULE_STATE_EXCPT_WAB))
|
|
{
|
|
pRule->m_dwState |= RULE_STATE_EXCPT_WAB;
|
|
}
|
|
else
|
|
{
|
|
pRule->m_dwState &= ~RULE_STATE_EXCPT_WAB;
|
|
}
|
|
|
|
// Do we have an Exceptions List?
|
|
if (NULL != m_pIAddrList)
|
|
{
|
|
// Get the interface from the new object
|
|
hr = pRule->QueryInterface(IID_IOERuleAddrList, (void **) &pIAddrList);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Get the list of exceptions
|
|
hr = m_pIAddrList->GetList(0, &pralList, &cralList);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Set the list of exceptions
|
|
hr = pIAddrList->SetList(0, pralList, cralList);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Get the rule interface
|
|
hr = pRule->QueryInterface(IID_IOERule, (void **) ppIRule);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Set the proper return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
FreeRuleAddrList(pralList, cralList);
|
|
SafeMemFree(pralList);
|
|
SafeRelease(pIAddrList);
|
|
SafeRelease(pRule);
|
|
return hr;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HrInit
|
|
//
|
|
// This initializes the junk rule.
|
|
//
|
|
// ppIRule - pointer to return the junk rule
|
|
//
|
|
// Returns: S_OK, on success
|
|
// E_OUTOFMEMORY, if can't create the JunkRule object
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT COEJunkRule::HrInit(LPCSTR pszJunkDll, LPCSTR pszDataFile)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IUnknown * pIUnkOuter = NULL;
|
|
IUnknown * pIUnkInner = NULL;
|
|
IOERuleAddrList * pIAddrList = NULL;
|
|
|
|
// Check the incoming params
|
|
if ((NULL == pszJunkDll) || (NULL == pszDataFile))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// If we've already been initialized
|
|
if (0 != (m_dwState & RULE_STATE_INIT))
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto exit;
|
|
}
|
|
|
|
Assert(NULL == m_hinst);
|
|
|
|
// Safe off the paths
|
|
m_pszJunkDll = PszDupA(pszJunkDll);
|
|
if (NULL == m_pszJunkDll)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
m_pszDataFile = PszDupA(pszDataFile);
|
|
if (NULL == m_pszDataFile)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
// Create an address list object
|
|
pIUnkOuter = static_cast<IUnknown *> (this);
|
|
hr = HrCreateAddrList(pIUnkOuter, IID_IUnknown, (void **) &pIUnkInner);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Get the Rule Address list interface
|
|
hr = pIUnkInner->QueryInterface(IID_IOERuleAddrList, (VOID **) &pIAddrList);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Save off the address list
|
|
m_pIAddrList = pIAddrList;
|
|
|
|
// Save off the inner IUnknown
|
|
m_pIUnkInner = pIUnkInner;
|
|
pIUnkInner = NULL;
|
|
|
|
// Note that wab exceptions is on by default
|
|
m_dwState |= RULE_STATE_EXCPT_WAB;
|
|
|
|
// Note that we have been initialized
|
|
m_dwState |= RULE_STATE_INIT;
|
|
|
|
// Set the proper return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
if (NULL != pIAddrList)
|
|
{
|
|
SafeRelease(pIUnkOuter);
|
|
}
|
|
SafeRelease(pIUnkInner);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT COEJunkRule::_HrGetDefaultActions(ACT_ITEM * pAct, ULONG cAct)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
FOLDERINFO fldinfo = {0};
|
|
RULEFOLDERDATA * prfdData = NULL;
|
|
STOREUSERDATA UserData = {0};
|
|
|
|
// Check incoming vars
|
|
if ((NULL == pAct) || (0 == cAct))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize the outgoing params
|
|
ZeroMemory(pAct, cAct * sizeof(*pAct));
|
|
|
|
// Fill up the action
|
|
pAct->type = ACT_TYPE_JUNKMAIL;
|
|
pAct->dwFlags = ACT_FLAG_DEFAULT;
|
|
pAct->propvar.vt = VT_EMPTY;
|
|
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT COEJunkRule::_HrSetSpamThresh(VOID)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG ulThresh = 0;
|
|
|
|
// If we haven't been loaded
|
|
if (0 == (m_dwState & RULE_STATE_DATA_LOADED))
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto exit;
|
|
}
|
|
|
|
// Get the threshold
|
|
switch (m_dwJunkPct)
|
|
{
|
|
case 0:
|
|
ulThresh = STF_USE_MOST;
|
|
break;
|
|
|
|
case 1:
|
|
ulThresh = STF_USE_MORE;
|
|
break;
|
|
|
|
case 2:
|
|
ulThresh = STF_USE_DEFAULT;
|
|
break;
|
|
|
|
case 3:
|
|
ulThresh = STF_USE_LESS;
|
|
break;
|
|
|
|
case 4:
|
|
ulThresh = STF_USE_LEAST;
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Set the threshold
|
|
hr = m_pIJunkFilter->SetSpamThresh(ulThresh);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT COEJunkRule::_HrGetSpamFlags(LPCSTR pszAcct, IMimeMessage * pIMMsg, DWORD * pdwFlags)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IImnAccount * pAccount = NULL;
|
|
CHAR szEmailAddress[CCHMAX_EMAIL_ADDRESS];
|
|
CHAR szReplyToAddress[CCHMAX_EMAIL_ADDRESS];
|
|
ADDRESSLIST rAddrList ={0};
|
|
ULONG ulIndex = 0;
|
|
BOOL fFound = FALSE;
|
|
|
|
Assert(NULL != g_pAcctMan);
|
|
|
|
// Initialize the flags
|
|
*pdwFlags = 0;
|
|
|
|
// Get the account
|
|
hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAcct, &pAccount);
|
|
|
|
// If we couldn't find the account, then just use the default
|
|
if (FAILED(hr))
|
|
{
|
|
hr = g_pAcctMan->GetDefaultAccount(ACCT_MAIL, &pAccount);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Get the default address on the account
|
|
if (FAILED(pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szEmailAddress, sizeof(szEmailAddress))))
|
|
{
|
|
szEmailAddress[0] = '\0';
|
|
}
|
|
|
|
// Get the reply to address on the account
|
|
if (FAILED(pAccount->GetPropSz(AP_SMTP_REPLY_EMAIL_ADDRESS, szReplyToAddress, sizeof(szReplyToAddress))))
|
|
{
|
|
szReplyToAddress[0] = '\0';
|
|
}
|
|
|
|
// Get the addresses
|
|
hr = pIMMsg->GetAddressTypes(IAT_TO | IAT_CC | IAT_BCC, IAP_EMAIL, &rAddrList);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Search through the address list
|
|
for (ulIndex = 0; ulIndex < rAddrList.cAdrs; ulIndex++)
|
|
{
|
|
// Skip blank addresses
|
|
if (NULL == rAddrList.prgAdr[ulIndex].pszEmail)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Search for the email address
|
|
if ('\0' != szEmailAddress[0])
|
|
{
|
|
fFound = !!(0 == lstrcmpi(rAddrList.prgAdr[ulIndex].pszEmail, szEmailAddress));
|
|
}
|
|
|
|
// Search for the reply to address
|
|
if ((FALSE == fFound) && ('\0' != szReplyToAddress[0]))
|
|
{
|
|
fFound = !!(0 == lstrcmpi(rAddrList.prgAdr[ulIndex].pszEmail, szReplyToAddress));
|
|
}
|
|
|
|
if (FALSE != fFound)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If we found something
|
|
if (FALSE != fFound)
|
|
{
|
|
*pdwFlags |= CJPF_SENT_TO_ME;
|
|
}
|
|
|
|
// Set the return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
g_pMoleAlloc->FreeAddressList(&rAddrList);
|
|
SafeRelease(pAccount);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT COEJunkRule::_HrIsSenderInWAB(IMimeMessage * pIMMsg)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IMimeAddressTable * pIAddrTable = NULL;
|
|
ADDRESSPROPS rSender = {0};
|
|
LPWAB pWAB = NULL;
|
|
LPADRBOOK pAddrBook = NULL;
|
|
LPWABOBJECT pWabObject = NULL;
|
|
ULONG cbeidWAB = 0;
|
|
LPENTRYID peidWAB = NULL;
|
|
ULONG ulDummy = 0;
|
|
LPABCONT pabcWAB = NULL;
|
|
ADRLIST * pAddrList = NULL;
|
|
FlagList rFlagList = {0};
|
|
|
|
Assert(NULL != pIMMsg);
|
|
|
|
// Get the address table from the message
|
|
hr = pIMMsg->GetAddressTable(&pIAddrTable);
|
|
if (FAILED(hr))
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
// Get the sender of the message
|
|
rSender.dwProps = IAP_EMAIL;
|
|
hr = pIAddrTable->GetSender(&rSender);
|
|
if (FAILED(hr))
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
// If the sender is empty,
|
|
// then we are done...
|
|
if ((NULL == rSender.pszEmail) || ('\0' == rSender.pszEmail[0]))
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
// Get the WAB
|
|
hr = HrCreateWabObject(&pWAB);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Get the AB object
|
|
hr = pWAB->HrGetAdrBook(&pAddrBook);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
hr = pWAB->HrGetWabObject(&pWabObject);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Get the PAB
|
|
hr = pAddrBook->GetPAB(&cbeidWAB, &peidWAB);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Get the address container
|
|
hr = pAddrBook->OpenEntry(cbeidWAB, peidWAB, NULL, 0, &ulDummy, (IUnknown **) (&pabcWAB));
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Allocate space to hold the address list
|
|
hr = pWabObject->AllocateBuffer(sizeof(ADRLIST), (VOID **)&(pAddrList));
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize the Address list
|
|
Assert(NULL != pAddrList);
|
|
pAddrList->cEntries = 1;
|
|
pAddrList->aEntries[0].ulReserved1 = 0;
|
|
pAddrList->aEntries[0].cValues = 1;
|
|
|
|
// Allocate space to hold the address props
|
|
hr = pWabObject->AllocateBuffer(sizeof(SPropValue), (VOID **)&(pAddrList->aEntries[0].rgPropVals));
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize the address props
|
|
pAddrList->aEntries[0].rgPropVals[0].ulPropTag = PR_EMAIL_ADDRESS;
|
|
pAddrList->aEntries[0].rgPropVals[0].Value.LPSZ = rSender.pszEmail;
|
|
|
|
// Resolve the sender address
|
|
rFlagList.cFlags = 1;
|
|
hr = pabcWAB->ResolveNames(NULL, WAB_RESOLVE_ALL_EMAILS, pAddrList, &rFlagList);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Check to see if it was found
|
|
if ((MAPI_RESOLVED == rFlagList.ulFlag[0]) || (MAPI_AMBIGUOUS == rFlagList.ulFlag[0]))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
exit:
|
|
if (pAddrList)
|
|
{
|
|
for (ULONG ul = 0; ul < pAddrList->cEntries; ul++)
|
|
pWabObject->FreeBuffer(pAddrList->aEntries[ul].rgPropVals);
|
|
pWabObject->FreeBuffer(pAddrList);
|
|
}
|
|
SafeRelease(pabcWAB);
|
|
if (NULL != peidWAB)
|
|
{
|
|
pWabObject->FreeBuffer(peidWAB);
|
|
}
|
|
SafeRelease(pWAB);
|
|
g_pMoleAlloc->FreeAddressProps(&rSender);
|
|
SafeRelease(pIAddrTable);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT COEJunkRule::_HrLoadJunkFilter(VOID)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG cbData = 0;
|
|
LPSTR pszPath = NULL;
|
|
ULONG cchPath = 0;
|
|
TYP_HrCreateJunkFilter pfnHrCreateJunkFilter = NULL;
|
|
IOEJunkFilter * pIJunk = NULL;
|
|
LPSTR pszFirst = NULL;
|
|
LPSTR pszLast = NULL;
|
|
LPSTR pszCompany = NULL;
|
|
|
|
// If we haven't been initialized yet
|
|
if (0 == (m_dwState & RULE_STATE_INIT))
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto exit;
|
|
}
|
|
|
|
// If we've already been loaded, we're done
|
|
if (0 != (m_dwState & RULE_STATE_DATA_LOADED))
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
Assert(NULL != m_pszJunkDll);
|
|
Assert(NULL != m_pszDataFile);
|
|
|
|
// Get the size of the path to Outlook Express
|
|
if (ERROR_SUCCESS != SHGetValue(HKEY_LOCAL_MACHINE, STR_REG_PATH_FLAT, "InstallRoot", NULL, NULL, &cbData))
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// How much room do we need to build up the path
|
|
cbData += max(lstrlen(m_pszJunkDll), lstrlen(m_pszDataFile)) + 2;
|
|
|
|
// Allocate space to hold the path
|
|
hr = HrAlloc((VOID **) &pszPath, cbData);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Get the path to Outlook Express
|
|
if (ERROR_SUCCESS != SHGetValue(HKEY_LOCAL_MACHINE, STR_REG_PATH_FLAT, "InstallRoot", NULL, (BYTE *) pszPath, &cbData))
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Build up the path to the Junk DLL
|
|
StrCatBuff(pszPath, g_szBackSlash, cbData);
|
|
cchPath = lstrlen(pszPath);
|
|
StrCpyN(&(pszPath[cchPath]), m_pszJunkDll, (cbData-cchPath));
|
|
|
|
// Load the Dll
|
|
Assert(NULL == m_hinst);
|
|
m_hinst = LoadLibrary(pszPath);
|
|
if (NULL == m_hinst)
|
|
{
|
|
AssertSz(FALSE, "Can't find the Dll");
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Find the entry points
|
|
pfnHrCreateJunkFilter = (TYP_HrCreateJunkFilter) GetProcAddress(m_hinst, c_szHrCreateJunkFilter);
|
|
if (NULL == pfnHrCreateJunkFilter)
|
|
{
|
|
AssertSz(FALSE, "Can't find the function HrCreateJunkFilter");
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Get the junk filter
|
|
hr = pfnHrCreateJunkFilter(0, &pIJunk);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Build up the path to the Junk DLL data file
|
|
StrCpyN(&(pszPath[cchPath]), m_pszDataFile, (cbData-cchPath));
|
|
|
|
// Load the test file
|
|
hr = pIJunk->LoadDataFile(pszPath);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Get user specifics
|
|
RuleUtil_HrGetUserData(0, &pszFirst, &pszLast, &pszCompany);
|
|
|
|
// Set the user specifics
|
|
hr = pIJunk->SetIdentity(pszFirst, pszLast, pszCompany);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Save of the data
|
|
m_pIJunkFilter = pIJunk;
|
|
pIJunk = NULL;
|
|
|
|
// Note that we've loaded the data
|
|
m_dwState |= RULE_STATE_DATA_LOADED;
|
|
|
|
// Set the return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
SafeMemFree(pszCompany);
|
|
SafeMemFree(pszLast);
|
|
SafeMemFree(pszFirst);
|
|
SafeRelease(pIJunk);
|
|
SafeMemFree(pszPath);
|
|
return hr;
|
|
}
|
|
|