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.
1306 lines
35 KiB
1306 lines
35 KiB
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Actions.cpp
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <pch.hxx>
|
|
#include "actions.h"
|
|
#include "storutil.h"
|
|
#include "ruleutil.h"
|
|
|
|
static const int ACT_GROW = 16;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HrCreateActions
|
|
//
|
|
// This creates an actions container.
|
|
//
|
|
// ppIActions - pointer to return the criteria container
|
|
//
|
|
// Returns: S_OK, on success
|
|
// E_OUTOFMEMORY, if can't create the IOEActions object
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT HrCreateActions(IOEActions ** ppIActions)
|
|
{
|
|
COEActions * pActions = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
// Check the incoming params
|
|
if (NULL == ppIActions)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize outgoing params
|
|
*ppIActions = NULL;
|
|
|
|
// Create the rules manager object
|
|
pActions = new COEActions;
|
|
if (NULL == pActions)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
// Get the rules manager interface
|
|
hr = pActions->QueryInterface(IID_IOEActions, (void **) ppIActions);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
pActions = NULL;
|
|
|
|
// Set the proper return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
if (NULL != pActions)
|
|
{
|
|
delete pActions;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
COEActions::~COEActions()
|
|
{
|
|
AssertSz(m_cRef == 0, "Somebody still has a hold of us!!");
|
|
Reset();
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) COEActions::AddRef()
|
|
{
|
|
return ::InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) COEActions::Release()
|
|
{
|
|
LONG cRef = 0;
|
|
|
|
cRef = ::InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef)
|
|
{
|
|
delete this;
|
|
return cRef;
|
|
}
|
|
|
|
return cRef;
|
|
}
|
|
|
|
STDMETHODIMP COEActions::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_IOEActions))
|
|
{
|
|
*ppvObject = static_cast<IOEActions *>(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 COEActions::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_HrFreeActionsItem(m_rgItems, m_cItems);
|
|
SafeMemFree(m_rgItems);
|
|
m_cItems = 0;
|
|
m_cItemsAlloc = 0;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEActions::GetState(DWORD * pdwState)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwState = ACT_STATE_NULL;
|
|
ULONG ulIndex = 0;
|
|
|
|
// Check incoming params
|
|
if (NULL == pdwState)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Init the outgoing param
|
|
*pdwState = ACT_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 ((ACT_STATE_NULL == dwState) &&
|
|
((ACT_TYPE_DELETESERVER == m_rgItems[ulIndex].type) ||
|
|
(ACT_TYPE_DONTDOWNLOAD == m_rgItems[ulIndex].type)))
|
|
{
|
|
dwState = ACT_STATE_SERVER;
|
|
}
|
|
else
|
|
{
|
|
dwState = ACT_STATE_LOCAL;
|
|
}
|
|
}
|
|
|
|
// Set the outgoing param
|
|
*pdwState = dwState;
|
|
|
|
// Set the proper return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEActions::GetActions(DWORD dwFlags, PACT_ITEM * ppItem, ULONG * pcItem)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ACT_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_HrDupActionsItem(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_HrFreeActionsItem(pItemNew, m_cItems);
|
|
SafeMemFree(pItemNew);
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEActions::SetActions(DWORD dwFlags, ACT_ITEM * pItem, ULONG cItem)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ACT_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_HrDupActionsItem(pItem, cItem, &pItemNew);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Save the criteria
|
|
m_rgItems = pItemNew;
|
|
pItemNew = NULL;
|
|
m_cItems = cItem;
|
|
m_cItemsAlloc = cItem;
|
|
|
|
exit:
|
|
RuleUtil_HrFreeActionsItem(pItemNew, cItem);
|
|
SafeMemFree(pItemNew);
|
|
return hr;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ValidateActions
|
|
//
|
|
// This verifies each of the action values
|
|
//
|
|
// Returns: S_OK, if the actions were valid
|
|
// S_FALSE, otherwise
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP COEActions::Validate(DWORD dwFlags)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG ulIndex = 0;
|
|
LPSTR pszText = NULL;
|
|
FOLDERINFO Folder={0};
|
|
RULEFOLDERDATA * prfdData = NULL;
|
|
|
|
// If we don't have any actions, then we must be valid
|
|
if (0 == m_cItems)
|
|
{
|
|
hr = S_OK;
|
|
goto exit;
|
|
}
|
|
|
|
for (ulIndex = 0; ulIndex < m_cItems; ulIndex++)
|
|
{
|
|
switch(m_rgItems[ulIndex].type)
|
|
{
|
|
// These ones are always valid
|
|
case ACT_TYPE_DELETESERVER:
|
|
case ACT_TYPE_DONTDOWNLOAD:
|
|
case ACT_TYPE_FLAG:
|
|
case ACT_TYPE_READ:
|
|
case ACT_TYPE_MARKDOWNLOAD:
|
|
case ACT_TYPE_DELETE:
|
|
case ACT_TYPE_JUNKMAIL:
|
|
case ACT_TYPE_STOP:
|
|
if (VT_EMPTY != m_rgItems[ulIndex].propvar.vt)
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
case ACT_TYPE_HIGHLIGHT:
|
|
if (VT_UI4 != m_rgItems[ulIndex].propvar.vt)
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
case ACT_TYPE_WATCH:
|
|
case ACT_TYPE_SHOW:
|
|
if (VT_UI4 != m_rgItems[ulIndex].propvar.vt)
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
if (ACT_DATA_NULL == m_rgItems[ulIndex].propvar.ulVal)
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
case ACT_TYPE_COPY:
|
|
case ACT_TYPE_MOVE:
|
|
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;
|
|
}
|
|
|
|
hr = g_pStore->GetFolderInfo(prfdData->idFolder, &Folder);
|
|
if (FAILED(hr))
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
else
|
|
g_pStore->FreeRecord(&Folder);
|
|
break;
|
|
|
|
case ACT_TYPE_REPLY:
|
|
case ACT_TYPE_NOTIFYSND:
|
|
if ((VT_LPSTR != m_rgItems[ulIndex].propvar.vt) ||
|
|
(NULL == m_rgItems[ulIndex].propvar.pszVal))
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
Assert(lstrlen(m_rgItems[ulIndex].propvar.pszVal) <= MAX_PATH)
|
|
if (0xFFFFFFFF == GetFileAttributes(m_rgItems[ulIndex].propvar.pszVal))
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
case ACT_TYPE_FWD:
|
|
{
|
|
LPWSTR pwszVal = NULL,
|
|
pwszText = 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;
|
|
}
|
|
|
|
// Update the display 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;
|
|
}
|
|
|
|
// If either always encrypt or always sign is turned on
|
|
// we can't do anything
|
|
if ((0 != DwGetOption(OPT_MAIL_DIGSIGNMESSAGES)) || (0 != DwGetOption(OPT_MAIL_ENCRYPTMESSAGES)))
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If we got here, the we must be AOK
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
SafeMemFree(pszText);
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEActions::AppendActions(DWORD dwFlags, ACT_ITEM * pItem, ULONG cItem, ULONG * pcItemAppended)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ACT_ITEM * pItemNew = NULL;
|
|
|
|
// Check incoming parameters
|
|
if ((0 != dwFlags) || (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(ACT_ITEM) * (m_cItemsAlloc + ACT_GROW));
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
ZeroMemory(m_rgItems + m_cItemsAlloc, sizeof(ACT_ITEM) * ACT_GROW);
|
|
m_cItemsAlloc += ACT_GROW;
|
|
}
|
|
|
|
// Let's duplicate the items that need to be added
|
|
hr = RuleUtil_HrDupActionsItem(pItem, cItem, &pItemNew);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Let's add them to the criteria array
|
|
CopyMemory(m_rgItems + m_cItems, pItemNew, sizeof(ACT_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;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LoadReg
|
|
//
|
|
// This loads in the actions from the registry. It loads in the actions
|
|
// order from the Order value. The string contains space delimitied values
|
|
// and each value contains the subkey name for each action. Each action
|
|
// is loaded in the order that is contained in the Order value. The actions
|
|
// are loaded with the Actions Type. The Actions Value Type is loaded if it exists.
|
|
// If an Action Value Type exists, then the corresponding Action Value is loaded in.
|
|
//
|
|
// pszRegPath - the path to load the actions from
|
|
//
|
|
// Returns: S_OK, if the actions were loaded without problems
|
|
// E_OUTOFMEMORY, if we couldn't allocate memory to hold the actions
|
|
// E_FAIL, otherwise
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP COEActions::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;
|
|
ACT_ITEM * pItems = NULL;
|
|
LPSTR pszNext = NULL;
|
|
ULONG ulOrder = 0;
|
|
HKEY hkeyAction = NULL;
|
|
ACT_TYPE typeAct;
|
|
PROPVARIANT propvar = {0};
|
|
DWORD dwType = 0;
|
|
BYTE * pbData = NULL;
|
|
DWORD dwFlags = ACT_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 & ACT_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 actions order
|
|
hr = RuleUtil_HrGetRegValue(hkeyRoot, c_szActionsOrder, 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 actions is mis-formatted in the registry");
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Convert the actions 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 actions
|
|
cbData = cOrder * sizeof(ACT_ITEM);
|
|
hr = HrAlloc((void **) &pItems, cbData);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize it to a known value
|
|
ZeroMemory(pItems, cbData);
|
|
|
|
// For each action in the order string
|
|
pszWalk = pszOrder;
|
|
for (ulOrder = 0, pszWalk = pszOrder; ulOrder < cOrder; ulOrder++, pszWalk += lstrlen(pszWalk) + 1)
|
|
{
|
|
// Open up the action reg key
|
|
lErr = RegOpenKeyEx(hkeyRoot, pszWalk, 0, KEY_READ, &hkeyAction);
|
|
if (ERROR_SUCCESS != lErr)
|
|
{
|
|
AssertSz(FALSE, "Part of the criteria is mis-formatted in the registry");
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Get the action type
|
|
cbData = sizeof(typeAct);
|
|
lErr = RegQueryValueEx(hkeyAction, c_szActionsType, 0, NULL,
|
|
(BYTE *) &(typeAct), &cbData);
|
|
if (ERROR_SUCCESS != lErr)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Get the action flags
|
|
cbData = sizeof(dwFlags);
|
|
lErr = RegQueryValueEx(hkeyAction, c_szActionsFlags, 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 = ACT_FLAG_DEFAULT;
|
|
}
|
|
|
|
// Does a action value type exist
|
|
lErr = RegQueryValueEx(hkeyAction, c_szActionsValueType, 0, NULL, NULL, &cbData);
|
|
if ((ERROR_SUCCESS == lErr) && (0 != cbData))
|
|
{
|
|
// Load the action value in
|
|
cbData = sizeof(dwType);
|
|
lErr = RegQueryValueEx(hkeyAction, c_szActionsValueType, 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 action value
|
|
cbData = sizeof(propvar.ulVal);
|
|
lErr = RegQueryValueEx(hkeyAction, c_szActionsValue, 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(hkeyAction, c_szActionsValue, 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 an invalid action type?");
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Save the value into the criteria array
|
|
pItems[ulOrder].type = typeAct;
|
|
pItems[ulOrder].dwFlags = dwFlags;
|
|
pItems[ulOrder].propvar = propvar;
|
|
ZeroMemory(&propvar, sizeof(propvar));
|
|
|
|
// Close the action
|
|
SideAssert(ERROR_SUCCESS == RegCloseKey(hkeyAction));
|
|
hkeyAction = NULL;
|
|
}
|
|
|
|
// Free up the current actions
|
|
SafeMemFree(m_rgItems);
|
|
|
|
// Save the new values
|
|
m_rgItems = pItems;
|
|
pItems = NULL;
|
|
m_cItems = cOrder;
|
|
|
|
// Make sure we clear the dirty bit
|
|
m_dwState &= ~ACT_STATE_DIRTY;
|
|
|
|
// Note that we have been loaded
|
|
m_dwState |= ACT_STATE_LOADED;
|
|
|
|
// Set the return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
SafeMemFree(pbData);
|
|
PropVariantClear(&propvar);
|
|
RuleUtil_HrFreeActionsItem(pItems, cOrder);
|
|
SafeMemFree(pItems);
|
|
SafeMemFree(pszOrder);
|
|
if (NULL != hkeyAction)
|
|
{
|
|
RegCloseKey(hkeyAction);
|
|
}
|
|
if (NULL != hkeyRoot)
|
|
{
|
|
RegCloseKey(hkeyRoot);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEActions::SaveReg(LPCSTR pszRegPath, BOOL fClearDirty)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG lErr = 0;
|
|
HKEY hkeyRoot = NULL;
|
|
DWORD dwDisp = 0;
|
|
LPSTR pszOrder = NULL;
|
|
ULONG ulIndex = 0;
|
|
ACT_ITEM * pItem = NULL;
|
|
CHAR rgchTag[CCH_ACT_ORDER];
|
|
HKEY hkeyAction = 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 < ACT_COUNT_MAX);
|
|
|
|
// Allocate space to hold the order
|
|
DWORD cchSize = (m_cItems * CCH_ACT_ORDER);
|
|
hr = HrAlloc((void **) &pszOrder, cchSize * sizeof(*pszOrder));
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
pszOrder[0] = '\0';
|
|
|
|
// Write out each of the actions
|
|
for (ulIndex = 0, pItem = m_rgItems; ulIndex < m_cItems; ulIndex++, pItem++)
|
|
{
|
|
// Get the new action 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 action
|
|
lErr = RegCreateKeyEx(hkeyRoot, rgchTag, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyAction, &dwDisp);
|
|
if (ERROR_SUCCESS != lErr)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
Assert(REG_CREATED_NEW_KEY == dwDisp);
|
|
|
|
// Write out the action type
|
|
lErr = RegSetValueEx(hkeyAction, c_szActionsType, 0, REG_DWORD,
|
|
(BYTE *) &(pItem->type), sizeof(pItem->type));
|
|
if (ERROR_SUCCESS != lErr)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Write out the action type
|
|
lErr = RegSetValueEx(hkeyAction, c_szActionsFlags, 0, REG_DWORD,
|
|
(BYTE *) &(pItem->dwFlags), sizeof(pItem->dwFlags));
|
|
if (ERROR_SUCCESS != lErr)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Do we have an action value?
|
|
if (VT_EMPTY != pItem->propvar.vt)
|
|
{
|
|
// Write out the criteria value type
|
|
dwDisp = pItem->propvar.vt;
|
|
lErr = RegSetValueEx(hkeyAction, c_szActionsValueType, 0, REG_DWORD, (BYTE *) &dwDisp, sizeof(dwDisp));
|
|
if (ERROR_SUCCESS != lErr)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Write out the action 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 an invalid action type?");
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
break;
|
|
}
|
|
|
|
// Write out the action value
|
|
lErr = RegSetValueEx(hkeyAction, c_szActionsValue, 0, dwDisp, pbData, cbData);
|
|
if (ERROR_SUCCESS != lErr)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Close the action
|
|
SideAssert(ERROR_SUCCESS == RegCloseKey(hkeyAction));
|
|
hkeyAction = NULL;
|
|
}
|
|
|
|
// Write out the order string.
|
|
lErr = RegSetValueEx(hkeyRoot, c_szActionsOrder, 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 &= ~ACT_STATE_DIRTY;
|
|
}
|
|
|
|
// Set the return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
if (NULL != hkeyAction)
|
|
{
|
|
RegCloseKey(hkeyAction);
|
|
}
|
|
SafeMemFree(pszOrder);
|
|
if (NULL != hkeyRoot)
|
|
{
|
|
RegCloseKey(hkeyRoot);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEActions::Clone(IOEActions ** ppIActions)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
COEActions * pActions = NULL;
|
|
|
|
// Check incoming params
|
|
if (NULL == ppIActions)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize the outgoing params
|
|
*ppIActions = NULL;
|
|
|
|
// Create a new actions
|
|
pActions = new COEActions;
|
|
if (NULL == pActions)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
// Copy over the list of actions
|
|
hr = pActions->SetActions(0, m_rgItems, m_cItems);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Get the actions interface
|
|
hr = pActions->QueryInterface(IID_IOEActions, (void **) ppIActions);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
pActions = NULL;
|
|
|
|
// Set the proper return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
if (NULL != pActions)
|
|
{
|
|
delete pActions;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEActions::GetClassID(CLSID * pclsid)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (NULL == pclsid)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
*pclsid = CLSID_OEActions;
|
|
|
|
// Set the proper return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEActions::IsDirty(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = (ACT_STATE_DIRTY == (m_dwState & ACT_STATE_DIRTY)) ? S_OK : S_FALSE;
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEActions::Load(IStream * pStm)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG cbData = 0;
|
|
ULONG cbRead = 0;
|
|
DWORD dwData = 0;
|
|
ULONG cItems = 0;
|
|
ACT_ITEM * pItems = NULL;
|
|
ULONG ulIndex = 0;
|
|
ACT_ITEM * pItem = NULL;
|
|
ACT_TYPE typeAct;
|
|
PROPVARIANT propvar = {0};
|
|
BYTE * pbData = NULL;
|
|
DWORD dwFlags = ACT_FLAG_DEFAULT;
|
|
|
|
// 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 != ACT_VERSION))
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Get the number of actions
|
|
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 actions
|
|
hr = HrAlloc( (void **) &pItems, cItems * sizeof(*pItems));
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize the actions to a known value
|
|
ZeroMemory(pItems, cItems * sizeof(*pItems));
|
|
|
|
// for each action
|
|
for (ulIndex = 0, pItem = pItems; ulIndex < cItems; ulIndex++, pItem++)
|
|
{
|
|
// Read in the action type
|
|
hr = pStm->Read(&typeAct, sizeof(typeAct), &cbRead);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if (cbRead != sizeof(typeAct))
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Read in the action flags
|
|
hr = pStm->Read(&dwFlags, sizeof(dwFlags), &cbRead);
|
|
if ((FAILED(hr)) || (cbRead != sizeof(dwFlags)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Read in the action value type
|
|
hr = pStm->Read(&dwData, sizeof(dwData), &cbRead);
|
|
if ((FAILED(hr)) || (cbRead != sizeof(dwData)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
propvar.vt = (VARTYPE) dwData;
|
|
|
|
if (VT_EMPTY != propvar.vt)
|
|
{
|
|
// Get the size of the action value
|
|
hr = pStm->Read(&cbData, sizeof(cbData), &cbRead);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if (cbRead != sizeof(cbData))
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Allocate space to hold the action value data
|
|
switch (propvar.vt)
|
|
{
|
|
case VT_UI4:
|
|
pbData = (BYTE * ) &(propvar.ulVal);
|
|
break;
|
|
|
|
case VT_BLOB:
|
|
case VT_LPSTR:
|
|
hr = HrAlloc((void **) &pbData, cbData);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if (VT_LPSTR == propvar.vt)
|
|
{
|
|
propvar.pszVal = (LPSTR) pbData;
|
|
}
|
|
else
|
|
{
|
|
propvar.blob.cbSize = cbData;
|
|
propvar.blob.pBlobData = pbData;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
AssertSz(FALSE, "Why are we trying to save in a invalid action type?");
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
break;
|
|
}
|
|
|
|
// Read in the action value
|
|
hr = pStm->Read(pbData, cbData, &cbRead);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if (cbRead != cbData)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
}
|
|
|
|
pItem->type = typeAct;
|
|
pItem->dwFlags = dwFlags;
|
|
pItem->propvar = propvar;
|
|
ZeroMemory(&propvar, sizeof(propvar));
|
|
}
|
|
|
|
// Free up the current actions
|
|
SafeMemFree(m_rgItems);
|
|
|
|
// Save the new values
|
|
m_rgItems = pItems;
|
|
pItems = NULL;
|
|
m_cItems = cItems;
|
|
|
|
// Make sure we clear the dirty bit
|
|
m_dwState &= ~ACT_STATE_DIRTY;
|
|
|
|
// Note that we have been loaded
|
|
m_dwState |= ACT_STATE_LOADED;
|
|
|
|
// Set the return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
PropVariantClear(&propvar);
|
|
RuleUtil_HrFreeActionsItem(pItems, cItems);
|
|
SafeMemFree(pItems);
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COEActions::Save(IStream * pStm, BOOL fClearDirty)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG cbData = 0;
|
|
ULONG cbWritten = 0;
|
|
DWORD dwData = 0;
|
|
ULONG ulIndex = 0;
|
|
ACT_ITEM * pItem = NULL;
|
|
BYTE * pbData = NULL;
|
|
|
|
// Check incoming param
|
|
if (NULL == pStm)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
// Write out the version
|
|
dwData = ACT_VERSION;
|
|
hr = pStm->Write(&dwData, sizeof(dwData), &cbWritten);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
Assert(cbWritten == sizeof(dwData));
|
|
|
|
// Write out the count of actions
|
|
hr = pStm->Write(&m_cItems, sizeof(m_cItems), &cbWritten);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
Assert(cbWritten == sizeof(m_cItems));
|
|
|
|
// Loop through each of the actions
|
|
for (ulIndex = 0, pItem = m_rgItems; ulIndex < m_cItems; ulIndex++, pItem++)
|
|
{
|
|
// Write out the action type
|
|
hr = pStm->Write(&(pItem->type), sizeof(pItem->type), &cbWritten);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
Assert(cbWritten == sizeof(pItem->type));
|
|
|
|
// Write out the actions flags
|
|
hr = pStm->Write(&(pItem->dwFlags), sizeof(pItem->dwFlags), &cbWritten);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
Assert(cbWritten == sizeof(pItem->dwFlags));
|
|
|
|
// Write out the value type
|
|
dwData = pItem->propvar.vt;
|
|
hr = pStm->Write(&(dwData), sizeof(dwData), &cbWritten);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
Assert(cbWritten == sizeof(dwData));
|
|
|
|
if (VT_EMPTY == pItem->propvar.vt)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Figure out the size of the action value
|
|
switch (pItem->propvar.vt)
|
|
{
|
|
case VT_UI4:
|
|
pbData = (BYTE * ) &(pItem->propvar.ulVal);
|
|
cbData = sizeof(pItem->propvar.ulVal);
|
|
break;
|
|
|
|
case VT_LPSTR:
|
|
pbData = (BYTE * ) (pItem->propvar.pszVal);
|
|
cbData = lstrlen(pItem->propvar.pszVal) + 1;
|
|
break;
|
|
|
|
case VT_BLOB:
|
|
pbData = pItem->propvar.blob.pBlobData;
|
|
cbData = pItem->propvar.blob.cbSize;
|
|
break;
|
|
|
|
default:
|
|
AssertSz(FALSE, "Why are we trying to save in a invalid action type?");
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
break;
|
|
}
|
|
|
|
// Write out the action value size
|
|
hr = pStm->Write(&cbData, sizeof(cbData), &cbWritten);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
Assert(cbWritten == sizeof(cbData));
|
|
|
|
// Write out the action value
|
|
hr = pStm->Write(pbData, cbData, &cbWritten);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
Assert(cbWritten == cbData);
|
|
}
|
|
|
|
// Should we clear out the dirty bit
|
|
if (FALSE != fClearDirty)
|
|
{
|
|
m_dwState &= ~ACT_STATE_DIRTY;
|
|
}
|
|
|
|
// Set the return value
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|