dovecot-1.2: Merge RFC 2231 header continuations in BODY/BODYSTR...
dovecot at dovecot.org
dovecot at dovecot.org
Tue Jun 24 16:49:42 EEST 2008
details: http://hg.dovecot.org/dovecot-1.2/rev/3412c43d6707
changeset: 7950:3412c43d6707
user: Timo Sirainen <tss at iki.fi>
date: Tue Jun 24 16:49:36 2008 +0300
description:
Merge RFC 2231 header continuations in BODY/BODYSTRUCTURE replies. Also use
them internally while parsing messages.
diffstat:
7 files changed, 245 insertions(+), 21 deletions(-)
src/lib-imap/imap-bodystructure.c | 27 +++---
src/lib-mail/Makefile.am | 2
src/lib-mail/message-decoder.c | 12 +-
src/lib-mail/message-parser.c | 11 +-
src/lib-mail/rfc2231-parser.c | 161 +++++++++++++++++++++++++++++++++++++
src/lib-mail/rfc2231-parser.h | 11 ++
src/tests/test-mail.c | 42 +++++++++
diffs (truncated from 404 to 300 lines):
diff -r e787f6cae97c -r 3412c43d6707 src/lib-imap/imap-bodystructure.c
--- a/src/lib-imap/imap-bodystructure.c Tue Jun 24 13:37:55 2008 +0300
+++ b/src/lib-imap/imap-bodystructure.c Tue Jun 24 16:49:36 2008 +0300
@@ -6,6 +6,7 @@
#include "str.h"
#include "message-parser.h"
#include "rfc822-parser.h"
+#include "rfc2231-parser.h"
#include "imap-parser.h"
#include "imap-quote.h"
#include "imap-envelope.h"
@@ -37,7 +38,7 @@ static void parse_content_type(struct me
struct message_header_line *hdr)
{
struct rfc822_parser_context parser;
- const char *key, *value;
+ const char *value, *const *results;
string_t *str;
unsigned int i;
bool charset_found = FALSE;
@@ -64,14 +65,15 @@ static void parse_content_type(struct me
/* parse parameters and save them */
str_truncate(str, 0);
- while (rfc822_parse_content_param(&parser, &key, &value) > 0) {
- if (strcasecmp(key, "charset") == 0)
+ (void)rfc2231_parse(&parser, &results);
+ for (; *results != NULL; results += 2) {
+ if (strcasecmp(results[0], "charset") == 0)
charset_found = TRUE;
str_append_c(str, ' ');
- imap_quote_append_string(str, key, TRUE);
- str_append_c(str, ' ');
- imap_quote_append_string(str, value, TRUE);
+ imap_quote_append_string(str, results[0], TRUE);
+ str_append_c(str, ' ');
+ imap_quote_append_string(str, results[1], TRUE);
}
if (!charset_found &&
@@ -106,7 +108,7 @@ static void parse_content_disposition(st
struct message_header_line *hdr)
{
struct rfc822_parser_context parser;
- const char *key, *value;
+ const char *const *results;
string_t *str;
rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
@@ -120,11 +122,12 @@ static void parse_content_disposition(st
/* parse parameters and save them */
str_truncate(str, 0);
- while (rfc822_parse_content_param(&parser, &key, &value) > 0) {
- str_append_c(str, ' ');
- imap_quote_append_string(str, key, TRUE);
- str_append_c(str, ' ');
- imap_quote_append_string(str, value, TRUE);
+ (void)rfc2231_parse(&parser, &results);
+ for (; *results != NULL; results += 2) {
+ str_append_c(str, ' ');
+ imap_quote_append_string(str, results[0], TRUE);
+ str_append_c(str, ' ');
+ imap_quote_append_string(str, results[1], TRUE);
}
if (str_len(str) > 0) {
data->content_disposition_params =
diff -r e787f6cae97c -r 3412c43d6707 src/lib-mail/Makefile.am
--- a/src/lib-mail/Makefile.am Tue Jun 24 13:37:55 2008 +0300
+++ b/src/lib-mail/Makefile.am Tue Jun 24 16:49:36 2008 +0300
@@ -19,6 +19,7 @@ libmail_a_SOURCES = \
message-send.c \
message-size.c \
quoted-printable.c \
+ rfc2231-parser.c \
rfc822-parser.c
headers = \
@@ -37,6 +38,7 @@ headers = \
message-send.h \
message-size.h \
quoted-printable.h \
+ rfc2231-parser.h \
rfc822-parser.h
if INSTALL_HEADERS
diff -r e787f6cae97c -r 3412c43d6707 src/lib-mail/message-decoder.c
--- a/src/lib-mail/message-decoder.c Tue Jun 24 13:37:55 2008 +0300
+++ b/src/lib-mail/message-decoder.c Tue Jun 24 16:49:36 2008 +0300
@@ -8,6 +8,7 @@
#include "charset-utf8.h"
#include "quoted-printable.h"
#include "rfc822-parser.h"
+#include "rfc2231-parser.h"
#include "message-parser.h"
#include "message-header-decode.h"
#include "message-decoder.h"
@@ -112,7 +113,7 @@ parse_content_type(struct message_decode
struct message_header_line *hdr)
{
struct rfc822_parser_context parser;
- const char *key, *value;
+ const char *const *results;
string_t *str;
if (ctx->content_charset != NULL)
@@ -124,10 +125,11 @@ parse_content_type(struct message_decode
if (rfc822_parse_content_type(&parser, str) <= 0)
return;
- while (rfc822_parse_content_param(&parser, &key, &value) > 0) {
- if (strcasecmp(key, "charset") == 0) {
- ctx->content_charset = i_strdup(value);
- ctx->charset_utf8 = charset_is_utf8(value);
+ (void)rfc2231_parse(&parser, &results);
+ for (; *results != NULL; results += 2) {
+ if (strcasecmp(results[0], "charset") == 0) {
+ ctx->content_charset = i_strdup(results[1]);
+ ctx->charset_utf8 = charset_is_utf8(results[1]);
break;
}
}
diff -r e787f6cae97c -r 3412c43d6707 src/lib-mail/message-parser.c
--- a/src/lib-mail/message-parser.c Tue Jun 24 13:37:55 2008 +0300
+++ b/src/lib-mail/message-parser.c Tue Jun 24 16:49:36 2008 +0300
@@ -4,6 +4,7 @@
#include "str.h"
#include "istream.h"
#include "rfc822-parser.h"
+#include "rfc2231-parser.h"
#include "message-parser.h"
/* RFC-2046 requires boundaries are max. 70 chars + "--" prefix + "--" suffix.
@@ -410,7 +411,7 @@ static void parse_content_type(struct me
struct message_header_line *hdr)
{
struct rfc822_parser_context parser;
- const char *key, *value;
+ const char *const *results;
string_t *content_type;
if (ctx->part_seen_content_type)
@@ -441,9 +442,11 @@ static void parse_content_type(struct me
ctx->last_boundary != NULL)
return;
- while (rfc822_parse_content_param(&parser, &key, &value) > 0) {
- if (strcasecmp(key, "boundary") == 0) {
- ctx->last_boundary = p_strdup(ctx->parser_pool, value);
+ (void)rfc2231_parse(&parser, &results);
+ for (; *results != NULL; results += 2) {
+ if (strcasecmp(results[0], "boundary") == 0) {
+ ctx->last_boundary =
+ p_strdup(ctx->parser_pool, results[1]);
break;
}
}
diff -r e787f6cae97c -r 3412c43d6707 src/lib-mail/rfc2231-parser.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-mail/rfc2231-parser.c Tue Jun 24 16:49:36 2008 +0300
@@ -0,0 +1,161 @@
+/* Copyright (c) 2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "rfc822-parser.h"
+#include "rfc2231-parser.h"
+
+#include <stdlib.h>
+
+struct rfc2231_parameter {
+ const char *key, *value;
+ unsigned int idx;
+ bool extended;
+};
+
+static int rfc2231_parameter_cmp(const void *p1, const void *p2)
+{
+ const struct rfc2231_parameter *r1 = p1, *r2 = p2;
+ int ret;
+
+ ret = strcmp(r1->key, r2->key);
+ if (ret != 0)
+ return ret;
+
+ return r1->idx < r2->idx ? -1 :
+ (r1-> idx > r2->idx ? 1 : 0);
+}
+
+static void rfc2231_escape(string_t *dest, const char *src)
+{
+ for (; *src != '\0'; src++) {
+ if (*src == '%')
+ str_append(dest, "%25");
+ else
+ str_append_c(dest, *src);
+ }
+}
+
+int rfc2231_parse(struct rfc822_parser_context *ctx,
+ const char *const **result_r)
+{
+ ARRAY_TYPE(const_string) result;
+ ARRAY_DEFINE(rfc2231_params_arr, struct rfc2231_parameter);
+ struct rfc2231_parameter rfc2231_param, *rfc2231_params;
+ const char *key, *value, *p, *p2;
+ string_t *str;
+ unsigned int i, j, count, next, next_idx;
+ bool ok, have_extended;
+ int ret;
+
+ /* Get a list of all parameters. RFC 2231 uses key*<n>[*]=value pairs,
+ which we want to merge to a key[*]=value pair. Save them to a
+ separate array. */
+ memset(&rfc2231_param, 0, sizeof(rfc2231_param));
+ t_array_init(&result, 8);
+ t_array_init(&rfc2231_params_arr, 8);
+ while ((ret = rfc822_parse_content_param(ctx, &key, &value)) > 0) {
+ p = strchr(key, '*');
+ if (p != NULL) {
+ p2 = p++;
+ rfc2231_param.idx = 0;
+ for (; *p >= '0' && *p <= '9'; p++) {
+ rfc2231_param.idx =
+ rfc2231_param.idx*10 + *p - '0';
+ }
+ if (*p != '*')
+ rfc2231_param.extended = FALSE;
+ else {
+ rfc2231_param.extended = TRUE;
+ p++;
+ }
+ if (*p != '\0')
+ p = NULL;
+ else {
+ rfc2231_param.key = t_strdup_until(key, p2);
+ rfc2231_param.value = value;
+ array_append(&rfc2231_params_arr,
+ &rfc2231_param, 1);
+ }
+ }
+ if (p == NULL) {
+ array_append(&result, &key, 1);
+ array_append(&result, &value, 1);
+ }
+ }
+
+ if (array_count(&rfc2231_params_arr) == 0) {
+ /* No RFC 2231 parameters */
+ (void)array_append_space(&result); /* NULL-terminate */
+ *result_r = array_idx(&result, 0);
+ return ret;
+ }
+
+ /* Merge the RFC 2231 parameters. Since their order isn't guaranteed to
+ be ascending, start by sorting them. */
+ rfc2231_params = array_get_modifiable(&rfc2231_params_arr, &count);
+ qsort(rfc2231_params, count, sizeof(*rfc2231_params),
+ rfc2231_parameter_cmp);
+
+ /* keys are now sorted primarily by their name and secondarily by
+ their index. If any indexes are missing, fallback to assuming
+ these aren't RFC 2231 encoded parameters. */
+ str = t_str_new(64);
+ for (i = 0; i < count; i = next) {
+ ok = TRUE;
+ have_extended = FALSE;
+ next_idx = 0;
+ for (j = i; j < count; j++) {
+ if (strcasecmp(rfc2231_params[i].key,
+ rfc2231_params[j].key) != 0)
+ break;
+ if (rfc2231_params[j].idx != next_idx) {
+ /* missing indexes */
+ ok = FALSE;
+ }
+ if (rfc2231_params[j].extended)
+ have_extended = TRUE;
+ next_idx++;
+ }
+ next = j;
+
+ if (!ok) {
+ /* missing indexes */
+ for (j = i; j < next; j++) {
+ key = t_strdup_printf(
+ rfc2231_params[j].extended ?
+ "%s*%u*" : "%s*%u",
+ rfc2231_params[j].key,
+ rfc2231_params[j].idx);
+ array_append(&result, &key, 1);
+ array_append(&result,
+ &rfc2231_params[j].value, 1);
+ }
+ } else {
+ /* everything was successful */
+ str_truncate(str, 0);
+ if (!rfc2231_params[i].extended && have_extended)
More information about the dovecot-cvs
mailing list