1 #ifndef MESSAGE_PARSER_H
2 #define MESSAGE_PARSER_H
3 
4 #include "message-header-parser.h"
5 #include "message-part.h"
6 
7 enum message_parser_flags {
8 	/* Don't return message bodies in message_blocks. */
9 	MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK		= 0x01,
10 	/* Buggy software creates Content-Type: headers without Mime-Version:
11 	   header. By default we allow this and assume message is MIME if
12 	   Content-Type: is found. This flag disables this. */
13 	MESSAGE_PARSER_FLAG_MIME_VERSION_STRICT		= 0x02,
14 	/* Return multipart (preamble and epilogue) blocks */
15 	MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS	= 0x04,
16 	/* Return --boundary lines */
17 	MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES		= 0x08
18 };
19 
20 #define MESSAGE_PARSER_DEFAULT_MAX_NESTED_MIME_PARTS 100
21 #define MESSAGE_PARSER_DEFAULT_MAX_TOTAL_MIME_PARTS 10000
22 
23 struct message_parser_settings {
24 	enum message_header_parser_flags hdr_flags;
25 	enum message_parser_flags flags;
26 
27 	/* Maximum nested MIME parts.
28 	   0 = MESSAGE_PARSER_DEFAULT_MAX_NESTED_MIME_PARTS. */
29 	unsigned int max_nested_mime_parts;
30 	/* Maximum MIME parts in total.
31 	   0 = MESSAGE_PARSER_DEFAULT_MAX_TOTAL_MIME_PARTS. */
32 	unsigned int max_total_mime_parts;
33 };
34 
35 struct message_parser_ctx;
36 
37 struct message_block {
38 	/* Message part this block belongs to */
39 	struct message_part *part;
40 
41 	/* non-NULL if a header line was read */
42 	struct message_header_line *hdr;
43 
44 	/* hdr = NULL, size = 0 block returned at the end of headers for the
45 	   empty line between header and body (unless the header is truncated).
46 	   Later on data and size>0 is returned for blocks of mail body that
47 	   is read (see message_parser_flags for what is actually returned) */
48 	const unsigned char *data;
49 	size_t size;
50 };
51 
52 /* called once with hdr = NULL at the end of headers */
53 typedef void message_part_header_callback_t(struct message_part *part,
54 					    struct message_header_line *hdr,
55 					    void *context);
56 
57 extern message_part_header_callback_t *null_message_part_header_callback;
58 
59 /* Initialize message parser. part_spool specifies where struct message_parts
60    are allocated from. */
61 struct message_parser_ctx *
62 message_parser_init(pool_t part_pool, struct istream *input,
63 		    const struct message_parser_settings *set);
64 /* Deinitialize message parser. The ctx must NOT have been created by
65    message_parser_init_from_parts(). */
66 void message_parser_deinit(struct message_parser_ctx **ctx,
67 			   struct message_part **parts_r);
68 /* Use preparsed parts to speed up parsing. */
69 struct message_parser_ctx *
70 message_parser_init_from_parts(struct message_part *parts,
71 			       struct istream *input,
72 			       const struct message_parser_settings *set);
73 /* Same as message_parser_deinit(), but return an error message describing
74    why the preparsed parts didn't match the message. This can also safely be
75    called even when preparsed parts weren't used - it'll always just return
76    success in that case. */
77 int message_parser_deinit_from_parts(struct message_parser_ctx **_ctx,
78 				     struct message_part **parts_r,
79 				     const char **error_r);
80 
81 /* Read the next block of a message. Returns 1 if block is returned, 0 if
82    input stream is non-blocking and more data needs to be read, -1 when all is
83    done or error occurred (see stream's error status). */
84 int message_parser_parse_next_block(struct message_parser_ctx *ctx,
85 				    struct message_block *block_r);
86 
87 /* Read and parse header. */
88 void message_parser_parse_header(struct message_parser_ctx *ctx,
89 				 struct message_size *hdr_size,
90 				 message_part_header_callback_t *callback,
91 				 void *context) ATTR_NULL(4);
92 #define message_parser_parse_header(ctx, hdr_size, callback, context) \
93 	  message_parser_parse_header(ctx, hdr_size - \
94 		CALLBACK_TYPECHECK(callback, void (*)( \
95 			struct message_part *, \
96 			struct message_header_line *, typeof(context))), \
97 		(message_part_header_callback_t *)callback, context)
98 
99 /* Read and parse body. If message is a MIME multipart or message/rfc822
100    message, hdr_callback is called for all headers. body_callback is called
101    for the body content. */
102 void message_parser_parse_body(struct message_parser_ctx *ctx,
103 			       message_part_header_callback_t *hdr_callback,
104 			       void *context) ATTR_NULL(3);
105 #define message_parser_parse_body(ctx, callback, context) \
106 	  message_parser_parse_body(ctx, \
107 		(message_part_header_callback_t *)callback, \
108 		(void *)((uintptr_t)context - CALLBACK_TYPECHECK(callback, \
109 			void (*)(struct message_part *, \
110 				struct message_header_line *, typeof(context)))))
111 
112 #endif
113