message-parser.c revision 0e50c91bdf1a470e016a7800020ad061ffbca427
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2002-2007 Dovecot authors, see the included COPYING file */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "lib.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "str.h"
65cca8364f483126b396aeb2036dc879ad45ab8dTimo Sirainen#include "istream.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "rfc822-parser.h"
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen#include "message-parser.h"
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen/* RFC-2046 requires boundaries are max. 70 chars + "--" prefix + "--" suffix.
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen We'll add a bit more just in case. */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen#define BOUNDARY_END_MAX_LEN (70 + 2 + 2 + 10)
b1f37113a5760bee842c5a7678bb5fa6f5bd8b60Timo Sirainen
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainenstruct message_boundary {
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen struct message_boundary *next;
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen struct message_part *part;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen const char *boundary;
13d98ffa534f2e7d04a832c9d0153fc9c568b878Timo Sirainen size_t len;
13d98ffa534f2e7d04a832c9d0153fc9c568b878Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int epilogue_found:1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen};
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenstruct message_parser_ctx {
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen pool_t parser_pool, part_pool;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct istream *input;
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen struct message_part *parts, *part;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen enum message_header_parser_flags hdr_flags;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen enum message_parser_flags flags;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *last_boundary;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct message_boundary *boundaries;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen size_t skip;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen char last_chr;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen unsigned int want_count;
220e21750948941dc6e33b8f11b552fa21d7f81eTimo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen struct message_header_parser_ctx *hdr_parser_ctx;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen int (*parse_next_block)(struct message_parser_ctx *ctx,
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen struct message_block *block_r);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen unsigned int part_seen_content_type:1;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen};
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenmessage_part_header_callback_t *null_message_part_header_callback = NULL;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenstatic int parse_next_header_init(struct message_parser_ctx *ctx,
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen struct message_block *block_r);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct message_block *block_r);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int parse_next_body_to_eof(struct message_parser_ctx *ctx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct message_block *block_r);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct message_block *block_r);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic struct message_boundary *
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenboundary_find(struct message_boundary *boundaries,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const unsigned char *data, size_t len)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* As MIME spec says: search from latest one to oldest one so that we
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen don't break if the same boundary is used in nested parts. Also the
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen full message line doesn't have to match the boundary, only the
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen beginning. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen while (boundaries != NULL) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (boundaries->len <= len &&
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen memcmp(boundaries->boundary, data, boundaries->len) == 0)
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen return boundaries;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen boundaries = boundaries->next;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return NULL;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void parse_body_add_block(struct message_parser_ctx *ctx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct message_block *block)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int missing_cr_count = 0;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const unsigned char *data = block->data;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen size_t i;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen block->hdr = NULL;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (i = 0; i < block->size; i++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (data[i] <= '\n') {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (data[i] == '\n') {
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen ctx->part->body_size.lines++;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen if ((i > 0 && data[i-1] != '\r') ||
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen (i == 0 && ctx->last_chr != '\r'))
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen missing_cr_count++;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen } else if (data[i] == '\0')
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen }
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen }
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen ctx->part->body_size.physical_size += block->size;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen ctx->part->body_size.virtual_size += block->size + missing_cr_count;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen ctx->last_chr = data[i-1];
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ctx->skip += block->size;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainenstatic int message_parser_read_more(struct message_parser_ctx *ctx,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct message_block *block_r)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen int ret;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (ctx->skip > 0) {
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen i_stream_skip(ctx->input, ctx->skip);
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen ctx->skip = 0;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ret = i_stream_read_data(ctx->input, &block_r->data,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen &block_r->size, ctx->want_count);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (ret <= 0) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (ret < 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return ret;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (!ctx->input->eof) {
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen i_assert(!ctx->input->blocking);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen return 0;
63e207529879438e9f4412d97cdc34bdc82a3702Timo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen ctx->want_count = 1;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen return 1;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen}
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainenstatic struct message_part *
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainenmessage_part_append(pool_t pool, struct message_part *parent)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen{
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen struct message_part *part, **list;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen part = p_new(pool, struct message_part, 1);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen part->parent = parent;
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* set child position */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen part->physical_pos =
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen parent->physical_pos +
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen parent->body_size.physical_size +
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen parent->header_size.physical_size;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen list = &part->parent->children;
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen while (*list != NULL)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list = &(*list)->next;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen *list = part;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen return part;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen}
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainenstatic void parse_next_body_multipart_init(struct message_parser_ctx *ctx)
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen{
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen struct message_boundary *b;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen b = p_new(ctx->parser_pool, struct message_boundary, 1);
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen b->part = ctx->part;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen b->boundary = ctx->last_boundary;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen b->len = strlen(b->boundary);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen b->next = ctx->boundaries;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ctx->boundaries = b;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen ctx->last_boundary = NULL;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic void parse_next_body_message_rfc822_init(struct message_parser_ctx *ctx)
27586e4785d56aeb76e1fd96af8db799688dc64aTimo Sirainen{
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen ctx->part = message_part_append(ctx->part_pool, ctx->part);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic int
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenboundary_line_find(struct message_parser_ctx *ctx,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen const unsigned char *data, size_t size, bool full,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct message_boundary **boundary_r)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen size_t i;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen *boundary_r = NULL;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (size < 2) {
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen i_assert(!full);
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen if (ctx->input->eof)
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen return -1;
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen ctx->want_count = 2;
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen return 0;
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen if (data[0] != '-' || data[1] != '-') {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk /* not a boundary, just skip this line */
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk return -1;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk }
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk /* need to find the end of line */
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk for (i = 2; i < size; i++) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk if (data[i] == '\n')
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen break;
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (i == size && i < BOUNDARY_END_MAX_LEN &&
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen !ctx->input->eof && !full) {
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen /* no LF found */
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen ctx->want_count = BOUNDARY_END_MAX_LEN;
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen return 0;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen data += 2;
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen size -= 2;
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen *boundary_r = boundary_find(ctx->boundaries, data, size);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (*boundary_r == NULL)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return -1;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen (*boundary_r)->epilogue_found =
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen size >= (*boundary_r)->len + 2 &&
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen memcmp(data + (*boundary_r)->len, "--", 2) == 0;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen return 1;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen}
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenstatic int parse_next_body_skip_boundary_line(struct message_parser_ctx *ctx,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen struct message_block *block_r)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen{
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen size_t i;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen int ret;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r)) <= 0)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return ret;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen for (i = 0; i < block_r->size; i++) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (block_r->data[i] == '\n')
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen break;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen }
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (i == block_r->size) {
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen parse_body_add_block(ctx, block_r);
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen return 1;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* found the LF */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen block_r->size = i + 1;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen parse_body_add_block(ctx, block_r);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* a new MIME part begins */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen ctx->part = message_part_append(ctx->part_pool, ctx->part);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_IS_MIME;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen ctx->parse_next_block = parse_next_header_init;
5c597df6aa8d81de4053c6986fab7739f3b44b20Timo Sirainen return parse_next_header_init(ctx, block_r);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen}
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenstatic int parse_part_finish(struct message_parser_ctx *ctx,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen struct message_boundary *boundary,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen struct message_block *block_r, bool first_line)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen{
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen struct message_part *part;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (boundary == NULL) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* message ended unexpectedly */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen return -1;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen }
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* get back to parent MIME part, summing the child MIME part sizes
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen into parent's body sizes */
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen for (part = ctx->part; part != boundary->part; part = part->parent) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen message_size_add(&part->parent->body_size, &part->body_size);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen message_size_add(&part->parent->body_size, &part->header_size);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen ctx->part = part;
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen if (boundary->epilogue_found) {
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen /* this boundary isn't needed anymore */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ctx->boundaries = boundary->next;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (ctx->boundaries != NULL)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen else
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen ctx->parse_next_block = parse_next_body_to_eof;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen return ctx->parse_next_block(ctx, block_r);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen }
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen /* forget about the boundaries we possibly skipped */
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen ctx->boundaries = boundary;
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen /* the boundary itself should already be in buffer. add that. */
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen block_r->data = i_stream_get_data(ctx->input, &block_r->size);
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen i_assert(block_r->size >= ctx->skip + 2 + boundary->len +
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen (first_line ? 0 : 1));
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen block_r->data += ctx->skip;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* [\n]--<boundary> */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen block_r->size = (first_line ? 0 : 1) + 2 + boundary->len;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen parse_body_add_block(ctx, block_r);
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen ctx->parse_next_block = parse_next_body_skip_boundary_line;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen return 1;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen}
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenstatic int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen struct message_block *block_r)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen{
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen struct message_boundary *boundary = NULL;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen const unsigned char *data;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen size_t i, boundary_start;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen int ret;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen bool eof, full;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if ((ret = message_parser_read_more(ctx, block_r)) == 0 ||
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen block_r->size == 0)
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen return ret;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen eof = ret == -1;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen full = ret == -2;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen data = block_r->data;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (ctx->last_chr == '\n') {
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen /* handle boundary in first line of message. alternatively
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen it's an empty line. */
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen ret = boundary_line_find(ctx, block_r->data,
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen block_r->size, full, &boundary);
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen if (ret >= 0) {
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (ret == 0)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return 0;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return parse_part_finish(ctx, boundary, block_r, TRUE);
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen }
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen }
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen for (i = boundary_start = 0; i < block_r->size; i++) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* skip to beginning of the next line. the first line was
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen handled already. */
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen size_t next_line_idx = block_r->size;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen for (; i < block_r->size; i++) {
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen if (data[i] == '\n') {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen boundary_start = i;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (i > 0 && data[i-1] == '\r')
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen boundary_start--;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen next_line_idx = i + 1;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen break;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (boundary_start != 0) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* we can skip the first lines. input buffer can't be
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen full anymore. */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen full = FALSE;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen } else if (next_line_idx == block_r->size) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* no linefeeds in this block. we can just skip it. */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen boundary_start = block_r->size;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen full = FALSE;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen ret = boundary_line_find(ctx, block_r->data + next_line_idx,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen block_r->size - next_line_idx, full,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen &boundary);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (ret >= 0) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* found / need more data */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (ret == 0 && boundary_start == 0)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen ctx->want_count += next_line_idx;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen break;
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen }
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen }
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen if (i >= block_r->size) {
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen /* the boundary wasn't found from this data block,
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen we'll need more data. */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (eof)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen ret = -1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen else {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen ret = 0;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen ctx->want_count = (block_r->size - boundary_start) + 1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen i_assert(!(ret == 0 && full));
4a514fb20e04df397842cde11cc9ea92abfe9728Timo Sirainen
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen if (ret >= 0) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* leave CR+LF + last line to buffer */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen block_r->size = boundary_start;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (block_r->size != 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen parse_body_add_block(ctx, block_r);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return ret <= 0 ? ret :
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen parse_part_finish(ctx, boundary, block_r, FALSE);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenstatic int parse_next_body_to_eof(struct message_parser_ctx *ctx,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen struct message_block *block_r)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen{
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen int ret;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if ((ret = message_parser_read_more(ctx, block_r)) <= 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return ret;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen parse_body_add_block(ctx, block_r);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen return 1;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen}
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainenstatic void parse_content_type(struct message_parser_ctx *ctx,
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen struct message_header_line *hdr)
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen{
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen struct rfc822_parser_context parser;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen const char *key, *value;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen string_t *content_type;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen if (ctx->part_seen_content_type)
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen return;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen ctx->part_seen_content_type = TRUE;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen (void)rfc822_skip_lwsp(&parser);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen content_type = t_str_new(64);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (rfc822_parse_content_type(&parser, content_type) < 0)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (strcasecmp(str_c(content_type), "message/rfc822") == 0)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MESSAGE_RFC822;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen else if (strncasecmp(str_c(content_type), "text", 4) == 0 &&
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen (str_len(content_type) == 4 ||
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen str_data(content_type)[4] == '/'))
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_TEXT;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen else if (strncasecmp(str_c(content_type), "multipart/", 10) == 0) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (strcasecmp(str_c(content_type)+10, "digest") == 0)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART_DIGEST;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 ||
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->last_boundary != NULL)
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen return;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen while (rfc822_parse_content_param(&parser, &key, &value) > 0) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (strcasecmp(key, "boundary") == 0) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->last_boundary = p_strdup(ctx->parser_pool, value);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen break;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen }
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen}
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen#define MUTEX_FLAGS \
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen (MESSAGE_PART_FLAG_MESSAGE_RFC822 | MESSAGE_PART_FLAG_MULTIPART)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenstatic int parse_next_header(struct message_parser_ctx *ctx,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct message_block *block_r)
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen{
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct message_part *part = ctx->part;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct message_header_line *hdr;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen int ret;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (ctx->skip > 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen i_stream_skip(ctx->input, ctx->skip);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->skip = 0;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0))
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return ret;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (hdr != NULL) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (hdr->eoh)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen else if (strcasecmp(hdr->name, "Mime-Version") == 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* it's MIME. Content-* headers are valid */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen part->flags |= MESSAGE_PART_FLAG_IS_MIME;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen } else if (strcasecmp(hdr->name, "Content-Type") == 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if ((ctx->flags &
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen MESSAGE_PARSER_FLAG_MIME_VERSION_STRICT) == 0)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen part->flags |= MESSAGE_PART_FLAG_IS_MIME;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (hdr->continues)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen hdr->use_full_value = TRUE;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen else {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen t_push();
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen parse_content_type(ctx, hdr);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen t_pop();
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen block_r->hdr = hdr;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen block_r->size = 0;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return 1;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* end of headers */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->last_boundary == NULL) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* multipart type but no message boundary */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen part->flags = 0;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if ((part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* It's not MIME. Reset everything we found from
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen Content-Type. */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen part->flags = 0;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->last_boundary = NULL;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (!ctx->part_seen_content_type ||
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen (part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (part->parent != NULL &&
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen (part->parent->flags &
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen MESSAGE_PART_FLAG_MULTIPART_DIGEST) != 0) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen /* when there's no content-type specified and we're
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen below multipart/digest, assume message/rfc822
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen content-type */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen part->flags |= MESSAGE_PART_FLAG_MESSAGE_RFC822;
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen } else {
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen /* otherwise we default to text/plain */
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen part->flags |= MESSAGE_PART_FLAG_TEXT;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
494a5de15db3b2806ab31d5ecc3e1c306ae14d06Timo Sirainen
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen if (message_parse_header_has_nuls(ctx->hdr_parser_ctx))
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen i_assert((part->flags & MUTEX_FLAGS) != MUTEX_FLAGS);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
9d4c027e7de01ab948d6221bc27c9b45d32d1ea5Timo Sirainen ctx->last_chr = '\n';
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (ctx->last_boundary != NULL) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen parse_next_body_multipart_init(ctx);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else if (part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) {
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen parse_next_body_message_rfc822_init(ctx);
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen ctx->parse_next_block = parse_next_header_init;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else if (ctx->boundaries != NULL)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ctx->parse_next_block = parse_next_body_to_boundary;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen else
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen ctx->parse_next_block = parse_next_body_to_eof;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen ctx->want_count = 1;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen /* return empty block as end of headers */
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen block_r->hdr = NULL;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen block_r->size = 0;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen return 1;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenstatic int parse_next_header_init(struct message_parser_ctx *ctx,
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen struct message_block *block_r)
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen{
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen i_assert(ctx->hdr_parser_ctx == NULL);
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen ctx->hdr_parser_ctx =
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen message_parse_header_init(ctx->input, &ctx->part->header_size,
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen ctx->hdr_flags);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->part_seen_content_type = FALSE;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->parse_next_block = parse_next_header;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return parse_next_header(ctx, block_r);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenstatic int preparsed_parse_eof(struct message_parser_ctx *ctx ATTR_UNUSED,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct message_block *block_r ATTR_UNUSED)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return -1;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenstatic void preparsed_skip_to_next(struct message_parser_ctx *ctx)
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen while (ctx->part != NULL) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (ctx->part->next != NULL) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ctx->part = ctx->part->next;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen break;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->part = ctx->part->parent;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (ctx->part == NULL)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ctx->parse_next_block = preparsed_parse_eof;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenstatic int preparsed_parse_body_finish(struct message_parser_ctx *ctx,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct message_block *block_r)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_stream_skip(ctx->input, ctx->skip);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ctx->skip = 0;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen preparsed_skip_to_next(ctx);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return ctx->parse_next_block(ctx, block_r);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenstatic int preparsed_parse_body_more(struct message_parser_ctx *ctx,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct message_block *block_r)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen{
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen uoff_t end_offset = ctx->part->physical_pos +
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->part->header_size.physical_size +
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen ctx->part->body_size.physical_size;
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen int ret;
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen ret = message_parser_read_more(ctx, block_r);
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen if (ret <= 0)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return ret;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (ctx->input->v_offset + block_r->size >= end_offset) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen block_r->size = end_offset - ctx->input->v_offset;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->parse_next_block = preparsed_parse_body_finish;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->skip = block_r->size;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return 1;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenstatic int preparsed_parse_body_init(struct message_parser_ctx *ctx,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct message_block *block_r)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen{
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen uoff_t offset = ctx->part->physical_pos +
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->part->header_size.physical_size;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen i_assert(offset >= ctx->input->v_offset);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen i_stream_skip(ctx->input, offset - ctx->input->v_offset);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->parse_next_block = preparsed_parse_body_more;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return preparsed_parse_body_more(ctx, block_r);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenstatic int preparsed_parse_finish_header(struct message_parser_ctx *ctx,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct message_block *block_r)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (ctx->part->children != NULL) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->part = ctx->part->children;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen } else if ((ctx->flags & MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK) == 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->parse_next_block = preparsed_parse_body_init;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen } else {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen preparsed_skip_to_next(ctx);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return ctx->parse_next_block(ctx, block_r);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenstatic int preparsed_parse_next_header(struct message_parser_ctx *ctx,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct message_block *block_r)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct message_header_line *hdr;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen int ret;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0))
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return ret;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (hdr != NULL) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen block_r->hdr = hdr;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen block_r->size = 0;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return 1;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen message_parse_header_deinit(&ctx->hdr_parser_ctx);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->parse_next_block = preparsed_parse_finish_header;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* return empty block as end of headers */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen block_r->hdr = NULL;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen block_r->size = 0;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return 1;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenstatic int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct message_block *block_r)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen i_assert(ctx->hdr_parser_ctx == NULL);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen i_assert(ctx->part->physical_pos >= ctx->input->v_offset);
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen i_stream_skip(ctx->input, ctx->part->physical_pos -
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen ctx->input->v_offset);
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ctx->hdr_parser_ctx =
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen message_parse_header_init(ctx->input, NULL, ctx->hdr_flags);
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen ctx->parse_next_block = preparsed_parse_next_header;
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen return preparsed_parse_next_header(ctx, block_r);
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen}
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainenstruct message_parser_ctx *
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainenmessage_parser_init(pool_t part_pool, struct istream *input,
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen enum message_header_parser_flags hdr_flags,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen enum message_parser_flags flags)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct message_parser_ctx *ctx;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen pool_t pool;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen pool = pool_alloconly_create("Message Parser", 1024);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ctx = p_new(pool, struct message_parser_ctx, 1);
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen ctx->parser_pool = pool;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen ctx->part_pool = part_pool;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen ctx->hdr_flags = hdr_flags;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->flags = flags;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->input = input;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->parts = ctx->part = part_pool == NULL ? NULL :
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen p_new(part_pool, struct message_part, 1);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ctx->parse_next_block = parse_next_header_init;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen i_stream_ref(input);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return ctx;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenstruct message_parser_ctx *
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenmessage_parser_init_from_parts(struct message_part *parts,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct istream *input,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen enum message_header_parser_flags hdr_flags,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen enum message_parser_flags flags)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen{
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct message_parser_ctx *ctx;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx = message_parser_init(NULL, input, hdr_flags, flags);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->parts = ctx->part = parts;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ctx->parse_next_block = preparsed_parse_next_header_init;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return ctx;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenstruct message_part *message_parser_deinit(struct message_parser_ctx **_ctx)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct message_parser_ctx *ctx = *_ctx;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct message_part *parts = ctx->parts;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen *_ctx = NULL;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_stream_unref(&ctx->input);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen pool_unref(&ctx->parser_pool);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return parts;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenint message_parser_parse_next_block(struct message_parser_ctx *ctx,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct message_block *block_r)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen int ret;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen bool eof = FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen while ((ret = ctx->parse_next_block(ctx, block_r)) == 0) {
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen ret = message_parser_read_more(ctx, block_r);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (ret == 0) {
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen i_assert(!ctx->input->blocking);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen return 0;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen }
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen if (ret == -1) {
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen i_assert(!eof);
cb933f0a570a9cef5c975eadb818aa6b1002a269Timo Sirainen eof = TRUE;
cb933f0a570a9cef5c975eadb818aa6b1002a269Timo Sirainen }
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen }
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen block_r->part = ctx->part;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (ret < 0 && ctx->part != NULL) {
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen i_assert(ctx->input->eof);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen while (ctx->part->parent != NULL) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen message_size_add(&ctx->part->parent->body_size,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen &ctx->part->body_size);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen message_size_add(&ctx->part->parent->body_size,
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen &ctx->part->header_size);
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen ctx->part = ctx->part->parent;
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen }
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen }
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen return ret;
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen}
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen#undef message_parser_parse_header
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainenvoid message_parser_parse_header(struct message_parser_ctx *ctx,
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen struct message_size *hdr_size,
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen message_part_header_callback_t *callback,
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen void *context)
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen{
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen struct message_block block;
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen int ret;
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen while ((ret = message_parser_parse_next_block(ctx, &block)) > 0) {
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen callback(block.part, block.hdr, context);
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (block.hdr == NULL)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen break;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen i_assert(ret != 0);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (ret < 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* well, can't return error so fake end of headers */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen callback(ctx->part, NULL, context);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen *hdr_size = ctx->part->header_size;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen#undef message_parser_parse_body
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid message_parser_parse_body(struct message_parser_ctx *ctx,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen message_part_header_callback_t *hdr_callback,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen void *context)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct message_block block;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen int ret;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen while ((ret = message_parser_parse_next_block(ctx, &block)) > 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (block.size == 0 && hdr_callback != NULL)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen hdr_callback(block.part, block.hdr, context);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_assert(ret != 0);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen