bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
64510d2cc23a79d2142030bf5bade44baa490db3Timo Sirainen/* base64 takes max 4 bytes per character, q-p takes max 3. */
2c70dc3ca3f0e9e67b76065c4824aba6b2e4251cTimo Sirainen char translation_buf[CHARSET_MAX_PENDING_BUF_SIZE];
7e50cca6b1dab5a7e2a90a8949678c62f4a0958aTimo Sirainenmessage_decode_body_init_charset(struct message_decoder_context *ctx,
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainenmessage_decoder_init(normalizer_func_t *normalizer,
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen ctx = i_new(struct message_decoder_context, 1);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen ctx->buf = buffer_create_dynamic(default_pool, 8192);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen ctx->buf2 = buffer_create_dynamic(default_pool, 8192);
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen ctx->encoding_buf = buffer_create_dynamic(default_pool, 128);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenvoid message_decoder_deinit(struct message_decoder_context **_ctx)
7e50cca6b1dab5a7e2a90a8949678c62f4a0958aTimo Sirainenvoid message_decoder_set_return_binary(struct message_decoder_context *ctx,
7e50cca6b1dab5a7e2a90a8949678c62f4a0958aTimo Sirainen ctx->flags |= MESSAGE_DECODER_FLAG_RETURN_BINARY;
7e50cca6b1dab5a7e2a90a8949678c62f4a0958aTimo Sirainen ctx->flags &= ~MESSAGE_DECODER_FLAG_RETURN_BINARY;
7e50cca6b1dab5a7e2a90a8949678c62f4a0958aTimo Sirainen message_decode_body_init_charset(ctx, ctx->prev_part);
4e2d7dd2b201ae2083b6637d7ec0d37f49faca45Timo Sirainenenum message_cte message_decoder_parse_cte(struct message_header_line *hdr)
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen (void)rfc822_parse_mime_token(&parser, value);
87b426af6a2365c6840b14281a98c23e903bf28eTimo Sirainen if (i_memcasecmp(str_data(value), "7bit", 4) == 0 ||
87b426af6a2365c6840b14281a98c23e903bf28eTimo Sirainen i_memcasecmp(str_data(value), "8bit", 4) == 0)
87b426af6a2365c6840b14281a98c23e903bf28eTimo Sirainen if (i_memcasecmp(str_data(value), "base64", 6) == 0)
87b426af6a2365c6840b14281a98c23e903bf28eTimo Sirainen else if (i_memcasecmp(str_data(value), "binary", 6) == 0)
87b426af6a2365c6840b14281a98c23e903bf28eTimo Sirainen if (i_memcasecmp(str_data(value), "quoted-printable", 16) == 0)
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainenparse_content_type(struct message_decoder_context *ctx,
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
13961419ca9710eb80c254e00510c58c466f3c08Timo Sirainen ret = rfc822_parse_content_type(&parser, str);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenstatic bool message_decode_header(struct message_decoder_context *ctx,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen strcasecmp(hdr->name, "Content-Transfer-Encoding") == 0)
4e2d7dd2b201ae2083b6637d7ec0d37f49faca45Timo Sirainen ctx->message_cte = message_decoder_parse_cte(hdr);
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen message_header_decode_utf8(hdr->full_value, hdr->full_value_len,
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen (void)ctx->normalizer(hdr->name, hdr->name_len, ctx->buf);
b516a7812b9acc04522869fead3aa6d2787dcdc6Timo Sirainen if (!uni_utf8_get_valid_data((const unsigned char *)hdr->name,
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen ctx->hdr.name = CONST_PTR_OFFSET(ctx->buf->data,
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen ctx->hdr.name_len = ctx->buf->used - 1 - value_len;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenstatic void translation_buf_decode(struct message_decoder_context *ctx,
2c70dc3ca3f0e9e67b76065c4824aba6b2e4251cTimo Sirainen unsigned char trans_buf[CHARSET_MAX_PENDING_BUF_SIZE+1];
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen /* @UNSAFE: move the previously untranslated bytes to trans_buf
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen and see if we have now enough data to get the next character
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen translated */
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen memcpy(trans_buf, ctx->translation_buf, ctx->translation_size);
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen data_wanted = sizeof(trans_buf) - ctx->translation_size;
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen memcpy(trans_buf + ctx->translation_size, *data, data_wanted);
2e0fa95785f9b41c1c6aaf541245579a49f94841Timo Sirainen orig_size = trans_size = ctx->translation_size + data_wanted;
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen (void)charset_to_utf8(ctx->charset_trans, trans_buf,
2e0fa95785f9b41c1c6aaf541245579a49f94841Timo Sirainen /* need more data to finish the translation. */
2c70dc3ca3f0e9e67b76065c4824aba6b2e4251cTimo Sirainen i_assert(orig_size < CHARSET_MAX_PENDING_BUF_SIZE);
2e0fa95785f9b41c1c6aaf541245579a49f94841Timo Sirainen memcpy(ctx->translation_buf, trans_buf, orig_size);
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainenmessage_decode_body_init_charset(struct message_decoder_context *ctx,
87506860556bf42f656b13f4b14cf81b75261e95Timo Sirainen ctx->binary_input = ctx->content_charset == NULL &&
87506860556bf42f656b13f4b14cf81b75261e95Timo Sirainen (ctx->flags & MESSAGE_DECODER_FLAG_RETURN_BINARY) != 0 &&
87506860556bf42f656b13f4b14cf81b75261e95Timo Sirainen if (ctx->charset_trans != NULL && ctx->content_charset != NULL &&
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen strcasecmp(ctx->content_charset, ctx->charset_trans_charset) == 0) {
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen /* already have the correct translation selected */
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen ctx->charset_trans_charset = i_strdup(ctx->content_charset != NULL ?
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen if (charset_to_utf8_begin(ctx->charset_trans_charset, ctx->normalizer,
c389f8bf1340ca004f3a8f94b3f020bf47fd2610Timo Sirainen ctx->charset_trans = charset_utf8_to_utf8_begin(ctx->normalizer);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenstatic bool message_decode_body(struct message_decoder_context *ctx,
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen buffer_append(ctx->encoding_buf, input->data, input->size);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen /* just skip this body */
1a6a2a1317965035bec89ffbbc0e408fc8652621Timo Sirainen (void)qp_decoder_more(ctx->qp, input->data, input->size,
1a6a2a1317965035bec89ffbbc0e408fc8652621Timo Sirainen /* eat away all input. qp-decoder buffers it internally. */
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen /* corrupted base64 data, don't bother with
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen the rest of it */
64510d2cc23a79d2142030bf5bade44baa490db3Timo Sirainen /* end of base64 input */
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenbool message_decoder_decode_next_block(struct message_decoder_context *ctx,
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen /* MIME part changed. */
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen return message_decode_header(ctx, input->hdr, output);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen return message_decode_body(ctx, input, output);
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen message_decode_body_init_charset(ctx, input->part);
01eef06269e04d0b1b6d67c5055248fefb4f613eTimo Sirainenmessage_decoder_current_content_type(struct message_decoder_context *ctx)