2020-09-30 16:53:55 +02:00

773 lines
19 KiB
C++

///////////////////////////////////////////////////////////////////////////////
//
// AddrRule.cpp
//
///////////////////////////////////////////////////////////////////////////////
#include <pch.hxx>
#include "addrrule.h"
#include "strconst.h"
#include "goptions.h"
#include "criteria.h"
#include "actions.h"
#include "ruleutil.h"
///////////////////////////////////////////////////////////////////////////////
//
// HrCreateAddrList
//
// This creates an address list.
//
// ppIRule - pointer to return the address list
//
// Returns: S_OK, on success
// E_OUTOFMEMORY, if can't create the Address List object
//
///////////////////////////////////////////////////////////////////////////////
HRESULT HrCreateAddrList(IUnknown * pIUnkOuter, const IID & riid, void ** ppvObject)
{
COERuleAddrList * pral = NULL;
HRESULT hr = S_OK;
// Check the incoming params
if ((NULL == ppvObject) || ((NULL != pIUnkOuter) && (IID_IUnknown != riid)))
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize outgoing params
*ppvObject = NULL;
// Create the rules address list object
pral = new COERuleAddrList;
if (NULL == pral)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Initialize the rule address list
hr = pral->HrInit(0, pIUnkOuter);
if (FAILED(hr))
{
goto exit;
}
// Get the rules address list interface
hr = pral->NondlgQueryInterface(riid, (void **) ppvObject);
if (FAILED(hr))
{
goto exit;
}
pral = NULL;
// Set the proper return value
hr = S_OK;
exit:
if (NULL != pral)
{
delete pral;
}
return hr;
}
VOID FreeRuleAddrList(RULEADDRLIST * pralList, ULONG cralList)
{
ULONG ulIndex = 0;
// Check incoming param
if (NULL == pralList)
{
goto exit;
}
for (ulIndex = 0; ulIndex < cralList; ulIndex++, pralList++)
{
SafeMemFree(pralList->pszAddr);
pralList->dwFlags = 0;
}
exit:
return;
}
HRESULT _HrLoadExcptFromReg(HKEY hkeyRoot, LPSTR pszKeyname, RULEADDRLIST * pralItem)
{
HRESULT hr = S_OK;
LONG lErr = ERROR_SUCCESS;
HKEY hkeyItem = NULL;
DWORD dwFlags = 0;
ULONG cbData = 0;
LPSTR pszExcpt = NULL;
Assert(NULL != hkeyRoot);
Assert(NULL != pszKeyname);
Assert(NULL != pralItem);
// Open up the entry
lErr = RegOpenKeyEx(hkeyRoot, pszKeyname, 0, KEY_READ, &hkeyItem);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Get the flags
cbData = sizeof(dwFlags);
lErr = RegQueryValueEx(hkeyItem, c_szExcptFlags, NULL, NULL, (BYTE *) &dwFlags, &cbData);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Get the size of the exception
lErr = RegQueryValueEx(hkeyItem, c_szException, NULL, NULL, NULL, &cbData);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Allocate space to hold the exception
hr = HrAlloc((VOID **) &pszExcpt, cbData * sizeof(*pszExcpt));
if (FAILED(hr))
{
goto exit;
}
// Get the exception
lErr = RegQueryValueEx(hkeyItem, c_szException, NULL, NULL, (BYTE *) pszExcpt, &cbData);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Verify the values
if (('\0' == pszExcpt[0]) || ((0 == (dwFlags & RALF_MAIL)) && (0 == (dwFlags & RALF_NEWS))))
{
hr = E_INVALIDARG;
goto exit;
}
// Set the values into the item
pralItem->dwFlags = dwFlags;
pralItem->pszAddr = pszExcpt;
pszExcpt = NULL;
// Set the proper return value
hr = S_OK;
exit:
SafeMemFree(pszExcpt);
if (NULL != hkeyItem)
{
RegCloseKey(hkeyItem);
}
return hr;
}
HRESULT _HrSaveExcptIntoReg(HKEY hkeyRoot, LPSTR pszKeyname, RULEADDRLIST * pralItem)
{
HRESULT hr = S_OK;
LONG lErr = ERROR_SUCCESS;
HKEY hkeyItem = NULL;
DWORD dwDisp = 0;
ULONG cbData = 0;
Assert(NULL != hkeyRoot);
Assert(NULL != pszKeyname);
Assert(NULL != pralItem);
// Verify the values
if (('\0' == pralItem->pszAddr[0]) ||
((0 == (pralItem->dwFlags & RALF_MAIL)) &&
(0 == (pralItem->dwFlags & RALF_NEWS))))
{
hr = E_INVALIDARG;
goto exit;
}
// Create the entry
lErr = RegCreateKeyEx(hkeyRoot, pszKeyname, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyItem, &dwDisp);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Set the flags
cbData = sizeof(pralItem->dwFlags);
lErr = RegSetValueEx(hkeyItem, c_szExcptFlags, NULL,
REG_DWORD, (CONST BYTE *) &(pralItem->dwFlags), cbData);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Set the exception
cbData = lstrlen(pralItem->pszAddr) + 1;
lErr = RegSetValueEx(hkeyItem, c_szException, NULL,
REG_SZ, (CONST BYTE *) (pralItem->pszAddr), cbData);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Set the proper return value
hr = S_OK;
exit:
if (NULL != hkeyItem)
{
RegCloseKey(hkeyItem);
}
return hr;
}
COERuleAddrList::~COERuleAddrList()
{
AssertSz(m_cRef == 0, "Somebody still has a hold of us!!");
FreeRuleAddrList(m_pralList, m_cralList);
SafeMemFree(m_pralList);
m_cralList = 0;
}
STDMETHODIMP_(ULONG) COERuleAddrList::NondlgAddRef()
{
return ::InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) COERuleAddrList::NondlgRelease()
{
LONG cRef = 0;
cRef = ::InterlockedDecrement(&m_cRef);
if (0 == cRef)
{
delete this;
return cRef;
}
return cRef;
}
STDMETHODIMP COERuleAddrList::NondlgQueryInterface(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)
{
*ppvObject = static_cast<IOENondlgUnk *>(this);
}
else if (riid == IID_IOERuleAddrList)
{
*ppvObject = static_cast<IOERuleAddrList *>(this);
}
else
{
hr = E_NOINTERFACE;
goto exit;
}
reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();
hr = S_OK;
exit:
return hr;
}
STDMETHODIMP COERuleAddrList::GetList(DWORD dwFlags, RULEADDRLIST ** ppralList, ULONG * pcralList)
{
HRESULT hr = S_OK;
RULEADDRLIST * pralListNew = NULL;
ULONG ulIndex = 0;
RULEADDRLIST * pralListWalk = NULL;
// Check the incoming params
if ((NULL == ppralList) || (NULL == pcralList))
{
hr = E_INVALIDARG;
goto exit;
}
// Do we have anything to copy
if (0 != m_cralList)
{
// Create space to hold all the new items
hr = HrAlloc((VOID **) &pralListNew, m_cralList * (sizeof(*pralListNew)));
if (FAILED(hr))
{
goto exit;
}
// Initialize the memory
ZeroMemory(pralListNew, m_cralList * (sizeof(*pralListNew)));
// Copy over each new address
for (ulIndex = 0, pralListWalk = m_pralList; ulIndex < m_cralList; ulIndex++, pralListWalk++)
{
// Copy over the flags
pralListNew[ulIndex].dwFlags = pralListWalk->dwFlags;
// Copy over the address
pralListNew[ulIndex].pszAddr = PszDupA(pralListWalk->pszAddr);
if (NULL == pralListNew[ulIndex].pszAddr)
{
hr = E_OUTOFMEMORY;
goto exit;
}
}
}
// Save off the new items
*ppralList = pralListNew;
pralListNew = NULL;
*pcralList = m_cralList;
// Set the return value
hr = S_OK;
exit:
FreeRuleAddrList(pralListNew, m_cralList);
SafeMemFree(pralListNew);
return hr;
}
STDMETHODIMP COERuleAddrList::SetList(DWORD dwFlags, RULEADDRLIST * pralList, ULONG cralList)
{
HRESULT hr = S_OK;
RULEADDRLIST * pralListNew = NULL;
ULONG ulIndex = 0;
// Check the incoming params
if ((NULL == pralList) && (0 != cralList))
{
hr = E_INVALIDARG;
goto exit;
}
// Do we have anything to copy
if (0 != cralList)
{
// Create space to hold all the new items
hr = HrAlloc((VOID **) &pralListNew, cralList * (sizeof(*pralListNew)));
if (FAILED(hr))
{
goto exit;
}
// Initialize the memory
ZeroMemory(pralListNew, cralList * (sizeof(*pralListNew)));
// Copy over each new address
for (ulIndex = 0; ulIndex < cralList; ulIndex++, pralList++)
{
// Copy over the flags
pralListNew[ulIndex].dwFlags = pralList->dwFlags;
// Copy over the address
pralListNew[ulIndex].pszAddr = PszDupA(pralList->pszAddr);
if (NULL == pralListNew[ulIndex].pszAddr)
{
hr = E_OUTOFMEMORY;
goto exit;
}
}
}
// Free up the old items
FreeRuleAddrList(m_pralList, m_cralList);
SafeMemFree(m_pralList);
// Save off the new items
m_pralList = pralListNew;
pralListNew = NULL;
m_cralList = cralList;
// Mark the list as dirty
m_dwState |= STATE_DIRTY;
// Set the return value
hr = S_OK;
exit:
FreeRuleAddrList(pralListNew, cralList);
SafeMemFree(pralListNew);
return hr;
}
STDMETHODIMP COERuleAddrList::Match(DWORD dwFlags, MESSAGEINFO * pMsgInfo, IMimeMessage * pIMMsg)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
// Check incoming params
if ((NULL == pMsgInfo) && (NULL == pIMMsg))
{
hr = E_INVALIDARG;
goto exit;
}
// If we haven't been initialized yet
if (0 == (m_dwState & STATE_INIT))
{
hr = E_UNEXPECTED;
goto exit;
}
// Search through each address for a match
for (ulIndex = 0; ulIndex < m_cralList; ulIndex++)
{
// Is this the same type?
if (0 != (dwFlags & m_pralList[ulIndex].dwFlags))
{
// If it exists in the Message info
if (S_OK == RuleUtil_HrMatchSender(m_pralList[ulIndex].pszAddr, pMsgInfo, pIMMsg, NULL))
{
break;
}
}
}
// Set the proper return value
hr = (ulIndex < m_cralList) ? S_OK : S_FALSE;
exit:
return hr;
}
STDMETHODIMP COERuleAddrList::LoadList(LPCSTR pszRegPath)
{
HRESULT hr = S_OK;
LONG lErr = ERROR_SUCCESS;
HKEY hkeyRoot = NULL;
DWORD dwDisp = 0;
DWORD dwVer = 0;
ULONG cbData = 0;
ULONG cExcpts = 0;
RULEADDRLIST * pralList = NULL;
CHAR rgchKeyname[CCH_EXCPT_KEYNAME_MAX];
ULONG ulIndex = 0;
// Check incoming params
if (NULL == pszRegPath)
{
hr = E_INVALIDARG;
goto exit;
}
// Should we fail if we're already loaded?
AssertSz(0 == (m_dwState & STATE_LOADED), "We're already loaded!!!");
// Open the registry location
lErr = AthUserCreateKey(pszRegPath, KEY_ALL_ACCESS, &hkeyRoot, &dwDisp);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Check the version
cbData = sizeof(dwVer);
lErr = RegQueryValueEx(hkeyRoot, c_szExcptVersion, NULL, NULL, (BYTE *) &dwVer, &cbData);
if ((ERROR_SUCCESS != lErr) && (ERROR_FILE_NOT_FOUND != lErr))
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Set the version if it didn't exist
if (ERROR_FILE_NOT_FOUND == lErr)
{
dwVer = RULEADDRLIST_VERSION;
lErr = RegSetValueEx(hkeyRoot, c_szExcptVersion, 0, REG_DWORD, (CONST BYTE *) &dwVer, sizeof(dwVer));
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
}
Assert(RULEADDRLIST_VERSION == dwVer);
// Get the total number of entries
cbData = sizeof(cExcpts);
lErr = RegQueryInfoKey(hkeyRoot, NULL, NULL, NULL, &cExcpts, NULL,
NULL, NULL, NULL, NULL, NULL, NULL);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Is there something to do...
if (0 != cExcpts)
{
// Allocate space to hold the entries
hr = HrAlloc((VOID **) &pralList, cExcpts * sizeof(*pralList));
if (FAILED(hr))
{
goto exit;
}
// Initialize the Exception List
ZeroMemory(pralList, cExcpts * sizeof(*pralList));
// For each entry
for (ulIndex = 0; ulIndex < cExcpts; ulIndex++)
{
// Get the key for the entry
cbData = sizeof(rgchKeyname);
lErr = RegEnumKeyEx(hkeyRoot, ulIndex, rgchKeyname, &cbData, NULL, NULL, NULL, NULL);
if ((ERROR_SUCCESS != lErr) && (ERROR_NO_MORE_ITEMS != lErr))
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// If we've ran out of entries, we're done
if (ERROR_NO_MORE_ITEMS == lErr)
{
break;
}
// Load the item
hr = _HrLoadExcptFromReg(hkeyRoot, rgchKeyname, &(pralList[ulIndex]));
if (FAILED(hr))
{
goto exit;
}
}
}
// Free up any old items
FreeRuleAddrList(m_pralList, m_cralList);
SafeMemFree(m_pralList);
m_cralList = 0;
// Save off the list
m_pralList = pralList;
pralList = NULL;
m_cralList = cExcpts;
// Make sure we clear the dirty bit
m_dwState &= ~STATE_DIRTY;
// Note that we have been loaded
m_dwState |= STATE_LOADED;
// Set the proper return value
hr = S_OK;
exit:
FreeRuleAddrList(pralList, cExcpts);
SafeMemFree(pralList);
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return hr;
}
STDMETHODIMP COERuleAddrList::SaveList(LPCSTR pszRegPath, BOOL fClearDirty)
{
HRESULT hr = S_OK;
LONG lErr = ERROR_SUCCESS;
HKEY hkeyRoot = NULL;
DWORD dwDisp = 0;
DWORD dwVer = 0;
ULONG ulIndex = 0;
ULONG cExcpts = 0;
ULONG cbData = 0;
CHAR rgchKeyname[CCH_EXCPT_KEYNAME_MAX];
// Check incoming params
if (NULL == pszRegPath)
{
hr = E_INVALIDARG;
goto exit;
}
// Create the registry location
lErr = AthUserCreateKey(pszRegPath, KEY_ALL_ACCESS, &hkeyRoot, &dwDisp);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Set the version
dwVer = RULEADDRLIST_VERSION;
lErr = RegSetValueEx(hkeyRoot, c_szExcptVersion, 0, REG_DWORD, (CONST BYTE *) &dwVer, sizeof(dwVer));
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Get the total number of sub keys
cbData = sizeof(cExcpts);
lErr = RegQueryInfoKey(hkeyRoot, NULL, NULL, NULL, &cExcpts, NULL,
NULL, NULL, NULL, NULL, NULL, NULL);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Delete any old entries
for (ulIndex = 0; ulIndex < cExcpts; ulIndex++)
{
// Get the name of the next sub key
cbData = sizeof(rgchKeyname);
lErr = RegEnumKeyEx(hkeyRoot, ulIndex, rgchKeyname, &cbData, NULL, NULL, NULL, NULL);
if (ERROR_NO_MORE_ITEMS == lErr)
{
break;
}
// If the key exists
if (ERROR_SUCCESS == lErr)
{
// Delete the sub key
SHDeleteKey(hkeyRoot, rgchKeyname);
}
}
// For each entry
for (ulIndex = 0; ulIndex < m_cralList; ulIndex++)
{
// Get the key for the entry
wnsprintf(rgchKeyname, ARRAYSIZE(rgchKeyname), "%08X", ulIndex);
// Load the item
hr = _HrSaveExcptIntoReg(hkeyRoot, rgchKeyname, &(m_pralList[ulIndex]));
if (FAILED(hr))
{
goto exit;
}
}
// Should we clear out the dirty bit?
if (FALSE != fClearDirty)
{
m_dwState &= ~STATE_DIRTY;
}
// Set the proper return value
hr = S_OK;
exit:
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return hr;
}
STDMETHODIMP COERuleAddrList::Clone(IOERuleAddrList ** ppIAddrList)
{
HRESULT hr = S_OK;
COERuleAddrList * pAddrList = NULL;
// Check incoming params
if (NULL == ppIAddrList)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the outgoing params
*ppIAddrList = NULL;
// Create a new Address list
pAddrList = new COERuleAddrList;
if (NULL == pAddrList)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Initialize the rule address list
hr = pAddrList->HrInit(m_dwFlags, m_pIUnkOuter);
if (FAILED(hr))
{
goto exit;
}
// Copy over the list of addresses
hr = pAddrList->SetList(0, m_pralList, m_cralList);
if (FAILED(hr))
{
goto exit;
}
// Get the Address list interface
hr = pAddrList->QueryInterface(IID_IOERuleAddrList, (void **) ppIAddrList);
if (FAILED(hr))
{
goto exit;
}
pAddrList = NULL;
// Set the proper return value
hr = S_OK;
exit:
if (NULL != pAddrList)
{
delete pAddrList;
}
return hr;
}
HRESULT COERuleAddrList::HrInit(DWORD dwFlags, IUnknown * pIUnkOuter)
{
HRESULT hr = S_OK;
// Save off the flags
m_dwFlags = dwFlags;
// Deal with the IUnknown
if (NULL == pIUnkOuter)
{
m_pIUnkOuter = reinterpret_cast<IUnknown *>
(static_cast<IOENondlgUnk *> (this));
}
else
{
m_pIUnkOuter = pIUnkOuter;
}
// Mark it as initialized
m_dwState |= STATE_INIT;
// Set the proper return value
hr = S_OK;
return hr;
}