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.

706 lines
19 KiB

  1. // --------------------------------------------------------------------------------
  2. // Partial.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "partial.h"
  8. #include "vstream.h"
  9. #include "strconst.h"
  10. #include "demand.h"
  11. // --------------------------------------------------------------------------------
  12. // Releases an array of IMimeMessage objects
  13. // --------------------------------------------------------------------------------
  14. void ReleaseParts(ULONG cParts, LPPARTINFO prgPart)
  15. {
  16. // Loop
  17. for (ULONG i=0; i<cParts; i++)
  18. {
  19. SafeRelease(prgPart[i].pMessage);
  20. }
  21. }
  22. // --------------------------------------------------------------------------------
  23. // CMimeMessageParts::CMimeMessageParts
  24. // --------------------------------------------------------------------------------
  25. CMimeMessageParts::CMimeMessageParts(void)
  26. {
  27. m_cRef = 1;
  28. m_cParts = 0;
  29. m_cAlloc =0;
  30. m_prgPart = NULL;
  31. InitializeCriticalSection(&m_cs);
  32. }
  33. // --------------------------------------------------------------------------------
  34. // CMimeMessageParts::CMimeMessageParts
  35. // --------------------------------------------------------------------------------
  36. CMimeMessageParts::~CMimeMessageParts(void)
  37. {
  38. ReleaseParts(m_cParts, m_prgPart);
  39. SafeMemFree(m_prgPart);
  40. DeleteCriticalSection(&m_cs);
  41. }
  42. // --------------------------------------------------------------------------------
  43. // CMimeMessageParts::QueryInterface
  44. // --------------------------------------------------------------------------------
  45. STDMETHODIMP CMimeMessageParts::QueryInterface(REFIID riid, LPVOID *ppv)
  46. {
  47. // check params
  48. if (ppv == NULL)
  49. return TrapError(E_INVALIDARG);
  50. // Find IID
  51. if (IID_IUnknown == riid)
  52. *ppv = (IUnknown *)this;
  53. else if (IID_IMimeMessageParts == riid)
  54. *ppv = (IMimeMessageParts *)this;
  55. else
  56. {
  57. *ppv = NULL;
  58. return TrapError(E_NOINTERFACE);
  59. }
  60. // AddRef It
  61. ((IUnknown *)*ppv)->AddRef();
  62. // Done
  63. return S_OK;
  64. }
  65. // --------------------------------------------------------------------------------
  66. // CMimeMessageParts::AddRef
  67. // --------------------------------------------------------------------------------
  68. STDMETHODIMP_(ULONG) CMimeMessageParts::AddRef(void)
  69. {
  70. return (ULONG)InterlockedIncrement(&m_cRef);
  71. }
  72. // --------------------------------------------------------------------------------
  73. // CMimeMessageParts::Release
  74. // --------------------------------------------------------------------------------
  75. STDMETHODIMP_(ULONG) CMimeMessageParts::Release(void)
  76. {
  77. LONG cRef = InterlockedDecrement(&m_cRef);
  78. if (0 == cRef)
  79. delete this;
  80. return (ULONG)cRef;
  81. }
  82. // --------------------------------------------------------------------------------
  83. // CMimeMessageParts::AddPart
  84. // --------------------------------------------------------------------------------
  85. STDMETHODIMP CMimeMessageParts::AddPart(IMimeMessage *pMessage)
  86. {
  87. // Locals
  88. HRESULT hr=S_OK;
  89. // Invalid ARg
  90. if (NULL == pMessage)
  91. return TrapError(E_INVALIDARG);
  92. // Thread Safety
  93. EnterCriticalSection(&m_cs);
  94. // Grow my internal array
  95. if (m_cParts + 1 >= m_cAlloc)
  96. {
  97. // Grow my array
  98. CHECKHR(hr = HrRealloc((LPVOID *)&m_prgPart, sizeof(PARTINFO) * (m_cAlloc + 10)));
  99. // Set alloc size
  100. m_cAlloc += 10;
  101. }
  102. // Set new
  103. ZeroMemory(&m_prgPart[m_cParts], sizeof(PARTINFO));
  104. m_prgPart[m_cParts].pMessage = pMessage;
  105. m_prgPart[m_cParts].pMessage->AddRef();
  106. m_cParts++;
  107. exit:
  108. // Thread Safety
  109. LeaveCriticalSection(&m_cs);
  110. // Done
  111. return hr;
  112. }
  113. // --------------------------------------------------------------------------------
  114. // CMimeMessageParts::SetMaxParts
  115. // --------------------------------------------------------------------------------
  116. STDMETHODIMP CMimeMessageParts::SetMaxParts(ULONG cParts)
  117. {
  118. // Locals
  119. HRESULT hr=S_OK;
  120. // Thread Safety
  121. EnterCriticalSection(&m_cs);
  122. // Less than number alloced?
  123. if (cParts <= m_cAlloc)
  124. goto exit;
  125. // Grow my array
  126. CHECKHR(hr = HrAlloc((LPVOID *)&m_prgPart, sizeof(PARTINFO) * (cParts + 10)));
  127. // Set alloc size
  128. m_cAlloc = cParts + 10;
  129. exit:
  130. // Thread Safety
  131. LeaveCriticalSection(&m_cs);
  132. // Done
  133. return hr;
  134. }
  135. // --------------------------------------------------------------------------------
  136. // CMimeMessageParts::CountParts
  137. // --------------------------------------------------------------------------------
  138. STDMETHODIMP CMimeMessageParts::CountParts(ULONG *pcParts)
  139. {
  140. // Invalid ARg
  141. if (NULL == pcParts)
  142. return TrapError(E_INVALIDARG);
  143. // Thread Safety
  144. EnterCriticalSection(&m_cs);
  145. // Set count
  146. *pcParts = m_cParts;
  147. // Thread Safety
  148. LeaveCriticalSection(&m_cs);
  149. // Done
  150. return S_OK;
  151. }
  152. // --------------------------------------------------------------------------------
  153. // CMimeMessageParts::EnumParts
  154. // --------------------------------------------------------------------------------
  155. STDMETHODIMP CMimeMessageParts::EnumParts(IMimeEnumMessageParts **ppEnum)
  156. {
  157. // Locals
  158. HRESULT hr=S_OK;
  159. CMimeEnumMessageParts *pEnum=NULL;
  160. // Invalid Arg
  161. if (NULL == ppEnum)
  162. return TrapError(E_INVALIDARG);
  163. // Thread Safety
  164. EnterCriticalSection(&m_cs);
  165. // Init
  166. *ppEnum = NULL;
  167. // Create the clone.
  168. pEnum = new CMimeEnumMessageParts;
  169. if (NULL == pEnum)
  170. {
  171. hr = TrapError(E_OUTOFMEMORY);
  172. goto exit;
  173. }
  174. // Init
  175. CHECKHR(hr = pEnum->HrInit(0, m_cParts, m_prgPart));
  176. // Set Return
  177. *ppEnum = pEnum;
  178. (*ppEnum)->AddRef();
  179. exit:
  180. // Cleanup
  181. SafeRelease(pEnum);
  182. // Thread Safety
  183. LeaveCriticalSection(&m_cs);
  184. // Done
  185. return hr;
  186. }
  187. // --------------------------------------------------------------------------------
  188. // CMimeMessageParts::CombineParts
  189. // --------------------------------------------------------------------------------
  190. STDMETHODIMP CMimeMessageParts::CombineParts(IMimeMessage **ppMessage)
  191. {
  192. // Locals
  193. HRESULT hr=S_OK;
  194. LPSTREAM pstmMsg=NULL,
  195. pstmSource=NULL;
  196. ULONG i,
  197. cMimePartials=0,
  198. iPart,
  199. cRejected=0;
  200. IMimeMessage *pMessage;
  201. IMimeMessage *pCombine=NULL;
  202. IMimeBody *pRootBody=NULL;
  203. BOOL fTreatAsMime;
  204. BODYOFFSETS rOffsets;
  205. LPSTR pszSubject=NULL;
  206. PROPVARIANT rData;
  207. // Invalid ARg
  208. if (NULL == ppMessage)
  209. return TrapError(E_INVALIDARG);
  210. // Thread Safety
  211. EnterCriticalSection(&m_cs);
  212. // Init
  213. *ppMessage = NULL;
  214. // Create Temp Stream...
  215. CHECKALLOC(pstmMsg = new CVirtualStream);
  216. // Set all rejected flags to FALSE...
  217. for (i=0; i<m_cParts; i++)
  218. m_prgPart[i].fRejected = FALSE;
  219. // Enumerate parts
  220. for (i=0; i<m_cParts; i++)
  221. {
  222. // Reability
  223. pMessage = m_prgPart[i].pMessage;
  224. Assert(pMessage);
  225. // Get Message Source
  226. CHECKHR(hr = pMessage->GetMessageSource(&pstmSource, COMMIT_ONLYIFDIRTY));
  227. // Get Tree Object
  228. CHECKHR(hr = pMessage->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *)&pRootBody));
  229. // Get Root Body Offset
  230. CHECKHR(hr = pRootBody->GetOffsets(&rOffsets));
  231. // Un-init iPart
  232. iPart = 0;
  233. // Mime Message ?
  234. rData.vt = VT_UI4;
  235. if (pRootBody->IsContentType(STR_CNT_MESSAGE, STR_SUB_PARTIAL) == S_OK && SUCCEEDED(pRootBody->GetProp(STR_PAR_NUMBER, 0, &rData)))
  236. {
  237. // Count MimePartials
  238. cMimePartials++;
  239. // Treat this part as mime...
  240. fTreatAsMime = TRUE;
  241. // Get Part Number
  242. iPart = rData.ulVal;
  243. }
  244. // Otherwise
  245. else
  246. {
  247. // Don't treat as mime
  248. fTreatAsMime = FALSE;
  249. // If There have been legal mime partials, this part is rejected
  250. m_prgPart[i].fRejected = BOOL(cMimePartials > 0);
  251. }
  252. // If Rejected, continue...
  253. if (m_prgPart[i].fRejected)
  254. {
  255. cRejected++;
  256. continue;
  257. }
  258. // If MIME - and part one
  259. if (i == 0)
  260. {
  261. // Treat as mime
  262. if (fTreatAsMime && 1 == iPart)
  263. {
  264. // Merge the headers of part one
  265. CHECKHR(hr = MimeOleMergePartialHeaders(pstmSource, pstmMsg));
  266. // CRLF
  267. CHECKHR(hr = pstmMsg->Write(c_szCRLF, lstrlen(c_szCRLF), NULL));
  268. // Append message body onto lpstmOut
  269. CHECKHR(hr = HrCopyStream(pstmSource, pstmMsg, NULL));
  270. }
  271. else
  272. {
  273. // Seek to body start
  274. CHECKHR(hr = HrStreamSeekSet(pstmSource, 0));
  275. // Append message body onto lpstmOut
  276. CHECKHR(hr = HrCopyStream(pstmSource, pstmMsg, NULL));
  277. }
  278. }
  279. else
  280. {
  281. // Seek to body start
  282. CHECKHR(hr = HrStreamSeekSet(pstmSource, rOffsets.cbBodyStart));
  283. // Append message body onto lpstmOut
  284. CHECKHR(hr = HrCopyStream(pstmSource, pstmMsg, NULL));
  285. }
  286. // Raid 67648 - Need to append a CRLF to the end of the last message...
  287. if (i < m_cParts - 1)
  288. {
  289. // Locals
  290. DWORD cbMsg;
  291. // Read the last 2 bytes...
  292. CHECKHR(hr = HrGetStreamSize(pstmMsg, &cbMsg));
  293. // If greater than 2...
  294. if (cbMsg > 2)
  295. {
  296. // Locals
  297. BYTE rgCRLF[2];
  298. // Seek...
  299. CHECKHR(hr = HrStreamSeekSet(pstmMsg, cbMsg - 2));
  300. // Read the last two bytes
  301. CHECKHR(hr = pstmMsg->Read(rgCRLF, 2, NULL));
  302. // If not a crlf, then write a crlf
  303. if (rgCRLF[0] != chCR && rgCRLF[1] != chLF)
  304. {
  305. // Write CRLF
  306. CHECKHR(hr = pstmMsg->Write(c_szCRLF, 2, NULL));
  307. }
  308. }
  309. }
  310. // Release
  311. SafeRelease(pstmSource);
  312. SafeRelease(pRootBody);
  313. }
  314. // Rewind message stream..
  315. CHECKHR(hr = HrRewindStream(pstmMsg));
  316. // Create a message
  317. CHECKHR(hr = MimeOleCreateMessage(NULL, &pCombine));
  318. // Init New
  319. CHECKHR(hr = pCombine->InitNew());
  320. // Load the message
  321. CHECKHR(hr = pCombine->Load(pstmMsg));
  322. // Any Rejected ?
  323. if (cRejected)
  324. {
  325. // Attach rejected messages
  326. for (i=0; i<m_cParts; i++)
  327. {
  328. // Rejected...
  329. if (m_prgPart[i].fRejected)
  330. {
  331. // Attach body to combined message
  332. CHECKHR(hr = pCombine->AttachObject(IID_IMimeMessage, m_prgPart[i].pMessage, NULL));
  333. }
  334. }
  335. }
  336. // Return the new message
  337. *ppMessage = pCombine;
  338. (*ppMessage)->AddRef();
  339. // Debug to temp file...
  340. #ifdef DEBUG
  341. LPSTREAM pstmFile;
  342. if (SUCCEEDED(OpenFileStream("d:\\lastcom.txt", CREATE_ALWAYS, GENERIC_WRITE, &pstmFile)))
  343. {
  344. HrRewindStream(pstmMsg);
  345. HrCopyStream(pstmMsg, pstmFile, NULL);
  346. pstmFile->Commit(STGC_DEFAULT);
  347. pstmFile->Release();
  348. }
  349. #endif
  350. exit:
  351. // Cleanup
  352. SafeRelease(pstmMsg);
  353. SafeRelease(pstmSource);
  354. SafeRelease(pRootBody);
  355. SafeRelease(pCombine);
  356. // Thread Safety
  357. LeaveCriticalSection(&m_cs);
  358. // Done
  359. return hr;
  360. }
  361. // --------------------------------------------------------------------------------
  362. // CMimeEnumMessageParts::CMimeEnumMessageParts
  363. // --------------------------------------------------------------------------------
  364. CMimeEnumMessageParts::CMimeEnumMessageParts(void)
  365. {
  366. m_cRef = 1;
  367. m_iPart = 0;
  368. m_cParts = 0;
  369. m_prgPart = NULL;
  370. InitializeCriticalSection(&m_cs);
  371. }
  372. // --------------------------------------------------------------------------------
  373. // CMimeEnumMessageParts::~CMimeEnumMessageParts
  374. // --------------------------------------------------------------------------------
  375. CMimeEnumMessageParts::~CMimeEnumMessageParts(void)
  376. {
  377. ReleaseParts(m_cParts, m_prgPart);
  378. SafeMemFree(m_prgPart);
  379. DeleteCriticalSection(&m_cs);
  380. }
  381. // --------------------------------------------------------------------------------
  382. // CMimeEnumMessageParts::QueryInterface
  383. // --------------------------------------------------------------------------------
  384. STDMETHODIMP CMimeEnumMessageParts::QueryInterface(REFIID riid, LPVOID *ppv)
  385. {
  386. // check params
  387. if (ppv == NULL)
  388. return TrapError(E_INVALIDARG);
  389. // Find IID
  390. if (IID_IUnknown == riid)
  391. *ppv = (IUnknown *)this;
  392. else if (IID_IMimeEnumMessageParts == riid)
  393. *ppv = (IMimeEnumMessageParts *)this;
  394. else
  395. {
  396. *ppv = NULL;
  397. return TrapError(E_NOINTERFACE);
  398. }
  399. // AddRef It
  400. ((IUnknown *)*ppv)->AddRef();
  401. // Done
  402. return S_OK;
  403. }
  404. // --------------------------------------------------------------------------------
  405. // CMimeEnumMessageParts::QueryInterface
  406. // --------------------------------------------------------------------------------
  407. STDMETHODIMP_(ULONG) CMimeEnumMessageParts::AddRef(void)
  408. {
  409. return (ULONG)InterlockedIncrement(&m_cRef);
  410. }
  411. // --------------------------------------------------------------------------------
  412. // CMimeEnumMessageParts::Release
  413. // --------------------------------------------------------------------------------
  414. STDMETHODIMP_(ULONG) CMimeEnumMessageParts::Release(void)
  415. {
  416. LONG cRef = InterlockedDecrement(&m_cRef);
  417. if (0 == cRef)
  418. delete this;
  419. return (ULONG)cRef;
  420. }
  421. // --------------------------------------------------------------------------------
  422. // CMimeEnumMessageParts::Next
  423. // --------------------------------------------------------------------------------
  424. STDMETHODIMP CMimeEnumMessageParts::Next(ULONG cWanted, IMimeMessage **prgpMessage, ULONG *pcFetched)
  425. {
  426. // Locals
  427. HRESULT hr=S_OK;
  428. ULONG cFetch=1, iPart=0;
  429. // Thread Safety
  430. EnterCriticalSection(&m_cs);
  431. // Init
  432. if (pcFetched)
  433. *pcFetched = 0;
  434. // No Internal Formats
  435. if (NULL == m_prgPart || NULL == prgpMessage)
  436. goto exit;
  437. // Compute number to fetch
  438. cFetch = min(cWanted, m_cParts - m_iPart);
  439. if (0 == cFetch)
  440. goto exit;
  441. // Copy cWanted
  442. for (iPart=0; iPart<cFetch; iPart++)
  443. {
  444. prgpMessage[iPart] = m_prgPart[m_iPart].pMessage;
  445. prgpMessage[iPart]->AddRef();
  446. m_iPart++;
  447. }
  448. // Return fetced ?
  449. if (pcFetched)
  450. *pcFetched = cFetch;
  451. exit:
  452. // Thread Safety
  453. LeaveCriticalSection(&m_cs);
  454. // Done
  455. return (cFetch == cWanted) ? S_OK : S_FALSE;
  456. }
  457. // --------------------------------------------------------------------------------
  458. // CMimeEnumMessageParts::Skip
  459. // --------------------------------------------------------------------------------
  460. STDMETHODIMP CMimeEnumMessageParts::Skip(ULONG cSkip)
  461. {
  462. // Locals
  463. HRESULT hr=S_OK;
  464. // Thread Safety
  465. EnterCriticalSection(&m_cs);
  466. // Can we do it...
  467. if (((m_iPart + cSkip) >= m_cParts) || NULL == m_prgPart)
  468. {
  469. hr = S_FALSE;
  470. goto exit;
  471. }
  472. // Skip
  473. m_iPart += cSkip;
  474. exit:
  475. // Thread Safety
  476. LeaveCriticalSection(&m_cs);
  477. // Done
  478. return hr;
  479. }
  480. // --------------------------------------------------------------------------------
  481. // CMimeEnumMessageParts::Reset
  482. // --------------------------------------------------------------------------------
  483. STDMETHODIMP CMimeEnumMessageParts::Reset(void)
  484. {
  485. EnterCriticalSection(&m_cs);
  486. m_iPart = 0;
  487. LeaveCriticalSection(&m_cs);
  488. return S_OK;
  489. }
  490. // --------------------------------------------------------------------------------
  491. // CMimeEnumMessageParts::Count
  492. // --------------------------------------------------------------------------------
  493. STDMETHODIMP CMimeEnumMessageParts::Count(ULONG *pcCount)
  494. {
  495. // Invalid Arg
  496. if (NULL == pcCount)
  497. return TrapError(E_INVALIDARG);
  498. // Thread Safety
  499. EnterCriticalSection(&m_cs);
  500. // Set Count
  501. *pcCount = m_cParts;
  502. // Thread Safety
  503. LeaveCriticalSection(&m_cs);
  504. // Done
  505. return S_OK;
  506. }
  507. // --------------------------------------------------------------------------------
  508. // CMimeEnumMessageParts::Clone
  509. // --------------------------------------------------------------------------------
  510. STDMETHODIMP CMimeEnumMessageParts::Clone(IMimeEnumMessageParts **ppEnum)
  511. {
  512. // Locals
  513. HRESULT hr=S_OK;
  514. CMimeEnumMessageParts *pEnum=NULL;
  515. // Invalid Arg
  516. if (NULL == ppEnum)
  517. return TrapError(E_INVALIDARG);
  518. // Thread Safety
  519. EnterCriticalSection(&m_cs);
  520. // Init
  521. *ppEnum = NULL;
  522. // Create the clone.
  523. pEnum = new CMimeEnumMessageParts;
  524. if (NULL == pEnum)
  525. {
  526. hr = TrapError(E_OUTOFMEMORY);
  527. goto exit;
  528. }
  529. // Init
  530. CHECKHR(hr = pEnum->HrInit(m_iPart, m_cParts, m_prgPart));
  531. // Set Return
  532. *ppEnum = pEnum;
  533. (*ppEnum)->AddRef();
  534. exit:
  535. // Cleanup
  536. SafeRelease(pEnum);
  537. // Thread Safety
  538. LeaveCriticalSection(&m_cs);
  539. // Done
  540. return hr;
  541. }
  542. // --------------------------------------------------------------------------------
  543. // CMimeEnumMessageParts::HrInit
  544. // --------------------------------------------------------------------------------
  545. HRESULT CMimeEnumMessageParts::HrInit(ULONG iPart, ULONG cParts, LPPARTINFO prgPart)
  546. {
  547. // Locals
  548. HRESULT hr=S_OK;
  549. ULONG i;
  550. // Thread Safety
  551. EnterCriticalSection(&m_cs);
  552. // Check param
  553. Assert(m_prgPart == NULL);
  554. // Empty Enumerator ?
  555. if (0 == cParts)
  556. {
  557. Assert(prgPart == NULL);
  558. m_cParts = m_iPart = 0;
  559. goto exit;
  560. }
  561. // Allocat an internal array
  562. CHECKHR(hr = HrAlloc((LPVOID *)&m_prgPart, sizeof(PARTINFO) * cParts));
  563. // Copy prgPart
  564. for (i=0; i<cParts; i++)
  565. {
  566. CopyMemory(&m_prgPart[i], &prgPart[i], sizeof(PARTINFO));
  567. Assert(m_prgPart[i].pMessage);
  568. m_prgPart[i].pMessage->AddRef();
  569. }
  570. // Save Size and State
  571. m_cParts = cParts;
  572. m_iPart = iPart;
  573. exit:
  574. // Thread Safety
  575. LeaveCriticalSection(&m_cs);
  576. // Done
  577. return hr;
  578. }