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.

1335 lines
32 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // JunkRule.cpp
  4. //
  5. ///////////////////////////////////////////////////////////////////////////////
  6. #include <pch.hxx>
  7. #include "junkrule.h"
  8. #include "msoejunk.h"
  9. #include "strconst.h"
  10. #include "goptions.h"
  11. #include "criteria.h"
  12. #include "actions.h"
  13. #include "ruleutil.h"
  14. #include <ipab.h>
  15. #include <shlwapip.h>
  16. typedef HRESULT (WINAPI * TYP_HrCreateJunkFilter) (DWORD dwFlags, IOEJunkFilter ** ppIJunkFilter);
  17. ///////////////////////////////////////////////////////////////////////////////
  18. //
  19. // HrCreateJunkRule
  20. //
  21. // This creates a junk rule.
  22. //
  23. // ppIRule - pointer to return the junk rule
  24. //
  25. // Returns: S_OK, on success
  26. // E_OUTOFMEMORY, if can't create the JunkRule object
  27. //
  28. ///////////////////////////////////////////////////////////////////////////////
  29. HRESULT HrCreateJunkRule(IOERule ** ppIRule)
  30. {
  31. COEJunkRule * pRule = NULL;
  32. HRESULT hr = S_OK;
  33. // Check the incoming params
  34. if (NULL == ppIRule)
  35. {
  36. hr = E_INVALIDARG;
  37. goto exit;
  38. }
  39. // Initialize outgoing params
  40. *ppIRule = NULL;
  41. // Create the rules manager object
  42. pRule = new COEJunkRule;
  43. if (NULL == pRule)
  44. {
  45. hr = E_OUTOFMEMORY;
  46. goto exit;
  47. }
  48. // Note that we have a reference
  49. pRule->AddRef();
  50. // Initialize the junk rule
  51. hr = pRule->HrInit(c_szJunkDll, c_szJunkFile);
  52. if (FAILED(hr))
  53. {
  54. goto exit;
  55. }
  56. // Get the rules manager interface
  57. hr = pRule->QueryInterface(IID_IOERule, (void **) ppIRule);
  58. if (FAILED(hr))
  59. {
  60. goto exit;
  61. }
  62. // Set the proper return value
  63. hr = S_OK;
  64. exit:
  65. SafeRelease(pRule);
  66. return hr;
  67. }
  68. COEJunkRule::~COEJunkRule()
  69. {
  70. IUnknown * pIUnkOuter = NULL;
  71. AssertSz(m_cRef == 0, "Somebody still has a hold of us!!");
  72. // Prevent recursive destruction on the next
  73. // AddRef/Release pair
  74. if (NULL != m_pIAddrList)
  75. {
  76. m_cRef = 1;
  77. // Counter the Release call in the creation function
  78. pIUnkOuter = this;
  79. pIUnkOuter->AddRef();
  80. // Release the aggregated interface
  81. m_pIAddrList->Release();
  82. m_pIAddrList = NULL;
  83. }
  84. SafeRelease(m_pIUnkInner);
  85. SafeRelease(m_pIJunkFilter);
  86. SafeMemFree(m_pszJunkDll);
  87. SafeMemFree(m_pszDataFile);
  88. if (NULL != m_hinst)
  89. {
  90. FreeLibrary(m_hinst);
  91. }
  92. }
  93. STDMETHODIMP_(ULONG) COEJunkRule::AddRef()
  94. {
  95. return ::InterlockedIncrement(&m_cRef);
  96. }
  97. STDMETHODIMP_(ULONG) COEJunkRule::Release()
  98. {
  99. LONG cRef = 0;
  100. cRef = ::InterlockedDecrement(&m_cRef);
  101. if (0 == cRef)
  102. {
  103. delete this;
  104. return cRef;
  105. }
  106. return cRef;
  107. }
  108. STDMETHODIMP COEJunkRule::QueryInterface(REFIID riid, void ** ppvObject)
  109. {
  110. HRESULT hr = S_OK;
  111. // Check the incoming params
  112. if (NULL == ppvObject)
  113. {
  114. hr = E_INVALIDARG;
  115. goto exit;
  116. }
  117. // Initialize outgoing param
  118. *ppvObject = NULL;
  119. if ((riid == IID_IUnknown) || (riid == IID_IOERule))
  120. {
  121. *ppvObject = static_cast<IUnknown *>(this);
  122. }
  123. else if (riid == IID_IOERule)
  124. {
  125. *ppvObject = static_cast<IOERule *>(this);
  126. }
  127. else if (riid == IID_IOERuleAddrList)
  128. {
  129. *ppvObject = m_pIAddrList;
  130. }
  131. else
  132. {
  133. hr = E_NOINTERFACE;
  134. goto exit;
  135. }
  136. reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();
  137. hr = S_OK;
  138. exit:
  139. return hr;
  140. }
  141. STDMETHODIMP COEJunkRule::Reset(void)
  142. {
  143. HRESULT hr = S_OK;
  144. // Set the current state
  145. m_dwState |= RULE_STATE_INIT;
  146. // Clear the dirty bit
  147. m_dwState &= ~RULE_STATE_DIRTY;
  148. // Set the return value
  149. hr = S_OK;
  150. return hr;
  151. }
  152. STDMETHODIMP COEJunkRule::GetState(DWORD * pdwState)
  153. {
  154. HRESULT hr = S_OK;
  155. ULONG ulIndex = 0;
  156. // Check incoming params
  157. if (NULL == pdwState)
  158. {
  159. hr = E_INVALIDARG;
  160. goto exit;
  161. }
  162. // If we're not enabled
  163. if ((0 != (m_dwState & RULE_STATE_DISABLED)) || (0 != (m_dwState & RULE_STATE_INVALID)))
  164. {
  165. *pdwState = RULE_STATE_NULL;
  166. }
  167. else
  168. {
  169. *pdwState = CRIT_STATE_ALL | ACT_STATE_LOCAL;
  170. }
  171. // Set the proper return value
  172. hr = S_OK;
  173. exit:
  174. return hr;
  175. }
  176. STDMETHODIMP COEJunkRule::GetProp(RULE_PROP prop, DWORD dwFlags, PROPVARIANT * pvarResult)
  177. {
  178. HRESULT hr = S_OK;
  179. TCHAR szRes[CCHMAX_STRINGRES];
  180. LPSTR pszName = NULL;
  181. CRIT_ITEM * pCrit = NULL;
  182. ACT_ITEM * pAct = NULL;
  183. ULONG cItem = 0;
  184. // Check incoming params
  185. if (NULL == pvarResult)
  186. {
  187. hr = E_INVALIDARG;
  188. goto exit;
  189. }
  190. // Initialize outgoing params
  191. ZeroMemory(pvarResult, sizeof(*pvarResult));
  192. switch(prop)
  193. {
  194. case RULE_PROP_NAME:
  195. // Get the name
  196. szRes[0] = '\0';
  197. LoadString(g_hLocRes, idsJunkMail, szRes, ARRAYSIZE(szRes));
  198. pszName = PszDupA(szRes);
  199. pvarResult->vt = VT_LPSTR;
  200. pvarResult->pszVal = pszName;
  201. pszName = NULL;
  202. break;
  203. case RULE_PROP_DISABLED:
  204. pvarResult->vt = VT_BOOL;
  205. pvarResult->boolVal = !!(m_dwState & RULE_STATE_DISABLED);
  206. break;
  207. case RULE_PROP_CRITERIA:
  208. pCrit = new CRIT_ITEM;
  209. if (NULL == pCrit)
  210. {
  211. hr = E_OUTOFMEMORY;
  212. goto exit;
  213. }
  214. ZeroMemory(pCrit, sizeof(*pCrit));
  215. pCrit->type = CRIT_TYPE_JUNK;
  216. pCrit->logic = CRIT_LOGIC_AND;
  217. pCrit->dwFlags = CRIT_FLAG_DEFAULT;
  218. pCrit->propvar.vt = VT_EMPTY;
  219. pvarResult->vt = VT_BLOB;
  220. pvarResult->blob.cbSize = sizeof(CRIT_ITEM);
  221. pvarResult->blob.pBlobData = (BYTE *) pCrit;
  222. pCrit = NULL;
  223. break;
  224. case RULE_PROP_ACTIONS:
  225. pAct = new ACT_ITEM;
  226. if (NULL == pAct)
  227. {
  228. hr = E_OUTOFMEMORY;
  229. goto exit;
  230. }
  231. hr = _HrGetDefaultActions(pAct, 1);
  232. if (FAILED(hr))
  233. {
  234. goto exit;
  235. }
  236. pvarResult->vt = VT_BLOB;
  237. pvarResult->blob.cbSize = sizeof(ACT_ITEM);
  238. pvarResult->blob.pBlobData = (BYTE *) pAct;
  239. pAct = NULL;
  240. break;
  241. case RULE_PROP_JUNKPCT:
  242. pvarResult->vt = VT_UI4;
  243. pvarResult->ulVal = m_dwJunkPct;
  244. break;
  245. case RULE_PROP_EXCPT_WAB:
  246. pvarResult->vt = VT_BOOL;
  247. pvarResult->boolVal = !!(0 != (m_dwState & RULE_STATE_EXCPT_WAB));
  248. break;
  249. default:
  250. hr = E_INVALIDARG;
  251. goto exit;
  252. }
  253. // Set the return value
  254. hr = S_OK;
  255. exit:
  256. SafeMemFree(pszName);
  257. RuleUtil_HrFreeCriteriaItem(pCrit, 1);
  258. SafeMemFree(pCrit);
  259. RuleUtil_HrFreeActionsItem(pAct, cItem);
  260. SafeMemFree(pAct);
  261. return hr;
  262. }
  263. STDMETHODIMP COEJunkRule::SetProp(RULE_PROP prop, DWORD dwFlags, PROPVARIANT * pvarResult)
  264. {
  265. HRESULT hr = S_OK;
  266. // Check incoming params
  267. if (NULL == pvarResult)
  268. {
  269. hr = E_INVALIDARG;
  270. goto exit;
  271. }
  272. switch(prop)
  273. {
  274. case RULE_PROP_DISABLED:
  275. if (VT_BOOL != pvarResult->vt)
  276. {
  277. hr = E_INVALIDARG;
  278. goto exit;
  279. }
  280. // Set the new value
  281. if (FALSE != !!(pvarResult->boolVal))
  282. {
  283. m_dwState |= RULE_STATE_DISABLED;
  284. }
  285. else
  286. {
  287. Assert(0 == (m_dwState & RULE_STATE_INVALID));
  288. m_dwState &= ~RULE_STATE_DISABLED;
  289. }
  290. break;
  291. case RULE_PROP_JUNKPCT:
  292. if (VT_UI4 != pvarResult->vt)
  293. {
  294. hr = E_INVALIDARG;
  295. goto exit;
  296. }
  297. // Set the new value
  298. m_dwJunkPct = pvarResult->ulVal;
  299. break;
  300. case RULE_PROP_EXCPT_WAB:
  301. if (VT_BOOL != pvarResult->vt)
  302. {
  303. hr = E_INVALIDARG;
  304. goto exit;
  305. }
  306. // Set the new value
  307. if (FALSE != !!(pvarResult->boolVal))
  308. {
  309. m_dwState |= RULE_STATE_EXCPT_WAB;
  310. }
  311. else
  312. {
  313. m_dwState &= ~RULE_STATE_EXCPT_WAB;
  314. }
  315. break;
  316. default:
  317. hr = E_INVALIDARG;
  318. goto exit;
  319. }
  320. // Mark the rule as dirty
  321. m_dwState |= RULE_STATE_DIRTY;
  322. // Set the return value
  323. hr = S_OK;
  324. exit:
  325. return hr;
  326. }
  327. STDMETHODIMP COEJunkRule::Evaluate(LPCSTR pszAcct, MESSAGEINFO * pMsgInfo, IMessageFolder * pFolder,
  328. IMimePropertySet * pIMPropSet, IMimeMessage * pIMMsg, ULONG cbMsgSize,
  329. ACT_ITEM ** ppActions, ULONG * pcActions)
  330. {
  331. HRESULT hr = S_OK;
  332. DOUBLE dblProb = 0.0;
  333. ACT_ITEM * pAct = NULL;
  334. ULONG cAct = 0;
  335. DWORD dwFlags = 0;
  336. IMimeMessage * pIMMsgNew = NULL;
  337. // Check incoming variables
  338. if (((NULL == pMsgInfo) && (NULL == pIMPropSet)) || ((NULL == pIMMsg) && ((NULL == pMsgInfo) || (NULL == pFolder))) ||
  339. (NULL == ppActions) || (NULL == pcActions))
  340. {
  341. hr = E_INVALIDARG;
  342. goto exit;
  343. }
  344. // Set outgoing params to default
  345. *ppActions = NULL;
  346. *pcActions = 0;
  347. // Load up the junk mail filter
  348. hr = _HrLoadJunkFilter();
  349. if (FAILED(hr))
  350. {
  351. hr = S_FALSE;
  352. goto exit;
  353. }
  354. // Set the spam threshold
  355. hr = _HrSetSpamThresh();
  356. if (FAILED(hr))
  357. {
  358. goto exit;
  359. }
  360. if (NULL != pIMMsg)
  361. {
  362. // Hold onto the message
  363. pIMMsgNew = pIMMsg;
  364. pIMMsgNew->AddRef();
  365. }
  366. else
  367. {
  368. // Get the message
  369. hr = pFolder->OpenMessage(pMsgInfo->idMessage, 0, &pIMMsgNew, NOSTORECALLBACK);
  370. if (FAILED(hr))
  371. {
  372. goto exit;
  373. }
  374. }
  375. // Do we need to see if this is in the WAB
  376. if (0 != (m_dwState & RULE_STATE_EXCPT_WAB))
  377. {
  378. if (S_OK == _HrIsSenderInWAB(pIMMsgNew))
  379. {
  380. hr = S_FALSE;
  381. goto exit;
  382. }
  383. }
  384. // Check to see if it's in the exceptions list
  385. if (NULL != m_pIAddrList)
  386. {
  387. hr = m_pIAddrList->Match(RALF_MAIL, pMsgInfo, pIMMsgNew);
  388. if (FAILED(hr))
  389. {
  390. goto exit;
  391. }
  392. // If we found a match then we are done
  393. if (S_OK == hr)
  394. {
  395. hr = S_FALSE;
  396. goto exit;
  397. }
  398. }
  399. // Figure out the proper flags
  400. hr = _HrGetSpamFlags(pszAcct, pIMMsgNew, &dwFlags);
  401. if (FAILED(hr))
  402. {
  403. goto exit;
  404. }
  405. // Is it Spam?
  406. hr = m_pIJunkFilter->CalcJunkProb(dwFlags, pIMPropSet, pIMMsgNew, &dblProb);
  407. if (FAILED(hr))
  408. {
  409. goto exit;
  410. }
  411. // If we didn't match then just return
  412. if (S_FALSE == hr)
  413. {
  414. goto exit;
  415. }
  416. // Create an action
  417. pAct = new ACT_ITEM;
  418. if (NULL == pAct)
  419. {
  420. hr = E_FAIL;
  421. goto exit;
  422. }
  423. cAct = 1;
  424. // Grab the actions and return them to the caller
  425. hr = _HrGetDefaultActions(pAct, cAct);
  426. if (FAILED(hr))
  427. {
  428. goto exit;
  429. }
  430. // Set the outgoing parameters
  431. *ppActions = pAct;
  432. pAct = NULL;
  433. *pcActions = cAct;
  434. // Set proper return value
  435. hr = S_OK;
  436. exit:
  437. RuleUtil_HrFreeActionsItem(pAct, cAct);
  438. SafeMemFree(pAct);
  439. SafeRelease(pIMMsgNew);
  440. return hr;
  441. }
  442. STDMETHODIMP COEJunkRule::LoadReg(LPCSTR pszRegPath)
  443. {
  444. HRESULT hr = S_OK;
  445. LONG lErr = 0;
  446. HKEY hkeyRoot = NULL;
  447. ULONG cbData = 0;
  448. ULONG cbRead = 0;
  449. DWORD dwData = 0;
  450. BOOL fDisabled = FALSE;
  451. LPSTR pszRegPathNew = NULL;
  452. ULONG cchRegPath = 0;
  453. // Check incoming param
  454. if (NULL == pszRegPath)
  455. {
  456. hr = E_INVALIDARG;
  457. goto exit;
  458. }
  459. // Should we fail if we're already loaded?
  460. AssertSz(0 == (m_dwState & RULE_STATE_LOADED), "We're already loaded!!!");
  461. // Open the reg key from the path
  462. lErr = AthUserOpenKey(pszRegPath, KEY_ALL_ACCESS, &hkeyRoot);
  463. if (ERROR_SUCCESS != lErr)
  464. {
  465. hr = E_FAIL;
  466. goto exit;
  467. }
  468. // Allocate space to hold the new reg path
  469. cchRegPath = lstrlen(pszRegPath);
  470. DWORD cchSize = (cchRegPath + lstrlen(c_szRulesExcpts) + 2);
  471. if (FAILED(HrAlloc((void **) &pszRegPathNew, cchSize)))
  472. {
  473. goto exit;
  474. }
  475. // Build reg path to criteria
  476. StrCpyN(pszRegPathNew, pszRegPath, cchSize);
  477. if ('\\' != pszRegPath[cchRegPath])
  478. {
  479. StrCatBuff(pszRegPathNew, g_szBackSlash, cchSize);
  480. cchRegPath++;
  481. }
  482. StrCatBuff(pszRegPathNew, c_szRulesExcpts, cchSize);
  483. // Get the Exceptions List
  484. hr = m_pIAddrList->LoadList(pszRegPathNew);
  485. if (FAILED(hr))
  486. {
  487. goto exit;
  488. }
  489. // Get the enabled state
  490. if (FALSE != DwGetOption(OPT_FILTERJUNK))
  491. {
  492. m_dwState &= ~RULE_STATE_DISABLED;
  493. }
  494. else
  495. {
  496. m_dwState |= RULE_STATE_DISABLED;
  497. }
  498. // Get the junk percent
  499. m_dwJunkPct = DwGetOption(OPT_JUNKPCT);
  500. // Get the WAB Exception state
  501. if (FALSE != DwGetOption(OPT_EXCEPTIONS_WAB))
  502. {
  503. m_dwState |= RULE_STATE_EXCPT_WAB;
  504. }
  505. else
  506. {
  507. m_dwState &= ~RULE_STATE_EXCPT_WAB;
  508. }
  509. // Make sure we clear the dirty bit
  510. m_dwState &= ~RULE_STATE_DIRTY;
  511. // Note that we have been loaded
  512. m_dwState |= RULE_STATE_LOADED;
  513. // Set the return value
  514. hr = S_OK;
  515. exit:
  516. SafeMemFree(pszRegPathNew);
  517. if (NULL != hkeyRoot)
  518. {
  519. RegCloseKey(hkeyRoot);
  520. }
  521. return hr;
  522. }
  523. STDMETHODIMP COEJunkRule::SaveReg(LPCSTR pszRegPath, BOOL fClearDirty)
  524. {
  525. HRESULT hr = S_OK;
  526. LONG lErr = 0;
  527. HKEY hkeyRoot = NULL;
  528. DWORD dwDisp = 0;
  529. DWORD dwData = 0;
  530. LPSTR pszRegPathNew = NULL;
  531. ULONG cchRegPath = 0;
  532. // Check incoming param
  533. if (NULL == pszRegPath)
  534. {
  535. hr = E_INVALIDARG;
  536. goto exit;
  537. }
  538. // Can't save out a rule if we don't have criteria or actions
  539. // or a rule name
  540. if (NULL == m_pIAddrList)
  541. {
  542. hr = E_FAIL;
  543. goto exit;
  544. }
  545. // Let's make sure we clear out the key first
  546. AthUserDeleteKey(pszRegPath);
  547. // Create the reg key from the path
  548. lErr = AthUserCreateKey(pszRegPath, KEY_ALL_ACCESS, &hkeyRoot, &dwDisp);
  549. if (ERROR_SUCCESS != lErr)
  550. {
  551. hr = E_FAIL;
  552. goto exit;
  553. }
  554. Assert(REG_CREATED_NEW_KEY == dwDisp);
  555. // Set the enabled state
  556. SetDwOption(OPT_FILTERJUNK, (DWORD) !(0 != (m_dwState & RULE_STATE_DISABLED)), NULL, 0);
  557. // Set the junk percent
  558. SetDwOption(OPT_JUNKPCT, m_dwJunkPct, NULL, 0);
  559. // Set the WAB Exception state
  560. SetDwOption(OPT_EXCEPTIONS_WAB, (DWORD) (0 != (m_dwState & RULE_STATE_EXCPT_WAB)), NULL, 0);
  561. // Allocate space to hold the new reg path
  562. cchRegPath = lstrlen(pszRegPath);
  563. DWORD cchSize = (cchRegPath + lstrlen(c_szRulesExcpts) + 2);
  564. if (FAILED(HrAlloc((void **) &pszRegPathNew, cchSize)))
  565. {
  566. goto exit;
  567. }
  568. // Build reg path to criteria
  569. StrCpyN(pszRegPathNew, pszRegPath, cchSize);
  570. if ('\\' != pszRegPath[cchRegPath])
  571. {
  572. StrCatBuff(pszRegPathNew, g_szBackSlash, cchSize);
  573. cchRegPath++;
  574. }
  575. StrCatBuff(pszRegPathNew, c_szRulesExcpts, cchSize);
  576. // Write out the Exceptions List
  577. hr = m_pIAddrList->SaveList(pszRegPathNew, fClearDirty);
  578. if (FAILED(hr))
  579. {
  580. goto exit;
  581. }
  582. // Should we clear the dirty bit?
  583. if (FALSE != fClearDirty)
  584. {
  585. m_dwState &= ~RULE_STATE_DIRTY;
  586. }
  587. // Set the return value
  588. hr = S_OK;
  589. exit:
  590. SafeMemFree(pszRegPathNew);
  591. if (NULL != hkeyRoot)
  592. {
  593. RegCloseKey(hkeyRoot);
  594. }
  595. return hr;
  596. }
  597. STDMETHODIMP COEJunkRule::Clone(IOERule ** ppIRule)
  598. {
  599. HRESULT hr = S_OK;
  600. COEJunkRule * pRule = NULL;
  601. IOERuleAddrList * pIAddrList = NULL;
  602. RULEADDRLIST * pralList = NULL;
  603. ULONG cralList = 0;
  604. // Check incoming params
  605. if (NULL == ppIRule)
  606. {
  607. hr = E_INVALIDARG;
  608. goto exit;
  609. }
  610. // Initialize the outgoing params
  611. *ppIRule = NULL;
  612. // Create a new rule
  613. pRule = new COEJunkRule;
  614. if (NULL == pRule)
  615. {
  616. hr = E_OUTOFMEMORY;
  617. goto exit;
  618. }
  619. // Note that we have a reference
  620. pRule->AddRef();
  621. // Initialize the junk rule
  622. hr = pRule->HrInit(c_szJunkDll, c_szJunkFile);
  623. if (FAILED(hr))
  624. {
  625. goto exit;
  626. }
  627. // Set the WAB Exception state
  628. if (0 != (m_dwState & RULE_STATE_DISABLED))
  629. {
  630. pRule->m_dwState |= RULE_STATE_DISABLED;
  631. }
  632. else
  633. {
  634. pRule->m_dwState &= ~RULE_STATE_DISABLED;
  635. }
  636. // Set the junk percent
  637. pRule->m_dwJunkPct = m_dwJunkPct;
  638. // Set the WAB Exception state
  639. if (0 != (m_dwState & RULE_STATE_EXCPT_WAB))
  640. {
  641. pRule->m_dwState |= RULE_STATE_EXCPT_WAB;
  642. }
  643. else
  644. {
  645. pRule->m_dwState &= ~RULE_STATE_EXCPT_WAB;
  646. }
  647. // Do we have an Exceptions List?
  648. if (NULL != m_pIAddrList)
  649. {
  650. // Get the interface from the new object
  651. hr = pRule->QueryInterface(IID_IOERuleAddrList, (void **) &pIAddrList);
  652. if (FAILED(hr))
  653. {
  654. goto exit;
  655. }
  656. // Get the list of exceptions
  657. hr = m_pIAddrList->GetList(0, &pralList, &cralList);
  658. if (FAILED(hr))
  659. {
  660. goto exit;
  661. }
  662. // Set the list of exceptions
  663. hr = pIAddrList->SetList(0, pralList, cralList);
  664. if (FAILED(hr))
  665. {
  666. goto exit;
  667. }
  668. }
  669. // Get the rule interface
  670. hr = pRule->QueryInterface(IID_IOERule, (void **) ppIRule);
  671. if (FAILED(hr))
  672. {
  673. goto exit;
  674. }
  675. // Set the proper return value
  676. hr = S_OK;
  677. exit:
  678. FreeRuleAddrList(pralList, cralList);
  679. SafeMemFree(pralList);
  680. SafeRelease(pIAddrList);
  681. SafeRelease(pRule);
  682. return hr;
  683. }
  684. ///////////////////////////////////////////////////////////////////////////////
  685. //
  686. // HrInit
  687. //
  688. // This initializes the junk rule.
  689. //
  690. // ppIRule - pointer to return the junk rule
  691. //
  692. // Returns: S_OK, on success
  693. // E_OUTOFMEMORY, if can't create the JunkRule object
  694. //
  695. ///////////////////////////////////////////////////////////////////////////////
  696. HRESULT COEJunkRule::HrInit(LPCSTR pszJunkDll, LPCSTR pszDataFile)
  697. {
  698. HRESULT hr = S_OK;
  699. IUnknown * pIUnkOuter = NULL;
  700. IUnknown * pIUnkInner = NULL;
  701. IOERuleAddrList * pIAddrList = NULL;
  702. // Check the incoming params
  703. if ((NULL == pszJunkDll) || (NULL == pszDataFile))
  704. {
  705. hr = E_INVALIDARG;
  706. goto exit;
  707. }
  708. // If we've already been initialized
  709. if (0 != (m_dwState & RULE_STATE_INIT))
  710. {
  711. hr = E_UNEXPECTED;
  712. goto exit;
  713. }
  714. Assert(NULL == m_hinst);
  715. // Safe off the paths
  716. m_pszJunkDll = PszDupA(pszJunkDll);
  717. if (NULL == m_pszJunkDll)
  718. {
  719. hr = E_OUTOFMEMORY;
  720. goto exit;
  721. }
  722. m_pszDataFile = PszDupA(pszDataFile);
  723. if (NULL == m_pszDataFile)
  724. {
  725. hr = E_OUTOFMEMORY;
  726. goto exit;
  727. }
  728. // Create an address list object
  729. pIUnkOuter = static_cast<IUnknown *> (this);
  730. hr = HrCreateAddrList(pIUnkOuter, IID_IUnknown, (void **) &pIUnkInner);
  731. if (FAILED(hr))
  732. {
  733. goto exit;
  734. }
  735. // Get the Rule Address list interface
  736. hr = pIUnkInner->QueryInterface(IID_IOERuleAddrList, (VOID **) &pIAddrList);
  737. if (FAILED(hr))
  738. {
  739. goto exit;
  740. }
  741. // Save off the address list
  742. m_pIAddrList = pIAddrList;
  743. // Save off the inner IUnknown
  744. m_pIUnkInner = pIUnkInner;
  745. pIUnkInner = NULL;
  746. // Note that wab exceptions is on by default
  747. m_dwState |= RULE_STATE_EXCPT_WAB;
  748. // Note that we have been initialized
  749. m_dwState |= RULE_STATE_INIT;
  750. // Set the proper return value
  751. hr = S_OK;
  752. exit:
  753. if (NULL != pIAddrList)
  754. {
  755. SafeRelease(pIUnkOuter);
  756. }
  757. SafeRelease(pIUnkInner);
  758. return hr;
  759. }
  760. HRESULT COEJunkRule::_HrGetDefaultActions(ACT_ITEM * pAct, ULONG cAct)
  761. {
  762. HRESULT hr = S_OK;
  763. FOLDERINFO fldinfo = {0};
  764. RULEFOLDERDATA * prfdData = NULL;
  765. STOREUSERDATA UserData = {0};
  766. // Check incoming vars
  767. if ((NULL == pAct) || (0 == cAct))
  768. {
  769. hr = E_INVALIDARG;
  770. goto exit;
  771. }
  772. // Initialize the outgoing params
  773. ZeroMemory(pAct, cAct * sizeof(*pAct));
  774. // Fill up the action
  775. pAct->type = ACT_TYPE_JUNKMAIL;
  776. pAct->dwFlags = ACT_FLAG_DEFAULT;
  777. pAct->propvar.vt = VT_EMPTY;
  778. hr = S_OK;
  779. exit:
  780. return hr;
  781. }
  782. HRESULT COEJunkRule::_HrSetSpamThresh(VOID)
  783. {
  784. HRESULT hr = S_OK;
  785. ULONG ulThresh = 0;
  786. // If we haven't been loaded
  787. if (0 == (m_dwState & RULE_STATE_DATA_LOADED))
  788. {
  789. hr = E_UNEXPECTED;
  790. goto exit;
  791. }
  792. // Get the threshold
  793. switch (m_dwJunkPct)
  794. {
  795. case 0:
  796. ulThresh = STF_USE_MOST;
  797. break;
  798. case 1:
  799. ulThresh = STF_USE_MORE;
  800. break;
  801. case 2:
  802. ulThresh = STF_USE_DEFAULT;
  803. break;
  804. case 3:
  805. ulThresh = STF_USE_LESS;
  806. break;
  807. case 4:
  808. ulThresh = STF_USE_LEAST;
  809. break;
  810. default:
  811. hr = E_INVALIDARG;
  812. goto exit;
  813. }
  814. // Set the threshold
  815. hr = m_pIJunkFilter->SetSpamThresh(ulThresh);
  816. if (FAILED(hr))
  817. {
  818. goto exit;
  819. }
  820. hr = S_OK;
  821. exit:
  822. return hr;
  823. }
  824. HRESULT COEJunkRule::_HrGetSpamFlags(LPCSTR pszAcct, IMimeMessage * pIMMsg, DWORD * pdwFlags)
  825. {
  826. HRESULT hr = S_OK;
  827. IImnAccount * pAccount = NULL;
  828. CHAR szEmailAddress[CCHMAX_EMAIL_ADDRESS];
  829. CHAR szReplyToAddress[CCHMAX_EMAIL_ADDRESS];
  830. ADDRESSLIST rAddrList ={0};
  831. ULONG ulIndex = 0;
  832. BOOL fFound = FALSE;
  833. Assert(NULL != g_pAcctMan);
  834. // Initialize the flags
  835. *pdwFlags = 0;
  836. // Get the account
  837. hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAcct, &pAccount);
  838. // If we couldn't find the account, then just use the default
  839. if (FAILED(hr))
  840. {
  841. hr = g_pAcctMan->GetDefaultAccount(ACCT_MAIL, &pAccount);
  842. if (FAILED(hr))
  843. {
  844. goto exit;
  845. }
  846. }
  847. // Get the default address on the account
  848. if (FAILED(pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szEmailAddress, sizeof(szEmailAddress))))
  849. {
  850. szEmailAddress[0] = '\0';
  851. }
  852. // Get the reply to address on the account
  853. if (FAILED(pAccount->GetPropSz(AP_SMTP_REPLY_EMAIL_ADDRESS, szReplyToAddress, sizeof(szReplyToAddress))))
  854. {
  855. szReplyToAddress[0] = '\0';
  856. }
  857. // Get the addresses
  858. hr = pIMMsg->GetAddressTypes(IAT_TO | IAT_CC | IAT_BCC, IAP_EMAIL, &rAddrList);
  859. if (FAILED(hr))
  860. {
  861. goto exit;
  862. }
  863. // Search through the address list
  864. for (ulIndex = 0; ulIndex < rAddrList.cAdrs; ulIndex++)
  865. {
  866. // Skip blank addresses
  867. if (NULL == rAddrList.prgAdr[ulIndex].pszEmail)
  868. {
  869. continue;
  870. }
  871. // Search for the email address
  872. if ('\0' != szEmailAddress[0])
  873. {
  874. fFound = !!(0 == lstrcmpi(rAddrList.prgAdr[ulIndex].pszEmail, szEmailAddress));
  875. }
  876. // Search for the reply to address
  877. if ((FALSE == fFound) && ('\0' != szReplyToAddress[0]))
  878. {
  879. fFound = !!(0 == lstrcmpi(rAddrList.prgAdr[ulIndex].pszEmail, szReplyToAddress));
  880. }
  881. if (FALSE != fFound)
  882. {
  883. break;
  884. }
  885. }
  886. // If we found something
  887. if (FALSE != fFound)
  888. {
  889. *pdwFlags |= CJPF_SENT_TO_ME;
  890. }
  891. // Set the return value
  892. hr = S_OK;
  893. exit:
  894. g_pMoleAlloc->FreeAddressList(&rAddrList);
  895. SafeRelease(pAccount);
  896. return hr;
  897. }
  898. HRESULT COEJunkRule::_HrIsSenderInWAB(IMimeMessage * pIMMsg)
  899. {
  900. HRESULT hr = S_OK;
  901. IMimeAddressTable * pIAddrTable = NULL;
  902. ADDRESSPROPS rSender = {0};
  903. LPWAB pWAB = NULL;
  904. LPADRBOOK pAddrBook = NULL;
  905. LPWABOBJECT pWabObject = NULL;
  906. ULONG cbeidWAB = 0;
  907. LPENTRYID peidWAB = NULL;
  908. ULONG ulDummy = 0;
  909. LPABCONT pabcWAB = NULL;
  910. ADRLIST * pAddrList = NULL;
  911. FlagList rFlagList = {0};
  912. Assert(NULL != pIMMsg);
  913. // Get the address table from the message
  914. hr = pIMMsg->GetAddressTable(&pIAddrTable);
  915. if (FAILED(hr))
  916. {
  917. hr = S_FALSE;
  918. goto exit;
  919. }
  920. // Get the sender of the message
  921. rSender.dwProps = IAP_EMAIL;
  922. hr = pIAddrTable->GetSender(&rSender);
  923. if (FAILED(hr))
  924. {
  925. hr = S_FALSE;
  926. goto exit;
  927. }
  928. // If the sender is empty,
  929. // then we are done...
  930. if ((NULL == rSender.pszEmail) || ('\0' == rSender.pszEmail[0]))
  931. {
  932. hr = S_FALSE;
  933. goto exit;
  934. }
  935. // Get the WAB
  936. hr = HrCreateWabObject(&pWAB);
  937. if (FAILED(hr))
  938. {
  939. goto exit;
  940. }
  941. // Get the AB object
  942. hr = pWAB->HrGetAdrBook(&pAddrBook);
  943. if (FAILED(hr))
  944. {
  945. goto exit;
  946. }
  947. hr = pWAB->HrGetWabObject(&pWabObject);
  948. if (FAILED(hr))
  949. {
  950. goto exit;
  951. }
  952. // Get the PAB
  953. hr = pAddrBook->GetPAB(&cbeidWAB, &peidWAB);
  954. if (FAILED(hr))
  955. {
  956. goto exit;
  957. }
  958. // Get the address container
  959. hr = pAddrBook->OpenEntry(cbeidWAB, peidWAB, NULL, 0, &ulDummy, (IUnknown **) (&pabcWAB));
  960. if (FAILED(hr))
  961. {
  962. goto exit;
  963. }
  964. // Allocate space to hold the address list
  965. hr = pWabObject->AllocateBuffer(sizeof(ADRLIST), (VOID **)&(pAddrList));
  966. if (FAILED(hr))
  967. {
  968. goto exit;
  969. }
  970. // Initialize the Address list
  971. Assert(NULL != pAddrList);
  972. pAddrList->cEntries = 1;
  973. pAddrList->aEntries[0].ulReserved1 = 0;
  974. pAddrList->aEntries[0].cValues = 1;
  975. // Allocate space to hold the address props
  976. hr = pWabObject->AllocateBuffer(sizeof(SPropValue), (VOID **)&(pAddrList->aEntries[0].rgPropVals));
  977. if (FAILED(hr))
  978. {
  979. goto exit;
  980. }
  981. // Initialize the address props
  982. pAddrList->aEntries[0].rgPropVals[0].ulPropTag = PR_EMAIL_ADDRESS;
  983. pAddrList->aEntries[0].rgPropVals[0].Value.LPSZ = rSender.pszEmail;
  984. // Resolve the sender address
  985. rFlagList.cFlags = 1;
  986. hr = pabcWAB->ResolveNames(NULL, WAB_RESOLVE_ALL_EMAILS, pAddrList, &rFlagList);
  987. if (FAILED(hr))
  988. {
  989. goto exit;
  990. }
  991. // Check to see if it was found
  992. if ((MAPI_RESOLVED == rFlagList.ulFlag[0]) || (MAPI_AMBIGUOUS == rFlagList.ulFlag[0]))
  993. {
  994. hr = S_OK;
  995. }
  996. else
  997. {
  998. hr = S_FALSE;
  999. }
  1000. exit:
  1001. if (pAddrList)
  1002. {
  1003. for (ULONG ul = 0; ul < pAddrList->cEntries; ul++)
  1004. pWabObject->FreeBuffer(pAddrList->aEntries[ul].rgPropVals);
  1005. pWabObject->FreeBuffer(pAddrList);
  1006. }
  1007. SafeRelease(pabcWAB);
  1008. if (NULL != peidWAB)
  1009. {
  1010. pWabObject->FreeBuffer(peidWAB);
  1011. }
  1012. SafeRelease(pWAB);
  1013. g_pMoleAlloc->FreeAddressProps(&rSender);
  1014. SafeRelease(pIAddrTable);
  1015. return hr;
  1016. }
  1017. HRESULT COEJunkRule::_HrLoadJunkFilter(VOID)
  1018. {
  1019. HRESULT hr = S_OK;
  1020. ULONG cbData = 0;
  1021. LPSTR pszPath = NULL;
  1022. ULONG cchPath = 0;
  1023. TYP_HrCreateJunkFilter pfnHrCreateJunkFilter = NULL;
  1024. IOEJunkFilter * pIJunk = NULL;
  1025. LPSTR pszFirst = NULL;
  1026. LPSTR pszLast = NULL;
  1027. LPSTR pszCompany = NULL;
  1028. // If we haven't been initialized yet
  1029. if (0 == (m_dwState & RULE_STATE_INIT))
  1030. {
  1031. hr = E_UNEXPECTED;
  1032. goto exit;
  1033. }
  1034. // If we've already been loaded, we're done
  1035. if (0 != (m_dwState & RULE_STATE_DATA_LOADED))
  1036. {
  1037. hr = S_FALSE;
  1038. goto exit;
  1039. }
  1040. Assert(NULL != m_pszJunkDll);
  1041. Assert(NULL != m_pszDataFile);
  1042. // Get the size of the path to Outlook Express
  1043. if (ERROR_SUCCESS != SHGetValue(HKEY_LOCAL_MACHINE, STR_REG_PATH_FLAT, "InstallRoot", NULL, NULL, &cbData))
  1044. {
  1045. hr = E_FAIL;
  1046. goto exit;
  1047. }
  1048. // How much room do we need to build up the path
  1049. cbData += max(lstrlen(m_pszJunkDll), lstrlen(m_pszDataFile)) + 2;
  1050. // Allocate space to hold the path
  1051. hr = HrAlloc((VOID **) &pszPath, cbData);
  1052. if (FAILED(hr))
  1053. {
  1054. goto exit;
  1055. }
  1056. // Get the path to Outlook Express
  1057. if (ERROR_SUCCESS != SHGetValue(HKEY_LOCAL_MACHINE, STR_REG_PATH_FLAT, "InstallRoot", NULL, (BYTE *) pszPath, &cbData))
  1058. {
  1059. hr = E_FAIL;
  1060. goto exit;
  1061. }
  1062. // Build up the path to the Junk DLL
  1063. StrCatBuff(pszPath, g_szBackSlash, cbData);
  1064. cchPath = lstrlen(pszPath);
  1065. StrCpyN(&(pszPath[cchPath]), m_pszJunkDll, (cbData-cchPath));
  1066. // Load the Dll
  1067. Assert(NULL == m_hinst);
  1068. m_hinst = LoadLibrary(pszPath);
  1069. if (NULL == m_hinst)
  1070. {
  1071. AssertSz(FALSE, "Can't find the Dll");
  1072. hr = E_FAIL;
  1073. goto exit;
  1074. }
  1075. // Find the entry points
  1076. pfnHrCreateJunkFilter = (TYP_HrCreateJunkFilter) GetProcAddress(m_hinst, c_szHrCreateJunkFilter);
  1077. if (NULL == pfnHrCreateJunkFilter)
  1078. {
  1079. AssertSz(FALSE, "Can't find the function HrCreateJunkFilter");
  1080. hr = E_FAIL;
  1081. goto exit;
  1082. }
  1083. // Get the junk filter
  1084. hr = pfnHrCreateJunkFilter(0, &pIJunk);
  1085. if (FAILED(hr))
  1086. {
  1087. goto exit;
  1088. }
  1089. // Build up the path to the Junk DLL data file
  1090. StrCpyN(&(pszPath[cchPath]), m_pszDataFile, (cbData-cchPath));
  1091. // Load the test file
  1092. hr = pIJunk->LoadDataFile(pszPath);
  1093. if (FAILED(hr))
  1094. {
  1095. goto exit;
  1096. }
  1097. // Get user specifics
  1098. RuleUtil_HrGetUserData(0, &pszFirst, &pszLast, &pszCompany);
  1099. // Set the user specifics
  1100. hr = pIJunk->SetIdentity(pszFirst, pszLast, pszCompany);
  1101. if (FAILED(hr))
  1102. {
  1103. goto exit;
  1104. }
  1105. // Save of the data
  1106. m_pIJunkFilter = pIJunk;
  1107. pIJunk = NULL;
  1108. // Note that we've loaded the data
  1109. m_dwState |= RULE_STATE_DATA_LOADED;
  1110. // Set the return value
  1111. hr = S_OK;
  1112. exit:
  1113. SafeMemFree(pszCompany);
  1114. SafeMemFree(pszLast);
  1115. SafeMemFree(pszFirst);
  1116. SafeRelease(pIJunk);
  1117. SafeMemFree(pszPath);
  1118. return hr;
  1119. }