message-part-data.c revision b674bd911aaab7e8b1a77c106a0b5bccb603439f
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2014-2017 Dovecot authors, see the included COPYING file */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "lib.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "str.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "array.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "rfc822-parser.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "rfc2231-parser.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "message-address.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "message-header-parser.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "message-part-data.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenconst char *message_part_envelope_headers[] = {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "Date", "Subject", "From", "Sender", "Reply-To",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "To", "Cc", "Bcc", "In-Reply-To", "Message-ID",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen NULL
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen};
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen/*
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen *
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenbool message_part_data_is_plain_7bit(const struct message_part *part)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const struct message_part_data *data = part->data;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_assert(part->parent == NULL);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* if content-type is text/xxx we don't have to check any
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen multipart stuff */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if ((part->flags & MESSAGE_PART_FLAG_TEXT) == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return FALSE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (part->next != NULL || part->children != NULL)
46e917c9fa05cbe7bddf805d3a9838b61e3960e1Timo Sirainen return FALSE; /* shouldn't happen normally.. */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* must be text/plain */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (data->content_subtype != NULL &&
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen strcasecmp(data->content_subtype, "plain") != 0)
46e917c9fa05cbe7bddf805d3a9838b61e3960e1Timo Sirainen return FALSE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* only allowed parameter is charset=us-ascii, which is also default */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (data->content_type_params_count > 0 &&
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen (strcasecmp(data->content_type_params[0].name, "charset") != 0 ||
b49aa341d28c0eec1229e30baa2f89d5bae52ff8Phil Carmody strcasecmp(data->content_type_params[0].value,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen MESSAGE_PART_DEFAULT_CHARSET) != 0))
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return FALSE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (data->content_id != NULL ||
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen data->content_description != NULL)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return FALSE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (data->content_transfer_encoding != NULL &&
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen strcasecmp(data->content_transfer_encoding, "7bit") != 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return FALSE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* BODYSTRUCTURE checks: */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (data->content_md5 != NULL ||
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen data->content_disposition != NULL ||
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen data->content_language != NULL ||
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen data->content_location != NULL)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return FALSE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
0ca3b9cb0f2a322a25ce7f229dc3d3a0b46be17bTimo Sirainen return TRUE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
7a88e726e7300fb0273cb4e55b43c27fbd90bdbdTimo Sirainen/*
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen * Header parsing
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen/* Message part envelope */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenenum envelope_field {
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen ENVELOPE_FIELD_DATE = 0,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen ENVELOPE_FIELD_SUBJECT,
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen ENVELOPE_FIELD_FROM,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen ENVELOPE_FIELD_SENDER,
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen ENVELOPE_FIELD_REPLY_TO,
56d1345c43bbd28c36b7faa85e4163bd9e874290Timo Sirainen ENVELOPE_FIELD_TO,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen ENVELOPE_FIELD_CC,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen ENVELOPE_FIELD_BCC,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen ENVELOPE_FIELD_IN_REPLY_TO,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen ENVELOPE_FIELD_MESSAGE_ID,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen ENVELOPE_FIELD_UNKNOWN
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen};
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic enum envelope_field
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenenvelope_get_field(const char *name)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen switch (*name) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 'B':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 'b':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strcasecmp(name, "Bcc") == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ENVELOPE_FIELD_BCC;
56aa97d74071f3a2987140c2ff1cfd5a59cb35aaTimo Sirainen break;
56aa97d74071f3a2987140c2ff1cfd5a59cb35aaTimo Sirainen case 'C':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 'c':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strcasecmp(name, "Cc") == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ENVELOPE_FIELD_CC;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 'D':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 'd':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strcasecmp(name, "Date") == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ENVELOPE_FIELD_DATE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 'F':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 'f':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strcasecmp(name, "From") == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ENVELOPE_FIELD_FROM;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 'I':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 'i':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strcasecmp(name, "In-reply-to") == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ENVELOPE_FIELD_IN_REPLY_TO;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 'M':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 'm':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strcasecmp(name, "Message-id") == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ENVELOPE_FIELD_MESSAGE_ID;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 'R':
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen case 'r':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strcasecmp(name, "Reply-to") == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ENVELOPE_FIELD_REPLY_TO;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 'S':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 's':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strcasecmp(name, "Subject") == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ENVELOPE_FIELD_SUBJECT;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strcasecmp(name, "Sender") == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ENVELOPE_FIELD_SENDER;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 'T':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 't':
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strcasecmp(name, "To") == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ENVELOPE_FIELD_TO;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ENVELOPE_FIELD_UNKNOWN;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenvoid message_part_envelope_parse_from_header(pool_t pool,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct message_part_envelope **data,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct message_header_line *hdr)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct message_part_envelope *d;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen enum envelope_field field;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct message_address **addr_p;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char **str_p;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (*data == NULL) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen *data = p_new(pool, struct message_part_envelope, 1);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (hdr == NULL)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen field = envelope_get_field(hdr->name);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (field == ENVELOPE_FIELD_UNKNOWN)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (hdr->continues) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* wait for full value */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen hdr->use_full_value = TRUE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
9a1f68e5ab08eabd352d533315cba1c69006e2c1Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen d = *data;
bdb026e2dc8a7c77585ed5ba489f0056df8074d4Timo Sirainen addr_p = NULL; str_p = NULL;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen switch (field) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case ENVELOPE_FIELD_DATE:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_p = &d->date;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case ENVELOPE_FIELD_SUBJECT:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_p = &d->subject;
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case ENVELOPE_FIELD_MESSAGE_ID:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_p = &d->message_id;
60d1fdf2c17fd0c7020234590dbd73da81c3ce8fTimo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case ENVELOPE_FIELD_IN_REPLY_TO:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_p = &d->in_reply_to;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case ENVELOPE_FIELD_CC:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen addr_p = &d->cc;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case ENVELOPE_FIELD_BCC:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen addr_p = &d->bcc;
5cdb246858f37469fe61351dbc147dabbdde342cTimo Sirainen break;
5cdb246858f37469fe61351dbc147dabbdde342cTimo Sirainen case ENVELOPE_FIELD_FROM:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen addr_p = &d->from;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case ENVELOPE_FIELD_SENDER:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen addr_p = &d->sender;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case ENVELOPE_FIELD_TO:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen addr_p = &d->to;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case ENVELOPE_FIELD_REPLY_TO:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen addr_p = &d->reply_to;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case ENVELOPE_FIELD_UNKNOWN:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_unreached();
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (addr_p != NULL) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen *addr_p = message_address_parse(pool, hdr->full_value,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen hdr->full_value_len,
5d4a0dac041964a04405bc6b94de51315ca917afTimo Sirainen UINT_MAX, TRUE);
5d4a0dac041964a04405bc6b94de51315ca917afTimo Sirainen } else if (str_p != NULL) {
5d4a0dac041964a04405bc6b94de51315ca917afTimo Sirainen *str_p = p_strndup(pool,
5d4a0dac041964a04405bc6b94de51315ca917afTimo Sirainen hdr->full_value, hdr->full_value_len);
5d4a0dac041964a04405bc6b94de51315ca917afTimo Sirainen }
5d4a0dac041964a04405bc6b94de51315ca917afTimo Sirainen}
5d4a0dac041964a04405bc6b94de51315ca917afTimo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen/* Message part data */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainenstatic void
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainenparse_mime_parameters(struct rfc822_parser_context *parser,
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen pool_t pool, const struct message_part_param **params_r,
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen unsigned int *params_count_r)
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen{
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen const char *const *results;
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen struct message_part_param *params;
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen unsigned int params_count, i;
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen rfc2231_parse(parser, &results);
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen params_count = str_array_length(results);
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen i_assert((params_count % 2) == 0);
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen params_count /= 2;
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen if (params_count > 0) {
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen params = p_new(pool, struct message_part_param, params_count);
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen for (i = 0; i < params_count; i++) {
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen params[i].name = p_strdup(pool, results[i*2+0]);
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen params[i].value = p_strdup(pool, results[i*2+1]);
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen }
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen *params_r = params;
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen }
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen *params_count_r = params_count;
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen}
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainenstatic void
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainenparse_content_type(struct message_part_data *data,
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen pool_t pool, struct message_header_line *hdr)
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen{
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen struct rfc822_parser_context parser;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen string_t *str;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *value;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen unsigned int i;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen int ret;
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen rfc822_skip_lwsp(&parser);
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen str = t_str_new(256);
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen ret = rfc822_parse_content_type(&parser, str);
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen /* Save content type and subtype */
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen value = str_c(str);
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen for (i = 0; value[i] != '\0'; i++) {
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen if (value[i] == '/') {
1ee74d70bb758637e560d556c7240563967d22c8Timo Sirainen data->content_subtype = p_strdup(pool, value + i+1);
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen break;
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen }
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen }
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen str_truncate(str, i);
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen data->content_type = p_strdup(pool, str_c(str));
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen if (ret < 0) {
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen /* Content-Type is broken, but we wanted to get it as well as
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen we could. Don't try to read the parameters anymore though.
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen We don't completely ignore a broken Content-Type, because
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen then it would be written as text/plain. This would cause a
1ee74d70bb758637e560d556c7240563967d22c8Timo Sirainen mismatch with the message_part's MESSAGE_PART_FLAG_TEXT. */
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen return;
1ee74d70bb758637e560d556c7240563967d22c8Timo Sirainen }
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen parse_mime_parameters(&parser, pool,
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen &data->content_type_params,
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen &data->content_type_params_count);
1ee74d70bb758637e560d556c7240563967d22c8Timo Sirainen}
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen
1ee74d70bb758637e560d556c7240563967d22c8Timo Sirainenstatic void
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainenparse_content_transfer_encoding(struct message_part_data *data,
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen pool_t pool, struct message_header_line *hdr)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct rfc822_parser_context parser;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen string_t *str;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen rfc822_skip_lwsp(&parser);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str = t_str_new(256);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (rfc822_parse_mime_token(&parser, str) >= 0 &&
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen rfc822_skip_lwsp(&parser) == 0 && str_len(str) > 0) {
e130bb802c8bfb6c6cc44e5c8bc098b4fa5af789Timo Sirainen data->content_transfer_encoding =
e130bb802c8bfb6c6cc44e5c8bc098b4fa5af789Timo Sirainen p_strdup(pool, str_c(str));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenparse_content_disposition(struct message_part_data *data,
c6afd726060aae56b6622c6c52aec10231c4bf1cTimo Sirainen pool_t pool, struct message_header_line *hdr)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct rfc822_parser_context parser;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen string_t *str;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
857c471c13ca215f4be9dd4b336b742b8d434e31Timo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
857c471c13ca215f4be9dd4b336b742b8d434e31Timo Sirainen rfc822_skip_lwsp(&parser);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str = t_str_new(256);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (rfc822_parse_mime_token(&parser, str) < 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen data->content_disposition = p_strdup(pool, str_c(str));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen parse_mime_parameters(&parser, pool,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen &data->content_disposition_params,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen &data->content_disposition_params_count);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenparse_content_language(struct message_part_data *data,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen pool_t pool, const unsigned char *value, size_t value_len)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen struct rfc822_parser_context parser;
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen ARRAY_TYPE(const_string) langs;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen string_t *str;
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen /* Language-Header = "Content-Language" ":" 1#Language-tag
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen Language-Tag = Primary-tag *( "-" Subtag )
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen Primary-tag = 1*8ALPHA
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen Subtag = 1*8ALPHA */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen rfc822_parser_init(&parser, value, value_len, NULL);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen t_array_init(&langs, 16);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str = t_str_new(128);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen rfc822_skip_lwsp(&parser);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen while (rfc822_parse_atom(&parser, str) >= 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *lang = p_strdup(pool, str_c(str));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen array_append(&langs, &lang, 1);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen str_truncate(str, 0);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (parser.data == parser.end || *parser.data != ',')
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen parser.data++;
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen rfc822_skip_lwsp(&parser);
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen }
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen if (array_count(&langs) > 0) {
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen array_append_zero(&langs);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen data->content_language =
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen p_strarray_dup(pool, array_idx(&langs, 0));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenparse_content_header(struct message_part_data *data,
pool_t pool, struct message_header_line *hdr)
{
const char *name = hdr->name + strlen("Content-");
const char *value;
if (hdr->continues) {
hdr->use_full_value = TRUE;
return;
}
value = t_strndup(hdr->full_value, hdr->full_value_len);
switch (*name) {
case 'i':
case 'I':
if (strcasecmp(name, "ID") == 0 && data->content_id == NULL)
data->content_id = p_strdup(pool, value);
break;
case 'm':
case 'M':
if (strcasecmp(name, "MD5") == 0 && data->content_md5 == NULL)
data->content_md5 = p_strdup(pool, value);
break;
case 't':
case 'T':
if (strcasecmp(name, "Type") == 0 && data->content_type == NULL)
parse_content_type(data, pool, hdr);
else if (strcasecmp(name, "Transfer-Encoding") == 0 &&
data->content_transfer_encoding == NULL)
parse_content_transfer_encoding(data, pool, hdr);
break;
case 'l':
case 'L':
if (strcasecmp(name, "Language") == 0 &&
data->content_language == NULL) {
parse_content_language(data, pool,
hdr->full_value, hdr->full_value_len);
} else if (strcasecmp(name, "Location") == 0 &&
data->content_location == NULL) {
data->content_location = p_strdup(pool, value);
}
break;
case 'd':
case 'D':
if (strcasecmp(name, "Description") == 0 &&
data->content_description == NULL)
data->content_description = p_strdup(pool, value);
else if (strcasecmp(name, "Disposition") == 0 &&
data->content_disposition_params == NULL)
parse_content_disposition(data, pool, hdr);
break;
}
}
void message_part_data_parse_from_header(pool_t pool,
struct message_part *part,
struct message_header_line *hdr)
{
struct message_part_data *part_data;
struct message_part_envelope *envelope;
bool parent_rfc822;
if (hdr == NULL) {
if (part->data == NULL) {
/* no Content-* headers. add an empty context
structure anyway. */
part->data = part_data =
p_new(pool, struct message_part_data, 1);
} else if ((part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
/* If there was no Mime-Version, forget all
the Content-stuff */
part_data = part->data;
envelope = part_data->envelope;
i_zero(part_data);
part_data->envelope = envelope;
}
return;
}
if (hdr->eoh)
return;
parent_rfc822 = part->parent != NULL &&
(part->parent->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) != 0;
if (!parent_rfc822 && strncasecmp(hdr->name, "Content-", 8) != 0)
return;
if (part->data == NULL) {
/* initialize message part data */
part->data = part_data =
p_new(pool, struct message_part_data, 1);
}
part_data = part->data;
if (strncasecmp(hdr->name, "Content-", 8) == 0) {
T_BEGIN {
parse_content_header(part_data, pool, hdr);
} T_END;
}
if (parent_rfc822) {
/* message/rfc822, we need the envelope */
message_part_envelope_parse_from_header(pool, &part_data->envelope, hdr);
}
}