# HG changeset patch # User Timo Sirainen # Date 1033420692 -10800 # Node ID 6f4eeb6a0a0deb82d1ff59e8e8045ef019526d5a # Parent 36ab6a6c8bdfe8696a95935b5dd810af6cd32f9b Several fields in BODY were unquoted. diff -r 36ab6a6c8bdf -r 6f4eeb6a0a0d src/lib-imap/Makefile.am --- a/src/lib-imap/Makefile.am Mon Sep 30 23:36:29 2002 +0300 +++ b/src/lib-imap/Makefile.am Tue Oct 01 00:18:12 2002 +0300 @@ -10,6 +10,7 @@ imap-envelope.c \ imap-match.c \ imap-message-cache.c \ + imap-quote.c \ imap-parser.c \ imap-util.c @@ -19,5 +20,6 @@ imap-envelope.h \ imap-match.h \ imap-message-cache.h \ + imap-quote.h \ imap-parser.h \ imap-util.h diff -r 36ab6a6c8bdf -r 6f4eeb6a0a0d src/lib-imap/imap-bodystructure.c --- a/src/lib-imap/imap-bodystructure.c Mon Sep 30 23:36:29 2002 +0300 +++ b/src/lib-imap/imap-bodystructure.c Tue Oct 01 00:18:12 2002 +0300 @@ -8,6 +8,7 @@ #include "message-content-parser.h" #include "imap-envelope.h" #include "imap-bodystructure.h" +#include "imap-quote.h" #define EMPTY_BODYSTRUCTURE \ "(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 0 0)" @@ -145,10 +146,11 @@ parse_content_transfer_encoding, NULL, part_data); } else if (strcasecmp(name, "Content-ID") == 0) { - part_data->content_id = p_strndup(pool, value, value_len); + part_data->content_id = + imap_quote_value(pool, value, value_len); } else if (strcasecmp(name, "Content-Description") == 0) { part_data->content_description = - p_strndup(pool, value, value_len); + imap_quote_value(pool, value, value_len); } else if (strcasecmp(name, "Content-Disposition") == 0) { part_data->str = t_string_new(256); (void)message_content_parse_header(t_strndup(value, value_len), @@ -162,7 +164,8 @@ parse_content_language, NULL, part_data); } else if (strcasecmp(name, "Content-MD5") == 0) { - part_data->content_md5 = p_strndup(pool, value, value_len); + part_data->content_md5 = + imap_quote_value(pool, value, value_len); } else if (parent_rfc822) { /* message/rfc822, we need the envelope */ imap_envelope_parse_header(pool, &part_data->envelope, diff -r 36ab6a6c8bdf -r 6f4eeb6a0a0d src/lib-imap/imap-envelope.c --- a/src/lib-imap/imap-envelope.c Mon Sep 30 23:36:29 2002 +0300 +++ b/src/lib-imap/imap-envelope.c Tue Oct 01 00:18:12 2002 +0300 @@ -4,6 +4,7 @@ #include "temp-string.h" #include "rfc822-address.h" #include "imap-envelope.h" +#include "imap-quote.h" struct _MessagePartEnvelopeData { Pool pool; @@ -15,178 +16,6 @@ char *in_reply_to, *message_id; }; -#define IS_BREAK_CHAR(c) \ - ((c) == ' ' || (c) == '\t' || \ - (c) == ',' || (c) == ':' || (c) == ';' || (c) == '@' || \ - (c) == '<' || (c) == '>' || (c) == '(' || (c) == ')' || \ - (c) == '[' || (c) == ']' || (c) == '=') - -#define IS_BREAK_OR_CRLF_CHAR(c) \ - (IS_BREAK_CHAR(c) || (c) == '\r' || (c) == '\n') - -static size_t next_token_quoted(const char *value, size_t len, - int *need_qp, int *quoted) -{ - size_t i; - - *need_qp = FALSE; - *quoted = TRUE; - - for (i = *quoted ? 0 : 1; i < len; i++) { - if ((unsigned char)value[i] & 0x80) - *need_qp = TRUE; - - if (value[i] == '"' || value[i] == '\r' || value[i] == '\n') { - i++; - *quoted = value[i] == '"'; - break; - } - } - - return i; -} - -static size_t next_token(const char *value, size_t len, - int *need_qp, int *quoted, int qp_on) -{ - size_t i = 0; - - if (value[0] == '"' || *quoted) - return next_token_quoted(value, len, need_qp, quoted); - - *need_qp = FALSE; - - if (qp_on) { - /* skip spaces, so we don't end up QP'ing word at a time */ - for (i = 0; i < len; i++) { - if (value[i] != ' ') - break; - } - - if (i == len) - return i; - } - - if (IS_BREAK_OR_CRLF_CHAR(value[i])) { - /* return all break-chars in one token */ - for (i++; i < len; i++) { - if (!IS_BREAK_CHAR(value[i])) - break; - } - - return i; - } - - /* then stop at break-char */ - for (; i < len; i++) { - if ((unsigned char)value[i] & 0x80) - *need_qp = TRUE; - - if (IS_BREAK_OR_CRLF_CHAR(value[i])) - break; - } - - return i; -} - -static void append_quoted_qp(TempString *str, const char *value, size_t len) -{ - size_t i; - unsigned char c; - - /* do this the easy way, it's already broken behaviour to leave the - 8bit text in mailbox, so we shouldn't need to try too hard to make - it readable. Keep 'A'..'Z', 'a'..'z' and '0'..'9', QP rest */ - - for (i = 0; i < len; i++) { - if (value[i] == ' ') - t_string_append_c(str, '_'); - else if ((value[i] >= 'A' && value[i] <= 'Z') || - (value[i] >= 'a' && value[i] <= 'z') || - (value[i] >= '0' && value[i] <= '9')) { - t_string_append_c(str, value[i]); - } else { - t_string_append_c(str, '='); - c = (unsigned char)value[i] >> 4; - t_string_append_c(str, c < 10 ? (c+'0') : (c-10+'A')); - c = (unsigned char)value[i] & 0x0f; - t_string_append_c(str, c < 10 ? (c+'0') : (c-10+'A')); - } - } -} - -static void append_quoted(TempString *str, const char *value, size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) { - if (value[i] == '\\' || value[i] == '"') - t_string_append_c(str, '\\'); - t_string_append_c(str, value[i]); - } -} - -/* does two things: 1) escape '\' and '"' characters, 2) 8bit text -> QP */ -static TempString *get_quoted_str(const char *value, size_t value_len) -{ - TempString *str; - size_t token_len; - int qp, need_qp, quoted; - - str = t_string_new(value_len * 2); - qp = FALSE; - quoted = FALSE; - - t_string_append_c(str, '"'); - while (value_len > 0) { - token_len = next_token(value, value_len, &need_qp, "ed, qp); - i_assert(token_len > 0 && token_len <= value_len); - - /* header may be split to multiple lines, we don't want them */ - while (token_len > 0 && (value[0] == '\r' || - value[0] == '\n')) { - value++; - token_len--; - value_len--; - } - - if (need_qp && !qp) { - t_string_append(str, "=?x-unknown?Q?"); - qp = TRUE; - } else if (!need_qp && qp) { - t_string_append(str, "?="); - qp = FALSE; - } - - if (need_qp) - append_quoted_qp(str, value, token_len); - else - append_quoted(str, value, token_len); - - value += token_len; - value_len -= token_len; - } - - if (qp) t_string_append(str, "?="); - t_string_append_c(str, '"'); - - return str; -} - -static const char *quote_str_nil(const char *value) -{ - return value == NULL ? "NIL" : - get_quoted_str(value, strlen(value))->str; -} - -static char *quote_value(Pool pool, const char *value, size_t value_len) -{ - TempString *str; - - str = get_quoted_str(value, value_len); - return p_strndup(pool, str->str, str->len); -} - static Rfc822Address *parse_address(Pool pool, const char *value, size_t value_len) { @@ -208,9 +37,9 @@ } if (strcasecmp(name, "Date") == 0) - (*data)->date = quote_value(pool, value, value_len); + (*data)->date = imap_quote_value(pool, value, value_len); else if (strcasecmp(name, "Subject") == 0) - (*data)->subject = quote_value(pool, value, value_len); + (*data)->subject = imap_quote_value(pool, value, value_len); else if (strcasecmp(name, "From") == 0) (*data)->from = parse_address(pool, value, value_len); else if (strcasecmp(name, "Sender") == 0) @@ -224,9 +53,9 @@ else if (strcasecmp(name, "Bcc") == 0) (*data)->bcc = parse_address(pool, value, value_len); else if (strcasecmp(name, "In-Reply-To") == 0) - (*data)->in_reply_to = quote_value(pool, value, value_len); + (*data)->in_reply_to = imap_quote_value(pool, value, value_len); else if (strcasecmp(name, "Message-Id") == 0) - (*data)->message_id = quote_value(pool, value, value_len); + (*data)->message_id = imap_quote_value(pool, value, value_len); } static void imap_write_address(TempString *str, Rfc822Address *addr) @@ -239,13 +68,13 @@ t_string_append_c(str, '('); while (addr != NULL) { t_string_append_c(str, '('); - t_string_append(str, quote_str_nil(addr->name)); + t_string_append(str, imap_quote_str_nil(addr->name)); t_string_append_c(str, ' '); - t_string_append(str, quote_str_nil(addr->route)); + t_string_append(str, imap_quote_str_nil(addr->route)); t_string_append_c(str, ' '); - t_string_append(str, quote_str_nil(addr->mailbox)); + t_string_append(str, imap_quote_str_nil(addr->mailbox)); t_string_append_c(str, ' '); - t_string_append(str, quote_str_nil(addr->domain)); + t_string_append(str, imap_quote_str_nil(addr->domain)); t_string_append_c(str, ')'); addr = addr->next; diff -r 36ab6a6c8bdf -r 6f4eeb6a0a0d src/lib-imap/imap-quote.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-imap/imap-quote.c Tue Oct 01 00:18:12 2002 +0300 @@ -0,0 +1,176 @@ +/* Copyright (C) 2002 Timo Sirainen */ + +#include "lib.h" +#include "temp-string.h" + +#define IS_BREAK_CHAR(c) \ + ((c) == ' ' || (c) == '\t' || \ + (c) == ',' || (c) == ':' || (c) == ';' || (c) == '@' || \ + (c) == '<' || (c) == '>' || (c) == '(' || (c) == ')' || \ + (c) == '[' || (c) == ']' || (c) == '=') + +#define IS_BREAK_OR_CRLF_CHAR(c) \ + (IS_BREAK_CHAR(c) || (c) == '\r' || (c) == '\n') + +static size_t next_token_quoted(const char *value, size_t len, + int *need_qp, int *quoted) +{ + size_t i; + + *need_qp = FALSE; + *quoted = TRUE; + + for (i = *quoted ? 0 : 1; i < len; i++) { + if ((unsigned char)value[i] & 0x80) + *need_qp = TRUE; + + if (value[i] == '"' || value[i] == '\r' || value[i] == '\n') { + i++; + *quoted = value[i] == '"'; + break; + } + } + + return i; +} + +static size_t next_token(const char *value, size_t len, + int *need_qp, int *quoted, int qp_on) +{ + size_t i = 0; + + if (value[0] == '"' || *quoted) + return next_token_quoted(value, len, need_qp, quoted); + + *need_qp = FALSE; + + if (qp_on) { + /* skip spaces, so we don't end up QP'ing word at a time */ + for (i = 0; i < len; i++) { + if (value[i] != ' ') + break; + } + + if (i == len) + return i; + } + + if (IS_BREAK_OR_CRLF_CHAR(value[i])) { + /* return all break-chars in one token */ + for (i++; i < len; i++) { + if (!IS_BREAK_CHAR(value[i])) + break; + } + + return i; + } + + /* then stop at break-char */ + for (; i < len; i++) { + if ((unsigned char)value[i] & 0x80) + *need_qp = TRUE; + + if (IS_BREAK_OR_CRLF_CHAR(value[i])) + break; + } + + return i; +} + +static void append_quoted_qp(TempString *str, const char *value, size_t len) +{ + size_t i; + unsigned char c; + + /* do this the easy way, it's already broken behaviour to leave the + 8bit text in mailbox, so we shouldn't need to try too hard to make + it readable. Keep 'A'..'Z', 'a'..'z' and '0'..'9', QP rest */ + + for (i = 0; i < len; i++) { + if (value[i] == ' ') + t_string_append_c(str, '_'); + else if ((value[i] >= 'A' && value[i] <= 'Z') || + (value[i] >= 'a' && value[i] <= 'z') || + (value[i] >= '0' && value[i] <= '9')) { + t_string_append_c(str, value[i]); + } else { + t_string_append_c(str, '='); + c = (unsigned char)value[i] >> 4; + t_string_append_c(str, c < 10 ? (c+'0') : (c-10+'A')); + c = (unsigned char)value[i] & 0x0f; + t_string_append_c(str, c < 10 ? (c+'0') : (c-10+'A')); + } + } +} + +static void append_quoted(TempString *str, const char *value, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (value[i] == '\\' || value[i] == '"') + t_string_append_c(str, '\\'); + t_string_append_c(str, value[i]); + } +} + +/* does two things: 1) escape '\' and '"' characters, 2) 8bit text -> QP */ +static TempString *get_quoted_str(const char *value, size_t value_len) +{ + TempString *str; + size_t token_len; + int qp, need_qp, quoted; + + str = t_string_new(value_len * 2); + qp = FALSE; + quoted = FALSE; + + t_string_append_c(str, '"'); + while (value_len > 0) { + token_len = next_token(value, value_len, &need_qp, "ed, qp); + i_assert(token_len > 0 && token_len <= value_len); + + /* header may be split to multiple lines, we don't want them */ + while (token_len > 0 && (value[0] == '\r' || + value[0] == '\n')) { + value++; + token_len--; + value_len--; + } + + if (need_qp && !qp) { + t_string_append(str, "=?x-unknown?Q?"); + qp = TRUE; + } else if (!need_qp && qp) { + t_string_append(str, "?="); + qp = FALSE; + } + + if (need_qp) + append_quoted_qp(str, value, token_len); + else + append_quoted(str, value, token_len); + + value += token_len; + value_len -= token_len; + } + + if (qp) t_string_append(str, "?="); + t_string_append_c(str, '"'); + + return str; +} + +const char *imap_quote_str_nil(const char *value) +{ + return value == NULL ? "NIL" : + get_quoted_str(value, strlen(value))->str; +} + +char *imap_quote_value(Pool pool, const char *value, size_t value_len) +{ + TempString *str; + + str = get_quoted_str(value, value_len); + return p_strndup(pool, str->str, str->len); +} diff -r 36ab6a6c8bdf -r 6f4eeb6a0a0d src/lib-imap/imap-quote.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-imap/imap-quote.h Tue Oct 01 00:18:12 2002 +0300 @@ -0,0 +1,10 @@ +#ifndef __IMAP_QUOTE_H +#define __IMAP_QUOTE_H + +/* If value is non-NULL, return it "quoted", otherwise return NIL unquoted. */ +const char *imap_quote_str_nil(const char *value); + +/* Return value quoted and allocated from specified pool. */ +char *imap_quote_value(Pool pool, const char *value, size_t value_len); + +#endif