From b7f741e76411bf3559e3f66cffc1e06ae1f525f6 Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Tue, 27 Nov 2007 03:38:49 +0100 Subject: [PATCH] Almost finished implementing the store action. But, I still get strange errors when the mail transaction commits. Mail is stored though. --- sieve/tests/actions.sieve | 14 ++--- src/lib-sieve/sieve-actions.c | 112 ++++++++++++++++++++++++++++++++-- src/lib-sieve/sieve-actions.h | 16 ++++- src/lib-sieve/sieve-result.c | 22 +++++-- src/lib-sieve/sieve.h | 1 + src/sieve-bin/Makefile.am | 6 ++ src/sieve-bin/mail-raw.c | 39 +----------- src/sieve-bin/mail-raw.h | 2 +- src/sieve-bin/namespaces.c | 64 +++++++++++++++++++ src/sieve-bin/namespaces.h | 7 +++ src/sieve-bin/sieve-exec.c | 35 ++++++++++- src/sieve-bin/sieve-test.c | 26 ++++++-- 12 files changed, 281 insertions(+), 63 deletions(-) create mode 100644 src/sieve-bin/namespaces.c create mode 100644 src/sieve-bin/namespaces.h diff --git a/sieve/tests/actions.sieve b/sieve/tests/actions.sieve index 0b3dd6f25..eeb7b7668 100644 --- a/sieve/tests/actions.sieve +++ b/sieve/tests/actions.sieve @@ -1,18 +1,18 @@ require "fileinto"; if address :contains "to" "vestingbar" { - redirect "stephan@example.com"; - fileinto "INBOX.vestingbar"; +# redirect "stephan@example.com"; +# fileinto "INBOX.vestingbar"; keep; } else { discard; } -redirect "stephan@rename-it.nl"; -redirect "nico@example.nl"; -redirect "stephan@example.com"; +#redirect "stephan@rename-it.nl"; +#redirect "nico@example.nl"; +#redirect "stephan@example.com"; -fileinto "INBOX.frop"; -fileinto "INBOX"; +#fileinto "INBOX.frop"; +#fileinto "INBOX"; keep; discard; diff --git a/src/lib-sieve/sieve-actions.c b/src/lib-sieve/sieve-actions.c index a62ce74b6..e20ba4982 100644 --- a/src/lib-sieve/sieve-actions.c +++ b/src/lib-sieve/sieve-actions.c @@ -1,3 +1,8 @@ +#include "lib.h" +#include "str-sanitize.h" +#include "mail-storage.h" +#include "mail-namespace.h" + #include "sieve-interpreter.h" #include "sieve-result.h" #include "sieve-actions.h" @@ -26,7 +31,7 @@ static bool act_store_commit const struct sieve_action_exec_env *aenv, void *tr_context); static void act_store_rollback (const struct sieve_action *action ATTR_UNUSED, - const struct sieve_action_exec_env *aenv, void *tr_context); + const struct sieve_action_exec_env *aenv, void *tr_context, bool success); const struct sieve_action act_store = { "store", @@ -79,31 +84,128 @@ static void act_store_print /* Store transaction */ +static void act_store_get_storage_error +(const struct sieve_action_exec_env *aenv, struct act_store_transaction *trans) +{ + enum mail_error error; + pool_t pool = sieve_result_pool(aenv->result); + + trans->error = p_strdup(pool, + mail_storage_get_last_error(trans->namespace->storage, &error)); +} + static bool act_store_start (const struct sieve_action *action ATTR_UNUSED, const struct sieve_action_exec_env *aenv, void *context, void **tr_context) { + struct act_store_context *ctx = (struct act_store_context *) context; + struct act_store_transaction *trans; + struct mail_namespace *ns; + struct mailbox *box; + pool_t pool; + + ns = mail_namespace_find(aenv->mailenv->namespaces, &ctx->folder); + if (ns == NULL) + return FALSE; + + box = mailbox_open(ns->storage, ctx->folder, NULL, MAILBOX_OPEN_FAST | + MAILBOX_OPEN_KEEP_RECENT); + + pool = sieve_result_pool(aenv->result); + trans = p_new(pool, struct act_store_transaction, 1); + trans->context = ctx; + trans->namespace = ns; + trans->box = box; + + if ( box == NULL ) { + printf("Open failed\n"); + act_store_get_storage_error(aenv, trans); + } + + *tr_context = (void *)trans; + return TRUE; } static bool act_store_execute (const struct sieve_action *action ATTR_UNUSED, const struct sieve_action_exec_env *aenv, void *tr_context) -{ +{ + struct act_store_transaction *trans = + (struct act_store_transaction *) tr_context; + + if ( trans->box == NULL ) return FALSE; + + trans->mail_trans = mailbox_transaction_begin + (trans->box, MAILBOX_TRANSACTION_FLAG_EXTERNAL); + + if (mailbox_copy(trans->mail_trans, aenv->msgdata->mail, 0, NULL, NULL) < 0) { + printf("Copy failed\n"); + act_store_get_storage_error(aenv, trans); + return FALSE; + } + return TRUE; } +static void act_store_log_status +(struct act_store_transaction *trans, + const struct sieve_message_data *msgdata, bool rolled_back, bool status ) +{ + const char *msgid, *mailbox_name; + + if (mail_get_first_header(msgdata->mail, "Message-ID", &msgid) <= 0) + msgid = ""; + else + msgid = str_sanitize(msgid, 80); + + if ( trans->box == NULL ) + mailbox_name = str_sanitize(trans->context->folder, 80); + else + mailbox_name = str_sanitize(mailbox_get_name(trans->box), 80); + + if (!rolled_back && status) { + i_info("msgid=%s: saved mail to %s", msgid, mailbox_name); + } else { + const char *errstr; + enum mail_error error; + + if ( trans->error != NULL ) + errstr = trans->error; + else + errstr = mail_storage_get_last_error(trans->namespace->storage, &error); + + if ( status ) + i_info("msgid=%s: save to %s aborted.", msgid, mailbox_name); + else + i_info("msgid=%s: save failed to %s: %s", msgid, mailbox_name, errstr); + } +} + static bool act_store_commit (const struct sieve_action *action ATTR_UNUSED, const struct sieve_action_exec_env *aenv, void *tr_context) { - return TRUE; + struct act_store_transaction *trans = + (struct act_store_transaction *) tr_context; + bool status = mailbox_transaction_commit(&trans->mail_trans); + + act_store_log_status(trans, aenv->msgdata, FALSE, status); + + return status; } static void act_store_rollback (const struct sieve_action *action ATTR_UNUSED, - const struct sieve_action_exec_env *aenv, void *tr_context) -{ + const struct sieve_action_exec_env *aenv, void *tr_context, bool success) +{ + struct act_store_transaction *trans = + (struct act_store_transaction *) tr_context; + + if ( trans->mail_trans != NULL ) + mailbox_transaction_rollback(&trans->mail_trans); + + act_store_log_status(trans, aenv->msgdata, TRUE, success); } diff --git a/src/lib-sieve/sieve-actions.h b/src/lib-sieve/sieve-actions.h index 64b298fea..f7dd0cde9 100644 --- a/src/lib-sieve/sieve-actions.h +++ b/src/lib-sieve/sieve-actions.h @@ -1,9 +1,13 @@ #ifndef __SIEVE_ACTIONS_H #define __SIEVE_ACTIONS_H +#include "lib.h" +#include "mail-storage.h" + #include "sieve-common.h" -struct sieve_action_exec_env { +struct sieve_action_exec_env { + struct sieve_result *result; const struct sieve_message_data *msgdata; const struct sieve_mail_environment *mailenv; }; @@ -34,7 +38,7 @@ struct sieve_action { const struct sieve_action_exec_env *aenv, void *tr_context); void (*rollback) (const struct sieve_action *action, - const struct sieve_action_exec_env *aenv, void *tr_context); + const struct sieve_action_exec_env *aenv, void *tr_context, bool success); }; /* Actions common to multiple commands */ @@ -45,6 +49,14 @@ struct act_store_context { const char *folder; }; +struct act_store_transaction { + struct act_store_context *context; + struct mail_namespace *namespace; + struct mailbox *box; + struct mailbox_transaction_context *mail_trans; + const char *error; +}; + bool sieve_act_store_add_to_result (const struct sieve_runtime_env *renv, const char *folder); diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c index e2b4f71bf..66c3e45ad 100644 --- a/src/lib-sieve/sieve-result.c +++ b/src/lib-sieve/sieve-result.c @@ -12,6 +12,7 @@ struct sieve_result_action { const struct sieve_action *action; void *context; void *tr_context; + bool success; struct sieve_result_action *prev, *next; }; @@ -33,6 +34,7 @@ struct sieve_result *sieve_result_create(void) pool = pool_alloconly_create("sieve_result", 4096); result = p_new(pool, struct sieve_result, 1); result->pool = pool; + result->action_env.result = result; result->first_action = NULL; result->last_action = NULL; @@ -73,7 +75,7 @@ bool sieve_result_add_action { struct sieve_result *result = renv->result; struct sieve_result_action *raction; - + /* First, check for duplicates or conflicts */ raction = result->first_action; while ( raction != NULL ) { @@ -105,6 +107,7 @@ bool sieve_result_add_action raction->action = action; raction->context = context; raction->tr_context = NULL; + raction->success = FALSE; /* Add */ if ( result->first_action == NULL ) { @@ -149,6 +152,8 @@ bool sieve_result_execute { bool success = TRUE, commit_ok; struct sieve_result_action *rac; + struct sieve_result_action *last_attempted; + result->action_env.msgdata = msgdata; result->action_env.mailenv = menv; @@ -162,8 +167,9 @@ bool sieve_result_execute const struct sieve_action *act = rac->action; if ( act->start != NULL ) { - success = success && act->start(act, &result->action_env, rac->context, + rac->success = act->start(act, &result->action_env, rac->context, &rac->tr_context); + success = success && rac->success; } rac = rac->next; } @@ -172,7 +178,9 @@ bool sieve_result_execute printf("\nTransaction execute:\n"); - rac = result->first_action; + if ( success ) + rac = result->first_action; + while ( success && rac != NULL ) { const struct sieve_action *act = rac->action; @@ -180,7 +188,8 @@ bool sieve_result_execute void *context = rac->tr_context == NULL ? rac->context : rac->tr_context; - success = success && act->execute(act, &result->action_env, context); + rac->success = act->execute(act, &result->action_env, context); + success = success && rac->success; } rac = rac->next; } @@ -192,8 +201,9 @@ bool sieve_result_execute printf("\nTransaction rollback:\n"); commit_ok = success; + last_attempted = rac; rac = result->first_action; - while ( rac != NULL ) { + while ( rac != NULL && rac != last_attempted ) { const struct sieve_action *act = rac->action; void *context = rac->tr_context == NULL ? rac->context : rac->tr_context; @@ -203,7 +213,7 @@ bool sieve_result_execute commit_ok = act->commit(act, &result->action_env, context) && commit_ok; } else { if ( act->rollback != NULL ) - act->rollback(act, &result->action_env, context); + act->rollback(act, &result->action_env, context, rac->success); } rac = rac->next; } diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h index ffb807881..97dd8e51a 100644 --- a/src/lib-sieve/sieve.h +++ b/src/lib-sieve/sieve.h @@ -16,6 +16,7 @@ struct sieve_message_data { struct sieve_mail_environment { const char *inbox; + struct mail_namespace *namespaces; /* Interface for sending mail (callbacks if you like) */ int (*send_rejection) diff --git a/src/sieve-bin/Makefile.am b/src/sieve-bin/Makefile.am index daed7c645..c677cdd4d 100644 --- a/src/sieve-bin/Makefile.am +++ b/src/sieve-bin/Makefile.am @@ -9,6 +9,8 @@ AM_CPPFLAGS = \ -I$(dovecot_incdir)/src/lib-storage \ -I$(dovecot_incdir)/src/lib-storage/index \ -I$(dovecot_incdir)/src/lib-storage/index/raw \ + -I$(dovecot_incdir)/src/lib-storage/index/mbox \ + -I$(dovecot_incdir)/src/lib-storage/index/maildir \ -I$(dovecot_incdir)/src/deliver sievec_LDFLAGS = -export-dynamic -Wl,--start-group @@ -19,6 +21,8 @@ libs = \ $(top_srcdir)/src/lib-sieve/libsieve.la \ $(dovecot_incdir)/src/lib-storage/list/libstorage_list.a \ $(dovecot_incdir)/src/lib-storage/index/raw/libstorage_raw.a \ + $(dovecot_incdir)/src/lib-storage/index/maildir/libstorage_maildir.a \ + $(dovecot_incdir)/src/lib-storage/index/mbox/libstorage_mbox.a \ $(dovecot_incdir)/src/lib-storage/index/libstorage_index.a \ $(dovecot_incdir)/src/lib-storage/libstorage.a \ $(dovecot_incdir)/src/lib-index/libindex.a \ @@ -43,6 +47,7 @@ sieve_exec_DEPENDENCIES = $(libs) common_sources = \ bin-common.c \ + namespaces.c \ mail-raw.c sievec_SOURCES = \ @@ -58,4 +63,5 @@ sieve_exec_SOURCES = \ noinst_HEADERS = \ bin-common.h \ + namespaces.h \ mail-raw.h diff --git a/src/sieve-bin/mail-raw.c b/src/sieve-bin/mail-raw.c index a426eb19c..fb314c156 100644 --- a/src/sieve-bin/mail-raw.c +++ b/src/sieve-bin/mail-raw.c @@ -28,20 +28,6 @@ #define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON" -/* Hideous .... */ - -extern struct mail_storage raw_storage; -void mail_storage_register_all(void) { - mail_storage_class_register(&raw_storage); -} - -extern struct mailbox_list fs_mailbox_list; -void index_mailbox_list_init(void); -void mailbox_list_register_all(void) { - mailbox_list_register(&fs_mailbox_list); - index_mailbox_list_init(); -} - /* After buffer grows larger than this, create a temporary file to /tmp where to read the mail. */ #define MAIL_MAX_MEMORY_BUFFER (1024*128) @@ -91,29 +77,11 @@ static struct istream *create_raw_stream(int fd) return input; } -static pool_t namespaces_pool; static struct mail_namespace *raw_ns; -void mail_raw_init(void) +void mail_raw_init(pool_t namespaces_pool, const char *user) { - const char *user, *error; - struct passwd *pw; - uid_t process_euid; - - mail_storage_init(); - mail_storage_register_all(); - mailbox_list_register_all(); - - process_euid = geteuid(); - pw = getpwuid(process_euid); - if (pw != NULL) { - user = t_strdup(pw->pw_name); - } else { - i_fatal("Couldn't lookup our username (uid=%s)", - dec2str(process_euid)); - } - - namespaces_pool = pool_alloconly_create("namespaces", 1024); + const char *error; raw_ns = mail_namespaces_init_empty(namespaces_pool); raw_ns->flags |= NAMESPACE_FLAG_INTERNAL; @@ -173,8 +141,5 @@ void mail_raw_close(struct mail_raw *mailr) void mail_raw_deinit(void) { mail_namespaces_deinit(&raw_ns); - mail_storage_deinit(); - - pool_unref(&namespaces_pool); } diff --git a/src/sieve-bin/mail-raw.h b/src/sieve-bin/mail-raw.h index 3848cc1e4..f54372e8e 100644 --- a/src/sieve-bin/mail-raw.h +++ b/src/sieve-bin/mail-raw.h @@ -10,7 +10,7 @@ struct mail_raw { struct mailbox_transaction_context *trans; }; -void mail_raw_init(void); +void mail_raw_init(pool_t namespaces_pool, const char *user); struct mail_raw *mail_raw_open(int fd); void mail_raw_close(struct mail_raw *mailr); void mail_raw_deinit(void); diff --git a/src/sieve-bin/namespaces.c b/src/sieve-bin/namespaces.c new file mode 100644 index 000000000..cc1378953 --- /dev/null +++ b/src/sieve-bin/namespaces.c @@ -0,0 +1,64 @@ +/* Copyright (c) 2005-2007 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "istream.h" +#include "istream-seekable.h" +#include "fd-set-nonblock.h" +#include "str.h" +#include "str-sanitize.h" +#include "strescape.h" +#include "message-address.h" +#include "raw-storage.h" +#include "mbox-storage.h" +#include "maildir-storage.h" +#include "mail-namespace.h" + +#include "namespaces.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <pwd.h> + +#define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON" + +/* Hideous .... */ + +extern struct mail_storage raw_storage; +extern struct mail_storage maildir_storage; +extern struct mail_storage mbox_storage; +void mail_storage_register_all(void) { + mail_storage_class_register(&raw_storage); + mail_storage_class_register(&mbox_storage); + mail_storage_class_register(&maildir_storage); +} + +extern struct mailbox_list maildir_mailbox_list; +extern struct mailbox_list fs_mailbox_list; +void index_mailbox_list_init(void); +void mailbox_list_register_all(void) { +mailbox_list_register(&maildir_mailbox_list); +mailbox_list_register(&fs_mailbox_list); +index_mailbox_list_init(); +} + +static pool_t namespaces_pool; + +pool_t namespaces_init(void) +{ + mail_storage_init(); + mail_storage_register_all(); + mailbox_list_register_all(); + + namespaces_pool = pool_alloconly_create("namespaces", 1024); + + return namespaces_pool; +} + +void namespaces_deinit(void) +{ + mail_storage_deinit(); + pool_unref(&namespaces_pool); +} + diff --git a/src/sieve-bin/namespaces.h b/src/sieve-bin/namespaces.h new file mode 100644 index 000000000..5f542d3f6 --- /dev/null +++ b/src/sieve-bin/namespaces.h @@ -0,0 +1,7 @@ +#ifndef __NAMESPACES_H +#define __NAMESPACES_H + +pool_t namespaces_init(void); +void namespaces_deinit(void); + +#endif /* __MAIL_RAW_H */ diff --git a/src/sieve-bin/sieve-exec.c b/src/sieve-bin/sieve-exec.c index 1088480bc..b52939b6e 100644 --- a/src/sieve-bin/sieve-exec.c +++ b/src/sieve-bin/sieve-exec.c @@ -1,13 +1,20 @@ /* Copyright (c) 2005-2007 Dovecot authors, see the included COPYING file */ #include "lib.h" +#include "mail-storage.h" +#include "mail-namespace.h" #include "bin-common.h" #include "mail-raw.h" +#include "namespaces.h" #include "sieve.h" #include <stdio.h> #include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <pwd.h> + #define DEFAULT_SENDMAIL_PATH "/usr/lib/sendmail" #define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON" @@ -31,7 +38,12 @@ static int sieve_send_forward int main(int argc, char **argv) { + const char *user; + struct passwd *pw; + uid_t process_euid; int sfd, mfd; + pool_t namespaces_pool; + struct mail_namespace *ns; struct mail_raw *mailr; struct sieve_binary *sbin; struct sieve_message_data msgdata; @@ -84,8 +96,26 @@ int main(int argc, char **argv) close(sfd); - mail_raw_init(); + process_euid = geteuid(); + pw = getpwuid(process_euid); + if (pw != NULL) { + user = t_strdup(pw->pw_name); + } else { + i_fatal("Couldn't lookup our username (uid=%s)", + dec2str(process_euid)); + } + + env_put(t_strdup_printf("NAMESPACE_1=%s", "maildir:/home/stephan/Maildir")); + env_put("NAMESPACE_1_PREFIX=INBOX."); + env_put("NAMESPACE_1_LIST=yes"); + env_put("NAMESPACE_1_SUBSCRIPTIONS=yes"); + + namespaces_pool = namespaces_init(); + + if (mail_namespaces_init(namespaces_pool, user, &ns) < 0) + i_fatal("Namespace initialization failed"); + mail_raw_init(namespaces_pool, user); mailr = mail_raw_open(mfd); /* Collect necessary message data */ @@ -98,6 +128,7 @@ int main(int argc, char **argv) memset(&mailenv, 0, sizeof(mailenv)); mailenv.inbox = "INBOX"; + mailenv.namespaces = ns; mailenv.send_forward = sieve_send_forward; mailenv.send_rejection = sieve_send_rejection; @@ -110,6 +141,8 @@ int main(int argc, char **argv) close(mfd); mail_raw_deinit(); + mail_namespaces_deinit(&ns); + namespaces_deinit(); bin_deinit(); return 0; } diff --git a/src/sieve-bin/sieve-test.c b/src/sieve-bin/sieve-test.c index fd623c3fc..3a60aaa09 100644 --- a/src/sieve-bin/sieve-test.c +++ b/src/sieve-bin/sieve-test.c @@ -4,17 +4,26 @@ #include "bin-common.h" #include "mail-raw.h" +#include "namespaces.h" #include "sieve.h" #include <stdio.h> #include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <pwd.h> + #define DEFAULT_SENDMAIL_PATH "/usr/lib/sendmail" #define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON" int main(int argc, char **argv) { + const char *user; + struct passwd *pw; + uid_t process_euid; int sfd, mfd; + pool_t namespaces_pool; struct mail_raw *mailr; struct sieve_binary *sbin; struct sieve_message_data msgdata; @@ -64,8 +73,18 @@ int main(int argc, char **argv) (void) sieve_dump(sbin); close(sfd); - - mail_raw_init(); + + process_euid = geteuid(); + pw = getpwuid(process_euid); + if (pw != NULL) { + user = t_strdup(pw->pw_name); + } else { + i_fatal("Couldn't lookup our username (uid=%s)", + dec2str(process_euid)); + } + + namespaces_pool = namespaces_init(); + mail_raw_init(namespaces_pool, user); mailr = mail_raw_open(mfd); @@ -79,8 +98,6 @@ int main(int argc, char **argv) memset(&mailenv, 0, sizeof(mailenv)); mailenv.inbox = "INBOX"; - mailenv.send_forward = NULL; - mailenv.send_rejection = NULL; /* Run the test */ (void) sieve_test(sbin, &msgdata, &mailenv); @@ -92,6 +109,7 @@ int main(int argc, char **argv) close(mfd); mail_raw_deinit(); + namespaces_deinit(); bin_deinit(); return 0; } -- GitLab