Esempio n. 1
0
static int parse_next_body_to_eof(struct message_parser_ctx *ctx,
				  struct message_block *block_r)
{
	bool full;
	int ret;

	if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
		return ret;

	parse_body_add_block(ctx, block_r);
	return 1;
}
Esempio n. 2
0
static int parse_next_body_to_eof(struct message_parser_ctx *ctx,
				  struct message_block *block_r)
{
	bool full;
	int ret;

	if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
		return ret;

	parse_body_add_block(ctx, block_r);

	if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
	    (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) == 0)
		return 0;

	return 1;
}
Esempio n. 3
0
static int parse_next_body_skip_boundary_line(struct message_parser_ctx *ctx,
					      struct message_block *block_r)
{
	const unsigned char *ptr;
	int ret;
	bool full;

	if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
		return ret;

	ptr = memchr(block_r->data, '\n', block_r->size);
	if (ptr == NULL) {
		parse_body_add_block(ctx, block_r);
		if (block_r->size > 0 &&
		    (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
			return 1;
		return 0;
	}

	/* found the LF */
	block_r->size = (ptr - block_r->data) + 1;
	parse_body_add_block(ctx, block_r);

	if (ctx->boundaries == NULL || ctx->boundaries->part != ctx->part) {
		/* epilogue */
		if (ctx->boundaries != NULL)
			ctx->parse_next_block = parse_next_body_to_boundary;
		else
			ctx->parse_next_block = parse_next_body_to_eof;
	} else {
		/* a new MIME part begins */
		ctx->parse_next_block = parse_next_mime_header_init;
	}
	if (block_r->size > 0 &&
	    (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
		return 1;
	return ctx->parse_next_block(ctx, block_r);
}
Esempio n. 4
0
static int parse_next_body_skip_boundary_line(struct message_parser_ctx *ctx,
					      struct message_block *block_r)
{
	const unsigned char *ptr;
	int ret;
	bool full;

	if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
		return ret;

	ptr = memchr(block_r->data, '\n', block_r->size);
	if (ptr == NULL) {
		parse_body_add_block(ctx, block_r);
		return 1;
	}

	/* found the LF */
	block_r->size = (ptr - block_r->data) + 1;
	parse_body_add_block(ctx, block_r);

	/* a new MIME part begins */
	ctx->parse_next_block = parse_next_mime_header_init;
	return 1;
}
Esempio n. 5
0
static int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
				       struct message_block *block_r)
{
	struct message_boundary *boundary = NULL;
	const unsigned char *data, *cur, *next, *end;
	size_t boundary_start;
	int ret;
	bool full;

	if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
		return ret;

	data = block_r->data;
	if (ctx->last_chr == '\n') {
		/* handle boundary in first line of message. alternatively
		   it's an empty line. */
		ret = boundary_line_find(ctx, block_r->data,
					 block_r->size, full, &boundary);
		if (ret >= 0) {
			return ret == 0 ? 0 :
				parse_part_finish(ctx, boundary, block_r, TRUE);
		}
	}

	i_assert(block_r->size > 0);
	boundary_start = 0;

	/* skip to beginning of the next line. the first line was
	   handled already. */
	cur = data; end = data + block_r->size;
	while ((next = memchr(cur, '\n', end - cur)) != NULL) {
		cur = next + 1;

		boundary_start = next - data;
		if (next > data && next[-1] == '\r')
			boundary_start--;

		if (boundary_start != 0) {
			/* we can at least skip data until the first [CR]LF.
			   input buffer can't be full anymore. */
			full = FALSE;
		}

		ret = boundary_line_find(ctx, cur, end - cur, full, &boundary);
		if (ret >= 0) {
			/* found / need more data */
			if (ret == 0 && boundary_start == 0)
				ctx->want_count += cur - block_r->data;
			break;
		}
	}

	if (next != NULL) {
		/* found / need more data */
		i_assert(ret >= 0);
		i_assert(!(ret == 0 && full));
	} else if (boundary_start == 0) {
		/* no linefeeds in this block. we can just skip it. */
		ret = 0;
		boundary_start = block_r->size;
	} else {
		/* the boundary wasn't found from this data block,
		   we'll need more data. */
		ret = 0;
		ctx->want_count = (block_r->size - boundary_start) + 1;
	}

	if (ret > 0 || (ret == 0 && !ctx->eof)) {
		/* a) we found the boundary
		   b) we need more data and haven't reached EOF yet
		   so leave CR+LF + last line to buffer */
		block_r->size = boundary_start;
	}
	if (block_r->size != 0) {
		parse_body_add_block(ctx, block_r);
		return 1;
	}
	return ret <= 0 ? ret :
		parse_part_finish(ctx, boundary, block_r, FALSE);
}
Esempio n. 6
0
static int parse_next_header(struct message_parser_ctx *ctx,
			     struct message_block *block_r)
{
	struct message_part *part = ctx->part;
	struct message_header_line *hdr;
	struct message_boundary *boundary;
	bool full;
	int ret;

	if ((ret = message_parser_read_more(ctx, block_r, &full)) == 0)
		return ret;

	if (ret > 0 && block_is_at_eoh(block_r) &&
	    ctx->last_boundary != NULL &&
	    (part->flags & MESSAGE_PART_FLAG_IS_MIME) != 0) {
		/* we are at the end of headers and we've determined that we're
		   going to start a multipart. add the boundary already here
		   at this point so we can reliably determine whether the
		   "\n--boundary" belongs to us or to a previous boundary.
		   this is a problem if the boundary prefixes are identical,
		   because MIME requires only the prefix to match. */
		parse_next_body_multipart_init(ctx);
		ctx->multipart = TRUE;
	}

	/* before parsing the header see if we can find a --boundary from here.
	   we're guaranteed to be at the beginning of the line here. */
	if (ret > 0) {
		ret = ctx->boundaries == NULL ? -1 :
			boundary_line_find(ctx, block_r->data,
					   block_r->size, full, &boundary);
		if (ret > 0 && boundary->part == ctx->part) {
			/* our own body begins with our own --boundary.
			   we don't want to handle that yet. */
			ret = -1;
		}
	}
	if (ret < 0) {
		/* no boundary */
		ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
		if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
			ctx->want_count = i_stream_get_data_size(ctx->input) + 1;
			return ret;
		}
	} else if (ret == 0) {
		/* need more data */
		return 0;
	} else {
		/* boundary found. stop parsing headers here. The previous
		   [CR]LF belongs to the MIME boundary though. */
		if (ctx->prev_hdr_newline_size > 0) {
			i_assert(ctx->part->header_size.lines > 0);
			/* remove the newline size from the MIME header */
			ctx->part->header_size.lines--;
			ctx->part->header_size.physical_size -=
				ctx->prev_hdr_newline_size;
			ctx->part->header_size.virtual_size -= 2;
			/* add the newline size to the parent's body */
			ctx->part->parent->body_size.lines++;
			ctx->part->parent->body_size.physical_size +=
				ctx->prev_hdr_newline_size;
			ctx->part->parent->body_size.virtual_size += 2;
		}
		hdr = NULL;
	}

	if (hdr != NULL) {
		if (hdr->eoh)
			;
		else if (strcasecmp(hdr->name, "Mime-Version") == 0) {
			/* it's MIME. Content-* headers are valid */
			part->flags |= MESSAGE_PART_FLAG_IS_MIME;
		} else if (strcasecmp(hdr->name, "Content-Type") == 0) {
			if ((ctx->flags &
			     MESSAGE_PARSER_FLAG_MIME_VERSION_STRICT) == 0)
				part->flags |= MESSAGE_PART_FLAG_IS_MIME;

			if (hdr->continues)
				hdr->use_full_value = TRUE;
			else T_BEGIN {
				parse_content_type(ctx, hdr);
			} T_END;
		}

		block_r->hdr = hdr;
		block_r->size = 0;
		ctx->prev_hdr_newline_size = hdr->no_newline ? 0 :
			(hdr->crlf_newline ? 2 : 1);
		return 1;
	}

	/* end of headers */
	if ((part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
		/* It's not MIME. Reset everything we found from
		   Content-Type. */
		i_assert(!ctx->multipart);
		part->flags = 0;
	}
	ctx->last_boundary = NULL;

	if (!ctx->part_seen_content_type ||
	    (part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
		if (part->parent != NULL &&
		    (part->parent->flags &
		     MESSAGE_PART_FLAG_MULTIPART_DIGEST) != 0) {
			/* when there's no content-type specified and we're
			   below multipart/digest, assume message/rfc822
			   content-type */
			part->flags |= MESSAGE_PART_FLAG_MESSAGE_RFC822;
		} else {
			/* otherwise we default to text/plain */
			part->flags |= MESSAGE_PART_FLAG_TEXT;
		}
	}

	if (message_parse_header_has_nuls(ctx->hdr_parser_ctx))
		part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
	message_parse_header_deinit(&ctx->hdr_parser_ctx);

	i_assert((part->flags & MUTEX_FLAGS) != MUTEX_FLAGS);

	ctx->last_chr = '\n';
	if (ctx->multipart) {
		i_assert(ctx->last_boundary == NULL);
		ctx->multipart = FALSE;
		ctx->parse_next_block = parse_next_body_to_boundary;
	} else if ((part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) != 0)
		ctx->parse_next_block = parse_next_body_message_rfc822_init;
	else if (ctx->boundaries != NULL)
		ctx->parse_next_block = parse_next_body_to_boundary;
	else
		ctx->parse_next_block = parse_next_body_to_eof;

	ctx->want_count = 1;

	/* return empty block as end of headers */
	block_r->hdr = NULL;
	block_r->size = 0;
	return 1;
}