mbox-sync.c revision a97a3ce5d82b16e8979de2d6cafbf6b0a129fe4e
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2004-2013 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/*
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Modifying mbox can be slow, so we try to do it all at once minimizing the
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen required disk I/O. We may need to:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - Update message flags in Status, X-Status and X-Keywords headers
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - Write missing X-UID and X-IMAPbase headers
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - Write missing or broken Content-Length header if there's space
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - Expunge specified messages
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Here's how we do it:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen - Start reading the mails from the beginning
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen - X-Keywords, X-UID and X-IMAPbase headers may contain padding at the end
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen of them, remember how much each message has and offset to beginning of the
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen padding
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen - If header needs to be rewritten and there's enough space, do it
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen - If we didn't have enough space, remember how much was missing
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen - Continue reading and counting the padding in each message. If available
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen padding is enough to rewrite all the previous messages needing it, do it
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen - When we encounter expunged message, treat all of it as padding and
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen rewrite previous messages if needed (and there's enough space).
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen Afterwards keep moving messages backwards to fill the expunged space.
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen Moving is done by rewriting each message's headers, with possibly adding
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen missing Content-Length header and padding. Message bodies are moved
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen without modifications.
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen - If we encounter end of file, grow the file and rewrite needed messages
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen - Rewriting is done by moving message body forward, rewriting message's
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen header and doing the same for previous message, until all of them are
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen rewritten.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen*/
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "array.h"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hostpid.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "file-set-size.h"
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "read-full.h"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen#include "write-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "message-date.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "istream-raw-mbox.h"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen#include "mbox-storage.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "index-sync-changes.h"
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen#include "mailbox-uidvalidity.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mbox-from.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mbox-file.h"
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen#include "mbox-lock.h"
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen#include "mbox-sync-private.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <stddef.h>
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen#include <stdlib.h>
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen#include <utime.h>
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen#include <sys/stat.h>
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainen/* The text below was taken exactly as c-client wrote it to my mailbox,
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen so it's probably copyrighted by University of Washington. */
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen#define PSEUDO_MESSAGE_BODY \
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen"This text is part of the internal format of your mail folder, and is not\n" \
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen"a real message. It is created automatically by the mail system software.\n" \
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen"If deleted, important folder data will be lost, and it will be re-created\n" \
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen"with the data reset to initial values.\n"
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainenvoid mbox_sync_set_critical(struct mbox_sync_context *sync_ctx,
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen const char *fmt, ...)
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen{
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen va_list va;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen sync_ctx->errors = TRUE;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen if (sync_ctx->ext_modified) {
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen mail_storage_set_critical(&sync_ctx->mbox->storage->storage,
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen "mbox file %s was modified while we were syncing, "
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen "check your locking settings",
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mailbox_get_path(&sync_ctx->mbox->box));
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen va_start(va, fmt);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen mail_storage_set_critical(&sync_ctx->mbox->storage->storage,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen "Sync failed for mbox file %s: %s",
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen mailbox_get_path(&sync_ctx->mbox->box),
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen t_strdup_vprintf(fmt, va));
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen va_end(va);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen}
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
445f9e31c6c3aa6c0a72be8565da8f6e594d24fbTimo Sirainenint mbox_sync_seek(struct mbox_sync_context *sync_ctx, uoff_t from_offset)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen{
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (istream_raw_mbox_seek(sync_ctx->input, from_offset) < 0) {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mbox_sync_set_critical(sync_ctx,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen "Unexpectedly lost From-line at offset %"PRIuUOFF_T,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen from_offset);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return -1;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return 0;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenvoid mbox_sync_file_update_ext_modified(struct mbox_sync_context *sync_ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen struct stat st;
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* Do this even if ext_modified is already set. Expunging code relies
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen on last_stat being updated. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (fstat(sync_ctx->write_fd, &st) < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "fstat()");
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (st.st_size != sync_ctx->last_stat.st_size ||
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen (sync_ctx->last_stat.st_mtime != 0 &&
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen !CMP_ST_MTIME(&st, &sync_ctx->last_stat)))
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen sync_ctx->ext_modified = TRUE;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen sync_ctx->last_stat = st;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen}
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainen
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainenvoid mbox_sync_file_updated(struct mbox_sync_context *sync_ctx, bool dirty)
c3412ddeb9abc13f99d3caf50faf76cd99f7e9d2Timo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (dirty) {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* just mark the stat as dirty. */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen sync_ctx->last_stat.st_mtime = 0;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (fstat(sync_ctx->write_fd, &sync_ctx->last_stat) < 0)
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "fstat()");
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen i_stream_sync(sync_ctx->input);
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen}
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainenstatic int
e8a35266a5ceacdfafeeffd6bddae77931ff97ebTimo Sirainenmbox_sync_read_next_mail(struct mbox_sync_context *sync_ctx,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen struct mbox_sync_mail_context *mail_ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* get EOF */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen (void)istream_raw_mbox_get_header_offset(sync_ctx->input);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (istream_raw_mbox_is_eof(sync_ctx->input))
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen return 0;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen p_clear(sync_ctx->mail_keyword_pool);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen memset(mail_ctx, 0, sizeof(*mail_ctx));
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen mail_ctx->sync_ctx = sync_ctx;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen mail_ctx->seq = ++sync_ctx->seq;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen mail_ctx->header = sync_ctx->header;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen mail_ctx->mail.from_offset =
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen istream_raw_mbox_get_start_offset(sync_ctx->input);
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen mail_ctx->mail.offset =
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen istream_raw_mbox_get_header_offset(sync_ctx->input);
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_sync_parse_next_mail(sync_ctx->input, mail_ctx);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(sync_ctx->input->v_offset != mail_ctx->mail.from_offset ||
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->input->eof);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (istream_raw_mbox_is_corrupted(sync_ctx->input))
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.body_size =
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen istream_raw_mbox_get_body_size(sync_ctx->input,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->content_length);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(mail_ctx->mail.body_size < OFF_T_MAX);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if ((mail_ctx->mail.flags & MAIL_RECENT) != 0 &&
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen !mail_ctx->mail.pseudo) {
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (!sync_ctx->keep_recent) {
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen /* need to add 'O' flag to Status-header */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_ctx->need_rewrite = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen mail_ctx->recent = TRUE;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen return 1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen}
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic void mbox_sync_read_index_syncs(struct mbox_sync_context *sync_ctx,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uint32_t uid, bool *sync_expunge_r)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen guid_128_t expunged_guid_128;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (uid == 0 || sync_ctx->index_reset) {
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen /* nothing for this or the future ones */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen uid = (uint32_t)-1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen index_sync_changes_read(sync_ctx->sync_changes, uid, sync_expunge_r,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen expunged_guid_128);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->readonly) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* we can't expunge anything from read-only mboxes */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen *sync_expunge_r = FALSE;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen }
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen}
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainenstatic bool
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainenmbox_sync_read_index_rec(struct mbox_sync_context *sync_ctx,
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen uint32_t uid, const struct mail_index_record **rec_r)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const struct mail_index_record *rec = NULL;
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen uint32_t messages_count;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen bool ret = FALSE;
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->index_reset) {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen *rec_r = NULL;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return TRUE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen messages_count =
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen mail_index_view_get_messages_count(sync_ctx->sync_view);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen while (sync_ctx->idx_seq <= messages_count) {
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen rec = mail_index_lookup(sync_ctx->sync_view, sync_ctx->idx_seq);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (uid <= rec->uid)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen break;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* externally expunged message, remove from index */
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen mail_index_expunge(sync_ctx->t, sync_ctx->idx_seq);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen sync_ctx->idx_seq++;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen rec = NULL;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (rec == NULL && uid < sync_ctx->idx_next_uid) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* this UID was already in index and it was expunged */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mbox_sync_set_critical(sync_ctx,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen "Expunged message reappeared to mailbox "
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen "(UID %u < %u, seq=%u, idx_msgs=%u)",
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen uid, sync_ctx->idx_next_uid,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen sync_ctx->seq, messages_count);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ret = FALSE; rec = NULL;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen } else if (rec != NULL && rec->uid != uid) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* new UID in the middle of the mailbox - shouldn't happen */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mbox_sync_set_critical(sync_ctx,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen "UID inserted in the middle of mailbox "
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen "(%u > %u, seq=%u, idx_msgs=%u)",
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen rec->uid, uid, sync_ctx->seq, messages_count);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ret = FALSE; rec = NULL;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen } else {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ret = TRUE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen *rec_r = rec;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return ret;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainenstatic void mbox_sync_find_index_md5(struct mbox_sync_context *sync_ctx,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen unsigned char hdr_md5_sum[],
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const struct mail_index_record **rec_r)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const struct mail_index_record *rec = NULL;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uint32_t messages_count;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const void *data;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (sync_ctx->index_reset) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen *rec_r = NULL;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen return;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen }
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen messages_count =
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen mail_index_view_get_messages_count(sync_ctx->sync_view);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen while (sync_ctx->idx_seq <= messages_count) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen rec = mail_index_lookup(sync_ctx->sync_view, sync_ctx->idx_seq);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_index_lookup_ext(sync_ctx->sync_view,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->idx_seq,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->mbox->md5hdr_ext_idx,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen &data, NULL);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (data != NULL && memcmp(data, hdr_md5_sum, 16) == 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen break;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* externally expunged message, remove from index */
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen mail_index_expunge(sync_ctx->t, sync_ctx->idx_seq);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->idx_seq++;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen rec = NULL;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen *rec_r = rec;
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen}
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic void
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainenmbox_sync_update_from_offset(struct mbox_sync_context *sync_ctx,
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen struct mbox_sync_mail *mail,
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen bool nocheck)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen const void *data;
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen uint64_t offset;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
484efa22e65c509f787dbbc892351146c726c257Timo Sirainen if (!nocheck) {
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen /* see if from_offset needs updating */
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen mail_index_lookup_ext(sync_ctx->sync_view, sync_ctx->idx_seq,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->mbox->mbox_ext_idx,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen &data, NULL);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (data != NULL &&
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen *((const uint64_t *)data) == mail->from_offset)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen offset = mail->from_offset;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mail_index_update_ext(sync_ctx->t, sync_ctx->idx_seq,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen sync_ctx->mbox->mbox_ext_idx, &offset, NULL);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen}
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainenstatic void
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainenmbox_sync_update_index_keywords(struct mbox_sync_mail_context *mail_ctx)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen{
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen struct mail_index *index = sync_ctx->mbox->box.index;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen struct mail_keywords *keywords;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen keywords = !array_is_created(&mail_ctx->mail.keywords) ?
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mail_index_keywords_create(index, NULL) :
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mail_index_keywords_create_from_indexes(index,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen &mail_ctx->mail.keywords);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mail_index_update_keywords(sync_ctx->t, sync_ctx->idx_seq,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen MODIFY_REPLACE, keywords);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen mail_index_keywords_unref(&keywords);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen}
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenstatic void
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenmbox_sync_update_md5_if_changed(struct mbox_sync_mail_context *mail_ctx)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen{
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen const void *ext_data;
f0f9c8e94abac18f8acd91b9e724c4c32863723aTimo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mail_index_lookup_ext(sync_ctx->sync_view, sync_ctx->idx_seq,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen sync_ctx->mbox->md5hdr_ext_idx, &ext_data, NULL);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (ext_data == NULL ||
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen memcmp(mail_ctx->hdr_md5_sum, ext_data, 16) != 0) {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mail_index_update_ext(sync_ctx->t, sync_ctx->idx_seq,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen sync_ctx->mbox->md5hdr_ext_idx,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mail_ctx->hdr_md5_sum, NULL);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen}
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainenstatic void mbox_sync_get_dirty_flags(struct mbox_sync_mail_context *mail_ctx,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen const struct mail_index_record *rec)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen ARRAY_TYPE(keyword_indexes) idx_keywords;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uint8_t idx_flags, mbox_flags;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen /* default to undirtying the message. it gets added back if
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen flags/keywords don't match what is in the index. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.flags &= ~MAIL_INDEX_MAIL_FLAG_DIRTY;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen /* replace flags */
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen idx_flags = rec->flags & MAIL_FLAGS_NONRECENT;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen mbox_flags = mail_ctx->mail.flags & MAIL_FLAGS_NONRECENT;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (idx_flags != mbox_flags) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen mail_ctx->need_rewrite = TRUE;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mail_ctx->mail.flags = (mail_ctx->mail.flags & MAIL_RECENT) |
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen idx_flags | MAIL_INDEX_MAIL_FLAG_DIRTY;
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen /* replace keywords */
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen t_array_init(&idx_keywords, 32);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_index_lookup_keywords(sync_ctx->sync_view, sync_ctx->idx_seq,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen &idx_keywords);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (!index_keyword_array_cmp(&idx_keywords, &mail_ctx->mail.keywords)) {
8af07808ba203f8709e2ff9eaf2291e1c4a4d53dTimo Sirainen mail_ctx->need_rewrite = TRUE;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen mail_ctx->mail.flags |= MAIL_INDEX_MAIL_FLAG_DIRTY;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (!array_is_created(&mail_ctx->mail.keywords)) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen p_array_init(&mail_ctx->mail.keywords,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->mail_keyword_pool,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen array_count(&idx_keywords));
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen array_clear(&mail_ctx->mail.keywords);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen array_append_array(&mail_ctx->mail.keywords, &idx_keywords);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic void mbox_sync_update_flags(struct mbox_sync_mail_context *mail_ctx,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen const struct mail_index_record *rec)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mailbox *box = &sync_ctx->mbox->box;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mbox_sync_mail *mail = &mail_ctx->mail;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen enum mail_index_sync_type sync_type;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ARRAY_TYPE(keyword_indexes) orig_keywords = ARRAY_INIT;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen uint8_t flags, orig_flags;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (rec != NULL) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
33d63688ed8b26dc333e3c2edbfb2fe6e412604dTimo Sirainen /* flags and keywords are dirty. replace the current
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ones from the flags in index file. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_sync_get_dirty_flags(mail_ctx, rec);
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen }
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen }
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen flags = orig_flags = mail->flags & MAIL_FLAGS_NONRECENT;
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen if (array_is_created(&mail->keywords)) {
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen t_array_init(&orig_keywords, 32);
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen array_append_array(&orig_keywords, &mail->keywords);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* apply new changes */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen index_sync_changes_apply(sync_ctx->sync_changes,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen sync_ctx->mail_keyword_pool,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen &flags, &mail->keywords, &sync_type);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (flags != orig_flags ||
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen !index_keyword_array_cmp(&mail->keywords, &orig_keywords)) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen mail_ctx->need_rewrite = TRUE;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mail->flags = flags | (mail->flags & MAIL_RECENT) |
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen MAIL_INDEX_MAIL_FLAG_DIRTY;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_type != 0 && box->v.sync_notify != NULL) {
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen box->v.sync_notify(box, mail_ctx->mail.uid,
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen index_sync_type_convert(sync_type));
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic void mbox_sync_update_index(struct mbox_sync_mail_context *mail_ctx,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen const struct mail_index_record *rec)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mbox_sync_mail *mail = &mail_ctx->mail;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ARRAY_TYPE(keyword_indexes) idx_keywords;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen uint8_t mbox_flags;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mbox_flags = mail->flags & ~MAIL_RECENT;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (!sync_ctx->delay_writes) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* changes are written to the mbox file */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_flags &= ~MAIL_INDEX_MAIL_FLAG_DIRTY;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen } else if (mail_ctx->need_rewrite) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* make sure this message gets written later */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mbox_flags |= MAIL_INDEX_MAIL_FLAG_DIRTY;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (rec == NULL) {
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen /* new message */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_index_append(sync_ctx->t, mail->uid, &sync_ctx->idx_seq);
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen mail_index_update_flags(sync_ctx->t, sync_ctx->idx_seq,
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen MODIFY_REPLACE, mbox_flags);
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen mbox_sync_update_index_keywords(mail_ctx);
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen if (sync_ctx->mbox->mbox_save_md5 != 0) {
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen mail_index_update_ext(sync_ctx->t, sync_ctx->idx_seq,
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen sync_ctx->mbox->md5hdr_ext_idx,
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen mail_ctx->hdr_md5_sum, NULL);
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen } else {
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen if ((rec->flags & MAIL_FLAGS_NONRECENT) !=
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen (mbox_flags & MAIL_FLAGS_NONRECENT)) {
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen /* flags other than recent/dirty have changed */
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen mail_index_update_flags(sync_ctx->t, sync_ctx->idx_seq,
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen MODIFY_REPLACE, mbox_flags);
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen } else if (((rec->flags ^ mbox_flags) &
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen /* only dirty flag state changed */
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen bool dirty;
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen dirty = (mbox_flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0;
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen mail_index_update_flags(sync_ctx->t, sync_ctx->idx_seq,
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen dirty ? MODIFY_ADD : MODIFY_REMOVE,
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen (enum mail_flags)MAIL_INDEX_MAIL_FLAG_DIRTY);
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen }
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen /* see if keywords changed */
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen t_array_init(&idx_keywords, 32);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen mail_index_lookup_keywords(sync_ctx->sync_view,
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen sync_ctx->idx_seq, &idx_keywords);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen if (!index_keyword_array_cmp(&idx_keywords, &mail->keywords))
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen mbox_sync_update_index_keywords(mail_ctx);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen /* see if we need to update md5 sum. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->mbox->mbox_save_md5 != 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen mbox_sync_update_md5_if_changed(mail_ctx);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (!mail_ctx->recent) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* Mail has "Status: O" header. No messages before this
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen can be recent. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->last_nonrecent_uid = mail->uid;
3023fb352cbc2052b156f6d325c2629531a1b5b4Timo Sirainen }
3023fb352cbc2052b156f6d325c2629531a1b5b4Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* update from_offsets, but not if we're going to rewrite this message.
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen rewriting would just move it anyway. */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (sync_ctx->need_space_seq == 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen bool nocheck = rec == NULL || sync_ctx->expunged_space > 0;
e8a35266a5ceacdfafeeffd6bddae77931ff97ebTimo Sirainen mbox_sync_update_from_offset(sync_ctx, mail, nocheck);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int mbox_read_from_line(struct mbox_sync_mail_context *ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct istream *input = ctx->sync_ctx->file_input;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const unsigned char *data;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen size_t size, from_line_size;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen buffer_set_used_size(ctx->sync_ctx->from_line, 0);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen from_line_size = ctx->hdr_offset - ctx->mail.from_offset;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen i_stream_seek(input, ctx->mail.from_offset);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen for (;;) {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen data = i_stream_get_data(input, &size);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (size >= from_line_size)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen size = from_line_size;
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen buffer_append(ctx->sync_ctx->from_line, data, size);
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen i_stream_skip(input, size);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen from_line_size -= size;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (from_line_size == 0)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen break;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (i_stream_read(input) < 0)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen return -1;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen return 0;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen}
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainenstatic int mbox_rewrite_base_uid_last(struct mbox_sync_context *sync_ctx)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen{
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen unsigned char buf[10];
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen const char *str;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen uint32_t uid_last;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen unsigned int i;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen int ret;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen i_assert(sync_ctx->base_uid_last_offset != 0);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* first check that the 10 bytes are there and they're exactly as
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen expected. just an extra safety check to make sure we never write
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen to wrong location in the mbox file. */
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen ret = pread_full(sync_ctx->write_fd, buf, sizeof(buf),
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->base_uid_last_offset);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (ret < 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "pread_full()");
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (ret == 0) {
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen mbox_sync_set_critical(sync_ctx,
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen "X-IMAPbase uid-last offset unexpectedly outside mbox");
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen return -1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen for (i = 0, uid_last = 0; i < sizeof(buf); i++) {
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen if (buf[i] < '0' || buf[i] > '9') {
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen uid_last = (uint32_t)-1;
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen break;
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen }
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen uid_last = uid_last * 10 + (buf[i] - '0');
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (uid_last != sync_ctx->base_uid_last) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mbox_sync_set_critical(sync_ctx,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen "X-IMAPbase uid-last unexpectedly lost");
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* and write it */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen str = t_strdup_printf("%010u", sync_ctx->next_uid - 1);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (pwrite_full(sync_ctx->write_fd, str, 10,
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen sync_ctx->base_uid_last_offset) < 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "pwrite_full()");
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mbox_sync_file_updated(sync_ctx, FALSE);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->base_uid_last = sync_ctx->next_uid - 1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return 0;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen}
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic int
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenmbox_write_from_line(struct mbox_sync_mail_context *ctx)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen{
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen string_t *str = ctx->sync_ctx->from_line;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (pwrite_full(ctx->sync_ctx->write_fd, str_data(str), str_len(str),
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ctx->mail.from_offset) < 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mbox_set_syscall_error(ctx->sync_ctx->mbox, "pwrite_full()");
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen return -1;
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen mbox_sync_file_updated(ctx->sync_ctx, FALSE);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen return 0;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen}
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic void update_from_offsets(struct mbox_sync_context *sync_ctx)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen{
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen const struct mbox_sync_mail *mails;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen unsigned int i, count;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen uint32_t ext_idx;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen uint64_t offset;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen ext_idx = sync_ctx->mbox->mbox_ext_idx;
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen mails = array_get(&sync_ctx->mails, &count);
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen for (i = 0; i < count; i++) {
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (mails[i].idx_seq == 0 || mails[i].expunged)
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen continue;
ab3c1eab9ca13916358a9e8b12df8212fefb7dbfTimo Sirainen
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen sync_ctx->moved_offsets = TRUE;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen offset = mails[i].from_offset;
3021a062b16ff0138408be6107d6bcd0ced280b9Timo Sirainen mail_index_update_ext(sync_ctx->t, mails[i].idx_seq,
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen ext_idx, &offset, NULL);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen }
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen}
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainenstatic void mbox_sync_handle_expunge(struct mbox_sync_mail_context *mail_ctx)
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainen{
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen struct mailbox *box = &sync_ctx->mbox->box;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen if (box->v.sync_notify != NULL) {
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen box->v.sync_notify(box, mail_ctx->mail.uid,
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen MAILBOX_SYNC_TYPE_EXPUNGE);
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_expunge(sync_ctx->t, mail_ctx->mail.idx_seq);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen mail_ctx->mail.expunged = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.offset = mail_ctx->mail.from_offset;
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen mail_ctx->mail.space =
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->body_offset - mail_ctx->mail.from_offset +
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.body_size;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.body_size = 0;
1276e0340fe29495b6694dc7508f070cf6fca1cfTimo Sirainen mail_ctx->mail.uid = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->seq == 1) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* expunging first message, fix space to contain next
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen message's \n header too since it will be removed. */
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen mail_ctx->mail.space++;
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen if (istream_raw_mbox_has_crlf_ending(sync_ctx->input)) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.space++;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen sync_ctx->first_mail_crlf_expunged = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen /* uid-last offset is invalid now */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->base_uid_last_offset = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->expunged_space += mail_ctx->mail.space;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int mbox_sync_handle_header(struct mbox_sync_mail_context *mail_ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen uoff_t orig_from_offset;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen off_t move_diff;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen int ret;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen if (sync_ctx->expunged_space > 0 && sync_ctx->need_space_seq == 0) {
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen /* move the header backwards to fill expunged space */
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen move_diff = -sync_ctx->expunged_space;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen orig_from_offset = mail_ctx->mail.from_offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->dest_first_mail) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* we're moving this mail to beginning of file.
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen skip the initial \n (it's already counted in
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen expunged_space) */
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen mail_ctx->mail.from_offset++;
60d3fa9883237e896a8704275b6116fa46f7ffdaTimo Sirainen if (sync_ctx->first_mail_crlf_expunged)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.from_offset++;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* read the From-line before rewriting overwrites it */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mbox_read_from_line(mail_ctx) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainen mbox_sync_update_header(mail_ctx);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen ret = mbox_sync_try_rewrite(mail_ctx, move_diff);
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen if (ret < 0)
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen return -1;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen if (ret > 0) {
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen /* rewrite successful, write From-line to
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen new location */
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen i_assert(move_diff > 0 ||
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen (off_t)mail_ctx->mail.from_offset >=
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen -move_diff);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_ctx->mail.from_offset += move_diff;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen mail_ctx->mail.offset += move_diff;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen if (mbox_write_from_line(mail_ctx) < 0)
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen return -1;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen } else {
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen if (sync_ctx->dest_first_mail) {
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen /* didn't have enough space, move the offset
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen back so seeking into it doesn't fail */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.from_offset = orig_from_offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else if (mail_ctx->need_rewrite) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_sync_update_header(mail_ctx);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (sync_ctx->delay_writes) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* mark it dirty and do it later */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->dirty = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if ((ret = mbox_sync_try_rewrite(mail_ctx, 0)) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* nothing to do */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen }
36816b5af1472ae76a1909ae3cf29fd614b2ebfcTimo Sirainen
829c036d4ddfbd9ea49bd8a7c54e3057177d346eTimo Sirainen if (ret == 0 && sync_ctx->need_space_seq == 0) {
36816b5af1472ae76a1909ae3cf29fd614b2ebfcTimo Sirainen /* first mail with no space to write it */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->need_space_seq = sync_ctx->seq;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->space_diff = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen if (sync_ctx->expunged_space > 0) {
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen /* create dummy message to describe the expunged data */
8d5991f5c4a8840bf1ea754093dbec505564ab78Timo Sirainen struct mbox_sync_mail mail;
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen memset(&mail, 0, sizeof(mail));
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen mail.expunged = TRUE;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mail.offset = mail.from_offset =
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen (sync_ctx->dest_first_mail ? 1 : 0) +
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.from_offset -
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->expunged_space;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail.space = sync_ctx->expunged_space;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->space_diff = sync_ctx->expunged_space;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->expunged_space = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(sync_ctx->space_diff < -mail_ctx->mail.space);
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen sync_ctx->need_space_seq--;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen array_append(&sync_ctx->mails, &mail, 1);
2cb565cd978aafd5714792b5161889986d49e431Timo Sirainen }
2cb565cd978aafd5714792b5161889986d49e431Timo Sirainen }
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen return 0;
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainenstatic int
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainenmbox_sync_handle_missing_space(struct mbox_sync_mail_context *mail_ctx)
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen{
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen uoff_t end_offset, move_diff, extra_space, needed_space;
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen uint32_t last_seq;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen ARRAY_TYPE(keyword_indexes) keywords_copy;
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen i_assert(mail_ctx->mail.uid == 0 || mail_ctx->mail.space > 0 ||
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.offset == mail_ctx->hdr_offset);
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen if (array_is_created(&mail_ctx->mail.keywords)) {
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen /* mail's keywords are allocated from a pool that's cleared
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen for each mail. we'll need to copy it to something more
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen permanent. */
8d5991f5c4a8840bf1ea754093dbec505564ab78Timo Sirainen p_array_init(&keywords_copy, sync_ctx->saved_keywords_pool,
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen array_count(&mail_ctx->mail.keywords));
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen array_append_array(&keywords_copy, &mail_ctx->mail.keywords);
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen mail_ctx->mail.keywords = keywords_copy;
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen }
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen array_append(&sync_ctx->mails, &mail_ctx->mail, 1);
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen sync_ctx->space_diff += mail_ctx->mail.space;
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen if (sync_ctx->space_diff < 0) {
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen if (sync_ctx->expunged_space > 0) {
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen i_assert(sync_ctx->expunged_space ==
c9a03c8a03a782488981f81bd7c6b5e01ff55f06Timo Sirainen mail_ctx->mail.space);
829c036d4ddfbd9ea49bd8a7c54e3057177d346eTimo Sirainen sync_ctx->expunged_space = 0;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen return 0;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen }
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen /* we have enough space now */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mail_ctx->mail.uid == 0) {
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen /* this message was expunged. fill more or less of the space.
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen space_diff now consists of a negative "bytes needed" sum,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen plus the expunged space of this message. so it contains how
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen many bytes of _extra_ space we have. */
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen i_assert(mail_ctx->mail.space >= sync_ctx->space_diff);
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen extra_space = MBOX_HEADER_PADDING *
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen (sync_ctx->seq - sync_ctx->need_space_seq + 1);
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen needed_space = mail_ctx->mail.space - sync_ctx->space_diff;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if ((uoff_t)sync_ctx->space_diff > needed_space + extra_space) {
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen /* don't waste too much on padding */
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen move_diff = needed_space + extra_space;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen sync_ctx->expunged_space =
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.space - move_diff;
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen } else {
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen move_diff = mail_ctx->mail.space;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen extra_space = sync_ctx->space_diff;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->expunged_space = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen last_seq = sync_ctx->seq - 1;
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen array_delete(&sync_ctx->mails,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen array_count(&sync_ctx->mails) - 1, 1);
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen end_offset = mail_ctx->mail.from_offset;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen } else {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* this message gave enough space from headers. rewriting stops
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen at the end of this message's headers. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->expunged_space = 0;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen last_seq = sync_ctx->seq;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen end_offset = mail_ctx->body_offset;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen move_diff = 0;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen extra_space = sync_ctx->space_diff;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen mbox_sync_file_update_ext_modified(sync_ctx);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (mbox_sync_rewrite(sync_ctx,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen last_seq == sync_ctx->seq ? mail_ctx : NULL,
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen end_offset, move_diff, extra_space,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen sync_ctx->need_space_seq, last_seq) < 0)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return -1;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen update_from_offsets(sync_ctx);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* mail_ctx may contain wrong data after rewrite, so make sure we
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen don't try to access it */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen memset(mail_ctx, 0, sizeof(*mail_ctx));
6a87059fc7d4e919aa55d0b208ff20708e13e2d7Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen sync_ctx->need_space_seq = 0;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen sync_ctx->space_diff = 0;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen array_clear(&sync_ctx->mails);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen p_clear(sync_ctx->saved_keywords_pool);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen}
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenstatic int
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenmbox_sync_seek_to_seq(struct mbox_sync_context *sync_ctx, uint32_t seq)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen{
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen struct mbox_mailbox *mbox = sync_ctx->mbox;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen uoff_t old_offset;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen uint32_t uid;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen int ret;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen bool deleted;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen if (seq == 0) {
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen if (istream_raw_mbox_seek(mbox->mbox_stream, 0) < 0) {
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen mbox->invalid_mbox_file = TRUE;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mail_storage_set_error(&mbox->storage->storage,
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen MAIL_ERROR_NOTPOSSIBLE,
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen "Mailbox isn't a valid mbox file");
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen return -1;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen }
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen seq++;
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen } else {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen old_offset = istream_raw_mbox_get_start_offset(sync_ctx->input);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen ret = mbox_file_seek(mbox, sync_ctx->sync_view, seq, &deleted);
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen if (ret < 0) {
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen if (deleted) {
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen mbox_sync_set_critical(sync_ctx,
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen "Message was expunged unexpectedly");
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen return -1;
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen }
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen if (ret == 0) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (istream_raw_mbox_seek(mbox->mbox_stream,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen old_offset) < 0) {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen mbox_sync_set_critical(sync_ctx,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen "Error seeking back to original "
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen "offset %s", dec2str(old_offset));
a10e5606a9e93f49cf13b3a35c8dc3f5d6ab5909Timo Sirainen return -1;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen return 0;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
a10e5606a9e93f49cf13b3a35c8dc3f5d6ab5909Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (seq <= 1)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen uid = 0;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen else
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen mail_index_lookup_uid(sync_ctx->sync_view, seq-1, &uid);
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen sync_ctx->prev_msg_uid = uid;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen /* set to -1, since it's always increased later */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->seq = seq-1;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (sync_ctx->seq == 0 &&
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen istream_raw_mbox_get_start_offset(sync_ctx->input) != 0) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen /* this mbox has pseudo mail which contains the X-IMAP header */
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->seq++;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->idx_seq = seq;
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen sync_ctx->dest_first_mail = sync_ctx->seq == 0;
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen (void)istream_raw_mbox_get_body_offset(sync_ctx->input);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return 1;
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen}
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen
a10e5606a9e93f49cf13b3a35c8dc3f5d6ab5909Timo Sirainenstatic int
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainenmbox_sync_seek_to_uid(struct mbox_sync_context *sync_ctx, uint32_t uid)
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen{
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen struct mail_index_view *sync_view = sync_ctx->sync_view;
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen uint32_t seq1, seq2;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen uoff_t size;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen int ret;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen i_assert(!sync_ctx->index_reset);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (!mail_index_lookup_seq_range(sync_view, uid, (uint32_t)-1,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen &seq1, &seq2)) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* doesn't exist anymore, seek to end of file */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ret = i_stream_get_size(sync_ctx->file_input, TRUE, &size);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ret < 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen "i_stream_get_size()");
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen i_assert(ret != 0);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (istream_raw_mbox_seek(sync_ctx->mbox->mbox_stream,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen size) < 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mbox_sync_set_critical(sync_ctx,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen "Error seeking to end of mbox");
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->idx_seq =
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen mail_index_view_get_messages_count(sync_view) + 1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return 1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return mbox_sync_seek_to_seq(sync_ctx, seq1);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen}
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenstatic int mbox_sync_partial_seek_next(struct mbox_sync_context *sync_ctx,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uint32_t next_uid, bool *partial,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen bool *skipped_mails)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen{
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uint32_t messages_count, uid;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen int ret;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen i_assert(!sync_ctx->index_reset);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen /* delete sync records up to next message. so if there's still
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen something left in array, it means the next message needs modifying */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen index_sync_changes_delete_to(sync_ctx->sync_changes, next_uid);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (index_sync_changes_have(sync_ctx->sync_changes))
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return 1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen if (sync_ctx->hdr->first_recent_uid <= next_uid &&
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen !sync_ctx->keep_recent) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* we'll need to rewrite Status: O headers */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return 1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uid = index_sync_changes_get_next_uid(sync_ctx->sync_changes);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (sync_ctx->hdr->first_recent_uid < sync_ctx->hdr->next_uid &&
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen (uid > sync_ctx->hdr->first_recent_uid || uid == 0) &&
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen !sync_ctx->keep_recent) {
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen /* we'll need to rewrite Status: O headers */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uid = sync_ctx->hdr->first_recent_uid;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen if (uid != 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* we can skip forward to next record which needs updating. */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (uid != next_uid) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen *skipped_mails = TRUE;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen next_uid = uid;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen ret = mbox_sync_seek_to_uid(sync_ctx, next_uid);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen } else {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* if there's no sync records left, we can stop. except if
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen this is a dirty sync, check if there are new messages. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (!sync_ctx->mbox->mbox_hdr.dirty_flag)
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen return 0;
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen messages_count =
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen mail_index_view_get_messages_count(sync_ctx->sync_view);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (sync_ctx->seq + 1 != messages_count) {
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen ret = mbox_sync_seek_to_seq(sync_ctx, messages_count);
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen *skipped_mails = TRUE;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen } else {
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen ret = 1;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen *partial = FALSE;
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen }
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen if (ret == 0) {
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen /* seek failed because the offset is dirty. just ignore and
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen continue from where we are now. */
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen *partial = FALSE;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen ret = 1;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen }
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen return ret;
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen}
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainenstatic void mbox_sync_hdr_update(struct mbox_sync_context *sync_ctx,
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen struct mbox_sync_mail_context *mail_ctx)
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen{
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen const struct mailbox_update *update = sync_ctx->mbox->sync_hdr_update;
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen if (update->uid_validity != 0) {
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen sync_ctx->base_uid_validity = update->uid_validity;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen mail_ctx->imapbase_rewrite = TRUE;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen mail_ctx->need_rewrite = TRUE;
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen }
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen if (update->min_next_uid != 0 &&
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen sync_ctx->base_uid_last+1 < update->min_next_uid) {
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen i_assert(sync_ctx->next_uid <= update->min_next_uid);
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen sync_ctx->base_uid_last = update->min_next_uid-1;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen sync_ctx->next_uid = update->min_next_uid;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen mail_ctx->imapbase_rewrite = TRUE;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen mail_ctx->need_rewrite = TRUE;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen}
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainenstatic bool mbox_sync_imapbase(struct mbox_sync_context *sync_ctx,
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen struct mbox_sync_mail_context *mail_ctx)
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen{
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen if (sync_ctx->base_uid_validity != 0 &&
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen sync_ctx->hdr->uid_validity != 0 &&
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen sync_ctx->base_uid_validity != sync_ctx->hdr->uid_validity) {
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen i_warning("UIDVALIDITY changed (%u -> %u) in mbox file %s",
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen sync_ctx->hdr->uid_validity,
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen sync_ctx->base_uid_validity,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mailbox_get_path(&sync_ctx->mbox->box));
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen sync_ctx->index_reset = TRUE;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen return TRUE;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (sync_ctx->mbox->sync_hdr_update != NULL)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mbox_sync_hdr_update(sync_ctx, mail_ctx);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen return FALSE;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen}
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainenstatic int mbox_sync_loop(struct mbox_sync_context *sync_ctx,
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen struct mbox_sync_mail_context *mail_ctx,
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen bool partial)
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen{
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen const struct mail_index_record *rec;
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen uint32_t uid, messages_count;
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen uoff_t offset;
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen int ret;
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen bool expunged, skipped_mails, uids_broken;
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen messages_count =
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen mail_index_view_get_messages_count(sync_ctx->sync_view);
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen /* always start from first message so we can read X-IMAP or
e9d68b41c007f0e545de361f8012f6f231bfec8bTimo Sirainen X-IMAPbase header */
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen ret = mbox_sync_seek_to_seq(sync_ctx, 0);
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen if (ret <= 0)
e9d68b41c007f0e545de361f8012f6f231bfec8bTimo Sirainen return ret;
e9d68b41c007f0e545de361f8012f6f231bfec8bTimo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (sync_ctx->renumber_uids) {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen /* expunge everything */
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen while (sync_ctx->idx_seq <= messages_count) {
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen mail_index_expunge(sync_ctx->t,
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen sync_ctx->idx_seq++);
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen }
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen }
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen skipped_mails = uids_broken = FALSE;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen while ((ret = mbox_sync_read_next_mail(sync_ctx, mail_ctx)) > 0) {
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen uid = mail_ctx->mail.uid;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (mail_ctx->seq == 1) {
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (mbox_sync_imapbase(sync_ctx, mail_ctx)) {
d0e5f8252516c4d4df2fbcdae4d37f9e5f931199Timo Sirainen sync_ctx->mbox->mbox_hdr.dirty_flag = TRUE;
d0e5f8252516c4d4df2fbcdae4d37f9e5f931199Timo Sirainen return 0;
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen }
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen }
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen if (mail_ctx->mail.uid_broken && partial) {
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen /* UID ordering problems, resync everything to make
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sure we get everything right */
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen if (sync_ctx->mbox->mbox_hdr.dirty_flag)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen mbox_sync_set_critical(sync_ctx,
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen "UIDs broken with partial sync");
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen sync_ctx->mbox->mbox_hdr.dirty_flag = TRUE;
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen return 0;
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (mail_ctx->mail.uid_broken)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen uids_broken = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mail_ctx->mail.pseudo)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uid = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen rec = NULL; ret = 1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (uid != 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (!mbox_sync_read_index_rec(sync_ctx, uid, &rec))
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen ret = 0;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (ret == 0) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen /* UID found but it's broken */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen uid = 0;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen } else if (uid == 0 &&
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen !mail_ctx->mail.pseudo &&
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen (sync_ctx->delay_writes ||
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen sync_ctx->idx_seq <= messages_count)) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen /* If we can't use/store X-UID header, use MD5 sum.
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen Also check for existing MD5 sums when we're actually
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen able to write X-UIDs. */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen sync_ctx->mbox->mbox_save_md5 = TRUE;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mbox_sync_find_index_md5(sync_ctx,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_ctx->hdr_md5_sum, &rec);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (rec != NULL)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uid = mail_ctx->mail.uid = rec->uid;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* get all sync records related to this message. with pseudo
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen message just get the first sync record so we can jump to
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen it with partial seeking. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mbox_sync_read_index_syncs(sync_ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_ctx->mail.pseudo ? 1 : uid,
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen &expunged);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen if (mail_ctx->mail.pseudo) {
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen /* if it was set, it was for the next message */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen expunged = FALSE;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen } else {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (rec == NULL) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* message wasn't found from index. we have to
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen read everything from now on, no skipping */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen partial = FALSE;
3cfff0ca01961d885bdbd6ef08d761880116af07Timo Sirainen }
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainen }
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (uid == 0 && !mail_ctx->mail.pseudo) {
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen /* missing/broken X-UID. all the rest of the mails
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen need new UIDs. */
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen while (sync_ctx->idx_seq <= messages_count) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen mail_index_expunge(sync_ctx->t,
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen sync_ctx->idx_seq++);
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen }
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (sync_ctx->next_uid == (uint32_t)-1) {
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen /* oh no, we're out of UIDs. this shouldn't
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen happen normally, so just try to get it fixed
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen without crashing. */
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen mail_storage_set_critical(
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen &sync_ctx->mbox->storage->storage,
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen "Out of UIDs, renumbering them in mbox "
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen "file %s",
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen mailbox_get_path(&sync_ctx->mbox->box));
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainen sync_ctx->renumber_uids = TRUE;
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainen return 0;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen }
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen mail_ctx->need_rewrite = TRUE;
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen mail_ctx->mail.uid = sync_ctx->next_uid++;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen }
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->prev_msg_uid = mail_ctx->mail.uid;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (!mail_ctx->mail.pseudo)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mail_ctx->mail.idx_seq = sync_ctx->idx_seq;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (!expunged) {
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (!mail_ctx->mail.pseudo) T_BEGIN {
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen mbox_sync_update_flags(mail_ctx, rec);
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen } T_END;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (mbox_sync_handle_header(mail_ctx) < 0)
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen return -1;
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen sync_ctx->dest_first_mail = FALSE;
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen } else {
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen mbox_sync_handle_expunge(mail_ctx);
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen }
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (!mail_ctx->mail.pseudo) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (!expunged) T_BEGIN {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_sync_update_index(mail_ctx, rec);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } T_END;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->idx_seq++;
f5b919e9b07dfd9d2401b998ef8759e5f0312719Timo Sirainen }
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen istream_raw_mbox_next(sync_ctx->input,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen mail_ctx->mail.body_size);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen offset = istream_raw_mbox_get_start_offset(sync_ctx->input);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (sync_ctx->need_space_seq != 0) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (mbox_sync_handle_missing_space(mail_ctx) < 0)
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen return -1;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (mbox_sync_seek(sync_ctx, offset) < 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return -1;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen } else if (sync_ctx->expunged_space > 0) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (!expunged) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen /* move the body */
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen mbox_sync_file_update_ext_modified(sync_ctx);
5edfc0f1c3c55e906d8316d9cdeaa3b0c7000c19Timo Sirainen if (mbox_move(sync_ctx,
5edfc0f1c3c55e906d8316d9cdeaa3b0c7000c19Timo Sirainen mail_ctx->body_offset -
8e1f0e57b7e90d9f454ebeac7a283485ced3780cTimo Sirainen sync_ctx->expunged_space,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_ctx->body_offset,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.body_size) < 0)
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen return -1;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (mbox_sync_seek(sync_ctx, offset) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else if (partial) {
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen ret = mbox_sync_partial_seek_next(sync_ctx, uid + 1,
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen &partial,
f5b919e9b07dfd9d2401b998ef8759e5f0312719Timo Sirainen &skipped_mails);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ret <= 0)
f5b919e9b07dfd9d2401b998ef8759e5f0312719Timo Sirainen break;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ret < 0)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen return -1;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen if (istream_raw_mbox_is_eof(sync_ctx->input)) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen /* rest of the messages in index don't exist -> expunge them */
f5b919e9b07dfd9d2401b998ef8759e5f0312719Timo Sirainen while (sync_ctx->idx_seq <= messages_count)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mail_index_expunge(sync_ctx->t, sync_ctx->idx_seq++);
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen if (!skipped_mails)
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->mbox->mbox_hdr.dirty_flag = FALSE;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen sync_ctx->mbox->mbox_broken_offsets = FALSE;
f5b919e9b07dfd9d2401b998ef8759e5f0312719Timo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen if (uids_broken && sync_ctx->delay_writes) {
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen /* once we get around to writing the changes, we'll need to do
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen a full sync to avoid the "UIDs broken in partial sync"
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen error */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen sync_ctx->mbox->mbox_hdr.dirty_flag = TRUE;
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen }
99be58a447b69d62cbd9e764000a06226b9c9c89Timo Sirainen return 1;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen}
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenstatic int mbox_write_pseudo(struct mbox_sync_context *sync_ctx)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen string_t *str;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen unsigned int uid_validity;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(sync_ctx->write_fd != -1);
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (sync_ctx->mbox->sync_hdr_update != NULL) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen const struct mailbox_update *update =
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->mbox->sync_hdr_update;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (update->uid_validity != 0)
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->base_uid_validity = update->uid_validity;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (update->min_next_uid != 0)
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen sync_ctx->base_uid_last = update->min_next_uid-1;
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen }
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen uid_validity = sync_ctx->base_uid_validity != 0 ?
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen sync_ctx->base_uid_validity : sync_ctx->hdr->uid_validity;
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen i_assert(uid_validity != 0);
5edfc0f1c3c55e906d8316d9cdeaa3b0c7000c19Timo Sirainen
5edfc0f1c3c55e906d8316d9cdeaa3b0c7000c19Timo Sirainen str = t_str_new(1024);
eb276c05bf6b0a383c772d61e31cf09a8dbd36c7Timo Sirainen str_printfa(str, "%sDate: %s\n"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "From: Mail System Internal Data <MAILER-DAEMON@%s>\n"
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen "Subject: DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA"
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen "\nMessage-ID: <%s@%s>\n"
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen "X-IMAP: %u %010u\n"
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen "Status: RO\n"
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen "\n"
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen PSEUDO_MESSAGE_BODY
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen "\n",
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_from_create("MAILER_DAEMON", ioloop_time),
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen message_date_create(ioloop_time),
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen my_hostname, dec2str(ioloop_time), my_hostname,
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen uid_validity, sync_ctx->next_uid-1);
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (pwrite_full(sync_ctx->write_fd,
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen str_data(str), str_len(str), 0) < 0) {
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (!ENOSPACE(errno)) {
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen "pwrite_full()");
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* out of disk space, truncate to empty */
af6d4a24cb6d18e50d172540cf49b1448a6f9872Timo Sirainen if (ftruncate(sync_ctx->write_fd, 0) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "ftruncate()");
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->base_uid_validity = uid_validity;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->base_uid_last_offset = 0; /* don't bother calculating */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->base_uid_last = sync_ctx->next_uid-1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainenstatic int mbox_append_zero(struct mbox_sync_context *sync_ctx,
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen uoff_t orig_file_size, uoff_t count)
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen{
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen char block[IO_BLOCK_SIZE];
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen uoff_t offset = orig_file_size;
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen ssize_t ret = 0;
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen memset(block, 0, I_MIN(sizeof(block), count));
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen while (count > 0) {
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen ret = pwrite(sync_ctx->write_fd, block,
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen I_MIN(sizeof(block), count), offset);
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen if (ret < 0)
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen break;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen offset += ret;
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen count -= ret;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen if (ret < 0) {
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "pwrite()");
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen if (ftruncate(sync_ctx->write_fd, orig_file_size) < 0)
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "ftruncate()");
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen return 0;
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen}
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainenstatic int mbox_sync_handle_eof_updates(struct mbox_sync_context *sync_ctx,
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen struct mbox_sync_mail_context *mail_ctx)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen{
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen uoff_t file_size, offset, padding, trailer_size;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen int ret;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (!istream_raw_mbox_is_eof(sync_ctx->input)) {
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen i_assert(sync_ctx->need_space_seq == 0);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen i_assert(sync_ctx->expunged_space == 0);
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen return 0;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen ret = i_stream_get_size(sync_ctx->file_input, TRUE, &file_size);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (ret < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "i_stream_get_size()");
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return -1;
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen }
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (ret == 0) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* Not a file - allow anyway */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (file_size < sync_ctx->file_input->v_offset) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_sync_set_critical(sync_ctx,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen "file size unexpectedly shrank "
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen "(%"PRIuUOFF_T" vs %"PRIuUOFF_T")", file_size,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->file_input->v_offset);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen trailer_size = file_size - sync_ctx->file_input->v_offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(trailer_size <= 2);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (sync_ctx->need_space_seq != 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen i_assert(sync_ctx->write_fd != -1);
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen i_assert(sync_ctx->space_diff < 0);
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen padding = MBOX_HEADER_PADDING *
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen (sync_ctx->seq - sync_ctx->need_space_seq + 1);
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen sync_ctx->space_diff -= padding;
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen i_assert(sync_ctx->expunged_space <= -sync_ctx->space_diff);
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen sync_ctx->space_diff += sync_ctx->expunged_space;
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen sync_ctx->expunged_space = 0;
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen if (mail_ctx->have_eoh && !mail_ctx->updated)
325f4573edfa5b751832ac01023f3e81be992bf0Timo Sirainen str_append_c(mail_ctx->header, '\n');
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(sync_ctx->space_diff < 0);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (mbox_append_zero(sync_ctx, file_size,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen -sync_ctx->space_diff) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_sync_file_updated(sync_ctx, FALSE);
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (mbox_sync_rewrite(sync_ctx, mail_ctx, file_size,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen -sync_ctx->space_diff, padding,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->need_space_seq,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->seq) < 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen update_from_offsets(sync_ctx);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->need_space_seq = 0;
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen array_clear(&sync_ctx->mails);
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen p_clear(sync_ctx->saved_keywords_pool);
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen }
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen if (sync_ctx->expunged_space > 0) {
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen i_assert(sync_ctx->write_fd != -1);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mbox_sync_file_update_ext_modified(sync_ctx);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* copy trailer, then truncate the file */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen file_size = sync_ctx->last_stat.st_size;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (file_size == (uoff_t)sync_ctx->expunged_space) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* everything deleted, the trailer_size still contains
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen the \n trailer though */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen trailer_size = 0;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen } else if (sync_ctx->expunged_space == (off_t)file_size + 1 ||
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->expunged_space == (off_t)file_size + 2) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* everything deleted and we didn't have a proper
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen trailer. */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen trailer_size = 0;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->expunged_space = file_size;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen i_assert(file_size >= sync_ctx->expunged_space + trailer_size);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen offset = file_size - sync_ctx->expunged_space - trailer_size;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen i_assert(offset == 0 || offset > 31);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (mbox_move(sync_ctx, offset,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen offset + sync_ctx->expunged_space,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen trailer_size) < 0)
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen return -1;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (ftruncate(sync_ctx->write_fd,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen offset + trailer_size) < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "ftruncate()");
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen return -1;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen }
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen
7c95b03620a03a43dd72d39608cea5fc77393ad6Timo Sirainen if (offset == 0) {
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen if (mbox_write_pseudo(sync_ctx) < 0)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen }
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->expunged_space = 0;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen mbox_sync_file_updated(sync_ctx, FALSE);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file_size == 0 && sync_ctx->mbox->sync_hdr_update != NULL) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mbox_write_pseudo(sync_ctx) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen }
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen return 0;
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen}
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainenstatic void
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainenmbox_sync_index_update_ext_header(struct mbox_mailbox *mbox,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mail_index_transaction *trans)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const struct mailbox_update *update = mbox->sync_hdr_update;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const void *data;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen size_t data_size;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (update != NULL && !guid_128_is_empty(update->mailbox_guid)) {
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen memcpy(mbox->mbox_hdr.mailbox_guid, update->mailbox_guid,
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen sizeof(mbox->mbox_hdr.mailbox_guid));
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen } else if (guid_128_is_empty(mbox->mbox_hdr.mailbox_guid)) {
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen guid_128_generate(mbox->mbox_hdr.mailbox_guid);
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen mail_index_get_header_ext(mbox->box.view, mbox->mbox_ext_idx,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen &data, &data_size);
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen if (data_size != sizeof(mbox->mbox_hdr) ||
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen memcmp(data, &mbox->mbox_hdr, data_size) != 0) {
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen if (data_size != sizeof(mbox->mbox_hdr)) {
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen /* upgrading from v1.x */
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen mail_index_ext_resize(trans, mbox->mbox_ext_idx,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sizeof(mbox->mbox_hdr),
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sizeof(uint64_t),
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen sizeof(uint64_t));
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen }
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen mail_index_update_header_ext(trans, mbox->mbox_ext_idx,
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen 0, &mbox->mbox_hdr,
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen sizeof(mbox->mbox_hdr));
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen}
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainenstatic uint32_t mbox_get_uidvalidity_next(struct mailbox_list *list)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen{
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen const char *path;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen path = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_CONTROL);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen path = t_strconcat(path, "/"MBOX_UIDVALIDITY_FNAME, NULL);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return mailbox_uidvalidity_next(list, path);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen}
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic int mbox_sync_update_index_header(struct mbox_sync_context *sync_ctx)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen{
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen struct mail_index_view *view;
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen const struct stat *st;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen uint32_t first_recent_uid, seq, seq2;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen if (i_stream_stat(sync_ctx->file_input, FALSE, &st) < 0) {
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "i_stream_stat()");
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen if (sync_ctx->moved_offsets &&
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen ((uint64_t)st->st_size == sync_ctx->mbox->mbox_hdr.sync_size ||
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen (uint64_t)st->st_size == sync_ctx->orig_size)) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* We moved messages inside the mbox file without changing
6597506f9317f3be644e708c9153dacaeeece84cTimo Sirainen the file's size. If mtime doesn't change, another process
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen not using the same index file as us can't know that the file
d252f81a2ff1bdd5439f9d2b3df715b70a4bcd3dTimo Sirainen was changed. So make sure the mtime changes. This should
d252f81a2ff1bdd5439f9d2b3df715b70a4bcd3dTimo Sirainen happen rarely enough that the sleeping doesn't become a
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen performance problem.
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen Note that to do this perfectly safe we should do this wait
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen whenever mails are moved or expunged, regardless of whether
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen the file's size changed. That however could become a
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen performance problem and the consequences of being wrong are
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen quite minimal (an extra logged error message). */
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen while (sync_ctx->orig_mtime == st->st_mtime) {
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen usleep(500000);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (utime(mailbox_get_path(&sync_ctx->mbox->box), NULL) < 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen "utime()");
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return -1;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen }
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen if (i_stream_stat(sync_ctx->file_input, FALSE, &st) < 0) {
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen "i_stream_stat()");
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen return -1;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen }
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen }
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen }
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen sync_ctx->mbox->mbox_hdr.sync_mtime = st->st_mtime;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->mbox->mbox_hdr.sync_size = st->st_size;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen mbox_sync_index_update_ext_header(sync_ctx->mbox, sync_ctx->t);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen /* only reason not to have UID validity at this point is if the file
f2b79667fc7a8f7c2c72cad18bd71d49730e36f6Timo Sirainen is entirely empty. In that case just make up a new one if needed. */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen i_assert(sync_ctx->base_uid_validity != 0 || st->st_size <= 0);
f2b79667fc7a8f7c2c72cad18bd71d49730e36f6Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen if (sync_ctx->base_uid_validity == 0) {
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen sync_ctx->base_uid_validity = sync_ctx->hdr->uid_validity != 0 ?
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen sync_ctx->hdr->uid_validity :
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen mbox_get_uidvalidity_next(sync_ctx->mbox->box.list);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen }
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen if (sync_ctx->base_uid_validity != sync_ctx->hdr->uid_validity) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mail_index_update_header(sync_ctx->t,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen offsetof(struct mail_index_header, uid_validity),
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen &sync_ctx->base_uid_validity,
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen sizeof(sync_ctx->base_uid_validity), TRUE);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (istream_raw_mbox_is_eof(sync_ctx->input) &&
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->next_uid != sync_ctx->hdr->next_uid) {
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen i_assert(sync_ctx->next_uid != 0);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen mail_index_update_header(sync_ctx->t,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen offsetof(struct mail_index_header, next_uid),
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen &sync_ctx->next_uid, sizeof(sync_ctx->next_uid), FALSE);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (sync_ctx->last_nonrecent_uid < sync_ctx->hdr->first_recent_uid) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* other sessions have already marked more messages as
757726d9acbd04cf0d0d4be8ce14e11525476a0bTimo Sirainen recent. */
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen sync_ctx->last_nonrecent_uid =
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen sync_ctx->hdr->first_recent_uid - 1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* mark recent messages */
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen view = mail_index_transaction_open_updated_view(sync_ctx->t);
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen if (mail_index_lookup_seq_range(view, sync_ctx->last_nonrecent_uid + 1,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen (uint32_t)-1, &seq, &seq2)) {
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen index_mailbox_set_recent_seq(&sync_ctx->mbox->box,
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen view, seq, seq2);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mail_index_view_close(&view);
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen first_recent_uid = !sync_ctx->keep_recent ?
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen sync_ctx->next_uid : sync_ctx->last_nonrecent_uid + 1;
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen if (sync_ctx->hdr->first_recent_uid < first_recent_uid) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mail_index_update_header(sync_ctx->t,
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen offsetof(struct mail_index_header, first_recent_uid),
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen &first_recent_uid, sizeof(first_recent_uid), FALSE);
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen }
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen return 0;
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen}
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainenstatic void mbox_sync_restart(struct mbox_sync_context *sync_ctx)
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen{
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen sync_ctx->base_uid_validity = 0;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen sync_ctx->base_uid_last = 0;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen sync_ctx->base_uid_last_offset = 0;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen array_clear(&sync_ctx->mails);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen p_clear(sync_ctx->saved_keywords_pool);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen index_sync_changes_reset(sync_ctx->sync_changes);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen mail_index_sync_reset(sync_ctx->index_sync_ctx);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen mail_index_transaction_reset(sync_ctx->t);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->index_reset) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mail_index_reset(sync_ctx->t);
de4288b7369945a31c4001add9445fd0195a358dTimo Sirainen sync_ctx->reset_hdr.next_uid = 1;
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen sync_ctx->hdr = &sync_ctx->reset_hdr;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen index_mailbox_reset_uidvalidity(&sync_ctx->mbox->box);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->prev_msg_uid = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->next_uid = sync_ctx->hdr->next_uid;
7c95b03620a03a43dd72d39608cea5fc77393ad6Timo Sirainen sync_ctx->idx_next_uid = sync_ctx->hdr->next_uid;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen sync_ctx->seq = 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen sync_ctx->idx_seq = 1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen sync_ctx->need_space_seq = 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->expunged_space = 0;
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen sync_ctx->space_diff = 0;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen sync_ctx->dest_first_mail = TRUE;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen sync_ctx->ext_modified = FALSE;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen sync_ctx->errors = FALSE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic int mbox_sync_do(struct mbox_sync_context *sync_ctx,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen enum mbox_sync_flags flags)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen{
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen struct mbox_index_header *mbox_hdr = &sync_ctx->mbox->mbox_hdr;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct mbox_sync_mail_context mail_ctx;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen const struct stat *st;
e5ee67f18b03015c88b579c8c1f17ebe6ce19b76Timo Sirainen unsigned int i;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen int ret, partial;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
de4288b7369945a31c4001add9445fd0195a358dTimo Sirainen if (i_stream_stat(sync_ctx->file_input, FALSE, &st) < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "i_stream_stat()");
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen sync_ctx->last_stat = *st;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->orig_size = st->st_size;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->orig_atime = st->st_atime;
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen sync_ctx->orig_mtime = st->st_mtime;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if ((flags & MBOX_SYNC_FORCE_SYNC) != 0) {
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen /* forcing a full sync. assume file has changed. */
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen partial = FALSE;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen mbox_hdr->dirty_flag = TRUE;
79c9f3069bde51f799a64ca5923d68c9a5bc2ad2Timo Sirainen } else if ((uint32_t)st->st_mtime == mbox_hdr->sync_mtime &&
79c9f3069bde51f799a64ca5923d68c9a5bc2ad2Timo Sirainen (uint64_t)st->st_size == mbox_hdr->sync_size) {
79c9f3069bde51f799a64ca5923d68c9a5bc2ad2Timo Sirainen /* file is fully synced */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox_hdr->dirty_flag && (flags & MBOX_SYNC_UNDIRTY) != 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen partial = FALSE;
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen else
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen partial = TRUE;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen } else if ((flags & MBOX_SYNC_UNDIRTY) != 0 ||
59ef34eafaf74d31ed88af444b22d1a0738a30aaTimo Sirainen (uint64_t)st->st_size == mbox_hdr->sync_size) {
59ef34eafaf74d31ed88af444b22d1a0738a30aaTimo Sirainen /* we want to do full syncing. always do this if
59ef34eafaf74d31ed88af444b22d1a0738a30aaTimo Sirainen file size hasn't changed but timestamp has. it most
59ef34eafaf74d31ed88af444b22d1a0738a30aaTimo Sirainen likely means that someone had modified some header
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen and we probably want to know about it */
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen partial = FALSE;
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen sync_ctx->mbox->mbox_hdr.dirty_flag = TRUE;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen } else {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* see if we can delay syncing the whole file.
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen normally we only notice expunges and appends
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen in partial syncing. */
8573a63139eab50fee1e497276f126f0d04d5637Timo Sirainen partial = TRUE;
8573a63139eab50fee1e497276f126f0d04d5637Timo Sirainen sync_ctx->mbox->mbox_hdr.dirty_flag = TRUE;
8573a63139eab50fee1e497276f126f0d04d5637Timo Sirainen }
8573a63139eab50fee1e497276f126f0d04d5637Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_sync_restart(sync_ctx);
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen for (i = 0;;) {
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen ret = mbox_sync_loop(sync_ctx, &mail_ctx, partial);
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if (ret > 0 && !sync_ctx->errors)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen break;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if (ret < 0)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen return -1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* a) partial sync didn't work
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen b) we ran out of UIDs
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen c) syncing had errors */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if (sync_ctx->delay_writes &&
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen (sync_ctx->errors || sync_ctx->renumber_uids)) {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* fixing a broken mbox state, be sure to write
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen the changes (except if we're readonly). */
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (!sync_ctx->readonly)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen sync_ctx->delay_writes = FALSE;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (++i == 3)
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen break;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen mbox_sync_restart(sync_ctx);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen partial = FALSE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (mbox_sync_handle_eof_updates(sync_ctx, &mail_ctx) < 0)
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen return -1;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen /* only syncs left should be just appends (and their updates)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen which weren't synced yet for some reason (crash). we'll just
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen ignore them, as we've overwritten them above. */
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen index_sync_changes_reset(sync_ctx->sync_changes);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (sync_ctx->base_uid_last != sync_ctx->next_uid-1 &&
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen ret > 0 && !sync_ctx->delay_writes &&
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen sync_ctx->base_uid_last_offset != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Rewrite uid_last in X-IMAPbase header if we've seen it
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen (ie. the file isn't empty) */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ret = mbox_rewrite_base_uid_last(sync_ctx);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen } else {
29e945d8550f297707f3a5f627a938401046c0ccTimo Sirainen ret = 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
95ed89440faab05cbb4f2473f2f4af19e848bde8Timo Sirainen
e5ee67f18b03015c88b579c8c1f17ebe6ce19b76Timo Sirainen if (mbox_sync_update_index_header(sync_ctx) < 0)
e5ee67f18b03015c88b579c8c1f17ebe6ce19b76Timo Sirainen return -1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return ret;
95ed89440faab05cbb4f2473f2f4af19e848bde8Timo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainenint mbox_sync_header_refresh(struct mbox_mailbox *mbox)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
const void *data;
size_t data_size;
if (mail_index_refresh(mbox->box.index) < 0) {
mailbox_set_index_error(&mbox->box);
return -1;
}
mail_index_get_header_ext(mbox->box.view, mbox->mbox_ext_idx,
&data, &data_size);
if (data_size == 0) {
/* doesn't exist yet. */
memset(&mbox->mbox_hdr, 0, sizeof(mbox->mbox_hdr));
return 0;
}
memcpy(&mbox->mbox_hdr, data, I_MIN(sizeof(mbox->mbox_hdr), data_size));
if (mbox->mbox_broken_offsets)
mbox->mbox_hdr.dirty_flag = TRUE;
return 0;
}
int mbox_sync_get_guid(struct mbox_mailbox *mbox)
{
struct mail_index_transaction *trans;
unsigned int lock_id;
int ret;
if (mbox_lock(mbox, F_WRLCK, &lock_id) <= 0)
return -1;
ret = mbox_sync_header_refresh(mbox);
if (ret == 0) {
trans = mail_index_transaction_begin(mbox->box.view,
MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL);
mbox_sync_index_update_ext_header(mbox, trans);
ret = mail_index_transaction_commit(&trans);
}
mbox_unlock(mbox, lock_id);
return ret;
}
int mbox_sync_has_changed(struct mbox_mailbox *mbox, bool leave_dirty)
{
bool empty;
return mbox_sync_has_changed_full(mbox, leave_dirty, &empty);
}
int mbox_sync_has_changed_full(struct mbox_mailbox *mbox, bool leave_dirty,
bool *empty_r)
{
const struct stat *st;
struct stat statbuf;
if (mbox->mbox_file_stream != NULL && mbox->mbox_fd == -1) {
/* read-only stream */
if (i_stream_stat(mbox->mbox_file_stream, FALSE, &st) < 0) {
if (errno == ENOENT) {
mailbox_set_deleted(&mbox->box);
return 0;
}
mbox_set_syscall_error(mbox, "i_stream_stat()");
return -1;
}
} else {
if (stat(mailbox_get_path(&mbox->box), &statbuf) < 0) {
if (errno == ENOENT) {
mailbox_set_deleted(&mbox->box);
return 0;
}
mbox_set_syscall_error(mbox, "stat()");
return -1;
}
st = &statbuf;
}
*empty_r = st->st_size == 0;
if (mbox_sync_header_refresh(mbox) < 0)
return -1;
if (guid_128_is_empty(mbox->mbox_hdr.mailbox_guid)) {
/* need to assign mailbox GUID */
return 1;
}
if ((uint32_t)st->st_mtime == mbox->mbox_hdr.sync_mtime &&
(uint64_t)st->st_size == mbox->mbox_hdr.sync_size) {
/* fully synced */
if (!mbox->mbox_hdr.dirty_flag || leave_dirty)
return 0;
/* flushing dirtyness */
}
/* file changed */
return 1;
}
static void mbox_sync_context_free(struct mbox_sync_context *sync_ctx)
{
index_sync_changes_deinit(&sync_ctx->sync_changes);
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);
}
static int mbox_sync_int(struct mbox_mailbox *mbox, enum mbox_sync_flags flags,
unsigned int *lock_id)
{
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;
int ret, changed;
bool delay_writes, readonly;
readonly = mbox_is_backend_readonly(mbox) ||
(flags & MBOX_SYNC_READONLY) != 0;
delay_writes = readonly ||
((flags & MBOX_SYNC_REWRITE) == 0 &&
mbox->storage->set->mbox_lazy_writes);
if (!mbox->storage->set->mbox_dirty_syncs &&
!mbox->storage->set->mbox_very_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) {
if (mbox_sync_header_refresh(mbox) < 0)
return -1;
changed = 1;
} else {
bool leave_dirty = (flags & MBOX_SYNC_UNDIRTY) == 0;
if ((changed = mbox_sync_has_changed(mbox, leave_dirty)) < 0)
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 */
mbox_unlock(mbox, *lock_id);
*lock_id = 0;
}
/* flush input streams' buffers */
if (mbox->mbox_stream != NULL)
i_stream_sync(mbox->mbox_stream);
if (mbox->mbox_file_stream != NULL)
i_stream_sync(mbox->mbox_file_stream);
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 = readonly ? F_RDLCK : F_WRLCK;
if ((ret = mbox_lock(mbox, lock_type, lock_id)) <= 0) {
if (ret == 0 || lock_type == F_RDLCK)
return -1;
/* try as read-only */
if (mbox_lock(mbox, F_RDLCK, lock_id) <= 0)
return -1;
mbox->backend_readonly = readonly = TRUE;
mbox->backend_readonly_set = TRUE;
delay_writes = TRUE;
}
}
sync_flags = index_storage_get_sync_flags(&mbox->box);
if ((flags & MBOX_SYNC_REWRITE) != 0)
sync_flags |= MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY;
ret = mail_index_sync_begin(mbox->box.index, &index_sync_ctx,
&sync_view, &trans, sync_flags);
if (ret <= 0) {
if (ret < 0)
mailbox_set_index_error(&mbox->box);
return ret;
}
if ((mbox->box.flags & MAILBOX_FLAG_DROP_RECENT) != 0) {
/* see if we need to drop recent flags */
sync_ctx.hdr = mail_index_get_header(sync_view);
if (sync_ctx.hdr->first_recent_uid < sync_ctx.hdr->next_uid)
changed = 1;
}
if (!changed && !mail_index_sync_have_more(index_sync_ctx)) {
/* nothing to do */
nothing_to_do:
/* index may need to do internal syncing though, so commit
instead of rollbacking. */
if (mail_index_sync_commit(&index_sync_ctx) < 0) {
mailbox_set_index_error(&mbox->box);
return -1;
}
return 0;
}
memset(&sync_ctx, 0, sizeof(sync_ctx));
sync_ctx.mbox = mbox;
sync_ctx.keep_recent =
(mbox->box.flags & MAILBOX_FLAG_DROP_RECENT) == 0;
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", 512);
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->box.index);
i_array_init(&sync_ctx.mails, 64);
sync_ctx.flags = flags;
sync_ctx.readonly = readonly;
sync_ctx.delay_writes = delay_writes;
sync_ctx.sync_changes =
index_sync_changes_init(index_sync_ctx, sync_view, trans,
sync_ctx.delay_writes);
if (!changed && delay_writes) {
/* if we have only flag changes, we don't need to open the
mbox file */
bool expunged;
uint32_t uid;
mbox_sync_read_index_syncs(&sync_ctx, 1, &expunged);
uid = expunged ? 1 :
index_sync_changes_get_next_uid(sync_ctx.sync_changes);
if (uid == 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);
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) {
mailbox_set_index_error(&mbox->box);
ret = -1;
}
sync_ctx.t = NULL;
sync_ctx.index_sync_ctx = NULL;
if (ret == 0 && mbox->mbox_fd != -1 && sync_ctx.keep_recent &&
!readonly) {
/* try to set atime back to its original value.
(it'll fail with EPERM for shared mailboxes where we aren't
the file's owner) */
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(mailbox_get_path(&mbox->box), &buf) < 0 &&
errno != EPERM)
mbox_set_syscall_error(mbox, "utime()");
}
}
i_assert(*lock_id != 0);
if (mbox->storage->storage.set->mail_nfs_storage &&
mbox->mbox_fd != -1) {
if (fdatasync(mbox->mbox_fd) < 0) {
mbox_set_syscall_error(mbox, "fdatasync()");
ret = -1;
}
}
mbox_sync_context_free(&sync_ctx);
return ret;
}
int mbox_sync(struct mbox_mailbox *mbox, enum mbox_sync_flags flags)
{
unsigned int lock_id = 0;
int ret;
i_assert(mbox->mbox_lock_type != F_RDLCK ||
(flags & MBOX_SYNC_READONLY) != 0);
mbox->syncing = TRUE;
ret = mbox_sync_int(mbox, flags, &lock_id);
mbox->syncing = FALSE;
if (lock_id != 0) {
if (ret < 0) {
/* syncing failed, don't leave it locked */
mbox_unlock(mbox, lock_id);
} else if ((flags & MBOX_SYNC_LOCK_READING) == 0) {
if (mbox_unlock(mbox, lock_id) < 0)
ret = -1;
} else 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;
if (mbox_unlock(mbox, lock_id) < 0)
ret = -1;
}
}
if (mbox->box.v.sync_notify != NULL)
mbox->box.v.sync_notify(&mbox->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) {
if (mailbox_open(box) < 0)
ret = -1;
}
if (index_mailbox_want_full_sync(&mbox->box, flags) && ret == 0) {
if ((flags & MAILBOX_SYNC_FLAG_FULL_READ) != 0 &&
!mbox->storage->set->mbox_very_dirty_syncs)
mbox_sync_flags |= MBOX_SYNC_UNDIRTY;
if ((flags & MAILBOX_SYNC_FLAG_FULL_WRITE) != 0)
mbox_sync_flags |= MBOX_SYNC_REWRITE;
if ((flags & MAILBOX_SYNC_FLAG_FORCE_RESYNC) != 0) {
mbox_sync_flags |= MBOX_SYNC_UNDIRTY |
MBOX_SYNC_REWRITE | MBOX_SYNC_FORCE_SYNC;
}
ret = mbox_sync(mbox, mbox_sync_flags);
}
return index_mailbox_sync_init(box, flags, ret < 0);
}