--- /dev/null
+//////////////////////////////////////////////////////////////////////\r
+//\r
+// MIME message encoding/decoding\r
+//\r
+// Jeff Lee\r
+// Dec 11, 2000\r
+//\r
+//////////////////////////////////////////////////////////////////////\r
+\r
+#if !defined(_MIME_H)\r
+#define _MIME_H\r
+\r
+#if _MSC_VER > 1000\r
+#pragma once\r
+#endif // _MSC_VER > 1000\r
+\r
+#include <string>\r
+#include <list>\r
+using namespace std;\r
+\r
+// RFC 1521 - Mechanisms for Specifying and Describing the Format of Internet Message Bodies\r
+// RFC 2045 - Format of Internet Message Bodies\r
+// RFC 2046 - Media Types\r
+// RFC 2047 - Message Header Extensions for Non-ASCII Text\r
+// RFC 2049 - Conformance Criteria and Examples\r
+// RFC 822 - Standard For The Format of ARPA Internet Text Message\r
+\r
+class CMimeConst\r
+{\r
+public:\r
+ // field names\r
+ static inline const char* MimeVersion() { return "MIME-Version"; }\r
+ static inline const char* ContentType() { return "Content-Type"; }\r
+ static inline const char* TransferEncoding() { return "Content-Transfer-Encoding"; }\r
+ static inline const char* ContentID() { return "Content-ID"; }\r
+ static inline const char* ContentDescription() { return "Content-Description"; }\r
+ static inline const char* ContentDisposition() { return "Content-Disposition"; }\r
+\r
+ // parameter names\r
+ static inline const char* Charset() { return "charset"; }\r
+ static inline const char* Name() { return "name"; }\r
+ static inline const char* Filename() { return "filename"; }\r
+ static inline const char* Boundary() { return "boundary"; }\r
+\r
+ // parameter values\r
+ static inline const char* Encoding7Bit() { return "7bit"; }\r
+ static inline const char* Encoding8Bit() { return "8bit"; }\r
+ static inline const char* EncodingBinary() { return "binary"; }\r
+ static inline const char* EncodingQP() { return "quoted-printable"; }\r
+ static inline const char* EncodingBase64() { return "base64"; }\r
+\r
+ static inline const char* MediaText() { return "text"; }\r
+ static inline const char* MediaImage() { return "image"; }\r
+ static inline const char* MediaAudio() { return "audio"; }\r
+ static inline const char* MediaVedio() { return "vedio"; }\r
+ static inline const char* MediaApplication() { return "application"; }\r
+ static inline const char* MediaMultiPart() { return "multipart"; }\r
+ static inline const char* MediaMessage() { return "message"; }\r
+};\r
+\r
+//////////////////////////////////////////////////////////////////////\r
+// CMimeField class - Represents a field of a MIME body part header\r
+//////////////////////////////////////////////////////////////////////\r
+class CMimeField\r
+{\r
+public:\r
+ CMimeField() {}\r
+ ~CMimeField() {}\r
+\r
+public:\r
+ void SetName(const char* pszName);\r
+ const char* GetName() const;\r
+ void SetValue(const char* pszValue);\r
+ const char* GetValue() const;\r
+ void GetValue(string& strValue) const;\r
+ void SetParameter(const char* pszAttr, const char* pszValue);\r
+ bool GetParameter(const char* pszAttr, string& strValue) const;\r
+ void SetCharset(const char* pszCharset);\r
+ const char* GetCharset() const;\r
+\r
+ void Clear();\r
+ int GetLength() const;\r
+ int Store(char* pszData, int nMaxSize) const;\r
+ int Load(const char* pszData, int nDataSize);\r
+\r
+private:\r
+ string m_strName; // field name\r
+ string m_strValue; // field value\r
+ string m_strCharset; // charset for non-ascii text\r
+\r
+private:\r
+ bool FindParameter(const char* pszAttr, int& nPos, int& nSize) const;\r
+};\r
+\r
+inline void CMimeField::SetName(const char* pszName)\r
+{ m_strName = pszName; }\r
+\r
+inline const char* CMimeField::GetName() const\r
+{ return m_strName.data(); }\r
+\r
+inline void CMimeField::SetValue(const char* pszValue)\r
+{ m_strValue = pszValue; }\r
+\r
+inline const char* CMimeField::GetValue() const\r
+{ return m_strValue.data(); }\r
+\r
+inline void CMimeField::SetCharset(const char* pszCharset)\r
+{ m_strCharset = pszCharset; }\r
+\r
+inline const char* CMimeField::GetCharset() const\r
+{ return m_strCharset.c_str(); }\r
+\r
+inline void CMimeField::Clear()\r
+{ m_strName.clear(); m_strValue.clear(); m_strCharset.clear(); }\r
+\r
+//////////////////////////////////////////////////////////////////////\r
+// CMimeHeader class - Represents the header of a MIME body part\r
+//////////////////////////////////////////////////////////////////////\r
+class CMimeHeader\r
+{\r
+public:\r
+ CMimeHeader() {}\r
+ virtual ~CMimeHeader() { Clear(); }\r
+\r
+public:\r
+ enum MediaType\r
+ {\r
+ MEDIA_TEXT, MEDIA_IMAGE, MEDIA_AUDIO, MEDIA_VEDIO, MEDIA_APPLICATION,\r
+ MEDIA_MULTIPART, MEDIA_MESSAGE,\r
+ MEDIA_UNKNOWN\r
+ };\r
+ MediaType GetMediaType() const;\r
+\r
+ // set/get the values of header fields\r
+ void SetField(const CMimeField& field);\r
+ const CMimeField* GetField(const char* pszFieldName) const;\r
+ CMimeField* GetField(const char* pszFieldName);\r
+ void SetFieldValue(const char* pszFieldName, const char* pszFieldValue, const char* pszCharset=NULL);\r
+ const char* GetFieldValue(const char* pszFieldName) const;\r
+ bool SetParameter(const char* pszFieldName, const char* pszAttr, const char* pszValue);\r
+ string GetParameter(const char* pszFieldName, const char* pszAttr) const;\r
+ void SetFieldCharset(const char* pszFieldName, const char* pszCharset);\r
+ const char* GetFieldCharset(const char* pszFieldName) const;\r
+\r
+ // helper functions for standard body part fields\r
+ void SetContentType(const char* pszValue, const char* pszCharset=NULL);\r
+ const char* GetContentType() const; // Content-Type: mediatype/subtype\r
+ string GetMainType() const;\r
+ string GetSubType() const;\r
+ void SetCharset(const char* pszCharset); // Content-Type: text/...; charset=...\r
+ string GetCharset() const;\r
+ void SetName(const char* pszName); // Content-Type: image/...; name=...\r
+ string GetName() const;\r
+ void SetBoundary(const char* pszBoundary=NULL); // Content-Type: multipart/...; boundary=...\r
+ string GetBoundary() const;\r
+\r
+ void SetTransferEncoding(const char* pszValue);\r
+ const char* GetTransferEncoding() const; // Content-Transfer-Encoding: ...\r
+ void SetDisposition(const char* pszValue, const char* pszCharset=NULL);\r
+ const char* GetDisposition() const; // Content-Disposition: ...\r
+ string GetFilename() const; // Content-Disposition: ...; filename=...\r
+ void SetDescription(const char* pszValue, const char* pszCharset=NULL);\r
+ const char* GetDescription() const; // Content-Description: ...\r
+\r
+ typedef list<CMimeField> CFieldList;\r
+ CFieldList& Fields() { return m_listFields; }\r
+\r
+public:\r
+ // overrides\r
+ virtual void Clear();\r
+ virtual int GetLength() const;\r
+ // serialization\r
+ virtual int Store(char* pszData, int nMaxSize) const;\r
+ virtual int Load(const char* pszData, int nDataSize);\r
+\r
+protected:\r
+ list<CMimeField> m_listFields; // list of all header fields\r
+ list<CMimeField>::const_iterator FindField(const char* pszFieldName) const;\r
+ list<CMimeField>::iterator FindField(const char* pszFieldName);\r
+\r
+ struct MediaTypeCvt\r
+ {\r
+ int nMediaType; // media type\r
+ const char* pszSubType; // subtype\r
+ const char* pszFileExt; // file extension name\r
+ };\r
+ static const MediaTypeCvt m_TypeCvtTable[];\r
+ static const char* m_TypeTable[];\r
+\r
+private:\r
+ CMimeHeader& operator=(const CMimeHeader&); // forbid operator =\r
+};\r
+\r
+// add a new field or update an existing field\r
+inline void CMimeHeader::SetField(const CMimeField& field)\r
+{\r
+ list<CMimeField>::iterator it = FindField(field.GetName());\r
+ if (it != m_listFields.end())\r
+ *it = field;\r
+ else\r
+ m_listFields.push_back(field);\r
+}\r
+\r
+// find a field by name\r
+inline const CMimeField* CMimeHeader::GetField(const char* pszFieldName) const\r
+{\r
+ list<CMimeField>::const_iterator it = FindField(pszFieldName);\r
+ if (it != m_listFields.end())\r
+ return &(*it);\r
+ return NULL;\r
+}\r
+\r
+inline CMimeField* CMimeHeader::GetField(const char* pszFieldName)\r
+{\r
+ list<CMimeField>::iterator it = FindField(pszFieldName);\r
+ if (it != m_listFields.end())\r
+ return &(*it);\r
+ return NULL;\r
+}\r
+\r
+// add a new field or update an existing field\r
+inline void CMimeHeader::SetFieldValue(const char* pszFieldName, const char* pszFieldValue, const char* pszCharset)\r
+{\r
+ CMimeField fd;\r
+ fd.SetName(pszFieldName);\r
+ fd.SetValue(pszFieldValue);\r
+ if (pszCharset != NULL)\r
+ fd.SetCharset(pszCharset);\r
+ SetField(fd);\r
+}\r
+\r
+inline const char* CMimeHeader::GetFieldValue(const char* pszFieldName) const\r
+{\r
+ const CMimeField* pfd = GetField(pszFieldName);\r
+ return pfd != NULL ? pfd->GetValue() : NULL;\r
+}\r
+\r
+inline void CMimeHeader::SetFieldCharset(const char* pszFieldName, const char* pszCharset)\r
+{\r
+ CMimeField *pfd = GetField(pszFieldName);\r
+ if (pfd)\r
+ pfd->SetCharset(pszCharset);\r
+ else\r
+ {\r
+ CMimeField fd;\r
+ fd.SetName(pszFieldName);\r
+ fd.SetCharset(pszCharset);\r
+ SetField(fd);\r
+ }\r
+}\r
+\r
+inline const char* CMimeHeader::GetFieldCharset(const char* pszFieldName) const\r
+{\r
+ const CMimeField* pfd = GetField(pszFieldName);\r
+ return pfd != NULL ? pfd->GetCharset() : NULL;\r
+}\r
+\r
+inline bool CMimeHeader::SetParameter(const char* pszFieldName, const char* pszAttr, const char* pszValue)\r
+{\r
+ CMimeField *pfd = GetField(pszFieldName);\r
+ if (pfd)\r
+ {\r
+ pfd->SetParameter(pszAttr, pszValue);\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+\r
+inline string CMimeHeader::GetParameter(const char* pszFieldName, const char* pszAttr) const\r
+{\r
+ string strVal;\r
+ const CMimeField *pfd = GetField(pszFieldName);\r
+ if (pfd)\r
+ pfd->GetParameter(pszAttr, strVal);\r
+ return strVal;\r
+}\r
+\r
+inline void CMimeHeader::SetContentType(const char* pszValue, const char* pszCharset)\r
+{ SetFieldValue(CMimeConst::ContentType(), pszValue, pszCharset); }\r
+\r
+inline const char* CMimeHeader::GetContentType() const\r
+{ return GetFieldValue(CMimeConst::ContentType()); }\r
+\r
+inline string CMimeHeader::GetCharset() const\r
+{ return GetParameter(CMimeConst::ContentType(), CMimeConst::Charset()); }\r
+\r
+inline string CMimeHeader::GetName() const\r
+{ return GetParameter(CMimeConst::ContentType(), CMimeConst::Name()); }\r
+\r
+inline string CMimeHeader::GetBoundary() const\r
+{ return GetParameter(CMimeConst::ContentType(), CMimeConst::Boundary()); }\r
+\r
+inline void CMimeHeader::SetTransferEncoding(const char* pszValue)\r
+{ SetFieldValue(CMimeConst::TransferEncoding(), pszValue); }\r
+\r
+inline const char* CMimeHeader::GetTransferEncoding() const\r
+{ return GetFieldValue(CMimeConst::TransferEncoding()); }\r
+\r
+// Content-Disposition header field specifies how to present this body part. it could be\r
+// inline or attachment. 'inline' indicates this body part should be displayed in the main body;\r
+// 'attachment' indicates it is separate from the main body. (RFC 2183)\r
+\r
+inline void CMimeHeader::SetDisposition(const char* pszValue, const char* pszCharset)\r
+{ SetFieldValue(CMimeConst::ContentDisposition(), pszValue, pszCharset); }\r
+\r
+inline const char* CMimeHeader::GetDisposition() const\r
+{ return GetFieldValue(CMimeConst::ContentDisposition()); }\r
+\r
+inline string CMimeHeader::GetFilename() const\r
+{ return GetParameter(CMimeConst::ContentDisposition(), CMimeConst::Filename()); }\r
+\r
+inline void CMimeHeader::SetDescription(const char* pszValue, const char* pszCharset)\r
+{ SetFieldValue(CMimeConst::ContentDescription(), pszValue, pszCharset); }\r
+\r
+inline const char* CMimeHeader::GetDescription() const\r
+{ return GetFieldValue(CMimeConst::ContentDescription()); }\r
+\r
+//////////////////////////////////////////////////////////////////////\r
+// CMimeBody class - Represents a body part in a MIME message\r
+//////////////////////////////////////////////////////////////////////\r
+class CMimeMessage;\r
+class CMimeBody : public CMimeHeader\r
+{\r
+protected:\r
+ CMimeBody() : // instantiate a CMimeBody object explicitly is not allowed. call CreatePart()\r
+ m_pbText(NULL),\r
+ m_nTextSize(0) {}\r
+ virtual ~CMimeBody() { Clear(); }\r
+\r
+public:\r
+ int GetContentLength() const;\r
+ const unsigned char* GetContent() const;\r
+\r
+ // operations for 'text' or 'message' media\r
+ bool IsText() const;\r
+ int SetText(const char* pbText, int nLength=0);\r
+ int GetText(char* pbText, int nMaxSize);\r
+ int GetText(string& strText);\r
+\r
+ // operations for 'message' media\r
+ bool IsMessage() const;\r
+ bool SetMessage(const CMimeMessage* pMM);\r
+ void GetMessage(CMimeMessage* pMM) const;\r
+\r
+ // operations for 'image/audio/vedio/application' (attachment) media\r
+ bool IsAttachment() const;\r
+ bool ReadFromFile(const char* pszFilename);\r
+ bool WriteToFile(const char* pszFilename);\r
+\r
+ // operations for 'multipart' media\r
+ bool IsMultiPart() const;\r
+ void DeleteAll();\r
+ CMimeBody* CreatePart(const char* pszMediaType=NULL, CMimeBody* pWhere=NULL);\r
+ void ErasePart(CMimeBody* pBP);\r
+ CMimeBody* FindFirstPart();\r
+ CMimeBody* FindNextPart();\r
+\r
+ typedef list<CMimeBody*> CBodyList;\r
+ int GetBodyPartList(CBodyList& rList) const;\r
+ int GetAttachmentList(CBodyList& rList) const;\r
+\r
+public:\r
+ // overrides\r
+ virtual void Clear();\r
+ virtual int GetLength() const;\r
+ // serialization\r
+ virtual int Store(char* pszData, int nMaxSize) const;\r
+ virtual void Store(std::string &str) const;\r
+ virtual int Load(const char* pszData, int nDataSize);\r
+\r
+protected:\r
+ unsigned char* m_pbText; // content (text) of the body part\r
+ int m_nTextSize; // length of content\r
+ CBodyList m_listBodies; // list of all child body parts\r
+ CBodyList::iterator m_itFind;\r
+\r
+protected:\r
+ bool AllocateBuffer(int nBufSize);\r
+ void FreeBuffer();\r
+\r
+ friend class CMimeEnvironment;\r
+};\r
+\r
+inline int CMimeBody::GetContentLength() const\r
+{ return m_nTextSize; }\r
+\r
+inline const unsigned char* CMimeBody::GetContent() const\r
+{ return m_pbText; }\r
+\r
+inline bool CMimeBody::IsText() const\r
+{ return GetMediaType() == MEDIA_TEXT; }\r
+\r
+inline bool CMimeBody::IsMessage() const\r
+{ return GetMediaType() == MEDIA_MESSAGE; }\r
+\r
+inline bool CMimeBody::IsAttachment() const\r
+{ return GetName().size() > 0; }\r
+\r
+inline bool CMimeBody::IsMultiPart() const\r
+{ return GetMediaType() == MEDIA_MULTIPART; }\r
+\r
+inline CMimeBody* CMimeBody::FindFirstPart()\r
+{\r
+ m_itFind = m_listBodies.begin();\r
+ return FindNextPart();\r
+}\r
+\r
+inline CMimeBody* CMimeBody::FindNextPart()\r
+{\r
+ if (m_itFind != m_listBodies.end())\r
+ return *m_itFind++;\r
+ return NULL;\r
+}\r
+\r
+inline bool CMimeBody::AllocateBuffer(int nBufSize)\r
+{\r
+ FreeBuffer();\r
+ m_pbText = new unsigned char[nBufSize];\r
+ if (!m_pbText) return false;\r
+ m_nTextSize = nBufSize;\r
+ return true;\r
+}\r
+\r
+inline void CMimeBody::FreeBuffer()\r
+{\r
+ delete []m_pbText;\r
+ m_pbText = NULL;\r
+ m_nTextSize = 0;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////\r
+// CMimeMessage - Represents a MIME message\r
+//////////////////////////////////////////////////////////////////////\r
+class CMimeMessage : public CMimeBody\r
+{\r
+public:\r
+ CMimeMessage() { /*SetVersion();*/ }\r
+ virtual ~CMimeMessage() { Clear(); }\r
+\r
+public:\r
+ // set/get RFC 822 message header fields\r
+ void SetFrom(const char* pszFrom, const char* pszCharset=NULL);\r
+ const char* GetFrom() const;\r
+ void SetTo(const char* pszTo, const char* pszCharset=NULL);\r
+ const char* GetTo() const;\r
+ void SetCc(const char* pszCc, const char* pszCharset=NULL);\r
+ const char* GetCc() const;\r
+ void SetBcc(const char* pszBcc, const char* pszCharset=NULL);\r
+ const char* GetBcc() const;\r
+\r
+ void SetSubject(const char* pszSubject, const char* pszCharset=NULL);\r
+ const char* GetSubject() const;\r
+\r
+ void SetDate();\r
+ void SetDate(int nYear, int nMonth, int nDay, int nHour, int nMinute, int nSecond);\r
+ const char* GetDate() const;\r
+ void SetVersion();\r
+};\r
+\r
+inline void CMimeMessage::SetFrom(const char* pszAddr, const char* pszCharset)\r
+{ SetFieldValue("From", pszAddr, pszCharset); }\r
+\r
+inline const char* CMimeMessage::GetFrom() const\r
+{ return GetFieldValue("From"); }\r
+\r
+inline void CMimeMessage::SetTo(const char* pszAddr, const char* pszCharset)\r
+{ SetFieldValue("To", pszAddr, pszCharset); }\r
+\r
+inline const char* CMimeMessage::GetTo() const\r
+{ return GetFieldValue("To"); }\r
+\r
+inline void CMimeMessage::SetCc(const char* pszAddr, const char* pszCharset)\r
+{ SetFieldValue("CC", pszAddr, pszCharset); }\r
+\r
+inline const char* CMimeMessage::GetCc() const\r
+{ return GetFieldValue("CC"); }\r
+\r
+inline void CMimeMessage::SetBcc(const char* pszAddr, const char* pszCharset)\r
+{ SetFieldValue("BCC", pszAddr, pszCharset); }\r
+\r
+inline const char* CMimeMessage::GetBcc() const\r
+{ return GetFieldValue("BCC"); }\r
+\r
+inline void CMimeMessage::SetSubject(const char* pszSubject, const char* pszCharset)\r
+{ SetFieldValue("Subject", pszSubject, pszCharset); }\r
+\r
+inline const char* CMimeMessage::GetSubject() const\r
+{ return GetFieldValue("Subject"); }\r
+\r
+inline const char* CMimeMessage::GetDate() const\r
+{ return GetFieldValue("Date"); }\r
+\r
+inline void CMimeMessage::SetVersion()\r
+{ SetFieldValue(CMimeConst::MimeVersion(), "1.0"); }\r
+\r
+#endif // !defined(_MIME_H)\r