Mercurial > dovecot > core-2.2
view src/lib-mail/rfc2231-parser.c @ 12782:447bce266022
Updated copyright notices to include year 2011.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 04 Mar 2011 20:54:29 +0200 |
parents | 615eef3139c2 |
children | ba770cba5598 |
line wrap: on
line source
/* Copyright (c) 2008-2011 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 struct rfc2231_parameter *r1, const struct rfc2231_parameter *r2) { 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; const struct rfc2231_parameter *rfc2231_params; const char *key, *value, *p, *p2; string_t *str; unsigned int i, j, count, next, next_idx; bool ok, have_extended, broken = FALSE; 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) { if (ret < 0) { /* try to continue anyway.. */ broken = TRUE; if (ctx->data == ctx->end) break; ctx->data++; continue; } p = strchr(key, '*'); if (p != NULL) { p2 = p; if (p[1] != '\0') { 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 broken ? -1 : 0; } /* Merge the RFC 2231 parameters. Since their order isn't guaranteed to be ascending, start by sorting them. */ array_sort(&rfc2231_params_arr, rfc2231_parameter_cmp); rfc2231_params = array_get(&rfc2231_params_arr, &count); /* 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) str_append(str, "''"); for (j = i; j < next; j++) { if (!rfc2231_params[j].extended && have_extended) { rfc2231_escape(str, rfc2231_params[j].value); } else { str_append(str, rfc2231_params[j].value); } } key = rfc2231_params[i].key; if (have_extended) key = t_strconcat(key, "*", NULL); value = t_strdup(str_c(str)); array_append(&result, &key, 1); array_append(&result, &value, 1); } } (void)array_append_space(&result); /* NULL-terminate */ *result_r = array_idx(&result, 0); return broken ? -1 : 0; }