mail-index-sync-keywords.c revision 02752bc8d64df8cd361f464e55422f7b3f2f143e
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher/* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan#include "lib.h"
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan#include "array.h"
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher#include "buffer.h"
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek#include "mail-index-modseq.h"
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek#include "mail-index-view-private.h"
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek#include "mail-index-sync-private.h"
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek#include "mail-transaction-log.h"
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic bool
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozekkeyword_lookup(struct mail_index_sync_map_ctx *ctx,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const char *keyword_name, unsigned int *idx_r)
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek{
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek struct mail_index_map *map = ctx->view->map;
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher const unsigned int *idx_map;
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek unsigned int i, count, keyword_idx;
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher if (array_is_created(&map->keyword_idx_map) &&
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan mail_index_keyword_lookup(ctx->view->index, keyword_name,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan &keyword_idx)) {
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher /* FIXME: slow. maybe create index -> file mapping as well */
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher idx_map = array_get(&map->keyword_idx_map, &count);
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek for (i = 0; i < count; i++) {
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek if (idx_map[i] == keyword_idx) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan *idx_r = i;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher return TRUE;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher }
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher }
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek }
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek return FALSE;
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek}
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozekstatic buffer_t *
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozekkeywords_get_header_buf(struct mail_index_map *map,
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek const struct mail_index_ext *ext,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan unsigned int new_count, unsigned int *keywords_count_r,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan size_t *rec_offset_r, size_t *name_offset_root_r,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan size_t *name_offset_r)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_t *buf;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const struct mail_index_keyword_header *kw_hdr;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const struct mail_index_keyword_header_rec *kw_rec;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const char *name;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher struct mail_index_keyword_header new_kw_hdr;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher uint32_t offset;
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek kw_rec = (const void *)(kw_hdr + 1);
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek name = (const char *)(kw_rec + kw_hdr->keywords_count);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (kw_hdr->keywords_count == 0)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan return NULL;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_assert((size_t)(name - (const char *)kw_hdr) < ext->hdr_size);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan new_kw_hdr = *kw_hdr;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan new_kw_hdr.keywords_count += new_count;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher *keywords_count_r = new_kw_hdr.keywords_count;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan offset = kw_rec[kw_hdr->keywords_count-1].name_offset;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher offset += strlen(name + offset) + 1;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher buf = buffer_create_dynamic(pool_datastack_create(), 512);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_append(buf, &new_kw_hdr, sizeof(new_kw_hdr));
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher buffer_append(buf, kw_rec, sizeof(*kw_rec) * kw_hdr->keywords_count);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher *rec_offset_r = buf->used;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher buffer_write(buf, buf->used + sizeof(*kw_rec) * new_count,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan name, offset);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher *name_offset_root_r = buf->used;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek *name_offset_r = offset;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher return buf;
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek}
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozekstatic void keywords_ext_register(struct mail_index_sync_map_ctx *ctx,
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek uint32_t ext_map_idx, uint32_t reset_id,
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek uint32_t hdr_size, uint32_t keywords_count)
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_t ext_intro_buf;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct mail_transaction_ext_intro *u;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan unsigned char ext_intro_data[sizeof(*u) +
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher sizeof(MAIL_INDEX_EXT_KEYWORDS)-1];
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_assert(keywords_count > 0);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_create_data(&ext_intro_buf, ext_intro_data,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan sizeof(ext_intro_data));
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan u = buffer_append_space_unsafe(&ext_intro_buf, sizeof(*u));
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan u->ext_id = ext_map_idx;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher u->reset_id = reset_id;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek u->hdr_size = hdr_size;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher u->record_size = (keywords_count + CHAR_BIT - 1) / CHAR_BIT;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if ((u->record_size % 4) != 0) {
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek /* since we aren't properly aligned anyway,
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek reserve one extra byte for future */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan u->record_size++;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan u->record_align = 1;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (ext_map_idx == (uint32_t)-1) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan u->name_size = strlen(MAIL_INDEX_EXT_KEYWORDS);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher buffer_append(&ext_intro_buf, MAIL_INDEX_EXT_KEYWORDS,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher u->name_size);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher ctx->internal_update = TRUE;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (mail_index_sync_ext_intro(ctx, u) < 0)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher i_panic("Keyword extension growing failed");
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan ctx->internal_update = FALSE;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherstatic void
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherkeywords_header_add(struct mail_index_sync_map_ctx *ctx,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const char *keyword_name, unsigned int *keyword_idx_r)
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher{
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher struct mail_index_map *map;
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan const struct mail_index_ext *ext = NULL;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct mail_index_keyword_header *kw_hdr;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher struct mail_index_keyword_header_rec kw_rec;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan uint32_t ext_map_idx;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_t *buf = NULL;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher size_t keyword_len, rec_offset, name_offset, name_offset_root;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher unsigned int keywords_count;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher /* if we crash in the middle of writing the header, the
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher keywords are more or less corrupted. avoid that by
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan making sure the header is updated atomically. */
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher map = mail_index_sync_get_atomic_map(ctx);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (!mail_index_map_lookup_ext(map, MAIL_INDEX_EXT_KEYWORDS,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher &ext_map_idx))
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher ext_map_idx = (uint32_t)-1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan else {
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher /* update existing header */
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher ext = array_idx(&map->extensions, ext_map_idx);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buf = keywords_get_header_buf(map, ext, 1, &keywords_count,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher &rec_offset, &name_offset_root,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan &name_offset);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (buf == NULL) {
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher /* create new / replace broken header */
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher buf = buffer_create_dynamic(pool_datastack_create(), 512);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek kw_hdr = buffer_append_space_unsafe(buf, sizeof(*kw_hdr));
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek kw_hdr->keywords_count = 1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan keywords_count = kw_hdr->keywords_count;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan rec_offset = buf->used;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher name_offset_root = rec_offset +
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher kw_hdr->keywords_count * sizeof(kw_rec);
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek name_offset = 0;
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* add the keyword */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan memset(&kw_rec, 0, sizeof(kw_rec));
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher kw_rec.name_offset = name_offset;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan keyword_len = strlen(keyword_name) + 1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_write(buf, rec_offset, &kw_rec, sizeof(kw_rec));
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_write(buf, name_offset_root, keyword_name, keyword_len);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan rec_offset += sizeof(kw_rec);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan kw_rec.name_offset += keyword_len;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan name_offset_root += keyword_len;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if ((buf->used % 4) != 0)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan buffer_append_zero(buf, 4 - (buf->used % 4));
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek if (ext == NULL || buf->used > ext->hdr_size ||
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek (uint32_t)ext->record_size * CHAR_BIT < keywords_count) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek /* if we need to grow the buffer, add some padding */
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek buffer_append_zero(buf, 128);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan keywords_ext_register(ctx, ext_map_idx,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan ext == NULL ? 0 : ext->reset_id,
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek buf->used, keywords_count);
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek /* map may have changed */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan map = ctx->view->map;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (!mail_index_map_lookup_ext(map, MAIL_INDEX_EXT_KEYWORDS,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan &ext_map_idx))
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_unreached();
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan ext = array_idx(&map->extensions, ext_map_idx);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher i_assert(ext->hdr_size == buf->used);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher }
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan buffer_copy(map->hdr_copy_buf, ext->hdr_offset, buf, 0, buf->used);
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan map->hdr_base = map->hdr_copy_buf->data;
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher if (mail_index_map_parse_keywords(map) < 0)
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher i_panic("Keyword update corrupted keywords header");
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher *keyword_idx_r = keywords_count - 1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_assert(*keyword_idx_r / CHAR_BIT < ext->record_size);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic int
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivankeywords_update_records(struct mail_index_sync_map_ctx *ctx,
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan const struct mail_index_ext *ext,
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan unsigned int keyword_idx, enum modify_type type,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan uint32_t uid1, uint32_t uid2)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher{
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct mail_index_view *view = ctx->view;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct mail_index_record *rec;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan unsigned char *data, data_mask;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher unsigned int data_offset;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan uint32_t seq1, seq2;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek i_assert(keyword_idx != (unsigned int)-1);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (!mail_index_lookup_seq_range(view, uid1, uid2, &seq1, &seq2))
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher return 1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan mail_index_sync_write_seq_update(ctx, seq1, seq2);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan mail_index_modseq_update_keyword(ctx->modseq_ctx, keyword_idx,
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan seq1, seq2);
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher data_offset = keyword_idx / CHAR_BIT;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan data_mask = 1 << (keyword_idx % CHAR_BIT);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher i_assert(data_offset < ext->record_size);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan data_offset += ext->record_offset;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_assert(data_offset >= sizeof(struct mail_index_record));
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan switch (type) {
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan case MODIFY_ADD:
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan for (seq1--; seq1 < seq2; seq1++) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan rec = MAIL_INDEX_MAP_IDX(view->map, seq1);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher data = PTR_OFFSET(rec, data_offset);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher *data |= data_mask;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek }
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek break;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek case MODIFY_REMOVE:
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek data_mask = ~data_mask;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek for (seq1--; seq1 < seq2; seq1++) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek rec = MAIL_INDEX_MAP_IDX(view->map, seq1);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek data = PTR_OFFSET(rec, data_offset);
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek *data &= data_mask;
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek }
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek break;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek default:
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek i_unreached();
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek }
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek return 1;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek}
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekint mail_index_sync_keywords(struct mail_index_sync_map_ctx *ctx,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek const struct mail_transaction_header *hdr,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek const struct mail_transaction_keyword_update *rec)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek{
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek struct mail_index_view *view = ctx->view;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek const char *keyword_name;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek const struct mail_index_ext *ext;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek const uint32_t *uid, *end;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek uint32_t seqset_offset, ext_map_idx;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek unsigned int keyword_idx;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek int ret;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek seqset_offset = sizeof(*rec) + rec->name_size;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek if ((seqset_offset % 4) != 0)
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek seqset_offset += 4 - (seqset_offset % 4);
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek i_assert(seqset_offset < hdr->size);
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek uid = CONST_PTR_OFFSET(rec, seqset_offset);
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek end = CONST_PTR_OFFSET(rec, hdr->size);
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek keyword_name = t_strndup(rec + 1, rec->name_size);
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek if (*keyword_name == '\0') {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek mail_index_sync_set_corrupted(ctx,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek "Trying to use empty keyword");
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek return -1;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek }
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek if (!keyword_lookup(ctx, keyword_name, &keyword_idx))
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek keywords_header_add(ctx, keyword_name, &keyword_idx);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek /* if the keyword wasn't found, the "keywords" extension was created.
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek if it was found, the record size should already be correct, but
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek in case it isn't just fix it ourself. */
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek if (!mail_index_map_lookup_ext(view->map, MAIL_INDEX_EXT_KEYWORDS,
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek &ext_map_idx))
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek i_unreached();
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek ext = array_idx(&view->map->extensions, ext_map_idx);
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek if (keyword_idx / CHAR_BIT >= ext->record_size) {
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek if (rec->modify_type == MODIFY_REMOVE) {
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek /* nothing to do */
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek return 1;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek }
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* grow the record size */
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek keywords_ext_register(ctx, ext_map_idx, ext->reset_id,
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek ext->hdr_size,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek array_count(&view->map->keyword_idx_map));
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (!mail_index_map_lookup_ext(view->map,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek MAIL_INDEX_EXT_KEYWORDS,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek &ext_map_idx))
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek i_unreached();
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek ext = array_idx(&view->map->extensions, ext_map_idx);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek }
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek while (uid+2 <= end) {
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek ret = keywords_update_records(ctx, ext, keyword_idx,
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek rec->modify_type,
531661c7bb54eb71853977a64cb30f80c20b963eJakub Hrozek uid[0], uid[1]);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (ret <= 0)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek return ret;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek uid += 2;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek }
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek return 1;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek}
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekint
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekmail_index_sync_keywords_reset(struct mail_index_sync_map_ctx *ctx,
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek const struct mail_transaction_header *hdr,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek const struct mail_transaction_keyword_reset *r)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek{
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek struct mail_index_map *map = ctx->view->map;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek struct mail_index_record *rec;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek const struct mail_index_ext *ext;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek const struct mail_transaction_keyword_reset *end;
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek uint32_t ext_map_idx, seq1, seq2;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (!mail_index_map_lookup_ext(map, MAIL_INDEX_EXT_KEYWORDS,
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek &ext_map_idx)) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* nothing to do */
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek return 1;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek }
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek ext = array_idx(&map->extensions, ext_map_idx);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek end = CONST_PTR_OFFSET(r, hdr->size);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek for (; r != end; r++) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (!mail_index_lookup_seq_range(ctx->view, r->uid1, r->uid2,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek &seq1, &seq2))
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek continue;
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek mail_index_sync_write_seq_update(ctx, seq1, seq2);
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek mail_index_modseq_reset_keywords(ctx->modseq_ctx, seq1, seq2);
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek for (seq1--; seq1 < seq2; seq1++) {
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek rec = MAIL_INDEX_MAP_IDX(map, seq1);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek memset(PTR_OFFSET(rec, ext->record_offset),
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek 0, ext->record_size);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek }
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek }
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek return 1;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan}
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan