]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
message-decoder: Fixed assert-crashes caused by the previous quoted-printable change.
authorTimo Sirainen <tss@iki.fi>
Sun, 26 Jul 2009 22:13:41 +0000 (18:13 -0400)
committerTimo Sirainen <tss@iki.fi>
Sun, 26 Jul 2009 22:13:41 +0000 (18:13 -0400)
--HG--
branch : HEAD

src/lib-mail/Makefile.am
src/lib-mail/message-decoder.c
src/lib-mail/test-message-decoder.c [new file with mode: 0644]

index 486c62ff84231a94016486fbf9ede3f7fd346499..5868bf2dbfada5b67cee293127e185488412a328 100644 (file)
@@ -57,6 +57,7 @@ test_programs = \
        test-mbox-from \
        test-message-address \
        test-message-date \
+       test-message-decoder \
        test-message-header-parser \
        test-message-id \
        test-message-parser \
@@ -89,6 +90,10 @@ test_message_date_SOURCES = test-message-date.c
 test_message_date_LDADD = message-date.lo rfc822-parser.lo $(test_libs)
 test_message_date_DEPENDENCIES = message-date.lo rfc822-parser.lo $(test_libs)
 
+test_message_decoder_SOURCES = test-message-decoder.c
+test_message_decoder_LDADD = message-decoder.lo rfc822-parser.lo rfc2231-parser.lo $(test_libs)
+test_message_decoder_DEPENDENCIES = message-decoder.lo rfc822-parser.lo rfc2231-parser.lo $(test_libs)
+
 test_message_header_parser_SOURCES = test-message-header-parser.c
 test_message_header_parser_LDADD = message-header-parser.lo $(test_libs)
 test_message_header_parser_DEPENDENCIES = message-header-parser.lo $(test_libs)
index 2f21ea2eb597365e8fbbcb0b399e1fdb14d73da6..cae1cbea7326c1dbbad4929856b5d8a891b8c70b 100644 (file)
@@ -39,8 +39,7 @@ struct message_decoder_context {
        char translation_buf[MAX_TRANSLATION_BUF_SIZE];
        unsigned int translation_size;
 
-       char encoding_buf[MAX_ENCODING_BUF_SIZE];
-       unsigned int encoding_size;
+       buffer_t *encoding_buf;
 
        char *content_charset;
        enum content_type content_type;
@@ -58,6 +57,7 @@ message_decoder_init(enum message_decoder_flags flags)
        ctx->flags = flags;
        ctx->buf = buffer_create_dynamic(default_pool, 8192);
        ctx->buf2 = buffer_create_dynamic(default_pool, 8192);
+       ctx->encoding_buf = buffer_create_dynamic(default_pool, 128);
        return ctx;
 }
 
@@ -70,6 +70,7 @@ void message_decoder_deinit(struct message_decoder_context **_ctx)
        if (ctx->charset_trans != NULL)
                charset_to_utf8_end(&ctx->charset_trans);
 
+       buffer_free(&ctx->encoding_buf);
        buffer_free(&ctx->buf);
        buffer_free(&ctx->buf2);
        i_free(ctx->charset_trans_charset);
@@ -250,18 +251,13 @@ static bool message_decode_body(struct message_decoder_context *ctx,
                                struct message_block *input,
                                struct message_block *output)
 {
-       unsigned char new_buf[MAX_ENCODING_BUF_SIZE+1];
        const unsigned char *data = NULL;
-       size_t pos, size = 0, skip = 0;
+       size_t pos, size = 0;
        int ret;
 
-       if (ctx->encoding_size != 0) {
+       if (ctx->encoding_buf->used != 0) {
                /* @UNSAFE */
-               memcpy(new_buf, ctx->encoding_buf, ctx->encoding_size);
-               skip = sizeof(new_buf) - ctx->encoding_size;
-               if (skip > input->size)
-                       skip = input->size;
-               memcpy(new_buf + ctx->encoding_size, input->data, skip);
+               buffer_append(ctx->encoding_buf, input->data, input->size);
        }
 
        switch (ctx->content_type) {
@@ -275,34 +271,27 @@ static bool message_decode_body(struct message_decoder_context *ctx,
                break;
        case CONTENT_TYPE_QP:
                buffer_set_used_size(ctx->buf, 0);
-               if (ctx->encoding_size != 0) {
-                       quoted_printable_decode(new_buf,
-                                               ctx->encoding_size + skip,
+               if (ctx->encoding_buf->used != 0) {
+                       quoted_printable_decode(ctx->encoding_buf->data,
+                                               ctx->encoding_buf->used,
+                                               &pos, ctx->buf);
+               } else {
+                       quoted_printable_decode(input->data, input->size,
                                                &pos, ctx->buf);
-                       i_assert(pos >= ctx->encoding_size);
-                       skip = pos - ctx->encoding_size;
                }
-
-               quoted_printable_decode(input->data + skip, input->size - skip,
-                                       &pos, ctx->buf);
-               pos += skip;
                data = ctx->buf->data;
                size = ctx->buf->used;
                break;
        case CONTENT_TYPE_BASE64:
                buffer_set_used_size(ctx->buf, 0);
-               if (ctx->encoding_size != 0) {
-                       if (base64_decode(new_buf, ctx->encoding_size + skip,
-                                         &pos, ctx->buf) < 0) {
-                               /* corrupted base64 data, don't bother with
-                                  the rest of it */
-                               return FALSE;
-                       }
-                       i_assert(pos >= ctx->encoding_size);
-                       skip = pos - ctx->encoding_size;
+               if (ctx->encoding_buf->used != 0) {
+                       ret = base64_decode(ctx->encoding_buf->data,
+                                           ctx->encoding_buf->used,
+                                           &pos, ctx->buf);
+               } else {
+                       ret = base64_decode(input->data, input->size,
+                                           &pos, ctx->buf);
                }
-               ret = base64_decode(input->data + skip, input->size - skip,
-                                   &pos, ctx->buf);
                if (ret < 0) {
                        /* corrupted base64 data, don't bother with
                           the rest of it */
@@ -310,23 +299,19 @@ static bool message_decode_body(struct message_decoder_context *ctx,
                }
                if (ret == 0) {
                        /* end of base64 input */
-                       pos = input->size - skip;
+                       pos = input->size;
+                       buffer_set_used_size(ctx->encoding_buf, 0);
                }
-               pos += skip;
                data = ctx->buf->data;
                size = ctx->buf->used;
                break;
        }
 
-       if (pos != input->size) {
-               /* @UNSAFE */
-               i_assert(pos < input->size);
-               ctx->encoding_size = input->size - pos;
-               i_assert(ctx->encoding_size <= sizeof(ctx->encoding_buf));
-               memcpy(ctx->encoding_buf, input->data + pos,
-                      ctx->encoding_size);
-       } else {
-               ctx->encoding_size = 0;
+       if (ctx->encoding_buf->used != 0)
+               buffer_delete(ctx->encoding_buf, 0, pos);
+       else if (pos != input->size) {
+               buffer_append(ctx->encoding_buf,
+                             input->data + pos, input->size - pos);
        }
 
        if (ctx->binary_input) {
@@ -408,5 +393,5 @@ void message_decoder_decode_reset(struct message_decoder_context *ctx)
        i_free_and_null(ctx->content_charset);
        ctx->content_type = CONTENT_TYPE_BINARY;
        ctx->charset_utf8 = TRUE;
-       ctx->encoding_size = 0;
+       buffer_set_used_size(ctx->encoding_buf, 0);
 }
diff --git a/src/lib-mail/test-message-decoder.c b/src/lib-mail/test-message-decoder.c
new file mode 100644 (file)
index 0000000..a3dc30e
--- /dev/null
@@ -0,0 +1,99 @@
+/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "buffer.h"
+#include "charset-utf8.h"
+#include "quoted-printable.h"
+#include "message-parser.h"
+#include "message-header-decode.h"
+#include "message-decoder.h"
+#include "test-common.h"
+
+bool message_header_decode_utf8(const unsigned char *data, size_t size,
+                               buffer_t *dest, bool dtcase ATTR_UNUSED)
+{
+       buffer_append(dest, data, size);
+       return FALSE;
+}
+
+void quoted_printable_decode(const unsigned char *src, size_t src_size,
+                            size_t *src_pos_r, buffer_t *dest)
+{
+       while (src_size > 0 && src[src_size-1] == ' ')
+               src_size--;
+       buffer_append(dest, src, src_size);
+       *src_pos_r = src_size;
+}
+
+int charset_to_utf8_begin(const char *charset ATTR_UNUSED,
+                         enum charset_flags flags ATTR_UNUSED,
+                         struct charset_translation **t_r)
+{
+       *t_r = NULL;
+       return 0;
+}
+void charset_to_utf8_end(struct charset_translation **t ATTR_UNUSED) { }
+bool charset_is_utf8(const char *charset ATTR_UNUSED) { return TRUE; }
+
+enum charset_result
+charset_to_utf8(struct charset_translation *t ATTR_UNUSED,
+               const unsigned char *src, size_t *src_size, buffer_t *dest)
+{
+       buffer_append(dest, src, *src_size);
+       return CHARSET_RET_OK;
+}
+
+static void test_message_decoder(void)
+{
+       struct message_decoder_context *ctx;
+       struct message_part part;
+       struct message_header_line hdr;
+       struct message_block input, output;
+
+       test_begin("message decoder");
+
+       memset(&part, 0, sizeof(part));
+       memset(&input, 0, sizeof(input));
+       memset(&output, 0, sizeof(output));
+       input.part = &part;
+
+       ctx = message_decoder_init(0);
+
+       hdr.name = "Content-Transfer-Encoding";
+       hdr.name_len = strlen(hdr.name);
+       hdr.full_value = (const void *)"quoted-printable";
+       hdr.full_value_len = strlen((const char *)hdr.full_value);
+       input.hdr = &hdr;
+       test_assert(message_decoder_decode_next_block(ctx, &input, &output));
+
+       input.hdr = NULL;
+       test_assert(message_decoder_decode_next_block(ctx, &input, &output));
+
+       input.hdr = NULL;
+       test_assert(message_decoder_decode_next_block(ctx, &input, &output));
+
+       input.data = (const void *)"foo           ";
+       input.size = strlen((const char *)input.data);
+       test_assert(message_decoder_decode_next_block(ctx, &input, &output));
+       test_assert(output.size == 3);
+       test_assert(memcmp(output.data, "foo", 3) == 0);
+
+       input.data = (const void *)"bar";
+       input.size = strlen((const char *)input.data);
+       test_assert(message_decoder_decode_next_block(ctx, &input, &output));
+       test_assert(output.size == 14);
+       test_assert(memcmp(output.data, "           bar", 14) == 0);
+
+       message_decoder_deinit(&ctx);
+
+       test_end();
+}
+
+int main(void)
+{
+       static void (*test_functions[])(void) = {
+               test_message_decoder,
+               NULL
+       };
+       return test_run(test_functions);
+}