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.

3044 lines
74 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // RulesMgr.cpp
  4. //
  5. ///////////////////////////////////////////////////////////////////////////////
  6. #include <pch.hxx>
  7. #include "rulesmgr.h"
  8. #include "ruleutil.h"
  9. #include "rule.h"
  10. #include "junkrule.h"
  11. #include <msgfldr.h>
  12. #include <goptions.h>
  13. #include <instance.h>
  14. #include "demand.h"
  15. CRulesManager::CRulesManager() : m_cRef(0), m_dwState(STATE_LOADED_INIT),
  16. m_pMailHead(NULL), m_pNewsHead(NULL), m_pFilterHead(NULL),
  17. m_pIRuleSenderMail(NULL),m_pIRuleSenderNews(NULL),
  18. m_pIRuleJunk(NULL)
  19. {
  20. // Thread Safety
  21. InitializeCriticalSection(&m_cs);
  22. }
  23. CRulesManager::~CRulesManager()
  24. {
  25. AssertSz(m_cRef == 0, "Somebody still has a hold of us!!");
  26. if (NULL != m_pMailHead)
  27. {
  28. _HrFreeRules(RULE_TYPE_MAIL);
  29. }
  30. if (NULL != m_pNewsHead)
  31. {
  32. _HrFreeRules(RULE_TYPE_NEWS);
  33. }
  34. if (NULL != m_pFilterHead)
  35. {
  36. _HrFreeRules(RULE_TYPE_FILTER);
  37. }
  38. SafeRelease(m_pIRuleSenderMail);
  39. SafeRelease(m_pIRuleSenderNews);
  40. SafeRelease(m_pIRuleJunk);
  41. // Thread Safety
  42. DeleteCriticalSection(&m_cs);
  43. }
  44. STDMETHODIMP_(ULONG) CRulesManager::AddRef()
  45. {
  46. return ::InterlockedIncrement(&m_cRef);
  47. }
  48. STDMETHODIMP_(ULONG) CRulesManager::Release()
  49. {
  50. LONG cRef = 0;
  51. cRef = ::InterlockedDecrement(&m_cRef);
  52. if (0 == cRef)
  53. {
  54. delete this;
  55. return cRef;
  56. }
  57. return cRef;
  58. }
  59. STDMETHODIMP CRulesManager::QueryInterface(REFIID riid, void ** ppvObject)
  60. {
  61. HRESULT hr = S_OK;
  62. // Check the incoming params
  63. if (NULL == ppvObject)
  64. {
  65. hr = E_INVALIDARG;
  66. goto exit;
  67. }
  68. // Initialize outgoing param
  69. *ppvObject = NULL;
  70. if ((riid == IID_IUnknown) || (riid == IID_IOERulesManager))
  71. {
  72. *ppvObject = static_cast<IOERulesManager *>(this);
  73. }
  74. else
  75. {
  76. hr = E_NOINTERFACE;
  77. goto exit;
  78. }
  79. reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();
  80. hr = S_OK;
  81. exit:
  82. return hr;
  83. }
  84. STDMETHODIMP CRulesManager::Initialize(DWORD dwFlags)
  85. {
  86. HRESULT hr = S_OK;
  87. // Check the incoming params
  88. if (0 != dwFlags)
  89. {
  90. hr = E_INVALIDARG;
  91. goto exit;
  92. }
  93. // Set the proper return value
  94. hr = S_OK;
  95. exit:
  96. return hr;
  97. }
  98. STDMETHODIMP CRulesManager::GetRule(RULEID ridRule, RULE_TYPE type, DWORD dwFlags, IOERule ** ppIRule)
  99. {
  100. HRESULT hr = S_OK;
  101. RULENODE * pNodeWalk = NULL;
  102. IOERule * pIRule = NULL;
  103. // Thread Safety
  104. EnterCriticalSection(&m_cs);
  105. // Check the incoming params
  106. if (RULEID_INVALID == ridRule)
  107. {
  108. hr = E_INVALIDARG;
  109. goto exit;
  110. }
  111. // Initialize the ougoing params
  112. if (NULL != ppIRule)
  113. {
  114. *ppIRule = NULL;
  115. }
  116. // Check to see if we already loaded the rules
  117. hr = _HrLoadRules(type);
  118. if (FAILED(hr))
  119. {
  120. goto exit;
  121. }
  122. // Check the special types
  123. if (RULEID_SENDERS == ridRule)
  124. {
  125. if (RULE_TYPE_MAIL == type)
  126. {
  127. pIRule = m_pIRuleSenderMail;
  128. }
  129. else if (RULE_TYPE_NEWS == type)
  130. {
  131. pIRule = m_pIRuleSenderNews;
  132. }
  133. else
  134. {
  135. hr = E_INVALIDARG;
  136. goto exit;
  137. }
  138. }
  139. else if (RULEID_JUNK == ridRule)
  140. {
  141. if (RULE_TYPE_MAIL != type)
  142. {
  143. hr = E_INVALIDARG;
  144. goto exit;
  145. }
  146. pIRule = m_pIRuleJunk;
  147. }
  148. else
  149. {
  150. // Walk the proper list
  151. if (RULE_TYPE_MAIL == type)
  152. {
  153. pNodeWalk = m_pMailHead;
  154. }
  155. else if (RULE_TYPE_NEWS == type)
  156. {
  157. pNodeWalk = m_pNewsHead;
  158. }
  159. else if (RULE_TYPE_FILTER == type)
  160. {
  161. pNodeWalk = m_pFilterHead;
  162. }
  163. else
  164. {
  165. hr = E_INVALIDARG;
  166. goto exit;
  167. }
  168. for (; NULL != pNodeWalk; pNodeWalk = pNodeWalk->pNext)
  169. {
  170. if (ridRule == pNodeWalk->ridRule)
  171. {
  172. pIRule = pNodeWalk->pIRule;
  173. break;
  174. }
  175. }
  176. }
  177. // Did we find something?
  178. if (NULL == pIRule)
  179. {
  180. hr = E_FAIL;
  181. goto exit;
  182. }
  183. // Set the outgoing param
  184. if (NULL != ppIRule)
  185. {
  186. *ppIRule = pIRule;
  187. (*ppIRule)->AddRef();
  188. }
  189. // Set the proper return value
  190. hr = S_OK;
  191. exit:
  192. // Thread Safety
  193. LeaveCriticalSection(&m_cs);
  194. return hr;
  195. }
  196. STDMETHODIMP CRulesManager::FindRule(LPCSTR pszRuleName, RULE_TYPE type, IOERule ** ppIRule)
  197. {
  198. HRESULT hr = S_OK;
  199. RULENODE * pNodeWalk = NULL;
  200. PROPVARIANT propvar;
  201. ZeroMemory(&propvar, sizeof(propvar));
  202. // Thread Safety
  203. EnterCriticalSection(&m_cs);
  204. // Check the incoming params
  205. if ((NULL == pszRuleName) || (NULL == ppIRule))
  206. {
  207. hr = E_INVALIDARG;
  208. goto exit;
  209. }
  210. // Initialize the ougoing params
  211. *ppIRule = NULL;
  212. // Check to see if we already loaded the rules
  213. hr = _HrLoadRules(type);
  214. if (FAILED(hr))
  215. {
  216. goto exit;
  217. }
  218. // Walk the proper list
  219. if (RULE_TYPE_MAIL == type)
  220. {
  221. pNodeWalk = m_pMailHead;
  222. }
  223. else if (RULE_TYPE_NEWS == type)
  224. {
  225. pNodeWalk = m_pNewsHead;
  226. }
  227. else if (RULE_TYPE_FILTER == type)
  228. {
  229. pNodeWalk = m_pFilterHead;
  230. }
  231. else
  232. {
  233. hr = E_INVALIDARG;
  234. goto exit;
  235. }
  236. while (NULL != pNodeWalk)
  237. {
  238. // Check to see if the name of the rule is the same
  239. hr = pNodeWalk->pIRule->GetProp(RULE_PROP_NAME , 0, &propvar);
  240. if (FAILED(hr))
  241. {
  242. continue;
  243. }
  244. if (0 == lstrcmpi(propvar.pszVal, pszRuleName))
  245. {
  246. *ppIRule = pNodeWalk->pIRule;
  247. (*ppIRule)->AddRef();
  248. break;
  249. }
  250. // Move to the next one
  251. PropVariantClear(&propvar);
  252. pNodeWalk = pNodeWalk->pNext;
  253. }
  254. // Set the proper return value
  255. if (NULL == pNodeWalk)
  256. {
  257. hr = E_FAIL;
  258. }
  259. else
  260. {
  261. hr = S_OK;
  262. }
  263. exit:
  264. PropVariantClear(&propvar);
  265. // Thread Safety
  266. LeaveCriticalSection(&m_cs);
  267. return hr;
  268. }
  269. STDMETHODIMP CRulesManager::GetRules(DWORD dwFlags, RULE_TYPE typeRule, RULEINFO ** ppinfoRule, ULONG * pcpinfoRule)
  270. {
  271. HRESULT hr = S_OK;
  272. ULONG cpinfoRule = 0;
  273. RULEINFO * pinfoRuleAlloc = NULL;
  274. IOERule * pIRuleSender = NULL;
  275. RULENODE * prnodeList = NULL;
  276. RULENODE * prnodeWalk = NULL;
  277. ULONG ulIndex = 0;
  278. // Thread Safety
  279. EnterCriticalSection(&m_cs);
  280. // Check the incoming params
  281. if (NULL == ppinfoRule)
  282. {
  283. hr = E_INVALIDARG;
  284. goto exit;
  285. }
  286. // Initialize the outgoing param
  287. *ppinfoRule = NULL;
  288. if (NULL != pcpinfoRule)
  289. {
  290. *pcpinfoRule = 0;
  291. }
  292. // Check to see if we already loaded the rules
  293. hr = _HrLoadRules(typeRule);
  294. if (FAILED(hr))
  295. {
  296. goto exit;
  297. }
  298. // Figure out which type of rules to work on
  299. switch (typeRule)
  300. {
  301. case RULE_TYPE_MAIL:
  302. prnodeList = m_pMailHead;
  303. break;
  304. case RULE_TYPE_NEWS:
  305. prnodeList = m_pNewsHead;
  306. break;
  307. case RULE_TYPE_FILTER:
  308. prnodeList = m_pFilterHead;
  309. break;
  310. default:
  311. hr = E_INVALIDARG;
  312. goto exit;
  313. }
  314. // Count the number of rules
  315. prnodeWalk = prnodeList;
  316. for (cpinfoRule = 0; NULL != prnodeWalk; prnodeWalk = prnodeWalk->pNext)
  317. {
  318. // Check to see if we should add this item
  319. if (RULE_TYPE_FILTER == typeRule)
  320. {
  321. if (0 != (dwFlags & GETF_POP3))
  322. {
  323. if (RULEID_VIEW_DOWNLOADED == prnodeWalk->ridRule)
  324. {
  325. continue;
  326. }
  327. }
  328. }
  329. cpinfoRule++;
  330. }
  331. // Allocate space to hold the rules
  332. if (0 != cpinfoRule)
  333. {
  334. hr = HrAlloc((VOID **) &pinfoRuleAlloc, cpinfoRule * sizeof(*pinfoRuleAlloc));
  335. if (FAILED(hr))
  336. {
  337. goto exit;
  338. }
  339. // Initialize it to known values
  340. ZeroMemory(pinfoRuleAlloc, cpinfoRule * sizeof(*pinfoRuleAlloc));
  341. // Fill up the info
  342. for (ulIndex = 0, prnodeWalk = prnodeList; NULL != prnodeWalk; prnodeWalk = prnodeWalk->pNext)
  343. {
  344. // Check to see if we should add this item
  345. if (RULE_TYPE_FILTER == typeRule)
  346. {
  347. if (0 != (dwFlags & GETF_POP3))
  348. {
  349. if (RULEID_VIEW_DOWNLOADED == prnodeWalk->ridRule)
  350. {
  351. continue;
  352. }
  353. }
  354. }
  355. pinfoRuleAlloc[ulIndex].ridRule = prnodeWalk->ridRule;
  356. pinfoRuleAlloc[ulIndex].pIRule = prnodeWalk->pIRule;
  357. pinfoRuleAlloc[ulIndex].pIRule->AddRef();
  358. ulIndex++;
  359. }
  360. }
  361. // Set the outgoing values
  362. *ppinfoRule = pinfoRuleAlloc;
  363. pinfoRuleAlloc = NULL;
  364. if (NULL != pcpinfoRule)
  365. {
  366. *pcpinfoRule = cpinfoRule;
  367. }
  368. // Set the proper return type
  369. hr = S_OK;
  370. exit:
  371. SafeMemFree(pinfoRuleAlloc);
  372. // Thread Safety
  373. LeaveCriticalSection(&m_cs);
  374. return S_OK;
  375. }
  376. STDMETHODIMP CRulesManager::SetRules(DWORD dwFlags, RULE_TYPE typeRule, RULEINFO * pinfoRule, ULONG cpinfoRule)
  377. {
  378. HRESULT hr = S_OK;
  379. ULONG ulIndex = 0;
  380. IOERule * pIRuleSender = NULL;
  381. // Thread Safety
  382. EnterCriticalSection(&m_cs);
  383. // Check the incoming params
  384. if ((NULL == pinfoRule) && (0 != cpinfoRule))
  385. {
  386. hr = E_INVALIDARG;
  387. goto exit;
  388. }
  389. // Check to see if we already loaded the rules
  390. hr = _HrLoadRules(typeRule);
  391. if (FAILED(hr))
  392. {
  393. goto exit;
  394. }
  395. // Do we have to free all the current rules
  396. if (0 != (dwFlags & SETF_SENDER))
  397. {
  398. if (RULE_TYPE_MAIL == typeRule)
  399. {
  400. SafeRelease(m_pIRuleSenderMail);
  401. m_pIRuleSenderMail = pinfoRule->pIRule;
  402. if (NULL != m_pIRuleSenderMail)
  403. {
  404. m_pIRuleSenderMail->AddRef();
  405. }
  406. }
  407. else if (RULE_TYPE_NEWS == typeRule)
  408. {
  409. SafeRelease(m_pIRuleSenderNews);
  410. m_pIRuleSenderNews = pinfoRule->pIRule;
  411. if (NULL != m_pIRuleSenderNews)
  412. {
  413. m_pIRuleSenderNews->AddRef();
  414. }
  415. }
  416. else
  417. {
  418. hr = E_INVALIDARG;
  419. goto exit;
  420. }
  421. }
  422. else if (0 != (dwFlags & SETF_JUNK))
  423. {
  424. if (RULE_TYPE_MAIL != typeRule)
  425. {
  426. hr = E_INVALIDARG;
  427. goto exit;
  428. }
  429. SafeRelease(m_pIRuleJunk);
  430. m_pIRuleJunk = pinfoRule->pIRule;
  431. if (NULL != m_pIRuleJunk)
  432. {
  433. m_pIRuleJunk->AddRef();
  434. }
  435. }
  436. else
  437. {
  438. if (0 != (dwFlags & SETF_CLEAR))
  439. {
  440. _HrFreeRules(typeRule);
  441. }
  442. // for each new rule
  443. for (ulIndex = 0; ulIndex < cpinfoRule; ulIndex++)
  444. {
  445. if (0 != (dwFlags & SETF_REPLACE))
  446. {
  447. // Add the rule to the list
  448. hr = _HrReplaceRule(pinfoRule[ulIndex].ridRule, pinfoRule[ulIndex].pIRule, typeRule);
  449. if (FAILED(hr))
  450. {
  451. goto exit;
  452. }
  453. }
  454. else
  455. {
  456. // Add the rule to the list
  457. hr = _HrAddRule(pinfoRule[ulIndex].ridRule, pinfoRule[ulIndex].pIRule, typeRule);
  458. if (FAILED(hr))
  459. {
  460. goto exit;
  461. }
  462. }
  463. }
  464. }
  465. // Save the rules
  466. hr = _HrSaveRules(typeRule);
  467. if (FAILED(hr))
  468. {
  469. goto exit;
  470. }
  471. if ((0 == (dwFlags & SETF_SENDER)) && (0 == (dwFlags & SETF_JUNK)))
  472. {
  473. // Fix up the rule ids
  474. hr = _HrFixupRuleInfo(typeRule, pinfoRule, cpinfoRule);
  475. if (FAILED(hr))
  476. {
  477. goto exit;
  478. }
  479. }
  480. // Set the proper return value
  481. hr = S_OK;
  482. exit:
  483. // Thread Safety
  484. LeaveCriticalSection(&m_cs);
  485. return hr;
  486. }
  487. STDMETHODIMP CRulesManager::EnumRules(DWORD dwFlags, RULE_TYPE type, IOEEnumRules ** ppIEnumRules)
  488. {
  489. HRESULT hr = S_OK;
  490. CEnumRules * pEnumRules = NULL;
  491. RULENODE rnode;
  492. RULENODE * prnode = NULL;
  493. IOERule * pIRuleSender = NULL;
  494. // Thread Safety
  495. EnterCriticalSection(&m_cs);
  496. // Check the incoming params
  497. if (NULL == ppIEnumRules)
  498. {
  499. hr = E_INVALIDARG;
  500. goto exit;
  501. }
  502. // Initialize outgoing params
  503. *ppIEnumRules = NULL;
  504. // Check to see if we already loaded the rules
  505. hr = _HrLoadRules(type);
  506. if (FAILED(hr))
  507. {
  508. goto exit;
  509. }
  510. // Create the rules enumerator object
  511. pEnumRules = new CEnumRules;
  512. if (NULL == pEnumRules)
  513. {
  514. hr = E_OUTOFMEMORY;
  515. goto exit;
  516. }
  517. // Initialize the rules enumerator
  518. if (0 != (dwFlags & ENUMF_SENDER))
  519. {
  520. if (RULE_TYPE_MAIL == type)
  521. {
  522. pIRuleSender = m_pIRuleSenderMail;
  523. }
  524. else if (RULE_TYPE_NEWS == type)
  525. {
  526. pIRuleSender = m_pIRuleSenderNews;
  527. }
  528. else
  529. {
  530. hr = E_INVALIDARG;
  531. goto exit;
  532. }
  533. if (NULL != pIRuleSender)
  534. {
  535. ZeroMemory(&rnode, sizeof(rnode));
  536. rnode.pIRule = pIRuleSender;
  537. prnode = &rnode;
  538. }
  539. else
  540. {
  541. prnode = NULL;
  542. }
  543. }
  544. else
  545. {
  546. if (RULE_TYPE_MAIL == type)
  547. {
  548. prnode = m_pMailHead;
  549. }
  550. else if (RULE_TYPE_NEWS == type)
  551. {
  552. prnode = m_pNewsHead;
  553. }
  554. else if (RULE_TYPE_FILTER == type)
  555. {
  556. prnode = m_pFilterHead;
  557. }
  558. else
  559. {
  560. hr = E_INVALIDARG;
  561. goto exit;
  562. }
  563. }
  564. hr = pEnumRules->_HrInitialize(0, type, prnode);
  565. if (FAILED(hr))
  566. {
  567. goto exit;
  568. }
  569. // Get the rules enumerator interface
  570. hr = pEnumRules->QueryInterface(IID_IOEEnumRules, (void **) ppIEnumRules);
  571. if (FAILED(hr))
  572. {
  573. goto exit;
  574. }
  575. pEnumRules = NULL;
  576. hr = S_OK;
  577. exit:
  578. if (NULL != pEnumRules)
  579. {
  580. delete pEnumRules;
  581. }
  582. // Thread Safety
  583. LeaveCriticalSection(&m_cs);
  584. return hr;
  585. }
  586. STDMETHODIMP CRulesManager::ExecRules(DWORD dwFlags, RULE_TYPE type, IOEExecRules ** ppIExecRules)
  587. {
  588. HRESULT hr = S_OK;
  589. CExecRules * pExecRules = NULL;
  590. RULENODE rnode;
  591. RULENODE * prnodeList = NULL;
  592. // Thread Safety
  593. EnterCriticalSection(&m_cs);
  594. // Check the incoming params
  595. if (NULL == ppIExecRules)
  596. {
  597. hr = E_INVALIDARG;
  598. goto exit;
  599. }
  600. // Initialize outgoing params
  601. *ppIExecRules = NULL;
  602. // Check to see if we already loaded the rules
  603. hr = _HrLoadRules(type);
  604. if (FAILED(hr))
  605. {
  606. goto exit;
  607. }
  608. // Create the rules enumerator object
  609. pExecRules = new CExecRules;
  610. if (NULL == pExecRules)
  611. {
  612. hr = E_OUTOFMEMORY;
  613. goto exit;
  614. }
  615. if (RULE_TYPE_MAIL == type)
  616. {
  617. prnodeList = m_pMailHead;
  618. }
  619. else if (RULE_TYPE_NEWS == type)
  620. {
  621. prnodeList = m_pNewsHead;
  622. }
  623. else
  624. {
  625. hr = E_INVALIDARG;
  626. goto exit;
  627. }
  628. // Initialize the rules enumerator
  629. hr = pExecRules->_HrInitialize(ERF_ONLY_ENABLED | ERF_ONLY_VALID, prnodeList);
  630. if (FAILED(hr))
  631. {
  632. goto exit;
  633. }
  634. // Get the rules enumerator interface
  635. hr = pExecRules->QueryInterface(IID_IOEExecRules, (void **) ppIExecRules);
  636. if (FAILED(hr))
  637. {
  638. goto exit;
  639. }
  640. pExecRules = NULL;
  641. hr = S_OK;
  642. exit:
  643. if (NULL != pExecRules)
  644. {
  645. delete pExecRules;
  646. }
  647. // Thread Safety
  648. LeaveCriticalSection(&m_cs);
  649. return hr;
  650. }
  651. STDMETHODIMP CRulesManager::ExecuteRules(RULE_TYPE typeRule, DWORD dwFlags, HWND hwndUI, IOEExecRules * pIExecRules,
  652. MESSAGEINFO * pMsgInfo, IMessageFolder * pFolder, IMimeMessage * pIMMsg)
  653. {
  654. HRESULT hr = S_OK;
  655. ULONG ulIndex = 0;
  656. RULENODE * prnodeHead = NULL;
  657. PROPVARIANT propvar = {0};
  658. ACT_ITEM * pActions = NULL;
  659. ULONG cActions = 0;
  660. ACT_ITEM * pActionsList = NULL;
  661. ULONG cActionsList = 0;
  662. ACT_ITEM * pActionsNew = NULL;
  663. ULONG cActionsNew = 0;
  664. BOOL fStopProcessing = FALSE;
  665. BOOL fMatch = FALSE;
  666. // Thread Safety
  667. EnterCriticalSection(&m_cs);
  668. // Check incoming params
  669. if ((NULL == pIExecRules) || (NULL == pMsgInfo))
  670. {
  671. hr = E_INVALIDARG;
  672. goto exit;
  673. }
  674. // Check to see if we already loaded the rules
  675. hr = _HrLoadRules(typeRule);
  676. if (FAILED(hr))
  677. {
  678. goto exit;
  679. }
  680. // Figure out which list to use
  681. switch (typeRule)
  682. {
  683. case RULE_TYPE_MAIL:
  684. prnodeHead = m_pMailHead;
  685. break;
  686. case RULE_TYPE_NEWS:
  687. prnodeHead = m_pNewsHead;
  688. break;
  689. default:
  690. Assert(FALSE);
  691. hr = E_INVALIDARG;
  692. goto exit;
  693. }
  694. // For each rule
  695. for (; NULL != prnodeHead; prnodeHead = prnodeHead->pNext)
  696. {
  697. // Skip if we don't have a rule
  698. if (NULL == prnodeHead)
  699. {
  700. continue;
  701. }
  702. // Skip if it isn't enabled
  703. hr = prnodeHead->pIRule->GetProp(RULE_PROP_DISABLED, 0, &propvar);
  704. Assert(VT_BOOL == propvar.vt);
  705. if (FAILED(hr) || (FALSE != propvar.boolVal))
  706. {
  707. continue;
  708. }
  709. // Execute rule
  710. hr = prnodeHead->pIRule->Evaluate(pMsgInfo->pszAcctId, pMsgInfo, pFolder,
  711. NULL, pIMMsg, pMsgInfo->cbMessage, &pActions, &cActions);
  712. if (FAILED(hr))
  713. {
  714. goto exit;
  715. }
  716. // Did we have a match
  717. if (S_OK == hr)
  718. {
  719. // We've matched at least once
  720. fMatch = TRUE;
  721. // If these are server actions
  722. if ((1 == cActions) && ((ACT_TYPE_DELETESERVER == pActions[ulIndex].type) ||
  723. (ACT_TYPE_DONTDOWNLOAD == pActions[ulIndex].type)))
  724. {
  725. // If this is our only action
  726. if (0 == cActionsList)
  727. {
  728. // Save the action
  729. pActionsList = pActions;
  730. pActions = NULL;
  731. cActionsList = cActions;
  732. // We are done
  733. fStopProcessing = TRUE;
  734. }
  735. else
  736. {
  737. // We already have to do something with it
  738. // so skip over this action
  739. RuleUtil_HrFreeActionsItem(pActions, cActions);
  740. SafeMemFree(pActions);
  741. continue;
  742. }
  743. }
  744. else
  745. {
  746. // Should we stop after merging these?
  747. for (ulIndex = 0; ulIndex < cActions; ulIndex++)
  748. {
  749. if (ACT_TYPE_STOP == pActions[ulIndex].type)
  750. {
  751. fStopProcessing = TRUE;
  752. break;
  753. }
  754. }
  755. // Merge these items with the previous ones
  756. hr = RuleUtil_HrMergeActions(pActionsList, cActionsList, pActions, cActions, &pActionsNew, &cActionsNew);
  757. if (FAILED(hr))
  758. {
  759. goto exit;
  760. }
  761. // Free up the previous ones
  762. RuleUtil_HrFreeActionsItem(pActionsList, cActionsList);
  763. SafeMemFree(pActionsList);
  764. RuleUtil_HrFreeActionsItem(pActions, cActions);
  765. SafeMemFree(pActions);
  766. // Save off the new ones
  767. pActionsList = pActionsNew;
  768. pActionsNew = NULL;
  769. cActionsList = cActionsNew;
  770. }
  771. // Should we continue...
  772. if (FALSE != fStopProcessing)
  773. {
  774. break;
  775. }
  776. }
  777. }
  778. // Apply the actions if need be
  779. if ((FALSE != fMatch) && (NULL != pActionsList) && (0 != cActionsList))
  780. {
  781. if (FAILED(RuleUtil_HrApplyActions(hwndUI, pIExecRules, pMsgInfo, pFolder, pIMMsg,
  782. (RULE_TYPE_MAIL != typeRule) ? DELETE_MESSAGE_NOTRASHCAN : 0, pActionsList, cActionsList, NULL, NULL)))
  783. {
  784. hr = E_FAIL;
  785. goto exit;
  786. }
  787. }
  788. // Set the return value
  789. hr = (FALSE != fMatch) ? S_OK : S_FALSE;
  790. exit:
  791. // Thread Safety
  792. RuleUtil_HrFreeActionsItem(pActionsNew, cActionsNew);
  793. SafeMemFree(pActionsNew);
  794. RuleUtil_HrFreeActionsItem(pActions, cActions);
  795. SafeMemFree(pActions);
  796. RuleUtil_HrFreeActionsItem(pActionsList, cActionsList);
  797. SafeMemFree(pActionsList);
  798. LeaveCriticalSection(&m_cs);
  799. return hr;
  800. }
  801. HRESULT CRulesManager::_HrLoadRules(RULE_TYPE type)
  802. {
  803. HRESULT hr = S_OK;
  804. LPCSTR pszSubKey = NULL;
  805. LPSTR pszOrderAlloc = NULL;
  806. LPSTR pszOrder = NULL;
  807. LPSTR pszWalk = NULL;
  808. HKEY hkeyRoot = NULL;
  809. DWORD dwDisp = 0;
  810. LONG lErr = 0;
  811. ULONG cbData = 0;
  812. IOERule * pIRule = NULL;
  813. DWORD dwData = 0;
  814. CHAR rgchRulePath[MAX_PATH];
  815. ULONG cchRulePath = 0;
  816. PROPVARIANT propvar = {0};
  817. RULEID ridRule = RULEID_INVALID;
  818. CHAR rgchTagBuff[CCH_INDEX_MAX + 2];
  819. // Check to see if we're already initialized
  820. if (RULE_TYPE_MAIL == type)
  821. {
  822. if (0 != (m_dwState & STATE_LOADED_MAIL))
  823. {
  824. hr = S_FALSE;
  825. goto exit;
  826. }
  827. // Make sure we loaded the sender rules
  828. _HrLoadSenders();
  829. // Make sure we loaded the junk rule
  830. if (0 != (g_dwAthenaMode & MODE_JUNKMAIL))
  831. {
  832. _HrLoadJunk();
  833. }
  834. // Set the key path
  835. pszSubKey = c_szRulesMail;
  836. }
  837. else if (RULE_TYPE_NEWS == type)
  838. {
  839. if (0 != (m_dwState & STATE_LOADED_NEWS))
  840. {
  841. hr = S_FALSE;
  842. goto exit;
  843. }
  844. // Make sure we loaded the sender rules
  845. _HrLoadSenders();
  846. // Set the key path
  847. pszSubKey = c_szRulesNews;
  848. }
  849. else if (RULE_TYPE_FILTER == type)
  850. {
  851. if (0 != (m_dwState & STATE_LOADED_FILTERS))
  852. {
  853. hr = S_FALSE;
  854. goto exit;
  855. }
  856. // Set the key path
  857. pszSubKey = c_szRulesFilter;
  858. }
  859. else
  860. {
  861. hr = E_INVALIDARG;
  862. goto exit;
  863. }
  864. // Check to see if the Rule node already exists
  865. lErr = AthUserCreateKey(pszSubKey, KEY_ALL_ACCESS, &hkeyRoot, &dwDisp);
  866. if (ERROR_SUCCESS != lErr)
  867. {
  868. hr = HRESULT_FROM_WIN32(lErr);
  869. goto exit;
  870. }
  871. // Check the current version
  872. cbData = sizeof(dwData);
  873. lErr = RegQueryValueEx(hkeyRoot, c_szRulesVersion, NULL, NULL, (BYTE *) &dwData, &cbData);
  874. if (ERROR_SUCCESS != lErr)
  875. {
  876. // Push out the correct rules manager version
  877. dwData = RULESMGR_VERSION;
  878. lErr = RegSetValueEx(hkeyRoot, c_szRulesVersion, 0, REG_DWORD, (CONST BYTE *) &dwData, sizeof(dwData));
  879. if (ERROR_SUCCESS != lErr)
  880. {
  881. hr = HRESULT_FROM_WIN32(lErr);
  882. goto exit;
  883. }
  884. }
  885. Assert(RULESMGR_VERSION == dwData);
  886. // Create the default rules if needed
  887. hr = RuleUtil_HrUpdateDefaultRules(type);
  888. if (FAILED(hr))
  889. {
  890. goto exit;
  891. }
  892. // Figure out the size of the order
  893. lErr = AthUserGetValue(pszSubKey, c_szRulesOrder, NULL, NULL, &cbData);
  894. if ((ERROR_SUCCESS != lErr) && (ERROR_FILE_NOT_FOUND != lErr))
  895. {
  896. hr = E_FAIL;
  897. goto exit;
  898. }
  899. if (ERROR_FILE_NOT_FOUND != lErr)
  900. {
  901. // Allocate the space to hold the order
  902. hr = HrAlloc((void **) &pszOrderAlloc, cbData);
  903. if (FAILED(hr))
  904. {
  905. goto exit;
  906. }
  907. // Get the order from the registry
  908. lErr = AthUserGetValue(pszSubKey, c_szRulesOrder, NULL, (LPBYTE) pszOrderAlloc, &cbData);
  909. if (ERROR_SUCCESS != lErr)
  910. {
  911. hr = E_FAIL;
  912. goto exit;
  913. }
  914. // Build up the rule registry path
  915. StrCpyN(rgchRulePath, pszSubKey, ARRAYSIZE(rgchRulePath));
  916. StrCatBuff(rgchRulePath, g_szBackSlash, ARRAYSIZE(rgchRulePath));
  917. cchRulePath = lstrlen(rgchRulePath);
  918. // Initialize the rule tag buffer
  919. rgchTagBuff[0] = '0';
  920. rgchTagBuff[1] = 'X';
  921. // Parse the order string to create the rules
  922. pszOrder = pszOrderAlloc;
  923. while ('\0' != *pszOrder)
  924. {
  925. SafeRelease(pIRule);
  926. // Create a new rule
  927. hr = HrCreateRule(&pIRule);
  928. if (FAILED(hr))
  929. {
  930. goto exit;
  931. }
  932. // Find the name of the new rule
  933. pszWalk = StrStr(pszOrder, g_szSpace);
  934. if (NULL != pszWalk)
  935. {
  936. *pszWalk = '\0';
  937. pszWalk++;
  938. }
  939. // Build the path to the rule
  940. StrCpyN(rgchRulePath + cchRulePath, pszOrder, ARRAYSIZE(rgchRulePath) - cchRulePath);
  941. // Load the rule
  942. hr = pIRule->LoadReg(rgchRulePath);
  943. if (SUCCEEDED(hr))
  944. {
  945. // Build the correct hex string
  946. StrCpyN(rgchTagBuff + 2, pszOrder, ARRAYSIZE(rgchTagBuff) - 2);
  947. // Get the new rule handle
  948. ridRule = ( ( RULEID ) 0);
  949. SideAssert(FALSE != StrToIntEx(rgchTagBuff, STIF_SUPPORT_HEX, (INT *) &ridRule));
  950. // Add the new rule to the manager
  951. hr = _HrAddRule(ridRule, pIRule, type);
  952. if (FAILED(hr))
  953. {
  954. goto exit;
  955. }
  956. }
  957. // Move to the next item in the order
  958. if (NULL == pszWalk)
  959. {
  960. pszOrder += lstrlen(pszOrder);
  961. }
  962. else
  963. {
  964. pszOrder = pszWalk;
  965. }
  966. }
  967. }
  968. // We've loaded the rules successfully
  969. if (RULE_TYPE_MAIL == type)
  970. {
  971. m_dwState |= STATE_LOADED_MAIL;
  972. }
  973. else if (RULE_TYPE_NEWS == type)
  974. {
  975. m_dwState |= STATE_LOADED_NEWS;
  976. }
  977. else
  978. {
  979. m_dwState |= STATE_LOADED_FILTERS;
  980. }
  981. // Set the return value
  982. hr = S_OK;
  983. exit:
  984. SafeMemFree(pszOrderAlloc);
  985. SafeRelease(pIRule);
  986. if (NULL != hkeyRoot)
  987. {
  988. RegCloseKey(hkeyRoot);
  989. }
  990. return hr;
  991. }
  992. HRESULT CRulesManager::_HrLoadSenders(VOID)
  993. {
  994. HRESULT hr = S_OK;
  995. HKEY hkeyRoot = NULL;
  996. DWORD dwDisp = 0;
  997. DWORD dwData = 0;
  998. LONG lErr = 0;
  999. ULONG cbData = 0;
  1000. IOERule * pIRule = NULL;
  1001. CHAR rgchSenderPath[MAX_PATH];
  1002. // Do we have anything to do?
  1003. if (0 != (m_dwState & STATE_LOADED_SENDERS))
  1004. {
  1005. hr = S_FALSE;
  1006. goto exit;
  1007. }
  1008. // Let's get access to the sender root key
  1009. lErr = AthUserCreateKey(c_szSenders, KEY_ALL_ACCESS, &hkeyRoot, &dwDisp);
  1010. if (ERROR_SUCCESS != lErr)
  1011. {
  1012. hr = E_FAIL;
  1013. goto exit;
  1014. }
  1015. // Are the senders the correct version?
  1016. cbData = sizeof(dwData);
  1017. lErr = RegQueryValueEx(hkeyRoot, c_szSendersVersion, 0, NULL, (BYTE *) &dwData, &cbData);
  1018. if ((ERROR_SUCCESS != lErr) && (ERROR_FILE_NOT_FOUND != lErr))
  1019. {
  1020. hr = E_FAIL;
  1021. goto exit;
  1022. }
  1023. if (ERROR_FILE_NOT_FOUND == lErr)
  1024. {
  1025. dwData = RULESMGR_VERSION;
  1026. cbData = sizeof(dwData);
  1027. lErr = RegSetValueEx(hkeyRoot, c_szSendersVersion, 0, REG_DWORD, (BYTE *) &dwData, cbData);
  1028. if (ERROR_SUCCESS != lErr)
  1029. {
  1030. hr = E_FAIL;
  1031. goto exit;
  1032. }
  1033. }
  1034. Assert(dwData == RULESMGR_VERSION);
  1035. // Is there anything to do?
  1036. if (REG_CREATED_NEW_KEY != dwDisp)
  1037. {
  1038. // Create the path to the sender
  1039. StrCpyN(rgchSenderPath, c_szSenders, ARRAYSIZE(rgchSenderPath));
  1040. StrCatBuff(rgchSenderPath, g_szBackSlash, ARRAYSIZE(rgchSenderPath));
  1041. StrCatBuff(rgchSenderPath, c_szMailDir, ARRAYSIZE(rgchSenderPath));
  1042. // Create the mail sender rule
  1043. hr = RuleUtil_HrLoadSender(rgchSenderPath, 0, &pIRule);
  1044. if (FAILED(hr))
  1045. {
  1046. goto exit;
  1047. }
  1048. // Save the loaded rule
  1049. if (S_OK == hr)
  1050. {
  1051. m_pIRuleSenderMail = pIRule;
  1052. pIRule = NULL;
  1053. }
  1054. // Create the path to the sender
  1055. StrCpyN(rgchSenderPath, c_szSenders, ARRAYSIZE(rgchSenderPath));
  1056. StrCatBuff(rgchSenderPath, g_szBackSlash, ARRAYSIZE(rgchSenderPath));
  1057. StrCatBuff(rgchSenderPath, c_szNewsDir, ARRAYSIZE(rgchSenderPath));
  1058. // Create the news sender rule
  1059. hr = RuleUtil_HrLoadSender(rgchSenderPath, 0, &pIRule);
  1060. if (FAILED(hr))
  1061. {
  1062. goto exit;
  1063. }
  1064. // Save the loaded rule
  1065. if (S_OK == hr)
  1066. {
  1067. m_pIRuleSenderNews = pIRule;
  1068. pIRule = NULL;
  1069. }
  1070. }
  1071. // Note that we've loaded the senders
  1072. m_dwState |= STATE_LOADED_SENDERS;
  1073. // Set the return value
  1074. hr = S_OK;
  1075. exit:
  1076. SafeRelease(pIRule);
  1077. if (NULL != hkeyRoot)
  1078. {
  1079. RegCloseKey(hkeyRoot);
  1080. }
  1081. return hr;
  1082. }
  1083. HRESULT CRulesManager::_HrLoadJunk(VOID)
  1084. {
  1085. HRESULT hr = S_OK;
  1086. HKEY hkeyRoot = NULL;
  1087. DWORD dwDisp = 0;
  1088. DWORD dwData = 0;
  1089. ULONG cbData = 0;
  1090. LONG lErr = 0;
  1091. IOERule * pIRule = NULL;
  1092. // Do we have anything to do?
  1093. if (0 != (m_dwState & STATE_LOADED_JUNK))
  1094. {
  1095. hr = S_FALSE;
  1096. goto exit;
  1097. }
  1098. // Let's get access to the Junk mail root key
  1099. lErr = AthUserCreateKey(c_szRulesJunkMail, KEY_ALL_ACCESS, &hkeyRoot, &dwDisp);
  1100. if (ERROR_SUCCESS != lErr)
  1101. {
  1102. hr = E_FAIL;
  1103. goto exit;
  1104. }
  1105. // Is the junk mail the correct version?
  1106. cbData = sizeof(dwData);
  1107. lErr = RegQueryValueEx(hkeyRoot, c_szRulesVersion, 0, NULL, (BYTE *) &dwData, &cbData);
  1108. if ((ERROR_SUCCESS != lErr) && (ERROR_FILE_NOT_FOUND != lErr))
  1109. {
  1110. hr = E_FAIL;
  1111. goto exit;
  1112. }
  1113. if (ERROR_FILE_NOT_FOUND == lErr)
  1114. {
  1115. dwData = RULESMGR_VERSION;
  1116. cbData = sizeof(dwData);
  1117. lErr = RegSetValueEx(hkeyRoot, c_szRulesVersion, 0, REG_DWORD, (BYTE *) &dwData, cbData);
  1118. if (ERROR_SUCCESS != lErr)
  1119. {
  1120. hr = E_FAIL;
  1121. goto exit;
  1122. }
  1123. }
  1124. Assert(dwData == RULESMGR_VERSION);
  1125. // Create the rule
  1126. hr = HrCreateJunkRule(&pIRule);
  1127. if (FAILED(hr))
  1128. {
  1129. goto exit;
  1130. }
  1131. // Load the junk rule
  1132. hr = pIRule->LoadReg(c_szRulesJunkMail);
  1133. if (FAILED(hr))
  1134. {
  1135. goto exit;
  1136. }
  1137. m_pIRuleJunk = pIRule;
  1138. pIRule = NULL;
  1139. // Note that we've loaded the junk rule
  1140. m_dwState |= STATE_LOADED_JUNK;
  1141. // Set the return value
  1142. hr = S_OK;
  1143. exit:
  1144. SafeRelease(pIRule);
  1145. if (NULL != hkeyRoot)
  1146. {
  1147. RegCloseKey(hkeyRoot);
  1148. }
  1149. return hr;
  1150. }
  1151. HRESULT CRulesManager::_HrSaveRules(RULE_TYPE type)
  1152. {
  1153. HRESULT hr = S_OK;
  1154. LPCSTR pszRegPath = NULL;
  1155. DWORD dwData = 0;
  1156. LONG lErr = 0;
  1157. RULENODE * pRuleNode = NULL;
  1158. RULENODE * pNodeWalk = NULL;
  1159. ULONG cpIRule = 0;
  1160. LPSTR pszOrder = NULL;
  1161. HKEY hkeyRoot = NULL;
  1162. DWORD dwIndex = 0;
  1163. CHAR rgchOrder[CCH_INDEX_MAX];
  1164. ULONG cchOrder = 0;
  1165. CHAR rgchRulePath[MAX_PATH];
  1166. ULONG cchRulePath = 0;
  1167. BOOL fNewRule = FALSE;
  1168. ULONG ulRuleID = 0;
  1169. HKEY hkeyDummy = NULL;
  1170. LONG cSubKeys = 0;
  1171. // Make sure we loaded the sender rules
  1172. _HrSaveSenders();
  1173. // Make sure we loaded the junk rules
  1174. if (0 != (g_dwAthenaMode & MODE_JUNKMAIL))
  1175. {
  1176. _HrSaveJunk();
  1177. }
  1178. // Check to see if we have anything to save
  1179. if (RULE_TYPE_MAIL == type)
  1180. {
  1181. if (0 == (m_dwState & STATE_LOADED_MAIL))
  1182. {
  1183. hr = S_FALSE;
  1184. goto exit;
  1185. }
  1186. // Set the key path
  1187. pszRegPath = c_szRulesMail;
  1188. pRuleNode = m_pMailHead;
  1189. }
  1190. else if (RULE_TYPE_NEWS == type)
  1191. {
  1192. if (0 == (m_dwState & STATE_LOADED_NEWS))
  1193. {
  1194. hr = S_FALSE;
  1195. goto exit;
  1196. }
  1197. // Set the key path
  1198. pszRegPath = c_szRulesNews;
  1199. pRuleNode = m_pNewsHead;
  1200. }
  1201. else if (RULE_TYPE_FILTER == type)
  1202. {
  1203. if (0 == (m_dwState & STATE_LOADED_FILTERS))
  1204. {
  1205. hr = S_FALSE;
  1206. goto exit;
  1207. }
  1208. // Set the key path
  1209. pszRegPath = c_szRulesFilter;
  1210. pRuleNode = m_pFilterHead;
  1211. }
  1212. else
  1213. {
  1214. hr = E_INVALIDARG;
  1215. goto exit;
  1216. }
  1217. lErr = AthUserCreateKey(pszRegPath, KEY_ALL_ACCESS, &hkeyRoot, &dwData);
  1218. if (ERROR_SUCCESS != lErr)
  1219. {
  1220. hr = E_FAIL;
  1221. goto exit;
  1222. }
  1223. // Save out the rules version
  1224. dwData = RULESMGR_VERSION;
  1225. lErr = RegSetValueEx(hkeyRoot, c_szRulesVersion, 0, REG_DWORD, (CONST BYTE *) &dwData, sizeof(dwData));
  1226. if (ERROR_SUCCESS != lErr)
  1227. {
  1228. hr = E_FAIL;
  1229. goto exit;
  1230. }
  1231. // Get the number of rules
  1232. cpIRule = 0;
  1233. for (pNodeWalk = pRuleNode; NULL != pNodeWalk; pNodeWalk = pNodeWalk->pNext)
  1234. {
  1235. cpIRule++;
  1236. }
  1237. // Allocate space to hold the order
  1238. DWORD cchSize = ((cpIRule * CCH_INDEX_MAX) + 1);
  1239. hr = HrAlloc((void **) &pszOrder, cchSize);
  1240. if (FAILED(hr))
  1241. {
  1242. goto exit;
  1243. }
  1244. pszOrder[0] = '\0';
  1245. // Delete all the old rules
  1246. lErr = SHQueryInfoKey(hkeyRoot, (LPDWORD) (&cSubKeys), NULL, NULL, NULL);
  1247. if (ERROR_SUCCESS != lErr)
  1248. {
  1249. hr = E_FAIL;
  1250. goto exit;
  1251. }
  1252. // Delete all the old rules
  1253. for (cSubKeys--; cSubKeys >= 0; cSubKeys--)
  1254. {
  1255. cchOrder = sizeof(rgchOrder);
  1256. lErr = SHEnumKeyEx(hkeyRoot, cSubKeys, rgchOrder, &cchOrder);
  1257. if (ERROR_NO_MORE_ITEMS == lErr)
  1258. {
  1259. break;
  1260. }
  1261. if (ERROR_SUCCESS != lErr)
  1262. {
  1263. continue;
  1264. }
  1265. SHDeleteKey(hkeyRoot, rgchOrder);
  1266. }
  1267. // Delete the old order string
  1268. RegDeleteValue(hkeyRoot, c_szRulesOrder);
  1269. // Build up the rule registry path
  1270. StrCpyN(rgchRulePath, pszRegPath, ARRAYSIZE(rgchRulePath));
  1271. StrCatBuff(rgchRulePath, g_szBackSlash, ARRAYSIZE(rgchRulePath));
  1272. cchRulePath = lstrlen(rgchRulePath);
  1273. // Write out the rules with good tags
  1274. for (dwIndex = 0, pNodeWalk = pRuleNode; NULL != pNodeWalk; pNodeWalk = pNodeWalk->pNext, dwIndex++)
  1275. {
  1276. if (RULEID_INVALID == pNodeWalk->ridRule)
  1277. {
  1278. fNewRule = TRUE;
  1279. continue;
  1280. }
  1281. // Get a new index from the order
  1282. wnsprintf(rgchOrder, ARRAYSIZE(rgchOrder), "%03X", pNodeWalk->ridRule);
  1283. // Build the path to the rule
  1284. StrCpyN(rgchRulePath + cchRulePath, rgchOrder, ARRAYSIZE(rgchRulePath) - cchRulePath);
  1285. // Save the rule
  1286. hr = pNodeWalk->pIRule->SaveReg(rgchRulePath, TRUE);
  1287. if (FAILED(hr))
  1288. {
  1289. goto exit;
  1290. }
  1291. }
  1292. // Fill in the new tags
  1293. if (FALSE != fNewRule)
  1294. {
  1295. ulRuleID = 0;
  1296. // Write out the updated rule
  1297. for (dwIndex = 0, pNodeWalk = pRuleNode; NULL != pNodeWalk; pNodeWalk = pNodeWalk->pNext, dwIndex++)
  1298. {
  1299. if (RULEID_INVALID != pNodeWalk->ridRule)
  1300. {
  1301. continue;
  1302. }
  1303. // Find the first open entry
  1304. for (; ulRuleID < PtrToUlong(RULEID_JUNK); ulRuleID++)
  1305. {
  1306. // Get a new index from the order
  1307. wnsprintf(rgchOrder, ARRAYSIZE(rgchOrder), "%03X", ulRuleID);
  1308. lErr = RegOpenKeyEx(hkeyRoot, rgchOrder, 0, KEY_READ, &hkeyDummy);
  1309. if (ERROR_SUCCESS == lErr)
  1310. {
  1311. RegCloseKey(hkeyDummy);
  1312. }
  1313. else
  1314. {
  1315. break;
  1316. }
  1317. }
  1318. if (ERROR_FILE_NOT_FOUND != lErr)
  1319. {
  1320. hr = E_FAIL;
  1321. goto exit;
  1322. }
  1323. // Set the rule tag
  1324. pNodeWalk->ridRule = (RULEID) IntToPtr(ulRuleID);
  1325. // Build the path to the rule
  1326. StrCpyN(rgchRulePath + cchRulePath, rgchOrder, ARRAYSIZE(rgchRulePath) - cchRulePath);
  1327. // Save the rule
  1328. hr = pNodeWalk->pIRule->SaveReg(rgchRulePath, TRUE);
  1329. if (FAILED(hr))
  1330. {
  1331. goto exit;
  1332. }
  1333. }
  1334. }
  1335. // Write out the new order string
  1336. for (dwIndex = 0, pNodeWalk = pRuleNode; NULL != pNodeWalk; pNodeWalk = pNodeWalk->pNext, dwIndex++)
  1337. {
  1338. // Get a new index from the order
  1339. wnsprintf(rgchOrder, ARRAYSIZE(rgchOrder), "%03X", pNodeWalk->ridRule);
  1340. // Add rule to the order
  1341. if ('\0' != pszOrder[0])
  1342. {
  1343. StrCatBuff(pszOrder, g_szSpace, cchSize);
  1344. }
  1345. StrCatBuff(pszOrder, rgchOrder, cchSize);
  1346. }
  1347. // Save the order string
  1348. if (ERROR_SUCCESS != AthUserSetValue(pszRegPath, c_szRulesOrder, REG_SZ, (CONST BYTE *) pszOrder, lstrlen(pszOrder) + 1))
  1349. {
  1350. hr = E_FAIL;
  1351. goto exit;
  1352. }
  1353. // Set the return value
  1354. hr = S_OK;
  1355. exit:
  1356. SafeMemFree(pszOrder);
  1357. if (NULL != hkeyRoot)
  1358. {
  1359. RegCloseKey(hkeyRoot);
  1360. }
  1361. return hr;
  1362. }
  1363. HRESULT CRulesManager::_HrSaveSenders(VOID)
  1364. {
  1365. HRESULT hr = S_OK;
  1366. DWORD dwData = 0;
  1367. LONG lErr = 0;
  1368. HKEY hkeyRoot = NULL;
  1369. DWORD dwIndex = 0;
  1370. CHAR rgchSenderPath[MAX_PATH];
  1371. // Check to see if we have anything to save
  1372. if (0 == (m_dwState & STATE_LOADED_SENDERS))
  1373. {
  1374. hr = S_FALSE;
  1375. goto exit;
  1376. }
  1377. lErr = AthUserCreateKey(c_szSenders, KEY_ALL_ACCESS, &hkeyRoot, &dwData);
  1378. if (ERROR_SUCCESS != lErr)
  1379. {
  1380. hr = E_FAIL;
  1381. goto exit;
  1382. }
  1383. // Save out the senders version
  1384. dwData = RULESMGR_VERSION;
  1385. lErr = RegSetValueEx(hkeyRoot, c_szSendersVersion, 0, REG_DWORD, (CONST BYTE *) &dwData, sizeof(dwData));
  1386. if (ERROR_SUCCESS != lErr)
  1387. {
  1388. hr = E_FAIL;
  1389. goto exit;
  1390. }
  1391. // Delete the old sender list
  1392. SHDeleteKey(hkeyRoot, c_szMailDir);
  1393. // Build up the sender registry path
  1394. StrCpyN(rgchSenderPath, c_szSenders, ARRAYSIZE(rgchSenderPath));
  1395. StrCatBuff(rgchSenderPath, g_szBackSlash, ARRAYSIZE(rgchSenderPath));
  1396. StrCatBuff(rgchSenderPath, c_szMailDir, ARRAYSIZE(rgchSenderPath));
  1397. // Save the rule
  1398. if (NULL != m_pIRuleSenderMail)
  1399. {
  1400. hr = m_pIRuleSenderMail->SaveReg(rgchSenderPath, TRUE);
  1401. if (FAILED(hr))
  1402. {
  1403. goto exit;
  1404. }
  1405. }
  1406. // Delete the old sender list
  1407. SHDeleteKey(hkeyRoot, c_szNewsDir);
  1408. // Build up the sender registry path
  1409. StrCpyN(rgchSenderPath, c_szSenders, ARRAYSIZE(rgchSenderPath));
  1410. StrCatBuff(rgchSenderPath, g_szBackSlash, ARRAYSIZE(rgchSenderPath));
  1411. StrCatBuff(rgchSenderPath, c_szNewsDir, ARRAYSIZE(rgchSenderPath));
  1412. // Save the rule
  1413. if (NULL != m_pIRuleSenderNews)
  1414. {
  1415. hr = m_pIRuleSenderNews->SaveReg(rgchSenderPath, TRUE);
  1416. if (FAILED(hr))
  1417. {
  1418. goto exit;
  1419. }
  1420. }
  1421. // Set the return value
  1422. hr = S_OK;
  1423. exit:
  1424. if (NULL != hkeyRoot)
  1425. {
  1426. RegCloseKey(hkeyRoot);
  1427. }
  1428. return hr;
  1429. }
  1430. HRESULT CRulesManager::_HrSaveJunk(VOID)
  1431. {
  1432. HRESULT hr = S_OK;
  1433. DWORD dwData = 0;
  1434. LONG lErr = 0;
  1435. HKEY hkeyRoot = NULL;
  1436. DWORD dwIndex = 0;
  1437. CHAR rgchSenderPath[MAX_PATH];
  1438. // Check to see if we have anything to save
  1439. if (0 == (m_dwState & STATE_LOADED_JUNK))
  1440. {
  1441. hr = S_FALSE;
  1442. goto exit;
  1443. }
  1444. lErr = AthUserCreateKey(c_szRulesJunkMail, KEY_ALL_ACCESS, &hkeyRoot, &dwData);
  1445. if (ERROR_SUCCESS != lErr)
  1446. {
  1447. hr = E_FAIL;
  1448. goto exit;
  1449. }
  1450. // Save out the senders version
  1451. dwData = RULESMGR_VERSION;
  1452. lErr = RegSetValueEx(hkeyRoot, c_szRulesVersion, 0, REG_DWORD, (CONST BYTE *) &dwData, sizeof(dwData));
  1453. if (ERROR_SUCCESS != lErr)
  1454. {
  1455. hr = E_FAIL;
  1456. goto exit;
  1457. }
  1458. // Save the rule
  1459. if (NULL != m_pIRuleJunk)
  1460. {
  1461. hr = m_pIRuleJunk->SaveReg(c_szRulesJunkMail, TRUE);
  1462. if (FAILED(hr))
  1463. {
  1464. goto exit;
  1465. }
  1466. }
  1467. // Set the return value
  1468. hr = S_OK;
  1469. exit:
  1470. if (NULL != hkeyRoot)
  1471. {
  1472. RegCloseKey(hkeyRoot);
  1473. }
  1474. return hr;
  1475. }
  1476. HRESULT CRulesManager::_HrFreeRules(RULE_TYPE type)
  1477. {
  1478. HRESULT hr = S_OK;
  1479. RULENODE * pNodeWalk = NULL;
  1480. RULENODE * pNodeNext = NULL;
  1481. // Initialize the params
  1482. if (RULE_TYPE_MAIL == type)
  1483. {
  1484. pNodeWalk = m_pMailHead;
  1485. pNodeNext = m_pMailHead;
  1486. }
  1487. else if (RULE_TYPE_NEWS == type)
  1488. {
  1489. pNodeWalk = m_pNewsHead;
  1490. pNodeNext = m_pNewsHead;
  1491. }
  1492. else if (RULE_TYPE_FILTER == type)
  1493. {
  1494. pNodeWalk = m_pFilterHead;
  1495. pNodeNext = m_pFilterHead;
  1496. }
  1497. else
  1498. {
  1499. hr = E_FAIL;
  1500. goto exit;
  1501. }
  1502. // Walk the list and free each item
  1503. while (NULL != pNodeWalk)
  1504. {
  1505. // Save off the next item
  1506. pNodeNext = pNodeWalk->pNext;
  1507. // Release the rule
  1508. AssertSz(NULL != pNodeWalk->pIRule, "Where the heck is the rule???");
  1509. pNodeWalk->pIRule->Release();
  1510. // Free up the node
  1511. delete pNodeWalk;
  1512. // Move to the next item
  1513. pNodeWalk = pNodeNext;
  1514. }
  1515. // Clear out the list head
  1516. if (RULE_TYPE_MAIL == type)
  1517. {
  1518. m_pMailHead = NULL;
  1519. }
  1520. else if (RULE_TYPE_NEWS == type)
  1521. {
  1522. m_pNewsHead = NULL;
  1523. }
  1524. else
  1525. {
  1526. m_pFilterHead = NULL;
  1527. }
  1528. exit:
  1529. // Set the return param
  1530. return hr;
  1531. }
  1532. HRESULT CRulesManager::_HrAddRule(RULEID ridRule, IOERule * pIRule, RULE_TYPE type)
  1533. {
  1534. HRESULT hr = S_OK;
  1535. RULENODE * pRuleNode = NULL;
  1536. RULENODE * pNodeWalk = NULL;
  1537. // Check incoming params
  1538. if (NULL == pIRule)
  1539. {
  1540. hr = E_INVALIDARG;
  1541. goto exit;
  1542. }
  1543. // Create a new rule node
  1544. pRuleNode = new RULENODE;
  1545. if (NULL == pRuleNode)
  1546. {
  1547. hr = E_OUTOFMEMORY;
  1548. goto exit;
  1549. }
  1550. // Initialize the node
  1551. pRuleNode->pNext = NULL;
  1552. pRuleNode->ridRule = ridRule;
  1553. pRuleNode->pIRule = pIRule;
  1554. pRuleNode->pIRule->AddRef();
  1555. // Add the node to the proper list
  1556. if (RULE_TYPE_MAIL == type)
  1557. {
  1558. pNodeWalk = m_pMailHead;
  1559. }
  1560. else if (RULE_TYPE_NEWS == type)
  1561. {
  1562. pNodeWalk = m_pNewsHead;
  1563. }
  1564. else
  1565. {
  1566. pNodeWalk = m_pFilterHead;
  1567. }
  1568. if (NULL == pNodeWalk)
  1569. {
  1570. if (RULE_TYPE_MAIL == type)
  1571. {
  1572. m_pMailHead = pRuleNode;
  1573. }
  1574. else if (RULE_TYPE_NEWS == type)
  1575. {
  1576. m_pNewsHead = pRuleNode;
  1577. }
  1578. else
  1579. {
  1580. m_pFilterHead = pRuleNode;
  1581. }
  1582. pRuleNode = NULL;
  1583. }
  1584. else
  1585. {
  1586. while (NULL != pNodeWalk->pNext)
  1587. {
  1588. pNodeWalk = pNodeWalk->pNext;
  1589. }
  1590. pNodeWalk->pNext = pRuleNode;
  1591. pRuleNode = NULL;
  1592. }
  1593. // Set return values
  1594. hr = S_OK;
  1595. exit:
  1596. if (NULL != pRuleNode)
  1597. {
  1598. pRuleNode->pIRule->Release();
  1599. delete pRuleNode;
  1600. }
  1601. return hr;
  1602. }
  1603. HRESULT CRulesManager::_HrReplaceRule(RULEID ridRule, IOERule * pIRule, RULE_TYPE type)
  1604. {
  1605. HRESULT hr = S_OK;
  1606. RULENODE * pNodeWalk = NULL;
  1607. RULENODE * pNodePrev = NULL;
  1608. // Nothing to do if we don't have a rule
  1609. if (NULL == pIRule)
  1610. {
  1611. hr = E_FAIL;
  1612. goto exit;
  1613. }
  1614. // Initialize the params
  1615. if (RULE_TYPE_MAIL == type)
  1616. {
  1617. pNodeWalk = m_pMailHead;
  1618. }
  1619. else if (RULE_TYPE_NEWS == type)
  1620. {
  1621. pNodeWalk = m_pNewsHead;
  1622. }
  1623. else
  1624. {
  1625. pNodeWalk = m_pFilterHead;
  1626. }
  1627. // Walk the list and free each item
  1628. for (; NULL != pNodeWalk; pNodeWalk = pNodeWalk->pNext)
  1629. {
  1630. if (pNodeWalk->ridRule == ridRule)
  1631. {
  1632. // We found it
  1633. break;
  1634. }
  1635. }
  1636. // Couldn't find the rule in the list
  1637. if (NULL == pNodeWalk)
  1638. {
  1639. hr = E_FAIL;
  1640. goto exit;
  1641. }
  1642. // Replace the rule
  1643. SafeRelease(pNodeWalk->pIRule);
  1644. pNodeWalk->pIRule = pIRule;
  1645. pNodeWalk->pIRule->AddRef();
  1646. // Set the return param
  1647. hr = S_OK;
  1648. exit:
  1649. return hr;
  1650. }
  1651. HRESULT CRulesManager::_HrRemoveRule(IOERule * pIRule, RULE_TYPE type)
  1652. {
  1653. HRESULT hr = S_OK;
  1654. RULENODE * pNodeWalk = NULL;
  1655. RULENODE * pNodePrev = NULL;
  1656. // Initialize the params
  1657. if (RULE_TYPE_MAIL == type)
  1658. {
  1659. pNodeWalk = m_pMailHead;
  1660. }
  1661. else if (RULE_TYPE_NEWS == type)
  1662. {
  1663. pNodeWalk = m_pNewsHead;
  1664. }
  1665. else
  1666. {
  1667. pNodeWalk = m_pFilterHead;
  1668. }
  1669. // Walk the list and free each item
  1670. pNodePrev = NULL;
  1671. while (NULL != pNodeWalk)
  1672. {
  1673. if (pNodeWalk->pIRule == pIRule)
  1674. {
  1675. // We found it
  1676. break;
  1677. }
  1678. // Save off the next item
  1679. pNodePrev = pNodeWalk;
  1680. // Move to the next item
  1681. pNodeWalk = pNodeWalk->pNext;
  1682. }
  1683. // Couldn't find the rule in the list
  1684. if (NULL == pNodeWalk)
  1685. {
  1686. hr = E_FAIL;
  1687. goto exit;
  1688. }
  1689. if (NULL == pNodePrev)
  1690. {
  1691. // Clear out the list head
  1692. if (RULE_TYPE_MAIL == type)
  1693. {
  1694. m_pMailHead = pNodeWalk->pNext;
  1695. }
  1696. else if (RULE_TYPE_NEWS == type)
  1697. {
  1698. m_pNewsHead = pNodeWalk->pNext;
  1699. }
  1700. else
  1701. {
  1702. m_pFilterHead = pNodeWalk->pNext;
  1703. }
  1704. }
  1705. else
  1706. {
  1707. pNodePrev->pNext = pNodeWalk->pNext;
  1708. }
  1709. // Free up the node
  1710. pNodeWalk->pIRule->Release();
  1711. pNodeWalk->pNext = NULL;
  1712. delete pNodeWalk;
  1713. // Set the return param
  1714. hr = S_OK;
  1715. exit:
  1716. return hr;
  1717. }
  1718. HRESULT CRulesManager::_HrFixupRuleInfo(RULE_TYPE typeRule, RULEINFO * pinfoRule, ULONG cpinfoRule)
  1719. {
  1720. HRESULT hr = S_OK;
  1721. ULONG ulIndex = 0;
  1722. RULENODE * pNodeHead = NULL;
  1723. RULENODE * pNodeWalk = NULL;
  1724. // Check incoming args
  1725. if ((NULL == pinfoRule) && (0 != cpinfoRule))
  1726. {
  1727. hr = E_INVALIDARG;
  1728. goto exit;
  1729. }
  1730. // Walk the proper list
  1731. if (RULE_TYPE_MAIL == typeRule)
  1732. {
  1733. pNodeHead = m_pMailHead;
  1734. }
  1735. else if (RULE_TYPE_NEWS == typeRule)
  1736. {
  1737. pNodeHead = m_pNewsHead;
  1738. }
  1739. else if (RULE_TYPE_FILTER == typeRule)
  1740. {
  1741. pNodeHead = m_pFilterHead;
  1742. }
  1743. else
  1744. {
  1745. hr = E_INVALIDARG;
  1746. goto exit;
  1747. }
  1748. // Search the rule info list for an unknown ruleid
  1749. for (ulIndex = 0; ulIndex < cpinfoRule; ulIndex++)
  1750. {
  1751. // If the rule id is invalid try to find it
  1752. if (RULEID_INVALID == pinfoRule[ulIndex].ridRule)
  1753. {
  1754. for (pNodeWalk = pNodeHead; NULL != pNodeWalk; pNodeWalk = pNodeWalk->pNext)
  1755. {
  1756. // Check to see if the rule is the same
  1757. if (pNodeWalk->pIRule == pinfoRule[ulIndex].pIRule)
  1758. {
  1759. pinfoRule[ulIndex].ridRule = pNodeWalk->ridRule;
  1760. break;
  1761. }
  1762. }
  1763. if (NULL == pNodeWalk)
  1764. {
  1765. hr = E_FAIL;
  1766. goto exit;
  1767. }
  1768. }
  1769. }
  1770. // Set the return value
  1771. hr = S_OK;
  1772. exit:
  1773. return hr;
  1774. }
  1775. CEnumRules::CEnumRules()
  1776. {
  1777. m_cRef = 0;
  1778. m_pNodeHead = NULL;
  1779. m_pNodeCurr = NULL;
  1780. m_dwFlags = 0;
  1781. m_typeRule = RULE_TYPE_MAIL;
  1782. }
  1783. CEnumRules::~CEnumRules()
  1784. {
  1785. RULENODE * pNodeNext = NULL;
  1786. AssertSz(m_cRef == 0, "Somebody still has a hold of us!!");
  1787. // Walk the list and free each item
  1788. while (NULL != m_pNodeHead)
  1789. {
  1790. // Save off the next item
  1791. pNodeNext = m_pNodeHead->pNext;
  1792. // Release the rule
  1793. AssertSz(NULL != m_pNodeHead->pIRule, "Where the heck is the rule???");
  1794. m_pNodeHead->pIRule->Release();
  1795. // Free up the node
  1796. delete m_pNodeHead;
  1797. // Move to the next item
  1798. m_pNodeHead = pNodeNext;
  1799. }
  1800. }
  1801. STDMETHODIMP_(ULONG) CEnumRules::AddRef()
  1802. {
  1803. return ::InterlockedIncrement(&m_cRef);
  1804. }
  1805. STDMETHODIMP_(ULONG) CEnumRules::Release()
  1806. {
  1807. LONG cRef = 0;
  1808. cRef = ::InterlockedDecrement(&m_cRef);
  1809. if (0 == cRef)
  1810. {
  1811. delete this;
  1812. return cRef;
  1813. }
  1814. return cRef;
  1815. }
  1816. STDMETHODIMP CEnumRules::QueryInterface(REFIID riid, void ** ppvObject)
  1817. {
  1818. HRESULT hr = S_OK;
  1819. // Check the incoming params
  1820. if (NULL == ppvObject)
  1821. {
  1822. hr = E_INVALIDARG;
  1823. goto exit;
  1824. }
  1825. // Initialize outgoing param
  1826. *ppvObject = NULL;
  1827. if ((riid == IID_IUnknown) || (riid == IID_IOEEnumRules))
  1828. {
  1829. *ppvObject = static_cast<IOEEnumRules *>(this);
  1830. }
  1831. else
  1832. {
  1833. hr = E_NOINTERFACE;
  1834. goto exit;
  1835. }
  1836. reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();
  1837. hr = S_OK;
  1838. exit:
  1839. return hr;
  1840. }
  1841. STDMETHODIMP CEnumRules::Next(ULONG cpIRule, IOERule ** rgpIRule, ULONG * pcpIRuleFetched)
  1842. {
  1843. HRESULT hr = S_OK;
  1844. ULONG cpIRuleRet = 0;
  1845. // Check incoming params
  1846. if (NULL == rgpIRule)
  1847. {
  1848. hr = E_INVALIDARG;
  1849. goto exit;
  1850. }
  1851. // Initialize outgoing params
  1852. *rgpIRule = NULL;
  1853. if (NULL != pcpIRuleFetched)
  1854. {
  1855. *pcpIRuleFetched = 0;
  1856. }
  1857. // If we're at the end then just return
  1858. if (NULL == m_pNodeCurr)
  1859. {
  1860. hr = S_FALSE;
  1861. goto exit;
  1862. }
  1863. for (cpIRuleRet = 0; cpIRuleRet < cpIRule; cpIRuleRet++)
  1864. {
  1865. rgpIRule[cpIRuleRet] = m_pNodeCurr->pIRule;
  1866. (rgpIRule[cpIRuleRet])->AddRef();
  1867. m_pNodeCurr = m_pNodeCurr->pNext;
  1868. if (NULL == m_pNodeCurr)
  1869. {
  1870. cpIRuleRet++;
  1871. break;
  1872. }
  1873. }
  1874. // Set outgoing params
  1875. if (NULL != pcpIRuleFetched)
  1876. {
  1877. *pcpIRuleFetched = cpIRuleRet;
  1878. }
  1879. // Set return value
  1880. hr = (cpIRuleRet == cpIRule) ? S_OK : S_FALSE;
  1881. exit:
  1882. return hr;
  1883. }
  1884. STDMETHODIMP CEnumRules::Skip(ULONG cpIRule)
  1885. {
  1886. HRESULT hr = S_OK;
  1887. ULONG cpIRuleWalk = 0;
  1888. for (cpIRuleWalk = 0; cpIRuleWalk < cpIRule; cpIRuleWalk++)
  1889. {
  1890. if (NULL == m_pNodeCurr)
  1891. {
  1892. break;
  1893. }
  1894. m_pNodeCurr = m_pNodeCurr->pNext;
  1895. }
  1896. hr = (cpIRuleWalk == cpIRule) ? S_OK : S_FALSE;
  1897. return hr;
  1898. }
  1899. STDMETHODIMP CEnumRules::Reset(void)
  1900. {
  1901. HRESULT hr = S_OK;
  1902. m_pNodeCurr = m_pNodeHead;
  1903. return hr;
  1904. }
  1905. STDMETHODIMP CEnumRules::Clone(IOEEnumRules ** ppIEnumRules)
  1906. {
  1907. HRESULT hr = S_OK;
  1908. CEnumRules * pEnumRules = NULL;
  1909. // Check incoming params
  1910. if (NULL == ppIEnumRules)
  1911. {
  1912. hr = E_INVALIDARG;
  1913. goto exit;
  1914. }
  1915. // Initialize outgoing params
  1916. *ppIEnumRules = NULL;
  1917. pEnumRules = new CEnumRules;
  1918. if (NULL == pEnumRules)
  1919. {
  1920. hr = E_OUTOFMEMORY;
  1921. goto exit;
  1922. }
  1923. // Initialize the rules enumerator
  1924. hr = pEnumRules->_HrInitialize(m_dwFlags, m_typeRule, m_pNodeHead);
  1925. if (FAILED(hr))
  1926. {
  1927. goto exit;
  1928. }
  1929. // Set the state of the new one to match the current one
  1930. pEnumRules->m_pNodeCurr = m_pNodeHead;
  1931. // Get the rules enumerator interface
  1932. hr = pEnumRules->QueryInterface(IID_IOEEnumRules, (void **) ppIEnumRules);
  1933. if (FAILED(hr))
  1934. {
  1935. goto exit;
  1936. }
  1937. pEnumRules = NULL;
  1938. hr = S_OK;
  1939. exit:
  1940. if (NULL != pEnumRules)
  1941. {
  1942. delete pEnumRules;
  1943. }
  1944. return hr;
  1945. }
  1946. HRESULT CEnumRules::_HrInitialize(DWORD dwFlags, RULE_TYPE typeRule, RULENODE * pNodeHead)
  1947. {
  1948. HRESULT hr = S_OK;
  1949. RULENODE * pNodeNew = NULL;
  1950. RULENODE * pNodeWalk = NULL;
  1951. if (NULL == pNodeHead)
  1952. {
  1953. hr = S_FALSE;
  1954. goto exit;
  1955. }
  1956. m_dwFlags = dwFlags;
  1957. m_typeRule = typeRule;
  1958. for (pNodeWalk = m_pNodeHead; NULL != pNodeHead; pNodeHead = pNodeHead->pNext)
  1959. {
  1960. // Check to see if we should add this item
  1961. if (RULE_TYPE_FILTER == m_typeRule)
  1962. {
  1963. if (0 != (dwFlags & ENUMF_POP3))
  1964. {
  1965. if (RULEID_VIEW_DOWNLOADED == pNodeHead->ridRule)
  1966. {
  1967. continue;
  1968. }
  1969. }
  1970. }
  1971. pNodeNew = new RULENODE;
  1972. if (NULL == pNodeNew)
  1973. {
  1974. hr = E_OUTOFMEMORY;
  1975. goto exit;
  1976. }
  1977. // Initialize new node
  1978. pNodeNew->pNext = NULL;
  1979. pNodeNew->pIRule = pNodeHead->pIRule;
  1980. pNodeNew->pIRule->AddRef();
  1981. // Add the new node to the list
  1982. if (NULL == pNodeWalk)
  1983. {
  1984. m_pNodeHead = pNodeNew;
  1985. pNodeWalk = pNodeNew;
  1986. }
  1987. else
  1988. {
  1989. pNodeWalk->pNext = pNodeNew;
  1990. pNodeWalk = pNodeNew;
  1991. }
  1992. pNodeNew = NULL;
  1993. }
  1994. // Set the current to the front of the chain
  1995. m_pNodeCurr = m_pNodeHead;
  1996. // Set return value
  1997. hr = S_OK;
  1998. exit:
  1999. if (pNodeNew)
  2000. delete pNodeNew;
  2001. return hr;
  2002. }
  2003. // The Rule Executor object
  2004. CExecRules::~CExecRules()
  2005. {
  2006. RULENODE * pNodeNext = NULL;
  2007. AssertSz(m_cRef == 0, "Somebody still has a hold of us!!");
  2008. // Walk the list and free each item
  2009. while (NULL != m_pNodeHead)
  2010. {
  2011. // Save off the next item
  2012. pNodeNext = m_pNodeHead->pNext;
  2013. // Release the rule
  2014. AssertSz(NULL != m_pNodeHead->pIRule, "Where the heck is the rule???");
  2015. m_pNodeHead->pIRule->Release();
  2016. // Free up the node
  2017. delete m_pNodeHead;
  2018. // Move to the next item
  2019. m_pNodeHead = pNodeNext;
  2020. }
  2021. // Free up the cached objects
  2022. _HrReleaseFolderObjects();
  2023. _HrReleaseFileObjects();
  2024. _HrReleaseSoundFiles();
  2025. // Free the folder list
  2026. SafeMemFree(m_pRuleFolder);
  2027. m_cRuleFolderAlloc = 0;
  2028. // Free the file list
  2029. SafeMemFree(m_pRuleFile);
  2030. m_cRuleFileAlloc = 0;
  2031. // Free the file list
  2032. SafeMemFree(m_ppszSndFile);
  2033. m_cpszSndFileAlloc = 0;
  2034. }
  2035. STDMETHODIMP_(ULONG) CExecRules::AddRef()
  2036. {
  2037. return ::InterlockedIncrement(&m_cRef);
  2038. }
  2039. STDMETHODIMP_(ULONG) CExecRules::Release()
  2040. {
  2041. LONG cRef = 0;
  2042. cRef = ::InterlockedDecrement(&m_cRef);
  2043. if (0 == cRef)
  2044. {
  2045. delete this;
  2046. return cRef;
  2047. }
  2048. return cRef;
  2049. }
  2050. STDMETHODIMP CExecRules::QueryInterface(REFIID riid, void ** ppvObject)
  2051. {
  2052. HRESULT hr = S_OK;
  2053. // Check the incoming params
  2054. if (NULL == ppvObject)
  2055. {
  2056. hr = E_INVALIDARG;
  2057. goto exit;
  2058. }
  2059. // Initialize outgoing param
  2060. *ppvObject = NULL;
  2061. if ((riid == IID_IUnknown) || (riid == IID_IOEExecRules))
  2062. {
  2063. *ppvObject = static_cast<IOEExecRules *>(this);
  2064. }
  2065. else
  2066. {
  2067. hr = E_NOINTERFACE;
  2068. goto exit;
  2069. }
  2070. reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();
  2071. hr = S_OK;
  2072. exit:
  2073. return hr;
  2074. }
  2075. STDMETHODIMP CExecRules::GetState(DWORD * pdwState)
  2076. {
  2077. HRESULT hr = S_OK;
  2078. // Check incoming params
  2079. if (NULL == pdwState)
  2080. {
  2081. hr = E_INVALIDARG;
  2082. goto exit;
  2083. }
  2084. *pdwState = m_dwState;
  2085. hr = S_OK;
  2086. exit:
  2087. return hr;
  2088. }
  2089. STDMETHODIMP CExecRules::ExecuteRules(DWORD dwFlags, LPCSTR pszAcct, MESSAGEINFO * pMsgInfo,
  2090. IMessageFolder * pFolder, IMimePropertySet * pIMPropSet,
  2091. IMimeMessage * pIMMsg, ULONG cbMsgSize,
  2092. ACT_ITEM ** ppActions, ULONG * pcActions)
  2093. {
  2094. HRESULT hr = S_OK;
  2095. ULONG ulIndex = 0;
  2096. RULENODE * pNodeWalk = NULL;
  2097. ACT_ITEM * pActions = NULL;
  2098. ULONG cActions = 0;
  2099. ACT_ITEM * pActionsList = NULL;
  2100. ULONG cActionsList = 0;
  2101. ACT_ITEM * pActionsNew = NULL;
  2102. ULONG cActionsNew = 0;
  2103. BOOL fStopProcessing = FALSE;
  2104. BOOL fMatch = FALSE;
  2105. DWORD dwState = 0;
  2106. // Check incoming params
  2107. if (((NULL == pMsgInfo) && (NULL == pIMPropSet)) ||
  2108. (0 == cbMsgSize) || (NULL == ppActions) || (NULL == pcActions))
  2109. {
  2110. hr = E_INVALIDARG;
  2111. goto exit;
  2112. }
  2113. // Initialize outgoing param
  2114. *ppActions = NULL;
  2115. *pcActions = 0;
  2116. // Should we skip partial messages?
  2117. if ((NULL != pIMPropSet) &&
  2118. (S_OK == pIMPropSet->IsContentType(STR_CNT_MESSAGE, STR_SUB_PARTIAL)) &&
  2119. (0 != (dwFlags & ERF_SKIPPARTIALS)))
  2120. {
  2121. hr = S_FALSE;
  2122. goto exit;
  2123. }
  2124. // Walk the list of rules executing each one
  2125. pNodeWalk = m_pNodeHead;
  2126. while (NULL != pNodeWalk)
  2127. {
  2128. Assert(NULL != pNodeWalk->pIRule);
  2129. // If we are only checking server rules
  2130. // Bail if we need more information...
  2131. if (0 != (dwFlags & ERF_ONLYSERVER))
  2132. {
  2133. hr = pNodeWalk->pIRule->GetState(&dwState);
  2134. if (FAILED(hr))
  2135. {
  2136. goto exit;
  2137. }
  2138. // Do we need more information...
  2139. if (0 != (dwState & CRIT_STATE_ALL))
  2140. {
  2141. hr = S_FALSE;
  2142. break;
  2143. }
  2144. }
  2145. // Evaluate the rule
  2146. hr = pNodeWalk->pIRule->Evaluate(pszAcct, pMsgInfo, pFolder, pIMPropSet, pIMMsg, cbMsgSize, &pActions, &cActions);
  2147. if (FAILED(hr))
  2148. {
  2149. goto exit;
  2150. }
  2151. // Did we have a match
  2152. if (S_OK == hr)
  2153. {
  2154. // We've matched at least once
  2155. fMatch = TRUE;
  2156. ulIndex = 0;
  2157. // If these are server actions
  2158. if ((1 == cActions) && ((ACT_TYPE_DELETESERVER == pActions[ulIndex].type) ||
  2159. (ACT_TYPE_DONTDOWNLOAD == pActions[ulIndex].type)))
  2160. {
  2161. // If this is our only action
  2162. if (0 == cActionsList)
  2163. {
  2164. // Save the action
  2165. pActionsList = pActions;
  2166. pActions = NULL;
  2167. cActionsList = cActions;
  2168. // We are done
  2169. fStopProcessing = TRUE;
  2170. }
  2171. else
  2172. {
  2173. // We already have to do something with it
  2174. // so skip over this action
  2175. RuleUtil_HrFreeActionsItem(pActions, cActions);
  2176. SafeMemFree(pActions);
  2177. // Move to the next rule
  2178. pNodeWalk = pNodeWalk->pNext;
  2179. continue;
  2180. }
  2181. }
  2182. else
  2183. {
  2184. // Should we stop after merging these?
  2185. for (ulIndex = 0; ulIndex < cActions; ulIndex++)
  2186. {
  2187. if (ACT_TYPE_STOP == pActions[ulIndex].type)
  2188. {
  2189. fStopProcessing = TRUE;
  2190. break;
  2191. }
  2192. }
  2193. // Merge these items with the previous ones
  2194. hr = RuleUtil_HrMergeActions(pActionsList, cActionsList, pActions, cActions, &pActionsNew, &cActionsNew);
  2195. if (FAILED(hr))
  2196. {
  2197. goto exit;
  2198. }
  2199. // Free up the previous ones
  2200. RuleUtil_HrFreeActionsItem(pActionsList, cActionsList);
  2201. SafeMemFree(pActionsList);
  2202. RuleUtil_HrFreeActionsItem(pActions, cActions);
  2203. SafeMemFree(pActions);
  2204. // Save off the new ones
  2205. pActionsList = pActionsNew;
  2206. pActionsNew = NULL;
  2207. cActionsList = cActionsNew;
  2208. }
  2209. // Should we continue...
  2210. if (FALSE != fStopProcessing)
  2211. {
  2212. break;
  2213. }
  2214. }
  2215. // Move to the next rule
  2216. pNodeWalk = pNodeWalk->pNext;
  2217. }
  2218. // Set outgoing param
  2219. *ppActions = pActionsList;
  2220. pActionsList = NULL;
  2221. *pcActions = cActionsList;
  2222. // Set the return value
  2223. hr = (FALSE != fMatch) ? S_OK : S_FALSE;
  2224. exit:
  2225. RuleUtil_HrFreeActionsItem(pActionsNew, cActionsNew);
  2226. SafeMemFree(pActionsNew);
  2227. RuleUtil_HrFreeActionsItem(pActions, cActions);
  2228. SafeMemFree(pActions);
  2229. RuleUtil_HrFreeActionsItem(pActionsList, cActionsList);
  2230. SafeMemFree(pActionsList);
  2231. return hr;
  2232. }
  2233. STDMETHODIMP CExecRules::ReleaseObjects(VOID)
  2234. {
  2235. // Free up the folders
  2236. _HrReleaseFolderObjects();
  2237. // Free up the files
  2238. _HrReleaseFileObjects();
  2239. // Free up the sound files
  2240. _HrReleaseSoundFiles();
  2241. return S_OK;
  2242. }
  2243. STDMETHODIMP CExecRules::GetRuleFolder(FOLDERID idFolder, DWORD_PTR * pdwFolder)
  2244. {
  2245. HRESULT hr = S_OK;
  2246. ULONG ulIndex = 0;
  2247. RULE_FOLDER * pRuleFolderWalk = NULL;
  2248. IMessageFolder *pFolder = NULL;
  2249. // Check incoming param
  2250. if ((FOLDERID_INVALID == idFolder) || (NULL == pdwFolder))
  2251. {
  2252. hr =E_INVALIDARG;
  2253. goto exit;
  2254. }
  2255. // Initialize outgoing param
  2256. *pdwFolder = NULL;
  2257. // Let's search for the folder
  2258. for (ulIndex = 0; ulIndex < m_cRuleFolder; ulIndex++)
  2259. {
  2260. pRuleFolderWalk = &(m_pRuleFolder[ulIndex]);
  2261. if (idFolder == pRuleFolderWalk->idFolder)
  2262. {
  2263. Assert(NULL != pRuleFolderWalk->pFolder);
  2264. break;
  2265. }
  2266. }
  2267. // If we didn't find it then let's open it and lock it...
  2268. if (ulIndex >= m_cRuleFolder)
  2269. {
  2270. // Do we need to alloc any more spaces
  2271. if (m_cRuleFolder >= m_cRuleFolderAlloc)
  2272. {
  2273. hr = HrRealloc((LPVOID *) &m_pRuleFolder, sizeof(*m_pRuleFolder) * (m_cRuleFolderAlloc + RULE_FOLDER_ALLOC));
  2274. if (FAILED(hr))
  2275. {
  2276. goto exit;
  2277. }
  2278. // Initialize the new rule folders
  2279. ZeroMemory(m_pRuleFolder + m_cRuleFolderAlloc, sizeof(*m_pRuleFolder) * RULE_FOLDER_ALLOC);
  2280. for (ulIndex = m_cRuleFolderAlloc; ulIndex < (m_cRuleFolderAlloc + RULE_FOLDER_ALLOC); ulIndex++)
  2281. {
  2282. m_pRuleFolder[ulIndex].idFolder = FOLDERID_INVALID;
  2283. }
  2284. m_cRuleFolderAlloc += RULE_FOLDER_ALLOC;
  2285. }
  2286. // Open the folder
  2287. hr = g_pStore->OpenFolder(idFolder, NULL, NOFLAGS, &pFolder);
  2288. if (FAILED(hr))
  2289. {
  2290. goto exit;
  2291. }
  2292. m_pRuleFolder[m_cRuleFolder].idFolder = idFolder;
  2293. m_pRuleFolder[m_cRuleFolder].pFolder = pFolder;
  2294. pFolder = NULL;
  2295. pRuleFolderWalk = &(m_pRuleFolder[m_cRuleFolder]);
  2296. m_cRuleFolder++;
  2297. }
  2298. *pdwFolder = (DWORD_PTR) (pRuleFolderWalk->pFolder);
  2299. // Set the proper return value
  2300. hr = S_OK;
  2301. exit:
  2302. if (NULL != pFolder)
  2303. pFolder->Release();
  2304. return hr;
  2305. }
  2306. STDMETHODIMP CExecRules::GetRuleFile(LPCSTR pszFile, IStream ** ppstmFile, DWORD * pdwType)
  2307. {
  2308. HRESULT hr = S_OK;
  2309. ULONG ulIndex = 0;
  2310. RULE_FILE * pRuleFileWalk = NULL;
  2311. IStream * pIStmFile = NULL;
  2312. LPSTR pszExt = NULL;
  2313. DWORD dwType = RFT_FILE;
  2314. // Check incoming param
  2315. if ((NULL == pszFile) || (NULL == ppstmFile) || (NULL == pdwType))
  2316. {
  2317. hr =E_INVALIDARG;
  2318. goto exit;
  2319. }
  2320. // Initialize outgoing param
  2321. *ppstmFile = NULL;
  2322. *pdwType = NULL;
  2323. // Let's search for the file
  2324. for (ulIndex = 0; ulIndex < m_cRuleFile; ulIndex++)
  2325. {
  2326. pRuleFileWalk = &(m_pRuleFile[ulIndex]);
  2327. if (0 == lstrcmpi(pRuleFileWalk->pszFile, pszFile))
  2328. {
  2329. Assert(NULL != pRuleFileWalk->pstmFile);
  2330. break;
  2331. }
  2332. }
  2333. // If we didn't find it then let's open it...
  2334. if (ulIndex >= m_cRuleFile)
  2335. {
  2336. // Do we need to alloc any more space
  2337. if (m_cRuleFile >= m_cRuleFileAlloc)
  2338. {
  2339. hr = HrRealloc((LPVOID *) &m_pRuleFile, sizeof(*m_pRuleFile) * (m_cRuleFileAlloc + RULE_FILE_ALLOC));
  2340. if (FAILED(hr))
  2341. {
  2342. goto exit;
  2343. }
  2344. // Initialize the new rule file
  2345. ZeroMemory(m_pRuleFile + m_cRuleFileAlloc, sizeof(*m_pRuleFile) * RULE_FILE_ALLOC);
  2346. m_cRuleFileAlloc += RULE_FILE_ALLOC;
  2347. }
  2348. // Open a stream on the file
  2349. hr = CreateStreamOnHFile((LPTSTR) pszFile, GENERIC_READ, FILE_SHARE_READ, NULL,
  2350. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL, &pIStmFile);
  2351. if (FAILED(hr))
  2352. {
  2353. goto exit;
  2354. }
  2355. // Lets split the file name and get the extension
  2356. pszExt = PathFindExtension(pszFile);
  2357. if ((0 == lstrcmpi(pszExt, c_szHtmExt)) || (0 == lstrcmpi(pszExt, c_szHtmlExt)))
  2358. {
  2359. dwType = RFT_HTML;
  2360. }
  2361. // Text File...
  2362. else if (0 == lstrcmpi(pszExt, c_szTxtExt))
  2363. {
  2364. dwType = RFT_TEXT;
  2365. }
  2366. // Else .nws or .eml file...
  2367. else if ((0 == lstrcmpi(pszExt, c_szEmlExt)) || (0 == lstrcmpi(pszExt, c_szNwsExt)))
  2368. {
  2369. dwType = RFT_MESSAGE;
  2370. }
  2371. // Otherwise, its an attachment
  2372. else
  2373. {
  2374. dwType = RFT_FILE;
  2375. }
  2376. // Save off the info
  2377. m_pRuleFile[m_cRuleFile].pszFile = PszDupA(pszFile);
  2378. if (NULL == m_pRuleFile[m_cRuleFile].pszFile)
  2379. {
  2380. hr = E_OUTOFMEMORY;
  2381. goto exit;
  2382. }
  2383. m_pRuleFile[m_cRuleFile].pstmFile = pIStmFile;
  2384. pIStmFile = NULL;
  2385. m_pRuleFile[m_cRuleFile].dwType = dwType;
  2386. pRuleFileWalk = &(m_pRuleFile[m_cRuleFile]);
  2387. m_cRuleFile++;
  2388. }
  2389. *ppstmFile = pRuleFileWalk->pstmFile;
  2390. (*ppstmFile)->AddRef();
  2391. *pdwType = pRuleFileWalk->dwType;
  2392. // Set the proper return value
  2393. hr = S_OK;
  2394. exit:
  2395. SafeRelease(pIStmFile);
  2396. return hr;
  2397. }
  2398. STDMETHODIMP CExecRules::AddSoundFile(DWORD dwFlags, LPCSTR pszSndFile)
  2399. {
  2400. HRESULT hr = S_OK;
  2401. ULONG ulIndex = 0;
  2402. // Check incoming param
  2403. if (NULL == pszSndFile)
  2404. {
  2405. hr = E_INVALIDARG;
  2406. goto exit;
  2407. }
  2408. // Let's search for the file
  2409. for (ulIndex = 0; ulIndex < m_cpszSndFile; ulIndex++)
  2410. {
  2411. Assert(NULL != m_ppszSndFile[ulIndex]);
  2412. if (0 == lstrcmpi(m_ppszSndFile[ulIndex], pszSndFile))
  2413. {
  2414. break;
  2415. }
  2416. }
  2417. // If we didn't find it then let's open it...
  2418. if (ulIndex >= m_cpszSndFile)
  2419. {
  2420. // Do we need to alloc any more space
  2421. if (m_cpszSndFile >= m_cpszSndFileAlloc)
  2422. {
  2423. hr = HrRealloc((LPVOID *) &m_ppszSndFile, sizeof(*m_ppszSndFile) * (m_cpszSndFileAlloc + SND_FILE_ALLOC));
  2424. if (FAILED(hr))
  2425. {
  2426. goto exit;
  2427. }
  2428. // Initialize the new rule file
  2429. ZeroMemory(m_ppszSndFile + m_cpszSndFileAlloc, sizeof(*m_ppszSndFile) * SND_FILE_ALLOC);
  2430. m_cpszSndFileAlloc += SND_FILE_ALLOC;
  2431. }
  2432. // Save off the info
  2433. m_ppszSndFile[m_cpszSndFile] = PszDupA(pszSndFile);
  2434. if (NULL == m_ppszSndFile[m_cpszSndFile])
  2435. {
  2436. hr = E_OUTOFMEMORY;
  2437. goto exit;
  2438. }
  2439. // Should we play it?
  2440. if (0 != (dwFlags & ASF_PLAYIFNEW))
  2441. {
  2442. sndPlaySound(m_ppszSndFile[m_cpszSndFile], SND_NODEFAULT | SND_SYNC);
  2443. }
  2444. m_cpszSndFile++;
  2445. }
  2446. // Set the proper return value
  2447. hr = S_OK;
  2448. exit:
  2449. return hr;
  2450. }
  2451. STDMETHODIMP CExecRules::PlaySounds(DWORD dwFlags)
  2452. {
  2453. HRESULT hr = S_OK;
  2454. ULONG ulIndex = 0;
  2455. // Let's search for the file
  2456. for (ulIndex = 0; ulIndex < m_cpszSndFile; ulIndex++)
  2457. {
  2458. Assert(NULL != m_ppszSndFile[ulIndex]);
  2459. sndPlaySound(m_ppszSndFile[ulIndex], SND_NODEFAULT | SND_SYNC);
  2460. }
  2461. return hr;
  2462. }
  2463. HRESULT CExecRules::_HrReleaseFolderObjects(VOID)
  2464. {
  2465. RULE_FOLDER * pRuleFolder = NULL;
  2466. ULONG ulIndex = 0;
  2467. for (ulIndex = 0; ulIndex < m_cRuleFolder; ulIndex++)
  2468. {
  2469. pRuleFolder = &(m_pRuleFolder[ulIndex]);
  2470. Assert(FOLDERID_INVALID != pRuleFolder->idFolder);
  2471. // If we have the folder opened then close it
  2472. SafeRelease(pRuleFolder->pFolder);
  2473. // Reset the folder list
  2474. pRuleFolder->idFolder = FOLDERID_INVALID;
  2475. }
  2476. // Let's clear out the number of messages
  2477. m_cRuleFolder = 0;
  2478. return S_OK;
  2479. }
  2480. HRESULT CExecRules::_HrReleaseFileObjects(VOID)
  2481. {
  2482. RULE_FILE * pRuleFile = NULL;
  2483. ULONG ulIndex = 0;
  2484. for (ulIndex = 0; ulIndex < m_cRuleFile; ulIndex++)
  2485. {
  2486. pRuleFile = &(m_pRuleFile[ulIndex]);
  2487. Assert(NULL != pRuleFile->pszFile);
  2488. // If we have the file opened then close it
  2489. SafeRelease(pRuleFile->pstmFile);
  2490. // Clear the file
  2491. SafeMemFree(pRuleFile->pszFile);
  2492. pRuleFile->dwType = RFT_FILE;
  2493. }
  2494. // Let's clear out the number of file
  2495. m_cRuleFile = 0;
  2496. return S_OK;
  2497. }
  2498. HRESULT CExecRules::_HrReleaseSoundFiles(VOID)
  2499. {
  2500. ULONG ulIndex = 0;
  2501. for (ulIndex = 0; ulIndex < m_cpszSndFile; ulIndex++)
  2502. {
  2503. Assert(NULL != m_ppszSndFile[ulIndex]);
  2504. // Clear the file
  2505. SafeMemFree(m_ppszSndFile[ulIndex]);
  2506. }
  2507. // Let's clear out the number of file
  2508. m_cpszSndFile = 0;
  2509. return S_OK;
  2510. }
  2511. HRESULT CExecRules::_HrInitialize(DWORD dwFlags, RULENODE * pNodeHead)
  2512. {
  2513. HRESULT hr = S_OK;
  2514. RULENODE * pNodeNew = NULL;
  2515. RULENODE * pNodeWalk = NULL;
  2516. DWORD dwState = 0;
  2517. PROPVARIANT propvar;
  2518. if (NULL == pNodeHead)
  2519. {
  2520. hr = S_FALSE;
  2521. goto exit;
  2522. }
  2523. for (pNodeWalk = m_pNodeHead; NULL != pNodeHead; pNodeHead = pNodeHead->pNext)
  2524. {
  2525. // Skip rules that are disabled
  2526. if (0 != (dwFlags & ERF_ONLY_ENABLED))
  2527. {
  2528. hr = pNodeHead->pIRule->GetProp(RULE_PROP_DISABLED, 0, &propvar);
  2529. Assert(VT_BOOL == propvar.vt);
  2530. if (FAILED(hr) || (FALSE != propvar.boolVal))
  2531. {
  2532. continue;
  2533. }
  2534. }
  2535. // Skip rules that are invalid
  2536. if (0 != (dwFlags & ERF_ONLY_VALID))
  2537. {
  2538. hr = pNodeHead->pIRule->Validate(dwFlags);
  2539. if (FAILED(hr) || (S_FALSE == hr))
  2540. {
  2541. continue;
  2542. }
  2543. }
  2544. pNodeNew = new RULENODE;
  2545. if (NULL == pNodeNew)
  2546. {
  2547. hr = E_OUTOFMEMORY;
  2548. goto exit;
  2549. }
  2550. // Initialize new node
  2551. pNodeNew->pNext = NULL;
  2552. pNodeNew->pIRule = pNodeHead->pIRule;
  2553. pNodeNew->pIRule->AddRef();
  2554. // Add the new node to the list
  2555. if (NULL == pNodeWalk)
  2556. {
  2557. m_pNodeHead = pNodeNew;
  2558. pNodeWalk = pNodeNew;
  2559. }
  2560. else
  2561. {
  2562. pNodeWalk->pNext = pNodeNew;
  2563. pNodeWalk = pNodeNew;
  2564. }
  2565. pNodeNew = NULL;
  2566. // Calculate state from message
  2567. if (SUCCEEDED(pNodeWalk->pIRule->GetState(&dwState)))
  2568. {
  2569. // Let's set the proper Criteria state
  2570. if ((m_dwState & CRIT_STATE_MASK) < (dwState & CRIT_STATE_MASK))
  2571. {
  2572. m_dwState = (m_dwState & ~CRIT_STATE_MASK) | (dwState & CRIT_STATE_MASK);
  2573. }
  2574. // Let's set the proper Action state
  2575. if (0 != (dwState & ACT_STATE_MASK))
  2576. {
  2577. m_dwState |= (dwState & ACT_STATE_MASK);
  2578. }
  2579. }
  2580. }
  2581. // Set return value
  2582. hr = S_OK;
  2583. exit:
  2584. if (pNodeNew)
  2585. delete pNodeNew;
  2586. return hr;
  2587. }