diff options
Diffstat (limited to 'src/plugins/virtual/virtual-save.c')
-rw-r--r-- | src/plugins/virtual/virtual-save.c | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/src/plugins/virtual/virtual-save.c b/src/plugins/virtual/virtual-save.c new file mode 100644 index 0000000..9499cd3 --- /dev/null +++ b/src/plugins/virtual/virtual-save.c @@ -0,0 +1,153 @@ +/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "virtual-transaction.h" +#include "virtual-storage.h" + +struct virtual_save_context { + struct mail_save_context ctx; + struct mail_save_context *backend_save_ctx; + struct mailbox *backend_box; + char *open_errstr; + enum mail_error open_error; +}; + +struct mail_save_context * +virtual_save_alloc(struct mailbox_transaction_context *_t) +{ + struct virtual_transaction_context *t = + (struct virtual_transaction_context *)_t; + struct virtual_mailbox *mbox = (struct virtual_mailbox *)_t->box; + struct mailbox_transaction_context *backend_trans; + struct virtual_save_context *ctx; + const char *errstr; + + if (_t->save_ctx == NULL) { + ctx = i_new(struct virtual_save_context, 1); + ctx->ctx.transaction = &t->t; + _t->save_ctx = &ctx->ctx; + } else { + ctx = (struct virtual_save_context *)_t->save_ctx; + } + + if (mbox->save_bbox != NULL) { + i_assert(ctx->backend_save_ctx == NULL); + i_assert(ctx->open_errstr == NULL); + + if (!mbox->save_bbox->box->opened && + virtual_backend_box_open(mbox, mbox->save_bbox) < 0) { + errstr = mailbox_get_last_error(mbox->save_bbox->box, + &ctx->open_error); + ctx->open_errstr = i_strdup(errstr); + } else { + backend_trans = + virtual_transaction_get(_t, mbox->save_bbox->box); + ctx->backend_save_ctx = mailbox_save_alloc(backend_trans); + } + virtual_backend_box_accessed(mbox, mbox->save_bbox); + } + return _t->save_ctx; +} + +static struct mail_keywords * +virtual_copy_keywords(struct mailbox *src_box, + const struct mail_keywords *src_keywords, + struct mailbox *dest_box) +{ + struct mailbox_status status; + ARRAY_TYPE(keywords) kw_strings; + const char *kw; + unsigned int i; + + if (src_keywords == NULL || src_keywords->count == 0) + return NULL; + + t_array_init(&kw_strings, src_keywords->count + 1); + mailbox_get_open_status(src_box, STATUS_KEYWORDS, &status); + + for (i = 0; i < src_keywords->count; i++) { + kw = array_idx_elem(status.keywords, src_keywords->idx[i]); + array_push_back(&kw_strings, &kw); + } + array_append_zero(&kw_strings); + return mailbox_keywords_create_valid(dest_box, + array_front(&kw_strings)); +} + +int virtual_save_begin(struct mail_save_context *_ctx, struct istream *input) +{ + struct virtual_save_context *ctx = (struct virtual_save_context *)_ctx; + struct mail_save_data *mdata = &_ctx->data; + struct mail_keywords *keywords; + + if (ctx->backend_save_ctx == NULL) { + if (ctx->open_errstr != NULL) { + /* mailbox_open() failed */ + mail_storage_set_error(_ctx->transaction->box->storage, + ctx->open_error, ctx->open_errstr); + } else { + mail_storage_set_error(_ctx->transaction->box->storage, + MAIL_ERROR_NOTPOSSIBLE, + "Can't save messages to this virtual mailbox"); + } + return -1; + } + + ctx->backend_box = ctx->backend_save_ctx->transaction->box; + keywords = virtual_copy_keywords(_ctx->transaction->box, mdata->keywords, + ctx->backend_box); + mailbox_save_set_flags(ctx->backend_save_ctx, + mdata->flags | mdata->pvt_flags, + keywords); + if (keywords != NULL) + mail_index_keywords_unref(&keywords); + + mailbox_save_set_received_date(ctx->backend_save_ctx, + mdata->received_date, + mdata->received_tz_offset); + mailbox_save_set_from_envelope(ctx->backend_save_ctx, + mdata->from_envelope); + mailbox_save_set_guid(ctx->backend_save_ctx, mdata->guid); + mailbox_save_set_min_modseq(ctx->backend_save_ctx, mdata->min_modseq); + + virtual_mail_set_unattached_backend_mail(_ctx->dest_mail, + ctx->backend_save_ctx->dest_mail); + return mailbox_save_begin(&ctx->backend_save_ctx, input); +} + +int virtual_save_continue(struct mail_save_context *_ctx) +{ + struct virtual_save_context *ctx = (struct virtual_save_context *)_ctx; + + return mailbox_save_continue(ctx->backend_save_ctx); +} + +int virtual_save_finish(struct mail_save_context *_ctx) +{ + struct virtual_save_context *ctx = (struct virtual_save_context *)_ctx; + int ret; + ret = mailbox_save_finish(&ctx->backend_save_ctx); + index_save_context_free(_ctx); + + return ret; +} + +void virtual_save_cancel(struct mail_save_context *_ctx) +{ + struct virtual_save_context *ctx = (struct virtual_save_context *)_ctx; + + if (ctx->backend_save_ctx != NULL) + mailbox_save_cancel(&ctx->backend_save_ctx); + i_free_and_null(ctx->open_errstr); + _ctx->unfinished = FALSE; +} + +void virtual_save_free(struct mail_save_context *_ctx) +{ + struct virtual_save_context *ctx = (struct virtual_save_context *)_ctx; + + virtual_save_cancel(_ctx); + mailbox_save_context_deinit(_ctx); + i_free(ctx); +} |