mbox-sync.c revision 7e0bb2b365cc38645313a3513fa79bd32d34b63c
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 "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "buffer.h"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen#include "hostpid.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "file-set-size.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "str.h"
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen#include "read-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "write-full.h"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen#include "message-date.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream-raw-mbox.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mbox-storage.h"
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen#include "index-sync-changes.h"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen#include "mbox-from.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mbox-file.h"
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen#include "mbox-lock.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mbox-sync-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen#include <stddef.h>
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen#include <stdlib.h>
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen#include <utime.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <sys/stat.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo 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. */
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainen#define PSEUDO_MESSAGE_BODY \
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen"This text is part of the internal format of your mail folder, and is not\n" \
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen"a real message. It is created automatically by the mail system software.\n" \
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen"If deleted, important folder data will be lost, and it will be re-created\n" \
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen"with the data reset to initial values.\n"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainenvoid mbox_sync_set_critical(struct mbox_sync_context *sync_ctx,
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen const char *fmt, ...)
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen{
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen va_list va;
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen if (sync_ctx->ext_modified) {
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen mail_storage_set_critical(&sync_ctx->mbox->storage->storage,
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen "mbox file %s was modified while we were syncing, "
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen "check your locking settings", sync_ctx->mbox->path);
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen }
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen va_start(va, fmt);
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen mail_storage_set_critical(&sync_ctx->mbox->storage->storage,
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen "%s", t_strdup_vprintf(fmt, va));
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen va_end(va);
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen}
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen
02b79f9c2636da1829eee5b92753602bba8b67edTimo 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) {
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen mbox_sync_set_critical(sync_ctx,
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen "Unexpectedly lost From-line at offset %"PRIuUOFF_T
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen " from mbox file %s", from_offset,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->mbox->path);
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen return -1;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen }
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen return 0;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen}
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainenvoid mbox_sync_file_update_ext_modified(struct mbox_sync_context *sync_ctx)
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen{
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen struct stat st;
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen /* Do this even if ext_modified is already set. Expunging code relies
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen on last_stat being updated. */
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen if (fstat(sync_ctx->write_fd, &st) < 0) {
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "fstat()");
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen return;
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen }
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen if (st.st_size != sync_ctx->last_stat.st_size ||
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen (sync_ctx->last_stat.st_mtime != 0 &&
6288d3611eda14a017dae9927b73f46afb646c96Timo Sirainen !CMP_ST_MTIME(&st, &sync_ctx->last_stat)))
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen sync_ctx->ext_modified = TRUE;
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen sync_ctx->last_stat = st;
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen}
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainenvoid mbox_sync_file_updated(struct mbox_sync_context *sync_ctx, bool dirty)
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen{
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen if (dirty) {
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen /* just mark the stat as dirty. */
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen sync_ctx->last_stat.st_mtime = 0;
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen return;
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen }
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen if (fstat(sync_ctx->write_fd, &sync_ctx->last_stat) < 0)
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "fstat()");
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen i_stream_sync(sync_ctx->input);
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen}
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenmbox_sync_read_next_mail(struct mbox_sync_context *sync_ctx,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mbox_sync_mail_context *mail_ctx)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen{
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainen /* get EOF */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen (void)istream_raw_mbox_get_header_offset(sync_ctx->input);
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen if (istream_raw_mbox_is_eof(sync_ctx->input))
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
2e937ed8585299b2e879a28314902a5f644813d2Timo Sirainen p_clear(sync_ctx->mail_keyword_pool);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen memset(mail_ctx, 0, sizeof(*mail_ctx));
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mail_ctx->sync_ctx = sync_ctx;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->seq = ++sync_ctx->seq;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mail_ctx->header = sync_ctx->header;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen mail_ctx->mail.from_offset =
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen istream_raw_mbox_get_start_offset(sync_ctx->input);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mail_ctx->mail.offset =
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen istream_raw_mbox_get_header_offset(sync_ctx->input);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainen mbox_sync_parse_next_mail(sync_ctx->input, mail_ctx);
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen i_assert(sync_ctx->input->v_offset != mail_ctx->mail.from_offset ||
c3412ddeb9abc13f99d3caf50faf76cd99f7e9d2Timo Sirainen sync_ctx->input->eof);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo 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);
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen i_assert(mail_ctx->mail.body_size < OFF_T_MAX);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen if ((mail_ctx->mail.flags & MAIL_RECENT) != 0 &&
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen !mail_ctx->mail.pseudo) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (!sync_ctx->mbox->ibox.keep_recent) {
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen /* need to add 'O' flag to Status-header */
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen mail_ctx->need_rewrite = TRUE;
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen }
e8a35266a5ceacdfafeeffd6bddae77931ff97ebTimo Sirainen mail_ctx->recent = TRUE;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
b08b33d1f5ce3721dc2d83586c9cb0ca141331fdTimo Sirainenstatic void mbox_sync_read_index_syncs(struct mbox_sync_context *sync_ctx,
b08b33d1f5ce3721dc2d83586c9cb0ca141331fdTimo Sirainen uint32_t uid, bool *sync_expunge_r)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen if (uid == 0 || sync_ctx->index_reset) {
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen /* nothing for this or the future ones */
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen uid = (uint32_t)-1;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen }
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
b08b33d1f5ce3721dc2d83586c9cb0ca141331fdTimo Sirainen index_sync_changes_read(sync_ctx->sync_changes, uid, sync_expunge_r);
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen if (sync_ctx->mbox->mbox_readonly) {
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen /* we can't expunge anything from read-only mboxes */
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen *sync_expunge_r = FALSE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen}
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstatic bool
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;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen bool ret = FALSE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen if (sync_ctx->index_reset) {
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen *rec_r = NULL;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen return TRUE;
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen }
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen messages_count =
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen mail_index_view_get_messages_count(sync_ctx->sync_view);
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen while (sync_ctx->idx_seq <= messages_count) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen rec = mail_index_lookup(sync_ctx->sync_view, sync_ctx->idx_seq);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo 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);
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen sync_ctx->idx_seq++;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen rec = NULL;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen if (rec == NULL && uid < sync_ctx->idx_next_uid) {
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen /* this UID was already in index and it was expunged */
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen mbox_sync_set_critical(sync_ctx,
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen "mbox sync: Expunged message reappeared in mailbox %s "
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen "(UID %u < %u, seq=%u, idx_msgs=%u)",
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen sync_ctx->mbox->path, uid, sync_ctx->idx_next_uid,
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen sync_ctx->seq, messages_count);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen ret = FALSE; rec = NULL;
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen } else if (rec != NULL && rec->uid != uid) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* new UID in the middle of the mailbox - shouldn't happen */
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen mbox_sync_set_critical(sync_ctx,
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen "mbox sync: UID inserted in the middle of mailbox %s "
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen "(%u > %u, seq=%u, idx_msgs=%u)", sync_ctx->mbox->path,
2bf7bb14894faf721518e2122a14a2389ef94078Timo Sirainen rec->uid, uid, sync_ctx->seq, messages_count);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen ret = FALSE; rec = NULL;
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen } else {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen ret = TRUE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen *rec_r = rec;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen return ret;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstatic void mbox_sync_find_index_md5(struct mbox_sync_context *sync_ctx,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen unsigned char hdr_md5_sum[],
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen const struct mail_index_record **rec_r)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen{
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen const struct mail_index_record *rec = NULL;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen uint32_t messages_count;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen const void *data;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen if (sync_ctx->index_reset) {
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen *rec_r = NULL;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen return;
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen }
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen messages_count =
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen mail_index_view_get_messages_count(sync_ctx->sync_view);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen while (sync_ctx->idx_seq <= messages_count) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen rec = mail_index_lookup(sync_ctx->sync_view, sync_ctx->idx_seq);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mail_index_lookup_ext(sync_ctx->sync_view,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen sync_ctx->idx_seq,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen sync_ctx->mbox->ibox.md5hdr_ext_idx,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen &data, NULL);
f0f9c8e94abac18f8acd91b9e724c4c32863723aTimo Sirainen if (data != NULL && memcmp(data, hdr_md5_sum, 16) == 0)
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen break;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen /* externally expunged message, remove from index */
7f3be7d885c75cdd77f536929a45bc9764595960Timo 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}
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstatic void
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenmbox_sync_update_from_offset(struct mbox_sync_context *sync_ctx,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mbox_sync_mail *mail,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool nocheck)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen const void *data;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uint64_t offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (!nocheck) {
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen /* see if from_offset needs updating */
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mail_index_lookup_ext(sync_ctx->sync_view, sync_ctx->idx_seq,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen sync_ctx->mbox->mbox_ext_idx,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen &data, NULL);
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen if (data != NULL &&
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen *((const uint64_t *)data) == mail->from_offset)
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen return;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
8af07808ba203f8709e2ff9eaf2291e1c4a4d53dTimo Sirainen offset = mail->from_offset;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen mail_index_update_ext(sync_ctx->t, sync_ctx->idx_seq,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->mbox->mbox_ext_idx, &offset, NULL);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic void
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenmbox_sync_update_index_keywords(struct mbox_sync_mail_context *mail_ctx)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo 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->mbox->ibox.index, NULL) :
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_index_keywords_create_from_indexes(
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen sync_ctx->mbox->ibox.index, &mail_ctx->mail.keywords);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_index_update_keywords(sync_ctx->t, sync_ctx->idx_seq,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen MODIFY_REPLACE, keywords);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen mail_index_keywords_free(&keywords);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstatic void
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainenmbox_sync_update_md5_if_changed(struct mbox_sync_mail_context *mail_ctx)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen{
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen const void *ext_data;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mail_index_lookup_ext(sync_ctx->sync_view, sync_ctx->idx_seq,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen sync_ctx->mbox->ibox.md5hdr_ext_idx,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen &ext_data, NULL);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen if (ext_data == NULL ||
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen memcmp(mail_ctx->hdr_md5_sum, ext_data, 16) != 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 }
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen}
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstatic void mbox_sync_update_index(struct mbox_sync_mail_context *mail_ctx,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen const struct mail_index_record *rec)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
33d63688ed8b26dc333e3c2edbfb2fe6e412604dTimo Sirainen struct mbox_sync_mail *mail = &mail_ctx->mail;
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen struct mailbox *box = &sync_ctx->mbox->ibox.box;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen uint8_t mbox_flags;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen mbox_flags = mail->flags & MAIL_FLAGS_NONRECENT;
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen if (mail_ctx->dirty)
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen mbox_flags |= MAIL_INDEX_MAIL_FLAG_DIRTY;
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen else if (!sync_ctx->delay_writes)
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen mbox_flags &= ~MAIL_INDEX_MAIL_FLAG_DIRTY;
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (rec == NULL) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* new message */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_index_append(sync_ctx->t, mail->uid, &sync_ctx->idx_seq);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_index_update_flags(sync_ctx->t, sync_ctx->idx_seq,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen MODIFY_REPLACE, mbox_flags);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mbox_sync_update_index_keywords(mail_ctx);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (sync_ctx->mbox->mbox_save_md5 != 0) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen mail_index_update_ext(sync_ctx->t, sync_ctx->idx_seq,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->mbox->ibox.md5hdr_ext_idx,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mail_ctx->hdr_md5_sum, NULL);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else {
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen /* see if we need to update flags in index file. the flags in
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen sync records are automatically applied to rec->flags at the
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen end of index syncing, so calculate those new flags first */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mbox_sync_mail idx_mail;
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen enum mailbox_sync_type sync_type;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen memset(&idx_mail, 0, sizeof(idx_mail));
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen idx_mail.flags = rec->flags & ~MAIL_RECENT;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* get old keywords */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen t_push();
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen t_array_init(&idx_mail.keywords, 32);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mail_index_lookup_keywords(sync_ctx->sync_view,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen sync_ctx->idx_seq,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen &idx_mail.keywords);
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen index_sync_changes_apply(sync_ctx->sync_changes,
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen sync_ctx->mail_keyword_pool,
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen &idx_mail.flags, &idx_mail.keywords,
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen &sync_type);
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen if (sync_type != 0 && box->v.sync_notify != NULL)
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen box->v.sync_notify(box, rec->uid, sync_type);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if ((idx_mail.flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen /* flags are dirty. ignore whatever was in the mbox,
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen but update dirty flag state if needed. */
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen mbox_flags &= ~MAIL_INDEX_MAIL_FLAG_DIRTY;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen mbox_flags |=
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen idx_mail.flags & ~MAIL_INDEX_MAIL_FLAG_DIRTY;
844adc2ea94a10ef81d1ceac9a87b877c20de623Timo Sirainen if (sync_ctx->delay_writes)
844adc2ea94a10ef81d1ceac9a87b877c20de623Timo Sirainen mbox_flags |= MAIL_INDEX_MAIL_FLAG_DIRTY;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if ((idx_mail.flags & ~MAIL_INDEX_MAIL_FLAG_DIRTY) !=
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen (mbox_flags & ~MAIL_INDEX_MAIL_FLAG_DIRTY)) {
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen /* flags other than recent/dirty have changed */
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen mail_index_update_flags(sync_ctx->t, sync_ctx->idx_seq,
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen MODIFY_REPLACE, mbox_flags);
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen } else {
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen if (((idx_mail.flags ^ mbox_flags) &
3f26c5aced2e71efc783f26bb8a7ac53f7504622Timo Sirainen MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen /* dirty flag state changed */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool dirty = (mbox_flags &
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen MAIL_INDEX_MAIL_FLAG_DIRTY) != 0;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen mail_index_update_flags(sync_ctx->t,
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen sync_ctx->idx_seq,
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen dirty ? MODIFY_ADD : MODIFY_REMOVE,
770cbd7d71f9e97256ecfcd8bfc134f7f048dafcTimo Sirainen (enum mail_flags)
770cbd7d71f9e97256ecfcd8bfc134f7f048dafcTimo Sirainen MAIL_INDEX_MAIL_FLAG_DIRTY);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if ((idx_mail.flags & MAIL_INDEX_MAIL_FLAG_DIRTY) == 0 &&
bb26f09873c18f342cd1ab2d0ee0b9018e6546d9Timo Sirainen !index_keyword_array_cmp(&idx_mail.keywords,
bb26f09873c18f342cd1ab2d0ee0b9018e6546d9Timo Sirainen &mail_ctx->mail.keywords))
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mbox_sync_update_index_keywords(mail_ctx);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen t_pop();
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen /* see if we need to update md5 sum. */
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (sync_ctx->mbox->mbox_save_md5 != 0)
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mbox_sync_update_md5_if_changed(mail_ctx);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
c84985f66c5c83db642d136aefa8864cb45158cfTimo Sirainen /* mail_ctx->recent is TRUE always if Status: O doesn't exist in the
c84985f66c5c83db642d136aefa8864cb45158cfTimo Sirainen mbox file. With lazy writes another session could have taken it
c84985f66c5c83db642d136aefa8864cb45158cfTimo Sirainen already, so we'll also have to check this from index header. */
c84985f66c5c83db642d136aefa8864cb45158cfTimo Sirainen if (!mail_ctx->recent || mail->uid < sync_ctx->hdr->first_recent_uid)
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen sync_ctx->last_nonrecent_uid = mail->uid;
a8b8cce8569753ed47c94782283a24fb11c5ab52Timo Sirainen else
a8b8cce8569753ed47c94782283a24fb11c5ab52Timo Sirainen index_mailbox_set_recent_uid(&sync_ctx->mbox->ibox, mail->uid);
e8a35266a5ceacdfafeeffd6bddae77931ff97ebTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* update from_offsets, but not if we're going to rewrite this message.
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen rewriting would just move it anyway. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->need_space_seq == 0) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool nocheck = rec == NULL || sync_ctx->expunged_space > 0;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mbox_sync_update_from_offset(sync_ctx, mail, nocheck);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainenstatic int mbox_read_from_line(struct mbox_sync_mail_context *ctx)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen{
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen struct istream *input = ctx->sync_ctx->file_input;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen const unsigned char *data;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen size_t size, from_line_size;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen buffer_set_used_size(ctx->sync_ctx->from_line, 0);
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen from_line_size = ctx->hdr_offset - ctx->mail.from_offset;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen i_stream_seek(input, ctx->mail.from_offset);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen for (;;) {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen data = i_stream_get_data(input, &size);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (size >= from_line_size)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen size = from_line_size;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen buffer_append(ctx->sync_ctx->from_line, data, size);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen i_stream_skip(input, size);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen from_line_size -= size;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (from_line_size == 0)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen break;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (i_stream_read(input) < 0)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen return -1;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen return 0;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen}
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenstatic int mbox_rewrite_base_uid_last(struct mbox_sync_context *sync_ctx)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen{
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen unsigned char buf[10];
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen const char *str;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uint32_t uid_last;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen unsigned int i;
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen int ret;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen i_assert(sync_ctx->base_uid_last_offset != 0);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* first check that the 10 bytes are there and they're exactly as
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen expected. just an extra safety check to make sure we never write
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen to wrong location in the mbox file. */
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen ret = pread_full(sync_ctx->write_fd, buf, sizeof(buf),
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen sync_ctx->base_uid_last_offset);
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen if (ret < 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "pread_full()");
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen if (ret == 0) {
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen mbox_sync_set_critical(sync_ctx,
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen "X-IMAPbase uid-last unexpectedly points outside "
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen "mbox file %s", sync_ctx->mbox->path);
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen return -1;
16aba431c576c1dbd99cbaae4f9d65eea9ad73c2Timo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen for (i = 0, uid_last = 0; i < sizeof(buf); i++) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (buf[i] < '0' || buf[i] > '9') {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uid_last = (uint32_t)-1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen break;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uid_last = uid_last * 10 + (buf[i] - '0');
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (uid_last != sync_ctx->base_uid_last) {
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen mbox_sync_set_critical(sync_ctx,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen "X-IMAPbase uid-last unexpectedly lost in mbox file %s",
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->mbox->path);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* and write it */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen str = t_strdup_printf("%010u", sync_ctx->next_uid - 1);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (pwrite_full(sync_ctx->write_fd, str, 10,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->base_uid_last_offset) < 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "pwrite_full()");
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen mbox_sync_file_updated(sync_ctx, FALSE);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->base_uid_last = sync_ctx->next_uid - 1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return 0;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen}
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainenstatic int
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainenmbox_write_from_line(struct mbox_sync_mail_context *ctx)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen{
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen string_t *str = ctx->sync_ctx->from_line;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (pwrite_full(ctx->sync_ctx->write_fd, str_data(str), str_len(str),
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainen ctx->mail.from_offset) < 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(ctx->sync_ctx->mbox, "pwrite_full()");
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen return -1;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen mbox_sync_file_updated(ctx->sync_ctx, FALSE);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen return 0;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen}
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainenstatic void update_from_offsets(struct mbox_sync_context *sync_ctx)
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen{
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen const struct mbox_sync_mail *mails;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen unsigned int i, count;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen uint32_t ext_idx;
ab3c1eab9ca13916358a9e8b12df8212fefb7dbfTimo Sirainen uint64_t offset;
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ext_idx = sync_ctx->mbox->mbox_ext_idx;
3021a062b16ff0138408be6107d6bcd0ced280b9Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen mails = array_get(&sync_ctx->mails, &count);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen for (i = 0; i < count; i++) {
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen if (mails[i].idx_seq == 0 || mails[i].expunged)
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainen continue;
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainen
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen sync_ctx->moved_offsets = TRUE;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen offset = mails[i].from_offset;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen mail_index_update_ext(sync_ctx->t, mails[i].idx_seq,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ext_idx, &offset, NULL);
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen }
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen}
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainenstatic void mbox_sync_handle_expunge(struct mbox_sync_mail_context *mail_ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen struct mailbox *box = &sync_ctx->mbox->ibox.box;
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen if (box->v.sync_notify != NULL) {
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen box->v.sync_notify(box, mail_ctx->mail.uid,
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen MAILBOX_SYNC_TYPE_EXPUNGE);
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen }
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen mail_index_expunge(sync_ctx->t, mail_ctx->mail.idx_seq);
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen mail_ctx->mail.expunged = TRUE;
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen mail_ctx->mail.offset = mail_ctx->mail.from_offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.space =
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen mail_ctx->body_offset - mail_ctx->mail.from_offset +
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.body_size;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.body_size = 0;
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen mail_ctx->mail.uid = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen if (sync_ctx->seq == 1) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* expunging first message, fix space to contain next
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen message's \n header too since it will be removed. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.space++;
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen if (istream_raw_mbox_has_crlf_ending(sync_ctx->input)) {
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen mail_ctx->mail.space++;
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen sync_ctx->first_mail_crlf_expunged = TRUE;
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen }
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen /* uid-last offset is invalid now */
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen sync_ctx->base_uid_last_offset = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen sync_ctx->expunged_space += mail_ctx->mail.space;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int mbox_sync_handle_header(struct mbox_sync_mail_context *mail_ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mbox_sync_context *sync_ctx = mail_ctx->sync_ctx;
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen uoff_t orig_from_offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen off_t move_diff;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen int ret;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->expunged_space > 0 && sync_ctx->need_space_seq == 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* move the header backwards to fill expunged space */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen move_diff = -sync_ctx->expunged_space;
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen orig_from_offset = mail_ctx->mail.from_offset;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen if (sync_ctx->dest_first_mail) {
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen /* we're moving this mail to beginning of file.
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen skip the initial \n (it's already counted in
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen expunged_space) */
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen mail_ctx->mail.from_offset++;
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen if (sync_ctx->first_mail_crlf_expunged)
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen mail_ctx->mail.from_offset++;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen }
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* read the From-line before rewriting overwrites it */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mbox_read_from_line(mail_ctx) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mbox_sync_update_header(mail_ctx);
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen ret = mbox_sync_try_rewrite(mail_ctx, move_diff);
60d3fa9883237e896a8704275b6116fa46f7ffdaTimo Sirainen if (ret < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ret > 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* rewrite successful, write From-line to
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen new location */
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen i_assert(move_diff > 0 ||
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen (off_t)mail_ctx->mail.from_offset >=
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen -move_diff);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.from_offset += move_diff;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.offset += move_diff;
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainen if (mbox_write_from_line(mail_ctx) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen } else {
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen if (sync_ctx->dest_first_mail) {
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen /* didn't have enough space, move the offset
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen back so seeking into it doesn't fail */
c35d0c3eb4ba89432896e1f9770ab31cc63c232bTimo Sirainen mail_ctx->mail.from_offset = orig_from_offset;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen }
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else if (mail_ctx->need_rewrite ||
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen index_sync_changes_have(sync_ctx->sync_changes)) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mbox_sync_update_header(mail_ctx);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen if (sync_ctx->delay_writes) {
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen /* mark it dirty and do it later */
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen mail_ctx->dirty = TRUE;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen return 0;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen if ((ret = mbox_sync_try_rewrite(mail_ctx, 0)) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* nothing to do */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ret == 0 && sync_ctx->need_space_seq == 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* first mail with no space to write it */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->need_space_seq = sync_ctx->seq;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->space_diff = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
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
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen memset(&mail, 0, sizeof(mail));
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen mail.expunged = TRUE;
36816b5af1472ae76a1909ae3cf29fd614b2ebfcTimo Sirainen mail.offset = mail.from_offset =
829c036d4ddfbd9ea49bd8a7c54e3057177d346eTimo Sirainen (sync_ctx->dest_first_mail ? 1 : 0) +
36816b5af1472ae76a1909ae3cf29fd614b2ebfcTimo Sirainen mail_ctx->mail.from_offset -
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->expunged_space;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail.space = sync_ctx->expunged_space;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen sync_ctx->space_diff = sync_ctx->expunged_space;
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen sync_ctx->expunged_space = 0;
8d5991f5c4a8840bf1ea754093dbec505564ab78Timo Sirainen i_assert(sync_ctx->space_diff < -mail_ctx->mail.space);
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->need_space_seq--;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen array_append(&sync_ctx->mails, &mail, 1);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo 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;
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen uoff_t end_offset, move_diff, extra_space, needed_space;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen uint32_t last_seq;
f5b4979e2780c4df112a300967d647e2fdd73511Timo Sirainen ARRAY_TYPE(keyword_indexes) keywords_copy;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
2cb565cd978aafd5714792b5161889986d49e431Timo Sirainen i_assert(mail_ctx->mail.uid == 0 || mail_ctx->mail.space > 0 ||
2cb565cd978aafd5714792b5161889986d49e431Timo Sirainen mail_ctx->mail.offset == mail_ctx->hdr_offset);
343a527f805ca5cce78496b959d6def70e5d0cd4Timo Sirainen
5486e1e123484f3a8d7d895e8ac41156f2a96305Timo Sirainen if (array_is_created(&mail_ctx->mail.keywords)) {
5486e1e123484f3a8d7d895e8ac41156f2a96305Timo Sirainen /* mail's keywords are allocated from a pool that's cleared
5486e1e123484f3a8d7d895e8ac41156f2a96305Timo Sirainen for each mail. we'll need to copy it to something more
5486e1e123484f3a8d7d895e8ac41156f2a96305Timo Sirainen permanent. */
f5b4979e2780c4df112a300967d647e2fdd73511Timo Sirainen p_array_init(&keywords_copy, sync_ctx->saved_keywords_pool,
5486e1e123484f3a8d7d895e8ac41156f2a96305Timo Sirainen array_count(&mail_ctx->mail.keywords));
5486e1e123484f3a8d7d895e8ac41156f2a96305Timo Sirainen array_append_array(&keywords_copy, &mail_ctx->mail.keywords);
5486e1e123484f3a8d7d895e8ac41156f2a96305Timo Sirainen mail_ctx->mail.keywords = keywords_copy;
5486e1e123484f3a8d7d895e8ac41156f2a96305Timo Sirainen }
6e4cd4ba520bc22ce375de378f4751136ebcf75aTimo Sirainen array_append(&sync_ctx->mails, &mail_ctx->mail, 1);
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->space_diff += mail_ctx->mail.space;
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen if (sync_ctx->space_diff < 0) {
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen if (sync_ctx->expunged_space > 0) {
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen i_assert(sync_ctx->expunged_space ==
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen mail_ctx->mail.space);
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen sync_ctx->expunged_space = 0;
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen }
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* we have enough space now */
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen if (mail_ctx->mail.uid == 0) {
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen /* this message was expunged. fill more or less of the space.
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen space_diff now consists of a negative "bytes needed" sum,
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen plus the expunged space of this message. so it contains how
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen many bytes of _extra_ space we have. */
8d5991f5c4a8840bf1ea754093dbec505564ab78Timo Sirainen i_assert(mail_ctx->mail.space >= sync_ctx->space_diff);
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen extra_space = MBOX_HEADER_PADDING *
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen (sync_ctx->seq - sync_ctx->need_space_seq + 1);
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen needed_space = mail_ctx->mail.space - sync_ctx->space_diff;
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen if ((uoff_t)sync_ctx->space_diff > needed_space + extra_space) {
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen /* don't waste too much on padding */
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen move_diff = needed_space + extra_space;
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen sync_ctx->expunged_space =
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen mail_ctx->mail.space - move_diff;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen } else {
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen move_diff = mail_ctx->mail.space;
c9a03c8a03a782488981f81bd7c6b5e01ff55f06Timo Sirainen extra_space = sync_ctx->space_diff;
829c036d4ddfbd9ea49bd8a7c54e3057177d346eTimo Sirainen sync_ctx->expunged_space = 0;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen last_seq = sync_ctx->seq - 1;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen array_delete(&sync_ctx->mails,
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen array_count(&sync_ctx->mails) - 1, 1);
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen end_offset = mail_ctx->mail.from_offset;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else {
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen /* this message gave enough space from headers. rewriting stops
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen at the end of this message's headers. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->expunged_space = 0;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen last_seq = sync_ctx->seq;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen end_offset = mail_ctx->body_offset;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen move_diff = 0;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen extra_space = sync_ctx->space_diff;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen mbox_sync_file_update_ext_modified(sync_ctx);
a614397cf1a4dde152eb1a38493a6ec3d817da16Timo Sirainen if (mbox_sync_rewrite(sync_ctx,
a614397cf1a4dde152eb1a38493a6ec3d817da16Timo Sirainen last_seq == sync_ctx->seq ? mail_ctx : NULL,
a614397cf1a4dde152eb1a38493a6ec3d817da16Timo Sirainen end_offset, move_diff, extra_space,
a614397cf1a4dde152eb1a38493a6ec3d817da16Timo Sirainen sync_ctx->need_space_seq, last_seq) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen update_from_offsets(sync_ctx);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* mail_ctx may contain wrong data after rewrite, so make sure we
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen don't try to access it */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen memset(mail_ctx, 0, sizeof(*mail_ctx));
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->need_space_seq = 0;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen sync_ctx->space_diff = 0;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen array_clear(&sync_ctx->mails);
343a527f805ca5cce78496b959d6def70e5d0cd4Timo Sirainen p_clear(sync_ctx->saved_keywords_pool);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstatic int
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenmbox_sync_seek_to_seq(struct mbox_sync_context *sync_ctx, uint32_t seq)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen{
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct mbox_mailbox *mbox = sync_ctx->mbox;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen uoff_t old_offset;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen uint32_t uid;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen int ret;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool deleted;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (seq == 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (istream_raw_mbox_seek(mbox->mbox_stream, 0) < 0) {
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen mail_storage_set_error(&mbox->storage->storage,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen MAIL_ERROR_NOTPOSSIBLE,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen "Mailbox isn't a valid mbox file");
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return -1;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen seq++;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen } else {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen old_offset = istream_raw_mbox_get_start_offset(sync_ctx->input);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ret = mbox_file_seek(mbox, sync_ctx->sync_view, seq, &deleted);
f12aabfeba81f0d741971d2b7e4a5008eb4383caTimo Sirainen if (ret < 0) {
f12aabfeba81f0d741971d2b7e4a5008eb4383caTimo Sirainen if (deleted) {
f12aabfeba81f0d741971d2b7e4a5008eb4383caTimo Sirainen mbox_sync_set_critical(sync_ctx,
f12aabfeba81f0d741971d2b7e4a5008eb4383caTimo Sirainen "Message was expunged unexpectedly "
f12aabfeba81f0d741971d2b7e4a5008eb4383caTimo Sirainen "in mbox file %s", mbox->path);
f12aabfeba81f0d741971d2b7e4a5008eb4383caTimo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return -1;
f12aabfeba81f0d741971d2b7e4a5008eb4383caTimo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (ret == 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (istream_raw_mbox_seek(mbox->mbox_stream,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen old_offset) < 0) {
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen mbox_sync_set_critical(sync_ctx,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen "Error seeking back to original "
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen "offset %s in mbox file %s",
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen dec2str(old_offset), mbox->path);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return -1;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return 0;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen if (seq <= 1)
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen uid = 0;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen else
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen mail_index_lookup_uid(sync_ctx->sync_view, seq-1, &uid);
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen sync_ctx->prev_msg_uid = uid;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo 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) {
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen /* this mbox has pseudo mail which contains the X-IMAP header */
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen sync_ctx->seq++;
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen }
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen sync_ctx->idx_seq = seq;
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen sync_ctx->dest_first_mail = sync_ctx->seq == 0;
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen (void)istream_raw_mbox_get_body_offset(sync_ctx->input);
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen return 1;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen}
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenstatic int
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenmbox_sync_seek_to_uid(struct mbox_sync_context *sync_ctx, uint32_t uid)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen{
a10e5606a9e93f49cf13b3a35c8dc3f5d6ab5909Timo Sirainen struct mail_index_view *sync_view = sync_ctx->sync_view;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen uint32_t seq1, seq2;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen const struct stat *st;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen i_assert(!sync_ctx->index_reset);
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen mail_index_lookup_uid_range(sync_view, uid, (uint32_t)-1,
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen &seq1, &seq2);
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen if (seq1 == 0) {
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen /* doesn't exist anymore, seek to end of file */
34d2ee1fa2b299267fcefd378f80690e7f601dfbTimo Sirainen st = i_stream_stat(sync_ctx->file_input, TRUE);
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (st == NULL) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen "i_stream_stat()");
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen return -1;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen }
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (istream_raw_mbox_seek(sync_ctx->mbox->mbox_stream,
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen st->st_size) < 0) {
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen mbox_sync_set_critical(sync_ctx,
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen "Error seeking to end of mbox file %s",
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->mbox->path);
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen return -1;
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen }
a10e5606a9e93f49cf13b3a35c8dc3f5d6ab5909Timo Sirainen sync_ctx->idx_seq =
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen mail_index_view_get_messages_count(sync_view) + 1;
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen return 1;
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen }
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return mbox_sync_seek_to_seq(sync_ctx, seq1);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen}
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenstatic int mbox_sync_partial_seek_next(struct mbox_sync_context *sync_ctx,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen uint32_t next_uid, bool *partial,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool *skipped_mails)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen uint32_t messages_count, uid;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen int ret;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen i_assert(!sync_ctx->index_reset);
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* delete sync records up to next message. so if there's still
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen something left in array, it means the next message needs modifying */
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen index_sync_changes_delete_to(sync_ctx->sync_changes, next_uid);
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen if (index_sync_changes_have(sync_ctx->sync_changes))
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return 1;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (sync_ctx->hdr->first_recent_uid <= next_uid &&
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen !sync_ctx->mbox->ibox.keep_recent) {
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen /* we'll need to rewrite Status: O headers */
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen return 1;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen }
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen uid = index_sync_changes_get_next_uid(sync_ctx->sync_changes);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (sync_ctx->hdr->first_recent_uid < sync_ctx->hdr->next_uid &&
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen (uid > sync_ctx->hdr->first_recent_uid || uid == 0) &&
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen !sync_ctx->mbox->ibox.keep_recent) {
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen /* we'll need to rewrite Status: O headers */
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen uid = sync_ctx->hdr->first_recent_uid;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen }
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen if (uid != 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* we can skip forward to next record which needs updating. */
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen if (uid != next_uid) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen *skipped_mails = TRUE;
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen next_uid = uid;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ret = mbox_sync_seek_to_uid(sync_ctx, next_uid);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen } else {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* if there's no sync records left, we can stop. except if
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen this is a dirty sync, check if there are new messages. */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (!sync_ctx->mbox->mbox_sync_dirty)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return 0;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen messages_count =
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_index_view_get_messages_count(sync_ctx->sync_view);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (sync_ctx->seq + 1 != messages_count) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ret = mbox_sync_seek_to_seq(sync_ctx, messages_count);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen *skipped_mails = TRUE;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen } else {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ret = 1;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen *partial = FALSE;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (ret == 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* seek failed because the offset is dirty. just ignore and
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen continue from where we are now. */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen *partial = FALSE;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ret = 1;
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return ret;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen}
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainenstatic bool mbox_sync_uidvalidity_changed(struct mbox_sync_context *sync_ctx)
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen{
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen if (sync_ctx->base_uid_validity != 0 &&
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen sync_ctx->hdr->uid_validity != 0 &&
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen sync_ctx->base_uid_validity != sync_ctx->hdr->uid_validity) {
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen i_warning("UIDVALIDITY changed (%u -> %u) in mbox file %s",
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen sync_ctx->hdr->uid_validity,
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen sync_ctx->base_uid_validity,
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen sync_ctx->mbox->path);
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen sync_ctx->index_reset = TRUE;
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen return TRUE;
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen }
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen return FALSE;
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen}
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainenstatic int mbox_sync_loop(struct mbox_sync_context *sync_ctx,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen struct mbox_sync_mail_context *mail_ctx,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool partial)
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen{
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen const struct mail_index_record *rec;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uint32_t uid, messages_count;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen uoff_t offset;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen int ret;
d31c4d7c161f9d7efa59964c7c958e83e05b218cTimo Sirainen bool expunged, skipped_mails, uids_broken;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen messages_count =
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_index_view_get_messages_count(sync_ctx->sync_view);
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* always start from first message so we can read X-IMAP or
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen X-IMAPbase header */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ret = mbox_sync_seek_to_seq(sync_ctx, 0);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (ret <= 0)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return ret;
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen if (sync_ctx->renumber_uids) {
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen /* expunge everything */
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen while (sync_ctx->idx_seq <= messages_count) {
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen mail_index_expunge(sync_ctx->t,
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen sync_ctx->idx_seq++);
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen }
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen }
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen
d31c4d7c161f9d7efa59964c7c958e83e05b218cTimo Sirainen skipped_mails = uids_broken = FALSE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen while ((ret = mbox_sync_read_next_mail(sync_ctx, mail_ctx)) > 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen uid = mail_ctx->mail.uid;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen if (mail_ctx->seq == 1) {
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen if (mbox_sync_uidvalidity_changed(sync_ctx)) {
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen sync_ctx->mbox->mbox_sync_dirty = TRUE;
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen return 0;
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen }
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen }
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen
912e870dcab2dadac8a6b20b42367999cdd8b5a1Timo Sirainen if (mail_ctx->mail.uid_broken && partial) {
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen /* UID ordering problems, resync everything to make
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen sure we get everything right */
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen if (sync_ctx->mbox->mbox_sync_dirty)
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen return 0;
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen mbox_sync_set_critical(sync_ctx,
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen "UIDs broken with partial sync in mbox file %s",
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen sync_ctx->mbox->path);
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen
b8765f6093ab35fc2345293d78132d35794cbff5Timo Sirainen sync_ctx->mbox->mbox_sync_dirty = TRUE;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen return 0;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen }
d31c4d7c161f9d7efa59964c7c958e83e05b218cTimo Sirainen if (mail_ctx->mail.uid_broken)
d31c4d7c161f9d7efa59964c7c958e83e05b218cTimo Sirainen uids_broken = TRUE;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen if (mail_ctx->mail.pseudo)
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen uid = 0;
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen rec = NULL; ret = 1;
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen if (uid != 0) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (!mbox_sync_read_index_rec(sync_ctx, uid, &rec))
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen ret = 0;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen if (ret == 0) {
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen /* UID found but it's broken */
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen uid = 0;
cdaf255d6a3daeef0ac85edaa60bfa6d1f945bffTimo Sirainen } else if (uid == 0 &&
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen !mail_ctx->mail.pseudo &&
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen (sync_ctx->delay_writes ||
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen sync_ctx->idx_seq <= messages_count)) {
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen /* If we can't use/store X-UID header, use MD5 sum.
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen Also check for existing MD5 sums when we're actually
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen able to write X-UIDs. */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->mbox->mbox_save_md5 = TRUE;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mbox_sync_find_index_md5(sync_ctx,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mail_ctx->hdr_md5_sum, &rec);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (rec != NULL)
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen uid = mail_ctx->mail.uid = rec->uid;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen /* get all sync records related to this message. with pseudo
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen message just get the first sync record so we can jump to
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen it with partial seeking. */
b08b33d1f5ce3721dc2d83586c9cb0ca141331fdTimo Sirainen mbox_sync_read_index_syncs(sync_ctx,
b08b33d1f5ce3721dc2d83586c9cb0ca141331fdTimo Sirainen mail_ctx->mail.pseudo ? 1 : uid,
b08b33d1f5ce3721dc2d83586c9cb0ca141331fdTimo Sirainen &expunged);
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen if (mail_ctx->mail.pseudo) {
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen /* if it was set, it was for the next message */
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen expunged = FALSE;
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen } else {
e9d68b41c007f0e545de361f8012f6f231bfec8bTimo Sirainen if (rec == NULL) {
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen /* message wasn't found from index. we have to
c9fe52d819c608b890620f7fe36ff509b14eb350Timo Sirainen read everything from now on, no skipping */
e9d68b41c007f0e545de361f8012f6f231bfec8bTimo Sirainen partial = FALSE;
e9d68b41c007f0e545de361f8012f6f231bfec8bTimo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen if (uid == 0 && !mail_ctx->mail.pseudo) {
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen /* missing/broken X-UID. all the rest of the mails
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen need new UIDs. */
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen while (sync_ctx->idx_seq <= messages_count) {
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen mail_index_expunge(sync_ctx->t,
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen sync_ctx->idx_seq++);
71a74e26cf070a205d31cf6c6fae003f90027b63Timo Sirainen }
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen if (sync_ctx->next_uid == (uint32_t)-1) {
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen /* oh no, we're out of UIDs. this shouldn't
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen happen normally, so just try to get it fixed
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen without crashing. */
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen mail_storage_set_critical(
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen &sync_ctx->mbox->storage->storage,
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen "Out of UIDs, renumbering them in mbox "
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen "file %s", sync_ctx->mbox->path);
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen sync_ctx->renumber_uids = TRUE;
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen return 0;
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen }
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen mail_ctx->need_rewrite = TRUE;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen mail_ctx->mail.uid = sync_ctx->next_uid++;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen }
1dd9801f7ace40777ecf8ed9a98c093bc40467a4Timo Sirainen sync_ctx->prev_msg_uid = mail_ctx->mail.uid;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen if (!mail_ctx->mail.pseudo)
b428c5993b01f4cffacdd24377ca2873fcc12184Timo Sirainen mail_ctx->mail.idx_seq = sync_ctx->idx_seq;
d0e5f8252516c4d4df2fbcdae4d37f9e5f931199Timo Sirainen
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen if (!expunged) {
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen if (mbox_sync_handle_header(mail_ctx) < 0)
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen return -1;
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen sync_ctx->dest_first_mail = FALSE;
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen } else {
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen mbox_sync_handle_expunge(mail_ctx);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen
1e76a5b92f9d82d557f81f080f3dfad1c9d8f200Timo Sirainen if (!mail_ctx->mail.pseudo) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (!expunged)
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen mbox_sync_update_index(mail_ctx, rec);
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen sync_ctx->idx_seq++;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen istream_raw_mbox_next(sync_ctx->input,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_ctx->mail.body_size);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen offset = istream_raw_mbox_get_start_offset(sync_ctx->input);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->need_space_seq != 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mbox_sync_handle_missing_space(mail_ctx) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen if (mbox_sync_seek(sync_ctx, offset) < 0)
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen return -1;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen } else if (sync_ctx->expunged_space > 0) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (!expunged) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen /* move the body */
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen mbox_sync_file_update_ext_modified(sync_ctx);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (mbox_move(sync_ctx,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen mail_ctx->body_offset -
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen sync_ctx->expunged_space,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen mail_ctx->body_offset,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen mail_ctx->mail.body_size) < 0)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return -1;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen if (mbox_sync_seek(sync_ctx, offset) < 0)
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen return -1;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen }
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen } else if (partial) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ret = mbox_sync_partial_seek_next(sync_ctx, uid + 1,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen &partial,
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen &skipped_mails);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (ret <= 0) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (ret < 0)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen break;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen if (istream_raw_mbox_is_eof(sync_ctx->input)) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen /* rest of the messages in index don't exist -> expunge them */
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen while (sync_ctx->idx_seq <= messages_count)
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen mail_index_expunge(sync_ctx->t, sync_ctx->idx_seq++);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (!skipped_mails)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->mbox->mbox_sync_dirty = FALSE;
d31c4d7c161f9d7efa59964c7c958e83e05b218cTimo Sirainen
d31c4d7c161f9d7efa59964c7c958e83e05b218cTimo Sirainen if (uids_broken && sync_ctx->delay_writes) {
d31c4d7c161f9d7efa59964c7c958e83e05b218cTimo Sirainen /* once we get around to writing the changes, we'll need to do
d31c4d7c161f9d7efa59964c7c958e83e05b218cTimo Sirainen a full sync to avoid the "UIDs broken in partial sync"
d31c4d7c161f9d7efa59964c7c958e83e05b218cTimo Sirainen error */
d31c4d7c161f9d7efa59964c7c958e83e05b218cTimo Sirainen sync_ctx->mbox->mbox_sync_dirty = TRUE;
d31c4d7c161f9d7efa59964c7c958e83e05b218cTimo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return 1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
3cfff0ca01961d885bdbd6ef08d761880116af07Timo Sirainen
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainenstatic int mbox_write_pseudo(struct mbox_sync_context *sync_ctx)
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen{
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen string_t *str;
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen unsigned int uid_validity;
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen i_assert(sync_ctx->write_fd != -1);
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen uid_validity = sync_ctx->base_uid_validity != 0 ?
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen sync_ctx->base_uid_validity : sync_ctx->hdr->uid_validity;
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen i_assert(uid_validity != 0);
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen str = t_str_new(1024);
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen str_printfa(str, "%sDate: %s\n"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen "From: Mail System Internal Data <MAILER-DAEMON@%s>\n"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen "Subject: DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen "\nMessage-ID: <%s@%s>\n"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen "X-IMAP: %u %010u\n"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen "Status: RO\n"
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen "\n"
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainen PSEUDO_MESSAGE_BODY
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainen "\n",
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen mbox_from_create("MAILER_DAEMON", ioloop_time),
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen message_date_create(ioloop_time),
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen my_hostname, dec2str(ioloop_time), my_hostname,
9d2040fbb941f411d57fd850b4cdc3b1cccc1168Timo Sirainen uid_validity, sync_ctx->next_uid-1);
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (pwrite_full(sync_ctx->write_fd,
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen str_data(str), str_len(str), 0) < 0) {
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (!ENOSPACE(errno)) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen "pwrite_full()");
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen return -1;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen }
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen /* out of disk space, truncate to empty */
b8bbfab97eed17fcb00b5a86128e1d7a3babc35cTimo Sirainen if (ftruncate(sync_ctx->write_fd, 0) < 0)
b8bbfab97eed17fcb00b5a86128e1d7a3babc35cTimo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "ftruncate()");
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen }
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen sync_ctx->base_uid_last_offset = 0; /* don't bother calculating */
2be66b9eddad3841a1195fe9aeb1eaf0f28f1116Timo Sirainen sync_ctx->base_uid_last = sync_ctx->next_uid-1;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen return 0;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen}
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int mbox_sync_handle_eof_updates(struct mbox_sync_context *sync_ctx,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mbox_sync_mail_context *mail_ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen const struct stat *st;
f5b919e9b07dfd9d2401b998ef8759e5f0312719Timo Sirainen uoff_t file_size, offset, padding, trailer_size;
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen if (!istream_raw_mbox_is_eof(sync_ctx->input)) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen i_assert(sync_ctx->need_space_seq == 0);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen i_assert(sync_ctx->expunged_space == 0);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return 0;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen st = i_stream_stat(sync_ctx->file_input, TRUE);
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (st == NULL) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "i_stream_stat()");
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen return -1;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen }
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen file_size = st->st_size;
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen if (file_size < sync_ctx->file_input->v_offset) {
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen mbox_sync_set_critical(sync_ctx,
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen "file size unexpectedly shrinked in mbox file %s "
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen "(%"PRIuUOFF_T" vs %"PRIuUOFF_T")",
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen sync_ctx->mbox->path, file_size,
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen sync_ctx->file_input->v_offset);
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen return -1;
09b9cbde9e7a0f9adea1fb054a7c62f35ad901e1Timo Sirainen }
5edfc0f1c3c55e906d8316d9cdeaa3b0c7000c19Timo Sirainen trailer_size = file_size - sync_ctx->file_input->v_offset;
686cb2418d4daa7bc747d3551783c1895e7c41b9Timo Sirainen i_assert(trailer_size <= 2);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->need_space_seq != 0) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen i_assert(sync_ctx->write_fd != -1);
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_assert(sync_ctx->space_diff < 0);
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen padding = MBOX_HEADER_PADDING *
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen (sync_ctx->seq - sync_ctx->need_space_seq + 1);
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen sync_ctx->space_diff -= padding;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
f5b919e9b07dfd9d2401b998ef8759e5f0312719Timo Sirainen i_assert(sync_ctx->expunged_space <= -sync_ctx->space_diff);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->space_diff += sync_ctx->expunged_space;
f5b919e9b07dfd9d2401b998ef8759e5f0312719Timo Sirainen sync_ctx->expunged_space = 0;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mail_ctx->have_eoh && !mail_ctx->updated)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen str_append_c(mail_ctx->header, '\n');
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen i_assert(sync_ctx->space_diff < 0);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (file_set_size(sync_ctx->write_fd,
f5b919e9b07dfd9d2401b998ef8759e5f0312719Timo Sirainen file_size + -sync_ctx->space_diff) < 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen "file_set_size()");
b8bbfab97eed17fcb00b5a86128e1d7a3babc35cTimo Sirainen if (ftruncate(sync_ctx->write_fd, file_size) < 0) {
b8bbfab97eed17fcb00b5a86128e1d7a3babc35cTimo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
b8bbfab97eed17fcb00b5a86128e1d7a3babc35cTimo Sirainen "ftruncate()");
b8bbfab97eed17fcb00b5a86128e1d7a3babc35cTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen }
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen mbox_sync_file_updated(sync_ctx, FALSE);
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen
f4b93a46e140823a64d88763ea6ef9f03c49844eTimo Sirainen if (mbox_sync_rewrite(sync_ctx, mail_ctx, file_size,
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen -sync_ctx->space_diff, padding,
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen sync_ctx->need_space_seq,
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen sync_ctx->seq) < 0)
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen return -1;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen update_from_offsets(sync_ctx);
99be58a447b69d62cbd9e764000a06226b9c9c89Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen sync_ctx->need_space_seq = 0;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen array_clear(&sync_ctx->mails);
343a527f805ca5cce78496b959d6def70e5d0cd4Timo Sirainen p_clear(sync_ctx->saved_keywords_pool);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx->expunged_space > 0) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen i_assert(sync_ctx->write_fd != -1);
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen mbox_sync_file_update_ext_modified(sync_ctx);
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen /* copy trailer, then truncate the file */
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen file_size = sync_ctx->last_stat.st_size;
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen if (file_size == (uoff_t)sync_ctx->expunged_space) {
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen /* everything deleted, the trailer_size still contains
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen the \n trailer though */
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen trailer_size = 0;
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen }
b397a802ec245a9169dab6b62efa4f7f877c07f6Timo Sirainen
5edfc0f1c3c55e906d8316d9cdeaa3b0c7000c19Timo Sirainen i_assert(file_size >= sync_ctx->expunged_space + trailer_size);
5edfc0f1c3c55e906d8316d9cdeaa3b0c7000c19Timo Sirainen offset = file_size - sync_ctx->expunged_space - trailer_size;
eb276c05bf6b0a383c772d61e31cf09a8dbd36c7Timo Sirainen i_assert(offset == 0 || offset > 31);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mbox_move(sync_ctx, offset,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen offset + sync_ctx->expunged_space,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen trailer_size) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (ftruncate(sync_ctx->write_fd,
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen offset + trailer_size) < 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "ftruncate()");
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen if (offset == 0) {
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainen if (mbox_write_pseudo(sync_ctx) < 0)
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen return -1;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen }
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen sync_ctx->expunged_space = 0;
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen mbox_sync_file_updated(sync_ctx, FALSE);
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
af6d4a24cb6d18e50d172540cf49b1448a6f9872Timo Sirainenstatic int mbox_sync_update_index_header(struct mbox_sync_context *sync_ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen const struct stat *st;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen uint32_t first_recent_uid;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen st = i_stream_stat(sync_ctx->file_input, FALSE);
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if (st == NULL) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "i_stream_stat()");
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen if (sync_ctx->moved_offsets &&
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen ((uint64_t)st->st_size == sync_ctx->hdr->sync_size ||
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen (uint64_t)st->st_size == sync_ctx->orig_size)) {
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen /* We moved messages inside the mbox file without changing
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen the file's size. If mtime doesn't change, another process
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen not using the same index file as us can't know that the file
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen was changed. So make sure the mtime changes. This should
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen happen rarely enough that the sleeping doesn't become a
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen performance problem.
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen Note that to do this perfectly safe we should do this wait
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen whenever mails are moved or expunged, regardless of whether
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen the file's size changed. That however could become a
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen performance problem and the consequences of being wrong are
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen quite minimal (an extra logged error message). */
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen while (sync_ctx->orig_mtime == st->st_mtime) {
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen usleep(500000);
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen if (utime(sync_ctx->mbox->path, NULL) < 0) {
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen "utime()");
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen return -1;
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen }
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen st = i_stream_stat(sync_ctx->file_input, FALSE);
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen if (st == NULL) {
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen mbox_set_syscall_error(sync_ctx->mbox,
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen "i_stream_stat()");
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen return -1;
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen }
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen }
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen }
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen /* only reason not to have UID validity at this point is if the file
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen is entirely empty. In that case just make up a new one if needed. */
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen i_assert(sync_ctx->base_uid_validity != 0 || st->st_size == 0);
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen if (sync_ctx->base_uid_validity != sync_ctx->hdr->uid_validity ||
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen sync_ctx->base_uid_validity == 0) {
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen if (sync_ctx->base_uid_validity == 0) {
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen sync_ctx->base_uid_validity =
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen sync_ctx->hdr->uid_validity != 0 ?
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen sync_ctx->hdr->uid_validity :
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen (unsigned int)ioloop_time;
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen }
dc42ce2d44e84d9d05a9310c11f8764f319eb3abTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_index_update_header(sync_ctx->t,
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen offsetof(struct mail_index_header, uid_validity),
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen &sync_ctx->base_uid_validity,
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen sizeof(sync_ctx->base_uid_validity), TRUE);
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen }
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainen
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen if (istream_raw_mbox_is_eof(sync_ctx->input) &&
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen sync_ctx->next_uid != sync_ctx->hdr->next_uid) {
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen i_assert(sync_ctx->next_uid != 0);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_index_update_header(sync_ctx->t,
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen offsetof(struct mail_index_header, next_uid),
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen &sync_ctx->next_uid, sizeof(sync_ctx->next_uid), FALSE);
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen }
fcfd317f7eb1f0216764c75c5fab3555020552d4Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if ((uint32_t)st->st_mtime != sync_ctx->hdr->sync_stamp &&
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen !sync_ctx->mbox->mbox_sync_dirty) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen uint32_t sync_stamp = st->st_mtime;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_index_update_header(sync_ctx->t,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen offsetof(struct mail_index_header, sync_stamp),
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen &sync_stamp, sizeof(sync_stamp), TRUE);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen }
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen if ((uint64_t)st->st_size != sync_ctx->hdr->sync_size &&
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen !sync_ctx->mbox->mbox_sync_dirty) {
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen uint64_t sync_size = st->st_size;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_index_update_header(sync_ctx->t,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen offsetof(struct mail_index_header, sync_size),
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen &sync_size, sizeof(sync_size), TRUE);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen }
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen first_recent_uid = !sync_ctx->mbox->ibox.keep_recent ? 0 :
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen sync_ctx->last_nonrecent_uid + 1;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (sync_ctx->hdr->first_recent_uid < first_recent_uid) {
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen mail_index_update_header(sync_ctx->t,
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen offsetof(struct mail_index_header, first_recent_uid),
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen &first_recent_uid, sizeof(first_recent_uid), FALSE);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen }
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->mbox->mbox_dirty_stamp = st->st_mtime;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->mbox->mbox_dirty_size = st->st_size;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic void mbox_sync_restart(struct mbox_sync_context *sync_ctx)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->base_uid_validity = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx->base_uid_last = 0;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen sync_ctx->base_uid_last_offset = 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen array_clear(&sync_ctx->mails);
343a527f805ca5cce78496b959d6def70e5d0cd4Timo Sirainen p_clear(sync_ctx->saved_keywords_pool);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen index_sync_changes_reset(sync_ctx->sync_changes);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen mail_index_sync_reset(sync_ctx->index_sync_ctx);
734f2ff794505007ac7310af12e1adef5643c36eTimo Sirainen mail_index_transaction_reset(sync_ctx->t);
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen if (sync_ctx->index_reset) {
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen mail_index_reset(sync_ctx->t);
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen sync_ctx->reset_hdr.next_uid = 1;
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen sync_ctx->hdr = &sync_ctx->reset_hdr;
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen }
f6699a08521aacc4c2bb5b6175691dad5f715f8cTimo Sirainen
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen sync_ctx->prev_msg_uid = 0;
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen sync_ctx->next_uid = sync_ctx->hdr->next_uid;
aa38d1a0945f0bc13a225d043f53fad2eec666b1Timo Sirainen sync_ctx->idx_next_uid = sync_ctx->hdr->next_uid;
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen sync_ctx->seq = 0;
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen sync_ctx->idx_seq = 1;
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen sync_ctx->need_space_seq = 0;
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen sync_ctx->expunged_space = 0;
c263e92d73889da530b308c9ab28b4b74031550eTimo Sirainen sync_ctx->space_diff = 0;
325f4573edfa5b751832ac01023f3e81be992bf0Timo Sirainen
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainen sync_ctx->dest_first_mail = TRUE;
a2637488c8d514ec1ac3914811deee814f9761b3Timo Sirainen sync_ctx->ext_modified = FALSE;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenstatic int mbox_sync_do(struct mbox_sync_context *sync_ctx,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen enum mbox_sync_flags flags)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mbox_sync_mail_context mail_ctx;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen const struct stat *st;
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen unsigned int i;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen int ret, partial;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen st = i_stream_stat(sync_ctx->file_input, FALSE);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen if (st == NULL) {
34d2ee1fa2b299267fcefd378f80690e7f601dfbTimo Sirainen mbox_set_syscall_error(sync_ctx->mbox, "i_stream_stat()");
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen return -1;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
299183fbb6ec5d0828a0880da372540421ac4665Timo Sirainen sync_ctx->last_stat = *st;
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen sync_ctx->orig_size = st->st_size;
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen sync_ctx->orig_atime = st->st_atime;
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen sync_ctx->orig_mtime = st->st_mtime;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen if ((flags & MBOX_SYNC_FORCE_SYNC) != 0) {
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen /* forcing a full sync. assume file has changed. */
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen partial = FALSE;
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen sync_ctx->mbox->mbox_sync_dirty = TRUE;
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen } else if ((uint32_t)st->st_mtime == sync_ctx->hdr->sync_stamp &&
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen (uint64_t)st->st_size == sync_ctx->hdr->sync_size) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* file is fully synced */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen partial = TRUE;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->mbox->mbox_sync_dirty = FALSE;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen } else if ((flags & MBOX_SYNC_UNDIRTY) != 0 ||
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen (uint64_t)st->st_size == sync_ctx->hdr->sync_size) {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* we want to do full syncing. always do this if
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen file size hasn't changed but timestamp has. it most
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen likely means that someone had modified some header
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen and we probably want to know about it */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen partial = FALSE;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->mbox->mbox_sync_dirty = TRUE;
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen } else {
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen /* see if we can delay syncing the whole file.
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen normally we only notice expunges and appends
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen in partial syncing. */
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen partial = TRUE;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx->mbox->mbox_sync_dirty = TRUE;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen mbox_sync_restart(sync_ctx);
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen for (i = 0; i < 3; i++) {
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen ret = mbox_sync_loop(sync_ctx, &mail_ctx, partial);
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen if (ret > 0)
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen break;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (ret < 0)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return -1;
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen /* partial syncing didn't work, do it again. we get here
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen also if we ran out of UIDs. */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen i_assert(sync_ctx->mbox->mbox_sync_dirty);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mbox_sync_restart(sync_ctx);
a486ed03dce069ff60ab5a65d0ae24a1862f22fcTimo Sirainen partial = FALSE;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mbox_sync_handle_eof_updates(sync_ctx, &mail_ctx) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen /* only syncs left should be just appends (and their updates)
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen which weren't synced yet for some reason (crash). we'll just
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen ignore them, as we've overwritten them above. */
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen index_sync_changes_reset(sync_ctx->sync_changes);
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (mbox_sync_update_index_header(sync_ctx) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen}
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenint mbox_sync_has_changed(struct mbox_mailbox *mbox, bool leave_dirty)
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen{
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen const struct mail_index_header *hdr;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen const struct stat *st;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen struct stat statbuf;
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox->mbox_file_stream != NULL && mbox->mbox_fd == -1) {
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen /* read-only stream */
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen st = i_stream_stat(mbox->mbox_file_stream, FALSE);
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen if (st == NULL) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(mbox, "i_stream_stat()");
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen return -1;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen }
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen } else {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (stat(mbox->path, &statbuf) < 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(mbox, "stat()");
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen return -1;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen }
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen st = &statbuf;
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen }
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen hdr = mail_index_get_header(mbox->ibox.view);
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen if ((uint32_t)st->st_mtime == hdr->sync_stamp &&
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen (uint64_t)st->st_size == hdr->sync_size) {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* fully synced */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox->mbox_sync_dirty = FALSE;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return 0;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen if (!mbox->mbox_sync_dirty || !leave_dirty) {
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen mbox->mbox_sync_dirty = TRUE;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return 1;
e05ea8311ae16687295048e88ca205dfe29fbcbfTimo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return st->st_mtime != mbox->mbox_dirty_stamp ||
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen st->st_size != mbox->mbox_dirty_size;
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen}
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainenstatic void mbox_sync_context_free(struct mbox_sync_context *sync_ctx)
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen{
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen index_sync_changes_deinit(&sync_ctx->sync_changes);
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen if (sync_ctx->index_sync_ctx != NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen mail_index_sync_rollback(&sync_ctx->index_sync_ctx);
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen pool_unref(sync_ctx->mail_keyword_pool);
343a527f805ca5cce78496b959d6def70e5d0cd4Timo Sirainen pool_unref(sync_ctx->saved_keywords_pool);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen str_free(&sync_ctx->header);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen str_free(&sync_ctx->from_line);
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen array_free(&sync_ctx->mails);
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen}
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainenstatic int mbox_sync_int(struct mbox_mailbox *mbox, enum mbox_sync_flags flags)
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen{
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen struct mail_index_sync_ctx *index_sync_ctx;
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen struct mail_index_view *sync_view;
aa0647f2debf0d48d504a321186f66c85596aaf4Timo Sirainen struct mail_index_transaction *trans;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct mbox_sync_context sync_ctx;
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen enum mail_index_sync_flags sync_flags;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen unsigned int lock_id = 0;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen int ret, changed;
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen bool delay_writes;
dcd50ecbfe796bd76f2d63483c534cc0e4e94164Timo Sirainen
dcd50ecbfe796bd76f2d63483c534cc0e4e94164Timo Sirainen delay_writes = mbox->mbox_readonly ||
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen ((flags & MBOX_SYNC_REWRITE) == 0 &&
7c6ad06e2bed011e3c0425bf1ceb5df3dc33b638Timo Sirainen getenv("MBOX_LAZY_WRITES") != NULL);
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen mbox->ibox.sync_last_check = ioloop_time;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (!mbox->mbox_do_dirty_syncs)
6597506f9317f3be644e708c9153dacaeeece84cTimo Sirainen flags |= MBOX_SYNC_UNDIRTY;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
d252f81a2ff1bdd5439f9d2b3df715b70a4bcd3dTimo Sirainen if ((flags & MBOX_SYNC_LOCK_READING) != 0) {
d252f81a2ff1bdd5439f9d2b3df715b70a4bcd3dTimo Sirainen if (mbox_lock(mbox, F_RDLCK, &lock_id) <= 0)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return -1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen if ((flags & MBOX_SYNC_HEADER) != 0 ||
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen (flags & MBOX_SYNC_FORCE_SYNC) != 0)
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen changed = 1;
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen else {
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen bool leave_dirty = (flags & MBOX_SYNC_UNDIRTY) == 0;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen if ((changed = mbox_sync_has_changed(mbox, leave_dirty)) < 0) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if ((flags & MBOX_SYNC_LOCK_READING) != 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen (void)mbox_unlock(mbox, lock_id);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return -1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen }
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen if ((flags & MBOX_SYNC_LOCK_READING) != 0) {
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen /* we just want to lock it for reading. if mbox hasn't been
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen modified don't do any syncing. */
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen if (!changed)
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen return 0;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen /* have to sync to make sure offsets have stayed the same */
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen (void)mbox_unlock(mbox, lock_id);
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen lock_id = 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen /* reopen input stream to make sure it has nothing buffered */
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen mbox_file_close_stream(mbox);
f2b79667fc7a8f7c2c72cad18bd71d49730e36f6Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenagain:
f2b79667fc7a8f7c2c72cad18bd71d49730e36f6Timo Sirainen if (changed) {
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen /* we're most likely modifying the mbox while syncing, just
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen lock it for writing immediately. the mbox must be locked
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen before index syncing is started to avoid deadlocks, so we
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen don't have much choice either (well, easy ones anyway). */
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen int lock_type = mbox->mbox_readonly ? F_RDLCK : F_WRLCK;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen int ret;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
30975737820f5855e2c26d81b574ae5f03a05407Timo Sirainen if ((ret = mbox_lock(mbox, lock_type, &lock_id)) <= 0) {
30975737820f5855e2c26d81b574ae5f03a05407Timo Sirainen if (ret == 0 || lock_type == F_RDLCK)
30975737820f5855e2c26d81b574ae5f03a05407Timo Sirainen return -1;
30975737820f5855e2c26d81b574ae5f03a05407Timo Sirainen
30975737820f5855e2c26d81b574ae5f03a05407Timo Sirainen /* try as read-only */
30975737820f5855e2c26d81b574ae5f03a05407Timo Sirainen if (mbox_lock(mbox, F_RDLCK, &lock_id) <= 0)
30975737820f5855e2c26d81b574ae5f03a05407Timo Sirainen return -1;
30975737820f5855e2c26d81b574ae5f03a05407Timo Sirainen mbox->mbox_readonly = TRUE;
30975737820f5855e2c26d81b574ae5f03a05407Timo Sirainen }
30975737820f5855e2c26d81b574ae5f03a05407Timo Sirainen }
30975737820f5855e2c26d81b574ae5f03a05407Timo Sirainen
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen sync_flags = 0;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen if (!mbox->ibox.keep_recent)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen sync_flags |= MAIL_INDEX_SYNC_FLAG_DROP_RECENT;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if ((flags & MBOX_SYNC_REWRITE) != 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_flags |= MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen if ((flags & MBOX_SYNC_LAST_COMMIT) != 0) {
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen ret = mail_index_sync_begin_to(mbox->ibox.index,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen &index_sync_ctx, &sync_view, &trans,
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen mbox->ibox.commit_log_file_seq,
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen mbox->ibox.commit_log_file_offset, sync_flags);
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen } else {
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen ret = mail_index_sync_begin(mbox->ibox.index, &index_sync_ctx,
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen &sync_view, &trans,
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen sync_flags) < 0 ? -1 : 1;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
aa0647f2debf0d48d504a321186f66c85596aaf4Timo Sirainen
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen if (ret <= 0) {
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen if (ret < 0)
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen mail_storage_set_index_error(&mbox->ibox);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (lock_id != 0)
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen (void)mbox_unlock(mbox, lock_id);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return ret;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
0b17b95357d5d73d941f1eb4ca9fc543bc510e42Timo Sirainen
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen if (!mbox->ibox.keep_recent) {
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen /* see if we need to drop recent flags */
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen sync_ctx.hdr = mail_index_get_header(sync_view);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (sync_ctx.hdr->first_recent_uid < sync_ctx.hdr->next_uid)
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen changed = 1;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen }
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (!changed && !mail_index_sync_have_more(index_sync_ctx)) {
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen /* nothing to do */
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen nothing_to_do:
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen if (lock_id != 0)
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen (void)mbox_unlock(mbox, lock_id);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen /* index may need to do internal syncing though, so commit
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen instead of rollbacking. */
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen if (mail_index_sync_commit(&index_sync_ctx) < 0) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen mail_storage_set_index_error(&mbox->ibox);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return -1;
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen }
4d10cf8c7879ccd377e7fb136913b2a258ba8d93Timo Sirainen return 0;
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen }
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen memset(&sync_ctx, 0, sizeof(sync_ctx));
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx.mbox = mbox;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
de4288b7369945a31c4001add9445fd0195a358dTimo Sirainen sync_ctx.hdr = mail_index_get_header(sync_view);
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen sync_ctx.from_line = str_new(default_pool, 256);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx.header = str_new(default_pool, 4096);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx.index_sync_ctx = index_sync_ctx;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx.sync_view = sync_view;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx.t = trans;
aa0647f2debf0d48d504a321186f66c85596aaf4Timo Sirainen sync_ctx.mail_keyword_pool =
2e937ed8585299b2e879a28314902a5f644813d2Timo Sirainen pool_alloconly_create("mbox keywords", 256);
2e937ed8585299b2e879a28314902a5f644813d2Timo Sirainen sync_ctx.saved_keywords_pool =
343a527f805ca5cce78496b959d6def70e5d0cd4Timo Sirainen pool_alloconly_create("mbox saved keywords", 4096);
343a527f805ca5cce78496b959d6def70e5d0cd4Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* make sure we've read the latest keywords in index */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen (void)mail_index_get_keywords(mbox->ibox.index);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen i_array_init(&sync_ctx.mails, 64);
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen sync_ctx.flags = flags;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen sync_ctx.delay_writes = delay_writes || sync_ctx.mbox->mbox_readonly;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen sync_ctx.sync_changes =
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen index_sync_changes_init(&mbox->ibox, index_sync_ctx,
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen sync_view, trans,
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen sync_ctx.delay_writes);
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen if (!changed && delay_writes) {
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen /* if we have only flag changes, we don't need to open the
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen mbox file */
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen bool expunged;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen uint32_t uid;
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen mbox_sync_read_index_syncs(&sync_ctx, 1, &expunged);
b08b33d1f5ce3721dc2d83586c9cb0ca141331fdTimo Sirainen uid = expunged ? 1 :
30975737820f5855e2c26d81b574ae5f03a05407Timo Sirainen index_sync_changes_get_next_uid(sync_ctx.sync_changes);
30975737820f5855e2c26d81b574ae5f03a05407Timo Sirainen if (uid == 0) {
022412398e56a8f31ef111cfd7271498d64af9a9Timo Sirainen sync_ctx.index_sync_ctx = NULL;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen mbox_sync_context_free(&sync_ctx);
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen goto nothing_to_do;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen }
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen }
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen if (lock_id == 0) {
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen /* ok, we have something to do but no locks. we'll have to
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen restart syncing to avoid deadlocking. */
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen mbox_sync_context_free(&sync_ctx);
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen changed = 1;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen goto again;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen }
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen if (mbox_file_open_stream(mbox) < 0) {
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen mbox_sync_context_free(&sync_ctx);
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen (void)mbox_unlock(mbox, lock_id);
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen return -1;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen }
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen sync_ctx.file_input = sync_ctx.mbox->mbox_file_stream;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx.input = sync_ctx.mbox->mbox_stream;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen sync_ctx.write_fd = sync_ctx.mbox->mbox_lock_type != F_WRLCK ? -1 :
d6e2b2761c8e0b6923c883fb2ead2665ee954be5Timo Sirainen sync_ctx.mbox->mbox_fd;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen ret = mbox_sync_do(&sync_ctx, flags);
de4288b7369945a31c4001add9445fd0195a358dTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ret < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen mail_index_sync_rollback(&index_sync_ctx);
aa0647f2debf0d48d504a321186f66c85596aaf4Timo Sirainen else if (mail_index_sync_commit(&index_sync_ctx) < 0) {
aa0647f2debf0d48d504a321186f66c85596aaf4Timo Sirainen mail_storage_set_index_error(&mbox->ibox);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ret = -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else {
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen mbox->ibox.commit_log_file_seq = 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox->ibox.commit_log_file_offset = 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen sync_ctx.t = NULL;
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen sync_ctx.index_sync_ctx = NULL;
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (sync_ctx.base_uid_last != sync_ctx.next_uid-1 &&
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen ret == 0 && !sync_ctx.delay_writes &&
59ef34eafaf74d31ed88af444b22d1a0738a30aaTimo Sirainen sync_ctx.base_uid_last_offset != 0) {
59ef34eafaf74d31ed88af444b22d1a0738a30aaTimo Sirainen /* Rewrite uid_last in X-IMAPbase header if we've seen it
59ef34eafaf74d31ed88af444b22d1a0738a30aaTimo Sirainen (ie. the file isn't empty) */
59ef34eafaf74d31ed88af444b22d1a0738a30aaTimo Sirainen ret = mbox_rewrite_base_uid_last(&sync_ctx);
84e1634acc701d14e358e27f1beff5ad74f5004aTimo Sirainen }
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen if (ret == 0 && mbox->mbox_fd != -1 && mbox->ibox.keep_recent) {
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen /* try to set atime back to its original value */
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen struct utimbuf buf;
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen struct stat st;
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen if (fstat(mbox->mbox_fd, &st) < 0)
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen mbox_set_syscall_error(mbox, "fstat()");
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen else {
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen buf.modtime = st.st_mtime;
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen buf.actime = sync_ctx.orig_atime;
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen if (utime(mbox->path, &buf) < 0)
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen mbox_set_syscall_error(mbox, "utime()");
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen }
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen }
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen
9d0e1fa945103f2875cdf6d18b2013809f566ea7Timo Sirainen i_assert(lock_id != 0);
34d2ee1fa2b299267fcefd378f80690e7f601dfbTimo Sirainen
34d2ee1fa2b299267fcefd378f80690e7f601dfbTimo Sirainen if ((mbox->storage->storage.flags &
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0 && mbox->mbox_fd != -1) {
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen if (fdatasync(mbox->mbox_fd) < 0) {
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen mbox_set_syscall_error(mbox, "fdatasync()");
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen ret = -1;
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen }
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen }
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen if (mbox->mbox_lock_type != F_RDLCK) {
34d2ee1fa2b299267fcefd378f80690e7f601dfbTimo Sirainen /* drop to read lock */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen unsigned int read_lock_id = 0;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if (mbox_lock(mbox, F_RDLCK, &read_lock_id) <= 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ret = -1;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen else {
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if (mbox_unlock(mbox, lock_id) < 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ret = -1;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen lock_id = read_lock_id;
d9de52132072d80b8c268094b879c0ef5a108db3Timo Sirainen }
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen }
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if ((flags & MBOX_SYNC_LOCK_READING) == 0) {
34d2ee1fa2b299267fcefd378f80690e7f601dfbTimo Sirainen if (mbox_unlock(mbox, lock_id) < 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ret = -1;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen mbox_sync_context_free(&sync_ctx);
ccb70ccfd9a25e490aab46d15d9b8323ad9ea3bfTimo Sirainen return ret;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mbox_sync(struct mbox_mailbox *mbox, enum mbox_sync_flags flags)
4b41116563110d00330896a568eff1078c382827Timo Sirainen{
4b41116563110d00330896a568eff1078c382827Timo Sirainen int ret;
4b41116563110d00330896a568eff1078c382827Timo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainen mbox->syncing = TRUE;
4b41116563110d00330896a568eff1078c382827Timo Sirainen ret = mbox_sync_int(mbox, flags);
4b41116563110d00330896a568eff1078c382827Timo Sirainen mbox->syncing = FALSE;
4b41116563110d00330896a568eff1078c382827Timo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainen if (mbox->ibox.box.v.sync_notify != NULL)
4b41116563110d00330896a568eff1078c382827Timo Sirainen mbox->ibox.box.v.sync_notify(&mbox->ibox.box, 0, 0);
4b41116563110d00330896a568eff1078c382827Timo Sirainen return ret;
4b41116563110d00330896a568eff1078c382827Timo Sirainen}
4b41116563110d00330896a568eff1078c382827Timo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainenstruct mailbox_sync_context *
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainenmbox_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)box;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen enum mbox_sync_flags mbox_sync_flags = 0;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen int ret = 0;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!box->opened)
013e3b3942e9550fde619a0b3ce6bdd04edc4268Timo Sirainen index_storage_mailbox_open(&mbox->ibox);
013e3b3942e9550fde619a0b3ce6bdd04edc4268Timo Sirainen
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen if ((flags & MAILBOX_SYNC_FLAG_FAST) == 0 ||
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen mbox->ibox.sync_last_check + MAILBOX_FULL_SYNC_INTERVAL <=
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ioloop_time) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if ((flags & MAILBOX_SYNC_FLAG_FULL_READ) != 0 &&
29e945d8550f297707f3a5f627a938401046c0ccTimo Sirainen !mbox->mbox_very_dirty_syncs)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_sync_flags |= MBOX_SYNC_UNDIRTY;
95ed89440faab05cbb4f2473f2f4af19e848bde8Timo Sirainen if ((flags & MAILBOX_SYNC_FLAG_FULL_WRITE) != 0)
e5ee67f18b03015c88b579c8c1f17ebe6ce19b76Timo Sirainen mbox_sync_flags |= MBOX_SYNC_REWRITE;
e5ee67f18b03015c88b579c8c1f17ebe6ce19b76Timo Sirainen ret = mbox_sync(mbox, mbox_sync_flags);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
95ed89440faab05cbb4f2473f2f4af19e848bde8Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return index_mailbox_sync_init(box, flags, ret < 0);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen