message-decoder.c revision 919733fcead68b0e9617cfff86ae5c74d097c6cd
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2006 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "buffer.h"
94a8cb0ee1d85569ad1a2acacd92d3ce22f8a1cbTimo Sirainen#include "strescape.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "base64.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "charset-utf8.h"
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen#include "quoted-printable.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "message-parser.h"
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen#include "message-content-parser.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "message-header-decode.h"
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen#include "message-decoder.h"
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenenum content_type {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen CONTENT_TYPE_UNKNOWN = 0,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen CONTENT_TYPE_BINARY,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen CONTENT_TYPE_QP,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen CONTENT_TYPE_BASE64
8887bf3757d51d73887dd20b1db3334d867d3817Timo Sirainen};
8887bf3757d51d73887dd20b1db3334d867d3817Timo Sirainen
369a1084c500a9df7448ffa9409ce32e42060bc2Timo Sirainen/* base64 takes max 4 bytes per character, q-p takes max 3. */
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen#define MAX_ENCODING_BUF_SIZE 3
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen/* UTF-8 takes max 5 bytes per character. Not sure about others, but I'd think
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen 10 is more than enough for everyone.. */
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen#define MAX_TRANSLATION_BUF_SIZE 10
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct message_decoder_context {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_part *prev_part;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_header_line hdr;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen buffer_t *buf, *buf2;
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen
e12648867876aaec17e06ee4caef0bb60363449dTimo Sirainen struct charset_translation *charset_trans;
e12648867876aaec17e06ee4caef0bb60363449dTimo Sirainen char translation_buf[MAX_TRANSLATION_BUF_SIZE];
e12648867876aaec17e06ee4caef0bb60363449dTimo Sirainen unsigned int translation_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen char encoding_buf[MAX_ENCODING_BUF_SIZE];
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen unsigned int encoding_size;
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen char *content_charset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum content_type content_type;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int charset_utf8:1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct message_decoder_context *message_decoder_init_ucase(void)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_decoder_context *ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx = i_new(struct message_decoder_context, 1);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen ctx->buf = buffer_create_dynamic(default_pool, 8192);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen ctx->buf2 = buffer_create_dynamic(default_pool, 8192);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen return ctx;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainenvoid message_decoder_deinit(struct message_decoder_context **_ctx)
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_decoder_context *ctx = *_ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *_ctx = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->charset_trans != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen charset_to_utf8_end(&ctx->charset_trans);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_free(ctx->buf);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen buffer_free(ctx->buf2);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(ctx->content_charset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainenstatic bool
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmessage_decode_header_callback(const unsigned char *data, size_t size,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *charset, void *context)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_decoder_context *ctx = context;
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen struct charset_translation *t;
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen bool unknown_charset;
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen if (charset == NULL || charset_is_utf8(charset)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* ASCII */
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen _charset_utf8_ucase(data, size, ctx->buf, ctx->buf->used);
2a734f36105e33ab452d057df6bc7a2b7d9f96f0Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen t = charset_to_utf8_begin(charset, &unknown_charset);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen if (unknown_charset) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* let's just ignore this part */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* ignore any errors */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)charset_to_ucase_utf8_full(t, data, &size, ctx->buf);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen charset_to_utf8_end(&t);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return TRUE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic void parse_content_encoding(const unsigned char *value, size_t value_len,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen void *context)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct message_decoder_context *ctx = context;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen ctx->content_type = CONTENT_TYPE_UNKNOWN;
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen switch (value_len) {
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen case 4:
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen if (memcasecmp(value, "7bit", 4) == 0 ||
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen memcasecmp(value, "8bit", 4) == 0)
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen ctx->content_type = CONTENT_TYPE_BINARY;
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen break;
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen case 6:
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen if (memcasecmp(value, "base64", 6) == 0)
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen ctx->content_type = CONTENT_TYPE_BASE64;
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen else if (memcasecmp(value, "binary", 6) == 0)
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen ctx->content_type = CONTENT_TYPE_BINARY;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen case 16:
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen if (memcasecmp(value, "quoted-printable", 16) == 0)
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen ctx->content_type = CONTENT_TYPE_QP;
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen break;
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen }
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6bc98d3898c475ba7615ba2b016e5142c8b2c09fTimo Sirainenstatic void
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainenparse_content_type_param(const unsigned char *name, size_t name_len,
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen const unsigned char *value, size_t value_len,
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen bool value_quoted, void *context)
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen{
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen struct message_decoder_context *ctx = context;
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen if (name_len == 7 && memcasecmp(name, "charset", 7) == 0 &&
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen ctx->content_charset == NULL) {
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen ctx->content_charset = i_strndup(value, value_len);
7761758f43d6150be4b07f4c54457ce662f78c4cTimo Sirainen if (value_quoted) str_unescape(ctx->content_charset);
6bc98d3898c475ba7615ba2b016e5142c8b2c09fTimo Sirainen
0cbbf6a61cc30312a76fa0c06cec01bae99d66b5Timo Sirainen ctx->charset_utf8 = charset_is_utf8(ctx->content_charset);
6bc98d3898c475ba7615ba2b016e5142c8b2c09fTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
659fe5d24825b160cae512538088020d97a60239Timo Sirainenstatic bool message_decode_header(struct message_decoder_context *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_header_line *hdr,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_block *output)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t value_len;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen if (hdr->continues) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen hdr->use_full_value = TRUE;
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen if (hdr->name_len == 12 &&
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen strcasecmp(hdr->name, "Content-Type") == 0) {
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen message_content_parse_header(hdr->full_value,
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen hdr->full_value_len,
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen null_parse_content_callback,
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen parse_content_type_param, ctx);
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen }
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen if (hdr->name_len == 25 &&
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen strcasecmp(hdr->name, "Content-Transfer-Encoding") == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen message_content_parse_header(hdr->full_value,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen hdr->full_value_len,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen parse_content_encoding,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen null_parse_content_param_callback,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_set_used_size(ctx->buf, 0);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen message_header_decode(hdr->full_value, hdr->full_value_len,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen message_decode_header_callback, ctx);
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen value_len = ctx->buf->used;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen _charset_utf8_ucase((const unsigned char *)hdr->name, hdr->name_len,
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen ctx->buf, ctx->buf->used);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen buffer_append_c(ctx->buf, '\0');
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->hdr = *hdr;
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen ctx->hdr.full_value = ctx->buf->data;
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen ctx->hdr.full_value_len = value_len;
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen ctx->hdr.value_len = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->hdr.name = CONST_PTR_OFFSET(ctx->buf->data,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->hdr.full_value_len);
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen ctx->hdr.name_len = ctx->buf->used - 1 - value_len;
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen output->hdr = &ctx->hdr;
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen return TRUE;
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void translation_buf_decode(struct message_decoder_context *ctx,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen const unsigned char **data, size_t *size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen unsigned char trans_buf[MAX_TRANSLATION_BUF_SIZE+1];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t pos, skip;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* @UNSAFE */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(trans_buf, ctx->translation_buf, ctx->translation_size);
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen skip = sizeof(trans_buf) - ctx->translation_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (skip > *size)
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen skip = *size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(trans_buf + ctx->translation_size, data, skip);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen pos = *size;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen (void)charset_to_ucase_utf8_full(ctx->charset_trans,
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen *data, &pos, ctx->buf2);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
7c95b03620a03a43dd72d39608cea5fc77393ad6Timo Sirainen i_assert(pos > ctx->translation_size);
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen skip = (ctx->translation_size + skip) - pos;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(*size >= skip);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *data += skip;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *size -= skip;
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen
2674b4f0cf8f3c203d8e56b29735f5e267038dafTimo Sirainen ctx->translation_size = 0;
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen}
48136ae5a0eb49daa44e343553f3688a500307e2Timo Sirainen
48136ae5a0eb49daa44e343553f3688a500307e2Timo Sirainenstatic bool message_decode_body(struct message_decoder_context *ctx,
2674b4f0cf8f3c203d8e56b29735f5e267038dafTimo Sirainen struct message_block *input,
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen struct message_block *output)
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen{
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen unsigned char new_buf[MAX_ENCODING_BUF_SIZE+1];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const unsigned char *data = NULL;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen size_t pos, size = 0, skip = 0;
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen bool unknown_charset;
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen int ret;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen if (ctx->charset_trans == NULL && !ctx->charset_utf8) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen ctx->charset_trans =
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen charset_to_utf8_begin(ctx->content_charset != NULL ?
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->content_charset : "UTF-8",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &unknown_charset);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->encoding_size != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* @UNSAFE */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(new_buf, ctx->encoding_buf, ctx->encoding_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen skip = sizeof(new_buf) - ctx->encoding_size;
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen if (skip > input->size)
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen skip = input->size;
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen memcpy(new_buf + ctx->encoding_size, input->data, skip);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen switch (ctx->content_type) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case CONTENT_TYPE_UNKNOWN:
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen /* just skip this body */
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen return FALSE;
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case CONTENT_TYPE_BINARY:
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen data = input->data;
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen size = pos = input->size;
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen break;
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen case CONTENT_TYPE_QP:
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen buffer_set_used_size(ctx->buf, 0);
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen if (ctx->encoding_size != 0) {
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen quoted_printable_decode(new_buf,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->encoding_size + skip,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &pos, ctx->buf);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(pos >= ctx->encoding_size);
aa0647f2debf0d48d504a321186f66c85596aaf4Timo Sirainen skip = pos - ctx->encoding_size;
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen }
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen quoted_printable_decode(input->data + skip, input->size - skip,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &pos, ctx->buf);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pos += skip;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen data = ctx->buf->data;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen size = ctx->buf->used;
89caf81340a4da959ef18c5f9b9c99824a53066bTimo Sirainen break;
89caf81340a4da959ef18c5f9b9c99824a53066bTimo Sirainen case CONTENT_TYPE_BASE64:
89caf81340a4da959ef18c5f9b9c99824a53066bTimo Sirainen buffer_set_used_size(ctx->buf, 0);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen if (ctx->encoding_size != 0) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (base64_decode(new_buf, ctx->encoding_size + skip,
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen &pos, ctx->buf) < 0) {
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen /* corrupted base64 data, don't bother with
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen the rest of it */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
685393de106e55b61f754d420e378d05bd462ebbTimo Sirainen }
87712707722ef7d73acb065546e61afa4455cd9eTimo Sirainen i_assert(pos >= ctx->encoding_size);
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen skip = pos - ctx->encoding_size;
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = base64_decode(input->data + skip, input->size - skip,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &pos, ctx->buf);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* corrupted base64 data, don't bother with
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen the rest of it */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
7761758f43d6150be4b07f4c54457ce662f78c4cTimo Sirainen if (ret == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* end of base64 input */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pos = input->size - skip;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen pos += skip;
94a8cb0ee1d85569ad1a2acacd92d3ce22f8a1cbTimo Sirainen data = ctx->buf->data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size = ctx->buf->used;
94a8cb0ee1d85569ad1a2acacd92d3ce22f8a1cbTimo Sirainen break;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (pos != input->size) {
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen /* @UNSAFE */
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen i_assert(pos < input->size);
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen ctx->encoding_size = input->size - pos;
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen i_assert(ctx->encoding_size <= sizeof(ctx->encoding_buf));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(ctx->encoding_buf, input->data + pos,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->encoding_size);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen } else {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ctx->encoding_size = 0;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
bb26f09873c18f342cd1ab2d0ee0b9018e6546d9Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (ctx->charset_utf8) {
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen#if 0
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_set_used_size(ctx->buf2, 0);
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen _charset_utf8_ucase(data, size, ctx->buf2, ctx->buf2->used);
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen output->data = ctx->buf2->data;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen output->size = ctx->buf2->used;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (ctx->charset_trans == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#endif
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen output->data = data;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen output->size = size;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen } else {
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen buffer_set_used_size(ctx->buf2, 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->translation_size != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen translation_buf_decode(ctx, &data, &size);
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen pos = size;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen (void)charset_to_ucase_utf8_full(ctx->charset_trans,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data, &pos, ctx->buf2);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (pos != size) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->translation_size = size - pos;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(ctx->translation_size <=
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen sizeof(ctx->translation_buf));
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen memcpy(ctx->translation_buf, data + pos,
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen ctx->translation_size);
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen output->data = ctx->buf2->data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen output->size = ctx->buf2->used;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen output->hdr = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
c251a38df327599a62d341bf5c2282f31352faa5Timo Sirainen
c251a38df327599a62d341bf5c2282f31352faa5Timo Sirainenbool message_decoder_decode_next_block(struct message_decoder_context *ctx,
c251a38df327599a62d341bf5c2282f31352faa5Timo Sirainen struct message_block *input,
c251a38df327599a62d341bf5c2282f31352faa5Timo Sirainen struct message_block *output)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (input->part != ctx->prev_part) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* MIME part changed. */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_free_and_null(ctx->content_charset);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ctx->content_type = CONTENT_TYPE_BINARY;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ctx->charset_utf8 = TRUE;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen ctx->encoding_size = 0;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen output->part = input->part;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ctx->prev_part = input->part;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen if (input->hdr != NULL)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return message_decode_header(ctx, input->hdr, output);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen else
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return message_decode_body(ctx, input, output);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen