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.

8155 lines
236 KiB

  1. // --------------------------------------------------------------------------------
  2. // Contain.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // --------------------------------------------------------------------------------
  5. #include "pch.hxx"
  6. #include "containx.h"
  7. #include "internat.h"
  8. #include "inetstm.h"
  9. #include "dllmain.h"
  10. #include "olealloc.h"
  11. #include "objheap.h"
  12. #include "vstream.h"
  13. #include "addparse.h"
  14. #include "enumhead.h"
  15. #include "addrenum.h"
  16. #include "stackstr.h"
  17. #include "stmlock.h"
  18. #include "enumprop.h"
  19. #include "smime.h"
  20. #ifndef WIN16
  21. #include "wchar.h"
  22. #endif // !WIN16
  23. #include "symcache.h"
  24. #ifdef MAC
  25. #include <stdio.h>
  26. #endif // MAC
  27. #include "mimeapi.h"
  28. #ifndef MAC
  29. #include <shlwapi.h>
  30. #endif // !MAC
  31. #include "demand.h"
  32. #include "mimeutil.h"
  33. //#define TRACEPARSE 1
  34. // --------------------------------------------------------------------------------
  35. // Hash Table Stats
  36. // --------------------------------------------------------------------------------
  37. #ifdef DEBUG
  38. DWORD g_cSetPidLookups = 0;
  39. DWORD g_cHashLookups = 0;
  40. DWORD g_cHashInserts = 0;
  41. DWORD g_cHashCollides = 0;
  42. #endif
  43. // --------------------------------------------------------------------------------
  44. // Default Header Options
  45. // --------------------------------------------------------------------------------
  46. const HEADOPTIONS g_rDefHeadOptions = {
  47. NULL, // hCharset
  48. DEF_CBMAX_HEADER_LINE, // OID_CBMAX_HEADER_LINE
  49. DEF_ALLOW_8BIT_HEADER, // OID_ALLOW_8BIT_HEADER
  50. DEF_SAVE_FORMAT, // OID_SAVE_FORMAT
  51. DEF_NO_DEFAULT_CNTTYPE, // OID_NO_DEFAULT_CNTTYPE
  52. DEF_HEADER_RELOAD_TYPE_PROPSET // OID_HEADER_REALOD_TYPE
  53. };
  54. // --------------------------------------------------------------------------------
  55. // ENCODINGTABLE
  56. // --------------------------------------------------------------------------------
  57. const ENCODINGTABLE g_rgEncoding[] = {
  58. { STR_ENC_7BIT, IET_7BIT },
  59. { STR_ENC_QP, IET_QP },
  60. { STR_ENC_BASE64, IET_BASE64 },
  61. { STR_ENC_UUENCODE, IET_UUENCODE },
  62. { STR_ENC_XUUENCODE, IET_UUENCODE },
  63. { STR_ENC_XUUE, IET_UUENCODE },
  64. { STR_ENC_8BIT, IET_8BIT },
  65. { STR_ENC_BINARY, IET_BINARY },
  66. { STR_ENC_BINHEX40, IET_BINHEX40 }
  67. };
  68. // --------------------------------------------------------------------------------
  69. // CMimePropertyContainer::CMimePropertyContainer
  70. // --------------------------------------------------------------------------------
  71. CMimePropertyContainer::CMimePropertyContainer(void)
  72. {
  73. // Basic Stuff
  74. m_cRef = 1;
  75. m_dwState = 0;
  76. m_cProps = 0;
  77. m_wTag = 0;
  78. m_cbSize = 0;
  79. m_cbStart = 0;
  80. m_pStmLock = NULL;
  81. // Default Options
  82. CopyMemory(&m_rOptions, &g_rDefHeadOptions, sizeof(HEADOPTIONS));
  83. m_rOptions.pDefaultCharset = CIntlGlobals::GetDefHeadCset();
  84. // Address Table
  85. ZeroMemory(&m_rAdrTable, sizeof(ADDRESSTABLE));
  86. // Header Table
  87. ZeroMemory(&m_rHdrTable, sizeof(HEADERTABLE));
  88. // Dispatch Call Stack
  89. ZeroMemory(&m_rTrigger, sizeof(TRIGGERCALLSTACK));
  90. // Property Indexes
  91. ZeroMemory(m_prgIndex, sizeof(m_prgIndex));
  92. ZeroMemory(m_prgHashTable, sizeof(m_prgHashTable));
  93. // Thread Safety
  94. InitializeCriticalSection(&m_cs);
  95. }
  96. // --------------------------------------------------------------------------------
  97. // CMimePropertyContainer::~CMimePropertyContainer
  98. // --------------------------------------------------------------------------------
  99. CMimePropertyContainer::~CMimePropertyContainer(void)
  100. {
  101. // I better not have any dispatch calls on the stack
  102. Assert(m_rTrigger.cCalls == 0);
  103. // Free Hash Table
  104. _FreeHashTableElements();
  105. // Free the Address Table
  106. SafeMemFree(m_rAdrTable.prgpAdr);
  107. // Free the Header Table
  108. SafeMemFree(m_rHdrTable.prgpRow);
  109. // Release Stream
  110. SafeRelease(m_pStmLock);
  111. // Delete CS
  112. DeleteCriticalSection(&m_cs);
  113. }
  114. // --------------------------------------------------------------------------------
  115. // CMimePropertyContainer::QueryInterface
  116. // --------------------------------------------------------------------------------
  117. HRESULT CMimePropertyContainer::QueryInterface(REFIID riid, LPVOID *ppv)
  118. {
  119. // Locals
  120. HRESULT hr=S_OK;
  121. // check params
  122. if (ppv == NULL)
  123. return TrapError(E_INVALIDARG);
  124. // Find IID
  125. if (IID_IUnknown == riid)
  126. *ppv = (IUnknown *)(IMimePropertySet *)this;
  127. else if (IID_IPersist == riid)
  128. *ppv = (IPersist *)(IMimePropertySet *)this;
  129. else if (IID_IPersistStreamInit == riid)
  130. *ppv = (IPersistStreamInit *)this;
  131. else if (IID_IMimePropertySet == riid)
  132. *ppv = (IMimePropertySet *)this;
  133. else if (IID_IMimeHeaderTable == riid)
  134. *ppv = (IMimeHeaderTable *)this;
  135. else if (IID_IMimeAddressTable == riid)
  136. *ppv = (IMimeAddressTable *)this;
  137. else if (IID_IMimeAddressTableW == riid)
  138. *ppv = (IMimeAddressTableW *)this;
  139. else if (IID_CMimePropertyContainer == riid)
  140. *ppv = (CMimePropertyContainer *)this;
  141. else
  142. {
  143. *ppv = NULL;
  144. hr = TrapError(E_NOINTERFACE);
  145. goto exit;
  146. }
  147. // AddRef It
  148. ((IUnknown *)*ppv)->AddRef();
  149. exit:
  150. // Done
  151. return hr;
  152. }
  153. // --------------------------------------------------------------------------------
  154. // CMimePropertyContainer::AddRef
  155. // --------------------------------------------------------------------------------
  156. STDMETHODIMP_(ULONG) CMimePropertyContainer::AddRef(void)
  157. {
  158. return InterlockedIncrement(&m_cRef);
  159. }
  160. // --------------------------------------------------------------------------------
  161. // CMimePropertyContainer::Release
  162. // --------------------------------------------------------------------------------
  163. STDMETHODIMP_(ULONG) CMimePropertyContainer::Release(void)
  164. {
  165. LONG cRef = InterlockedDecrement(&m_cRef);
  166. if (0 == cRef)
  167. delete this;
  168. return (ULONG)cRef;
  169. }
  170. // --------------------------------------------------------------------------------
  171. // CMimePropertyContainer::IsState
  172. // --------------------------------------------------------------------------------
  173. HRESULT CMimePropertyContainer::IsState(DWORD dwState)
  174. {
  175. EnterCriticalSection(&m_cs);
  176. HRESULT hr = (ISFLAGSET(m_dwState, dwState)) ? S_OK : S_FALSE;
  177. LeaveCriticalSection(&m_cs);
  178. return hr;
  179. }
  180. // --------------------------------------------------------------------------------
  181. // CMimePropertyContainer::ClearState
  182. // --------------------------------------------------------------------------------
  183. void CMimePropertyContainer::ClearState(DWORD dwState)
  184. {
  185. EnterCriticalSection(&m_cs);
  186. FLAGCLEAR(m_dwState, dwState);
  187. LeaveCriticalSection(&m_cs);
  188. }
  189. // --------------------------------------------------------------------------------
  190. // CMimePropertyContainer::DwGetState
  191. // --------------------------------------------------------------------------------
  192. DWORD CMimePropertyContainer::DwGetState(LPDWORD pdwState)
  193. {
  194. Assert(pdwState);
  195. EnterCriticalSection(&m_cs);
  196. DWORD dw = m_dwState;
  197. LeaveCriticalSection(&m_cs);
  198. return dw;
  199. }
  200. // --------------------------------------------------------------------------------
  201. // CMimePropertyContainer::SetState
  202. // --------------------------------------------------------------------------------
  203. void CMimePropertyContainer::SetState(DWORD dwState)
  204. {
  205. EnterCriticalSection(&m_cs);
  206. FLAGSET(m_dwState, dwState);
  207. LeaveCriticalSection(&m_cs);
  208. }
  209. // --------------------------------------------------------------------------------
  210. // CMimePropertyContainer::GetClassID
  211. // --------------------------------------------------------------------------------
  212. STDMETHODIMP CMimePropertyContainer::GetClassID(CLSID *pClassID)
  213. {
  214. // Copy Class Id
  215. CopyMemory(pClassID, &IID_IMimePropertySet, sizeof(CLSID));
  216. // Done
  217. return S_OK;
  218. }
  219. // --------------------------------------------------------------------------------
  220. // CMimePropertyContainer::GetSizeMax
  221. // --------------------------------------------------------------------------------
  222. STDMETHODIMP CMimePropertyContainer::GetSizeMax(ULARGE_INTEGER *pcbSize)
  223. {
  224. // Locals
  225. HRESULT hr=S_OK;
  226. IStream *pStream=NULL;
  227. ULONG cbSize;
  228. // Invalid Arg
  229. if (NULL == pcbSize)
  230. return TrapError(E_INVALIDARG);
  231. // Thread Safety
  232. EnterCriticalSection(&m_cs);
  233. // If Dirty
  234. if (ISFLAGSET(m_dwState, COSTATE_DIRTY))
  235. {
  236. // Create temp stream
  237. CHECKALLOC(pStream = new CVirtualStream);
  238. // Commit
  239. CHECKHR(hr = Save(pStream, FALSE));
  240. // Get the Stream Size
  241. CHECKHR(hr = HrGetStreamSize(pStream, &cbSize));
  242. }
  243. // Otherwise, m_cbSize should be set to current size
  244. else
  245. cbSize = m_cbSize;
  246. // Return the Size
  247. #ifdef MAC
  248. ULISet32(*pcbSize, cbSize);
  249. #else // !MAC
  250. pcbSize->QuadPart = cbSize;
  251. #endif // MAC
  252. exit:
  253. // Cleanup
  254. SafeRelease(pStream);
  255. // Thread Safety
  256. LeaveCriticalSection(&m_cs);
  257. // Done
  258. return hr;
  259. }
  260. // --------------------------------------------------------------------------------
  261. // CMimePropertyContainer::IsDirty
  262. // --------------------------------------------------------------------------------
  263. STDMETHODIMP CMimePropertyContainer::IsDirty(void)
  264. {
  265. EnterCriticalSection(&m_cs);
  266. HRESULT hr = (ISFLAGSET(m_dwState, COSTATE_DIRTY)) ? S_OK : S_FALSE;
  267. LeaveCriticalSection(&m_cs);
  268. return hr;
  269. }
  270. // --------------------------------------------------------------------------------
  271. // CMimePropertyContainer::_ReloadInitNew
  272. // --------------------------------------------------------------------------------
  273. void CMimePropertyContainer::_ReloadInitNew(void)
  274. {
  275. // Handle all reload types
  276. switch(m_rOptions.ReloadType)
  277. {
  278. // Default behavior is no InitNew
  279. case RELOAD_HEADER_NONE:
  280. return;
  281. // InitNew everytime Load is called
  282. case RELOAD_HEADER_RESET:
  283. InitNew();
  284. break;
  285. // Merge or replace headers
  286. case RELOAD_HEADER_APPEND:
  287. SafeRelease(m_pStmLock);
  288. break;
  289. case RELOAD_HEADER_REPLACE:
  290. SafeRelease(m_pStmLock);
  291. _SetStateOnAllProps(PRSTATE_EXIST_BEFORE_LOAD);
  292. break;
  293. }
  294. }
  295. // --------------------------------------------------------------------------------
  296. // CMimePropertyContainer::_SetStateOnAllProps (only first level properties)
  297. // --------------------------------------------------------------------------------
  298. void CMimePropertyContainer::_SetStateOnAllProps(DWORD dwState)
  299. {
  300. // Locals
  301. ULONG i;
  302. LPPROPERTY pProperty;
  303. // Do I have any groups
  304. if (0 == m_cProps)
  305. return;
  306. // Loop through the item table
  307. for (i=0; i<CBUCKETS; i++)
  308. {
  309. // Walk the hash list
  310. pProperty = m_prgHashTable[i];
  311. // Loop the overflows
  312. while(pProperty)
  313. {
  314. // Set the state on the property
  315. FLAGSET(pProperty->dwState, dwState);
  316. // Goto Next
  317. pProperty = pProperty->pNextHash;
  318. }
  319. }
  320. }
  321. // --------------------------------------------------------------------------------
  322. // CMimePropertyContainer::InitNew
  323. // --------------------------------------------------------------------------------
  324. STDMETHODIMP CMimePropertyContainer::InitNew(void)
  325. {
  326. // Thread Safety
  327. EnterCriticalSection(&m_cs);
  328. // No dispatchs better be out...
  329. Assert(m_rTrigger.cCalls == 0);
  330. // Free the PropTable
  331. _FreeHashTableElements();
  332. // Release the Stream
  333. SafeRelease(m_pStmLock);
  334. // Reset m_wTag
  335. m_wTag = LOWORD(GetTickCount());
  336. while(m_wTag == 0 || m_wTag == 0xffff)
  337. m_wTag++;
  338. // Clear State
  339. m_dwState = 0;
  340. m_cbSize = 0;
  341. m_cbStart = 0;
  342. // Thread Safety
  343. LeaveCriticalSection(&m_cs);
  344. // Done
  345. return S_OK;
  346. }
  347. // --------------------------------------------------------------------------------
  348. // CMimePropertyContainer::Load
  349. // --------------------------------------------------------------------------------
  350. STDMETHODIMP CMimePropertyContainer::Load(IStream *pStream)
  351. {
  352. // Locals
  353. HRESULT hr=S_OK;
  354. CStreamLockBytes *pStmLock=NULL;
  355. CInternetStream cInternet;
  356. ULONG cbOffset;
  357. // check params
  358. if (NULL == pStream)
  359. return TrapError(E_INVALIDARG);
  360. // Wrap pStream in a pStmLock
  361. CHECKALLOC(pStmLock = new CStreamLockBytes(pStream));
  362. // Get Current Stream Position
  363. CHECKHR(hr = HrGetStreamPos(pStream, &cbOffset));
  364. // Create text stream object
  365. cInternet.InitNew(cbOffset, pStmLock);
  366. // Load from text stream object
  367. CHECKHR(hr = Load(&cInternet));
  368. exit:
  369. // Cleanup
  370. SafeRelease(pStmLock);
  371. // Done
  372. return hr;
  373. }
  374. // --------------------------------------------------------------------------------
  375. // CMimePropertyContainer::Load
  376. // --------------------------------------------------------------------------------
  377. HRESULT CMimePropertyContainer::Load(CInternetStream *pInternet)
  378. {
  379. // Locals
  380. HRESULT hr=S_OK;
  381. ULONG cbData,
  382. cbStart,
  383. cboffStart,
  384. cboffEnd;
  385. LONG cboffColon;
  386. LPSTR psz;
  387. DWORD dwRowNumber=1;
  388. LPPROPSYMBOL pSymbol;
  389. LPPROPERTY pProperty;
  390. MIMEVARIANT rValue;
  391. PROPSTRINGA rHeader;
  392. // Thread Safety
  393. EnterCriticalSection(&m_cs);
  394. // Get Starting Position
  395. m_cbStart = pInternet->DwGetOffset();
  396. // Initialize the PropValue
  397. rValue.type = MVT_STRINGA;
  398. // Reload InitNewType
  399. _ReloadInitNew();
  400. // Read Headers into Rows
  401. while(1)
  402. {
  403. // Mark Start of this header
  404. cboffStart = pInternet->DwGetOffset();
  405. // Read header line...
  406. CHECKHR(hr = pInternet->HrReadHeaderLine(&rHeader, &cboffColon));
  407. Assert(ISVALIDSTRINGA(&rHeader));
  408. // Are we done - empty line signals end of header
  409. if (*rHeader.pszVal == '\0')
  410. {
  411. // Compute Header Size
  412. m_cbSize = (LONG)(pInternet->DwGetOffset() - m_cbStart);
  413. // Done
  414. break;
  415. }
  416. // If no colon found
  417. if (-1 == cboffColon)
  418. {
  419. // Use the Illegal Symbol
  420. pSymbol = SYM_ATT_ILLEGAL;
  421. }
  422. // Otherwise...
  423. else
  424. {
  425. // Skip whitespace
  426. cbData = cboffColon;
  427. psz = rHeader.pszVal;
  428. #if 0
  429. while(*psz && (*psz == ' ' || *psz == '\t'))
  430. {
  431. cbData--;
  432. psz++;
  433. }
  434. #endif
  435. // Save Header Name
  436. Assert(rHeader.pszVal[cboffColon] == ':');
  437. *(rHeader.pszVal + cboffColon) = '\0';
  438. // Find Global Property
  439. hr = g_pSymCache->HrOpenSymbol(rHeader.pszVal, TRUE, &pSymbol);
  440. // Replace the colon
  441. *(rHeader.pszVal + cboffColon) = ':';
  442. // Bad Header Name or Failure
  443. if (FAILED(hr))
  444. {
  445. // Unknown Failure
  446. if (MIME_E_INVALID_HEADER_NAME != hr)
  447. {
  448. TrapError(hr);
  449. goto exit;
  450. }
  451. // Use the Illegal Symbol
  452. pSymbol = SYM_ATT_ILLEGAL;
  453. // Were are S_OK
  454. hr = S_OK;
  455. }
  456. }
  457. // Assert pSymbol
  458. Assert(pSymbol);
  459. // If Not Illegal
  460. if (PID_ATT_ILLEGAL == pSymbol->dwPropId)
  461. {
  462. cbData = rHeader.cchVal;
  463. psz = rHeader.pszVal;
  464. cboffColon = 0;
  465. }
  466. // Otherwise
  467. else
  468. {
  469. // We better have a symbol
  470. Assert(rHeader.pszVal[cboffColon] == ':');
  471. // Step over space between colon and first character
  472. cbData = (rHeader.cchVal - cboffColon - 1);
  473. psz = rHeader.pszVal + cboffColon + 1;
  474. if (*psz == ' ' || *psz == '\t')
  475. {
  476. cbData--;
  477. psz++;
  478. }
  479. }
  480. // Invalid Arg
  481. Assert(psz && psz[cbData] == '\0');
  482. // Append a Property
  483. if (RELOAD_HEADER_REPLACE == m_rOptions.ReloadType)
  484. {
  485. // Dos the property pSymbol already exist?
  486. if (SUCCEEDED(_HrFindProperty(pSymbol, &pProperty)))
  487. {
  488. // Did the property exist before the load
  489. if (ISFLAGSET(pProperty->dwState, PRSTATE_EXIST_BEFORE_LOAD))
  490. {
  491. // Delete the Property
  492. SideAssert(SUCCEEDED(DeleteProp(pSymbol)));
  493. }
  494. }
  495. }
  496. // Simply append any existing property
  497. CHECKHR(hr = _HrAppendProperty(pSymbol, &pProperty));
  498. // Setup Property Value
  499. rValue.rStringA.pszVal = psz;
  500. rValue.rStringA.cchVal = cbData;
  501. // Store the data on the property
  502. CHECKHR(hr = _HrSetPropertyValue(pProperty, PDF_ENCODED, &rValue, FALSE));
  503. // Still Trying to detect a character set...
  504. if (!ISFLAGSET(m_dwState, COSTATE_CSETTAGGED) && PID_ATT_ILLEGAL != pSymbol->dwPropId)
  505. {
  506. // Content-Type charset=xxx
  507. if (PID_HDR_CNTTYPE == pSymbol->dwPropId && NULL != m_prgIndex[PID_PAR_CHARSET])
  508. {
  509. // Locals
  510. LPPROPERTY pProperty;
  511. LPINETCSETINFO pCharset;
  512. // Did we have a charset=xxxx yet
  513. pProperty = m_prgIndex[PID_PAR_CHARSET];
  514. // Make sure it is a valid string property
  515. Assert(ISSTRINGA(&pProperty->rValue));
  516. // Get charset handle...
  517. if (SUCCEEDED(g_pInternat->HrOpenCharset(pProperty->rValue.rStringA.pszVal, &pCharset)))
  518. {
  519. // We are tagged
  520. FLAGSET(m_dwState, COSTATE_CSETTAGGED);
  521. // Save the charset
  522. m_rOptions.pDefaultCharset = pCharset;
  523. }
  524. }
  525. // Otherwise, is the property encoded in an rfc1522 charset?
  526. else if (!ISFLAGSET(m_dwState, COSTATE_1522CSETTAG) && pProperty->pCharset)
  527. {
  528. // The header is tagged with a 1522 charset
  529. FLAGSET(m_dwState, COSTATE_1522CSETTAG);
  530. // Assume that charset
  531. m_rOptions.pDefaultCharset = pProperty->pCharset;
  532. }
  533. }
  534. // Set The Row Number
  535. pProperty->dwRowNumber = dwRowNumber++;
  536. // Set Start Offset
  537. pProperty->cboffStart = cboffStart;
  538. // Map cboffColon from Line to Stream offset
  539. pProperty->cboffColon = cboffColon + pProperty->cboffStart;
  540. // Save cbOffEnd
  541. pProperty->cboffEnd = pInternet->DwGetOffset();
  542. }
  543. // Save the Stream
  544. Assert(NULL == m_pStmLock);
  545. // Get the stream object from the text stream
  546. pInternet->GetLockBytes(&m_pStmLock);
  547. // If not character set tagged
  548. if (!ISFLAGSET(m_dwState, COSTATE_CSETTAGGED))
  549. {
  550. // If not tagged with a 1522 charset, use the default
  551. if (!ISFLAGSET(m_dwState, COSTATE_1522CSETTAG) && CIntlGlobals::GetDefHeadCset())
  552. {
  553. // Assume the Default character Set
  554. m_rOptions.pDefaultCharset = CIntlGlobals::GetDefHeadCset();
  555. }
  556. // Lookup Charset Info
  557. if (m_rOptions.pDefaultCharset)
  558. {
  559. // Locals
  560. MIMEVARIANT rValue;
  561. // Setup Variant
  562. rValue.type = MVT_STRINGA;
  563. rValue.rStringA.pszVal = m_rOptions.pDefaultCharset->szName;
  564. rValue.rStringA.cchVal = lstrlen(m_rOptions.pDefaultCharset->szName);
  565. // Set the Charset Attribute
  566. SideAssert(SUCCEEDED(SetProp(SYM_PAR_CHARSET, 0, &rValue)));
  567. }
  568. }
  569. // We better have a charset
  570. Assert(m_rOptions.pDefaultCharset);
  571. // Make sure we are not dirty
  572. FLAGCLEAR(m_dwState, COSTATE_DIRTY);
  573. // Any Illegal lines found ?
  574. hr = (NULL == m_prgIndex[PID_ATT_ILLEGAL]) ? S_OK : MIME_S_ILLEGAL_LINES_FOUND;
  575. exit:
  576. // Failure
  577. if (FAILED(hr))
  578. InitNew();
  579. // Thread Safety
  580. LeaveCriticalSection(&m_cs);
  581. // Done
  582. return hr;
  583. }
  584. // --------------------------------------------------------------------------------
  585. // CMimePropertyContainer::_HrGetHeaderTableSaveIndex
  586. // --------------------------------------------------------------------------------
  587. HRESULT CMimePropertyContainer::_HrGetHeaderTableSaveIndex(ULONG *pcRows, LPROWINDEX *pprgIndex)
  588. {
  589. // Locals
  590. HRESULT hr=S_OK;
  591. ULONG i;
  592. LPPROPERTY pRow;
  593. ULONG cRows=0;
  594. LPROWINDEX prgIndex=NULL;
  595. ULONG cSymbols=g_pSymCache->GetCount();
  596. DWORD dwMaxRow=0;
  597. // Invalid Arg
  598. Assert(pcRows && pprgIndex);
  599. // Init Row Count
  600. *pcRows = 0;
  601. *pprgIndex = NULL;
  602. // Allocate pprgdwIndex based on m_rHdrTable.cRows (this is the max)
  603. CHECKALLOC(prgIndex = (LPROWINDEX)g_pMalloc->Alloc(sizeof(ROWINDEX) * m_rHdrTable.cRows));
  604. // Zero
  605. ZeroMemory(prgIndex, sizeof(ROWINDEX) * m_rHdrTable.cRows);
  606. // I need to find the larged pProperty->dwRowNumber so that I can order the rows better
  607. for (i=0; i<m_rHdrTable.cRows; i++)
  608. {
  609. if (m_rHdrTable.prgpRow[i])
  610. if (!ISFLAGSET(m_rHdrTable.prgpRow[i]->dwState, PRSTATE_USERSETROWNUM))
  611. if (m_rHdrTable.prgpRow[i]->dwRowNumber > dwMaxRow)
  612. dwMaxRow = m_rHdrTable.prgpRow[i]->dwRowNumber;
  613. }
  614. // Compute Position Weight for all items in the table
  615. for (i=0; i<m_rHdrTable.cRows; i++)
  616. {
  617. // Readability
  618. pRow = m_rHdrTable.prgpRow[i];
  619. if (NULL == pRow)
  620. continue;
  621. // Save As SAVE_RFC822 and this is a MPF_MIME header
  622. if (SAVE_RFC822 == m_rOptions.savetype && ISFLAGSET(pRow->pSymbol->dwFlags, MPF_MIME))
  623. continue;
  624. // Init dwPosWeight
  625. prgIndex[cRows].dwWeight = 0;
  626. prgIndex[cRows].hRow = pRow->hRow;
  627. // Unknonw Row Number
  628. if (0 == pRow->dwRowNumber)
  629. {
  630. // Compute the Row Weigth
  631. Assert(pRow->pSymbol->dwRowNumber != 0);
  632. prgIndex[cRows].dwWeight = (ULONG)((pRow->pSymbol->dwRowNumber * 1000) / m_rHdrTable.cRows);
  633. }
  634. // User set the row number
  635. else if (ISFLAGSET(pRow->dwState, PRSTATE_USERSETROWNUM))
  636. {
  637. // Compute the Row Weigth
  638. prgIndex[cRows].dwWeight = (ULONG)((pRow->dwRowNumber * 1000) / m_rHdrTable.cRows);
  639. }
  640. // Otheriwse, this row number have been in the original row set from ::Load
  641. else if (dwMaxRow > 0)
  642. {
  643. // Weight within original row set
  644. DWORD dw1 = (DWORD)((pRow->dwRowNumber * 100) / dwMaxRow);
  645. // Compute global symbol row number
  646. DWORD dwRow = (DWORD)((float)((float)dw1 / (float)100) * cSymbols);
  647. // Compute the Row Weigth
  648. prgIndex[cRows].dwWeight = (ULONG)((dwRow * 1000) / m_rHdrTable.cRows);
  649. }
  650. // Increment Row Count
  651. cRows++;
  652. }
  653. // Set the Sort Order Index of all the rows
  654. if (cRows > 0)
  655. _SortHeaderTableSaveIndex(0, cRows - 1, prgIndex);
  656. // Return the Index
  657. *pprgIndex = prgIndex;
  658. *pcRows = cRows;
  659. prgIndex = NULL;
  660. exit:
  661. // Cleanup
  662. SafeMemFree(prgIndex);
  663. // Done
  664. return hr;
  665. }
  666. // --------------------------------------------------------------------------------
  667. // CMimePropertyContainer::_SortHeaderTableSaveIndex
  668. // --------------------------------------------------------------------------------
  669. void CMimePropertyContainer::_SortHeaderTableSaveIndex(LONG left, LONG right, LPROWINDEX prgIndex)
  670. {
  671. // Locals
  672. register long i, j;
  673. ROWINDEX k, temp;
  674. i = left;
  675. j = right;
  676. CopyMemory(&k, &prgIndex[(i + j) / 2], sizeof(ROWINDEX));
  677. do
  678. {
  679. while(prgIndex[i].dwWeight < k.dwWeight && i < right)
  680. i++;
  681. while (prgIndex[j].dwWeight > k.dwWeight && j > left)
  682. j--;
  683. if (i <= j)
  684. {
  685. CopyMemory(&temp, &prgIndex[i], sizeof(ROWINDEX));
  686. CopyMemory(&prgIndex[i], &prgIndex[j], sizeof(ROWINDEX));
  687. CopyMemory(&prgIndex[j], &temp, sizeof(ROWINDEX));
  688. i++; j--;
  689. }
  690. } while (i <= j);
  691. if (left < j)
  692. _SortHeaderTableSaveIndex(left, j, prgIndex);
  693. if (i < right)
  694. _SortHeaderTableSaveIndex(i, right, prgIndex);
  695. }
  696. // --------------------------------------------------------------------------------
  697. // CMimePropertyContainer::_FIsValidHAddress
  698. // --------------------------------------------------------------------------------
  699. BOOL CMimePropertyContainer::_FIsValidHAddress(HADDRESS hAddress)
  700. {
  701. // Invalid Sig or index
  702. if ((WORD)(HADDRESSTICK(hAddress)) != m_wTag || HADDRESSINDEX(hAddress) >= m_rAdrTable.cAdrs)
  703. return FALSE;
  704. // Row has been deleted
  705. if (NULL == m_rAdrTable.prgpAdr[HADDRESSINDEX(hAddress)])
  706. return FALSE;
  707. // Otherwise, its valid
  708. return TRUE;
  709. }
  710. // --------------------------------------------------------------------------------
  711. // CMimePropertyContainer::_FIsValidHRow
  712. // --------------------------------------------------------------------------------
  713. BOOL CMimePropertyContainer::_FIsValidHRow(HHEADERROW hRow)
  714. {
  715. // Invalid Sig or index
  716. if ((WORD)(HROWTICK(hRow)) != m_wTag || HROWINDEX(hRow) >= m_rHdrTable.cRows)
  717. return FALSE;
  718. // Row has been deleted
  719. if (NULL == m_rHdrTable.prgpRow[HROWINDEX(hRow)])
  720. return FALSE;
  721. // Otherwise, its valid
  722. return TRUE;
  723. }
  724. // --------------------------------------------------------------------------------
  725. // CMimePropertyContainer::Save
  726. // --------------------------------------------------------------------------------
  727. STDMETHODIMP CMimePropertyContainer::Save(LPSTREAM pStream, BOOL fClearDirty)
  728. {
  729. // Locals
  730. HRESULT hr=S_OK;
  731. LPPROPERTY pRow;
  732. LPPROPERTY pProperty;
  733. ULONG i,
  734. j,
  735. cbWrote,
  736. cRows;
  737. MIMEVARIANT rValue;
  738. LPROWINDEX prgIndex=NULL;
  739. INETCSETINFO rCharset;
  740. // Invalid Arg
  741. if (NULL == pStream)
  742. return TrapError(E_INVALIDARG);
  743. // Thread Safety
  744. EnterCriticalSection(&m_cs);
  745. // There Better be a content type
  746. if (FALSE == m_rOptions.fNoDefCntType && NULL == m_prgIndex[PID_HDR_CNTTYPE])
  747. {
  748. // Set the content Type
  749. SideAssert(SUCCEEDED(SetProp(SYM_HDR_CNTTYPE, STR_MIME_TEXT_PLAIN)));
  750. }
  751. // Validate the Charset
  752. if (m_rOptions.pDefaultCharset)
  753. {
  754. // Internet Encoded and Windows Encoding are CPI_AUTODETECT
  755. if (CP_JAUTODETECT == m_rOptions.pDefaultCharset->cpiInternet ||
  756. 50222 == m_rOptions.pDefaultCharset->cpiInternet ||
  757. 50221 == m_rOptions.pDefaultCharset->cpiInternet)
  758. {
  759. // Only for _autodetect
  760. if (CP_JAUTODETECT == m_rOptions.pDefaultCharset->cpiInternet)
  761. {
  762. // Change Charset
  763. SideAssert(SUCCEEDED(g_pInternat->HrOpenCharset(c_szISO2022JP, &m_rOptions.pDefaultCharset)));
  764. }
  765. // Reset It
  766. if (m_prgIndex[PID_PAR_CHARSET])
  767. {
  768. // Set the Charset...
  769. SideAssert(SUCCEEDED(SetProp(SYM_PAR_CHARSET, c_szISO2022JP)));
  770. }
  771. }
  772. }
  773. // This builds an inverted index on the header rows sorted by postion weight
  774. CHECKHR(hr = _HrGetHeaderTableSaveIndex(&cRows, &prgIndex));
  775. // Speicify data type
  776. rValue.type = MVT_STREAM;
  777. rValue.pStream = pStream;
  778. // Loop through the rows
  779. for (i=0; i<cRows; i++)
  780. {
  781. // Get the row
  782. Assert(_FIsValidHRow(prgIndex[i].hRow));
  783. // Saved already
  784. if (TRUE == prgIndex[i].fSaved)
  785. continue;
  786. // Readability
  787. pRow = PRowFromHRow(prgIndex[i].hRow);
  788. // Ask the value for the data
  789. CHECKHR(hr = _HrGetPropertyValue(pRow, PDF_HEADERFORMAT | PDF_NAMEINDATA, &rValue));
  790. // This block of code was disabled to fix:
  791. // Raid-62460: MimeOLE: IMimeAddressTable::AppendRfc822 does not work correctly
  792. #if 0
  793. // Raid-43786: Mail: Reply all to a message with multiple To: fields in header and the original recipient list is tripled
  794. if (ISFLAGSET(pRow->pSymbol->dwFlags, MPF_ADDRESS))
  795. {
  796. // Loop through remainin items and mark as saved
  797. for (j=i+1; j<cRows; j++)
  798. {
  799. // Get the row
  800. Assert(_FIsValidHRow(prgIndex[j].hRow));
  801. // Readability
  802. pProperty = PRowFromHRow(prgIndex[j].hRow);
  803. // Same Address Type
  804. if (pProperty->pSymbol->dwAdrType == pRow->pSymbol->dwAdrType)
  805. prgIndex[j].fSaved = TRUE;
  806. }
  807. }
  808. #endif
  809. }
  810. // Make sure we are not dirty
  811. if (fClearDirty)
  812. FLAGCLEAR(m_dwState, COSTATE_DIRTY);
  813. exit:
  814. // Cleanup
  815. SafeMemFree(prgIndex);
  816. // Thread Safety
  817. LeaveCriticalSection(&m_cs);
  818. // Done
  819. return hr;
  820. }
  821. // --------------------------------------------------------------------------------
  822. // CMimePropertyContainer::_FreeHashTableElements
  823. // --------------------------------------------------------------------------------
  824. void CMimePropertyContainer::_FreeHashTableElements(void)
  825. {
  826. // Locals
  827. ULONG i;
  828. LPPROPERTY pCurrHash,
  829. pNextHash;
  830. // Do I have any groups
  831. if (0 == m_cProps)
  832. return;
  833. // Loop through the item table
  834. for (i=0; i<CBUCKETS; i++)
  835. {
  836. // Is this chain empty ?
  837. if (m_prgHashTable[i])
  838. {
  839. // Walk the hash list
  840. pCurrHash = m_prgHashTable[i];
  841. // Loop the overflows
  842. while(pCurrHash)
  843. {
  844. // Save Next
  845. pNextHash = pCurrHash->pNextHash;
  846. // Release This Chain
  847. _FreePropertyChain(pCurrHash);
  848. // Goto Next
  849. pCurrHash = pNextHash;
  850. }
  851. // Set to NULL
  852. m_prgHashTable[i] = NULL;
  853. }
  854. }
  855. // Empty the arrays
  856. ZeroMemory(m_prgIndex, sizeof(m_prgIndex));
  857. // No Groups
  858. m_cProps = 0;
  859. m_rAdrTable.cAdrs = 0;
  860. m_rHdrTable.cRows = 0;
  861. m_rHdrTable.cEmpty = 0;
  862. m_rAdrTable.cEmpty = 0;
  863. }
  864. // ---------------------------------------------------------------------------
  865. // CMimePropertyContainer::_FreePropertyChain
  866. // ---------------------------------------------------------------------------
  867. void CMimePropertyContainer::_FreePropertyChain(LPPROPERTY pProperty)
  868. {
  869. // Locals
  870. LPPROPERTY pCurrValue,
  871. pNextValue;
  872. // Walk this list
  873. pCurrValue = pProperty;
  874. while(pCurrValue)
  875. {
  876. // Save Next Item
  877. pNextValue = pCurrValue->pNextValue;
  878. // Remove from header table
  879. if (pCurrValue->hRow)
  880. _UnlinkHeaderRow(pCurrValue->hRow);
  881. // Remove from address table
  882. if (pCurrValue->pGroup)
  883. _UnlinkAddressGroup(pCurrValue);
  884. // Free this item
  885. ObjectHeap_FreeProperty(pCurrValue);
  886. // Goto next
  887. pCurrValue = pNextValue;
  888. }
  889. }
  890. // ---------------------------------------------------------------------------
  891. // CMimePropertyContainer::_UnlinkHeaderRow
  892. // ---------------------------------------------------------------------------
  893. void CMimePropertyContainer::_UnlinkHeaderRow(HHEADERROW hRow)
  894. {
  895. // Validate the Handle
  896. Assert(_FIsValidHRow(hRow));
  897. // Get the row
  898. m_rHdrTable.prgpRow[HROWINDEX(hRow)] = NULL;
  899. // Increment Empty Count
  900. m_rHdrTable.cEmpty++;
  901. }
  902. // ---------------------------------------------------------------------------
  903. // CMimePropertyContainer::_UnlinkAddressGroup
  904. // ---------------------------------------------------------------------------
  905. void CMimePropertyContainer::_UnlinkAddressGroup(LPPROPERTY pProperty)
  906. {
  907. // Invalid Arg
  908. Assert(pProperty && pProperty->pGroup);
  909. // Free This Address Chain
  910. _FreeAddressChain(pProperty->pGroup);
  911. // Prepare for unlink
  912. LPPROPERTY pNext = pProperty->pGroup->pNext;
  913. LPPROPERTY pPrev = pProperty->pGroup->pPrev;
  914. // If Previious...
  915. if (pPrev)
  916. {
  917. Assert(pPrev->pGroup);
  918. pPrev->pGroup->pNext = pNext;
  919. }
  920. // If Next
  921. if (pNext)
  922. {
  923. Assert(pNext->pGroup);
  924. pNext->pGroup->pPrev = pPrev;
  925. }
  926. // Was this the header ?
  927. if (m_rAdrTable.pHead == pProperty)
  928. m_rAdrTable.pHead = pNext;
  929. if (m_rAdrTable.pTail == pProperty)
  930. m_rAdrTable.pTail = pPrev;
  931. // Clear the Group
  932. ZeroMemory(pProperty->pGroup, sizeof(ADDRESSGROUP));
  933. }
  934. // ---------------------------------------------------------------------------
  935. // CMimePropertyContainer::_FreeAddressChain
  936. // ---------------------------------------------------------------------------
  937. void CMimePropertyContainer::_FreeAddressChain(LPADDRESSGROUP pGroup)
  938. {
  939. // Locals
  940. LPMIMEADDRESS pCurr;
  941. LPMIMEADDRESS pNext;
  942. // Loop through data structures
  943. pCurr = pGroup->pHead;
  944. while(pCurr)
  945. {
  946. // Set Next
  947. pNext = pCurr->pNext;
  948. // Unlink this address
  949. _FreeAddress(pCurr);
  950. // Goto Next
  951. pCurr = pNext;
  952. }
  953. // Fixup the Group
  954. pGroup->pHead = NULL;
  955. pGroup->pTail = NULL;
  956. pGroup->cAdrs = 0;
  957. }
  958. // ---------------------------------------------------------------------------
  959. // CMimePropertyContainer::_FreeAddress
  960. // ---------------------------------------------------------------------------
  961. void CMimePropertyContainer::_FreeAddress(LPMIMEADDRESS pAddress)
  962. {
  963. // Validate the Handle
  964. Assert(_FIsValidHAddress(pAddress->hThis));
  965. // Get the row
  966. m_rAdrTable.prgpAdr[HADDRESSINDEX(pAddress->hThis)] = NULL;
  967. // Increment Empty Count
  968. m_rAdrTable.cEmpty++;
  969. // Free pCurr
  970. ObjectHeap_FreeAddress(pAddress);
  971. }
  972. // ---------------------------------------------------------------------------
  973. // CMimePropertyContainer::_UnlinkAddress
  974. // ---------------------------------------------------------------------------
  975. void CMimePropertyContainer::_UnlinkAddress(LPMIMEADDRESS pAddress)
  976. {
  977. // Invalid Arg
  978. Assert(pAddress && pAddress->pGroup);
  979. // Prepare for unlink
  980. LPMIMEADDRESS pNext = pAddress->pNext;
  981. LPMIMEADDRESS pPrev = pAddress->pPrev;
  982. // If Previious...
  983. if (pPrev)
  984. {
  985. Assert(pPrev->pGroup && pPrev->pGroup == pAddress->pGroup);
  986. pPrev->pNext = pNext;
  987. }
  988. // If Next
  989. if (pNext)
  990. {
  991. Assert(pNext->pGroup && pNext->pGroup == pAddress->pGroup);
  992. pNext->pPrev = pPrev;
  993. }
  994. // Was this the header ?
  995. if (pAddress->pGroup->pHead == pAddress)
  996. pAddress->pGroup->pHead = pNext;
  997. if (pAddress->pGroup->pTail == pAddress)
  998. pAddress->pGroup->pTail = pPrev;
  999. // Decrement Group Count
  1000. pAddress->pGroup->cAdrs--;
  1001. // Address group is dirty
  1002. pAddress->pGroup->fDirty = TRUE;
  1003. // Cleanup pAddress
  1004. pAddress->pNext = NULL;
  1005. pAddress->pPrev = NULL;
  1006. pAddress->pGroup = NULL;
  1007. }
  1008. // ---------------------------------------------------------------------------
  1009. // CMimePropertyContainer::_HrFindFirstProperty
  1010. // ---------------------------------------------------------------------------
  1011. HRESULT CMimePropertyContainer::_HrFindFirstProperty(LPFINDPROPERTY pFind, LPPROPERTY *ppProperty)
  1012. {
  1013. // Validate pFind
  1014. Assert(pFind->pszPrefix && pFind->pszName)
  1015. Assert(pFind->pszPrefix[pFind->cchPrefix] == '\0' && pFind->pszName[pFind->cchName] == '\0');
  1016. // Start with first hash table bucket
  1017. pFind->wHashIndex = 0;
  1018. // Start with first property in the hash table
  1019. pFind->pProperty = m_prgHashTable[pFind->wHashIndex];
  1020. // Find Next
  1021. return _HrFindNextProperty(pFind, ppProperty);
  1022. }
  1023. // ---------------------------------------------------------------------------
  1024. // CMimePropertyContainer::_HrFindNextProperty
  1025. // ---------------------------------------------------------------------------
  1026. HRESULT CMimePropertyContainer::_HrFindNextProperty(LPFINDPROPERTY pFind, LPPROPERTY *ppProperty)
  1027. {
  1028. // Locals
  1029. HRESULT hr=S_OK;
  1030. LPPROPSYMBOL pSymbol;
  1031. // Init
  1032. *ppProperty = NULL;
  1033. // Continue walking buckets
  1034. while (1)
  1035. {
  1036. // Continue looping chain
  1037. while (pFind->pProperty)
  1038. {
  1039. // Good Symbol
  1040. Assert(SUCCEEDED(HrIsValidSymbol(pFind->pProperty->pSymbol)));
  1041. // Readability
  1042. pSymbol = pFind->pProperty->pSymbol;
  1043. // Should I delete this one
  1044. if (pSymbol->cchName >= pFind->cchPrefix + pFind->cchName)
  1045. {
  1046. // Compare Prefix
  1047. if (StrCmpNI(pSymbol->pszName, pFind->pszPrefix, pFind->cchPrefix) == 0)
  1048. {
  1049. // Compare Name
  1050. if (StrCmpNI(pSymbol->pszName + pFind->cchPrefix, pFind->pszName, pFind->cchName) == 0)
  1051. {
  1052. // We found a property
  1053. *ppProperty = pFind->pProperty;
  1054. // Goto the next in the chain
  1055. pFind->pProperty = pFind->pProperty->pNextHash;
  1056. // Done
  1057. goto exit;
  1058. }
  1059. }
  1060. }
  1061. // Next in chain
  1062. pFind->pProperty = pFind->pProperty->pNextHash;
  1063. }
  1064. // Next Bucket
  1065. pFind->wHashIndex++;
  1066. // Done
  1067. if (pFind->wHashIndex >= CBUCKETS)
  1068. break;
  1069. // If not done, goto first item in the bucket
  1070. pFind->pProperty = m_prgHashTable[pFind->wHashIndex];
  1071. }
  1072. // NOt Found
  1073. hr = MIME_E_NOT_FOUND;
  1074. exit:
  1075. // Done
  1076. return hr;
  1077. }
  1078. // --------------------------------------------------------------------------------
  1079. // CMimePropertyContainer::_HrFindProperty
  1080. // --------------------------------------------------------------------------------
  1081. HRESULT CMimePropertyContainer::_HrFindProperty(LPPROPSYMBOL pSymbol, LPPROPERTY *ppProperty)
  1082. {
  1083. // Locals
  1084. HRESULT hr=S_OK;
  1085. BOOL fTryName=FALSE;
  1086. // Invalid Arg
  1087. Assert(pSymbol && ppProperty);
  1088. // By Known Symbol
  1089. if (ISKNOWNPID(pSymbol->dwPropId))
  1090. {
  1091. // Stats
  1092. #ifdef DEBUG
  1093. g_cSetPidLookups++;
  1094. #endif
  1095. // Is there data
  1096. if (m_prgIndex[pSymbol->dwPropId])
  1097. {
  1098. // Set It (could be NULL)
  1099. *ppProperty = m_prgIndex[pSymbol->dwPropId];
  1100. // Done
  1101. goto exit;
  1102. }
  1103. }
  1104. // Otherwise, lookup by name
  1105. else
  1106. {
  1107. // Stats
  1108. #ifdef DEBUG
  1109. g_cHashLookups++;
  1110. #endif
  1111. // Loop
  1112. Assert(pSymbol->wHashIndex < CBUCKETS);
  1113. for (LPPROPERTY pProperty=m_prgHashTable[pSymbol->wHashIndex]; pProperty!=NULL; pProperty=pProperty->pNextHash)
  1114. {
  1115. // Compare
  1116. if (pProperty && pProperty->pSymbol->dwPropId == pSymbol->dwPropId)
  1117. {
  1118. // Validate Hash Index
  1119. Assert(pProperty->pSymbol->wHashIndex == pSymbol->wHashIndex);
  1120. // Set Return
  1121. *ppProperty = pProperty;
  1122. // Done
  1123. goto exit;
  1124. }
  1125. }
  1126. }
  1127. // Not Found
  1128. hr = MIME_E_NOT_FOUND;
  1129. exit:
  1130. // Not Found
  1131. return hr;
  1132. }
  1133. // --------------------------------------------------------------------------------
  1134. // CMimePropertyContainer::_HrOpenProperty
  1135. // --------------------------------------------------------------------------------
  1136. HRESULT CMimePropertyContainer::_HrOpenProperty(LPPROPSYMBOL pSymbol, LPPROPERTY *ppProperty)
  1137. {
  1138. // If we dont find it, try to create it
  1139. if (FAILED(_HrFindProperty(pSymbol, ppProperty)))
  1140. return TrapError(_HrCreateProperty(pSymbol, ppProperty));
  1141. // We Found It, return
  1142. return S_OK;
  1143. }
  1144. // --------------------------------------------------------------------------------
  1145. // CMimePropertyContainer::_HrCreateProperty
  1146. // --------------------------------------------------------------------------------
  1147. HRESULT CMimePropertyContainer::_HrCreateProperty(LPPROPSYMBOL pSymbol, LPPROPERTY *ppProperty)
  1148. {
  1149. // Locals
  1150. HRESULT hr=S_OK;
  1151. LPPROPERTY pProperty;
  1152. #ifdef DEBUG
  1153. LPPROPERTY pTemp;
  1154. #endif
  1155. // Invalid Arg
  1156. Assert(pSymbol && ppProperty);
  1157. // Allocate an item...
  1158. CHECKHR(hr = ObjectHeap_HrAllocProperty(&pProperty));
  1159. // Set the symbol
  1160. pProperty->pSymbol = pSymbol;
  1161. // The Property Better Not Exist Yet (Assumes caller did a FindProperty before CreateProperty)
  1162. Assert(_HrFindProperty(pSymbol, &pTemp) == MIME_E_NOT_FOUND);
  1163. // MPF_HEADER
  1164. if (ISFLAGSET(pSymbol->dwFlags, MPF_HEADER))
  1165. {
  1166. // Insert into the header table
  1167. CHECKHR(hr = _HrAppendHeaderTable(pProperty));
  1168. }
  1169. // MPF_ADDRESS
  1170. if (ISFLAGSET(pSymbol->dwFlags, MPF_ADDRESS))
  1171. {
  1172. // Insert into the header table
  1173. CHECKHR(hr = _HrAppendAddressTable(pProperty));
  1174. }
  1175. // Stats
  1176. #ifdef DEBUG
  1177. g_cHashInserts++;
  1178. if (m_prgHashTable[pSymbol->wHashIndex])
  1179. g_cHashCollides++;
  1180. #endif
  1181. // Set Next Hash Item
  1182. Assert(pSymbol->wHashIndex < CBUCKETS);
  1183. pProperty->pNextHash = m_prgHashTable[pSymbol->wHashIndex];
  1184. // New Properties are places as the head of the overflow chain
  1185. m_prgHashTable[pSymbol->wHashIndex] = pProperty;
  1186. // Insert into Known Property Index
  1187. if (ISKNOWNPID(pSymbol->dwPropId))
  1188. {
  1189. Assert(m_prgIndex[pSymbol->dwPropId] == NULL);
  1190. m_prgIndex[pSymbol->dwPropId] = pProperty;
  1191. }
  1192. // PRSTATE_PARENT
  1193. FLAGSET(pProperty->dwState, PRSTATE_PARENT);
  1194. // Return this prop
  1195. *ppProperty = pProperty;
  1196. // Count Properties
  1197. m_cProps++;
  1198. exit:
  1199. // Done
  1200. return hr;
  1201. }
  1202. // --------------------------------------------------------------------------------
  1203. // CMimePropertyContainer::_HrAppendProperty
  1204. // --------------------------------------------------------------------------------
  1205. HRESULT CMimePropertyContainer::_HrAppendProperty(LPPROPSYMBOL pSymbol, LPPROPERTY *ppProperty)
  1206. {
  1207. // Locals
  1208. HRESULT hr=S_OK;
  1209. LPPROPERTY pParent,
  1210. pAppend;
  1211. // Invalid Arg
  1212. Assert(pSymbol && ppProperty);
  1213. // Does pTag already exist ?
  1214. if (SUCCEEDED(_HrFindProperty(pSymbol, &pParent)))
  1215. {
  1216. // Better be a parent property
  1217. Assert(ISFLAGSET(pParent->dwState, PRSTATE_PARENT));
  1218. // Allocate an item...
  1219. CHECKHR(hr = ObjectHeap_HrAllocProperty(&pAppend));
  1220. // pSymbol From pTag
  1221. pAppend->pSymbol = pParent->pSymbol;
  1222. // If this is a header property, insert into the header table
  1223. if (ISFLAGSET(pSymbol->dwFlags, MPF_HEADER))
  1224. {
  1225. // Insert into the header table
  1226. CHECKHR(hr = _HrAppendHeaderTable(pAppend));
  1227. }
  1228. // MPF_ADDRESS
  1229. if (ISFLAGSET(pSymbol->dwFlags, MPF_ADDRESS))
  1230. {
  1231. // Insert into the header table
  1232. CHECKHR(hr = _HrAppendAddressTable(pAppend));
  1233. }
  1234. // Update pParent->pTailData
  1235. if (NULL == pParent->pNextValue)
  1236. {
  1237. Assert(NULL == pParent->pTailValue);
  1238. pParent->pNextValue = pAppend;
  1239. pParent->pTailValue = pAppend;
  1240. }
  1241. else
  1242. {
  1243. Assert(pParent->pTailValue && pParent->pTailValue->pNextValue == NULL);
  1244. pParent->pTailValue->pNextValue = pAppend;
  1245. pParent->pTailValue = pAppend;
  1246. }
  1247. // Return this prop
  1248. *ppProperty = pAppend;
  1249. // Count Properties
  1250. m_cProps++;
  1251. }
  1252. // Otherwise, create a new property
  1253. else
  1254. {
  1255. // Create It
  1256. CHECKHR(hr = _HrCreateProperty(pSymbol, ppProperty));
  1257. }
  1258. exit:
  1259. // Done
  1260. return hr;
  1261. }
  1262. // --------------------------------------------------------------------------------
  1263. // CMimePropertyContainer::_HrAppendAddressGroup
  1264. // --------------------------------------------------------------------------------
  1265. HRESULT CMimePropertyContainer::_HrAppendAddressGroup(LPADDRESSGROUP pGroup, LPMIMEADDRESS *ppAddress)
  1266. {
  1267. // Locals
  1268. HRESULT hr=S_OK;
  1269. ULONG i=0;
  1270. BOOL fUsingEmpty=FALSE;
  1271. LPMIMEADDRESS pAddress;
  1272. // Use Empty Cell
  1273. if (m_rAdrTable.cEmpty)
  1274. {
  1275. // Find First Empty Cell..
  1276. for (i=0; i<m_rAdrTable.cAdrs; i++)
  1277. {
  1278. // Empty ?
  1279. if (NULL == m_rAdrTable.prgpAdr[i])
  1280. {
  1281. fUsingEmpty = TRUE;
  1282. break;
  1283. }
  1284. }
  1285. }
  1286. // If not using empty
  1287. if (FALSE == fUsingEmpty)
  1288. {
  1289. // Lets grow the table first...
  1290. if (m_rAdrTable.cAdrs + 1 > m_rAdrTable.cAlloc)
  1291. {
  1292. // Grow my current property value array
  1293. CHECKHR(hr = HrRealloc((LPVOID *)&m_rAdrTable.prgpAdr, sizeof(LPMIMEADDRESS) * (m_rAdrTable.cAlloc + 10)));
  1294. // Increment alloc size
  1295. m_rAdrTable.cAlloc += 10;
  1296. }
  1297. // Index to use
  1298. i = m_rAdrTable.cAdrs;
  1299. }
  1300. // Allocate an address props structure
  1301. CHECKHR(hr = ObjectHeap_HrAllocAddress(&pAddress));
  1302. // Assign a Handle
  1303. pAddress->hThis = HADDRESSMAKE(i);
  1304. // Link the Address into the group
  1305. _LinkAddress(pAddress, pGroup);
  1306. // Put it into the Array
  1307. m_rAdrTable.prgpAdr[i] = pAddress;
  1308. // Return It
  1309. *ppAddress = pAddress;
  1310. // If not using empty cell, increment body count
  1311. if (FALSE == fUsingEmpty)
  1312. m_rAdrTable.cAdrs++;
  1313. else
  1314. m_rAdrTable.cEmpty--;
  1315. exit:
  1316. // Done
  1317. return hr;
  1318. }
  1319. // --------------------------------------------------------------------------------
  1320. // CMimePropertyContainer::_LinkAddress
  1321. // --------------------------------------------------------------------------------
  1322. void CMimePropertyContainer::_LinkAddress(LPMIMEADDRESS pAddress, LPADDRESSGROUP pGroup)
  1323. {
  1324. // Validate Arg
  1325. Assert(pAddress && pGroup && NULL == pAddress->pNext && NULL == pAddress->pPrev);
  1326. // Put pGroup into pAddress
  1327. pAddress->pGroup = pGroup;
  1328. // Link into the list
  1329. if (NULL == pGroup->pHead)
  1330. {
  1331. Assert(NULL == pGroup->pTail);
  1332. pGroup->pHead = pAddress;
  1333. pGroup->pTail = pAddress;
  1334. }
  1335. else
  1336. {
  1337. Assert(pGroup->pTail && pGroup->pTail->pNext == NULL);
  1338. pGroup->pTail->pNext = pAddress;
  1339. pAddress->pPrev = pGroup->pTail;
  1340. pGroup->pTail = pAddress;
  1341. }
  1342. // Increment Count
  1343. pGroup->cAdrs++;
  1344. }
  1345. // --------------------------------------------------------------------------------
  1346. // CMimePropertyContainer::_HrAppendAddressTable
  1347. // --------------------------------------------------------------------------------
  1348. HRESULT CMimePropertyContainer::_HrAppendAddressTable(LPPROPERTY pProperty)
  1349. {
  1350. // Locals
  1351. HRESULT hr=S_OK;
  1352. // Invalid Arg
  1353. Assert(pProperty && NULL == pProperty->pGroup);
  1354. // New Group
  1355. CHECKALLOC(pProperty->pGroup = (LPADDRESSGROUP)g_pMalloc->Alloc(sizeof(ADDRESSGROUP)));
  1356. // ZeroInit
  1357. ZeroMemory(pProperty->pGroup, sizeof(ADDRESSGROUP));
  1358. // Link this group
  1359. if (NULL == m_rAdrTable.pHead)
  1360. {
  1361. Assert(m_rAdrTable.pTail == NULL);
  1362. m_rAdrTable.pHead = pProperty;
  1363. m_rAdrTable.pTail = pProperty;
  1364. }
  1365. else
  1366. {
  1367. Assert(m_rAdrTable.pTail && m_rAdrTable.pTail->pGroup && m_rAdrTable.pTail->pGroup->pNext == NULL);
  1368. m_rAdrTable.pTail->pGroup->pNext = pProperty;
  1369. pProperty->pGroup->pPrev = m_rAdrTable.pTail;
  1370. m_rAdrTable.pTail = pProperty;
  1371. }
  1372. exit:
  1373. // Done
  1374. return hr;
  1375. }
  1376. // --------------------------------------------------------------------------------
  1377. // CMimePropertyContainer::_HrAppendHeaderTable
  1378. // --------------------------------------------------------------------------------
  1379. HRESULT CMimePropertyContainer::_HrAppendHeaderTable(LPPROPERTY pProperty)
  1380. {
  1381. // Locals
  1382. HRESULT hr=S_OK;
  1383. ULONG i=0;
  1384. BOOL fUsingEmpty=FALSE;
  1385. // Invalid Arg
  1386. Assert(pProperty && NULL == pProperty->hRow);
  1387. // Use Empty Cell
  1388. if (m_rHdrTable.cEmpty)
  1389. {
  1390. // Find First Empty Cell..
  1391. for (i=0; i<m_rHdrTable.cRows; i++)
  1392. {
  1393. // Empty ?
  1394. if (NULL == m_rHdrTable.prgpRow)
  1395. {
  1396. fUsingEmpty = TRUE;
  1397. break;
  1398. }
  1399. }
  1400. }
  1401. // If not using empty
  1402. if (FALSE == fUsingEmpty)
  1403. {
  1404. // Lets grow the table first...
  1405. if (m_rHdrTable.cRows + 1 > m_rHdrTable.cAlloc)
  1406. {
  1407. // Grow my current property value array
  1408. CHECKHR(hr = HrRealloc((LPVOID *)&m_rHdrTable.prgpRow, sizeof(LPPROPERTY) * (m_rHdrTable.cAlloc + 10)));
  1409. // Increment alloc size
  1410. m_rHdrTable.cAlloc += 10;
  1411. }
  1412. // Index to use
  1413. i = m_rHdrTable.cRows;
  1414. }
  1415. // Save Property index table
  1416. m_rHdrTable.prgpRow[i] = pProperty;
  1417. // Set Handle
  1418. pProperty->hRow = HROWMAKE(i);
  1419. // If not using empty cell, increment body count
  1420. if (FALSE == fUsingEmpty)
  1421. m_rHdrTable.cRows++;
  1422. else
  1423. m_rHdrTable.cEmpty--;
  1424. exit:
  1425. // Done
  1426. return hr;
  1427. }
  1428. // --------------------------------------------------------------------------------
  1429. // CMimePropertyContainer::IsPropSet
  1430. // --------------------------------------------------------------------------------
  1431. HRESULT CMimePropertyContainer::IsPropSet(LPCSTR pszName)
  1432. {
  1433. // Locals
  1434. HRESULT hr=S_FALSE;
  1435. LPPROPSYMBOL pSymbol;
  1436. LPPROPERTY pProperty;
  1437. // Invalid Arg
  1438. if (NULL == pszName)
  1439. return TrapError(E_INVALIDARG);
  1440. // Thread Safety
  1441. EnterCriticalSection(&m_cs);
  1442. // Find the Symbol
  1443. if (FAILED(g_pSymCache->HrOpenSymbol(pszName, FALSE, &pSymbol)))
  1444. goto exit;
  1445. // Find the Property
  1446. if (FAILED(_HrFindProperty(pSymbol, &pProperty)))
  1447. goto exit;
  1448. // Its Set
  1449. hr = S_OK;
  1450. exit:
  1451. // Thread Safety
  1452. LeaveCriticalSection(&m_cs);
  1453. // Done
  1454. return hr;
  1455. }
  1456. // --------------------------------------------------------------------------------
  1457. // CMimePropertyContainer::GetPropInfo
  1458. // --------------------------------------------------------------------------------
  1459. STDMETHODIMP CMimePropertyContainer::GetPropInfo(LPCSTR pszName, LPMIMEPROPINFO pInfo)
  1460. {
  1461. // Locals
  1462. HRESULT hr=S_OK;
  1463. LPPROPSYMBOL pSymbol;
  1464. LPPROPERTY pProperty;
  1465. LPPROPERTY pCurr;
  1466. // Invalid Arg
  1467. if (NULL == pszName || NULL == pInfo)
  1468. return TrapError(E_INVALIDARG);
  1469. // Thread Safety
  1470. EnterCriticalSection(&m_cs);
  1471. // Find the Symbol
  1472. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pszName, FALSE, &pSymbol));
  1473. // Find the Property
  1474. CHECKHR(hr = _HrFindProperty(pSymbol, &pProperty));
  1475. // PIM_CHARSET
  1476. if (ISFLAGSET(pInfo->dwMask, PIM_CHARSET))
  1477. {
  1478. // Get Charset
  1479. pInfo->hCharset = pProperty->pCharset ? pProperty->pCharset->hCharset : m_rOptions.pDefaultCharset->hCharset;
  1480. }
  1481. // PIM_ENCODINGTYPE
  1482. if (ISFLAGSET(pInfo->dwMask, PIM_ENCODINGTYPE))
  1483. {
  1484. // Get Encoding
  1485. pInfo->ietEncoding = pProperty->ietValue;
  1486. }
  1487. // PIM_ROWNUMBER
  1488. if (ISFLAGSET(pInfo->dwMask, PIM_ROWNUMBER))
  1489. pInfo->dwRowNumber = pProperty->dwRowNumber;
  1490. // PIM_FLAGS
  1491. if (ISFLAGSET(pInfo->dwMask, PIM_FLAGS))
  1492. pInfo->dwFlags = pProperty->pSymbol->dwFlags;
  1493. // PIM_PROPID
  1494. if (ISFLAGSET(pInfo->dwMask, PIM_PROPID))
  1495. pInfo->dwPropId = pProperty->pSymbol->dwPropId;
  1496. // PIM_VALUES
  1497. if (ISFLAGSET(pInfo->dwMask, PIM_VALUES))
  1498. {
  1499. // Let me count the ways
  1500. for(pCurr=pProperty, pInfo->cValues=0; pCurr!=NULL; pCurr=pCurr->pNextValue)
  1501. pInfo->cValues++;
  1502. }
  1503. // PIM_VTCURRENT
  1504. if (ISFLAGSET(pInfo->dwMask, PIM_VTCURRENT))
  1505. pInfo->vtCurrent = MimeVT_To_PropVT(&pProperty->rValue);
  1506. // PIM_VTDEFAULT
  1507. if (ISFLAGSET(pInfo->dwMask, PIM_VTDEFAULT))
  1508. pInfo->vtDefault = pProperty->pSymbol->vtDefault;
  1509. exit:
  1510. // Thread Safety
  1511. LeaveCriticalSection(&m_cs);
  1512. // Done
  1513. return hr;
  1514. }
  1515. // --------------------------------------------------------------------------------
  1516. // CMimePropertyContainer::SetPropInfo
  1517. // --------------------------------------------------------------------------------
  1518. STDMETHODIMP CMimePropertyContainer::SetPropInfo(LPCSTR pszName, LPCMIMEPROPINFO pInfo)
  1519. {
  1520. // Locals
  1521. HRESULT hr=S_OK;
  1522. LPPROPSYMBOL pSymbol;
  1523. LPPROPERTY pProperty;
  1524. LPPROPERTY pCurr;
  1525. LPINETCSETINFO pCharset;
  1526. // Invalid Arg
  1527. if (NULL == pszName || NULL == pInfo)
  1528. return TrapError(E_INVALIDARG);
  1529. // Thread Safety
  1530. EnterCriticalSection(&m_cs);
  1531. // Find the Symbol
  1532. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pszName, FALSE, &pSymbol));
  1533. // Find the Property
  1534. CHECKHR(hr = _HrFindProperty(pSymbol, &pProperty));
  1535. // Set All Values with the property information
  1536. for(pCurr=pProperty; pCurr!=NULL; pCurr=pCurr->pNextValue)
  1537. {
  1538. // PIM_CHARSET
  1539. if (ISFLAGSET(pInfo->dwMask, PIM_CHARSET))
  1540. {
  1541. // Open the Charset
  1542. if (SUCCEEDED(g_pInternat->HrOpenCharset(pInfo->hCharset, &pCharset)))
  1543. pProperty->pCharset = pCharset;
  1544. }
  1545. // PIM_ENCODED
  1546. if (ISFLAGSET(pInfo->dwMask, PIM_ENCODINGTYPE))
  1547. {
  1548. // Change Encoding State of the mime Variant
  1549. pProperty->ietValue = (IET_ENCODED == pInfo->ietEncoding) ? IET_ENCODED : IET_DECODED;
  1550. }
  1551. // PIM_ROWNUMBER
  1552. if (ISFLAGSET(pInfo->dwMask, PIM_ROWNUMBER))
  1553. {
  1554. // Save the Row Number
  1555. pCurr->dwRowNumber = pInfo->dwRowNumber;
  1556. // Make a note that the use set this row number so the save order doesn't get hosed
  1557. FLAGSET(pCurr->dwState, PRSTATE_USERSETROWNUM);
  1558. }
  1559. }
  1560. exit:
  1561. // Thread Safety
  1562. LeaveCriticalSection(&m_cs);
  1563. // Done
  1564. return hr;
  1565. }
  1566. // --------------------------------------------------------------------------------
  1567. // CMimePropertyContainer::EnumProps
  1568. // --------------------------------------------------------------------------------
  1569. STDMETHODIMP CMimePropertyContainer::EnumProps(DWORD dwFlags, IMimeEnumProperties **ppEnum)
  1570. {
  1571. // Locals
  1572. HRESULT hr=S_OK;
  1573. ULONG i,
  1574. cProps=0,
  1575. cAlloc=0;
  1576. LPENUMPROPERTY prgProp=NULL;
  1577. LPPROPERTY pCurrProp;
  1578. CMimeEnumProperties *pEnum=NULL;
  1579. // Invalid Arg
  1580. if (NULL == ppEnum)
  1581. return TrapError(E_INVALIDARG);
  1582. // Init
  1583. *ppEnum = NULL;
  1584. // Thread Safety
  1585. EnterCriticalSection(&m_cs);
  1586. // Loop through the item table
  1587. for (i=0; i<CBUCKETS; i++)
  1588. {
  1589. // Walk the Hash Chain
  1590. for (pCurrProp=m_prgHashTable[i]; pCurrProp!=NULL; pCurrProp=pCurrProp->pNextHash)
  1591. {
  1592. // Grow the array ?
  1593. if (cProps + 1 > cAlloc)
  1594. {
  1595. // Realloc
  1596. CHECKALLOC(prgProp = (LPENUMPROPERTY)g_pMalloc->Realloc((LPVOID)prgProp, sizeof(ENUMPROPERTY) * (cAlloc + 10)));
  1597. // Increment cAlloc
  1598. cAlloc += 10;
  1599. }
  1600. // hRow
  1601. prgProp[cProps].hRow = pCurrProp->hRow;
  1602. // dwPropId
  1603. prgProp[cProps].dwPropId = pCurrProp->pSymbol->dwPropId;
  1604. // Init Name to Null
  1605. prgProp[cProps].pszName = NULL;
  1606. // Name
  1607. if (ISFLAGSET(dwFlags, EPF_NONAME) == FALSE)
  1608. {
  1609. // Return name
  1610. CHECKALLOC(prgProp[cProps].pszName = PszDupA(pCurrProp->pSymbol->pszName));
  1611. }
  1612. // Increment iProp
  1613. cProps++;
  1614. }
  1615. }
  1616. // Allocate
  1617. CHECKALLOC(pEnum = new CMimeEnumProperties);
  1618. // Initialize
  1619. CHECKHR(hr = pEnum->HrInit(0, cProps, prgProp, FALSE));
  1620. // Don't Free pEnumRow
  1621. prgProp = NULL;
  1622. cProps = 0;
  1623. // Return it
  1624. (*ppEnum) = (IMimeEnumProperties *)pEnum;
  1625. (*ppEnum)->AddRef();
  1626. exit:
  1627. // Cleanup
  1628. SafeRelease(pEnum);
  1629. g_pMoleAlloc->FreeEnumPropertyArray(cProps, prgProp, TRUE);
  1630. // Thread Safety
  1631. LeaveCriticalSection(&m_cs);
  1632. // Done
  1633. return hr;
  1634. }
  1635. // --------------------------------------------------------------------------------
  1636. // CMimePropertyContainer::BindToObject
  1637. // --------------------------------------------------------------------------------
  1638. HRESULT CMimePropertyContainer::BindToObject(REFIID riid, void **ppvObject)
  1639. {
  1640. return TrapError(QueryInterface(riid, ppvObject));
  1641. }
  1642. // --------------------------------------------------------------------------------
  1643. // CMimePropertyContainer::_HrBuildAddressString
  1644. // --------------------------------------------------------------------------------
  1645. HRESULT CMimePropertyContainer::_HrBuildAddressString(LPPROPERTY pProperty, DWORD dwFlags, LPMIMEVARIANT pValue)
  1646. {
  1647. // Locals
  1648. HRESULT hr=S_OK;
  1649. ULONG cAddrsWrote=0;
  1650. LPSTREAM pStream=NULL;
  1651. CByteStream cByteStream;
  1652. LPPROPERTY pCurrValue;
  1653. MIMEVARIANT rValue;
  1654. ADDRESSFORMAT format;
  1655. LPINETCSETINFO pCharsetSource=NULL;
  1656. // Invalid Arg
  1657. Assert(pProperty && pValue);
  1658. // Variant Not Supported
  1659. if (MVT_VARIANT == pValue->type)
  1660. return TrapError(MIME_E_VARTYPE_NO_CONVERT);
  1661. if (MVT_STRINGW == pValue->type && ISFLAGSET(dwFlags, PDF_ENCODED))
  1662. return TrapError(MIME_E_VARTYPE_NO_CONVERT);
  1663. // Init
  1664. ZeroMemory(&rValue, sizeof(MIMEVARIANT));
  1665. // I need a stream to write to...
  1666. if (MVT_STREAM == pValue->type)
  1667. {
  1668. // Validate the stream
  1669. if (NULL == pValue->pStream)
  1670. {
  1671. hr = TrapError(E_INVALIDARG);
  1672. goto exit;
  1673. }
  1674. // Save the Stream
  1675. pStream = pValue->pStream;
  1676. }
  1677. // Otherwise, create my own stream
  1678. else
  1679. pStream = &cByteStream;
  1680. // Decide on a format
  1681. if (ISFLAGSET(dwFlags, PDF_HEADERFORMAT))
  1682. format = AFT_RFC822_TRANSMIT;
  1683. else if (ISFLAGSET(dwFlags, PDF_ENCODED))
  1684. format = AFT_RFC822_ENCODED;
  1685. else
  1686. format = AFT_DISPLAY_BOTH;
  1687. // If Writing Transmit (Write Header Name)
  1688. if (ISFLAGSET(dwFlags, PDF_NAMEINDATA))
  1689. {
  1690. // Write the header name
  1691. CHECKHR(hr = pStream->Write(pProperty->pSymbol->pszName, pProperty->pSymbol->cchName, NULL));
  1692. // Write Colon
  1693. CHECKHR(hr = pStream->Write(c_szColonSpace, lstrlen(c_szColonSpace), NULL));
  1694. }
  1695. // Save with no encoding
  1696. if (ISFLAGSET(pProperty->dwState, PRSTATE_SAVENOENCODE))
  1697. {
  1698. // Better be groupdirty
  1699. Assert(ISFLAGSET(pProperty->dwState, PRSTATE_NEEDPARSE));
  1700. // Convert Data...
  1701. rValue.type = MVT_STRINGA;
  1702. // Destination is not encoded
  1703. pCharsetSource = pProperty->pCharset ? pProperty->pCharset : m_rOptions.pDefaultCharset;
  1704. // Convert It
  1705. CHECKHR(hr = HrConvertVariant(pProperty, CVF_NOALLOC | PDF_ENCODED, &rValue));
  1706. // Write it to the stream
  1707. CHECKHR(hr = pStream->Write(rValue.rStringA.pszVal, rValue.rStringA.cchVal, NULL));
  1708. }
  1709. // Otherwise, normal save
  1710. else
  1711. {
  1712. // Loop through parsed addresses...
  1713. for (pCurrValue=pProperty; pCurrValue!=NULL; pCurrValue=pCurrValue->pNextValue)
  1714. {
  1715. // We should have an address
  1716. Assert(pCurrValue->pGroup && ISFLAGSET(pCurrValue->pSymbol->dwFlags, MPF_ADDRESS));
  1717. // Does the Property need to be parsed ?
  1718. CHECKHR(hr = _HrParseInternetAddress(pCurrValue));
  1719. // Tell each address group object to write its data to the stream
  1720. if (pCurrValue->pGroup)
  1721. {
  1722. // Write the data
  1723. CHECKHR(hr = _HrSaveAddressGroup(pCurrValue, pStream, &cAddrsWrote, format, VT_LPSTR));
  1724. }
  1725. // Set It Yet ?
  1726. if (NULL == pCharsetSource)
  1727. {
  1728. pCharsetSource = pCurrValue->pCharset ? pCurrValue->pCharset : m_rOptions.pDefaultCharset;
  1729. }
  1730. // No Vectoring
  1731. if (FALSE == ISFLAGSET(dwFlags, PDF_VECTOR))
  1732. break;
  1733. }
  1734. }
  1735. // Transmit
  1736. if (ISFLAGSET(dwFlags, PDF_HEADERFORMAT))
  1737. {
  1738. // Final CRLF if Transmit Format
  1739. CHECKHR(hr = pStream->Write(g_szCRLF, lstrlen(g_szCRLF), NULL));
  1740. }
  1741. // Final CRLF
  1742. if (cAddrsWrote || ISFLAGSET(dwFlags, PDF_NAMEINDATA) || ISFLAGSET(dwFlags,PDF_HEADERFORMAT))
  1743. {
  1744. // MVT_STRINGA
  1745. if (MVT_STRINGA == pValue->type)
  1746. {
  1747. // pStream better be the byte stream
  1748. Assert(pStream == &cByteStream);
  1749. // Get string from stream...
  1750. CHECKHR(hr = cByteStream.HrAcquireStringA(&pValue->rStringA.cchVal, &pValue->rStringA.pszVal, ACQ_DISPLACE));
  1751. }
  1752. // MVT_STRINGW
  1753. else if (MVT_STRINGW == pValue->type)
  1754. {
  1755. // Locals
  1756. CODEPAGEID cpSource=CP_ACP;
  1757. PROPSTRINGA rStringA;
  1758. // Init
  1759. ZeroMemory(&rStringA, sizeof(PROPSTRINGA));
  1760. // pStream better be the byte stream
  1761. Assert(pStream == &cByteStream);
  1762. // Get string from stream...
  1763. CHECKHR(hr = cByteStream.HrAcquireStringA(&rStringA.cchVal, &rStringA.pszVal, ACQ_COPY));
  1764. // Determine cpSoruce
  1765. if (pCharsetSource)
  1766. {
  1767. // If Encoded, use internet codepage, otherwise, use Windows codepage
  1768. cpSource = ISFLAGSET(dwFlags, PDF_ENCODED) ? pCharsetSource->cpiInternet : MimeOleGetWindowsCPEx(pCharsetSource);
  1769. }
  1770. // Convert to Unicode
  1771. CHECKHR(hr = g_pInternat->HrMultiByteToWideChar(cpSource, &rStringA, &pValue->rStringW));
  1772. }
  1773. else
  1774. Assert(MVT_STREAM == pValue->type);
  1775. }
  1776. // No Data
  1777. else
  1778. {
  1779. hr = MIME_E_NO_DATA;
  1780. goto exit;
  1781. }
  1782. exit:
  1783. // Cleanup
  1784. MimeVariantFree(&rValue);
  1785. // Done
  1786. return hr;
  1787. }
  1788. // --------------------------------------------------------------------------------
  1789. // CMimePropertyContainer::_HrBuildParameterString
  1790. // --------------------------------------------------------------------------------
  1791. HRESULT CMimePropertyContainer::_HrBuildParameterString(LPPROPERTY pProperty, DWORD dwFlags, LPMIMEVARIANT pValue)
  1792. {
  1793. // Locals
  1794. HRESULT hr=S_OK,
  1795. hrFind;
  1796. LPSTR pszParamName;
  1797. LPSTR pszEscape=NULL;
  1798. FINDPROPERTY rFind;
  1799. LPPROPERTY pParameter;
  1800. LPSTREAM pStream=NULL;
  1801. CByteStream cByteStream;
  1802. BOOL fQuoted;
  1803. ULONG cWrote=0;
  1804. MIMEVARIANT rValue;
  1805. // Invalid Arg
  1806. Assert(pProperty && pProperty->pNextValue == NULL && pValue);
  1807. Assert(ISSTRINGA(&pProperty->rValue));
  1808. // Variant Not Supported
  1809. if (MVT_VARIANT == pValue->type)
  1810. return TrapError(MIME_E_VARTYPE_NO_CONVERT);
  1811. if (MVT_STRINGW == pValue->type && ISFLAGSET(dwFlags, PDF_ENCODED))
  1812. return TrapError(MIME_E_VARTYPE_NO_CONVERT);
  1813. // Init rValue
  1814. ZeroMemory(&rValue, sizeof(MIMEVARIANT));
  1815. // I need a stream to write to...
  1816. if (MVT_STREAM == pValue->type)
  1817. {
  1818. // Validate the stream
  1819. if (NULL == pValue->pStream)
  1820. {
  1821. hr = TrapError(E_INVALIDARG);
  1822. goto exit;
  1823. }
  1824. // Save the Stream
  1825. pStream = pValue->pStream;
  1826. }
  1827. // Otherwise, create my own stream
  1828. else
  1829. pStream = &cByteStream;
  1830. // If Writing Transmit (Write Header Name)
  1831. if (ISFLAGSET(dwFlags, PDF_NAMEINDATA))
  1832. {
  1833. // Write the header name
  1834. CHECKHR(hr = pStream->Write(pProperty->pSymbol->pszName, pProperty->pSymbol->cchName, NULL));
  1835. // Write Colon
  1836. CHECKHR(hr = pStream->Write(c_szColonSpace, lstrlen(c_szColonSpace), NULL));
  1837. }
  1838. // Write First Prop
  1839. CHECKHR(hr = pStream->Write(pProperty->rValue.rStringA.pszVal, pProperty->rValue.rStringA.cchVal, NULL));
  1840. // We wrote one item
  1841. cWrote = 1;
  1842. // Initialize rFind
  1843. ZeroMemory(&rFind, sizeof(FINDPROPERTY));
  1844. rFind.pszPrefix = "par:";
  1845. rFind.cchPrefix = 4;
  1846. rFind.pszName = pProperty->pSymbol->pszName;
  1847. rFind.cchName = pProperty->pSymbol->cchName;
  1848. // Find First..
  1849. hrFind = _HrFindFirstProperty(&rFind, &pParameter);
  1850. while(SUCCEEDED(hrFind) && pParameter)
  1851. {
  1852. // Transmit Format
  1853. if (ISFLAGSET(dwFlags, PDF_HEADERFORMAT))
  1854. {
  1855. // Write ';\r\n\t'
  1856. CHECKHR(hr = pStream->Write(c_szParamFold, lstrlen(c_szParamFold), NULL));
  1857. }
  1858. // Otherwise
  1859. else
  1860. {
  1861. // Write ';\r\n\t'
  1862. CHECKHR(hr = pStream->Write(c_szSemiColonSpace, lstrlen(c_szSemiColonSpace), NULL));
  1863. }
  1864. // Get Parameter Name
  1865. pszParamName = PszScanToCharA((LPSTR)pParameter->pSymbol->pszName, ':');
  1866. pszParamName++;
  1867. pszParamName = PszScanToCharA(pszParamName, ':');
  1868. pszParamName++;
  1869. // Write the name
  1870. CHECKHR(hr = pStream->Write(pszParamName, lstrlen(pszParamName), NULL));
  1871. // Write the property...
  1872. CHECKHR(hr = pStream->Write(c_szEqual, lstrlen(c_szEqual), NULL));
  1873. // Convert Data...
  1874. rValue.type = MVT_STRINGA;
  1875. // Convert It
  1876. CHECKHR(hr = HrConvertVariant(pParameter, CVF_NOALLOC | PDF_ENCODED, &rValue));
  1877. // Quoted
  1878. fQuoted = FALSE;
  1879. if (lstrcmpi(pszParamName, (LPSTR)c_szBoundary) == 0 || lstrcmpi(pszParamName, (LPSTR)c_szFileName) == 0 ||
  1880. lstrcmpi(pszParamName, (LPSTR)c_szName) == 0 || lstrcmpi(pszParamName, (LPSTR)c_szID) == 0 ||
  1881. lstrcmpi(pszParamName, (LPSTR)c_szCharset) == 0)
  1882. fQuoted = TRUE;
  1883. // Otherwise, check for must quote characters
  1884. else
  1885. {
  1886. // Loop the string
  1887. for (ULONG i=0; i<rValue.rStringA.cchVal; i++)
  1888. {
  1889. // Must quote character
  1890. if (rValue.rStringA.pszVal[i] == ';' ||
  1891. rValue.rStringA.pszVal[i] == '\"' ||
  1892. rValue.rStringA.pszVal[i] == '/' ||
  1893. rValue.rStringA.pszVal[i] == '\""' ||
  1894. rValue.rStringA.pszVal[i] == '\'' ||
  1895. rValue.rStringA.pszVal[i] == '=')
  1896. {
  1897. fQuoted = TRUE;
  1898. break;
  1899. }
  1900. }
  1901. }
  1902. // Quoted
  1903. if (fQuoted)
  1904. {
  1905. CHECKHR(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
  1906. CHECKHR(hr = pStream->Write(rValue.rStringA.pszVal, rValue.rStringA.cchVal, NULL));
  1907. CHECKHR(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
  1908. }
  1909. // Ohterwise, just write the data
  1910. else
  1911. {
  1912. // Set pszValue
  1913. LPSTR pszValue = rValue.rStringA.pszVal;
  1914. ULONG cchValue = rValue.rStringA.cchVal;
  1915. // Escape It
  1916. if (MimeOleEscapeString(CP_ACP, pszValue, &pszEscape) == S_OK)
  1917. {
  1918. pszValue = pszEscape;
  1919. cchValue = lstrlen(pszEscape);
  1920. }
  1921. // Write the property...
  1922. CHECKHR(hr = pStream->Write(pszValue, cchValue, NULL));
  1923. }
  1924. // Count Props Wrote
  1925. cWrote++;
  1926. // Find Next
  1927. hrFind = _HrFindNextProperty(&rFind, &pParameter);
  1928. // Cleanup
  1929. MimeVariantFree(&rValue);
  1930. SafeMemFree(pszEscape);
  1931. }
  1932. // Transmit
  1933. if (ISFLAGSET(dwFlags, PDF_HEADERFORMAT))
  1934. {
  1935. // Final CRLF if Transmit Format
  1936. CHECKHR(hr = pStream->Write(g_szCRLF, lstrlen(g_szCRLF), NULL));
  1937. }
  1938. // If We Wrote Stuff
  1939. if (cWrote)
  1940. {
  1941. // MVT_STRINGA
  1942. if (MVT_STRINGA == pValue->type)
  1943. {
  1944. // pStream better be the byte stream
  1945. Assert(pStream == &cByteStream);
  1946. // Get string from stream...
  1947. CHECKHR(hr = cByteStream.HrAcquireStringA(&pValue->rStringA.cchVal, &pValue->rStringA.pszVal, ACQ_DISPLACE));
  1948. }
  1949. // MVT_STRINGW
  1950. else if (MVT_STRINGW == pValue->type)
  1951. {
  1952. // Locals
  1953. PROPSTRINGA rStringA;
  1954. // Init
  1955. ZeroMemory(&rStringA, sizeof(PROPSTRINGA));
  1956. // pStream better be the byte stream
  1957. Assert(pStream == &cByteStream);
  1958. // Get string from stream...
  1959. CHECKHR(hr = cByteStream.HrAcquireStringA(&rStringA.cchVal, &rStringA.pszVal, ACQ_COPY));
  1960. // Convert to variant
  1961. CHECKHR(hr = g_pInternat->HrMultiByteToWideChar(CP_ACP, &rStringA, &pValue->rStringW));
  1962. }
  1963. else
  1964. Assert(MVT_STREAM == pValue->type);
  1965. }
  1966. exit:
  1967. // Cleanup
  1968. MimeVariantFree(&rValue);
  1969. SafeMemFree(pszEscape);
  1970. // Done
  1971. return hr;
  1972. }
  1973. // --------------------------------------------------------------------------------
  1974. // CMimePropertyContainer::_HrGetMultiValueProperty
  1975. // --------------------------------------------------------------------------------
  1976. HRESULT CMimePropertyContainer::_HrGetMultiValueProperty(LPPROPERTY pProperty, DWORD dwFlags, LPMIMEVARIANT pValue)
  1977. {
  1978. // Locals
  1979. HRESULT hr=S_OK;
  1980. MIMEVARIANT rValue;
  1981. LPPROPERTY pCurrProp;
  1982. CByteStream cByteStream;
  1983. ULONG cLines;
  1984. // Invalid Arg
  1985. Assert(pProperty && pValue);
  1986. // Variant Not Supported
  1987. if (MVT_VARIANT == pValue->type)
  1988. return TrapError(MIME_E_VARTYPE_NO_CONVERT);
  1989. if (MVT_STRINGW == pValue->type && ISFLAGSET(dwFlags, PDF_ENCODED))
  1990. return TrapError(MIME_E_VARTYPE_NO_CONVERT);
  1991. // Init
  1992. ZeroMemory(&rValue, sizeof(MIMEVARIANT));
  1993. // I will read it as a stream
  1994. rValue.type = MVT_STREAM;
  1995. // I need a stream to write to...
  1996. if (MVT_STREAM == pValue->type)
  1997. {
  1998. // Validate the stream
  1999. if (NULL == pValue->pStream)
  2000. {
  2001. hr = TrapError(E_INVALIDARG);
  2002. goto exit;
  2003. }
  2004. // Save the Stream
  2005. rValue.pStream = pValue->pStream;
  2006. }
  2007. // Otherwise, create my own stream
  2008. else
  2009. rValue.pStream = &cByteStream;
  2010. // Count lines for rItem.hItem and mark iFirst and iLast
  2011. for (cLines=0, pCurrProp=pProperty; pCurrProp!=NULL; pCurrProp=pCurrProp->pNextValue, cLines++)
  2012. {
  2013. // Get the variant
  2014. CHECKHR(hr = HrConvertVariant(pCurrProp, dwFlags | CVF_NOALLOC, &rValue));
  2015. Assert(rValue.fCopy == FALSE);
  2016. // Not Header Format, add CRLF
  2017. if (FALSE == ISFLAGSET(dwFlags, PDF_HEADERFORMAT) && cLines > 0)
  2018. {
  2019. // CRLF
  2020. CHECKHR(hr = rValue.pStream->Write(g_szCRLF, lstrlen(g_szCRLF), NULL));
  2021. }
  2022. }
  2023. // More than 1 line
  2024. if (cLines > 0)
  2025. {
  2026. // MVT_STRINGA
  2027. if (MVT_STRINGA == pValue->type)
  2028. {
  2029. // pStream better be the byte stream
  2030. Assert(rValue.pStream == &cByteStream);
  2031. // Get string from stream...
  2032. CHECKHR(hr = cByteStream.HrAcquireStringA(&pValue->rStringA.cchVal, &pValue->rStringA.pszVal, ACQ_DISPLACE));
  2033. }
  2034. // MVT_STRINGW
  2035. else if (MVT_STRINGW == pValue->type)
  2036. {
  2037. // Locals
  2038. PROPSTRINGA rStringA;
  2039. // ZeroMemory
  2040. ZeroMemory(&rStringA, sizeof(PROPSTRINGA));
  2041. // pStream better be the byte stream
  2042. Assert(rValue.pStream == &cByteStream);
  2043. // Get string from stream...
  2044. CHECKHR(hr = cByteStream.HrAcquireStringA(&rStringA.cchVal, &rStringA.pszVal, ACQ_COPY));
  2045. // Convert to Unicode
  2046. CHECKHR(hr = g_pInternat->HrMultiByteToWideChar(CP_ACP, &rStringA, &pValue->rStringW));
  2047. }
  2048. else
  2049. Assert(MVT_STREAM == pValue->type);
  2050. }
  2051. // Otherwise, no data
  2052. else
  2053. {
  2054. hr = MIME_E_NO_DATA;
  2055. goto exit;
  2056. }
  2057. exit:
  2058. // Done
  2059. return hr;
  2060. }
  2061. // --------------------------------------------------------------------------------
  2062. // CMimePropertyContainer::_HrIsTriggerCaller
  2063. // --------------------------------------------------------------------------------
  2064. HRESULT CMimePropertyContainer::_HrIsTriggerCaller(DWORD dwPropId, TRIGGERTYPE tyTrigger)
  2065. {
  2066. // If there is 0 or 1 calls on the stack, there is no caller
  2067. if (m_rTrigger.cCalls <= 1)
  2068. return S_FALSE;
  2069. // Readability
  2070. LPTRIGGERCALL pCall = &m_rTrigger.rgStack[m_rTrigger.cCalls - 2];
  2071. // Is the Previous entry on the stack equal to dwPropId tyTrigger
  2072. return (dwPropId == pCall->pSymbol->dwPropId && tyTrigger == pCall->tyTrigger) ? S_OK : S_FALSE;
  2073. }
  2074. // --------------------------------------------------------------------------------
  2075. // CMimePropertyContainer::_HrCallSymbolTrigger
  2076. // --------------------------------------------------------------------------------
  2077. HRESULT CMimePropertyContainer::_HrCallSymbolTrigger(LPPROPSYMBOL pSymbol, TRIGGERTYPE tyTrigger, DWORD dwFlags,
  2078. LPMIMEVARIANT pValue)
  2079. {
  2080. // Locals
  2081. HRESULT hr=S_OK;
  2082. WORD cCalls;
  2083. // Validate Params
  2084. Assert(pSymbol && ISTRIGGERED(pSymbol, tyTrigger));
  2085. // Dispatch Stack Overflow - If this happens, there is a design problem
  2086. Assert(m_rTrigger.cCalls + 1 < CTSTACKSIZE);
  2087. // Note current number of calls
  2088. cCalls = m_rTrigger.cCalls;
  2089. // Put this call onto the stack
  2090. m_rTrigger.rgStack[m_rTrigger.cCalls].pSymbol = pSymbol;
  2091. m_rTrigger.rgStack[m_rTrigger.cCalls].tyTrigger = tyTrigger;
  2092. // Increment Call Stack Size
  2093. m_rTrigger.cCalls++;
  2094. // Property Dispatch
  2095. hr = CALLTRIGGER(pSymbol, this, tyTrigger, dwFlags, pValue, NULL);
  2096. // Increment Call Stack Size
  2097. Assert(m_rTrigger.cCalls > 0);
  2098. m_rTrigger.cCalls--;
  2099. // Same Number of Calls in/out
  2100. Assert(cCalls == m_rTrigger.cCalls);
  2101. // Done
  2102. return hr;
  2103. }
  2104. // --------------------------------------------------------------------------------
  2105. // CMimePropertyContainer::_HrGetPropertyValue
  2106. // --------------------------------------------------------------------------------
  2107. HRESULT CMimePropertyContainer::_HrGetPropertyValue(LPPROPERTY pProperty, DWORD dwFlags, LPMIMEVARIANT pValue)
  2108. {
  2109. // Locals
  2110. HRESULT hr=S_OK;
  2111. // Delegate if MPF_ADDRESS
  2112. if (ISFLAGSET(pProperty->pSymbol->dwFlags, MPF_ADDRESS))
  2113. {
  2114. // Get Address Data
  2115. CHECKHR(hr = _HrBuildAddressString(pProperty, dwFlags, pValue));
  2116. }
  2117. // Delegate if MPF_HASPARAMS
  2118. else if (ISFLAGSET(dwFlags, PDF_ENCODED) && ISFLAGSET(pProperty->pSymbol->dwFlags, MPF_HASPARAMS))
  2119. {
  2120. // Get Address Data
  2121. CHECKHR(hr = _HrBuildParameterString(pProperty, dwFlags, pValue));
  2122. }
  2123. // Multivalue property
  2124. else if (pProperty->pNextValue && ISFLAGSET(dwFlags, PDF_VECTOR))
  2125. {
  2126. // Translate pProperty->rVariant to pVariant
  2127. CHECKHR(hr = _HrGetMultiValueProperty(pProperty, dwFlags, pValue));
  2128. }
  2129. // Otherwise, single value property
  2130. else
  2131. {
  2132. // Translate pProperty->rVariant to pVariant
  2133. CHECKHR(hr = HrConvertVariant(pProperty, dwFlags, pValue));
  2134. }
  2135. // Dispatch
  2136. if (ISTRIGGERED(pProperty->pSymbol, IST_POSTGETPROP))
  2137. {
  2138. // Property Dispatch
  2139. CHECKHR(hr = _HrCallSymbolTrigger(pProperty->pSymbol, IST_POSTGETPROP, dwFlags, pValue));
  2140. }
  2141. exit:
  2142. // Done
  2143. return hr;
  2144. }
  2145. // --------------------------------------------------------------------------------
  2146. // CMimePropertyContainer::HrConvertVariant
  2147. // --------------------------------------------------------------------------------
  2148. HRESULT CMimePropertyContainer::HrConvertVariant(LPPROPERTY pProperty, DWORD dwFlags,
  2149. DWORD dwState, LPMIMEVARIANT pSource, LPMIMEVARIANT pDest, BOOL *pfRfc1522 /* = NULL */)
  2150. {
  2151. // Invalid Arg
  2152. Assert(pProperty && pDest);
  2153. // Thread Safety
  2154. EnterCriticalSection(&m_cs);
  2155. // HrConvertVariant
  2156. HRESULT hr = ::HrConvertVariant(&m_rOptions, pProperty->pSymbol, pProperty->pCharset,
  2157. pProperty->ietValue, dwFlags, dwState, pSource, pDest, pfRfc1522);
  2158. // Thread Safety
  2159. LeaveCriticalSection(&m_cs);
  2160. // Done
  2161. return hr;
  2162. }
  2163. // --------------------------------------------------------------------------------
  2164. // CMimePropertyContainer::HrConvertVariant
  2165. // --------------------------------------------------------------------------------
  2166. HRESULT CMimePropertyContainer::HrConvertVariant(LPPROPERTY pProperty, DWORD dwFlags, LPMIMEVARIANT pDest)
  2167. {
  2168. // Invalid Arg
  2169. Assert(pProperty && pDest);
  2170. // Thread Safety
  2171. EnterCriticalSection(&m_cs);
  2172. // HrConvertVariant
  2173. HRESULT hr = ::HrConvertVariant(&m_rOptions, pProperty->pSymbol, pProperty->pCharset,
  2174. pProperty->ietValue, dwFlags, pProperty->dwState, &pProperty->rValue, pDest);
  2175. // Thread Safety
  2176. LeaveCriticalSection(&m_cs);
  2177. // Done
  2178. return hr;
  2179. }
  2180. // --------------------------------------------------------------------------------
  2181. // CMimePropertyContainer::HrConvertVariant
  2182. // --------------------------------------------------------------------------------
  2183. HRESULT CMimePropertyContainer::HrConvertVariant(LPPROPSYMBOL pSymbol, LPINETCSETINFO pCharset,
  2184. ENCODINGTYPE ietSource, DWORD dwFlags, DWORD dwState, LPMIMEVARIANT pSource,
  2185. LPMIMEVARIANT pDest, BOOL *pfRfc1522 /* = NULL */)
  2186. {
  2187. // Locals
  2188. LPPROPERTY pProperty;
  2189. // Invalid Args
  2190. Assert(pSymbol && pSource && pDest);
  2191. // Thread Safety
  2192. EnterCriticalSection(&m_cs);
  2193. // No Charset Passed In
  2194. if (NULL == pCharset && SUCCEEDED(_HrFindProperty(pSymbol, &pProperty)))
  2195. pCharset = pProperty->pCharset;
  2196. // HrConvertVariant
  2197. HRESULT hr = ::HrConvertVariant(&m_rOptions, pSymbol, pCharset, ietSource, dwFlags, dwState, pSource, pDest, pfRfc1522);
  2198. // Thread Safety
  2199. LeaveCriticalSection(&m_cs);
  2200. // Done
  2201. return hr;
  2202. }
  2203. // --------------------------------------------------------------------------------
  2204. // CMimePropertyContainer::_HrSetPropertyValue
  2205. // --------------------------------------------------------------------------------
  2206. HRESULT CMimePropertyContainer::_HrSetPropertyValue(LPPROPERTY pProperty, DWORD dwFlags, LPCMIMEVARIANT pValue, BOOL fFromMovePropos)
  2207. {
  2208. // Locals
  2209. HRESULT hr=S_OK;
  2210. MIMEVARIANT rSource;
  2211. LPSTR pszFree=NULL;
  2212. // Adjust pValue if property can not be internationalized
  2213. if (MVT_STRINGW == pValue->type && (!ISFLAGSET(pProperty->pSymbol->dwFlags, MPF_INETCSET) || ISFLAGSET(pProperty->pSymbol->dwFlags, MPF_ADDRESS)))
  2214. {
  2215. // Convert to ANSI
  2216. CHECKHR(hr = g_pInternat->HrWideCharToMultiByte(CP_ACP, &pValue->rStringW, &rSource.rStringA));
  2217. // Setup Source
  2218. rSource.type = MVT_STRINGA;
  2219. // Free This
  2220. pszFree = rSource.rStringA.pszVal;
  2221. // Change the Value
  2222. pValue = &rSource;
  2223. }
  2224. // MPF_HASPARAMS
  2225. if (ISFLAGSET(dwFlags, PDF_ENCODED) && ISFLAGSET(pProperty->pSymbol->dwFlags, MPF_HASPARAMS) && !fFromMovePropos)
  2226. {
  2227. // Parse parameters into other properties
  2228. CHECKHR(hr = _HrParseParameters(pProperty, dwFlags, pValue));
  2229. }
  2230. // Otherwise, just copy the data
  2231. else
  2232. {
  2233. // Store the variant data
  2234. CHECKHR(hr = _HrStoreVariantValue(pProperty, dwFlags, pValue));
  2235. // If Encoded, check for rfc1522 character set
  2236. if (ISFLAGSET(pProperty->pSymbol->dwFlags, MPF_RFC1522) && ISFLAGSET(dwFlags, PDF_ENCODED) && MVT_STRINGA == pValue->type)
  2237. {
  2238. // Locals
  2239. CHAR szCharset[CCHMAX_CSET_NAME];
  2240. LPINETCSETINFO pCharset;
  2241. // Scan for 1522 Encoding...
  2242. if (SUCCEEDED(MimeOleRfc1522Decode(pValue->rStringA.pszVal, szCharset, sizeof(szCharset)-1, NULL)))
  2243. {
  2244. // Find the Charset
  2245. if (SUCCEEDED(g_pInternat->HrOpenCharset(szCharset, &pCharset)))
  2246. {
  2247. // Save Pointer to Charset
  2248. pProperty->pCharset = pCharset;
  2249. }
  2250. }
  2251. }
  2252. // MPF_ADDRESS
  2253. if (ISFLAGSET(pProperty->pSymbol->dwFlags, MPF_ADDRESS))
  2254. {
  2255. // Parse the address into the address group
  2256. _FreeAddressChain(pProperty->pGroup);
  2257. // Not Dirty
  2258. pProperty->pGroup->fDirty = FALSE;
  2259. // Reset the parsing flag
  2260. FLAGSET(pProperty->dwState, PRSTATE_NEEDPARSE);
  2261. }
  2262. }
  2263. // Set some new state
  2264. FLAGSET(pProperty->dwState, PRSTATE_HASDATA);
  2265. // Dispatch
  2266. if (ISTRIGGERED(pProperty->pSymbol, IST_POSTSETPROP))
  2267. {
  2268. // Property Dispatch
  2269. CHECKHR(hr = _HrCallSymbolTrigger(pProperty->pSymbol, IST_POSTSETPROP, dwFlags, &pProperty->rValue));
  2270. }
  2271. exit:
  2272. // Cleanup
  2273. SafeMemFree(pszFree);
  2274. // Done
  2275. return hr;
  2276. }
  2277. // --------------------------------------------------------------------------------
  2278. // CMimePropertyContainer::_HrParseParameters
  2279. // --------------------------------------------------------------------------------
  2280. HRESULT CMimePropertyContainer::_HrParseParameters(LPPROPERTY pProperty, DWORD dwFlags, LPCMIMEVARIANT pValue)
  2281. {
  2282. // Locals
  2283. HRESULT hr=S_OK;
  2284. ULONG cchName;
  2285. CStringParser cString;
  2286. CHAR chToken;
  2287. MIMEVARIANT rValue;
  2288. LPPROPSYMBOL pParameter;
  2289. // Invalid Arg
  2290. Assert(pProperty && pValue && ISFLAGSET(dwFlags, PDF_ENCODED));
  2291. // Define a Stack String to hold parameter names
  2292. STACKSTRING_DEFINE(rName, 255);
  2293. // Error
  2294. if (!ISSTRINGA(pValue))
  2295. {
  2296. Assert(FALSE);
  2297. hr = TrapError(MIME_E_VARTYPE_NO_CONVERT);
  2298. goto exit;
  2299. }
  2300. // Init rValue
  2301. rValue.type = MVT_STRINGA;
  2302. // Lets delete currently linked parameters
  2303. _DeleteLinkedParameters(pProperty);
  2304. // Set the Members
  2305. cString.Init(pValue->rStringA.pszVal, pValue->rStringA.cchVal, PSF_NOFRONTWS | PSF_NOTRAILWS | PSF_NOCOMMENTS);
  2306. // Parse up to colon
  2307. chToken = cString.ChParse(";");
  2308. if (0 == cString.CchValue())
  2309. {
  2310. // Setup a variant
  2311. rValue.rStringA.pszVal = (LPSTR)STR_MIME_TEXT_PLAIN;
  2312. rValue.rStringA.cchVal = lstrlen(STR_MIME_TEXT_PLAIN);
  2313. // Store the variant data
  2314. CHECKHR(hr = _HrStoreVariantValue(pProperty, PDF_ENCODED, &rValue));
  2315. // Done
  2316. goto exit;
  2317. }
  2318. // Setup a variant
  2319. rValue.rStringA.pszVal = (LPSTR)cString.PszValue();
  2320. rValue.rStringA.cchVal = cString.CchValue();
  2321. // Store the variant data
  2322. CHECKHR(hr = _HrStoreVariantValue(pProperty, PDF_ENCODED, &rValue));
  2323. // Done
  2324. if (';' != chToken)
  2325. goto exit;
  2326. // Read all parameters
  2327. while('\0' != chToken)
  2328. {
  2329. Assert(';' == chToken);
  2330. // $$$ BUG $$$ - This fixes the bogus NDR messages returned from Netscape server.
  2331. // there message have a invalid Content-Type line:
  2332. // mulipart/alternative;; boundary="--=============12345678"
  2333. // ^^
  2334. // The double semi-colon is invalid, but I will handle it here since
  2335. // a parameter name can not begin with a semicolon.
  2336. // Better be at a semicolon
  2337. chToken = cString.ChSkip();
  2338. if ('\0' == chToken)
  2339. goto exit;
  2340. // Parse parameter name
  2341. chToken = cString.ChParse("=");
  2342. if ('=' != chToken)
  2343. goto exit;
  2344. // Compute the length of the name
  2345. cchName = pProperty->pSymbol->cchName + cString.CchValue() + 6; // (YST) QFE bug
  2346. // Grow the stack string to hold cchName
  2347. STACKSTRING_SETSIZE(rName, cchName);
  2348. // Make Parameter Name, set actual cchName
  2349. cchName = wnsprintf(rName.pszVal, cchName, "par:%s:%s", pProperty->pSymbol->pszName, cString.PszValue());
  2350. // Parse parameter value
  2351. chToken = cString.ChParse("\";");
  2352. // Quoted ?
  2353. if ('\"' == chToken)
  2354. {
  2355. // Locals
  2356. CHAR ch;
  2357. DWORD dwFlags = PSF_DBCS | PSF_ESCAPED;
  2358. // Lookup the property symbol to see if it exist
  2359. if (FAILED(g_pSymCache->HrOpenSymbol(rName.pszVal, FALSE, &pParameter)))
  2360. pParameter = NULL;
  2361. // For "par:content-disposition:filename" property assume no escaped chars
  2362. if (pParameter && (pParameter->dwPropId == PID_PAR_FILENAME))
  2363. dwFlags &= ~PSF_ESCAPED;
  2364. // Raid-48365: FE-J:OExpress: JIS file name of attachment is not decoded correctly.
  2365. while(1)
  2366. {
  2367. // Parse parameter value
  2368. ch = cString.ChParse('\"', '\"', dwFlags);
  2369. if ('\0' == ch)
  2370. break;
  2371. // Not a international parameter
  2372. if (pParameter && !ISFLAGSET(pParameter->dwFlags, MPF_INETCSET))
  2373. break;
  2374. // Skip White Space
  2375. ch = cString.ChSkipWhite();
  2376. if ('\0' == ch || ';' == ch)
  2377. break;
  2378. // Put a quote back into the string
  2379. CHECKHR(hr = cString.HrAppendValue('\"'));
  2380. // Add PSF_NORESET flag
  2381. FLAGSET(dwFlags, PSF_NORESET);
  2382. }
  2383. // If no value, were done
  2384. if (0 == cString.CchValue())
  2385. goto exit;
  2386. }
  2387. else
  2388. Assert(';' == chToken || '\0' == chToken);
  2389. // Setup Value
  2390. rValue.type = MVT_STRINGA;
  2391. rValue.rStringA.pszVal = (LPSTR)cString.PszValue();
  2392. rValue.rStringA.cchVal = cString.CchValue();
  2393. // Set the property
  2394. CHECKHR(hr = SetProp(rName.pszVal, PDF_ENCODED, &rValue));
  2395. // If last token was a '"', then seek to semicolon
  2396. if ('\"' == chToken)
  2397. {
  2398. // Parse parameter value
  2399. chToken = cString.ChParse(";");
  2400. }
  2401. }
  2402. exit:
  2403. // Cleanup
  2404. STACKSTRING_FREE(rName);
  2405. // Done
  2406. return hr;
  2407. }
  2408. // --------------------------------------------------------------------------------
  2409. // CMimePropertyContainer::_HrParseInternetAddress
  2410. // --------------------------------------------------------------------------------
  2411. HRESULT CMimePropertyContainer::_HrParseInternetAddress(LPPROPERTY pProperty)
  2412. {
  2413. // Locals
  2414. HRESULT hr=S_OK;
  2415. MIMEVARIANT rSource;
  2416. LPMIMEADDRESS pAddress;
  2417. LPINETCSETINFO pCharset=NULL;
  2418. CAddressParser cAdrParse;
  2419. // Invalid Arg
  2420. Assert(pProperty && pProperty->pSymbol && ISFLAGSET(pProperty->pSymbol->dwFlags, MPF_ADDRESS) && pProperty->pGroup);
  2421. // Init
  2422. ZeroMemory(&rSource, sizeof(MIMEVARIANT));
  2423. // If the property does not need PRSTATE_NEEDPARSE, return
  2424. if (!ISFLAGSET(pProperty->dwState, PRSTATE_NEEDPARSE))
  2425. goto exit;
  2426. // Setup rSource
  2427. rSource.type = MVT_STRINGW;
  2428. // Convert to multibyte
  2429. CHECKHR(hr = HrConvertVariant(pProperty, CVF_NOALLOC, &rSource));
  2430. // Figure out pCharset
  2431. if (pProperty->pCharset)
  2432. pCharset = pProperty->pCharset;
  2433. else if (m_rOptions.pDefaultCharset)
  2434. pCharset = m_rOptions.pDefaultCharset;
  2435. else if (CIntlGlobals::GetDefHeadCset())
  2436. pCharset = CIntlGlobals::GetDefHeadCset();
  2437. // Initialize Parse Structure
  2438. cAdrParse.Init(rSource.rStringW.pszVal, rSource.rStringW.cchVal);
  2439. // Parse
  2440. while(SUCCEEDED(cAdrParse.Next()))
  2441. {
  2442. // Append an Address
  2443. CHECKHR(hr = _HrAppendAddressGroup(pProperty->pGroup, &pAddress));
  2444. // Set the Address Type
  2445. pAddress->dwAdrType = pProperty->pSymbol->dwAdrType;
  2446. // Store Friendly Name
  2447. CHECKHR(hr = HrSetAddressTokenW(cAdrParse.PszFriendly(), cAdrParse.CchFriendly(), &pAddress->rFriendly));
  2448. // Store Email
  2449. CHECKHR(hr = HrSetAddressTokenW(cAdrParse.PszEmail(), cAdrParse.CchEmail(), &pAddress->rEmail));
  2450. // Save the Address
  2451. pAddress->pCharset = pCharset;
  2452. }
  2453. // No sync needed anymore
  2454. FLAGCLEAR(pProperty->dwState, PRSTATE_NEEDPARSE);
  2455. exit:
  2456. // Cleanup
  2457. MimeVariantFree(&rSource);
  2458. // Done
  2459. return hr;
  2460. }
  2461. // --------------------------------------------------------------------------------
  2462. // CMimePropertyContainer::_HrStoreVariantValue
  2463. // --------------------------------------------------------------------------------
  2464. HRESULT CMimePropertyContainer::_HrStoreVariantValue(LPPROPERTY pProperty, DWORD dwFlags, LPCMIMEVARIANT pValue)
  2465. {
  2466. // Locals
  2467. HRESULT hr=S_OK;
  2468. ULONG cbSource=0;
  2469. LPBYTE pbSource=NULL;
  2470. LPBYTE *ppbDest=NULL;
  2471. ULONG *pcbDest=NULL;
  2472. LPBYTE pbNewBlob;
  2473. ULONG cbNewBlob;
  2474. // Invalid Arg
  2475. Assert(pProperty && pValue);
  2476. // Handle Data Type
  2477. switch(pValue->type)
  2478. {
  2479. case MVT_STRINGA:
  2480. // Invalid Arg
  2481. if (ISVALIDSTRINGA(&pValue->rStringA) == FALSE)
  2482. {
  2483. hr = TrapError(E_INVALIDARG);
  2484. goto exit;
  2485. }
  2486. // Set Byte Source
  2487. pbSource = (LPBYTE)pValue->rStringA.pszVal;
  2488. // Set Source Byte Count
  2489. cbSource = pValue->rStringA.cchVal + 1;
  2490. // Set Destination Byte Pointer
  2491. ppbDest = (LPBYTE *)&(pProperty->rValue.rStringA.pszVal);
  2492. // Save Length Now
  2493. pProperty->rValue.rStringA.cchVal = pValue->rStringA.cchVal;
  2494. break;
  2495. case MVT_STRINGW:
  2496. // Invalid Arg
  2497. if (ISVALIDSTRINGW(&pValue->rStringW) == FALSE)
  2498. {
  2499. hr = TrapError(E_INVALIDARG);
  2500. goto exit;
  2501. }
  2502. // Set Byte Source
  2503. pbSource = (LPBYTE)pValue->rStringW.pszVal;
  2504. // Set Source Byte Count
  2505. cbSource = ((pValue->rStringW.cchVal + 1) * sizeof(WCHAR));
  2506. // Set Destination Byte Pointer
  2507. ppbDest = (LPBYTE *)&(pProperty->rValue.rStringW.pszVal);
  2508. // Save Length Now
  2509. pProperty->rValue.rStringW.cchVal = pValue->rStringW.cchVal;
  2510. break;
  2511. case MVT_VARIANT:
  2512. pProperty->rValue.rVariant.vt = pValue->rVariant.vt;
  2513. switch(pValue->rVariant.vt)
  2514. {
  2515. case VT_FILETIME:
  2516. CopyMemory(&pProperty->rValue.rVariant.filetime, &pValue->rVariant.filetime, sizeof(FILETIME));
  2517. pbSource = (LPBYTE)&pValue->rVariant.filetime;
  2518. cbSource = sizeof(pValue->rVariant.filetime);
  2519. break;
  2520. case VT_I4:
  2521. pProperty->rValue.rVariant.lVal = pValue->rVariant.lVal;
  2522. pbSource = (LPBYTE)&pValue->rVariant.lVal;
  2523. cbSource = sizeof(pValue->rVariant.lVal);
  2524. break;
  2525. case VT_UI4:
  2526. pProperty->rValue.rVariant.ulVal = pValue->rVariant.ulVal;
  2527. pbSource = (LPBYTE)&pValue->rVariant.ulVal;
  2528. cbSource = sizeof(pValue->rVariant.ulVal);
  2529. break;
  2530. default:
  2531. Assert(FALSE);
  2532. hr = TrapError(MIME_E_INVALID_VARTYPE);
  2533. goto exit;
  2534. }
  2535. break;
  2536. default:
  2537. Assert(FALSE);
  2538. hr = TrapError(E_FAIL);
  2539. goto exit;
  2540. }
  2541. // Better have a source
  2542. Assert(cbSource && cbSource);
  2543. // Store the data
  2544. if (cbSource > pProperty->cbAlloc)
  2545. {
  2546. // Fits into static buffer ?
  2547. if (cbSource <= sizeof(pProperty->rgbScratch))
  2548. {
  2549. // If not reallocing...
  2550. if (ISFLAGSET(pProperty->dwState, PRSTATE_ALLOCATED))
  2551. {
  2552. Assert(pProperty->pbBlob);
  2553. g_pMalloc->Free(pProperty->pbBlob);
  2554. FLAGCLEAR(pProperty->dwState, PRSTATE_ALLOCATED);
  2555. }
  2556. // Use Scratch Buffer
  2557. pProperty->pbBlob = pProperty->rgbScratch;
  2558. pProperty->cbAlloc = sizeof(pProperty->rgbScratch);
  2559. }
  2560. // Was my current buffer allocated
  2561. else
  2562. {
  2563. // If not reallocing...
  2564. if (!ISFLAGSET(pProperty->dwState, PRSTATE_ALLOCATED))
  2565. {
  2566. pProperty->pbBlob = NULL;
  2567. pProperty->cbAlloc = 0;
  2568. }
  2569. else
  2570. Assert(pProperty->cbAlloc > sizeof(pProperty->rgbScratch) && g_pMalloc->DidAlloc(pProperty->pbBlob) == 1);
  2571. // Compute Size of new blob
  2572. cbNewBlob = pProperty->cbAlloc + (cbSource - pProperty->cbAlloc);
  2573. // Realloc New Blob
  2574. CHECKALLOC(pbNewBlob = (LPBYTE)g_pMalloc->Realloc((LPVOID)pProperty->pbBlob, cbNewBlob));
  2575. // We've allocated it
  2576. FLAGSET(pProperty->dwState, PRSTATE_ALLOCATED);
  2577. // Assume the new blob
  2578. pProperty->pbBlob = pbNewBlob;
  2579. pProperty->cbAlloc = cbNewBlob;
  2580. }
  2581. }
  2582. // Copy the data
  2583. CopyMemory(pProperty->pbBlob, pbSource, cbSource);
  2584. // Set Size of Data in m_pbBlob
  2585. pProperty->cbBlob = cbSource;
  2586. // If there is a ppbDest assign to it
  2587. if (ppbDest)
  2588. *ppbDest = pProperty->pbBlob;
  2589. // Save Encoding Type
  2590. pProperty->ietValue = (ISFLAGSET(dwFlags, PDF_ENCODED)) ? IET_ENCODED : IET_DECODED;
  2591. // PRSTATE_SAVENOENCODE
  2592. if (ISFLAGSET(dwFlags, PDF_SAVENOENCODE))
  2593. FLAGSET(pProperty->dwState, PRSTATE_SAVENOENCODE);
  2594. // Save Type
  2595. pProperty->rValue.type = pValue->type;
  2596. exit:
  2597. // Failure
  2598. if (FAILED(hr))
  2599. ZeroMemory(&pProperty->rValue, sizeof(MIMEVARIANT));
  2600. // Done
  2601. return hr;
  2602. }
  2603. // --------------------------------------------------------------------------------
  2604. // CMimePropertyContainer::GetProp
  2605. // --------------------------------------------------------------------------------
  2606. HRESULT CMimePropertyContainer::GetProp(LPCSTR pszName, LPSTR *ppszData)
  2607. {
  2608. // Locals
  2609. HRESULT hr=S_OK;
  2610. MIMEVARIANT rValue;
  2611. LPPROPSYMBOL pSymbol;
  2612. // Invalid Arg
  2613. Assert(pszName && ppszData);
  2614. // Init
  2615. *ppszData = NULL;
  2616. // Open Property Symbol
  2617. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pszName, FALSE, &pSymbol));
  2618. // Init the variant
  2619. rValue.type = MVT_STRINGA;
  2620. // Get Property by Symbol
  2621. CHECKHR(hr = GetProp(pSymbol, 0, &rValue));
  2622. // Set the string
  2623. Assert(rValue.rStringA.pszVal);
  2624. *ppszData = rValue.rStringA.pszVal;
  2625. exit:
  2626. // Done
  2627. return hr;
  2628. }
  2629. // --------------------------------------------------------------------------------
  2630. // CMimePropertyContainer::GetProp
  2631. // --------------------------------------------------------------------------------
  2632. HRESULT CMimePropertyContainer::GetProp(LPPROPSYMBOL pSymbol, LPSTR *ppszData)
  2633. {
  2634. // Locals
  2635. HRESULT hr=S_OK;
  2636. MIMEVARIANT rValue;
  2637. // Invalid Arg
  2638. Assert(pSymbol && ppszData);
  2639. // Init
  2640. *ppszData = NULL;
  2641. // Init the variant
  2642. rValue.type = MVT_STRINGA;
  2643. // Get Property by Symbol
  2644. CHECKHR(hr = GetProp(pSymbol, 0, &rValue));
  2645. // Set the string
  2646. Assert(rValue.rStringA.pszVal);
  2647. *ppszData = rValue.rStringA.pszVal;
  2648. exit:
  2649. // Done
  2650. return hr;
  2651. }
  2652. // --------------------------------------------------------------------------------
  2653. // CMimePropertyContainer::GetPropW
  2654. // --------------------------------------------------------------------------------
  2655. HRESULT CMimePropertyContainer::GetPropW(LPPROPSYMBOL pSymbol, LPWSTR *ppwszData)
  2656. {
  2657. // Locals
  2658. HRESULT hr=S_OK;
  2659. MIMEVARIANT rValue;
  2660. // Invalid Arg
  2661. Assert(pSymbol && ppwszData);
  2662. // Init
  2663. *ppwszData = NULL;
  2664. // Init the variant
  2665. rValue.type = MVT_STRINGW;
  2666. // Get Property by Symbol
  2667. CHECKHR(hr = GetProp(pSymbol, 0, &rValue));
  2668. // Set the string
  2669. Assert(rValue.rStringW.pszVal);
  2670. *ppwszData = rValue.rStringW.pszVal;
  2671. exit:
  2672. // Done
  2673. return hr;
  2674. }
  2675. // --------------------------------------------------------------------------------
  2676. // CMimePropertyContainer::GetProp
  2677. // --------------------------------------------------------------------------------
  2678. HRESULT CMimePropertyContainer::GetProp(LPCSTR pszName, DWORD dwFlags, LPPROPVARIANT pVariant)
  2679. {
  2680. // Locals
  2681. HRESULT hr=S_OK;
  2682. LPPROPSYMBOL pSymbol;
  2683. MIMEVARIANT rValue;
  2684. // Invaid Arg
  2685. if (NULL == pszName || NULL == pVariant)
  2686. return TrapError(E_INVALIDARG);
  2687. // Open Property Symbol
  2688. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pszName, FALSE, &pSymbol));
  2689. // Symbol Better have a supported variant type
  2690. Assert(ISSUPPORTEDVT(pSymbol->vtDefault));
  2691. // Set rValue Variant
  2692. if (VT_EMPTY == pVariant->vt)
  2693. rValue.rVariant.vt = pVariant->vt = pSymbol->vtDefault;
  2694. else
  2695. rValue.rVariant.vt = pVariant->vt;
  2696. // Map to MIMEVARIANT
  2697. if (VT_LPSTR == pVariant->vt || VT_EMPTY == pVariant->vt)
  2698. rValue.type = MVT_STRINGA;
  2699. else if (VT_LPWSTR == pVariant->vt)
  2700. rValue.type = MVT_STRINGW;
  2701. else
  2702. rValue.type = MVT_VARIANT;
  2703. // Get Property by Symbol
  2704. CHECKHR(hr = GetProp(pSymbol, dwFlags, &rValue));
  2705. // Map to PROPVARIANT
  2706. if (MVT_STRINGA == rValue.type)
  2707. pVariant->pszVal = rValue.rStringA.pszVal;
  2708. else if (MVT_STRINGW == rValue.type)
  2709. pVariant->pwszVal = rValue.rStringW.pszVal;
  2710. else
  2711. CopyMemory(pVariant, &rValue.rVariant, sizeof(PROPVARIANT));
  2712. exit:
  2713. // Done
  2714. return hr;
  2715. }
  2716. // --------------------------------------------------------------------------------
  2717. // CMimePropertyContainer::GetProp
  2718. // --------------------------------------------------------------------------------
  2719. HRESULT CMimePropertyContainer::GetProp(LPPROPSYMBOL pSymbol, DWORD dwFlags, LPMIMEVARIANT pValue)
  2720. {
  2721. // Locals
  2722. HRESULT hr=S_OK;
  2723. LPPROPERTY pProperty;
  2724. // Thread Safety
  2725. EnterCriticalSection(&m_cs);
  2726. // Find the property
  2727. hr = _HrFindProperty(pSymbol, &pProperty);
  2728. // Failure
  2729. if (FAILED(hr))
  2730. {
  2731. // See if there is a default value for this property
  2732. if (MIME_E_NOT_FOUND != hr)
  2733. {
  2734. hr = TrapError(hr);
  2735. goto exit;
  2736. }
  2737. // Dispatch Default Request, otherwise, hr is still equal to MIME_E_NOT_FOUND....
  2738. if (ISTRIGGERED(pSymbol, IST_GETDEFAULT))
  2739. {
  2740. // Property Dispatch
  2741. CHECKHR(hr = _HrCallSymbolTrigger(pSymbol, IST_GETDEFAULT, dwFlags, pValue));
  2742. }
  2743. }
  2744. // Otherwise, get the property data
  2745. else
  2746. {
  2747. // Raid-62460: Dependency Hack to make sure the GetProp works the same when getting addresses
  2748. // PDF_VECTOR is always supported by _HrBuildAddressString, which gets called by _HrGetPropertyValue
  2749. if (ISFLAGSET(pSymbol->dwFlags, MPF_ADDRESS))
  2750. FLAGSET(dwFlags, PDF_VECTOR);
  2751. // Get the property value
  2752. CHECKHR(hr = _HrGetPropertyValue(pProperty, dwFlags, pValue));
  2753. }
  2754. exit:
  2755. // Thread Safety
  2756. LeaveCriticalSection(&m_cs);
  2757. // Done
  2758. return hr;
  2759. }
  2760. // --------------------------------------------------------------------------------
  2761. // CMimePropertyContainer::SetProp
  2762. // --------------------------------------------------------------------------------
  2763. HRESULT CMimePropertyContainer::SetProp(LPCSTR pszName, DWORD dwFlags, LPCMIMEVARIANT pValue)
  2764. {
  2765. // Locals
  2766. HRESULT hr=S_OK;
  2767. LPPROPSYMBOL pSymbol;
  2768. // Invalid Arg
  2769. Assert(pszName && pValue);
  2770. // Open Property Symbol
  2771. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pszName, TRUE, &pSymbol));
  2772. // Get Property by Symbol
  2773. CHECKHR(hr = SetProp(pSymbol, dwFlags, pValue));
  2774. exit:
  2775. // Done
  2776. return hr;
  2777. }
  2778. // --------------------------------------------------------------------------------
  2779. // CMimePropertyContainer::SetProp
  2780. // --------------------------------------------------------------------------------
  2781. HRESULT CMimePropertyContainer::SetProp(LPCSTR pszName, LPCSTR pszData)
  2782. {
  2783. // Locals
  2784. HRESULT hr=S_OK;
  2785. LPPROPSYMBOL pSymbol;
  2786. MIMEVARIANT rValue;
  2787. // Invalid Arg
  2788. Assert(pszName && pszData);
  2789. // Open Property Symbol
  2790. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pszName, TRUE, &pSymbol));
  2791. // Init the variant
  2792. rValue.type = MVT_STRINGA;
  2793. rValue.rStringA.pszVal = (LPSTR)pszData;
  2794. rValue.rStringA.cchVal = lstrlen(pszData);
  2795. // Get Property by Symbol
  2796. CHECKHR(hr = SetProp(pSymbol, 0, &rValue));
  2797. exit:
  2798. // Done
  2799. return hr;
  2800. }
  2801. // --------------------------------------------------------------------------------
  2802. // CMimePropertyContainer::SetProp
  2803. // --------------------------------------------------------------------------------
  2804. HRESULT CMimePropertyContainer::SetProp(LPPROPSYMBOL pSymbol, LPCSTR pszData)
  2805. {
  2806. // Locals
  2807. HRESULT hr=S_OK;
  2808. MIMEVARIANT rValue;
  2809. // Invalid Arg
  2810. Assert(pSymbol && pszData);
  2811. // Init the variant
  2812. rValue.type = MVT_STRINGA;
  2813. rValue.rStringA.pszVal = (LPSTR)pszData;
  2814. rValue.rStringA.cchVal = lstrlen(pszData);
  2815. // Get Property by Symbol
  2816. CHECKHR(hr = SetProp(pSymbol, 0, &rValue));
  2817. exit:
  2818. // Done
  2819. return hr;
  2820. }
  2821. // --------------------------------------------------------------------------------
  2822. // CMimePropertyContainer::SetProp
  2823. // --------------------------------------------------------------------------------
  2824. HRESULT CMimePropertyContainer::SetProp(LPCSTR pszName, DWORD dwFlags, LPCPROPVARIANT pVariant)
  2825. {
  2826. // Locals
  2827. HRESULT hr=S_OK;
  2828. LPPROPSYMBOL pSymbol;
  2829. MIMEVARIANT rValue;
  2830. // Invalid Arg
  2831. if (NULL == pszName || NULL == pVariant)
  2832. return TrapError(E_INVALIDARG);
  2833. // Open Property Symbol
  2834. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pszName, TRUE, &pSymbol));
  2835. // MVT_STRINGW
  2836. if (VT_LPSTR == pVariant->vt)
  2837. {
  2838. // Invalid Arg
  2839. if (NULL == pVariant->pszVal)
  2840. {
  2841. hr = TrapError(E_INVALIDARG);
  2842. goto exit;
  2843. }
  2844. // Setup rValue
  2845. rValue.type = MVT_STRINGA;
  2846. rValue.rStringA.pszVal = pVariant->pszVal;
  2847. rValue.rStringA.cchVal = lstrlen(pVariant->pszVal);
  2848. }
  2849. // MVT_STRINGW
  2850. else if (VT_LPWSTR == pVariant->vt)
  2851. {
  2852. // Invalid Arg
  2853. if (NULL == pVariant->pwszVal)
  2854. {
  2855. hr = TrapError(E_INVALIDARG);
  2856. goto exit;
  2857. }
  2858. // Fill rValue
  2859. rValue.type = MVT_STRINGW;
  2860. rValue.rStringW.pszVal = pVariant->pwszVal;
  2861. rValue.rStringW.cchVal = lstrlenW(pVariant->pwszVal);
  2862. }
  2863. // MVT_VARIANT
  2864. else
  2865. {
  2866. rValue.type = MVT_VARIANT;
  2867. CopyMemory(&rValue.rVariant, pVariant, sizeof(PROPVARIANT));
  2868. }
  2869. // Get Property by Symbol
  2870. CHECKHR(hr = SetProp(pSymbol, dwFlags, &rValue));
  2871. exit:
  2872. // Done
  2873. return hr;
  2874. }
  2875. // --------------------------------------------------------------------------------
  2876. // CMimePropertyContainer::SetProp
  2877. // --------------------------------------------------------------------------------
  2878. HRESULT CMimePropertyContainer::SetProp(LPPROPSYMBOL pSymbol, DWORD dwFlags, LPCMIMEVARIANT pValue)
  2879. {
  2880. // Locals
  2881. HRESULT hr=S_OK;
  2882. LPPROPERTY pProperty=NULL;
  2883. // Invalid Arg
  2884. Assert(pSymbol && pValue);
  2885. // Thread Safety
  2886. EnterCriticalSection(&m_cs);
  2887. // Read-Only
  2888. if (ISFLAGSET(pSymbol->dwFlags, MPF_READONLY))
  2889. {
  2890. AssertSz(FALSE, "This property has the MPF_READONLY flag.");
  2891. hr = TrapError(MIME_E_READ_ONLY);
  2892. goto exit;
  2893. }
  2894. // Find the property
  2895. if (FAILED(_HrFindProperty(pSymbol, &pProperty)))
  2896. {
  2897. // Create it
  2898. CHECKHR(hr = _HrCreateProperty(pSymbol, &pProperty));
  2899. }
  2900. // This better be a root property
  2901. Assert(ISFLAGSET(pProperty->dwState, PRSTATE_PARENT));
  2902. // Remove multi-values
  2903. if (pProperty->pNextValue)
  2904. {
  2905. // Free the chain
  2906. _FreePropertyChain(pProperty->pNextValue);
  2907. // No more pNextValue or pTailValue
  2908. pProperty->pNextValue = pProperty->pTailValue = NULL;
  2909. }
  2910. // Store the data
  2911. CHECKHR(hr = _HrSetPropertyValue(pProperty, dwFlags, pValue, FALSE));
  2912. // Dirty
  2913. if (!ISFLAGSET(pSymbol->dwFlags, MPF_NODIRTY))
  2914. FLAGSET(m_dwState, COSTATE_DIRTY);
  2915. exit:
  2916. // Failure
  2917. if (FAILED(hr) && pProperty)
  2918. {
  2919. // Delete the Property
  2920. _UnlinkProperty(pProperty);
  2921. }
  2922. // Thread Safety
  2923. LeaveCriticalSection(&m_cs);
  2924. // Done
  2925. return hr;
  2926. }
  2927. // --------------------------------------------------------------------------------
  2928. // CMimePropertyContainer::AppendProp
  2929. // --------------------------------------------------------------------------------
  2930. HRESULT CMimePropertyContainer::AppendProp(LPCSTR pszName, DWORD dwFlags, LPPROPVARIANT pVariant)
  2931. {
  2932. // Locals
  2933. HRESULT hr=S_OK;
  2934. LPPROPSYMBOL pSymbol;
  2935. MIMEVARIANT rValue;
  2936. // Invalid Arg
  2937. if (NULL == pszName || NULL == pVariant)
  2938. return TrapError(E_INVALIDARG);
  2939. // Open Property Symbol
  2940. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pszName, TRUE, &pSymbol));
  2941. // MVT_STRINGW
  2942. if (VT_LPSTR == pVariant->vt)
  2943. {
  2944. // Invalid Arg
  2945. if (NULL == pVariant->pszVal)
  2946. {
  2947. hr = TrapError(E_INVALIDARG);
  2948. goto exit;
  2949. }
  2950. // Fill rValue
  2951. rValue.type = MVT_STRINGA;
  2952. rValue.rStringA.pszVal = pVariant->pszVal;
  2953. rValue.rStringA.cchVal = lstrlen(pVariant->pszVal);
  2954. }
  2955. // MVT_STRINGW
  2956. else if (VT_LPWSTR == pVariant->vt)
  2957. {
  2958. // Invalid Arg
  2959. if (NULL == pVariant->pwszVal)
  2960. {
  2961. hr = TrapError(E_INVALIDARG);
  2962. goto exit;
  2963. }
  2964. // Fill rValue
  2965. rValue.type = MVT_STRINGW;
  2966. rValue.rStringW.pszVal = pVariant->pwszVal;
  2967. rValue.rStringW.cchVal = lstrlenW(pVariant->pwszVal);
  2968. }
  2969. // MVT_VARIANT
  2970. else
  2971. {
  2972. rValue.type = MVT_VARIANT;
  2973. CopyMemory(&rValue.rVariant, pVariant, sizeof(PROPVARIANT));
  2974. }
  2975. // Get Property by Symbol
  2976. CHECKHR(hr = AppendProp(pSymbol, dwFlags, &rValue));
  2977. exit:
  2978. // Done
  2979. return hr;
  2980. }
  2981. // --------------------------------------------------------------------------------
  2982. // CMimePropertyContainer::AppendProp
  2983. // --------------------------------------------------------------------------------
  2984. HRESULT CMimePropertyContainer::AppendProp(LPPROPSYMBOL pSymbol, DWORD dwFlags, LPMIMEVARIANT pValue)
  2985. {
  2986. // Locals
  2987. HRESULT hr=S_OK;
  2988. LPPROPERTY pProperty=NULL;
  2989. BOOL fAppended=FALSE;
  2990. // Invalid Arg
  2991. Assert(pSymbol && pValue);
  2992. // Thread Safety
  2993. EnterCriticalSection(&m_cs);
  2994. // Read-Only
  2995. if (ISFLAGSET(pSymbol->dwFlags, MPF_READONLY))
  2996. {
  2997. AssertSz(FALSE, "This property has the MPF_READONLY flag.");
  2998. hr = TrapError(MIME_E_READ_ONLY);
  2999. goto exit;
  3000. }
  3001. // Find the Property
  3002. if (FAILED(_HrFindProperty(pSymbol, &pProperty)))
  3003. {
  3004. // If not found... treat as basic set prop...
  3005. CHECKHR(hr = SetProp(pSymbol, dwFlags, pValue));
  3006. }
  3007. // Otherwise, of not multiline, fail
  3008. else
  3009. {
  3010. // Its appended
  3011. fAppended = TRUE;
  3012. // Append a property
  3013. CHECKHR(hr = _HrAppendProperty(pSymbol, &pProperty));
  3014. // Store the data
  3015. CHECKHR(hr = _HrSetPropertyValue(pProperty, dwFlags, pValue, FALSE));
  3016. // I am now dirty
  3017. if (!ISFLAGSET(pSymbol->dwFlags, MPF_NODIRTY))
  3018. FLAGSET(m_dwState, COSTATE_DIRTY);
  3019. }
  3020. exit:
  3021. // Failure
  3022. if (FAILED(hr) && pProperty && fAppended)
  3023. {
  3024. // Delete the Property
  3025. _UnlinkProperty(pProperty);
  3026. }
  3027. // Thread Safety
  3028. LeaveCriticalSection(&m_cs);
  3029. // Done
  3030. return hr;
  3031. }
  3032. // --------------------------------------------------------------------------------
  3033. // CMimePropertyContainer::_UnlinkProperty
  3034. // --------------------------------------------------------------------------------
  3035. void CMimePropertyContainer::_UnlinkProperty(LPPROPERTY pProperty, LPPROPERTY *ppNextHash)
  3036. {
  3037. // Locals
  3038. LPPROPERTY pCurrHash;
  3039. LPPROPERTY pNextHash;
  3040. LPPROPERTY pPrevHash=NULL;
  3041. #ifdef DEBUG
  3042. BOOL fUnlinked=FALSE;
  3043. #endif
  3044. // Invalid Arg
  3045. Assert(pProperty && pProperty->pSymbol && ISFLAGSET(pProperty->dwState, PRSTATE_PARENT) && pProperty->pSymbol->wHashIndex < CBUCKETS);
  3046. // Remove from array
  3047. if (ISKNOWNPID(pProperty->pSymbol->dwPropId))
  3048. m_prgIndex[pProperty->pSymbol->dwPropId] = NULL;
  3049. // Include Parameters
  3050. if (ISFLAGSET(pProperty->pSymbol->dwFlags, MPF_HASPARAMS))
  3051. _DeleteLinkedParameters(pProperty);
  3052. // Remove Property from the hash table
  3053. for (pCurrHash=m_prgHashTable[pProperty->pSymbol->wHashIndex]; pCurrHash!=NULL; pCurrHash=pCurrHash->pNextHash)
  3054. {
  3055. // Is this pProp
  3056. if (pCurrHash == pProperty)
  3057. {
  3058. // NextHash
  3059. pNextHash = pCurrHash->pNextHash;
  3060. // Set Previous
  3061. if (pPrevHash)
  3062. pPrevHash->pNextHash = pNextHash;
  3063. else
  3064. m_prgHashTable[pProperty->pSymbol->wHashIndex] = pNextHash;
  3065. // Free pCurrHash
  3066. _FreePropertyChain(pCurrHash);
  3067. // Set this after I set pCurr in case *ppNextHash is &pProperty
  3068. if (ppNextHash)
  3069. *ppNextHash = pNextHash;
  3070. // One less property
  3071. m_cProps--;
  3072. #ifdef DEBUG
  3073. fUnlinked = TRUE;
  3074. #endif
  3075. // Done
  3076. break;
  3077. }
  3078. // Set Previous
  3079. pPrevHash = pCurrHash;
  3080. }
  3081. // We better have found it
  3082. Assert(fUnlinked);
  3083. }
  3084. // --------------------------------------------------------------------------------
  3085. // CMimePropertyContainer::DeleteProp
  3086. // --------------------------------------------------------------------------------
  3087. HRESULT CMimePropertyContainer::DeleteProp(LPCSTR pszName)
  3088. {
  3089. // Locals
  3090. HRESULT hr=S_OK;
  3091. LPPROPSYMBOL pSymbol;
  3092. // Invalid Arg
  3093. Assert(pszName);
  3094. // Open Property Symbol
  3095. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pszName, FALSE, &pSymbol));
  3096. // Delete by symbol
  3097. CHECKHR(hr = DeleteProp(pSymbol));
  3098. exit:
  3099. // Done
  3100. return hr;
  3101. }
  3102. // --------------------------------------------------------------------------------
  3103. // CMimePropertyContainer::DeleteProp
  3104. // --------------------------------------------------------------------------------
  3105. HRESULT CMimePropertyContainer::DeleteProp(LPPROPSYMBOL pSymbol)
  3106. {
  3107. // Locals
  3108. HRESULT hr=S_OK;
  3109. LPPROPERTY pProperty;
  3110. // Invalid Arg
  3111. Assert(pSymbol);
  3112. // Thread Safety
  3113. EnterCriticalSection(&m_cs);
  3114. // Find the property
  3115. CHECKHR(hr = _HrFindProperty(pSymbol, &pProperty));
  3116. // Delete Prop
  3117. _UnlinkProperty(pProperty);
  3118. // Cascade Delete Dispatch
  3119. if (ISTRIGGERED(pSymbol, IST_DELETEPROP))
  3120. {
  3121. // Property Dispatch
  3122. CHECKHR(hr = _HrCallSymbolTrigger(pSymbol, IST_DELETEPROP, 0, NULL));
  3123. }
  3124. // Dirty
  3125. if (!ISFLAGSET(pSymbol->dwFlags, MPF_NODIRTY))
  3126. FLAGSET(m_dwState, COSTATE_DIRTY);
  3127. exit:
  3128. // Thread Safety
  3129. LeaveCriticalSection(&m_cs);
  3130. // Done
  3131. return hr;
  3132. }
  3133. // --------------------------------------------------------------------------------
  3134. // CMimePropertyContainer::_DeleteLinkedParameters
  3135. // --------------------------------------------------------------------------------
  3136. void CMimePropertyContainer::_DeleteLinkedParameters(LPPROPERTY pProperty)
  3137. {
  3138. // Locals
  3139. HRESULT hrFind;
  3140. FINDPROPERTY rFind;
  3141. LPPROPERTY pParameter;
  3142. // Invalid Arg
  3143. Assert(pProperty && ISFLAGSET(pProperty->pSymbol->dwFlags, MPF_HASPARAMS));
  3144. // Initialize rFind
  3145. ZeroMemory(&rFind, sizeof(FINDPROPERTY));
  3146. rFind.pszPrefix = "par:";
  3147. rFind.cchPrefix = 4;
  3148. rFind.pszName = pProperty->pSymbol->pszName;
  3149. rFind.cchName = pProperty->pSymbol->cchName;
  3150. // Find First..
  3151. hrFind = _HrFindFirstProperty(&rFind, &pParameter);
  3152. // While we find them, delete them
  3153. while (SUCCEEDED(hrFind) && pParameter)
  3154. {
  3155. // Raid-13506 - Basically PID_ATT_FILENAME doesn't get removed when all other associated props are gone.
  3156. if (ISTRIGGERED(pParameter->pSymbol, IST_DELETEPROP))
  3157. {
  3158. // Call the Trigger
  3159. _HrCallSymbolTrigger(pParameter->pSymbol, IST_DELETEPROP, 0, NULL);
  3160. }
  3161. // Remove the parameter
  3162. _UnlinkProperty(pParameter, &rFind.pProperty);
  3163. // Find Next
  3164. hrFind = _HrFindNextProperty(&rFind, &pParameter);
  3165. }
  3166. }
  3167. // --------------------------------------------------------------------------------
  3168. // CMimePropertyContainer::_FExcept
  3169. // --------------------------------------------------------------------------------
  3170. BOOL CMimePropertyContainer::_FExcept(LPPROPSYMBOL pSymbol, ULONG cNames, LPCSTR *prgszName)
  3171. {
  3172. // Verify the array
  3173. for (ULONG i=0; i<cNames; i++)
  3174. {
  3175. // By PID
  3176. if (ISPIDSTR(prgszName[i]))
  3177. {
  3178. // Compare by id
  3179. if (pSymbol->dwPropId == STRTOPID(prgszName[i]))
  3180. return TRUE;
  3181. // Else if pSymbol is linked to prgszName[i]
  3182. else if (pSymbol->pLink && pSymbol->pLink->dwPropId == STRTOPID(prgszName[i]))
  3183. return TRUE;
  3184. }
  3185. // Otherwise, by name
  3186. else
  3187. {
  3188. // Compare by name
  3189. if (lstrcmpi(pSymbol->pszName, prgszName[i]) == 0)
  3190. return TRUE;
  3191. // Otherwise if pSymbol is linked to prgszName[i]
  3192. else if (pSymbol->pLink && lstrcmpi(pSymbol->pLink->pszName, prgszName[i]) == 0)
  3193. return TRUE;
  3194. }
  3195. }
  3196. // Not Except
  3197. return FALSE;
  3198. }
  3199. // --------------------------------------------------------------------------------
  3200. // CMimePropertyContainer::DeleteExcept
  3201. // --------------------------------------------------------------------------------
  3202. HRESULT CMimePropertyContainer::DeleteExcept(ULONG cNames, LPCSTR *prgszName)
  3203. {
  3204. // Locals
  3205. HRESULT hr=S_OK;
  3206. LPPROPERTY pProperty;
  3207. ULONG i;
  3208. // Invalid Arg
  3209. if ((0 == cNames && NULL != prgszName) || (NULL == prgszName && 0 != cNames))
  3210. return TrapError(E_INVALIDARG);
  3211. // Thread Safety
  3212. EnterCriticalSection(&m_cs);
  3213. // Delete Everything
  3214. if (0 == cNames)
  3215. {
  3216. // Free the PropTable
  3217. _FreeHashTableElements();
  3218. }
  3219. // Otherwise
  3220. else
  3221. {
  3222. // Loop through the item table
  3223. for (i=0; i<CBUCKETS; i++)
  3224. {
  3225. // Walk through the chain...
  3226. pProperty = m_prgHashTable[i];
  3227. while(pProperty)
  3228. {
  3229. // Loop through the tags
  3230. if (!_FExcept(pProperty->pSymbol, cNames, prgszName))
  3231. _UnlinkProperty(pProperty, &pProperty);
  3232. else
  3233. pProperty = pProperty->pNextHash;
  3234. }
  3235. }
  3236. }
  3237. // Dirty
  3238. FLAGSET(m_dwState, COSTATE_DIRTY);
  3239. // Thread Safety
  3240. LeaveCriticalSection(&m_cs);
  3241. // Done
  3242. return hr;
  3243. }
  3244. // --------------------------------------------------------------------------------
  3245. // CMimePropertyContainer::QueryProp
  3246. // --------------------------------------------------------------------------------
  3247. HRESULT CMimePropertyContainer::QueryProp(LPCSTR pszName, LPCSTR pszCriteria, boolean fSubString, boolean fCaseSensitive)
  3248. {
  3249. // Locals
  3250. HRESULT hr=S_OK;
  3251. LPPROPSYMBOL pSymbol;
  3252. // Invalid Arg
  3253. Assert(pszName);
  3254. // Open Property Symbol
  3255. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pszName, FALSE, &pSymbol));
  3256. // Get Property by Symbol
  3257. CHECKHR(hr = QueryProp(pSymbol, pszCriteria, fSubString, fCaseSensitive));
  3258. exit:
  3259. // Done
  3260. return hr;
  3261. }
  3262. // --------------------------------------------------------------------------------
  3263. // CMimePropertyContainer::QueryProp
  3264. // --------------------------------------------------------------------------------
  3265. HRESULT CMimePropertyContainer::QueryProp(LPPROPSYMBOL pSymbol, LPCSTR pszCriteria, boolean fSubString, boolean fCaseSensitive)
  3266. {
  3267. // Locals
  3268. HRESULT hr=S_OK;
  3269. LPPROPERTY pProperty,
  3270. pCurrProp;
  3271. LPCSTR pszSearch;
  3272. MIMEVARIANT rValue;
  3273. // Parameters
  3274. if (NULL == pSymbol || NULL == pszCriteria)
  3275. return TrapError(E_INVALIDARG);
  3276. // Init
  3277. STACKSTRING_DEFINE(rCritLower, 255);
  3278. ZeroMemory(&rValue, sizeof(MIMEVARIANT));
  3279. // Init pszsearch
  3280. pszSearch = pszCriteria;
  3281. // Thread Safety
  3282. EnterCriticalSection(&m_cs);
  3283. // Find the Property
  3284. if (FAILED(_HrFindProperty(pSymbol, &pProperty)))
  3285. {
  3286. hr = S_FALSE;
  3287. goto exit;
  3288. }
  3289. // Need Lower Case...?
  3290. if (TRUE == fSubString && FALSE == fCaseSensitive)
  3291. {
  3292. // Get Length
  3293. ULONG cchCriteria = lstrlen(pszCriteria);
  3294. // Get the length of pszCritieria
  3295. STACKSTRING_SETSIZE(rCritLower, cchCriteria + 1);
  3296. // Copy It
  3297. CopyMemory(rCritLower.pszVal, pszCriteria, cchCriteria + 1);
  3298. // Lower Case...
  3299. CharLower(rCritLower.pszVal);
  3300. // Set Search
  3301. pszSearch = rCritLower.pszVal;
  3302. }
  3303. // Walk multiline properties...
  3304. for (pCurrProp=pProperty; pCurrProp!=NULL; pCurrProp=pCurrProp->pNextValue)
  3305. {
  3306. // Better have the same symbol
  3307. Assert(pCurrProp->pSymbol == pSymbol);
  3308. // If Address...
  3309. if (ISFLAGSET(pCurrProp->pSymbol->dwFlags, MPF_ADDRESS))
  3310. {
  3311. // Better have an address group
  3312. Assert(pCurrProp->pGroup);
  3313. // Search the address group
  3314. if (_HrQueryAddressGroup(pCurrProp, pszSearch, fSubString, fCaseSensitive) == S_OK)
  3315. goto exit;
  3316. }
  3317. // Otherwise
  3318. else
  3319. {
  3320. // Convert to a MVT_STRINGA
  3321. rValue.type = MVT_STRINGA;
  3322. // Convert to string
  3323. CHECKHR(hr = HrConvertVariant(pCurrProp, CVF_NOALLOC, &rValue));
  3324. // Query String
  3325. if (MimeOleQueryString(rValue.rStringA.pszVal, pszSearch, fSubString, fCaseSensitive) == S_OK)
  3326. goto exit;
  3327. // Cleanup
  3328. MimeVariantFree(&rValue);
  3329. }
  3330. }
  3331. // Not Equal
  3332. hr = S_FALSE;
  3333. exit:
  3334. // Cleanup
  3335. STACKSTRING_FREE(rCritLower);
  3336. MimeVariantFree(&rValue);
  3337. // Thread Safety
  3338. LeaveCriticalSection(&m_cs);
  3339. // Done
  3340. return hr;
  3341. }
  3342. // --------------------------------------------------------------------------------
  3343. // CMimePropertyContainer::GetCharset
  3344. // --------------------------------------------------------------------------------
  3345. HRESULT CMimePropertyContainer::GetCharset(LPHCHARSET phCharset)
  3346. {
  3347. // Invalid Arg
  3348. if (NULL == phCharset)
  3349. return TrapError(E_INVALIDARG);
  3350. // Init
  3351. *phCharset = NULL;
  3352. // Thread Safety
  3353. EnterCriticalSection(&m_cs);
  3354. // No Charset...
  3355. Assert(m_rOptions.pDefaultCharset);
  3356. // Return
  3357. *phCharset = m_rOptions.pDefaultCharset->hCharset;
  3358. // Thread Safety
  3359. LeaveCriticalSection(&m_cs);
  3360. // Done
  3361. return S_OK;
  3362. }
  3363. // --------------------------------------------------------------------------------
  3364. // CMimePropertyContainer::SetCharset
  3365. // --------------------------------------------------------------------------------
  3366. HRESULT CMimePropertyContainer::SetCharset(HCHARSET hCharset, CSETAPPLYTYPE applytype)
  3367. {
  3368. // Locals
  3369. HRESULT hr=S_OK;
  3370. LPINETCSETINFO pCharset;
  3371. LPCODEPAGEINFO pCodePage;
  3372. MIMEVARIANT rValue;
  3373. LPINETCSETINFO pCset;
  3374. LPPROPERTY pProperty;
  3375. // Invalid Arg
  3376. if (NULL == hCharset)
  3377. return TrapError(E_INVALIDARG);
  3378. // Thread Safety
  3379. EnterCriticalSection(&m_cs);
  3380. // IE v. 5.0 37562 multiple charsets are ignored on inbound message
  3381. // if we are already tagged and called with CSET_APPLY_UNTAGGED then don't overwrite
  3382. // the existing charset.
  3383. if(CSET_APPLY_UNTAGGED == applytype && ISFLAGSET(m_dwState, COSTATE_CSETTAGGED))
  3384. goto exit;
  3385. // Lookiup Charset Info
  3386. CHECKHR(hr = g_pInternat->HrOpenCharset(hCharset, &pCharset));
  3387. #ifdef OLD // See attachemnt to bug 40626
  3388. // RAID-22767 - FE-H : Athena Mail: Header should be encoded to the "EUC-KR" for the Korean
  3389. if (SUCCEEDED(g_pInternat->HrFindCodePage(pCharset->cpiInternet, &pCodePage)) && pCodePage->dwMask & ILM_HEADERCSET)
  3390. {
  3391. // Map New Charset...
  3392. if (SUCCEEDED(g_pInternat->HrOpenCharset(pCodePage->szHeaderCset, &pCset)))
  3393. {
  3394. // Example: When hCharset == ISO-2022-KR, we map to EUC-KR == hHeaderCset, and we use that as
  3395. // the header of the message, but we set param charset=iso-2022-kr and encode the body
  3396. // using iso-2022-kr. This is why rCsetInfo contains iso-2022-kr and not euc-kr.
  3397. pCharset = pCset;
  3398. }
  3399. }
  3400. #else // !OLD
  3401. // We always use now WebCharSet (see attachment message to bug 40626
  3402. if (SUCCEEDED(g_pInternat->HrFindCodePage(pCharset->cpiInternet, &pCodePage)) && pCodePage->dwMask & ILM_WEBCSET)
  3403. {
  3404. // Map New Charset...
  3405. if (SUCCEEDED(g_pInternat->HrOpenCharset(pCodePage->szWebCset, &pCset)))
  3406. pCharset = pCset;
  3407. }
  3408. #endif // OLD
  3409. // Setup a variant
  3410. rValue.type = MVT_STRINGA;
  3411. rValue.rStringA.pszVal = pCharset->szName;
  3412. rValue.rStringA.cchVal = lstrlen(pCharset->szName);
  3413. // Set the Charset Attribute
  3414. SideAssert(SUCCEEDED(SetProp(SYM_PAR_CHARSET, 0, &rValue)));
  3415. // Return
  3416. m_rOptions.pDefaultCharset = pCharset;
  3417. // Remove any specific charset information on each property
  3418. if (CSET_APPLY_ALL == applytype && m_cProps > 0)
  3419. {
  3420. // Locals
  3421. LPPROPERTY pCurrHash;
  3422. LPPROPERTY pCurrValue;
  3423. // Loop through the item table
  3424. for (ULONG i=0; i<CBUCKETS; i++)
  3425. {
  3426. // Walk the hash list
  3427. for (pCurrHash=m_prgHashTable[i]; pCurrHash!=NULL; pCurrHash=pCurrHash->pNextHash)
  3428. {
  3429. // Walk the multi-value chain
  3430. for (pCurrValue=pCurrHash; pCurrValue!=NULL; pCurrValue=pCurrValue->pNextValue)
  3431. {
  3432. // This will force it to use the default
  3433. pCurrValue->pCharset = NULL;
  3434. }
  3435. }
  3436. }
  3437. }
  3438. // Raid-38725: FE: Selecting EUC does not immediately change the encoding of sender name in preview pane
  3439. //
  3440. // $$HACKHACK$$ - This block of code is a hack because it only works if an address group has been parsed
  3441. // and not modified. Only in this case, will the new charset be applied to the addresses.
  3442. for (pProperty=m_rAdrTable.pHead; pProperty!=NULL; pProperty=pProperty->pGroup->pNext)
  3443. {
  3444. // If the property has been parsed into addresses
  3445. if (!ISFLAGSET(pProperty->dwState, PRSTATE_NEEDPARSE))
  3446. {
  3447. // We should have an address group
  3448. Assert(pProperty->pGroup);
  3449. // If we have an address group and its dirty
  3450. if (pProperty->pGroup && FALSE == pProperty->pGroup->fDirty)
  3451. {
  3452. // Free the curent list of parsed addresses
  3453. _FreeAddressChain(pProperty->pGroup);
  3454. // Not Dirty
  3455. pProperty->pGroup->fDirty = FALSE;
  3456. // Reset the parsing flag
  3457. FLAGSET(pProperty->dwState, PRSTATE_NEEDPARSE);
  3458. }
  3459. }
  3460. }
  3461. // Tag It ?
  3462. if (CSET_APPLY_TAG_ALL == applytype)
  3463. {
  3464. // Mark as being tagged
  3465. FLAGSET(m_dwState, COSTATE_CSETTAGGED);
  3466. }
  3467. // Dirty
  3468. FLAGSET(m_dwState, COSTATE_DIRTY);
  3469. exit:
  3470. // Thread Safety
  3471. LeaveCriticalSection(&m_cs);
  3472. // Done
  3473. return hr;
  3474. }
  3475. // --------------------------------------------------------------------------------
  3476. // CMimePropertyContainer::GetParameters
  3477. // --------------------------------------------------------------------------------
  3478. HRESULT CMimePropertyContainer::GetParameters(LPCSTR pszName, ULONG *pcParams, LPMIMEPARAMINFO *pprgParam)
  3479. {
  3480. // Locals
  3481. HRESULT hr=S_OK,
  3482. hrFind;
  3483. FINDPROPERTY rFind;
  3484. LPMIMEPARAMINFO prgParam=NULL;
  3485. ULONG cParams=0,
  3486. cAlloc=0;
  3487. LPSTR pszParamName;
  3488. LPPROPERTY pParameter;
  3489. MIMEVARIANT rValue;
  3490. LPPROPSYMBOL pSymbol;
  3491. // Parameters
  3492. if (NULL == pszName || NULL == pcParams || NULL == pprgParam)
  3493. return TrapError(E_INVALIDARG);
  3494. // Init
  3495. *pcParams = 0;
  3496. *pprgParam = NULL;
  3497. // Thread Safety
  3498. EnterCriticalSection(&m_cs);
  3499. // Find Symbol from pszName
  3500. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pszName, FALSE, &pSymbol));
  3501. // Initialize rFind
  3502. ZeroMemory(&rFind, sizeof(FINDPROPERTY));
  3503. rFind.pszPrefix = "par:";
  3504. rFind.cchPrefix = 4;
  3505. rFind.pszName = pSymbol->pszName;
  3506. rFind.cchName = pSymbol->cchName;
  3507. // Find First..
  3508. hrFind = _HrFindFirstProperty(&rFind, &pParameter);
  3509. // While we find them, delete them
  3510. while (SUCCEEDED(hrFind) && pParameter)
  3511. {
  3512. // Grow my array
  3513. if (cParams + 1 >= cAlloc)
  3514. {
  3515. // Realloc
  3516. CHECKHR(hr = HrRealloc((LPVOID *)&prgParam, sizeof(MIMEPARAMINFO) * (cAlloc + 5)));
  3517. // Inc cAlloc
  3518. cAlloc+=5;
  3519. }
  3520. // Get Parameter Name
  3521. pszParamName = PszScanToCharA((LPSTR)pParameter->pSymbol->pszName, ':');
  3522. pszParamName++;
  3523. pszParamName = PszScanToCharA(pszParamName, ':');
  3524. pszParamName++;
  3525. // Copy Name
  3526. CHECKALLOC(prgParam[cParams].pszName = PszDupA(pszParamName));
  3527. // Copy Data
  3528. rValue.type = MVT_STRINGA;
  3529. CHECKHR(hr = GetProp(pParameter->pSymbol, 0, &rValue));
  3530. // Save this
  3531. prgParam[cParams].pszData = rValue.rStringA.pszVal;
  3532. // Increment cParams
  3533. cParams++;
  3534. // Find Next
  3535. hrFind = _HrFindNextProperty(&rFind, &pParameter);
  3536. }
  3537. // Return it
  3538. *pcParams = cParams;
  3539. *pprgParam = prgParam;
  3540. exit:
  3541. // Failure...
  3542. if (FAILED(hr) && prgParam)
  3543. g_pMoleAlloc->FreeParamInfoArray(cParams, prgParam, TRUE);
  3544. // Thread Safety
  3545. LeaveCriticalSection(&m_cs);
  3546. // Done
  3547. return hr;
  3548. }
  3549. #ifndef WIN16
  3550. // --------------------------------------------------------------------------------
  3551. // CMimePropertyContainer::HrResolveURL
  3552. // --------------------------------------------------------------------------------
  3553. HRESULT CMimePropertyContainer::HrResolveURL(LPRESOLVEURLINFO pURL)
  3554. {
  3555. // Locals
  3556. HRESULT hr=S_OK;
  3557. LPWSTR pwszTemp=NULL;
  3558. LPSTR pszBase=NULL;
  3559. LPSTR pszContentID=NULL;
  3560. LPSTR pszLocation=NULL;
  3561. LPSTR pszAbsURL1=NULL;
  3562. LPSTR pszAbsURL2=NULL;
  3563. LPSTR pszT=NULL;
  3564. ULONG cch;
  3565. // Invalid Arg
  3566. Assert(pURL);
  3567. // Init Stack Strings
  3568. STACKSTRING_DEFINE(rCleanCID, 255);
  3569. // Thread Safety
  3570. EnterCriticalSection(&m_cs);
  3571. // Content-Location
  3572. if(SUCCEEDED(GetPropW(SYM_HDR_CNTLOC, &pwszTemp)))
  3573. {
  3574. cch = lstrlenW(pwszTemp) + 1;
  3575. if(SUCCEEDED(HrAlloc((LPVOID *)&pszLocation, cch * sizeof(WCHAR))))
  3576. WideCharToMultiByte(CP_ACP, 0, pwszTemp, -1, pszLocation, cch * sizeof(WCHAR), NULL, NULL);
  3577. MemFree(pwszTemp);
  3578. }
  3579. // Content-ID
  3580. if(SUCCEEDED(GetPropW(SYM_HDR_CNTID, &pwszTemp)))
  3581. {
  3582. cch = lstrlenW(pwszTemp) + 1;
  3583. if(SUCCEEDED(HrAlloc((LPVOID *)&pszContentID, cch * sizeof(WCHAR))))
  3584. WideCharToMultiByte(CP_ACP, 0, pwszTemp, -1, pszContentID, cch * sizeof(WCHAR), NULL, NULL);
  3585. MemFree(pwszTemp);
  3586. }
  3587. // Content-Base
  3588. if(SUCCEEDED(GetPropW(SYM_HDR_CNTBASE, &pwszTemp)))
  3589. {
  3590. cch = lstrlenW(pwszTemp) + 1;
  3591. if(SUCCEEDED(HrAlloc((LPVOID *)&pszBase, cch * sizeof(WCHAR))))
  3592. WideCharToMultiByte(CP_ACP, 0, pwszTemp, -1, pszBase, cch * sizeof(WCHAR), NULL, NULL);
  3593. MemFree(pwszTemp);
  3594. }
  3595. // Both Null, no match
  3596. if (!pszLocation && !pszContentID)
  3597. {
  3598. hr = TrapError(MIME_E_NOT_FOUND);
  3599. goto exit;
  3600. }
  3601. // If URL is a CID
  3602. if (TRUE == pURL->fIsCID)
  3603. {
  3604. // Locals
  3605. ULONG cb;
  3606. if(pszLocation)
  3607. {
  3608. // Match char for char
  3609. if (MimeOleCompareUrl(pszLocation, TRUE, pURL->pszURL, FALSE) == S_OK)
  3610. goto exit;
  3611. }
  3612. if(pszContentID)
  3613. {
  3614. // Match char for char minus cid:
  3615. if (MimeOleCompareUrlSimple(pURL->pszURL, pszContentID) == S_OK)
  3616. goto exit;
  3617. // Dup the string
  3618. CHECKALLOC(pszT = PszDupA(pURL->pszURL));
  3619. // Strip leading and trailing whitespace
  3620. cb = lstrlen(pszT);
  3621. UlStripWhitespace(pszT, TRUE, TRUE, &cb);
  3622. // Get Stack Stream Read for
  3623. STACKSTRING_SETSIZE(rCleanCID, cb + 4);
  3624. // Format the string
  3625. wnsprintf(rCleanCID.pszVal, (cb + 4), "<%s>", pszT);
  3626. // Match char for char minus cid:
  3627. if (MimeOleCompareUrlSimple(rCleanCID.pszVal, pszContentID) == S_OK)
  3628. goto exit;
  3629. }
  3630. }
  3631. // Otherwise, non-CID resolution
  3632. else if (pszLocation)
  3633. {
  3634. // Raid-62579: Athena: Need to support MHTML content-base inheritance
  3635. if (NULL == pszBase && pURL->pszInheritBase)
  3636. {
  3637. // Jimmy up a fake base
  3638. pszBase = StrDupA(pURL->pszInheritBase);
  3639. }
  3640. // Part Has Base
  3641. if (NULL != pszBase)
  3642. {
  3643. // Combine URLs
  3644. CHECKHR(hr = MimeOleCombineURL(pszBase, lstrlen(pszBase), pszLocation, lstrlen(pszLocation), TRUE, &pszAbsURL1));
  3645. // URI has no base
  3646. if (NULL == pURL->pszBase)
  3647. {
  3648. // Compare
  3649. if (MimeOleCompareUrlSimple(pURL->pszURL, pszAbsURL1) == S_OK)
  3650. goto exit;
  3651. }
  3652. // URI Has a Base
  3653. else
  3654. {
  3655. // Combine URLs
  3656. CHECKHR(hr = MimeOleCombineURL(pURL->pszBase, lstrlen(pURL->pszBase), pURL->pszURL, lstrlen(pURL->pszURL), FALSE, &pszAbsURL2));
  3657. // Compare
  3658. if (MimeOleCompareUrlSimple(pszAbsURL1, pszAbsURL2) == S_OK)
  3659. goto exit;
  3660. }
  3661. }
  3662. // Part has no base
  3663. else
  3664. {
  3665. // URI has no base
  3666. if (NULL == pURL->pszBase)
  3667. {
  3668. // Compare
  3669. if (MimeOleCompareUrl(pszLocation, TRUE, pURL->pszURL, FALSE) == S_OK)
  3670. goto exit;
  3671. }
  3672. // URI Has a Base
  3673. else
  3674. {
  3675. // Combine URLs
  3676. CHECKHR(hr = MimeOleCombineURL(pURL->pszBase, lstrlen(pURL->pszBase), pURL->pszURL, lstrlen(pURL->pszURL), FALSE, &pszAbsURL2));
  3677. // Compare
  3678. if (MimeOleCompareUrl(pszLocation, TRUE, pszAbsURL2, FALSE) == S_OK)
  3679. goto exit;
  3680. }
  3681. }
  3682. }
  3683. // Not Found
  3684. hr = TrapError(MIME_E_NOT_FOUND);
  3685. exit:
  3686. // Cleanup
  3687. STACKSTRING_FREE(rCleanCID);
  3688. MemFree(pszBase);
  3689. MemFree(pszContentID);
  3690. MemFree(pszLocation);
  3691. MemFree(pszAbsURL1);
  3692. MemFree(pszAbsURL2);
  3693. MemFree(pszT);
  3694. // Thread Safety
  3695. LeaveCriticalSection(&m_cs);
  3696. // Done
  3697. return hr;
  3698. }
  3699. // --------------------------------------------------------------------------------
  3700. // CMimePropertyContainer::IsContentType
  3701. // --------------------------------------------------------------------------------
  3702. HRESULT CMimePropertyContainer::IsContentType(LPCSTR pszPriType, LPCSTR pszSubType)
  3703. {
  3704. // Locals
  3705. HRESULT hr=S_OK;
  3706. // Wildcard everyting
  3707. if (NULL == pszPriType && NULL == pszSubType)
  3708. return S_OK;
  3709. // Thread Safety
  3710. EnterCriticalSection(&m_cs);
  3711. // Get Known
  3712. LPPROPERTY pCntType = m_prgIndex[PID_ATT_PRITYPE];
  3713. LPPROPERTY pSubType = m_prgIndex[PID_ATT_SUBTYPE];
  3714. // No Data
  3715. if (NULL == pCntType || NULL == pSubType || !ISSTRINGA(&pCntType->rValue) || !ISSTRINGA(&pSubType->rValue))
  3716. {
  3717. // Compare Against STR_CNT_TEXT
  3718. if (pszPriType && lstrcmpi(pszPriType, STR_CNT_TEXT) != 0)
  3719. {
  3720. hr = S_FALSE;
  3721. goto exit;
  3722. }
  3723. // Compare Against STR_CNT_TEXT
  3724. if (pszSubType && lstrcmpi(pszSubType, STR_SUB_PLAIN) != 0)
  3725. {
  3726. hr = S_FALSE;
  3727. goto exit;
  3728. }
  3729. }
  3730. else
  3731. {
  3732. // Comparing pszPriType
  3733. if (pszPriType && lstrcmpi(pszPriType, pCntType->rValue.rStringA.pszVal) != 0)
  3734. {
  3735. hr = S_FALSE;
  3736. goto exit;
  3737. }
  3738. // Comparing pszSubType
  3739. if (pszSubType && lstrcmpi(pszSubType, pSubType->rValue.rStringA.pszVal) != 0)
  3740. {
  3741. hr = S_FALSE;
  3742. goto exit;
  3743. }
  3744. }
  3745. exit:
  3746. // Thread Safety
  3747. LeaveCriticalSection(&m_cs);
  3748. // Done
  3749. return hr;
  3750. }
  3751. // --------------------------------------------------------------------------------
  3752. // CMimePropertyContainer::IsContentTypeW
  3753. // --------------------------------------------------------------------------------
  3754. HRESULT CMimePropertyContainer::IsContentTypeW(LPCWSTR pszPriType, LPCWSTR pszSubType)
  3755. {
  3756. // Locals
  3757. HRESULT hr=S_OK;
  3758. LPWSTR pszT1=NULL;
  3759. LPWSTR pszT2=NULL;
  3760. // Wildcard everyting
  3761. if (NULL == pszPriType && NULL == pszSubType)
  3762. return S_OK;
  3763. // Thread Safety
  3764. EnterCriticalSection(&m_cs);
  3765. // Get Known
  3766. LPPROPERTY pCntType = m_prgIndex[PID_ATT_PRITYPE];
  3767. LPPROPERTY pSubType = m_prgIndex[PID_ATT_SUBTYPE];
  3768. // No Data
  3769. if (NULL == pCntType || NULL == pSubType || !ISSTRINGA(&pCntType->rValue) || !ISSTRINGA(&pSubType->rValue))
  3770. {
  3771. // Compare Against STR_CNT_TEXT
  3772. if (pszPriType && StrCmpIW(pszPriType, L"text") != 0)
  3773. {
  3774. hr = S_FALSE;
  3775. goto exit;
  3776. }
  3777. // Compare Against STR_CNT_TEXT
  3778. if (pszSubType && StrCmpIW(pszSubType, L"plain") != 0)
  3779. {
  3780. hr = S_FALSE;
  3781. goto exit;
  3782. }
  3783. }
  3784. else
  3785. {
  3786. // Compare pszPriType
  3787. if (pszPriType)
  3788. {
  3789. // To Unicode
  3790. IF_NULLEXIT(pszT1 = PszToUnicode(CP_ACP, pCntType->rValue.rStringA.pszVal));
  3791. // Compare
  3792. if (StrCmpIW(pszPriType, pszT1) != 0)
  3793. {
  3794. hr = S_FALSE;
  3795. goto exit;
  3796. }
  3797. }
  3798. // Compare pszSubType
  3799. if (pszSubType)
  3800. {
  3801. // To Unicode
  3802. IF_NULLEXIT(pszT2 = PszToUnicode(CP_ACP, pSubType->rValue.rStringA.pszVal));
  3803. // Comparing pszSubType
  3804. if (StrCmpIW(pszSubType, pszT2) != 0)
  3805. {
  3806. hr = S_FALSE;
  3807. goto exit;
  3808. }
  3809. }
  3810. }
  3811. exit:
  3812. // Thread Safety
  3813. LeaveCriticalSection(&m_cs);
  3814. // Cleanup
  3815. MemFree(pszT1);
  3816. MemFree(pszT2);
  3817. // Done
  3818. return hr;
  3819. }
  3820. // --------------------------------------------------------------------------------
  3821. // CMimePropertyContainer::Clone
  3822. // --------------------------------------------------------------------------------
  3823. HRESULT CMimePropertyContainer::Clone(IMimePropertySet **ppPropertySet)
  3824. {
  3825. // Locals
  3826. HRESULT hr=S_OK;
  3827. LPCONTAINER pContainer=NULL;
  3828. // InvalidArg
  3829. if (NULL == ppPropertySet)
  3830. return TrapError(E_INVALIDARG);
  3831. // Init
  3832. *ppPropertySet = NULL;
  3833. // Thread Safety
  3834. EnterCriticalSection(&m_cs);
  3835. // Ask the container to clone itself
  3836. CHECKHR(hr = Clone(&pContainer));
  3837. // Bind to the IID_IMimeHeaderTable View
  3838. CHECKHR(hr = pContainer->QueryInterface(IID_IMimePropertySet, (LPVOID *)ppPropertySet));
  3839. exit:
  3840. // Cleanup
  3841. SafeRelease(pContainer);
  3842. // Thread Safety
  3843. LeaveCriticalSection(&m_cs);
  3844. // Done
  3845. return hr;
  3846. }
  3847. // --------------------------------------------------------------------------------
  3848. // CMimePropertyContainer::Clone
  3849. // --------------------------------------------------------------------------------
  3850. HRESULT CMimePropertyContainer::Clone(LPCONTAINER *ppContainer)
  3851. {
  3852. // Locals
  3853. HRESULT hr=S_OK;
  3854. LPCONTAINER pContainer=NULL;
  3855. // Invalid ARg
  3856. if (NULL == ppContainer)
  3857. return TrapError(E_INVALIDARG);
  3858. // Init
  3859. *ppContainer = NULL;
  3860. // Thread Safety
  3861. EnterCriticalSection(&m_cs);
  3862. // Create new container, NULL == no outer property set
  3863. CHECKALLOC(pContainer = new CMimePropertyContainer);
  3864. // Init that new container
  3865. CHECKHR(hr = pContainer->InitNew());
  3866. // Interate the Properties
  3867. CHECKHR(hr = _HrClonePropertiesTo(pContainer));
  3868. // If I have a stream, give it to the new table
  3869. if (m_pStmLock)
  3870. {
  3871. // Just pass m_pStmLock into pTable
  3872. pContainer->m_pStmLock = m_pStmLock;
  3873. pContainer->m_pStmLock->AddRef();
  3874. pContainer->m_cbStart = m_cbStart;
  3875. pContainer->m_cbSize = m_cbSize;
  3876. }
  3877. // Give it my state
  3878. pContainer->m_dwState = m_dwState;
  3879. // Give it my options
  3880. pContainer->m_rOptions.pDefaultCharset = m_rOptions.pDefaultCharset;
  3881. pContainer->m_rOptions.cbMaxLine = m_rOptions.cbMaxLine;
  3882. pContainer->m_rOptions.fAllow8bit = m_rOptions.fAllow8bit;
  3883. // Return Clone
  3884. (*ppContainer) = pContainer;
  3885. (*ppContainer)->AddRef();
  3886. exit:
  3887. // Cleanup
  3888. SafeRelease(pContainer);
  3889. // Thread Safety
  3890. LeaveCriticalSection(&m_cs);
  3891. // Done
  3892. return hr;
  3893. }
  3894. // --------------------------------------------------------------------------------
  3895. // CMimePropertyContainer::_HrClonePropertiesTo
  3896. // --------------------------------------------------------------------------------
  3897. HRESULT CMimePropertyContainer::_HrClonePropertiesTo(LPCONTAINER pContainer)
  3898. {
  3899. // Locals
  3900. HRESULT hr=S_OK;
  3901. LPPROPERTY pCurrHash, pCurrValue, pDestProp;
  3902. // Invalid Arg
  3903. Assert(pContainer);
  3904. // Loop through the item table
  3905. for (ULONG i=0; i<CBUCKETS; i++)
  3906. {
  3907. // Walk the Hash Chain
  3908. for (pCurrHash=m_prgHashTable[i]; pCurrHash!=NULL; pCurrHash=pCurrHash->pNextHash)
  3909. {
  3910. // Walk multiple Values
  3911. for (pCurrValue=pCurrHash; pCurrValue!=NULL; pCurrValue=pCurrValue->pNextValue)
  3912. {
  3913. // Linked Attributes are Not Copied
  3914. if (ISFLAGSET(pCurrValue->pSymbol->dwFlags, MPF_ATTRIBUTE) && NULL != pCurrValue->pSymbol->pLink)
  3915. continue;
  3916. // Does the Property need to be parsed ?
  3917. if (ISFLAGSET(pCurrValue->pSymbol->dwFlags, MPF_ADDRESS))
  3918. {
  3919. // Make sure the address is parsed
  3920. CHECKHR(hr = _HrParseInternetAddress(pCurrValue));
  3921. }
  3922. // Insert Copy of pCurrValue into pContiner
  3923. CHECKHR(hr = pContainer->HrInsertCopy(pCurrValue, FALSE));
  3924. }
  3925. }
  3926. }
  3927. exit:
  3928. // Done
  3929. return hr;
  3930. }
  3931. // --------------------------------------------------------------------------------
  3932. // CMimePropertyContainer::_HrCopyProperty
  3933. // --------------------------------------------------------------------------------
  3934. HRESULT CMimePropertyContainer::_HrCopyProperty(LPPROPERTY pProperty, LPCONTAINER pDest, BOOL fFromMovePropos)
  3935. {
  3936. // Locals
  3937. HRESULT hr=S_OK;
  3938. LPPROPERTY pCurrValue;
  3939. // Walk multiple Values
  3940. for (pCurrValue=pProperty; pCurrValue!=NULL; pCurrValue=pCurrValue->pNextValue)
  3941. {
  3942. // Does the Property need to be parsed ?
  3943. if (ISFLAGSET(pCurrValue->pSymbol->dwFlags, MPF_ADDRESS))
  3944. {
  3945. // Make sure the address is parsed
  3946. CHECKHR(hr = _HrParseInternetAddress(pCurrValue));
  3947. }
  3948. // Insert pProperty into pDest
  3949. CHECKHR(hr = pDest->HrInsertCopy(pCurrValue, fFromMovePropos));
  3950. }
  3951. // If pCurrHash has Parameters, copy those over as well
  3952. if (ISFLAGSET(pProperty->pSymbol->dwFlags, MPF_HASPARAMS))
  3953. {
  3954. // Copy Parameters
  3955. CHECKHR(hr = _HrCopyParameters(pProperty, pDest));
  3956. }
  3957. exit:
  3958. // Done
  3959. return hr;
  3960. }
  3961. // --------------------------------------------------------------------------------
  3962. // CMimePropertyContainer::_HrCopyParameters
  3963. // --------------------------------------------------------------------------------
  3964. HRESULT CMimePropertyContainer::_HrCopyParameters(LPPROPERTY pProperty, LPCONTAINER pDest)
  3965. {
  3966. // Locals
  3967. HRESULT hr=S_OK;
  3968. HRESULT hrFind;
  3969. FINDPROPERTY rFind;
  3970. LPPROPERTY pParameter;
  3971. // Invalid Arg
  3972. Assert(pProperty && ISFLAGSET(pProperty->pSymbol->dwFlags, MPF_HASPARAMS));
  3973. // Initialize rFind
  3974. ZeroMemory(&rFind, sizeof(FINDPROPERTY));
  3975. rFind.pszPrefix = "par:";
  3976. rFind.cchPrefix = 4;
  3977. rFind.pszName = pProperty->pSymbol->pszName;
  3978. rFind.cchName = pProperty->pSymbol->cchName;
  3979. // Find First..
  3980. hrFind = _HrFindFirstProperty(&rFind, &pParameter);
  3981. // While we find them, delete them
  3982. while (SUCCEEDED(hrFind) && pParameter)
  3983. {
  3984. // Remove the parameter
  3985. CHECKHR(hr = pDest->HrInsertCopy(pParameter, FALSE));
  3986. // Find Next
  3987. hrFind = _HrFindNextProperty(&rFind, &pParameter);
  3988. }
  3989. exit:
  3990. // Done
  3991. return hr;
  3992. }
  3993. // --------------------------------------------------------------------------------
  3994. // CMimePropertyContainer::HrInsertCopy
  3995. // --------------------------------------------------------------------------------
  3996. HRESULT CMimePropertyContainer::HrInsertCopy(LPPROPERTY pSource, BOOL fFromMovePropos)
  3997. {
  3998. // Locals
  3999. HRESULT hr=S_OK;
  4000. LPPROPERTY pDest;
  4001. LPMIMEADDRESS pAddress;
  4002. LPMIMEADDRESS pNew;
  4003. // Invalid Arg
  4004. Assert(pSource);
  4005. // Thread Safety
  4006. EnterCriticalSection(&m_cs);
  4007. // Append a new property to the
  4008. CHECKHR(hr = _HrAppendProperty(pSource->pSymbol, &pDest));
  4009. // If this is an address...
  4010. if (ISFLAGSET(pSource->pSymbol->dwFlags, MPF_ADDRESS))
  4011. {
  4012. // Both Address Group Better Exist
  4013. Assert(pSource->pGroup && pDest->pGroup && !ISFLAGSET(pSource->dwState, PRSTATE_NEEDPARSE));
  4014. // Loop Infos...
  4015. for (pAddress=pSource->pGroup->pHead; pAddress!=NULL; pAddress=pAddress->pNext)
  4016. {
  4017. // Append pDest->pGroup
  4018. CHECKHR(hr = _HrAppendAddressGroup(pDest->pGroup, &pNew));
  4019. // Copy Current to New
  4020. CHECKHR(hr = HrMimeAddressCopy(pAddress, pNew));
  4021. }
  4022. }
  4023. // Otheriwse, just set the variant data on pDest
  4024. else
  4025. {
  4026. // Set It
  4027. CHECKHR(hr = _HrSetPropertyValue(pDest, ((pSource->ietValue == IET_ENCODED) ? PDF_ENCODED : 0), &pSource->rValue, fFromMovePropos));
  4028. }
  4029. // Copy the State
  4030. pDest->dwState = pSource->dwState;
  4031. pDest->dwRowNumber = pSource->dwRowNumber;
  4032. pDest->cboffStart = pSource->cboffStart;
  4033. pDest->cboffColon = pSource->cboffColon;
  4034. pDest->cboffEnd = pSource->cboffEnd;
  4035. exit:
  4036. // Thread Safety
  4037. LeaveCriticalSection(&m_cs);
  4038. // Done
  4039. return hr;
  4040. }
  4041. // --------------------------------------------------------------------------------
  4042. // CMimePropertyContainer::CopyProps
  4043. // --------------------------------------------------------------------------------
  4044. HRESULT CMimePropertyContainer::CopyProps(ULONG cNames, LPCSTR *prgszName, IMimePropertySet *pPropertySet)
  4045. {
  4046. // Locals
  4047. HRESULT hr=S_OK;
  4048. ULONG i;
  4049. LPPROPSYMBOL pSymbol;
  4050. LPPROPERTY pProperty,
  4051. pCurrValue,
  4052. pCurrHash,
  4053. pNextHash;
  4054. LPCONTAINER pDest=NULL;
  4055. // Invalid ARg
  4056. if ((0 == cNames && NULL != prgszName) || (NULL == prgszName && 0 != cNames) || NULL == pPropertySet)
  4057. return TrapError(E_INVALIDARG);
  4058. // Thread Safety
  4059. EnterCriticalSection(&m_cs);
  4060. // QI for destination continer
  4061. CHECKHR(hr = pPropertySet->BindToObject(IID_CMimePropertyContainer, (LPVOID *)&pDest));
  4062. // Raid-62016: CDO: Bodypart promotion causes loss of charset
  4063. // Delete All Properties
  4064. if (0 == cNames)
  4065. {
  4066. // Loop through the item table
  4067. for (i=0; i<CBUCKETS; i++)
  4068. {
  4069. // Init First Item
  4070. for (pCurrHash=m_prgHashTable[i]; pCurrHash!=NULL; pCurrHash=pCurrHash->pNextHash)
  4071. {
  4072. // Delete from Destination Container
  4073. pDest->DeleteProp(pCurrHash->pSymbol);
  4074. }
  4075. }
  4076. }
  4077. // Otherwise, copy selected properties
  4078. else
  4079. {
  4080. // Call Into InetPropSet
  4081. for (i=0; i<cNames; i++)
  4082. {
  4083. // Bad Name..
  4084. if (NULL == prgszName[i])
  4085. {
  4086. Assert(FALSE);
  4087. continue;
  4088. }
  4089. // Open Property Symbol
  4090. if (SUCCEEDED(g_pSymCache->HrOpenSymbol(prgszName[i], FALSE, &pSymbol)))
  4091. {
  4092. // Find the Property
  4093. if (SUCCEEDED(_HrFindProperty(pSymbol, &pProperty)))
  4094. {
  4095. // Delete from Destination Container
  4096. pDest->DeleteProp(pSymbol);
  4097. }
  4098. }
  4099. }
  4100. }
  4101. // Move All Properties
  4102. if (0 == cNames)
  4103. {
  4104. // Loop through the item table
  4105. for (i=0; i<CBUCKETS; i++)
  4106. {
  4107. // Init First Item
  4108. for (pCurrHash=m_prgHashTable[i]; pCurrHash!=NULL; pCurrHash=pCurrHash->pNextHash)
  4109. {
  4110. // Copy the Property To
  4111. CHECKHR(hr = _HrCopyProperty(pCurrHash, pDest, FALSE));
  4112. }
  4113. }
  4114. }
  4115. // Otherwise, copy selected properties
  4116. else
  4117. {
  4118. // Call Into InetPropSet
  4119. for (i=0; i<cNames; i++)
  4120. {
  4121. // Bad Name..
  4122. if (NULL == prgszName[i])
  4123. {
  4124. Assert(FALSE);
  4125. continue;
  4126. }
  4127. // Open Property Symbol
  4128. if (SUCCEEDED(g_pSymCache->HrOpenSymbol(prgszName[i], FALSE, &pSymbol)))
  4129. {
  4130. // Find the Property
  4131. if (SUCCEEDED(_HrFindProperty(pSymbol, &pProperty)))
  4132. {
  4133. // Copy the Property To
  4134. CHECKHR(hr = _HrCopyProperty(pProperty, pDest, FALSE));
  4135. }
  4136. }
  4137. }
  4138. }
  4139. exit:
  4140. // Cleanup
  4141. SafeRelease(pDest);
  4142. // Thread Safety
  4143. LeaveCriticalSection(&m_cs);
  4144. // Done
  4145. return hr;
  4146. }
  4147. // --------------------------------------------------------------------------------
  4148. // CMimePropertyContainer::MoveProps
  4149. // --------------------------------------------------------------------------------
  4150. HRESULT CMimePropertyContainer::MoveProps(ULONG cNames, LPCSTR *prgszName, IMimePropertySet *pPropertySet)
  4151. {
  4152. // Locals
  4153. HRESULT hr=S_OK;
  4154. ULONG i;
  4155. LPPROPSYMBOL pSymbol;
  4156. LPPROPERTY pProperty;
  4157. LPPROPERTY pCurrHash;
  4158. LPCONTAINER pDest=NULL;
  4159. // Invalid ARg
  4160. if ((0 == cNames && NULL != prgszName) || (NULL == prgszName && 0 != cNames) || NULL == pPropertySet)
  4161. return TrapError(E_INVALIDARG);
  4162. // Thread Safety
  4163. EnterCriticalSection(&m_cs);
  4164. // QI for destination continer
  4165. CHECKHR(hr = pPropertySet->BindToObject(IID_CMimePropertyContainer, (LPVOID *)&pDest));
  4166. // Raid-62016: CDO: Bodypart promotion causes loss of charset
  4167. // Delete Properties in the Destination First
  4168. if (0 == cNames)
  4169. {
  4170. // Loop through the item table
  4171. for (i=0; i<CBUCKETS; i++)
  4172. {
  4173. // Init First Item
  4174. for (pCurrHash=m_prgHashTable[i]; pCurrHash!=NULL; pCurrHash=pCurrHash->pNextHash)
  4175. {
  4176. // Delete from Destination Container
  4177. pDest->DeleteProp(pCurrHash->pSymbol);
  4178. }
  4179. }
  4180. }
  4181. // Otherwise, selective delete
  4182. else
  4183. {
  4184. // Call Into InetPropSet
  4185. for (i=0; i<cNames; i++)
  4186. {
  4187. // Bad Name..
  4188. if (NULL == prgszName[i])
  4189. {
  4190. Assert(FALSE);
  4191. continue;
  4192. }
  4193. // Open Property Symbol
  4194. if (SUCCEEDED(g_pSymCache->HrOpenSymbol(prgszName[i], FALSE, &pSymbol)))
  4195. {
  4196. // Find the Property
  4197. if (SUCCEEDED(_HrFindProperty(pSymbol, &pProperty)))
  4198. {
  4199. // Delete from Destination Container
  4200. pDest->DeleteProp(pSymbol);
  4201. }
  4202. }
  4203. }
  4204. }
  4205. // Move All Properties
  4206. if (0 == cNames)
  4207. {
  4208. // Loop through the item table
  4209. for (i=0; i<CBUCKETS; i++)
  4210. {
  4211. // Init First Item
  4212. pCurrHash = m_prgHashTable[i];
  4213. // Walk the Hash Chain
  4214. while(pCurrHash)
  4215. {
  4216. // Copy the Property To
  4217. CHECKHR(hr = _HrCopyProperty(pCurrHash, pDest, TRUE));
  4218. // Delete pProperty
  4219. _UnlinkProperty(pCurrHash, &pCurrHash);
  4220. }
  4221. }
  4222. }
  4223. // Otherwise, selective move
  4224. else
  4225. {
  4226. // Call Into InetPropSet
  4227. for (i=0; i<cNames; i++)
  4228. {
  4229. // Bad Name..
  4230. if (NULL == prgszName[i])
  4231. {
  4232. Assert(FALSE);
  4233. continue;
  4234. }
  4235. // Open Property Symbol
  4236. if (SUCCEEDED(g_pSymCache->HrOpenSymbol(prgszName[i], FALSE, &pSymbol)))
  4237. {
  4238. // Find the Property
  4239. if (SUCCEEDED(_HrFindProperty(pSymbol, &pProperty)))
  4240. {
  4241. // Copy the Property To
  4242. CHECKHR(hr = _HrCopyProperty(pProperty, pDest, FALSE));
  4243. // Delete pProperty
  4244. _UnlinkProperty(pProperty);
  4245. }
  4246. }
  4247. }
  4248. }
  4249. // Dirty
  4250. FLAGSET(m_dwState, COSTATE_DIRTY);
  4251. exit:
  4252. // Cleanup
  4253. SafeRelease(pDest);
  4254. // Thread Safety
  4255. LeaveCriticalSection(&m_cs);
  4256. // Done
  4257. return hr;
  4258. }
  4259. // --------------------------------------------------------------------------------
  4260. // CMimePropertyContainer::SetOption
  4261. // --------------------------------------------------------------------------------
  4262. HRESULT CMimePropertyContainer::SetOption(const TYPEDID oid, LPCPROPVARIANT pVariant)
  4263. {
  4264. // Locals
  4265. HRESULT hr=S_OK;
  4266. // check params
  4267. if (NULL == pVariant)
  4268. return TrapError(E_INVALIDARG);
  4269. // Thread Safety
  4270. EnterCriticalSection(&m_cs);
  4271. // Handle Optid
  4272. switch(oid)
  4273. {
  4274. // -----------------------------------------------------------------------
  4275. case OID_HEADER_RELOAD_TYPE:
  4276. if (pVariant->ulVal > RELOAD_HEADER_REPLACE)
  4277. {
  4278. hr = TrapError(MIME_E_INVALID_OPTION_VALUE);
  4279. goto exit;
  4280. }
  4281. if (m_rOptions.ReloadType != (RELOADTYPE)pVariant->ulVal)
  4282. {
  4283. FLAGSET(m_dwState, COSTATE_DIRTY);
  4284. m_rOptions.ReloadType = (RELOADTYPE)pVariant->ulVal;
  4285. }
  4286. break;
  4287. // -----------------------------------------------------------------------
  4288. case OID_NO_DEFAULT_CNTTYPE:
  4289. if (m_rOptions.fNoDefCntType != (pVariant->boolVal ? TRUE : FALSE))
  4290. m_rOptions.fNoDefCntType = pVariant->boolVal ? TRUE : FALSE;
  4291. break;
  4292. // -----------------------------------------------------------------------
  4293. case OID_ALLOW_8BIT_HEADER:
  4294. if (m_rOptions.fAllow8bit != (pVariant->boolVal ? TRUE : FALSE))
  4295. {
  4296. FLAGSET(m_dwState, COSTATE_DIRTY);
  4297. m_rOptions.fAllow8bit = pVariant->boolVal ? TRUE : FALSE;
  4298. }
  4299. break;
  4300. // -----------------------------------------------------------------------
  4301. case OID_CBMAX_HEADER_LINE:
  4302. if (pVariant->ulVal < MIN_CBMAX_HEADER_LINE || pVariant->ulVal > MAX_CBMAX_HEADER_LINE)
  4303. {
  4304. hr = TrapError(MIME_E_INVALID_OPTION_VALUE);
  4305. goto exit;
  4306. }
  4307. if (m_rOptions.cbMaxLine != pVariant->ulVal)
  4308. {
  4309. FLAGSET(m_dwState, COSTATE_DIRTY);
  4310. m_rOptions.cbMaxLine = pVariant->ulVal;
  4311. }
  4312. break;
  4313. // -----------------------------------------------------------------------
  4314. case OID_SAVE_FORMAT:
  4315. if (SAVE_RFC822 != pVariant->ulVal && SAVE_RFC1521 != pVariant->ulVal)
  4316. {
  4317. hr = TrapError(MIME_E_INVALID_OPTION_VALUE);
  4318. goto exit;
  4319. }
  4320. if (m_rOptions.savetype != (MIMESAVETYPE)pVariant->ulVal)
  4321. {
  4322. FLAGSET(m_dwState, COSTATE_DIRTY);
  4323. m_rOptions.savetype = (MIMESAVETYPE)pVariant->ulVal;
  4324. }
  4325. break;
  4326. // -----------------------------------------------------------------------
  4327. default:
  4328. hr = TrapError(MIME_E_INVALID_OPTION_ID);
  4329. goto exit;
  4330. }
  4331. exit:
  4332. // Thread Safety
  4333. LeaveCriticalSection(&m_cs);
  4334. // Done
  4335. return hr;
  4336. }
  4337. // --------------------------------------------------------------------------------
  4338. // CMimePropertyContainer::GetOption
  4339. // --------------------------------------------------------------------------------
  4340. HRESULT CMimePropertyContainer::GetOption(const TYPEDID oid, LPPROPVARIANT pVariant)
  4341. {
  4342. // Locals
  4343. HRESULT hr=S_OK;
  4344. // check params
  4345. if (NULL == pVariant)
  4346. return TrapError(E_INVALIDARG);
  4347. pVariant->vt = TYPEDID_TYPE(oid);
  4348. // Thread Safety
  4349. EnterCriticalSection(&m_cs);
  4350. // Handle Optid
  4351. switch(oid)
  4352. {
  4353. // -----------------------------------------------------------------------
  4354. case OID_HEADER_RELOAD_TYPE:
  4355. pVariant->ulVal = m_rOptions.ReloadType;
  4356. break;
  4357. // -----------------------------------------------------------------------
  4358. case OID_NO_DEFAULT_CNTTYPE:
  4359. pVariant->boolVal = (VARIANT_BOOL) !!m_rOptions.fNoDefCntType;
  4360. break;
  4361. // -----------------------------------------------------------------------
  4362. case OID_ALLOW_8BIT_HEADER:
  4363. pVariant->boolVal = (VARIANT_BOOL) !!m_rOptions.fAllow8bit;
  4364. break;
  4365. // -----------------------------------------------------------------------
  4366. case OID_CBMAX_HEADER_LINE:
  4367. pVariant->ulVal = m_rOptions.cbMaxLine;
  4368. break;
  4369. // -----------------------------------------------------------------------
  4370. case OID_SAVE_FORMAT:
  4371. pVariant->ulVal = (ULONG)m_rOptions.savetype;
  4372. break;
  4373. // -----------------------------------------------------------------------
  4374. default:
  4375. pVariant->vt = VT_NULL;
  4376. hr = TrapError(MIME_E_INVALID_OPTION_ID);
  4377. goto exit;
  4378. }
  4379. exit:
  4380. // Thread Safety
  4381. LeaveCriticalSection(&m_cs);
  4382. // Done
  4383. return hr;
  4384. }
  4385. // --------------------------------------------------------------------------------
  4386. // CMimePropertyContainer::DwGetMessageFlags
  4387. // --------------------------------------------------------------------------------
  4388. DWORD CMimePropertyContainer::DwGetMessageFlags(BOOL fHideTnef)
  4389. {
  4390. // Locals
  4391. DWORD dwFlags=0;
  4392. // Thread Safety
  4393. EnterCriticalSection(&m_cs);
  4394. // Get pritype/subtype
  4395. LPCSTR pszPriType = PSZDEFPROPSTRINGA(m_prgIndex[PID_ATT_PRITYPE], STR_CNT_TEXT);
  4396. LPCSTR pszSubType = PSZDEFPROPSTRINGA(m_prgIndex[PID_ATT_SUBTYPE], STR_SUB_PLAIN);
  4397. LPCSTR pszCntDisp = PSZDEFPROPSTRINGA(m_prgIndex[PID_HDR_CNTDISP], STR_DIS_INLINE);
  4398. // Mime
  4399. if (m_prgIndex[PID_HDR_MIMEVER])
  4400. FLAGSET(dwFlags, IMF_MIME);
  4401. // VoiceMail
  4402. if (S_OK == IsPropSet(STR_HDR_XVOICEMAIL))
  4403. FLAGSET(dwFlags, IMF_VOICEMAIL);
  4404. // IMF_NEWS
  4405. if (m_prgIndex[PID_HDR_XNEWSRDR] || m_prgIndex[PID_HDR_NEWSGROUPS] || m_prgIndex[PID_HDR_NEWSGROUP] || m_prgIndex[PID_HDR_PATH])
  4406. FLAGSET(dwFlags, IMF_NEWS);
  4407. // text
  4408. if (lstrcmpi(pszPriType, STR_CNT_TEXT) == 0)
  4409. {
  4410. // There is text
  4411. FLAGSET(dwFlags, IMF_TEXT);
  4412. // text/plain
  4413. if (lstrcmpi(pszSubType, STR_SUB_PLAIN) == 0)
  4414. FLAGSET(dwFlags, IMF_PLAIN);
  4415. // text/html
  4416. else if (lstrcmpi(pszSubType, STR_SUB_HTML) == 0)
  4417. FLAGSET(dwFlags, IMF_HTML);
  4418. // text/enriched = text/html
  4419. else if (lstrcmpi(pszSubType, STR_SUB_ENRICHED) == 0)
  4420. FLAGSET(dwFlags, IMF_HTML);
  4421. // text/v-card
  4422. else if (lstrcmpi(pszSubType, STR_SUB_VCARD) == 0)
  4423. FLAGSET(dwFlags, IMF_HASVCARD);
  4424. }
  4425. // multipart
  4426. else if (lstrcmpi(pszPriType, STR_CNT_MULTIPART) == 0)
  4427. {
  4428. // Multipart
  4429. FLAGSET(dwFlags, IMF_MULTIPART);
  4430. // multipart/related
  4431. if (lstrcmpi(pszSubType, STR_SUB_RELATED) == 0)
  4432. FLAGSET(dwFlags, IMF_MHTML);
  4433. // multipart/signed
  4434. else if (0 == lstrcmpi(pszSubType, STR_SUB_SIGNED))
  4435. if (IsSMimeProtocol(this))
  4436. FLAGSET(dwFlags, IMF_SIGNED | IMF_SECURE);
  4437. }
  4438. // message/partial
  4439. else if (lstrcmpi(pszPriType, STR_CNT_MESSAGE) == 0 && lstrcmpi(pszSubType, STR_SUB_PARTIAL) == 0)
  4440. FLAGSET(dwFlags, IMF_PARTIAL);
  4441. // application
  4442. else if (lstrcmpi(pszPriType, STR_CNT_APPLICATION) == 0)
  4443. {
  4444. // application/ms-tnef
  4445. if (0 == lstrcmpi(pszSubType, STR_SUB_MSTNEF))
  4446. FLAGSET(dwFlags, IMF_TNEF);
  4447. // application/x-pkcs7-mime
  4448. else if (0 == lstrcmpi(pszSubType, STR_SUB_XPKCS7MIME) ||
  4449. 0 == lstrcmpi(pszSubType, STR_SUB_PKCS7MIME)) // nonstandard
  4450. FLAGSET(dwFlags, IMF_SECURE);
  4451. }
  4452. // Raid-37086 - Cset Tagged
  4453. if (ISFLAGSET(m_dwState, COSTATE_CSETTAGGED))
  4454. FLAGSET(dwFlags, IMF_CSETTAGGED);
  4455. // Attachment...
  4456. if (!ISFLAGSET(dwFlags, IMF_MULTIPART) && (FALSE == fHideTnef || !ISFLAGSET(dwFlags, IMF_TNEF)))
  4457. {
  4458. // Marked as an attachment ?
  4459. if (!ISFLAGSET(dwFlags, IMF_HASVCARD) &&
  4460. !ISFLAGSET(dwFlags, IMF_SECURE) &&
  4461. 0 != lstrcmpi(pszSubType, STR_SUB_PKCS7SIG) &&
  4462. 0 != lstrcmpi(pszSubType, STR_SUB_XPKCS7SIG)) // Raid-1960
  4463. {
  4464. // Not Rendered Yet
  4465. if (NULL == m_prgIndex[PID_ATT_RENDERED] || 0 == m_prgIndex[PID_ATT_RENDERED]->rValue.rVariant.ulVal)
  4466. {
  4467. // Marked as an Attachment
  4468. if (lstrcmpi(pszCntDisp, STR_DIS_ATTACHMENT) == 0)
  4469. FLAGSET(dwFlags, IMF_ATTACHMENTS);
  4470. // Is there a Content-Type: xxx; name=xxx
  4471. else if (NULL != m_prgIndex[PID_PAR_NAME])
  4472. FLAGSET(dwFlags, IMF_ATTACHMENTS);
  4473. // Is there a Content-Disposition: xxx; filename=xxx
  4474. else if (NULL != m_prgIndex[PID_PAR_FILENAME])
  4475. FLAGSET(dwFlags, IMF_ATTACHMENTS);
  4476. // Else if it is not marked as text
  4477. else if (ISFLAGSET(dwFlags, IMF_TEXT) == FALSE)
  4478. FLAGSET(dwFlags, IMF_ATTACHMENTS);
  4479. // If not text/plain and not text/html
  4480. else if (lstrcmpi(pszSubType, STR_SUB_PLAIN) != 0 && lstrcmpi(pszSubType, STR_SUB_HTML) != 0 && lstrcmpi(pszSubType, STR_SUB_ENRICHED) != 0)
  4481. FLAGSET(dwFlags, IMF_ATTACHMENTS);
  4482. }
  4483. }
  4484. }
  4485. // Thread Safety
  4486. LeaveCriticalSection(&m_cs);
  4487. // Done
  4488. return dwFlags;
  4489. }
  4490. // --------------------------------------------------------------------------------
  4491. // CMimePropertyContainer::GetEncodingType
  4492. // --------------------------------------------------------------------------------
  4493. ENCODINGTYPE CMimePropertyContainer::GetEncodingType(void)
  4494. {
  4495. // Locals
  4496. ENCODINGTYPE ietEncoding=IET_7BIT;
  4497. // Thread Safety
  4498. EnterCriticalSection(&m_cs);
  4499. // Get pritype/subtype
  4500. LPPROPERTY pCntXfer = m_prgIndex[PID_HDR_CNTXFER];
  4501. // Do we have data the I like ?
  4502. if (pCntXfer && ISSTRINGA(&pCntXfer->rValue))
  4503. {
  4504. // Local
  4505. CStringParser cString;
  4506. // cString...
  4507. cString.Init(pCntXfer->rValue.rStringA.pszVal, pCntXfer->rValue.rStringA.cchVal, PSF_NOTRAILWS | PSF_NOFRONTWS | PSF_NOCOMMENTS);
  4508. // Parse to end, remove white space and comments
  4509. SideAssert('\0' == cString.ChParse(""));
  4510. // Loop the table
  4511. for (ULONG i=0; i<ARRAYSIZE(g_rgEncoding); i++)
  4512. {
  4513. // Match Encoding Strings
  4514. if (lstrcmpi(g_rgEncoding[i].pszEncoding, cString.PszValue()) == 0)
  4515. {
  4516. ietEncoding = g_rgEncoding[i].ietEncoding;
  4517. break;
  4518. }
  4519. }
  4520. }
  4521. // Thread Safety
  4522. LeaveCriticalSection(&m_cs);
  4523. // Done
  4524. return ietEncoding;
  4525. }
  4526. // --------------------------------------------------------------------------------
  4527. // CMimePropertyContainer::_HrGetInlineSymbol
  4528. // --------------------------------------------------------------------------------
  4529. HRESULT CMimePropertyContainer::_HrGetInlineSymbol(LPCSTR pszData, LPPROPSYMBOL *ppSymbol, ULONG *pcboffColon)
  4530. {
  4531. // Locals
  4532. HRESULT hr=S_OK;
  4533. CHAR szHeader[255];
  4534. LPSTR pszHeader=NULL;
  4535. // Invalid Arg
  4536. Assert(pszData && ppSymbol);
  4537. // _HrParseInlineHeaderName
  4538. CHECKHR(hr = _HrParseInlineHeaderName(pszData, szHeader, sizeof(szHeader), &pszHeader, pcboffColon));
  4539. // Find Global Property
  4540. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pszHeader, TRUE, ppSymbol));
  4541. exit:
  4542. // Cleanup
  4543. if (pszHeader != szHeader)
  4544. SafeMemFree(pszHeader);
  4545. // Done
  4546. return hr;
  4547. }
  4548. // --------------------------------------------------------------------------------
  4549. // CMimePropertyContainer::_HrParseInlineHeaderName
  4550. // --------------------------------------------------------------------------------
  4551. HRESULT CMimePropertyContainer::_HrParseInlineHeaderName(LPCSTR pszData, LPSTR pszScratch, ULONG cchScratch,
  4552. LPSTR *ppszHeader, ULONG *pcboffColon)
  4553. {
  4554. // Locals
  4555. HRESULT hr=S_OK;
  4556. LPSTR psz=(LPSTR)pszData,
  4557. pszStart;
  4558. ULONG i=0;
  4559. // Invalid Arg
  4560. Assert(pszData && pszScratch && ppszHeader && pcboffColon);
  4561. // Lets Parse the name out and find the symbol
  4562. while (*psz && (' ' == *psz || '\t' == *psz))
  4563. {
  4564. i++;
  4565. psz++;
  4566. }
  4567. // Done
  4568. if ('\0' == *psz)
  4569. {
  4570. hr = TrapError(MIME_E_INVALID_HEADER_NAME);
  4571. goto exit;
  4572. }
  4573. // Seek to the colon
  4574. pszStart = psz;
  4575. while (*psz && ':' != *psz)
  4576. {
  4577. i++;
  4578. psz++;
  4579. }
  4580. // Set Colon Position
  4581. (*pcboffColon) = i;
  4582. // Done
  4583. if ('\0' == *psz || 0 == i)
  4584. {
  4585. hr = TrapError(MIME_E_INVALID_HEADER_NAME);
  4586. goto exit;
  4587. }
  4588. // Copy the name
  4589. if (i + 1 <= cchScratch)
  4590. *ppszHeader = pszScratch;
  4591. // Otherwise, allocate
  4592. else
  4593. {
  4594. // Allocate space for the name
  4595. *ppszHeader = PszAllocA(i + 1);
  4596. if (NULL == *ppszHeader)
  4597. {
  4598. hr = TrapError(E_OUTOFMEMORY);
  4599. goto exit;
  4600. }
  4601. }
  4602. // Copy the data
  4603. CopyMemory(*ppszHeader, pszStart, i);
  4604. // Null
  4605. *((*ppszHeader) + i) = '\0';
  4606. exit:
  4607. // Done
  4608. return hr;
  4609. }
  4610. // --------------------------------------------------------------------------------
  4611. // CMimePropertyContainer::FindFirstRow
  4612. // --------------------------------------------------------------------------------
  4613. STDMETHODIMP CMimePropertyContainer::FindFirstRow(LPFINDHEADER pFindHeader, LPHHEADERROW phRow)
  4614. {
  4615. // Invalid Arg
  4616. if (NULL == pFindHeader)
  4617. return TrapError(E_INVALIDARG);
  4618. // Init pFindHeader
  4619. pFindHeader->dwReserved = 0;
  4620. // FindNext
  4621. return FindNextRow(pFindHeader, phRow);
  4622. }
  4623. // --------------------------------------------------------------------------------
  4624. // CMimePropertyContainer::FindNextRow
  4625. // --------------------------------------------------------------------------------
  4626. STDMETHODIMP CMimePropertyContainer::FindNextRow(LPFINDHEADER pFindHeader, LPHHEADERROW phRow)
  4627. {
  4628. // Locals
  4629. HRESULT hr=S_OK;
  4630. LPPROPERTY pRow;
  4631. // InvalidArg
  4632. if (NULL == pFindHeader || NULL == phRow)
  4633. return TrapError(E_INVALIDARG);
  4634. // Init
  4635. *phRow = NULL;
  4636. // Thread Safety
  4637. EnterCriticalSection(&m_cs);
  4638. // Loop through the table
  4639. for (ULONG i=pFindHeader->dwReserved; i<m_rHdrTable.cRows; i++)
  4640. {
  4641. // Next Row
  4642. pRow = m_rHdrTable.prgpRow[i];
  4643. if (NULL == pRow)
  4644. continue;
  4645. // Is this the header
  4646. if (NULL == pFindHeader->pszHeader || lstrcmpi(pRow->pSymbol->pszName, pFindHeader->pszHeader) == 0)
  4647. {
  4648. // Save Index of next item to search
  4649. pFindHeader->dwReserved = i + 1;
  4650. // Return the handle
  4651. *phRow = pRow->hRow;
  4652. // Done
  4653. goto exit;
  4654. }
  4655. }
  4656. // Not Found
  4657. pFindHeader->dwReserved = m_rHdrTable.cRows;
  4658. hr = MIME_E_NOT_FOUND;
  4659. exit:
  4660. // Thread Safety
  4661. LeaveCriticalSection(&m_cs);
  4662. // Done
  4663. return hr;
  4664. }
  4665. // --------------------------------------------------------------------------------
  4666. // CMimePropertyContainer::CountRows
  4667. // --------------------------------------------------------------------------------
  4668. STDMETHODIMP CMimePropertyContainer::CountRows(LPCSTR pszHeader, ULONG *pcRows)
  4669. {
  4670. // Locals
  4671. LPPROPERTY pRow;
  4672. // InvalidArg
  4673. if (NULL == pcRows)
  4674. return TrapError(E_INVALIDARG);
  4675. // Init
  4676. *pcRows = 0;
  4677. // Thread Safety
  4678. EnterCriticalSection(&m_cs);
  4679. // Loop through the table
  4680. for (ULONG i=0; i<m_rHdrTable.cRows; i++)
  4681. {
  4682. // Next Row
  4683. pRow = m_rHdrTable.prgpRow[i];
  4684. if (NULL == pRow)
  4685. continue;
  4686. // Is this the header
  4687. if (NULL == pszHeader || lstrcmpi(pRow->pSymbol->pszName, pszHeader) == 0)
  4688. (*pcRows)++;
  4689. }
  4690. // Thread Safety
  4691. LeaveCriticalSection(&m_cs);
  4692. // Done
  4693. return S_OK;
  4694. }
  4695. // --------------------------------------------------------------------------------
  4696. // CMimePropertyContainer::AppendRow
  4697. // --------------------------------------------------------------------------------
  4698. STDMETHODIMP CMimePropertyContainer::AppendRow(LPCSTR pszHeader, DWORD dwFlags, LPCSTR pszData, ULONG cchData,
  4699. LPHHEADERROW phRow)
  4700. {
  4701. // Locals
  4702. HRESULT hr=S_OK;
  4703. LPPROPSYMBOL pSymbol=NULL;
  4704. ULONG cboffColon;
  4705. LPPROPERTY pProperty;
  4706. // InvalidArg
  4707. if (NULL == pszData || '\0' != pszData[cchData])
  4708. return TrapError(E_INVALIDARG);
  4709. // Init
  4710. if (phRow)
  4711. *phRow = NULL;
  4712. // Thread Safety
  4713. EnterCriticalSection(&m_cs);
  4714. // If we have a header, lookup the symbol
  4715. if (pszHeader)
  4716. {
  4717. // HTF_NAMEINDATA better not be set
  4718. Assert(!ISFLAGSET(dwFlags, HTF_NAMEINDATA));
  4719. // Lookup the symbol
  4720. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pszHeader, TRUE, &pSymbol));
  4721. // Create a row
  4722. CHECKHR(hr = _HrAppendProperty(pSymbol, &pProperty));
  4723. // Set the Data on this row
  4724. CHECKHR(hr = SetRowData(pProperty->hRow, dwFlags, pszData, cchData));
  4725. }
  4726. // Otherwise...
  4727. else if (ISFLAGSET(dwFlags, HTF_NAMEINDATA))
  4728. {
  4729. // GetInlineSymbol
  4730. CHECKHR(hr = _HrGetInlineSymbol(pszData, &pSymbol, &cboffColon));
  4731. // Create a row
  4732. CHECKHR(hr = _HrAppendProperty(pSymbol, &pProperty));
  4733. // Remove IHF_NAMELINE
  4734. FLAGCLEAR(dwFlags, HTF_NAMEINDATA);
  4735. // Set the Data on this row
  4736. Assert(cboffColon + 1 < cchData);
  4737. CHECKHR(hr = SetRowData(pProperty->hRow, dwFlags, pszData + cboffColon + 1, cchData - cboffColon - 1));
  4738. }
  4739. // Otherwise, failed
  4740. else
  4741. {
  4742. hr = TrapError(E_INVALIDARG);
  4743. goto exit;
  4744. }
  4745. // Return phRow
  4746. if (phRow && pProperty)
  4747. *phRow = pProperty->hRow;
  4748. exit:
  4749. // Thread Safety
  4750. LeaveCriticalSection(&m_cs);
  4751. // Done
  4752. return hr;
  4753. }
  4754. // --------------------------------------------------------------------------------
  4755. // CMimePropertyContainer::DeleteRow
  4756. // --------------------------------------------------------------------------------
  4757. STDMETHODIMP CMimePropertyContainer::DeleteRow(HHEADERROW hRow)
  4758. {
  4759. // Locals
  4760. HRESULT hr=S_OK;
  4761. LPPROPERTY pRow;
  4762. // Thread Safety
  4763. EnterCriticalSection(&m_cs);
  4764. // Validate the Handle
  4765. CHECKEXP(_FIsValidHRow(hRow) == FALSE, MIME_E_INVALID_HANDLE);
  4766. // Get the row
  4767. pRow = PRowFromHRow(hRow);
  4768. // Standard Delete Prop
  4769. CHECKHR(hr = DeleteProp(pRow->pSymbol));
  4770. exit:
  4771. // Thread Safety
  4772. LeaveCriticalSection(&m_cs);
  4773. // Done
  4774. return hr;
  4775. }
  4776. // --------------------------------------------------------------------------------
  4777. // CMimePropertyContainer::GetRowData
  4778. // --------------------------------------------------------------------------------
  4779. STDMETHODIMP CMimePropertyContainer::GetRowData(HHEADERROW hRow, DWORD dwFlags, LPSTR *ppszData, ULONG *pcchData)
  4780. {
  4781. // Locals
  4782. HRESULT hr=S_OK;
  4783. ULONG cchData=0;
  4784. LPPROPERTY pRow;
  4785. MIMEVARIANT rValue;
  4786. DWORD dwPropFlags;
  4787. // Init
  4788. if (ppszData)
  4789. *ppszData = NULL;
  4790. if (pcchData)
  4791. *pcchData = 0;
  4792. // Thread Safety
  4793. EnterCriticalSection(&m_cs);
  4794. // Validate the Handle
  4795. CHECKEXP(_FIsValidHRow(hRow) == FALSE, MIME_E_INVALID_HANDLE);
  4796. // Get the row
  4797. pRow = PRowFromHRow(hRow);
  4798. // Compute dwPropFlags
  4799. dwPropFlags = PDF_HEADERFORMAT | ((dwFlags & HTF_NAMEINDATA) ? PDF_NAMEINDATA : 0);
  4800. // Speicify data type
  4801. rValue.type = MVT_STRINGA;
  4802. // Ask the value for the data
  4803. CHECKHR(hr = _HrGetPropertyValue(pRow, dwPropFlags, &rValue));
  4804. // Want Length
  4805. cchData = rValue.rStringA.cchVal;
  4806. // Want the data
  4807. if (ppszData)
  4808. {
  4809. *ppszData = rValue.rStringA.pszVal;
  4810. rValue.rStringA.pszVal = NULL;
  4811. }
  4812. // Else Free It
  4813. else
  4814. SafeMemFree(rValue.rStringA.pszVal);
  4815. // Verify the NULL
  4816. Assert(ppszData ? '\0' == *((*ppszData) + cchData) : TRUE);
  4817. // Return Length ?
  4818. if (pcchData)
  4819. *pcchData = cchData;
  4820. exit:
  4821. // Thread Safety
  4822. LeaveCriticalSection(&m_cs);
  4823. // Done
  4824. return hr;
  4825. }
  4826. // --------------------------------------------------------------------------------
  4827. // CMimePropertyContainer::SetRowData
  4828. // --------------------------------------------------------------------------------
  4829. STDMETHODIMP CMimePropertyContainer::SetRowData(HHEADERROW hRow, DWORD dwFlags, LPCSTR pszData, ULONG cchData)
  4830. {
  4831. // Locals
  4832. HRESULT hr=S_OK;
  4833. LPPROPERTY pRow;
  4834. MIMEVARIANT rValue;
  4835. ULONG cboffColon;
  4836. LPPROPSYMBOL pSymbol;
  4837. LPSTR psz=(LPSTR)pszData;
  4838. // InvalidArg
  4839. if (NULL == pszData || '\0' != pszData[cchData])
  4840. return TrapError(E_INVALIDARG);
  4841. // Thread Safety
  4842. EnterCriticalSection(&m_cs);
  4843. // Validate the Handle
  4844. CHECKEXP(_FIsValidHRow(hRow) == FALSE, MIME_E_INVALID_HANDLE);
  4845. // Get the row
  4846. pRow = PRowFromHRow(hRow);
  4847. // If HTF_NAMEINDATA
  4848. if (ISFLAGSET(dwFlags, HTF_NAMEINDATA))
  4849. {
  4850. // Extract the name
  4851. CHECKHR(hr = _HrGetInlineSymbol(pszData, &pSymbol, &cboffColon));
  4852. // Symbol Must be the same
  4853. if (pRow->pSymbol != pSymbol)
  4854. {
  4855. hr = TrapError(E_FAIL);
  4856. goto exit;
  4857. }
  4858. // Adjust pszData
  4859. Assert(cboffColon < cchData);
  4860. psz = (LPSTR)(pszData + cboffColon + 1);
  4861. cchData = cchData - cboffColon - 1;
  4862. Assert(psz[cchData] == '\0');
  4863. }
  4864. // Setup the variant
  4865. rValue.type = MVT_STRINGA;
  4866. rValue.rStringA.pszVal = psz;
  4867. rValue.rStringA.cchVal = cchData;
  4868. // Tell value about the new row data
  4869. CHECKHR(hr = _HrSetPropertyValue(pRow, 0, &rValue, FALSE));
  4870. // Clear Position Information
  4871. pRow->cboffStart = 0;
  4872. pRow->cboffColon = 0;
  4873. pRow->cboffEnd = 0;
  4874. exit:
  4875. // Thread Safety
  4876. LeaveCriticalSection(&m_cs);
  4877. // Done
  4878. return hr;
  4879. }
  4880. // --------------------------------------------------------------------------------
  4881. // CMimePropertyContainer::GetRowInfo
  4882. // --------------------------------------------------------------------------------
  4883. STDMETHODIMP CMimePropertyContainer::GetRowInfo(HHEADERROW hRow, LPHEADERROWINFO pInfo)
  4884. {
  4885. // Locals
  4886. HRESULT hr=S_OK;
  4887. LPPROPERTY pRow;
  4888. // InvalidArg
  4889. if (NULL == pInfo)
  4890. return TrapError(E_INVALIDARG);
  4891. // Thread Safety
  4892. EnterCriticalSection(&m_cs);
  4893. // Validate the Handle
  4894. CHECKEXP(_FIsValidHRow(hRow) == FALSE, MIME_E_INVALID_HANDLE);
  4895. // Get the row
  4896. pRow = PRowFromHRow(hRow);
  4897. // Copy the row info
  4898. pInfo->dwRowNumber = pRow->dwRowNumber;
  4899. pInfo->cboffStart = pRow->cboffStart;
  4900. pInfo->cboffColon = pRow->cboffColon;
  4901. pInfo->cboffEnd = pRow->cboffEnd;
  4902. exit:
  4903. // Thread Safety
  4904. LeaveCriticalSection(&m_cs);
  4905. // Done
  4906. return hr;
  4907. }
  4908. // --------------------------------------------------------------------------------
  4909. // CMimePropertyContainer::SetRowNumber
  4910. // --------------------------------------------------------------------------------
  4911. STDMETHODIMP CMimePropertyContainer::SetRowNumber(HHEADERROW hRow, DWORD dwRowNumber)
  4912. {
  4913. // Locals
  4914. HRESULT hr=S_OK;
  4915. LPPROPERTY pRow;
  4916. // Thread Safety
  4917. EnterCriticalSection(&m_cs);
  4918. // Validate the Handle
  4919. CHECKEXP(_FIsValidHRow(hRow) == FALSE, MIME_E_INVALID_HANDLE);
  4920. // Get the row
  4921. pRow = PRowFromHRow(hRow);
  4922. // Copy the row info
  4923. pRow->dwRowNumber = dwRowNumber;
  4924. exit:
  4925. // Thread Safety
  4926. LeaveCriticalSection(&m_cs);
  4927. // Done
  4928. return hr;
  4929. }
  4930. // --------------------------------------------------------------------------------
  4931. // CMimePropertyContainer::EnumRows
  4932. // --------------------------------------------------------------------------------
  4933. STDMETHODIMP CMimePropertyContainer::EnumRows(LPCSTR pszHeader, DWORD dwFlags, IMimeEnumHeaderRows **ppEnum)
  4934. {
  4935. // Locals
  4936. HRESULT hr=S_OK;
  4937. ULONG i,
  4938. iEnum=0,
  4939. cEnumCount;
  4940. LPENUMHEADERROW pEnumRow=NULL;
  4941. LPPROPERTY pRow;
  4942. CMimeEnumHeaderRows *pEnum=NULL;
  4943. LPROWINDEX prgIndex=NULL;
  4944. ULONG cRows;
  4945. // check params
  4946. if (NULL == ppEnum)
  4947. return TrapError(E_INVALIDARG);
  4948. // Init
  4949. *ppEnum = NULL;
  4950. // Thread Safety
  4951. EnterCriticalSection(&m_cs);
  4952. // This builds an inverted index on the header rows sorted by postion weight
  4953. CHECKHR(hr = _HrGetHeaderTableSaveIndex(&cRows, &prgIndex));
  4954. // Lets Count the Rows
  4955. CHECKHR(hr = CountRows(pszHeader, &cEnumCount));
  4956. // Allocate pEnumRow
  4957. CHECKALLOC(pEnumRow = (LPENUMHEADERROW)g_pMalloc->Alloc(cEnumCount * sizeof(ENUMHEADERROW)));
  4958. // ZeroInit
  4959. ZeroMemory(pEnumRow, cEnumCount * sizeof(ENUMHEADERROW));
  4960. // Loop through the rows
  4961. for (i=0; i<cRows; i++)
  4962. {
  4963. // Get the row
  4964. Assert(_FIsValidHRow(prgIndex[i].hRow));
  4965. pRow = PRowFromHRow(prgIndex[i].hRow);
  4966. // Is this a header the client wants
  4967. if (NULL == pszHeader || lstrcmpi(pszHeader, pRow->pSymbol->pszName) == 0)
  4968. {
  4969. // Valide
  4970. Assert(iEnum < cEnumCount);
  4971. // Set the symbol on this enum row
  4972. pEnumRow[iEnum].dwReserved = (DWORD_PTR)pRow->pSymbol;
  4973. // Lets always give the handle
  4974. pEnumRow[iEnum].hRow = pRow->hRow;
  4975. // If Enumerating only handles...
  4976. if (!ISFLAGSET(dwFlags, HTF_ENUMHANDLESONLY))
  4977. {
  4978. // Get the data for this enum row
  4979. CHECKHR(hr = GetRowData(pRow->hRow, dwFlags, &pEnumRow[iEnum].pszData, &pEnumRow[iEnum].cchData));
  4980. }
  4981. // Increment iEnum
  4982. iEnum++;
  4983. }
  4984. }
  4985. // Allocate
  4986. CHECKALLOC(pEnum = new CMimeEnumHeaderRows);
  4987. // Initialize
  4988. CHECKHR(hr = pEnum->HrInit(0, dwFlags, cEnumCount, pEnumRow, FALSE));
  4989. // Don't Free pEnumRow
  4990. pEnumRow = NULL;
  4991. // Return it
  4992. (*ppEnum) = (IMimeEnumHeaderRows *)pEnum;
  4993. (*ppEnum)->AddRef();
  4994. exit:
  4995. // Cleanup
  4996. SafeRelease(pEnum);
  4997. SafeMemFree(prgIndex);
  4998. if (pEnumRow)
  4999. g_pMoleAlloc->FreeEnumHeaderRowArray(cEnumCount, pEnumRow, TRUE);
  5000. // Thread Safety
  5001. LeaveCriticalSection(&m_cs);
  5002. // Done
  5003. return hr;
  5004. }
  5005. // --------------------------------------------------------------------------------
  5006. // CMimePropertyContainer::Clone
  5007. // --------------------------------------------------------------------------------
  5008. STDMETHODIMP CMimePropertyContainer::Clone(IMimeHeaderTable **ppTable)
  5009. {
  5010. // Locals
  5011. HRESULT hr=S_OK;
  5012. LPCONTAINER pContainer=NULL;
  5013. // InvalidArg
  5014. if (NULL == ppTable)
  5015. return TrapError(E_INVALIDARG);
  5016. // Init
  5017. *ppTable = NULL;
  5018. // Thread Safety
  5019. EnterCriticalSection(&m_cs);
  5020. // Ask the container to clone itself
  5021. CHECKHR(hr = Clone(&pContainer));
  5022. // Bind to the IID_IMimeHeaderTable View
  5023. CHECKHR(hr = pContainer->QueryInterface(IID_IMimeHeaderTable, (LPVOID *)ppTable));
  5024. exit:
  5025. // Cleanup
  5026. SafeRelease(pContainer);
  5027. // Thread Safety
  5028. LeaveCriticalSection(&m_cs);
  5029. // Done
  5030. return hr;
  5031. }
  5032. // --------------------------------------------------------------------------------
  5033. // CMimePropertyContainer::_HrSaveAddressGroup
  5034. // --------------------------------------------------------------------------------
  5035. HRESULT CMimePropertyContainer::_HrSaveAddressGroup(LPPROPERTY pProperty, IStream *pStream,
  5036. ULONG *pcAddrsWrote, ADDRESSFORMAT format, VARTYPE vtFormat)
  5037. {
  5038. // Locals
  5039. HRESULT hr=S_OK;
  5040. LPMIMEADDRESS pAddress;
  5041. // Invalid Arg
  5042. Assert(pProperty && pProperty->pGroup && pStream && pcAddrsWrote);
  5043. Assert(!ISFLAGSET(pProperty->dwState, PRSTATE_NEEDPARSE));
  5044. // Loop Infos...
  5045. for (pAddress=pProperty->pGroup->pHead; pAddress!=NULL; pAddress=pAddress->pNext)
  5046. {
  5047. // Multibyte
  5048. if (VT_LPSTR == vtFormat)
  5049. {
  5050. // Tell the Address Info object to write its display information
  5051. CHECKHR(hr = _HrSaveAddressA(pProperty, pAddress, pStream, pcAddrsWrote, format));
  5052. }
  5053. // Otherwise
  5054. else
  5055. {
  5056. // Validate
  5057. Assert(VT_LPWSTR == vtFormat);
  5058. // Tell the Address Info object to write its display information
  5059. CHECKHR(hr = _HrSaveAddressW(pProperty, pAddress, pStream, pcAddrsWrote, format));
  5060. }
  5061. // Increment cAddresses Count
  5062. (*pcAddrsWrote)++;
  5063. }
  5064. exit:
  5065. // Done
  5066. return hr;
  5067. }
  5068. ///////////////////////////////////////////////////////////////////////////////
  5069. // bIsInLineEncodedA
  5070. //
  5071. // [PaulHi] 6/29/99
  5072. // Helper function to determine if single byte string contains RFC1522 inline
  5073. // encoding.
  5074. // Format is: "=?[charset]?[encoding]?[data]?=".
  5075. ///////////////////////////////////////////////////////////////////////////////
  5076. BOOL bIsInLineEncodedA(LPCSTR pcszName)
  5077. {
  5078. Assert(pcszName);
  5079. int nState = 0; // 0-Begin,charset; 1-encoding; 2-data; 3-Ending
  5080. while(*pcszName)
  5081. {
  5082. // Check for beginning delimiter.
  5083. if ( (*pcszName == '=') && (*(pcszName+1) == '?') )
  5084. {
  5085. // Set/reset state
  5086. nState = 1;
  5087. pcszName += 1; // Skip past.
  5088. }
  5089. else
  5090. {
  5091. switch (nState)
  5092. {
  5093. case 1:
  5094. case 2:
  5095. // Find encoding, data bodies.
  5096. if (*pcszName == '?')
  5097. {
  5098. ++nState;
  5099. ++pcszName; // Skip past body
  5100. }
  5101. break;
  5102. case 3:
  5103. // Find ending delimiter.
  5104. if ( (*pcszName == '?') && (*(pcszName+1) == '=') )
  5105. return TRUE;
  5106. break;
  5107. }
  5108. }
  5109. if (*pcszName != '\0')
  5110. {
  5111. if (IsDBCSLeadByte(*pcszName))
  5112. ++pcszName;
  5113. ++pcszName;
  5114. }
  5115. }
  5116. return FALSE;
  5117. }
  5118. // ----------------------------------------------------------------------------
  5119. // CMimePropertyContainer::_HrSaveAddressA
  5120. // ----------------------------------------------------------------------------
  5121. HRESULT CMimePropertyContainer::_HrSaveAddressA(LPPROPERTY pProperty, LPMIMEADDRESS pAddress,
  5122. IStream *pStream, ULONG *pcAddrsWrote, ADDRESSFORMAT format)
  5123. {
  5124. // Locals
  5125. HRESULT hr=S_OK;
  5126. LPWSTR pszNameW=NULL;
  5127. LPSTR pszNameA=NULL;
  5128. LPSTR pszEmailA=NULL;
  5129. BOOL fWriteEmail=FALSE;
  5130. LPWSTR pszEscape=NULL;
  5131. BOOL fRFC822=FALSE;
  5132. BOOL fRFC1522=FALSE;
  5133. DWORD dwFlags;
  5134. MIMEVARIANT rSource;
  5135. MIMEVARIANT rDest;
  5136. // Invalid Arg
  5137. Assert(pProperty && pAddress && pStream && pcAddrsWrote);
  5138. // Init Dest
  5139. ZeroMemory(&rDest, sizeof(MIMEVARIANT));
  5140. // Deleted or Empty continue
  5141. if (FIsEmptyW(pAddress->rFriendly.psz) && FIsEmptyW(pAddress->rEmail.psz))
  5142. {
  5143. Assert(FALSE);
  5144. goto exit;
  5145. }
  5146. // RFC822 Format
  5147. if (AFT_RFC822_TRANSMIT == format || AFT_RFC822_ENCODED == format || AFT_RFC822_DECODED == format)
  5148. fRFC822 = TRUE;
  5149. // Decide Delimiter
  5150. if (*pcAddrsWrote > 0)
  5151. {
  5152. // AFT_RFC822_TRANSMIT
  5153. if (AFT_RFC822_TRANSMIT == format)
  5154. {
  5155. // ',\r\n\t'
  5156. CHECKHR (hr = pStream->Write(c_szAddressFold, lstrlen(c_szAddressFold), NULL));
  5157. }
  5158. // AFT_RFC822_DECODED, AFT_RFC822_ENCODED
  5159. else if (AFT_RFC822_DECODED == format || AFT_RFC822_ENCODED == format)
  5160. {
  5161. // ', '
  5162. CHECKHR(hr = pStream->Write(c_szCommaSpace, lstrlen(c_szCommaSpace), NULL));
  5163. }
  5164. // AFT_DISPLAY_FRIENDLY, AFT_DISPLAY_EMAIL, AFT_DISPLAY_BOTH
  5165. else
  5166. {
  5167. // '; '
  5168. CHECKHR(hr = pStream->Write(c_szSemiColonSpace, lstrlen(c_szSemiColonSpace), NULL));
  5169. }
  5170. }
  5171. // Only format that excludes writing the email name
  5172. if (AFT_DISPLAY_FRIENDLY != format && FIsEmptyW(pAddress->rEmail.psz) == FALSE)
  5173. fWriteEmail = TRUE;
  5174. // Only format that excludes writing the display name
  5175. if (AFT_DISPLAY_EMAIL != format && FIsEmptyW(pAddress->rFriendly.psz) == FALSE)
  5176. {
  5177. // Should we write the name
  5178. if ((AFT_RFC822_TRANSMIT == format || AFT_DISPLAY_BOTH == format) && fWriteEmail && StrStrW(pAddress->rFriendly.psz, pAddress->rEmail.psz))
  5179. pszNameA = NULL;
  5180. else
  5181. {
  5182. // Setup Types
  5183. rDest.type = MVT_STRINGA;
  5184. rSource.type = MVT_STRINGW;
  5185. // Init pszName
  5186. pszNameW = pAddress->rFriendly.psz;
  5187. // Escape It
  5188. if (fRFC822 && MimeOleEscapeStringW(pszNameW, &pszEscape) == S_OK)
  5189. {
  5190. // Escaped
  5191. pszNameW = pszEscape;
  5192. rSource.rStringW.pszVal = pszNameW;
  5193. rSource.rStringW.cchVal = lstrlenW(pszNameW);
  5194. }
  5195. // Otherwise
  5196. else
  5197. {
  5198. rSource.rStringW.pszVal = pAddress->rFriendly.psz;
  5199. rSource.rStringW.cchVal = pAddress->rFriendly.cch;
  5200. }
  5201. // Encoded
  5202. if (AFT_RFC822_ENCODED == format || AFT_RFC822_TRANSMIT == format)
  5203. dwFlags = CVF_NOALLOC | PDF_ENCODED;
  5204. else
  5205. dwFlags = CVF_NOALLOC;
  5206. // Convert to ansi
  5207. if (SUCCEEDED(HrConvertVariant(pProperty->pSymbol, pAddress->pCharset, IET_DECODED, dwFlags, 0, &rSource, &rDest, &fRFC1522)))
  5208. {
  5209. // Set pszNameA
  5210. pszNameA = rDest.rStringA.pszVal;
  5211. }
  5212. }
  5213. }
  5214. // Write Display Name ?
  5215. if (NULL != pszNameA)
  5216. {
  5217. // [PaulHi] 6/29/99 Raid 81539
  5218. // Double quote all display names unless they are in-line encoded.
  5219. BOOL fInLineEncoded = bIsInLineEncodedA(pszNameA);
  5220. // if (fRFC822 && !fRFC1522)
  5221. // Write Quote
  5222. if ((AFT_DISPLAY_FRIENDLY != format) && !fInLineEncoded)
  5223. {
  5224. // Write It
  5225. CHECKHR(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
  5226. }
  5227. // Write display name
  5228. CHECKHR(hr = pStream->Write(pszNameA, lstrlen(pszNameA), NULL));
  5229. // Write Quote
  5230. if ((AFT_DISPLAY_FRIENDLY != format) && !fInLineEncoded)
  5231. {
  5232. // Write It
  5233. CHECKHR (hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
  5234. }
  5235. }
  5236. // Write Email
  5237. if (TRUE == fWriteEmail)
  5238. {
  5239. // Set Start
  5240. LPCSTR pszStart = pszNameA ? c_szEmailSpaceStart : c_szEmailStart;
  5241. // Begin Email '>'
  5242. CHECKHR(hr = pStream->Write(pszStart, lstrlen(pszStart), NULL));
  5243. // Convert to ansi
  5244. CHECKALLOC(pszEmailA = PszToANSI(CP_ACP, pAddress->rEmail.psz));
  5245. // Write email
  5246. CHECKHR(hr = pStream->Write(pszEmailA, lstrlen(pszEmailA), NULL));
  5247. // End Email '>'
  5248. CHECKHR(hr = pStream->Write(c_szEmailEnd, lstrlen(c_szEmailEnd), NULL));
  5249. }
  5250. exit:
  5251. // Cleanup
  5252. SafeMemFree(pszEscape);
  5253. SafeMemFree(pszEmailA);
  5254. MimeVariantFree(&rDest);
  5255. // Done
  5256. return hr;
  5257. }
  5258. ///////////////////////////////////////////////////////////////////////////////
  5259. // bIsInLineEncodedW
  5260. //
  5261. // [PaulHi] 6/29/99
  5262. // Helper function to determine if double byte string contains RFC1522 inline
  5263. // encoding.
  5264. // Format is: "=?[charset]?[encoding]?[data]?=".
  5265. ///////////////////////////////////////////////////////////////////////////////
  5266. BOOL bIsInLineEncodedW(LPCWSTR pcwszName)
  5267. {
  5268. Assert(pcwszName);
  5269. int nState = 0; // 0-Begin,charset; 1-encoding; 2-data; 3-Ending
  5270. while(*pcwszName)
  5271. {
  5272. if ( (*pcwszName == L'=') && (*(pcwszName+1) == L'?') )
  5273. {
  5274. // Set/reset state.
  5275. nState = 1;
  5276. ++pcwszName; // Skip past
  5277. }
  5278. else
  5279. {
  5280. switch (nState)
  5281. {
  5282. case 1:
  5283. case 2:
  5284. // Find encoding, data bodies.
  5285. if (*pcwszName == L'?')
  5286. {
  5287. ++nState;
  5288. ++pcwszName; // Skip past body
  5289. }
  5290. break;
  5291. case 3:
  5292. // Find ending delimiter.
  5293. if ( (*pcwszName == L'?') && (*(pcwszName+1) == L'=') )
  5294. return TRUE;
  5295. break;
  5296. }
  5297. }
  5298. if (*pcwszName != 0)
  5299. ++pcwszName;
  5300. }
  5301. return FALSE;
  5302. }
  5303. // ----------------------------------------------------------------------------
  5304. // CMimePropertyContainer::_HrSaveAddressW
  5305. // ----------------------------------------------------------------------------
  5306. HRESULT CMimePropertyContainer::_HrSaveAddressW(LPPROPERTY pProperty, LPMIMEADDRESS pAddress,
  5307. IStream *pStream, ULONG *pcAddrsWrote, ADDRESSFORMAT format)
  5308. {
  5309. // Locals
  5310. HRESULT hr=S_OK;
  5311. LPWSTR pszNameW=NULL;
  5312. BOOL fWriteEmail=FALSE;
  5313. LPWSTR pszEscape=NULL;
  5314. BOOL fRFC822=FALSE;
  5315. BOOL fRFC1522=FALSE;
  5316. MIMEVARIANT rSource;
  5317. MIMEVARIANT rDest;
  5318. // Invalid Arg
  5319. Assert(pProperty && pAddress && pStream && pcAddrsWrote);
  5320. // Init Dest
  5321. ZeroMemory(&rDest, sizeof(MIMEVARIANT));
  5322. // Deleted or Empty continue
  5323. if (FIsEmptyW(pAddress->rFriendly.psz) && FIsEmptyW(pAddress->rEmail.psz))
  5324. {
  5325. Assert(FALSE);
  5326. goto exit;
  5327. }
  5328. // RFC822 Format
  5329. if (AFT_RFC822_TRANSMIT == format || AFT_RFC822_ENCODED == format || AFT_RFC822_DECODED == format)
  5330. fRFC822 = TRUE;
  5331. // Decide Delimiter
  5332. if (*pcAddrsWrote > 0)
  5333. {
  5334. // AFT_RFC822_TRANSMIT
  5335. if (AFT_RFC822_TRANSMIT == format)
  5336. {
  5337. // ',\r\n\t'
  5338. CHECKHR (hr = pStream->Write(c_wszAddressFold, lstrlenW(c_wszAddressFold) * sizeof(WCHAR), NULL));
  5339. }
  5340. // AFT_RFC822_DECODED, AFT_RFC822_ENCODED
  5341. else if (AFT_RFC822_DECODED == format || AFT_RFC822_ENCODED == format)
  5342. {
  5343. // ', '
  5344. CHECKHR(hr = pStream->Write(c_wszCommaSpace, lstrlenW(c_wszCommaSpace) * sizeof(WCHAR), NULL));
  5345. }
  5346. // AFT_DISPLAY_FRIENDLY, AFT_DISPLAY_EMAIL, AFT_DISPLAY_BOTH
  5347. else
  5348. {
  5349. // '; '
  5350. CHECKHR(hr = pStream->Write(c_wszSemiColonSpace, lstrlenW(c_wszSemiColonSpace) * sizeof(WCHAR), NULL));
  5351. }
  5352. }
  5353. // Only format that excludes writing the email name
  5354. if (AFT_DISPLAY_FRIENDLY != format && FIsEmptyW(pAddress->rEmail.psz) == FALSE)
  5355. fWriteEmail = TRUE;
  5356. // Only format that excludes writing the display name
  5357. if (AFT_DISPLAY_EMAIL != format && FIsEmptyW(pAddress->rFriendly.psz) == FALSE)
  5358. {
  5359. // Should we write the name
  5360. if ((AFT_RFC822_TRANSMIT == format || AFT_DISPLAY_BOTH == format) && fWriteEmail && StrStrW(pAddress->rFriendly.psz, pAddress->rEmail.psz))
  5361. pszNameW = NULL;
  5362. else
  5363. {
  5364. // Setup Types
  5365. rDest.type = MVT_STRINGW;
  5366. rSource.type = MVT_STRINGW;
  5367. // Init pszName
  5368. pszNameW = pAddress->rFriendly.psz;
  5369. // Escape It
  5370. if (fRFC822 && MimeOleEscapeStringW(pszNameW, &pszEscape) == S_OK)
  5371. {
  5372. // Escaped
  5373. pszNameW = pszEscape;
  5374. rSource.rStringW.pszVal = pszNameW;
  5375. rSource.rStringW.cchVal = lstrlenW(pszNameW);
  5376. }
  5377. // Otherwise
  5378. else
  5379. {
  5380. rSource.rStringW.pszVal = pAddress->rFriendly.psz;
  5381. rSource.rStringW.cchVal = pAddress->rFriendly.cch;
  5382. }
  5383. // Encoded
  5384. if (AFT_RFC822_ENCODED == format || AFT_RFC822_TRANSMIT == format)
  5385. {
  5386. // Convert to ansi
  5387. if (SUCCEEDED(HrConvertVariant(pProperty->pSymbol, pAddress->pCharset, IET_DECODED, CVF_NOALLOC | PDF_ENCODED, 0, &rSource, &rDest, &fRFC1522)))
  5388. {
  5389. // Set pszNameA
  5390. pszNameW = rDest.rStringW.pszVal;
  5391. }
  5392. }
  5393. }
  5394. }
  5395. // Write Display Name ?
  5396. if (NULL != pszNameW)
  5397. {
  5398. // [PaulHi] 6/29/99 Raid 81539
  5399. // Double quote all display names unless they are in-line encoded.
  5400. BOOL fInLineEncoded = bIsInLineEncodedW(pszNameW);
  5401. // if (fRFC822 && !fRFC1522)
  5402. // Write Quote
  5403. if ((AFT_DISPLAY_FRIENDLY != format) && !fInLineEncoded)
  5404. {
  5405. // Write It
  5406. CHECKHR(hr = pStream->Write(c_wszDoubleQuote, lstrlenW(c_wszDoubleQuote) * sizeof(WCHAR), NULL));
  5407. }
  5408. // Write display name
  5409. CHECKHR(hr = pStream->Write(pszNameW, lstrlenW(pszNameW) * sizeof(WCHAR), NULL));
  5410. // Write Quote
  5411. if ((AFT_DISPLAY_FRIENDLY != format) && !fInLineEncoded)
  5412. {
  5413. // Write It
  5414. CHECKHR (hr = pStream->Write(c_wszDoubleQuote, lstrlenW(c_wszDoubleQuote) * sizeof(WCHAR), NULL));
  5415. }
  5416. }
  5417. // Write Email
  5418. if (TRUE == fWriteEmail)
  5419. {
  5420. // Set Start
  5421. LPCWSTR pszStart = pszNameW ? c_wszEmailSpaceStart : c_wszEmailStart;
  5422. // Begin Email '>'
  5423. CHECKHR(hr = pStream->Write(pszStart, lstrlenW(pszStart) * sizeof(WCHAR), NULL));
  5424. // Write email
  5425. CHECKHR(hr = pStream->Write(pAddress->rEmail.psz, pAddress->rEmail.cch * sizeof(WCHAR), NULL));
  5426. // End Email '>'
  5427. CHECKHR(hr = pStream->Write(c_wszEmailEnd, lstrlenW(c_wszEmailEnd) * sizeof(WCHAR), NULL));
  5428. }
  5429. exit:
  5430. // Cleanup
  5431. SafeMemFree(pszEscape);
  5432. MimeVariantFree(&rDest);
  5433. // Done
  5434. return hr;
  5435. }
  5436. // --------------------------------------------------------------------------------
  5437. // CMimePropertyContainer::_HrQueryAddressGroup
  5438. // --------------------------------------------------------------------------------
  5439. HRESULT CMimePropertyContainer::_HrQueryAddressGroup(LPPROPERTY pProperty, LPCSTR pszCriteria,
  5440. boolean fSubString, boolean fCaseSensitive)
  5441. {
  5442. // Locals
  5443. HRESULT hr=S_OK;
  5444. LPMIMEADDRESS pAddress;
  5445. // Invalid Arg
  5446. Assert(pProperty && pProperty->pGroup && pszCriteria);
  5447. // Does the Property need to be parsed ?
  5448. CHECKHR(hr = _HrParseInternetAddress(pProperty));
  5449. // Loop Infos...
  5450. for (pAddress=pProperty->pGroup->pHead; pAddress!=NULL; pAddress=pAddress->pNext)
  5451. {
  5452. // Tell the Address Info object to write its display information
  5453. if (_HrQueryAddress(pProperty, pAddress, pszCriteria, fSubString, fCaseSensitive) == S_OK)
  5454. goto exit;
  5455. }
  5456. // Not Found
  5457. hr = S_FALSE;
  5458. exit:
  5459. // Done
  5460. return hr;
  5461. }
  5462. // ----------------------------------------------------------------------------
  5463. // CMimePropertyContainer::_HrQueryAddress
  5464. // ----------------------------------------------------------------------------
  5465. HRESULT CMimePropertyContainer::_HrQueryAddress(LPPROPERTY pProperty, LPMIMEADDRESS pAddress,
  5466. LPCSTR pszCriteria, boolean fSubString, boolean fCaseSensitive)
  5467. {
  5468. // Locals
  5469. HRESULT hr=S_OK;
  5470. LPWSTR pwszCriteria=NULL;
  5471. // Invalid Arg
  5472. Assert(pProperty && pAddress && pszCriteria);
  5473. // Convert to Unicode
  5474. CHECKALLOC(pwszCriteria = PszToUnicode(CP_ACP, pszCriteria));
  5475. // Query Email Address First
  5476. if (MimeOleQueryStringW(pAddress->rEmail.psz, pwszCriteria, fSubString, fCaseSensitive) == S_OK)
  5477. goto exit;
  5478. // Query Display Address First
  5479. if (MimeOleQueryStringW(pAddress->rFriendly.psz, pwszCriteria, fSubString, fCaseSensitive) == S_OK)
  5480. goto exit;
  5481. // Not Found
  5482. hr = S_FALSE;
  5483. exit:
  5484. // Cleanup
  5485. SafeMemFree(pwszCriteria);
  5486. // Done
  5487. return hr;
  5488. }
  5489. // ----------------------------------------------------------------------------
  5490. // CMimePropertyContainer::Append
  5491. // ----------------------------------------------------------------------------
  5492. STDMETHODIMP CMimePropertyContainer::Append(DWORD dwAdrType, ENCODINGTYPE ietFriendly, LPCSTR pszFriendly,
  5493. LPCSTR pszEmail, LPHADDRESS phAddress)
  5494. {
  5495. // Locals
  5496. HRESULT hr=S_OK;
  5497. ADDRESSPROPS rProps;
  5498. // Setup rProps
  5499. ZeroMemory(&rProps, sizeof(rProps));
  5500. // Set AddrTyupe
  5501. rProps.dwProps = IAP_ADRTYPE | IAP_ENCODING;
  5502. rProps.dwAdrType = dwAdrType;
  5503. rProps.ietFriendly = ietFriendly;
  5504. // Set pszFriendly
  5505. if (pszFriendly)
  5506. {
  5507. FLAGSET(rProps.dwProps, IAP_FRIENDLY);
  5508. rProps.pszFriendly = (LPSTR)pszFriendly;
  5509. }
  5510. // Set pszEmail
  5511. if (pszEmail)
  5512. {
  5513. FLAGSET(rProps.dwProps, IAP_EMAIL);
  5514. rProps.pszEmail = (LPSTR)pszEmail;
  5515. }
  5516. // Set the Email Address
  5517. CHECKHR(hr = Insert(&rProps, phAddress));
  5518. exit:
  5519. // Done
  5520. return hr;
  5521. }
  5522. // ----------------------------------------------------------------------------
  5523. // CMimePropertyContainer::AppendW
  5524. // ----------------------------------------------------------------------------
  5525. STDMETHODIMP CMimePropertyContainer::AppendW(DWORD dwAdrType, ENCODINGTYPE ietFriendly, LPCWSTR pwszFriendly,
  5526. LPCWSTR pwszEmail, LPHADDRESS phAddress)
  5527. {
  5528. // Locals
  5529. HRESULT hr=S_OK;
  5530. ADDRESSPROPS rProps;
  5531. LPSTR pszFriendly = NULL,
  5532. pszEmail = NULL;
  5533. // Setup rProps
  5534. ZeroMemory(&rProps, sizeof(rProps));
  5535. // Set AddrTyupe
  5536. rProps.dwProps = IAP_ADRTYPE | IAP_ENCODING;
  5537. rProps.dwAdrType = dwAdrType;
  5538. rProps.ietFriendly = ietFriendly;
  5539. // Set pszFriendly
  5540. if (pwszFriendly)
  5541. {
  5542. FLAGSET(rProps.dwProps, IAP_FRIENDLYW);
  5543. rProps.pszFriendlyW = (LPWSTR)pwszFriendly;
  5544. IF_NULLEXIT(pszFriendly = PszToANSI(CP_ACP, pwszFriendly));
  5545. FLAGSET(rProps.dwProps, IAP_FRIENDLY);
  5546. rProps.pszFriendly = pszFriendly;
  5547. }
  5548. // Set pszEmail
  5549. if (pwszEmail)
  5550. {
  5551. IF_NULLEXIT(pszEmail = PszToANSI(CP_ACP, pwszEmail));
  5552. FLAGSET(rProps.dwProps, IAP_EMAIL);
  5553. rProps.pszEmail = pszEmail;
  5554. }
  5555. // Set the Email Address
  5556. CHECKHR(hr = Insert(&rProps, phAddress));
  5557. exit:
  5558. MemFree(pszFriendly);
  5559. MemFree(pszEmail);
  5560. return hr;
  5561. }
  5562. // ----------------------------------------------------------------------------
  5563. // CMimePropertyContainer::Insert
  5564. // ----------------------------------------------------------------------------
  5565. STDMETHODIMP CMimePropertyContainer::Insert(LPADDRESSPROPS pProps, LPHADDRESS phAddress)
  5566. {
  5567. // Locals
  5568. HRESULT hr=S_OK;
  5569. LPPROPSYMBOL pSymbol;
  5570. LPPROPERTY pProperty;
  5571. LPMIMEADDRESS pAddress;
  5572. // Invalid Arg
  5573. if (NULL == pProps)
  5574. return TrapError(E_INVALIDARG);
  5575. // Must have an Email Address and Address Type
  5576. if (!ISFLAGSET(pProps->dwProps, IAP_ADRTYPE) || (ISFLAGSET(pProps->dwProps, IAP_EMAIL) && FIsEmptyA(pProps->pszEmail)))
  5577. return TrapError(E_INVALIDARG);
  5578. // Init
  5579. if (phAddress)
  5580. *phAddress = NULL;
  5581. // Thread Safety
  5582. EnterCriticalSection(&m_cs);
  5583. // Get Header
  5584. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pProps->dwAdrType, &pSymbol));
  5585. // Open the group
  5586. CHECKHR(hr = _HrOpenProperty(pSymbol, &pProperty));
  5587. // Does the Property need to be parsed ?
  5588. CHECKHR(hr = _HrParseInternetAddress(pProperty));
  5589. // Append an Address to the group
  5590. CHECKHR(hr = _HrAppendAddressGroup(pProperty->pGroup, &pAddress));
  5591. // The group is dirty
  5592. Assert(pAddress->pGroup);
  5593. pAddress->pGroup->fDirty = TRUE;
  5594. // Set the Address Type
  5595. pAddress->dwAdrType = pProps->dwAdrType;
  5596. // Copy Address Props to Mime Address
  5597. CHECKHR(hr = SetProps(pAddress->hThis, pProps));
  5598. // Return the Handle
  5599. if (phAddress)
  5600. *phAddress = pAddress->hThis;
  5601. exit:
  5602. // Failure
  5603. if (FAILED(hr) && pAddress)
  5604. Delete(pAddress->hThis);
  5605. // Thread Safety
  5606. LeaveCriticalSection(&m_cs);
  5607. // Done
  5608. return hr;
  5609. }
  5610. // --------------------------------------------------------------------------------
  5611. // CMimePropertyContainer::_GetAddressCodePageId
  5612. // --------------------------------------------------------------------------------
  5613. CODEPAGEID CMimePropertyContainer::_GetAddressCodePageId(LPINETCSETINFO pCharset,
  5614. ENCODINGTYPE ietEncoding)
  5615. {
  5616. // Locals
  5617. CODEPAGEID cpiCodePage=CP_ACP;
  5618. // No Charset Yet
  5619. if (NULL == pCharset)
  5620. {
  5621. // Try to use the default
  5622. if (m_rOptions.pDefaultCharset)
  5623. pCharset = m_rOptions.pDefaultCharset;
  5624. // Use the global default
  5625. else if (CIntlGlobals::GetDefHeadCset())
  5626. pCharset = CIntlGlobals::GetDefHeadCset();
  5627. }
  5628. // If we have a charset, compute the friendly name codepage
  5629. if (pCharset)
  5630. {
  5631. // Decoded
  5632. if (IET_DECODED == ietEncoding)
  5633. {
  5634. // Get Windows
  5635. cpiCodePage = (CP_UNICODE == pCharset->cpiWindows) ? CP_ACP : MimeOleGetWindowsCPEx(pCharset);
  5636. }
  5637. // Otherwise
  5638. else
  5639. {
  5640. // Use Internet Codepage
  5641. cpiCodePage = (CP_UNICODE == pCharset->cpiInternet) ? CP_ACP : pCharset->cpiInternet;
  5642. }
  5643. }
  5644. // Done
  5645. return(cpiCodePage);
  5646. }
  5647. // --------------------------------------------------------------------------------
  5648. // CMimePropertyContainer::_HrSetAddressProps
  5649. // --------------------------------------------------------------------------------
  5650. HRESULT CMimePropertyContainer::_HrSetAddressProps(LPADDRESSPROPS pProps, LPMIMEADDRESS pAddress)
  5651. {
  5652. // Locals
  5653. HRESULT hr=S_OK;
  5654. LPINETCSETINFO pCharset=NULL;
  5655. LPWSTR pszFriendlyW=NULL;
  5656. LPWSTR pszEmailW=NULL;
  5657. ENCODINGTYPE ietFriendly;
  5658. // Set ietFriendly
  5659. ietFriendly = (ISFLAGSET(pProps->dwProps, IAP_ENCODING)) ? pProps->ietFriendly : IET_DECODED;
  5660. // IAP_ADRTYPE
  5661. if (ISFLAGSET(pProps->dwProps, IAP_ADRTYPE))
  5662. pAddress->dwAdrType = pProps->dwAdrType;
  5663. // IAP_HCHARSET
  5664. if (ISFLAGSET(pProps->dwProps, IAP_CHARSET) && pProps->hCharset)
  5665. {
  5666. // Resolve to pCharset
  5667. if (SUCCEEDED(g_pInternat->HrOpenCharset(pProps->hCharset, &pCharset)))
  5668. pAddress->pCharset = pCharset;
  5669. }
  5670. // IAP_CERTSTATE
  5671. if (ISFLAGSET(pProps->dwProps, IAP_CERTSTATE))
  5672. pAddress->certstate = pProps->certstate;
  5673. // IAP_COOKIE
  5674. if (ISFLAGSET(pProps->dwProps, IAP_COOKIE))
  5675. pAddress->dwCookie = pProps->dwCookie;
  5676. // IAP_FRIENDLYW
  5677. if (ISFLAGSET(pProps->dwProps, IAP_FRIENDLYW) && pProps->pszFriendlyW)
  5678. {
  5679. // Set It
  5680. CHECKHR(hr = HrSetAddressTokenW(pProps->pszFriendlyW, lstrlenW(pProps->pszFriendlyW), &pAddress->rFriendly));
  5681. }
  5682. // IAP_FRIENDLY
  5683. else if (ISFLAGSET(pProps->dwProps, IAP_FRIENDLY) && pProps->pszFriendly)
  5684. {
  5685. // If the string is encoded, then we have to convert from cpiInternet to a Unicode
  5686. if (IET_DECODED != ietFriendly)
  5687. {
  5688. // No Charset Yet
  5689. if (NULL == pCharset)
  5690. {
  5691. // Try to use the default
  5692. if (m_rOptions.pDefaultCharset)
  5693. pCharset = m_rOptions.pDefaultCharset;
  5694. // Use the global default
  5695. else if (CIntlGlobals::GetDefHeadCset())
  5696. pCharset = CIntlGlobals::GetDefHeadCset();
  5697. }
  5698. // If we have a charset
  5699. if (pCharset)
  5700. {
  5701. // Locals
  5702. RFC1522INFO Rfc1522Info={0};
  5703. PROPVARIANT Decoded;
  5704. // rfc1522 ?
  5705. Rfc1522Info.fRfc1522Allowed = TRUE;
  5706. // Init
  5707. Decoded.vt = VT_LPWSTR;
  5708. // Decode the header
  5709. if (SUCCEEDED(g_pInternat->DecodeHeader(pCharset->hCharset, pProps->pszFriendly, &Decoded, &Rfc1522Info)))
  5710. {
  5711. // Set
  5712. pszFriendlyW = Decoded.pwszVal;
  5713. }
  5714. }
  5715. }
  5716. // Otherwise, just convert to unicode
  5717. else
  5718. {
  5719. // Convert To Unicode
  5720. pszFriendlyW = PszToUnicode(_GetAddressCodePageId(pCharset, IET_DECODED), pProps->pszFriendly);
  5721. }
  5722. // If we haven't set pszFriendlyW, then just copy pszFriendly
  5723. if (NULL == pszFriendlyW)
  5724. {
  5725. // Convert from CP_ACP to unicode
  5726. CHECKALLOC(pszFriendlyW = PszToUnicode(CP_ACP, pProps->pszFriendly));
  5727. }
  5728. // Set It
  5729. CHECKHR(hr = HrSetAddressTokenW(pszFriendlyW, lstrlenW(pszFriendlyW), &pAddress->rFriendly));
  5730. }
  5731. // IAP_EMAIL
  5732. if (ISFLAGSET(pProps->dwProps, IAP_EMAIL) && pProps->pszEmail)
  5733. {
  5734. // Convert To Unicode
  5735. CHECKALLOC(pszEmailW = PszToUnicode(CP_ACP, pProps->pszEmail));
  5736. // Set It
  5737. CHECKHR(hr = HrSetAddressTokenW(pszEmailW, lstrlenW(pszEmailW), &pAddress->rEmail));
  5738. }
  5739. // IAP_SIGNING_PRINT
  5740. if (ISFLAGSET(pProps->dwProps, IAP_SIGNING_PRINT) && pProps->tbSigning.pBlobData)
  5741. {
  5742. // Free Current Blob
  5743. SafeMemFree(pAddress->tbSigning.pBlobData);
  5744. pAddress->tbSigning.cbSize = 0;
  5745. // Dup
  5746. CHECKHR(hr = HrCopyBlob(&pProps->tbSigning, &pAddress->tbSigning));
  5747. }
  5748. // IAP_ENCRYPTION_PRINT
  5749. if (ISFLAGSET(pProps->dwProps, IAP_ENCRYPTION_PRINT) && pProps->tbEncryption.pBlobData)
  5750. {
  5751. // Free Current Blob
  5752. SafeMemFree(pAddress->tbEncryption.pBlobData);
  5753. pAddress->tbEncryption.cbSize = 0;
  5754. // Dup
  5755. CHECKHR(hr = HrCopyBlob(&pProps->tbEncryption, &pAddress->tbEncryption));
  5756. }
  5757. // pAddress->pGroup is Dirty
  5758. Assert(pAddress->pGroup);
  5759. if (pAddress->pGroup)
  5760. pAddress->pGroup->fDirty = TRUE;
  5761. exit:
  5762. // Cleanup
  5763. SafeMemFree(pszFriendlyW);
  5764. SafeMemFree(pszEmailW);
  5765. // Done
  5766. return hr;
  5767. }
  5768. // --------------------------------------------------------------------------------
  5769. // CMimePropertyContainer::_HrGetAddressProps
  5770. // --------------------------------------------------------------------------------
  5771. HRESULT CMimePropertyContainer::_HrGetAddressProps(LPADDRESSPROPS pProps, LPMIMEADDRESS pAddress)
  5772. {
  5773. // Locals
  5774. HRESULT hr=S_OK;
  5775. // IAP_CHARSET
  5776. if (ISFLAGSET(pProps->dwProps, IAP_CHARSET))
  5777. {
  5778. if (pAddress->pCharset && pAddress->pCharset->hCharset)
  5779. {
  5780. pProps->hCharset = pAddress->pCharset->hCharset;
  5781. }
  5782. else
  5783. {
  5784. pProps->hCharset = NULL;
  5785. FLAGCLEAR(pProps->dwProps, IAP_CHARSET);
  5786. }
  5787. }
  5788. // IAP_HANDLE
  5789. if (ISFLAGSET(pProps->dwProps, IAP_HANDLE))
  5790. {
  5791. Assert(pAddress->hThis);
  5792. pProps->hAddress = pAddress->hThis;
  5793. }
  5794. // IAP_ADRTYPE
  5795. if (ISFLAGSET(pProps->dwProps, IAP_ADRTYPE))
  5796. {
  5797. Assert(pAddress->dwAdrType);
  5798. pProps->dwAdrType = pAddress->dwAdrType;
  5799. }
  5800. // IAP_COOKIE
  5801. if (ISFLAGSET(pProps->dwProps, IAP_COOKIE))
  5802. {
  5803. pProps->dwCookie = pAddress->dwCookie;
  5804. }
  5805. // IAP_CERTSTATE
  5806. if (ISFLAGSET(pProps->dwProps, IAP_CERTSTATE))
  5807. {
  5808. pProps->certstate = pAddress->certstate;
  5809. }
  5810. // IAP_ENCODING
  5811. if (ISFLAGSET(pProps->dwProps, IAP_ENCODING))
  5812. {
  5813. pProps->ietFriendly = IET_DECODED;
  5814. }
  5815. // IAP_FRIENDLY
  5816. if (ISFLAGSET(pProps->dwProps, IAP_FRIENDLY))
  5817. {
  5818. // Decode
  5819. if (pAddress->rFriendly.psz)
  5820. {
  5821. // Compute the correct codepage...
  5822. CHECKALLOC(pProps->pszFriendly = PszToANSI(_GetAddressCodePageId(pAddress->pCharset, IET_DECODED), pAddress->rFriendly.psz));
  5823. }
  5824. else
  5825. {
  5826. pProps->pszFriendly = NULL;
  5827. FLAGCLEAR(pProps->dwProps, IAP_FRIENDLY);
  5828. }
  5829. }
  5830. // IAT_FRIENDLYW
  5831. if (ISFLAGSET(pProps->dwProps, IAP_FRIENDLYW))
  5832. {
  5833. // Get the email address
  5834. if (pAddress->rFriendly.psz)
  5835. {
  5836. CHECKALLOC(pProps->pszFriendlyW = PszDupW(pAddress->rFriendly.psz));
  5837. }
  5838. else
  5839. {
  5840. pProps->pszFriendlyW = NULL;
  5841. FLAGCLEAR(pProps->dwProps, IAP_FRIENDLYW);
  5842. }
  5843. }
  5844. // IAP_EMAIL
  5845. if (ISFLAGSET(pProps->dwProps, IAP_EMAIL))
  5846. {
  5847. // Get the email address
  5848. if (pAddress->rEmail.psz)
  5849. {
  5850. CHECKALLOC(pProps->pszEmail = PszToANSI(CP_ACP, pAddress->rEmail.psz));
  5851. }
  5852. else
  5853. {
  5854. pProps->pszEmail = NULL;
  5855. FLAGCLEAR(pProps->dwProps, IAP_EMAIL);
  5856. }
  5857. }
  5858. // IAP_SIGNING_PRINT
  5859. if (ISFLAGSET(pProps->dwProps, IAP_SIGNING_PRINT))
  5860. {
  5861. if (pAddress->tbSigning.pBlobData)
  5862. {
  5863. CHECKHR(hr = HrCopyBlob(&pAddress->tbSigning, &pProps->tbSigning));
  5864. }
  5865. else
  5866. {
  5867. pProps->tbSigning.pBlobData = NULL;
  5868. pProps->tbSigning.cbSize = 0;
  5869. FLAGCLEAR(pProps->dwProps, IAP_SIGNING_PRINT);
  5870. }
  5871. }
  5872. // IAP_ENCRYPTION_PRINT
  5873. if (ISFLAGSET(pProps->dwProps, IAP_ENCRYPTION_PRINT))
  5874. {
  5875. if (pAddress->tbEncryption.pBlobData)
  5876. {
  5877. CHECKHR(hr = HrCopyBlob(&pAddress->tbEncryption, &pProps->tbEncryption));
  5878. }
  5879. else
  5880. {
  5881. pProps->tbEncryption.pBlobData = NULL;
  5882. pProps->tbEncryption.cbSize = 0;
  5883. FLAGCLEAR(pProps->dwProps, IAP_ENCRYPTION_PRINT);
  5884. }
  5885. }
  5886. exit:
  5887. // Done
  5888. return hr;
  5889. }
  5890. // ----------------------------------------------------------------------------
  5891. // CMimePropertyContainer::SetProps
  5892. // ----------------------------------------------------------------------------
  5893. STDMETHODIMP CMimePropertyContainer::SetProps(HADDRESS hAddress, LPADDRESSPROPS pProps)
  5894. {
  5895. // Locals
  5896. HRESULT hr=S_OK;
  5897. LPPROPSYMBOL pSymbol;
  5898. LPPROPERTY pProperty;
  5899. LPMIMEADDRESS pAddress;
  5900. // Invalid Arg
  5901. if (NULL == pProps)
  5902. return TrapError(E_INVALIDARG);
  5903. // Must have an Email Address
  5904. if (ISFLAGSET(pProps->dwProps, IAP_EMAIL) && FIsEmptyA(pProps->pszEmail))
  5905. return TrapError(E_INVALIDARG);
  5906. // Thread Safety
  5907. EnterCriticalSection(&m_cs);
  5908. // Invalid Handle
  5909. if (_FIsValidHAddress(hAddress) == FALSE)
  5910. {
  5911. hr = TrapError(MIME_E_INVALID_HANDLE);
  5912. goto exit;
  5913. }
  5914. // Deref
  5915. pAddress = HADDRESSGET(hAddress);
  5916. // Changing Address Type
  5917. if (ISFLAGSET(pProps->dwProps, IAP_ADRTYPE) && pProps->dwAdrType != pAddress->dwAdrType)
  5918. {
  5919. // Unlink this address from this group
  5920. _UnlinkAddress(pAddress);
  5921. // Get Header
  5922. CHECKHR(hr = g_pSymCache->HrOpenSymbol(pProps->dwAdrType, &pSymbol));
  5923. // Open the group
  5924. CHECKHR(hr = _HrOpenProperty(pSymbol, &pProperty));
  5925. // Does the Property need to be parsed ?
  5926. CHECKHR(hr = _HrParseInternetAddress(pProperty));
  5927. // LinkAddress
  5928. _LinkAddress(pAddress, pProperty->pGroup);
  5929. // Dirty
  5930. pProperty->pGroup->fDirty = TRUE;
  5931. }
  5932. // Changing other properties
  5933. CHECKHR(hr = _HrSetAddressProps(pProps, pAddress));
  5934. exit:
  5935. // Thread Safety
  5936. LeaveCriticalSection(&m_cs);
  5937. // Done
  5938. return hr;
  5939. }
  5940. // ----------------------------------------------------------------------------
  5941. // CMimePropertyContainer::GetProps
  5942. // ----------------------------------------------------------------------------
  5943. STDMETHODIMP CMimePropertyContainer::GetProps(HADDRESS hAddress, LPADDRESSPROPS pProps)
  5944. {
  5945. // Locals
  5946. HRESULT hr=S_OK;
  5947. LPMIMEADDRESS pAddress;
  5948. // Invalid Arg
  5949. if (NULL == pProps)
  5950. return TrapError(E_INVALIDARG);
  5951. // Thread Safety
  5952. EnterCriticalSection(&m_cs);
  5953. // Invalid Handle
  5954. if (_FIsValidHAddress(hAddress) == FALSE)
  5955. {
  5956. hr = TrapError(MIME_E_INVALID_HANDLE);
  5957. goto exit;
  5958. }
  5959. // Deref
  5960. pAddress = HADDRESSGET(hAddress);
  5961. // Changing Email Address to Null
  5962. CHECKHR(hr = _HrGetAddressProps(pProps, pAddress));
  5963. exit:
  5964. // Thread Safety
  5965. LeaveCriticalSection(&m_cs);
  5966. // Done
  5967. return hr;
  5968. }
  5969. // ----------------------------------------------------------------------------
  5970. // CMimePropertyContainer::GetSender
  5971. // ----------------------------------------------------------------------------
  5972. STDMETHODIMP CMimePropertyContainer::GetSender(LPADDRESSPROPS pProps)
  5973. {
  5974. // Locals
  5975. HRESULT hr=S_OK;
  5976. LPPROPERTY pProperty;
  5977. LPPROPERTY pSender=NULL;
  5978. HADDRESS hAddress=NULL;
  5979. // Invalid Arg
  5980. if (NULL == pProps)
  5981. return TrapError(E_INVALIDARG);
  5982. // Thread Safety
  5983. EnterCriticalSection(&m_cs);
  5984. // Find first from
  5985. for (pProperty=m_rAdrTable.pHead; pProperty!=NULL; pProperty=pProperty->pGroup->pNext)
  5986. {
  5987. // Not the type I want
  5988. if (ISFLAGSET(pProperty->pSymbol->dwAdrType, IAT_FROM))
  5989. {
  5990. // Does the Property need to be parsed ?
  5991. CHECKHR(hr = _HrParseInternetAddress(pProperty));
  5992. // Take the first address
  5993. if (pProperty->pGroup->pHead)
  5994. hAddress = pProperty->pGroup->pHead->hThis;
  5995. // Done
  5996. break;
  5997. }
  5998. // Look for Sender:
  5999. if (ISFLAGSET(pProperty->pSymbol->dwAdrType, IAT_SENDER) && NULL == pSender)
  6000. {
  6001. // Does the Property need to be parsed ?
  6002. CHECKHR(hr = _HrParseInternetAddress(pProperty));
  6003. // Sender Property
  6004. pSender = pProperty;
  6005. }
  6006. }
  6007. // Is there a sender group
  6008. if (NULL == hAddress && NULL != pSender && NULL != pSender->pGroup->pHead)
  6009. hAddress = pSender->pGroup->pHead->hThis;
  6010. // No Address
  6011. if (NULL == hAddress)
  6012. {
  6013. hr = TrapError(MIME_E_NOT_FOUND);
  6014. goto exit;
  6015. }
  6016. // Get Props
  6017. CHECKHR(hr = GetProps(hAddress, pProps));
  6018. exit:
  6019. // Thread Safety
  6020. LeaveCriticalSection(&m_cs);
  6021. // Done
  6022. return hr;
  6023. }
  6024. // ----------------------------------------------------------------------------
  6025. // CMimePropertyContainer::CountTypes
  6026. // ----------------------------------------------------------------------------
  6027. STDMETHODIMP CMimePropertyContainer::CountTypes(DWORD dwAdrTypes, ULONG *pcAdrs)
  6028. {
  6029. // Locals
  6030. HRESULT hr=S_OK;
  6031. LPPROPERTY pProperty;
  6032. // Invalid Arg
  6033. if (NULL == pcAdrs)
  6034. return TrapError(E_INVALIDARG);
  6035. // Thread Safety
  6036. EnterCriticalSection(&m_cs);
  6037. // Init
  6038. *pcAdrs = 0;
  6039. // Loop through groups
  6040. for (pProperty=m_rAdrTable.pHead; pProperty!=NULL; pProperty=pProperty->pGroup->pNext)
  6041. {
  6042. // Not the type I want
  6043. if (ISFLAGSET(dwAdrTypes, pProperty->pSymbol->dwAdrType))
  6044. {
  6045. // Does the Property need to be parsed ?
  6046. CHECKHR(hr = _HrParseInternetAddress(pProperty));
  6047. // Increment Count
  6048. (*pcAdrs) += pProperty->pGroup->cAdrs;
  6049. }
  6050. }
  6051. exit:
  6052. // Thread Safety
  6053. LeaveCriticalSection(&m_cs);
  6054. // Done
  6055. return hr;
  6056. }
  6057. // ----------------------------------------------------------------------------
  6058. // CMimePropertyContainer::GetTypes
  6059. // ----------------------------------------------------------------------------
  6060. STDMETHODIMP CMimePropertyContainer::GetTypes(DWORD dwAdrTypes, DWORD dwProps, LPADDRESSLIST pList)
  6061. {
  6062. // Locals
  6063. HRESULT hr=S_OK;
  6064. ULONG iAddress;
  6065. LPPROPERTY pProperty;
  6066. LPMIMEADDRESS pAddress;
  6067. // Invalid Arg
  6068. if (NULL == pList)
  6069. return TrapError(E_INVALIDARG);
  6070. // Init
  6071. ZeroMemory(pList, sizeof(ADDRESSLIST));
  6072. // Thread Safety
  6073. EnterCriticalSection(&m_cs);
  6074. // Loop through groups
  6075. CHECKHR(hr = CountTypes(dwAdrTypes, &pList->cAdrs));
  6076. // Nothing..
  6077. if (0 == pList->cAdrs)
  6078. goto exit;
  6079. // Allocate an array
  6080. CHECKHR(hr = HrAlloc((LPVOID *)&pList->prgAdr, pList->cAdrs * sizeof(ADDRESSPROPS)));
  6081. // Init
  6082. ZeroMemory(pList->prgAdr, pList->cAdrs * sizeof(ADDRESSPROPS));
  6083. // Fill with types...
  6084. for (iAddress=0, pProperty=m_rAdrTable.pHead; pProperty!=NULL; pProperty=pProperty->pGroup->pNext)
  6085. {
  6086. // Not the type I want
  6087. if (!ISFLAGSET(dwAdrTypes, pProperty->pSymbol->dwAdrType))
  6088. continue;
  6089. // Does the Property need to be parsed ?
  6090. CHECKHR(hr = _HrParseInternetAddress(pProperty));
  6091. // Loop Infos...
  6092. for (pAddress=pProperty->pGroup->pHead; pAddress!=NULL; pAddress=pAddress->pNext)
  6093. {
  6094. // Verify Size...
  6095. Assert(iAddress < pList->cAdrs);
  6096. // Zeromemory
  6097. ZeroMemory(&pList->prgAdr[iAddress], sizeof(ADDRESSPROPS));
  6098. // Set Desired Props
  6099. pList->prgAdr[iAddress].dwProps = dwProps;
  6100. // Get the Address Props
  6101. CHECKHR(hr = _HrGetAddressProps(&pList->prgAdr[iAddress], pAddress));
  6102. // Increment piCurrent
  6103. iAddress++;
  6104. }
  6105. }
  6106. exit:
  6107. // Failure..
  6108. if (FAILED(hr))
  6109. {
  6110. g_pMoleAlloc->FreeAddressList(pList);
  6111. ZeroMemory(pList, sizeof(ADDRESSLIST));
  6112. }
  6113. // Thread Safety
  6114. LeaveCriticalSection(&m_cs);
  6115. // Done
  6116. return hr;
  6117. }
  6118. // ----------------------------------------------------------------------------
  6119. // CMimePropertyContainer::EnumTypes
  6120. // ----------------------------------------------------------------------------
  6121. STDMETHODIMP CMimePropertyContainer::EnumTypes(DWORD dwAdrTypes, DWORD dwProps, IMimeEnumAddressTypes **ppEnum)
  6122. {
  6123. // Locals
  6124. HRESULT hr=S_OK;
  6125. CMimeEnumAddressTypes *pEnum=NULL;
  6126. ADDRESSLIST rList;
  6127. // Invalid Arg
  6128. if (NULL == ppEnum)
  6129. return TrapError(E_INVALIDARG);
  6130. // Init out param in case of error
  6131. *ppEnum = NULL;
  6132. // Init rList
  6133. ZeroMemory(&rList, sizeof(ADDRESSLIST));
  6134. // Thread Safety
  6135. EnterCriticalSection(&m_cs);
  6136. // Get the address lsit
  6137. CHECKHR(hr = GetTypes(dwAdrTypes, dwProps, &rList));
  6138. // Create a new Enumerator
  6139. CHECKALLOC(pEnum = new CMimeEnumAddressTypes);
  6140. // Init
  6141. CHECKHR(hr = pEnum->HrInit((IMimeAddressTable *)this, 0, &rList, FALSE));
  6142. // Clear rList
  6143. rList.cAdrs = 0;
  6144. rList.prgAdr = NULL;
  6145. // Return it
  6146. *ppEnum = pEnum;
  6147. (*ppEnum)->AddRef();
  6148. exit:
  6149. // Cleanup
  6150. SafeRelease(pEnum);
  6151. if (rList.cAdrs)
  6152. g_pMoleAlloc->FreeAddressList(&rList);
  6153. // Thread Safety
  6154. LeaveCriticalSection(&m_cs);
  6155. // Done
  6156. return hr;
  6157. }
  6158. // ----------------------------------------------------------------------------
  6159. // CMimePropertyContainer::Delete
  6160. // ----------------------------------------------------------------------------
  6161. STDMETHODIMP CMimePropertyContainer::Delete(HADDRESS hAddress)
  6162. {
  6163. // Locals
  6164. HRESULT hr=S_OK;
  6165. LPMIMEADDRESS pAddress;
  6166. // Thread Safety
  6167. EnterCriticalSection(&m_cs);
  6168. // Invalid Handle
  6169. if (_FIsValidHAddress(hAddress) == FALSE)
  6170. {
  6171. hr = TrapError(MIME_E_INVALID_HANDLE);
  6172. goto exit;
  6173. }
  6174. // Deref Address
  6175. pAddress = HADDRESSGET(hAddress);
  6176. // Unlink this address
  6177. _UnlinkAddress(pAddress);
  6178. // Unlink this address
  6179. _FreeAddress(pAddress);
  6180. exit:
  6181. // Thread Safety
  6182. LeaveCriticalSection(&m_cs);
  6183. // Done
  6184. return hr;
  6185. }
  6186. // ----------------------------------------------------------------------------
  6187. // CMimePropertyContainer::DeleteTypes
  6188. // ----------------------------------------------------------------------------
  6189. STDMETHODIMP CMimePropertyContainer::DeleteTypes(DWORD dwAdrTypes)
  6190. {
  6191. // Locals
  6192. LPPROPERTY pProperty;
  6193. BOOL fFound;
  6194. // Thread Safety
  6195. EnterCriticalSection(&m_cs);
  6196. // While there are address types
  6197. while(dwAdrTypes)
  6198. {
  6199. // Reset fFound
  6200. fFound = FALSE;
  6201. // Search for first delete-able address type
  6202. for (pProperty=m_rAdrTable.pHead; pProperty!=NULL; pProperty=pProperty->pGroup->pNext)
  6203. {
  6204. // Not the type I want
  6205. if (ISFLAGSET(dwAdrTypes, pProperty->pSymbol->dwAdrType))
  6206. {
  6207. // We found a properyt
  6208. fFound = TRUE;
  6209. // Clear this address type ad being deleted
  6210. FLAGCLEAR(dwAdrTypes, pProperty->pSymbol->dwAdrType);
  6211. // Unlink this property
  6212. _UnlinkProperty(pProperty);
  6213. // Done
  6214. break;
  6215. }
  6216. }
  6217. // No Property Found
  6218. if (FALSE == fFound)
  6219. break;
  6220. }
  6221. // Thread Safety
  6222. LeaveCriticalSection(&m_cs);
  6223. // Done
  6224. return S_OK;
  6225. }
  6226. // ----------------------------------------------------------------------------
  6227. // GetFormatW
  6228. // ----------------------------------------------------------------------------
  6229. HRESULT CMimePropertyContainer::GetFormatW(DWORD dwAdrType, ADDRESSFORMAT format,
  6230. LPWSTR *ppwszFormat)
  6231. {
  6232. // Locals
  6233. HRESULT hr=S_OK;
  6234. PROPVARIANT Variant;
  6235. // Trace
  6236. TraceCall("CMimePropertyContainer::GetFormatW");
  6237. // Invalid Args
  6238. if (NULL == ppwszFormat)
  6239. return(TraceResult(E_INVALIDARG));
  6240. // Thread Safety
  6241. EnterCriticalSection(&m_cs);
  6242. // Init
  6243. ZeroMemory(&Variant, sizeof(PROPVARIANT));
  6244. // I want a unicode string
  6245. Variant.vt = VT_LPWSTR;
  6246. // Get the address format
  6247. CHECKHR(hr = _GetFormatBase(dwAdrType, format, &Variant));
  6248. // Return the String
  6249. *ppwszFormat = Variant.pwszVal;
  6250. exit:
  6251. // Thread Safety
  6252. LeaveCriticalSection(&m_cs);
  6253. // Done
  6254. return(hr);
  6255. }
  6256. // ----------------------------------------------------------------------------
  6257. // CMimePropertyContainer::GetFormat
  6258. // ----------------------------------------------------------------------------
  6259. STDMETHODIMP CMimePropertyContainer::GetFormat(DWORD dwAdrType, ADDRESSFORMAT format,
  6260. LPSTR *ppszFormat)
  6261. {
  6262. // Locals
  6263. HRESULT hr=S_OK;
  6264. PROPVARIANT Variant;
  6265. // Trace
  6266. TraceCall("CMimePropertyContainer::GetFormat");
  6267. // Invalid Args
  6268. if (NULL == ppszFormat)
  6269. return(TraceResult(E_INVALIDARG));
  6270. // Thread Safety
  6271. EnterCriticalSection(&m_cs);
  6272. // Init
  6273. ZeroMemory(&Variant, sizeof(PROPVARIANT));
  6274. // I want a unicode string
  6275. Variant.vt = VT_LPSTR;
  6276. // Get the address format
  6277. CHECKHR(hr = _GetFormatBase(dwAdrType, format, &Variant));
  6278. // Return the String
  6279. *ppszFormat = Variant.pszVal;
  6280. exit:
  6281. // Thread Safety
  6282. LeaveCriticalSection(&m_cs);
  6283. // Done
  6284. return(hr);
  6285. }
  6286. // ----------------------------------------------------------------------------
  6287. // CMimePropertyContainer::_GetFormatBase
  6288. // ----------------------------------------------------------------------------
  6289. HRESULT CMimePropertyContainer::_GetFormatBase(DWORD dwAdrType, ADDRESSFORMAT format,
  6290. LPPROPVARIANT pVariant)
  6291. {
  6292. // Locals
  6293. HRESULT hr=S_OK;
  6294. CByteStream cByteStream;
  6295. ULONG cAddrsWrote=0;
  6296. LPPROPERTY pProperty;
  6297. // Validate
  6298. Assert(pVariant && (VT_LPWSTR == pVariant->vt || VT_LPSTR == pVariant->vt));
  6299. // Fill with types...
  6300. for (pProperty=m_rAdrTable.pHead; pProperty!=NULL; pProperty=pProperty->pGroup->pNext)
  6301. {
  6302. // Not the type I want
  6303. if (!ISFLAGSET(dwAdrType, pProperty->pSymbol->dwAdrType))
  6304. continue;
  6305. // Does the Property need to be parsed ?
  6306. CHECKHR(hr = _HrParseInternetAddress(pProperty));
  6307. // Tell the group object to write its display address into pStream
  6308. CHECKHR(hr = _HrSaveAddressGroup(pProperty, &cByteStream, &cAddrsWrote, format, pVariant->vt));
  6309. }
  6310. // Did we write any for this address tyep ?
  6311. if (cAddrsWrote)
  6312. {
  6313. // Multibyte
  6314. if (VT_LPSTR == pVariant->vt)
  6315. {
  6316. // Get Text
  6317. CHECKHR(hr = cByteStream.HrAcquireStringA(NULL, &pVariant->pszVal, ACQ_DISPLACE));
  6318. }
  6319. // Otherwise, unicode
  6320. else
  6321. {
  6322. // Validate
  6323. Assert(VT_LPWSTR == pVariant->vt);
  6324. // Get Text
  6325. CHECKHR(hr = cByteStream.HrAcquireStringW(NULL, &pVariant->pwszVal, ACQ_DISPLACE));
  6326. }
  6327. }
  6328. else
  6329. hr = MIME_E_NO_DATA;
  6330. exit:
  6331. // Done
  6332. return hr;
  6333. }
  6334. // ----------------------------------------------------------------------------
  6335. // CMimePropertyContainer::AppendRfc822
  6336. // ----------------------------------------------------------------------------
  6337. STDMETHODIMP CMimePropertyContainer::AppendRfc822(DWORD dwAdrType, ENCODINGTYPE ietEncoding, LPCSTR pszRfc822Adr)
  6338. {
  6339. // Locals
  6340. HRESULT hr=S_OK;
  6341. MIMEVARIANT rValue;
  6342. LPPROPSYMBOL pSymbol;
  6343. // Invalid Arg
  6344. if (NULL == pszRfc822Adr)
  6345. return TrapError(E_INVALIDARG);
  6346. // Thread Safety
  6347. EnterCriticalSection(&m_cs);
  6348. // Get Header
  6349. CHECKHR(hr = g_pSymCache->HrOpenSymbol(dwAdrType, &pSymbol));
  6350. // MimeVariant
  6351. rValue.type = MVT_STRINGA;
  6352. rValue.rStringA.pszVal = (LPSTR)pszRfc822Adr;
  6353. rValue.rStringA.cchVal = lstrlen(pszRfc822Adr);
  6354. // Store as a property
  6355. CHECKHR(hr = AppendProp(pSymbol, (IET_ENCODED == ietEncoding) ? PDF_ENCODED : 0, &rValue));
  6356. exit:
  6357. // Thread Safety
  6358. LeaveCriticalSection(&m_cs);
  6359. // Done
  6360. return hr;
  6361. }
  6362. // ----------------------------------------------------------------------------
  6363. // CMimePropertyContainer::AppendRfc822W
  6364. // ----------------------------------------------------------------------------
  6365. STDMETHODIMP CMimePropertyContainer::AppendRfc822W(DWORD dwAdrType, ENCODINGTYPE ietEncoding, LPCWSTR pwszRfc822Adr)
  6366. {
  6367. // Locals
  6368. HRESULT hr=S_OK;
  6369. MIMEVARIANT rValue;
  6370. LPPROPSYMBOL pSymbol;
  6371. // Invalid Arg
  6372. if (NULL == pwszRfc822Adr)
  6373. return TrapError(E_INVALIDARG);
  6374. // Thread Safety
  6375. EnterCriticalSection(&m_cs);
  6376. // Get Header
  6377. CHECKHR(hr = g_pSymCache->HrOpenSymbol(dwAdrType, &pSymbol));
  6378. // MimeVariant
  6379. rValue.type = MVT_STRINGW;
  6380. rValue.rStringW.pszVal = (LPWSTR)pwszRfc822Adr;
  6381. rValue.rStringW.cchVal = lstrlenW(pwszRfc822Adr);
  6382. // Store as a property
  6383. CHECKHR(hr = AppendProp(pSymbol, (IET_ENCODED == ietEncoding) ? PDF_ENCODED : 0, &rValue));
  6384. exit:
  6385. // Thread Safety
  6386. LeaveCriticalSection(&m_cs);
  6387. // Done
  6388. return hr;
  6389. }
  6390. // ----------------------------------------------------------------------------
  6391. // CMimePropertyContainer::ParseRfc822
  6392. // ----------------------------------------------------------------------------
  6393. STDMETHODIMP CMimePropertyContainer::ParseRfc822(DWORD dwAdrType, ENCODINGTYPE ietEncoding,
  6394. LPCSTR pszRfc822Adr, LPADDRESSLIST pList)
  6395. {
  6396. // Locals
  6397. HRESULT hr=S_OK;
  6398. LPPROPSYMBOL pSymbol;
  6399. LPADDRESSPROPS pAddress;
  6400. ULONG cAlloc=0;
  6401. LPWSTR pwszData=NULL;
  6402. PROPVARIANT rDecoded;
  6403. RFC1522INFO rRfc1522Info;
  6404. CAddressParser cAdrParse;
  6405. CODEPAGEID cpiAddress=CP_ACP;
  6406. INETCSETINFO CsetInfo;
  6407. // Invalid Arg
  6408. if (NULL == pszRfc822Adr || NULL == pList)
  6409. return TrapError(E_INVALIDARG);
  6410. // LocalInit
  6411. ZeroMemory(&rDecoded, sizeof(PROPVARIANT));
  6412. // ZeroParse
  6413. ZeroMemory(pList, sizeof(ADDRESSLIST));
  6414. // Get codepage
  6415. cpiAddress = _GetAddressCodePageId(NULL, IET_DECODED);
  6416. // Get Header
  6417. CHECKHR(hr = g_pSymCache->HrOpenSymbol(dwAdrType, &pSymbol));
  6418. // Setup rfc1522Info
  6419. rRfc1522Info.hRfc1522Cset = NULL;
  6420. // Decode...
  6421. if (IET_DECODED != ietEncoding)
  6422. {
  6423. // Setup rfc1522Info
  6424. rRfc1522Info.fRfc1522Allowed = TRUE;
  6425. rRfc1522Info.fAllow8bit = FALSE;
  6426. rDecoded.vt = VT_LPWSTR;
  6427. // Check for 1522 Encoding...
  6428. if (SUCCEEDED(g_pInternat->DecodeHeader(NULL, pszRfc822Adr, &rDecoded, &rRfc1522Info)))
  6429. {
  6430. // Set the data
  6431. pwszData = rDecoded.pwszVal;
  6432. // Get the pCharset
  6433. if (rRfc1522Info.hRfc1522Cset)
  6434. {
  6435. // Get the charset info
  6436. if (SUCCEEDED(MimeOleGetCharsetInfo(rRfc1522Info.hRfc1522Cset, &CsetInfo)))
  6437. {
  6438. // Set cpiAddress
  6439. cpiAddress = MimeOleGetWindowsCPEx(&CsetInfo);
  6440. // Can't be unicode
  6441. if (CP_UNICODE == cpiAddress)
  6442. cpiAddress = CP_ACP;
  6443. }
  6444. }
  6445. }
  6446. }
  6447. // Otherwise, convert to unicode...
  6448. else
  6449. {
  6450. // Convert
  6451. CHECKALLOC(pwszData = PszToUnicode(cpiAddress, pszRfc822Adr));
  6452. }
  6453. // Initialize Parse Structure
  6454. cAdrParse.Init(pwszData, lstrlenW(pwszData));
  6455. // Parse
  6456. while(SUCCEEDED(cAdrParse.Next()))
  6457. {
  6458. // Grow my address array ?
  6459. if (pList->cAdrs + 1 > cAlloc)
  6460. {
  6461. // Realloc the array
  6462. CHECKHR(hr = HrRealloc((LPVOID *)&pList->prgAdr, sizeof(ADDRESSPROPS) * (cAlloc + 5)));
  6463. // Increment alloc size
  6464. cAlloc += 5;
  6465. }
  6466. // Readability
  6467. pAddress = &pList->prgAdr[pList->cAdrs];
  6468. // Init
  6469. ZeroMemory(pAddress, sizeof(*pAddress));
  6470. // Copy the Friendly Name
  6471. CHECKALLOC(pAddress->pszFriendly = PszToANSI(cpiAddress, cAdrParse.PszFriendly()));
  6472. // Copy the Email Name
  6473. CHECKALLOC(pAddress->pszEmail = PszToANSI(CP_ACP, cAdrParse.PszEmail()));
  6474. // Charset
  6475. if (rRfc1522Info.hRfc1522Cset)
  6476. {
  6477. pAddress->hCharset = rRfc1522Info.hRfc1522Cset;
  6478. FLAGSET(pAddress->dwProps, IAP_CHARSET);
  6479. }
  6480. // Encoding
  6481. pAddress->ietFriendly = IET_DECODED;
  6482. // Set Property Mask
  6483. FLAGSET(pAddress->dwProps, IAP_FRIENDLY | IAP_EMAIL | IAP_ENCODING);
  6484. // Increment Count
  6485. pList->cAdrs++;
  6486. }
  6487. exit:
  6488. // Failure
  6489. if (FAILED(hr))
  6490. g_pMoleAlloc->FreeAddressList(pList);
  6491. // Cleanup
  6492. MemFree(pwszData);
  6493. // Done
  6494. return hr;
  6495. }
  6496. // ----------------------------------------------------------------------------
  6497. // CMimePropertyContainer::ParseRfc822W
  6498. // ----------------------------------------------------------------------------
  6499. STDMETHODIMP CMimePropertyContainer::ParseRfc822W(DWORD dwAdrType, LPCWSTR pwszRfc822Adr, LPADDRESSLIST pList)
  6500. {
  6501. // Locals
  6502. HRESULT hr=S_OK;
  6503. LPPROPSYMBOL pSymbol;
  6504. LPADDRESSPROPS pAddress;
  6505. ULONG cAlloc=0;
  6506. PROPVARIANT rDecoded = {0};
  6507. RFC1522INFO rRfc1522Info;
  6508. CAddressParser cAdrParse;
  6509. // Invalid Arg
  6510. if (NULL == pwszRfc822Adr || NULL == pList)
  6511. return TrapError(E_INVALIDARG);
  6512. // ZeroParse
  6513. ZeroMemory(pList, sizeof(*pList));
  6514. // Get Header
  6515. CHECKHR(hr = g_pSymCache->HrOpenSymbol(dwAdrType, &pSymbol));
  6516. // Setup rfc1522Info
  6517. rRfc1522Info.hRfc1522Cset = NULL;
  6518. // Initialize Parse Structure
  6519. cAdrParse.Init(pwszRfc822Adr, lstrlenW(pwszRfc822Adr));
  6520. // Parse
  6521. while(SUCCEEDED(cAdrParse.Next()))
  6522. {
  6523. // Grow my address array ?
  6524. if (pList->cAdrs + 1 > cAlloc)
  6525. {
  6526. // Realloc the array
  6527. CHECKHR(hr = HrRealloc((LPVOID *)&pList->prgAdr, sizeof(ADDRESSPROPS) * (cAlloc + 5)));
  6528. // Increment alloc size
  6529. cAlloc += 5;
  6530. }
  6531. // Readability
  6532. pAddress = &pList->prgAdr[pList->cAdrs];
  6533. // Init
  6534. ZeroMemory(pAddress, sizeof(*pAddress));
  6535. IF_NULLEXIT(pAddress->pszFriendlyW = StrDupW(cAdrParse.PszFriendly()));
  6536. IF_NULLEXIT(pAddress->pszFriendly = PszToANSI(CP_ACP, pAddress->pszFriendlyW));
  6537. // Copy the Email Name
  6538. CHECKALLOC(pAddress->pszEmail = PszToANSI(CP_ACP, cAdrParse.PszEmail()));
  6539. // Charset
  6540. if (rRfc1522Info.hRfc1522Cset)
  6541. {
  6542. pAddress->hCharset = rRfc1522Info.hRfc1522Cset;
  6543. FLAGSET(pAddress->dwProps, IAP_CHARSET);
  6544. }
  6545. // Encoding
  6546. pAddress->ietFriendly = IET_DECODED;
  6547. // Set Property Mask
  6548. FLAGSET(pAddress->dwProps, IAP_FRIENDLY | IAP_EMAIL | IAP_ENCODING | IAP_FRIENDLYW);
  6549. // Increment Count
  6550. pList->cAdrs++;
  6551. }
  6552. exit:
  6553. // Failure
  6554. if (FAILED(hr))
  6555. g_pMoleAlloc->FreeAddressList(pList);
  6556. // Done
  6557. return hr;
  6558. }
  6559. // ----------------------------------------------------------------------------
  6560. // CMimePropertyContainer::Clone
  6561. // ----------------------------------------------------------------------------
  6562. STDMETHODIMP CMimePropertyContainer::Clone(IMimeAddressTable **ppTable)
  6563. {
  6564. // Locals
  6565. HRESULT hr=S_OK;
  6566. LPCONTAINER pContainer=NULL;
  6567. // InvalidArg
  6568. if (NULL == ppTable)
  6569. return TrapError(E_INVALIDARG);
  6570. // Init
  6571. *ppTable = NULL;
  6572. // Thread Safety
  6573. EnterCriticalSection(&m_cs);
  6574. // Ask the container to clone itself
  6575. CHECKHR(hr = Clone(&pContainer));
  6576. // Bind to the IID_IMimeHeaderTable View
  6577. CHECKHR(hr = pContainer->QueryInterface(IID_IMimeAddressTable, (LPVOID *)ppTable));
  6578. exit:
  6579. // Cleanup
  6580. SafeRelease(pContainer);
  6581. // Thread Safety
  6582. LeaveCriticalSection(&m_cs);
  6583. // Done
  6584. return hr;
  6585. }
  6586. // --------------------------------------------------------------------------------
  6587. // CMimePropertyContainer::HrGenerateFileName
  6588. // --------------------------------------------------------------------------------
  6589. HRESULT CMimePropertyContainer::_HrGenerateFileName(LPCWSTR pszSuggest, DWORD dwFlags, LPMIMEVARIANT pValue)
  6590. {
  6591. // Locals
  6592. HRESULT hr=S_OK;
  6593. LPWSTR pszDefExt=NULL;
  6594. LPWSTR pszData=NULL;
  6595. LPWSTR pszFree=NULL;
  6596. LPCSTR pszCntType=NULL;
  6597. LPPROPERTY pProperty;
  6598. MIMEVARIANT rSource;
  6599. // Compute Content Type
  6600. pszCntType = PSZDEFPROPSTRINGA(m_prgIndex[PID_HDR_CNTTYPE], STR_MIME_TEXT_PLAIN);
  6601. // No suggestion yet
  6602. if (NULL == pszSuggest)
  6603. {
  6604. // Get as Unicode
  6605. rSource.type = MVT_STRINGW;
  6606. // Compute Subject as suggested base file name...
  6607. if (SUCCEEDED(GetProp(SYM_HDR_SUBJECT, 0, &rSource)))
  6608. {
  6609. // Save as new suggest and free it later
  6610. pszSuggest = pszFree = rSource.rStringW.pszVal;
  6611. }
  6612. // If still nothing, then get the content-description header
  6613. if (NULL == pszSuggest)
  6614. {
  6615. // Get Content-Description as unicode
  6616. if (SUCCEEDED(GetProp(SYM_HDR_CNTDESC, 0, &rSource)))
  6617. {
  6618. // Save as new suggest and free it later
  6619. pszSuggest = pszFree = rSource.rStringW.pszVal;
  6620. }
  6621. }
  6622. }
  6623. // message/rfc822
  6624. if (lstrcmpi(pszCntType, (LPSTR)STR_MIME_MSG_RFC822) == 0)
  6625. {
  6626. // If there is a news header, use c_szDotNws
  6627. if (ISFLAGSET(m_dwState, COSTATE_RFC822NEWS))
  6628. pszDefExt = (LPWSTR)c_wszDotNws;
  6629. else
  6630. pszDefExt = (LPWSTR)c_wszDotEml;
  6631. // I will never lookup message/rfc822 extension
  6632. pszCntType = NULL;
  6633. }
  6634. // message/disposition-notification
  6635. else if (lstrcmpi(pszCntType, "message/disposition-notification") == 0)
  6636. pszDefExt = (LPWSTR)c_wszDotTxt;
  6637. // Still no default
  6638. else if (StrCmpNI(pszCntType, STR_CNT_TEXT, lstrlen(STR_CNT_TEXT)) == 0)
  6639. pszDefExt = (LPWSTR)c_wszDotTxt;
  6640. // Generate a filename based on the content type...
  6641. CHECKHR(hr = MimeOleGenerateFileNameW(pszCntType, pszSuggest, pszDefExt, &pszData));
  6642. // Setup rSource
  6643. ZeroMemory(&rSource, sizeof(MIMEVARIANT));
  6644. rSource.type = MVT_STRINGW;
  6645. rSource.rStringW.pszVal = pszData;
  6646. rSource.rStringW.cchVal = lstrlenW(pszData);
  6647. // Return per user request
  6648. CHECKHR(hr = HrConvertVariant(SYM_ATT_GENFNAME, NULL, IET_DECODED, dwFlags, 0, &rSource, pValue));
  6649. exit:
  6650. // Cleanup
  6651. SafeMemFree(pszData);
  6652. SafeMemFree(pszFree);
  6653. // Done
  6654. return hr;
  6655. }
  6656. #endif // !WIN16