Windows2003-3790/inetcore/outlookexpress/inetcomm/mimeole/mimeapi.cpp
2020-09-30 16:53:55 +02:00

4429 lines
125 KiB
C++

// --------------------------------------------------------------------------------
// Mimeapi.cpp
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
// Steven J. Bailey
// --------------------------------------------------------------------------------
#include "pch.hxx"
#include "dllmain.h"
#include "olealloc.h"
#include "partial.h"
#include "smime.h"
#include "vstream.h"
#include "internat.h"
#include "stackstr.h"
#include "ixputil.h"
#include "webdocs.h"
#include "containx.h"
#include "inetstm.h"
#include "mhtmlurl.h"
#include "booktree.h"
#include "bookbody.h"
#include <shlwapi.h>
#include <shlwapip.h>
#include "mlang.h"
#include "strconst.h"
#include "symcache.h"
#include "mimeapi.h"
#include "hash.h"
#include "shared.h"
#include "demand.h"
// ------------------------------------------------------------------------------------------
// Special Partial Headers
// ------------------------------------------------------------------------------------------
static LPCSTR g_rgszPartialPids[] = {
PIDTOSTR(PID_HDR_CNTTYPE),
PIDTOSTR(PID_HDR_CNTXFER),
PIDTOSTR(PID_HDR_CNTDESC),
PIDTOSTR(PID_HDR_MESSAGEID),
PIDTOSTR(PID_HDR_MIMEVER),
PIDTOSTR(PID_HDR_CNTID),
PIDTOSTR(PID_HDR_CNTDISP),
STR_HDR_ENCRYPTED
};
// --------------------------------------------------------------------------------
// MimeGetAddressFormatW
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeGetAddressFormatW(REFIID riid, LPVOID pvObject, DWORD dwAdrType,
ADDRESSFORMAT format, LPWSTR *ppszFormat)
{
// Locals
HRESULT hr=S_OK;
CMimePropertyContainer *pContainer=NULL;
// Trace
TraceCall("MimeGetAddressFormatW");
// Invalid Args
if (NULL == pvObject)
return(TraceResult(E_INVALIDARG));
// Is a messageW object ?
if (IID_IMimeMessageW == riid)
{
// Get It
CHECKHR(hr = ((IMimeMessageW *)pvObject)->GetAddressFormatW(dwAdrType, format, ppszFormat));
}
// Is a message object ?
else if (IID_IMimeMessage == riid)
{
// Query for IID_CMimePropertyContainer
CHECKHR(hr = ((IMimeMessage *)pvObject)->BindToObject(HBODY_ROOT, IID_CMimePropertyContainer, (LPVOID *)&pContainer));
// Get the format
CHECKHR(hr = pContainer->GetFormatW(dwAdrType, format, ppszFormat));
}
// IID_IMimePropertySet
else if (IID_IMimePropertySet == riid)
{
// Query for IID_CMimePropertyContainer
CHECKHR(hr = ((IMimePropertySet *)pvObject)->QueryInterface(IID_CMimePropertyContainer, (LPVOID *)&pContainer));
// Get the format
CHECKHR(hr = pContainer->GetFormatW(dwAdrType, format, ppszFormat));
}
// IID_IMimeAddressTable
else if (IID_IMimeAddressTable == riid)
{
// Query for IID_CMimePropertyContainer
CHECKHR(hr = ((IMimeAddressTable *)pvObject)->QueryInterface(IID_CMimePropertyContainer, (LPVOID *)&pContainer));
// Get the format
CHECKHR(hr = pContainer->GetFormatW(dwAdrType, format, ppszFormat));
}
// IID_IMimeHeaderTable
else if (IID_IMimeHeaderTable == riid)
{
// Query for IID_CMimePropertyContainer
CHECKHR(hr = ((IMimeHeaderTable *)pvObject)->QueryInterface(IID_CMimePropertyContainer, (LPVOID *)&pContainer));
// Get the format
CHECKHR(hr = pContainer->GetFormatW(dwAdrType, format, ppszFormat));
}
// Final
else
{
hr = TraceResult(E_NOINTERFACE);
goto exit;
}
exit:
// Cleanup
SafeRelease(pContainer);
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// MimeOleGetWindowsCP
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleSetCompatMode(DWORD dwMode)
{
// Add in the bit
FLAGSET(g_dwCompatMode, dwMode);
// Done
return(S_OK);
}
// --------------------------------------------------------------------------------
// MimeOleGetWindowsCP
// --------------------------------------------------------------------------------
CODEPAGEID MimeOleGetWindowsCP(HCHARSET hCharset)
{
// Locals
INETCSETINFO rCharset;
// Invalid Arg
if (NULL == hCharset)
return CP_ACP;
// Loopup charset
Assert(g_pInternat);
if (FAILED(g_pInternat->GetCharsetInfo(hCharset, &rCharset)))
return CP_ACP;
// Return
return MimeOleGetWindowsCPEx(&rCharset);
}
// --------------------------------------------------------------------------------
// MimeOleStripHeaders
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleStripHeaders(IMimeMessage *pMessage, HBODY hBody, LPCSTR pszNameDelete,
LPCSTR pszHeaderAdd, IStream **ppStream)
{
// Locals
HRESULT hr=S_OK;
IMimeHeaderTable *pHdrTable=NULL;
LPSTREAM pStmSource=NULL;
LPSTREAM pStmDest=NULL;
HHEADERROW hRow;
HEADERROWINFO Info;
DWORD cbLastRead=0;
FINDHEADER Find={0};
ULARGE_INTEGER uliCopy;
// Trace
TraceCall("MimeOleStripHeaders");
// Invalid Arg
if (NULL == pMessage || NULL == hBody || NULL == pszNameDelete || NULL == ppStream)
return TraceResult(E_INVALIDARG);
// Initialize
*ppStream = NULL;
// Get the message source, no commit
IF_FAILEXIT(hr = pMessage->GetMessageSource(&pStmSource, 0));
// Get the Header Table for hBody
IF_FAILEXIT(hr = pMessage->BindToObject(hBody, IID_IMimeHeaderTable, (LPVOID *)&pHdrTable));
// Initialize the Find
Find.pszHeader = pszNameDelete;
// Find this row
IF_FAILEXIT(hr = pHdrTable->FindFirstRow(&Find, &hRow));
// Create a stream
IF_FAILEXIT(hr = MimeOleCreateVirtualStream(&pStmDest));
// Delete this row
while(1)
{
// Get the row information
IF_FAILEXIT(hr = pHdrTable->GetRowInfo(hRow, &Info));
// Setup uliCopy
uliCopy.QuadPart = Info.cboffStart - cbLastRead;
// Seek
IF_FAILEXIT(hr = HrStreamSeekSet(pStmSource, cbLastRead));
// Write from cbLast to Info.cboffStart
IF_FAILEXIT(hr = HrCopyStreamCB(pStmSource, pStmDest, uliCopy, NULL, NULL));
// Set cbLast
cbLastRead = Info.cboffEnd;
// Find the next
hr = pHdrTable->FindNextRow(&Find, &hRow);
// Failure
if (FAILED(hr))
{
// MIME_E_NOT_FOUND
if (MIME_E_NOT_FOUND == hr)
{
hr = S_OK;
break;
}
else
{
TraceResult(hr);
goto exit;
}
}
}
// Add on pszHeaderAdd
if (pszHeaderAdd)
{
// Write the Add Header
IF_FAILEXIT(hr = pStmDest->Write(pszHeaderAdd, lstrlen(pszHeaderAdd), NULL));
}
// Write the Rest of pStmSource
IF_FAILEXIT(hr = HrStreamSeekSet(pStmSource, cbLastRead));
// Write the Rest
IF_FAILEXIT(hr = HrCopyStream(pStmSource, pStmDest, NULL));
// Commit
IF_FAILEXIT(hr = pStmDest->Commit(STGC_DEFAULT));
// Rewind It
IF_FAILEXIT(hr = HrRewindStream(pStmDest));
// Return pStmDest
*ppStream = pStmDest;
(*ppStream)->AddRef();
exit:
// Cleanup
SafeRelease(pStmSource);
SafeRelease(pHdrTable);
SafeRelease(pStmDest);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleGetWindowsCPEx
// --------------------------------------------------------------------------------
CODEPAGEID MimeOleGetWindowsCPEx(LPINETCSETINFO pCharset)
{
// Invalid Arg
if (NULL == pCharset)
return CP_ACP;
// Check for Auto-Detect
if (CP_JAUTODETECT == pCharset->cpiWindows)
return 932;
else if (CP_ISO2022JPESC == pCharset->cpiWindows)
return 932;
else if (CP_ISO2022JPSIO == pCharset->cpiWindows)
return 932;
else if (CP_KAUTODETECT == pCharset->cpiWindows)
return 949;
else
return pCharset->cpiWindows;
}
// --------------------------------------------------------------------------------
// MimeOleClearDirtyTree
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleClearDirtyTree(IMimeMessageTree *pITree)
{
// Locals
HRESULT hr=S_OK;
CMessageTree *pTree=NULL;
// Invalid Arg
if (NULL == pITree)
return TrapError(E_INVALIDARG);
// I need a private IID_CMessageTree to do this
CHECKHR(hr = pITree->QueryInterface(IID_CMessageTree, (LPVOID *)&pTree));
// ClearDirty
pTree->ClearDirty();
// Validate
Assert(pTree->IsDirty() == S_FALSE);
exit:
// Cleanup
SafeRelease(pTree);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// PszDefaultSubType
// --------------------------------------------------------------------------------
LPCSTR PszDefaultSubType(LPCSTR pszPriType)
{
if (lstrcmpi(pszPriType, STR_CNT_TEXT) == 0)
return STR_SUB_PLAIN;
else if (lstrcmpi(pszPriType, STR_CNT_MULTIPART) == 0)
return STR_SUB_MIXED;
else
return STR_SUB_OCTETSTREAM;
}
// --------------------------------------------------------------------------------
// MimeOleContentTypeFromUrl
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleContentTypeFromUrl(
/* in */ LPCSTR pszBase,
/* in */ LPCSTR pszUrl,
/* out */ LPSTR *ppszCntType)
{
// Locals
HRESULT hr=S_OK;
LPSTR pszFree=NULL;
LPSTR pszCombined=NULL;
LPWSTR pwszUrl=NULL;
LPWSTR pwszCntType=NULL;
// Invalid Arg
if (NULL == pszUrl || NULL == ppszCntType)
return TrapError(E_INVALIDARG);
// Init
*ppszCntType = NULL;
// Combine the URL
if (pszBase)
{
// Allocate Base + URL
DWORD cchSize = (lstrlen(pszUrl) + lstrlen(pszBase) + 1);
CHECKALLOC(pszFree = (LPSTR)g_pMalloc->Alloc(cchSize));
// Format It
wnsprintfA(pszFree, cchSize, "%s%s", pszBase, pszUrl);
// Set combined
pszCombined = pszFree;
// Convert to Unicode
CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszCombined));
}
// To Unicode
else
{
// Set combined
pszCombined = (LPSTR)pszUrl;
// Convert to Unicode
CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszUrl));
}
// Get the Mime Content Type from the Url
CHECKHR(hr = FindMimeFromData(NULL, pwszUrl, NULL, NULL, NULL, 0, &pwszCntType, 0));
// Convert to ANSI
CHECKALLOC(*ppszCntType = PszToANSI(CP_ACP, pwszCntType));
exit:
// Cleanup
SafeMemFree(pszFree);
SafeMemFree(pwszUrl);
SafeMemFree(pwszCntType);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleObjectFromMoniker
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleObjectFromMoniker(
/* in */ BINDF bindf,
/* in */ IMoniker *pmkOriginal,
/* in */ IBindCtx *pBindCtx,
/* in */ REFIID riid,
/* out */ LPVOID *ppvObject,
/* out */ IMoniker **ppmkNew)
{
Assert(g_pUrlCache);
return TrapError(g_pUrlCache->ActiveObjectFromMoniker(bindf, pmkOriginal, pBindCtx, riid, ppvObject, ppmkNew));
}
// --------------------------------------------------------------------------------
// MimeOleObjectFromUrl
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleObjectFromUrl(
/* in */ LPCSTR pszUrl,
/* in */ BOOL fCreate,
/* in */ REFIID riid,
/* out */ LPVOID *ppvObject,
/* out */ IUnknown **ppUnkKeepAlive)
{
Assert(g_pUrlCache);
return TrapError(g_pUrlCache->ActiveObjectFromUrl(pszUrl, fCreate, riid, ppvObject, ppUnkKeepAlive));
}
// --------------------------------------------------------------------------------
// MimeOleCombineMhtmlUrl
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleCombineMhtmlUrl(
/* in */ LPSTR pszRootUrl,
/* in */ LPSTR pszBodyUrl,
/* out */ LPSTR *ppszUrl)
{
// Locals
HRESULT hr=S_OK;
ULONG cchPrefix=lstrlen(c_szMHTMLColon);
// Invalid Arg
if (NULL == pszRootUrl || NULL == pszBodyUrl || NULL == ppszUrl)
return TrapError(E_INVALIDARG);
// Init
*ppszUrl = NULL;
// Allocate memory: pszRootUrl + ! + pszBodyUrl
DWORD cchSize = (cchPrefix + lstrlen(pszRootUrl) + lstrlen(pszBodyUrl) + 2);
CHECKALLOC(*ppszUrl = (LPSTR)g_pMalloc->Alloc(cchSize));
// Root must start with mhtml://pszRootUrl!pszBodyUrl
if (StrCmpNI(pszRootUrl, c_szMHTMLColon, cchPrefix) != 0)
wnsprintfA(*ppszUrl, cchSize, "%s%s!%s", c_szMHTMLColon, pszRootUrl, pszBodyUrl);
else
wnsprintfA(*ppszUrl, cchSize, "%s!%s", pszRootUrl, pszBodyUrl);
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleSplitMhtmlUrl - Returns E_INVLAIDARG if pszUrl does not start with mhtml:
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleParseMhtmlUrl(
/* in */ LPSTR pszUrl,
/* out */ LPSTR *ppszRootUrl,
/* out */ LPSTR *ppszBodyUrl)
{
// Locals
HRESULT hr=S_OK;
CStringParser cString;
CHAR chToken;
ULONG cchUrl;
ULONG cchPrefix=lstrlen(c_szMHTMLColon);
// Invalid Arg
if (NULL == pszUrl)
return TrapError(E_INVALIDARG);
// Init
if (ppszRootUrl)
*ppszRootUrl = NULL;
if (ppszBodyUrl)
*ppszBodyUrl = NULL;
// No an mhtml Url ?
if (StrCmpNI(pszUrl, c_szMHTMLColon, cchPrefix) != 0)
{
hr = E_FAIL;
goto exit;
}
// Get the length
cchUrl = lstrlen(pszUrl);
// Init the Parser
cString.Init(pszUrl + cchPrefix, cchUrl - cchPrefix, PSF_NOFRONTWS | PSF_NOTRAILWS);
// Skip Over any '/'
cString.ChSkip("/");
// Parse
chToken = cString.ChParse("!");
if (0 == cString.CchValue())
{
hr = TrapError(E_FAIL);
goto exit;
}
// Client Wants ppszRootUrl
if (ppszRootUrl)
{
// Allocate length for root part
CHECKALLOC(*ppszRootUrl = (LPSTR)g_pMalloc->Alloc(cString.CchValue() + 1));
// Copy It
CopyMemory((LPBYTE)*ppszRootUrl, (LPBYTE)cString.PszValue(), cString.CchValue() + 1);
}
// Client Wants ppszBodyUrl
if (ppszBodyUrl)
{
// Parse to the end of the string
chToken = cString.ChParse(NULL);
Assert('\0' == chToken);
// Is there data
if (cString.CchValue() > 0)
{
// Allocate length for root part
CHECKALLOC(*ppszBodyUrl = (LPSTR)g_pMalloc->Alloc(cString.CchValue() + 1));
// Copy It
CopyMemory((LPBYTE)*ppszBodyUrl, (LPBYTE)cString.PszValue(), cString.CchValue() + 1);
}
}
exit:
// Failure
if (FAILED(hr))
{
if (ppszRootUrl)
SafeMemFree(*ppszRootUrl);
if (ppszBodyUrl)
SafeMemFree(*ppszBodyUrl);
}
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleCombineURL
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleCombineURL(
/* in */ LPCSTR pszBase,
/* in */ ULONG cchBase,
/* in */ LPCSTR pszURL,
/* in */ ULONG cchURL,
/* in */ BOOL fUnEscape,
/* out */ LPSTR *ppszAbsolute)
{
// Locals
HRESULT hr=S_OK;
LPWSTR pwszBase=NULL;
LPWSTR pwszUrl=NULL;
LPWSTR pwszCombined=NULL;
ULONG cchCombined;
ULONG cchActual;
WCHAR wchCombined[255];
LPSTR pszT;
CStringParser cString;
// Invalid Arg
if (NULL == pszBase || '\0' != pszBase[cchBase] || NULL == pszURL || '\0' != pszURL[cchURL] || NULL == ppszAbsolute)
return TrapError(E_INVALIDARG);
// INit
*ppszAbsolute = NULL;
// Raid-2621: Mail : Can't display images when message is only in HTML and the Content Base is in the headers
pszT = PszSkipWhiteA((LPSTR)pszBase);
if (pszT && '\"' == *pszT)
{
// Init the String
cString.Init(pszBase, cchBase, PSF_NOTRAILWS | PSF_NOFRONTWS | PSF_ESCAPED | PSF_DBCS);
// Remove Quotes
if ('\"' == cString.ChParse("\"") && '\"' == cString.ChParse("\""))
{
// Reset pszBase
pszBase = cString.PszValue();
cchBase = cString.CchValue();
}
}
// Convert to Wide
CHECKALLOC(pwszBase = PszToUnicode(CP_ACP, pszBase));
CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszURL));
// Combine
if (SUCCEEDED(CoInternetCombineUrl(pwszBase, pwszUrl, 0, wchCombined, ARRAYSIZE(wchCombined) - 1, &cchCombined, 0)))
{
// Convert to ANSI
CHECKALLOC(*ppszAbsolute = PszToANSI(CP_ACP, wchCombined));
}
// Otherwise, allocate
else
{
// Allocate
CHECKALLOC(pwszCombined = PszAllocW(cchCombined));
// Combine
CHECKHR(hr = CoInternetCombineUrl(pwszBase, pwszUrl, 0, pwszCombined, cchCombined, &cchActual, 0));
// Valid?
Assert(cchCombined == cchActual);
// Convert to ANSI
CHECKALLOC(*ppszAbsolute = PszToANSI(CP_ACP, pwszCombined));
}
// Unescape
if (fUnEscape)
{
// Do it
CHECKHR(hr = UrlUnescapeA(*ppszAbsolute, NULL, NULL, URL_UNESCAPE_INPLACE));
}
exit:
// Cleanup
SafeMemFree(pwszBase);
SafeMemFree(pwszUrl);
SafeMemFree(pwszCombined);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleGetSubjectFileName
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetSubjectFileName(IMimePropertySet *pPropertySet, ULONG *pulPart, ULONG *pulTotal,
LPSTR pszFileName, ULONG cchMax)
{
return E_FAIL;
#if 0
// Locals
HRESULT hr=S_OK;
PROPVARIANT rSubject;
PARSESTRINGINFO rParse;
PARSESTRINGINFO rTemp;
CHAR szScratch[255],
szFileName[MAX_PATH];
ULONG i,
iString;
BOOL fValid;
// Invalid Arg
if (NULL == pPropertySet || NULL == pszFileName || NULL == pulPart || NULL == pulTotal)
return TrapError(E_INVALIDARG);
// Zero the Structure
ZeroMemory(&rParse, sizeof(PARSESTRINGINFO));
// Init
*pulPart = 0;
*pulTotal = 0;
*pszFileName = '\0';
*szFileName = '\0';
// Init
rSubject.vt = VT_LPSTR;
rSubject.pszVal = NULL;
// Get the subject
CHECKHR(hr = pPropertySet->GetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &rSubject));
// Set the Members
rParse.cpiCodePage = CP_ACP;
rParse.pszString = rSubject.pszVal;
rParse.cchString = lstrlen(rSubject.pszVal);
rParse.pszScratch = szScratch;
rParse.pszValue = szScratch;
rParse.cchValMax = sizeof(szScratch);
rParse.dwFlags = PARSTR_SKIP_FORWARD_WS | PARSTR_STRIP_TRAILING_WS | PARSTR_GROW_VALUE_ALLOWED;
// Initialize My String Parser
MimeOleSetParseTokens(&rParse, " ([");
// Loop for a while
while(1)
{
// Parse up to colon
CHECKHR(hr = MimeOleParseString(&rParse));
// Done
if (rParse.fDone)
break;
// Space, just save the last value
if (' ' == rParse.chToken)
{
// Less than MAX_PATH
if (rParse.cchValue < MAX_PATH)
StrCpyN(szFileName, rParse.pszValue, ARRAYSIZE(szFileName));
}
// Loop Next few characters (001\010)
else
{
// Less than MAX_PATH
if (rParse.cchValue && rParse.cchValue < MAX_PATH)
StrCpyN(szFileName, rParse.pszValue, ARRAYSIZE(szFileName));
// Save the Current State
iString = rParse.iString;
// Find the Ending Token
if ('(' == rParse.chToken)
MimeOleSetParseTokens(&rParse, ")");
else
MimeOleSetParseTokens(&rParse, "]");
// Parse up to colon
CHECKHR(hr = MimeOleParseString(&rParse));
// Done
if (rParse.fDone)
break;
// (000/000) All Numbers in rParse.pszValue are numbers
for (fValid=TRUE, i=0; i<rParse.cchValue; i++)
{
// End of Part Number
if ('/' == rParse.pszValue[i])
{
rParse.pszValue[i] = '\0';
*pulPart = StrToInt(rParse.pszValue);
*pulTotal = StrToInt((rParse.pszValue + i + 1));
}
// Digit
else if (IsDigit(rParse.pszValue) == FALSE)
{
fValid = FALSE;
break;
}
}
// Valid ?
if (fValid)
{
// Dup It
StrCpyN(pszFileName, szFileName, cchMax);
// Done
goto exit;
}
// Reset Parser
rParse.iString = iString;
// Initialize My String Parser
MimeOleSetParseTokens(&rParse, " ([");
}
}
// Not Found
hr = MIME_E_NOT_FOUND;
exit:
// Cleanup
SafeMemFree(rSubject.pszVal);
MimeOleFreeParseString(&rParse);
// Done
return hr;
#endif
}
// --------------------------------------------------------------------------------
// MimeOleCreateWebDocument
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleCreateWebDocument(
LPCSTR pszBase,
LPCSTR pszURL,
IMimeWebDocument **ppDocument)
{
// Locals
HRESULT hr=S_OK;
CMimeWebDocument *pDocument=NULL;
// Invalid Arg
if (NULL == pszURL || NULL == ppDocument)
return TrapError(E_INVALIDARG);
// Create a Web Document Object
CHECKALLOC(pDocument = new CMimeWebDocument);
// Initialize It
CHECKHR(hr = pDocument->HrInitialize(pszBase, pszURL));
// Return It
*ppDocument = (IMimeWebDocument *)pDocument;
(*ppDocument)->AddRef();
exit:
// Cleanup
SafeRelease(pDocument);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleComputeContentBase
// --------------------------------------------------------------------------------
HRESULT MimeOleComputeContentBase(IMimeMessage *pMessage, HBODY hRelated,
LPSTR *ppszBase, BOOL *pfMultipartBase)
{
// Locals
HRESULT hr=S_OK;
HBODY hBase=NULL;
// Init
if (pfMultipartBase)
*pfMultipartBase = FALSE;
// If no hRelated was passed in, lets try to find one
if (NULL == hRelated)
{
// Find the related section
if (FAILED(MimeOleGetRelatedSection(pMessage, FALSE, &hRelated, NULL)))
{
// Get the root body
pMessage->GetBody(IBL_ROOT, NULL, &hRelated);
}
}
// Get the text/html body
if (FAILED(pMessage->GetTextBody(TXT_HTML, IET_BINARY, NULL, &hBase)))
hBase = hRelated;
// No Base
if (NULL == hBase)
{
hr = E_FAIL;
goto exit;
}
// Call utility function
*ppszBase = MimeOleContentBaseFromBody(pMessage, hBase);
// If that failed and we used the text body
if (NULL == *ppszBase && hRelated && hBase != hRelated)
*ppszBase = MimeOleContentBaseFromBody(pMessage, hRelated);
// Did this come from the multipart related
if (NULL != *ppszBase && hBase == hRelated && pfMultipartBase)
*pfMultipartBase = TRUE;
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleContentBaseFromBody
// --------------------------------------------------------------------------------
LPSTR MimeOleContentBaseFromBody(IMimeMessageTree *pTree, HBODY hBody)
{
// Locals
PROPVARIANT rVariant;
// Setup Variant
rVariant.vt = VT_LPSTR;
rVariant.pszVal = NULL;
// Get Content-Base first, and then try Content-Location
if (FAILED(pTree->GetBodyProp(hBody, PIDTOSTR(PID_HDR_CNTBASE), NOFLAGS, &rVariant)))
{
// Try Content-Location
if (FAILED(pTree->GetBodyProp(hBody, PIDTOSTR(PID_HDR_CNTLOC), NOFLAGS, &rVariant)))
rVariant.pszVal = NULL;
}
// Return
return rVariant.pszVal;
}
// --------------------------------------------------------------------------------
// MimeOleGetRelatedSection
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetRelatedSection(
IMimeMessageTree *pTree,
boolean fCreate,
LPHBODY phRelated,
boolean *pfMultiple)
{
// Locals
HRESULT hr=S_OK;
HBODY hRoot;
FINDBODY rFind;
PROPVARIANT rVariant;
// Invalid Args
if (NULL == pTree || NULL == phRelated)
return TrapError(E_INVALIDARG);
// Init
ZeroMemory(&rFind, sizeof(FINDBODY));
// Find first multipart/related section
rFind.pszPriType = (LPSTR)STR_CNT_MULTIPART;
rFind.pszSubType = (LPSTR)STR_SUB_RELATED;
// Init
if (pfMultiple)
*pfMultiple = FALSE;
// Find First
if (SUCCEEDED(pTree->FindFirst(&rFind, phRelated)))
{
// Is there another multipart/related section
if (pfMultiple && SUCCEEDED(pTree->FindNext(&rFind, &hRoot)))
*pfMultiple = TRUE;
// Done
goto exit;
}
// If no Create, fail
if (FALSE == fCreate)
{
hr = TrapError(MIME_E_NOT_FOUND);
goto exit;
}
// Get the Root Body
CHECKHR(hr = pTree->GetBody(IBL_ROOT, NULL, &hRoot));
// Setup Variant
rVariant.vt = VT_LPSTR;
rVariant.pszVal = (LPSTR)STR_MIME_MPART_RELATED;
// If Root is empty
if (pTree->IsBodyType(hRoot, IBT_EMPTY) == S_OK)
{
// Set the Content Type
CHECKHR(hr = pTree->SetBodyProp(hRoot, PIDTOSTR(PID_HDR_CNTTYPE), 0, &rVariant));
// Set phRelated
*phRelated = hRoot;
}
// If root is non-multipart, convert it to multipart/related
else if (pTree->IsContentType(hRoot, STR_CNT_MULTIPART, NULL) == S_FALSE)
{
// Conver this body to a multipart/related
CHECKHR(hr = pTree->ToMultipart(hRoot, STR_SUB_RELATED, phRelated));
}
// Otherwise, if root is multipart/mixed
else if (pTree->IsContentType(hRoot, NULL, STR_SUB_MIXED) == S_OK)
{
// Insert First Child of multipart/mixed as multipart/related
CHECKHR(hr = pTree->InsertBody(IBL_FIRST, hRoot, phRelated));
// Set the Content Type
CHECKHR(hr = pTree->SetBodyProp(*phRelated, PIDTOSTR(PID_HDR_CNTTYPE), 0, &rVariant));
}
// Otherwise, if root is multipart/alternative
else if (pTree->IsContentType(HBODY_ROOT, NULL, STR_SUB_ALTERNATIVE) == S_OK)
{
// Convert this body to a multipart/related (alternative becomes first child)
CHECKHR(hr = pTree->ToMultipart(HBODY_ROOT, STR_SUB_RELATED, phRelated));
// Should I set multipart/related; start=multipart/alternative at this point ?
}
// Otherwise, for unknown multipart content types
else
{
// Convert this body to a multipart/related
CHECKHR(hr = pTree->ToMultipart(HBODY_ROOT, STR_SUB_RELATED, phRelated));
}
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleGetMixedSection
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetMixedSection(
IMimeMessageTree *pTree,
boolean fCreate,
LPHBODY phMixed,
boolean *pfMultiple)
{
// Locals
HRESULT hr=S_OK;
HBODY hTemp;
HBODY hRoot;
FINDBODY rFind;
PROPVARIANT rVariant;
// Invalid Args
if (NULL == pTree || NULL == phMixed)
return TrapError(E_INVALIDARG);
// Init
ZeroMemory(&rFind, sizeof(FINDBODY));
// Find first multipart/mixed section
rFind.pszPriType = (LPSTR)STR_CNT_MULTIPART;
rFind.pszSubType = (LPSTR)STR_SUB_MIXED;
// Find First
if (SUCCEEDED(pTree->FindFirst(&rFind, phMixed)))
{
// Is there another multipart/mixed section
if (pfMultiple && SUCCEEDED(pTree->FindNext(&rFind, &hTemp)))
*pfMultiple = TRUE;
// Done
goto exit;
}
// Init
if (pfMultiple)
*pfMultiple = FALSE;
// If no Create, fail
if (FALSE == fCreate)
{
hr = TrapError(MIME_E_NOT_FOUND);
goto exit;
}
// Get the Root Body
CHECKHR(hr = pTree->GetBody(IBL_ROOT, NULL, &hRoot));
// If Root is empty
if (pTree->IsBodyType(hRoot, IBT_EMPTY) == S_OK)
{
// Setup Variant
rVariant.vt = VT_LPSTR;
rVariant.pszVal = (LPSTR)STR_MIME_MPART_MIXED;
// Set the Content Type
CHECKHR(hr = pTree->SetBodyProp(hRoot, PIDTOSTR(PID_HDR_CNTTYPE), 0, &rVariant));
// Set phRelated
*phMixed = hRoot;
}
// Otherwise, convert it to a multipart
else
{
// Conver this body to a multipart/mixed
CHECKHR(hr = pTree->ToMultipart(HBODY_ROOT, STR_SUB_MIXED, phMixed));
}
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleGetAlternativeSection
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetAlternativeSection(
IMimeMessageTree *pTree,
LPHBODY phAlternative,
boolean *pfMultiple)
{
// Locals
HRESULT hr=S_OK;
HBODY hTemp;
FINDBODY rFind;
// Invalid Args
if (NULL == pTree || NULL == phAlternative)
return TrapError(E_INVALIDARG);
// Init
ZeroMemory(&rFind, sizeof(FINDBODY));
// Find first multipart/mixed section
rFind.pszPriType = (LPSTR)STR_CNT_MULTIPART;
rFind.pszSubType = (LPSTR)STR_SUB_ALTERNATIVE;
// Find First
if (SUCCEEDED(pTree->FindFirst(&rFind, phAlternative)))
{
// Is there another multipart/mixed section
if (pfMultiple && SUCCEEDED(pTree->FindNext(&rFind, &hTemp)))
*pfMultiple = TRUE;
// Done
goto exit;
}
// Init
if (pfMultiple)
*pfMultiple = FALSE;
// If no Create, fail
hr = TrapError(MIME_E_NOT_FOUND);
exit:
// Done
return hr;
}
// ------------------------------------------------------------------------------------------
// MimeOleGenerateCID
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGenerateCID(LPSTR pszCID, ULONG cchMax, boolean fAbsolute)
{
// Locals
HRESULT hr=S_OK;
ULONG cch;
FILETIME ft;
SYSTEMTIME st;
WORD wCounter;
// Invalid Arg
if (NULL == pszCID)
return TrapError(E_INVALIDARG);
// Get Current Time
GetSystemTime(&st);
// Convert to FileTime
SystemTimeToFileTime(&st, &ft);
// Build MessageID
if (FALSE == fAbsolute)
cch = wnsprintfA(pszCID, cchMax, "%04x%08.8lx$%08.8lx$%s@%s", DwCounterNext(), ft.dwHighDateTime, ft.dwLowDateTime, (LPTSTR)SzGetLocalPackedIP(), PszGetDomainName());
else
cch = wnsprintfA(pszCID, cchMax, "CID:%04x%08.8lx$%08.8lx$%s@%s", DwCounterNext(), ft.dwHighDateTime, ft.dwLowDateTime, (LPTSTR)SzGetLocalPackedIP(), PszGetDomainName());
// Buffer Overwrite
Assert(cch + 1 <= CCHMAX_CID);
// Done
return hr;
}
// ------------------------------------------------------------------------------------------
// MimeOleGenerateMID
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGenerateMID(LPSTR pszMID, ULONG cchMax, boolean fAbsolute)
{
// Locals
HRESULT hr=S_OK;
ULONG cch;
FILETIME ft;
SYSTEMTIME st;
WORD wCounter;
// Invalid Arg
if (NULL == pszMID || cchMax < CCHMAX_MID)
return TrapError(E_INVALIDARG);
// Get Current Time
GetSystemTime(&st);
// Convert to FileTime
SystemTimeToFileTime(&st, &ft);
// Build MessageID
if (FALSE == fAbsolute)
cch = wnsprintfA(pszMID, cchMax, "<%04x%08.8lx$%08.8lx$%s@%s>", DwCounterNext(), ft.dwHighDateTime, ft.dwLowDateTime, (LPTSTR)SzGetLocalPackedIP(), PszGetDomainName());
else
cch = wnsprintfA(pszMID, cchMax, "MID:%04x%08.8lx$%08.8lx$%s@%s", DwCounterNext(), ft.dwHighDateTime, ft.dwLowDateTime, (LPTSTR)SzGetLocalPackedIP(), PszGetDomainName());
// Buffer Overwrite
Assert(cch + 1 <= CCHMAX_MID);
// Done
return hr;
}
// ------------------------------------------------------------------------------------------
// MimeOleCreateByteStream
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleCreateByteStream(
IStream **ppStream)
{
// Locals
HRESULT hr=S_OK;
// Invalid Arg
if (NULL == ppStream)
return TrapError(E_INVALIDARG);
// Alocate It
CHECKALLOC((*ppStream) = new CByteStream);
exit:
// Done
return hr;
}
// ------------------------------------------------------------------------------------------
// MimeOleGetPropertySchema
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetPropertySchema(
IMimePropertySchema **ppSchema)
{
// Locals
HRESULT hr=S_OK;
// check params
if (NULL == ppSchema)
return TrapError(E_INVALIDARG);
// Out of memory
if (NULL == g_pSymCache)
return TrapError(E_OUTOFMEMORY);
// Create me
*ppSchema = (IMimePropertySchema *)g_pSymCache;
// Add Ref
(*ppSchema)->AddRef();
// Done
return S_OK;
}
// ------------------------------------------------------------------------------------------
// MimeOleCreateHeaderTable
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleCreateHeaderTable(IMimeHeaderTable **ppTable)
{
// Locals
HRESULT hr=S_OK;
LPCONTAINER pContainer=NULL;
// check params
if (NULL == ppTable)
return TrapError(E_INVALIDARG);
// Create a new Container Object
CHECKALLOC(pContainer = new CMimePropertyContainer);
// Init
CHECKHR(hr = pContainer->InitNew());
// Bind to Header table
CHECKHR(hr = pContainer->QueryInterface(IID_IMimeHeaderTable, (LPVOID *)ppTable));
exit:
// Failure
SafeRelease(pContainer);
// Done
return hr;
}
// ------------------------------------------------------------------------------------------
// MimeOleCreateVirtualStream
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleCreateVirtualStream(IStream **ppStream)
{
// Locals
HRESULT hr=S_OK;
// check params
if (NULL == ppStream)
return TrapError(E_INVALIDARG);
// Allocate Virtual Stream
*ppStream = new CVirtualStream;
if (NULL == *ppStream)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
exit:
// Done
return hr;
}
// ------------------------------------------------------------------------------------------
// MimeOleOpenFileStream
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleOpenFileStream(LPCSTR pszFilePath, DWORD dwCreationDistribution, DWORD dwAccess, IStream **ppstmFile)
{
// Invalid Arg
if (NULL == pszFilePath || NULL == ppstmFile)
return TrapError(E_INVALIDARG);
// Call Internal Tool
return OpenFileStream((LPSTR)pszFilePath, dwCreationDistribution, dwAccess, ppstmFile);
}
// ------------------------------------------------------------------------------------------
// MimeOleIsEnrichedStream, text must start with <x-rich>
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleIsEnrichedStream(IStream *pStream)
{
// Locals
HRESULT hr=S_OK;
LPSTR pszT;
BYTE rgbBuffer[30 + 1];
ULONG cbRead;
// Invalid Arg
if (NULL == pStream)
return TrapError(E_INVALIDARG);
// Rewind the stream
CHECKHR(hr = HrRewindStream(pStream));
// Read the first four bytes
CHECKHR(hr = pStream->Read(rgbBuffer, sizeof(rgbBuffer) - 1, &cbRead));
// Less than four bytes read ?
if (cbRead < (ULONG)lstrlen(c_szXRich))
{
hr = S_FALSE;
goto exit;
}
// Stick in a null
rgbBuffer[cbRead] = '\0';
// Skip White Space
pszT = (LPSTR)rgbBuffer;
// Skip White
pszT = PszSkipWhiteA(pszT);
if ('\0' == *pszT)
{
hr = S_FALSE;
goto exit;
}
// Compare
if (StrCmpNI(pszT, c_szXRich, lstrlen(c_szXRich)) != 0)
{
hr = S_FALSE;
goto exit;
}
exit:
// Done
return hr;
}
// ------------------------------------------------------------------------------------------
// MimeOleIsTnefStream
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleIsTnefStream(IStream *pStream)
{
// Locals
HRESULT hr=S_OK;
BYTE rgbSignature[4];
ULONG cbRead;
// Invalid Arg
if (NULL == pStream)
return TrapError(E_INVALIDARG);
// Read the first four bytes
CHECKHR(hr = pStream->Read(rgbSignature, sizeof(rgbSignature), &cbRead));
// Less than four bytes read ?
if (cbRead < 4)
{
hr = S_FALSE;
goto exit;
}
// Compare bytes
if (rgbSignature[0] != 0x78 && rgbSignature[1] != 0x9f &&
rgbSignature[2] != 0x3e && rgbSignature[3] != 0x22)
{
hr = S_FALSE;
goto exit;
}
// Its TNEF
hr = S_OK;
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleGenerateFileName
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGenerateFileName(LPCSTR pszContentType, LPCSTR pszSuggest, LPCSTR pszDefaultExt, LPSTR *ppszFileName)
{
// Locals
HRESULT hr=S_OK;
LPSTR pszExt=NULL,
pszName=NULL;
CHAR szName[10];
LPCSTR pszExtension=NULL,
pszPrefix=NULL;
// Invalid Arg
if (NULL == ppszFileName)
return TrapError(E_INVALIDARG);
// Init
*ppszFileName = NULL;
// Find a filename extension
if (pszContentType)
{
// Get the content type...
if (SUCCEEDED(MimeOleGetContentTypeExt(pszContentType, &pszExt)))
pszExtension = (LPCSTR)pszExt;
}
// Extension is still null
if (NULL == pszExtension)
{
// Use default extension...
if (pszDefaultExt)
pszExtension = pszDefaultExt;
// Otherwise, internal default
else
pszExtension = c_szDotDat;
}
// We Should have an extension
Assert(pszExtension);
// Suggested file name ?
if (pszSuggest)
{
// Dup It
pszName = PszDupA(pszSuggest);
if (NULL == pszName)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
// Dupit and remove illegal filename characters...
CleanupFileNameInPlaceA(CP_ACP, pszName);
// Set Prefix
pszPrefix = (LPCSTR)pszName;
}
// Otherwise, build a filename...
else
{
// Locals
CHAR szNumber[30];
// Get a number...
wnsprintfA(szNumber, ARRAYSIZE(szNumber), "%05d", DwCounterNext());
// Allocate pszName
wnsprintfA(szName, ARRAYSIZE(szName), "ATT%s", szNumber);
// Set Prefix
pszPrefix = (LPCSTR)szName;
}
// Build Final FileNmae= pszPrefix + pszExtension + dot + null
DWORD cchSize = (lstrlen(pszPrefix) + lstrlen(pszExtension) + 2);
*ppszFileName = PszAllocA(cchSize);
if (NULL == *ppszFileName)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
// Build filename
wnsprintfA(*ppszFileName, cchSize, "%s%s", pszPrefix, pszExtension);
exit:
// Failure
if (FAILED(hr) && E_OUTOFMEMORY != hr)
{
// Assume Success
hr = S_OK;
// Use default Attachment name
*ppszFileName = PszDupA(c_szDefaultAttach);
// Memory Failure
if (NULL == *ppszFileName)
hr = TrapError(E_OUTOFMEMORY);
}
// Cleanup
SafeMemFree(pszExt);
SafeMemFree(pszName);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleGenerateFileNameW
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGenerateFileNameW(LPCSTR pszContentType, LPCWSTR pszSuggest,
LPCWSTR pszDefaultExt, LPWSTR *ppszFileName)
{
// Locals
HRESULT hr=S_OK;
LPSTR pszExtA=NULL;
LPWSTR pszExtW=NULL;
LPWSTR pszName=NULL;
WCHAR szName[10];
LPWSTR pszExtension=NULL;
LPWSTR pszPrefix=NULL;
int cch = 0;
// Invalid Arg
if (NULL == ppszFileName)
return TrapError(E_INVALIDARG);
// Init
*ppszFileName = NULL;
// Find a filename extension
if (pszContentType)
{
// Get the content type...
if (SUCCEEDED(MimeOleGetContentTypeExt(pszContentType, &pszExtA)))
{
// I'm going to convert to unicode because I assume extensions are usascii
IF_NULLEXIT(pszExtW = PszToUnicode(CP_ACP, pszExtA));
// Save as the extension
pszExtension = pszExtW;
}
}
// Extension is still null
if (NULL == pszExtension)
{
// Use default extension...
if (pszDefaultExt)
pszExtension = (LPWSTR)pszDefaultExt;
// Otherwise, internal default
else
pszExtension = (LPWSTR)c_wszDotDat;
}
// We Should have an extension
Assert(pszExtension);
// Suggested file name ?
if (pszSuggest)
{
// Dup It
IF_NULLEXIT(pszName = PszDupW(pszSuggest));
// Dupit and remove illegal filename characters...
CleanupFileNameInPlaceW(pszName);
// Set Prefix
pszPrefix = pszName;
}
// Otherwise, build a filename...
else
{
// Locals
WCHAR szNumber[30];
// Get a number...
wnsprintfW(szNumber, ARRAYSIZE(szNumber), L"%05d", DwCounterNext());
// Allocate pszName
wnsprintfW(szName, ARRAYSIZE(szName), L"ATT%s", szNumber);
// Set Prefix
pszPrefix = szName;
}
// Build Final FileNmae= pszPrefix + pszExtension + dot + null
cch = lstrlenW(pszPrefix) + lstrlenW(pszExtension) + 2;
IF_NULLEXIT(*ppszFileName = PszAllocW(cch));
// Build filename
wnsprintfW(*ppszFileName, cch, L"%s%s", pszPrefix, pszExtension);
exit:
// Failure
if (FAILED(hr) && E_OUTOFMEMORY != hr)
{
// Assume Success
hr = S_OK;
// Use default Attachment name
*ppszFileName = PszDupW(c_wszDefaultAttach);
// Memory Failure
if (NULL == *ppszFileName)
hr = TrapError(E_OUTOFMEMORY);
}
// Cleanup
SafeMemFree(pszExtA);
SafeMemFree(pszExtW);
SafeMemFree(pszName);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CreateMimeSecurity
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
{
// check params
if (NULL == ppSecurity)
return TrapError(E_INVALIDARG);
// Create the object
*ppSecurity = (IMimeSecurity *) new CSMime;
if (NULL == *ppSecurity)
return TrapError(E_OUTOFMEMORY);
// Done
return S_OK;
}
// ------------------------------------------------------------------------------------------
// MimeOleCreateMessageParts
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleCreateMessageParts(IMimeMessageParts **ppParts)
{
// Locals
HRESULT hr=S_OK;
CMimeMessageParts *pParts=NULL;
// check params
if (NULL == ppParts)
return TrapError(E_INVALIDARG);
// Init
*ppParts = NULL;
// Allocate Message Parts
pParts = new CMimeMessageParts;
if (NULL == pParts)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
// Success
*ppParts = pParts;
(*ppParts)->AddRef();
exit:
// Done
SafeRelease(pParts);
// Done
return hr;
}
// ------------------------------------------------------------------------------------------
// MimeOleGetAllocator
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetAllocator(IMimeAllocator **ppMalloc)
{
// Locals
HRESULT hr=S_OK;
// check params
if (NULL == ppMalloc)
return TrapError(E_INVALIDARG);
// Allocate MimeOleMalloc
*ppMalloc = new CMimeAllocator;
if (NULL == *ppMalloc)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
exit:
// Done
return hr;
}
// ------------------------------------------------------------------------------------------
// MimeOleCreateMessage
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleCreateHashTable(DWORD dwSize, BOOL fDupeKeys, IHashTable **ppHashTable)
{
// Locals
HRESULT hr=S_OK;
IHashTable *pHash;
// check params
if (NULL == ppHashTable)
return TrapError(E_INVALIDARG);
// Init
*ppHashTable = NULL;
// Allocate MimeMessage
CHECKALLOC(pHash = new CHash(NULL));
// Init New
CHECKHR(hr = pHash->Init(dwSize, fDupeKeys));
// Success
*ppHashTable = pHash;
(*ppHashTable)->AddRef();
exit:
// Done
SafeRelease(pHash);
// Done
return hr;
}
// ------------------------------------------------------------------------------------------
// MimeOleCreateMessage
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
{
// Locals
HRESULT hr=S_OK;
LPMESSAGETREE pTree=NULL;
// check params
if (NULL == ppMessage)
return TrapError(E_INVALIDARG);
// Init
*ppMessage = NULL;
// Allocate MimeMessage
CHECKALLOC(pTree = new CMessageTree(pUnkOuter));
// Init New
CHECKHR(hr = pTree->InitNew());
// Success
*ppMessage = pTree;
(*ppMessage)->AddRef();
exit:
// Done
SafeRelease(pTree);
// Done
return hr;
}
// ------------------------------------------------------------------------------------------
// MimeOleCreateMessageTree
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleCreateMessageTree(IUnknown *pUnkOuter, IMimeMessageTree **ppMessageTree)
{
// Locals
HRESULT hr=S_OK;
LPMESSAGETREE pTree=NULL;
// check params
if (NULL == ppMessageTree)
return TrapError(E_INVALIDARG);
// INit
*ppMessageTree = NULL;
// Allocate MimeMessageTree
CHECKALLOC(pTree = new CMessageTree(pUnkOuter));
// Init New
CHECKHR(hr = pTree->InitNew());
// Success
*ppMessageTree = pTree;
(*ppMessageTree)->AddRef();
exit:
// Done
SafeRelease(pTree);
// Done
return hr;
}
// ------------------------------------------------------------------------------------------
// MimeOleCreatePropertySet
// ------------------------------------------------------------------------------------------
MIMEOLEAPI MimeOleCreatePropertySet(IUnknown *pUnkOuter, IMimePropertySet **ppPropertySet)
{
// Locals
HRESULT hr=S_OK;
LPMESSAGEBODY pBody=NULL;
// check params
if (NULL == ppPropertySet)
return TrapError(E_INVALIDARG);
// Init
*ppPropertySet = NULL;
// Allocate MimePropertySet
CHECKALLOC(pBody = new CMessageBody(NULL, pUnkOuter));
// Init New
CHECKHR(hr = pBody->InitNew());
// Success
*ppPropertySet = (IMimePropertySet *)pBody;
(*ppPropertySet)->AddRef();
exit:
// Done
SafeRelease(pBody);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleMergePartialHeaders
// -------------------------------
// Rules
// -----
// (1) All of the header fields from the initial enclosing entity
// (part one), except those that start with "Content-" and the
// specific header fields "Message-ID", "Encrypted", and "MIME-
// Version", must be copied, in order, to the new message.
//
// (2) Only those header fields in the enclosed message which start
// with "Content-" and "Message-ID", "Encrypted", and "MIME-Version"
// must be appended, in order, to the header fields of the new
// message. Any header fields in the enclosed message which do not
// start with "Content-" (except for "Message-ID", "Encrypted", and
// "MIME-Version") will be ignored.
//
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleMergePartialHeaders(IStream *pstmIn, IStream *pstmOut)
{
// Locals
HRESULT hr = S_OK;
LPCONTAINER pc1=NULL;
LPCONTAINER pc2=NULL;
ULONG i;
ULONG cboffStart;
CInternetStream cInternet;
LONG iColon;
PROPSTRINGA rHeader;
PROPVARIANT rOption;
// check params
if (NULL == pstmIn || NULL == pstmOut)
return TrapError(E_INVALIDARG);
// Create text stream object
CHECKHR(hr = cInternet.HrInitNew(pstmIn));
// Create Property Sets
CHECKALLOC(pc1 = new CMimePropertyContainer);
CHECKALLOC(pc2 = new CMimePropertyContainer);
// Init
CHECKHR(hr = pc1->InitNew());
CHECKHR(hr = pc2->InitNew());
// Load the first header
CHECKHR(hr = pc1->Load(&cInternet));
// RAID-18376: POPDOG adds extra lines after the header, so I must read the blank lines
// until I hit the next header, then backup.
while(1)
{
// Get current position
cboffStart = cInternet.DwGetOffset();
// Read a line
CHECKHR(hr = cInternet.HrReadHeaderLine(&rHeader, &iColon));
// If line is not empty, assume its the start of the next header...
if ('\0' != *rHeader.pszVal)
{
// Line better have a length
Assert(rHeader.cchVal);
// Reset position back to cboffStart
cInternet.Seek(cboffStart);
// Done
break;
}
}
// Load the second header
CHECKHR(hr = pc2->Load(&cInternet));
// Delete Props From Header 1
for (i=0; i<ARRAYSIZE(g_rgszPartialPids); i++)
pc1->DeleteProp(g_rgszPartialPids[i]);
// Delete Except from header 2
pc2->DeleteExcept(ARRAYSIZE(g_rgszPartialPids), g_rgszPartialPids);
// Save as Mime
rOption.vt = VT_UI4;
rOption.ulVal = SAVE_RFC1521;
// Store Some Options
pc1->SetOption(OID_SAVE_FORMAT, &rOption);
pc2->SetOption(OID_SAVE_FORMAT, &rOption);
// Don't default to text/plain if Content-Type is not yet set...
rOption.vt = VT_BOOL;
rOption.boolVal = TRUE;
pc1->SetOption(OID_NO_DEFAULT_CNTTYPE, &rOption);
pc2->SetOption(OID_NO_DEFAULT_CNTTYPE, &rOption);
// Save Header 1
CHECKHR(hr = pc1->Save(pstmOut, TRUE));
CHECKHR(hr = pc2->Save(pstmOut, TRUE));
exit:
// Cleanup
SafeRelease(pc1);
SafeRelease(pc2);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleParseRfc822Address
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleParseRfc822Address(
DWORD dwAdrType,
ENCODINGTYPE ietEncoding,
LPCSTR pszRfc822Adr,
LPADDRESSLIST pList)
{
// Locals
CMimePropertyContainer cContainer;
// Parse the address
return cContainer.ParseRfc822(dwAdrType, ietEncoding, pszRfc822Adr, pList);
}
// --------------------------------------------------------------------------------
// MimeOleParseRfc822Address
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleParseRfc822AddressW(
DWORD dwAdrType,
LPCWSTR pwszRfc822Adr,
LPADDRESSLIST pList)
{
// Locals
CMimePropertyContainer cContainer;
// Parse the address
return cContainer.ParseRfc822W(dwAdrType, pwszRfc822Adr, pList);
}
// --------------------------------------------------------------------------------
// MimeOleGetInternat
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetInternat(IMimeInternational **ppInternat)
{
// check params
if (NULL == ppInternat)
return TrapError(E_INVALIDARG);
// Out of memory
if (NULL == g_pInternat)
return TrapError(E_OUTOFMEMORY);
// Assume Global
*ppInternat = (IMimeInternational *)g_pInternat;
// Set database
(*ppInternat)->AddRef();
// Done
return S_OK;
}
// --------------------------------------------------------------------------------
// MimeOleSplitContentType
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleSplitContentType(LPWSTR pszFull, LPWSTR *ppszCntType, LPWSTR *ppszSubType)
{
// Locals
HRESULT hr = E_FAIL;
LPWSTR pszFreeMe = NULL,
psz = NULL,
pszStart;
// check params
if (NULL == pszFull)
return TrapError(E_INVALIDARG);
// Lets dup pszFull to make sure we have read access
psz = pszFreeMe = PszDupW(pszFull);
if (NULL == psz)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
// Find '/'
pszStart = psz;
while(*psz && *psz != L'/')
psz++;
// If not found, return
if (L'\0' == *psz)
goto exit;
// Otherwise stuff a null
*psz = L'\0';
// Dup
*ppszCntType = PszDupW(pszStart);
if (NULL == *ppszCntType)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
// Step over
*psz = L'/';
psz++;
// If not found, return
if (L'\0' == *psz)
goto exit;
// Save position
pszStart = psz;
while(*psz && L';' != *psz)
psz++;
// Save character...
*psz = L'\0';
// Dup as sub type
*ppszSubType = PszDupW(pszStart);
if (NULL == *ppszSubType)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
// Success
hr = S_OK;
exit:
// If failed
if (FAILED(hr))
{
SafeMemFree((*ppszCntType));
SafeMemFree((*ppszSubType));
}
// Cleanup
SafeMemFree(pszFreeMe);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeEscapeString - quotes '"' and '\'
//
// Returns S_OK if *ppszOut was allocated and set to the escaped string
// Retruns S_FALSE if *ppszOut is NULL - pszIn did not require escaping
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleEscapeString(CODEPAGEID cpiCodePage, LPCSTR pszIn, LPSTR *ppszOut)
{
// Locals
HRESULT hr=S_FALSE;
LPSTR pszOut,
psz;
ULONG cb,
c;
// check parameters
if (NULL == pszIn || NULL == ppszOut)
return TrapError(E_INVALIDARG);
// $$ INFO $$ This is basically as fast as doing an lstrlen
// I've decided to first detect if we need to escape
c = 0;
cb = 0;
psz = (LPSTR)pszIn;
while (*psz)
{
// If DBCS Lead-Byte, then skip
if (IsDBCSLeadByteEx(cpiCodePage, *psz))
{
cb += 2;
psz += 2;
}
// Otherwise, text for escaped character
else
{
// Count the number of character to escape
if ('\"' == *psz || '\\' == *psz || '(' == *psz || ')' == *psz)
c++;
// Step one more character
psz++;
cb++;
}
}
// No escape needed
if (0 == c)
goto exit;
// Adjust number of bytes to allocate
cb += (c + 1);
// worst case - escape every character, so use double original strlen
CHECKHR(hr = HrAlloc((LPVOID *)ppszOut, cb));
// Start copy
psz = (LPSTR)pszIn;
pszOut = *ppszOut;
while (*psz)
{
// If DBCS Lead-Byte, then skip
if (IsDBCSLeadByteEx(cpiCodePage, *psz))
{
*pszOut++ = *psz++;
*pszOut++ = *psz++;
}
// Otherwise, non-DBCS
else
{
// Do escape
if ('\"' == *psz || '\\' == *psz || '(' == *psz || ')' == *psz)
*pszOut++ = '\\';
// Regular char
*pszOut++ = *psz++;
}
}
// Null term
*pszOut = '\0';
exit:
// Done
return hr;
}
MIMEOLEAPI MimeOleUnEscapeStringInPlace(LPSTR pszIn)
{
HRESULT hr = S_OK;
ULONG cchOffset = 0;
ULONG i = 0;
IF_TRUEEXIT((pszIn == NULL), E_INVALIDARG);
for(;;i++)
{
if((pszIn[i + cchOffset] == '\\') &&
(pszIn[i + cchOffset + 1] == '\\' ||
pszIn[i + cchOffset + 1] == '\"' ||
pszIn[i + cchOffset + 1] == '(' ||
pszIn[i + cchOffset + 1] == ')'))
cchOffset++;
pszIn[i] = pszIn[i + cchOffset];
if(pszIn[i] == 0)
break;
}
exit:
return hr;
}
// --------------------------------------------------------------------------------
// MimeEscapeString - quotes '"' and '\'
//
// Returns S_OK if *ppszOut was allocated and set to the escaped string
// Retruns S_FALSE if *ppszOut is NULL - pszIn did not require escaping
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleEscapeStringW(LPCWSTR pszIn, LPWSTR *ppszOut)
{
// Locals
HRESULT hr=S_FALSE;
LPWSTR pszOut;
LPWSTR psz;
ULONG cch;
ULONG cchExtra;
// check parameters
if (NULL == pszIn || NULL == ppszOut)
return TrapError(E_INVALIDARG);
// $$ INFO $$ This is basically as fast as doing an lstrlen
// I've decided to first detect if we need to escape
cchExtra = 0;
cch = 0;
psz = (LPWSTR)pszIn;
while (*psz)
{
// Count the number of character to escape
if (L'\"' == *psz || L'\\' == *psz || L'(' == *psz || L')' == *psz)
cchExtra++;
// Step one more character
psz++;
cch++;
}
// No escape needed
if (0 == cchExtra)
goto exit;
// Adjust number of bytes to allocate
cch += (cchExtra + 1);
// worst case - escape every character, so use double original strlen
CHECKHR(hr = HrAlloc((LPVOID *)ppszOut, cch * sizeof(WCHAR)));
// Start copy
psz = (LPWSTR)pszIn;
pszOut = *ppszOut;
while (*psz)
{
// Do escape
if (L'\"' == *psz || L'\\' == *psz || L'(' == *psz || L')' == *psz)
*pszOut++ = L'\\';
// Regular char
*pszOut++ = *psz++;
}
// Null term
*pszOut = L'\0';
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleGetFileExtension
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetFileExtension(LPCSTR pszFilePath, LPSTR pszExt, ULONG cchMax)
{
// Locals
CHAR *pszExtT;
// Invalid Arg
if (NULL == pszFilePath || NULL == pszExt || cchMax < _MAX_EXT)
return TrapError(E_INVALIDARG);
// Locate the extension of the file
pszExtT = PathFindExtension(pszFilePath);
StrCpyN(pszExt, pszExtT, cchMax);
// Done
return S_OK;
}
// --------------------------------------------------------------------------------
// MimeOleGetExtClassId
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetExtClassId(LPCSTR pszExtension, LPCLSID pclsid)
{
// Locals
HRESULT hr=S_OK;
ULONG cb;
LPSTR pszCLSID=NULL;
HKEY hkeyExt=NULL;
HKEY hkeyCLSID=NULL;
LPSTR pszData=NULL;
LPWSTR pwszCLSID=NULL;
// check params
if (NULL == pszExtension || NULL == pclsid)
return TrapError(E_INVALIDARG);
// Otherwise, lets lookup the extension in HKEY_CLASSESS_ROOT
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, pszExtension, 0, KEY_READ, &hkeyExt) != ERROR_SUCCESS)
{
hr = MIME_E_NOT_FOUND;
goto exit;
}
// Query Value
if (RegQueryValueEx(hkeyExt, NULL, 0, NULL, NULL, &cb) != ERROR_SUCCESS)
{
hr = MIME_E_NOT_FOUND;
goto exit;
}
// Allocate Size
cb += 1;
CHECKHR(hr = HrAlloc((LPVOID *)&pszData, cb));
// Get the data
if (RegQueryValueEx(hkeyExt, NULL, 0, NULL, (LPBYTE)pszData, &cb) != ERROR_SUCCESS)
{
hr = TrapError(E_FAIL);
goto exit;
}
// Close this regkey
RegCloseKey(hkeyExt);
hkeyExt = NULL;
// Otherwise, lets lookup the extension in HKEY_CLASSESS_ROOT
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, pszData, 0, KEY_READ, &hkeyExt) != ERROR_SUCCESS)
{
hr = MIME_E_NOT_FOUND;
goto exit;
}
// Otherwise, lets lookup the extension in HKEY_CLASSESS_ROOT
if (RegOpenKeyEx(hkeyExt, c_szCLSID, 0, KEY_READ, &hkeyCLSID) != ERROR_SUCCESS)
{
hr = MIME_E_NOT_FOUND;
goto exit;
}
// Get the data
if (RegQueryValueEx(hkeyCLSID, NULL, 0, NULL, NULL, &cb) != ERROR_SUCCESS)
{
hr = TrapError(E_FAIL);
goto exit;
}
// Add One
cb += 1;
CHECKHR(hr = HrAlloc((LPVOID *)&pszCLSID, cb));
// Get the data
if (RegQueryValueEx(hkeyCLSID, NULL, 0, NULL, (LPBYTE)pszCLSID, &cb) != ERROR_SUCCESS)
{
hr = TrapError(E_FAIL);
goto exit;
}
// ToUnicode
IF_NULLEXIT(pwszCLSID = PszToUnicode(CP_ACP, pszCLSID));
// Convert to class id
CHECKHR(hr = CLSIDFromString(pwszCLSID, pclsid));
exit:
// Close Reg Keys
if (hkeyExt)
RegCloseKey(hkeyExt);
if (hkeyCLSID)
RegCloseKey(hkeyCLSID);
SafeMemFree(pszData);
SafeMemFree(pwszCLSID);
SafeMemFree(pszCLSID);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleGetExtContentType
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetExtContentType(LPCSTR pszExtension, LPSTR *ppszContentType)
{
LPWSTR pwszExt,
pwszContType = NULL;
HRESULT hr = S_OK;
if (NULL == pszExtension || NULL == ppszContentType || '.' != *pszExtension)
return TrapError(E_INVALIDARG);
IF_NULLEXIT(pwszExt = PszToUnicode(CP_ACP, pszExtension));
IF_FAILEXIT(hr = MimeOleGetExtContentTypeW(pwszExt, &pwszContType));
IF_NULLEXIT(*ppszContentType = PszToANSI(CP_ACP, pwszContType));
exit:
MemFree(pwszExt);
MemFree(pwszContType);
return hr;
}
MIMEOLEAPI MimeOleGetExtContentTypeW(LPCWSTR pszExtension, LPWSTR *ppszContentType)
{
// Locals
HRESULT hr=S_OK;
ULONG i;
HKEY hkeyExt=NULL;
LPWSTR pszFull=NULL;
ULONG cb;
// check params
if (NULL == pszExtension || NULL == ppszContentType || '.' != *pszExtension)
return TrapError(E_INVALIDARG);
// Otherwise, lets lookup the extension in HKEY_CLASSESS_ROOT
if (RegOpenKeyExWrapW(HKEY_CLASSES_ROOT, pszExtension, 0, KEY_READ, &hkeyExt) == ERROR_SUCCESS)
{
// Query Value
if (RegQueryValueExWrapW(hkeyExt, c_szContentTypeW, 0, NULL, NULL, &cb) == ERROR_SUCCESS)
{
// Add One
cb += 1;
// Allocate Size
pszFull = PszAllocW(cb);
if (NULL == pszFull)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
// Get the data
if (RegQueryValueExWrapW(hkeyExt, c_szContentTypeW, 0, NULL, (LPBYTE)pszFull, &cb) == ERROR_SUCCESS)
{
// Set It
*ppszContentType = pszFull;
pszFull = NULL;
goto exit;
}
}
}
// Not found
hr = MIME_E_NOT_FOUND;
exit:
// Close Reg Keys
if (hkeyExt)
RegCloseKey(hkeyExt);
// Cleanup
MemFree(pszFull);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleGetFileInfo
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetFileInfo(
LPSTR pszFilePath, LPSTR *ppszCntType,
LPSTR *ppszSubType, LPSTR *ppszCntDesc,
LPSTR *ppszFileName, LPSTR *ppszExtension)
{
HRESULT hr = S_OK;
LPWSTR pwszFilePath,
pwszCntType = NULL,
pwszSubType = NULL,
pwszCntDesc = NULL,
pwszFileName = NULL,
pwszExtension = NULL;
LPSTR pszCntType = NULL,
pszSubType = NULL,
pszCntDesc = NULL,
pszFileName = NULL,
pszExtension = NULL;
// check params
if (NULL == pszFilePath)
return TrapError(E_INVALIDARG);
IF_NULLEXIT(pwszFilePath = PszToUnicode(CP_ACP, pszFilePath));
// Only pass in parameters for items that
IF_FAILEXIT(hr = MimeOleGetFileInfoW(pwszFilePath,
ppszCntType ? &pwszCntType : NULL,
ppszSubType ? &pwszSubType : NULL,
ppszCntDesc ? &pwszCntDesc : NULL,
ppszFileName ? &pwszFileName : NULL,
ppszExtension ? &pwszExtension : NULL));
if (ppszCntType)
{
Assert(pwszCntType);
IF_NULLEXIT(pszCntType = PszToANSI(CP_ACP, pwszCntType));
}
if (ppszSubType)
{
Assert(pwszSubType);
IF_NULLEXIT(pszSubType = PszToANSI(CP_ACP, pwszSubType));
}
if (ppszCntDesc)
{
Assert(pwszCntDesc);
IF_NULLEXIT(pszCntDesc = PszToANSI(CP_ACP, pwszCntDesc));
}
if (ppszFileName)
{
Assert(pwszFileName);
IF_NULLEXIT(pszFileName = PszToANSI(CP_ACP, pwszFileName));
}
if (ppszExtension)
{
Assert(pwszExtension);
IF_NULLEXIT(pszExtension = PszToANSI(CP_ACP, pwszExtension));
}
if (ppszCntType)
*ppszCntType = pszCntType;
if (ppszSubType)
*ppszSubType = pszSubType;
if (ppszCntDesc)
*ppszCntDesc = pszCntDesc;
if (ppszFileName)
*ppszFileName = pszFileName;
if (ppszExtension)
*ppszExtension = pszExtension;
exit:
MemFree(pwszCntType);
MemFree(pwszSubType);
MemFree(pwszCntDesc);
MemFree(pwszFileName);
MemFree(pwszExtension);
MemFree(pwszFilePath);
if (FAILED(hr))
{
MemFree(pszCntType);
MemFree(pszSubType);
MemFree(pszCntDesc);
MemFree(pszFileName);
MemFree(pszExtension);
}
return hr;
}
MIMEOLEAPI MimeOleGetFileInfoW(
LPWSTR pszFilePath, LPWSTR *ppszCntType,
LPWSTR *ppszSubType, LPWSTR *ppszCntDesc,
LPWSTR *ppszFileName, LPWSTR *ppszExtension)
{
// Locals
HRESULT hr=S_OK;
SHFILEINFOW rShFileInfo;
LPWSTR pszFull=NULL,
pszExt,
pszFname;
// check params
if (NULL == pszFilePath)
return TrapError(E_INVALIDARG);
// Init
if (ppszCntType)
*ppszCntType = NULL;
if (ppszSubType)
*ppszSubType = NULL;
if (ppszCntDesc)
*ppszCntDesc = NULL;
if (ppszFileName)
*ppszFileName = NULL;
if (ppszExtension)
*ppszExtension = NULL;
// Locate the extension of the file
pszFname = PathFindFileNameW(pszFilePath);
pszExt = PathFindExtensionW(pszFilePath);
// Did the user want the actual filename...
if (ppszFileName)
{
// Allocate
*ppszFileName = PszDupW(pszFname);
if (NULL == *ppszFileName)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
}
// Empty extension
if (FIsEmptyW(pszExt))
{
hr = TrapError(E_FAIL);
goto exit;
}
// User wanted the extension
if (ppszExtension)
{
// Allocate
*ppszExtension = PszDupW(pszExt);
if (NULL == *ppszExtension)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
}
// User wanted ppszCntDesc
if (ppszCntDesc)
{
// Lets try to get the extension file information first
if (SHGetFileInfoWrapW(pszExt, FILE_ATTRIBUTE_NORMAL, &rShFileInfo, sizeof(rShFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_DISPLAYNAME | SHGFI_TYPENAME))
{
// Set lppszCntDesc + ( )
DWORD cchSize = (lstrlenW(rShFileInfo.szDisplayName) + lstrlenW(rShFileInfo.szTypeName) + 5);
*ppszCntDesc = PszAllocW(cchSize);
if (NULL == *ppszCntDesc)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
// Format the string
wnsprintfW(*ppszCntDesc, cchSize, L"%s, (%s)", rShFileInfo.szDisplayName, rShFileInfo.szTypeName);
}
}
// Content type
if (ppszCntType && ppszSubType)
{
// Lookup content type
if (SUCCEEDED(MimeOleGetExtContentTypeW(pszExt, &pszFull)))
{
// Split content type
CHECKHR(hr = MimeOleSplitContentType(pszFull, ppszCntType, ppszSubType));
}
}
exit:
// Set defaults if something was not found...
if (ppszCntType && NULL == *ppszCntType)
*ppszCntType = PszDupW((LPWSTR)STR_CNT_APPLICATIONW);
if (ppszSubType && NULL == *ppszSubType)
*ppszSubType = PszDupW((LPWSTR)STR_SUB_OCTETSTREAMW);
if (ppszCntDesc && NULL == *ppszCntDesc)
*ppszCntDesc = PszDupW((LPWSTR)c_szEmptyW);
// Cleanup
SafeMemFree(pszFull);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleGetContentTypeExt
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetContentTypeExt(LPCSTR pszContentType, LPSTR *ppszExtension)
{
// Locals
HRESULT hr=S_OK;
HKEY hDatabase=NULL;
HKEY hContentType=NULL;
ULONG cb;
// check params
if (NULL == pszContentType || NULL == ppszExtension)
return TrapError(E_INVALIDARG);
// Open Content-Type --> file extension MIME Database registry key
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, c_szMDBContentType, 0, KEY_READ, &hDatabase) != ERROR_SUCCESS)
{
hr = MIME_E_NOT_FOUND;
goto exit;
}
// Open Content Type
if (RegOpenKeyEx(hDatabase, pszContentType, 0, KEY_READ, &hContentType) != ERROR_SUCCESS)
{
hr = MIME_E_NOT_FOUND;
goto exit;
}
// Query for size
if (RegQueryValueEx(hContentType, c_szExtension, 0, NULL, NULL, &cb) != ERROR_SUCCESS)
{
hr = MIME_E_NOT_FOUND;
goto exit;
}
// Allocate It
*ppszExtension = PszAllocA(cb + 1);
if (NULL == *ppszExtension)
{
hr = TrapError(E_OUTOFMEMORY);
goto exit;
}
// Query for extension
cb = cb + 1;
if (RegQueryValueEx(hContentType, c_szExtension, 0, NULL, (LPBYTE)*ppszExtension, &cb) != ERROR_SUCCESS)
{
hr = TrapError(E_FAIL);
goto exit;
}
exit:
// Cleanup
if (hContentType)
RegCloseKey(hContentType);
if (hDatabase)
RegCloseKey(hDatabase);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleFindCharset
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleFindCharset(LPCSTR pszCharset, LPHCHARSET phCharset)
{
Assert(g_pInternat);
return g_pInternat->FindCharset(pszCharset, phCharset);
}
// --------------------------------------------------------------------------------
// MimeOleGetCharsetInfo
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetCharsetInfo(HCHARSET hCharset, LPINETCSETINFO pCsetInfo)
{
Assert(g_pInternat);
return g_pInternat->GetCharsetInfo(hCharset, pCsetInfo);
}
// --------------------------------------------------------------------------------
// MimeOleGetCodePageInfo
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetCodePageInfo(CODEPAGEID cpiCodePage, LPCODEPAGEINFO pCodePageInfo)
{
Assert(g_pInternat);
return g_pInternat->GetCodePageInfo(cpiCodePage, pCodePageInfo);
}
// --------------------------------------------------------------------------------
// MimeOleGetDefaultCharset
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetDefaultCharset(LPHCHARSET phCharset)
{
Assert(g_pInternat);
return g_pInternat->GetDefaultCharset(phCharset);
}
// --------------------------------------------------------------------------------
// MimeOleSetDefaultCharset
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleSetDefaultCharset(HCHARSET hCharset)
{
Assert(g_pInternat);
return g_pInternat->SetDefaultCharset(hCharset);
}
// --------------------------------------------------------------------------------
// MimeOleGetCodePageCharset
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetCodePageCharset(CODEPAGEID cpiCodePage, CHARSETTYPE ctCsetType, LPHCHARSET phCharset)
{
Assert(g_pInternat);
return g_pInternat->GetCodePageCharset(cpiCodePage, ctCsetType, phCharset);
}
// --------------------------------------------------------------------------------
// MimeOleEncodeHeader
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleEncodeHeader(
HCHARSET hCharset,
LPPROPVARIANT pData,
LPSTR *ppszEncoded,
LPRFC1522INFO pRfc1522Info)
{
Assert(g_pInternat);
return g_pInternat->EncodeHeader(hCharset, pData, ppszEncoded, pRfc1522Info);
}
// --------------------------------------------------------------------------------
// MimeOleDecodeHeader
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleDecodeHeader(
HCHARSET hCharset,
LPCSTR pszData,
LPPROPVARIANT pDecoded,
LPRFC1522INFO pRfc1522Info)
{
Assert(g_pInternat);
return g_pInternat->DecodeHeader(hCharset, pszData, pDecoded, pRfc1522Info);
}
// --------------------------------------------------------------------------------
// MimeOleVariantFree
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleVariantFree(LPPROPVARIANT pProp)
{
// Locals
HRESULT hr=S_OK;
// Invalid Arg
Assert(pProp);
// Handle Variant Type...
switch(pProp->vt)
{
case VT_NULL:
case VT_EMPTY:
case VT_ILLEGAL:
case VT_UI1:
case VT_I2:
case VT_UI2:
case VT_I4:
case VT_UI4:
case VT_I8:
case VT_UI8:
case VT_R4:
case VT_R8:
case VT_CY:
case VT_DATE:
case VT_BOOL:
case VT_ERROR:
case VT_FILETIME:
break;
case VT_CF:
case VT_CLSID:
case VT_LPWSTR:
case VT_LPSTR:
if ((LPVOID)pProp->pszVal != NULL)
MemFree((LPVOID)pProp->pszVal);
break;
case VT_BLOB:
if (pProp->blob.pBlobData)
MemFree(pProp->blob.pBlobData);
break;
case VT_STREAM:
if (pProp->pStream)
pProp->pStream->Release();
break;
case VT_STORAGE:
if (pProp->pStorage)
pProp->pStorage->Release();
break;
default:
Assert(FALSE);
hr = TrapError(E_INVALIDARG);
break;
}
// Init
MimeOleVariantInit(pProp);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleVariantCopy
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleVariantCopy(LPPROPVARIANT pDest, LPPROPVARIANT pSource)
{
// Locals
HRESULT hr=S_OK;
ULONG cb;
// Invalid Arg
Assert(pSource && pDest);
// Handle Variant Type...
switch(pSource->vt)
{
case VT_UI1:
pDest->bVal = pSource->bVal;
break;
case VT_I2:
pDest->iVal= pSource->iVal;
break;
case VT_UI2:
pDest->uiVal = pSource->uiVal;
break;
case VT_I4:
pDest->lVal = pSource->lVal;
break;
case VT_UI4:
pDest->ulVal = pSource->ulVal;
break;
case VT_I8:
pDest->hVal.QuadPart = pSource->hVal.QuadPart;
break;
case VT_UI8:
pDest->uhVal.QuadPart = pSource->uhVal.QuadPart;
break;
case VT_R4:
pDest->fltVal = pSource->fltVal;
break;
case VT_R8:
pDest->dblVal = pSource->dblVal;
break;
case VT_CY:
CopyMemory(&pDest->cyVal, &pSource->cyVal, sizeof(CY));
break;
case VT_DATE:
pDest->date = pSource->date;
break;
case VT_BOOL:
pDest->boolVal = pSource->boolVal;
break;
case VT_ERROR:
pDest->scode = pSource->scode;
break;
case VT_FILETIME:
CopyMemory(&pDest->filetime, &pSource->filetime, sizeof(FILETIME));
break;
case VT_CF:
// Invalid Arg
if (NULL == pSource->pclipdata)
return TrapError(E_INVALIDARG);
// Duplicate the clipboard format
CHECKALLOC(pDest->pclipdata = (CLIPDATA *)g_pMalloc->Alloc(sizeof(CLIPDATA)));
// Copy the data
CopyMemory(pDest->pclipdata, pSource->pclipdata, sizeof(CLIPDATA));
break;
case VT_CLSID:
// Invalid Arg
if (NULL == pDest->puuid)
return TrapError(E_INVALIDARG);
// Duplicate the CLSID
CHECKALLOC(pDest->puuid = (CLSID *)g_pMalloc->Alloc(sizeof(CLSID)));
// Copy
CopyMemory(pDest->puuid, pSource->puuid, sizeof(CLSID));
break;
case VT_LPWSTR:
// Invalid Arg
if (NULL == pSource->pwszVal)
return TrapError(E_INVALIDARG);
// Get Size
cb = (lstrlenW(pSource->pwszVal) + 1) * sizeof(WCHAR);
// Dup the unicode String
CHECKALLOC(pDest->pwszVal = (LPWSTR)g_pMalloc->Alloc(cb));
// Copy the data
CopyMemory(pDest->pwszVal, pSource->pwszVal, cb);
break;
case VT_LPSTR:
// Invalid Arg
if (NULL == pSource->pszVal)
return TrapError(E_INVALIDARG);
// Get Size
cb = lstrlen(pSource->pszVal) + 1;
// Dup the unicode String
CHECKALLOC(pDest->pszVal = (LPSTR)g_pMalloc->Alloc(cb));
// Copy the data
CopyMemory(pDest->pszVal, pSource->pszVal, cb);
break;
case VT_BLOB:
// Invalid Arg
if (NULL == pSource->blob.pBlobData)
return TrapError(E_INVALIDARG);
// Duplicate the blob
CHECKALLOC(pDest->blob.pBlobData = (LPBYTE)g_pMalloc->Alloc(pSource->blob.cbSize));
// Copy the data
CopyMemory(pDest->blob.pBlobData, pSource->blob.pBlobData, pSource->blob.cbSize);
break;
case VT_STREAM:
// Invalid Arg
if (NULL == pSource->pStream)
return TrapError(E_INVALIDARG);
// Assume the new stream
pDest->pStream = pSource->pStream;
pDest->pStream->AddRef();
break;
case VT_STORAGE:
// Invalid Arg
if (NULL == pSource->pStorage)
return TrapError(E_INVALIDARG);
// Assume the new storage
pDest->pStorage = pSource->pStorage;
pDest->pStorage->AddRef();
break;
default:
Assert(FALSE);
hr = TrapError(E_INVALIDARG);
goto exit;
}
// Success, return vt
pDest->vt = pSource->vt;
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleRecurseSetProp
// --------------------------------------------------------------------------------
HRESULT MimeOleRecurseSetProp(IMimeMessageTree *pTree, HBODY hBody, LPCSTR pszName,
DWORD dwFlags, LPCPROPVARIANT pValue)
{
// Locals
HRESULT hr=S_OK;
HRESULT hrFind;
HBODY hChild;
// Invalid Arg
Assert(pTree && hBody && pValue);
// multipart/alternative
if (pTree->IsContentType(hBody, STR_CNT_MULTIPART, NULL) == S_OK)
{
// Get First Child
hrFind = pTree->GetBody(IBL_FIRST, hBody, &hChild);
while(SUCCEEDED(hrFind) && hChild)
{
// Go down to the child
CHECKHR(hr = MimeOleRecurseSetProp(pTree, hChild, pszName, dwFlags, pValue));
// Next Child
hrFind = pTree->GetBody(IBL_NEXT, hChild, &hChild);
}
}
// Otherwise
else
{
// Go down to the child
CHECKHR(hr = pTree->SetBodyProp(hBody, pszName, dwFlags, pValue));
}
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleGetPropA
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetPropA(
IMimePropertySet *pPropertySet,
LPCSTR pszName,
DWORD dwFlags,
LPSTR *ppszData)
{
// Locals
HRESULT hr=S_OK;
// Invaid Arg
if (NULL == pPropertySet)
return TrapError(E_INVALIDARG);
// Initialzie PropVariant
PROPVARIANT rVariant;
rVariant.vt = VT_LPSTR;
// Call Method
CHECKHR(hr = pPropertySet->GetProp(pszName, dwFlags, &rVariant));
// Return the Data
*ppszData = rVariant.pszVal;
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleSetPropA
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleSetPropA(
IMimePropertySet *pPropertySet,
LPCSTR pszName,
DWORD dwFlags,
LPCSTR pszData)
{
// Invaid Arg
if (NULL == pPropertySet)
return TrapError(E_INVALIDARG);
// Initialzie PropVariant
PROPVARIANT rVariant;
rVariant.vt = VT_LPSTR;
rVariant.pszVal = (LPSTR)pszData;
// Call Method
return TrapError(pPropertySet->SetProp(pszName, dwFlags, &rVariant));
}
// --------------------------------------------------------------------------------
// MimeOleGetPropW
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetPropW(
IMimePropertySet *pPropertySet,
LPCSTR pszName,
DWORD dwFlags,
LPWSTR *ppszData)
{
// Locals
HRESULT hr=S_OK;
// Invaid Arg
if (NULL == pPropertySet)
return TrapError(E_INVALIDARG);
// Initialzie PropVariant
PROPVARIANT rVariant;
rVariant.vt = VT_LPWSTR;
// Call Method
CHECKHR(hr = pPropertySet->GetProp(pszName, dwFlags, &rVariant));
// Return the Data
*ppszData = rVariant.pwszVal;
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleSetPropW
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleSetPropW(
IMimePropertySet *pPropertySet,
LPCSTR pszName,
DWORD dwFlags,
LPWSTR pszData)
{
// Invaid Arg
if (NULL == pPropertySet)
return TrapError(E_INVALIDARG);
// Initialzie PropVariant
PROPVARIANT rVariant;
rVariant.vt = VT_LPWSTR;
rVariant.pwszVal = (LPWSTR)pszData;
// Call Method
return TrapError(pPropertySet->SetProp(pszName, dwFlags, &rVariant));
}
// --------------------------------------------------------------------------------
// MimeOleGetBodyPropA
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetBodyPropA(
IMimeMessageTree *pTree,
HBODY hBody,
LPCSTR pszName,
DWORD dwFlags,
LPSTR *ppszData)
{
// Locals
HRESULT hr=S_OK;
// Invaid Arg
if (NULL == pTree)
return TrapError(E_INVALIDARG);
// Initialzie PropVariant
PROPVARIANT rVariant;
rVariant.vt = VT_LPSTR;
// Call Method
CHECKHR(hr = pTree->GetBodyProp(hBody, pszName, dwFlags, &rVariant));
// Return the Data
*ppszData = rVariant.pszVal;
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleSetBodyPropA
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleSetBodyPropA(
IMimeMessageTree *pTree,
HBODY hBody,
LPCSTR pszName,
DWORD dwFlags,
LPCSTR pszData)
{
// Invaid Arg
if (NULL == pTree)
return TrapError(E_INVALIDARG);
// Initialzie PropVariant
PROPVARIANT rVariant;
rVariant.vt = VT_LPSTR;
rVariant.pszVal = (LPSTR)pszData;
// Call Method
return TrapError(pTree->SetBodyProp(hBody, pszName, dwFlags, &rVariant));
}
// --------------------------------------------------------------------------------
// MimeOleGetBodyPropW
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleGetBodyPropW(
IMimeMessageTree *pTree,
HBODY hBody,
LPCSTR pszName,
DWORD dwFlags,
LPWSTR *ppszData)
{
// Locals
HRESULT hr=S_OK;
// Invaid Arg
if (NULL == pTree)
return TrapError(E_INVALIDARG);
// Initialzie PropVariant
PROPVARIANT rVariant;
rVariant.vt = VT_LPWSTR;
// Call Method
CHECKHR(hr = pTree->GetBodyProp(hBody, pszName, dwFlags, &rVariant));
// Return the Data
*ppszData = rVariant.pwszVal;
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleSetBodyPropW
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleSetBodyPropW(
IMimeMessageTree *pTree,
HBODY hBody,
LPCSTR pszName,
DWORD dwFlags,
LPCWSTR pszData)
{
// Invaid Arg
if (NULL == pTree)
return TrapError(E_INVALIDARG);
// Initialzie PropVariant
PROPVARIANT rVariant;
rVariant.vt = VT_LPWSTR;
rVariant.pwszVal = (LPWSTR)pszData;
// Call Method
return TrapError(pTree->SetBodyProp(hBody, pszName, dwFlags, &rVariant));
}
// --------------------------------------------------------------------------------
// MimeOleQueryString
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleQueryString(
LPCSTR pszSearchMe,
LPCSTR pszCriteria,
boolean fSubString,
boolean fCaseSensitive)
{
// Locals
HRESULT hr=S_OK;
LPSTR pszDataLower=NULL;
// Invalid Arg
Assert(pszSearchMe && pszCriteria);
// Init
STACKSTRING_DEFINE(rDataLower, 255);
// No SubString Search
if (FALSE == fSubString)
{
// Case Sensitive
if (fCaseSensitive)
{
// Equal
if (lstrcmp(pszSearchMe, pszCriteria) == 0)
goto exit;
}
// Otherwise, Not Case Sensitive
else if (lstrcmpi(pszSearchMe, pszCriteria) == 0)
goto exit;
}
// Otheriwse, comparing substring
else
{
// Case Sensitive
if (fCaseSensitive)
{
// Equal
if (StrStr(pszSearchMe, pszCriteria) != NULL)
goto exit;
}
// Otherwise, Not Case Sensitive
else
{
// Get the Length
ULONG cchSearchMe = lstrlen(pszSearchMe);
// Set size the stack string
STACKSTRING_SETSIZE(rDataLower, cchSearchMe + 1);
// Copy the data
CopyMemory(rDataLower.pszVal, pszSearchMe, cchSearchMe + 1);
// Lower Case Compare
CharLower(rDataLower.pszVal);
// Compare Strings...
if (StrStr(rDataLower.pszVal, pszCriteria) != NULL)
goto exit;
}
}
// No Match
hr = S_FALSE;
exit:
// Cleanup
STACKSTRING_FREE(rDataLower);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleQueryStringW
// --------------------------------------------------------------------------------
HRESULT MimeOleQueryStringW(LPCWSTR pszSearchMe, LPCWSTR pszCriteria,
boolean fSubString, boolean fCaseSensitive)
{
// Locals
HRESULT hr=S_OK;
// Invalid Arg
Assert(pszSearchMe && pszCriteria);
// No SubString Search
if (FALSE == fSubString)
{
// Case Sensitive
if (fCaseSensitive)
{
// Equal
if (StrCmpW(pszSearchMe, pszCriteria) == 0)
goto exit;
}
// Otherwise, Not Case Sensitive
else if (StrCmpIW(pszSearchMe, pszCriteria) == 0)
goto exit;
}
// Otheriwse, comparing substring
else
{
// Case Sensitive
if (fCaseSensitive)
{
// Equal
if (StrStrW(pszSearchMe, pszCriteria) != NULL)
goto exit;
}
// Otherwise, Not Case Sensitive
else if (StrStrIW(pszSearchMe, pszCriteria) != NULL)
goto exit;
}
// No Match
hr = S_FALSE;
exit:
// Done
return hr;
}
#define FILETIME_SECOND 10000000 // 100ns intervals per second
LONG CertVerifyTimeValidityWithDelta(LPFILETIME pTimeToVerify, PCERT_INFO pCertInfo, ULONG ulOffset) {
LONG lRet;
FILETIME ftNow;
__int64 i64Offset;
#ifdef WIN32
union {
FILETIME ftDelta;
__int64 i64Delta;
};
#else
// FILETIME ftDelta;
// __int64 i64Delta;
//
// WIN32 specific. I've commented this for WIN32 so that it will produce a compilation
// error on non Win32 platforms. The following code is specific to i386 since it relies on
// __int64 being stored low dword first.
//
// I would have used right shift by 32 but it is not in iert.lib Maybe you unix and mac folks
// can get it in there. On the other hand, maybe you won't need to.
#endif
lRet = CertVerifyTimeValidity(pTimeToVerify, pCertInfo);
if (lRet < 0) {
if (! pTimeToVerify) {
// Get the current time in filetime format so we can add the offset
GetSystemTimeAsFileTime(&ftNow);
pTimeToVerify = &ftNow;
}
i64Delta = pTimeToVerify->dwHighDateTime;
i64Delta = i64Delta << 32;
i64Delta += pTimeToVerify->dwLowDateTime;
// Add the offset into the original time to get us a new time to check
i64Offset = FILETIME_SECOND;
i64Offset *= ulOffset;
i64Delta += i64Offset;
// ftDelta.dwLowDateTime = (ULONG)i64Delta & 0xFFFFFFFF;
// ftDelta.dwHighDateTime = (ULONG)(i64Delta >> 32);
lRet = CertVerifyTimeValidity(&ftDelta, pCertInfo);
}
return(lRet);
}
/* GetCertsFromThumbprints:
**
** Purpose:
** Given a set of thumbprints, return an equivalent set of certificates.
** Takes:
** IN rgThumbprint - array of thumbprints to lookup
** INOUT pResults - the hr array contains error info for each cert
** lookup. The pCert array has the certs.
** cEntries must be set on IN
** arrays must be alloc'd on IN
** IN rghCertStore - set of stores to search
** IN cCertStore - size of rghCertStore
** Returns:
** MIME_S_SECURITY_ERROROCCURED if any of the lookups fail
** (CERTIFICATE_NOT_PRESENT in the cs array for such cases)
** MIME_S_SECURITY_NOOP if you call it with 0 in cEntries
** E_INVALIDARG if any of the parameters are null
** S_OK implies that all certs were found
** Note:
** only indexes with non-null thumbprints are considered
*/
MIMEOLEAPI MimeOleGetCertsFromThumbprints(
THUMBBLOB *const rgThumbprint,
X509CERTRESULT *const pResults,
const HCERTSTORE *const rghCertStore,
const DWORD cCertStore)
{
HRESULT hr;
ULONG iEntry, iStore;
if (!(rgThumbprint &&
pResults && pResults->rgpCert && pResults->rgcs &&
rghCertStore && cCertStore))
{
hr = TrapError(E_INVALIDARG);
goto exit;
}
if (0 == pResults->cEntries)
{
hr = MIME_S_SECURITY_NOOP;
goto exit;
}
hr = S_OK;
for (iEntry = 0; iEntry < pResults->cEntries; iEntry++)
{
if (rgThumbprint[iEntry].pBlobData)
{
for (iStore = 0; iStore < cCertStore; iStore++)
{
// We have a thumbprint, so do lookup
pResults->rgpCert[iEntry] = CertFindCertificateInStore(rghCertStore[iStore],
X509_ASN_ENCODING,
0, //dwFindFlags
CERT_FIND_HASH,
(void *)(CRYPT_DIGEST_BLOB *)&(rgThumbprint[iEntry]),
NULL);
if (pResults->rgpCert[iEntry])
{
break;
}
}
if (!pResults->rgpCert[iEntry])
{
DOUTL(1024, "CRYPT: Cert lookup failed. #%d", iEntry);
pResults->rgcs[iEntry] = CERTIFICATE_NOT_PRESENT;
hr = MIME_S_SECURITY_ERROROCCURED;
}
else
{
// Validity check
if (0 != CertVerifyTimeValidityWithDelta(NULL,
PCCERT_CONTEXT(pResults->rgpCert[iEntry])->pCertInfo,
TIME_DELTA_SECONDS))
{
pResults->rgcs[iEntry] = CERTIFICATE_EXPIRED;
}
else
{
pResults->rgcs[iEntry] = CERTIFICATE_OK;
}
}
}
else
{
CRDOUT("For want of a thumbprint... #%d", iEntry);
pResults->rgpCert[iEntry] = NULL;
pResults->rgcs[iEntry] = CERTIFICATE_NOPRINT;
hr = MIME_S_SECURITY_ERROROCCURED;
}
}
exit:
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleMapSpecialCodePage
// --------------------------------------------------------------------------------
HRESULT MimeOleMapSpecialCodePage(CODEPAGEID cpIn, BOOL fRead, CODEPAGEID *pcpOut)
{
// Locals
DWORD i;
INETCSETINFO CsetInfo;
// Trace
TraceCall("MimeOleMapSpecialCodePage");
// Invalid Args
if (NULL == pcpOut)
return(TraceResult(E_INVALIDARG));
// Initialize
*pcpOut = cpIn;
// Walk through the non-standard codepages list
for (i=0; OENonStdCPs[i].Codepage != 0; i++)
{
// Is this it?
if (OENonStdCPs[i].Codepage == cpIn)
{
// Read ?
if (fRead && OENonStdCPs[i].cpRead)
*pcpOut = OENonStdCPs[i].cpRead;
// Send ?
else if (OENonStdCPs[i].cpSend)
*pcpOut = OENonStdCPs[i].cpSend;
// Done
break;
}
}
// Done
return(S_OK);
}
// --------------------------------------------------------------------------------
// MimeOleMapCodePageToCharset
// --------------------------------------------------------------------------------
HRESULT MimeOleMapCodePageToCharset(CODEPAGEID cpIn, LPHCHARSET phCharset)
{
// Locals
HRESULT hr=S_OK;
LPSTR pszCharset;
CODEPAGEINFO CodePage;
// Trace
TraceCall("MimeOleMapCodePageToCharset");
// Invalid Args
if (NULL == phCharset)
return(TraceResult(E_INVALIDARG));
// Get codepage info
IF_FAILEXIT(hr = MimeOleGetCodePageInfo(cpIn, &CodePage));
// Default to using the body charset
pszCharset = CodePage.szBodyCset;
// Use WebCharset if body charset starts with '_' and the codepage is not 949
if (*CodePage.szBodyCset != '_' && 949 != CodePage.cpiCodePage)
pszCharset = CodePage.szWebCset;
// Find the Charset
IF_FAILEXIT(hr = MimeOleFindCharset(pszCharset, phCharset));
exit:
// Done
return(hr);
}
// --------------------------------------------------------------------------------
// MimeOleSplitMessage
// --------------------------------------------------------------------------------
MIMEOLEAPI MimeOleSplitMessage(IMimeMessage *pMessage, ULONG cbMaxPart, IMimeMessageParts **ppParts)
{
// Locals
HRESULT hr=S_OK;
ULONG cbMessage,
cbHeader,
cParts,
iPart,
cbActual,
cbRead=0,
cAttach,
i,
cbSubjectAddOn,
cbSubjectNew;
LPHBODY prghAttach=NULL;
IStream *pstmMsg=NULL,
*pstmPart=NULL;
ULARGE_INTEGER ulicbHeader;
IMimePropertySet *pRootProps=NULL;
CMimeMessageParts *pParts=NULL;
IMimeMessage *pmsgPart=NULL;
FILETIME ft;
SYSTEMTIME st;
CHAR szMimeId[CCHMAX_MID],
szNumber[30],
szFormat[50];
MIMESAVETYPE savetype;
BODYOFFSETS rOffsets;
IMimeBody *pRootBody=NULL;
LPSTR pszSubjectAddOn=NULL,
pszSubjectNew=NULL;
PROPVARIANT rVariant,
rSubject,
rFileName;
float dParts;
HCHARSET hCharset=NULL;
INETCSETINFO CsetInfo;
// Invalid Arg
if (NULL == ppParts)
return TrapError(E_INVALIDARG);
// Initialize Variants
MimeOleVariantInit(&rSubject);
MimeOleVariantInit(&rFileName);
// Init
*ppParts = NULL;
// Get Option
rVariant.vt = VT_UI4;
pMessage->GetOption(OID_SAVE_FORMAT, &rVariant);
savetype = (MIMESAVETYPE)rVariant.ulVal;
// Raid-73119: OE : Kor: the charset for the message sent in broken apart is shown as "_autodetect_kr"
if (SUCCEEDED(pMessage->GetCharset(&hCharset)))
{
// Get the charset info for the HCHARSET
if (SUCCEEDED(MimeOleGetCharsetInfo(hCharset, &CsetInfo)))
{
// Map the codepage
CODEPAGEID cpActual;
// Map the codepage to the correct codepage..
if (SUCCEEDED(MimeOleMapSpecialCodePage(CsetInfo.cpiInternet, FALSE, &cpActual)))
{
// If Different
if (cpActual != CsetInfo.cpiInternet)
{
// Map the codepage to a character set
MimeOleMapCodePageToCharset(cpActual, &hCharset);
// Reset the character set....
SideAssert(SUCCEEDED(pMessage->SetCharset(hCharset, CSET_APPLY_TAG_ALL)));
}
}
}
}
// Get Message Source
CHECKHR(hr = pMessage->GetMessageSource(&pstmMsg, COMMIT_ONLYIFDIRTY));
// Create Parts Object
CHECKALLOC(pParts = new CMimeMessageParts);
// Rewind the stream
CHECKHR(hr = HrRewindStream(pstmMsg));
// Get Stream Size
CHECKHR(hr = HrSafeGetStreamSize(pstmMsg, &cbMessage));
// Is this size larger than the max part size
if (cbMessage <= cbMaxPart)
{
// Add Single Parts to parts object
CHECKHR(hr = pParts->AddPart(pMessage));
// Done
goto exit;
}
// Get the root body
CHECKHR(hr = pMessage->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *)&pRootBody));
// Get Root body offset info
CHECKHR(hr = pRootBody->GetOffsets(&rOffsets));
// If the header is bigger than the max message size, we have a problem
cbHeader = (ULONG)rOffsets.cbBodyStart - rOffsets.cbHeaderStart;
if (cbHeader >= cbMessage || cbHeader + 256 >= cbMaxPart)
{
AssertSz(FALSE, "SplitMessage: The header is bigger than the max message size");
hr = TrapError(MIME_E_MAX_SIZE_TOO_SMALL);
goto exit;
}
// Get a copy of the root header
CHECKHR(hr = pRootBody->Clone(&pRootProps));
// Lets cleanup this header...
pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTTYPE));
pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTDISP));
pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTDESC));
pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTID));
pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTLOC));
pRootProps->DeleteProp(PIDTOSTR(PID_HDR_MIMEVER));
pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTXFER));
pRootProps->DeleteProp("Disposition-Notification-To");
pRootProps->DeleteProp(PIDTOSTR(PID_HDR_MESSAGEID));
// Compute the number of parts as a float
dParts = (float)((float)cbMessage / (float)(cbMaxPart - cbHeader));
// If dParts is not an integer, round up.
cParts = (dParts - ((ULONG)dParts)) ? ((ULONG)dParts) + 1 : ((ULONG)dParts);
// Set Max Parts in parts object
CHECKHR(hr = pParts->SetMaxParts(cParts));
// If MIME, create id
if (SAVE_RFC1521 == savetype)
{
// Create Mime Id
GetSystemTime(&st);
SystemTimeToFileTime(&st, &ft);
wnsprintfA(szMimeId, ARRAYSIZE(szMimeId), "%08.8lX.%08.8lX@%s", ft.dwHighDateTime, ft.dwLowDateTime, (LPSTR)SzGetLocalHostName());
// total=X
wnsprintfA(szNumber, ARRAYSIZE(szNumber), "%d", cParts);
// number=x
rVariant.vt = VT_LPSTR;
rVariant.pszVal = szNumber;
CHECKHR(hr = pRootProps->SetProp(STR_PAR_TOTAL, 0, &rVariant));
// id=XXXX
rVariant.pszVal = szMimeId;
CHECKHR(hr = pRootProps->SetProp(STR_PAR_ID, 0, &rVariant));
// MIME Version
rVariant.pszVal = (LPSTR)c_szMimeVersion;
CHECKHR(hr = pRootProps->SetProp(PIDTOSTR(PID_HDR_MIMEVER), 0, &rVariant));
}
// Otherwise, seek pstmMsg to end of header
else
{
// Get Stream Position
CHECKHR(hr = HrStreamSeekSet(pstmMsg, rOffsets.cbBodyStart));
// Reduce the message size
cbMessage -= rOffsets.cbBodyStart;
}
// Init the variant
rSubject.vt = VT_LPSTR;
// Get Subject
if (FAILED(pRootBody->GetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &rSubject)))
rSubject.pszVal = NULL;
// Enumerate bodies and get the first file name and use it in the new subject...
if (SUCCEEDED(pMessage->GetAttachments(&cAttach, &prghAttach)))
{
// Init the variant
rFileName.vt = VT_LPSTR;
// Loop Attached
for (i=0; i<cAttach; i++)
{
// Get File Name...
if (SUCCEEDED(pMessage->GetBodyProp(prghAttach[i], PIDTOSTR(PID_ATT_FILENAME), 0, &rFileName)))
break;
}
}
// Format Number
wnsprintfA(szNumber, ARRAYSIZE(szNumber), "%d", cParts);
// Have a file name
if (rFileName.pszVal)
{
// Make Format String...
wnsprintfA(szFormat, ARRAYSIZE(szFormat), "%%s [%%0%dd/%d]", lstrlen(szNumber), cParts);
// Size of subject add on string
cbSubjectAddOn = lstrlen(rFileName.pszVal) + lstrlen(szFormat) + lstrlen(szNumber) + 1;
}
// Otherwise, no filename
else
{
// Make Format String...
wnsprintfA(szFormat, ARRAYSIZE(szFormat), "[%%0%dd/%d]", lstrlen(szNumber), cParts);
// Size of subject add on string
cbSubjectAddOn = lstrlen(szFormat) + lstrlen(szNumber) + 1;
}
// Allocate Subject Add On
DWORD cchSize = (cbSubjectAddOn / sizeof(pszSubjectAddOn[0]));
CHECKALLOC(pszSubjectAddOn = PszAllocA(cchSize));
// Allocate new subject
if (rSubject.pszVal)
cbSubjectNew = cbSubjectAddOn + lstrlen(rSubject.pszVal) + 5;
else
cbSubjectNew = cbSubjectAddOn + 5;
// Allocate Subject New
CHECKALLOC(pszSubjectNew = PszAllocA(cbSubjectNew));
// Loop throught the number of parts
for (iPart=0; iPart<cParts; iPart++)
{
// Create a new stream...
CHECKHR(hr = CreateTempFileStream(&pstmPart));
// If MIME, I can do the partial stuff for them
if (SAVE_RFC1521 == savetype)
{
// Content-Type: message/partial; number=X; total=X; id=XXXXXX
rVariant.vt = VT_LPSTR;
rVariant.pszVal = (LPSTR)STR_MIME_MSG_PART;
CHECKHR(hr = pRootProps->SetProp(PIDTOSTR(PID_HDR_CNTTYPE), 0, &rVariant));
// number=X
wnsprintfA(szNumber, ARRAYSIZE(szNumber), "%d", iPart+1);
rVariant.pszVal = szNumber;
CHECKHR(hr = pRootProps->SetProp(STR_PAR_NUMBER, 0, &rVariant));
}
// Build Subject AddOn
if (rFileName.pszVal)
wnsprintfA(pszSubjectAddOn, cchSize, szFormat, rFileName.pszVal, iPart + 1);
else
wnsprintfA(pszSubjectAddOn, cchSize, szFormat, iPart + 1);
// Build New Subject
if (rSubject.pszVal)
wnsprintfA(pszSubjectNew, cbSubjectNew, "%s %s", rSubject.pszVal, pszSubjectAddOn);
else
wnsprintfA(pszSubjectNew, cbSubjectNew, "%s", pszSubjectAddOn);
// Set New Subject
rVariant.vt = VT_LPSTR;
rVariant.pszVal = pszSubjectNew;
CHECKHR(hr = pRootProps->SetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &rVariant));
// Save Root Header
CHECKHR(hr = pRootProps->Save(pstmPart, TRUE));
// Emit Line Break
CHECKHR(hr = pstmPart->Write(c_szCRLF, lstrlen(c_szCRLF), NULL));
// Copy bytes from lpstmMsg to pstmPart
CHECKHR(hr = HrCopyStreamCBEndOnCRLF(pstmMsg, pstmPart, cbMaxPart - cbHeader, &cbActual));
// Increment read
cbRead += cbActual;
// If cbActual is less than cbMaxMsgSize-cbHeader, better be the last part
#ifdef DEBUG
if (iPart + 1 < cParts && cbActual < (cbMaxPart - cbHeader))
AssertSz (FALSE, "One more partial message is going to be produced than needed. This should be harmless.");
#endif
// Commit pstmPart
CHECKHR(hr = pstmPart->Commit(STGC_DEFAULT));
// Rewind it
CHECKHR(hr = HrRewindStream(pstmPart));
// Create Message Part...
CHECKHR(hr = MimeOleCreateMessage(NULL, &pmsgPart));
// Make the message build itself
CHECKHR (hr = pmsgPart->Load(pstmPart));
// We need another message and stream
CHECKHR (hr = pParts->AddPart(pmsgPart));
// Cleanup
SafeRelease(pmsgPart);
SafeRelease(pstmPart);
}
// Lets hope we read everything...
AssertSz(cbRead == cbMessage, "Please let sbailey know if these fails.");
exit:
// Succeeded
if (SUCCEEDED(hr))
{
// Returns Parts Object
(*ppParts) = pParts;
(*ppParts)->AddRef();
}
// Cleanup
SafeRelease(pRootBody);
SafeRelease(pstmMsg);
SafeRelease(pParts);
SafeRelease(pRootProps);
SafeRelease(pmsgPart);
SafeRelease(pstmPart);
SafeMemFree(pszSubjectAddOn);
SafeMemFree(pszSubjectNew);
SafeMemFree(prghAttach);
MimeOleVariantFree(&rSubject);
MimeOleVariantFree(&rFileName);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CompareBlob
// --------------------------------------------------------------------------------
int CompareBlob(LPCBLOB pBlob1, LPCBLOB pBlob2)
{
// Locals
register int ret = 0;
Assert(pBlob1 && pBlob2);
if (pBlob1->cbSize != pBlob2->cbSize)
ret = pBlob1->cbSize - pBlob2->cbSize;
else
ret = memcmp(pBlob1->pBlobData, pBlob2->pBlobData, pBlob2->cbSize);
return ret;
}
// --------------------------------------------------------------------------------
// HrCopyBlob
// --------------------------------------------------------------------------------
HRESULT HrCopyBlob(LPCBLOB pIn, LPBLOB pOut)
{
// Locals
HRESULT hr;
ULONG cb = 0;
Assert(pIn && pOut);
if (pIn->cbSize == 0)
{
pOut->cbSize = 0;
pOut->pBlobData = NULL;
return S_OK;
}
// Dup It...
cb = pIn->cbSize;
#ifdef _WIN64
cb = LcbAlignLcb(cb);
#endif //_WIN64
if (SUCCEEDED(hr = HrAlloc((LPVOID *)&pOut->pBlobData, cb)))
{
// Copy Memory
CopyMemory(pOut->pBlobData, pIn->pBlobData, pIn->cbSize);
// Set Size
pOut->cbSize = pIn->cbSize;
}
else
{
pOut->cbSize = 0;
}
// Done
return hr;
}
// --------------------------------------------------------------------------------
// PriorityFromStringA
// --------------------------------------------------------------------------------
IMSGPRIORITY PriorityFromStringA(LPCSTR pszPriority)
{
// Locals
IMSGPRIORITY priority=IMSG_PRI_NORMAL;
DWORD dwPriority;
// If IsDigit...
if (IsDigit((LPSTR)pszPriority))
{
// Convert
dwPriority = (DWORD)StrToInt(pszPriority);
// Map to pri type
if (dwPriority <= 2)
priority = IMSG_PRI_HIGH;
else if (dwPriority > 3)
priority = IMSG_PRI_LOW;
}
// Otheriwse, map from high, normal and low...
else
{
// High, Highest, Low, Lowest
if (lstrcmpi(pszPriority, STR_PRI_MS_HIGH) == 0)
priority = IMSG_PRI_HIGH;
else if (lstrcmpi(pszPriority, STR_PRI_MS_LOW) == 0)
priority = IMSG_PRI_LOW;
else if (lstrcmpi(pszPriority, STR_PRI_HIGHEST) == 0)
priority = IMSG_PRI_HIGH;
else if (lstrcmpi(pszPriority, STR_PRI_LOWEST) == 0)
priority = IMSG_PRI_LOW;
}
// Done
return priority;
}
// --------------------------------------------------------------------------------
// PriorityFromStringW
// --------------------------------------------------------------------------------
IMSGPRIORITY PriorityFromStringW(LPCWSTR pwszPriority)
{
// Locals
HRESULT hr=S_OK;
LPSTR pszPriority=NULL;
IMSGPRIORITY priority=IMSG_PRI_NORMAL;
// Convert to ANSI
CHECKALLOC(pszPriority = PszToANSI(CP_ACP, pwszPriority));
// Normal Conversion
priority = PriorityFromStringA(pszPriority);
exit:
// Done
return priority;
}
// --------------------------------------------------------------------------------
// MimeOleCompareUrlSimple
// --------------------------------------------------------------------------------
HRESULT MimeOleCompareUrlSimple(LPCSTR pszUrl1, LPCSTR pszUrl2)
{
// Locals
HRESULT hr=S_OK;
CHAR chUrl1;
CHAR chUrl2;
// Skip leading white space
while(*pszUrl1 && (' ' == *pszUrl1 || '\t' == *pszUrl1))
pszUrl1++;
while(*pszUrl2 && (' ' == *pszUrl2 || '\t' == *pszUrl2))
pszUrl2++;
// Start the loop
while(*pszUrl1 && *pszUrl2)
{
// Case Insensitive
chUrl1 = TOUPPERA(*pszUrl1);
chUrl2 = TOUPPERA(*pszUrl2);
// Not Equal
if (chUrl1 != chUrl2)
{
hr = S_FALSE;
break;
}
// Next
pszUrl1++;
pszUrl2++;
}
// Skip over trailing whitespace
while(*pszUrl1 && (' ' == *pszUrl1 || '\t' == *pszUrl1))
pszUrl1++;
while(*pszUrl2 && (' ' == *pszUrl2 || '\t' == *pszUrl2))
pszUrl2++;
// No substrings
if ('\0' != *pszUrl1 || '\0' != *pszUrl2)
hr = S_FALSE;
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleCompareUrl
// --------------------------------------------------------------------------------
HRESULT MimeOleCompareUrl(LPCSTR pszCurrentUrl, BOOL fUnEscapeCurrent, LPCSTR pszCompareUrl, BOOL fUnEscapeCompare)
{
// Locals
HRESULT hr=S_OK;
LPSTR pszUrl1=(LPSTR)pszCurrentUrl;
LPSTR pszUrl2=(LPSTR)pszCompareUrl;
CHAR chPrev='\0';
CHAR chUrl1;
CHAR chUrl2;
ULONG cb;
// Stack Strings
STACKSTRING_DEFINE(rCurrentUrl, 255);
STACKSTRING_DEFINE(rCompareUrl, 255);
// fUnEscapeCurrent
if (fUnEscapeCurrent)
{
// Get Size
cb = lstrlen(pszCurrentUrl) + 1;
// Set Size
STACKSTRING_SETSIZE(rCurrentUrl, cb);
// Copy
CopyMemory(rCurrentUrl.pszVal, pszCurrentUrl, cb);
// Dupe It
CHECKHR(hr = UrlUnescapeA(rCurrentUrl.pszVal, NULL, NULL, URL_UNESCAPE_INPLACE));
// Adjust pszUrl1
pszUrl1 = rCurrentUrl.pszVal;
}
// fUnEscapeCurrent
if (fUnEscapeCompare)
{
// Get Size
cb = lstrlen(pszCompareUrl) + 1;
// Set Size
STACKSTRING_SETSIZE(rCompareUrl, cb);
// Copy
CopyMemory(rCompareUrl.pszVal, pszCompareUrl, cb);
// Dupe It
CHECKHR(hr = UrlUnescapeA(rCompareUrl.pszVal, NULL, NULL, URL_UNESCAPE_INPLACE));
// Adjust pszUrl2
pszUrl2 = rCompareUrl.pszVal;
}
// Skip leading white space
while(*pszUrl1 && (' ' == *pszUrl1 || '\t' == *pszUrl1))
pszUrl1++;
while(*pszUrl2 && (' ' == *pszUrl2 || '\t' == *pszUrl2))
pszUrl2++;
// Start the loop
while(*pszUrl1 && *pszUrl2)
{
// Case Insensitive
chUrl1 = TOUPPERA(*pszUrl1);
chUrl2 = TOUPPERA(*pszUrl2);
// Special case search for '/'
if (':' == chPrev && '/' == chUrl2 && '/' != *(pszUrl2 + 1) && '/' == chUrl1 && '/' == *(pszUrl1 + 1))
{
// Next
pszUrl1++;
// Done
if ('\0' == *pszUrl1)
{
hr = S_FALSE;
break;
}
// Rset chUrl1
chUrl1 = TOUPPERA(*pszUrl1);
}
// Not Equal
if (chUrl1 != chUrl2)
{
hr = S_FALSE;
break;
}
// Save Prev
chPrev = *pszUrl1;
// Next
pszUrl1++;
pszUrl2++;
}
// Skip over trailing whitespace
while(*pszUrl1 && (' ' == *pszUrl1 || '\t' == *pszUrl1))
pszUrl1++;
while(*pszUrl2 && (' ' == *pszUrl2 || '\t' == *pszUrl2))
pszUrl2++;
// Raid 63823: Mail : Content-Location Href's inside the message do not work if there is a Start Parameter in headers
// Skim over remaining '/' in both urls
while (*pszUrl1 && '/' == *pszUrl1)
pszUrl1++;
while (*pszUrl2 && '/' == *pszUrl2)
pszUrl2++;
// No substrings
if ('\0' != *pszUrl1 || '\0' != *pszUrl2)
hr = S_FALSE;
// file://d:\test\foo.mhtml == d:\test\foo.mhtml
if (S_FALSE == hr && StrCmpNI(pszCurrentUrl, "file:", 5) == 0)
{
// Skip over file:
LPSTR pszRetryUrl = (LPSTR)(pszCurrentUrl + 5);
// Skip over forward slashes
while(*pszRetryUrl && '/' == *pszRetryUrl)
pszRetryUrl++;
// Compare Again
hr = MimeOleCompareUrl(pszRetryUrl, fUnEscapeCurrent, pszCompareUrl, fUnEscapeCompare);
}
exit:
// Cleanup
STACKSTRING_FREE(rCurrentUrl);
STACKSTRING_FREE(rCompareUrl);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleWrapHeaderText
// --------------------------------------------------------------------------------
HRESULT MimeOleWrapHeaderText(CODEPAGEID codepage, ULONG cchMaxLine, LPCSTR pszLine,
ULONG cchLine, LPSTREAM pStream)
{
// Locals
HRESULT hr=S_OK;
ULONG cchIndex=0;
ULONG cchWrite;
// Invalid Arg
Assert(pszLine && pszLine[cchLine] == '\0' && pStream && cchMaxLine >= 2);
// Start Writing
while(1)
{
// Validate
Assert(cchIndex <= cchLine);
// Compute cchWrite
cchWrite = min(cchLine - cchIndex, cchMaxLine - 2);
// Done
if (0 == cchWrite)
{
// Final Line Wrap
CHECKHR(hr = pStream->Write(c_szCRLF, 2, NULL));
// Done
break;
}
// Write the line
CHECKHR(hr = pStream->Write(pszLine + cchIndex, cchWrite, NULL));
// If there is still more text
if (cchIndex + cchWrite < cchLine)
{
// Write '\r\n\t'
CHECKHR(hr = pStream->Write(c_szCRLFTab, 3, NULL));
}
// Increment iText
cchIndex += cchWrite;
}
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleCreateBody
// --------------------------------------------------------------------------------
HRESULT MimeOleCreateBody(IMimeBody **ppBody)
{
HRESULT hr;
CMessageBody *pNew;
pNew = new CMessageBody(NULL, NULL);
if (NULL == pNew)
return TrapError(E_OUTOFMEMORY);
hr = pNew->QueryInterface(IID_IMimeBody, (LPVOID *)ppBody);
pNew->Release();
return hr;
}
// --------------------------------------------------------------------------------
// MimeOleGetSentTime
// --------------------------------------------------------------------------------
HRESULT MimeOleGetSentTime(LPCONTAINER pContainer, DWORD dwFlags, LPMIMEVARIANT pValue)
{
// Locals
HRESULT hr=S_OK;
// Get the data: header field
if (FAILED(pContainer->GetProp(SYM_HDR_DATE, dwFlags, pValue)))
{
// Locals
SYSTEMTIME st;
MIMEVARIANT rValue;
// Setup rValue
rValue.type = MVT_VARIANT;
rValue.rVariant.vt = VT_FILETIME;
// Get current systemtime
GetSystemTime(&st);
SystemTimeToFileTime(&st, &rValue.rVariant.filetime);
// If the Conversion Fails, get the current time
CHECKHR(hr = pContainer->HrConvertVariant(SYM_ATT_SENTTIME, NULL, IET_DECODED, dwFlags, 0, &rValue, pValue));
}
exit:
// Done
return hr;
}