/* 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); }