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.

6532 lines
184 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // RuleUtil.cpp
  4. //
  5. ///////////////////////////////////////////////////////////////////////////////
  6. #include <pch.hxx>
  7. #include "ruleutil.h"
  8. #include "rulesmgr.h"
  9. #include "rulesui.h"
  10. #include "editrule.h"
  11. #include "spamui.h"
  12. #include "viewsui.h"
  13. #include "rule.h"
  14. #include <msoeobj.h>
  15. #include <xpcomm.h>
  16. #include <ipab.h>
  17. #include <pop3task.h>
  18. #include <msgfldr.h>
  19. #include <mimeolep.h>
  20. #include <storecb.h>
  21. #include <menures.h>
  22. #include <hotlinks.h>
  23. #include <menuutil.h>
  24. #include <mru.h>
  25. #include <options.h>
  26. #include <mailutil.h>
  27. #include <secutil.h>
  28. #include "shlwapip.h"
  29. #include "reutil.h"
  30. #include <demand.h>
  31. // Typedefs
  32. typedef enum tagDEF_CRIT_TYPE
  33. {
  34. DEF_CRIT_ALLMSGS = 0,
  35. DEF_CRIT_READ,
  36. DEF_CRIT_DWNLDMSGS,
  37. DEF_CRIT_IGNTHDS
  38. } DEF_CRIT_TYPE;
  39. typedef enum tagDEF_ACT_TYPE
  40. {
  41. DEF_ACT_SHOWMSGS = 0,
  42. DEF_ACT_HIDEMSGS
  43. } DEF_ACT_TYPE;
  44. typedef struct tagDEFAULT_RULE
  45. {
  46. // The rule handle
  47. RULEID ridRule;
  48. // The rule name
  49. UINT idName;
  50. // Which type of criteria for the rule
  51. DEF_CRIT_TYPE critType;
  52. // Which type of actions for the rule
  53. DEF_ACT_TYPE actType;
  54. // The current version number for the rule
  55. DWORD dwVersion;
  56. } DEFAULT_RULE, * PDEFAULT_RULE;
  57. // Constants
  58. static const ULONG CDEF_CRIT_ITEM_MAX = 2;
  59. static const ULONG CDEF_ACT_ITEM_MAX = 1;
  60. static const DWORD DEFAULT_RULE_VERSION = 0x00000004;
  61. static const DEFAULT_RULE g_defruleFilters[] =
  62. {
  63. {RULEID_VIEW_ALL, idsViewAllMessages, DEF_CRIT_ALLMSGS, DEF_ACT_SHOWMSGS, DEFAULT_RULE_VERSION},
  64. {RULEID_VIEW_UNREAD, idsViewUnread, DEF_CRIT_READ, DEF_ACT_HIDEMSGS, DEFAULT_RULE_VERSION},
  65. {RULEID_VIEW_DOWNLOADED, idsViewDownloaded, DEF_CRIT_DWNLDMSGS, DEF_ACT_SHOWMSGS, DEFAULT_RULE_VERSION},
  66. {RULEID_VIEW_IGNORED, idsViewNoIgnored, DEF_CRIT_IGNTHDS, DEF_ACT_HIDEMSGS, DEFAULT_RULE_VERSION}
  67. };
  68. static const CHAR g_szOrderFilterDef[] = "FFA FFB FFC FFF";
  69. static const ULONG RULE_FILE_VERSION = 0x00050000;
  70. static const char c_szLeftParen[] = "(";
  71. static const char c_szRightParen[] = ")";
  72. static const char c_szDoubleQuote[] = "\"";
  73. static const char c_szLogicalAnd[] = " && ";
  74. static const char c_szLogicalOr[] = " || ";
  75. static const char c_szFilterRead[] = "(0 != (MSGCOL_FLAGS & ARF_READ))";
  76. static const char c_szFilterNotRead[] = "(0 == (MSGCOL_FLAGS & ARF_READ))";
  77. static const char c_szFilterDeleted[] = "(0 != (MSGCOL_FLAGS & ARF_ENDANGERED))";
  78. static const char c_szFilterNotDeleted[] = "(0 == (MSGCOL_FLAGS & ARF_ENDANGERED))";
  79. static const char c_szFilterDownloaded[] = "(0 != (MSGCOL_FLAGS & ARF_HASBODY))";
  80. static const char c_szFilterNotDownloaded[] = "(0 == (MSGCOL_FLAGS & ARF_HASBODY))";
  81. static const char c_szFilterWatched[] = "(0 != (MSGCOL_FLAGS & ARF_WATCH))";
  82. static const char c_szFilterIgnored[] = "(0 != (MSGCOL_FLAGS & ARF_IGNORE))";
  83. static const char c_szFilterAttach[] = "(0 != (MSGCOL_FLAGS & ARF_HASATTACH))";
  84. static const char c_szFilterSigned[] = "(0 != (MSGCOL_FLAGS & ARF_SIGNED))";
  85. static const char c_szFilterEncrypt[] = "(0 != (MSGCOL_FLAGS & ARF_ENCRYPTED))";
  86. static const char c_szFilterFlagged[] = "(0 != (MSGCOL_FLAGS & ARF_FLAGGED))";
  87. static const char c_szFilterNotFlagged[] = "(0 == (MSGCOL_FLAGS & ARF_FLAGGED))";
  88. static const char c_szFilterPriorityHi[] = "(MSGCOL_PRIORITY == IMSG_PRI_HIGH)";
  89. static const char c_szFilterPriorityLo[] = "(MSGCOL_PRIORITY == IMSG_PRI_LOW)";
  90. static const char c_szFilterReplyPost[] = "(0 != IsReplyPostVisible)";
  91. static const char c_szFilterNotReplyPost[] = "(0 == IsReplyPostVisible)";
  92. static const char c_szFilterShowAll[] = "(0 == 0)";
  93. static const char c_szFilterHideAll[] = "(0 != 0)";
  94. static const char c_szFilterHide[] = "0 == ";
  95. static const char c_szFilterShow[] = "0 != ";
  96. static const char c_szEmailFromAddrPrefix[] = "(MSGCOL_EMAILFROM containsi ";
  97. static const char c_szEmailSubjectPrefix[] = "(MSGCOL_SUBJECT containsi ";
  98. static const char c_szEmailAcctPrefix[] = "(MSGCOL_ACCOUNTID containsi ";
  99. static const char c_szEmailFromPrefix[] = "(MSGCOL_DISPLAYFROM containsi ";
  100. static const char c_szEmailLinesPrefix[] = "(MSGCOL_LINECOUNT > ";
  101. static const char c_szFilterReplyChild[] = "(0 != (MSGCOL_FLAGS & ARF_HASCHILDREN))";
  102. static const char c_szFilterReplyRoot[] = "(0 != MSGCOL_PARENT)";
  103. static const char c_szEmailAgePrefix[] = "(MessageAgeInDays > ";
  104. void DoMessageRulesDialog(HWND hwnd, DWORD dwFlags)
  105. {
  106. COERulesMgrUI * pRulesMgrUI = NULL;
  107. if (NULL == hwnd)
  108. {
  109. goto exit;
  110. }
  111. // Create the rules UI object
  112. pRulesMgrUI = new COERulesMgrUI;
  113. if (NULL == pRulesMgrUI)
  114. {
  115. goto exit;
  116. }
  117. if (FAILED(pRulesMgrUI->HrInit(hwnd, dwFlags)))
  118. {
  119. goto exit;
  120. }
  121. pRulesMgrUI->HrShow();
  122. exit:
  123. if (NULL != pRulesMgrUI)
  124. {
  125. delete pRulesMgrUI;
  126. }
  127. return;
  128. }
  129. HRESULT HrDoViewsManagerDialog(HWND hwnd, DWORD dwFlags, RULEID * pridRule, BOOL * pfApplyAll)
  130. {
  131. HRESULT hr = S_OK;
  132. COEViewsMgrUI * pViewsMgrUI = NULL;
  133. if ((NULL == hwnd) || (NULL == pfApplyAll))
  134. {
  135. hr = E_INVALIDARG;
  136. goto exit;
  137. }
  138. // Create the rules UI object
  139. pViewsMgrUI = new COEViewsMgrUI;
  140. if (NULL == pViewsMgrUI)
  141. {
  142. hr = E_OUTOFMEMORY;
  143. goto exit;
  144. }
  145. hr = pViewsMgrUI->HrInit(hwnd, dwFlags, pridRule);
  146. if (FAILED(hr))
  147. {
  148. goto exit;
  149. }
  150. hr = pViewsMgrUI->HrShow(pfApplyAll);
  151. exit:
  152. if (NULL != pViewsMgrUI)
  153. {
  154. delete pViewsMgrUI;
  155. }
  156. return hr;
  157. }
  158. ///////////////////////////////////////////////////////////////////////////////
  159. //
  160. // HrCreateRuleFromMessage
  161. //
  162. // This creates a rules editor of the proper type.
  163. //
  164. // hwnd - The owner dialog
  165. // dwFlags - What type of editor to bring up
  166. // pmsginfo - The message information
  167. // pMsgList - The owner of the message
  168. //
  169. // Returns: S_OK, on success
  170. // E_OUTOFMEMORY, if can't create the Rules Manager object
  171. //
  172. ///////////////////////////////////////////////////////////////////////////////
  173. HRESULT HrCreateRuleFromMessage(HWND hwnd, DWORD dwFlags, MESSAGEINFO * pmsginfo, IMimeMessage * pMessage)
  174. {
  175. HRESULT hr = S_OK;
  176. CEditRuleUI * pEditRuleUI = NULL;
  177. IOERule * pIRule = NULL;
  178. UINT uiStrId = 0;
  179. TCHAR szRes[CCHMAX_STRINGRES + 5];
  180. ULONG cchRes = 0;
  181. ULONG ulIndex = 0;
  182. TCHAR szName[CCHMAX_STRINGRES + 5];
  183. RULE_TYPE typeRule = RULE_TYPE_MAIL;
  184. IOERule * pIRuleFound = NULL;
  185. PROPVARIANT propvar = {0};
  186. LPSTR pszEmailFrom = NULL;
  187. ADDRESSPROPS rSender = {0};
  188. RULEINFO infoRule = {0};
  189. BYTE * pBlobData = NULL;
  190. ULONG cbSize = 0;
  191. Assert(NULL != g_pMoleAlloc);
  192. Assert(NULL != g_pRulesMan);
  193. // Check incoming params
  194. if ((NULL == hwnd) || (NULL == pmsginfo))
  195. {
  196. hr = E_INVALIDARG;
  197. goto exit;
  198. }
  199. // Create a rules editor object
  200. pEditRuleUI = new CEditRuleUI;
  201. if (NULL == pEditRuleUI)
  202. {
  203. hr = E_OUTOFMEMORY;
  204. goto exit;
  205. }
  206. // Create a new rule object
  207. hr = HrCreateRule(&pIRule);
  208. if (FAILED(hr))
  209. {
  210. goto exit;
  211. }
  212. // Figure out the string Id
  213. if (0 != (dwFlags & CRFMF_NEWS))
  214. {
  215. uiStrId = idsRuleNewsDefaultName;
  216. typeRule = RULE_TYPE_NEWS;
  217. }
  218. else
  219. {
  220. uiStrId = idsRuleMailDefaultName;
  221. typeRule = RULE_TYPE_MAIL;
  222. }
  223. // Figure out the name of the new rule ...
  224. cchRes = LoadString(g_hLocRes, uiStrId, szRes, ARRAYSIZE(szRes));
  225. if (0 == cchRes)
  226. {
  227. hr = E_FAIL;
  228. goto exit;
  229. }
  230. ulIndex = 1;
  231. wnsprintf(szName, ARRAYSIZE(szName), szRes, ulIndex);
  232. // Make sure the name is unique
  233. while (S_OK == g_pRulesMan->FindRule(szName, typeRule, &pIRuleFound))
  234. {
  235. pIRuleFound->Release();
  236. pIRuleFound = NULL;
  237. ulIndex++;
  238. wnsprintf(szName, ARRAYSIZE(szName), szRes, ulIndex);
  239. }
  240. ZeroMemory(&propvar, sizeof(propvar));
  241. propvar.vt = VT_LPSTR;
  242. propvar.pszVal = szName;
  243. // Set the rule name
  244. hr = pIRule->SetProp(RULE_PROP_NAME, 0, &propvar);
  245. if (FAILED(hr))
  246. {
  247. goto exit;
  248. }
  249. if ((NULL == pmsginfo->pszEmailFrom) || (FALSE != FIsEmpty(pmsginfo->pszEmailFrom)))
  250. {
  251. // Get the load interface from the preview pane object
  252. if (NULL != pMessage)
  253. {
  254. rSender.dwProps = IAP_EMAIL;
  255. pMessage->GetSender(&rSender);
  256. Assert(rSender.pszEmail && ISFLAGSET(rSender.dwProps, IAP_EMAIL));
  257. pszEmailFrom = rSender.pszEmail;
  258. }
  259. }
  260. else
  261. {
  262. pszEmailFrom = pmsginfo->pszEmailFrom;
  263. }
  264. if (NULL != pszEmailFrom)
  265. {
  266. // Create space to hold the email address
  267. if (FALSE == FIsEmpty(pszEmailFrom))
  268. {
  269. cbSize = lstrlen(pszEmailFrom) + 3;
  270. if (SUCCEEDED(HrAlloc((VOID **) &pBlobData, cbSize)))
  271. {
  272. StrCpyN((LPSTR) pBlobData, pszEmailFrom, cbSize);
  273. pBlobData[cbSize - 2] = '\0';
  274. pBlobData[cbSize - 1] = '\0';
  275. }
  276. else
  277. {
  278. cbSize = 0;
  279. }
  280. }
  281. }
  282. if (0 != cbSize)
  283. {
  284. CRIT_ITEM citemFrom;
  285. // Set the default criteria on the rule
  286. ZeroMemory(&citemFrom, sizeof(citemFrom));
  287. citemFrom.type = CRIT_TYPE_FROM;
  288. citemFrom.logic = CRIT_LOGIC_NULL;
  289. citemFrom.dwFlags = CRIT_FLAG_DEFAULT;
  290. citemFrom.propvar.vt = VT_BLOB;
  291. citemFrom.propvar.blob.cbSize = cbSize;
  292. citemFrom.propvar.blob.pBlobData = pBlobData;
  293. ZeroMemory(&propvar, sizeof(propvar));
  294. propvar.vt = VT_BLOB;
  295. propvar.blob.cbSize = sizeof(citemFrom);
  296. propvar.blob.pBlobData = (BYTE *) &citemFrom;
  297. hr = pIRule->SetProp(RULE_PROP_CRITERIA, 0, &propvar);
  298. if (FAILED(hr))
  299. {
  300. goto exit;
  301. }
  302. }
  303. // Initialize the editor object
  304. hr = pEditRuleUI->HrInit(hwnd, ERF_NEWRULE, typeRule, pIRule, NULL);
  305. if (FAILED(hr))
  306. {
  307. goto exit;
  308. }
  309. // Bring up the rules editor UI
  310. hr = pEditRuleUI->HrShow();
  311. if (FAILED(hr))
  312. {
  313. goto exit;
  314. }
  315. if (S_OK == hr)
  316. {
  317. // Initialize the rule info
  318. infoRule.pIRule = pIRule;
  319. infoRule.ridRule = RULEID_INVALID;
  320. // Add the rule to the list of rules
  321. hr = g_pRulesMan->SetRules(SETF_APPEND, typeRule, &infoRule, 1);
  322. if(FAILED(hr))
  323. {
  324. goto exit;
  325. }
  326. }
  327. exit:
  328. SafeMemFree(pBlobData);
  329. g_pMoleAlloc->FreeAddressProps(&rSender);
  330. SafeRelease(pIRule);
  331. if (NULL != pEditRuleUI)
  332. {
  333. delete pEditRuleUI;
  334. }
  335. if (S_OK == hr)
  336. {
  337. AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena),
  338. MAKEINTRESOURCEW(idsRuleAdded), NULL, MB_OK | MB_ICONINFORMATION);
  339. }
  340. else if (FAILED(hr))
  341. {
  342. AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena),
  343. MAKEINTRESOURCEW(idsCreateRuleError), NULL, MB_OK | MB_ICONERROR);
  344. }
  345. return hr;
  346. }
  347. HRESULT HrBlockSendersFromFolder(HWND hwnd, DWORD dwFlags, FOLDERID idFolder, LPSTR * ppszSender, ULONG cpszSender)
  348. {
  349. HRESULT hr = S_OK;
  350. IMessageFolder * pFolder = NULL;
  351. FOLDERINFO infoFolder = {0};
  352. CProgress * pProgress = NULL;
  353. IOERule * pIRule = NULL;
  354. CRIT_ITEM * pCritItem = NULL;
  355. ULONG cCritItem = 0;
  356. ULONG ulIndex = 0;
  357. PROPVARIANT propvar = {0};
  358. CExecRules * pExecRules = NULL;
  359. RULENODE rnode = {0};
  360. IOEExecRules * pIExecRules = NULL;
  361. CHAR rgchTmpl[CCHMAX_STRINGRES];
  362. LPSTR pszText = NULL;
  363. // Check incoming params
  364. if ((NULL == hwnd) || (FOLDERID_INVALID == idFolder) || (NULL == ppszSender) || (0 == cpszSender))
  365. {
  366. hr = E_INVALIDARG;
  367. goto exit;
  368. }
  369. // Open up the folder
  370. hr = g_pStore->OpenFolder(idFolder, NULL, NOFLAGS, &pFolder);
  371. if (FAILED(hr))
  372. {
  373. goto exit;
  374. }
  375. hr = g_pStore->GetFolderInfo(idFolder, &infoFolder);
  376. if (FAILED(hr))
  377. {
  378. goto exit;
  379. }
  380. // Create the progress dialog
  381. pProgress = new CProgress;
  382. if (NULL == pProgress)
  383. {
  384. hr = E_OUTOFMEMORY;
  385. goto exit;
  386. }
  387. pProgress->Init(hwnd, MAKEINTRESOURCE(idsAthena), MAKEINTRESOURCE(idsSendersApplyProgress), infoFolder.cMessages, 0, TRUE, FALSE);
  388. // Create the Block Sender rule
  389. hr = RuleUtil_HrCreateSendersRule(0, &pIRule);
  390. if (FAILED(hr))
  391. {
  392. goto exit;
  393. }
  394. // Allocate space to hold all the senders
  395. hr = HrAlloc((VOID **) &pCritItem, sizeof(*pCritItem) * cpszSender);
  396. if (FAILED(hr))
  397. {
  398. goto exit;
  399. }
  400. // Initialize it
  401. ZeroMemory(pCritItem, sizeof(*pCritItem) * cpszSender);
  402. // Add in each of the criteria
  403. for (ulIndex = 0; ulIndex < cpszSender; ulIndex++, ppszSender++)
  404. {
  405. if ((NULL != *ppszSender) && ('\0' != (*ppszSender)[0]))
  406. {
  407. pCritItem[cCritItem].type = CRIT_TYPE_SENDER;
  408. pCritItem[cCritItem].logic = CRIT_LOGIC_OR;
  409. pCritItem[cCritItem].dwFlags = CRIT_FLAG_DEFAULT;
  410. pCritItem[cCritItem].propvar.vt = VT_LPSTR;
  411. pCritItem[cCritItem].propvar.pszVal = *ppszSender;
  412. cCritItem++;
  413. }
  414. }
  415. // Do we need to do anything?
  416. if (0 == cCritItem)
  417. {
  418. hr = E_FAIL;
  419. goto exit;
  420. }
  421. // Set the senders into the rule
  422. propvar.vt = VT_BLOB;
  423. propvar.blob.cbSize = sizeof(*pCritItem) * cCritItem;
  424. propvar.blob.pBlobData = (BYTE *) pCritItem;
  425. hr = pIRule->SetProp(RULE_PROP_CRITERIA, 0, &propvar);
  426. if (FAILED(hr))
  427. {
  428. goto exit;
  429. }
  430. // Create the rule executor
  431. pExecRules = new CExecRules;
  432. if (NULL == pExecRules)
  433. {
  434. hr = E_OUTOFMEMORY;
  435. goto exit;
  436. }
  437. // Initialize the rule executor
  438. rnode.pIRule = pIRule;
  439. hr = pExecRules->_HrInitialize(0, &rnode);
  440. if (FAILED(hr))
  441. {
  442. goto exit;
  443. }
  444. // Get the rule executor interface
  445. hr = pExecRules->QueryInterface(IID_IOEExecRules, (void **) &pIExecRules);
  446. if (FAILED(hr))
  447. {
  448. goto exit;
  449. }
  450. pExecRules = NULL;
  451. // Show dialog in 2 second
  452. pProgress->Show(0);
  453. hr = RuleUtil_HrApplyRulesToFolder(RULE_APPLY_SHOWUI, (FOLDER_LOCAL != infoFolder.tyFolder) ? DELETE_MESSAGE_NOTRASHCAN : 0,
  454. pIExecRules, pFolder, pProgress->GetHwnd(), pProgress);
  455. // Close the progress window
  456. pProgress->Close();
  457. if (FAILED(hr))
  458. {
  459. goto exit;
  460. }
  461. // Show confirmation dialog
  462. AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsSendersApplySuccess), NULL, MB_OK | MB_ICONINFORMATION);
  463. hr = S_OK;
  464. exit:
  465. SafeMemFree(pszText);
  466. SafeRelease(pIExecRules);
  467. if (NULL != pExecRules)
  468. {
  469. delete pExecRules;
  470. }
  471. SafeMemFree(pCritItem);
  472. SafeRelease(pIRule);
  473. SafeRelease(pProgress);
  474. g_pStore->FreeRecord(&infoFolder);
  475. SafeRelease(pFolder);
  476. if (FAILED(hr))
  477. {
  478. AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena),
  479. MAKEINTRESOURCEW(idsSendersApplyFail), NULL, MB_OK | MB_ICONERROR);
  480. }
  481. return hr;
  482. }
  483. ///////////////////////////////////////////////////////////////////////////////
  484. //
  485. // HrCreateRulesManager
  486. //
  487. // This creates a rules manager.
  488. //
  489. // pIUnkOuter - For aggregation, it must be NULL
  490. // ppIUnknown - The interface the was created
  491. //
  492. // Returns: S_OK, on success
  493. // E_OUTOFMEMORY, if can't create the Rules Manager object
  494. //
  495. ///////////////////////////////////////////////////////////////////////////////
  496. HRESULT HrCreateRulesManager(IUnknown * pIUnkOuter, IUnknown ** ppIUnknown)
  497. {
  498. HRESULT hr = S_OK;
  499. CRulesManager * pRulesManager = NULL;
  500. IOERulesManager * pIRulesMgr = NULL;
  501. // Check the incoming params
  502. if (NULL == ppIUnknown)
  503. {
  504. hr = E_INVALIDARG;
  505. goto exit;
  506. }
  507. Assert(NULL == pIUnkOuter);
  508. // Initialize outgoing params
  509. *ppIUnknown = NULL;
  510. // Create the rules manager object
  511. pRulesManager = new CRulesManager;
  512. if (NULL == pRulesManager)
  513. {
  514. hr = E_OUTOFMEMORY;
  515. goto exit;
  516. }
  517. // Get the rules manager interface
  518. hr = pRulesManager->QueryInterface(IID_IOERulesManager, (void **) &pIRulesMgr);
  519. if (FAILED(hr))
  520. {
  521. goto exit;
  522. }
  523. pRulesManager = NULL;
  524. *ppIUnknown = static_cast<IUnknown *>(pIRulesMgr);
  525. pIRulesMgr = NULL;
  526. // Set the proper return value
  527. hr = S_OK;
  528. exit:
  529. SafeRelease(pIRulesMgr);
  530. if (NULL != pRulesManager)
  531. {
  532. delete pRulesManager;
  533. }
  534. return hr;
  535. }
  536. HRESULT RuleUtil_HrBuildEmailString(LPWSTR pwszText, ULONG cchText, LPWSTR * ppwszEmail, ULONG * pcchEmail)
  537. {
  538. HRESULT hr = S_OK;
  539. WCHAR wszParseSep[16];
  540. LPWSTR pwszAddr = NULL,
  541. pwszTerm = NULL,
  542. pwszWalk = NULL,
  543. pwszStrip = NULL;
  544. ULONG cchParse = 0;
  545. // Check incoming params
  546. if ((NULL == pwszText) || (NULL == ppwszEmail))
  547. {
  548. hr = E_INVALIDARG;
  549. goto exit;
  550. }
  551. // Initialize outgoing params
  552. *ppwszEmail = NULL;
  553. if (NULL != pcchEmail)
  554. {
  555. *pcchEmail = 0;
  556. }
  557. // Grab the terminator
  558. cchParse = LoadStringWrapW(g_hLocRes, idsEmailParseSep, wszParseSep, ARRAYSIZE(wszParseSep));
  559. Assert(cchParse != 0);
  560. // The output string is at least as long as the imput string
  561. pwszAddr = PszDupW(pwszText);
  562. if (NULL == pwszAddr)
  563. {
  564. hr = E_OUTOFMEMORY;
  565. goto exit;
  566. }
  567. DWORD cchSizeAddr = (lstrlenW(pwszAddr) + 1);
  568. DWORD cchSizeWalk = cchSizeAddr;
  569. pwszAddr[0] = L'\0';
  570. pwszTerm = pwszText;
  571. pwszWalk = pwszAddr;
  572. while (NULL != pwszTerm)
  573. {
  574. pwszStrip = pwszWalk;
  575. pwszTerm = StrStrW(pwszText, wszParseSep);
  576. if (L'\0' != pwszAddr[0])
  577. {
  578. StrCpyNW(pwszWalk, g_wszComma, cchSizeWalk);
  579. pwszStrip++;
  580. }
  581. if (NULL == pwszTerm)
  582. {
  583. StrCatBuffW(pwszWalk, pwszText, cchSizeWalk);
  584. }
  585. else
  586. {
  587. StrNCatW(pwszWalk, pwszText, (int)(pwszTerm - pwszText + 1));
  588. pwszTerm += cchParse;
  589. pwszText = pwszTerm;
  590. }
  591. if (0 == UlStripWhitespaceW(pwszStrip, TRUE, TRUE, NULL))
  592. {
  593. *pwszWalk = '\0';
  594. }
  595. cchSizeWalk -= lstrlenW(pwszWalk);
  596. pwszWalk += lstrlenW(pwszWalk);
  597. }
  598. // Set the outgoing params
  599. if (NULL != pcchEmail)
  600. {
  601. *pcchEmail = lstrlenW(pwszAddr);
  602. }
  603. *ppwszEmail = pwszAddr;
  604. pwszAddr = NULL;
  605. // Set proper return value
  606. hr = S_OK;
  607. exit:
  608. SafeMemFree(pwszAddr);
  609. return hr;
  610. }
  611. HRESULT RuleUtil_HrParseEmailString(LPWSTR pwszEmail, ULONG cchEmail, LPWSTR *ppwszOut, ULONG * pcchOut)
  612. {
  613. HRESULT hr = S_OK;
  614. LPWSTR pwszText = NULL,
  615. pwszTerm = NULL;
  616. ULONG cchText = 0;
  617. ULONG ulIndex = 0;
  618. ULONG ulTerm = 0;
  619. WCHAR wszSep[16];
  620. ULONG cchSep = 0;
  621. // Check incoming params
  622. if ((NULL == pwszEmail) || (NULL == ppwszOut))
  623. {
  624. hr = E_INVALIDARG;
  625. goto exit;
  626. }
  627. // Initialize outgoing params
  628. *ppwszOut = NULL;
  629. if (NULL != pcchOut)
  630. {
  631. *pcchOut = 0;
  632. }
  633. // Make sure we know how big the input string is
  634. if (0 == cchEmail)
  635. {
  636. cchEmail = (ULONG) lstrlenW(pwszEmail);
  637. }
  638. cchText = cchEmail;
  639. pwszTerm = pwszEmail;
  640. // Figure out the space needed to hold the new addresses
  641. while (NULL != pwszTerm)
  642. {
  643. pwszTerm = StrStrW(pwszTerm, g_wszComma);
  644. if (NULL != pwszTerm)
  645. {
  646. cchText++;
  647. pwszTerm++;
  648. }
  649. }
  650. // Grab the terminator
  651. LoadStringWrapW(g_hLocRes, idsEmailSep, wszSep, ARRAYSIZE(wszSep));
  652. cchSep = lstrlenW(wszSep);
  653. // The output string is at least as long as the imput string
  654. hr = HrAlloc((void **) &pwszText, (cchText + 1)*sizeof(*pwszText));
  655. if (FAILED(hr))
  656. {
  657. goto exit;
  658. }
  659. pwszText[0] = L'\0';
  660. pwszTerm = pwszEmail;
  661. cchText++;
  662. while (NULL != pwszTerm)
  663. {
  664. pwszTerm = StrStrW(pwszEmail, g_wszComma);
  665. if (NULL != pwszTerm)
  666. {
  667. pwszTerm++;
  668. StrNCatW(pwszText, pwszEmail, (int)(pwszTerm - pwszEmail));
  669. StrCatBuffW(pwszText, wszSep, cchText);
  670. pwszEmail = pwszTerm;
  671. }
  672. else
  673. {
  674. StrCatBuffW(pwszText, pwszEmail, cchText);
  675. }
  676. }
  677. // Terminate the string
  678. cchText = lstrlenW(pwszText);
  679. // Set the outgoing param
  680. *ppwszOut = pwszText;
  681. pwszText = NULL;
  682. if (NULL != pcchOut)
  683. {
  684. *pcchOut = cchText;
  685. }
  686. // Set proper return value
  687. hr = S_OK;
  688. exit:
  689. SafeMemFree(pwszText);
  690. return hr;
  691. }
  692. HRESULT RuleUtil_HrBuildTextString(LPTSTR pszIn, ULONG cchIn, LPTSTR * ppszText, ULONG * pcchText)
  693. {
  694. HRESULT hr = S_OK;
  695. LPTSTR pszText = NULL;
  696. LPTSTR pszTerm = NULL;
  697. LPTSTR pszWalk = NULL;
  698. LPTSTR pszStrip = NULL;
  699. ULONG cchSpace = 0;
  700. // Check incoming params
  701. if ((NULL == pszIn) || (NULL == ppszText))
  702. {
  703. hr = E_INVALIDARG;
  704. goto exit;
  705. }
  706. // Initialize outgoing params
  707. *ppszText = NULL;
  708. if (NULL != pcchText)
  709. {
  710. *pcchText = 0;
  711. }
  712. // The output string is at least as long as the imput string
  713. pszText = PszDupA(pszIn);
  714. if (NULL == pszText)
  715. {
  716. hr = E_OUTOFMEMORY;
  717. goto exit;
  718. }
  719. pszText[0] = '\0';
  720. pszTerm = pszIn;
  721. pszWalk = pszText;
  722. cchSpace = lstrlen(g_szSpace);
  723. DWORD cchSize = lstrlen(pszIn)+1;
  724. while ('\0' != *pszTerm)
  725. {
  726. pszStrip = pszWalk;
  727. pszTerm = pszIn;
  728. while(('\0' != *pszTerm) && (FALSE == FIsSpaceA(pszTerm)))
  729. {
  730. pszTerm = CharNext(pszTerm);
  731. }
  732. if ('\0' != pszText[0])
  733. {
  734. StrCpyN(pszWalk, g_szSpace, cchSize);
  735. pszStrip += cchSpace;
  736. }
  737. if ('\0' == *pszTerm)
  738. {
  739. StrCatBuff(pszWalk, pszIn, cchSize);
  740. }
  741. else
  742. {
  743. pszTerm = CharNext(pszTerm);
  744. StrNCat(pszWalk, pszIn, (int)(pszTerm - pszIn));
  745. pszIn = pszTerm;
  746. }
  747. if (0 == UlStripWhitespace(pszStrip, TRUE, TRUE, NULL))
  748. {
  749. *pszWalk = '\0';
  750. }
  751. cchSize -= lstrlen(pszWalk);
  752. pszWalk += lstrlen(pszWalk);
  753. }
  754. // Set the outgoing params
  755. if (NULL != pcchText)
  756. {
  757. *pcchText = lstrlen(pszText);
  758. }
  759. *ppszText = pszText;
  760. pszText = NULL;
  761. // Set proper return value
  762. hr = S_OK;
  763. exit:
  764. SafeMemFree(pszText);
  765. return hr;
  766. }
  767. // -------------------------------------------------------------------------------------------
  768. // HrDlgRuleGetString
  769. // -------------------------------------------------------------------------------------------
  770. HRESULT RuleUtil_HrGetDlgString(HWND hwndDlg, UINT uiCtlId, LPTSTR *ppszText, ULONG * pcchText)
  771. {
  772. HRESULT hr = S_OK;
  773. HWND hwndCtl = NULL;
  774. LPTSTR pszText = NULL;
  775. ULONG cchText = 0;
  776. // Check the incoming params
  777. if ((NULL == hwndDlg) || (NULL == ppszText))
  778. {
  779. hr = E_INVALIDARG;
  780. goto exit;
  781. }
  782. Assert(FALSE != IsWindow(hwndDlg));
  783. // Init the output params
  784. *ppszText = NULL;
  785. if (NULL != pcchText)
  786. {
  787. *pcchText = 0;
  788. }
  789. // Get the dialog control
  790. hwndCtl = GetDlgItem(hwndDlg, uiCtlId);
  791. if (NULL == hwndCtl)
  792. {
  793. hr = E_FAIL;
  794. goto exit;
  795. }
  796. // Get text length
  797. cchText = (ULONG) SendMessage(hwndCtl, WM_GETTEXTLENGTH, 0, 0);
  798. hr = HrAlloc((void **) &pszText, cchText + 1);
  799. if (FAILED(hr))
  800. {
  801. goto exit;
  802. }
  803. GetDlgItemText(hwndDlg, uiCtlId, pszText, cchText + 1);
  804. // Set the output params
  805. *ppszText = pszText;
  806. pszText = NULL;
  807. if (NULL != pcchText)
  808. {
  809. *pcchText = cchText;
  810. }
  811. // Set the proper return value
  812. hr = S_OK;
  813. exit:
  814. SafeMemFree(pszText);
  815. return hr;
  816. }
  817. HRESULT RuleUtil_HrGetRegValue(HKEY hkey, LPCSTR pszValueName, DWORD * pdwType, BYTE ** ppbData, ULONG * pcbData)
  818. {
  819. HRESULT hr = S_OK;
  820. LONG lErr = ERROR_SUCCESS;
  821. ULONG cbData = 0;
  822. BYTE * pbData = NULL;
  823. // Check incoming params
  824. if (NULL == ppbData)
  825. {
  826. hr = E_FAIL;
  827. goto exit;
  828. }
  829. // Figure out the space to hold the criteria order
  830. lErr = SHQueryValueEx(hkey, pszValueName, 0, pdwType, NULL, &cbData);
  831. if (ERROR_SUCCESS != lErr)
  832. {
  833. hr = HRESULT_FROM_WIN32(lErr);
  834. goto exit;
  835. }
  836. // Allocate the space to hold the criteria order
  837. hr = HrAlloc((void **) &pbData, cbData);
  838. if (FAILED(hr))
  839. {
  840. goto exit;
  841. }
  842. // Get the criteria order
  843. lErr = SHQueryValueEx(hkey, pszValueName, 0, pdwType, pbData, &cbData);
  844. if (ERROR_SUCCESS != lErr)
  845. {
  846. hr = HRESULT_FROM_WIN32(lErr);
  847. goto exit;
  848. }
  849. // Return the values
  850. *ppbData = pbData;
  851. pbData = NULL;
  852. if (NULL != pcbData)
  853. {
  854. *pcbData = cbData;
  855. }
  856. exit:
  857. SafeMemFree(pbData);
  858. return hr;
  859. }
  860. // -------------------------------------------------------------------------------------------
  861. // RuleUtil_HrGetAddressesFromWAB
  862. // -------------------------------------------------------------------------------------------
  863. HRESULT RuleUtil_HrGetAddressesFromWAB(HWND hwndDlg, LONG lRecipType, UINT uidsWellButton, LPWSTR *ppwszAddrs)
  864. {
  865. HRESULT hr = S_OK;
  866. CWabal *pWabal = NULL,
  867. *pWabalExpand = NULL;
  868. LPWSTR pwszText = NULL,
  869. pwszLoop = NULL;
  870. BOOL fFound = FALSE,
  871. fBadAddrs = FALSE;
  872. ULONG cchText = 0;
  873. ADRINFO adrInfo = {0};
  874. // Check the incoming params
  875. if ((NULL == hwndDlg) || (NULL == ppwszAddrs))
  876. {
  877. hr = E_INVALIDARG;
  878. goto exit;
  879. }
  880. Assert(FALSE != IsWindow(hwndDlg));
  881. // Create Wabal Object
  882. hr = HrCreateWabalObject(&pWabal);
  883. if (FAILED(hr))
  884. {
  885. goto exit;
  886. }
  887. // If we have a string then add it to the wabal object
  888. if (NULL != *ppwszAddrs)
  889. {
  890. for (pwszLoop = *ppwszAddrs; L'\0' != pwszLoop[0]; pwszLoop += lstrlenW(pwszLoop) + 1)
  891. pWabal->HrAddEntry(pwszLoop, pwszLoop, lRecipType);
  892. }
  893. // Let's go pick some new names
  894. hr = pWabal->HrRulePickNames(hwndDlg, lRecipType, idsRuleAddrCaption, idsRuleAddrWell, uidsWellButton);
  895. if (FAILED(hr))
  896. {
  897. goto exit;
  898. }
  899. // Figure out the space needed to hold the new addresses
  900. // Create the expanded Wabal Object
  901. hr = HrCreateWabalObject(&pWabalExpand);
  902. if (FAILED(hr))
  903. {
  904. goto exit;
  905. }
  906. //Expand the groups to addresses...
  907. hr = pWabal->HrExpandTo(pWabalExpand);
  908. if (FAILED(hr))
  909. {
  910. goto exit;
  911. }
  912. SafeRelease(pWabal);
  913. cchText = 0;
  914. fFound = pWabalExpand->FGetFirst(&adrInfo);
  915. while(FALSE != fFound)
  916. {
  917. if ((NULL != adrInfo.lpwszAddress) && (L'\0' != adrInfo.lpwszAddress[0]))
  918. {
  919. cchText += lstrlenW(adrInfo.lpwszAddress) + 1;
  920. }
  921. else
  922. {
  923. fBadAddrs = TRUE;
  924. }
  925. // Get the next address
  926. fFound = pWabalExpand->FGetNext(&adrInfo);
  927. }
  928. // Add space for the terminator
  929. cchText += 2;
  930. // Allocate the new space
  931. hr = HrAlloc((void **) &pwszText, cchText*sizeof(WCHAR));
  932. if (FAILED(hr))
  933. {
  934. goto exit;
  935. }
  936. pwszText[0] = L'\0';
  937. // Build up the new string
  938. pwszLoop = pwszText;
  939. DWORD cchLoop = cchText;
  940. fFound = pWabalExpand->FGetFirst(&adrInfo);
  941. while(FALSE != fFound)
  942. {
  943. if ((NULL != adrInfo.lpwszAddress) && (L'\0' != adrInfo.lpwszAddress[0]))
  944. {
  945. StrCpyNW(pwszLoop, adrInfo.lpwszAddress, cchLoop);
  946. cchLoop -= (lstrlenW(adrInfo.lpwszAddress) + 1);
  947. pwszLoop += (lstrlenW(adrInfo.lpwszAddress) + 1);
  948. }
  949. else
  950. {
  951. fBadAddrs = TRUE;
  952. }
  953. // Get the next address
  954. fFound = pWabalExpand->FGetNext(&adrInfo);
  955. }
  956. // Terminate the string
  957. pwszLoop[0] = L'\0';
  958. pwszLoop[1] = L'\0';
  959. // Set the outgoing param
  960. if (NULL != *ppwszAddrs)
  961. {
  962. MemFree(*ppwszAddrs);
  963. }
  964. *ppwszAddrs = pwszText;
  965. pwszText = NULL;
  966. // Set the proper return value
  967. hr = S_OK;
  968. exit:
  969. if (FALSE != fBadAddrs)
  970. {
  971. AthMessageBoxW(hwndDlg, MAKEINTRESOURCEW(idsAthena),
  972. MAKEINTRESOURCEW(idsRulesWarnEmptyEmail), NULL, MB_ICONINFORMATION | MB_OK);
  973. }
  974. MemFree(pwszText);
  975. ReleaseObj(pWabal);
  976. ReleaseObj(pWabalExpand);
  977. return hr;
  978. }
  979. // -------------------------------------------------------------------------------------------
  980. // FPickEMailNames
  981. // -------------------------------------------------------------------------------------------
  982. HRESULT RuleUtil_HrPickEMailNames(HWND hwndDlg, LONG lRecipType, UINT uidsWellButton, LPWSTR *ppwszAddrs)
  983. {
  984. HRESULT hr = S_OK;
  985. CWabal *pWabal = NULL,
  986. *pWabalExpand = NULL;
  987. LPWSTR pwszText = NULL,
  988. pwszNames = NULL,
  989. pwszLoop = NULL,
  990. pwszTerm = NULL;
  991. ULONG cchText = 0,
  992. cchSep = 0;
  993. BOOL fFound = FALSE,
  994. fAddSep = FALSE,
  995. fBadAddrs = FALSE;
  996. ADRINFO adrInfo;
  997. // Check the incoming params
  998. if ((NULL == hwndDlg) || (NULL == ppwszAddrs))
  999. {
  1000. hr = E_INVALIDARG;
  1001. goto exit;
  1002. }
  1003. Assert(FALSE != IsWindow(hwndDlg));
  1004. // Create Wabal Object
  1005. hr = HrCreateWabalObject(&pWabal);
  1006. if (FAILED(hr))
  1007. {
  1008. goto exit;
  1009. }
  1010. // If we have a string then add it to the wabal object
  1011. if ((NULL != *ppwszAddrs) && (L'\0' != **ppwszAddrs))
  1012. {
  1013. pwszNames = PszDupW(*ppwszAddrs);
  1014. pwszTerm = pwszNames;
  1015. for (pwszLoop = pwszNames; NULL != pwszTerm; pwszLoop += lstrlenW(pwszLoop) + 1)
  1016. {
  1017. // Terminate the address
  1018. pwszTerm = StrStrW(pwszLoop, g_wszComma);
  1019. if (NULL != pwszTerm)
  1020. {
  1021. *pwszTerm = L'\0';
  1022. }
  1023. pWabal->HrAddEntry(pwszLoop, pwszLoop, lRecipType);
  1024. }
  1025. SafeMemFree(pwszNames);
  1026. }
  1027. // Let's go pick some new names
  1028. hr = pWabal->HrRulePickNames(hwndDlg, lRecipType, idsRuleAddrCaption, idsRuleAddrWell, uidsWellButton);
  1029. if (FAILED(hr))
  1030. {
  1031. goto exit;
  1032. }
  1033. // Figure out the space needed to hold the new addresses
  1034. // Create the expanded Wabal Object
  1035. hr = HrCreateWabalObject(&pWabalExpand);
  1036. if (FAILED(hr))
  1037. {
  1038. goto exit;
  1039. }
  1040. //Expand the groups to addresses...
  1041. hr = pWabal->HrExpandTo(pWabalExpand);
  1042. if (FAILED(hr))
  1043. {
  1044. goto exit;
  1045. }
  1046. SafeRelease(pWabal);
  1047. // Load the email seperator
  1048. cchSep = lstrlenW(g_wszComma);
  1049. cchText = 0;
  1050. fFound = pWabalExpand->FGetFirst(&adrInfo);
  1051. while(FALSE != fFound)
  1052. {
  1053. if (NULL != adrInfo.lpwszAddress)
  1054. {
  1055. cchText += lstrlenW(adrInfo.lpwszAddress) + cchSep;
  1056. }
  1057. else
  1058. {
  1059. fBadAddrs = TRUE;
  1060. }
  1061. // Get the next address
  1062. fFound = pWabalExpand->FGetNext(&adrInfo);
  1063. }
  1064. // Allocate the new space
  1065. hr = HrAlloc((void **) &pwszText, (cchText + 1)*sizeof(*pwszText));
  1066. if (FAILED(hr))
  1067. {
  1068. goto exit;
  1069. }
  1070. pwszText[0] = L'\0';
  1071. // Build up the new string
  1072. DWORD cchBufSize = cchText+1;
  1073. cchText = 0;
  1074. fFound = pWabalExpand->FGetFirst(&adrInfo);
  1075. while(FALSE != fFound)
  1076. {
  1077. if (NULL != adrInfo.lpwszAddress)
  1078. {
  1079. if (FALSE == fAddSep)
  1080. {
  1081. fAddSep = TRUE;
  1082. }
  1083. else
  1084. {
  1085. StrCatBuffW(pwszText, g_wszComma, cchBufSize);
  1086. cchText += cchSep;
  1087. }
  1088. StrCatBuffW(pwszText, adrInfo.lpwszAddress, cchBufSize);
  1089. cchText += lstrlenW(adrInfo.lpwszAddress);
  1090. }
  1091. else
  1092. {
  1093. fBadAddrs = TRUE;
  1094. }
  1095. // Get the next address
  1096. fFound = pWabalExpand->FGetNext(&adrInfo);
  1097. }
  1098. // Set the outgoing param
  1099. if (NULL != *ppwszAddrs)
  1100. {
  1101. MemFree(*ppwszAddrs);
  1102. }
  1103. *ppwszAddrs = pwszText;
  1104. pwszText = NULL;
  1105. // Set the proper return value
  1106. hr = S_OK;
  1107. exit:
  1108. if (FALSE != fBadAddrs)
  1109. {
  1110. AthMessageBoxW(hwndDlg, MAKEINTRESOURCEW(idsAthena),
  1111. MAKEINTRESOURCEW(idsRulesWarnEmptyEmail), NULL, MB_ICONINFORMATION | MB_OK);
  1112. }
  1113. SafeMemFree(pwszText);
  1114. SafeRelease(pWabal);
  1115. SafeRelease(pWabalExpand);
  1116. return hr;
  1117. }
  1118. ///////////////////////////////////////////////////////////////////////////////
  1119. //
  1120. // RuleUtil_FEnDisDialogItem
  1121. //
  1122. // This enables or disables a control in a dialog.
  1123. // The real special thing this function does is make sure
  1124. // the focus of the dialog isn't stuck in a disabled control
  1125. //
  1126. // Returns: TRUE, if the enabled state was changed
  1127. // FALSE, otherwise
  1128. //
  1129. ///////////////////////////////////////////////////////////////////////////////
  1130. BOOL RuleUtil_FEnDisDialogItem(HWND hwndDlg, UINT idcItem, BOOL fEnable)
  1131. {
  1132. BOOL fRet = FALSE;
  1133. HWND hwndFocus = NULL;
  1134. HWND hwndItem = NULL;
  1135. // check params
  1136. if (NULL == hwndDlg)
  1137. {
  1138. fRet = FALSE;
  1139. goto exit;
  1140. }
  1141. hwndItem = GetDlgItem(hwndDlg, idcItem);
  1142. // Make sure we aren't disabling the window with the focus
  1143. if ((FALSE == fEnable) && (hwndItem == GetFocus()))
  1144. {
  1145. SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM) 0, (LPARAM) LOWORD(FALSE));
  1146. }
  1147. // Enable or disable the window
  1148. EnableWindow(hwndItem, fEnable);
  1149. exit:
  1150. return fRet;
  1151. }
  1152. ///////////////////////////////////////////////////////////////////////////////
  1153. //
  1154. // RuleUtil_AppendRichEditText
  1155. //
  1156. // This sets a string into a richedit control with the proper style.
  1157. //
  1158. // Returns: S_OK, if the string was set
  1159. //
  1160. ///////////////////////////////////////////////////////////////////////////////
  1161. HRESULT RuleUtil_AppendRichEditText(HWND hwndRedit, ULONG ulStart, LPCWSTR pwszText, CHARFORMAT *pchfmt)
  1162. {
  1163. CHARFORMAT chFmtDef = {0};
  1164. HRESULT hr = S_OK;
  1165. ULONG cchText = 0;
  1166. CHARRANGE chrg = {0};
  1167. // check params
  1168. Assert(hwndRedit);
  1169. Assert(pwszText);
  1170. // Set the string into the richedit control
  1171. chrg.cpMin = ulStart;
  1172. chrg.cpMax = ulStart;
  1173. RichEditExSetSel(hwndRedit, &chrg);
  1174. // Figure out the string length
  1175. cchText = lstrlenW(pwszText);
  1176. SetRichEditText(hwndRedit, (LPWSTR)pwszText, TRUE, NULL, TRUE);
  1177. chrg.cpMax = ulStart + cchText;
  1178. RichEditExSetSel(hwndRedit, &chrg);
  1179. // If we have a style to set on the string let's do it
  1180. if (pchfmt)
  1181. {
  1182. SendMessage(hwndRedit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM)pchfmt);
  1183. // Reset default settings for CHARFORMAT
  1184. chrg.cpMin = ulStart + cchText;
  1185. RichEditExSetSel(hwndRedit, &chrg);
  1186. chFmtDef.cbSize = sizeof(chFmtDef);
  1187. chFmtDef.dwMask = CFM_BOLD | CFM_UNDERLINE | CFM_COLOR;
  1188. chFmtDef.dwEffects = CFE_AUTOCOLOR;
  1189. SendMessage(hwndRedit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM)&chFmtDef);
  1190. }
  1191. return hr;
  1192. }
  1193. ///////////////////////////////////////////////////////////////////////////////
  1194. //
  1195. // RuleUtil_HrShowLinkedString
  1196. //
  1197. // This writes a format string into a richedit control
  1198. //
  1199. // Returns: S_OK, if it was successfully written
  1200. // E_FAIL, otherwise
  1201. //
  1202. ///////////////////////////////////////////////////////////////////////////////
  1203. HRESULT RuleUtil_HrShowLinkedString(HWND hwndEdit, BOOL fError, BOOL fReadOnly,
  1204. LPWSTR pwszFmt, LPCWSTR pwszData, ULONG ulStart,
  1205. ULONG * pulStartLink, ULONG * pulEndLink, ULONG * pulEnd)
  1206. {
  1207. HRESULT hr = S_OK;
  1208. CHARFORMAT chfmt = {0};
  1209. COLORREF clr = 0;
  1210. LPWSTR pwszMark = NULL;
  1211. ULONG ulStartLink = 0;
  1212. ULONG ulEndLink = 0;
  1213. if ((NULL == hwndEdit) || (NULL == pwszFmt) || (L'\0' == *pwszFmt))
  1214. {
  1215. hr = E_INVALIDARG;
  1216. goto exit;
  1217. }
  1218. // Initialize the outgoing param
  1219. if (pulStartLink)
  1220. {
  1221. *pulStartLink = 0;
  1222. }
  1223. if (pulEndLink)
  1224. {
  1225. *pulEndLink = 0;
  1226. }
  1227. if (pulEnd)
  1228. {
  1229. *pulEnd = 0;
  1230. }
  1231. // Find the underline mark
  1232. pwszMark = StrStrW(pwszFmt, c_wszRuleMarkStart);
  1233. if (NULL != pwszMark)
  1234. {
  1235. *pwszMark = L'\0';
  1236. }
  1237. // Write out the normal string
  1238. RuleUtil_AppendRichEditText(hwndEdit, ulStart, pwszFmt, NULL);
  1239. ulStart += lstrlenW(pwszFmt);
  1240. // If we didn't have anything to underline
  1241. // then we're done.
  1242. if (NULL == pwszMark)
  1243. {
  1244. // Save off the new end
  1245. if (NULL != pulEnd)
  1246. {
  1247. *pulEnd = ulStart;
  1248. }
  1249. // Return
  1250. hr = S_OK;
  1251. goto exit;
  1252. }
  1253. // Skip over the mark
  1254. pwszFmt = pwszMark + lstrlenW(c_wszRuleMarkStart);
  1255. // Find the mark end
  1256. pwszMark = StrStrW(pwszFmt, c_wszRuleMarkEnd);
  1257. if (NULL == pwszMark)
  1258. {
  1259. hr = E_FAIL;
  1260. goto exit;
  1261. }
  1262. // If we don't have some data then
  1263. // just underline the original string
  1264. if (NULL == pwszData)
  1265. {
  1266. *pwszMark = L'\0';
  1267. pwszData = pwszFmt;
  1268. }
  1269. // Save off the character positions
  1270. ulStartLink = ulStart;
  1271. ulEndLink = ulStart + lstrlenW(pwszData);
  1272. // If readonly, then don't add links
  1273. if (fReadOnly)
  1274. RuleUtil_AppendRichEditText(hwndEdit, ulStart, pwszData, NULL);
  1275. else
  1276. {
  1277. if (fError)
  1278. clr = RGB(255, 0, 0);
  1279. else
  1280. LookupLinkColors(&clr, NULL);
  1281. // Which color should we use for underlining
  1282. chfmt.crTextColor = clr;
  1283. chfmt.cbSize = sizeof(chfmt);
  1284. chfmt.dwMask = CFM_UNDERLINE | CFM_COLOR;
  1285. chfmt.dwEffects = CFE_UNDERLINE;
  1286. RuleUtil_AppendRichEditText(hwndEdit, ulStart, pwszData, &chfmt);
  1287. }
  1288. // Write out the linked string
  1289. ulStart = ulEndLink;
  1290. // Move to the next part of the string
  1291. pwszFmt = pwszMark + lstrlenW(c_wszRuleMarkEnd);
  1292. // If we have more of the string to write out
  1293. if (L'\0' != *pwszFmt)
  1294. {
  1295. // Write out the rest of the string string
  1296. RuleUtil_AppendRichEditText(hwndEdit, ulStart, pwszFmt, NULL);
  1297. ulStart += lstrlenW(pwszFmt);
  1298. }
  1299. // Set the outgoing param
  1300. if (pulStartLink)
  1301. {
  1302. *pulStartLink = ulStartLink;
  1303. }
  1304. if (pulEndLink)
  1305. {
  1306. *pulEndLink = ulEndLink;
  1307. }
  1308. if (pulEnd)
  1309. {
  1310. *pulEnd = ulStart;
  1311. }
  1312. // Set the return value
  1313. hr = S_OK;
  1314. exit:
  1315. return hr;
  1316. }
  1317. HRESULT RuleUtil_HrDupCriteriaItem(CRIT_ITEM * pItemIn, ULONG cItemIn, CRIT_ITEM ** ppItemOut)
  1318. {
  1319. HRESULT hr = S_OK;
  1320. ULONG ulIndex = 0;
  1321. CRIT_ITEM * pItem = NULL;
  1322. // Check incoming params
  1323. if ((NULL == pItemIn) || (NULL == ppItemOut) || (0 == cItemIn))
  1324. {
  1325. hr = E_INVALIDARG;
  1326. goto exit;
  1327. }
  1328. // Initialize the outgoing param
  1329. *ppItemOut = NULL;
  1330. // Allocate the initial list of criteria
  1331. hr = HrAlloc((void **) &pItem, cItemIn * sizeof(*pItem));
  1332. if (FAILED(hr))
  1333. {
  1334. goto exit;
  1335. }
  1336. // Initialize the entire new criteria list
  1337. ZeroMemory(pItem, cItemIn * sizeof(*pItem));
  1338. // Walk over the list of criteria and set up the propvar for each one
  1339. for (ulIndex = 0; ulIndex < cItemIn; ulIndex++)
  1340. {
  1341. // Copy over the criteria info
  1342. pItem[ulIndex].type = pItemIn[ulIndex].type;
  1343. pItem[ulIndex].dwFlags = pItemIn[ulIndex].dwFlags;
  1344. pItem[ulIndex].logic = pItemIn[ulIndex].logic;
  1345. // Copy over the propvar
  1346. hr = PropVariantCopy(&(pItem[ulIndex].propvar), &(pItemIn[ulIndex].propvar));
  1347. if (FAILED(hr))
  1348. {
  1349. goto exit;
  1350. }
  1351. }
  1352. // Set the outgoing param
  1353. *ppItemOut = pItem;
  1354. pItem = NULL;
  1355. // Set proper return value
  1356. hr = S_OK;
  1357. exit:
  1358. if (NULL != pItem)
  1359. {
  1360. RuleUtil_HrFreeCriteriaItem(pItem, cItemIn);
  1361. MemFree(pItem);
  1362. }
  1363. return hr;
  1364. }
  1365. HRESULT RuleUtil_HrFreeCriteriaItem(CRIT_ITEM * pItem, ULONG cItem)
  1366. {
  1367. HRESULT hr = S_OK;
  1368. ULONG ulIndex = 0;
  1369. // Check incoming params
  1370. if ((NULL == pItem) || (0 == cItem))
  1371. {
  1372. hr = E_INVALIDARG;
  1373. goto exit;
  1374. }
  1375. // Walk over the list of criteria and free each one
  1376. for (ulIndex = 0; ulIndex < cItem; ulIndex++)
  1377. {
  1378. PropVariantClear(&(pItem[ulIndex].propvar));
  1379. }
  1380. // Set proper return value
  1381. hr = S_OK;
  1382. exit:
  1383. return hr;
  1384. }
  1385. HRESULT RuleUtil_HrDupActionsItem(ACT_ITEM * pItemIn, ULONG cItemIn, ACT_ITEM ** ppItemOut)
  1386. {
  1387. HRESULT hr = S_OK;
  1388. ULONG ulIndex = 0;
  1389. ACT_ITEM * pItem = NULL;
  1390. // Check incoming params
  1391. if ((NULL == pItemIn) || (NULL == ppItemOut) || (0 == cItemIn))
  1392. {
  1393. hr = E_INVALIDARG;
  1394. goto exit;
  1395. }
  1396. // Initialize the outgoing param
  1397. *ppItemOut = NULL;
  1398. // Allocate the initial list of actions
  1399. hr = HrAlloc((void **) &pItem, cItemIn * sizeof(*pItem));
  1400. if (FAILED(hr))
  1401. {
  1402. goto exit;
  1403. }
  1404. // Initialize the entire new actions list
  1405. ZeroMemory(pItem, cItemIn * sizeof(*pItem));
  1406. // Walk over the list of actions and set up the propvar for each one
  1407. for (ulIndex = 0; ulIndex < cItemIn; ulIndex++)
  1408. {
  1409. // Copy over the actions info
  1410. pItem[ulIndex].type = pItemIn[ulIndex].type;
  1411. pItem[ulIndex].dwFlags = pItemIn[ulIndex].dwFlags;
  1412. // Copy over the propvar
  1413. hr = PropVariantCopy(&(pItem[ulIndex].propvar), &(pItemIn[ulIndex].propvar));
  1414. if (FAILED(hr))
  1415. {
  1416. goto exit;
  1417. }
  1418. }
  1419. // Set the outgoing param
  1420. *ppItemOut = pItem;
  1421. pItem = NULL;
  1422. // Set proper return value
  1423. hr = S_OK;
  1424. exit:
  1425. SafeMemFree(pItem);
  1426. return hr;
  1427. }
  1428. HRESULT RuleUtil_HrFreeActionsItem(ACT_ITEM * pItem, ULONG cItem)
  1429. {
  1430. HRESULT hr = S_OK;
  1431. ULONG ulIndex = 0;
  1432. // Check incoming params
  1433. if ((NULL == pItem) || (0 == cItem))
  1434. {
  1435. hr = E_INVALIDARG;
  1436. goto exit;
  1437. }
  1438. // Walk over the list of criteria and free each one
  1439. for (ulIndex = 0; ulIndex < cItem; ulIndex++)
  1440. {
  1441. PropVariantClear(&(pItem[ulIndex].propvar));
  1442. }
  1443. // Set proper return value
  1444. hr = S_OK;
  1445. exit:
  1446. return hr;
  1447. }
  1448. ///////////////////////////////////////////////////////////////////////////////
  1449. //
  1450. // RuleUtil_HrAddBlockSender
  1451. //
  1452. // This adds the address/domain name to the list of senders we will block
  1453. //
  1454. // hwndOwner - the window the owns this UI
  1455. // pszAddr - the address/domain name to add
  1456. // dwFlags - modifiers on how to add the address/domain name
  1457. //
  1458. // Returns: S_OK, if the address/domain name was added
  1459. // S_FALSE, if the address/domain name was already in the list
  1460. //
  1461. ///////////////////////////////////////////////////////////////////////////////
  1462. HRESULT RuleUtil_HrAddBlockSender(RULE_TYPE type, LPCSTR pszAddr)
  1463. {
  1464. HRESULT hr = S_OK;
  1465. IOERule * pIRuleOrig = NULL;
  1466. IOERule * pIRule = NULL;
  1467. PROPVARIANT propvar = {0};
  1468. ACT_ITEM aitem;
  1469. CRIT_ITEM * pcitem = NULL;
  1470. ULONG ccitem = 0;
  1471. ULONG ulIndex = 0;
  1472. BOOL fFound = FALSE;
  1473. LPSTR pszAddrNew = NULL;
  1474. RULEINFO infoRule = {0};
  1475. // Check incoming params
  1476. if ((NULL == pszAddr) || ('\0' == pszAddr[0]))
  1477. {
  1478. hr = E_INVALIDARG;
  1479. goto exit;
  1480. }
  1481. // Get the block sender rule from the rules manager
  1482. Assert(NULL != g_pRulesMan);
  1483. hr = g_pRulesMan->GetRule(RULEID_SENDERS, type, 0, &pIRuleOrig);
  1484. if (FAILED(hr))
  1485. {
  1486. // Create the new rule
  1487. hr = RuleUtil_HrCreateSendersRule(0, &pIRule);
  1488. if (FAILED(hr))
  1489. {
  1490. goto exit;
  1491. }
  1492. }
  1493. // If the block sender rule exist
  1494. else
  1495. {
  1496. // Clone it so we can make a change
  1497. hr = pIRuleOrig->Clone(&pIRule);
  1498. if (FAILED(hr))
  1499. {
  1500. goto exit;
  1501. }
  1502. SafeRelease(pIRuleOrig);
  1503. }
  1504. // Get the criteria list from the rules object
  1505. hr = pIRule->GetProp(RULE_PROP_CRITERIA, 0, &propvar);
  1506. if (FAILED(hr))
  1507. {
  1508. goto exit;
  1509. }
  1510. Assert(VT_BLOB == propvar.vt);
  1511. ccitem = propvar.blob.cbSize / sizeof(CRIT_ITEM);
  1512. pcitem = (CRIT_ITEM *) propvar.blob.pBlobData;
  1513. ZeroMemory(&propvar, sizeof(propvar));
  1514. // Search for the address/domain name in the criteria list
  1515. if (NULL != pcitem)
  1516. {
  1517. for (ulIndex = 0; ulIndex < ccitem; ulIndex++)
  1518. {
  1519. Assert(CRIT_TYPE_SENDER == pcitem[ulIndex].type)
  1520. Assert(CRIT_LOGIC_OR == pcitem[ulIndex].logic)
  1521. if ((VT_LPSTR != pcitem[ulIndex].propvar.vt) || (NULL == pcitem[ulIndex].propvar.pszVal))
  1522. {
  1523. continue;
  1524. }
  1525. if (0 == lstrcmpi(pszAddr, pcitem[ulIndex].propvar.pszVal))
  1526. {
  1527. fFound = TRUE;
  1528. break;
  1529. }
  1530. }
  1531. }
  1532. // Did we find it?
  1533. if (FALSE != fFound)
  1534. {
  1535. hr = S_FALSE;
  1536. goto exit;
  1537. }
  1538. // Allocate space to hold the new criteria
  1539. hr = HrRealloc((void **) &pcitem, (ccitem + 1) * sizeof(CRIT_ITEM));
  1540. if (FAILED(hr))
  1541. {
  1542. goto exit;
  1543. }
  1544. // Copy over the name
  1545. pszAddrNew = PszDupA(pszAddr);
  1546. if (NULL == pszAddrNew)
  1547. {
  1548. hr = E_OUTOFMEMORY;
  1549. goto exit;
  1550. }
  1551. // Add in to the end of the criteria list
  1552. pcitem[ccitem].type = CRIT_TYPE_SENDER;
  1553. pcitem[ccitem].dwFlags = CRIT_FLAG_DEFAULT;
  1554. pcitem[ccitem].logic = CRIT_LOGIC_OR;
  1555. pcitem[ccitem].propvar.vt = VT_LPSTR;
  1556. pcitem[ccitem].propvar.pszVal = pszAddrNew;
  1557. pszAddrNew = NULL;
  1558. ccitem++;
  1559. // Set the criteria back into the rule
  1560. PropVariantClear(&propvar);
  1561. propvar.vt = VT_BLOB;
  1562. propvar.blob.cbSize = ccitem * sizeof(CRIT_ITEM);
  1563. propvar.blob.pBlobData = (BYTE *) pcitem;
  1564. hr = pIRule->SetProp(RULE_PROP_CRITERIA, 0, &propvar);
  1565. ZeroMemory(&propvar, sizeof(propvar));
  1566. if (FAILED(hr))
  1567. {
  1568. goto exit;
  1569. }
  1570. // Initialize the rule info
  1571. infoRule.ridRule = RULEID_SENDERS;
  1572. infoRule.pIRule = pIRule;
  1573. // Set the rule back into the rules manager
  1574. hr = g_pRulesMan->SetRules(SETF_SENDER, type, &infoRule, 1);
  1575. if (FAILED(hr))
  1576. {
  1577. goto exit;
  1578. }
  1579. // Set the proper return value
  1580. hr = S_OK;
  1581. exit:
  1582. SafeMemFree(pszAddrNew);
  1583. RuleUtil_HrFreeCriteriaItem(pcitem, ccitem);
  1584. SafeMemFree(pcitem);
  1585. PropVariantClear(&propvar);
  1586. SafeRelease(pIRule);
  1587. SafeRelease(pIRuleOrig);
  1588. return hr;
  1589. }
  1590. HRESULT RuleUtil_HrMergeActions(ACT_ITEM * pActionsOrig, ULONG cActionsOrig,
  1591. ACT_ITEM * pActionsNew, ULONG cActionsNew,
  1592. ACT_ITEM ** ppActionsDest, ULONG * pcActionsDest)
  1593. {
  1594. HRESULT hr = S_OK;
  1595. ACT_ITEM * pActions = NULL;
  1596. ULONG cActions = 0;
  1597. ULONG ulIndex = 0;
  1598. ULONG ulAction = 0;
  1599. ULONG cActionsAdded = 0;
  1600. ULONG ulAdd = 0;
  1601. // Verify incoming params
  1602. if (((NULL == pActionsOrig) && (0 != cActionsOrig)) || (NULL == pActionsNew) || (0 == cActionsNew) ||
  1603. (NULL == ppActionsDest) || (NULL == pcActionsDest))
  1604. {
  1605. hr = E_INVALIDARG;
  1606. goto exit;
  1607. }
  1608. // Initialize the outgoing params
  1609. *ppActionsDest = NULL;
  1610. *pcActionsDest = 0;
  1611. // Allocate the maximum space to hold the destination actions
  1612. hr = HrAlloc((VOID **) &pActions, (cActionsOrig + cActionsNew) * sizeof(*pActions));
  1613. if (FAILED(hr))
  1614. {
  1615. goto exit;
  1616. }
  1617. // Initialize the destination actions list
  1618. ZeroMemory(pActions, (cActionsOrig + cActionsNew) * sizeof(*pActions));
  1619. // Copy over the original list to the destination actions list
  1620. for (ulIndex = 0; ulIndex < cActionsOrig; ulIndex++)
  1621. {
  1622. // Copy over the actions info
  1623. pActions[ulIndex].type = pActionsOrig[ulIndex].type;
  1624. pActions[ulIndex].dwFlags = pActionsOrig[ulIndex].dwFlags;
  1625. // Copy over the propvar
  1626. hr = PropVariantCopy(&(pActions[ulIndex].propvar), &(pActionsOrig[ulIndex].propvar));
  1627. if (FAILED(hr))
  1628. {
  1629. goto exit;
  1630. }
  1631. }
  1632. // For each item in the new actions list
  1633. cActionsAdded = cActionsOrig;
  1634. for (ulIndex = 0; ulIndex < cActionsNew; ulIndex++)
  1635. {
  1636. // if it's a copy, fwd or reply
  1637. if ((ACT_TYPE_COPY == pActionsNew->type) ||
  1638. (ACT_TYPE_FWD == pActionsNew->type) ||
  1639. (ACT_TYPE_REPLY == pActionsNew->type))
  1640. {
  1641. // Append it to the list
  1642. ulAdd = cActionsAdded;
  1643. }
  1644. else
  1645. {
  1646. // Find the item in the new list
  1647. for (ulAction = 0; ulAction < cActionsAdded; ulAction++)
  1648. {
  1649. // If we have a match, the replace it
  1650. if (pActionsNew[ulIndex].type == pActions[ulAction].type)
  1651. {
  1652. break;
  1653. }
  1654. // else, if we have some type of move operation
  1655. // then replace it
  1656. else if (((ACT_TYPE_MOVE == pActionsNew[ulIndex].type) ||
  1657. (ACT_TYPE_DELETE == pActionsNew[ulIndex].type) ||
  1658. (ACT_TYPE_JUNKMAIL == pActionsNew[ulIndex].type)) &&
  1659. ((ACT_TYPE_MOVE == pActions[ulAction].type) ||
  1660. (ACT_TYPE_DELETE == pActions[ulAction].type) ||
  1661. (ACT_TYPE_JUNKMAIL == pActions[ulAction].type)))
  1662. {
  1663. break;
  1664. }
  1665. }
  1666. // Did we find anything
  1667. if (ulAction >= cActionsAdded)
  1668. {
  1669. ulAdd = cActionsAdded;
  1670. }
  1671. else
  1672. {
  1673. ulAdd = ulAction;
  1674. }
  1675. }
  1676. // Replace the item
  1677. pActions[ulAdd].type = pActionsNew[ulIndex].type;
  1678. pActions[ulAdd].dwFlags = pActionsNew[ulIndex].dwFlags;
  1679. // Clear out the old propvar
  1680. PropVariantClear(&(pActions[ulAdd].propvar));
  1681. // Copy over the propvar
  1682. hr = PropVariantCopy(&(pActions[ulAdd].propvar), &(pActionsNew[ulIndex].propvar));
  1683. if (FAILED(hr))
  1684. {
  1685. goto exit;
  1686. }
  1687. // If we added something
  1688. if (ulAdd == cActionsAdded)
  1689. {
  1690. cActionsAdded++;
  1691. }
  1692. }
  1693. // Set the outgoing params
  1694. *ppActionsDest = pActions;
  1695. pActions = NULL;
  1696. *pcActionsDest = cActionsAdded;
  1697. // Set the return value
  1698. hr = S_OK;
  1699. exit:
  1700. return hr;
  1701. }
  1702. HRESULT RuleUtil_HrGetOldFormatString(HKEY hkeyRoot, LPCSTR pszValue, LPCSTR pszSep, LPSTR * ppszString, ULONG * pcchString)
  1703. {
  1704. HRESULT hr = S_OK;
  1705. DWORD dwType = 0;
  1706. LPSTR pszData = NULL;
  1707. ULONG cbData = 0;
  1708. LPSTR pszWalk = NULL;
  1709. ULONG ulIndex = 0;
  1710. LPSTR pszTerm = NULL;
  1711. ULONG cchLen = 0;
  1712. ULONG cchString = 0;
  1713. LPSTR pszString = NULL;
  1714. LPSTR pszOld = NULL;
  1715. // Check incoming params
  1716. if ((NULL == hkeyRoot) || (NULL == pszValue) || (NULL == pszSep) || (NULL == ppszString))
  1717. {
  1718. hr = E_INVALIDARG;
  1719. goto exit;
  1720. }
  1721. // Initialize the outgoing params
  1722. *ppszString = NULL;
  1723. if (NULL != pcchString)
  1724. {
  1725. *pcchString = 0;
  1726. }
  1727. // Get the old value from the registry
  1728. hr = RuleUtil_HrGetRegValue(hkeyRoot, pszValue, &dwType, (BYTE **) &pszData, &cbData);
  1729. if (FAILED(hr))
  1730. {
  1731. goto exit;
  1732. }
  1733. // Figure out the number of bytes needed
  1734. pszWalk = pszData;
  1735. cchString = 0;
  1736. for (ulIndex = 0; ulIndex < cbData; ulIndex += cchLen, pszWalk += cchLen)
  1737. {
  1738. // Search for terminator
  1739. pszTerm = StrStr(pszWalk, pszSep);
  1740. // If we have a terminator
  1741. if (NULL != pszTerm)
  1742. {
  1743. cchLen = (ULONG)(pszTerm - pszWalk + 1);
  1744. }
  1745. else
  1746. {
  1747. cchLen = lstrlen(pszWalk) + 1;
  1748. }
  1749. // If this isn't a null string
  1750. if (1 != cchLen)
  1751. {
  1752. // Add the number of characters
  1753. cchString += cchLen;
  1754. }
  1755. }
  1756. // Add in space to hold the terminator
  1757. cchString += 2;
  1758. // Allocate space to hold the final string
  1759. hr = HrAlloc((VOID **) &pszString, cchString * sizeof(*pszString));
  1760. if (FAILED(hr))
  1761. {
  1762. goto exit;
  1763. }
  1764. // Copy over each string
  1765. pszWalk = pszString;
  1766. pszOld = pszData;
  1767. for (ulIndex = 0; ulIndex < cbData; ulIndex += cchLen, pszOld += cchLen)
  1768. {
  1769. // Search for terminator
  1770. pszTerm = StrStr(pszOld, pszSep);
  1771. // If we have a terminator
  1772. if (NULL != pszTerm)
  1773. {
  1774. cchLen = (ULONG)(pszTerm - pszOld + 1);
  1775. }
  1776. else
  1777. {
  1778. cchLen = lstrlen(pszOld) + 1;
  1779. }
  1780. // If this isn't a null string
  1781. if (1 != cchLen)
  1782. {
  1783. // Copy over the string
  1784. StrCpyN(pszWalk, pszOld, cchLen);
  1785. // Move to the next string
  1786. pszWalk += lstrlen(pszWalk) + 1;
  1787. }
  1788. }
  1789. // Terminate the string
  1790. pszWalk[0] = '\0';
  1791. pszWalk[1] = '\0';
  1792. // Set the outgoing params
  1793. *ppszString = pszString;
  1794. pszString = NULL;
  1795. if (NULL != pcchString)
  1796. {
  1797. *pcchString = cchString;
  1798. }
  1799. // Set the return value
  1800. hr = S_OK;
  1801. exit:
  1802. SafeMemFree(pszString);
  1803. SafeMemFree(pszData);
  1804. return hr;
  1805. }
  1806. // ------------------------------------------------------------------------------------
  1807. // _FIsLoopingAddress
  1808. // ------------------------------------------------------------------------------------
  1809. BOOL _FIsLoopingAddress(LPCSTR pszAddressTo)
  1810. {
  1811. // Locals
  1812. HRESULT hr=S_OK;
  1813. LPSTR pszAddress=NULL;
  1814. CHAR szFrom[CCHMAX_EMAIL_ADDRESS];
  1815. BOOL fResult=FALSE;
  1816. IImnEnumAccounts *pEnum=NULL;
  1817. IImnAccount *pAccount=NULL;
  1818. // Check State
  1819. Assert(pszAddressTo);
  1820. // Enumerate the user's SMTP and POP3 Accounts
  1821. CHECKHR(hr = g_pAcctMan->Enumerate(SRV_POP3 | SRV_SMTP, &pEnum));
  1822. // Duplicate the To Address
  1823. CHECKALLOC(pszAddress = PszDupA(pszAddressTo));
  1824. // Make it lower case
  1825. CharLower(pszAddress);
  1826. // Enumerate
  1827. while(SUCCEEDED(pEnum->GetNext(&pAccount)))
  1828. {
  1829. // Get Email Address
  1830. if (SUCCEEDED(pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szFrom, ARRAYSIZE(szFrom))))
  1831. {
  1832. // Lower it
  1833. CharLower(szFrom);
  1834. // Is this to myself
  1835. if (StrStr(pszAddress, szFrom) || StrStr(szFrom, pszAddress))
  1836. {
  1837. fResult = TRUE;
  1838. goto exit;
  1839. }
  1840. }
  1841. // Done
  1842. SafeRelease(pAccount);
  1843. }
  1844. exit:
  1845. // Cleanup
  1846. SafeRelease(pEnum);
  1847. SafeRelease(pAccount);
  1848. SafeMemFree(pszAddress);
  1849. // Done
  1850. return fResult;
  1851. }
  1852. // ------------------------------------------------------------------------------------
  1853. // _HrAutoForwardMessage
  1854. // ------------------------------------------------------------------------------------
  1855. HRESULT _HrAutoForwardMessage(HWND hwndUI, LPCSTR pszForwardTo, LPCSTR pszAcctId, IStream *pstmMsg, BOOL *pfLoop)
  1856. {
  1857. // Locals
  1858. HRESULT hr=S_OK;
  1859. IMimeMessage *pMessage=NULL;
  1860. PROPVARIANT rUserData;
  1861. IMimeAddressTable *pAddrTable=NULL;
  1862. CHAR szDisplayName[CCHMAX_DISPLAY_NAME];
  1863. CHAR szEmailAddress[CCHMAX_EMAIL_ADDRESS];
  1864. HTMLOPT rHtmlOpt;
  1865. PLAINOPT rPlainOpt;
  1866. BOOL fHTML;
  1867. IImnAccount *pAccount=NULL;
  1868. PROPVARIANT rOption;
  1869. CHAR szId[CCHMAX_ACCOUNT_NAME];
  1870. BOOL fUseDefaultAcct = FALSE;
  1871. BOOL fSendImmediate = FALSE;
  1872. // check Params
  1873. Assert(pstmMsg && pszForwardTo && pfLoop);
  1874. // Init
  1875. *pfLoop = FALSE;
  1876. // Is the new recipient the same as my current email address
  1877. if (NULL == pszForwardTo || _FIsLoopingAddress(pszForwardTo))
  1878. {
  1879. *pfLoop = TRUE;
  1880. return TrapError(E_FAIL);
  1881. }
  1882. // Open the Account
  1883. hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAcctId, &pAccount);
  1884. // If we couldn't find the account, then just use the default
  1885. if (FAILED(hr))
  1886. {
  1887. CHECKHR(hr = g_pAcctMan->GetDefaultAccount(ACCT_MAIL, &pAccount));
  1888. fUseDefaultAcct = TRUE;
  1889. }
  1890. // Create a Message
  1891. CHECKHR(hr = HrCreateMessage(&pMessage));
  1892. // Lets rewind pstmReplyWith
  1893. CHECKHR(hr = HrRewindStream(pstmMsg));
  1894. // Load String into my message object
  1895. CHECKHR(hr = pMessage->Load(pstmMsg));
  1896. // Get the wabal
  1897. CHECKHR(hr = pMessage->GetAddressTable(&pAddrTable));
  1898. // Remove all of the recipients...
  1899. CHECKHR(hr = pAddrTable->DeleteTypes(IAT_ALL));
  1900. // Get Originator Display Name
  1901. CHECKHR(hr = pAccount->GetPropSz(AP_SMTP_DISPLAY_NAME, szDisplayName, ARRAYSIZE(szDisplayName)));
  1902. // Get Originator Email Name
  1903. CHECKHR(hr = pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szEmailAddress, ARRAYSIZE(szEmailAddress)));
  1904. // Add Sender...
  1905. CHECKHR(hr = pAddrTable->Append(IAT_FROM, IET_DECODED, szDisplayName, szEmailAddress, NULL));
  1906. // Add Recipient
  1907. CHECKHR(hr = pAddrTable->AppendRfc822(IAT_TO, IET_DECODED, pszForwardTo));
  1908. // Save the AccountID
  1909. rUserData.vt = VT_LPSTR;
  1910. if (FALSE == fUseDefaultAcct)
  1911. {
  1912. rUserData.pszVal = (LPSTR) pszAcctId;
  1913. }
  1914. else
  1915. {
  1916. if (SUCCEEDED(pAccount->GetPropSz(AP_ACCOUNT_ID, szId, sizeof(szId))))
  1917. {
  1918. rUserData.pszVal = szId;
  1919. }
  1920. else
  1921. {
  1922. rUserData.pszVal = (LPSTR) pszAcctId;
  1923. }
  1924. }
  1925. pMessage->SetProp(PIDTOSTR(PID_ATT_ACCOUNTID), 0, &rUserData);
  1926. // Save the Account
  1927. CHECKHR(hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, szId, sizeof(szId)))
  1928. rUserData.pszVal = szId;
  1929. pMessage->SetProp(STR_ATT_ACCOUNTNAME, 0, &rUserData);
  1930. // Raid-33842: Set the date
  1931. CHECKHR(hr = HrSetSentTimeProp(pMessage, NULL));
  1932. // Get Mail Options
  1933. GetDefaultOptInfo(&rHtmlOpt, &rPlainOpt, &fHTML, FMT_MAIL);
  1934. // Store the options on the messaage
  1935. CHECKHR(hr = HrSetMailOptionsOnMessage(pMessage, &rHtmlOpt, &rPlainOpt, NULL, fHTML));
  1936. // Raid-63259: MIMEOLE - Creating message ID causes autodialer to fire
  1937. // Raid-50793: Athena: Should be setting message-ID's in email
  1938. #if 0
  1939. rOption.vt = VT_BOOL;
  1940. rOption.boolVal = TRUE;
  1941. pMessage->SetOption(OID_GENERATE_MESSAGE_ID, &rOption);
  1942. #endif
  1943. // Should we send it immediately?
  1944. fSendImmediate = DwGetOption(OPT_SENDIMMEDIATE);
  1945. // Send the message
  1946. CHECKHR(hr = HrSendMailToOutBox(hwndUI, pMessage, fSendImmediate, TRUE));
  1947. exit:
  1948. // Cleanup
  1949. SafeRelease(pMessage);
  1950. SafeRelease(pAddrTable);
  1951. SafeRelease(pAccount);
  1952. // done
  1953. return hr;
  1954. }
  1955. // ------------------------------------------------------------------------------------
  1956. // _HrAutoReplyMessage
  1957. // ------------------------------------------------------------------------------------
  1958. HRESULT _HrAutoReplyMessage(HWND hwndUI, DWORD dwType, LPCSTR pszFilename, IStream * pstmFile,
  1959. LPCSTR pszAcctId, IMimeMessage *pMsgIn, BOOL *pfLoop)
  1960. {
  1961. // Locals
  1962. HRESULT hr=S_OK;
  1963. CHAR szRe[20];
  1964. IMimeMessage *pMsgOut=NULL;
  1965. LPSTR pszNewSubj=NULL,
  1966. pszCurSubj=NULL,
  1967. pszNormal;
  1968. IMimeAddressTable *pTable=NULL;
  1969. ADDRESSPROPS rSender;
  1970. HBODY hBody;
  1971. CHAR szDisplayName[CCHMAX_DISPLAY_NAME];
  1972. CHAR szEmailAddress[CCHMAX_EMAIL_ADDRESS];
  1973. PROPVARIANT rUserData;
  1974. HTMLOPT rHtmlOpt;
  1975. PLAINOPT rPlainOpt;
  1976. BOOL fHTML;
  1977. IImnAccount *pAccount=NULL;
  1978. PROPVARIANT rOption;
  1979. CHAR szId[CCHMAX_ACCOUNT_NAME];
  1980. BOOL fUseDefaultAcct = FALSE;
  1981. BOOL fSendImmediate = FALSE;
  1982. // Problems
  1983. // PMsgIn can be NULL in here (Access Dineied for S/MIME messages.
  1984. // shoul return immediatelly
  1985. if(!pMsgIn)
  1986. return(hr);
  1987. Assert(pszFilename && pstmFile && pMsgIn && pfLoop);
  1988. // Init
  1989. *pfLoop = FALSE;
  1990. // Init
  1991. ZeroMemory(&rSender, sizeof(ADDRESSPROPS));
  1992. // Open the Account
  1993. hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAcctId, &pAccount);
  1994. // If we couldn't find the account, then just use the default
  1995. if (FAILED(hr))
  1996. {
  1997. CHECKHR(hr = g_pAcctMan->GetDefaultAccount(ACCT_MAIL, &pAccount));
  1998. fUseDefaultAcct = TRUE;
  1999. }
  2000. // Create a Message
  2001. CHECKHR(hr = HrCreateMessage(&pMsgOut));
  2002. // Lets rewind pstmFile
  2003. CHECKHR(hr = HrRewindStream(pstmFile));
  2004. // RW_HTML
  2005. switch (dwType)
  2006. {
  2007. case RFT_HTML:
  2008. // Use the stream as the message body
  2009. CHECKHR(hr = pMsgOut->SetTextBody(TXT_HTML, IET_DECODED, NULL, pstmFile, NULL));
  2010. break;
  2011. case RFT_TEXT:
  2012. // Use the stream as the message body
  2013. CHECKHR(hr = pMsgOut->SetTextBody(TXT_PLAIN, IET_DECODED, NULL, pstmFile, NULL));
  2014. break;
  2015. case RFT_MESSAGE:
  2016. // Use the stream as a message attachment
  2017. CHECKHR(hr = pMsgOut->AttachObject(IID_IStream, pstmFile, &hBody));
  2018. // Note that the attachment is a message
  2019. MimeOleSetBodyPropA(pMsgOut, hBody, PIDTOSTR(PID_HDR_CNTTYPE), NOFLAGS, STR_MIME_MSG_RFC822);
  2020. break;
  2021. case RFT_FILE:
  2022. // Attach File
  2023. CHECKHR(hr = pMsgOut->AttachFile(pszFilename, pstmFile, NULL));
  2024. break;
  2025. default:
  2026. Assert(FALSE);
  2027. hr = E_FAIL;
  2028. goto exit;
  2029. break;
  2030. }
  2031. // Get Re:
  2032. AthLoadString(idsPrefixReply, szRe, ARRAYSIZE(szRe));
  2033. // Get the normalized subject
  2034. if (SUCCEEDED(MimeOleGetBodyPropA(pMsgIn, HBODY_ROOT, STR_ATT_NORMSUBJ, NOFLAGS, &pszCurSubj)))
  2035. pszNormal = pszCurSubj;
  2036. // Fixup if null...
  2037. pszNormal = pszNormal ? pszNormal : (LPTSTR)c_szEmpty;
  2038. // Allocate the subject...
  2039. DWORD cchSize = (lstrlen(szRe) + lstrlen(pszNormal) + 5);
  2040. CHECKALLOC(pszNewSubj = PszAllocA(cchSize));
  2041. // Build the subject
  2042. wnsprintf(pszNewSubj, cchSize, "%s%s", szRe, pszNormal);
  2043. // Set the subject
  2044. CHECKHR(hr = MimeOleSetBodyPropA(pMsgOut, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, pszNewSubj));
  2045. // Get the message Wabal
  2046. rSender.dwProps = IAP_EMAIL | IAP_FRIENDLY;
  2047. CHECKHR(hr = pMsgIn->GetSender(&rSender));
  2048. Assert(rSender.pszEmail && ISFLAGSET(rSender.dwProps, IAP_EMAIL));
  2049. // Is the new recipient the same as my current email address
  2050. if (_FIsLoopingAddress(rSender.pszEmail))
  2051. {
  2052. *pfLoop = TRUE;
  2053. hr = TrapError(E_FAIL);
  2054. goto exit;
  2055. }
  2056. // Add to recipient list of autgen message
  2057. CHECKHR(hr = pMsgOut->GetAddressTable(&pTable));
  2058. // Modify rSender Address Type
  2059. rSender.dwAdrType = IAT_TO;
  2060. FLAGSET(rSender.dwProps, IAP_ADRTYPE);
  2061. // Append Sender as the recipient
  2062. CHECKHR(hr = pTable->Insert(&rSender, NULL));
  2063. // Get Originator Display Name
  2064. CHECKHR(hr = pAccount->GetPropSz(AP_SMTP_DISPLAY_NAME, szDisplayName, ARRAYSIZE(szDisplayName)));
  2065. // Get Originator Email Name
  2066. CHECKHR(hr = pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szEmailAddress, ARRAYSIZE(szEmailAddress)));
  2067. // Append Sender
  2068. CHECKHR(hr = pTable->Append(IAT_FROM, IET_DECODED, szDisplayName, szEmailAddress, NULL));
  2069. // Save the AccountID
  2070. rUserData.vt = VT_LPSTR;
  2071. if (FALSE == fUseDefaultAcct)
  2072. {
  2073. rUserData.pszVal = (LPSTR) pszAcctId;
  2074. }
  2075. else
  2076. {
  2077. if (SUCCEEDED(pAccount->GetPropSz(AP_ACCOUNT_ID, szId, sizeof(szId))))
  2078. {
  2079. rUserData.pszVal = szId;
  2080. }
  2081. else
  2082. {
  2083. rUserData.pszVal = (LPSTR) pszAcctId;
  2084. }
  2085. }
  2086. pMsgOut->SetProp(PIDTOSTR(PID_ATT_ACCOUNTID), 0, &rUserData);
  2087. // Save the Account
  2088. CHECKHR(hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, szId, sizeof(szId)))
  2089. rUserData.pszVal = szId;
  2090. pMsgOut->SetProp(STR_ATT_ACCOUNTNAME, 0, &rUserData);
  2091. // Raid-33842: Set the date
  2092. CHECKHR(hr = HrSetSentTimeProp(pMsgOut, NULL));
  2093. // Get Mail Options
  2094. GetDefaultOptInfo(&rHtmlOpt, &rPlainOpt, &fHTML, FMT_MAIL);
  2095. // Store the options on the messaage
  2096. CHECKHR(hr = HrSetMailOptionsOnMessage(pMsgOut, &rHtmlOpt, &rPlainOpt, NULL, fHTML));
  2097. // Raid-63259: MIMEOLE - Creating message ID causes autodialer to fire
  2098. // Raid-50793: Athena: Should be setting message-ID's in email
  2099. #if 0
  2100. rOption.vt = VT_BOOL;
  2101. rOption.boolVal = TRUE;
  2102. pMsgOut->SetOption(OID_GENERATE_MESSAGE_ID, &rOption);
  2103. #endif
  2104. // Should we send it immediately?
  2105. fSendImmediate = DwGetOption(OPT_SENDIMMEDIATE);
  2106. // Send the message
  2107. CHECKHR(hr = HrSendMailToOutBox(hwndUI, pMsgOut, fSendImmediate, TRUE));
  2108. exit:
  2109. // Cleanup
  2110. SafeRelease(pTable);
  2111. SafeMemFree(pszCurSubj);
  2112. SafeMemFree(pszNewSubj);
  2113. SafeRelease(pMsgOut);
  2114. SafeRelease(pAccount);
  2115. g_pMoleAlloc->FreeAddressProps(&rSender);
  2116. // Done
  2117. return hr;
  2118. }
  2119. HRESULT _HrRecurseSetFilter(FOLDERINFO * pfldinfo, BOOL fSubFolders, DWORD cIndent, DWORD_PTR dwCookie)
  2120. {
  2121. RULEID ridRule = RULEID_INVALID;
  2122. IMessageFolder * pFolder = NULL;
  2123. FOLDERUSERDATA UserData = {0};
  2124. ridRule = (RULEID) dwCookie;
  2125. if (RULEID_INVALID == ridRule)
  2126. {
  2127. goto exit;
  2128. }
  2129. // If not hidden
  2130. if ((0 != (pfldinfo->dwFlags & FOLDER_HIDDEN)) || (FOLDERID_ROOT == pfldinfo->idFolder))
  2131. {
  2132. goto exit;
  2133. }
  2134. // Not Subscribed
  2135. if (0 == (pfldinfo->dwFlags & FOLDER_SUBSCRIBED))
  2136. {
  2137. goto exit;
  2138. }
  2139. // Server node
  2140. if (0 != (pfldinfo->dwFlags & FOLDER_SERVER))
  2141. {
  2142. goto exit;
  2143. }
  2144. if (FAILED(g_pStore->OpenFolder(pfldinfo->idFolder, NULL, OPEN_FOLDER_NOCREATE, &pFolder)))
  2145. {
  2146. goto exit;
  2147. }
  2148. if ((FOLDER_LOCAL == pfldinfo->tyFolder) && (RULEID_VIEW_DOWNLOADED == ridRule))
  2149. {
  2150. ridRule = RULEID_VIEW_ALL;
  2151. }
  2152. // Create the struct to insert
  2153. if (FAILED(pFolder->GetUserData(&UserData, sizeof(FOLDERUSERDATA))))
  2154. {
  2155. goto exit;
  2156. }
  2157. UserData.ridFilter = ridRule;
  2158. UserData.dwFilterVersion = 0xFFFFFFFF;
  2159. if (FAILED(pFolder->SetUserData(&UserData, sizeof(FOLDERUSERDATA))))
  2160. {
  2161. goto exit;
  2162. }
  2163. exit:
  2164. SafeRelease(pFolder);
  2165. return S_OK;
  2166. }
  2167. HRESULT RuleUtil_HrApplyRulesToFolder(DWORD dwFlags, DWORD dwDeleteFlags,
  2168. IOEExecRules * pIExecRules, IMessageFolder * pFolder, HWND hwndUI, CProgress * pProgress)
  2169. {
  2170. HRESULT hr = S_OK;
  2171. HCURSOR hcursor = NULL;
  2172. FOLDERID idFolder = FOLDERID_ROOT;
  2173. HLOCK hLockNotify = NULL;
  2174. HROWSET hRowset = NULL;
  2175. MESSAGEINFO Message = {0};
  2176. IMimeMessage * pIMMsg = NULL;
  2177. IMimePropertySet * pIMPropSet = NULL;
  2178. ACT_ITEM * pActions = NULL;
  2179. ULONG cActions = 0;
  2180. DWORD dwExecFlags = 0;
  2181. // Wait Cursor
  2182. if (NULL == pProgress)
  2183. {
  2184. hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2185. }
  2186. // Check incoming params
  2187. if ((NULL == pIExecRules) || (NULL == pFolder))
  2188. {
  2189. hr = E_INVALIDARG;
  2190. goto exit;
  2191. }
  2192. // Get the Folder Id
  2193. hr = pFolder->GetFolderId(&idFolder);
  2194. if (FAILED(hr))
  2195. {
  2196. goto exit;
  2197. }
  2198. // We handle partial messages for News
  2199. if (FOLDER_NEWS != GetFolderType(idFolder))
  2200. {
  2201. dwExecFlags |= ERF_SKIPPARTIALS;
  2202. }
  2203. // This forces all notifications to be queued (this is good since you do segmented deletes)
  2204. pFolder->LockNotify(0, &hLockNotify);
  2205. // Create a Rowset
  2206. hr = pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset);
  2207. if (FAILED(hr))
  2208. {
  2209. goto exit;
  2210. }
  2211. // Loop
  2212. while (S_OK == pFolder->QueryRowset(hRowset, 1, (LPVOID *)&Message, NULL))
  2213. {
  2214. // Do we need to only handle partial messages?
  2215. if ((0 == (dwFlags & RULE_APPLY_PARTIALS)) || (MESSAGE_COMBINED == Message.dwPartial))
  2216. {
  2217. // Open the message object if it's available
  2218. if (Message.faStream)
  2219. {
  2220. if (SUCCEEDED(pFolder->OpenMessage(Message.idMessage, 0, &pIMMsg, NOSTORECALLBACK)))
  2221. {
  2222. pIMMsg->BindToObject(HBODY_ROOT, IID_IMimePropertySet, (LPVOID *)&pIMPropSet);
  2223. }
  2224. }
  2225. // Get the Actions for this rule
  2226. hr = pIExecRules->ExecuteRules(dwExecFlags, Message.pszAcctId, &Message, pFolder, pIMPropSet,
  2227. pIMMsg, Message.cbMessage, &pActions, &cActions);
  2228. // Free up the stuff we're not using anymore
  2229. SafeRelease(pIMPropSet);
  2230. // Did we find anything?
  2231. if (S_OK == hr)
  2232. {
  2233. // Apply this action
  2234. SideAssert(SUCCEEDED(RuleUtil_HrApplyActions(hwndUI, pIExecRules, &Message,
  2235. pFolder, pIMMsg, dwDeleteFlags, pActions, cActions, NULL, NULL)));
  2236. // Free up the actions
  2237. RuleUtil_HrFreeActionsItem(pActions, cActions);
  2238. SafeMemFree(pActions);
  2239. }
  2240. SafeRelease(pIMMsg);
  2241. }
  2242. pFolder->FreeRecord(&Message);
  2243. // Update progress
  2244. if (NULL != pProgress)
  2245. {
  2246. if (S_OK != pProgress->HrUpdate(1))
  2247. {
  2248. hr = S_FALSE;
  2249. goto exit;
  2250. }
  2251. }
  2252. }
  2253. hr = S_OK;
  2254. exit:
  2255. RuleUtil_HrFreeActionsItem(pActions, cActions);
  2256. SafeMemFree(pActions);
  2257. SafeRelease(pIMPropSet);
  2258. SafeRelease(pIMMsg);
  2259. pFolder->FreeRecord(&Message);
  2260. pFolder->CloseRowset(&hRowset);
  2261. if (NULL != hLockNotify)
  2262. {
  2263. pFolder->UnlockNotify(&hLockNotify);
  2264. }
  2265. if (NULL == pProgress)
  2266. {
  2267. SetCursor(hcursor);
  2268. }
  2269. return hr;
  2270. }
  2271. ///////////////////////////////////////////////////////////////////////////////
  2272. //
  2273. // RuleUtil_HrImportRules
  2274. //
  2275. // This imports the rules from a file
  2276. //
  2277. // Returns: NONE
  2278. //
  2279. ///////////////////////////////////////////////////////////////////////////////
  2280. HRESULT RuleUtil_HrImportRules(HWND hwnd)
  2281. {
  2282. HRESULT hr = S_OK;
  2283. OPENFILENAME ofn;
  2284. CHAR szFilename[MAX_PATH] = _T("");
  2285. CHAR szFilter[MAX_PATH] = _T("");
  2286. CHAR szDefExt[20] = _T("");
  2287. IStream * pIStm = NULL;
  2288. CLSID clsid = {0};
  2289. ULONG cbRead = 0;
  2290. ULONG cRules = 0;
  2291. RULEINFO * pinfoRule = NULL;
  2292. CProgress * pProgress = NULL;
  2293. ULONG ulIndex = 0;
  2294. IOERule * pIRule = NULL;
  2295. IPersistStream * pIPStm = NULL;
  2296. DWORD dwData = 0;
  2297. RULE_TYPE type;
  2298. // Load Res Strings
  2299. LoadStringReplaceSpecial(idsRulesFilter, szFilter, sizeof(szFilter));
  2300. AthLoadString(idsDefRulesExt, szDefExt, sizeof(szDefExt));
  2301. // Setup Save file struct
  2302. ZeroMemory (&ofn, sizeof (ofn));
  2303. ofn.lStructSize = sizeof (ofn);
  2304. ofn.hwndOwner = hwnd;
  2305. ofn.lpstrFilter = szFilter;
  2306. ofn.nFilterIndex = 1;
  2307. ofn.lpstrFile = szFilename;
  2308. ofn.nMaxFile = MAX_PATH;
  2309. ofn.lpstrDefExt = szDefExt;
  2310. ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
  2311. hr = HrAthGetFileName(&ofn, TRUE);
  2312. if (S_OK != hr)
  2313. {
  2314. goto exit;
  2315. }
  2316. hr = CreateStreamOnHFile(szFilename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  2317. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL, &pIStm);
  2318. if (FAILED(hr))
  2319. {
  2320. goto exit;
  2321. }
  2322. // MAke sure we have a file using our Rules Manager
  2323. hr = pIStm->Read(&clsid, sizeof(clsid), &cbRead);
  2324. if (FAILED(hr))
  2325. {
  2326. goto exit;
  2327. }
  2328. Assert(cbRead == sizeof(clsid));
  2329. if (clsid != CLSID_OERulesManager)
  2330. {
  2331. Assert("Ahhhhh This is a bogus file!!!!!");
  2332. hr = E_FAIL;
  2333. goto exit;
  2334. }
  2335. // Read in the version of the rules file format
  2336. hr = pIStm->Read(&dwData, sizeof(dwData), &cbRead);
  2337. if (FAILED(hr))
  2338. {
  2339. goto exit;
  2340. }
  2341. Assert(cbRead == sizeof(dwData));
  2342. // Check the file format version
  2343. if (dwData != RULE_FILE_VERSION)
  2344. {
  2345. AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena),
  2346. MAKEINTRESOURCEW(idsRulesErrBadFileFormat), NULL, MB_ICONINFORMATION | MB_OK);
  2347. hr = E_FAIL;
  2348. goto exit;
  2349. }
  2350. // Get the count of rules in the file
  2351. hr = pIStm->Read(&cRules, sizeof(cRules), &cbRead);
  2352. if (FAILED(hr))
  2353. {
  2354. goto exit;
  2355. }
  2356. Assert(cbRead == sizeof(cRules));
  2357. // Allocate space to hold all of the rules
  2358. hr = HrAlloc((void **) &pinfoRule, cRules * sizeof(*pinfoRule));
  2359. if (FAILED(hr))
  2360. {
  2361. goto exit;
  2362. }
  2363. // Initialize it to a known value
  2364. ZeroMemory(pinfoRule, cRules * sizeof(*pinfoRule));
  2365. // Get the type of rules in the file
  2366. hr = pIStm->Read(&dwData, sizeof(dwData), &cbRead);
  2367. if (FAILED(hr))
  2368. {
  2369. goto exit;
  2370. }
  2371. Assert(cbRead == sizeof(dwData));
  2372. type = (RULE_TYPE) dwData;
  2373. // Set up the progress dialog
  2374. pProgress = new CProgress;
  2375. if (NULL == pProgress)
  2376. {
  2377. hr = E_OUTOFMEMORY;
  2378. goto exit;
  2379. }
  2380. pProgress->Init(hwnd, MAKEINTRESOURCE(idsAthena),
  2381. MAKEINTRESOURCE(idsApplyingRules), cRules, 0, TRUE, FALSE);
  2382. // Show progress in 2 second
  2383. pProgress->Show(0);
  2384. for (ulIndex = 0; ulIndex < cRules; ulIndex++)
  2385. {
  2386. SafeRelease(pIRule);
  2387. // Create a new rule
  2388. hr = HrCreateRule(&pIRule);
  2389. if (FAILED(hr))
  2390. {
  2391. continue;
  2392. }
  2393. SafeRelease(pIPStm);
  2394. // Get the persistance interface from the rule
  2395. hr = pIRule->QueryInterface(IID_IPersistStream, (void **) &pIPStm);
  2396. if (FAILED(hr))
  2397. {
  2398. continue;
  2399. }
  2400. // Load in the rule from the file
  2401. hr = pIPStm->Load(pIStm);
  2402. if (FAILED(hr))
  2403. {
  2404. continue;
  2405. }
  2406. // Add the rule to the list
  2407. pinfoRule[ulIndex].ridRule = RULEID_INVALID;
  2408. pinfoRule[ulIndex].pIRule = pIRule;
  2409. pIRule = NULL;
  2410. // Bump up the progress dialog
  2411. hr = pProgress->HrUpdate(1);
  2412. if (S_OK != hr)
  2413. {
  2414. break;
  2415. }
  2416. }
  2417. // Add the rules to the rules manager
  2418. Assert(NULL != g_pRulesMan);
  2419. hr = g_pRulesMan->SetRules(SETF_APPEND, type, pinfoRule, cRules);
  2420. if (FAILED(hr))
  2421. {
  2422. goto exit;
  2423. }
  2424. hr = S_OK;
  2425. exit:
  2426. SafeRelease(pIRule);
  2427. SafeRelease(pProgress);
  2428. SafeRelease(pIPStm);
  2429. if (NULL != pinfoRule)
  2430. {
  2431. for (ulIndex = 0; ulIndex < cRules; ulIndex++)
  2432. {
  2433. SafeRelease(pinfoRule[ulIndex].pIRule);
  2434. }
  2435. MemFree(pinfoRule);
  2436. }
  2437. SafeRelease(pIStm);
  2438. return hr;
  2439. }
  2440. ///////////////////////////////////////////////////////////////////////////////
  2441. //
  2442. // RuleUtil_HrExportRules
  2443. //
  2444. // This exports the rules into a file
  2445. //
  2446. // Returns: NONE
  2447. //
  2448. ///////////////////////////////////////////////////////////////////////////////
  2449. HRESULT RuleUtil_HrExportRules(HWND hwnd)
  2450. {
  2451. HRESULT hr = S_OK;
  2452. OPENFILENAME ofn;
  2453. CHAR szFilename[MAX_PATH] = _T("");
  2454. CHAR szFilter[MAX_PATH] = _T("");
  2455. CHAR szDefExt[20] = _T("");
  2456. IStream * pIStm = NULL;
  2457. ULONG cbWritten = 0;
  2458. IOEEnumRules * pIEnumRules = NULL;
  2459. ULONG cpIRule = 0;
  2460. IPersistStream * pIPStm = NULL;
  2461. CProgress * pProgress = NULL;
  2462. ULONG ulIndex = 0;
  2463. IOERule * pIRule = NULL;
  2464. LARGE_INTEGER liSeek = {0};
  2465. DWORD dwData = 0;
  2466. // Load Res Strings
  2467. LoadStringReplaceSpecial(idsRulesFilter, szFilter, sizeof(szFilter));
  2468. AthLoadString(idsDefRulesExt, szDefExt, sizeof(szDefExt));
  2469. AthLoadString(idsRulesDefFile, szFilename, sizeof(szFilename));
  2470. // Setup Save file struct
  2471. ZeroMemory (&ofn, sizeof (ofn));
  2472. ofn.lStructSize = sizeof (ofn);
  2473. ofn.hwndOwner = hwnd;
  2474. ofn.lpstrFilter = szFilter;
  2475. ofn.nFilterIndex = 1;
  2476. ofn.lpstrFile = szFilename;
  2477. ofn.nMaxFile = MAX_PATH;
  2478. ofn.lpstrDefExt = szDefExt;
  2479. ofn.Flags = OFN_NOCHANGEDIR | OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  2480. hr = HrAthGetFileName(&ofn, FALSE);
  2481. if (S_OK != hr)
  2482. {
  2483. goto exit;
  2484. }
  2485. hr = CreateStreamOnHFile(szFilename, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  2486. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL, &pIStm);
  2487. if (FAILED(hr))
  2488. {
  2489. goto exit;
  2490. }
  2491. // Write out the class id for the Rules Manager
  2492. hr = pIStm->Write(&CLSID_OERulesManager, sizeof(CLSID_OERulesManager), &cbWritten);
  2493. if (FAILED(hr))
  2494. {
  2495. goto exit;
  2496. }
  2497. Assert(cbWritten == sizeof(CLSID_OERulesManager));
  2498. // Write out the version of the rules format
  2499. dwData = RULE_FILE_VERSION;
  2500. hr = pIStm->Write(&dwData, sizeof(dwData), &cbWritten);
  2501. if (FAILED(hr))
  2502. {
  2503. goto exit;
  2504. }
  2505. Assert(cbWritten == sizeof(dwData));
  2506. // Get the list of rules
  2507. Assert(NULL != g_pRulesMan);
  2508. hr = g_pRulesMan->EnumRules(ENUMF_EDIT, RULE_TYPE_MAIL, &pIEnumRules);
  2509. if (FAILED(hr))
  2510. {
  2511. goto exit;
  2512. }
  2513. // Figure out the total number of rules
  2514. cpIRule = 0;
  2515. while (S_OK == pIEnumRules->Next(1, &pIRule, NULL))
  2516. {
  2517. cpIRule++;
  2518. SafeRelease(pIRule);
  2519. }
  2520. hr = pIEnumRules->Reset();
  2521. if (FAILED(hr))
  2522. {
  2523. goto exit;
  2524. }
  2525. // Write out the number of rules going to be exported
  2526. hr = pIStm->Write(&cpIRule, sizeof(cpIRule), &cbWritten);
  2527. if (FAILED(hr))
  2528. {
  2529. goto exit;
  2530. }
  2531. Assert(cbWritten == sizeof(cpIRule));
  2532. // Write out the type of rules going to be exported
  2533. dwData = RULE_TYPE_MAIL;
  2534. hr = pIStm->Write(&dwData, sizeof(dwData), &cbWritten);
  2535. if (FAILED(hr))
  2536. {
  2537. goto exit;
  2538. }
  2539. Assert(cbWritten == sizeof(dwData));
  2540. // Set up the progress dialog
  2541. pProgress = new CProgress;
  2542. if (NULL == pProgress)
  2543. {
  2544. hr = E_OUTOFMEMORY;
  2545. goto exit;
  2546. }
  2547. pProgress->Init(hwnd, MAKEINTRESOURCE(idsAthena),
  2548. MAKEINTRESOURCE(idsApplyingRules), cpIRule, 0, TRUE, FALSE);
  2549. // Show progress in 2 seconds
  2550. pProgress->Show(0);
  2551. for (ulIndex = 0; ulIndex < cpIRule; ulIndex++)
  2552. {
  2553. // Get the next rule
  2554. SafeRelease(pIRule);
  2555. hr = pIEnumRules->Next(1, &pIRule, NULL);
  2556. if (FAILED(hr))
  2557. {
  2558. continue;
  2559. }
  2560. Assert(S_OK == hr);
  2561. SafeRelease(pIPStm);
  2562. if (FAILED(pIRule->QueryInterface(IID_IPersistStream, (void **) &pIPStm)))
  2563. {
  2564. continue;
  2565. }
  2566. if (FAILED(pIPStm->Save(pIStm, FALSE)))
  2567. {
  2568. continue;
  2569. }
  2570. // Update progress
  2571. if (S_OK != pProgress->HrUpdate(1))
  2572. {
  2573. // Change the rule count to the proper total
  2574. liSeek.QuadPart = sizeof(CLSID_OERulesManager);
  2575. if (SUCCEEDED(pIStm->Seek(liSeek, STREAM_SEEK_SET, NULL)))
  2576. {
  2577. ulIndex++;
  2578. SideAssert(SUCCEEDED(pIStm->Write(&ulIndex, sizeof(ulIndex), &cbWritten)));
  2579. Assert(cbWritten == sizeof(ulIndex));
  2580. }
  2581. break;
  2582. }
  2583. }
  2584. hr = S_OK;
  2585. exit:
  2586. SafeRelease(pIPStm);
  2587. SafeRelease(pIRule);
  2588. SafeRelease(pProgress);
  2589. SafeRelease(pIEnumRules);
  2590. SafeRelease(pIStm);
  2591. return hr;
  2592. }
  2593. typedef struct _tagFOLDERIDMAP
  2594. {
  2595. FOLDERID dwFldIdOld;
  2596. FOLDERID dwFldIdNew;
  2597. } FOLDERIDMAP, * PFOLDERIDMAP;
  2598. HRESULT RuleUtil_HrMapFldId(DWORD dwFlags, BYTE * pbFldIdMap, FOLDERID fldidOld, FOLDERID * pfldidNew)
  2599. {
  2600. HRESULT hr = S_OK;
  2601. ULONG cmpfldid = 0;
  2602. FOLDERIDMAP * pmpfldid;
  2603. ULONG ulIndex = 0;
  2604. // Verify incoming params
  2605. if ((NULL == pbFldIdMap) || (FOLDERID_INVALID == fldidOld) || (NULL == pfldidNew))
  2606. {
  2607. hr = E_INVALIDARG;
  2608. goto exit;
  2609. }
  2610. // Initialize the outgoing param
  2611. *pfldidNew = FOLDERID_INVALID;
  2612. cmpfldid = *((DWORD *) pbFldIdMap);
  2613. if (0 == cmpfldid)
  2614. {
  2615. goto exit;
  2616. }
  2617. pmpfldid = (FOLDERIDMAP *) (pbFldIdMap + sizeof(cmpfldid));
  2618. for (ulIndex = 0; ulIndex < cmpfldid; ulIndex++)
  2619. {
  2620. if (fldidOld == pmpfldid[ulIndex].dwFldIdOld)
  2621. {
  2622. *pfldidNew = pmpfldid[ulIndex].dwFldIdNew;
  2623. break;
  2624. }
  2625. }
  2626. // Set the return value
  2627. hr = (FOLDERID_INVALID != *pfldidNew) ? S_OK : S_FALSE;
  2628. exit:
  2629. return hr;
  2630. }
  2631. HRESULT RuleUtil_HrGetUserData(DWORD dwFlags, LPSTR * ppszFirstName, LPSTR * ppszLastName, LPSTR * ppszCompanyName)
  2632. {
  2633. HRESULT hr = S_OK;
  2634. LPWAB pWab = NULL;
  2635. LPWABOBJECT pWabObj = NULL;
  2636. SBinary sbEID = {0};
  2637. IAddrBook * pIAddrBook = NULL;
  2638. ULONG ulObjType = 0;
  2639. IMailUser * pIMailUser = NULL;
  2640. SizedSPropTagArray(3, ptaDefMailUser) = {3, {PR_GIVEN_NAME_A, PR_SURNAME_A, PR_COMPANY_NAME_A}};
  2641. ULONG cProps = 0;
  2642. LPSPropValue pProps = NULL;
  2643. LPSPropValue pPropsWalk = NULL;
  2644. if ((NULL == ppszFirstName) || (NULL == ppszLastName) || (NULL == ppszCompanyName))
  2645. {
  2646. hr = E_INVALIDARG;
  2647. goto exit;
  2648. }
  2649. *ppszFirstName = NULL;
  2650. *ppszLastName = NULL;
  2651. *ppszCompanyName = NULL;
  2652. // Get Wab object
  2653. hr = HrCreateWabObject(&pWab);
  2654. if (FAILED(hr))
  2655. {
  2656. goto exit;
  2657. }
  2658. hr = pWab->HrGetWabObject(&pWabObj);
  2659. if (FAILED(hr))
  2660. {
  2661. goto exit;
  2662. }
  2663. hr = pWab->HrGetAdrBook(&pIAddrBook);
  2664. if (FAILED(hr))
  2665. {
  2666. goto exit;
  2667. }
  2668. // Do we already have a concept of me?
  2669. hr = pWabObj->GetMe(pIAddrBook, AB_NO_DIALOG | WABOBJECT_ME_NOCREATE, NULL, &sbEID, NULL);
  2670. if (FAILED(hr))
  2671. {
  2672. goto exit;
  2673. }
  2674. // Open the entry
  2675. hr = pIAddrBook->OpenEntry(sbEID.cb, (ENTRYID *)(sbEID.lpb), NULL, 0, &ulObjType, (IUnknown **) &pIMailUser);
  2676. if (FAILED(hr))
  2677. {
  2678. goto exit;
  2679. }
  2680. // Get the relevant info
  2681. hr = pIMailUser->GetProps((LPSPropTagArray) &ptaDefMailUser, 0, &cProps, &pProps);
  2682. if (FAILED(hr))
  2683. {
  2684. goto exit;
  2685. }
  2686. pPropsWalk = pProps;
  2687. // Grab the first name if it exists
  2688. if ((PR_GIVEN_NAME_A == pPropsWalk->ulPropTag) && (NULL != pPropsWalk->Value.lpszA))
  2689. {
  2690. *ppszFirstName = PszDupA(pPropsWalk->Value.lpszA);
  2691. }
  2692. pPropsWalk++;
  2693. // Grab the last name if it exists
  2694. if ((PR_SURNAME_A == pPropsWalk->ulPropTag) && (NULL != pPropsWalk->Value.lpszA))
  2695. {
  2696. *ppszLastName = PszDupA(pPropsWalk->Value.lpszA);
  2697. }
  2698. pPropsWalk++;
  2699. // Grab the company name if it exists
  2700. if ((PR_COMPANY_NAME_A == pPropsWalk->ulPropTag) && (NULL != pPropsWalk->Value.lpszA))
  2701. {
  2702. *ppszCompanyName = PszDupA(pPropsWalk->Value.lpszA);
  2703. }
  2704. hr = S_OK;
  2705. exit:
  2706. SafeRelease(pIMailUser);
  2707. if (NULL != pWabObj)
  2708. {
  2709. if (NULL != pProps)
  2710. {
  2711. pWabObj->FreeBuffer(pProps);
  2712. }
  2713. if (NULL != sbEID.lpb)
  2714. {
  2715. pWabObj->FreeBuffer(sbEID.lpb);
  2716. }
  2717. }
  2718. SafeRelease(pWab);
  2719. return hr;
  2720. }
  2721. HRESULT _HrMarkThreadAsWatched(MESSAGEID idMessage, IMessageFolder * pFolder, ADJUSTFLAGS * pflgWatch)
  2722. {
  2723. HRESULT hr = S_OK;
  2724. MESSAGEINFO infoMessage = {0};
  2725. // Check incoming param
  2726. if ((MESSAGEID_INVALID == idMessage) || (NULL == pFolder) || (NULL == pflgWatch))
  2727. {
  2728. hr = E_INVALIDARG;
  2729. goto exit;
  2730. }
  2731. // Get the message info
  2732. hr = GetMessageInfo(pFolder, idMessage, &infoMessage);
  2733. if (FAILED(hr))
  2734. {
  2735. goto exit;
  2736. }
  2737. // Add Flags
  2738. FLAGSET(infoMessage.dwFlags, pflgWatch->dwAdd);
  2739. // ClearFlags
  2740. FLAGCLEAR(infoMessage.dwFlags, pflgWatch->dwRemove);
  2741. // Update the Message
  2742. IF_FAILEXIT(hr = pFolder->UpdateRecord(&infoMessage));
  2743. // Set the return value
  2744. hr = S_OK;
  2745. exit:
  2746. pFolder->FreeRecord(&infoMessage);
  2747. return hr;
  2748. }
  2749. HRESULT RuleUtil_HrApplyActions(HWND hwndUI, IOEExecRules * pIExecRules, MESSAGEINFO * pMsgInfo,
  2750. IMessageFolder * pFolder, IMimeMessage * pIMMsg, DWORD dwDeleteFlags,
  2751. ACT_ITEM * pActions, ULONG cActions, ULONG * pcInfiniteLoops, BOOL *pfDeleteOffServer)
  2752. {
  2753. HRESULT hr = S_OK;
  2754. ULONG ulIndex = 0;
  2755. FOLDERID idFolder = 0;
  2756. ACT_ITEM * pActionsList = NULL;
  2757. IMessageFolder * pFolderNew = NULL;
  2758. MESSAGEIDLIST List = {0};
  2759. ADJUSTFLAGS Flags = {0};
  2760. DWORD dwType = RFT_HTML;
  2761. IStream * pIStm = NULL;
  2762. LPSTR pszExt = NULL;
  2763. BOOL fLoop = FALSE;
  2764. DWORD dwFlag = 0;
  2765. FOLDERID idFolderJunkMail = FOLDERID_INVALID;
  2766. RULEFOLDERDATA * prfdData = NULL;
  2767. BOOL fSetFlags = FALSE;
  2768. DWORD dwFlagRemove = 0;
  2769. BOOL fDoWatch = FALSE;
  2770. ADJUSTFLAGS WatchFlags = {0};
  2771. // Check incoming params
  2772. if ((NULL == pIExecRules) || (NULL == pMsgInfo) || (NULL == pActions) || (NULL == pFolder))
  2773. {
  2774. hr = E_INVALIDARG;
  2775. goto exit;
  2776. }
  2777. // Init
  2778. if (pfDeleteOffServer)
  2779. *pfDeleteOffServer = FALSE;
  2780. // Initialize the list
  2781. List.cMsgs = 1;
  2782. List.prgidMsg = &(pMsgInfo->idMessage);
  2783. // Get the folder id of the message
  2784. hr = pFolder->GetFolderId(&idFolder);
  2785. if (FAILED(hr))
  2786. {
  2787. goto exit;
  2788. }
  2789. // Do all modification operations first
  2790. for (pActionsList = pActions, ulIndex = 0; ulIndex < cActions; ulIndex++, pActionsList++)
  2791. {
  2792. switch(pActionsList->type)
  2793. {
  2794. case ACT_TYPE_HIGHLIGHT:
  2795. Assert(pActionsList->propvar.vt == VT_UI4);
  2796. // Is there something to do?
  2797. if (pMsgInfo->wHighlight != (WORD) (pActionsList->propvar.ulVal))
  2798. {
  2799. pMsgInfo->wHighlight = (WORD) (pActionsList->propvar.ulVal);
  2800. pFolder->UpdateRecord(pMsgInfo);
  2801. }
  2802. break;
  2803. case ACT_TYPE_WATCH:
  2804. Assert(pActionsList->propvar.vt == VT_UI4);
  2805. // Is there something to do?
  2806. if (ACT_DATA_WATCHTHREAD == pActions[ulIndex].propvar.ulVal)
  2807. {
  2808. dwFlag = ARF_WATCH;
  2809. dwFlagRemove = ARF_IGNORE;
  2810. }
  2811. else
  2812. {
  2813. Assert(ACT_DATA_IGNORETHREAD == pActions[ulIndex].propvar.ulVal);
  2814. dwFlag = ARF_IGNORE;
  2815. dwFlagRemove = ARF_WATCH;
  2816. }
  2817. // Is there something to do?
  2818. if (0 == (pMsgInfo->dwFlags & dwFlag))
  2819. {
  2820. // Init flags
  2821. WatchFlags.dwAdd |= dwFlag;
  2822. WatchFlags.dwRemove |= dwFlagRemove;
  2823. // Mark as watched/ignored
  2824. fDoWatch = TRUE;
  2825. }
  2826. break;
  2827. case ACT_TYPE_FLAG:
  2828. Assert(pActionsList->propvar.vt == VT_EMPTY);
  2829. // Is there something to do?
  2830. if (0 == (pMsgInfo->dwFlags & ARF_FLAGGED))
  2831. {
  2832. // Init flags
  2833. Flags.dwAdd |= ARF_FLAGGED;
  2834. // Flag the message
  2835. fSetFlags = TRUE;
  2836. }
  2837. break;
  2838. case ACT_TYPE_READ:
  2839. Assert(pActionsList->propvar.vt == VT_EMPTY);
  2840. // Is there something to do?
  2841. if (0 == (pMsgInfo->dwFlags & ARF_READ))
  2842. {
  2843. // Init flags
  2844. Flags.dwAdd |= ARF_READ;
  2845. Flags.dwRemove = 0;
  2846. // Mark as read
  2847. fSetFlags = TRUE;
  2848. }
  2849. break;
  2850. case ACT_TYPE_MARKDOWNLOAD:
  2851. Assert(pActionsList->propvar.vt == VT_EMPTY);
  2852. // Is there something to do?
  2853. if (0 == (pMsgInfo->dwFlags & ARF_DOWNLOAD))
  2854. {
  2855. // Init flags
  2856. Flags.dwAdd |= ARF_DOWNLOAD;
  2857. Flags.dwRemove = 0;
  2858. // Mark as downloaded
  2859. fSetFlags = TRUE;
  2860. }
  2861. break;
  2862. case ACT_TYPE_FWD:
  2863. Assert(VT_LPSTR == pActionsList->propvar.vt);
  2864. SafeRelease(pIStm);
  2865. // Check message secure or not
  2866. if(NULL != pIMMsg)
  2867. {
  2868. pIMMsg->GetFlags(&dwFlag);
  2869. // Get the message source
  2870. if (!(IMF_SECURE & dwFlag) &&
  2871. (SUCCEEDED(pIMMsg->GetMessageSource(&pIStm, 0))))
  2872. {
  2873. // Auto Forward
  2874. fLoop = FALSE;
  2875. if ((FAILED(_HrAutoForwardMessage(hwndUI, pActionsList->propvar.pszVal,
  2876. pMsgInfo->pszAcctId, pIStm, &fLoop))) && (FALSE != fLoop))
  2877. {
  2878. if (NULL != pcInfiniteLoops)
  2879. {
  2880. (*pcInfiniteLoops)++;
  2881. }
  2882. }
  2883. else
  2884. {
  2885. // Is there something to do?
  2886. if (0 == (pMsgInfo->dwFlags & ARF_FORWARDED))
  2887. {
  2888. // Init flags
  2889. Flags.dwAdd |= ARF_FORWARDED;
  2890. Flags.dwRemove = 0;
  2891. // Mark as forwarded
  2892. fSetFlags = TRUE;
  2893. }
  2894. }
  2895. }
  2896. }
  2897. break;
  2898. case ACT_TYPE_REPLY:
  2899. Assert(VT_LPSTR == pActionsList->propvar.vt);
  2900. // Auto Reply
  2901. fLoop = FALSE;
  2902. SafeRelease(pIStm);
  2903. if (SUCCEEDED(pIExecRules->GetRuleFile(pActionsList->propvar.pszVal, &pIStm, &dwType)))
  2904. {
  2905. if ((FAILED(_HrAutoReplyMessage(hwndUI, dwType, pActionsList->propvar.pszVal, pIStm,
  2906. pMsgInfo->pszAcctId, pIMMsg, &fLoop))) && (FALSE != fLoop))
  2907. {
  2908. if (NULL != pcInfiniteLoops)
  2909. {
  2910. (*pcInfiniteLoops)++;
  2911. }
  2912. }
  2913. else
  2914. {
  2915. // Is there something to do?
  2916. if (0 == (pMsgInfo->dwFlags & ARF_REPLIED))
  2917. {
  2918. // Init flags
  2919. Flags.dwAdd |= ARF_REPLIED;
  2920. Flags.dwRemove = 0;
  2921. // Mark as replied
  2922. fSetFlags = TRUE;
  2923. }
  2924. }
  2925. }
  2926. break;
  2927. }
  2928. }
  2929. // Should we set the flags?
  2930. if (FALSE != fSetFlags)
  2931. {
  2932. SetMessageFlagsProgress(hwndUI, pFolder, &Flags, &List);
  2933. }
  2934. // Should we watch the message?
  2935. if (FALSE != fDoWatch)
  2936. {
  2937. _HrMarkThreadAsWatched(pMsgInfo->idMessage, pFolder, &WatchFlags);
  2938. }
  2939. // Do all non-modification operations next
  2940. for (pActionsList = pActions, ulIndex = 0; ulIndex < cActions; ulIndex++, pActionsList++)
  2941. {
  2942. switch(pActionsList->type)
  2943. {
  2944. case ACT_TYPE_COPY:
  2945. case ACT_TYPE_MOVE:
  2946. Assert(VT_BLOB == pActionsList->propvar.vt);
  2947. if (0 == pActionsList->propvar.blob.cbSize)
  2948. {
  2949. hr = S_FALSE;
  2950. goto exit;
  2951. }
  2952. // Make life simpler
  2953. prfdData = (RULEFOLDERDATA *) (pActionsList->propvar.blob.pBlobData);
  2954. // Validate the rule folder data
  2955. if (S_OK != RuleUtil_HrValidateRuleFolderData(prfdData))
  2956. {
  2957. hr = S_FALSE;
  2958. goto exit;
  2959. }
  2960. // Is there something to do?
  2961. if (idFolder != prfdData->idFolder)
  2962. {
  2963. hr = pIExecRules->GetRuleFolder(prfdData->idFolder, (DWORD_PTR *) (&pFolderNew));
  2964. if (FAILED(hr))
  2965. {
  2966. goto exit;
  2967. }
  2968. // Move/copy the messages
  2969. CopyMessagesProgress(hwndUI, pFolder, pFolderNew,
  2970. (pActionsList->type != ACT_TYPE_COPY) ? COPY_MESSAGE_MOVE : NOFLAGS,
  2971. &List, NULL);
  2972. }
  2973. break;
  2974. case ACT_TYPE_NOTIFYMSG:
  2975. // Nothing to do for now
  2976. break;
  2977. case ACT_TYPE_NOTIFYSND:
  2978. Assert(VT_LPSTR == pActionsList->propvar.vt);
  2979. hr = pIExecRules->AddSoundFile(ASF_PLAYIFNEW, pActionsList->propvar.pszVal);
  2980. if (FAILED(hr))
  2981. {
  2982. goto exit;
  2983. }
  2984. break;
  2985. case ACT_TYPE_DELETE:
  2986. Assert(pActionsList->propvar.vt == VT_EMPTY);
  2987. DeleteMessagesProgress(hwndUI, pFolder, dwDeleteFlags | DELETE_MESSAGE_NOPROMPT, &List);
  2988. break;
  2989. case ACT_TYPE_JUNKMAIL:
  2990. Assert(pActionsList->propvar.vt == VT_EMPTY);
  2991. // Get the Junk Mail folder id, if we don't already have it
  2992. if (FOLDERID_INVALID == idFolderJunkMail)
  2993. {
  2994. FOLDERINFO Folder;
  2995. hr = g_pStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, FOLDER_JUNK, &Folder);
  2996. if (FAILED(hr))
  2997. {
  2998. goto exit;;
  2999. }
  3000. idFolderJunkMail = Folder.idFolder;
  3001. g_pStore->FreeRecord(&Folder);
  3002. }
  3003. hr = pIExecRules->GetRuleFolder(idFolderJunkMail, (DWORD_PTR *) (&pFolderNew));
  3004. if (FAILED(hr))
  3005. {
  3006. goto exit;
  3007. }
  3008. // Move the messages
  3009. CopyMessagesProgress(hwndUI, pFolder, pFolderNew, COPY_MESSAGE_MOVE, &List, NULL);
  3010. break;
  3011. case ACT_TYPE_DELETESERVER:
  3012. if (pfDeleteOffServer)
  3013. *pfDeleteOffServer = TRUE;
  3014. break;
  3015. case ACT_TYPE_DONTDOWNLOAD:
  3016. // Nothing to do for now
  3017. break;
  3018. case ACT_TYPE_STOP:
  3019. // Nothing to do for now
  3020. break;
  3021. }
  3022. }
  3023. // Set the proper return value
  3024. hr = S_OK;
  3025. exit:
  3026. SafeRelease(pIStm);
  3027. return hr;
  3028. }
  3029. HRESULT RuleUtil_HrCreateSendersRule(DWORD dwFlags, IOERule ** ppIRule)
  3030. {
  3031. HRESULT hr = S_OK;
  3032. IOERule * pIRule = NULL;
  3033. PROPVARIANT propvar = {0};
  3034. TCHAR szRes[CCHMAX_STRINGRES];
  3035. ACT_ITEM aitem;
  3036. // Check incoming params
  3037. if (NULL == ppIRule)
  3038. {
  3039. hr = E_INVALIDARG;
  3040. goto exit;
  3041. }
  3042. // Initialize the list
  3043. *ppIRule = NULL;
  3044. // Create the new rule
  3045. hr = HrCreateRule(&pIRule);
  3046. if (FAILED(hr))
  3047. {
  3048. goto exit;
  3049. }
  3050. // Get the name
  3051. if (0 != LoadString(g_hLocRes, idsBlockSender, szRes, ARRAYSIZE(szRes)))
  3052. {
  3053. propvar.vt = VT_LPSTR;
  3054. propvar.pszVal = szRes;
  3055. // Set the name
  3056. hr = pIRule->SetProp(RULE_PROP_NAME, 0, &propvar);
  3057. ZeroMemory(&propvar, sizeof(propvar));
  3058. if (FAILED(hr))
  3059. {
  3060. goto exit;
  3061. }
  3062. }
  3063. // Set the normal action
  3064. ZeroMemory(&aitem, sizeof(aitem));
  3065. aitem.type = ACT_TYPE_DELETE;
  3066. aitem.dwFlags = ACT_FLAG_DEFAULT;
  3067. PropVariantClear(&propvar);
  3068. propvar.vt = VT_BLOB;
  3069. propvar.blob.cbSize = sizeof(ACT_ITEM);
  3070. propvar.blob.pBlobData = (BYTE *) &aitem;
  3071. hr = pIRule->SetProp(RULE_PROP_ACTIONS, 0, &propvar);
  3072. ZeroMemory(&propvar, sizeof(propvar));
  3073. if (FAILED(hr))
  3074. {
  3075. goto exit;
  3076. }
  3077. // Set the outgoing param
  3078. *ppIRule = pIRule;
  3079. pIRule = NULL;
  3080. // Set the proper return value
  3081. hr = S_OK;
  3082. exit:
  3083. SafeRelease(pIRule);
  3084. return hr;
  3085. }
  3086. ///////////////////////////////////////////////////////////////////////////////
  3087. //
  3088. // _HrLoadSender
  3089. //
  3090. // This creates the sender rule
  3091. //
  3092. //
  3093. // Returns: S_OK, if it was rules were successfully created
  3094. // S_FALSE, if the rules were already created
  3095. //
  3096. ///////////////////////////////////////////////////////////////////////////////
  3097. HRESULT RuleUtil_HrLoadSender(LPCSTR pszRegPath, DWORD dwFlags, IOERule ** ppIRule)
  3098. {
  3099. HRESULT hr = S_OK;
  3100. HKEY hkeyRoot = NULL;
  3101. LONG lErr = ERROR_SUCCESS;
  3102. DWORD dwData = 0;
  3103. ULONG cbData = 0;
  3104. TCHAR szRes[CCHMAX_STRINGRES];
  3105. IOERule * pIRule = NULL;
  3106. Assert(NULL != pszRegPath);
  3107. Assert(NULL != ppIRule);
  3108. // Let's get access to the sender root key
  3109. lErr = AthUserOpenKey(pszRegPath, KEY_ALL_ACCESS, &hkeyRoot);
  3110. if ((ERROR_SUCCESS != lErr) && (ERROR_FILE_NOT_FOUND != lErr))
  3111. {
  3112. hr = E_FAIL;
  3113. goto exit;
  3114. }
  3115. // If we don't have it saved, then we're done
  3116. if (ERROR_FILE_NOT_FOUND == lErr)
  3117. {
  3118. hr = S_FALSE;
  3119. goto exit;
  3120. }
  3121. // Make sure we have a name
  3122. cbData = sizeof(dwData);
  3123. lErr = RegQueryValueEx(hkeyRoot, c_szRuleName, 0, NULL, NULL, &cbData);
  3124. if ((ERROR_SUCCESS != lErr) && (ERROR_FILE_NOT_FOUND != lErr))
  3125. {
  3126. hr = E_FAIL;
  3127. goto exit;
  3128. }
  3129. // Do we have to set the name?
  3130. if (ERROR_FILE_NOT_FOUND == lErr)
  3131. {
  3132. // Get the name
  3133. if (0 == LoadString(g_hLocRes, idsBlockSender, szRes, ARRAYSIZE(szRes)))
  3134. {
  3135. hr = E_FAIL;
  3136. goto exit;
  3137. }
  3138. // Set the name
  3139. lErr = RegSetValueEx(hkeyRoot, c_szRuleName, 0, REG_SZ, (BYTE *) szRes, lstrlen(szRes) + 1);
  3140. if (ERROR_SUCCESS != lErr)
  3141. {
  3142. hr = E_FAIL;
  3143. goto exit;
  3144. }
  3145. }
  3146. // Create the rule
  3147. hr = HrCreateRule(&pIRule);
  3148. if (FAILED(hr))
  3149. {
  3150. goto exit;
  3151. }
  3152. // Load in the rule
  3153. hr = pIRule->LoadReg(pszRegPath);
  3154. if (FAILED(hr))
  3155. {
  3156. goto exit;
  3157. }
  3158. // Set the outgoing param
  3159. *ppIRule = pIRule;
  3160. pIRule = NULL;
  3161. // Set the return value
  3162. hr = S_OK;
  3163. exit:
  3164. SafeRelease(pIRule);
  3165. if (NULL != hkeyRoot)
  3166. {
  3167. RegCloseKey(hkeyRoot);
  3168. }
  3169. return hr;
  3170. }
  3171. ///////////////////////////////////////////////////////////////////////////////
  3172. //
  3173. // RuleUtil_FMatchSender
  3174. //
  3175. // This match the sender to the message
  3176. //
  3177. //
  3178. // Returns: S_OK, if it was in the sender of the message
  3179. // S_FALSE, if it was not the sender of the message
  3180. //
  3181. ///////////////////////////////////////////////////////////////////////////////
  3182. HRESULT RuleUtil_HrMatchSender(LPCSTR pszSender, MESSAGEINFO * pMsgInfo,
  3183. IMimeMessage * pIMMsg, IMimePropertySet * pIMPropSet)
  3184. {
  3185. HRESULT hr = S_OK;
  3186. LPSTR pszAddr = NULL;
  3187. ADDRESSPROPS rSender = {0};
  3188. IMimeAddressTable * pIAddrTable = NULL;
  3189. BOOL fMatch = FALSE;
  3190. ULONG cchVal = 0;
  3191. ULONG cchEmail = 0;
  3192. CHAR chTest = 0;
  3193. // Do we have good values
  3194. if ((NULL == pszSender) || ((NULL == pMsgInfo) && (NULL == pIMMsg) && (NULL == pIMPropSet)))
  3195. {
  3196. hr = E_INVALIDARG;
  3197. goto exit;
  3198. }
  3199. // Check to make sure that there's something to match
  3200. if ('\0' == pszSender[0])
  3201. {
  3202. hr = S_FALSE;
  3203. goto exit;
  3204. }
  3205. // Get the address
  3206. if ((NULL != pMsgInfo) && (NULL != pMsgInfo->pszEmailFrom))
  3207. {
  3208. pszAddr = pMsgInfo->pszEmailFrom;
  3209. }
  3210. else if (NULL != pIMMsg)
  3211. {
  3212. rSender.dwProps = IAP_EMAIL;
  3213. if (SUCCEEDED(pIMMsg->GetSender(&rSender)))
  3214. {
  3215. pszAddr = rSender.pszEmail;
  3216. }
  3217. }
  3218. else if ((NULL != pIMPropSet) && (SUCCEEDED(pIMPropSet->BindToObject(IID_IMimeAddressTable, (LPVOID *)&pIAddrTable))))
  3219. {
  3220. rSender.dwProps = IAP_EMAIL;
  3221. if (SUCCEEDED(pIAddrTable->GetSender(&rSender)))
  3222. {
  3223. pszAddr = rSender.pszEmail;
  3224. }
  3225. pIAddrTable->Release();
  3226. }
  3227. // Did we find anything?
  3228. if (NULL == pszAddr)
  3229. {
  3230. hr = S_FALSE;
  3231. goto exit;
  3232. }
  3233. // Check to see if it is an address
  3234. if (NULL != StrStrI(pszSender, "@"))
  3235. {
  3236. fMatch = (0 == lstrcmpi(pszSender, pszAddr));
  3237. }
  3238. else
  3239. {
  3240. cchVal = lstrlen(pszSender);
  3241. cchEmail = lstrlen(pszAddr);
  3242. if (cchVal <= cchEmail)
  3243. {
  3244. fMatch = (0 == lstrcmpi(pszSender, pszAddr + (cchEmail - cchVal)));
  3245. if ((FALSE != fMatch) && (cchVal != cchEmail))
  3246. {
  3247. chTest = *(pszAddr + (cchEmail - cchVal - 1));
  3248. if (('@' != chTest) && ('.' != chTest))
  3249. {
  3250. fMatch = FALSE;
  3251. }
  3252. }
  3253. }
  3254. }
  3255. // Set the proper return value
  3256. hr = (FALSE != fMatch) ? S_OK : S_FALSE;
  3257. exit:
  3258. g_pMoleAlloc->FreeAddressProps(&rSender);
  3259. return hr;
  3260. }
  3261. HRESULT RuleUtil_HrValidateRuleFolderData(RULEFOLDERDATA * prfdData)
  3262. {
  3263. HRESULT hr = S_OK;
  3264. STOREUSERDATA UserData = {0};
  3265. // Check incoming params
  3266. if (NULL == prfdData)
  3267. {
  3268. hr = E_INVALIDARG;
  3269. goto exit;
  3270. }
  3271. // Get the timestamp for the store
  3272. hr = g_pStore->GetUserData(&UserData, sizeof(STOREUSERDATA));
  3273. if (FAILED(hr))
  3274. {
  3275. goto exit;
  3276. }
  3277. // Is the stamp correct
  3278. if ((UserData.ftCreated.dwLowDateTime != prfdData->ftStamp.dwLowDateTime) ||
  3279. (UserData.ftCreated.dwHighDateTime != prfdData->ftStamp.dwHighDateTime))
  3280. {
  3281. hr = S_FALSE;
  3282. goto exit;
  3283. }
  3284. // Set the proper return value
  3285. hr = S_OK;
  3286. exit:
  3287. return hr;
  3288. }
  3289. ///////////////////////////////////////////////////////////////////////////////
  3290. //
  3291. // _HrSetDefaultCriteria
  3292. //
  3293. // This creates a default rule in the specified location
  3294. //
  3295. //
  3296. // Returns: S_OK, if it was rules were successfully created
  3297. // S_FALSE, if the rules were already created
  3298. //
  3299. ///////////////////////////////////////////////////////////////////////////////
  3300. HRESULT _HrSetDefaultCriteria(IOERule * pIRule, const DEFAULT_RULE * pdefRule)
  3301. {
  3302. HRESULT hr = S_OK;
  3303. PROPVARIANT propvar = {0};
  3304. CRIT_ITEM rgCritItem[CDEF_CRIT_ITEM_MAX];
  3305. ULONG cCritItem = 0;
  3306. Assert(NULL != pIRule);
  3307. Assert(NULL != pdefRule);
  3308. // Initialize the criteria
  3309. ZeroMemory(rgCritItem, sizeof(*rgCritItem) * CDEF_CRIT_ITEM_MAX);
  3310. // Set the criteria
  3311. switch (pdefRule->critType)
  3312. {
  3313. case DEF_CRIT_ALLMSGS:
  3314. cCritItem = 1;
  3315. rgCritItem[0].type = CRIT_TYPE_ALL;
  3316. rgCritItem[0].dwFlags = CRIT_FLAG_DEFAULT;
  3317. rgCritItem[0].propvar.vt = VT_EMPTY;
  3318. rgCritItem[0].logic = CRIT_LOGIC_NULL;
  3319. break;
  3320. case DEF_CRIT_READ:
  3321. cCritItem = 1;
  3322. rgCritItem[0].type = CRIT_TYPE_READ;
  3323. rgCritItem[0].dwFlags = CRIT_FLAG_DEFAULT;
  3324. rgCritItem[0].propvar.vt = VT_EMPTY;
  3325. rgCritItem[0].logic = CRIT_LOGIC_NULL;
  3326. break;
  3327. case DEF_CRIT_DWNLDMSGS:
  3328. cCritItem = 1;
  3329. rgCritItem[0].type = CRIT_TYPE_DOWNLOADED;
  3330. rgCritItem[0].dwFlags = CRIT_FLAG_DEFAULT;
  3331. rgCritItem[0].propvar.vt = VT_EMPTY;
  3332. rgCritItem[0].logic = CRIT_LOGIC_NULL;
  3333. break;
  3334. case DEF_CRIT_IGNTHDS:
  3335. cCritItem = 2;
  3336. rgCritItem[0].type = CRIT_TYPE_THREADSTATE;
  3337. rgCritItem[0].dwFlags = CRIT_FLAG_DEFAULT;
  3338. rgCritItem[0].propvar.vt = VT_UI4;
  3339. rgCritItem[0].propvar.ulVal = CRIT_DATA_IGNORETHREAD;
  3340. rgCritItem[0].logic = CRIT_LOGIC_OR;
  3341. rgCritItem[1].type = CRIT_TYPE_READ;
  3342. rgCritItem[1].dwFlags = CRIT_FLAG_DEFAULT;
  3343. rgCritItem[1].propvar.vt = VT_EMPTY;
  3344. rgCritItem[1].logic = CRIT_LOGIC_NULL;
  3345. break;
  3346. default:
  3347. hr = E_INVALIDARG;
  3348. goto exit;
  3349. }
  3350. // Set the rule criteria
  3351. propvar.vt = VT_BLOB;
  3352. propvar.blob.cbSize = cCritItem * sizeof(CRIT_ITEM);
  3353. propvar.blob.pBlobData = (BYTE *) rgCritItem;
  3354. hr = pIRule->SetProp(RULE_PROP_CRITERIA, 0, &propvar);
  3355. ZeroMemory(&propvar, sizeof(propvar));
  3356. if (FAILED(hr))
  3357. {
  3358. goto exit;
  3359. }
  3360. // Set the proper return value
  3361. hr = S_OK;
  3362. exit:
  3363. return hr;
  3364. }
  3365. ///////////////////////////////////////////////////////////////////////////////
  3366. //
  3367. // _HrSetDefaultActions
  3368. //
  3369. // This creates a default rule in the specified location
  3370. //
  3371. //
  3372. // Returns: S_OK, if it was rules were successfully created
  3373. // S_FALSE, if the rules were already created
  3374. //
  3375. ///////////////////////////////////////////////////////////////////////////////
  3376. HRESULT _HrSetDefaultActions(IOERule * pIRule, const DEFAULT_RULE * pdefRule)
  3377. {
  3378. HRESULT hr = S_OK;
  3379. PROPVARIANT propvar = {0};
  3380. ACT_ITEM rgActItem[CDEF_ACT_ITEM_MAX];
  3381. ULONG cActItem = 0;
  3382. Assert(NULL != pIRule);
  3383. Assert(NULL != pdefRule);
  3384. // Initialize the actions
  3385. ZeroMemory(rgActItem, sizeof(*rgActItem) * CDEF_ACT_ITEM_MAX);
  3386. // Set the actions
  3387. switch (pdefRule->actType)
  3388. {
  3389. case DEF_ACT_SHOWMSGS:
  3390. cActItem = 1;
  3391. rgActItem[0].type = ACT_TYPE_SHOW;
  3392. rgActItem[0].dwFlags = ACT_FLAG_DEFAULT;
  3393. rgActItem[0].propvar.vt = VT_UI4;
  3394. rgActItem[0].propvar.ulVal = ACT_DATA_SHOW;
  3395. break;
  3396. case DEF_ACT_HIDEMSGS:
  3397. cActItem = 1;
  3398. rgActItem[0].type = ACT_TYPE_SHOW;
  3399. rgActItem[0].dwFlags = ACT_FLAG_DEFAULT;
  3400. rgActItem[0].propvar.vt = VT_UI4;
  3401. rgActItem[0].propvar.ulVal = ACT_DATA_HIDE;
  3402. break;
  3403. default:
  3404. hr = E_INVALIDARG;
  3405. goto exit;
  3406. }
  3407. // Set the rule actions
  3408. propvar.vt = VT_BLOB;
  3409. propvar.blob.cbSize = cActItem * sizeof(ACT_ITEM);
  3410. propvar.blob.pBlobData = (BYTE *) rgActItem;
  3411. hr = pIRule->SetProp(RULE_PROP_ACTIONS, 0, &propvar);
  3412. ZeroMemory(&propvar, sizeof(propvar));
  3413. if (FAILED(hr))
  3414. {
  3415. goto exit;
  3416. }
  3417. // Set the proper return value
  3418. hr = S_OK;
  3419. exit:
  3420. return hr;
  3421. }
  3422. ///////////////////////////////////////////////////////////////////////////////
  3423. //
  3424. // _HrUpdateDefaultRule
  3425. //
  3426. // This creates a default rule in the specified location
  3427. //
  3428. //
  3429. // Returns: S_OK, if it was rules were successfully created
  3430. // S_FALSE, if the rules were already created
  3431. //
  3432. ///////////////////////////////////////////////////////////////////////////////
  3433. HRESULT _HrUpdateDefaultRule(LPCSTR pszRegPath, const DEFAULT_RULE * pdefRule)
  3434. {
  3435. HRESULT hr = S_OK;
  3436. IOERule * pIRule = NULL;
  3437. TCHAR szFullPath[CCHMAX_STRINGRES];
  3438. TCHAR szName[CCHMAX_STRINGRES];
  3439. PROPVARIANT propvar = {0};
  3440. Assert(NULL != pszRegPath);
  3441. Assert(NULL != pdefRule);
  3442. // Whip up a rule
  3443. hr = HrCreateRule(&pIRule);
  3444. if (FAILED(hr))
  3445. {
  3446. goto exit;
  3447. }
  3448. // Build up the rule path
  3449. if(lstrlen(pszRegPath) >= sizeof(szFullPath) / sizeof(szFullPath[0]))
  3450. {
  3451. hr = E_FAIL;
  3452. goto exit;
  3453. }
  3454. StrCpyN(szFullPath, pszRegPath, ARRAYSIZE(szFullPath));
  3455. StrCatBuff(szFullPath, g_szBackSlash, ARRAYSIZE(szFullPath));
  3456. wnsprintf(szFullPath + lstrlen(szFullPath), (ARRAYSIZE(szFullPath) - lstrlen(szFullPath)), "%03X", pdefRule->ridRule);
  3457. // Do we need to do anything?
  3458. hr = pIRule->LoadReg(szFullPath);
  3459. if (SUCCEEDED(hr))
  3460. {
  3461. // Get the version from the rule
  3462. hr = pIRule->GetProp(RULE_PROP_VERSION, 0, &propvar);
  3463. if (SUCCEEDED(hr))
  3464. {
  3465. Assert(VT_UI4 == propvar.vt);
  3466. // Is the rule too old?
  3467. if (pdefRule->dwVersion <= propvar.ulVal)
  3468. {
  3469. //Bug# 67782
  3470. //We reload the name of the string every time in case, a localized version of OE is installed.
  3471. if (SUCCEEDED(hr = RuleUtil_SetName(pIRule, pdefRule->idName)))
  3472. {
  3473. if (SUCCEEDED(pIRule->SaveReg(szFullPath, TRUE)))
  3474. hr = S_FALSE;
  3475. }
  3476. goto exit;
  3477. }
  3478. }
  3479. }
  3480. //Bug# 67782
  3481. //We reload the name of the string every time in case, a localized version of OE is installed.
  3482. hr = RuleUtil_SetName(pIRule, pdefRule->idName);
  3483. if (FAILED(hr))
  3484. {
  3485. goto exit;
  3486. }
  3487. // Set the rule version
  3488. propvar.vt = VT_UI4;
  3489. propvar.ulVal = pdefRule->dwVersion - 1;
  3490. hr = pIRule->SetProp(RULE_PROP_VERSION, 0, &propvar);
  3491. ZeroMemory(&propvar, sizeof(propvar));
  3492. if (FAILED(hr))
  3493. {
  3494. goto exit;
  3495. }
  3496. // Set the rule criteria
  3497. hr = _HrSetDefaultCriteria(pIRule, pdefRule);
  3498. if (FAILED(hr))
  3499. {
  3500. goto exit;
  3501. }
  3502. // Set the rule actions
  3503. hr = _HrSetDefaultActions(pIRule, pdefRule);
  3504. if (FAILED(hr))
  3505. {
  3506. goto exit;
  3507. }
  3508. // Save the rule
  3509. hr = pIRule->SaveReg(szFullPath, TRUE);
  3510. if (FAILED(hr))
  3511. {
  3512. goto exit;
  3513. }
  3514. // Set the proper return value
  3515. hr = S_OK;
  3516. exit:
  3517. SafeRelease(pIRule);
  3518. return hr;
  3519. }
  3520. HRESULT RuleUtil_SetName(IOERule *pIRule, int idRes)
  3521. {
  3522. HRESULT hr = S_OK;
  3523. TCHAR szName[CCHMAX_STRINGRES];
  3524. PROPVARIANT propvar = {0};
  3525. if (0 == AthLoadString(idRes, szName, ARRAYSIZE(szName)))
  3526. {
  3527. hr = E_FAIL;
  3528. goto exit;
  3529. }
  3530. // Set the rule name
  3531. ZeroMemory(&propvar, sizeof(propvar));
  3532. propvar.vt = VT_LPSTR;
  3533. propvar.pszVal = szName;
  3534. hr = pIRule->SetProp(RULE_PROP_NAME, 0, &propvar);
  3535. exit:
  3536. return hr;
  3537. }
  3538. ///////////////////////////////////////////////////////////////////////////////
  3539. //
  3540. // RuleUtil_HrUpdateDefaultRules
  3541. //
  3542. // This updates the default rules for the specified rule type
  3543. // when the version in the registry is older than the current
  3544. // version
  3545. //
  3546. // Returns: S_OK, if it was rules were successfully updated
  3547. // S_FALSE, if the rules were already at the correct version
  3548. //
  3549. ///////////////////////////////////////////////////////////////////////////////
  3550. HRESULT RuleUtil_HrUpdateDefaultRules(RULE_TYPE typeRule)
  3551. {
  3552. HRESULT hr = S_OK;
  3553. LPCSTR pszSubKey = NULL;
  3554. LONG lErr = ERROR_SUCCESS;
  3555. HKEY hkeyRoot = NULL;
  3556. DWORD dwData = 0;
  3557. ULONG cbData = 0;
  3558. const DEFAULT_RULE * pdefrule = NULL;
  3559. ULONG cpdefrule = 0;
  3560. LPCSTR pszOrderDef = NULL;
  3561. ULONG ulIndex = 0;
  3562. // If we're already loaded then
  3563. // there's nothing to do
  3564. switch(typeRule)
  3565. {
  3566. case RULE_TYPE_FILTER:
  3567. pszSubKey = c_szRulesFilter;
  3568. pdefrule = g_defruleFilters;
  3569. cpdefrule = ARRAYSIZE(g_defruleFilters);
  3570. pszOrderDef = g_szOrderFilterDef;
  3571. break;
  3572. default:
  3573. // Nothing to do..
  3574. hr = S_FALSE;
  3575. goto exit;
  3576. }
  3577. // Check to see if the Rule node already exists
  3578. lErr = AthUserOpenKey(pszSubKey, KEY_ALL_ACCESS, &hkeyRoot);
  3579. if (ERROR_SUCCESS != lErr)
  3580. {
  3581. hr = HRESULT_FROM_WIN32(lErr);
  3582. goto exit;
  3583. }
  3584. // Check the current version
  3585. cbData = sizeof(dwData);
  3586. lErr = RegQueryValueEx(hkeyRoot, c_szRulesVersion, NULL, NULL, (BYTE *) &dwData, &cbData);
  3587. if (ERROR_SUCCESS != lErr)
  3588. {
  3589. hr = HRESULT_FROM_WIN32(lErr);
  3590. goto exit;
  3591. }
  3592. Assert(RULESMGR_VERSION == dwData);
  3593. // Update out the default rules
  3594. for (ulIndex = 0; ulIndex < cpdefrule; ulIndex++, pdefrule++)
  3595. {
  3596. hr = _HrUpdateDefaultRule(pszSubKey, pdefrule);
  3597. if (FAILED(hr))
  3598. {
  3599. goto exit;
  3600. }
  3601. }
  3602. // Write out the default order
  3603. if (NULL != pszOrderDef)
  3604. {
  3605. // If the order already exists, then leave it alone
  3606. lErr = RegQueryValueEx(hkeyRoot, c_szRulesOrder, NULL, NULL, NULL, &cbData);
  3607. if (ERROR_SUCCESS != lErr)
  3608. {
  3609. lErr = RegSetValueEx(hkeyRoot, c_szRulesOrder, 0,
  3610. REG_SZ, (CONST BYTE *) pszOrderDef, lstrlen(pszOrderDef) + 1);
  3611. if (ERROR_SUCCESS != lErr)
  3612. {
  3613. hr = HRESULT_FROM_WIN32(lErr);
  3614. goto exit;
  3615. }
  3616. }
  3617. }
  3618. // Set the proper return value
  3619. hr = S_OK;
  3620. exit:
  3621. if (NULL != hkeyRoot)
  3622. {
  3623. RegCloseKey(hkeyRoot);
  3624. }
  3625. return hr;
  3626. }
  3627. //--------------------------------------------------------------------------
  3628. // RuleUtil_HrGetFilterVersion
  3629. //--------------------------------------------------------------------------
  3630. HRESULT RuleUtil_HrGetFilterVersion(RULEID ridFilter, DWORD * pdwVersion)
  3631. {
  3632. HRESULT hr = S_OK;
  3633. IOERule * pIRule = NULL;
  3634. PROPVARIANT propvar = {0};
  3635. TraceCall("_GetFilterVersion");
  3636. Assert(NULL != pdwVersion);
  3637. // Is there something to do
  3638. if (RULEID_INVALID == ridFilter)
  3639. {
  3640. hr = E_FAIL;
  3641. goto exit;
  3642. }
  3643. // Initialize the outgoing param
  3644. *pdwVersion = 0;
  3645. // Get the rule from the rules manager
  3646. Assert(NULL != g_pRulesMan);
  3647. hr = g_pRulesMan->GetRule(ridFilter, RULE_TYPE_FILTER, 0, &pIRule);
  3648. if (FAILED(hr))
  3649. {
  3650. goto exit;
  3651. }
  3652. // Get the version from the rule
  3653. hr = pIRule->GetProp(RULE_PROP_VERSION, 0, &propvar);
  3654. if (FAILED(hr))
  3655. {
  3656. goto exit;
  3657. }
  3658. // Set the outgoing param
  3659. Assert(VT_UI4 == propvar.vt);
  3660. *pdwVersion = propvar.ulVal;
  3661. // Set the proper return value
  3662. hr = S_OK;
  3663. exit:
  3664. PropVariantClear(&propvar);
  3665. SafeRelease(pIRule);
  3666. return hr;
  3667. }
  3668. //--------------------------------------------------------------------------
  3669. // _HrWriteClause
  3670. //--------------------------------------------------------------------------
  3671. HRESULT _HrWriteClause(IStream * pStm, ULONG cClauses, BOOL fAnd, LPCSTR pszClause)
  3672. {
  3673. HRESULT hr = S_OK;
  3674. LPCSTR pszLogic = NULL;
  3675. // Do we have something to write
  3676. if (NULL != pszClause)
  3677. {
  3678. // Add the proper logical operation
  3679. if (cClauses > 0)
  3680. {
  3681. if (FALSE != fAnd)
  3682. {
  3683. pszLogic = c_szLogicalAnd;
  3684. }
  3685. else
  3686. {
  3687. pszLogic = c_szLogicalOr;
  3688. }
  3689. // Write Logical And
  3690. IF_FAILEXIT(hr = pStm->Write(pszLogic, lstrlen(pszLogic), NULL));
  3691. }
  3692. // Write out the clause
  3693. IF_FAILEXIT(hr = pStm->Write(pszClause, lstrlen(pszClause), NULL));
  3694. hr = S_OK;
  3695. }
  3696. else
  3697. {
  3698. hr = S_FALSE;
  3699. }
  3700. exit:
  3701. return hr;
  3702. }
  3703. //--------------------------------------------------------------------------
  3704. // _HrWriteFromClause
  3705. //--------------------------------------------------------------------------
  3706. HRESULT _HrWriteFromClause(IStream * pStream, ULONG cClauses, BOOL fAnd, DWORD dwFlags, LPCSTR pszText, ULONG * pcClausesNew)
  3707. {
  3708. HRESULT hr = S_OK;
  3709. ULONG cClausesOld = 0;
  3710. LPCSTR pszLogic = NULL;
  3711. LPCTSTR pszContains = NULL;
  3712. Assert(pStream && pszText && pcClausesNew);
  3713. // Add the proper logical operation
  3714. if (cClauses > 0)
  3715. {
  3716. if (FALSE != fAnd)
  3717. {
  3718. pszLogic = c_szLogicalAnd;
  3719. }
  3720. else
  3721. {
  3722. pszLogic = c_szLogicalOr;
  3723. }
  3724. // Write Logical And
  3725. IF_FAILEXIT(hr = pStream->Write(pszLogic, lstrlen(pszLogic), NULL));
  3726. }
  3727. // Figure out the logical operation
  3728. if (0 != (dwFlags & CRIT_FLAG_MULTIPLEAND))
  3729. {
  3730. pszLogic = c_szLogicalAnd;
  3731. }
  3732. else
  3733. {
  3734. pszLogic = c_szLogicalOr;
  3735. }
  3736. // Write the proper comparison op
  3737. if (0 == (dwFlags & CRIT_FLAG_INVERT))
  3738. {
  3739. pszContains = c_szFilterShow;
  3740. }
  3741. else
  3742. {
  3743. pszContains = c_szFilterHide;
  3744. }
  3745. // Write the left parenthesis
  3746. IF_FAILEXIT(hr = pStream->Write(c_szLeftParen, lstrlen(c_szLeftParen), NULL));
  3747. // Write Logical And
  3748. IF_FAILEXIT(hr = pStream->Write(pszContains, lstrlen(pszContains), NULL));
  3749. // Write the left parenthesis
  3750. IF_FAILEXIT(hr = pStream->Write(c_szLeftParen, lstrlen(c_szLeftParen), NULL));
  3751. // Add each of the addresses to the stream
  3752. cClausesOld = cClauses;
  3753. for (; '\0' != pszText[0]; pszText += lstrlen(pszText) + 1)
  3754. {
  3755. if ((cClauses - cClausesOld) > 0)
  3756. {
  3757. // Write Logical And
  3758. IF_FAILEXIT(hr = pStream->Write(pszLogic, lstrlen(pszLogic), NULL));
  3759. }
  3760. // Open the criteria
  3761. IF_FAILEXIT(hr = pStream->Write(c_szLeftParen, lstrlen(c_szLeftParen), NULL));
  3762. // Write (MSGCOL_EMAILFROM containsi
  3763. IF_FAILEXIT(hr = pStream->Write(c_szEmailFromAddrPrefix, lstrlen(c_szEmailFromAddrPrefix), NULL));
  3764. // Write a Quote
  3765. IF_FAILEXIT(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
  3766. // Write a Email Address
  3767. IF_FAILEXIT(hr = pStream->Write(pszText, lstrlen(pszText), NULL));
  3768. // Write a Quote
  3769. IF_FAILEXIT(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
  3770. // Close the MSGCOL_EMAILFROM
  3771. IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
  3772. // Write Logical Or
  3773. IF_FAILEXIT(hr = pStream->Write(c_szLogicalOr, lstrlen(c_szLogicalOr), NULL));
  3774. // Write (MSGCOL_DISPLAYFROM containsi
  3775. IF_FAILEXIT(hr = pStream->Write(c_szEmailFromPrefix, lstrlen(c_szEmailFromPrefix), NULL));
  3776. // Write a Quote
  3777. IF_FAILEXIT(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
  3778. // Write a Email Address
  3779. IF_FAILEXIT(hr = pStream->Write(pszText, lstrlen(pszText), NULL));
  3780. // Write a Quote
  3781. IF_FAILEXIT(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
  3782. // Close the MSGCOL_DISPLAYFROM
  3783. IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
  3784. // Close the criteria
  3785. IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
  3786. cClauses++;
  3787. }
  3788. // Write the right parenthesis
  3789. IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
  3790. // Write the right parenthesis
  3791. IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
  3792. // Set the outgoing param
  3793. *pcClausesNew = cClauses - cClausesOld;
  3794. // Set the return value
  3795. hr = S_OK;
  3796. exit:
  3797. return hr;
  3798. }
  3799. //--------------------------------------------------------------------------
  3800. // _HrWriteTextClause
  3801. //--------------------------------------------------------------------------
  3802. HRESULT _HrWriteTextClause(IStream * pStream, ULONG cClauses, BOOL fAnd, DWORD dwFlags, LPCSTR pszHeader, LPCSTR pszText, ULONG * pcClausesNew)
  3803. {
  3804. HRESULT hr = S_OK;
  3805. ULONG cClausesOld = 0;
  3806. LPCSTR pszLogic = NULL;
  3807. LPCTSTR pszContains = NULL;
  3808. Assert(pStream && pszText && pcClausesNew);
  3809. // Add the proper logical operation
  3810. if (cClauses > 0)
  3811. {
  3812. if (FALSE != fAnd)
  3813. {
  3814. pszLogic = c_szLogicalAnd;
  3815. }
  3816. else
  3817. {
  3818. pszLogic = c_szLogicalOr;
  3819. }
  3820. // Write Logical And
  3821. IF_FAILEXIT(hr = pStream->Write(pszLogic, lstrlen(pszLogic), NULL));
  3822. }
  3823. // Figure out the logical operation
  3824. if (0 != (dwFlags & CRIT_FLAG_MULTIPLEAND))
  3825. {
  3826. pszLogic = c_szLogicalAnd;
  3827. }
  3828. else
  3829. {
  3830. pszLogic = c_szLogicalOr;
  3831. }
  3832. // Write the proper comparison op
  3833. if (0 == (dwFlags & CRIT_FLAG_INVERT))
  3834. {
  3835. pszContains = c_szFilterShow;
  3836. }
  3837. else
  3838. {
  3839. pszContains = c_szFilterHide;
  3840. }
  3841. // Write the left parenthesis
  3842. IF_FAILEXIT(hr = pStream->Write(c_szLeftParen, lstrlen(c_szLeftParen), NULL));
  3843. // Write Logical And
  3844. IF_FAILEXIT(hr = pStream->Write(pszContains, lstrlen(pszContains), NULL));
  3845. // Write the left parenthesis
  3846. IF_FAILEXIT(hr = pStream->Write(c_szLeftParen, lstrlen(c_szLeftParen), NULL));
  3847. // Add each of the words to the stream
  3848. cClausesOld = cClauses;
  3849. for (; '\0' != pszText[0]; pszText += lstrlen(pszText) + 1)
  3850. {
  3851. if ((cClauses - cClausesOld) > 0)
  3852. {
  3853. // Write Logical And
  3854. IF_FAILEXIT(hr = pStream->Write(pszLogic, lstrlen(pszLogic), NULL));
  3855. }
  3856. // Write (MSGCOL_EMAILFROM containsi
  3857. IF_FAILEXIT(hr = pStream->Write(pszHeader, lstrlen(pszHeader), NULL));
  3858. // Write a Quote
  3859. IF_FAILEXIT(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
  3860. // Write a Email Address
  3861. IF_FAILEXIT(hr = pStream->Write(pszText, lstrlen(pszText), NULL));
  3862. // Write a Quote
  3863. IF_FAILEXIT(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
  3864. // Write Left Paren
  3865. IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
  3866. cClauses++;
  3867. }
  3868. // Write the right parenthesis
  3869. IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
  3870. // Write the right parenthesis
  3871. IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
  3872. // Set the outgoing param
  3873. *pcClausesNew = cClauses - cClausesOld;
  3874. // Set the return value
  3875. hr = S_OK;
  3876. exit:
  3877. return hr;
  3878. }
  3879. //--------------------------------------------------------------------------
  3880. // _HrWriteAccountClause
  3881. //--------------------------------------------------------------------------
  3882. HRESULT _HrWriteAccountClause(IStream * pStream, ULONG cClauses, BOOL fAnd, LPCSTR pszAcctId, ULONG * pcClausesNew)
  3883. {
  3884. HRESULT hr = S_OK;
  3885. Assert(pStream && pszAcctId && pcClausesNew);
  3886. // Write the header
  3887. hr = _HrWriteClause(pStream, cClauses, fAnd, c_szEmailAcctPrefix);
  3888. if (FAILED(hr))
  3889. {
  3890. goto exit;
  3891. }
  3892. // Write a Quote
  3893. hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL);
  3894. if (FAILED(hr))
  3895. {
  3896. goto exit;
  3897. }
  3898. // Write the account ID
  3899. hr = pStream->Write(pszAcctId, lstrlen(pszAcctId), NULL);
  3900. if (FAILED(hr))
  3901. {
  3902. goto exit;
  3903. }
  3904. // Write a Quote
  3905. hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL);
  3906. if (FAILED(hr))
  3907. {
  3908. goto exit;
  3909. }
  3910. // Close the criteria query
  3911. hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL);
  3912. if (FAILED(hr))
  3913. {
  3914. goto exit;
  3915. }
  3916. // Set the outgoing param
  3917. *pcClausesNew = 1;
  3918. // Set the return value
  3919. hr = S_OK;
  3920. exit:
  3921. return hr;
  3922. }
  3923. //--------------------------------------------------------------------------
  3924. // _HrWriteUlongClause
  3925. //--------------------------------------------------------------------------
  3926. HRESULT _HrWriteUlongClause(IStream * pStream, ULONG cClauses, BOOL fAnd, LPCSTR pszHeader, ULONG ulVal, ULONG * pcClausesNew)
  3927. {
  3928. HRESULT hr = S_OK;
  3929. CHAR rgchBuff[10];
  3930. Assert(pStream && pszHeader && pcClausesNew);
  3931. // Write the header
  3932. hr = _HrWriteClause(pStream, cClauses, fAnd, pszHeader);
  3933. if (FAILED(hr))
  3934. {
  3935. goto exit;
  3936. }
  3937. // Convert the number to a string
  3938. rgchBuff[0] = '\0';
  3939. wnsprintf(rgchBuff, ARRAYSIZE(rgchBuff), "%d", ulVal);
  3940. // Write the account ID
  3941. hr = pStream->Write(rgchBuff, lstrlen(rgchBuff), NULL);
  3942. if (FAILED(hr))
  3943. {
  3944. goto exit;
  3945. }
  3946. // Close the criteria query
  3947. hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL);
  3948. if (FAILED(hr))
  3949. {
  3950. goto exit;
  3951. }
  3952. // Set the outgoing param
  3953. *pcClausesNew = 1;
  3954. // Set the return value
  3955. hr = S_OK;
  3956. exit:
  3957. return hr;
  3958. }
  3959. //--------------------------------------------------------------------------
  3960. // _HrWriteClauseFromCriteria
  3961. //--------------------------------------------------------------------------
  3962. HRESULT _HrWriteClauseFromCriteria(CRIT_ITEM *pCritItem, ULONG cClauses, BOOL fAnd, BOOL fShow, IStream *pStm, ULONG * pcClausesNew)
  3963. {
  3964. // Locals
  3965. HRESULT hr = S_OK;
  3966. LPCSTR pszClause = NULL;
  3967. ULONG cClausesNew = 0;
  3968. // Trace
  3969. TraceCall("WriteClauseFromCriteria");
  3970. // Invalid Args
  3971. Assert(pCritItem && pStm && pcClausesNew);
  3972. // Do we have something to do?
  3973. switch(pCritItem->type)
  3974. {
  3975. case CRIT_TYPE_SUBJECT:
  3976. Assert(VT_BLOB == pCritItem->propvar.vt);
  3977. hr = _HrWriteTextClause(pStm, cClauses, fAnd, pCritItem->dwFlags,
  3978. c_szEmailSubjectPrefix, (LPTSTR) (pCritItem->propvar.blob.pBlobData), &cClausesNew);
  3979. if (FAILED(hr))
  3980. {
  3981. goto exit;
  3982. }
  3983. break;
  3984. case CRIT_TYPE_ACCOUNT:
  3985. Assert(VT_LPSTR == pCritItem->propvar.vt);
  3986. hr = _HrWriteAccountClause(pStm, cClauses, fAnd, pCritItem->propvar.pszVal, &cClausesNew);
  3987. if (FAILED(hr))
  3988. {
  3989. goto exit;
  3990. }
  3991. break;
  3992. case CRIT_TYPE_FROM:
  3993. Assert(VT_BLOB == pCritItem->propvar.vt);
  3994. hr = _HrWriteFromClause(pStm, cClauses, fAnd, pCritItem->dwFlags,
  3995. (LPTSTR) (pCritItem->propvar.blob.pBlobData), &cClausesNew);
  3996. if (FAILED(hr))
  3997. {
  3998. goto exit;
  3999. }
  4000. break;
  4001. case CRIT_TYPE_PRIORITY:
  4002. Assert(VT_UI4 == pCritItem->propvar.vt);
  4003. switch (pCritItem->propvar.ulVal)
  4004. {
  4005. case CRIT_DATA_HIPRI:
  4006. pszClause = c_szFilterPriorityHi;
  4007. break;
  4008. case CRIT_DATA_LOPRI:
  4009. pszClause = c_szFilterPriorityLo;
  4010. break;
  4011. }
  4012. IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
  4013. cClausesNew = 1;
  4014. break;
  4015. case CRIT_TYPE_ATTACH:
  4016. Assert(VT_EMPTY == pCritItem->propvar.vt);
  4017. IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, c_szFilterAttach));
  4018. cClausesNew = 1;
  4019. break;
  4020. case CRIT_TYPE_READ:
  4021. Assert(VT_EMPTY == pCritItem->propvar.vt);
  4022. if (0 != (pCritItem->dwFlags & CRIT_FLAG_INVERT))
  4023. {
  4024. pszClause = c_szFilterNotRead;
  4025. }
  4026. else
  4027. {
  4028. pszClause = c_szFilterRead;
  4029. }
  4030. IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
  4031. cClausesNew = 1;
  4032. break;
  4033. case CRIT_TYPE_DOWNLOADED:
  4034. Assert(VT_EMPTY == pCritItem->propvar.vt);
  4035. if (0 != (pCritItem->dwFlags & CRIT_FLAG_INVERT))
  4036. {
  4037. pszClause = c_szFilterNotDownloaded;
  4038. }
  4039. else
  4040. {
  4041. pszClause = c_szFilterDownloaded;
  4042. }
  4043. IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
  4044. cClausesNew = 1;
  4045. break;
  4046. case CRIT_TYPE_DELETED:
  4047. Assert(VT_EMPTY == pCritItem->propvar.vt);
  4048. if (0 != (pCritItem->dwFlags & CRIT_FLAG_INVERT))
  4049. {
  4050. pszClause = c_szFilterNotDeleted;
  4051. }
  4052. else
  4053. {
  4054. pszClause = c_szFilterDeleted;
  4055. }
  4056. IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
  4057. cClausesNew = 1;
  4058. break;
  4059. case CRIT_TYPE_FLAGGED:
  4060. Assert(VT_EMPTY == pCritItem->propvar.vt);
  4061. if (0 != (pCritItem->dwFlags & CRIT_FLAG_INVERT))
  4062. {
  4063. pszClause = c_szFilterNotFlagged;
  4064. }
  4065. else
  4066. {
  4067. pszClause = c_szFilterFlagged;
  4068. }
  4069. IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
  4070. cClausesNew = 1;
  4071. break;
  4072. case CRIT_TYPE_THREADSTATE:
  4073. Assert(VT_UI4 == pCritItem->propvar.vt);
  4074. switch (pCritItem->propvar.ulVal)
  4075. {
  4076. case CRIT_DATA_IGNORETHREAD:
  4077. pszClause = c_szFilterIgnored;
  4078. break;
  4079. case CRIT_DATA_WATCHTHREAD:
  4080. pszClause = c_szFilterWatched;
  4081. break;
  4082. }
  4083. IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
  4084. cClausesNew = 1;
  4085. break;
  4086. case CRIT_TYPE_LINES:
  4087. Assert(VT_UI4 == pCritItem->propvar.vt);
  4088. hr = _HrWriteUlongClause(pStm, cClauses, fAnd, c_szEmailLinesPrefix, pCritItem->propvar.ulVal, &cClausesNew);
  4089. if (FAILED(hr))
  4090. {
  4091. goto exit;
  4092. }
  4093. break;
  4094. case CRIT_TYPE_AGE:
  4095. Assert(VT_UI4 == pCritItem->propvar.vt);
  4096. hr = _HrWriteUlongClause(pStm, cClauses, fAnd, c_szEmailAgePrefix, pCritItem->propvar.ulVal, &cClausesNew);
  4097. if (FAILED(hr))
  4098. {
  4099. goto exit;
  4100. }
  4101. break;
  4102. case CRIT_TYPE_SECURE:
  4103. Assert(VT_UI4 == pCritItem->propvar.vt);
  4104. switch (pCritItem->propvar.ulVal)
  4105. {
  4106. case CRIT_DATA_ENCRYPTSECURE:
  4107. pszClause = c_szFilterEncrypt;
  4108. break;
  4109. case CRIT_DATA_SIGNEDSECURE:
  4110. pszClause = c_szFilterSigned;
  4111. break;
  4112. }
  4113. IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
  4114. cClausesNew = 1;
  4115. break;
  4116. case CRIT_TYPE_REPLIES:
  4117. Assert(VT_EMPTY == pCritItem->propvar.vt);
  4118. if (0 != (pCritItem->dwFlags & CRIT_FLAG_INVERT))
  4119. {
  4120. pszClause = c_szFilterNotReplyPost;
  4121. }
  4122. else
  4123. {
  4124. pszClause = c_szFilterReplyPost;
  4125. }
  4126. IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
  4127. cClausesNew = 1;
  4128. break;
  4129. case CRIT_TYPE_ALL:
  4130. Assert(VT_EMPTY == pCritItem->propvar.vt);
  4131. if (FALSE == fShow)
  4132. {
  4133. IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, c_szFilterShowAll));
  4134. cClausesNew = 1;
  4135. }
  4136. break;
  4137. }
  4138. // Set the outgoing param
  4139. *pcClausesNew = cClausesNew;
  4140. exit:
  4141. // Done
  4142. return(hr);
  4143. }
  4144. //--------------------------------------------------------------------------
  4145. // _HrBuildQueryFromFilter
  4146. //--------------------------------------------------------------------------
  4147. HRESULT _HrBuildQueryFromFilter(CRIT_ITEM * pCritList, ULONG cCritList, BOOL fShow,
  4148. LPSTR * ppszQuery, ULONG * pcchQuery,
  4149. ULONG * pcClauses)
  4150. {
  4151. HRESULT hr = S_OK;
  4152. BOOL fAnd = FALSE;
  4153. CByteStream stmQuery;
  4154. DWORD cClauses = 0;
  4155. ULONG ulIndex = 0;
  4156. LPSTR pszQuery = NULL;
  4157. ULONG cchQuery = 0;
  4158. BOOL fUnread = FALSE;
  4159. ULONG cClausesNew = 0;
  4160. Assert((NULL != ppszQuery) && (NULL != pcchQuery) && (NULL != pcClauses));
  4161. // Initialize all outgoing params
  4162. *ppszQuery = NULL;
  4163. *pcchQuery = 0;
  4164. *pcClauses = 0;
  4165. // Figure out the logic op
  4166. if (1 < cCritList)
  4167. {
  4168. fAnd = (CRIT_LOGIC_AND == pCritList->logic);
  4169. }
  4170. // Start the query string
  4171. hr = stmQuery.Write(c_szLeftParen, lstrlen(c_szLeftParen), NULL);
  4172. if (FAILED(hr))
  4173. {
  4174. goto exit;
  4175. }
  4176. // Write out the proper action
  4177. if (FALSE == fShow)
  4178. {
  4179. // End the query string
  4180. IF_FAILEXIT(hr = stmQuery.Write(c_szFilterHide, lstrlen(c_szFilterHide), NULL));
  4181. }
  4182. else
  4183. {
  4184. // End the query string
  4185. IF_FAILEXIT(hr = stmQuery.Write(c_szFilterShow, lstrlen(c_szFilterShow), NULL));
  4186. }
  4187. // Start the criteria string
  4188. hr = stmQuery.Write(c_szLeftParen, lstrlen(c_szLeftParen), NULL);
  4189. if (FAILED(hr))
  4190. {
  4191. goto exit;
  4192. }
  4193. // For each of the criteria
  4194. for (ulIndex = 0; ulIndex < cCritList; ulIndex++)
  4195. {
  4196. // Write out the clause
  4197. hr = _HrWriteClauseFromCriteria(pCritList + ulIndex, cClauses, fAnd, fShow, &stmQuery, &cClausesNew);
  4198. if (FAILED(hr))
  4199. {
  4200. goto exit;
  4201. }
  4202. // If we did something
  4203. if (S_OK == hr)
  4204. {
  4205. cClauses += cClausesNew;
  4206. }
  4207. }
  4208. // Clauses
  4209. if (cClauses > 0)
  4210. {
  4211. // End the criteria string
  4212. hr = stmQuery.Write(c_szRightParen, lstrlen(c_szRightParen), NULL);
  4213. if (FAILED(hr))
  4214. {
  4215. goto exit;
  4216. }
  4217. // End the query string
  4218. hr = stmQuery.Write(c_szRightParen, lstrlen(c_szRightParen), NULL);
  4219. if (FAILED(hr))
  4220. {
  4221. goto exit;
  4222. }
  4223. // Return the Query
  4224. IF_FAILEXIT(hr = stmQuery.HrAcquireStringA(&cchQuery, &pszQuery, ACQ_DISPLACE));
  4225. }
  4226. // Set the outgoing param
  4227. *ppszQuery = pszQuery;
  4228. *pcchQuery = cchQuery;
  4229. *pcClauses = cClauses;
  4230. // Set the return value
  4231. hr = S_OK;
  4232. exit:
  4233. // Cleanup
  4234. // Done
  4235. return(hr);
  4236. }
  4237. //--------------------------------------------------------------------------
  4238. // RuleUtil_HrBuildQuerysFromFilter
  4239. //--------------------------------------------------------------------------
  4240. HRESULT RuleUtil_HrBuildQuerysFromFilter(RULEID ridFilter,
  4241. QUERYINFO * pqinfoFilter)
  4242. {
  4243. HRESULT hr = S_OK;
  4244. IOERule * pIRule = NULL;
  4245. PROPVARIANT propvar = {0};
  4246. CRIT_ITEM * pCritList = NULL;
  4247. ULONG cCritList = 0;
  4248. ACT_ITEM * pActList = NULL;
  4249. ULONG cActList = 0;
  4250. DWORD cClauses = 0;
  4251. LPSTR pszQuery = NULL;
  4252. ULONG cchQuery = 0;
  4253. // Initialize
  4254. ZeroMemory(pqinfoFilter, sizeof(pqinfoFilter));
  4255. // Get the rule
  4256. hr = g_pRulesMan->GetRule(ridFilter, RULE_TYPE_FILTER, 0, &pIRule);
  4257. if (FAILED(hr))
  4258. {
  4259. goto exit;
  4260. }
  4261. Assert(NULL != pIRule);
  4262. // Get criteria from filter
  4263. hr = pIRule->GetProp(RULE_PROP_CRITERIA, 0, &propvar);
  4264. if (FAILED(hr))
  4265. {
  4266. goto exit;
  4267. }
  4268. Assert(VT_BLOB == propvar.vt);
  4269. // Save off the criteria list
  4270. pCritList = (CRIT_ITEM *) propvar.blob.pBlobData;
  4271. cCritList = propvar.blob.cbSize / sizeof(CRIT_ITEM);
  4272. Assert(cCritList * sizeof(CRIT_ITEM) == propvar.blob.cbSize);
  4273. ZeroMemory(&propvar, sizeof(propvar));
  4274. // Get actions from filter
  4275. hr = pIRule->GetProp(RULE_PROP_ACTIONS, 0, &propvar);
  4276. if (FAILED(hr))
  4277. {
  4278. goto exit;
  4279. }
  4280. Assert(VT_BLOB == propvar.vt);
  4281. // Save off the actions list
  4282. pActList = (ACT_ITEM *) propvar.blob.pBlobData;
  4283. cActList = propvar.blob.cbSize / sizeof(ACT_ITEM);
  4284. Assert(cActList * sizeof(ACT_ITEM) == propvar.blob.cbSize);
  4285. ZeroMemory(&propvar, sizeof(propvar));
  4286. // Write out the proper action
  4287. Assert(1 == cActList);
  4288. Assert(ACT_TYPE_SHOW == pActList->type);
  4289. Assert(VT_UI4 == pActList->propvar.vt);
  4290. // Get the query string
  4291. hr = _HrBuildQueryFromFilter(pCritList, cCritList, (ACT_DATA_SHOW == pActList->propvar.ulVal),
  4292. &pszQuery, &cchQuery, &cClauses);
  4293. if (FAILED(hr))
  4294. {
  4295. goto exit;
  4296. }
  4297. // Set the outgoing param
  4298. pqinfoFilter->pszQuery = pszQuery;
  4299. pszQuery = NULL;
  4300. pqinfoFilter->cchQuery = cchQuery;
  4301. // Set the return value
  4302. hr = S_OK;
  4303. exit:
  4304. // Cleanup
  4305. if (NULL != pActList)
  4306. {
  4307. RuleUtil_HrFreeActionsItem(pActList, cActList);
  4308. MemFree(pActList);
  4309. }
  4310. if (NULL != pCritList)
  4311. {
  4312. RuleUtil_HrFreeCriteriaItem(pCritList, cCritList);
  4313. MemFree(pCritList);
  4314. }
  4315. SafeRelease(pIRule);
  4316. SafeMemFree(pszQuery);
  4317. // Done
  4318. return(hr);
  4319. }
  4320. typedef struct tagVIEWMENUMAP
  4321. {
  4322. RULEID ridFilter;
  4323. DWORD dwMenuID;
  4324. } VIEWMENUMAP, * PVIEWMENUMAP;
  4325. static const VIEWMENUMAP g_vmmDefault[] =
  4326. {
  4327. {RULEID_VIEW_ALL, ID_VIEW_ALL},
  4328. {RULEID_VIEW_UNREAD, ID_VIEW_UNREAD},
  4329. {RULEID_VIEW_DOWNLOADED, ID_VIEW_DOWNLOADED},
  4330. {RULEID_VIEW_IGNORED, ID_VIEW_IGNORED}
  4331. };
  4332. static const int g_cvmmDefault = sizeof(g_vmmDefault) / sizeof(g_vmmDefault[0]);
  4333. static const int VMM_ALL = 0;
  4334. static const int VMM_UNREAD = 1;
  4335. static const int VMM_DOWNLOADED = 2;
  4336. static const int VMM_IGNORED = 3;
  4337. ///////////////////////////////////////////////////////////////////////////////
  4338. //
  4339. // HrCustomizeCurrentView
  4340. //
  4341. // This creates a rules editor of the proper type.
  4342. //
  4343. // hwnd - The owner dialog
  4344. // dwFlags - What type of editor to bring up
  4345. // ridFilter - The current filter to customize
  4346. //
  4347. // Returns: S_OK, on success
  4348. // E_OUTOFMEMORY, if can't create the Rules Manager object
  4349. //
  4350. ///////////////////////////////////////////////////////////////////////////////
  4351. HRESULT HrCustomizeCurrentView(HWND hwnd, DWORD dwFlags, RULEID * pridFilter)
  4352. {
  4353. HRESULT hr = S_OK;
  4354. CEditRuleUI * pEditRuleUI = NULL;
  4355. IOERule * pIFilter = NULL;
  4356. IOERule * pIFilterNew = NULL;
  4357. TCHAR szRes[CCHMAX_STRINGRES + 5];
  4358. ULONG cchRes = 0;
  4359. LPSTR pszName = NULL;
  4360. PROPVARIANT propvar = {0};
  4361. RULEINFO infoRule = {0};
  4362. DWORD dwFlagsSet = 0;
  4363. // Check incoming params
  4364. if ((NULL == hwnd) || (NULL == pridFilter) || (RULEID_INVALID == *pridFilter))
  4365. {
  4366. hr = E_INVALIDARG;
  4367. goto exit;
  4368. }
  4369. // Create a rule editor object
  4370. pEditRuleUI = new CEditRuleUI;
  4371. if (NULL == pEditRuleUI)
  4372. {
  4373. hr = E_OUTOFMEMORY;
  4374. goto exit;
  4375. }
  4376. // Get the filter
  4377. hr = g_pRulesMan->GetRule(*pridFilter, RULE_TYPE_FILTER, 0, &pIFilter);
  4378. if (FAILED(hr))
  4379. {
  4380. goto exit;
  4381. }
  4382. // Clone the rule
  4383. hr = pIFilter->Clone(&pIFilterNew);
  4384. if (FAILED(hr))
  4385. {
  4386. goto exit;
  4387. }
  4388. // Is this filter a read only filter?
  4389. if (FALSE != FIsFilterReadOnly(*pridFilter))
  4390. {
  4391. // Get the name from the source rule
  4392. hr = pIFilterNew->GetProp(RULE_PROP_NAME, 0, &propvar);
  4393. if (FAILED(hr))
  4394. {
  4395. goto exit;
  4396. }
  4397. // Get the string template to display
  4398. cchRes = LoadString(g_hLocRes, idsRulesCopyName, szRes, ARRAYSIZE(szRes));
  4399. if (0 == cchRes)
  4400. {
  4401. goto exit;
  4402. }
  4403. // Allocate space to hold the final display string
  4404. DWORD cchSize = (cchRes + lstrlen(propvar.pszVal) + 1);
  4405. hr = HrAlloc((void ** ) &pszName, cchSize);
  4406. if (FAILED(hr))
  4407. {
  4408. goto exit;
  4409. }
  4410. // Build up the string and set it
  4411. wnsprintf(pszName, cchSize, szRes, propvar.pszVal);
  4412. PropVariantClear(&propvar);
  4413. propvar.vt = VT_LPSTR;
  4414. propvar.pszVal = pszName;
  4415. pszName = NULL;
  4416. // Set the name into the new rule
  4417. Assert(VT_LPSTR == propvar.vt);
  4418. Assert(NULL != propvar.pszVal);
  4419. hr = pIFilterNew->SetProp(RULE_PROP_NAME, 0, &propvar);
  4420. if (FAILED(hr))
  4421. {
  4422. goto exit;
  4423. }
  4424. // Clear the version of the new rule
  4425. PropVariantClear(&propvar);
  4426. propvar.vt = VT_UI4;
  4427. propvar.ulVal = 0;
  4428. hr = pIFilterNew->SetProp(RULE_PROP_VERSION, 0, &propvar);
  4429. if (FAILED(hr))
  4430. {
  4431. goto exit;
  4432. }
  4433. // Set the rule id to invalid
  4434. *pridFilter = RULEID_INVALID;
  4435. // Note that we want to append the rule
  4436. dwFlagsSet = SETF_APPEND;
  4437. }
  4438. else
  4439. {
  4440. dwFlagsSet = SETF_REPLACE;
  4441. }
  4442. // Initialize the rule editor object
  4443. hr = pEditRuleUI->HrInit(hwnd, ERF_CUSTOMIZEVIEW, RULE_TYPE_FILTER, pIFilterNew, NULL);
  4444. if (FAILED(hr))
  4445. {
  4446. goto exit;
  4447. }
  4448. // Bring up the rules editor UI
  4449. hr = pEditRuleUI->HrShow();
  4450. if (FAILED(hr))
  4451. {
  4452. goto exit;
  4453. }
  4454. // Did anything change
  4455. if (S_OK == hr)
  4456. {
  4457. // Initialize the rule info
  4458. infoRule.pIRule = pIFilterNew;
  4459. infoRule.ridRule = *pridFilter;
  4460. // Add the rule to the list of rules
  4461. hr = g_pRulesMan->SetRules(dwFlagsSet, RULE_TYPE_FILTER, &infoRule, 1);
  4462. if(FAILED(hr))
  4463. {
  4464. goto exit;
  4465. }
  4466. *pridFilter = infoRule.ridRule;
  4467. }
  4468. exit:
  4469. PropVariantClear(&propvar);
  4470. SafeMemFree(pszName);
  4471. SafeRelease(pIFilterNew);
  4472. SafeRelease(pIFilter);
  4473. if (NULL != pEditRuleUI)
  4474. {
  4475. delete pEditRuleUI;
  4476. }
  4477. return hr;
  4478. }
  4479. CViewMenu::~CViewMenu()
  4480. {
  4481. if (NULL != m_pmruList)
  4482. {
  4483. delete m_pmruList;
  4484. }
  4485. }
  4486. ULONG CViewMenu::AddRef(VOID)
  4487. {
  4488. return ++m_cRef;
  4489. }
  4490. ULONG CViewMenu::Release(VOID)
  4491. {
  4492. if (--m_cRef == 0)
  4493. {
  4494. delete this;
  4495. return 0;
  4496. }
  4497. return m_cRef;
  4498. }
  4499. HRESULT CViewMenu::HrInit(DWORD dwFlags)
  4500. {
  4501. HRESULT hr = S_OK;
  4502. m_dwFlags = dwFlags;
  4503. // Create the MRU list
  4504. m_pmruList = new CMRUList;
  4505. if (NULL == m_pmruList)
  4506. {
  4507. hr = E_OUTOFMEMORY;
  4508. goto exit;
  4509. }
  4510. m_pmruList->CreateList(5, 0, c_szRulesFilterMRU);
  4511. // Make sure the MRU list is up to date
  4512. SideAssert(FALSE != _FValiadateMRUList());
  4513. m_dwState |= STATE_INIT;
  4514. hr = S_OK;
  4515. exit:
  4516. return hr;
  4517. }
  4518. HRESULT CViewMenu::HrReplaceMenu(DWORD dwFlags, HMENU hmenu)
  4519. {
  4520. HRESULT hr = S_OK;
  4521. HMENU hmenuView = NULL;
  4522. MENUITEMINFO mii = {0};
  4523. // Load in the real view menu
  4524. hmenuView = LoadPopupMenu(IDR_VIEW_POPUP);
  4525. if (NULL == hmenuView)
  4526. {
  4527. hr = E_OUTOFMEMORY;
  4528. goto exit;
  4529. }
  4530. // Add in the default views
  4531. _AddDefaultViews(hmenuView);
  4532. // Set the real view menu in
  4533. mii.cbSize = sizeof(MENUITEMINFO);
  4534. mii.fMask = MIIM_SUBMENU;
  4535. mii.hSubMenu = hmenuView;
  4536. SetMenuItemInfo(hmenu, ID_POPUP_FILTER, FALSE, &mii);
  4537. // Mark the menu as dirty
  4538. m_dwState |= STATE_DIRTY;
  4539. hr = S_OK;
  4540. exit:
  4541. return hr;
  4542. }
  4543. HRESULT CViewMenu::UpdateViewMenu(DWORD dwFlags, HMENU hmenuView, IMessageList * pMsgList)
  4544. {
  4545. HRESULT hr = S_OK;
  4546. IOEMessageList * pIMsgList = NULL;
  4547. ULONGLONG ullFolder = 0;
  4548. FOLDERID idFolder = FOLDERID_INVALID;
  4549. FOLDERINFO infoFolder = {0};
  4550. MENUITEMINFO mii = {0};
  4551. BOOL fDeletedExists = FALSE;
  4552. BOOL fDownloadedExists = FALSE;
  4553. BOOL fRepliesExists = FALSE;
  4554. CHAR szName[CCHMAX_STRINGRES];
  4555. // Check incoming params
  4556. if (NULL == pMsgList)
  4557. {
  4558. hr = E_INVALIDARG;
  4559. goto exit;
  4560. }
  4561. // Have we been initialized yet?
  4562. if (0 == (m_dwState & STATE_INIT))
  4563. {
  4564. hr = E_UNEXPECTED;
  4565. goto exit;
  4566. }
  4567. // If we don't have a menu, we got problems
  4568. if ((NULL == hmenuView) || (FALSE == IsMenu(hmenuView)))
  4569. {
  4570. hr = E_FAIL;
  4571. goto exit;
  4572. }
  4573. // Get the folder type from the list
  4574. // Get the OE message list interface
  4575. if (FAILED(pMsgList->QueryInterface(IID_IOEMessageList, (VOID **) &pIMsgList)))
  4576. {
  4577. hr = E_FAIL;
  4578. goto exit;
  4579. }
  4580. // Get the folder id from the list
  4581. hr = pIMsgList->get_Folder(&ullFolder);
  4582. if (FAILED(hr))
  4583. {
  4584. goto exit;
  4585. }
  4586. idFolder = (FOLDERID) ullFolder;
  4587. // Get the folder info from the folder id
  4588. Assert(NULL != g_pStore);
  4589. hr = g_pStore->GetFolderInfo(idFolder, &infoFolder);
  4590. if (FAILED(hr))
  4591. {
  4592. goto exit;
  4593. }
  4594. // Figure out if we're supposed to remove/add IMAP specific menus
  4595. // Initialize the menu info for searching
  4596. mii.cbSize = sizeof(mii);
  4597. mii.fMask = MIIM_DATA;
  4598. // Does the ID_SHOW_DELETED menu item exist?
  4599. if (FALSE != GetMenuItemInfo(hmenuView, ID_SHOW_DELETED, FALSE, &mii))
  4600. {
  4601. fDeletedExists = TRUE;
  4602. }
  4603. // Does the ID_SHOW_REPLIES menu item exist?
  4604. if (FALSE != GetMenuItemInfo(hmenuView, ID_SHOW_REPLIES, FALSE, &mii))
  4605. {
  4606. fRepliesExists = TRUE;
  4607. }
  4608. // Does the ID_VIEW_DOWNLOADED menu item exist?
  4609. if (FALSE != GetMenuItemInfo(hmenuView, ID_VIEW_DOWNLOADED, FALSE, &mii))
  4610. {
  4611. fDownloadedExists = TRUE;
  4612. }
  4613. // If the folder is not a LOCAL folder or it is a find folder and
  4614. // the menu item item does not exist
  4615. if (((FOLDER_LOCAL != infoFolder.tyFolder) || (0 != (m_dwFlags & VMF_FINDER)))&& (FALSE == fDownloadedExists))
  4616. {
  4617. // Insert the downloaded menu after the replies menu
  4618. hr = _HrInsertViewMenu(hmenuView, g_vmmDefault[VMM_DOWNLOADED].ridFilter,
  4619. g_vmmDefault[VMM_DOWNLOADED].dwMenuID, ID_VIEW_IGNORED);
  4620. if (FAILED(hr))
  4621. {
  4622. goto exit;
  4623. }
  4624. }
  4625. // else if the folder is a LOCAL folder and not a find folder and
  4626. // the menu item does exist
  4627. else if ((FOLDER_LOCAL == infoFolder.tyFolder) && (0 == (m_dwFlags & VMF_FINDER)) && (FALSE != fDownloadedExists))
  4628. {
  4629. // Remove the Deleted Items menu
  4630. RemoveMenu(hmenuView, ID_VIEW_DOWNLOADED, MF_BYCOMMAND);
  4631. }
  4632. // If the folder is an NNTP folder and
  4633. // the menu item item does not exist
  4634. if ((FOLDER_NEWS == infoFolder.tyFolder) && (FALSE == fRepliesExists))
  4635. {
  4636. // Get the name of the deleted item string
  4637. AthLoadString(idsViewReplies, szName, sizeof(szName));
  4638. // Initialize the menu info
  4639. mii.cbSize = sizeof(mii);
  4640. mii.fMask = MIIM_ID | MIIM_TYPE;
  4641. mii.fType = MFT_STRING;
  4642. mii.fState = MFS_ENABLED;
  4643. mii.wID = ID_SHOW_REPLIES;
  4644. mii.dwTypeData = szName;
  4645. mii.cch = lstrlen(szName);
  4646. // Insert the menu item
  4647. if (FALSE == InsertMenuItem(hmenuView, ID_THREAD_MESSAGES, FALSE, &mii))
  4648. {
  4649. hr = E_FAIL;
  4650. goto exit;
  4651. }
  4652. }
  4653. // else if the folder is not an NNTP folder and
  4654. // the menu item does exist
  4655. else if ((FOLDER_NEWS != infoFolder.tyFolder) && (FALSE != fRepliesExists))
  4656. {
  4657. // Remove the Deleted Items menu
  4658. RemoveMenu(hmenuView, ID_SHOW_REPLIES, MF_BYCOMMAND);
  4659. }
  4660. // If the folder is an IMAP folder or a find folder and
  4661. // the menu item item does not exist
  4662. if (((FOLDER_IMAP == infoFolder.tyFolder) || (0 != (m_dwFlags & VMF_FINDER))) && (FALSE == fDeletedExists))
  4663. {
  4664. // Get the name of the deleted item string
  4665. AthLoadString(idsShowDeleted, szName, sizeof(szName));
  4666. // Initialize the menu info
  4667. mii.cbSize = sizeof(mii);
  4668. mii.fMask = MIIM_ID | MIIM_TYPE;
  4669. mii.fType = MFT_STRING;
  4670. mii.fState = MFS_ENABLED;
  4671. mii.wID = ID_SHOW_DELETED;
  4672. mii.dwTypeData = szName;
  4673. mii.cch = lstrlen(szName);
  4674. // Insert the menu item
  4675. if (FALSE == InsertMenuItem(hmenuView, ID_THREAD_MESSAGES, FALSE, &mii))
  4676. {
  4677. hr = E_FAIL;
  4678. goto exit;
  4679. }
  4680. }
  4681. // else if the folder is not an IMAP folder and not a Find folder and
  4682. // the menu item does exist
  4683. else if ((FOLDER_IMAP != infoFolder.tyFolder) && (0 == (m_dwFlags & VMF_FINDER)) && (FALSE != fDeletedExists))
  4684. {
  4685. // Remove the Deleted Items menu
  4686. RemoveMenu(hmenuView, ID_SHOW_DELETED, MF_BYCOMMAND);
  4687. }
  4688. // if we're dirty
  4689. if (0 != (m_dwState & STATE_DIRTY))
  4690. {
  4691. // Load in the MRU filter list
  4692. hr = _HrReloadMRUViewMenu(hmenuView);
  4693. if (FAILED(hr))
  4694. {
  4695. goto exit;
  4696. }
  4697. // Note that we've reloaded ourselves
  4698. m_dwState &= ~STATE_DIRTY;
  4699. }
  4700. // See if we need to add the extra view menu
  4701. hr = _HrAddExtraViewMenu(hmenuView, pIMsgList);
  4702. if (FAILED(hr))
  4703. {
  4704. goto exit;
  4705. }
  4706. // Set the return value
  4707. hr = S_OK;
  4708. exit:
  4709. g_pStore->FreeRecord(&infoFolder);
  4710. SafeRelease(pIMsgList);
  4711. return hr;
  4712. }
  4713. HRESULT CViewMenu::QueryStatus(IMessageList * pMsgList, OLECMD * prgCmds)
  4714. {
  4715. HRESULT hr = S_OK;
  4716. IOEMessageList * pIMsgList = NULL;
  4717. BOOL fThreading = FALSE;
  4718. BOOL fShowDeleted = FALSE;
  4719. BOOL fShowReplies = FALSE;
  4720. MENUITEMINFO mii = {0};
  4721. CHAR rgchFilterTag[CCH_FILTERTAG_MAX];
  4722. ULONGLONG ullFilter = 0;
  4723. RULEID ridFilter = RULEID_INVALID;
  4724. RULEID ridFilterTag = RULEID_INVALID;
  4725. // Check incoming params
  4726. if ((NULL == pMsgList) || (NULL == prgCmds))
  4727. {
  4728. hr = E_INVALIDARG;
  4729. goto exit;
  4730. }
  4731. // Get the OE message list interface
  4732. if (FAILED(pMsgList->QueryInterface(IID_IOEMessageList, (VOID **) &pIMsgList)))
  4733. {
  4734. hr = E_FAIL;
  4735. goto exit;
  4736. }
  4737. // Get the current filter on the message list
  4738. pIMsgList->get_FilterMessages(&ullFilter);
  4739. ridFilter = (RULEID) ullFilter;
  4740. // Set the flags on the correct menu item
  4741. switch(prgCmds->cmdID)
  4742. {
  4743. case ID_VIEW_ALL:
  4744. // These menu item are always enabled
  4745. prgCmds->cmdf |= OLECMDF_ENABLED;
  4746. // If this filter is turned on, make sure the item is checked
  4747. if (g_vmmDefault[VMM_ALL].ridFilter == ridFilter)
  4748. {
  4749. prgCmds->cmdf |= OLECMDF_NINCHED;
  4750. }
  4751. break;
  4752. case ID_VIEW_UNREAD:
  4753. // These menu item are always enabled
  4754. prgCmds->cmdf |= OLECMDF_ENABLED;
  4755. // If this filter is turned on, make sure the item is checked
  4756. if (g_vmmDefault[VMM_UNREAD].ridFilter == ridFilter)
  4757. {
  4758. prgCmds->cmdf |= OLECMDF_NINCHED;
  4759. }
  4760. break;
  4761. case ID_VIEW_DOWNLOADED:
  4762. // These menu item are always enabled
  4763. prgCmds->cmdf |= OLECMDF_ENABLED;
  4764. // If this filter is turned on, make sure the item is checked
  4765. if (g_vmmDefault[VMM_DOWNLOADED].ridFilter == ridFilter)
  4766. {
  4767. prgCmds->cmdf |= OLECMDF_NINCHED;
  4768. }
  4769. break;
  4770. case ID_VIEW_IGNORED:
  4771. // These menu item are always enabled
  4772. prgCmds->cmdf |= OLECMDF_ENABLED;
  4773. // If this filter is turned on, make sure the item is checked
  4774. if (g_vmmDefault[VMM_IGNORED].ridFilter == ridFilter)
  4775. {
  4776. prgCmds->cmdf |= OLECMDF_NINCHED;
  4777. }
  4778. break;
  4779. case ID_VIEW_CURRENT:
  4780. // These menu item are always enabled
  4781. prgCmds->cmdf |= OLECMDF_ENABLED;
  4782. // If this filter is turned on, make sure the item is checked
  4783. if (m_ridCurrent == ridFilter)
  4784. {
  4785. prgCmds->cmdf |= OLECMDF_NINCHED;
  4786. }
  4787. break;
  4788. case ID_VIEW_RECENT_0:
  4789. case ID_VIEW_RECENT_1:
  4790. case ID_VIEW_RECENT_2:
  4791. case ID_VIEW_RECENT_3:
  4792. case ID_VIEW_RECENT_4:
  4793. // These menu item are always enabled
  4794. prgCmds->cmdf |= OLECMDF_ENABLED;
  4795. if (NULL != m_pmruList)
  4796. {
  4797. if (-1 == m_pmruList->EnumList(prgCmds->cmdID - ID_VIEW_RECENT_0, rgchFilterTag, ARRAYSIZE(rgchFilterTag)))
  4798. {
  4799. break;
  4800. }
  4801. if (FALSE == StrToIntEx(rgchFilterTag, STIF_SUPPORT_HEX, (int *) &ridFilterTag))
  4802. {
  4803. break;
  4804. }
  4805. // If this filter is turned on, make sure the item is checked
  4806. if (ridFilterTag == ridFilter)
  4807. {
  4808. prgCmds->cmdf |= OLECMDF_NINCHED;
  4809. }
  4810. }
  4811. break;
  4812. case ID_VIEW_APPLY:
  4813. case ID_VIEW_CUSTOMIZE:
  4814. case ID_VIEW_MANAGER:
  4815. // If we have a Rules Manager,
  4816. // then we are enabled
  4817. if (NULL != g_pRulesMan)
  4818. {
  4819. prgCmds->cmdf |= OLECMDF_ENABLED;
  4820. }
  4821. break;
  4822. case ID_SHOW_REPLIES:
  4823. // These menu item are always enabled
  4824. prgCmds->cmdf |= OLECMDF_ENABLED;
  4825. // Check to see if show replies is turned on
  4826. if (SUCCEEDED(pIMsgList->get_ShowReplies(&fShowReplies)))
  4827. {
  4828. // If replies is turned on, make sure the item is checked
  4829. if (FALSE != fShowReplies)
  4830. {
  4831. prgCmds->cmdf |= OLECMDF_LATCHED;
  4832. }
  4833. }
  4834. break;
  4835. case ID_SHOW_DELETED:
  4836. // These menu item are always enabled
  4837. prgCmds->cmdf |= OLECMDF_ENABLED;
  4838. // Check to see if show deleted is turned on
  4839. if (SUCCEEDED(pIMsgList->get_ShowDeleted(&fShowDeleted)))
  4840. {
  4841. // If threading is turned on, make sure the item is checked
  4842. if (FALSE != fShowDeleted)
  4843. {
  4844. prgCmds->cmdf |= OLECMDF_LATCHED;
  4845. }
  4846. }
  4847. break;
  4848. case ID_THREAD_MESSAGES:
  4849. // This menu item is always enabled
  4850. prgCmds->cmdf |= OLECMDF_ENABLED;
  4851. // Check to see if threading is turned on
  4852. if (SUCCEEDED(pIMsgList->get_GroupMessages(&fThreading)))
  4853. {
  4854. // If threading is turned on, make sure the item is checked
  4855. if (FALSE != fThreading)
  4856. {
  4857. prgCmds->cmdf |= OLECMDF_LATCHED;
  4858. }
  4859. }
  4860. break;
  4861. }
  4862. // Set the proper return value
  4863. hr = S_OK;
  4864. exit:
  4865. SafeRelease(pIMsgList);
  4866. return hr;
  4867. }
  4868. HRESULT CViewMenu::Exec(HWND hwndUI, DWORD nCmdID, IMessageList * pMsgList, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  4869. {
  4870. HRESULT hr = S_OK;
  4871. IOEMessageList * pIMsgList = NULL;
  4872. BOOL fThreading = FALSE;
  4873. BOOL fShowDeleted = FALSE;
  4874. BOOL fShowReplies = FALSE;
  4875. MENUITEMINFO mii = {0};
  4876. ULONGLONG ullFilter = 0;
  4877. RULEID ridFilter = RULEID_INVALID;
  4878. TCHAR rgchFilterTag[CCH_FILTERTAG_MAX];
  4879. RULEID ridFilterTag = RULEID_INVALID;
  4880. FOLDERID idFolder = FOLDERID_INVALID;
  4881. ULONGLONG ullFolder = 0;
  4882. FOLDERTYPE typeFolder = FOLDER_INVALID;
  4883. DWORD dwFlags = 0;
  4884. BOOL fApplyAll = FALSE;
  4885. // Check incoming params
  4886. if (NULL == pMsgList)
  4887. {
  4888. hr = E_INVALIDARG;
  4889. goto exit;
  4890. }
  4891. // Get the OE message list interface
  4892. hr = pMsgList->QueryInterface(IID_IOEMessageList, (VOID **) &pIMsgList);
  4893. if (FAILED(hr))
  4894. {
  4895. goto exit;
  4896. }
  4897. // Get the current filter on the message list
  4898. hr = pIMsgList->get_FilterMessages(&ullFilter);
  4899. if (FAILED(hr))
  4900. {
  4901. goto exit;
  4902. }
  4903. ridFilter = (RULEID) ullFilter;
  4904. // Execute the actions for the correct menu item
  4905. switch(nCmdID)
  4906. {
  4907. case ID_VIEW_ALL:
  4908. // If this filter is turned on, make sure the item is checked
  4909. if (g_vmmDefault[VMM_ALL].ridFilter != ridFilter)
  4910. {
  4911. // Set the new filter on the item
  4912. hr = pIMsgList->put_FilterMessages((ULONGLONG) g_vmmDefault[VMM_ALL].ridFilter);
  4913. if (FAILED(hr))
  4914. {
  4915. goto exit;
  4916. }
  4917. // Mark the menu as dirty
  4918. m_dwState |= STATE_DIRTY;
  4919. }
  4920. break;
  4921. case ID_VIEW_UNREAD:
  4922. // If this filter is turned on, make sure the item is checked
  4923. if (g_vmmDefault[VMM_UNREAD].ridFilter != ridFilter)
  4924. {
  4925. // Set the new filter on the item
  4926. hr = pIMsgList->put_FilterMessages((ULONGLONG) g_vmmDefault[VMM_UNREAD].ridFilter);
  4927. if (FAILED(hr))
  4928. {
  4929. goto exit;
  4930. }
  4931. // Mark the menu as dirty
  4932. m_dwState |= STATE_DIRTY;
  4933. }
  4934. break;
  4935. case ID_VIEW_DOWNLOADED:
  4936. // If this filter is turned on, make sure the item is checked
  4937. if (g_vmmDefault[VMM_DOWNLOADED].ridFilter != ridFilter)
  4938. {
  4939. // Set the new filter on the item
  4940. hr = pIMsgList->put_FilterMessages((ULONGLONG) g_vmmDefault[VMM_DOWNLOADED].ridFilter);
  4941. if (FAILED(hr))
  4942. {
  4943. goto exit;
  4944. }
  4945. // Mark the menu as dirty
  4946. m_dwState |= STATE_DIRTY;
  4947. }
  4948. break;
  4949. case ID_VIEW_IGNORED:
  4950. // If this filter is turned on, make sure the item is checked
  4951. if (g_vmmDefault[VMM_IGNORED].ridFilter != ridFilter)
  4952. {
  4953. // Set the new filter on the item
  4954. hr = pIMsgList->put_FilterMessages((ULONGLONG) g_vmmDefault[VMM_IGNORED].ridFilter);
  4955. if (FAILED(hr))
  4956. {
  4957. goto exit;
  4958. }
  4959. // Mark the menu as dirty
  4960. m_dwState |= STATE_DIRTY;
  4961. }
  4962. break;
  4963. case ID_VIEW_CURRENT:
  4964. // Make sure we add the filter to the MRU list
  4965. _AddViewToMRU(m_ridCurrent);
  4966. // If this filter is turned on, make sure the item is checked
  4967. if (m_ridCurrent != ridFilter)
  4968. {
  4969. // Set the new filter on the item
  4970. hr = pIMsgList->put_FilterMessages((ULONGLONG) m_ridCurrent);
  4971. if (FAILED(hr))
  4972. {
  4973. goto exit;
  4974. }
  4975. // Mark the menu as dirty
  4976. m_dwState |= STATE_DIRTY;
  4977. }
  4978. break;
  4979. case ID_VIEW_RECENT_0:
  4980. case ID_VIEW_RECENT_1:
  4981. case ID_VIEW_RECENT_2:
  4982. case ID_VIEW_RECENT_3:
  4983. case ID_VIEW_RECENT_4:
  4984. if (NULL != m_pmruList)
  4985. {
  4986. if (-1 == m_pmruList->EnumList(nCmdID - ID_VIEW_RECENT_0, rgchFilterTag, ARRAYSIZE(rgchFilterTag)))
  4987. {
  4988. break;
  4989. }
  4990. if (FALSE == StrToIntEx(rgchFilterTag, STIF_SUPPORT_HEX, (int *) &ridFilterTag))
  4991. {
  4992. break;
  4993. }
  4994. // Make sure we add the filter to the MRU list
  4995. _AddViewToMRU(ridFilterTag);
  4996. // If this filter is turned on, make sure the item is checked
  4997. if (ridFilterTag != ridFilter)
  4998. {
  4999. // Set the new filter on the item
  5000. hr = pIMsgList->put_FilterMessages((ULONGLONG) ridFilterTag);
  5001. if (FAILED(hr))
  5002. {
  5003. goto exit;
  5004. }
  5005. // Mark the menu as dirty
  5006. m_dwState |= STATE_DIRTY;
  5007. }
  5008. }
  5009. break;
  5010. case ID_VIEW_APPLY:
  5011. if ((NULL != pvaIn) && (VT_I4 == pvaIn->vt))
  5012. {
  5013. // Make sure we add the filter to the MRU list
  5014. _AddViewToMRU((RULEID) IntToPtr(pvaIn->lVal));
  5015. // If threading is turned on, make sure the item is checked
  5016. if (ridFilter != (RULEID) IntToPtr(pvaIn->lVal))
  5017. {
  5018. // Set the new filter on the item
  5019. hr = pIMsgList->put_FilterMessages((long) pvaIn->lVal);
  5020. if (FAILED(hr))
  5021. {
  5022. goto exit;
  5023. }
  5024. // Mark the menu as dirty
  5025. m_dwState |= STATE_DIRTY;
  5026. }
  5027. }
  5028. break;
  5029. case ID_VIEW_CUSTOMIZE:
  5030. hr = HrCustomizeCurrentView(hwndUI, 0, &ridFilter);
  5031. if (FAILED(hr))
  5032. {
  5033. goto exit;
  5034. }
  5035. // If the views list changed, then apply the filter to the list
  5036. if (S_OK == hr)
  5037. {
  5038. // Make sure we add the filter to the MRU list
  5039. _AddViewToMRU(ridFilter);
  5040. // Get the current threading state
  5041. hr = pIMsgList->put_FilterMessages((ULONGLONG) ridFilter);
  5042. if (FAILED(hr))
  5043. {
  5044. goto exit;
  5045. }
  5046. // Mark the menu as dirty
  5047. m_dwState |= STATE_DIRTY;
  5048. }
  5049. break;
  5050. case ID_VIEW_MANAGER:
  5051. if (0 == (m_dwFlags & VMF_FINDER))
  5052. {
  5053. // Get the current folder id
  5054. hr = pIMsgList->get_Folder(&ullFolder);
  5055. if (FAILED(hr))
  5056. {
  5057. goto exit;
  5058. }
  5059. idFolder = (FOLDERID) ullFolder;
  5060. // Get the folder info for this folder
  5061. typeFolder = GetFolderType(idFolder);
  5062. if (FOLDER_LOCAL == typeFolder)
  5063. {
  5064. dwFlags = VRDF_POP3;
  5065. }
  5066. else if (FOLDER_NEWS == typeFolder)
  5067. {
  5068. dwFlags = VRDF_NNTP;
  5069. }
  5070. else if (FOLDER_IMAP == typeFolder)
  5071. {
  5072. dwFlags = VRDF_IMAP;
  5073. }
  5074. else if (FOLDER_HTTPMAIL == typeFolder)
  5075. {
  5076. dwFlags = VRDF_HTTPMAIL;
  5077. }
  5078. }
  5079. hr = HrDoViewsManagerDialog(hwndUI, dwFlags, &ridFilter, &fApplyAll);
  5080. if (FAILED(hr))
  5081. {
  5082. goto exit;
  5083. }
  5084. // If the views list changed, then apply the filter to the list
  5085. if (S_OK == hr)
  5086. {
  5087. // Make sure the MRU list is up to date
  5088. SideAssert(FALSE != _FValiadateMRUList());
  5089. // Make sure we add the filter to the MRU list
  5090. _AddViewToMRU(ridFilter);
  5091. // Get the current threading state
  5092. hr = pIMsgList->put_FilterMessages((ULONGLONG) ridFilter);
  5093. if (FAILED(hr))
  5094. {
  5095. goto exit;
  5096. }
  5097. if (FALSE != fApplyAll)
  5098. {
  5099. // Set the global view
  5100. SetDwOption(OPT_VIEW_GLOBAL, PtrToUlong(ridFilter), NULL, 0);
  5101. // Set the new view on all the subscribed folders
  5102. hr = RecurseFolderHierarchy(FOLDERID_ROOT, RECURSE_SUBFOLDERS | RECURSE_INCLUDECURRENT,
  5103. 0, (DWORD_PTR) ridFilter, _HrRecurseSetFilter);
  5104. if (FAILED(hr))
  5105. {
  5106. goto exit;
  5107. }
  5108. }
  5109. // Mark the menu as dirty
  5110. m_dwState |= STATE_DIRTY;
  5111. }
  5112. break;
  5113. case ID_SHOW_REPLIES:
  5114. // Get the current deleted state
  5115. hr = pIMsgList->get_ShowReplies(&fShowReplies);
  5116. if (FAILED(hr))
  5117. {
  5118. goto exit;
  5119. }
  5120. // Switch it to the opposite state
  5121. fShowReplies = !fShowReplies;
  5122. // Set the current deleted state
  5123. hr = pIMsgList->put_ShowReplies(fShowReplies);
  5124. if (FAILED(hr))
  5125. {
  5126. goto exit;
  5127. }
  5128. break;
  5129. case ID_SHOW_DELETED:
  5130. // Get the current deleted state
  5131. hr = pIMsgList->get_ShowDeleted(&fShowDeleted);
  5132. if (FAILED(hr))
  5133. {
  5134. goto exit;
  5135. }
  5136. // Switch it to the opposite state
  5137. fShowDeleted = !fShowDeleted;
  5138. // Set the current deleted state
  5139. hr = pIMsgList->put_ShowDeleted(fShowDeleted);
  5140. if (FAILED(hr))
  5141. {
  5142. goto exit;
  5143. }
  5144. break;
  5145. case ID_THREAD_MESSAGES:
  5146. // Get the current threading state
  5147. hr = pIMsgList->get_GroupMessages(&fThreading);
  5148. if (FAILED(hr))
  5149. {
  5150. goto exit;
  5151. }
  5152. // Switch it to the opposite state
  5153. fThreading = !fThreading;
  5154. // Set the current threading state
  5155. hr = pIMsgList->put_GroupMessages(fThreading);
  5156. if (FAILED(hr))
  5157. {
  5158. goto exit;
  5159. }
  5160. break;
  5161. }
  5162. // Set the proper return value
  5163. hr = S_OK;
  5164. exit:
  5165. SafeRelease(pIMsgList);
  5166. return hr;
  5167. }
  5168. VOID CViewMenu::_AddDefaultViews(HMENU hmenu)
  5169. {
  5170. HRESULT hr = S_OK;
  5171. ULONG ulIndex = 0;
  5172. PROPVARIANT propvar = {0};
  5173. IOERule * pIFilter = NULL;
  5174. MENUITEMINFO mii = {0};
  5175. ULONG ulMenu = 0;
  5176. Assert(NULL != hmenu);
  5177. // If we don't have a rules manager then fail
  5178. if (NULL == g_pRulesMan)
  5179. {
  5180. goto exit;
  5181. }
  5182. // Initialize the menu info
  5183. mii.cbSize = sizeof(mii);
  5184. mii.fMask = MIIM_ID | MIIM_DATA | MIIM_TYPE;
  5185. mii.fType = MFT_STRING;
  5186. mii.fState = MFS_ENABLED;
  5187. // Add each one of the default views
  5188. for (ulIndex = 0; ulIndex < g_cvmmDefault; ulIndex++)
  5189. {
  5190. // Get the view from the rules manager
  5191. if (FAILED(g_pRulesMan->GetRule(g_vmmDefault[ulIndex].ridFilter, RULE_TYPE_FILTER, 0, &pIFilter)))
  5192. {
  5193. continue;
  5194. }
  5195. // Get the name from the rule
  5196. ZeroMemory(&propvar, sizeof(propvar));
  5197. if ((SUCCEEDED(pIFilter->GetProp(RULE_PROP_NAME, 0, &propvar))) &&
  5198. (NULL != propvar.pszVal))
  5199. {
  5200. // Add the name to the rule
  5201. Assert(VT_LPSTR == propvar.vt);
  5202. mii.wID = g_vmmDefault[ulIndex].dwMenuID;
  5203. mii.dwItemData = (DWORD_PTR) g_vmmDefault[ulIndex].ridFilter;
  5204. mii.dwTypeData = propvar.pszVal;
  5205. mii.cch = lstrlen(propvar.pszVal);
  5206. if (FALSE != InsertMenuItem(hmenu, ulMenu, TRUE, &mii))
  5207. {
  5208. ulMenu++;
  5209. }
  5210. }
  5211. PropVariantClear(&propvar);
  5212. SafeRelease(pIFilter);
  5213. }
  5214. // Add in the default separator if we added at least one item
  5215. if (0 != ulMenu)
  5216. {
  5217. // Set up the menu items
  5218. mii.fMask = MIIM_ID | MIIM_TYPE;
  5219. mii.fType = MFT_SEPARATOR;
  5220. mii.fState = MFS_ENABLED;
  5221. mii.wID = ID_VIEW_DEFAULT_SEPERATOR;
  5222. mii.dwItemData = 0;
  5223. mii.dwTypeData = 0;
  5224. mii.cch = 0;
  5225. // Insert the separator
  5226. InsertMenuItem(hmenu, ulMenu, TRUE, &mii);
  5227. }
  5228. exit:
  5229. PropVariantClear(&propvar);
  5230. SafeRelease(pIFilter);
  5231. return;
  5232. }
  5233. HRESULT CViewMenu::_HrInsertViewMenu(HMENU hmenuView, RULEID ridFilter, DWORD dwMenuID, DWORD dwMenuIDInsert)
  5234. {
  5235. HRESULT hr = S_OK;
  5236. IOERule * pIFilter = NULL;
  5237. PROPVARIANT propvar = {0};
  5238. MENUITEMINFO mii = {0};
  5239. // Get the view from the rules manager
  5240. hr = g_pRulesMan->GetRule(ridFilter, RULE_TYPE_FILTER, 0, &pIFilter);
  5241. if (FAILED(hr))
  5242. {
  5243. goto exit;
  5244. }
  5245. // Get the name from the view
  5246. hr = pIFilter->GetProp(RULE_PROP_NAME, 0, &propvar);
  5247. if (FAILED(hr))
  5248. {
  5249. goto exit;
  5250. }
  5251. // Nothing to do if we don't have a name
  5252. if (NULL == propvar.pszVal)
  5253. {
  5254. hr = E_FAIL;
  5255. goto exit;
  5256. }
  5257. // Initialize the menu info
  5258. mii.cbSize = sizeof(mii);
  5259. mii.fMask = MIIM_ID | MIIM_DATA | MIIM_TYPE;
  5260. mii.fType = MFT_STRING;
  5261. mii.fState = MFS_ENABLED;
  5262. mii.wID = dwMenuID;
  5263. mii.dwItemData = (DWORD_PTR) ridFilter;
  5264. mii.dwTypeData = propvar.pszVal;
  5265. mii.cch = lstrlen(propvar.pszVal);
  5266. // Insert the menu item
  5267. if (FALSE == InsertMenuItem(hmenuView, dwMenuIDInsert, FALSE, &mii))
  5268. {
  5269. hr = E_FAIL;
  5270. goto exit;
  5271. }
  5272. // Set the return value
  5273. hr = S_OK;
  5274. exit:
  5275. PropVariantClear(&propvar);
  5276. SafeRelease(pIFilter);
  5277. return hr;
  5278. }
  5279. HRESULT CViewMenu::_HrReloadMRUViewMenu(HMENU hmenuView)
  5280. {
  5281. HRESULT hr = S_OK;
  5282. ULONG ulMenu = 0;
  5283. INT nItem = 0;
  5284. CHAR rgchFilterTag[CCH_FILTERTAG_MAX];
  5285. RULEID ridFilter = RULEID_INVALID;
  5286. MENUITEMINFO mii = {0};
  5287. // Set up the menu items
  5288. mii.cbSize = sizeof(mii);
  5289. mii.fMask = MIIM_ID;
  5290. // Delete the old items
  5291. for (ulMenu = ID_VIEW_RECENT_0; ulMenu < ID_VIEW_CUSTOMIZE; ulMenu++)
  5292. {
  5293. if (FALSE != GetMenuItemInfo(hmenuView, ulMenu, FALSE, &mii))
  5294. {
  5295. RemoveMenu(hmenuView, ulMenu, MF_BYCOMMAND);
  5296. }
  5297. }
  5298. // Add in each of the filters from the mru list
  5299. for (nItem = 0, ulMenu = ID_VIEW_RECENT_0;
  5300. ((-1 != m_pmruList->EnumList(nItem, rgchFilterTag, ARRAYSIZE(rgchFilterTag))) &&
  5301. (ulMenu < ID_VIEW_RECENT_SEPERATOR)); nItem++)
  5302. {
  5303. // Convert the tag string to a rule id
  5304. if (FALSE == StrToIntEx(rgchFilterTag, STIF_SUPPORT_HEX, (int *) &ridFilter))
  5305. {
  5306. continue;
  5307. }
  5308. // Insert the menu item
  5309. if (SUCCEEDED(_HrInsertViewMenu(hmenuView, ridFilter, ulMenu, ID_VIEW_CUSTOMIZE)))
  5310. {
  5311. ulMenu++;
  5312. }
  5313. }
  5314. // Add in the MRU separator if we added at least one item
  5315. if (ID_VIEW_RECENT_0 != ulMenu)
  5316. {
  5317. // Set up the menu items
  5318. mii.fMask = MIIM_ID | MIIM_TYPE;
  5319. mii.fType = MFT_SEPARATOR;
  5320. mii.fState = MFS_ENABLED;
  5321. mii.wID = ID_VIEW_RECENT_SEPERATOR;
  5322. mii.dwItemData = 0;
  5323. mii.dwTypeData = 0;
  5324. mii.cch = 0;
  5325. // Insert the separator
  5326. InsertMenuItem(hmenuView, ID_VIEW_CUSTOMIZE, FALSE, &mii);
  5327. }
  5328. // Set the proper return value
  5329. hr = S_OK;
  5330. return hr;
  5331. }
  5332. HRESULT CViewMenu::_HrAddExtraViewMenu(HMENU hmenuView, IOEMessageList * pIMsgList)
  5333. {
  5334. HRESULT hr = S_OK;
  5335. ULONGLONG ullFilter = 0;
  5336. RULEID ridFilter = RULEID_INVALID;
  5337. MENUITEMINFO mii = {0};
  5338. BOOL fExtraMenu = FALSE;
  5339. IOERule * pIFilter = NULL;
  5340. PROPVARIANT propvar = {0};
  5341. DWORD dwMenuID = 0;
  5342. Assert(NULL != pIMsgList);
  5343. // Get the current filter on the message list
  5344. hr = pIMsgList->get_FilterMessages(&ullFilter);
  5345. if (FAILED(hr))
  5346. {
  5347. goto exit;
  5348. }
  5349. ridFilter = (RULEID) ullFilter;
  5350. // Initialize the menu info
  5351. mii.cbSize = sizeof(mii);
  5352. mii.fMask = MIIM_DATA;
  5353. // Does the ID_VIEW_CURRENT menu item exist?
  5354. fExtraMenu = !!GetMenuItemInfo(hmenuView, ID_VIEW_CURRENT, FALSE, &mii);
  5355. // Is the view filter one of the defaults or in the MRU list?
  5356. if ((FALSE != FIsFilterReadOnly(ridFilter)) || (FALSE != _FViewInMRUList(ridFilter, NULL)))
  5357. {
  5358. // Does the ID_VIEW_CURRENT menu item exist?
  5359. if (FALSE != fExtraMenu)
  5360. {
  5361. // Remove the ID_VIEW_CURRENT menu item
  5362. RemoveMenu(hmenuView, ID_VIEW_CURRENT, MF_BYCOMMAND);
  5363. // Remove the ID_VIEW_CURRENT_SEPERATOR menu item separator
  5364. RemoveMenu(hmenuView, ID_VIEW_CURRENT_SEPERATOR, MF_BYCOMMAND);
  5365. // Clear out the saved current id
  5366. m_ridCurrent = RULEID_INVALID;
  5367. }
  5368. }
  5369. else
  5370. {
  5371. // Does the ID_VIEW_CURRENT menu item exist?
  5372. if (FALSE != fExtraMenu)
  5373. {
  5374. // Is it different than the current view filter
  5375. if (ridFilter != (RULEID) mii.dwItemData)
  5376. {
  5377. // Get the view from the rules manager
  5378. hr = g_pRulesMan->GetRule(ridFilter, RULE_TYPE_FILTER, 0, &pIFilter);
  5379. if (FAILED(hr))
  5380. {
  5381. goto exit;
  5382. }
  5383. // Get the name from the view
  5384. hr = pIFilter->GetProp(RULE_PROP_NAME, 0, &propvar);
  5385. if (FAILED(hr))
  5386. {
  5387. goto exit;
  5388. }
  5389. // Nothing to do if we don't have a name
  5390. if (NULL == propvar.pszVal)
  5391. {
  5392. hr = E_FAIL;
  5393. goto exit;
  5394. }
  5395. // Initialize the menu info
  5396. mii.cbSize = sizeof(mii);
  5397. mii.fMask = MIIM_DATA | MIIM_TYPE;
  5398. mii.fType = MFT_STRING;
  5399. mii.dwItemData = (DWORD_PTR) ridFilter;
  5400. mii.dwTypeData = propvar.pszVal;
  5401. mii.cch = lstrlen(propvar.pszVal);
  5402. // Reset the menu name and data
  5403. SetMenuItemInfo(hmenuView, ID_VIEW_CURRENT, FALSE, &mii);
  5404. }
  5405. }
  5406. else
  5407. {
  5408. // Initialize the menu item info
  5409. mii.fMask = MIIM_DATA;
  5410. // Figure out which menu to add it before
  5411. dwMenuID = (FALSE != GetMenuItemInfo(hmenuView, ID_VIEW_RECENT_0, FALSE, &mii)) ? ID_VIEW_RECENT_0: ID_VIEW_CUSTOMIZE;
  5412. // Add the extra menu item
  5413. hr = _HrInsertViewMenu(hmenuView, ridFilter, ID_VIEW_CURRENT, dwMenuID);
  5414. if (FAILED(hr))
  5415. {
  5416. goto exit;
  5417. }
  5418. // Set up the menu item info
  5419. mii.fMask = MIIM_ID | MIIM_TYPE;
  5420. mii.fType = MFT_SEPARATOR;
  5421. mii.fState = MFS_ENABLED;
  5422. mii.wID = ID_VIEW_CURRENT_SEPERATOR;
  5423. mii.dwItemData = 0;
  5424. mii.dwTypeData = 0;
  5425. mii.cch = 0;
  5426. // Add the extra menu item separator
  5427. InsertMenuItem(hmenuView, dwMenuID, FALSE, &mii);
  5428. }
  5429. // Save the current rule id
  5430. m_ridCurrent = ridFilter;
  5431. }
  5432. // Set the proper return value
  5433. hr = S_OK;
  5434. exit:
  5435. PropVariantClear(&propvar);
  5436. SafeRelease(pIFilter);
  5437. return hr;
  5438. }
  5439. VOID CViewMenu::_AddViewToMRU(RULEID ridFilter)
  5440. {
  5441. CHAR rgchFilterTag[CCH_FILTERTAG_MAX];
  5442. // Is there anything to do?
  5443. if (RULEID_INVALID == ridFilter)
  5444. {
  5445. goto exit;
  5446. }
  5447. // If this isn't a default view
  5448. if (FALSE == FIsFilterReadOnly(ridFilter))
  5449. {
  5450. // Format the rule id as a hex string
  5451. wnsprintf(rgchFilterTag, ARRAYSIZE(rgchFilterTag), "0X%08X", PtrToUlong(ridFilter));
  5452. // Add the string into the MRU list
  5453. m_pmruList->AddString(rgchFilterTag);
  5454. }
  5455. exit:
  5456. return;
  5457. }
  5458. BOOL CViewMenu::_FViewInMRUList(RULEID ridFilter, DWORD * pdwID)
  5459. {
  5460. BOOL fRet = FALSE;
  5461. INT nItem = 0;
  5462. CHAR rgchFilterTag[CCH_FILTERTAG_MAX];
  5463. RULEID ridFilterMRU = RULEID_INVALID;
  5464. // Initialize the return value
  5465. if (NULL != pdwID)
  5466. {
  5467. *pdwID = -1;
  5468. }
  5469. // Add in each of the filters from the mru list
  5470. for (nItem = 0; -1 != m_pmruList->EnumList(nItem, rgchFilterTag, ARRAYSIZE(rgchFilterTag)); nItem++)
  5471. {
  5472. // Convert the tag string to a rule id
  5473. if (FALSE == StrToIntEx(rgchFilterTag, STIF_SUPPORT_HEX, (int *) &ridFilterMRU))
  5474. {
  5475. continue;
  5476. }
  5477. if (ridFilterMRU == ridFilter)
  5478. {
  5479. fRet = TRUE;
  5480. break;
  5481. }
  5482. }
  5483. return fRet;
  5484. }
  5485. BOOL CViewMenu::_FValiadateMRUList(VOID)
  5486. {
  5487. BOOL fRet = FALSE;
  5488. INT nItem = 0;
  5489. CHAR rgchFilterTag[CCH_FILTERTAG_MAX];
  5490. RULEID ridFilterMRU = RULEID_INVALID;
  5491. IOERule * pIFilter = NULL;
  5492. Assert(NULL != m_pmruList);
  5493. Assert(NULL != g_pRulesMan);
  5494. // Add in each of the filters from the mru list
  5495. for (nItem = 0; -1 != m_pmruList->EnumList(nItem, rgchFilterTag, ARRAYSIZE(rgchFilterTag)); nItem++)
  5496. {
  5497. // Convert the tag string to a rule id
  5498. if (FALSE == StrToIntEx(rgchFilterTag, STIF_SUPPORT_HEX, (int *) &ridFilterMRU))
  5499. {
  5500. continue;
  5501. }
  5502. // Get the view from the rules manager
  5503. if (FAILED(g_pRulesMan->GetRule(ridFilterMRU, RULE_TYPE_FILTER, 0, &pIFilter)))
  5504. {
  5505. if (-1 == m_pmruList->RemoveString(rgchFilterTag))
  5506. {
  5507. fRet = FALSE;
  5508. goto exit;
  5509. }
  5510. }
  5511. SafeRelease(pIFilter);
  5512. }
  5513. // Set the return value
  5514. fRet = TRUE;
  5515. exit:
  5516. SafeRelease(pIFilter);
  5517. return fRet;
  5518. }
  5519. ///////////////////////////////////////////////////////////////////////////////
  5520. //
  5521. // HrCreateViewMenu
  5522. //
  5523. // This creates a view menu.
  5524. //
  5525. // ppViewMenu - pointer to return the view menu
  5526. //
  5527. // Returns: S_OK, on success
  5528. // E_OUTOFMEMORY, if can't create the View Menu object
  5529. //
  5530. ///////////////////////////////////////////////////////////////////////////////
  5531. HRESULT HrCreateViewMenu(DWORD dwFlags, CViewMenu ** ppViewMenu)
  5532. {
  5533. CViewMenu * pViewMenu = NULL;
  5534. HRESULT hr = S_OK;
  5535. // Check the incoming params
  5536. if (NULL == ppViewMenu)
  5537. {
  5538. hr = E_INVALIDARG;
  5539. goto exit;
  5540. }
  5541. // Initialize outgoing params
  5542. *ppViewMenu = NULL;
  5543. // Create the view menu object
  5544. pViewMenu = new CViewMenu;
  5545. if (NULL == pViewMenu)
  5546. {
  5547. hr = E_OUTOFMEMORY;
  5548. goto exit;
  5549. }
  5550. // Initialize the view menu
  5551. hr = pViewMenu->HrInit(dwFlags);
  5552. if (FAILED(hr))
  5553. {
  5554. goto exit;
  5555. }
  5556. // Set the outgoing param
  5557. *ppViewMenu = pViewMenu;
  5558. pViewMenu = NULL;
  5559. // Set the proper return value
  5560. hr = S_OK;
  5561. exit:
  5562. if (NULL != pViewMenu)
  5563. {
  5564. delete pViewMenu;
  5565. }
  5566. return hr;
  5567. }