message-parser.c revision 35283613d4c04ce18836e9fc431582c87b3710a0
/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
#include "lib.h"
#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.
We'll add a bit more just in case. */
struct message_boundary {
struct message_boundary *next;
struct message_part *part;
const char *boundary;
unsigned int epilogue_found:1;
};
struct message_parser_ctx {
enum message_parser_flags flags;
const char *last_boundary;
struct message_boundary *boundaries;
char last_chr;
unsigned int want_count;
struct message_header_parser_ctx *hdr_parser_ctx;
struct message_block *block_r);
unsigned int part_seen_content_type:1;
unsigned int broken:1;
unsigned int eof:1;
};
struct message_block *block_r);
struct message_block *block_r);
struct message_block *block_r);
struct message_block *block_r);
static struct message_boundary *
{
/* As MIME spec says: search from latest one to oldest one so that we
don't break if the same boundary is used in nested parts. Also the
full message line doesn't have to match the boundary, only the
beginning. */
while (boundaries != NULL) {
return boundaries;
}
return NULL;
}
struct message_block *block)
{
unsigned int missing_cr_count = 0;
/* check if we have NULs */
/* count number of lines and missing CRs */
if (*data == '\n') {
}
}
}
{
int ret;
}
if (ret <= 0) {
switch (ret) {
case 0:
return 0;
}
break;
case -1:
/* EOF, but we still have some data.
return it. */
return 1;
}
return -1;
case -2:
break;
default:
i_unreached();
}
}
return 1;
}
static struct message_part *
{
/* set child position */
part->physical_pos =
return part;
}
{
struct message_boundary *b;
ctx->boundaries = b;
}
struct message_block *block_r)
{
}
static int
struct message_boundary **boundary_r)
{
*boundary_r = NULL;
if (size < 2) {
return -1;
return 0;
}
/* not a boundary, just skip this line */
return -1;
}
/* need to find the end of line */
size < BOUNDARY_END_MAX_LEN &&
/* no LF found */
return 0;
}
data += 2;
size -= 2;
if (*boundary_r == NULL)
return -1;
(*boundary_r)->epilogue_found =
return 1;
}
struct message_block *block_r)
{
}
struct message_block *block_r)
{
const unsigned char *ptr;
int ret;
bool full;
return ret;
return 1;
}
/* found the LF */
/* a new MIME part begins */
return 1;
}
struct message_boundary *boundary,
{
struct message_part *part;
/* get back to parent MIME part, summing the child MIME part sizes
into parent's body sizes */
}
if (boundary->epilogue_found) {
/* this boundary isn't needed anymore */
else
}
/* forget about the boundaries we possibly skipped */
/* the boundary itself should already be in buffer. add that. */
(first_line ? 0 : 1));
/* [\n]--<boundary> */
return 1;
}
struct message_block *block_r)
{
int ret;
bool full;
return ret;
/* handle boundary in first line of message. alternatively
it's an empty line. */
if (ret >= 0) {
return ret == 0 ? 0 :
}
}
boundary_start = 0;
/* skip to beginning of the next line. the first line was
handled already. */
if (boundary_start != 0) {
/* we can at least skip data until the first [CR]LF.
input buffer can't be full anymore. */
}
if (ret >= 0) {
/* found / need more data */
if (ret == 0 && boundary_start == 0)
break;
}
}
/* found / need more data */
} else if (boundary_start == 0) {
/* no linefeeds in this block. we can just skip it. */
ret = 0;
} else {
/* the boundary wasn't found from this data block,
we'll need more data. */
ret = 0;
}
/* a) we found the boundary
b) we need more data and haven't reached EOF yet
so leave CR+LF + last line to buffer */
}
return 1;
}
}
struct message_block *block_r)
{
bool full;
int ret;
return ret;
return 1;
}
struct message_header_line *hdr)
{
struct rfc822_parser_context parser;
const char *const *results;
if (ctx->part_seen_content_type)
return;
(void)rfc822_skip_lwsp(&parser);
return;
}
return;
ctx->last_boundary =
break;
}
}
}
#define MUTEX_FLAGS \
struct message_block *block_r)
{
struct message_header_line *hdr;
int ret;
}
return ret;
}
;
/* it's MIME. Content-* headers are valid */
else T_BEGIN {
} T_END;
}
return 1;
}
/* end of headers */
/* multipart type but no message boundary */
}
/* It's not MIME. Reset everything we found from
Content-Type. */
}
if (!ctx->part_seen_content_type ||
MESSAGE_PART_FLAG_MULTIPART_DIGEST) != 0) {
/* when there's no content-type specified and we're
content-type */
} else {
}
}
else
/* return empty block as end of headers */
return 1;
}
struct message_block *block_r)
{
}
{
return -1;
}
{
break;
}
}
}
struct message_block *block_r)
{
}
struct message_block *block_r)
{
bool full;
int ret;
return ret;
}
return 1;
}
struct message_block *block_r)
{
/* header was actually larger than the cached size suggested */
return -1;
}
}
struct message_block *block_r)
{
} else {
}
}
struct message_block *block_r)
{
struct message_header_line *hdr;
int ret;
return ret;
}
return 1;
}
/* return empty block as end of headers */
return -1;
}
return 1;
}
struct message_block *block_r)
{
}
static struct message_parser_ctx *
enum message_parser_flags flags)
{
struct message_parser_ctx *ctx;
return ctx;
}
struct message_parser_ctx *
enum message_parser_flags flags)
{
struct message_parser_ctx *ctx;
return ctx;
}
struct message_parser_ctx *
enum message_parser_flags flags)
{
struct message_parser_ctx *ctx;
return ctx;
}
struct message_part **parts_r)
{
return ret;
}
struct message_block *block_r)
{
int ret;
if (ret == 0) {
return 0;
}
if (ret == -1) {
}
}
/* Successful EOF or unexpected failure */
}
}
return ret;
}
struct message_size *hdr_size,
void *context)
{
struct message_block block;
int ret;
break;
}
if (ret < 0) {
/* well, can't return error so fake end of headers */
}
}
void *context)
{
struct message_block block;
int ret;
}
}