mbox-sync.c revision 2d39dc1a453546892109b35c0d9770369011a13d
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose/* Copyright (C) 2004 Timo Sirainen */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose/*
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose Modifying mbox can be slow, so we try to do it all at once minimizing the
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose required disk I/O. We may need to:
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose - Update message flags in Status, X-Status and X-Keywords headers
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose - Write missing X-UID and X-IMAPbase headers
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose - Write missing or broken Content-Length header if there's space
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose - Expunge specified messages
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose Here's how we do it:
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose - Start reading the mails from the beginning
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose - X-Keywords, X-UID and X-IMAPbase headers may contain padding at the end
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose of them, remember how much each message has and offset to beginning of the
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose padding
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose - If header needs to be rewritten and there's enough space, do it
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose - If we didn't have enough space, remember how much was missing
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose - Continue reading and counting the padding in each message. If available
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose padding is enough to rewrite all the previous messages needing it, do it
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose - When we encounter expunged message, treat all of it as padding and
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose rewrite previous messages if needed (and there's enough space).
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose Afterwards keep moving messages backwards to fill the expunged space.
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose Moving is done by rewriting each message's headers, with possibly adding
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose missing Content-Length header and padding. Message bodies are moved
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose without modifications.
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose - If we encounter end of file, grow the file and rewrite needed messages
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose - Rewriting is done by moving message body forward, rewriting message's
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose header and doing the same for previous message, until all of them are
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose rewritten.
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose*/
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "lib.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "ioloop.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "array.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "buffer.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "hostpid.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "istream.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "file-set-size.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "str.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "read-full.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "write-full.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "message-date.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "istream-raw-mbox.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "mbox-storage.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "mbox-from.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "mbox-file.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "mbox-lock.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include "mbox-sync-private.h"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include <stddef.h>
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include <stdlib.h>
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include <utime.h>
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#include <sys/stat.h>
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose/* The text below was taken exactly as c-client wrote it to my mailbox,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose so it's probably copyrighted by University of Washington. */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#define PSEUDO_MESSAGE_BODY \
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose"This text is part of the internal format of your mail folder, and is not\n" \
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov"a real message. It is created automatically by the mail system software.\n" \
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose"If deleted, important folder data will be lost, and it will be re-created\n" \
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose"with the data reset to initial values.\n"
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosevoid mbox_sync_set_critical(struct mbox_sync_context *sync_ctx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const char *fmt, ...)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov va_list va;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->ext_modified) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_storage_set_critical(&sync_ctx->mbox->storage->storage,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose "mbox file %s was modified while we were syncing, "
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose "check your locking settings", sync_ctx->mbox->path);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose va_start(va, fmt);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_storage_set_critical(&sync_ctx->mbox->storage->storage,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose "%s", t_strdup_vprintf(fmt, va));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose va_end(va);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Boseint mbox_sync_seek(struct mbox_sync_context *sync_ctx, uoff_t from_offset)
401d8b0600dd2d36f6d62ee1d72f56a245cc3158Jakub Hrozek{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (istream_raw_mbox_seek(sync_ctx->input, from_offset) < 0) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov mbox_sync_set_critical(sync_ctx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose "Unexpectedly lost From-line at offset %"PRIuUOFF_T
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose " from mbox file %s", from_offset,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->mbox->path);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
401d8b0600dd2d36f6d62ee1d72f56a245cc3158Jakub Hrozekvoid mbox_sync_file_update_ext_modified(struct mbox_sync_context *sync_ctx)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov struct stat st;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* Do this even if ext_modified is already set. Expunging code relies
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose on last_stat being updated. */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (fstat(sync_ctx->write_fd, &st) < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_set_syscall_error(sync_ctx->mbox, "fstat()");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (st.st_size != sync_ctx->last_stat.st_size ||
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov (sync_ctx->last_stat.st_mtime != 0 &&
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose (st.st_mtime != sync_ctx->last_stat.st_mtime
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#ifdef HAVE_STAT_TV_NSEC
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* nanoseconds give better precision to this check if they're
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose supported by the OS */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose || st.st_mtim.tv_nsec != sync_ctx->last_stat.st_mtim.tv_nsec
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#endif
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose )))
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov sync_ctx->ext_modified = TRUE;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->last_stat = st;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosevoid mbox_sync_file_updated(struct mbox_sync_context *sync_ctx, bool dirty)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (dirty) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* just mark the stat as dirty. */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->last_stat.st_mtime = 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (fstat(sync_ctx->write_fd, &sync_ctx->last_stat) < 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_set_syscall_error(sync_ctx->mbox, "fstat()");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_stream_sync(sync_ctx->input);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic void mbox_sync_array_delete_to(ARRAY_TYPE(sync_recs) *syncs_arr,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uint32_t last_uid)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mail_index_sync_rec *syncs;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose unsigned int src, dest, count;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose syncs = array_get_modifiable(syncs_arr, &count);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose for (src = dest = 0; src < count; src++) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_assert(last_uid >= syncs[src].uid1);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (last_uid <= syncs[src].uid2) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* keep it */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (src != dest)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov syncs[dest] = syncs[src];
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose dest++;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose array_delete(syncs_arr, dest, count - dest);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashovstatic int
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosembox_sync_read_next_mail(struct mbox_sync_context *sync_ctx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mbox_sync_mail_context *mail_ctx)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* get EOF */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose (void)istream_raw_mbox_get_header_offset(sync_ctx->input);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (istream_raw_mbox_is_eof(sync_ctx->input))
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose p_clear(sync_ctx->mail_keyword_pool);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose memset(mail_ctx, 0, sizeof(*mail_ctx));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->sync_ctx = sync_ctx;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->seq = ++sync_ctx->seq;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->header = sync_ctx->header;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.from_offset =
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose istream_raw_mbox_get_start_offset(sync_ctx->input);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.offset =
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose istream_raw_mbox_get_header_offset(sync_ctx->input);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_sync_parse_next_mail(sync_ctx->input, mail_ctx);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_assert(sync_ctx->input->v_offset != mail_ctx->mail.from_offset ||
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->input->eof);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.body_size =
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose istream_raw_mbox_get_body_size(sync_ctx->input,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->content_length);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_assert(mail_ctx->mail.body_size < OFF_T_MAX);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if ((mail_ctx->mail.flags & MAIL_RECENT) != 0 &&
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose !mail_ctx->mail.pseudo) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (!sync_ctx->mbox->ibox.keep_recent) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* need to add 'O' flag to Status-header */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->need_rewrite = TRUE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->recent = TRUE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic bool mbox_sync_buf_have_expunges(ARRAY_TYPE(sync_recs) *syncs_arr)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const struct mail_index_sync_rec *syncs;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose unsigned int i, count;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
b3292840ebaa747a9fd596ff47cc5d18198361d0Michal Zidek syncs = array_get(syncs_arr, &count);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose for (i = 0; i < count; i++) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (syncs[i].type == MAIL_INDEX_SYNC_TYPE_EXPUNGE)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return TRUE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return FALSE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashovstatic int mbox_sync_read_index_syncs(struct mbox_sync_context *sync_ctx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uint32_t uid, bool *sync_expunge_r)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mail_index_sync_rec *sync_rec = &sync_ctx->sync_rec;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose int ret;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose *sync_expunge_r = FALSE;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->index_sync_ctx == NULL)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (uid == 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* nothing for this or the future ones */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uid = (uint32_t)-1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_sync_array_delete_to(&sync_ctx->syncs, uid);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose while (uid >= sync_rec->uid1) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (uid <= sync_rec->uid2 &&
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_rec->type != MAIL_INDEX_SYNC_TYPE_APPEND &&
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov (sync_rec->type != MAIL_INDEX_SYNC_TYPE_EXPUNGE ||
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov !sync_ctx->mbox->mbox_readonly)) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose array_append(&sync_ctx->syncs, sync_rec, 1);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_EXPUNGE)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose *sync_expunge_r = TRUE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov ret = mail_index_sync_next(sync_ctx->index_sync_ctx, sync_rec);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (ret < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_storage_set_index_error(&sync_ctx->mbox->ibox);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (ret == 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose memset(sync_rec, 0, sizeof(*sync_rec));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose break;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose switch (sync_rec->type) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose case MAIL_INDEX_SYNC_TYPE_APPEND:
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (sync_rec->uid2 >= sync_ctx->next_uid)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov sync_ctx->next_uid = sync_rec->uid2 + 1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose memset(sync_rec, 0, sizeof(*sync_rec));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose break;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose break;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose case MAIL_INDEX_SYNC_TYPE_FLAGS:
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET:
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->delay_writes) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* we're not going to write these yet */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uint32_t seq1, seq2;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (mail_index_lookup_uid_range(
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->sync_view,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_rec->uid1, sync_rec->uid2,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose &seq1, &seq2) < 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose memset(sync_rec, 0, sizeof(*sync_rec));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (seq1 == 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose break;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_update_flags_range(sync_ctx->t,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose seq1, seq2, MODIFY_ADD,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose (enum mail_flags)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose MAIL_INDEX_MAIL_FLAG_DIRTY);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose break;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (!*sync_expunge_r)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose *sync_expunge_r = mbox_sync_buf_have_expunges(&sync_ctx->syncs);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosevoid mbox_sync_apply_index_syncs(struct mbox_sync_context *sync_ctx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mbox_sync_mail *mail,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose enum mailbox_sync_type *sync_type_r)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const struct mail_index_sync_rec *syncs;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose unsigned int i, count;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose enum mailbox_sync_type sync_type = 0;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose syncs = array_get(&sync_ctx->syncs, &count);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose for (i = 0; i < count; i++) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose switch (syncs[i].type) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose case MAIL_INDEX_SYNC_TYPE_FLAGS:
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_sync_flags_apply(&syncs[i], &mail->flags);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_type |= MAILBOX_SYNC_TYPE_FLAGS;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose break;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET:
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (!array_is_created(&mail->keywords)) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* no existing keywords */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (syncs[i].type !=
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose break;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* adding, create the array */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose p_array_init(&mail->keywords,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->mail_keyword_pool,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose I_MIN(10, count - i));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (mail_index_sync_keywords_apply(&syncs[i],
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose &mail->keywords))
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_type |= MAILBOX_SYNC_TYPE_KEYWORDS;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose break;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose default:
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose break;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose *sync_type_r = sync_type;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic int
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosembox_sync_read_index_rec(struct mbox_sync_context *sync_ctx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uint32_t uid, const struct mail_index_record **rec_r)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const struct mail_index_record *rec = NULL;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uint32_t messages_count;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose int ret = 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose messages_count =
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_view_get_messages_count(sync_ctx->sync_view);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov while (sync_ctx->idx_seq <= messages_count) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose ret = mail_index_lookup(sync_ctx->sync_view,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->idx_seq, &rec);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (ret < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_storage_set_index_error(&sync_ctx->mbox->ibox);
d115f40c7a3999e3cbe705a2ff9cf0fd493f80fbMichal Zidek return -1;
d115f40c7a3999e3cbe705a2ff9cf0fd493f80fbMichal Zidek }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_assert(ret != 0); /* we should be looking at head index */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (uid <= rec->uid)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov break;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* externally expunged message, remove from index */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_expunge(sync_ctx->t, sync_ctx->idx_seq);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov sync_ctx->idx_seq++;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose rec = NULL;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (rec == NULL && uid < sync_ctx->idx_next_uid) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* this UID was already in index and it was expunged */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_sync_set_critical(sync_ctx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose "mbox sync: Expunged message reappeared in mailbox %s "
d115f40c7a3999e3cbe705a2ff9cf0fd493f80fbMichal Zidek "(UID %u < %u, seq=%u, idx_msgs=%u)",
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->mbox->path, uid, sync_ctx->idx_next_uid,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->seq, messages_count);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov ret = 0; rec = NULL;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose } else if (rec != NULL && rec->uid != uid) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* new UID in the middle of the mailbox - shouldn't happen */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_sync_set_critical(sync_ctx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose "mbox sync: UID inserted in the middle of mailbox %s "
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose "(%u > %u, seq=%u, idx_msgs=%u)", sync_ctx->mbox->path,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov rec->uid, uid, sync_ctx->seq, messages_count);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose ret = 0; rec = NULL;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose } else {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose ret = 1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose *rec_r = rec;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return ret;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic int mbox_sync_find_index_md5(struct mbox_sync_context *sync_ctx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose unsigned char hdr_md5_sum[],
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const struct mail_index_record **rec_r)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const struct mail_index_record *rec = NULL;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov uint32_t messages_count;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const void *data;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose int ret;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose messages_count =
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_view_get_messages_count(sync_ctx->sync_view);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose while (sync_ctx->idx_seq <= messages_count) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose ret = mail_index_lookup(sync_ctx->sync_view,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->idx_seq, &rec);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (ret < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_storage_set_index_error(&sync_ctx->mbox->ibox);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (mail_index_lookup_ext(sync_ctx->sync_view,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->idx_seq,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->mbox->ibox.md5hdr_ext_idx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose &data) < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_storage_set_index_error(&sync_ctx->mbox->ibox);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (data != NULL && memcmp(data, hdr_md5_sum, 16) == 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose break;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* externally expunged message, remove from index */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_expunge(sync_ctx->t, sync_ctx->idx_seq);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->idx_seq++;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose rec = NULL;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose *rec_r = rec;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic int
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosembox_sync_update_from_offset(struct mbox_sync_context *sync_ctx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mbox_sync_mail *mail,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose bool nocheck)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const void *data;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uint64_t offset;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (!nocheck) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* see if from_offset needs updating */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (mail_index_lookup_ext(sync_ctx->sync_view,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->idx_seq,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->mbox->mbox_ext_idx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose &data) < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_storage_set_index_error(&sync_ctx->mbox->ibox);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (data != NULL &&
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose *((const uint64_t *)data) == mail->from_offset)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose offset = mail->from_offset;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_update_ext(sync_ctx->t, sync_ctx->idx_seq,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov sync_ctx->mbox->mbox_ext_idx, &offset, NULL);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic void
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosembox_sync_update_index_keywords(struct mbox_sync_mail_context *mail_ctx)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mail_keywords *keywords;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose keywords = !array_is_created(&mail_ctx->mail.keywords) ?
63748c69a2c6785d949c82f94749704e0408e5a7Sumit Bose mail_index_keywords_create(sync_ctx->t, NULL) :
63748c69a2c6785d949c82f94749704e0408e5a7Sumit Bose mail_index_keywords_create_from_indexes(sync_ctx->t,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose &mail_ctx->mail.keywords);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov mail_index_update_keywords(sync_ctx->t, sync_ctx->idx_seq,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose MODIFY_REPLACE, keywords);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_keywords_free(&keywords);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic int
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosembox_sync_update_md5_if_changed(struct mbox_sync_mail_context *mail_ctx)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const void *ext_data;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (mail_index_lookup_ext(sync_ctx->sync_view, sync_ctx->idx_seq,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->mbox->ibox.md5hdr_ext_idx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose &ext_data) < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_storage_set_index_error(&sync_ctx->mbox->ibox);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (ext_data == NULL ||
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose memcmp(mail_ctx->hdr_md5_sum, ext_data, 16) != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_update_ext(sync_ctx->t, sync_ctx->idx_seq,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->mbox->ibox.md5hdr_ext_idx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->hdr_md5_sum, NULL);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic int mbox_sync_update_index(struct mbox_sync_mail_context *mail_ctx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const struct mail_index_record *rec)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mbox_sync_mail *mail = &mail_ctx->mail;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov struct mailbox *box = &sync_ctx->mbox->ibox.box;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uint8_t mbox_flags;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_flags = mail->flags & MAIL_FLAGS_MASK;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (mail_ctx->dirty)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_flags |= MAIL_INDEX_MAIL_FLAG_DIRTY;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov else if (!sync_ctx->delay_writes)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_flags &= ~MAIL_INDEX_MAIL_FLAG_DIRTY;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (rec == NULL) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* new message */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_append(sync_ctx->t, mail->uid, &sync_ctx->idx_seq);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_update_flags(sync_ctx->t, sync_ctx->idx_seq,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose MODIFY_REPLACE, mbox_flags);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov mbox_sync_update_index_keywords(mail_ctx);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->mbox->mbox_save_md5 != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_update_ext(sync_ctx->t, sync_ctx->idx_seq,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->mbox->ibox.md5hdr_ext_idx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->hdr_md5_sum, NULL);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose } else {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* see if we need to update flags in index file. the flags in
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync records are automatically applied to rec->flags at the
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose end of index syncing, so calculate those new flags first */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mbox_sync_mail idx_mail;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose enum mailbox_sync_type sync_type;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose memset(&idx_mail, 0, sizeof(idx_mail));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose idx_mail.flags = rec->flags;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* get old keywords */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose t_push();
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose t_array_init(&idx_mail.keywords, 32);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (mail_index_lookup_keywords(sync_ctx->sync_view,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->idx_seq,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose &idx_mail.keywords) < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_storage_set_index_error(&sync_ctx->mbox->ibox);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose t_pop();
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_sync_apply_index_syncs(sync_ctx, &idx_mail,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose &sync_type);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_type != 0 && box->v.sync_notify != NULL)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose box->v.sync_notify(box, rec->uid, sync_type);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose#define SYNC_FLAGS (MAIL_RECENT | MAIL_INDEX_MAIL_FLAG_DIRTY)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if ((idx_mail.flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* flags are dirty. ignore whatever was in the mbox,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose but update recent/dirty flag states if needed. */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov mbox_flags &= SYNC_FLAGS;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_flags |= idx_mail.flags & ~SYNC_FLAGS;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->delay_writes)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov mbox_flags |= MAIL_INDEX_MAIL_FLAG_DIRTY;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov } else {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* keep index's internal flags */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_flags &= MAIL_FLAGS_MASK | SYNC_FLAGS;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_flags |= idx_mail.flags &
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose ~(MAIL_FLAGS_MASK | SYNC_FLAGS);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if ((idx_mail.flags & ~SYNC_FLAGS) !=
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose (mbox_flags & ~SYNC_FLAGS)) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* flags other than recent/dirty have changed */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_update_flags(sync_ctx->t, sync_ctx->idx_seq,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose MODIFY_REPLACE, mbox_flags);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose } else {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (((idx_mail.flags ^ mbox_flags) &
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose MAIL_RECENT) != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* drop recent flag (it can only be dropped) */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_update_flags(sync_ctx->t,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->idx_seq,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose MODIFY_REMOVE, MAIL_RECENT);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (((idx_mail.flags ^ mbox_flags) &
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* dirty flag state changed */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose bool dirty = (mbox_flags &
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose MAIL_INDEX_MAIL_FLAG_DIRTY) != 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_update_flags(sync_ctx->t,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->idx_seq,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose dirty ? MODIFY_ADD : MODIFY_REMOVE,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose (enum mail_flags)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose MAIL_INDEX_MAIL_FLAG_DIRTY);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if ((idx_mail.flags & MAIL_INDEX_MAIL_FLAG_DIRTY) == 0 &&
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose !index_keyword_array_cmp(&idx_mail.keywords,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose &mail_ctx->mail.keywords))
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_sync_update_index_keywords(mail_ctx);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose t_pop();
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* see if we need to update md5 sum. */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->mbox->mbox_save_md5 != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (mbox_sync_update_md5_if_changed(mail_ctx) < 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (mail_ctx->recent &&
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov (rec == NULL || (rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) == 0 ||
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose (rec->flags & MAIL_RECENT) != 0)) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose index_mailbox_set_recent(&sync_ctx->mbox->ibox,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->idx_seq);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* update from_offsets, but not if we're going to rewrite this message.
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose rewriting would just move it anyway. */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->need_space_seq == 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose bool nocheck = rec == NULL || sync_ctx->expunged_space > 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (mbox_sync_update_from_offset(sync_ctx, mail, nocheck) < 0)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic int mbox_read_from_line(struct mbox_sync_mail_context *ctx)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct istream *input = ctx->sync_ctx->file_input;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const unsigned char *data;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose size_t size, from_line_size;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose buffer_set_used_size(ctx->sync_ctx->from_line, 0);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose from_line_size = ctx->hdr_offset - ctx->mail.from_offset;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_stream_seek(input, ctx->mail.from_offset);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov for (;;) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose data = i_stream_get_data(input, &size);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (size >= from_line_size)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose size = from_line_size;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose buffer_append(ctx->sync_ctx->from_line, data, size);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_stream_skip(input, size);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose from_line_size -= size;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (from_line_size == 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose break;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (i_stream_read(input) < 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic int mbox_rewrite_base_uid_last(struct mbox_sync_context *sync_ctx)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose unsigned char buf[10];
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov const char *str;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uint32_t uid_last;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose unsigned int i;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose int ret;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov i_assert(sync_ctx->base_uid_last_offset != 0);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* first check that the 10 bytes are there and they're exactly as
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose expected. just an extra safety check to make sure we never write
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose to wrong location in the mbox file. */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose ret = pread_full(sync_ctx->write_fd, buf, sizeof(buf),
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->base_uid_last_offset);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (ret < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_set_syscall_error(sync_ctx->mbox, "pread_full()");
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (ret == 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_sync_set_critical(sync_ctx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose "X-IMAPbase uid-last unexpectedly points outside "
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose "mbox file %s", sync_ctx->mbox->path);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose for (i = 0, uid_last = 0; i < sizeof(buf); i++) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (buf[i] < '0' || buf[i] > '9') {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uid_last = (uint32_t)-1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose break;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uid_last = uid_last * 10 + (buf[i] - '0');
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (uid_last != sync_ctx->base_uid_last) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_sync_set_critical(sync_ctx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose "X-IMAPbase uid-last unexpectedly lost in mbox file %s",
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->mbox->path);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* and write it */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose str = t_strdup_printf("%010u", sync_ctx->next_uid - 1);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (pwrite_full(sync_ctx->write_fd, str, 10,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->base_uid_last_offset) < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_set_syscall_error(sync_ctx->mbox, "pwrite_full()");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_sync_file_updated(sync_ctx, FALSE);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->base_uid_last = sync_ctx->next_uid - 1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic int
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosembox_write_from_line(struct mbox_sync_mail_context *ctx)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose string_t *str = ctx->sync_ctx->from_line;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (pwrite_full(ctx->sync_ctx->write_fd, str_data(str), str_len(str),
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose ctx->mail.from_offset) < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_set_syscall_error(ctx->sync_ctx->mbox, "pwrite_full()");
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_sync_file_updated(ctx->sync_ctx, FALSE);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic void update_from_offsets(struct mbox_sync_context *sync_ctx)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose const struct mbox_sync_mail *mails;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose unsigned int i, count;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uint32_t ext_idx;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uint64_t offset;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose ext_idx = sync_ctx->mbox->mbox_ext_idx;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mails = array_get(&sync_ctx->mails, &count);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose for (i = 0; i < count; i++) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (mails[i].idx_seq == 0 || mails[i].expunged)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose continue;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->moved_offsets = TRUE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose offset = mails[i].from_offset;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_update_ext(sync_ctx->t, mails[i].idx_seq,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose ext_idx, &offset, NULL);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic void mbox_sync_handle_expunge(struct mbox_sync_mail_context *mail_ctx)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mailbox *box = &sync_ctx->mbox->ibox.box;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (box->v.sync_notify != NULL) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose box->v.sync_notify(box, mail_ctx->mail.uid,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov MAILBOX_SYNC_TYPE_EXPUNGE);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_index_expunge(sync_ctx->t, mail_ctx->mail.idx_seq);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.expunged = TRUE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.offset = mail_ctx->mail.from_offset;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.space =
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->body_offset - mail_ctx->mail.from_offset +
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.body_size;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.body_size = 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.uid = 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->seq == 1) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* expunging first message, fix space to contain next
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose message's \n header too since it will be removed. */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.space++;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (istream_raw_mbox_has_crlf_ending(sync_ctx->input)) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.space++;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->first_mail_crlf_expunged = TRUE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* uid-last offset is invalid now */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->base_uid_last_offset = 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->expunged_space += mail_ctx->mail.space;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov}
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosestatic int mbox_sync_handle_header(struct mbox_sync_mail_context *mail_ctx)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uoff_t orig_from_offset;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose off_t move_diff;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose int ret;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->expunged_space > 0 && sync_ctx->need_space_seq == 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* move the header backwards to fill expunged space */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose move_diff = -sync_ctx->expunged_space;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose orig_from_offset = mail_ctx->mail.from_offset;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->dest_first_mail) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* we're moving this mail to beginning of file.
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov skip the initial \n (it's already counted in
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose expunged_space) */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.from_offset++;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->first_mail_crlf_expunged)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.from_offset++;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* read the From-line before rewriting overwrites it */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (mbox_read_from_line(mail_ctx) < 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_sync_update_header(mail_ctx);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose ret = mbox_sync_try_rewrite(mail_ctx, move_diff);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (ret < 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (ret > 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* rewrite successful, write From-line to
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose new location */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_assert(move_diff > 0 ||
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose (off_t)mail_ctx->mail.from_offset >=
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose -move_diff);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.from_offset += move_diff;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.offset += move_diff;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (mbox_write_from_line(mail_ctx) < 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose } else {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->dest_first_mail) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* didn't have enough space, move the offset
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose back so seeking into it doesn't fail */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.from_offset = orig_from_offset;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose } else if (mail_ctx->need_rewrite ||
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov array_count(&sync_ctx->syncs) != 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_sync_update_header(mail_ctx);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->delay_writes) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* mark it dirty and do it later */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov mail_ctx->dirty = TRUE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if ((ret = mbox_sync_try_rewrite(mail_ctx, 0)) < 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose } else {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* nothing to do */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (ret == 0 && sync_ctx->need_space_seq == 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* first mail with no space to write it */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->need_space_seq = sync_ctx->seq;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->space_diff = 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->expunged_space > 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* create dummy message to describe the expunged data */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mbox_sync_mail mail;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose memset(&mail, 0, sizeof(mail));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail.expunged = TRUE;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail.offset = mail.from_offset =
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose (sync_ctx->dest_first_mail ? 1 : 0) +
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.from_offset -
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->expunged_space;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail.space = sync_ctx->expunged_space;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->space_diff = sync_ctx->expunged_space;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->expunged_space = 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_assert(sync_ctx->space_diff < -mail_ctx->mail.space);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->need_space_seq--;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose array_append(&sync_ctx->mails, &mail, 1);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
b07a3b729892d2bc2ffa73d93de95e19003cc6c8Pavel Reichl return 0;
b07a3b729892d2bc2ffa73d93de95e19003cc6c8Pavel Reichl}
b07a3b729892d2bc2ffa73d93de95e19003cc6c8Pavel Reichl
b07a3b729892d2bc2ffa73d93de95e19003cc6c8Pavel Reichlstatic int
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bosembox_sync_handle_missing_space(struct mbox_sync_mail_context *mail_ctx)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose{
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uoff_t end_offset, move_diff, extra_space, needed_space;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose uint32_t last_seq;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose ARRAY_TYPE(keyword_indexes) keywords_copy;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_assert(mail_ctx->mail.uid == 0 || mail_ctx->mail.space > 0 ||
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov mail_ctx->mail.offset == mail_ctx->hdr_offset);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (array_is_created(&mail_ctx->mail.keywords)) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* mail's keywords are allocated from a pool that's cleared
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose for each mail. we'll need to copy it to something more
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose permanent. */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose p_array_init(&keywords_copy, sync_ctx->saved_keywords_pool,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose array_count(&mail_ctx->mail.keywords));
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose array_append_array(&keywords_copy, &mail_ctx->mail.keywords);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.keywords = keywords_copy;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose array_append(&sync_ctx->mails, &mail_ctx->mail, 1);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->space_diff += mail_ctx->mail.space;
d81d8d3dc151ebc95cd0e3f3b14c1cdaa48980f1Sumit Bose if (sync_ctx->space_diff < 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (sync_ctx->expunged_space > 0) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov i_assert(sync_ctx->expunged_space ==
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.space);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->expunged_space = 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* we have enough space now */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (mail_ctx->mail.uid == 0) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* this message was expunged. fill more or less of the space.
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose space_diff now consists of a negative "bytes needed" sum,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose plus the expunged space of this message. so it contains how
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose many bytes of _extra_ space we have. */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose i_assert(mail_ctx->mail.space >= sync_ctx->space_diff);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose extra_space = MBOX_HEADER_PADDING *
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose (sync_ctx->seq - sync_ctx->need_space_seq + 1);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose needed_space = mail_ctx->mail.space - sync_ctx->space_diff;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if ((uoff_t)sync_ctx->space_diff > needed_space + extra_space) {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* don't waste too much on padding */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose move_diff = needed_space + extra_space;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->expunged_space =
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mail_ctx->mail.space - move_diff;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose } else {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov move_diff = mail_ctx->mail.space;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov extra_space = sync_ctx->space_diff;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->expunged_space = 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose last_seq = sync_ctx->seq - 1;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose array_delete(&sync_ctx->mails,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose array_count(&sync_ctx->mails) - 1, 1);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose end_offset = mail_ctx->mail.from_offset;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose } else {
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose /* this message gave enough space from headers. rewriting stops
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose at the end of this message's headers. */
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->expunged_space = 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose last_seq = sync_ctx->seq;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose end_offset = mail_ctx->body_offset;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose move_diff = 0;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose extra_space = sync_ctx->space_diff;
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose }
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose mbox_sync_file_update_ext_modified(sync_ctx);
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose if (mbox_sync_rewrite(sync_ctx,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose last_seq == sync_ctx->seq ? mail_ctx : NULL,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose end_offset, move_diff, extra_space,
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose sync_ctx->need_space_seq, last_seq) < 0)
caee9828ee30609e9f433957dbb3d0163390a207Sumit Bose return -1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek update_from_offsets(sync_ctx);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* mail_ctx may contain wrong data after rewrite, so make sure we
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek don't try to access it */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek memset(mail_ctx, 0, sizeof(*mail_ctx));
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->need_space_seq = 0;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->space_diff = 0;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek array_clear(&sync_ctx->mails);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek p_clear(sync_ctx->saved_keywords_pool);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return 0;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek}
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozekstatic int
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozekmbox_sync_seek_to_seq(struct mbox_sync_context *sync_ctx, uint32_t seq)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek{
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek struct mbox_mailbox *mbox = sync_ctx->mbox;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek uoff_t old_offset;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek uint32_t uid;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek int ret;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek bool deleted;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (seq == 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (istream_raw_mbox_seek(mbox->mbox_stream, 0) < 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mail_storage_set_error(&mbox->storage->storage,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek MAIL_ERROR_NOTPOSSIBLE,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek "Mailbox isn't a valid mbox file");
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return -1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek seq++;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek } else {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek old_offset = istream_raw_mbox_get_start_offset(sync_ctx->input);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek ret = mbox_file_seek(mbox, sync_ctx->sync_view, seq, &deleted);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (ret < 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (deleted) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mbox_sync_set_critical(sync_ctx,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek "Message was expunged unexpectedly "
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek "in mbox file %s", mbox->path);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return -1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (ret == 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (istream_raw_mbox_seek(mbox->mbox_stream,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek old_offset) < 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mbox_sync_set_critical(sync_ctx,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek "Error seeking back to original "
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek "offset %s in mbox file %s",
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek dec2str(old_offset), mbox->path);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return -1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return 0;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (seq <= 1)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek uid = 0;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek else if (mail_index_lookup_uid(sync_ctx->sync_view, seq-1, &uid) < 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mail_storage_set_index_error(&mbox->ibox);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return -1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->prev_msg_uid = uid;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* set to -1, since it's always increased later */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->seq = seq-1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (sync_ctx->seq == 0 &&
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek istream_raw_mbox_get_start_offset(sync_ctx->input) != 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* this mbox has pseudo mail which contains the X-IMAP header */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->seq++;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->idx_seq = seq;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->dest_first_mail = sync_ctx->seq == 0;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek (void)istream_raw_mbox_get_body_offset(sync_ctx->input);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return 1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek}
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozekstatic int
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozekmbox_sync_seek_to_uid(struct mbox_sync_context *sync_ctx, uint32_t uid)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek{
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek struct mail_index_view *sync_view = sync_ctx->sync_view;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek uint32_t seq1, seq2;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek const struct stat *st;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (mail_index_lookup_uid_range(sync_view, uid, (uint32_t)-1,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek &seq1, &seq2) < 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mail_storage_set_index_error(&sync_ctx->mbox->ibox);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return -1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (seq1 == 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* doesn't exist anymore, seek to end of file */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek st = i_stream_stat(sync_ctx->file_input, TRUE);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (st == NULL) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mbox_set_syscall_error(sync_ctx->mbox,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek "i_stream_stat()");
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return -1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (istream_raw_mbox_seek(sync_ctx->mbox->mbox_stream,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek st->st_size) < 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mbox_sync_set_critical(sync_ctx,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek "Error seeking to end of mbox file %s",
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->mbox->path);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return -1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->idx_seq =
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mail_index_view_get_messages_count(sync_view) + 1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return 1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return mbox_sync_seek_to_seq(sync_ctx, seq1);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek}
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozekstatic int mbox_sync_partial_seek_next(struct mbox_sync_context *sync_ctx,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek uint32_t next_uid, bool *partial,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek bool *skipped_mails)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek{
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek uint32_t messages_count;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek int ret;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* delete sync records up to next message. so if there's still
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek something left in array, it means the next message needs modifying */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mbox_sync_array_delete_to(&sync_ctx->syncs, next_uid);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (array_count(&sync_ctx->syncs) > 0)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return 1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (sync_ctx->sync_rec.uid1 != 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* we can skip forward to next record which needs updating. */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (sync_ctx->sync_rec.uid1 != next_uid) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek *skipped_mails = TRUE;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek next_uid = sync_ctx->sync_rec.uid1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek ret = mbox_sync_seek_to_uid(sync_ctx, next_uid);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek } else {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* if there's no sync records left, we can stop. except if
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek this is a dirty sync, check if there are new messages. */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (!sync_ctx->mbox->mbox_sync_dirty)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return 0;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek messages_count =
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mail_index_view_get_messages_count(sync_ctx->sync_view);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (sync_ctx->seq + 1 != messages_count) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek ret = mbox_sync_seek_to_seq(sync_ctx, messages_count);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek *skipped_mails = TRUE;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek } else {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek ret = 1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek *partial = FALSE;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (ret == 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* seek failed because the offset is dirty. just ignore and
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek continue from where we are now. */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek *partial = FALSE;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek ret = 1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return ret;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek}
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozekstatic int mbox_sync_loop(struct mbox_sync_context *sync_ctx,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek struct mbox_sync_mail_context *mail_ctx,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek bool partial)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek{
b4456f3944e7d02f2976ac77f74aa379a7b06032Lukas Slebodnik const struct mail_index_record *rec;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek uint32_t uid, messages_count;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek uoff_t offset;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek int ret;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek bool expunged, skipped_mails, uids_broken;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek messages_count =
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mail_index_view_get_messages_count(sync_ctx->sync_view);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* always start from first message so we can read X-IMAP or
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek X-IMAPbase header */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek ret = mbox_sync_seek_to_seq(sync_ctx, 0);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (ret <= 0)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return ret;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (sync_ctx->renumber_uids) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* expunge everything */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek while (sync_ctx->idx_seq <= messages_count) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mail_index_expunge(sync_ctx->t,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->idx_seq++);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek skipped_mails = uids_broken = FALSE;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek while ((ret = mbox_sync_read_next_mail(sync_ctx, mail_ctx)) > 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek uid = mail_ctx->mail.uid;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (mail_ctx->seq == 1 && sync_ctx->base_uid_validity != 0 &&
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->hdr->uid_validity != 0 &&
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->base_uid_validity !=
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->hdr->uid_validity) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mail_storage_set_critical(
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek &sync_ctx->mbox->storage->storage,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek "UIDVALIDITY changed (%u -> %u) "
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek "in mbox file %s",
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->hdr->uid_validity,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->base_uid_validity,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->mbox->path);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mail_index_mark_corrupted(sync_ctx->mbox->ibox.index);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return -1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (mail_ctx->mail.uid_broken && partial) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* UID ordering problems, resync everything to make
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sure we get everything right */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (sync_ctx->mbox->mbox_sync_dirty)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return 0;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mbox_sync_set_critical(sync_ctx,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek "UIDs broken with partial sync in mbox file %s",
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->mbox->path);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->mbox->mbox_sync_dirty = TRUE;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return 0;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (mail_ctx->mail.uid_broken)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek uids_broken = TRUE;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (mail_ctx->mail.pseudo)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek uid = 0;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek rec = NULL; ret = 1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (uid != 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek ret = mbox_sync_read_index_rec(sync_ctx, uid, &rec);
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (ret < 0)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return -1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (ret == 0) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* UID found but it's broken */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek uid = 0;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek } else if (uid == 0 &&
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek !mail_ctx->mail.pseudo &&
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek (sync_ctx->delay_writes ||
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->idx_seq <= messages_count)) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* If we can't use/store X-UID header, use MD5 sum.
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek Also check for existing MD5 sums when we're actually
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek able to write X-UIDs. */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek sync_ctx->mbox->mbox_save_md5 = TRUE;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (mbox_sync_find_index_md5(sync_ctx,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mail_ctx->hdr_md5_sum,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek &rec) < 0)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return -1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (rec != NULL)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek uid = mail_ctx->mail.uid = rec->uid;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* get all sync records related to this message. with pseudo
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek message just get the first sync record so we can jump to
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek it with partial seeking. */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (mbox_sync_read_index_syncs(sync_ctx,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek mail_ctx->mail.pseudo ? 1 : uid,
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek &expunged) < 0)
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek return -1;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (mail_ctx->mail.pseudo) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* if it was set, it was for the next message */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek expunged = FALSE;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek } else {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek if (rec == NULL) {
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek /* message wasn't found from index. we have to
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek read everything from now on, no skipping */
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek partial = FALSE;
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
e2d96566aeb881bd89e5c9236d663f6a9a88019aJakub Hrozek }
if (uid == 0 && !mail_ctx->mail.pseudo) {
/* missing/broken X-UID. all the rest of the mails
need new UIDs. */
while (sync_ctx->idx_seq <= messages_count) {
mail_index_expunge(sync_ctx->t,
sync_ctx->idx_seq++);
}
if (sync_ctx->next_uid == (uint32_t)-1) {
/* oh no, we're out of UIDs. this shouldn't
happen normally, so just try to get it fixed
without crashing. */
mail_storage_set_critical(
&sync_ctx->mbox->storage->storage,
"Out of UIDs, renumbering them in mbox "
"file %s", sync_ctx->mbox->path);
sync_ctx->renumber_uids = TRUE;
return 0;
}
mail_ctx->need_rewrite = TRUE;
mail_ctx->mail.uid = sync_ctx->next_uid++;
}
sync_ctx->prev_msg_uid = mail_ctx->mail.uid;
if (!mail_ctx->mail.pseudo)
mail_ctx->mail.idx_seq = sync_ctx->idx_seq;
if (!expunged) {
if (mbox_sync_handle_header(mail_ctx) < 0)
return -1;
sync_ctx->dest_first_mail = FALSE;
} else {
mbox_sync_handle_expunge(mail_ctx);
}
if (!mail_ctx->mail.pseudo) {
if (!expunged) {
if (mbox_sync_update_index(mail_ctx, rec) < 0)
return -1;
}
sync_ctx->idx_seq++;
}
istream_raw_mbox_next(sync_ctx->input,
mail_ctx->mail.body_size);
offset = istream_raw_mbox_get_start_offset(sync_ctx->input);
if (sync_ctx->need_space_seq != 0) {
if (mbox_sync_handle_missing_space(mail_ctx) < 0)
return -1;
if (mbox_sync_seek(sync_ctx, offset) < 0)
return -1;
} else if (sync_ctx->expunged_space > 0) {
if (!expunged) {
/* move the body */
mbox_sync_file_update_ext_modified(sync_ctx);
if (mbox_move(sync_ctx,
mail_ctx->body_offset -
sync_ctx->expunged_space,
mail_ctx->body_offset,
mail_ctx->mail.body_size) < 0)
return -1;
if (mbox_sync_seek(sync_ctx, offset) < 0)
return -1;
}
} else if (partial) {
ret = mbox_sync_partial_seek_next(sync_ctx, uid + 1,
&partial,
&skipped_mails);
if (ret <= 0) {
if (ret < 0)
return -1;
break;
}
}
}
if (istream_raw_mbox_is_eof(sync_ctx->input)) {
/* rest of the messages in index don't exist -> expunge them */
while (sync_ctx->idx_seq <= messages_count)
mail_index_expunge(sync_ctx->t, sync_ctx->idx_seq++);
}
if (!skipped_mails)
sync_ctx->mbox->mbox_sync_dirty = FALSE;
if (uids_broken && sync_ctx->delay_writes) {
/* once we get around to writing the changes, we'll need to do
a full sync to avoid the "UIDs broken in partial sync"
error */
sync_ctx->mbox->mbox_sync_dirty = TRUE;
}
return 1;
}
static int mbox_write_pseudo(struct mbox_sync_context *sync_ctx)
{
string_t *str;
unsigned int uid_validity;
i_assert(sync_ctx->write_fd != -1);
uid_validity = sync_ctx->base_uid_validity != 0 ?
sync_ctx->base_uid_validity : sync_ctx->hdr->uid_validity;
i_assert(uid_validity != 0);
str = t_str_new(1024);
str_printfa(str, "%sDate: %s\n"
"From: Mail System Internal Data <MAILER-DAEMON@%s>\n"
"Subject: DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA"
"\nMessage-ID: <%s@%s>\n"
"X-IMAP: %u %010u\n"
"Status: RO\n"
"\n"
PSEUDO_MESSAGE_BODY
"\n",
mbox_from_create("MAILER_DAEMON", ioloop_time),
message_date_create(ioloop_time),
my_hostname, dec2str(ioloop_time), my_hostname,
uid_validity, sync_ctx->next_uid-1);
if (pwrite_full(sync_ctx->write_fd,
str_data(str), str_len(str), 0) < 0) {
if (!ENOSPACE(errno)) {
mbox_set_syscall_error(sync_ctx->mbox,
"pwrite_full()");
return -1;
}
/* out of disk space, truncate to empty */
if (ftruncate(sync_ctx->write_fd, 0) < 0)
mbox_set_syscall_error(sync_ctx->mbox, "ftruncate()");
}
sync_ctx->base_uid_last_offset = 0; /* don't bother calculating */
sync_ctx->base_uid_last = sync_ctx->next_uid-1;
return 0;
}
static int mbox_sync_handle_eof_updates(struct mbox_sync_context *sync_ctx,
struct mbox_sync_mail_context *mail_ctx)
{
const struct stat *st;
uoff_t file_size, offset, padding, trailer_size;
if (!istream_raw_mbox_is_eof(sync_ctx->input)) {
i_assert(sync_ctx->need_space_seq == 0);
i_assert(sync_ctx->expunged_space == 0);
return 0;
}
st = i_stream_stat(sync_ctx->file_input, TRUE);
if (st == NULL) {
mbox_set_syscall_error(sync_ctx->mbox, "i_stream_stat()");
return -1;
}
file_size = st->st_size;
if (file_size < sync_ctx->file_input->v_offset) {
mbox_sync_set_critical(sync_ctx,
"file size unexpectedly shrinked in mbox file %s "
"(%"PRIuUOFF_T" vs %"PRIuUOFF_T")",
sync_ctx->mbox->path, file_size,
sync_ctx->file_input->v_offset);
return -1;
}
trailer_size = file_size - sync_ctx->file_input->v_offset;
i_assert(trailer_size <= 2);
if (sync_ctx->need_space_seq != 0) {
i_assert(sync_ctx->write_fd != -1);
i_assert(sync_ctx->space_diff < 0);
padding = MBOX_HEADER_PADDING *
(sync_ctx->seq - sync_ctx->need_space_seq + 1);
sync_ctx->space_diff -= padding;
i_assert(sync_ctx->expunged_space <= -sync_ctx->space_diff);
sync_ctx->space_diff += sync_ctx->expunged_space;
sync_ctx->expunged_space = 0;
if (mail_ctx->have_eoh && !mail_ctx->updated)
str_append_c(mail_ctx->header, '\n');
i_assert(sync_ctx->space_diff < 0);
if (file_set_size(sync_ctx->write_fd,
file_size + -sync_ctx->space_diff) < 0) {
mbox_set_syscall_error(sync_ctx->mbox,
"file_set_size()");
if (ftruncate(sync_ctx->write_fd, file_size) < 0) {
mbox_set_syscall_error(sync_ctx->mbox,
"ftruncate()");
}
return -1;
}
mbox_sync_file_updated(sync_ctx, FALSE);
if (mbox_sync_rewrite(sync_ctx, mail_ctx, file_size,
-sync_ctx->space_diff, padding,
sync_ctx->need_space_seq,
sync_ctx->seq) < 0)
return -1;
update_from_offsets(sync_ctx);
sync_ctx->need_space_seq = 0;
array_clear(&sync_ctx->mails);
p_clear(sync_ctx->saved_keywords_pool);
}
if (sync_ctx->expunged_space > 0) {
i_assert(sync_ctx->write_fd != -1);
mbox_sync_file_update_ext_modified(sync_ctx);
/* copy trailer, then truncate the file */
file_size = sync_ctx->last_stat.st_size;
if (file_size == (uoff_t)sync_ctx->expunged_space) {
/* everything deleted, the trailer_size still contains
the \n trailer though */
trailer_size = 0;
}
i_assert(file_size >= sync_ctx->expunged_space + trailer_size);
offset = file_size - sync_ctx->expunged_space - trailer_size;
i_assert(offset == 0 || offset > 31);
if (mbox_move(sync_ctx, offset,
offset + sync_ctx->expunged_space,
trailer_size) < 0)
return -1;
if (ftruncate(sync_ctx->write_fd,
offset + trailer_size) < 0) {
mbox_set_syscall_error(sync_ctx->mbox, "ftruncate()");
return -1;
}
if (offset == 0) {
if (mbox_write_pseudo(sync_ctx) < 0)
return -1;
}
sync_ctx->expunged_space = 0;
mbox_sync_file_updated(sync_ctx, FALSE);
}
return 0;
}
static int mbox_sync_update_index_header(struct mbox_sync_context *sync_ctx)
{
const struct stat *st;
st = i_stream_stat(sync_ctx->file_input, FALSE);
if (st == NULL) {
mbox_set_syscall_error(sync_ctx->mbox, "i_stream_stat()");
return -1;
}
if (sync_ctx->moved_offsets &&
((uint64_t)st->st_size == sync_ctx->hdr->sync_size ||
(uint64_t)st->st_size == sync_ctx->orig_size)) {
/* We moved messages inside the mbox file without changing
the file's size. If mtime doesn't change, another process
not using the same index file as us can't know that the file
was changed. So make sure the mtime changes. This should
happen rarely enough that the sleeping doesn't become a
performance problem.
Note that to do this perfectly safe we should do this wait
whenever mails are moved or expunged, regardless of whether
the file's size changed. That however could become a
performance problem and the consequences of being wrong are
quite minimal (an extra logged error message). */
while (sync_ctx->orig_mtime == st->st_mtime) {
usleep(500000);
if (utime(sync_ctx->mbox->path, NULL) < 0) {
mbox_set_syscall_error(sync_ctx->mbox,
"utime()");
return -1;
}
st = i_stream_stat(sync_ctx->file_input, FALSE);
if (st == NULL) {
mbox_set_syscall_error(sync_ctx->mbox,
"i_stream_stat()");
return -1;
}
}
}
/* only reason not to have UID validity at this point is if the file
is entirely empty. In that case just make up a new one if needed. */
i_assert(sync_ctx->base_uid_validity != 0 || st->st_size == 0);
if (sync_ctx->base_uid_validity != sync_ctx->hdr->uid_validity ||
sync_ctx->base_uid_validity == 0) {
if (sync_ctx->base_uid_validity == 0) {
sync_ctx->base_uid_validity =
sync_ctx->hdr->uid_validity != 0 ?
sync_ctx->hdr->uid_validity :
(unsigned int)ioloop_time;
}
mail_index_update_header(sync_ctx->t,
offsetof(struct mail_index_header, uid_validity),
&sync_ctx->base_uid_validity,
sizeof(sync_ctx->base_uid_validity), TRUE);
}
if (istream_raw_mbox_is_eof(sync_ctx->input) &&
sync_ctx->next_uid != sync_ctx->hdr->next_uid) {
i_assert(sync_ctx->next_uid != 0);
mail_index_update_header(sync_ctx->t,
offsetof(struct mail_index_header, next_uid),
&sync_ctx->next_uid, sizeof(sync_ctx->next_uid), FALSE);
}
if ((uint32_t)st->st_mtime != sync_ctx->hdr->sync_stamp &&
!sync_ctx->mbox->mbox_sync_dirty) {
uint32_t sync_stamp = st->st_mtime;
mail_index_update_header(sync_ctx->t,
offsetof(struct mail_index_header, sync_stamp),
&sync_stamp, sizeof(sync_stamp), TRUE);
}
if ((uint64_t)st->st_size != sync_ctx->hdr->sync_size &&
!sync_ctx->mbox->mbox_sync_dirty) {
uint64_t sync_size = st->st_size;
mail_index_update_header(sync_ctx->t,
offsetof(struct mail_index_header, sync_size),
&sync_size, sizeof(sync_size), TRUE);
}
sync_ctx->mbox->mbox_dirty_stamp = st->st_mtime;
sync_ctx->mbox->mbox_dirty_size = st->st_size;
return 0;
}
static void mbox_sync_restart(struct mbox_sync_context *sync_ctx)
{
sync_ctx->base_uid_validity = 0;
sync_ctx->base_uid_last = 0;
sync_ctx->base_uid_last_offset = 0;
array_clear(&sync_ctx->mails);
array_clear(&sync_ctx->syncs);
p_clear(sync_ctx->saved_keywords_pool);
memset(&sync_ctx->sync_rec, 0, sizeof(sync_ctx->sync_rec));
mail_index_sync_reset(sync_ctx->index_sync_ctx);
mail_index_transaction_reset(sync_ctx->t);
sync_ctx->prev_msg_uid = 0;
sync_ctx->next_uid = sync_ctx->hdr->next_uid;
sync_ctx->idx_next_uid = sync_ctx->hdr->next_uid;
sync_ctx->seq = 0;
sync_ctx->idx_seq = 1;
sync_ctx->need_space_seq = 0;
sync_ctx->expunged_space = 0;
sync_ctx->space_diff = 0;
sync_ctx->dest_first_mail = TRUE;
sync_ctx->ext_modified = FALSE;
}
static int mbox_sync_do(struct mbox_sync_context *sync_ctx,
enum mbox_sync_flags flags)
{
struct mbox_sync_mail_context mail_ctx;
const struct stat *st;
unsigned int i;
int ret, partial;
st = i_stream_stat(sync_ctx->file_input, FALSE);
if (st == NULL) {
mbox_set_syscall_error(sync_ctx->mbox, "i_stream_stat()");
return -1;
}
sync_ctx->last_stat = *st;
sync_ctx->orig_size = st->st_size;
sync_ctx->orig_atime = st->st_atime;
sync_ctx->orig_mtime = st->st_mtime;
if ((flags & MBOX_SYNC_FORCE_SYNC) != 0) {
/* forcing a full sync. assume file has changed. */
partial = FALSE;
sync_ctx->mbox->mbox_sync_dirty = TRUE;
} else if ((uint32_t)st->st_mtime == sync_ctx->hdr->sync_stamp &&
(uint64_t)st->st_size == sync_ctx->hdr->sync_size) {
/* file is fully synced */
partial = TRUE;
sync_ctx->mbox->mbox_sync_dirty = FALSE;
} else if ((flags & MBOX_SYNC_UNDIRTY) != 0 ||
(uint64_t)st->st_size == sync_ctx->hdr->sync_size) {
/* we want to do full syncing. always do this if
file size hasn't changed but timestamp has. it most
likely means that someone had modified some header
and we probably want to know about it */
partial = FALSE;
sync_ctx->mbox->mbox_sync_dirty = TRUE;
} else {
/* see if we can delay syncing the whole file.
normally we only notice expunges and appends
in partial syncing. */
partial = TRUE;
sync_ctx->mbox->mbox_sync_dirty = TRUE;
}
mbox_sync_restart(sync_ctx);
for (i = 0; i < 3; i++) {
ret = mbox_sync_loop(sync_ctx, &mail_ctx, partial);
if (ret > 0)
break;
if (ret < 0)
return -1;
/* partial syncing didn't work, do it again. we get here
also if we ran out of UIDs. */
i_assert(sync_ctx->mbox->mbox_sync_dirty);
mbox_sync_restart(sync_ctx);
partial = FALSE;
}
if (mbox_sync_handle_eof_updates(sync_ctx, &mail_ctx) < 0)
return -1;
/* only syncs left should be just appends (and their updates)
which weren't synced yet for some reason (crash). we'll just
ignore them, as we've overwritten them above. */
array_clear(&sync_ctx->syncs);
memset(&sync_ctx->sync_rec, 0, sizeof(sync_ctx->sync_rec));
if (mbox_sync_update_index_header(sync_ctx) < 0)
return -1;
return 0;
}
int mbox_sync_has_changed(struct mbox_mailbox *mbox, bool leave_dirty)
{
const struct mail_index_header *hdr;
const struct stat *st;
struct stat statbuf;
if (mbox->mbox_file_stream != NULL && mbox->mbox_fd == -1) {
/* read-only stream */
st = i_stream_stat(mbox->mbox_file_stream, FALSE);
if (st == NULL) {
mbox_set_syscall_error(mbox, "i_stream_stat()");
return -1;
}
} else {
if (stat(mbox->path, &statbuf) < 0) {
mbox_set_syscall_error(mbox, "stat()");
return -1;
}
st = &statbuf;
}
hdr = mail_index_get_header(mbox->ibox.view);
if ((uint32_t)st->st_mtime == hdr->sync_stamp &&
(uint64_t)st->st_size == hdr->sync_size) {
/* fully synced */
mbox->mbox_sync_dirty = FALSE;
return 0;
}
if (!mbox->mbox_sync_dirty || !leave_dirty) {
mbox->mbox_sync_dirty = TRUE;
return 1;
}
return st->st_mtime != mbox->mbox_dirty_stamp ||
st->st_size != mbox->mbox_dirty_size;
}
static void mbox_sync_context_free(struct mbox_sync_context *sync_ctx)
{
if (sync_ctx->index_sync_ctx != NULL)
mail_index_sync_rollback(&sync_ctx->index_sync_ctx);
pool_unref(sync_ctx->mail_keyword_pool);
pool_unref(sync_ctx->saved_keywords_pool);
str_free(&sync_ctx->header);
str_free(&sync_ctx->from_line);
array_free(&sync_ctx->mails);
array_free(&sync_ctx->syncs);
}
static int mbox_sync_int(struct mbox_mailbox *mbox, enum mbox_sync_flags flags)
{
struct mail_index_sync_ctx *index_sync_ctx;
struct mail_index_view *sync_view;
struct mail_index_transaction *trans;
struct mbox_sync_context sync_ctx;
enum mail_index_sync_flags sync_flags;
uint32_t seq;
uoff_t offset;
unsigned int lock_id = 0;
int ret, changed;
bool delay_writes;
delay_writes = mbox->mbox_readonly ||
((flags & MBOX_SYNC_REWRITE) == 0 &&
getenv("MBOX_LAZY_WRITES") != NULL);
mbox->ibox.sync_last_check = ioloop_time;
if (!mbox->mbox_do_dirty_syncs)
flags |= MBOX_SYNC_UNDIRTY;
if ((flags & MBOX_SYNC_LOCK_READING) != 0) {
if (mbox_lock(mbox, F_RDLCK, &lock_id) <= 0)
return -1;
}
if ((flags & MBOX_SYNC_HEADER) != 0 ||
(flags & MBOX_SYNC_FORCE_SYNC) != 0)
changed = 1;
else {
bool leave_dirty = (flags & MBOX_SYNC_UNDIRTY) == 0;
if ((changed = mbox_sync_has_changed(mbox, leave_dirty)) < 0) {
if ((flags & MBOX_SYNC_LOCK_READING) != 0)
(void)mbox_unlock(mbox, lock_id);
return -1;
}
}
if ((flags & MBOX_SYNC_LOCK_READING) != 0) {
/* we just want to lock it for reading. if mbox hasn't been
modified don't do any syncing. */
if (!changed)
return 0;
/* have to sync to make sure offsets have stayed the same */
(void)mbox_unlock(mbox, lock_id);
lock_id = 0;
}
/* reopen input stream to make sure it has nothing buffered */
mbox_file_close_stream(mbox);
__again:
if (changed) {
/* we're most likely modifying the mbox while syncing, just
lock it for writing immediately. the mbox must be locked
before index syncing is started to avoid deadlocks, so we
don't have much choice either (well, easy ones anyway). */
int lock_type = mbox->mbox_readonly ? F_RDLCK : F_WRLCK;
if (mbox_lock(mbox, lock_type, &lock_id) <= 0)
return -1;
}
if ((flags & MBOX_SYNC_LAST_COMMIT) != 0) {
seq = mbox->ibox.commit_log_file_seq;
offset = mbox->ibox.commit_log_file_offset;
} else {
seq = (uint32_t)-1;
offset = (uoff_t)-1;
}
sync_flags = 0;
if (!mbox->ibox.keep_recent)
sync_flags |= MAIL_INDEX_SYNC_FLAG_DROP_RECENT;
if ((flags & MBOX_SYNC_REWRITE) != 0)
sync_flags |= MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY;
ret = mail_index_sync_begin(mbox->ibox.index, &index_sync_ctx,
&sync_view, &trans, seq, offset,
sync_flags);
if (ret <= 0) {
if (ret < 0)
mail_storage_set_index_error(&mbox->ibox);
if (lock_id != 0)
(void)mbox_unlock(mbox, lock_id);
return ret;
}
if (!changed && !mail_index_sync_have_more(index_sync_ctx)) {
/* nothing to do */
__nothing_to_do:
if (lock_id != 0)
(void)mbox_unlock(mbox, lock_id);
/* index may need to do internal syncing though, so commit
instead of rollbacking. */
if (mail_index_sync_commit(&index_sync_ctx) < 0) {
mail_storage_set_index_error(&mbox->ibox);
return -1;
}
return 0;
}
memset(&sync_ctx, 0, sizeof(sync_ctx));
sync_ctx.mbox = mbox;
sync_ctx.hdr = mail_index_get_header(sync_view);
sync_ctx.from_line = str_new(default_pool, 256);
sync_ctx.header = str_new(default_pool, 4096);
sync_ctx.index_sync_ctx = index_sync_ctx;
sync_ctx.sync_view = sync_view;
sync_ctx.t = trans;
sync_ctx.mail_keyword_pool =
pool_alloconly_create("mbox keywords", 256);
sync_ctx.saved_keywords_pool =
pool_alloconly_create("mbox saved keywords", 4096);
/* make sure we've read the latest keywords in index */
(void)mail_index_get_keywords(mbox->ibox.index);
i_array_init(&sync_ctx.mails, 64);
i_array_init(&sync_ctx.syncs, 32);
sync_ctx.flags = flags;
sync_ctx.delay_writes = delay_writes || sync_ctx.mbox->mbox_readonly;
if (!changed && delay_writes) {
/* if we have only flag changes, we don't need to open the
mbox file */
bool expunged;
if (mbox_sync_read_index_syncs(&sync_ctx, 1, &expunged) < 0)
return -1;
if (sync_ctx.sync_rec.uid1 == 0) {
sync_ctx.index_sync_ctx = NULL;
mbox_sync_context_free(&sync_ctx);
goto __nothing_to_do;
}
}
if (lock_id == 0) {
/* ok, we have something to do but no locks. we'll have to
restart syncing to avoid deadlocking. */
mbox_sync_context_free(&sync_ctx);
changed = 1;
goto __again;
}
if (mbox_file_open_stream(mbox) < 0) {
mbox_sync_context_free(&sync_ctx);
(void)mbox_unlock(mbox, lock_id);
return -1;
}
sync_ctx.file_input = sync_ctx.mbox->mbox_file_stream;
sync_ctx.input = sync_ctx.mbox->mbox_stream;
sync_ctx.write_fd = sync_ctx.mbox->mbox_lock_type != F_WRLCK ? -1 :
sync_ctx.mbox->mbox_fd;
ret = mbox_sync_do(&sync_ctx, flags);
if (ret < 0)
mail_index_sync_rollback(&index_sync_ctx);
else if (mail_index_sync_commit(&index_sync_ctx) < 0) {
mail_storage_set_index_error(&mbox->ibox);
ret = -1;
} else {
mbox->ibox.commit_log_file_seq = 0;
mbox->ibox.commit_log_file_offset = 0;
}
sync_ctx.t = NULL;
sync_ctx.index_sync_ctx = NULL;
if (sync_ctx.base_uid_last != sync_ctx.next_uid-1 &&
ret == 0 && !sync_ctx.delay_writes &&
sync_ctx.base_uid_last_offset != 0) {
/* Rewrite uid_last in X-IMAPbase header if we've seen it
(ie. the file isn't empty) */
ret = mbox_rewrite_base_uid_last(&sync_ctx);
}
if (ret == 0 && mbox->mbox_fd != -1 && mbox->ibox.keep_recent) {
/* try to set atime back to its original value */
struct utimbuf buf;
struct stat st;
if (fstat(mbox->mbox_fd, &st) < 0)
mbox_set_syscall_error(mbox, "fstat()");
else {
buf.modtime = st.st_mtime;
buf.actime = sync_ctx.orig_atime;
if (utime(mbox->path, &buf) < 0)
mbox_set_syscall_error(mbox, "utime()");
}
}
i_assert(lock_id != 0);
if (mbox->mbox_lock_type != F_RDLCK) {
/* drop to read lock */
unsigned int read_lock_id = 0;
if (mbox_lock(mbox, F_RDLCK, &read_lock_id) <= 0)
ret = -1;
else {
if (mbox_unlock(mbox, lock_id) < 0)
ret = -1;
lock_id = read_lock_id;
}
}
if ((flags & MBOX_SYNC_LOCK_READING) == 0) {
if (mbox_unlock(mbox, lock_id) < 0)
ret = -1;
}
mbox_sync_context_free(&sync_ctx);
return ret;
}
int mbox_sync(struct mbox_mailbox *mbox, enum mbox_sync_flags flags)
{
int ret;
mbox->syncing = TRUE;
ret = mbox_sync_int(mbox, flags);
mbox->syncing = FALSE;
if (mbox->ibox.box.v.sync_notify != NULL)
mbox->ibox.box.v.sync_notify(&mbox->ibox.box, 0, 0);
return ret;
}
struct mailbox_sync_context *
mbox_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
{
struct mbox_mailbox *mbox = (struct mbox_mailbox *)box;
enum mbox_sync_flags mbox_sync_flags = 0;
int ret = 0;
if (!box->opened)
index_storage_mailbox_open(&mbox->ibox);
if ((flags & MAILBOX_SYNC_FLAG_FAST) == 0 ||
mbox->ibox.sync_last_check + MAILBOX_FULL_SYNC_INTERVAL <=
ioloop_time) {
if ((flags & MAILBOX_SYNC_FLAG_FULL_READ) != 0 &&
!mbox->mbox_very_dirty_syncs)
mbox_sync_flags |= MBOX_SYNC_UNDIRTY;
if ((flags & MAILBOX_SYNC_FLAG_FULL_WRITE) != 0)
mbox_sync_flags |= MBOX_SYNC_REWRITE;
ret = mbox_sync(mbox, mbox_sync_flags);
}
return index_mailbox_sync_init(box, flags, ret < 0);
}