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
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
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
imap \
pop3-login \
pop3 \
- deliver \
+ lda \
config \
tests \
util \
+++ /dev/null
-#ifndef DELIVER_H
-#define DELIVER_H
-
-#include <sysexits.h>
-
-#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
+++ /dev/null
-#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
pkglibexecdir = $(libexecdir)/dovecot
-pkglibexec_PROGRAMS = deliver
+pkglibexec_PROGRAMS = dovecot-lda
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-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
#include "lib.h"
#include "lib-signals.h"
-#include "ioloop.h"
#include "env-util.h"
#include "fd-set-nonblock.h"
#include "istream.h"
#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"
#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 <stdio.h>
#include <stdlib.h>
#include <pwd.h>
+#include <sysexits.h>
+
+#ifndef EX_CONFIG
+# define EX_CONFIG 78 /* for HP-UX */
+#endif
#define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON"
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("<dovecot-%s-%s-%d@%s>",
- 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;
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;
}
}
- 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);
{
printf(
"Usage: deliver [-c <config file>] [-a <address>] [-d <username>] [-p <path>]\n"
-" [-f <envelope sender>] [-m <mailbox>] [-n] [-s] [-e] [-k]\n");
+" [-f <envelope sender>] [-m <mailbox>] [-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;
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;
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:",
switch (c) {
case 'a':
/* destination address */
- destaddr = optarg;
+ ctx.dest_addr = optarg;
break;
case 'd':
/* destination user */
/* 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)) {
}
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)
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);
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");
}
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. */
}
/* 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);
--- /dev/null
+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
#include "home-expand.h"
#include "file-dotlock.h"
#include "hash.h"
+#include "mail-storage-settings.h"
#include "duplicate.h"
#include <stdlib.h>
#ifndef DUPLICATE_H
#define DUPLICATE_H
-#include "mail-storage-settings.h"
+struct mail_storage_settings;
#define DUPLICATE_DEFAULT_KEEP (3600 * 24)
/* 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 <stddef.h>
-#include <stdlib.h>
-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),
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",
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";
-#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;
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
--- /dev/null
+/* 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("<dovecot-%s-%s-%d@%s>",
+ 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;
+}
--- /dev/null
+#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
#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 <stdlib.h>
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;
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),
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: "
"\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));
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));
"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);
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"
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,
return smtp_client_close(smtp_client);
}
-
--- /dev/null
+#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
/* 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 <unistd.h>
#include <sys/wait.h>
+#include <sysexits.h>
struct smtp_client {
FILE *f;
}
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 */
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;
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]);
#include <stdio.h>
-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);