mail-cache-lookup.c revision b1f58fea9e1813b48735a021043f1cea2b495c3b
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher/* Copyright (C) 2003-2004 Timo Sirainen */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan#include "lib.h"
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan#include "array.h"
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher#include "buffer.h"
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher#include "str.h"
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher#include "mail-cache-private.h"
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan#include <stdlib.h>
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan#define CACHE_PREFETCH 1024
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozekint mail_cache_get_record(struct mail_cache *cache, uint32_t offset,
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher const struct mail_cache_record **rec_r)
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher{
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher const struct mail_cache_record *cache_rec;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan *rec_r = NULL;
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher if (offset == 0)
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher return 0;
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (mail_cache_map(cache, offset,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher sizeof(*cache_rec) + CACHE_PREFETCH) < 0)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher return -1;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek if (offset + sizeof(*cache_rec) > cache->mmap_length) {
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek mail_cache_set_corrupted(cache, "record points outside file");
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek return -1;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek }
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek cache_rec = CACHE_RECORD(cache, offset);
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (cache_rec->size < sizeof(*cache_rec)) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan mail_cache_set_corrupted(cache, "invalid record size");
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return -1;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (cache_rec->size > CACHE_PREFETCH) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (mail_cache_map(cache, offset, cache_rec->size) < 0)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return -1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan cache_rec = CACHE_RECORD(cache, offset);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher }
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (cache_rec->size > cache->mmap_length ||
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher offset + cache_rec->size > cache->mmap_length) {
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher mail_cache_set_corrupted(cache, "record points outside file");
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek return -1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan *rec_r = cache_rec;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher return 0;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic int
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanmail_cache_lookup_offset(struct mail_cache *cache, struct mail_index_view *view,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher uint32_t seq, uint32_t *offset_r)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct mail_index_map *map;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher const struct mail_index_ext *ext;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher const void *data;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher uint32_t idx;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan int i, ret;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (mail_index_lookup_ext_full(view, seq, cache->ext_id,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher &map, &data) < 0)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return -1;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (data == NULL)
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher return 0;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek if (!mail_index_map_get_ext_idx(map, cache->ext_id, &idx)) {
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek /* no cache */
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek return 0;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek }
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher ext = array_idx(&map->extensions, idx);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan for (i = 0; i < 2; i++) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (cache->hdr->file_seq == ext->reset_id) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher *offset_r = *((const uint32_t *)data);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return 1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if ((ret = mail_cache_reopen(cache)) <= 0)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return ret;
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan if (MAIL_CACHE_IS_UNUSABLE(cache))
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return 0;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher }
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher return 0;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher}
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozekstatic int
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanmail_cache_foreach_rec(struct mail_cache_view *view, uint32_t *offset,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan mail_cache_foreach_callback_t *callback, void *context)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan{
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher struct mail_cache *cache = view->cache;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const struct mail_cache_record *cache_rec;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan size_t pos, next_pos, max_size;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher unsigned int data_size;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher uint32_t file_field;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan unsigned int field;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher int ret;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (mail_cache_get_record(view->cache, *offset, &cache_rec) < 0)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher return -1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (cache_rec == NULL) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan *offset = 0;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher return 1;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher }
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan max_size = cache_rec->size;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher if (max_size < sizeof(*cache_rec) + sizeof(uint32_t)*2) {
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher mail_cache_set_corrupted(cache, "record has invalid size");
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan return -1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher max_size -= sizeof(uint32_t);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan for (pos = sizeof(*cache_rec); pos < max_size; ) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher file_field =
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher *((const uint32_t *)CONST_PTR_OFFSET(cache_rec, pos));
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan pos += sizeof(uint32_t);
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher if (file_field >= cache->file_fields_count) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* new field, have to re-read fields header to figure
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher out its size */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (mail_cache_header_fields_read(cache) < 0)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return -1;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (file_field >= cache->file_fields_count) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher mail_cache_set_corrupted(cache,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan "field index too large (%u >= %u)",
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher file_field, cache->file_fields_count);
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher return -1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* field reading might have re-mmaped the file and
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan caused cache_rec to break. need to get it again. */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (mail_cache_get_record(view->cache, *offset,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan &cache_rec) < 0)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher return -1;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher i_assert(cache_rec != NULL);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan field = cache->file_field_map[file_field];
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan data_size = cache->fields[field].field.field_size;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (data_size == (unsigned int)-1) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher data_size = *((const uint32_t *)
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek CONST_PTR_OFFSET(cache_rec, pos));
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan pos += sizeof(uint32_t);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher next_pos = pos + ((data_size + 3) & ~3);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (data_size > cache_rec->size || next_pos > cache_rec->size) {
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek mail_cache_set_corrupted(cache,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan "record continues outside its allocated size");
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return -1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan ret = callback(view, field, CONST_PTR_OFFSET(cache_rec, pos),
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan data_size, context);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (ret != 1)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return ret;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan pos = next_pos;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan *offset = cache_rec->prev_offset;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher return 1;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic bool find_offset(struct mail_cache_view *view, uint32_t offset)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan{
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher const uint32_t *offsets;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher unsigned int i, count;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan offsets = array_get(&view->tmp_offsets, &count);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher for (i = 0; i < count; i++) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (offsets[i] == offset)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return TRUE;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return FALSE;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher}
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanint mail_cache_foreach(struct mail_cache_view *view, uint32_t seq,
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan mail_cache_foreach_callback_t *callback, void *context)
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan{
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan uint32_t offset;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher int ret;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (!view->cache->opened)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher (void)mail_cache_open_and_verify(view->cache);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (MAIL_CACHE_IS_UNUSABLE(view->cache))
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return 0;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if ((ret = mail_cache_lookup_offset(view->cache, view->view,
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan seq, &offset)) <= 0)
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan return ret;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher ret = 1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan array_clear(&view->tmp_offsets);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan while (offset != 0 && ret > 0) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (find_offset(view, offset)) {
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher mail_cache_set_corrupted(view->cache,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan "record list is circular");
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher return -1;
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan array_append(&view->tmp_offsets, &offset, 1);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher ret = mail_cache_foreach_rec(view, &offset,
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher callback, context);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (ret > 0 && view->trans_seq1 <= seq && view->trans_seq2 >= seq &&
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan mail_cache_lookup_offset(view->cache, view->trans_view,
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher seq, &offset) > 0) {
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher array_clear(&view->tmp_offsets);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan while (offset != 0 && ret > 0) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (find_offset(view, offset)) {
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher mail_cache_set_corrupted(view->cache,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan "record list is circular");
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return -1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan array_append(&view->tmp_offsets, &offset, 1);
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan ret = mail_cache_foreach_rec(view, &offset,
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan callback, context);
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher return ret;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic int
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallaghermail_cache_seq_callback(struct mail_cache_view *view, uint32_t field,
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher const void *data __attr_unused__,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan size_t data_size __attr_unused__,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan void *context __attr_unused__)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan{
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher buffer_write(view->cached_exists_buf, field,
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek &view->cached_exists_value, 1);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return 1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherstatic int mail_cache_seq(struct mail_cache_view *view, uint32_t seq)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan int ret;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (++view->cached_exists_value == 0) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher /* wrapped, we'll have to clear the buffer */
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher memset(buffer_get_modifiable_data(view->cached_exists_buf,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan NULL), 0,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_get_size(view->cached_exists_buf));
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan view->cached_exists_value++;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan view->cached_exists_seq = seq;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan ret = mail_cache_foreach(view, seq, mail_cache_seq_callback, NULL);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher return ret < 0 ? -1 : 0;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanint mail_cache_field_exists(struct mail_cache_view *view, uint32_t seq,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan unsigned int field)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher{
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher const uint8_t *data;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan uint32_t file_field;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan size_t size;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan i_assert(seq > 0);
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan i_assert(field < view->cache->fields_count);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (!view->cache->opened)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher (void)mail_cache_open_and_verify(view->cache);
056302a92862fda16351d7192600746746f38e5dStephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher file_field = view->cache->field_file_map[field];
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if (file_field == (uint32_t)-1)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher return 0;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
056302a92862fda16351d7192600746746f38e5dStephen Gallagher if (view->cached_exists_seq != seq) {
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if (mail_cache_seq(view, seq) < 0)
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher return -1;
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek }
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan data = buffer_get_data(view->cached_exists_buf, &size);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher return size <= field ? FALSE :
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher data[field] == view->cached_exists_value;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanenum mail_cache_decision_type
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallaghermail_cache_field_get_decision(struct mail_cache *cache, unsigned int field)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_assert(field < cache->fields_count);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return cache->fields[field].field.decision;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagherstruct mail_cache_lookup_context {
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher buffer_t *dest_buf;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan uint32_t field;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher bool found;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher};
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic int
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanmail_cache_lookup_callback(struct mail_cache_view *view __attr_unused__,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher uint32_t field, const void *data,
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher size_t data_size, void *context)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct mail_cache_lookup_context *ctx = context;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (ctx->field != field)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher return 1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_append(ctx->dest_buf, data, data_size);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan ctx->found = TRUE;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return 0;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivanstatic int
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivanmail_cache_lookup_bitmask_callback(struct mail_cache_view *view __attr_unused__,
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan uint32_t field, const void *data,
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher size_t data_size, void *context)
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct mail_cache_lookup_context *ctx = context;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher unsigned char *dest;
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek size_t i;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (ctx->field != field)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return 1;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher /* merge all bits */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan dest = buffer_get_space_unsafe(ctx->dest_buf, 0, data_size);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher for (i = 0; i < data_size; i++)
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher dest[i] |= ((const unsigned char *)data)[i];
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan ctx->found = TRUE;
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek return 1;
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherint mail_cache_lookup_field(struct mail_cache_view *view, buffer_t *dest_buf,
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher uint32_t seq, unsigned int field)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan{
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher struct mail_cache_lookup_context ctx;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher unsigned int data_size;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan int ret;
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek if ((ret = mail_cache_field_exists(view, seq, field)) <= 0)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return ret;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek mail_cache_decision_lookup(view, seq, field);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan /* should exist. find it. */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan ctx.field = field;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher ctx.dest_buf = dest_buf;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher ctx.found = FALSE;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (view->cache->fields[field].field.type != MAIL_CACHE_FIELD_BITMASK) {
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher ret = mail_cache_foreach(view, seq, mail_cache_lookup_callback,
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher &ctx);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher } else {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* make sure we're cleared first */
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek data_size = view->cache->fields[field].field.field_size;
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek memset(buffer_get_space_unsafe(dest_buf, 0, data_size),
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek 0, data_size);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher ret = mail_cache_foreach(view, seq,
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher mail_cache_lookup_bitmask_callback,
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher &ctx);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher }
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher return ret < 0 ? -1 : ctx.found;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher}
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozekstruct header_lookup_data_rec {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan uint32_t offset;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher uint32_t data_size;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher};
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivanstruct header_lookup_data {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan uint32_t line_num;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher struct header_lookup_data_rec *data;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher};
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstruct header_lookup_context {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan unsigned int *fields;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan unsigned int fields_count;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_t *data;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan unsigned int max_field;
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan uint8_t *fields_found;
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan};
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic int
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherheaders_find_callback(struct mail_cache_view *view, uint32_t field,
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher const void *data, size_t data_size, void *context)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct header_lookup_context *ctx = context;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const uint32_t *lines = data;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct header_lookup_data hdr_data;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct header_lookup_data_rec *hdr_data_rec;
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan unsigned int i, lines_count;
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (field > ctx->max_field || ctx->fields_found[field] != 1) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher /* a) don't want it, b) duplicate */
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher return 1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan ctx->fields_found[field]++;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* data = { line_nums[], 0, "headers" } */
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan for (i = 0; data_size >= sizeof(uint32_t); i++) {
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan data_size -= sizeof(uint32_t);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (lines[i] == 0)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher break;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan lines_count = i;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan hdr_data_rec = t_new(struct header_lookup_data_rec, 1);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan hdr_data_rec->offset = (const char *)&lines[lines_count+1] -
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan (const char *)view->cache->data;
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan hdr_data_rec->data_size = (uint32_t)data_size;
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan for (i = 0; i < lines_count; i++) {
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher hdr_data.line_num = lines[i];
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher hdr_data.data = hdr_data_rec;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher buffer_append(ctx->data, &hdr_data, sizeof(hdr_data));
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher }
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher return 1;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher}
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagherstatic int header_lookup_data_cmp(const void *p1, const void *p2)
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher{
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher const struct header_lookup_data *d1 = p1, *d2 = p2;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher return (int)d1->line_num - (int)d2->line_num;
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher}
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagherint mail_cache_lookup_headers(struct mail_cache_view *view, string_t *dest,
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher uint32_t seq, unsigned int fields[],
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher unsigned int fields_count)
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher{
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher struct mail_cache *cache = view->cache;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher struct header_lookup_context ctx;
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher struct header_lookup_data *data;
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher const unsigned char *p, *start, *end;
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher size_t i, size, hdr_size;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher uint8_t one = 1;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher buffer_t *buf;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher int ret;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if (fields_count == 0)
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher return 1;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher t_push();
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher /* @UNSAFE */
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher memset(&ctx, 0, sizeof(ctx));
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher ctx.fields = t_new(unsigned int, fields_count);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher ctx.fields_count = fields_count;
486237ee009f1d84fc4c85665dce80ade76f7079Stephen Gallagher
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher ctx.max_field = 0;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher buf = buffer_create_dynamic(pool_datastack_create(), 32);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher for (i = 0; i < fields_count; i++) {
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher i_assert(fields[i] < cache->fields_count);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher if (cache->field_file_map[fields[i]] == (unsigned int)-1) {
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher /* not cached at all */
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher t_pop();
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher return 0;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher }
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
486237ee009f1d84fc4c85665dce80ade76f7079Stephen Gallagher if (fields[i] > ctx.max_field)
486237ee009f1d84fc4c85665dce80ade76f7079Stephen Gallagher ctx.max_field = fields[i];
486237ee009f1d84fc4c85665dce80ade76f7079Stephen Gallagher
486237ee009f1d84fc4c85665dce80ade76f7079Stephen Gallagher buffer_write(buf, fields[i], &one, 1);
486237ee009f1d84fc4c85665dce80ade76f7079Stephen Gallagher ctx.fields[i] = fields[i];
486237ee009f1d84fc4c85665dce80ade76f7079Stephen Gallagher }
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher ctx.fields_found = buffer_get_modifiable_data(buf, NULL);
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek ctx.data = buffer_create_dynamic(pool_datastack_create(), 256);
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher /* we need to return them in sorted order. create array:
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher { line number -> cache file offset } */
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher ret = mail_cache_foreach(view, seq, headers_find_callback, &ctx);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (ret <= 0) {
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher t_pop();
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return ret;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* check that all fields were found */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan for (i = 0; i <= ctx.max_field; i++) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (ctx.fields_found[i] == 1) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher t_pop();
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return 0;
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan }
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan }
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan for (i = 0; i < fields_count; i++)
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher mail_cache_decision_lookup(view, seq, fields[i]);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher data = buffer_get_modifiable_data(ctx.data, &size);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher size /= sizeof(*data);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan qsort(data, size, sizeof(*data), header_lookup_data_cmp);
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* then start filling dest buffer from the headers */
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher for (i = 0; i < size; i++) {
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher start = CONST_PTR_OFFSET(cache->data, data[i].data->offset);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan end = start + data[i].data->data_size;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan for (p = start; p != end; p++) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (*p == '\n' &&
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher (p+1 == end || (p[1] != ' ' && p[1] != '\t'))) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan p++;
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan break;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher }
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher }
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher hdr_size = (size_t)(p - start);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan data[i].data->offset += hdr_size;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher data[i].data->data_size -= hdr_size;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher buffer_append(dest, start, hdr_size);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan t_pop();
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher return 1;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan