Click here to Skip to main content
15,896,063 members
Articles / Desktop Programming / ATL

En/Decode MIME-Content with MimeSniffer

Rate me:
Please Sign up or sign in to vote.
4.88/5 (26 votes)
2 Dec 20022 min read 377.1K   7K   74  
RFC-compliant Mime-En/Decoder
// 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;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions