acl  3.5.3.0
mime.hpp
浏览该文件的文档.
1 #pragma once
2 #include "../acl_cpp_define.hpp"
3 #include "../stdlib/noncopyable.hpp"
4 #include <list>
5 #include <string>
6 #include "mime_head.hpp"
7 
8 #if !defined(ACL_MIME_DISABLE)
9 
10 struct MIME_STATE;
11 
12 namespace acl {
13 
14 class string;
15 class mime_node;
16 class mime_attach;
17 class mime_body;
18 class mime_image;
19 class ifstream;
20 class fstream;
21 
23 {
24 public:
25  mime(void);
26  ~mime(void);
27 
28  /////////////////////////////////////////////////////////////////////
29  // 与邮件解析相关的函数
30 
31  /**
32  * 当用同一个MIME解析器对多封邮件解析时, 需要调用此函数清理之前
33  * 解析过程中产生的内存, 虽然多次调用该函数无害, 但为了不影响
34  * 效率, 最好在利用该解析器解析下一封邮件前调用该函数
35  */
36  mime& reset(void);
37 
38  /**
39  * 调用者可以手工调用此函数以触发分析邮件头过程
40  */
41  void primary_head_finish(void);
42 
43  /**
44  * 调用流式分析时用此函数判断邮件头是否解析完毕
45  * @return {bool} 是否邮件头解析完毕
46  */
47  bool primary_head_ok(void) const;
48 
49  /**
50  * 开始进行流式解析过程, 该函数内部会自动调用 reset() 函数以重置解析
51  * 器状态
52  * @param path {const char*} 邮件文件路径名, 如果该参数为空, 则不能
53  * 获得邮件体数据, 也不能调用 save_xxx 相关的接口
54  */
55  void update_begin(const char* path);
56 
57  /**
58  * 调用此函数进行流式方式解析邮件内容, 如果仅想解析邮件头, 则可以用此
59  * 接口解析完邮件头后调用 update_end() 接口即可, 如果想要解析完整的一
60  * 封邮件, 则需要不断地调用此函数直到本函数返回 true 表示 multipart 格式
61  * 的邮件解析完毕; 如果不是 multipart 格式邮件, 则此函数不可能会回返 true,
62  * 调用者需要自行判断邮件的结束位置
63  * @param data {const char*} 邮件数据(可能是邮件头也可能是邮件体, 并且
64  * 不必是完整的数据行)
65  * @param len {size_t} data 数据长度
66  * @return {bool} 针对 multipart 邮件, 返回 true 表示该封邮件结束完毕;
67  * 对于非 multipart 邮件, 该返回值永远为 false, 没有任何意义, 需要调用
68  * 者自己判断邮件的结束位置
69  * 注意: 调用完此函数后一定需要调用 update_end 函数通知解析器解析完毕
70  */
71  bool update(const char* data, size_t len);
72 
73  /**
74  * 在采用流式解析结束后必须调用此函数
75  */
76  void update_end(void);
77 
78  /**
79  * 调用此函数解析磁盘上的一封邮件
80  * @param file_path {const char*} 邮件文件路径
81  * @return {bool} 如果返回 false 说明源邮件文件无法打开
82  */
83  bool parse(const char* file_path);
84 
85  /**
86  * 将邮件解析结果另存为另一个文件名
87  * @param out {ostream&} 目标流对象
88  * @return {bool} 是否成功
89  */
90  bool save_as(ostream& out);
91 
92  /**
93  * 将邮件解析结果另存为另一个文件中
94  * @param file_path {const char*} 目标文件名
95  * @return {bool} 是否成功
96  */
97  bool save_as(const char* file_path);
98 
99  /**
100  * 邮件解析完毕后,按客户显示的方式将解析结果保存于磁盘,
101  * 用户可以使用浏览器打开该 html 页面
102  * @param path {const char*} 页面保存路径
103  * @param filename {const char*} 目标文件名
104  * @param enableDecode {bool} 转储时是否自动进行解码
105  * @param toCharset {const char*} 目标字符集
106  * @param off {off_t} 调用者希望给邮件结点附加的相对偏移量
107  * @return {bool} 是否成功
108  */
109  bool save_mail(const char* path, const char* filename,
110  bool enableDecode = true, const char* toCharset = "gb2312",
111  off_t off = 0);
112 
113  /**
114  * 获得邮件正文节点
115  * @param htmlFirst {bool} 优先获得HTML格式的文本;否则优先获得
116  * 纯文本,且如果只有HTML文本则转换为纯文本
117  * @param enableDecode {bool} 转储时是否对原文进行解码
118  * @param toCharset {const char*} 目标字符集
119  * @param off {off_t} 调用者希望给邮件体结点附加的相对偏移量
120  * @return {mime_body*} 若未找到正文内容则返回 NULL
121  */
122  mime_body* get_body_node(bool htmlFirst, bool enableDecode = true,
123  const char* toCharset = "gb2312", off_t off = 0);
124 
125  /**
126  * 获得 text/plain 格式的正文节点
127  * @param enableDecode {bool} 转储时是否对原文进行解码
128  * @param toCharset {const char*} 目标字符集
129  * @param off {off_t} 调用者希望给邮件体结点附加的相对偏移量
130  * @return {mime_body*} 若未找到 plain 格式的正文内容则返回 NULL
131  */
132  mime_body* get_plain_body(bool enableDecode = true,
133  const char* toCharset = "gb2312", off_t off = 0);
134 
135  /**
136  * 获得 text/html 格式的正文节点
137  * @param enableDecode {bool} 转储时是否对原文进行解码
138  * @param toCharset {const char*} 目标字符集
139  * @param off {off_t} 调用者希望给邮件体结点附加的相对偏移量
140  * @return {mime_body*} 若未找到 html 格式的正文内容则返回 NULL
141  */
142  mime_body* get_html_body(bool enableDecode = true,
143  const char* toCharset = "gb2312", off_t off = 0);
144 
145  /**
146  * 获得所有的 mime 节点列表
147  * @param enableDecode {bool} 转储时是否自动进行解码
148  * @param toCharset {const char*} 目标字符集
149  * @param off {off_t} 调用者希望给邮件结点附加的相对偏移量
150  * @return {const std::list<mime_node*>&}
151  */
152  const std::list<mime_node*>& get_mime_nodes(bool enableDecode = true,
153  const char* toCharset = "gb2312", off_t off = 0);
154 
155  /**
156  * 获得附件列表
157  * @param enableDecode {bool} 转储时是否自动进行解码
158  * @param toCharset {const char*} 目标字符集
159  * @param off {off_t} 调用者希望给邮件结点附加的相对偏移量
160  * @param all {bool} 提取所有包括 message/application/image 在内的所有节点
161  * @return {const std::list<mime_attach*>&}
162  */
163  const std::list<mime_attach*>& get_attachments(bool enableDecode = true,
164  const char* toCharset = "gb2312", off_t off = 0, bool all = true);
165 
166  /**
167  * 获得图片列表
168  * @param enableDecode {bool} 转储时是否自动进行解码
169  * @param toCharset {const char*} 目标字符集
170  * @param off {off_t} 调用者希望给邮件结点附加的相对偏移量
171  * @return {const std::list<mime_image*>&}
172  */
173  const std::list<mime_image*>& get_images(bool enableDecode = true,
174  const char* toCharset = "gb2312", off_t off = 0);
175  mime_image* get_image(const char* cld, bool enableDecode = true,
176  const char* toCharset = "gb2312", off_t off = 0);
177 
178  /**
179  * 调试MIME解析结果
180  * @param save_path {const char*} 存储 MIME 解析结果的路径
181  * @param decode {bool} 是否对原文进行解码
182  */
183  void mime_debug(const char* save_path, bool decode = true);
184 
185  /////////////////////////////////////////////////////////////////////
186  // 和邮件头相关的函数
187 
188  /**
189  * 设置发件人
190  * @param addr {const char*} 邮件地址
191  * @return {mime&}
192  */
193  mime& set_sender(const char* addr)
194  {
195  m_primaryHeader.set_returnpath(addr);
196  return *this;
197  }
198 
199  /**
200  * 设置发件人: From: zhengshuxin@51iker.com
201  * @param addr {const char*} 邮件地址
202  * @return {mime&}
203  */
204  mime& set_from(const char* addr)
205  {
206  m_primaryHeader.set_from(addr);
207  return *this;
208  }
209 
210  /**
211  * 设置邮件回地址: Reply-To: zhengshuxin@51iker.com
212  * @param addr {const char*} 邮件地址
213  * @return {mime&}
214  */
215  mime& set_replyto(const char* addr)
216  {
217  m_primaryHeader.set_replyto(addr);
218  return *this;
219  }
220 
221  /**
222  * 设置邮件反复地址 Return-Path: <zhengshuxin@51iker.com>
223  * @param addr {const char*} 邮件地址
224  * @return {mime&}
225  */
226  mime& set_returnpath(const char* addr)
227  {
228  m_primaryHeader.set_returnpath(addr);
229  return *this;
230  }
231 
232  /**
233  * 设置邮件主题: Subject: test
234  * @param s {const char*} 邮件主题
235  * @return {mime&}
236  */
237  mime& set_subject(const char* s)
238  {
239  m_primaryHeader.set_subject(s);
240  return *this;
241  }
242 
243  /**
244  * 添加邮件接收人: To: <zhengshuxin@51iker.com>
245  * @param addr {const char*} 邮件地址
246  * @return {mime&}
247  */
248  mime& add_to(const char* addr)
249  {
250  m_primaryHeader.add_to(addr);
251  return *this;
252  }
253 
254  /**
255  * 添加邮件抄送者: CC: <zhengshuxin@51iker.com>
256  * @param addr {const char* addr} 邮件地址
257  * @return {mime&}
258  */
259  mime& add_cc(const char* addr)
260  {
261  m_primaryHeader.add_cc(addr);
262  return *this;
263  }
264 
265  /**
266  * 添加邮件密送者: BCC: <zhengshuxin@51iker.com>
267  * @param addr {const char* addr} 邮件地址
268  * @return {mime&}
269  */
270  mime& add_bcc(const char* addr)
271  {
272  m_primaryHeader.add_bcc(addr);
273  return *this;
274  }
275 
276  /**
277  * 添加邮件接收者: CC: <zhengshuxin@51iker.com>
278  * @param addr {const char* addr} 邮件地址
279  * @return {mime&}
280  */
281  mime& add_rcpt(const char* addr)
282  {
283  m_primaryHeader.add_rcpt(addr);
284  return *this;
285  }
286 
287  /**
288  * 添加邮件头的字段
289  * @param name {const char*} 字段名
290  * @param value {const char*} 字段值
291  * @return {mime&}
292  */
293  mime& add_header(const char* name, const char* value)
294  {
295  m_primaryHeader.add_header(name, value);
296  return *this;
297  }
298 
299  /**
300  * 设置邮件头的内容类型: Content-Type: text/plain
301  * @param ctype {const char*} 主类型
302  * @param stype {const char*} 子类型
303  * @return {mime&}
304  */
305  mime& set_type(const char* ctype, const char* stype)
306  {
307  m_primaryHeader.set_type(ctype, stype);
308  return *this;
309  }
310 
311  /**
312  * 设置邮件头部的分隔符
313  * @param s {const char*} 分隔串
314  * @return {mime&}
315  */
316  mime& set_boundary(const char* s)
317  {
318  m_primaryHeader.set_boundary(s);
319  return *this;
320  }
321 
322  /**
323  * 获得发件人
324  * @return {const string&} 如果返回对象的内容为空
325  * (调用 string::empty()) 则表示没有此字段
326  */
327  const string& sender(void) const
328  {
329  return m_primaryHeader.sender();
330  }
331 
332  /**
333  * 获得发件人
334  * @return {const string&} 如果返回对象的内容为空
335  * (调用 string::empty()) 则表示没有此字段
336  */
337  const string& from(void) const
338  {
339  return m_primaryHeader.from();
340  }
341 
342  /**
343  * 获得回复邮件地址
344  * @return {const string&} 如果返回对象的内容为空
345  * (调用 string::empty()) 则表示没有此字段
346  */
347  const string& replyto(void) const
348  {
349  return m_primaryHeader.replyto();
350  }
351 
352  /**
353  * 获得回复邮件地址
354  * @return {const string&} 如果返回对象的内容为空
355  * (调用 string::empty()) 则表示没有此字段
356  */
357  const string& returnpath(void) const
358  {
359  return m_primaryHeader.returnpath();
360  }
361 
362  /**
363  * 获得邮件主题
364  * @return {const string&} 如果返回对象的内容为空
365  * (调用 string::empty()) 则表示没有此字段
366  */
367  const string& subject(void) const
368  {
369  return m_primaryHeader.subject();
370  }
371 
372  /**
373  * 获得收件人列表: To: xxx@xxx.com
374  * @return {const std::list<char*>&) 如果返回对象的内容为空
375  * (调用 std::list<char*>::empty()) 则表示没有此字段
376  */
377  const std::list<char*>& to_list(void) const
378  {
379  return m_primaryHeader.to_list();
380  }
381 
382  /**
383  * 获得抄送人列表: To: xxx@xxx.com
384  * @return {const std::list<char*>&) 如果返回对象的内容为空
385  * (调用 std::list<char*>::empty()) 则表示没有此字段
386  */
387  const std::list<char*>& cc_list(void) const
388  {
389  return m_primaryHeader.cc_list();
390  }
391 
392  /**
393  * 获得暗送人列表: To: xxx@xxx.com
394  * @return {const std::list<char*>&) 如果返回对象的内容为空
395  * (调用 std::list<char*>::empty()) 则表示没有此字段
396  */
397  const std::list<char*>& bcc_list(void) const
398  {
399  return m_primaryHeader.bcc_list();
400  }
401 
402  /**
403  * 获得收件人列表:
404  * To: xxx@xxx.xxx, CC: xxx@xxx.xxx, BCC: xxx@xxx.xxx
405  * @return {const std::list<char*>&) 如果返回对象的内容为空
406  * (调用 std::list<char*>::empty()) 则表示没有此字段
407  */
408  const std::list<char*>& rcpt_list(void) const
409  {
410  return m_primaryHeader.rcpt_list();
411  }
412 
413  /**
414  * 获得邮件头的各个字段列表
415  * @return {const std::list<HEADER*>&)
416  */
417  const std::list<HEADER*>& header_list(void) const
418  {
419  return m_primaryHeader.header_list();
420  }
421 
422  /**
423  * 查询邮件头对应字段名的字段值
424  * @param name {const char*} 字段名
425  * @return {const char*} 字段值, 为空时表示不存在
426  */
427  const char* header_value(const char* name) const
428  {
429  return m_primaryHeader.header_value(name);
430  }
431 
432  /**
433  * 查询邮件头对应字段名的字段值集合
434  * @param name {const char*} 字段名
435  * @param values {std::list<const char*>*} 存储对应的结果集
436  * @return {int} 字段值集合的个数
437  */
438  int header_values(const char* name, std::list<const char*>* values) const
439  {
440  return m_primaryHeader.header_values(name, values);
441  }
442 
443  /**
444  * 获得邮件头中关于 Content-Type: text/html 中的 text 字段
445  * @return {const char*} 永远返回非空值
446  */
447  const char* get_ctype(void) const
448  {
449  return m_primaryHeader.get_ctype();
450  }
451 
452  /**
453  * 获得邮件头中关于 Content-Type: text/html 中的 html 字段
454  * @return {const char*} 永远返回非空值
455  */
456  const char* get_stype(void) const
457  {
458  return m_primaryHeader.get_stype();
459  }
460 
461  /**
462  * 获得邮件头
463  * @return {const mime_head&}
464  */
465  const mime_head& primary_header(void) const
466  {
467  return m_primaryHeader;
468  }
469 
470 private:
471  mime_head m_primaryHeader;
472 
473  MIME_STATE* m_pMimeState;
474  bool m_bPrimaryHeadFinish;
475  char* m_pFilePath;
476  mime_body* m_pBody;
477  std::list<mime_node*>* m_pNodes;
478  std::list<mime_attach*>* m_pAttaches;
479  std::list<mime_image*>* m_pImages;
480 };
481 
482 } // namespace acl
483 
484 #endif // !defined(ACL_MIME_DISABLE)
const std::list< char * > & cc_list(void) const
Definition: mime.hpp:387
HTTP_API void const char * name
Definition: lib_http.h:620
mime & set_sender(const char *addr)
Definition: mime.hpp:193
mime & add_header(const char *name, const char *value)
Definition: mime.hpp:293
mime & add_to(const char *addr)
Definition: mime.hpp:248
const mime_head & primary_header(void) const
Definition: mime.hpp:465
const string & returnpath(void) const
Definition: mime.hpp:357
const std::list< char * > & rcpt_list(void) const
Definition: mime.hpp:408
const std::list< char * > & to_list(void) const
Definition: mime.hpp:377
const char * get_stype(void) const
Definition: mime.hpp:456
mime & add_rcpt(const char *addr)
Definition: mime.hpp:281
mime & set_type(const char *ctype, const char *stype)
Definition: mime.hpp:305
const std::list< HEADER * > & header_list(void) const
Definition: mime.hpp:417
const string & sender(void) const
Definition: mime.hpp:327
mime & set_boundary(const char *s)
Definition: mime.hpp:316
const std::list< char * > & bcc_list(void) const
Definition: mime.hpp:397
const string & subject(void) const
Definition: mime.hpp:367
const char * get_ctype(void) const
Definition: mime.hpp:447
const char * header_value(const char *name) const
Definition: mime.hpp:427
mime & add_cc(const char *addr)
Definition: mime.hpp:259
mime & set_subject(const char *s)
Definition: mime.hpp:237
mime & set_replyto(const char *addr)
Definition: mime.hpp:215
mime & add_bcc(const char *addr)
Definition: mime.hpp:270
int header_values(const char *name, std::list< const char * > *values) const
Definition: mime.hpp:438
const string & from(void) const
Definition: mime.hpp:337
#define ACL_CPP_API
const string & replyto(void) const
Definition: mime.hpp:347
mime & set_from(const char *addr)
Definition: mime.hpp:204
mime & set_returnpath(const char *addr)
Definition: mime.hpp:226