changeset 5525:94bc3fbdecd5 HEAD

Removed message body/header searchers. They're now combined into one message-search.
author Timo Sirainen <tss@iki.fi>
date Wed, 04 Apr 2007 13:16:38 +0300
parents aee211178d23
children aedfd6623f84
files src/lib-mail/Makefile.am src/lib-mail/message-body-search.c src/lib-mail/message-body-search.h src/lib-mail/message-header-search.c src/lib-mail/message-header-search.h src/lib-mail/message-search.c src/lib-mail/message-search.h src/lib-storage/index/index-search.c
diffstat 8 files changed, 277 insertions(+), 447 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-mail/Makefile.am	Wed Apr 04 13:14:02 2007 +0300
+++ b/src/lib-mail/Makefile.am	Wed Apr 04 13:16:38 2007 +0300
@@ -7,16 +7,15 @@
 libmail_a_SOURCES = \
 	istream-header-filter.c \
 	message-address.c \
-	message-body-search.c \
 	message-content-parser.c \
 	message-date.c \
 	message-decoder.c \
 	message-header-decode.c \
 	message-header-parser.c \
-	message-header-search.c \
 	message-id.c \
 	message-parser.c \
 	message-part-serialize.c \
+	message-search.c \
 	message-send.c \
 	message-size.c \
 	quoted-printable.c \
@@ -26,16 +25,15 @@
 	istream-header-filter.h \
 	mail-types.h \
 	message-address.h \
-	message-body-search.h \
 	message-content-parser.h \
 	message-date.h \
 	message-decoder.h \
 	message-header-decode.h \
 	message-header-parser.h \
-	message-header-search.h \
 	message-id.h \
 	message-parser.h \
 	message-part-serialize.h \
+	message-search.a \
 	message-send.h \
 	message-size.h \
 	quoted-printable.h \
