message-parser.c revision f755df78a17a7c003a182594ab78b0325d929ad4
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "iobuffer.h"
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen#include "rfc822-tokenize.h"
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen#include "message-content-parser.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "message-parser.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "message-size.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainentypedef struct _MessageBoundary {
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen struct _MessageBoundary *next;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen MessagePart *part;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen const char *boundary;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen unsigned int len;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen} MessageBoundary;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainentypedef struct {
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen Pool pool;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen MessagePart *part;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen char *last_boundary;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen char *last_content_type;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen MessageBoundary *boundaries;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen MessageHeaderFunc func;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen void *context;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen} MessageParseContext;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic MessagePart *message_parse_part(IOBuffer *inbuf,
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen MessageParseContext *parse_ctx);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic MessagePart *message_parse_body(IOBuffer *inbuf,
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen MessageBoundary *boundaries,
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen MessageSize *body_size);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenstatic MessagePart *message_skip_boundary(IOBuffer *inbuf,
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen MessageBoundary *boundaries,
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen MessageSize *boundary_size);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenstatic void message_size_add_part(MessageSize *dest, MessagePart *part)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen dest->physical_size +=
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen part->header_size.physical_size +
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen part->body_size.physical_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen dest->virtual_size +=
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen part->header_size.virtual_size +
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen part->body_size.virtual_size;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen dest->lines += part->header_size.lines + part->body_size.lines;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen}
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenstatic MessagePart *message_part_append(Pool pool, MessagePart *parent)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen{
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen MessagePart *part, **list;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen part = p_new(pool, MessagePart, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen part->parent = parent;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen list = &part->parent->children;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen while (*list != NULL)
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen list = &(*list)->next;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen *list = part;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return part;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen}
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainenstatic void parse_content_type(const Rfc822Token *tokens, int count,
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen void *context)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen{
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen MessageParseContext *parse_ctx = context;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen const char *str;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (tokens[0].token != 'A')
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return;
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen if (parse_ctx->last_content_type != NULL)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen str = rfc822_tokens_get_value(tokens, count);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen parse_ctx->last_content_type = p_strdup(parse_ctx->pool, str);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
df831edaa3b3aa22e03bc5fd416a0553c5600a69Phil Carmody if (strcasecmp(str, "message/rfc822") == 0)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen parse_ctx->part->flags |= MESSAGE_PART_FLAG_MESSAGE_RFC822;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen else if (strncasecmp(str, "text/", 5) == 0)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen parse_ctx->part->flags |= MESSAGE_PART_FLAG_TEXT;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen else if (strncasecmp(str, "multipart/", 10) == 0) {
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen parse_ctx->part->flags |= MESSAGE_PART_FLAG_MULTIPART;
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen if (strcasecmp(str+10, "digest") == 0) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen parse_ctx->part->flags |=
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen MESSAGE_PART_FLAG_MULTIPART_DIGEST;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void parse_content_type_param(const Rfc822Token *name,
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen const Rfc822Token *value,
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen int value_count, void *context)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen{
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen MessageParseContext *parse_ctx = context;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen const char *str;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if ((parse_ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 ||
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen name->len != 8 || strncasecmp(name->ptr, "boundary", 8) != 0)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (parse_ctx->last_boundary == NULL) {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen str = rfc822_tokens_get_value(value, value_count);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen parse_ctx->last_boundary = p_strdup(parse_ctx->pool, str);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen }
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen}
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenstatic void parse_header_field(MessagePart *part,
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen const char *name, unsigned int name_len,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen const char *value, unsigned int value_len,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen void *context)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen MessageParseContext *parse_ctx = context;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen /* call the user-defined header parser */
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen if (parse_ctx->func != NULL) {
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen parse_ctx->func(part, name, name_len, value, value_len,
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen parse_ctx->context);
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen }
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (name_len == 12 && strncasecmp(name, "Content-Type", 12) == 0) {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen /* we need to know the boundary */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (void)message_content_parse_header(t_strndup(value, value_len),
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen parse_content_type,
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen parse_content_type_param,
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen parse_ctx);
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen }
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen}
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenstatic MessagePart *message_parse_multipart(IOBuffer *inbuf,
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen MessageParseContext *parse_ctx)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen{
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen MessagePart *parent_part, *next_part, *part;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen MessageBoundary *b;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* multipart message. add new boundary */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen b = t_new(MessageBoundary, 1);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen b->part = parse_ctx->part;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen b->boundary = parse_ctx->last_boundary;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen b->len = strlen(b->boundary);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen b->next = parse_ctx->boundaries;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen parse_ctx->boundaries = b;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* reset fields */
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen parse_ctx->last_boundary = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen parse_ctx->last_content_type = NULL;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen /* skip the data before the first boundary */
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen parent_part = parse_ctx->part;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen next_part = message_skip_boundary(inbuf, parse_ctx->boundaries,
a2738cdb6d2733fb3e186331d68009421a19ea00Timo Sirainen &parent_part->body_size);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* now, parse the parts */
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen while (next_part == parent_part) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* new child */
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen part = message_part_append(parse_ctx->pool, parent_part);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* set child position */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen part->physical_pos =
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen parent_part->physical_pos +
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen parent_part->body_size.physical_size +
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen parent_part->header_size.physical_size;
7af4788b402346c94496095dd819f95ce03fe431Timo Sirainen
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen parse_ctx->part = part;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen next_part = message_parse_part(inbuf, parse_ctx);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen /* update our size */
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen message_size_add_part(&parent_part->body_size, part);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (next_part != parent_part)
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen break;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen /* skip the boundary */
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen next_part = message_skip_boundary(inbuf, parse_ctx->boundaries,
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen &parent_part->body_size);
c24ef531ca58abad996482f5c2e8992be9ae8981Timo Sirainen }
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen /* remove boundary */
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen i_assert(parse_ctx->boundaries == b);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen parse_ctx->boundaries = b->next;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen return next_part;
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen}
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen
2524ef7b34965a1b1895d6140fd8296bf57c78d2Timo Sirainenstatic MessagePart *message_parse_part(IOBuffer *inbuf,
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen MessageParseContext *parse_ctx)
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen{
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen MessagePart *next_part, *part;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen uoff_t hdr_size;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen message_parse_header(parse_ctx->part, inbuf,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen &parse_ctx->part->header_size,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen parse_header_field, parse_ctx);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* update message position/size */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen hdr_size = parse_ctx->part->header_size.physical_size;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (parse_ctx->last_boundary != NULL)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return message_parse_multipart(inbuf, parse_ctx);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (parse_ctx->last_content_type == NULL) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (parse_ctx->part->parent != NULL &&
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen (parse_ctx->part->parent->flags &
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen MESSAGE_PART_FLAG_MULTIPART_DIGEST)) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* when there's no content-type specified and we're
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen below multipart/digest, the assume message/rfc822
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainen content-type */
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainen parse_ctx->part->flags |=
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen MESSAGE_PART_FLAG_MESSAGE_RFC822;
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainen } else {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* otherwise we default to text/plain */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen parse_ctx->part->flags |= MESSAGE_PART_FLAG_TEXT;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen parse_ctx->last_boundary = NULL;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen parse_ctx->last_content_type = NULL;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (parse_ctx->part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* message/rfc822 part - the message body begins with
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen headers again, this works pretty much the same as
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen a single multipart/mixed item */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen part = message_part_append(parse_ctx->pool, parse_ctx->part);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
c6b6ac7819931dfa92c0182ffaa7db07ac6ab0daTimo Sirainen parse_ctx->part = part;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen next_part = message_parse_part(inbuf, parse_ctx);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen parse_ctx->part = part->parent;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* our body size is the size of header+body in message/rfc822 */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen message_size_add_part(&part->parent->body_size, part);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen } else {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* normal message, read until the next boundary */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen part = parse_ctx->part;
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen next_part = message_parse_body(inbuf, parse_ctx->boundaries,
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen &part->body_size);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return next_part;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo SirainenMessagePart *message_parse(Pool pool, IOBuffer *inbuf,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen MessageHeaderFunc func, void *context)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen MessagePart *part;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen MessageParseContext parse_ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen memset(&parse_ctx, 0, sizeof(parse_ctx));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen parse_ctx.pool = pool;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen parse_ctx.func = func;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen parse_ctx.context = context;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen parse_ctx.part = part = p_new(pool, MessagePart, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen t_push();
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen message_parse_part(inbuf, &parse_ctx);
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen t_pop();
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return part;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen}
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen/* skip over to next line increasing message size */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic void message_skip_line(IOBuffer *inbuf, MessageSize *msg_size)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen unsigned char *msg;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen unsigned int i, size, startpos;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen startpos = 0;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen while (io_buffer_read_data(inbuf, &msg, &size, startpos) >= 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (i = startpos; i < size; i++) {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (msg[i] == '\n') {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (msg_size != NULL) {
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen if (i == 0 || msg[i-1] != '\r')
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen msg_size->virtual_size++;
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen msg_size->lines++;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen break;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (i < size) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen startpos = i+1;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen break;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen }
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen if (i > 0) {
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen /* leave the last character, it may be \r */
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_buffer_skip(inbuf, i - 1);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen startpos = 1;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen if (msg_size != NULL) {
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen msg_size->physical_size += i - 1;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen msg_size->virtual_size += i - 1;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen io_buffer_skip(inbuf, startpos);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (msg_size != NULL) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen msg_size->physical_size += startpos;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen msg_size->virtual_size += startpos;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen }
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen}
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenvoid message_parse_header(MessagePart *part, IOBuffer *inbuf,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen MessageSize *hdr_size,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen MessageHeaderFunc func, void *context)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen{
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen unsigned char *msg;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen unsigned int i, size, startpos, missing_cr_count;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen unsigned int line_start, colon_pos, end_pos, name_len, value_len;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen int ret;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen if (hdr_size != NULL)
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen memset(hdr_size, 0, sizeof(MessageSize));
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen missing_cr_count = startpos = line_start = 0;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen colon_pos = UINT_MAX;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen while ((ret = io_buffer_read_data(inbuf, &msg,
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen &size, startpos+1)) != -1) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (ret == -2) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* overflow, line is too long. just skip it. */
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen i_assert(size > 2);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen message_skip_line(inbuf, hdr_size);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen startpos = line_start = 0;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen colon_pos = UINT_MAX;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen continue;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen }
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen if (size == 0) {
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen /* no, we never want empty buffer */
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen continue;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen }
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen /* don't parse the last character, so we can always have
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen one character read-ahead. we never care about the last
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen character anyway, it's either the first character in
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen message body, or if there's no body for any reason, it's
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen the \n ending the header. */
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen size--;
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen for (i = startpos; i < size; i++) {
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen if (msg[i] == ':' && colon_pos == UINT_MAX) {
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen colon_pos = i;
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen continue;
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen }
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen if (msg[i] != '\n')
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen continue;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (hdr_size != NULL)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen hdr_size->lines++;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (i == 0 || msg[i-1] != '\r') {
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen /* missing CR */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen missing_cr_count++;
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen }
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (i == 0 || (i == 1 && msg[i-1] == '\r')) {
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen /* no headers at all */
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen break;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if ((i > 0 && msg[i-1] == '\n') ||
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen (i > 1 && msg[i-2] == '\n' && msg[i-1] == '\r')) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* \n\n or \n\r\n - end of headers */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen break;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* make sure the header doesn't continue to next line */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (!IS_LWSP(msg[i+1])) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (colon_pos != UINT_MAX &&
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen colon_pos != line_start && func != NULL &&
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen !IS_LWSP(msg[line_start])) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* we have a valid header line */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen /* get length of name-field */
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen end_pos = colon_pos-1;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen while (end_pos > line_start &&
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen IS_LWSP(msg[end_pos]))
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen end_pos--;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen name_len = end_pos - line_start + 1;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen /* get length of value field. skip
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen only the initial LWSP after ':'.
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen some fields may want to keep
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen the extra spaces.. */
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen colon_pos++;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (colon_pos < i &&
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen IS_LWSP(msg[colon_pos]))
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen colon_pos++;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen value_len = i - colon_pos;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (msg[i-1] == '\r') value_len--;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* and finally call the function */
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen func(part, msg + line_start, name_len,
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen msg + colon_pos, value_len,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen context);
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen }
df16c7e87511fed827e6890a2a47d13ca48716deTimo Sirainen
df16c7e87511fed827e6890a2a47d13ca48716deTimo Sirainen colon_pos = UINT_MAX;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen line_start = i+1;
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen if (i < size) {
b7651d283ca261015ef3c445f1f27f340f0864e2Timo Sirainen /* end of header */
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen startpos = i+1;
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen break;
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen }
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen if (i > 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* leave the last line to buffer */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (colon_pos != UINT_MAX)
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen colon_pos -= line_start;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen if (hdr_size != NULL)
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen hdr_size->physical_size += line_start;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen io_buffer_skip(inbuf, line_start);
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen startpos = i-line_start;
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen line_start = 0;
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen }
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen }
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen io_buffer_skip(inbuf, startpos);
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen if (hdr_size != NULL) {
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen hdr_size->physical_size += startpos;
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen hdr_size->virtual_size +=
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen hdr_size->physical_size + missing_cr_count;
f20e7fbdc9bdbe8fecb9c661c9b8175f3bb78c69Timo Sirainen i_assert(hdr_size->virtual_size >= hdr_size->physical_size);
c0b1543512bc3e0a3a9f526056a3678a07ce32f5Timo Sirainen }
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen}
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenstatic MessageBoundary *boundary_find(MessageBoundary *boundaries,
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen const char *msg, unsigned int len)
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen{
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen while (boundaries != NULL) {
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen if (boundaries->len <= len &&
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen strncmp(boundaries->boundary, msg, boundaries->len) == 0)
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen return boundaries;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen boundaries = boundaries->next;
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen }
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen return NULL;
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen}
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen/* read until next boundary is found. if skip_over = FALSE, stop at the
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen [\r]\n before the boundary, otherwise leave it right after the known
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen boundary so the ending "--" can be checked. */
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainenstatic MessageBoundary *
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainenmessage_find_boundary(IOBuffer *inbuf, MessageBoundary *boundaries,
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen MessageSize *msg_size, int skip_over)
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen{
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen MessageBoundary *boundary;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen unsigned char *msg;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen unsigned int i, size, startpos, line_start, missing_cr_count;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen boundary = NULL;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen missing_cr_count = startpos = line_start = 0;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen while (io_buffer_read_data(inbuf, &msg, &size, startpos) >= 0) {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen for (i = startpos; i < size; i++) {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (msg[i] != '\n')
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen continue;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen if (i > line_start+2 && msg[line_start] == '-' &&
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen msg[line_start+1] == '-') {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* possible boundary */
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen boundary = boundary_find(boundaries,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg + line_start + 2,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i - line_start - 2);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (boundary != NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen break;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (i == 0 || msg[i-1] != '\r') {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen /* missing CR */
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen missing_cr_count++;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen }
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen msg_size->lines++;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen line_start = i+1;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen }
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (boundary != NULL) {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen /* boundary found */
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen break;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen }
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (i > 0) {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (i - line_start > 128 &&
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen msg[line_start] == '-' && msg[line_start+1] == '-') {
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen /* long partial line, see if it's a boundary.
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen RFC-2046 says that the boundaries must be
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen 70 chars without "--" or less. We allow
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen a bit larger.. */
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen boundary = boundary_find(boundaries,
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen msg + line_start + 2,
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen i - line_start - 2);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (boundary != NULL)
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen break;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* nope, we can skip over the line, just
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen leave the last char since it may be \r */
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen i--;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen } else {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen /* leave the last line to buffer, it may be
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen boundary */
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen i = line_start;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (i > 2) i -= 2; /* leave the \r\n too */
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen line_start -= i;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen }
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen io_buffer_skip(inbuf, i);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg_size->physical_size += i;
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen msg_size->virtual_size += i;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen startpos = size - i;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (boundary != NULL) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (skip_over) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* leave the pointer right after the boundary */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen line_start += 2 + boundary->len;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else if (line_start > 0 && msg[line_start-1] == '\n') {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen /* leave the \r\n before the boundary */
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen line_start--;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg_size->lines--;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if (line_start > 0 && msg[line_start-1] == '\r')
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen line_start--;
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen else
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen missing_cr_count--;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen }
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen startpos = line_start;
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
f4bbeadda12fbd7c219063db68f3e78646d83c2cTimo Sirainen io_buffer_skip(inbuf, startpos);
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen msg_size->physical_size += startpos;
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen msg_size->virtual_size += startpos + missing_cr_count;
abe8754852e70763e92f74caabbcc13d0917714cTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(msg_size->virtual_size >= msg_size->physical_size);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen return boundary;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen}
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainenstatic MessagePart *message_parse_body(IOBuffer *inbuf,
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen MessageBoundary *boundaries,
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen MessageSize *body_size)
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen{
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen MessageBoundary *boundary;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (boundaries == NULL) {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen message_get_body_size(inbuf, body_size, (uoff_t)-1);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen return NULL;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen } else {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen boundary = message_find_boundary(inbuf, boundaries,
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen body_size, FALSE);
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen return boundary == NULL ? NULL : boundary->part;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen/* skip data until next boundary is found. if it's end boundary,
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen skip the footer as well. */
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainenstatic MessagePart *message_skip_boundary(IOBuffer *inbuf,
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen MessageBoundary *boundaries,
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen MessageSize *boundary_size)
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen{
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen MessageBoundary *boundary;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen unsigned char *msg;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen unsigned int size;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen int end_boundary;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen boundary = message_find_boundary(inbuf, boundaries,
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen boundary_size, TRUE);
97e62b2b36dda0acb3215667042f5c80cdee8155Timo Sirainen if (boundary == NULL)
97e62b2b36dda0acb3215667042f5c80cdee8155Timo Sirainen return NULL;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen /* now, see if it's end boundary */
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen end_boundary = FALSE;
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen while (io_buffer_read_data(inbuf, &msg, &size, 1) >= 0) {
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen if (size >= 2) {
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen end_boundary = msg[0] == '-' && msg[1] == '-';
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen break;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen }
97e62b2b36dda0acb3215667042f5c80cdee8155Timo Sirainen }
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen /* skip the rest of the line */
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen message_skip_line(inbuf, boundary_size);
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen if (end_boundary) {
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen /* skip the footer */
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen return message_parse_body(inbuf, boundaries, boundary_size);
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen }
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen return boundary == NULL ? NULL : boundary->part;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen}
dd2df6a67f10792ce31a3666197c0b6885893a3aTimo Sirainen