mdbox-save.c revision 0001f76bf725c5cf403bade8556f142dd43144ee
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2007-2012 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "lib.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "array.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "fdatasync-path.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "hex-binary.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "hex-dec.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "str.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "istream.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "istream-crlf.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "ostream.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "write-full.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "index-mail.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mail-copy.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "dbox-save.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mdbox-storage.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mdbox-map.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mdbox-file.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mdbox-sync.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <stdlib.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct dbox_save_mail {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_file_append_context *file_append;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t seq;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t append_offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen};
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct mdbox_save_context {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_save_context ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_mailbox *mbox;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_sync_context *sync_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen struct dbox_file *cur_file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_file_append_context *cur_file_append;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen struct mdbox_map_append_context *append_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ARRAY_TYPE(uint32_t) copy_map_uids;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen struct mdbox_map_atomic_context *atomic;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen struct mdbox_map_transaction_context *map_trans;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct dbox_save_mail) mails;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen};
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainenstatic struct dbox_file *
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainenmdbox_copy_file_get_file(struct mailbox_transaction_context *t,
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen uint32_t seq, uoff_t *offset_r)
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen{
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen struct mdbox_save_context *ctx =
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen (struct mdbox_save_context *)t->save_ctx;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen const struct mdbox_mail_index_record *rec;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen const void *data;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen bool expunged;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen uint32_t file_id;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen mail_index_lookup_ext(t->view, seq, ctx->mbox->ext_id,
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen &data, &expunged);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen rec = data;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (mdbox_map_lookup(ctx->mbox->storage->map, rec->map_uid,
714c6a150480112eb1a5f309d0cc39b60613a719Timo Sirainen &file_id, offset_r) < 0)
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen i_unreached();
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen return mdbox_file_init(ctx->mbox->storage, file_id);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen}
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct dbox_file *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmdbox_save_file_get_file(struct mailbox_transaction_context *t,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t seq, uoff_t *offset_r)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_save_context *ctx =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (struct mdbox_save_context *)t->save_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct dbox_save_mail *mails, *mail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mails = array_get(&ctx->mails, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(count > 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(seq >= mails[0].seq);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9a02317c852face76737763fa6ec43b444688de5Timo Sirainen mail = &mails[seq - mails[0].seq];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(mail->seq == seq);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen if (mail->file_append == NULL) {
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen /* copied mail */
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen return mdbox_copy_file_get_file(t, seq, offset_r);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen }
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen /* saved mail */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (dbox_file_append_flush(mail->file_append) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.failed = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen mail->file_append->file->refcount++;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *offset_r = mail->append_offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return mail->file_append->file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct mail_save_context *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmdbox_save_alloc(struct mailbox_transaction_context *t)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_mailbox *mbox = (struct mdbox_mailbox *)t->box;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_save_context *ctx =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (struct mdbox_save_context *)t->save_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert((t->flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* use the existing allocated structure */
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen ctx->cur_file = NULL;
e2eac5bb5637c2d4aaf453389750740931822b92Timo Sirainen ctx->ctx.failed = FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.finished = FALSE;
e2bdacc34dde56aa664059ab56e8b77e82bd1805Timo Sirainen ctx->ctx.dbox_output = NULL;
e2bdacc34dde56aa664059ab56e8b77e82bd1805Timo Sirainen ctx->cur_file_append = NULL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return &ctx->ctx.ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx = i_new(struct mdbox_save_context, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.ctx.transaction = t;
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen ctx->ctx.trans = t->itrans;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->mbox = mbox;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen ctx->atomic = mdbox_map_atomic_begin(mbox->storage->map);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen ctx->append_ctx = mdbox_map_append_begin(ctx->atomic);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_array_init(&ctx->mails, 32);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen t->save_ctx = &ctx->ctx.ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return t->save_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mdbox_save_begin(struct mail_save_context *_ctx, struct istream *input)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_save_mail *save_mail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uoff_t mail_size, append_offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* get the size of the mail to be saved, if possible */
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen if (i_stream_get_size(input, TRUE, &mail_size) <= 0) {
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen /* we couldn't find out the exact size. fallback to non-exact,
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen maybe it'll give something useful. the mail size is used
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen only to figure out if it's causing mdbox file to grow
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen too large. */
46908da82cd45dd90ca7e438c8453bc9669868ecTimo Sirainen if (i_stream_get_size(input, FALSE, &mail_size) <= 0)
46908da82cd45dd90ca7e438c8453bc9669868ecTimo Sirainen mail_size = 0;
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen }
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (mdbox_map_append_next(ctx->append_ctx, mail_size, 0,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen &ctx->cur_file_append,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen &ctx->ctx.dbox_output) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.failed = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen i_assert(ctx->ctx.dbox_output->offset <= (uint32_t)-1);
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen append_offset = ctx->ctx.dbox_output->offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen ctx->cur_file = ctx->cur_file_append->file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_save_begin(&ctx->ctx, input);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen save_mail = array_append_space(&ctx->mails);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen save_mail->file_append = ctx->cur_file_append;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen save_mail->seq = ctx->ctx.seq;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen save_mail->append_offset = append_offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ctx->ctx.failed ? -1 : 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int mdbox_save_mail_write_metadata(struct mdbox_save_context *ctx,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_save_mail *mail)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_file *file = mail->file_append->file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_message_header dbox_msg_hdr;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uoff_t message_size;
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen guid_128_t guid_128;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(file->msg_header_size == sizeof(dbox_msg_hdr));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen message_size = ctx->ctx.dbox_output->offset -
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail->append_offset - mail->file_append->file->msg_header_size;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen dbox_save_write_metadata(&ctx->ctx.ctx, ctx->ctx.dbox_output,
1f19649986397419d014febd1337c6eb7b530f26Timo Sirainen message_size, ctx->mbox->box.name, guid_128);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* save the 128bit GUID to index so if the map index gets corrupted
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen we can still find the message */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_index_update_ext(ctx->ctx.trans, ctx->ctx.seq,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->mbox->guid_ext_id, guid_128, NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_msg_header_fill(&dbox_msg_hdr, message_size);
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen if (o_stream_pwrite(ctx->ctx.dbox_output, &dbox_msg_hdr,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sizeof(dbox_msg_hdr), mail->append_offset) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_file_set_syscall_error(file, "pwrite()");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int mdbox_save_finish_write(struct mail_save_context *_ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen struct dbox_save_mail *mail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.finished = TRUE;
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen if (ctx->ctx.dbox_output == NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen dbox_save_end(&ctx->ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen mail = array_idx_modifiable(&ctx->mails, array_count(&ctx->mails) - 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!ctx->ctx.failed) T_BEGIN {
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen if (mdbox_save_mail_write_metadata(ctx, mail) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.failed = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen mdbox_map_append_finish(ctx->append_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } T_END;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen if (mail->file_append->file->input != NULL) {
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen /* if we try to read the saved mail before unlocking file,
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen make sure the input stream doesn't have stale data */
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen i_stream_sync(mail->file_append->file->input);
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_stream_unref(&ctx->ctx.input);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->ctx.failed) {
9047d770bfbb93ab6af5363dedb2d01363877243Timo Sirainen mail_index_expunge(ctx->ctx.trans, ctx->ctx.seq);
836e57b1e7817d008f8ae05cd4b506f420fed80dTimo Sirainen mdbox_map_append_abort(ctx->append_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_delete(&ctx->mails, array_count(&ctx->mails) - 1, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mdbox_save_finish(struct mail_save_context *ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen int ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = mdbox_save_finish_write(ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen index_save_context_free(ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid mdbox_save_cancel(struct mail_save_context *_ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->failed = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (void)mdbox_save_finish(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainenstatic void
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainenmdbox_save_set_map_uids(struct mdbox_save_context *ctx,
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen uint32_t first_map_uid, uint32_t last_map_uid)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen{
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen struct mdbox_mailbox *mbox = ctx->mbox;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen struct mail_index_view *view = ctx->ctx.ctx.transaction->view;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen const struct mdbox_mail_index_record *old_rec;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen struct mdbox_mail_index_record rec;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen const struct dbox_save_mail *mails;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen unsigned int i, count;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen const void *data;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen bool expunged;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen uint32_t next_map_uid = first_map_uid;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen mdbox_update_header(mbox, ctx->ctx.trans, NULL);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen memset(&rec, 0, sizeof(rec));
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen rec.save_date = ioloop_time;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen mails = array_get(&ctx->mails, &count);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen for (i = 0; i < count; i++) {
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen mail_index_lookup_ext(view, mails[i].seq, mbox->ext_id,
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen &data, &expunged);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen old_rec = data;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (old_rec != NULL && old_rec->map_uid != 0) {
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen /* message was copied. keep the existing map uid */
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen continue;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen }
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen rec.map_uid = next_map_uid++;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen mail_index_update_ext(ctx->ctx.trans, mails[i].seq,
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen mbox->ext_id, &rec, NULL);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen }
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen i_assert(next_map_uid == last_map_uid + 1);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen}
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mdbox_transaction_save_commit_pre(struct mail_save_context *_ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox_transaction_context *_t = _ctx->transaction;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct mail_index_header *hdr;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t first_map_uid, last_map_uid;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(ctx->ctx.finished);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen /* flush/fsync writes to m.* files before locking the map */
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen if (mdbox_map_append_flush(ctx->append_ctx) < 0) {
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen mdbox_transaction_save_rollback(_ctx);
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen return -1;
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen }
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen
f1612f8421207632e1dc9addd6c23e7f7098a54cTimo Sirainen /* make sure the map gets locked */
56aa9083e1742d0083885aaf0c5b8581577731aeTimo Sirainen if (mdbox_map_atomic_lock(ctx->atomic) < 0) {
56aa9083e1742d0083885aaf0c5b8581577731aeTimo Sirainen mdbox_transaction_save_rollback(_ctx);
f1612f8421207632e1dc9addd6c23e7f7098a54cTimo Sirainen return -1;
56aa9083e1742d0083885aaf0c5b8581577731aeTimo Sirainen }
f1612f8421207632e1dc9addd6c23e7f7098a54cTimo Sirainen
fb5efc6ed69da679d9da31ef62daa7024de18212Timo Sirainen /* assign map UIDs for newly saved messages. they're written to
fb5efc6ed69da679d9da31ef62daa7024de18212Timo Sirainen transaction log immediately within this function, but the map
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen is left locked. */
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (mdbox_map_append_assign_map_uids(ctx->append_ctx, &first_map_uid,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen &last_map_uid) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mdbox_transaction_save_rollback(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen /* lock the mailbox after map to avoid deadlocks. if we've noticed
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen any corruption, deal with it later, otherwise we won't have
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen up-to-date atomic->sync_view */
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (mdbox_sync_begin(ctx->mbox, MDBOX_SYNC_FLAG_NO_PURGE |
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen MDBOX_SYNC_FLAG_FORCE |
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen MDBOX_SYNC_FLAG_FSYNC |
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen MDBOX_SYNC_FLAG_NO_REBUILD, ctx->atomic,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen &ctx->sync_ctx) < 0) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mdbox_transaction_save_rollback(_ctx);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return -1;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* assign UIDs for new messages */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen hdr = mail_index_get_header(ctx->sync_ctx->sync_view);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_index_append_finish_uids(ctx->ctx.trans, hdr->next_uid,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen &_t->changes->saved_uids);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
fb5efc6ed69da679d9da31ef62daa7024de18212Timo Sirainen /* save map UIDs to mailbox index */
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (first_map_uid != 0)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen mdbox_save_set_map_uids(ctx, first_map_uid, last_map_uid);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* increase map's refcount for copied mails */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (array_is_created(&ctx->copy_map_uids)) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen ctx->map_trans = mdbox_map_transaction_begin(ctx->atomic, FALSE);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (mdbox_map_update_refcounts(ctx->map_trans,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen &ctx->copy_map_uids, 1) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mdbox_transaction_save_rollback(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->ctx.mail != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_free(&ctx->ctx.mail);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen _t->changes->uid_validity = hdr->uid_validity;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainenvoid mdbox_transaction_save_commit_post(struct mail_save_context *_ctx,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen struct mail_index_transaction_commit_result *result)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen struct mail_storage *storage = _ctx->transaction->box->storage;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen _ctx->transaction = NULL; /* transaction is already freed */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen mail_index_sync_set_commit_result(ctx->sync_ctx->index_sync_ctx,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen result);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* finish writing the mailbox APPENDs */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mdbox_sync_finish(&ctx->sync_ctx, TRUE) == 0) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* commit refcount increases for copied mails */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (ctx->map_trans != NULL) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (mdbox_map_transaction_commit(ctx->map_trans) < 0)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mdbox_map_atomic_set_failed(ctx->atomic);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* flush file append writes */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (mdbox_map_append_commit(ctx->append_ctx) < 0)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mdbox_map_atomic_set_failed(ctx->atomic);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen mdbox_map_append_free(&ctx->append_ctx);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* update the sync tail offset, everything else
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen was already written at this point. */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen (void)mdbox_map_atomic_finish(&ctx->atomic);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen const char *box_path = mailbox_get_path(&ctx->mbox->box);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (fdatasync_path(box_path) < 0) {
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen mail_storage_set_critical(storage,
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen "fdatasync_path(%s) failed: %m", box_path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mdbox_transaction_save_rollback(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid mdbox_transaction_save_rollback(struct mail_save_context *_ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!ctx->ctx.finished)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mdbox_save_cancel(&ctx->ctx.ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->append_ctx != NULL)
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen mdbox_map_append_free(&ctx->append_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->map_trans != NULL)
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen mdbox_map_transaction_free(&ctx->map_trans);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (ctx->atomic != NULL)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen (void)mdbox_map_atomic_finish(&ctx->atomic);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (array_is_created(&ctx->copy_map_uids))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_free(&ctx->copy_map_uids);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->sync_ctx != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (void)mdbox_sync_finish(&ctx->sync_ctx, FALSE);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->ctx.mail != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_free(&ctx->ctx.mail);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_free(&ctx->mails);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_free(ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mdbox_copy(struct mail_save_context *_ctx, struct mail *mail)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen struct dbox_save_mail *save_mail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_mailbox *src_mbox;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_mail_index_record rec;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const void *data;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen bool expunged;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.finished = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainen if (mail->box->storage != _ctx->transaction->box->storage ||
90e39174d397567c101dbf694761371af3682928Timo Sirainen _ctx->transaction->box->disable_reflink_copy_to ||
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen _ctx->data.guid != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return mail_storage_copy(_ctx, mail);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen src_mbox = (struct mdbox_mailbox *)mail->box;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen memset(&rec, 0, sizeof(rec));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen rec.save_date = ioloop_time;
767ff4367960efd5fa868f3b56f850fd4c205c8bTimo Sirainen if (mdbox_mail_lookup(src_mbox, mail->transaction->view, mail->seq,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen &rec.map_uid) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* remember the map_uid so we can later increase its refcount */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!array_is_created(&ctx->copy_map_uids))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_array_init(&ctx->copy_map_uids, 32);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_append(&ctx->copy_map_uids, &rec.map_uid, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* add message to mailbox index */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_save_add_to_index(&ctx->ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_index_update_ext(ctx->ctx.trans, ctx->ctx.seq,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->mbox->ext_id, &rec, NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
767ff4367960efd5fa868f3b56f850fd4c205c8bTimo Sirainen mail_index_lookup_ext(mail->transaction->view, mail->seq,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen src_mbox->guid_ext_id, &data, &expunged);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (data != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_index_update_ext(ctx->ctx.trans, ctx->ctx.seq,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->mbox->guid_ext_id, data, NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1554bed8d2b4e4286c10f7d6bcf716b246bd5bafTimo Sirainen index_copy_cache_fields(_ctx, mail, ctx->ctx.seq);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen save_mail = array_append_space(&ctx->mails);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen save_mail->seq = ctx->ctx.seq;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen if (_ctx->dest_mail != NULL)
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen mail_set_seq_saving(_ctx->dest_mail, ctx->ctx.seq);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}