Mercurial > dovecot > original-hg > dovecot-1.2
changeset 5517:2608b9e18bbb HEAD
Rewrite/cleanup
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 04 Apr 2007 08:39:13 +0300 |
parents | 96f0b56489a2 |
children | c7c3855454cb |
files | src/lib-mail/message-header-decode.c |
diffstat | 1 files changed, 82 insertions(+), 88 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-mail/message-header-decode.c Wed Apr 04 07:47:14 2007 +0300 +++ b/src/lib-mail/message-header-decode.c Wed Apr 04 08:39:13 2007 +0300 @@ -1,4 +1,4 @@ -/* Copyright (C) 2002 Timo Sirainen */ +/* Copyright (C) 2002-2007 Timo Sirainen */ #include "lib.h" #include "base64.h" @@ -6,116 +6,110 @@ #include "quoted-printable.h" #include "message-header-decode.h" -static bool split_encoded(const unsigned char *data, size_t *size_p, - const char **charset, const char **encoding, - const unsigned char **text, size_t *text_size_r) +static size_t +message_header_decode_encoded(const unsigned char *data, size_t size, + buffer_t *decodebuf, unsigned int *charsetlen_r) { - size_t size, pos, textpos; - - size = *size_p; - - /* get charset */ - for (pos = 0; pos < size && data[pos] != '?'; pos++) ; - if (data[pos] != '?') return FALSE; - *charset = t_strndup(data, pos); - - /* get encoding */ - pos++; - if (pos+2 >= size || data[pos+1] != '?') - return FALSE; - - if (data[pos] == 'Q' || data[pos] == 'q') - *encoding = "Q"; - else if (data[pos] == 'B' || data[pos] == 'b') - *encoding = "B"; - else - return FALSE; +#define QCOUNT 3 + unsigned int num = 0; + size_t i, start_pos[QCOUNT]; - /* get text */ - pos += 2; - textpos = pos; - while (pos < size && data[pos] != '?') pos++; - if (data[pos] != '?' || pos+1 >= size || data[pos+1] != '=') - return FALSE; - - *text = data + textpos; - *text_size_r = pos - textpos; - *size_p = pos+2; - return TRUE; -} - -static bool -message_header_decode_encoded(const unsigned char *data, size_t *size, - message_header_decode_callback_t *callback, - void *context) -{ - const unsigned char *text; - const char *charset, *encoding; - buffer_t *decodebuf; - size_t text_size; - int ret; - - t_push(); - - /* first split the string charset?encoding?text?= */ - if (!split_encoded(data, size, &charset, &encoding, - &text, &text_size)) { - t_pop(); - return TRUE; + /* data should contain "charset?encoding?text?=" */ + for (i = 0; i < size; i++) { + if (data[i] == '?') { + start_pos[num++] = i; + if (num == QCOUNT) + break; + } + } + if (i == size || data[i+1] != '=') { + /* invalid block */ + return 0; } - decodebuf = buffer_create_static_hard(pool_datastack_create(), - text_size); + buffer_append(decodebuf, data, start_pos[0]); + buffer_append_c(decodebuf, '\0'); + *charsetlen_r = decodebuf->used; - if (*encoding == 'Q') - quoted_printable_decode(text, text_size, NULL, decodebuf); - else { - if (base64_decode(text, text_size, NULL, decodebuf) < 0) { - /* corrupted encoding */ - t_pop(); - return TRUE; + switch (data[start_pos[0]+1]) { + case 'q': + case 'Q': + quoted_printable_decode(data + start_pos[1] + 1, + start_pos[2] - start_pos[1] - 1, + NULL, decodebuf); + break; + case 'b': + case 'B': + if (base64_decode(data + start_pos[1] + 1, + start_pos[2] - start_pos[1] - 1, + NULL, decodebuf) < 0) { + /* contains invalid data. show what we got so far. */ } + break; + default: + /* unknown encoding */ + return 0; } - ret = decodebuf->used == 0 ? FALSE : - callback(decodebuf->data, decodebuf->used, charset, context); - - t_pop(); - return ret; + return start_pos[2] + 2; } void message_header_decode(const unsigned char *data, size_t size, message_header_decode_callback_t *callback, void *context) { - size_t pos, start_pos, subsize; + buffer_t *decodebuf = NULL; + unsigned int charsetlen = 0; + size_t pos, start_pos; + /* =?charset?Q|B?text?= */ + t_push(); start_pos = pos = 0; - while (pos < size) { - if (data[pos] == '=' && pos+1 < size && data[pos+1] == '?') { - /* encoded string beginning */ - if (pos != start_pos) { - /* send the unencoded data so far */ - if (!callback(data + start_pos, pos - start_pos, - NULL, context)) - return; + for (pos = 0; pos + 1 < size; ) { + if (data[pos] != '=' || data[pos+1] != '?') { + pos++; + continue; + } + + /* encoded string beginning */ + if (pos != start_pos) { + /* send the unencoded data so far */ + if (!callback(data + start_pos, pos - start_pos, + NULL, context)) { + start_pos = size; + break; } + } - pos += 2; - subsize = size - pos; - if (!message_header_decode_encoded(data + pos, &subsize, - callback, context)) - return; + if (decodebuf == NULL) { + decodebuf = + buffer_create_dynamic(pool_datastack_create(), + size - pos); + } else { + buffer_set_used_size(decodebuf, 0); + } + + pos += 2; + pos += message_header_decode_encoded(data + pos, size - pos, + decodebuf, &charsetlen); - pos += subsize; - start_pos = pos; - } else { - pos++; + if (decodebuf->used > charsetlen) { + /* decodebuf contains <charset> NUL <text> */ + if (!callback(CONST_PTR_OFFSET(decodebuf->data, + charsetlen), + decodebuf->used - charsetlen, + decodebuf->data, context)) { + start_pos = size; + break; + } } + + start_pos = pos; } - if (size > start_pos) { + if (size != start_pos) { (void)callback(data + start_pos, size - start_pos, NULL, context); } + t_pop(); }