mail-index-sync-keywords.c revision 8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765c
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2004-2013 Dovecot authors, see the included COPYING file */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "array.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "buffer.h"
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen#include "mail-index-modseq.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "mail-index-view-private.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "mail-index-sync-private.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "mail-transaction-log.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainenstatic bool
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainenkeyword_lookup(struct mail_index_sync_map_ctx *ctx,
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen const char *keyword_name, unsigned int *idx_r)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen struct mail_index_map *map = ctx->view->map;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen const unsigned int *idx_map;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen unsigned int i, count, keyword_idx;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
8f7b00599e73fe71b1d2c6c65f8ae98aac1b23fbTimo Sirainen if (array_is_created(&map->keyword_idx_map) &&
8f7b00599e73fe71b1d2c6c65f8ae98aac1b23fbTimo Sirainen mail_index_keyword_lookup(ctx->view->index, keyword_name,
6825360d446542046757b06064282301c4c6b27cTimo Sirainen &keyword_idx)) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* FIXME: slow. maybe create index -> file mapping as well */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen idx_map = array_get(&map->keyword_idx_map, &count);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen for (i = 0; i < count; i++) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (idx_map[i] == keyword_idx) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen *idx_r = i;
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen return TRUE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen return FALSE;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenstatic buffer_t *
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenkeywords_get_header_buf(struct mail_index_map *map,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_index_ext *ext,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen unsigned int new_count, unsigned int *keywords_count_r,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen size_t *rec_offset_r, size_t *name_offset_root_r,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen size_t *name_offset_r)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_t *buf;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_index_keyword_header *kw_hdr;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_index_keyword_header_rec *kw_rec;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const char *name;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_keyword_header new_kw_hdr;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen uint32_t offset;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen kw_rec = (const void *)(kw_hdr + 1);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen name = (const char *)(kw_rec + kw_hdr->keywords_count);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (kw_hdr->keywords_count == 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return NULL;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
d1c2f6dd39ebb7f6b220ae2afda1162ba72ab43bTimo Sirainen i_assert((size_t)(name - (const char *)kw_hdr) < ext->hdr_size);
d1c2f6dd39ebb7f6b220ae2afda1162ba72ab43bTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen new_kw_hdr = *kw_hdr;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen new_kw_hdr.keywords_count += new_count;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen *keywords_count_r = new_kw_hdr.keywords_count;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen offset = kw_rec[kw_hdr->keywords_count-1].name_offset;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen offset += strlen(name + offset) + 1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 512);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_append(buf, &new_kw_hdr, sizeof(new_kw_hdr));
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_append(buf, kw_rec, sizeof(*kw_rec) * kw_hdr->keywords_count);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen *rec_offset_r = buf->used;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_write(buf, buf->used + sizeof(*kw_rec) * new_count,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen name, offset);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen *name_offset_root_r = buf->used;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen *name_offset_r = offset;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return buf;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainenstatic void keywords_ext_register(struct mail_index_sync_map_ctx *ctx,
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen uint32_t ext_map_idx, uint32_t reset_id,
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen uint32_t hdr_size, uint32_t keywords_count)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
02752bc8d64df8cd361f464e55422f7b3f2f143eTimo Sirainen buffer_t ext_intro_buf;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_transaction_ext_intro *u;
02752bc8d64df8cd361f464e55422f7b3f2f143eTimo Sirainen unsigned char ext_intro_data[sizeof(*u) +
02752bc8d64df8cd361f464e55422f7b3f2f143eTimo Sirainen sizeof(MAIL_INDEX_EXT_KEYWORDS)-1];
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen i_assert(keywords_count > 0);
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen buffer_create_from_data(&ext_intro_buf, ext_intro_data,
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen sizeof(ext_intro_data));
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
02752bc8d64df8cd361f464e55422f7b3f2f143eTimo Sirainen u = buffer_append_space_unsafe(&ext_intro_buf, sizeof(*u));
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen u->ext_id = ext_map_idx;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen u->reset_id = reset_id;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen u->hdr_size = hdr_size;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen u->record_size = (keywords_count + CHAR_BIT - 1) / CHAR_BIT;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if ((u->record_size % 4) != 0) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* since we aren't properly aligned anyway,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen reserve one extra byte for future */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen u->record_size++;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen u->record_align = 1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen if (ext_map_idx == (uint32_t)-1) {
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen u->name_size = strlen(MAIL_INDEX_EXT_KEYWORDS);
02752bc8d64df8cd361f464e55422f7b3f2f143eTimo Sirainen buffer_append(&ext_intro_buf, MAIL_INDEX_EXT_KEYWORDS,
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen u->name_size);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
08f03325b34becc0e9f2bb130ac013bf54b9cca3Timo Sirainen ctx->internal_update = TRUE;
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen if (mail_index_sync_ext_intro(ctx, u) < 0)
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen i_panic("Keyword extension growing failed");
08f03325b34becc0e9f2bb130ac013bf54b9cca3Timo Sirainen ctx->internal_update = FALSE;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainenstatic void
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainenkeywords_header_add(struct mail_index_sync_map_ctx *ctx,
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen const char *keyword_name, unsigned int *keyword_idx_r)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
08f03325b34becc0e9f2bb130ac013bf54b9cca3Timo Sirainen struct mail_index_map *map;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_index_ext *ext = NULL;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_keyword_header *kw_hdr;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_keyword_header_rec kw_rec;
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen uint32_t ext_map_idx;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_t *buf = NULL;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen size_t keyword_len, rec_offset, name_offset, name_offset_root;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen unsigned int keywords_count;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* if we crash in the middle of writing the header, the
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen keywords are more or less corrupted. avoid that by
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen making sure the header is updated atomically. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen map = mail_index_sync_get_atomic_map(ctx);
055a42c6987f93fb88291f64813dfceb1b25895dTimo Sirainen
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen if (!mail_index_map_lookup_ext(map, MAIL_INDEX_EXT_KEYWORDS,
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen &ext_map_idx))
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen ext_map_idx = (uint32_t)-1;
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen else {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen /* update existing header */
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen ext = array_idx(&map->extensions, ext_map_idx);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen buf = keywords_get_header_buf(map, ext, 1, &keywords_count,
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen &rec_offset, &name_offset_root,
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen &name_offset);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (buf == NULL) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* create new / replace broken header */
d721a5f55d3a4a100ae593ab85fa13661d2134abTimo Sirainen const unsigned int initial_keywords_count = 1;
d721a5f55d3a4a100ae593ab85fa13661d2134abTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 512);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen kw_hdr = buffer_append_space_unsafe(buf, sizeof(*kw_hdr));
d721a5f55d3a4a100ae593ab85fa13661d2134abTimo Sirainen kw_hdr->keywords_count = initial_keywords_count;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen keywords_count = kw_hdr->keywords_count;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen rec_offset = buf->used;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen name_offset_root = rec_offset +
d721a5f55d3a4a100ae593ab85fa13661d2134abTimo Sirainen initial_keywords_count * sizeof(kw_rec);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen name_offset = 0;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen /* add the keyword */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen memset(&kw_rec, 0, sizeof(kw_rec));
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen kw_rec.name_offset = name_offset;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
bf045aa2e9c3846ecde84db303db6588b173bbaeTimo Sirainen keyword_len = strlen(keyword_name) + 1;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen buffer_write(buf, rec_offset, &kw_rec, sizeof(kw_rec));
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen buffer_write(buf, name_offset_root, keyword_name, keyword_len);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen rec_offset += sizeof(kw_rec);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen kw_rec.name_offset += keyword_len;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen name_offset_root += keyword_len;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if ((buf->used % 4) != 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_append_zero(buf, 4 - (buf->used % 4));
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (ext == NULL || buf->used > ext->hdr_size ||
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen (uint32_t)ext->record_size * CHAR_BIT < keywords_count) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* if we need to grow the buffer, add some padding */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_append_zero(buf, 128);
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen keywords_ext_register(ctx, ext_map_idx,
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen ext == NULL ? 0 : ext->reset_id,
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen buf->used, keywords_count);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* map may have changed */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen map = ctx->view->map;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen if (!mail_index_map_lookup_ext(map, MAIL_INDEX_EXT_KEYWORDS,
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen &ext_map_idx))
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen i_unreached();
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen ext = array_idx(&map->extensions, ext_map_idx);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_assert(ext->hdr_size == buf->used);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen buffer_copy(map->hdr_copy_buf, ext->hdr_offset, buf, 0, buf->used);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen map->hdr_base = map->hdr_copy_buf->data;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen if (mail_index_map_parse_keywords(map) < 0)
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen i_panic("Keyword update corrupted keywords header");
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen *keyword_idx_r = keywords_count - 1;
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen i_assert(*keyword_idx_r / CHAR_BIT < ext->record_size);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainenstatic int
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenkeywords_update_records(struct mail_index_sync_map_ctx *ctx,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_index_ext *ext,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen unsigned int keyword_idx, enum modify_type type,
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen uint32_t uid1, uint32_t uid2)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct mail_index_view *view = ctx->view;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_record *rec;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen unsigned char *data, data_mask;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen unsigned int data_offset;
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen uint32_t seq1, seq2;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen i_assert(keyword_idx != UINT_MAX);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen if (!mail_index_lookup_seq_range(view, uid1, uid2, &seq1, &seq2))
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen return 1;
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen
d7c8280f58292cc292eba9209dcc9024fe96cf06Timo Sirainen view->map->rec_map->records_changed = TRUE;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen mail_index_modseq_update_keyword(ctx->modseq_ctx, keyword_idx,
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen seq1, seq2);
41bb0aa8e357876bc9a1916a37c9e3e78e5f8185Timo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen data_offset = keyword_idx / CHAR_BIT;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen data_mask = 1 << (keyword_idx % CHAR_BIT);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen i_assert(data_offset < ext->record_size);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen data_offset += ext->record_offset;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
8f7b00599e73fe71b1d2c6c65f8ae98aac1b23fbTimo Sirainen i_assert(data_offset >= sizeof(struct mail_index_record));
8f7b00599e73fe71b1d2c6c65f8ae98aac1b23fbTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen switch (type) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen case MODIFY_ADD:
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen for (seq1--; seq1 < seq2; seq1++) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, seq1);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen data = PTR_OFFSET(rec, data_offset);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen *data |= data_mask;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen break;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen case MODIFY_REMOVE:
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen data_mask = ~data_mask;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen for (seq1--; seq1 < seq2; seq1++) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, seq1);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen data = PTR_OFFSET(rec, data_offset);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen *data &= data_mask;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen break;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen default:
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen i_unreached();
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen return 1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenint mail_index_sync_keywords(struct mail_index_sync_map_ctx *ctx,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_transaction_header *hdr,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_transaction_keyword_update *rec)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen struct mail_index_view *view = ctx->view;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen const char *keyword_name;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_index_ext *ext;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen const uint32_t *uid, *end;
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen uint32_t seqset_offset, ext_map_idx;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen unsigned int keyword_idx;
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen int ret;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen i_assert(rec->name_size > 0);
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen seqset_offset = sizeof(*rec) + rec->name_size;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if ((seqset_offset % 4) != 0)
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen seqset_offset += 4 - (seqset_offset % 4);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen i_assert(seqset_offset < hdr->size);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen uid = CONST_PTR_OFFSET(rec, seqset_offset);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen end = CONST_PTR_OFFSET(rec, hdr->size);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen keyword_name = t_strndup(rec + 1, rec->name_size);
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen if (!keyword_lookup(ctx, keyword_name, &keyword_idx))
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen keywords_header_add(ctx, keyword_name, &keyword_idx);
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen /* if the keyword wasn't found, the "keywords" extension was created.
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen if it was found, the record size should already be correct, but
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen in case it isn't just fix it ourself. */
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen if (!mail_index_map_lookup_ext(view->map, MAIL_INDEX_EXT_KEYWORDS,
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen &ext_map_idx))
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen i_unreached();
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen ext = array_idx(&view->map->extensions, ext_map_idx);
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen if (keyword_idx / CHAR_BIT >= ext->record_size) {
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen if (rec->modify_type == MODIFY_REMOVE) {
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen /* nothing to do */
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen return 1;
f0559b6bd1914e9118772d49415defe3dbb1817bTimo Sirainen }
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen /* grow the record size */
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen keywords_ext_register(ctx, ext_map_idx, ext->reset_id,
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen ext->hdr_size,
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen array_count(&view->map->keyword_idx_map));
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen if (!mail_index_map_lookup_ext(view->map,
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen MAIL_INDEX_EXT_KEYWORDS,
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen &ext_map_idx))
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen i_unreached();
d051664df497582e1eb75a9f238d04b65e858db8Timo Sirainen ext = array_idx(&view->map->extensions, ext_map_idx);
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen }
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen while (uid+2 <= end) {
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen ret = keywords_update_records(ctx, ext, keyword_idx,
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen rec->modify_type,
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen uid[0], uid[1]);
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen if (ret <= 0)
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen return ret;
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen uid += 2;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return 1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainenint
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainenmail_index_sync_keywords_reset(struct mail_index_sync_map_ctx *ctx,
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen const struct mail_transaction_header *hdr,
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen const struct mail_transaction_keyword_reset *r)
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen{
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen struct mail_index_map *map = ctx->view->map;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen struct mail_index_record *rec;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen const struct mail_index_ext *ext;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen const struct mail_transaction_keyword_reset *end;
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen uint32_t ext_map_idx, seq1, seq2;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen if (!mail_index_map_lookup_ext(map, MAIL_INDEX_EXT_KEYWORDS,
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen &ext_map_idx)) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen /* nothing to do */
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen return 1;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
7ded22760598b78ee29f9418eacc0abe3fb51055Timo Sirainen ext = array_idx(&map->extensions, ext_map_idx);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen end = CONST_PTR_OFFSET(r, hdr->size);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen for (; r != end; r++) {
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen if (!mail_index_lookup_seq_range(ctx->view, r->uid1, r->uid2,
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen &seq1, &seq2))
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen continue;
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen
d7c8280f58292cc292eba9209dcc9024fe96cf06Timo Sirainen map->rec_map->records_changed = TRUE;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen mail_index_modseq_reset_keywords(ctx->modseq_ctx, seq1, seq2);
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen for (seq1--; seq1 < seq2; seq1++) {
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen rec = MAIL_INDEX_MAP_IDX(map, seq1);
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen memset(PTR_OFFSET(rec, ext->record_offset),
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen 0, ext->record_size);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen return 1;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen}