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.

4428 lines
125 KiB

  1. // --------------------------------------------------------------------------------
  2. // Mimeapi.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "dllmain.h"
  8. #include "olealloc.h"
  9. #include "partial.h"
  10. #include "smime.h"
  11. #include "vstream.h"
  12. #include "internat.h"
  13. #include "stackstr.h"
  14. #include "ixputil.h"
  15. #include "webdocs.h"
  16. #include "containx.h"
  17. #include "inetstm.h"
  18. #include "mhtmlurl.h"
  19. #include "booktree.h"
  20. #include "bookbody.h"
  21. #include <shlwapi.h>
  22. #include <shlwapip.h>
  23. #include "mlang.h"
  24. #include "strconst.h"
  25. #include "symcache.h"
  26. #include "mimeapi.h"
  27. #include "hash.h"
  28. #include "shared.h"
  29. #include "demand.h"
  30. // ------------------------------------------------------------------------------------------
  31. // Special Partial Headers
  32. // ------------------------------------------------------------------------------------------
  33. static LPCSTR g_rgszPartialPids[] = {
  34. PIDTOSTR(PID_HDR_CNTTYPE),
  35. PIDTOSTR(PID_HDR_CNTXFER),
  36. PIDTOSTR(PID_HDR_CNTDESC),
  37. PIDTOSTR(PID_HDR_MESSAGEID),
  38. PIDTOSTR(PID_HDR_MIMEVER),
  39. PIDTOSTR(PID_HDR_CNTID),
  40. PIDTOSTR(PID_HDR_CNTDISP),
  41. STR_HDR_ENCRYPTED
  42. };
  43. // --------------------------------------------------------------------------------
  44. // MimeGetAddressFormatW
  45. // --------------------------------------------------------------------------------
  46. MIMEOLEAPI MimeGetAddressFormatW(REFIID riid, LPVOID pvObject, DWORD dwAdrType,
  47. ADDRESSFORMAT format, LPWSTR *ppszFormat)
  48. {
  49. // Locals
  50. HRESULT hr=S_OK;
  51. CMimePropertyContainer *pContainer=NULL;
  52. // Trace
  53. TraceCall("MimeGetAddressFormatW");
  54. // Invalid Args
  55. if (NULL == pvObject)
  56. return(TraceResult(E_INVALIDARG));
  57. // Is a messageW object ?
  58. if (IID_IMimeMessageW == riid)
  59. {
  60. // Get It
  61. CHECKHR(hr = ((IMimeMessageW *)pvObject)->GetAddressFormatW(dwAdrType, format, ppszFormat));
  62. }
  63. // Is a message object ?
  64. else if (IID_IMimeMessage == riid)
  65. {
  66. // Query for IID_CMimePropertyContainer
  67. CHECKHR(hr = ((IMimeMessage *)pvObject)->BindToObject(HBODY_ROOT, IID_CMimePropertyContainer, (LPVOID *)&pContainer));
  68. // Get the format
  69. CHECKHR(hr = pContainer->GetFormatW(dwAdrType, format, ppszFormat));
  70. }
  71. // IID_IMimePropertySet
  72. else if (IID_IMimePropertySet == riid)
  73. {
  74. // Query for IID_CMimePropertyContainer
  75. CHECKHR(hr = ((IMimePropertySet *)pvObject)->QueryInterface(IID_CMimePropertyContainer, (LPVOID *)&pContainer));
  76. // Get the format
  77. CHECKHR(hr = pContainer->GetFormatW(dwAdrType, format, ppszFormat));
  78. }
  79. // IID_IMimeAddressTable
  80. else if (IID_IMimeAddressTable == riid)
  81. {
  82. // Query for IID_CMimePropertyContainer
  83. CHECKHR(hr = ((IMimeAddressTable *)pvObject)->QueryInterface(IID_CMimePropertyContainer, (LPVOID *)&pContainer));
  84. // Get the format
  85. CHECKHR(hr = pContainer->GetFormatW(dwAdrType, format, ppszFormat));
  86. }
  87. // IID_IMimeHeaderTable
  88. else if (IID_IMimeHeaderTable == riid)
  89. {
  90. // Query for IID_CMimePropertyContainer
  91. CHECKHR(hr = ((IMimeHeaderTable *)pvObject)->QueryInterface(IID_CMimePropertyContainer, (LPVOID *)&pContainer));
  92. // Get the format
  93. CHECKHR(hr = pContainer->GetFormatW(dwAdrType, format, ppszFormat));
  94. }
  95. // Final
  96. else
  97. {
  98. hr = TraceResult(E_NOINTERFACE);
  99. goto exit;
  100. }
  101. exit:
  102. // Cleanup
  103. SafeRelease(pContainer);
  104. // Done
  105. return(hr);
  106. }
  107. // --------------------------------------------------------------------------------
  108. // MimeOleGetWindowsCP
  109. // --------------------------------------------------------------------------------
  110. MIMEOLEAPI MimeOleSetCompatMode(DWORD dwMode)
  111. {
  112. // Add in the bit
  113. FLAGSET(g_dwCompatMode, dwMode);
  114. // Done
  115. return(S_OK);
  116. }
  117. // --------------------------------------------------------------------------------
  118. // MimeOleGetWindowsCP
  119. // --------------------------------------------------------------------------------
  120. CODEPAGEID MimeOleGetWindowsCP(HCHARSET hCharset)
  121. {
  122. // Locals
  123. INETCSETINFO rCharset;
  124. // Invalid Arg
  125. if (NULL == hCharset)
  126. return CP_ACP;
  127. // Loopup charset
  128. Assert(g_pInternat);
  129. if (FAILED(g_pInternat->GetCharsetInfo(hCharset, &rCharset)))
  130. return CP_ACP;
  131. // Return
  132. return MimeOleGetWindowsCPEx(&rCharset);
  133. }
  134. // --------------------------------------------------------------------------------
  135. // MimeOleStripHeaders
  136. // --------------------------------------------------------------------------------
  137. MIMEOLEAPI MimeOleStripHeaders(IMimeMessage *pMessage, HBODY hBody, LPCSTR pszNameDelete,
  138. LPCSTR pszHeaderAdd, IStream **ppStream)
  139. {
  140. // Locals
  141. HRESULT hr=S_OK;
  142. IMimeHeaderTable *pHdrTable=NULL;
  143. LPSTREAM pStmSource=NULL;
  144. LPSTREAM pStmDest=NULL;
  145. HHEADERROW hRow;
  146. HEADERROWINFO Info;
  147. DWORD cbLastRead=0;
  148. FINDHEADER Find={0};
  149. ULARGE_INTEGER uliCopy;
  150. // Trace
  151. TraceCall("MimeOleStripHeaders");
  152. // Invalid Arg
  153. if (NULL == pMessage || NULL == hBody || NULL == pszNameDelete || NULL == ppStream)
  154. return TraceResult(E_INVALIDARG);
  155. // Initialize
  156. *ppStream = NULL;
  157. // Get the message source, no commit
  158. IF_FAILEXIT(hr = pMessage->GetMessageSource(&pStmSource, 0));
  159. // Get the Header Table for hBody
  160. IF_FAILEXIT(hr = pMessage->BindToObject(hBody, IID_IMimeHeaderTable, (LPVOID *)&pHdrTable));
  161. // Initialize the Find
  162. Find.pszHeader = pszNameDelete;
  163. // Find this row
  164. IF_FAILEXIT(hr = pHdrTable->FindFirstRow(&Find, &hRow));
  165. // Create a stream
  166. IF_FAILEXIT(hr = MimeOleCreateVirtualStream(&pStmDest));
  167. // Delete this row
  168. while(1)
  169. {
  170. // Get the row information
  171. IF_FAILEXIT(hr = pHdrTable->GetRowInfo(hRow, &Info));
  172. // Setup uliCopy
  173. uliCopy.QuadPart = Info.cboffStart - cbLastRead;
  174. // Seek
  175. IF_FAILEXIT(hr = HrStreamSeekSet(pStmSource, cbLastRead));
  176. // Write from cbLast to Info.cboffStart
  177. IF_FAILEXIT(hr = HrCopyStreamCB(pStmSource, pStmDest, uliCopy, NULL, NULL));
  178. // Set cbLast
  179. cbLastRead = Info.cboffEnd;
  180. // Find the next
  181. hr = pHdrTable->FindNextRow(&Find, &hRow);
  182. // Failure
  183. if (FAILED(hr))
  184. {
  185. // MIME_E_NOT_FOUND
  186. if (MIME_E_NOT_FOUND == hr)
  187. {
  188. hr = S_OK;
  189. break;
  190. }
  191. else
  192. {
  193. TraceResult(hr);
  194. goto exit;
  195. }
  196. }
  197. }
  198. // Add on pszHeaderAdd
  199. if (pszHeaderAdd)
  200. {
  201. // Write the Add Header
  202. IF_FAILEXIT(hr = pStmDest->Write(pszHeaderAdd, lstrlen(pszHeaderAdd), NULL));
  203. }
  204. // Write the Rest of pStmSource
  205. IF_FAILEXIT(hr = HrStreamSeekSet(pStmSource, cbLastRead));
  206. // Write the Rest
  207. IF_FAILEXIT(hr = HrCopyStream(pStmSource, pStmDest, NULL));
  208. // Commit
  209. IF_FAILEXIT(hr = pStmDest->Commit(STGC_DEFAULT));
  210. // Rewind It
  211. IF_FAILEXIT(hr = HrRewindStream(pStmDest));
  212. // Return pStmDest
  213. *ppStream = pStmDest;
  214. (*ppStream)->AddRef();
  215. exit:
  216. // Cleanup
  217. SafeRelease(pStmSource);
  218. SafeRelease(pHdrTable);
  219. SafeRelease(pStmDest);
  220. // Done
  221. return hr;
  222. }
  223. // --------------------------------------------------------------------------------
  224. // MimeOleGetWindowsCPEx
  225. // --------------------------------------------------------------------------------
  226. CODEPAGEID MimeOleGetWindowsCPEx(LPINETCSETINFO pCharset)
  227. {
  228. // Invalid Arg
  229. if (NULL == pCharset)
  230. return CP_ACP;
  231. // Check for Auto-Detect
  232. if (CP_JAUTODETECT == pCharset->cpiWindows)
  233. return 932;
  234. else if (CP_ISO2022JPESC == pCharset->cpiWindows)
  235. return 932;
  236. else if (CP_ISO2022JPSIO == pCharset->cpiWindows)
  237. return 932;
  238. else if (CP_KAUTODETECT == pCharset->cpiWindows)
  239. return 949;
  240. else
  241. return pCharset->cpiWindows;
  242. }
  243. // --------------------------------------------------------------------------------
  244. // MimeOleClearDirtyTree
  245. // --------------------------------------------------------------------------------
  246. MIMEOLEAPI MimeOleClearDirtyTree(IMimeMessageTree *pITree)
  247. {
  248. // Locals
  249. HRESULT hr=S_OK;
  250. CMessageTree *pTree=NULL;
  251. // Invalid Arg
  252. if (NULL == pITree)
  253. return TrapError(E_INVALIDARG);
  254. // I need a private IID_CMessageTree to do this
  255. CHECKHR(hr = pITree->QueryInterface(IID_CMessageTree, (LPVOID *)&pTree));
  256. // ClearDirty
  257. pTree->ClearDirty();
  258. // Validate
  259. Assert(pTree->IsDirty() == S_FALSE);
  260. exit:
  261. // Cleanup
  262. SafeRelease(pTree);
  263. // Done
  264. return hr;
  265. }
  266. // --------------------------------------------------------------------------------
  267. // PszDefaultSubType
  268. // --------------------------------------------------------------------------------
  269. LPCSTR PszDefaultSubType(LPCSTR pszPriType)
  270. {
  271. if (lstrcmpi(pszPriType, STR_CNT_TEXT) == 0)
  272. return STR_SUB_PLAIN;
  273. else if (lstrcmpi(pszPriType, STR_CNT_MULTIPART) == 0)
  274. return STR_SUB_MIXED;
  275. else
  276. return STR_SUB_OCTETSTREAM;
  277. }
  278. // --------------------------------------------------------------------------------
  279. // MimeOleContentTypeFromUrl
  280. // --------------------------------------------------------------------------------
  281. MIMEOLEAPI MimeOleContentTypeFromUrl(
  282. /* in */ LPCSTR pszBase,
  283. /* in */ LPCSTR pszUrl,
  284. /* out */ LPSTR *ppszCntType)
  285. {
  286. // Locals
  287. HRESULT hr=S_OK;
  288. LPSTR pszFree=NULL;
  289. LPSTR pszCombined=NULL;
  290. LPWSTR pwszUrl=NULL;
  291. LPWSTR pwszCntType=NULL;
  292. // Invalid Arg
  293. if (NULL == pszUrl || NULL == ppszCntType)
  294. return TrapError(E_INVALIDARG);
  295. // Init
  296. *ppszCntType = NULL;
  297. // Combine the URL
  298. if (pszBase)
  299. {
  300. // Allocate Base + URL
  301. DWORD cchSize = (lstrlen(pszUrl) + lstrlen(pszBase) + 1);
  302. CHECKALLOC(pszFree = (LPSTR)g_pMalloc->Alloc(cchSize));
  303. // Format It
  304. wnsprintfA(pszFree, cchSize, "%s%s", pszBase, pszUrl);
  305. // Set combined
  306. pszCombined = pszFree;
  307. // Convert to Unicode
  308. CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszCombined));
  309. }
  310. // To Unicode
  311. else
  312. {
  313. // Set combined
  314. pszCombined = (LPSTR)pszUrl;
  315. // Convert to Unicode
  316. CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszUrl));
  317. }
  318. // Get the Mime Content Type from the Url
  319. CHECKHR(hr = FindMimeFromData(NULL, pwszUrl, NULL, NULL, NULL, 0, &pwszCntType, 0));
  320. // Convert to ANSI
  321. CHECKALLOC(*ppszCntType = PszToANSI(CP_ACP, pwszCntType));
  322. exit:
  323. // Cleanup
  324. SafeMemFree(pszFree);
  325. SafeMemFree(pwszUrl);
  326. SafeMemFree(pwszCntType);
  327. // Done
  328. return hr;
  329. }
  330. // --------------------------------------------------------------------------------
  331. // MimeOleObjectFromMoniker
  332. // --------------------------------------------------------------------------------
  333. MIMEOLEAPI MimeOleObjectFromMoniker(
  334. /* in */ BINDF bindf,
  335. /* in */ IMoniker *pmkOriginal,
  336. /* in */ IBindCtx *pBindCtx,
  337. /* in */ REFIID riid,
  338. /* out */ LPVOID *ppvObject,
  339. /* out */ IMoniker **ppmkNew)
  340. {
  341. Assert(g_pUrlCache);
  342. return TrapError(g_pUrlCache->ActiveObjectFromMoniker(bindf, pmkOriginal, pBindCtx, riid, ppvObject, ppmkNew));
  343. }
  344. // --------------------------------------------------------------------------------
  345. // MimeOleObjectFromUrl
  346. // --------------------------------------------------------------------------------
  347. MIMEOLEAPI MimeOleObjectFromUrl(
  348. /* in */ LPCSTR pszUrl,
  349. /* in */ BOOL fCreate,
  350. /* in */ REFIID riid,
  351. /* out */ LPVOID *ppvObject,
  352. /* out */ IUnknown **ppUnkKeepAlive)
  353. {
  354. Assert(g_pUrlCache);
  355. return TrapError(g_pUrlCache->ActiveObjectFromUrl(pszUrl, fCreate, riid, ppvObject, ppUnkKeepAlive));
  356. }
  357. // --------------------------------------------------------------------------------
  358. // MimeOleCombineMhtmlUrl
  359. // --------------------------------------------------------------------------------
  360. MIMEOLEAPI MimeOleCombineMhtmlUrl(
  361. /* in */ LPSTR pszRootUrl,
  362. /* in */ LPSTR pszBodyUrl,
  363. /* out */ LPSTR *ppszUrl)
  364. {
  365. // Locals
  366. HRESULT hr=S_OK;
  367. ULONG cchPrefix=lstrlen(c_szMHTMLColon);
  368. // Invalid Arg
  369. if (NULL == pszRootUrl || NULL == pszBodyUrl || NULL == ppszUrl)
  370. return TrapError(E_INVALIDARG);
  371. // Init
  372. *ppszUrl = NULL;
  373. // Allocate memory: pszRootUrl + ! + pszBodyUrl
  374. DWORD cchSize = (cchPrefix + lstrlen(pszRootUrl) + lstrlen(pszBodyUrl) + 2);
  375. CHECKALLOC(*ppszUrl = (LPSTR)g_pMalloc->Alloc(cchSize));
  376. // Root must start with mhtml://pszRootUrl!pszBodyUrl
  377. if (StrCmpNI(pszRootUrl, c_szMHTMLColon, cchPrefix) != 0)
  378. wnsprintfA(*ppszUrl, cchSize, "%s%s!%s", c_szMHTMLColon, pszRootUrl, pszBodyUrl);
  379. else
  380. wnsprintfA(*ppszUrl, cchSize, "%s!%s", pszRootUrl, pszBodyUrl);
  381. exit:
  382. // Done
  383. return hr;
  384. }
  385. // --------------------------------------------------------------------------------
  386. // MimeOleSplitMhtmlUrl - Returns E_INVLAIDARG if pszUrl does not start with mhtml:
  387. // --------------------------------------------------------------------------------
  388. MIMEOLEAPI MimeOleParseMhtmlUrl(
  389. /* in */ LPSTR pszUrl,
  390. /* out */ LPSTR *ppszRootUrl,
  391. /* out */ LPSTR *ppszBodyUrl)
  392. {
  393. // Locals
  394. HRESULT hr=S_OK;
  395. CStringParser cString;
  396. CHAR chToken;
  397. ULONG cchUrl;
  398. ULONG cchPrefix=lstrlen(c_szMHTMLColon);
  399. // Invalid Arg
  400. if (NULL == pszUrl)
  401. return TrapError(E_INVALIDARG);
  402. // Init
  403. if (ppszRootUrl)
  404. *ppszRootUrl = NULL;
  405. if (ppszBodyUrl)
  406. *ppszBodyUrl = NULL;
  407. // No an mhtml Url ?
  408. if (StrCmpNI(pszUrl, c_szMHTMLColon, cchPrefix) != 0)
  409. {
  410. hr = E_FAIL;
  411. goto exit;
  412. }
  413. // Get the length
  414. cchUrl = lstrlen(pszUrl);
  415. // Init the Parser
  416. cString.Init(pszUrl + cchPrefix, cchUrl - cchPrefix, PSF_NOFRONTWS | PSF_NOTRAILWS);
  417. // Skip Over any '/'
  418. cString.ChSkip("/");
  419. // Parse
  420. chToken = cString.ChParse("!");
  421. if (0 == cString.CchValue())
  422. {
  423. hr = TrapError(E_FAIL);
  424. goto exit;
  425. }
  426. // Client Wants ppszRootUrl
  427. if (ppszRootUrl)
  428. {
  429. // Allocate length for root part
  430. CHECKALLOC(*ppszRootUrl = (LPSTR)g_pMalloc->Alloc(cString.CchValue() + 1));
  431. // Copy It
  432. CopyMemory((LPBYTE)*ppszRootUrl, (LPBYTE)cString.PszValue(), cString.CchValue() + 1);
  433. }
  434. // Client Wants ppszBodyUrl
  435. if (ppszBodyUrl)
  436. {
  437. // Parse to the end of the string
  438. chToken = cString.ChParse(NULL);
  439. Assert('\0' == chToken);
  440. // Is there data
  441. if (cString.CchValue() > 0)
  442. {
  443. // Allocate length for root part
  444. CHECKALLOC(*ppszBodyUrl = (LPSTR)g_pMalloc->Alloc(cString.CchValue() + 1));
  445. // Copy It
  446. CopyMemory((LPBYTE)*ppszBodyUrl, (LPBYTE)cString.PszValue(), cString.CchValue() + 1);
  447. }
  448. }
  449. exit:
  450. // Failure
  451. if (FAILED(hr))
  452. {
  453. if (ppszRootUrl)
  454. SafeMemFree(*ppszRootUrl);
  455. if (ppszBodyUrl)
  456. SafeMemFree(*ppszBodyUrl);
  457. }
  458. // Done
  459. return hr;
  460. }
  461. // --------------------------------------------------------------------------------
  462. // MimeOleCombineURL
  463. // --------------------------------------------------------------------------------
  464. MIMEOLEAPI MimeOleCombineURL(
  465. /* in */ LPCSTR pszBase,
  466. /* in */ ULONG cchBase,
  467. /* in */ LPCSTR pszURL,
  468. /* in */ ULONG cchURL,
  469. /* in */ BOOL fUnEscape,
  470. /* out */ LPSTR *ppszAbsolute)
  471. {
  472. // Locals
  473. HRESULT hr=S_OK;
  474. LPWSTR pwszBase=NULL;
  475. LPWSTR pwszUrl=NULL;
  476. LPWSTR pwszCombined=NULL;
  477. ULONG cchCombined;
  478. ULONG cchActual;
  479. WCHAR wchCombined[255];
  480. LPSTR pszT;
  481. CStringParser cString;
  482. // Invalid Arg
  483. if (NULL == pszBase || '\0' != pszBase[cchBase] || NULL == pszURL || '\0' != pszURL[cchURL] || NULL == ppszAbsolute)
  484. return TrapError(E_INVALIDARG);
  485. // INit
  486. *ppszAbsolute = NULL;
  487. // Raid-2621: Mail : Can't display images when message is only in HTML and the Content Base is in the headers
  488. pszT = PszSkipWhiteA((LPSTR)pszBase);
  489. if (pszT && '\"' == *pszT)
  490. {
  491. // Init the String
  492. cString.Init(pszBase, cchBase, PSF_NOTRAILWS | PSF_NOFRONTWS | PSF_ESCAPED | PSF_DBCS);
  493. // Remove Quotes
  494. if ('\"' == cString.ChParse("\"") && '\"' == cString.ChParse("\""))
  495. {
  496. // Reset pszBase
  497. pszBase = cString.PszValue();
  498. cchBase = cString.CchValue();
  499. }
  500. }
  501. // Convert to Wide
  502. CHECKALLOC(pwszBase = PszToUnicode(CP_ACP, pszBase));
  503. CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszURL));
  504. // Combine
  505. if (SUCCEEDED(CoInternetCombineUrl(pwszBase, pwszUrl, 0, wchCombined, ARRAYSIZE(wchCombined) - 1, &cchCombined, 0)))
  506. {
  507. // Convert to ANSI
  508. CHECKALLOC(*ppszAbsolute = PszToANSI(CP_ACP, wchCombined));
  509. }
  510. // Otherwise, allocate
  511. else
  512. {
  513. // Allocate
  514. CHECKALLOC(pwszCombined = PszAllocW(cchCombined));
  515. // Combine
  516. CHECKHR(hr = CoInternetCombineUrl(pwszBase, pwszUrl, 0, pwszCombined, cchCombined, &cchActual, 0));
  517. // Valid?
  518. Assert(cchCombined == cchActual);
  519. // Convert to ANSI
  520. CHECKALLOC(*ppszAbsolute = PszToANSI(CP_ACP, pwszCombined));
  521. }
  522. // Unescape
  523. if (fUnEscape)
  524. {
  525. // Do it
  526. CHECKHR(hr = UrlUnescapeA(*ppszAbsolute, NULL, NULL, URL_UNESCAPE_INPLACE));
  527. }
  528. exit:
  529. // Cleanup
  530. SafeMemFree(pwszBase);
  531. SafeMemFree(pwszUrl);
  532. SafeMemFree(pwszCombined);
  533. // Done
  534. return hr;
  535. }
  536. // --------------------------------------------------------------------------------
  537. // MimeOleGetSubjectFileName
  538. // --------------------------------------------------------------------------------
  539. MIMEOLEAPI MimeOleGetSubjectFileName(IMimePropertySet *pPropertySet, ULONG *pulPart, ULONG *pulTotal,
  540. LPSTR pszFileName, ULONG cchMax)
  541. {
  542. return E_FAIL;
  543. #if 0
  544. // Locals
  545. HRESULT hr=S_OK;
  546. PROPVARIANT rSubject;
  547. PARSESTRINGINFO rParse;
  548. PARSESTRINGINFO rTemp;
  549. CHAR szScratch[255],
  550. szFileName[MAX_PATH];
  551. ULONG i,
  552. iString;
  553. BOOL fValid;
  554. // Invalid Arg
  555. if (NULL == pPropertySet || NULL == pszFileName || NULL == pulPart || NULL == pulTotal)
  556. return TrapError(E_INVALIDARG);
  557. // Zero the Structure
  558. ZeroMemory(&rParse, sizeof(PARSESTRINGINFO));
  559. // Init
  560. *pulPart = 0;
  561. *pulTotal = 0;
  562. *pszFileName = '\0';
  563. *szFileName = '\0';
  564. // Init
  565. rSubject.vt = VT_LPSTR;
  566. rSubject.pszVal = NULL;
  567. // Get the subject
  568. CHECKHR(hr = pPropertySet->GetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &rSubject));
  569. // Set the Members
  570. rParse.cpiCodePage = CP_ACP;
  571. rParse.pszString = rSubject.pszVal;
  572. rParse.cchString = lstrlen(rSubject.pszVal);
  573. rParse.pszScratch = szScratch;
  574. rParse.pszValue = szScratch;
  575. rParse.cchValMax = sizeof(szScratch);
  576. rParse.dwFlags = PARSTR_SKIP_FORWARD_WS | PARSTR_STRIP_TRAILING_WS | PARSTR_GROW_VALUE_ALLOWED;
  577. // Initialize My String Parser
  578. MimeOleSetParseTokens(&rParse, " ([");
  579. // Loop for a while
  580. while(1)
  581. {
  582. // Parse up to colon
  583. CHECKHR(hr = MimeOleParseString(&rParse));
  584. // Done
  585. if (rParse.fDone)
  586. break;
  587. // Space, just save the last value
  588. if (' ' == rParse.chToken)
  589. {
  590. // Less than MAX_PATH
  591. if (rParse.cchValue < MAX_PATH)
  592. StrCpyN(szFileName, rParse.pszValue, ARRAYSIZE(szFileName));
  593. }
  594. // Loop Next few characters (001\010)
  595. else
  596. {
  597. // Less than MAX_PATH
  598. if (rParse.cchValue && rParse.cchValue < MAX_PATH)
  599. StrCpyN(szFileName, rParse.pszValue, ARRAYSIZE(szFileName));
  600. // Save the Current State
  601. iString = rParse.iString;
  602. // Find the Ending Token
  603. if ('(' == rParse.chToken)
  604. MimeOleSetParseTokens(&rParse, ")");
  605. else
  606. MimeOleSetParseTokens(&rParse, "]");
  607. // Parse up to colon
  608. CHECKHR(hr = MimeOleParseString(&rParse));
  609. // Done
  610. if (rParse.fDone)
  611. break;
  612. // (000/000) All Numbers in rParse.pszValue are numbers
  613. for (fValid=TRUE, i=0; i<rParse.cchValue; i++)
  614. {
  615. // End of Part Number
  616. if ('/' == rParse.pszValue[i])
  617. {
  618. rParse.pszValue[i] = '\0';
  619. *pulPart = StrToInt(rParse.pszValue);
  620. *pulTotal = StrToInt((rParse.pszValue + i + 1));
  621. }
  622. // Digit
  623. else if (IsDigit(rParse.pszValue) == FALSE)
  624. {
  625. fValid = FALSE;
  626. break;
  627. }
  628. }
  629. // Valid ?
  630. if (fValid)
  631. {
  632. // Dup It
  633. StrCpyN(pszFileName, szFileName, cchMax);
  634. // Done
  635. goto exit;
  636. }
  637. // Reset Parser
  638. rParse.iString = iString;
  639. // Initialize My String Parser
  640. MimeOleSetParseTokens(&rParse, " ([");
  641. }
  642. }
  643. // Not Found
  644. hr = MIME_E_NOT_FOUND;
  645. exit:
  646. // Cleanup
  647. SafeMemFree(rSubject.pszVal);
  648. MimeOleFreeParseString(&rParse);
  649. // Done
  650. return hr;
  651. #endif
  652. }
  653. // --------------------------------------------------------------------------------
  654. // MimeOleCreateWebDocument
  655. // --------------------------------------------------------------------------------
  656. MIMEOLEAPI MimeOleCreateWebDocument(
  657. LPCSTR pszBase,
  658. LPCSTR pszURL,
  659. IMimeWebDocument **ppDocument)
  660. {
  661. // Locals
  662. HRESULT hr=S_OK;
  663. CMimeWebDocument *pDocument=NULL;
  664. // Invalid Arg
  665. if (NULL == pszURL || NULL == ppDocument)
  666. return TrapError(E_INVALIDARG);
  667. // Create a Web Document Object
  668. CHECKALLOC(pDocument = new CMimeWebDocument);
  669. // Initialize It
  670. CHECKHR(hr = pDocument->HrInitialize(pszBase, pszURL));
  671. // Return It
  672. *ppDocument = (IMimeWebDocument *)pDocument;
  673. (*ppDocument)->AddRef();
  674. exit:
  675. // Cleanup
  676. SafeRelease(pDocument);
  677. // Done
  678. return hr;
  679. }
  680. // --------------------------------------------------------------------------------
  681. // MimeOleComputeContentBase
  682. // --------------------------------------------------------------------------------
  683. HRESULT MimeOleComputeContentBase(IMimeMessage *pMessage, HBODY hRelated,
  684. LPSTR *ppszBase, BOOL *pfMultipartBase)
  685. {
  686. // Locals
  687. HRESULT hr=S_OK;
  688. HBODY hBase=NULL;
  689. // Init
  690. if (pfMultipartBase)
  691. *pfMultipartBase = FALSE;
  692. // If no hRelated was passed in, lets try to find one
  693. if (NULL == hRelated)
  694. {
  695. // Find the related section
  696. if (FAILED(MimeOleGetRelatedSection(pMessage, FALSE, &hRelated, NULL)))
  697. {
  698. // Get the root body
  699. pMessage->GetBody(IBL_ROOT, NULL, &hRelated);
  700. }
  701. }
  702. // Get the text/html body
  703. if (FAILED(pMessage->GetTextBody(TXT_HTML, IET_BINARY, NULL, &hBase)))
  704. hBase = hRelated;
  705. // No Base
  706. if (NULL == hBase)
  707. {
  708. hr = E_FAIL;
  709. goto exit;
  710. }
  711. // Call utility function
  712. *ppszBase = MimeOleContentBaseFromBody(pMessage, hBase);
  713. // If that failed and we used the text body
  714. if (NULL == *ppszBase && hRelated && hBase != hRelated)
  715. *ppszBase = MimeOleContentBaseFromBody(pMessage, hRelated);
  716. // Did this come from the multipart related
  717. if (NULL != *ppszBase && hBase == hRelated && pfMultipartBase)
  718. *pfMultipartBase = TRUE;
  719. exit:
  720. // Done
  721. return hr;
  722. }
  723. // --------------------------------------------------------------------------------
  724. // MimeOleContentBaseFromBody
  725. // --------------------------------------------------------------------------------
  726. LPSTR MimeOleContentBaseFromBody(IMimeMessageTree *pTree, HBODY hBody)
  727. {
  728. // Locals
  729. PROPVARIANT rVariant;
  730. // Setup Variant
  731. rVariant.vt = VT_LPSTR;
  732. rVariant.pszVal = NULL;
  733. // Get Content-Base first, and then try Content-Location
  734. if (FAILED(pTree->GetBodyProp(hBody, PIDTOSTR(PID_HDR_CNTBASE), NOFLAGS, &rVariant)))
  735. {
  736. // Try Content-Location
  737. if (FAILED(pTree->GetBodyProp(hBody, PIDTOSTR(PID_HDR_CNTLOC), NOFLAGS, &rVariant)))
  738. rVariant.pszVal = NULL;
  739. }
  740. // Return
  741. return rVariant.pszVal;
  742. }
  743. // --------------------------------------------------------------------------------
  744. // MimeOleGetRelatedSection
  745. // --------------------------------------------------------------------------------
  746. MIMEOLEAPI MimeOleGetRelatedSection(
  747. IMimeMessageTree *pTree,
  748. boolean fCreate,
  749. LPHBODY phRelated,
  750. boolean *pfMultiple)
  751. {
  752. // Locals
  753. HRESULT hr=S_OK;
  754. HBODY hRoot;
  755. FINDBODY rFind;
  756. PROPVARIANT rVariant;
  757. // Invalid Args
  758. if (NULL == pTree || NULL == phRelated)
  759. return TrapError(E_INVALIDARG);
  760. // Init
  761. ZeroMemory(&rFind, sizeof(FINDBODY));
  762. // Find first multipart/related section
  763. rFind.pszPriType = (LPSTR)STR_CNT_MULTIPART;
  764. rFind.pszSubType = (LPSTR)STR_SUB_RELATED;
  765. // Init
  766. if (pfMultiple)
  767. *pfMultiple = FALSE;
  768. // Find First
  769. if (SUCCEEDED(pTree->FindFirst(&rFind, phRelated)))
  770. {
  771. // Is there another multipart/related section
  772. if (pfMultiple && SUCCEEDED(pTree->FindNext(&rFind, &hRoot)))
  773. *pfMultiple = TRUE;
  774. // Done
  775. goto exit;
  776. }
  777. // If no Create, fail
  778. if (FALSE == fCreate)
  779. {
  780. hr = TrapError(MIME_E_NOT_FOUND);
  781. goto exit;
  782. }
  783. // Get the Root Body
  784. CHECKHR(hr = pTree->GetBody(IBL_ROOT, NULL, &hRoot));
  785. // Setup Variant
  786. rVariant.vt = VT_LPSTR;
  787. rVariant.pszVal = (LPSTR)STR_MIME_MPART_RELATED;
  788. // If Root is empty
  789. if (pTree->IsBodyType(hRoot, IBT_EMPTY) == S_OK)
  790. {
  791. // Set the Content Type
  792. CHECKHR(hr = pTree->SetBodyProp(hRoot, PIDTOSTR(PID_HDR_CNTTYPE), 0, &rVariant));
  793. // Set phRelated
  794. *phRelated = hRoot;
  795. }
  796. // If root is non-multipart, convert it to multipart/related
  797. else if (pTree->IsContentType(hRoot, STR_CNT_MULTIPART, NULL) == S_FALSE)
  798. {
  799. // Conver this body to a multipart/related
  800. CHECKHR(hr = pTree->ToMultipart(hRoot, STR_SUB_RELATED, phRelated));
  801. }
  802. // Otherwise, if root is multipart/mixed
  803. else if (pTree->IsContentType(hRoot, NULL, STR_SUB_MIXED) == S_OK)
  804. {
  805. // Insert First Child of multipart/mixed as multipart/related
  806. CHECKHR(hr = pTree->InsertBody(IBL_FIRST, hRoot, phRelated));
  807. // Set the Content Type
  808. CHECKHR(hr = pTree->SetBodyProp(*phRelated, PIDTOSTR(PID_HDR_CNTTYPE), 0, &rVariant));
  809. }
  810. // Otherwise, if root is multipart/alternative
  811. else if (pTree->IsContentType(HBODY_ROOT, NULL, STR_SUB_ALTERNATIVE) == S_OK)
  812. {
  813. // Convert this body to a multipart/related (alternative becomes first child)
  814. CHECKHR(hr = pTree->ToMultipart(HBODY_ROOT, STR_SUB_RELATED, phRelated));
  815. // Should I set multipart/related; start=multipart/alternative at this point ?
  816. }
  817. // Otherwise, for unknown multipart content types
  818. else
  819. {
  820. // Convert this body to a multipart/related
  821. CHECKHR(hr = pTree->ToMultipart(HBODY_ROOT, STR_SUB_RELATED, phRelated));
  822. }
  823. exit:
  824. // Done
  825. return hr;
  826. }
  827. // --------------------------------------------------------------------------------
  828. // MimeOleGetMixedSection
  829. // --------------------------------------------------------------------------------
  830. MIMEOLEAPI MimeOleGetMixedSection(
  831. IMimeMessageTree *pTree,
  832. boolean fCreate,
  833. LPHBODY phMixed,
  834. boolean *pfMultiple)
  835. {
  836. // Locals
  837. HRESULT hr=S_OK;
  838. HBODY hTemp;
  839. HBODY hRoot;
  840. FINDBODY rFind;
  841. PROPVARIANT rVariant;
  842. // Invalid Args
  843. if (NULL == pTree || NULL == phMixed)
  844. return TrapError(E_INVALIDARG);
  845. // Init
  846. ZeroMemory(&rFind, sizeof(FINDBODY));
  847. // Find first multipart/mixed section
  848. rFind.pszPriType = (LPSTR)STR_CNT_MULTIPART;
  849. rFind.pszSubType = (LPSTR)STR_SUB_MIXED;
  850. // Find First
  851. if (SUCCEEDED(pTree->FindFirst(&rFind, phMixed)))
  852. {
  853. // Is there another multipart/mixed section
  854. if (pfMultiple && SUCCEEDED(pTree->FindNext(&rFind, &hTemp)))
  855. *pfMultiple = TRUE;
  856. // Done
  857. goto exit;
  858. }
  859. // Init
  860. if (pfMultiple)
  861. *pfMultiple = FALSE;
  862. // If no Create, fail
  863. if (FALSE == fCreate)
  864. {
  865. hr = TrapError(MIME_E_NOT_FOUND);
  866. goto exit;
  867. }
  868. // Get the Root Body
  869. CHECKHR(hr = pTree->GetBody(IBL_ROOT, NULL, &hRoot));
  870. // If Root is empty
  871. if (pTree->IsBodyType(hRoot, IBT_EMPTY) == S_OK)
  872. {
  873. // Setup Variant
  874. rVariant.vt = VT_LPSTR;
  875. rVariant.pszVal = (LPSTR)STR_MIME_MPART_MIXED;
  876. // Set the Content Type
  877. CHECKHR(hr = pTree->SetBodyProp(hRoot, PIDTOSTR(PID_HDR_CNTTYPE), 0, &rVariant));
  878. // Set phRelated
  879. *phMixed = hRoot;
  880. }
  881. // Otherwise, convert it to a multipart
  882. else
  883. {
  884. // Conver this body to a multipart/mixed
  885. CHECKHR(hr = pTree->ToMultipart(HBODY_ROOT, STR_SUB_MIXED, phMixed));
  886. }
  887. exit:
  888. // Done
  889. return hr;
  890. }
  891. // --------------------------------------------------------------------------------
  892. // MimeOleGetAlternativeSection
  893. // --------------------------------------------------------------------------------
  894. MIMEOLEAPI MimeOleGetAlternativeSection(
  895. IMimeMessageTree *pTree,
  896. LPHBODY phAlternative,
  897. boolean *pfMultiple)
  898. {
  899. // Locals
  900. HRESULT hr=S_OK;
  901. HBODY hTemp;
  902. FINDBODY rFind;
  903. // Invalid Args
  904. if (NULL == pTree || NULL == phAlternative)
  905. return TrapError(E_INVALIDARG);
  906. // Init
  907. ZeroMemory(&rFind, sizeof(FINDBODY));
  908. // Find first multipart/mixed section
  909. rFind.pszPriType = (LPSTR)STR_CNT_MULTIPART;
  910. rFind.pszSubType = (LPSTR)STR_SUB_ALTERNATIVE;
  911. // Find First
  912. if (SUCCEEDED(pTree->FindFirst(&rFind, phAlternative)))
  913. {
  914. // Is there another multipart/mixed section
  915. if (pfMultiple && SUCCEEDED(pTree->FindNext(&rFind, &hTemp)))
  916. *pfMultiple = TRUE;
  917. // Done
  918. goto exit;
  919. }
  920. // Init
  921. if (pfMultiple)
  922. *pfMultiple = FALSE;
  923. // If no Create, fail
  924. hr = TrapError(MIME_E_NOT_FOUND);
  925. exit:
  926. // Done
  927. return hr;
  928. }
  929. // ------------------------------------------------------------------------------------------
  930. // MimeOleGenerateCID
  931. // ------------------------------------------------------------------------------------------
  932. MIMEOLEAPI MimeOleGenerateCID(LPSTR pszCID, ULONG cchMax, boolean fAbsolute)
  933. {
  934. // Locals
  935. HRESULT hr=S_OK;
  936. ULONG cch;
  937. FILETIME ft;
  938. SYSTEMTIME st;
  939. WORD wCounter;
  940. // Invalid Arg
  941. if (NULL == pszCID)
  942. return TrapError(E_INVALIDARG);
  943. // Get Current Time
  944. GetSystemTime(&st);
  945. // Convert to FileTime
  946. SystemTimeToFileTime(&st, &ft);
  947. // Build MessageID
  948. if (FALSE == fAbsolute)
  949. cch = wnsprintfA(pszCID, cchMax, "%04x%08.8lx$%08.8lx$%s@%s", DwCounterNext(), ft.dwHighDateTime, ft.dwLowDateTime, (LPTSTR)SzGetLocalPackedIP(), PszGetDomainName());
  950. else
  951. cch = wnsprintfA(pszCID, cchMax, "CID:%04x%08.8lx$%08.8lx$%s@%s", DwCounterNext(), ft.dwHighDateTime, ft.dwLowDateTime, (LPTSTR)SzGetLocalPackedIP(), PszGetDomainName());
  952. // Buffer Overwrite
  953. Assert(cch + 1 <= CCHMAX_CID);
  954. // Done
  955. return hr;
  956. }
  957. // ------------------------------------------------------------------------------------------
  958. // MimeOleGenerateMID
  959. // ------------------------------------------------------------------------------------------
  960. MIMEOLEAPI MimeOleGenerateMID(LPSTR pszMID, ULONG cchMax, boolean fAbsolute)
  961. {
  962. // Locals
  963. HRESULT hr=S_OK;
  964. ULONG cch;
  965. FILETIME ft;
  966. SYSTEMTIME st;
  967. WORD wCounter;
  968. // Invalid Arg
  969. if (NULL == pszMID || cchMax < CCHMAX_MID)
  970. return TrapError(E_INVALIDARG);
  971. // Get Current Time
  972. GetSystemTime(&st);
  973. // Convert to FileTime
  974. SystemTimeToFileTime(&st, &ft);
  975. // Build MessageID
  976. if (FALSE == fAbsolute)
  977. cch = wnsprintfA(pszMID, cchMax, "<%04x%08.8lx$%08.8lx$%s@%s>", DwCounterNext(), ft.dwHighDateTime, ft.dwLowDateTime, (LPTSTR)SzGetLocalPackedIP(), PszGetDomainName());
  978. else
  979. cch = wnsprintfA(pszMID, cchMax, "MID:%04x%08.8lx$%08.8lx$%s@%s", DwCounterNext(), ft.dwHighDateTime, ft.dwLowDateTime, (LPTSTR)SzGetLocalPackedIP(), PszGetDomainName());
  980. // Buffer Overwrite
  981. Assert(cch + 1 <= CCHMAX_MID);
  982. // Done
  983. return hr;
  984. }
  985. // ------------------------------------------------------------------------------------------
  986. // MimeOleCreateByteStream
  987. // ------------------------------------------------------------------------------------------
  988. MIMEOLEAPI MimeOleCreateByteStream(
  989. IStream **ppStream)
  990. {
  991. // Locals
  992. HRESULT hr=S_OK;
  993. // Invalid Arg
  994. if (NULL == ppStream)
  995. return TrapError(E_INVALIDARG);
  996. // Alocate It
  997. CHECKALLOC((*ppStream) = new CByteStream);
  998. exit:
  999. // Done
  1000. return hr;
  1001. }
  1002. // ------------------------------------------------------------------------------------------
  1003. // MimeOleGetPropertySchema
  1004. // ------------------------------------------------------------------------------------------
  1005. MIMEOLEAPI MimeOleGetPropertySchema(
  1006. IMimePropertySchema **ppSchema)
  1007. {
  1008. // Locals
  1009. HRESULT hr=S_OK;
  1010. // check params
  1011. if (NULL == ppSchema)
  1012. return TrapError(E_INVALIDARG);
  1013. // Out of memory
  1014. if (NULL == g_pSymCache)
  1015. return TrapError(E_OUTOFMEMORY);
  1016. // Create me
  1017. *ppSchema = (IMimePropertySchema *)g_pSymCache;
  1018. // Add Ref
  1019. (*ppSchema)->AddRef();
  1020. // Done
  1021. return S_OK;
  1022. }
  1023. // ------------------------------------------------------------------------------------------
  1024. // MimeOleCreateHeaderTable
  1025. // ------------------------------------------------------------------------------------------
  1026. MIMEOLEAPI MimeOleCreateHeaderTable(IMimeHeaderTable **ppTable)
  1027. {
  1028. // Locals
  1029. HRESULT hr=S_OK;
  1030. LPCONTAINER pContainer=NULL;
  1031. // check params
  1032. if (NULL == ppTable)
  1033. return TrapError(E_INVALIDARG);
  1034. // Create a new Container Object
  1035. CHECKALLOC(pContainer = new CMimePropertyContainer);
  1036. // Init
  1037. CHECKHR(hr = pContainer->InitNew());
  1038. // Bind to Header table
  1039. CHECKHR(hr = pContainer->QueryInterface(IID_IMimeHeaderTable, (LPVOID *)ppTable));
  1040. exit:
  1041. // Failure
  1042. SafeRelease(pContainer);
  1043. // Done
  1044. return hr;
  1045. }
  1046. // ------------------------------------------------------------------------------------------
  1047. // MimeOleCreateVirtualStream
  1048. // ------------------------------------------------------------------------------------------
  1049. MIMEOLEAPI MimeOleCreateVirtualStream(IStream **ppStream)
  1050. {
  1051. // Locals
  1052. HRESULT hr=S_OK;
  1053. // check params
  1054. if (NULL == ppStream)
  1055. return TrapError(E_INVALIDARG);
  1056. // Allocate Virtual Stream
  1057. *ppStream = new CVirtualStream;
  1058. if (NULL == *ppStream)
  1059. {
  1060. hr = TrapError(E_OUTOFMEMORY);
  1061. goto exit;
  1062. }
  1063. exit:
  1064. // Done
  1065. return hr;
  1066. }
  1067. // ------------------------------------------------------------------------------------------
  1068. // MimeOleOpenFileStream
  1069. // ------------------------------------------------------------------------------------------
  1070. MIMEOLEAPI MimeOleOpenFileStream(LPCSTR pszFilePath, DWORD dwCreationDistribution, DWORD dwAccess, IStream **ppstmFile)
  1071. {
  1072. // Invalid Arg
  1073. if (NULL == pszFilePath || NULL == ppstmFile)
  1074. return TrapError(E_INVALIDARG);
  1075. // Call Internal Tool
  1076. return OpenFileStream((LPSTR)pszFilePath, dwCreationDistribution, dwAccess, ppstmFile);
  1077. }
  1078. // ------------------------------------------------------------------------------------------
  1079. // MimeOleIsEnrichedStream, text must start with <x-rich>
  1080. // ------------------------------------------------------------------------------------------
  1081. MIMEOLEAPI MimeOleIsEnrichedStream(IStream *pStream)
  1082. {
  1083. // Locals
  1084. HRESULT hr=S_OK;
  1085. LPSTR pszT;
  1086. BYTE rgbBuffer[30 + 1];
  1087. ULONG cbRead;
  1088. // Invalid Arg
  1089. if (NULL == pStream)
  1090. return TrapError(E_INVALIDARG);
  1091. // Rewind the stream
  1092. CHECKHR(hr = HrRewindStream(pStream));
  1093. // Read the first four bytes
  1094. CHECKHR(hr = pStream->Read(rgbBuffer, sizeof(rgbBuffer) - 1, &cbRead));
  1095. // Less than four bytes read ?
  1096. if (cbRead < (ULONG)lstrlen(c_szXRich))
  1097. {
  1098. hr = S_FALSE;
  1099. goto exit;
  1100. }
  1101. // Stick in a null
  1102. rgbBuffer[cbRead] = '\0';
  1103. // Skip White Space
  1104. pszT = (LPSTR)rgbBuffer;
  1105. // Skip White
  1106. pszT = PszSkipWhiteA(pszT);
  1107. if ('\0' == *pszT)
  1108. {
  1109. hr = S_FALSE;
  1110. goto exit;
  1111. }
  1112. // Compare
  1113. if (StrCmpNI(pszT, c_szXRich, lstrlen(c_szXRich)) != 0)
  1114. {
  1115. hr = S_FALSE;
  1116. goto exit;
  1117. }
  1118. exit:
  1119. // Done
  1120. return hr;
  1121. }
  1122. // ------------------------------------------------------------------------------------------
  1123. // MimeOleIsTnefStream
  1124. // ------------------------------------------------------------------------------------------
  1125. MIMEOLEAPI MimeOleIsTnefStream(IStream *pStream)
  1126. {
  1127. // Locals
  1128. HRESULT hr=S_OK;
  1129. BYTE rgbSignature[4];
  1130. ULONG cbRead;
  1131. // Invalid Arg
  1132. if (NULL == pStream)
  1133. return TrapError(E_INVALIDARG);
  1134. // Read the first four bytes
  1135. CHECKHR(hr = pStream->Read(rgbSignature, sizeof(rgbSignature), &cbRead));
  1136. // Less than four bytes read ?
  1137. if (cbRead < 4)
  1138. {
  1139. hr = S_FALSE;
  1140. goto exit;
  1141. }
  1142. // Compare bytes
  1143. if (rgbSignature[0] != 0x78 && rgbSignature[1] != 0x9f &&
  1144. rgbSignature[2] != 0x3e && rgbSignature[3] != 0x22)
  1145. {
  1146. hr = S_FALSE;
  1147. goto exit;
  1148. }
  1149. // Its TNEF
  1150. hr = S_OK;
  1151. exit:
  1152. // Done
  1153. return hr;
  1154. }
  1155. // --------------------------------------------------------------------------------
  1156. // MimeOleGenerateFileName
  1157. // --------------------------------------------------------------------------------
  1158. MIMEOLEAPI MimeOleGenerateFileName(LPCSTR pszContentType, LPCSTR pszSuggest, LPCSTR pszDefaultExt, LPSTR *ppszFileName)
  1159. {
  1160. // Locals
  1161. HRESULT hr=S_OK;
  1162. LPSTR pszExt=NULL,
  1163. pszName=NULL;
  1164. CHAR szName[10];
  1165. LPCSTR pszExtension=NULL,
  1166. pszPrefix=NULL;
  1167. // Invalid Arg
  1168. if (NULL == ppszFileName)
  1169. return TrapError(E_INVALIDARG);
  1170. // Init
  1171. *ppszFileName = NULL;
  1172. // Find a filename extension
  1173. if (pszContentType)
  1174. {
  1175. // Get the content type...
  1176. if (SUCCEEDED(MimeOleGetContentTypeExt(pszContentType, &pszExt)))
  1177. pszExtension = (LPCSTR)pszExt;
  1178. }
  1179. // Extension is still null
  1180. if (NULL == pszExtension)
  1181. {
  1182. // Use default extension...
  1183. if (pszDefaultExt)
  1184. pszExtension = pszDefaultExt;
  1185. // Otherwise, internal default
  1186. else
  1187. pszExtension = c_szDotDat;
  1188. }
  1189. // We Should have an extension
  1190. Assert(pszExtension);
  1191. // Suggested file name ?
  1192. if (pszSuggest)
  1193. {
  1194. // Dup It
  1195. pszName = PszDupA(pszSuggest);
  1196. if (NULL == pszName)
  1197. {
  1198. hr = TrapError(E_OUTOFMEMORY);
  1199. goto exit;
  1200. }
  1201. // Dupit and remove illegal filename characters...
  1202. CleanupFileNameInPlaceA(CP_ACP, pszName);
  1203. // Set Prefix
  1204. pszPrefix = (LPCSTR)pszName;
  1205. }
  1206. // Otherwise, build a filename...
  1207. else
  1208. {
  1209. // Locals
  1210. CHAR szNumber[30];
  1211. // Get a number...
  1212. wnsprintfA(szNumber, ARRAYSIZE(szNumber), "%05d", DwCounterNext());
  1213. // Allocate pszName
  1214. wnsprintfA(szName, ARRAYSIZE(szName), "ATT%s", szNumber);
  1215. // Set Prefix
  1216. pszPrefix = (LPCSTR)szName;
  1217. }
  1218. // Build Final FileNmae= pszPrefix + pszExtension + dot + null
  1219. DWORD cchSize = (lstrlen(pszPrefix) + lstrlen(pszExtension) + 2);
  1220. *ppszFileName = PszAllocA(cchSize);
  1221. if (NULL == *ppszFileName)
  1222. {
  1223. hr = TrapError(E_OUTOFMEMORY);
  1224. goto exit;
  1225. }
  1226. // Build filename
  1227. wnsprintfA(*ppszFileName, cchSize, "%s%s", pszPrefix, pszExtension);
  1228. exit:
  1229. // Failure
  1230. if (FAILED(hr) && E_OUTOFMEMORY != hr)
  1231. {
  1232. // Assume Success
  1233. hr = S_OK;
  1234. // Use default Attachment name
  1235. *ppszFileName = PszDupA(c_szDefaultAttach);
  1236. // Memory Failure
  1237. if (NULL == *ppszFileName)
  1238. hr = TrapError(E_OUTOFMEMORY);
  1239. }
  1240. // Cleanup
  1241. SafeMemFree(pszExt);
  1242. SafeMemFree(pszName);
  1243. // Done
  1244. return hr;
  1245. }
  1246. // --------------------------------------------------------------------------------
  1247. // MimeOleGenerateFileNameW
  1248. // --------------------------------------------------------------------------------
  1249. MIMEOLEAPI MimeOleGenerateFileNameW(LPCSTR pszContentType, LPCWSTR pszSuggest,
  1250. LPCWSTR pszDefaultExt, LPWSTR *ppszFileName)
  1251. {
  1252. // Locals
  1253. HRESULT hr=S_OK;
  1254. LPSTR pszExtA=NULL;
  1255. LPWSTR pszExtW=NULL;
  1256. LPWSTR pszName=NULL;
  1257. WCHAR szName[10];
  1258. LPWSTR pszExtension=NULL;
  1259. LPWSTR pszPrefix=NULL;
  1260. int cch = 0;
  1261. // Invalid Arg
  1262. if (NULL == ppszFileName)
  1263. return TrapError(E_INVALIDARG);
  1264. // Init
  1265. *ppszFileName = NULL;
  1266. // Find a filename extension
  1267. if (pszContentType)
  1268. {
  1269. // Get the content type...
  1270. if (SUCCEEDED(MimeOleGetContentTypeExt(pszContentType, &pszExtA)))
  1271. {
  1272. // I'm going to convert to unicode because I assume extensions are usascii
  1273. IF_NULLEXIT(pszExtW = PszToUnicode(CP_ACP, pszExtA));
  1274. // Save as the extension
  1275. pszExtension = pszExtW;
  1276. }
  1277. }
  1278. // Extension is still null
  1279. if (NULL == pszExtension)
  1280. {
  1281. // Use default extension...
  1282. if (pszDefaultExt)
  1283. pszExtension = (LPWSTR)pszDefaultExt;
  1284. // Otherwise, internal default
  1285. else
  1286. pszExtension = (LPWSTR)c_wszDotDat;
  1287. }
  1288. // We Should have an extension
  1289. Assert(pszExtension);
  1290. // Suggested file name ?
  1291. if (pszSuggest)
  1292. {
  1293. // Dup It
  1294. IF_NULLEXIT(pszName = PszDupW(pszSuggest));
  1295. // Dupit and remove illegal filename characters...
  1296. CleanupFileNameInPlaceW(pszName);
  1297. // Set Prefix
  1298. pszPrefix = pszName;
  1299. }
  1300. // Otherwise, build a filename...
  1301. else
  1302. {
  1303. // Locals
  1304. WCHAR szNumber[30];
  1305. // Get a number...
  1306. wnsprintfW(szNumber, ARRAYSIZE(szNumber), L"%05d", DwCounterNext());
  1307. // Allocate pszName
  1308. wnsprintfW(szName, ARRAYSIZE(szName), L"ATT%s", szNumber);
  1309. // Set Prefix
  1310. pszPrefix = szName;
  1311. }
  1312. // Build Final FileNmae= pszPrefix + pszExtension + dot + null
  1313. cch = lstrlenW(pszPrefix) + lstrlenW(pszExtension) + 2;
  1314. IF_NULLEXIT(*ppszFileName = PszAllocW(cch));
  1315. // Build filename
  1316. wnsprintfW(*ppszFileName, cch, L"%s%s", pszPrefix, pszExtension);
  1317. exit:
  1318. // Failure
  1319. if (FAILED(hr) && E_OUTOFMEMORY != hr)
  1320. {
  1321. // Assume Success
  1322. hr = S_OK;
  1323. // Use default Attachment name
  1324. *ppszFileName = PszDupW(c_wszDefaultAttach);
  1325. // Memory Failure
  1326. if (NULL == *ppszFileName)
  1327. hr = TrapError(E_OUTOFMEMORY);
  1328. }
  1329. // Cleanup
  1330. SafeMemFree(pszExtA);
  1331. SafeMemFree(pszExtW);
  1332. SafeMemFree(pszName);
  1333. // Done
  1334. return hr;
  1335. }
  1336. // --------------------------------------------------------------------------------
  1337. // CreateMimeSecurity
  1338. // --------------------------------------------------------------------------------
  1339. MIMEOLEAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
  1340. {
  1341. // check params
  1342. if (NULL == ppSecurity)
  1343. return TrapError(E_INVALIDARG);
  1344. // Create the object
  1345. *ppSecurity = (IMimeSecurity *) new CSMime;
  1346. if (NULL == *ppSecurity)
  1347. return TrapError(E_OUTOFMEMORY);
  1348. // Done
  1349. return S_OK;
  1350. }
  1351. // ------------------------------------------------------------------------------------------
  1352. // MimeOleCreateMessageParts
  1353. // ------------------------------------------------------------------------------------------
  1354. MIMEOLEAPI MimeOleCreateMessageParts(IMimeMessageParts **ppParts)
  1355. {
  1356. // Locals
  1357. HRESULT hr=S_OK;
  1358. CMimeMessageParts *pParts=NULL;
  1359. // check params
  1360. if (NULL == ppParts)
  1361. return TrapError(E_INVALIDARG);
  1362. // Init
  1363. *ppParts = NULL;
  1364. // Allocate Message Parts
  1365. pParts = new CMimeMessageParts;
  1366. if (NULL == pParts)
  1367. {
  1368. hr = TrapError(E_OUTOFMEMORY);
  1369. goto exit;
  1370. }
  1371. // Success
  1372. *ppParts = pParts;
  1373. (*ppParts)->AddRef();
  1374. exit:
  1375. // Done
  1376. SafeRelease(pParts);
  1377. // Done
  1378. return hr;
  1379. }
  1380. // ------------------------------------------------------------------------------------------
  1381. // MimeOleGetAllocator
  1382. // ------------------------------------------------------------------------------------------
  1383. MIMEOLEAPI MimeOleGetAllocator(IMimeAllocator **ppMalloc)
  1384. {
  1385. // Locals
  1386. HRESULT hr=S_OK;
  1387. // check params
  1388. if (NULL == ppMalloc)
  1389. return TrapError(E_INVALIDARG);
  1390. // Allocate MimeOleMalloc
  1391. *ppMalloc = new CMimeAllocator;
  1392. if (NULL == *ppMalloc)
  1393. {
  1394. hr = TrapError(E_OUTOFMEMORY);
  1395. goto exit;
  1396. }
  1397. exit:
  1398. // Done
  1399. return hr;
  1400. }
  1401. // ------------------------------------------------------------------------------------------
  1402. // MimeOleCreateMessage
  1403. // ------------------------------------------------------------------------------------------
  1404. MIMEOLEAPI MimeOleCreateHashTable(DWORD dwSize, BOOL fDupeKeys, IHashTable **ppHashTable)
  1405. {
  1406. // Locals
  1407. HRESULT hr=S_OK;
  1408. IHashTable *pHash;
  1409. // check params
  1410. if (NULL == ppHashTable)
  1411. return TrapError(E_INVALIDARG);
  1412. // Init
  1413. *ppHashTable = NULL;
  1414. // Allocate MimeMessage
  1415. CHECKALLOC(pHash = new CHash(NULL));
  1416. // Init New
  1417. CHECKHR(hr = pHash->Init(dwSize, fDupeKeys));
  1418. // Success
  1419. *ppHashTable = pHash;
  1420. (*ppHashTable)->AddRef();
  1421. exit:
  1422. // Done
  1423. SafeRelease(pHash);
  1424. // Done
  1425. return hr;
  1426. }
  1427. // ------------------------------------------------------------------------------------------
  1428. // MimeOleCreateMessage
  1429. // ------------------------------------------------------------------------------------------
  1430. MIMEOLEAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
  1431. {
  1432. // Locals
  1433. HRESULT hr=S_OK;
  1434. LPMESSAGETREE pTree=NULL;
  1435. // check params
  1436. if (NULL == ppMessage)
  1437. return TrapError(E_INVALIDARG);
  1438. // Init
  1439. *ppMessage = NULL;
  1440. // Allocate MimeMessage
  1441. CHECKALLOC(pTree = new CMessageTree(pUnkOuter));
  1442. // Init New
  1443. CHECKHR(hr = pTree->InitNew());
  1444. // Success
  1445. *ppMessage = pTree;
  1446. (*ppMessage)->AddRef();
  1447. exit:
  1448. // Done
  1449. SafeRelease(pTree);
  1450. // Done
  1451. return hr;
  1452. }
  1453. // ------------------------------------------------------------------------------------------
  1454. // MimeOleCreateMessageTree
  1455. // ------------------------------------------------------------------------------------------
  1456. MIMEOLEAPI MimeOleCreateMessageTree(IUnknown *pUnkOuter, IMimeMessageTree **ppMessageTree)
  1457. {
  1458. // Locals
  1459. HRESULT hr=S_OK;
  1460. LPMESSAGETREE pTree=NULL;
  1461. // check params
  1462. if (NULL == ppMessageTree)
  1463. return TrapError(E_INVALIDARG);
  1464. // INit
  1465. *ppMessageTree = NULL;
  1466. // Allocate MimeMessageTree
  1467. CHECKALLOC(pTree = new CMessageTree(pUnkOuter));
  1468. // Init New
  1469. CHECKHR(hr = pTree->InitNew());
  1470. // Success
  1471. *ppMessageTree = pTree;
  1472. (*ppMessageTree)->AddRef();
  1473. exit:
  1474. // Done
  1475. SafeRelease(pTree);
  1476. // Done
  1477. return hr;
  1478. }
  1479. // ------------------------------------------------------------------------------------------
  1480. // MimeOleCreatePropertySet
  1481. // ------------------------------------------------------------------------------------------
  1482. MIMEOLEAPI MimeOleCreatePropertySet(IUnknown *pUnkOuter, IMimePropertySet **ppPropertySet)
  1483. {
  1484. // Locals
  1485. HRESULT hr=S_OK;
  1486. LPMESSAGEBODY pBody=NULL;
  1487. // check params
  1488. if (NULL == ppPropertySet)
  1489. return TrapError(E_INVALIDARG);
  1490. // Init
  1491. *ppPropertySet = NULL;
  1492. // Allocate MimePropertySet
  1493. CHECKALLOC(pBody = new CMessageBody(NULL, pUnkOuter));
  1494. // Init New
  1495. CHECKHR(hr = pBody->InitNew());
  1496. // Success
  1497. *ppPropertySet = (IMimePropertySet *)pBody;
  1498. (*ppPropertySet)->AddRef();
  1499. exit:
  1500. // Done
  1501. SafeRelease(pBody);
  1502. // Done
  1503. return hr;
  1504. }
  1505. // --------------------------------------------------------------------------------
  1506. // MimeOleMergePartialHeaders
  1507. // -------------------------------
  1508. // Rules
  1509. // -----
  1510. // (1) All of the header fields from the initial enclosing entity
  1511. // (part one), except those that start with "Content-" and the
  1512. // specific header fields "Message-ID", "Encrypted", and "MIME-
  1513. // Version", must be copied, in order, to the new message.
  1514. //
  1515. // (2) Only those header fields in the enclosed message which start
  1516. // with "Content-" and "Message-ID", "Encrypted", and "MIME-Version"
  1517. // must be appended, in order, to the header fields of the new
  1518. // message. Any header fields in the enclosed message which do not
  1519. // start with "Content-" (except for "Message-ID", "Encrypted", and
  1520. // "MIME-Version") will be ignored.
  1521. //
  1522. // --------------------------------------------------------------------------------
  1523. MIMEOLEAPI MimeOleMergePartialHeaders(IStream *pstmIn, IStream *pstmOut)
  1524. {
  1525. // Locals
  1526. HRESULT hr = S_OK;
  1527. LPCONTAINER pc1=NULL;
  1528. LPCONTAINER pc2=NULL;
  1529. ULONG i;
  1530. ULONG cboffStart;
  1531. CInternetStream cInternet;
  1532. LONG iColon;
  1533. PROPSTRINGA rHeader;
  1534. PROPVARIANT rOption;
  1535. // check params
  1536. if (NULL == pstmIn || NULL == pstmOut)
  1537. return TrapError(E_INVALIDARG);
  1538. // Create text stream object
  1539. CHECKHR(hr = cInternet.HrInitNew(pstmIn));
  1540. // Create Property Sets
  1541. CHECKALLOC(pc1 = new CMimePropertyContainer);
  1542. CHECKALLOC(pc2 = new CMimePropertyContainer);
  1543. // Init
  1544. CHECKHR(hr = pc1->InitNew());
  1545. CHECKHR(hr = pc2->InitNew());
  1546. // Load the first header
  1547. CHECKHR(hr = pc1->Load(&cInternet));
  1548. // RAID-18376: POPDOG adds extra lines after the header, so I must read the blank lines
  1549. // until I hit the next header, then backup.
  1550. while(1)
  1551. {
  1552. // Get current position
  1553. cboffStart = cInternet.DwGetOffset();
  1554. // Read a line
  1555. CHECKHR(hr = cInternet.HrReadHeaderLine(&rHeader, &iColon));
  1556. // If line is not empty, assume its the start of the next header...
  1557. if ('\0' != *rHeader.pszVal)
  1558. {
  1559. // Line better have a length
  1560. Assert(rHeader.cchVal);
  1561. // Reset position back to cboffStart
  1562. cInternet.Seek(cboffStart);
  1563. // Done
  1564. break;
  1565. }
  1566. }
  1567. // Load the second header
  1568. CHECKHR(hr = pc2->Load(&cInternet));
  1569. // Delete Props From Header 1
  1570. for (i=0; i<ARRAYSIZE(g_rgszPartialPids); i++)
  1571. pc1->DeleteProp(g_rgszPartialPids[i]);
  1572. // Delete Except from header 2
  1573. pc2->DeleteExcept(ARRAYSIZE(g_rgszPartialPids), g_rgszPartialPids);
  1574. // Save as Mime
  1575. rOption.vt = VT_UI4;
  1576. rOption.ulVal = SAVE_RFC1521;
  1577. // Store Some Options
  1578. pc1->SetOption(OID_SAVE_FORMAT, &rOption);
  1579. pc2->SetOption(OID_SAVE_FORMAT, &rOption);
  1580. // Don't default to text/plain if Content-Type is not yet set...
  1581. rOption.vt = VT_BOOL;
  1582. rOption.boolVal = TRUE;
  1583. pc1->SetOption(OID_NO_DEFAULT_CNTTYPE, &rOption);
  1584. pc2->SetOption(OID_NO_DEFAULT_CNTTYPE, &rOption);
  1585. // Save Header 1
  1586. CHECKHR(hr = pc1->Save(pstmOut, TRUE));
  1587. CHECKHR(hr = pc2->Save(pstmOut, TRUE));
  1588. exit:
  1589. // Cleanup
  1590. SafeRelease(pc1);
  1591. SafeRelease(pc2);
  1592. // Done
  1593. return hr;
  1594. }
  1595. // --------------------------------------------------------------------------------
  1596. // MimeOleParseRfc822Address
  1597. // --------------------------------------------------------------------------------
  1598. MIMEOLEAPI MimeOleParseRfc822Address(
  1599. DWORD dwAdrType,
  1600. ENCODINGTYPE ietEncoding,
  1601. LPCSTR pszRfc822Adr,
  1602. LPADDRESSLIST pList)
  1603. {
  1604. // Locals
  1605. CMimePropertyContainer cContainer;
  1606. // Parse the address
  1607. return cContainer.ParseRfc822(dwAdrType, ietEncoding, pszRfc822Adr, pList);
  1608. }
  1609. // --------------------------------------------------------------------------------
  1610. // MimeOleParseRfc822Address
  1611. // --------------------------------------------------------------------------------
  1612. MIMEOLEAPI MimeOleParseRfc822AddressW(
  1613. DWORD dwAdrType,
  1614. LPCWSTR pwszRfc822Adr,
  1615. LPADDRESSLIST pList)
  1616. {
  1617. // Locals
  1618. CMimePropertyContainer cContainer;
  1619. // Parse the address
  1620. return cContainer.ParseRfc822W(dwAdrType, pwszRfc822Adr, pList);
  1621. }
  1622. // --------------------------------------------------------------------------------
  1623. // MimeOleGetInternat
  1624. // --------------------------------------------------------------------------------
  1625. MIMEOLEAPI MimeOleGetInternat(IMimeInternational **ppInternat)
  1626. {
  1627. // check params
  1628. if (NULL == ppInternat)
  1629. return TrapError(E_INVALIDARG);
  1630. // Out of memory
  1631. if (NULL == g_pInternat)
  1632. return TrapError(E_OUTOFMEMORY);
  1633. // Assume Global
  1634. *ppInternat = (IMimeInternational *)g_pInternat;
  1635. // Set database
  1636. (*ppInternat)->AddRef();
  1637. // Done
  1638. return S_OK;
  1639. }
  1640. // --------------------------------------------------------------------------------
  1641. // MimeOleSplitContentType
  1642. // --------------------------------------------------------------------------------
  1643. MIMEOLEAPI MimeOleSplitContentType(LPWSTR pszFull, LPWSTR *ppszCntType, LPWSTR *ppszSubType)
  1644. {
  1645. // Locals
  1646. HRESULT hr = E_FAIL;
  1647. LPWSTR pszFreeMe = NULL,
  1648. psz = NULL,
  1649. pszStart;
  1650. // check params
  1651. if (NULL == pszFull)
  1652. return TrapError(E_INVALIDARG);
  1653. // Lets dup pszFull to make sure we have read access
  1654. psz = pszFreeMe = PszDupW(pszFull);
  1655. if (NULL == psz)
  1656. {
  1657. hr = TrapError(E_OUTOFMEMORY);
  1658. goto exit;
  1659. }
  1660. // Find '/'
  1661. pszStart = psz;
  1662. while(*psz && *psz != L'/')
  1663. psz++;
  1664. // If not found, return
  1665. if (L'\0' == *psz)
  1666. goto exit;
  1667. // Otherwise stuff a null
  1668. *psz = L'\0';
  1669. // Dup
  1670. *ppszCntType = PszDupW(pszStart);
  1671. if (NULL == *ppszCntType)
  1672. {
  1673. hr = TrapError(E_OUTOFMEMORY);
  1674. goto exit;
  1675. }
  1676. // Step over
  1677. *psz = L'/';
  1678. psz++;
  1679. // If not found, return
  1680. if (L'\0' == *psz)
  1681. goto exit;
  1682. // Save position
  1683. pszStart = psz;
  1684. while(*psz && L';' != *psz)
  1685. psz++;
  1686. // Save character...
  1687. *psz = L'\0';
  1688. // Dup as sub type
  1689. *ppszSubType = PszDupW(pszStart);
  1690. if (NULL == *ppszSubType)
  1691. {
  1692. hr = TrapError(E_OUTOFMEMORY);
  1693. goto exit;
  1694. }
  1695. // Success
  1696. hr = S_OK;
  1697. exit:
  1698. // If failed
  1699. if (FAILED(hr))
  1700. {
  1701. SafeMemFree((*ppszCntType));
  1702. SafeMemFree((*ppszSubType));
  1703. }
  1704. // Cleanup
  1705. SafeMemFree(pszFreeMe);
  1706. // Done
  1707. return hr;
  1708. }
  1709. // --------------------------------------------------------------------------------
  1710. // MimeEscapeString - quotes '"' and '\'
  1711. //
  1712. // Returns S_OK if *ppszOut was allocated and set to the escaped string
  1713. // Retruns S_FALSE if *ppszOut is NULL - pszIn did not require escaping
  1714. // --------------------------------------------------------------------------------
  1715. MIMEOLEAPI MimeOleEscapeString(CODEPAGEID cpiCodePage, LPCSTR pszIn, LPSTR *ppszOut)
  1716. {
  1717. // Locals
  1718. HRESULT hr=S_FALSE;
  1719. LPSTR pszOut,
  1720. psz;
  1721. ULONG cb,
  1722. c;
  1723. // check parameters
  1724. if (NULL == pszIn || NULL == ppszOut)
  1725. return TrapError(E_INVALIDARG);
  1726. // $$ INFO $$ This is basically as fast as doing an lstrlen
  1727. // I've decided to first detect if we need to escape
  1728. c = 0;
  1729. cb = 0;
  1730. psz = (LPSTR)pszIn;
  1731. while (*psz)
  1732. {
  1733. // If DBCS Lead-Byte, then skip
  1734. if (IsDBCSLeadByteEx(cpiCodePage, *psz))
  1735. {
  1736. cb += 2;
  1737. psz += 2;
  1738. }
  1739. // Otherwise, text for escaped character
  1740. else
  1741. {
  1742. // Count the number of character to escape
  1743. if ('\"' == *psz || '\\' == *psz || '(' == *psz || ')' == *psz)
  1744. c++;
  1745. // Step one more character
  1746. psz++;
  1747. cb++;
  1748. }
  1749. }
  1750. // No escape needed
  1751. if (0 == c)
  1752. goto exit;
  1753. // Adjust number of bytes to allocate
  1754. cb += (c + 1);
  1755. // worst case - escape every character, so use double original strlen
  1756. CHECKHR(hr = HrAlloc((LPVOID *)ppszOut, cb));
  1757. // Start copy
  1758. psz = (LPSTR)pszIn;
  1759. pszOut = *ppszOut;
  1760. while (*psz)
  1761. {
  1762. // If DBCS Lead-Byte, then skip
  1763. if (IsDBCSLeadByteEx(cpiCodePage, *psz))
  1764. {
  1765. *pszOut++ = *psz++;
  1766. *pszOut++ = *psz++;
  1767. }
  1768. // Otherwise, non-DBCS
  1769. else
  1770. {
  1771. // Do escape
  1772. if ('\"' == *psz || '\\' == *psz || '(' == *psz || ')' == *psz)
  1773. *pszOut++ = '\\';
  1774. // Regular char
  1775. *pszOut++ = *psz++;
  1776. }
  1777. }
  1778. // Null term
  1779. *pszOut = '\0';
  1780. exit:
  1781. // Done
  1782. return hr;
  1783. }
  1784. MIMEOLEAPI MimeOleUnEscapeStringInPlace(LPSTR pszIn)
  1785. {
  1786. HRESULT hr = S_OK;
  1787. ULONG cchOffset = 0;
  1788. ULONG i = 0;
  1789. IF_TRUEEXIT((pszIn == NULL), E_INVALIDARG);
  1790. for(;;i++)
  1791. {
  1792. if((pszIn[i + cchOffset] == '\\') &&
  1793. (pszIn[i + cchOffset + 1] == '\\' ||
  1794. pszIn[i + cchOffset + 1] == '\"' ||
  1795. pszIn[i + cchOffset + 1] == '(' ||
  1796. pszIn[i + cchOffset + 1] == ')'))
  1797. cchOffset++;
  1798. pszIn[i] = pszIn[i + cchOffset];
  1799. if(pszIn[i] == 0)
  1800. break;
  1801. }
  1802. exit:
  1803. return hr;
  1804. }
  1805. // --------------------------------------------------------------------------------
  1806. // MimeEscapeString - quotes '"' and '\'
  1807. //
  1808. // Returns S_OK if *ppszOut was allocated and set to the escaped string
  1809. // Retruns S_FALSE if *ppszOut is NULL - pszIn did not require escaping
  1810. // --------------------------------------------------------------------------------
  1811. MIMEOLEAPI MimeOleEscapeStringW(LPCWSTR pszIn, LPWSTR *ppszOut)
  1812. {
  1813. // Locals
  1814. HRESULT hr=S_FALSE;
  1815. LPWSTR pszOut;
  1816. LPWSTR psz;
  1817. ULONG cch;
  1818. ULONG cchExtra;
  1819. // check parameters
  1820. if (NULL == pszIn || NULL == ppszOut)
  1821. return TrapError(E_INVALIDARG);
  1822. // $$ INFO $$ This is basically as fast as doing an lstrlen
  1823. // I've decided to first detect if we need to escape
  1824. cchExtra = 0;
  1825. cch = 0;
  1826. psz = (LPWSTR)pszIn;
  1827. while (*psz)
  1828. {
  1829. // Count the number of character to escape
  1830. if (L'\"' == *psz || L'\\' == *psz || L'(' == *psz || L')' == *psz)
  1831. cchExtra++;
  1832. // Step one more character
  1833. psz++;
  1834. cch++;
  1835. }
  1836. // No escape needed
  1837. if (0 == cchExtra)
  1838. goto exit;
  1839. // Adjust number of bytes to allocate
  1840. cch += (cchExtra + 1);
  1841. // worst case - escape every character, so use double original strlen
  1842. CHECKHR(hr = HrAlloc((LPVOID *)ppszOut, cch * sizeof(WCHAR)));
  1843. // Start copy
  1844. psz = (LPWSTR)pszIn;
  1845. pszOut = *ppszOut;
  1846. while (*psz)
  1847. {
  1848. // Do escape
  1849. if (L'\"' == *psz || L'\\' == *psz || L'(' == *psz || L')' == *psz)
  1850. *pszOut++ = L'\\';
  1851. // Regular char
  1852. *pszOut++ = *psz++;
  1853. }
  1854. // Null term
  1855. *pszOut = L'\0';
  1856. exit:
  1857. // Done
  1858. return hr;
  1859. }
  1860. // --------------------------------------------------------------------------------
  1861. // MimeOleGetFileExtension
  1862. // --------------------------------------------------------------------------------
  1863. MIMEOLEAPI MimeOleGetFileExtension(LPCSTR pszFilePath, LPSTR pszExt, ULONG cchMax)
  1864. {
  1865. // Locals
  1866. CHAR *pszExtT;
  1867. // Invalid Arg
  1868. if (NULL == pszFilePath || NULL == pszExt || cchMax < _MAX_EXT)
  1869. return TrapError(E_INVALIDARG);
  1870. // Locate the extension of the file
  1871. pszExtT = PathFindExtension(pszFilePath);
  1872. StrCpyN(pszExt, pszExtT, cchMax);
  1873. // Done
  1874. return S_OK;
  1875. }
  1876. // --------------------------------------------------------------------------------
  1877. // MimeOleGetExtClassId
  1878. // --------------------------------------------------------------------------------
  1879. MIMEOLEAPI MimeOleGetExtClassId(LPCSTR pszExtension, LPCLSID pclsid)
  1880. {
  1881. // Locals
  1882. HRESULT hr=S_OK;
  1883. ULONG cb;
  1884. LPSTR pszCLSID=NULL;
  1885. HKEY hkeyExt=NULL;
  1886. HKEY hkeyCLSID=NULL;
  1887. LPSTR pszData=NULL;
  1888. LPWSTR pwszCLSID=NULL;
  1889. // check params
  1890. if (NULL == pszExtension || NULL == pclsid)
  1891. return TrapError(E_INVALIDARG);
  1892. // Otherwise, lets lookup the extension in HKEY_CLASSESS_ROOT
  1893. if (RegOpenKeyEx(HKEY_CLASSES_ROOT, pszExtension, 0, KEY_READ, &hkeyExt) != ERROR_SUCCESS)
  1894. {
  1895. hr = MIME_E_NOT_FOUND;
  1896. goto exit;
  1897. }
  1898. // Query Value
  1899. if (RegQueryValueEx(hkeyExt, NULL, 0, NULL, NULL, &cb) != ERROR_SUCCESS)
  1900. {
  1901. hr = MIME_E_NOT_FOUND;
  1902. goto exit;
  1903. }
  1904. // Allocate Size
  1905. cb += 1;
  1906. CHECKHR(hr = HrAlloc((LPVOID *)&pszData, cb));
  1907. // Get the data
  1908. if (RegQueryValueEx(hkeyExt, NULL, 0, NULL, (LPBYTE)pszData, &cb) != ERROR_SUCCESS)
  1909. {
  1910. hr = TrapError(E_FAIL);
  1911. goto exit;
  1912. }
  1913. // Close this regkey
  1914. RegCloseKey(hkeyExt);
  1915. hkeyExt = NULL;
  1916. // Otherwise, lets lookup the extension in HKEY_CLASSESS_ROOT
  1917. if (RegOpenKeyEx(HKEY_CLASSES_ROOT, pszData, 0, KEY_READ, &hkeyExt) != ERROR_SUCCESS)
  1918. {
  1919. hr = MIME_E_NOT_FOUND;
  1920. goto exit;
  1921. }
  1922. // Otherwise, lets lookup the extension in HKEY_CLASSESS_ROOT
  1923. if (RegOpenKeyEx(hkeyExt, c_szCLSID, 0, KEY_READ, &hkeyCLSID) != ERROR_SUCCESS)
  1924. {
  1925. hr = MIME_E_NOT_FOUND;
  1926. goto exit;
  1927. }
  1928. // Get the data
  1929. if (RegQueryValueEx(hkeyCLSID, NULL, 0, NULL, NULL, &cb) != ERROR_SUCCESS)
  1930. {
  1931. hr = TrapError(E_FAIL);
  1932. goto exit;
  1933. }
  1934. // Add One
  1935. cb += 1;
  1936. CHECKHR(hr = HrAlloc((LPVOID *)&pszCLSID, cb));
  1937. // Get the data
  1938. if (RegQueryValueEx(hkeyCLSID, NULL, 0, NULL, (LPBYTE)pszCLSID, &cb) != ERROR_SUCCESS)
  1939. {
  1940. hr = TrapError(E_FAIL);
  1941. goto exit;
  1942. }
  1943. // ToUnicode
  1944. IF_NULLEXIT(pwszCLSID = PszToUnicode(CP_ACP, pszCLSID));
  1945. // Convert to class id
  1946. CHECKHR(hr = CLSIDFromString(pwszCLSID, pclsid));
  1947. exit:
  1948. // Close Reg Keys
  1949. if (hkeyExt)
  1950. RegCloseKey(hkeyExt);
  1951. if (hkeyCLSID)
  1952. RegCloseKey(hkeyCLSID);
  1953. SafeMemFree(pszData);
  1954. SafeMemFree(pwszCLSID);
  1955. SafeMemFree(pszCLSID);
  1956. // Done
  1957. return hr;
  1958. }
  1959. // --------------------------------------------------------------------------------
  1960. // MimeOleGetExtContentType
  1961. // --------------------------------------------------------------------------------
  1962. MIMEOLEAPI MimeOleGetExtContentType(LPCSTR pszExtension, LPSTR *ppszContentType)
  1963. {
  1964. LPWSTR pwszExt,
  1965. pwszContType = NULL;
  1966. HRESULT hr = S_OK;
  1967. if (NULL == pszExtension || NULL == ppszContentType || '.' != *pszExtension)
  1968. return TrapError(E_INVALIDARG);
  1969. IF_NULLEXIT(pwszExt = PszToUnicode(CP_ACP, pszExtension));
  1970. IF_FAILEXIT(hr = MimeOleGetExtContentTypeW(pwszExt, &pwszContType));
  1971. IF_NULLEXIT(*ppszContentType = PszToANSI(CP_ACP, pwszContType));
  1972. exit:
  1973. MemFree(pwszExt);
  1974. MemFree(pwszContType);
  1975. return hr;
  1976. }
  1977. MIMEOLEAPI MimeOleGetExtContentTypeW(LPCWSTR pszExtension, LPWSTR *ppszContentType)
  1978. {
  1979. // Locals
  1980. HRESULT hr=S_OK;
  1981. ULONG i;
  1982. HKEY hkeyExt=NULL;
  1983. LPWSTR pszFull=NULL;
  1984. ULONG cb;
  1985. // check params
  1986. if (NULL == pszExtension || NULL == ppszContentType || '.' != *pszExtension)
  1987. return TrapError(E_INVALIDARG);
  1988. // Otherwise, lets lookup the extension in HKEY_CLASSESS_ROOT
  1989. if (RegOpenKeyExWrapW(HKEY_CLASSES_ROOT, pszExtension, 0, KEY_READ, &hkeyExt) == ERROR_SUCCESS)
  1990. {
  1991. // Query Value
  1992. if (RegQueryValueExWrapW(hkeyExt, c_szContentTypeW, 0, NULL, NULL, &cb) == ERROR_SUCCESS)
  1993. {
  1994. // Add One
  1995. cb += 1;
  1996. // Allocate Size
  1997. pszFull = PszAllocW(cb);
  1998. if (NULL == pszFull)
  1999. {
  2000. hr = TrapError(E_OUTOFMEMORY);
  2001. goto exit;
  2002. }
  2003. // Get the data
  2004. if (RegQueryValueExWrapW(hkeyExt, c_szContentTypeW, 0, NULL, (LPBYTE)pszFull, &cb) == ERROR_SUCCESS)
  2005. {
  2006. // Set It
  2007. *ppszContentType = pszFull;
  2008. pszFull = NULL;
  2009. goto exit;
  2010. }
  2011. }
  2012. }
  2013. // Not found
  2014. hr = MIME_E_NOT_FOUND;
  2015. exit:
  2016. // Close Reg Keys
  2017. if (hkeyExt)
  2018. RegCloseKey(hkeyExt);
  2019. // Cleanup
  2020. MemFree(pszFull);
  2021. // Done
  2022. return hr;
  2023. }
  2024. // --------------------------------------------------------------------------------
  2025. // MimeOleGetFileInfo
  2026. // --------------------------------------------------------------------------------
  2027. MIMEOLEAPI MimeOleGetFileInfo(
  2028. LPSTR pszFilePath, LPSTR *ppszCntType,
  2029. LPSTR *ppszSubType, LPSTR *ppszCntDesc,
  2030. LPSTR *ppszFileName, LPSTR *ppszExtension)
  2031. {
  2032. HRESULT hr = S_OK;
  2033. LPWSTR pwszFilePath,
  2034. pwszCntType = NULL,
  2035. pwszSubType = NULL,
  2036. pwszCntDesc = NULL,
  2037. pwszFileName = NULL,
  2038. pwszExtension = NULL;
  2039. LPSTR pszCntType = NULL,
  2040. pszSubType = NULL,
  2041. pszCntDesc = NULL,
  2042. pszFileName = NULL,
  2043. pszExtension = NULL;
  2044. // check params
  2045. if (NULL == pszFilePath)
  2046. return TrapError(E_INVALIDARG);
  2047. IF_NULLEXIT(pwszFilePath = PszToUnicode(CP_ACP, pszFilePath));
  2048. // Only pass in parameters for items that
  2049. IF_FAILEXIT(hr = MimeOleGetFileInfoW(pwszFilePath,
  2050. ppszCntType ? &pwszCntType : NULL,
  2051. ppszSubType ? &pwszSubType : NULL,
  2052. ppszCntDesc ? &pwszCntDesc : NULL,
  2053. ppszFileName ? &pwszFileName : NULL,
  2054. ppszExtension ? &pwszExtension : NULL));
  2055. if (ppszCntType)
  2056. {
  2057. Assert(pwszCntType);
  2058. IF_NULLEXIT(pszCntType = PszToANSI(CP_ACP, pwszCntType));
  2059. }
  2060. if (ppszSubType)
  2061. {
  2062. Assert(pwszSubType);
  2063. IF_NULLEXIT(pszSubType = PszToANSI(CP_ACP, pwszSubType));
  2064. }
  2065. if (ppszCntDesc)
  2066. {
  2067. Assert(pwszCntDesc);
  2068. IF_NULLEXIT(pszCntDesc = PszToANSI(CP_ACP, pwszCntDesc));
  2069. }
  2070. if (ppszFileName)
  2071. {
  2072. Assert(pwszFileName);
  2073. IF_NULLEXIT(pszFileName = PszToANSI(CP_ACP, pwszFileName));
  2074. }
  2075. if (ppszExtension)
  2076. {
  2077. Assert(pwszExtension);
  2078. IF_NULLEXIT(pszExtension = PszToANSI(CP_ACP, pwszExtension));
  2079. }
  2080. if (ppszCntType)
  2081. *ppszCntType = pszCntType;
  2082. if (ppszSubType)
  2083. *ppszSubType = pszSubType;
  2084. if (ppszCntDesc)
  2085. *ppszCntDesc = pszCntDesc;
  2086. if (ppszFileName)
  2087. *ppszFileName = pszFileName;
  2088. if (ppszExtension)
  2089. *ppszExtension = pszExtension;
  2090. exit:
  2091. MemFree(pwszCntType);
  2092. MemFree(pwszSubType);
  2093. MemFree(pwszCntDesc);
  2094. MemFree(pwszFileName);
  2095. MemFree(pwszExtension);
  2096. MemFree(pwszFilePath);
  2097. if (FAILED(hr))
  2098. {
  2099. MemFree(pszCntType);
  2100. MemFree(pszSubType);
  2101. MemFree(pszCntDesc);
  2102. MemFree(pszFileName);
  2103. MemFree(pszExtension);
  2104. }
  2105. return hr;
  2106. }
  2107. MIMEOLEAPI MimeOleGetFileInfoW(
  2108. LPWSTR pszFilePath, LPWSTR *ppszCntType,
  2109. LPWSTR *ppszSubType, LPWSTR *ppszCntDesc,
  2110. LPWSTR *ppszFileName, LPWSTR *ppszExtension)
  2111. {
  2112. // Locals
  2113. HRESULT hr=S_OK;
  2114. SHFILEINFOW rShFileInfo;
  2115. LPWSTR pszFull=NULL,
  2116. pszExt,
  2117. pszFname;
  2118. // check params
  2119. if (NULL == pszFilePath)
  2120. return TrapError(E_INVALIDARG);
  2121. // Init
  2122. if (ppszCntType)
  2123. *ppszCntType = NULL;
  2124. if (ppszSubType)
  2125. *ppszSubType = NULL;
  2126. if (ppszCntDesc)
  2127. *ppszCntDesc = NULL;
  2128. if (ppszFileName)
  2129. *ppszFileName = NULL;
  2130. if (ppszExtension)
  2131. *ppszExtension = NULL;
  2132. // Locate the extension of the file
  2133. pszFname = PathFindFileNameW(pszFilePath);
  2134. pszExt = PathFindExtensionW(pszFilePath);
  2135. // Did the user want the actual filename...
  2136. if (ppszFileName)
  2137. {
  2138. // Allocate
  2139. *ppszFileName = PszDupW(pszFname);
  2140. if (NULL == *ppszFileName)
  2141. {
  2142. hr = TrapError(E_OUTOFMEMORY);
  2143. goto exit;
  2144. }
  2145. }
  2146. // Empty extension
  2147. if (FIsEmptyW(pszExt))
  2148. {
  2149. hr = TrapError(E_FAIL);
  2150. goto exit;
  2151. }
  2152. // User wanted the extension
  2153. if (ppszExtension)
  2154. {
  2155. // Allocate
  2156. *ppszExtension = PszDupW(pszExt);
  2157. if (NULL == *ppszExtension)
  2158. {
  2159. hr = TrapError(E_OUTOFMEMORY);
  2160. goto exit;
  2161. }
  2162. }
  2163. // User wanted ppszCntDesc
  2164. if (ppszCntDesc)
  2165. {
  2166. // Lets try to get the extension file information first
  2167. if (SHGetFileInfoWrapW(pszExt, FILE_ATTRIBUTE_NORMAL, &rShFileInfo, sizeof(rShFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_DISPLAYNAME | SHGFI_TYPENAME))
  2168. {
  2169. // Set lppszCntDesc + ( )
  2170. DWORD cchSize = (lstrlenW(rShFileInfo.szDisplayName) + lstrlenW(rShFileInfo.szTypeName) + 5);
  2171. *ppszCntDesc = PszAllocW(cchSize);
  2172. if (NULL == *ppszCntDesc)
  2173. {
  2174. hr = TrapError(E_OUTOFMEMORY);
  2175. goto exit;
  2176. }
  2177. // Format the string
  2178. wnsprintfW(*ppszCntDesc, cchSize, L"%s, (%s)", rShFileInfo.szDisplayName, rShFileInfo.szTypeName);
  2179. }
  2180. }
  2181. // Content type
  2182. if (ppszCntType && ppszSubType)
  2183. {
  2184. // Lookup content type
  2185. if (SUCCEEDED(MimeOleGetExtContentTypeW(pszExt, &pszFull)))
  2186. {
  2187. // Split content type
  2188. CHECKHR(hr = MimeOleSplitContentType(pszFull, ppszCntType, ppszSubType));
  2189. }
  2190. }
  2191. exit:
  2192. // Set defaults if something was not found...
  2193. if (ppszCntType && NULL == *ppszCntType)
  2194. *ppszCntType = PszDupW((LPWSTR)STR_CNT_APPLICATIONW);
  2195. if (ppszSubType && NULL == *ppszSubType)
  2196. *ppszSubType = PszDupW((LPWSTR)STR_SUB_OCTETSTREAMW);
  2197. if (ppszCntDesc && NULL == *ppszCntDesc)
  2198. *ppszCntDesc = PszDupW((LPWSTR)c_szEmptyW);
  2199. // Cleanup
  2200. SafeMemFree(pszFull);
  2201. // Done
  2202. return hr;
  2203. }
  2204. // --------------------------------------------------------------------------------
  2205. // MimeOleGetContentTypeExt
  2206. // --------------------------------------------------------------------------------
  2207. MIMEOLEAPI MimeOleGetContentTypeExt(LPCSTR pszContentType, LPSTR *ppszExtension)
  2208. {
  2209. // Locals
  2210. HRESULT hr=S_OK;
  2211. HKEY hDatabase=NULL;
  2212. HKEY hContentType=NULL;
  2213. ULONG cb;
  2214. // check params
  2215. if (NULL == pszContentType || NULL == ppszExtension)
  2216. return TrapError(E_INVALIDARG);
  2217. // Open Content-Type --> file extension MIME Database registry key
  2218. if (RegOpenKeyEx(HKEY_CLASSES_ROOT, c_szMDBContentType, 0, KEY_READ, &hDatabase) != ERROR_SUCCESS)
  2219. {
  2220. hr = MIME_E_NOT_FOUND;
  2221. goto exit;
  2222. }
  2223. // Open Content Type
  2224. if (RegOpenKeyEx(hDatabase, pszContentType, 0, KEY_READ, &hContentType) != ERROR_SUCCESS)
  2225. {
  2226. hr = MIME_E_NOT_FOUND;
  2227. goto exit;
  2228. }
  2229. // Query for size
  2230. if (RegQueryValueEx(hContentType, c_szExtension, 0, NULL, NULL, &cb) != ERROR_SUCCESS)
  2231. {
  2232. hr = MIME_E_NOT_FOUND;
  2233. goto exit;
  2234. }
  2235. // Allocate It
  2236. *ppszExtension = PszAllocA(cb + 1);
  2237. if (NULL == *ppszExtension)
  2238. {
  2239. hr = TrapError(E_OUTOFMEMORY);
  2240. goto exit;
  2241. }
  2242. // Query for extension
  2243. cb = cb + 1;
  2244. if (RegQueryValueEx(hContentType, c_szExtension, 0, NULL, (LPBYTE)*ppszExtension, &cb) != ERROR_SUCCESS)
  2245. {
  2246. hr = TrapError(E_FAIL);
  2247. goto exit;
  2248. }
  2249. exit:
  2250. // Cleanup
  2251. if (hContentType)
  2252. RegCloseKey(hContentType);
  2253. if (hDatabase)
  2254. RegCloseKey(hDatabase);
  2255. // Done
  2256. return hr;
  2257. }
  2258. // --------------------------------------------------------------------------------
  2259. // MimeOleFindCharset
  2260. // --------------------------------------------------------------------------------
  2261. MIMEOLEAPI MimeOleFindCharset(LPCSTR pszCharset, LPHCHARSET phCharset)
  2262. {
  2263. Assert(g_pInternat);
  2264. return g_pInternat->FindCharset(pszCharset, phCharset);
  2265. }
  2266. // --------------------------------------------------------------------------------
  2267. // MimeOleGetCharsetInfo
  2268. // --------------------------------------------------------------------------------
  2269. MIMEOLEAPI MimeOleGetCharsetInfo(HCHARSET hCharset, LPINETCSETINFO pCsetInfo)
  2270. {
  2271. Assert(g_pInternat);
  2272. return g_pInternat->GetCharsetInfo(hCharset, pCsetInfo);
  2273. }
  2274. // --------------------------------------------------------------------------------
  2275. // MimeOleGetCodePageInfo
  2276. // --------------------------------------------------------------------------------
  2277. MIMEOLEAPI MimeOleGetCodePageInfo(CODEPAGEID cpiCodePage, LPCODEPAGEINFO pCodePageInfo)
  2278. {
  2279. Assert(g_pInternat);
  2280. return g_pInternat->GetCodePageInfo(cpiCodePage, pCodePageInfo);
  2281. }
  2282. // --------------------------------------------------------------------------------
  2283. // MimeOleGetDefaultCharset
  2284. // --------------------------------------------------------------------------------
  2285. MIMEOLEAPI MimeOleGetDefaultCharset(LPHCHARSET phCharset)
  2286. {
  2287. Assert(g_pInternat);
  2288. return g_pInternat->GetDefaultCharset(phCharset);
  2289. }
  2290. // --------------------------------------------------------------------------------
  2291. // MimeOleSetDefaultCharset
  2292. // --------------------------------------------------------------------------------
  2293. MIMEOLEAPI MimeOleSetDefaultCharset(HCHARSET hCharset)
  2294. {
  2295. Assert(g_pInternat);
  2296. return g_pInternat->SetDefaultCharset(hCharset);
  2297. }
  2298. // --------------------------------------------------------------------------------
  2299. // MimeOleGetCodePageCharset
  2300. // --------------------------------------------------------------------------------
  2301. MIMEOLEAPI MimeOleGetCodePageCharset(CODEPAGEID cpiCodePage, CHARSETTYPE ctCsetType, LPHCHARSET phCharset)
  2302. {
  2303. Assert(g_pInternat);
  2304. return g_pInternat->GetCodePageCharset(cpiCodePage, ctCsetType, phCharset);
  2305. }
  2306. // --------------------------------------------------------------------------------
  2307. // MimeOleEncodeHeader
  2308. // --------------------------------------------------------------------------------
  2309. MIMEOLEAPI MimeOleEncodeHeader(
  2310. HCHARSET hCharset,
  2311. LPPROPVARIANT pData,
  2312. LPSTR *ppszEncoded,
  2313. LPRFC1522INFO pRfc1522Info)
  2314. {
  2315. Assert(g_pInternat);
  2316. return g_pInternat->EncodeHeader(hCharset, pData, ppszEncoded, pRfc1522Info);
  2317. }
  2318. // --------------------------------------------------------------------------------
  2319. // MimeOleDecodeHeader
  2320. // --------------------------------------------------------------------------------
  2321. MIMEOLEAPI MimeOleDecodeHeader(
  2322. HCHARSET hCharset,
  2323. LPCSTR pszData,
  2324. LPPROPVARIANT pDecoded,
  2325. LPRFC1522INFO pRfc1522Info)
  2326. {
  2327. Assert(g_pInternat);
  2328. return g_pInternat->DecodeHeader(hCharset, pszData, pDecoded, pRfc1522Info);
  2329. }
  2330. // --------------------------------------------------------------------------------
  2331. // MimeOleVariantFree
  2332. // --------------------------------------------------------------------------------
  2333. MIMEOLEAPI MimeOleVariantFree(LPPROPVARIANT pProp)
  2334. {
  2335. // Locals
  2336. HRESULT hr=S_OK;
  2337. // Invalid Arg
  2338. Assert(pProp);
  2339. // Handle Variant Type...
  2340. switch(pProp->vt)
  2341. {
  2342. case VT_NULL:
  2343. case VT_EMPTY:
  2344. case VT_ILLEGAL:
  2345. case VT_UI1:
  2346. case VT_I2:
  2347. case VT_UI2:
  2348. case VT_I4:
  2349. case VT_UI4:
  2350. case VT_I8:
  2351. case VT_UI8:
  2352. case VT_R4:
  2353. case VT_R8:
  2354. case VT_CY:
  2355. case VT_DATE:
  2356. case VT_BOOL:
  2357. case VT_ERROR:
  2358. case VT_FILETIME:
  2359. break;
  2360. case VT_CF:
  2361. case VT_CLSID:
  2362. case VT_LPWSTR:
  2363. case VT_LPSTR:
  2364. if ((LPVOID)pProp->pszVal != NULL)
  2365. MemFree((LPVOID)pProp->pszVal);
  2366. break;
  2367. case VT_BLOB:
  2368. if (pProp->blob.pBlobData)
  2369. MemFree(pProp->blob.pBlobData);
  2370. break;
  2371. case VT_STREAM:
  2372. if (pProp->pStream)
  2373. pProp->pStream->Release();
  2374. break;
  2375. case VT_STORAGE:
  2376. if (pProp->pStorage)
  2377. pProp->pStorage->Release();
  2378. break;
  2379. default:
  2380. Assert(FALSE);
  2381. hr = TrapError(E_INVALIDARG);
  2382. break;
  2383. }
  2384. // Init
  2385. MimeOleVariantInit(pProp);
  2386. // Done
  2387. return hr;
  2388. }
  2389. // --------------------------------------------------------------------------------
  2390. // MimeOleVariantCopy
  2391. // --------------------------------------------------------------------------------
  2392. MIMEOLEAPI MimeOleVariantCopy(LPPROPVARIANT pDest, LPPROPVARIANT pSource)
  2393. {
  2394. // Locals
  2395. HRESULT hr=S_OK;
  2396. ULONG cb;
  2397. // Invalid Arg
  2398. Assert(pSource && pDest);
  2399. // Handle Variant Type...
  2400. switch(pSource->vt)
  2401. {
  2402. case VT_UI1:
  2403. pDest->bVal = pSource->bVal;
  2404. break;
  2405. case VT_I2:
  2406. pDest->iVal= pSource->iVal;
  2407. break;
  2408. case VT_UI2:
  2409. pDest->uiVal = pSource->uiVal;
  2410. break;
  2411. case VT_I4:
  2412. pDest->lVal = pSource->lVal;
  2413. break;
  2414. case VT_UI4:
  2415. pDest->ulVal = pSource->ulVal;
  2416. break;
  2417. case VT_I8:
  2418. pDest->hVal.QuadPart = pSource->hVal.QuadPart;
  2419. break;
  2420. case VT_UI8:
  2421. pDest->uhVal.QuadPart = pSource->uhVal.QuadPart;
  2422. break;
  2423. case VT_R4:
  2424. pDest->fltVal = pSource->fltVal;
  2425. break;
  2426. case VT_R8:
  2427. pDest->dblVal = pSource->dblVal;
  2428. break;
  2429. case VT_CY:
  2430. CopyMemory(&pDest->cyVal, &pSource->cyVal, sizeof(CY));
  2431. break;
  2432. case VT_DATE:
  2433. pDest->date = pSource->date;
  2434. break;
  2435. case VT_BOOL:
  2436. pDest->boolVal = pSource->boolVal;
  2437. break;
  2438. case VT_ERROR:
  2439. pDest->scode = pSource->scode;
  2440. break;
  2441. case VT_FILETIME:
  2442. CopyMemory(&pDest->filetime, &pSource->filetime, sizeof(FILETIME));
  2443. break;
  2444. case VT_CF:
  2445. // Invalid Arg
  2446. if (NULL == pSource->pclipdata)
  2447. return TrapError(E_INVALIDARG);
  2448. // Duplicate the clipboard format
  2449. CHECKALLOC(pDest->pclipdata = (CLIPDATA *)g_pMalloc->Alloc(sizeof(CLIPDATA)));
  2450. // Copy the data
  2451. CopyMemory(pDest->pclipdata, pSource->pclipdata, sizeof(CLIPDATA));
  2452. break;
  2453. case VT_CLSID:
  2454. // Invalid Arg
  2455. if (NULL == pDest->puuid)
  2456. return TrapError(E_INVALIDARG);
  2457. // Duplicate the CLSID
  2458. CHECKALLOC(pDest->puuid = (CLSID *)g_pMalloc->Alloc(sizeof(CLSID)));
  2459. // Copy
  2460. CopyMemory(pDest->puuid, pSource->puuid, sizeof(CLSID));
  2461. break;
  2462. case VT_LPWSTR:
  2463. // Invalid Arg
  2464. if (NULL == pSource->pwszVal)
  2465. return TrapError(E_INVALIDARG);
  2466. // Get Size
  2467. cb = (lstrlenW(pSource->pwszVal) + 1) * sizeof(WCHAR);
  2468. // Dup the unicode String
  2469. CHECKALLOC(pDest->pwszVal = (LPWSTR)g_pMalloc->Alloc(cb));
  2470. // Copy the data
  2471. CopyMemory(pDest->pwszVal, pSource->pwszVal, cb);
  2472. break;
  2473. case VT_LPSTR:
  2474. // Invalid Arg
  2475. if (NULL == pSource->pszVal)
  2476. return TrapError(E_INVALIDARG);
  2477. // Get Size
  2478. cb = lstrlen(pSource->pszVal) + 1;
  2479. // Dup the unicode String
  2480. CHECKALLOC(pDest->pszVal = (LPSTR)g_pMalloc->Alloc(cb));
  2481. // Copy the data
  2482. CopyMemory(pDest->pszVal, pSource->pszVal, cb);
  2483. break;
  2484. case VT_BLOB:
  2485. // Invalid Arg
  2486. if (NULL == pSource->blob.pBlobData)
  2487. return TrapError(E_INVALIDARG);
  2488. // Duplicate the blob
  2489. CHECKALLOC(pDest->blob.pBlobData = (LPBYTE)g_pMalloc->Alloc(pSource->blob.cbSize));
  2490. // Copy the data
  2491. CopyMemory(pDest->blob.pBlobData, pSource->blob.pBlobData, pSource->blob.cbSize);
  2492. break;
  2493. case VT_STREAM:
  2494. // Invalid Arg
  2495. if (NULL == pSource->pStream)
  2496. return TrapError(E_INVALIDARG);
  2497. // Assume the new stream
  2498. pDest->pStream = pSource->pStream;
  2499. pDest->pStream->AddRef();
  2500. break;
  2501. case VT_STORAGE:
  2502. // Invalid Arg
  2503. if (NULL == pSource->pStorage)
  2504. return TrapError(E_INVALIDARG);
  2505. // Assume the new storage
  2506. pDest->pStorage = pSource->pStorage;
  2507. pDest->pStorage->AddRef();
  2508. break;
  2509. default:
  2510. Assert(FALSE);
  2511. hr = TrapError(E_INVALIDARG);
  2512. goto exit;
  2513. }
  2514. // Success, return vt
  2515. pDest->vt = pSource->vt;
  2516. exit:
  2517. // Done
  2518. return hr;
  2519. }
  2520. // --------------------------------------------------------------------------------
  2521. // MimeOleRecurseSetProp
  2522. // --------------------------------------------------------------------------------
  2523. HRESULT MimeOleRecurseSetProp(IMimeMessageTree *pTree, HBODY hBody, LPCSTR pszName,
  2524. DWORD dwFlags, LPCPROPVARIANT pValue)
  2525. {
  2526. // Locals
  2527. HRESULT hr=S_OK;
  2528. HRESULT hrFind;
  2529. HBODY hChild;
  2530. // Invalid Arg
  2531. Assert(pTree && hBody && pValue);
  2532. // multipart/alternative
  2533. if (pTree->IsContentType(hBody, STR_CNT_MULTIPART, NULL) == S_OK)
  2534. {
  2535. // Get First Child
  2536. hrFind = pTree->GetBody(IBL_FIRST, hBody, &hChild);
  2537. while(SUCCEEDED(hrFind) && hChild)
  2538. {
  2539. // Go down to the child
  2540. CHECKHR(hr = MimeOleRecurseSetProp(pTree, hChild, pszName, dwFlags, pValue));
  2541. // Next Child
  2542. hrFind = pTree->GetBody(IBL_NEXT, hChild, &hChild);
  2543. }
  2544. }
  2545. // Otherwise
  2546. else
  2547. {
  2548. // Go down to the child
  2549. CHECKHR(hr = pTree->SetBodyProp(hBody, pszName, dwFlags, pValue));
  2550. }
  2551. exit:
  2552. // Done
  2553. return hr;
  2554. }
  2555. // --------------------------------------------------------------------------------
  2556. // MimeOleGetPropA
  2557. // --------------------------------------------------------------------------------
  2558. MIMEOLEAPI MimeOleGetPropA(
  2559. IMimePropertySet *pPropertySet,
  2560. LPCSTR pszName,
  2561. DWORD dwFlags,
  2562. LPSTR *ppszData)
  2563. {
  2564. // Locals
  2565. HRESULT hr=S_OK;
  2566. // Invaid Arg
  2567. if (NULL == pPropertySet)
  2568. return TrapError(E_INVALIDARG);
  2569. // Initialzie PropVariant
  2570. PROPVARIANT rVariant;
  2571. rVariant.vt = VT_LPSTR;
  2572. // Call Method
  2573. CHECKHR(hr = pPropertySet->GetProp(pszName, dwFlags, &rVariant));
  2574. // Return the Data
  2575. *ppszData = rVariant.pszVal;
  2576. exit:
  2577. // Done
  2578. return hr;
  2579. }
  2580. // --------------------------------------------------------------------------------
  2581. // MimeOleSetPropA
  2582. // --------------------------------------------------------------------------------
  2583. MIMEOLEAPI MimeOleSetPropA(
  2584. IMimePropertySet *pPropertySet,
  2585. LPCSTR pszName,
  2586. DWORD dwFlags,
  2587. LPCSTR pszData)
  2588. {
  2589. // Invaid Arg
  2590. if (NULL == pPropertySet)
  2591. return TrapError(E_INVALIDARG);
  2592. // Initialzie PropVariant
  2593. PROPVARIANT rVariant;
  2594. rVariant.vt = VT_LPSTR;
  2595. rVariant.pszVal = (LPSTR)pszData;
  2596. // Call Method
  2597. return TrapError(pPropertySet->SetProp(pszName, dwFlags, &rVariant));
  2598. }
  2599. // --------------------------------------------------------------------------------
  2600. // MimeOleGetPropW
  2601. // --------------------------------------------------------------------------------
  2602. MIMEOLEAPI MimeOleGetPropW(
  2603. IMimePropertySet *pPropertySet,
  2604. LPCSTR pszName,
  2605. DWORD dwFlags,
  2606. LPWSTR *ppszData)
  2607. {
  2608. // Locals
  2609. HRESULT hr=S_OK;
  2610. // Invaid Arg
  2611. if (NULL == pPropertySet)
  2612. return TrapError(E_INVALIDARG);
  2613. // Initialzie PropVariant
  2614. PROPVARIANT rVariant;
  2615. rVariant.vt = VT_LPWSTR;
  2616. // Call Method
  2617. CHECKHR(hr = pPropertySet->GetProp(pszName, dwFlags, &rVariant));
  2618. // Return the Data
  2619. *ppszData = rVariant.pwszVal;
  2620. exit:
  2621. // Done
  2622. return hr;
  2623. }
  2624. // --------------------------------------------------------------------------------
  2625. // MimeOleSetPropW
  2626. // --------------------------------------------------------------------------------
  2627. MIMEOLEAPI MimeOleSetPropW(
  2628. IMimePropertySet *pPropertySet,
  2629. LPCSTR pszName,
  2630. DWORD dwFlags,
  2631. LPWSTR pszData)
  2632. {
  2633. // Invaid Arg
  2634. if (NULL == pPropertySet)
  2635. return TrapError(E_INVALIDARG);
  2636. // Initialzie PropVariant
  2637. PROPVARIANT rVariant;
  2638. rVariant.vt = VT_LPWSTR;
  2639. rVariant.pwszVal = (LPWSTR)pszData;
  2640. // Call Method
  2641. return TrapError(pPropertySet->SetProp(pszName, dwFlags, &rVariant));
  2642. }
  2643. // --------------------------------------------------------------------------------
  2644. // MimeOleGetBodyPropA
  2645. // --------------------------------------------------------------------------------
  2646. MIMEOLEAPI MimeOleGetBodyPropA(
  2647. IMimeMessageTree *pTree,
  2648. HBODY hBody,
  2649. LPCSTR pszName,
  2650. DWORD dwFlags,
  2651. LPSTR *ppszData)
  2652. {
  2653. // Locals
  2654. HRESULT hr=S_OK;
  2655. // Invaid Arg
  2656. if (NULL == pTree)
  2657. return TrapError(E_INVALIDARG);
  2658. // Initialzie PropVariant
  2659. PROPVARIANT rVariant;
  2660. rVariant.vt = VT_LPSTR;
  2661. // Call Method
  2662. CHECKHR(hr = pTree->GetBodyProp(hBody, pszName, dwFlags, &rVariant));
  2663. // Return the Data
  2664. *ppszData = rVariant.pszVal;
  2665. exit:
  2666. // Done
  2667. return hr;
  2668. }
  2669. // --------------------------------------------------------------------------------
  2670. // MimeOleSetBodyPropA
  2671. // --------------------------------------------------------------------------------
  2672. MIMEOLEAPI MimeOleSetBodyPropA(
  2673. IMimeMessageTree *pTree,
  2674. HBODY hBody,
  2675. LPCSTR pszName,
  2676. DWORD dwFlags,
  2677. LPCSTR pszData)
  2678. {
  2679. // Invaid Arg
  2680. if (NULL == pTree)
  2681. return TrapError(E_INVALIDARG);
  2682. // Initialzie PropVariant
  2683. PROPVARIANT rVariant;
  2684. rVariant.vt = VT_LPSTR;
  2685. rVariant.pszVal = (LPSTR)pszData;
  2686. // Call Method
  2687. return TrapError(pTree->SetBodyProp(hBody, pszName, dwFlags, &rVariant));
  2688. }
  2689. // --------------------------------------------------------------------------------
  2690. // MimeOleGetBodyPropW
  2691. // --------------------------------------------------------------------------------
  2692. MIMEOLEAPI MimeOleGetBodyPropW(
  2693. IMimeMessageTree *pTree,
  2694. HBODY hBody,
  2695. LPCSTR pszName,
  2696. DWORD dwFlags,
  2697. LPWSTR *ppszData)
  2698. {
  2699. // Locals
  2700. HRESULT hr=S_OK;
  2701. // Invaid Arg
  2702. if (NULL == pTree)
  2703. return TrapError(E_INVALIDARG);
  2704. // Initialzie PropVariant
  2705. PROPVARIANT rVariant;
  2706. rVariant.vt = VT_LPWSTR;
  2707. // Call Method
  2708. CHECKHR(hr = pTree->GetBodyProp(hBody, pszName, dwFlags, &rVariant));
  2709. // Return the Data
  2710. *ppszData = rVariant.pwszVal;
  2711. exit:
  2712. // Done
  2713. return hr;
  2714. }
  2715. // --------------------------------------------------------------------------------
  2716. // MimeOleSetBodyPropW
  2717. // --------------------------------------------------------------------------------
  2718. MIMEOLEAPI MimeOleSetBodyPropW(
  2719. IMimeMessageTree *pTree,
  2720. HBODY hBody,
  2721. LPCSTR pszName,
  2722. DWORD dwFlags,
  2723. LPCWSTR pszData)
  2724. {
  2725. // Invaid Arg
  2726. if (NULL == pTree)
  2727. return TrapError(E_INVALIDARG);
  2728. // Initialzie PropVariant
  2729. PROPVARIANT rVariant;
  2730. rVariant.vt = VT_LPWSTR;
  2731. rVariant.pwszVal = (LPWSTR)pszData;
  2732. // Call Method
  2733. return TrapError(pTree->SetBodyProp(hBody, pszName, dwFlags, &rVariant));
  2734. }
  2735. // --------------------------------------------------------------------------------
  2736. // MimeOleQueryString
  2737. // --------------------------------------------------------------------------------
  2738. MIMEOLEAPI MimeOleQueryString(
  2739. LPCSTR pszSearchMe,
  2740. LPCSTR pszCriteria,
  2741. boolean fSubString,
  2742. boolean fCaseSensitive)
  2743. {
  2744. // Locals
  2745. HRESULT hr=S_OK;
  2746. LPSTR pszDataLower=NULL;
  2747. // Invalid Arg
  2748. Assert(pszSearchMe && pszCriteria);
  2749. // Init
  2750. STACKSTRING_DEFINE(rDataLower, 255);
  2751. // No SubString Search
  2752. if (FALSE == fSubString)
  2753. {
  2754. // Case Sensitive
  2755. if (fCaseSensitive)
  2756. {
  2757. // Equal
  2758. if (lstrcmp(pszSearchMe, pszCriteria) == 0)
  2759. goto exit;
  2760. }
  2761. // Otherwise, Not Case Sensitive
  2762. else if (lstrcmpi(pszSearchMe, pszCriteria) == 0)
  2763. goto exit;
  2764. }
  2765. // Otheriwse, comparing substring
  2766. else
  2767. {
  2768. // Case Sensitive
  2769. if (fCaseSensitive)
  2770. {
  2771. // Equal
  2772. if (StrStr(pszSearchMe, pszCriteria) != NULL)
  2773. goto exit;
  2774. }
  2775. // Otherwise, Not Case Sensitive
  2776. else
  2777. {
  2778. // Get the Length
  2779. ULONG cchSearchMe = lstrlen(pszSearchMe);
  2780. // Set size the stack string
  2781. STACKSTRING_SETSIZE(rDataLower, cchSearchMe + 1);
  2782. // Copy the data
  2783. CopyMemory(rDataLower.pszVal, pszSearchMe, cchSearchMe + 1);
  2784. // Lower Case Compare
  2785. CharLower(rDataLower.pszVal);
  2786. // Compare Strings...
  2787. if (StrStr(rDataLower.pszVal, pszCriteria) != NULL)
  2788. goto exit;
  2789. }
  2790. }
  2791. // No Match
  2792. hr = S_FALSE;
  2793. exit:
  2794. // Cleanup
  2795. STACKSTRING_FREE(rDataLower);
  2796. // Done
  2797. return hr;
  2798. }
  2799. // --------------------------------------------------------------------------------
  2800. // MimeOleQueryStringW
  2801. // --------------------------------------------------------------------------------
  2802. HRESULT MimeOleQueryStringW(LPCWSTR pszSearchMe, LPCWSTR pszCriteria,
  2803. boolean fSubString, boolean fCaseSensitive)
  2804. {
  2805. // Locals
  2806. HRESULT hr=S_OK;
  2807. // Invalid Arg
  2808. Assert(pszSearchMe && pszCriteria);
  2809. // No SubString Search
  2810. if (FALSE == fSubString)
  2811. {
  2812. // Case Sensitive
  2813. if (fCaseSensitive)
  2814. {
  2815. // Equal
  2816. if (StrCmpW(pszSearchMe, pszCriteria) == 0)
  2817. goto exit;
  2818. }
  2819. // Otherwise, Not Case Sensitive
  2820. else if (StrCmpIW(pszSearchMe, pszCriteria) == 0)
  2821. goto exit;
  2822. }
  2823. // Otheriwse, comparing substring
  2824. else
  2825. {
  2826. // Case Sensitive
  2827. if (fCaseSensitive)
  2828. {
  2829. // Equal
  2830. if (StrStrW(pszSearchMe, pszCriteria) != NULL)
  2831. goto exit;
  2832. }
  2833. // Otherwise, Not Case Sensitive
  2834. else if (StrStrIW(pszSearchMe, pszCriteria) != NULL)
  2835. goto exit;
  2836. }
  2837. // No Match
  2838. hr = S_FALSE;
  2839. exit:
  2840. // Done
  2841. return hr;
  2842. }
  2843. #define FILETIME_SECOND 10000000 // 100ns intervals per second
  2844. LONG CertVerifyTimeValidityWithDelta(LPFILETIME pTimeToVerify, PCERT_INFO pCertInfo, ULONG ulOffset) {
  2845. LONG lRet;
  2846. FILETIME ftNow;
  2847. __int64 i64Offset;
  2848. #ifdef WIN32
  2849. union {
  2850. FILETIME ftDelta;
  2851. __int64 i64Delta;
  2852. };
  2853. #else
  2854. // FILETIME ftDelta;
  2855. // __int64 i64Delta;
  2856. //
  2857. // WIN32 specific. I've commented this for WIN32 so that it will produce a compilation
  2858. // error on non Win32 platforms. The following code is specific to i386 since it relies on
  2859. // __int64 being stored low dword first.
  2860. //
  2861. // I would have used right shift by 32 but it is not in iert.lib Maybe you unix and mac folks
  2862. // can get it in there. On the other hand, maybe you won't need to.
  2863. #endif
  2864. lRet = CertVerifyTimeValidity(pTimeToVerify, pCertInfo);
  2865. if (lRet < 0) {
  2866. if (! pTimeToVerify) {
  2867. // Get the current time in filetime format so we can add the offset
  2868. GetSystemTimeAsFileTime(&ftNow);
  2869. pTimeToVerify = &ftNow;
  2870. }
  2871. i64Delta = pTimeToVerify->dwHighDateTime;
  2872. i64Delta = i64Delta << 32;
  2873. i64Delta += pTimeToVerify->dwLowDateTime;
  2874. // Add the offset into the original time to get us a new time to check
  2875. i64Offset = FILETIME_SECOND;
  2876. i64Offset *= ulOffset;
  2877. i64Delta += i64Offset;
  2878. // ftDelta.dwLowDateTime = (ULONG)i64Delta & 0xFFFFFFFF;
  2879. // ftDelta.dwHighDateTime = (ULONG)(i64Delta >> 32);
  2880. lRet = CertVerifyTimeValidity(&ftDelta, pCertInfo);
  2881. }
  2882. return(lRet);
  2883. }
  2884. /* GetCertsFromThumbprints:
  2885. **
  2886. ** Purpose:
  2887. ** Given a set of thumbprints, return an equivalent set of certificates.
  2888. ** Takes:
  2889. ** IN rgThumbprint - array of thumbprints to lookup
  2890. ** INOUT pResults - the hr array contains error info for each cert
  2891. ** lookup. The pCert array has the certs.
  2892. ** cEntries must be set on IN
  2893. ** arrays must be alloc'd on IN
  2894. ** IN rghCertStore - set of stores to search
  2895. ** IN cCertStore - size of rghCertStore
  2896. ** Returns:
  2897. ** MIME_S_SECURITY_ERROROCCURED if any of the lookups fail
  2898. ** (CERTIFICATE_NOT_PRESENT in the cs array for such cases)
  2899. ** MIME_S_SECURITY_NOOP if you call it with 0 in cEntries
  2900. ** E_INVALIDARG if any of the parameters are null
  2901. ** S_OK implies that all certs were found
  2902. ** Note:
  2903. ** only indexes with non-null thumbprints are considered
  2904. */
  2905. MIMEOLEAPI MimeOleGetCertsFromThumbprints(
  2906. THUMBBLOB *const rgThumbprint,
  2907. X509CERTRESULT *const pResults,
  2908. const HCERTSTORE *const rghCertStore,
  2909. const DWORD cCertStore)
  2910. {
  2911. HRESULT hr;
  2912. ULONG iEntry, iStore;
  2913. if (!(rgThumbprint &&
  2914. pResults && pResults->rgpCert && pResults->rgcs &&
  2915. rghCertStore && cCertStore))
  2916. {
  2917. hr = TrapError(E_INVALIDARG);
  2918. goto exit;
  2919. }
  2920. if (0 == pResults->cEntries)
  2921. {
  2922. hr = MIME_S_SECURITY_NOOP;
  2923. goto exit;
  2924. }
  2925. hr = S_OK;
  2926. for (iEntry = 0; iEntry < pResults->cEntries; iEntry++)
  2927. {
  2928. if (rgThumbprint[iEntry].pBlobData)
  2929. {
  2930. for (iStore = 0; iStore < cCertStore; iStore++)
  2931. {
  2932. // We have a thumbprint, so do lookup
  2933. pResults->rgpCert[iEntry] = CertFindCertificateInStore(rghCertStore[iStore],
  2934. X509_ASN_ENCODING,
  2935. 0, //dwFindFlags
  2936. CERT_FIND_HASH,
  2937. (void *)(CRYPT_DIGEST_BLOB *)&(rgThumbprint[iEntry]),
  2938. NULL);
  2939. if (pResults->rgpCert[iEntry])
  2940. {
  2941. break;
  2942. }
  2943. }
  2944. if (!pResults->rgpCert[iEntry])
  2945. {
  2946. DOUTL(1024, "CRYPT: Cert lookup failed. #%d", iEntry);
  2947. pResults->rgcs[iEntry] = CERTIFICATE_NOT_PRESENT;
  2948. hr = MIME_S_SECURITY_ERROROCCURED;
  2949. }
  2950. else
  2951. {
  2952. // Validity check
  2953. if (0 != CertVerifyTimeValidityWithDelta(NULL,
  2954. PCCERT_CONTEXT(pResults->rgpCert[iEntry])->pCertInfo,
  2955. TIME_DELTA_SECONDS))
  2956. {
  2957. pResults->rgcs[iEntry] = CERTIFICATE_EXPIRED;
  2958. }
  2959. else
  2960. {
  2961. pResults->rgcs[iEntry] = CERTIFICATE_OK;
  2962. }
  2963. }
  2964. }
  2965. else
  2966. {
  2967. CRDOUT("For want of a thumbprint... #%d", iEntry);
  2968. pResults->rgpCert[iEntry] = NULL;
  2969. pResults->rgcs[iEntry] = CERTIFICATE_NOPRINT;
  2970. hr = MIME_S_SECURITY_ERROROCCURED;
  2971. }
  2972. }
  2973. exit:
  2974. return hr;
  2975. }
  2976. // --------------------------------------------------------------------------------
  2977. // MimeOleMapSpecialCodePage
  2978. // --------------------------------------------------------------------------------
  2979. HRESULT MimeOleMapSpecialCodePage(CODEPAGEID cpIn, BOOL fRead, CODEPAGEID *pcpOut)
  2980. {
  2981. // Locals
  2982. DWORD i;
  2983. INETCSETINFO CsetInfo;
  2984. // Trace
  2985. TraceCall("MimeOleMapSpecialCodePage");
  2986. // Invalid Args
  2987. if (NULL == pcpOut)
  2988. return(TraceResult(E_INVALIDARG));
  2989. // Initialize
  2990. *pcpOut = cpIn;
  2991. // Walk through the non-standard codepages list
  2992. for (i=0; OENonStdCPs[i].Codepage != 0; i++)
  2993. {
  2994. // Is this it?
  2995. if (OENonStdCPs[i].Codepage == cpIn)
  2996. {
  2997. // Read ?
  2998. if (fRead && OENonStdCPs[i].cpRead)
  2999. *pcpOut = OENonStdCPs[i].cpRead;
  3000. // Send ?
  3001. else if (OENonStdCPs[i].cpSend)
  3002. *pcpOut = OENonStdCPs[i].cpSend;
  3003. // Done
  3004. break;
  3005. }
  3006. }
  3007. // Done
  3008. return(S_OK);
  3009. }
  3010. // --------------------------------------------------------------------------------
  3011. // MimeOleMapCodePageToCharset
  3012. // --------------------------------------------------------------------------------
  3013. HRESULT MimeOleMapCodePageToCharset(CODEPAGEID cpIn, LPHCHARSET phCharset)
  3014. {
  3015. // Locals
  3016. HRESULT hr=S_OK;
  3017. LPSTR pszCharset;
  3018. CODEPAGEINFO CodePage;
  3019. // Trace
  3020. TraceCall("MimeOleMapCodePageToCharset");
  3021. // Invalid Args
  3022. if (NULL == phCharset)
  3023. return(TraceResult(E_INVALIDARG));
  3024. // Get codepage info
  3025. IF_FAILEXIT(hr = MimeOleGetCodePageInfo(cpIn, &CodePage));
  3026. // Default to using the body charset
  3027. pszCharset = CodePage.szBodyCset;
  3028. // Use WebCharset if body charset starts with '_' and the codepage is not 949
  3029. if (*CodePage.szBodyCset != '_' && 949 != CodePage.cpiCodePage)
  3030. pszCharset = CodePage.szWebCset;
  3031. // Find the Charset
  3032. IF_FAILEXIT(hr = MimeOleFindCharset(pszCharset, phCharset));
  3033. exit:
  3034. // Done
  3035. return(hr);
  3036. }
  3037. // --------------------------------------------------------------------------------
  3038. // MimeOleSplitMessage
  3039. // --------------------------------------------------------------------------------
  3040. MIMEOLEAPI MimeOleSplitMessage(IMimeMessage *pMessage, ULONG cbMaxPart, IMimeMessageParts **ppParts)
  3041. {
  3042. // Locals
  3043. HRESULT hr=S_OK;
  3044. ULONG cbMessage,
  3045. cbHeader,
  3046. cParts,
  3047. iPart,
  3048. cbActual,
  3049. cbRead=0,
  3050. cAttach,
  3051. i,
  3052. cbSubjectAddOn,
  3053. cbSubjectNew;
  3054. LPHBODY prghAttach=NULL;
  3055. IStream *pstmMsg=NULL,
  3056. *pstmPart=NULL;
  3057. ULARGE_INTEGER ulicbHeader;
  3058. IMimePropertySet *pRootProps=NULL;
  3059. CMimeMessageParts *pParts=NULL;
  3060. IMimeMessage *pmsgPart=NULL;
  3061. FILETIME ft;
  3062. SYSTEMTIME st;
  3063. CHAR szMimeId[CCHMAX_MID],
  3064. szNumber[30],
  3065. szFormat[50];
  3066. MIMESAVETYPE savetype;
  3067. BODYOFFSETS rOffsets;
  3068. IMimeBody *pRootBody=NULL;
  3069. LPSTR pszSubjectAddOn=NULL,
  3070. pszSubjectNew=NULL;
  3071. PROPVARIANT rVariant,
  3072. rSubject,
  3073. rFileName;
  3074. float dParts;
  3075. HCHARSET hCharset=NULL;
  3076. INETCSETINFO CsetInfo;
  3077. // Invalid Arg
  3078. if (NULL == ppParts)
  3079. return TrapError(E_INVALIDARG);
  3080. // Initialize Variants
  3081. MimeOleVariantInit(&rSubject);
  3082. MimeOleVariantInit(&rFileName);
  3083. // Init
  3084. *ppParts = NULL;
  3085. // Get Option
  3086. rVariant.vt = VT_UI4;
  3087. pMessage->GetOption(OID_SAVE_FORMAT, &rVariant);
  3088. savetype = (MIMESAVETYPE)rVariant.ulVal;
  3089. // Raid-73119: OE : Kor: the charset for the message sent in broken apart is shown as "_autodetect_kr"
  3090. if (SUCCEEDED(pMessage->GetCharset(&hCharset)))
  3091. {
  3092. // Get the charset info for the HCHARSET
  3093. if (SUCCEEDED(MimeOleGetCharsetInfo(hCharset, &CsetInfo)))
  3094. {
  3095. // Map the codepage
  3096. CODEPAGEID cpActual;
  3097. // Map the codepage to the correct codepage..
  3098. if (SUCCEEDED(MimeOleMapSpecialCodePage(CsetInfo.cpiInternet, FALSE, &cpActual)))
  3099. {
  3100. // If Different
  3101. if (cpActual != CsetInfo.cpiInternet)
  3102. {
  3103. // Map the codepage to a character set
  3104. MimeOleMapCodePageToCharset(cpActual, &hCharset);
  3105. // Reset the character set....
  3106. SideAssert(SUCCEEDED(pMessage->SetCharset(hCharset, CSET_APPLY_TAG_ALL)));
  3107. }
  3108. }
  3109. }
  3110. }
  3111. // Get Message Source
  3112. CHECKHR(hr = pMessage->GetMessageSource(&pstmMsg, COMMIT_ONLYIFDIRTY));
  3113. // Create Parts Object
  3114. CHECKALLOC(pParts = new CMimeMessageParts);
  3115. // Rewind the stream
  3116. CHECKHR(hr = HrRewindStream(pstmMsg));
  3117. // Get Stream Size
  3118. CHECKHR(hr = HrSafeGetStreamSize(pstmMsg, &cbMessage));
  3119. // Is this size larger than the max part size
  3120. if (cbMessage <= cbMaxPart)
  3121. {
  3122. // Add Single Parts to parts object
  3123. CHECKHR(hr = pParts->AddPart(pMessage));
  3124. // Done
  3125. goto exit;
  3126. }
  3127. // Get the root body
  3128. CHECKHR(hr = pMessage->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *)&pRootBody));
  3129. // Get Root body offset info
  3130. CHECKHR(hr = pRootBody->GetOffsets(&rOffsets));
  3131. // If the header is bigger than the max message size, we have a problem
  3132. cbHeader = (ULONG)rOffsets.cbBodyStart - rOffsets.cbHeaderStart;
  3133. if (cbHeader >= cbMessage || cbHeader + 256 >= cbMaxPart)
  3134. {
  3135. AssertSz(FALSE, "SplitMessage: The header is bigger than the max message size");
  3136. hr = TrapError(MIME_E_MAX_SIZE_TOO_SMALL);
  3137. goto exit;
  3138. }
  3139. // Get a copy of the root header
  3140. CHECKHR(hr = pRootBody->Clone(&pRootProps));
  3141. // Lets cleanup this header...
  3142. pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTTYPE));
  3143. pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTDISP));
  3144. pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTDESC));
  3145. pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTID));
  3146. pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTLOC));
  3147. pRootProps->DeleteProp(PIDTOSTR(PID_HDR_MIMEVER));
  3148. pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTXFER));
  3149. pRootProps->DeleteProp("Disposition-Notification-To");
  3150. pRootProps->DeleteProp(PIDTOSTR(PID_HDR_MESSAGEID));
  3151. // Compute the number of parts as a float
  3152. dParts = (float)((float)cbMessage / (float)(cbMaxPart - cbHeader));
  3153. // If dParts is not an integer, round up.
  3154. cParts = (dParts - ((ULONG)dParts)) ? ((ULONG)dParts) + 1 : ((ULONG)dParts);
  3155. // Set Max Parts in parts object
  3156. CHECKHR(hr = pParts->SetMaxParts(cParts));
  3157. // If MIME, create id
  3158. if (SAVE_RFC1521 == savetype)
  3159. {
  3160. // Create Mime Id
  3161. GetSystemTime(&st);
  3162. SystemTimeToFileTime(&st, &ft);
  3163. wnsprintfA(szMimeId, ARRAYSIZE(szMimeId), "%08.8lX.%08.8lX@%s", ft.dwHighDateTime, ft.dwLowDateTime, (LPSTR)SzGetLocalHostName());
  3164. // total=X
  3165. wnsprintfA(szNumber, ARRAYSIZE(szNumber), "%d", cParts);
  3166. // number=x
  3167. rVariant.vt = VT_LPSTR;
  3168. rVariant.pszVal = szNumber;
  3169. CHECKHR(hr = pRootProps->SetProp(STR_PAR_TOTAL, 0, &rVariant));
  3170. // id=XXXX
  3171. rVariant.pszVal = szMimeId;
  3172. CHECKHR(hr = pRootProps->SetProp(STR_PAR_ID, 0, &rVariant));
  3173. // MIME Version
  3174. rVariant.pszVal = (LPSTR)c_szMimeVersion;
  3175. CHECKHR(hr = pRootProps->SetProp(PIDTOSTR(PID_HDR_MIMEVER), 0, &rVariant));
  3176. }
  3177. // Otherwise, seek pstmMsg to end of header
  3178. else
  3179. {
  3180. // Get Stream Position
  3181. CHECKHR(hr = HrStreamSeekSet(pstmMsg, rOffsets.cbBodyStart));
  3182. // Reduce the message size
  3183. cbMessage -= rOffsets.cbBodyStart;
  3184. }
  3185. // Init the variant
  3186. rSubject.vt = VT_LPSTR;
  3187. // Get Subject
  3188. if (FAILED(pRootBody->GetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &rSubject)))
  3189. rSubject.pszVal = NULL;
  3190. // Enumerate bodies and get the first file name and use it in the new subject...
  3191. if (SUCCEEDED(pMessage->GetAttachments(&cAttach, &prghAttach)))
  3192. {
  3193. // Init the variant
  3194. rFileName.vt = VT_LPSTR;
  3195. // Loop Attached
  3196. for (i=0; i<cAttach; i++)
  3197. {
  3198. // Get File Name...
  3199. if (SUCCEEDED(pMessage->GetBodyProp(prghAttach[i], PIDTOSTR(PID_ATT_FILENAME), 0, &rFileName)))
  3200. break;
  3201. }
  3202. }
  3203. // Format Number
  3204. wnsprintfA(szNumber, ARRAYSIZE(szNumber), "%d", cParts);
  3205. // Have a file name
  3206. if (rFileName.pszVal)
  3207. {
  3208. // Make Format String...
  3209. wnsprintfA(szFormat, ARRAYSIZE(szFormat), "%%s [%%0%dd/%d]", lstrlen(szNumber), cParts);
  3210. // Size of subject add on string
  3211. cbSubjectAddOn = lstrlen(rFileName.pszVal) + lstrlen(szFormat) + lstrlen(szNumber) + 1;
  3212. }
  3213. // Otherwise, no filename
  3214. else
  3215. {
  3216. // Make Format String...
  3217. wnsprintfA(szFormat, ARRAYSIZE(szFormat), "[%%0%dd/%d]", lstrlen(szNumber), cParts);
  3218. // Size of subject add on string
  3219. cbSubjectAddOn = lstrlen(szFormat) + lstrlen(szNumber) + 1;
  3220. }
  3221. // Allocate Subject Add On
  3222. DWORD cchSize = (cbSubjectAddOn / sizeof(pszSubjectAddOn[0]));
  3223. CHECKALLOC(pszSubjectAddOn = PszAllocA(cchSize));
  3224. // Allocate new subject
  3225. if (rSubject.pszVal)
  3226. cbSubjectNew = cbSubjectAddOn + lstrlen(rSubject.pszVal) + 5;
  3227. else
  3228. cbSubjectNew = cbSubjectAddOn + 5;
  3229. // Allocate Subject New
  3230. CHECKALLOC(pszSubjectNew = PszAllocA(cbSubjectNew));
  3231. // Loop throught the number of parts
  3232. for (iPart=0; iPart<cParts; iPart++)
  3233. {
  3234. // Create a new stream...
  3235. CHECKHR(hr = CreateTempFileStream(&pstmPart));
  3236. // If MIME, I can do the partial stuff for them
  3237. if (SAVE_RFC1521 == savetype)
  3238. {
  3239. // Content-Type: message/partial; number=X; total=X; id=XXXXXX
  3240. rVariant.vt = VT_LPSTR;
  3241. rVariant.pszVal = (LPSTR)STR_MIME_MSG_PART;
  3242. CHECKHR(hr = pRootProps->SetProp(PIDTOSTR(PID_HDR_CNTTYPE), 0, &rVariant));
  3243. // number=X
  3244. wnsprintfA(szNumber, ARRAYSIZE(szNumber), "%d", iPart+1);
  3245. rVariant.pszVal = szNumber;
  3246. CHECKHR(hr = pRootProps->SetProp(STR_PAR_NUMBER, 0, &rVariant));
  3247. }
  3248. // Build Subject AddOn
  3249. if (rFileName.pszVal)
  3250. wnsprintfA(pszSubjectAddOn, cchSize, szFormat, rFileName.pszVal, iPart + 1);
  3251. else
  3252. wnsprintfA(pszSubjectAddOn, cchSize, szFormat, iPart + 1);
  3253. // Build New Subject
  3254. if (rSubject.pszVal)
  3255. wnsprintfA(pszSubjectNew, cbSubjectNew, "%s %s", rSubject.pszVal, pszSubjectAddOn);
  3256. else
  3257. wnsprintfA(pszSubjectNew, cbSubjectNew, "%s", pszSubjectAddOn);
  3258. // Set New Subject
  3259. rVariant.vt = VT_LPSTR;
  3260. rVariant.pszVal = pszSubjectNew;
  3261. CHECKHR(hr = pRootProps->SetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &rVariant));
  3262. // Save Root Header
  3263. CHECKHR(hr = pRootProps->Save(pstmPart, TRUE));
  3264. // Emit Line Break
  3265. CHECKHR(hr = pstmPart->Write(c_szCRLF, lstrlen(c_szCRLF), NULL));
  3266. // Copy bytes from lpstmMsg to pstmPart
  3267. CHECKHR(hr = HrCopyStreamCBEndOnCRLF(pstmMsg, pstmPart, cbMaxPart - cbHeader, &cbActual));
  3268. // Increment read
  3269. cbRead += cbActual;
  3270. // If cbActual is less than cbMaxMsgSize-cbHeader, better be the last part
  3271. #ifdef DEBUG
  3272. if (iPart + 1 < cParts && cbActual < (cbMaxPart - cbHeader))
  3273. AssertSz (FALSE, "One more partial message is going to be produced than needed. This should be harmless.");
  3274. #endif
  3275. // Commit pstmPart
  3276. CHECKHR(hr = pstmPart->Commit(STGC_DEFAULT));
  3277. // Rewind it
  3278. CHECKHR(hr = HrRewindStream(pstmPart));
  3279. // Create Message Part...
  3280. CHECKHR(hr = MimeOleCreateMessage(NULL, &pmsgPart));
  3281. // Make the message build itself
  3282. CHECKHR (hr = pmsgPart->Load(pstmPart));
  3283. // We need another message and stream
  3284. CHECKHR (hr = pParts->AddPart(pmsgPart));
  3285. // Cleanup
  3286. SafeRelease(pmsgPart);
  3287. SafeRelease(pstmPart);
  3288. }
  3289. // Lets hope we read everything...
  3290. AssertSz(cbRead == cbMessage, "Please let sbailey know if these fails.");
  3291. exit:
  3292. // Succeeded
  3293. if (SUCCEEDED(hr))
  3294. {
  3295. // Returns Parts Object
  3296. (*ppParts) = pParts;
  3297. (*ppParts)->AddRef();
  3298. }
  3299. // Cleanup
  3300. SafeRelease(pRootBody);
  3301. SafeRelease(pstmMsg);
  3302. SafeRelease(pParts);
  3303. SafeRelease(pRootProps);
  3304. SafeRelease(pmsgPart);
  3305. SafeRelease(pstmPart);
  3306. SafeMemFree(pszSubjectAddOn);
  3307. SafeMemFree(pszSubjectNew);
  3308. SafeMemFree(prghAttach);
  3309. MimeOleVariantFree(&rSubject);
  3310. MimeOleVariantFree(&rFileName);
  3311. // Done
  3312. return hr;
  3313. }
  3314. // --------------------------------------------------------------------------------
  3315. // CompareBlob
  3316. // --------------------------------------------------------------------------------
  3317. int CompareBlob(LPCBLOB pBlob1, LPCBLOB pBlob2)
  3318. {
  3319. // Locals
  3320. register int ret = 0;
  3321. Assert(pBlob1 && pBlob2);
  3322. if (pBlob1->cbSize != pBlob2->cbSize)
  3323. ret = pBlob1->cbSize - pBlob2->cbSize;
  3324. else
  3325. ret = memcmp(pBlob1->pBlobData, pBlob2->pBlobData, pBlob2->cbSize);
  3326. return ret;
  3327. }
  3328. // --------------------------------------------------------------------------------
  3329. // HrCopyBlob
  3330. // --------------------------------------------------------------------------------
  3331. HRESULT HrCopyBlob(LPCBLOB pIn, LPBLOB pOut)
  3332. {
  3333. // Locals
  3334. HRESULT hr;
  3335. ULONG cb = 0;
  3336. Assert(pIn && pOut);
  3337. if (pIn->cbSize == 0)
  3338. {
  3339. pOut->cbSize = 0;
  3340. pOut->pBlobData = NULL;
  3341. return S_OK;
  3342. }
  3343. // Dup It...
  3344. cb = pIn->cbSize;
  3345. #ifdef _WIN64
  3346. cb = LcbAlignLcb(cb);
  3347. #endif //_WIN64
  3348. if (SUCCEEDED(hr = HrAlloc((LPVOID *)&pOut->pBlobData, cb)))
  3349. {
  3350. // Copy Memory
  3351. CopyMemory(pOut->pBlobData, pIn->pBlobData, pIn->cbSize);
  3352. // Set Size
  3353. pOut->cbSize = pIn->cbSize;
  3354. }
  3355. else
  3356. {
  3357. pOut->cbSize = 0;
  3358. }
  3359. // Done
  3360. return hr;
  3361. }
  3362. // --------------------------------------------------------------------------------
  3363. // PriorityFromStringA
  3364. // --------------------------------------------------------------------------------
  3365. IMSGPRIORITY PriorityFromStringA(LPCSTR pszPriority)
  3366. {
  3367. // Locals
  3368. IMSGPRIORITY priority=IMSG_PRI_NORMAL;
  3369. DWORD dwPriority;
  3370. // If IsDigit...
  3371. if (IsDigit((LPSTR)pszPriority))
  3372. {
  3373. // Convert
  3374. dwPriority = (DWORD)StrToInt(pszPriority);
  3375. // Map to pri type
  3376. if (dwPriority <= 2)
  3377. priority = IMSG_PRI_HIGH;
  3378. else if (dwPriority > 3)
  3379. priority = IMSG_PRI_LOW;
  3380. }
  3381. // Otheriwse, map from high, normal and low...
  3382. else
  3383. {
  3384. // High, Highest, Low, Lowest
  3385. if (lstrcmpi(pszPriority, STR_PRI_MS_HIGH) == 0)
  3386. priority = IMSG_PRI_HIGH;
  3387. else if (lstrcmpi(pszPriority, STR_PRI_MS_LOW) == 0)
  3388. priority = IMSG_PRI_LOW;
  3389. else if (lstrcmpi(pszPriority, STR_PRI_HIGHEST) == 0)
  3390. priority = IMSG_PRI_HIGH;
  3391. else if (lstrcmpi(pszPriority, STR_PRI_LOWEST) == 0)
  3392. priority = IMSG_PRI_LOW;
  3393. }
  3394. // Done
  3395. return priority;
  3396. }
  3397. // --------------------------------------------------------------------------------
  3398. // PriorityFromStringW
  3399. // --------------------------------------------------------------------------------
  3400. IMSGPRIORITY PriorityFromStringW(LPCWSTR pwszPriority)
  3401. {
  3402. // Locals
  3403. HRESULT hr=S_OK;
  3404. LPSTR pszPriority=NULL;
  3405. IMSGPRIORITY priority=IMSG_PRI_NORMAL;
  3406. // Convert to ANSI
  3407. CHECKALLOC(pszPriority = PszToANSI(CP_ACP, pwszPriority));
  3408. // Normal Conversion
  3409. priority = PriorityFromStringA(pszPriority);
  3410. exit:
  3411. // Done
  3412. return priority;
  3413. }
  3414. // --------------------------------------------------------------------------------
  3415. // MimeOleCompareUrlSimple
  3416. // --------------------------------------------------------------------------------
  3417. HRESULT MimeOleCompareUrlSimple(LPCSTR pszUrl1, LPCSTR pszUrl2)
  3418. {
  3419. // Locals
  3420. HRESULT hr=S_OK;
  3421. CHAR chUrl1;
  3422. CHAR chUrl2;
  3423. // Skip leading white space
  3424. while(*pszUrl1 && (' ' == *pszUrl1 || '\t' == *pszUrl1))
  3425. pszUrl1++;
  3426. while(*pszUrl2 && (' ' == *pszUrl2 || '\t' == *pszUrl2))
  3427. pszUrl2++;
  3428. // Start the loop
  3429. while(*pszUrl1 && *pszUrl2)
  3430. {
  3431. // Case Insensitive
  3432. chUrl1 = TOUPPERA(*pszUrl1);
  3433. chUrl2 = TOUPPERA(*pszUrl2);
  3434. // Not Equal
  3435. if (chUrl1 != chUrl2)
  3436. {
  3437. hr = S_FALSE;
  3438. break;
  3439. }
  3440. // Next
  3441. pszUrl1++;
  3442. pszUrl2++;
  3443. }
  3444. // Skip over trailing whitespace
  3445. while(*pszUrl1 && (' ' == *pszUrl1 || '\t' == *pszUrl1))
  3446. pszUrl1++;
  3447. while(*pszUrl2 && (' ' == *pszUrl2 || '\t' == *pszUrl2))
  3448. pszUrl2++;
  3449. // No substrings
  3450. if ('\0' != *pszUrl1 || '\0' != *pszUrl2)
  3451. hr = S_FALSE;
  3452. // Done
  3453. return hr;
  3454. }
  3455. // --------------------------------------------------------------------------------
  3456. // MimeOleCompareUrl
  3457. // --------------------------------------------------------------------------------
  3458. HRESULT MimeOleCompareUrl(LPCSTR pszCurrentUrl, BOOL fUnEscapeCurrent, LPCSTR pszCompareUrl, BOOL fUnEscapeCompare)
  3459. {
  3460. // Locals
  3461. HRESULT hr=S_OK;
  3462. LPSTR pszUrl1=(LPSTR)pszCurrentUrl;
  3463. LPSTR pszUrl2=(LPSTR)pszCompareUrl;
  3464. CHAR chPrev='\0';
  3465. CHAR chUrl1;
  3466. CHAR chUrl2;
  3467. ULONG cb;
  3468. // Stack Strings
  3469. STACKSTRING_DEFINE(rCurrentUrl, 255);
  3470. STACKSTRING_DEFINE(rCompareUrl, 255);
  3471. // fUnEscapeCurrent
  3472. if (fUnEscapeCurrent)
  3473. {
  3474. // Get Size
  3475. cb = lstrlen(pszCurrentUrl) + 1;
  3476. // Set Size
  3477. STACKSTRING_SETSIZE(rCurrentUrl, cb);
  3478. // Copy
  3479. CopyMemory(rCurrentUrl.pszVal, pszCurrentUrl, cb);
  3480. // Dupe It
  3481. CHECKHR(hr = UrlUnescapeA(rCurrentUrl.pszVal, NULL, NULL, URL_UNESCAPE_INPLACE));
  3482. // Adjust pszUrl1
  3483. pszUrl1 = rCurrentUrl.pszVal;
  3484. }
  3485. // fUnEscapeCurrent
  3486. if (fUnEscapeCompare)
  3487. {
  3488. // Get Size
  3489. cb = lstrlen(pszCompareUrl) + 1;
  3490. // Set Size
  3491. STACKSTRING_SETSIZE(rCompareUrl, cb);
  3492. // Copy
  3493. CopyMemory(rCompareUrl.pszVal, pszCompareUrl, cb);
  3494. // Dupe It
  3495. CHECKHR(hr = UrlUnescapeA(rCompareUrl.pszVal, NULL, NULL, URL_UNESCAPE_INPLACE));
  3496. // Adjust pszUrl2
  3497. pszUrl2 = rCompareUrl.pszVal;
  3498. }
  3499. // Skip leading white space
  3500. while(*pszUrl1 && (' ' == *pszUrl1 || '\t' == *pszUrl1))
  3501. pszUrl1++;
  3502. while(*pszUrl2 && (' ' == *pszUrl2 || '\t' == *pszUrl2))
  3503. pszUrl2++;
  3504. // Start the loop
  3505. while(*pszUrl1 && *pszUrl2)
  3506. {
  3507. // Case Insensitive
  3508. chUrl1 = TOUPPERA(*pszUrl1);
  3509. chUrl2 = TOUPPERA(*pszUrl2);
  3510. // Special case search for '/'
  3511. if (':' == chPrev && '/' == chUrl2 && '/' != *(pszUrl2 + 1) && '/' == chUrl1 && '/' == *(pszUrl1 + 1))
  3512. {
  3513. // Next
  3514. pszUrl1++;
  3515. // Done
  3516. if ('\0' == *pszUrl1)
  3517. {
  3518. hr = S_FALSE;
  3519. break;
  3520. }
  3521. // Rset chUrl1
  3522. chUrl1 = TOUPPERA(*pszUrl1);
  3523. }
  3524. // Not Equal
  3525. if (chUrl1 != chUrl2)
  3526. {
  3527. hr = S_FALSE;
  3528. break;
  3529. }
  3530. // Save Prev
  3531. chPrev = *pszUrl1;
  3532. // Next
  3533. pszUrl1++;
  3534. pszUrl2++;
  3535. }
  3536. // Skip over trailing whitespace
  3537. while(*pszUrl1 && (' ' == *pszUrl1 || '\t' == *pszUrl1))
  3538. pszUrl1++;
  3539. while(*pszUrl2 && (' ' == *pszUrl2 || '\t' == *pszUrl2))
  3540. pszUrl2++;
  3541. // Raid 63823: Mail : Content-Location Href's inside the message do not work if there is a Start Parameter in headers
  3542. // Skim over remaining '/' in both urls
  3543. while (*pszUrl1 && '/' == *pszUrl1)
  3544. pszUrl1++;
  3545. while (*pszUrl2 && '/' == *pszUrl2)
  3546. pszUrl2++;
  3547. // No substrings
  3548. if ('\0' != *pszUrl1 || '\0' != *pszUrl2)
  3549. hr = S_FALSE;
  3550. // file://d:\test\foo.mhtml == d:\test\foo.mhtml
  3551. if (S_FALSE == hr && StrCmpNI(pszCurrentUrl, "file:", 5) == 0)
  3552. {
  3553. // Skip over file:
  3554. LPSTR pszRetryUrl = (LPSTR)(pszCurrentUrl + 5);
  3555. // Skip over forward slashes
  3556. while(*pszRetryUrl && '/' == *pszRetryUrl)
  3557. pszRetryUrl++;
  3558. // Compare Again
  3559. hr = MimeOleCompareUrl(pszRetryUrl, fUnEscapeCurrent, pszCompareUrl, fUnEscapeCompare);
  3560. }
  3561. exit:
  3562. // Cleanup
  3563. STACKSTRING_FREE(rCurrentUrl);
  3564. STACKSTRING_FREE(rCompareUrl);
  3565. // Done
  3566. return hr;
  3567. }
  3568. // --------------------------------------------------------------------------------
  3569. // MimeOleWrapHeaderText
  3570. // --------------------------------------------------------------------------------
  3571. HRESULT MimeOleWrapHeaderText(CODEPAGEID codepage, ULONG cchMaxLine, LPCSTR pszLine,
  3572. ULONG cchLine, LPSTREAM pStream)
  3573. {
  3574. // Locals
  3575. HRESULT hr=S_OK;
  3576. ULONG cchIndex=0;
  3577. ULONG cchWrite;
  3578. // Invalid Arg
  3579. Assert(pszLine && pszLine[cchLine] == '\0' && pStream && cchMaxLine >= 2);
  3580. // Start Writing
  3581. while(1)
  3582. {
  3583. // Validate
  3584. Assert(cchIndex <= cchLine);
  3585. // Compute cchWrite
  3586. cchWrite = min(cchLine - cchIndex, cchMaxLine - 2);
  3587. // Done
  3588. if (0 == cchWrite)
  3589. {
  3590. // Final Line Wrap
  3591. CHECKHR(hr = pStream->Write(c_szCRLF, 2, NULL));
  3592. // Done
  3593. break;
  3594. }
  3595. // Write the line
  3596. CHECKHR(hr = pStream->Write(pszLine + cchIndex, cchWrite, NULL));
  3597. // If there is still more text
  3598. if (cchIndex + cchWrite < cchLine)
  3599. {
  3600. // Write '\r\n\t'
  3601. CHECKHR(hr = pStream->Write(c_szCRLFTab, 3, NULL));
  3602. }
  3603. // Increment iText
  3604. cchIndex += cchWrite;
  3605. }
  3606. exit:
  3607. // Done
  3608. return hr;
  3609. }
  3610. // --------------------------------------------------------------------------------
  3611. // MimeOleCreateBody
  3612. // --------------------------------------------------------------------------------
  3613. HRESULT MimeOleCreateBody(IMimeBody **ppBody)
  3614. {
  3615. HRESULT hr;
  3616. CMessageBody *pNew;
  3617. pNew = new CMessageBody(NULL, NULL);
  3618. if (NULL == pNew)
  3619. return TrapError(E_OUTOFMEMORY);
  3620. hr = pNew->QueryInterface(IID_IMimeBody, (LPVOID *)ppBody);
  3621. pNew->Release();
  3622. return hr;
  3623. }
  3624. // --------------------------------------------------------------------------------
  3625. // MimeOleGetSentTime
  3626. // --------------------------------------------------------------------------------
  3627. HRESULT MimeOleGetSentTime(LPCONTAINER pContainer, DWORD dwFlags, LPMIMEVARIANT pValue)
  3628. {
  3629. // Locals
  3630. HRESULT hr=S_OK;
  3631. // Get the data: header field
  3632. if (FAILED(pContainer->GetProp(SYM_HDR_DATE, dwFlags, pValue)))
  3633. {
  3634. // Locals
  3635. SYSTEMTIME st;
  3636. MIMEVARIANT rValue;
  3637. // Setup rValue
  3638. rValue.type = MVT_VARIANT;
  3639. rValue.rVariant.vt = VT_FILETIME;
  3640. // Get current systemtime
  3641. GetSystemTime(&st);
  3642. SystemTimeToFileTime(&st, &rValue.rVariant.filetime);
  3643. // If the Conversion Fails, get the current time
  3644. CHECKHR(hr = pContainer->HrConvertVariant(SYM_ATT_SENTTIME, NULL, IET_DECODED, dwFlags, 0, &rValue, pValue));
  3645. }
  3646. exit:
  3647. // Done
  3648. return hr;
  3649. }