1 //////////////////////////////////////////////////////////////////////
\r
3 // MIME message encoding/decoding
\r
8 //////////////////////////////////////////////////////////////////////
\r
10 #if !defined(_MIME_H)
\r
15 #endif // _MSC_VER > 1000
\r
19 using namespace std;
\r
21 // RFC 1521 - Mechanisms for Specifying and Describing the Format of Internet Message Bodies
\r
22 // RFC 2045 - Format of Internet Message Bodies
\r
23 // RFC 2046 - Media Types
\r
24 // RFC 2047 - Message Header Extensions for Non-ASCII Text
\r
25 // RFC 2049 - Conformance Criteria and Examples
\r
26 // RFC 822 - Standard For The Format of ARPA Internet Text Message
\r
32 static inline const char* MimeVersion() { return "MIME-Version"; }
\r
33 static inline const char* ContentType() { return "Content-Type"; }
\r
34 static inline const char* TransferEncoding() { return "Content-Transfer-Encoding"; }
\r
35 static inline const char* ContentID() { return "Content-ID"; }
\r
36 static inline const char* ContentDescription() { return "Content-Description"; }
\r
37 static inline const char* ContentDisposition() { return "Content-Disposition"; }
\r
40 static inline const char* Charset() { return "charset"; }
\r
41 static inline const char* Name() { return "name"; }
\r
42 static inline const char* Filename() { return "filename"; }
\r
43 static inline const char* Boundary() { return "boundary"; }
\r
46 static inline const char* Encoding7Bit() { return "7bit"; }
\r
47 static inline const char* Encoding8Bit() { return "8bit"; }
\r
48 static inline const char* EncodingBinary() { return "binary"; }
\r
49 static inline const char* EncodingQP() { return "quoted-printable"; }
\r
50 static inline const char* EncodingBase64() { return "base64"; }
\r
52 static inline const char* MediaText() { return "text"; }
\r
53 static inline const char* MediaImage() { return "image"; }
\r
54 static inline const char* MediaAudio() { return "audio"; }
\r
55 static inline const char* MediaVedio() { return "vedio"; }
\r
56 static inline const char* MediaApplication() { return "application"; }
\r
57 static inline const char* MediaMultiPart() { return "multipart"; }
\r
58 static inline const char* MediaMessage() { return "message"; }
\r
61 //////////////////////////////////////////////////////////////////////
\r
62 // CMimeField class - Represents a field of a MIME body part header
\r
63 //////////////////////////////////////////////////////////////////////
\r
71 void SetName(const char* pszName);
\r
72 const char* GetName() const;
\r
73 void SetValue(const char* pszValue);
\r
74 const char* GetValue() const;
\r
75 void GetValue(string& strValue) const;
\r
76 void SetParameter(const char* pszAttr, const char* pszValue);
\r
77 bool GetParameter(const char* pszAttr, string& strValue) const;
\r
78 void SetCharset(const char* pszCharset);
\r
79 const char* GetCharset() const;
\r
82 int GetLength() const;
\r
83 int Store(char* pszData, int nMaxSize) const;
\r
84 int Load(const char* pszData, int nDataSize);
\r
87 string m_strName; // field name
\r
88 string m_strValue; // field value
\r
89 string m_strCharset; // charset for non-ascii text
\r
92 bool FindParameter(const char* pszAttr, int& nPos, int& nSize) const;
\r
95 inline void CMimeField::SetName(const char* pszName)
\r
96 { m_strName = pszName; }
\r
98 inline const char* CMimeField::GetName() const
\r
99 { return m_strName.data(); }
\r
101 inline void CMimeField::SetValue(const char* pszValue)
\r
102 { m_strValue = pszValue; }
\r
104 inline const char* CMimeField::GetValue() const
\r
105 { return m_strValue.data(); }
\r
107 inline void CMimeField::SetCharset(const char* pszCharset)
\r
108 { m_strCharset = pszCharset; }
\r
110 inline const char* CMimeField::GetCharset() const
\r
111 { return m_strCharset.c_str(); }
\r
113 inline void CMimeField::Clear()
\r
114 { m_strName.clear(); m_strValue.clear(); m_strCharset.clear(); }
\r
116 //////////////////////////////////////////////////////////////////////
\r
117 // CMimeHeader class - Represents the header of a MIME body part
\r
118 //////////////////////////////////////////////////////////////////////
\r
123 virtual ~CMimeHeader() { Clear(); }
\r
128 MEDIA_TEXT, MEDIA_IMAGE, MEDIA_AUDIO, MEDIA_VEDIO, MEDIA_APPLICATION,
\r
129 MEDIA_MULTIPART, MEDIA_MESSAGE,
\r
132 MediaType GetMediaType() const;
\r
134 // set/get the values of header fields
\r
135 void SetField(const CMimeField& field);
\r
136 const CMimeField* GetField(const char* pszFieldName) const;
\r
137 CMimeField* GetField(const char* pszFieldName);
\r
138 void SetFieldValue(const char* pszFieldName, const char* pszFieldValue, const char* pszCharset=NULL);
\r
139 const char* GetFieldValue(const char* pszFieldName) const;
\r
140 bool SetParameter(const char* pszFieldName, const char* pszAttr, const char* pszValue);
\r
141 string GetParameter(const char* pszFieldName, const char* pszAttr) const;
\r
142 void SetFieldCharset(const char* pszFieldName, const char* pszCharset);
\r
143 const char* GetFieldCharset(const char* pszFieldName) const;
\r
145 // helper functions for standard body part fields
\r
146 void SetContentType(const char* pszValue, const char* pszCharset=NULL);
\r
147 const char* GetContentType() const; // Content-Type: mediatype/subtype
\r
148 string GetMainType() const;
\r
149 string GetSubType() const;
\r
150 void SetCharset(const char* pszCharset); // Content-Type: text/...; charset=...
\r
151 string GetCharset() const;
\r
152 void SetName(const char* pszName); // Content-Type: image/...; name=...
\r
153 string GetName() const;
\r
154 void SetBoundary(const char* pszBoundary=NULL); // Content-Type: multipart/...; boundary=...
\r
155 string GetBoundary() const;
\r
157 void SetTransferEncoding(const char* pszValue);
\r
158 const char* GetTransferEncoding() const; // Content-Transfer-Encoding: ...
\r
159 void SetDisposition(const char* pszValue, const char* pszCharset=NULL);
\r
160 const char* GetDisposition() const; // Content-Disposition: ...
\r
161 string GetFilename() const; // Content-Disposition: ...; filename=...
\r
162 void SetDescription(const char* pszValue, const char* pszCharset=NULL);
\r
163 const char* GetDescription() const; // Content-Description: ...
\r
165 typedef list<CMimeField> CFieldList;
\r
166 CFieldList& Fields() { return m_listFields; }
\r
170 virtual void Clear();
\r
171 virtual int GetLength() const;
\r
173 virtual int Store(char* pszData, int nMaxSize) const;
\r
174 virtual int Load(const char* pszData, int nDataSize);
\r
177 list<CMimeField> m_listFields; // list of all header fields
\r
178 list<CMimeField>::const_iterator FindField(const char* pszFieldName) const;
\r
179 list<CMimeField>::iterator FindField(const char* pszFieldName);
\r
181 struct MediaTypeCvt
\r
183 int nMediaType; // media type
\r
184 const char* pszSubType; // subtype
\r
185 const char* pszFileExt; // file extension name
\r
187 static const MediaTypeCvt m_TypeCvtTable[];
\r
188 static const char* m_TypeTable[];
\r
191 CMimeHeader& operator=(const CMimeHeader&); // forbid operator =
\r
194 // add a new field or update an existing field
\r
195 inline void CMimeHeader::SetField(const CMimeField& field)
\r
197 list<CMimeField>::iterator it = FindField(field.GetName());
\r
198 if (it != m_listFields.end())
\r
201 m_listFields.push_back(field);
\r
204 // find a field by name
\r
205 inline const CMimeField* CMimeHeader::GetField(const char* pszFieldName) const
\r
207 list<CMimeField>::const_iterator it = FindField(pszFieldName);
\r
208 if (it != m_listFields.end())
\r
213 inline CMimeField* CMimeHeader::GetField(const char* pszFieldName)
\r
215 list<CMimeField>::iterator it = FindField(pszFieldName);
\r
216 if (it != m_listFields.end())
\r
221 // add a new field or update an existing field
\r
222 inline void CMimeHeader::SetFieldValue(const char* pszFieldName, const char* pszFieldValue, const char* pszCharset)
\r
225 fd.SetName(pszFieldName);
\r
226 fd.SetValue(pszFieldValue);
\r
227 if (pszCharset != NULL)
\r
228 fd.SetCharset(pszCharset);
\r
232 inline const char* CMimeHeader::GetFieldValue(const char* pszFieldName) const
\r
234 const CMimeField* pfd = GetField(pszFieldName);
\r
235 return pfd != NULL ? pfd->GetValue() : NULL;
\r
238 inline void CMimeHeader::SetFieldCharset(const char* pszFieldName, const char* pszCharset)
\r
240 CMimeField *pfd = GetField(pszFieldName);
\r
242 pfd->SetCharset(pszCharset);
\r
246 fd.SetName(pszFieldName);
\r
247 fd.SetCharset(pszCharset);
\r
252 inline const char* CMimeHeader::GetFieldCharset(const char* pszFieldName) const
\r
254 const CMimeField* pfd = GetField(pszFieldName);
\r
255 return pfd != NULL ? pfd->GetCharset() : NULL;
\r
258 inline bool CMimeHeader::SetParameter(const char* pszFieldName, const char* pszAttr, const char* pszValue)
\r
260 CMimeField *pfd = GetField(pszFieldName);
\r
263 pfd->SetParameter(pszAttr, pszValue);
\r
269 inline string CMimeHeader::GetParameter(const char* pszFieldName, const char* pszAttr) const
\r
272 const CMimeField *pfd = GetField(pszFieldName);
\r
274 pfd->GetParameter(pszAttr, strVal);
\r
278 inline void CMimeHeader::SetContentType(const char* pszValue, const char* pszCharset)
\r
279 { SetFieldValue(CMimeConst::ContentType(), pszValue, pszCharset); }
\r
281 inline const char* CMimeHeader::GetContentType() const
\r
282 { return GetFieldValue(CMimeConst::ContentType()); }
\r
284 inline string CMimeHeader::GetCharset() const
\r
285 { return GetParameter(CMimeConst::ContentType(), CMimeConst::Charset()); }
\r
287 inline string CMimeHeader::GetName() const
\r
288 { return GetParameter(CMimeConst::ContentType(), CMimeConst::Name()); }
\r
290 inline string CMimeHeader::GetBoundary() const
\r
291 { return GetParameter(CMimeConst::ContentType(), CMimeConst::Boundary()); }
\r
293 inline void CMimeHeader::SetTransferEncoding(const char* pszValue)
\r
294 { SetFieldValue(CMimeConst::TransferEncoding(), pszValue); }
\r
296 inline const char* CMimeHeader::GetTransferEncoding() const
\r
297 { return GetFieldValue(CMimeConst::TransferEncoding()); }
\r
299 // Content-Disposition header field specifies how to present this body part. it could be
\r
300 // inline or attachment. 'inline' indicates this body part should be displayed in the main body;
\r
301 // 'attachment' indicates it is separate from the main body. (RFC 2183)
\r
303 inline void CMimeHeader::SetDisposition(const char* pszValue, const char* pszCharset)
\r
304 { SetFieldValue(CMimeConst::ContentDisposition(), pszValue, pszCharset); }
\r
306 inline const char* CMimeHeader::GetDisposition() const
\r
307 { return GetFieldValue(CMimeConst::ContentDisposition()); }
\r
309 inline string CMimeHeader::GetFilename() const
\r
310 { return GetParameter(CMimeConst::ContentDisposition(), CMimeConst::Filename()); }
\r
312 inline void CMimeHeader::SetDescription(const char* pszValue, const char* pszCharset)
\r
313 { SetFieldValue(CMimeConst::ContentDescription(), pszValue, pszCharset); }
\r
315 inline const char* CMimeHeader::GetDescription() const
\r
316 { return GetFieldValue(CMimeConst::ContentDescription()); }
\r
318 //////////////////////////////////////////////////////////////////////
\r
319 // CMimeBody class - Represents a body part in a MIME message
\r
320 //////////////////////////////////////////////////////////////////////
\r
321 class CMimeMessage;
\r
322 class CMimeBody : public CMimeHeader
\r
325 CMimeBody() : // instantiate a CMimeBody object explicitly is not allowed. call CreatePart()
\r
328 virtual ~CMimeBody() { Clear(); }
\r
331 int GetContentLength() const;
\r
332 const unsigned char* GetContent() const;
\r
334 // operations for 'text' or 'message' media
\r
335 bool IsText() const;
\r
336 int SetText(const char* pbText, int nLength=0);
\r
337 int GetText(char* pbText, int nMaxSize);
\r
338 int GetText(string& strText);
\r
340 // operations for 'message' media
\r
341 bool IsMessage() const;
\r
342 bool SetMessage(const CMimeMessage* pMM);
\r
343 void GetMessage(CMimeMessage* pMM) const;
\r
345 // operations for 'image/audio/vedio/application' (attachment) media
\r
346 bool IsAttachment() const;
\r
347 bool ReadFromFile(const char* pszFilename);
\r
348 bool WriteToFile(const char* pszFilename);
\r
350 // operations for 'multipart' media
\r
351 bool IsMultiPart() const;
\r
353 CMimeBody* CreatePart(const char* pszMediaType=NULL, CMimeBody* pWhere=NULL);
\r
354 void ErasePart(CMimeBody* pBP);
\r
355 CMimeBody* FindFirstPart();
\r
356 CMimeBody* FindNextPart();
\r
358 typedef list<CMimeBody*> CBodyList;
\r
359 int GetBodyPartList(CBodyList& rList) const;
\r
360 int GetAttachmentList(CBodyList& rList) const;
\r
364 virtual void Clear();
\r
365 virtual int GetLength() const;
\r
367 virtual int Store(char* pszData, int nMaxSize) const;
\r
368 virtual void Store(std::string &str) const;
\r
369 virtual int Load(const char* pszData, int nDataSize);
\r
372 unsigned char* m_pbText; // content (text) of the body part
\r
373 int m_nTextSize; // length of content
\r
374 CBodyList m_listBodies; // list of all child body parts
\r
375 CBodyList::iterator m_itFind;
\r
378 bool AllocateBuffer(int nBufSize);
\r
381 friend class CMimeEnvironment;
\r
384 inline int CMimeBody::GetContentLength() const
\r
385 { return m_nTextSize; }
\r
387 inline const unsigned char* CMimeBody::GetContent() const
\r
388 { return m_pbText; }
\r
390 inline bool CMimeBody::IsText() const
\r
391 { return GetMediaType() == MEDIA_TEXT; }
\r
393 inline bool CMimeBody::IsMessage() const
\r
394 { return GetMediaType() == MEDIA_MESSAGE; }
\r
396 inline bool CMimeBody::IsAttachment() const
\r
397 { return GetName().size() > 0; }
\r
399 inline bool CMimeBody::IsMultiPart() const
\r
400 { return GetMediaType() == MEDIA_MULTIPART; }
\r
402 inline CMimeBody* CMimeBody::FindFirstPart()
\r
404 m_itFind = m_listBodies.begin();
\r
405 return FindNextPart();
\r
408 inline CMimeBody* CMimeBody::FindNextPart()
\r
410 if (m_itFind != m_listBodies.end())
\r
411 return *m_itFind++;
\r
415 inline bool CMimeBody::AllocateBuffer(int nBufSize)
\r
418 m_pbText = new unsigned char[nBufSize];
\r
419 if (!m_pbText) return false;
\r
420 m_nTextSize = nBufSize;
\r
424 inline void CMimeBody::FreeBuffer()
\r
431 //////////////////////////////////////////////////////////////////////
\r
432 // CMimeMessage - Represents a MIME message
\r
433 //////////////////////////////////////////////////////////////////////
\r
434 class CMimeMessage : public CMimeBody
\r
437 CMimeMessage() { /*SetVersion();*/ }
\r
438 virtual ~CMimeMessage() { Clear(); }
\r
441 // set/get RFC 822 message header fields
\r
442 void SetFrom(const char* pszFrom, const char* pszCharset=NULL);
\r
443 const char* GetFrom() const;
\r
444 void SetTo(const char* pszTo, const char* pszCharset=NULL);
\r
445 const char* GetTo() const;
\r
446 void SetCc(const char* pszCc, const char* pszCharset=NULL);
\r
447 const char* GetCc() const;
\r
448 void SetBcc(const char* pszBcc, const char* pszCharset=NULL);
\r
449 const char* GetBcc() const;
\r
451 void SetSubject(const char* pszSubject, const char* pszCharset=NULL);
\r
452 const char* GetSubject() const;
\r
455 void SetDate(int nYear, int nMonth, int nDay, int nHour, int nMinute, int nSecond);
\r
456 const char* GetDate() const;
\r
460 inline void CMimeMessage::SetFrom(const char* pszAddr, const char* pszCharset)
\r
461 { SetFieldValue("From", pszAddr, pszCharset); }
\r
463 inline const char* CMimeMessage::GetFrom() const
\r
464 { return GetFieldValue("From"); }
\r
466 inline void CMimeMessage::SetTo(const char* pszAddr, const char* pszCharset)
\r
467 { SetFieldValue("To", pszAddr, pszCharset); }
\r
469 inline const char* CMimeMessage::GetTo() const
\r
470 { return GetFieldValue("To"); }
\r
472 inline void CMimeMessage::SetCc(const char* pszAddr, const char* pszCharset)
\r
473 { SetFieldValue("CC", pszAddr, pszCharset); }
\r
475 inline const char* CMimeMessage::GetCc() const
\r
476 { return GetFieldValue("CC"); }
\r
478 inline void CMimeMessage::SetBcc(const char* pszAddr, const char* pszCharset)
\r
479 { SetFieldValue("BCC", pszAddr, pszCharset); }
\r
481 inline const char* CMimeMessage::GetBcc() const
\r
482 { return GetFieldValue("BCC"); }
\r
484 inline void CMimeMessage::SetSubject(const char* pszSubject, const char* pszCharset)
\r
485 { SetFieldValue("Subject", pszSubject, pszCharset); }
\r
487 inline const char* CMimeMessage::GetSubject() const
\r
488 { return GetFieldValue("Subject"); }
\r
490 inline const char* CMimeMessage::GetDate() const
\r
491 { return GetFieldValue("Date"); }
\r
493 inline void CMimeMessage::SetVersion()
\r
494 { SetFieldValue(CMimeConst::MimeVersion(), "1.0"); }
\r
496 #endif // !defined(_MIME_H)
\r