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.

1062 lines
35 KiB

  1. // --------------------------------------------------------------------------------
  2. // Trigger.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // --------------------------------------------------------------------------------
  5. #include "pch.hxx"
  6. #include "containx.h"
  7. #include "symcache.h"
  8. #include "containx.h"
  9. #include "stackstr.h"
  10. #include "variantx.h"
  11. #include "mimeapi.h"
  12. #ifndef MAC
  13. #include <shlwapi.h>
  14. #endif // !MAC
  15. #include "demand.h"
  16. // --------------------------------------------------------------------------------
  17. // CMimePropertyContainer::TRIGGER_ATT_FILENAME
  18. // --------------------------------------------------------------------------------
  19. HRESULT CMimePropertyContainer::TRIGGER_ATT_FILENAME(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
  20. DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
  21. {
  22. // Locals
  23. HRESULT hr=S_OK;
  24. BOOL fUseProperty;
  25. LPWSTR pszExt;
  26. LPWSTR pszFileName=NULL;
  27. LPPROPSYMBOL pSymbol;
  28. // Handle Dispatch Type
  29. switch(tyTrigger)
  30. {
  31. case IST_DELETEPROP:
  32. if (pContainer->_HrIsTriggerCaller(PID_PAR_FILENAME, IST_DELETEPROP) == S_FALSE)
  33. {
  34. pContainer->DeleteProp(SYM_PAR_FILENAME);
  35. }
  36. break;
  37. case IST_POSTSETPROP:
  38. // Update PID_PAR_NAME, if it didn't generate this
  39. if (pContainer->_HrIsTriggerCaller(PID_PAR_NAME, IST_POSTSETPROP) == S_FALSE)
  40. pContainer->SetProp(SYM_PAR_NAME, dwFlags, pValue);
  41. // Update PAR_FILENAME, if it didn't generate this
  42. if (pContainer->_HrIsTriggerCaller(PID_PAR_FILENAME, IST_POSTSETPROP) == S_FALSE)
  43. pContainer->SetProp(SYM_PAR_FILENAME, dwFlags, pValue);
  44. break;
  45. case IST_POSTGETPROP:
  46. // Cleanup the file name
  47. if (!ISFLAGSET(dwFlags, PDF_ENCODED))
  48. MimeVariantCleanupFileName(pContainer->GetWindowsCP(), pValue);
  49. break;
  50. case IST_GETDEFAULT:
  51. // Try to get PID_PAR_FILENAME first
  52. if (FAILED(pContainer->GetPropW(SYM_PAR_FILENAME, &pszFileName)))
  53. {
  54. // Try to get PID_PAR_NAME
  55. if (FAILED(pContainer->GetPropW(SYM_PAR_NAME, &pszFileName)))
  56. {
  57. hr = MIME_E_NO_DATA;
  58. goto exit;
  59. }
  60. else
  61. pSymbol = SYM_PAR_NAME;
  62. }
  63. else
  64. pSymbol = SYM_PAR_FILENAME;
  65. // Set Source
  66. fUseProperty = TRUE;
  67. // Locate the extension of the file
  68. pszExt = PathFindExtensionW(pszFileName);
  69. // If .com
  70. if (pszExt && StrCmpIW(pszExt, L".com") == 0)
  71. {
  72. // Locals
  73. LPWSTR pszCntType=NULL;
  74. LPWSTR pszSubType=NULL;
  75. // Get the file information
  76. if (SUCCEEDED(MimeOleGetFileInfoW(pszFileName, &pszCntType, &pszSubType, NULL, NULL, NULL)))
  77. {
  78. // Extension is .com and content types don't match what is in the body
  79. if (pContainer->IsContentTypeW(pszCntType, pszSubType) == S_FALSE)
  80. {
  81. // Generate It
  82. if (SUCCEEDED(pContainer->_HrGenerateFileName(NULL, dwFlags, pValue)))
  83. fUseProperty = FALSE;
  84. }
  85. }
  86. // Cleanup
  87. SafeMemFree(pszCntType);
  88. SafeMemFree(pszSubType);
  89. }
  90. // Raid-63402: OE: cc: mail problems with OE
  91. // Empty file extension ?
  92. else if (NULL == pszExt || L'\0' == *pszExt)
  93. {
  94. // Generate a new filename
  95. CHECKHR(hr = pContainer->_HrGenerateFileName(pszFileName, dwFlags, pValue));
  96. // Done
  97. fUseProperty = FALSE;
  98. }
  99. // Return per user request
  100. if (fUseProperty)
  101. {
  102. // Use the property
  103. CHECKHR(hr = pContainer->GetProp(pSymbol, dwFlags, pValue));
  104. }
  105. // Cleanup the file name
  106. if (!ISFLAGSET(dwFlags, PDF_ENCODED))
  107. MimeVariantCleanupFileName(pContainer->GetWindowsCP(), pValue);
  108. break;
  109. }
  110. exit:
  111. // Cleanup
  112. SafeMemFree(pszFileName);
  113. // Done
  114. return hr;
  115. }
  116. // --------------------------------------------------------------------------------
  117. // CMimePropertyContainer::TRIGGER_ATT_GENFNAME
  118. // --------------------------------------------------------------------------------
  119. HRESULT CMimePropertyContainer::TRIGGER_ATT_GENFNAME(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
  120. DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
  121. {
  122. // Locals
  123. HRESULT hr=S_OK;
  124. LPPROPERTY pProperty;
  125. LPSTR pszDefExt=NULL,
  126. pszData=NULL,
  127. pszFree=NULL,
  128. pszSuggest=NULL;
  129. LPCSTR pszCntType=NULL;
  130. MIMEVARIANT rSource;
  131. // Handle Dispatch Type
  132. switch(tyTrigger)
  133. {
  134. case IST_POSTGETPROP:
  135. if (!ISFLAGSET(dwFlags, PDF_ENCODED))
  136. MimeVariantCleanupFileName(pContainer->GetWindowsCP(), pValue);
  137. break;
  138. case IST_GETDEFAULT:
  139. // Try to just get the normal filename
  140. if (SUCCEEDED(TRIGGER_ATT_FILENAME(pContainer, IST_GETDEFAULT, dwFlags, pValue, NULL)))
  141. goto exit;
  142. // Call back into the container
  143. CHECKHR(hr = pContainer->_HrGenerateFileName(NULL, dwFlags, pValue));
  144. // Cleanup the file name
  145. if (!ISFLAGSET(dwFlags, PDF_ENCODED))
  146. MimeVariantCleanupFileName(pContainer->GetWindowsCP(), pValue);
  147. break;
  148. }
  149. exit:
  150. // Cleanup
  151. SafeMemFree(pszData);
  152. SafeMemFree(pszFree);
  153. // Done
  154. return hr;
  155. }
  156. // --------------------------------------------------------------------------------
  157. // CMimePropertyContainer::TRIGGER_ATT_NORMSUBJ
  158. // --------------------------------------------------------------------------------
  159. HRESULT CMimePropertyContainer::TRIGGER_ATT_NORMSUBJ(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
  160. DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
  161. {
  162. // Locals
  163. HRESULT hr=S_OK;
  164. MIMEVARIANT rSubject;
  165. MIMEVARIANT rNormal;
  166. LPSTR pszNormal,
  167. pszFree=NULL;
  168. LPWSTR pszNormalW,
  169. pszFreeW=NULL;
  170. ULONG i=0,
  171. cch=0;
  172. LPPROPERTY pSubject;
  173. // Handle Dispatch Type
  174. if (IST_GETDEFAULT == tyTrigger)
  175. {
  176. // Get Subject
  177. pSubject = pContainer->m_prgIndex[PID_HDR_SUBJECT];
  178. // No Data
  179. if (NULL == pSubject)
  180. {
  181. hr = MIME_E_NO_DATA;
  182. goto exit;
  183. }
  184. switch (pValue->type)
  185. {
  186. case MVT_STRINGA:
  187. {
  188. // Set Subject Type
  189. rSubject.type = MVT_STRINGA;
  190. // Return per user request
  191. CHECKHR(hr = pContainer->HrConvertVariant(pSubject, CVF_NOALLOC, &rSubject));
  192. // Set Normal subject
  193. pszFree = rSubject.fCopy ? NULL : rSubject.rStringA.pszVal;
  194. pszNormal = rSubject.rStringA.pszVal;
  195. // Less than 5 "xxx: "
  196. if (rSubject.rStringA.cchVal >= 4)
  197. {
  198. // 1, 2, 3, 4 spaces followed by a ':' then a space
  199. while (cch < 7 && i < rSubject.rStringA.cchVal)
  200. {
  201. // Skip Lead Bytes
  202. if (IsDBCSLeadByte(rSubject.rStringA.pszVal[i]))
  203. {
  204. i++;
  205. cch++;
  206. }
  207. // Colon
  208. else if (':' == rSubject.rStringA.pszVal[i])
  209. {
  210. if (i+1 >= rSubject.rStringA.cchVal)
  211. {
  212. i++;
  213. pszNormal = (LPSTR)(rSubject.rStringA.pszVal + i);
  214. break;
  215. }
  216. else if (cch <= 4 && ' ' == rSubject.rStringA.pszVal[i+1])
  217. {
  218. i++;
  219. pszNormal = PszSkipWhiteA((LPSTR)(rSubject.rStringA.pszVal + i));
  220. break;
  221. }
  222. else
  223. break;
  224. }
  225. // Next Character
  226. i++;
  227. cch++;
  228. }
  229. }
  230. // Reset Source
  231. if (pszNormal != rSubject.rStringA.pszVal)
  232. {
  233. rSubject.rStringA.pszVal = pszNormal;
  234. rSubject.rStringA.cchVal = lstrlen(pszNormal);
  235. }
  236. break;
  237. }
  238. case MVT_STRINGW:
  239. {
  240. // Set Subject Type
  241. rSubject.type = MVT_STRINGW;
  242. // Return per user request
  243. CHECKHR(hr = pContainer->HrConvertVariant(pSubject, CVF_NOALLOC, &rSubject));
  244. // Set Normal subject
  245. pszFreeW = rSubject.fCopy ? NULL : rSubject.rStringW.pszVal;
  246. pszNormalW = rSubject.rStringW.pszVal;
  247. // Less than 5 "xxx: "
  248. if (rSubject.rStringW.cchVal >= 4)
  249. {
  250. // 1, 2, or 3 spaces followed by a ':' then a space
  251. while (cch < 7 && i < rSubject.rStringW.cchVal)
  252. {
  253. // Colon
  254. if (L':' == rSubject.rStringW.pszVal[i])
  255. {
  256. if (i+1 >= rSubject.rStringW.cchVal)
  257. {
  258. i++;
  259. pszNormalW = (LPWSTR)(rSubject.rStringW.pszVal + i);
  260. break;
  261. }
  262. else if (cch <= 4 && L' ' == rSubject.rStringW.pszVal[i+1])
  263. {
  264. i++;
  265. pszNormalW = PszSkipWhiteW((LPWSTR)(rSubject.rStringW.pszVal + i));
  266. break;
  267. }
  268. else
  269. break;
  270. }
  271. // Next Character
  272. i++;
  273. cch++;
  274. }
  275. }
  276. // Reset Source
  277. if (pszNormalW != rSubject.rStringW.pszVal)
  278. {
  279. rSubject.rStringW.pszVal = pszNormalW;
  280. rSubject.rStringW.cchVal = lstrlenW(pszNormalW);
  281. }
  282. break;
  283. }
  284. default:
  285. AssertSz(FALSE, "Didn't prepare for this type!!!");
  286. break;
  287. }
  288. // Return per user request
  289. CHECKHR(hr = pContainer->HrConvertVariant(pSubject->pSymbol, pSubject->pCharset, IET_DECODED, dwFlags, 0, &rSubject, pValue));
  290. }
  291. exit:
  292. // Cleanup
  293. SafeMemFree(pszFree);
  294. SafeMemFree(pszFreeW);
  295. // Done
  296. return hr;
  297. }
  298. // --------------------------------------------------------------------------------
  299. // CMimePropertyContainer::TRIGGER_HDR_SUBJECT
  300. // --------------------------------------------------------------------------------
  301. HRESULT CMimePropertyContainer::TRIGGER_HDR_SUBJECT(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
  302. DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
  303. {
  304. // Handle Dispatch type
  305. if (IST_DELETEPROP == tyTrigger)
  306. pContainer->DeleteProp(SYM_ATT_NORMSUBJ);
  307. // Done
  308. return S_OK;
  309. }
  310. // --------------------------------------------------------------------------------
  311. // CMimePropertyContainer::TRIGGER_HDR_CNTTYPE
  312. // --------------------------------------------------------------------------------
  313. HRESULT CMimePropertyContainer::TRIGGER_HDR_CNTTYPE(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
  314. DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
  315. {
  316. // Locals
  317. HRESULT hr=S_OK;
  318. CStringParser cString;
  319. CHAR chToken;
  320. MIMEVARIANT rValue;
  321. LPSTR pszCntType=NULL;
  322. // Invalid Arg
  323. Assert(pContainer);
  324. // Handle Dispatch type
  325. switch(tyTrigger)
  326. {
  327. case IST_DELETEPROP:
  328. pContainer->DeleteProp(SYM_ATT_PRITYPE);
  329. pContainer->DeleteProp(SYM_ATT_SUBTYPE);
  330. break;
  331. case IST_POSTSETPROP:
  332. // If not generated from corresponding atributes
  333. if (pContainer->_HrIsTriggerCaller(PID_ATT_PRITYPE, IST_POSTSETPROP) == S_OK ||
  334. pContainer->_HrIsTriggerCaller(PID_ATT_SUBTYPE, IST_POSTSETPROP) == S_OK)
  335. goto exit;
  336. // Validate the Variant
  337. if (ISSTRINGA(pValue))
  338. {
  339. // Locals
  340. CHAR szPriType[255];
  341. // Set the Members
  342. cString.Init(pValue->rStringA.pszVal, pValue->rStringA.cchVal, PSF_NOTRAILWS | PSF_NOCOMMENTS);
  343. // Set Parse Tokens
  344. chToken = cString.ChParse("/");
  345. if ('\0' == chToken && 0 == cString.CchValue())
  346. goto exit;
  347. // Setup the Variant
  348. rValue.type = MVT_STRINGA;
  349. rValue.rStringA.pszVal = (LPSTR)cString.PszValue();
  350. rValue.rStringA.cchVal = cString.CchValue();
  351. // Save Primary Type
  352. StrCpyN(szPriType, rValue.rStringA.pszVal, ARRAYSIZE(szPriType));
  353. // Add New attribute...
  354. CHECKHR(hr = pContainer->SetProp(SYM_ATT_PRITYPE, 0, &rValue));
  355. // Raid-52462: outlook express: mail with bad content type header comes in as an attachment
  356. // Seek end of sub content-type
  357. chToken = cString.ChParse(" ;");
  358. if (0 == cString.CchValue())
  359. {
  360. // Locals
  361. LPCSTR pszSubType = PszDefaultSubType(szPriType);
  362. ULONG cchCntType;
  363. // Set Default SubType
  364. CHECKHR(hr = pContainer->SetProp(SYM_ATT_SUBTYPE, pszSubType));
  365. // Build ContentType
  366. DWORD cchSize = (lstrlen(szPriType) + lstrlen(pszSubType) + 2);
  367. CHECKALLOC(pszCntType = PszAllocA(cchSize));
  368. // Format the ContentType
  369. cchCntType = wnsprintf(pszCntType, cchSize, "%s/%s", szPriType, pszSubType);
  370. // Setup a variant
  371. rValue.type = MVT_STRINGA;
  372. rValue.rStringA.pszVal = (LPSTR)pszCntType;
  373. rValue.rStringA.cchVal = cchCntType;
  374. // Store the variant data
  375. Assert(pContainer->m_prgIndex[PID_HDR_CNTTYPE]);
  376. CHECKHR(hr = pContainer->_HrStoreVariantValue(pContainer->m_prgIndex[PID_HDR_CNTTYPE], 0, &rValue));
  377. // Done
  378. goto exit;
  379. }
  380. // Setup the Variant
  381. rValue.rStringA.pszVal = (LPSTR)cString.PszValue();
  382. rValue.rStringA.cchVal = cString.CchValue();
  383. // Add New attribute...
  384. CHECKHR(hr = pContainer->SetProp(SYM_ATT_SUBTYPE, 0, &rValue));
  385. // We should be done
  386. Assert(';' == chToken || '(' == chToken || '\0' == chToken || ' ' == chToken);
  387. }
  388. break;
  389. case IST_GETDEFAULT:
  390. rValue.type = MVT_STRINGA;
  391. rValue.rStringA.pszVal = (LPSTR)STR_MIME_TEXT_PLAIN;
  392. rValue.rStringA.cchVal = lstrlen(STR_MIME_TEXT_PLAIN);
  393. CHECKHR(hr = pContainer->HrConvertVariant(SYM_HDR_CNTTYPE, NULL, IET_DECODED, dwFlags, 0, &rValue, pValue));
  394. break;
  395. }
  396. exit:
  397. // Cleanup
  398. SafeMemFree(pszCntType);
  399. // Done
  400. return hr;
  401. }
  402. // --------------------------------------------------------------------------------
  403. // CMimePropertyContainer::TRIGGER_ATT_PRITYPE
  404. // --------------------------------------------------------------------------------
  405. HRESULT CMimePropertyContainer::TRIGGER_ATT_PRITYPE(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
  406. DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
  407. {
  408. // Locals
  409. HRESULT hr=S_OK;
  410. LPPROPERTY pSubType;
  411. LPSTR pszSubType;
  412. ULONG cchSubType;
  413. MIMEVARIANT rValue;
  414. // Define a Stack String
  415. STACKSTRING_DEFINE(rContentType, 255);
  416. // Handle Dispatch Type
  417. switch(tyTrigger)
  418. {
  419. case IST_POSTSETPROP:
  420. {
  421. // If inside content type dispatch setprop
  422. if (pContainer->_HrIsTriggerCaller(PID_HDR_CNTTYPE, IST_POSTSETPROP) == S_OK)
  423. goto exit;
  424. // Asser Type
  425. Assert(pValue && ISSTRINGA(pValue));
  426. // Get pCntType
  427. pSubType = pContainer->m_prgIndex[PID_ATT_SUBTYPE];
  428. // Is the subtype set yet
  429. if (pSubType)
  430. {
  431. Assert(ISSTRINGA(&pSubType->rValue));
  432. pszSubType = pSubType->rValue.rStringA.pszVal;
  433. cchSubType = pSubType->rValue.rStringA.cchVal;
  434. }
  435. else
  436. {
  437. pszSubType = (LPSTR)STR_SUB_PLAIN;
  438. cchSubType = lstrlen(STR_SUB_PLAIN);
  439. }
  440. // Make Sure the stack string can hold the data
  441. DWORD cchSize = (cchSubType + pValue->rStringA.cchVal + 2);
  442. STACKSTRING_SETSIZE(rContentType, cchSize);
  443. // Init rValue
  444. ZeroMemory(&rValue, sizeof(MIMEVARIANT));
  445. // Format the content type
  446. rValue.rStringA.cchVal = wnsprintf(rContentType.pszVal, cchSize, "%s/%s", pValue->rStringA.pszVal, pszSubType);
  447. // Setup the value
  448. rValue.type = MVT_STRINGA;
  449. rValue.rStringA.pszVal = rContentType.pszVal;
  450. // SetProp
  451. CHECKHR(hr = pContainer->SetProp(SYM_HDR_CNTTYPE, 0, &rValue));
  452. }
  453. break;
  454. case IST_GETDEFAULT:
  455. rValue.type = MVT_STRINGA;
  456. rValue.rStringA.pszVal = (LPSTR)STR_CNT_TEXT;
  457. rValue.rStringA.cchVal = lstrlen(STR_CNT_TEXT);
  458. CHECKHR(hr = pContainer->HrConvertVariant(SYM_HDR_CNTTYPE, NULL, IET_DECODED, dwFlags, 0, &rValue, pValue));
  459. break;
  460. }
  461. exit:
  462. // Cleanup
  463. STACKSTRING_FREE(rContentType);
  464. // Done
  465. return hr;
  466. }
  467. // --------------------------------------------------------------------------------
  468. // CMimePropertyContainer::TRIGGER_ATT_SUBTYPE
  469. // --------------------------------------------------------------------------------
  470. HRESULT CMimePropertyContainer::TRIGGER_ATT_SUBTYPE(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
  471. DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
  472. {
  473. // Locals
  474. HRESULT hr=S_OK;
  475. LPPROPERTY pPriType;
  476. LPSTR pszPriType;
  477. ULONG cchPriType;
  478. MIMEVARIANT rValue;
  479. // Define a Stack String
  480. STACKSTRING_DEFINE(rContentType, 255);
  481. // Handle Dispatch Type
  482. switch(tyTrigger)
  483. {
  484. case IST_POSTSETPROP:
  485. {
  486. // If inside content type dispatch setprop
  487. if (pContainer->_HrIsTriggerCaller(PID_HDR_CNTTYPE, IST_POSTSETPROP) == S_OK)
  488. goto exit;
  489. // Asser Type
  490. Assert(pValue && ISSTRINGA(pValue));
  491. // Get pCntType
  492. pPriType = pContainer->m_prgIndex[PID_ATT_PRITYPE];
  493. // Is the subtype set yet
  494. if (pPriType)
  495. {
  496. Assert(ISSTRINGA(&pPriType->rValue));
  497. pszPriType = pPriType->rValue.rStringA.pszVal;
  498. cchPriType = pPriType->rValue.rStringA.cchVal;
  499. }
  500. else
  501. {
  502. pszPriType = (LPSTR)STR_CNT_TEXT;
  503. cchPriType = lstrlen(STR_CNT_TEXT);
  504. }
  505. // Make Sure the stack string can hold the data
  506. DWORD cchSize = (cchPriType + pValue->rStringA.cchVal + 2);
  507. STACKSTRING_SETSIZE(rContentType, cchSize);
  508. // Init rValue
  509. ZeroMemory(&rValue, sizeof(MIMEVARIANT));
  510. // Format the content type
  511. rValue.rStringA.cchVal = wnsprintf(rContentType.pszVal, cchSize, "%s/%s", pszPriType, pValue->rStringA.pszVal);
  512. // Setup the value
  513. rValue.type = MVT_STRINGA;
  514. rValue.rStringA.pszVal = rContentType.pszVal;
  515. // SetProp
  516. CHECKHR(hr = pContainer->SetProp(SYM_HDR_CNTTYPE, 0, &rValue));
  517. }
  518. break;
  519. case IST_GETDEFAULT:
  520. rValue.type = MVT_STRINGA;
  521. rValue.rStringA.pszVal = (LPSTR)STR_SUB_PLAIN;
  522. rValue.rStringA.cchVal = lstrlen(STR_SUB_PLAIN);
  523. CHECKHR(hr = pContainer->HrConvertVariant(SYM_HDR_CNTTYPE, NULL, IET_DECODED, dwFlags, 0, &rValue, pValue));
  524. break;
  525. }
  526. exit:
  527. // Cleanup
  528. STACKSTRING_FREE(rContentType);
  529. // Done
  530. return hr;
  531. }
  532. // --------------------------------------------------------------------------------
  533. // CMimePropertyContainer::TRIGGER_HDR_CNTXFER
  534. // --------------------------------------------------------------------------------
  535. HRESULT CMimePropertyContainer::TRIGGER_HDR_CNTXFER(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
  536. DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
  537. {
  538. // Locals
  539. HRESULT hr=S_OK;
  540. MIMEVARIANT rSource;
  541. // Handle Dispatch Type
  542. switch(tyTrigger)
  543. {
  544. case IST_GETDEFAULT:
  545. rSource.type = MVT_STRINGA;
  546. rSource.rStringA.pszVal = (LPSTR)STR_ENC_7BIT;
  547. rSource.rStringA.cchVal = lstrlen(STR_ENC_7BIT);
  548. CHECKHR(hr = pContainer->HrConvertVariant(SYM_HDR_CNTXFER, NULL, IET_DECODED, dwFlags, 0, &rSource, pValue));
  549. break;
  550. }
  551. exit:
  552. // Done
  553. return hr;
  554. }
  555. // --------------------------------------------------------------------------------
  556. // CMimePropertyContainer::TRIGGER_PAR_NAME
  557. // --------------------------------------------------------------------------------
  558. HRESULT CMimePropertyContainer::TRIGGER_PAR_NAME(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
  559. DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
  560. {
  561. // Handle Dispatch type
  562. switch(tyTrigger)
  563. {
  564. case IST_POSTSETPROP:
  565. if (pContainer->_HrIsTriggerCaller(PID_ATT_FILENAME, IST_POSTSETPROP) == S_FALSE)
  566. pContainer->SetProp(SYM_ATT_FILENAME, dwFlags, pValue);
  567. break;
  568. }
  569. // Done
  570. return S_OK;
  571. }
  572. // --------------------------------------------------------------------------------
  573. // CMimePropertyContainer::TRIGGER_PAR_FILENAME
  574. // --------------------------------------------------------------------------------
  575. HRESULT CMimePropertyContainer::TRIGGER_PAR_FILENAME(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
  576. DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
  577. {
  578. // Handle Dispatch type
  579. switch(tyTrigger)
  580. {
  581. case IST_DELETEPROP:
  582. if (pContainer->_HrIsTriggerCaller(PID_ATT_FILENAME, IST_DELETEPROP) == S_FALSE)
  583. pContainer->DeleteProp(SYM_ATT_FILENAME);
  584. break;
  585. case IST_POSTSETPROP:
  586. if (pContainer->_HrIsTriggerCaller(PID_ATT_FILENAME, IST_POSTSETPROP) == S_FALSE)
  587. pContainer->SetProp(SYM_ATT_FILENAME, dwFlags, pValue);
  588. break;
  589. }
  590. // Done
  591. return S_OK;
  592. }
  593. // --------------------------------------------------------------------------------
  594. // CMimePropertyContainer::TRIGGER_ATT_SENTTIME
  595. // --------------------------------------------------------------------------------
  596. HRESULT CMimePropertyContainer::TRIGGER_ATT_SENTTIME(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
  597. DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
  598. {
  599. // Locals
  600. HRESULT hr=S_OK;
  601. // Handle Dispatch type
  602. switch(tyTrigger)
  603. {
  604. case IST_DELETEPROP:
  605. pContainer->DeleteProp(SYM_HDR_DATE);
  606. break;
  607. case IST_POSTSETPROP:
  608. pContainer->SetProp(SYM_HDR_DATE, dwFlags, pValue);
  609. break;
  610. case IST_GETDEFAULT:
  611. // Raid-39471-Mail: Date showing as jan 01, 1601 in readnote for attached message
  612. if (FAILED(pContainer->GetProp(SYM_HDR_DATE, dwFlags, pValue)))
  613. {
  614. // Get Known Property
  615. LPPROPERTY pProperty = pContainer->m_prgIndex[PID_HDR_RECEIVED];
  616. if (pProperty && ISSTRINGA(&pProperty->rValue))
  617. {
  618. // Try Getting Sent Time
  619. CHECKHR(hr = pContainer->GetProp(SYM_ATT_RECVTIME, dwFlags, pValue));
  620. }
  621. else
  622. {
  623. // Locals
  624. SYSTEMTIME st;
  625. MIMEVARIANT rValue;
  626. // Setup rValue
  627. rValue.type = MVT_VARIANT;
  628. rValue.rVariant.vt = VT_FILETIME;
  629. // Get current systemtime
  630. GetSystemTime(&st);
  631. SystemTimeToFileTime(&st, &rValue.rVariant.filetime);
  632. // If the Conversion Fails, get the current time
  633. CHECKHR(hr = pContainer->HrConvertVariant(SYM_ATT_SENTTIME, NULL, IET_DECODED, dwFlags, 0, &rValue, pValue));
  634. }
  635. }
  636. break;
  637. }
  638. exit:
  639. // Done
  640. return hr;
  641. }
  642. // --------------------------------------------------------------------------------
  643. // CMimePropertyContainer::TRIGGER_ATT_RECVTIME
  644. // --------------------------------------------------------------------------------
  645. HRESULT CMimePropertyContainer::TRIGGER_ATT_RECVTIME(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
  646. DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
  647. {
  648. // Locals
  649. HRESULT hr=S_OK;
  650. MIMEVARIANT rSource;
  651. LPMIMEVARIANT pSource;
  652. LPPROPERTY pProperty;
  653. // Handle Dispatch Type
  654. switch(tyTrigger)
  655. {
  656. case IST_DELETEPROP:
  657. pContainer->DeleteProp(SYM_HDR_RECEIVED);
  658. break;
  659. case IST_GETDEFAULT:
  660. // Get Known Property
  661. pProperty = pContainer->m_prgIndex[PID_HDR_RECEIVED];
  662. if (NULL == pProperty || !ISSTRINGA(&pProperty->rValue))
  663. {
  664. // Try Getting Sent Time
  665. MimeOleGetSentTime(pContainer, dwFlags, pValue);
  666. }
  667. // Otherwise, try to convert it
  668. else
  669. {
  670. // If StringA
  671. if (MVT_STRINGA == pProperty->rValue.type)
  672. {
  673. // Find the first header which has a semi-colon in it
  674. while(1)
  675. {
  676. // Seek to last colon
  677. LPSTR psz = pProperty->rValue.rStringA.pszVal;
  678. int i;
  679. for (i = 0; psz[i] ; i++);
  680. rSource.rStringA.pszVal = psz + i; // set to end of string
  681. for (; i >= 0 ; i--)
  682. {
  683. if (psz[i] == ';')
  684. {
  685. rSource.rStringA.pszVal = psz + i;
  686. break;
  687. }
  688. }
  689. if ('\0' == *rSource.rStringA.pszVal)
  690. {
  691. // No more values
  692. if (NULL == pProperty->pNextValue)
  693. {
  694. // Try Getting Sent Time
  695. MimeOleGetSentTime(pContainer, dwFlags, pValue);
  696. // Done
  697. goto exit;
  698. }
  699. // Goto next
  700. pProperty = pProperty->pNextValue;
  701. }
  702. // Otherwise, we must have a good property
  703. else
  704. break;
  705. }
  706. // Step over ';
  707. rSource.rStringA.pszVal++;
  708. // Setup Source
  709. rSource.type = MVT_STRINGA;
  710. rSource.rStringA.cchVal = lstrlen(rSource.rStringA.pszVal);
  711. pSource = &rSource;
  712. }
  713. // Otherwise, just try to conver the current property data
  714. else
  715. pSource = &pProperty->rValue;
  716. // If the Conversion Fails, get the current time
  717. if (FAILED(pContainer->HrConvertVariant(SYM_ATT_RECVTIME, NULL, IET_DECODED, dwFlags, 0, pSource, pValue)))
  718. {
  719. // Try Getting Sent Time
  720. MimeOleGetSentTime(pContainer, dwFlags, pValue);
  721. }
  722. }
  723. break;
  724. }
  725. exit:
  726. // Done
  727. return hr;
  728. }
  729. // --------------------------------------------------------------------------------
  730. // CMimePropertyContainer::TRIGGER_ATT_PRIORITY
  731. // --------------------------------------------------------------------------------
  732. HRESULT CMimePropertyContainer::TRIGGER_ATT_PRIORITY(LPCONTAINER pContainer, TRIGGERTYPE tyTrigger,
  733. DWORD dwFlags, LPMIMEVARIANT pValue, LPMIMEVARIANT pDest)
  734. {
  735. // Locals
  736. HRESULT hr=S_OK;
  737. MIMEVARIANT rSource;
  738. PROPVARIANT rVariant;
  739. LPMIMEVARIANT pSource;
  740. LPPROPERTY pProperty;
  741. // Handle Dispatch type
  742. switch(tyTrigger)
  743. {
  744. // IST_VARIANT_TO_STRINGA
  745. case IST_VARIANT_TO_STRINGA:
  746. Assert(pValue && pDest && MVT_VARIANT == pValue->type && MVT_STRINGA == pDest->type);
  747. if (VT_UI4 != pValue->rVariant.vt)
  748. {
  749. hr = TrapError(MIME_E_VARTYPE_NO_CONVERT);
  750. goto exit;
  751. }
  752. switch(pValue->rVariant.ulVal)
  753. {
  754. // IMSG_PRI_LOW
  755. case IMSG_PRI_LOW:
  756. pDest->rStringA.pszVal = (LPSTR)STR_PRI_MS_LOW;
  757. pDest->rStringA.cchVal = lstrlen(STR_PRI_MS_LOW);
  758. break;
  759. // IMSG_PRI_HIGH
  760. case IMSG_PRI_HIGH:
  761. pDest->rStringA.pszVal = (LPSTR)STR_PRI_MS_HIGH;
  762. pDest->rStringA.cchVal = lstrlen(STR_PRI_MS_HIGH);
  763. break;
  764. // IMSG_PRI_NORMAL
  765. default:
  766. case IMSG_PRI_NORMAL:
  767. pDest->rStringA.pszVal = (LPSTR)STR_PRI_MS_NORMAL;
  768. pDest->rStringA.cchVal = lstrlen(STR_PRI_MS_NORMAL);
  769. break;
  770. }
  771. break;
  772. // IST_VARIANT_TO_STRINGW
  773. case IST_VARIANT_TO_STRINGW:
  774. Assert(pValue && pDest && MVT_VARIANT == pValue->type && MVT_STRINGW == pDest->type);
  775. if (VT_UI4 != pValue->rVariant.vt)
  776. {
  777. hr = TrapError(MIME_E_VARTYPE_NO_CONVERT);
  778. goto exit;
  779. }
  780. switch(pValue->rVariant.ulVal)
  781. {
  782. // IMSG_PRI_LOW
  783. case IMSG_PRI_LOW:
  784. #ifndef WIN16
  785. pDest->rStringW.pszVal = L"Low";
  786. #else
  787. pDest->rStringW.pszVal = "Low";
  788. #endif // !WIN16
  789. pDest->rStringW.cchVal = 3;
  790. break;
  791. // IMSG_PRI_HIGH
  792. case IMSG_PRI_HIGH:
  793. #ifndef WIN16
  794. pDest->rStringW.pszVal = L"High";
  795. #else
  796. pDest->rStringW.pszVal = "High";
  797. #endif // !WIN16
  798. pDest->rStringW.cchVal = 4;
  799. break;
  800. // IMSG_PRI_NORMAL
  801. default:
  802. case IMSG_PRI_NORMAL:
  803. #ifndef WIN16
  804. pDest->rStringW.pszVal = L"Normal";
  805. #else
  806. pDest->rStringW.pszVal = "Normal";
  807. #endif // !WIN16
  808. pDest->rStringW.cchVal = 6;
  809. break;
  810. }
  811. break;
  812. // IST_VARIANT_TO_VARIANT
  813. case IST_VARIANT_TO_VARIANT:
  814. Assert(pValue && pDest && MVT_VARIANT == pValue->type && MVT_VARIANT == pDest->type);
  815. if (VT_UI4 != pValue->rVariant.vt && VT_UI4 != pDest->rVariant.vt)
  816. {
  817. hr = TrapError(MIME_E_VARTYPE_NO_CONVERT);
  818. goto exit;
  819. }
  820. // Nice and Easy
  821. pDest->rVariant.ulVal = pValue->rVariant.ulVal;
  822. break;
  823. // IST_STRINGA_TO_VARIANT
  824. case IST_STRINGA_TO_VARIANT:
  825. Assert(pValue && pDest && MVT_STRINGA == pValue->type && MVT_VARIANT == pDest->type);
  826. if (VT_UI4 != pDest->rVariant.vt)
  827. {
  828. hr = TrapError(MIME_E_VARTYPE_NO_CONVERT);
  829. goto exit;
  830. }
  831. // Priority From String
  832. pDest->rVariant.ulVal = PriorityFromStringA(pValue->rStringA.pszVal);
  833. break;
  834. // IST_STRINGW_TO_VARIANT
  835. case IST_STRINGW_TO_VARIANT:
  836. Assert(pValue && pDest && MVT_STRINGW == pValue->type && MVT_VARIANT == pDest->type);
  837. if (VT_UI4 != pDest->rVariant.vt)
  838. {
  839. hr = TrapError(MIME_E_VARTYPE_NO_CONVERT);
  840. goto exit;
  841. }
  842. // Priority From String
  843. pDest->rVariant.ulVal = PriorityFromStringW(pValue->rStringW.pszVal);
  844. break;
  845. // IST_DELETEPROP
  846. case IST_DELETEPROP:
  847. pContainer->DeleteProp(SYM_HDR_XPRI);
  848. pContainer->DeleteProp(SYM_HDR_XMSPRI);
  849. break;
  850. // IST_POSTSETPROP
  851. case IST_POSTSETPROP:
  852. // Setup rSource
  853. rSource.type = MVT_VARIANT;
  854. rSource.rVariant.vt = VT_UI4;
  855. // Convert to User's Variant to a Integer Priority
  856. CHECKHR(hr = pContainer->HrConvertVariant(SYM_ATT_PRIORITY, NULL, IET_DECODED, 0, 0, pValue, &rSource));
  857. // Setup rVariant
  858. rVariant.vt = VT_LPSTR;
  859. // Switch on priority
  860. switch(rSource.rVariant.ulVal)
  861. {
  862. case IMSG_PRI_LOW:
  863. CHECKHR(hr = pContainer->SetProp(PIDTOSTR(PID_HDR_XMSPRI), STR_PRI_MS_LOW));
  864. CHECKHR(hr = pContainer->SetProp(PIDTOSTR(PID_HDR_XPRI), STR_PRI_LOW));
  865. break;
  866. case IMSG_PRI_NORMAL:
  867. CHECKHR(hr = pContainer->SetProp(PIDTOSTR(PID_HDR_XMSPRI), STR_PRI_MS_NORMAL));
  868. CHECKHR(hr = pContainer->SetProp(PIDTOSTR(PID_HDR_XPRI), STR_PRI_NORMAL));
  869. break;
  870. case IMSG_PRI_HIGH:
  871. CHECKHR(hr = pContainer->SetProp(PIDTOSTR(PID_HDR_XMSPRI), STR_PRI_MS_HIGH));
  872. CHECKHR(hr = pContainer->SetProp(PIDTOSTR(PID_HDR_XPRI), STR_PRI_HIGH));
  873. break;
  874. default:
  875. hr = TrapError(MIME_E_VARTYPE_NO_CONVERT);
  876. goto exit;
  877. }
  878. // Done
  879. break;
  880. // IST_GETDEFAULT
  881. case IST_GETDEFAULT:
  882. // Get the Priority Property
  883. pProperty = pContainer->m_prgIndex[PID_HDR_XPRI];
  884. if (NULL == pProperty)
  885. pProperty = pContainer->m_prgIndex[PID_HDR_XMSPRI];
  886. // No Data
  887. if (NULL == pProperty)
  888. {
  889. rSource.type = MVT_VARIANT;
  890. rSource.rVariant.vt = VT_UI4;
  891. rSource.rVariant.ulVal = IMSG_PRI_NORMAL;
  892. pSource = &rSource;
  893. }
  894. // Otherwise
  895. else
  896. pSource = &pProperty->rValue;
  897. // Convert to User's Variant
  898. CHECKHR(hr = pContainer->HrConvertVariant(SYM_ATT_PRIORITY, NULL, IET_DECODED, dwFlags, 0, pSource, pValue));
  899. // Done
  900. break;
  901. }
  902. exit:
  903. // Done
  904. return hr;
  905. }