bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2007-2018 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"
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen#include "index-pop3-uidl.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "dbox-attachment.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "dbox-save.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "sdbox-storage.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "sdbox-file.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "sdbox-sync.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct sdbox_save_context {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_save_context ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct sdbox_mailbox *mbox;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct sdbox_sync_context *sync_ctx;
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen struct dbox_file *cur_file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_file_append_context *append_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t first_saved_seq;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct dbox_file *) files;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen};
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek#define SDBOX_SAVECTX(s) container_of(DBOX_SAVECTX(s), struct sdbox_save_context, ctx)
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct dbox_file *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainensdbox_save_file_get_file(struct mailbox_transaction_context *t, uint32_t seq)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek struct sdbox_save_context *ctx = SDBOX_SAVECTX(t->save_ctx);
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen struct dbox_file *const *files, *file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(seq >= ctx->first_saved_seq);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen files = array_get(&ctx->files, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(count > 0);
5fc7434595b04687b14efafdc0c1597538da5c09Timo Sirainen i_assert(seq - ctx->first_saved_seq < count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen file = files[seq - ctx->first_saved_seq];
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen i_assert(((struct sdbox_file *)file)->written_to_disk);
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen return file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct mail_save_context *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainensdbox_save_alloc(struct mailbox_transaction_context *t)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek struct sdbox_mailbox *mbox = SDBOX_MAILBOX(t->box);
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek struct sdbox_save_context *ctx = SDBOX_SAVECTX(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;
2f5954db411ea9d63e831a01dd57211e55448463Timo Sirainen ctx->ctx.dbox_output = NULL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return &ctx->ctx.ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx = i_new(struct sdbox_save_context, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.ctx.transaction = t;
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen ctx->ctx.trans = t->itrans;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->mbox = mbox;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_array_init(&ctx->files, 32);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen t->save_ctx = &ctx->ctx.ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return t->save_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainenvoid sdbox_save_add_file(struct mail_save_context *_ctx, struct dbox_file *file)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen{
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek struct sdbox_save_context *ctx = SDBOX_SAVECTX(_ctx);
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen struct dbox_file *const *files;
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen unsigned int count;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
5fc7434595b04687b14efafdc0c1597538da5c09Timo Sirainen if (ctx->first_saved_seq == 0)
5fc7434595b04687b14efafdc0c1597538da5c09Timo Sirainen ctx->first_saved_seq = ctx->ctx.seq;
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen files = array_get(&ctx->files, &count);
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen if (count > 0) {
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen /* a plugin may leave a previously saved file open.
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen we'll close it here to avoid eating too many fds. */
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen dbox_file_close(files[count-1]);
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen }
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen array_append(&ctx->files, &file, 1);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen}
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint sdbox_save_begin(struct mail_save_context *_ctx, struct istream *input)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek struct sdbox_save_context *ctx = SDBOX_SAVECTX(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_file *file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen int ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen file = sdbox_file_create(ctx->mbox);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->append_ctx = dbox_file_append_init(file);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = dbox_file_get_append_stream(ctx->append_ctx,
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen &ctx->ctx.dbox_output);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ret <= 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(ret != 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_file_append_rollback(&ctx->append_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_file_unref(&file);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.failed = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen ctx->cur_file = file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_save_begin(&ctx->ctx, input);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen sdbox_save_add_file(_ctx, file);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ctx->ctx.failed ? -1 : 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int dbox_save_mail_write_metadata(struct dbox_save_context *ctx,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_file *file)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct sdbox_file *sfile = (struct sdbox_file *)file;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const ARRAY_TYPE(mail_attachment_extref) *extrefs_arr;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const struct mail_attachment_extref *extrefs;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_message_header dbox_msg_hdr;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uoff_t message_size;
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen guid_128_t guid_128;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(file->msg_header_size == sizeof(dbox_msg_hdr));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen message_size = ctx->dbox_output->offset -
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->msg_header_size - file->file_header_size;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1f19649986397419d014febd1337c6eb7b530f26Timo Sirainen dbox_save_write_metadata(&ctx->ctx, ctx->dbox_output,
1f19649986397419d014febd1337c6eb7b530f26Timo Sirainen message_size, NULL, guid_128);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_msg_header_fill(&dbox_msg_hdr, message_size);
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen if (o_stream_pwrite(ctx->dbox_output, &dbox_msg_hdr,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sizeof(dbox_msg_hdr),
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->file_header_size) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_file_set_syscall_error(file, "pwrite()");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen sfile->written_to_disk = TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* remember the attachment paths until commit time */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen extrefs_arr = index_attachment_save_get_extrefs(&ctx->ctx);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (extrefs_arr != NULL)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen extrefs = array_get(extrefs_arr, &count);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen else {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen extrefs = NULL;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen count = 0;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (count > 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen sfile->attachment_pool =
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen pool_alloconly_create("sdbox attachment paths", 512);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen p_array_init(&sfile->attachment_paths,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen sfile->attachment_pool, count);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen for (i = 0; i < count; i++) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const char *path = p_strdup(sfile->attachment_pool,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen extrefs[i].path);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen array_append(&sfile->attachment_paths, &path, 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int dbox_save_finish_write(struct mail_save_context *_ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct sdbox_save_context *ctx = (struct sdbox_save_context *)_ctx;
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen struct dbox_file **files;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.finished = TRUE;
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen if (ctx->ctx.dbox_output == NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen if (_ctx->data.save_date != (time_t)-1) {
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainen /* we can't change ctime, but we can add the date to cache */
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainen struct index_mail *mail = (struct index_mail *)_ctx->dest_mail;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen uint32_t t = _ctx->data.save_date;
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainen
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainen index_mail_cache_add(mail, MAIL_CACHE_SAVE_DATE, &t, sizeof(t));
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainen }
c3d9da3955043aef88c17b71f2081e894186aa6bTimo Sirainen dbox_save_end(&ctx->ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen files = array_idx_modifiable(&ctx->files, array_count(&ctx->files) - 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!ctx->ctx.failed) T_BEGIN {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (dbox_save_mail_write_metadata(&ctx->ctx, *files) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.failed = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } T_END;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9047d770bfbb93ab6af5363dedb2d01363877243Timo Sirainen if (ctx->ctx.failed) {
f776b9a125c59a96de6807e9558942cf7b7ab079Timo Sirainen index_storage_save_abort_last(&ctx->ctx.ctx, ctx->ctx.seq);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_file_append_rollback(&ctx->append_ctx);
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen dbox_file_unlink(*files);
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen dbox_file_unref(files);
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen array_delete(&ctx->files, array_count(&ctx->files) - 1, 1);
9047d770bfbb93ab6af5363dedb2d01363877243Timo Sirainen } else {
a62470cd293855dff816317d35356a989bda8f20Timo Sirainen dbox_file_append_checkpoint(ctx->append_ctx);
a62470cd293855dff816317d35356a989bda8f20Timo Sirainen if (dbox_file_append_commit(&ctx->append_ctx) < 0)
a62470cd293855dff816317d35356a989bda8f20Timo Sirainen ctx->ctx.failed = TRUE;
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen dbox_file_close(*files);
a62470cd293855dff816317d35356a989bda8f20Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_stream_unref(&ctx->ctx.input);
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen ctx->ctx.dbox_output = NULL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ctx->ctx.failed ? -1 : 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint sdbox_save_finish(struct mail_save_context *ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen int ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = dbox_save_finish_write(ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen index_save_context_free(ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid sdbox_save_cancel(struct mail_save_context *_ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
804fa3f03bd9170272168a5ad214053bbe3160c7Josef 'Jeff' Sipek struct dbox_save_context *ctx = DBOX_SAVECTX(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->failed = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (void)sdbox_save_finish(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int dbox_save_assign_uids(struct sdbox_save_context *ctx,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const ARRAY_TYPE(seq_range) *uids)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_file *const *files;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct seq_range_iter iter;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count, n = 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uint32_t uid;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen bool ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen seq_range_array_iter_init(&iter, uids);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen files = array_get(&ctx->files, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct sdbox_file *sfile = (struct sdbox_file *)files[i];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = seq_range_array_iter_nth(&iter, n++, &uid);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(ret);
172b6edea36e425b0d0c35a854721ae63f57c289Timo Sirainen if (sdbox_file_assign_uid(sfile, uid, FALSE) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen if (ctx->ctx.highest_pop3_uidl_seq == i+1) {
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen index_pop3_uidl_set_max_uid(&ctx->mbox->box,
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen ctx->ctx.trans, uid);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(!seq_range_array_iter_nth(&iter, n, &uid));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainenstatic int dbox_save_assign_stub_uids(struct sdbox_save_context *ctx)
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen{
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen struct dbox_file *const *files;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen unsigned int i, count;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen files = array_get(&ctx->files, &count);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen for (i = 0; i < count; i++) {
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen struct sdbox_file *sfile = (struct sdbox_file *)files[i];
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen uint32_t uid;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen mail_index_lookup_uid(ctx->ctx.trans->view,
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen ctx->first_saved_seq + i, &uid);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen i_assert(uid != 0);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
172b6edea36e425b0d0c35a854721ae63f57c289Timo Sirainen if (sdbox_file_assign_uid(sfile, uid, TRUE) < 0)
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen return -1;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen }
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen return 0;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen}
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void dbox_save_unref_files(struct sdbox_save_context *ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct dbox_file **files;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen files = array_get_modifiable(&ctx->files, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->ctx.failed) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct sdbox_file *sfile =
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen (struct sdbox_file *)files[i];
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen (void)sdbox_file_unlink_aborted_save(sfile);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_file_unref(&files[i]);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_free(&ctx->files);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint sdbox_transaction_save_commit_pre(struct mail_save_context *_ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek struct sdbox_save_context *ctx = SDBOX_SAVECTX(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox_transaction_context *_t = _ctx->transaction;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct mail_index_header *hdr;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(ctx->ctx.finished);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
c7a50b2c29780eaa3668bbac738e3fa3e4e171e8Timo Sirainen if (array_count(&ctx->files) == 0) {
c7a50b2c29780eaa3668bbac738e3fa3e4e171e8Timo Sirainen /* the mail must be freed in the commit_pre() */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
c7a50b2c29780eaa3668bbac738e3fa3e4e171e8Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (sdbox_sync_begin(ctx->mbox, SDBOX_SYNC_FLAG_FORCE |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen SDBOX_SYNC_FLAG_FSYNC, &ctx->sync_ctx) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sdbox_transaction_save_rollback(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen /* update dbox header flags */
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen dbox_save_update_header_flags(&ctx->ctx, ctx->sync_ctx->sync_view,
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen ctx->mbox->hdr_ext_id, offsetof(struct sdbox_index_header, flags));
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen hdr = mail_index_get_header(ctx->sync_ctx->sync_view);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen if ((_ctx->transaction->flags & MAILBOX_TRANSACTION_FLAG_FILL_IN_STUB) == 0) {
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen /* assign UIDs for new messages */
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen mail_index_append_finish_uids(ctx->ctx.trans, hdr->next_uid,
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen &_t->changes->saved_uids);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen if (dbox_save_assign_uids(ctx, &_t->changes->saved_uids) < 0) {
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen sdbox_transaction_save_rollback(_ctx);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen return -1;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen }
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen } else {
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen /* assign UIDs that we stashed away */
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen if (dbox_save_assign_stub_uids(ctx) < 0) {
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen sdbox_transaction_save_rollback(_ctx);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen return -1;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen _t->changes->uid_validity = hdr->uid_validity;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainenvoid sdbox_transaction_save_commit_post(struct mail_save_context *_ctx,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen struct mail_index_transaction_commit_result *result)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek struct sdbox_save_context *ctx = SDBOX_SAVECTX(_ctx);
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen struct mail_storage *storage = _ctx->transaction->box->storage;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen _ctx->transaction = NULL; /* transaction is already freed */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (array_count(&ctx->files) == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sdbox_transaction_save_rollback(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen mail_index_sync_set_commit_result(ctx->sync_ctx->index_sync_ctx,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen result);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (sdbox_sync_finish(&ctx->sync_ctx, TRUE) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->ctx.failed = TRUE;
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) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mail_set_critical(_ctx->dest_mail,
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen "fdatasync_path(%s) failed: %m", box_path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sdbox_transaction_save_rollback(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid sdbox_transaction_save_rollback(struct mail_save_context *_ctx)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek struct sdbox_save_context *ctx = SDBOX_SAVECTX(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!ctx->ctx.finished)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sdbox_save_cancel(_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_save_unref_files(ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->sync_ctx != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (void)sdbox_sync_finish(&ctx->sync_ctx, FALSE);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_free(ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}