dbox-save.c revision 1b6c4fdd2bb4234b5711874b3845547f49649744
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2007-2012 Dovecot authors, see the included COPYING file */
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen#include "lib.h"
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen#include "istream.h"
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen#include "istream-crlf.h"
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen#include "ostream.h"
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen#include "str.h"
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen#include "hex-binary.h"
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen#include "index-mail.h"
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen#include "dbox-attachment.h"
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen#include "dbox-file.h"
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen#include "dbox-save.h"
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainenvoid dbox_save_add_to_index(struct dbox_save_context *ctx)
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen{
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen struct mail_save_data *mdata = &ctx->ctx.data;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen enum mail_flags save_flags;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen save_flags = mdata->flags & ~MAIL_RECENT;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen mail_index_append(ctx->trans, mdata->uid, &ctx->seq);
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE,
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen save_flags);
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen if (mdata->keywords != NULL) {
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen mail_index_update_keywords(ctx->trans, ctx->seq,
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen MODIFY_REPLACE, mdata->keywords);
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen }
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen if (mdata->min_modseq != 0) {
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen mail_index_update_modseq(ctx->trans, ctx->seq,
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen mdata->min_modseq);
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen }
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen}
93ae7fcd39c6982f7e338adfe71139942d9bbad1Timo Sirainen
93ae7fcd39c6982f7e338adfe71139942d9bbad1Timo Sirainenvoid dbox_save_begin(struct dbox_save_context *ctx, struct istream *input)
93ae7fcd39c6982f7e338adfe71139942d9bbad1Timo Sirainen{
93ae7fcd39c6982f7e338adfe71139942d9bbad1Timo Sirainen struct mail_save_context *_ctx = &ctx->ctx;
93ae7fcd39c6982f7e338adfe71139942d9bbad1Timo Sirainen struct mail_storage *_storage = _ctx->transaction->box->storage;
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen struct dbox_storage *storage = (struct dbox_storage *)_storage;
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen struct dbox_message_header dbox_msg_hdr;
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen struct istream *crlf_input;
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen dbox_save_add_to_index(ctx);
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen if (_ctx->dest_mail == NULL) {
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen if (ctx->mail == NULL)
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen ctx->mail = mail_alloc(_ctx->transaction, 0, NULL);
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen _ctx->dest_mail = ctx->mail;
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen }
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen mail_set_seq_saving(_ctx->dest_mail, ctx->seq);
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen crlf_input = i_stream_create_lf(input);
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen ctx->input = index_mail_cache_parse_init(_ctx->dest_mail, crlf_input);
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen i_stream_unref(&crlf_input);
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen /* write a dummy header. it'll get rewritten when we're finished */
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen memset(&dbox_msg_hdr, 0, sizeof(dbox_msg_hdr));
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen o_stream_cork(ctx->dbox_output);
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen if (o_stream_send(ctx->dbox_output, &dbox_msg_hdr,
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen sizeof(dbox_msg_hdr)) < 0) {
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen mail_storage_set_critical(_storage, "write(%s) failed: %m",
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen o_stream_get_name(ctx->dbox_output));
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen ctx->failed = TRUE;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen }
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen _ctx->data.output = ctx->dbox_output;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen if (_ctx->data.received_date == (time_t)-1)
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen _ctx->data.received_date = ioloop_time;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen index_attachment_save_begin(_ctx, storage->attachment_fs, ctx->input);
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen}
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainenint dbox_save_continue(struct mail_save_context *_ctx)
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen{
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen struct mail_storage *storage = _ctx->transaction->box->storage;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen if (ctx->failed)
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen return -1;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen if (_ctx->data.attach != NULL)
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen return index_attachment_save_continue(_ctx);
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen do {
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen if (o_stream_send_istream(_ctx->data.output, ctx->input) < 0) {
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen if (!mail_storage_set_error_from_errno(storage)) {
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen mail_storage_set_critical(storage,
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen "write(%s) failed: %m",
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen o_stream_get_name(_ctx->data.output));
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen }
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen ctx->failed = TRUE;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen return -1;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen }
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen index_mail_cache_parse_continue(_ctx->dest_mail);
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen /* both tee input readers may consume data from our primary
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen input stream. we'll have to make sure we don't return with
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen one of the streams still having data in them. */
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen } while (i_stream_read(ctx->input) > 0);
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen return 0;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen}
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainenvoid dbox_save_end(struct dbox_save_context *ctx)
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen{
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen struct mail_save_data *mdata = &ctx->ctx.data;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen struct ostream *dbox_output = ctx->dbox_output;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen if (mdata->attach != NULL && !ctx->failed) {
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen if (index_attachment_save_finish(&ctx->ctx) < 0)
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen ctx->failed = TRUE;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen }
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen if (o_stream_nfinish(mdata->output) < 0) {
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen mail_storage_set_critical(ctx->ctx.transaction->box->storage,
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen "write(%s) failed: %m",
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen o_stream_get_name(mdata->output));
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen ctx->failed = TRUE;
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen }
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen if (mdata->output == dbox_output)
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen return;
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen /* e.g. zlib plugin had changed this */
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen o_stream_ref(dbox_output);
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen o_stream_destroy(&mdata->output);
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen mdata->output = dbox_output;
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen}
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainenvoid dbox_save_write_metadata(struct mail_save_context *_ctx,
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen struct ostream *output, uoff_t output_msg_size,
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen const char *orig_mailbox_name,
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen guid_128_t guid_128)
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen{
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen struct mail_save_data *mdata = &ctx->ctx.data;
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen struct dbox_metadata_header metadata_hdr;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen const char *guid;
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen string_t *str;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen uoff_t vsize;
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen
56bcd695f96f093d801743a5633555339e241f5bTimo Sirainen memset(&metadata_hdr, 0, sizeof(metadata_hdr));
e0e555a09a8ff93aa904586aeffd37f5b0e3a84dTimo Sirainen memcpy(metadata_hdr.magic_post, DBOX_MAGIC_POST,
8e4a702a1f96f118976da6eb9ece344df625eabbTimo Sirainen sizeof(metadata_hdr.magic_post));
o_stream_nsend(output, &metadata_hdr, sizeof(metadata_hdr));
str = t_str_new(256);
if (output_msg_size != ctx->input->v_offset) {
/* a plugin changed the data written to disk, so the
"message size" dbox header doesn't contain the actual
"physical" message size. we need to save it as a
separate metadata header. */
str_printfa(str, "%c%llx\n", DBOX_METADATA_PHYSICAL_SIZE,
(unsigned long long)ctx->input->v_offset);
}
str_printfa(str, "%c%lx\n", DBOX_METADATA_RECEIVED_TIME,
(unsigned long)mdata->received_date);
if (mail_get_virtual_size(_ctx->dest_mail, &vsize) < 0)
i_unreached();
str_printfa(str, "%c%llx\n", DBOX_METADATA_VIRTUAL_SIZE,
(unsigned long long)vsize);
if (mdata->pop3_uidl != NULL) {
i_assert(strchr(mdata->pop3_uidl, '\n') == NULL);
str_printfa(str, "%c%s\n", DBOX_METADATA_POP3_UIDL,
mdata->pop3_uidl);
}
guid = mdata->guid;
if (guid != NULL)
mail_generate_guid_128_hash(guid, guid_128);
else {
guid_128_generate(guid_128);
guid = guid_128_to_string(guid_128);
}
str_printfa(str, "%c%s\n", DBOX_METADATA_GUID, guid);
if (orig_mailbox_name != NULL &&
strchr(orig_mailbox_name, '\r') == NULL &&
strchr(orig_mailbox_name, '\n') == NULL) {
/* save the original mailbox name so if mailbox indexes get
corrupted we can place at least some (hopefully most) of
the messages to correct mailboxes. */
str_printfa(str, "%c%s\n", DBOX_METADATA_ORIG_MAILBOX,
orig_mailbox_name);
}
dbox_attachment_save_write_metadata(_ctx, str);
str_append_c(str, '\n');
o_stream_nsend(output, str_data(str), str_len(str));
}