imap-bodystructure.c revision 2454dfa32c93c20a8522c6ed42fe057baaac9f9a
/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "istream.h"
#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"
#include "imap-bodystructure.h"
#define DEFAULT_CHARSET \
"\"charset\" \"us-ascii\""
#define EMPTY_BODYSTRUCTURE \
{
}
struct message_header_line *hdr)
{
struct rfc822_parser_context parser;
unsigned int i;
bool charset_found = FALSE;
int ret;
/* Save content type and subtype */
for (i = 0; value[i] != '\0'; i++) {
if (value[i] == '/') {
break;
}
}
str_truncate(str, i);
if (ret < 0) {
/* Content-Type is broken, but we wanted to get it as well as
we could. Don't try to read the parameters anymore though.
We don't completely ignore a broken Content-Type, because
mismatch with the message_part's MESSAGE_PART_FLAG_TEXT. */
return;
}
/* parse parameters and save them */
str_truncate(str, 0);
}
if (!charset_found &&
/* set a default charset */
}
}
}
struct message_header_line *hdr)
{
struct rfc822_parser_context parser;
}
}
struct message_header_line *hdr)
{
struct rfc822_parser_context parser;
const char *const *results;
return;
/* parse parameters and save them */
str_truncate(str, 0);
}
}
}
struct message_part_body_data *data)
{
struct rfc822_parser_context parser;
/* Language-Header = "Content-Language" ":" 1#Language-tag
Language-Tag = Primary-tag *( "-" Subtag )
Primary-tag = 1*8ALPHA
Subtag = 1*8ALPHA */
break;
}
}
}
static void parse_content_header(struct message_part_body_data *d,
struct message_header_line *hdr,
{
const char *value;
return;
}
switch (*name) {
case 'i':
case 'I':
break;
case 'm':
case 'M':
break;
case 't':
case 'T':
parse_content_type(d, hdr);
d->content_transfer_encoding == NULL)
break;
case 'l':
case 'L':
d->content_language == NULL) {
hdr->full_value_len, d);
d->content_location == NULL) {
}
break;
case 'd':
case 'D':
d->content_description == NULL)
d->content_disposition_params == NULL)
break;
}
}
struct message_header_line *hdr)
{
struct message_part_body_data *part_data;
struct message_part_envelope_data *envelope;
bool parent_rfc822;
/* no Content-* headers. add an empty context
structure anyway. */
/* If there was no Mime-Version, forget all
the Content-stuff */
}
return;
}
return;
return;
/* initialize message part data */
}
T_BEGIN {
} T_END;
}
if (parent_rfc822) {
}
}
static void
{
}
}
static void
{
else {
else {
}
}
else {
}
}
{
else {
/* no parts in multipart message,
that's not allowed. write a single
}
else
if (!extended)
return;
/* BODYSTRUCTURE data */
else {
}
}
{
bool text;
} else {
/* "content type" "subtype" */
else {
if (text)
else
}
}
/* ("content type param key" "value" ...) */
if (!text)
else
} else {
}
if (text) {
/* text/.. contains line count */
struct message_part_body_data *child_data;
else
}
if (!extended)
return;
/* BODYSTRUCTURE data */
/* "md5" ("content disposition" ("disposition" "params"))
("body" "language" "params") "location" */
}
{
multipart stuff */
return FALSE;
return FALSE; /* shouldn't happen normally.. */
return FALSE;
/* only allowed parameter is charset=us-ascii, which is also default */
return FALSE;
return FALSE;
return FALSE;
/* BODYSTRUCTURE checks: */
return FALSE;
return TRUE;
}
{
else
}
{
const char *cstr;
return FALSE;
case IMAP_ARG_NIL:
break;
case IMAP_ARG_ATOM:
break;
case IMAP_ARG_STRING:
/* NOTE: we're parsing with no-unescape flag,
so don't double-escape it here */
break;
case IMAP_ARG_LITERAL: {
break;
}
default:
i_unreached();
return FALSE;
}
return TRUE;
}
static bool
const char **value_r)
{
return TRUE;
}
str_truncate(tmpstr, 0);
return FALSE;
return TRUE;
}
static void
bool toplevel)
{
/* don't do any typechecking, just write it out */
while (!IMAP_ARG_IS_EOL(args)) {
/* everything is either nstring or list */
i_unreached();
}
}
args++;
}
}
static void
{
}
{
str_truncate(str, 0);
while (!IMAP_ARG_IS_EOL(args)) {
return -1;
args++;
if (IMAP_ARG_IS_EOL(args))
break;
}
return 0;
}
const char **value_r)
{
unsigned int list_count;
return 0;
}
return -1;
if ((list_count % divisible) != 0)
return -1;
return -1;
return 0;
}
static int
const struct message_part *part,
const char **error_r)
{
const char *value;
unsigned int lines;
*error_r = "Invalid lines field";
return -1;
}
*error_r = "message_part lines doesn't match lines in BODYSTRUCTURE";
return -1;
}
return 0;
}
static int
const char **error_r)
{
args++;
*error_r = "Invalid content-disposition list";
return -1;
} else {
&data->content_disposition)) {
*error_r = "Invalid content-disposition";
return -1;
}
&data->content_disposition_params) < 0) {
*error_r = "Invalid content-disposition params";
return -1;
}
args++;
}
&data->content_language) < 0) {
*error_r = "Invalid content-language";
return -1;
}
*error_r = "Invalid content-location";
return -1;
}
return 0;
}
static int
const char **error_r)
{
struct message_part_body_data *data;
struct message_part *child_part;
child_part == NULL) {
*error_r = "message_part hierarchy doesn't match BODYSTRUCTURE";
return -1;
}
error_r) < 0)
return -1;
args++;
}
if (multipart) {
if (child_part != NULL) {
*error_r = "message_part hierarchy doesn't match BODYSTRUCTURE";
return -1;
}
*error_r = "Invalid multipart content-type";
return -1;
}
&data->content_type_params) < 0) {
*error_r = "Invalid content params";
return -1;
}
}
*error_r = "message_part multipart flag doesn't match BODYSTRUCTURE";
return -1;
}
/* "content type" "subtype" */
*error_r = "Invalid content-type";
return -1;
}
i_unreached();
args += 2;
#if 0
/* Disabled for now. Earlier Dovecot versions handled broken
Content-Type headers by writing them as "text" "plain" to
BODYSTRUCTURE reply, but the message_part didn't have
MESSAGE_PART_FLAG_TEXT. */
*error_r = "message_part text flag doesn't match BODYSTRUCTURE";
return -1;
}
#endif
return -1;
}
/* ("content type param key" "value" ...) | NIL */
&data->content_type_params) < 0) {
*error_r = "Invalid content params";
return -1;
}
/* "content id" "content description" "transfer encoding" size */
*error_r = "Invalid content-id";
return -1;
}
*error_r = "Invalid content-description";
return -1;
}
*error_r = "Invalid content-transfer-encoding";
return -1;
}
*error_r = "Invalid size field";
return -1;
}
*error_r = "message_part virtual_size doesn't match "
"size in BODYSTRUCTURE";
return -1;
}
if (text) {
return -1;
args++;
} else if (message_rfc822) {
struct message_part_body_data *child_data;
*error_r = "Child bodystructure list expected";
return -1;
}
return -1;
/* save envelope to the child's context data */
*error_r = "Envelope list expected";
return -1;
}
str_truncate(tmpstr, 0);
args += 2;
return -1;
args++;
} else {
}
*error_r = "Invalid content-description";
return -1;
}
}
{
struct imap_parser *parser;
int ret;
(void)i_stream_read(input);
if (ret < 0) {
} else if (ret == 0) {
*error_r = "Empty bodystructure";
ret = -1;
} else T_BEGIN {
} T_END;
return ret;
}
{
int i;
return -1;
args++;
}
if (multipart) {
/* next is subtype of Content-Type. rest is skipped. */
*error_r = "Invalid multipart content-type";
return -1;
}
return 0;
}
/* "content type" "subtype" */
*error_r = "Invalid content-type";
return -1;
}
i_unreached();
i_unreached();
args += 2;
/* ("content type param key" "value" ...) | NIL */
while (!IMAP_ARG_IS_EOL(subargs)) {
*error_r = "Invalid content param key";
return -1;
}
*error_r = "Invalid content param value";
return -1;
}
subargs += 2;
if (IMAP_ARG_IS_EOL(subargs))
break;
}
} else {
return -1;
}
args++;
/* "content id" "content description" "transfer encoding" size */
for (i = 0; i < 4; i++, args++) {
*error_r = "nstring expected";
return -1;
}
}
if (text) {
*error_r = "Text lines expected";
return -1;
}
} else if (message_rfc822) {
*error_r = "Envelope list expected";
return -1;
}
*error_r = "Child bodystructure list expected";
return -1;
}
return -1;
*error_r = "Text lines expected";
return -1;
}
}
return 0;
}
int imap_body_parse_from_bodystructure(const char *bodystructure,
{
struct imap_parser *parser;
int ret;
(void)i_stream_read(input);
if (ret < 0) {
} else if (ret == 0) {
*error_r = "Empty bodystructure";
ret = -1;
} else {
}
return ret;
}