--- a/src/lib-mail/message-body-search.c	Wed Apr 04 13:14:02 2007 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,171 +0,0 @@
-/* Copyright (C) 2002-2007 Timo Sirainen */
-
-#include "lib.h"
-#include "buffer.h"
-#include "istream.h"
-#include "str-find.h"
-#include "charset-utf8.h"
-#include "message-decoder.h"
-#include "message-parser.h"
-#include "message-content-parser.h"
-#include "message-body-search.h"
-
-struct message_body_search_context {
-	pool_t pool;
-
-	char *key;
-	char *key_charset;
-	unsigned int key_len;
-
-	struct str_find_context *str_find_ctx;
-
-	struct message_decoder_context *decoder;
-	unsigned int search_header:1;
-	unsigned int content_type_text:1; /* text/any or message/any */
-};
-
-static void parse_content_type(const unsigned char *value, size_t value_len,
-			       void *context)
-{
-	struct message_body_search_context *ctx = context;
-	const char *str;
-
-	t_push();
-	str = t_strndup(value, value_len);
-	ctx->content_type_text =
-		strncasecmp(str, "text/", 5) == 0 ||
-		strncasecmp(str, "message/", 8) == 0;
-	t_pop();
-}
-
-int message_body_search_init(pool_t pool, const char *key, const char *charset,
-			     bool search_header,
-			     struct message_body_search_context **ctx_r)
-{
-	struct message_body_search_context *ctx;
-	bool unknown_charset;
-	size_t key_len;
-
-	/* get the key uppercased */
-	t_push();
-	key = charset_to_ucase_utf8_string(charset, &unknown_charset,
-					   (const unsigned char *)key,
-					   strlen(key), &key_len);
-	if (key == NULL) {
-		t_pop();
-		return unknown_charset ? 0 : -1;
-	}
-
-	ctx = *ctx_r = p_new(pool, struct message_body_search_context, 1);
-	ctx->pool = pool;
-	ctx->key = p_strdup(pool, key);
-	ctx->key_len = key_len;
-	ctx->key_charset = p_strdup(pool, charset);
-	ctx->search_header = search_header;
-	ctx->decoder = message_decoder_init_ucase();
-	ctx->str_find_ctx = str_find_init(pool, ctx->key);
-	t_pop();
-	return 1;
-}
-
-void message_body_search_deinit(struct message_body_search_context **_ctx)
-{
-	struct message_body_search_context *ctx = *_ctx;
-
-	*_ctx = NULL;
-	str_find_deinit(&ctx->str_find_ctx);
-	message_decoder_deinit(&ctx->decoder);
-	p_free(ctx->pool, ctx->key);
-	p_free(ctx->pool, ctx->key_charset);
-	p_free(ctx->pool, ctx);
-}
-
-static void handle_header(struct message_body_search_context *ctx,
-			  struct message_header_line *hdr)
-{
-	if (hdr->name_len == 12 &&
-	    strcasecmp(hdr->name, "Content-Type") == 0) {
-		if (hdr->continues) {
-			hdr->use_full_value = TRUE;
-			return;
-		}
-		message_content_parse_header(hdr->full_value,
-					     hdr->full_value_len,
-					     parse_content_type, NULL, ctx);
-	}
-}
-
-static bool search_header(struct message_body_search_context *ctx,
-			  const struct message_header_line *hdr)
-{
-	return str_find_more(ctx->str_find_ctx,
-			     (const unsigned char *)hdr->name, hdr->name_len) ||
-		str_find_more(ctx->str_find_ctx,
-			      hdr->middle, hdr->middle_len) ||
-		str_find_more(ctx->str_find_ctx, hdr->full_value,
-			      hdr->full_value_len);
-}
-
-int message_body_search(struct message_body_search_context *ctx,
-			struct istream *input,
-			const struct message_part *parts)
-{
-	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, block;
-	int ret = 0;
-
-	t_push();
-	/* Content-Type defaults to text/plain */
-	ctx->content_type_text = TRUE;
-
-	parser_ctx =
-		message_parser_init_from_parts((struct message_part *)parts,
-					       input, hdr_parser_flags, 0);
-
-	while ((ret = message_parser_parse_next_block(parser_ctx,
-						      &raw_block)) > 0) {
-		if (raw_block.hdr != NULL) {
-			if (raw_block.part->parent == NULL &&
-			    !ctx->search_header) {
-				/* skipping the main header */
-				continue;
-			}
-
-			handle_header(ctx, raw_block.hdr);
-		} else if (raw_block.size == 0) {
-			/* part changes */
-			ctx->content_type_text = TRUE;
-			str_find_reset(ctx->str_find_ctx);
-			continue;
-		} else {
-			/* body */
-			if (!ctx->content_type_text)
-				continue;
-		}
-		if (!message_decoder_decode_next_block(ctx->decoder, &raw_block,
-						       &block))
-			continue;
-
-		if (block.hdr != NULL) {
-			if (search_header(ctx, block.hdr)) {
-				ret = 1;
-				break;
-			}
-		} else {
-			if (str_find_more(ctx->str_find_ctx,
-					  block.data, block.size)) {
-				ret = 1;
-				break;
-			}
-		}
-	}
-	i_assert(ret != 0);
-	if (ret < 0 && input->stream_errno == 0)
-		ret = 0;
-	(void)message_parser_deinit(&parser_ctx);
-	t_pop();
-
-	return ret;
-}
--- a/src/lib-mail/message-body-search.h	Wed Apr 04 13:14:02 2007 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-#ifndef __MESSAGE_BODY_SEARCH_H
-#define __MESSAGE_BODY_SEARCH_H
-
-struct message_part;
-struct message_body_search_context;
-
-/* Returns 1 if ok, 0 if unknown charset, -1 if key contains invalid characters
-   in given charset. */
-int message_body_search_init(pool_t pool, const char *key, const char *charset,
-			     bool search_header,
-			     struct message_body_search_context **ctx_r);
-void message_body_search_deinit(struct message_body_search_context **ctx);
-
-/* Returns 1 if key is found from input buffer, 0 if not and -1 if message_part
-   is invalid. */
-int message_body_search(struct message_body_search_context *ctx,
-			struct istream *input,
-			const struct message_part *parts);
-
-#endif
--- a/src/lib-mail/message-header-search.c	Wed Apr 04 13:14:02 2007 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "lib.h"
-#include "base64.h"
-#include "buffer.h"
-#include "str-find.h"
-#include "charset-utf8.h"
-#include "quoted-printable.h"
-#include "message-parser.h"
-#include "message-header-decode.h"
-#include "message-header-search.h"
-
-#include <ctype.h>
-
-struct message_header_search_context {
-	pool_t pool;
-
-	unsigned char *key;
-	size_t key_len;
-	char *key_charset;
-
-	struct str_find_context *str_find_ctx;
-
-	unsigned int found:1;
-	unsigned int last_lf:1;
-	unsigned int unknown_charset:1;
-};
-
-int message_header_search_init(pool_t pool, const char *key,
-			       const char *charset,
-			       struct message_header_search_context **ctx_r)
-{
-	struct message_header_search_context *ctx;
-	size_t key_len;
-	bool unknown_charset;
-
-	/* get the key uppercased */
-	t_push();
-	key = charset_to_ucase_utf8_string(charset, &unknown_charset,
-					   (const unsigned char *) key,
-					   strlen(key), &key_len);
-
-	if (key == NULL) {
-		t_pop();
-		return unknown_charset ? 0 : -1;
-	}
-
-	ctx = *ctx_r = p_new(pool, struct message_header_search_context, 1);
-	ctx->pool = pool;
-	ctx->key = (unsigned char *) p_strdup(pool, key);
-	ctx->key_len = key_len;
-	ctx->key_charset = p_strdup(pool, charset);
-	ctx->unknown_charset = charset == NULL;
-	ctx->str_find_ctx = str_find_init(pool, key);
-
-	i_assert(ctx->key_len <= SSIZE_T_MAX/sizeof(size_t));
-	t_pop();
-	return 1;
-}
-
-void message_header_search_deinit(struct message_header_search_context **_ctx)
-{
-        struct message_header_search_context *ctx = *_ctx;
-	pool_t pool;
-
-	*_ctx = NULL;
-
-	str_find_deinit(&ctx->str_find_ctx);
-
-	pool = ctx->pool;
-	p_free(pool, ctx->key);
-	p_free(pool, ctx->key_charset);
-	p_free(pool, ctx);
-}
-
-static bool search_with_charset(const unsigned char *data, size_t size,
-				const char *charset,
-				struct message_header_search_context *ctx)
-{
-	const char *utf8_data;
-	size_t utf8_size;
-
-	if (ctx->unknown_charset) {
-		/* we don't know the source charset, so assume we want to
-		   match using same charsets */
-		charset = NULL;
-	} else if (charset != NULL && strcasecmp(charset, "x-unknown") == 0) {
-		/* compare with same charset as search key. the key is already
-		   in utf-8 so we can't use charset = NULL comparing. */
-		charset = ctx->key_charset;
-	}
-
-	utf8_data = charset_to_ucase_utf8_string(charset, NULL, data, size,
-						 &utf8_size);
-
-	if (utf8_data == NULL) {
-		/* unknown character set, or invalid data. just compare it
-		   directly so at least ASCII comparision works. */
-		utf8_data = str_ucase(p_strndup(unsafe_data_stack_pool,
-						data, size));
-		utf8_size = size;
-	}
-
-	return str_find_more(ctx->str_find_ctx, utf8_data, utf8_size);
-}
-
-static bool search_block(const unsigned char *data, size_t size,
-			 const char *charset, void *context)
-{
-	struct message_header_search_context *ctx = context;
-
-	t_push();
-	ctx->found = search_with_charset(data, size, charset, ctx);
-	t_pop();
-	return !ctx->found;
-}
-
-bool message_header_search(struct message_header_search_context *ctx,
-			   const unsigned char *header_block, size_t size)
-{
-	if (!ctx->found)
-		message_header_decode(header_block, size, search_block, ctx);
-	return ctx->found;
-}
-
-void message_header_search_reset(struct message_header_search_context *ctx)
-{
-	str_find_reset(ctx->str_find_ctx);
-	ctx->last_lf = FALSE;
-	ctx->found = FALSE;
-}
--- a/src/lib-mail/message-header-search.h	Wed Apr 04 13:14:02 2007 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#ifndef __MESSAGE_HEADER_SEARCH_H
-#define __MESSAGE_HEADER_SEARCH_H
-
-struct message_header_search_context;
-
-/* Returns 1 if ok, 0 if unknown charset, -1 if key contains invalid characters
-   in given charset. */
-int message_header_search_init(pool_t pool, const char *key,
-			       const char *charset,
-			       struct message_header_search_context **ctx_r);
-/* Deinitialize search context. Not needed if you just destroy the pool. */
-void message_header_search_deinit(struct message_header_search_context **ctx);
-
-/* Returns TRUE if key is found from header. This function may be called
-   multiple times with partial header blocks, but the blocks must contain only
-   full lines so RFC2047 parsing can be done. */
-bool message_header_search(struct message_header_search_context *ctx,
-			   const unsigned char *header_block, size_t size);
-
-/* Next call to message_header_search() will begin a new header. */
-void message_header_search_reset(struct message_header_search_context *ctx);
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-mail/message-search.c	Wed Apr 04 13:16:38 2007 +0300
@@ -0,0 +1,192 @@
+/* Copyright (C) 2002-2007 Timo Sirainen */
+
+#include "lib.h"
+#include "buffer.h"
+#include "istream.h"
+#include "str-find.h"
+#include "charset-utf8.h"
+#include "message-decoder.h"
+#include "message-parser.h"
+#include "message-content-parser.h"
+#include "message-search.h"
+
+struct message_search_context {
+	pool_t pool;
+
+	char *key;
+	char *key_charset;
+	unsigned int key_len;
+
+	enum message_search_flags flags;
+	struct str_find_context *str_find_ctx;
+	struct message_part *prev_part;
+
+	struct message_decoder_context *decoder;
+	unsigned int content_type_text:1; /* text/any or message/any */
+};
+
+static void parse_content_type(const unsigned char *value, size_t value_len,
+			       void *context)
+{
+	struct message_search_context *ctx = context;
+	const char *str;
+
+	t_push();
+	str = t_strndup(value, value_len);
+	ctx->content_type_text =
+		strncasecmp(str, "text/", 5) == 0 ||
+		strncasecmp(str, "message/", 8) == 0;
+	t_pop();
+}
+
+int message_search_init(pool_t pool, const char *key, const char *charset,
+			enum message_search_flags flags,
+			struct message_search_context **ctx_r)
+{
+	struct message_search_context *ctx;
+	bool unknown_charset;
+	size_t key_len;
+
+	/* get the key uppercased */
+	t_push();
+	key = charset_to_ucase_utf8_string(charset, &unknown_charset,
+					   (const unsigned char *)key,
+					   strlen(key), &key_len);
+	if (key == NULL) {
+		t_pop();
+		return unknown_charset ? 0 : -1;
+	}
+
+	ctx = *ctx_r = p_new(pool, struct message_search_context, 1);
+	ctx->pool = pool;
+	ctx->key = p_strdup(pool, key);
+	ctx->key_len = key_len;
+	ctx->key_charset = p_strdup(pool, charset);
+	ctx->flags = flags;
+	ctx->decoder = message_decoder_init_ucase();
+	ctx->str_find_ctx = str_find_init(pool, ctx->key);
+	t_pop();
+	return 1;
+}
+
+void message_search_deinit(struct message_search_context **_ctx)
+{
+	struct message_search_context *ctx = *_ctx;
+
+	*_ctx = NULL;
+	str_find_deinit(&ctx->str_find_ctx);
+	message_decoder_deinit(&ctx->decoder);
+	p_free(ctx->pool, ctx->key);
+	p_free(ctx->pool, ctx->key_charset);
+	p_free(ctx->pool, ctx);
+}
+
+static void handle_header(struct message_search_context *ctx,
+			  struct message_header_line *hdr)
+{
+	if (hdr->name_len == 12 &&
+	    strcasecmp(hdr->name, "Content-Type") == 0) {
+		if (hdr->continues) {
+			hdr->use_full_value = TRUE;
+			return;
+		}
+		message_content_parse_header(hdr->full_value,
+					     hdr->full_value_len,
+					     parse_content_type, NULL, ctx);
+	}
+}
+
+static bool search_header(struct message_search_context *ctx,
+			  const struct message_header_line *hdr)
+{
+	return str_find_more(ctx->str_find_ctx,
+			     (const unsigned char *)hdr->name, hdr->name_len) ||
+		str_find_more(ctx->str_find_ctx,
+			      hdr->middle, hdr->middle_len) ||
+		str_find_more(ctx->str_find_ctx, hdr->full_value,
+			      hdr->full_value_len);
+}
+
+int message_search_more(struct message_search_context *ctx,
+			struct message_block *raw_block)
+{
+	struct message_block block;
+
+	if (raw_block->hdr != NULL) {
+		if (ctx->flags & MESSAGE_SEARCH_FLAG_SKIP_HEADERS)
+			return 0;
+
+		handle_header(ctx, raw_block->hdr);
+	} else {
+		/* body */
+		if (!ctx->content_type_text)
+			return 0;
+	}
+	if (!message_decoder_decode_next_block(ctx->decoder, raw_block, &block))
+		return 0;
+
+	return message_search_more_decoded(ctx, &block);
+}
+
+int message_search_more_decoded(struct message_search_context *ctx,
+				struct message_block *block)
+{
+	if (block->part != ctx->prev_part) {
+		/* part changes */
+		message_search_reset(ctx);
+		ctx->prev_part = block->part;
+	}
+
+	if (block->hdr != NULL) {
+		if (search_header(ctx, block->hdr))
+			return 1;
+	} else {
+		if (str_find_more(ctx->str_find_ctx, block->data, block->size))
+			return 1;
+	}
+	return 0;
+}
+
+void message_search_reset(struct message_search_context *ctx)
+{
+	/* Content-Type defaults to text/plain */
+	ctx->content_type_text = TRUE;
+
+	ctx->prev_part = NULL;
+	str_find_reset(ctx->str_find_ctx);
+}
+
+int message_search_msg(struct message_search_context *ctx,
+		       struct istream *input, const struct message_part *parts)
+{
+	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;
+	int ret = 0;
+
+	t_push();
+	message_search_reset(ctx);
+
+	if (parts != NULL) {
+		parser_ctx = message_parser_init_from_parts(
+						(struct message_part *)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 ((ret = message_search_more(ctx, &raw_block)) != 0)
+			break;
+	}
+	i_assert(ret != 0);
+	if (ret < 0 && input->stream_errno == 0)
+		ret = 0;
+	(void)message_parser_deinit(&parser_ctx);
+	t_pop();
+
+	return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-mail/message-search.h	Wed Apr 04 13:16:38 2007 +0300
@@ -0,0 +1,32 @@
+#ifndef __MESSAGE_SEARCH_H
+#define __MESSAGE_SEARCH_H
+
+struct message_block;
+struct message_part;
+struct message_search_context;
+
+enum message_search_flags {
+	/* Skip the main header and all the MIME headers. */
+	MESSAGE_SEARCH_FLAG_SKIP_HEADERS	= 0x01
+};
+
+/* Returns 1 if ok, 0 if unknown charset, -1 if key contains invalid characters
+   in given charset. */
+int message_search_init(pool_t pool, const char *key, const char *charset,
+			enum message_search_flags flags,
+			struct message_search_context **ctx_r);
+void message_search_deinit(struct message_search_context **ctx);
+
+/* Returns 1 if key is found from input buffer, 0 if not and -1 if error
+   occurred */
+int message_search_more(struct message_search_context *ctx,
+			struct message_block *raw_block);
+/* The data has already passed through decoder. */
+int message_search_more_decoded(struct message_search_context *ctx,
+				struct message_block *block);
+void message_search_reset(struct message_search_context *ctx);
+/* Search a full message. */
+int message_search_msg(struct message_search_context *ctx,
+		       struct istream *input, const struct message_part *parts);
+
+#endif
--- a/src/lib-storage/index/index-search.c	Wed Apr 04 13:14:02 2007 +0300
+++ b/src/lib-storage/index/index-search.c	Wed Apr 04 13:16:38 2007 +0300
@@ -7,8 +7,7 @@
 #include "str.h"
 #include "message-address.h"
 #include "message-date.h"
-#include "message-body-search.h"
-#include "message-header-search.h"
+#include "message-search.h"
 #include "message-parser.h"
 #include "imap-date.h"
 #include "index-storage.h"
@@ -61,11 +60,6 @@
 	const struct message_part *part;
 };
 
-struct search_arg_context {
-	struct message_header_search_context *hdr_search_ctx;
-	struct message_body_search_context *body_search_ctx;
-};
-
 static const enum message_header_parser_flags hdr_parser_flags =
 	MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE;
 
@@ -318,11 +312,13 @@
 	}
 }
 
