static void test_message_parser_small_blocks(void)
{
	struct message_parser_ctx *parser;
	struct istream *input;
	struct message_part *parts, *parts2;
	struct message_block block;
	unsigned int i, end_of_headers_idx;
	pool_t pool;
	int ret;

	test_begin("message parser in small blocks");
	pool = pool_alloconly_create("message parser", 10240);
	input = test_istream_create(test_msg);

	/* full parsing */
	parser = message_parser_init(pool, input, 0, 0);
	while ((ret = message_parser_parse_next_block(parser, &block)) > 0) ;
	test_assert(ret < 0);
	test_assert(message_parser_deinit(&parser, &parts) == 0);

	/* parsing in small blocks */
	i_stream_seek(input, 0);
	test_istream_set_allow_eof(input, FALSE);

	parser = message_parser_init(pool, input, 0, 0);
	for (i = 1; i <= TEST_MSG_LEN*2+1; i++) {
		test_istream_set_size(input, i/2);
		if (i > TEST_MSG_LEN*2)
			test_istream_set_allow_eof(input, TRUE);
		while ((ret = message_parser_parse_next_block(parser,
							      &block)) > 0) ;
		test_assert((ret == 0 && i <= TEST_MSG_LEN*2) ||
			    (ret < 0 && i > TEST_MSG_LEN*2));
	}
	test_assert(message_parser_deinit(&parser, &parts2) == 0);
	test_assert(msg_parts_cmp(parts, parts2));

	/* parsing in small blocks from preparsed parts */
	i_stream_seek(input, 0);
	test_istream_set_allow_eof(input, FALSE);

	end_of_headers_idx = (strstr(test_msg, "\n-----") - test_msg);
	parser = message_parser_init_from_parts(parts, input, 0,
					MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK);
	for (i = 1; i <= TEST_MSG_LEN*2+1; i++) {
		test_istream_set_size(input, i/2);
		if (i > TEST_MSG_LEN*2)
			test_istream_set_allow_eof(input, TRUE);
		while ((ret = message_parser_parse_next_block(parser,
							      &block)) > 0) ;
		test_assert((ret == 0 && i/2 <= end_of_headers_idx) ||
			    (ret < 0 && i/2 > end_of_headers_idx));
	}
	test_assert(message_parser_deinit(&parser, &parts2) == 0);
	test_assert(msg_parts_cmp(parts, parts2));

	i_stream_unref(&input);
	pool_unref(&pool);
	test_end();
}
static struct message_part *msg_parse(pool_t pool, bool parse_bodystructure)
{
	struct message_parser_ctx *parser;
	struct istream *input;
	struct message_block block;
	struct message_part *parts;
	int ret;

	input = i_stream_create_from_data(testmsg, sizeof(testmsg)-1);
	parser = message_parser_init(pool, input,
			MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP |
			MESSAGE_HEADER_PARSER_FLAG_DROP_CR,
			MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK);
	while ((ret = message_parser_parse_next_block(parser, &block)) > 0) {
		if (parse_bodystructure) {
			imap_bodystructure_parse_header(pool, block.part,
							block.hdr);
		}
	}
	test_assert(ret < 0);

	test_assert(message_parser_deinit(&parser, &parts) == 0);
	i_stream_unref(&input);
	return parts;
}
示例#3
0
int message_snippet_generate(struct istream *input,
			     unsigned int max_snippet_chars,
			     string_t *snippet)
{
	struct message_parser_ctx *parser;
	struct message_part *parts;
	struct message_decoder_context *decoder;
	struct message_block raw_block, block;
	struct snippet_context ctx;
	pool_t pool;
	int ret;

	memset(&ctx, 0, sizeof(ctx));
	pool = pool_alloconly_create("message snippet", 1024);
	ctx.snippet = snippet;
	ctx.chars_left = max_snippet_chars;

	parser = message_parser_init(pool_datastack_create(), input, 0, 0);
	decoder = message_decoder_init(NULL, 0);
	while ((ret = message_parser_parse_next_block(parser, &raw_block)) > 0) {
		if (!message_decoder_decode_next_block(decoder, &raw_block, &block))
			continue;
		if (block.size == 0) {
			const char *ct;

			if (block.hdr != NULL)
				continue;

			/* end of headers - verify that we can use this
			   Content-Type. we get here only once, because we
			   always handle only one non-multipart MIME part. */
			ct = message_decoder_current_content_type(decoder);
			if (ct == NULL)
				/* text/plain */ ;
			else if (mail_html2text_content_type_match(ct)) {
				ctx.html2text = mail_html2text_init(MAIL_HTML2TEXT_FLAG_SKIP_QUOTED);
				ctx.plain_output = buffer_create_dynamic(pool, 1024);
			} else if (strncasecmp(ct, "text/", 5) != 0)
				break;
			continue;
		}
		if (!snippet_generate(&ctx, block.data, block.size))
			break;
	}
	i_assert(ret != 0);
	message_decoder_deinit(&decoder);
	message_parser_deinit(&parser, &parts);
	if (ctx.html2text != NULL)
		mail_html2text_deinit(&ctx.html2text);
	pool_unref(&pool);
	return input->stream_errno == 0 ? 0 : -1;
}
示例#4
0
void index_mail_cache_parse_continue(struct mail *_mail)
{
	struct index_mail *mail = (struct index_mail *)_mail;
	struct message_block block;

	while (message_parser_parse_next_block(mail->data.parser_ctx,
					       &block) > 0) {
		if (block.size != 0)
			continue;

		if (!mail->data.header_parsed) {
			index_mail_parse_header(block.part, block.hdr, mail);
			if (block.hdr == NULL)
				mail->data.header_parsed = TRUE;
		} else {
			imap_bodystructure_parse_header(mail->data_pool,
							block.part, block.hdr);
		}
	}
}
示例#5
0
static void test_message_part_idx(void)
{
	struct message_parser_ctx *parser;
	struct istream *input;
	struct message_part *parts, *part, *prev_part;
	struct message_block block;
	unsigned int i, prev_idx = 0, part_idx;
	pool_t pool;
	int ret;

	test_begin("message part indexes");
	pool = pool_alloconly_create("message parser", 10240);
	input = i_stream_create_from_data(test_msg, TEST_MSG_LEN);

	parser = message_parser_init(pool, input, 0, 0);
	while ((ret = message_parser_parse_next_block(parser, &block)) > 0) {
		part_idx = message_part_to_idx(block.part);
		test_assert(part_idx >= prev_idx);
		prev_idx = part_idx;
	}
	test_assert(ret < 0);
	test_assert(message_parser_deinit(&parser, &parts) == 0);

	part = message_part_by_idx(parts, 0);
	test_assert(part == parts);
	test_assert(message_part_by_idx(parts, 1) == parts->children);

	for (i = 1; i < 11; i++) {
		prev_part = part;
		part = message_part_by_idx(parts, i);
		test_assert(part != NULL);
		test_assert(part != NULL && message_part_to_idx(part) == i);
		test_assert(part != NULL && prev_part != NULL &&
			    prev_part->physical_pos < part->physical_pos);
	}
	test_assert(message_part_by_idx(parts, i) == NULL);

	i_stream_unref(&input);
	pool_unref(&pool);
	test_end();
}
示例#6
0
static int
message_search_msg_real(struct message_search_context *ctx,
			struct istream *input, struct message_part *parts,
			const char **error_r)
{
	const enum message_header_parser_flags hdr_parser_flags =
		MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE;
	struct message_parser_ctx *parser_ctx;
	struct message_block raw_block;
	struct message_part *new_parts;
	int ret;

	message_search_reset(ctx);

	if (parts != NULL) {
		parser_ctx = message_parser_init_from_parts(parts,
						input, hdr_parser_flags, 0);
	} else {
		parser_ctx = message_parser_init(pool_datastack_create(),
						 input, hdr_parser_flags, 0);
	}

	while ((ret = message_parser_parse_next_block(parser_ctx,
						      &raw_block)) > 0) {
		if (message_search_more(ctx, &raw_block)) {
			ret = 1;
			break;
		}
	}
	i_assert(ret != 0);
	if (ret < 0 && input->stream_errno == 0) {
		/* normal exit */
		ret = 0;
	}
	if (message_parser_deinit_from_parts(&parser_ctx, &new_parts, error_r) < 0) {
		/* broken parts */
		ret = -1;
	}
	return ret;
}
static int astream_read_next(struct attachment_istream *astream, bool *retry_r)
{
	struct istream_private *stream = &astream->istream;
	struct message_block block;
	size_t old_size, new_size;
	const char *error;
	int ret;

	*retry_r = FALSE;

	if (stream->pos - stream->skip >= i_stream_get_max_buffer_size(&stream->istream))
		return -2;

	if (astream->failed) {
		stream->istream.stream_errno = EINVAL;
		return -1;
	}

	old_size = stream->pos - stream->skip;
	switch (message_parser_parse_next_block(astream->parser, &block)) {
	case -1:
		/* done / error */
		ret = astream_end_of_part(astream, &error);
		if (ret > 0) {
			/* final data */
			new_size = stream->pos - stream->skip;
			return new_size - old_size;
		}
		stream->istream.eof = TRUE;
		stream->istream.stream_errno = stream->parent->stream_errno;

		if (ret < 0) {
			io_stream_set_error(&stream->iostream, "%s", error);
			stream->istream.stream_errno = EINVAL;
			astream->failed = TRUE;
		}
		astream->cur_part = NULL;
		return -1;
	case 0:
		/* need more data */
		return 0;
	default:
		break;
	}

	if (block.part != astream->cur_part && astream->cur_part != NULL) {
		/* end of a MIME part */
		if (astream_end_of_part(astream, &error) < 0) {
			io_stream_set_error(&stream->iostream, "%s", error);
			stream->istream.stream_errno = EINVAL;
			astream->failed = TRUE;
			return -1;
		}
	}
	astream->cur_part = block.part;

	if (block.hdr != NULL) {
		/* parsing a header */
		astream_parse_header(astream, block.hdr);
	} else if (block.size == 0) {
		/* end of headers */
		if (astream_want_attachment(astream, block.part)) {
			astream->part.state = MAIL_ATTACHMENT_STATE_MAYBE;
			astream->part.start_offset = stream->parent->v_offset;
		}
	} else {
		astream_add_body(astream, &block);
	}
	new_size = stream->pos - stream->skip;
	*retry_r = new_size == old_size;
	return new_size - old_size;
}