From: Timo Sirainen Date: Mon, 13 Apr 2009 19:45:17 +0000 (-0400) Subject: Renamed deliver to dovecot-lda and moved most of its code to lib-lda. X-Git-Tag: 2.0.alpha1~960 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=58c61ac5650583d21c891e61e051c614290d31fb;p=thirdparty%2Fdovecot%2Fcore.git Renamed deliver to dovecot-lda and moved most of its code to lib-lda. --HG-- branch : HEAD --- diff --git a/.hgignore b/.hgignore index 7d7db71a1f..28f032ac60 100644 --- a/.hgignore +++ b/.hgignore @@ -55,7 +55,7 @@ src/auth/checkpassword-reply src/auth/dovecot-auth src/config/all-settings.c src/config/doveconf -src/deliver/deliver +src/lda/dovecot-lda src/dict/dict src/imap-login/imap-login src/imap/imap diff --git a/configure.in b/configure.in index 98cc501a56..418f1b4582 100644 --- a/configure.in +++ b/configure.in @@ -2360,6 +2360,7 @@ src/lib-charset/Makefile src/lib-dict/Makefile src/lib-imap/Makefile src/lib-index/Makefile +src/lib-lda/Makefile src/lib-mail/Makefile src/lib-master/Makefile src/lib-ntlm/Makefile @@ -2378,7 +2379,7 @@ src/lib-storage/index/shared/Makefile src/lib-storage/register/Makefile src/auth/Makefile src/config/Makefile -src/deliver/Makefile +src/lda/Makefile src/dict/Makefile src/imap/Makefile src/imap-login/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index d23981a8fb..da4660a5ca 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,7 +24,7 @@ SUBDIRS = \ imap \ pop3-login \ pop3 \ - deliver \ + lda \ config \ tests \ util \ diff --git a/src/deliver/deliver.h b/src/deliver/deliver.h deleted file mode 100644 index 5c4bafd48f..0000000000 --- a/src/deliver/deliver.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef DELIVER_H -#define DELIVER_H - -#include - -#ifndef EX_CONFIG -# define EX_CONFIG 78 /* HP-UX */ -#endif - -#include "lib.h" -#include "mail-storage.h" -#include "deliver-settings.h" - -extern const struct deliver_settings *deliver_set; -extern bool mailbox_autosubscribe; -extern bool mailbox_autocreate; -extern bool tried_default_save; - -typedef int deliver_mail_func_t(struct mail_namespace *namespaces, - struct mail_storage **storage_r, - struct mail *mail, - const char *destaddr, const char *mailbox); - -extern deliver_mail_func_t *deliver_mail; - -/* Save a mail into given mailbox with given flags and keywords. */ -int deliver_save(struct mail_namespace *namespaces, - struct mail_storage **storage_r, const char *mailbox, - struct mail *mail, enum mail_flags flags, - const char *const *keywords); - -/* Extracts user@domain from Return-Path header. Returns NULL if not found. */ -const char *deliver_get_return_address(struct mail *mail); - -/* Returns a new unique Message-ID */ -const char *deliver_get_new_message_id(void); - -#endif diff --git a/src/deliver/mail-send.h b/src/deliver/mail-send.h deleted file mode 100644 index fd1e05e6c9..0000000000 --- a/src/deliver/mail-send.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef MAIL_SEND_H -#define MAIL_SEND_H - -struct mail; - -int mail_send_rejection(struct mail *mail, const char *recipient, - const char *reason); -int mail_send_forward(struct mail *mail, const char *forwardto); - -#endif diff --git a/src/deliver/Makefile.am b/src/lda/Makefile.am similarity index 51% rename from src/deliver/Makefile.am rename to src/lda/Makefile.am index c3d2d0add5..3eae845cd9 100644 --- a/src/deliver/Makefile.am +++ b/src/lda/Makefile.am @@ -1,6 +1,6 @@ pkglibexecdir = $(libexecdir)/dovecot -pkglibexec_PROGRAMS = deliver +pkglibexec_PROGRAMS = dovecot-lda AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib \ @@ -9,38 +9,22 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib-imap \ -I$(top_srcdir)/src/lib-index \ -I$(top_srcdir)/src/lib-master \ + -I$(top_srcdir)/src/lib-lda \ -I$(top_srcdir)/src/lib-storage \ -I$(top_srcdir)/src/lib-storage/index \ -I$(top_srcdir)/src/lib-storage/index/raw \ -DPKG_RUNDIR=\""$(rundir)"\" -deliver_LDFLAGS = -export-dynamic +dovecot_lda_LDFLAGS = -export-dynamic libs = \ + ../lib-lda/liblda.a \ ../lib-storage/libdovecot-storage.la \ ../lib-dovecot/libdovecot.la -deliver_LDADD = $(libs) +dovecot_lda_LDADD = $(libs) -deliver_DEPENDENCIES = $(libs) +dovecot_lda_DEPENDENCIES = $(libs) -deliver_SOURCES = \ - deliver.c \ - deliver-settings.c \ - duplicate.c \ - mail-send.c \ - smtp-client.c - -headers = \ - deliver.h \ - deliver-settings.h \ - duplicate.h \ - mail-send.h \ - smtp-client.h - -if INSTALL_HEADERS - pkginc_libdir=$(pkgincludedir)/src/deliver - pkginc_lib_HEADERS = $(headers) -else - noinst_HEADERS = $(headers) -endif +dovecot_lda_SOURCES = \ + main.c diff --git a/src/deliver/deliver.c b/src/lda/main.c similarity index 54% rename from src/deliver/deliver.c rename to src/lda/main.c index a55d775fa0..2dc560e8a1 100644 --- a/src/deliver/deliver.c +++ b/src/lda/main.c @@ -2,7 +2,6 @@ #include "lib.h" #include "lib-signals.h" -#include "ioloop.h" #include "env-util.h" #include "fd-set-nonblock.h" #include "istream.h" @@ -10,7 +9,6 @@ #include "str.h" #include "str-sanitize.h" #include "strescape.h" -#include "var-expand.h" #include "rfc822-parser.h" #include "message-address.h" #include "imap-utf7.h" @@ -20,14 +18,20 @@ #include "mail-storage-service.h" #include "mail-namespace.h" #include "raw-storage.h" +#include "mail-deliver.h" #include "mail-send.h" #include "duplicate.h" #include "mbox-from.h" -#include "deliver.h" +#include "lda-settings.h" #include #include #include +#include + +#ifndef EX_CONFIG +# define EX_CONFIG 78 /* for HP-UX */ +#endif #define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON" @@ -40,219 +44,8 @@ static const char *wanted_headers[] = { NULL }; -const struct deliver_settings *deliver_set; -deliver_mail_func_t *deliver_mail = NULL; -bool mailbox_autosubscribe; -bool mailbox_autocreate; -bool tried_default_save = FALSE; - -/* FIXME: these two should be in some context struct instead of as globals.. */ -static const char *default_mailbox_name = NULL; -static bool saved_mail = FALSE; -static char *explicit_envelope_sender = NULL; - static struct master_service *service; -static const char *deliver_get_address(struct mail *mail, const char *header) -{ - struct message_address *addr; - const char *str; - - if (mail_get_first_header(mail, header, &str) <= 0) - return NULL; - addr = message_address_parse(pool_datastack_create(), - (const unsigned char *)str, - strlen(str), 1, FALSE); - return addr == NULL || addr->mailbox == NULL || addr->domain == NULL || - *addr->mailbox == '\0' || *addr->domain == '\0' ? - NULL : t_strconcat(addr->mailbox, "@", addr->domain, NULL); -} - -static const struct var_expand_table * -get_log_var_expand_table(struct mail *mail, const char *message) -{ - static struct var_expand_table static_tab[] = { - { '$', NULL, NULL }, - { 'm', NULL, "msgid" }, - { 's', NULL, "subject" }, - { 'f', NULL, "from" }, - { '\0', NULL, NULL } - }; - struct var_expand_table *tab; - unsigned int i; - - tab = t_malloc(sizeof(static_tab)); - memcpy(tab, static_tab, sizeof(static_tab)); - - tab[0].value = message; - (void)mail_get_first_header(mail, "Message-ID", &tab[1].value); - (void)mail_get_first_header(mail, "Subject", &tab[2].value); - tab[3].value = deliver_get_address(mail, "From"); - for (i = 1; tab[i].key != '\0'; i++) - tab[i].value = str_sanitize(tab[i].value, 80); - return tab; -} - -static void -deliver_log(struct mail *mail, const char *fmt, ...) ATTR_FORMAT(2, 3); - -static void deliver_log(struct mail *mail, const char *fmt, ...) -{ - va_list args; - string_t *str; - const char *msg; - - va_start(args, fmt); - msg = t_strdup_vprintf(fmt, args); - - str = t_str_new(256); - var_expand(str, deliver_set->deliver_log_format, - get_log_var_expand_table(mail, msg)); - i_info("%s", str_c(str)); - va_end(args); -} - -static struct mailbox * -mailbox_open_or_create_synced(struct mail_namespace *namespaces, - struct mail_storage **storage_r, - const char *name) -{ - struct mail_namespace *ns; - struct mailbox *box; - enum mail_error error; - enum mailbox_open_flags open_flags = MAILBOX_OPEN_FAST | - MAILBOX_OPEN_KEEP_RECENT | MAILBOX_OPEN_SAVEONLY | - MAILBOX_OPEN_POST_SESSION; - - if (strcasecmp(name, "INBOX") == 0) { - /* deliveries to INBOX must always succeed, - regardless of ACLs */ - open_flags |= MAILBOX_OPEN_IGNORE_ACLS; - } - - ns = mail_namespace_find(namespaces, &name); - if (ns == NULL) { - *storage_r = NULL; - return NULL; - } - *storage_r = ns->storage; - - if (*name == '\0') { - /* delivering to a namespace prefix means we actually want to - deliver to the INBOX instead */ - return NULL; - } - - box = mailbox_open(storage_r, name, NULL, open_flags); - if (box != NULL || !mailbox_autocreate) - return box; - - (void)mail_storage_get_last_error(*storage_r, &error); - if (error != MAIL_ERROR_NOTFOUND) - return NULL; - - /* try creating it. */ - if (mail_storage_mailbox_create(*storage_r, name, FALSE) < 0) - return NULL; - if (mailbox_autosubscribe) { - /* (try to) subscribe to it */ - (void)mailbox_list_set_subscribed(ns->list, name, TRUE); - } - - /* and try opening again */ - box = mailbox_open(storage_r, name, NULL, open_flags); - if (box == NULL) - return NULL; - - if (mailbox_sync(box, 0, 0, NULL) < 0) { - mailbox_close(&box); - return NULL; - } - return box; -} - -int deliver_save(struct mail_namespace *namespaces, - struct mail_storage **storage_r, const char *mailbox, - struct mail *mail, enum mail_flags flags, - const char *const *keywords) -{ - struct mailbox *box; - struct mailbox_transaction_context *t; - struct mail_save_context *save_ctx; - struct mail_keywords *kw; - enum mail_error error; - const char *mailbox_name; - bool default_save; - int ret = 0; - - default_save = strcmp(mailbox, default_mailbox_name) == 0; - if (default_save) - tried_default_save = TRUE; - - mailbox_name = str_sanitize(mailbox, 80); - box = mailbox_open_or_create_synced(namespaces, storage_r, mailbox); - if (box == NULL) { - if (*storage_r == NULL) { - deliver_log(mail, - "save failed to %s: Unknown namespace", - mailbox_name); - return -1; - } - if (default_save && - strcmp((*storage_r)->ns->prefix, mailbox) == 0) { - /* silently store to the INBOX instead */ - return -1; - } - deliver_log(mail, "save failed to %s: %s", mailbox_name, - mail_storage_get_last_error(*storage_r, &error)); - return -1; - } - - t = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_EXTERNAL); - - kw = str_array_length(keywords) == 0 ? NULL : - mailbox_keywords_create_valid(box, keywords); - save_ctx = mailbox_save_alloc(t); - mailbox_save_set_flags(save_ctx, flags, kw); - if (mailbox_copy(&save_ctx, mail) < 0) - ret = -1; - mailbox_keywords_free(box, &kw); - - if (ret < 0) - mailbox_transaction_rollback(&t); - else - ret = mailbox_transaction_commit(&t); - - if (ret == 0) { - saved_mail = TRUE; - deliver_log(mail, "saved mail to %s", mailbox_name); - } else { - deliver_log(mail, "save failed to %s: %s", mailbox_name, - mail_storage_get_last_error(*storage_r, &error)); - } - - mailbox_close(&box); - return ret; -} - -const char *deliver_get_return_address(struct mail *mail) -{ - if (explicit_envelope_sender != NULL) - return explicit_envelope_sender; - - return deliver_get_address(mail, "Return-Path"); -} - -const char *deliver_get_new_message_id(void) -{ - static int count = 0; - - return t_strdup_printf("", - dec2str(ioloop_timeval.tv_sec), - dec2str(ioloop_timeval.tv_usec), - count++, deliver_set->hostname); -} - static const char *escape_local_part(const char *local_part) { const char *p; @@ -293,7 +86,8 @@ static const char *address_sanitize(const char *address) static struct istream * -create_raw_stream(const char *temp_path_prefix, int fd, time_t *mtime_r) +create_raw_stream(struct mail_deliver_context *ctx, + const char *temp_path_prefix, int fd, time_t *mtime_r) { struct istream *input, *input2, *input_list[2]; const unsigned char *data; @@ -326,10 +120,10 @@ create_raw_stream(const char *temp_path_prefix, int fd, time_t *mtime_r) } } - if (sender != NULL && explicit_envelope_sender == NULL) { + if (sender != NULL && ctx->src_envelope_sender == NULL) { /* use the envelope sender from From_-line, but only if it hasn't been specified with -f already. */ - explicit_envelope_sender = i_strdup(sender); + ctx->src_envelope_sender = p_strdup(ctx->pool, sender); } i_free(sender); @@ -377,15 +171,15 @@ static void print_help(void) { printf( "Usage: deliver [-c ] [-a
] [-d ] [-p ]\n" -" [-f ] [-m ] [-n] [-s] [-e] [-k]\n"); +" [-f ] [-m ] [-e] [-k]\n"); } int main(int argc, char *argv[]) { + struct mail_deliver_context ctx; enum mail_storage_service_flags service_flags = 0; - const char *mailbox = "INBOX"; - const char *destaddr, *user, *errstr, *path, *getopt_str; - struct mail_user *mail_user, *raw_mail_user; + const char *user, *errstr, *path, *getopt_str; + struct mail_user *raw_mail_user; struct mail_namespace *raw_ns; struct mail_namespace_settings raw_ns_set; struct mail_storage *storage; @@ -394,7 +188,6 @@ int main(int argc, char *argv[]) struct istream *input; struct mailbox_transaction_context *t; struct mailbox_header_lookup_ctx *headers_ctx; - struct mail *mail; char cwd[PATH_MAX]; void **sets; uid_t process_euid; @@ -430,8 +223,10 @@ int main(int argc, char *argv[]) lib_signals_ignore(SIGXFSZ, TRUE); #endif - mailbox_autocreate = TRUE; - destaddr = path = NULL; + memset(&ctx, 0, sizeof(ctx)); + ctx.pool = pool_alloconly_create("mail deliver context", 256); + ctx.dest_mailbox_name = "INBOX"; + path = NULL; user = getenv("USER"); getopt_str = t_strconcat("a:d:p:ekm:nsf:", @@ -440,7 +235,7 @@ int main(int argc, char *argv[]) switch (c) { case 'a': /* destination address */ - destaddr = optarg; + ctx.dest_addr = optarg; break; case 'd': /* destination user */ @@ -464,25 +259,20 @@ int main(int argc, char *argv[]) /* destination mailbox. Ignore -m "". This allows doing -m ${extension} in Postfix to handle user+mailbox */ - if (*optarg != '\0') { + if (*optarg != '\0') T_BEGIN { str = t_str_new(256); if (imap_utf8_to_utf7(optarg, str) < 0) { i_fatal("Mailbox name not UTF-8: %s", - mailbox); + optarg); } - mailbox = str_c(str); - } - break; - case 'n': - mailbox_autocreate = FALSE; - break; - case 's': - mailbox_autosubscribe = TRUE; + ctx.dest_mailbox_name = + p_strdup(ctx.pool, str_c(str)); + } T_END; break; case 'f': /* envelope sender address */ - explicit_envelope_sender = - i_strdup(address_sanitize(optarg)); + ctx.src_envelope_sender = + p_strdup(ctx.pool, address_sanitize(optarg)); break; default: if (!master_service_parse_option(service, c, optarg)) { @@ -524,10 +314,10 @@ int main(int argc, char *argv[]) } service_flags |= MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT; - mail_user = mail_storage_service_init_user(service, user, - &deliver_setting_parser_info, service_flags); - deliver_set = mail_storage_service_get_settings(service); - duplicate_init(mail_user_set_get_storage_set(mail_user->set)); + ctx.dest_user = mail_storage_service_init_user(service, user, + &lda_setting_parser_info, service_flags); + ctx.set = mail_storage_service_get_settings(service); + duplicate_init(mail_user_set_get_storage_set(ctx.dest_user->set)); /* create a separate mail user for the internal namespace */ if (master_service_set(service, "mail_full_filesystem_access=yes") < 0) @@ -547,8 +337,8 @@ int main(int argc, char *argv[]) if (mail_storage_create(raw_ns, "raw", 0, &errstr) < 0) i_fatal("Couldn't create internal raw storage: %s", errstr); if (path == NULL) { - const char *prefix = mail_user_get_temp_prefix(mail_user); - input = create_raw_stream(prefix, 0, &mtime); + const char *prefix = mail_user_get_temp_prefix(ctx.dest_user); + input = create_raw_stream(&ctx, prefix, 0, &mtime); box = mailbox_open(&raw_ns->storage, "Dovecot Delivery Mail", input, MAILBOX_OPEN_NO_INDEX_FILES); i_stream_unref(&input); @@ -566,53 +356,25 @@ int main(int argc, char *argv[]) mail_storage_get_last_error(raw_ns->storage, &error)); } raw_box = (struct raw_mailbox *)box; - raw_box->envelope_sender = explicit_envelope_sender != NULL ? - explicit_envelope_sender : DEFAULT_ENVELOPE_SENDER; + raw_box->envelope_sender = ctx.src_envelope_sender != NULL ? + ctx.src_envelope_sender : DEFAULT_ENVELOPE_SENDER; raw_box->mtime = mtime; t = mailbox_transaction_begin(box, 0); headers_ctx = mailbox_header_lookup_init(box, wanted_headers); - mail = mail_alloc(t, 0, headers_ctx); - mail_set_seq(mail, 1); - - if (destaddr == NULL) { - destaddr = deliver_get_address(mail, "Envelope-To"); - if (destaddr == NULL) { - destaddr = strchr(user, '@') != NULL ? user : - t_strconcat(user, "@", - deliver_set->hostname, NULL); + ctx.src_mail = mail_alloc(t, 0, headers_ctx); + mail_set_seq(ctx.src_mail, 1); + + if (ctx.dest_addr == NULL) { + ctx.dest_addr = mail_deliver_get_address(&ctx, "Envelope-To"); + if (ctx.dest_addr == NULL) { + ctx.dest_addr = strchr(user, '@') != NULL ? user : + t_strconcat(user, "@", ctx.set->hostname, NULL); } } - storage = NULL; - default_mailbox_name = mailbox; - if (deliver_mail == NULL) - ret = -1; - else { - if (deliver_mail(mail_user->namespaces, &storage, mail, - destaddr, mailbox) <= 0) { - /* if message was saved, don't bounce it even though - the script failed later. */ - ret = saved_mail ? 0 : -1; - } else { - /* success. message may or may not have been saved. */ - ret = 0; - } - } - - if (ret < 0 && !tried_default_save) { - /* plugins didn't handle this. save into the default mailbox. */ - ret = deliver_save(mail_user->namespaces, - &storage, mailbox, mail, 0, NULL); - } - if (ret < 0 && strcasecmp(mailbox, "INBOX") != 0) { - /* still didn't work. try once more to save it - to INBOX. */ - ret = deliver_save(mail_user->namespaces, - &storage, "INBOX", mail, 0, NULL); - } - - if (ret < 0 ) { + ret = mail_deliver(&ctx, &storage); + if (ret < 0) { if (storage == NULL) { /* This shouldn't happen */ i_error("BUG: Saving failed for unknown storage"); @@ -628,7 +390,7 @@ int main(int argc, char *argv[]) } if (error != MAIL_ERROR_NOSPACE || - deliver_set->quota_full_tempfail) { + ctx.set->quota_full_tempfail) { /* Saving to INBOX should always work unless we're over quota. If it didn't, it's probably a configuration problem. */ @@ -636,26 +398,26 @@ int main(int argc, char *argv[]) } /* we'll have to reply with permanent failure */ - deliver_log(mail, "rejected: %s", - str_sanitize(errstr, 512)); + mail_deliver_log(&ctx, "rejected: %s", + str_sanitize(errstr, 512)); if (stderr_rejection) return EX_NOPERM; - ret = mail_send_rejection(mail, user, errstr); + ret = mail_send_rejection(&ctx, user, errstr); if (ret != 0) return ret < 0 ? EX_TEMPFAIL : ret; /* ok, rejection sent */ } - i_free(explicit_envelope_sender); - mail_free(&mail); + mail_free(&ctx.src_mail); mailbox_header_lookup_unref(&headers_ctx); mailbox_transaction_rollback(&t); mailbox_close(&box); - mail_user_unref(&mail_user); + mail_user_unref(&ctx.dest_user); mail_user_unref(&raw_mail_user); duplicate_deinit(); + pool_unref(&ctx.pool); mail_storage_service_deinit_user(); master_service_deinit(&service); diff --git a/src/lib-lda/Makefile.am b/src/lib-lda/Makefile.am new file mode 100644 index 0000000000..d7e967c949 --- /dev/null +++ b/src/lib-lda/Makefile.am @@ -0,0 +1,29 @@ +noinst_LIBRARIES = liblda.a + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-settings \ + -I$(top_srcdir)/src/lib-master \ + -I$(top_srcdir)/src/lib-mail \ + -I$(top_srcdir)/src/lib-storage + +liblda_a_SOURCES = \ + lda-settings.c \ + duplicate.c \ + mail-deliver.c \ + mail-send.c \ + smtp-client.c + +headers = \ + lda-settings.h \ + duplicate.h \ + mail-deliver.h \ + mail-send.h \ + smtp-client.h + +if INSTALL_HEADERS + pkginc_libdir=$(pkgincludedir)/src/lib-lda + pkginc_lib_HEADERS = $(headers) +else + noinst_HEADERS = $(headers) +endif diff --git a/src/deliver/duplicate.c b/src/lib-lda/duplicate.c similarity index 99% rename from src/deliver/duplicate.c rename to src/lib-lda/duplicate.c index 45884a5628..fd88c68ba8 100644 --- a/src/deliver/duplicate.c +++ b/src/lib-lda/duplicate.c @@ -7,6 +7,7 @@ #include "home-expand.h" #include "file-dotlock.h" #include "hash.h" +#include "mail-storage-settings.h" #include "duplicate.h" #include diff --git a/src/deliver/duplicate.h b/src/lib-lda/duplicate.h similarity index 91% rename from src/deliver/duplicate.h rename to src/lib-lda/duplicate.h index 4f220ae47e..5e8745376c 100644 --- a/src/deliver/duplicate.h +++ b/src/lib-lda/duplicate.h @@ -1,7 +1,7 @@ #ifndef DUPLICATE_H #define DUPLICATE_H -#include "mail-storage-settings.h" +struct mail_storage_settings; #define DUPLICATE_DEFAULT_KEEP (3600 * 24) diff --git a/src/deliver/deliver-settings.c b/src/lib-lda/lda-settings.c similarity index 51% rename from src/deliver/deliver-settings.c rename to src/lib-lda/lda-settings.c index 858008f87d..5f3bc7b827 100644 --- a/src/deliver/deliver-settings.c +++ b/src/lib-lda/lda-settings.c @@ -1,26 +1,21 @@ /* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */ -#include "deliver.h" -#include "array.h" -#include "hostpid.h" -#include "istream.h" +#include "lib.h" #include "settings-parser.h" -#include "mail-storage-settings.h" -#include "deliver-settings.h" +#include "lda-settings.h" #include -#include -static bool deliver_settings_check(void *_set, pool_t pool, const char **error_r); +static bool lda_settings_check(void *_set, pool_t pool, const char **error_r); #undef DEF #undef DEFLIST #define DEF(type, name) \ - { type, #name, offsetof(struct deliver_settings, name), NULL } + { type, #name, offsetof(struct lda_settings, name), NULL } #define DEFLIST(field, name, defines) \ - { SET_DEFLIST, name, offsetof(struct deliver_settings, field), defines } + { SET_DEFLIST, name, offsetof(struct lda_settings, field), defines } -static struct setting_define deliver_setting_defines[] = { +static struct setting_define lda_setting_defines[] = { DEF(SET_STR, postmaster_address), DEF(SET_STR, hostname), DEF(SET_STR, sendmail_path), @@ -28,13 +23,15 @@ static struct setting_define deliver_setting_defines[] = { DEF(SET_STR, rejection_reason), DEF(SET_STR, deliver_log_format), DEF(SET_BOOL, quota_full_tempfail), + DEF(SET_BOOL, lda_mailbox_autocreate), + DEF(SET_BOOL, lda_mailbox_autosubscribe), - { SET_STRLIST, "plugin", offsetof(struct deliver_settings, plugin_envs), NULL }, + { SET_STRLIST, "plugin", offsetof(struct lda_settings, plugin_envs), NULL }, SETTING_DEFINE_LIST_END }; -static struct deliver_settings deliver_default_settings = { +static struct lda_settings lda_default_settings = { MEMBER(postmaster_address) "", MEMBER(hostname) "", MEMBER(sendmail_path) "/usr/lib/sendmail", @@ -42,30 +39,32 @@ static struct deliver_settings deliver_default_settings = { MEMBER(rejection_reason) "Your message to <%t> was automatically rejected:%n%r", MEMBER(deliver_log_format) "msgid=%m: %$", - MEMBER(quota_full_tempfail) FALSE + MEMBER(quota_full_tempfail) FALSE, + MEMBER(lda_mailbox_autocreate) FALSE, + MEMBER(lda_mailbox_autosubscribe) FALSE }; -struct setting_parser_info deliver_setting_parser_info = { - MEMBER(defines) deliver_setting_defines, - MEMBER(defaults) &deliver_default_settings, +struct setting_parser_info lda_setting_parser_info = { + MEMBER(defines) lda_setting_defines, + MEMBER(defaults) &lda_default_settings, MEMBER(parent) NULL, MEMBER(dynamic_parsers) NULL, MEMBER(parent_offset) (size_t)-1, MEMBER(type_offset) (size_t)-1, - MEMBER(struct_size) sizeof(struct deliver_settings), + MEMBER(struct_size) sizeof(struct lda_settings), #ifdef CONFIG_BINARY MEMBER(check_func) NULL #else - MEMBER(check_func) deliver_settings_check + MEMBER(check_func) lda_settings_check #endif }; -static bool deliver_settings_check(void *_set, pool_t pool ATTR_UNUSED, - const char **error_r) +static bool lda_settings_check(void *_set, pool_t pool ATTR_UNUSED, + const char **error_r) { - struct deliver_settings *set = _set; + struct lda_settings *set = _set; if (*set->postmaster_address == '\0') { *error_r = "postmaster_address setting not given"; diff --git a/src/deliver/deliver-settings.h b/src/lib-lda/lda-settings.h similarity index 60% rename from src/deliver/deliver-settings.h rename to src/lib-lda/lda-settings.h index 92a8d50fa3..51dd95961b 100644 --- a/src/deliver/deliver-settings.h +++ b/src/lib-lda/lda-settings.h @@ -1,9 +1,9 @@ -#ifndef DELIVER_SETTINGS_H -#define DELIVER_SETTINGS_H +#ifndef LDA_SETTINGS_H +#define LDA_SETTINGS_H struct mail_user_settings; -struct deliver_settings { +struct lda_settings { const char *postmaster_address; const char *hostname; const char *sendmail_path; @@ -11,10 +11,12 @@ struct deliver_settings { const char *rejection_reason; const char *deliver_log_format; bool quota_full_tempfail; + bool lda_mailbox_autocreate; + bool lda_mailbox_autosubscribe; ARRAY_DEFINE(plugin_envs, const char *); }; -extern struct setting_parser_info deliver_setting_parser_info; +extern struct setting_parser_info lda_setting_parser_info; #endif diff --git a/src/lib-lda/mail-deliver.c b/src/lib-lda/mail-deliver.c new file mode 100644 index 0000000000..89874ee800 --- /dev/null +++ b/src/lib-lda/mail-deliver.c @@ -0,0 +1,244 @@ +/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ioloop.h" +#include "str.h" +#include "str-sanitize.h" +#include "var-expand.h" +#include "message-address.h" +#include "lda-settings.h" +#include "mail-storage.h" +#include "mail-namespace.h" +#include "mail-deliver.h" + +deliver_mail_func_t *deliver_mail = NULL; + +const char *mail_deliver_get_address(struct mail_deliver_context *ctx, + const char *header) +{ + struct message_address *addr; + const char *str; + + if (mail_get_first_header(ctx->src_mail, header, &str) <= 0) + return NULL; + addr = message_address_parse(pool_datastack_create(), + (const unsigned char *)str, + strlen(str), 1, FALSE); + return addr == NULL || addr->mailbox == NULL || addr->domain == NULL || + *addr->mailbox == '\0' || *addr->domain == '\0' ? + NULL : t_strconcat(addr->mailbox, "@", addr->domain, NULL); +} + +static const struct var_expand_table * +get_log_var_expand_table(struct mail_deliver_context *ctx, const char *message) +{ + static struct var_expand_table static_tab[] = { + { '$', NULL, NULL }, + { 'm', NULL, "msgid" }, + { 's', NULL, "subject" }, + { 'f', NULL, "from" }, + { '\0', NULL, NULL } + }; + struct var_expand_table *tab; + unsigned int i; + + tab = t_malloc(sizeof(static_tab)); + memcpy(tab, static_tab, sizeof(static_tab)); + + tab[0].value = message; + (void)mail_get_first_header(ctx->src_mail, "Message-ID", &tab[1].value); + (void)mail_get_first_header(ctx->src_mail, "Subject", &tab[2].value); + tab[3].value = mail_deliver_get_address(ctx, "From"); + for (i = 1; tab[i].key != '\0'; i++) + tab[i].value = str_sanitize(tab[i].value, 80); + return tab; +} + +void mail_deliver_log(struct mail_deliver_context *ctx, const char *fmt, ...) +{ + va_list args; + string_t *str; + const char *msg; + + va_start(args, fmt); + msg = t_strdup_vprintf(fmt, args); + + str = t_str_new(256); + var_expand(str, ctx->set->deliver_log_format, + get_log_var_expand_table(ctx, msg)); + i_info("%s", str_c(str)); + va_end(args); +} + +static struct mailbox * +mailbox_open_or_create_synced(struct mail_deliver_context *ctx, + struct mail_storage **storage_r, + const char *name) +{ + struct mail_namespace *ns; + struct mailbox *box; + enum mail_error error; + enum mailbox_open_flags open_flags = MAILBOX_OPEN_FAST | + MAILBOX_OPEN_KEEP_RECENT | MAILBOX_OPEN_SAVEONLY | + MAILBOX_OPEN_POST_SESSION; + + if (strcasecmp(name, "INBOX") == 0) { + /* deliveries to INBOX must always succeed, + regardless of ACLs */ + open_flags |= MAILBOX_OPEN_IGNORE_ACLS; + } + + ns = mail_namespace_find(ctx->dest_user->namespaces, &name); + if (ns == NULL) { + *storage_r = NULL; + return NULL; + } + *storage_r = ns->storage; + + if (*name == '\0') { + /* delivering to a namespace prefix means we actually want to + deliver to the INBOX instead */ + return NULL; + } + + box = mailbox_open(storage_r, name, NULL, open_flags); + if (box != NULL || !ctx->set->lda_mailbox_autocreate) + return box; + + (void)mail_storage_get_last_error(*storage_r, &error); + if (error != MAIL_ERROR_NOTFOUND) + return NULL; + + /* try creating it. */ + if (mail_storage_mailbox_create(*storage_r, name, FALSE) < 0) + return NULL; + if (ctx->set->lda_mailbox_autosubscribe) { + /* (try to) subscribe to it */ + (void)mailbox_list_set_subscribed(ns->list, name, TRUE); + } + + /* and try opening again */ + box = mailbox_open(storage_r, name, NULL, open_flags); + if (box == NULL) + return NULL; + + if (mailbox_sync(box, 0, 0, NULL) < 0) { + mailbox_close(&box); + return NULL; + } + return box; +} + +int mail_deliver_save(struct mail_deliver_context *ctx, const char *mailbox, + enum mail_flags flags, const char *const *keywords, + struct mail_storage **storage_r) +{ + struct mail_namespace *ns; + struct mailbox *box; + struct mailbox_transaction_context *t; + struct mail_save_context *save_ctx; + struct mail_keywords *kw; + enum mail_error error; + const char *mailbox_name; + bool default_save; + int ret = 0; + + default_save = strcmp(mailbox, ctx->dest_mailbox_name) == 0; + if (default_save) + ctx->tried_default_save = TRUE; + + mailbox_name = str_sanitize(mailbox, 80); + box = mailbox_open_or_create_synced(ctx, storage_r, mailbox); + if (box == NULL) { + if (*storage_r == NULL) { + mail_deliver_log(ctx, + "save failed to %s: Unknown namespace", + mailbox_name); + return -1; + } + ns = mail_storage_get_namespace(*storage_r); + if (default_save && strcmp(ns->prefix, mailbox) == 0) { + /* silently store to the INBOX instead */ + return -1; + } + mail_deliver_log(ctx, "save failed to %s: %s", mailbox_name, + mail_storage_get_last_error(*storage_r, &error)); + return -1; + } + + t = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_EXTERNAL); + + kw = str_array_length(keywords) == 0 ? NULL : + mailbox_keywords_create_valid(box, keywords); + save_ctx = mailbox_save_alloc(t); + mailbox_save_set_flags(save_ctx, flags, kw); + if (mailbox_copy(&save_ctx, ctx->src_mail) < 0) + ret = -1; + mailbox_keywords_free(box, &kw); + + if (ret < 0) + mailbox_transaction_rollback(&t); + else + ret = mailbox_transaction_commit(&t); + + if (ret == 0) { + ctx->saved_mail = TRUE; + mail_deliver_log(ctx, "saved mail to %s", mailbox_name); + } else { + mail_deliver_log(ctx, "save failed to %s: %s", mailbox_name, + mail_storage_get_last_error(*storage_r, &error)); + } + + mailbox_close(&box); + return ret; +} + +const char *mail_deliver_get_return_address(struct mail_deliver_context *ctx) +{ + if (ctx->src_envelope_sender != NULL) + return ctx->src_envelope_sender; + + return mail_deliver_get_address(ctx, "Return-Path"); +} + +const char *mail_deliver_get_new_message_id(struct mail_deliver_context *ctx) +{ + static int count = 0; + + return t_strdup_printf("", + dec2str(ioloop_timeval.tv_sec), + dec2str(ioloop_timeval.tv_usec), + count++, ctx->set->hostname); +} + +int mail_deliver(struct mail_deliver_context *ctx, + struct mail_storage **storage_r) +{ + int ret; + + *storage_r = NULL; + if (deliver_mail == NULL) + ret = -1; + else { + if (deliver_mail(ctx, storage_r) <= 0) { + /* if message was saved, don't bounce it even though + the script failed later. */ + ret = ctx->saved_mail ? 0 : -1; + } else { + /* success. message may or may not have been saved. */ + ret = 0; + } + } + + if (ret < 0 && !ctx->tried_default_save) { + /* plugins didn't handle this. save into the default mailbox. */ + ret = mail_deliver_save(ctx, ctx->dest_mailbox_name, 0, NULL, + storage_r); + } + if (ret < 0 && strcasecmp(ctx->dest_mailbox_name, "INBOX") != 0) { + /* still didn't work. try once more to save it + to INBOX. */ + ret = mail_deliver_save(ctx, "INBOX", 0, NULL, storage_r); + } + return ret; +} diff --git a/src/lib-lda/mail-deliver.h b/src/lib-lda/mail-deliver.h new file mode 100644 index 0000000000..b622108944 --- /dev/null +++ b/src/lib-lda/mail-deliver.h @@ -0,0 +1,48 @@ +#ifndef MAIL_DELIVER_H +#define MAIL_DELIVER_H + +enum mail_flags; +struct mail_storage; + +struct mail_deliver_context { + pool_t pool; + const struct lda_settings *set; + + /* Mail to save */ + struct mail *src_mail; + /* Envelope sender, if known. */ + const char *src_envelope_sender; + + /* Destination user */ + struct mail_user *dest_user; + /* Destination email address */ + const char *dest_addr; + /* Mailbox where mail should be saved, unless e.g. Sieve does + something to it. */ + const char *dest_mailbox_name; + + bool tried_default_save; + bool saved_mail; +}; + +typedef int deliver_mail_func_t(struct mail_deliver_context *ctx, + struct mail_storage **storage_r); + +extern deliver_mail_func_t *deliver_mail; + +void mail_deliver_log(struct mail_deliver_context *ctx, const char *fmt, ...) + ATTR_FORMAT(2, 3); + +const char *mail_deliver_get_address(struct mail_deliver_context *ctx, + const char *header); +const char *mail_deliver_get_return_address(struct mail_deliver_context *ctx); +const char *mail_deliver_get_new_message_id(struct mail_deliver_context *ctx); + +int mail_deliver_save(struct mail_deliver_context *ctx, const char *mailbox, + enum mail_flags flags, const char *const *keywords, + struct mail_storage **storage_r); + +int mail_deliver(struct mail_deliver_context *ctx, + struct mail_storage **storage_r); + +#endif diff --git a/src/deliver/mail-send.c b/src/lib-lda/mail-send.c similarity index 85% rename from src/deliver/mail-send.c rename to src/lib-lda/mail-send.c index fbdf6f98b7..6380771ba8 100644 --- a/src/deliver/mail-send.c +++ b/src/lib-lda/mail-send.c @@ -9,11 +9,12 @@ #include "var-expand.h" #include "message-date.h" #include "message-size.h" -#include "duplicate.h" #include "istream-header-filter.h" +#include "mail-storage.h" #include "mail-storage-settings.h" +#include "lda-settings.h" +#include "mail-deliver.h" #include "smtp-client.h" -#include "deliver.h" #include "mail-send.h" #include @@ -48,9 +49,10 @@ get_var_expand_table(struct mail *mail, const char *reason, return tab; } -int mail_send_rejection(struct mail *mail, const char *recipient, +int mail_send_rejection(struct mail_deliver_context *ctx, const char *recipient, const char *reason) { + struct mail *mail = ctx->src_mail; struct istream *input; struct smtp_client *smtp_client; FILE *f; @@ -64,7 +66,7 @@ int mail_send_rejection(struct mail *mail, const char *recipient, if (mail_get_first_header(mail, "Message-ID", &orig_msgid) < 0) orig_msgid = NULL; - return_addr = deliver_get_return_address(mail); + return_addr = mail_deliver_get_return_address(ctx); if (return_addr == NULL) { i_info("msgid=%s: Return-Path missing, rejection reason: %s", orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80), @@ -77,15 +79,15 @@ int mail_send_rejection(struct mail *mail, const char *recipient, str_sanitize(reason, 512)); } - smtp_client = smtp_client_open(return_addr, NULL, &f); + smtp_client = smtp_client_open(ctx, return_addr, NULL, &f); - msgid = deliver_get_new_message_id(); - boundary = t_strdup_printf("%s/%s", my_pid, deliver_set->hostname); + msgid = mail_deliver_get_new_message_id(ctx); + boundary = t_strdup_printf("%s/%s", my_pid, ctx->set->hostname); fprintf(f, "Message-ID: %s\r\n", msgid); fprintf(f, "Date: %s\r\n", message_date_create(ioloop_time)); fprintf(f, "From: Mail Delivery Subsystem <%s>\r\n", - deliver_set->postmaster_address); + ctx->set->postmaster_address); fprintf(f, "To: <%s>\r\n", return_addr); fprintf(f, "MIME-Version: 1.0\r\n"); fprintf(f, "Content-Type: " @@ -93,7 +95,7 @@ int mail_send_rejection(struct mail *mail, const char *recipient, "\tboundary=\"%s\"\r\n", boundary); str = t_str_new(256); - var_expand(str, deliver_set->rejection_subject, + var_expand(str, ctx->set->rejection_subject, get_var_expand_table(mail, reason, recipient)); fprintf(f, "Subject: %s\r\n", str_c(str)); @@ -108,7 +110,7 @@ int mail_send_rejection(struct mail *mail, const char *recipient, fprintf(f, "Content-Transfer-Encoding: 8bit\r\n\r\n"); str_truncate(str, 0); - var_expand(str, deliver_set->rejection_reason, + var_expand(str, ctx->set->rejection_reason, get_var_expand_table(mail, reason, recipient)); fprintf(f, "%s\r\n", str_c(str)); @@ -117,7 +119,7 @@ int mail_send_rejection(struct mail *mail, const char *recipient, "Content-Type: message/disposition-notification\r\n\r\n", boundary); fprintf(f, "Reporting-UA: %s; Dovecot Mail Delivery Agent\r\n", - deliver_set->hostname); + ctx->set->hostname); if (mail_get_first_header(mail, "Original-Recipient", &hdr) > 0) fprintf(f, "Original-Recipient: rfc822; %s\r\n", hdr); fprintf(f, "Final-Recipient: rfc822; %s\r\n", recipient); @@ -160,7 +162,7 @@ int mail_send_rejection(struct mail *mail, const char *recipient, return smtp_client_close(smtp_client); } -int mail_send_forward(struct mail *mail, const char *forwardto) +int mail_send_forward(struct mail_deliver_context *ctx, const char *forwardto) { static const char *hide_headers[] = { "Return-Path" @@ -173,18 +175,18 @@ int mail_send_forward(struct mail *mail, const char *forwardto) size_t size; int ret; - if (mail_get_stream(mail, NULL, NULL, &input) < 0) + if (mail_get_stream(ctx->src_mail, NULL, NULL, &input) < 0) return -1; - if (mail_get_first_header(mail, "Return-Path", &return_path) <= 0) + if (mail_get_first_header(ctx->src_mail, "Return-Path", &return_path) <= 0) return_path = ""; - if (mailbox_get_settings(mail->box)->mail_debug) { + if (mailbox_get_settings(ctx->src_mail->box)->mail_debug) { i_info("Sending a forward to <%s> with return path <%s>", forwardto, return_path); } - smtp_client = smtp_client_open(forwardto, return_path, &f); + smtp_client = smtp_client_open(ctx, forwardto, return_path, &f); input = i_stream_create_header_filter(input, HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR, hide_headers, @@ -200,4 +202,3 @@ int mail_send_forward(struct mail *mail, const char *forwardto) return smtp_client_close(smtp_client); } - diff --git a/src/lib-lda/mail-send.h b/src/lib-lda/mail-send.h new file mode 100644 index 0000000000..5c7c009830 --- /dev/null +++ b/src/lib-lda/mail-send.h @@ -0,0 +1,11 @@ +#ifndef MAIL_SEND_H +#define MAIL_SEND_H + +struct mail; +struct mail_deliver_context; + +int mail_send_rejection(struct mail_deliver_context *ctx, const char *recipient, + const char *reason); +int mail_send_forward(struct mail_deliver_context *ctx, const char *forwardto); + +#endif diff --git a/src/deliver/smtp-client.c b/src/lib-lda/smtp-client.c similarity index 86% rename from src/deliver/smtp-client.c rename to src/lib-lda/smtp-client.c index fb3ad80ba9..aed7ba1e7b 100644 --- a/src/deliver/smtp-client.c +++ b/src/lib-lda/smtp-client.c @@ -1,12 +1,14 @@ /* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */ #include "lib.h" -#include "deliver.h" #include "master-service.h" +#include "lda-settings.h" +#include "mail-deliver.h" #include "smtp-client.h" #include #include +#include struct smtp_client { FILE *f; @@ -26,14 +28,15 @@ static struct smtp_client *smtp_client_devnull(FILE **file_r) } static void ATTR_NORETURN -smtp_client_run_sendmail(const char *destination, +smtp_client_run_sendmail(struct mail_deliver_context *ctx, + const char *destination, const char *return_path, int fd) { const char *argv[7], *sendmail_path; /* deliver_set's contents may point to environment variables. deliver_env_clean() cleans them up, so they have to be copied. */ - sendmail_path = t_strdup(deliver_set->sendmail_path); + sendmail_path = t_strdup(ctx->set->sendmail_path); argv[0] = sendmail_path; argv[1] = "-i"; /* ignore dots */ @@ -53,7 +56,8 @@ smtp_client_run_sendmail(const char *destination, i_fatal("execv(%s) failed: %m", sendmail_path); } -struct smtp_client *smtp_client_open(const char *destination, +struct smtp_client *smtp_client_open(struct mail_deliver_context *ctx, + const char *destination, const char *return_path, FILE **file_r) { struct smtp_client *client; @@ -73,7 +77,7 @@ struct smtp_client *smtp_client_open(const char *destination, if (pid == 0) { /* child */ (void)close(fd[1]); - smtp_client_run_sendmail(destination, return_path, fd[0]); + smtp_client_run_sendmail(ctx, destination, return_path, fd[0]); } (void)close(fd[0]); diff --git a/src/deliver/smtp-client.h b/src/lib-lda/smtp-client.h similarity index 67% rename from src/deliver/smtp-client.h rename to src/lib-lda/smtp-client.h index 482998d04b..24b14b2f5e 100644 --- a/src/deliver/smtp-client.h +++ b/src/lib-lda/smtp-client.h @@ -3,7 +3,8 @@ #include -struct smtp_client *smtp_client_open(const char *destination, +struct smtp_client *smtp_client_open(struct mail_deliver_context *ctx, + const char *destination, const char *return_path, FILE **file_r); /* Returns sysexits-compatible return value */ int smtp_client_close(struct smtp_client *client);