#include "array.h"
#include "index-sync-private.h"
+struct index_storage_list_index_record {
+ uint32_t size;
+ uint32_t mtime;
+};
+
+ enum cache_mask {
+ CACHE_HDR = 0x01,
+ CACHE_BODY = 0x02,
+ CACHE_RECEIVED_DATE = 0x04,
+ CACHE_SAVE_DATE = 0x08,
+ CACHE_VIRTUAL_SIZE = 0x10,
+ CACHE_PHYSICAL_SIZE = 0x20,
+ CACHE_POP3_UIDL = 0x40,
+ CACHE_GUID = 0x80
+ };
+
enum mail_index_sync_flags index_storage_get_sync_flags(struct mailbox *box)
{
enum mail_index_sync_flags sync_flags = 0;
#endif
}
-cache_fields_get(const struct mailbox_status *status, bool debug)
+ static enum cache_mask
- cache_fields = array_get(status->cache_fields, &count);
++cache_fields_get(const struct mailbox_metadata *metadata, bool debug)
+ {
+ const char *const *cache_fields;
+ unsigned int i, count;
+ enum cache_mask cache = 0;
+
-static int cache_add(struct mailbox *box, const struct mailbox_status *status,
- enum cache_mask cache)
++ cache_fields = array_get(metadata->cache_fields, &count);
+ for (i = 0; i < count; i++) {
+ if (strncmp(cache_fields[i], "hdr.", 4) == 0 ||
+ strcmp(cache_fields[i], "date.sent") == 0 ||
+ strcmp(cache_fields[i], "imap.envelope") == 0)
+ cache |= CACHE_HDR;
+ else if (strcmp(cache_fields[i], "mime.parts") == 0 ||
+ strcmp(cache_fields[i], "imap.body") == 0 ||
+ strcmp(cache_fields[i], "imap.bodystructure") == 0)
+ cache |= CACHE_BODY;
+ else if (strcmp(cache_fields[i], "date.received") == 0)
+ cache |= CACHE_RECEIVED_DATE;
+ else if (strcmp(cache_fields[i], "date.save") == 0)
+ cache |= CACHE_SAVE_DATE;
+ else if (strcmp(cache_fields[i], "size.virtual") == 0)
+ cache |= CACHE_VIRTUAL_SIZE;
+ else if (strcmp(cache_fields[i], "size.physical") == 0)
+ cache |= CACHE_PHYSICAL_SIZE;
+ else if (strcmp(cache_fields[i], "pop3.uidl") == 0)
+ cache |= CACHE_POP3_UIDL;
+ else if (strcmp(cache_fields[i], "guid") == 0)
+ cache |= CACHE_GUID;
+ else if (debug) {
+ i_debug("Ignoring unknown cache field: %s",
+ cache_fields[i]);
+ }
+ }
+ return cache;
+ }
+
- mailbox_get_vname(box));
++static int cache_add(struct mailbox *box, enum cache_mask cache)
+ {
++ struct mailbox_status status;
+ struct mailbox_transaction_context *trans;
+ struct mail *mail;
+ uint32_t seq;
+ time_t date;
+ uoff_t size;
+ const char *str;
+
+ if (cache == 0) {
+ if (box->storage->set->mail_debug) {
+ i_debug("%s: Nothing in mailbox cache, skipping",
- for (seq = status->messages; seq > 0; seq--) {
++ box->vname);
+ }
+ return 0;
+ }
+
+ /* find the first message we need to index */
++ mailbox_get_open_status(box, STATUS_MESSAGES, &status);
+ trans = mailbox_transaction_begin(box, 0);
+ mail = mail_alloc(trans, 0, NULL);
- if (seq > status->messages) {
- i_debug("%s: Cache is already up to date",
- mailbox_get_vname(box));
++ for (seq = status.messages; seq > 0; seq--) {
+ mail_set_seq(mail, seq);
+ if (mail_is_cached(mail))
+ break;
+ }
+ seq++;
+
+ if (box->storage->set->mail_debug) {
- mailbox_get_vname(box),
- seq, status->messages, cache);
++ if (seq > status.messages) {
++ i_debug("%s: Cache is already up to date", box->vname);
+ } else {
+ i_debug("%s: Caching mails seq=%u..%u cache=0x%x",
- for (; seq <= status->messages; seq++) {
++ box->vname, seq, status.messages, cache);
+ }
+ }
+
- i_error("Commiting mailbox %s failed: %s",
- mailbox_get_vname(box),
- mail_storage_get_last_error(mailbox_get_storage(box), NULL));
++ for (; seq <= status.messages; seq++) {
+ mail_set_seq(mail, seq);
+
+ if ((cache & (CACHE_HDR | CACHE_BODY)) != 0)
+ mail_parse(mail, (cache & CACHE_BODY) != 0);
+ if ((cache & CACHE_RECEIVED_DATE) != 0)
+ (void)mail_get_received_date(mail, &date);
+ if ((cache & CACHE_SAVE_DATE) != 0)
+ (void)mail_get_save_date(mail, &date);
+ if ((cache & CACHE_VIRTUAL_SIZE) != 0)
+ (void)mail_get_virtual_size(mail, &size);
+ if ((cache & CACHE_PHYSICAL_SIZE) != 0)
+ (void)mail_get_physical_size(mail, &size);
+ if ((cache & CACHE_POP3_UIDL) != 0) {
+ (void)mail_get_special(mail, MAIL_FETCH_UIDL_BACKEND,
+ &str);
+ }
+ if ((cache & CACHE_GUID) != 0)
+ (void)mail_get_special(mail, MAIL_FETCH_GUID, &str);
+ }
+ mail_free(&mail);
+ if (mailbox_transaction_commit(&trans) < 0) {
- struct mailbox_status status;
++ mail_storage_set_critical(box->storage,
++ "Commiting mailbox %s failed: %s", box->vname,
++ mailbox_get_last_error(box, NULL));
+ return -1;
+ }
+ return 0;
+ }
+
+ static int index_sync_precache(struct mailbox *box)
+ {
- mailbox_get_status(box, STATUS_MESSAGES | STATUS_CACHE_FIELDS, &status);
++ struct mailbox_metadata metadata;
+ enum cache_mask cache;
+
- cache = cache_fields_get(&status, box->storage->set->mail_debug);
- return cache_add(box, &status, cache);
++ if (mailbox_get_metadata(box, MAILBOX_METADATA_CACHE_FIELDS,
++ &metadata) < 0) {
++ mail_storage_set_critical(box->storage,
++ "Metadata lookup from mailbox %s failed: %s", box->vname,
++ mailbox_get_last_error(box, NULL));
++ return -1;
++ }
+
++ cache = cache_fields_get(&metadata, box->storage->set->mail_debug);
++ return cache_add(box, cache);
+ }
+
int index_mailbox_sync_deinit(struct mailbox_sync_context *_ctx,
struct mailbox_sync_status *status_r)
{
struct fts_storage_build_context {
struct mail_search_context *search_ctx;
struct mail_search_args *search_args;
-- struct mail *mail;
struct fts_backend_build_context *build;
struct timeval search_start_time, last_notify;
str_append_c(ctx->headers, '\n');
}
--static int fts_build_mail(struct fts_storage_build_context *ctx, uint32_t uid)
++static int
++fts_build_mail(struct fts_storage_build_context *ctx, struct mail *mail)
{
enum message_decoder_flags decoder_flags = MESSAGE_DECODER_FLAG_DTCASE;
struct istream *input;
bool skip_body = FALSE, body_part = FALSE;
int ret;
-- ctx->uid = uid;
++ ctx->uid = mail->uid;
-- if (mail_get_stream(ctx->mail, NULL, NULL, &input) < 0)
++ if (mail_get_stream(mail, NULL, NULL, &input) < 0)
return -1;
prev_part = NULL;
if (!skip_body && body_part)
fts_backend_build_body_end(ctx->build);
if (message_parser_deinit(&parser, &parts) < 0)
-- mail_set_cache_corrupted(ctx->mail, MAIL_FETCH_MESSAGE_PARTS);
++ mail_set_cache_corrupted(mail, MAIL_FETCH_MESSAGE_PARTS);
message_decoder_deinit(&decoder);
if (ret == 0) {
static int fts_build_deinit(struct fts_storage_build_context **_ctx)
{
struct fts_storage_build_context *ctx = *_ctx;
-- struct mailbox *box = ctx->mail->transaction->box;
++ struct mailbox *box = ctx->search_ctx->transaction->box;
struct fts_mailbox *fbox = FTS_CONTEXT(box);
struct mailbox_status status;
int ret = 0;
if (mailbox_search_deinit(&ctx->search_ctx) < 0)
ret = -1;
- ctx->mail = NULL;
- mail_free(&ctx->mail);
if (fts_backend_build_deinit(&ctx->build) < 0)
ret = -1;
return ret;
}
--static void fts_build_notify(struct fts_storage_build_context *ctx)
++static void
++fts_build_notify(struct fts_storage_build_context *ctx, uint32_t seq)
{
-- struct mailbox *box = ctx->mail->transaction->box;
++ struct mailbox *box = ctx->search_ctx->transaction->box;
if (ctx->last_notify.tv_sec == 0) {
/* set the search time in here, in case a plugin
seq_diff = range->seq2 - range->seq1;
if (seq_diff != 0) {
-- completed_frac = (double)(ctx->mail->seq - range->seq1) / seq_diff;
++ completed_frac = (double)(seq - range->seq1) / seq_diff;
if (completed_frac >= 0.000001) {
unsigned int elapsed_msecs, est_total_msecs;
static int fts_build_more(struct fts_storage_build_context *ctx)
{
++ struct mail *mail = NULL;
unsigned int count = 0;
int ret;
-- if (ioloop_time - ctx->last_notify.tv_sec >=
-- FTS_BUILD_NOTIFY_INTERVAL_SECS)
-- fts_build_notify(ctx);
--
- while (mailbox_search_next(ctx->search_ctx, &ctx->mail)) {
- while (mailbox_search_next(ctx->search_ctx, ctx->mail)) {
++ while (mailbox_search_next(ctx->search_ctx, &mail)) {
T_BEGIN {
-- ret = fts_build_mail(ctx, ctx->mail->uid);
++ ret = fts_build_mail(ctx, mail);
} T_END;
if (ret < 0)
return 0;
}
++ if (ioloop_time - ctx->last_notify.tv_sec >=
++ FTS_BUILD_NOTIFY_INTERVAL_SECS && mail != NULL)
++ fts_build_notify(ctx, mail->seq);
return 1;
}
}
}
}
- struct mail *mail, bool *tryagain_r)
+ return ret;
+ }
+
+ static bool
+ fts_mailbox_search_next_nonblock(struct mail_search_context *ctx,
++ struct mail **mail_r, bool *tryagain_r)
+ {
+ struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
+ struct fts_search_context *fctx = FTS_CONTEXT(ctx);
+
+ if (!fctx->build_initialized) {
+ /* we're still waiting for this process (but another command)
+ to finish building the indexes */
+ if (!fts_try_build_init(ctx, fctx)) {
+ *tryagain_r = TRUE;
+ return FALSE;
+ }
+ }
+
+ if (fts_mailbox_search_build_more(ctx) == 0) {
+ *tryagain_r = TRUE;
+ return FALSE;
+ }
/* if we're here, the indexes are either built or they're not used */
return fbox->module_ctx.super.
return ret;
}
- search_args->charset = "UTF-8";
+ static int fts_update(struct mailbox *box)
+ {
+ struct mailbox_transaction_context *t;
+ struct mail_search_args *search_args;
+ struct mail_search_arg *arg;
+ struct mail_search_context *ctx;
+ struct fts_search_context *fctx;
+ int ret = 0;
+
+ t = mailbox_transaction_begin(box, 0);
+ search_args = mail_search_build_init();
- ctx = mailbox_search_init(t, search_args, NULL);
+ mail_search_build_add_all(search_args);
+ arg = mail_search_build_add(search_args, SEARCH_BODY_FAST);
+ arg->value.str = "xyzzy";
+
++ ctx = mailbox_search_init(t, search_args, NULL, 0, NULL);
+ mail_search_args_unref(&search_args);
+
+ fctx = FTS_CONTEXT(ctx);
+ if (fctx->build_initialized) {
+ while ((ret = fts_mailbox_search_build_more(ctx)) == 0) ;
+ }
+ (void)mailbox_search_deinit(&ctx);
+ (void)mailbox_transaction_commit(&t);
+
+ return ret < 0 ? -1 : 0;
+ }
+
+ static int fts_sync_deinit(struct mailbox_sync_context *ctx,
+ struct mailbox_sync_status *status_r)
+ {
+ struct mailbox *box = ctx->box;
+ struct fts_mailbox *fbox = FTS_CONTEXT(box);
+ bool precache;
+
+ precache = (ctx->flags & MAILBOX_SYNC_FLAG_PRECACHE) != 0;
+ if (fbox->module_ctx.super.sync_deinit(ctx, status_r) < 0)
+ return -1;
+ ctx = NULL;
+
+ return !precache ? 0 : fts_update(box);
+ }
+
static void fts_mailbox_init(struct mailbox *box, const char *env)
{
struct mailbox_vfuncs *v = box->vlast;