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.

1074 lines
32 KiB

  1. // --------------------------------------------------------------------------------
  2. // Symcache.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // --------------------------------------------------------------------------------
  5. #include "pch.hxx"
  6. #include "symcache.h"
  7. #include "containx.h"
  8. #include "stackstr.h"
  9. #ifndef MAC
  10. #include <shlwapi.h>
  11. #endif // !MAC
  12. #include "demand.h"
  13. #include "qstrcmpi.h"
  14. // --------------------------------------------------------------------------------
  15. // Array of Pointers to known property symbols. This array's order defines the
  16. // header row order in which headers will be saved.
  17. // --------------------------------------------------------------------------------
  18. static const LPPROPSYMBOL g_prgKnownSymbol[] = {
  19. { SYM_HDR_RECEIVED },
  20. { SYM_HDR_RETURNPATH },
  21. { SYM_HDR_RETRCPTTO },
  22. { SYM_HDR_RR },
  23. { SYM_HDR_REPLYTO },
  24. { SYM_HDR_APPARTO },
  25. { SYM_HDR_FROM },
  26. { SYM_HDR_SENDER },
  27. { SYM_HDR_TO },
  28. { SYM_HDR_CC },
  29. { SYM_HDR_BCC },
  30. { SYM_HDR_NEWSGROUPS },
  31. { SYM_HDR_PATH },
  32. { SYM_HDR_FOLLOWUPTO },
  33. { SYM_HDR_REFS },
  34. { SYM_HDR_SUBJECT },
  35. { SYM_HDR_DATE },
  36. { SYM_HDR_EXPIRES },
  37. { SYM_HDR_CONTROL },
  38. { SYM_HDR_DISTRIB },
  39. { SYM_HDR_KEYWORDS },
  40. { SYM_HDR_SUMMARY },
  41. { SYM_HDR_APPROVED },
  42. { SYM_HDR_LINES },
  43. { SYM_HDR_XREF },
  44. { SYM_HDR_ORG },
  45. { SYM_HDR_COMMENT },
  46. { SYM_HDR_ENCODING },
  47. { SYM_HDR_ENCRYPTED },
  48. { SYM_HDR_OFFSETS },
  49. { SYM_ATT_FILENAME },
  50. { SYM_ATT_GENFNAME },
  51. { SYM_PAR_BOUNDARY },
  52. { SYM_PAR_CHARSET },
  53. { SYM_PAR_NAME },
  54. { SYM_PAR_FILENAME },
  55. { SYM_ATT_PRITYPE },
  56. { SYM_ATT_SUBTYPE },
  57. { SYM_ATT_NORMSUBJ },
  58. { SYM_ATT_ILLEGAL },
  59. { SYM_HDR_MESSAGEID },
  60. { SYM_HDR_MIMEVER },
  61. { SYM_HDR_CNTTYPE },
  62. { SYM_HDR_CNTXFER },
  63. { SYM_HDR_CNTID },
  64. { SYM_HDR_CNTDESC },
  65. { SYM_HDR_CNTDISP },
  66. { SYM_HDR_CNTBASE },
  67. { SYM_HDR_CNTLOC },
  68. { SYM_ATT_RENDERED },
  69. { SYM_ATT_SENTTIME },
  70. { SYM_ATT_RECVTIME },
  71. { SYM_ATT_PRIORITY },
  72. { SYM_HDR_ARTICLEID },
  73. { SYM_HDR_NEWSGROUP },
  74. { SYM_HDR_XPRI },
  75. { SYM_HDR_XMSPRI },
  76. { SYM_HDR_XMAILER },
  77. { SYM_HDR_XNEWSRDR },
  78. { SYM_HDR_XUNSENT },
  79. { SYM_ATT_SERVER },
  80. { SYM_ATT_ACCOUNTID },
  81. { SYM_ATT_UIDL },
  82. { SYM_ATT_STOREMSGID },
  83. { SYM_ATT_USERNAME },
  84. { SYM_ATT_FORWARDTO },
  85. { SYM_ATT_STOREFOLDERID },
  86. { SYM_ATT_GHOSTED },
  87. { SYM_ATT_UNCACHEDSIZE },
  88. { SYM_ATT_COMBINED },
  89. { SYM_ATT_AUTOINLINED },
  90. { SYM_HDR_DISP_NOTIFICATION_TO }
  91. };
  92. // --------------------------------------------------------------------------------
  93. // Address Types To Property Symbol Mapping Table (Clients can register types)
  94. // --------------------------------------------------------------------------------
  95. static ADDRSYMBOL g_prgAddrSymbol[32] = {
  96. { IAT_FROM, SYM_HDR_FROM },
  97. { IAT_SENDER, SYM_HDR_SENDER },
  98. { IAT_TO, SYM_HDR_TO },
  99. { IAT_CC, SYM_HDR_CC },
  100. { IAT_BCC, SYM_HDR_BCC },
  101. { IAT_REPLYTO, SYM_HDR_REPLYTO },
  102. { IAT_RETURNPATH, SYM_HDR_RETURNPATH },
  103. { IAT_RETRCPTTO, SYM_HDR_RETRCPTTO },
  104. { IAT_RR, SYM_HDR_RR },
  105. { IAT_APPARTO, SYM_HDR_APPARTO },
  106. { IAT_DISP_NOTIFICATION_TO, SYM_HDR_DISP_NOTIFICATION_TO},
  107. { FLAG12, NULL },
  108. { FLAG13, NULL },
  109. { FLAG14, NULL },
  110. { FLAG15, NULL },
  111. { FLAG16, NULL },
  112. { FLAG17, NULL },
  113. { FLAG18, NULL },
  114. { FLAG19, NULL },
  115. { FLAG20, NULL },
  116. { FLAG21, NULL },
  117. { FLAG22, NULL },
  118. { FLAG23, NULL },
  119. { FLAG24, NULL },
  120. { FLAG25, NULL },
  121. { FLAG26, NULL },
  122. { FLAG27, NULL },
  123. { FLAG28, NULL },
  124. { FLAG29, NULL },
  125. { FLAG30, NULL },
  126. { FLAG31, NULL },
  127. { FLAG32, NULL }
  128. };
  129. // --------------------------------------------------------------------------------
  130. // CPropertySymbolCache::CPropertySymbolCache
  131. // --------------------------------------------------------------------------------
  132. CPropertySymbolCache::CPropertySymbolCache(void)
  133. {
  134. m_cRef = 1;
  135. m_dwNextPropId = PID_LAST;
  136. m_cSymbolsInit = 0;
  137. ZeroMemory(&m_rTable, sizeof(m_rTable));
  138. ZeroMemory(m_prgIndex, sizeof(m_prgIndex));
  139. }
  140. // --------------------------------------------------------------------------------
  141. // CPropertySymbolCache::CPropertySymbolCache
  142. // --------------------------------------------------------------------------------
  143. CPropertySymbolCache::~CPropertySymbolCache(void)
  144. {
  145. DebugTrace("MimeOLE - CPropertySymbolCache %d Symbols in Cache.\n", m_rTable.cSymbols);
  146. _FreeTableElements();
  147. }
  148. // --------------------------------------------------------------------------------
  149. // CPropertySymbolCache::QueryInterface
  150. // --------------------------------------------------------------------------------
  151. STDMETHODIMP CPropertySymbolCache::QueryInterface(REFIID riid, LPVOID *ppv)
  152. {
  153. // check params
  154. if (ppv == NULL)
  155. return TrapError(E_INVALIDARG);
  156. // Find IID
  157. if (IID_IUnknown == riid)
  158. *ppv = (IUnknown *)this;
  159. else if (IID_IMimePropertySchema == riid)
  160. *ppv = (IMimePropertySchema *)this;
  161. else
  162. {
  163. *ppv = NULL;
  164. return TrapError(E_NOINTERFACE);
  165. }
  166. // AddRef It
  167. ((IUnknown *)*ppv)->AddRef();
  168. // Done
  169. return S_OK;
  170. }
  171. // --------------------------------------------------------------------------------
  172. // CPropertySymbolCache::AddRef
  173. // --------------------------------------------------------------------------------
  174. STDMETHODIMP_(ULONG) CPropertySymbolCache::AddRef(void)
  175. {
  176. return (ULONG)InterlockedIncrement(&m_cRef);
  177. }
  178. // --------------------------------------------------------------------------------
  179. // CPropertySymbolCache::Release
  180. // --------------------------------------------------------------------------------
  181. STDMETHODIMP_(ULONG) CPropertySymbolCache::Release(void)
  182. {
  183. LONG cRef = InterlockedDecrement(&m_cRef);
  184. if (0 == cRef)
  185. delete this;
  186. return (ULONG)cRef;
  187. }
  188. // --------------------------------------------------------------------------------
  189. // CPropertySymbolCache::GetPropertyId
  190. // --------------------------------------------------------------------------------
  191. STDMETHODIMP CPropertySymbolCache::GetPropertyId(LPCSTR pszName, LPDWORD pdwPropId)
  192. {
  193. // Locals
  194. HRESULT hr=S_OK;
  195. LPPROPSYMBOL pSymbol;
  196. // Invalid Args
  197. if (NULL == pszName || NULL == pdwPropId)
  198. return TrapError(E_INVALIDARG);
  199. // Find the Property By Name
  200. CHECKHR(hr = HrOpenSymbol(pszName, FALSE, &pSymbol));
  201. // Return the Id
  202. *pdwPropId = pSymbol->dwPropId;
  203. exit:
  204. // Done
  205. return hr;
  206. }
  207. // --------------------------------------------------------------------------------
  208. // CPropertySymbolCache::GetPropertyName
  209. // --------------------------------------------------------------------------------
  210. STDMETHODIMP CPropertySymbolCache::GetPropertyName(DWORD dwPropId, LPSTR *ppszName)
  211. {
  212. // Locals
  213. HRESULT hr=S_OK;
  214. LPPROPSYMBOL pSymbol;
  215. // Invalid Args
  216. if (NULL == ppszName)
  217. return TrapError(E_INVALIDARG);
  218. // Find the Property By Name
  219. CHECKHR(hr = HrOpenSymbol(PIDTOSTR(dwPropId), FALSE, &pSymbol));
  220. // Return the Id
  221. CHECKALLOC(*ppszName = PszDupA(pSymbol->pszName));
  222. exit:
  223. // Done
  224. return hr;
  225. }
  226. // --------------------------------------------------------------------------------
  227. // CPropertySymbolCache::RegisterProperty
  228. // --------------------------------------------------------------------------------
  229. STDMETHODIMP CPropertySymbolCache::RegisterProperty(LPCSTR pszName, DWORD dwFlags,
  230. DWORD dwRowNumber, VARTYPE vtDefault, LPDWORD pdwPropId)
  231. {
  232. // Locals
  233. HRESULT hr=S_OK;
  234. LPPROPSYMBOL pSymbol;
  235. // Invalid Args
  236. if (NULL == pszName)
  237. return TrapError(E_INVALIDARG);
  238. // Is Supported VARTYPE
  239. if (ISSUPPORTEDVT(vtDefault) == FALSE)
  240. return TrapError(MIME_E_UNSUPPORTED_VARTYPE);
  241. // Thread Safety
  242. m_lock.ExclusiveLock();
  243. // Validate the dwFlags
  244. CHECKHR(hr = HrIsValidPropFlags(dwFlags));
  245. // Already Exist ?
  246. CHECKHR(hr = _HrOpenSymbolWithLockOption(pszName, TRUE, &pSymbol,FALSE));
  247. // If MPF_ADDRESS flag is not equal to what the symbol already has, this is an error
  248. if (ISFLAGSET(dwFlags, MPF_ADDRESS) != ISFLAGSET(pSymbol->dwFlags, MPF_ADDRESS))
  249. {
  250. hr = TrapError(E_FAIL);
  251. goto exit;
  252. }
  253. // Change the Flags
  254. pSymbol->dwFlags = dwFlags;
  255. // Change the row number
  256. pSymbol->dwRowNumber = ((dwRowNumber == 0) ? 1 : dwRowNumber);
  257. // Save the Default Data Type
  258. pSymbol->vtDefault = vtDefault;
  259. // Return the Property Id
  260. if (pdwPropId)
  261. *pdwPropId = pSymbol->dwPropId;
  262. exit:
  263. // Thread Safety
  264. m_lock.ExclusiveUnlock();
  265. // Done
  266. return hr;
  267. }
  268. // --------------------------------------------------------------------------------
  269. // CPropertySymbolCache::ModifyProperty
  270. // --------------------------------------------------------------------------------
  271. STDMETHODIMP CPropertySymbolCache::ModifyProperty(LPCSTR pszName, DWORD dwFlags, DWORD dwRowNumber,
  272. VARTYPE vtDefault)
  273. {
  274. // Locals
  275. HRESULT hr=S_OK;
  276. LPPROPSYMBOL pSymbol;
  277. // Invalid Args
  278. if (NULL == pszName)
  279. return TrapError(E_INVALIDARG);
  280. // Is Supported VARTYPE
  281. if (ISSUPPORTEDVT(vtDefault) == FALSE)
  282. return TrapError(MIME_E_UNSUPPORTED_VARTYPE);
  283. // Thread Safety
  284. m_lock.ExclusiveLock();
  285. // Validate the dwFlags
  286. CHECKHR(hr = HrIsValidPropFlags(dwFlags));
  287. // Find the Property By Name
  288. CHECKHR(hr = _HrOpenSymbolWithLockOption(pszName, FALSE, &pSymbol,FALSE));
  289. // If MPF_ADDRESS flag is not equal to what the symbol already has, this is an error
  290. if (ISFLAGSET(dwFlags, MPF_ADDRESS) != ISFLAGSET(pSymbol->dwFlags, MPF_ADDRESS))
  291. {
  292. hr = TrapError(E_FAIL);
  293. goto exit;
  294. }
  295. // Change the Flags
  296. pSymbol->dwFlags = dwFlags;
  297. // Change the row number
  298. pSymbol->dwRowNumber = ((dwRowNumber == 0) ? 1 : dwRowNumber);
  299. // Save the Default Data Type
  300. pSymbol->vtDefault = vtDefault;
  301. exit:
  302. // Thread Safety
  303. m_lock.ExclusiveUnlock();
  304. // Done
  305. return hr;
  306. }
  307. // --------------------------------------------------------------------------------
  308. // CPropertySymbolCache::RegisterAddressType
  309. // --------------------------------------------------------------------------------
  310. STDMETHODIMP CPropertySymbolCache::RegisterAddressType(LPCSTR pszName, LPDWORD pdwAdrType)
  311. {
  312. // Locals
  313. HRESULT hr=S_OK;
  314. LPPROPSYMBOL pSymbol;
  315. // Invalid Args
  316. if (NULL == pszName || NULL == pdwAdrType)
  317. return TrapError(E_INVALIDARG);
  318. // Thread Safety
  319. m_lock.ExclusiveLock();
  320. // Already Exist ?
  321. CHECKHR(hr = _HrOpenSymbolWithLockOption(pszName, TRUE, &pSymbol,FALSE));
  322. // If pSymbol already has an address type ?
  323. if (ISFLAGSET(pSymbol->dwFlags, MPF_ADDRESS))
  324. {
  325. // Better have a known address type
  326. Assert(IAT_UNKNOWN != pSymbol->dwAdrType);
  327. // Return the Address Type
  328. *pdwAdrType = pSymbol->dwAdrType;
  329. }
  330. // Otherwise
  331. else
  332. {
  333. // Better have an unknown address type
  334. Assert(IAT_UNKNOWN == pSymbol->dwAdrType);
  335. // Find the first empty cell in the address type table
  336. for (ULONG i=0; i<ARRAYSIZE(g_prgAddrSymbol); i++)
  337. {
  338. // Empty ?
  339. if (NULL == g_prgAddrSymbol[i].pSymbol)
  340. {
  341. // Put the symbol into the address table
  342. g_prgAddrSymbol[i].pSymbol = pSymbol;
  343. // Put the address type into the symbol
  344. pSymbol->dwAdrType = g_prgAddrSymbol[i].dwAdrType;
  345. // Add the MPF_ADDRESS flag onto the symbol
  346. FLAGSET(pSymbol->dwFlags, MPF_ADDRESS);
  347. // Return the Address Type
  348. *pdwAdrType = pSymbol->dwAdrType;
  349. // Done
  350. goto exit;
  351. }
  352. }
  353. // Error
  354. hr = TrapError(MIME_E_NO_MORE_ADDRESS_TYPES);
  355. goto exit;
  356. }
  357. exit:
  358. // Thread Safety
  359. m_lock.ExclusiveUnlock();
  360. // Done
  361. return hr;
  362. }
  363. // --------------------------------------------------------------------------------
  364. // CPropertySymbolCache::_FreeTableElements
  365. // --------------------------------------------------------------------------------
  366. void CPropertySymbolCache::_FreeTableElements(void)
  367. {
  368. // Thread Safety
  369. m_lock.ExclusiveLock();
  370. // May not actually exist yet...
  371. if (m_rTable.prgpSymbol)
  372. {
  373. // Loop through the items...
  374. for (ULONG i=0; i<m_rTable.cSymbols; i++)
  375. _FreeSymbol(m_rTable.prgpSymbol[i]);
  376. // Free the array
  377. SafeMemFree(m_rTable.prgpSymbol);
  378. // Zero It
  379. ZeroMemory(&m_rTable, sizeof(SYMBOLTABLE));
  380. }
  381. // Thread Safety
  382. m_lock.ExclusiveUnlock();
  383. }
  384. // ---------------------------------------------------------------------------
  385. // CPropertySymbolCache::_FreeSymbol
  386. // ---------------------------------------------------------------------------
  387. void CPropertySymbolCache::_FreeSymbol(LPPROPSYMBOL pSymbol)
  388. {
  389. // If Not a Known Property, free the pTag Structure...
  390. if (pSymbol && ISFLAGSET(pSymbol->dwFlags, MPF_KNOWN) == FALSE)
  391. {
  392. // Free Property Name
  393. SafeMemFree(pSymbol->pszName);
  394. // Free Global Prop
  395. SafeMemFree(pSymbol);
  396. }
  397. }
  398. // --------------------------------------------------------------------------------
  399. // CPropertySymbolCache::HrOpenSymbol
  400. // --------------------------------------------------------------------------------
  401. HRESULT CPropertySymbolCache::HrOpenSymbol(DWORD dwAdrType, LPPROPSYMBOL *ppSymbol)
  402. {
  403. // Locals
  404. HRESULT hr=S_OK;
  405. DWORD dw=dwAdrType;
  406. ULONG iAddress=0;
  407. // Invalid Arg
  408. Assert(dwAdrType && dwAdrType <= FLAG32);
  409. if (0 == dwAdrType || dwAdrType > FLAG32 || NULL == ppSymbol)
  410. return TrapError(E_INVALIDARG);
  411. // Init
  412. *ppSymbol = NULL;
  413. // Thread Safety
  414. m_lock.ShareLock();
  415. // Initialized Yet
  416. Assert(m_rTable.prgpSymbol);
  417. // Compute index into g_prgAddrSymbol
  418. while(dw)
  419. {
  420. dw = dw >> 1;
  421. iAddress++;
  422. }
  423. // Decrement one
  424. iAddress--;
  425. // iAddress Out of Range
  426. if (iAddress >= 32)
  427. {
  428. hr = TrapError(E_FAIL);
  429. goto exit;
  430. }
  431. // Get the Symbol
  432. if (NULL == g_prgAddrSymbol[iAddress].pSymbol)
  433. {
  434. hr = TrapError(MIME_E_NOT_FOUND);
  435. goto exit;
  436. }
  437. // Return it
  438. *ppSymbol = g_prgAddrSymbol[iAddress].pSymbol;
  439. Assert((*ppSymbol)->dwAdrType == dwAdrType);
  440. exit:
  441. // Thread Safety
  442. m_lock.ShareUnlock();
  443. // Done
  444. return hr;
  445. }
  446. // --------------------------------------------------------------------------------
  447. // CPropertySymbolCache::HrOpenSymbol
  448. // --------------------------------------------------------------------------------
  449. HRESULT CPropertySymbolCache::HrOpenSymbol(LPCSTR pszName, BOOL fCreate, LPPROPSYMBOL *ppSymbol)
  450. {
  451. return(_HrOpenSymbolWithLockOption(pszName,fCreate,ppSymbol,TRUE)); //call with lockOption=TRUE
  452. }
  453. // --------------------------------------------------------------------------------
  454. // CPropertySymbolCache::_HrOpenSymbolWithLockOption
  455. // --------------------------------------------------------------------------------
  456. HRESULT CPropertySymbolCache::_HrOpenSymbolWithLockOption(LPCSTR pszName, BOOL fCreate, LPPROPSYMBOL *ppSymbol,BOOL fLockOption)
  457. {
  458. // Locals
  459. HRESULT hr=S_OK;
  460. DWORD dwFlags;
  461. ULONG cchName;
  462. LPPROPSYMBOL pSymbol=NULL;
  463. LPPROPSYMBOL pLink=NULL;
  464. BOOL fExcLock; //flag used to define which unlock to use
  465. fExcLock = FALSE;
  466. // Invalid Arg
  467. if (NULL == pszName || NULL == ppSymbol)
  468. return TrapError(E_INVALIDARG);
  469. // Init
  470. *ppSymbol = NULL;
  471. if(TRUE == fLockOption)
  472. // Thread Safety
  473. m_lock.ShareLock();
  474. // Initialized Yet
  475. Assert(m_rTable.prgpSymbol);
  476. // If property tag exist, return it
  477. if (SUCCEEDED(_HrFindSymbol(pszName, ppSymbol)))
  478. goto exit;
  479. // Don't Create...
  480. if (FALSE == fCreate || ISPIDSTR(pszName))
  481. {
  482. hr = MIME_E_NOT_FOUND;
  483. goto exit;
  484. }
  485. //This part is added to convert the lock to Exclusive
  486. //if the symbol is not found in the cache
  487. if(TRUE == fLockOption)
  488. {
  489. fExcLock = TRUE;
  490. if(FALSE == m_lock.SharedToExclusive())
  491. {
  492. //if the attempt at conversion does not
  493. //succeed tryu to do it by explicitly
  494. m_lock.ShareUnlock(); //Release the Sharelock before
  495. m_lock.ExclusiveLock(); //getting the exclusive lock
  496. //during the change of lock the cache might have changed
  497. //check it again
  498. if (SUCCEEDED(_HrFindSymbol(pszName, ppSymbol)))
  499. goto exit;
  500. }
  501. }
  502. // Get the length of the name
  503. cchName = lstrlen(pszName);
  504. // MPF_PARAMETER
  505. if (StrCmpNI(pszName, "par:", 4) == 0)
  506. {
  507. // Its a parameter
  508. dwFlags = MPF_PARAMETER;
  509. // I need to locate pLink (the root header of this parameter)
  510. CHECKHR(hr = _HrGetParameterLinkSymbolWithLockOption(pszName, cchName, &pLink,FALSE));
  511. }
  512. // MPF_ATTRIBUTE
  513. else if (StrCmpNI(pszName, "att:", 4) == 0)
  514. dwFlags = MPF_ATTRIBUTE;
  515. // MPF_HEADER
  516. else
  517. {
  518. dwFlags = MPF_HEADER;
  519. // validate each character in the name against rfc (no :, or spaces)
  520. LPSTR psz = (LPSTR)pszName;
  521. while(*psz)
  522. {
  523. // Invalid Chars
  524. if ('.' == *psz || ' ' == *psz || '\t' == *psz || chCR == *psz || chLF == *psz || ':' == *psz)
  525. {
  526. hr = MIME_E_INVALID_HEADER_NAME;
  527. goto exit;
  528. }
  529. // Next
  530. psz++;
  531. }
  532. }
  533. // Do I need to replace an item...
  534. if (m_rTable.cSymbols + 1 > m_rTable.cAlloc)
  535. {
  536. // Reallocate the array
  537. CHECKHR(hr = HrRealloc((LPVOID *)&m_rTable.prgpSymbol, sizeof(LPPROPSYMBOL) * (m_rTable.cAlloc + 10)));
  538. // Increment
  539. m_rTable.cAlloc += 10;
  540. }
  541. // Allocate a new propinfo struct
  542. CHECKALLOC(pSymbol = (LPPROPSYMBOL)g_pMalloc->Alloc(sizeof(PROPSYMBOL)));
  543. // Zero
  544. ZeroMemory(pSymbol, sizeof(PROPSYMBOL));
  545. // Copy Name
  546. CHECKALLOC(pSymbol->pszName = (LPSTR)g_pMalloc->Alloc(cchName + 1));
  547. // Copy
  548. CopyMemory(pSymbol->pszName, pszName, cchName + 1);
  549. // Copy Other Data
  550. pSymbol->cchName = cchName;
  551. pSymbol->dwFlags = dwFlags;
  552. pSymbol->dwSort = m_rTable.cSymbols;
  553. pSymbol->dwRowNumber = m_rTable.cSymbols + 1;
  554. pSymbol->vtDefault = VT_LPSTR;
  555. pSymbol->dwAdrType = IAT_UNKNOWN;
  556. pSymbol->pLink = pLink;
  557. // Compute the property Id
  558. pSymbol->dwPropId = m_dwNextPropId++;
  559. // Compute Hash Value
  560. pSymbol->wHashIndex = (WORD)(pSymbol->dwPropId % CBUCKETS);
  561. // Save item into array
  562. m_rTable.prgpSymbol[m_rTable.cSymbols] = pSymbol;
  563. // Increment count
  564. m_rTable.cSymbols++;
  565. // Resort the array
  566. _SortTableElements(0, m_rTable.cSymbols - 1);
  567. // Set Handle
  568. *ppSymbol = pSymbol;
  569. // Make sure we can still actually find it by property id
  570. #ifdef DEBUG
  571. LPPROPSYMBOL pDebug;
  572. Assert(SUCCEEDED(_HrOpenSymbolWithLockOption(PIDTOSTR(pSymbol->dwPropId), FALSE, &pDebug,FALSE)));
  573. #endif
  574. exit:
  575. // Failure
  576. if (FAILED(hr) && pSymbol)
  577. _FreeSymbol(pSymbol);
  578. if(TRUE == fLockOption)
  579. {
  580. // Thread Safety
  581. if(TRUE==fExcLock)
  582. m_lock.ExclusiveUnlock();
  583. else
  584. m_lock.ShareUnlock();
  585. }
  586. // Done
  587. return hr;
  588. }
  589. // --------------------------------------------------------------------------------
  590. // CPropertySymbolCache::_HrGetParameterLinkSymbol
  591. // --------------------------------------------------------------------------------
  592. HRESULT CPropertySymbolCache::_HrGetParameterLinkSymbol(LPCSTR pszName, ULONG cchName, LPPROPSYMBOL *ppSymbol)
  593. {
  594. return(_HrGetParameterLinkSymbolWithLockOption(pszName,cchName,ppSymbol,TRUE)); //call with LockOption=TRUE
  595. }
  596. // --------------------------------------------------------------------------------
  597. // CPropertySymbolCache::_HrGetParameterLinkSymbolWithLockOption
  598. // --------------------------------------------------------------------------------
  599. HRESULT CPropertySymbolCache::_HrGetParameterLinkSymbolWithLockOption(LPCSTR pszName, ULONG cchName, LPPROPSYMBOL *ppSymbol,BOOL fLockOption)
  600. {
  601. // Locals
  602. HRESULT hr=S_OK;
  603. LPSTR pszStart;
  604. LPSTR pszEnd;
  605. ULONG cchHeader=0;
  606. // Invalid Arg
  607. Assert(pszName && ':' == pszName[3] && ppSymbol);
  608. // Stack String
  609. STACKSTRING_DEFINE(rHeader, 255);
  610. // Find first semicolon
  611. pszEnd = (LPSTR)(pszName + 4);
  612. while (*pszEnd && ':' != *pszEnd)
  613. {
  614. pszEnd++;
  615. cchHeader++;
  616. }
  617. // Set the name
  618. STACKSTRING_SETSIZE(rHeader, cchHeader+1);
  619. // Copy It
  620. CopyMemory(rHeader.pszVal, (LPBYTE)(pszName + 4), cchHeader);
  621. *(rHeader.pszVal + cchHeader) = '\0';
  622. // Find the Symbol
  623. CHECKHR(hr = _HrOpenSymbolWithLockOption(rHeader.pszVal, TRUE, ppSymbol,fLockOption));
  624. exit:
  625. // Cleanup
  626. STACKSTRING_FREE(rHeader);
  627. // Done
  628. return hr;
  629. }
  630. // --------------------------------------------------------------------------------
  631. // CPropertySymbolCache::_HrFindSymbol
  632. // --------------------------------------------------------------------------------
  633. HRESULT CPropertySymbolCache::_HrFindSymbol(LPCSTR pszName, LPPROPSYMBOL *ppSymbol)
  634. {
  635. // Locals
  636. HRESULT hr=S_OK;
  637. LPPROPSYMBOL pSymbol=NULL;
  638. DWORD dwPropId;
  639. // Invalid Arg
  640. Assert(ppSymbol);
  641. // If this is a known property tag...
  642. if (ISPIDSTR(pszName))
  643. {
  644. // Cast the dwPropId
  645. dwPropId = STRTOPID(pszName);
  646. // Set Symbol
  647. if (ISKNOWNPID(dwPropId))
  648. {
  649. // De-ref into known property index (ordered differently than g_prgKnownProps)
  650. pSymbol = m_prgIndex[dwPropId];
  651. }
  652. // Otherwise, must be an unknown pid index
  653. else
  654. {
  655. // I need to re-align dwPropId because it starts at PID_LAST and my not be a direct index
  656. // into the symbol table since the symbol table is not initialized with PID_LAST properties
  657. dwPropId -= (PID_LAST - ARRAYSIZE(g_prgKnownSymbol));
  658. // Must be >= PID_LAST and < m_rTable.cSymbols
  659. if (dwPropId >= m_cSymbolsInit && dwPropId < m_rTable.cSymbols)
  660. {
  661. // dwPropId is an index into the symbol table
  662. pSymbol = m_rTable.prgpSymbol[dwPropId];
  663. Assert(pSymbol);
  664. }
  665. // Else
  666. else
  667. AssertSz(FALSE, "How did you get an invalid unknown property id?");
  668. }
  669. }
  670. // Otherwise, look for it by name
  671. else
  672. {
  673. // Locals
  674. LONG lUpper, lLower, lMiddle, nCompare;
  675. ULONG i;
  676. // Set lLower and lUpper
  677. lLower = 0;
  678. lUpper = m_rTable.cSymbols - 1;
  679. // Do binary search / insert
  680. while (lLower <= lUpper)
  681. {
  682. // Compute middle record to compare against
  683. lMiddle = (LONG)((lLower + lUpper) / 2);
  684. // Get string to compare against
  685. i = m_rTable.prgpSymbol[lMiddle]->dwSort;
  686. // Do compare
  687. nCompare = OEMstrcmpi(pszName, m_rTable.prgpSymbol[i]->pszName);
  688. // If Equal, then were done
  689. if (nCompare == 0)
  690. {
  691. // Set Symbol
  692. pSymbol = m_rTable.prgpSymbol[i];
  693. // Done
  694. break;
  695. }
  696. // Compute upper and lower
  697. if (nCompare > 0)
  698. lLower = lMiddle + 1;
  699. else
  700. lUpper = lMiddle - 1;
  701. }
  702. }
  703. // Not Found
  704. if (NULL == pSymbol)
  705. {
  706. hr = MIME_E_NOT_FOUND;
  707. goto exit;
  708. }
  709. // Validate PropSymbol
  710. Assert(SUCCEEDED(HrIsValidSymbol(pSymbol)));
  711. // Otherwise...
  712. *ppSymbol = pSymbol;
  713. exit:
  714. // Done
  715. return hr;
  716. }
  717. // ---------------------------------------------------------------------------
  718. // CPropertySymbolCache::Init
  719. // ---------------------------------------------------------------------------
  720. HRESULT CPropertySymbolCache::Init(void)
  721. {
  722. // Locals
  723. HRESULT hr=S_OK;
  724. ULONG i;
  725. // We should not be initialized yet
  726. Assert(NULL == m_rTable.prgpSymbol);
  727. // Thread Safety
  728. m_lock.ExclusiveLock();
  729. // Set Sizes
  730. m_rTable.cSymbols = ARRAYSIZE(g_prgKnownSymbol);
  731. m_rTable.cAlloc = m_rTable.cSymbols + 30;
  732. // Allocate the global item table
  733. CHECKHR(hr = HrAlloc((LPVOID *)&m_rTable.prgpSymbol, sizeof(LPPROPSYMBOL) * m_rTable.cAlloc));
  734. // Zero Init
  735. ZeroMemory(m_rTable.prgpSymbol, sizeof(LPPROPSYMBOL) * m_rTable.cAlloc);
  736. // Loop through known items
  737. for(i=0; i<m_rTable.cSymbols; i++)
  738. {
  739. // Just assume the global data pointer
  740. m_rTable.prgpSymbol[i] = g_prgKnownSymbol[i];
  741. // Set the sort position
  742. m_rTable.prgpSymbol[i]->dwSort = i;
  743. // Compute Hash Index
  744. m_rTable.prgpSymbol[i]->wHashIndex = (WORD)(m_rTable.prgpSymbol[i]->dwPropId % CBUCKETS);
  745. // Set the sort position
  746. m_rTable.prgpSymbol[i]->dwRowNumber = i + 1;
  747. // Put it into my index
  748. Assert(ISKNOWNPID(m_rTable.prgpSymbol[i]->dwPropId) == TRUE);
  749. // Put into symbol index
  750. m_prgIndex[m_rTable.prgpSymbol[i]->dwPropId] = m_rTable.prgpSymbol[i];
  751. }
  752. // Sort the item table...
  753. _SortTableElements(0, m_rTable.cSymbols - 1);
  754. // Save Number of Symbols initialised in the table
  755. m_cSymbolsInit = m_rTable.cSymbols;
  756. // Table Validation
  757. #ifdef DEBUG
  758. LPPROPSYMBOL pDebug;
  759. // Lets validate the table
  760. for(i=0; i<m_rTable.cSymbols; i++)
  761. {
  762. // Validate pLink
  763. if (ISFLAGSET(m_rTable.prgpSymbol[i]->dwFlags, MPF_PARAMETER))
  764. {
  765. // Locals
  766. LPPROPSYMBOL pLink;
  767. // Look for the link symbol
  768. Assert(SUCCEEDED(_HrGetParameterLinkSymbolWithLockOption(m_rTable.prgpSymbol[i]->pszName, m_rTable.prgpSymbol[i]->cchName, &pLink,FALSE)));
  769. // Validate the the computed link with the const link
  770. Assert(pLink == m_rTable.prgpSymbol[i]->pLink);
  771. }
  772. // If this has an address flag
  773. if (ISFLAGSET(m_rTable.prgpSymbol[i]->dwFlags, MPF_ADDRESS))
  774. {
  775. // Locals
  776. ULONG j;
  777. BOOL f=FALSE;
  778. // Make sure it is in the address type table
  779. for (j=0; j<ARRAYSIZE(g_prgAddrSymbol); j++)
  780. {
  781. // Found It
  782. if (m_rTable.prgpSymbol[i] == g_prgAddrSymbol[j].pSymbol)
  783. {
  784. f=TRUE;
  785. break;
  786. }
  787. }
  788. // We better have found it
  789. AssertSz(f, "A symbol has the MPF_ADDRESS flag, but is not in the address table.");
  790. }
  791. // Make sure we can still actually find it by property id
  792. Assert(SUCCEEDED(_HrOpenSymbolWithLockOption(PIDTOSTR(m_rTable.prgpSymbol[i]->dwPropId), FALSE, &pDebug,FALSE)));
  793. }
  794. #endif
  795. exit:
  796. // Thread Safety
  797. m_lock.ExclusiveUnlock();
  798. // Done
  799. return hr;
  800. }
  801. // -----------------------------------------------------------------------------
  802. // CPropertySymbolCache::_SortTableElements
  803. // -----------------------------------------------------------------------------
  804. void CPropertySymbolCache::_SortTableElements(LONG left, LONG right)
  805. {
  806. // Locals
  807. register long i, j;
  808. DWORD k, temp;
  809. i = left;
  810. j = right;
  811. k = m_rTable.prgpSymbol[(i + j) / 2]->dwSort;
  812. do
  813. {
  814. while(OEMstrcmpi(m_rTable.prgpSymbol[m_rTable.prgpSymbol[i]->dwSort]->pszName, m_rTable.prgpSymbol[k]->pszName) < 0 && i < right)
  815. i++;
  816. while (OEMstrcmpi(m_rTable.prgpSymbol[m_rTable.prgpSymbol[j]->dwSort]->pszName, m_rTable.prgpSymbol[k]->pszName) > 0 && j > left)
  817. j--;
  818. if (i <= j)
  819. {
  820. temp = m_rTable.prgpSymbol[i]->dwSort;
  821. m_rTable.prgpSymbol[i]->dwSort = m_rTable.prgpSymbol[j]->dwSort;
  822. m_rTable.prgpSymbol[j]->dwSort = temp;
  823. i++; j--;
  824. }
  825. } while (i <= j);
  826. if (left < j)
  827. _SortTableElements(left, j);
  828. if (i < right)
  829. _SortTableElements(i, right);
  830. }
  831. // --------------------------------------------------------------------------------
  832. // WGetHashTableIndex
  833. // --------------------------------------------------------------------------------
  834. WORD WGetHashTableIndex(LPCSTR pszName, ULONG cchName)
  835. {
  836. // Locals
  837. ULONG nHash=0;
  838. LONG c, j=0;
  839. ULONG i;
  840. CHAR ch;
  841. // Invalid Arg
  842. Assert(pszName && pszName[cchName] =='\0');
  843. // Compute Number of characters to hash
  844. i = cchName - 1;
  845. c = min(3, cchName);
  846. // Loop
  847. for (; j<c; j++)
  848. {
  849. ch = (CHAR)CharLower((LPSTR)(DWORD_PTR)MAKELONG(pszName[i - j], 0));
  850. nHash += (ULONG)(ch);
  851. }
  852. // Done
  853. return (WORD)(nHash % CBUCKETS);
  854. }
  855. // --------------------------------------------------------------------------------
  856. // HrIsValidSymbol
  857. // --------------------------------------------------------------------------------
  858. HRESULT HrIsValidSymbol(LPCPROPSYMBOL pSymbol)
  859. {
  860. // Validate the symbol
  861. if (NULL == pSymbol || NULL == pSymbol->pszName || '\0' != pSymbol->pszName[pSymbol->cchName])
  862. return TrapError(E_FAIL);
  863. // Validate the flags
  864. return HrIsValidPropFlags(pSymbol->dwFlags);
  865. }
  866. // --------------------------------------------------------------------------------
  867. // HrIsValidPropFlags
  868. // --------------------------------------------------------------------------------
  869. HRESULT HrIsValidPropFlags(DWORD dwFlags)
  870. {
  871. // If has parameters, it can only be a mime header property
  872. if (ISFLAGSET(dwFlags, MPF_HASPARAMS) && (!ISFLAGSET(dwFlags, MPF_MIME) || !ISFLAGSET(dwFlags, MPF_HEADER)))
  873. return TrapError(MIME_E_INVALID_PROP_FLAGS);
  874. // If not inetcset, then rfc1522 better not be set either
  875. if (!ISFLAGSET(dwFlags, MPF_INETCSET) && ISFLAGSET(dwFlags, MPF_RFC1522))
  876. return TrapError(MIME_E_INVALID_PROP_FLAGS);
  877. // If rfc1522 is set, inetset better be set
  878. if (ISFLAGSET(dwFlags, MPF_RFC1522) && !ISFLAGSET(dwFlags, MPF_INETCSET))
  879. return TrapError(MIME_E_INVALID_PROP_FLAGS);
  880. // Is either MDF_ADDRESS or MDF_HASPARAMS
  881. if (ISFLAGSET(dwFlags, MPF_ADDRESS) && ISFLAGSET(dwFlags, MPF_HASPARAMS))
  882. return TrapError(MIME_E_INVALID_PROP_FLAGS);
  883. // Done
  884. return S_OK;
  885. }