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.
 
 
 
 
 
 

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;
}