Leaked source code of windows server 2003

1270 lines
28 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Rule.cpp
  4. //
  5. ///////////////////////////////////////////////////////////////////////////////
  6. #include <pch.hxx>
  7. #include "rule.h"
  8. #include "strconst.h"
  9. #include "goptions.h"
  10. #include "criteria.h"
  11. #include "actions.h"
  12. #include "ruleutil.h"
  13. ///////////////////////////////////////////////////////////////////////////////
  14. //
  15. // HrCreateRule
  16. //
  17. // This creates a rule.
  18. //
  19. // ppIRule - pointer to return the rule
  20. //
  21. // Returns: S_OK, on success
  22. // E_OUTOFMEMORY, if can't create the Rule object
  23. //
  24. ///////////////////////////////////////////////////////////////////////////////
  25. HRESULT HrCreateRule(IOERule ** ppIRule)
  26. {
  27. COERule * pRule = NULL;
  28. HRESULT hr = S_OK;
  29. // Check the incoming params
  30. if (NULL == ppIRule)
  31. {
  32. hr = E_INVALIDARG;
  33. goto exit;
  34. }
  35. // Initialize outgoing params
  36. *ppIRule = NULL;
  37. // Create the rules manager object
  38. pRule = new COERule;
  39. if (NULL == pRule)
  40. {
  41. hr = E_OUTOFMEMORY;
  42. goto exit;
  43. }
  44. // Get the rules manager interface
  45. hr = pRule->QueryInterface(IID_IOERule, (void **) ppIRule);
  46. if (FAILED(hr))
  47. {
  48. goto exit;
  49. }
  50. pRule = NULL;
  51. // Set the proper return value
  52. hr = S_OK;
  53. exit:
  54. if (NULL != pRule)
  55. {
  56. delete pRule;
  57. }
  58. return hr;
  59. }
  60. COERule::COERule()
  61. {
  62. m_cRef = 0;
  63. m_dwState = RULE_STATE_NULL;
  64. m_pszName = NULL;
  65. m_pICrit = NULL;
  66. m_pIAct = NULL;
  67. m_dwVersion = 0;
  68. }
  69. COERule::~COERule()
  70. {
  71. ULONG ulIndex = 0;
  72. AssertSz(m_cRef == 0, "Somebody still has a hold of us!!");
  73. SafeMemFree(m_pszName);
  74. SafeRelease(m_pICrit);
  75. SafeRelease(m_pIAct);
  76. }
  77. STDMETHODIMP_(ULONG) COERule::AddRef()
  78. {
  79. return ::InterlockedIncrement(&m_cRef);
  80. }
  81. STDMETHODIMP_(ULONG) COERule::Release()
  82. {
  83. LONG cRef = 0;
  84. cRef = ::InterlockedDecrement(&m_cRef);
  85. if (0 == cRef)
  86. {
  87. delete this;
  88. return cRef;
  89. }
  90. return cRef;
  91. }
  92. STDMETHODIMP COERule::QueryInterface(REFIID riid, void ** ppvObject)
  93. {
  94. HRESULT hr = S_OK;
  95. // Check the incoming params
  96. if (NULL == ppvObject)
  97. {
  98. hr = E_INVALIDARG;
  99. goto exit;
  100. }
  101. // Initialize outgoing param
  102. *ppvObject = NULL;
  103. if ((riid == IID_IUnknown) || (riid == IID_IOERule))
  104. {
  105. *ppvObject = static_cast<IOERule *>(this);
  106. }
  107. else if ((riid == IID_IPersistStream) || (riid == IID_IPersist))
  108. {
  109. *ppvObject = static_cast<IPersistStream *>(this);
  110. }
  111. else
  112. {
  113. hr = E_NOINTERFACE;
  114. goto exit;
  115. }
  116. reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();
  117. hr = S_OK;
  118. exit:
  119. return hr;
  120. }
  121. STDMETHODIMP COERule::Reset(void)
  122. {
  123. HRESULT hr = S_OK;
  124. LPSTR pszKeyPath = NULL;
  125. LPCSTR pszKeyStart = NULL;
  126. // Release the criteria
  127. SafeRelease(m_pICrit);
  128. // Release the actions
  129. SafeRelease(m_pIAct);
  130. // Free up the rule name
  131. SafeMemFree(m_pszName);
  132. // Set the current state
  133. m_dwState |= RULE_STATE_INIT;
  134. // Clear the dirty bit
  135. m_dwState &= ~RULE_STATE_DIRTY;
  136. // Set the return value
  137. hr = S_OK;
  138. return hr;
  139. }
  140. STDMETHODIMP COERule::GetState(DWORD * pdwState)
  141. {
  142. HRESULT hr = S_OK;
  143. ULONG ulIndex = 0;
  144. // Check incoming params
  145. if (NULL == pdwState)
  146. {
  147. hr = E_INVALIDARG;
  148. goto exit;
  149. }
  150. // If we're not enabled
  151. if ((0 != (m_dwState & RULE_STATE_DISABLED)) || (0 != (m_dwState & RULE_STATE_INVALID)))
  152. {
  153. *pdwState = RULE_STATE_NULL;
  154. }
  155. else
  156. {
  157. *pdwState = m_dwState;
  158. }
  159. // Set the proper return value
  160. hr = S_OK;
  161. exit:
  162. return hr;
  163. }
  164. STDMETHODIMP COERule::Validate(DWORD dwFlags)
  165. {
  166. HRESULT hr = S_OK;
  167. BOOL fValid = FALSE;
  168. // If we don't have a criteria or actions object then we fail
  169. if ((NULL == m_pICrit) || (NULL == m_pIAct))
  170. {
  171. hr = E_FAIL;
  172. goto exit;
  173. }
  174. // Validate the criteria
  175. hr = m_pICrit->Validate(dwFlags);
  176. if (FAILED(hr))
  177. {
  178. goto exit;
  179. }
  180. fValid = TRUE;
  181. if (S_OK != hr)
  182. {
  183. fValid = FALSE;
  184. }
  185. // Validate the actions
  186. hr = m_pIAct->Validate(dwFlags);
  187. if (FAILED(hr))
  188. {
  189. goto exit;
  190. }
  191. if (S_OK != hr)
  192. {
  193. fValid = FALSE;
  194. }
  195. // If the rule is invalid, make sure we disable it
  196. if (FALSE == fValid)
  197. {
  198. m_dwState |= RULE_STATE_INVALID;
  199. }
  200. else
  201. {
  202. m_dwState &= ~RULE_STATE_INVALID;
  203. }
  204. // Set the proper return value
  205. hr = fValid ? S_OK : S_FALSE;
  206. exit:
  207. return hr;
  208. }
  209. STDMETHODIMP COERule::GetProp(RULE_PROP prop, DWORD dwFlags, PROPVARIANT * pvarResult)
  210. {
  211. HRESULT hr = S_OK;
  212. LPSTR pszName = NULL;
  213. CRIT_ITEM * pCrit = NULL;
  214. ACT_ITEM * pAct = NULL;
  215. ULONG cItem = 0;
  216. // Check incoming params
  217. if (NULL == pvarResult)
  218. {
  219. hr = E_INVALIDARG;
  220. goto exit;
  221. }
  222. // Initialize outgoing params
  223. ZeroMemory(pvarResult, sizeof(*pvarResult));
  224. switch(prop)
  225. {
  226. case RULE_PROP_NAME:
  227. if (NULL == m_pszName)
  228. {
  229. pszName = PszDupA("");
  230. }
  231. else
  232. {
  233. pszName = PszDupA(m_pszName);
  234. }
  235. pvarResult->vt = VT_LPSTR;
  236. pvarResult->pszVal = pszName;
  237. pszName = NULL;
  238. break;
  239. case RULE_PROP_DISABLED:
  240. pvarResult->vt = VT_BOOL;
  241. pvarResult->boolVal = !!(m_dwState & RULE_STATE_DISABLED);
  242. break;
  243. case RULE_PROP_VERSION:
  244. pvarResult->vt = VT_UI4;
  245. pvarResult->ulVal = m_dwVersion;
  246. break;
  247. case RULE_PROP_CRITERIA:
  248. if (NULL == m_pICrit)
  249. {
  250. cItem = 0;
  251. pCrit = NULL;
  252. }
  253. else
  254. {
  255. hr = m_pICrit->GetCriteria(0, &pCrit, &cItem);
  256. if (FAILED(hr))
  257. {
  258. goto exit;
  259. }
  260. }
  261. pvarResult->vt = VT_BLOB;
  262. pvarResult->blob.cbSize = cItem * sizeof(CRIT_ITEM);
  263. pvarResult->blob.pBlobData = (BYTE *) pCrit;
  264. pCrit = NULL;
  265. break;
  266. case RULE_PROP_ACTIONS:
  267. if (NULL == m_pIAct)
  268. {
  269. cItem = 0;
  270. pAct = NULL;
  271. }
  272. else
  273. {
  274. hr = m_pIAct->GetActions(0, &pAct, &cItem);
  275. if (FAILED(hr))
  276. {
  277. goto exit;
  278. }
  279. }
  280. pvarResult->vt = VT_BLOB;
  281. pvarResult->blob.cbSize = cItem * sizeof(ACT_ITEM);
  282. pvarResult->blob.pBlobData = (BYTE *) pAct;
  283. pAct = NULL;
  284. break;
  285. default:
  286. hr = E_INVALIDARG;
  287. goto exit;
  288. }
  289. // Set the return value
  290. hr = S_OK;
  291. exit:
  292. SafeMemFree(pszName);
  293. RuleUtil_HrFreeCriteriaItem(pCrit, cItem);
  294. SafeMemFree(pCrit);
  295. RuleUtil_HrFreeActionsItem(pAct, cItem);
  296. SafeMemFree(pAct);
  297. return hr;
  298. }
  299. STDMETHODIMP COERule::SetProp(RULE_PROP prop, DWORD dwFlags, PROPVARIANT * pvarResult)
  300. {
  301. HRESULT hr = S_OK;
  302. LPSTR pszName = NULL;
  303. DWORD dwState = 0;
  304. ULONG cItems = 0;
  305. // Check incoming params
  306. if (NULL == pvarResult)
  307. {
  308. hr = E_INVALIDARG;
  309. goto exit;
  310. }
  311. switch(prop)
  312. {
  313. case RULE_PROP_NAME:
  314. if ((VT_LPSTR != pvarResult->vt) || (NULL == pvarResult->pszVal))
  315. {
  316. hr = E_INVALIDARG;
  317. goto exit;
  318. }
  319. // Create a new copy
  320. pszName = PszDupA(pvarResult->pszVal);
  321. if (NULL == pszName)
  322. {
  323. hr = E_OUTOFMEMORY;
  324. goto exit;
  325. }
  326. // Free up any old value
  327. SafeMemFree(m_pszName);
  328. // Set the new value
  329. m_pszName = pszName;
  330. pszName = NULL;
  331. break;
  332. case RULE_PROP_DISABLED:
  333. if (VT_BOOL != pvarResult->vt)
  334. {
  335. hr = E_INVALIDARG;
  336. goto exit;
  337. }
  338. // Set the new value
  339. if (FALSE != !!(pvarResult->boolVal))
  340. {
  341. m_dwState |= RULE_STATE_DISABLED;
  342. }
  343. else
  344. {
  345. Assert(0 == (m_dwState & RULE_STATE_INVALID));
  346. m_dwState &= ~RULE_STATE_DISABLED;
  347. }
  348. break;
  349. case RULE_PROP_VERSION:
  350. if (VT_UI4 != pvarResult->vt)
  351. {
  352. hr = E_INVALIDARG;
  353. goto exit;
  354. }
  355. // Set the new value
  356. m_dwVersion = pvarResult->ulVal;
  357. break;
  358. case RULE_PROP_CRITERIA:
  359. if ((VT_BLOB != pvarResult->vt) || (0 == pvarResult->blob.cbSize) ||
  360. (NULL == pvarResult->blob.pBlobData))
  361. {
  362. hr = E_INVALIDARG;
  363. goto exit;
  364. }
  365. if (NULL == m_pICrit)
  366. {
  367. hr = HrCreateCriteria(&m_pICrit);
  368. if (FAILED(hr))
  369. {
  370. goto exit;
  371. }
  372. }
  373. cItems = pvarResult->blob.cbSize / sizeof(CRIT_ITEM);
  374. Assert(cItems * sizeof(CRIT_ITEM) == pvarResult->blob.cbSize);
  375. hr = m_pICrit->SetCriteria(0, (CRIT_ITEM *) pvarResult->blob.pBlobData, cItems);
  376. if (FAILED(hr))
  377. {
  378. goto exit;
  379. }
  380. hr = m_pICrit->GetState(&dwState);
  381. if (FAILED(hr))
  382. {
  383. goto exit;
  384. }
  385. m_dwState = (m_dwState & ~CRIT_STATE_MASK) | (dwState & CRIT_STATE_MASK);
  386. break;
  387. case RULE_PROP_ACTIONS:
  388. if ((VT_BLOB != pvarResult->vt) || (0 == pvarResult->blob.cbSize) ||
  389. (NULL == pvarResult->blob.pBlobData))
  390. {
  391. hr = E_INVALIDARG;
  392. goto exit;
  393. }
  394. if (NULL == m_pIAct)
  395. {
  396. hr = HrCreateActions(&m_pIAct);
  397. if (FAILED(hr))
  398. {
  399. goto exit;
  400. }
  401. }
  402. cItems = pvarResult->blob.cbSize / sizeof(ACT_ITEM);
  403. Assert(cItems * sizeof(ACT_ITEM) == pvarResult->blob.cbSize);
  404. hr = m_pIAct->SetActions(0, (ACT_ITEM *) pvarResult->blob.pBlobData, cItems);
  405. if (FAILED(hr))
  406. {
  407. goto exit;
  408. }
  409. hr = m_pIAct->GetState(&dwState);
  410. if (FAILED(hr))
  411. {
  412. goto exit;
  413. }
  414. m_dwState = (m_dwState & ~ACT_STATE_MASK) | (dwState & ACT_STATE_MASK);
  415. break;
  416. default:
  417. hr = E_INVALIDARG;
  418. goto exit;
  419. }
  420. // Mark the rule as dirty
  421. m_dwState |= RULE_STATE_DIRTY;
  422. // Set the return value
  423. hr = S_OK;
  424. exit:
  425. SafeMemFree(pszName);
  426. return hr;
  427. }
  428. STDMETHODIMP COERule::Evaluate(LPCSTR pszAcct, MESSAGEINFO * pMsgInfo, IMessageFolder * pFolder,
  429. IMimePropertySet * pIMPropSet, IMimeMessage * pIMMsg, ULONG cbMsgSize,
  430. ACT_ITEM ** ppActions, ULONG * pcActions)
  431. {
  432. HRESULT hr = S_OK;
  433. ACT_ITEM * pAct = NULL;
  434. ULONG cAct = 0;
  435. // Check incoming variables
  436. if (((NULL == pMsgInfo) && (NULL == pIMPropSet)) || (0 == cbMsgSize) ||
  437. (NULL == ppActions) || (NULL == pcActions))
  438. {
  439. hr = E_INVALIDARG;
  440. goto exit;
  441. }
  442. // Set outgoing params to default
  443. *ppActions = NULL;
  444. *pcActions = 0;
  445. // If we don't have a criteria or actions object then we fail
  446. if ((NULL == m_pICrit) || (NULL == m_pIAct))
  447. {
  448. hr = S_FALSE;
  449. goto exit;
  450. }
  451. // If we ain't valid then we can just bail
  452. if (0 != (m_dwState & RULE_STATE_INVALID))
  453. {
  454. hr = S_FALSE;
  455. goto exit;
  456. }
  457. // Do we match??
  458. hr = m_pICrit->MatchMessage(pszAcct, pMsgInfo, pFolder, pIMPropSet, pIMMsg, cbMsgSize);
  459. if (FAILED(hr))
  460. {
  461. goto exit;
  462. }
  463. // If we didn't match then just return
  464. if (S_FALSE == hr)
  465. {
  466. goto exit;
  467. }
  468. // Grab the actions and return them to the caller
  469. hr = m_pIAct->GetActions(0, &pAct, &cAct);
  470. if (FAILED(hr))
  471. {
  472. goto exit;
  473. }
  474. // Set the outgoing parameters
  475. *ppActions = pAct;
  476. pAct = NULL;
  477. *pcActions = cAct;
  478. // Set proper return value
  479. hr = S_OK;
  480. exit:
  481. RuleUtil_HrFreeActionsItem(pAct, cAct);
  482. SafeMemFree(pAct);
  483. return hr;
  484. }
  485. STDMETHODIMP COERule::LoadReg(LPCSTR pszRegPath)
  486. {
  487. HRESULT hr = S_OK;
  488. LONG lErr = 0;
  489. HKEY hkeyRoot = NULL;
  490. ULONG cbData = 0;
  491. ULONG cbRead = 0;
  492. DWORD dwData = 0;
  493. LPSTR pszName = NULL;
  494. BOOL fDisabled = FALSE;
  495. IOECriteria * pICriteria = NULL;
  496. IOEActions * pIActions = NULL;
  497. LPSTR pszRegPathNew = NULL;
  498. ULONG cchRegPath = 0;
  499. DWORD dwState = 0;
  500. // Check incoming param
  501. if (NULL == pszRegPath)
  502. {
  503. hr = E_INVALIDARG;
  504. goto exit;
  505. }
  506. // Should we fail if we're already loaded?
  507. AssertSz(0 == (m_dwState & RULE_STATE_LOADED), "We're already loaded!!!");
  508. // Open the reg key from the path
  509. lErr = AthUserOpenKey(pszRegPath, KEY_ALL_ACCESS, &hkeyRoot);
  510. if (ERROR_SUCCESS != lErr)
  511. {
  512. hr = E_FAIL;
  513. goto exit;
  514. }
  515. // Get the rule name
  516. hr = RuleUtil_HrGetRegValue(hkeyRoot, c_szRuleName, NULL, (BYTE **) &pszName, NULL);
  517. if (FAILED(hr))
  518. {
  519. SafeMemFree(pszName);
  520. }
  521. // Get the enabled state
  522. cbData = sizeof(dwData);
  523. lErr = RegQueryValueEx(hkeyRoot, c_szRuleEnabled, 0, NULL, (BYTE *) &dwData, &cbData);
  524. if (ERROR_SUCCESS != lErr)
  525. {
  526. hr = E_FAIL;
  527. goto exit;
  528. }
  529. Assert(cbData == sizeof(dwData));
  530. fDisabled = ! (BOOL) dwData;
  531. // Get the version of the rule
  532. cbData = sizeof(dwData);
  533. lErr = RegQueryValueEx(hkeyRoot, c_szRulesVersion, 0, NULL, (BYTE *) &dwData, &cbData);
  534. if ((ERROR_SUCCESS != lErr) && (ERROR_FILE_NOT_FOUND != lErr))
  535. {
  536. hr = E_FAIL;
  537. goto exit;
  538. }
  539. if (ERROR_FILE_NOT_FOUND == lErr)
  540. {
  541. dwData = 0;
  542. lErr = RegSetValueEx(hkeyRoot, c_szRulesVersion, 0, REG_DWORD, (CONST BYTE *) &dwData, sizeof(dwData));
  543. if (ERROR_SUCCESS != lErr)
  544. {
  545. hr = E_FAIL;
  546. goto exit;
  547. }
  548. }
  549. m_dwVersion = dwData;
  550. // Allocate space to hold the new reg path
  551. cchRegPath = lstrlen(pszRegPath);
  552. Assert(lstrlen(c_szRuleCriteria) >= lstrlen(c_szRuleActions));
  553. DWORD cchSize = (cchRegPath + lstrlen(c_szRuleCriteria) + 2);
  554. if (FAILED(HrAlloc((void **) &pszRegPathNew, cchSize)))
  555. {
  556. goto exit;
  557. }
  558. // Build reg path to criteria
  559. StrCpyN(pszRegPathNew, pszRegPath, cchSize);
  560. if ('\\' != pszRegPath[cchRegPath])
  561. {
  562. StrCatBuff(pszRegPathNew, g_szBackSlash, cchSize);
  563. cchRegPath++;
  564. }
  565. StrCatBuff(pszRegPathNew, c_szRuleCriteria, cchSize);
  566. // Create a new criteria object
  567. hr = HrCreateCriteria(&pICriteria);
  568. if (FAILED(hr))
  569. {
  570. goto exit;
  571. }
  572. // Get the criteria
  573. hr = pICriteria->LoadReg(pszRegPathNew);
  574. if (FAILED(hr))
  575. {
  576. goto exit;
  577. }
  578. // Get the state of the criteria
  579. hr = pICriteria->GetState(&dwState);
  580. if (FAILED(hr))
  581. {
  582. goto exit;
  583. }
  584. m_dwState = (m_dwState & ~CRIT_STATE_MASK) | (dwState & CRIT_STATE_MASK);
  585. // Build reg path to actions
  586. StrCpyN(pszRegPathNew + cchRegPath, c_szRuleActions, (cchSize - cchRegPath));
  587. // Create a new actions object
  588. hr = HrCreateActions(&pIActions);
  589. if (FAILED(hr))
  590. {
  591. goto exit;
  592. }
  593. // Get the actions
  594. hr = pIActions->LoadReg(pszRegPathNew);
  595. if (FAILED(hr))
  596. {
  597. goto exit;
  598. }
  599. // Get the state of the actions
  600. hr = pIActions->GetState(&dwState);
  601. if (FAILED(hr))
  602. {
  603. goto exit;
  604. }
  605. m_dwState = (m_dwState & ~ACT_STATE_MASK) | (dwState & ACT_STATE_MASK);
  606. // Free up the current values
  607. SafeMemFree(m_pszName);
  608. SafeRelease(m_pICrit);
  609. SafeRelease(m_pIAct);
  610. // Save the new values
  611. m_pszName = pszName;
  612. pszName = NULL;
  613. if (FALSE == fDisabled)
  614. {
  615. m_dwState &= ~RULE_STATE_DISABLED;
  616. }
  617. else
  618. {
  619. m_dwState |= RULE_STATE_DISABLED;
  620. }
  621. m_pICrit = pICriteria;
  622. pICriteria = NULL;
  623. m_pIAct = pIActions;
  624. pIActions = NULL;
  625. // Make sure we clear the dirty bit
  626. m_dwState &= ~RULE_STATE_DIRTY;
  627. // Note that we have been loaded
  628. m_dwState |= RULE_STATE_LOADED;
  629. // Set the return value
  630. hr = S_OK;
  631. exit:
  632. SafeMemFree(pszRegPathNew);
  633. SafeRelease(pIActions);
  634. SafeRelease(pICriteria);
  635. SafeMemFree(pszName);
  636. if (NULL != hkeyRoot)
  637. {
  638. RegCloseKey(hkeyRoot);
  639. }
  640. return hr;
  641. }
  642. STDMETHODIMP COERule::SaveReg(LPCSTR pszRegPath, BOOL fClearDirty)
  643. {
  644. HRESULT hr = S_OK;
  645. LONG lErr = 0;
  646. HKEY hkeyRoot = NULL;
  647. DWORD dwDisp = 0;
  648. DWORD dwData = 0;
  649. LPSTR pszRegPathNew = NULL;
  650. ULONG cchRegPath = 0;
  651. // Check incoming param
  652. if (NULL == pszRegPath)
  653. {
  654. hr = E_INVALIDARG;
  655. goto exit;
  656. }
  657. // Can't save out a rule if we don't have criteria or actions
  658. // or a rule name
  659. if ((NULL == m_pICrit) || (NULL == m_pIAct))
  660. {
  661. hr = E_FAIL;
  662. goto exit;
  663. }
  664. // Let's make sure we clear out the key first
  665. AthUserDeleteKey(pszRegPath);
  666. // Create the reg key from the path
  667. lErr = AthUserCreateKey(pszRegPath, KEY_ALL_ACCESS, &hkeyRoot, &dwDisp);
  668. if (ERROR_SUCCESS != lErr)
  669. {
  670. hr = E_FAIL;
  671. goto exit;
  672. }
  673. Assert(REG_CREATED_NEW_KEY == dwDisp);
  674. // Write out the rule name
  675. if (NULL != m_pszName)
  676. {
  677. lErr = RegSetValueEx(hkeyRoot, c_szRuleName, 0, REG_SZ,
  678. (BYTE *) m_pszName, lstrlen(m_pszName) + 1);
  679. if (ERROR_SUCCESS != lErr)
  680. {
  681. hr = E_FAIL;
  682. goto exit;
  683. }
  684. }
  685. // Write out the disabled state
  686. dwData = !(m_dwState & RULE_STATE_DISABLED);
  687. lErr = RegSetValueEx(hkeyRoot, c_szRuleEnabled, 0, REG_DWORD,
  688. (BYTE *) &dwData, sizeof(dwData));
  689. if (ERROR_SUCCESS != lErr)
  690. {
  691. hr = E_FAIL;
  692. goto exit;
  693. }
  694. // Allocate space to hold the new reg path
  695. cchRegPath = lstrlen(pszRegPath);
  696. Assert(lstrlen(c_szRuleCriteria) >= lstrlen(c_szRuleActions));
  697. DWORD cchSize = (cchRegPath + lstrlen(c_szRuleCriteria) + 2);
  698. if (FAILED(HrAlloc((void **) &pszRegPathNew, cchSize)))
  699. {
  700. goto exit;
  701. }
  702. // Build reg path to criteria
  703. StrCpyN(pszRegPathNew, pszRegPath, cchSize);
  704. if ('\\' != pszRegPath[cchRegPath])
  705. {
  706. StrCatBuff(pszRegPathNew, g_szBackSlash, cchSize);
  707. cchRegPath++;
  708. }
  709. StrCatBuff(pszRegPathNew, c_szRuleCriteria, cchSize);
  710. // Write out the criteria
  711. hr = m_pICrit->SaveReg(pszRegPathNew, fClearDirty);
  712. if (FAILED(hr))
  713. {
  714. goto exit;
  715. }
  716. // Build reg path to actions
  717. StrCpyN(pszRegPathNew + cchRegPath, c_szRuleActions, (cchSize - cchRegPath));
  718. // Write out the actions
  719. hr = m_pIAct->SaveReg(pszRegPathNew, fClearDirty);
  720. if (FAILED(hr))
  721. {
  722. goto exit;
  723. }
  724. // Bump up the version
  725. if (0 != (m_dwState & RULE_STATE_DIRTY))
  726. {
  727. m_dwVersion++;
  728. }
  729. lErr = RegSetValueEx(hkeyRoot, c_szRulesVersion, 0, REG_DWORD, (BYTE *) &m_dwVersion, sizeof(m_dwVersion));
  730. if (ERROR_SUCCESS != lErr)
  731. {
  732. hr = E_FAIL;
  733. goto exit;
  734. }
  735. // Should we clear the dirty bit?
  736. if (FALSE != fClearDirty)
  737. {
  738. m_dwState &= ~RULE_STATE_DIRTY;
  739. }
  740. // Set the return value
  741. hr = S_OK;
  742. exit:
  743. SafeMemFree(pszRegPathNew);
  744. if (NULL != hkeyRoot)
  745. {
  746. RegCloseKey(hkeyRoot);
  747. }
  748. return hr;
  749. }
  750. STDMETHODIMP COERule::Clone(IOERule ** ppIRule)
  751. {
  752. HRESULT hr = S_OK;
  753. COERule * pRule = NULL;
  754. // Check incoming params
  755. if (NULL == ppIRule)
  756. {
  757. hr = E_INVALIDARG;
  758. goto exit;
  759. }
  760. // Initialize the outgoing params
  761. *ppIRule = NULL;
  762. // Create a new rule
  763. pRule = new COERule;
  764. if (NULL == pRule)
  765. {
  766. hr = E_OUTOFMEMORY;
  767. goto exit;
  768. }
  769. // Copy over the rule name
  770. if (NULL != m_pszName)
  771. {
  772. pRule->m_pszName = PszDupA(m_pszName);
  773. if (NULL == pRule->m_pszName)
  774. {
  775. hr = E_OUTOFMEMORY;
  776. goto exit;
  777. }
  778. }
  779. // Copy over the enabled state
  780. pRule->m_dwState = m_dwState;
  781. // Copy over the version
  782. pRule->m_dwVersion = m_dwVersion;
  783. // Clone the criteria
  784. if (FAILED(m_pICrit->Clone(&(pRule->m_pICrit))))
  785. {
  786. goto exit;
  787. }
  788. // Clone the actions
  789. if (FAILED(m_pIAct->Clone(&(pRule->m_pIAct))))
  790. {
  791. goto exit;
  792. }
  793. // Get the rule interface
  794. hr = pRule->QueryInterface(IID_IOERule, (void **) ppIRule);
  795. if (FAILED(hr))
  796. {
  797. goto exit;
  798. }
  799. pRule = NULL;
  800. // Set the proper return value
  801. hr = S_OK;
  802. exit:
  803. if (NULL != pRule)
  804. {
  805. delete pRule;
  806. }
  807. return hr;
  808. }
  809. STDMETHODIMP COERule::GetClassID(CLSID * pclsid)
  810. {
  811. HRESULT hr = S_OK;
  812. if (NULL == pclsid)
  813. {
  814. hr = E_INVALIDARG;
  815. goto exit;
  816. }
  817. *pclsid = CLSID_OERule;
  818. // Set the proper return value
  819. hr = S_OK;
  820. exit:
  821. return hr;
  822. }
  823. STDMETHODIMP COERule::IsDirty(void)
  824. {
  825. HRESULT hr = S_OK;
  826. hr = (RULE_STATE_DIRTY == (m_dwState & RULE_STATE_DIRTY)) ? S_OK : S_FALSE;
  827. return hr;
  828. }
  829. STDMETHODIMP COERule::Load(IStream * pStm)
  830. {
  831. HRESULT hr = S_OK;
  832. ULONG cbData = 0;
  833. ULONG cbRead = 0;
  834. DWORD dwData = 0;
  835. LPSTR pszName = NULL;
  836. BOOL fDisabled = FALSE;
  837. IOECriteria * pICriteria = NULL;
  838. IPersistStream * pIPStm = NULL;
  839. IOEActions * pIActions = NULL;
  840. // Check incoming param
  841. if (NULL == pStm)
  842. {
  843. hr = E_INVALIDARG;
  844. goto exit;
  845. }
  846. // Verify we have the correct version
  847. hr = pStm->Read(&dwData, sizeof(dwData), &cbRead);
  848. if (FAILED(hr))
  849. {
  850. goto exit;
  851. }
  852. if ((cbRead != sizeof(dwData)) || (dwData != RULE_VERSION))
  853. {
  854. hr = E_FAIL;
  855. goto exit;
  856. }
  857. // Get the size of the rule name
  858. hr = pStm->Read(&cbData, sizeof(cbData), &cbRead);
  859. if (FAILED(hr))
  860. {
  861. goto exit;
  862. }
  863. if (cbRead != sizeof(cbData))
  864. {
  865. hr = E_FAIL;
  866. goto exit;
  867. }
  868. if (0 != cbData)
  869. {
  870. // Allocate space to hold the rule name
  871. hr = HrAlloc((void **) &pszName, cbData);
  872. if (FAILED(hr))
  873. {
  874. goto exit;
  875. }
  876. // Get the rule name
  877. hr = pStm->Read(pszName, cbData, &cbRead);
  878. if (FAILED(hr))
  879. {
  880. goto exit;
  881. }
  882. if (cbRead != cbData)
  883. {
  884. hr = E_FAIL;
  885. goto exit;
  886. }
  887. }
  888. // Get the enabled state
  889. hr = pStm->Read(&dwData, sizeof(dwData), &cbRead);
  890. if (FAILED(hr))
  891. {
  892. goto exit;
  893. }
  894. if (cbRead != sizeof(dwData))
  895. {
  896. hr = E_FAIL;
  897. goto exit;
  898. }
  899. fDisabled = ! (BOOL) dwData;
  900. // Create a new criteria object
  901. hr = HrCreateCriteria(&pICriteria);
  902. if (FAILED(hr))
  903. {
  904. goto exit;
  905. }
  906. // Get the persistance interface for the criteria
  907. hr = pICriteria->QueryInterface(IID_IPersistStream, (void **) &pIPStm);
  908. if (FAILED(hr))
  909. {
  910. goto exit;
  911. }
  912. // Get the criteria
  913. hr = pIPStm->Load(pStm);
  914. if (FAILED(hr))
  915. {
  916. goto exit;
  917. }
  918. // Create a new actions object
  919. hr = HrCreateActions(&pIActions);
  920. if (FAILED(hr))
  921. {
  922. goto exit;
  923. }
  924. // Get the persistance interface for the actions
  925. pIPStm->Release();
  926. pIPStm = NULL;
  927. hr = pIActions->QueryInterface(IID_IPersistStream, (void **) &pIPStm);
  928. if (FAILED(hr))
  929. {
  930. goto exit;
  931. }
  932. // Get the actions
  933. hr = pIPStm->Load(pStm);
  934. if (FAILED(hr))
  935. {
  936. goto exit;
  937. }
  938. // Free up the current values
  939. SafeMemFree(m_pszName);
  940. SafeRelease(m_pICrit);
  941. SafeRelease(m_pIAct);
  942. // Save the new values
  943. m_pszName = pszName;
  944. pszName = NULL;
  945. if (FALSE == fDisabled)
  946. {
  947. m_dwState &= ~RULE_STATE_DISABLED;
  948. }
  949. else
  950. {
  951. m_dwState |= RULE_STATE_DISABLED;
  952. }
  953. m_pICrit = pICriteria;
  954. pICriteria = NULL;
  955. m_pIAct = pIActions;
  956. pIActions = NULL;
  957. // Make sure we clear the dirty bit
  958. m_dwState &= ~RULE_STATE_DIRTY;
  959. // Note that we have been loaded
  960. m_dwState |= RULE_STATE_LOADED;
  961. // Set the return value
  962. hr = S_OK;
  963. exit:
  964. SafeRelease(pIActions);
  965. SafeRelease(pICriteria);
  966. SafeRelease(pIPStm);
  967. SafeMemFree(pszName);
  968. return hr;
  969. }
  970. STDMETHODIMP COERule::Save(IStream * pStm, BOOL fClearDirty)
  971. {
  972. HRESULT hr = S_OK;
  973. ULONG cbData = 0;
  974. ULONG cbWritten = 0;
  975. DWORD dwData = 0;
  976. ULONG ulIndex = 0;
  977. IPersistStream * pIPStm = NULL;
  978. // Check incoming param
  979. if (NULL == pStm)
  980. {
  981. hr = E_INVALIDARG;
  982. goto exit;
  983. }
  984. // Can't write out a rule if we don't have criteria or actions
  985. // or a rule name
  986. if ((NULL == m_pICrit) || (NULL == m_pIAct))
  987. {
  988. hr = E_FAIL;
  989. goto exit;
  990. }
  991. // Write out the version
  992. dwData = RULE_VERSION;
  993. hr = pStm->Write(&dwData, sizeof(dwData), &cbWritten);
  994. if (FAILED(hr))
  995. {
  996. goto exit;
  997. }
  998. Assert(cbWritten == sizeof(dwData));
  999. // Write out the size of the rule name
  1000. if (NULL != m_pszName)
  1001. {
  1002. cbData = lstrlen(m_pszName) + 1;
  1003. }
  1004. else
  1005. {
  1006. cbData = 0;
  1007. }
  1008. hr = pStm->Write(&cbData, sizeof(cbData), &cbWritten);
  1009. if (FAILED(hr))
  1010. {
  1011. goto exit;
  1012. }
  1013. Assert(cbWritten == sizeof(cbData));
  1014. if (NULL != m_pszName)
  1015. {
  1016. // Write out the rule name
  1017. hr = pStm->Write(m_pszName, cbData, &cbWritten);
  1018. if (FAILED(hr))
  1019. {
  1020. goto exit;
  1021. }
  1022. Assert(cbWritten == cbData);
  1023. }
  1024. // Write out the enabled state
  1025. dwData = !(m_dwState & RULE_STATE_DISABLED);
  1026. hr = pStm->Write(&dwData, sizeof(dwData), &cbWritten);
  1027. if (FAILED(hr))
  1028. {
  1029. goto exit;
  1030. }
  1031. Assert(cbWritten == sizeof(dwData));
  1032. // Get the persistance interface for the criteria
  1033. hr = m_pICrit->QueryInterface(IID_IPersistStream, (void **) &pIPStm);
  1034. if (FAILED(hr))
  1035. {
  1036. goto exit;
  1037. }
  1038. // Write out the criteria
  1039. hr = pIPStm->Save(pStm, fClearDirty);
  1040. if (FAILED(hr))
  1041. {
  1042. goto exit;
  1043. }
  1044. // Get the persistance interface for the actions
  1045. pIPStm->Release();
  1046. pIPStm = NULL;
  1047. hr = m_pIAct->QueryInterface(IID_IPersistStream, (void **) &pIPStm);
  1048. if (FAILED(hr))
  1049. {
  1050. goto exit;
  1051. }
  1052. // Write out the actions
  1053. hr = pIPStm->Save(pStm, fClearDirty);
  1054. if (FAILED(hr))
  1055. {
  1056. goto exit;
  1057. }
  1058. // Should we clear out the dirty bit
  1059. if (FALSE != fClearDirty)
  1060. {
  1061. m_dwState &= ~RULE_STATE_DIRTY;
  1062. }
  1063. // Set the return value
  1064. hr = S_OK;
  1065. exit:
  1066. SafeRelease(pIPStm);
  1067. return hr;
  1068. }