mbox-save.c revision a485d6b39bcdc27af6856b34bef465c312bbb66f
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek/* Copyright (C) 2002-2007 Timo Sirainen */
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "lib.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "ioloop.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "array.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "base64.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "hostpid.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "randgen.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "istream.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "ostream.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "str.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "write-full.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "istream-header-filter.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "ostream-crlf.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "message-parser.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "index-mail.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "mbox-storage.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "mbox-file.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "mbox-from.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include "mbox-lock.h"
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina#include "mbox-md5.h"
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina#include "mbox-sync-private.h"
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina#include <stddef.h>
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include <stdlib.h>
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include <unistd.h>
1a542b3698d8c42cf075b722f8838f106eb09fccPavel Březina#include <fcntl.h>
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include <sys/stat.h>
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#include <netdb.h>
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek#define MBOX_DELIVERY_ID_RAND_BYTES (64/8)
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozekstruct mbox_save_context {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek struct mail_save_context ctx;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek struct mbox_mailbox *mbox;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek struct mail_index_transaction *trans;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina struct mail *mail;
80941dd89fd8bc7c4a1272c304f737ce0fd5fc54Sumit Bose uoff_t append_offset, mail_offset;
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina string_t *headers;
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina size_t space_end_idx;
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina uint32_t seq, next_uid, uid_validity;
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina struct istream *input;
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina struct ostream *output, *body_output;
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina uoff_t extra_hdr_offset, eoh_offset, eoh_input_offset;
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina char last_char;
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina struct mbox_md5_context *mbox_md5_ctx;
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina unsigned int synced:1;
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina unsigned int failed:1;
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina unsigned int finished:1;
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina};
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březinastatic char my_hostdomain[256] = "";
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březinastatic void write_error(struct mbox_save_context *ctx, int error)
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina{
80941dd89fd8bc7c4a1272c304f737ce0fd5fc54Sumit Bose if (ENOSPACE(error)) {
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina mail_storage_set_error(STORAGE(ctx->mbox->storage),
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina "Not enough disk space");
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina } else {
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina errno = error;
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina mbox_set_syscall_error(ctx->mbox, "write()");
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina }
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina ctx->failed = TRUE;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina}
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březinastatic int mbox_seek_to_end(struct mbox_save_context *ctx, uoff_t *offset)
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina{
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina struct stat st;
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina char ch;
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek int fd;
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina if (ctx->mbox->mbox_writeonly) {
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina *offset = 0;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina return 0;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina }
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek fd = ctx->mbox->mbox_fd;
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek if (fstat(fd, &st) < 0)
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina return mbox_set_syscall_error(ctx->mbox, "fstat()");
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina *offset = (uoff_t)st.st_size;
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina if (st.st_size == 0)
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina return 0;
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina if (lseek(fd, st.st_size-1, SEEK_SET) < 0)
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina return mbox_set_syscall_error(ctx->mbox, "lseek()");
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina if (read(fd, &ch, 1) != 1)
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina return mbox_set_syscall_error(ctx->mbox, "read()");
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina if (ch != '\n') {
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina if (write_full(fd, "\n", 1) < 0) {
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina write_error(ctx, errno);
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek return -1;
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek }
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek *offset += 1;
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek }
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina return 0;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina}
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březinastatic int mbox_append_lf(struct mbox_save_context *ctx)
ed44814e0e7ff9f0ef7ffc98fab7d9542a7822dfPavel Březina{
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek if (o_stream_send(ctx->output, "\n", 1) < 0) {
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina write_error(ctx, ctx->output->stream_errno);
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina return -1;
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek }
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek
ed44814e0e7ff9f0ef7ffc98fab7d9542a7822dfPavel Březina return 0;
ed44814e0e7ff9f0ef7ffc98fab7d9542a7822dfPavel Březina}
ed44814e0e7ff9f0ef7ffc98fab7d9542a7822dfPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březinastatic int write_from_line(struct mbox_save_context *ctx, time_t received_date,
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek const char *from_envelope)
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek{
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina const char *line, *name;
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina int ret;
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina if (*my_hostdomain == '\0') {
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina struct hostent *hent;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina hent = gethostbyname(my_hostname);
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek name = hent != NULL ? hent->h_name : NULL;
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek if (name == NULL) {
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek /* failed, use just the hostname */
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek name = my_hostname;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina }
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina strocpy(my_hostdomain, name, sizeof(my_hostdomain));
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina }
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina t_push();
ed44814e0e7ff9f0ef7ffc98fab7d9542a7822dfPavel Březina if (from_envelope == NULL) {
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek from_envelope =
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina t_strconcat(INDEX_STORAGE(ctx->mbox->storage)->user,
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina "@", my_hostdomain, NULL);
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek }
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek
ed44814e0e7ff9f0ef7ffc98fab7d9542a7822dfPavel Březina /* save in local timezone, no matter what it was given with */
ed44814e0e7ff9f0ef7ffc98fab7d9542a7822dfPavel Březina line = mbox_from_create(from_envelope, received_date);
ed44814e0e7ff9f0ef7ffc98fab7d9542a7822dfPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina if ((ret = o_stream_send_str(ctx->output, line)) < 0)
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina write_error(ctx, ctx->output->stream_errno);
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek t_pop();
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina
5a2cce34cf8843613b0b9dfde054b3d471dd5f3aPavel Březina return ret;
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina}
db419c61035cb262010cc8d5a4047191c2b60f05Pavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březinastatic int mbox_write_content_length(struct mbox_save_context *ctx)
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina{
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina uoff_t end_offset;
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek const char *str;
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek size_t len;
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek int ret = 0;
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek if (ctx->mbox->mbox_writeonly) {
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina /* we can't seek, don't set Content-Length */
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina return 0;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina }
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina end_offset = ctx->output->offset;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina /* write Content-Length headers */
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek t_push();
4be402505ba20b43361753f0e6e1589c9b029e81Jakub Hrozek str = t_strdup_printf("\nContent-Length: %s",
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina dec2str(end_offset - ctx->eoh_offset));
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina len = strlen(str);
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina if (o_stream_seek(ctx->output, ctx->extra_hdr_offset +
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina ctx->space_end_idx - len) < 0) {
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina mbox_set_syscall_error(ctx->mbox, "o_stream_seek()");
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina ret = -1;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina } else if (o_stream_send(ctx->output, str, len) < 0) {
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina write_error(ctx, ctx->output->stream_errno);
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina ret = -1;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek } else {
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina if (o_stream_seek(ctx->output, end_offset) < 0) {
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina mbox_set_syscall_error(ctx->mbox, "o_stream_seek()");
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina ret = -1;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina }
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina }
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina t_pop();
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina return ret;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina}
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březinastatic void mbox_save_init_sync(struct mbox_transaction_context *t)
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina{
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek struct mbox_mailbox *mbox = (struct mbox_mailbox *)t->ictx.ibox;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek struct mbox_save_context *ctx = t->save_ctx;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina const struct mail_index_header *hdr;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina struct mail_index_view *view;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina /* open a new view to get the header. this is required if we just
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina synced the mailbox so we can get updated next_uid. */
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina view = mail_index_view_open(mbox->ibox.index);
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina hdr = mail_index_get_header(view);
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina ctx->next_uid = hdr->next_uid;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina ctx->uid_validity = hdr->uid_validity;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek ctx->synced = TRUE;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek t->mbox_modified = TRUE;
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina mail_index_view_close(&view);
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina}
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březinastatic void status_flags_append(string_t *str, enum mail_flags flags,
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina const struct mbox_flag_type *flags_list)
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina{
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina int i;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek flags ^= MBOX_NONRECENT_KLUDGE;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek for (i = 0; flags_list[i].chr != 0; i++) {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if ((flags & flags_list[i].flag) != 0)
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek str_append_c(str, flags_list[i].chr);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek }
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek flags ^= MBOX_NONRECENT_KLUDGE;
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina}
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březinastatic void mbox_save_append_flag_headers(string_t *str, enum mail_flags flags)
f7af8c5b369938725e47585c641ae5b017d442a1Pavel Březina{
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if ((flags & STATUS_FLAGS_MASK) != 0) {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek str_append(str, "Status: ");
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek status_flags_append(str, flags, mbox_status_flags);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek str_append_c(str, '\n');
f643754db81eeade60485bbe3d80324d889cc4f3Pavel Březina }
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina if ((flags & XSTATUS_FLAGS_MASK) != 0) {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek str_append(str, "X-Status: ");
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina status_flags_append(str, flags, mbox_xstatus_flags);
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina str_append_c(str, '\n');
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina }
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina}
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březinastatic void
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březinambox_save_append_keyword_headers(struct mbox_save_context *ctx,
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek struct mail_keywords *keywords)
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek{
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina unsigned char space[MBOX_HEADER_PADDING+1 +
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina sizeof("Content-Length: \n")-1 + MAX_INT_STRLEN];
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina const ARRAY_TYPE(keywords) *keyword_names_list;
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina const char *const *keyword_names;
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina unsigned int i, count, keyword_names_count;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina keyword_names_list = mail_index_get_keywords(ctx->mbox->ibox.index);
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina keyword_names = array_get(keyword_names_list, &keyword_names_count);
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina str_append(ctx->headers, "X-Keywords:");
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina count = keywords == NULL ? 0 : keywords->count;
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina for (i = 0; i < count; i++) {
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina i_assert(keywords->idx[i] < keyword_names_count);
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina str_append_c(ctx->headers, ' ');
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina str_append(ctx->headers, keyword_names[keywords->idx[i]]);
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina }
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek memset(space, ' ', sizeof(space));
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek str_append_n(ctx->headers, space, sizeof(space));
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina ctx->space_end_idx = str_len(ctx->headers);
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina str_append_c(ctx->headers, '\n');
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina}
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březinastatic int
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březinambox_save_init_file(struct mbox_save_context *ctx,
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek struct mbox_transaction_context *t, bool want_mail)
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek{
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek struct mbox_mailbox *mbox = ctx->mbox;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek int ret;
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina if (ctx->mbox->mbox_readonly) {
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina mail_storage_set_error(STORAGE(ctx->mbox->storage),
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek "Read-only mbox");
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek return -1;
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina }
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina if (ctx->append_offset == (uoff_t)-1) {
fb4e4c4eb6a6dc732370584f70d23dd4a2c5c7b6Pavel Březina /* first appended mail in this transaction */
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina if (mbox->mbox_lock_type != F_WRLCK) {
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina if (mbox->mbox_lock_type == F_RDLCK) {
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina /* FIXME: we shouldn't fail here. it's just
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina a locking issue that should be possible to
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek fix.. */
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek mail_storage_set_error(
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek STORAGE(ctx->mbox->storage),
f7af8c5b369938725e47585c641ae5b017d442a1Pavel Březina "Can't copy mails inside same mailbox");
f7af8c5b369938725e47585c641ae5b017d442a1Pavel Březina return -1;
f7af8c5b369938725e47585c641ae5b017d442a1Pavel Březina }
f7af8c5b369938725e47585c641ae5b017d442a1Pavel Březina if (mbox_lock(mbox, F_WRLCK, &t->mbox_lock_id) <= 0)
f7af8c5b369938725e47585c641ae5b017d442a1Pavel Březina return -1;
f7af8c5b369938725e47585c641ae5b017d442a1Pavel Březina }
f7af8c5b369938725e47585c641ae5b017d442a1Pavel Březina
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina if (mbox->mbox_fd == -1) {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (mbox_file_open(mbox) < 0)
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek return -1;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek }
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
f6171b2bc954a367f316853ab71090eb213bdee3Pavel Březina if (!want_mail) {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek /* assign UIDs only if mbox doesn't require syncing */
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek ret = mbox_sync_has_changed(mbox, TRUE);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (ret < 0)
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek return -1;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (ret == 0)
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek mbox_save_init_sync(t);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek }
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (mbox_seek_to_end(ctx, &ctx->append_offset) < 0)
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek return -1;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek ctx->output = o_stream_create_file(mbox->mbox_fd, default_pool,
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek 0, FALSE);
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina }
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina if (!ctx->synced && want_mail) {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek /* we'll need to assign UID for the mail immediately. */
8bbf89c5ab798c112773fe23515c3a9df56dde71Nick Guay if (mbox_sync(mbox, 0) < 0)
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina return -1;
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina mbox_save_init_sync(t);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek }
9bdb93119ceaf9e2bbcec0c0a4747f1a04b48a12Pavel Březina
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina return 0;
9bdb93119ceaf9e2bbcec0c0a4747f1a04b48a12Pavel Březina}
9bdb93119ceaf9e2bbcec0c0a4747f1a04b48a12Pavel Březina
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březinastatic void save_header_callback(struct message_header_line *hdr,
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina bool *matched, struct mbox_save_context *ctx)
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek{
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (hdr != NULL) {
f643754db81eeade60485bbe3d80324d889cc4f3Pavel Březina if (strncmp(hdr->name, "From ", 5) == 0) {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek /* we can't allow From_-lines in headers. there's no
2ce00e0d3896bb42db169d1e79553a81ca837a22Simo Sorce legitimate reason for allowing them in any case,
2ce00e0d3896bb42db169d1e79553a81ca837a22Simo Sorce so just drop them. */
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek *matched = TRUE;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek return;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek }
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (!*matched && ctx->mbox_md5_ctx != NULL)
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina mbox_md5_continue(ctx->mbox_md5_ctx, hdr);
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina }
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina if ((hdr == NULL && ctx->eoh_input_offset == (uoff_t)-1) ||
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina (hdr != NULL && hdr->eoh))
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina ctx->eoh_input_offset = ctx->input->v_offset;
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (ctx->mail != NULL) {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek index_mail_parse_header(NULL, hdr,
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina (struct index_mail *)ctx->mail);
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina }
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina}
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březinastatic void mbox_save_x_delivery_id(struct mbox_save_context *ctx)
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina{
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina unsigned char md5_result[MD5_RESULTLEN];
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina buffer_t *buf;
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina void *randbuf;
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina t_push();
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina buf = buffer_create_dynamic(pool_datastack_create(), 256);
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina buffer_append(buf, &ioloop_time, sizeof(ioloop_time));
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina buffer_append(buf, &ioloop_timeval.tv_usec,
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina sizeof(ioloop_timeval.tv_usec));
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina randbuf = buffer_append_space_unsafe(buf, MBOX_DELIVERY_ID_RAND_BYTES);
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina random_fill_weak(randbuf, MBOX_DELIVERY_ID_RAND_BYTES);
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina md5_get_digest(buf->data, buf->used, md5_result);
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina str_append(ctx->headers, "X-Delivery-ID: ");
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek base64_encode(md5_result, sizeof(md5_result), ctx->headers);
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina str_append_c(ctx->headers, '\n');
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek t_pop();
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek}
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březinaint mbox_save_init(struct mailbox_transaction_context *_t,
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina enum mail_flags flags, struct mail_keywords *keywords,
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina time_t received_date, int timezone_offset __attr_unused__,
5d72a91a37273c8c874640906fd2f7a70e606812Simo Sorce const char *from_envelope, struct istream *input,
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina struct mail *dest_mail, struct mail_save_context **ctx_r)
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina{
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina struct mbox_transaction_context *t =
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina (struct mbox_transaction_context *)_t;
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina struct mbox_mailbox *mbox = (struct mbox_mailbox *)t->ictx.ibox;
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina struct mbox_save_context *ctx = t->save_ctx;
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina enum mail_flags save_flags;
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina uint64_t offset;
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina i_assert((t->ictx.flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina /* FIXME: we could write timezone_offset to From-line.. */
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina if (received_date == (time_t)-1)
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina received_date = ioloop_time;
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina if (ctx == NULL) {
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina ctx = t->save_ctx = i_new(struct mbox_save_context, 1);
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina ctx->ctx.transaction = &t->ictx.mailbox_ctx;
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina ctx->mbox = mbox;
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina ctx->trans = t->ictx.trans;
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina ctx->append_offset = (uoff_t)-1;
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina ctx->headers = str_new(default_pool, 512);
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina ctx->mail_offset = (uoff_t)-1;
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina }
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina
e7b5b99e5a5d276f32039c4fb8b21ba51bdb1537Pavel Březina ctx->failed = FALSE;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek ctx->seq = 0;
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina if (mbox_save_init_file(ctx, t, dest_mail != NULL) < 0) {
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina ctx->failed = TRUE;
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina return -1;
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina }
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina save_flags = (flags & ~MAIL_RECENT) | MAIL_RECENT;
cda8ff6cfdef22356dc3c06ec5204344912f0f0bPavel Březina str_truncate(ctx->headers, 0);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (ctx->synced) {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (ctx->output->offset == 0) {
69e7d6649b58c66675ef38084868fc5356c5a240Jakub Hrozek /* writing the first mail. Insert X-IMAPbase as well. */
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek str_printfa(ctx->headers, "X-IMAPbase: %u %010u\n",
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek ctx->uid_validity, ctx->next_uid);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek }
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if ((STORAGE(mbox->storage)->flags &
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) != 0) {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek /* we're using MD5 sums to generate POP3 UIDLs.
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek clients don't like it much if there are duplicates,
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek so make sure that there can't be any by appending
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek our own X-Delivery-ID header. */
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek mbox_save_x_delivery_id(ctx);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek }
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek str_printfa(ctx->headers, "X-UID: %u\n", ctx->next_uid);
fb4e4c4eb6a6dc732370584f70d23dd4a2c5c7b6Pavel Březina if (!mbox->ibox.keep_recent)
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek save_flags &= ~MAIL_RECENT;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek mail_index_append(ctx->trans, ctx->next_uid, &ctx->seq);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE,
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek save_flags);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (keywords != NULL) {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek mail_index_update_keywords(ctx->trans, ctx->seq,
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek MODIFY_REPLACE, keywords);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek }
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek offset = ctx->output->offset == 0 ? 0 :
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek ctx->output->offset - 1;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek mail_index_update_ext(ctx->trans, ctx->seq,
dd7192379e5fc5bb852863e60ad4b6a20c5da183Simo Sorce mbox->mbox_ext_idx, &offset, NULL);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek ctx->next_uid++;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek /* parse and cache the mail headers as we read it */
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (dest_mail == NULL) {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (ctx->mail == NULL)
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek ctx->mail = index_mail_alloc(_t, 0, NULL);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek dest_mail = ctx->mail;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek }
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (mail_set_seq(dest_mail, ctx->seq) < 0)
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina i_unreached();
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina index_mail_parse_header_init((struct index_mail *)dest_mail,
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina NULL);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina mbox_save_append_flag_headers(ctx->headers, save_flags);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina mbox_save_append_keyword_headers(ctx, keywords);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina str_append_c(ctx->headers, '\n');
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina i_assert(mbox->mbox_lock_type == F_WRLCK);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->mail_offset = ctx->output->offset;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->eoh_input_offset = (uoff_t)-1;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->eoh_offset = (uoff_t)-1;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->last_char = '\n';
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (write_from_line(ctx, received_date, from_envelope) < 0)
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->failed = TRUE;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina else {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->input =
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina i_stream_create_header_filter(input,
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina HEADER_FILTER_EXCLUDE |
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina HEADER_FILTER_NO_CR,
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina mbox_hide_headers,
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina mbox_hide_headers_count,
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina save_header_callback,
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->body_output =
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina (STORAGE(mbox->storage)->flags &
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina MAIL_STORAGE_FLAG_SAVE_CRLF) != 0 ?
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina o_stream_create_crlf(default_pool, ctx->output) :
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina o_stream_create_lf(default_pool, ctx->output);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (ctx->mbox->mbox_save_md5 && ctx->synced)
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->mbox_md5_ctx = mbox_md5_init();
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina *ctx_r = &ctx->ctx;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina return ctx->failed ? -1 : 0;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina}
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březinaint mbox_save_continue(struct mail_save_context *_ctx)
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina{
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina struct mbox_save_context *ctx = (struct mbox_save_context *)_ctx;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina const unsigned char *data;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina size_t size;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ssize_t ret;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (ctx->failed)
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina return -1;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (ctx->eoh_offset != (uoff_t)-1) {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina /* writing body */
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina while ((ret = i_stream_read(ctx->input)) != -1) {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (ret == 0)
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina return 0;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina data = i_stream_get_data(ctx->input, &size);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (o_stream_send(ctx->body_output, data, size) < 0) {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina write_error(ctx,
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->body_output->stream_errno);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina return -1;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->last_char = data[size-1];
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina i_stream_skip(ctx->input, size);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (ctx->last_char != '\n') {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina /* if mail doesn't end with LF, we'll do that.
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina otherwise some mbox parsers don't like the result.
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina this makes it impossible to save a mail that doesn't
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina end with LF though. */
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (o_stream_send(ctx->body_output, "\n", 1) < 0) {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina write_error(ctx,
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->body_output->stream_errno);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina return -1;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina return 0;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina while ((ret = i_stream_read(ctx->input)) != -1) {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (ret == 0)
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina return 0;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina data = i_stream_get_data(ctx->input, &size);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (ctx->eoh_input_offset != (uoff_t)-1 &&
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->input->v_offset + size >= ctx->eoh_input_offset) {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina /* found end of headers. write the rest of them. */
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina size = ctx->eoh_input_offset - ctx->input->v_offset;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (o_stream_send(ctx->output, data, size) < 0) {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina write_error(ctx, ctx->output->stream_errno);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina return -1;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (size > 0)
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->last_char = data[size-1];
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina i_stream_skip(ctx->input, size + 1);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina break;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (o_stream_send(ctx->output, data, size) < 0) {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina write_error(ctx, ctx->output->stream_errno);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina return -1;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->last_char = data[size-1];
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina i_stream_skip(ctx->input, size);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (ctx->last_char != '\n') {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (o_stream_send(ctx->output, "\n", 1) < 0) {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina write_error(ctx, ctx->output->stream_errno);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina return -1;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (ctx->mbox_md5_ctx) {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina unsigned char hdr_md5_sum[16];
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina mbox_md5_finish(ctx->mbox_md5_ctx, hdr_md5_sum);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina mail_index_update_ext(ctx->trans, ctx->seq,
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->mbox->ibox.md5hdr_ext_idx,
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina hdr_md5_sum, NULL);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina /* append our own headers and ending empty line */
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->extra_hdr_offset = ctx->output->offset;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (o_stream_send(ctx->output, str_data(ctx->headers),
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina str_len(ctx->headers)) < 0) {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina write_error(ctx, ctx->output->stream_errno);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina return -1;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina }
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->eoh_offset = ctx->output->offset;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina /* write body */
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina (void)i_stream_get_data(ctx->input, &size);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina return ctx->input->eof && size == 0 ? 0 : mbox_save_continue(_ctx);
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina}
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březinaint mbox_save_finish(struct mail_save_context *_ctx)
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina{
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina struct mbox_save_context *ctx = (struct mbox_save_context *)_ctx;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina ctx->finished = TRUE;
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (!ctx->failed) {
44749ce0c1fee9babee80060fa0db99eebb2ab51Pavel Březina if (mbox_write_content_length(ctx) < 0 ||
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina mbox_append_lf(ctx) < 0)
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina ctx->failed = TRUE;
9675bccabff4e79d224f64611ad9ff3e073b488eSimo Sorce }
9675bccabff4e79d224f64611ad9ff3e073b488eSimo Sorce
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina if (ctx->input != NULL)
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina i_stream_destroy(&ctx->input);
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina if (ctx->body_output != NULL)
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina o_stream_destroy(&ctx->body_output);
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina if (ctx->failed && ctx->mail_offset != (uoff_t)-1) {
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina /* saving this mail failed - truncate back to beginning of it */
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina if (ftruncate(ctx->mbox->mbox_fd, (off_t)ctx->mail_offset) < 0)
9675bccabff4e79d224f64611ad9ff3e073b488eSimo Sorce mbox_set_syscall_error(ctx->mbox, "ftruncate()");
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina ctx->mail_offset = (uoff_t)-1;
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina }
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina return ctx->failed ? -1 : 0;
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina}
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březinavoid mbox_save_cancel(struct mail_save_context *_ctx)
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina{
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina struct mbox_save_context *ctx = (struct mbox_save_context *)_ctx;
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina ctx->failed = TRUE;
2d34690ae92215d355b0272001d9e68214dc80f6Jakub Hrozek (void)mbox_save_finish(_ctx);
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina}
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březinastatic void mbox_transaction_save_deinit(struct mbox_save_context *ctx)
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina{
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina i_assert(ctx->body_output == NULL);
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina if (ctx->output != NULL)
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina o_stream_destroy(&ctx->output);
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina if (ctx->mail != NULL)
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina index_mail_free(ctx->mail);
9675bccabff4e79d224f64611ad9ff3e073b488eSimo Sorce str_free(&ctx->headers);
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina i_free(ctx);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek}
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozekint mbox_transaction_save_commit(struct mbox_save_context *ctx)
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek{
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek struct stat st;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek int ret = 0;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina i_assert(ctx->finished);
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina
f643754db81eeade60485bbe3d80324d889cc4f3Pavel Březina if (ctx->synced) {
f643754db81eeade60485bbe3d80324d889cc4f3Pavel Březina mail_index_update_header(ctx->trans,
f643754db81eeade60485bbe3d80324d889cc4f3Pavel Březina offsetof(struct mail_index_header, next_uid),
f643754db81eeade60485bbe3d80324d889cc4f3Pavel Březina &ctx->next_uid, sizeof(ctx->next_uid), FALSE);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (fstat(ctx->mbox->mbox_fd, &st) < 0) {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek mbox_set_syscall_error(ctx->mbox, "fstat()");
9675bccabff4e79d224f64611ad9ff3e073b488eSimo Sorce ret = -1;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek } else {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek uint32_t sync_stamp = st.st_mtime;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek uint64_t sync_size = st.st_size;
f643754db81eeade60485bbe3d80324d889cc4f3Pavel Březina
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek mail_index_update_header(ctx->trans,
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek offsetof(struct mail_index_header, sync_stamp),
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek &sync_stamp, sizeof(sync_stamp), TRUE);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek mail_index_update_header(ctx->trans,
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek offsetof(struct mail_index_header, sync_size),
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina &sync_size, sizeof(sync_size), TRUE);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek }
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek }
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina if (!ctx->synced && ctx->mbox->mbox_fd != -1 &&
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina !ctx->mbox->mbox_writeonly && !ctx->mbox->ibox.fsync_disable) {
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina if (fdatasync(ctx->mbox->mbox_fd) < 0) {
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek mbox_set_syscall_error(ctx->mbox, "fdatasync()");
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek ret = -1;
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina }
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina }
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina mbox_transaction_save_deinit(ctx);
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina return ret;
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina}
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozekvoid mbox_transaction_save_rollback(struct mbox_save_context *ctx)
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek{
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek struct mbox_mailbox *mbox = ctx->mbox;
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
f643754db81eeade60485bbe3d80324d889cc4f3Pavel Březina if (!ctx->finished)
f643754db81eeade60485bbe3d80324d889cc4f3Pavel Březina mbox_save_cancel(&ctx->ctx);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek if (ctx->append_offset != (uoff_t)-1 && mbox->mbox_fd != -1) {
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina i_assert(mbox->mbox_lock_type == F_WRLCK);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek /* failed, truncate file back to original size.
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek output stream needs to be flushed before truncating
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek so unref() won't write anything. */
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek o_stream_flush(ctx->output);
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina if (ftruncate(mbox->mbox_fd, (off_t)ctx->append_offset) < 0)
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek mbox_set_syscall_error(mbox, "ftruncate()");
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek }
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina mbox_transaction_save_deinit(ctx);
3a59cbd0b7b9c5dd3c62ac1679876070c264d80fMichal Zidek}
f5d4b05027acce06e3509ecb68869d1c7ef37180Pavel Březina