summaryrefslogtreecommitdiffstats
path: root/src/plugins/virtual/virtual-save.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/virtual/virtual-save.c')
-rw-r--r--src/plugins/virtual/virtual-save.c153
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);
+}