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.

1453 lines
42 KiB

  1. // --------------------------------------------------------------------------------
  2. // Mimeutil.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // --------------------------------------------------------------------------------
  5. #include "pch.hxx"
  6. #include "demand.h"
  7. #include "ipab.h"
  8. #include "resource.h"
  9. #include <mimeole.h>
  10. #include "mimeutil.h"
  11. #include "secutil.h"
  12. #include "strconst.h"
  13. #include "oleutil.h"
  14. #include <error.h>
  15. #include "options.h"
  16. #include <shlwapi.h>
  17. #include "fonts.h"
  18. #include "multlang.h"
  19. #include "xpcomm.h"
  20. #include "multiusr.h"
  21. // --------------------------------------------------------------------------------
  22. // Cached Current Default Character Set From Fonts Options Dialog
  23. // --------------------------------------------------------------------------------
  24. static HCHARSET g_hDefaultCharset=NULL; // default charset for reading
  25. HCHARSET g_hDefaultCharsetForMail=NULL; // default charset for sending news
  26. int g_iLastCharsetSelection=0; // last charset selection from View/Language
  27. int g_iCurrentCharsetSelection=0; // current charset selection from View/Language
  28. // --------------------------------------------------------------------------------
  29. // local function
  30. // --------------------------------------------------------------------------------
  31. HRESULT HrGetCodePageTagName(ULONG uCodePage, BSTR *pbstr);
  32. HRESULT GetSubTreeAttachCount(LPMIMEMESSAGE pMsg, HBODY hFirst, ULONG *cCount);
  33. HRESULT HrSetMessageText(LPMIMEMESSAGE pMsg, LPTSTR pszText)
  34. {
  35. TCHAR rgchText[CCHMAX_STRINGRES];
  36. HBODY hBody;
  37. IStream *pstm;
  38. // Is it a string resource id?
  39. if (IS_INTRESOURCE(pszText))
  40. {
  41. if (0 == AthLoadString(PtrToUlong(pszText), rgchText, sizeof(rgchText)))
  42. return E_FAIL;
  43. pszText = rgchText;
  44. }
  45. if (SUCCEEDED(pMsg->GetBody(IBL_ROOT, 0, &hBody)))
  46. pMsg->DeleteBody(hBody, 0);
  47. if (MimeOleCreateVirtualStream(&pstm)==S_OK)
  48. {
  49. pstm->Write(pszText, lstrlen(rgchText)*sizeof(TCHAR), NULL);
  50. pMsg->SetTextBody(TXT_HTML, IET_BINARY, NULL, pstm, NULL);
  51. pstm->Release();
  52. }
  53. pMsg->Commit(0);
  54. return S_OK;
  55. }
  56. HRESULT HrGetWabalFromMsg(LPMIMEMESSAGE pMsg, LPWABAL *ppWabal)
  57. {
  58. ADDRESSLIST addrList={0};
  59. HRESULT hr = S_OK;
  60. LPWABAL lpWabal = NULL;
  61. LONG lRecipType;
  62. ULONG i;
  63. LONG lMapiType;
  64. LPADDRESSPROPS pSender = NULL;
  65. LPADDRESSPROPS pFrom = NULL;
  66. LPWSTR pwszEmail = NULL;
  67. if (!pMsg || !ppWabal)
  68. IF_FAILEXIT(hr = E_INVALIDARG);
  69. IF_FAILEXIT(hr = HrCreateWabalObject(&lpWabal));
  70. lpWabal->SetAssociatedMessage(pMsg);
  71. IF_FAILEXIT(hr=pMsg->GetAddressTypes(IAT_KNOWN, IAP_FRIENDLYW | IAP_EMAIL | IAP_ADRTYPE, &addrList));
  72. for (i=0; i<addrList.cAdrs; i++)
  73. {
  74. // Raid 40730 - OE shows a message was sent by 2 people if the sender and from field do not match.
  75. lMapiType = MimeOleRecipToMapi(addrList.prgAdr[i].dwAdrType);
  76. // If Originator and IAT_FROM
  77. if (MAPI_ORIG == lMapiType)
  78. {
  79. // If IAT_SENDER, remember this item but don't add it yet
  80. if (ISFLAGSET(addrList.prgAdr[i].dwAdrType, IAT_SENDER))
  81. pSender = &addrList.prgAdr[i];
  82. // Have we seen the pFrom
  83. if (ISFLAGSET(addrList.prgAdr[i].dwAdrType, IAT_FROM))
  84. pFrom = &addrList.prgAdr[i];
  85. }
  86. // Don't add the IAT_SENDER
  87. if (!ISFLAGSET(addrList.prgAdr[i].dwAdrType, IAT_SENDER))
  88. {
  89. pwszEmail = PszToUnicode(CP_ACP, addrList.prgAdr[i].pszEmail);
  90. if (addrList.prgAdr[i].pszEmail && !pwszEmail)
  91. IF_FAILEXIT(hr = E_OUTOFMEMORY);
  92. // Add an Entry
  93. IF_FAILEXIT(hr = lpWabal->HrAddEntry(addrList.prgAdr[i].pszFriendlyW, pwszEmail, lMapiType));
  94. SafeMemFree(pwszEmail);
  95. }
  96. }
  97. // If no pFrom, and we have a pSender, at the entry
  98. if (NULL == pFrom && NULL != pSender)
  99. {
  100. pwszEmail = PszToUnicode(CP_ACP, addrList.prgAdr[i].pszEmail);
  101. if (addrList.prgAdr[i].pszEmail && !pwszEmail)
  102. IF_FAILEXIT(hr = E_OUTOFMEMORY);
  103. // Add an Entry
  104. IF_FAILEXIT(hr = lpWabal->HrAddEntry(pSender->pszFriendlyW, pwszEmail, MAPI_ORIG));
  105. }
  106. // success
  107. *ppWabal = lpWabal;
  108. lpWabal->AddRef();
  109. exit:
  110. ReleaseObj(lpWabal);
  111. MemFree(pwszEmail);
  112. g_pMoleAlloc->FreeAddressList(&addrList);
  113. return hr;
  114. }
  115. HRESULT HrCheckDisplayNames(LPWABAL lpWabal, CODEPAGEID cpID)
  116. {
  117. HRESULT hr = S_OK;
  118. ADRINFO wabInfo = {0};
  119. LPWABAL lpWabalFlat = NULL;
  120. IMimeBody *pBody = NULL;
  121. IImnAccount *pAccount = NULL;
  122. if (!lpWabal)
  123. return E_INVALIDARG;
  124. // flatten the distribution lists in the wabal...
  125. IF_FAILEXIT(hr = HrCreateWabalObject(&lpWabalFlat));
  126. IF_FAILEXIT(hr = lpWabal->HrExpandTo(lpWabalFlat));
  127. // use the new flat-wabal
  128. lpWabal = lpWabalFlat;
  129. if (lpWabal->FGetFirst(&wabInfo))
  130. {
  131. do
  132. {
  133. IF_FAILEXIT((hr = HrSafeToEncodeToCP(wabInfo.lpwszDisplay, cpID)));
  134. if (MIME_S_CHARSET_CONFLICT == hr)
  135. goto exit;
  136. }
  137. while (lpWabal->FGetNext(&wabInfo));
  138. }
  139. exit:
  140. ReleaseObj(lpWabalFlat);
  141. return hr;
  142. }
  143. HRESULT HrSetWabalOnMsg(LPMIMEMESSAGE pMsg, LPWABAL lpWabal)
  144. {
  145. LPMIMEADDRESSTABLE pAddrTable = NULL;
  146. LPMIMEADDRESSTABLEW pAddrTableW = NULL;
  147. ADRINFO wabInfo = {0};
  148. LPWABAL lpWabalFlat = NULL;
  149. HADDRESS hAddress = NULL;
  150. HRESULT hr = S_OK;
  151. ADDRESSPROPS rAddress;
  152. const DWORD dwSecurity = DwGetSecurityOfMessage(pMsg);
  153. const BOOL fEncrypt = BOOL(MST_ENCRYPT_MASK & dwSecurity);
  154. const BOOL fSigned = BOOL(MST_SIGN_MASK & dwSecurity);
  155. ULONG cbSymCapsMe = 0;
  156. LPBYTE pbSymCapsMe = NULL;
  157. BOOL fFreeSymCapsMe = FALSE;
  158. LPVOID pvSymCapsCookie = NULL;
  159. PROPVARIANT var;
  160. IMimeBody *pBody = NULL;
  161. IImnAccount *pAccount = NULL;
  162. if (!pMsg || !lpWabal)
  163. return E_INVALIDARG;
  164. IF_FAILEXIT(hr = pMsg->GetAddressTable(&pAddrTable));
  165. IF_FAILEXIT(hr = pAddrTable->QueryInterface(IID_IMimeAddressTableW, (LPVOID*)&pAddrTableW));
  166. pAddrTableW->DeleteTypes(IAT_ALL);
  167. // flatten the distribution lists in the wabal...
  168. IF_FAILEXIT(hr = HrCreateWabalObject(&lpWabalFlat));
  169. lpWabal->SetAssociatedMessage(pMsg);
  170. IF_FAILEXIT(hr = lpWabal->HrExpandTo(lpWabalFlat));
  171. // use the new flat-wabal
  172. lpWabal = lpWabalFlat;
  173. if (fEncrypt || fSigned)
  174. {
  175. //
  176. // Signed message gets OID_SECURITY_SYMCAPS
  177. //
  178. // Encrypted message uses SYMCAPS to prime the pump on the algorithm determination engine.
  179. //
  180. // Get the body object
  181. if (SUCCEEDED(hr = pMsg->BindToObject(HBODY_ROOT, IID_IMimeBody, (void **)&pBody)))
  182. {
  183. // Get the default caps blob from the registry
  184. var.vt = VT_LPSTR;
  185. IF_FAILEXIT(hr = pMsg->GetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &var));
  186. hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, var.pszVal, &pAccount);
  187. SafeMemFree(var.pszVal);
  188. IF_FAILEXIT(hr);
  189. if(SUCCEEDED(hr = pAccount->GetProp(AP_SMTP_ENCRYPT_ALGTH, NULL, &cbSymCapsMe)))
  190. {
  191. if (! MemAlloc((LPVOID *)&pbSymCapsMe, cbSymCapsMe))
  192. {
  193. cbSymCapsMe = 0;
  194. }
  195. else
  196. {
  197. if(FAILED(hr = pAccount->GetProp(AP_SMTP_ENCRYPT_ALGTH, pbSymCapsMe, &cbSymCapsMe)))
  198. {
  199. Assert(FALSE); // Huh, now it fails?
  200. SafeMemFree(pbSymCapsMe);
  201. cbSymCapsMe = 0;
  202. }
  203. else
  204. {
  205. fFreeSymCapsMe = TRUE;
  206. }
  207. }
  208. }
  209. ReleaseObj(pAccount);
  210. if(FAILED(hr))
  211. {
  212. // No Symcap option set for ME. Go get the default value.
  213. if (SUCCEEDED(HrGetHighestSymcaps(&pbSymCapsMe, &cbSymCapsMe)))
  214. {
  215. fFreeSymCapsMe = TRUE;
  216. }
  217. }
  218. // Set our SYMCAPS property on the message
  219. if (fSigned && cbSymCapsMe)
  220. {
  221. var.vt = VT_BLOB;
  222. var.blob.cbSize = cbSymCapsMe;
  223. var.blob.pBlobData = pbSymCapsMe;
  224. pBody->SetOption(OID_SECURITY_SYMCAPS, &var);
  225. }
  226. if (fEncrypt)
  227. {
  228. if (! cbSymCapsMe)
  229. {
  230. // Default value for algorithm determination
  231. pbSymCapsMe = (LPBYTE)c_RC2_40_ALGORITHM_ID;
  232. cbSymCapsMe = cbRC2_40_ALGORITHM_ID;
  233. }
  234. // Prime the pump for calculating encryption algorithm
  235. if (FAILED(hr = MimeOleSMimeCapInit(pbSymCapsMe, cbSymCapsMe, &pvSymCapsCookie)))
  236. {
  237. DOUTL(DOUTL_CRYPT, "MimeOleSMimeCapInit -> %x", hr);
  238. }
  239. }
  240. if (fFreeSymCapsMe)
  241. {
  242. SafeMemFree(pbSymCapsMe);
  243. }
  244. }
  245. }
  246. if (lpWabal->FGetFirst(&wabInfo))
  247. {
  248. do
  249. {
  250. rAddress.dwProps = IAP_ENCRYPTION_PRINT;
  251. LONG l;
  252. l = MapiRecipToMimeOle(wabInfo.lRecipType);
  253. IF_FAILEXIT(hr = pAddrTableW->AppendW(l, IET_DECODED, wabInfo.lpwszDisplay, wabInfo.lpwszAddress, &hAddress));
  254. if (fEncrypt)
  255. {
  256. // need to treat sender differently since there is
  257. // no cert in the wab for her
  258. // it gets taken care of in _HrPrepSecureMsgForSending in secutil
  259. if (MAPI_ORIG != wabInfo.lRecipType && MAPI_REPLYTO != wabInfo.lRecipType)
  260. {
  261. BLOB blSymCaps;
  262. FILETIME ftSigningTime;
  263. blSymCaps.cbSize = 0;
  264. // if these fail, big deal. We just don't have a print then.
  265. // we'll wait for the S/MIME engine to yell, since there may
  266. // be other things wrong with other certs.
  267. hr = HrGetThumbprint(lpWabal, &wabInfo, &(rAddress.tbEncryption), &blSymCaps, &ftSigningTime);
  268. if (SUCCEEDED(hr) && rAddress.tbEncryption.pBlobData)
  269. {
  270. pAddrTableW->SetProps(hAddress, &rAddress);
  271. SafeMemFree(rAddress.tbEncryption.pBlobData);
  272. if (pvSymCapsCookie)
  273. {
  274. if (blSymCaps.cbSize && blSymCaps.pBlobData)
  275. {
  276. // Pass the recipient's SYMCAPS to the algorithm selection engine
  277. hr = MimeOleSMimeCapAddSMimeCap(
  278. blSymCaps.pBlobData,
  279. blSymCaps.cbSize,
  280. pvSymCapsCookie);
  281. MemFree(blSymCaps.pBlobData);
  282. }
  283. else
  284. {
  285. LPBYTE pbCert = NULL;
  286. ULONG cbCert = 0;
  287. // Need to get the cert context for this cert
  288. // BUGBUG: MimeOleSMimeCapAddCert currently doesn't even look
  289. // at the cert. Why should we bother getting it from the thumbprint?
  290. // It only looks at fParanoid
  291. hr = MimeOleSMimeCapAddCert(pbCert,
  292. cbCert,
  293. FALSE, // fParanoid,
  294. pvSymCapsCookie);
  295. }
  296. }
  297. }
  298. }
  299. }
  300. }
  301. while (lpWabal->FGetNext(&wabInfo));
  302. }
  303. if (fEncrypt)
  304. {
  305. LPBYTE pbEncode = NULL;
  306. ULONG cbEncode = 0;
  307. BOOL fFreeEncode = FALSE;
  308. DWORD dwBits = 0;
  309. if (pvSymCapsCookie)
  310. {
  311. // Finish up with SymCaps and save the ALG_BULK
  312. MimeOleSMimeCapGetEncAlg(pvSymCapsCookie,
  313. pbEncode,
  314. &cbEncode,
  315. &dwBits);
  316. if (cbEncode)
  317. {
  318. if (! MemAlloc((LPVOID *)&pbEncode, cbEncode))
  319. {
  320. cbEncode = 0;
  321. }
  322. else
  323. {
  324. fFreeEncode = TRUE;
  325. if (SUCCEEDED(hr = MimeOleSMimeCapGetEncAlg(
  326. pvSymCapsCookie,
  327. pbEncode,
  328. &cbEncode,
  329. &dwBits)))
  330. {
  331. }
  332. }
  333. }
  334. else
  335. {
  336. // Hey, there should ALWAYS be at least RC2 (40 bit). What happened?
  337. AssertSz(cbEncode, "MimeOleSMimeCapGetEncAlg gave us no encoding algorithm");
  338. }
  339. }
  340. if (! pbEncode)
  341. {
  342. // Stick in the RC2 value as a default
  343. pbEncode = (LPBYTE)c_RC2_40_ALGORITHM_ID;
  344. cbEncode = cbRC2_40_ALGORITHM_ID;
  345. }
  346. // Ah, finally, we have calculated the algorithm.
  347. // Set it on the message body
  348. var.vt = VT_BLOB;
  349. var.blob.cbSize = cbEncode;
  350. var.blob.pBlobData = pbEncode;
  351. hr = pBody->SetOption(OID_SECURITY_ALG_BULK, &var);
  352. if (fFreeEncode)
  353. {
  354. SafeMemFree(pbEncode);
  355. }
  356. }
  357. // No more commits needed in the address table hr=pAddrTableW->Commit();
  358. exit:
  359. MemFree(pvSymCapsCookie);
  360. ReleaseObj(pBody);
  361. ReleaseObj(pAddrTable);
  362. ReleaseObj(pAddrTableW);
  363. ReleaseObj(lpWabalFlat);
  364. return hr;
  365. }
  366. #if 0
  367. HRESULT HrSetReplyTo(LPMIMEMESSAGE pMsg, LPSTR lpszEmail)
  368. {
  369. LPMIMEADDRESSTABLE pAddrTable=0;
  370. HRESULT hr;
  371. if (!pMsg)
  372. return E_INVALIDARG;
  373. hr=pMsg->GetAddressTable(&pAddrTable);
  374. if (FAILED(hr))
  375. goto error;
  376. hr=pAddrTable->Append(IAT_REPLYTO, IET_DECODED, NULL, lpszEmail, NULL);
  377. if (FAILED(hr))
  378. goto error;
  379. error:
  380. ReleaseObj(pAddrTable);
  381. return hr;
  382. }
  383. #endif
  384. LONG MimeOleRecipToMapi(IADDRESSTYPE addrtype)
  385. {
  386. LONG lRecipType = MAPI_ORIG;
  387. AssertSz(addrtype & IAT_KNOWN, "Must be a known type for this to work!!");
  388. switch (addrtype)
  389. {
  390. case IAT_FROM:
  391. case IAT_SENDER:
  392. lRecipType=MAPI_ORIG;
  393. break;
  394. case IAT_TO:
  395. lRecipType=MAPI_TO;
  396. break;
  397. case IAT_CC:
  398. lRecipType=MAPI_CC;
  399. break;
  400. case IAT_BCC:
  401. lRecipType=MAPI_BCC;
  402. break;
  403. case IAT_REPLYTO:
  404. lRecipType=MAPI_REPLYTO;
  405. break;
  406. default:
  407. Assert(FALSE);
  408. }
  409. return lRecipType;
  410. }
  411. IADDRESSTYPE MapiRecipToMimeOle(LONG lRecip)
  412. {
  413. IADDRESSTYPE addrtype = IAT_UNKNOWN;
  414. switch (lRecip)
  415. {
  416. case MAPI_ORIG:
  417. addrtype=IAT_FROM;
  418. break;
  419. case MAPI_TO:
  420. addrtype=IAT_TO;
  421. break;
  422. case MAPI_CC:
  423. addrtype=IAT_CC;
  424. break;
  425. case MAPI_BCC:
  426. addrtype=IAT_BCC;
  427. break;
  428. case MAPI_REPLYTO:
  429. addrtype=IAT_REPLYTO;
  430. break;
  431. default:
  432. Assert(FALSE);
  433. }
  434. return addrtype;
  435. }
  436. // CANDIDATES.
  437. // This function is never called to dup a message that has all the security
  438. // fully encoded into the message. Because of that, we always need to clear
  439. // the security flags and then reset them into the
  440. HRESULT HrDupeMsg(LPMIMEMESSAGE pMsg, LPMIMEMESSAGE *ppMsg)
  441. {
  442. LPMIMEMESSAGE pMsgDupe=0;
  443. IMimePropertySet *pPropsSrc,
  444. *pPropsDest;
  445. LPSTREAM pstm=0;
  446. HRESULT hr;
  447. HCHARSET hCharset ;
  448. DWORD dwSecFlags = MST_NONE;
  449. SECSTATE secState = {0};
  450. LPCSTR rgszHdrCopy[] = {
  451. PIDTOSTR(PID_ATT_ACCOUNTID),
  452. STR_ATT_ACCOUNTNAME,
  453. PIDTOSTR(PID_ATT_STOREMSGID),
  454. PIDTOSTR(PID_ATT_STOREFOLDERID) };
  455. if (!ppMsg || !pMsg)
  456. return E_INVALIDARG;
  457. *ppMsg=0;
  458. hr=HrCreateMessage(&pMsgDupe);
  459. if (FAILED(hr))
  460. goto error;
  461. HrGetSecurityState(pMsg, &secState, NULL);
  462. if (IsSecure(secState.type))
  463. {
  464. dwSecFlags = MST_CLASS_SMIME_V1;
  465. if (IsSigned(secState.type))
  466. dwSecFlags |= ((DwGetOption(OPT_OPAQUE_SIGN)) ? MST_THIS_BLOBSIGN : MST_THIS_SIGN);
  467. if (IsEncrypted(secState.type))
  468. dwSecFlags |= MST_THIS_ENCRYPT;
  469. hr = HrInitSecurityOptions(pMsg, 0);
  470. if (FAILED(hr))
  471. goto error;
  472. }
  473. hr = pMsg->GetMessageSource(&pstm, 0);
  474. if (FAILED(hr))
  475. goto error;
  476. pMsg->GetCharset(&hCharset);
  477. hr= pMsgDupe->Load(pstm);
  478. if (FAILED(hr))
  479. goto error;
  480. if (hCharset) // for uuencode msg, we need to do this to carry over the charset
  481. pMsgDupe->SetCharset(hCharset, CSET_APPLY_ALL);
  482. if (pMsgDupe->BindToObject(HBODY_ROOT, IID_IMimePropertySet, (LPVOID *)&pPropsDest)==S_OK)
  483. {
  484. if (pMsg->BindToObject(HBODY_ROOT, IID_IMimePropertySet, (LPVOID *)&pPropsSrc)==S_OK)
  485. {
  486. pPropsSrc->CopyProps(ARRAYSIZE(rgszHdrCopy), rgszHdrCopy, pPropsDest);
  487. pPropsSrc->Release();
  488. }
  489. pPropsDest->Release();
  490. }
  491. if (MST_NONE != dwSecFlags)
  492. {
  493. hr = HrInitSecurityOptions(pMsg, dwSecFlags);
  494. if (FAILED(hr))
  495. goto error;
  496. hr = HrInitSecurityOptions(pMsgDupe, dwSecFlags);
  497. if (FAILED(hr))
  498. goto error;
  499. }
  500. *ppMsg = pMsgDupe;
  501. pMsgDupe->AddRef();
  502. error:
  503. ReleaseObj(pMsgDupe);
  504. CleanupSECSTATE(&secState);
  505. ReleaseObj(pstm);
  506. return hr;
  507. }
  508. HRESULT HrRemoveAttachments(LPMIMEMESSAGE pMsg, BOOL fKeepRelatedSection)
  509. {
  510. HRESULT hr;
  511. ULONG cAttach,
  512. uAttach;
  513. LPHBODY rghAttach=0;
  514. HBODY hBody;
  515. if(!pMsg)
  516. return E_INVALIDARG;
  517. hr = pMsg->GetAttachments(&cAttach, &rghAttach);
  518. if (FAILED(hr))
  519. goto error;
  520. for(uAttach=0; uAttach<cAttach; uAttach++)
  521. {
  522. if (fKeepRelatedSection &&
  523. HrIsInRelatedSection(pMsg, rghAttach[uAttach])==S_OK)
  524. continue; // skip related content
  525. hr = pMsg->DeleteBody(rghAttach[uAttach], 0);
  526. if (FAILED(hr))
  527. goto error;
  528. }
  529. //N BUGBUG
  530. /*this is to keep the tree (which may now be a
  531. multipart with single child) in sync. We should
  532. look at DeleteBody performing this. Additionally,
  533. we could have the children whose parents are deleted
  534. inherit their parents' inheritable properties*/
  535. pMsg->Commit(0);
  536. error:
  537. SafeMimeOleFree(rghAttach);
  538. return hr;
  539. }
  540. HRESULT HrCreateMessage(IMimeMessage **ppMsg)
  541. {
  542. return MimeOleCreateMessage(NULL, ppMsg);
  543. }
  544. HRESULT GetAttachmentCount(LPMIMEMESSAGE pMsg, ULONG *pcCount)
  545. {
  546. HRESULT hr = E_INVALIDARG;
  547. ULONG cCount = 0;
  548. if (pMsg && pcCount)
  549. {
  550. HBODY hRootBody;
  551. // WHY? because GetAttachments calculated from renderred body parts. If we call
  552. // on a fresh stream it returns 2 - for the multi/alternate plain/html section
  553. // GetTextBody will mark these body parts as inlinable and they won't show as
  554. // 'attachments'
  555. pMsg->GetTextBody(TXT_HTML, IET_UNICODE, NULL, &hRootBody);
  556. pMsg->GetTextBody(TXT_PLAIN, IET_UNICODE, NULL, &hRootBody);
  557. hr = pMsg->GetBody(IBL_ROOT, NULL, &hRootBody);
  558. if (!FAILED(hr))
  559. {
  560. if(S_OK != pMsg->IsContentType(hRootBody, STR_CNT_MULTIPART, STR_SUB_RELATED))
  561. hr = GetSubTreeAttachCount(pMsg, hRootBody, &cCount);
  562. }
  563. }
  564. *pcCount = cCount;
  565. return hr;
  566. }
  567. HRESULT GetSubTreeAttachCount(LPMIMEMESSAGE pMsg, HBODY hFirst, ULONG *pcCount)
  568. {
  569. HRESULT hr = S_OK;
  570. HBODY hIter = hFirst;
  571. ULONG cCount = 0;
  572. do
  573. {
  574. // Is multipart?
  575. if(S_OK == pMsg->IsContentType(hIter, STR_CNT_MULTIPART, NULL))
  576. {
  577. // Only count the sub tree if is not multipart/related,
  578. if (S_OK != pMsg->IsContentType(hIter, NULL, STR_SUB_RELATED))
  579. {
  580. ULONG cLocalCount;
  581. HBODY hMultiPart;
  582. hr = pMsg->GetBody(IBL_FIRST, hIter, &hMultiPart);
  583. // If GetBody fails, just ignore this sub tree
  584. if (!FAILED(hr))
  585. {
  586. hr = GetSubTreeAttachCount(pMsg, hMultiPart, &cLocalCount);
  587. if (FAILED(hr))
  588. goto Error;
  589. cCount += cLocalCount;
  590. }
  591. }
  592. }
  593. else
  594. {
  595. PROPVARIANT rVariant;
  596. rVariant.vt = VT_I4;
  597. // See RAID-56665: Should ignore this type
  598. if (S_OK != pMsg->IsContentType(hIter, STR_CNT_APPLICATION, STR_SUB_MSTNEF))
  599. {
  600. if (FAILED(pMsg->GetBodyProp(hIter, PIDTOSTR(PID_ATT_RENDERED), NOFLAGS, &rVariant)) || rVariant.ulVal==FALSE)
  601. cCount++;
  602. }
  603. }
  604. } while (S_OK == pMsg->GetBody(IBL_NEXT, hIter, &hIter));
  605. Error:
  606. *pcCount = cCount;
  607. return hr;
  608. }
  609. HRESULT HrSaveMsgToFile(LPMIMEMESSAGE pMsg, LPSTR lpszFile)
  610. {
  611. return HrIPersistFileSave((LPUNKNOWN)pMsg, lpszFile);
  612. }
  613. HRESULT HrSetServer(LPMIMEMESSAGE pMsg, LPSTR lpszServer)
  614. {
  615. PROPVARIANT rUserData;
  616. if (!lpszServer)
  617. return S_OK;
  618. rUserData.vt = VT_LPSTR;
  619. rUserData.pszVal = lpszServer;
  620. return pMsg->SetProp(PIDTOSTR(PID_ATT_SERVER), 0, &rUserData);
  621. }
  622. HRESULT HrSetAccount(LPMIMEMESSAGE pMsg, LPSTR pszAcctName)
  623. {
  624. IImnAccount *pAccount;
  625. PROPVARIANT rUserData;
  626. if (!pszAcctName)
  627. return S_OK;
  628. if (SUCCEEDED(g_pAcctMan->FindAccount(AP_ACCOUNT_NAME, pszAcctName, &pAccount)))
  629. {
  630. CHAR szId[CCHMAX_ACCOUNT_NAME];
  631. rUserData.vt = VT_LPSTR;
  632. rUserData.pszVal = (LPSTR)pszAcctName;
  633. pMsg->SetProp(STR_ATT_ACCOUNTNAME, 0, &rUserData);
  634. if (SUCCEEDED(pAccount->GetPropSz(AP_ACCOUNT_ID, szId, sizeof(szId))))
  635. {
  636. rUserData.pszVal = szId;
  637. pMsg->SetProp(PIDTOSTR(PID_ATT_ACCOUNTID), 0, &rUserData);
  638. }
  639. pAccount->Release();
  640. }
  641. else
  642. return(E_FAIL);
  643. return(S_OK);
  644. }
  645. HRESULT HrSetAccountByAccount(LPMIMEMESSAGE pMsg, IImnAccount *pAcct)
  646. {
  647. TCHAR szAccount[CCHMAX_ACCOUNT_NAME];
  648. TCHAR szId[CCHMAX_ACCOUNT_NAME];
  649. PROPVARIANT rUserData;
  650. if (!pAcct)
  651. return S_OK;
  652. rUserData.vt = VT_LPSTR;
  653. // Having the name in the msg is good, but not necessary
  654. if (SUCCEEDED(pAcct->GetPropSz(AP_ACCOUNT_NAME, szAccount, sizeof(szAccount))))
  655. {
  656. rUserData.pszVal = (LPSTR)szAccount;
  657. pMsg->SetProp(STR_ATT_ACCOUNTNAME, 0, &rUserData);
  658. }
  659. // Must have the account ID in the msg
  660. if (SUCCEEDED(pAcct->GetPropSz(AP_ACCOUNT_ID, szId, sizeof(szId))))
  661. {
  662. rUserData.pszVal = szId;
  663. pMsg->SetProp(PIDTOSTR(PID_ATT_ACCOUNTID), 0, &rUserData);
  664. }
  665. else
  666. return(E_FAIL);
  667. return(S_OK);
  668. }
  669. HRESULT HrLoadMsgFromFile(LPMIMEMESSAGE pMsg, LPSTR lpszFile)
  670. {
  671. return HrIPersistFileLoad((LPUNKNOWN)pMsg, lpszFile);
  672. }
  673. HRESULT HrLoadMsgFromFileW(LPMIMEMESSAGE pMsg, LPWSTR lpwszFile)
  674. {
  675. return HrIPersistFileLoadW((LPUNKNOWN)pMsg, lpwszFile);
  676. }
  677. #define CCH_COUNTBUFFER 4096
  678. HRESULT HrComputeLineCount(LPMIMEMESSAGE pMsg, LPDWORD pdw)
  679. {
  680. HRESULT hr;
  681. BODYOFFSETS rOffset;
  682. LPSTREAM pstm=0;
  683. TCHAR rgch[CCH_COUNTBUFFER+1];
  684. ULONG cb,
  685. i,
  686. cLines=0;
  687. if (!pdw)
  688. return E_INVALIDARG;
  689. *pdw=0;
  690. hr = pMsg->GetMessageSource(&pstm, COMMIT_ONLYIFDIRTY);
  691. if (FAILED(hr))
  692. goto error;
  693. hr=pMsg->GetBodyOffsets(HBODY_ROOT, &rOffset);
  694. if (FAILED(hr))
  695. goto error;
  696. hr=HrStreamSeekSet(pstm, rOffset.cbBodyStart);
  697. if (FAILED(hr))
  698. goto error;
  699. while (pstm->Read(rgch, CCH_COUNTBUFFER, &cb)==S_OK && cb)
  700. {
  701. if (cLines==0) // if there's text, then there's atleast one line.
  702. cLines++;
  703. for (i=0; i<cb; i++)
  704. {
  705. if (rgch[i]=='\n')
  706. cLines++;
  707. }
  708. }
  709. error:
  710. ReleaseObj(pstm);
  711. *pdw=cLines;
  712. return hr;
  713. }
  714. #if 0
  715. // =====================================================================================
  716. // HrEscapeQuotedString - quotes '"' and '\'
  717. // =====================================================================================
  718. HRESULT HrEscapeQuotedString (LPTSTR pszIn, LPTSTR *ppszOut)
  719. {
  720. LPTSTR pszOut;
  721. TCHAR ch;
  722. // worst case - escape every character, so use double original strlen
  723. if (!MemAlloc((LPVOID*)ppszOut, (2 * lstrlen(pszIn) + 1) * sizeof(TCHAR)))
  724. return E_OUTOFMEMORY;
  725. pszOut = *ppszOut;
  726. while (ch = *pszIn++)
  727. {
  728. if (ch == _T('"') || ch == _T('\\'))
  729. *pszOut++ = _T('\\');
  730. *pszOut++ = ch;
  731. }
  732. *pszOut = _T('\0');
  733. return NOERROR;
  734. }
  735. #endif
  736. HRESULT HrHasBodyParts(LPMIMEMESSAGE pMsg)
  737. {
  738. DWORD dwFlags=0;
  739. if (pMsg)
  740. pMsg->GetFlags(&dwFlags);
  741. return (dwFlags&IMF_HTML || dwFlags & IMF_PLAIN)? S_OK : S_FALSE;
  742. }
  743. HRESULT HrHasEncodedBodyParts(LPMIMEMESSAGE pMsg, ULONG cBody, LPHBODY rghBody)
  744. {
  745. ULONG uBody;
  746. if (cBody==0 || rghBody==NULL)
  747. return S_FALSE;
  748. for (uBody=0; uBody<cBody; uBody++)
  749. {
  750. if (HrIsBodyEncoded(pMsg, rghBody[uBody])==S_OK)
  751. return S_OK;
  752. }
  753. return S_FALSE;
  754. }
  755. /*
  756. * looks for non-7bit or non-8bit encoding
  757. */
  758. HRESULT HrIsBodyEncoded(LPMIMEMESSAGE pMsg, HBODY hBody)
  759. {
  760. LPSTR lpsz;
  761. HRESULT hr=S_FALSE;
  762. if (!FAILED(MimeOleGetBodyPropA(pMsg, hBody, PIDTOSTR(PID_HDR_CNTXFER), NOFLAGS, &lpsz)))
  763. {
  764. if (lstrcmpi(lpsz, STR_ENC_7BIT)!=0 && lstrcmpi(lpsz, STR_ENC_8BIT)!=0)
  765. hr=S_OK;
  766. SafeMimeOleFree(lpsz);
  767. }
  768. return hr;
  769. }
  770. // sizeof(lspzBuffer) needs to be == or > CCHMAX_CSET_NAME
  771. HRESULT HrGetMetaTagName(HCHARSET hCharset, LPSTR pszBuffer, DWORD cchSize)
  772. {
  773. INETCSETINFO rCsetInfo;
  774. CODEPAGEINFO rCodePage;
  775. HRESULT hr;
  776. LPSTR psz;
  777. if (hCharset == NULL)
  778. return E_INVALIDARG;
  779. hr = MimeOleGetCharsetInfo(hCharset, &rCsetInfo);
  780. if (FAILED(hr))
  781. goto error;
  782. hr = MimeOleGetCodePageInfo(rCsetInfo.cpiInternet, &rCodePage);
  783. if (FAILED(hr))
  784. goto error;
  785. psz = rCodePage.szWebCset;
  786. if (FIsEmpty(psz)) // if no webset, try the body cset
  787. psz = rCodePage.szBodyCset;
  788. if (FIsEmpty(psz))
  789. {
  790. hr = E_FAIL;
  791. goto error;
  792. }
  793. StrCpyN(pszBuffer, psz, cchSize);
  794. error:
  795. return hr;
  796. }
  797. // --------------------------------------------------------------------------------
  798. // SetDefaultCharset
  799. // --------------------------------------------------------------------------------
  800. void SetDefaultCharset(HCHARSET hCharset)
  801. {
  802. g_hDefaultCharset = hCharset;
  803. }
  804. // --------------------------------------------------------------------------------
  805. // HGetCharsetFromCodepage
  806. // --------------------------------------------------------------------------------
  807. HRESULT HGetCharsetFromCodepage(CODEPAGEID cp, HCHARSET *phCharset)
  808. {
  809. CODEPAGEINFO rCodePage;
  810. HRESULT hr = S_OK;
  811. if(!phCharset)
  812. return E_INVALIDARG;
  813. // Ask MimeOle for the CodePage Information
  814. IF_FAILEXIT(hr = MimeOleGetCodePageInfo(cp, &rCodePage));
  815. // Better Have a WebCharset
  816. if (!(ILM_WEBCSET & rCodePage.dwMask))
  817. {
  818. hr = E_FAIL;
  819. goto exit;
  820. }
  821. // Find the body charset
  822. hr = MimeOleFindCharset(rCodePage.szWebCset, phCharset);
  823. exit:
  824. return hr;
  825. }
  826. // --------------------------------------------------------------------------------
  827. // HGetDefaultCharset
  828. // --------------------------------------------------------------------------------
  829. HRESULT HGetDefaultCharset(HCHARSET *phCharset)
  830. {
  831. DWORD cb;
  832. CODEPAGEID cpiWindows,
  833. cpiInternet;
  834. CHAR szCodePage[MAX_PATH];
  835. HCHARSET hDefaultCharset = NULL; // default charset for reading
  836. HRESULT hr = E_FAIL;
  837. // No Null...
  838. if (g_hDefaultCharset)
  839. {
  840. if(phCharset)
  841. *phCharset = g_hDefaultCharset;
  842. return S_OK;
  843. }
  844. // Open Trident\International
  845. cb = sizeof(cpiWindows);
  846. if (ERROR_SUCCESS != SHGetValue(MU_GetCurrentUserHKey(), c_szRegInternational, c_szDefaultCodePage, NULL, (LPBYTE)&cpiWindows, &cb))
  847. cpiWindows = GetACP();
  848. // Open the CodePage Key
  849. wnsprintf(szCodePage, ARRAYSIZE(szCodePage), "%s\\%d", c_szRegInternational, cpiWindows);
  850. cb = sizeof(cpiInternet);
  851. if (ERROR_SUCCESS != SHGetValue(MU_GetCurrentUserHKey(), szCodePage, c_szDefaultEncoding, NULL, (LPBYTE)&cpiInternet, &cb))
  852. cpiInternet = GetICP(cpiWindows);
  853. // If you can't get the charset, this could be because of user
  854. // roaming or cset uninstall, retry with the default codepage
  855. if(FAILED(HGetCharsetFromCodepage(cpiInternet, &hDefaultCharset)) && (cpiInternet != GetACP()))
  856. {
  857. cpiInternet = GetACP();
  858. IF_FAILEXIT(hr = HGetCharsetFromCodepage(cpiInternet, &hDefaultCharset));
  859. }
  860. // for JP codepage 50221 and 50222, we have to check whether it is
  861. // consistent with registry. If not, we need to override it.
  862. // 50221 and 50222 both have same user friendly name "JIS-allow 1 byte Kana".
  863. // but in registry, it defines which one should be used.
  864. if (cpiInternet == 50222 || cpiInternet == 50221 )
  865. hDefaultCharset = GetJP_ISOControlCharset();
  866. // Set the default charset
  867. g_hDefaultCharset = hDefaultCharset;
  868. // Tell MimeOle About the New Default Charset...
  869. IF_FAILEXIT(hr = MimeOleSetDefaultCharset(hDefaultCharset));
  870. if(phCharset)
  871. *phCharset = hDefaultCharset;
  872. exit:
  873. return hr;
  874. }
  875. HRESULT HrIsInRelatedSection(LPMIMEMESSAGE pMsg, HBODY hBody)
  876. {
  877. HBODY hBodyParent;
  878. if (!FAILED(pMsg->GetBody(IBL_PARENT, hBody, &hBodyParent)) &&
  879. (pMsg->IsContentType(hBodyParent, STR_CNT_MULTIPART, STR_SUB_RELATED)==S_OK))
  880. return S_OK;
  881. else
  882. return S_FALSE;
  883. }
  884. #if 0
  885. HRESULT HrMarkGhosted(LPMIMEMESSAGE pMsg, HBODY hBody)
  886. {
  887. PROPVARIANT pv;
  888. Assert (pMsg && hBody);
  889. pv.vt = VT_I4;
  890. pv.lVal = TRUE;
  891. return pMsg->SetBodyProp(hBody, PIDTOSTR(PID_ATT_GHOSTED), NOFLAGS, &pv);
  892. }
  893. HRESULT HrIsReferencedUrl(LPMIMEMESSAGE pMsg, HBODY hBody)
  894. {
  895. PROPVARIANT rVariant;
  896. rVariant.vt = VT_I4;
  897. if (!FAILED(pMsg->GetBodyProp(hBody, PIDTOSTR(PID_ATT_RENDERED), NOFLAGS, &rVariant)) && rVariant.ulVal)
  898. return S_OK;
  899. return S_FALSE;
  900. }
  901. HRESULT HrIsGhosted(LPMIMEMESSAGE pMsg, HBODY hBody)
  902. {
  903. PROPVARIANT pv;
  904. pv.vt = VT_I4;
  905. if (pMsg->GetBodyProp(hBody, PIDTOSTR(PID_ATT_GHOSTED), NOFLAGS, &pv)==S_OK &&
  906. pv.vt == VT_I4 && pv.lVal == TRUE)
  907. return S_OK;
  908. else
  909. return S_FALSE;
  910. }
  911. HRESULT HrGhostKids(LPMIMEMESSAGE pMsg, HBODY hBody)
  912. {
  913. HRESULT hr=S_OK;
  914. if (pMsg && hBody)
  915. {
  916. if (!FAILED(pMsg->GetBody(IBL_FIRST, hBody, &hBody)))
  917. {
  918. do
  919. {
  920. if (HrIsReferencedUrl(pMsg, hBody)==S_OK)
  921. {
  922. hr = HrMarkGhosted(pMsg, hBody);
  923. if (FAILED(hr))
  924. goto error;
  925. }
  926. }
  927. while (!FAILED(pMsg->GetBody(IBL_NEXT, hBody, &hBody)));
  928. }
  929. }
  930. error:
  931. return hr;
  932. }
  933. HRESULT HrDeleteGhostedKids(LPMIMEMESSAGE pMsg, HBODY hBody)
  934. {
  935. HRESULT hr=S_OK;
  936. ULONG cKids=0,
  937. uKid;
  938. LPHBODY rghKids=0;
  939. pMsg->CountBodies(hBody, FALSE, &cKids);
  940. if (cKids)
  941. {
  942. if (!MemAlloc((LPVOID *)&rghKids, sizeof(HBODY) * cKids))
  943. {
  944. hr = E_OUTOFMEMORY;
  945. goto error;
  946. }
  947. cKids = 0;
  948. if (!FAILED(pMsg->GetBody(IBL_FIRST, hBody, &hBody)))
  949. {
  950. do
  951. {
  952. if (HrIsGhosted(pMsg, hBody)==S_OK)
  953. {
  954. rghKids[cKids++] = hBody;
  955. }
  956. }
  957. while (!FAILED(pMsg->GetBody(IBL_NEXT, hBody, &hBody)));
  958. }
  959. for (uKid = 0; uKid < cKids; uKid++)
  960. {
  961. hr=pMsg->DeleteBody(rghKids[uKid], 0);
  962. if (FAILED(hr))
  963. goto error;
  964. }
  965. }
  966. error:
  967. SafeMemFree(rghKids);
  968. return hr;
  969. }
  970. #endif
  971. // --------------------------------------------------------------------------------
  972. // HrSetSentTimeProp
  973. // --------------------------------------------------------------------------------
  974. HRESULT HrSetSentTimeProp(IMimeMessage *pMessage, LPSYSTEMTIME pst)
  975. {
  976. // Locals
  977. PROPVARIANT rVariant;
  978. SYSTEMTIME st;
  979. // No time was passed in
  980. if (NULL == pst)
  981. {
  982. GetSystemTime(&st);
  983. pst = &st;
  984. }
  985. // Setup the Variant
  986. rVariant.vt = VT_FILETIME;
  987. SystemTimeToFileTime(&st, &rVariant.filetime);
  988. // Set the property and return
  989. return TrapError(pMessage->SetProp(PIDTOSTR(PID_ATT_SENTTIME), 0, &rVariant));
  990. }
  991. // --------------------------------------------------------------------------------
  992. // HrSetMailOptionsOnMessage
  993. // --------------------------------------------------------------------------------
  994. HRESULT HrSetMailOptionsOnMessage(IMimeMessage *pMessage, HTMLOPT *pHtmlOpt, PLAINOPT *pPlainOpt,
  995. HCHARSET hCharset, BOOL fHTML)
  996. {
  997. // Locals
  998. HRESULT hr=S_OK;
  999. PROPVARIANT rVariant;
  1000. ENCODINGTYPE ietEncoding;
  1001. ULONG uSaveFmt,
  1002. uWrap;
  1003. BOOL f8Bit,
  1004. fWrap=FALSE;
  1005. // Invalid Arg
  1006. Assert(pMessage && pHtmlOpt && pPlainOpt);
  1007. // Html Mail
  1008. if (fHTML)
  1009. {
  1010. uSaveFmt = (ULONG)SAVE_RFC1521; // always MIME
  1011. ietEncoding = (IsSecure(pMessage) ? IET_QP : pHtmlOpt->ietEncoding);
  1012. // ietEncoding = pHtmlOpt->ietEncoding;
  1013. f8Bit = pHtmlOpt->f8Bit;
  1014. uWrap = pHtmlOpt->uWrap;
  1015. fWrap = (IET_7BIT == pHtmlOpt->ietEncoding && uWrap > 0) ? TRUE : FALSE;
  1016. }
  1017. else
  1018. {
  1019. // Bug 44270: UUEncode on secure message doesn't make sense. If they asked for secure, they get Mime.
  1020. uSaveFmt = (ULONG)((pPlainOpt->fMime || IsSecure(pMessage)) ? SAVE_RFC1521 : SAVE_RFC822);
  1021. ietEncoding = pPlainOpt->ietEncoding;
  1022. f8Bit = pPlainOpt->f8Bit;
  1023. uWrap = pPlainOpt->uWrap;
  1024. fWrap = (IET_7BIT == pPlainOpt->ietEncoding && uWrap > 0) ? TRUE : FALSE;
  1025. }
  1026. // Save Format
  1027. rVariant.vt = VT_UI4;
  1028. rVariant.ulVal = uSaveFmt;
  1029. CHECKHR(hr = pMessage->SetOption(OID_SAVE_FORMAT, &rVariant));
  1030. // Text body encoding
  1031. rVariant.ulVal = (ULONG)ietEncoding;
  1032. CHECKHR(hr = pMessage->SetOption(OID_TRANSMIT_TEXT_ENCODING, &rVariant));
  1033. // Plain Text body encoding
  1034. rVariant.ulVal = (ULONG)ietEncoding;
  1035. CHECKHR(hr = pMessage->SetOption(OID_XMIT_PLAIN_TEXT_ENCODING, &rVariant));
  1036. // HTML Text body encoding
  1037. rVariant.ulVal = (ULONG)((IET_7BIT == ietEncoding) ? IET_QP : ietEncoding);
  1038. CHECKHR(hr = pMessage->SetOption(OID_XMIT_HTML_TEXT_ENCODING, &rVariant));
  1039. // Wrapping Length
  1040. if (uWrap)
  1041. {
  1042. rVariant.ulVal = (ULONG)uWrap;
  1043. CHECKHR(hr = pMessage->SetOption(OID_CBMAX_BODY_LINE, &rVariant));
  1044. }
  1045. // Allow 8bit Header
  1046. rVariant.vt = VT_BOOL;
  1047. rVariant.boolVal = (VARIANT_BOOL)!!f8Bit;
  1048. CHECKHR(hr = pMessage->SetOption(OID_ALLOW_8BIT_HEADER, &rVariant));
  1049. // Wrapping
  1050. rVariant.boolVal = (VARIANT_BOOL)!!fWrap;
  1051. CHECKHR(hr = pMessage->SetOption(OID_WRAP_BODY_TEXT, &rVariant));
  1052. // set the character set also based on what's set in the fontUI.
  1053. if (hCharset)
  1054. CHECKHR(hr = pMessage->SetCharset(hCharset, CSET_APPLY_ALL));
  1055. exit:
  1056. // Done
  1057. return hr;
  1058. }
  1059. HRESULT HrSetMsgCodePage(LPMIMEMESSAGE pMsg, UINT uCodePage)
  1060. {
  1061. HRESULT hr=E_FAIL;
  1062. HCHARSET hCharset;
  1063. if (pMsg == NULL || uCodePage == 0)
  1064. return E_INVALIDARG;
  1065. // use the WEB charset then the BODY charset, then default charset.
  1066. // EXCEPT for codepage 932 (shift-jis) where bug #61416 requires we ignore the webcarset
  1067. if (uCodePage != 932)
  1068. hr = MimeOleGetCodePageCharset(uCodePage, CHARSET_WEB, &hCharset);
  1069. if (FAILED(hr))
  1070. hr = MimeOleGetCodePageCharset(uCodePage, CHARSET_BODY, &hCharset);
  1071. if (!FAILED(hr))
  1072. hr = pMsg->SetCharset(hCharset, CSET_APPLY_ALL);
  1073. return hr;
  1074. }
  1075. UINT uCodePageFromCharset(HCHARSET hCharset)
  1076. {
  1077. INETCSETINFO CsetInfo;
  1078. UINT uiCodePage = GetACP();
  1079. if (hCharset &&
  1080. (MimeOleGetCharsetInfo(hCharset, &CsetInfo)==S_OK))
  1081. uiCodePage = CsetInfo.cpiInternet ;
  1082. return uiCodePage;
  1083. }
  1084. UINT uCodePageFromMsg(LPMIMEMESSAGE pMsg)
  1085. {
  1086. HCHARSET hCharset=0;
  1087. if (pMsg)
  1088. pMsg->GetCharset(&hCharset);
  1089. return uCodePageFromCharset(hCharset);
  1090. }
  1091. HRESULT HrSafeToEncodeToCP(LPWSTR pwsz, CODEPAGEID cpID)
  1092. {
  1093. HRESULT hr = S_OK;
  1094. INT cbIn = (lstrlenW(pwsz)+1)*sizeof(WCHAR);
  1095. DWORD dwTemp = 0;
  1096. IF_FAILEXIT(hr = ConvertINetString(&dwTemp, CP_UNICODE, cpID, (LPCSTR)pwsz, &cbIn, NULL, NULL));
  1097. if (S_FALSE == hr)
  1098. hr = MIME_S_CHARSET_CONFLICT;
  1099. exit:
  1100. return hr;
  1101. }
  1102. HRESULT HrSafeToEncodeToCPA(LPCSTR psz, CODEPAGEID cpSrc, CODEPAGEID cpDest)
  1103. {
  1104. HRESULT hr = S_OK;
  1105. LPWSTR pwsz = NULL;
  1106. Assert(psz);
  1107. IF_NULLEXIT(pwsz = PszToUnicode(cpSrc, psz));
  1108. IF_FAILEXIT(hr = HrSafeToEncodeToCP(pwsz, cpDest));
  1109. exit:
  1110. MemFree(pwsz);
  1111. return hr;
  1112. }
  1113. #if 0
  1114. HRESULT HrIStreamWToInetCset(LPSTREAM pstmW, HCHARSET hCharset, LPSTREAM *ppstmOut)
  1115. {
  1116. IMimeBody *pBody;
  1117. HRESULT hr;
  1118. hr = MimeOleCreateBody(&pBody);
  1119. if (!FAILED(hr))
  1120. {
  1121. hr = pBody->InitNew();
  1122. if (!FAILED(hr))
  1123. {
  1124. hr = pBody->SetData(IET_UNICODE, STR_CNT_TEXT, STR_SUB_HTML, IID_IStream, pstmW);
  1125. if (!FAILED(hr))
  1126. {
  1127. hr = pBody->SetCharset(hCharset, CSET_APPLY_ALL);
  1128. if (!FAILED(hr))
  1129. hr = pBody->GetData(IET_INETCSET, ppstmOut);
  1130. }
  1131. }
  1132. pBody->Release();
  1133. }
  1134. return hr;
  1135. }
  1136. #endif
  1137. #if 0
  1138. HRESULT HrCopyHeader(LPMIMEMESSAGE pMsg, HBODY hBodyDest, HBODY hBodySrc, LPCSTR pszName)
  1139. {
  1140. LPSTR lpszProp;
  1141. HRESULT hr;
  1142. hr = MimeOleGetBodyPropA(pMsg, hBodySrc, pszName, NOFLAGS, &lpszProp);
  1143. if (!FAILED(hr))
  1144. {
  1145. hr = MimeOleSetBodyPropA(pMsg, hBodyDest, pszName, NOFLAGS, lpszProp);
  1146. SafeMimeOleFree(lpszProp);
  1147. }
  1148. return hr;
  1149. }
  1150. #endif
  1151. #if 0
  1152. HRESULT HrFindUrlInMsg(LPMIMEMESSAGE pMsg, LPSTR lpszUrl, LPSTREAM *ppstm)
  1153. {
  1154. HBODY hBody;
  1155. HRESULT hr = E_FAIL;
  1156. if (MimeOleGetRelatedSection(pMsg, FALSE, &hBody, NULL)==S_OK && hBody)
  1157. {
  1158. if (!FAILED(hr = pMsg->ResolveURL(hBody, NULL, lpszUrl, 0, &hBody)))
  1159. hr = pMsg->BindToObject(hBody, IID_IStream, (LPVOID *)ppstm);
  1160. }
  1161. return hr;
  1162. }
  1163. HRESULT HrSniffStreamFileExt(LPSTREAM pstm, LPSTR *lplpszExt)
  1164. {
  1165. BYTE pb[4096];
  1166. LPWSTR lpszW;
  1167. TCHAR rgch[MAX_PATH];
  1168. if (!FAILED(pstm->Read(&pb, 4096, NULL)))
  1169. {
  1170. if (!FAILED(FindMimeFromData(NULL, NULL, pb, 4096, NULL, NULL, &lpszW, 0)))
  1171. {
  1172. WideCharToMultiByte(CP_ACP, 0, lpszW, -1, rgch, MAX_PATH, NULL, NULL);
  1173. return MimeOleGetContentTypeExt(rgch, lplpszExt);
  1174. }
  1175. }
  1176. return S_FALSE;
  1177. }
  1178. #endif