message-decoder.c revision 2c70dc3ca3f0e9e67b76065c4824aba6b2e4251c
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2006-2015 Dovecot authors, see the included COPYING file */
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen/* base64 takes max 4 bytes per character, q-p takes max 3. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen char translation_buf[CHARSET_MAX_PENDING_BUF_SIZE];
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainenmessage_decode_body_init_charset(struct message_decoder_context *ctx,
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainenmessage_decoder_init(normalizer_func_t *normalizer,
104318260228780a5c6b3181b3401e8e504e2776Timo Sirainen ctx = i_new(struct message_decoder_context, 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->buf = buffer_create_dynamic(default_pool, 8192);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->buf2 = buffer_create_dynamic(default_pool, 8192);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->encoding_buf = buffer_create_dynamic(default_pool, 128);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid message_decoder_deinit(struct message_decoder_context **_ctx)
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainenvoid message_decoder_set_return_binary(struct message_decoder_context *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->flags |= MESSAGE_DECODER_FLAG_RETURN_BINARY;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->flags &= ~MESSAGE_DECODER_FLAG_RETURN_BINARY;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen message_decode_body_init_charset(ctx, ctx->prev_part);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenenum message_cte message_decoder_parse_cte(struct message_header_line *hdr)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (void)rfc822_parse_mime_token(&parser, value);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (i_memcasecmp(str_data(value), "7bit", 4) == 0 ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_memcasecmp(str_data(value), "8bit", 4) == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (i_memcasecmp(str_data(value), "base64", 6) == 0)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen else if (i_memcasecmp(str_data(value), "binary", 6) == 0)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (i_memcasecmp(str_data(value), "quoted-printable", 16) == 0)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenparse_content_type(struct message_decoder_context *ctx,
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen const char *const *results;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (rfc822_parse_content_type(&parser, str) <= 0)
cd2ed64888b42b481cde6bb9548c8520516fa3e9Timo Sirainenstatic bool message_decode_header(struct message_decoder_context *ctx,
b8efab7ea8876c0a33a73ee0d08eddada31320f8Timo Sirainen strcasecmp(hdr->name, "Content-Transfer-Encoding") == 0)
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen ctx->message_cte = message_decoder_parse_cte(hdr);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen message_header_decode_utf8(hdr->full_value, hdr->full_value_len,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (void)ctx->normalizer(hdr->name, hdr->name_len, ctx->buf);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (!uni_utf8_get_valid_data((const unsigned char *)hdr->name,
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen ctx->hdr.name = CONST_PTR_OFFSET(ctx->buf->data,
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen ctx->hdr.name_len = ctx->buf->used - 1 - value_len;
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainenstatic void translation_buf_decode(struct message_decoder_context *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned char trans_buf[CHARSET_MAX_PENDING_BUF_SIZE+1];
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* @UNSAFE: move the previously untranslated bytes to trans_buf
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen and see if we have now enough data to get the next character
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen translated */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen memcpy(trans_buf, ctx->translation_buf, ctx->translation_size);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen data_wanted = sizeof(trans_buf) - ctx->translation_size;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen memcpy(trans_buf + ctx->translation_size, *data, data_wanted);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen orig_size = trans_size = ctx->translation_size + data_wanted;
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen (void)charset_to_utf8(ctx->charset_trans, trans_buf,
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* need more data to finish the translation. */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen i_assert(orig_size < CHARSET_MAX_PENDING_BUF_SIZE);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen memcpy(ctx->translation_buf, trans_buf, orig_size);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainenmessage_decode_body_init_charset(struct message_decoder_context *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->binary_input = ctx->content_charset == NULL &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (ctx->flags & MESSAGE_DECODER_FLAG_RETURN_BINARY) != 0 &&
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen if (ctx->charset_trans != NULL && ctx->content_charset != NULL &&
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen strcasecmp(ctx->content_charset, ctx->charset_trans_charset) == 0) {
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen /* already have the correct translation selected */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->charset_trans_charset = i_strdup(ctx->content_charset != NULL ?
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen if (charset_to_utf8_begin(ctx->charset_trans_charset, ctx->normalizer,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic bool message_decode_body(struct message_decoder_context *ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* @UNSAFE */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_append(ctx->encoding_buf, input->data, input->size);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* just skip this body */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (void)quoted_printable_decode(ctx->encoding_buf->data,
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen (void)quoted_printable_decode(input->data, input->size,
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* corrupted base64 data, don't bother with
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen the rest of it */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* end of base64 input */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenbool message_decoder_decode_next_block(struct message_decoder_context *ctx,
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen /* MIME part changed. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return message_decode_header(ctx, input->hdr, output);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return message_decode_body(ctx, input, output);
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen message_decode_body_init_charset(ctx, input->part);