message-decoder.c revision 511ba4416aafb9f9ba1a4193703b95a033267068
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2006-2007 Dovecot authors, see the included COPYING file */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen/* base64 takes max 4 bytes per character, q-p takes max 3. */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen/* UTF-8 takes max 5 bytes per character. Not sure about others, but I'd think
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen 10 is more than enough for everyone.. */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen char translation_buf[MAX_TRANSLATION_BUF_SIZE];
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstruct message_decoder_context *message_decoder_init(bool dtcase)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx = i_new(struct message_decoder_context, 1);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->buf = buffer_create_dynamic(default_pool, 8192);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->buf2 = buffer_create_dynamic(default_pool, 8192);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenvoid message_decoder_deinit(struct message_decoder_context **_ctx)
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainenparse_content_transfer_encoding(struct message_decoder_context *ctx,
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen (void)rfc822_parse_mime_token(&parser, value);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (i_memcasecmp(str_data(value), "7bit", 4) == 0 ||
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_memcasecmp(str_data(value), "8bit", 4) == 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (i_memcasecmp(str_data(value), "base64", 6) == 0)
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen else if (i_memcasecmp(str_data(value), "binary", 6) == 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (i_memcasecmp(str_data(value), "quoted-printable", 16) == 0)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainenparse_content_type(struct message_decoder_context *ctx,
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen if (rfc822_parse_content_type(&parser, str) <= 0)
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainen while (rfc822_parse_content_param(&parser, &key, &value) > 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic bool message_decode_header(struct message_decoder_context *ctx,
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen strcasecmp(hdr->name, "Content-Transfer-Encoding") == 0)
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen message_header_decode_utf8(hdr->full_value, hdr->full_value_len,
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen (void)uni_utf8_to_decomposed_titlecase(hdr->name, hdr->name_len,
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen ctx->hdr.name = CONST_PTR_OFFSET(ctx->buf->data,
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen ctx->hdr.name_len = ctx->buf->used - 1 - value_len;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainenstatic void translation_buf_decode(struct message_decoder_context *ctx,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen unsigned char trans_buf[MAX_TRANSLATION_BUF_SIZE+1];
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* @UNSAFE: move the previously untranslated bytes to trans_buf
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen and see if we have now enough data to get the next character
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen translated */
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen memcpy(trans_buf, ctx->translation_buf, ctx->translation_size);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen data_wanted = sizeof(trans_buf) - ctx->translation_size;
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen memcpy(trans_buf + ctx->translation_size, *data, data_wanted);
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen trans_size = ctx->translation_size + data_wanted;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen (void)charset_to_utf8(ctx->charset_trans, trans_buf,
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainenstatic void message_decode_body_init_charset(struct message_decoder_context *ctx)
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainen strcasecmp(ctx->content_charset, ctx->charset_trans_charset) == 0) {
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainen /* already have the correct translation selected */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen flags = ctx->dtcase ? CHARSET_FLAG_DECOMP_TITLECASE : 0;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen ctx->charset_trans_charset = i_strdup(ctx->content_charset != NULL ?
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (charset_to_utf8_begin(ctx->charset_trans_charset,
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainenstatic bool message_decode_body(struct message_decoder_context *ctx,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned char new_buf[MAX_ENCODING_BUF_SIZE+1];
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen /* @UNSAFE */
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen memcpy(new_buf, ctx->encoding_buf, ctx->encoding_size);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen memcpy(new_buf + ctx->encoding_size, input->data, skip);
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen /* just skip this body */
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen quoted_printable_decode(input->data + skip, input->size - skip,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (base64_decode(new_buf, ctx->encoding_size + skip,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* corrupted base64 data, don't bother with
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen the rest of it */
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen ret = base64_decode(input->data + skip, input->size - skip,
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen /* corrupted base64 data, don't bother with
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen the rest of it */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* end of base64 input */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* @UNSAFE */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen i_assert(ctx->encoding_size <= sizeof(ctx->encoding_buf));
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen (void)uni_utf8_to_decomposed_titlecase(data, size,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen uni_utf8_get_valid_data(data, size, ctx->buf2,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* unknown charset */
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen output->data = uni_utf8_get_valid_data(data, size, ctx->buf2,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenbool message_decoder_decode_next_block(struct message_decoder_context *ctx,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* MIME part changed. */
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainen return message_decode_header(ctx, input->hdr, output);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen return message_decode_body(ctx, input, output);