mbox-sync.c revision 6060b7c8edf8fce73470d0df6a2479b69b01c537
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
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"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hostpid.h"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "file-set-size.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "read-full.h"
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen#include "write-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "message-date.h"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen#include "istream-raw-mbox.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mbox-storage.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mbox-from.h"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen#include "mbox-file.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mbox-lock.h"
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen#include "mbox-sync-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stddef.h>
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen#include <stdlib.h>
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen#include <sys/stat.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#define MBOX_SYNC_SECS 1
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo 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 \
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo 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" \
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen"with the data reset to initial values.\n"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainenint mbox_sync_seek(struct mbox_sync_context *sync_ctx, uoff_t from_offset)
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen{
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen if (istream_raw_mbox_seek(sync_ctx->input, from_offset) < 0) {
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen mail_storage_set_critical(STORAGE(sync_ctx->mbox->storage),
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen "Unexpectedly lost From-line at offset %"PRIuUOFF_T
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen " from mbox file %s", from_offset,
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen sync_ctx->mbox->path);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return -1;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen }
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen return 0;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen}
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainenstatic void mbox_sync_array_delete_to(array_t *syncs_arr, uint32_t last_uid)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen ARRAY_SET_TYPE(syncs_arr, struct mail_index_sync_rec);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen struct mail_index_sync_rec *syncs;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen unsigned int src, dest, count;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen syncs = array_get_modifyable(syncs_arr, &count);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen for (src = dest = 0; src < count; src++) {
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen i_assert(last_uid >= syncs[src].uid1);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (last_uid <= syncs[src].uid2) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* keep it */
445f9e31c6c3aa6c0a72be8565da8f6e594d24fbTimo Sirainen if (src != dest)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen syncs[dest] = syncs[src];
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen dest++;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen array_delete(syncs_arr, dest, count - dest);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen}
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenstatic int
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenmbox_sync_read_next_mail(struct mbox_sync_context *sync_ctx,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mbox_sync_mail_context *mail_ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* get EOF */
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainen (void)istream_raw_mbox_get_header_offset(sync_ctx->input);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (istream_raw_mbox_is_eof(sync_ctx->input))
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen memset(mail_ctx, 0, sizeof(*mail_ctx));
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mail_ctx->sync_ctx = sync_ctx;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mail_ctx->seq = ++sync_ctx->seq;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->header = sync_ctx->header;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mail_ctx->mail.from_offset =
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen istream_raw_mbox_get_start_offset(sync_ctx->input);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen mail_ctx->mail.offset =
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen istream_raw_mbox_get_header_offset(sync_ctx->input);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mbox_sync_parse_next_mail(sync_ctx->input, mail_ctx);
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainen i_assert(sync_ctx->input->v_offset != mail_ctx->mail.from_offset ||
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen sync_ctx->input->eof);
c3412ddeb9abc13f99d3caf50faf76cd99f7e9d2Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mail_ctx->mail.body_size =
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen istream_raw_mbox_get_body_size(sync_ctx->input,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mail_ctx->content_length);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen i_assert(mail_ctx->mail.body_size < OFF_T_MAX);
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if ((mail_ctx->mail.flags & MAIL_RECENT) != 0 && !mail_ctx->pseudo) {
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen if (!sync_ctx->mbox->ibox.keep_recent) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* need to add 'O' flag to Status-header */
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen mail_ctx->need_rewrite = TRUE;
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen }
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen mail_ctx->recent = TRUE;
e8a35266a5ceacdfafeeffd6bddae77931ff97ebTimo Sirainen }
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen return 1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int mbox_sync_buf_have_expunges(array_t *syncs_arr)
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen{
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen ARRAY_SET_TYPE(syncs_arr, struct mail_index_sync_rec);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen const struct mail_index_sync_rec *syncs;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen unsigned int i, count;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen syncs = array_get(syncs_arr, &count);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen for (i = 0; i < count; i++) {
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (syncs[i].type == MAIL_INDEX_SYNC_TYPE_EXPUNGE)
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen return TRUE;
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen }
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen return FALSE;
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen}
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainenstatic int mbox_sync_read_index_syncs(struct mbox_sync_context *sync_ctx,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uint32_t uid, int *sync_expunge_r)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mail_index_sync_rec *sync_rec = &sync_ctx->sync_rec;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen int ret;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen *sync_expunge_r = FALSE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->index_sync_ctx == NULL)
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (uid == 0) {
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen /* nothing for this or the future ones */
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen uid = (uint32_t)-1;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen }
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen mbox_sync_array_delete_to(&sync_ctx->syncs, uid);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen while (uid >= sync_rec->uid1) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (uid <= sync_rec->uid2 &&
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen sync_rec->type != MAIL_INDEX_SYNC_TYPE_APPEND &&
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen (sync_rec->type != MAIL_INDEX_SYNC_TYPE_EXPUNGE ||
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen !sync_ctx->mbox->mbox_readonly)) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen array_append(&sync_ctx->syncs, sync_rec, 1);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_EXPUNGE)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen *sync_expunge_r = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen ret = mail_index_sync_next(sync_ctx->index_sync_ctx, sync_rec);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ret < 0) {
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen mail_storage_set_index_error(&sync_ctx->mbox->ibox);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ret == 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen memset(sync_rec, 0, sizeof(*sync_rec));
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen break;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_APPEND) {
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen if (sync_rec->uid2 >= sync_ctx->next_uid)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->next_uid = sync_rec->uid2 + 1;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen memset(sync_rec, 0, sizeof(*sync_rec));
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen }
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (!*sync_expunge_r)
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen *sync_expunge_r = mbox_sync_buf_have_expunges(&sync_ctx->syncs);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenvoid mbox_sync_apply_index_syncs(struct mbox_sync_context *sync_ctx,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mbox_sync_mail *mail,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen int *keywords_changed_r)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen const struct mail_index_sync_rec *syncs;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen unsigned int i, count;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen *keywords_changed_r = FALSE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen syncs = array_get(&sync_ctx->syncs, &count);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen for (i = 0; i < count; i++) {
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen switch (syncs[i].type) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen case MAIL_INDEX_SYNC_TYPE_FLAGS:
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_index_sync_flags_apply(&syncs[i], &mail->flags);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen break;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET:
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (!array_is_created(&mail->keywords)) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* no existing keywords */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (syncs[i].type !=
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen break;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* adding, create the array */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ARRAY_CREATE(&mail->keywords,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen sync_ctx->mail_keyword_pool,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen unsigned int,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen I_MIN(10, count - i));
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (mail_index_sync_keywords_apply(&syncs[i],
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen &mail->keywords))
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen *keywords_changed_r = TRUE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen break;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen default:
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen break;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen}
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainenstatic int
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenmbox_sync_read_index_rec(struct mbox_sync_context *sync_ctx,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uint32_t uid, 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 int ret = 0;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen messages_count =
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen mail_index_view_get_messages_count(sync_ctx->sync_view);
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen while (sync_ctx->idx_seq <= messages_count) {
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen ret = mail_index_lookup(sync_ctx->sync_view,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen sync_ctx->idx_seq, &rec);
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen if (ret < 0) {
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen mail_storage_set_index_error(&sync_ctx->mbox->ibox);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen if (uid <= rec->uid)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen break;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* externally expunged message, remove from index */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_index_expunge(sync_ctx->t, sync_ctx->idx_seq);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->idx_seq++;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen rec = NULL;
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ret == 0 && uid < sync_ctx->idx_next_uid) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* this UID was already in index and it was expunged */
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen mail_storage_set_critical(STORAGE(sync_ctx->mbox->storage),
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen "mbox sync: Expunged message reappeared in mailbox %s "
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen "(UID %u < %u)", sync_ctx->mbox->path, uid,
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen sync_ctx->idx_next_uid);
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen ret = 0; rec = NULL;
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen } else if (rec != NULL && rec->uid != uid) {
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen /* new UID in the middle of the mailbox - shouldn't happen */
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen mail_storage_set_critical(STORAGE(sync_ctx->mbox->storage),
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen "mbox sync: UID inserted in the middle of mailbox %s "
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen "(%u > %u)", sync_ctx->mbox->path, rec->uid, uid);
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen ret = 0; rec = NULL;
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen } else {
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen ret = 1;
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen }
484efa22e65c509f787dbbc892351146c726c257Timo Sirainen
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen *rec_r = rec;
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen return ret;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int mbox_sync_find_index_md5(struct mbox_sync_context *sync_ctx,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen unsigned char hdr_md5_sum[],
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const struct mail_index_record **rec_r)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen const struct mail_index_record *rec = NULL;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen uint32_t messages_count;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen const void *data;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen int ret;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen messages_count =
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mail_index_view_get_messages_count(sync_ctx->sync_view);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen while (sync_ctx->idx_seq <= messages_count) {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen ret = mail_index_lookup(sync_ctx->sync_view,
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen sync_ctx->idx_seq, &rec);
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen if (ret < 0) {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mail_storage_set_index_error(&sync_ctx->mbox->ibox);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen return -1;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mail_index_lookup_ext(sync_ctx->sync_view,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen sync_ctx->idx_seq,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen sync_ctx->mbox->ibox.md5hdr_ext_idx,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen &data) < 0) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen mail_storage_set_index_error(&sync_ctx->mbox->ibox);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen return -1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (data != NULL && memcmp(data, hdr_md5_sum, 16) == 0)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen break;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen /* externally expunged message, remove from index */
f0f9c8e94abac18f8acd91b9e724c4c32863723aTimo Sirainen mail_index_expunge(sync_ctx->t, sync_ctx->idx_seq);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen sync_ctx->idx_seq++;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen rec = NULL;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen *rec_r = rec;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen return 0;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen}
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainenstatic int
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainenmbox_sync_update_from_offset(struct mbox_sync_context *sync_ctx,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen struct mbox_sync_mail *mail,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen int nocheck)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const void *data;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uint64_t offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (!nocheck) {
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen /* see if from_offset needs updating */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mail_index_lookup_ext(sync_ctx->sync_view,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->idx_seq,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->mbox->mbox_ext_idx,
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen &data) < 0) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen mail_storage_set_index_error(&sync_ctx->mbox->ibox);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen return -1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (data != NULL &&
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen *((const uint64_t *)data) == mail->from_offset)
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen offset = mail->from_offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_index_update_ext(sync_ctx->t, sync_ctx->idx_seq,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->mbox->mbox_ext_idx, &offset, NULL);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
8af07808ba203f8709e2ff9eaf2291e1c4a4d53dTimo Sirainen}
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic void
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenmbox_sync_update_index_keywords(struct mbox_sync_mail_context *mail_ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mail_keywords *keywords;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen keywords = !array_is_created(&mail_ctx->mail.keywords) ?
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_index_keywords_create(sync_ctx->t, NULL) :
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_index_keywords_create_from_indexes(sync_ctx->t,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen &mail_ctx->mail.keywords);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_index_update_keywords(sync_ctx->t, sync_ctx->idx_seq,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MODIFY_REPLACE, keywords);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_index_keywords_free(keywords);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic int 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;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen struct mbox_sync_mail *mail = &mail_ctx->mail;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen uint8_t mbox_flags;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen mbox_flags = mail->flags & MAIL_FLAGS_MASK;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen if (mail_ctx->dirty)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen mbox_flags |= MAIL_INDEX_MAIL_FLAG_DIRTY;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen else if (!sync_ctx->delay_writes)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen mbox_flags &= ~MAIL_INDEX_MAIL_FLAG_DIRTY;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen if (rec == NULL) {
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen /* new message */
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen mail_index_append(sync_ctx->t, mail->uid, &sync_ctx->idx_seq);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen mail_index_update_flags(sync_ctx->t, sync_ctx->idx_seq,
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen MODIFY_REPLACE, mbox_flags);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen mbox_sync_update_index_keywords(mail_ctx);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen if (sync_ctx->mbox->mbox_save_md5 != 0) {
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen mail_index_update_ext(sync_ctx->t, sync_ctx->idx_seq,
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen sync_ctx->mbox->ibox.md5hdr_ext_idx,
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen mail_ctx->hdr_md5_sum, NULL);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen } else {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* see if we need to update flags in index file. the flags in
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync records are automatically applied to rec->flags at the
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen end of index syncing, so calculate those new flags first */
33d63688ed8b26dc333e3c2edbfb2fe6e412604dTimo Sirainen struct mbox_sync_mail idx_mail;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen int keywords_changed;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen memset(&idx_mail, 0, sizeof(idx_mail));
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen idx_mail.flags = rec->flags;
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen /* get old keywords */
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen t_push();
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen ARRAY_CREATE(&idx_mail.keywords, pool_datastack_create(),
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen unsigned int, 32);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mail_index_lookup_keywords(sync_ctx->sync_view,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->idx_seq,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen &idx_mail.keywords) < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_storage_set_index_error(&sync_ctx->mbox->ibox);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen t_pop();
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return -1;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_sync_apply_index_syncs(sync_ctx, &idx_mail,
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen &keywords_changed);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen#define SYNC_FLAGS (MAIL_RECENT | MAIL_INDEX_MAIL_FLAG_DIRTY)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if ((idx_mail.flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* flags are dirty. ignore whatever was in the mbox,
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen but update recent/dirty flag states if needed. */
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen mbox_flags &= SYNC_FLAGS;
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen mbox_flags |= idx_mail.flags & ~SYNC_FLAGS;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen } else {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* keep index's internal flags */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mbox_flags &= MAIL_FLAGS_MASK | SYNC_FLAGS;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mbox_flags |= idx_mail.flags &
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ~(MAIL_FLAGS_MASK | SYNC_FLAGS);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if ((idx_mail.flags & ~SYNC_FLAGS) !=
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen (mbox_flags & ~SYNC_FLAGS)) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* flags other than recent/dirty have changed */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_index_update_flags(sync_ctx->t, sync_ctx->idx_seq,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MODIFY_REPLACE, mbox_flags);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen } else {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (((idx_mail.flags ^ mbox_flags) &
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_RECENT) != 0) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* drop recent flag (it can only be dropped) */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_index_update_flags(sync_ctx->t,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen sync_ctx->idx_seq,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MODIFY_REMOVE, MAIL_RECENT);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen if (((idx_mail.flags ^ mbox_flags) &
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen /* dirty flag state changed */
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen int dirty = (mbox_flags &
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen MAIL_INDEX_MAIL_FLAG_DIRTY) != 0;
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen mail_index_update_flags(sync_ctx->t,
844adc2ea94a10ef81d1ceac9a87b877c20de623Timo Sirainen sync_ctx->idx_seq,
844adc2ea94a10ef81d1ceac9a87b877c20de623Timo Sirainen dirty ? MODIFY_ADD : MODIFY_REMOVE,
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen MAIL_INDEX_MAIL_FLAG_DIRTY);
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen }
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen }
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen if ((idx_mail.flags & MAIL_INDEX_MAIL_FLAG_DIRTY) == 0 &&
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen !array_cmp(&idx_mail.keywords, &mail_ctx->mail.keywords))
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen mbox_sync_update_index_keywords(mail_ctx);
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen t_pop();
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen }
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen if (mail_ctx->recent &&
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen (rec == NULL || (rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) == 0 ||
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen (rec->flags & MAIL_RECENT) != 0)) {
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen index_mailbox_set_recent(&sync_ctx->mbox->ibox,
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen sync_ctx->idx_seq);
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen }
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen /* update from_offsets, but not if we're going to rewrite this message.
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen rewriting would just move it anyway. */
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen if (sync_ctx->need_space_seq == 0) {
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen int nocheck = rec == NULL || sync_ctx->expunged_space > 0;
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen if (mbox_sync_update_from_offset(sync_ctx, mail, nocheck) < 0)
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen return -1;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen return 0;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen}
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainenstatic int mbox_read_from_line(struct mbox_sync_mail_context *ctx)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen struct istream *input = ctx->sync_ctx->file_input;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const unsigned char *data;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen size_t size, from_line_size;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen buffer_set_used_size(ctx->sync_ctx->from_line, 0);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen from_line_size = ctx->hdr_offset - ctx->mail.from_offset;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen i_stream_seek(input, ctx->mail.from_offset);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen for (;;) {
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen data = i_stream_get_data(input, &size);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen if (size >= from_line_size)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen size = from_line_size;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen buffer_append(ctx->sync_ctx->from_line, data, size);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_stream_skip(input, size);
3023fb352cbc2052b156f6d325c2629531a1b5b4Timo Sirainen from_line_size -= size;
3023fb352cbc2052b156f6d325c2629531a1b5b4Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (from_line_size == 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen break;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (i_stream_read(input) < 0)
e8a35266a5ceacdfafeeffd6bddae77931ff97ebTimo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int mbox_rewrite_base_uid_last(struct mbox_sync_context *sync_ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen unsigned char buf[10];
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const char *str;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uint32_t uid_last;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen unsigned int i;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen int ret;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen i_assert(sync_ctx->base_uid_last_offset != 0);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen /* first check that the 10 bytes are there and they're exactly as
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen expected. just an extra safety check to make sure we never write
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen to wrong location in the mbox file. */
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen ret = pread_full(sync_ctx->write_fd, buf, sizeof(buf),
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen sync_ctx->base_uid_last_offset);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (ret < 0) {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "pread_full()");
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen return -1;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (ret == 0) {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen mail_storage_set_critical(STORAGE(sync_ctx->mbox->storage),
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen "X-IMAPbase uid-last unexpectedly points outside "
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen "mbox file %s", sync_ctx->mbox->path);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen return -1;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen for (i = 0, uid_last = 0; i < sizeof(buf); i++) {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (buf[i] < '0' || buf[i] > '9') {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen uid_last = (uint32_t)-1;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen break;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen uid_last = uid_last * 10 + (buf[i] - '0');
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (uid_last != sync_ctx->base_uid_last) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_storage_set_critical(STORAGE(sync_ctx->mbox->storage),
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen "X-IMAPbase uid-last unexpectedly lost in mbox file %s",
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->mbox->path);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo 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,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->base_uid_last_offset) < 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "pwrite_full()");
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen }
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen sync_ctx->base_uid_last = sync_ctx->next_uid - 1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return 0;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen}
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainenstatic int
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainenmbox_write_from_line(struct mbox_sync_mail_context *ctx)
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen{
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen string_t *str = ctx->sync_ctx->from_line;
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo 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()");
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen i_stream_sync(ctx->sync_ctx->input);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return 0;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen}
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenstatic void update_from_offsets(struct mbox_sync_context *sync_ctx)
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen{
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen const struct mbox_sync_mail *mails;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen unsigned int i, count;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uint32_t ext_idx;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uint64_t offset;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ext_idx = sync_ctx->mbox->mbox_ext_idx;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mails = array_get(&sync_ctx->mails, &count);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen for (i = 0; i < count; i++) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mails[i].idx_seq == 0 ||
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen (mails[i].flags & MBOX_EXPUNGED) != 0)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen continue;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen offset = mails[i].from_offset;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_index_update_ext(sync_ctx->t, mails[i].idx_seq,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ext_idx, &offset, NULL);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen}
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainenstatic void mbox_sync_handle_expunge(struct mbox_sync_mail_context *mail_ctx)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen{
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen mail_ctx->mail.flags = MBOX_EXPUNGED;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen mail_ctx->mail.offset = mail_ctx->mail.from_offset;
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainen mail_ctx->mail.space =
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mail_ctx->body_offset - mail_ctx->mail.from_offset +
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen mail_ctx->mail.body_size;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen mail_ctx->mail.body_size = 0;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (mail_ctx->sync_ctx->seq == 1) {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen /* expunging first message, fix space to contain next
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen message's \n header too since it will be removed. */
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen mail_ctx->mail.space++;
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen /* uid-last offset is invalid now */
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen mail_ctx->sync_ctx->base_uid_last_offset = 0;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen }
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
ab3c1eab9ca13916358a9e8b12df8212fefb7dbfTimo Sirainen mail_ctx->sync_ctx->expunged_space += mail_ctx->mail.space;
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen}
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
3021a062b16ff0138408be6107d6bcd0ced280b9Timo Sirainenstatic int mbox_sync_handle_header(struct mbox_sync_mail_context *mail_ctx)
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen{
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen off_t move_diff;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen int ret;
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainen
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainen if (sync_ctx->expunged_space > 0 && sync_ctx->need_space_seq == 0) {
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen /* move the header backwards to fill expunged space */
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen move_diff = -sync_ctx->expunged_space;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen if (sync_ctx->dest_first_mail) {
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen /* we're moving this mail to beginning of file.
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen skip the initial \n (it's already counted in
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen expunged_space) */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_ctx->mail.from_offset++;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen }
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* read the From-line before rewriting overwrites it */
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen if (mbox_read_from_line(mail_ctx) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_sync_update_header(mail_ctx);
1276e0340fe29495b6694dc7508f070cf6fca1cfTimo Sirainen ret = mbox_sync_try_rewrite(mail_ctx, move_diff);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ret < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen if (ret > 0) {
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen /* rewrite successful, write From-line to
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen new location */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.from_offset += move_diff;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen mail_ctx->mail.offset += move_diff;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mbox_write_from_line(mail_ctx) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen } else {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->dest_first_mail) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* didn't have enough space, move the offset
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen back so seeking into it doesn't fail */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.from_offset--;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else if (mail_ctx->need_rewrite ||
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen array_count(&sync_ctx->syncs) != 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_sync_update_header(mail_ctx);
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen if (sync_ctx->delay_writes) {
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen /* mark it dirty and do it later */
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen mail_ctx->dirty = TRUE;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen return 0;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen }
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen if ((ret = mbox_sync_try_rewrite(mail_ctx, 0)) < 0)
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* nothing to do */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen if (ret == 0 && sync_ctx->need_space_seq == 0) {
60d3fa9883237e896a8704275b6116fa46f7ffdaTimo Sirainen /* first mail with no space to write it */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->need_space_seq = sync_ctx->seq;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen sync_ctx->space_diff = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->expunged_space > 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* create dummy message to describe the expunged data */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mbox_sync_mail mail;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainen memset(&mail, 0, sizeof(mail));
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail.flags = MBOX_EXPUNGED;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen mail.offset = mail.from_offset =
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen (sync_ctx->dest_first_mail ? 1 : 0) +
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen mail_ctx->mail.from_offset -
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen sync_ctx->expunged_space;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen mail.space = sync_ctx->expunged_space;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen sync_ctx->space_diff = sync_ctx->expunged_space;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->expunged_space = 0;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen i_assert(sync_ctx->space_diff < -mail_ctx->mail.space);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen sync_ctx->need_space_seq--;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen array_append(&sync_ctx->mails, &mail, 1);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen return 0;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen}
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenmbox_sync_handle_missing_space(struct mbox_sync_mail_context *mail_ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uoff_t end_offset, move_diff, extra_space, needed_space;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen uint32_t last_seq;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(mail_ctx->mail.uid == 0 || mail_ctx->mail.space > 0 ||
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.offset == mail_ctx->hdr_offset);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen array_append(&sync_ctx->mails, &mail_ctx->mail, 1);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->space_diff += mail_ctx->mail.space;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->space_diff < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->expunged_space > 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(sync_ctx->expunged_space ==
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.space);
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen sync_ctx->expunged_space = 0;
36816b5af1472ae76a1909ae3cf29fd614b2ebfcTimo Sirainen }
829c036d4ddfbd9ea49bd8a7c54e3057177d346eTimo Sirainen return 0;
36816b5af1472ae76a1909ae3cf29fd614b2ebfcTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* we have enough space now */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mail_ctx->mail.uid == 0) {
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen /* this message was expunged. fill more or less of the space.
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen space_diff now consists of a negative "bytes needed" sum,
8d5991f5c4a8840bf1ea754093dbec505564ab78Timo Sirainen plus the expunged space of this message. so it contains how
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen many bytes of _extra_ space we have. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(mail_ctx->mail.space >= sync_ctx->space_diff);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen extra_space = MBOX_HEADER_PADDING *
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen (sync_ctx->seq - sync_ctx->need_space_seq + 1);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen needed_space = mail_ctx->mail.space - sync_ctx->space_diff;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if ((uoff_t)sync_ctx->space_diff > needed_space + extra_space) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* don't waste too much on padding */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen move_diff = needed_space + extra_space;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->expunged_space =
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.space - move_diff;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen move_diff = mail_ctx->mail.space;
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen extra_space = sync_ctx->space_diff;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen sync_ctx->expunged_space = 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
2cb565cd978aafd5714792b5161889986d49e431Timo Sirainen last_seq = sync_ctx->seq - 1;
2cb565cd978aafd5714792b5161889986d49e431Timo Sirainen array_delete(&sync_ctx->mails,
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen array_count(&sync_ctx->mails) - 1, 1);
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen end_offset = mail_ctx->mail.from_offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else {
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen /* this message gave enough space from headers. rewriting stops
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen at the end of this message's headers. */
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen sync_ctx->expunged_space = 0;
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen last_seq = sync_ctx->seq;
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen end_offset = mail_ctx->body_offset;
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen move_diff = 0;
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen extra_space = sync_ctx->space_diff;
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen if (mbox_sync_rewrite(sync_ctx, end_offset, move_diff, extra_space,
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen sync_ctx->need_space_seq, last_seq) < 0)
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen return -1;
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen update_from_offsets(sync_ctx);
8d5991f5c4a8840bf1ea754093dbec505564ab78Timo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen /* mail_ctx may contain wrong data after rewrite, so make sure we
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen don't try to access it */
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen memset(mail_ctx, 0, sizeof(*mail_ctx));
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen sync_ctx->need_space_seq = 0;
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen sync_ctx->space_diff = 0;
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen array_clear(&sync_ctx->mails);
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen return 0;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen}
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen
c9a03c8a03a782488981f81bd7c6b5e01ff55f06Timo Sirainenstatic int
829c036d4ddfbd9ea49bd8a7c54e3057177d346eTimo Sirainenmbox_sync_seek_to_seq(struct mbox_sync_context *sync_ctx, uint32_t seq)
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen{
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen struct mbox_mailbox *mbox = sync_ctx->mbox;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen uoff_t old_offset;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen uint32_t uid;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen int ret, deleted;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen if (seq == 0) {
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen if (istream_raw_mbox_seek(mbox->mbox_stream, 0) < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_storage_set_error(STORAGE(mbox->storage),
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen "Mailbox isn't a valid mbox file");
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen return -1;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen }
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen seq++;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen } else {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen old_offset = istream_raw_mbox_get_start_offset(sync_ctx->input);
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen ret = mbox_file_seek(mbox, sync_ctx->sync_view, seq, &deleted);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen if (ret < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen if (ret == 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (istream_raw_mbox_seek(mbox->mbox_stream,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen old_offset) < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_storage_set_critical(
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen STORAGE(mbox->storage),
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen "Error seeking back to original "
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen "offset %s in mbox file %s",
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen dec2str(old_offset), mbox->path);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (seq <= 1)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen uid = 0;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen else if (mail_index_lookup_uid(sync_ctx->sync_view, seq-1, &uid) < 0) {
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen mail_storage_set_index_error(&mbox->ibox);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return -1;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->prev_msg_uid = uid;
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* set to -1, since it's always increased later */
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen sync_ctx->seq = seq-1;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (sync_ctx->seq == 0 &&
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen istream_raw_mbox_get_start_offset(sync_ctx->input) != 0) {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* this mbox has pseudo mail which contains the X-IMAP header */
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen sync_ctx->seq++;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
6a87059fc7d4e919aa55d0b208ff20708e13e2d7Timo Sirainen sync_ctx->idx_seq = seq;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen sync_ctx->dest_first_mail = sync_ctx->seq == 0;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen (void)istream_raw_mbox_get_body_offset(sync_ctx->input);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return 1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen}
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic int
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainenmbox_sync_seek_to_uid(struct mbox_sync_context *sync_ctx, uint32_t uid)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen{
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen struct mail_index_view *sync_view = sync_ctx->sync_view;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen uint32_t seq1, seq2;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen const struct stat *st;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (mail_index_lookup_uid_range(sync_view, uid, (uint32_t)-1,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen &seq1, &seq2) < 0) {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen mail_storage_set_index_error(&sync_ctx->mbox->ibox);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return -1;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen }
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen if (seq1 == 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* doesn't exist anymore, seek to end of file */
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen st = i_stream_stat(sync_ctx->mbox->mbox_file_stream);
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen if (st == NULL) {
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen "i_stream_stat()");
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen return -1;
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (istream_raw_mbox_seek(sync_ctx->mbox->mbox_stream,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen st->st_size) < 0) {
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen mail_storage_set_critical(
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen STORAGE(sync_ctx->mbox->storage),
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen "Error seeking to end of mbox file %s",
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen sync_ctx->mbox->path);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return -1;
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen }
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen sync_ctx->idx_seq =
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen mail_index_view_get_messages_count(sync_view) + 1;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return 1;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return mbox_sync_seek_to_seq(sync_ctx, seq1);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen}
a10e5606a9e93f49cf13b3a35c8dc3f5d6ab5909Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenstatic int mbox_sync_partial_seek_next(struct mbox_sync_context *sync_ctx,
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen uint32_t next_uid, int *partial,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen int *skipped_mails)
a10e5606a9e93f49cf13b3a35c8dc3f5d6ab5909Timo Sirainen{
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen uint32_t messages_count;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen int ret;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* delete sync records up to next message. so if there's still
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen something left in array, it means the next message needs modifying */
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen mbox_sync_array_delete_to(&sync_ctx->syncs, next_uid);
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen if (array_count(&sync_ctx->syncs) > 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return 1;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (sync_ctx->sync_rec.uid1 != 0) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen /* we can skip forward to next record which needs updating. */
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (sync_ctx->sync_rec.uid1 != next_uid) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen *skipped_mails = TRUE;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen next_uid = sync_ctx->sync_rec.uid1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen ret = mbox_sync_seek_to_uid(sync_ctx, next_uid);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen } else {
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen /* if there's no sync records left, we can stop. except if
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen this is a dirty sync, check if there are new messages. */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (!sync_ctx->mbox->mbox_sync_dirty)
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen return 0;
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen
a10e5606a9e93f49cf13b3a35c8dc3f5d6ab5909Timo Sirainen messages_count =
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen mail_index_view_get_messages_count(sync_ctx->sync_view);
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen if (sync_ctx->seq + 1 != messages_count) {
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen ret = mbox_sync_seek_to_seq(sync_ctx, messages_count);
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen *skipped_mails = TRUE;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen } else {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen ret = 1;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen *partial = FALSE;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ret == 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* seek failed because the offset is dirty. just ignore and
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen continue from where we are now. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen *partial = FALSE;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ret = 1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return ret;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen}
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenstatic int mbox_sync_loop(struct mbox_sync_context *sync_ctx,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen struct mbox_sync_mail_context *mail_ctx,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen int partial)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen{
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen const struct mail_index_record *rec;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uint32_t uid, messages_count;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uoff_t offset;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen int ret, expunged, skipped_mails;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen messages_count =
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_index_view_get_messages_count(sync_ctx->sync_view);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* always start from first message so we can read X-IMAP or
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen X-IMAPbase header */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ret = mbox_sync_seek_to_seq(sync_ctx, 0);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (ret <= 0)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return ret;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen skipped_mails = FALSE;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen while ((ret = mbox_sync_read_next_mail(sync_ctx, mail_ctx)) > 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uid = mail_ctx->mail.uid;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (mail_ctx->seq == 1 && sync_ctx->base_uid_validity != 0 &&
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->hdr->uid_validity != 0 &&
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen sync_ctx->base_uid_validity !=
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->hdr->uid_validity) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_storage_set_critical(
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen STORAGE(sync_ctx->mbox->storage),
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen "UIDVALIDITY changed (%u -> %u) "
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen "in mbox file %s",
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen sync_ctx->hdr->uid_validity,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->base_uid_validity,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->mbox->path);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_index_mark_corrupted(sync_ctx->mbox->ibox.index);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (mail_ctx->uid_broken && partial) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* UID ordering problems, resync everything to make
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sure we get everything right */
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen return 0;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (mail_ctx->pseudo)
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen uid = 0;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen rec = NULL; ret = 1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (uid != 0) {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen ret = mbox_sync_read_index_rec(sync_ctx, uid, &rec);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (ret < 0)
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ret == 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* UID found but it's broken */
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen uid = 0;
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen } else if (uid == 0 &&
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen !mail_ctx->pseudo &&
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen (sync_ctx->delay_writes ||
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->idx_seq <= messages_count)) {
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen /* If we can't use/store X-UID header, use MD5 sum.
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen Also check for existing MD5 sums when we're actually
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen able to write X-UIDs. */
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen sync_ctx->mbox->mbox_save_md5 = TRUE;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox_sync_find_index_md5(sync_ctx,
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen mail_ctx->hdr_md5_sum,
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen &rec) < 0)
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen return -1;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen if (rec != NULL)
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen uid = mail_ctx->mail.uid = rec->uid;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen }
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen if (rec == NULL) {
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen /* from now on, don't skip anything */
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen partial = FALSE;
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen }
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen if (!mail_ctx->pseudo) {
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen /* get all sync records related to this message */
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen if (mbox_sync_read_index_syncs(sync_ctx, uid,
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen &expunged) < 0)
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen return -1;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen } else {
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen expunged = FALSE;
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen }
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen if (uid == 0 && !mail_ctx->pseudo) {
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen /* missing/broken X-UID. all the rest of the mails
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen need new UIDs. */
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen while (sync_ctx->idx_seq <= messages_count) {
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen mail_index_expunge(sync_ctx->t,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen sync_ctx->idx_seq++);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mail_ctx->need_rewrite = TRUE;
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen mail_ctx->mail.uid = sync_ctx->next_uid++;
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen sync_ctx->prev_msg_uid = mail_ctx->mail.uid;
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen }
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen mail_ctx->mail.idx_seq = sync_ctx->idx_seq;
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen if (!expunged) {
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen if (mbox_sync_handle_header(mail_ctx) < 0)
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen return -1;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen sync_ctx->dest_first_mail = FALSE;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen } else {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mail_ctx->mail.uid = 0;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mbox_sync_handle_expunge(mail_ctx);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (!mail_ctx->pseudo) {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (!expunged) {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (mbox_sync_update_index(mail_ctx, rec) < 0)
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen return -1;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen sync_ctx->idx_seq++;
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen }
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen istream_raw_mbox_next(sync_ctx->input,
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen mail_ctx->mail.body_size);
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen offset = istream_raw_mbox_get_start_offset(sync_ctx->input);
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen if (sync_ctx->need_space_seq != 0) {
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen if (mbox_sync_handle_missing_space(mail_ctx) < 0)
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen return -1;
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen if (mbox_sync_seek(sync_ctx, offset) < 0)
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen return -1;
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen } else if (sync_ctx->expunged_space > 0) {
e9d68b41c007f0e545de361f8012f6f231bfec8bTimo Sirainen if (!expunged) {
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen /* move the body */
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen if (mbox_move(sync_ctx,
e9d68b41c007f0e545de361f8012f6f231bfec8bTimo Sirainen mail_ctx->body_offset -
e9d68b41c007f0e545de361f8012f6f231bfec8bTimo Sirainen sync_ctx->expunged_space,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mail_ctx->body_offset,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen mail_ctx->mail.body_size) < 0)
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen return -1;
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen if (mbox_sync_seek(sync_ctx, offset) < 0)
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen return -1;
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen }
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen } else if (partial) {
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen ret = mbox_sync_partial_seek_next(sync_ctx, uid + 1,
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen &partial,
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen &skipped_mails);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (ret <= 0) {
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (ret < 0)
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen return -1;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen break;
d0e5f8252516c4d4df2fbcdae4d37f9e5f931199Timo Sirainen }
d0e5f8252516c4d4df2fbcdae4d37f9e5f931199Timo Sirainen }
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen }
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen if (istream_raw_mbox_is_eof(sync_ctx->input)) {
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen /* rest of the messages in index don't exist -> expunge them */
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen while (sync_ctx->idx_seq <= messages_count)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_index_expunge(sync_ctx->t, sync_ctx->idx_seq++);
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen if (!skipped_mails)
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen sync_ctx->mbox->mbox_sync_dirty = FALSE;
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen return 1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainenstatic int mbox_write_pseudo(struct mbox_sync_context *sync_ctx)
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen{
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen string_t *str;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen unsigned int uid_validity;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(sync_ctx->write_fd != -1);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uid_validity = sync_ctx->base_uid_validity != 0 ?
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->base_uid_validity : sync_ctx->hdr->uid_validity;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(uid_validity != 0);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen str = t_str_new(1024);
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen str_printfa(str, "%sDate: %s\n"
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen "From: Mail System Internal Data <MAILER-DAEMON@%s>\n"
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen "Subject: DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA"
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen "\nMessage-ID: <%s@%s>\n"
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen "X-IMAP: %u %010u\n"
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen "Status: RO\n"
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen "\n"
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen PSEUDO_MESSAGE_BODY
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen "\n",
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen mbox_from_create("MAILER_DAEMON", ioloop_time),
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen message_date_create(ioloop_time),
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen my_hostname, dec2str(ioloop_time), my_hostname,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen uid_validity, sync_ctx->next_uid-1);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (pwrite_full(sync_ctx->write_fd,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen str_data(str), str_len(str), 0) < 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (!ENOSPACE(errno)) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen "pwrite_full()");
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* out of disk space, truncate to empty */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)ftruncate(sync_ctx->write_fd, 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen sync_ctx->base_uid_last_offset = 0; /* don't bother calculating */
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen sync_ctx->base_uid_last = sync_ctx->next_uid-1;
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen return 0;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen}
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenstatic int mbox_sync_handle_eof_updates(struct mbox_sync_context *sync_ctx,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct mbox_sync_mail_context *mail_ctx)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const struct stat *st;
3cfff0ca01961d885bdbd6ef08d761880116af07Timo Sirainen uoff_t file_size, offset, padding, trailer_size;
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (!istream_raw_mbox_is_eof(sync_ctx->input)) {
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen i_assert(sync_ctx->need_space_seq == 0);
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen i_assert(sync_ctx->expunged_space == 0);
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen return 0;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen }
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen st = i_stream_stat(sync_ctx->file_input);
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen if (st == NULL) {
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "i_stream_stat()");
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen return -1;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen }
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen file_size = st->st_size;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen i_assert(file_size >= sync_ctx->file_input->v_offset);
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen trailer_size = file_size - sync_ctx->file_input->v_offset;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen i_assert(trailer_size <= 1);
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (sync_ctx->need_space_seq != 0) {
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainen i_assert(sync_ctx->write_fd != -1);
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen i_assert(sync_ctx->space_diff < 0);
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen padding = MBOX_HEADER_PADDING *
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen (sync_ctx->seq - sync_ctx->need_space_seq + 1);
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen sync_ctx->space_diff -= padding;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen i_assert(sync_ctx->expunged_space <= -sync_ctx->space_diff);
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->space_diff += sync_ctx->expunged_space;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen sync_ctx->expunged_space = 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (mail_ctx->have_eoh && !mail_ctx->updated)
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen str_append_c(mail_ctx->header, '\n');
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen i_assert(sync_ctx->space_diff < 0);
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (file_set_size(sync_ctx->write_fd,
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen file_size + -sync_ctx->space_diff) < 0) {
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen "file_set_size()");
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen return -1;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen }
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen i_stream_sync(sync_ctx->input);
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mbox_sync_rewrite(sync_ctx, file_size,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen -sync_ctx->space_diff, padding,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->need_space_seq,
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->seq) < 0)
f5b919e9b07dfd9d2401b998ef8759e5f0312719Timo Sirainen return -1;
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen update_from_offsets(sync_ctx);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen sync_ctx->need_space_seq = 0;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen array_clear(&sync_ctx->mails);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen if (sync_ctx->expunged_space > 0) {
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen i_assert(sync_ctx->write_fd != -1);
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen /* copy trailer, then truncate the file */
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen st = i_stream_stat(sync_ctx->file_input);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (st == NULL) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen "i_stream_stat()");
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen return -1;
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen }
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen file_size = st->st_size;
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen if (file_size == (uoff_t)sync_ctx->expunged_space) {
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen /* everything deleted, the trailer_size still contains
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen the \n trailer though */
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen trailer_size = 0;
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen }
5edfc0f1c3c55e906d8316d9cdeaa3b0c7000c19Timo Sirainen
686cb2418d4daa7bc747d3551783c1895e7c41b9Timo Sirainen i_assert(file_size >= sync_ctx->expunged_space + trailer_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen offset = file_size - sync_ctx->expunged_space - trailer_size;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(offset == 0 || offset > 31);
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (mbox_move(sync_ctx, offset,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen offset + sync_ctx->expunged_space,
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen trailer_size) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen if (ftruncate(sync_ctx->write_fd,
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen offset + trailer_size) < 0) {
f5b919e9b07dfd9d2401b998ef8759e5f0312719Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "ftruncate()");
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
f5b919e9b07dfd9d2401b998ef8759e5f0312719Timo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (offset == 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mbox_write_pseudo(sync_ctx) < 0)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen return -1;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen }
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->expunged_space = 0;
f5b919e9b07dfd9d2401b998ef8759e5f0312719Timo Sirainen i_stream_sync(sync_ctx->input);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainenstatic int mbox_sync_update_index_header(struct mbox_sync_context *sync_ctx)
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen{
f5b919e9b07dfd9d2401b998ef8759e5f0312719Timo Sirainen const struct stat *st;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen st = i_stream_stat(sync_ctx->file_input);
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen if (st == NULL) {
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "i_stream_stat()");
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return -1;
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen }
99be58a447b69d62cbd9e764000a06226b9c9c89Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen /* only reason not to have UID validity at this point is if the file
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen is entirely empty. In that case just make up a new one if needed. */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen i_assert(sync_ctx->base_uid_validity != 0 || st->st_size == 0);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->base_uid_validity != sync_ctx->hdr->uid_validity ||
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->base_uid_validity == 0) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (sync_ctx->base_uid_validity == 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->base_uid_validity =
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->hdr->uid_validity != 0 ?
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->hdr->uid_validity :
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen (unsigned int)ioloop_time;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen }
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen mail_index_update_header(sync_ctx->t,
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen offsetof(struct mail_index_header, uid_validity),
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen &sync_ctx->base_uid_validity,
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen sizeof(sync_ctx->base_uid_validity), TRUE);
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen }
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen if (istream_raw_mbox_is_eof(sync_ctx->input) &&
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen sync_ctx->next_uid != sync_ctx->hdr->next_uid) {
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen i_assert(sync_ctx->next_uid != 0);
5edfc0f1c3c55e906d8316d9cdeaa3b0c7000c19Timo Sirainen mail_index_update_header(sync_ctx->t,
5edfc0f1c3c55e906d8316d9cdeaa3b0c7000c19Timo Sirainen offsetof(struct mail_index_header, next_uid),
eb276c05bf6b0a383c772d61e31cf09a8dbd36c7Timo Sirainen &sync_ctx->next_uid, sizeof(sync_ctx->next_uid), FALSE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if ((uint32_t)st->st_mtime != sync_ctx->hdr->sync_stamp &&
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen !sync_ctx->mbox->mbox_sync_dirty) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uint32_t sync_stamp = st->st_mtime;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen mail_index_update_header(sync_ctx->t,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen offsetof(struct mail_index_header, sync_stamp),
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen &sync_stamp, sizeof(sync_stamp), TRUE);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if ((uint64_t)st->st_size != sync_ctx->hdr->sync_size &&
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainen !sync_ctx->mbox->mbox_sync_dirty) {
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen uint64_t sync_size = st->st_size;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen mail_index_update_header(sync_ctx->t,
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen offsetof(struct mail_index_header, sync_size),
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen &sync_size, sizeof(sync_size), TRUE);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->mbox->mbox_dirty_stamp = st->st_mtime;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->mbox->mbox_dirty_size = st->st_size;
af6d4a24cb6d18e50d172540cf49b1448a6f9872Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainenstatic void mbox_sync_restart(struct mbox_sync_context *sync_ctx)
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen{
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->base_uid_validity = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->base_uid_last = 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen sync_ctx->base_uid_last_offset = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen array_clear(&sync_ctx->mails);
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen array_clear(&sync_ctx->syncs);
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen memset(&sync_ctx->sync_rec, 0, sizeof(sync_ctx->sync_rec));
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen mail_index_sync_reset(sync_ctx->index_sync_ctx);
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen sync_ctx->prev_msg_uid = 0;
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen sync_ctx->next_uid = sync_ctx->hdr->next_uid;
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen sync_ctx->idx_next_uid = sync_ctx->hdr->next_uid;
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen sync_ctx->seq = 0;
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen sync_ctx->idx_seq = 1;
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen sync_ctx->need_space_seq = 0;
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen sync_ctx->expunged_space = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->space_diff = 0;
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->dest_first_mail = TRUE;
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen}
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainenstatic int mbox_sync_do(struct mbox_sync_context *sync_ctx,
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen enum mbox_sync_flags flags)
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen{
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen struct mbox_sync_mail_context mail_ctx;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen const struct stat *st;
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen int ret, partial;
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen st = i_stream_stat(sync_ctx->file_input);
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen if (st == NULL) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen "i_stream_stat()");
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen return -1;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if ((flags & MBOX_SYNC_FORCE_SYNC) != 0) {
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen /* forcing a full sync. assume file has changed. */
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen partial = FALSE;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen sync_ctx->mbox->mbox_sync_dirty = TRUE;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen } else if ((uint32_t)st->st_mtime == sync_ctx->hdr->sync_stamp &&
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen (uint64_t)st->st_size == sync_ctx->hdr->sync_size) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen /* file is fully synced */
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen partial = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->mbox->mbox_sync_dirty = FALSE;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen } else if ((flags & MBOX_SYNC_UNDIRTY) != 0 ||
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen (uint64_t)st->st_size == sync_ctx->hdr->sync_size) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* we want to do full syncing. always do this if
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen file size hasn't changed but timestamp has. it most
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen likely means that someone had modified some header
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen and we probably want to know about it */
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen partial = FALSE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->mbox->mbox_sync_dirty = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* see if we can delay syncing the whole file.
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen normally we only notice expunges and appends
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen in partial syncing. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen partial = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->mbox->mbox_sync_dirty = TRUE;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen mbox_sync_restart(sync_ctx);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen ret = mbox_sync_loop(sync_ctx, &mail_ctx, partial);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (ret <= 0) {
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen if (ret < 0)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen /* partial syncing didn't work, do it again */
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen i_assert(sync_ctx->mbox->mbox_sync_dirty);
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen mbox_sync_restart(sync_ctx);
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen mail_index_transaction_rollback(sync_ctx->t);
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen sync_ctx->t = mail_index_transaction_begin(sync_ctx->sync_view,
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen FALSE, TRUE);
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen
325f4573edfa5b751832ac01023f3e81be992bf0Timo Sirainen ret = mbox_sync_loop(sync_ctx, &mail_ctx, FALSE);
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainen if (ret <= 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(ret != 0);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mbox_sync_handle_eof_updates(sync_ctx, &mail_ctx) < 0)
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen return -1;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* only syncs left should be just appends (and their updates)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen which weren't synced yet for some reason (crash). we'll just
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ignore them, as we've overwritten them above. */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen array_clear(&sync_ctx->syncs);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen memset(&sync_ctx->sync_rec, 0, sizeof(sync_ctx->sync_rec));
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (mbox_sync_update_index_header(sync_ctx) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen return 0;
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen}
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainenint mbox_sync_has_changed(struct mbox_mailbox *mbox, int leave_dirty)
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen{
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen const struct mail_index_header *hdr;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen const struct stat *st;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct stat statbuf;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (mbox->mbox_file_stream != NULL && mbox->mbox_fd == -1) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* read-only stream */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen st = i_stream_stat(mbox->mbox_file_stream);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (st == NULL) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mbox_set_syscall_error(mbox, "i_stream_stat()");
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen } else {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (stat(mbox->path, &statbuf) < 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mbox_set_syscall_error(mbox, "stat()");
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen st = &statbuf;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen hdr = mail_index_get_header(mbox->ibox.view);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if ((uint32_t)st->st_mtime == hdr->sync_stamp &&
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen (uint64_t)st->st_size == hdr->sync_size) {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* fully synced */
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen mbox->mbox_sync_dirty = FALSE;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen if (!mbox->mbox_sync_dirty || !leave_dirty)
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen return 1;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen
7c95b03620a03a43dd72d39608cea5fc77393ad6Timo Sirainen return st->st_mtime != mbox->mbox_dirty_stamp ||
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen st->st_size != mbox->mbox_dirty_size;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen}
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainenint mbox_sync(struct mbox_mailbox *mbox, enum mbox_sync_flags flags)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen struct mail_index_sync_ctx *index_sync_ctx;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen struct mail_index_view *sync_view;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mbox_sync_context sync_ctx;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uint32_t seq;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uoff_t offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen unsigned int lock_id = 0;
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen int ret, changed;
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen mbox->ibox.sync_last_check = ioloop_time;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen if (!mbox->mbox_do_dirty_syncs)
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen flags |= MBOX_SYNC_UNDIRTY;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if ((flags & MBOX_SYNC_LOCK_READING) != 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mbox_lock(mbox, F_RDLCK, &lock_id) <= 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if ((flags & MBOX_SYNC_HEADER) != 0 ||
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen (flags & MBOX_SYNC_FORCE_SYNC) != 0)
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen changed = 1;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen else {
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen int leave_dirty = (flags & MBOX_SYNC_UNDIRTY) == 0;
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen if ((changed = mbox_sync_has_changed(mbox, leave_dirty)) < 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if ((flags & MBOX_SYNC_LOCK_READING) != 0)
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen (void)mbox_unlock(mbox, lock_id);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return -1;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen if ((flags & MBOX_SYNC_LOCK_READING) != 0) {
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen /* we just want to lock it for reading. if mbox hasn't been
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen modified don't do any syncing. */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (!changed)
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen return 0;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen /* have to sync to make sure offsets have stayed the same */
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen (void)mbox_unlock(mbox, lock_id);
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen lock_id = 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen /* reopen input stream to make sure it has nothing buffered */
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen mbox_file_close_stream(mbox);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen__again:
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (changed) {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* we're most likely modifying the mbox while syncing, just
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen lock it for writing immediately. the mbox must be locked
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen before index syncing is started to avoid deadlocks, so we
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen don't have much choice either (well, easy ones anyway). */
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen int lock_type = mbox->mbox_readonly ? F_RDLCK : F_WRLCK;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox_lock(mbox, lock_type, &lock_id) <= 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return -1;
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen }
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if ((flags & MBOX_SYNC_LAST_COMMIT) != 0) {
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen seq = mbox->ibox.commit_log_file_seq;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen offset = mbox->ibox.commit_log_file_offset;
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen } else {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen seq = (uint32_t)-1;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen offset = (uoff_t)-1;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen ret = mail_index_sync_begin(mbox->ibox.index, &index_sync_ctx,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen &sync_view, seq, offset,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen !mbox->ibox.keep_recent,
6597506f9317f3be644e708c9153dacaeeece84cTimo Sirainen (flags & MBOX_SYNC_REWRITE) != 0);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (ret <= 0) {
d252f81a2ff1bdd5439f9d2b3df715b70a4bcd3dTimo Sirainen if (ret < 0)
d252f81a2ff1bdd5439f9d2b3df715b70a4bcd3dTimo Sirainen mail_storage_set_index_error(&mbox->ibox);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (lock_id != 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen (void)mbox_unlock(mbox, lock_id);
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen return ret;
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen }
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen if (!changed && !mail_index_sync_have_more(index_sync_ctx)) {
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen /* nothing to do */
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen if (lock_id != 0)
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen (void)mbox_unlock(mbox, lock_id);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* index may need to do internal syncing though, so commit
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen instead of rollbacking. */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mail_index_sync_commit(index_sync_ctx) < 0) {
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen mail_storage_set_index_error(&mbox->ibox);
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen return -1;
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen }
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen return 0;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen if (lock_id == 0) {
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen /* ok, we have something to do but no locks. we'll have to
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen restart syncing to avoid deadlocking. */
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen mail_index_sync_rollback(index_sync_ctx);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen changed = 1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen goto __again;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen }
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen if (mbox_file_open_stream(mbox) < 0) {
f2b79667fc7a8f7c2c72cad18bd71d49730e36f6Timo Sirainen mail_index_sync_rollback(index_sync_ctx);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen (void)mbox_unlock(mbox, lock_id);
f2b79667fc7a8f7c2c72cad18bd71d49730e36f6Timo Sirainen return -1;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen }
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen memset(&sync_ctx, 0, sizeof(sync_ctx));
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen sync_ctx.mbox = mbox;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen sync_ctx.hdr = mail_index_get_header(sync_view);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx.from_line = str_new(default_pool, 256);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx.header = str_new(default_pool, 4096);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen sync_ctx.index_sync_ctx = index_sync_ctx;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen sync_ctx.sync_view = sync_view;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen sync_ctx.t = mail_index_transaction_begin(sync_view, FALSE, TRUE);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx.mail_keyword_pool = pool_alloconly_create("keywords", 4096);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen /* make sure we've read the latest keywords in index */
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen (void)mail_index_get_keywords(mbox->ibox.index);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen ARRAY_CREATE(&sync_ctx.mails, default_pool,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen struct mbox_sync_mail, 64);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ARRAY_CREATE(&sync_ctx.syncs, default_pool,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct mail_index_sync_rec, 32);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
757726d9acbd04cf0d0d4be8ce14e11525476a0bTimo Sirainen sync_ctx.file_input = sync_ctx.mbox->mbox_file_stream;
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen sync_ctx.input = sync_ctx.mbox->mbox_stream;
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen sync_ctx.write_fd = sync_ctx.mbox->mbox_readonly ? -1 :
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx.mbox->mbox_fd;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen sync_ctx.flags = flags;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx.delay_writes = sync_ctx.mbox->mbox_readonly ||
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen sync_ctx.mbox->ibox.readonly ||
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen ((flags & MBOX_SYNC_REWRITE) == 0 &&
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen getenv("MBOX_LAZY_WRITES") != NULL);
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen ret = mbox_sync_do(&sync_ctx, flags);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (ret < 0)
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen mail_index_transaction_rollback(sync_ctx.t);
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen else if (mail_index_transaction_commit(sync_ctx.t, &seq, &offset) < 0) {
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen mail_storage_set_index_error(&mbox->ibox);
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen ret = -1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen } else {
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen mbox->ibox.commit_log_file_seq = 0;
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen mbox->ibox.commit_log_file_offset = 0;
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen }
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen sync_ctx.t = NULL;
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen if (ret < 0)
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen mail_index_sync_rollback(index_sync_ctx);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen else if (mail_index_sync_commit(index_sync_ctx) < 0) {
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen mail_storage_set_index_error(&mbox->ibox);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen ret = -1;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen }
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen if (sync_ctx.base_uid_last != sync_ctx.next_uid-1 &&
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ret == 0 && !sync_ctx.delay_writes &&
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen sync_ctx.base_uid_last_offset != 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* Rewrite uid_last in X-IMAPbase header if we've seen it
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen (ie. the file isn't empty) */
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen ret = mbox_rewrite_base_uid_last(&sync_ctx);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (ret == 0 && mbox->mbox_lock_type == F_WRLCK &&
de4288b7369945a31c4001add9445fd0195a358dTimo Sirainen !mbox->mbox_writeonly) {
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen if (fsync(mbox->mbox_fd) < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_set_syscall_error(mbox, "fsync()");
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen ret = -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
7c95b03620a03a43dd72d39608cea5fc77393ad6Timo Sirainen if (lock_id != 0 && mbox->mbox_lock_type != F_RDLCK) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* drop to read lock */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen unsigned int read_lock_id = 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox_lock(mbox, F_RDLCK, &read_lock_id) <= 0)
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen ret = -1;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen else {
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (mbox_unlock(mbox, lock_id) < 0)
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen ret = -1;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen lock_id = read_lock_id;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (lock_id != 0 && (flags & MBOX_SYNC_LOCK_READING) == 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* FIXME: keep the lock MBOX_SYNC_SECS+1 to make sure we
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen notice changes made by others .. and this has to be done
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen even if lock_reading is set.. except if
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_sync_dirty = TRUE */
e5ee67f18b03015c88b579c8c1f17ebe6ce19b76Timo Sirainen if (mbox_unlock(mbox, lock_id) < 0)
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen ret = -1;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen }
de4288b7369945a31c4001add9445fd0195a358dTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen pool_unref(sync_ctx.mail_keyword_pool);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen str_free(sync_ctx.header);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen str_free(sync_ctx.from_line);
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen array_free(&sync_ctx.mails);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen array_free(&sync_ctx.syncs);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return ret;
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen}
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstruct mailbox_sync_context *
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainenmbox_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen{
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)box;
79c9f3069bde51f799a64ca5923d68c9a5bc2ad2Timo Sirainen enum mbox_sync_flags mbox_sync_flags = 0;
79c9f3069bde51f799a64ca5923d68c9a5bc2ad2Timo Sirainen int ret = 0;
79c9f3069bde51f799a64ca5923d68c9a5bc2ad2Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if ((flags & MAILBOX_SYNC_FLAG_FAST) == 0 ||
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox->ibox.sync_last_check + MAILBOX_FULL_SYNC_INTERVAL <=
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen ioloop_time) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if ((flags & MAILBOX_SYNC_FLAG_FULL_READ) != 0 &&
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen !mbox->mbox_very_dirty_syncs)
59ef34eafaf74d31ed88af444b22d1a0738a30aaTimo Sirainen mbox_sync_flags |= MBOX_SYNC_UNDIRTY;
59ef34eafaf74d31ed88af444b22d1a0738a30aaTimo Sirainen if ((flags & MAILBOX_SYNC_FLAG_FULL_WRITE) != 0)
59ef34eafaf74d31ed88af444b22d1a0738a30aaTimo Sirainen mbox_sync_flags |= MBOX_SYNC_REWRITE;
59ef34eafaf74d31ed88af444b22d1a0738a30aaTimo Sirainen ret = mbox_sync(mbox, mbox_sync_flags);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen return index_mailbox_sync_init(box, flags, ret < 0);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen}
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen