Mercurial > dovecot > core-2.2
diff src/imap/imap-fetch-body.c @ 2675:60d33cf81c8e HEAD
BODY.PEEK[HEADER.FIELDS (...)] list is allowed to contain strings and
literals. We didn't handle them correctly before.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 28 Sep 2004 13:55:36 +0300 |
parents | 2b5d4de3d827 |
children | c6f128e5520b |
line wrap: on
line diff
--- a/src/imap/imap-fetch-body.c Mon Sep 27 18:58:56 2004 +0300 +++ b/src/imap/imap-fetch-body.c Tue Sep 28 13:55:36 2004 +0300 @@ -3,12 +3,14 @@ #include "common.h" #include "buffer.h" #include "str.h" +#include "strescape.h" #include "istream.h" #include "ostream.h" #include "istream-header-filter.h" #include "message-parser.h" #include "message-send.h" #include "mail-storage.h" +#include "imap-parser.h" #include "imap-fetch.h" #include <stdlib.h> @@ -22,6 +24,10 @@ const char *section; /* NOTE: always uppercased */ uoff_t skip, max_size; /* if you don't want max_size, set it to (uoff_t)-1 */ + + const char *const *fields; + size_t fields_count; + unsigned int skip_set:1; unsigned int peek:1; }; @@ -37,24 +43,6 @@ static struct partial_cache partial = { 0, 0, 0, 0, { 0, 0, 0 } }; -static const char *const * -imap_fetch_get_body_fields(const char *fields, size_t *count_r) -{ - const char **arr, **p; - size_t count; - - i_assert(*fields == '('); - - arr = t_strsplit_spaces(t_strcut(fields+1, ')'), " "); - for (count = 0, p = arr; *p != NULL; p++) - count++; - - qsort(arr, count, sizeof(*arr), strcasecmp_p); - - *count_r = count; - return arr; -} - static int seek_partial(unsigned int select_counter, unsigned int uid, struct partial_cache *partial, struct istream *stream, uoff_t virtual_skip) @@ -376,27 +364,23 @@ const struct imap_fetch_body_data *body, const char *header_section) { - const char *const *fields; struct message_size msg_size; struct istream *input; - size_t fields_count; /* MIME, HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */ ctx->cur_have_eoh = FALSE; if (strncmp(header_section, "HEADER.FIELDS ", 14) == 0) { - fields = imap_fetch_get_body_fields(header_section + 14, - &fields_count); input = i_stream_create_header_filter(ctx->cur_input, HEADER_FILTER_INCLUDE, - fields, fields_count, + body->fields, + body->fields_count, header_filter_eoh, ctx); } else if (strncmp(header_section, "HEADER.FIELDS.NOT ", 18) == 0) { - fields = imap_fetch_get_body_fields(header_section + 18, - &fields_count); input = i_stream_create_header_filter(ctx->cur_input, HEADER_FILTER_EXCLUDE, - fields, fields_count, + body->fields, + body->fields_count, header_filter_eoh, ctx); } else if (strcmp(header_section, "MIME") == 0) { /* Mime-Version + Content-* fields */ @@ -589,8 +573,7 @@ struct imap_fetch_body_data *body, const char *section) { - const char *const *headers, *const *arr; - size_t count; + const char *const *arr; if (!fetch_body_header_fields_check(section)) return FALSE; @@ -604,14 +587,13 @@ } t_push(); - headers = imap_fetch_get_body_fields(section, &count); - for (arr = headers; *arr != NULL; arr++) { + for (arr = body->fields; *arr != NULL; arr++) { char *hdr = p_strdup(ctx->client->cmd_pool, *arr); buffer_append(ctx->all_headers_buf, &hdr, sizeof(hdr)); } - body->header_ctx = mailbox_header_lookup_init(ctx->box, headers); + body->header_ctx = mailbox_header_lookup_init(ctx->box, body->fields); imap_fetch_add_handler(ctx, fetch_body_header_fields, body); t_pop(); return TRUE; @@ -698,11 +680,58 @@ return TRUE; } -int fetch_body_section_init(struct imap_fetch_context *ctx, const char *arg) +static int body_section_build(struct imap_fetch_context *ctx, + struct imap_fetch_body_data *body, + const char *prefix, + const struct imap_arg_list *list) +{ + string_t *str; + const char **arr; + size_t i; + + str = str_new(ctx->client->cmd_pool, 128); + str_append(str, prefix); + str_append(str, " ("); + + /* @UNSAFE: NULL-terminated list of headers */ + arr = p_new(ctx->client->cmd_pool, const char *, list->size + 1); + + for (i = 0; i < list->size; i++) { + if (list->args[i].type != IMAP_ARG_ATOM && + list->args[i].type != IMAP_ARG_STRING) { + client_send_command_error(ctx->client, + "Invalid BODY[..] parameter: " + "Header list contains non-strings"); + return FALSE; + } + + if (i != 0) + str_append_c(str, ' '); + arr[i] = str_ucase(IMAP_ARG_STR(&list->args[i])); + + if (list->args[i].type == IMAP_ARG_ATOM) + str_append(str, arr[i]); + else { + str_append_c(str, '"'); + str_append(str, str_escape(arr[i])); + str_append_c(str, '"'); + } + } + str_append_c(str, ')'); + + qsort(arr, list->size, sizeof(*arr), strcasecmp_p); + body->fields = arr; + body->fields_count = list->size; + body->section = str_c(str); + return TRUE; +} + +int fetch_body_section_init(struct imap_fetch_context *ctx, const char *name, + struct imap_arg **args) { struct imap_fetch_body_data *body; const char *partial; - const char *p = arg + 4; + const char *p = name + 4; body = p_new(ctx->client->cmd_pool, struct imap_fetch_body_data, 1); body->max_size = (uoff_t)-1; @@ -720,14 +749,31 @@ return FALSE; } - body->section = p+1; - p = strchr(body->section, ']'); - if (p == NULL) { - client_send_command_error(ctx->client, - "Invalid BODY[..] parameter: Missing ']'"); - return FALSE; + if ((*args)[0].type == IMAP_ARG_LIST) { + /* BODY[HEADER.FIELDS.. (headers list)] */ + if ((*args)[1].type != IMAP_ARG_ATOM || + IMAP_ARG_STR(&(*args)[1])[0] != ']') { + client_send_command_error(ctx->client, + "Invalid BODY[..] parameter: Missing ']'"); + return FALSE; + } + if (!body_section_build(ctx, body, p+1, + IMAP_ARG_LIST(&(*args)[0]))) + return FALSE; + p = IMAP_ARG_STR(&(*args)[1]); + *args += 2; + } else { + /* no headers list */ + body->section = p+1; + p = strchr(body->section, ']'); + if (p == NULL) { + client_send_command_error(ctx->client, + "Invalid BODY[..] parameter: Missing ']'"); + return FALSE; + } + body->section = p_strdup_until(ctx->client->cmd_pool, + body->section, p); } - body->section = p_strdup_until(ctx->client->cmd_pool, body->section, p); if (*++p == '<') { /* <start.end> */ @@ -860,9 +906,10 @@ return fetch_stream(ctx, &body_size); } -int fetch_rfc822_init(struct imap_fetch_context *ctx, const char *arg) +int fetch_rfc822_init(struct imap_fetch_context *ctx, const char *name, + struct imap_arg **args __attr_unused__) { - if (arg[6] == '\0') { + if (name[6] == '\0') { ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY; ctx->flags_update_seen = TRUE; @@ -870,17 +917,17 @@ return TRUE; } - if (strcmp(arg+6, ".SIZE") == 0) { + if (strcmp(name+6, ".SIZE") == 0) { ctx->fetch_data |= MAIL_FETCH_VIRTUAL_SIZE; imap_fetch_add_handler(ctx, fetch_rfc822_size, NULL); return TRUE; } - if (strcmp(arg+6, ".HEADER") == 0) { + if (strcmp(name+6, ".HEADER") == 0) { ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER; imap_fetch_add_handler(ctx, fetch_rfc822_header, NULL); return TRUE; } - if (strcmp(arg+6, ".TEXT") == 0) { + if (strcmp(name+6, ".TEXT") == 0) { ctx->fetch_data |= MAIL_FETCH_STREAM_BODY; ctx->flags_update_seen = TRUE; imap_fetch_add_handler(ctx, fetch_rfc822_text, NULL); @@ -888,6 +935,6 @@ } client_send_command_error(ctx->client, t_strconcat( - "Unknown parameter ", arg, NULL)); + "Unknown parameter ", name, NULL)); return FALSE; }