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