[dovecot-cvs] dovecot/src/lib-index Makefile.am, 1.23,
1.24 mail-index-private.h, 1.44,
1.45 mail-index-sync-keywords.c, NONE,
1.1 mail-index-sync-private.h, 1.17,
1.18 mail-index-sync-update.c, 1.77, 1.78 mail-index-sync.c,
1.44, 1.45 mail-index-transaction-private.h, 1.18,
1.19 mail-index-transaction.c, 1.36,
1.37 mail-index-view-sync.c, 1.33, 1.34 mail-index-view.c,
1.31, 1.32 mail-index.c, 1.183, 1.184 mail-index.h, 1.139,
1.140 mail-transaction-log.c, 1.78,
1.79 mail-transaction-log.h, 1.21,
1.22 mail-transaction-util.c, 1.21, 1.22
cras at dovecot.org
cras at dovecot.org
Sun Dec 26 11:12:43 EET 2004
- Previous message: [dovecot-cvs] dovecot/src/lib-mail mail-types.h,1.2,1.3
- Next message: [dovecot-cvs] dovecot/src/lib-storage mail-copy.c, 1.1,
1.2 mail-storage-private.h, 1.9, 1.10 mail-storage.c, 1.31,
1.32 mail-storage.h, 1.84, 1.85 proxy-mail.c, 1.6,
1.7 proxy-mailbox.c, 1.12, 1.13
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /var/lib/cvs/dovecot/src/lib-index
In directory talvi:/tmp/cvs-serv26125/lib-index
Modified Files:
Makefile.am mail-index-private.h mail-index-sync-private.h
mail-index-sync-update.c mail-index-sync.c
mail-index-transaction-private.h mail-index-transaction.c
mail-index-view-sync.c mail-index-view.c mail-index.c
mail-index.h mail-transaction-log.c mail-transaction-log.h
mail-transaction-util.c
Added Files:
mail-index-sync-keywords.c
Log Message:
Initial support for keywords. Syncing to mbox/maildir doesn't work yet.
Index: Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/Makefile.am,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- Makefile.am 7 Dec 2004 03:59:20 -0000 1.23
+++ Makefile.am 26 Dec 2004 09:12:40 -0000 1.24
@@ -19,6 +19,7 @@
mail-index-transaction-view.c \
mail-index-sync.c \
mail-index-sync-ext.c \
+ mail-index-sync-keywords.c \
mail-index-sync-update.c \
mail-index-view.c \
mail-index-view-sync.c \
Index: mail-index-private.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-private.h,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -d -r1.44 -r1.45
--- mail-index-private.h 5 Dec 2004 04:10:43 -0000 1.44
+++ mail-index-private.h 26 Dec 2004 09:12:40 -0000 1.45
@@ -60,6 +60,23 @@
/* unsigned char name[] */
};
+struct mail_keywords {
+ unsigned int count;
+ const char **keywords;
+ struct mail_index_keyword_transaction *transaction;
+};
+
+struct mail_index_keyword_header {
+ uint32_t keywords_count;
+ /* struct mail_index_keyword_header_rec[] */
+ /* char name[][] */
+};
+
+struct mail_index_keyword_header_rec {
+ uint32_t count;
+ uint32_t name_offset; /* relative to beginning of name[] */
+};
+
struct mail_index_map {
int refcount;
@@ -78,6 +95,10 @@
buffer_t *buffer;
buffer_t *hdr_copy_buf;
+ pool_t keywords_pool;
+ const char *const *keywords;
+ unsigned int keywords_count;
+
unsigned int write_to_disk:1;
};
@@ -108,13 +129,14 @@
unsigned int lock_id;
char *copy_lock_path;
struct dotlock dotlock;
- enum mail_index_lock_method lock_method;
+ enum mail_index_lock_method lock_method;
/* These are typically same as map->hdr->log_file_*, but with
mmap_disable we may have synced more than index */
uint32_t sync_log_file_seq;
uoff_t sync_log_file_offset;
+ uint32_t keywords_ext_id;
unsigned int last_grow_count;
char *error;
@@ -196,6 +218,9 @@
const struct mail_index_ext *
mail_index_view_get_ext(struct mail_index_view *view, uint32_t ext_id);
+int mail_index_map_read_keywords(struct mail_index *index,
+ struct mail_index_map *map);
+
int mail_index_fix_header(struct mail_index *index, struct mail_index_map *map,
struct mail_index_header *hdr, const char **error_r);
--- NEW FILE: mail-index-sync-keywords.c ---
/* Copyright (C) 2004 Timo Sirainen */
#include "lib.h"
#include "buffer.h"
#include "mail-index-view-private.h"
#include "mail-index-sync-private.h"
#include "mail-transaction-log.h"
static const char *const *
keywords_get_from_header(const struct mail_transaction_keyword_update *rec,
size_t size, const uint32_t **uid_r)
{
buffer_t *buf;
const unsigned char *p, *end;
const char *name;
uint32_t i, diff;
buf = buffer_create_static_hard(pool_datastack_create(),
(rec->keywords_count + 1) *
sizeof(const char *));
p = (const unsigned char *)(rec->name_size + rec->keywords_count);
end = CONST_PTR_OFFSET(rec, size);
if (p >= end)
return NULL;
for (i = 0; i < rec->keywords_count; i++) {
if (p + rec->name_size[i] >= end)
return NULL;
name = t_strndup(p, rec->name_size[i]);
buffer_append(buf, &name, sizeof(name));
p += rec->name_size[i];
}
diff = (p - (const unsigned char *)rec) % 4;
if (diff != 0)
p += 4 - diff;
*uid_r = (const uint32_t *)p;
name = NULL;
buffer_append(buf, &name, sizeof(name));
return buf->data;
}
static int keywords_get_missing(struct mail_index *index,
const char *const *keywords,
const char *const **missing_r)
{
struct mail_index_map *map = index->map;
const char *name;
buffer_t *missing_buf;
unsigned int i;
if (mail_index_map_read_keywords(index, map) < 0)
return -1;
missing_buf = buffer_create_dynamic(pool_datastack_create(), 64);
for (; *keywords != NULL; keywords++) {
for (i = 0; i < map->keywords_count; i++) {
if (strcmp(map->keywords[i], *keywords) == 0)
break;
}
if (i == map->keywords_count)
buffer_append(missing_buf, keywords, sizeof(*keywords));
}
if (missing_buf->used == 0)
*missing_r = NULL;
else {
name = NULL;
buffer_append(missing_buf, &name, sizeof(name));
*missing_r = missing_buf->data;
}
return 0;
}
static buffer_t *
keywords_get_header_buf(struct mail_index_map *map,
const struct mail_index_ext *ext,
unsigned int new_count, unsigned int *keywords_count_r,
size_t *rec_offset_r, size_t *name_offset_root_r,
size_t *name_offset_r)
{
buffer_t *buf;
const struct mail_index_keyword_header *kw_hdr;
const struct mail_index_keyword_header_rec *kw_rec;
const char *name;
struct mail_index_keyword_header new_kw_hdr;
uint32_t offset;
kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
kw_rec = (const void *)(kw_hdr + 1);
name = (const char *)(kw_rec + kw_hdr->keywords_count);
if (kw_hdr->keywords_count == 0)
return NULL;
new_kw_hdr = *kw_hdr;
new_kw_hdr.keywords_count += new_count;
*keywords_count_r = new_kw_hdr.keywords_count;
offset = kw_rec[kw_hdr->keywords_count-1].name_offset;
offset += strlen(name + offset) + 1;
buf = buffer_create_dynamic(pool_datastack_create(), 512);
buffer_append(buf, &new_kw_hdr, sizeof(new_kw_hdr));
buffer_append(buf, kw_rec, sizeof(*kw_rec) * kw_hdr->keywords_count);
*rec_offset_r = buf->used;
buffer_write(buf, buf->used + sizeof(*kw_rec) * new_count,
name, offset);
*name_offset_root_r = buf->used;
*name_offset_r = offset;
return buf;
}
static int keywords_ext_register(struct mail_index_sync_map_ctx *ctx,
uint32_t ext_id, uint32_t reset_id,
uint32_t hdr_size, uint32_t keywords_count)
{
buffer_t *ext_intro_buf;
struct mail_transaction_ext_intro *u;
ext_intro_buf =
buffer_create_static_hard(pool_datastack_create(),
sizeof(*u) + sizeof("keywords")-1);
u = buffer_append_space_unsafe(ext_intro_buf, sizeof(*u));
u->ext_id = ext_id;
u->reset_id = reset_id;
u->hdr_size = hdr_size;
u->record_size = (keywords_count + CHAR_BIT - 1) / CHAR_BIT;
if ((u->record_size % 4) != 0) {
/* since we aren't properly aligned anyway,
reserve one extra byte for future */
u->record_size++;
}
u->record_align = 1;
if (ext_id == (uint32_t)-1) {
u->name_size = strlen("keywords");
buffer_append(ext_intro_buf, "keywords", u->name_size);
}
return mail_index_sync_ext_intro(ctx, u);
}
static int
keywords_update_header(struct mail_index_sync_map_ctx *ctx,
const char *const *keywords)
{
struct mail_index_map *map = ctx->view->map;
const struct mail_index_ext *ext = NULL;
struct mail_index_keyword_header *kw_hdr;
struct mail_index_keyword_header_rec kw_rec;
uint32_t ext_id;
const char *const *missing = keywords;
buffer_t *buf = NULL;
size_t rec_offset, name_offset, name_offset_root;
unsigned int keywords_count;
int ret = 0;
ext_id = mail_index_map_lookup_ext(map, "keywords");
if (ext_id != (uint32_t)-1) {
/* make sure all keywords exist in the header */
ext = map->extensions->data;
ext += ext_id;
ret = keywords_get_missing(ctx->view->index,
keywords, &missing);
if (ret == 0 && missing != NULL) {
/* update existing header */
buf = keywords_get_header_buf(map, ext,
strarray_length(missing),
&keywords_count,
&rec_offset,
&name_offset_root,
&name_offset);
}
}
if (buf == NULL) {
/* create new / replace broken header */
buf = buffer_create_dynamic(pool_datastack_create(), 512);
kw_hdr = buffer_append_space_unsafe(buf, sizeof(*kw_hdr));
kw_hdr->keywords_count = strarray_length(missing);
keywords_count = kw_hdr->keywords_count;
rec_offset = buf->used;
name_offset_root = rec_offset +
kw_hdr->keywords_count * sizeof(kw_rec);
name_offset = 0;
}
if (missing == NULL)
return 1;
/* missing some keywords - add them */
memset(&kw_rec, 0, sizeof(kw_rec));
kw_rec.name_offset = name_offset;
for (; *missing != NULL; missing++) {
size_t len = strlen(*missing) + 1;
buffer_write(buf, rec_offset, &kw_rec, sizeof(kw_rec));
buffer_write(buf, name_offset_root, *missing, len);
rec_offset += sizeof(kw_rec);
kw_rec.name_offset += len;
name_offset_root += len;
}
if ((buf->used % 4) != 0)
buffer_append_zero(buf, 4 - (buf->used % 4));
if (ext == NULL || buf->used > ext->hdr_size ||
(uint32_t)ext->record_size * CHAR_BIT < keywords_count) {
/* if we need to grow the buffer, add some padding */
buffer_append_zero(buf, 128);
ret = keywords_ext_register(ctx, ext_id,
ext == NULL ? 0 : ext->reset_id,
buf->used, keywords_count);
if (ret <= 0)
return ret;
/* map may have changed */
map = ctx->view->map;
if (ext == NULL) {
ext_id = mail_index_map_lookup_ext(map, "keywords");
i_assert(ext_id != (uint32_t)-1);
}
ext = map->extensions->data;
ext += ext_id;
i_assert(ext->hdr_size == buf->used);
}
buffer_copy(map->hdr_copy_buf, ext->hdr_offset,
buf, 0, buf->used);
map->hdr_base = map->hdr_copy_buf->data;
return 1;
}
static const unsigned char *
keywords_make_mask(struct mail_index_map *map, const struct mail_index_ext *ext,
const char *const *keywords)
{
const struct mail_index_keyword_header *kw_hdr;
const struct mail_index_keyword_header_rec *kw_rec;
const char *name, *const *n;
unsigned char *mask;
unsigned int i;
kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
kw_rec = (const void *)(kw_hdr + 1);
name = (const char *)(kw_rec + kw_hdr->keywords_count);
mask = t_malloc0(ext->record_size);
for (i = 0; i < kw_hdr->keywords_count; i++) {
for (n = keywords; *n != NULL; n++) {
if (strcmp(name + kw_rec[i].name_offset, *n) == 0) {
mask[i / CHAR_BIT] |= 1 << (i % CHAR_BIT);
break;
}
}
}
return mask;
}
static int
keywords_update_records(struct mail_index_view *view,
const struct mail_index_ext *ext,
const unsigned char *mask,
enum modify_type type,
uint32_t uid1, uint32_t uid2)
{
struct mail_index_record *rec;
unsigned char *data;
uint32_t seq1, seq2;
unsigned int i;
if (mail_index_lookup_uid_range(view, uid1, uid2, &seq1, &seq2) < 0)
return -1;
if (seq1 == 0)
return 1;
for (; seq1 <= seq2; seq1++) {
rec = MAIL_INDEX_MAP_IDX(view->map, seq1-1);
data = PTR_OFFSET(rec, ext->record_offset);
switch (type) {
case MODIFY_ADD:
for (i = 0; i < ext->record_size; i++)
data[i] |= mask[i];
break;
case MODIFY_REMOVE:
for (i = 0; i < ext->record_size; i++)
data[i] &= ~mask[i];
break;
case MODIFY_REPLACE:
memcpy(data, mask, ext->record_size);
break;
default:
i_unreached();
}
}
return 1;
}
int mail_index_sync_keywords(struct mail_index_sync_map_ctx *ctx,
const struct mail_transaction_header *hdr,
const struct mail_transaction_keyword_update *rec)
{
const uint32_t *uid, *end;
const char *const *keywords;
const struct mail_index_ext *ext;
const unsigned char *mask;
uint32_t ext_id;
int ret;
keywords = keywords_get_from_header(rec, hdr->size, &uid);
if (keywords == NULL) {
mail_transaction_log_view_set_corrupted(ctx->view->log_view,
"Keyword header ended unexpectedly");
return -1;
}
end = CONST_PTR_OFFSET(rec, hdr->size);
if (rec->modify_type != MODIFY_REMOVE) {
ret = keywords_update_header(ctx, keywords);
if (ret <= 0)
return ret;
}
ext_id = mail_index_map_lookup_ext(ctx->view->map, "keywords");
if (ext_id == (uint32_t)-1) {
/* nothing to do */
i_assert(rec->modify_type == MODIFY_REMOVE);
return 1;
}
ext = ctx->view->map->extensions->data;
ext += ext_id;
mask = keywords_make_mask(ctx->view->map, ext, keywords);
while (uid+2 <= end) {
ret = keywords_update_records(ctx->view, ext, mask,
rec->modify_type,
uid[0], uid[1]);
if (ret <= 0)
return ret;
uid += 2;
}
return 1;
}
Index: mail-index-sync-private.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-sync-private.h,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- mail-index-sync-private.h 7 Dec 2004 03:59:20 -0000 1.17
+++ mail-index-sync-private.h 26 Dec 2004 09:12:40 -0000 1.18
@@ -90,4 +90,8 @@
mail_index_sync_ext_rec_update(struct mail_index_sync_map_ctx *ctx,
const struct mail_transaction_ext_rec_update *u);
+int mail_index_sync_keywords(struct mail_index_sync_map_ctx *ctx,
+ const struct mail_transaction_header *hdr,
+ const struct mail_transaction_keyword_update *rec);
+
#endif
Index: mail-index-sync-update.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-sync-update.c,v
retrieving revision 1.77
retrieving revision 1.78
diff -u -d -r1.77 -r1.78
--- mail-index-sync-update.c 20 Dec 2004 07:51:40 -0000 1.77
+++ mail-index-sync-update.c 26 Dec 2004 09:12:40 -0000 1.78
@@ -206,9 +206,7 @@
struct mail_index_header *hdr;
struct mail_index_record *rec;
uint8_t flag_mask, old_flags;
- keywords_mask_t keyword_mask;
- uint32_t i, idx, seq1, seq2;
- int update_keywords;
+ uint32_t idx, seq1, seq2;
if (u->uid1 > u->uid2 || u->uid1 == 0) {
mail_transaction_log_view_set_corrupted(ctx->view->log_view,
@@ -228,13 +226,6 @@
if ((u->add_flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0)
hdr->flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
- update_keywords = FALSE;
- for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++) {
- if (u->add_keywords[i] != 0 ||
- u->remove_keywords[i] != 0)
- update_keywords = TRUE;
- keyword_mask[i] = ~u->remove_keywords[i];
- }
flag_mask = ~u->remove_flags;
for (idx = seq1-1; idx < seq2; idx++) {
@@ -242,12 +233,6 @@
old_flags = rec->flags;
rec->flags = (rec->flags & flag_mask) | u->add_flags;
- if (update_keywords) {
- for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++) {
- rec->keywords[i] = u->add_keywords[i] |
- (rec->keywords[i] & keyword_mask[i]);
- }
- }
mail_index_header_update_counts(hdr, old_flags, rec->flags);
mail_index_header_update_lowwaters(hdr, rec);
@@ -381,6 +366,7 @@
{
int ret = 0;
+ t_push();
switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
case MAIL_TRANSACTION_APPEND: {
const struct mail_index_record *rec, *end;
@@ -507,9 +493,16 @@
}
break;
}
+ case MAIL_TRANSACTION_KEYWORD_UPDATE: {
+ const struct mail_transaction_keyword_update *rec = data;
+
+ ret = mail_index_sync_keywords(ctx, hdr, rec);
+ break;
+ }
default:
i_unreached();
}
+ t_pop();
i_assert(ctx->view->map->records_count ==
ctx->view->map->hdr.messages_count);
Index: mail-index-sync.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-sync.c,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -d -r1.44 -r1.45
--- mail-index-sync.c 13 Dec 2004 00:55:42 -0000 1.44
+++ mail-index-sync.c 26 Dec 2004 09:12:40 -0000 1.45
@@ -19,7 +19,6 @@
struct mail_transaction_flag_update *dest;
struct mail_transaction_flag_update new_update, tmp_update;
size_t i, dest_count;
- int j;
dest = buffer_get_modifyable_data(dest_buf, &dest_count);
dest_count /= sizeof(*dest);
@@ -91,17 +90,6 @@
dest[i].add_flags &= ~new_update.remove_flags;
dest[i].remove_flags |= new_update.remove_flags;
dest[i].remove_flags &= ~new_update.add_flags;
-
- for (j = 0; j < INDEX_KEYWORDS_BYTE_COUNT; j++) {
- dest[i].add_keywords[j] |=
- new_update.add_keywords[j];
- dest[i].add_keywords[j] &=
- ~new_update.remove_keywords[j];
- dest[i].remove_keywords[j] |=
- new_update.remove_keywords[j];
- dest[i].remove_keywords[j] &=
- ~new_update.add_keywords[j];
- }
}
if (new_update.uid1 <= new_update.uid2) {
@@ -147,7 +135,6 @@
struct mail_transaction_flag_update update;
const struct mail_index_record *rec;
uint32_t seq, messages_count;
- int i;
memset(&update, 0, sizeof(update));
@@ -162,10 +149,6 @@
update.uid1 = update.uid2 = rec->uid;
update.add_flags = rec->flags;
update.remove_flags = ~update.add_flags;
- memcpy(update.add_keywords, rec->keywords,
- INDEX_KEYWORDS_BYTE_COUNT);
- for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++)
- update.remove_keywords[i] = ~update.add_keywords[i];
mail_index_sync_sort_flags(ctx->updates_buf,
&update, sizeof(update));
@@ -426,11 +409,7 @@
rec->uid2 = update->uid2;
rec->add_flags = update->add_flags;
- memcpy(rec->add_keywords, update->add_keywords,
- sizeof(rec->add_keywords));
rec->remove_flags = update->remove_flags;
- memcpy(rec->remove_keywords, update->remove_keywords,
- sizeof(rec->remove_keywords));
}
static int mail_index_sync_rec_check(struct mail_index_view *view,
@@ -439,6 +418,7 @@
switch (rec->type) {
case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
case MAIL_INDEX_SYNC_TYPE_FLAGS:
+ case MAIL_INDEX_SYNC_TYPE_KEYWORDS:
if (rec->uid1 > rec->uid2 || rec->uid1 == 0) {
mail_transaction_log_view_set_corrupted(view->log_view,
"Broken UID range: %u..%u (type 0x%x)",
@@ -585,15 +565,9 @@
}
void mail_index_sync_flags_apply(const struct mail_index_sync_rec *sync_rec,
- uint8_t *flags, keywords_mask_t keywords)
+ uint8_t *flags)
{
- int i;
-
i_assert(sync_rec->type == MAIL_INDEX_SYNC_TYPE_FLAGS);
*flags = (*flags & ~sync_rec->remove_flags) | sync_rec->add_flags;
- for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++) {
- keywords[i] = (keywords[i] & ~sync_rec->remove_keywords[i]) |
- sync_rec->add_keywords[i];
- }
}
Index: mail-index-transaction-private.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-transaction-private.h,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- mail-index-transaction-private.h 13 Nov 2004 23:08:07 -0000 1.18
+++ mail-index-transaction-private.h 26 Dec 2004 09:12:40 -0000 1.19
@@ -3,6 +3,17 @@
#include "mail-transaction-log.h"
+struct mail_index_keyword_transaction {
+ struct mail_keywords keywords;
+ pool_t pool;
+ enum modify_type modify_type;
+ buffer_t *messages;
+
+ /* mail_keywords points to first mail_index_keyword_transaction.
+ this points to next transaction using the same keywords */
+ struct mail_index_keyword_transaction *next;
+};
+
struct mail_index_transaction {
int refcount;
struct mail_index_view *view;
@@ -22,6 +33,7 @@
buffer_t *ext_rec_updates; /* buffer[] */
buffer_t *ext_resizes; /* struct mail_transaction_ext_intro[] */
buffer_t *ext_resets; /* uint32_t[] */
+ buffer_t *keyword_updates; /* struct mail_index_keyword_transaction[] */
struct mail_cache_transaction_ctx *cache_trans_ctx;
Index: mail-index-transaction.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-transaction.c,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -d -r1.36 -r1.37
--- mail-index-transaction.c 28 Nov 2004 23:19:53 -0000 1.36
+++ mail-index-transaction.c 26 Dec 2004 09:12:40 -0000 1.37
@@ -12,6 +12,7 @@
#include "mail-index-transaction-private.h"
#include <stddef.h>
+#include <stdlib.h>
static void mail_index_transaction_add_last(struct mail_index_transaction *t);
@@ -58,6 +59,17 @@
buffer_free(t->ext_rec_updates);
}
+ if (t->keyword_updates != NULL) {
+ struct mail_index_keyword_transaction *kt;
+
+ kt = buffer_get_modifyable_data(t->keyword_updates, &size);
+ size /= sizeof(*kt);
+
+ for (i = 0; i < size; i++)
+ pool_unref(kt[i].pool);
+ buffer_free(t->keyword_updates);
+ }
+
if (t->appends != NULL)
buffer_free(t->appends);
if (t->expunges != NULL)
@@ -141,6 +153,21 @@
}
}
+ if (t->keyword_updates != NULL) {
+ struct mail_index_keyword_transaction *kt;
+
+ kt = buffer_get_modifyable_data(t->keyword_updates, &size);
+ size /= sizeof(*kt);
+
+ for (i = 0; i < size; i++) {
+ if (kt[i].messages == NULL)
+ continue;
+
+ mail_index_buffer_convert_to_uids(t, kt[i].messages,
+ sizeof(uint32_t) * 2, TRUE);
+ }
+ }
+
mail_index_buffer_convert_to_uids(t, t->expunges,
sizeof(struct mail_transaction_expunge), TRUE);
mail_index_buffer_convert_to_uids(t, t->updates,
@@ -249,46 +276,39 @@
*next_uid_r = first_uid;
}
-void mail_index_expunge(struct mail_index_transaction *t, uint32_t seq)
+struct seq_range {
+ uint32_t seq1, seq2;
+};
+
+static void mail_index_update_seq_range_buffer(buffer_t *buffer, uint32_t seq)
{
- struct mail_transaction_expunge exp, *data;
+ struct seq_range *data, value;
unsigned int idx, left_idx, right_idx;
size_t size;
- i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(t->view));
-
- t->log_updates = TRUE;
- exp.uid1 = exp.uid2 = seq;
-
- /* expunges is a sorted array of {seq1, seq2, ..}, .. */
-
- if (t->expunges == NULL) {
- t->expunges = buffer_create_dynamic(default_pool, 1024);
- buffer_append(t->expunges, &exp, sizeof(exp));
- return;
- }
+ value.seq1 = value.seq2 = seq;
- data = buffer_get_modifyable_data(t->expunges, &size);
+ data = buffer_get_modifyable_data(buffer, &size);
size /= sizeof(*data);
i_assert(size > 0);
/* quick checks */
- if (data[size-1].uid2 == seq-1) {
+ if (data[size-1].seq2 == seq-1) {
/* grow last range */
- data[size-1].uid2 = seq;
+ data[size-1].seq2 = seq;
return;
}
- if (data[size-1].uid2 < seq) {
- buffer_append(t->expunges, &exp, sizeof(exp));
+ if (data[size-1].seq2 < seq) {
+ buffer_append(buffer, &value, sizeof(value));
return;
}
- if (data[0].uid1 == seq+1) {
+ if (data[0].seq1 == seq+1) {
/* grow down first range */
- data[0].uid1 = seq;
+ data[0].seq1 = seq;
return;
}
- if (data[0].uid1 > seq) {
- buffer_insert(t->expunges, 0, &exp, sizeof(exp));
+ if (data[0].seq1 > seq) {
+ buffer_insert(buffer, 0, &value, sizeof(value));
return;
}
@@ -298,8 +318,8 @@
while (left_idx < right_idx) {
idx = (left_idx + right_idx) / 2;
- if (data[idx].uid1 <= seq) {
- if (data[idx].uid2 >= seq) {
+ if (data[idx].seq1 <= seq) {
+ if (data[idx].seq2 >= seq) {
/* it's already expunged */
return;
}
@@ -309,70 +329,77 @@
}
}
- if (data[idx].uid2 < seq)
+ if (data[idx].seq2 < seq)
idx++;
/* idx == size couldn't happen because we already handle it above */
- i_assert(idx < size && data[idx].uid1 >= seq);
- i_assert(data[idx].uid1 > seq || data[idx].uid2 < seq);
+ i_assert(idx < size && data[idx].seq1 >= seq);
+ i_assert(data[idx].seq1 > seq || data[idx].seq2 < seq);
- if (data[idx].uid1 == seq+1) {
- data[idx].uid1 = seq;
- if (idx > 0 && data[idx-1].uid2 == seq-1) {
+ if (data[idx].seq1 == seq+1) {
+ data[idx].seq1 = seq;
+ if (idx > 0 && data[idx-1].seq2 == seq-1) {
/* merge */
- data[idx-1].uid2 = data[idx].uid2;
- buffer_delete(t->expunges, idx * sizeof(*data),
+ data[idx-1].seq2 = data[idx].seq2;
+ buffer_delete(buffer, idx * sizeof(*data),
sizeof(*data));
}
- } else if (data[idx].uid2 == seq-1) {
+ } else if (data[idx].seq2 == seq-1) {
i_assert(idx+1 < size); /* already handled above */
- data[idx].uid2 = seq;
- if (data[idx+1].uid1 == seq+1) {
+ data[idx].seq2 = seq;
+ if (data[idx+1].seq1 == seq+1) {
/* merge */
- data[idx+1].uid1 = data[idx].uid1;
- buffer_delete(t->expunges, idx * sizeof(*data),
+ data[idx+1].seq1 = data[idx].seq1;
+ buffer_delete(buffer, idx * sizeof(*data),
sizeof(*data));
}
} else {
- buffer_insert(t->expunges, idx * sizeof(*data),
- &exp, sizeof(exp));
+ buffer_insert(buffer, idx * sizeof(*data),
+ &value, sizeof(value));
+ }
+}
+
+void mail_index_expunge(struct mail_index_transaction *t, uint32_t seq)
+{
+ i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(t->view));
+
+ t->log_updates = TRUE;
+
+ /* expunges is a sorted array of {seq1, seq2, ..}, .. */
+ if (t->expunges == NULL) {
+ t->expunges = buffer_create_dynamic(default_pool, 1024);
+ buffer_append(t->expunges, &seq, sizeof(seq));
+ buffer_append(t->expunges, &seq, sizeof(seq));
+ return;
}
+
+ mail_index_update_seq_range_buffer(t->expunges, seq);
}
static void mail_index_record_modify_flags(struct mail_index_record *rec,
enum modify_type modify_type,
- enum mail_flags flags,
- keywords_mask_t keywords)
+ enum mail_flags flags)
{
- int i;
-
switch (modify_type) {
case MODIFY_REPLACE:
rec->flags = flags;
- memcpy(rec->keywords, keywords, INDEX_KEYWORDS_BYTE_COUNT);
break;
case MODIFY_ADD:
rec->flags |= flags;
- for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++)
- rec->keywords[i] |= keywords[i];
break;
case MODIFY_REMOVE:
rec->flags &= ~flags;
- for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++)
- rec->keywords[i] &= ~keywords[i];
break;
}
}
-#define IS_COMPATIBLE_UPDATE(t, modify_type, flags, keywords) \
+#define IS_COMPATIBLE_UPDATE(t, modify_type, flags) \
((t)->last_update_modify_type == (modify_type) && \
- (t)->last_update.add_flags == (flags) && \
- memcmp((t)->last_update.add_keywords, keywords, \
- INDEX_KEYWORDS_BYTE_COUNT) == 0)
+ (t)->last_update.add_flags == (flags))
void mail_index_update_flags(struct mail_index_transaction *t, uint32_t seq,
enum modify_type modify_type,
- enum mail_flags flags, keywords_mask_t keywords)
+ enum mail_flags flags)
{
struct mail_index_record *rec;
@@ -381,8 +408,7 @@
if (seq >= t->first_new_seq) {
/* just appended message, modify it directly */
rec = mail_index_transaction_lookup(t, seq);
- mail_index_record_modify_flags(rec, modify_type,
- flags, keywords);
+ mail_index_record_modify_flags(rec, modify_type, flags);
return;
}
@@ -393,13 +419,13 @@
transaction (eg. 1:10 +seen, 1:10 +deleted) */
if (t->last_update.uid2 == seq-1) {
if (t->last_update.uid1 != 0 &&
- IS_COMPATIBLE_UPDATE(t, modify_type, flags, keywords)) {
+ IS_COMPATIBLE_UPDATE(t, modify_type, flags)) {
t->last_update.uid2 = seq;
return;
}
} else if (t->last_update.uid1 == seq+1) {
if (t->last_update.uid1 != 0 &&
- IS_COMPATIBLE_UPDATE(t, modify_type, flags, keywords)) {
+ IS_COMPATIBLE_UPDATE(t, modify_type, flags)) {
t->last_update.uid1 = seq;
return;
}
@@ -411,24 +437,18 @@
t->last_update_modify_type = modify_type;
t->last_update.uid1 = t->last_update.uid2 = seq;
t->last_update.add_flags = flags;
- memcpy(t->last_update.add_keywords, keywords,
- INDEX_KEYWORDS_BYTE_COUNT);
}
static void
mail_index_transaction_get_last(struct mail_index_transaction *t,
struct mail_transaction_flag_update *update)
{
- int i;
-
*update = t->last_update;
switch (t->last_update_modify_type) {
case MODIFY_REPLACE:
/* remove_flags = ~add_flags */
update->remove_flags =
~update->add_flags & MAIL_INDEX_FLAGS_MASK;
- for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++)
- update->remove_keywords[i] = ~update->add_keywords[i];
break;
case MODIFY_ADD:
/* already in add_flags */
@@ -436,10 +456,7 @@
case MODIFY_REMOVE:
/* add_flags -> remove_flags */
update->remove_flags = update->add_flags;
- memcpy(&update->remove_keywords, &update->add_keywords,
- INDEX_KEYWORDS_BYTE_COUNT);
update->add_flags = 0;
- memset(&update->add_keywords, 0, INDEX_KEYWORDS_BYTE_COUNT);
break;
}
}
@@ -698,3 +715,107 @@
memset(old_data_r, 0, record_size);
}
}
+
+static int keywords_match(const struct mail_keywords *keywords,
+ const char *const *list)
+{
+ unsigned int i;
+
+ for (i = 0; list[i] != NULL; i++) {
+ if (strcasecmp(keywords->keywords[i], list[i]) != 0)
+ return FALSE;
+ }
+ i_assert(i == keywords->count);
+ return TRUE;
+}
+
+static struct mail_index_keyword_transaction *
+mail_index_keyword_transaction_new(struct mail_index_transaction *t,
+ const char *const sorted_keywords[],
+ unsigned int count)
+{
+ struct mail_index_keyword_transaction *kt;
+ unsigned int i;
+
+ kt = buffer_append_space_unsafe(t->keyword_updates, sizeof(*kt));
+ kt->pool = pool_alloconly_create("keywords", 128);
+ kt->keywords.count = count;
+ kt->keywords.keywords = p_new(kt->pool, const char *, count + 1);
+ kt->keywords.transaction = kt;
+ for (i = 0; i < count; i++) {
+ kt->keywords.keywords[i] =
+ p_strdup(kt->pool, sorted_keywords[i]);
+ }
+
+ return kt;
+}
+
+static struct mail_index_keyword_transaction *
+mail_index_keyword_transaction_clone(struct mail_index_transaction *t,
+ struct mail_index_keyword_transaction *kt)
+{
+ struct mail_index_keyword_transaction *new_kt;
+
+ new_kt = buffer_append_space_unsafe(t->keyword_updates, sizeof(*kt));
+ new_kt->pool = pool_alloconly_create("keywords", 128);
+ new_kt->keywords = kt->keywords;
+ return new_kt;
+}
+
+struct mail_keywords *
+mail_index_keywords_create(struct mail_index_transaction *t,
+ const char *const keywords[])
+{
+ struct mail_index_keyword_transaction *kt;
+ const char **sorted_keywords;
+ unsigned int i, count;
+ size_t size;
+
+ count = strarray_length(keywords);
+
+ sorted_keywords = t_new(const char *, count + 1);
+ memcpy(sorted_keywords, keywords, count * sizeof(*sorted_keywords));
+ qsort(sorted_keywords, count, sizeof(*sorted_keywords), strcasecmp_p);
+
+ if (t->keyword_updates == NULL)
+ t->keyword_updates = buffer_create_dynamic(default_pool, 512);
+
+ kt = buffer_get_modifyable_data(t->keyword_updates, &size);
+ size /= sizeof(*kt);
+
+ /* try to use existing ones */
+ for (i = 0; i < size; i++) {
+ if (kt[i].keywords.count == count &&
+ keywords_match(&kt[i].keywords, sorted_keywords))
+ return &kt[i].keywords;
+ }
+
+ kt = mail_index_keyword_transaction_new(t, sorted_keywords, count);
+ return &kt->keywords;
+}
+
+void mail_index_update_keywords(struct mail_index_transaction *t, uint32_t seq,
+ enum modify_type modify_type,
+ const struct mail_keywords *keywords)
+{
+ struct mail_index_keyword_transaction *kt;
+
+ kt = keywords->transaction;
+ while (kt->modify_type != modify_type && kt->messages != NULL) {
+ if (kt->next == NULL) {
+ kt = mail_index_keyword_transaction_clone(t, kt);
+ break;
+ }
+ kt = kt->next;
+ }
+
+ if (kt->messages == NULL) {
+ kt->messages = buffer_create_dynamic(kt->pool, 32);
+ kt->modify_type = modify_type;
+ buffer_append(kt->messages, &seq, sizeof(seq));
+ buffer_append(kt->messages, &seq, sizeof(seq));
+ } else {
+ mail_index_update_seq_range_buffer(kt->messages, seq);
+ }
+ t->log_updates = TRUE;
+}
Index: mail-index-view-sync.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-view-sync.c,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -d -r1.33 -r1.34
--- mail-index-view-sync.c 5 Dec 2004 01:47:03 -0000 1.33
+++ mail-index-view-sync.c 26 Dec 2004 09:12:40 -0000 1.34
@@ -74,7 +74,7 @@
#define MAIL_INDEX_VIEW_VISIBLE_SYNC_MASK \
(MAIL_TRANSACTION_EXPUNGE | MAIL_TRANSACTION_APPEND | \
- MAIL_TRANSACTION_FLAG_UPDATE)
+ MAIL_TRANSACTION_FLAG_UPDATE | MAIL_TRANSACTION_KEYWORD_UPDATE)
int mail_index_view_sync_begin(struct mail_index_view *view,
enum mail_index_sync_type sync_mask,
@@ -240,17 +240,14 @@
return 1;
}
-#define FLAG_UPDATE_IS_INTERNAL(u, empty) \
+#define FLAG_UPDATE_IS_INTERNAL(u) \
((((u)->add_flags | (u)->remove_flags) & \
- ~(MAIL_INDEX_MAIL_FLAG_DIRTY | MAIL_RECENT)) == 0 && \
- memcmp((u)->add_keywords, empty, INDEX_KEYWORDS_BYTE_COUNT) == 0 && \
- memcmp((u)->add_keywords, empty, INDEX_KEYWORDS_BYTE_COUNT) == 0)
+ ~(MAIL_INDEX_MAIL_FLAG_DIRTY | MAIL_RECENT)) == 0)
static int
mail_index_view_sync_get_rec(struct mail_index_view_sync_ctx *ctx,
struct mail_index_sync_rec *rec)
{
- static keywords_mask_t empty_keywords = { 0, };
const struct mail_transaction_header *hdr = ctx->hdr;
const void *data = ctx->data;
@@ -275,7 +272,7 @@
for (;;) {
ctx->data_offset += sizeof(*update);
- if (!FLAG_UPDATE_IS_INTERNAL(update, empty_keywords))
+ if (!FLAG_UPDATE_IS_INTERNAL(update))
break;
if (ctx->data_offset == ctx->hdr->size)
@@ -284,6 +281,31 @@
mail_index_sync_get_update(rec, update);
break;
}
+ case MAIL_TRANSACTION_KEYWORD_UPDATE: {
+ const struct mail_transaction_keyword_update *update = data;
+ const unsigned char *p;
+ const uint32_t *uids;
+ uint32_t i;
+
+ if (ctx->data_offset == 0) {
+ p = (const unsigned char *)
+ (update->name_size + update->keywords_count);
+
+ for (i = 0; i < update->keywords_count; i++)
+ p += update->name_size[i];
+
+ ctx->data_offset = p - (const unsigned char *)update;
+ if ((ctx->data_offset % 4) != 0)
+ ctx->data_offset += 4 - (ctx->data_offset % 4);
+ }
+
+ uids = CONST_PTR_OFFSET(data, ctx->data_offset);
+ rec->type = MAIL_INDEX_SYNC_TYPE_KEYWORDS;
+ rec->uid1 = uids[0];
+ rec->uid2 = uids[1];
+ ctx->data_offset += sizeof(uint32_t) * 2;
+ break;
+ }
default:
i_unreached();
}
Index: mail-index-view.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-view.c,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -d -r1.31 -r1.32
--- mail-index-view.c 5 Dec 2004 01:45:53 -0000 1.31
+++ mail-index-view.c 26 Dec 2004 09:12:40 -0000 1.32
@@ -400,6 +400,7 @@
const void **data_r, size_t *data_size_r)
{
const struct mail_index_ext *ext;
+ uint32_t idx;
if (map != NULL) {
if (mail_index_view_lock(view) < 0)
@@ -411,8 +412,14 @@
map = view->index->map;
}
+ if (!mail_index_map_get_ext_idx(map, ext_id, &idx)) {
+ *data_r = NULL;
+ *data_size_r = 0;
+ return 0;
+ }
+
ext = map->extensions->data;
- ext += ext_id;
+ ext += idx;
*data_r = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
*data_size_r = ext->hdr_size;
@@ -453,6 +460,64 @@
return view->methods.lookup_full(view, seq, map_r, rec_r);
}
+int mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq,
+ buffer_t *buf, const char *const **keywords_r)
+{
+ struct mail_index_map *map;
+ const struct mail_index_ext *ext;
+ const void *data;
+ unsigned int i, j;
+ uint32_t ext_id, idx;
+ int ret;
+
+ *keywords_r = NULL;
+ buffer_set_used_size(buf, 0);
+
+ ext_id = view->index->keywords_ext_id;
+ ret = mail_index_lookup_ext_full(view, seq, ext_id, &map, &data);
+ if (ret < 0)
+ return -1;
+
+ if (!mail_index_map_get_ext_idx(map, ext_id, &idx)) {
+ buffer_append_zero(buf, sizeof(const char *));
+ *keywords_r = buf->data;
+ return ret;
+ }
+
+ ext = map->extensions->data;
+ ext += idx;
+
+ for (i = 0, idx = 0; i < ext->record_size; i++) {
+ if (((const char *)data)[i] == 0)
+ continue;
+
+ for (j = 0; j < CHAR_BIT; j++, idx++) {
+ if ((((const char *)data)[i] & (1 << j)) == 0)
+ continue;
+
+ if (idx >= map->keywords_count) {
+ /* keyword header is updated, re-read
+ it so we know what this one is
+ called */
+ if (mail_index_map_read_keywords(view->index,
+ map) < 0)
+ return -1;
+ if (idx >= map->keywords_count) {
+ /* extra bits set in keyword bytes.
+ shouldn't happen, but just ignore. */
+ break;
+ }
+ }
+ buffer_append(buf, &map->keywords[idx],
+ sizeof(const char *));
+ }
+ }
+ buffer_append_zero(buf, sizeof(const char *));
+ *keywords_r = buf->data;
+
+ return ret;
+}
+
int mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq,
uint32_t *uid_r)
{
Index: mail-index.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index.c,v
retrieving revision 1.183
retrieving revision 1.184
diff -u -d -r1.183 -r1.184
--- mail-index.c 7 Dec 2004 21:32:09 -0000 1.183
+++ mail-index.c 26 Dec 2004 09:12:40 -0000 1.184
@@ -34,6 +34,9 @@
index->mode = 0600;
index->gid = (gid_t)-1;
+
+ index->keywords_ext_id =
+ mail_index_ext_register(index, "keywords", 128, 2, 1);
return index;
}
@@ -270,6 +273,92 @@
return 1;
}
+int mail_index_map_read_keywords(struct mail_index *index,
+ struct mail_index_map *map)
+{
+ const struct mail_index_ext *ext;
+ const struct mail_index_keyword_header *kw_hdr;
+ const struct mail_index_keyword_header_rec *kw_rec;
+ const char *name, **keywords_list;
+ unsigned int i, name_len;
+ uint32_t ext_id;
+
+ ext_id = mail_index_map_lookup_ext(map, "keywords");
+ if (ext_id == (uint32_t)-1) {
+ map->keywords = NULL;
+ map->keywords_count = 0;
+ return 0;
+ }
+
+ ext = map->extensions->data;
+ ext += ext_id;
+
+ kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
+ kw_rec = (const void *)(kw_hdr + 1);
+ name = (const char *)(kw_rec + kw_hdr->keywords_count);
+
+ if ((size_t)(name - (const char *)kw_hdr) > ext->hdr_size) {
+ mail_index_set_error(index, "Corrupted index file %s: "
+ "keywords_count larger than header size",
+ index->filepath);
+ return -1;
+ }
+
+ /* make sure the header is valid */
+ name_len = (const char *)kw_hdr + ext->hdr_size - name;
+ for (i = 0; i < kw_hdr->keywords_count; i++) {
+ if (kw_rec[i].name_offset > name_len) {
+ mail_index_set_error(index, "Corrupted index file %s: "
+ "name_offset points outside allocated header",
+ index->filepath);
+ return -1;
+ }
+ }
+ if (name[name_len-1] != '\0') {
+ mail_index_set_error(index, "Corrupted index file %s: "
+ "header doesn't end with NUL",
+ index->filepath);
+ return -1;
+ }
+
+ if (map->keywords_pool == NULL)
+ map->keywords_pool = pool_alloconly_create("keywords", 1024);
+
+ /* Save keywords in memory. Only new keywords should come into the
+ mapping, so keep the existing keyword strings in memory to allow
+ mail_index_lookup_keywords() to safely return direct pointers
+ into them. */
+ if (kw_hdr->keywords_count < map->keywords_count) {
+ mail_index_set_error(index, "Corrupted index file %s: "
+ "Keywords removed unexpectedly",
+ index->filepath);
+ return -1;
+ }
+ if (kw_hdr->keywords_count == map->keywords_count) {
+ /* nothing changed */
+ return 0;
+ }
+
+ /* @UNSAFE */
+ keywords_list = p_new(map->keywords_pool,
+ const char *, kw_hdr->keywords_count + 1);
+ for (i = 0; i < map->keywords_count; i++)
+ keywords_list[i] = map->keywords[i];
+ for (; i < kw_hdr->keywords_count; i++) {
+ keywords_list[i] = p_strdup(map->keywords_pool,
+ name + kw_rec[i].name_offset);
+ }
+ map->keywords = keywords_list;
+ map->keywords_count = kw_hdr->keywords_count;
+ return 0;
+}
+
+const char *const *mail_index_get_keywords(struct mail_index *index)
+{
+ (void)mail_index_map_read_keywords(index, index->map);
+ return index->map->keywords;
+}
+
static int mail_index_check_header(struct mail_index *index,
struct mail_index_map *map)
{
@@ -305,14 +394,6 @@
return -1;
}
- if (hdr->keywords_mask_size != sizeof(keywords_mask_t)) {
- mail_index_set_error(index, "Corrupted index file %s: "
- "keywords_mask_size mismatch: %d != %d",
- index->filepath, hdr->keywords_mask_size,
- (int)sizeof(keywords_mask_t));
- return -1;
- }
-
if (hdr->record_size < sizeof(struct mail_index_record)) {
mail_index_set_error(index, "Corrupted index file %s: "
"record_size too small: %u < %"PRIuSIZE_T,
@@ -368,6 +449,8 @@
mail_index_map_clear(index, map);
if (map->extension_pool != NULL)
pool_unref(map->extension_pool);
+ if (map->keywords_pool != NULL)
+ pool_unref(map->keywords_pool);
buffer_free(map->hdr_copy_buf);
i_free(map);
}
@@ -1080,7 +1163,6 @@
hdr->base_header_size = sizeof(*hdr);
hdr->header_size = sizeof(*hdr);
hdr->record_size = sizeof(struct mail_index_record);
- hdr->keywords_mask_size = sizeof(keywords_mask_t);
#ifndef WORDS_BIGENDIAN
hdr->compat_data[0] = MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
Index: mail-index.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index.h,v
retrieving revision 1.139
retrieving revision 1.140
diff -u -d -r1.139 -r1.140
--- mail-index.h 5 Dec 2004 01:45:53 -0000 1.139
+++ mail-index.h 26 Dec 2004 09:12:40 -0000 1.140
@@ -3,15 +3,11 @@
#include "mail-types.h"
-#define MAIL_INDEX_MAJOR_VERSION 6
+#define MAIL_INDEX_MAJOR_VERSION 7
#define MAIL_INDEX_MINOR_VERSION 0
#define MAIL_INDEX_HEADER_MIN_SIZE 120
-/* Number of keywords in mail_index_record. */
-#define INDEX_KEYWORDS_COUNT (3*8)
-#define INDEX_KEYWORDS_BYTE_COUNT ((INDEX_KEYWORDS_COUNT+CHAR_BIT-1) / CHAR_BIT)
-
enum mail_index_open_flags {
/* Create index if it doesn't exist */
MAIL_INDEX_OPEN_FLAG_CREATE = 0x01,
@@ -58,8 +54,6 @@
#define MAIL_INDEX_FLAGS_MASK \
(MAIL_ANSWERED | MAIL_FLAGGED | MAIL_DELETED | MAIL_SEEN | MAIL_DRAFT)
-typedef unsigned char keywords_mask_t[INDEX_KEYWORDS_BYTE_COUNT];
-
struct mail_index_header {
/* major version is increased only when you can't have backwards
compatibility. minor version is increased when header size is
@@ -69,8 +63,7 @@
uint16_t base_header_size;
uint32_t header_size; /* base + extended header size */
- uint16_t record_size;
- uint16_t keywords_mask_size;
+ uint32_t record_size;
/* 0 = flags
1 = sizeof(uoff_t)
@@ -110,14 +103,14 @@
struct mail_index_record {
uint32_t uid;
- uint8_t flags; /* mail_flags | mail_index_mail_flags */
- keywords_mask_t keywords;
+ uint8_t flags; /* enum mail_flags | enum mail_index_mail_flags */
};
enum mail_index_sync_type {
MAIL_INDEX_SYNC_TYPE_APPEND = 0x01,
MAIL_INDEX_SYNC_TYPE_EXPUNGE = 0x02,
- MAIL_INDEX_SYNC_TYPE_FLAGS = 0x04
+ MAIL_INDEX_SYNC_TYPE_FLAGS = 0x04,
+ MAIL_INDEX_SYNC_TYPE_KEYWORDS = 0x08
};
#define MAIL_INDEX_SYNC_MASK_ALL 0xff
@@ -127,11 +120,10 @@
/* MAIL_INDEX_SYNC_TYPE_FLAGS: */
uint8_t add_flags;
- keywords_mask_t add_keywords;
uint8_t remove_flags;
- keywords_mask_t remove_keywords;
};
+struct mail_keywords;
struct mail_index;
struct mail_index_map;
struct mail_index_view;
@@ -258,6 +250,8 @@
int mail_index_lookup_full(struct mail_index_view *view, uint32_t seq,
struct mail_index_map **map_r,
const struct mail_index_record **rec_r);
+int mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq,
+ buffer_t *buf, const char *const **keywords_r);
/* Returns the UID for given message. May be slightly faster than
mail_index_lookup()->uid. */
int mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq,
@@ -286,7 +280,20 @@
/* Update flags in index. */
void mail_index_update_flags(struct mail_index_transaction *t, uint32_t seq,
enum modify_type modify_type,
- enum mail_flags flags, keywords_mask_t keywords);
+ enum mail_flags flags);
+
+/* Return a list of all existing keywords, or NULL if there is none. */
+const char *const *mail_index_get_keywords(struct mail_index *index);
+/* Create a keyword list structure. It's freed automatically at the end of
+ the transaction. */
+struct mail_keywords *
+mail_index_keywords_create(struct mail_index_transaction *t,
+ const char *const keywords[]);
+/* Update keywords for given message. */
+void mail_index_update_keywords(struct mail_index_transaction *t, uint32_t seq,
+ enum modify_type modify_type,
+ const struct mail_keywords *keywords);
+
/* Update field in header. */
void mail_index_update_header(struct mail_index_transaction *t,
size_t offset, const void *data, size_t size);
@@ -302,7 +309,7 @@
/* Apply changes in MAIL_INDEX_SYNC_TYPE_FLAGS typed sync records to given
flags variables. */
void mail_index_sync_flags_apply(const struct mail_index_sync_rec *sync_rec,
- uint8_t *flags, keywords_mask_t keywords);
+ uint8_t *flags);
/* register index extension. name is a unique identifier for the extension.
returns unique identifier for the name. */
Index: mail-transaction-log.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-transaction-log.c,v
retrieving revision 1.78
retrieving revision 1.79
diff -u -d -r1.78 -r1.79
--- mail-transaction-log.c 7 Dec 2004 01:02:04 -0000 1.78
+++ mail-transaction-log.c 26 Dec 2004 09:12:40 -0000 1.79
@@ -1188,6 +1188,50 @@
return 0;
}
+static int log_append_keyword_updates(struct mail_transaction_log_file *file,
+ struct mail_index_transaction *t)
+{
+ struct mail_index_keyword_transaction *kt;
+ struct mail_transaction_keyword_update *kt_hdr;
+ buffer_t *buf;
+ size_t i, size;
+ unsigned int j;
+
+ buf = buffer_create_dynamic(pool_datastack_create(), 128);
+
+ kt = buffer_get_modifyable_data(t->keyword_updates, &size);
+ size /= sizeof(*kt);
+ for (i = 0; i < size; i++) {
+ if (kt[i].messages == NULL)
+ continue;
+
+ buffer_set_used_size(buf, 0);
+ kt_hdr = buffer_append_space_unsafe(buf, sizeof(*kt_hdr));
+ kt_hdr->keywords_count = kt[i].keywords.count;
+ kt_hdr->modify_type = kt[i].modify_type;
+ kt_hdr->name_size[0] = strlen(kt[i].keywords.keywords[0]);
+
+ for (j = 1; j < kt[i].keywords.count; j++) {
+ uint16_t name_size = strlen(kt[i].keywords.keywords[j]);
+ buffer_append(buf, &name_size, sizeof(name_size));
+ }
+ for (j = 0; j < kt[i].keywords.count; j++) {
+ const char *name = kt[i].keywords.keywords[j];
+ buffer_append(buf, name, strlen(name));
+ }
+ if ((buf->used % 4) != 0)
+ buffer_append_zero(buf, 4 - (buf->used % 4));
+ buffer_append_buf(buf, kt[i].messages, 0, (size_t)-1);
+
+ if (log_append_buffer(file, buf, NULL,
+ MAIL_TRANSACTION_KEYWORD_UPDATE,
+ t->external) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
int mail_transaction_log_append(struct mail_index_transaction *t,
uint32_t *log_file_seq_r,
uoff_t *log_file_offset_r)
@@ -1272,6 +1316,9 @@
if (t->ext_rec_updates != NULL && ret == 0)
ret = log_append_ext_rec_updates(file, t);
+ if (t->keyword_updates != NULL && ret == 0)
+ ret = log_append_keyword_updates(file, t);
+
if (t->expunges != NULL && ret == 0) {
ret = log_append_buffer(file, t->expunges, NULL,
MAIL_TRANSACTION_EXPUNGE, t->external);
Index: mail-transaction-log.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-transaction-log.h,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- mail-transaction-log.h 6 Nov 2004 17:20:19 -0000 1.21
+++ mail-transaction-log.h 26 Dec 2004 09:12:40 -0000 1.22
@@ -21,6 +21,7 @@
MAIL_TRANSACTION_EXT_RESET = 0x00000080,
MAIL_TRANSACTION_EXT_HDR_UPDATE = 0x00000100,
MAIL_TRANSACTION_EXT_REC_UPDATE = 0x00000200,
+ MAIL_TRANSACTION_KEYWORD_UPDATE = 0x00000400,
MAIL_TRANSACTION_TYPE_MASK = 0x0000ffff,
@@ -46,9 +47,17 @@
struct mail_transaction_flag_update {
uint32_t uid1, uid2;
uint8_t add_flags;
- keywords_mask_t add_keywords;
uint8_t remove_flags;
- keywords_mask_t remove_keywords;
+};
+
+struct mail_transaction_keyword_update {
+ uint32_t keywords_count;
+ uint8_t modify_type; /* enum modify_type */
+ uint8_t padding;
+ uint16_t name_size[1]; /* [keywords_count] */
+ /* unsigned char name[keywords_count][name_size];
+ array of { uint32_t uid1, uid2; }
+ */
};
struct mail_transaction_header_update {
Index: mail-transaction-util.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-transaction-util.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- mail-transaction-util.c 6 Nov 2004 17:20:19 -0000 1.21
+++ mail-transaction-util.c 26 Dec 2004 09:12:40 -0000 1.22
@@ -19,6 +19,7 @@
sizeof(struct mail_transaction_ext_reset) },
{ MAIL_TRANSACTION_EXT_HDR_UPDATE, 0, 1 },
{ MAIL_TRANSACTION_EXT_REC_UPDATE, 0, 1 },
+ { MAIL_TRANSACTION_KEYWORD_UPDATE, MAIL_INDEX_SYNC_TYPE_KEYWORDS, 1 },
{ 0, 0, 0 }
};
- Previous message: [dovecot-cvs] dovecot/src/lib-mail mail-types.h,1.2,1.3
- Next message: [dovecot-cvs] dovecot/src/lib-storage mail-copy.c, 1.1,
1.2 mail-storage-private.h, 1.9, 1.10 mail-storage.c, 1.31,
1.32 mail-storage.h, 1.84, 1.85 proxy-mail.c, 1.6,
1.7 proxy-mailbox.c, 1.12, 1.13
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the dovecot-cvs
mailing list