mail-index-view.c revision e49e973f363a56ad186fce372310d5ec6d83d8fa
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2003-2013 Dovecot authors, see the included COPYING file */
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen#include "lib.h"
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen#include "array.h"
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen#include "buffer.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "mail-index-view-private.h"
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen#include "mail-transaction-log.h"
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstruct mail_index_view *
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenmail_index_view_dup_private(const struct mail_index_view *src)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct mail_index_view *view;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen struct mail_index_map *map;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen view = i_new(struct mail_index_view, 1);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mail_index_view_clone(view, src);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen map = mail_index_map_clone(view->map);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen mail_index_unmap(&view->map);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen view->map = map;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen return view;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen}
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid mail_index_view_clone(struct mail_index_view *dest,
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen const struct mail_index_view *src)
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen{
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen memset(dest, 0, sizeof(*dest));
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen dest->refcount = 1;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen dest->v = src->v;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen dest->index = src->index;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (src->log_view != NULL) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen dest->log_view =
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mail_transaction_log_view_open(src->index->log);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen }
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen dest->indexid = src->indexid;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen dest->inconsistency_id = src->inconsistency_id;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen dest->map = src->map;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen if (dest->map != NULL)
4c892b0d94c5b1d6853dbe8e0b38059ea5b08ecaTimo Sirainen dest->map->refcount++;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
abc79eec93e58e0152cd1d483f37be66c26811b9Timo Sirainen dest->log_file_expunge_seq = src->log_file_expunge_seq;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen dest->log_file_expunge_offset = src->log_file_expunge_offset;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen dest->log_file_head_seq = src->log_file_head_seq;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen dest->log_file_head_offset = src->log_file_head_offset;
4c892b0d94c5b1d6853dbe8e0b38059ea5b08ecaTimo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_array_init(&dest->module_contexts,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen I_MIN(5, mail_index_module_register.id));
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen dest->index->view_count++;
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen}
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainenvoid mail_index_view_ref(struct mail_index_view *view)
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen{
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen view->refcount++;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen}
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic void view_close(struct mail_index_view *view)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(view->refcount == 0);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen i_assert(view->index->view_count > 0);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen view->index->view_count--;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen mail_transaction_log_view_close(&view->log_view);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (array_is_created(&view->syncs_hidden))
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen array_free(&view->syncs_hidden);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen mail_index_unmap(&view->map);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (array_is_created(&view->map_refs)) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen mail_index_view_unref_maps(view);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen array_free(&view->map_refs);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen array_free(&view->module_contexts);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen i_free(view);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenbool mail_index_view_is_inconsistent(struct mail_index_view *view)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (view->index->indexid != view->indexid ||
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen view->index->inconsistency_id != view->inconsistency_id)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen view->inconsistent = TRUE;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen return view->inconsistent;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstruct mail_index *mail_index_view_get_index(struct mail_index_view *view)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen return view->index;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenunsigned int
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenmail_index_view_get_transaction_count(struct mail_index_view *view)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(view->transactions >= 0);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return view->transactions;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid mail_index_view_transaction_ref(struct mail_index_view *view)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen view->transactions++;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid mail_index_view_transaction_unref(struct mail_index_view *view)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen i_assert(view->transactions > 0);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen view->transactions--;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenstatic void mail_index_view_ref_map(struct mail_index_view *view,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen struct mail_index_map *map)
65889a7d8c059e2feb159aee1633b847aba84831Timo Sirainen{
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen struct mail_index_map *const *maps;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen unsigned int i, count;
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen if (array_is_created(&view->map_refs)) {
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen maps = array_get(&view->map_refs, &count);
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen /* if map is already referenced, do nothing */
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen for (i = 0; i < count; i++) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (maps[i] == map)
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen return;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen }
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen } else {
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen i_array_init(&view->map_refs, 4);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen }
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen /* reference the given mapping. the reference is dropped when the view
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen is synchronized or closed. */
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen map->refcount++;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen array_append(&view->map_refs, &map, 1);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen}
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainenvoid mail_index_view_unref_maps(struct mail_index_view *view)
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen{
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen struct mail_index_map **maps;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen unsigned int i, count;
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen if (!array_is_created(&view->map_refs))
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen return;
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen maps = array_get_modifiable(&view->map_refs, &count);
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen for (i = 0; i < count; i++)
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen mail_index_unmap(&maps[i]);
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen array_clear(&view->map_refs);
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen}
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainenstatic uint32_t view_get_messages_count(struct mail_index_view *view)
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen{
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen return view->map->hdr.messages_count;
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen}
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainenstatic const struct mail_index_header *
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainenview_get_header(struct mail_index_view *view)
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen{
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen return &view->map->hdr;
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen}
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainenstatic const struct mail_index_record *
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenview_lookup_full(struct mail_index_view *view, uint32_t seq,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen struct mail_index_map **map_r, bool *expunged_r)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen static struct mail_index_record broken_rec;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct mail_index_map *map;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen const struct mail_index_record *rec, *head_rec;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(view));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen /* look up the record */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, seq-1);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (unlikely(rec->uid == 0)) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (!view->inconsistent) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mail_index_set_error(view->index,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen "Corrupted Index file %s: Record [%u].uid=0",
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen view->index->filepath, seq);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen (void)mail_index_fsck(view->index);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen view->inconsistent = TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* we'll need to return something so the caller doesn't crash */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *map_r = view->map;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (expunged_r != NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *expunged_r = TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return &broken_rec;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (view->map == view->index->map) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* view's mapping is latest. we can use it directly. */
a2150da2dc906c26a26219cbefbe28a119aafee2Timo Sirainen *map_r = view->map;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (expunged_r != NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *expunged_r = FALSE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return rec;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* look up the record from head mapping. it may contain some changes.
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen start looking up from the same sequence as in the old view.
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if there are no expunges, it's there. otherwise it's somewhere
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen before (since records can't be inserted).
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen usually there are only a few expunges, so just going downwards from
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen our initial sequence position is probably faster than binary
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen search. */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (seq > view->index->map->hdr.messages_count)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen seq = view->index->map->hdr.messages_count;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (seq == 0) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* everything is expunged from head. use the old record. */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *map_r = view->map;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (expunged_r != NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *expunged_r = TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return rec;
88b0427d90f1d3c2c5fb3171e53a505c46e2c39dTimo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen map = view->index->map;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen do {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen seq--;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen head_rec = MAIL_INDEX_MAP_IDX(map, seq);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen if (head_rec->uid <= rec->uid)
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen break;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen } while (seq > 0);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen if (head_rec->uid == rec->uid) {
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen /* found it. use it. reference the index mapping so that the
94ce7e7700cda14a8342cb08e7285507b4b531daTimo Sirainen returned record doesn't get invalidated after next sync. */
94ce7e7700cda14a8342cb08e7285507b4b531daTimo Sirainen mail_index_view_ref_map(view, view->index->map);
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen *map_r = view->index->map;
94ce7e7700cda14a8342cb08e7285507b4b531daTimo Sirainen if (expunged_r != NULL)
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen *expunged_r = FALSE;
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen return head_rec;
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen } else {
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen /* expuned from head. use the old record. */
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen *map_r = view->map;
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen if (expunged_r != NULL)
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen *expunged_r = TRUE;
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen return rec;
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen }
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen}
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainenstatic void view_lookup_uid(struct mail_index_view *view, uint32_t seq,
94ce7e7700cda14a8342cb08e7285507b4b531daTimo Sirainen uint32_t *uid_r)
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen{
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(view));
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen *uid_r = MAIL_INDEX_MAP_IDX(view->map, seq-1)->uid;
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen}
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainenstatic void view_lookup_seq_range(struct mail_index_view *view,
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen uint32_t first_uid, uint32_t last_uid,
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen uint32_t *first_seq_r, uint32_t *last_seq_r)
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen{
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen mail_index_map_lookup_seq_range(view->map, first_uid, last_uid,
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen first_seq_r, last_seq_r);
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen}
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainenstatic void view_lookup_first(struct mail_index_view *view,
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen enum mail_flags flags, uint8_t flags_mask,
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen uint32_t *seq_r)
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen{
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen#define LOW_UPDATE(x) \
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen STMT_START { if ((x) > low_uid) low_uid = x; } STMT_END
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen const struct mail_index_header *hdr = &view->map->hdr;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen const struct mail_index_record *rec;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen uint32_t seq, seq2, low_uid = 1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen *seq_r = 0;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen if ((flags_mask & MAIL_SEEN) != 0 && (flags & MAIL_SEEN) == 0)
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen LOW_UPDATE(hdr->first_unseen_uid_lowwater);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen if ((flags_mask & MAIL_DELETED) != 0 && (flags & MAIL_DELETED) != 0)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen LOW_UPDATE(hdr->first_deleted_uid_lowwater);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (low_uid == 1)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen seq = 1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen else {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (!mail_index_lookup_seq_range(view, low_uid, hdr->next_uid,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen &seq, &seq2))
d2c853636ec2d99c9f96da877ff520a3b86a18baTimo Sirainen return;
d2c853636ec2d99c9f96da877ff520a3b86a18baTimo Sirainen }
d2c853636ec2d99c9f96da877ff520a3b86a18baTimo Sirainen
d2c853636ec2d99c9f96da877ff520a3b86a18baTimo Sirainen i_assert(hdr->messages_count <= view->map->rec_map->records_count);
72276c90ac2a38c9db7b4458acd3a2f5b61892bbTimo Sirainen for (; seq <= hdr->messages_count; seq++) {
d2c853636ec2d99c9f96da877ff520a3b86a18baTimo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, seq-1);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if ((rec->flags & flags_mask) == (uint8_t)flags) {
7afde4b6c600f86ef6f742ea3b01640075ce16a2Timo Sirainen *seq_r = seq;
7afde4b6c600f86ef6f742ea3b01640075ce16a2Timo Sirainen break;
5e751dbaecf7c337abc149f328c4a13ee5c15134Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
72276c90ac2a38c9db7b4458acd3a2f5b61892bbTimo Sirainenstatic void
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainenmail_index_data_lookup_keywords(struct mail_index_map *map,
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen const unsigned char *data,
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen ARRAY_TYPE(keyword_indexes) *keyword_idx)
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen{
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen const unsigned int *keyword_idx_map;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen unsigned int i, j, keyword_count, index_idx;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen uint32_t idx, hdr_size;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen uint16_t record_size, record_align;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen array_clear(keyword_idx);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen if (data == NULL) {
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen /* no keywords at all in index */
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen return;
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen }
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen (void)mail_index_ext_get_size(map, map->index->keywords_ext_id,
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen &hdr_size, &record_size,
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen &record_align);
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen /* keyword_idx_map[] contains file => index keyword mapping */
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen if (!array_is_created(&map->keyword_idx_map))
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen return;
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen keyword_idx_map = array_get(&map->keyword_idx_map, &keyword_count);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen for (i = 0; i < record_size; i++) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* first do the quick check to see if there's keywords at all */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (data[i] == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen continue;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen idx = i * CHAR_BIT;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (j = 0; j < CHAR_BIT; j++, idx++) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if ((data[i] & (1 << j)) == 0)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen continue;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (idx >= keyword_count) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* extra bits set in keyword bytes.
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen shouldn't happen, but just ignore. */
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen index_idx = keyword_idx_map[idx];
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen array_append(keyword_idx, &index_idx, 1);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainenstatic void view_lookup_keywords(struct mail_index_view *view, uint32_t seq,
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen ARRAY_TYPE(keyword_indexes) *keyword_idx)
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen{
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen struct mail_index_map *map;
d2c853636ec2d99c9f96da877ff520a3b86a18baTimo Sirainen const void *data;
d2c853636ec2d99c9f96da877ff520a3b86a18baTimo Sirainen
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen mail_index_lookup_ext_full(view, seq, view->index->keywords_ext_id,
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainen &map, &data, NULL);
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainen mail_index_data_lookup_keywords(map, data, keyword_idx);
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainen}
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainenstatic const void *
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainenview_map_lookup_ext_full(struct mail_index_map *map,
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen const struct mail_index_record *rec, uint32_t ext_id)
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen{
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen const struct mail_index_ext *ext;
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen uint32_t idx;
b16ee3cbbcd18cb86f2f73b5cc163ebfb995ffafTimo Sirainen
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen if (!mail_index_map_get_ext_idx(map, ext_id, &idx))
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen return NULL;
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen ext = array_idx(&map->extensions, idx);
b16ee3cbbcd18cb86f2f73b5cc163ebfb995ffafTimo Sirainen return ext->record_offset == 0 ? NULL :
b16ee3cbbcd18cb86f2f73b5cc163ebfb995ffafTimo Sirainen CONST_PTR_OFFSET(rec, ext->record_offset);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen}
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenstatic void
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenview_lookup_ext_full(struct mail_index_view *view, uint32_t seq,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen uint32_t ext_id, struct mail_index_map **map_r,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen const void **data_r, bool *expunged_r)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen{
const struct mail_index_record *rec;
rec = view->v.lookup_full(view, seq, map_r, expunged_r);
*data_r = view_map_lookup_ext_full(*map_r, rec, ext_id);
}
static void view_get_header_ext(struct mail_index_view *view,
struct mail_index_map *map, uint32_t ext_id,
const void **data_r, size_t *data_size_r)
{
const struct mail_index_ext *ext;
uint32_t idx;
if (map == NULL) {
/* no mapping given, use head mapping */
map = view->index->map;
}
if (!mail_index_map_get_ext_idx(map, ext_id, &idx)) {
/* extension doesn't exist in this index file */
*data_r = NULL;
*data_size_r = 0;
return;
}
ext = array_idx(&map->extensions, idx);
*data_r = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
*data_size_r = ext->hdr_size;
}
static bool view_ext_get_reset_id(struct mail_index_view *view ATTR_UNUSED,
struct mail_index_map *map,
uint32_t ext_id, uint32_t *reset_id_r)
{
const struct mail_index_ext *ext;
uint32_t idx;
if (!mail_index_map_get_ext_idx(map, ext_id, &idx))
return FALSE;
ext = array_idx(&map->extensions, idx);
*reset_id_r = ext->reset_id;
return TRUE;
}
void mail_index_view_close(struct mail_index_view **_view)
{
struct mail_index_view *view = *_view;
*_view = NULL;
if (--view->refcount > 0)
return;
i_assert(view->transactions == 0);
view->v.close(view);
}
uint32_t mail_index_view_get_messages_count(struct mail_index_view *view)
{
return view->v.get_messages_count(view);
}
const struct mail_index_header *
mail_index_get_header(struct mail_index_view *view)
{
return view->v.get_header(view);
}
const struct mail_index_record *
mail_index_lookup(struct mail_index_view *view, uint32_t seq)
{
struct mail_index_map *map;
return mail_index_lookup_full(view, seq, &map);
}
const struct mail_index_record *
mail_index_lookup_full(struct mail_index_view *view, uint32_t seq,
struct mail_index_map **map_r)
{
return view->v.lookup_full(view, seq, map_r, NULL);
}
bool mail_index_is_expunged(struct mail_index_view *view, uint32_t seq)
{
struct mail_index_map *map;
bool expunged;
(void)view->v.lookup_full(view, seq, &map, &expunged);
return expunged;
}
void mail_index_map_lookup_keywords(struct mail_index_map *map, uint32_t seq,
ARRAY_TYPE(keyword_indexes) *keyword_idx)
{
const struct mail_index_ext *ext;
const struct mail_index_record *rec;
const void *data;
uint32_t idx;
if (!mail_index_map_get_ext_idx(map, map->index->keywords_ext_id, &idx))
data = NULL;
else {
rec = MAIL_INDEX_MAP_IDX(map, seq-1);
ext = array_idx(&map->extensions, idx);
data = ext->record_offset == 0 ? NULL :
CONST_PTR_OFFSET(rec, ext->record_offset);
}
mail_index_data_lookup_keywords(map, data, keyword_idx);
}
void mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq,
ARRAY_TYPE(keyword_indexes) *keyword_idx)
{
view->v.lookup_keywords(view, seq, keyword_idx);
}
void mail_index_lookup_view_flags(struct mail_index_view *view, uint32_t seq,
enum mail_flags *flags_r,
ARRAY_TYPE(keyword_indexes) *keyword_idx)
{
const struct mail_index_record *rec;
const unsigned char *keyword_data;
i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(view));
rec = MAIL_INDEX_MAP_IDX(view->map, seq-1);
*flags_r = rec->flags;
keyword_data = view_map_lookup_ext_full(view->map, rec,
view->index->keywords_ext_id);
mail_index_data_lookup_keywords(view->map, keyword_data, keyword_idx);
}
void mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq,
uint32_t *uid_r)
{
view->v.lookup_uid(view, seq, uid_r);
}
bool mail_index_lookup_seq_range(struct mail_index_view *view,
uint32_t first_uid, uint32_t last_uid,
uint32_t *first_seq_r, uint32_t *last_seq_r)
{
view->v.lookup_seq_range(view, first_uid, last_uid,
first_seq_r, last_seq_r);
return *first_seq_r != 0;
}
bool mail_index_lookup_seq(struct mail_index_view *view,
uint32_t uid, uint32_t *seq_r)
{
view->v.lookup_seq_range(view, uid, uid, seq_r, seq_r);
return *seq_r != 0;
}
void mail_index_lookup_first(struct mail_index_view *view,
enum mail_flags flags, uint8_t flags_mask,
uint32_t *seq_r)
{
view->v.lookup_first(view, flags, flags_mask, seq_r);
}
void mail_index_lookup_ext(struct mail_index_view *view, uint32_t seq,
uint32_t ext_id, const void **data_r,
bool *expunged_r)
{
struct mail_index_map *map;
mail_index_lookup_ext_full(view, seq, ext_id, &map, data_r, expunged_r);
}
void mail_index_lookup_ext_full(struct mail_index_view *view, uint32_t seq,
uint32_t ext_id, struct mail_index_map **map_r,
const void **data_r, bool *expunged_r)
{
view->v.lookup_ext_full(view, seq, ext_id, map_r, data_r, expunged_r);
}
void mail_index_get_header_ext(struct mail_index_view *view, uint32_t ext_id,
const void **data_r, size_t *data_size_r)
{
view->v.get_header_ext(view, NULL, ext_id, data_r, data_size_r);
}
void mail_index_map_get_header_ext(struct mail_index_view *view,
struct mail_index_map *map, uint32_t ext_id,
const void **data_r, size_t *data_size_r)
{
view->v.get_header_ext(view, map, ext_id, data_r, data_size_r);
}
bool mail_index_ext_get_reset_id(struct mail_index_view *view,
struct mail_index_map *map,
uint32_t ext_id, uint32_t *reset_id_r)
{
return view->v.ext_get_reset_id(view, map, ext_id, reset_id_r);
}
void mail_index_ext_get_size(struct mail_index_map *map, uint32_t ext_id,
uint32_t *hdr_size_r, uint16_t *record_size_r,
uint16_t *record_align_r)
{
const struct mail_index_ext *ext;
uint32_t idx;
i_assert(map != NULL);
if (!mail_index_map_get_ext_idx(map, ext_id, &idx)) {
/* extension doesn't exist in this index file */
*hdr_size_r = 0;
*record_size_r = 0;
*record_align_r = 0;
return;
}
ext = array_idx(&map->extensions, idx);
*hdr_size_r = ext->hdr_size;
*record_size_r = ext->record_size;
*record_align_r = ext->record_align;
}
static struct mail_index_view_vfuncs view_vfuncs = {
view_close,
view_get_messages_count,
view_get_header,
view_lookup_full,
view_lookup_uid,
view_lookup_seq_range,
view_lookup_first,
view_lookup_keywords,
view_lookup_ext_full,
view_get_header_ext,
view_ext_get_reset_id
};
struct mail_index_view *
mail_index_view_open_with_map(struct mail_index *index,
struct mail_index_map *map)
{
struct mail_index_view *view;
view = i_new(struct mail_index_view, 1);
view->refcount = 1;
view->v = view_vfuncs;
view->index = index;
view->log_view = mail_transaction_log_view_open(index->log);
view->indexid = index->indexid;
view->inconsistency_id = index->inconsistency_id;
view->map = map;
view->map->refcount++;
view->log_file_expunge_seq = view->log_file_head_seq =
view->map->hdr.log_file_seq;
view->log_file_expunge_offset = view->log_file_head_offset =
view->map->hdr.log_file_head_offset;
i_array_init(&view->module_contexts,
I_MIN(5, mail_index_module_register.id));
index->view_count++;
return view;
}
struct mail_index_view *mail_index_view_open(struct mail_index *index)
{
return mail_index_view_open_with_map(index, index->map);
}
const struct mail_index_ext *
mail_index_view_get_ext(struct mail_index_view *view, uint32_t ext_id)
{
uint32_t idx;
if (!mail_index_map_get_ext_idx(view->map, ext_id, &idx))
return NULL;
return array_idx(&view->map->extensions, idx);
}