index-sync.c revision 2dec8a2ed04c9e0ac92bcce9aa7270eb98b3d53c
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "lib.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "buffer.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "index-storage.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainenstruct index_mailbox_sync_context {
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen struct mailbox_sync_context ctx;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen struct index_mailbox *ibox;
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen struct mail_index_view_sync_ctx *sync_ctx;
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen uint32_t messages_count;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
e82af44fe25ca9b88210f313548dc08538e4a677Timo Sirainen const uint32_t *expunges;
94a78eb438622fa53abef1e1726714dacad4b61cTimo Sirainen size_t expunges_count;
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen int failed;
d43c646d4b84635aa795946555be04a553d5413aTimo Sirainen};
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainenvoid index_mailbox_set_recent(struct index_mailbox *ibox, uint32_t seq)
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen{
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen unsigned char *p;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen size_t dest_idx;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen if (ibox->recent_flags_start_seq == 0) {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen ibox->recent_flags = buffer_create_dynamic(default_pool, 128);
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen ibox->recent_flags_start_seq = seq;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen } else if (seq < ibox->recent_flags_start_seq) {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen dest_idx = ibox->recent_flags_start_seq - seq;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen buffer_copy(ibox->recent_flags, dest_idx,
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen ibox->recent_flags, 0, (size_t)-1);
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen memset(buffer_get_modifyable_data(ibox->recent_flags, NULL),
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen 0, dest_idx);
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen ibox->recent_flags_start_seq = seq;
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen }
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen p = buffer_get_space_unsafe(ibox->recent_flags,
22535a9e685e29214082878e37a267157044618eTimo Sirainen seq - ibox->recent_flags_start_seq, 1);
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen if (*p == 0) {
1f1e81aab38d833d1c9cdc244c91fd762e0080d4Timo Sirainen ibox->recent_flags_count++;
1f1e81aab38d833d1c9cdc244c91fd762e0080d4Timo Sirainen *p = 1;
08aea01ef9a9d20703e0fcf8618e6195c0037a44Timo Sirainen }
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen}
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainenint index_mailbox_is_recent(struct index_mailbox *ibox, uint32_t seq)
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen{
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen const unsigned char *data;
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen size_t size;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen uint32_t idx;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen if (seq < ibox->recent_flags_start_seq ||
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen ibox->recent_flags_start_seq == 0)
22535a9e685e29214082878e37a267157044618eTimo Sirainen return FALSE;
7d6389e4053c2dac1fb37180b5756b00785983dcTimo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen idx = seq - ibox->recent_flags_start_seq;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen data = buffer_get_data(ibox->recent_flags, &size);
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen return idx < size ? data[idx] : FALSE;
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen}
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
473080c7c0d25ddfdf77e7dfa0ba8f73c6c669d5Timo Sirainenstatic void index_mailbox_expunge_recent(struct index_mailbox *ibox,
473080c7c0d25ddfdf77e7dfa0ba8f73c6c669d5Timo Sirainen uint32_t seq1, uint32_t seq2)
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen{
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen const unsigned char *data;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen size_t size;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen uint32_t i, idx, count, move;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen if (ibox->recent_flags_start_seq == 0) {
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen /* no recent flags */
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen return;
}
if (seq2 < ibox->recent_flags_start_seq) {
/* expunging messages before recent flags, just modify
the recent start position */
ibox->recent_flags_start_seq -= seq2 - seq1 + 1;
return;
}
if (seq1 < ibox->recent_flags_start_seq) {
move = ibox->recent_flags_start_seq - seq1;
seq1 = ibox->recent_flags_start_seq;
} else {
move = 0;
}
idx = seq1 - ibox->recent_flags_start_seq;
count = seq2 - seq1 + 1;
data = buffer_get_data(ibox->recent_flags, &size);
if (idx < size) {
if (idx + count > size)
count = size - idx;
for (i = 0; i < count; i++) {
if (data[idx+i])
ibox->recent_flags_count--;
}
buffer_copy(ibox->recent_flags, idx,
ibox->recent_flags, idx + count, (size_t)-1);
buffer_set_used_size(ibox->recent_flags, size - count);
}
ibox->recent_flags_start_seq -= move;
}
static int index_mailbox_update_recent(struct index_mailbox *ibox,
uint32_t seq1, uint32_t seq2)
{
const struct mail_index_record *rec;
for (; seq1 <= seq2; seq1++) {
if (mail_index_lookup(ibox->view, seq1, &rec) < 0) {
mail_storage_set_index_error(ibox);
return -1;
}
if ((rec->flags & MAIL_RECENT) != 0 ||
ibox->is_recent(ibox, rec->uid))
index_mailbox_set_recent(ibox, seq1);
}
return 0;
}
struct mailbox_sync_context *
index_mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags,
int failed)
{
struct index_mailbox *ibox = (struct index_mailbox *)box;
struct index_mailbox_sync_context *ctx;
enum mail_index_sync_type sync_mask;
ctx = i_new(struct index_mailbox_sync_context, 1);
ctx->ctx.box = box;
ctx->ibox = ibox;
if (failed) {
ctx->failed = TRUE;
return &ctx->ctx;
}
ctx->messages_count = mail_index_view_get_message_count(ibox->view);
sync_mask = MAIL_INDEX_SYNC_MASK_ALL;
if ((flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) != 0)
sync_mask &= ~MAIL_INDEX_SYNC_TYPE_EXPUNGE;
if (mail_index_view_sync_begin(ibox->view, sync_mask,
&ctx->sync_ctx) < 0) {
mail_storage_set_index_error(ibox);
ctx->failed = TRUE;
return &ctx->ctx;
}
if (!ibox->recent_flags_synced) {
ibox->recent_flags_synced = TRUE;
index_mailbox_update_recent(ibox, 1, ctx->messages_count);
}
if ((flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) == 0) {
ctx->expunges =
mail_index_view_sync_get_expunges(ctx->sync_ctx,
&ctx->expunges_count);
}
return &ctx->ctx;
}
int index_mailbox_sync_next(struct mailbox_sync_context *_ctx,
struct mailbox_sync_rec *sync_rec_r)
{
struct index_mailbox_sync_context *ctx =
(struct index_mailbox_sync_context *)_ctx;
struct mail_index_sync_rec sync;
int ret;
if (ctx->failed)
return -1;
while ((ret = mail_index_view_sync_next(ctx->sync_ctx, &sync)) > 0) {
switch (sync.type) {
case MAIL_INDEX_SYNC_TYPE_APPEND:
/* not interested */
break;
case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
/* later */
break;
case MAIL_INDEX_SYNC_TYPE_FLAGS:
/* FIXME: hide the flag updates for expunged messages */
if (mail_index_lookup_uid_range(ctx->ibox->view,
sync.uid1, sync.uid2,
&sync_rec_r->seq1,
&sync_rec_r->seq2) < 0) {
ctx->failed = TRUE;
return -1;
}
if (sync_rec_r->seq1 == 0)
break;
sync_rec_r->type = MAILBOX_SYNC_TYPE_FLAGS;
return 1;
}
}
if (ret == 0 && ctx->expunges_count > 0) {
/* expunges[] is a sorted array of sequences. it's easiest for
us to print them from end to beginning. */
sync_rec_r->seq1 = ctx->expunges[ctx->expunges_count*2-2];
sync_rec_r->seq2 = ctx->expunges[ctx->expunges_count*2-1];
index_mailbox_expunge_recent(ctx->ibox, sync_rec_r->seq1,
sync_rec_r->seq2);
if (sync_rec_r->seq2 > ctx->messages_count)
sync_rec_r->seq2 = ctx->messages_count;
ctx->messages_count -= sync_rec_r->seq2 - sync_rec_r->seq1 + 1;
ctx->expunges_count--;
sync_rec_r->type = MAILBOX_SYNC_TYPE_EXPUNGE;
return 1;
}
if (ret < 0)
mail_storage_set_index_error(ctx->ibox);
return ret;
}
#define SYNC_STATUS_FLAGS \
(STATUS_MESSAGES | STATUS_RECENT | STATUS_UIDNEXT | \
STATUS_UIDVALIDITY | STATUS_UNSEEN | STATUS_KEYWORDS)
int index_mailbox_sync_deinit(struct mailbox_sync_context *_ctx,
struct mailbox_status *status_r)
{
struct index_mailbox_sync_context *ctx =
(struct index_mailbox_sync_context *)_ctx;
struct index_mailbox *ibox = ctx->ibox;
uint32_t messages_count;
int ret = ctx->failed ? -1 : 0;
if (ctx->sync_ctx != NULL)
mail_index_view_sync_end(ctx->sync_ctx);
if (ret == 0) {
messages_count = mail_index_view_get_message_count(ibox->view);
if (messages_count != ctx->messages_count) {
index_mailbox_update_recent(ibox,
ctx->messages_count+1,
messages_count);
}
ibox->synced_recent_count = ibox->recent_flags_count;
ret = index_storage_get_status_locked(ctx->ibox,
SYNC_STATUS_FLAGS,
status_r);
}
mail_index_view_unlock(ctx->ibox->view);
i_free(ctx);
return ret;
}