dbox-save.c revision e6440616c02bb1404dc35debf45d9741260c7831
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2007-2010 Dovecot authors, see the included COPYING file */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "lib.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "istream.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "istream-crlf.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "ostream.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "str.h"
5733207dc3ec10e6e5a6e0a8b30fbd1b061062b9Timo Sirainen#include "hex-binary.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "index-mail.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "dbox-file.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "dbox-save.h"
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainenvoid dbox_save_add_to_index(struct dbox_save_context *ctx)
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen{
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen enum mail_flags save_flags;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen save_flags = ctx->ctx.flags & ~MAIL_RECENT;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_append(ctx->trans, ctx->ctx.uid, &ctx->seq);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen save_flags);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (ctx->ctx.keywords != NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_update_keywords(ctx->trans, ctx->seq,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MODIFY_REPLACE, ctx->ctx.keywords);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen }
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen if (ctx->ctx.min_modseq != 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_update_modseq(ctx->trans, ctx->seq,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ctx->ctx.min_modseq);
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid dbox_save_begin(struct dbox_save_context *ctx, struct istream *input)
5733207dc3ec10e6e5a6e0a8b30fbd1b061062b9Timo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_save_context *_ctx = &ctx->ctx;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen struct dbox_message_header dbox_msg_hdr;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen struct istream *crlf_input;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dbox_save_add_to_index(ctx);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (_ctx->dest_mail == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (ctx->mail == NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ctx->mail = mail_alloc(_ctx->transaction, 0, NULL);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen _ctx->dest_mail = ctx->mail;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_set_seq(_ctx->dest_mail, ctx->seq);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen crlf_input = i_stream_create_lf(input);
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen ctx->input = index_mail_cache_parse_init(_ctx->dest_mail, crlf_input);
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen i_stream_unref(&crlf_input);
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* write a dummy header. it'll get rewritten when we're finished */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen memset(&dbox_msg_hdr, 0, sizeof(dbox_msg_hdr));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_cork(ctx->dbox_output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (o_stream_send(ctx->dbox_output, &dbox_msg_hdr,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen sizeof(dbox_msg_hdr)) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_storage_set_critical(_ctx->transaction->box->storage,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "o_stream_send(%s) failed: %m",
afbc6221ea2dae6c86c04efbf443bd891cb61e45Timo Sirainen ctx->cur_file->cur_path);
afbc6221ea2dae6c86c04efbf443bd891cb61e45Timo Sirainen ctx->failed = TRUE;
afbc6221ea2dae6c86c04efbf443bd891cb61e45Timo Sirainen }
afbc6221ea2dae6c86c04efbf443bd891cb61e45Timo Sirainen _ctx->output = ctx->dbox_output;
afbc6221ea2dae6c86c04efbf443bd891cb61e45Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (_ctx->received_date == (time_t)-1)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen _ctx->received_date = ioloop_time;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenint dbox_save_continue(struct mail_save_context *_ctx)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen struct mail_storage *storage = _ctx->transaction->box->storage;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen if (ctx->failed)
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen return -1;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen do {
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen if (o_stream_send_istream(_ctx->output, ctx->input) < 0) {
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen if (!mail_storage_set_error_from_errno(storage)) {
79ee504bdf920f01e12e28f238799bf2616489dfTimo Sirainen mail_storage_set_critical(storage,
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen "o_stream_send_istream(%s) failed: %m",
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen ctx->cur_file->cur_path);
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen }
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen ctx->failed = TRUE;
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen return -1;
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen }
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen index_mail_cache_parse_continue(_ctx->dest_mail);
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen /* both tee input readers may consume data from our primary
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen input stream. we'll have to make sure we don't return with
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen one of the streams still having data in them. */
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen } while (i_stream_read(ctx->input) > 0);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen return 0;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid dbox_save_end(struct dbox_save_context *ctx)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2726de0d31ed0f1a1425e4c8d167f7681e07fc25Timo Sirainen struct ostream *dbox_output = ctx->dbox_output;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (ctx->ctx.output != dbox_output) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* e.g. zlib plugin had changed this */
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen o_stream_ref(dbox_output);
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen o_stream_destroy(&ctx->ctx.output);
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen ctx->ctx.output = dbox_output;
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen }
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid dbox_save_write_metadata(struct mail_save_context *ctx,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ostream *output,
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen const char *orig_mailbox_name,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen uint8_t guid_128[MAIL_GUID_128_SIZE])
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen{
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen struct dbox_metadata_header metadata_hdr;
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen const char *guid;
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen string_t *str;
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen uoff_t vsize;
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen memset(&metadata_hdr, 0, sizeof(metadata_hdr));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen memcpy(metadata_hdr.magic_post, DBOX_MAGIC_POST,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen sizeof(metadata_hdr.magic_post));
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen o_stream_send(output, &metadata_hdr, sizeof(metadata_hdr));
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen str = t_str_new(256);
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen str_printfa(str, "%c%lx\n", DBOX_METADATA_RECEIVED_TIME,
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen (unsigned long)ctx->received_date);
f561fba30221abcc40288cace406289a8e44da89Timo Sirainen str_printfa(str, "%c%lx\n", DBOX_METADATA_SAVE_TIME,
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen (unsigned long)ioloop_time);
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen if (mail_get_virtual_size(ctx->dest_mail, &vsize) < 0)
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen i_unreached();
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen str_printfa(str, "%c%llx\n", DBOX_METADATA_VIRTUAL_SIZE,
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen (unsigned long long)vsize);
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen guid = ctx->guid;
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen if (guid != NULL)
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen mail_generate_guid_128_hash(guid, guid_128);
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen else {
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen mail_generate_guid_128(guid_128);
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen guid = binary_to_hex(guid_128, MAIL_GUID_128_SIZE);
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen }
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen str_printfa(str, "%c%s\n", DBOX_METADATA_GUID, guid);
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen if (orig_mailbox_name != NULL &&
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen strchr(orig_mailbox_name, '\r') == NULL &&
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen strchr(orig_mailbox_name, '\n') == NULL) {
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen /* save the original mailbox name so if mailbox indexes get
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen corrupted we can place at least some (hopefully most) of
f561fba30221abcc40288cace406289a8e44da89Timo Sirainen the messages to correct mailboxes. */
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen str_printfa(str, "%c%s\n", DBOX_METADATA_ORIG_MAILBOX,
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen orig_mailbox_name);
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen }
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen str_append_c(str, '\n');
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen o_stream_send(output, str_data(str), str_len(str));
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen}
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen