maildir-save.c revision fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "lib.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "ioloop.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "ostream.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "ostream-crlf.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "str.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "maildir-storage.h"
fc4b301e2dd86c096b9c41ad1b011b752fffd570Timo Sirainen#include "maildir-uidlist.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
12ab808b472ed51923945efac4156a380bd58d57Timo Sirainen#include <stdio.h>
01afde78e4ff6b4c75f75257a7972eca37114383Timo Sirainen#include <stdlib.h>
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen#include <unistd.h>
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen#include <fcntl.h>
ec1a4f4306496380e9d96ee08a3718a669d0875aTimo Sirainen#include <utime.h>
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen#include <sys/stat.h>
7a5e2e937f0f388465c2938645ee971b4fd01bf1Timo Sirainen
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainenstruct maildir_filename {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct maildir_filename *next;
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen const char *basename, *dest;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen};
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainenstruct maildir_save_context {
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen struct mail_save_context ctx;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen pool_t pool;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct index_mailbox *ibox;
4e0204dbac352e271c79cfa6c74a71145a058de5Timo Sirainen struct mail_index_transaction *trans;
4e0204dbac352e271c79cfa6c74a71145a058de5Timo Sirainen struct maildir_uidlist_sync_ctx *sync_ctx;
4e0204dbac352e271c79cfa6c74a71145a058de5Timo Sirainen
4e0204dbac352e271c79cfa6c74a71145a058de5Timo Sirainen const char *tmpdir, *newdir, *curdir;
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainen struct maildir_filename *files;
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainen
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainen struct istream *input;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen struct ostream *output;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen int fd;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen time_t received_date;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen uint32_t seq;
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen unsigned int save_crlf:1;
73b8333f9a979efefe1db70f22c63edec5ad4466Timo Sirainen unsigned int failed:1;
0171540a6764f714b8b753ba209ec9a83c213d25Timo Sirainen};
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainenstatic int maildir_file_move(struct maildir_save_context *ctx,
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen const char *basename, const char *dest)
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen{
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen const char *tmp_path, *new_path;
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen int ret;
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen t_push();
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen /* if we have flags, we'll move it to cur/ directly, because files in
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen new/ directory can't have flags. alternative would be to write it
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen in new/ and set the flags dirty in index file, but in that case
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen external MUAs would see wrong flags. */
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen tmp_path = t_strconcat(ctx->tmpdir, "/", basename, NULL);
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen new_path = dest == NULL ?
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen t_strconcat(ctx->newdir, "/", basename, NULL) :
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen t_strconcat(ctx->curdir, "/", dest, NULL);
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen if (link(tmp_path, new_path) == 0)
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen ret = 0;
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen else {
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen ret = -1;
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen if (ENOSPACE(errno)) {
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen mail_storage_set_error(ctx->ibox->box.storage,
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen "Not enough disk space");
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen } else {
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen mail_storage_set_critical(ctx->ibox->box.storage,
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen "link(%s, %s) failed: %m", tmp_path, new_path);
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen }
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen }
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen if (unlink(tmp_path) < 0 && errno != ENOENT) {
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen mail_storage_set_critical(ctx->ibox->box.storage,
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen "unlink(%s) failed: %m", tmp_path);
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen }
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen t_pop();
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen return ret;
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen}
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainenstatic struct maildir_save_context *
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainenmaildir_save_transaction_init(struct maildir_transaction_context *t)
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen{
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen struct index_mailbox *ibox = t->ictx.ibox;
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen struct maildir_save_context *ctx;
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen pool_t pool;
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen pool = pool_alloconly_create("maildir_save_context", 4096);
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen ctx = p_new(pool, struct maildir_save_context, 1);
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen ctx->ctx.transaction = &t->ictx.mailbox_ctx;
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen ctx->pool = pool;
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen ctx->ibox = ibox;
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen ctx->trans = t->ictx.trans;
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen ctx->tmpdir = p_strconcat(pool, ibox->path, "/tmp", NULL);
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen ctx->newdir = p_strconcat(pool, ibox->path, "/new", NULL);
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen ctx->curdir = p_strconcat(pool, ibox->path, "/cur", NULL);
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ctx->save_crlf = getenv("MAIL_SAVE_CRLF") != NULL;
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen return ctx;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstruct mail_save_context *
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainenmaildir_save_init(struct mailbox_transaction_context *_t,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen enum mail_flags flags, struct mail_keywords *keywords,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen time_t received_date, int timezone_offset __attr_unused__,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const char *from_envelope __attr_unused__,
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen struct istream *input, int want_mail __attr_unused__)
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen{
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen struct maildir_transaction_context *t =
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen (struct maildir_transaction_context *)_t;
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen struct maildir_save_context *ctx;
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen struct index_mailbox *ibox = t->ictx.ibox;
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen struct maildir_filename *mf;
33ef806e0d378a0b2326cd939714c9070502d1e5Timo Sirainen struct ostream *output;
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen const char *fname, *dest_fname, *path;
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen i_assert((t->ictx.flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen t_push();
36175032e12e7dfe67f92ee7c2065fdc6865aefdTimo Sirainen
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen if (t->save_ctx == NULL)
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen t->save_ctx = maildir_save_transaction_init(t);
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen ctx = t->save_ctx;
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* create a new file in tmp/ directory */
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen ctx->fd = maildir_create_tmp(ibox, ctx->tmpdir, ibox->mail_create_mode,
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen &path);
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen if (ctx->fd == -1) {
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen ctx->failed = TRUE;
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen t_pop();
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen return &ctx->ctx;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen }
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen fname = strrchr(path, '/');
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen i_assert(fname != NULL);
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen fname++;
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen ctx->received_date = received_date;
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen ctx->input = input;
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen output = o_stream_create_file(ctx->fd, system_pool, 0, FALSE);
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen ctx->output = ctx->save_crlf ?
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen o_stream_create_crlf(default_pool, output) :
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen o_stream_create_lf(default_pool, output);
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen o_stream_unref(output);
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen flags &= ~MAIL_RECENT;
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen if (ibox->keep_recent)
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen flags |= MAIL_RECENT;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* now, we want to be able to rollback the whole append session,
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen so we'll just store the name of this temp file and move it later
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen into new/ or cur/. if dest_fname is NULL, it's moved to new/,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen otherwise to cur/. */
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainen dest_fname = flags == MAIL_RECENT ? NULL :
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen maildir_filename_set_flags(fname, flags, NULL); // FIXME
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen mf = p_new(ctx->pool, struct maildir_filename, 1);
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainen mf->next = ctx->files;
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainen mf->basename = p_strdup(ctx->pool, fname);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen mf->dest = p_strdup(ctx->pool, dest_fname);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen ctx->files = mf;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* insert into index */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen mail_index_append(ctx->trans, 0, &ctx->seq);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE, flags);
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen if (keywords != NULL) {
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen mail_index_update_keywords(ctx->trans, ctx->seq,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen MODIFY_REPLACE, keywords);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen }
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen t_pop();
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen ctx->failed = FALSE;
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainen return &ctx->ctx;
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainen}
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainen
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainenint maildir_save_continue(struct mail_save_context *_ctx)
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainen{
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainen struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainen
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainen if (ctx->failed)
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainen return -1;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (o_stream_send_istream(ctx->output, ctx->input) < 0) {
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen ctx->failed = TRUE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return -1;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen }
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return 0;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen}
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainenint maildir_save_finish(struct mail_save_context *_ctx, struct mail *dest_mail)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen{
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen struct utimbuf buf;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen const char *path;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen int output_errno;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (ctx->failed && ctx->fd == -1) {
1618629fd55e914c8d2e28fc01b8264613f00a99Timo Sirainen /* tmp file creation failed */
1618629fd55e914c8d2e28fc01b8264613f00a99Timo Sirainen return -1;
1618629fd55e914c8d2e28fc01b8264613f00a99Timo Sirainen }
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen t_push();
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen path = t_strconcat(ctx->tmpdir, "/", ctx->files->basename, NULL);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen if (ctx->received_date != (time_t)-1) {
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen /* set the received_date by modifying mtime */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen buf.actime = ioloop_time;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen buf.modtime = ctx->received_date;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if (utime(path, &buf) < 0) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen ctx->failed = TRUE;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen mail_storage_set_critical(ctx->ibox->box.storage,
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen "utime(%s) failed: %m", path);
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen }
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen }
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen output_errno = ctx->output->stream_errno;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen o_stream_unref(ctx->output);
de44e83f4b5e366e57e973b26f2eb0ad26984945Timo Sirainen ctx->output = NULL;
de44e83f4b5e366e57e973b26f2eb0ad26984945Timo Sirainen
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen /* FIXME: when saving multiple messages, we could get better
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen performance if we left the fd open and fsync()ed it later */
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen if (fsync(ctx->fd) < 0) {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen mail_storage_set_critical(ctx->ibox->box.storage,
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainen "fsync(%s) failed: %m", path);
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen ctx->failed = TRUE;
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen }
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen if (close(ctx->fd) < 0) {
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen mail_storage_set_critical(ctx->ibox->box.storage,
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen "close(%s) failed: %m", path);
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen ctx->failed = TRUE;
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen }
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen ctx->fd = -1;
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen if (ctx->failed) {
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen /* delete the tmp file */
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainen if (unlink(path) < 0 && errno != ENOENT) {
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainen mail_storage_set_critical(ctx->ibox->box.storage,
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen "unlink(%s) failed: %m", path);
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainen }
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainen
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen errno = output_errno;
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen if (ENOSPACE(errno)) {
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen mail_storage_set_error(ctx->ibox->box.storage,
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen "Not enough disk space");
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen } else if (errno != 0) {
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen mail_storage_set_critical(ctx->ibox->box.storage,
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen "write(%s) failed: %m", ctx->ibox->path);
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainen }
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainen
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainen ctx->files = ctx->files->next;
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainen t_pop();
6a865d46c3704c7d9781f5f249d87796ec5d3591Timo Sirainen return -1;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen }
059b4bb561737ce8e15620149140b122021929c9Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (dest_mail != NULL) {
059b4bb561737ce8e15620149140b122021929c9Timo Sirainen i_assert(ctx->seq != 0);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
059b4bb561737ce8e15620149140b122021929c9Timo Sirainen if (mail_set_seq(dest_mail, ctx->seq) < 0)
059b4bb561737ce8e15620149140b122021929c9Timo Sirainen return -1;
059b4bb561737ce8e15620149140b122021929c9Timo Sirainen }
059b4bb561737ce8e15620149140b122021929c9Timo Sirainen
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen t_pop();
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen return 0;
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen}
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainenvoid maildir_save_cancel(struct mail_save_context *_ctx)
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen{
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen ctx->failed = TRUE;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen (void)maildir_save_finish(_ctx, NULL);
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen}
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainenstatic void maildir_save_commit_abort(struct maildir_save_context *ctx,
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen struct maildir_filename *pos)
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen{
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen struct maildir_filename *mf;
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen string_t *str;
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen t_push();
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen str = t_str_new(1024);
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen /* try to unlink the mails already moved */
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen for (mf = ctx->files; mf != pos; mf = mf->next) {
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen str_truncate(str, 0);
7c2b57939462fc2022d7e7f7aecd768ec1a8ba38Timo Sirainen if (mf->dest == NULL)
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen str_printfa(str, "%s/%s", ctx->newdir, mf->basename);
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen else
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen str_printfa(str, "%s/%s", ctx->curdir, mf->dest);
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen (void)unlink(str_c(str));
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen }
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen ctx->files = pos;
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen t_pop();
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen
7c2b57939462fc2022d7e7f7aecd768ec1a8ba38Timo Sirainen maildir_transaction_save_rollback(ctx);
7c2b57939462fc2022d7e7f7aecd768ec1a8ba38Timo Sirainen}
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainenint maildir_transaction_save_commit_pre(struct maildir_save_context *ctx)
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen{
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen struct maildir_index_sync_context *sync_ctx;
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen struct maildir_filename *mf;
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen uint32_t first_uid, last_uid;
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen enum maildir_uidlist_rec_flag flags;
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen const char *fname;
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen int ret;
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen
7c2b57939462fc2022d7e7f7aecd768ec1a8ba38Timo Sirainen i_assert(ctx->output == NULL);
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen sync_ctx = maildir_sync_index_begin(ctx->ibox);
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen if (sync_ctx == NULL) {
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen maildir_save_commit_abort(ctx, ctx->files);
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen return -1;
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen }
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen ret = maildir_uidlist_lock(ctx->ibox->uidlist);
7c2b57939462fc2022d7e7f7aecd768ec1a8ba38Timo Sirainen if (ret <= 0) {
7c2b57939462fc2022d7e7f7aecd768ec1a8ba38Timo Sirainen /* error or timeout - our transaction is broken */
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen maildir_sync_index_abort(sync_ctx);
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen maildir_save_commit_abort(ctx, ctx->files);
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen return -1;
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen }
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (maildir_sync_index_finish(sync_ctx, TRUE) < 0) {
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen maildir_save_commit_abort(ctx, ctx->files);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return -1;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen }
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen first_uid = maildir_uidlist_get_next_uid(ctx->ibox->uidlist);
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen mail_index_append_assign_uids(ctx->trans, first_uid, &last_uid);
ec1a4f4306496380e9d96ee08a3718a669d0875aTimo Sirainen
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen flags = MAILDIR_UIDLIST_REC_FLAG_NEW_DIR |
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen MAILDIR_UIDLIST_REC_FLAG_RECENT;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* move them into new/ */
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen ctx->sync_ctx = maildir_uidlist_sync_init(ctx->ibox->uidlist, TRUE);
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen for (mf = ctx->files; mf != NULL; mf = mf->next) {
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen fname = mf->dest != NULL ? mf->dest : mf->basename;
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen if (maildir_file_move(ctx, mf->basename, mf->dest) < 0 ||
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainen maildir_uidlist_sync_next(ctx->sync_ctx,
e982ce57ae92ab7ac22496357219697676fab731Timo Sirainen fname, flags) < 0) {
633a3da9d3e9a5befd3405f6651043a6bdd327cbTimo Sirainen (void)maildir_uidlist_sync_deinit(ctx->sync_ctx);
633a3da9d3e9a5befd3405f6651043a6bdd327cbTimo Sirainen maildir_save_commit_abort(ctx, mf);
e982ce57ae92ab7ac22496357219697676fab731Timo Sirainen return -1;
e982ce57ae92ab7ac22496357219697676fab731Timo Sirainen }
df6551ce47053de2c366f490bef60803207beaa4Timo Sirainen }
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen return 0;
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen}
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainenvoid maildir_transaction_save_commit_post(struct maildir_save_context *ctx)
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen{
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen /* can't do anything anymore if we fail */
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen (void)maildir_uidlist_sync_deinit(ctx->sync_ctx);
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen
ec1a4f4306496380e9d96ee08a3718a669d0875aTimo Sirainen pool_unref(ctx->pool);
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen}
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
ec1a4f4306496380e9d96ee08a3718a669d0875aTimo Sirainenvoid maildir_transaction_save_rollback(struct maildir_save_context *ctx)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen{
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen struct maildir_filename *mf;
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen string_t *str;
f637b33bb82d56c0546eb08cefcbd7617d885232Timo Sirainen
f637b33bb82d56c0546eb08cefcbd7617d885232Timo Sirainen i_assert(ctx->output == NULL);
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen t_push();
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen str = t_str_new(1024);
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen /* clean up the temp files */
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen for (mf = ctx->files; mf != NULL; mf = mf->next) {
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen str_truncate(str, 0);
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen str_printfa(str, "%s/%s", ctx->tmpdir, mf->basename);
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen (void)unlink(str_c(str));
f637b33bb82d56c0546eb08cefcbd7617d885232Timo Sirainen }
f637b33bb82d56c0546eb08cefcbd7617d885232Timo Sirainen t_pop();
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen pool_unref(ctx->pool);
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen}
6407c617c37ddf87a8d21745bc95d826c62200a4Timo Sirainen