# HG changeset patch # User Timo Sirainen # Date 1043127392 -7200 # Node ID 9c8df18fb2a9324b5dba7f3d63dbb038cbcf61f4 # Parent e6a7afe4cca717ddf09e0bb0db9f6b9b0ec35428 Forgot to add diff -r e6a7afe4cca7 -r 9c8df18fb2a9 src/lib-storage/index/index-mail.c --- /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 + +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; +} diff -r e6a7afe4cca7 -r 9c8df18fb2a9 src/lib-storage/index/index-mail.h --- /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