-static struct search_arg_context *
-search_arg_context(struct index_search_context *ctx,
-		   struct mail_search_arg *arg)
+static struct message_search_context *
+msg_search_arg_context(struct index_search_context *ctx,
+		       struct mail_search_arg *arg)
 {
-	struct search_arg_context *arg_ctx = arg->context;
+	struct message_search_context *arg_ctx = arg->context;
+	enum message_search_flags flags;
+	int ret;
 
 	if (arg_ctx != NULL)
 		return arg_ctx;
@@ -330,54 +326,14 @@
 	if (ctx->search_pool == NULL)
 		ctx->search_pool = pool_alloconly_create("search pool", 8192);
 
-	arg_ctx = p_new(ctx->search_pool, struct search_arg_context, 1);
-	arg->context = arg_ctx;
-	return arg_ctx;
-}
+	flags = (arg->type == SEARCH_BODY || arg->type == SEARCH_BODY_FAST) ?
+		MESSAGE_SEARCH_FLAG_SKIP_HEADERS : 0;
 
-static struct message_header_search_context *
-search_header_context(struct index_search_context *ctx,
-		      struct mail_search_arg *arg)
-{
-	struct search_arg_context *arg_ctx;
-	int ret;
-
-	arg_ctx = search_arg_context(ctx, arg);
-	if (arg_ctx->hdr_search_ctx != NULL) {
-                message_header_search_reset(arg_ctx->hdr_search_ctx);
-		return arg_ctx->hdr_search_ctx;
-	}
-
-	ret = message_header_search_init(ctx->search_pool, arg->value.str,
-					 ctx->mail_ctx.charset,
-					 &arg_ctx->hdr_search_ctx);
+	ret = message_search_init(ctx->search_pool, arg->value.str,
+				  ctx->mail_ctx.charset, flags,
+				  &arg_ctx);
 	if (ret > 0)
-		return arg_ctx->hdr_search_ctx;
-	if (ret == 0)
-		ctx->error = TXT_UNKNOWN_CHARSET;
-	else
-		ctx->error = TXT_INVALID_SEARCH_KEY;
-	return NULL;
-}
-
-static struct message_body_search_context *
-search_body_context(struct index_search_context *ctx,
-		    struct mail_search_arg *arg)
-{
-	struct search_arg_context *arg_ctx;
-	int ret;
-
-	arg_ctx = search_arg_context(ctx, arg);
-	if (arg_ctx->body_search_ctx != NULL)
-		return arg_ctx->body_search_ctx;
-
-	ret = message_body_search_init(ctx->search_pool, arg->value.str,
-				       ctx->mail_ctx.charset,
-				       arg->type == SEARCH_TEXT ||
-				       arg->type == SEARCH_TEXT_FAST,
-				       &arg_ctx->body_search_ctx);
-	if (ret > 0)
-		return arg_ctx->body_search_ctx;
+		return arg_ctx;
 
 	if (ret == 0)
 		ctx->error = TXT_UNKNOWN_CHARSET;
@@ -389,7 +345,8 @@
 static void search_header_arg(struct mail_search_arg *arg,
 			      struct search_header_context *ctx)
 {
-        struct message_header_search_context *hdr_search_ctx;
+        struct message_search_context *msg_search_ctx;
+	struct message_block block;
 	int ret;
 
 	/* first check that the field name matches to argument. */
@@ -423,44 +380,42 @@
 
 	if (arg->value.str[0] == '\0') {
 		/* we're just testing existence of the field. always matches. */
-		ret = 1;
-	} else {
-		if (ctx->hdr->continues) {
-			ctx->hdr->use_full_value = TRUE;
-			return;
-		}
+		ARG_SET_RESULT(arg, 1);
+		return;
+	}
+
+	if (ctx->hdr->continues) {
+		ctx->hdr->use_full_value = TRUE;
+		return;
+	}
+
+	memset(&block, 0, sizeof(block));
+	msg_search_ctx = msg_search_arg_context(ctx->index_context, arg);
+	if (msg_search_ctx == NULL)
+		ret = 0;
+	else if (arg->type == SEARCH_HEADER_ADDRESS) {
+		/* we have to match against normalized address */
+		struct message_address *addr;
+		string_t *str;
 
 		t_push();
-
-		hdr_search_ctx = search_header_context(ctx->index_context, arg);
-		if (hdr_search_ctx == NULL)
-			ret = 0;
-		else if (arg->type == SEARCH_HEADER_ADDRESS) {
-			/* we have to match against normalized address */
-			struct message_address *addr;
-			string_t *str;
-
-			addr = message_address_parse(pool_datastack_create(),
-						     ctx->hdr->full_value,
-						     ctx->hdr->full_value_len,
-						     (unsigned int)-1, TRUE);
-			str = t_str_new(ctx->hdr->value_len);
-			message_address_write(str, addr);
-			ret = message_header_search(hdr_search_ctx,
-						    str_data(str),
-						    str_len(str)) ? 1 : 0;
-		} else {
-			if (message_header_search(hdr_search_ctx,
-						  ctx->hdr->full_value,
-						  ctx->hdr->full_value_len))
-				ret = 1;
-			else
-				ret = 0;
-		}
+		addr = message_address_parse(pool_datastack_create(),
+					     ctx->hdr->full_value,
+					     ctx->hdr->full_value_len,
+					     (unsigned int)-1, TRUE);
+		str = t_str_new(ctx->hdr->value_len);
+		message_address_write(str, addr);
+		block.data = str_data(str);
+		block.size = str_len(str);
+		ret = message_search_more_decoded(msg_search_ctx, &block);
 		t_pop();
+	} else {
+		block.data = ctx->hdr->full_value;
+		block.size = ctx->hdr->full_value_len;
+		ret = message_search_more_decoded(msg_search_ctx, &block);
 	}
 
-	if (ret == 1 ||
+	if (ret > 0 ||
 	    (arg->type != SEARCH_HEADER &&
 	     arg->type != SEARCH_HEADER_ADDRESS)) {
 		/* set only when we definitely know if it's a match */
@@ -516,7 +471,7 @@
 static void search_body(struct mail_search_arg *arg,
 			struct search_body_context *ctx)
 {
-	struct message_body_search_context *body_search_ctx;
+	struct message_search_context *msg_search_ctx;
 	int ret;
 
 	if (ctx->index_ctx->error != NULL)
@@ -532,14 +487,14 @@
 		return;
 	}
 
-	body_search_ctx = search_body_context(ctx->index_ctx, arg);
-	if (body_search_ctx == NULL) {
+	msg_search_ctx = msg_search_arg_context(ctx->index_ctx, arg);
+	if (msg_search_ctx == NULL) {
 		ARG_SET_RESULT(arg, 0);
 		return;
 	}
 
 	i_stream_seek(ctx->input, 0);
-	ret = message_body_search(body_search_ctx, ctx->input, ctx->part);
+	ret = message_search_msg(msg_search_ctx, ctx->input, ctx->part);
 	if (ret < 0) {
 		mail_cache_set_corrupted(ctx->index_ctx->ibox->cache,
 			"Broken message structure for mail UID %u",
@@ -547,11 +502,9 @@
 
 		/* get the body parts, and try again */
 		ctx->index_ctx->imail->data.parts = NULL;
-		ctx->part = mail_get_parts(ctx->index_ctx->mail);
 
 		i_stream_seek(ctx->input, 0);
-		ret = message_body_search(body_search_ctx,
-					  ctx->input, ctx->part);
+		ret = message_search_msg(msg_search_ctx, ctx->input, NULL);
 		if (ret < 0)
 			i_panic("Couldn't fix broken body structure");
 	}