Mercurial > dovecot > core-2.2
view src/lib-storage/index/index-mail.c @ 3863:55df57c028d4 HEAD
Added "bool" type and changed all ints that were used as booleans to bool.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 13 Jan 2006 22:25:57 +0200 |
parents | 7a94871543f5 |
children | 928229f8b3e6 |
line wrap: on
line source
/* Copyright (C) 2002-2003 Timo Sirainen */ #include "lib.h" #include "array.h" #include "buffer.h" #include "istream.h" #include "hex-binary.h" #include "str.h" #include "message-date.h" #include "message-part-serialize.h" #include "message-parser.h" #include "imap-bodystructure.h" #include "imap-envelope.h" #include "mail-cache.h" #include "index-storage.h" #include "index-mail.h" struct mail_cache_field global_cache_fields[MAIL_CACHE_FIELD_COUNT] = { { "flags", 0, MAIL_CACHE_FIELD_BITMASK, sizeof(uint32_t), 0 }, { "date.sent", 0, MAIL_CACHE_FIELD_FIXED_SIZE, sizeof(struct mail_sent_date), 0 }, { "date.received", 0, MAIL_CACHE_FIELD_FIXED_SIZE, sizeof(time_t), 0 }, { "size.virtual", 0, MAIL_CACHE_FIELD_FIXED_SIZE, sizeof(uoff_t), 0 }, { "size.physical", 0, MAIL_CACHE_FIELD_FIXED_SIZE, sizeof(uoff_t), 0 }, { "imap.body", 0, MAIL_CACHE_FIELD_STRING, 0, 0 }, { "imap.bodystructure", 0, MAIL_CACHE_FIELD_STRING, 0, 0 }, { "imap.envelope", 0, MAIL_CACHE_FIELD_STRING, 0, 0 }, { "mime.parts", 0, MAIL_CACHE_FIELD_VARIABLE_SIZE, 0, 0 } }; static void index_mail_parse_body(struct index_mail *mail, bool need_parts); static bool get_cached_parts(struct index_mail *mail) { struct mail_cache_field *cache_fields = mail->ibox->cache_fields; struct message_part *part; buffer_t *part_buf; const char *error; t_push(); part_buf = buffer_create_dynamic(pool_datastack_create(), 128); if (mail_cache_lookup_field(mail->trans->cache_view, part_buf, mail->data.seq, cache_fields[MAIL_CACHE_MESSAGEPART].idx) <= 0) { t_pop(); return FALSE; } part = message_part_deserialize(mail->data_pool, part_buf->data, part_buf->used, &error); t_pop(); if (part == NULL) { mail_cache_set_corrupted(mail->ibox->cache, "Corrupted cached message_part data (%s)", error); return FALSE; } /* we know the NULs now, update them */ if ((part->flags & MESSAGE_PART_FLAG_HAS_NULS) != 0) { mail->mail.mail.has_nuls = TRUE; mail->mail.mail.has_no_nuls = FALSE; } else { mail->mail.mail.has_nuls = FALSE; mail->mail.mail.has_no_nuls = TRUE; } mail->data.parts = part; return TRUE; } const char *index_mail_get_cached_string(struct index_mail *mail, enum index_cache_field field) { string_t *str; str = str_new(mail->data_pool, 32); if (mail_cache_lookup_field(mail->trans->cache_view, str, mail->data.seq, mail->ibox->cache_fields[field].idx) <= 0) { p_free(mail->data_pool, str); return NULL; } return str_c(str); } static bool index_mail_get_fixed_field(struct index_mail *mail, enum index_cache_field field, void *data, size_t data_size) { buffer_t *buf; int ret; t_push(); buf = buffer_create_data(pool_datastack_create(), data, data_size); if (mail_cache_lookup_field(mail->trans->cache_view, buf, mail->data.seq, mail->ibox->cache_fields[field].idx) <= 0) { ret = FALSE; } else { i_assert(buffer_get_used_size(buf) == data_size); ret = TRUE; } t_pop(); return ret; } uoff_t index_mail_get_cached_uoff_t(struct index_mail *mail, enum index_cache_field field) { uoff_t uoff; if (!index_mail_get_fixed_field(mail, mail->ibox->cache_fields[field].idx, &uoff, sizeof(uoff))) uoff = (uoff_t)-1; return uoff; } uoff_t index_mail_get_cached_virtual_size(struct index_mail *mail) { return index_mail_get_cached_uoff_t(mail, MAIL_CACHE_VIRTUAL_FULL_SIZE); } static uoff_t index_mail_get_cached_physical_size(struct index_mail *mail) { return index_mail_get_cached_uoff_t(mail, MAIL_CACHE_PHYSICAL_FULL_SIZE); } time_t index_mail_get_cached_received_date(struct index_mail *mail) { time_t t; if (!index_mail_get_fixed_field(mail, MAIL_CACHE_RECEIVED_DATE, &t, sizeof(t))) t = (time_t)-1; return t; } enum mail_flags index_mail_get_flags(struct mail *_mail) { struct index_mail *mail = (struct index_mail *) _mail; struct index_mail_data *data = &mail->data; data->flags = data->rec->flags & MAIL_FLAGS_MASK; if (index_mailbox_is_recent(mail->ibox, data->seq)) data->flags |= MAIL_RECENT; return data->flags; } const char *const *index_mail_get_keywords(struct mail *_mail) { struct index_mail *mail = (struct index_mail *) _mail; struct index_mail_data *data = &mail->data; array_t ARRAY_DEFINE(keyword_indexes_arr, unsigned int); const char *const *names; const unsigned int *keyword_indexes; unsigned int i, count, names_count; if (array_is_created(&data->keywords)) return array_get(&data->keywords, NULL); t_push(); ARRAY_CREATE(&keyword_indexes_arr, pool_datastack_create(), unsigned int, 128); if (mail_index_lookup_keywords(mail->ibox->view, mail->data.seq, &keyword_indexes_arr) < 0) { mail_storage_set_index_error(mail->ibox); t_pop(); return NULL; } keyword_indexes = array_get(&keyword_indexes_arr, &count); names = array_get(mail->ibox->keyword_names, &names_count); ARRAY_CREATE(&data->keywords, mail->data_pool, const char *, count); for (i = 0; i < count; i++) { const char *name; i_assert(keyword_indexes[i] < names_count); name = names[keyword_indexes[i]]; array_append(&data->keywords, &name, 1); } /* end with NULL */ (void)array_append_space(&data->keywords); t_pop(); return array_get(&data->keywords, NULL); } const struct message_part *index_mail_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 (get_cached_parts(mail)) return data->parts; if (data->parser_ctx == NULL) { if (index_mail_parse_headers(mail, NULL) < 0) return NULL; } index_mail_parse_body(mail, TRUE); return data->parts; } time_t index_mail_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) { data->received_date = index_mail_get_cached_received_date(mail); if (data->received_date != (time_t)-1) return data->received_date; } return data->received_date; } time_t index_mail_get_date(struct mail *_mail, int *timezone) { struct index_mail *mail = (struct index_mail *) _mail; struct index_mail_data *data = &mail->data; struct mail_cache_field *cache_fields = mail->ibox->cache_fields; const char *str; int tz; if (data->sent_date.time != (time_t)-1) { if (timezone != NULL) *timezone = data->sent_date.timezone; return data->sent_date.time; } (void)index_mail_get_fixed_field(mail, MAIL_CACHE_SENT_DATE, &data->sent_date, sizeof(data->sent_date)); if (data->sent_date.time == (time_t)-1) { str = mail_get_first_header(_mail, "Date"); if (str == NULL || !message_date_parse((const unsigned char *)str, strlen(str), &data->sent_date.time, &tz)) { /* 0 = not found / invalid */ data->sent_date.time = 0; tz = 0; } data->sent_date.timezone = tz; mail_cache_add(mail->trans->cache_trans, mail->data.seq, cache_fields[MAIL_CACHE_SENT_DATE].idx, &data->sent_date, sizeof(data->sent_date)); } if (timezone != NULL) *timezone = data->sent_date.timezone; return data->sent_date.time; } static bool get_cached_msgpart_sizes(struct index_mail *mail) { struct index_mail_data *data = &mail->data; if (data->parts == NULL) get_cached_parts(mail); if (data->parts != NULL) { data->hdr_size_set = TRUE; data->hdr_size = data->parts->header_size; data->body_size = data->parts->body_size; data->body_size_set = TRUE; data->virtual_size = data->parts->header_size.virtual_size + data->body_size.virtual_size; data->physical_size = data->parts->header_size.physical_size + data->body_size.physical_size; } return data->parts != NULL; } uoff_t index_mail_get_virtual_size(struct mail *_mail) { struct index_mail *mail = (struct index_mail *) _mail; struct index_mail_data *data = &mail->data; struct mail_cache_field *cache_fields = mail->ibox->cache_fields; struct message_size hdr_size, body_size; if (data->virtual_size != (uoff_t)-1) return data->virtual_size; data->virtual_size = index_mail_get_cached_virtual_size(mail); if (data->virtual_size != (uoff_t)-1) return data->virtual_size; if (!get_cached_msgpart_sizes(mail)) { if (mail_get_stream(_mail, &hdr_size, &body_size) == NULL) return (uoff_t)-1; } i_assert(data->virtual_size != (uoff_t)-1); mail_cache_add(mail->trans->cache_trans, mail->data.seq, cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx, &data->virtual_size, sizeof(data->virtual_size)); return data->virtual_size; } uoff_t index_mail_get_physical_size(struct mail *_mail) { struct index_mail *mail = (struct index_mail *) _mail; struct index_mail_data *data = &mail->data; if (data->physical_size != (uoff_t)-1) return data->physical_size; data->physical_size = index_mail_get_cached_physical_size(mail); if (data->physical_size != (uoff_t)-1) return data->physical_size; if (get_cached_msgpart_sizes(mail)) return data->physical_size; return (uoff_t)-1; } static void parse_bodystructure_part_header(struct message_part *part, struct message_header_line *hdr, void *context) { pool_t pool = context; imap_bodystructure_parse_header(pool, part, hdr); } static void index_mail_parse_body(struct index_mail *mail, bool need_parts) { struct index_mail_data *data = &mail->data; struct mail_cache_field *cache_fields = mail->ibox->cache_fields; enum mail_cache_decision_type decision; buffer_t *buffer; const void *buf_data; size_t buf_size; uint32_t cache_flags; i_assert(data->parts == NULL); i_assert(data->parser_ctx != NULL); i_stream_seek(data->stream, data->hdr_size.physical_size); if (data->save_bodystructure_body) { /* bodystructure header is parsed, we want the body's mime headers too */ i_assert(!data->save_bodystructure_header); message_parser_parse_body(data->parser_ctx, parse_bodystructure_part_header, NULL, mail->data_pool); data->save_bodystructure_body = FALSE; data->parsed_bodystructure = TRUE; } else { message_parser_parse_body(data->parser_ctx, NULL, NULL, NULL); } data->parts = message_parser_deinit(data->parser_ctx); data->parser_ctx = NULL; if (data->parsed_bodystructure && imap_bodystructure_is_plain_7bit(data->parts)) { data->cache_flags |= MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII; /* we need message_parts cached to be able to actually use it in BODY/BODYSTRUCTURE reply */ need_parts = TRUE; } data->body_size = data->parts->body_size; data->body_size_set = TRUE; cache_flags = data->cache_flags & ~(MAIL_CACHE_FLAG_BINARY_HEADER | MAIL_CACHE_FLAG_BINARY_BODY | MAIL_CACHE_FLAG_HAS_NULS | MAIL_CACHE_FLAG_HAS_NO_NULS); if (!mail->mail.mail.has_nuls && !mail->mail.mail.has_no_nuls) { /* we know the NULs now, update them */ if ((data->parts->flags & MESSAGE_PART_FLAG_HAS_NULS) != 0) { mail->mail.mail.has_nuls = TRUE; mail->mail.mail.has_no_nuls = FALSE; } else { mail->mail.mail.has_nuls = FALSE; mail->mail.mail.has_no_nuls = TRUE; } if (mail->mail.mail.has_nuls) cache_flags |= MAIL_CACHE_FLAG_HAS_NULS; else cache_flags |= MAIL_CACHE_FLAG_HAS_NO_NULS; } if (data->hdr_size.virtual_size == data->hdr_size.physical_size) cache_flags |= MAIL_CACHE_FLAG_BINARY_HEADER; if (data->body_size.virtual_size == data->body_size.physical_size) cache_flags |= MAIL_CACHE_FLAG_BINARY_BODY; if (cache_flags != data->cache_flags) { data->cache_flags = cache_flags; mail_cache_add(mail->trans->cache_trans, mail->data.seq, cache_fields[MAIL_CACHE_FLAGS].idx, &cache_flags, sizeof(cache_flags)); } /* see if we want to cache the message part */ if (mail_cache_field_exists(mail->trans->cache_view, mail->data.seq, cache_fields[MAIL_CACHE_MESSAGEPART].idx) != 0) return; decision = mail_cache_field_get_decision(mail->ibox->cache, cache_fields[MAIL_CACHE_MESSAGEPART].idx); if (decision != (MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED) && (decision != MAIL_CACHE_DECISION_NO || need_parts || (mail->wanted_fields & MAIL_FETCH_MESSAGE_PARTS) != 0)) { t_push(); buffer = buffer_create_dynamic(pool_datastack_create(), 1024); message_part_serialize(mail->data.parts, buffer); buf_data = buffer_get_data(buffer, &buf_size); mail_cache_add(mail->trans->cache_trans, mail->data.seq, cache_fields[MAIL_CACHE_MESSAGEPART].idx, buf_data, buf_size); t_pop(); data->messageparts_saved_to_cache = TRUE; } } struct istream *index_mail_init_stream(struct index_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 (hdr_size != NULL || body_size != NULL) (void)get_cached_msgpart_sizes(mail); if (hdr_size != NULL || body_size != NULL) { i_stream_seek(data->stream, 0); if (!data->hdr_size_set) { if ((data->access_part & PARSE_HDR) != 0) { if (index_mail_parse_headers(mail, NULL) < 0) return NULL; } else { message_get_header_size(data->stream, &data->hdr_size, NULL); data->hdr_size_set = TRUE; } } *hdr_size = data->hdr_size; } if (body_size != NULL) { i_stream_seek(data->stream, data->hdr_size.physical_size); if (!data->body_size_set) { if ((data->access_part & PARSE_BODY) != 0) index_mail_parse_body(mail, FALSE); else { message_get_body_size(data->stream, &data->body_size, NULL); data->body_size_set = TRUE; } } *body_size = data->body_size; } if (data->hdr_size_set && data->body_size_set) { data->virtual_size = data->hdr_size.virtual_size + data->body_size.virtual_size; data->physical_size = data->hdr_size.physical_size + data->body_size.physical_size; } i_stream_seek(data->stream, 0); return data->stream; } static void index_mail_parse_bodystructure(struct index_mail *mail, enum index_cache_field field) { struct index_mail_data *data = &mail->data; struct mail_cache_field *cache_fields = mail->ibox->cache_fields; enum mail_cache_decision_type dec; string_t *str; bool bodystructure_cached = FALSE; bool plain_bodystructure = FALSE; if (!data->parsed_bodystructure) { if (data->save_bodystructure_header || !data->save_bodystructure_body) { /* we haven't parsed the header yet */ data->save_bodystructure_header = TRUE; data->save_bodystructure_body = TRUE; if (index_mail_parse_headers(mail, NULL) < 0) return; } if (data->parts != NULL) { i_assert(data->parts->next == NULL); i_stream_seek(data->stream, data->hdr_size.physical_size); message_parse_from_parts(data->parts->children, data->stream, parse_bodystructure_part_header, mail->data_pool); data->parsed_bodystructure = TRUE; } else { index_mail_parse_body(mail, FALSE); } } if ((data->cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) != 0) { if (data->messageparts_saved_to_cache || mail_cache_field_exists(mail->trans->cache_view, data->seq, cache_fields[MAIL_CACHE_MESSAGEPART].idx) > 0) { /* cached it as flag + message_parts */ plain_bodystructure = TRUE; } } dec = mail_cache_field_get_decision(mail->ibox->cache, cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx); if (field == MAIL_CACHE_IMAP_BODYSTRUCTURE || ((dec & ~MAIL_CACHE_DECISION_FORCED) != MAIL_CACHE_DECISION_NO && mail_cache_field_exists(mail->trans->cache_view, data->seq, cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx) == 0)) { str = str_new(mail->data_pool, 128); imap_bodystructure_write(data->parts, str, TRUE); data->bodystructure = str_c(str); if (!plain_bodystructure && dec != (MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED)) { mail_cache_add(mail->trans->cache_trans, data->seq, cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx, str_c(str), str_len(str)+1); bodystructure_cached = TRUE; } } dec = mail_cache_field_get_decision(mail->ibox->cache, cache_fields[MAIL_CACHE_IMAP_BODY].idx); if (field == MAIL_CACHE_IMAP_BODY || ((dec & ~MAIL_CACHE_DECISION_FORCED) != MAIL_CACHE_DECISION_NO && mail_cache_field_exists(mail->trans->cache_view, data->seq, cache_fields[MAIL_CACHE_IMAP_BODY].idx) == 0)) { str = str_new(mail->data_pool, 128); imap_bodystructure_write(data->parts, str, FALSE); data->body = str_c(str); if (!bodystructure_cached && !plain_bodystructure && dec != (MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED)) { mail_cache_add(mail->trans->cache_trans, data->seq, cache_fields[MAIL_CACHE_IMAP_BODY].idx, str_c(str), str_len(str)+1); } } } static void index_mail_get_plain_bodystructure(struct index_mail *mail, string_t *str, bool extended) { str_printfa(str, IMAP_BODY_PLAIN_7BIT_ASCII" %"PRIuUOFF_T" %u", mail->data.parts->body_size.virtual_size, mail->data.parts->body_size.lines); if (extended) str_append(str, " NIL NIL NIL"); } const char *index_mail_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; struct mail_cache_field *cache_fields = mail->ibox->cache_fields; string_t *str; const void *ext_data; switch (field) { case MAIL_FETCH_IMAP_BODY: { unsigned int body_cache_field = cache_fields[MAIL_CACHE_IMAP_BODY].idx; unsigned int bodystructure_cache_field = cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx; if (data->body != NULL) return data->body; /* 1) use plain-7bit-ascii flag if it exists 2) get BODY if it exists 3) get it using BODYSTRUCTURE if it exists 4) parse body structure, and save BODY/BODYSTRUCTURE depending on what we want cached */ str = str_new(mail->data_pool, 128); if ((mail->data.cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) != 0 && get_cached_parts(mail)) { index_mail_get_plain_bodystructure(mail, str, FALSE); return str_c(str); } if (mail_cache_lookup_field(mail->trans->cache_view, str, mail->data.seq, body_cache_field) > 0) { data->body = str_c(str); return data->body; } if (mail_cache_lookup_field(mail->trans->cache_view, str, mail->data.seq, bodystructure_cache_field) > 0) { data->bodystructure = p_strdup(mail->data_pool, str_c(str)); str_truncate(str, 0); if (imap_body_parse_from_bodystructure( data->bodystructure, str)) { data->body = str_c(str); return data->body; } /* broken, continue.. */ mail_cache_set_corrupted(mail->ibox->cache, "Corrupted BODYSTRUCTURE for mail %u", mail->mail.mail.uid); data->bodystructure = NULL; } p_free(mail->data_pool, str); index_mail_parse_bodystructure(mail, MAIL_CACHE_IMAP_BODY); return data->body; } case MAIL_FETCH_IMAP_BODYSTRUCTURE: { unsigned int bodystructure_cache_field = cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx; if (data->bodystructure != NULL) return data->bodystructure; str = str_new(mail->data_pool, 128); if ((mail->data.cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) != 0 && get_cached_parts(mail)) { index_mail_get_plain_bodystructure(mail, str, TRUE); return str_c(str); } if (mail_cache_lookup_field(mail->trans->cache_view, str, mail->data.seq, bodystructure_cache_field) > 0) { data->bodystructure = str_c(str); return data->bodystructure; } p_free(mail->data_pool, str); index_mail_parse_bodystructure(mail, MAIL_CACHE_IMAP_BODYSTRUCTURE); return data->bodystructure; } case MAIL_FETCH_IMAP_ENVELOPE: if (data->envelope == NULL) index_mail_headers_get_envelope(mail); return data->envelope; case MAIL_FETCH_FROM_ENVELOPE: case MAIL_FETCH_UIDL_FILE_NAME: return NULL; case MAIL_FETCH_HEADER_MD5: if (mail_index_lookup_ext(mail->trans->trans_view, data->seq, mail->ibox->md5hdr_ext_idx, &ext_data) < 0) { mail_storage_set_index_error(mail->ibox); return NULL; } if (ext_data == NULL) return NULL; return binary_to_hex(ext_data, 16); default: i_unreached(); return NULL; } } struct mail * index_mail_alloc(struct mailbox_transaction_context *_t, enum mail_fetch_field wanted_fields, struct mailbox_header_lookup_ctx *_wanted_headers) { struct index_transaction_context *t = (struct index_transaction_context *)_t; struct index_header_lookup_ctx *wanted_headers = (struct index_header_lookup_ctx *)_wanted_headers; struct index_mail *mail; const struct mail_index_header *hdr; pool_t pool; pool = pool_alloconly_create("mail", 512); mail = p_new(pool, struct index_mail, 1); mail->mail.pool = pool; array_create(&mail->mail.module_contexts, pool, sizeof(void *), 5); mail->mail.v = *t->ibox->mail_vfuncs; mail->mail.mail.box = &t->ibox->box; mail->mail.mail.transaction = &t->mailbox_ctx; hdr = mail_index_get_header(t->ibox->view); mail->uid_validity = hdr->uid_validity; mail->data_pool = pool_alloconly_create("index_mail", 16384); mail->ibox = t->ibox; mail->trans = t; mail->wanted_fields = wanted_fields; mail->wanted_headers = wanted_headers; return &mail->mail.mail; } static void index_mail_close(struct index_mail *mail) { if (mail->data.stream != NULL) i_stream_unref(mail->data.stream); if (mail->data.filter_stream != NULL) i_stream_unref(mail->data.filter_stream); } int index_mail_set_seq(struct mail *_mail, uint32_t seq) { struct index_mail *mail = (struct index_mail *)_mail; struct index_mail_data *data = &mail->data; struct mail_cache_field *cache_fields = mail->ibox->cache_fields; struct mail_cache_view *cache_view = mail->trans->cache_view; const struct mail_index_record *rec; if (mail_index_lookup(mail->trans->trans_view, seq, &rec) < 0) { mail_storage_set_index_error(mail->ibox); return -1; } index_mail_close(mail); memset(data, 0, sizeof(*data)); p_clear(mail->data_pool); data->rec = rec; data->seq = seq; data->virtual_size = (uoff_t)-1; data->physical_size = (uoff_t)-1; data->received_date = data->sent_date.time = (time_t)-1; if (!index_mail_get_fixed_field(mail, MAIL_CACHE_FLAGS, &data->cache_flags, sizeof(data->cache_flags))) data->cache_flags = 0; /* set public fields */ mail->mail.mail.seq = seq; mail->mail.mail.uid = rec->uid; mail->mail.mail.has_nuls = (data->cache_flags & MAIL_CACHE_FLAG_HAS_NULS) != 0; mail->mail.mail.has_no_nuls = (data->cache_flags & MAIL_CACHE_FLAG_HAS_NO_NULS) != 0; /* see if wanted_fields can tell us if we need to read/parse header/body */ if ((mail->wanted_fields & MAIL_FETCH_MESSAGE_PARTS) != 0) { unsigned int cache_field = cache_fields[MAIL_CACHE_MESSAGEPART].idx; if (mail_cache_field_exists(cache_view, seq, cache_field) <= 0) data->access_part |= PARSE_HDR | PARSE_BODY; } if ((mail->wanted_fields & MAIL_FETCH_VIRTUAL_SIZE) != 0) { unsigned int cache_field = cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx; if (mail_cache_field_exists(cache_view, seq, cache_field) <= 0) data->access_part |= READ_HDR | READ_BODY; } if ((mail->wanted_fields & MAIL_FETCH_IMAP_ENVELOPE) != 0 && (data->access_part & PARSE_HDR) == 0) { /* don't waste time doing full checks for all required headers. assume that if we have "hdr.message-id" or "imap.envelope" cached, we don't need to parse header. */ unsigned int cache_field1 = mail_cache_register_lookup(mail->ibox->cache, "hdr.message-id"); unsigned int cache_field2 = cache_fields[MAIL_CACHE_IMAP_ENVELOPE].idx; if ((cache_field1 == (unsigned int)-1 || mail_cache_field_exists(cache_view, seq, cache_field1) <= 0) && mail_cache_field_exists(cache_view, seq, cache_field2) <= 0) data->access_part |= PARSE_HDR; } if ((mail->wanted_fields & MAIL_FETCH_IMAP_BODY) != 0 && (data->cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) == 0) { /* we need either imap.body or imap.bodystructure */ unsigned int cache_field1 = cache_fields[MAIL_CACHE_IMAP_BODY].idx; unsigned int cache_field2 = cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx; if (mail_cache_field_exists(cache_view, seq, cache_field1) <= 0 && mail_cache_field_exists(cache_view, seq, cache_field2) <= 0) data->access_part |= PARSE_HDR | PARSE_BODY; else { data->save_bodystructure_header = TRUE; data->save_bodystructure_body = TRUE; } } if ((mail->wanted_fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0 && (data->cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) == 0) { unsigned int cache_field = cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx; if (mail_cache_field_exists(cache_view, seq, cache_field) <= 0) data->access_part |= PARSE_HDR | PARSE_BODY; else { data->save_bodystructure_header = TRUE; data->save_bodystructure_body = TRUE; } } if ((mail->wanted_fields & MAIL_FETCH_DATE) != 0) { unsigned int cache_field = cache_fields[MAIL_CACHE_SENT_DATE].idx; if (mail_cache_field_exists(cache_view, seq, cache_field) <= 0) { data->access_part |= PARSE_HDR; data->save_sent_date = TRUE; } } if ((mail->wanted_fields & MAIL_FETCH_IMAP_ENVELOPE) != 0) data->save_envelope = TRUE; if ((mail->wanted_fields & (MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY)) != 0) { /* open stream immediately to set expunged flag if it's already lost */ if ((mail->wanted_fields & MAIL_FETCH_STREAM_HEADER) != 0) data->access_part |= READ_HDR; if ((mail->wanted_fields & MAIL_FETCH_STREAM_BODY) != 0) data->access_part |= READ_BODY; (void)mail_get_stream(_mail, NULL, NULL); } return 0; } void index_mail_free(struct mail *_mail) { struct index_mail *mail = (struct index_mail *)_mail; index_mail_close(mail); if (mail->header_data != NULL) buffer_free(mail->header_data); if (array_is_created(&mail->header_lines)) array_free(&mail->header_lines); if (array_is_created(&mail->header_match)) array_free(&mail->header_match); if (array_is_created(&mail->header_match_lines)) array_free(&mail->header_match_lines); pool_unref(mail->data_pool); pool_unref(mail->mail.pool); } int index_mail_update_flags(struct mail *mail, enum modify_type modify_type, enum mail_flags flags) { struct index_mail *imail = (struct index_mail *)mail; mail_index_update_flags(imail->trans->trans, mail->seq, modify_type, flags & MAIL_FLAGS_MASK); return 0; } int index_mail_update_keywords(struct mail *mail, enum modify_type modify_type, struct mail_keywords *keywords) { struct index_mail *imail = (struct index_mail *)mail; mail_index_update_keywords(imail->trans->trans, mail->seq, modify_type, keywords); return 0; } int index_mail_expunge(struct mail *mail) { struct index_mail *imail = (struct index_mail *)mail; mail_index_expunge(imail->trans->trans, mail->seq); return 0; }