// MimeBody.cpp : Implementation of CMimeBody
#include "stdafx.h"
#include "MimeSniffer.h"
#include "MimeBody.h"
#include "MimeCode.h"
#include "FileSystemStorage.h"
#include "quote.h"
#include "ISSHelper.h"
static ULONG __Write(LPSTREAM pStm, const char* text)
{
ULONG nWritten = 0;
pStm->Write(text, strlen(text), &nWritten);
return nWritten;
}
template <class T>
static ULONG __WriteParameter(LPSTREAM pStm, T p)
{
ULONG nWritten = 0;
nWritten = __Write(pStm, "\r\n\t\t;");
nWritten += __Write(pStm, p->first.c_str());
nWritten += __Write(pStm, "=");
if (p->second.vt != VT_BSTR)
{
USES_CONVERSION;
CComVariant varTemp(p->second);
varTemp.ChangeType(VT_BSTR);
if (varTemp.vt != VT_BSTR)
__Write(pStm, OLE2CA(varTemp.bstrVal));
}
else
{
USES_CONVERSION;
__Write(pStm, OLE2CA(p->second.bstrVal));
}
return nWritten;
}
/////////////////////////////////////////////////////////////////////////////
// CMimeBody
CMimeBody::CMimeBody()
{
m_pBody = NULL;
m_pRoot = NULL;
m_pProxy = NULL;
ATLTRACE(_T("CMimeBody()\n"));
}
CMimeBody::~CMimeBody()
{
if (m_pProxy != NULL)
m_pProxy->Release();
ATLTRACE(_T("~CMimeBody()\n"));
}
void CMimeBody::Init(CYYSType* pBody, CMimeDecoder* pRoot)
{
m_pBody = pBody;
ATLASSERT(m_pBody != NULL);
m_pRoot = pRoot;
ATLASSERT(m_pRoot != NULL);
if (m_pBody->GetType() != CYYSType::type_Container)
{
m_pBody->InitType(CYYSType::type_Container);
}
CComVariant var1;
CComVariant var2;
get_MajorContentType(&var1);
get_MinorContentType(&var2);
if ( var1.vt == VT_I4 && var2.vt == VT_I4
&& var1.lVal == CMimeDecoder::mimetype_message
&& var2.lVal == CMimeDecoder::msg_subtype_rfc822
&& m_pRoot->m_bInterpretEmbeddedMails
)
{
CYYSType* bContentIsRaw = NULL;
CYYSType& body = GetBody(bContentIsRaw);
if (body.GetType() == CYYSType::type_Bulk)
{
m_pProxy = new CComObject<CMimeDecoder>;
m_pProxy->AddRef();
m_pProxy->IsProxy(body.m_streamVal, m_pRoot);
if (m_pProxy->m_bErrorOccured)
{
m_pProxy->Release();
m_pProxy = NULL;
}
}
}
}
CYYSType& CMimeBody::GetBody(CYYSType*& bContentIsRaw, bool bCreate /* = false */)
{
static CYYSType dummy;
ATLASSERT(m_pBody != NULL);
ATLASSERT(m_pBody->GetType() == CYYSType::type_Container);
vector<CYYSType>& body = m_pBody->m_Container;
if (body.size() > 1)
{
if (body.size() <= 2)
{
if (bCreate)
body.push_back(CYYSType(0l));
}
if (body.size() > 2)
bContentIsRaw = &body[2];
return body[1];
}
else if (bCreate)
{
if (body.size() == 0)
body.push_back(CYYSType());
if (body.size() == 1)
{
body.push_back(CYYSType());
body.push_back(CYYSType(0l));
}
bContentIsRaw = &body[2];
return body[1];
}
return dummy;
}
CYYSType& CMimeBody::GetField(LPCTSTR strField, bool bCreate /* = false */)
{
static CYYSType dummy;
ATLASSERT(m_pBody != NULL);
ATLASSERT(m_pBody->GetType() == CYYSType::type_Container);
vector<CYYSType>& body = m_pBody->m_Container;
if (body.size() == 0 && bCreate)
body.push_back(CYYSType());
if (body.size() > 0)
{
if (body[0].GetType() != CYYSType::type_Container && bCreate)
body[0].InitType(CYYSType::type_Container);
if (body[0].GetType() == CYYSType::type_Container)
{
// fields sind vorhanden
vector<CYYSType>& fields = body[0].m_Container;
for (vector<CYYSType>::iterator i = fields.begin(); i != fields.end(); ++i)
{
ATLASSERT(i->GetType() == CYYSType::type_Container);
ATLASSERT(i->m_Container.size() > 1);
ATLASSERT(i->m_Container[0].GetType() == CYYSType::type_String);
if (i->m_Container[0].m_sVal == strField)
{
return i->m_Container[1];
}
}
if (bCreate)
{
CYYSType field;
CYYSType name(strField);
field.Contains(name);
field += CYYSType();
fields.push_back(field);
return fields.rbegin()->m_Container[1];
}
}
}
return dummy;
}
void CMimeBody::GetFields(LPCTSTR strField, vector<CYYSType>& result)
{
ATLASSERT(m_pBody != NULL);
ATLASSERT(m_pBody->GetType() == CYYSType::type_Container);
vector<CYYSType>& body = m_pBody->m_Container;
ATLASSERT(body.size() > 0);
if (body[0].GetType() == CYYSType::type_Container)
{
// fields sind vorhanden
vector<CYYSType>& fields = body[0].m_Container;
ATLASSERT(fields.size() > 0);
for (vector<CYYSType>::iterator i = fields.begin(); i != fields.end(); ++i)
{
ATLASSERT(i->GetType() == CYYSType::type_Container);
ATLASSERT(i->m_Container.size() > 1);
ATLASSERT(i->m_Container[0].GetType() == CYYSType::type_String);
if (i->m_Container[0].m_sVal == strField)
{
result.push_back(i->m_Container[1]);
}
}
}
}
STDMETHODIMP CMimeBody::InitNew()
{
return E_NOTIMPL;
}
STDMETHODIMP CMimeBody::Load(LPSTREAM pStm)
{
return E_NOTIMPL;
}
STDMETHODIMP CMimeBody::Save(LPSTREAM pStm, BOOL fClearDirty)
{
if (pStm != NULL)
{
ATLASSERT(m_pBody != NULL);
ATLASSERT(m_pBody->GetType() == CYYSType::type_Container);
vector<CYYSType>& body = m_pBody->m_Container;
if (body.size() > 0)
{
USES_CONVERSION;
bool bMultipart = false;
long encoding = CMimeDecoder::mechanism_unknown;
string strBoundary;
// erstma alle Fields....
if (body[0].GetType() == CYYSType::type_Container)
{
// fields sind vorhanden
vector<CYYSType>& fields = body[0].m_Container;
for (vector<CYYSType>::iterator i = fields.begin(); i != fields.end(); ++i)
{
ATLASSERT(i->GetType() == CYYSType::type_Container);
ATLASSERT(i->m_Container.size() > 1);
ATLASSERT(i->m_Container[0].GetType() == CYYSType::type_String);
string& s = i->m_Container[0].m_sVal;
if (s == "Content-Type")
{
__Write(pStm, "Content-Type: ");
CYYSType& type = i->m_Container[1];
if (type.GetType() == CYYSType::type_Container && type.m_Container.size() > 1)
{
CYYSType& major = type.m_Container[0];
CYYSType& minor = type.m_Container[1];
if (major.GetType() == CYYSType::type_Long)
{
switch(major.m_nVal)
{
case CMimeDecoder::mimetype_multipart:
{
__Write(pStm, "multipart");
bMultipart = true;
__Write(pStm, "/");
if (minor.GetType() == CYYSType::type_Long)
{
switch(minor.m_nVal)
{
case CMimeDecoder::multipart_subtype_mixed:
{
__Write(pStm, "mixed");
}
break;
case CMimeDecoder::multipart_subtype_parallel:
{
__Write(pStm, "parallel");
}
break;
case CMimeDecoder::multipart_subtype_digest:
{
__Write(pStm, "digest");
}
break;
case CMimeDecoder::multipart_subtype_alternative:
{
__Write(pStm, "alternative");
}
break;
default:
{
ATLASSERT(FALSE);
}
}
}
else
{
__Write(pStm, minor);
}
}
break;
case CMimeDecoder::mimetype_text:
{
__Write(pStm, "text");
__Write(pStm, "/");
if (minor.GetType() == CYYSType::type_Long)
{
switch(minor.m_nVal)
{
case CMimeDecoder::text_subtype_plain:
{
__Write(pStm, "plain");
}
break;
case CMimeDecoder::text_subtype_html:
{
__Write(pStm, "html");
}
break;
default:
{
ATLASSERT(FALSE);
}
}
}
else
{
__Write(pStm, minor);
}
}
break;
case CMimeDecoder::mimetype_image:
{
__Write(pStm, "image");
__Write(pStm, "/");
if (minor.GetType() == CYYSType::type_Long)
{
switch(minor.m_nVal)
{
case CMimeDecoder::image_subtype_gif:
{
__Write(pStm, "gif");
}
break;
case CMimeDecoder::image_subtype_jpg:
{
__Write(pStm, "jpeg");
}
break;
default:
{
ATLASSERT(FALSE);
}
}
}
else
{
__Write(pStm, minor);
}
}
break;
case CMimeDecoder::mimetype_application:
{
__Write(pStm, "application");
__Write(pStm, "/");
if (minor.GetType() == CYYSType::type_Long)
{
switch(minor.m_nVal)
{
case CMimeDecoder::application_subtype_octet_stream:
{
__Write(pStm, "octet-stream");
}
break;
case CMimeDecoder::application_subtype_postscript:
{
__Write(pStm, "postscript");
}
break;
default:
{
ATLASSERT(FALSE);
}
}
}
else
{
__Write(pStm, minor);
}
}
break;
case CMimeDecoder::mimetype_audio:
{
__Write(pStm, "audio");
__Write(pStm, "/");
if (minor.GetType() == CYYSType::type_Long)
{
switch(minor.m_nVal)
{
case CMimeDecoder::audio_subtype_basic:
{
__Write(pStm, "basic");
}
break;
default:
{
ATLASSERT(FALSE);
}
}
}
else
{
__Write(pStm, minor);
}
}
break;
case CMimeDecoder::mimetype_video:
{
__Write(pStm, "video");
__Write(pStm, "/");
if (minor.GetType() == CYYSType::type_Long)
{
switch(minor.m_nVal)
{
case CMimeDecoder::video_subtype_mpeg:
{
__Write(pStm, "mpeg");
}
break;
default:
{
ATLASSERT(FALSE);
}
}
}
else
{
__Write(pStm, minor);
}
}
break;
case CMimeDecoder::mimetype_message:
{
__Write(pStm, "message");
__Write(pStm, "/");
if (minor.GetType() == CYYSType::type_Long)
{
switch(minor.m_nVal)
{
case CMimeDecoder::msg_subtype_rfc822:
{
__Write(pStm, "rfc822");
}
break;
case CMimeDecoder::msg_subtype_partial:
{
__Write(pStm, "partial");
}
break;
case CMimeDecoder::msg_subtype_external_body:
{
__Write(pStm, "external-body");
}
break;
default:
{
ATLASSERT(FALSE);
}
}
}
else
{
__Write(pStm, minor);
}
}
break;
default:
{
ATLASSERT(FALSE);
}
}
}
else
{
__Write(pStm, major);
__Write(pStm, "/");
__Write(pStm, minor);
}
}
else
__Write(pStm, type);
if (type.m_Container.size() > 2)
{
// Parameter
CYYSType& map = type.m_Container[2];
if (map.GetType() == CYYSType::type_ParamMap)
{
for (CYYSType::param_map::iterator p = map.m_mVal.begin(); p != map.m_mVal.end(); ++p)
{
__WriteParameter(pStm, p);
if (stricmp(p->first.c_str(), "boundary") == 0)
{
if (p->second.vt == VT_BSTR)
{
strBoundary = OLE2CT(p->second.bstrVal);
UnQuote(strBoundary);
}
}
}
}
}
__Write(pStm, "\r\n");
}
else if (s == "Content-ID")
{
__Write(pStm, "Content-ID: ");
CYYSType& id = i->m_Container[1];
__Write(pStm, id);
__Write(pStm, "\r\n");
}
else if (s == "Content-Description")
{
__Write(pStm, "Content-Description: ");
CYYSType& descr = i->m_Container[1];
__Write(pStm, descr);
__Write(pStm, "\r\n");
}
else if (s == "Content-Transfer-Encoding")
{
__Write(pStm, "Content-Transfer-Encoding: ");
CYYSType& type = i->m_Container[1];
if (type.GetType() == CYYSType::type_Long)
{
encoding = type.m_nVal;
switch(encoding)
{
case CMimeDecoder::mechanism_7bit:
{
__Write(pStm, "7bit");
}
break;
case CMimeDecoder::mechanism_quoted_printable:
{
__Write(pStm, "quoted-printable");
}
break;
case CMimeDecoder::mechanism_base64:
{
__Write(pStm, "base64");
}
break;
case CMimeDecoder::mechanism_8bit:
{
__Write(pStm, "8bit");
}
break;
case CMimeDecoder::mechanism_binary:
{
__Write(pStm, "binary");
}
break;
default:
{
ATLASSERT(FALSE);
}
}
}
else
__Write(pStm, type);
__Write(pStm, "\r\n");
}
else if (s == "ExtField")
{
CYYSType& field = i->m_Container[1];
ATLASSERT(field.GetType() == CYYSType::type_Param);
__Write(pStm, field.m_pVal.first.c_str());
__Write(pStm, ": ");
__Write(pStm, field);
__Write(pStm, "\r\n");
}
}
}
// ....dann der eigentliche Body
if (body.size() > 1)
{
bool bContentIsRaw = false;
if (body.size() > 2)
{
if (body[2].GetType() == CYYSType::type_Long)
{
bContentIsRaw = body[2].m_nVal != 0 ? true : false;
}
}
// Leerzeile!
__Write(pStm, "\r\n");
if (bMultipart)
{
ATLASSERT(body[1].GetType() == CYYSType::type_Container);
// Intro - Discard Text!
__Write(pStm, "This message is in MIME format. Since your mail reader does not understand\r\nthis format, some or all of this message may not be legible.\r\n\r\n");
// mehrere Parts
vector<CYYSType>& parts = body[1].m_Container;
for (vector<CYYSType>::iterator part = parts.begin(); part != parts.end(); ++part)
{
__Write(pStm, "--");
__Write(pStm, strBoundary.c_str());
__Write(pStm, "\r\n");
IPersistStreamPtr pBody;
if (SUCCEEDED(CMimeBody::CreateInstance(&pBody)))
{
((CMimeBody*)((IPersistStream*)pBody))->Init(part, m_pRoot);
pBody->Save(pStm, fClearDirty);
}
}
__Write(pStm, "--");
__Write(pStm, strBoundary.c_str());
__Write(pStm, "--\r\n\r\n");
}
else
{
ATLASSERT(body[1].GetType() == CYYSType::type_Bulk);
CMIMECode* pCoder = CMIMECode::GetCoderByTransferType(bContentIsRaw ? encoding : CMimeDecoder::mechanism_unknown);
if (pCoder != NULL)
{
// Stream
IStreamPtr& stream = body[1].m_streamVal;
SEEK_TO_BEGIN(stream)
pCoder->Encode(stream, pStm);
delete pCoder;
}
}
}
}
return S_OK;
}
return E_INVALIDARG;
}
STDMETHODIMP CMimeBody::get_Count(long* pcount)
{
*pcount = 0;
CComVariant vtType;
get_MajorContentType(&vtType);
if (vtType.vt == VT_I4 && vtType.lVal == CMimeDecoder::mimetype_multipart)
{
CYYSType* dummy;
CYYSType& body = GetBody(dummy);
if (body.GetType() == CYYSType::type_Container)
{
*pcount = body.m_Container.size();
}
}
else if (vtType.vt == VT_I4 && vtType.lVal == CMimeDecoder::mimetype_message)
{
*pcount = 1;
}
return S_OK;
}
STDMETHODIMP CMimeBody::get_Item(long Index, VARIANT* pvar)
{
CComVariant vtType;
get_MajorContentType(&vtType);
if (vtType.vt == VT_I4 && vtType.lVal == CMimeDecoder::mimetype_multipart)
{
CYYSType* dummy;
CYYSType& body = GetBody(dummy);
if (body.GetType() == CYYSType::type_Container)
{
if (Index < body.m_Container.size())
{
HRESULT hr;
if (pvar->vt != VT_EMPTY)
::VariantClear(pvar);
pvar->pdispVal = NULL;
if (SUCCEEDED(hr = CMimeBody::CreateInstance(&pvar->pdispVal)))
{
((CMimeBody*)pvar->pdispVal)->Init(&body.m_Container[Index], m_pRoot);
pvar->vt = VT_DISPATCH;
}
return hr;
}
}
}
else if (vtType.vt == VT_I4 && vtType.lVal == CMimeDecoder::mimetype_message)
{
if (m_pProxy != NULL)
{
return m_pProxy->get_Body(pvar);
}
}
return E_INVALIDARG;
}
STDMETHODIMP CMimeBody::AddNew(LPDISPATCH* ppResult)
{
CComVariant vtType;
get_MajorContentType(&vtType);
if (vtType.vt == VT_I4 && vtType.lVal == CMimeDecoder::mimetype_multipart)
{
CYYSType* dummy;
CYYSType& body = GetBody(dummy, true);
if (body.GetType() != CYYSType::type_Container)
body.InitType(CYYSType::type_Container);
CYYSType newPart;
newPart.InitType(CYYSType::type_Container);
newPart.m_Container.push_back(CYYSType());
body.m_Container.push_back(newPart);
m_pRoot->Modified();
if (ppResult != NULL)
{
HRESULT hr;
*ppResult = NULL;
if (SUCCEEDED(hr = CMimeBody::CreateInstance(ppResult)))
{
((CMimeBody*)*ppResult)->Init(&body.m_Container[body.m_Container.size()-1], m_pRoot);
}
return hr;
}
return S_OK;
}
return E_INVALIDARG;
}
STDMETHODIMP CMimeBody::Remove(/*[in]*/ long Index)
{
CComVariant vtType;
get_MajorContentType(&vtType);
if (vtType.vt == VT_I4 && vtType.lVal == CMimeDecoder::mimetype_multipart)
{
ATLASSERT(m_pBody != NULL);
ATLASSERT(m_pBody->GetType() == CYYSType::type_Container);
vector<CYYSType>& body = m_pBody->m_Container;
if (Index < body.size())
{
body.erase(&body[Index]);
m_pRoot->Modified();
return S_OK;
}
}
return E_INVALIDARG;
}
STDMETHODIMP CMimeBody::Clear()
{
CComVariant vtType;
get_MajorContentType(&vtType);
if (vtType.vt == VT_I4 && vtType.lVal == CMimeDecoder::mimetype_multipart)
{
ATLASSERT(m_pBody != NULL);
ATLASSERT(m_pBody->GetType() == CYYSType::type_Container);
vector<CYYSType>& body = m_pBody->m_Container;
body.clear();
m_pRoot->Modified();
return S_OK;
}
return E_INVALIDARG;
}
STDMETHODIMP CMimeBody::get_MajorContentType(VARIANT *pVal)
{
CComVariant vtResult;
CYYSType& type = GetField(_T("Content-Type"));
if (type.IsValid())
{
if (type.GetType() == CYYSType::type_Container)
{
ATLASSERT(type.m_Container.size() > 0);
vtResult = (CComVariant)type.m_Container[0];
}
else
vtResult = (CComVariant)type;
}
else
vtResult = (long)CMimeDecoder::mimetype_text;
return ::VariantCopyInd(pVal, &vtResult);
}
STDMETHODIMP CMimeBody::put_MajorContentType(VARIANT newVal)
{
CComVariant var(newVal);
CYYSType& field = GetField(_T("Content-Type"), true);
if (field.GetType() != CYYSType::type_Container)
field.Contains(CYYSType());
CYYSType& type = field.m_Container[0];
if (var.vt == VT_BSTR)
{
if (wcsicmp(var.bstrVal, L"multipart") == 0)
{
type = (long)CMimeDecoder::mimetype_multipart;
}
else if (wcsicmp(var.bstrVal, L"text") == 0)
{
type = (long)CMimeDecoder::mimetype_text;
}
else if (wcsicmp(var.bstrVal, L"image") == 0)
{
type = (long)CMimeDecoder::mimetype_image;
}
else if (wcsicmp(var.bstrVal, L"application") == 0)
{
type = (long)CMimeDecoder::mimetype_application;
}
else if (wcsicmp(var.bstrVal, L"audio") == 0)
{
type = (long)CMimeDecoder::mimetype_audio;
}
else if (wcsicmp(var.bstrVal, L"video") == 0)
{
type = (long)CMimeDecoder::mimetype_video;
}
else if (wcsicmp(var.bstrVal, L"message") == 0)
{
type = (long)CMimeDecoder::mimetype_message;
}
else
{
USES_CONVERSION;
type = OLE2CT(var.bstrVal);
}
}
else
{
if (var.vt != VT_I4)
var.ChangeType(VT_I4);
if (var.vt == VT_I4)
type = var.lVal;
else
type = (long)CMimeDecoder::mimetype_application;
}
if (type.GetType() == CYYSType::type_Long && type.m_nVal == CMimeDecoder::mimetype_multipart)
{
while (field.m_Container.size() < 3)
field += CYYSType();
CYYSType& paramMap = field.m_Container[2];
if (paramMap.GetType() != CYYSType::type_ParamMap)
paramMap.InitType(CYYSType::type_ParamMap);
CComVariant &vtBoundary = paramMap[string("boundary")];
if (vtBoundary.vt == VT_EMPTY)
{
char buf[256];
sprintf(buf, _T("\"----_=_NeXtPaRt_BoUnDaRy_%ld.%ld\""), (long)rand(), (long)rand());
vtBoundary = buf;
}
}
m_pRoot->Modified();
return S_OK;
}
STDMETHODIMP CMimeBody::get_MinorContentType(VARIANT *pVal)
{
CComVariant vtResult;
CYYSType type = GetField(_T("Content-Type"));
if (type.IsValid())
{
if (type.GetType() == CYYSType::type_Container)
{
ATLASSERT(type.m_Container.size() > 1);
vtResult = (CComVariant)type.m_Container[1];
}
else
vtResult = (CComVariant)type;
}
else
vtResult = (long)CMimeDecoder::text_subtype_plain;
return ::VariantCopyInd(pVal, &vtResult);
}
STDMETHODIMP CMimeBody::put_MinorContentType(VARIANT newVal)
{
CComVariant var(newVal);
CYYSType& field = GetField(_T("Content-Type"), true);
if (field.GetType() != CYYSType::type_Container)
{
field.Contains(CYYSType());
field += CYYSType();
}
while (field.m_Container.size() < 2)
field += CYYSType();
CYYSType& type = field.m_Container[1];
if (var.vt == VT_BSTR)
{
if (wcsicmp(var.bstrVal, L"mixed") == 0)
{
type = (long)CMimeDecoder::multipart_subtype_mixed;
}
else if (wcsicmp(var.bstrVal, L"parallel") == 0)
{
type = (long)CMimeDecoder::multipart_subtype_parallel;
}
else if (wcsicmp(var.bstrVal, L"digest") == 0)
{
type = (long)CMimeDecoder::multipart_subtype_digest;
}
else if (wcsicmp(var.bstrVal, L"alternative") == 0)
{
type = (long)CMimeDecoder::multipart_subtype_alternative;
}
else if (wcsicmp(var.bstrVal, L"plain") == 0)
{
type = (long)CMimeDecoder::text_subtype_plain;
}
else if (wcsicmp(var.bstrVal, L"html") == 0)
{
type = (long)CMimeDecoder::text_subtype_html;
}
else if (wcsicmp(var.bstrVal, L"gif") == 0)
{
type = (long)CMimeDecoder::image_subtype_gif;
}
else if (wcsicmp(var.bstrVal, L"jpg") == 0 || wcsicmp(var.bstrVal, L"jpeg") == 0)
{
type = (long)CMimeDecoder::image_subtype_jpg;
}
else if (wcsnicmp(var.bstrVal, L"octet", 5) == 0)
{
type = (long)CMimeDecoder::application_subtype_octet_stream;
}
else if (wcsicmp(var.bstrVal, L"postscript") == 0)
{
type = (long)CMimeDecoder::application_subtype_postscript;
}
else if (wcsicmp(var.bstrVal, L"basic") == 0)
{
type = (long)CMimeDecoder::audio_subtype_basic;
}
else if (wcsicmp(var.bstrVal, L"mpg") == 0 || wcsicmp(var.bstrVal, L"mpeg") == 0)
{
type = (long)CMimeDecoder::video_subtype_mpeg;
}
else if (wcsicmp(var.bstrVal, L"rfc822") == 0)
{
type = (long)CMimeDecoder::msg_subtype_rfc822;
}
else if (wcsicmp(var.bstrVal, L"partial") == 0)
{
type = (long)CMimeDecoder::msg_subtype_partial;
}
else if (wcsicmp(var.bstrVal, L"external-body") == 0)
{
type = (long)CMimeDecoder::msg_subtype_external_body;
}
else
{
USES_CONVERSION;
type = OLE2CT(var.bstrVal);
}
}
else
{
if (var.vt != VT_I4)
var.ChangeType(VT_I4);
if (var.vt == VT_I4)
type = var.lVal;
else
type = (long)0;
}
m_pRoot->Modified();
return S_OK;
}
STDMETHODIMP CMimeBody::get_FileName(BSTR *pVal)
{
CComVariant vtResult;
CYYSType type = GetField(_T("Content-Type"));
if (type.IsValid())
{
if (type.GetType() == CYYSType::type_Container)
{
if (type.m_Container.size() > 2)
{
CYYSType& paramMap = type.m_Container[2];
if (paramMap.GetType() == CYYSType::type_ParamMap)
{
for (CYYSType::param_map::iterator p = paramMap.m_mVal.begin(); p != paramMap.m_mVal.end(); ++p)
{
if (stricmp(p->first.c_str(), "name") == 0)
{
vtResult = p->second;
break;
}
}
}
}
}
}
if (vtResult.vt != VT_BSTR)
vtResult.ChangeType(VT_BSTR);
if (vtResult.vt == VT_BSTR && vtResult.bstrVal != NULL)
{
USES_CONVERSION;
string str(OLE2CT(vtResult.bstrVal));
UnQuote(str);
*pVal = ::SysAllocString(T2OLE(str.c_str()));
}
else
{
*pVal = ::SysAllocString(L"");
}
return S_OK;
}
STDMETHODIMP CMimeBody::put_FileName(BSTR newVal)
{
USES_CONVERSION;
CYYSType& field = GetField(_T("Content-Type"), true);
if (field.GetType() != CYYSType::type_Container)
{
field.Contains(CYYSType());
field += CYYSType();
field += CYYSType();
}
while (field.m_Container.size() < 3)
field += CYYSType();
CYYSType& paramMap = field.m_Container[2];
if (paramMap.GetType() != CYYSType::type_ParamMap)
paramMap.InitType(CYYSType::type_ParamMap);
string str(OLE2CT(newVal));
QuoteInline(str);
str = "\"" + str + "\"";
paramMap[string(_T("name"))] = str.c_str();
m_pRoot->Modified();
return S_OK;
}
STDMETHODIMP CMimeBody::get_ExtField(BSTR strName, VARIANT *pVal)
{
USES_CONVERSION;
vector<CYYSType> fields;
CComVariant vtResult(L"");
GetFields(_T("ExtField"), fields);
LPCTSTR t_strName = OLE2CT(strName);
for (vector<CYYSType>::iterator i = fields.begin(); i != fields.end(); ++i)
{
ATLASSERT(i->GetType() == CYYSType::type_Param);
if (_tcsicmp(i->m_pVal.first.c_str(), t_strName) == 0)
{
vtResult = i->m_pVal.second;
break;
}
}
return ::VariantCopyInd(pVal, &vtResult);
}
STDMETHODIMP CMimeBody::put_ExtField(BSTR strName, VARIANT newVal)
{
USES_CONVERSION;
ATLASSERT(m_pBody != NULL);
ATLASSERT(m_pBody->GetType() == CYYSType::type_Container);
vector<CYYSType>& body = m_pBody->m_Container;
if (body.size() == 0)
body.push_back(CYYSType());
if (body[0].GetType() != CYYSType::type_Container)
body[0].InitType(CYYSType::type_Container);
CYYSType& fields = body[0];
CYYSType field;
field.InitType(CYYSType::type_Container);
field += CYYSType(_T("ExtField"));
field += CYYSType::param(OLE2CT(strName), newVal);
fields += field;
m_pRoot->Modified();
return S_OK;
}
STDMETHODIMP CMimeBody::get_Encoding(VARIANT *pVal)
{
CYYSType& type = GetField(_T("Content-Transfer-Encoding"));
CComVariant vtResult;
if (type.IsValid())
vtResult = (CComVariant)type;
return ::VariantCopyInd(pVal, &vtResult);
}
STDMETHODIMP CMimeBody::put_Encoding(VARIANT newVal)
{
CComVariant var(newVal);
CYYSType& type = GetField(_T("Content-Transfer-Encoding"), true);
if (var.vt == VT_BSTR)
{
if (wcsicmp(var.bstrVal, L"mixed") == 0)
{
type = (long)CMimeDecoder::mechanism_7bit;
}
else if (wcsnicmp(var.bstrVal, L"quoted", 6) == 0)
{
type = (long)CMimeDecoder::mechanism_quoted_printable;
}
else if (wcsicmp(var.bstrVal, L"base64") == 0)
{
type = (long)CMimeDecoder::mechanism_base64;
}
else if (wcsicmp(var.bstrVal, L"8bit") == 0)
{
type = (long)CMimeDecoder::mechanism_8bit;
}
else if (wcsicmp(var.bstrVal, L"binary") == 0)
{
type = (long)CMimeDecoder::mechanism_binary;
}
else
{
type = (long)CMimeDecoder::mechanism_7bit;
}
}
else
{
if (var.vt != VT_I4)
var.ChangeType(VT_I4);
if (var.vt == VT_I4)
type = var.lVal;
else
type = (long)CMimeDecoder::mechanism_7bit;
}
m_pRoot->Modified();
return S_OK;
}
STDMETHODIMP CMimeBody::get_Description(VARIANT *pVal)
{
CComVariant vtResult;
CYYSType descr = GetField(_T("Content-Description"));
if (descr.IsValid())
{
vtResult = (CComVariant)descr;
}
return ::VariantCopyInd(pVal, &vtResult);
}
STDMETHODIMP CMimeBody::put_Description(VARIANT newVal)
{
CYYSType& descr = GetField(_T("Content-Description"), true);
descr = newVal;
m_pRoot->Modified();
return S_OK;
}
STDMETHODIMP CMimeBody::get_ContentID(VARIANT *pVal)
{
CComVariant vtResult;
CYYSType id = GetField(_T("Content-ID"));
if (id.IsValid())
{
vtResult = (CComVariant)id;
}
return ::VariantCopyInd(pVal, &vtResult);
}
STDMETHODIMP CMimeBody::put_ContentID(VARIANT newVal)
{
CYYSType& id = GetField(_T("Content-ID"), true);
id = newVal;
m_pRoot->Modified();
return S_OK;
}
STDMETHODIMP CMimeBody::ExportAsFile(BSTR Path, VARIANT_BOOL* pbvarResult)
{
USES_CONVERSION;
*pbvarResult = VARIANT_FALSE;
HANDLE hFile = ::CreateFile(OLE2CT(Path), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
CFileSystemStream* pStream = new CFileSystemStream(hFile);
Export(pStream, pbvarResult);
pStream->Release();
}
return S_OK;
}
STDMETHODIMP CMimeBody::ImportFromFile(BSTR Path, VARIANT_BOOL StreamByReference, VARIANT_BOOL* pbvarResult)
{
USES_CONVERSION;
*pbvarResult = VARIANT_FALSE;
HANDLE hFile = ::CreateFile(OLE2CT(Path), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
CFileSystemStream* pStream = new CFileSystemStream(hFile);
Import(pStream, StreamByReference, pbvarResult);
pStream->Release();
}
return S_OK;
}
STDMETHODIMP CMimeBody::Export(LPUNKNOWN pStream, VARIANT_BOOL *pbvarResult)
{
CYYSType& type = GetField(_T("Content-Transfer-Encoding"));
*pbvarResult = VARIANT_FALSE;
if (type.GetType() != CYYSType::type_Long)
type = (long)CMimeDecoder::mechanism_unknown;
if (type.IsValid())
{
if (type.GetType() == CYYSType::type_Long)
{
CYYSType* bContentIsRaw = NULL;
CYYSType& body = GetBody(bContentIsRaw);
if (body.GetType() == CYYSType::type_Bulk)
{
IStreamPtr pDest;
if (SUCCEEDED(pStream->QueryInterface(&pDest)))
{
long encoding = bContentIsRaw != NULL && bContentIsRaw->m_nVal ? CMimeDecoder::mechanism_unknown : (long)type;
CMIMECode* pCoder = CMIMECode::GetCoderByTransferType(encoding);
if (pCoder != NULL)
{
SEEK_TO_BEGIN(body.m_streamVal)
pCoder->Decode(body.m_streamVal, pDest);
*pbvarResult = VARIANT_TRUE;
delete pCoder;
}
}
}
}
}
return S_OK;
}
STDMETHODIMP CMimeBody::Import(LPUNKNOWN pStream, VARIANT_BOOL StreamByReference, VARIANT_BOOL *pbvarResult)
{
*pbvarResult = VARIANT_FALSE;
IStreamPtr pSource;
if (SUCCEEDED(pStream->QueryInterface(&pSource)))
{
CYYSType* bContentIsRaw = NULL;
CYYSType& body = GetBody(bContentIsRaw, true);
if (body.GetType() != CYYSType::type_Bulk)
body.InitType(CYYSType::type_Bulk);
if (body.GetType() == CYYSType::type_Bulk)
{
ATLASSERT(bContentIsRaw != NULL);
*bContentIsRaw = 1l;
if (StreamByReference != VARIANT_FALSE)
{
body.m_streamVal = pSource;
}
else
{
long encoding = CMimeDecoder::mechanism_unknown;
CMIMECode* pCoder = CMIMECode::GetCoderByTransferType(encoding);
if (pCoder != NULL)
{
SETSIZEOF_STREAM(0, body.m_streamVal)
pCoder->Decode(pSource, body.m_streamVal);
delete pCoder;
}
}
m_pRoot->Modified();
*pbvarResult = VARIANT_TRUE;
}
}
return S_OK;
}
STDMETHODIMP CMimeBody::get_Value(BSTR *pVal)
{
USES_CONVERSION;
CISSHelper helper;
string strResult;
VARIANT_BOOL result;
Export(&helper, &result);
if (result != VARIANT_FALSE)
{
char buf[4096];
DWORD dwRead;
SEEK_TO_BEGIN((&helper))
do
{
memset(buf, 0, sizeof(buf));
helper.Read(buf, 4095, &dwRead);
if (dwRead == 0)
break;
strResult += buf;
}
while(true);
}
*pVal = ::SysAllocString(T2OLE(strResult.c_str()));
return S_OK;
}
STDMETHODIMP CMimeBody::put_Value(BSTR newVal)
{
USES_CONVERSION;
CISSHelper* pHelper = new CISSHelper(true);
pHelper->Write(OLE2CA(newVal), wcslen(newVal), NULL);
VARIANT_BOOL result;
return Import(pHelper, VARIANT_TRUE, &result);
}
STDMETHODIMP CMimeBody::get_EmbeddedMessage(LPDISPATCH *pVal)
{
if (m_pProxy != NULL)
{
return m_pProxy->QueryInterface(__uuidof(IDispatch), (void**)pVal);
}
else
*pVal = NULL;
return S_OK;
}