mail-cache-lookup.c revision 02166e32bcda5d0018ae1a2a38614126ab5c6025
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "buffer.h"
1171f0abf442638bac1827bb24a0b6b8eb682a82Timo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-cache-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include <stdlib.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#define CACHE_PREFETCH 1024
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainenint mail_cache_get_record(struct mail_cache *cache, uint32_t offset,
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen const struct mail_cache_record **rec_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen const struct mail_cache_record *rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen i_assert(offset != 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* we don't know yet how large the record is, so just guess */
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (mail_cache_map(cache, offset, sizeof(*rec) + CACHE_PREFETCH) < 0)
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (offset + sizeof(*rec) > cache->mmap_length) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_corrupted(cache, "record points outside file");
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen rec = CACHE_RECORD(cache, offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (rec->size < sizeof(*rec)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_corrupted(cache, "invalid record size");
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (rec->size > CACHE_PREFETCH) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* larger than we guessed. map the rest of the record. */
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (mail_cache_map(cache, offset, rec->size) < 0)
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen return -1;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen rec = CACHE_RECORD(cache, offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (rec->size > cache->mmap_length ||
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen offset + rec->size > cache->mmap_length) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_corrupted(cache, "record points outside file");
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen *rec_r = rec;
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenstatic int
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenmail_cache_lookup_offset(struct mail_cache *cache, struct mail_index_view *view,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen uint32_t seq, uint32_t *offset_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen struct mail_index_map *map;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen const struct mail_index_ext *ext;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen const void *data;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen uint32_t idx;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen int i, ret;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (mail_index_lookup_ext_full(view, seq, cache->ext_id,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen &map, &data) < 0)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return -1;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (data == NULL || *((const uint32_t *)data) == 0) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* nothing in cache (for this record) */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return 0;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (!mail_index_map_get_ext_idx(map, cache->ext_id, &idx))
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen i_unreached();
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen ext = array_idx(&map->extensions, idx);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* reset_id must match file_seq or the offset is for a different cache
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen file. if this happens, try if reopening the cache helps. if not,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen it was probably for an old cache file that's already lost by now. */
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen i = 0;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen while (cache->hdr->file_seq != ext->reset_id) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (++i == 2)
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if ((ret = mail_cache_reopen(cache)) <= 0) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* error / we already have the latest file open */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return ret;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen *offset_r = *((const uint32_t *)data);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainenbool mail_cache_track_loops(ARRAY_TYPE(uint32_t) *array, uint32_t offset)
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen{
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen const uint32_t *offsets;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen unsigned int i, count;
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen offsets = array_get(array, &count);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen for (i = 0; i < count; i++) {
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen if (offsets[i] == offset)
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen return TRUE;
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen }
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen array_append(array, &offset, 1);
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen return FALSE;
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen}
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenvoid mail_cache_lookup_iter_init(struct mail_cache_view *view, uint32_t seq,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_lookup_iterate_ctx *ctx_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_lookup_iterate_ctx *ctx = ctx_r;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen if (!view->cache->opened)
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen (void)mail_cache_open_and_verify(view->cache);
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen memset(ctx, 0, sizeof(*ctx));
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->view = view;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->seq = seq;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (!MAIL_CACHE_IS_UNUSABLE(view->cache)) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* look up the first offset */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (mail_cache_lookup_offset(view->cache, view->view, seq,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen &ctx->offset) < 0)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->failed = TRUE;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->remap_counter = view->cache->remap_counter;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen array_clear(&view->looping_offsets);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenstatic int
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenmail_cache_lookup_iter_next_record(struct mail_cache_lookup_iterate_ctx *ctx)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_view *view = ctx->view;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ctx->failed)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ctx->rec != NULL)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->offset = ctx->rec->prev_offset;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ctx->offset == 0) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* end of this record list. check newly appended data. */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ctx->appends_checked ||
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen view->trans_seq1 > ctx->seq ||
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen view->trans_seq2 < ctx->seq ||
02166e32bcda5d0018ae1a2a38614126ab5c6025Timo Sirainen MAIL_CACHE_IS_UNUSABLE(view->cache) ||
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_lookup_offset(view->cache, view->trans_view,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->seq, &ctx->offset) <= 0)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return 0;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->appends_checked = TRUE;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->remap_counter = view->cache->remap_counter;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen array_clear(&view->looping_offsets);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* look up the next record */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (mail_cache_track_loops(&view->looping_offsets, ctx->offset)) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_set_corrupted(view->cache,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen "record list is circular");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (mail_cache_get_record(view->cache, ctx->offset, &ctx->rec) < 0)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->remap_counter = view->cache->remap_counter;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->pos = sizeof(*ctx->rec);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->rec_size = ctx->rec->size;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return 1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenint mail_cache_lookup_iter_next(struct mail_cache_lookup_iterate_ctx *ctx,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_iterate_field *field_r)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache *cache = ctx->view->cache;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen unsigned int field_idx;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen unsigned int data_size;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint32_t file_field;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen int ret;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen i_assert(ctx->remap_counter == cache->remap_counter);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ctx->pos + sizeof(uint32_t) > ctx->rec_size) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ctx->pos != ctx->rec_size) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_set_corrupted(cache,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen "record has invalid size");
58febed28f2af78b2d8a281c851d9b67160c4bd3Timo Sirainen return -1;
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if ((ret = mail_cache_lookup_iter_next_record(ctx)) <= 0)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* return the next field */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen file_field = *((const uint32_t *)CONST_PTR_OFFSET(ctx->rec, ctx->pos));
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->pos += sizeof(uint32_t);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (file_field >= cache->file_fields_count) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* new field, have to re-read fields header to figure
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen out its size */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (mail_cache_header_fields_read(cache) < 0)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (file_field >= cache->file_fields_count) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_set_corrupted(cache,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen "field index too large (%u >= %u)",
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen file_field, cache->file_fields_count);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
ca316aeb7648d3f1bcf45231f73ddeb1b67a6961Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* field reading might have re-mmaped the file and
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen caused rec pointer to break. need to get it again. */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (mail_cache_get_record(cache, ctx->offset, &ctx->rec) < 0)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->remap_counter = cache->remap_counter;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen }
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field_idx = cache->file_field_map[file_field];
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen data_size = cache->fields[field_idx].field.field_size;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (data_size == (unsigned int)-1 &&
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->pos + sizeof(uint32_t) <= ctx->rec->size) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* variable size field. get its size from the file. */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen data_size = *((const uint32_t *)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen CONST_PTR_OFFSET(ctx->rec, ctx->pos));
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->pos += sizeof(uint32_t);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (ctx->rec->size - ctx->pos < data_size) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_set_corrupted(cache,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen "record continues outside its allocated size");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return -1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field_r->field_idx = field_idx;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field_r->data = CONST_PTR_OFFSET(ctx->rec, ctx->pos);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field_r->size = data_size;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* each record begins from 32bit aligned position */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx->pos += (data_size + sizeof(uint32_t)-1) & ~(sizeof(uint32_t)-1);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return 1;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainenstatic int mail_cache_seq(struct mail_cache_view *view, uint32_t seq)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_lookup_iterate_ctx iter;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_iterate_field field;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (++view->cached_exists_value == 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* wrapped, we'll have to clear the buffer */
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen buffer_reset(view->cached_exists_buf);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen view->cached_exists_value++;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen view->cached_exists_seq = seq;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_lookup_iter_init(view, seq, &iter);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen while ((ret = mail_cache_lookup_iter_next(&iter, &field)) > 0) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen buffer_write(view->cached_exists_buf, field.field_idx,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen &view->cached_exists_value, 1);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return ret;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainenstatic bool
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainenmail_cache_file_has_field(struct mail_cache *cache, unsigned int field)
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen{
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen i_assert(field < cache->fields_count);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen return cache->field_file_map[field] != (uint32_t)-1;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen}
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainenint mail_cache_field_exists(struct mail_cache_view *view, uint32_t seq,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int field)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const uint8_t *data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen i_assert(seq > 0);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen if (!view->cache->opened)
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen (void)mail_cache_open_and_verify(view->cache);
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (!mail_cache_file_has_field(view->cache, field))
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* FIXME: we should discard the cache if view has been synced */
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen if (view->cached_exists_seq != seq) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen if (mail_cache_seq(view, seq) < 0)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen data = view->cached_exists_buf->data;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen return (field <= view->cached_exists_buf->used &&
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen data[field] == view->cached_exists_value) ? 1 : 0;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainenenum mail_cache_decision_type
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainenmail_cache_field_get_decision(struct mail_cache *cache, unsigned int field_idx)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen{
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen i_assert(field_idx < cache->fields_count);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen return cache->fields[field_idx].field.decision;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen}
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainenstatic int
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenmail_cache_lookup_bitmask(struct mail_cache_lookup_iterate_ctx *iter,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen unsigned int field_idx, unsigned int field_size,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen buffer_t *dest_buf)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_iterate_field field;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const unsigned char *src;
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen unsigned char *dest;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen unsigned int i;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen bool found = FALSE;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen int ret;
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* make sure all bits are cleared first */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen buffer_write_zero(dest_buf, 0, field_size);
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen while ((ret = mail_cache_lookup_iter_next(iter, &field)) > 0) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (field.field_idx != field_idx)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen continue;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* merge all bits */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen src = field.data;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen dest = buffer_get_space_unsafe(dest_buf, 0, field.size);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen for (i = 0; i < field.size; i++)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen dest[i] |= src[i];
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen found = TRUE;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return ret < 0 ? -1 : (found ? 1 : 0);
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen}
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen
1171f0abf442638bac1827bb24a0b6b8eb682a82Timo Sirainenint mail_cache_lookup_field(struct mail_cache_view *view, buffer_t *dest_buf,
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen uint32_t seq, unsigned int field_idx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen const struct mail_cache_field *field_def;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_lookup_iterate_ctx iter;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_iterate_field field;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen int ret;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen if ((ret = mail_cache_field_exists(view, seq, field_idx)) <= 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return ret;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* the field should exist */
710deabc6b3c305c3a842e7a2e0d173c526d13a7Timo Sirainen mail_cache_decision_state_update(view, seq, field_idx);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_lookup_iter_init(view, seq, &iter);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field_def = &view->cache->fields[field_idx].field;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (field_def->type == MAIL_CACHE_FIELD_BITMASK) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return mail_cache_lookup_bitmask(&iter, field_idx,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field_def->field_size,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen dest_buf);
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* return the first one that's found. if there are multiple
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen they're all identical. */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen while ((ret = mail_cache_lookup_iter_next(&iter, &field)) > 0) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (field.field_idx == field_idx) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen buffer_append(dest_buf, field.data, field.size);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen break;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainenstruct header_lookup_data {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen uint32_t offset;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen uint32_t data_size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainenstruct header_lookup_line {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen uint32_t line_num;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen struct header_lookup_data *data;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen};
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenstruct header_lookup_context {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_view *view;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ARRAY_DEFINE(lines, struct header_lookup_line);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen};
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainenenum {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen HDR_FIELD_STATE_DONTWANT = 0,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen HDR_FIELD_STATE_WANT,
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen HDR_FIELD_STATE_SEEN
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen};
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenstatic void header_lines_save(struct header_lookup_context *ctx,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const struct mail_cache_iterate_field *field)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const uint32_t *lines = field->data;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint32_t data_size = field->size;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen struct header_lookup_line hdr_line;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen struct header_lookup_data *hdr_data;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int i, lines_count;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* data = { line_nums[], 0, "headers" } */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; data_size >= sizeof(uint32_t); i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen data_size -= sizeof(uint32_t);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (lines[i] == 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen break;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen lines_count = i;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen hdr_data = t_new(struct header_lookup_data, 1);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen hdr_data->offset = (const char *)&lines[lines_count+1] -
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen (const char *)ctx->view->cache->data;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen hdr_data->data_size = data_size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < lines_count; i++) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen hdr_line.line_num = lines[i];
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen hdr_line.data = hdr_data;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen array_append(&ctx->lines, &hdr_line, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainenstatic int header_lookup_line_cmp(const void *p1, const void *p2)
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen{
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen const struct header_lookup_line *l1 = p1, *l2 = p2;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen return (int)l1->line_num - (int)l2->line_num;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenint mail_cache_lookup_headers(struct mail_cache_view *view, string_t *dest,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint32_t seq, unsigned int field_idxs[],
9d3ccd79130199ffdb19a688027d49bf20a4aaaaTimo Sirainen unsigned int fields_count)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mail_cache *cache = view->cache;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_lookup_iterate_ctx iter;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct mail_cache_iterate_field field;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct header_lookup_context ctx;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen struct header_lookup_line *lines;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const unsigned char *p, *start, *end;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen uint8_t *field_state;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen unsigned int i, count, max_field = 0;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen size_t hdr_size;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen uint8_t want = HDR_FIELD_STATE_WANT;
65a5fb2343f9870713bfca0b24abb58dcade605eTimo Sirainen buffer_t *buf;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen int ret;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (fields_count == 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
2a21435425c50514fa4d0708110a4ed7f0d85661Timo Sirainen if (!view->cache->opened)
2a21435425c50514fa4d0708110a4ed7f0d85661Timo Sirainen (void)mail_cache_open_and_verify(view->cache);
2a21435425c50514fa4d0708110a4ed7f0d85661Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_push();
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* mark all the fields we want to find. */
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 32);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < fields_count; i++) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (!mail_cache_file_has_field(cache, field_idxs[i])) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_pop();
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 0;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (field_idxs[i] > max_field)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen max_field = field_idxs[i];
65a5fb2343f9870713bfca0b24abb58dcade605eTimo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen buffer_write(buf, field_idxs[i], &want, 1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field_state = buffer_get_modifiable_data(buf, NULL);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* lookup the fields */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen memset(&ctx, 0, sizeof(ctx));
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ctx.view = view;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen t_array_init(&ctx.lines, 32);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_lookup_iter_init(view, seq, &iter);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen while ((ret = mail_cache_lookup_iter_next(&iter, &field)) > 0) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (field.field_idx > max_field ||
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field_state[field.field_idx] != HDR_FIELD_STATE_WANT) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* a) don't want it, b) duplicate */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen } else {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen field_state[field.field_idx] = HDR_FIELD_STATE_SEEN;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen header_lines_save(&ctx, &field);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (ret <= 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_pop();
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return ret;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* check that all fields were found */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen for (i = 0; i <= max_field; i++) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (field_state[i] == HDR_FIELD_STATE_WANT) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_pop();
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 0;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
b1f58fea9e1813b48735a021043f1cea2b495c3bTimo Sirainen for (i = 0; i < fields_count; i++)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen mail_cache_decision_state_update(view, seq, field_idxs[i]);
b1f58fea9e1813b48735a021043f1cea2b495c3bTimo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* we need to return headers in the order they existed originally.
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen we can do this by sorting the messages by their line numbers. */
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen lines = array_get_modifiable(&ctx.lines, &count);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen qsort(lines, count, sizeof(*lines), header_lookup_line_cmp);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* then start filling dest buffer from the headers */
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen for (i = 0; i < count; i++) {
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen start = CONST_PTR_OFFSET(cache->data, lines[i].data->offset);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen end = start + lines[i].data->data_size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* find the end of the (multiline) header */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (p = start; p != end; p++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (*p == '\n' &&
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (p+1 == end || (p[1] != ' ' && p[1] != '\t'))) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen p++;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen break;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen hdr_size = (size_t)(p - start);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen buffer_append(dest, start, hdr_size);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* if there are more lines for this header, the following lines
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen continue after this one. so skip this line. */
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen lines[i].data->offset += hdr_size;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen lines[i].data->data_size -= hdr_size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_pop();
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 1;
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen}