message-decoder.c revision 919733fcead68b0e9617cfff86ae5c74d097c6cd
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2006 Timo Sirainen */
369a1084c500a9df7448ffa9409ce32e42060bc2Timo Sirainen/* base64 takes max 4 bytes per character, q-p takes max 3. */
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.. */
e12648867876aaec17e06ee4caef0bb60363449dTimo Sirainen char translation_buf[MAX_TRANSLATION_BUF_SIZE];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct message_decoder_context *message_decoder_init_ucase(void)
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);
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainenvoid message_decoder_deinit(struct message_decoder_context **_ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmessage_decode_header_callback(const unsigned char *data, size_t size,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_decoder_context *ctx = context;
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen if (charset == NULL || charset_is_utf8(charset)) {
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen _charset_utf8_ucase(data, size, ctx->buf, ctx->buf->used);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen t = charset_to_utf8_begin(charset, &unknown_charset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* let's just ignore this part */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* ignore any errors */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)charset_to_ucase_utf8_full(t, data, &size, ctx->buf);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic void parse_content_encoding(const unsigned char *value, size_t value_len,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct message_decoder_context *ctx = context;
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen if (memcasecmp(value, "quoted-printable", 16) == 0)
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainenparse_content_type_param(const unsigned char *name, size_t name_len,
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen struct message_decoder_context *ctx = context;
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen if (name_len == 7 && memcasecmp(name, "charset", 7) == 0 &&
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen ctx->content_charset = i_strndup(value, value_len);
7761758f43d6150be4b07f4c54457ce662f78c4cTimo Sirainen if (value_quoted) str_unescape(ctx->content_charset);
0cbbf6a61cc30312a76fa0c06cec01bae99d66b5Timo Sirainen ctx->charset_utf8 = charset_is_utf8(ctx->content_charset);
659fe5d24825b160cae512538088020d97a60239Timo Sirainenstatic bool message_decode_header(struct message_decoder_context *ctx,
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen strcasecmp(hdr->name, "Content-Transfer-Encoding") == 0) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen message_header_decode(hdr->full_value, hdr->full_value_len,
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen _charset_utf8_ucase((const unsigned char *)hdr->name, hdr->name_len,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->hdr.name = CONST_PTR_OFFSET(ctx->buf->data,
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen ctx->hdr.name_len = ctx->buf->used - 1 - value_len;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void translation_buf_decode(struct message_decoder_context *ctx,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen unsigned char trans_buf[MAX_TRANSLATION_BUF_SIZE+1];
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 memcpy(trans_buf + ctx->translation_size, data, skip);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen (void)charset_to_ucase_utf8_full(ctx->charset_trans,
48136ae5a0eb49daa44e343553f3688a500307e2Timo Sirainenstatic bool message_decode_body(struct message_decoder_context *ctx,
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen unsigned char new_buf[MAX_ENCODING_BUF_SIZE+1];
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen if (ctx->charset_trans == NULL && !ctx->charset_utf8) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen charset_to_utf8_begin(ctx->content_charset != NULL ?
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* @UNSAFE */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(new_buf, ctx->encoding_buf, ctx->encoding_size);
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen memcpy(new_buf + ctx->encoding_size, input->data, skip);
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen /* just skip this body */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen quoted_printable_decode(input->data + skip, input->size - skip,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (base64_decode(new_buf, ctx->encoding_size + skip,
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen /* corrupted base64 data, don't bother with
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen the rest of it */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = base64_decode(input->data + skip, input->size - skip,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* corrupted base64 data, don't bother with
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen the rest of it */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* end of base64 input */
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen /* @UNSAFE */
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen i_assert(ctx->encoding_size <= sizeof(ctx->encoding_buf));
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen _charset_utf8_ucase(data, size, ctx->buf2, ctx->buf2->used);
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen (void)charset_to_ucase_utf8_full(ctx->charset_trans,
c251a38df327599a62d341bf5c2282f31352faa5Timo Sirainenbool message_decoder_decode_next_block(struct message_decoder_context *ctx,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* MIME part changed. */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return message_decode_header(ctx, input->hdr, output);