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.
6585 lines
208 KiB
6585 lines
208 KiB
// --------------------------------------------------------------------------------
|
|
// BookBody.cpp
|
|
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
|
|
// Steven J. Bailey
|
|
// --------------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "bookbody.h"
|
|
#include "dllmain.h"
|
|
#include "ibdylock.h"
|
|
#include "stmlock.h"
|
|
#include "ibdystm.h"
|
|
#include "resource.h"
|
|
#include "smime.h"
|
|
#include "objheap.h"
|
|
#include "internat.h"
|
|
#include "urlmon.h"
|
|
#include "symcache.h"
|
|
#include "booktree.h"
|
|
#include <demand.h>
|
|
#include "mimeapi.h"
|
|
#include <shlwapi.h>
|
|
#include "webdocs.h"
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// ASSERTINIT
|
|
// --------------------------------------------------------------------------------
|
|
#define ASSERTINIT \
|
|
AssertSz(m_pContainer, "Object is being used before a call to InitNew")
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Default Body Options
|
|
// --------------------------------------------------------------------------------
|
|
static const BODYOPTIONS g_rDefBodyOptions = {
|
|
IET_UNKNOWN, // OID_TRANSMIT_BODY_FORMAT
|
|
DEF_CBMAX_BODY_LINE, // OID_CBMAX_BODY_LINE
|
|
DEF_WRAP_BODY_TEXT, // OID_WRAP_BODY_TEXT
|
|
DEF_BODY_REMOVE_NBSP, // OID_BODY_REMOVE_NBSP
|
|
DEF_DBCS_ESCAPE_IS_8BIT, // OID_DBCS_ESCAPE_IS_8BIT
|
|
DEF_HIDE_TNEF_ATTACHMENTS, // OID_HIDE_TNEF_ATTACHMENTS
|
|
MST_NONE, // OID_SECURITY_TYPE
|
|
NULL, // OID_SECURITY_ALG_HASH and OID_SECURITY_ALG_HASH_RG
|
|
{ 0, NULL }, // OID_SECURITY_ALG_BULK
|
|
NULL, // OID_SECURITY_CERT_SIGNING and OID_SECURITY_CERT_SIGNING_RG
|
|
0, // OID_SECURITY_CERT_DECRYPTION
|
|
NULL, // OID_SECURITY_HCERTSTORE and OID_SECURITY_HCERTSTORE_RG
|
|
{ 0, NULL }, // OID_SECURITY_SEARCHSTORES
|
|
0,
|
|
NULL, // OID_SECURITY_RG_IASN
|
|
#ifdef SMIME_V3
|
|
NULL, // OID_SECURITY_AUTHATTR and OID_SECURITY_AUTHATTR_RG
|
|
NULL, // OID_SECURITY_UNAUTHATTR and OID_SECURITY_UNAUTHATTR_RG
|
|
NULL, // OID_SECURITY_UNPROTECTATTR_RG
|
|
#else // !SMIME_V3
|
|
NULL, // OID_SECURITY_SYMCAPS and OID_SECURITY_SYMCAPS_RG
|
|
NULL, // OID_SECURITY_AUTHATTR and OID_SECURITY_AUTHATTR_RG
|
|
NULL, // OID_SECURITY_UNAUTHATTR and OID_SECURITY_UNAUTHATTR_RG
|
|
NULL, // OID_SECURITY_SIGNTIME and OID_SECURITY_SIGNTIME_RG
|
|
#endif // SMIME_V3
|
|
NULL, // OID_SECURITY_USER_VALIDITY and OID_SECURITY_USER_VALIDITY_RG
|
|
NULL, // OID_SECURITY_RO_MSG_VALIDITY and OID_SECURITY_RO_MSG_VALIDITY_RG
|
|
0, // OID_SECURITY_HCRYPTPROV
|
|
0, // OID_SECURITY_ENCODE_FLAGS
|
|
FALSE, // OID_SECURITY_CERT_INCLUDED
|
|
// This is NULL b/c default is generated at runtime
|
|
NULL, // OID_SECURITY_HWND_OWNER
|
|
// Base64 is the recommended value in the S/MIME spec
|
|
IET_BASE64, // OID_SECURITY_REQUESTED_CTE
|
|
#ifdef SMIME_V3
|
|
NULL, // OID_SECURITY_RECEIPT_RG
|
|
NULL, // OID_SECURITY_MESSAGE_HASH_RG
|
|
NULL, // OID_SECURITY_KEY_PROMPT
|
|
#endif // SMIME_V3
|
|
DEF_SHOW_MACBINARY, // OID_SHOW_MACBINARY
|
|
DEF_SUPPORT_EXTERNAL_BODY, // OID_SUPPORT_EXTERNAL_BODY
|
|
0, // cSecurityLayers (size of arrays of
|
|
// OID_SECURITY_ALG_HASH
|
|
// OID_SECURITY_CERT_SIGNING
|
|
// OID_SECURITY_HCERTSTORE
|
|
// OID_SECURITY_SYMCAPS
|
|
// OID_SECURITY_AUTHATTR
|
|
// OID_SECURITY_UNAUTHATTR
|
|
// OID_SECURITY_SIGNTIME
|
|
// OID_SECURITY_USER_VALIDITY
|
|
// OID_SECURITY_RO_MSG_VALIDITY)
|
|
FALSE, // OID_NOSECURITY_ON_SAVE
|
|
#ifdef SMIME_V3
|
|
0, 0, NULL, // cRecipients/rgRecipients
|
|
#endif // SMIME_V3
|
|
NULL, // OID_SECURITY_ENCRYPT_CERT_BAG
|
|
};
|
|
|
|
static const BLOB blobNULL = {0, NULL};
|
|
|
|
HRESULT HrCopyBlobArray(LPCBLOB pIn, ULONG cEntries, PROPVARIANT FAR * pvOut);
|
|
HRESULT HrCopyDwordArray(LPDWORD pIn, ULONG cEntries, PROPVARIANT FAR * pvOut);
|
|
HRESULT HrCopyIntoUlonglongArray(ULARGE_INTEGER * pIn, ULONG cEntries, PROPVARIANT FAR * pvOut);
|
|
HRESULT HrCopyFiletimeArray(LPFILETIME pIn, ULONG cEntries, PROPVARIANT FAR * pvOut);
|
|
DWORD MergeDWORDFlags(LPDWORD rgdw, ULONG cEntries);
|
|
extern HRESULT HrGetLastError(void);
|
|
extern BOOL FIsMsasn1Loaded();
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// WebBookContentBody_CreateInstance
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT WebBookContentBody_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppUnknown)
|
|
{
|
|
// Invalid Arg
|
|
Assert(ppUnknown);
|
|
|
|
// Initialize
|
|
*ppUnknown = NULL;
|
|
|
|
// Create me
|
|
CMessageBody *pNew = new CMessageBody(NULL, pUnkOuter);
|
|
if (NULL == pNew)
|
|
return TrapError(E_OUTOFMEMORY);
|
|
|
|
// Return the Innter
|
|
*ppUnknown = pNew->GetInner();
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::CMessageBody
|
|
// --------------------------------------------------------------------------------
|
|
CMessageBody::CMessageBody(LPTREENODEINFO pNode, IUnknown *pUnkOuter)
|
|
: m_pNode(pNode), CPrivateUnknown(pUnkOuter)
|
|
{
|
|
DllAddRef();
|
|
m_cRef = 1;
|
|
m_dwState = 0;
|
|
m_pszDisplay = NULL;
|
|
m_ietEncoding = IET_BINARY;
|
|
m_ietPrevious = IET_UNKNOWN;
|
|
m_pCharset = CIntlGlobals::GetDefBodyCset();
|
|
m_pCsetTagged = NULL;
|
|
m_pContainer = NULL;
|
|
m_cbExternal = 0xFFFFFFFF;
|
|
ZeroMemory(&m_rStorage, sizeof(BODYSTORAGE));
|
|
CopyMemory(&m_rOptions, &g_rDefBodyOptions, sizeof(BODYOPTIONS));
|
|
// (t-erikne) need to get this default at run time
|
|
m_rOptions.hwndOwner = HWND_DESKTOP;
|
|
InitializeCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::~CMessageBody
|
|
// --------------------------------------------------------------------------------
|
|
CMessageBody::~CMessageBody(void)
|
|
{
|
|
SafeRelease(m_pContainer);
|
|
SafeMemFree(m_pszDisplay);
|
|
SafeRelease(m_rStorage.pUnkRelease);
|
|
|
|
// Clear out the options
|
|
_FreeOptions();
|
|
|
|
DeleteCriticalSection(&m_cs);
|
|
DllRelease();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::PrivateQueryInterface
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::PrivateQueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
// check params
|
|
if (ppv == NULL)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Init
|
|
*ppv = NULL;
|
|
|
|
// Find IID
|
|
if (IID_IMimeBody == riid)
|
|
*ppv = (IMimeBody *)this;
|
|
else if (IID_IMimeBodyW == riid)
|
|
*ppv = (IMimeBodyW *)this;
|
|
else if (IID_IMimePropertySet == riid)
|
|
*ppv = (IMimePropertySet *)this;
|
|
else if (IID_IPersist == riid)
|
|
*ppv = (IPersist *)this;
|
|
else if (IID_IPersistStreamInit == riid)
|
|
*ppv = (IPersistStreamInit *)this;
|
|
else if (IID_CMessageBody == riid)
|
|
*ppv = (CMessageBody *)this;
|
|
#ifdef SMIME_V3
|
|
else if (IID_IMimeSecurity2 == riid)
|
|
*ppv = (IMimeSecurity2 *) this;
|
|
#endif
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
// AddRef It
|
|
((IUnknown *)*ppv)->AddRef();
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::RevokeTreeNode
|
|
// --------------------------------------------------------------------------------
|
|
void CMessageBody::RevokeTreeNode(void)
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
m_pNode = NULL;
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::HrBindToTree
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::HrBindToTree(CStreamLockBytes *pStmLock, LPTREENODEINFO pNode)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
HCHARSET hCharset=NULL;
|
|
IStream *pstmBody=NULL;
|
|
ASSERTINIT;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Invalid Arg
|
|
Assert(pNode && NULL == pNode->pLockBytes && pStmLock && m_pNode == pNode);
|
|
|
|
// Create the body lock bytes
|
|
CHECKALLOC(pNode->pLockBytes = new CBodyLockBytes(pStmLock, pNode));
|
|
|
|
// Just assume it
|
|
m_rStorage.riid = IID_ILockBytes;
|
|
m_rStorage.pLockBytes = (ILockBytes *)pNode->pLockBytes;
|
|
m_rStorage.pUnkRelease = m_rStorage.pLockBytes;
|
|
m_rStorage.pUnkRelease->AddRef();
|
|
|
|
// Test for binhex
|
|
if (S_FALSE == m_pContainer->IsPropSet(PIDTOSTR(PID_HDR_CNTXFER)) && m_pContainer->IsContentType(STR_CNT_APPLICATION, STR_SUB_BINHEX) == S_OK)
|
|
{
|
|
// Locals
|
|
PROPVARIANT rVariant;
|
|
|
|
// Setup the variant
|
|
rVariant.vt = VT_LPSTR;
|
|
|
|
// If there is a filename, lets re-compute the content-type
|
|
if (SUCCEEDED(m_pContainer->GetProp(PIDTOSTR(PID_ATT_FILENAME), 0, &rVariant)))
|
|
{
|
|
// Locals
|
|
LPSTR pszCntType;
|
|
LPSTR pszSubType;
|
|
|
|
// Get mime file information
|
|
if (SUCCEEDED(MimeOleGetFileInfo(rVariant.pszVal, &pszCntType, &pszSubType, NULL, NULL, NULL)))
|
|
{
|
|
// ContentType
|
|
if (pszCntType && pszSubType)
|
|
{
|
|
CHECKHR(hr = m_pContainer->SetProp(PIDTOSTR(PID_ATT_PRITYPE), pszCntType));
|
|
CHECKHR(hr = m_pContainer->SetProp(PIDTOSTR(PID_ATT_SUBTYPE), pszSubType));
|
|
}
|
|
|
|
// application/octet-stream
|
|
else
|
|
{
|
|
CHECKHR(hr = m_pContainer->SetProp(PIDTOSTR(PID_HDR_CNTTYPE), STR_MIME_APPL_STREAM));
|
|
}
|
|
|
|
// Cleanup
|
|
SafeMemFree(pszCntType);
|
|
SafeMemFree(pszSubType);
|
|
}
|
|
|
|
// Clenaup
|
|
SafeMemFree(rVariant.pszVal);
|
|
}
|
|
|
|
// Set the Content-Transfer-Encoding to binhex
|
|
m_pContainer->SetProp(PIDTOSTR(PID_HDR_CNTXFER), STR_ENC_BINHEX40);
|
|
|
|
// The encoding type better be binhex
|
|
Assert(m_pContainer->GetEncodingType() == IET_BINHEX40);
|
|
}
|
|
|
|
// Otherwise, test for message/external-body
|
|
else if (m_rOptions.fExternalBody && S_OK == m_pContainer->IsContentType(STR_CNT_MESSAGE, STR_SUB_EXTERNAL))
|
|
{
|
|
// Bind to External-Body
|
|
_BindToExternalBody();
|
|
}
|
|
|
|
// Save The Format
|
|
m_ietPrevious = m_ietEncoding = m_pContainer->GetEncodingType();
|
|
|
|
// Raid 2215: Map a CTE of binary to 8bit so that it gets decoded correctly from the internet character set
|
|
if (IET_BINARY == m_ietEncoding)
|
|
{
|
|
// Switch to 8bit because ibdystm.cpp will not do the charset translation right if the source is binary...
|
|
m_ietEncoding = IET_8BIT;
|
|
}
|
|
|
|
// LateTnef Check
|
|
if (ISFLAGSET(pNode->dwState, NODESTATE_VERIFYTNEF))
|
|
{
|
|
// Get the data stream
|
|
if (SUCCEEDED(GetData(IET_BINARY, &pstmBody)))
|
|
{
|
|
// If TNEF, apply content type...
|
|
if (MimeOleIsTnefStream(pstmBody) == S_OK)
|
|
{
|
|
// application/ms-tnef
|
|
CHECKHR(hr = m_pContainer->SetProp(SYM_HDR_CNTTYPE, STR_MIME_APPLY_MSTNEF));
|
|
}
|
|
}
|
|
|
|
// Clear the flag
|
|
FLAGCLEAR(pNode->dwState, NODESTATE_VERIFYTNEF);
|
|
}
|
|
|
|
// If I'm a message with crypto mime types, say I'm "secure"
|
|
if (IsSecureContentType(m_pContainer))
|
|
{
|
|
// TREENODE_SECURE
|
|
FLAGSET(m_dwState, BODYSTATE_SECURE);
|
|
}
|
|
|
|
// If the Header was tagged with a charset, use that charset
|
|
if (m_pContainer->IsState(COSTATE_CSETTAGGED) == S_OK)
|
|
{
|
|
// Get Internal Character Set
|
|
if (SUCCEEDED(m_pContainer->GetCharset(&hCharset)))
|
|
{
|
|
// Get Pointer
|
|
SideAssert(SUCCEEDED(g_pInternat->HrOpenCharset(hCharset, &m_pCharset)));
|
|
|
|
// Save this as m_pCsetTagged
|
|
m_pCsetTagged = m_pCharset;
|
|
}
|
|
|
|
// I was tagged with a charset
|
|
FLAGSET(m_dwState, BODYSTATE_CSETTAGGED);
|
|
}
|
|
|
|
// Bound to tree
|
|
FLAGSET(pNode->dwState, NODESTATE_BOUNDTOTREE);
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pstmBody);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CMessageBody::_BindToExternalBody
|
|
// ---------------------------------------------------------------------------
|
|
void CMessageBody::_BindToExternalBody(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPSTR pszAccessType=NULL;
|
|
LPSTR pszUrl=NULL;
|
|
IStream *pstmBody=NULL;
|
|
DWORD cbSize=0xFFFFFFFF;
|
|
CMimeWebDocument *pWebDoc=NULL;
|
|
|
|
// Get par:content-type:access-type
|
|
CHECKHR(hr = m_pContainer->GetProp(STR_PAR_ACCESSTYPE, &pszAccessType));
|
|
|
|
// Handle Access-Types that I know about
|
|
if (lstrcmpi(pszAccessType, "X-URL") == 0)
|
|
{
|
|
// Locals
|
|
PROPVARIANT rSize;
|
|
|
|
// Get par:content-type:xurl
|
|
CHECKHR(hr = m_pContainer->GetProp(STR_PAR_XURL, &pszUrl));
|
|
|
|
// Create the WebDoc
|
|
CHECKALLOC(pWebDoc = new CMimeWebDocument);
|
|
|
|
// Initialize It
|
|
CHECKHR(hr = pWebDoc->HrInitialize(NULL, pszUrl));
|
|
|
|
// Setup Variant
|
|
rSize.vt = VT_UI4;
|
|
|
|
// Get par:content-type:size
|
|
if (SUCCEEDED(m_pContainer->GetProp(STR_PAR_SIZE, 0, &rSize)))
|
|
cbSize = rSize.ulVal;
|
|
}
|
|
|
|
// If we have a webdocument...
|
|
if (pWebDoc)
|
|
{
|
|
// Get the Body Data
|
|
if (SUCCEEDED(GetData(IET_BINARY, &pstmBody)))
|
|
{
|
|
// Locals
|
|
PROPVARIANT rOption;
|
|
|
|
// Setup the option variant
|
|
rOption.vt = VT_UI4;
|
|
rOption.ulVal = RELOAD_HEADER_REPLACE;
|
|
|
|
// Set special option since I'm realoding the header...
|
|
CHECKHR(hr = m_pContainer->SetOption(OID_HEADER_RELOAD_TYPE, &rOption));
|
|
|
|
// Load this body into the container
|
|
CHECKHR(hr = m_pContainer->Load(pstmBody));
|
|
|
|
// Reset the option variant
|
|
rOption.vt = VT_UI4;
|
|
rOption.ulVal = DEF_HEADER_RELOAD_TYPE_PROPSET;
|
|
|
|
// Set special option since I'm realoding the header...
|
|
CHECKHR(hr = m_pContainer->SetOption(OID_HEADER_RELOAD_TYPE, &rOption));
|
|
}
|
|
|
|
// SetData
|
|
CHECKHR(hr = SetData(IET_BINARY, NULL, NULL, IID_IMimeWebDocument, (LPVOID)pWebDoc));
|
|
|
|
// Create a External Body Info Structure: MUST BE SET AFTER CALL TO SETDATA
|
|
FLAGSET(m_dwState, BODYSTATE_EXTERNAL);
|
|
|
|
// Set Size: MUST BE SET AFTER CALL TO SETDATA
|
|
m_cbExternal = cbSize;
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pszAccessType);
|
|
SafeMemFree(pszUrl);
|
|
SafeRelease(pstmBody);
|
|
SafeRelease(pWebDoc);
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
// ---------------------------------------------------------------------------
|
|
// CMessageBody::UseOriginalCharset
|
|
// ---------------------------------------------------------------------------
|
|
void CMessageBody::UseOriginalCharset(void)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// We should have m_pCsetTagged
|
|
Assert(m_pCsetTagged);
|
|
|
|
// Set the Charset
|
|
if (m_pCsetTagged)
|
|
SetCharset(m_pCsetTagged->hCharset, CSET_APPLY_ALL);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
#endif
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CMessageBody::SetDisplayName
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::SetDisplayName(LPCSTR pszDisplayName)
|
|
{
|
|
LPWSTR pwszDispName;
|
|
HRESULT hr = S_OK;
|
|
|
|
Assert(pszDisplayName);
|
|
|
|
IF_NULLEXIT(pwszDispName = PszToUnicode(CP_ACP, pszDisplayName));
|
|
|
|
hr = SetDisplayNameW(pwszDispName);
|
|
|
|
exit:
|
|
MemFree(pwszDispName);
|
|
|
|
return hr;
|
|
}
|
|
|
|
#define DisplayMaxLen 64
|
|
|
|
STDMETHODIMP CMessageBody::SetDisplayNameW(LPCWSTR pszDisplayName)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
WCHAR szSize[30],
|
|
szScratch[30],
|
|
szBuf[MAX_PATH];
|
|
ULONG cbSize=0,
|
|
cAlloc,
|
|
cLen;
|
|
ASSERTINIT;
|
|
|
|
// check params
|
|
if (NULL == pszDisplayName)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Free current display name
|
|
SafeMemFree(m_pszDisplay);
|
|
|
|
// Get Data Size...
|
|
GetEstimatedSize(IET_BINARY, &cbSize);
|
|
|
|
// Format the Size
|
|
StrFormatByteSizeW(cbSize, szScratch, ARRAYSIZE(szScratch));
|
|
StrCpyNW(szSize, L"(", ARRAYSIZE(szSize));
|
|
StrCatBuffW(szSize, szScratch, ARRAYSIZE(szSize));
|
|
StrCatBuffW(szSize, L")", ARRAYSIZE(szSize));
|
|
|
|
cLen = lstrlenW(pszDisplayName);
|
|
if (cLen+1 > ARRAYSIZE(szBuf))
|
|
cLen = ARRAYSIZE(szBuf) - 1;
|
|
StrCpyNW(szBuf, pszDisplayName, cLen+1);
|
|
PathStripPathW(szBuf);
|
|
cLen = lstrlenW(szBuf);
|
|
if (cLen > DisplayMaxLen)
|
|
{
|
|
WCHAR szBuf2[MAX_PATH];
|
|
WCHAR *szExt;
|
|
szExt = PathFindExtensionW(szBuf);
|
|
if (*szExt)
|
|
{
|
|
int cExt = lstrlenW(szExt);
|
|
if (cExt < DisplayMaxLen-3)
|
|
{
|
|
WCHAR szExt2[DisplayMaxLen];
|
|
StrCpyNW(szExt2, szExt, ARRAYSIZE(szExt2));
|
|
PathCompactPathExW(szBuf2, szBuf, DisplayMaxLen-cExt, 0);
|
|
StrCatBuffW(szBuf2, szExt2, ARRAYSIZE(szBuf2));
|
|
}
|
|
else
|
|
PathCompactPathExW(szBuf2, szBuf, DisplayMaxLen, 0);
|
|
}
|
|
else
|
|
{
|
|
PathCompactPathExW(szBuf2, szBuf, DisplayMaxLen, 0);
|
|
}
|
|
StrCpyNW(szBuf, szBuf2, ARRAYSIZE(szBuf));
|
|
}
|
|
|
|
// Size to allocate: filename.dat (x)\0
|
|
cAlloc = lstrlenW(szBuf) + lstrlenW(szSize) + 2;
|
|
|
|
// Dup the display name
|
|
CHECKALLOC(m_pszDisplay = PszAllocW(cAlloc));
|
|
|
|
// Format the Display Name
|
|
StrCpyNW(m_pszDisplay, szBuf, cAlloc);
|
|
StrCatBuffW(m_pszDisplay, L" ", cAlloc);
|
|
StrCatBuffW(m_pszDisplay, szSize, cAlloc);
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CMessageBody::GetDisplayName
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetDisplayName(LPSTR *ppszDisplayName)
|
|
{
|
|
LPWSTR pwszDispName = NULL;
|
|
HRESULT hr;
|
|
|
|
Assert(ppszDisplayName);
|
|
|
|
*ppszDisplayName = NULL;
|
|
|
|
IF_FAILEXIT(hr = GetDisplayNameW(ppszDisplayName ? &pwszDispName : NULL));
|
|
|
|
IF_NULLEXIT(*ppszDisplayName = PszToANSI(CP_ACP, pwszDispName));
|
|
|
|
exit:
|
|
MemFree(pwszDispName);
|
|
return TraceResult(hr);
|
|
}
|
|
|
|
STDMETHODIMP CMessageBody::GetDisplayNameW(LPWSTR *ppszDisplayName)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ASSERTINIT;
|
|
|
|
// check params
|
|
if (NULL == ppszDisplayName)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Init
|
|
*ppszDisplayName = NULL;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Do I have an internal displayname ?
|
|
if (NULL == m_pszDisplay)
|
|
{
|
|
LPSTR pszVal = NULL;
|
|
LPWSTR pwszVal = NULL;
|
|
|
|
// Use m_pszURL first
|
|
if (IID_IMimeWebDocument == m_rStorage.riid && SUCCEEDED(m_rStorage.pWebDocument->GetURL(&pszVal)))
|
|
SetDisplayName(pszVal);
|
|
|
|
// Raid-38681 - mail:file name is incorrect when attaching renamed saved message
|
|
// Raid-18813 - Single Bodies messages can have a filename and a subject.
|
|
else if (SUCCEEDED(m_pContainer->GetPropW(SYM_ATT_FILENAME, &pwszVal)) && pwszVal)
|
|
SetDisplayNameW(pwszVal);
|
|
|
|
// If I'm an message/rfc822
|
|
else if (m_pContainer->IsContentType(STR_CNT_MESSAGE, STR_SUB_RFC822) == S_OK && FExtractRfc822Subject(&pwszVal))
|
|
SetDisplayNameW(pwszVal);
|
|
|
|
// Parent is multipart/digest
|
|
else if (m_pNode && m_pNode->pParent && m_pNode->pParent->pBody && m_pNode->pParent->pBody->IsContentType(STR_CNT_MULTIPART, STR_SUB_DIGEST) == S_OK && FExtractRfc822Subject(&pwszVal))
|
|
SetDisplayNameW(pwszVal);
|
|
|
|
// Use Subject
|
|
else if (SUCCEEDED(m_pContainer->GetPropW(SYM_HDR_SUBJECT, &pwszVal)) && pwszVal)
|
|
SetDisplayNameW(pwszVal);
|
|
|
|
// Use Generated File Name...
|
|
else if (SUCCEEDED(m_pContainer->GetPropW(SYM_ATT_GENFNAME, &pwszVal)) && pwszVal)
|
|
SetDisplayNameW(pwszVal);
|
|
|
|
// Content Description
|
|
else if (SUCCEEDED(m_pContainer->GetPropW(SYM_HDR_CNTDESC, &pwszVal)) && pwszVal)
|
|
SetDisplayNameW(pwszVal);
|
|
|
|
SafeMemFree(pszVal);
|
|
SafeMemFree(pwszVal);
|
|
}
|
|
|
|
// If there is a display name now, then dup it.
|
|
if (m_pszDisplay)
|
|
CHECKALLOC(*ppszDisplayName = PszDupW(m_pszDisplay));
|
|
else
|
|
hr = MIME_E_NO_DATA;
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CMessageBody::FExtractRfc822Subject
|
|
// ---------------------------------------------------------------------------
|
|
BOOL CMessageBody::FExtractRfc822Subject(LPWSTR *ppwszVal)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
IStream *pstmData=NULL;
|
|
IMimePropertySet *pPropertySet=NULL;
|
|
PROPVARIANT rSubject;
|
|
ASSERTINIT;
|
|
|
|
// Invalid Arg
|
|
Assert(ppwszVal);
|
|
|
|
// Init
|
|
MimeOleVariantInit(&rSubject);
|
|
*ppwszVal = NULL;
|
|
|
|
// Get the data
|
|
CHECKHR(hr = GetData(IET_BINARY, &pstmData));
|
|
|
|
// Lets create a header
|
|
CHECKHR(hr = MimeOleCreatePropertySet(NULL, &pPropertySet));
|
|
|
|
// Parse the header
|
|
CHECKHR(hr = pPropertySet->Load(pstmData));
|
|
|
|
// Init Variant
|
|
rSubject.vt = VT_LPWSTR;
|
|
|
|
// Get the subject and set the display name
|
|
CHECKHR(hr = pPropertySet->GetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &rSubject));
|
|
|
|
// Raid-38681 - mail:file name is incorrect when attaching renamed saved message
|
|
if (FIsEmptyW(rSubject.pwszVal))
|
|
{
|
|
SafeMemFree(rSubject.pwszVal);
|
|
goto exit;
|
|
}
|
|
|
|
// Set this subject on my self so that STR_ATT_GENFNAME works
|
|
m_pContainer->SetProp(PIDTOSTR(PID_HDR_CNTDESC), 0, &rSubject);
|
|
|
|
// Return It
|
|
*ppwszVal = rSubject.pwszVal;
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pstmData);
|
|
SafeRelease(pPropertySet);
|
|
|
|
// Done
|
|
return (NULL == *ppwszVal) ? FALSE : TRUE;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CMessageBody::SetOption
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::SetOption(const TYPEDID oid, LPCPROPVARIANT pValue)
|
|
{
|
|
// check params
|
|
if (NULL == pValue)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
return InternalSetOption(oid, pValue, FALSE, FALSE);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CMessageBody::InternalSetOption
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT CMessageBody::InternalSetOption(const TYPEDID oid, LPCPROPVARIANT pValue, BOOL fInternal, BOOL fNoDirty)
|
|
{
|
|
// Locals
|
|
#ifdef SMIME_V3
|
|
DWORD cb;
|
|
#endif // SMIME_V3
|
|
HRESULT hr=S_OK;
|
|
DWORD i;
|
|
ASSERTINIT;
|
|
CAPROPVARIANT capv;
|
|
CAUL caul;
|
|
CAUH cauh;
|
|
CAFILETIME cafiletime;
|
|
#ifdef SMIME_V3
|
|
BYTE rgb[50];
|
|
#endif // SMIME_V3
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Handle Optid
|
|
switch(oid)
|
|
{
|
|
case OID_SUPPORT_EXTERNAL_BODY:
|
|
if (m_rOptions.fExternalBody != (pValue->boolVal ? TRUE : FALSE))
|
|
{
|
|
m_rOptions.fExternalBody = pValue->boolVal ? TRUE : FALSE;
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_SHOW_MACBINARY:
|
|
if (m_rOptions.fShowMacBin != (pValue->boolVal ? TRUE : FALSE))
|
|
{
|
|
m_rOptions.fShowMacBin = pValue->boolVal ? TRUE : FALSE;
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
|
|
case OID_CBMAX_BODY_LINE:
|
|
if (pValue->ulVal < MIN_CBMAX_BODY_LINE || pValue->ulVal > MAX_CBMAX_BODY_LINE)
|
|
{
|
|
hr = TrapError(MIME_E_INVALID_OPTION_VALUE);
|
|
goto exit;
|
|
}
|
|
if (m_rOptions.cbMaxLine != pValue->ulVal)
|
|
{
|
|
m_rOptions.cbMaxLine = pValue->ulVal;
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_TRANSMIT_BODY_ENCODING:
|
|
if (FALSE == FIsValidBodyEncoding((ENCODINGTYPE)pValue->ulVal))
|
|
{
|
|
hr = TrapError(MIME_E_INVALID_OPTION_VALUE);
|
|
goto exit;
|
|
}
|
|
if (m_rOptions.ietTransmit != (ENCODINGTYPE)pValue->ulVal)
|
|
{
|
|
m_rOptions.ietTransmit = (ENCODINGTYPE)pValue->ulVal;
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_WRAP_BODY_TEXT:
|
|
if (m_rOptions.fWrapText != (pValue->boolVal ? TRUE : FALSE))
|
|
{
|
|
m_rOptions.fWrapText = pValue->boolVal ? TRUE : FALSE;
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_HIDE_TNEF_ATTACHMENTS:
|
|
if (m_rOptions.fHideTNEF != (pValue->boolVal ? TRUE : FALSE))
|
|
{
|
|
m_rOptions.fHideTNEF = pValue->boolVal ? TRUE : FALSE;
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_DBCS_ESCAPE_IS_8BIT:
|
|
if (m_rOptions.fDBCSEscape8 != (pValue->boolVal ? TRUE : FALSE))
|
|
{
|
|
m_rOptions.fDBCSEscape8 = pValue->boolVal ? TRUE : FALSE;
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_TYPE:
|
|
if (m_rOptions.ulSecurityType != pValue->ulVal)
|
|
{
|
|
m_rOptions.ulSecurityType = pValue->ulVal;
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_ALG_HASH: // innermost signing algorithm
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(1)))
|
|
{
|
|
break;
|
|
}
|
|
if (CompareBlob(&m_rOptions.rgblobHash[0], &pValue->blob))
|
|
{
|
|
ReleaseMem(m_rOptions.rgblobHash[0].pBlobData);
|
|
hr = HrCopyBlob(&pValue->blob, &m_rOptions.rgblobHash[0]);
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_ALG_HASH_RG: // signing algorithms
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(pValue)))
|
|
{
|
|
break;
|
|
}
|
|
hr = _CompareCopyBlobArray(pValue, &m_rOptions.rgblobHash, fNoDirty);
|
|
break;
|
|
|
|
case OID_SECURITY_ALG_BULK:
|
|
if (CompareBlob(&m_rOptions.blobBulk, &pValue->blob))
|
|
{
|
|
ReleaseMem(m_rOptions.blobBulk.pBlobData);
|
|
hr = HrCopyBlob(&pValue->blob, &m_rOptions.blobBulk);
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
#ifndef _WIN64
|
|
case OID_SECURITY_CERT_SIGNING:
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(1)))
|
|
{
|
|
break;
|
|
}
|
|
if (m_rOptions.rgpcCertSigning[0] != (PCCERT_CONTEXT)pValue->ulVal)
|
|
{
|
|
if (m_rOptions.rgpcCertSigning[0])
|
|
CertFreeCertificateContext(m_rOptions.rgpcCertSigning[0]);
|
|
m_rOptions.rgpcCertSigning[0] = CertDuplicateCertificateContext((PCCERT_CONTEXT)pValue->ulVal);
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_CERT_SIGNING_RG: // signing algorithms
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(pValue)))
|
|
{
|
|
break;
|
|
}
|
|
caul = pValue->caul;
|
|
Assert(caul.cElems == m_rOptions.cSigners || 0 == m_rOptions.cSigners);
|
|
if (m_rOptions.cSigners != caul.cElems && 0 != m_rOptions.cSigners)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < caul.cElems; i++) {
|
|
if (m_rOptions.rgpcCertSigning[i] != (PCCERT_CONTEXT)caul.pElems[i])
|
|
{
|
|
if (m_rOptions.rgpcCertSigning[i])
|
|
CertFreeCertificateContext(m_rOptions.rgpcCertSigning[i]);
|
|
m_rOptions.rgpcCertSigning[i] = CertDuplicateCertificateContext((PCCERT_CONTEXT)caul.pElems[i]);
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_CERT_DECRYPTION:
|
|
if (m_rOptions.pcCertDecryption != (PCCERT_CONTEXT)pValue->ulVal)
|
|
{
|
|
if (m_rOptions.pcCertDecryption)
|
|
CertFreeCertificateContext(m_rOptions.pcCertDecryption);
|
|
m_rOptions.pcCertDecryption = CertDuplicateCertificateContext((PCCERT_CONTEXT)pValue->ulVal);
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_RG_CERT_ENCRYPT:
|
|
#ifdef SMIME_V3
|
|
for (i=0; i<pValue->caul.cElems; i++)
|
|
{
|
|
CMS_RECIPIENT_INFO info = {0};
|
|
info.pccert = (PCCERT_CONTEXT) pValue->caul.pElems[i];
|
|
hr = AddRecipient((i == 0) ? SMIME_RECIPIENT_REPLACE_ALL : 0, 1, &info);
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (SUCCEEDED(hr) && !fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
#else // !SMIME_V3
|
|
if (SUCCEEDED(hr = _CAULToCERTARRAY(pValue->caul, &m_rOptions.caEncrypt)))
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
#endif // !SMIME_V3
|
|
break;
|
|
|
|
case OID_SECURITY_HCERTSTORE:
|
|
CertCloseStore(m_rOptions.hCertStore, 0);
|
|
if (pValue->ulVal)
|
|
m_rOptions.hCertStore = CertDuplicateStore((HCERTSTORE)pValue->ulVal);
|
|
else
|
|
m_rOptions.hCertStore = NULL;
|
|
break;
|
|
|
|
case OID_SECURITY_ENCRYPT_CERT_BAG:
|
|
CertCloseStore(m_rOptions.hstoreEncrypt, 0);
|
|
if (pValue->ulVal)
|
|
m_rOptions.hstoreEncrypt = CertDuplicateStore((HCERTSTORE) pValue->ulVal);
|
|
else
|
|
m_rOptions.hstoreEncrypt = NULL;
|
|
break;
|
|
|
|
case OID_SECURITY_RG_CERT_BAG:
|
|
if (SUCCEEDED(hr = _CAULToCertStore(pValue->caul, &m_rOptions.hCertStore)))
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
break;
|
|
|
|
case OID_SECURITY_SEARCHSTORES:
|
|
if (SUCCEEDED(hr = _CAULToSTOREARRAY(pValue->caul, &m_rOptions.saSearchStore)))
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
break;
|
|
|
|
case OID_SECURITY_RG_IASN:
|
|
//N TODO: OID_SECURITY_RG_IASN
|
|
if (fInternal)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
hr = MIME_E_READ_ONLY;
|
|
}
|
|
break;
|
|
|
|
// 2 Key implementation
|
|
case OID_SECURITY_2KEY_CERT_BAG:
|
|
{
|
|
hr = S_OK;
|
|
// Create a new store if needed
|
|
if (m_rOptions.hCertStore == NULL)
|
|
{
|
|
m_rOptions.hCertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING,
|
|
NULL, 0, NULL);
|
|
}
|
|
|
|
if (m_rOptions.hCertStore == NULL)
|
|
{
|
|
hr = HrGetLastError();
|
|
}
|
|
|
|
for (i=0; i < (pValue->caul).cElems; i++)
|
|
{
|
|
if (!CertAddCertificateContextToStore(m_rOptions.hCertStore,
|
|
(PCCERT_CONTEXT) IntToPtr((pValue->caul).pElems[i]),
|
|
CERT_STORE_ADD_ALWAYS, NULL))
|
|
{
|
|
hr = HrGetLastError();
|
|
}
|
|
}
|
|
if(hr == S_OK)
|
|
{
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_HCRYPTPROV:
|
|
if (m_rOptions.hCryptProv != pValue->ulVal)
|
|
{
|
|
if (m_rOptions.hCryptProv)
|
|
CryptReleaseContext(m_rOptions.hCryptProv, 0);
|
|
m_rOptions.hCryptProv = pValue->ulVal;
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
#else // _WIN64
|
|
case OID_SECURITY_CERT_SIGNING_64:
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(1)))
|
|
{
|
|
break;
|
|
}
|
|
if (m_rOptions.rgpcCertSigning[0] != (PCCERT_CONTEXT)pValue->pulVal)
|
|
{
|
|
if (m_rOptions.rgpcCertSigning[0])
|
|
CertFreeCertificateContext(m_rOptions.rgpcCertSigning[0]);
|
|
m_rOptions.rgpcCertSigning[0] = CertDuplicateCertificateContext((PCCERT_CONTEXT)pValue->pulVal);
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_CERT_SIGNING_RG_64: // signing algorithms
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(pValue)))
|
|
{
|
|
break;
|
|
}
|
|
cauh = pValue->cauh;
|
|
Assert(cauh.cElems == m_rOptions.cSigners || 0 == m_rOptions.cSigners);
|
|
if (m_rOptions.cSigners != cauh.cElems && 0 != m_rOptions.cSigners)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
} else {
|
|
for (i = 0; i < cauh.cElems; i++)
|
|
{
|
|
PCCERT_CONTEXT pCert = *(PCCERT_CONTEXT *) (&(cauh.pElems[i]));
|
|
|
|
if (m_rOptions.rgpcCertSigning[i] != (PCCERT_CONTEXT)(pCert))
|
|
{
|
|
if (m_rOptions.rgpcCertSigning[i])
|
|
CertFreeCertificateContext(m_rOptions.rgpcCertSigning[i]);
|
|
m_rOptions.rgpcCertSigning[i] = CertDuplicateCertificateContext((PCCERT_CONTEXT)(pCert));
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_CERT_DECRYPTION_64:
|
|
if (m_rOptions.pcCertDecryption != (PCCERT_CONTEXT)pValue->pulVal)
|
|
{
|
|
if (m_rOptions.pcCertDecryption)
|
|
CertFreeCertificateContext(m_rOptions.pcCertDecryption);
|
|
m_rOptions.pcCertDecryption = CertDuplicateCertificateContext((PCCERT_CONTEXT)pValue->pulVal);
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_RG_CERT_ENCRYPT_64:
|
|
#ifdef SMIME_V3
|
|
for (i=0; i<pValue->cauh.cElems; i++)
|
|
{
|
|
CMS_RECIPIENT_INFO info = {0};
|
|
info.pccert = *((PCCERT_CONTEXT*) &(pValue->cauh.pElems[i]));
|
|
hr = AddRecipient((i == 0) ? SMIME_RECIPIENT_REPLACE_ALL : 0, 1, &info);
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (SUCCEEDED(hr) && !fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
#else // !SMIME_V3
|
|
if (SUCCEEDED(hr = _CAUHToCERTARRAY(pValue->cauh, &m_rOptions.caEncrypt)))
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
#endif // !SMIME_V3
|
|
break;
|
|
|
|
case OID_SECURITY_HCERTSTORE_64:
|
|
CertCloseStore(m_rOptions.hCertStore, 0);
|
|
if (pValue->pulVal)
|
|
m_rOptions.hCertStore = CertDuplicateStore((HCERTSTORE)pValue->pulVal);
|
|
else
|
|
m_rOptions.hCertStore = NULL;
|
|
break;
|
|
|
|
case OID_SECURITY_ENCRYPT_CERT_BAG_64:
|
|
CertCloseStore(m_rOptions.hstoreEncrypt, 0);
|
|
if (pValue->pulVal)
|
|
m_rOptions.hstoreEncrypt = CertDuplicateStore((HCERTSTORE) pValue->pulVal);
|
|
else
|
|
m_rOptions.hstoreEncrypt = NULL;
|
|
break;
|
|
|
|
case OID_SECURITY_RG_CERT_BAG_64:
|
|
if (SUCCEEDED(hr = _CAUHToCertStore(pValue->cauh, &m_rOptions.hCertStore)))
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
break;
|
|
|
|
case OID_SECURITY_SEARCHSTORES_64:
|
|
if (SUCCEEDED(hr = _CAUHToSTOREARRAY(pValue->cauh, &m_rOptions.saSearchStore)))
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
break;
|
|
|
|
case OID_SECURITY_RG_IASN_64:
|
|
//N TODO: OID_SECURITY_RG_IASN
|
|
if (fInternal)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
hr = MIME_E_READ_ONLY;
|
|
}
|
|
break;
|
|
|
|
// 2 Key implementation
|
|
case OID_SECURITY_2KEY_CERT_BAG_64:
|
|
{
|
|
hr = S_OK;
|
|
// Create a new store if needed
|
|
if (m_rOptions.hCertStore == NULL)
|
|
{
|
|
m_rOptions.hCertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING,
|
|
NULL, 0, NULL);
|
|
}
|
|
|
|
if (m_rOptions.hCertStore == NULL)
|
|
{
|
|
hr = HrGetLastError();
|
|
}
|
|
|
|
for (i=0; i < (pValue->cauh).cElems; i++)
|
|
{
|
|
if (!CertAddCertificateContextToStore(m_rOptions.hCertStore,
|
|
*((PCCERT_CONTEXT *) (&((pValue->cauh).pElems[i]))),
|
|
CERT_STORE_ADD_ALWAYS, NULL))
|
|
{
|
|
hr = HrGetLastError();
|
|
}
|
|
}
|
|
if(hr == S_OK)
|
|
{
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_HCRYPTPROV_64:
|
|
if (m_rOptions.hCryptProv != (((HCRYPTPROV) (pValue->pulVal))))
|
|
{
|
|
if (m_rOptions.hCryptProv)
|
|
CryptReleaseContext(m_rOptions.hCryptProv, 0);
|
|
m_rOptions.hCryptProv = (HCRYPTPROV) pValue->pulVal;
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
#endif //_WIN64
|
|
|
|
case OID_SECURITY_CRL:
|
|
if (m_rOptions.hCertStore == NULL)
|
|
{
|
|
m_rOptions.hCertStore = CertOpenStore(CERT_STORE_PROV_MEMORY,
|
|
X509_ASN_ENCODING,
|
|
NULL, 0, NULL);
|
|
if (m_rOptions.hCertStore == NULL)
|
|
{
|
|
hr = HrGetLastError();
|
|
break;
|
|
}
|
|
}
|
|
if (!CertAddEncodedCRLToStore(m_rOptions.hCertStore, X509_ASN_ENCODING,
|
|
pValue->blob.pBlobData,
|
|
pValue->blob.cbSize,
|
|
CERT_STORE_ADD_ALWAYS, NULL))
|
|
{
|
|
hr = HrGetLastError();
|
|
}
|
|
else if (!fNoDirty)
|
|
{
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_SYMCAPS:
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(1)))
|
|
{
|
|
break;
|
|
}
|
|
#ifdef SMIME_V3
|
|
hr = _HrSetAttribute(0, &m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][0],
|
|
szOID_RSA_SMIMECapabilities,
|
|
pValue->blob.cbSize, pValue->blob.pBlobData);
|
|
#else // !SMIME_V3
|
|
if (CompareBlob(&m_rOptions.rgblobSymCaps[0], &pValue->blob))
|
|
{
|
|
ReleaseMem(m_rOptions.rgblobSymCaps[0].pBlobData);
|
|
hr = HrCopyBlob(&pValue->blob, &m_rOptions.rgblobSymCaps[0]);
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
#endif // SMIME_V3
|
|
break;
|
|
|
|
case OID_SECURITY_SYMCAPS_RG: // symetric capabilities
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(pValue)))
|
|
{
|
|
break;
|
|
}
|
|
#ifdef SMIME_V3
|
|
for (i=0; i<pValue->capropvar.cElems; i++)
|
|
{
|
|
hr = _HrSetAttribute(0, &m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][i],
|
|
szOID_RSA_SMIMECapabilities,
|
|
pValue->capropvar.pElems[i].blob.cbSize,
|
|
pValue->capropvar.pElems[i].blob.pBlobData);
|
|
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
#else // !SMIME_V3
|
|
hr = _CompareCopyBlobArray(pValue, &m_rOptions.rgblobSymCaps, fNoDirty);
|
|
#endif // SMIME_V3
|
|
break;
|
|
|
|
case OID_SECURITY_AUTHATTR:
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(1)))
|
|
{
|
|
break;
|
|
}
|
|
#ifdef SMIME_V3
|
|
hr = _HrSetAttribute(0, &m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][0],
|
|
NULL, pValue->blob.cbSize, pValue->blob.pBlobData);
|
|
#else // !SMIME_V3
|
|
if (CompareBlob(&m_rOptions.rgblobAuthAttr[0], &pValue->blob))
|
|
{
|
|
ReleaseMem(m_rOptions.rgblobAuthAttr[0].pBlobData);
|
|
hr = HrCopyBlob(&pValue->blob, &m_rOptions.rgblobAuthAttr[0]);
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
#endif // SMIME_V3
|
|
break;
|
|
|
|
case OID_SECURITY_AUTHATTR_RG: // authenticated attributes
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(pValue)))
|
|
{
|
|
break;
|
|
}
|
|
#ifdef SMIME_V3
|
|
for (i=0; i<pValue->capropvar.cElems; i++)
|
|
{
|
|
hr = _HrSetAttribute(0, &m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][i],
|
|
NULL, pValue->capropvar.pElems[i].blob.cbSize,
|
|
pValue->capropvar.pElems[i].blob.pBlobData);
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
#else // !SMIME_V3
|
|
hr = _CompareCopyBlobArray(pValue, &m_rOptions.rgblobAuthAttr, fNoDirty);
|
|
#endif // SMIME_V3
|
|
break;
|
|
|
|
|
|
case OID_SECURITY_UNAUTHATTR:
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(1)))
|
|
{
|
|
break;
|
|
}
|
|
#ifdef SMIME_V3
|
|
hr = _HrSetAttribute(0, &m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_UNSIGNED][0],
|
|
NULL, pValue->blob.cbSize, pValue->blob.pBlobData);
|
|
#else // !SMIME_V3
|
|
if (CompareBlob(&m_rOptions.rgblobUnauthAttr[0], &pValue->blob))
|
|
{
|
|
ReleaseMem(m_rOptions.rgblobUnauthAttr[0].pBlobData);
|
|
hr = HrCopyBlob(&pValue->blob, &m_rOptions.rgblobUnauthAttr[0]);
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
#endif // SMIME_V3
|
|
break;
|
|
|
|
case OID_SECURITY_UNAUTHATTR_RG: // unauthenticated attributes
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(pValue)))
|
|
{
|
|
break;
|
|
}
|
|
#ifdef SMIME_V3
|
|
for (i=0; i<pValue->capropvar.cElems; i++)
|
|
{
|
|
hr = _HrSetAttribute(0, &m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_UNSIGNED][i],
|
|
NULL, pValue->capropvar.pElems[i].blob.cbSize,
|
|
pValue->capropvar.pElems[i].blob.pBlobData);
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
#else // !SMIME_V3
|
|
hr = _CompareCopyBlobArray(pValue, &m_rOptions.rgblobUnauthAttr, fNoDirty);
|
|
#endif // SMIME_V3
|
|
break;
|
|
|
|
|
|
case OID_SECURITY_SIGNTIME:
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(1)))
|
|
{
|
|
break;
|
|
}
|
|
#ifdef SMIME_V3
|
|
if ((pValue->filetime.dwLowDateTime == 0) &&
|
|
(pValue->filetime.dwHighDateTime == 0))
|
|
{
|
|
hr = DeleteAttribute(0, 0, SMIME_ATTRIBUTE_SET_SIGNED, 0,
|
|
szOID_RSA_signingTime);
|
|
}
|
|
else
|
|
{
|
|
cb = sizeof(rgb);
|
|
if (!CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CHOICE_OF_TIME,
|
|
&pValue->filetime, 0, NULL,
|
|
rgb, &cb))
|
|
{
|
|
hr = HrGetLastError();
|
|
break;
|
|
}
|
|
|
|
hr = _HrSetAttribute(0, &m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][0],
|
|
szOID_RSA_signingTime, cb, rgb);
|
|
}
|
|
#else // !SMIME_V3
|
|
if (CompareFileTime(&m_rOptions.rgftSigning[0], (FILETIME FAR*)&pValue->filetime))
|
|
{
|
|
CopyMemory(&m_rOptions.rgftSigning[0], &pValue->filetime, sizeof(FILETIME));
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
#endif // SMIME_V3
|
|
break;
|
|
|
|
case OID_SECURITY_SIGNTIME_RG: // signing times
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(pValue)))
|
|
{
|
|
break;
|
|
}
|
|
#ifdef SMIME_V3
|
|
for (i=0; i<pValue->cafiletime.cElems; i++)
|
|
{
|
|
if ((pValue->cafiletime.pElems[i].dwLowDateTime == 0) &&
|
|
(pValue->cafiletime.pElems[i].dwHighDateTime == 0))
|
|
{
|
|
hr = DeleteAttribute(0, 0, SMIME_ATTRIBUTE_SET_SIGNED, 0,
|
|
szOID_RSA_signingTime);
|
|
}
|
|
else
|
|
{
|
|
cb = sizeof(rgb);
|
|
if (!CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CHOICE_OF_TIME,
|
|
&pValue->cafiletime.pElems[i], 0, NULL,
|
|
rgb, &cb))
|
|
{
|
|
hr = HrGetLastError();
|
|
break;
|
|
}
|
|
|
|
hr = _HrSetAttribute(0, &m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][i],
|
|
szOID_RSA_signingTime, cb, rgb);
|
|
}
|
|
}
|
|
#else // !SMIME_V3
|
|
cafiletime = pValue->cafiletime;
|
|
Assert(cafiletime.cElems == m_rOptions.cSigners);
|
|
if (m_rOptions.cSigners != cafiletime.cElems)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
} else {
|
|
for (i = 0; i < cafiletime.cElems; i++)
|
|
{
|
|
if (CompareFileTime(&m_rOptions.rgftSigning[i], (FILETIME FAR*)&cafiletime.pElems[i]))
|
|
{
|
|
CopyMemory(&m_rOptions.rgftSigning[i], &cafiletime.pElems[i], sizeof(FILETIME));
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
}
|
|
}
|
|
#endif // SMIME_V3
|
|
break;
|
|
|
|
case OID_SECURITY_USER_VALIDITY:
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(1)))
|
|
{
|
|
break;
|
|
}
|
|
if (m_rOptions.rgulUserDef[0] != pValue->ulVal)
|
|
{
|
|
m_rOptions.rgulUserDef[0] = pValue->ulVal;
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_USER_VALIDITY_RG: // user validity flags
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(pValue)))
|
|
{
|
|
break;
|
|
}
|
|
caul = pValue->caul;
|
|
Assert(caul.cElems == m_rOptions.cSigners || 0 == m_rOptions.cSigners);
|
|
if (m_rOptions.cSigners != caul.cElems && 0 != m_rOptions.cSigners)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
} else {
|
|
for (i = 0; i < caul.cElems; i++)
|
|
{
|
|
if (m_rOptions.rgulUserDef[i] != caul.pElems[i])
|
|
{
|
|
m_rOptions.rgulUserDef[i] = caul.pElems[i];
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_RO_MSG_VALIDITY:
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(1)))
|
|
{
|
|
break;
|
|
}
|
|
if (fInternal)
|
|
{
|
|
if (m_rOptions.rgulROValid[0] != pValue->ulVal)
|
|
{
|
|
m_rOptions.rgulROValid[0] = pValue->ulVal;
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = MIME_E_READ_ONLY;
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_RO_MSG_VALIDITY_RG: // message validity flags
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(pValue)))
|
|
{
|
|
break;
|
|
}
|
|
caul = pValue->caul;
|
|
Assert(caul.cElems == m_rOptions.cSigners || 0 == m_rOptions.cSigners);
|
|
if (m_rOptions.cSigners != caul.cElems && 0 != m_rOptions.cSigners)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < caul.cElems; i++)
|
|
{
|
|
if (m_rOptions.rgulROValid[i] != caul.pElems[i])
|
|
{
|
|
m_rOptions.rgulROValid[i] = caul.pElems[i];
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_ENCODE_FLAGS:
|
|
if (m_rOptions.ulEncodeFlags != pValue->ulVal)
|
|
{
|
|
m_rOptions.ulEncodeFlags = pValue->ulVal;
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_CERT_INCLUDED:
|
|
if (fInternal)
|
|
{
|
|
if (m_rOptions.fCertWithMsg != pValue->boolVal)
|
|
{
|
|
m_rOptions.fCertWithMsg = pValue->boolVal;
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = MIME_E_READ_ONLY;
|
|
}
|
|
break;
|
|
|
|
#ifndef _WIN64
|
|
case OID_SECURITY_HWND_OWNER:
|
|
m_rOptions.hwndOwner = HWND(pValue->ulVal);
|
|
break;
|
|
#endif
|
|
|
|
case OID_SECURITY_REQUESTED_CTE:
|
|
if (m_rOptions.ietRequested != pValue->lVal)
|
|
{
|
|
m_rOptions.ietRequested = ENCODINGTYPE(pValue->lVal);
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_SIGNATURE_COUNT:
|
|
// M00BUG - I just found out that if lVal >0 but lVal < m_rOptions.cSigners
|
|
// then we don't do any adjustments to handle this case.
|
|
if (pValue->lVal == 0)
|
|
{
|
|
if (m_rOptions.cSigners)
|
|
{
|
|
// OID_SECURITY_ALG_HASH
|
|
SafeMemFree(m_rOptions.rgblobHash[0].pBlobData);
|
|
|
|
|
|
// OID_SECURITY_CERT_SIGNING
|
|
for (i = 0; i < m_rOptions.cSigners; i++)
|
|
{
|
|
CertFreeCertificateContext(m_rOptions.rgpcCertSigning[i]);
|
|
|
|
#ifdef SMIME_V3
|
|
// Attributes
|
|
SafeMemFree(m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][i]);
|
|
SafeMemFree(m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_UNSIGNED][i]);
|
|
|
|
// OID_SECURITY_RECEIPT_RG
|
|
SafeMemFree(m_rOptions.rgblobReceipt[i].pBlobData);
|
|
// OID_SECURITY_MESSAGE_HASH_RG
|
|
SafeMemFree(m_rOptions.rgblobMsgHash[i].pBlobData);
|
|
// OID_SECURITY_KEY_PROMPT
|
|
SafeMemFree(m_rOptions.pwszKeyPrompt);
|
|
#else // !SMIME_V3
|
|
// OID_SECURITY_SYMCAPS
|
|
SafeMemFree(m_rOptions.rgblobSymCaps[i].pBlobData);
|
|
|
|
// OID_SECURITY_AUTHATTR
|
|
SafeMemFree(m_rOptions.rgblobAuthAttr[i].pBlobData);
|
|
|
|
// OID_SECURITY_UNAUTHATTR
|
|
SafeMemFree(m_rOptions.rgblobUnauthAttr[i].pBlobData);
|
|
#endif // SMIME_V3
|
|
}
|
|
|
|
// OID_SECURITY_HCERTSTORE
|
|
CertCloseStore(m_rOptions.hCertStore, 0);
|
|
m_rOptions.hCertStore = NULL;
|
|
|
|
_FreeLayerArrays();
|
|
m_rOptions.cSigners = 0;
|
|
}
|
|
}
|
|
else if (m_rOptions.cSigners <= pValue->ulVal)
|
|
{
|
|
hr = _HrEnsureBodyOptionLayers(pValue);
|
|
}
|
|
break;
|
|
|
|
#ifdef SMIME_V3
|
|
case OID_SECURITY_RECEIPT_RG:
|
|
if (fInternal)
|
|
{
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(pValue)))
|
|
{
|
|
break;
|
|
}
|
|
hr = _CompareCopyBlobArray(pValue, &m_rOptions.rgblobReceipt, fNoDirty);
|
|
}
|
|
else
|
|
hr = MIME_E_READ_ONLY;
|
|
break;
|
|
|
|
case OID_SECURITY_MESSAGE_HASH_RG:
|
|
if (fInternal)
|
|
{
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(pValue)))
|
|
{
|
|
break;
|
|
}
|
|
hr = _CompareCopyBlobArray(pValue, &m_rOptions.rgblobMsgHash, fNoDirty);
|
|
}
|
|
else
|
|
hr = MIME_E_READ_ONLY;
|
|
break;
|
|
|
|
case OID_SECURITY_KEY_PROMPT:
|
|
if ((m_rOptions.pwszKeyPrompt == NULL) ||
|
|
(pValue->pwszVal == NULL) ||
|
|
(lstrcmpW(m_rOptions.pwszKeyPrompt,pValue->pwszVal) != 0))
|
|
{
|
|
SafeMemFree(m_rOptions.pwszKeyPrompt);
|
|
if (pValue->pwszVal != NULL)
|
|
{
|
|
m_rOptions.pwszKeyPrompt = PszDupW(pValue->pwszVal);
|
|
if (NULL == m_rOptions.pwszKeyPrompt)
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
break;
|
|
|
|
#endif // SMIME_V3
|
|
|
|
case OID_NOSECURITY_ONSAVE:
|
|
m_rOptions.fNoSecurityOnSave = !!pValue->boolVal;
|
|
break;
|
|
#ifdef _WIN65
|
|
// (YST) This was checked in by BriMo at 01/22/99
|
|
case OID_SECURITY_CERT_SIGNING2:
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(1)))
|
|
{
|
|
break;
|
|
}
|
|
if (m_rOptions.rgpcCertSigning[0] != *(PCCERT_CONTEXT *)(&(pValue->uhVal)))
|
|
{
|
|
if (m_rOptions.rgpcCertSigning[0])
|
|
CertFreeCertificateContext(m_rOptions.rgpcCertSigning[0]);
|
|
m_rOptions.rgpcCertSigning[0] = CertDuplicateCertificateContext(*(PCCERT_CONTEXT *)(&(pValue->uhVal)));
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_CERT_SIGNING_RG2: // signing algorithms
|
|
if (FAILED(hr = _HrEnsureBodyOptionLayers(pValue)))
|
|
{
|
|
break;
|
|
}
|
|
cauh = pValue->cauh;
|
|
Assert(cauh.cElems == m_rOptions.cSigners || 0 == m_rOptions.cSigners);
|
|
if (m_rOptions.cSigners != cauh.cElems && 0 != m_rOptions.cSigners)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
} else {
|
|
for (i = 0; i < cauh.cElems; i++)
|
|
{
|
|
if (m_rOptions.rgpcCertSigning[i] != (PCCERT_CONTEXT)(cauh.pElems[i]))
|
|
{
|
|
if (m_rOptions.rgpcCertSigning[i])
|
|
CertFreeCertificateContext(m_rOptions.rgpcCertSigning[i]);
|
|
m_rOptions.rgpcCertSigning[i] = CertDuplicateCertificateContext((PCCERT_CONTEXT )(cauh.pElems[i]));
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_CERT_DECRYPTION2:
|
|
if (m_rOptions.pcCertDecryption != *(PCCERT_CONTEXT *)(&(pValue->uhVal)))
|
|
{
|
|
if (m_rOptions.pcCertDecryption)
|
|
CertFreeCertificateContext(m_rOptions.pcCertDecryption);
|
|
m_rOptions.pcCertDecryption = CertDuplicateCertificateContext(*(PCCERT_CONTEXT *)(&(pValue->uhVal)));
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_RG_CERT_ENCRYPT2:
|
|
if (SUCCEEDED(hr = _CAUHToCERTARRAY(pValue->cauh, &m_rOptions.caEncrypt)))
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
break;
|
|
|
|
case OID_SECURITY_HCERTSTORE2:
|
|
CertCloseStore(m_rOptions.hCertStore, 0);
|
|
if (pValue->ulVal)
|
|
m_rOptions.hCertStore = CertDuplicateStore(*(HCERTSTORE *)(&(pValue->uhVal)));
|
|
else
|
|
m_rOptions.hCertStore = NULL;
|
|
break;
|
|
|
|
case OID_SECURITY_RG_CERT_BAG2:
|
|
if (SUCCEEDED(hr = _CAUHToCertStore(pValue->cauh, &m_rOptions.hCertStore)))
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
break;
|
|
|
|
case OID_SECURITY_SEARCHSTORES2:
|
|
if (SUCCEEDED(hr = _CAUHToSTOREARRAY(pValue->cauh, &m_rOptions.saSearchStore)))
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
break;
|
|
|
|
case OID_SECURITY_RG_IASN2:
|
|
//N TODO: OID_SECURITY_RG_IASN2
|
|
if (fInternal)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
hr = MIME_E_READ_ONLY;
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_HCRYPTPROV2:
|
|
if (m_rOptions.hCryptProv != *(HCRYPTPROV *)(&(pValue->uhVal)))
|
|
{
|
|
if (m_rOptions.hCryptProv)
|
|
CryptReleaseContext(m_rOptions.hCryptProv, 0);
|
|
m_rOptions.hCryptProv = *(HCRYPTPROV *)(&(pValue->uhVal));
|
|
if (!fNoDirty)
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
break;
|
|
// End of BriMo checkin
|
|
#endif // _WIN65
|
|
|
|
#ifdef _WIN64
|
|
case OID_SECURITY_HWND_OWNER_64:
|
|
m_rOptions.hwndOwner = (HWND)(pValue->pulVal);
|
|
break;
|
|
#endif // _WIN64
|
|
|
|
default:
|
|
hr = m_pContainer->SetOption(oid, pValue);
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return TrapError(hr);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CMessageBody::GetOption
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetOption(const TYPEDID oid, LPPROPVARIANT pValue)
|
|
{
|
|
// Locals
|
|
DWORD cb;
|
|
HRESULT hr=S_OK;
|
|
DWORD i;
|
|
LPBYTE pb;
|
|
ASSERTINIT;
|
|
ULONG iLayer;
|
|
#ifdef SMIME_V3
|
|
CRYPT_ATTRIBUTE UNALIGNED *pattr;
|
|
#endif // SMIME_V3
|
|
|
|
#ifdef _WIN64
|
|
void UNALIGNED *pv = NULL;
|
|
PCCERT_CONTEXT pTmpCert = NULL;
|
|
PCCERT_CONTEXT pcCert = NULL;
|
|
#endif // _WIN64
|
|
CRYPT_ATTR_BLOB UNALIGNED *pVal = NULL;
|
|
|
|
// check params
|
|
if (NULL == pValue)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
pValue->vt = TYPEDID_TYPE(oid);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Handle Optid
|
|
switch(oid)
|
|
{
|
|
case OID_SUPPORT_EXTERNAL_BODY:
|
|
pValue->boolVal = (VARIANT_BOOL) !!m_rOptions.fExternalBody;
|
|
break;
|
|
|
|
case OID_SHOW_MACBINARY:
|
|
pValue->boolVal = (VARIANT_BOOL) !!m_rOptions.fShowMacBin;
|
|
break;
|
|
|
|
case OID_CBMAX_BODY_LINE:
|
|
pValue->ulVal = m_rOptions.cbMaxLine;
|
|
break;
|
|
|
|
case OID_TRANSMIT_BODY_ENCODING:
|
|
pValue->ulVal = (ULONG)m_rOptions.ietTransmit;
|
|
break;
|
|
|
|
case OID_WRAP_BODY_TEXT:
|
|
pValue->boolVal = (VARIANT_BOOL) !!m_rOptions.fWrapText;
|
|
break;
|
|
|
|
case OID_HIDE_TNEF_ATTACHMENTS:
|
|
pValue->boolVal = (VARIANT_BOOL) !!m_rOptions.fHideTNEF;
|
|
break;
|
|
|
|
case OID_DBCS_ESCAPE_IS_8BIT:
|
|
pValue->boolVal = (VARIANT_BOOL) !!m_rOptions.fDBCSEscape8;
|
|
break;
|
|
|
|
case OID_SECURITY_TYPE:
|
|
pValue->ulVal = m_rOptions.ulSecurityType;
|
|
break;
|
|
|
|
case OID_SECURITY_ALG_HASH:
|
|
if (m_rOptions.cSigners)
|
|
{
|
|
hr = HrCopyBlob(&m_rOptions.rgblobHash[0], &pValue->blob);
|
|
}
|
|
else
|
|
{
|
|
hr = HrCopyBlob(&blobNULL, &pValue->blob);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_ALG_HASH_RG:
|
|
hr = HrCopyBlobArray(m_rOptions.rgblobHash, m_rOptions.cSigners, pValue);
|
|
break;
|
|
|
|
case OID_SECURITY_ALG_BULK:
|
|
hr = HrCopyBlob(&m_rOptions.blobBulk, &pValue->blob);
|
|
break;
|
|
|
|
#ifndef _WIN64
|
|
case OID_SECURITY_CERT_SIGNING:
|
|
if (m_rOptions.cSigners)
|
|
pValue->ulVal = (ULONG)CertDuplicateCertificateContext(m_rOptions.rgpcCertSigning[0]);
|
|
else
|
|
pValue->ulVal = 0; // ?
|
|
break;
|
|
|
|
case OID_SECURITY_CERT_SIGNING_RG:
|
|
hr = HrCopyDwordArray((ULONG*)m_rOptions.rgpcCertSigning, m_rOptions.cSigners, pValue);
|
|
// Duplicate the certs in place.
|
|
for (iLayer = 0; iLayer < m_rOptions.cSigners; iLayer++)
|
|
{
|
|
pValue->caul.pElems[iLayer] = (ULONG)CertDuplicateCertificateContext((PCCERT_CONTEXT)pValue->caul.pElems[iLayer]);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_CERT_DECRYPTION:
|
|
|
|
pValue->ulVal = (ULONG)CertDuplicateCertificateContext(m_rOptions.pcCertDecryption);
|
|
break;
|
|
|
|
#ifndef SMIME_V3
|
|
case OID_SECURITY_RG_CERT_ENCRYPT:
|
|
hr = _CERTARRAYToCAUL(m_rOptions.caEncrypt, &pValue->caul);
|
|
break;
|
|
#endif // !SMIEM_V3
|
|
|
|
case OID_SECURITY_HCERTSTORE:
|
|
pValue->ulVal = 0;
|
|
if (m_rOptions.hCertStore)
|
|
pValue->ulVal = (ULONG)CertDuplicateStore(m_rOptions.hCertStore);
|
|
break;
|
|
|
|
case OID_SECURITY_ENCRYPT_CERT_BAG:
|
|
pValue->ulVal = 0;
|
|
if (m_rOptions.hstoreEncrypt != NULL)
|
|
pValue->ulVal = (ULONG) CertDuplicateStore(m_rOptions.hstoreEncrypt);
|
|
break;
|
|
|
|
case OID_SECURITY_RG_CERT_BAG:
|
|
hr = _CertStoreToCAUL(m_rOptions.hCertStore, &pValue->caul);
|
|
break;
|
|
|
|
case OID_SECURITY_SEARCHSTORES:
|
|
hr = _STOREARRAYToCAUL(m_rOptions.saSearchStore, &pValue->caul);
|
|
break;
|
|
|
|
case OID_SECURITY_RG_IASN:
|
|
Assert(FALSE);
|
|
//N TODO: OID_SECURITY_RG_IASN
|
|
break;
|
|
|
|
case OID_SECURITY_HCRYPTPROV:
|
|
pValue->ulVal = m_rOptions.hCryptProv;
|
|
m_rOptions.hCryptProv = NULL; // read-once
|
|
break;
|
|
|
|
#else //_WIN64
|
|
case OID_SECURITY_CERT_SIGNING_64:
|
|
if (m_rOptions.cSigners)
|
|
pValue->pulVal = (ULONG *)CertDuplicateCertificateContext(m_rOptions.rgpcCertSigning[0]);
|
|
else
|
|
pValue->pulVal = 0; // ?
|
|
break;
|
|
|
|
case OID_SECURITY_CERT_SIGNING_RG_64:
|
|
hr = HrCopyIntoUlonglongArray((ULARGE_INTEGER *)m_rOptions.rgpcCertSigning, m_rOptions.cSigners, pValue);
|
|
// Duplicate the certs in place.
|
|
if(m_rOptions.cSigners > 0)
|
|
{
|
|
for (iLayer = 0; iLayer < m_rOptions.cSigners; iLayer++)
|
|
{
|
|
pv = (void*) (&(pValue->cauh.pElems[iLayer]));
|
|
pTmpCert = *((PCCERT_CONTEXT *) pv);
|
|
pcCert = CertDuplicateCertificateContext(pTmpCert);
|
|
pValue->cauh.pElems[iLayer] = *((ULARGE_INTEGER *)(&(pcCert)));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_CERT_DECRYPTION_64:
|
|
pValue->pulVal = (ULONG *)CertDuplicateCertificateContext(m_rOptions.pcCertDecryption);
|
|
break;
|
|
|
|
#ifndef SMIME_V3
|
|
case OID_SECURITY_RG_CERT_ENCRYPT_64:
|
|
hr = _CERTARRAYToCAUH(m_rOptions.caEncrypt, &pValue->cauh);
|
|
break;
|
|
#endif // !SMIEM_V3
|
|
|
|
case OID_SECURITY_HCERTSTORE_64:
|
|
pValue->pulVal = 0;
|
|
if (m_rOptions.hCertStore)
|
|
pValue->pulVal = (ULONG *)CertDuplicateStore(m_rOptions.hCertStore);
|
|
break;
|
|
|
|
case OID_SECURITY_ENCRYPT_CERT_BAG_64:
|
|
pValue->pulVal = 0;
|
|
if (m_rOptions.hstoreEncrypt != NULL)
|
|
pValue->pulVal = (ULONG *) CertDuplicateStore(m_rOptions.hstoreEncrypt);
|
|
break;
|
|
|
|
case OID_SECURITY_RG_CERT_BAG_64:
|
|
hr = _CertStoreToCAUH(m_rOptions.hCertStore, &pValue->cauh);
|
|
break;
|
|
|
|
case OID_SECURITY_SEARCHSTORES_64:
|
|
hr = _STOREARRAYToCAUH(m_rOptions.saSearchStore, &pValue->cauh);
|
|
break;
|
|
|
|
case OID_SECURITY_RG_IASN_64:
|
|
Assert(FALSE);
|
|
//N TODO: OID_SECURITY_RG_IASN
|
|
break;
|
|
|
|
case OID_SECURITY_HCRYPTPROV_64:
|
|
pValue->pulVal = (ULONG *) (m_rOptions.hCryptProv);
|
|
m_rOptions.hCryptProv = NULL; // read-once
|
|
break;
|
|
|
|
#endif //_WIN64
|
|
|
|
case OID_SECURITY_CRL:
|
|
// hr = HrCopyBlob(&m_rOptions.blobCRL, &pValue->blob);
|
|
Assert(FALSE);
|
|
// M00BUG -- MUST IMPLEMENT THIS
|
|
break;
|
|
|
|
case OID_SECURITY_SYMCAPS:
|
|
#ifdef SMIME_V3
|
|
pattr = _FindAttribute(m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][0],
|
|
szOID_RSA_SMIMECapabilities, 0);
|
|
if (pattr != NULL)
|
|
{
|
|
pVal = &(pattr->rgValue[0]);
|
|
|
|
Assert(pattr->cValue == 1);
|
|
if (!MemAlloc((LPVOID UNALIGNED *) &pValue->blob.pBlobData,
|
|
pVal->cbData))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
pValue->blob.cbSize = pVal->cbData;
|
|
memcpy(pValue->blob.pBlobData, pVal->pbData,
|
|
pVal->cbData);
|
|
}
|
|
else {
|
|
pValue->blob.cbSize = 0;
|
|
pValue->blob.pBlobData = NULL;
|
|
}
|
|
pValue->vt = VT_BLOB;
|
|
#else // !SMIME_V3
|
|
if (m_rOptions.cSigners)
|
|
{
|
|
hr = HrCopyBlob(&m_rOptions.rgblobSymCaps[0], &pValue->blob);
|
|
} else {
|
|
hr = HrCopyBlob(&blobNULL, &pValue->blob);
|
|
}
|
|
#endif // SMIME_V3
|
|
break;
|
|
|
|
case OID_SECURITY_SYMCAPS_RG:
|
|
#ifdef SMIME_V3
|
|
hr = _HrGetAttrs(m_rOptions.cSigners, m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED],
|
|
szOID_RSA_SMIMECapabilities, pValue);
|
|
#else // !SMIME_V3
|
|
hr = HrCopyBlobArray(m_rOptions.rgblobSymCaps, m_rOptions.cSigners, pValue);
|
|
#endif // SMIME_V3
|
|
break;
|
|
|
|
case OID_SECURITY_AUTHATTR:
|
|
if (m_rOptions.cSigners)
|
|
{
|
|
#ifdef SMIME_V3
|
|
memset(pValue, 0, sizeof(*pValue));
|
|
pValue->vt = VT_BLOB;
|
|
if ((m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][0] != NULL) &&
|
|
!CryptEncodeObjectEx(X509_ASN_ENCODING,
|
|
szOID_Microsoft_Attribute_Sequence,
|
|
m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][0],
|
|
CRYPT_ENCODE_ALLOC_FLAG,
|
|
&CryptEncodeAlloc, &pValue->blob.pBlobData,
|
|
&pValue->blob.cbSize))
|
|
{
|
|
hr = HrGetLastError();
|
|
}
|
|
#else // !SMIME_V3
|
|
hr = HrCopyBlob(&m_rOptions.rgblobAuthAttr[0], &pValue->blob);
|
|
#endif // SMIME_V3
|
|
}
|
|
else
|
|
{
|
|
hr = HrCopyBlob(&blobNULL, &pValue->blob);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_AUTHATTR_RG:
|
|
#ifdef SMIME_V3
|
|
hr = _HrGetAttrs(m_rOptions.cSigners, m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED], NULL, pValue);
|
|
#else // !SMIME_V3
|
|
hr = HrCopyBlobArray(m_rOptions.rgblobAuthAttr, m_rOptions.cSigners, pValue);
|
|
#endif // SMIME_V3
|
|
break;
|
|
|
|
case OID_SECURITY_UNAUTHATTR:
|
|
if (m_rOptions.cSigners)
|
|
{
|
|
#ifdef SMIME_V3
|
|
memset(pValue, 0, sizeof(*pValue));
|
|
pValue->vt = VT_BLOB;
|
|
if ((m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_UNSIGNED][0] != NULL) &&
|
|
!CryptEncodeObjectEx(X509_ASN_ENCODING,
|
|
szOID_Microsoft_Attribute_Sequence,
|
|
m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_UNSIGNED][0],
|
|
CRYPT_ENCODE_ALLOC_FLAG,
|
|
&CryptEncodeAlloc, &pValue->blob.pBlobData,
|
|
&pValue->blob.cbSize))
|
|
{
|
|
hr = HrGetLastError();
|
|
}
|
|
#else // !SMIME_V3
|
|
hr = HrCopyBlob(&m_rOptions.rgblobUnauthAttr[0], &pValue->blob);
|
|
#endif // SMIME_V3
|
|
} else {
|
|
hr = HrCopyBlob(&blobNULL, &pValue->blob);
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_UNAUTHATTR_RG:
|
|
#ifdef SMIME_V3
|
|
hr = _HrGetAttrs(m_rOptions.cSigners, m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_UNSIGNED], NULL, pValue);
|
|
#else // !SMIME_V3
|
|
hr = HrCopyBlobArray(m_rOptions.rgblobUnauthAttr, m_rOptions.cSigners, pValue);
|
|
#endif // SMIME_V3
|
|
break;
|
|
|
|
case OID_SECURITY_SIGNTIME:
|
|
#ifdef SMIME_V3
|
|
pattr = _FindAttribute(m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][0], szOID_RSA_signingTime, 0);
|
|
|
|
pValue->vt = VT_FILETIME;
|
|
|
|
if (pattr == NULL)
|
|
{
|
|
pValue->filetime.dwLowDateTime = 0;
|
|
pValue->filetime.dwHighDateTime = 0;
|
|
}
|
|
else
|
|
{
|
|
cb = sizeof(pValue->filetime);
|
|
Assert(pattr->cValue == 1);
|
|
pVal = &(pattr->rgValue[0]);
|
|
if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CHOICE_OF_TIME,
|
|
pVal->pbData,
|
|
pVal->cbData,
|
|
0, NULL, &pValue->filetime, &cb))
|
|
{
|
|
hr = HrGetLastError();
|
|
break;
|
|
}
|
|
}
|
|
#else // !SMIME_V3
|
|
if (m_rOptions.cSigners)
|
|
{
|
|
CopyMemory(&pValue->filetime, &m_rOptions.rgftSigning[0], sizeof(FILETIME));
|
|
}
|
|
else
|
|
{
|
|
hr = HrCopyBlob(&blobNULL, &pValue->blob);
|
|
}
|
|
#endif // SMIME_V3
|
|
break;
|
|
|
|
case OID_SECURITY_SIGNTIME_RG:
|
|
#ifdef SMIME_V3
|
|
pValue->vt = VT_VECTOR | VT_VARIANT;
|
|
pValue->capropvar.cElems = m_rOptions.cSigners;
|
|
if (m_rOptions.cSigners > 0)
|
|
{
|
|
hr = HrAlloc((LPVOID *) &pValue->capropvar.pElems,
|
|
m_rOptions.cSigners * sizeof(PROPVARIANT));
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
memset(pValue->capropvar.pElems, 0, m_rOptions.cSigners * sizeof(PROPVARIANT));
|
|
for (i=0; i<m_rOptions.cSigners; i++)
|
|
{
|
|
pValue->capropvar.pElems[i].vt = VT_FILETIME;
|
|
|
|
pattr = _FindAttribute(m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][i],
|
|
szOID_RSA_signingTime, 0);
|
|
if (pattr != NULL)
|
|
{
|
|
cb = sizeof(pValue->filetime);
|
|
Assert(pattr->cValue == 1);
|
|
|
|
pVal = &(pattr->rgValue[0]);
|
|
if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CHOICE_OF_TIME,
|
|
pVal->pbData,
|
|
pVal->cbData, 0, NULL,
|
|
&pValue->capropvar.pElems[i].filetime,
|
|
&cb))
|
|
{
|
|
hr = HrGetLastError();
|
|
MemFree(pValue->capropvar.pElems);
|
|
pValue->capropvar.pElems = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else // !SMIME_V3
|
|
hr = HrCopyFiletimeArray(m_rOptions.rgftSigning, m_rOptions.cSigners, pValue);
|
|
#endif // SMIME_V3
|
|
break;
|
|
|
|
case OID_SECURITY_USER_VALIDITY:
|
|
if (m_rOptions.cSigners)
|
|
{
|
|
pValue->ulVal = m_rOptions.rgulUserDef[0];
|
|
} else {
|
|
pValue->ulVal = 0;
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_USER_VALIDITY_RG:
|
|
hr = HrCopyDwordArray(m_rOptions.rgulUserDef, m_rOptions.cSigners, pValue);
|
|
break;
|
|
|
|
case OID_SECURITY_RO_MSG_VALIDITY:
|
|
if (m_rOptions.cSigners)
|
|
{
|
|
pValue->ulVal = m_rOptions.rgulROValid[0];
|
|
} else {
|
|
pValue->ulVal = 0;
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_RO_MSG_VALIDITY_RG:
|
|
hr = HrCopyDwordArray(m_rOptions.rgulROValid, m_rOptions.cSigners, pValue);
|
|
break;
|
|
|
|
case OID_SECURITY_ENCODE_FLAGS:
|
|
pValue->ulVal = m_rOptions.ulEncodeFlags;
|
|
break;
|
|
|
|
case OID_SECURITY_CERT_INCLUDED:
|
|
pValue->boolVal = (VARIANT_BOOL) !!m_rOptions.fCertWithMsg;
|
|
break;
|
|
|
|
#ifndef _WIN64
|
|
case OID_SECURITY_HWND_OWNER:
|
|
pValue->ulVal = ULONG(m_rOptions.hwndOwner);
|
|
break;
|
|
#endif // _WIN64
|
|
|
|
case OID_SECURITY_REQUESTED_CTE:
|
|
pValue->lVal = m_rOptions.ietRequested;
|
|
break;
|
|
|
|
case OID_SECURITY_SIGNATURE_COUNT:
|
|
pValue->ulVal = ULONG(m_rOptions.cSigners);
|
|
break;
|
|
|
|
#ifdef SMIME_V3
|
|
case OID_SECURITY_RECEIPT_RG:
|
|
hr = HrCopyBlobArray(m_rOptions.rgblobReceipt, m_rOptions.cSigners, pValue);
|
|
break;
|
|
|
|
case OID_SECURITY_MESSAGE_HASH_RG:
|
|
hr = HrCopyBlobArray(m_rOptions.rgblobMsgHash, m_rOptions.cSigners, pValue);
|
|
break;
|
|
|
|
case OID_SECURITY_KEY_PROMPT:
|
|
ZeroMemory(&(pValue->pwszVal), sizeof(pValue->pwszVal));
|
|
if (m_rOptions.pwszKeyPrompt != NULL)
|
|
{
|
|
pValue->pwszVal = PszDupW(m_rOptions.pwszKeyPrompt);
|
|
if (NULL == pValue->pwszVal)
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
break;
|
|
#endif // SMIME_V3
|
|
|
|
case OID_NOSECURITY_ONSAVE:
|
|
pValue->boolVal = (VARIANT_BOOL) !!m_rOptions.fNoSecurityOnSave;
|
|
break;
|
|
|
|
#ifdef _WIN65
|
|
// BriMo checkin at 01/22/99
|
|
case OID_SECURITY_CERT_SIGNING2:
|
|
if (m_rOptions.cSigners)
|
|
{
|
|
PCCERT_CONTEXT pcCert = CertDuplicateCertificateContext(m_rOptions.rgpcCertSigning[0]);
|
|
pValue->uhVal = *(ULARGE_INTEGER *)(&(pcCert));
|
|
} else {
|
|
ZeroMemory(&(pValue->uhVal), sizeof(pValue->uhVal));
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_CERT_SIGNING_RG2:
|
|
hr = HrCopyIntoUlonglongArray((ULARGE_INTEGER *)m_rOptions.rgpcCertSigning, m_rOptions.cSigners, pValue);
|
|
// Duplicate the certs in place.
|
|
for (iLayer = 0; iLayer < m_rOptions.cSigners; iLayer++)
|
|
{
|
|
PCCERT_CONTEXT pcCert = CertDuplicateCertificateContext((PCCERT_CONTEXT)(pValue->cauh.pElems[iLayer]));
|
|
pValue->cauh.pElems[iLayer] = *(ULARGE_INTEGER *)(&(pcCert));
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_CERT_DECRYPTION2:
|
|
{
|
|
PCCERT_CONTEXT pcCert = CertDuplicateCertificateContext(m_rOptions.pcCertDecryption);
|
|
pValue->uhVal = *(ULARGE_INTEGER *)(&(pcCert));
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_RG_CERT_ENCRYPT2:
|
|
hr = _CERTARRAYToCAUH(m_rOptions.caEncrypt, &pValue->cauh);
|
|
break;
|
|
|
|
case OID_SECURITY_HCERTSTORE2:
|
|
ZeroMemory(&(pValue->uhVal), sizeof(pValue->uhVal));
|
|
if (m_rOptions.hCertStore)
|
|
{
|
|
HCERTSTORE hCertStore = CertDuplicateStore(m_rOptions.hCertStore);
|
|
|
|
pValue->uhVal = *(ULARGE_INTEGER *)(&(hCertStore));
|
|
}
|
|
break;
|
|
|
|
case OID_SECURITY_RG_CERT_BAG2:
|
|
hr = _CertStoreToCAUH(m_rOptions.hCertStore, &pValue->cauh);
|
|
break;
|
|
|
|
case OID_SECURITY_SEARCHSTORES2:
|
|
hr = _STOREARRAYToCAUH(m_rOptions.saSearchStore, &pValue->cauh);
|
|
break;
|
|
|
|
case OID_SECURITY_RG_IASN2:
|
|
Assert(FALSE);
|
|
//N TODO: OID_SECURITY_RG_IASN
|
|
break;
|
|
|
|
case OID_SECURITY_HCRYPTPROV2:
|
|
pValue->uhVal = *(ULARGE_INTEGER *)(&(m_rOptions.hCryptProv));
|
|
m_rOptions.hCryptProv = NULL; // read-once
|
|
break;
|
|
// End of BriMo check-in
|
|
#endif // _WIN65
|
|
|
|
#ifdef _WIN64
|
|
case OID_SECURITY_HWND_OWNER_64:
|
|
pValue->pulVal = (ULONG *)(m_rOptions.hwndOwner);
|
|
break;
|
|
#endif _WIN64
|
|
|
|
default:
|
|
hr = m_pContainer->GetOption(oid, pValue);
|
|
break;
|
|
}
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::InitNew
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::InitNew(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Release Lock Bytes
|
|
EmptyData();
|
|
|
|
// These flags are based on the data objects
|
|
m_dwState = 0;
|
|
|
|
// Change Size
|
|
m_cbExternal = 0xFFFFFFFF;
|
|
|
|
// Have I Created my property set yet ?
|
|
if (NULL == m_pContainer)
|
|
{
|
|
// Create Init
|
|
CHECKALLOC(m_pContainer = new CMimePropertyContainer);
|
|
}
|
|
|
|
// Reset the property set
|
|
CHECKHR(hr = m_pContainer->InitNew());
|
|
|
|
// Reset m_pCsetTagged
|
|
m_pCsetTagged = NULL;
|
|
|
|
// Reset Options
|
|
_FreeOptions();
|
|
|
|
// Reset to default options (this is probably a bug)
|
|
CopyMemory(&m_rOptions, &g_rDefBodyOptions, sizeof(BODYOPTIONS));
|
|
|
|
// (t-erikne) need to get this default at run time
|
|
m_rOptions.hwndOwner = HWND_DESKTOP;
|
|
|
|
// Reset Charset
|
|
m_pCharset = CIntlGlobals::GetDefBodyCset();
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::EmptyData
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::EmptyData(void)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Free current display name
|
|
SafeMemFree(m_pszDisplay);
|
|
|
|
// Do I have Data
|
|
SafeRelease(m_rStorage.pUnkRelease);
|
|
|
|
// Zero
|
|
ZeroMemory(&m_rStorage, sizeof(BODYSTORAGE));
|
|
|
|
// Removed CSETTAGGED state
|
|
FLAGCLEAR(m_dwState, BODYSTATE_CSETTAGGED);
|
|
FLAGCLEAR(m_dwState, BODYSTATE_EXTERNAL);
|
|
|
|
// Change Size
|
|
m_cbExternal = 0xFFFFFFFF;
|
|
|
|
// Reset Encoding
|
|
m_ietEncoding = IET_7BIT;
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::SetState
|
|
// --------------------------------------------------------------------------------
|
|
void CMessageBody::SetState(DWORD dwState)
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
FLAGSET(m_dwState, dwState);
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::ClearState
|
|
// --------------------------------------------------------------------------------
|
|
void CMessageBody::ClearState(DWORD dwState)
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
FLAGCLEAR(m_dwState, dwState);
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::ClearDirty
|
|
// --------------------------------------------------------------------------------
|
|
void CMessageBody::ClearDirty(void)
|
|
{
|
|
ASSERTINIT;
|
|
EnterCriticalSection(&m_cs);
|
|
FLAGCLEAR(m_dwState, BODYSTATE_DIRTY);
|
|
m_pContainer->ClearState(COSTATE_DIRTY);
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::IsType
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::IsType(IMSGBODYTYPE type)
|
|
{
|
|
// Locals
|
|
HRESULT hr;
|
|
STATSTG rStat;
|
|
ASSERTINIT;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Handle Type
|
|
if (IBT_SECURE == type)
|
|
{
|
|
// Is Secure Flag Set
|
|
hr = (ISFLAGSET(m_dwState, BODYSTATE_SECURE)) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
// Charset Tagged
|
|
else if (IBT_CSETTAGGED == type)
|
|
{
|
|
hr = ISFLAGSET(m_dwState, BODYSTATE_CSETTAGGED) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
// Is this an attachment
|
|
else if (IBT_ATTACHMENT == type)
|
|
{
|
|
// If container returns IMF_ATTACHMENTS, it must be an attachment
|
|
DWORD dw = m_pContainer->DwGetMessageFlags(m_rOptions.fHideTNEF);
|
|
hr = (ISFLAGSET(dw, IMF_ATTACHMENTS) || ISFLAGSET(dw, IMF_HASVCARD)) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
// Was AUTOATTACH
|
|
else if (IBT_AUTOATTACH == type)
|
|
{
|
|
hr = (m_pNode && ISFLAGSET(m_pNode->dwState, NODESTATE_AUTOATTACH)) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
// Is the body empty
|
|
else if (IBT_EMPTY == type)
|
|
{
|
|
// Body is not empty if it is a multipart with children
|
|
if (m_pContainer->IsContentType(STR_CNT_MULTIPART, NULL) == S_OK && m_pNode && m_pNode->cChildren > 0)
|
|
hr = S_FALSE;
|
|
else if (m_rStorage.pUnkRelease)
|
|
hr = S_FALSE;
|
|
else
|
|
hr = S_OK;
|
|
}
|
|
|
|
// Error
|
|
else
|
|
{
|
|
hr = TrapError(MIME_E_INVALID_BODYTYPE);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::IsDirty
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::IsDirty(void)
|
|
{
|
|
ASSERTINIT;
|
|
EnterCriticalSection(&m_cs);
|
|
HRESULT hr = (ISFLAGSET(m_dwState, BODYSTATE_DIRTY) || m_pContainer->IsDirty() == S_OK) ? S_OK : S_FALSE;
|
|
LeaveCriticalSection(&m_cs);
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::GetOffsets
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetOffsets(LPBODYOFFSETS pOffsets)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ASSERTINIT;
|
|
|
|
// Invalid Arg
|
|
if (NULL == pOffsets)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Init
|
|
ZeroMemory(pOffsets, sizeof(BODYOFFSETS));
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Not Bound
|
|
if (NULL == m_pNode || (0 == m_pNode->cbBodyStart && 0 == pOffsets->cbBodyEnd))
|
|
{
|
|
hr = TrapError(MIME_E_NO_DATA);
|
|
goto exit;
|
|
}
|
|
|
|
// Get Offset Info
|
|
pOffsets->cbBoundaryStart = m_pNode->cbBoundaryStart;
|
|
pOffsets->cbHeaderStart = m_pNode->cbHeaderStart;
|
|
pOffsets->cbBodyStart = m_pNode->cbBodyStart;
|
|
pOffsets->cbBodyEnd = m_pNode->cbBodyEnd;
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::GetEstimatedSize
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetEstimatedSize(ENCODINGTYPE ietEncoding, ULONG *pcbSize)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cbSize=0;
|
|
STATSTG rStat;
|
|
DOCCONVTYPE dctConvert;
|
|
ILockBytes *plb=NULL;
|
|
ASSERTINIT;
|
|
|
|
// Parameter Check
|
|
if (NULL == pcbSize)
|
|
return TrapError(E_INVALIDARG);
|
|
if (ietEncoding >= IET_UNKNOWN)
|
|
return TrapError(MIME_E_INVALID_ENCODINGTYPE);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// If external..
|
|
if (ISFLAGSET(m_dwState, BODYSTATE_EXTERNAL) && TRUE == m_rOptions.fExternalBody && 0xFFFFFFFF != m_cbExternal)
|
|
{
|
|
*pcbSize = m_cbExternal;
|
|
goto exit;
|
|
}
|
|
|
|
// No internal lockbytes yet ?
|
|
CHECKHR(hr = HrGetLockBytes(&plb));
|
|
|
|
// Query m_pLockBytes Size
|
|
CHECKHR(hr = plb->Stat(&rStat, STATFLAG_NONAME));
|
|
cbSize = (ULONG)rStat.cbSize.QuadPart;
|
|
|
|
// Otheriwse
|
|
if (IET_CURRENT != ietEncoding)
|
|
{
|
|
// Compute ietEncoding type...
|
|
dctConvert = g_rgConversionMap[m_pContainer->GetEncodingType()].rgDestType[ietEncoding];
|
|
|
|
// Handle Conversion type
|
|
if (DCT_ENCODE == dctConvert)
|
|
cbSize = (ULONG)((cbSize * 4) / 3);
|
|
else if (DCT_DECODE == dctConvert)
|
|
cbSize = (ULONG)((cbSize * 3) / 4);
|
|
}
|
|
|
|
// Set Return Size
|
|
*pcbSize = cbSize;
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(plb);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::SaveToFile
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::SaveToFile(ENCODINGTYPE ietEncoding, LPCSTR pszFilePath)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPWSTR pszFilePathW=NULL;
|
|
|
|
// Trace
|
|
TraceCall("CMessageBody::SaveToFile");
|
|
|
|
// Convert
|
|
IF_NULLEXIT(pszFilePathW = PszToUnicode(CP_ACP, pszFilePath));
|
|
|
|
// Do it as unicode
|
|
IF_FAILEXIT(hr = SaveToFileW(ietEncoding, pszFilePathW));
|
|
|
|
exit:
|
|
// Cleanup
|
|
MemFree(pszFilePathW);
|
|
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::SaveToFileW
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::SaveToFileW(ENCODINGTYPE ietEncoding, LPCWSTR pszFilePath)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
HRESULT hrWarnings=S_OK;
|
|
LPSTREAM pstmFile=NULL,
|
|
pstmBody=NULL;
|
|
ASSERTINIT;
|
|
|
|
// Parameter Check
|
|
if (NULL == pszFilePath)
|
|
return TrapError(E_INVALIDARG);
|
|
if (ietEncoding >= IET_UNKNOWN)
|
|
return TrapError(MIME_E_INVALID_ENCODINGTYPE);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Call Get Data
|
|
CHECKHR(hr = GetData(ietEncoding, &pstmBody));
|
|
|
|
// Open File Stream
|
|
CHECKHR(hr = OpenFileStreamW((LPWSTR)pszFilePath, CREATE_ALWAYS, GENERIC_WRITE, &pstmFile));
|
|
|
|
// Copy Stream
|
|
CHECKHR(hr = _HrCopyDataStream(pstmBody, pstmFile));
|
|
if (S_OK != hr)
|
|
hrWarnings = TrapError(hr);
|
|
|
|
// Commit
|
|
CHECKHR(hr = pstmFile->Commit(STGC_DEFAULT));
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pstmFile);
|
|
SafeRelease(pstmBody);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return (hr == S_OK) ? hrWarnings : hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::GetData
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetData(ENCODINGTYPE ietEncoding, IStream **ppStream)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
BODYSTREAMINIT rStreamInit;
|
|
CBodyStream *pBodyStream=NULL;
|
|
ASSERTINIT;
|
|
|
|
// Parameter Check
|
|
if (NULL == ppStream)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Init StreamInit
|
|
ZeroMemory(&rStreamInit, sizeof(BODYSTREAMINIT));
|
|
|
|
// Initialzie
|
|
rStreamInit.ietExternal = ietEncoding;
|
|
rStreamInit.ietInternal = m_ietEncoding;
|
|
rStreamInit.fRemoveNBSP = m_rOptions.fRemoveNBSP;
|
|
rStreamInit.pCharset = m_pCharset;
|
|
|
|
// Create a new body stream...
|
|
CHECKALLOC(pBodyStream = new CBodyStream());
|
|
|
|
// Initialize the body stream
|
|
CHECKHR(hr = pBodyStream->HrInitialize(&rStreamInit, this));
|
|
|
|
// Set return
|
|
*ppStream = (IStream *)pBodyStream;
|
|
(*ppStream)->AddRef();
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pBodyStream);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::GetDataHere
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetDataHere(ENCODINGTYPE ietEncoding, IStream *pStream)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
HRESULT hrWarnings=S_OK;
|
|
IStream *pBodyStream=NULL;
|
|
ASSERTINIT;
|
|
|
|
// Parameter Check
|
|
if (NULL == pStream)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Get the body stream
|
|
CHECKHR(hr = GetData(ietEncoding, &pBodyStream));
|
|
|
|
// Copy Stream
|
|
CHECKHR(hr = _HrCopyDataStream(pBodyStream, pStream));
|
|
if (S_OK != hr)
|
|
hrWarnings = TrapError(hr);
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pBodyStream);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return (hr == S_OK) ? hrWarnings : hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_HrCopyDataStream
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::_HrCopyDataStream(IStream *pstmSource, IStream *pstmDest)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
HRESULT hrWarnings=S_OK;
|
|
BYTE rgBuffer[4096];
|
|
ULONG cbRead;
|
|
DWORD cbStream = 0;
|
|
STATSTG statstg;
|
|
|
|
// Invalid Arg
|
|
Assert(pstmSource && pstmDest);
|
|
|
|
// get the size of the stream
|
|
CHECKHR(pstmSource->Stat(&statstg, STATFLAG_NONAME));
|
|
cbStream = statstg.cbSize.LowPart;
|
|
|
|
// Loop for ever
|
|
while(cbStream)
|
|
{
|
|
// Read a buffer
|
|
CHECKHR(hr = pstmSource->Read(rgBuffer, ARRAYSIZE(rgBuffer), &cbRead));
|
|
if (S_OK != hr)
|
|
hrWarnings = TrapError(hr);
|
|
|
|
// Done
|
|
if (0 == cbRead)
|
|
break;
|
|
|
|
cbStream = cbStream - cbRead;
|
|
|
|
// Write It
|
|
CHECKHR(hr = pstmDest->Write(rgBuffer, cbRead, NULL));
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return (hr == S_OK) ? hrWarnings : hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::HrGetLockBytes
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::HrGetLockBytes(ILockBytes **ppLockBytes)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ASSERTINIT;
|
|
|
|
// Invalid Arg
|
|
Assert(ppLockBytes);
|
|
|
|
// Init
|
|
*ppLockBytes = NULL;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// No Data
|
|
if (NULL == m_rStorage.pUnkRelease)
|
|
{
|
|
hr = TrapError(MIME_E_NO_DATA);
|
|
goto exit;
|
|
}
|
|
|
|
// IID_ILockBytes
|
|
if (IID_ILockBytes == m_rStorage.riid)
|
|
{
|
|
// AddRef It
|
|
*ppLockBytes = m_rStorage.pLockBytes;
|
|
(*ppLockBytes)->AddRef();
|
|
}
|
|
|
|
// IID_IMimeWebDocument
|
|
else if (IID_IMimeWebDocument == m_rStorage.riid)
|
|
{
|
|
// BindToStorage
|
|
CHECKHR(hr = m_rStorage.pWebDocument->BindToStorage(IID_ILockBytes, (LPVOID *)ppLockBytes));
|
|
|
|
// Lets Cache ppLockBytes
|
|
SafeRelease(m_rStorage.pUnkRelease);
|
|
|
|
// Assume the lock bytes
|
|
m_rStorage.pLockBytes = (*ppLockBytes);
|
|
m_rStorage.pLockBytes->AddRef();
|
|
|
|
// Set pUnkRelease
|
|
m_rStorage.pUnkRelease = m_rStorage.pLockBytes;
|
|
|
|
// Set Storage Id
|
|
m_rStorage.riid = IID_ILockBytes;
|
|
}
|
|
|
|
// Big Problem
|
|
else
|
|
Assert(FALSE);
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::SetData
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::SetData(ENCODINGTYPE ietEncoding, LPCSTR pszPriType, LPCSTR pszSubType,
|
|
REFIID riid, LPVOID pvObject)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
IStream *pStream=NULL;
|
|
ASSERTINIT;
|
|
|
|
// Parameter Check
|
|
if (NULL == pvObject || ietEncoding >= IET_UNKNOWN || FALSE == FBODYSETDATAIID(riid))
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// If multipart...
|
|
if (m_pContainer->IsContentType(STR_CNT_MULTIPART, NULL) == S_OK)
|
|
{
|
|
// RAID-29817: Only fail if there are children
|
|
if (m_pNode && m_pNode->cChildren > 0)
|
|
{
|
|
hr = TrapError(MIME_E_MULTIPART_NO_DATA);
|
|
goto exit;
|
|
}
|
|
|
|
// Lets adjust the Content-Type to application/octet-stream now so that things don't get confused
|
|
CHECKHR(hr = m_pContainer->SetProp(SYM_HDR_CNTTYPE, STR_MIME_APPL_STREAM));
|
|
}
|
|
|
|
// Release current m_pLockBytes
|
|
EmptyData();
|
|
|
|
// IID_IStream
|
|
if (IID_IStream == riid)
|
|
{
|
|
// New CBodyLockBytes
|
|
CHECKALLOC(m_rStorage.pLockBytes = new CStreamLockBytes((IStream *)pvObject));
|
|
|
|
// Set m_rStorage type
|
|
m_rStorage.riid = IID_ILockBytes;
|
|
m_rStorage.pUnkRelease = m_rStorage.pLockBytes;
|
|
}
|
|
|
|
// IID_ILockBytes
|
|
else if (IID_ILockBytes == riid)
|
|
{
|
|
// Just assume it
|
|
m_rStorage.pLockBytes = (ILockBytes *)pvObject;
|
|
m_rStorage.pLockBytes->AddRef();
|
|
|
|
// Set m_rStorage type
|
|
m_rStorage.riid = IID_ILockBytes;
|
|
m_rStorage.pUnkRelease = m_rStorage.pLockBytes;
|
|
}
|
|
|
|
// IID_IMimeBody
|
|
else if (IID_IMimeBody == riid)
|
|
{
|
|
// CopyTo
|
|
CHECKHR(hr = ((IMimeBody *)pvObject)->CopyTo(this));
|
|
}
|
|
|
|
// IID_IMimeMessage
|
|
else if (IID_IMimeMessage == riid)
|
|
{
|
|
// Locals
|
|
IMimePropertySet *pProps;
|
|
IMimeMessage *pMessage=(IMimeMessage *)pvObject;
|
|
|
|
// Get the message source
|
|
CHECKHR(hr = pMessage->GetMessageSource(&pStream, 0));
|
|
|
|
// New CBodyLockBytes
|
|
CHECKALLOC(m_rStorage.pLockBytes = new CStreamLockBytes(pStream));
|
|
|
|
// Set m_rStorage type
|
|
m_rStorage.riid = IID_ILockBytes;
|
|
m_rStorage.pUnkRelease = m_rStorage.pLockBytes;
|
|
|
|
// Set Content Type message/rfc822
|
|
CHECKHR(hr = m_pContainer->SetProp(SYM_HDR_CNTTYPE, STR_MIME_MSG_RFC822));
|
|
|
|
// Get Root Property Container
|
|
if (SUCCEEDED(pMessage->BindToObject(HBODY_ROOT, IID_IMimePropertySet, (LPVOID *)&pProps)))
|
|
{
|
|
// Locals
|
|
MIMEPROPINFO rPropInfo;
|
|
|
|
// I don't actualy want any props, just want to know if its set
|
|
rPropInfo.dwMask = 0;
|
|
|
|
// News Message ?
|
|
if (SUCCEEDED(pProps->GetPropInfo(PIDTOSTR(PID_HDR_NEWSGROUPS), &rPropInfo)) ||
|
|
SUCCEEDED(pProps->GetPropInfo(PIDTOSTR(PID_HDR_XNEWSRDR), &rPropInfo)) ||
|
|
SUCCEEDED(pProps->GetPropInfo(PIDTOSTR(PID_HDR_NEWSGROUP), &rPropInfo)))
|
|
m_pContainer->SetState(COSTATE_RFC822NEWS);
|
|
else
|
|
m_pContainer->ClearState(COSTATE_RFC822NEWS);
|
|
|
|
// Release
|
|
pProps->Release();
|
|
}
|
|
}
|
|
|
|
// IID_IMimeWebDocument
|
|
else if (IID_IMimeWebDocument == riid)
|
|
{
|
|
// Just assume it
|
|
m_rStorage.pWebDocument = (IMimeWebDocument *)pvObject;
|
|
m_rStorage.pWebDocument->AddRef();
|
|
|
|
// Set m_rStorage type
|
|
m_rStorage.riid = IID_IMimeWebDocument;
|
|
m_rStorage.pUnkRelease = m_rStorage.pWebDocument;
|
|
}
|
|
|
|
// Save The Format
|
|
m_ietEncoding = ietEncoding;
|
|
|
|
// Save Format per bert
|
|
if (g_rgEncodingMap[ietEncoding].pszName)
|
|
CHECKHR(hr = m_pContainer->SetProp(SYM_HDR_CNTXFER, g_rgEncodingMap[ietEncoding].pszName));
|
|
|
|
// Set PriType
|
|
if (pszPriType)
|
|
CHECKHR(hr = m_pContainer->SetProp(SYM_ATT_PRITYPE, pszPriType));
|
|
|
|
// Set SubType
|
|
if (pszSubType)
|
|
CHECKHR(hr = m_pContainer->SetProp(SYM_ATT_SUBTYPE, pszSubType));
|
|
|
|
// Assume The User is now controlling the Character Set Properties of this body
|
|
FLAGCLEAR(m_dwState, BODYSTATE_CSETTAGGED);
|
|
|
|
// We are now dirty
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pStream);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CMessageBody::SetDataW(ENCODINGTYPE ietEncoding, LPCWSTR pwszPriType, LPCWSTR pwszSubType,
|
|
REFIID riid, LPVOID pvObject)
|
|
{
|
|
return TraceResult(E_NOTIMPL);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::CopyTo
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::CopyTo(IMimeBody *pBodyIn)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPMESSAGEBODY pBody=NULL;
|
|
LPCONTAINER pContainer=NULL;
|
|
|
|
// Invalid Arg
|
|
if (NULL == pBodyIn)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// QI for Private CMessageBody
|
|
CHECKHR(hr = pBodyIn->QueryInterface(IID_CMessageBody, (LPVOID *)&pBody));
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&pBody->m_cs);
|
|
|
|
// Copy Data Over
|
|
pBody->m_dwState = m_dwState;
|
|
|
|
// Release Current Data
|
|
pBody->EmptyData();
|
|
|
|
// Copy body props
|
|
CHECKHR(hr = m_pContainer->Clone(&pContainer));
|
|
|
|
// Release the Bodies' Current Container
|
|
SafeRelease(pBody->m_pContainer);
|
|
|
|
// Reset the Container
|
|
pBody->m_pContainer = pContainer;
|
|
pBody->m_pContainer->AddRef();
|
|
|
|
// Assume new container in pNode
|
|
if (pBody->m_pNode)
|
|
{
|
|
SafeRelease(pBody->m_pNode->pContainer);
|
|
pBody->m_pNode->pContainer = pContainer;
|
|
pContainer->AddRef();
|
|
}
|
|
|
|
// Copy Display Name
|
|
if (m_pszDisplay)
|
|
CHECKALLOC(pBody->m_pszDisplay = PszDupW(m_pszDisplay));
|
|
|
|
// Copy Options
|
|
|
|
// BUGBUG: This is pretty iffy. BODYOPTIONS contains pointers, each of which should
|
|
// be duplicated. Caller beware!
|
|
|
|
CopyMemory(&pBody->m_rOptions, &m_rOptions, sizeof(BODYOPTIONS));
|
|
|
|
// Current Encoding
|
|
pBody->m_ietEncoding = m_ietEncoding;
|
|
|
|
// Charset
|
|
pBody->m_pCharset = m_pCharset;
|
|
|
|
// If we have data
|
|
if (m_rStorage.pUnkRelease)
|
|
{
|
|
// IID_ILockBytes
|
|
if (IID_ILockBytes == m_rStorage.riid)
|
|
{
|
|
pBody->m_rStorage.pLockBytes = m_rStorage.pLockBytes;
|
|
pBody->m_rStorage.pLockBytes->AddRef();
|
|
pBody->m_rStorage.pUnkRelease = pBody->m_rStorage.pLockBytes;
|
|
pBody->m_rStorage.riid = IID_ILockBytes;
|
|
}
|
|
|
|
// IID_IMimeWebDocument
|
|
else if (IID_IMimeWebDocument == m_rStorage.riid)
|
|
{
|
|
pBody->m_rStorage.pWebDocument = m_rStorage.pWebDocument;
|
|
pBody->m_rStorage.pWebDocument->AddRef();
|
|
pBody->m_rStorage.pUnkRelease = pBody->m_rStorage.pWebDocument;
|
|
pBody->m_rStorage.riid = IID_IMimeWebDocument;
|
|
}
|
|
|
|
// Big Problem
|
|
else
|
|
Assert(FALSE);
|
|
}
|
|
|
|
exit:
|
|
// Release Thread Safety
|
|
if (pBody)
|
|
LeaveCriticalSection(&pBody->m_cs);
|
|
|
|
// Cleanup
|
|
SafeRelease(pBody);
|
|
SafeRelease(pContainer);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::SetCurrentEncoding
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::SetCurrentEncoding(ENCODINGTYPE ietEncoding)
|
|
{
|
|
// Parameter Check
|
|
if (ietEncoding >= IET_UNKNOWN)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Set the current encoding
|
|
m_ietEncoding = ietEncoding;
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::GetCurrentEncoding
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetCurrentEncoding(ENCODINGTYPE *pietEncoding)
|
|
{
|
|
// Invalid Arg
|
|
if (NULL == pietEncoding)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Set Return
|
|
*pietEncoding = m_ietEncoding;
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::GetTransmitInfo
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetTransmitInfo(LPTRANSMITINFO pTransmit)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
HRESULT hrWarnings=S_OK;
|
|
ULONG cbRead,
|
|
cbLine=0,
|
|
cEscapeChars=0,
|
|
i;
|
|
BYTE rgBuffer[4096];
|
|
LPSTREAM pStream=NULL;
|
|
BYTE bPrev='\0';
|
|
BOOL fBadEOL=FALSE;
|
|
DWORD cbStream = 0;
|
|
STATSTG statstg;
|
|
ASSERTINIT;
|
|
|
|
// Parmaeters
|
|
if (NULL == pTransmit)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Init
|
|
ZeroMemory(pTransmit, sizeof(TRANSMITINFO));
|
|
|
|
// Set the current code page
|
|
pTransmit->ietCurrent = m_ietEncoding;
|
|
|
|
// Init Format
|
|
pTransmit->ietXmitMime = IET_7BIT;
|
|
pTransmit->ietXmit822 = IET_7BIT;
|
|
|
|
// Don't call for multipart types...
|
|
if (m_pContainer->IsContentType(STR_CNT_MULTIPART, NULL) == S_OK)
|
|
{
|
|
Assert(FALSE);
|
|
hr = TrapError(MIME_E_MULTIPART_NO_DATA);
|
|
goto exit;
|
|
}
|
|
|
|
// Lets a binary stream of the data
|
|
CHECKHR(hr = GetData(IET_INETCSET, &pStream));
|
|
|
|
// get the size of the stream
|
|
CHECKHR(pStream->Stat(&statstg, STATFLAG_NONAME));
|
|
cbStream = statstg.cbSize.LowPart;
|
|
|
|
// Scan It
|
|
while(cbStream)
|
|
{
|
|
// Read a buffer
|
|
CHECKHR(hr = pStream->Read(rgBuffer, sizeof(rgBuffer), &cbRead));
|
|
if (S_OK != hr)
|
|
hrWarnings = TrapError(hr);
|
|
|
|
// Done
|
|
if (0 == cbRead)
|
|
break;
|
|
|
|
cbStream = cbStream - cbRead;
|
|
|
|
// Scan the buffer
|
|
for (i=0; i<cbRead; i++, cbLine++)
|
|
{
|
|
// If End of line, reset line length
|
|
if (chLF == rgBuffer[i])
|
|
{
|
|
// Count lines
|
|
pTransmit->cLines++;
|
|
cbLine = 0;
|
|
|
|
// Raid-41839: x-bitmap images are not correctly transferred via Schotzie
|
|
// Don't write out lines that end with only a \n, not legal
|
|
if (chCR != bPrev)
|
|
fBadEOL = TRUE;
|
|
}
|
|
|
|
// Line too long
|
|
if (cbLine > pTransmit->cbLongestLine)
|
|
pTransmit->cbLongestLine++;
|
|
|
|
// Tests for extended and control characters
|
|
if (IS_EXTENDED(rgBuffer[i]))
|
|
{
|
|
// Count Extneded
|
|
pTransmit->cExtended++;
|
|
|
|
// Count Escape Characters
|
|
if (0x1B == rgBuffer[i])
|
|
cEscapeChars++;
|
|
}
|
|
|
|
// Save Previous
|
|
bPrev = rgBuffer[i];
|
|
}
|
|
|
|
// Increment Total
|
|
pTransmit->cbSize += cbRead;
|
|
}
|
|
|
|
// No Data ?
|
|
if (0 == pTransmit->cbSize)
|
|
{
|
|
pTransmit->ulPercentExt = 0;
|
|
goto exit;
|
|
}
|
|
|
|
// RAID-22542: FE-J:Athena:mail:sending mail with text/plain has Content-transfer-encording:8bit
|
|
if (FALSE == m_rOptions.fDBCSEscape8 && cEscapeChars > 0 && m_pCharset && g_pInternat->IsDBCSCharset(m_pCharset->hCharset) == S_OK)
|
|
{
|
|
// Subtract the Number of EscapeChars off of the number of extended chars
|
|
Assert(cEscapeChars <= pTransmit->cExtended);
|
|
pTransmit->cExtended -= cEscapeChars;
|
|
}
|
|
|
|
if (IET_UNKNOWN == m_rOptions.ietTransmit)
|
|
{
|
|
// More than 25% extended characters
|
|
pTransmit->ulPercentExt = ((pTransmit->cExtended * 100) / pTransmit->cbSize);
|
|
|
|
// Raid-41839: x-bitmap images are not correctly transferred via Schotzie
|
|
// More than 17 percent extended
|
|
if (pTransmit->ulPercentExt > 17)
|
|
{
|
|
pTransmit->ietXmitMime = IET_BASE64;
|
|
pTransmit->ietXmit822 = IET_UUENCODE;
|
|
}
|
|
|
|
// Some Extended Characters or line longer than max
|
|
else if (pTransmit->cExtended || pTransmit->cbLongestLine > m_rOptions.cbMaxLine || TRUE == fBadEOL)
|
|
{
|
|
pTransmit->ietXmitMime = IET_QP;
|
|
pTransmit->ietXmit822 = IET_7BIT;
|
|
}
|
|
|
|
// Otherwise, 7bit
|
|
else
|
|
{
|
|
pTransmit->ietXmitMime = IET_7BIT;
|
|
pTransmit->ietXmit822 = IET_7BIT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the client specifically set this option, so honor it
|
|
pTransmit->ietXmitMime = m_rOptions.ietTransmit;
|
|
|
|
// we may need to fixup ietXmit822 if the XmitMime
|
|
// option does not make sense for it
|
|
switch (m_rOptions.ietTransmit)
|
|
{
|
|
case IET_BASE64:
|
|
pTransmit->ietXmit822 = IET_UUENCODE;
|
|
break;
|
|
case IET_QP:
|
|
pTransmit->ietXmit822 = IET_7BIT;
|
|
break;
|
|
default:
|
|
pTransmit->ietXmit822 = m_rOptions.ietTransmit;
|
|
break;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pStream);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return (hr == S_OK) ? hrWarnings : hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::SwitchContainers
|
|
// --------------------------------------------------------------------------------
|
|
void CMessageBody::SwitchContainers(CMessageBody *pBody)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
EnterCriticalSection(&pBody->m_cs);
|
|
|
|
// Invalid Arg
|
|
Assert(pBody && pBody->m_pContainer && m_pContainer && m_pNode && pBody->m_pNode);
|
|
|
|
// Simple Varialbe Swap
|
|
LPCONTAINER pTemp = m_pContainer;
|
|
m_pNode->pContainer = m_pContainer = pBody->m_pContainer;
|
|
pBody->m_pNode->pContainer = pBody->m_pContainer = pTemp;
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&pBody->m_cs);
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::GetHandle
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetHandle(LPHBODY phBody)
|
|
{
|
|
// Local
|
|
HRESULT hr=S_OK;
|
|
ASSERTINIT;
|
|
|
|
// Invalid Arg
|
|
if (NULL == phBody)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Init
|
|
*phBody = NULL;
|
|
|
|
// Not Bound...
|
|
if (NULL == m_pNode || NULL == m_pNode->hBody)
|
|
{
|
|
hr = MIME_E_NO_DATA;
|
|
goto exit;
|
|
}
|
|
|
|
// Set Handle
|
|
*phBody = m_pNode->hBody;
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::GetClassID
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetClassID(CLSID *pClassID)
|
|
{
|
|
ASSERTINIT;
|
|
|
|
// Parmaeters
|
|
if (NULL == pClassID)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Copy Class Id
|
|
CopyMemory(pClassID, &IID_IMimeBody, sizeof(CLSID));
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::GetSizeMax
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetSizeMax(ULARGE_INTEGER* pcbSize)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cbSize;
|
|
ASSERTINIT;
|
|
|
|
// Get The Size
|
|
CHECKHR(hr = GetEstimatedSize(IET_BINARY, &cbSize));
|
|
|
|
// Return the Size
|
|
pcbSize->QuadPart = cbSize;
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::Load
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::Load(LPSTREAM pStream)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->Load(pStream));
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CMessageBody::Load
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT CMessageBody::Load(CInternetStream *pInternet)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->Load(pInternet));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::Save
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::Save(LPSTREAM pStream, BOOL fClearDirty)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->Save(pStream, fClearDirty));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::IsContentType
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::IsContentType(LPCSTR pszPriType, LPCSTR pszSubType)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->IsContentType(pszPriType, pszSubType));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::GetCharset
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetCharset(LPHCHARSET phCharset)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->GetCharset(phCharset));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::SetCharset
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::SetCharset(HCHARSET hCharset, CSETAPPLYTYPE applytype)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ASSERTINIT;
|
|
|
|
// Invalid Arg
|
|
if (NULL == hCharset)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Lookiup Charset Info
|
|
if (FALSE == g_pInternat->FIsValidHandle(hCharset))
|
|
{
|
|
hr = TrapError(MIME_E_INVALID_HANDLE);
|
|
goto exit;
|
|
}
|
|
|
|
// If I'm already tagged with a charset, and applytype is CSET_APPLY_UNTAGGED, then leave
|
|
if (ISFLAGSET(m_dwState, BODYSTATE_SKIPCSET) == TRUE && CSET_APPLY_UNTAGGED == applytype)
|
|
goto exit;
|
|
|
|
// Pass it into the property set
|
|
CHECKHR(hr = m_pContainer->SetCharset(hCharset, applytype));
|
|
|
|
// If I'm already tagged with a charset, and applytype is CSET_APPLY_UNTAGGED, then leave
|
|
if (ISFLAGSET(m_dwState, BODYSTATE_CSETTAGGED) == TRUE && CSET_APPLY_UNTAGGED == applytype)
|
|
goto exit;
|
|
|
|
// Save the character set...
|
|
SideAssert(SUCCEEDED(g_pInternat->HrOpenCharset(hCharset, &m_pCharset)));
|
|
|
|
// Mark as Tagged
|
|
if (CSET_APPLY_TAG_ALL == applytype)
|
|
{
|
|
// Mark the body as being tagged with a charset
|
|
|
|
// Get Internal Character Set
|
|
if (SUCCEEDED(m_pContainer->GetCharset(&hCharset)))
|
|
{
|
|
// Get Pointer
|
|
SideAssert(SUCCEEDED(g_pInternat->HrOpenCharset(hCharset, &m_pCharset)));
|
|
|
|
// Save this as m_pCsetTagged
|
|
m_pCsetTagged = m_pCharset;
|
|
}
|
|
|
|
// I was tagged with a charset
|
|
FLAGSET(m_dwState, BODYSTATE_CSETTAGGED);
|
|
|
|
// Mark the charset as explicitly set
|
|
FLAGSET(m_dwState, BODYSTATE_SKIPCSET);
|
|
}
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::GetProp
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetProp(LPCSTR pszName, DWORD dwFlags, LPPROPVARIANT pValue)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->GetProp(pszName, dwFlags, pValue));
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CMessageBody::AppendProp
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::AppendProp(LPCSTR pszName, DWORD dwFlags, LPPROPVARIANT pValue)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->AppendProp(pszName, dwFlags, pValue));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::SetProp
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::SetProp(LPCSTR pszName, DWORD dwFlags, LPCPROPVARIANT pValue)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->SetProp(pszName, dwFlags, pValue));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::DeleteProp
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::DeleteProp(LPCSTR pszName)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->DeleteProp(pszName));
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CMessageBody::QueryProp
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::QueryProp(LPCSTR pszName, LPCSTR pszCriteria, boolean fSubString, boolean fCaseSensitive)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->QueryProp(pszName, pszCriteria, fSubString, fCaseSensitive));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::Clone
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::Clone(IMimePropertySet **ppPropertySet)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->Clone(ppPropertySet));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::BindToObject
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::BindToObject(REFIID riid, void **ppvObject)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ASSERTINIT;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// IID_IStream
|
|
if (IID_IStream == riid)
|
|
{
|
|
// Get Data...
|
|
CHECKHR(hr = GetData(IET_INETCSET, (IStream **)ppvObject));
|
|
}
|
|
|
|
// IID_IUnicodeStream
|
|
else if (IID_IUnicodeStream == riid)
|
|
{
|
|
// Get Data...
|
|
CHECKHR(hr = GetData(IET_UNICODE, (IStream **)ppvObject));
|
|
}
|
|
|
|
// IID_IMimeMessage... (returns message/rfc822 or message/partial bodies)
|
|
else if (IID_IMimeMessage == riid)
|
|
{
|
|
// Better be message/rfc822 or message/partial...
|
|
if (m_pContainer->IsContentType(STR_CNT_MESSAGE, STR_SUB_RFC822) == S_OK ||
|
|
m_pContainer->IsContentType(STR_CNT_MESSAGE, STR_SUB_PARTIAL) == S_OK)
|
|
{
|
|
// Locals
|
|
LPSTREAM pstmMsg=NULL;
|
|
IMimeMessage *pMessage=NULL;
|
|
|
|
// Create a message object
|
|
CHECKHR(hr = MimeOleCreateMessage(NULL, &pMessage));
|
|
|
|
// Get the body stream...
|
|
hr = GetData(IET_BINARY, &pstmMsg);
|
|
if (FAILED(hr))
|
|
{
|
|
pMessage->Release();
|
|
TrapError(hr);
|
|
goto exit;
|
|
}
|
|
|
|
// Load the message...
|
|
hr = pMessage->Load(pstmMsg);
|
|
if (FAILED(hr))
|
|
{
|
|
pstmMsg->Release();
|
|
pMessage->Release();
|
|
TrapError(hr);
|
|
goto exit;
|
|
}
|
|
|
|
// Return the message
|
|
*ppvObject = pMessage;
|
|
((IUnknown *)*ppvObject)->AddRef();
|
|
|
|
// Cleanup
|
|
SafeRelease(pstmMsg);
|
|
SafeRelease(pMessage);
|
|
}
|
|
|
|
// Otherwise, fail
|
|
else
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Otheriwse, do a normal QI of the body/property set
|
|
else if (SUCCEEDED(QueryInterface(riid, ppvObject)))
|
|
goto exit;
|
|
|
|
// Otherwise, try to do a bindtoobject on the container
|
|
else if (SUCCEEDED(m_pContainer->BindToObject(riid, ppvObject)))
|
|
goto exit;
|
|
|
|
// Not Found
|
|
else
|
|
hr = TrapError(MIME_E_NOT_FOUND);
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::DeleteExcept
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::DeleteExcept(ULONG cNames, LPCSTR *prgszName)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->DeleteExcept(cNames, prgszName));
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CMessageBody::GetParameters
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetParameters(LPCSTR pszName, ULONG *pcParams, LPMIMEPARAMINFO *pprgParam)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->GetParameters(pszName, pcParams, pprgParam));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::CopyProps
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::CopyProps(ULONG cNames, LPCSTR *prgszName, IMimePropertySet *pPropSet)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->CopyProps(cNames, prgszName, pPropSet));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::MoveProps
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::MoveProps(ULONG cNames, LPCSTR *prgszName, IMimePropertySet *pPropSet)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->MoveProps(cNames, prgszName, pPropSet));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::GetPropInfo
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::GetPropInfo(LPCSTR pszName, LPMIMEPROPINFO pInfo)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->GetPropInfo(pszName, pInfo));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::SetPropInfo
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::SetPropInfo(LPCSTR pszName, LPCMIMEPROPINFO pInfo)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->SetPropInfo(pszName, pInfo));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::EnumProps
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMessageBody::EnumProps(DWORD dwFlags, IMimeEnumProperties **ppEnum)
|
|
{
|
|
ASSERTINIT;
|
|
return TrapError(m_pContainer->EnumProps(dwFlags, ppEnum));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::DwGetFlags
|
|
// --------------------------------------------------------------------------------
|
|
DWORD CMessageBody::DwGetFlags(BOOL fHideTnef)
|
|
{
|
|
DWORD dwFlags = 0;
|
|
ASSERTINIT;
|
|
|
|
dwFlags |= m_pContainer->DwGetMessageFlags(fHideTnef);
|
|
|
|
// if it isn't x-pkcs7-mime, we already know the flags, so no need for the call
|
|
// check the flag first b/c it is cheap
|
|
if (dwFlags & IMF_SECURE &&
|
|
(S_OK == m_pContainer->IsContentType(STR_CNT_APPLICATION, STR_SUB_XPKCS7MIME) ||
|
|
S_OK == m_pContainer->IsContentType(STR_CNT_APPLICATION, STR_SUB_PKCS7MIME)))
|
|
dwFlags |= _GetSecureTypeFlags();
|
|
return dwFlags;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_GetSecureTypeFlags
|
|
// --------------------------------------------------------------------------------
|
|
DWORD CMessageBody::_GetSecureTypeFlags()
|
|
{
|
|
DWORD dwSecType;
|
|
DWORD dwFlags;
|
|
|
|
// if the data isn't ASN.1, then this call should fail
|
|
if (SUCCEEDED(TrapError(CSMime::StaticGetMessageType(m_rOptions.hwndOwner,
|
|
(IMimeBody *)this, &dwSecType))))
|
|
{
|
|
dwFlags = IMF_SECURE;
|
|
if (MST_THIS_SIGN & dwSecType)
|
|
dwFlags |= IMF_SIGNED;
|
|
if (MST_THIS_ENCRYPT & dwSecType)
|
|
dwFlags |= IMF_ENCRYPTED;
|
|
}
|
|
else
|
|
dwFlags = 0;
|
|
|
|
return dwFlags;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::CopyOptionsTo
|
|
// --------------------------------------------------------------------------------
|
|
void CMessageBody::CopyOptionsTo(CMessageBody *pBody, BOOL fNewOnwer /*=FALSE*/)
|
|
{
|
|
// Locals
|
|
ENCODINGTYPE ietTransmit;
|
|
ASSERTINIT;
|
|
|
|
// Valid State
|
|
Assert(pBody);
|
|
|
|
// critsec both bodies since we are using information on both
|
|
EnterCriticalSection(&m_cs);
|
|
EnterCriticalSection(&pBody->m_cs);
|
|
|
|
// Copy Body Options
|
|
pBody->m_rOptions = m_rOptions;
|
|
|
|
// Raid 33207 - Preserve transmit body encoding
|
|
ietTransmit = m_rOptions.ietTransmit;
|
|
|
|
// If pBody->m_rOptions is the new owner, then clear my structure
|
|
CopyMemory(&m_rOptions, &g_rDefBodyOptions, sizeof(BODYOPTIONS));
|
|
|
|
// Raid 33207 - Restore transmit body encoding
|
|
m_rOptions.ietTransmit = ietTransmit;
|
|
|
|
LeaveCriticalSection(&pBody->m_cs);
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
#ifndef _WIN64
|
|
// -----------------------------------------------------------------------------
|
|
// CMessageBody::_CAULToCertStore
|
|
// -----------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::_CAULToCertStore(const CAUL caul, HCERTSTORE * phcertstor)
|
|
{
|
|
DWORD i;
|
|
|
|
// Release the old store -- we don't want it anymore
|
|
|
|
if (*phcertstor != NULL)
|
|
{
|
|
CertCloseStore(*phcertstor, 0);
|
|
*phcertstor = NULL;
|
|
}
|
|
|
|
// Create a new store if needed
|
|
if (*phcertstor == NULL)
|
|
{
|
|
*phcertstor = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING,
|
|
NULL, 0, NULL);
|
|
}
|
|
|
|
if (*phcertstor == NULL)
|
|
{
|
|
return HrGetLastError();
|
|
}
|
|
|
|
for (i=0; i<caul.cElems; i++)
|
|
{
|
|
if (!CertAddCertificateContextToStore(*phcertstor,
|
|
(PCCERT_CONTEXT) caul.pElems[i],
|
|
CERT_STORE_ADD_ALWAYS, NULL))
|
|
{
|
|
return HrGetLastError();
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
#endif // _WIN64
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CMessageBody::_CertStoreToCAUL
|
|
// -----------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::_CertStoreToCAUL(const HCERTSTORE hcertstor, CAUL * pcaul)
|
|
{
|
|
DWORD cCerts = 0;
|
|
PCCERT_CONTEXT pccert = NULL;
|
|
PCCERT_CONTEXT * rgpccert;
|
|
|
|
if (hcertstor != NULL)
|
|
{
|
|
while ((pccert = CertEnumCertificatesInStore(hcertstor, pccert)) != NULL)
|
|
{
|
|
cCerts += 1;
|
|
}
|
|
}
|
|
|
|
if (cCerts == 0)
|
|
{
|
|
pcaul->pElems = NULL;
|
|
pcaul->cElems = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
pcaul->pElems = (ULONG *) g_pMalloc->Alloc(cCerts*sizeof(PCCERT_CONTEXT *));
|
|
if (pcaul->pElems == NULL)
|
|
{
|
|
return TrapError(E_OUTOFMEMORY);
|
|
}
|
|
|
|
rgpccert = (PCCERT_CONTEXT *) pcaul->pElems;
|
|
while ((pccert = CertEnumCertificatesInStore(hcertstor, pccert)) != NULL)
|
|
{
|
|
*rgpccert = CertDuplicateCertificateContext(pccert);
|
|
rgpccert++;
|
|
}
|
|
|
|
pcaul->cElems = cCerts;
|
|
return S_OK;
|
|
}
|
|
|
|
#ifndef SMIME_V3
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_CAULToCERTARRAY
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::_CAULToCERTARRAY(const CAUL caul, CERTARRAY *pca)
|
|
{
|
|
// Locals
|
|
HRESULT hr;
|
|
register DWORD i;
|
|
|
|
if (SUCCEEDED(hr = HrRealloc((void**)&pca->rgpCerts, caul.cElems*sizeof(PCCERT_CONTEXT))))
|
|
{
|
|
for (i = 0; i < pca->cCerts; i++)
|
|
CertFreeCertificateContext(pca->rgpCerts[i]);
|
|
|
|
pca->cCerts = caul.cElems;
|
|
for (i = 0; i < caul.cElems; i++)
|
|
pca->rgpCerts[i] = CertDuplicateCertificateContext((PCCERT_CONTEXT)caul.pElems[i]);
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_CERTARRAYToCAUL
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::_CERTARRAYToCAUL(const CERTARRAY ca, CAUL *pcaul)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
register DWORD i;
|
|
|
|
if (ca.cCerts)
|
|
{
|
|
if ((pcaul->pElems = (ULONG*)(PCCERT_CONTEXT*)g_pMalloc->Alloc(ca.cCerts*sizeof(PCCERT_CONTEXT))))
|
|
{
|
|
pcaul->cElems = ca.cCerts;
|
|
for (i = 0; i < ca.cCerts; i++)
|
|
pcaul->pElems[i] = (ULONG)CertDuplicateCertificateContext(ca.rgpCerts[i]);
|
|
}
|
|
else
|
|
hr = TrapError(E_OUTOFMEMORY);
|
|
}
|
|
else
|
|
{
|
|
pcaul->pElems = NULL;
|
|
pcaul->cElems = 0;
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
#endif // !SMIEM_V3
|
|
|
|
#ifndef _WIN64
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_CAULToSTOREARRAY
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::_CAULToSTOREARRAY(const CAUL caul, STOREARRAY *psa)
|
|
{
|
|
// Locals
|
|
HRESULT hr;
|
|
register DWORD i;
|
|
|
|
if (SUCCEEDED(hr = HrRealloc((void**)&psa->rgStores, caul.cElems*sizeof(HCERTSTORE))))
|
|
{
|
|
for (i = 0; i < psa->cStores; i++)
|
|
CertCloseStore(psa->rgStores[i], 0);
|
|
|
|
psa->cStores = caul.cElems;
|
|
for (i = 0; i < caul.cElems; i++)
|
|
psa->rgStores[i] = CertDuplicateStore((HCERTSTORE)caul.pElems[i]);
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
#endif // _WIN64
|
|
|
|
#ifndef _WIN64
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_STOREARRAYToCAUL
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::_STOREARRAYToCAUL(const STOREARRAY sa, CAUL *pcaul)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
register DWORD i;
|
|
|
|
if (sa.cStores)
|
|
{
|
|
if ((pcaul->pElems = (ULONG*)(HCERTSTORE*)g_pMalloc->Alloc(sa.cStores*sizeof(HCERTSTORE))))
|
|
{
|
|
pcaul->cElems = sa.cStores;
|
|
for (i = 0; i < sa.cStores; i++)
|
|
pcaul->pElems[i] = (ULONG)CertDuplicateStore(sa.rgStores[i]);
|
|
}
|
|
else
|
|
hr = TrapError(E_OUTOFMEMORY);
|
|
}
|
|
else
|
|
{
|
|
pcaul->pElems = NULL;
|
|
pcaul->cElems = 0;
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
#endif // _WIN64
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CMessageBody::_CAUHToCertStore
|
|
// -----------------------------------------------------------------------------
|
|
HRESULT CMessageBody::_CAUHToCertStore(const CAUH cauh, HCERTSTORE * phcertstor)
|
|
{
|
|
DWORD i;
|
|
|
|
#ifndef NEED // This prevent us from send 2 certificates.
|
|
// Release the old store -- we don't want it anymore
|
|
|
|
if (*phcertstor != NULL)
|
|
{
|
|
CertCloseStore(*phcertstor, 0);
|
|
*phcertstor = NULL;
|
|
}
|
|
#endif
|
|
|
|
// Create a new store if needed
|
|
if (*phcertstor == NULL)
|
|
{
|
|
*phcertstor = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING,
|
|
NULL, 0, NULL);
|
|
}
|
|
|
|
if (*phcertstor == NULL)
|
|
{
|
|
return HrGetLastError();
|
|
}
|
|
|
|
for (i=0; i<cauh.cElems; i++)
|
|
{
|
|
if (!CertAddCertificateContextToStore(*phcertstor,
|
|
*(PCCERT_CONTEXT *) (&(cauh.pElems[i])),
|
|
CERT_STORE_ADD_ALWAYS, NULL))
|
|
{
|
|
return HrGetLastError();
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// CMessageBody::_CertStoreToCAUH
|
|
// -----------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::_CertStoreToCAUH(const HCERTSTORE hcertstor, CAUH * pcauh)
|
|
{
|
|
DWORD cCerts = 0;
|
|
PCCERT_CONTEXT pccert = NULL;
|
|
PCCERT_CONTEXT * rgpccert;
|
|
|
|
if (hcertstor != NULL)
|
|
{
|
|
while ((pccert = CertEnumCertificatesInStore(hcertstor, pccert)) != NULL)
|
|
{
|
|
cCerts += 1;
|
|
}
|
|
}
|
|
|
|
if (cCerts == 0)
|
|
{
|
|
pcauh->pElems = NULL;
|
|
pcauh->cElems = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
pcauh->pElems = (ULARGE_INTEGER *) g_pMalloc->Alloc(cCerts*sizeof(PCCERT_CONTEXT *));
|
|
if (pcauh->pElems == NULL)
|
|
{
|
|
return TrapError(E_OUTOFMEMORY);
|
|
}
|
|
|
|
rgpccert = (PCCERT_CONTEXT *) pcauh->pElems;
|
|
while ((pccert = CertEnumCertificatesInStore(hcertstor, pccert)) != NULL)
|
|
{
|
|
*rgpccert = CertDuplicateCertificateContext(pccert);
|
|
rgpccert++;
|
|
}
|
|
|
|
pcauh->cElems = cCerts;
|
|
return S_OK;
|
|
}
|
|
|
|
#ifdef _WIN65
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_CAUHToCERTARRAY
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::_CAUHToCERTARRAY(const CAUH cauh, CERTARRAY *pca)
|
|
{
|
|
// Locals
|
|
HRESULT hr;
|
|
register DWORD i;
|
|
|
|
if (SUCCEEDED(hr = HrRealloc((void**)&pca->rgpCerts, cauh.cElems*sizeof(PCCERT_CONTEXT))))
|
|
{
|
|
for (i = 0; i < pca->cCerts; i++)
|
|
CertFreeCertificateContext(pca->rgpCerts[i]);
|
|
|
|
pca->cCerts = cauh.cElems;
|
|
for (i = 0; i < cauh.cElems; i++)
|
|
pca->rgpCerts[i] = CertDuplicateCertificateContext(*(PCCERT_CONTEXT *)(&(cauh.pElems[i])));
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_CERTARRAYToCAUH
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::_CERTARRAYToCAUH(const CERTARRAY ca, CAUH *pcauh)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
register DWORD i;
|
|
PCCERT_CONTEXT * rgpccert = NULL;
|
|
|
|
if (ca.cCerts)
|
|
{
|
|
if ((pcauh->pElems = (ULARGE_INTEGER *)g_pMalloc->Alloc(ca.cCerts*sizeof(PCCERT_CONTEXT))))
|
|
{
|
|
pcauh->cElems = ca.cCerts;
|
|
rgpccert = *(PCCERT_CONTEXT **)(&(pcauh->pElems));
|
|
for (i = 0; i < ca.cCerts; i++)
|
|
rgpccert[i] = CertDuplicateCertificateContext(ca.rgpCerts[i]);
|
|
}
|
|
else
|
|
hr = TrapError(E_OUTOFMEMORY);
|
|
}
|
|
else
|
|
{
|
|
pcauh->pElems = NULL;
|
|
pcauh->cElems = 0;
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
#endif // _WIN65
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_CAUHToSTOREARRAY
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::_CAUHToSTOREARRAY(const CAUH cauh, STOREARRAY *psa)
|
|
{
|
|
// Locals
|
|
HRESULT hr;
|
|
register DWORD i;
|
|
|
|
if (SUCCEEDED(hr = HrRealloc((void**)&psa->rgStores, cauh.cElems*sizeof(HCERTSTORE))))
|
|
{
|
|
for (i = 0; i < psa->cStores; i++)
|
|
CertCloseStore(psa->rgStores[i], 0);
|
|
|
|
psa->cStores = cauh.cElems;
|
|
for (i = 0; i < cauh.cElems; i++)
|
|
psa->rgStores[i] = CertDuplicateStore(*(HCERTSTORE *)(&(cauh.pElems[i])));
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_STOREARRAYToCAUH
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::_STOREARRAYToCAUH(const STOREARRAY sa, CAUH *pcauh)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
register DWORD i;
|
|
HCERTSTORE * rgStores = NULL;
|
|
|
|
if (sa.cStores)
|
|
{
|
|
if ((pcauh->pElems = (ULARGE_INTEGER *)g_pMalloc->Alloc(sa.cStores*sizeof(HCERTSTORE))))
|
|
{
|
|
pcauh->cElems = sa.cStores;
|
|
rgStores = *(HCERTSTORE **)(&(pcauh->pElems));
|
|
for (i = 0; i < sa.cStores; i++)
|
|
rgStores[i] = CertDuplicateStore(sa.rgStores[i]);
|
|
}
|
|
else
|
|
hr = TrapError(E_OUTOFMEMORY);
|
|
}
|
|
else
|
|
{
|
|
pcauh->pElems = NULL;
|
|
pcauh->cElems = 0;
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_FreeOptions
|
|
// --------------------------------------------------------------------------------
|
|
void CMessageBody::_FreeOptions()
|
|
{
|
|
DWORD i;
|
|
|
|
if (m_rOptions.cSigners)
|
|
{
|
|
// OID_SECURITY_ALG_HASH
|
|
SafeMemFree(m_rOptions.rgblobHash[0].pBlobData);
|
|
|
|
// OID_SECURITY_CERT_SIGNING
|
|
for (i = 0; i < m_rOptions.cSigners; i++)
|
|
{
|
|
CertFreeCertificateContext(m_rOptions.rgpcCertSigning[i]);
|
|
|
|
#ifdef SMIME_V3
|
|
// Attributes
|
|
SafeMemFree(m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][i]);
|
|
SafeMemFree(m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_UNSIGNED][i]);
|
|
|
|
// OID_SECURITY_RECEIPT_RG
|
|
SafeMemFree(m_rOptions.rgblobReceipt[i].pBlobData);
|
|
// OID_SECURITY_MESSAGE_HASH_RG
|
|
SafeMemFree(m_rOptions.rgblobMsgHash[i].pBlobData);
|
|
// OID_SECURITY_KEY_PROMPT
|
|
SafeMemFree(m_rOptions.pwszKeyPrompt);
|
|
#else // !SMIME_V3
|
|
// OID_SECURITY_SYMCAPS
|
|
SafeMemFree(m_rOptions.rgblobSymCaps[i].pBlobData);
|
|
|
|
// OID_SECURITY_AUTHATTR
|
|
SafeMemFree(m_rOptions.rgblobAuthAttr[i].pBlobData);
|
|
|
|
// OID_SECURITY_UNAUTHATTR
|
|
SafeMemFree(m_rOptions.rgblobUnauthAttr[i].pBlobData);
|
|
#endif // SMIME_V3
|
|
}
|
|
|
|
// OID_SECURITY_HCERTSTORE
|
|
CertCloseStore(m_rOptions.hCertStore, 0);
|
|
|
|
_FreeLayerArrays();
|
|
|
|
if (m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_UNPROTECTED] != NULL) {
|
|
SafeMemFree(m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_UNPROTECTED][0]);
|
|
SafeMemFree(m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_UNPROTECTED]);
|
|
}
|
|
}
|
|
|
|
// OID_SECURITY_ALG_BULK
|
|
SafeMemFree(m_rOptions.blobBulk.pBlobData);
|
|
|
|
// OID_SECURITY_CERT_DECRYPTION
|
|
if (m_rOptions.pcCertDecryption)
|
|
CertFreeCertificateContext(m_rOptions.pcCertDecryption);
|
|
|
|
#ifdef SMIME_V3
|
|
if (m_rOptions.rgRecipients != 0)
|
|
{
|
|
for (i=0; i<m_rOptions.cRecipients; i++)
|
|
{
|
|
FreeRecipientInfoContent(&m_rOptions.rgRecipients[i]);
|
|
}
|
|
}
|
|
SafeMemFree(m_rOptions.rgRecipients);
|
|
m_rOptions.cRecipients = 0;
|
|
m_rOptions.cRecipsAllocated = 0;
|
|
#else // SMIME_V3
|
|
// OID_SECURITY_RG_CERT_ENCRYPT
|
|
for (i=0; i<m_rOptions.caEncrypt.cCerts; i++)
|
|
CertFreeCertificateContext(m_rOptions.caEncrypt.rgpCerts[i]);
|
|
SafeMemFree(m_rOptions.caEncrypt.rgpCerts);
|
|
#endif // !SMIEM_V3
|
|
|
|
// OID_SECURITY_SEARCHSTORES
|
|
for (i=0; i<m_rOptions.saSearchStore.cStores; i++)
|
|
CertCloseStore(m_rOptions.saSearchStore.rgStores[i], 0);
|
|
SafeMemFree(m_rOptions.saSearchStore.rgStores);
|
|
|
|
// OID_SECURITY_RG_IASN
|
|
// nyi
|
|
|
|
// OID_SECURITY_HCRYPTPROV
|
|
if (m_rOptions.hCryptProv)
|
|
CryptReleaseContext(m_rOptions.hCryptProv, 0);
|
|
|
|
return;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
#define REALLOC_AND_INIT_OPTION(Option) \
|
|
if (FAILED(hr = HrRealloc((void**)&Option, LcbAlignLcb(ulLayers * sizeof(*Option))))) { \
|
|
goto exit; \
|
|
} \
|
|
ZeroMemory(&Option[m_rOptions.cSigners], LcbAlignLcb((ulLayersNew) * sizeof(*Option)));
|
|
#else
|
|
#define REALLOC_AND_INIT_OPTION(Option) \
|
|
if (FAILED(hr = HrRealloc((void**)&Option, ulLayers * sizeof(*Option)))) { \
|
|
goto exit; \
|
|
} \
|
|
ZeroMemory(&Option[m_rOptions.cSigners], (ulLayersNew) * sizeof(*Option));
|
|
#endif //_WIN64
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_HrEnsureBodyOptionLayers
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::_HrEnsureBodyOptionLayers(ULONG ulLayers)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG ulLayersNew = ulLayers - m_rOptions.cSigners;
|
|
|
|
if (m_rOptions.cSigners < ulLayers)
|
|
{
|
|
// Time to grow the arrays
|
|
REALLOC_AND_INIT_OPTION(m_rOptions.rgblobHash);
|
|
REALLOC_AND_INIT_OPTION(m_rOptions.rgpcCertSigning);
|
|
#ifdef SMIME_V3
|
|
REALLOC_AND_INIT_OPTION(m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED]);
|
|
REALLOC_AND_INIT_OPTION(m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_UNSIGNED]);
|
|
#else // !SMIME_V3
|
|
REALLOC_AND_INIT_OPTION(m_rOptions.rgblobSymCaps);
|
|
REALLOC_AND_INIT_OPTION(m_rOptions.rgblobAuthAttr);
|
|
REALLOC_AND_INIT_OPTION(m_rOptions.rgblobUnauthAttr);
|
|
REALLOC_AND_INIT_OPTION(m_rOptions.rgftSigning);
|
|
#endif // SMIME_V3
|
|
REALLOC_AND_INIT_OPTION(m_rOptions.rgulUserDef);
|
|
REALLOC_AND_INIT_OPTION(m_rOptions.rgulROValid);
|
|
#ifdef SMIME_V3
|
|
REALLOC_AND_INIT_OPTION(m_rOptions.rgblobReceipt);
|
|
REALLOC_AND_INIT_OPTION(m_rOptions.rgblobMsgHash);
|
|
#endif // SMIME_V3
|
|
|
|
m_rOptions.cSigners = ulLayers;
|
|
}
|
|
|
|
exit:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT CMessageBody::_HrEnsureBodyOptionLayers(LPCPROPVARIANT ppv)
|
|
{
|
|
CAUL * pcaul = (CAUL *)&ppv->caul;
|
|
|
|
return(_HrEnsureBodyOptionLayers(pcaul->cElems));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_HrEnsureBodyOptionLayers
|
|
// --------------------------------------------------------------------------------
|
|
void CMessageBody::_FreeLayerArrays(void)
|
|
{
|
|
if (m_rOptions.cSigners)
|
|
{
|
|
SafeMemFree(m_rOptions.rgblobHash);
|
|
SafeMemFree(m_rOptions.rgpcCertSigning);
|
|
#ifdef SMIME_V3
|
|
SafeMemFree(m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED]);
|
|
SafeMemFree(m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_UNSIGNED]);
|
|
#else // !SMIME_V3
|
|
SafeMemFree(m_rOptions.rgblobSymCaps);
|
|
SafeMemFree(m_rOptions.rgblobAuthAttr);
|
|
SafeMemFree(m_rOptions.rgblobUnauthAttr);
|
|
SafeMemFree(m_rOptions.rgftSigning);
|
|
#endif // SMIME_V3
|
|
SafeMemFree(m_rOptions.rgulUserDef);
|
|
SafeMemFree(m_rOptions.rgulROValid);
|
|
#ifdef SMIME_V3
|
|
SafeMemFree(m_rOptions.rgblobReceipt);
|
|
SafeMemFree(m_rOptions.rgblobMsgHash);
|
|
#endif // SMIME_V3
|
|
m_rOptions.cSigners = 0;
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT CMessageBody::_CompareCopyBlobArray(const PROPVARIANT FAR * pvSource, BLOB FAR * FAR * prgblDestination, BOOL fNoDirty)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG i;
|
|
BOOL fReplace;
|
|
CAPROPVARIANT capropvar = pvSource->capropvar;
|
|
ULONG ulSize = capropvar.cElems;
|
|
|
|
Assert(ulSize == m_rOptions.cSigners);
|
|
Assert(*prgblDestination);
|
|
|
|
if (ulSize == m_rOptions.cSigners)
|
|
{
|
|
for (i = 0; i < ulSize; i++)
|
|
{
|
|
if ((*prgblDestination)[i].pBlobData)
|
|
{
|
|
if (fReplace = CompareBlob(&(*prgblDestination)[i], (BLOB FAR *)&capropvar.pElems[i]))
|
|
{
|
|
ReleaseMem((VOID FAR *)(*prgblDestination)[i].pBlobData);
|
|
}
|
|
} else {
|
|
fReplace = TRUE;
|
|
}
|
|
|
|
if (fReplace)
|
|
{
|
|
if (FAILED(hr = HrCopyBlob(&(capropvar.pElems[i].blob), &(*prgblDestination)[i])))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if (!fNoDirty)
|
|
{
|
|
FLAGSET(m_dwState, BODYSTATE_DIRTY);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
hr = E_INVALIDARG;
|
|
}
|
|
exit:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// HrCopyBlobArray
|
|
//
|
|
// Allocate a new propvariant blob array, copy the original to it.
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT HrCopyBlobArray(LPCBLOB pIn, ULONG cEntries, PROPVARIANT FAR * pvOut)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
CAPROPVARIANT * pcapropvar;
|
|
PROPVARIANT * ppv;
|
|
ULONG i;
|
|
|
|
pvOut->vt = VT_VECTOR | VT_VARIANT;
|
|
pcapropvar = &pvOut->capropvar;
|
|
pcapropvar->cElems = cEntries;
|
|
|
|
if (cEntries)
|
|
{
|
|
Assert(pIn && pvOut);
|
|
|
|
// Allocate the array of VT_BLOB propvariants
|
|
if (FAILED(hr = HrAlloc((LPVOID *)&ppv, cEntries * sizeof(PROPVARIANT))))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
pcapropvar->pElems = ppv;
|
|
|
|
// Fill in the array of BLOBs
|
|
for (i = 0; i < cEntries; i++)
|
|
{
|
|
ppv[i].vt = VT_BLOB;
|
|
// HrCopyBlob allocates memory for the blob data.
|
|
if (FAILED(hr = HrCopyBlob((BLOB FAR *)&pIn[i] , &ppv[i].blob)))
|
|
{
|
|
goto exit;
|
|
}
|
|
}
|
|
} else {
|
|
pcapropvar->pElems = NULL;
|
|
}
|
|
exit:
|
|
// BUGBUG: Should clean up allocations on failure
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// HrCopyArray
|
|
//
|
|
// Allocate a new array, copy the original to it.
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT HrCopyArray(LPBYTE pIn, ULONG cEntries, PROPVARIANT FAR * pvOut, ULONG cbElement)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
BYTE * pb;
|
|
ULONG i;
|
|
ULONG cbArray = cEntries * cbElement;
|
|
CAUL * pcaul = &pvOut->caul;
|
|
|
|
pcaul->cElems = cEntries;
|
|
|
|
if (cEntries)
|
|
{
|
|
Assert(pIn && pvOut);
|
|
|
|
// Allocate the array of VT_BLOB propvariants
|
|
if (FAILED(hr = HrAlloc((LPVOID *)&pb, cbArray)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
pcaul->pElems = (PULONG)pb;
|
|
|
|
// Fill in the array of BLOBs
|
|
memcpy(pb, pIn, cbArray);
|
|
} else {
|
|
pcaul->pElems = NULL;
|
|
}
|
|
exit:
|
|
// BUGBUG: Should clean up allocations on failure
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// HrCopyDwordArray
|
|
//
|
|
// Allocate a new dword array, copy the original to it.
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT HrCopyDwordArray(LPDWORD pIn, ULONG cEntries, PROPVARIANT FAR * pvOut)
|
|
{
|
|
pvOut->vt = VT_VECTOR | VT_UI4;
|
|
return(HrCopyArray((LPBYTE)pIn, cEntries, pvOut, sizeof(DWORD)));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// HrCopyIntoUlonglongArray
|
|
//
|
|
// Allocate a new Ulonglong array, copy the original to it.
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT HrCopyIntoUlonglongArray(ULARGE_INTEGER *pIn, ULONG cEntries, PROPVARIANT FAR * pvOut)
|
|
{
|
|
// Locals
|
|
HRESULT hr = S_OK;
|
|
ULARGE_INTEGER * pullBuff;
|
|
CAUH * pcauh = &pvOut->cauh;
|
|
|
|
pvOut->vt = VT_VECTOR | VT_UI8;
|
|
pcauh->cElems = cEntries;
|
|
|
|
if (cEntries)
|
|
{
|
|
Assert(pIn && pvOut);
|
|
|
|
// Allocate the array of VT_BLOB propvariants
|
|
if (FAILED(hr = HrAlloc((LPVOID *)&pullBuff, cEntries * sizeof(ULARGE_INTEGER *))))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
pcauh->pElems = (ULARGE_INTEGER *) pullBuff;
|
|
|
|
// Fill in the array of BLOBs
|
|
for (; cEntries > 0; cEntries--, pullBuff++, pIn++)
|
|
{
|
|
*pullBuff = *pIn;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pcauh->pElems = NULL;
|
|
}
|
|
exit:
|
|
// BUGBUG: Should clean up allocations on failure
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// HrCopyFiletimeArray
|
|
//
|
|
// Allocate a new filetime array, copy the original to it.
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT HrCopyFiletimeArray(LPFILETIME pIn, ULONG cEntries, PROPVARIANT FAR * pvOut)
|
|
{
|
|
pvOut->vt = VT_VECTOR | VT_FILETIME;
|
|
return(HrCopyArray((LPBYTE)pIn, cEntries, pvOut, sizeof(FILETIME)));
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// MergeDWORDFlags
|
|
//
|
|
// Merge the flags from an array of DWORDs into one DWORD
|
|
// --------------------------------------------------------------------------------
|
|
DWORD MergeDWORDFlags(LPDWORD rgdw, ULONG cEntries)
|
|
{
|
|
DWORD dwReturn = 0;
|
|
|
|
for (ULONG i = 0; i < cEntries; i++)
|
|
{
|
|
dwReturn |= rgdw[i];
|
|
}
|
|
|
|
return(dwReturn);
|
|
}
|
|
|
|
#ifdef SMIME_V3
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::Encode
|
|
// --------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::Encode(HWND hwnd, DWORD dwFlags)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::Decode
|
|
// --------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::Decode(HWND hwnd, DWORD dwFlags, IMimeSecurityCallback * pCallback)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::GetRecipientCount
|
|
// --------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::GetRecipientCount(DWORD dwFlags, DWORD * pdwRecipCount)
|
|
{
|
|
Assert(dwFlags == 0);
|
|
if (dwFlags != 0) return E_INVALIDARG;
|
|
*pdwRecipCount = m_rOptions.cRecipients;
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::AddRecipient
|
|
// --------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::AddRecipient(DWORD dwFlags, DWORD cRecipData,
|
|
PCMS_RECIPIENT_INFO precipData)
|
|
{
|
|
DWORD cbExtra;
|
|
DWORD dw;
|
|
DWORD dwCaps;
|
|
HRESULT hr;
|
|
DWORD i;
|
|
|
|
Assert((dwFlags & ~(SMIME_RECIPIENT_REPLACE_ALL)) == 0);
|
|
if ((dwFlags & (~SMIME_RECIPIENT_REPLACE_ALL)) != 0) return E_INVALIDARG;
|
|
|
|
//
|
|
// Query capabilities
|
|
//
|
|
|
|
CHECKHR(hr = CapabilitiesSupported(&dwCaps));
|
|
|
|
//
|
|
// Start by running the verification code on the structures.
|
|
//
|
|
|
|
for (i=0; i<cRecipData; i++)
|
|
{
|
|
switch(precipData[i].dwRecipientType)
|
|
{
|
|
//
|
|
// If you tell use that you don't know whats going on, then you must
|
|
// 1. Give us a certificate
|
|
// 2. If you don't specify an alg, we must recognize the alg in the cert
|
|
//
|
|
|
|
case CMS_RECIPIENT_INFO_TYPE_UNKNOWN:
|
|
if (precipData[i].pccert == NULL)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
if (precipData[i].KeyEncryptionAlgorithm.pszObjId == NULL)
|
|
{
|
|
hr = _HrMapPublicKeyAlg(&precipData[i].pccert->pCertInfo->SubjectPublicKeyInfo,
|
|
&dw, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if (dw == CMS_RECIPIENT_INFO_TYPE_KEYTRANS) {
|
|
;
|
|
}
|
|
else if (dw == CMS_RECIPIENT_INFO_TYPE_KEYAGREE) {
|
|
if (!(dwCaps & SMIME_SUPPORT_KEY_AGREE)) {
|
|
return MIME_E_SECURITY_NOTIMPLEMENTED;
|
|
}
|
|
}
|
|
else {
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
break;
|
|
|
|
//
|
|
// We have no requirements here.
|
|
//
|
|
case CMS_RECIPIENT_INFO_TYPE_KEYTRANS:
|
|
break;
|
|
|
|
case CMS_RECIPIENT_INFO_TYPE_KEYAGREE:
|
|
if (!(dwCaps & SMIME_SUPPORT_KEY_AGREE)) {
|
|
return MIME_E_SECURITY_NOTIMPLEMENTED;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// If you give use a mail list key, you must also tell us the
|
|
// public key identifier and the mail list key or we are going
|
|
// to fail big time
|
|
//
|
|
|
|
case CMS_RECIPIENT_INFO_TYPE_MAIL_LIST:
|
|
if (!(dwCaps & SMIME_SUPPORT_MAILLIST)) {
|
|
return MIME_E_SECURITY_NOTIMPLEMENTED;
|
|
}
|
|
if ((precipData[i].dwU1 != CMS_RECIPIENT_INFO_PUBKEY_PROVIDER) ||
|
|
(precipData[i].dwU3 != CMS_RECIPIENT_INFO_KEYID_KEY_ID))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Assert(FALSE);
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
|
|
if (dwFlags & SMIME_RECIPIENT_REPLACE_ALL)
|
|
{
|
|
for (i=0; i<m_rOptions.cRecipients; i++)
|
|
{
|
|
FreeRecipientInfoContent(&m_rOptions.rgRecipients[i]);
|
|
}
|
|
m_rOptions.cRecipients = 0;
|
|
}
|
|
|
|
//
|
|
|
|
Assert(m_rOptions.cRecipients <= m_rOptions.cRecipsAllocated);
|
|
if (m_rOptions.cRecipients >= m_rOptions.cRecipsAllocated)
|
|
{
|
|
hr = HrRealloc((LPVOID *) &m_rOptions.rgRecipients,
|
|
(m_rOptions.cRecipsAllocated+cRecipData+5)*sizeof(CMS_RECIPIENT_INFO));
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
m_rOptions.cRecipsAllocated += 5 + cRecipData;
|
|
}
|
|
|
|
//
|
|
// Do the actual copy of the data
|
|
//
|
|
|
|
CHECKHR(hr = _HrCopyRecipInfos(cRecipData, precipData,
|
|
&m_rOptions.rgRecipients[m_rOptions.cRecipients]));
|
|
|
|
m_rOptions.cRecipients += cRecipData;
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// CMessageBody::_HrMapPublicKeyAlg
|
|
// ------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::_HrMapPublicKeyAlg(CERT_PUBLIC_KEY_INFO * pkey, DWORD * pdw,
|
|
CRYPT_ALGORITHM_IDENTIFIER ** ppalg)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
static CRYPT_ALGORITHM_IDENTIFIER rgAlgs[] = {
|
|
{szOID_RSA_RSA, {0, 0}},
|
|
{szOID_RSA_SMIMEalgESDH, {0, 0}}
|
|
};
|
|
|
|
if (lstrcmp(pkey->Algorithm.pszObjId, szOID_RSA_RSA) == 0)
|
|
{
|
|
*pdw = CMS_RECIPIENT_INFO_TYPE_KEYTRANS;
|
|
if (ppalg != NULL)
|
|
{
|
|
*ppalg = &rgAlgs[0];
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
else if (lstrcmp(pkey->Algorithm.pszObjId, szOID_ANSI_X942_DH) == 0)
|
|
{
|
|
*pdw = CMS_RECIPIENT_INFO_TYPE_KEYAGREE;
|
|
if (ppalg != NULL)
|
|
{
|
|
*ppalg = &rgAlgs[1];
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
else {
|
|
*pdw = CMS_RECIPIENT_INFO_TYPE_UNKNOWN;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// CMessageBody::_HrCopyRecipInfos
|
|
// ------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::_HrCopyRecipInfos(DWORD cItems,
|
|
const CMS_RECIPIENT_INFO * precipSrc,
|
|
PCMS_RECIPIENT_INFO precipDst)
|
|
{
|
|
DWORD cb;
|
|
DWORD dw;
|
|
HRESULT hr;
|
|
DWORD i;
|
|
CRYPT_ALGORITHM_IDENTIFIER * palg;
|
|
|
|
memset(precipDst, 0, cItems*sizeof(*precipDst));
|
|
|
|
for (i=0; i<cItems; i++, precipSrc++, precipDst++)
|
|
{
|
|
//
|
|
// Now copy over the information
|
|
//
|
|
|
|
precipDst->dwRecipientType = precipSrc->dwRecipientType;
|
|
|
|
if (precipSrc->pccert != NULL)
|
|
{
|
|
precipDst->pccert = CertDuplicateCertificateContext(
|
|
(PCCERT_CONTEXT) precipSrc->pccert);
|
|
}
|
|
|
|
// Move over the key encryption alg if it exists
|
|
|
|
if (precipSrc->KeyEncryptionAlgorithm.pszObjId != NULL)
|
|
{
|
|
CHECKHR(hr = HrCopyOID(precipSrc->KeyEncryptionAlgorithm.pszObjId,
|
|
&precipDst->KeyEncryptionAlgorithm.pszObjId));
|
|
CHECKHR(hr = HrCopyCryptDataBlob(&precipSrc->KeyEncryptionAlgorithm.Parameters,
|
|
&precipDst->KeyEncryptionAlgorithm.Parameters));
|
|
}
|
|
else {
|
|
//
|
|
// If the data does not exist, then we need to create the data
|
|
// from scratch. We do this by pulling information out of the
|
|
// certificate and create the algorithm information about this.
|
|
//
|
|
// Maps RSA->RSA; DH -> smimeAlgESDH
|
|
//
|
|
|
|
Assert(precipSrc->pccert != NULL);
|
|
hr = _HrMapPublicKeyAlg(&precipDst->pccert->pCertInfo->SubjectPublicKeyInfo,
|
|
&dw, &palg);
|
|
Assert(hr == S_OK);
|
|
precipDst->dwRecipientType = dw;
|
|
|
|
CHECKHR(hr = HrCopyCryptAlgorithm(palg, &precipDst->KeyEncryptionAlgorithm));
|
|
}
|
|
|
|
//
|
|
// Move over the aux encryption info if it exists. The length has already
|
|
// been copied over
|
|
//
|
|
|
|
if (precipSrc->cbKeyEncryptionAuxInfo != 0)
|
|
{
|
|
CHECKHR(hr = HrAlloc(&precipDst->pvKeyEncryptionAuxInfo,
|
|
precipSrc->cbKeyEncryptionAuxInfo));
|
|
}
|
|
|
|
//
|
|
// Copy over the subject key id information
|
|
//
|
|
|
|
precipDst->dwU1 = precipSrc->dwU1;
|
|
switch (precipSrc->dwU1)
|
|
{
|
|
case CMS_RECIPIENT_INFO_PUBKEY_CERTIFICATE:
|
|
if (precipDst->dwRecipientType == CMS_RECIPIENT_INFO_TYPE_KEYTRANS)
|
|
{
|
|
precipDst->dwU1 = CMS_RECIPIENT_INFO_PUBKEY_KEYTRANS;
|
|
|
|
CHECKHR(hr = HrCopyCryptBitBlob(
|
|
&precipSrc->pccert->pCertInfo->SubjectPublicKeyInfo.PublicKey,
|
|
&precipDst->u1.SubjectPublicKey));
|
|
|
|
}
|
|
else if (precipDst->dwRecipientType == CMS_RECIPIENT_INFO_TYPE_KEYAGREE)
|
|
{
|
|
precipDst->dwU1 = CMS_RECIPIENT_INFO_PUBKEY_EPHEMERAL_KEYAGREE;
|
|
|
|
CHECKHR(hr = HrCopyCryptBitBlob(
|
|
&precipSrc->pccert->pCertInfo->SubjectPublicKeyInfo.PublicKey,
|
|
&precipDst->u1.u3.SubjectPublicKey));
|
|
|
|
// precipDst->u1.u3.UserKeyingMaterial = NULL;
|
|
|
|
CHECKHR(hr = HrCopyCryptAlgorithm(
|
|
&precipSrc->pccert->pCertInfo->SubjectPublicKeyInfo.Algorithm,
|
|
&precipDst->u1.u3.EphemeralAlgorithm));
|
|
}
|
|
else {
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
case CMS_RECIPIENT_INFO_PUBKEY_KEYTRANS:
|
|
CHECKHR(hr = HrCopyCryptBitBlob(&precipSrc->u1.SubjectPublicKey,
|
|
&precipDst->u1.SubjectPublicKey));
|
|
break;
|
|
|
|
case CMS_RECIPIENT_INFO_PUBKEY_EPHEMERAL_KEYAGREE:
|
|
CHECKHR(hr = HrCopyCryptDataBlob(&precipSrc->u1.u3.UserKeyingMaterial,
|
|
&precipDst->u1.u3.UserKeyingMaterial));
|
|
CHECKHR(hr = HrCopyCryptAlgorithm(&precipSrc->u1.u3.EphemeralAlgorithm,
|
|
&precipDst->u1.u3.EphemeralAlgorithm));
|
|
CHECKHR(hr = HrCopyCryptBitBlob(&precipSrc->u1.u3.SubjectPublicKey,
|
|
&precipDst->u1.u3.SubjectPublicKey));
|
|
break;
|
|
|
|
case CMS_RECIPIENT_INFO_PUBKEY_STATIC_KEYAGREE:
|
|
CHECKHR(hr = HrCopyCryptDataBlob(&precipSrc->u1.u4.UserKeyingMaterial,
|
|
&precipDst->u1.u4.UserKeyingMaterial));
|
|
if (!CryptContextAddRef(precipSrc->u1.u4.hprov, 0, 0))
|
|
{
|
|
hr = HrGetLastError();
|
|
goto exit;
|
|
}
|
|
precipDst->u1.u4.hprov = precipSrc->u1.u4.hprov;
|
|
precipDst->u1.u4.dwKeySpec = precipSrc->u1.u4.dwKeySpec;
|
|
CHECKHR(hr = HrCopyCertId(&precipSrc->u1.u4.senderCertId,
|
|
&precipDst->u1.u4.senderCertId));
|
|
CHECKHR(hr = HrCopyCryptBitBlob(&precipSrc->u1.u4.SubjectPublicKey,
|
|
&precipDst->u1.u4.SubjectPublicKey));
|
|
break;
|
|
|
|
// hprov & hkey are already copied over
|
|
case CMS_RECIPIENT_INFO_PUBKEY_PROVIDER:
|
|
if (!CryptContextAddRef(precipDst->u1.u2.hprov, 0, 0))
|
|
{
|
|
hr = HrGetLastError();
|
|
goto exit;
|
|
}
|
|
precipDst->u1.u2.hprov = precipSrc->u1.u2.hprov;
|
|
if (!CryptDuplicateKey(precipSrc->u1.u2.hkey, 0, 0,
|
|
&precipDst->u1.u2.hkey))
|
|
{
|
|
hr = HrGetLastError();
|
|
goto exit;
|
|
}
|
|
precipDst->u1.u2.hkey = precipSrc->u1.u2.hkey;
|
|
break;
|
|
}
|
|
|
|
precipDst->dwU3 = precipSrc->dwU3;
|
|
switch (precipSrc->dwU3)
|
|
{
|
|
case CMS_RECIPIENT_INFO_KEYID_CERTIFICATE:
|
|
precipDst->dwU3 = CMS_RECIPIENT_INFO_KEYID_ISSUERSERIAL;
|
|
CHECKHR(hr = HrCopyCryptDataBlob(&precipSrc->pccert->pCertInfo->Issuer,
|
|
&precipDst->u3.IssuerSerial.Issuer));
|
|
CHECKHR(hr = HrCopyCryptDataBlob(&precipSrc->pccert->pCertInfo->SerialNumber,
|
|
&precipDst->u3.IssuerSerial.SerialNumber));
|
|
break;
|
|
|
|
case CMS_RECIPIENT_INFO_KEYID_ISSUERSERIAL:
|
|
CHECKHR(hr = HrCopyCryptDataBlob( &precipSrc->u3.IssuerSerial.Issuer,
|
|
&precipDst->u3.IssuerSerial.Issuer));
|
|
CHECKHR(hr = HrCopyCryptDataBlob( &precipSrc->u3.IssuerSerial.SerialNumber,
|
|
&precipDst->u3.IssuerSerial.SerialNumber));
|
|
break;
|
|
|
|
case CMS_RECIPIENT_INFO_KEYID_KEY_ID:
|
|
CHECKHR(hr = HrCopyCryptDataBlob(&precipSrc->u3.KeyId, &precipDst->u3.KeyId));
|
|
break;
|
|
}
|
|
|
|
precipDst->filetime = precipSrc->filetime;
|
|
if (precipSrc->pOtherAttr != NULL)
|
|
{
|
|
Assert(FALSE);
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// CMessageBody::GetRecipient
|
|
// ------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::GetRecipient(DWORD dwFlags, DWORD iRecipient, DWORD cRecipients, PCMS_RECIPIENT_INFO pRecipData)
|
|
{
|
|
DWORD cbAlloc;
|
|
HRESULT hr;
|
|
LPBYTE pb;
|
|
PCMS_RECIPIENT_INFO precip;
|
|
|
|
if (iRecipient+cRecipients > m_rOptions.cRecipients)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto exit;
|
|
}
|
|
|
|
precip = &m_rOptions.rgRecipients[iRecipient];
|
|
|
|
//
|
|
// Copy the buffer
|
|
//
|
|
|
|
CHECKHR(hr = _HrCopyRecipInfos(cRecipients, precip, pRecipData));
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::DeleteRecipient
|
|
// --------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::DeleteRecipient(DWORD dwFlags, DWORD iRecipient, DWORD cRecipients)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::GetAttribute
|
|
// --------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::GetAttribute(DWORD dwFlags, DWORD iSigner, DWORD iAttribSet,
|
|
DWORD iInstance, LPCSTR pszObjId,
|
|
CRYPT_ATTRIBUTE ** ppattr)
|
|
{
|
|
DWORD cb;
|
|
HRESULT hr;
|
|
DWORD i;
|
|
DWORD i1;
|
|
PCRYPT_ATTRIBUTE pattr = NULL;
|
|
PCRYPT_ATTRIBUTES pattrs;
|
|
PCRYPT_ATTRIBUTE pattrSrc;
|
|
LPBYTE pb;
|
|
LPBLOB pblob;
|
|
|
|
//
|
|
// Start with some simple parameter checks
|
|
//
|
|
|
|
if ( // (iAttribSet < SMIME_ATTRIBUTE_SET_SIGNED) ||
|
|
(iAttribSet > SMIME_ATTRIBUTE_SET_UNPROTECTED))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (dwFlags & ~(SMIME_RECIPIENT_REPLACE_ALL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (iAttribSet == SMIME_ATTRIBUTE_SET_UNPROTECTED)
|
|
{
|
|
if ((iSigner != 0) || !g_FSupportV3)
|
|
return E_INVALIDARG;
|
|
if (m_rOptions.rgrgpattrs[iAttribSet] == NULL)
|
|
return S_FALSE;
|
|
}
|
|
else if (iSigner >= m_rOptions.cSigners)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Special case of getting every single attribute on record
|
|
//
|
|
|
|
if (pszObjId == NULL) {
|
|
if (!CryptEncodeObjectEx(X509_ASN_ENCODING,
|
|
szOID_Microsoft_Attribute_Sequence,
|
|
m_rOptions.rgrgpattrs[iAttribSet][iSigner],
|
|
0, NULL, NULL, &cb))
|
|
{
|
|
hr = HrGetLastError();
|
|
goto exit;
|
|
}
|
|
|
|
if (!MemAlloc((LPVOID *) &pattr, cb + sizeof(CRYPT_ATTRIBUTE) +
|
|
sizeof(CRYPT_ATTR_BLOB))) {
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
pattr->cValue = 1;
|
|
pattr->rgValue = (PCRYPT_ATTR_BLOB) &pattr[1];
|
|
pb = (LPBYTE) &pattr->rgValue[1];
|
|
|
|
pattr->pszObjId = NULL;
|
|
pattr->rgValue[0].pbData = pb;
|
|
pattr->rgValue[0].cbData = cb;
|
|
|
|
if (!CryptEncodeObjectEx(X509_ASN_ENCODING,
|
|
szOID_Microsoft_Attribute_Sequence,
|
|
m_rOptions.rgrgpattrs[iAttribSet][iSigner],
|
|
0, NULL, pb, &cb))
|
|
{
|
|
hr = HrGetLastError();
|
|
goto exit;
|
|
}
|
|
|
|
*ppattr = pattr;
|
|
pattr = NULL;
|
|
hr = S_OK;
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
//
|
|
|
|
pattrSrc = _FindAttribute(m_rOptions.rgrgpattrs[iAttribSet][iSigner], pszObjId,
|
|
iInstance);
|
|
if (pattrSrc != NULL)
|
|
{
|
|
#ifdef _WIN64
|
|
cb = sizeof(CRYPT_ATTRIBUTE) + LcbAlignLcb(strlen(pszObjId) + 1);
|
|
#else
|
|
cb = sizeof(CRYPT_ATTRIBUTE) + strlen(pszObjId) + 1;
|
|
#endif
|
|
for (i1=0; i1<pattrSrc->cValue; i1++)
|
|
{
|
|
cb += sizeof(CRYPT_ATTR_BLOB);
|
|
#ifdef _WIN64
|
|
cb += LcbAlignLcb(pattrSrc->rgValue[i1].cbData);
|
|
#else
|
|
cb += pattrSrc->rgValue[i1].cbData;
|
|
#endif
|
|
}
|
|
|
|
if (!MemAlloc((LPVOID *) &pattr, cb))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
pattr->cValue = pattrSrc->cValue;
|
|
pattr->rgValue = (PCRYPT_ATTR_BLOB) &pattr[1];
|
|
pb = (LPBYTE) &pattr->rgValue[pattrSrc->cValue];
|
|
|
|
pattr->pszObjId = (LPSTR) pb;
|
|
cb = strlen(pszObjId)+1;
|
|
memcpy(pattr->pszObjId, pszObjId, cb);
|
|
#ifdef _WIN64
|
|
pb += LcbAlignLcb(cb);
|
|
#else
|
|
pb += cb;
|
|
#endif //_WIN64
|
|
|
|
for (i1=0; i1<pattrSrc->cValue; i1++)
|
|
{
|
|
pattr->rgValue[i1].pbData = pb;
|
|
pattr->rgValue[i1].cbData = pattrSrc->rgValue[i1].cbData;
|
|
memcpy(pb, pattrSrc->rgValue[i1].pbData,
|
|
pattrSrc->rgValue[i1].cbData);
|
|
#ifdef _WIN64
|
|
pb += LcbAlignLcb(pattrSrc->rgValue[i1].cbData);
|
|
#else
|
|
pb += pattrSrc->rgValue[i1].cbData;
|
|
#endif //_WIN64
|
|
}
|
|
|
|
*ppattr = pattr;
|
|
pattr = NULL;
|
|
hr = S_OK;
|
|
}
|
|
else {
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
exit:
|
|
if (pattr != NULL) MemFree(pattr);
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::SetAttribute
|
|
// --------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::SetAttribute(DWORD dwFlags, DWORD iSigner, DWORD iAttribSet,
|
|
const CRYPT_ATTRIBUTE * pattr)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
|
|
//
|
|
// Start with some simple parameter checks
|
|
//
|
|
|
|
if (// (iAttribSet < SMIME_ATTRIBUTE_SET_SIGNED) ||
|
|
(iAttribSet > SMIME_ATTRIBUTE_SET_UNPROTECTED))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (dwFlags & ~(SMIME_ATTR_ADD_TO_EXISTING |
|
|
SMIME_ATTR_ADD_IF_NOT_EXISTS))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (iAttribSet == SMIME_ATTRIBUTE_SET_UNPROTECTED) {
|
|
if ((iSigner != 0) || !g_FSupportV3)
|
|
return E_INVALIDARG;
|
|
|
|
if (m_rOptions.rgrgpattrs[iAttribSet] == NULL) {
|
|
if (!MemAlloc((LPVOID *) &m_rOptions.rgrgpattrs[iAttribSet],
|
|
sizeof(LPVOID))) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
m_rOptions.rgrgpattrs[iAttribSet][0] = NULL;
|
|
}
|
|
}
|
|
else if ((iSigner >= m_rOptions.cSigners) && (iSigner != (DWORD) -1))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Now make the correct utility call to put things right
|
|
//
|
|
|
|
Assert(pattr->cValue == 1);
|
|
|
|
if (iSigner == (DWORD) -1)
|
|
{
|
|
Assert(iAttribSet != SMIME_ATTRIBUTE_SET_UNPROTECTED);
|
|
|
|
for (i=0; i<m_rOptions.cSigners; i++)
|
|
{
|
|
hr = _HrSetAttribute(dwFlags, &m_rOptions.rgrgpattrs[iAttribSet][i],
|
|
pattr->pszObjId, pattr->rgValue[0].cbData,
|
|
pattr->rgValue[0].pbData);
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
hr = _HrSetAttribute(dwFlags, &m_rOptions.rgrgpattrs[iAttribSet][iSigner],
|
|
pattr->pszObjId, pattr->rgValue[0].cbData,
|
|
pattr->rgValue[0].pbData);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::DeleteAttribute
|
|
// --------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::DeleteAttribute(DWORD dwFlags, DWORD iSigner,
|
|
DWORD iAttribSet, DWORD iInstance,
|
|
LPCSTR pszObjId)
|
|
{
|
|
UINT i;
|
|
PCRYPT_ATTRIBUTE pattr;
|
|
PCRYPT_ATTRIBUTES pattrs;
|
|
|
|
//
|
|
// Start with some simple parameter checks
|
|
//
|
|
|
|
if (// (iAttribSet < SMIME_ATTRIBUTE_SET_SIGNED) ||
|
|
(iAttribSet > SMIME_ATTRIBUTE_SET_UNPROTECTED))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (dwFlags & ~(SMIME_RECIPIENT_REPLACE_ALL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (iAttribSet == SMIME_ATTRIBUTE_SET_UNPROTECTED) {
|
|
if ((iSigner != 0) || !g_FSupportV3)
|
|
return E_INVALIDARG;
|
|
if (m_rOptions.rgrgpattrs[iAttribSet] == NULL)
|
|
return S_OK;
|
|
}
|
|
else if (iSigner >= m_rOptions.cSigners)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
|
|
pattrs = m_rOptions.rgrgpattrs[iAttribSet][iSigner];
|
|
|
|
pattr = _FindAttribute(pattrs, pszObjId, iInstance);
|
|
if (pattr != NULL)
|
|
{
|
|
i = (UINT) (pattr - &pattrs->rgAttr[0]);
|
|
Assert( (0 <= ((int) i)) && (((int) i) < pattrs->cAttr));
|
|
memcpy(pattr, pattr+1, (pattrs->cAttr - i - 1) * sizeof(CRYPT_ATTRIBUTE));
|
|
pattrs->cAttr -= 1;
|
|
}
|
|
else {
|
|
return S_FALSE;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CMessageBody::_SetNames(ReceiptNames * pnames, DWORD cNames, CERT_NAME_BLOB * rgNames)
|
|
{
|
|
DWORD cb;
|
|
HRESULT hr = S_OK;
|
|
DWORD i;
|
|
LPBYTE pb;
|
|
|
|
if (pnames->rgNames != NULL)
|
|
{
|
|
MemFree(pnames->rgNames);
|
|
pnames->rgNames = NULL;
|
|
pnames->cNames = 0;
|
|
}
|
|
|
|
for (i=0, cb=cNames*sizeof(CERT_NAME_BLOB); i<cNames; i++)
|
|
#ifdef _WIN64
|
|
cb += LcbAlignLcb(rgNames[i].cbData);
|
|
#else
|
|
cb += rgNames[i].cbData;
|
|
#endif //_WIN64
|
|
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pnames->rgNames, cb));
|
|
|
|
pb = (LPBYTE) &pnames->rgNames[cNames];
|
|
for (i=0; i<cNames; i++)
|
|
{
|
|
pnames->rgNames[i].pbData = pb;
|
|
pnames->rgNames[i].cbData = rgNames[i].cbData;
|
|
memcpy(pb, rgNames[i].pbData, rgNames[i].cbData);
|
|
#ifdef _WIN64
|
|
pb += LcbAlignLcb(rgNames[i].cbData);
|
|
#else
|
|
pb += rgNames[i].cbData;
|
|
#endif //_WIN64
|
|
}
|
|
|
|
pnames->cNames = cNames;
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CMessageBody::_MergeNames(ReceiptNames * pnames, DWORD cNames, CERT_NAME_BLOB * rgNames)
|
|
{
|
|
DWORD cb;
|
|
HRESULT hr = S_OK;
|
|
DWORD i;
|
|
DWORD i1;
|
|
LPBYTE pb;
|
|
CERT_NAME_BLOB * p;
|
|
|
|
for (i=0, cb=0; i<pnames->cNames; i++)
|
|
#ifdef _WIN64
|
|
cb += LcbAlignLcb(pnames->rgNames[i].cbData);
|
|
#else
|
|
cb += pnames->rgNames[i].cbData;
|
|
#endif //_WIN64
|
|
|
|
for (i=0; i<cNames; i++)
|
|
#ifdef _WIN64
|
|
cb += LcbAlignLcb(rgNames[i].cbData);
|
|
#else
|
|
cb += rgNames[i].cbData;
|
|
#endif //_WIN64
|
|
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&p, cb + (pnames->cNames + cNames) *
|
|
sizeof(CERT_NAME_BLOB)));
|
|
|
|
pb = (LPBYTE) &p[pnames->cNames + cNames];
|
|
for (i=0, i1=0; i<pnames->cNames; i++, i1++)
|
|
{
|
|
p[i1].pbData = pb;
|
|
p[i1].cbData = pnames->rgNames[i].cbData;
|
|
memcpy(pb, pnames->rgNames[i].pbData, pnames->rgNames[i].cbData);
|
|
#ifdef _WIN64
|
|
pb += LcbAlignLcb(pnames->rgNames[i].cbData);
|
|
#else
|
|
pb += pnames->rgNames[i].cbData;
|
|
#endif //_WIN64
|
|
}
|
|
|
|
for (i=0; i<pnames->cNames; i++, i1++)
|
|
{
|
|
p[i1].pbData = pb;
|
|
p[i1].cbData = rgNames[i].cbData;
|
|
memcpy(pb, rgNames[i].pbData, rgNames[i].cbData);
|
|
#ifdef _WIN64
|
|
pb += LcbAlignLcb(rgNames[i].cbData);
|
|
#else
|
|
pb += rgNames[i].cbData;
|
|
#endif //_WIN64
|
|
}
|
|
|
|
MemFree(pnames->rgNames);
|
|
pnames->rgNames = p;
|
|
pnames->cNames = i1;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
//--------------------------------------------------------------------------------
|
|
// CMessageBody::_GetReceiptRequest
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::_GetReceiptRequest(DWORD dwFlags,
|
|
PSMIME_RECEIPT_REQUEST *ppreq,
|
|
ReceiptNames *pReceiptsTo,
|
|
DWORD *pcbReceipt,
|
|
LPBYTE *ppbReceipt,
|
|
DWORD *pcbMsgHash,
|
|
LPBYTE *ppbMsgHash)
|
|
{
|
|
DWORD cb;
|
|
DWORD cbMLHistory = 0;
|
|
DWORD cbMsgHash = 0;
|
|
DWORD cbReceipt = 0;
|
|
DWORD cSendersList = 0;
|
|
DWORD dwReciptsFrom;
|
|
HRESULT hr = S_OK;
|
|
DWORD i;
|
|
DWORD iAttr;
|
|
DWORD iSigner;
|
|
PCRYPT_ATTRIBUTES pattrs = NULL;
|
|
LPBYTE pb;
|
|
LPBYTE pbMLHistory = NULL;
|
|
LPBYTE pbMsgHash = NULL;
|
|
LPBYTE pbReceipt = NULL;
|
|
PSMIME_RECEIPT_REQUEST preq = NULL;
|
|
ReceiptNames receiptsTo = {0, NULL};
|
|
CERT_NAME_BLOB *rgSendersList = NULL;
|
|
PROPVARIANT var;
|
|
|
|
*ppreq = NULL;
|
|
if (pReceiptsTo != NULL)
|
|
{
|
|
pReceiptsTo->cNames = 0;
|
|
pReceiptsTo->rgNames = NULL;
|
|
}
|
|
if (pcbReceipt != NULL) *pcbReceipt = 0;
|
|
if (ppbReceipt != NULL) *ppbReceipt = NULL;
|
|
Assert(((pcbReceipt == NULL) && (ppbReceipt == NULL)) ||
|
|
((pcbReceipt != NULL) && (ppbReceipt != NULL)));
|
|
if (pcbMsgHash != NULL) *pcbMsgHash = 0;
|
|
if (ppbMsgHash != NULL) *ppbMsgHash = NULL;
|
|
Assert(((pcbMsgHash == NULL) && (ppbMsgHash == NULL)) ||
|
|
((pcbMsgHash != NULL) && (ppbMsgHash != NULL)));
|
|
|
|
//
|
|
// If this is the bottom layer then
|
|
// find and Decode Receipt Request
|
|
// Set ReceiptsTo from the request
|
|
// if not then
|
|
// check lower layers
|
|
// if mlExpansion in this layer? No -- Skip to next layer
|
|
// Receipt for First Tier only? Yes - return S_FALSE
|
|
// Policy override on mlExpansion?
|
|
// None - return S_FALSE
|
|
// return S_OK
|
|
|
|
// If this is not the bottom layer then look for MLHistory
|
|
if (IsContentType(STR_CNT_MULTIPART, "y-security") == S_OK)
|
|
{
|
|
Assert(m_pNode->cChildren == 1);
|
|
|
|
hr = m_pNode->pChildHead->pBody->_GetReceiptRequest(
|
|
dwFlags,
|
|
&preq,
|
|
(pReceiptsTo) ? &receiptsTo : NULL,
|
|
(pcbReceipt) ? &cbReceipt : NULL,
|
|
(ppbReceipt) ? &pbReceipt : NULL,
|
|
(pcbMsgHash) ? &cbMsgHash : NULL,
|
|
(ppbMsgHash) ? &pbMsgHash : NULL);
|
|
if (hr)
|
|
goto exit;
|
|
|
|
//
|
|
// Walk through each signer's authenticated attributes processing the
|
|
// relevant attribute.
|
|
//
|
|
|
|
for (iSigner=0; iSigner<m_rOptions.cSigners; iSigner++)
|
|
{
|
|
//
|
|
// Walk through each attribute looking for
|
|
// a Mail List expansion history
|
|
//
|
|
|
|
pattrs = m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][iSigner];
|
|
for (iAttr=0; iAttr<pattrs->cAttr; iAttr++)
|
|
{
|
|
if (lstrcmp(pattrs->rgAttr[iAttr].pszObjId,
|
|
szOID_SMIME_MLExpansion_History) == 0)
|
|
{
|
|
//
|
|
// If receipts are from first tier only and we are at
|
|
// this layer then we are not first tier by definition.
|
|
//
|
|
if (preq->ReceiptsFrom.AllOrFirstTier == SMIME_RECEIPTS_FROM_FIRST_TIER)
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
if (cbMLHistory == 0)
|
|
{
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pbMLHistory,
|
|
pattrs->rgAttr[iAttr].rgValue[0].cbData));
|
|
memcpy(pbMLHistory,pattrs->rgAttr[iAttr].rgValue[0].pbData,
|
|
pattrs->rgAttr[iAttr].rgValue[0].cbData);
|
|
cbMLHistory = pattrs->rgAttr[iAttr].rgValue[0].cbData;
|
|
}
|
|
else if ((pattrs->rgAttr[iAttr].rgValue[0].cbData != cbMLHistory) ||
|
|
(memcmp(pattrs->rgAttr[iAttr].rgValue[0].pbData,
|
|
pbMLHistory, cbMLHistory)))
|
|
{
|
|
// Hey, all MLHistorys should match
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Decode and respect the MLHistory
|
|
if (cbMLHistory != 0)
|
|
{
|
|
PSMIME_ML_EXPANSION_HISTORY pmlhist = NULL;
|
|
|
|
//
|
|
// Crack the attribute
|
|
//
|
|
|
|
if (!CryptDecodeObjectEx(X509_ASN_ENCODING,
|
|
szOID_SMIME_MLExpansion_History,
|
|
pbMLHistory,
|
|
cbMLHistory,
|
|
CRYPT_ENCODE_ALLOC_FLAG,
|
|
&CryptDecodeAlloc, &pmlhist, &cb))
|
|
goto GeneralFail;
|
|
|
|
PSMIME_MLDATA pMLData = &pmlhist->rgMLData[pmlhist->cMLData-1];
|
|
|
|
switch( pMLData->dwPolicy)
|
|
{
|
|
// No receipt is to be returned
|
|
case SMIME_MLPOLICY_NONE:
|
|
hr = S_FALSE;
|
|
SafeMemFree(pmlhist);
|
|
goto exit;
|
|
|
|
// Return receipt to a new list
|
|
case SMIME_MLPOLICY_INSTEAD_OF:
|
|
if (pReceiptsTo != NULL)
|
|
_SetNames(&receiptsTo, pMLData->cNames, pMLData->rgNames);
|
|
break;
|
|
|
|
case SMIME_MLPOLICY_IN_ADDITION_TO:
|
|
if (pReceiptsTo != NULL)
|
|
_MergeNames(&receiptsTo, pMLData->cNames, pMLData->rgNames);
|
|
break;
|
|
|
|
case SMIME_MLPOLICY_NO_CHANGE:
|
|
break;
|
|
|
|
default:
|
|
SafeMemFree(pmlhist);
|
|
goto GeneralFail;
|
|
}
|
|
|
|
SafeMemFree(pmlhist);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Else this is the bottom layer so look for receipt request
|
|
|
|
//
|
|
// Walk through each signer's authenticated attributes processing the
|
|
// two relevant attributes.
|
|
//
|
|
|
|
for (iSigner=0; iSigner<m_rOptions.cSigners; iSigner++)
|
|
{
|
|
// Check if receipt was created for this signer if not then
|
|
// it's signature must have been bad or it had not request
|
|
if (m_rOptions.rgblobReceipt[iSigner].cbSize == 0)
|
|
continue;
|
|
|
|
// if we have a receipt we should also have a message hash
|
|
if (m_rOptions.rgblobMsgHash[iSigner].cbSize == 0)
|
|
{
|
|
Assert(FALSE);
|
|
continue;
|
|
}
|
|
|
|
if (m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][iSigner] == NULL)
|
|
{
|
|
// Hey how did we get a receipt without any attributes
|
|
Assert(FALSE);
|
|
goto GeneralFail;
|
|
}
|
|
|
|
pattrs = m_rOptions.rgrgpattrs[SMIME_ATTRIBUTE_SET_SIGNED][iSigner];
|
|
|
|
//
|
|
// Walk through each attribute looking for the receipt request
|
|
//
|
|
|
|
for (iAttr=0; iAttr<pattrs->cAttr; iAttr++)
|
|
{
|
|
if (lstrcmp(pattrs->rgAttr[iAttr].pszObjId,
|
|
szOID_SMIME_MLExpansion_History) == 0)
|
|
{
|
|
// We are at the bottom so we should not have found a ML History
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
if (lstrcmp(pattrs->rgAttr[iAttr].pszObjId,
|
|
szOID_SMIME_Receipt_Request) == 0)
|
|
{
|
|
//
|
|
// Crack the contents of the receipt request
|
|
//
|
|
|
|
if (!CryptDecodeObjectEx(X509_ASN_ENCODING,
|
|
szOID_SMIME_Receipt_Request,
|
|
pattrs->rgAttr[iAttr].rgValue[0].pbData,
|
|
pattrs->rgAttr[iAttr].rgValue[0].cbData,
|
|
CRYPT_DECODE_ALLOC_FLAG,
|
|
&CryptDecodeAlloc, &preq, &cb) ||
|
|
(preq->cReceiptsTo == 0))
|
|
goto GeneralFail;
|
|
|
|
//
|
|
// Initialize the ReceiptsTo list
|
|
//
|
|
|
|
if (pReceiptsTo != NULL)
|
|
_SetNames(&receiptsTo, preq->cReceiptsTo, preq->rgReceiptsTo);
|
|
|
|
if (ppbReceipt != NULL)
|
|
{
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pbReceipt,
|
|
m_rOptions.rgblobReceipt[iSigner].cbSize));
|
|
memcpy(pbReceipt,m_rOptions.rgblobReceipt[iSigner].pBlobData,
|
|
m_rOptions.rgblobReceipt[iSigner].cbSize);
|
|
}
|
|
if (pcbReceipt != NULL) cbReceipt = m_rOptions.rgblobReceipt[iSigner].cbSize;
|
|
|
|
if (ppbMsgHash != NULL)
|
|
{
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pbMsgHash,
|
|
m_rOptions.rgblobMsgHash[iSigner].cbSize));
|
|
memcpy(pbMsgHash,m_rOptions.rgblobMsgHash[iSigner].pBlobData,
|
|
m_rOptions.rgblobMsgHash[iSigner].cbSize);
|
|
}
|
|
if (pcbMsgHash != NULL) cbMsgHash = m_rOptions.rgblobMsgHash[iSigner].cbSize;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (preq == NULL)
|
|
{
|
|
// We are at the bottom so we should have found a receipt request
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
*ppreq = preq;
|
|
preq = NULL;
|
|
if (pReceiptsTo != NULL)
|
|
{
|
|
pReceiptsTo->cNames = receiptsTo.cNames;
|
|
pReceiptsTo->rgNames = receiptsTo.rgNames;
|
|
receiptsTo.cNames = 0;
|
|
receiptsTo.rgNames = NULL;
|
|
}
|
|
if (pcbReceipt != NULL)
|
|
{
|
|
*pcbReceipt = cbReceipt;
|
|
cbReceipt = 0;
|
|
}
|
|
if (ppbReceipt != NULL)
|
|
{
|
|
*ppbReceipt = pbReceipt;
|
|
pbReceipt = NULL;
|
|
}
|
|
if (pcbMsgHash != NULL)
|
|
{
|
|
*pcbMsgHash = cbMsgHash;
|
|
cbMsgHash = 0;
|
|
}
|
|
if (ppbMsgHash != NULL)
|
|
{
|
|
*ppbMsgHash = pbMsgHash;
|
|
pbMsgHash = NULL;
|
|
}
|
|
|
|
exit:
|
|
SafeMemFree(preq);
|
|
SafeMemFree(receiptsTo.rgNames);
|
|
SafeMemFree(pbReceipt);
|
|
SafeMemFree(pbMsgHash);
|
|
SafeMemFree(pbMLHistory);
|
|
return hr;
|
|
|
|
GeneralFail:
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
// CMessageBody::CreateReceipt
|
|
//--------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::CreateReceipt(DWORD dwFlags, DWORD cbFromNames,
|
|
const BYTE *pbFromNames, DWORD cSignerCertificates,
|
|
PCCERT_CONTEXT *rgSignerCertificates,
|
|
IMimeMessage ** ppMimeMessageReceipt)
|
|
{
|
|
CRYPT_ATTRIBUTE attrMsgHash;
|
|
DWORD cb;
|
|
DWORD cbEncodedMsgHash = 0;
|
|
DWORD cbMsgHash = 0;
|
|
DWORD cbReceipt = 0;
|
|
DWORD cLayers;
|
|
DWORD dwReceiptsFrom;
|
|
BOOL fAddedAddress = FALSE;
|
|
HRESULT hr;
|
|
DWORD i;
|
|
DWORD i1;
|
|
DWORD i2;
|
|
DWORD iLayer;
|
|
LPBYTE pbEncodedMsgHash = NULL;
|
|
LPBYTE pbMsgHash = NULL;
|
|
LPBYTE pbReceipt = NULL;
|
|
IMimeAddressTable * pmatbl = NULL;
|
|
IMimeBody * pmb = NULL;
|
|
IMimeMessage * pmm = NULL;
|
|
IMimeSecurity2 * pms = NULL;
|
|
PSMIME_RECEIPT_REQUEST preq = NULL;
|
|
LPSTREAM pstm = NULL;
|
|
ReceiptNames receiptsTo = {0, NULL};
|
|
PROPVARIANT var;
|
|
CRYPT_ATTR_BLOB valMsgHash;
|
|
|
|
|
|
hr = _GetReceiptRequest(dwFlags,
|
|
&preq,
|
|
&receiptsTo,
|
|
&cbReceipt,
|
|
&pbReceipt,
|
|
&cbMsgHash,
|
|
&pbMsgHash);
|
|
if (hr)
|
|
goto exit;
|
|
|
|
//
|
|
// Am I on the ReceiptsFrom List --
|
|
//
|
|
|
|
if (preq->ReceiptsFrom.cNames != 0)
|
|
{
|
|
BOOL fFoundMe = FALSE;
|
|
CERT_ALT_NAME_INFO * pname2 = NULL;
|
|
|
|
if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
|
|
pbFromNames,
|
|
cbFromNames,
|
|
CRYPT_ENCODE_ALLOC_FLAG,
|
|
&CryptDecodeAlloc, &pname2, &cb))
|
|
goto GeneralFail;
|
|
|
|
for (i=0; !fFoundMe && (i<preq->ReceiptsFrom.cNames); i++)
|
|
{
|
|
CERT_ALT_NAME_INFO * pname = NULL;
|
|
|
|
if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
|
|
preq->ReceiptsFrom.rgNames[i].pbData,
|
|
preq->ReceiptsFrom.rgNames[i].cbData,
|
|
CRYPT_ENCODE_ALLOC_FLAG,
|
|
&CryptDecodeAlloc, &pname, &cb))
|
|
goto GeneralFail;
|
|
|
|
for (i1=0; i1<pname->cAltEntry; i1++)
|
|
{
|
|
for (i2=0; i2<pname2->cAltEntry; i2++)
|
|
{
|
|
if (pname->rgAltEntry[i1].dwAltNameChoice !=
|
|
pname2->rgAltEntry[i2].dwAltNameChoice)
|
|
continue;
|
|
|
|
switch (pname->rgAltEntry[i1].dwAltNameChoice)
|
|
{
|
|
case CERT_ALT_NAME_RFC822_NAME:
|
|
if (lstrcmpiW(pname->rgAltEntry[i1].pwszRfc822Name,
|
|
pname2->rgAltEntry[i2].pwszRfc822Name) == 0)
|
|
{
|
|
fFoundMe = TRUE;
|
|
goto FoundMe;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FoundMe:
|
|
SafeMemFree(pname);
|
|
}
|
|
|
|
SafeMemFree(pname2);
|
|
if (!fFoundMe)
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Create a stream object to hold the receipt and put the receipt into the
|
|
// stream -- this supplies the body of the receipt message.
|
|
|
|
CHECKHR(hr = MimeOleCreateVirtualStream(&pstm));
|
|
CHECKHR(hr = pstm->Write(pbReceipt, cbReceipt, NULL));
|
|
|
|
CHECKHR(hr = MimeOleCreateMessage(NULL, &pmm));
|
|
CHECKHR(hr = pmm->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *) &pmb));
|
|
CHECKHR(hr = pmb->QueryInterface(IID_IMimeSecurity2, (LPVOID *) &pms));
|
|
CHECKHR(hr = pmb->SetData(IET_BINARY, "OID", szOID_SMIME_ContentType_Receipt,
|
|
IID_IStream, pstm));
|
|
|
|
//
|
|
// Address the receipt back to the receipients
|
|
//
|
|
|
|
CHECKHR(hr = pmm->GetAddressTable(&pmatbl));
|
|
|
|
for (i=0; i<receiptsTo.cNames; i++)
|
|
{
|
|
CERT_ALT_NAME_INFO * pname = NULL;
|
|
|
|
if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
|
|
receiptsTo.rgNames[i].pbData,
|
|
receiptsTo.rgNames[i].cbData,
|
|
CRYPT_ENCODE_ALLOC_FLAG,
|
|
&CryptDecodeAlloc, &pname, &cb))
|
|
goto GeneralFail;
|
|
|
|
for (i1=0; i1<pname->cAltEntry; i1++)
|
|
{
|
|
int cch;
|
|
TCHAR rgch[256];
|
|
|
|
if (pname->rgAltEntry[i1].dwAltNameChoice == CERT_ALT_NAME_RFC822_NAME)
|
|
{
|
|
cch = WideCharToMultiByte(CP_ACP, 0,
|
|
pname->rgAltEntry[i1].pwszRfc822Name,
|
|
-1, rgch, sizeof(rgch), NULL, NULL);
|
|
if (cch > 0)
|
|
{
|
|
CHECKHR(hr = pmatbl->AppendRfc822(IAT_TO, IET_DECODED,
|
|
rgch));
|
|
fAddedAddress = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
SafeMemFree(pname);
|
|
}
|
|
|
|
if (!fAddedAddress)
|
|
{
|
|
hr = S_FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
var.vt = VT_UI4;
|
|
var.ulVal = MST_CLASS_SMIME_V1 | MST_THIS_BLOBSIGN;
|
|
CHECKHR(hr = pmb->SetOption(OID_SECURITY_TYPE, &var));
|
|
|
|
#ifndef _WIN64
|
|
var.vt = (VT_VECTOR | VT_UI4);
|
|
var.caul.cElems = cSignerCertificates;
|
|
var.caul.pElems = (DWORD *) rgSignerCertificates;
|
|
CHECKHR(hr = pmb->SetOption(OID_SECURITY_CERT_SIGNING_RG, &var));
|
|
#else
|
|
var.vt = (VT_VECTOR | VT_UI8);
|
|
var.cauh.cElems = cSignerCertificates;
|
|
var.cauh.pElems = (ULARGE_INTEGER *) rgSignerCertificates;
|
|
CHECKHR(hr = pmb->SetOption(OID_SECURITY_CERT_SIGNING_RG_64, &var));
|
|
#endif
|
|
|
|
//
|
|
// Setup the authorized attribute block so that
|
|
// we can get the correct information transfered. At present we
|
|
// are only looking at one item to be included here.
|
|
// 1. The Message Hash of the message requesting the receipt
|
|
|
|
valMsgHash.cbData = cbMsgHash;
|
|
valMsgHash.pbData = pbMsgHash;
|
|
if (!CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
|
|
&valMsgHash, CRYPT_ENCODE_ALLOC_FLAG,
|
|
&CryptEncodeAlloc, &pbEncodedMsgHash, &cbEncodedMsgHash))
|
|
goto GeneralFail;
|
|
|
|
attrMsgHash.pszObjId = szOID_SMIME_Msg_Sig_Digest;
|
|
attrMsgHash.cValue = 1;
|
|
attrMsgHash.rgValue = &valMsgHash;
|
|
valMsgHash.cbData = cbEncodedMsgHash;
|
|
valMsgHash.pbData = pbEncodedMsgHash;
|
|
CHECKHR(hr = pms->SetAttribute(0, -1, SMIME_ATTRIBUTE_SET_SIGNED, &attrMsgHash));
|
|
|
|
hr = S_OK;
|
|
*ppMimeMessageReceipt = pmm;
|
|
pmm->AddRef();
|
|
|
|
exit:
|
|
SafeMemFree(preq);
|
|
SafeMemFree(receiptsTo.rgNames);
|
|
SafeMemFree(pbEncodedMsgHash);
|
|
SafeMemFree(pbMsgHash);
|
|
SafeMemFree(pbReceipt);
|
|
if (pstm != NULL) pstm->Release();
|
|
if (pmatbl != NULL) pmatbl->Release();
|
|
if (pmb != NULL) pmb->Release();
|
|
if (pms != NULL) pms->Release();
|
|
if (pmm != NULL) pmm->Release();
|
|
return hr;
|
|
|
|
GeneralFail:
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
// CMessageBody::GetReceiptSendersList
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::GetReceiptSendersList(DWORD dwFlags, DWORD *pcSendersList,
|
|
CERT_NAME_BLOB * *rgSendersList)
|
|
{
|
|
DWORD cb;
|
|
HRESULT hr;
|
|
DWORD i;
|
|
LPBYTE pb;
|
|
PSMIME_RECEIPT_REQUEST preq = NULL;
|
|
|
|
hr = _GetReceiptRequest(dwFlags,
|
|
&preq,
|
|
NULL, NULL, NULL, NULL, NULL);
|
|
if (hr)
|
|
goto exit;
|
|
|
|
if (preq->ReceiptsFrom.cNames == 0)
|
|
{
|
|
*rgSendersList = NULL;
|
|
*pcSendersList = preq->ReceiptsFrom.cNames;
|
|
goto exit;
|
|
}
|
|
|
|
cb = 0;
|
|
for (i =0; i < preq->ReceiptsFrom.cNames; i++)
|
|
#ifdef _WIN64
|
|
cb += sizeof(CERT_NAME_BLOB) + LcbAlignLcb(preq->ReceiptsFrom.rgNames[i].cbData);
|
|
#else
|
|
cb += sizeof(CERT_NAME_BLOB) + preq->ReceiptsFrom.rgNames[i].cbData;
|
|
#endif // _WIN64
|
|
CHECKHR(hr = HrAlloc((LPVOID *)rgSendersList, cb));
|
|
*pcSendersList = preq->ReceiptsFrom.cNames;
|
|
pb = (LPBYTE)*rgSendersList + (sizeof(CERT_NAME_BLOB) * (*pcSendersList));
|
|
|
|
for (i =0; i < preq->ReceiptsFrom.cNames; i++)
|
|
{
|
|
(*rgSendersList)[i].cbData = preq->ReceiptsFrom.rgNames[i].cbData;
|
|
(*rgSendersList)[i].pbData = pb;
|
|
memcpy(pb, preq->ReceiptsFrom.rgNames[i].pbData, preq->ReceiptsFrom.rgNames[i].cbData);
|
|
#ifdef _WIN64
|
|
pb += LcbAlignLcb((*rgSendersList)[i].cbData);
|
|
#else
|
|
pb += (*rgSendersList)[i].cbData;
|
|
#endif // _WIN64
|
|
}
|
|
|
|
exit:
|
|
SafeMemFree(preq);
|
|
return hr;
|
|
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::VerifyReceipt
|
|
//
|
|
// Assumes the passed in pMimeMessageReceipt has been decoded and
|
|
// it's signature verified.
|
|
//
|
|
// This function verifies that the values in the Receipt content are
|
|
// identical to those i the original sigendData signerInfo that
|
|
// requested the receipt and that the message hash of the original message
|
|
// is identical to the msgSigDigest sigend Attribute of the receipt
|
|
//
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMessageBody::VerifyReceipt(DWORD dwFlags,
|
|
IMimeMessage * pMimeMessageReceipt)
|
|
{
|
|
PCRYPT_ATTRIBUTE pattrMsgHash = NULL;
|
|
PCRYPT_ATTRIBUTE pattrMsgHash2 = NULL;
|
|
DWORD cb;
|
|
DWORD cbMsgHash = 0;
|
|
DWORD cbData;
|
|
HRESULT hr;
|
|
DWORD iReceiptSigner;
|
|
DWORD iSigner;
|
|
LPBYTE pb;
|
|
LPBYTE pbData = NULL;
|
|
PCRYPT_ATTR_BLOB pblobMsgHash = NULL;
|
|
IMimeBody * pmb = NULL;
|
|
IMimeSecurity2 * pms = NULL;
|
|
PSMIME_RECEIPT_REQUEST preq = NULL;
|
|
PSMIME_RECEIPT pSecReceipt = NULL;
|
|
LPSTREAM pstm = NULL;
|
|
STATSTG statstg;
|
|
PROPVARIANT var;
|
|
|
|
// If this is not the bottom layer then ask child to verify receipt
|
|
if (IsContentType(STR_CNT_MULTIPART, "y-security") == S_OK)
|
|
{
|
|
Assert(m_pNode->cChildren == 1);
|
|
|
|
hr = m_pNode->pChildHead->pBody->VerifyReceipt(
|
|
dwFlags,
|
|
pMimeMessageReceipt);
|
|
goto exit;
|
|
}
|
|
|
|
CHECKHR(hr = pMimeMessageReceipt->BindToObject(HBODY_ROOT, IID_IMimeBody,
|
|
(LPVOID *) &pmb));
|
|
CHECKHR(hr = pmb->QueryInterface(IID_IMimeSecurity2, (LPVOID *) &pms));
|
|
CHECKHR(hr = pmb->GetData(IET_BINARY, &pstm));
|
|
CHECKHR(hr = pstm->Stat(&statstg,STATFLAG_NONAME));
|
|
|
|
Assert(statstg.cbSize.HighPart == 0);
|
|
|
|
CHECKHR(hr = HrAlloc((LPVOID *)&pbData, statstg.cbSize.LowPart));
|
|
CHECKHR(hr = pstm->Read(pbData, statstg.cbSize.LowPart, &cbData));
|
|
|
|
// Check if receipt is the receipt we expect
|
|
for (iSigner=0; iSigner<m_rOptions.cSigners; iSigner++)
|
|
{
|
|
if ((m_rOptions.rgblobReceipt[iSigner].cbSize == cbData) &&
|
|
!memcmp(m_rOptions.rgblobReceipt[iSigner].pBlobData,pbData,cbData))
|
|
break;
|
|
}
|
|
|
|
// check if we found a matching receipt
|
|
if (iSigner == m_rOptions.cSigners)
|
|
{
|
|
hr = MIME_E_SECURITY_RECEIPT_NOMATCHINGRECEIPTBODY;
|
|
goto exit;
|
|
}
|
|
|
|
if (!CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_SMIME_ContentType_Receipt,
|
|
pbData,
|
|
cbData,
|
|
CRYPT_ENCODE_ALLOC_FLAG, &CryptDecodeAlloc,
|
|
&pSecReceipt, &cb))
|
|
goto GeneralFail;
|
|
|
|
//
|
|
// Get the first signatures MsgSigDigest
|
|
//
|
|
CHECKHR(hr = pms->GetAttribute(0, 0, SMIME_ATTRIBUTE_SET_SIGNED,
|
|
0, szOID_SMIME_Msg_Sig_Digest,
|
|
&pattrMsgHash));
|
|
|
|
if ((hr == S_FALSE) ||
|
|
(!CryptDecodeObjectEx(X509_ASN_ENCODING,
|
|
X509_OCTET_STRING,
|
|
pattrMsgHash->rgValue[0].pbData,
|
|
pattrMsgHash->rgValue[0].cbData,
|
|
CRYPT_DECODE_ALLOC_FLAG,
|
|
&CryptDecodeAlloc, &pblobMsgHash, &cbMsgHash)))
|
|
{
|
|
hr = MIME_E_SECURITY_RECEIPT_MSGHASHMISMATCH;
|
|
goto exit;
|
|
}
|
|
|
|
if ((m_rOptions.rgblobMsgHash[iSigner].cbSize != pblobMsgHash->cbData) ||
|
|
memcmp(m_rOptions.rgblobMsgHash[iSigner].pBlobData,
|
|
pblobMsgHash->pbData, pblobMsgHash->cbData))
|
|
{
|
|
hr = MIME_E_SECURITY_RECEIPT_MSGHASHMISMATCH;
|
|
goto exit;
|
|
}
|
|
|
|
CHECKHR(hr = pmb->GetOption(OID_SECURITY_SIGNATURE_COUNT, &var));
|
|
for (iReceiptSigner = 1; iReceiptSigner < var.ulVal; iReceiptSigner++)
|
|
{
|
|
CHECKHR(hr = pms->GetAttribute(0, iReceiptSigner, SMIME_ATTRIBUTE_SET_SIGNED,
|
|
0, szOID_SMIME_Msg_Sig_Digest,
|
|
&pattrMsgHash2));
|
|
|
|
if ((hr == S_FALSE) ||
|
|
(pattrMsgHash->rgValue[0].cbData != pattrMsgHash2->rgValue[0].cbData) ||
|
|
memcmp(pattrMsgHash->rgValue[0].pbData,
|
|
pattrMsgHash2->rgValue[0].pbData,
|
|
pattrMsgHash->rgValue[0].cbData))
|
|
{
|
|
hr = MIME_E_SECURITY_RECEIPT_MSGHASHMISMATCH;
|
|
goto exit;
|
|
}
|
|
|
|
SafeMemFree(pattrMsgHash2);
|
|
}
|
|
|
|
exit:
|
|
SafeMemFree(pblobMsgHash);
|
|
SafeMemFree(pbData);
|
|
SafeMemFree(pSecReceipt);
|
|
SafeMemFree(pattrMsgHash);
|
|
SafeMemFree(pattrMsgHash2);
|
|
if (pstm != NULL) pstm->Release();
|
|
if (pmb != NULL) pmb->Release();
|
|
if (pms != NULL) pms->Release();
|
|
return hr;
|
|
|
|
GeneralFail:
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::CapabilitiesSupported
|
|
// --------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::CapabilitiesSupported(DWORD * pdwFlags)
|
|
{
|
|
// Assume no capabilities
|
|
*pdwFlags = 0;
|
|
|
|
// If we have msasn1.dll on the system, then we can support labels
|
|
if (FIsMsasn1Loaded()) *pdwFlags |= SMIME_SUPPORT_LABELS;
|
|
|
|
// If we have a correct crypt32, then we can support receipts & key agreement
|
|
|
|
DemandLoadCrypt32();
|
|
if (g_FSupportV3 && FIsMsasn1Loaded())
|
|
*pdwFlags |= SMIME_SUPPORT_RECEIPTS;
|
|
|
|
if (g_FSupportV3)
|
|
*pdwFlags |= SMIME_SUPPORT_KEY_AGREE;
|
|
|
|
// If we have a correct advapi32, then we can support maillist keys
|
|
DemandLoadAdvApi32();
|
|
if (VAR_CryptContextAddRef != MY_CryptContextAddRef)
|
|
*pdwFlags |= SMIME_SUPPORT_MAILLIST;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessage::_HrGetAttrs
|
|
//
|
|
// Utility function to retrieve attributes
|
|
// --------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::_HrGetAttrs(DWORD cSigners, PCRYPT_ATTRIBUTES * rgpattrs,
|
|
LPCSTR pszObjId, PROPVARIANT FAR * pvOut)
|
|
{
|
|
// Locals
|
|
CRYPT_ATTRIBUTES attrs;
|
|
HRESULT hr = S_OK;
|
|
DWORD i;
|
|
DWORD i1;
|
|
CRYPT_ATTRIBUTES UNALIGNED *pattrs;
|
|
CAPROPVARIANT UNALIGNED *pcapropvar;
|
|
PROPVARIANT *ppv = NULL;
|
|
|
|
pvOut->vt = VT_VECTOR | VT_VARIANT;
|
|
pcapropvar = &pvOut->capropvar;
|
|
pcapropvar->cElems = cSigners;
|
|
|
|
if (cSigners > 0)
|
|
{
|
|
Assert(rgpattrs && pvOut);
|
|
|
|
// Allocate the array of VT_BLOB propvariants
|
|
if (FAILED(hr = HrAlloc((LPVOID *)&ppv, cSigners * sizeof(PROPVARIANT))))
|
|
{
|
|
goto exit;
|
|
}
|
|
memset(ppv, 0, cSigners * sizeof(PROPVARIANT));
|
|
|
|
pcapropvar->pElems = ppv;
|
|
|
|
// Fill in the array of BLOBs
|
|
for (i = 0; i < cSigners; i++)
|
|
{
|
|
ppv[i].vt = VT_BLOB;
|
|
// HrCopyBlob allocates memory for the blob data.
|
|
if (rgpattrs[i] == NULL)
|
|
continue;
|
|
|
|
if (pszObjId == NULL)
|
|
{
|
|
pattrs = rgpattrs[i];
|
|
}
|
|
else
|
|
{
|
|
pattrs = NULL;
|
|
for (i1=0; i1<rgpattrs[i]->cAttr; i1++)
|
|
{
|
|
if (lstrcmp(rgpattrs[i]->rgAttr[i1].pszObjId, pszObjId) == NULL)
|
|
{
|
|
pattrs = &attrs;
|
|
attrs.cAttr = 1;
|
|
attrs.rgAttr = &rgpattrs[i]->rgAttr[i1];
|
|
break;
|
|
}
|
|
}
|
|
if (pattrs == NULL)
|
|
continue;
|
|
}
|
|
|
|
if (!CryptEncodeObjectEx(X509_ASN_ENCODING,
|
|
szOID_Microsoft_Attribute_Sequence,
|
|
pattrs, CRYPT_ENCODE_ALLOC_FLAG,
|
|
&CryptEncodeAlloc, &ppv[i].blob.pBlobData,
|
|
&ppv[i].blob.cbSize))
|
|
{
|
|
hr = HrGetLastError();
|
|
goto exit;
|
|
}
|
|
}
|
|
} else {
|
|
pcapropvar->pElems = NULL;
|
|
}
|
|
|
|
hr = S_OK;
|
|
exit:
|
|
if (FAILED(hr) && (ppv != NULL))
|
|
{
|
|
for (i=0; i<cSigners; i++)
|
|
{
|
|
MemFree(&ppv[i].blob.pBlobData);
|
|
}
|
|
MemFree(ppv);
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_FindAttribute
|
|
//
|
|
// Utility function designed to find attributes in an attribute set
|
|
// --------------------------------------------------------------------------------
|
|
|
|
PCRYPT_ATTRIBUTE CMessageBody::_FindAttribute(PCRYPT_ATTRIBUTES pattrs,
|
|
LPCSTR pszObjId, DWORD iInstance)
|
|
{
|
|
DWORD i;
|
|
|
|
if (pattrs == NULL)
|
|
return NULL;
|
|
|
|
for (i=0; i<pattrs->cAttr; i++)
|
|
{
|
|
if (lstrcmp(pattrs->rgAttr[i].pszObjId, pszObjId) == 0)
|
|
{
|
|
if (iInstance == 0)
|
|
{
|
|
return &pattrs->rgAttr[i];
|
|
}
|
|
else
|
|
{
|
|
iInstance -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMessageBody::_HrSetAttribute
|
|
//
|
|
// Utility function designed to set attributes. Called from set property as well
|
|
// as public interface set attribute function
|
|
// --------------------------------------------------------------------------------
|
|
|
|
HRESULT CMessageBody::_HrSetAttribute(DWORD dwFlags, PCRYPT_ATTRIBUTES * ppattrs,
|
|
LPCSTR pszObjId, DWORD cbNew, const BYTE * pbNew)
|
|
{
|
|
DWORD cAttr =0;
|
|
DWORD cb;
|
|
HRESULT hr;
|
|
DWORD i;
|
|
PCRYPT_ATTRIBUTES pattrs = *ppattrs;
|
|
PCRYPT_ATTRIBUTES pattrs2 = NULL;
|
|
LPBYTE pb;
|
|
CRYPT_ATTR_BLOB UNALIGNED *pVal = NULL;
|
|
|
|
//
|
|
// We have a special case of pszObjId == NULL, in this case the entire
|
|
// encoded item is passed in
|
|
//
|
|
|
|
if (pszObjId == NULL)
|
|
{
|
|
hr = HrDecodeObject(pbNew, cbNew, szOID_Microsoft_Attribute_Sequence, 0,
|
|
&cb, (LPVOID *) &pattrs2);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
#ifdef _WIN64
|
|
*ppattrs = (PCRYPT_ATTRIBUTES) MyPbAlignPb(*ppattrs);
|
|
#endif //_WIN64
|
|
MemFree(*ppattrs);
|
|
*ppattrs = NULL;
|
|
*ppattrs = pattrs2;
|
|
pattrs2 = NULL;
|
|
}
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Compute size of buffer we are going to need to hold the result
|
|
//
|
|
|
|
if (pattrs == NULL)
|
|
{
|
|
cb = sizeof(CRYPT_ATTRIBUTES);
|
|
}
|
|
else
|
|
{
|
|
cb = sizeof(CRYPT_ATTRIBUTES);
|
|
|
|
for (i=0; i<pattrs->cAttr; i++)
|
|
{
|
|
Assert(pattrs->rgAttr[i].cValue == 1);
|
|
|
|
//
|
|
// If we are going to replace something, then set it's oid to NULL
|
|
//
|
|
|
|
if ((lstrcmp(pattrs->rgAttr[i].pszObjId, pszObjId) == 0) &&
|
|
!(dwFlags & SMIME_ATTR_ADD_TO_EXISTING))
|
|
{
|
|
if (dwFlags & SMIME_ATTR_ADD_IF_NOT_EXISTS)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
pattrs->rgAttr[i].pszObjId = NULL;
|
|
continue;
|
|
}
|
|
|
|
pVal = &(pattrs->rgAttr[i].rgValue[0]);
|
|
|
|
cb += ((DWORD) (sizeof(CRYPT_ATTRIBUTE) + sizeof(CRYPT_ATTR_BLOB) +
|
|
strlen(pattrs->rgAttr[i].pszObjId) + 1 +
|
|
pVal->cbData));
|
|
#ifdef _WIN64
|
|
cb = LcbAlignLcb(cb);
|
|
#endif // _WIN64
|
|
cAttr += 1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add room for the one we are about to include
|
|
//
|
|
#ifdef _WIN64
|
|
cb = LcbAlignLcb(cb);
|
|
#endif // _WIN64
|
|
|
|
cb += (DWORD)(sizeof(CRYPT_ATTRIBUTE) + sizeof(CRYPT_ATTR_BLOB) +
|
|
#ifdef _WIN64
|
|
LcbAlignLcb(strlen(pszObjId) + 1) + cbNew);
|
|
#else
|
|
strlen(pszObjId) + 1 + cbNew);
|
|
#endif // _WIN64
|
|
cAttr += 1;
|
|
|
|
//
|
|
// Allocate Memory to hold the result
|
|
//
|
|
|
|
pattrs2 = (PCRYPT_ATTRIBUTES) g_pMalloc->Alloc(cb);
|
|
if (pattrs2 == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Now copy over the items appending our item at the end
|
|
//
|
|
|
|
pattrs2->rgAttr = (PCRYPT_ATTRIBUTE) &pattrs2[1];
|
|
pb = (LPBYTE) &pattrs2->rgAttr[cAttr];
|
|
|
|
cAttr = 0;
|
|
if (pattrs != NULL)
|
|
{
|
|
for (i=0; i<pattrs->cAttr; i++)
|
|
{
|
|
if (pattrs->rgAttr[i].pszObjId == NULL) continue;
|
|
|
|
pattrs2->rgAttr[cAttr].pszObjId = (LPSTR) pb;
|
|
#ifdef _WIN64
|
|
cb = LcbAlignLcb(strlen(pattrs->rgAttr[i].pszObjId) + 1);
|
|
#else
|
|
cb = strlen(pattrs->rgAttr[i].pszObjId) + 1;
|
|
#endif // _WIN64
|
|
memcpy(pb, pattrs->rgAttr[i].pszObjId, cb);
|
|
pb += cb;
|
|
|
|
pattrs2->rgAttr[cAttr].cValue = 1;
|
|
pattrs2->rgAttr[cAttr].rgValue = (PCRYPT_ATTR_BLOB) pb;
|
|
#ifdef _WIN64
|
|
pb += LcbAlignLcb(sizeof(CRYPT_ATTR_BLOB));
|
|
#else
|
|
pb += sizeof(CRYPT_ATTR_BLOB);
|
|
#endif
|
|
pVal = &(pattrs->rgAttr[i].rgValue[0]);
|
|
|
|
cb = ((DWORD) (pVal->cbData));
|
|
|
|
#ifdef _WIN64
|
|
// cb = LcbAlignLcb(cb);
|
|
#endif // _WIN64
|
|
|
|
pVal = &(pattrs2->rgAttr[cAttr].rgValue[0]);
|
|
|
|
pVal->pbData = pb;
|
|
pVal->cbData = cb;
|
|
|
|
pVal = &(pattrs->rgAttr[i].rgValue[0]);
|
|
memcpy(pb, pVal->pbData, cb);
|
|
|
|
#ifdef _WIN64
|
|
pb += LcbAlignLcb(cb);
|
|
#else
|
|
pb += cb;
|
|
#endif
|
|
cAttr += 1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Append the new one
|
|
//
|
|
|
|
#ifdef _WIN64
|
|
cb = LcbAlignLcb(strlen(pszObjId) + 1);
|
|
#else
|
|
cb = strlen(pszObjId) + 1;
|
|
#endif // _WIN64
|
|
pattrs2->rgAttr[cAttr].pszObjId = (LPSTR) pb;
|
|
memcpy(pb, pszObjId, cb);
|
|
pb += cb;
|
|
|
|
pattrs2->rgAttr[cAttr].cValue = (DWORD) 1;
|
|
pattrs2->rgAttr[cAttr].rgValue = (PCRYPT_ATTR_BLOB) pb;
|
|
#ifdef _WIN64
|
|
pb += LcbAlignLcb(sizeof(CRYPT_ATTR_BLOB));
|
|
#else
|
|
pb += sizeof(CRYPT_ATTR_BLOB);
|
|
#endif
|
|
|
|
pVal = &(pattrs2->rgAttr[cAttr].rgValue[0]);
|
|
|
|
pVal->cbData = (DWORD) cbNew;
|
|
pVal->pbData = pb;
|
|
memcpy(pb, pbNew, cbNew);
|
|
#ifdef _WIN64
|
|
pb += LcbAlignLcb(cbNew);
|
|
#else
|
|
pb += cbNew;
|
|
#endif
|
|
|
|
pattrs2->cAttr = cAttr + 1;
|
|
|
|
|
|
MemFree(*ppattrs);
|
|
*ppattrs = NULL;
|
|
*ppattrs = pattrs2;
|
|
pattrs2 = NULL;
|
|
|
|
hr = S_OK;
|
|
exit:
|
|
if (pattrs2 != NULL) MemFree(pattrs2);
|
|
return hr;
|
|
}
|
|
|
|
|
|
#endif // SMIME_V3
|