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
1074 lines
32 KiB
// --------------------------------------------------------------------------------
|
|
// Symcache.cpp
|
|
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
|
|
// --------------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "symcache.h"
|
|
#include "containx.h"
|
|
#include "stackstr.h"
|
|
#ifndef MAC
|
|
#include <shlwapi.h>
|
|
#endif // !MAC
|
|
#include "demand.h"
|
|
#include "qstrcmpi.h"
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Array of Pointers to known property symbols. This array's order defines the
|
|
// header row order in which headers will be saved.
|
|
// --------------------------------------------------------------------------------
|
|
static const LPPROPSYMBOL g_prgKnownSymbol[] = {
|
|
{ SYM_HDR_RECEIVED },
|
|
{ SYM_HDR_RETURNPATH },
|
|
{ SYM_HDR_RETRCPTTO },
|
|
{ SYM_HDR_RR },
|
|
{ SYM_HDR_REPLYTO },
|
|
{ SYM_HDR_APPARTO },
|
|
{ SYM_HDR_FROM },
|
|
{ SYM_HDR_SENDER },
|
|
{ SYM_HDR_TO },
|
|
{ SYM_HDR_CC },
|
|
{ SYM_HDR_BCC },
|
|
{ SYM_HDR_NEWSGROUPS },
|
|
{ SYM_HDR_PATH },
|
|
{ SYM_HDR_FOLLOWUPTO },
|
|
{ SYM_HDR_REFS },
|
|
{ SYM_HDR_SUBJECT },
|
|
{ SYM_HDR_DATE },
|
|
{ SYM_HDR_EXPIRES },
|
|
{ SYM_HDR_CONTROL },
|
|
{ SYM_HDR_DISTRIB },
|
|
{ SYM_HDR_KEYWORDS },
|
|
{ SYM_HDR_SUMMARY },
|
|
{ SYM_HDR_APPROVED },
|
|
{ SYM_HDR_LINES },
|
|
{ SYM_HDR_XREF },
|
|
{ SYM_HDR_ORG },
|
|
{ SYM_HDR_COMMENT },
|
|
{ SYM_HDR_ENCODING },
|
|
{ SYM_HDR_ENCRYPTED },
|
|
{ SYM_HDR_OFFSETS },
|
|
{ SYM_ATT_FILENAME },
|
|
{ SYM_ATT_GENFNAME },
|
|
{ SYM_PAR_BOUNDARY },
|
|
{ SYM_PAR_CHARSET },
|
|
{ SYM_PAR_NAME },
|
|
{ SYM_PAR_FILENAME },
|
|
{ SYM_ATT_PRITYPE },
|
|
{ SYM_ATT_SUBTYPE },
|
|
{ SYM_ATT_NORMSUBJ },
|
|
{ SYM_ATT_ILLEGAL },
|
|
{ SYM_HDR_MESSAGEID },
|
|
{ SYM_HDR_MIMEVER },
|
|
{ SYM_HDR_CNTTYPE },
|
|
{ SYM_HDR_CNTXFER },
|
|
{ SYM_HDR_CNTID },
|
|
{ SYM_HDR_CNTDESC },
|
|
{ SYM_HDR_CNTDISP },
|
|
{ SYM_HDR_CNTBASE },
|
|
{ SYM_HDR_CNTLOC },
|
|
{ SYM_ATT_RENDERED },
|
|
{ SYM_ATT_SENTTIME },
|
|
{ SYM_ATT_RECVTIME },
|
|
{ SYM_ATT_PRIORITY },
|
|
{ SYM_HDR_ARTICLEID },
|
|
{ SYM_HDR_NEWSGROUP },
|
|
{ SYM_HDR_XPRI },
|
|
{ SYM_HDR_XMSPRI },
|
|
{ SYM_HDR_XMAILER },
|
|
{ SYM_HDR_XNEWSRDR },
|
|
{ SYM_HDR_XUNSENT },
|
|
{ SYM_ATT_SERVER },
|
|
{ SYM_ATT_ACCOUNTID },
|
|
{ SYM_ATT_UIDL },
|
|
{ SYM_ATT_STOREMSGID },
|
|
{ SYM_ATT_USERNAME },
|
|
{ SYM_ATT_FORWARDTO },
|
|
{ SYM_ATT_STOREFOLDERID },
|
|
{ SYM_ATT_GHOSTED },
|
|
{ SYM_ATT_UNCACHEDSIZE },
|
|
{ SYM_ATT_COMBINED },
|
|
{ SYM_ATT_AUTOINLINED },
|
|
{ SYM_HDR_DISP_NOTIFICATION_TO }
|
|
};
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Address Types To Property Symbol Mapping Table (Clients can register types)
|
|
// --------------------------------------------------------------------------------
|
|
static ADDRSYMBOL g_prgAddrSymbol[32] = {
|
|
{ IAT_FROM, SYM_HDR_FROM },
|
|
{ IAT_SENDER, SYM_HDR_SENDER },
|
|
{ IAT_TO, SYM_HDR_TO },
|
|
{ IAT_CC, SYM_HDR_CC },
|
|
{ IAT_BCC, SYM_HDR_BCC },
|
|
{ IAT_REPLYTO, SYM_HDR_REPLYTO },
|
|
{ IAT_RETURNPATH, SYM_HDR_RETURNPATH },
|
|
{ IAT_RETRCPTTO, SYM_HDR_RETRCPTTO },
|
|
{ IAT_RR, SYM_HDR_RR },
|
|
{ IAT_APPARTO, SYM_HDR_APPARTO },
|
|
{ IAT_DISP_NOTIFICATION_TO, SYM_HDR_DISP_NOTIFICATION_TO},
|
|
{ FLAG12, NULL },
|
|
{ FLAG13, NULL },
|
|
{ FLAG14, NULL },
|
|
{ FLAG15, NULL },
|
|
{ FLAG16, NULL },
|
|
{ FLAG17, NULL },
|
|
{ FLAG18, NULL },
|
|
{ FLAG19, NULL },
|
|
{ FLAG20, NULL },
|
|
{ FLAG21, NULL },
|
|
{ FLAG22, NULL },
|
|
{ FLAG23, NULL },
|
|
{ FLAG24, NULL },
|
|
{ FLAG25, NULL },
|
|
{ FLAG26, NULL },
|
|
{ FLAG27, NULL },
|
|
{ FLAG28, NULL },
|
|
{ FLAG29, NULL },
|
|
{ FLAG30, NULL },
|
|
{ FLAG31, NULL },
|
|
{ FLAG32, NULL }
|
|
};
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::CPropertySymbolCache
|
|
// --------------------------------------------------------------------------------
|
|
CPropertySymbolCache::CPropertySymbolCache(void)
|
|
{
|
|
m_cRef = 1;
|
|
m_dwNextPropId = PID_LAST;
|
|
m_cSymbolsInit = 0;
|
|
ZeroMemory(&m_rTable, sizeof(m_rTable));
|
|
ZeroMemory(m_prgIndex, sizeof(m_prgIndex));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::CPropertySymbolCache
|
|
// --------------------------------------------------------------------------------
|
|
CPropertySymbolCache::~CPropertySymbolCache(void)
|
|
{
|
|
DebugTrace("MimeOLE - CPropertySymbolCache %d Symbols in Cache.\n", m_rTable.cSymbols);
|
|
_FreeTableElements();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::QueryInterface
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPropertySymbolCache::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
// check params
|
|
if (ppv == NULL)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Find IID
|
|
if (IID_IUnknown == riid)
|
|
*ppv = (IUnknown *)this;
|
|
else if (IID_IMimePropertySchema == riid)
|
|
*ppv = (IMimePropertySchema *)this;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return TrapError(E_NOINTERFACE);
|
|
}
|
|
|
|
// AddRef It
|
|
((IUnknown *)*ppv)->AddRef();
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::AddRef
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CPropertySymbolCache::AddRef(void)
|
|
{
|
|
return (ULONG)InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::Release
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CPropertySymbolCache::Release(void)
|
|
{
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef)
|
|
delete this;
|
|
return (ULONG)cRef;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::GetPropertyId
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPropertySymbolCache::GetPropertyId(LPCSTR pszName, LPDWORD pdwPropId)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPPROPSYMBOL pSymbol;
|
|
|
|
// Invalid Args
|
|
if (NULL == pszName || NULL == pdwPropId)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Find the Property By Name
|
|
CHECKHR(hr = HrOpenSymbol(pszName, FALSE, &pSymbol));
|
|
|
|
// Return the Id
|
|
*pdwPropId = pSymbol->dwPropId;
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::GetPropertyName
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPropertySymbolCache::GetPropertyName(DWORD dwPropId, LPSTR *ppszName)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPPROPSYMBOL pSymbol;
|
|
|
|
// Invalid Args
|
|
if (NULL == ppszName)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Find the Property By Name
|
|
CHECKHR(hr = HrOpenSymbol(PIDTOSTR(dwPropId), FALSE, &pSymbol));
|
|
|
|
// Return the Id
|
|
CHECKALLOC(*ppszName = PszDupA(pSymbol->pszName));
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::RegisterProperty
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPropertySymbolCache::RegisterProperty(LPCSTR pszName, DWORD dwFlags,
|
|
DWORD dwRowNumber, VARTYPE vtDefault, LPDWORD pdwPropId)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPPROPSYMBOL pSymbol;
|
|
|
|
// Invalid Args
|
|
if (NULL == pszName)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Is Supported VARTYPE
|
|
if (ISSUPPORTEDVT(vtDefault) == FALSE)
|
|
return TrapError(MIME_E_UNSUPPORTED_VARTYPE);
|
|
|
|
// Thread Safety
|
|
m_lock.ExclusiveLock();
|
|
|
|
// Validate the dwFlags
|
|
CHECKHR(hr = HrIsValidPropFlags(dwFlags));
|
|
|
|
// Already Exist ?
|
|
CHECKHR(hr = _HrOpenSymbolWithLockOption(pszName, TRUE, &pSymbol,FALSE));
|
|
|
|
// If MPF_ADDRESS flag is not equal to what the symbol already has, this is an error
|
|
if (ISFLAGSET(dwFlags, MPF_ADDRESS) != ISFLAGSET(pSymbol->dwFlags, MPF_ADDRESS))
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Change the Flags
|
|
pSymbol->dwFlags = dwFlags;
|
|
|
|
// Change the row number
|
|
pSymbol->dwRowNumber = ((dwRowNumber == 0) ? 1 : dwRowNumber);
|
|
|
|
// Save the Default Data Type
|
|
pSymbol->vtDefault = vtDefault;
|
|
|
|
// Return the Property Id
|
|
if (pdwPropId)
|
|
*pdwPropId = pSymbol->dwPropId;
|
|
|
|
exit:
|
|
// Thread Safety
|
|
m_lock.ExclusiveUnlock();
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::ModifyProperty
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPropertySymbolCache::ModifyProperty(LPCSTR pszName, DWORD dwFlags, DWORD dwRowNumber,
|
|
VARTYPE vtDefault)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPPROPSYMBOL pSymbol;
|
|
|
|
// Invalid Args
|
|
if (NULL == pszName)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Is Supported VARTYPE
|
|
if (ISSUPPORTEDVT(vtDefault) == FALSE)
|
|
return TrapError(MIME_E_UNSUPPORTED_VARTYPE);
|
|
|
|
// Thread Safety
|
|
m_lock.ExclusiveLock();
|
|
|
|
// Validate the dwFlags
|
|
CHECKHR(hr = HrIsValidPropFlags(dwFlags));
|
|
|
|
// Find the Property By Name
|
|
CHECKHR(hr = _HrOpenSymbolWithLockOption(pszName, FALSE, &pSymbol,FALSE));
|
|
|
|
// If MPF_ADDRESS flag is not equal to what the symbol already has, this is an error
|
|
if (ISFLAGSET(dwFlags, MPF_ADDRESS) != ISFLAGSET(pSymbol->dwFlags, MPF_ADDRESS))
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Change the Flags
|
|
pSymbol->dwFlags = dwFlags;
|
|
|
|
// Change the row number
|
|
pSymbol->dwRowNumber = ((dwRowNumber == 0) ? 1 : dwRowNumber);
|
|
|
|
// Save the Default Data Type
|
|
pSymbol->vtDefault = vtDefault;
|
|
|
|
exit:
|
|
// Thread Safety
|
|
m_lock.ExclusiveUnlock();
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::RegisterAddressType
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CPropertySymbolCache::RegisterAddressType(LPCSTR pszName, LPDWORD pdwAdrType)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPPROPSYMBOL pSymbol;
|
|
|
|
// Invalid Args
|
|
if (NULL == pszName || NULL == pdwAdrType)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
m_lock.ExclusiveLock();
|
|
|
|
// Already Exist ?
|
|
CHECKHR(hr = _HrOpenSymbolWithLockOption(pszName, TRUE, &pSymbol,FALSE));
|
|
|
|
// If pSymbol already has an address type ?
|
|
if (ISFLAGSET(pSymbol->dwFlags, MPF_ADDRESS))
|
|
{
|
|
// Better have a known address type
|
|
Assert(IAT_UNKNOWN != pSymbol->dwAdrType);
|
|
|
|
// Return the Address Type
|
|
*pdwAdrType = pSymbol->dwAdrType;
|
|
}
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
// Better have an unknown address type
|
|
Assert(IAT_UNKNOWN == pSymbol->dwAdrType);
|
|
|
|
// Find the first empty cell in the address type table
|
|
for (ULONG i=0; i<ARRAYSIZE(g_prgAddrSymbol); i++)
|
|
{
|
|
// Empty ?
|
|
if (NULL == g_prgAddrSymbol[i].pSymbol)
|
|
{
|
|
// Put the symbol into the address table
|
|
g_prgAddrSymbol[i].pSymbol = pSymbol;
|
|
|
|
// Put the address type into the symbol
|
|
pSymbol->dwAdrType = g_prgAddrSymbol[i].dwAdrType;
|
|
|
|
// Add the MPF_ADDRESS flag onto the symbol
|
|
FLAGSET(pSymbol->dwFlags, MPF_ADDRESS);
|
|
|
|
// Return the Address Type
|
|
*pdwAdrType = pSymbol->dwAdrType;
|
|
|
|
// Done
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Error
|
|
hr = TrapError(MIME_E_NO_MORE_ADDRESS_TYPES);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
// Thread Safety
|
|
m_lock.ExclusiveUnlock();
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::_FreeTableElements
|
|
// --------------------------------------------------------------------------------
|
|
void CPropertySymbolCache::_FreeTableElements(void)
|
|
{
|
|
// Thread Safety
|
|
m_lock.ExclusiveLock();
|
|
|
|
// May not actually exist yet...
|
|
if (m_rTable.prgpSymbol)
|
|
{
|
|
// Loop through the items...
|
|
for (ULONG i=0; i<m_rTable.cSymbols; i++)
|
|
_FreeSymbol(m_rTable.prgpSymbol[i]);
|
|
|
|
// Free the array
|
|
SafeMemFree(m_rTable.prgpSymbol);
|
|
|
|
// Zero It
|
|
ZeroMemory(&m_rTable, sizeof(SYMBOLTABLE));
|
|
}
|
|
|
|
// Thread Safety
|
|
m_lock.ExclusiveUnlock();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CPropertySymbolCache::_FreeSymbol
|
|
// ---------------------------------------------------------------------------
|
|
void CPropertySymbolCache::_FreeSymbol(LPPROPSYMBOL pSymbol)
|
|
{
|
|
// If Not a Known Property, free the pTag Structure...
|
|
if (pSymbol && ISFLAGSET(pSymbol->dwFlags, MPF_KNOWN) == FALSE)
|
|
{
|
|
// Free Property Name
|
|
SafeMemFree(pSymbol->pszName);
|
|
|
|
// Free Global Prop
|
|
SafeMemFree(pSymbol);
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::HrOpenSymbol
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPropertySymbolCache::HrOpenSymbol(DWORD dwAdrType, LPPROPSYMBOL *ppSymbol)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD dw=dwAdrType;
|
|
ULONG iAddress=0;
|
|
|
|
// Invalid Arg
|
|
Assert(dwAdrType && dwAdrType <= FLAG32);
|
|
if (0 == dwAdrType || dwAdrType > FLAG32 || NULL == ppSymbol)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Init
|
|
*ppSymbol = NULL;
|
|
|
|
// Thread Safety
|
|
m_lock.ShareLock();
|
|
|
|
// Initialized Yet
|
|
Assert(m_rTable.prgpSymbol);
|
|
|
|
// Compute index into g_prgAddrSymbol
|
|
while(dw)
|
|
{
|
|
dw = dw >> 1;
|
|
iAddress++;
|
|
}
|
|
|
|
// Decrement one
|
|
iAddress--;
|
|
|
|
// iAddress Out of Range
|
|
if (iAddress >= 32)
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Get the Symbol
|
|
if (NULL == g_prgAddrSymbol[iAddress].pSymbol)
|
|
{
|
|
hr = TrapError(MIME_E_NOT_FOUND);
|
|
goto exit;
|
|
}
|
|
|
|
// Return it
|
|
*ppSymbol = g_prgAddrSymbol[iAddress].pSymbol;
|
|
Assert((*ppSymbol)->dwAdrType == dwAdrType);
|
|
|
|
exit:
|
|
// Thread Safety
|
|
m_lock.ShareUnlock();
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::HrOpenSymbol
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPropertySymbolCache::HrOpenSymbol(LPCSTR pszName, BOOL fCreate, LPPROPSYMBOL *ppSymbol)
|
|
{
|
|
return(_HrOpenSymbolWithLockOption(pszName,fCreate,ppSymbol,TRUE)); //call with lockOption=TRUE
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::_HrOpenSymbolWithLockOption
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPropertySymbolCache::_HrOpenSymbolWithLockOption(LPCSTR pszName, BOOL fCreate, LPPROPSYMBOL *ppSymbol,BOOL fLockOption)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD dwFlags;
|
|
ULONG cchName;
|
|
LPPROPSYMBOL pSymbol=NULL;
|
|
LPPROPSYMBOL pLink=NULL;
|
|
BOOL fExcLock; //flag used to define which unlock to use
|
|
|
|
|
|
fExcLock = FALSE;
|
|
|
|
// Invalid Arg
|
|
if (NULL == pszName || NULL == ppSymbol)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Init
|
|
*ppSymbol = NULL;
|
|
|
|
if(TRUE == fLockOption)
|
|
// Thread Safety
|
|
m_lock.ShareLock();
|
|
|
|
// Initialized Yet
|
|
Assert(m_rTable.prgpSymbol);
|
|
|
|
// If property tag exist, return it
|
|
if (SUCCEEDED(_HrFindSymbol(pszName, ppSymbol)))
|
|
goto exit;
|
|
|
|
// Don't Create...
|
|
if (FALSE == fCreate || ISPIDSTR(pszName))
|
|
{
|
|
hr = MIME_E_NOT_FOUND;
|
|
goto exit;
|
|
}
|
|
|
|
//This part is added to convert the lock to Exclusive
|
|
//if the symbol is not found in the cache
|
|
|
|
if(TRUE == fLockOption)
|
|
{
|
|
fExcLock = TRUE;
|
|
if(FALSE == m_lock.SharedToExclusive())
|
|
{
|
|
//if the attempt at conversion does not
|
|
//succeed tryu to do it by explicitly
|
|
|
|
m_lock.ShareUnlock(); //Release the Sharelock before
|
|
m_lock.ExclusiveLock(); //getting the exclusive lock
|
|
|
|
//during the change of lock the cache might have changed
|
|
//check it again
|
|
|
|
if (SUCCEEDED(_HrFindSymbol(pszName, ppSymbol)))
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Get the length of the name
|
|
cchName = lstrlen(pszName);
|
|
|
|
// MPF_PARAMETER
|
|
if (StrCmpNI(pszName, "par:", 4) == 0)
|
|
{
|
|
// Its a parameter
|
|
dwFlags = MPF_PARAMETER;
|
|
|
|
// I need to locate pLink (the root header of this parameter)
|
|
CHECKHR(hr = _HrGetParameterLinkSymbolWithLockOption(pszName, cchName, &pLink,FALSE));
|
|
}
|
|
|
|
// MPF_ATTRIBUTE
|
|
else if (StrCmpNI(pszName, "att:", 4) == 0)
|
|
dwFlags = MPF_ATTRIBUTE;
|
|
|
|
// MPF_HEADER
|
|
else
|
|
{
|
|
dwFlags = MPF_HEADER;
|
|
|
|
// validate each character in the name against rfc (no :, or spaces)
|
|
LPSTR psz = (LPSTR)pszName;
|
|
while(*psz)
|
|
{
|
|
// Invalid Chars
|
|
if ('.' == *psz || ' ' == *psz || '\t' == *psz || chCR == *psz || chLF == *psz || ':' == *psz)
|
|
{
|
|
hr = MIME_E_INVALID_HEADER_NAME;
|
|
goto exit;
|
|
}
|
|
|
|
// Next
|
|
psz++;
|
|
}
|
|
}
|
|
|
|
// Do I need to replace an item...
|
|
if (m_rTable.cSymbols + 1 > m_rTable.cAlloc)
|
|
{
|
|
// Reallocate the array
|
|
CHECKHR(hr = HrRealloc((LPVOID *)&m_rTable.prgpSymbol, sizeof(LPPROPSYMBOL) * (m_rTable.cAlloc + 10)));
|
|
|
|
// Increment
|
|
m_rTable.cAlloc += 10;
|
|
}
|
|
|
|
// Allocate a new propinfo struct
|
|
CHECKALLOC(pSymbol = (LPPROPSYMBOL)g_pMalloc->Alloc(sizeof(PROPSYMBOL)));
|
|
|
|
// Zero
|
|
ZeroMemory(pSymbol, sizeof(PROPSYMBOL));
|
|
|
|
// Copy Name
|
|
CHECKALLOC(pSymbol->pszName = (LPSTR)g_pMalloc->Alloc(cchName + 1));
|
|
|
|
// Copy
|
|
CopyMemory(pSymbol->pszName, pszName, cchName + 1);
|
|
|
|
// Copy Other Data
|
|
pSymbol->cchName = cchName;
|
|
pSymbol->dwFlags = dwFlags;
|
|
pSymbol->dwSort = m_rTable.cSymbols;
|
|
pSymbol->dwRowNumber = m_rTable.cSymbols + 1;
|
|
pSymbol->vtDefault = VT_LPSTR;
|
|
pSymbol->dwAdrType = IAT_UNKNOWN;
|
|
pSymbol->pLink = pLink;
|
|
|
|
// Compute the property Id
|
|
pSymbol->dwPropId = m_dwNextPropId++;
|
|
|
|
// Compute Hash Value
|
|
pSymbol->wHashIndex = (WORD)(pSymbol->dwPropId % CBUCKETS);
|
|
|
|
// Save item into array
|
|
m_rTable.prgpSymbol[m_rTable.cSymbols] = pSymbol;
|
|
|
|
// Increment count
|
|
m_rTable.cSymbols++;
|
|
|
|
// Resort the array
|
|
_SortTableElements(0, m_rTable.cSymbols - 1);
|
|
|
|
// Set Handle
|
|
*ppSymbol = pSymbol;
|
|
|
|
// Make sure we can still actually find it by property id
|
|
#ifdef DEBUG
|
|
LPPROPSYMBOL pDebug;
|
|
Assert(SUCCEEDED(_HrOpenSymbolWithLockOption(PIDTOSTR(pSymbol->dwPropId), FALSE, &pDebug,FALSE)));
|
|
#endif
|
|
|
|
exit:
|
|
// Failure
|
|
if (FAILED(hr) && pSymbol)
|
|
_FreeSymbol(pSymbol);
|
|
|
|
if(TRUE == fLockOption)
|
|
{
|
|
// Thread Safety
|
|
if(TRUE==fExcLock)
|
|
m_lock.ExclusiveUnlock();
|
|
else
|
|
m_lock.ShareUnlock();
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::_HrGetParameterLinkSymbol
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPropertySymbolCache::_HrGetParameterLinkSymbol(LPCSTR pszName, ULONG cchName, LPPROPSYMBOL *ppSymbol)
|
|
{
|
|
return(_HrGetParameterLinkSymbolWithLockOption(pszName,cchName,ppSymbol,TRUE)); //call with LockOption=TRUE
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::_HrGetParameterLinkSymbolWithLockOption
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPropertySymbolCache::_HrGetParameterLinkSymbolWithLockOption(LPCSTR pszName, ULONG cchName, LPPROPSYMBOL *ppSymbol,BOOL fLockOption)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPSTR pszStart;
|
|
LPSTR pszEnd;
|
|
ULONG cchHeader=0;
|
|
|
|
// Invalid Arg
|
|
Assert(pszName && ':' == pszName[3] && ppSymbol);
|
|
|
|
// Stack String
|
|
STACKSTRING_DEFINE(rHeader, 255);
|
|
|
|
// Find first semicolon
|
|
pszEnd = (LPSTR)(pszName + 4);
|
|
while (*pszEnd && ':' != *pszEnd)
|
|
{
|
|
pszEnd++;
|
|
cchHeader++;
|
|
}
|
|
|
|
// Set the name
|
|
STACKSTRING_SETSIZE(rHeader, cchHeader+1);
|
|
|
|
// Copy It
|
|
CopyMemory(rHeader.pszVal, (LPBYTE)(pszName + 4), cchHeader);
|
|
*(rHeader.pszVal + cchHeader) = '\0';
|
|
|
|
// Find the Symbol
|
|
CHECKHR(hr = _HrOpenSymbolWithLockOption(rHeader.pszVal, TRUE, ppSymbol,fLockOption));
|
|
|
|
exit:
|
|
// Cleanup
|
|
STACKSTRING_FREE(rHeader);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CPropertySymbolCache::_HrFindSymbol
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CPropertySymbolCache::_HrFindSymbol(LPCSTR pszName, LPPROPSYMBOL *ppSymbol)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPPROPSYMBOL pSymbol=NULL;
|
|
DWORD dwPropId;
|
|
|
|
// Invalid Arg
|
|
Assert(ppSymbol);
|
|
|
|
// If this is a known property tag...
|
|
if (ISPIDSTR(pszName))
|
|
{
|
|
// Cast the dwPropId
|
|
dwPropId = STRTOPID(pszName);
|
|
|
|
// Set Symbol
|
|
if (ISKNOWNPID(dwPropId))
|
|
{
|
|
// De-ref into known property index (ordered differently than g_prgKnownProps)
|
|
pSymbol = m_prgIndex[dwPropId];
|
|
}
|
|
|
|
// Otherwise, must be an unknown pid index
|
|
else
|
|
{
|
|
// I need to re-align dwPropId because it starts at PID_LAST and my not be a direct index
|
|
// into the symbol table since the symbol table is not initialized with PID_LAST properties
|
|
dwPropId -= (PID_LAST - ARRAYSIZE(g_prgKnownSymbol));
|
|
|
|
// Must be >= PID_LAST and < m_rTable.cSymbols
|
|
if (dwPropId >= m_cSymbolsInit && dwPropId < m_rTable.cSymbols)
|
|
{
|
|
// dwPropId is an index into the symbol table
|
|
pSymbol = m_rTable.prgpSymbol[dwPropId];
|
|
Assert(pSymbol);
|
|
}
|
|
|
|
// Else
|
|
else
|
|
AssertSz(FALSE, "How did you get an invalid unknown property id?");
|
|
}
|
|
}
|
|
|
|
// Otherwise, look for it by name
|
|
else
|
|
{
|
|
// Locals
|
|
LONG lUpper, lLower, lMiddle, nCompare;
|
|
ULONG i;
|
|
|
|
// Set lLower and lUpper
|
|
lLower = 0;
|
|
lUpper = m_rTable.cSymbols - 1;
|
|
|
|
// Do binary search / insert
|
|
while (lLower <= lUpper)
|
|
{
|
|
// Compute middle record to compare against
|
|
lMiddle = (LONG)((lLower + lUpper) / 2);
|
|
|
|
// Get string to compare against
|
|
i = m_rTable.prgpSymbol[lMiddle]->dwSort;
|
|
|
|
// Do compare
|
|
nCompare = OEMstrcmpi(pszName, m_rTable.prgpSymbol[i]->pszName);
|
|
|
|
// If Equal, then were done
|
|
if (nCompare == 0)
|
|
{
|
|
// Set Symbol
|
|
pSymbol = m_rTable.prgpSymbol[i];
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
|
|
// Compute upper and lower
|
|
if (nCompare > 0)
|
|
lLower = lMiddle + 1;
|
|
else
|
|
lUpper = lMiddle - 1;
|
|
}
|
|
}
|
|
|
|
// Not Found
|
|
if (NULL == pSymbol)
|
|
{
|
|
hr = MIME_E_NOT_FOUND;
|
|
goto exit;
|
|
}
|
|
|
|
// Validate PropSymbol
|
|
Assert(SUCCEEDED(HrIsValidSymbol(pSymbol)));
|
|
|
|
// Otherwise...
|
|
*ppSymbol = pSymbol;
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CPropertySymbolCache::Init
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT CPropertySymbolCache::Init(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG i;
|
|
|
|
// We should not be initialized yet
|
|
Assert(NULL == m_rTable.prgpSymbol);
|
|
|
|
// Thread Safety
|
|
m_lock.ExclusiveLock();
|
|
|
|
// Set Sizes
|
|
m_rTable.cSymbols = ARRAYSIZE(g_prgKnownSymbol);
|
|
m_rTable.cAlloc = m_rTable.cSymbols + 30;
|
|
|
|
// Allocate the global item table
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&m_rTable.prgpSymbol, sizeof(LPPROPSYMBOL) * m_rTable.cAlloc));
|
|
|
|
// Zero Init
|
|
ZeroMemory(m_rTable.prgpSymbol, sizeof(LPPROPSYMBOL) * m_rTable.cAlloc);
|
|
|
|
// Loop through known items
|
|
for(i=0; i<m_rTable.cSymbols; i++)
|
|
{
|
|
// Just assume the global data pointer
|
|
m_rTable.prgpSymbol[i] = g_prgKnownSymbol[i];
|
|
|
|
// Set the sort position
|
|
m_rTable.prgpSymbol[i]->dwSort = i;
|
|
|
|
// Compute Hash Index
|
|
m_rTable.prgpSymbol[i]->wHashIndex = (WORD)(m_rTable.prgpSymbol[i]->dwPropId % CBUCKETS);
|
|
|
|
// Set the sort position
|
|
m_rTable.prgpSymbol[i]->dwRowNumber = i + 1;
|
|
|
|
// Put it into my index
|
|
Assert(ISKNOWNPID(m_rTable.prgpSymbol[i]->dwPropId) == TRUE);
|
|
|
|
// Put into symbol index
|
|
m_prgIndex[m_rTable.prgpSymbol[i]->dwPropId] = m_rTable.prgpSymbol[i];
|
|
}
|
|
|
|
// Sort the item table...
|
|
_SortTableElements(0, m_rTable.cSymbols - 1);
|
|
|
|
// Save Number of Symbols initialised in the table
|
|
m_cSymbolsInit = m_rTable.cSymbols;
|
|
|
|
// Table Validation
|
|
#ifdef DEBUG
|
|
LPPROPSYMBOL pDebug;
|
|
|
|
// Lets validate the table
|
|
for(i=0; i<m_rTable.cSymbols; i++)
|
|
{
|
|
// Validate pLink
|
|
if (ISFLAGSET(m_rTable.prgpSymbol[i]->dwFlags, MPF_PARAMETER))
|
|
{
|
|
// Locals
|
|
LPPROPSYMBOL pLink;
|
|
|
|
// Look for the link symbol
|
|
Assert(SUCCEEDED(_HrGetParameterLinkSymbolWithLockOption(m_rTable.prgpSymbol[i]->pszName, m_rTable.prgpSymbol[i]->cchName, &pLink,FALSE)));
|
|
|
|
// Validate the the computed link with the const link
|
|
Assert(pLink == m_rTable.prgpSymbol[i]->pLink);
|
|
}
|
|
|
|
// If this has an address flag
|
|
if (ISFLAGSET(m_rTable.prgpSymbol[i]->dwFlags, MPF_ADDRESS))
|
|
{
|
|
// Locals
|
|
ULONG j;
|
|
BOOL f=FALSE;
|
|
|
|
// Make sure it is in the address type table
|
|
for (j=0; j<ARRAYSIZE(g_prgAddrSymbol); j++)
|
|
{
|
|
// Found It
|
|
if (m_rTable.prgpSymbol[i] == g_prgAddrSymbol[j].pSymbol)
|
|
{
|
|
f=TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// We better have found it
|
|
AssertSz(f, "A symbol has the MPF_ADDRESS flag, but is not in the address table.");
|
|
}
|
|
|
|
// Make sure we can still actually find it by property id
|
|
Assert(SUCCEEDED(_HrOpenSymbolWithLockOption(PIDTOSTR(m_rTable.prgpSymbol[i]->dwPropId), FALSE, &pDebug,FALSE)));
|
|
}
|
|
#endif
|
|
|
|
exit:
|
|
// Thread Safety
|
|
m_lock.ExclusiveUnlock();
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CPropertySymbolCache::_SortTableElements
|
|
// -----------------------------------------------------------------------------
|
|
void CPropertySymbolCache::_SortTableElements(LONG left, LONG right)
|
|
{
|
|
// Locals
|
|
register long i, j;
|
|
DWORD k, temp;
|
|
|
|
i = left;
|
|
j = right;
|
|
k = m_rTable.prgpSymbol[(i + j) / 2]->dwSort;
|
|
|
|
do
|
|
{
|
|
while(OEMstrcmpi(m_rTable.prgpSymbol[m_rTable.prgpSymbol[i]->dwSort]->pszName, m_rTable.prgpSymbol[k]->pszName) < 0 && i < right)
|
|
i++;
|
|
while (OEMstrcmpi(m_rTable.prgpSymbol[m_rTable.prgpSymbol[j]->dwSort]->pszName, m_rTable.prgpSymbol[k]->pszName) > 0 && j > left)
|
|
j--;
|
|
|
|
if (i <= j)
|
|
{
|
|
temp = m_rTable.prgpSymbol[i]->dwSort;
|
|
m_rTable.prgpSymbol[i]->dwSort = m_rTable.prgpSymbol[j]->dwSort;
|
|
m_rTable.prgpSymbol[j]->dwSort = temp;
|
|
i++; j--;
|
|
}
|
|
|
|
} while (i <= j);
|
|
|
|
if (left < j)
|
|
_SortTableElements(left, j);
|
|
if (i < right)
|
|
_SortTableElements(i, right);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// WGetHashTableIndex
|
|
// --------------------------------------------------------------------------------
|
|
WORD WGetHashTableIndex(LPCSTR pszName, ULONG cchName)
|
|
{
|
|
// Locals
|
|
ULONG nHash=0;
|
|
LONG c, j=0;
|
|
ULONG i;
|
|
CHAR ch;
|
|
|
|
// Invalid Arg
|
|
Assert(pszName && pszName[cchName] =='\0');
|
|
|
|
// Compute Number of characters to hash
|
|
i = cchName - 1;
|
|
c = min(3, cchName);
|
|
|
|
// Loop
|
|
for (; j<c; j++)
|
|
{
|
|
ch = (CHAR)CharLower((LPSTR)(DWORD_PTR)MAKELONG(pszName[i - j], 0));
|
|
nHash += (ULONG)(ch);
|
|
}
|
|
|
|
// Done
|
|
return (WORD)(nHash % CBUCKETS);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// HrIsValidSymbol
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT HrIsValidSymbol(LPCPROPSYMBOL pSymbol)
|
|
{
|
|
// Validate the symbol
|
|
if (NULL == pSymbol || NULL == pSymbol->pszName || '\0' != pSymbol->pszName[pSymbol->cchName])
|
|
return TrapError(E_FAIL);
|
|
|
|
// Validate the flags
|
|
return HrIsValidPropFlags(pSymbol->dwFlags);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// HrIsValidPropFlags
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT HrIsValidPropFlags(DWORD dwFlags)
|
|
{
|
|
// If has parameters, it can only be a mime header property
|
|
if (ISFLAGSET(dwFlags, MPF_HASPARAMS) && (!ISFLAGSET(dwFlags, MPF_MIME) || !ISFLAGSET(dwFlags, MPF_HEADER)))
|
|
return TrapError(MIME_E_INVALID_PROP_FLAGS);
|
|
|
|
// If not inetcset, then rfc1522 better not be set either
|
|
if (!ISFLAGSET(dwFlags, MPF_INETCSET) && ISFLAGSET(dwFlags, MPF_RFC1522))
|
|
return TrapError(MIME_E_INVALID_PROP_FLAGS);
|
|
|
|
// If rfc1522 is set, inetset better be set
|
|
if (ISFLAGSET(dwFlags, MPF_RFC1522) && !ISFLAGSET(dwFlags, MPF_INETCSET))
|
|
return TrapError(MIME_E_INVALID_PROP_FLAGS);
|
|
|
|
// Is either MDF_ADDRESS or MDF_HASPARAMS
|
|
if (ISFLAGSET(dwFlags, MPF_ADDRESS) && ISFLAGSET(dwFlags, MPF_HASPARAMS))
|
|
return TrapError(MIME_E_INVALID_PROP_FLAGS);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|