|
|
// --------------------------------------------------------------------------------
// Partial.cpp
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
// Steven J. Bailey
// --------------------------------------------------------------------------------
#include "pch.hxx"
#include "partial.h"
#include "vstream.h"
#include "strconst.h"
#include "demand.h"
// --------------------------------------------------------------------------------
// Releases an array of IMimeMessage objects
// --------------------------------------------------------------------------------
void ReleaseParts(ULONG cParts, LPPARTINFO prgPart) { // Loop
for (ULONG i=0; i<cParts; i++) { SafeRelease(prgPart[i].pMessage); } }
// --------------------------------------------------------------------------------
// CMimeMessageParts::CMimeMessageParts
// --------------------------------------------------------------------------------
CMimeMessageParts::CMimeMessageParts(void) { m_cRef = 1; m_cParts = 0; m_cAlloc =0; m_prgPart = NULL; InitializeCriticalSection(&m_cs); }
// --------------------------------------------------------------------------------
// CMimeMessageParts::CMimeMessageParts
// --------------------------------------------------------------------------------
CMimeMessageParts::~CMimeMessageParts(void) { ReleaseParts(m_cParts, m_prgPart); SafeMemFree(m_prgPart); DeleteCriticalSection(&m_cs); }
// --------------------------------------------------------------------------------
// CMimeMessageParts::QueryInterface
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeMessageParts::QueryInterface(REFIID riid, LPVOID *ppv) { // check params
if (ppv == NULL) return TrapError(E_INVALIDARG);
// Find IID
if (IID_IUnknown == riid) *ppv = (IUnknown *)this; else if (IID_IMimeMessageParts == riid) *ppv = (IMimeMessageParts *)this; else { *ppv = NULL; return TrapError(E_NOINTERFACE); }
// AddRef It
((IUnknown *)*ppv)->AddRef();
// Done
return S_OK; }
// --------------------------------------------------------------------------------
// CMimeMessageParts::AddRef
// --------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CMimeMessageParts::AddRef(void) { return (ULONG)InterlockedIncrement(&m_cRef); }
// --------------------------------------------------------------------------------
// CMimeMessageParts::Release
// --------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CMimeMessageParts::Release(void) { LONG cRef = InterlockedDecrement(&m_cRef); if (0 == cRef) delete this; return (ULONG)cRef; }
// --------------------------------------------------------------------------------
// CMimeMessageParts::AddPart
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeMessageParts::AddPart(IMimeMessage *pMessage) { // Locals
HRESULT hr=S_OK;
// Invalid ARg
if (NULL == pMessage) return TrapError(E_INVALIDARG);
// Thread Safety
EnterCriticalSection(&m_cs);
// Grow my internal array
if (m_cParts + 1 >= m_cAlloc) { // Grow my array
CHECKHR(hr = HrRealloc((LPVOID *)&m_prgPart, sizeof(PARTINFO) * (m_cAlloc + 10)));
// Set alloc size
m_cAlloc += 10; }
// Set new
ZeroMemory(&m_prgPart[m_cParts], sizeof(PARTINFO)); m_prgPart[m_cParts].pMessage = pMessage; m_prgPart[m_cParts].pMessage->AddRef(); m_cParts++;
exit: // Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr; }
// --------------------------------------------------------------------------------
// CMimeMessageParts::SetMaxParts
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeMessageParts::SetMaxParts(ULONG cParts) { // Locals
HRESULT hr=S_OK;
// Thread Safety
EnterCriticalSection(&m_cs);
// Less than number alloced?
if (cParts <= m_cAlloc) goto exit;
// Grow my array
CHECKHR(hr = HrAlloc((LPVOID *)&m_prgPart, sizeof(PARTINFO) * (cParts + 10)));
// Set alloc size
m_cAlloc = cParts + 10;
exit: // Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr; }
// --------------------------------------------------------------------------------
// CMimeMessageParts::CountParts
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeMessageParts::CountParts(ULONG *pcParts) { // Invalid ARg
if (NULL == pcParts) return TrapError(E_INVALIDARG);
// Thread Safety
EnterCriticalSection(&m_cs);
// Set count
*pcParts = m_cParts;
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return S_OK; }
// --------------------------------------------------------------------------------
// CMimeMessageParts::EnumParts
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeMessageParts::EnumParts(IMimeEnumMessageParts **ppEnum) { // Locals
HRESULT hr=S_OK; CMimeEnumMessageParts *pEnum=NULL;
// Invalid Arg
if (NULL == ppEnum) return TrapError(E_INVALIDARG);
// Thread Safety
EnterCriticalSection(&m_cs);
// Init
*ppEnum = NULL;
// Create the clone.
pEnum = new CMimeEnumMessageParts; if (NULL == pEnum) { hr = TrapError(E_OUTOFMEMORY); goto exit; }
// Init
CHECKHR(hr = pEnum->HrInit(0, m_cParts, m_prgPart));
// Set Return
*ppEnum = pEnum; (*ppEnum)->AddRef();
exit: // Cleanup
SafeRelease(pEnum);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr; }
// --------------------------------------------------------------------------------
// CMimeMessageParts::CombineParts
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeMessageParts::CombineParts(IMimeMessage **ppMessage) { // Locals
HRESULT hr=S_OK; LPSTREAM pstmMsg=NULL, pstmSource=NULL; ULONG i, cMimePartials=0, iPart, cRejected=0; IMimeMessage *pMessage; IMimeMessage *pCombine=NULL; IMimeBody *pRootBody=NULL; BOOL fTreatAsMime; BODYOFFSETS rOffsets; LPSTR pszSubject=NULL; PROPVARIANT rData;
// Invalid ARg
if (NULL == ppMessage) return TrapError(E_INVALIDARG);
// Thread Safety
EnterCriticalSection(&m_cs);
// Init
*ppMessage = NULL;
// Create Temp Stream...
CHECKALLOC(pstmMsg = new CVirtualStream);
// Set all rejected flags to FALSE...
for (i=0; i<m_cParts; i++) m_prgPart[i].fRejected = FALSE;
// Enumerate parts
for (i=0; i<m_cParts; i++) { // Reability
pMessage = m_prgPart[i].pMessage; Assert(pMessage);
// Get Message Source
CHECKHR(hr = pMessage->GetMessageSource(&pstmSource, COMMIT_ONLYIFDIRTY));
// Get Tree Object
CHECKHR(hr = pMessage->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *)&pRootBody));
// Get Root Body Offset
CHECKHR(hr = pRootBody->GetOffsets(&rOffsets));
// Un-init iPart
iPart = 0;
// Mime Message ?
rData.vt = VT_UI4; if (pRootBody->IsContentType(STR_CNT_MESSAGE, STR_SUB_PARTIAL) == S_OK && SUCCEEDED(pRootBody->GetProp(STR_PAR_NUMBER, 0, &rData))) { // Count MimePartials
cMimePartials++;
// Treat this part as mime...
fTreatAsMime = TRUE;
// Get Part Number
iPart = rData.ulVal; }
// Otherwise
else { // Don't treat as mime
fTreatAsMime = FALSE;
// If There have been legal mime partials, this part is rejected
m_prgPart[i].fRejected = BOOL(cMimePartials > 0); }
// If Rejected, continue...
if (m_prgPart[i].fRejected) { cRejected++; continue; }
// If MIME - and part one
if (i == 0) { // Treat as mime
if (fTreatAsMime && 1 == iPart) { // Merge the headers of part one
CHECKHR(hr = MimeOleMergePartialHeaders(pstmSource, pstmMsg));
// CRLF
CHECKHR(hr = pstmMsg->Write(c_szCRLF, lstrlen(c_szCRLF), NULL));
// Append message body onto lpstmOut
CHECKHR(hr = HrCopyStream(pstmSource, pstmMsg, NULL)); }
else { // Seek to body start
CHECKHR(hr = HrStreamSeekSet(pstmSource, 0));
// Append message body onto lpstmOut
CHECKHR(hr = HrCopyStream(pstmSource, pstmMsg, NULL)); } }
else { // Seek to body start
CHECKHR(hr = HrStreamSeekSet(pstmSource, rOffsets.cbBodyStart));
// Append message body onto lpstmOut
CHECKHR(hr = HrCopyStream(pstmSource, pstmMsg, NULL)); }
// Raid 67648 - Need to append a CRLF to the end of the last message...
if (i < m_cParts - 1) { // Locals
DWORD cbMsg;
// Read the last 2 bytes...
CHECKHR(hr = HrGetStreamSize(pstmMsg, &cbMsg));
// If greater than 2...
if (cbMsg > 2) { // Locals
BYTE rgCRLF[2];
// Seek...
CHECKHR(hr = HrStreamSeekSet(pstmMsg, cbMsg - 2));
// Read the last two bytes
CHECKHR(hr = pstmMsg->Read(rgCRLF, 2, NULL));
// If not a crlf, then write a crlf
if (rgCRLF[0] != chCR && rgCRLF[1] != chLF) { // Write CRLF
CHECKHR(hr = pstmMsg->Write(c_szCRLF, 2, NULL)); } } } // Release
SafeRelease(pstmSource); SafeRelease(pRootBody); }
// Rewind message stream..
CHECKHR(hr = HrRewindStream(pstmMsg));
// Create a message
CHECKHR(hr = MimeOleCreateMessage(NULL, &pCombine));
// Init New
CHECKHR(hr = pCombine->InitNew());
// Load the message
CHECKHR(hr = pCombine->Load(pstmMsg));
// Any Rejected ?
if (cRejected) { // Attach rejected messages
for (i=0; i<m_cParts; i++) { // Rejected...
if (m_prgPart[i].fRejected) { // Attach body to combined message
CHECKHR(hr = pCombine->AttachObject(IID_IMimeMessage, m_prgPart[i].pMessage, NULL)); } } }
// Return the new message
*ppMessage = pCombine; (*ppMessage)->AddRef();
// Debug to temp file...
#ifdef DEBUG
LPSTREAM pstmFile; if (SUCCEEDED(OpenFileStream("d:\\lastcom.txt", CREATE_ALWAYS, GENERIC_WRITE, &pstmFile))) { HrRewindStream(pstmMsg); HrCopyStream(pstmMsg, pstmFile, NULL); pstmFile->Commit(STGC_DEFAULT); pstmFile->Release(); } #endif
exit: // Cleanup
SafeRelease(pstmMsg); SafeRelease(pstmSource); SafeRelease(pRootBody); SafeRelease(pCombine);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr; }
// --------------------------------------------------------------------------------
// CMimeEnumMessageParts::CMimeEnumMessageParts
// --------------------------------------------------------------------------------
CMimeEnumMessageParts::CMimeEnumMessageParts(void) { m_cRef = 1; m_iPart = 0; m_cParts = 0; m_prgPart = NULL; InitializeCriticalSection(&m_cs); }
// --------------------------------------------------------------------------------
// CMimeEnumMessageParts::~CMimeEnumMessageParts
// --------------------------------------------------------------------------------
CMimeEnumMessageParts::~CMimeEnumMessageParts(void) { ReleaseParts(m_cParts, m_prgPart); SafeMemFree(m_prgPart); DeleteCriticalSection(&m_cs); }
// --------------------------------------------------------------------------------
// CMimeEnumMessageParts::QueryInterface
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeEnumMessageParts::QueryInterface(REFIID riid, LPVOID *ppv) { // check params
if (ppv == NULL) return TrapError(E_INVALIDARG);
// Find IID
if (IID_IUnknown == riid) *ppv = (IUnknown *)this; else if (IID_IMimeEnumMessageParts == riid) *ppv = (IMimeEnumMessageParts *)this; else { *ppv = NULL; return TrapError(E_NOINTERFACE); }
// AddRef It
((IUnknown *)*ppv)->AddRef();
// Done
return S_OK; }
// --------------------------------------------------------------------------------
// CMimeEnumMessageParts::QueryInterface
// --------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CMimeEnumMessageParts::AddRef(void) { return (ULONG)InterlockedIncrement(&m_cRef); }
// --------------------------------------------------------------------------------
// CMimeEnumMessageParts::Release
// --------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CMimeEnumMessageParts::Release(void) { LONG cRef = InterlockedDecrement(&m_cRef); if (0 == cRef) delete this; return (ULONG)cRef; }
// --------------------------------------------------------------------------------
// CMimeEnumMessageParts::Next
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeEnumMessageParts::Next(ULONG cWanted, IMimeMessage **prgpMessage, ULONG *pcFetched) { // Locals
HRESULT hr=S_OK; ULONG cFetch=1, iPart=0;
// Thread Safety
EnterCriticalSection(&m_cs);
// Init
if (pcFetched) *pcFetched = 0;
// No Internal Formats
if (NULL == m_prgPart || NULL == prgpMessage) goto exit;
// Compute number to fetch
cFetch = min(cWanted, m_cParts - m_iPart); if (0 == cFetch) goto exit;
// Copy cWanted
for (iPart=0; iPart<cFetch; iPart++) { prgpMessage[iPart] = m_prgPart[m_iPart].pMessage; prgpMessage[iPart]->AddRef(); m_iPart++; }
// Return fetced ?
if (pcFetched) *pcFetched = cFetch;
exit: // Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return (cFetch == cWanted) ? S_OK : S_FALSE; }
// --------------------------------------------------------------------------------
// CMimeEnumMessageParts::Skip
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeEnumMessageParts::Skip(ULONG cSkip) { // Locals
HRESULT hr=S_OK;
// Thread Safety
EnterCriticalSection(&m_cs);
// Can we do it...
if (((m_iPart + cSkip) >= m_cParts) || NULL == m_prgPart) { hr = S_FALSE; goto exit; }
// Skip
m_iPart += cSkip;
exit: // Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr; }
// --------------------------------------------------------------------------------
// CMimeEnumMessageParts::Reset
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeEnumMessageParts::Reset(void) { EnterCriticalSection(&m_cs); m_iPart = 0; LeaveCriticalSection(&m_cs); return S_OK; }
// --------------------------------------------------------------------------------
// CMimeEnumMessageParts::Count
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeEnumMessageParts::Count(ULONG *pcCount) { // Invalid Arg
if (NULL == pcCount) return TrapError(E_INVALIDARG);
// Thread Safety
EnterCriticalSection(&m_cs);
// Set Count
*pcCount = m_cParts;
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return S_OK; }
// --------------------------------------------------------------------------------
// CMimeEnumMessageParts::Clone
// --------------------------------------------------------------------------------
STDMETHODIMP CMimeEnumMessageParts::Clone(IMimeEnumMessageParts **ppEnum) { // Locals
HRESULT hr=S_OK; CMimeEnumMessageParts *pEnum=NULL;
// Invalid Arg
if (NULL == ppEnum) return TrapError(E_INVALIDARG);
// Thread Safety
EnterCriticalSection(&m_cs);
// Init
*ppEnum = NULL;
// Create the clone.
pEnum = new CMimeEnumMessageParts; if (NULL == pEnum) { hr = TrapError(E_OUTOFMEMORY); goto exit; }
// Init
CHECKHR(hr = pEnum->HrInit(m_iPart, m_cParts, m_prgPart));
// Set Return
*ppEnum = pEnum; (*ppEnum)->AddRef();
exit: // Cleanup
SafeRelease(pEnum);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr; }
// --------------------------------------------------------------------------------
// CMimeEnumMessageParts::HrInit
// --------------------------------------------------------------------------------
HRESULT CMimeEnumMessageParts::HrInit(ULONG iPart, ULONG cParts, LPPARTINFO prgPart) { // Locals
HRESULT hr=S_OK; ULONG i;
// Thread Safety
EnterCriticalSection(&m_cs);
// Check param
Assert(m_prgPart == NULL);
// Empty Enumerator ?
if (0 == cParts) { Assert(prgPart == NULL); m_cParts = m_iPart = 0; goto exit; }
// Allocat an internal array
CHECKHR(hr = HrAlloc((LPVOID *)&m_prgPart, sizeof(PARTINFO) * cParts));
// Copy prgPart
for (i=0; i<cParts; i++) { CopyMemory(&m_prgPart[i], &prgPart[i], sizeof(PARTINFO)); Assert(m_prgPart[i].pMessage); m_prgPart[i].pMessage->AddRef(); }
// Save Size and State
m_cParts = cParts; m_iPart = iPart;
exit: // Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr; }
|