changeset 990:9c8df18fb2a9 HEAD

Forgot to add
author Timo Sirainen <tss@iki.fi>
date Tue, 21 Jan 2003 07:36:32 +0200
parents e6a7afe4cca7
children 21788a1e9e39
files src/lib-storage/index/index-mail.c src/lib-storage/index/index-mail.h
diffstat 2 files changed, 844 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/index/index-mail.c	Tue Jan 21 07:36:32 2003 +0200
@@ -0,0 +1,786 @@
+/* Copyright (C) 2002 Timo Sirainen */
+
+#include "lib.h"
+#include "istream.h"
+#include "message-address.h"
+#include "message-date.h"
+#include "message-part-serialize.h"
+#include "imap-bodystructure.h"
+#include "imap-envelope.h"
+#include "mail-index.h"
+#include "mail-index-util.h"
+#include "mail-custom-flags.h"
+#include "index-storage.h"
+#include "index-mail.h"
+
+#include <ctype.h>
+
+static int get_envelope_header_field(const char *name,
+				     enum imap_envelope_field *ret)
+{
+	*ret = (enum imap_envelope_field)-1;
+
+	switch (i_toupper(*name)) {
+	case 'B':
+		if (strcasecmp(name, "bcc") == 0)
+			*ret = IMAP_ENVELOPE_BCC;
+		break;
+	case 'C':
+		if (strcasecmp(name, "cc") == 0)
+			*ret = IMAP_ENVELOPE_CC;
+		break;
+	case 'D':
+		if (strcasecmp(name, "date") == 0)
+			*ret = IMAP_ENVELOPE_DATE;
+		break;
+	case 'F':
+		if (strcasecmp(name, "from") == 0)
+			*ret = IMAP_ENVELOPE_FROM;
+		break;
+	case 'I':
+		if (strcasecmp(name, "in-reply-to") == 0)
+			*ret = IMAP_ENVELOPE_IN_REPLY_TO;
+		break;
+	case 'M':
+		if (strcasecmp(name, "message-id") == 0)
+			*ret = IMAP_ENVELOPE_MESSAGE_ID;
+		break;
+	case 'R':
+		if (strcasecmp(name, "reply-to") == 0)
+			*ret = IMAP_ENVELOPE_REPLY_TO;
+		break;
+	case 'S':
+		if (strcasecmp(name, "subject") == 0)
+			*ret = IMAP_ENVELOPE_SUBJECT;
+		if (strcasecmp(name, "sender") == 0)
+			*ret = IMAP_ENVELOPE_SENDER;
+		break;
+	case 'T':
+		if (strcasecmp(name, "to") == 0)
+			*ret = IMAP_ENVELOPE_TO;
+		break;
+	}
+
+	return *ret != (enum imap_envelope_field)-1;
+}
+
+static struct message_part *get_cached_parts(struct index_mail *mail)
+{
+	struct message_part *part;
+	const void *part_data;
+	const char *error;
+	size_t part_size;
+
+	part_data = mail->ibox->index->
+		lookup_field_raw(mail->ibox->index, mail->data.rec,
+				 DATA_FIELD_MESSAGEPART, &part_size);
+	if (part_data == NULL) {
+		mail->ibox->index->cache_fields_later(mail->ibox->index,
+						      DATA_FIELD_MESSAGEPART);
+		return NULL;
+	}
+
+	part = message_part_deserialize(mail->pool, part_data, part_size,
+					&error);
+	if (part == NULL) {
+		index_set_corrupted(mail->ibox->index,
+			"Corrupted cached message_part data (%s)", error);
+		return NULL;
+	}
+
+	return part;
+}
+
+static char *get_cached_field(struct index_mail *mail,
+			      enum mail_data_field field)
+{
+	const char *ret;
+
+	ret = mail->ibox->index->lookup_field(mail->ibox->index,
+					      mail->data.rec, field);
+	if (ret == NULL)
+		mail->ibox->index->cache_fields_later(mail->ibox->index, field);
+	return p_strdup(mail->pool, ret);
+}
+
+static uoff_t get_cached_uoff_t(struct index_mail *mail,
+				enum mail_data_field field,
+				const char *field_name)
+{
+	const uoff_t *uoff_p;
+	size_t size;
+
+	uoff_p = mail->ibox->index->
+		lookup_field_raw(mail->ibox->index, mail->data.rec,
+				 field, &size);
+
+	if (uoff_p == NULL)
+		mail->ibox->index->cache_fields_later(mail->ibox->index, field);
+	else if (size != sizeof(*uoff_p)) {
+		index_set_corrupted(mail->ibox->index,
+				    "Corrupted cached %s", field_name);
+		uoff_p = NULL;
+	}
+
+	return uoff_p == NULL ? (uoff_t)-1 : *uoff_p;
+}
+
+static uoff_t get_cached_virtual_size(struct index_mail *mail)
+{
+	return get_cached_uoff_t(mail, DATA_HDR_VIRTUAL_SIZE, "virtual size");
+}
+
+static time_t get_cached_received_date(struct index_mail *mail)
+{
+	const time_t *time_p;
+	size_t size;
+
+	time_p = mail->ibox->index->
+		lookup_field_raw(mail->ibox->index, mail->data.rec,
+				 DATA_HDR_INTERNAL_DATE, &size);
+
+	if (time_p == NULL) {
+		mail->ibox->index->cache_fields_later(mail->ibox->index,
+						      DATA_HDR_INTERNAL_DATE);
+	} else if (size != sizeof(*time_p)) {
+		index_set_corrupted(mail->ibox->index,
+				    "Corrupted cached received time");
+		time_p = NULL;
+	}
+
+	return time_p == NULL ? (time_t)-1 : *time_p;
+}
+
+static int open_stream(struct index_mail *mail, uoff_t position)
+{
+	int deleted;
+
+	if (mail->data.stream == NULL) {
+		mail->data.stream = mail->ibox->index->
+			open_mail(mail->ibox->index, mail->data.rec,
+				  &mail->data.received_date, &deleted);
+
+		if (mail->data.stream == NULL)
+			return FALSE;
+	}
+
+	i_stream_seek(mail->data.stream, position);
+	return TRUE;
+}
+
+static void prepend_cached_header(struct index_mail *mail, const char *name)
+{
+	struct cached_header *hdr;
+
+	hdr = p_new(mail->pool, struct cached_header, 1);
+	hdr->name = name;
+	hdr->name_len = strlen(name);
+
+	hdr->next = mail->data.headers;
+	mail->data.headers = hdr;
+}
+
+void index_mail_init_parse_header(struct index_mail *mail)
+{
+	const char *const *tmp;
+
+	if (mail->wanted_headers != NULL) {
+		for (tmp = mail->wanted_headers; *tmp != NULL; tmp++)
+			prepend_cached_header(mail, *tmp);
+	}
+}
+
+void index_mail_parse_header(struct message_part *part __attr_unused__,
+			     const unsigned char *name, size_t name_len,
+			     const unsigned char *value, size_t value_len,
+			     void *context)
+{
+	struct index_mail *mail = context;
+	struct index_mail_data *data = &mail->data;
+	struct cached_header *hdr;
+
+	if (data->save_envelope) {
+		imap_envelope_parse_header(mail->pool, &data->envelope_data,
+					   name, name_len, value, value_len);
+	}
+
+	if (name_len == 4 && data->save_sent_time &&
+	    memcasecmp(name, "date",4) == 0) {
+		if (!message_date_parse(value, value_len, &data->sent_time,
+					&data->sent_timezone)) {
+			/* 0 == parse error */
+			data->sent_time = 0;
+			data->sent_timezone = 0;
+		}
+		data->save_sent_time = FALSE;
+	}
+
+	if (name_len == 0) {
+		/* end of headers */
+		if (data->save_sent_time) {
+			/* not found */
+			data->sent_time = 0;
+			data->sent_timezone = 0;
+			data->save_sent_time = FALSE;
+		}
+	}
+
+	for (hdr = data->headers; hdr != NULL; hdr = hdr->next) {
+		if (hdr->name_len == name_len &&
+		    memcasecmp(hdr->name, name, name_len) == 0) {
+			/* save only the first header */
+			if (hdr->value == NULL) {
+				hdr->value = p_strndup(mail->pool,
+						       value, value_len);
+			}
+			break;
+		}
+	}
+}
+
+static int parse_header(struct index_mail *mail)
+{
+	if (!open_stream(mail, 0))
+		return FALSE;
+
+        index_mail_init_parse_header(mail);
+	message_parse_header(NULL, mail->data.stream, &mail->data.hdr_size,
+			     index_mail_parse_header, mail);
+	mail->data.parse_header = FALSE;
+	mail->data.hdr_size_set = TRUE;
+
+	return TRUE;
+}
+
+static const struct mail_full_flags *get_flags(struct mail *_mail)
+{
+	struct index_mail *mail = (struct index_mail *) _mail;
+	struct index_mail_data *data = &mail->data;
+
+	data->flags.flags = data->rec->msg_flags;
+	data->flags.custom_flags =
+		mail_custom_flags_list_get(mail->ibox->index->custom_flags);
+	data->flags.custom_flags_count = MAIL_CUSTOM_FLAGS_COUNT;
+
+	if (data->rec->uid >= mail->ibox->index->first_recent_uid)
+		data->flags.flags |= MAIL_RECENT;
+
+	return &data->flags;
+}
+
+static const struct message_part *get_parts(struct mail *_mail)
+{
+	struct index_mail *mail = (struct index_mail *) _mail;
+	struct index_mail_data *data = &mail->data;
+
+	if (data->parts != NULL)
+		return data->parts;
+
+	if ((mail->wanted_fields & MAIL_FETCH_MESSAGE_PARTS) == 0) {
+		data->parts = get_cached_parts(mail);
+		if (data->parts != NULL)
+			return data->parts;
+	}
+
+	if (!open_stream(mail, 0))
+		return NULL;
+
+        index_mail_init_parse_header(mail);
+	data->parts = message_parse(mail->pool, data->stream,
+				    index_mail_parse_header, mail);
+	return data->parts;
+}
+
+static time_t get_received_date(struct mail *_mail)
+{
+	struct index_mail *mail = (struct index_mail *) _mail;
+	struct index_mail_data *data = &mail->data;
+
+	if (data->received_date != (time_t)-1)
+		return data->received_date;
+
+	if ((mail->wanted_fields & MAIL_FETCH_RECEIVED_DATE) == 0) {
+		data->received_date = get_cached_received_date(mail);
+		if (data->received_date != (time_t)-1)
+			return data->received_date;
+	}
+
+	data->received_date = mail->ibox->index->
+		get_internal_date(mail->ibox->index, mail->data.rec);
+	return data->received_date;
+}
+
+static time_t get_date(struct mail *_mail, int *timezone)
+{
+	struct index_mail *mail = (struct index_mail *) _mail;
+	struct index_mail_data *data = &mail->data;
+	const char *result;
+
+	if (data->sent_time != (time_t)-1) {
+		if (timezone != NULL)
+			*timezone = data->sent_timezone;
+		return data->sent_time;
+	}
+
+	if (data->parse_header || data->envelope == NULL) {
+		data->save_sent_time = TRUE;
+		parse_header(mail);
+	} else {
+		if (!imap_envelope_parse(data->envelope,
+					 IMAP_ENVELOPE_DATE,
+					 IMAP_ENVELOPE_RESULT_TYPE_STRING,
+					 &result))
+			return (time_t)-1;
+
+		if (!message_date_parse((const unsigned char *) result,
+					(size_t)-1, &data->sent_time,
+					&data->sent_timezone))
+			data->sent_time = 0;
+	}
+
+	if (timezone != NULL)
+		*timezone = data->sent_timezone;
+	return data->sent_time;
+}
+
+static int get_msgpart_sizes(struct index_mail *mail)
+{
+	struct index_mail_data *data = &mail->data;
+
+	if ((mail->wanted_fields & MAIL_FETCH_MESSAGE_PARTS) != 0)
+		(void)get_parts(&mail->mail);
+
+	if (data->parts == NULL)
+		data->parts = get_cached_parts(mail);
+
+	if (data->parts != NULL) {
+		data->hdr_size = data->parts->header_size;
+		data->body_size = data->parts->body_size;
+		data->hdr_size_set = TRUE;
+		data->body_size_set = TRUE;
+	}
+
+	return data->parts != NULL;
+}
+
+static void get_binary_sizes(struct index_mail *mail)
+{
+	uoff_t size;
+
+	if (!mail->data.hdr_size_set &&
+	    (mail->data.rec->index_flags & INDEX_MAIL_FLAG_BINARY_HEADER)) {
+		size = get_cached_uoff_t(mail, DATA_HDR_HEADER_SIZE,
+					 "header size");
+		if (size != (uoff_t)-1) {
+			mail->data.hdr_size.physical_size =
+				mail->data.hdr_size.virtual_size = size;
+			mail->data.hdr_size_set = TRUE;
+		}
+	}
+
+	if (!mail->data.body_size_set &&
+	    (mail->data.rec->index_flags & INDEX_MAIL_FLAG_BINARY_BODY)) {
+		size = get_cached_uoff_t(mail, DATA_HDR_BODY_SIZE, "body size");
+		if (size != (uoff_t)-1) {
+			mail->data.body_size.physical_size =
+				mail->data.body_size.virtual_size = size;
+			mail->data.body_size_set = TRUE;
+		}
+	}
+}
+
+static uoff_t get_size(struct mail *_mail)
+{
+	struct index_mail *mail = (struct index_mail *) _mail;
+	struct index_mail_data *data = &mail->data;
+	uoff_t hdr_size, body_size;
+
+	if (data->size != (uoff_t)-1)
+		return data->size;
+
+	if ((mail->wanted_fields & MAIL_FETCH_SIZE) == 0) {
+		data->size = get_cached_virtual_size(mail);
+		if (data->size != (uoff_t)-1)
+			return data->size;
+	}
+
+	if (!get_msgpart_sizes(mail)) {
+		if (data->parse_header)
+			parse_header(mail);
+	}
+
+	hdr_size = data->hdr_size_set ?
+		data->hdr_size.virtual_size : (uoff_t)-1;
+	body_size = data->body_size_set ?
+		data->body_size.virtual_size : (uoff_t)-1;
+
+	if (body_size != (uoff_t)-1 && hdr_size != (uoff_t)-1) {
+		data->size = hdr_size + body_size;
+		return data->size;
+	}
+
+	/* maybe it's binary */
+	get_binary_sizes(mail);
+	if (data->hdr_size_set && hdr_size == (uoff_t)-1)
+		hdr_size = data->hdr_size.virtual_size;
+	if (data->body_size_set && body_size == (uoff_t)-1)
+		body_size = data->body_size.virtual_size;
+
+	if (body_size != (uoff_t)-1 && hdr_size != (uoff_t)-1) {
+		data->size = hdr_size + body_size;
+		return data->size;
+	}
+
+	/* have to parse, slow.. */
+	if (!open_stream(mail, hdr_size != (uoff_t)-1 ? hdr_size : 0))
+		return (uoff_t)-1;
+
+	if (hdr_size == (uoff_t)-1) {
+		message_get_header_size(data->stream, &data->hdr_size);
+		hdr_size = data->hdr_size.virtual_size;
+		data->hdr_size_set = TRUE;
+	}
+	if (body_size == (uoff_t)-1) {
+		message_get_body_size(data->stream, &data->body_size,
+				      (uoff_t)-1, NULL);
+		body_size = data->body_size.virtual_size;
+		data->body_size_set = TRUE;
+	}
+
+	data->size = hdr_size + body_size;
+	return data->size;
+}
+
+static const char *get_header(struct mail *_mail, const char *field)
+{
+	struct index_mail *mail = (struct index_mail *) _mail;
+	struct index_mail_data *data = &mail->data;
+	struct cached_header *hdr;
+	enum imap_envelope_field env_field = 0;
+	const char *str;
+	char *ret;
+
+	for (hdr = data->headers; hdr != NULL; hdr = hdr->next) {
+		if (strcasecmp(hdr->name, field) == 0)
+			return hdr->value;
+	}
+
+	if (data->parse_header || data->envelope == NULL ||
+	    !get_envelope_header_field(field, &env_field)) {
+		/* if we have to parse the header, do it even if we could use
+		   envelope - envelope parsing would just slow up. */
+                prepend_cached_header(mail, field);
+		parse_header(mail);
+
+		for (hdr = data->headers; hdr != NULL; hdr = hdr->next) {
+			if (strcasecmp(hdr->name, field) == 0)
+				return hdr->value;
+		}
+
+		return NULL;
+	} else {
+		t_push();
+		if (!imap_envelope_parse(data->envelope, env_field,
+					 IMAP_ENVELOPE_RESULT_TYPE_STRING,
+					 &str))
+			str = NULL;
+		ret = p_strdup(mail->pool, str);
+		t_pop();
+		return ret;
+	}
+}
+
+static const struct message_address *
+get_address(struct mail *_mail, const char *field)
+{
+	struct index_mail *mail = (struct index_mail *) _mail;
+	const char *str;
+
+	/* don't bother with checking envelope - we're most likely
+	   creating it */
+	str = get_header(_mail, field);
+	if (str == NULL)
+		return NULL;
+
+	return message_address_parse(mail->pool, str, (size_t)-1, 1);
+}
+
+static const char *get_first_mailbox(struct mail *_mail, const char *field)
+{
+	struct index_mail *mail = (struct index_mail *) _mail;
+	struct index_mail_data *data = &mail->data;
+	enum imap_envelope_field env_field;
+	const char *str;
+	const char *ret = NULL;
+
+	if (data->envelope != NULL &&
+	    get_envelope_header_field(field, &env_field)) {
+		/* prefer parsing envelope - faster than having to actually
+		   parse the header field */
+		t_push();
+		if (!imap_envelope_parse(data->envelope, env_field,
+					IMAP_ENVELOPE_RESULT_TYPE_FIRST_MAILBOX,
+					&str))
+			str = NULL;
+		ret = p_strdup(mail->pool, str);
+		t_pop();
+	} else {
+		struct message_address *addr;
+
+		str = get_header(_mail, field);
+		if (str == NULL)
+			return NULL;
+
+		addr = message_address_parse(mail->pool, str,
+					     (size_t)-1, 1);
+		if (addr != NULL)
+			ret = addr->mailbox;
+	}
+
+	return ret;
+}
+
+static struct istream *get_stream(struct mail *_mail,
+				  struct message_size *hdr_size,
+				  struct message_size *body_size)
+{
+	struct index_mail *mail = (struct index_mail *) _mail;
+	struct index_mail_data *data = &mail->data;
+
+	if (!open_stream(mail, 0))
+		return NULL;
+
+	if (hdr_size != NULL || body_size != NULL) {
+		if (!get_msgpart_sizes(mail))
+			get_binary_sizes(mail);
+	}
+
+	if (hdr_size != NULL) {
+		if (!data->hdr_size_set) {
+			message_get_header_size(data->stream, &data->hdr_size);
+			data->hdr_size_set = TRUE;
+		}
+
+		*hdr_size = data->hdr_size;
+	}
+
+	if (body_size != NULL) {
+		if (!data->body_size_set) {
+			i_stream_seek(data->stream,
+				      data->hdr_size.physical_size);
+
+			message_get_body_size(data->stream, &data->body_size,
+					      (uoff_t)-1, NULL);
+			data->body_size_set = TRUE;
+		}
+
+		*body_size = data->body_size;
+	}
+
+	i_stream_seek(data->stream, 0);
+	return data->stream;
+}
+
+static const char *get_special(struct mail *_mail, enum mail_fetch_field field)
+{
+	struct index_mail *mail = (struct index_mail *) _mail;
+	struct index_mail_data *data = &mail->data;
+	char *str;
+
+	switch (field) {
+	case MAIL_FETCH_IMAP_BODY:
+		if (data->body != NULL)
+			return data->body;
+		/* fall through */
+	case MAIL_FETCH_IMAP_BODYSTRUCTURE:
+		if (data->bodystructure != NULL) {
+			if (field == MAIL_FETCH_IMAP_BODYSTRUCTURE)
+				return data->bodystructure;
+
+			/* create BODY from cached BODYSTRUCTURE */
+			t_push();
+			data->body = p_strdup(mail->pool,
+				imap_body_parse_from_bodystructure(
+							data->bodystructure));
+			t_pop();
+			return data->body;
+		}
+
+		if (data->parts == NULL)
+			data->parts = get_cached_parts(mail);
+
+		t_push();
+		str = p_strdup(mail->pool, imap_part_get_bodystructure(
+				mail->pool, &data->parts, data->stream,
+				field == MAIL_FETCH_IMAP_BODYSTRUCTURE));
+		t_pop();
+
+		if (field == MAIL_FETCH_IMAP_BODYSTRUCTURE)
+			data->bodystructure = str;
+		else
+			data->body = str;
+		return str;
+	case MAIL_FETCH_IMAP_ENVELOPE:
+		if (data->envelope != NULL)
+			return data->envelope;
+
+		if ((mail->wanted_fields & MAIL_FETCH_IMAP_ENVELOPE) == 0) {
+			data->envelope = p_strdup(mail->pool,
+				get_cached_field(mail, DATA_FIELD_ENVELOPE));
+			if (data->envelope != NULL)
+				return data->envelope;
+		}
+
+		data->save_envelope = TRUE;
+		parse_header(mail);
+		return data->envelope;
+	default:
+		i_unreached();
+		return NULL;
+	}
+}
+
+static struct mail index_mail = {
+	0, 0, 0,
+
+	get_flags,
+	get_parts,
+	get_received_date,
+	get_date,
+	get_size,
+	get_header,
+	get_address,
+	get_first_mailbox,
+	get_stream,
+	get_special
+};
+
+void index_mail_init(struct index_mailbox *ibox, struct index_mail *mail,
+		     enum mail_fetch_field wanted_fields,
+		     const char *const wanted_headers[])
+{
+	mail->mail = index_mail;
+	mail->pool = pool_alloconly_create("index_mail", 4096);
+
+	mail->ibox = ibox;
+	mail->wanted_fields = wanted_fields;
+	mail->wanted_headers = wanted_headers;
+}
+
+int index_mail_next(struct index_mail *mail, struct mail_index_record *rec)
+{
+	struct index_mail_data *data = &mail->data;
+	int open_mail, parse_header;
+
+	/* close the old one */
+	if (data->stream != NULL)
+		i_stream_unref(data->stream);
+
+	memset(data, 0, sizeof(*data));
+	p_clear(mail->pool);
+
+	data->rec = rec;
+	data->size = (uoff_t)-1;
+	data->received_date = data->sent_time = (time_t)-1;
+
+	/* if some wanted fields are cached, get them */
+	if (mail->wanted_fields & MAIL_FETCH_MESSAGE_PARTS)
+		data->parts = get_cached_parts(mail);
+	if (mail->wanted_fields & MAIL_FETCH_IMAP_ENVELOPE)
+		data->envelope = get_cached_field(mail, DATA_FIELD_ENVELOPE);
+	if (mail->wanted_fields & MAIL_FETCH_IMAP_BODY)
+		data->body = get_cached_field(mail, DATA_FIELD_BODY);
+	if (mail->wanted_fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) {
+		data->bodystructure =
+			get_cached_field(mail, DATA_FIELD_BODYSTRUCTURE);
+	}
+	if (mail->wanted_fields & MAIL_FETCH_SIZE)
+		data->size = get_cached_virtual_size(mail);
+
+	/* see if we have to parse the message */
+	open_mail = parse_header = FALSE;
+	if ((mail->wanted_fields & MAIL_FETCH_MESSAGE_PARTS) &&
+	    data->parts == NULL)
+		parse_header = TRUE;
+	else if ((mail->wanted_fields & (MAIL_FETCH_DATE |
+					 MAIL_FETCH_IMAP_ENVELOPE)) &&
+		 data->envelope == NULL)
+		parse_header = TRUE;
+	else if ((mail->wanted_fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) &&
+		 data->bodystructure == NULL) {
+		if (data->parts == NULL)
+			data->parts = get_cached_parts(mail);
+		/* FIXME: this isn't helping really.. */
+		open_mail = TRUE;
+		parse_header = data->parts == NULL;
+	} else if ((mail->wanted_fields & MAIL_FETCH_IMAP_BODY) &&
+		   data->body == NULL && data->bodystructure == NULL) {
+		if (data->parts == NULL)
+			data->parts = get_cached_parts(mail);
+		open_mail = TRUE;
+		parse_header = data->parts == NULL;
+	} else if (mail->wanted_fields & (MAIL_FETCH_STREAM_HEADER |
+					  MAIL_FETCH_STREAM_BODY))
+		open_mail = TRUE;
+	else if ((mail->wanted_fields & MAIL_FETCH_SIZE) && data->size == 0)
+		open_mail = TRUE;
+
+	if (!parse_header && mail->wanted_headers != NULL) {
+		const char *const *tmp;
+		enum imap_envelope_field env_field;
+		int envelope_headers = FALSE;
+
+		for (tmp = mail->wanted_headers; *tmp != NULL; tmp++) {
+			if (get_envelope_header_field(*tmp, &env_field))
+				envelope_headers = TRUE;
+			else {
+				open_mail = TRUE;
+				parse_header = TRUE;
+				break;
+			}
+		}
+
+		if (!parse_header && envelope_headers &&
+		    data->envelope == NULL) {
+			data->envelope =
+				get_cached_field(mail, DATA_FIELD_ENVELOPE);
+			if (data->envelope == NULL)
+				parse_header = TRUE;
+		}
+	}
+
+	if (open_mail || parse_header) {
+		int deleted;
+
+		data->stream = mail->ibox->index->
+			open_mail(mail->ibox->index, data->rec,
+				  &data->received_date, &deleted);
+		if (data->stream == NULL)
+			return deleted ? 0 : -1;
+	}
+
+	if ((mail->wanted_fields & MAIL_FETCH_RECEIVED_DATE) &&
+	    data->received_date == (time_t)-1) {
+		/* check this only after open_mail() */
+		data->received_date = get_cached_received_date(mail);
+	}
+
+	if (mail->wanted_fields & MAIL_FETCH_DATE)
+		data->save_sent_time = TRUE;
+	if (mail->wanted_fields & MAIL_FETCH_IMAP_ENVELOPE)
+		data->save_envelope = TRUE;
+
+	data->parse_header = parse_header;
+	return 1;
+}
+
+void index_mail_deinit(struct index_mail *mail)
+{
+	if (mail->data.stream != NULL) {
+		i_stream_unref(mail->data.stream);
+		mail->data.stream = NULL;
+	}
+
+	pool_unref(mail->pool);
+	mail->pool = NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/index/index-mail.h	Tue Jan 21 07:36:32 2003 +0200
@@ -0,0 +1,58 @@
+#ifndef __INDEX_MAIL_H
+#define __INDEX_MAIL_H
+
+struct cached_header {
+	struct cached_header *next;
+
+	size_t name_len;
+	const char *name, *value;
+};
+
+struct index_mail_data {
+	struct mail_full_flags flags;
+	time_t received_date;
+	uoff_t size;
+
+	time_t sent_time;
+	int sent_timezone;
+
+	struct cached_header *headers;
+	struct message_part *parts;
+	char *envelope, *body, *bodystructure;
+        struct message_part_envelope_data *envelope_data;
+
+	struct mail_index_record *rec;
+	struct istream *stream;
+        struct message_size hdr_size, body_size;
+
+	unsigned int parse_header:1;
+	unsigned int save_sent_time:1;
+	unsigned int save_envelope:1;
+	unsigned int hdr_size_set:1;
+	unsigned int body_size_set:1;
+};
+
+struct index_mail {
+	struct mail mail;
+	struct index_mail_data data;
+
+	pool_t pool;
+	struct index_mailbox *ibox;
+
+	enum mail_fetch_field wanted_fields;
+	const char *const *wanted_headers;
+};
+
+void index_mail_init(struct index_mailbox *ibox, struct index_mail *mail,
+		     enum mail_fetch_field wanted_fields,
+		     const char *const wanted_headers[]);
+int index_mail_next(struct index_mail *mail, struct mail_index_record *rec);
+void index_mail_deinit(struct index_mail *mail);
+
+void index_mail_init_parse_header(struct index_mail *mail);
+void index_mail_parse_header(struct message_part *part,
+			     const unsigned char *name, size_t name_len,
+			     const unsigned char *value, size_t value_len,
+			     void *context);
+
+#endif