You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4428 lines
125 KiB
4428 lines
125 KiB
// --------------------------------------------------------------------------------
|
|
// 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;
|
|
}
|