]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Initial commit for config rewrite.
authorTimo Sirainen <tss@iki.fi>
Tue, 27 Jan 2009 23:21:53 +0000 (18:21 -0500)
committerTimo Sirainen <tss@iki.fi>
Tue, 27 Jan 2009 23:21:53 +0000 (18:21 -0500)
--HG--
branch : HEAD

162 files changed:
.hgignore
TODO
configure.in
src/Makefile.am
src/auth/Makefile.am
src/auth/auth-client-connection.c
src/auth/auth-master-connection.c
src/auth/auth-request-handler.c
src/auth/auth-request.c
src/auth/auth-settings.c [new file with mode: 0644]
src/auth/auth-settings.h [new file with mode: 0644]
src/auth/auth-worker-server.c
src/auth/auth-worker-server.h
src/auth/auth.c
src/auth/auth.h
src/auth/db-ldap.c
src/auth/main.c
src/auth/mech-anonymous.c
src/auth/mech-digest-md5.c
src/auth/mech-gssapi.c
src/auth/mech-rpa.c
src/auth/mech-winbind.c
src/auth/mech.c
src/auth/mech.h
src/auth/passdb-cache.c
src/auth/passdb-cache.h
src/auth/passdb-passwd-file.c
src/auth/passdb.c
src/auth/passdb.h
src/auth/userdb-passwd-file.c
src/auth/userdb-prefetch.c
src/auth/userdb.c
src/auth/userdb.h
src/config/Makefile.am [new file with mode: 0644]
src/config/common.h [new file with mode: 0644]
src/config/config-connection.c [new file with mode: 0644]
src/config/config-connection.h [new file with mode: 0644]
src/config/config-parser.c [new file with mode: 0644]
src/config/config-parser.h [new file with mode: 0644]
src/config/main.c [new file with mode: 0644]
src/config/settings-get.pl [new file with mode: 0755]
src/deliver/Makefile.am
src/deliver/deliver-settings.c [new file with mode: 0644]
src/deliver/deliver-settings.h [new file with mode: 0644]
src/deliver/deliver.c
src/deliver/deliver.h
src/imap-login/Makefile.am
src/imap-login/client-authenticate.c
src/imap-login/client.c
src/imap-login/imap-proxy.c
src/imap/Makefile.am
src/imap/client.c
src/imap/client.h
src/imap/cmd-append.c
src/imap/cmd-capability.c
src/imap/cmd-delete.c
src/imap/cmd-id.c
src/imap/cmd-idle.c
src/imap/cmd-subscribe.c
src/imap/common.h
src/imap/imap-fetch-body.c
src/imap/imap-settings.c [new file with mode: 0644]
src/imap/imap-settings.h [new file with mode: 0644]
src/imap/imap-sync.c
src/imap/main.c
src/lib-settings/Makefile.am
src/lib-settings/settings-parser.c [new file with mode: 0644]
src/lib-settings/settings-parser.h [new file with mode: 0644]
src/lib-storage/Makefile.am
src/lib-storage/index/cydir/cydir-storage.c
src/lib-storage/index/dbox/Makefile.am
src/lib-storage/index/dbox/dbox-file.c
src/lib-storage/index/dbox/dbox-settings.c [new file with mode: 0644]
src/lib-storage/index/dbox/dbox-settings.h [new file with mode: 0644]
src/lib-storage/index/dbox/dbox-storage.c
src/lib-storage/index/dbox/dbox-storage.h
src/lib-storage/index/index-mail.c
src/lib-storage/index/index-storage.c
src/lib-storage/index/index-storage.h
src/lib-storage/index/maildir/Makefile.am
src/lib-storage/index/maildir/maildir-copy.c
src/lib-storage/index/maildir/maildir-keywords.c
src/lib-storage/index/maildir/maildir-save.c
src/lib-storage/index/maildir/maildir-settings.c [new file with mode: 0644]
src/lib-storage/index/maildir/maildir-settings.h [new file with mode: 0644]
src/lib-storage/index/maildir/maildir-storage.c
src/lib-storage/index/maildir/maildir-storage.h
src/lib-storage/index/maildir/maildir-uidlist.c
src/lib-storage/index/mbox/Makefile.am
src/lib-storage/index/mbox/mbox-lock.c
src/lib-storage/index/mbox/mbox-mail.c
src/lib-storage/index/mbox/mbox-save.c
src/lib-storage/index/mbox/mbox-settings.c [new file with mode: 0644]
src/lib-storage/index/mbox/mbox-settings.h [new file with mode: 0644]
src/lib-storage/index/mbox/mbox-storage.c
src/lib-storage/index/mbox/mbox-storage.h
src/lib-storage/index/mbox/mbox-sync.c
src/lib-storage/index/raw/raw-storage.c
src/lib-storage/index/shared/shared-storage.c
src/lib-storage/list/index-mailbox-list.c
src/lib-storage/list/mailbox-list-fs-iter.c
src/lib-storage/list/mailbox-list-fs.c
src/lib-storage/list/mailbox-list-maildir.c
src/lib-storage/list/subscription-file.c
src/lib-storage/mail-namespace.c
src/lib-storage/mail-namespace.h
src/lib-storage/mail-storage-private.h
src/lib-storage/mail-storage-settings.c [new file with mode: 0644]
src/lib-storage/mail-storage-settings.h [new file with mode: 0644]
src/lib-storage/mail-storage.c
src/lib-storage/mail-storage.h
src/lib-storage/mail-user.c
src/lib-storage/mail-user.h
src/lib-storage/mailbox-list-private.h
src/lib-storage/mailbox-list.c
src/lib-storage/mailbox-list.h
src/lib/array-decl.h
src/login-common/Makefile.am
src/login-common/client-common.c
src/login-common/common.h
src/login-common/login-settings.c [new file with mode: 0644]
src/login-common/login-settings.h [new file with mode: 0644]
src/login-common/main.c
src/login-common/master.c
src/login-common/sasl-server.c
src/login-common/ssl-proxy-openssl.c
src/master/Makefile.am
src/master/auth-process.c
src/master/child-process.c
src/master/child-process.h
src/master/dict-process.c
src/master/listener.c
src/master/listener.h
src/master/login-process.c
src/master/login-process.h
src/master/mail-process.c
src/master/mail-process.h
src/master/main.c
src/master/master-settings-defs.c [deleted file]
src/master/master-settings.c
src/master/master-settings.h
src/master/ssl-init.c
src/plugins/acl/acl-mailbox-list.c
src/plugins/fts-lucene/fts-backend-lucene.c
src/plugins/fts-squat/fts-backend-squat.c
src/plugins/fts/fts-storage.c
src/plugins/imap-acl/imap-acl-plugin.c
src/plugins/imap-quota/imap-quota-plugin.c
src/plugins/mbox-snarf/mbox-snarf-plugin.c
src/plugins/virtual/virtual-storage.c
src/pop3-login/Makefile.am
src/pop3-login/client-authenticate.c
src/pop3-login/client.c
src/pop3-login/pop3-proxy.c
src/pop3/Makefile.am
src/pop3/client.c
src/pop3/client.h
src/pop3/commands.c
src/pop3/common.h
src/pop3/main.c
src/pop3/pop3-settings.c [new file with mode: 0644]
src/pop3/pop3-settings.h [new file with mode: 0644]

index e9299c2ec75f0af2cdffc2778071d897f6d1bef8..4bacebcc6b902d299d5d3a7790d6f1c1d3c9e300 100644 (file)
--- a/.hgignore
+++ b/.hgignore
@@ -51,6 +51,9 @@ doc/wiki/*.txt
 doc/wiki/Makefile.am
 src/auth/checkpassword-reply
 src/auth/dovecot-auth
+src/config/all-settings.c
+src/config/all-settings.h
+src/config/doveconf
 src/deliver/deliver
 src/dict/dict
 src/imap-login/imap-login
diff --git a/TODO b/TODO
index f8bcc266a505b38284b7cb93019f2cbdce39d382..b2df19e2d23c3c3b79057fc50d62213133df226f 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,3 +1,14 @@
+ - config rewrite
+   - deliver: plugin var expanding
+   - master: expands only known vars, not all_settings.. should it expand
+     anything after all? use the 1/0 prefix to mark which vars have been
+     expanded (config vs userdb)?
+   - go through mail-process.c. nfs test?
+   - support !include and !include_try
+   - check plugins to make sure they're using only internal getenv()s,
+     especially fix DEBUG env checks
+   - add back all setting verification code from master
+   - put plugin settings to some plugins array, not envs, var expand
  - proxying: support fallbacking to local (or other?) server if the first
    one is down
 user_attrs {
index e1ea98a140a447c534c660927584fbc55a64689b..9c1b148f5dea323c3b533806daeed5f21fb6d44b 100644 (file)
@@ -2335,6 +2335,14 @@ if test "$want_solr" != "no"; then
 fi
 AM_CONDITIONAL(BUILD_SOLR, test "$have_solr" = "yes")
 
+dnl **
+dnl ** Settings
+dnl **
+
+dnl get a list of setting .[ch] files, but list .h files first
+SETTING_FILES=`find $srcdir/src -name '*settings.[[ch]]' ! -name all-settings.[[ch]] | sed -e s,$srcdir/src,./src,g -e 's,./src,$(top_srcdir)/src,g' -e 's/^\(.*\)\(.\)$/\2 \1\2/' | sort -r | sed s/^..//|tr '\n' ' '`
+AC_SUBST(SETTING_FILES)
+
 dnl **
 dnl ** capabilities
 dnl **
@@ -2380,6 +2388,7 @@ src/lib-storage/index/raw/Makefile
 src/lib-storage/index/shared/Makefile
 src/lib-storage/register/Makefile
 src/auth/Makefile
+src/config/Makefile
 src/deliver/Makefile
 src/dict/Makefile
 src/imap/Makefile
index 778b1bea553d955fc5abc57a07891a21ea90e5bd..18151f4b99f185f72570e249c59564f17e580b25 100644 (file)
@@ -20,6 +20,7 @@ SUBDIRS = \
        lib-storage \
        lib-auth \
        auth \
+       config \
        dict \
        master \
        login-common \
index e9e626f17807e31d837f8456869619f19e10cf25..8c48539d6545b3f549f083a1aa0ec559d24f0431 100644 (file)
@@ -25,6 +25,7 @@ AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib-otp \
        -DAUTH_MODULE_DIR=\""$(auth_moduledir)"\" \
        -DPKG_LIBEXECDIR=\""$(pkglibexecdir)"\" \
+       -DPKG_RUNDIR=\""$(rundir)"\" \
        $(AUTH_CFLAGS)
 
 dovecot_auth_LDFLAGS = -export-dynamic
@@ -64,6 +65,7 @@ dovecot_auth_SOURCES = \
        auth-master-listener.c \
        auth-request.c \
        auth-request-handler.c \
+       auth-settings.c \
        auth-stream.c \
        auth-worker-client.c \
        auth-worker-server.c \
@@ -120,6 +122,7 @@ headers = \
        auth-master-listener.h \
        auth-request.h \
        auth-request-handler.h \
+       auth-settings.h \
        auth-stream.h \
        auth-worker-client.h \
        auth-worker-server.h \
index f6f53b9a02f0ce103806ee6073354bf4fb9005d2..6adc6f3b4f0fa3e5a740f4194927de3767b755a8 100644 (file)
@@ -58,8 +58,8 @@ static void auth_client_send(struct auth_client_connection *conn,
                        io_remove(&conn->io);
        }
 
-       if (conn->auth->verbose_debug) {
-               i_info("client out: %s", conn->auth->verbose_debug_passwords ?
+       if (conn->auth->set->debug) {
+               i_info("client out: %s", conn->auth->set->debug_passwords ?
                       cmd : reply_line_hide_pass(cmd));
        }
 }
@@ -117,7 +117,7 @@ auth_client_input_cpid(struct auth_client_connection *conn, const char *args)
        auth_request_handler_set(conn->request_handler, conn->connect_uid, pid);
 
        conn->pid = pid;
-       if (conn->auth->verbose_debug)
+       if (conn->auth->set->debug)
                i_info("new auth connection: pid=%u", conn->pid);
        return TRUE;
 }
@@ -166,18 +166,18 @@ static bool
 auth_client_handle_line(struct auth_client_connection *conn, const char *line)
 {
        if (strncmp(line, "AUTH\t", 5) == 0) {
-               if (conn->auth->verbose_debug) {
+               if (conn->auth->set->debug) {
                        i_info("client in: %s",
-                              conn->auth->verbose_debug_passwords ? line :
+                              conn->auth->set->debug_passwords ? line :
                               auth_line_hide_pass(line));
                }
                return auth_request_handler_auth_begin(conn->request_handler,
                                                       line + 5);
        }
        if (strncmp(line, "CONT\t", 5) == 0) {
-               if (conn->auth->verbose_debug) {
+               if (conn->auth->set->debug) {
                        i_info("client in: %s",
-                              conn->auth->verbose_debug_passwords ? line :
+                              conn->auth->set->debug_passwords ? line :
                               cont_line_hide_pass(line));
                }
                return auth_request_handler_auth_continue(conn->request_handler,
index 0cee5fb746fa5836bf55dabc1a20e9489e093a12..e794fee932a208f4b5815ca2a21a2d2545ae5f5f 100644 (file)
@@ -38,7 +38,7 @@ void auth_master_request_callback(struct auth_stream_reply *reply,
 
        reply_str = auth_stream_reply_export(reply);
 
-       if (conn->listener->auth->verbose_debug)
+       if (conn->listener->auth->set->debug)
                i_info("master out: %s", reply_str);
 
        iov[0].iov_base = reply_str;
@@ -105,7 +105,7 @@ user_callback(enum userdb_result result,
                break;
        }
 
-       if (conn->listener->auth->verbose_debug)
+       if (conn->listener->auth->set->debug)
                i_info("master out: %s", str_c(str));
 
        str_append_c(str, '\n');
@@ -163,7 +163,7 @@ master_input_user(struct auth_master_connection *conn, const char *args)
 static bool
 auth_master_input_line(struct auth_master_connection *conn, const char *line)
 {
-       if (conn->listener->auth->verbose_debug)
+       if (conn->listener->auth->set->debug)
                i_info("master in: %s", line);
 
        if (strncmp(line, "REQUEST\t", 8) == 0)
index 37d7724d5b37bb88079f56973e3a8f9259061013..43e19a54b39a3f23d5b4a7cc1d188701dcf4b0be 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <stdlib.h>
 
-#define DEFAULT_AUTH_FAILURE_DELAY 2
 #define AUTH_FAILURE_DELAY_CHECK_MSECS 500
 
 struct auth_request_handler {
@@ -34,7 +33,6 @@ struct auth_request_handler {
 static ARRAY_DEFINE(auth_failures_arr, struct auth_request *);
 static struct aqueue *auth_failures;
 static struct timeout *to_auth_failures;
-static unsigned int auth_failure_delay;
 
 static void auth_failure_timeout(void *context);
 
@@ -356,7 +354,7 @@ bool auth_request_handler_auth_begin(struct auth_request_handler *handler,
 
        hash_table_insert(handler->requests, POINTER_CAST(id), request);
 
-       if (request->auth->ssl_require_client_cert &&
+       if (request->auth->set->ssl_require_client_cert &&
            !request->valid_client_cert) {
                /* we fail without valid certificate */
                 auth_request_handler_auth_fail(handler, request,
@@ -546,8 +544,10 @@ void auth_request_handler_flush_failures(bool flush_all)
        for (i = 0; i < count; i++) {
                auth_request = auth_requests[aqueue_idx(auth_failures, 0)];
 
+               /* FIXME: assumess that failure_delay is always the same. */
                diff = ioloop_time - auth_request->last_access;
-               if (diff < (time_t)auth_failure_delay && !flush_all)
+               if (diff < (time_t)auth_request->auth->set->failure_delay &&
+                   !flush_all)
                        break;
 
                aqueue_delete_tail(auth_failures);
@@ -566,12 +566,6 @@ static void auth_failure_timeout(void *context ATTR_UNUSED)
 
 void auth_request_handler_init(void)
 {
-       const char *env;
-
-       env = getenv("FAILURE_DELAY");
-       auth_failure_delay = env != NULL ? atoi(env) :
-               DEFAULT_AUTH_FAILURE_DELAY;
-
        i_array_init(&auth_failures_arr, 128);
        auth_failures = aqueue_init(&auth_failures_arr.arr);
 }
index 758e6233ccb6cb64c92200ce2c167299ba7621e5..4fe5ec61e1d545535c0f5717700b714e4a1fad3b 100644 (file)
@@ -165,7 +165,7 @@ bool auth_request_import(struct auth_request *request,
        else if (strcmp(key, "original_username") == 0)
                request->original_username = p_strdup(request->pool, value);
        else if (strcmp(key, "cert_username") == 0) {
-               if (request->auth->ssl_username_from_cert) {
+               if (request->auth->set->ssl_username_from_cert) {
                        /* get username from SSL certificate. it overrides
                           the username given by the auth mechanism. */
                        request->user = p_strdup(request->pool, value);
@@ -521,7 +521,7 @@ auth_request_lookup_credentials_finish(enum passdb_result result,
                        request->credentials_scheme,
                        request->private_callback.lookup_credentials);
        } else {
-               if (request->auth->verbose_debug_passwords &&
+               if (request->auth->set->debug_passwords &&
                    result == PASSDB_RESULT_OK) {
                        auth_request_log_debug(request, "password",
                                "Credentials: %s",
@@ -772,10 +772,10 @@ auth_request_fix_username(struct auth_request *request, const char *username,
        unsigned char *p;
         char *user;
 
-       if (strchr(username, '@') == NULL &&
-           request->auth->default_realm != NULL) {
+       if (*request->auth->set->default_realm != '\0' &&
+           strchr(username, '@') == NULL) {
                user = p_strconcat(request->pool, username, "@",
-                                   request->auth->default_realm, NULL);
+                                   request->auth->set->default_realm, NULL);
        } else {
                user = p_strdup(request->pool, username);
        }
@@ -791,7 +791,7 @@ auth_request_fix_username(struct auth_request *request, const char *username,
                }
        }
 
-       if (request->auth->username_format != NULL) {
+       if (*request->auth->set->username_format != '\0') {
                /* username format given, put it through variable expansion.
                   we'll have to temporarily replace request->user to get
                   %u to be the wanted username */
@@ -804,7 +804,7 @@ auth_request_fix_username(struct auth_request *request, const char *username,
 
                dest = t_str_new(256);
                table = auth_request_get_var_expand_table(request, NULL);
-               var_expand(dest, request->auth->username_format, table);
+               var_expand(dest, request->auth->set->username_format, table);
                user = p_strdup(request->pool, str_c(dest));
 
                request->user = old_username;
@@ -816,12 +816,12 @@ auth_request_fix_username(struct auth_request *request, const char *username,
 bool auth_request_set_username(struct auth_request *request,
                               const char *username, const char **error_r)
 {
+       const struct auth_settings *set = request->auth->set;
        const char *p, *login_username = NULL;
 
-       if (request->auth->master_user_separator != '\0' &&
-           !request->userdb_lookup) {
+       if (*set->master_user_separator != '\0' && !request->userdb_lookup) {
                /* check if the username contains a master user */
-               p = strchr(username, request->auth->master_user_separator);
+               p = strchr(username, *set->master_user_separator);
                if (p != NULL) {
                        /* it does, set it. */
                        login_username = t_strdup_until(username, p);
@@ -1312,7 +1312,7 @@ int auth_request_password_verify(struct auth_request *request,
        if (ret == 0) {
                auth_request_log_info(request, subsystem,
                                      "Password mismatch");
-               if (request->auth->verbose_debug_passwords) {
+               if (request->auth->set->debug_passwords) {
                        auth_request_log_debug(request, subsystem,
                                               "%s(%s) != '%s'", scheme,
                                               plain_password,
@@ -1436,7 +1436,7 @@ void auth_request_log_debug(struct auth_request *auth_request,
 {
        va_list va;
 
-       if (!auth_request->auth->verbose_debug)
+       if (!auth_request->auth->set->debug)
                return;
 
        va_start(va, format);
@@ -1452,7 +1452,7 @@ void auth_request_log_info(struct auth_request *auth_request,
 {
        va_list va;
 
-       if (!auth_request->auth->verbose)
+       if (!auth_request->auth->set->verbose)
                return;
 
        va_start(va, format);
diff --git a/src/auth/auth-settings.c b/src/auth/auth-settings.c
new file mode 100644 (file)
index 0000000..9c0e568
--- /dev/null
@@ -0,0 +1,347 @@
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "hostpid.h"
+#include "settings-parser.h"
+#include "auth-settings.h"
+
+#include <stddef.h>
+
+extern struct setting_parser_info auth_socket_setting_parser_info;
+extern struct setting_parser_info auth_setting_parser_info;
+extern struct setting_parser_info auth_root_setting_parser_info;
+
+#undef DEF
+#define DEF(type, name) \
+       { type, #name, offsetof(struct auth_socket_unix_settings, name), NULL }
+
+static struct setting_define auth_socket_client_setting_defines[] = {
+       DEF(SET_STR, path),
+       DEF(SET_UINT, mode),
+       DEF(SET_STR, user),
+       DEF(SET_STR, group),
+
+       SETTING_DEFINE_LIST_END
+};
+
+static struct auth_socket_unix_settings auth_socket_client_default_settings = {
+       MEMBER(path) "auth-client",
+       MEMBER(mode) 0660,
+       MEMBER(user) "",
+       MEMBER(group) ""
+};
+
+struct setting_parser_info auth_socket_client_setting_parser_info = {
+       MEMBER(defines) auth_socket_client_setting_defines,
+       MEMBER(defaults) &auth_socket_client_default_settings,
+
+       MEMBER(parent) &auth_socket_setting_parser_info,
+       MEMBER(dynamic_parsers) NULL,
+
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) (size_t)-1,
+       MEMBER(struct_size) sizeof(struct auth_socket_unix_settings)
+};
+
+#undef DEF
+#define DEF(type, name) \
+       { type, #name, offsetof(struct auth_socket_unix_settings, name), NULL }
+
+static struct setting_define auth_socket_master_setting_defines[] = {
+       DEF(SET_STR, path),
+       DEF(SET_UINT, mode),
+       DEF(SET_STR, user),
+       DEF(SET_STR, group),
+
+       SETTING_DEFINE_LIST_END
+};
+
+static struct auth_socket_unix_settings auth_socket_master_default_settings = {
+       MEMBER(path) "auth-master",
+       MEMBER(mode) 0660,
+       MEMBER(user) "",
+       MEMBER(group) ""
+};
+
+struct setting_parser_info auth_socket_master_setting_parser_info = {
+       MEMBER(defines) auth_socket_master_setting_defines,
+       MEMBER(defaults) &auth_socket_master_default_settings,
+
+       MEMBER(parent) &auth_socket_setting_parser_info,
+       MEMBER(dynamic_parsers) NULL,
+
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) (size_t)-1,
+       MEMBER(struct_size) sizeof(struct auth_socket_unix_settings)
+};
+
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+       { type, #name, offsetof(struct auth_socket_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+       { SET_DEFLIST, name, offsetof(struct auth_socket_settings, field), defines }
+
+static struct setting_define auth_socket_setting_defines[] = {
+       DEF(SET_STR, type),
+
+       DEFLIST(clients, "client", &auth_socket_client_setting_parser_info),
+       DEFLIST(masters, "master", &auth_socket_master_setting_parser_info),
+
+       SETTING_DEFINE_LIST_END
+};
+
+static struct auth_socket_settings auth_socket_default_settings = {
+       MEMBER(type) "listen"
+};
+
+struct setting_parser_info auth_socket_setting_parser_info = {
+       MEMBER(defines) auth_socket_setting_defines,
+       MEMBER(defaults) &auth_socket_default_settings,
+
+       MEMBER(parent) &auth_setting_parser_info,
+       MEMBER(dynamic_parsers) NULL,
+
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) offsetof(struct auth_socket_settings, type),
+       MEMBER(struct_size) sizeof(struct auth_socket_settings)
+};
+
+#undef DEF
+#define DEF(type, name) \
+       { type, #name, offsetof(struct auth_passdb_settings, name), NULL }
+
+static struct setting_define auth_passdb_setting_defines[] = {
+       DEF(SET_STR, driver),
+       DEF(SET_STR, args),
+       DEF(SET_BOOL, deny),
+
+       SETTING_DEFINE_LIST_END
+};
+
+struct setting_parser_info auth_passdb_setting_parser_info = {
+       MEMBER(defines) auth_passdb_setting_defines,
+       MEMBER(defaults) NULL,
+
+       MEMBER(parent) &auth_setting_parser_info,
+       MEMBER(dynamic_parsers) NULL,
+
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) offsetof(struct auth_passdb_settings, driver),
+       MEMBER(struct_size) sizeof(struct auth_passdb_settings)
+};
+
+#undef DEF
+#define DEF(type, name) \
+       { type, #name, offsetof(struct auth_userdb_settings, name), NULL }
+
+static struct setting_define auth_userdb_setting_defines[] = {
+       DEF(SET_STR, driver),
+       DEF(SET_STR, args),
+
+       SETTING_DEFINE_LIST_END
+};
+
+struct setting_parser_info auth_userdb_setting_parser_info = {
+       MEMBER(defines) auth_userdb_setting_defines,
+       MEMBER(defaults) NULL,
+
+       MEMBER(parent) &auth_setting_parser_info,
+       MEMBER(dynamic_parsers) NULL,
+
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) offsetof(struct auth_userdb_settings, driver),
+       MEMBER(struct_size) sizeof(struct auth_userdb_settings)
+};
+
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+       { type, #name, offsetof(struct auth_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+       { SET_DEFLIST, name, offsetof(struct auth_settings, field), defines }
+
+static struct setting_define auth_setting_defines[] = {
+       DEF(SET_STR, name),
+       DEF(SET_STR, mechanisms),
+       DEF(SET_STR, realms),
+       DEF(SET_STR, default_realm),
+       DEF(SET_UINT, cache_size),
+       DEF(SET_UINT, cache_ttl),
+       DEF(SET_UINT, cache_negative_ttl),
+       DEF(SET_STR, username_chars),
+       DEF(SET_STR, username_translation),
+       DEF(SET_STR, username_format),
+       DEF(SET_STR, master_user_separator),
+       DEF(SET_STR, anonymous_username),
+       DEF(SET_STR, krb5_keytab),
+       DEF(SET_STR, gssapi_hostname),
+       DEF(SET_STR, winbind_helper_path),
+       DEF(SET_UINT, failure_delay),
+
+       DEF(SET_BOOL, verbose),
+       DEF(SET_BOOL, debug),
+       DEF(SET_BOOL, debug_passwords),
+       DEF(SET_BOOL, ssl_require_client_cert),
+       DEF(SET_BOOL, ssl_username_from_cert),
+       DEF(SET_BOOL, use_winbind),
+
+       DEF(SET_UINT, worker_max_count),
+
+       DEFLIST(sockets, "socket", &auth_socket_setting_parser_info),
+       DEFLIST(passdbs, "passdb", &auth_passdb_setting_parser_info),
+       DEFLIST(userdbs, "userdb", &auth_userdb_setting_parser_info),
+
+       SETTING_DEFINE_LIST_END
+};
+
+static struct auth_settings auth_default_settings = {
+       MEMBER(name) NULL,
+       MEMBER(root) NULL,
+
+       MEMBER(mechanisms) "plain",
+       MEMBER(realms) "",
+       MEMBER(default_realm) "",
+       MEMBER(cache_size) 0,
+       MEMBER(cache_ttl) 3600,
+       MEMBER(cache_negative_ttl) 0,
+       MEMBER(username_chars) "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@",
+       MEMBER(username_translation) "",
+       MEMBER(username_format) "",
+       MEMBER(master_user_separator) "",
+       MEMBER(anonymous_username) "anonymous",
+       MEMBER(krb5_keytab) "",
+       MEMBER(gssapi_hostname) "",
+       MEMBER(winbind_helper_path) "/usr/bin/ntlm_auth",
+       MEMBER(failure_delay) 2,
+
+       MEMBER(verbose) FALSE,
+       MEMBER(debug) FALSE,
+       MEMBER(debug_passwords) FALSE,
+       MEMBER(ssl_require_client_cert) FALSE,
+       MEMBER(ssl_username_from_cert) FALSE,
+       MEMBER(use_winbind) FALSE,
+
+       MEMBER(worker_max_count) 30,
+
+       MEMBER(sockets) ARRAY_INIT,
+       MEMBER(passdbs) ARRAY_INIT,
+       MEMBER(userdbs) ARRAY_INIT
+};
+
+struct setting_parser_info auth_setting_parser_info = {
+       MEMBER(defines) auth_setting_defines,
+       MEMBER(defaults) &auth_default_settings,
+
+       MEMBER(parent) &auth_root_setting_parser_info,
+       MEMBER(dynamic_parsers) NULL,
+
+       MEMBER(parent_offset) offsetof(struct auth_settings, root),
+       MEMBER(type_offset) offsetof(struct auth_settings, name),
+       MEMBER(struct_size) sizeof(struct auth_settings)
+};
+
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+       { type, #name, offsetof(struct auth_root_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+       { SET_DEFLIST, name, offsetof(struct auth_root_settings, field), defines }
+
+static struct setting_define auth_root_setting_defines[] = {
+       DEF(SET_STR, base_dir),
+       DEFLIST(auths, "auth", &auth_setting_parser_info),
+
+       SETTING_DEFINE_LIST_END
+};
+
+static struct auth_root_settings auth_root_default_settings = {
+       MEMBER(base_dir) PKG_RUNDIR,
+       MEMBER(auths) ARRAY_INIT
+};
+
+struct setting_parser_info auth_root_setting_parser_info = {
+       MEMBER(defines) auth_root_setting_defines,
+       MEMBER(defaults) &auth_root_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 auth_root_settings)
+};
+
+static pool_t settings_pool = NULL;
+
+static void fix_base_path(struct auth_settings *set, const char **str)
+{
+       if (*str != NULL && **str != '\0' && **str != '/') {
+               *str = p_strconcat(settings_pool,
+                                  set->root->base_dir, "/", *str, NULL);
+       }
+}
+
+static void auth_settings_check(struct auth_settings *set)
+{
+       struct auth_socket_unix_settings *const *u;
+       struct auth_socket_settings *const *sockets;
+       unsigned int i, j, count, count2;
+
+       if (!array_is_created(&set->sockets))
+               return;
+
+       sockets = array_get(&set->sockets, &count);
+       for (i = 0; i < count; i++) {
+               if (array_is_created(&sockets[i]->masters)) {
+                       u = array_get(&sockets[i]->masters, &count2);
+                       for (j = 0; j < count2; j++)
+                               fix_base_path(set, &u[j]->path);
+               }
+               if (array_is_created(&sockets[i]->clients)) {
+                       u = array_get(&sockets[i]->clients, &count2);
+                       for (j = 0; j < count2; j++)
+                               fix_base_path(set, &u[j]->path);
+               }
+       }
+}
+
+struct auth_settings *auth_settings_read(const char *name)
+{
+       struct setting_parser_context *parser;
+       struct auth_root_settings *set;
+       struct auth_settings *const *auths;
+       unsigned int i, count;
+
+       if (settings_pool == NULL)
+               settings_pool = pool_alloconly_create("auth settings", 1024);
+       else
+               p_clear(settings_pool);
+
+       parser = settings_parser_init(settings_pool,
+                                     &auth_root_setting_parser_info,
+                                     SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
+
+       auth_default_settings.gssapi_hostname = my_hostname;
+
+       if (settings_parse_environ(parser) < 0) {
+               i_fatal("Error reading configuration: %s",
+                       settings_parser_get_error(parser));
+       }
+
+       set = settings_parser_get(parser);
+       settings_parser_deinit(&parser);
+
+       if (array_is_created(&set->auths)) {
+               auths = array_get(&set->auths, &count);
+               for (i = 0; i < count; i++) {
+                       if (strcmp(auths[i]->name, name) == 0) {
+                               auth_settings_check(auths[i]);
+                               return auths[i];
+                       }
+               }
+       }
+       i_fatal("Error reading configuration: No auth section: %s", name);
+       return NULL;
+}
diff --git a/src/auth/auth-settings.h b/src/auth/auth-settings.h
new file mode 100644 (file)
index 0000000..bf9c166
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef AUTH_SETTINGS_H
+#define AUTH_SETTINGS_H
+
+struct auth_socket_unix_settings {
+       const char *path;
+       unsigned int mode;
+       const char *user;
+       const char *group;
+};
+
+struct auth_socket_settings {
+       const char *type;
+
+       ARRAY_DEFINE(clients, struct auth_socket_unix_settings *);
+       ARRAY_DEFINE(masters, struct auth_socket_unix_settings *);
+};
+
+struct auth_passdb_settings {
+       const char *driver;
+       const char *args;
+       bool deny;
+       bool pass;
+       bool master;
+};
+
+struct auth_userdb_settings {
+       const char *driver;
+       const char *args;
+};
+
+struct auth_settings {
+       const char *name;
+       struct auth_root_settings *root;
+
+       const char *mechanisms;
+       const char *realms;
+       const char *default_realm;
+       unsigned int cache_size;
+       unsigned int cache_ttl;
+       unsigned int cache_negative_ttl;
+       const char *username_chars;
+       const char *username_translation;
+       const char *username_format;
+       const char *master_user_separator;
+       const char *anonymous_username;
+       const char *krb5_keytab;
+       const char *gssapi_hostname;
+       const char *winbind_helper_path;
+       unsigned int failure_delay;
+
+       bool verbose, debug, debug_passwords;
+       bool ssl_require_client_cert;
+       bool ssl_username_from_cert;
+       bool use_winbind;
+
+       unsigned int worker_max_count;
+
+       ARRAY_DEFINE(sockets, struct auth_socket_settings *);
+       ARRAY_DEFINE(passdbs, struct auth_passdb_settings *);
+       ARRAY_DEFINE(userdbs, struct auth_userdb_settings *);
+};
+
+struct auth_root_settings {
+       const char *base_dir;
+
+       ARRAY_DEFINE(auths, struct auth_settings *);
+};
+
+struct auth_settings *auth_settings_read(const char *name);
+
+#endif
index ef0cbd2af218fda5f68bf61a07e3484be6cccc25..bd975bf006fb03dbbd2f6e4016d10f94ece472dd 100644 (file)
@@ -28,6 +28,7 @@ struct auth_worker_request {
 };
 
 struct auth_worker_connection {
+       struct auth *auth;
        int fd;
 
        struct io *io;
@@ -43,8 +44,6 @@ struct auth_worker_connection {
 
 static ARRAY_DEFINE(connections, struct auth_worker_connection *) = ARRAY_INIT;
 static unsigned int idle_count;
-static unsigned int auth_workers_max;
-
 static ARRAY_DEFINE(worker_request_array, struct auth_worker_request *);
 static struct aqueue *worker_request_queue;
 static time_t auth_worker_last_warn;
@@ -120,12 +119,12 @@ static void auth_worker_request_send_next(struct auth_worker_connection *conn)
        auth_worker_request_send(conn, request);
 }
 
-static struct auth_worker_connection *auth_worker_create(void)
+static struct auth_worker_connection *auth_worker_create(struct auth *auth)
 {
        struct auth_worker_connection *conn;
        int fd, try;
 
-       if (array_count(&connections) >= auth_workers_max)
+       if (array_count(&connections) >= auth->set->worker_max_count)
                return NULL;
 
        for (try = 0;; try++) {
@@ -154,6 +153,7 @@ static struct auth_worker_connection *auth_worker_create(void)
        }
 
        conn = i_new(struct auth_worker_connection, 1);
+       conn->auth = auth;
        conn->fd = fd;
        conn->input = i_stream_create_fd(fd, AUTH_WORKER_MAX_LINE_LENGTH,
                                         FALSE);
@@ -172,6 +172,7 @@ static void auth_worker_destroy(struct auth_worker_connection **_conn,
                                const char *reason, bool restart)
 {
        struct auth_worker_connection *conn = *_conn;
+       struct auth *auth = conn->auth;
        struct auth_worker_connection **connp;
        unsigned int i, count;
 
@@ -208,7 +209,7 @@ static void auth_worker_destroy(struct auth_worker_connection **_conn,
        i_free(conn);
 
        if (idle_count == 0 && restart) {
-               conn = auth_worker_create();
+               conn = auth_worker_create(auth);
                if (conn != NULL)
                        auth_worker_request_send_next(conn);
        }
@@ -323,7 +324,7 @@ void auth_worker_call(struct auth_request *auth_request,
                conn = auth_worker_find_free();
                if (conn == NULL) {
                        /* no free connections, create a new one */
-                       conn = auth_worker_create();
+                       conn = auth_worker_create(auth_request->auth);
                }
        }
        if (conn != NULL)
@@ -334,7 +335,7 @@ void auth_worker_call(struct auth_request *auth_request,
        }
 }
 
-void auth_worker_server_init(void)
+void auth_worker_server_init(struct auth *auth)
 {
        const char *env;
 
@@ -348,16 +349,11 @@ void auth_worker_server_init(void)
                i_fatal("AUTH_WORKER_PATH environment not set");
        worker_socket_path = i_strdup(env);
 
-       env = getenv("AUTH_WORKER_MAX_COUNT");
-       if (env == NULL)
-               i_fatal("AUTH_WORKER_MAX_COUNT environment not set");
-       auth_workers_max = atoi(env);
-
        i_array_init(&worker_request_array, 128);
        worker_request_queue = aqueue_init(&worker_request_array.arr);
 
        i_array_init(&connections, 16);
-       (void)auth_worker_create();
+       (void)auth_worker_create(auth);
 }
 
 void auth_worker_server_deinit(void)
index f50ab4a3d6c837ae3f3994b6bdbbbe70092c0f8e..3e5e120b5dbd2c0c37d04610a9fa76ebf89b48f8 100644 (file)
@@ -11,7 +11,7 @@ void auth_worker_call(struct auth_request *auth_request,
                      struct auth_stream_reply *data,
                      auth_worker_callback_t *callback);
 
-void auth_worker_server_init(void);
+void auth_worker_server_init(struct auth *auth);
 void auth_worker_server_deinit(void);
 
 #endif
index fc6cd62d26b32f26535ec3c8495b2dd8fde25277..d50d70ba8512b4793c2fb78d4055b99a53eadf13 100644 (file)
@@ -2,9 +2,9 @@
 
 #include "common.h"
 #include "network.h"
-#include "buffer.h"
+#include "array.h"
 #include "str.h"
-#include "hostpid.h"
+#include "env-util.h"
 #include "mech.h"
 #include "userdb.h"
 #include "passdb.h"
 #include <stdlib.h>
 #include <unistd.h>
 
-struct auth *auth_preinit(void)
+struct auth_userdb_settings userdb_dummy_set = {
+       MEMBER(driver) "static",
+       MEMBER(args) ""
+};
+
+struct auth *auth_preinit(struct auth_settings *set)
 {
+       struct auth_passdb_settings *const *passdbs;
+       struct auth_userdb_settings *const *userdbs;
        struct auth *auth;
-       struct auth_passdb *auth_passdb, **passdb_p, **masterdb_p;
-       const char *driver, *args;
        pool_t pool;
-       unsigned int i;
+       unsigned int i, count, db_count, passdb_count, last_passdb = 0;
 
        pool = pool_alloconly_create("auth", 2048);
        auth = p_new(pool, struct auth, 1);
        auth->pool = pool;
+       auth->set = set;
 
-       auth->verbose_debug_passwords =
-               getenv("VERBOSE_DEBUG_PASSWORDS") != NULL;
-       auth->verbose_debug = getenv("VERBOSE_DEBUG") != NULL ||
-               auth->verbose_debug_passwords;
-       auth->verbose = getenv("VERBOSE") != NULL || auth->verbose_debug;
-
-       passdb_p = &auth->passdbs;
-       masterdb_p = &auth->masterdbs;
-       auth_passdb = NULL;
-       for (i = 1; ; i++) {
-               driver = getenv(t_strdup_printf("PASSDB_%u_DRIVER", i));
-               if (driver == NULL)
-                       break;
+       if (array_is_created(&set->passdbs))
+               passdbs = array_get(&set->passdbs, &db_count);
+       else {
+               passdbs = NULL;
+               db_count = 0;
+       }
 
-                args = getenv(t_strdup_printf("PASSDB_%u_ARGS", i));
-               auth_passdb = passdb_preinit(auth, driver, args, i);
+       /* initialize passdbs first and count them */
+       for (passdb_count = 0, i = 0; i < db_count; i++) {
+               if (passdbs[i]->master)
+                       continue;
 
-                auth_passdb->deny =
-                        getenv(t_strdup_printf("PASSDB_%u_DENY", i)) != NULL;
-               auth_passdb->pass =
-                        getenv(t_strdup_printf("PASSDB_%u_PASS", i)) != NULL;
+               passdb_preinit(auth, passdbs[i]);
+               passdb_count++;
+               last_passdb = i;
+       }
+       if (passdb_count != 0 && passdbs[last_passdb]->pass)
+               i_fatal("Last passdb can't have pass=yes");
 
-               if (getenv(t_strdup_printf("PASSDB_%u_MASTER", i)) == NULL) {
-                       *passdb_p = auth_passdb;
-                       passdb_p = &auth_passdb->next;
-                } else {
-                       if (auth_passdb->deny)
-                               i_fatal("Master passdb can't have deny=yes");
+       for (passdb_count = 0, i = 0; i < db_count; i++) {
+               if (!passdbs[i]->master)
+                       continue;
 
-                       *masterdb_p = auth_passdb;
-                       masterdb_p = &auth_passdb->next;
-               }
-       }
-       if (auth_passdb != NULL && auth_passdb->pass) {
-               if (masterdb_p != &auth_passdb->next)
-                       i_fatal("Last passdb can't have pass=yes");
-               else if (auth->passdbs == NULL) {
+               if (passdbs[i]->deny)
+                       i_fatal("Master passdb can't have deny=yes");
+               if (passdbs[i]->pass && passdb_count == 0) {
                        i_fatal("Master passdb can't have pass=yes "
                                "if there are no passdbs");
                }
+               passdb_preinit(auth, passdbs[i]);
        }
 
-       for (i = 1; ; i++) {
-               driver = getenv(t_strdup_printf("USERDB_%u_DRIVER", i));
-               if (driver == NULL)
-                       break;
-
-                args = getenv(t_strdup_printf("USERDB_%u_ARGS", i));
-               userdb_preinit(auth, driver, args);
+       if (array_is_created(&set->userdbs)) {
+               userdbs = array_get(&set->userdbs, &count);
+               for (i = 0; i < count; i++)
+                       userdb_preinit(auth, userdbs[i]);
        }
 
        if (auth->userdbs == NULL) {
                /* use a dummy userdb static. */
-               userdb_preinit(auth, "static", "");
+               userdb_preinit(auth, &userdb_dummy_set);
        }
        return auth;
 }
@@ -209,7 +202,7 @@ void auth_init(struct auth *auth)
        struct auth_userdb *userdb;
        const struct mech_module *mech;
        const char *const *mechanisms;
-       const char *env;
+       const char *p;
 
        for (passdb = auth->masterdbs; passdb != NULL; passdb = passdb->next)
                passdb_init(passdb);
@@ -219,26 +212,17 @@ void auth_init(struct auth *auth)
                userdb_init(userdb);
        /* caching is handled only by the main auth process */
        if (!worker)
-               passdb_cache_init();
+               passdb_cache_init(auth->set);
 
        auth->mech_handshake = str_new(auth->pool, 512);
 
-       auth->anonymous_username = getenv("ANONYMOUS_USERNAME");
-       if (auth->anonymous_username != NULL &&
-           *auth->anonymous_username == '\0')
-                auth->anonymous_username = NULL;
-
        /* register wanted mechanisms */
-       env = getenv("MECHANISMS");
-       if (env == NULL)
-               i_fatal("MECHANISMS environment is unset");
-
-       mechanisms = t_strsplit_spaces(env, " ");
+       mechanisms = t_strsplit_spaces(auth->set->mechanisms, " ");
        while (*mechanisms != NULL) {
                if (strcasecmp(*mechanisms, "ANONYMOUS") == 0) {
-                       if (auth->anonymous_username == NULL) {
+                       if (*auth->set->anonymous_username == '\0') {
                                i_fatal("ANONYMOUS listed in mechanisms, "
-                                       "but anonymous_username not given");
+                                       "but anonymous_username not set");
                        }
                }
                mech = mech_module_find(*mechanisms);
@@ -255,48 +239,22 @@ void auth_init(struct auth *auth)
                i_fatal("No authentication mechanisms configured");
        auth_mech_list_verify_passdb(auth);
 
-       env = getenv("REALMS");
-       if (env == NULL)
-               env = "";
-       auth->auth_realms = p_strsplit_spaces(auth->pool, env, " ");
+       auth->auth_realms = (const char *const *)
+               p_strsplit_spaces(auth->pool, auth->set->realms, " ");
 
-       env = getenv("DEFAULT_REALM");
-       if (env != NULL && *env != '\0')
-               auth->default_realm = env;
-
-       env = getenv("USERNAME_CHARS");
-       if (env == NULL || *env == '\0') {
+       if (*auth->set->username_chars == '\0') {
                /* all chars are allowed */
                memset(auth->username_chars, 1, sizeof(auth->username_chars));
        } else {
-               for (; *env != '\0'; env++)
-                       auth->username_chars[(int)(uint8_t)*env] = 1;
+               for (p = auth->set->username_chars; *p != '\0'; p++)
+                       auth->username_chars[(int)(uint8_t)*p] = 1;
        }
 
-       env = getenv("USERNAME_TRANSLATION");
-       if (env != NULL) {
-               for (; *env != '\0' && env[1] != '\0'; env += 2)
-                       auth->username_translation[(int)(uint8_t)*env] = env[1];
+       if (*auth->set->username_translation != '\0') {
+               p = auth->set->username_translation;
+               for (; *p != '\0' && p[1] != '\0'; p += 2)
+                       auth->username_translation[(int)(uint8_t)*p] = p[1];
        }
-
-       env = getenv("USERNAME_FORMAT");
-       if (env != NULL && *env != '\0')
-               auth->username_format = env;
-
-       env = getenv("GSSAPI_HOSTNAME");
-       if (env != NULL && *env != '\0')
-               auth->gssapi_hostname = env;
-       else
-               auth->gssapi_hostname = my_hostname;
-
-       env = getenv("MASTER_USER_SEPARATOR");
-       if (env != NULL)
-               auth->master_user_separator = env[0];
-
-       auth->ssl_require_client_cert =
-               getenv("SSL_REQUIRE_CLIENT_CERT") != NULL;
-       auth->ssl_username_from_cert =
-               getenv("SSL_USERNAME_FROM_CERT") != NULL;
 }
 
 void auth_deinit(struct auth **_auth)
index 2ac3d1ae6d9f9d918c28a9f081d68a80a55bd714..da331064ac947c986e2ee1647d17df02166945c8 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef AUTH_H
 #define AUTH_H
 
+#include "auth-settings.h"
+
 #define PASSWORD_HIDDEN_STR "<hidden>"
 
 struct auth_passdb {
@@ -29,6 +31,7 @@ struct auth_userdb {
 
 struct auth {
        pool_t pool;
+       const struct auth_settings *set;
 
        struct mech_module_list *mech_modules;
        buffer_t *mech_handshake;
@@ -37,23 +40,14 @@ struct auth {
        struct auth_passdb *passdbs;
        struct auth_userdb *userdbs;
 
-       char *const *auth_realms;
-       const char *default_realm;
-       const char *anonymous_username;
-       const char *username_format;
-       const char *gssapi_hostname;
+       const char *const *auth_realms;
        char username_chars[256];
        char username_translation[256];
-       char master_user_separator;
-       bool ssl_require_client_cert;
-       bool ssl_username_from_cert;
-
-       bool verbose, verbose_debug, verbose_debug_passwords;
 };
 
 const string_t *auth_mechanisms_get_list(struct auth *auth);
 
-struct auth *auth_preinit(void);
+struct auth *auth_preinit(struct auth_settings *set);
 void auth_init(struct auth *auth);
 void auth_deinit(struct auth **auth);
 
index 8d5c61f42375b24b9032c6958b8d86aa44279366..71f21f5f1d68a53a8ba4e69c95fa3576f0c212c1 100644 (file)
@@ -997,7 +997,7 @@ db_ldap_result_iterate_init(struct ldap_connection *conn, LDAPMessage *entry,
                ctx->static_attrs = t_strsplit(str_c(str), ",");
        }
 
-       if (auth_request->auth->verbose_debug)
+       if (auth_request->auth->set->debug)
                ctx->debug = t_str_new(256);
 
        ctx->attr = ldap_first_attribute(conn->ld, entry, &ctx->ber);
@@ -1069,7 +1069,7 @@ db_ldap_result_return_value(struct db_ldap_result_iterate_context *ctx)
        if (ctx->debug != NULL) {
                if (!first)
                        str_append_c(ctx->debug, '/');
-               if (ctx->auth_request->auth->verbose_debug_passwords ||
+               if (ctx->auth_request->auth->set->debug_passwords ||
                    strcmp(ctx->name, "password") != 0)
                        str_append(ctx->debug, ctx->value);
                else
index 8a9704605875a7bc4a28e5bdf34379c18a9df360..8d62f34c5510525c14d1290b69855067bd2e7349 100644 (file)
@@ -175,7 +175,7 @@ static void add_extra_listeners(void)
 
 static void drop_privileges(void)
 {
-       const char *version;
+       const char *version, *name;
 
        version = getenv("DOVECOT_VERSION");
        if (version != NULL && strcmp(version, PACKAGE_VERSION) != 0) {
@@ -191,6 +191,9 @@ static void drop_privileges(void)
                        "it standalone, you'll need to set AUTH_* "
                        "environment variables (AUTH_1 isn't set).");
        }
+       name = getenv("AUTH_NAME");
+       if (name == NULL)
+               i_fatal("Missing AUTH_NAME environment");
 
        open_logfile();
 
@@ -207,7 +210,7 @@ static void drop_privileges(void)
        userdbs_init();
        modules = module_dir_load(AUTH_MODULE_DIR, NULL, TRUE, version);
        module_dir_init(modules);
-       auth = auth_preinit();
+       auth = auth_preinit(auth_settings_read(name));
        auth_master_listeners_init();
        if (!worker)
                add_extra_listeners();
@@ -233,7 +236,7 @@ static void main_init(bool nodaemon)
        lib_signals_ignore(SIGUSR2, TRUE);
 
        child_wait_init();
-       mech_init();
+       mech_init(auth->set);
        password_schemes_init();
        auth_init(auth);
        auth_request_handler_init();
@@ -283,11 +286,11 @@ static void main_deinit(void)
         auth_worker_server_deinit();
        auth_master_listeners_deinit();
 
-       auth_deinit(&auth);
        module_dir_unload(&modules);
        userdbs_deinit();
        passdbs_deinit();
-       mech_deinit();
+       mech_deinit(auth->set);
+       auth_deinit(&auth);
 
         password_schemes_deinit();
        sql_drivers_deinit();
index 1758020db0f63e3b510c0305b6017207a782d562..e214064b30e5048ed8be553b3a6b6351f7564f41 100644 (file)
@@ -7,9 +7,9 @@ static void
 mech_anonymous_auth_continue(struct auth_request *request,
                             const unsigned char *data, size_t data_size)
 {
-       i_assert(request->auth->anonymous_username != NULL);
+       i_assert(*request->auth->set->anonymous_username != '\0');
 
-       if (request->auth->verbose) {
+       if (request->auth->set->verbose) {
                /* temporarily set the user to the one that was given,
                   so that the log message goes right */
                request->user =
@@ -18,7 +18,7 @@ mech_anonymous_auth_continue(struct auth_request *request,
        }
 
        request->user = p_strdup(request->pool,
-                                request->auth->anonymous_username);
+                                request->auth->set->anonymous_username);
 
        auth_request_success(request, NULL, 0);
 }
index ca000b443e632d25eb82e0024cd14c257db476a1..0a7c452ad6f45556d0afc89c86f4c54a8577e1be 100644 (file)
@@ -60,7 +60,7 @@ static string_t *get_digest_challenge(struct digest_auth_request *request)
        struct auth *auth = request->auth_request.auth;
        buffer_t *buf;
        string_t *str;
-       char *const *tmp;
+       const char *const *tmp;
        unsigned char nonce[16];
        int i;
        bool first_qop;
@@ -220,7 +220,7 @@ static bool verify_credentials(struct digest_auth_request *request,
 
 static bool verify_realm(struct digest_auth_request *request, const char *realm)
 {
-       char *const *tmp;
+       const char *const *tmp;
 
        if (*realm == '\0')
                return TRUE;
index 8d2c5ae8972ed011467fdb0f1e2e1bb5e8ef78f9..af8eca1ce865c35bb4642ea8f670e67d259edf3e 100644 (file)
  */
 
 #include "common.h"
-#include "mech.h"
-#include "passdb.h"
+#include "env-util.h"
 #include "str.h"
 #include "str-sanitize.h"
-#include "buffer.h"
 #include "hex-binary.h"
 #include "safe-memset.h"
+#include "mech.h"
+#include "passdb.h"
 
 #include <stdlib.h>
 
@@ -98,12 +98,13 @@ static void auth_request_log_gss_error(struct auth_request *request,
        } while (message_context != 0);
 }
 
-static void mech_gssapi_initialize(void)
+static void mech_gssapi_initialize(struct auth *auth)
 {
-       const char *path;
+       const char *path = auth->set->krb5_keytab;
 
-       path = getenv("KRB5_KTNAME");
-       if (path != NULL) {
+       if (*path != '\0') {
+               /* environment may be used by Kerberos 5 library directly */
+               env_put(t_strconcat("KRB5_KTNAME=", path, NULL));
 #ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
                gsskrb5_register_acceptor_identity(path);
 #elif defined (HAVE_KRB5_GSS_REGISTER_ACCEPTOR_IDENTITY)
@@ -117,11 +118,6 @@ static struct auth_request *mech_gssapi_auth_new(void)
        struct gssapi_auth_request *request;
        pool_t pool;
 
-       if (!gssapi_initialized) {
-               gssapi_initialized = TRUE;
-               mech_gssapi_initialize();
-       }
-
        pool = pool_alloconly_create("gssapi_auth_request", 1024);
        request = p_new(pool, struct gssapi_auth_request, 1);
        request->pool = pool;
@@ -141,7 +137,12 @@ static OM_uint32 obtain_service_credentials(struct auth_request *request,
        gss_name_t gss_principal;
        const char *service_name;
 
-       if (strcmp(request->auth->gssapi_hostname, "$ALL") == 0) {
+       if (!gssapi_initialized) {
+               gssapi_initialized = TRUE;
+               mech_gssapi_initialize(request->auth);
+       }
+
+       if (strcmp(request->auth->set->gssapi_hostname, "$ALL") == 0) {
                auth_request_log_info(request, "gssapi",
                                      "Using all keytab entries");
                *ret = GSS_C_NO_CREDENTIAL;
@@ -159,7 +160,7 @@ static OM_uint32 obtain_service_credentials(struct auth_request *request,
        principal_name = t_str_new(128);
        str_append(principal_name, service_name);
        str_append_c(principal_name, '@');
-       str_append(principal_name, request->auth->gssapi_hostname);
+       str_append(principal_name, request->auth->set->gssapi_hostname);
 
        auth_request_log_info(request, "gssapi",
                "Obtaining credentials for %s", str_c(principal_name));
index de41a2128ec744e962cbe47341cf44a1293af772..3a9f7142cd98ece0f489dcfeba80dcd9a367fa60 100644 (file)
@@ -238,18 +238,17 @@ rpa_read_buffer(pool_t pool, const unsigned char **data,
 static bool
 rpa_verify_realm(struct rpa_auth_request *request, const char *realm)
 {
+       const struct auth *auth = request->auth_request.auth;
        const char *default_realm;
-       char *const *tmp;
+       const char *const *tmp;
 
-       tmp = request->auth_request.auth->auth_realms;
-       for (; *tmp != NULL; tmp++) {
+       for (tmp = auth->auth_realms; *tmp != NULL; tmp++) {
                if (strcasecmp(realm, *tmp) == 0)
                        return TRUE;
        }
 
-       default_realm = request->auth_request.auth->default_realm != NULL ?
-                       request->auth_request.auth->default_realm :
-                       my_hostname;
+       default_realm = *auth->set->default_realm != '\0' ?
+               auth->set->default_realm : my_hostname;
 
        return strcasecmp(realm, default_realm) == 0;
 }
@@ -353,7 +352,7 @@ mech_rpa_build_token2(struct rpa_auth_request *request, size_t *size)
        string_t *realms;
        buffer_t *buf;
        unsigned char timestamp[RPA_TIMESTAMP_LEN / 2];
-       char *const *tmp;
+       const char *const *tmp;
 
        realms = t_str_new(64);
        for (tmp = auth->auth_realms; *tmp != NULL; tmp++) {
@@ -361,8 +360,8 @@ mech_rpa_build_token2(struct rpa_auth_request *request, size_t *size)
        }
 
        if (str_len(realms) == 0) {
-               rpa_add_realm(realms, auth->default_realm != NULL ?
-                             auth->default_realm : my_hostname,
+               rpa_add_realm(realms, *auth->set->default_realm != '\0' ?
+                             auth->set->default_realm : my_hostname,
                              request->auth_request.service);
        }
 
index 2579854730f13427b7125d14bb9235ac542da817..b9a030382d75c71ba87343f80643c471f6d62596 100644 (file)
@@ -95,7 +95,8 @@ static void sigchld_handler(int signo ATTR_UNUSED,
        winbind_wait_pid(&winbind_spnego_context);
 }
 
-static void winbind_helper_connect(struct winbind_helper *winbind)
+static void
+winbind_helper_connect(struct auth *auth, struct winbind_helper *winbind)
 {
        int infd[2], outfd[2];
        pid_t pid;
@@ -122,7 +123,7 @@ static void winbind_helper_connect(struct winbind_helper *winbind)
 
        if (pid == 0) {
                /* child */
-               const char *helper_path, *args[3];
+               const char *args[3];
 
                (void)close(infd[0]);
                (void)close(outfd[1]);
@@ -131,11 +132,7 @@ static void winbind_helper_connect(struct winbind_helper *winbind)
                    dup2(infd[1], STDOUT_FILENO) < 0)
                        i_fatal("dup2() failed: %m");
 
-               helper_path = getenv("WINBIND_HELPER_PATH");
-               if (helper_path == NULL)
-                       helper_path = DEFAULT_WINBIND_HELPER_PATH;
-
-               args[0] = helper_path;
+               args[0] = auth->set->winbind_helper_path;
                args[1] = winbind->param;
                args[2] = NULL;
                execv(args[0], (void *)args);
@@ -280,6 +277,17 @@ do_auth_continue(struct auth_request *auth_request,
        }
 }
 
+static void
+mech_winbind_auth_initial(struct auth_request *auth_request,
+                         const unsigned char *data, size_t data_size)
+{
+       struct winbind_auth_request *request =
+               (struct winbind_auth_request *)auth_request;
+
+       winbind_helper_connect(auth_request->auth, request->winbind);
+       mech_generic_auth_initial(auth_request, data, data_size);
+}
+
 static void
 mech_winbind_auth_continue(struct auth_request *auth_request,
                           const unsigned char *data, size_t data_size)
@@ -306,7 +314,6 @@ static struct auth_request *do_auth_new(struct winbind_helper *winbind)
        request->auth_request.pool = pool;
 
        request->winbind = winbind;
-       winbind_helper_connect(request->winbind);
        return &request->auth_request;
 }
 
@@ -339,7 +346,7 @@ const struct mech_module mech_winbind_spnego = {
        MEMBER(passdb_need) MECH_PASSDB_NEED_NOTHING,
 
        mech_winbind_spnego_auth_new,
-       mech_generic_auth_initial,
+       mech_winbind_auth_initial,
        mech_winbind_auth_continue,
        mech_generic_auth_free
 };
index 16fbee419a73131ce9c9a90c40fd5e779a615ce9..d7fe3253711a869d83ebd9f7cd4bb5a01f3f86f1 100644 (file)
@@ -81,14 +81,14 @@ extern const struct mech_module mech_gssapi_spnego;
 extern const struct mech_module mech_winbind_ntlm;
 extern const struct mech_module mech_winbind_spnego;
 
-void mech_init(void)
+void mech_init(const struct auth_settings *set)
 {
        mech_register_module(&mech_plain);
        mech_register_module(&mech_login);
        mech_register_module(&mech_apop);
        mech_register_module(&mech_cram_md5);
        mech_register_module(&mech_digest_md5);
-       if (getenv("USE_WINBIND") != NULL) {
+       if (set->use_winbind) {
                mech_register_module(&mech_winbind_ntlm);
                mech_register_module(&mech_winbind_spnego);
        } else {
@@ -106,14 +106,14 @@ void mech_init(void)
 #endif
 }
 
-void mech_deinit(void)
+void mech_deinit(const struct auth_settings *set)
 {
        mech_unregister_module(&mech_plain);
        mech_unregister_module(&mech_login);
        mech_unregister_module(&mech_apop);
        mech_unregister_module(&mech_cram_md5);
        mech_unregister_module(&mech_digest_md5);
-       if (getenv("NTLM_USE_WINBIND") != NULL) {
+       if (set->use_winbind) {
                mech_unregister_module(&mech_winbind_ntlm);
                mech_unregister_module(&mech_winbind_spnego);
        } else {
index 72327d2302a437c7546ef397f4c791e8b83d3476..46d8a07ce34d3aaf7a428e3fe49ad796828477a3 100644 (file)
@@ -63,7 +63,7 @@ void mech_generic_auth_initial(struct auth_request *request,
                               const unsigned char *data, size_t data_size);
 void mech_generic_auth_free(struct auth_request *request);
 
-void mech_init(void);
-void mech_deinit(void);
+void mech_init(const struct auth_settings *set);
+void mech_deinit(const struct auth_settings *set);
 
 #endif
index 5b3bbb307c1724366b066bdf5765d77710d7ba54..541c1d61a06d06165d4901b29860f2c86663f366 100644 (file)
@@ -14,7 +14,7 @@ passdb_cache_log_hit(struct auth_request *request, const char *value)
 {
        const char *p;
 
-       if (!request->auth->verbose_debug_passwords &&
+       if (!request->auth->set->debug_passwords &&
            *value != '\0' && *value != '\t') {
                /* hide the password */
                p = strchr(value, '\t');
@@ -125,31 +125,13 @@ bool passdb_cache_lookup_credentials(struct auth_request *request,
        return TRUE;
 }
 
-void passdb_cache_init(void)
+void passdb_cache_init(const struct auth_settings *set)
 {
-       const char *env;
-       size_t max_size;
-       unsigned int cache_ttl, neg_cache_ttl;
-
-       env = getenv("CACHE_SIZE");
-       if (env == NULL)
-               return;
-
-       max_size = (size_t)strtoul(env, NULL, 10) * 1024;
-       if (max_size == 0)
-               return;
-
-       env = getenv("CACHE_TTL");
-       if (env == NULL)
-               return;
-
-       cache_ttl = (unsigned int)strtoul(env, NULL, 10);
-       if (cache_ttl == 0)
+       if (set->cache_size == 0 || set->cache_ttl == 0)
                return;
 
-       env = getenv("CACHE_NEGATIVE_TTL");
-       neg_cache_ttl = env == NULL ? 0 : (unsigned int)strtoul(env, NULL, 10);
-       passdb_cache = auth_cache_new(max_size, cache_ttl, neg_cache_ttl);
+       passdb_cache = auth_cache_new(set->cache_size * 1024UL, set->cache_ttl,
+                                     set->cache_negative_ttl);
 }
 
 void passdb_cache_deinit(void)
index 42d2089fa4efb042f79d21929baa5be04a13d8cc..98e84ae99a8bade36d2b984f4d4abac1b46b1f26 100644 (file)
@@ -14,7 +14,7 @@ bool passdb_cache_lookup_credentials(struct auth_request *request,
                                     enum passdb_result *result_r,
                                     bool use_expired);
 
-void passdb_cache_init(void);
+void passdb_cache_init(const struct auth_settings *set);
 void passdb_cache_deinit(void);
 
 #endif
index 8c789c861fafde716dcb4775b316e5528c2b7100..9478cd5b09dba0580a708dc00d3816d95b32132e 100644 (file)
@@ -147,7 +147,7 @@ passwd_file_preinit(struct auth_passdb *auth_passdb, const char *args)
                       struct passwd_file_passdb_module, 1);
        module->auth = auth_passdb->auth;
        module->pwf = db_passwd_file_init(args, format, FALSE,
-                                         module->auth->verbose_debug);
+                                         module->auth->set->debug);
 
        if (!module->pwf->vars)
                module->module.cache_key = format;
index 898c8b38aaa1252486b4a7366703c30796167d53..671b2b065032adc03bad89b0636ffa0ea7adb113 100644 (file)
@@ -81,7 +81,7 @@ bool passdb_get_credentials(struct auth_request *auth_request,
                        const char *error = t_strdup_printf(
                                "Requested %s scheme, but we have only %s",
                                wanted_scheme, input_scheme);
-                       if (auth_request->auth->verbose_debug_passwords) {
+                       if (auth_request->auth->set->debug_passwords) {
                                error = t_strdup_printf("%s (input: %s)",
                                                        error, input);
                        }
@@ -92,7 +92,7 @@ bool passdb_get_credentials(struct auth_request *auth_request,
 
                /* we can generate anything out of plaintext passwords */
                plaintext = t_strndup(*credentials_r, *size_r);
-               if (auth_request->auth->verbose_debug_passwords) {
+               if (auth_request->auth->set->debug_passwords) {
                        auth_request_log_info(auth_request, "password",
                                "Generating %s from user %s password %s",
                                wanted_scheme, auth_request->original_username,
@@ -131,31 +131,34 @@ void passdb_handle_credentials(enum passdb_result result,
        callback(result, credentials, size, auth_request);
 }
 
-struct auth_passdb *passdb_preinit(struct auth *auth, const char *driver,
-                                  const char *args, unsigned int id)
+struct auth_passdb *
+passdb_preinit(struct auth *auth, struct auth_passdb_settings *set)
 {
        struct passdb_module_interface *iface;
-        struct auth_passdb *auth_passdb;
-
-       if (args == NULL) args = "";
+        struct auth_passdb *auth_passdb, **dest;
 
        auth_passdb = p_new(auth->pool, struct auth_passdb, 1);
        auth_passdb->auth = auth;
-        auth_passdb->args = p_strdup(auth->pool, args);
-        auth_passdb->id = id;
+       auth_passdb->args = set->args == NULL ? "" :
+               p_strdup(auth->pool, set->args);
+       auth_passdb->deny = set->deny;
+
+       for (dest = &auth->passdbs; *dest != NULL; dest = &(*dest)->next)
+               auth_passdb->id++;
+       *dest = auth_passdb;
 
-       iface = passdb_interface_find(driver);
+       iface = passdb_interface_find(set->driver);
        if (iface == NULL)
-               i_fatal("Unknown passdb driver '%s'", driver);
+               i_fatal("Unknown passdb driver '%s'", set->driver);
        if (iface->verify_plain == NULL) {
                i_fatal("Support not compiled in for passdb driver '%s'",
-                       driver);
+                       set->driver);
        }
 
        if (iface->preinit == NULL && iface->init == NULL &&
            *auth_passdb->args != '\0') {
                i_fatal("passdb %s: No args are supported: %s",
-                       driver, auth_passdb->args);
+                       set->driver, auth_passdb->args);
        }
 
        if (iface->preinit == NULL) {
@@ -179,7 +182,7 @@ void passdb_init(struct auth_passdb *passdb)
 
        if (passdb->passdb->blocking && !worker) {
                /* blocking passdb - we need an auth server */
-               auth_worker_server_init();
+               auth_worker_server_init(passdb->auth);
        }
 }
 
index 94cc36a7ecf9f8669f5c84d44af29340c31eea30..123f0f62fddb60fb85ac850a225679540948384c 100644 (file)
@@ -80,8 +80,9 @@ void passdb_handle_credentials(enum passdb_result result,
                               lookup_credentials_callback_t *callback,
                                struct auth_request *auth_request);
 
-struct auth_passdb *passdb_preinit(struct auth *auth, const char *driver,
-                                  const char *args, unsigned int id);
+struct auth_passdb *
+       passdb_preinit(struct auth *auth, struct auth_passdb_settings *set);
+
 void passdb_init(struct auth_passdb *passdb);
 void passdb_deinit(struct auth_passdb *passdb);
 
index 501eae0da922dfcb01b558543310efec306c69e1..2fe4f054285c0d66f95a79a43738692e9585a5a8 100644 (file)
@@ -97,7 +97,7 @@ passwd_file_preinit(struct auth_userdb *auth_userdb, const char *args)
                       struct passwd_file_userdb_module, 1);
        module->auth = auth_userdb->auth;
        module->pwf = db_passwd_file_init(args, format, TRUE,
-                                         module->auth->verbose_debug);
+                                         module->auth->set->debug);
 
        if (!module->pwf->vars)
                module->module.cache_key = PASSWD_FILE_CACHE_KEY;
index 61bda31cdc1eda34f81fbc73e887926c0b2ef314..5320d14e679a2b8a6e63d6cd1cf5e6986a9544c2 100644 (file)
@@ -26,7 +26,7 @@ static void prefetch_lookup(struct auth_request *auth_request,
                                        "passdb didn't return userdb entries");
                        }
                } else if (!auth_request->userdb_lookup ||
-                          auth_request->auth->verbose_debug) {
+                          auth_request->auth->set->debug) {
                        /* more userdbs, they may know the user */
                        auth_request_log_info(auth_request, "prefetch",
                                "passdb didn't return userdb entries, "
index dffcfdaed1e26fb4e59404db37e120cf9c3e9ed1..fd139d8e5685bd1a6d2e82254a31b845971300a4 100644 (file)
@@ -100,33 +100,32 @@ gid_t userdb_parse_gid(struct auth_request *request, const char *str)
        return gr->gr_gid;
 }
 
-void userdb_preinit(struct auth *auth, const char *driver, const char *args)
+void userdb_preinit(struct auth *auth, struct auth_userdb_settings *set)
 {
        struct userdb_module_interface *iface;
         struct auth_userdb *auth_userdb, **dest;
 
-       if (args == NULL) args = "";
-
        auth_userdb = p_new(auth->pool, struct auth_userdb, 1);
        auth_userdb->auth = auth;
-       auth_userdb->args = p_strdup(auth->pool, args);
+       auth_userdb->args = set->args == NULL ? "" :
+               p_strdup(auth->pool, set->args);
 
        for (dest = &auth->userdbs; *dest != NULL; dest = &(*dest)->next)
                auth_userdb->num++;
        *dest = auth_userdb;
 
-       iface = userdb_interface_find(driver);
+       iface = userdb_interface_find(set->driver);
        if (iface == NULL)
-               i_fatal("Unknown userdb driver '%s'", driver);
+               i_fatal("Unknown userdb driver '%s'", set->driver);
        if (iface->lookup == NULL) {
                i_fatal("Support not compiled in for userdb driver '%s'",
-                       driver);
+                       set->driver);
        }
 
        if (iface->preinit == NULL && iface->init == NULL &&
            *auth_userdb->args != '\0') {
                i_fatal("userdb %s: No args are supported: %s",
-                       driver, auth_userdb->args);
+                       set->driver, auth_userdb->args);
        }
 
        if (iface->preinit == NULL) {
@@ -146,7 +145,7 @@ void userdb_init(struct auth_userdb *userdb)
 
        if (userdb->userdb->blocking && !worker) {
                /* blocking userdb - we need an auth server */
-               auth_worker_server_init();
+               auth_worker_server_init(userdb->auth);
        }
 }
 
index 66392245c6faacc7f3213381a0fc8f1d48017c94..623c18a1928bafb031aee7de3303f85fc14a129e 100644 (file)
@@ -41,7 +41,7 @@ struct userdb_module_interface {
 uid_t userdb_parse_uid(struct auth_request *request, const char *str);
 gid_t userdb_parse_gid(struct auth_request *request, const char *str);
 
-void userdb_preinit(struct auth *auth, const char *driver, const char *args);
+void userdb_preinit(struct auth *auth, struct auth_userdb_settings *set);
 void userdb_init(struct auth_userdb *userdb);
 void userdb_deinit(struct auth_userdb *userdb);
 
diff --git a/src/config/Makefile.am b/src/config/Makefile.am
new file mode 100644 (file)
index 0000000..57cfb87
--- /dev/null
@@ -0,0 +1,33 @@
+bin_PROGRAMS = doveconf
+
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/src/lib \
+       -I$(top_srcdir)/src/lib-settings \
+       -DSYSCONFDIR=\""$(sysconfdir)"\" \
+       -DPKG_RUNDIR=\""$(rundir)"\" \
+       -DPKG_LIBEXECDIR=\""$(pkglibexecdir)"\" \
+       -DMODULEDIR=\""$(moduledir)"\" \
+       -DSSLDIR=\""$(ssldir)\""
+
+doveconf_LDADD = \
+       ../lib-settings/libsettings.a \
+       ../lib/liblib.a \
+       $(RAND_LIBS)
+
+doveconf_SOURCES = \
+       all-settings.c \
+       config-connection.c \
+       config-parser.c \
+       main.c
+
+noinst_HEADERS = \
+       all-settings.h \
+       common.h \
+       config-connection.h \
+       config-parser.h
+
+all-settings.c: $(SETTING_FILES) $(top_srcdir)/src/config/settings-get.pl
+       $(top_srcdir)/src/config/settings-get.pl $(SETTING_FILES) > all-settings.c || rm -f all-settings.c
+
+EXTRA_DIST = \
+       settings-get.pl
diff --git a/src/config/common.h b/src/config/common.h
new file mode 100644 (file)
index 0000000..2a40691
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __COMMON_H
+#define __COMMON_H
+
+#include "lib.h"
+
+extern struct master_service *service;
+extern string_t *config_string;
+
+#endif
diff --git a/src/config/config-connection.c b/src/config/config-connection.c
new file mode 100644 (file)
index 0000000..8499f6a
--- /dev/null
@@ -0,0 +1,123 @@
+/* Copyright (C) 2005 Timo Sirainen */
+
+#include "common.h"
+#include "str.h"
+#include "ioloop.h"
+#include "network.h"
+#include "istream.h"
+#include "ostream.h"
+#include "config-connection.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define MAX_INBUF_SIZE 1024
+
+#define CONFIG_CLIENT_PROTOCOL_MAJOR_VERSION 1
+#define CONFIG_CLIENT_PROTOCOL_MINOR_VERSION 0
+
+struct config_connection {
+       int fd;
+       struct istream *input;
+       struct ostream *output;
+       struct io *io;
+
+       unsigned int version_received:1;
+       unsigned int handshaked:1;
+};
+
+static const char *const *
+config_connection_next_line(struct config_connection *conn)
+{
+       const char *line;
+
+       line = i_stream_next_line(conn->input);
+       if (line == NULL)
+               return NULL;
+
+       return t_strsplit(line, "\t");
+}
+
+static void config_connection_request(struct config_connection *conn,
+                                     const char *const *args)
+{
+       /* <process> [<args>] */
+       // FIXME
+       o_stream_send(conn->output, str_data(config_string),
+                     str_len(config_string));
+       o_stream_flush(conn->output);
+}
+
+static void config_connection_input(void *context)
+{
+       struct config_connection *conn = context;
+       const char *const *args, *line;
+
+       switch (i_stream_read(conn->input)) {
+       case -2:
+               i_error("BUG: Config client connection sent too much data");
+                config_connection_destroy(conn);
+               return;
+       case -1:
+                config_connection_destroy(conn);
+               return;
+       }
+
+       if (!conn->version_received) {
+               line = i_stream_next_line(conn->input);
+               if (line == NULL)
+                       return;
+
+               if (strncmp(line, "VERSION\t", 8) != 0 ||
+                   atoi(t_strcut(line + 8, '\t')) !=
+                   CONFIG_CLIENT_PROTOCOL_MAJOR_VERSION) {
+                       i_error("Config client not compatible with this server "
+                               "(mixed old and new binaries?)");
+                       config_connection_destroy(conn);
+                       return;
+               }
+               conn->version_received = TRUE;
+       }
+
+       t_push();
+       while ((args = config_connection_next_line(conn)) != NULL) {
+               if (args[0] == NULL)
+                       continue;
+               if (strcmp(args[0], "REQ") == 0)
+                       config_connection_request(conn, args + 1);
+       }
+       t_pop();
+}
+
+struct config_connection *config_connection_create(int fd)
+{
+       struct config_connection *conn;
+
+       conn = i_new(struct config_connection, 1);
+       conn->fd = fd;
+       conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
+       conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+       conn->io = io_add(fd, IO_READ, config_connection_input, conn);
+       return conn;
+}
+
+void config_connection_destroy(struct config_connection *conn)
+{
+       io_remove(&conn->io);
+       i_stream_destroy(&conn->input);
+       o_stream_destroy(&conn->output);
+       if (close(conn->fd) < 0)
+               i_error("close(config conn) failed: %m");
+       i_free(conn);
+}
+
+void config_connection_dump_request(int fd, const char *service)
+{
+       struct config_connection *conn;
+       const char *args[2] = { service, NULL };
+
+       conn = config_connection_create(fd);
+        config_connection_request(conn, args);
+       config_connection_destroy(conn);
+}
diff --git a/src/config/config-connection.h b/src/config/config-connection.h
new file mode 100644 (file)
index 0000000..e5e9cf1
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __CONFIG_CONNECTION_H
+#define __CONFIG_CONNECTION_H
+
+struct config_connection *config_connection_create(int fd);
+void config_connection_destroy(struct config_connection *conn);
+
+void config_connection_dump_request(int fd, const char *service);
+
+#endif
diff --git a/src/config/config-parser.c b/src/config/config-parser.c
new file mode 100644 (file)
index 0000000..864d706
--- /dev/null
@@ -0,0 +1,534 @@
+/* Copyright (C) 2005 Timo Sirainen */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "hash.h"
+#include "strescape.h"
+#include "istream.h"
+#include "settings-parser.h"
+#include "all-settings.h"
+#include "config-parser.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
+
+void config_parsers_fix_parents(pool_t pool)
+{
+#if 0
+       struct config_setting_parser_list *l;
+       const struct setting_define *d;
+       ARRAY_DEFINE(parents, ARRAY_TYPE(dynamic_settings_parsers));
+       ARRAY_TYPE(dynamic_settings_parsers) *parsers;
+       struct dynamic_settings_parsers *parser;
+       unsigned int i, count;
+
+       /* FIXME: currently we assume everyone are under a single parent */
+       t_push();
+       t_array_init(&parents, 4);
+       for (l = config_setting_parsers; l->module_name != NULL; l++) {
+               if (l->root->parent == NULL)
+                       continue;
+
+               for (d = l->root->parent->defines; d->key != NULL; d++) {
+                       if (d->list_info == l->root)
+                               break;
+               }
+
+               if (d->key == NULL) {
+                       parsers = array_get_modifiable(&parents, &count);
+                       for (i = 0; i < count; i++) {
+                               parser = array_idx_modifiable(&parsers[i], 0);
+                               if (parser->info->parent == l->root->parent)
+                                       break;
+                       }
+                       if (i == count) {
+                               parsers = array_append_space(&parents);
+                               t_array_init(parsers, 16);
+                       }
+
+                       parser = array_append_space(parsers);
+                       parser->name = l->module_name;
+                       parser->info = l->root;
+               }
+       }
+
+       parsers = array_get_modifiable(&parents, &count);
+       for (i = 0; i < count; i++) {
+               (void)array_append_space(&parsers[i]); /* NULL-terminate */
+               parser = array_idx_modifiable(&parsers[i], 0);
+
+               settings_parser_info_update(pool, parser->info->parent, parser);
+       }
+
+       t_pop();
+#endif
+}
+
+static const char *
+config_parse_line(pool_t pool, const char *key, const char *line,
+                 const struct setting_parser_info **info_r)
+{
+       enum settings_parser_flags parser_flags =
+                SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS;
+       struct config_setting_parser_list *l;
+       bool found = FALSE;
+       int ret;
+
+       *info_r = NULL;
+       for (l = config_setting_parsers; l->module_name != NULL; l++) {
+               if (l->parser == NULL) {
+                       l->parser = settings_parser_init(pool, l->root,
+                                                        parser_flags);
+               }
+
+               ret = settings_parse_line(l->parser, line);
+               if (ret > 0) {
+                       found = TRUE;
+                       *info_r = settings_parse_get_prev_info(l->parser);
+               } else if (ret < 0)
+                       return settings_parser_get_error(l->parser);
+       }
+
+       return found ? NULL : t_strconcat("Unknown setting: ", key, NULL);
+}
+
+struct settings_export_context {
+       string_t *dest;
+       string_t *value;
+       string_t *prefix;
+       struct hash_table *keys;
+       pool_t pool;
+       bool export_defaults;
+};
+
+static void settings_export(struct settings_export_context *ctx,
+                           const struct setting_parser_info *info,
+                           const void *set)
+{
+       const struct setting_define *def;
+       const void *value, *default_value;
+       void *const *children = NULL;
+       unsigned int i, count, prefix_len;
+       char *key;
+
+       for (def = info->defines; def->key != NULL; def++) {
+               value = CONST_PTR_OFFSET(set, def->offset);
+               default_value = info->defaults == NULL ? NULL :
+                       CONST_PTR_OFFSET(info->defaults, def->offset);
+
+               count = 0;
+               str_truncate(ctx->value, 0);
+               switch (def->type) {
+               case SET_INTERNAL:
+                       break;
+               case SET_BOOL: {
+                       const bool *val = value, *dval = default_value;
+                       if (ctx->export_defaults ||
+                           dval == NULL || *val != *dval) {
+                               str_append(ctx->value,
+                                          *val ? "yes" : "no");
+                       }
+                       break;
+               }
+               case SET_UINT: {
+                       const unsigned int *val = value, *dval = default_value;
+                       if (ctx->export_defaults ||
+                           dval == NULL || *val != *dval)
+                               str_printfa(ctx->value, "%u", *val);
+                       break;
+               }
+               case SET_STR_VARS: {
+                       const char *const *val = value, *sval;
+                       const char *const *_dval = default_value;
+                       const char *dval = _dval == NULL ? NULL : *_dval;
+
+                       i_assert(*val == NULL ||
+                                **val == SETTING_STRVAR_UNEXPANDED[0]);
+
+                       sval = *val == NULL ? NULL : (*val + 1);
+                       if ((ctx->export_defaults ||
+                            null_strcmp(sval, dval) != 0) && sval != NULL)
+                               str_append(ctx->value, sval);
+                       break;
+               }
+               case SET_STR: {
+                       const char *const *val = value;
+                       const char *const *_dval = default_value;
+                       const char *dval = _dval == NULL ? NULL : *_dval;
+
+                       if ((ctx->export_defaults ||
+                            null_strcmp(*val, dval) != 0) && *val != NULL)
+                               str_append(ctx->value, *val);
+                       break;
+               }
+               case SET_ENUM: {
+                       const char *const *val = value;
+                       const char *const *_dval = default_value;
+                       const char *dval = _dval == NULL ? NULL : *_dval;
+                       unsigned int len = strlen(*val);
+
+                       if (ctx->export_defaults ||
+                           strncmp(*val, dval, len) != 0 ||
+                           ((*val)[len] != ':' && (*val)[len] != '\0'))
+                               str_append(ctx->value, *val);
+                       break;
+               }
+               case SET_DEFLIST: {
+                       const ARRAY_TYPE(void_array) *val = value;
+
+                       if (!array_is_created(val))
+                               break;
+
+                       children = array_get(val, &count);
+                       for (i = 0; i < count; i++) {
+                               if (i > 0)
+                                       str_append_c(ctx->value, ' ');
+                               str_printfa(ctx->value, "%u", i);
+                       }
+                       break;
+               }
+               case SET_STRLIST: {
+                       const ARRAY_TYPE(const_string) *val = value;
+                       unsigned int pos = str_len(ctx->dest);
+                       const char *const *strings;
+
+                       if (!array_is_created(val))
+                               break;
+
+                       str_append_str(ctx->dest, ctx->prefix);
+                       str_append(ctx->dest, def->key);
+                       str_append(ctx->dest, "=0\n");
+
+                       if (hash_table_lookup(ctx->keys,
+                                             str_c(ctx->dest) + pos) != NULL) {
+                               /* already added all of these */
+                               str_truncate(ctx->dest, pos);
+                               break;
+                       }
+                       key = p_strdup(ctx->pool, str_c(ctx->dest) + pos);
+                       hash_table_insert(ctx->keys, key, key);
+
+                       strings = array_get(val, &count);
+                       i_assert(count % 2 == 0);
+                       for (i = 0; i < count; i += 2) {
+                               str_append_str(ctx->dest, ctx->prefix);
+                               str_append(ctx->dest, def->key);
+                               str_append_c(ctx->dest, SETTINGS_SEPARATOR);
+                               str_append_c(ctx->dest, '0');
+                               str_append_c(ctx->dest, SETTINGS_SEPARATOR);
+                               str_append(ctx->dest, strings[i+0]);
+                               str_append_c(ctx->dest, '=');
+                               str_append(ctx->dest, strings[i+1]);
+                               str_append_c(ctx->dest, '\n');
+                       }
+                       count = 0;
+                       break;
+               }
+               }
+               if (str_len(ctx->value) > 0) {
+                       unsigned int pos = str_len(ctx->dest);
+                       str_append_str(ctx->dest, ctx->prefix);
+                       str_append(ctx->dest, def->key);
+
+                       if (hash_table_lookup(ctx->keys,
+                                             str_c(ctx->dest) + pos) != NULL) {
+                               /* already exists */
+                               str_truncate(ctx->dest, pos);
+                       } else {
+                               str_append_c(ctx->dest, '=');
+                               str_append_str(ctx->dest, ctx->value);
+                               str_append_c(ctx->dest, '\n');
+                               key = p_strconcat(ctx->pool, str_c(ctx->prefix),
+                                                 def->key, NULL);
+                               hash_table_insert(ctx->keys, key, key);
+                       }
+               }
+
+               prefix_len = str_len(ctx->prefix);
+               for (i = 0; i < count; i++) {
+                       str_append(ctx->prefix, def->key);
+                       str_append_c(ctx->prefix, SETTINGS_SEPARATOR);
+                       str_printfa(ctx->prefix, "%u", i);
+                       str_append_c(ctx->prefix, SETTINGS_SEPARATOR);
+                       settings_export(ctx, def->list_info, children[i]);
+
+                       str_truncate(ctx->prefix, prefix_len);
+               }
+       }
+}
+
+static void config_export(string_t *dest)
+{
+       struct config_setting_parser_list *l;
+       struct settings_export_context ctx;
+       const void *set;
+
+       memset(&ctx, 0, sizeof(ctx));
+       ctx.dest = dest;
+       ctx.export_defaults = FALSE;
+       ctx.value = t_str_new(256);
+       ctx.prefix = t_str_new(64);
+       ctx.pool = pool_alloconly_create("config keys", 10240);
+       ctx.keys = hash_table_create(default_pool, ctx.pool, 0,
+                                    str_hash, (hash_cmp_callback_t *)strcmp);
+
+       for (l = config_setting_parsers; l->module_name != NULL; l++) {
+               if (l->parser != NULL) {
+                       set = settings_parser_get(l->parser);
+                       settings_export(&ctx, l->root, set);
+               }
+       }
+       hash_table_destroy(&ctx.keys);
+       pool_unref(&ctx.pool);
+}
+
+static const char *info_type_name_find(const struct setting_parser_info *info)
+{
+       unsigned int i;
+
+       for (i = 0; info->defines[i].key != NULL; i++) {
+               if (info->defines[i].offset == info->type_offset)
+                       return info->defines[i].key;
+       }
+       i_panic("setting parser: Invalid type_offset value");
+       return NULL;
+}
+
+void config_parse_file(string_t *dest, const char *path, const char *service)
+{
+       ARRAY_DEFINE(pathlen_stack, unsigned int);
+       ARRAY_TYPE(const_string) auth_defaults;
+       const struct setting_parser_info *info;
+       unsigned int pathlen = 0;
+       unsigned int counter = 0, auth_counter = 0, cur_counter;
+       struct istream *input;
+       const char *errormsg, *name, *type_name;
+       char *line, *key, *p;
+       int fd, linenum, ret, ignore;
+       string_t *str, *full_line;
+       size_t len;
+       pool_t pool;
+       bool asis;
+
+       pool = pool_alloconly_create("config file parser", 10240);
+
+       fd = open(path, O_RDONLY);
+       if (fd < 0)
+               i_fatal("open(%s) failed: %m", path);
+
+       t_array_init(&pathlen_stack, 10);
+       t_array_init(&auth_defaults, 32);
+
+       errormsg = config_parse_line(pool, "0", "auth=0", &info);
+       i_assert(errormsg == NULL);
+
+       str = t_str_new(256);
+       full_line = t_str_new(512);
+       linenum = 0; errormsg = NULL; ignore = 0; asis = FALSE;
+       input = i_stream_create_fd(fd, (size_t)-1, FALSE);
+       while ((line = i_stream_read_next_line(input)) != NULL) {
+               linenum++;
+
+               /* @UNSAFE: line is modified */
+
+               /* skip whitespace */
+               while (IS_WHITE(*line))
+                       line++;
+
+               /* ignore comments or empty lines */
+               if (*line == '#' || *line == '\0')
+                       continue;
+
+               /* strip away comments. pretty kludgy way really.. */
+               for (p = line; *p != '\0'; p++) {
+                       if (*p == '\'' || *p == '"') {
+                               char quote = *p;
+                               for (p++; *p != quote && *p != '\0'; p++) {
+                                       if (*p == '\\' && p[1] != '\0')
+                                               p++;
+                               }
+                               if (*p == '\0')
+                                       break;
+                       } else if (*p == '#') {
+                               *p = '\0';
+                               break;
+                       }
+               }
+
+               /* remove whitespace from end of line */
+               len = strlen(line);
+               while (IS_WHITE(line[len-1]))
+                       len--;
+               line[len] = '\0';
+
+               if (len > 0 && line[len-1] == '\\') {
+                       /* continues in next line */
+                       line[len-1] = '\0';
+                       str_append(full_line, line);
+                       continue;
+               }
+               if (str_len(full_line) > 0) {
+                       str_append(full_line, line);
+                       line = str_c_modifiable(full_line);
+               }
+
+               /* a) key = value
+                  b) section_type [section_name] {
+                  c) } */
+               key = line;
+               while (!IS_WHITE(*line) && *line != '\0' && *line != '=')
+                       line++;
+               if (IS_WHITE(*line)) {
+                       *line++ = '\0';
+                       while (IS_WHITE(*line)) line++;
+               }
+
+               ret = 1;
+               if (*line == '=') {
+                       /* a) */
+                       *line++ = '\0';
+                       while (IS_WHITE(*line)) line++;
+
+                       len = strlen(line);
+                       if (len > 0 &&
+                           ((*line == '"' && line[len-1] == '"') ||
+                            (*line == '\'' && line[len-1] == '\''))) {
+                               line[len-1] = '\0';
+                               line = str_unescape(line+1);
+                       }
+
+                       str_truncate(str, pathlen);
+                       str_append(str, key);
+                       str_append_c(str, '=');
+                       str_append(str, line);
+                       if (ignore > 0) {
+                               /* ignore this setting */
+                       } else if (pathlen == 0 &&
+                                  strncmp(str_c(str), "auth_", 5) == 0) {
+                               /* verify that the setting is valid,
+                                  but delay actually adding it */
+                               const char *s = t_strdup(str_c(str) + 5);
+
+                               str_truncate(str, 0);
+                               str_printfa(str, "auth/0/%s=%s", key + 5, line);
+                               errormsg = config_parse_line(pool, key + 5, str_c(str), &info);
+                               array_append(&auth_defaults, &s, 1);
+                       } else if (asis) {
+                               /* don't do any parsing, just add it */
+                               str_append(dest, str_c(str));
+                               str_append_c(dest, '\n');
+                       } else {
+                               errormsg = config_parse_line(pool, key, str_c(str), &info);
+                       }
+               } else if (strcmp(key, "}") != 0 || *line != '\0') {
+                       /* b) + errors */
+                       line[-1] = '\0';
+
+                       if (*line == '{')
+                               name = "";
+                       else {
+                               name = line;
+                               while (!IS_WHITE(*line) && *line != '\0')
+                                       line++;
+
+                               if (*line != '\0') {
+                                       *line++ = '\0';
+                                       while (IS_WHITE(*line))
+                                               line++;
+                               }
+                       }
+
+                       if (*line != '{')
+                               errormsg = "Expecting '='";
+                       else if (ignore > 0) {
+                               ignore++;
+                       } else if (strcmp(key, "protocol") == 0) {
+                               array_append(&pathlen_stack, &pathlen, 1);
+                               ignore = strcmp(name, service) != 0;
+                       } else {
+                               array_append(&pathlen_stack, &pathlen, 1);
+
+                               str_truncate(str, pathlen);
+                               str_append(str, key);
+                               pathlen = str_len(str);
+
+                               if (strcmp(key, "auth") == 0)
+                                       cur_counter = auth_counter++;
+                               else
+                                       cur_counter = counter++;
+
+                               str_append_c(str, '=');
+                               str_printfa(str, "%u", cur_counter);
+                               if (cur_counter == 0 && strcmp(key, "auth") == 0) {
+                                       /* already added this */
+                               } else {
+                                       errormsg = config_parse_line(pool, key,
+                                                                    str_c(str), &info);
+                               }
+
+                               str_truncate(str, pathlen);
+                               str_append_c(str, SETTINGS_SEPARATOR);
+                               str_printfa(str, "%u", cur_counter);
+                               str_append_c(str, SETTINGS_SEPARATOR);
+                               pathlen = str_len(str);
+
+                               if (errormsg == NULL && info->type_offset != (size_t)-1) {
+                                       type_name = info_type_name_find(info);
+                                       str_append(str, type_name);
+                                       str_append_c(str, '=');
+                                       str_append(str, name);
+                                       errormsg = config_parse_line(pool, type_name,
+                                                                    str_c(str), &info);
+
+                                       str_truncate(str, pathlen);
+                               }
+
+                               if (strcmp(key, "auth") == 0 && errormsg == NULL) {
+                                       /* add auth default settings */
+                                       const char *const *lines;
+                                       unsigned int i, count;
+
+                                       lines = array_get(&auth_defaults, &count);
+                                       for (i = 0; i < count; i++) {
+                                               str_truncate(str, pathlen);
+
+                                               p = strchr(lines[i], '=');
+                                               str_append(str, lines[i]);
+
+                                               errormsg = config_parse_line(pool, t_strdup_until(lines[i], p), str_c(str), &info);
+                                               i_assert(errormsg == NULL);
+                                       }
+                               }
+                       }
+               } else {
+                       /* c) */
+                       unsigned int pathlen_count;
+                       const unsigned int *arr;
+
+                       if (ignore > 0)
+                               ignore--;
+                       asis = FALSE;
+
+                       arr = array_get(&pathlen_stack, &pathlen_count);
+                       if (pathlen_count == 0)
+                               errormsg = "Unexpected '}'";
+                       else {
+                               pathlen = arr[pathlen_count - 1];
+                               array_delete(&pathlen_stack,
+                                            pathlen_count - 1, 1);
+                       }
+               }
+
+               if (errormsg != NULL) {
+                       i_fatal("Error in configuration file %s line %d: %s",
+                               path, linenum, errormsg);
+                       break;
+               }
+               str_truncate(full_line, 0);
+       }
+       i_stream_unref(&input);
+       config_export(dest);
+}
diff --git a/src/config/config-parser.h b/src/config/config-parser.h
new file mode 100644 (file)
index 0000000..fe807c1
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __CONFIG_PARSER_H
+#define __CONFIG_PARSER_H
+
+void config_parsers_fix_parents(pool_t pool);
+
+void config_parse_file(string_t *dest, const char *path, const char *service);
+
+#endif
diff --git a/src/config/main.c b/src/config/main.c
new file mode 100644 (file)
index 0000000..4ceefef
--- /dev/null
@@ -0,0 +1,69 @@
+/* Copyright (C) 2005-2008 Timo Sirainen */
+
+#include "common.h"
+#include "lib-signals.h"
+#include "ioloop.h"
+#include "str.h"
+#include "config-connection.h"
+#include "config-parser.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+string_t *config_string;
+pool_t parsers_pool;
+
+static const char *config_path = SYSCONFDIR "/" PACKAGE ".conf";
+
+static void main_init(const char *service)
+{
+       i_set_failure_internal();
+
+       parsers_pool = pool_alloconly_create("parent parsers", 2048);
+       config_parsers_fix_parents(parsers_pool);
+
+       config_string = str_new(default_pool, 10240);
+       config_parse_file(config_string, config_path, service);
+       str_append_c(config_string, '\n');
+}
+
+int main(int argc, char *argv[])
+{
+       struct ioloop *ioloop;
+       const char *path, *service = "";
+       bool dump_nondefaults = FALSE, human_readable = FALSE;
+       int c;
+
+       lib_init();
+
+       path = getenv("CONFIG_FILE_PATH");
+       if (path != NULL)
+               config_path = path;
+
+       while ((c = getopt(argc, argv, "c:s:na")) > 0) {
+               switch (c) {
+               case 'c':
+                       config_path = optarg;
+                       break;
+               case 's':
+                       service = optarg;
+                       break;
+               case 'n':
+                       dump_nondefaults = TRUE;
+                       /* fall through */
+               case 'a':
+                       /* FIXME: make it work */
+                       human_readable = TRUE;
+                       break;
+               default:
+                       i_fatal("Unknown parameter: %c", c);
+               }
+       }
+
+       main_init(service);
+       ioloop = io_loop_create();
+       config_connection_dump_request(STDOUT_FILENO, "master");
+       io_loop_destroy(&ioloop);
+       lib_deinit();
+        return 0;
+}
diff --git a/src/config/settings-get.pl b/src/config/settings-get.pl
new file mode 100755 (executable)
index 0000000..43d97ca
--- /dev/null
@@ -0,0 +1,87 @@
+#!/usr/bin/env perl
+use strict;
+
+print '#include "lib.h"'."\n";
+print '#include "settings-parser.h"'."\n";
+print '#include "all-settings.h"'."\n";
+print '#include <stddef.h>'."\n";
+print '#define CONFIG_BINARY'."\n";
+
+my %parsers = {};
+
+foreach my $file (@ARGV) {
+  my $f;
+  open($f, $file) || die "Can't open $file: $@";
+  
+  my $state = 0;
+  my $file_contents = "";
+  my $externs = "";
+  
+  while (<$f>) {
+    my $write = 0;
+    if ($state == 0) {
+      if (/struct .*_settings {/ ||
+         /struct setting_define.*{/ ||
+         /struct .*_default_settings = {/) {
+       $state++;
+      } elsif (/^(static )?struct setting_parser_info (.*) = {/) {
+       $state++;
+       $parsers{$2} = 1;
+      } elsif (/^extern struct setting_parser_info (.*);/) {
+       $externs .= "extern struct setting_parser_info $1;\n";
+      }
+
+      if (/#define.*DEF/ || /^#undef.*DEF/) {
+       $write = 1;
+       $state = 2 if (/\\$/);
+      }
+    } elsif ($state == 2) {
+      $write = 1;
+      $state = 0 if (!/\\$/);
+    }
+    
+    if ($state == 1 || $state == 3) {
+      if ($state == 1) {
+       if (/DEFLIST.*".*",(.*)$/) {
+         my $value = $1;
+         if ($value =~ /.*&(.*)\)/) {
+           $parsers{$1} = 0;
+           $externs .= "extern struct setting_parser_info $1;\n";
+         } else {
+           $state = 3;
+         }
+       }
+      } elsif ($state == 3) {
+       if (/.*&(.*)\)/) {
+         $parsers{$1} = 0;
+       }        
+      }
+      
+      $write = 1;
+      if (/};/) {
+       $state = 0;
+      }
+    }
+  
+    $file_contents .= $_ if ($write);
+  }
+  
+  print "/* $file */\n";
+  print $externs;
+  print $file_contents;
+
+  close $f;
+}
+
+print "struct config_setting_parser_list config_setting_parsers[] = {\n";
+foreach my $name (keys %parsers) {
+  next if (!$parsers{$name});
+
+  my $module = "";
+  if ($name =~ /^([^_]*)/) {
+    $module = $1;
+  }
+  print "  { \"$module\", &".$name.", NULL, NULL }, \n";
+}
+print "  { NULL, NULL, NULL, NULL }\n";
+print "};\n";
index 0e79cf5445960a44b7f91baa94c708a887e6bbb4..3694b6a5d5644860e3b2599bde3aad9c9955d579 100644 (file)
@@ -5,6 +5,7 @@ pkglibexec_PROGRAMS = deliver
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
        -I$(top_srcdir)/src/lib-auth \
+       -I$(top_srcdir)/src/lib-settings \
        -I$(top_srcdir)/src/lib-dict \
        -I$(top_srcdir)/src/lib-mail \
        -I$(top_srcdir)/src/lib-imap \
@@ -13,6 +14,7 @@ AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib-storage \
        -I$(top_srcdir)/src/lib-storage/index \
        -I$(top_srcdir)/src/lib-storage/index/raw \
+       -DBINDIR=\""$(bindir)"\" \
        -DSYSCONFDIR=\""$(sysconfdir)"\" \
        -DPKG_RUNDIR=\""$(rundir)"\" \
        -DMODULEDIR=\""$(moduledir)"\"
@@ -28,6 +30,7 @@ unused_objects = \
 libs = \
        $(STORAGE_LIBS) \
        ../lib-dict/libdict.a \
+       ../lib-settings/libsettings.a \
        $(unused_objects)
 
 deliver_LDADD = \
@@ -40,6 +43,7 @@ deliver_DEPENDENCIES = $(libs)
 deliver_SOURCES = \
        auth-client.c \
        deliver.c \
+       deliver-settings.c \
        duplicate.c \
        mail-send.c \
        smtp-client.c
@@ -47,6 +51,7 @@ deliver_SOURCES = \
 headers = \
        auth-client.h \
        deliver.h \
+       deliver-settings.h \
        duplicate.h \
        mail-send.h \
        smtp-client.h
diff --git a/src/deliver/deliver-settings.c b/src/deliver/deliver-settings.c
new file mode 100644 (file)
index 0000000..488028e
--- /dev/null
@@ -0,0 +1,159 @@
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "deliver.h"
+#include "array.h"
+#include "hostpid.h"
+#include "istream.h"
+#include "settings-parser.h"
+#include "mail-storage-settings.h"
+#include "deliver-settings.h"
+
+#include <stddef.h>
+
+#define DOVECOT_CONFIG_BIN_PATH BINDIR"/doveconf"
+
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+       { type, #name, offsetof(struct deliver_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+       { SET_DEFLIST, name, offsetof(struct deliver_settings, field), defines }
+
+static struct setting_define deliver_setting_defines[] = {
+       DEF(SET_STR, base_dir),
+       DEF(SET_STR, log_path),
+       DEF(SET_STR, info_log_path),
+       DEF(SET_STR, log_timestamp),
+       DEF(SET_STR, syslog_facility),
+       DEF(SET_BOOL, version_ignore),
+       DEF(SET_UINT, umask),
+
+       DEF(SET_STR, mail_plugins),
+       DEF(SET_STR, mail_plugin_dir),
+       DEF(SET_STR_VARS, mail_log_prefix),
+
+       DEF(SET_STR, postmaster_address),
+       DEF(SET_STR, hostname),
+       DEF(SET_STR, sendmail_path),
+       DEF(SET_STR, rejection_subject),
+       DEF(SET_STR, rejection_reason),
+       DEF(SET_STR, auth_socket_path),
+       DEF(SET_STR, deliver_log_format),
+       DEF(SET_BOOL, quota_full_tempfail),
+
+       { SET_STRLIST, "plugin", offsetof(struct deliver_settings, plugin_envs), NULL },
+
+       SETTING_DEFINE_LIST_END
+};
+
+static struct deliver_settings deliver_default_settings = {
+       MEMBER(base_dir) PKG_RUNDIR,
+       MEMBER(log_path) "",
+       MEMBER(info_log_path) "",
+       MEMBER(log_timestamp) DEFAULT_FAILURE_STAMP_FORMAT,
+       MEMBER(syslog_facility) "mail",
+       MEMBER(version_ignore) FALSE,
+       MEMBER(umask) 0077,
+
+       MEMBER(mail_plugins) "",
+       MEMBER(mail_plugin_dir) MODULEDIR"/lda",
+       MEMBER(mail_log_prefix) "%Us(%u): ",
+
+       MEMBER(postmaster_address) "",
+       MEMBER(hostname) "",
+       MEMBER(sendmail_path) "/usr/lib/sendmail",
+       MEMBER(rejection_subject) "Rejected: %s",
+       MEMBER(rejection_reason)
+               "Your message to <%t> was automatically rejected:%n%r",
+       MEMBER(auth_socket_path) "auth-master",
+       MEMBER(deliver_log_format) "msgid=%m: %$",
+       MEMBER(quota_full_tempfail) FALSE
+};
+
+struct setting_parser_info deliver_setting_parser_info = {
+       MEMBER(defines) deliver_setting_defines,
+       MEMBER(defaults) &deliver_default_settings,
+
+       MEMBER(parent) NULL,
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) (size_t)-1,
+       MEMBER(struct_size) sizeof(struct deliver_settings)
+};
+
+static pool_t settings_pool = NULL;
+
+static void fix_base_path(struct deliver_settings *set, const char **str)
+{
+       if (*str != NULL && **str != '\0' && **str != '/') {
+               *str = p_strconcat(settings_pool,
+                                  set->base_dir, "/", *str, NULL);
+       }
+}
+
+struct setting_parser_context *
+deliver_settings_read(const char *path,
+                     struct deliver_settings **set_r,
+                     struct mail_user_settings **user_set_r)
+{
+       static const struct setting_parser_info *roots[] = {
+                &deliver_setting_parser_info,
+                &mail_user_setting_parser_info
+       };
+       void **sets;
+       struct deliver_settings *deliver_set;
+       struct setting_parser_context *parser;
+
+       if (settings_pool == NULL)
+               settings_pool = pool_alloconly_create("deliver settings", 1024);
+       else
+               p_clear(settings_pool);
+
+       mail_storage_namespace_defines_init(settings_pool);
+
+       parser = settings_parser_init_list(settings_pool,
+                               roots, N_ELEMENTS(roots),
+                               SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
+       if (settings_parse_exec(parser, DOVECOT_CONFIG_BIN_PATH,
+                               path, "lda") < 0) {
+               i_fatal_status(EX_CONFIG, "Error reading configuration: %s",
+                              settings_parser_get_error(parser));
+       }
+
+       sets = settings_parser_get_list(parser);
+
+       deliver_set = sets[0];
+       if (*deliver_set->hostname == '\0')
+               deliver_set->hostname = my_hostname;
+       fix_base_path(deliver_set, &deliver_set->auth_socket_path);
+
+       if (*deliver_set->postmaster_address == '\0') {
+               i_fatal_status(EX_CONFIG,
+                              "postmaster_address setting not given");
+       }
+
+       *set_r = deliver_set;
+       *user_set_r = sets[1];
+       return parser;
+}
+
+void deliver_settings_add(struct setting_parser_context *parser,
+                         const ARRAY_TYPE(const_string) *extra_fields)
+{
+       const char *const *str, *p, *line;
+       unsigned int i, count;
+
+       str = array_get(extra_fields, &count);
+       for (i = 0; i < count; i++) T_BEGIN {
+               p = strchr(str[i], '=');
+               if (p != NULL)
+                       line = str[i];
+               else
+                       line = t_strconcat(str[i], "=yes", NULL);
+               if (settings_parse_line(parser, str[i]) < 0) {
+                       i_fatal_status(EX_CONFIG,
+                                      "Invalid userdb input '%s': %s", str[i],
+                                      settings_parser_get_error(parser));
+               }
+       } T_END;
+
+}
diff --git a/src/deliver/deliver-settings.h b/src/deliver/deliver-settings.h
new file mode 100644 (file)
index 0000000..33de1ea
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef DELIVER_SETTINGS_H
+#define DELIVER_SETTINGS_H
+
+struct mail_user_settings;
+
+struct deliver_settings {
+       const char *base_dir;
+       const char *log_path;
+       const char *info_log_path;
+       const char *log_timestamp;
+       const char *syslog_facility;
+       bool version_ignore;
+       unsigned int umask;
+
+       const char *mail_plugins;
+       const char *mail_plugin_dir;
+       const char *mail_log_prefix;
+
+       /* deliver: */
+       const char *postmaster_address;
+       const char *hostname;
+       const char *sendmail_path;
+       const char *rejection_subject;
+       const char *rejection_reason;
+       const char *auth_socket_path;
+       const char *deliver_log_format;
+       bool quota_full_tempfail;
+
+       ARRAY_DEFINE(plugin_envs, const char *);
+};
+
+struct setting_parser_context *
+deliver_settings_read(const char *path,
+                     struct deliver_settings **set_r,
+                     struct mail_user_settings **user_set_r);
+void deliver_settings_add(struct setting_parser_context *parser,
+                         const ARRAY_TYPE(const_string) *extra_fields);
+
+#endif
index fb0ac7ec0b9abec3b7b2217e2d86a64f12e8f401..bd7775768d396a74312c3b349bc38805d629a0b7 100644 (file)
@@ -25,6 +25,7 @@
 #include "mail-namespace.h"
 #include "raw-storage.h"
 #include "imap-utf7.h"
+#include "settings-parser.h"
 #include "dict.h"
 #include "auth-client.h"
 #include "mail-send.h"
@@ -56,6 +57,8 @@ static const char *wanted_headers[] = {
 
 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.. */
@@ -66,10 +69,6 @@ static char *explicit_envelope_sender = NULL;
 static struct module *modules;
 static struct ioloop *ioloop;
 
-static pool_t plugin_pool;
-static ARRAY_DEFINE(lda_envs, const char *);
-static ARRAY_DEFINE(plugin_envs, const char *);
-
 static void sig_die(int signo, void *context ATTR_UNUSED)
 {
        /* warn about being killed because of some signal, except SIGINT (^C)
@@ -135,7 +134,7 @@ static void deliver_log(struct mail *mail, const char *fmt, ...)
        msg = t_strdup_vprintf(fmt, args);
 
        str = t_str_new(256);
-       var_expand(str, deliver_set->log_format,
+       var_expand(str, deliver_set->deliver_log_format,
                   get_log_var_expand_table(mail, msg));
        i_info("%s", str_c(str));
        va_end(args);
@@ -173,7 +172,7 @@ mailbox_open_or_create_synced(struct mail_namespace *namespaces,
        }
 
        box = mailbox_open(storage_r, name, NULL, open_flags);
-       if (box != NULL || !deliver_set->mailbox_autocreate)
+       if (box != NULL || !mailbox_autocreate)
                return box;
 
        (void)mail_storage_get_last_error(*storage_r, &error);
@@ -183,7 +182,7 @@ mailbox_open_or_create_synced(struct mail_namespace *namespaces,
        /* try creating it. */
        if (mail_storage_mailbox_create(*storage_r, name, FALSE) < 0)
                return NULL;
-       if (deliver_set->mailbox_autosubscribe) {
+       if (mailbox_autosubscribe) {
                /* (try to) subscribe to it */
                (void)mailbox_list_set_subscribed(ns->list, name, TRUE);
        }
@@ -276,294 +275,6 @@ const char *deliver_get_new_message_id(void)
                               count++, deliver_set->hostname);
 }
 
-#include "settings.h"
-#include "../master/master-settings.h"
-#include "../master/master-settings-defs.c"
-
-#define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
-
-static bool setting_is_bool(const char *name)
-{
-       const struct setting_def *def;
-
-       for (def = setting_defs; def->name != NULL; def++) {
-               if (strcmp(def->name, name) == 0)
-                       return def->type == SET_BOOL;
-       }
-       if (strncmp(name, "NAMESPACE_", 10) == 0) {
-               return strstr(name, "_list") != NULL ||
-                       strstr(name, "_inbox") != NULL ||
-                       strstr(name, "_hidden") != NULL ||
-                       strstr(name, "_subscriptions") != NULL;
-       }
-       if (strcmp(name, "quota_full_tempfail") == 0)
-               return TRUE;
-       return FALSE;
-}
-
-/* more ugly kludging because we have our own config parsing code.
-   hopefully this goes away in v1.2. */
-static struct {
-       const char *name;
-       bool set;
-} default_yes_settings[] = {
-       { "dotlock_use_excl", TRUE },
-       { "maildir_copy_with_hardlinks", TRUE },
-       { "mbox_dirty_syncs", TRUE },
-       { "mbox_lazy_writes", TRUE }
-};
-
-static void config_file_init(const char *path)
-{
-       struct istream *input;
-       const char *key, *value, *str, *ukey;
-       char *line, *p, quote;
-       int fd, sections = 0;
-       bool lda_section = FALSE, pop3_section = FALSE, plugin_section = FALSE;
-       bool ns_section = FALSE, ns_location = FALSE, ns_list = FALSE;
-       bool ns_subscriptions = FALSE;
-       unsigned int i, ns_idx = 0;
-       size_t len;
-
-       plugin_pool = pool_alloconly_create("Plugin strings", 512);
-       i_array_init(&lda_envs, 16);
-       i_array_init(&plugin_envs, 16);
-
-       fd = open(path, O_RDONLY);
-       if (fd < 0)
-               i_fatal_status(EX_CONFIG, "open(%s) failed: %m", path);
-
-       input = i_stream_create_fd(fd, 1024, TRUE);
-       i_stream_set_return_partial_line(input, TRUE);
-       while ((line = i_stream_read_next_line(input)) != NULL) {
-               /* @UNSAFE: line is modified */
-
-               /* skip whitespace */
-               while (IS_WHITE(*line))
-                       line++;
-
-               /* ignore comments or empty lines */
-               if (*line == '#' || *line == '\0')
-                       continue;
-
-               /* strip away comments. pretty kludgy way really.. */
-               for (p = line; *p != '\0'; p++) {
-                       if (*p == '\'' || *p == '"') {
-                               quote = *p;
-                               for (p++; *p != quote && *p != '\0'; p++) {
-                                       if (*p == '\\' && p[1] != '\0')
-                                               p++;
-                               }
-                               if (*p == '\0')
-                                       break;
-                       } else if (*p == '#') {
-                               *p = '\0';
-                               break;
-                       }
-               }
-
-               /* remove whitespace from end of line */
-               len = strlen(line);
-               while (IS_WHITE(line[len-1]))
-                       len--;
-               line[len] = '\0';
-
-               if (strncmp(line, "!include_try ", 13) == 0)
-                       continue;
-               if (strncmp(line, "!include ", 9) == 0) {
-                       i_fatal_status(EX_CONFIG, "Error in config file %s: "
-                                      "deliver doesn't support !include directive", path);
-               }
-
-               value = p = strchr(line, '=');
-               if (value == NULL) {
-                       if (strchr(line, '{') != NULL) {
-                               if (strcmp(line, "protocol lda {") == 0)
-                                       lda_section = TRUE;
-                               else if (strcmp(line, "plugin {") == 0)
-                                       plugin_section = TRUE;
-                               else if (strcmp(line, "protocol pop3 {") == 0)
-                                       pop3_section = TRUE;
-                               else if (strncmp(line, "namespace ", 10) == 0) {
-                                       ns_section = TRUE;
-                                       ns_idx++;
-                                       line += 10;
-                                       env_put(t_strdup_printf(
-                                               "NAMESPACE_%u_TYPE=%s", ns_idx,
-                                               t_strcut(line, ' ')));
-                               }
-                               sections++;
-                       }
-                       if (*line == '}') {
-                               sections--;
-                               lda_section = FALSE;
-                               plugin_section = FALSE;
-                               pop3_section = FALSE;
-                               if (ns_section) {
-                                       ns_section = FALSE;
-                                       if (ns_location)
-                                               ns_location = FALSE;
-                                       else {
-                                               env_put(t_strdup_printf(
-                                                       "NAMESPACE_%u=", ns_idx));
-                                       }
-                                       if (ns_list)
-                                               ns_list = FALSE;
-                                       else {
-                                               env_put(t_strdup_printf(
-                                                       "NAMESPACE_%u_LIST=1", ns_idx));
-                                       }
-                                       if (ns_subscriptions)
-                                               ns_subscriptions = FALSE;
-                                       else {
-                                               env_put(t_strdup_printf(
-                                                       "NAMESPACE_%u_SUBSCRIPTIONS=1",
-                                                       ns_idx));
-                                       }
-                               }
-                       }
-                       continue;
-               }
-
-               while (p > line && IS_WHITE(p[-1])) p--;
-               key = t_strdup_until(line, p);
-
-               if (sections > 0 && !lda_section && !plugin_section) {
-                       if (pop3_section) {
-                               if (strcmp(key, "pop3_uidl_format") != 0)
-                                       continue;
-                       } else if (ns_section) {
-                               if (strcmp(key, "separator") == 0) {
-                                       key = t_strdup_printf(
-                                               "NAMESPACE_%u_SEP", ns_idx);
-                               } else if (strcmp(key, "location") == 0) {
-                                       ns_location = TRUE;
-                                       key = t_strdup_printf("NAMESPACE_%u",
-                                                             ns_idx);
-                               } else {
-                                       if (strcmp(key, "list") == 0)
-                                               ns_list = TRUE;
-                                       if (strcmp(key, "subscriptions") == 0)
-                                               ns_subscriptions = TRUE;
-                                       key = t_strdup_printf("NAMESPACE_%u_%s",
-                                                             ns_idx, key);
-                               }
-                       } else {
-                               /* unwanted section */
-                               continue;
-                       }
-               }
-
-               do {
-                       value++;
-               } while (IS_WHITE(*value));
-
-               len = strlen(value);
-               if (len > 0 &&
-                   ((*value == '"' && value[len-1] == '"') ||
-                    (*value == '\'' && value[len-1] == '\''))) {
-                       value = str_unescape(p_strndup(unsafe_data_stack_pool,
-                                                      value+1, len - 2));
-               }
-               ukey = t_str_ucase(key);
-               if (setting_is_bool(key) && strcasecmp(value, "yes") != 0) {
-                       for (i = 0; i < N_ELEMENTS(default_yes_settings); i++) {
-                               if (strcmp(default_yes_settings[i].name,
-                                          key) == 0)
-                                       default_yes_settings[i].set = FALSE;
-                       }
-                       env_remove(ukey);
-                       continue;
-               }
-
-               if (lda_section) {
-                       str = p_strconcat(plugin_pool, ukey, "=", value, NULL);
-                       array_append(&lda_envs, &str, 1);
-               }
-               if (!plugin_section) {
-                       env_put(t_strconcat(ukey, "=", value, NULL));
-               } else {
-                       /* %variables need to be expanded.
-                          store these for later. */
-                       value = p_strconcat(plugin_pool,
-                                           ukey, "=", value, NULL);
-                       array_append(&plugin_envs, &value, 1);
-               }
-       }
-       i_stream_unref(&input);
-
-       for (i = 0; i < N_ELEMENTS(default_yes_settings); i++) {
-               if (default_yes_settings[i].set) {
-                       key = default_yes_settings[i].name;
-                       env_put(t_strconcat(t_str_ucase(key), "=1", NULL));
-               }
-       }
-}
-
-static const struct var_expand_table *
-get_var_expand_table(const char *user, const char *home)
-{
-       static struct var_expand_table static_tab[] = {
-               { 'u', NULL, "user" },
-               { 'n', NULL, "username" },
-               { 'd', NULL, "domain" },
-               { 's', NULL, "service" },
-               { 'h', NULL, "home" },
-               { 'l', NULL, "lip" },
-               { 'r', NULL, "rip" },
-               { 'p', NULL, "pid" },
-               { 'i', NULL, "uid" },
-               { '\0', NULL, NULL }
-       };
-       struct var_expand_table *tab;
-
-       tab = t_malloc(sizeof(static_tab));
-       memcpy(tab, static_tab, sizeof(static_tab));
-
-       tab[0].value = user;
-       tab[1].value = t_strcut(user, '@');
-       tab[2].value = strchr(user, '@');
-       if (tab[2].value != NULL) tab[2].value++;
-       tab[3].value = "DELIVER";
-       tab[4].value = home != NULL ? home :
-               "/HOME_DIRECTORY_USED_BUT_NOT_GIVEN_BY_USERDB";
-       tab[5].value = NULL;
-       tab[6].value = NULL;
-       tab[7].value = my_pid;
-       tab[8].value = dec2str(geteuid());
-
-       return tab;
-}
-
-static const char *
-expand_mail_env(const char *env, const struct var_expand_table *table)
-{
-       string_t *str;
-       const char *p;
-
-       str = t_str_new(256);
-
-       /* it's either type:data or just data */
-       p = strchr(env, ':');
-       if (p != NULL) {
-               while (env != p) {
-                       str_append_c(str, *env);
-                       env++;
-               }
-
-               str_append_c(str, *env++);
-       }
-
-       if (env[0] == '~' && env[1] == '/') {
-               /* expand home */
-               env = t_strconcat("%h", env+1, NULL);
-       }
-
-       /* expand %vars */
-       var_expand(str, env, table);
-       return str_c(str);
-}
-
 static const char *escape_local_part(const char *local_part)
 {
        const char *p;
@@ -685,15 +396,15 @@ static void failure_exit_callback(int *status)
 
 static void open_logfile(const char *username)
 {
-       const char *prefix, *log_path, *stamp;
+       const char *prefix, *log_path;
 
        prefix = t_strdup_printf("deliver(%s): ", username);
-       log_path = home_expand(getenv("LOG_PATH"));
-       if (log_path == NULL || *log_path == '\0') {
-               const char *env = getenv("SYSLOG_FACILITY");
+       log_path = home_expand(deliver_set->log_path);
+       if (*log_path == '\0') {
                int facility;
 
-               if (env == NULL || !syslog_facility_find(env, &facility))
+               if (!syslog_facility_find(deliver_set->syslog_facility,
+                                         &facility))
                        facility = LOG_MAIL;
                i_set_failure_prefix(prefix);
                i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
@@ -702,14 +413,11 @@ static void open_logfile(const char *username)
                i_set_failure_file(log_path, prefix);
        }
 
-       log_path = home_expand(getenv("INFO_LOG_PATH"));
-       if (log_path != NULL && *log_path != '\0')
+       log_path = home_expand(deliver_set->info_log_path);
+       if (*log_path != '\0')
                i_set_info_file(log_path);
 
-       stamp = getenv("LOG_TIMESTAMP");
-       if (stamp == NULL)
-               stamp = DEFAULT_FAILURE_STAMP_FORMAT;
-       i_set_failure_timestamp_format(stamp);
+       i_set_failure_timestamp_format(deliver_set->log_timestamp);
 }
 
 static void print_help(void)
@@ -739,72 +447,20 @@ void deliver_env_clean(bool preserve_home)
        if (home != NULL) env_put(home);
 }
 
-static void expand_envs(const char *user)
-{
-        const struct var_expand_table *table;
-       const char *value, *const *envs, *home, *env_name;
-       unsigned int i, count;
-       string_t *str;
-
-       home = getenv("HOME");
-
-       str = t_str_new(256);
-       table = get_var_expand_table(user, home);
-       envs = array_get(&plugin_envs, &count);
-       for (i = 0; i < count; i++) {
-               str_truncate(str, 0);
-               var_expand(str, envs[i], table);
-               env_put(str_c(str));
-       }
-       /* add LDA envs again to make sure they override plugin settings */
-       envs = array_get(&lda_envs, &count);
-       for (i = 0; i < count; i++)
-               env_put(envs[i]);
-
-       /* get the table again in case plugin envs provided the home
-          directory (yea, kludgy) */
-       if (home == NULL)
-               home = getenv("HOME");
-       table = get_var_expand_table(user, home);
-
-       value = getenv("MAIL_LOCATION");
-       if (value != NULL)
-               value = expand_mail_env(value, table);
-       env_put(t_strconcat("MAIL=", value, NULL));
-
-       for (i = 1;; i++) {
-               env_name = t_strdup_printf("NAMESPACE_%u", i);
-               value = getenv(env_name);
-               if (value == NULL)
-                       break;
-
-               value = expand_mail_env(value, table);
-               env_put(t_strconcat(env_name, "=", value, NULL));
-
-               env_name = t_strdup_printf("NAMESPACE_%u_PREFIX", i);
-               value = getenv(env_name);
-               if (value != NULL) {
-                       str_truncate(str, 0);
-                       var_expand(str, value, table);
-                       env_put(t_strconcat(env_name, "=", str_c(str), NULL));
-               }
-       }
-}
-
-static void putenv_extra_fields(const ARRAY_TYPE(const_string) *extra_fields)
+static void plugin_get_home(void)
 {
-       const char *const *fields;
-       const char *key, *p;
+       const char *const *envs;
        unsigned int i, count;
 
-       fields = array_get(extra_fields, &count);
-       for (i = 0; i < count; i++) {
-               p = strchr(fields[i], '=');
-               if (p == NULL)
-                       env_put(t_strconcat(fields[i], "=1", NULL));
-               else {
-                       key = t_str_ucase(t_strdup_until(fields[i], p));
-                       env_put(t_strconcat(key, p, NULL));
+       /* kludgy. this should be removed some day, but for now don't break
+          existing setups that rely on it. */
+       if (array_is_created(&deliver_set->plugin_envs)) {
+               envs = array_get(&deliver_set->plugin_envs, &count);
+               for (i = 0; i < count; i++) {
+                       if (strncmp(envs[i], "home=", 5) == 0) {
+                               env_put(t_strconcat("HOME=", envs[i]+5, NULL));
+                               break;
+                       }
                }
        }
 }
@@ -813,17 +469,20 @@ int main(int argc, char *argv[])
 {
        const char *config_path = DEFAULT_CONFIG_FILE;
        const char *mailbox = "INBOX";
-       const char *auth_socket;
-       const char *home, *destaddr, *user, *value, *errstr, *path, *orig_user;
+       const char *home, *destaddr, *user, *error, *path, *orig_user;
        ARRAY_TYPE(const_string) extra_fields = ARRAY_INIT;
+       struct setting_parser_context *parser;
        struct mail_user *mail_user, *raw_mail_user;
        struct mail_namespace *raw_ns;
+       struct mail_namespace_settings raw_ns_set;
        struct mail_storage *storage;
        struct mailbox *box;
        struct raw_mailbox *raw_box;
        struct istream *input;
        struct mailbox_transaction_context *t;
        struct mailbox_header_lookup_ctx *headers_ctx;
+       struct mail_user_settings *user_set;
+       const struct mail_storage_settings *mail_set;
        struct mail *mail;
        uid_t process_euid;
        bool stderr_rejection = FALSE;
@@ -867,7 +526,7 @@ int main(int argc, char *argv[])
 #endif
 
        deliver_set = i_new(struct deliver_settings, 1);
-       deliver_set->mailbox_autocreate = TRUE;
+       mailbox_autocreate = TRUE;
 
        destaddr = user = path = NULL;
        for (i = 1; i < argc; i++) {
@@ -918,9 +577,9 @@ int main(int argc, char *argv[])
                                mailbox = str_c(str);
                        }
                } else if (strcmp(argv[i], "-n") == 0) {
-                       deliver_set->mailbox_autocreate = FALSE;
+                       mailbox_autocreate = FALSE;
                } else if (strcmp(argv[i], "-s") == 0) {
-                       deliver_set->mailbox_autosubscribe = TRUE;
+                       mailbox_autosubscribe = TRUE;
                } else if (strcmp(argv[i], "-f") == 0) {
                        /* envelope sender address */
                        i++;
@@ -964,42 +623,29 @@ int main(int argc, char *argv[])
                        "destination user parameter (-d user) not given");
        }
 
-       T_BEGIN {
-               config_file_init(config_path);
-       } T_END;
-       open_logfile(user);
+        mail_storage_init();
+       mail_storage_register_all();
+       mailbox_list_register_all();
 
-       if (getenv("MAIL_DEBUG") != NULL)
-               env_put("DEBUG=1");
+       parser = deliver_settings_read(config_path, &deliver_set, &user_set);
+       open_logfile(user);
 
-       if (getenv("MAIL_PLUGINS") == NULL)
+       mail_set = mail_user_set_get_driver_settings(user_set, "MAIL");
+       if (deliver_set->mail_plugins == '\0')
                modules = NULL;
        else {
-               const char *plugin_dir = getenv("MAIL_PLUGIN_DIR");
                const char *version;
 
-               if (plugin_dir == NULL)
-                       plugin_dir = MODULEDIR"/lda";
-
-               version = getenv("VERSION_IGNORE") != NULL ?
-                       NULL : PACKAGE_VERSION;
-               modules = module_dir_load(plugin_dir, getenv("MAIL_PLUGINS"),
+               version = deliver_set->version_ignore ? NULL : PACKAGE_VERSION;
+               modules = module_dir_load(deliver_set->mail_plugin_dir,
+                                         deliver_set->mail_plugins,
                                          TRUE, version);
        }
 
        if (user_auth) {
-               auth_socket = getenv("AUTH_SOCKET_PATH");
-               if (auth_socket == NULL) {
-                       const char *base_dir = getenv("BASE_DIR");
-                       if (base_dir == NULL)
-                               base_dir = PKG_RUNDIR;
-                       auth_socket = t_strconcat(base_dir, "/auth-master",
-                                                 NULL);
-               }
-
                userdb_pool = pool_alloconly_create("userdb lookup replys", 512);
                orig_user = user;
-               ret = auth_client_lookup_and_restrict(auth_socket,
+               ret = auth_client_lookup_and_restrict(deliver_set->auth_socket_path,
                                                      &user, process_euid,
                                                      userdb_pool,
                                                      &extra_fields);
@@ -1008,7 +654,7 @@ int main(int argc, char *argv[])
 
                if (strcmp(user, orig_user) != 0) {
                        /* auth lookup changed the user. */
-                       if (getenv("DEBUG") != NULL)
+                       if (mail_set->mail_debug)
                                i_info("userdb changed username to %s", user);
                        i_set_failure_prefix(t_strdup_printf("deliver(%s): ",
                                                             user));
@@ -1018,90 +664,62 @@ int main(int argc, char *argv[])
                user = t_strdup(user);
        }
 
-       expand_envs(user);
        if (userdb_pool != NULL) {
-               putenv_extra_fields(&extra_fields);
+               settings_parse_set_expanded(parser, TRUE);
+               deliver_settings_add(parser, &extra_fields);
                pool_unref(&userdb_pool);
        }
 
-       /* Fix namespaces with empty locations */
-       for (i = 1;; i++) {
-               value = getenv(t_strdup_printf("NAMESPACE_%u", i));
-               if (value == NULL)
-                       break;
-
-               if (*value == '\0') {
-                       env_put(t_strdup_printf("NAMESPACE_%u=%s", i,
-                                               getenv("MAIL")));
-               }
+       home = getenv("HOME");
+       if (home == NULL) {
+               plugin_get_home();
+               home = getenv("HOME");
        }
 
        /* If possible chdir to home directory, so that core file
           could be written in case we crash. */
-       home = getenv("HOME");
        if (home != NULL) {
                if (chdir(home) < 0) {
                        if (errno != ENOENT)
                                i_error("chdir(%s) failed: %m", home);
-                       else if (getenv("DEBUG") != NULL)
+                       else if (mail_set->mail_debug)
                                i_info("Home dir not found: %s", home);
                }
        }
 
        env_put(t_strconcat("USER=", user, NULL));
-
-       value = getenv("UMASK");
-       if (value == NULL || sscanf(value, "%i", &i) != 1 || i < 0)
-               i = 0077;
-       (void)umask(i);
-
-       deliver_set->hostname = getenv("HOSTNAME");
-       if (deliver_set->hostname == NULL)
-               deliver_set->hostname = my_hostname;
-       deliver_set->postmaster_address = getenv("POSTMASTER_ADDRESS");
-       if (deliver_set->postmaster_address == NULL) {
-               i_fatal_status(EX_CONFIG,
-                              "postmaster_address setting not given");
-       }
-       deliver_set->sendmail_path = getenv("SENDMAIL_PATH");
-       if (deliver_set->sendmail_path == NULL)
-               deliver_set->sendmail_path = DEFAULT_SENDMAIL_PATH;
-       deliver_set->rejection_subject = getenv("REJECTION_SUBJECT");
-       if (deliver_set->rejection_subject == NULL)
-               deliver_set->rejection_subject = DEFAULT_MAIL_REJECTION_SUBJECT;
-       deliver_set->rejection_reason = getenv("REJECTION_REASON");
-       if (deliver_set->rejection_reason == NULL) {
-               deliver_set->rejection_reason =
-                       DEFAULT_MAIL_REJECTION_HUMAN_REASON;
-       }
-       deliver_set->log_format = getenv("DELIVER_LOG_FORMAT");
-       if (deliver_set->log_format == NULL)
-               deliver_set->log_format = DEFAULT_LOG_FORMAT;
+       (void)umask(deliver_set->umask);
 
        dict_drivers_register_builtin();
         duplicate_init();
-       mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL);
-        mail_storage_init();
-       mail_storage_register_all();
-       mailbox_list_register_all();
+       mail_users_init(deliver_set->auth_socket_path, mail_set->mail_debug);
 
        module_dir_init(modules);
 
-       mail_user = mail_user_init(user);
+       mail_user = mail_user_alloc(user, user_set);
        mail_user_set_home(mail_user, home);
-       if (mail_namespaces_init(mail_user) < 0)
-               i_fatal("Namespace initialization failed");
+       mail_user_set_vars(mail_user, geteuid(), "deliver", NULL, NULL);
+       if (mail_user_init(mail_user, &error) < 0)
+               i_fatal("Mail user initialization failed: %s", error);
+       if (mail_namespaces_init(mail_user, &error) < 0)
+               i_fatal("Namespace initialization failed: %s", error);
 
        /* create a separate mail user for the internal namespace */
-       raw_mail_user = mail_user_init(user);
-       mail_user_set_home(raw_mail_user, NULL);
+       raw_mail_user = mail_user_alloc(user, user_set);
+       mail_user_set_home(raw_mail_user, "/");
+       if (mail_user_init(raw_mail_user, &error) < 0)
+               i_fatal("Raw user initialization failed: %s", error);
+
+       settings_parser_deinit(&parser);
+
+       memset(&raw_ns_set, 0, sizeof(raw_ns_set));
+       raw_ns_set.location = "/tmp";
+
        raw_ns = mail_namespaces_init_empty(raw_mail_user);
        raw_ns->flags |= NAMESPACE_FLAG_INTERNAL;
-
-       if (mail_storage_create(raw_ns, "raw", "/tmp",
-                               MAIL_STORAGE_FLAG_FULL_FS_ACCESS,
-                               FILE_LOCK_METHOD_FCNTL, &errstr) < 0)
-               i_fatal("Couldn't create internal raw storage: %s", errstr);
+       raw_ns->set = &raw_ns_set;
+       if (mail_storage_create(raw_ns, "raw", 0, &error) < 0)
+               i_fatal("Couldn't create internal raw storage: %s", error);
        if (path == NULL) {
                input = create_raw_stream(0, &mtime);
                box = mailbox_open(&raw_ns->storage, "Dovecot Delivery Mail",
@@ -1186,7 +804,7 @@ int main(int argc, char *argv[])
                }
 
                if (error != MAIL_ERROR_NOSPACE ||
-                   getenv("QUOTA_FULL_TEMPFAIL") != NULL) {
+                   deliver_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. */
index cffb6ab02ee983fe63d6b9c3a065db051fa545c8..398326c3eb90cfcda56d3d1a09975f25352cdeda 100644 (file)
@@ -9,25 +9,11 @@
 
 #include "lib.h"
 #include "mail-storage.h"
-
-#define DEFAULT_MAIL_REJECTION_SUBJECT \
-       "Rejected: %s"
-#define DEFAULT_MAIL_REJECTION_HUMAN_REASON \
-       "Your message to <%t> was automatically rejected:%n%r"
-#define DEFAULT_LOG_FORMAT "msgid=%m: %$"
-
-struct deliver_settings {
-       const char *hostname;
-       const char *postmaster_address;
-       const char *sendmail_path;
-       const char *rejection_subject;
-       const char *rejection_reason;
-       const char *log_format;
-       bool mailbox_autosubscribe;
-       bool mailbox_autocreate;
-};
+#include "deliver-settings.h"
 
 extern 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,
index 791e45b977743d40711ea2794a5e3f4971ac29a9..0eaf6c2e8722c057fad1aef3c7d002466830e694 100644 (file)
@@ -12,6 +12,7 @@ imap_login_LDADD = \
        ../login-common/liblogin-common.a \
        ../lib-imap/libimap.a \
        ../lib-auth/libauth.a \
+       ../lib-settings/libsettings.a \
        ../lib/liblib.a \
        $(SSL_LIBS)
 
index 4a27d085882beb6ea9a3db7f310d1e0c79827d6d..995b3abe7115c3dc3128813c641a646ed24825a9 100644 (file)
@@ -39,7 +39,7 @@ const char *client_authenticate_get_capabilities(bool secured)
                   c) we allow insecure authentication
                */
                if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
-                   (secured || !disable_plaintext_auth ||
+                   (secured || !login_settings->disable_plaintext_auth ||
                     (mech[i].flags & MECH_SEC_PLAINTEXT) == 0)) {
                        str_append_c(str, ' ');
                        str_append(str, "AUTH=");
@@ -158,7 +158,7 @@ static bool client_handle_args(struct imap_client *client,
                        master_user = *args + 7;
                else if (strncmp(*args, "user=", 5) == 0) {
                        /* already handled in login-common */
-               } else if (auth_debug) {
+               } else if (login_settings->auth_debug) {
                        i_info("Ignoring unknown passdb extra field: %s",
                               *args);
                }
@@ -347,8 +347,9 @@ int cmd_authenticate(struct imap_client *client, const struct imap_arg *args)
                init_resp = IMAP_ARG_STR(&args[1]);
        }
 
-       if (!client->common.secured && ssl_required) {
-               if (verbose_auth) {
+       if (!client->common.secured &&
+           strcmp(login_settings->ssl, "required") == 0) {
+               if (login_settings->verbose_auth) {
                        client_syslog(&client->common, "Login failed: "
                                      "SSL required for authentication");
                }
@@ -381,8 +382,8 @@ int cmd_login(struct imap_client *client, const struct imap_arg *args)
        user = IMAP_ARG_STR(&args[0]);
        pass = IMAP_ARG_STR(&args[1]);
 
-       if (!client->common.secured && disable_plaintext_auth) {
-               if (verbose_auth) {
+       if (!client->common.secured && login_settings->disable_plaintext_auth) {
+               if (login_settings->verbose_auth) {
                        client_syslog(&client->common, "Login failed: "
                                      "Plaintext authentication disabled");
                }
index 3e8a1e8adc38d1b173e8c82d5e06a599cafcfcd6..f70b98d6713713d15916fe391d29c68aeca53e01 100644 (file)
@@ -52,7 +52,8 @@ static void client_set_title(struct imap_client *client)
 {
        const char *addr;
 
-       if (!verbose_proctitle || !process_per_connection)
+       if (!login_settings->verbose_proctitle ||
+           !login_settings->login_process_per_connection)
                return;
 
        addr = net_ip2addr(&client->common.ip);
@@ -99,7 +100,8 @@ static const char *get_capability(struct imap_client *client, bool full)
        return t_strconcat(full ? capability_string : CAPABILITY_BANNER_STRING,
                           (ssl_initialized && !client->common.tls) ?
                           " STARTTLS" : "",
-                          disable_plaintext_auth && !client->common.secured ?
+                          login_settings->disable_plaintext_auth &&
+                          !client->common.secured ?
                           " LOGINDISABLED" : "", auths, NULL);
 }
 
@@ -423,6 +425,7 @@ void client_input(struct imap_client *client)
 
 void client_destroy_oldest(void)
 {
+       unsigned int max_connections = login_settings->login_max_connections;
        struct client *client;
        struct imap_client *destroy_buf[CLIENT_DESTROY_OLDEST_COUNT];
        unsigned int i, destroy_count;
@@ -465,7 +468,7 @@ static void client_send_greeting(struct imap_client *client)
        greet = t_str_new(128);
        str_append(greet, "* OK ");
        str_printfa(greet, "[CAPABILITY %s] ", get_capability(client, FALSE));
-       str_append(greet, greeting);
+       str_append(greet, login_settings->login_greeting);
 
        client_send_line(client, str_c(greet));
        client->greeting_sent = TRUE;
index eda3fa65d38ebdfea4f95d71f7a52d48d175426a..762da254f98a426aa0855b833773077643aad789 100644 (file)
@@ -201,7 +201,7 @@ static int proxy_input_line(struct imap_client *client,
                   be using only Dovecot as their backend :) */
                client_send_tagline(client, line + 2);
 
-               if (verbose_auth) {
+               if (login_settings->verbose_auth) {
                        str = t_str_new(128);
                        str_printfa(str, "proxy(%s): Login failed to %s:%u",
                                    client->common.virtual_user,
index 1bcb1da7bd18266e0594a6380d383e945a101d0d..5f51edb3630338bf599f38cc1d22c45f3a01ca32 100644 (file)
@@ -4,6 +4,7 @@ pkglibexec_PROGRAMS = imap
 
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
+       -I$(top_srcdir)/src/lib-settings \
        -I$(top_srcdir)/src/lib-dict \
        -I$(top_srcdir)/src/lib-mail \
        -I$(top_srcdir)/src/lib-imap \
@@ -21,6 +22,7 @@ unused_objects = \
 libs = \
        $(STORAGE_LIBS) \
        ../lib-dict/libdict.a \
+       ../lib-settings/libsettings.a \
        $(unused_objects)
 
 imap_LDADD = \
@@ -72,6 +74,7 @@ imap_SOURCES = \
        imap-fetch.c \
        imap-fetch-body.c \
        imap-search.c \
+       imap-settings.c \
        imap-sort.c \
        imap-status.c \
        imap-sync.c \
@@ -87,6 +90,7 @@ headers = \
        imap-expunge.h \
        imap-fetch.h \
        imap-search.h \
+       imap-settings.h \
        imap-sort.h \
        imap-status.h \
        imap-sync.h
index d579c7c546fa063cc2f9d73acf2811bc78db88e9..d4a7c3e98865492162d93f55c97c7483c7e70b0a 100644 (file)
@@ -26,7 +26,8 @@ static void client_idle_timeout(struct client *client)
        client_destroy(client, "Disconnected for inactivity");
 }
 
-struct client *client_create(int fd_in, int fd_out, struct mail_user *user)
+struct client *client_create(int fd_in, int fd_out, struct mail_user *user,
+                            const struct imap_settings *set)
 {
        struct client *client;
        struct mail_namespace *ns;
@@ -36,9 +37,11 @@ struct client *client_create(int fd_in, int fd_out, struct mail_user *user)
        net_set_nonblock(fd_out, TRUE);
 
        client = i_new(struct client, 1);
+       client->set = set;
        client->fd_in = fd_in;
        client->fd_out = fd_out;
-       client->input = i_stream_create_fd(fd_in, imap_max_line_length, FALSE);
+       client->input = i_stream_create_fd(fd_in,
+                                          set->imap_max_line_length, FALSE);
        client->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE);
 
        o_stream_set_flush_callback(client->output, client_output, client);
@@ -56,6 +59,11 @@ struct client *client_create(int fd_in, int fd_out, struct mail_user *user)
                                           &mail_storage_callbacks, client);
        }
 
+       client->capability_string =
+               str_new(default_pool, sizeof(CAPABILITY_STRING)+32);
+       str_append(client->capability_string, *set->imap_capability != '\0' ?
+                  set->imap_capability : CAPABILITY_STRING);
+
        i_assert(my_client == NULL);
        my_client = client;
 
@@ -114,7 +122,7 @@ static const char *client_stats(struct client *client)
        tab[1].value = dec2str(client->output->offset);
 
        str = t_str_new(128);
-       var_expand(str, logout_format, tab);
+       var_expand(str, client->set->imap_logout_format, tab);
        return str_c(str);
 }
 
@@ -186,6 +194,7 @@ void client_destroy(struct client *client, const char *reason)
                array_free(&client->search_saved_uidset);
        if (array_is_created(&client->search_updates))
                array_free(&client->search_updates);
+       str_free(&client->capability_string);
        pool_unref(&client->command_pool);
        i_free(client);
 
@@ -431,8 +440,9 @@ client_command_new(struct client *client)
                cmd->parser = client->free_parser;
                client->free_parser = NULL;
        } else {
-               cmd->parser = imap_parser_create(client->input, client->output,
-                                                imap_max_line_length);
+               cmd->parser =
+                       imap_parser_create(client->input, client->output,
+                                          client->set->imap_max_line_length);
        }
 
        DLLIST_PREPEND(&client->command_queue, cmd);
index ab5b245cb7d7dc39206cc183ff72c3ec768e26ae..8a605611326dd2d1af198acb93b257b96fa451a4 100644 (file)
@@ -74,7 +74,11 @@ struct client {
        struct ostream *output;
        struct timeout *to_idle, *to_idle_output;
 
-       struct mail_user *user;
+        const struct imap_settings *set;
+       enum client_workarounds workarounds;
+       string_t *capability_string;
+
+        struct mail_user *user;
        struct mailbox *mailbox;
         struct mailbox_keywords keywords;
        unsigned int select_counter; /* increased when mailbox is changed */
@@ -124,7 +128,8 @@ struct client {
 
 /* Create new client with specified input/output handles. socket specifies
    if the handle is a socket. */
-struct client *client_create(int fd_in, int fd_out, struct mail_user *user);
+struct client *client_create(int fd_in, int fd_out, struct mail_user *user,
+                            const struct imap_settings *set);
 void client_destroy(struct client *client, const char *reason);
 
 /* Disconnect client connection */
index 8eb245a990fa4a596802e68bde992fff219936f8..515b1aaa3815750c9484232821c161e180f4fe04 100644 (file)
@@ -499,7 +499,7 @@ bool cmd_append(struct client_command_context *cmd)
        o_stream_unset_flush_callback(client->output);
 
        ctx->save_parser = imap_parser_create(client->input, client->output,
-                                             imap_max_line_length);
+                                             client->set->imap_max_line_length);
 
        cmd->func = cmd_append_continue_parsing;
        cmd->context = ctx;
index 3351399f3cc25384586144b01bd986c5e47bc894..62fed7c2268d1b6bf508800db74fca4a41b12805 100644 (file)
@@ -6,9 +6,8 @@
 
 bool cmd_capability(struct client_command_context *cmd)
 {
-       client_send_line(cmd->client,
-                        t_strconcat("* CAPABILITY ",
-                                    str_c(capability_string), NULL));
+       client_send_line(cmd->client, t_strconcat(
+               "* CAPABILITY ", str_c(cmd->client->capability_string), NULL));
 
        client_send_tagline(cmd, "OK Capability completed.");
        return TRUE;
index cd6746c9bb0704eab2feef7d685fb5ec49523db6..43edb6d230d25c4a0ace79fa5df161de22b44139 100644 (file)
@@ -36,7 +36,7 @@ bool cmd_delete(struct client_command_context *cmd)
                        return TRUE;
        }
 
-       if ((client_workarounds & WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
+       if ((client->workarounds & WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
            *name != '\0' &&
            name[strlen(name)-1] == mail_storage_get_hierarchy_sep(storage)) {
                /* drop the extra trailing hierarchy separator */
index b7150490cbf38eb8305fc4e3459a66de1acc2a4c..3723ba743a49a588e04210a488f425c9814d2f76 100644 (file)
@@ -5,6 +5,7 @@
 
 bool cmd_id(struct client_command_context *cmd)
 {
+       const struct imap_settings *set = cmd->client->set;
        const struct imap_arg *args;
        const char *value;
 
@@ -13,13 +14,13 @@ bool cmd_id(struct client_command_context *cmd)
 
        if (!cmd->client->id_logged) {
                cmd->client->id_logged = TRUE;
-               value = imap_id_args_get_log_reply(args, imap_id_log);
+               value = imap_id_args_get_log_reply(args, set->imap_id_log);
                if (value != NULL)
                        i_info("ID sent: %s", value);
        }
 
        client_send_line(cmd->client, t_strdup_printf(
-               "* ID %s", imap_id_reply_generate(imap_id_send)));
+               "* ID %s", imap_id_reply_generate(set->imap_id_send)));
        client_send_tagline(cmd, "OK ID completed.");
        return TRUE;
 }
index ce08764e2ad5d34326a91402a0bbf7ad3a7d9253..c8982c197f80350b88f4ebfc583d9f486bbd3849 100644 (file)
@@ -4,12 +4,12 @@
 #include "ioloop.h"
 #include "istream.h"
 #include "ostream.h"
+#include "mail-storage-settings.h"
 #include "commands.h"
 #include "imap-sync.h"
 
 #include <stdlib.h>
 
-#define DEFAULT_IDLE_CHECK_INTERVAL 30
 /* Send some noice to client every few minutes to avoid NATs and stateful
    firewalls from closing the connection */
 #define KEEPALIVE_TIMEOUT (2*60)
@@ -197,8 +197,6 @@ bool cmd_idle(struct client_command_context *cmd)
 {
        struct client *client = cmd->client;
        struct cmd_idle_context *ctx;
-       const char *str;
-       unsigned int interval;
 
        ctx = p_new(cmd->pool, struct cmd_idle_context, 1);
        ctx->cmd = cmd;
@@ -207,13 +205,12 @@ bool cmd_idle(struct client_command_context *cmd)
        ctx->keepalive_to = timeout_add(KEEPALIVE_TIMEOUT * 1000,
                                        keepalive_timeout, ctx);
 
-       str = getenv("MAILBOX_IDLE_CHECK_INTERVAL");
-       interval = str == NULL ? 0 : (unsigned int)strtoul(str, NULL, 10);
-       if (interval == 0)
-               interval = DEFAULT_IDLE_CHECK_INTERVAL;
-
        if (client->mailbox != NULL) {
-               mailbox_notify_changes(client->mailbox, interval,
+               const struct mail_storage_settings *set;
+
+               set = mailbox_get_settings(client->mailbox);
+               mailbox_notify_changes(client->mailbox,
+                                      set->mailbox_idle_check_interval,
                                       idle_callback, ctx);
        }
        client_send_line(client, "+ idling");
index ad565295867e17c1b13803939d81c5a29f97a834..abbb0e9b29af9e6b76968ac80fc3348457e74d0e 100644 (file)
@@ -60,7 +60,7 @@ bool cmd_subscribe_full(struct client_command_context *cmd, bool subscribe)
                mailbox += strlen(ns->prefix);
        }
 
-       if ((client_workarounds & WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
+       if ((cmd->client->workarounds & WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
            *mailbox != '\0' && mailbox[strlen(mailbox)-1] ==
            mail_storage_get_hierarchy_sep(ns->storage)) {
                /* verify the validity without the trailing '/' */
index afea42f9a6494dd0d36eebf71bd6320e201ff11d..e4102c9d794be5afe8fb93e4d9d31cc4a7817daf 100644 (file)
@@ -1,9 +1,6 @@
 #ifndef COMMON_H
 #define COMMON_H
 
-#include "lib.h"
-#include "client.h"
-
 /* Disconnect client after idling this many milliseconds */
 #define CLIENT_IDLE_TIMEOUT_MSECS (60*30*1000)
 
 /* Disconnect client when it sends too many bad commands in a row */
 #define CLIENT_MAX_BAD_COMMANDS 20
 
-/* RFC-2683 recommends at least 8000 bytes. Some clients however don't
-   break large message sets to multiple commands, so we're pretty liberal
-   by default. */
-#define DEFAULT_IMAP_MAX_LINE_LENGTH 65536
-
 enum client_workarounds {
        WORKAROUND_DELAY_NEWMAIL                = 0x01,
        WORKAROUND_NETSCAPE_EOH                 = 0x04,
        WORKAROUND_TB_EXTRA_MAILBOX_SEP         = 0x08
 };
 
-extern struct ioloop *ioloop;
-extern unsigned int imap_max_line_length;
-extern enum client_workarounds client_workarounds;
-extern const char *logout_format;
-extern const char *imap_id_send, *imap_id_log;
+#include "lib.h"
+#include "client.h"
+#include "imap-settings.h"
 
-extern string_t *capability_string;
+extern struct ioloop *ioloop;
 
 extern void (*hook_client_created)(struct client **client);
 
index 44004d91b4ccccae60f2de19a3fe97f36a1e51bd..64a9058914132dea560f578ebfa6b82baa195feb 100644 (file)
@@ -431,7 +431,7 @@ static int fetch_header_partial_from(struct imap_fetch_context *ctx,
        i_stream_seek(ctx->cur_input, old_offset);
 
        if (!ctx->cur_have_eoh &&
-           (client_workarounds & WORKAROUND_NETSCAPE_EOH) != 0) {
+           (ctx->client->workarounds & WORKAROUND_NETSCAPE_EOH) != 0) {
                /* Netscape 4.x doesn't like if end of headers line is
                   missing. */
                msg_size.virtual_size += 2;
diff --git a/src/imap/imap-settings.c b/src/imap/imap-settings.c
new file mode 100644 (file)
index 0000000..a8d20f4
--- /dev/null
@@ -0,0 +1,102 @@
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "mail-storage-settings.h"
+#include "imap-settings.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+       { type, #name, offsetof(struct imap_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+       { SET_DEFLIST, name, offsetof(struct imap_settings, field), defines }
+
+static struct setting_define imap_setting_defines[] = {
+       DEF(SET_BOOL, mail_debug),
+       DEF(SET_BOOL, shutdown_clients),
+       DEF(SET_BOOL, verbose_proctitle),
+
+       DEF(SET_STR, mail_plugins),
+       DEF(SET_STR, mail_plugin_dir),
+       DEF(SET_STR_VARS, mail_log_prefix),
+
+       DEF(SET_UINT, imap_max_line_length),
+       DEF(SET_STR, imap_capability),
+       DEF(SET_STR, imap_client_workarounds),
+       DEF(SET_STR, imap_logout_format),
+       DEF(SET_STR, imap_id_send),
+       DEF(SET_STR, imap_id_log),
+
+       SETTING_DEFINE_LIST_END
+};
+
+static struct imap_settings imap_default_settings = {
+       MEMBER(mail_debug) FALSE,
+       MEMBER(shutdown_clients) FALSE,
+       MEMBER(verbose_proctitle) FALSE,
+
+       MEMBER(mail_plugins) "",
+       MEMBER(mail_plugin_dir) MODULEDIR"/imap",
+       MEMBER(mail_log_prefix) "%Us(%u): ",
+
+       /* RFC-2683 recommends at least 8000 bytes. Some clients however don't
+          break large message sets to multiple commands, so we're pretty
+          liberal by default. */
+       MEMBER(imap_max_line_length) 65536,
+       MEMBER(imap_capability) "",
+       MEMBER(imap_client_workarounds) "outlook-idle",
+       MEMBER(imap_logout_format) "bytes=%i/%o",
+       MEMBER(imap_id_send) "",
+       MEMBER(imap_id_log) ""
+};
+
+struct setting_parser_info imap_setting_parser_info = {
+       MEMBER(defines) imap_setting_defines,
+       MEMBER(defaults) &imap_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 imap_settings)
+};
+
+static pool_t settings_pool = NULL;
+
+void imap_settings_read(const struct imap_settings **set_r,
+                       const struct mail_user_settings **user_set_r)
+{
+       static const struct setting_parser_info *roots[] = {
+                &imap_setting_parser_info,
+                &mail_user_setting_parser_info
+       };
+       struct setting_parser_context *parser;
+       void **sets;
+
+       if (settings_pool == NULL)
+               settings_pool = pool_alloconly_create("imap settings", 2048);
+       else
+               p_clear(settings_pool);
+
+       mail_storage_namespace_defines_init(settings_pool);
+
+       parser = settings_parser_init_list(settings_pool,
+                               roots, N_ELEMENTS(roots),
+                               SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
+
+       settings_parse_set_expanded(parser, TRUE);
+       if (settings_parse_environ(parser) < 0) {
+               i_fatal("Error reading configuration: %s",
+                       settings_parser_get_error(parser));
+       }
+
+       sets = settings_parser_get_list(parser);
+       *set_r = sets[0];
+       *user_set_r = sets[1];
+       settings_parser_deinit(&parser);
+}
diff --git a/src/imap/imap-settings.h b/src/imap/imap-settings.h
new file mode 100644 (file)
index 0000000..902ba8c
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef IMAP_SETTINGS_H
+#define IMAP_SETTINGS_H
+
+struct mail_user_settings;
+
+struct imap_settings {
+       bool mail_debug;
+       bool shutdown_clients;
+       bool verbose_proctitle;
+
+       const char *mail_plugins;
+       const char *mail_plugin_dir;
+       const char *mail_log_prefix;
+
+       /* imap: */
+       unsigned int imap_max_line_length;
+       const char *imap_capability;
+       const char *imap_client_workarounds;
+       const char *imap_logout_format;
+       const char *imap_id_send;
+       const char *imap_id_log;
+};
+
+void imap_settings_read(const struct imap_settings **set_r,
+                       const struct mail_user_settings **user_set_r);
+
+#endif
index e78ecf453e4a736edcafb218a0ecee93eea1976f..35b08294ad3dc1e4547bc9627e7aed8b0d39a164 100644 (file)
@@ -562,7 +562,7 @@ static bool cmd_sync_client(struct client_command_context *sync_cmd)
        get_common_sync_flags(client, &flags, &imap_flags);
        client->sync_counter++;
 
-       no_newmail = (client_workarounds & WORKAROUND_DELAY_NEWMAIL) != 0 &&
+       no_newmail = (client->workarounds & WORKAROUND_DELAY_NEWMAIL) != 0 &&
                (imap_flags & IMAP_SYNC_FLAG_SAFE) == 0;
        if (no_newmail) {
                /* expunges might break the client just as badly as new mail
index 13420dd27ed3799c9179cb292974e3d2d3768218..7014342e822d0c3e84432909a209cc62f299c285 100644 (file)
@@ -39,10 +39,6 @@ static struct client_workaround_list client_workaround_list[] = {
 };
 
 struct ioloop *ioloop;
-unsigned int imap_max_line_length;
-enum client_workarounds client_workarounds = 0;
-const char *logout_format;
-const char *imap_id_send, *imap_id_log;
 
 static struct io *log_io = NULL;
 static struct module *modules = NULL;
@@ -50,8 +46,6 @@ static char log_prefix[128]; /* syslog() needs this to be permanent */
 
 void (*hook_client_created)(struct client **client) = NULL;
 
-string_t *capability_string;
-
 static void sig_die(int signo, void *context ATTR_UNUSED)
 {
        /* warn about being killed because of some signal, except SIGINT (^C)
@@ -66,16 +60,15 @@ static void log_error_callback(void *context ATTR_UNUSED)
        io_loop_stop(ioloop);
 }
 
-static void parse_workarounds(void)
+static enum client_workarounds
+parse_workarounds(const struct imap_settings *set)
 {
+        enum client_workarounds client_workarounds = 0;
         struct client_workaround_list *list;
-       const char *env, *const *str;
-
-       env = getenv("IMAP_CLIENT_WORKAROUNDS");
-       if (env == NULL)
-               return;
+       const char *const *str;
 
-       for (str = t_strsplit_spaces(env, " ,"); *str != NULL; str++) {
+        str = t_strsplit_spaces(set->imap_client_workarounds, " ,");
+       for (; *str != NULL; str++) {
                list = client_workaround_list;
                for (; list->name != NULL; list++) {
                        if (strcasecmp(*str, list->name) == 0) {
@@ -86,6 +79,8 @@ static void parse_workarounds(void)
                if (list->name == NULL)
                        i_fatal("Unknown client workaround: %s", *str);
        }
+
+       return client_workarounds;
 }
 
 static void open_logfile(void)
@@ -129,7 +124,8 @@ static void open_logfile(void)
        i_set_failure_timestamp_format(getenv("LOGSTAMP"));
 }
 
-static void drop_privileges(void)
+static void main_preinit(const struct imap_settings **set_r,
+                        const struct mail_user_settings **user_set_r)
 {
        const char *version;
 
@@ -143,25 +139,30 @@ static void drop_privileges(void)
        /* Log file or syslog opening probably requires roots */
        open_logfile();
 
-       /* Load the plugins before chrooting. Their init() is called later. */
-       if (getenv("MAIL_PLUGINS") != NULL) {
-               const char *plugin_dir = getenv("MAIL_PLUGIN_DIR");
+        mail_storage_init();
+       mail_storage_register_all();
+       mailbox_list_register_all();
 
-               if (plugin_dir == NULL)
-                       plugin_dir = MODULEDIR"/imap";
-               modules = module_dir_load(plugin_dir, getenv("MAIL_PLUGINS"),
-                                         TRUE, version);
-       }
+       /* read settings after registering storages so they can have their
+          own setting definitions too */
+       imap_settings_read(set_r, user_set_r);
+
+       /* Load the plugins before chrooting. Their init() is called later. */
+       modules = *(*set_r)->mail_plugins == '\0' ? NULL :
+               module_dir_load((*set_r)->mail_plugin_dir,
+                               (*set_r)->mail_plugins, TRUE, version);
 
        restrict_access_by_env(!IS_STANDALONE());
 }
 
-static void main_init(void)
+static void main_init(const struct imap_settings *set,
+                     const struct mail_user_settings *user_set)
 {
        struct client *client;
        struct ostream *output;
        struct mail_user *user;
-       const char *username, *home, *str, *tag;
+       const char *username, *home, *str, *tag, *error;
+       bool dump_capability;
 
        lib_signals_init();
         lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
@@ -169,6 +170,8 @@ static void main_init(void)
         lib_signals_ignore(SIGPIPE, TRUE);
         lib_signals_ignore(SIGALRM, FALSE);
 
+       dump_capability = getenv("DUMP_CAPABILITY") != NULL;
+
        username = getenv("USER");
        if (username == NULL) {
                if (IS_STANDALONE())
@@ -178,63 +181,40 @@ static void main_init(void)
        }
 
        home = getenv("HOME");
-       if (getenv("DEBUG") != NULL) {
+       if (set->mail_debug) {
+               home = getenv("HOME");
                i_info("Effective uid=%s, gid=%s, home=%s",
                       dec2str(geteuid()), dec2str(getegid()),
                       home != NULL ? home : "(none)");
        }
 
-       if (getenv("STDERR_CLOSE_SHUTDOWN") != NULL) {
+       if (set->shutdown_clients && !dump_capability) {
                /* If master dies, the log fd gets closed and we'll quit */
                log_io = io_add(STDERR_FILENO, IO_ERROR,
                                log_error_callback, NULL);
        }
 
-       capability_string = str_new(default_pool, sizeof(CAPABILITY_STRING)+32);
-       str_append(capability_string, CAPABILITY_STRING);
-
        dict_drivers_register_builtin();
        mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL);
-        mail_storage_init();
-       mail_storage_register_all();
-       mailbox_list_register_all();
        clients_init();
        commands_init();
 
        module_dir_init(modules);
 
-       if (getenv("DUMP_CAPABILITY") != NULL) {
-               printf("%s\n", str_c(capability_string));
+       user = mail_user_alloc(username, user_set);
+       mail_user_set_home(user, home);
+       if (mail_user_init(user, &error) < 0)
+               i_fatal("Mail user initialization failed: %s", error);
+       if (mail_namespaces_init(user, &error) < 0)
+               i_fatal("Namespace initialization failed: %s", error);
+       client = client_create(0, 1, user, set);
+        client->workarounds = parse_workarounds(set);
+
+       if (dump_capability) {
+               printf("%s\n", str_c(client->capability_string));
                exit(0);
        }
 
-       str = getenv("IMAP_CAPABILITY");
-       if (str != NULL && *str != '\0') {
-               /* Overrides all capabilities */
-               str_truncate(capability_string, 0);
-               str_append(capability_string, str);
-       }
-
-       str = getenv("IMAP_MAX_LINE_LENGTH");
-       imap_max_line_length = str != NULL ?
-               (unsigned int)strtoul(str, NULL, 10) :
-               DEFAULT_IMAP_MAX_LINE_LENGTH;
-
-       logout_format = getenv("IMAP_LOGOUT_FORMAT");
-       if (logout_format == NULL)
-               logout_format = "bytes=%i/%o";
-
-       imap_id_send = getenv("IMAP_ID_SEND");
-       imap_id_log = getenv("IMAP_ID_LOG");
-
-        parse_workarounds();
-
-       user = mail_user_init(username);
-       mail_user_set_home(user, home);
-       if (mail_namespaces_init(user) < 0)
-               i_fatal("Namespace initialization failed");
-       client = client_create(0, 1, user);
-
        output = client->output;
        o_stream_ref(output);
        o_stream_cork(output);
@@ -244,12 +224,12 @@ static void main_init(void)
        if (tag == NULL) {
                client_send_line(client, t_strconcat(
                        "* PREAUTH [CAPABILITY ",
-                       str_c(capability_string), "] "
+                       str_c(client->capability_string), "] "
                        "Logged in as ", user->username, NULL));
        } else {
                client_send_line(client, t_strconcat(
                        tag, " OK [CAPABILITY ",
-                       str_c(capability_string), "] Logged in", NULL));
+                       str_c(client->capability_string), "] Logged in", NULL));
        }
        str = getenv("CLIENT_INPUT");
        if (str != NULL) T_BEGIN {
@@ -277,14 +257,15 @@ static void main_deinit(void)
        mail_users_deinit();
        dict_drivers_unregister_builtin();
 
-       str_free(&capability_string);
-
        lib_signals_deinit();
        closelog();
 }
 
 int main(int argc ATTR_UNUSED, char *argv[], char *envp[])
 {
+       const struct imap_settings *set;
+       const struct mail_user_settings *user_set;
+
 #ifdef DEBUG
        if (!IS_STANDALONE() && getenv("GDB") == NULL)
                fd_debug_verify_leaks(3, 1024);
@@ -299,7 +280,7 @@ int main(int argc ATTR_UNUSED, char *argv[], char *envp[])
        /* NOTE: we start rooted, so keep the code minimal until
           restrict_access_by_env() is called */
        lib_init();
-       drop_privileges();
+       main_preinit(&set, &user_set);
 
         process_title_init(argv, envp);
        ioloop = io_loop_create();
@@ -307,7 +288,7 @@ int main(int argc ATTR_UNUSED, char *argv[], char *envp[])
        /* fake that we're running, so we know if client was destroyed
           while initializing */
        io_loop_set_running(ioloop);
-       main_init();
+       main_init(set, user_set);
        if (io_loop_is_running(ioloop))
                io_loop_run(ioloop);
        main_deinit();
index 819784862a6ad24a382ca4be482f8b0c03c35212..a6f109b65ae66258eecbfcc016298c3e95f27c8e 100644 (file)
@@ -4,10 +4,12 @@ AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib
 
 libsettings_a_SOURCES = \
-       settings.c
+       settings.c \
+       settings-parser.c
 
 headers = \
-       settings.h
+       settings.h \
+       settings-parser.h
 
 if INSTALL_HEADERS
   pkginc_libdir=$(pkgincludedir)/src/lib-settings
diff --git a/src/lib-settings/settings-parser.c b/src/lib-settings/settings-parser.c
new file mode 100644 (file)
index 0000000..79804d8
--- /dev/null
@@ -0,0 +1,903 @@
+/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "hash.h"
+#include "network.h"
+#include "istream.h"
+#include "str.h"
+#include "strescape.h"
+#include "var-expand.h"
+#include "settings-parser.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
+
+struct setting_link {
+        struct setting_link *parent;
+       const struct setting_parser_info *info;
+
+       ARRAY_TYPE(void_array) *array;
+       void *set_struct;
+};
+
+struct setting_parser_context {
+       pool_t set_pool, parser_pool;
+        enum settings_parser_flags flags;
+       bool str_vars_are_expanded;
+
+       struct setting_link *roots;
+       unsigned int root_count;
+       struct hash_table *links;
+       string_t *save_input_str;
+
+       unsigned int linenum;
+       const char *error;
+       const struct setting_parser_info *prev_info;
+};
+
+static const struct setting_parser_info strlist_info = {
+       MEMBER(defines) NULL,
+       MEMBER(defaults) NULL,
+
+       MEMBER(parent) NULL,
+       MEMBER(dynamic_parsers) NULL,
+
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) (size_t)-1,
+       MEMBER(struct_size) 0
+};
+
+struct setting_parser_context *
+settings_parser_init(pool_t set_pool, const struct setting_parser_info *root,
+                    enum settings_parser_flags flags)
+{
+        return settings_parser_init_list(set_pool, &root, 1, flags);
+}
+
+static void
+setting_parser_copy_defaults(const struct setting_parser_info *info,
+                            pool_t pool, void *dest)
+{
+       const struct setting_define *def;
+       const char *p, **strp;
+
+       if (info->defaults == NULL)
+               return;
+
+       memcpy(dest, info->defaults, info->struct_size);
+       for (def = info->defines; def->key != NULL; def++) {
+               switch (def->type) {
+               case SET_ENUM: {
+                       /* fix enums by dropping everything after the
+                          first ':' */
+                       strp = STRUCT_MEMBER_P(dest, def->offset);
+                       p = strchr(*strp, ':');
+                       if (p != NULL)
+                               *strp = p_strdup_until(pool, *strp, p);
+                       break;
+               }
+               case SET_STR_VARS: {
+                       /* insert the unexpanded-character */
+                       strp = STRUCT_MEMBER_P(dest, def->offset);
+                       if (*strp != NULL) {
+                               *strp = p_strconcat(pool,
+                                                   SETTING_STRVAR_UNEXPANDED,
+                                                   *strp, NULL);
+                       }
+                       break;
+               }
+               default:
+                       break;
+               }
+       }
+}
+
+struct setting_parser_context *
+settings_parser_init_list(pool_t set_pool,
+                         const struct setting_parser_info *const *roots,
+                         unsigned int count, enum settings_parser_flags flags)
+{
+       struct setting_parser_context *ctx;
+       unsigned int i;
+       pool_t parser_pool;
+
+       i_assert(count > 0);
+
+       parser_pool = pool_alloconly_create("settings parser", 8192);
+       ctx = p_new(parser_pool, struct setting_parser_context, 1);
+       ctx->set_pool = set_pool;
+       ctx->parser_pool = parser_pool;
+       ctx->flags = flags;
+
+       ctx->root_count = count;
+       ctx->roots = p_new(ctx->set_pool, struct setting_link, count);
+       for (i = 0; i < count; i++) {
+               ctx->roots[i].info = roots[i];
+               ctx->roots[i].set_struct =
+                       p_malloc(ctx->set_pool, roots[i]->struct_size);
+               setting_parser_copy_defaults(roots[i], ctx->set_pool,
+                                            ctx->roots[i].set_struct);
+       }
+
+       ctx->links = hash_table_create(default_pool, ctx->parser_pool, 0,
+                                      str_hash, (hash_cmp_callback_t *)strcmp);
+       pool_ref(ctx->set_pool);
+       return ctx;
+}
+
+void settings_parser_deinit(struct setting_parser_context **_ctx)
+{
+       struct setting_parser_context *ctx = *_ctx;
+
+       *_ctx = NULL;
+       hash_table_destroy(&ctx->links);
+       pool_unref(&ctx->set_pool);
+       pool_unref(&ctx->parser_pool);
+}
+
+void *settings_parser_get(struct setting_parser_context *ctx)
+{
+       i_assert(ctx->root_count == 1);
+
+       return ctx->roots[0].set_struct;
+}
+
+void **settings_parser_get_list(struct setting_parser_context *ctx)
+{
+       unsigned int i;
+       void **sets;
+
+       sets = t_new(void *, ctx->root_count);
+       for (i = 0; i < ctx->root_count; i++)
+               sets[i] = ctx->roots[i].set_struct;
+       return sets;
+}
+
+const char *settings_parser_get_error(struct setting_parser_context *ctx)
+{
+       return ctx->error;
+}
+
+static const struct setting_define *
+setting_define_find(const struct setting_parser_info *info, const char *key)
+{
+       const struct setting_define *list;
+
+       for (list = info->defines; list->key != NULL; list++) {
+               if (strcmp(list->key, key) == 0 && list->type != SET_INTERNAL)
+                       return list;
+       }
+       return NULL;
+}
+
+static int
+get_bool(struct setting_parser_context *ctx, const char *value, bool *result_r)
+{
+       /* FIXME: eventually we'd want to support only yes/no */
+       if (strcasecmp(value, "yes") == 0 ||
+           strcasecmp(value, "y") == 0 || strcmp(value, "1") == 0)
+               *result_r = TRUE;
+       else if (strcasecmp(value, "no") == 0)
+               *result_r = FALSE;
+       else {
+               ctx->error = p_strconcat(ctx->parser_pool, "Invalid boolean: ",
+                                        value, NULL);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+get_uint(struct setting_parser_context *ctx, const char *value,
+        unsigned int *result_r)
+{
+       int num;
+
+       /* use %i so we can handle eg. 0600 as octal value with umasks */
+       if (!sscanf(value, "%i", &num) || num < 0) {
+               ctx->error = p_strconcat(ctx->parser_pool, "Invalid number: ",
+                                        value, NULL);
+               return -1;
+       }
+       *result_r = num;
+       return 0;
+}
+
+static int get_enum(struct setting_parser_context *ctx, const char *value,
+                   char **result_r, const char *allowed_values)
+{
+       const char *p;
+
+       while (allowed_values != NULL) {
+               p = strchr(allowed_values, ':');
+               if (p == NULL) {
+                       if (strcmp(allowed_values, value) == 0)
+                               break;
+
+                       ctx->error = p_strconcat(ctx->parser_pool,
+                                                "Invalid value: ",
+                                                value, NULL);
+                       return -1;
+               }
+
+               if (strncmp(allowed_values, value, p - allowed_values) == 0 &&
+                   value[p - allowed_values] == '\0')
+                       break;
+
+               allowed_values = p + 1;
+       }
+
+       *result_r = p_strdup(ctx->set_pool, value);
+       return 0;
+}
+
+static int
+get_deflist(struct setting_parser_context *ctx, struct setting_link *parent,
+           const struct setting_parser_info *info,
+           const char *key, const char *value, ARRAY_TYPE(void_array) *result)
+{
+       struct setting_link *link;
+       const char *const *list;
+       char *full_key;
+
+       i_assert(info->defines != NULL || info == &strlist_info);
+
+       if (!array_is_created(result))
+               p_array_init(result, ctx->set_pool, 5);
+
+       list = t_strsplit(value, "\t ");
+       for (; *list != NULL; list++) {
+               if (**list == '\0')
+                       continue;
+
+               full_key = p_strconcat(ctx->parser_pool, key,
+                                      SETTINGS_SEPARATOR_S, *list, NULL);
+               if (hash_table_lookup(ctx->links, full_key) != NULL) {
+                       ctx->error = p_strconcat(ctx->parser_pool, full_key,
+                                                " already exists", NULL);
+                       return -1;
+               }
+
+               link = p_new(ctx->parser_pool, struct setting_link, 1);
+               link->parent = parent;
+               link->info = info;
+               link->array = result;
+               hash_table_insert(ctx->links, full_key, link);
+       }
+       return 0;
+}
+
+static int
+settings_parse(struct setting_parser_context *ctx, struct setting_link *link,
+              const struct setting_define *def,
+              const char *key, const char *value)
+{
+        void *ptr, *ptr2;
+
+       ctx->prev_info = link->info;
+
+       if (link->set_struct == NULL) {
+               link->set_struct =
+                       p_malloc(ctx->set_pool, link->info->struct_size);
+               setting_parser_copy_defaults(link->info, ctx->set_pool,
+                                            link->set_struct);
+               array_append(link->array, &link->set_struct, 1);
+
+               if (link->info->parent_offset != (size_t)-1 &&
+                   link->parent != NULL) {
+                       ptr = STRUCT_MEMBER_P(link->set_struct,
+                                             link->info->parent_offset);
+                       *((void **)ptr) = link->parent->set_struct;
+               }
+       }
+
+       ptr = STRUCT_MEMBER_P(link->set_struct, def->offset);
+       switch (def->type) {
+       case SET_INTERNAL:
+               i_unreached();
+       case SET_BOOL:
+               return get_bool(ctx, value, (bool *)ptr);
+       case SET_UINT:
+               return get_uint(ctx, value, (unsigned int *)ptr);
+       case SET_STR:
+               *((char **)ptr) = p_strdup(ctx->set_pool, value);
+               return 0;
+       case SET_STR_VARS:
+               *((char **)ptr) = p_strconcat(ctx->set_pool,
+                                             ctx->str_vars_are_expanded ?
+                                             SETTING_STRVAR_EXPANDED :
+                                             SETTING_STRVAR_UNEXPANDED,
+                                             value, NULL);
+               return 0;
+       case SET_ENUM:
+               /* get the available values from default string */
+               i_assert(link->info->defaults != NULL);
+               ptr2 = STRUCT_MEMBER_P(link->info->defaults, def->offset);
+               return get_enum(ctx, value, (char **)ptr, *(const char **)ptr2);
+       case SET_DEFLIST:
+               ctx->prev_info = def->list_info;
+               return get_deflist(ctx, link, def->list_info,
+                                  key, value, (ARRAY_TYPE(void_array) *)ptr);
+       case SET_STRLIST: {
+               ctx->prev_info = &strlist_info;
+               return get_deflist(ctx, link, &strlist_info,
+                                  key, value, (ARRAY_TYPE(void_array) *)ptr);
+       }
+       }
+
+       i_unreached();
+       return -1;
+}
+
+static int settings_parse_keyvalue(struct setting_parser_context *ctx,
+                                  const char *key, const char *value)
+{
+       const struct setting_define *def = NULL;
+       unsigned int i;
+       int ret = 1;
+
+       /* try to find from roots */
+       for (i = 0; i < ctx->root_count; i++) {
+               def = setting_define_find(ctx->roots[i].info, key);
+               if (def != NULL)
+                       break;
+       }
+       if (def != NULL) {
+               if (settings_parse(ctx, &ctx->roots[i], def, key, value) < 0)
+                       ret = -1;
+       } else {
+               /* try to find from links */
+               const char *end = strrchr(key, SETTINGS_SEPARATOR);
+               struct setting_link *link;
+
+               link = end == NULL ? NULL :
+                       hash_table_lookup(ctx->links, t_strdup_until(key, end));
+               if (link == NULL)
+                       def = NULL;
+               else if (link->info == &strlist_info) {
+                       void *vkey, *vvalue;
+
+                       vkey = p_strdup(ctx->set_pool, end + 1);
+                       vvalue = p_strdup(ctx->set_pool, value);
+                       array_append(link->array, &vkey, 1);
+                       array_append(link->array, &vvalue, 1);
+                       return 1;
+               } else {
+                       def = setting_define_find(link->info, end + 1);
+               }
+               if (def != NULL) {
+                       if (settings_parse(ctx, link, def, key, value) < 0)
+                               ret = -1;
+               } else {
+                       ctx->error = p_strconcat(ctx->parser_pool,
+                               "Unknown setting: ", key, NULL);
+                       ret = 0;
+               }
+       }
+       return ret;
+}
+
+int settings_parse_line(struct setting_parser_context *ctx, const char *line)
+{
+       const char *key, *value;
+       int ret;
+
+       ctx->error = NULL;
+       ctx->prev_info = NULL;
+
+       key = line;
+       value = strchr(line, '=');
+       if (value == NULL) {
+               ctx->error = "Missing '='";
+               return -1;
+       }
+
+       if (key == value) {
+               ctx->error = "Missing key name ('=' at the beginning of line)";
+               return -1;
+       }
+
+       T_BEGIN {
+               key = t_strdup_until(key, value);
+               ret = settings_parse_keyvalue(ctx, key, value + 1);
+       } T_END;
+       return ret;
+}
+
+const struct setting_parser_info *
+settings_parse_get_prev_info(struct setting_parser_context *ctx)
+{
+       return ctx->prev_info;
+}
+
+int settings_parse_stream(struct setting_parser_context *ctx,
+                         struct istream *input)
+{
+       const char *line;
+       string_t *full_line;
+       size_t len;
+       int ret = 1;
+
+       full_line = str_new(default_pool, 512);
+       while ((line = i_stream_next_line(input)) != NULL) {
+               if (*line == '\0') {
+                       /* empty line finishes it */
+                       ret = 0;
+                       break;
+               }
+
+               ctx->linenum++;
+               while (IS_WHITE(*line == ' '))
+                       line++;
+               if (*line == '\0' || *line == '#')
+                       continue;
+
+               len = strlen(line);
+               while (len > 0 && IS_WHITE(line[len-1]))
+                       len--;
+               if (line[len] == '\\') {
+                       /* line continues */
+                       str_append_n(full_line, line, len - 1);
+               } else {
+                       /* full line */
+                       if (str_len(full_line) > 0) {
+                               str_append_n(full_line, line, len);
+                               line = str_c(full_line);
+                       }
+
+                       ret = settings_parse_line(ctx, line);
+                       if (ret == 0 &&
+                           (ctx->flags &
+                            SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS) == 0)
+                               ret = -1;
+
+                       if (ret < 0) {
+                               ctx->error = p_strdup_printf(ctx->parser_pool,
+                                                            "Line %u: %s",
+                                                            ctx->linenum,
+                                                            ctx->error);
+                               ret = -1;
+                               break;
+                       }
+                       str_truncate(full_line, 0);
+               }
+       }
+       str_free(&full_line);
+       return ret;
+}
+
+int settings_parse_stream_read(struct setting_parser_context *ctx,
+                              struct istream *input)
+{
+       const unsigned char *data;
+       size_t size;
+       int ret;
+
+       while ((ret = i_stream_read(input)) > 0) {
+               if (ctx->save_input_str != NULL) {
+                       data = i_stream_get_data(input, &size);
+                       str_append_n(ctx->save_input_str, data, size);
+               }
+               if ((ret = settings_parse_stream(ctx, input)) < 0)
+                       return -1;
+               if (ret == 0) {
+                       /* empty line read */
+                       return 0;
+               }
+       }
+
+       switch (ret) {
+       case -1:
+               if (input->stream_errno != 0) {
+                       ctx->error = p_strdup_printf(ctx->parser_pool,
+                                                    "read() failed: %m");
+               } else {
+                       ctx->error = "input is missing end-of-settings line";
+               }
+               break;
+       case -2:
+               ctx->error = p_strdup_printf(ctx->parser_pool,
+                                            "Line %u: line too long",
+                                            ctx->linenum);
+               break;
+       case 0:
+               /* blocks */
+               return 1;
+       default:
+               i_unreached();
+       }
+       return -1;
+}
+
+int settings_parse_file(struct setting_parser_context *ctx,
+                       const char *path, size_t max_line_length)
+{
+       struct istream *input;
+       int fd, ret;
+
+       fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               ctx->error = p_strdup_printf(ctx->parser_pool,
+                                            "open(%s) failed: %m", path);
+               return -1;
+       }
+
+       input = i_stream_create_fd(fd, max_line_length, TRUE);
+       ret = settings_parse_stream_read(ctx, input);
+       i_stream_unref(&input);
+
+       return ret;
+}
+
+int settings_parse_environ(struct setting_parser_context *ctx)
+{
+       extern char **environ;
+       const char *key, *value;
+       unsigned int i;
+       int ret = 0;
+
+       for (i = 0; environ[i] != NULL && ret == 0; i++) {
+               value = strchr(environ[i], '=');
+               if (value != NULL) T_BEGIN {
+                       key = t_strdup_until(environ[i], value++);
+                       key = t_str_lcase(key);
+                       if (settings_parse_keyvalue(ctx, key, value) < 0) {
+                               ctx->error = p_strdup_printf(ctx->parser_pool,
+                                       "Invalid setting %s: %s",
+                                       key, ctx->error);
+                               ret = -1;
+                       }
+               } T_END;
+       }
+       return ret;
+}
+
+int settings_parse_exec(struct setting_parser_context *ctx,
+                       const char *bin_path, const char *config_path,
+                       const char *service)
+{
+       struct istream *input;
+       pid_t pid;
+       int ret, fd[2], status;
+
+       if (pipe(fd) < 0) {
+               i_error("pipe() failed: %m");
+               return -1;
+       }
+
+       pid = fork();
+       if (pid == (pid_t)-1) {
+               i_error("fork() failed: %m");
+               (void)close(fd[0]);
+               (void)close(fd[1]);
+               return -1;
+       }
+       if (pid == 0) {
+               /* child */
+               static const char *argv[] = {
+                       NULL,
+                       "-c", NULL,
+                       "-s", NULL,
+                       NULL
+               };
+               argv[0] = bin_path;
+               argv[2] = config_path;
+               argv[4] = service;
+               (void)close(fd[0]);
+               if (dup2(fd[1], STDOUT_FILENO) < 0)
+                       i_fatal("dup2() failed: %m");
+
+               execv(argv[0], (void *)argv);
+               i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", bin_path);
+               return -1;
+       }
+       (void)close(fd[1]);
+
+       input = i_stream_create_fd(fd[0], (size_t)-1, TRUE);
+       ret = settings_parse_stream_read(ctx, input);
+       i_stream_destroy(&input);
+
+       if (waitpid(pid, &status, 0) < 0) {
+               i_error("waitpid() failed: %m");
+               ret = -1;
+       } else if (status != 0) {
+               i_error("%s returned failure: %d", bin_path, status);
+               ret = -1;
+       }
+       return ret;
+}
+
+void settings_parse_set_expanded(struct setting_parser_context *ctx,
+                                bool is_expanded)
+{
+       ctx->str_vars_are_expanded = is_expanded;
+}
+
+static void
+settings_var_expand_info(const struct setting_parser_info *info,
+                        pool_t pool, void *set,
+                        const struct var_expand_table *table, string_t *str)
+{
+       const struct setting_define *def;
+       void *value, *const *children;
+       unsigned int i, count;
+
+       for (def = info->defines; def->key != NULL; def++) {
+               value = PTR_OFFSET(set, def->offset);
+               switch (def->type) {
+               case SET_STR_VARS: {
+                       const char **val = value;
+
+                       if (*val == NULL)
+                               break;
+
+                       if (**val == SETTING_STRVAR_UNEXPANDED[0]) {
+                               str_truncate(str, 0);
+                               var_expand(str, *val + 1, table);
+                               *val = p_strdup(pool, str_c(str));
+                       } else {
+                               i_assert(**val == SETTING_STRVAR_EXPANDED[0]);
+                               *val += 1;
+                       }
+                       break;
+               }
+               case SET_DEFLIST: {
+                       const ARRAY_TYPE(void_array) *val = value;
+
+                       if (!array_is_created(val))
+                               break;
+
+                       children = array_get(val, &count);
+                       for (i = 0; i < count; i++) {
+                               settings_var_expand_info(def->list_info,
+                                                        pool, children[i],
+                                                        table, str);
+                       }
+                       break;
+               }
+               default:
+                       break;
+               }
+       }
+}
+
+void settings_var_expand(const struct setting_parser_info *info,
+                        void *set, pool_t pool,
+                        const struct var_expand_table *table)
+{
+       string_t *str;
+
+       T_BEGIN {
+               str = t_str_new(256);
+               settings_var_expand_info(info, pool, set, table, str);
+       } T_END;
+}
+
+bool settings_vars_have_key(const struct setting_parser_info *info, void *set,
+                           char var_key, const char *long_var_key,
+                           const char **key_r, const char **value_r)
+{
+       const struct setting_define *def;
+       const void *value;
+       void *const *children;
+       unsigned int i, count;
+
+       for (def = info->defines; def->key != NULL; def++) {
+               value = CONST_PTR_OFFSET(set, def->offset);
+               switch (def->type) {
+               case SET_STR_VARS: {
+                       const char *const *val = value;
+
+                       if (*val == NULL)
+                               break;
+
+                       if (**val == SETTING_STRVAR_UNEXPANDED[0]) {
+                               if (var_has_key(*val + 1, var_key,
+                                               long_var_key)) {
+                                       *key_r = def->key;
+                                       *value_r = *val + 1;
+                                       return TRUE;
+                               }
+                       } else {
+                               i_assert(**val == SETTING_STRVAR_EXPANDED[0]);
+                       }
+                       break;
+               }
+               case SET_DEFLIST: {
+                       const ARRAY_TYPE(void_array) *val = value;
+
+                       if (!array_is_created(val))
+                               break;
+
+                       children = array_get(val, &count);
+                       for (i = 0; i < count; i++) {
+                               if (settings_vars_have_key(def->list_info,
+                                                          children[i], var_key,
+                                                          long_var_key,
+                                                          key_r, value_r))
+                                       return TRUE;
+                       }
+                       break;
+               }
+               default:
+                       break;
+               }
+       }
+       return FALSE;
+}
+
+void *settings_dup(const struct setting_parser_info *info,
+                  const void *set, pool_t pool)
+{
+       const struct setting_define *def;
+       const void *src;
+       void *dest_set, *dest, *const *children;
+       unsigned int i, count;
+
+       dest_set = p_malloc(pool, info->struct_size);
+       memcpy(dest_set, set, info->struct_size);
+       for (def = info->defines; def->key != NULL; def++) {
+               src = CONST_PTR_OFFSET(set, def->offset);
+               dest = PTR_OFFSET(dest_set, def->offset);
+
+               switch (def->type) {
+               case SET_INTERNAL:
+               case SET_BOOL:
+               case SET_UINT:
+                       break;
+               case SET_STR_VARS:
+               case SET_STR:
+               case SET_ENUM: {
+                       const char *const *src_str = src;
+                       const char **dest_str = dest;
+
+                       *dest_str = p_strdup(pool, *src_str);
+                       break;
+               }
+               case SET_DEFLIST: {
+                       const ARRAY_TYPE(void_array) *src_arr = src;
+                       ARRAY_TYPE(void_array) *dest_arr = dest;
+                       void *child_set;
+
+                       if (!array_is_created(src_arr))
+                               break;
+
+                       children = array_get(src_arr, &count);
+                       p_array_init(dest_arr, pool, count);
+                       for (i = 0; i < count; i++) {
+                               child_set = settings_dup(def->list_info,
+                                                        children[i], pool);
+                               array_append(dest_arr, &child_set, 1);
+                       }
+                       break;
+               }
+               case SET_STRLIST: {
+                       const ARRAY_TYPE(const_string) *src_arr = src;
+                       ARRAY_TYPE(const_string) *dest_arr = dest;
+                       const char *const *strings, *dup;
+
+                       if (!array_is_created(src_arr))
+                               break;
+
+                       strings = array_get(src_arr, &count);
+                       p_array_init(dest_arr, pool, count);
+                       for (i = 0; i < count; i += 2)
+                               dup = p_strdup(pool, strings[i]);
+                       break;
+               }
+               }
+       }
+       return dest_set;
+}
+
+void settings_parse_save_input(struct setting_parser_context *ctx,
+                              string_t *dest)
+{
+       ctx->save_input_str = dest;
+}
+
+static void
+info_update_real(pool_t pool, struct setting_parser_info *parent,
+                const struct dynamic_settings_parser *parsers)
+{
+       /* @UNSAFE */
+       ARRAY_DEFINE(defines, struct setting_define);
+       ARRAY_TYPE(dynamic_settings_parser) dynamic_parsers;
+       struct dynamic_settings_parser new_parser;
+       const struct setting_define *cur_defines;
+       struct setting_define *new_defines, new_define;
+       void *parent_defaults;
+       unsigned int i, j;
+       size_t offset, new_struct_size;
+
+       t_array_init(&defines, 128);
+       /* add existing defines */
+       for (j = 0; parent->defines[j].key != NULL; j++)
+               array_append(&defines, &parent->defines[j], 1);
+       new_struct_size = parent->struct_size;
+
+       /* add new dynamic defines */
+       for (i = 0; parsers[i].name != NULL; i++) {
+               i_assert(parsers[i].info->parent == parent);
+               cur_defines = parsers[i].info->defines;
+               for (j = 0; cur_defines[j].key != NULL; j++) {
+                       new_define = cur_defines[j];
+                       new_define.offset += new_struct_size;
+                       array_append(&defines, &new_define, 1);
+               }
+               new_struct_size += MEM_ALIGN(parsers[i].info->struct_size);
+       }
+       new_defines = p_new(pool, struct setting_define,
+                           array_count(&defines) + 1);
+       memcpy(new_defines, array_idx(&defines, 0),
+              sizeof(*parent->defines) * array_count(&defines));
+       parent->defines = new_defines;
+
+       /* update defaults */
+       parent_defaults = p_malloc(pool, new_struct_size);
+       memcpy(parent_defaults, parent->defaults, parent->struct_size);
+       offset = parent->struct_size;
+       for (i = 0; parsers[i].name != NULL; i++) {
+               memcpy(PTR_OFFSET(parent_defaults, offset),
+                      parsers[i].info->defaults, parsers[i].info->struct_size);
+               offset += MEM_ALIGN(parsers[i].info->struct_size);
+       }
+       parent->defaults = parent_defaults;
+
+       /* update dynamic parsers list */
+       t_array_init(&dynamic_parsers, 32);
+       if (parent->dynamic_parsers != NULL) {
+               for (i = 0; parent->dynamic_parsers[i].name != NULL; i++) {
+                       array_append(&dynamic_parsers,
+                                    &parent->dynamic_parsers[i], 1);
+               }
+       }
+       offset = parent->struct_size;
+       for (i = 0; parsers[i].name != NULL; i++) {
+               new_parser = parsers[i];
+               new_parser.name = p_strdup(pool, new_parser.name);
+               new_parser.struct_offset = offset;
+               array_append(&dynamic_parsers, &new_parser, 1);
+               offset += MEM_ALIGN(parsers[i].info->struct_size);
+       }
+       parent->dynamic_parsers =
+               p_new(pool, struct dynamic_settings_parser,
+                     array_count(&dynamic_parsers) + 1);
+       memcpy(parent->dynamic_parsers, array_idx(&dynamic_parsers, 0),
+              sizeof(*parent->dynamic_parsers) *
+              array_count(&dynamic_parsers));
+       parent->struct_size = new_struct_size;
+}
+
+void
+settings_parser_info_update(pool_t pool, struct setting_parser_info *parent,
+                           const struct dynamic_settings_parser *parsers)
+{
+       T_BEGIN {
+               info_update_real(pool, parent, parsers);
+       } T_END;
+}
+
+const void *settings_find_dynamic(struct setting_parser_info *info,
+                                 const void *base_set, const char *name)
+{
+       unsigned int i;
+
+       if (info->dynamic_parsers == NULL)
+               return NULL;
+
+       for (i = 0; info->dynamic_parsers[i].name != NULL; i++) {
+               if (strcmp(info->dynamic_parsers[i].name, name) == 0) {
+                       return CONST_PTR_OFFSET(base_set,
+                               info->dynamic_parsers[i].struct_offset);
+               }
+       }
+       return NULL;
+}
diff --git a/src/lib-settings/settings-parser.h b/src/lib-settings/settings-parser.h
new file mode 100644 (file)
index 0000000..a8d42b1
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef SETTINGS_PARSER_H
+#define SETTINGS_PARSER_H
+
+struct var_expand_table;
+
+#define SETTINGS_SEPARATOR '/'
+#define SETTINGS_SEPARATOR_S "/"
+
+/* STR_VARS pointer begins with either of these initially. Before actually
+   using the variables all variables in all unexpanded strings need to be
+   expanded. Afterwards the string pointers should be increased to skip
+   the initial '1' so it'll be easy to use them. */
+#define SETTING_STRVAR_UNEXPANDED "0"
+#define SETTING_STRVAR_EXPANDED "1"
+
+enum setting_type {
+       SET_INTERNAL, /* don't set this variable */
+       SET_BOOL,
+       SET_UINT,
+       SET_STR,
+       SET_STR_VARS, /* string with %variables */
+       SET_ENUM,
+       SET_DEFLIST, /* of type array_t */
+       SET_STRLIST /* of type ARRAY_TYPE(const_string) */
+};
+
+#define SETTING_DEFINE_LIST_END { 0, NULL, 0, NULL }
+
+struct setting_define {
+       enum setting_type type;
+       const char *key;
+
+       size_t offset;
+       const struct setting_parser_info *list_info;
+};
+
+#define SETTING_DEFINE_STRUCT_BOOL(name, struct_name) \
+       { SET_BOOL + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
+               ((struct struct_name *)0)->name, bool), \
+         #name, offsetof(struct struct_name, name), NULL }
+#define SETTING_DEFINE_STRUCT_UINT(name, struct_name) \
+       { SET_UINT + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
+               ((struct struct_name *)0)->name, unsigned int), \
+         #name, offsetof(struct struct_name, name), NULL }
+#define SETTING_DEFINE_STRUCT_STR(name, struct_name) \
+       { SET_STR + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
+               ((struct struct_name *)0)->name, const char *), \
+         #name, offsetof(struct struct_name, name), NULL }
+
+struct setting_parser_info {
+       const struct setting_define *defines;
+       const void *defaults;
+
+       struct setting_parser_info *parent;
+       struct dynamic_settings_parser *dynamic_parsers;
+
+       size_t parent_offset;
+       size_t type_offset;
+       size_t struct_size;
+};
+ARRAY_DEFINE_TYPE(setting_parser_info, struct setting_parser_info);
+
+/* name=NULL-terminated list of parsers. These follow the static settings.
+   After this list follows the actual settings. */
+struct dynamic_settings_parser {
+       const char *name;
+       const struct setting_parser_info *info;
+       size_t struct_offset;
+};
+ARRAY_DEFINE_TYPE(dynamic_settings_parser, struct dynamic_settings_parser);
+
+enum settings_parser_flags {
+       SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS        = 0x01
+};
+
+struct setting_parser_context;
+
+struct setting_parser_context *
+settings_parser_init(pool_t set_pool, const struct setting_parser_info *root,
+                    enum settings_parser_flags flags);
+struct setting_parser_context *
+settings_parser_init_list(pool_t set_pool,
+                         const struct setting_parser_info *const *roots,
+                         unsigned int count, enum settings_parser_flags flags);
+void settings_parser_deinit(struct setting_parser_context **ctx);
+
+/* Return pointer to root setting structure. */
+void *settings_parser_get(struct setting_parser_context *ctx);
+/* If there are multiple roots, return list to all of their settings. */
+void **settings_parser_get_list(struct setting_parser_context *ctx);
+
+/* Return the last error. */
+const char *settings_parser_get_error(struct setting_parser_context *ctx);
+/* Return the parser info used for the previously parsed line. */
+const struct setting_parser_info *
+settings_parse_get_prev_info(struct setting_parser_context *ctx);
+/* Save all parsed input to given string. */
+void settings_parse_save_input(struct setting_parser_context *ctx,
+                              string_t *dest);
+
+/* Parse a single line. Returns 1 if OK, 0 if key is unknown, -1 if error. */
+int settings_parse_line(struct setting_parser_context *ctx, const char *line);
+/* Parse data already read in input stream. */
+int settings_parse_stream(struct setting_parser_context *ctx,
+                         struct istream *input);
+/* Read data from input stream and parser it. returns -1 = error,
+   0 = eof/stream error, 1 = not finished yet (stream is non-blocking) */
+int settings_parse_stream_read(struct setting_parser_context *ctx,
+                              struct istream *input);
+/* Open file and parse it. */
+int settings_parse_file(struct setting_parser_context *ctx,
+                       const char *path, size_t max_line_length);
+int settings_parse_environ(struct setting_parser_context *ctx);
+/* Execute the given binary and wait for it to return the configuration. */
+int settings_parse_exec(struct setting_parser_context *ctx,
+                       const char *bin_path, const char *config_path,
+                       const char *service);
+
+/* While parsing values, specifies if STR_VARS strings are already expanded. */
+void settings_parse_set_expanded(struct setting_parser_context *ctx,
+                                bool is_expanded);
+/* Expand all unexpanded variables using the given table. Update the string
+   pointers so that they can be used without skipping over the '1'. */
+void settings_var_expand(const struct setting_parser_info *info,
+                        void *set, pool_t pool,
+                        const struct var_expand_table *table);
+/* Go through all the settings and return the first one that has an unexpanded
+   setting containing the given %key. */
+bool settings_vars_have_key(const struct setting_parser_info *info, void *set,
+                           char var_key, const char *long_var_key,
+                           const char **key_r, const char **value_r);
+/* Duplicate the entire settings structure. */
+void *settings_dup(const struct setting_parser_info *info,
+                  const void *set, pool_t pool);
+/* parsers is a name=NULL -terminated list. The parsers are appended as
+   dynamic_settings_list structures to parent. The new structures are allocated
+   from the given pool. */
+void
+settings_parser_info_update(pool_t pool, struct setting_parser_info *parent,
+                           const struct dynamic_settings_parser *parsers);
+
+/* Return pointer to beginning of settings for given name, or NULL if there is
+   no such registered name. */
+const void *settings_find_dynamic(struct setting_parser_info *info,
+                                 const void *base_set, const char *name);
+
+#endif
index 237430e7cc556e24fbebe04e46af8f4f6f24f3ad..838d90063555423cf268f7723fffd37f5a1d30b8 100644 (file)
@@ -5,6 +5,7 @@ noinst_LIBRARIES = libstorage.a
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
        -I$(top_srcdir)/src/lib-auth \
+       -I$(top_srcdir)/src/lib-settings \
        -I$(top_srcdir)/src/lib-mail \
        -I$(top_srcdir)/src/lib-imap \
        -I$(top_srcdir)/src/lib-index \
@@ -18,6 +19,7 @@ libstorage_a_SOURCES = \
        mail-search.c \
        mail-search-build.c \
        mail-storage.c \
+       mail-storage-settings.c \
        mail-user.c \
        mailbox-list.c \
        mailbox-search-result.c \
@@ -33,6 +35,7 @@ headers = \
        mail-thread.h \
        mail-storage.h \
        mail-storage-private.h \
+       mail-storage-settings.h \
        mail-user.h \
        mailbox-list.h \
        mailbox-list-private.h \
index 7af9bf98e8ed09179fb86370cb63450b4f271d2a..995505cf70acb2cbf80e458fb9d43310ea3225f1 100644 (file)
@@ -37,7 +37,7 @@ cydir_get_list_settings(struct mailbox_list_settings *list_set,
                        const char *data, struct mail_storage *storage,
                        const char **layout_r, const char **error_r)
 {
-       bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+       bool debug = storage->set->mail_debug;
 
        *layout_r = "fs";
 
@@ -125,8 +125,7 @@ static int cydir_create(struct mail_storage *_storage, const char *data,
                                storage, &storage->list_module_ctx);
 
        /* finish list init after we've overridden vfuncs */
-       mailbox_list_init(_storage->list, _storage->ns, &list_set,
-                         mail_storage_get_list_flags(_storage->flags));
+       mailbox_list_init(_storage->list, _storage->ns, &list_set, 0);
        return 0;
 }
 
@@ -409,6 +408,7 @@ struct mail_storage cydir_storage = {
        MEMBER(mailbox_is_file) FALSE,
 
        {
+               NULL,
                cydir_class_init,
                cydir_class_deinit,
                cydir_alloc,
index 6707b20bf7291dd9c0f465dbe2cb1899aa15a50e..05e5d539022028242d40039338fc68660512fdff 100644 (file)
@@ -2,6 +2,7 @@ noinst_LIBRARIES = libstorage_dbox.a
 
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
+       -I$(top_srcdir)/src/lib-settings \
        -I$(top_srcdir)/src/lib-mail \
        -I$(top_srcdir)/src/lib-imap \
        -I$(top_srcdir)/src/lib-index \
@@ -14,6 +15,7 @@ libstorage_dbox_a_SOURCES = \
        dbox-index.c \
        dbox-mail.c \
        dbox-save.c \
+       dbox-settings.c \
        dbox-sync.c \
        dbox-sync-file.c \
        dbox-sync-rebuild.c \
@@ -24,6 +26,7 @@ headers = \
        dbox-file.h \
        dbox-file-maildir.h \
        dbox-index.h \
+       dbox-settings.h \
        dbox-storage.h \
        dbox-sync.h
 
index 0ff0ee6aa91c2d3871f7ead9139c23ed4f87a18e..8a415880d29edd404cdfab650241a197475c9bca 100644 (file)
@@ -154,6 +154,7 @@ dbox_file_id_get_fname(struct dbox_mailbox *mbox, unsigned int file_id,
 struct dbox_file *
 dbox_file_init(struct dbox_mailbox *mbox, unsigned int file_id)
 {
+       const struct dbox_settings *set = mbox->storage->set;
        struct dbox_file *file;
        unsigned int count;
        bool maildir;
@@ -166,8 +167,8 @@ dbox_file_init(struct dbox_mailbox *mbox, unsigned int file_id)
        }
 
        count = array_count(&mbox->open_files);
-       if (count > mbox->max_open_files)
-               dbox_close_open_files(mbox, count - mbox->max_open_files);
+       if (count > set->dbox_max_open_files)
+               dbox_close_open_files(mbox, count - set->dbox_max_open_files);
 
        file = i_new(struct dbox_file, 1);
        file->refcount = 1;
@@ -254,7 +255,8 @@ void dbox_file_unref(struct dbox_file **_file)
 
        if (file->file_id != 0) {
                files = array_get(&file->mbox->open_files, &count);
-               if (!file->deleted && count <= file->mbox->max_open_files) {
+               if (!file->deleted &&
+                   count <= file->mbox->storage->set->dbox_max_open_files) {
                        /* we can leave this file open for now */
                        return;
                }
@@ -292,6 +294,8 @@ static time_t day_begin_stamp(unsigned int days)
 
 bool dbox_file_can_append(struct dbox_file *file, uoff_t mail_size)
 {
+       const struct dbox_settings *set = file->mbox->storage->set;
+
        if (file->nonappendable)
                return FALSE;
 
@@ -300,12 +304,12 @@ bool dbox_file_can_append(struct dbox_file *file, uoff_t mail_size)
                return FALSE;
        }
 
-       if (file->append_offset < file->mbox->rotate_min_size ||
+       if (file->append_offset < set->dbox_rotate_min_size ||
            file->append_offset == file->file_header_size)
                return TRUE;
-       if (file->append_offset + mail_size >= file->mbox->rotate_size)
+       if (file->append_offset + mail_size >= set->dbox_rotate_size)
                return FALSE;
-       return file->create_time >= day_begin_stamp(file->mbox->rotate_days);
+       return file->create_time >= day_begin_stamp(set->dbox_rotate_days);
 }
 
 static int dbox_file_parse_header(struct dbox_file *file, const char *line)
diff --git a/src/lib-storage/index/dbox/dbox-settings.c b/src/lib-storage/index/dbox/dbox-settings.c
new file mode 100644 (file)
index 0000000..9f87da4
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (c) 2006-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "mail-storage-settings.h"
+#include "dbox-settings.h"
+
+#include <stddef.h>
+
+#undef DEF
+#define DEF(type, name) \
+       { type, #name, offsetof(struct dbox_settings, name), NULL }
+
+static struct setting_define dbox_setting_defines[] = {
+       DEF(SET_UINT, dbox_rotate_size),
+       DEF(SET_UINT, dbox_rotate_min_size),
+       DEF(SET_UINT, dbox_rotate_days),
+       DEF(SET_UINT, dbox_max_open_files),
+
+       SETTING_DEFINE_LIST_END
+};
+
+static struct dbox_settings dbox_default_settings = {
+       MEMBER(dbox_rotate_size) 2048*1024,
+       MEMBER(dbox_rotate_min_size) 16*1024,
+       MEMBER(dbox_rotate_days) 0,
+       MEMBER(dbox_max_open_files) 64
+};
+
+static struct setting_parser_info dbox_setting_parser_info = {
+       MEMBER(defines) dbox_setting_defines,
+       MEMBER(defaults) &dbox_default_settings,
+
+       MEMBER(parent) &mail_user_setting_parser_info,
+       MEMBER(dynamic_parsers) NULL,
+
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) (size_t)-1,
+       MEMBER(struct_size) sizeof(struct dbox_settings)
+};
+
+const struct setting_parser_info *dbox_get_setting_parser_info(void)
+{
+       return &dbox_setting_parser_info;
+}
diff --git a/src/lib-storage/index/dbox/dbox-settings.h b/src/lib-storage/index/dbox/dbox-settings.h
new file mode 100644 (file)
index 0000000..58a473c
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef DBOX_SETTINGS_H
+#define DBOX_SETTINGS_H
+
+struct dbox_settings {
+       unsigned int dbox_rotate_size;
+       unsigned int dbox_rotate_min_size;
+       unsigned int dbox_rotate_days;
+       unsigned int dbox_max_open_files;
+};
+
+const struct setting_parser_info *dbox_get_setting_parser_info(void);
+
+#endif
index d29dfb72d15228a07918d3d9562b935bc4a6c5ab..7716a06a7b628770b79ddd0ef5007d3cdc6a89e4 100644 (file)
@@ -50,7 +50,7 @@ dbox_get_list_settings(struct mailbox_list_settings *list_set,
                       const char **layout_r, const char **alt_dir_r,
                       const char **error_r)
 {
-       bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+       bool debug = storage->set->mail_debug;
 
        *layout_r = "fs";
 
@@ -132,6 +132,8 @@ static int dbox_create(struct mail_storage *_storage, const char *data,
                return -1;
        }
 
+       storage->set = mail_storage_get_driver_settings(_storage);
+
        if (mailbox_list_alloc(layout, &_storage->list, error_r) < 0)
                return -1;
        storage->list_module_ctx.super = _storage->list->v;
@@ -145,8 +147,7 @@ static int dbox_create(struct mail_storage *_storage, const char *data,
                                storage, &storage->list_module_ctx);
 
        /* finish list init after we've overridden vfuncs */
-       mailbox_list_init(_storage->list, _storage->ns, &list_set,
-                         mail_storage_get_list_flags(_storage->flags));
+       mailbox_list_init(_storage->list, _storage->ns, &list_set, 0);
        return 0;
 }
 
@@ -194,7 +195,7 @@ dbox_open(struct dbox_storage *storage, const char *name,
        struct mail_storage *_storage = &storage->storage;
        struct dbox_mailbox *mbox;
        struct mail_index *index;
-       const char *path, *value;
+       const char *path;
        pool_t pool;
 
        path = mailbox_list_get_path(_storage->list, name,
@@ -216,31 +217,8 @@ dbox_open(struct dbox_storage *storage, const char *name,
        mbox->storage = storage;
        mbox->last_interactive_change = ioloop_time;
 
-       value = getenv("DBOX_ROTATE_SIZE");
-       if (value != NULL)
-               mbox->rotate_size = (uoff_t)strtoul(value, NULL, 10) * 1024;
-       else
-               mbox->rotate_size = DBOX_DEFAULT_ROTATE_SIZE;
-       mbox->rotate_size = 0; /* FIXME: currently anything else doesn't work */
-       value = getenv("DBOX_ROTATE_MIN_SIZE");
-       if (value != NULL)
-               mbox->rotate_min_size = (uoff_t)strtoul(value, NULL, 10) * 1024;
-       else
-               mbox->rotate_min_size = DBOX_DEFAULT_ROTATE_MIN_SIZE;
-       if (mbox->rotate_min_size > mbox->rotate_size)
-               mbox->rotate_min_size = mbox->rotate_size;
-       value = getenv("DBOX_ROTATE_DAYS");
-       if (value != NULL)
-               mbox->rotate_days = (unsigned int)strtoul(value, NULL, 10);
-       else
-               mbox->rotate_days = DBOX_DEFAULT_ROTATE_DAYS;
-
-       value = getenv("DBOX_MAX_OPEN_FILES");
-       if (value != NULL)
-               mbox->max_open_files = (unsigned int)strtoul(value, NULL, 10);
-       else
-               mbox->max_open_files = DBOX_DEFAULT_MAX_OPEN_FILES;
-       i_array_init(&mbox->open_files, I_MIN(mbox->max_open_files, 128));
+       i_array_init(&mbox->open_files,
+                    I_MIN(storage->set->dbox_max_open_files, 128));
 
        mbox->dbox_ext_id =
                mail_index_ext_register(index, "dbox", 0,
@@ -679,6 +657,7 @@ struct mail_storage dbox_storage = {
        MEMBER(mailbox_is_file) FALSE,
 
        {
+                dbox_get_setting_parser_info,
                dbox_class_init,
                dbox_class_deinit,
                dbox_alloc,
index dafcefdb0312470db9a01b9907109c70d3ddf5d7..d224cc85d2e6627183c3a749b15e74d1b280dc40 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "index-storage.h"
 #include "mailbox-list-private.h"
+#include "dbox-settings.h"
 
 #define DBOX_STORAGE_NAME "dbox"
 #define DBOX_SUBSCRIPTION_FILE_NAME ".dbox-subscriptions"
 /* Delete temp files having ctime older than this. */
 #define DBOX_TMP_DELETE_SECS (36*60*60)
 
-/* Default rotation settings */
-#define DBOX_DEFAULT_ROTATE_SIZE (2*1024*1024)
-#define DBOX_DEFAULT_ROTATE_MIN_SIZE (1024*16)
-#define DBOX_DEFAULT_ROTATE_DAYS 0
-#define DBOX_DEFAULT_MAX_OPEN_FILES 64
-
 /* Flag specifies if the message should be in primary or alternative storage */
 #define DBOX_INDEX_FLAG_ALT MAIL_INDEX_MAIL_FLAG_BACKEND
 
@@ -37,6 +32,7 @@ struct dbox_index_header {
 struct dbox_storage {
        struct mail_storage storage;
        union mailbox_list_module_context list_module_ctx;
+       const struct dbox_settings *set;
        const char *alt_dir;
 };
 
@@ -56,11 +52,7 @@ struct dbox_mailbox {
        /* set while rebuilding indexes with converted maildir files */
        struct maildir_keywords_sync_ctx *maildir_sync_keywords;
 
-       uoff_t rotate_size, rotate_min_size;
-       unsigned int rotate_days;
-
        ARRAY_DEFINE(open_files, struct dbox_file *);
-       unsigned int max_open_files;
 
        const char *path, *alt_path;
 };
index 1c0487ffd71f827f3bca7afaf5ab79d5cf635412..2325efd6aee4b5fc8fa1609ab807dfbe37d34385 100644 (file)
@@ -418,13 +418,14 @@ void index_mail_cache_add(struct index_mail *mail, enum index_cache_field field,
 void index_mail_cache_add_idx(struct index_mail *mail, unsigned int field_idx,
                              const void *data, size_t data_size)
 {
+       const struct mail_storage_settings *set = mail->ibox->box.storage->set;
        const struct mail_index_header *hdr;
 
-       if (mail->ibox->mail_cache_min_mail_count > 0) {
+       if (set->mail_cache_min_mail_count > 0) {
                /* First check if we've configured caching not to be used with
                   low enough message count. */
                hdr = mail_index_get_header(mail->ibox->view);
-               if (hdr->messages_count < mail->ibox->mail_cache_min_mail_count)
+               if (hdr->messages_count < set->mail_cache_min_mail_count)
                        return;
        }
 
index 5dc73984b1637f3558c6c24ce4cd19076e0d87ff..6b11fa8e9cbce0ec0e51315abd7bae2ffbcdd310 100644 (file)
@@ -17,9 +17,6 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
-#define DEFAULT_CACHE_FIELDS ""
-#define DEFAULT_NEVER_CACHE_FIELDS "imap.envelope"
-
 /* How many seconds to keep index opened for reuse after it's been closed */
 #define INDEX_CACHE_TIMEOUT 10
 /* How many closed indexes to keep */
@@ -305,29 +302,20 @@ static void set_cache_decisions(const char *set, const char *fields,
 
 static void index_cache_register_defaults(struct index_mailbox *ibox)
 {
+       const struct mail_storage_settings *set = ibox->box.storage->set;
        static bool initialized = FALSE;
        struct mail_cache *cache = ibox->cache;
-       const char *cache_env, *never_env, *env;
 
        if (!initialized) {
                initialized = TRUE;
 
-               cache_env = getenv("MAIL_CACHE_FIELDS");
-               if (cache_env == NULL)
-                       cache_env = DEFAULT_CACHE_FIELDS;
-               never_env = getenv("MAIL_NEVER_CACHE_FIELDS");
-               if (never_env == NULL)
-                       never_env = DEFAULT_NEVER_CACHE_FIELDS;
-
-               set_cache_decisions("mail_cache_fields", cache_env,
+               set_cache_decisions("mail_cache_fields",
+                                   set->mail_cache_fields,
                                    MAIL_CACHE_DECISION_TEMP);
-               set_cache_decisions("mail_never_cache_fields", never_env,
+               set_cache_decisions("mail_never_cache_fields",
+                                   set->mail_never_cache_fields,
                                    MAIL_CACHE_DECISION_NO |
                                    MAIL_CACHE_DECISION_FORCED);
-
-               env = getenv("MAIL_CACHE_MIN_MAIL_COUNT");
-               if (env != NULL)
-                       ibox->mail_cache_min_mail_count = atoi(env);
        }
 
        ibox->cache_fields = i_malloc(sizeof(global_cache_fields));
@@ -399,20 +387,9 @@ void index_storage_mailbox_open(struct index_mailbox *ibox)
 
        i_assert(!ibox->box.opened);
 
+       index_flags = mail_storage_settings_to_index_flags(storage->set);
        if (!ibox->move_to_memory)
                index_flags |= MAIL_INDEX_OPEN_FLAG_CREATE;
-#ifndef MMAP_CONFLICTS_WRITE
-       if ((storage->flags & MAIL_STORAGE_FLAG_MMAP_DISABLE) != 0)
-#endif
-               index_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE;
-       if ((storage->flags & MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0)
-               index_flags |= MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL;
-       if ((storage->flags & MAIL_STORAGE_FLAG_NFS_FLUSH_INDEX) != 0)
-               index_flags |= MAIL_INDEX_OPEN_FLAG_NFS_FLUSH;
-       if ((storage->flags & MAIL_STORAGE_FLAG_FSYNC_DISABLE) != 0) {
-               index_flags |= MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE;
-               ibox->fsync_disable = TRUE;
-       }
 
        ret = mail_index_open(ibox->index, index_flags, storage->lock_method);
        if (ret <= 0 || ibox->move_to_memory) {
@@ -563,7 +540,7 @@ bool index_keyword_is_valid(struct mailbox *box, const char *keyword,
                        return FALSE;
                }
        }
-       if (i > ibox->box.storage->keyword_max_len) {
+       if (i > ibox->box.storage->set->mail_max_keyword_length) {
                *error_r = "Keyword length too long";
                return FALSE;
        }
index bde4f9fee190ec19dbf1c131872857ce2e24adb0..3faf74d4cf1c06e7f6ff9bd030d443e5fd2931bf 100644 (file)
@@ -47,7 +47,6 @@ struct index_mailbox {
 
        const ARRAY_TYPE(keywords) *keyword_names;
        struct mail_cache_field *cache_fields;
-       unsigned int mail_cache_min_mail_count;
 
        ARRAY_TYPE(seq_range) recent_flags;
        uint32_t recent_flags_prev_uid;
index d45c75f5cd438b77c28278540adca064e538f215..218d798f543340455bd5214a073c91da381a23db 100644 (file)
@@ -2,6 +2,7 @@ noinst_LIBRARIES = libstorage_maildir.a
 
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
+       -I$(top_srcdir)/src/lib-settings \
        -I$(top_srcdir)/src/lib-mail \
        -I$(top_srcdir)/src/lib-imap \
        -I$(top_srcdir)/src/lib-index \
@@ -14,6 +15,7 @@ libstorage_maildir_a_SOURCES = \
        maildir-keywords.c \
        maildir-mail.c \
        maildir-save.c \
+       maildir-settings.c \
        maildir-storage.c \
        maildir-sync.c \
        maildir-sync-index.c \
@@ -25,6 +27,7 @@ headers = \
        maildir-filename.h \
        maildir-keywords.h \
        maildir-storage.h \
+       maildir-settings.h \
        maildir-sync.h \
        maildir-uidlist.h
 
index b3bc7a8d4c0089ba5d387ecc4435b006e835c149..050abb81819a8c235bccc6278e5beac0532d0f71 100644 (file)
@@ -94,8 +94,7 @@ static int do_hardlink(struct maildir_mailbox *mbox, const char *path,
                        do_save_mail_vsize(path, ctx);
        }
 
-       if ((mbox->storage->storage.flags &
-            MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0)
+       if (mbox->storage->storage.set->mail_nfs_storage)
                ret = nfs_safe_link(path, str_c(ctx->dest_path), FALSE);
        else
                ret = link(path, str_c(ctx->dest_path));
@@ -162,7 +161,8 @@ maildir_copy_hardlink(struct maildir_transaction_context *t, struct mail *mail,
        memset(&do_ctx, 0, sizeof(do_ctx));
        do_ctx.dest_path = str_new(default_pool, 512);
 
-       if (dest_mbox->storage->copy_preserve_filename && src_mbox != NULL) {
+       if (dest_mbox->storage->set->maildir_copy_preserve_filename &&
+           src_mbox != NULL) {
                enum maildir_uidlist_rec_flag src_flags;
                const char *src_fname;
 
@@ -268,7 +268,7 @@ int maildir_copy(struct mailbox_transaction_context *_t, struct mail *mail,
        struct maildir_mailbox *mbox = (struct maildir_mailbox *)t->ictx.ibox;
        int ret;
 
-       if (mbox->storage->copy_with_hardlinks &&
+       if (mbox->storage->set->maildir_copy_with_hardlinks &&
            maildir_compatible_file_modes(&mbox->ibox.box, mail->box)) {
                T_BEGIN {
                        ret = maildir_copy_hardlink(t, mail, flags,
index 3c8ccaf1a32f044750257a053e8f98217a3237ff..5488b87eab493141d528a9754a8b728f788c85d6 100644 (file)
@@ -75,10 +75,9 @@ maildir_keywords_init_readonly(struct mailbox *box)
                                     strcase_hash, (hash_cmp_callback_t *)strcasecmp);
 
        mk->dotlock_settings.use_excl_lock =
-               (box->storage->flags & MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0;
+               box->storage->set->dotlock_use_excl;
        mk->dotlock_settings.nfs_flush =
-               (box->storage->flags &
-                MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0;
+               box->storage->set->mail_nfs_storage;
        mk->dotlock_settings.timeout = KEYWORDS_LOCK_STALE_TIMEOUT + 2;
        mk->dotlock_settings.stale_timeout = KEYWORDS_LOCK_STALE_TIMEOUT;
        mk->dotlock_settings.temp_prefix =
@@ -117,7 +116,7 @@ static int maildir_keywords_sync(struct maildir_keywords *mk)
            we rely on stat()'s timestamp and don't bother handling ESTALE
            errors. */
 
-       if ((mk->storage->flags & MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0) {
+       if (mk->storage->set->mail_nfs_storage) {
                /* file is updated only by replacing it, no need to flush
                   attribute cache */
                nfs_flush_file_handle_cache(mk->path);
index 8414ca6f8697d488e2f13a4cadf10b8148caffb5..98b414b2c80066c953aac3084bf4fa0288d5260d 100644 (file)
@@ -378,11 +378,10 @@ int maildir_save_begin(struct mail_save_context *_ctx, struct istream *input)
                if (ctx->fd == -1)
                        ctx->failed = TRUE;
                else {
-                       ctx->input = (ctx->mbox->storage->storage.flags &
-                                     MAIL_STORAGE_FLAG_SAVE_CRLF) != 0 ?
-                               i_stream_create_crlf(input) :
-                               i_stream_create_lf(input);
-
+                       if (ctx->mbox->storage->storage.set->mail_save_crlf)
+                               ctx->input = i_stream_create_crlf(input);
+                       else
+                               ctx->input = i_stream_create_lf(input);
                        maildir_save_add(t, fname, _ctx->flags, _ctx->keywords,
                                         _ctx->dest_mail);
                }
diff --git a/src/lib-storage/index/maildir/maildir-settings.c b/src/lib-storage/index/maildir/maildir-settings.c
new file mode 100644 (file)
index 0000000..01cbe9a
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "mail-storage-settings.h"
+#include "maildir-settings.h"
+
+#include <stddef.h>
+
+#undef DEF
+#define DEF(type, name) \
+       { type, #name, offsetof(struct maildir_settings, name), NULL }
+
+static struct setting_define maildir_setting_defines[] = {
+       DEF(SET_BOOL, maildir_stat_dirs),
+       DEF(SET_BOOL, maildir_copy_with_hardlinks),
+       DEF(SET_BOOL, maildir_copy_preserve_filename),
+
+       SETTING_DEFINE_LIST_END
+};
+
+static struct maildir_settings maildir_default_settings = {
+       MEMBER(maildir_stat_dirs) FALSE,
+       MEMBER(maildir_copy_with_hardlinks) TRUE,
+       MEMBER(maildir_copy_preserve_filename) FALSE
+};
+
+static struct setting_parser_info maildir_setting_parser_info = {
+       MEMBER(defines) maildir_setting_defines,
+       MEMBER(defaults) &maildir_default_settings,
+
+       MEMBER(parent) &mail_user_setting_parser_info,
+       MEMBER(dynamic_parsers) NULL,
+
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) (size_t)-1,
+       MEMBER(struct_size) sizeof(struct maildir_settings)
+};
+
+const struct setting_parser_info *maildir_get_setting_parser_info(void)
+{
+       return &maildir_setting_parser_info;
+}
+
diff --git a/src/lib-storage/index/maildir/maildir-settings.h b/src/lib-storage/index/maildir/maildir-settings.h
new file mode 100644 (file)
index 0000000..37355a7
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef MAILDIR_SETTINGS_H
+#define MAILDIR_SETTINGS_H
+
+struct maildir_settings {
+       bool maildir_stat_dirs;
+       bool maildir_copy_with_hardlinks;
+       bool maildir_copy_preserve_filename;
+};
+
+const struct setting_parser_info *maildir_get_setting_parser_info(void);
+
+#endif
index 71ea3bc9135998d83c38b22c5e0a9ecd246e1084..011ae3ef09525d50b46410ac71755c5b90278890 100644 (file)
@@ -63,9 +63,8 @@ maildir_get_list_settings(struct mailbox_list_settings *list_set,
                          const char *data, struct mail_storage *storage,
                          const char **layout_r, const char **error_r)
 {
-       enum mail_storage_flags flags = storage->flags;
        struct mail_user *user = storage->ns->user;
-       bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+       bool debug = storage->set->mail_debug;
        const char *path, *home;
 
        *layout_r = MAILDIR_PLUSPLUS_DRIVER_NAME;
@@ -75,7 +74,8 @@ maildir_get_list_settings(struct mailbox_list_settings *list_set,
        list_set->maildir_name = "";
 
        if (data == NULL || *data == '\0') {
-               if ((flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) != 0) {
+               if ((storage->flags &
+                    MAIL_STORAGE_FLAG_NO_AUTODETECTION) != 0) {
                        *error_r = "Root mail directory not given";
                        return -1;
                }
@@ -229,6 +229,8 @@ maildir_create(struct mail_storage *_storage, const char *data,
        if (mailbox_list_alloc(layout, &list, error_r) < 0)
                return -1;
 
+       storage->set = mail_storage_get_driver_settings(_storage);
+
        _storage->list = list;
        storage->list_module_ctx.super = list->v;
        if (strcmp(layout, MAILDIR_PLUSPLUS_DRIVER_NAME) == 0) {
@@ -248,14 +250,7 @@ maildir_create(struct mail_storage *_storage, const char *data,
                                storage, &storage->list_module_ctx);
 
        /* finish list init after we've overridden vfuncs */
-       mailbox_list_init(list, _storage->ns, &list_set,
-                         mail_storage_get_list_flags(flags));
-
-       storage->copy_with_hardlinks =
-               getenv("MAILDIR_COPY_WITH_HARDLINKS") != NULL;
-       storage->copy_preserve_filename =
-               getenv("MAILDIR_COPY_PRESERVE_FILENAME") != NULL;
-       storage->stat_dirs = getenv("MAILDIR_STAT_DIRS") != NULL;
+       mailbox_list_init(list, _storage->ns, &list_set, 0);
 
        storage->temp_prefix = mailbox_list_get_temp_prefix(list);
        if (list_set.control_dir == NULL) {
@@ -267,15 +262,13 @@ maildir_create(struct mail_storage *_storage, const char *data,
        return 0;
 }
 
-static bool maildir_autodetect(const char *data, enum mail_storage_flags flags)
+static bool maildir_autodetect(const struct mail_namespace *ns)
 {
-       bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+       bool debug = ns->mail_set->mail_debug;
        struct stat st;
        const char *path;
 
-       data = t_strcut(data, ':');
-
-       path = t_strconcat(data, "/cur", NULL);
+       path = t_strconcat(t_strcut(ns->set->location, ':'), "/cur", NULL);
        if (stat(path, &st) < 0) {
                if (debug)
                        i_info("maildir autodetect: stat(%s) failed: %m", path);
@@ -629,7 +622,7 @@ maildir_get_unlink_dest(struct mailbox_list *list, const char *name)
        const char *root_dir;
        char sep;
 
-       if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0 &&
+       if (list->mail_set->mail_full_filesystem_access &&
            (*name == '/' || *name == '~'))
                return NULL;
 
@@ -1014,7 +1007,7 @@ maildirplusplus_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
 
        /* Check files beginning with .nfs always because they may be
           temporary files created by the kernel */
-       if (storage->stat_dirs || *fname == '\0' ||
+       if (storage->set->maildir_stat_dirs || *fname == '\0' ||
            strncmp(fname, ".nfs", 4) == 0) {
                const char *path;
                struct stat st;
@@ -1071,6 +1064,7 @@ struct mail_storage maildir_storage = {
        MEMBER(mailbox_is_file) FALSE,
 
        {
+                maildir_get_setting_parser_info,
                maildir_class_init,
                maildir_class_deinit,
                maildir_alloc,
index ed1ecd5e5fac16d8a9d9236d718313b97933d680..f8764d40f4d0bb5810ae14c4702cbdb976b5238a 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef MAILDIR_STORAGE_H
 #define MAILDIR_STORAGE_H
 
+#include "maildir-settings.h"
+
 #define MAILDIR_STORAGE_NAME "maildir"
 #define MAILDIR_SUBSCRIPTION_FILE_NAME "subscriptions"
 #define MAILDIR_INDEX_PREFIX "dovecot.index"
@@ -69,14 +71,12 @@ struct maildir_storage {
        struct mail_storage storage;
 
        union mailbox_list_module_context list_module_ctx;
+       const struct maildir_settings *set;
        const char *temp_prefix;
 
        uint32_t maildir_list_ext_id;
 
-       unsigned int copy_with_hardlinks:1;
-       unsigned int copy_preserve_filename:1;
        unsigned int save_size_in_filename:1;
-       unsigned int stat_dirs:1;
 };
 
 struct maildir_mailbox {
index 0fe4911e73a784a27bb4bf81121d1587a54b5b6b..0f1ea95f2f37eb8cde4dfb11b5c43efad64c9091 100644 (file)
@@ -236,10 +236,9 @@ maildir_uidlist_init_readonly(struct index_mailbox *ibox)
 
        uidlist->dotlock_settings.use_io_notify = TRUE;
        uidlist->dotlock_settings.use_excl_lock =
-               (box->storage->flags & MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0;
+               box->storage->set->dotlock_use_excl;
        uidlist->dotlock_settings.nfs_flush =
-               (box->storage->flags &
-                MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0;
+               box->storage->set->mail_nfs_storage;
        uidlist->dotlock_settings.timeout =
                MAILDIR_UIDLIST_LOCK_STALE_TIMEOUT + 2;
        uidlist->dotlock_settings.stale_timeout =
@@ -711,7 +710,7 @@ maildir_uidlist_stat(struct maildir_uidlist *uidlist, struct stat *st_r)
 {
        struct mail_storage *storage = uidlist->ibox->box.storage;
 
-       if ((storage->flags & MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0) {
+       if (storage->set->mail_nfs_storage) {
                nfs_flush_file_handle_cache(uidlist->path);
                nfs_flush_attr_cache_unlocked(uidlist->path);
        }
@@ -745,7 +744,7 @@ maildir_uidlist_has_changed(struct maildir_uidlist *uidlist, bool *recreated_r)
                return 1;
        }
 
-       if ((storage->flags & MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0) {
+       if (storage->set->mail_nfs_storage) {
                /* NFS: either the file hasn't been changed, or it has already
                   been deleted and the inodes just happen to be the same.
                   check if the fd is still valid. */
@@ -1432,7 +1431,6 @@ int maildir_uidlist_sync_next(struct maildir_uidlist_sync_ctx *ctx,
 
        if (ctx->failed)
                return -1;
-
        for (p = filename; *p != '\0'; p++) {
                if (*p == 13 || *p == 10) {
                        i_warning("Maildir %s: Ignoring a file with #0x%x: %s",
index 72e095ebfe9e37a7aa077d54db7e62ad2d505a0e..54768a83da079a2c9ddede4478393189cf428fa7 100644 (file)
@@ -2,6 +2,7 @@ noinst_LIBRARIES = libstorage_mbox.a
 
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
+       -I$(top_srcdir)/src/lib-settings \
        -I$(top_srcdir)/src/lib-mail \
        -I$(top_srcdir)/src/lib-imap \
        -I$(top_srcdir)/src/lib-index \
@@ -15,6 +16,7 @@ libstorage_mbox_a_SOURCES = \
        mbox-mail.c \
        mbox-md5.c \
        mbox-save.c \
+       mbox-settings.c \
        mbox-sync-parse.c \
        mbox-sync-rewrite.c \
        mbox-sync-update.c \
@@ -27,6 +29,7 @@ headers = \
        mbox-file.h \
        mbox-lock.h \
        mbox-md5.h \
+       mbox-settings.h \
        mbox-storage.h \
        mbox-sync-private.h
 
index 50a3eab4109ec88d695124cce7d7e1d937b4a0b2..3a6964780b930902302879141fb0e00e4f05cf6a 100644 (file)
 /* 0.1 .. 0.2msec */
 #define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
 
-/* lock methods to use in wanted order */
-#define DEFAULT_READ_LOCK_METHODS "fcntl"
-#define DEFAULT_WRITE_LOCK_METHODS "dotlock fcntl"
-/* lock timeout */
-#define MBOX_DEFAULT_LOCK_TIMEOUT (5*60)
-/* assume stale dotlock if mbox file hasn't changed for n seconds */
-#define DEFAULT_DOTLOCK_CHANGE_TIMEOUT (120)
-
 enum mbox_lock_type {
        MBOX_LOCK_DOTLOCK,
        MBOX_LOCK_DOTLOCK_TRY,
@@ -92,11 +84,6 @@ static struct mbox_lock_data lock_data[] = {
        { 0, NULL, NULL }
 };
 
-static bool lock_settings_initialized = FALSE;
-static enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1];
-static enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
-static int lock_timeout, dotlock_change_timeout;
-
 static int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
                          time_t max_wait_time, int idx);
 static int mbox_unlock_files(struct mbox_lock_context *ctx);
@@ -133,18 +120,16 @@ static void mbox_read_lock_methods(const char *str, const char *env,
        locks[dest] = (enum mbox_lock_type)-1;
 }
 
-static void mbox_init_lock_settings(void)
+static void mbox_init_lock_settings(struct mbox_storage *storage)
 {
-       const char *str;
+       enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1];
+       enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
        int r, w;
 
-       str = getenv("MBOX_READ_LOCKS");
-       if (str == NULL) str = DEFAULT_READ_LOCK_METHODS;
-       mbox_read_lock_methods(str, "MBOX_READ_LOCKS", read_locks);
-
-       str = getenv("MBOX_WRITE_LOCKS");
-       if (str == NULL) str = DEFAULT_WRITE_LOCK_METHODS;
-       mbox_read_lock_methods(str, "MBOX_WRITE_LOCKS", write_locks);
+       mbox_read_lock_methods(storage->set->mbox_read_locks,
+                              "mbox_read_locks", read_locks);
+       mbox_read_lock_methods(storage->set->mbox_write_locks,
+                              "mbox_write_locks", write_locks);
 
        /* check that read/write list orders match. write_locks must contain
           at least read_locks and possibly more. */
@@ -161,14 +146,17 @@ static void mbox_init_lock_settings(void)
                        "(and possibly more)");
        }
 
-       str = getenv("MBOX_LOCK_TIMEOUT");
-       lock_timeout = str == NULL ? MBOX_DEFAULT_LOCK_TIMEOUT : atoi(str);
+       storage->read_locks = p_new(storage->storage.pool,
+                                   enum mbox_lock_type, MBOX_LOCK_COUNT+1);
+       memcpy(storage->read_locks, read_locks,
+              sizeof(*storage->read_locks) * (MBOX_LOCK_COUNT+1));
 
-       str = getenv("MBOX_DOTLOCK_CHANGE_TIMEOUT");
-       dotlock_change_timeout = str == NULL ?
-               DEFAULT_DOTLOCK_CHANGE_TIMEOUT : atoi(str);
+       storage->write_locks = p_new(storage->storage.pool,
+                                    enum mbox_lock_type, MBOX_LOCK_COUNT+1);
+       memcpy(storage->write_locks, write_locks,
+              sizeof(*storage->write_locks) * (MBOX_LOCK_COUNT+1));
 
-        lock_settings_initialized = TRUE;
+        storage->lock_settings_initialized = TRUE;
 }
 
 static int mbox_file_open_latest(struct mbox_lock_context *ctx, int lock_type)
@@ -221,7 +209,8 @@ static bool dotlock_callback(unsigned int secs_left, bool stale, void *context)
                lock_types = ctx->lock_type == F_WRLCK ||
                        (ctx->lock_type == F_UNLCK &&
                         ctx->mbox->mbox_lock_type == F_WRLCK) ?
-                       write_locks : read_locks;
+                       ctx->mbox->storage->write_locks :
+                       ctx->mbox->storage->read_locks;
 
                for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) {
                        if (lock_types[i] == MBOX_LOCK_DOTLOCK)
@@ -370,12 +359,10 @@ mbox_lock_dotlock_int(struct mbox_lock_context *ctx, int lock_type, bool try)
         ctx->dotlock_last_stale = -1;
 
        memset(&set, 0, sizeof(set));
-       set.use_excl_lock = (mbox->storage->storage.flags &
-                            MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0;
-       set.nfs_flush = (mbox->storage->storage.flags &
-                        MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0;
-       set.timeout = lock_timeout;
-       set.stale_timeout = dotlock_change_timeout;
+       set.use_excl_lock = mbox->storage->storage.set->dotlock_use_excl;
+       set.nfs_flush = mbox->storage->storage.set->mail_nfs_storage;
+       set.timeout = mbox->storage->set->mbox_lock_timeout;
+       set.stale_timeout = mbox->storage->set->mbox_dotlock_change_timeout;
        set.callback = dotlock_callback;
        set.context = ctx;
 
@@ -588,7 +575,8 @@ static int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
 
        lock_types = lock_type == F_WRLCK ||
                (lock_type == F_UNLCK && ctx->mbox->mbox_lock_type == F_WRLCK) ?
-               write_locks : read_locks;
+               ctx->mbox->storage->write_locks :
+               ctx->mbox->storage->read_locks;
        for (i = idx; lock_types[i] != (enum mbox_lock_type)-1; i++) {
                type = lock_types[i];
                lock_status = lock_type != F_UNLCK;
@@ -616,8 +604,8 @@ static int mbox_update_locking(struct mbox_mailbox *mbox, int lock_type,
 
         index_storage_lock_notify_reset(&mbox->ibox);
 
-       if (!lock_settings_initialized)
-                mbox_init_lock_settings();
+       if (!mbox->storage->lock_settings_initialized)
+                mbox_init_lock_settings(mbox->storage);
 
        if (mbox->mbox_fd == -1 && mbox->mbox_file_stream != NULL) {
                /* read-only mbox stream. no need to lock. */
@@ -626,7 +614,7 @@ static int mbox_update_locking(struct mbox_mailbox *mbox, int lock_type,
                return 1;
        }
 
-       max_wait_time = time(NULL) + lock_timeout;
+       max_wait_time = time(NULL) + mbox->storage->set->mbox_lock_timeout;
 
        memset(&ctx, 0, sizeof(ctx));
        ctx.mbox = mbox;
@@ -634,6 +622,9 @@ static int mbox_update_locking(struct mbox_mailbox *mbox, int lock_type,
        if (mbox->mbox_lock_type == F_WRLCK) {
                /* dropping to shared lock. first drop those that we
                   don't remove completely. */
+               const enum mbox_lock_type *read_locks =
+                        mbox->storage->read_locks;
+
                for (i = 0; i < MBOX_LOCK_COUNT; i++)
                        ctx.lock_status[i] = 1;
                for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
@@ -658,6 +649,11 @@ static int mbox_update_locking(struct mbox_mailbox *mbox, int lock_type,
        if (drop_locks) {
                /* dropping to shared lock: drop the locks that are only
                   in write list */
+               const enum mbox_lock_type *read_locks =
+                        mbox->storage->read_locks;
+               const enum mbox_lock_type *write_locks =
+                       mbox->storage->write_locks;
+
                memset(ctx.lock_status, 0, sizeof(ctx.lock_status));
                for (i = 0; write_locks[i] != (enum mbox_lock_type)-1; i++)
                        ctx.lock_status[write_locks[i]] = 1;
@@ -691,8 +687,7 @@ int mbox_lock(struct mbox_mailbox *mbox, int lock_type,
                if (ret <= 0)
                        return ret;
 
-               if ((mbox->storage->storage.flags &
-                    MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0) {
+               if (mbox->storage->storage.set->mail_nfs_storage) {
                        if (fcntl_locked) {
                                nfs_flush_attr_cache_fd_locked(mbox->path,
                                                               mbox->mbox_fd);
index 8487a60dcb8001a02731d653d9f3c464927ade28..1c5d0fd4b27acfb9a2f92ffd1d2c94567fb85262 100644 (file)
@@ -208,8 +208,8 @@ mbox_mail_get_next_offset(struct index_mail *mail, uoff_t *next_offset_r)
 
        if (seq == hdr->messages_count) {
                /* last message, use the synced mbox size */
-               trailer_size = (mbox->storage->storage.flags &
-                               MAIL_STORAGE_FLAG_SAVE_CRLF) != 0 ? 2 : 1;
+               trailer_size =
+                       mbox->storage->storage.set->mail_save_crlf ? 2 : 1;
                *next_offset_r = mbox->mbox_hdr.sync_size - trailer_size;
        } else {
                if (mbox_file_lookup_offset(mbox, view, seq + 1,
index 82a3b69ef0b7875741bebc0b972354b1a5b06480..cceefeeae4fd9e7a12ad656670f1a493b98594e3 100644 (file)
@@ -393,8 +393,7 @@ mbox_save_get_input_stream(struct mbox_save_context *ctx, struct istream *input)
        }
 
        /* convert linefeeds to wanted format */
-       ret = (ctx->mbox->storage->storage.flags &
-              MAIL_STORAGE_FLAG_SAVE_CRLF) != 0 ?
+       ret = ctx->mbox->storage->storage.set->mail_save_crlf ?
                i_stream_create_crlf(filter) : i_stream_create_lf(filter);
        i_stream_unref(&filter);
 
@@ -542,8 +541,7 @@ static int mbox_save_body(struct mbox_save_context *ctx)
                   this makes it impossible to save a mail that doesn't
                   end with LF though. */
                const char *linefeed =
-                       (ctx->mbox->storage->storage.flags &
-                        MAIL_STORAGE_FLAG_SAVE_CRLF) != 0 ?
+                       ctx->mbox->storage->storage.set->mail_save_crlf ?
                        "\r\n" : "\n";
                if (o_stream_send_str(ctx->output, linefeed) < 0)
                        return write_error(ctx);
diff --git a/src/lib-storage/index/mbox/mbox-settings.c b/src/lib-storage/index/mbox/mbox-settings.c
new file mode 100644 (file)
index 0000000..801cb7f
--- /dev/null
@@ -0,0 +1,53 @@
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "mail-storage-settings.h"
+#include "mbox-settings.h"
+
+#include <stddef.h>
+
+#undef DEF
+#define DEF(type, name) \
+       { type, #name, offsetof(struct mbox_settings, name), NULL }
+
+static struct setting_define mbox_setting_defines[] = {
+       DEF(SET_STR, mbox_read_locks),
+       DEF(SET_STR, mbox_write_locks),
+       DEF(SET_UINT, mbox_lock_timeout),
+       DEF(SET_UINT, mbox_dotlock_change_timeout),
+       DEF(SET_UINT, mbox_min_index_size),
+       DEF(SET_BOOL, mbox_dirty_syncs),
+       DEF(SET_BOOL, mbox_very_dirty_syncs),
+       DEF(SET_BOOL, mbox_lazy_writes),
+
+       SETTING_DEFINE_LIST_END
+};
+
+static struct mbox_settings mbox_default_settings = {
+       MEMBER(mbox_read_locks) "fcntl",
+       MEMBER(mbox_write_locks) "dotlock fcntl",
+       MEMBER(mbox_lock_timeout) 5*60,
+       MEMBER(mbox_dotlock_change_timeout) 2*60,
+       MEMBER(mbox_min_index_size) 0,
+       MEMBER(mbox_dirty_syncs) TRUE,
+       MEMBER(mbox_very_dirty_syncs) FALSE,
+       MEMBER(mbox_lazy_writes) TRUE
+};
+
+static struct setting_parser_info mbox_setting_parser_info = {
+       MEMBER(defines) mbox_setting_defines,
+       MEMBER(defaults) &mbox_default_settings,
+
+       MEMBER(parent) &mail_user_setting_parser_info,
+       MEMBER(dynamic_parsers) NULL,
+
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) (size_t)-1,
+       MEMBER(struct_size) sizeof(struct mbox_settings)
+};
+
+const struct setting_parser_info *mbox_get_setting_parser_info(void)
+{
+       return &mbox_setting_parser_info;
+}
diff --git a/src/lib-storage/index/mbox/mbox-settings.h b/src/lib-storage/index/mbox/mbox-settings.h
new file mode 100644 (file)
index 0000000..7c3188c
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef MBOX_SETTINGS_H
+#define MBOX_SETTINGS_H
+
+struct mbox_settings {
+       const char *mbox_read_locks;
+       const char *mbox_write_locks;
+       unsigned int mbox_lock_timeout;
+       unsigned int mbox_dotlock_change_timeout;
+       unsigned int mbox_min_index_size;
+       bool mbox_dirty_syncs;
+       bool mbox_very_dirty_syncs;
+       bool mbox_lazy_writes;
+};
+
+const struct setting_parser_info *mbox_get_setting_parser_info(void);
+
+#endif
index 416258898dc21be3d7473aa66c4a769091e4a4c6..9dfd875544d3014fc6930417d991036a2315ec35 100644 (file)
@@ -155,13 +155,13 @@ static bool mbox_is_dir(const char *path, const char *name, bool debug)
        return TRUE;
 }
 
-static bool mbox_autodetect(const char *data, enum mail_storage_flags flags)
+static bool mbox_autodetect(const struct mail_namespace *ns)
 {
-       bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+       bool debug = ns->mail_set->mail_debug;
+       const char *data = ns->set->location;
        const char *path;
 
        path = t_strcut(data, ':');
-
        if (debug) {
                if (strchr(data, ':') != NULL) {
                        i_info("mbox autodetect: data=%s, splitting ':' -> %s",
@@ -187,8 +187,10 @@ static bool mbox_autodetect(const char *data, enum mail_storage_flags flags)
 
 static const char *get_root_dir(struct mail_storage *storage)
 {
+       struct mail_namespace auto_ns;
+       struct mail_namespace_settings ns_set;
        const char *home, *path;
-       bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+       bool debug = storage->set->mail_debug;
 
        if (mail_user_get_home(storage->ns->user, &home) > 0) {
                path = t_strconcat(home, "/mail", NULL);
@@ -212,12 +214,17 @@ static const char *get_root_dir(struct mail_storage *storage)
 
        if (debug)
                i_info("mbox: checking if we are chrooted:");
-       if (mbox_autodetect("", storage->flags))
+
+       memset(&ns_set, 0, sizeof(ns_set));
+       ns_set.location = "";
+       memset(&auto_ns, 0, sizeof(auto_ns));
+       auto_ns.set = &ns_set;
+       auto_ns.mail_set = storage->set;
+       if (mbox_autodetect(&auto_ns))
                return "/";
 
        if (debug)
                i_info("mbox: root mail directory not found");
-
        return NULL;
 }
 
@@ -270,7 +277,7 @@ static const char *create_root_dir(struct mail_storage *storage,
                return NULL;
        }
 
-       if ((storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0)
+       if (storage->set->mail_debug)
                i_info("mbox: root directory created: %s", path);
        return path;
 }
@@ -281,7 +288,7 @@ mbox_get_list_settings(struct mailbox_list_settings *list_set,
                       const char **layout_r, const char **error_r)
 {
        enum mail_storage_flags flags = storage->flags;
-       bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+       bool debug = storage->set->mail_debug;
        const char *p;
        struct stat st;
        bool autodetect;
@@ -453,6 +460,8 @@ static int mbox_create(struct mail_storage *_storage, const char *data,
        if (mailbox_list_alloc(layout, &_storage->list, error_r) < 0)
                return -1;
 
+       storage->set = mail_storage_get_driver_settings(_storage);
+
        storage->list_module_ctx.super = _storage->list->v;
        if (strcmp(layout, "fs") == 0 && *list_set.maildir_name == '\0') {
                /* have to use .imap/ directories */
@@ -468,7 +477,6 @@ static int mbox_create(struct mail_storage *_storage, const char *data,
 
        /* finish list init after we've overridden vfuncs */
        mailbox_list_init(_storage->list, _storage->ns, &list_set,
-                         mail_storage_get_list_flags(_storage->flags) |
                          MAILBOX_LIST_FLAG_MAILBOX_FILES);
        return 0;
 }
@@ -515,16 +523,9 @@ static int verify_inbox(struct mail_storage *storage)
 
 static bool want_memory_indexes(struct mbox_storage *storage, const char *path)
 {
-       const char *env;
        struct stat st;
-       unsigned int min_size;
 
-       env = getenv("MBOX_MIN_INDEX_SIZE");
-       if (env == NULL)
-               return FALSE;
-
-       min_size = strtoul(env, NULL, 10);
-       if (min_size == 0)
+       if (storage->set->mbox_min_index_size == 0)
                return FALSE;
 
        if (stat(path, &st) < 0) {
@@ -536,7 +537,7 @@ static bool want_memory_indexes(struct mbox_storage *storage, const char *path)
                        return FALSE;
                }
        }
-       return st.st_size / 1024 < min_size;
+       return st.st_size / 1024 < storage->set->mbox_min_index_size;
 }
 
 static void mbox_lock_touch_timeout(struct mbox_mailbox *mbox)
@@ -569,10 +570,6 @@ mbox_alloc_mailbox(struct mbox_storage *storage, struct mail_index *index,
                                        sizeof(mbox->mbox_hdr),
                                        sizeof(uint64_t), sizeof(uint64_t));
 
-        mbox->mbox_very_dirty_syncs = getenv("MBOX_VERY_DIRTY_SYNCS") != NULL;
-       mbox->mbox_do_dirty_syncs = mbox->mbox_very_dirty_syncs ||
-               getenv("MBOX_DIRTY_SYNCS") != NULL;
-
        if ((storage->storage.flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) != 0)
                mbox->mbox_save_md5 = TRUE;
 
@@ -989,6 +986,7 @@ struct mail_storage mbox_storage = {
        MEMBER(mailbox_is_file) TRUE,
 
        {
+                mbox_get_setting_parser_info,
                mbox_class_init,
                mbox_class_deinit,
                mbox_alloc,
index e61b95ee1c2877bfdbb85c942ce9256bf718cdb1..a06d12cc4dfd0a75265c401f9f4a39812652102a 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef MBOX_STORAGE_H
 #define MBOX_STORAGE_H
 
+#include "index-storage.h"
+#include "mbox-settings.h"
+#include "mailbox-list-private.h"
+
 /* Padding to leave in X-Keywords header when rewriting mbox */
 #define MBOX_HEADER_PADDING 50
 /* Don't write Content-Length header unless it's value is larger than this. */
@@ -11,9 +15,6 @@
 #define MBOX_INDEX_PREFIX "dovecot.index"
 #define MBOX_INDEX_DIR_NAME ".imap"
 
-#include "index-storage.h"
-#include "mailbox-list-private.h"
-
 struct mbox_index_header {
        uint64_t sync_size;
        uint32_t sync_mtime;
@@ -23,6 +24,11 @@ struct mbox_index_header {
 struct mbox_storage {
        struct mail_storage storage;
 
+       const struct mbox_settings *set;
+       enum mbox_lock_type *read_locks;
+       enum mbox_lock_type *write_locks;
+       unsigned int lock_settings_initialized:1;
+
        union mailbox_list_module_context list_module_ctx;
 };
 
@@ -49,8 +55,6 @@ struct mbox_mailbox {
        unsigned int no_mbox_file:1;
        unsigned int invalid_mbox_file:1;
        unsigned int mbox_broken_offsets:1;
-       unsigned int mbox_do_dirty_syncs:1;
-       unsigned int mbox_very_dirty_syncs:1;
        unsigned int mbox_save_md5:1;
        unsigned int mbox_dotlocked:1;
        unsigned int mbox_used_privileges:1;
index 4ae5c99657cecbab932a915c18bf505725dfc4b2..e61f19793e57d9fa41c117aa7a43ca084ba65bff 100644 (file)
@@ -1675,9 +1675,10 @@ static int mbox_sync_int(struct mbox_mailbox *mbox, enum mbox_sync_flags flags,
 
        delay_writes = mbox->ibox.backend_readonly ||
                ((flags & MBOX_SYNC_REWRITE) == 0 &&
-                getenv("MBOX_LAZY_WRITES") != NULL);
+                mbox->storage->set->mbox_lazy_writes);
 
-       if (!mbox->mbox_do_dirty_syncs)
+       if (!mbox->storage->set->mbox_dirty_syncs &&
+           !mbox->storage->set->mbox_very_dirty_syncs)
                flags |= MBOX_SYNC_UNDIRTY;
 
        if ((flags & MBOX_SYNC_LOCK_READING) != 0) {
@@ -1865,8 +1866,8 @@ again:
 
        i_assert(*lock_id != 0);
 
-       if ((mbox->storage->storage.flags &
-            MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0 && mbox->mbox_fd != -1) {
+       if (mbox->storage->storage.set->mail_nfs_storage &&
+           mbox->mbox_fd != -1) {
                if (fdatasync(mbox->mbox_fd) < 0) {
                        mbox_set_syscall_error(mbox, "fdatasync()");
                        ret = -1;
@@ -1923,7 +1924,7 @@ mbox_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
 
        if (index_mailbox_want_full_sync(&mbox->ibox, flags)) {
                if ((flags & MAILBOX_SYNC_FLAG_FULL_READ) != 0 &&
-                   !mbox->mbox_very_dirty_syncs)
+                   !mbox->storage->set->mbox_very_dirty_syncs)
                        mbox_sync_flags |= MBOX_SYNC_UNDIRTY;
                if ((flags & MAILBOX_SYNC_FLAG_FULL_WRITE) != 0)
                        mbox_sync_flags |= MBOX_SYNC_REWRITE;
index a727e402b07045cef228295b710b1468482bc569..6cab2f30abe7db4d2c4461320209f7700d064127 100644 (file)
@@ -30,7 +30,7 @@ raw_get_list_settings(struct mailbox_list_settings *list_set,
                      const char *data, struct mail_storage *storage,
                      const char **layout_r, const char **error_r)
 {
-       bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+       bool debug = storage->set->mail_debug;
 
        *layout_r = "fs";
 
@@ -102,7 +102,7 @@ static int raw_create(struct mail_storage *_storage, const char *data,
 
        /* finish list init after we've overridden vfuncs */
        mailbox_list_init(_storage->list, _storage->ns, &list_set,
-                         mail_storage_get_list_flags(_storage->flags));
+                         MAILBOX_LIST_FLAG_MAILBOX_FILES);
        return 0;
 }
 
@@ -258,6 +258,7 @@ struct mail_storage raw_storage = {
        MEMBER(mailbox_is_file) TRUE,
 
        {
+               NULL,
                raw_class_init,
                raw_class_deinit,
                raw_alloc,
index 83fe0c1af118503b097b366127c8873191025192..2cc8dd800b65cf3d178907a6a4a08c0b42839b9d 100644 (file)
@@ -69,7 +69,6 @@ static int shared_create(struct mail_storage *_storage, const char *data,
                return -1;
        }
        storage->ns_prefix_pattern = p_strdup(_storage->pool, wildcardp);
-       *wildcardp = '\0';
 
        have_username = FALSE;
        for (p = storage->ns_prefix_pattern; *p != '\0'; p++) {
@@ -91,6 +90,10 @@ static int shared_create(struct mail_storage *_storage, const char *data,
                return -1;
        }
 
+       /* truncate prefix after the above checks are done, so they can log
+          the full prefix in error conditions */
+       *wildcardp = '\0';
+
        if (mailbox_list_alloc("shared", &_storage->list, error_r) < 0)
                return -1;
        MODULE_CONTEXT_SET_FULL(_storage->list, shared_mailbox_list_module,
@@ -99,8 +102,7 @@ static int shared_create(struct mail_storage *_storage, const char *data,
        memset(&list_set, 0, sizeof(list_set));
        list_set.mail_storage_flags = &_storage->flags;
        list_set.lock_method = &_storage->lock_method;
-       mailbox_list_init(_storage->list, _storage->ns, &list_set,
-                         mail_storage_get_list_flags(_storage->flags));
+       mailbox_list_init(_storage->list, _storage->ns, &list_set, 0);
        return 0;
 }
 
@@ -134,6 +136,7 @@ int shared_storage_get_namespace(struct mail_storage *_storage,
        };
        struct var_expand_table *tab;
        struct mail_namespace *ns;
+       struct mail_namespace_settings *ns_set;
        struct mail_user *owner;
        const char *domain = NULL, *username = NULL, *userdomain = NULL;
        const char *name, *p, *next, **dest, *error;
@@ -207,7 +210,7 @@ int shared_storage_get_namespace(struct mail_storage *_storage,
                return 0;
        }
 
-       owner = mail_user_init(userdomain);
+       owner = mail_user_alloc(userdomain, user->unexpanded_set);
        if (!var_has_key(storage->location, 'h', "home"))
                ret = 1;
        else {
@@ -220,6 +223,13 @@ int shared_storage_get_namespace(struct mail_storage *_storage,
                        return -1;
                }
        }
+       if (mail_user_init(owner, &error) < 0) {
+               mail_storage_set_critical(_storage,
+                       "Couldn't create namespace '%s' for user %s: %s",
+                       _storage->ns->prefix, userdomain, error);
+               mail_user_unref(&owner);
+               return -1;
+       }
 
        /* create the new namespace */
        ns = i_new(struct mail_namespace, 1);
@@ -230,14 +240,24 @@ int shared_storage_get_namespace(struct mail_storage *_storage,
        ns->flags = NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_HIDDEN |
                NAMESPACE_FLAG_AUTOCREATED;
        ns->sep = _storage->ns->sep;
+       ns->mail_set = _storage->set;
 
        location = t_str_new(256);
        if (ret > 0)
                var_expand(location, storage->location, tab);
        else
                get_nonexisting_user_location(storage, userdomain, location);
-       if (mail_storage_create(ns, NULL, str_c(location), _storage->flags,
-                               _storage->lock_method, &error) < 0) {
+
+       ns_set = p_new(user->pool, struct mail_namespace_settings, 1);
+       ns_set->type = "shared";
+       ns_set->separator = p_strdup_printf(user->pool, "%c", ns->sep);
+       ns_set->prefix = ns->prefix;
+       ns_set->location = p_strdup(user->pool, str_c(location));
+       ns_set->hidden = TRUE;
+       ns_set->list = "yes";
+       ns->set = ns_set;
+
+       if (mail_storage_create(ns, NULL, _storage->flags, &error) < 0) {
                mail_storage_set_critical(_storage, "Namespace '%s': %s",
                                          ns->prefix, error);
                mail_namespace_destroy(ns);
@@ -308,6 +328,7 @@ struct mail_storage shared_storage = {
        MEMBER(mailbox_is_file) FALSE, /* unknown at this point */
 
        {
+               NULL,
                NULL,
                NULL,
                shared_alloc,
index 483c5790fbf6a511757ef342c2ea332c4d72a011..88c7950cfbf85cee04642354517a8f362136dffc 100644 (file)
@@ -457,16 +457,17 @@ static int index_mailbox_list_open_indexes(struct mailbox_list *list,
        struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list);
        const char *path;
        enum mail_index_open_flags index_flags;
-       enum mail_storage_flags storage_flags;
+       enum file_lock_method lock_method;
        int ret;
 
-       /* FIXME: a bit ugly way to get the flags, but this will do for now.. */
-       index_flags = MAIL_INDEX_OPEN_FLAG_CREATE;
-       storage_flags = *list->set.mail_storage_flags;
-#ifndef MMAP_CONFLICTS_WRITE
-       if ((storage_flags & MAIL_STORAGE_FLAG_MMAP_DISABLE) != 0)
-#endif
-               index_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE;
+       index_flags = MAIL_INDEX_OPEN_FLAG_CREATE |
+               mail_storage_settings_to_index_flags(list->mail_set);
+
+       if (!file_lock_method_parse(list->mail_set->lock_method,
+                                   &lock_method)) {
+               i_error("Unknown lock_method: %s", list->mail_set->lock_method);
+               return -1;
+       }
 
        if (mail_index_open(ilist->mail_index, index_flags,
                            *list->set.lock_method) < 0) {
@@ -507,7 +508,7 @@ static void index_mailbox_list_created(struct mailbox_list *list)
 
        /* FIXME: always disabled for now */
        dir = mailbox_list_get_path(list, NULL, MAILBOX_LIST_PATH_TYPE_INDEX);
-       if (*dir == '\0' || getenv("MAILBOX_LIST_INDEX_DISABLE") != NULL ||
+       if (*dir == '\0' || list->mail_set->mailbox_list_index_disable ||
            strcmp(list->name, "maildir++") != 0 || 1) {
                /* reserve the module context anyway, so syncing code knows
                   that the index is disabled */
index 5aa484a28c87151c57282450d4bdfbc4605e6f07..30b035867bf8a29ec514eadf086ef583f6439b86 100644 (file)
@@ -178,7 +178,7 @@ static const char *list_get_rootdir(struct fs_list_iterate_context *ctx,
 {
        const char *const *patterns, *name, *p, *last;
 
-       if ((ctx->ctx.list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) == 0)
+       if (!ctx->ctx.list->mail_set->mail_full_filesystem_access)
                return NULL;
 
        /* see if there are any absolute paths in patterns */
index d4ae5015dbe95018e88fde62a767253343c67bd2..4a11072feae8b6349001e3248d5a64aa05a34f88 100644 (file)
@@ -97,7 +97,7 @@ fs_list_is_valid_common_nonfs(struct mailbox_list *list, const char *name)
 static bool
 fs_is_valid_pattern(struct mailbox_list *list, const char *pattern)
 {
-       if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0)
+       if (list->mail_set->mail_full_filesystem_access)
                return TRUE;
 
        return fs_list_is_valid_common_nonfs(list, pattern);
@@ -111,7 +111,7 @@ fs_is_valid_existing_name(struct mailbox_list *list, const char *name)
        if (!fs_list_is_valid_common(name, &len))
                return FALSE;
 
-       if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0)
+       if (list->mail_set->mail_full_filesystem_access)
                return TRUE;
 
        return fs_list_is_valid_common_nonfs(list, name);
@@ -127,7 +127,7 @@ fs_is_valid_create_name(struct mailbox_list *list, const char *name)
        if (len > FS_MAX_CREATE_MAILBOX_NAME_LENGTH)
                return FALSE;
 
-       if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0)
+       if (list->mail_set->mail_full_filesystem_access)
                return TRUE;
 
        if (mailbox_list_name_is_too_large(name, '/'))
index 51694206d74c4b26cecadee7d12b224a06dacc20..b1a4e997895fdf9fbf405e641ac9f8909c4a0ec0 100644 (file)
@@ -137,7 +137,7 @@ maildir_is_valid_existing_name(struct mailbox_list *list, const char *name)
        if (!maildir_list_is_valid_common(list, name, &len))
                return FALSE;
 
-       if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0)
+       if (list->mail_set->mail_full_filesystem_access)
                return TRUE;
 
        return maildir_list_is_valid_common_nonfs(name);
@@ -153,7 +153,7 @@ maildir_is_valid_create_name(struct mailbox_list *list, const char *name)
        if (len > MAILDIR_MAX_CREATE_MAILBOX_NAME_LENGTH)
                return FALSE;
 
-       if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0)
+       if (list->mail_set->mail_full_filesystem_access)
                return TRUE;
 
        if (!maildir_list_is_valid_common_nonfs(name))
@@ -168,9 +168,6 @@ static const char *
 maildir_list_get_path(struct mailbox_list *_list, const char *name,
                      enum mailbox_list_path_type type)
 {
-       struct maildir_mailbox_list *list =
-               (struct maildir_mailbox_list *)_list;
-
        if (name == NULL) {
                /* return root directories */
                switch (type) {
@@ -187,7 +184,7 @@ maildir_list_get_path(struct mailbox_list *_list, const char *name,
                i_unreached();
        }
 
-       if ((list->list.flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0 &&
+       if (_list->mail_set->mail_full_filesystem_access &&
            (*name == '/' || *name == '~'))
                return maildir_list_get_absolute_path(_list, name);
 
index c1589071b5e1b42b1ae2949116b58a238e8e5253..b22c3367c42e13e913b8322a0f5d8dcae66ccd06 100644 (file)
@@ -27,8 +27,7 @@ struct subsfile_list_context {
 static void subsread_set_syscall_error(struct mailbox_list *list,
                                       const char *function, const char *path)
 {
-       if (errno == EACCES &&
-           (list->flags & MAILBOX_LIST_FLAG_DEBUG) == 0) {
+       if (errno == EACCES && !list->mail_set->mail_debug) {
                mailbox_list_set_error(list, MAIL_ERROR_PERM,
                                       "No permission to read subscriptions");
        } else {
@@ -41,8 +40,7 @@ static void subsread_set_syscall_error(struct mailbox_list *list,
 static void subswrite_set_syscall_error(struct mailbox_list *list,
                                        const char *function, const char *path)
 {
-       if (errno == EACCES &&
-           (list->flags & MAILBOX_LIST_FLAG_DEBUG) == 0) {
+       if (errno == EACCES && !list->mail_set->mail_debug) {
                mailbox_list_set_error(list, MAIL_ERROR_PERM,
                                       "No permission to modify subscriptions");
        } else {
@@ -103,10 +101,8 @@ int subsfile_set_subscribed(struct mailbox_list *list, const char *path,
                name = "INBOX";
 
        memset(&dotlock_set, 0, sizeof(dotlock_set));
-       dotlock_set.use_excl_lock =
-               (list->flags & MAILBOX_LIST_FLAG_DOTLOCK_USE_EXCL) != 0;
-       dotlock_set.nfs_flush =
-               (list->flags & MAILBOX_LIST_FLAG_NFS_FLUSH) != 0;
+       dotlock_set.use_excl_lock = list->mail_set->dotlock_use_excl;
+       dotlock_set.nfs_flush = list->mail_set->mail_nfs_storage;
        dotlock_set.temp_prefix = temp_prefix;
        dotlock_set.timeout = SUBSCRIPTION_FILE_LOCK_TIMEOUT;
        dotlock_set.stale_timeout = SUBSCRIPTION_FILE_CHANGE_TIMEOUT;
index 657732bc065a9371551451cfb2107f330f7b2f34..c7c2c66046e7d9d46794832a1695f171ca98c39f 100644 (file)
@@ -1,9 +1,11 @@
 /* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "array.h"
 #include "str.h"
 #include "file-lock.h"
 #include "mail-storage.h"
+#include "mail-storage-settings.h"
 #include "mail-namespace.h"
 
 #include <stdlib.h>
@@ -35,82 +37,85 @@ static void mail_namespace_free(struct mail_namespace *ns)
        i_free(ns);
 }
 
-static struct mail_namespace *
-namespace_add_env(const char *data, unsigned int num,
-                 struct mail_user *user, enum mail_storage_flags flags,
-                 enum file_lock_method lock_method,
-                 struct mail_namespace *prev_namespaces)
+static int
+namespace_add(struct mail_user *user,
+             struct mail_namespace_settings *ns_set,
+             const struct mail_storage_settings *mail_set,
+             struct mail_namespace *prev_namespaces,
+             struct mail_namespace **ns_p, const char **error_r)
 {
         struct mail_namespace *ns;
-       const char *sep, *type, *prefix, *driver, *error, *list, *alias_for;
+       const char *driver, *error;
 
        ns = i_new(struct mail_namespace, 1);
-
-       sep = getenv(t_strdup_printf("NAMESPACE_%u_SEP", num));
-       type = getenv(t_strdup_printf("NAMESPACE_%u_TYPE", num));
-       prefix = getenv(t_strdup_printf("NAMESPACE_%u_PREFIX", num));
-       list = getenv(t_strdup_printf("NAMESPACE_%u_LIST", num));
-       alias_for = getenv(t_strdup_printf("NAMESPACE_%u_ALIAS", num));
-       if (getenv(t_strdup_printf("NAMESPACE_%u_INBOX", num)) != NULL)
-               ns->flags |= NAMESPACE_FLAG_INBOX;
-       if (getenv(t_strdup_printf("NAMESPACE_%u_HIDDEN", num)) != NULL)
-               ns->flags |= NAMESPACE_FLAG_HIDDEN;
-       if (list != NULL) {
-               if (strcmp(list, "children") == 0)
-                       ns->flags |= NAMESPACE_FLAG_LIST_CHILDREN;
-               else
-                       ns->flags |= NAMESPACE_FLAG_LIST_PREFIX;
-       }
-       if (getenv(t_strdup_printf("NAMESPACE_%u_SUBSCRIPTIONS", num)) != NULL)
-               ns->flags |= NAMESPACE_FLAG_SUBSCRIPTIONS;
-
-       if (type == NULL || *type == '\0' || strncmp(type, "private", 7) == 0) {
-               ns->type = NAMESPACE_PRIVATE;
+       if (strncmp(ns_set->type, "private", 7) == 0) {
                ns->owner = user;
-       } else if (strncmp(type, "shared", 6) == 0)
+               ns->type = NAMESPACE_PRIVATE;
+       } else if (strncmp(ns_set->type, "shared", 6) == 0)
                ns->type = NAMESPACE_SHARED;
-       else if (strncmp(type, "public", 6) == 0)
+       else if (strncmp(ns_set->type, "public", 6) == 0)
                ns->type = NAMESPACE_PUBLIC;
        else {
-               i_error("Unknown namespace type: %s", type);
+               *error_r = t_strdup_printf("Unknown namespace type: %s",
+                                          ns_set->type);
                mail_namespace_free(ns);
-               return NULL;
+               return -1;
        }
 
-       if (alias_for != NULL) {
+       if (strcmp(ns_set->list, "children") == 0)
+               ns->flags |= NAMESPACE_FLAG_LIST_CHILDREN;
+       else if (strcmp(ns_set->list, "yes") == 0)
+               ns->flags |= NAMESPACE_FLAG_LIST_PREFIX;
+       else if (strcmp(ns_set->list, "no") != 0) {
+               *error_r = t_strdup_printf("Invalid list setting value: %s",
+                                          ns_set->list);
+               mail_namespace_free(ns);
+               return -1;
+       }
+
+       if (ns_set->inbox)
+               ns->flags |= NAMESPACE_FLAG_INBOX;
+       if (ns_set->hidden)
+               ns->flags |= NAMESPACE_FLAG_HIDDEN;
+       if (ns_set->subscriptions)
+               ns->flags |= NAMESPACE_FLAG_SUBSCRIPTIONS;
+
+       if (ns_set->alias_for != NULL) {
                ns->alias_for = mail_namespace_find_prefix(prev_namespaces,
-                                                          alias_for);
+                                                          ns_set->alias_for);
                if (ns->alias_for == NULL) {
-                       i_error("Invalid namespace alias_for: %s", alias_for);
+                       *error_r = t_strdup_printf("Invalid namespace alias_for: %s",
+                                                  ns_set->alias_for);
                        mail_namespace_free(ns);
-                       return NULL;
+                       return -1;
                }
                if (ns->alias_for->alias_for != NULL) {
-                       i_error("Chained namespace alias_for: %s", alias_for);
+                       *error_r = t_strdup_printf("Chained namespace alias_for: %s",
+                                                  ns_set->alias_for);
                        mail_namespace_free(ns);
-                       return NULL;
+                       return -1;
                }
                ns->alias_chain_next = ns->alias_for->alias_chain_next;
                ns->alias_for->alias_chain_next = ns;
        }
 
-       if (prefix == NULL)
-               prefix = "";
-
-       if ((flags & MAIL_STORAGE_FLAG_DEBUG) != 0) {
+       if (mail_set->mail_debug) {
                i_info("Namespace: type=%s, prefix=%s, sep=%s, "
                       "inbox=%s, hidden=%s, list=%s, subscriptions=%s",
-                      type == NULL ? "" : type, prefix, sep == NULL ? "" : sep,
-                      (ns->flags & NAMESPACE_FLAG_INBOX) ? "yes" : "no",
-                      (ns->flags & NAMESPACE_FLAG_HIDDEN) ? "yes" : "no",
-                      list,
-                      (ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) ?
-                      "yes" : "no");
+                      ns_set->type, ns_set->prefix,
+                      ns_set->separator == NULL ? "" : ns_set->separator,
+                      ns_set->inbox ? "yes" : "no",
+                      ns_set->hidden ? "yes" : "no",
+                      ns_set->list ? "yes" : "no",
+                      ns_set->subscriptions ? "yes" : "no");
        }
 
-       if (sep != NULL)
-               ns->sep = *sep;
-       ns->prefix = i_strdup(prefix);
+       if (*ns_set->location == '\0')
+               ns_set->location = mail_set->mail_location;
+
+       ns->set = ns_set;
+       ns->mail_set = mail_set;
+       ns->prefix = i_strdup(ns_set->prefix);
        ns->user = user;
 
        if (ns->type == NAMESPACE_SHARED && strchr(ns->prefix, '%') != NULL) {
@@ -121,16 +126,21 @@ namespace_add_env(const char *data, unsigned int num,
                driver = NULL;
        }
 
-       if (mail_storage_create(ns, driver, data, flags, lock_method,
-                               &error) < 0) {
-               i_error("Namespace '%s': %s", ns->prefix, error);
+       if (mail_storage_create(ns, driver, 0, &error) < 0) {
+               *error_r = t_strdup_printf("Namespace '%s': %s",
+                                          ns->prefix, error);
                mail_namespace_free(ns);
-               return NULL;
+               return -1;
        }
-       return ns;
+       if (ns_set->separator != NULL)
+               ns->sep = *ns_set->separator;
+
+       *ns_p = ns;
+       return 0;
 }
 
-static bool namespaces_check(struct mail_namespace *namespaces)
+static bool
+namespaces_check(struct mail_namespace *namespaces, const char **error_r)
 {
        struct mail_namespace *ns, *inbox_ns = NULL, *private_ns = NULL;
        unsigned int private_ns_count = 0;
@@ -140,9 +150,9 @@ static bool namespaces_check(struct mail_namespace *namespaces)
        for (ns = namespaces; ns != NULL; ns = ns->next) {
                if ((ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
                        if (inbox_ns != NULL) {
-                               i_error("namespace configuration error: "
+                               *error_r = "namespace configuration error: "
                                        "There can be only one namespace with "
-                                       "inbox=yes");
+                                       "inbox=yes";
                                return FALSE;
                        }
                        inbox_ns = ns;
@@ -154,7 +164,8 @@ static bool namespaces_check(struct mail_namespace *namespaces)
                if (*ns->prefix != '\0' &&
                    (ns->flags & NAMESPACE_FLAG_LIST_PREFIX) != 0 &&
                    ns->prefix[strlen(ns->prefix)-1] != ns->sep) {
-                       i_error("namespace configuration error: "
+                       *error_r = t_strdup_printf(
+                               "namespace configuration error: "
                                "list=yes requires prefix=%s "
                                "to end with separator", ns->prefix);
                        return FALSE;
@@ -164,16 +175,16 @@ static bool namespaces_check(struct mail_namespace *namespaces)
                        if (list_sep == '\0')
                                list_sep = ns->sep;
                        else if (list_sep != ns->sep) {
-                               i_error("namespace configuration error: "
+                               *error_r = "namespace configuration error: "
                                        "All list=yes namespaces must use "
-                                       "the same separator");
+                                       "the same separator";
                                return FALSE;
                        }
                }
                if (*ns->prefix == '\0' &&
                    (ns->flags & NAMESPACE_FLAG_LIST_PREFIX) == 0) {
-                       i_error("namespace configuration error: "
-                               "Empty prefix requires list=yes");
+                       *error_r = "namespace configuration error: "
+                               "Empty prefix requires list=yes";
                        return FALSE;
                }
                if ((ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) != 0)
@@ -186,57 +197,53 @@ static bool namespaces_check(struct mail_namespace *namespaces)
                           the INBOX namespace. */
                        private_ns->flags |= NAMESPACE_FLAG_INBOX;
                } else {
-                       i_error("namespace configuration error: "
-                               "inbox=yes namespace missing");
+                       *error_r = "namespace configuration error: "
+                               "inbox=yes namespace missing";
                        return FALSE;
                }
        }
        if (list_sep == '\0') {
-               i_error("namespace configuration error: "
-                       "no list=yes namespaces");
+               *error_r = "namespace configuration error: "
+                       "no list=yes namespaces";
                return FALSE;
        }
        if (subscriptions_count == 0) {
-               i_error("namespace configuration error: "
-                       "no subscriptions=yes namespaces");
+               *error_r = "namespace configuration error: "
+                       "no subscriptions=yes namespaces";
                return FALSE;
        }
        return TRUE;
 }
 
-int mail_namespaces_init(struct mail_user *user)
+int mail_namespaces_init(struct mail_user *user, const char **error_r)
 {
+       const struct mail_storage_settings *mail_set;
+       struct mail_namespace_settings *const *ns_set;
        struct mail_namespace *namespaces, *ns, **ns_p;
-       enum mail_storage_flags flags;
-        enum file_lock_method lock_method;
-       const char *mail, *data, *error;
-       unsigned int i;
+       struct mail_namespace_settings *inbox_set;
+       const char *error, *driver, *env;
+       unsigned int i, count;
 
-       mail_storage_parse_env(&flags, &lock_method);
-        namespaces = NULL; ns_p = &namespaces;
-
-       /* first try NAMESPACE_* environments */
-       for (i = 1; ; i++) {
-               T_BEGIN {
-                       data = getenv(t_strdup_printf("NAMESPACE_%u", i));
-               } T_END;
+       i_assert(user->initialized);
 
-               if (data == NULL)
-                       break;
-
-               T_BEGIN {
-                       *ns_p = namespace_add_env(data, i, user, flags,
-                                                 lock_method, namespaces);
-               } T_END;
+        namespaces = NULL; ns_p = &namespaces;
 
-               if (*ns_p == NULL)
+       mail_set = mail_user_set_get_driver_settings(user->set, "MAIL");
+       if (array_is_created(&user->set->namespaces))
+               ns_set = array_get(&user->set->namespaces, &count);
+       else {
+               ns_set = NULL;
+               count = 0;
+       }
+       for (i = 0; i < count; i++) {
+               if (namespace_add(user, ns_set[i], mail_set, namespaces,
+                                 ns_p, error_r) < 0)
                        return -1;
-
                ns_p = &(*ns_p)->next;
        }
 
        if (namespaces != NULL) {
-               if (!namespaces_check(namespaces)) {
+               if (!namespaces_check(namespaces, error_r)) {
                        while (namespaces != NULL) {
                                ns = namespaces;
                                namespaces = ns->next;
@@ -254,35 +261,50 @@ int mail_namespaces_init(struct mail_user *user)
                return 0;
        }
 
-       /* fallback to MAIL */
-       mail = getenv("MAIL");
-       if (mail == NULL) {
-               /* support also maildir-specific environment */
-               mail = getenv("MAILDIR");
-               if (mail != NULL)
-                       mail = t_strconcat("maildir:", mail, NULL);
-       }
-
+       /* fallback to using environment variables */
        ns = i_new(struct mail_namespace, 1);
        ns->type = NAMESPACE_PRIVATE;
        ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST_PREFIX |
                NAMESPACE_FLAG_SUBSCRIPTIONS;
-       ns->prefix = i_strdup("");
-       ns->user = user;
        ns->owner = user;
 
-       if (mail_storage_create(ns, NULL, mail, flags, lock_method,
-                               &error) < 0) {
-               if (mail != NULL && *mail != '\0')
-                       i_error("mail_location: %s", error);
+       inbox_set = p_new(user->pool, struct mail_namespace_settings, 1);
+       *inbox_set = mail_namespace_default_settings;
+       inbox_set->inbox = TRUE;
+
+       driver = NULL;
+       env = "MAIL";
+       inbox_set->location = getenv("MAIL");
+       if (inbox_set->location == NULL) {
+               /* support also maildir-specific environment */
+               inbox_set->location = getenv("MAILDIR");
+               if (inbox_set->location == NULL)
+                       inbox_set->location = "";
                else {
-                       i_error("mail_location not set and "
-                               "autodetection failed: %s", error);
+                       driver = "maildir";
+                       env = "MAILDIR";
+               }
+       }
+
+       ns->set = inbox_set;
+       ns->mail_set = mail_set;
+       ns->prefix = i_strdup(ns->set->prefix);
+       ns->user = user;
+
+       if (mail_storage_create(ns, driver, 0, &error) < 0) {
+               if (*inbox_set->location != '\0') {
+                       *error_r = t_strdup_printf(
+                               "Initializing mail storage from environment %s "
+                               "failed: %s", env, error);
+               } else {
+                       *error_r = t_strdup_printf("mail_location not set and "
+                                       "autodetection failed: %s", error);
                }
                mail_namespace_free(ns);
                return -1;
        }
        user->namespaces = ns;
+       mail_namespace_init_storage(ns);
 
        if (hook_mail_namespaces_created != NULL) {
                T_BEGIN {
@@ -292,8 +314,7 @@ int mail_namespaces_init(struct mail_user *user)
        return 0;
 }
 
-struct mail_namespace *
-mail_namespaces_init_empty(struct mail_user *user)
+struct mail_namespace *mail_namespaces_init_empty(struct mail_user *user)
 {
        struct mail_namespace *ns;
 
@@ -303,6 +324,7 @@ mail_namespaces_init_empty(struct mail_user *user)
        ns->prefix = i_strdup("");
        ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST_PREFIX |
                NAMESPACE_FLAG_SUBSCRIPTIONS;
+       ns->mail_set = mail_user_set_get_driver_settings(user->set, "MAIL");
        user->namespaces = ns;
        return ns;
 }
index b4bc997dd3e94a3b1cb31b2361afa58e110ee74e..dbda0f341d59032ea2afff840c14e63957a05ce4 100644 (file)
@@ -3,6 +3,8 @@
 
 #include "mail-user.h"
 
+struct mail_storage_root_settings;
+
 enum namespace_type {
        NAMESPACE_PRIVATE,
        NAMESPACE_SHARED,
@@ -55,12 +57,15 @@ struct mail_namespace {
        struct mailbox_list *list;
        /* FIXME: we should support multiple storages in one namespace */
        struct mail_storage *storage;
+
+       const struct mail_namespace_settings *set;
+       const struct mail_storage_settings *mail_set;
 };
 
 /* Called after namespaces has been created */
 extern void (*hook_mail_namespaces_created)(struct mail_namespace *namespaces);
 
-int mail_namespaces_init(struct mail_user *user);
+int mail_namespaces_init(struct mail_user *user, const char **error_r);
 struct mail_namespace *mail_namespaces_init_empty(struct mail_user *user);
 void mail_namespaces_deinit(struct mail_namespace **namespaces);
 
index 2f56a6b7534aecced920bc736edc20a6a2031dba..aefd9a913f45297bae08c70bcaf444e4d93dfe6c 100644 (file)
@@ -4,6 +4,7 @@
 #include "module-context.h"
 #include "file-lock.h"
 #include "mail-storage.h"
+#include "mail-storage-settings.h"
 #include "mail-index-private.h"
 
 /* Called after mail storage has been created */
@@ -22,6 +23,8 @@ struct mail_module_register {
 };
 
 struct mail_storage_vfuncs {
+       const struct setting_parser_info *(*get_setting_parser_info)(void);
+
        void (*class_init)(void);
        void (*class_deinit)(void);
 
@@ -30,7 +33,7 @@ struct mail_storage_vfuncs {
                      const char **error_r);
        void (*destroy)(struct mail_storage *storage);
 
-       bool (*autodetect)(const char *data, enum mail_storage_flags flags);
+       bool (*autodetect)(const struct mail_namespace *ns);
 
        struct mailbox *(*mailbox_open)(struct mail_storage *storage,
                                        const char *name,
@@ -61,10 +64,10 @@ struct mail_storage {
         const struct mail_storage *storage_class;
        struct mail_namespace *ns;
        struct mailbox_list *list;
+       const struct mail_storage_settings *set;
 
        enum mail_storage_flags flags;
        enum file_lock_method lock_method;
-       unsigned int keyword_max_len;
 
        struct mail_storage_callbacks *callbacks;
        void *callback_context;
@@ -380,7 +383,5 @@ const char *mail_generate_guid_string(void);
 void mail_set_expunged(struct mail *mail);
 void mailbox_set_deleted(struct mailbox *box);
 
-enum mailbox_list_flags
-mail_storage_get_list_flags(enum mail_storage_flags storage_flags);
 
 #endif
diff --git a/src/lib-storage/mail-storage-settings.c b/src/lib-storage/mail-storage-settings.c
new file mode 100644 (file)
index 0000000..d7b545f
--- /dev/null
@@ -0,0 +1,208 @@
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "settings-parser.h"
+#include "mail-index.h"
+#include "mail-user.h"
+#include "mail-namespace.h"
+#include "mail-storage-private.h"
+#include "mail-storage-settings.h"
+
+#include <stddef.h>
+
+#undef DEF
+#define DEF(type, name) \
+       { type, #name, offsetof(struct mail_storage_settings, name), NULL }
+
+static struct setting_define mail_storage_setting_defines[] = {
+       DEF(SET_STR_VARS, mail_location),
+       DEF(SET_STR, mail_cache_fields),
+       DEF(SET_STR, mail_never_cache_fields),
+       DEF(SET_UINT, mail_cache_min_mail_count),
+       DEF(SET_UINT, mailbox_idle_check_interval),
+       DEF(SET_UINT, mail_max_keyword_length),
+       DEF(SET_BOOL, mail_save_crlf),
+       DEF(SET_BOOL, fsync_disable),
+       DEF(SET_BOOL, mmap_disable),
+       DEF(SET_BOOL, dotlock_use_excl),
+       DEF(SET_BOOL, mail_nfs_storage),
+       DEF(SET_BOOL, mail_nfs_index),
+       DEF(SET_BOOL, mailbox_list_index_disable),
+       DEF(SET_BOOL, mail_debug),
+       DEF(SET_BOOL, mail_full_filesystem_access),
+       DEF(SET_ENUM, lock_method),
+       DEF(SET_STR, pop3_uidl_format),
+
+       SETTING_DEFINE_LIST_END
+};
+
+struct mail_storage_settings mail_storage_default_settings = {
+       MEMBER(mail_location) "",
+       MEMBER(mail_cache_fields) "flags",
+       MEMBER(mail_never_cache_fields) "imap.envelope",
+       MEMBER(mail_cache_min_mail_count) 0,
+       MEMBER(mailbox_idle_check_interval) 30,
+       MEMBER(mail_max_keyword_length) 50,
+       MEMBER(mail_save_crlf) FALSE,
+       MEMBER(fsync_disable) FALSE,
+       MEMBER(mmap_disable) FALSE,
+       MEMBER(dotlock_use_excl) FALSE,
+       MEMBER(mail_nfs_storage) FALSE,
+       MEMBER(mail_nfs_index) FALSE,
+       MEMBER(mailbox_list_index_disable) FALSE,
+       MEMBER(mail_debug) FALSE,
+       MEMBER(mail_full_filesystem_access) FALSE,
+       MEMBER(lock_method) "fcntl:flock:dotlock",
+       MEMBER(pop3_uidl_format) "%08Xu%08Xv"
+};
+
+struct setting_parser_info mail_storage_setting_parser_info = {
+       MEMBER(defines) mail_storage_setting_defines,
+       MEMBER(defaults) &mail_storage_default_settings,
+
+       MEMBER(parent) &mail_user_setting_parser_info,
+       MEMBER(dynamic_parsers) NULL,
+
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) (size_t)-1,
+       MEMBER(struct_size) sizeof(struct mail_storage_settings)
+};
+
+#undef DEF
+#define DEF(type, name) \
+       { type, #name, offsetof(struct mail_namespace_settings, name), NULL }
+
+static struct setting_define mail_namespace_setting_defines[] = {
+       DEF(SET_ENUM, type),
+       DEF(SET_STR, separator),
+       DEF(SET_STR_VARS, prefix),
+       DEF(SET_STR_VARS, location),
+       DEF(SET_STR_VARS, alias_for),
+
+       DEF(SET_BOOL, inbox),
+       DEF(SET_BOOL, hidden),
+       DEF(SET_ENUM, list),
+       DEF(SET_BOOL, subscriptions),
+
+       SETTING_DEFINE_LIST_END
+};
+
+struct mail_namespace_settings mail_namespace_default_settings = {
+       MEMBER(type) "private:shared:public",
+       MEMBER(separator) "",
+       MEMBER(prefix) "",
+       MEMBER(location) "",
+       MEMBER(alias_for) NULL,
+
+       MEMBER(inbox) FALSE,
+       MEMBER(hidden) FALSE,
+       MEMBER(list) "yes:no:children",
+       MEMBER(subscriptions) TRUE
+};
+
+struct setting_parser_info mail_namespace_setting_parser_info = {
+       MEMBER(defines) mail_namespace_setting_defines,
+       MEMBER(defaults) &mail_namespace_default_settings,
+
+       MEMBER(parent) &mail_user_setting_parser_info,
+       MEMBER(dynamic_parsers) NULL,
+
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) offsetof(struct mail_namespace_settings, type),
+       MEMBER(struct_size) sizeof(struct mail_namespace_settings)
+};
+
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+       { type, #name, offsetof(struct mail_user_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+       { SET_DEFLIST, name, \
+         offsetof(struct mail_user_settings, field), defines }
+
+static struct setting_define mail_user_setting_defines[] = {
+       DEF(SET_UINT, umask),
+
+       DEFLIST(namespaces, "namespace", &mail_namespace_setting_parser_info),
+
+       SETTING_DEFINE_LIST_END
+};
+
+static struct mail_user_settings mail_user_default_settings = {
+       MEMBER(umask) 0077,
+
+       MEMBER(namespaces) ARRAY_INIT
+};
+
+struct setting_parser_info mail_user_setting_parser_info = {
+       MEMBER(defines) mail_user_setting_defines,
+       MEMBER(defaults) &mail_user_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 mail_user_settings)
+};
+
+const void *
+mail_user_set_get_driver_settings(const struct mail_user_settings *set,
+                                 const char *driver)
+{
+       const void *dset;
+
+       dset = settings_find_dynamic(&mail_user_setting_parser_info,
+                                    set, driver);
+       if (dset == NULL) {
+               i_panic("Default settings not found for storage driver %s",
+                       driver);
+       }
+       return dset;
+}
+
+const void *mail_storage_get_driver_settings(struct mail_storage *storage)
+{
+       return mail_user_set_get_driver_settings(storage->ns->user->set,
+                                                storage->name);
+}
+
+enum mail_index_open_flags
+mail_storage_settings_to_index_flags(const struct mail_storage_settings *set)
+{
+       enum mail_index_open_flags index_flags = 0;
+
+       if (set->fsync_disable)
+               index_flags |= MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE;
+#ifndef MMAP_CONFLICTS_WRITE
+       if (set->mmap_disable)
+#endif
+               index_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE;
+       if (set->dotlock_use_excl)
+               index_flags |= MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL;
+       return index_flags;
+}
+
+void mail_storage_namespace_defines_init(pool_t pool)
+{
+       struct dynamic_settings_parser *parsers;
+       struct mail_storage *const *storages;
+       unsigned int i, j, count;
+
+       storages = array_get(&mail_storage_classes, &count);
+       parsers = t_new(struct dynamic_settings_parser, count + 1);
+       parsers[0].name = "MAIL";
+       parsers[0].info = &mail_storage_setting_parser_info;
+
+       for (i = 0, j = 1; i < count; i++) {
+               if (storages[i]->v.get_setting_parser_info == NULL)
+                       continue;
+
+               parsers[j].name = storages[i]->name;
+               parsers[j].info = storages[i]->v.get_setting_parser_info();
+               j++;
+       }
+
+       settings_parser_info_update(pool, parsers[j-1].info->parent, parsers);
+}
diff --git a/src/lib-storage/mail-storage-settings.h b/src/lib-storage/mail-storage-settings.h
new file mode 100644 (file)
index 0000000..f107a88
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef MAIL_STORAGE_SETTINGS_H
+#define MAIL_STORAGE_SETTINGS_H
+
+struct mail_user;
+struct mail_storage;
+
+struct mail_storage_settings {
+       const char *mail_location;
+       const char *mail_cache_fields;
+       const char *mail_never_cache_fields;
+       unsigned int mail_cache_min_mail_count;
+       unsigned int mailbox_idle_check_interval;
+       unsigned int mail_max_keyword_length;
+       bool mail_save_crlf;
+       bool fsync_disable;
+       bool mmap_disable;
+       bool dotlock_use_excl;
+       bool mail_nfs_storage;
+       bool mail_nfs_index;
+       bool mailbox_list_index_disable;
+       bool mail_debug;
+       bool mail_full_filesystem_access;
+       const char *lock_method;
+       const char *pop3_uidl_format;
+};
+
+struct mail_namespace_settings {
+       const char *type;
+       const char *separator;
+       const char *prefix;
+       const char *location;
+       const char *alias_for;
+
+       bool inbox;
+       bool hidden;
+       const char *list;
+       bool subscriptions;
+};
+
+struct mail_user_settings {
+       unsigned int umask;
+
+       ARRAY_DEFINE(namespaces, struct mail_namespace_settings *);
+};
+
+extern struct setting_parser_info mail_user_setting_parser_info;
+extern struct setting_parser_info mail_namespace_setting_parser_info;
+extern struct setting_parser_info mail_storage_setting_parser_info;
+extern struct mail_namespace_settings mail_namespace_default_settings;
+
+const void *
+mail_user_set_get_driver_settings(const struct mail_user_settings *set,
+                                 const char *driver);
+const void *mail_storage_get_driver_settings(struct mail_storage *storage);
+
+enum mail_index_open_flags
+mail_storage_settings_to_index_flags(const struct mail_storage_settings *set);
+
+void mail_storage_namespace_defines_init(pool_t pool);
+
+#endif
index 647e520276297a853fe71385edeb6c28d750f174..6d1c741d07a17e0097cb2c70d53b99280a0d727a 100644 (file)
@@ -7,6 +7,7 @@
 #include "mail-index-private.h"
 #include "mailbox-list-private.h"
 #include "mail-storage-private.h"
+#include "mail-storage-settings.h"
 #include "mail-namespace.h"
 #include "mail-search.h"
 #include "mailbox-search-result-private.h"
@@ -14,8 +15,6 @@
 #include <stdlib.h>
 #include <ctype.h>
 
-#define DEFAULT_MAX_KEYWORD_LENGTH 50
-
 struct mail_storage_module_register mail_storage_module_register = { 0 };
 struct mail_module_register mail_module_register = { 0 };
 
@@ -26,28 +25,30 @@ void (*hook_mail_storage_created)(struct mail_storage *storage);
 void (*hook_mailbox_opened)(struct mailbox *box) = NULL;
 void (*hook_mailbox_index_opened)(struct mailbox *box) = NULL;
 
-static ARRAY_DEFINE(storages, struct mail_storage *);
+ARRAY_TYPE(mail_storage) mail_storage_classes;
 
 void mail_storage_init(void)
 {
        mailbox_lists_init();
-       i_array_init(&storages, 8);
+       i_array_init(&mail_storage_classes, 8);
 }
 
 void mail_storage_deinit(void)
 {
-       if (array_is_created(&storages))
-               array_free(&storages);
+       if (array_is_created(&mail_storage_classes))
+               array_free(&mail_storage_classes);
        mailbox_lists_deinit();
 }
 
 void mail_storage_class_register(struct mail_storage *storage_class)
 {
+       i_assert(mail_storage_find_class(storage_class->name) == NULL);
+
        if (storage_class->v.class_init != NULL)
                storage_class->v.class_init();
 
        /* append it after the list, so the autodetection order is correct */
-       array_append(&storages, &storage_class, 1);
+       array_append(&mail_storage_classes, &storage_class, 1);
 }
 
 void mail_storage_class_unregister(struct mail_storage *storage_class)
@@ -55,10 +56,10 @@ void mail_storage_class_unregister(struct mail_storage *storage_class)
        struct mail_storage *const *classes;
        unsigned int i, count;
 
-       classes = array_get(&storages, &count);
+       classes = array_get(&mail_storage_classes, &count);
        for (i = 0; i < count; i++) {
                if (classes[i] == storage_class) {
-                       array_delete(&storages, i, 1);
+                       array_delete(&mail_storage_classes, i, 1);
                        break;
                }
        }
@@ -66,48 +67,6 @@ void mail_storage_class_unregister(struct mail_storage *storage_class)
        storage_class->v.class_deinit();
 }
 
-void mail_storage_parse_env(enum mail_storage_flags *flags_r,
-                           enum file_lock_method *lock_method_r)
-{
-       const char *str;
-
-       *flags_r = 0;
-       if (getenv("FULL_FILESYSTEM_ACCESS") != NULL)
-               *flags_r |= MAIL_STORAGE_FLAG_FULL_FS_ACCESS;
-       if (getenv("DEBUG") != NULL)
-               *flags_r |= MAIL_STORAGE_FLAG_DEBUG;
-       if (getenv("MMAP_DISABLE") != NULL)
-               *flags_r |= MAIL_STORAGE_FLAG_MMAP_DISABLE;
-       if (getenv("MMAP_NO_WRITE") != NULL)
-               *flags_r |= MAIL_STORAGE_FLAG_MMAP_NO_WRITE;
-       if (getenv("DOTLOCK_USE_EXCL") != NULL)
-               *flags_r |= MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL;
-       if (getenv("MAIL_SAVE_CRLF") != NULL)
-               *flags_r |= MAIL_STORAGE_FLAG_SAVE_CRLF;
-       if (getenv("FSYNC_DISABLE") != NULL)
-               *flags_r |= MAIL_STORAGE_FLAG_FSYNC_DISABLE;
-       if (getenv("MAIL_NFS_STORAGE") != NULL)
-               *flags_r |= MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE;
-       if (getenv("MAIL_NFS_INDEX") != NULL) {
-               *flags_r |= MAIL_STORAGE_FLAG_NFS_FLUSH_INDEX;
-               if ((*flags_r & MAIL_STORAGE_FLAG_MMAP_DISABLE) == 0)
-                       i_fatal("mail_nfs_index=yes requires mmap_disable=yes");
-               if ((*flags_r & MAIL_STORAGE_FLAG_FSYNC_DISABLE) != 0)
-                       i_fatal("mail_nfs_index=yes requires fsync_disable=no");
-       }
-
-       str = getenv("POP3_UIDL_FORMAT");
-       if (str != NULL && (str = strchr(str, '%')) != NULL &&
-           str != NULL && var_get_key(str + 1) == 'm')
-               *flags_r |= MAIL_STORAGE_FLAG_KEEP_HEADER_MD5;
-
-       str = getenv("LOCK_METHOD");
-       if (str == NULL)
-               *lock_method_r = FILE_LOCK_METHOD_FCNTL;
-       else if (!file_lock_method_parse(str, lock_method_r))
-               i_fatal("Unknown lock_method: %s", str);
-}
-
 struct mail_storage *mail_storage_find_class(const char *name)
 {
        struct mail_storage *const *classes;
@@ -115,7 +74,7 @@ struct mail_storage *mail_storage_find_class(const char *name)
 
        i_assert(name != NULL);
 
-       classes = array_get(&storages, &count);
+       classes = array_get(&mail_storage_classes, &count);
        for (i = 0; i < count; i++) {
                if (strcasecmp(classes[i]->name, name) == 0)
                        return classes[i];
@@ -124,15 +83,15 @@ struct mail_storage *mail_storage_find_class(const char *name)
 }
 
 static struct mail_storage *
-mail_storage_autodetect(const char *data, enum mail_storage_flags flags)
+mail_storage_autodetect(const struct mail_namespace *ns)
 {
        struct mail_storage *const *classes;
        unsigned int i, count;
 
-       classes = array_get(&storages, &count);
+       classes = array_get(&mail_storage_classes, &count);
        for (i = 0; i < count; i++) {
                if (classes[i]->v.autodetect != NULL &&
-                   classes[i]->v.autodetect(data, flags))
+                   classes[i]->v.autodetect(ns))
                        return classes[i];
        }
        return NULL;
@@ -158,15 +117,30 @@ mail_storage_set_autodetection(const char **data, const char **driver,
 }
 
 int mail_storage_create(struct mail_namespace *ns, const char *driver,
-                       const char *data, enum mail_storage_flags flags,
-                       enum file_lock_method lock_method,
-                       const char **error_r)
+                       enum mail_storage_flags flags, const char **error_r)
 {
        struct mail_storage *storage_class, *storage;
        struct mail_storage *const *classes;
-       const char *home, *value;
+       const char *data = ns->set->location;
+       const char *home, *p;
        unsigned int i, count;
 
+       if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
+           ns->mail_set->pop3_uidl_format != NULL) {
+               /* if pop3_uidl_format contains %m, we want to keep the
+                  header MD5 sums stored even if we're not running POP3
+                  right now. */
+               p = ns->mail_set->pop3_uidl_format;
+               while ((p = strchr(p, '%')) != NULL) {
+                       if (p[1] == '%')
+                               p += 2;
+                       else if (var_get_key(++p) == 'm') {
+                               flags |= MAIL_STORAGE_FLAG_KEEP_HEADER_MD5;
+                               break;
+                       }
+               }
+       }
+
        if (data == NULL)
                data = "";
        else if (driver == NULL)
@@ -174,9 +148,9 @@ int mail_storage_create(struct mail_namespace *ns, const char *driver,
 
        if (*data == '\0' && driver == NULL) {
                /* use the first driver that works */
-               classes = array_get(&storages, &count);
+               classes = array_get(&mail_storage_classes, &count);
        } else if (driver == NULL) {
-               storage_class = mail_storage_autodetect(data, flags);
+               storage_class = mail_storage_autodetect(ns);
                if (storage_class == NULL) {
                        *error_r = t_strdup_printf(
                                "Ambiguous mail location setting, "
@@ -200,8 +174,13 @@ int mail_storage_create(struct mail_namespace *ns, const char *driver,
 
        for (i = 0; i < count; i++) {
                storage = classes[i]->v.alloc();
+               storage->set = ns->mail_set;
                storage->flags = flags;
-               storage->lock_method = lock_method;
+               if (!file_lock_method_parse(storage->set->lock_method,
+                                           &storage->lock_method)) {
+                       i_fatal("Unknown lock_method: %s",
+                               storage->set->lock_method);
+               }
                storage->ns = ns;
 
                storage->callbacks =
@@ -211,7 +190,7 @@ int mail_storage_create(struct mail_namespace *ns, const char *driver,
                if (classes[i]->v.create(storage, data, error_r) == 0)
                        break;
 
-               if ((flags & MAIL_STORAGE_FLAG_DEBUG) != 0 && count > 1) {
+               if (ns->mail_set->mail_debug && count > 1) {
                        i_info("%s: Couldn't create mail storage %s: %s",
                               classes[i]->name, data, *error_r);
                }
@@ -234,10 +213,6 @@ int mail_storage_create(struct mail_namespace *ns, const char *driver,
                return -1;
        }
 
-       value = getenv("MAIL_MAX_KEYWORD_LENGTH");
-       storage->keyword_max_len = value != NULL ?
-               atoi(value) : DEFAULT_MAX_KEYWORD_LENGTH;
-       
        if (hook_mail_storage_created != NULL) {
                T_BEGIN {
                        hook_mail_storage_created(storage);
@@ -327,6 +302,12 @@ mail_storage_get_namespace(const struct mail_storage *storage)
        return storage->ns;
 }
 
+const struct mail_storage_settings *
+mail_storage_get_settings(struct mail_storage *storage)
+{
+       return storage->set;
+}
+
 void mail_storage_set_callbacks(struct mail_storage *storage,
                                struct mail_storage_callbacks *callbacks,
                                void *context)
@@ -404,22 +385,6 @@ const char *mail_storage_get_mailbox_index_dir(struct mail_storage *storage,
                                     MAILBOX_LIST_PATH_TYPE_INDEX);
 }
 
-enum mailbox_list_flags
-mail_storage_get_list_flags(enum mail_storage_flags storage_flags)
-{
-       enum mailbox_list_flags list_flags = 0;
-
-       if ((storage_flags & MAIL_STORAGE_FLAG_DEBUG) != 0)
-               list_flags |= MAILBOX_LIST_FLAG_DEBUG;
-       if ((storage_flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0)
-               list_flags |= MAILBOX_LIST_FLAG_FULL_FS_ACCESS;
-       if ((storage_flags & MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0)
-               list_flags |= MAILBOX_LIST_FLAG_DOTLOCK_USE_EXCL;
-       if ((storage_flags & MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0)
-               list_flags |= MAILBOX_LIST_FLAG_NFS_FLUSH;
-       return list_flags;
-}
-
 bool mail_storage_set_error_from_errno(struct mail_storage *storage)
 {
        const char *error_string;
@@ -427,8 +392,7 @@ bool mail_storage_set_error_from_errno(struct mail_storage *storage)
 
        if (!mail_error_from_errno(&error, &error_string))
                return FALSE;
-       if ((storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0 &&
-           error != MAIL_ERROR_NOTFOUND) {
+       if (storage->set->mail_debug && error != MAIL_ERROR_NOTFOUND) {
                /* debugging is enabled - admin may be debugging a
                   (permission) problem, so return FALSE to get the caller to
                   log the full error message. */
@@ -493,6 +457,11 @@ struct mail_storage *mailbox_get_storage(const struct mailbox *box)
        return box->storage;
 }
 
+const struct mail_storage_settings *mailbox_get_settings(struct mailbox *box)
+{
+       return box->storage->set;
+}
+
 const char *mailbox_get_name(const struct mailbox *box)
 {
        return box->name;
index ac210cc41383e0fce1a0ac234ec6959e20954885..a407d71e2150733fcd2466cd18b32074985d24c9 100644 (file)
@@ -13,33 +13,14 @@ struct message_size;
 #define MAIL_STORAGE_STAYALIVE_SECS 15
 
 enum mail_storage_flags {
-       /* Print debugging information while initializing the storage */
-       MAIL_STORAGE_FLAG_DEBUG                 = 0x01,
-       /* Allow full filesystem access with absolute or relative paths. */
-       MAIL_STORAGE_FLAG_FULL_FS_ACCESS        = 0x02,
-       /* Don't try to mmap() files */
-       MAIL_STORAGE_FLAG_MMAP_DISABLE          = 0x04,
-       /* Don't try to write() to mmap()ed files. Required for the few
-          OSes that don't have unified buffer cache
-          (currently OpenBSD <= 3.5) */
-       MAIL_STORAGE_FLAG_MMAP_NO_WRITE         = 0x08,
        /* Remember message headers' MD5 sum */
-       MAIL_STORAGE_FLAG_KEEP_HEADER_MD5       = 0x10,
-       /* Use CRLF linefeeds when saving mails. */
-       MAIL_STORAGE_FLAG_SAVE_CRLF             = 0x40,
+       MAIL_STORAGE_FLAG_KEEP_HEADER_MD5       = 0x01,
        /* Don't try to autodetect anything, require that the given data 
           contains all the necessary information. */
-       MAIL_STORAGE_FLAG_NO_AUTODETECTION      = 0x100,
+       MAIL_STORAGE_FLAG_NO_AUTODETECTION      = 0x02,
        /* Don't autocreate any directories. If they don't exist,
           fail to create the storage. */
-       MAIL_STORAGE_FLAG_NO_AUTOCREATE         = 0x200,
-       /* Rely on O_EXCL when creating dotlocks */
-       MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL      = 0x400,
-       /* Flush NFS caches for mail storage / index */
-       MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE     = 0x800,
-       MAIL_STORAGE_FLAG_NFS_FLUSH_INDEX       = 0x1000,
-       /* Don't use fsync() or fdatasync() */
-       MAIL_STORAGE_FLAG_FSYNC_DISABLE         = 0x2000
+       MAIL_STORAGE_FLAG_NO_AUTOCREATE         = 0x04
 };
 
 enum mailbox_open_flags {
@@ -239,9 +220,11 @@ struct mailbox_virtual_pattern {
        const char *pattern;
 };
 ARRAY_DEFINE_TYPE(mailbox_virtual_patterns, struct mailbox_virtual_pattern);
-
+ARRAY_DEFINE_TYPE(mail_storage, struct mail_storage *);
 ARRAY_DEFINE_TYPE(mailboxes, struct mailbox *);
 
+extern ARRAY_TYPE(mail_storage) mail_storage_classes;
+
 typedef void mailbox_notify_callback_t(struct mailbox *box, void *context);
 
 void mail_storage_init(void);
@@ -257,25 +240,25 @@ void mail_storage_class_unregister(struct mail_storage *storage_class);
 /* Find mail storage class by name */
 struct mail_storage *mail_storage_find_class(const char *name);
 
-/* Returns flags and lock_method based on environment settings. */
-void mail_storage_parse_env(enum mail_storage_flags *flags_r,
-                           enum file_lock_method *lock_method_r);
-
 /* Create a new instance of registered mail storage class with given
    storage-specific data. If driver is NULL, it's tried to be autodetected
-   from data. If data is NULL, it uses the first storage that exists.
-   The storage is put into ns->storage. */
+   from ns location. If ns location is NULL, it uses the first storage that
+   exists. The storage is put into ns->storage. */
 int mail_storage_create(struct mail_namespace *ns, const char *driver,
-                       const char *data, enum mail_storage_flags flags,
-                       enum file_lock_method lock_method,
-                       const char **error_r);
+                       enum mail_storage_flags flags, const char **error_r);
 void mail_storage_destroy(struct mail_storage **storage);
 
+/* Returns the storage's real hierarchy separator. */
 char mail_storage_get_hierarchy_sep(struct mail_storage *storage);
+/* Returns the storage's mailbox list backend. */
 struct mailbox_list *
 mail_storage_get_list(const struct mail_storage *storage) ATTR_PURE;
+/* Returns the storage's namespace. */
 struct mail_namespace *
 mail_storage_get_namespace(const struct mail_storage *storage) ATTR_PURE;
+/* Returns the mail storage settings. */
+const struct mail_storage_settings *
+mail_storage_get_settings(struct mail_storage *storage) ATTR_PURE;
 
 /* Set storage callback functions to use. */
 void mail_storage_set_callbacks(struct mail_storage *storage,
@@ -326,10 +309,15 @@ int mailbox_close(struct mailbox **box);
 
 /* Enable the given feature for the mailbox. */
 int mailbox_enable(struct mailbox *box, enum mailbox_feature features);
-enum mailbox_feature mailbox_get_enabled_features(struct mailbox *box);
+/* Returns all enabled features. */
+enum mailbox_feature
+mailbox_get_enabled_features(struct mailbox *box) ATTR_PURE;
 
 /* Returns storage of given mailbox */
 struct mail_storage *mailbox_get_storage(const struct mailbox *box) ATTR_PURE;
+/* Returns the storage's settings. */
+const struct mail_storage_settings *
+mailbox_get_settings(struct mailbox *box) ATTR_PURE;
 
 /* Returns name of given mailbox */
 const char *mailbox_get_name(const struct mailbox *box) ATTR_PURE;
index adb3290712311089e12b48158f9248792a539e20..6a5bc9be89a6ee95c28399fd1294a66847a43e2a 100644 (file)
@@ -2,7 +2,12 @@
 
 #include "lib.h"
 #include "array.h"
+#include "hostpid.h"
+#include "network.h"
+#include "var-expand.h"
+#include "settings-parser.h"
 #include "auth-master.h"
+#include "mail-storage-settings.h"
 #include "mail-namespace.h"
 #include "mail-user.h"
 
@@ -19,7 +24,8 @@ static void mail_user_deinit_base(struct mail_user *user)
        pool_unref(&user->pool);
 }
 
-struct mail_user *mail_user_init(const char *username)
+struct mail_user *mail_user_alloc(const char *username,
+                                 const struct mail_user_settings *set)
 {
        struct mail_user *user;
        pool_t pool;
@@ -27,17 +33,39 @@ struct mail_user *mail_user_init(const char *username)
        i_assert(username != NULL);
        i_assert(*username != '\0');
 
-       pool = pool_alloconly_create("mail user", 512);
+       pool = pool_alloconly_create("mail user", 2048);
        user = p_new(pool, struct mail_user, 1);
        user->pool = pool;
        user->refcount = 1;
        user->username = p_strdup(pool, username);
+       user->unexpanded_set = set;
+       user->set = settings_dup(&mail_user_setting_parser_info, set, pool);
        user->v.deinit = mail_user_deinit_base;
        p_array_init(&user->module_contexts, user->pool, 5);
+       return user;
+}
 
+int mail_user_init(struct mail_user *user, const char **error_r)
+{
+       const char *home, *key, *value;
+
+       if (user->_home == NULL &&
+           settings_vars_have_key(&mail_user_setting_parser_info, user->set,
+                                  'h', "home", &key, &value) &&
+           mail_user_get_home(user, &home) <= 0) {
+               *error_r = t_strdup_printf(
+                       "userdb didn't return a home directory, "
+                       "but %s used it (%%h): %s", key, value);
+               return -1;
+       }
+
+       settings_var_expand(&mail_user_setting_parser_info, user->set,
+                           user->pool, mail_user_var_expand_table(user));
+
+       user->initialized = TRUE;
        if (hook_mail_user_created != NULL)
                hook_mail_user_created(user);
-       return user;
+       return 0;
 }
 
 void mail_user_ref(struct mail_user *user)
@@ -69,6 +97,62 @@ struct mail_user *mail_user_find(struct mail_user *user, const char *name)
        return NULL;
 }
 
+void mail_user_set_vars(struct mail_user *user, uid_t uid, const char *service,
+                       const struct ip_addr *local_ip,
+                       const struct ip_addr *remote_ip)
+{
+       user->uid = uid;
+       user->service = p_strdup(user->pool, service);
+       if (local_ip != NULL) {
+               user->local_ip = p_new(user->pool, struct ip_addr, 1);
+               *user->local_ip = *local_ip;
+       }
+       if (remote_ip != NULL) {
+               user->remote_ip = p_new(user->pool, struct ip_addr, 1);
+               *user->remote_ip = *remote_ip;
+       }
+}
+
+const struct var_expand_table *
+mail_user_var_expand_table(struct mail_user *user)
+{
+       static struct var_expand_table static_tab[] = {
+               { 'u', NULL, "user" },
+               { 'n', NULL, "username" },
+               { 'd', NULL, "domain" },
+               { 's', NULL, "service" },
+               { 'h', NULL, "home" },
+               { 'l', NULL, "lip" },
+               { 'r', NULL, "rip" },
+               { 'p', NULL, "pid" },
+               { 'i', NULL, "uid" },
+               { '\0', NULL, NULL }
+       };
+       struct var_expand_table *tab;
+
+       if (user->var_expand_table != NULL)
+               return user->var_expand_table;
+
+       tab = p_malloc(user->pool, sizeof(static_tab));
+       memcpy(tab, static_tab, sizeof(static_tab));
+
+       tab[0].value = user->username;
+       tab[1].value = p_strdup(user->pool, t_strcut(user->username, '@'));
+       tab[2].value = strchr(user->username, '@');
+       if (tab[2].value != NULL) tab[2].value++;
+       tab[3].value = user->service;
+       tab[4].value = user->_home; /* don't look it up unless we need it */
+       tab[5].value = user->local_ip == NULL ? NULL :
+               p_strdup(user->pool, net_ip2addr(user->local_ip));
+       tab[6].value = user->remote_ip == NULL ? NULL :
+               p_strdup(user->pool, net_ip2addr(user->remote_ip));
+       tab[7].value = my_pid;
+       tab[8].value = p_strdup(user->pool, dec2str(user->uid));
+
+       user->var_expand_table = tab;
+       return user->var_expand_table;
+}
+
 void mail_user_set_home(struct mail_user *user, const char *home)
 {
        user->_home = p_strdup(user->pool, home);
index 15903a5f5915336f5d416fde855c564eaa940cb0..873873bfcfc0cb1dcdaa82ea4dad9b2c79182969 100644 (file)
@@ -16,6 +16,15 @@ struct mail_user {
        /* don't access the home directly. It may be set lazily. */
        const char *_home;
 
+       uid_t uid;
+       const char *service;
+       struct ip_addr *local_ip, *remote_ip;
+       const struct var_expand_table *var_expand_table;
+       /* error during initialization */
+       const char *error;
+
+       const struct mail_user_settings *unexpanded_set;
+       struct mail_user_settings *set;
        struct mail_namespace *namespaces;
 
        /* Module-specific contexts. See mail_storage_module_id. */
@@ -26,6 +35,8 @@ struct mail_user {
        /* User is an administrator. Allow operations not normally allowed
           for other people. */
        unsigned int admin:1;
+       /* mail_user_init() has been called */
+       unsigned int initialized:1;
 };
 
 struct mail_user_module_register {
@@ -44,13 +55,25 @@ extern void (*hook_mail_user_created)(struct mail_user *user);
 void mail_users_init(const char *auth_socket_path, bool debug);
 void mail_users_deinit(void);
 
-struct mail_user *mail_user_init(const char *username);
+struct mail_user *mail_user_alloc(const char *username,
+                                 const struct mail_user_settings *set);
+/* Returns -1 if settings were invalid. */
+int mail_user_init(struct mail_user *user, const char **error_r);
+
 void mail_user_ref(struct mail_user *user);
 void mail_user_unref(struct mail_user **user);
 
 /* Find another user from the given user's namespaces. */
 struct mail_user *mail_user_find(struct mail_user *user, const char *name);
 
+/* Specify mail location %variable expansion data. */
+void mail_user_set_vars(struct mail_user *user, uid_t uid, const char *service,
+                       const struct ip_addr *local_ip,
+                       const struct ip_addr *remote_ip);
+/* Return %variable expansion table for the user. */
+const struct var_expand_table *
+mail_user_var_expand_table(struct mail_user *user);
+
 /* Specify the user's home directory. This should be called also when it's
    known that the user doesn't have a home directory to avoid the internal
    lookup. */
index 6f15cbdca7a9f23a997a268ac9e9803e63cbb1f7..66bcab4455f7316c646bf4b0f1a3dccdb84968ac 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "mail-namespace.h"
 #include "mailbox-list.h"
+#include "mail-storage-settings.h"
 
 struct dirent;
 struct imap_match_glob;
@@ -76,6 +77,7 @@ struct mailbox_list {
        pool_t pool;
        struct mail_namespace *ns;
        struct mailbox_list_settings set;
+       const struct mail_storage_settings *mail_set;
        enum mailbox_list_flags flags;
 
        /* -1 if not set yet. use mailbox_list_get_permissions() to set them */
index 6bd7a2fdc2df4238c6c760bff7686b9e5d238a3a..912f9eb385b7d7207b1f62aa261592462469f427 100644 (file)
@@ -192,6 +192,7 @@ void mailbox_list_init(struct mailbox_list *list, struct mail_namespace *ns,
                 *set->subscription_fname != '\0');
 
        list->ns = ns;
+       list->mail_set = ns->mail_set;
        list->flags = flags;
        list->file_create_mode = (mode_t)-1;
        list->file_create_gid = (gid_t)-1;
@@ -215,7 +216,7 @@ void mailbox_list_init(struct mailbox_list *list, struct mail_namespace *ns,
        list->set.mail_storage_flags = set->mail_storage_flags;
        list->set.lock_method = set->lock_method;
 
-       if ((flags & MAILBOX_LIST_FLAG_DEBUG) != 0) {
+       if (ns->mail_set->mail_debug) {
                i_info("%s: root=%s, index=%s, control=%s, inbox=%s",
                       list->name,
                       list->set.root_dir == NULL ? "" : list->set.root_dir,
@@ -278,7 +279,7 @@ void mailbox_list_get_permissions(struct mailbox_list *list,
                if (!ENOTFOUND(errno)) {
                        mailbox_list_set_critical(list, "stat(%s) failed: %m",
                                                  path);
-               } else if ((list->flags & MAILBOX_LIST_FLAG_DEBUG) != 0) {
+               } else if (list->mail_set->mail_debug) {
                        i_info("Namespace %s: Permission lookup failed from %s",
                               list->ns->prefix, path);
                }
@@ -303,7 +304,7 @@ void mailbox_list_get_permissions(struct mailbox_list *list,
                list->file_create_gid = st.st_gid;
        }
 
-       if ((list->flags & MAILBOX_LIST_FLAG_DEBUG) != 0) {
+       if (list->mail_set->mail_debug) {
                i_info("Namespace %s: Using permissions from %s: "
                       "mode=0%o gid=%ld", list->ns->prefix, path,
                       (int)list->file_create_mode,
@@ -726,7 +727,7 @@ mailbox_list_get_file_type(const struct dirent *d ATTR_UNUSED)
 bool mailbox_list_try_get_absolute_path(struct mailbox_list *list,
                                        const char **name)
 {
-       if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) == 0)
+       if (!list->mail_set->mail_full_filesystem_access)
                return FALSE;
 
        if (**name == '/')
index 0fe18ac6c9b09eaad8ed895f38eae6dcb27a867d..50366388a6d96ccb977a1eeeca211e8dbc062434 100644 (file)
@@ -13,16 +13,8 @@ enum mailbox_list_properties {
 };
 
 enum mailbox_list_flags {
-       /* Print debugging information while initializing the driver */
-       MAILBOX_LIST_FLAG_DEBUG                 = 0x01,
-       /* Allow full filesystem access with absolute or relative paths. */
-       MAILBOX_LIST_FLAG_FULL_FS_ACCESS        = 0x04,
-       /* Rely on O_EXCL when creating dotlocks */
-       MAILBOX_LIST_FLAG_DOTLOCK_USE_EXCL      = 0x08,
        /* Mailboxes are files, not directories. */
-       MAILBOX_LIST_FLAG_MAILBOX_FILES         = 0x10,
-       /* Flush NFS attribute cache when needed */
-       MAILBOX_LIST_FLAG_NFS_FLUSH             = 0x20
+       MAILBOX_LIST_FLAG_MAILBOX_FILES         = 0x01
 };
 
 enum mailbox_info_flags {
index 53cca2742baa20a9e334c793ccae482af35c8ac5..72196f65b2de79a19a161f39556047bc8be40075 100644 (file)
@@ -17,5 +17,6 @@ struct array {
 ARRAY_DEFINE_TYPE(string, char *);
 ARRAY_DEFINE_TYPE(const_string, const char *);
 ARRAY_DEFINE_TYPE(uint32_t, uint32_t);
+ARRAY_DEFINE_TYPE(void_array, void *);
 
 #endif
index e2b64af373a2c40334356f1523c75593bdeb295e..62bb7a2c836570d021405b9fecbae59c255a7b8a 100644 (file)
@@ -2,14 +2,17 @@ noinst_LIBRARIES = liblogin-common.a
 
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
+       -I$(top_srcdir)/src/lib-settings \
        -I$(top_srcdir)/src/lib-auth \
        -DPKG_RUNDIR=\""$(rundir)"\" \
        -DPKG_STATEDIR=\""$(statedir)"\" \
-       -DSBINDIR=\""$(sbindir)"\"
+       -DSBINDIR=\""$(sbindir)"\" \
+       -DSSLDIR=\""$(ssldir)\""
 
 liblogin_common_a_SOURCES = \
        client-common.c \
        login-proxy.c \
+       login-settings.c \
        main.c \
        master.c \
        sasl-server.c \
@@ -20,6 +23,7 @@ liblogin_common_a_SOURCES = \
 noinst_HEADERS = \
        client-common.h \
        login-proxy.h \
+       login-settings.h \
        common.h \
        master.h \
        sasl-server.h \
index c1609cf90fef3e7d65fa97ff4a2b91c1c3877900..32adfbe73894041af2c0b446e9f1d4c8defab63c 100644 (file)
@@ -128,7 +128,7 @@ client_get_log_str(struct client *client, const char *msg)
        memcpy(tab, static_tab, sizeof(static_tab));
 
        str = t_str_new(256);
-       for (e = log_format_elements; *e != NULL; e++) {
+       for (e = login_settings->log_format_elements_split; *e != NULL; e++) {
                for (p = *e; *p != '\0'; p++) {
                        if (*p != '%' || p[1] == '\0')
                                continue;
@@ -147,7 +147,7 @@ client_get_log_str(struct client *client, const char *msg)
        tab[1].value = msg;
        str_truncate(str, 0);
 
-       var_expand(str, log_format, tab);
+       var_expand(str, login_settings->login_log_format, tab);
        return str_c(str);
 }
 
@@ -171,10 +171,10 @@ bool client_is_trusted(struct client *client)
        struct ip_addr net_ip;
        unsigned int bits;
 
-       if (trusted_networks == NULL)
+       if (login_settings->login_trusted_networks == NULL)
                return FALSE;
 
-       net = t_strsplit_spaces(trusted_networks, ", ");
+       net = t_strsplit_spaces(login_settings->login_trusted_networks, ", ");
        for (; *net != NULL; net++) {
                if (net_parse_range(*net, &net_ip, &bits) < 0) {
                        i_error("login_trusted_networks: "
@@ -190,7 +190,7 @@ bool client_is_trusted(struct client *client)
 
 const char *client_get_extra_disconnect_reason(struct client *client)
 {
-       if (ssl_require_client_cert && client->proxy != NULL) {
+       if (login_settings->ssl_require_client_cert && client->proxy != NULL) {
                if (ssl_proxy_has_broken_client_cert(client->proxy))
                        return "(client sent an invalid cert)";
                if (!ssl_proxy_has_valid_client_cert(client->proxy))
@@ -203,7 +203,7 @@ const char *client_get_extra_disconnect_reason(struct client *client)
        /* some auth attempts without SSL/TLS */
        if (client->auth_tried_disabled_plaintext)
                return "(tried to use disabled plaintext auth)";
-       if (ssl_require_client_cert)
+       if (login_settings->ssl_require_client_cert)
                return "(cert required, client didn't start TLS)";
 
        return t_strdup_printf("(auth failed, %u attempts)",
index c55509d8a2787f638a6b3b9ebf3925b4c0e5ca6b..5c92dc9a6db2ac7b3dbaedb4c4487bae84e2ab0e 100644 (file)
@@ -2,6 +2,7 @@
 #define COMMON_H
 
 #include "lib.h"
+#include "login-settings.h"
 
 /* Used only for string sanitization */
 #define MAX_MECH_NAME 64
 
 extern const char *login_protocol;
 
-extern bool disable_plaintext_auth, process_per_connection;
-extern bool verbose_proctitle, verbose_ssl, verbose_auth, auth_debug;
-extern bool ssl_required, ssl_require_client_cert;
-extern const char *greeting, *log_format;
-extern const char *const *log_format_elements;
-extern const char *capability_string;
-extern const char *trusted_networks;
-extern unsigned int max_connections;
-extern unsigned int login_process_uid;
 extern struct auth_client *auth_client;
 extern bool closing_down;
+extern unsigned int login_process_uid;
+
+extern struct login_settings *login_settings;
 
 void main_ref(void);
 void main_unref(void);
diff --git a/src/login-common/login-settings.c b/src/login-common/login-settings.c
new file mode 100644 (file)
index 0000000..4a84684
--- /dev/null
@@ -0,0 +1,184 @@
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "login-settings.h"
+
+#include <stddef.h>
+#include <unistd.h>
+
+#undef DEF
+#define DEF(type, name) \
+       { type, #name, offsetof(struct login_settings, name), NULL }
+
+static struct setting_define login_setting_defines[] = {
+       DEF(SET_STR, login_dir),
+       DEF(SET_BOOL, login_chroot),
+       DEF(SET_STR, login_trusted_networks),
+       DEF(SET_STR, login_greeting),
+       DEF(SET_STR, login_log_format_elements),
+       DEF(SET_STR, login_log_format),
+
+       DEF(SET_BOOL, login_process_per_connection),
+       DEF(SET_STR, capability_string),
+
+       DEF(SET_ENUM, ssl),
+       DEF(SET_STR, ssl_ca_file),
+       DEF(SET_STR, ssl_cert_file),
+       DEF(SET_STR, ssl_key_file),
+       DEF(SET_STR, ssl_key_password),
+       DEF(SET_STR, ssl_parameters_file),
+       DEF(SET_STR, ssl_cipher_list),
+       DEF(SET_STR, ssl_cert_username_field),
+       DEF(SET_BOOL, ssl_verify_client_cert),
+       DEF(SET_BOOL, ssl_require_client_cert),
+       DEF(SET_BOOL, ssl_username_from_cert),
+       DEF(SET_BOOL, verbose_ssl),
+
+       DEF(SET_BOOL, disable_plaintext_auth),
+       DEF(SET_BOOL, verbose_auth),
+       DEF(SET_BOOL, auth_debug),
+       DEF(SET_BOOL, verbose_proctitle),
+
+       DEF(SET_UINT, login_max_connections),
+
+       SETTING_DEFINE_LIST_END
+};
+
+static struct login_settings login_default_settings = {
+       MEMBER(login_dir) "login",
+       MEMBER(login_chroot) TRUE,
+       MEMBER(login_trusted_networks) "",
+       MEMBER(login_greeting) PACKAGE" ready.",
+       MEMBER(login_log_format_elements) "user=<%u> method=%m rip=%r lip=%l %c",
+       MEMBER(login_log_format) "%$: %s",
+
+       MEMBER(login_process_per_connection) TRUE,
+       MEMBER(capability_string) NULL,
+
+       MEMBER(ssl) "yes:no:required",
+       MEMBER(ssl_ca_file) "",
+       MEMBER(ssl_cert_file) SSLDIR"/certs/dovecot.pem",
+       MEMBER(ssl_key_file) SSLDIR"/private/dovecot.pem",
+       MEMBER(ssl_key_password) "",
+       MEMBER(ssl_parameters_file) "ssl-parameters.dat",
+       MEMBER(ssl_cipher_list) "ALL:!LOW:!SSLv2",
+       MEMBER(ssl_cert_username_field) "commonName",
+       MEMBER(ssl_verify_client_cert) FALSE,
+       MEMBER(ssl_require_client_cert) FALSE,
+       MEMBER(ssl_username_from_cert) FALSE,
+       MEMBER(verbose_ssl) FALSE,
+
+       MEMBER(disable_plaintext_auth) TRUE,
+       MEMBER(verbose_auth) FALSE,
+       MEMBER(auth_debug) FALSE,
+       MEMBER(verbose_proctitle) FALSE,
+
+       MEMBER(login_max_connections) 256
+};
+
+struct setting_parser_info login_setting_parser_info = {
+       MEMBER(defines) login_setting_defines,
+       MEMBER(defaults) &login_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 login_settings)
+};
+
+static pool_t settings_pool = NULL;
+
+static int ssl_settings_check(struct login_settings *set ATTR_UNUSED)
+{
+#ifndef HAVE_SSL
+        i_error("SSL support not compiled in but ssl_disable=no");
+       return FALSE;
+#else
+       if (*set->ssl_cert_file == '\0') {
+               i_error("ssl_cert_file not set");
+               return FALSE;
+       }
+       if (access(set->ssl_cert_file, R_OK) < 0) {
+               i_error("ssl_cert_file: access(%s) failed: %m",
+                       set->ssl_cert_file);
+               return FALSE;
+       }
+
+       if (*set->ssl_key_file == '\0') {
+               i_error("ssl_key_file not set");
+               return FALSE;
+       }
+       if (access(set->ssl_key_file, R_OK) < 0) {
+               i_error("ssl_key_file: access(%s) failed: %m",
+                       set->ssl_key_file);
+               return FALSE;
+       }
+
+       if (*set->ssl_ca_file != '\0' &&
+           access(set->ssl_ca_file, R_OK) < 0) {
+               i_error("ssl_ca_file: access(%s) failed: %m",
+                       set->ssl_ca_file);
+               return FALSE;
+       }
+
+       if (set->ssl_verify_client_cert && *set->ssl_ca_file == '\0') {
+               i_error("ssl_verify_client_cert set, but ssl_ca_file not");
+               return FALSE;
+       }
+       return TRUE;
+#endif
+}
+
+static void login_settings_check(struct login_settings *set)
+{
+       if (strcmp(set->ssl, "no") == 0) {
+               /* disabled */
+       } else if (strcmp(set->ssl, "yes") == 0) {
+               if (!ssl_settings_check(set))
+                       set->ssl = "no";
+       } else if (strcmp(set->ssl, "required") == 0) {
+               if (!ssl_settings_check(set))
+                       i_fatal("Couldn't initialize ssl with ssl=required");
+               set->disable_plaintext_auth = TRUE;
+       } else {
+               i_fatal("Unknown ssl setting value: %s", set->ssl);
+       }
+
+       set->log_format_elements_split =
+               t_strsplit(set->login_log_format_elements, " ");
+
+       if (set->ssl_require_client_cert || set->ssl_username_from_cert) {
+               /* if we require valid cert, make sure we also ask for it */
+               set->ssl_verify_client_cert = TRUE;
+       }
+       if (set->login_max_connections < 1)
+               i_fatal("login_max_connections must be at least 1");
+}
+
+struct login_settings *login_settings_read(void)
+{
+       struct setting_parser_context *parser;
+        struct login_settings *set;
+
+       if (settings_pool == NULL)
+               settings_pool = pool_alloconly_create("settings pool", 512);
+       else
+               p_clear(settings_pool);
+
+       parser = settings_parser_init(settings_pool,
+                                     &login_setting_parser_info,
+                                     SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
+
+       if (settings_parse_environ(parser) < 0) {
+               i_fatal("Error reading configuration: %s",
+                       settings_parser_get_error(parser));
+       }
+
+       set = settings_parser_get(parser);
+       settings_parser_deinit(&parser);
+       login_settings_check(set);
+       return set;
+}
diff --git a/src/login-common/login-settings.h b/src/login-common/login-settings.h
new file mode 100644 (file)
index 0000000..c8109b3
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef __LOGIN_SETTINGS_H
+#define __LOGIN_SETTINGS_H
+
+struct login_settings {
+       const char *login_dir;
+       bool login_chroot;
+       const char *login_trusted_networks;
+       const char *login_greeting;
+       const char *login_log_format_elements, *login_log_format;
+
+       bool login_process_per_connection;
+       const char *capability_string;
+
+       const char *ssl;
+       const char *ssl_ca_file;
+       const char *ssl_cert_file;
+       const char *ssl_key_file;
+       const char *ssl_key_password;
+       const char *ssl_parameters_file;
+       const char *ssl_cipher_list;
+       const char *ssl_cert_username_field;
+       bool ssl_verify_client_cert;
+       bool ssl_require_client_cert;
+       bool ssl_username_from_cert;
+       bool verbose_ssl;
+
+       bool disable_plaintext_auth;
+       bool verbose_auth;
+       bool auth_debug;
+       bool verbose_proctitle;
+
+       unsigned int login_max_connections;
+
+       /* generated: */
+       const char *const *log_format_elements_split;
+};
+
+struct login_settings *login_settings_read(void);
+
+#endif
index 67eb90d60b07f9352d4d1868371eb102457bd0d8..2152ccb78f66731602294fe94d1731d504b90938 100644 (file)
 #include <unistd.h>
 #include <syslog.h>
 
-bool disable_plaintext_auth, process_per_connection;
-bool verbose_proctitle, verbose_ssl, verbose_auth, auth_debug;
-bool ssl_required, ssl_require_client_cert;
-const char *greeting, *log_format;
-const char *const *log_format_elements;
-const char *trusted_networks;
-unsigned int max_connections;
+struct login_settings *login_settings;
 unsigned int login_process_uid;
 struct auth_client *auth_client;
 bool closing_down;
@@ -101,7 +95,7 @@ static void login_accept(void *context)
        client->remote_port = remote_port;
        client->local_port = local_port;
 
-       if (process_per_connection) {
+       if (login_settings->login_process_per_connection) {
                closing_down = TRUE;
                main_listen_stop();
        }
@@ -139,7 +133,7 @@ static void login_accept_ssl(void *context)
                client->local_port = local_port;
        }
 
-       if (process_per_connection) {
+       if (login_settings->login_process_per_connection) {
                closing_down = TRUE;
                main_listen_stop();
        }
@@ -161,7 +155,7 @@ void main_listen_start(void)
        }
 
        current_count = ssl_proxy_get_count() + login_proxy_get_count();
-       if (current_count >= max_connections) {
+       if (current_count >= login_settings->login_max_connections) {
                /* can't accept any more connections until existing proxies
                   get destroyed */
                return;
@@ -220,9 +214,10 @@ void main_listen_stop(void)
 
 void connection_queue_add(unsigned int connection_count)
 {
+       unsigned int max_connections = login_settings->login_max_connections;
        unsigned int current_count;
 
-       if (process_per_connection)
+       if (login_settings->login_process_per_connection)
                return;
 
        current_count = clients_get_count() + ssl_proxy_get_count() +
@@ -256,6 +251,8 @@ static void drop_privileges(unsigned int *max_fds_r)
 {
        const char *value;
 
+        login_settings = login_settings_read();
+
        if (!is_inetd)
                i_set_failure_internal();
        else {
@@ -271,6 +268,7 @@ static void drop_privileges(unsigned int *max_fds_r)
        if (chdir(value) < 0)
                i_error("chdir(%s) failed: %m", value);
 
+
        /* Initialize SSL proxy so it can read certificate and private
           key file. */
        random_init();
@@ -280,14 +278,13 @@ static void drop_privileges(unsigned int *max_fds_r)
        listen_count = value == NULL ? 0 : atoi(value);
        value = getenv("SSL_LISTEN_FDS");
        ssl_listen_count = value == NULL ? 0 : atoi(value);
-       value = getenv("MAX_CONNECTIONS");
-       max_connections = value == NULL ? 1 : strtoul(value, NULL, 10);
 
        /* set the number of fds we want to use. it may get increased or
           decreased. leave a couple of extra fds for auth sockets and such.
           normal connections each use one fd, but SSL connections use two */
        *max_fds_r = LOGIN_MASTER_SOCKET_FD + 16 +
-               listen_count + ssl_listen_count + max_connections*2;
+               listen_count + ssl_listen_count +
+               login_settings->login_max_connections*2;
        restrict_fd_limit(*max_fds_r);
 
        /* Refuse to run as root - we should never need it and it's
@@ -314,31 +311,6 @@ static void main_init(void)
         lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
         lib_signals_ignore(SIGPIPE, TRUE);
 
-       process_per_connection = getenv("PROCESS_PER_CONNECTION") != NULL;
-       verbose_proctitle = getenv("VERBOSE_PROCTITLE") != NULL;
-        verbose_ssl = getenv("VERBOSE_SSL") != NULL;
-        verbose_auth = getenv("VERBOSE_AUTH") != NULL;
-        auth_debug = getenv("AUTH_DEBUG") != NULL;
-       ssl_required = getenv("SSL_REQUIRED") != NULL;
-       ssl_require_client_cert = getenv("SSL_REQUIRE_CLIENT_CERT") != NULL;
-       disable_plaintext_auth = ssl_required ||
-               getenv("DISABLE_PLAINTEXT_AUTH") != NULL;
-
-       greeting = getenv("GREETING");
-       if (greeting == NULL)
-               greeting = PACKAGE" ready.";
-
-       value = getenv("LOG_FORMAT_ELEMENTS");
-       if (value == NULL)
-               value = "user=<%u> method=%m rip=%r lip=%l %c : %$";
-       log_format_elements = t_strsplit(value, " ");
-
-       log_format = getenv("LOG_FORMAT");
-       if (log_format == NULL)
-               log_format = "%$: %s";
-
-       trusted_networks = getenv("TRUSTED_NETWORKS");
-
        value = getenv("PROCESS_UID");
        if (value == NULL)
                i_fatal("BUG: PROCESS_UID environment not given");
@@ -346,11 +318,6 @@ static void main_init(void)
        if (login_process_uid == 0)
                i_fatal("BUG: PROCESS_UID environment is 0");
 
-       /* capability default is set in imap/pop3-login */
-       value = getenv("CAPABILITY_STRING");
-       if (value != NULL && *value != '\0')
-               capability_string = value;
-
         closing_down = FALSE;
        main_refcount = 0;
 
index 43ead630ec37a6d1153f6489a183fd1800b80882..cf266356779cfa67cbe64c48c573874037e908c3 100644 (file)
@@ -39,7 +39,7 @@ static void request_handle(struct master_login_reply *reply)
 {
        struct client *client;
 
-       if (reply->tag == 0 && !process_per_connection) {
+       if (reply->tag == 0 && !login_settings->login_process_per_connection) {
                /* this means we have to start listening again.
                   we've reached maximum number of login processes. */
                main_listen_start();
index 52b476125605392b84a9a7fe94e1d49e7bf35102..45c8acb48bab0d231cfb1e536f05c4a4c58faca5 100644 (file)
@@ -149,7 +149,7 @@ void sasl_server_auth_begin(struct client *client,
                return;
        }
 
-       if (!client->secured && disable_plaintext_auth &&
+       if (!client->secured && login_settings->disable_plaintext_auth &&
            (mech->flags & MECH_SEC_PLAINTEXT) != 0) {
                sasl_server_auth_failed(client,
                        "Plaintext authentication disabled.");
@@ -182,7 +182,7 @@ static void sasl_server_auth_cancel(struct client *client, const char *reason,
 {
        i_assert(client->authenticating);
 
-       if (verbose_auth && reason != NULL) {
+       if (login_settings->verbose_auth && reason != NULL) {
                const char *auth_name =
                        str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
                client_syslog(client,
index 7fb9cffd5d92d6a6b4e512e6c0f6881b0b99075f..8cfbad9d063085aa34e87c786ad65affd0188929 100644 (file)
@@ -6,6 +6,7 @@
 #include "network.h"
 #include "ostream.h"
 #include "read-full.h"
+#include "safe-memset.h"
 #include "llist.h"
 #include "ssl-proxy.h"
 
@@ -22,7 +23,6 @@
 #include <openssl/err.h>
 #include <openssl/rand.h>
 
-#define DOVECOT_SSL_DEFAULT_CIPHER_LIST "ALL:!LOW:!SSLv2"
 /* Check every 30 minutes if parameters file has been updated */
 #define SSL_PARAMFILE_CHECK_INTERVAL (60*30)
 
@@ -679,7 +679,8 @@ static int ssl_verify_client_cert(int preverify_ok, X509_STORE_CTX *ctx)
        proxy = SSL_get_ex_data(ssl, extdata_index);
        proxy->cert_received = TRUE;
 
-       if (verbose_ssl || (verbose_auth && !preverify_ok)) {
+       if (login_settings->verbose_ssl ||
+           (login_settings->verbose_auth && !preverify_ok)) {
                char buf[1024];
                X509_NAME *subject;
 
@@ -755,23 +756,13 @@ static bool is_pem_key_file(const char *path)
 void ssl_proxy_init(void)
 {
        static char dovecot[] = "dovecot";
-       const char *cafile, *certfile, *keyfile, *cipher_list, *username_field;
-       char *password;
+       const struct login_settings *set = login_settings;
        unsigned char buf;
+       char *password;
        unsigned long err;
 
-       memset(&ssl_params, 0, sizeof(ssl_params));
-
-       cafile = getenv("SSL_CA_FILE");
-       certfile = getenv("SSL_CERT_FILE");
-       keyfile = getenv("SSL_KEY_FILE");
-       ssl_params.fname = getenv("SSL_PARAM_FILE");
-       password = getenv("SSL_KEY_PASSWORD");
-
-       if (certfile == NULL || keyfile == NULL || ssl_params.fname == NULL) {
-               /* SSL support is disabled */
+       if (strcmp(set->ssl, "no") == 0)
                return;
-       }
 
        CRYPTO_set_mem_functions(ssl_clean_malloc, ssl_clean_realloc,
                                 ssl_clean_free);
@@ -785,55 +776,56 @@ void ssl_proxy_init(void)
 
        SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL);
 
-       cipher_list = getenv("SSL_CIPHER_LIST");
-       if (cipher_list == NULL)
-               cipher_list = DOVECOT_SSL_DEFAULT_CIPHER_LIST;
-       if (SSL_CTX_set_cipher_list(ssl_ctx, cipher_list) != 1) {
+       if (SSL_CTX_set_cipher_list(ssl_ctx, set->ssl_cipher_list) != 1) {
                i_fatal("Can't set cipher list to '%s': %s",
-                       cipher_list, ssl_last_error());
+                       set->ssl_cipher_list, ssl_last_error());
        }
 
-       if (cafile != NULL) {
-               if (SSL_CTX_load_verify_locations(ssl_ctx, cafile, NULL) != 1) {
+       if (*set->ssl_ca_file != '\0') {
+               if (SSL_CTX_load_verify_locations(ssl_ctx, set->ssl_ca_file,
+                                                 NULL) != 1) {
                        i_fatal("Can't load CA file %s: %s",
-                               cafile, ssl_last_error());
+                               set->ssl_ca_file, ssl_last_error());
                }
        }
 
-       if (SSL_CTX_use_certificate_chain_file(ssl_ctx, certfile) != 1) {
+       if (SSL_CTX_use_certificate_chain_file(ssl_ctx,
+                                              set->ssl_cert_file) != 1) {
                err = ERR_peek_error();
                if (ERR_GET_LIB(err) != ERR_LIB_PEM ||
                    ERR_GET_REASON(err) != PEM_R_NO_START_LINE) {
                        i_fatal("Can't load certificate file %s: %s",
-                               certfile, ssl_last_error());
-               } else if (is_pem_key_file(certfile)) {
+                       set->ssl_cert_file, ssl_last_error());
+               } else if (is_pem_key_file(set->ssl_cert_file)) {
                        i_fatal("Can't load certificate file %s: "
                                "The file contains a private key "
                                "(you've mixed ssl_cert_file and ssl_key_file settings)",
-                               certfile);
+                               set->ssl_cert_file);
                } else {
                        i_fatal("Can't load certificate file %s: "
                                "The file doesn't contain a certificate.",
-                               certfile);
+                               set->ssl_cert_file);
                }
        }
 
+       password = t_strdup_noconst(set->ssl_key_password);
         SSL_CTX_set_default_passwd_cb(ssl_ctx, pem_password_callback);
         SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, password);
-       if (SSL_CTX_use_PrivateKey_file(ssl_ctx, keyfile,
+       if (SSL_CTX_use_PrivateKey_file(ssl_ctx, set->ssl_key_file,
                                        SSL_FILETYPE_PEM) != 1) {
                i_fatal("Can't load private key file %s: %s",
-                       keyfile, ssl_last_error());
+                       set->ssl_key_file, ssl_last_error());
        }
+       safe_memset(password, 0, strlen(password));
 
        if (SSL_CTX_need_tmp_RSA(ssl_ctx))
                SSL_CTX_set_tmp_rsa_callback(ssl_ctx, ssl_gen_rsa_key);
        SSL_CTX_set_tmp_dh_callback(ssl_ctx, ssl_tmp_dh_callback);
 
-       if (verbose_ssl)
+       if (set->verbose_ssl)
                SSL_CTX_set_info_callback(ssl_ctx, ssl_info_callback);
 
-       if (getenv("SSL_VERIFY_CLIENT_CERT") != NULL) {
+       if (set->ssl_verify_client_cert) {
 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
                X509_STORE *store;
 
@@ -845,18 +837,13 @@ void ssl_proxy_init(void)
                                   SSL_VERIFY_CLIENT_ONCE,
                                   ssl_verify_client_cert);
                SSL_CTX_set_client_CA_list(ssl_ctx,
-                                          SSL_load_client_CA_file(cafile));
+                       SSL_load_client_CA_file(set->ssl_ca_file));
        }
 
-       username_field = getenv("SSL_CERT_USERNAME_FIELD");
-       if (username_field == NULL)
-               ssl_username_nid = NID_commonName;
-       else {
-               ssl_username_nid = OBJ_txt2nid(username_field);
-               if (ssl_username_nid == NID_undef) {
-                       i_fatal("Invalid ssl_cert_username_field: %s",
-                               username_field);
-               }
+       ssl_username_nid = OBJ_txt2nid(set->ssl_cert_username_field);
+       if (ssl_username_nid == NID_undef) {
+               i_fatal("Invalid ssl_cert_username_field: %s",
+                       set->ssl_cert_username_field);
        }
 
        /* PRNG initialization might want to use /dev/urandom, make sure it
index aae3d7ebc06eded726d6c53fcb690514cf7695c7..ef647ea633bd788e170c46b7dfce38868614145a 100644 (file)
@@ -10,6 +10,7 @@ AM_CPPFLAGS = \
        -DPKG_RUNDIR=\""$(rundir)"\" \
        -DPKG_STATEDIR=\""$(statedir)"\" \
        -DPKG_LIBEXECDIR=\""$(pkglibexecdir)"\" \
+       -DBINDIR=\""$(bindir)"\" \
        -DMODULEDIR=\""$(moduledir)"\" \
        -DSSLDIR=\""$(ssldir)\""
 
@@ -29,8 +30,8 @@ dovecot_SOURCES = \
        log.c \
        login-process.c \
        mail-process.c \
-       main.c \
        master-settings.c \
+       main.c \
        syslog-util.c \
        ssl-init.c \
        sysinfo-get.c
@@ -53,9 +54,6 @@ noinst_HEADERS = \
        ssl-init.h \
        sysinfo-get.h
 
-EXTRA_DIST = \
-       master-settings-defs.c
-
 ssl_build_param_SOURCES = \
        ssl-init-main.c \
        ssl-init-openssl.c \
index a0804be567fff9d668613bcacb38f3c6c532e299..bdd790d6661d00f5b4b7cdbb95d92b0cb3f8e84f 100644 (file)
@@ -1,6 +1,7 @@
 /* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
 
 #include "common.h"
+#include "array.h"
 #include "hash.h"
 #include "ioloop.h"
 #include "env-util.h"
@@ -30,7 +31,8 @@ struct auth_process_group {
        struct auth_process_group *next;
 
        int listen_fd;
-       struct auth_settings *set;
+       const struct master_settings *master_set;
+       const struct master_auth_settings *set;
 
        unsigned int process_count;
        struct auth_process *processes;
@@ -323,7 +325,7 @@ auth_process_new(pid_t pid, int fd, struct auth_process_group *group)
        path = t_strdup_printf("%s/auth-worker.%s",
                               *group->set->chroot != '\0' ?
                               group->set->chroot :
-                              group->set->parent->defaults->base_dir,
+                              group->master_set->base_dir,
                               dec2str(pid));
        p->worker_listen_fd =
                unix_socket_create(path, 0600, group->set->uid,
@@ -371,7 +373,7 @@ static void auth_process_destroy(struct auth_process *p)
        path = t_strdup_printf("%s/auth-worker.%s",
                               *p->group->set->chroot != '\0' ?
                               p->group->set->chroot :
-                              p->group->set->parent->defaults->base_dir,
+                              p->group->master_set->base_dir,
                               dec2str(p->pid));
        (void)unlink(path);
 
@@ -393,21 +395,6 @@ static void auth_process_destroy(struct auth_process *p)
        i_free(p);
 }
 
-static void
-socket_settings_env_put(const char *env_base, struct socket_settings *set)
-{
-       if (!set->used)
-               return;
-
-       env_put(t_strdup_printf("%s=%s", env_base, set->path));
-       if (set->mode != 0)
-               env_put(t_strdup_printf("%s_MODE=%o", env_base, set->mode));
-       if (*set->user != '\0')
-               env_put(t_strdup_printf("%s_USER=%s", env_base, set->user));
-       if (*set->group != '\0')
-               env_put(t_strdup_printf("%s_GROUP=%s", env_base, set->group));
-}
-
 static int connect_auth_socket(struct auth_process_group *group,
                               const char *path)
 {
@@ -427,13 +414,10 @@ static int connect_auth_socket(struct auth_process_group *group,
        return 0;
 }
 
-static void auth_set_environment(struct auth_settings *set)
+static void auth_set_environment(const struct master_settings *master_set,
+                                const struct master_auth_settings *set)
 {
-       struct auth_socket_settings *as;
-       struct auth_passdb_settings *ap;
-       struct auth_userdb_settings *au;
-       const char *str;
-       int i;
+       master_settings_export_to_env(master_set);
 
        /* setup access environment */
        restrict_access_set_env(set->user, set->uid, set->gid,
@@ -442,93 +426,42 @@ static void auth_set_environment(struct auth_settings *set)
        /* set other environment */
        env_put("DOVECOT_MASTER=1");
        env_put(t_strconcat("AUTH_NAME=", set->name, NULL));
-       env_put(t_strconcat("MECHANISMS=", set->mechanisms, NULL));
-       env_put(t_strconcat("REALMS=", set->realms, NULL));
-       env_put(t_strconcat("DEFAULT_REALM=", set->default_realm, NULL));
-       env_put(t_strconcat("USERNAME_CHARS=", set->username_chars, NULL));
-       env_put(t_strconcat("ANONYMOUS_USERNAME=",
-                           set->anonymous_username, NULL));
-       env_put(t_strconcat("USERNAME_TRANSLATION=",
-                           set->username_translation, NULL));
-       env_put(t_strconcat("USERNAME_FORMAT=", set->username_format, NULL));
-       env_put(t_strconcat("MASTER_USER_SEPARATOR=",
-                           set->master_user_separator, NULL));
-       env_put(t_strdup_printf("CACHE_SIZE=%u", set->cache_size));
-       env_put(t_strdup_printf("CACHE_TTL=%u", set->cache_ttl));
-       env_put(t_strdup_printf("CACHE_NEGATIVE_TTL=%u",
-                               set->cache_negative_ttl));
-
-       for (ap = set->passdbs, i = 1; ap != NULL; ap = ap->next, i++) {
-               env_put(t_strdup_printf("PASSDB_%u_DRIVER=%s", i, ap->driver));
-               if (ap->args != NULL) {
-                       env_put(t_strdup_printf("PASSDB_%u_ARGS=%s",
-                                               i, ap->args));
-               }
-               if (ap->deny)
-                       env_put(t_strdup_printf("PASSDB_%u_DENY=1", i));
-                if (ap->pass)
-                        env_put(t_strdup_printf("PASSDB_%u_PASS=1", i));
-               if (ap->master)
-                        env_put(t_strdup_printf("PASSDB_%u_MASTER=1", i));
-       }
-       for (au = set->userdbs, i = 1; au != NULL; au = au->next, i++) {
-               env_put(t_strdup_printf("USERDB_%u_DRIVER=%s", i, au->driver));
-               if (au->args != NULL) {
-                       env_put(t_strdup_printf("USERDB_%u_ARGS=%s",
-                                               i, au->args));
-               }
-       }
-
-       for (as = set->sockets, i = 1; as != NULL; as = as->next, i++) {
-               if (strcmp(as->type, "listen") != 0)
-                       continue;
+       restrict_process_size(set->process_size, (unsigned int)-1);
+}
 
-               str = t_strdup_printf("AUTH_%u", i);
-               socket_settings_env_put(str, &as->client);
-               socket_settings_env_put(t_strconcat(str, "_MASTER", NULL),
-                                       &as->master);
-       }
+static const struct master_auth_socket_settings *
+get_connect_socket(const struct master_auth_settings *auth_set)
+{
+       struct master_auth_socket_settings *const *as;
+       unsigned int count;
 
-       if (set->verbose)
-               env_put("VERBOSE=1");
-       if (set->debug)
-               env_put("VERBOSE_DEBUG=1");
-       if (set->debug_passwords)
-               env_put("VERBOSE_DEBUG_PASSWORDS=1");
-       if (set->ssl_require_client_cert)
-               env_put("SSL_REQUIRE_CLIENT_CERT=1");
-       if (set->ssl_username_from_cert)
-               env_put("SSL_USERNAME_FROM_CERT=1");
-       if (set->use_winbind)
-               env_put("USE_WINBIND=1");
-       if (*set->krb5_keytab != '\0') {
-               /* Environment may be used by Kerberos 5 library directly,
-                  although we also try to use it directly as well */
-               env_put(t_strconcat("KRB5_KTNAME=", set->krb5_keytab, NULL));
-       }
-       if (*set->gssapi_hostname != '\0') {
-               env_put(t_strconcat("GSSAPI_HOSTNAME=",
-                                   set->gssapi_hostname, NULL));
-       }
-       env_put(t_strconcat("WINBIND_HELPER_PATH=",
-                           set->winbind_helper_path, NULL));
-       env_put(t_strdup_printf("FAILURE_DELAY=%u", set->failure_delay));
+       if (!array_is_created(&auth_set->sockets))
+               return NULL;
 
-       restrict_process_size(set->process_size, (unsigned int)-1);
+       as = array_get(&auth_set->sockets, &count);
+       if (count > 0 && strcmp(as[0]->type, "connect") == 0)
+               return as[0];
+       else
+               return NULL;
 }
 
 static int create_auth_process(struct auth_process_group *group)
 {
-       struct auth_socket_settings *as;
+       const struct master_auth_socket_settings *as;
+       struct master_auth_socket_unix_settings *const *masters;
        const char *prefix, *executable;
        struct log_io *log;
        pid_t pid;
+       unsigned int count;
        int fd[2], log_fd, i;
 
        /* see if this is a connect socket */
-       as = group->set->sockets;
-       if (as != NULL && strcmp(as->type, "connect") == 0)
-               return connect_auth_socket(group, as->master.path);
+       as = get_connect_socket(group->set);
+       if (as != NULL) {
+               masters = array_get(&as->masters, &count);
+               if (count > 0)
+                       return connect_auth_socket(group, masters[0]->path);
+       }
 
        /* create communication to process with a socket pair */
        if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
@@ -583,7 +516,7 @@ static int create_auth_process(struct auth_process_group *group)
        if (dup2(log_fd, 2) < 0)
                i_fatal("dup2(stderr) failed: %m");
 
-       child_process_init_env();
+       child_process_init_env(group->master_set);
 
        if (group->listen_fd != 3) {
                if (dup2(group->listen_fd, 3) < 0)
@@ -594,14 +527,12 @@ static int create_auth_process(struct auth_process_group *group)
        for (i = 0; i <= 2; i++)
                fd_close_on_exec(i, FALSE);
 
-        auth_set_environment(group->set);
+        auth_set_environment(group->master_set, group->set);
 
        env_put(t_strdup_printf("AUTH_WORKER_PATH=%s/auth-worker.%s",
                                *group->set->chroot != '\0' ? "" :
-                               group->set->parent->defaults->base_dir,
+                               group->master_set->base_dir,
                                dec2str(getpid())));
-       env_put(t_strdup_printf("AUTH_WORKER_MAX_COUNT=%u",
-                               group->set->worker_max_count));
 
        /* make sure we don't leak syslog fd, but do it last so that
           any errors above will be logged */
@@ -666,8 +597,8 @@ static int create_auth_worker(struct auth_process *process, int fd)
                fd_close_on_exec(i, FALSE);
        fd_close_on_exec(4, FALSE);
 
-       child_process_init_env();
-        auth_set_environment(process->group->set);
+       child_process_init_env(process->group->master_set);
+        auth_set_environment(process->group->master_set, process->group->set);
 
        /* make sure we don't leak syslog fd, but do it last so that
           any errors above will be logged */
@@ -694,25 +625,25 @@ struct auth_process *auth_process_find(unsigned int pid)
        return NULL;
 }
 
-static void auth_process_group_create(struct auth_settings *auth_set)
+static void auth_process_group_create(struct master_settings *set,
+                                     struct master_auth_settings *auth_set)
 {
        struct auth_process_group *group;
        const char *path;
 
        group = i_new(struct auth_process_group, 1);
+       group->master_set = set;
        group->set = auth_set;
 
        group->next = process_groups;
        process_groups = group;
 
-       if (auth_set->sockets != NULL &&
-           strcmp(auth_set->sockets->type, "connect") == 0)
+       if (get_connect_socket(auth_set) != NULL)
                return;
 
-       path = t_strconcat(auth_set->parent->defaults->login_dir, "/",
-                          auth_set->name, NULL);
+       path = t_strconcat(set->login_dir, "/", auth_set->name, NULL);
        group->listen_fd = unix_socket_create(path, 0660, master_uid,
-                                             auth_set->parent->login_gid, 128);
+                                             set->server->login_gid, 128);
        if (group->listen_fd == -1)
                i_fatal("Couldn't create auth process listener");
 
@@ -731,7 +662,7 @@ static void auth_process_group_destroy(struct auth_process_group *group)
                 group->processes = next;
        }
 
-       path = t_strconcat(group->set->parent->defaults->login_dir, "/",
+       path = t_strconcat(group->master_set->login_dir, "/",
                           group->set->name, NULL);
        (void)unlink(path);
 
@@ -753,17 +684,14 @@ void auth_processes_destroy_all(void)
        have_initialized_auth_processes = FALSE;
 }
 
-static void auth_process_groups_create(struct server_settings *server)
+static void auth_process_groups_create(struct master_settings *set)
 {
-       struct auth_settings *auth_set;
-
-       while (server != NULL) {
-               auth_set = server->auths;
-               for (; auth_set != NULL; auth_set = auth_set->next)
-                       auth_process_group_create(auth_set);
+       struct master_auth_settings *const *auth_sets;
+       unsigned int i, count;
 
-                server = server->next;
-       }
+       auth_sets = array_get(&set->auths, &count);
+       for (i = 0; i < count; i++)
+               auth_process_group_create(set, auth_sets[i]);
 }
 
 static void auth_processes_stall(void)
@@ -787,7 +715,7 @@ auth_processes_start_missing(void *context ATTR_UNUSED)
 
        if (process_groups == NULL) {
                /* first time here, create the groups */
-               auth_process_groups_create(settings_root);
+               auth_process_groups_create(master_set->defaults);
        }
 
        for (group = process_groups; group != NULL; group = group->next) {
index ad285421e2083c284e2c9189d10494a956f432dc..e2092a50229bc474d19caecd533092378c71cc89 100644 (file)
@@ -41,7 +41,7 @@ void child_process_remove(pid_t pid)
        hash_table_remove(processes, POINTER_CAST(pid));
 }
 
-void child_process_init_env(void)
+void child_process_init_env(const struct master_settings *set)
 {
        int facility;
 
@@ -53,13 +53,12 @@ void child_process_init_env(void)
        if (env_tz != NULL)
                env_put(t_strconcat("TZ=", env_tz, NULL));
 
-       if (settings_root == NULL ||
-           !syslog_facility_find(settings_root->defaults->syslog_facility,
-                                 &facility))
+       if (master_set == NULL ||
+           !syslog_facility_find(set->syslog_facility, &facility))
                facility = LOG_MAIL;
        env_put(t_strdup_printf("SYSLOG_FACILITY=%d", facility));
 
-       if (settings_root != NULL && !settings_root->defaults->version_ignore)
+       if (master_set != NULL && !set->version_ignore)
                env_put("DOVECOT_VERSION="PACKAGE_VERSION);
 #ifdef DEBUG
        if (gdb) env_put("GDB=1");
index c98b832cefc7cf21bd44ec5b2fe02ebf9992212c..0c4e826122575078deba53cffe371fb1b96791db 100644 (file)
@@ -32,7 +32,7 @@ struct child_process *child_process_lookup(pid_t pid);
 void child_process_add(pid_t pid, struct child_process *process);
 void child_process_remove(pid_t pid);
 
-void child_process_init_env(void);
+void child_process_init_env(const struct master_settings *set);
 void client_process_exec(const char *cmd, const char *title);
 void client_process_exec_argv(const char *executable, const char **argv);
 
index 3aa6b2f5f95e35f0cc27ea28770ad5d9f92756b8..8d9a8bac029680203e2528e3947d9db14ec85117 100644 (file)
@@ -94,17 +94,17 @@ static int dict_process_create(struct dict_listener *listener)
        for (i = 0; i <= 3; i++)
                fd_close_on_exec(i, FALSE);
 
-       child_process_init_env();
+       child_process_init_env(master_set->defaults);
        env_put(t_strconcat("DICT_LISTEN_FROM_FD=",
                            process->listener->path, NULL));
 
-       if (settings_root->defaults->dict_db_config != NULL) {
+       if (master_set->defaults->dict_db_config != NULL) {
                env_put(t_strconcat("DB_CONFIG=",
-                                   settings_root->defaults->dict_db_config,
+                                   master_set->defaults->dict_db_config,
                                    NULL));
        }
 
-       dicts = array_get(&settings_root->dicts, &count);
+       dicts = array_get(&master_set->defaults->dicts, &count);
        i_assert((count % 2) == 0);
        for (i = 0; i < count; i += 2)
                env_put(t_strdup_printf("DICT_%s=%s", dicts[i], dicts[i+1]));
@@ -146,14 +146,16 @@ static void dict_process_deinit(struct dict_process *process)
 
 static void dict_listener_input(struct dict_listener *listener)
 {
-       unsigned int i;
+       unsigned int i = 0;
        int fd;
 
        i_assert(listener->processes == NULL);
 
-       for (i = 0; i < settings_root->defaults->dict_process_count; i++) {
-               if (dict_process_create(listener) < 0)
-                       break;
+       if (array_is_created(&master_set->defaults->dicts)) {
+               for (i = 0; i < master_set->defaults->dict_process_count; i++) {
+                       if (dict_process_create(listener) < 0)
+                               break;
+               }
        }
        if (i > 0)
                io_remove(&listener->io);
@@ -220,7 +222,7 @@ void dict_processes_init(void)
 {
        const char *path;
 
-       path = t_strconcat(settings_root->defaults->base_dir,
+       path = t_strconcat(master_set->defaults->base_dir,
                           "/"DICT_SERVER_SOCKET_NAME, NULL);
        dict_listener = dict_listener_init(path);
 
index 747df9b94f40f4ae69971b5a0ecd0e9665c7a703..337c44be7c78ef93e1fd72992c3d11ed98b09173 100644 (file)
@@ -79,7 +79,7 @@ static void resolve_ip(const char *set_name, const char *name,
 }
 
 static void
-check_conflicts_set(const struct settings *set, const struct ip_addr *ip,
+check_conflicts_set(const struct master_settings *set, const struct ip_addr *ip,
                    unsigned int port, const char *name1, const char *name2)
 {
        const struct listener *listens = NULL;
@@ -115,17 +115,13 @@ check_conflicts_set(const struct settings *set, const struct ip_addr *ip,
 static void check_conflicts(const struct ip_addr *ip, unsigned int port,
                            const char *proto)
 {
-       struct server_settings *server;
-
-       for (server = settings_root; server != NULL; server = server->next) {
-               if (server->imap != NULL) {
-                       check_conflicts_set(server->imap, ip, port,
-                                           "imap", proto);
-               }
-               if (server->pop3 != NULL) {
-                       check_conflicts_set(server->pop3, ip, port,
-                                           "pop3", proto);
-               }
+       if (master_set->imap != NULL) {
+               check_conflicts_set(master_set->imap, ip, port,
+                                   "imap", proto);
+       }
+       if (master_set->pop3 != NULL) {
+               check_conflicts_set(master_set->pop3, ip, port,
+                                   "pop3", proto);
        }
 }
 
@@ -200,7 +196,7 @@ static void listener_close_fds(ARRAY_TYPE(listener) *listens_arr)
        array_free(listens_arr);
 }
 
-static void listen_parse_and_close_unneeded(struct settings *set)
+static void listen_parse_and_close_unneeded(struct master_settings *set)
 {
        const char *const *proto;
        unsigned int default_port;
@@ -246,7 +242,8 @@ static void listen_parse_and_close_unneeded(struct settings *set)
        }
 }
 
-static void listen_copy_old(struct settings *old_set, struct settings *new_set)
+static void listen_copy_old(struct master_settings *old_set,
+                           struct master_settings *new_set)
 {
        if (old_set == NULL || new_set == NULL) {
                if (old_set != NULL) {
@@ -317,49 +314,37 @@ listener_array_listen_missing(const char *proto,
 }
 
 static void
-listener_listen_missing(struct settings *set, const char *proto, bool retry)
+listener_listen_missing(struct master_settings *set,
+                       const char *proto, bool retry)
 {
        listener_array_listen_missing(proto, &set->listens, retry);
        listener_array_listen_missing(t_strconcat(proto, "s", NULL),
                                      &set->ssl_listens, retry);
 }
 
-void listeners_open_fds(struct server_settings *old_set, bool retry)
+void listeners_open_fds(struct master_server_settings *old_set, bool retry)
 {
-       struct server_settings *server;
-
-       for (server = settings_root; server != NULL; server = server->next) {
-               if (old_set != NULL) {
-                       listen_copy_old(old_set->imap, server->imap);
-                       listen_copy_old(old_set->pop3, server->pop3);
-               }
-               listen_parse_and_close_unneeded(server->imap);
-               listen_parse_and_close_unneeded(server->pop3);
-
-               if (old_set != NULL)
-                       old_set = old_set->next;
+       if (old_set != NULL) {
+               listen_copy_old(old_set->imap, master_set->imap);
+               listen_copy_old(old_set->pop3, master_set->pop3);
        }
+       listen_parse_and_close_unneeded(master_set->imap);
+       listen_parse_and_close_unneeded(master_set->pop3);
 
-       for (server = settings_root; server != NULL; server = server->next) {
-               if (server->imap != NULL)
-                       listener_listen_missing(server->imap, "imap", retry);
-               if (server->pop3 != NULL)
-                       listener_listen_missing(server->pop3, "pop3", retry);
-       }
+       if (master_set->imap != NULL)
+               listener_listen_missing(master_set->imap, "imap", retry);
+       if (master_set->pop3 != NULL)
+               listener_listen_missing(master_set->pop3, "pop3", retry);
 }
 
 void listeners_close_fds(void)
 {
-       struct server_settings *server;
-
-       for (server = settings_root; server != NULL; server = server->next) {
-               if (server->imap != NULL) {
-                       listener_close_fds(&server->imap->listens);
-                       listener_close_fds(&server->imap->ssl_listens);
-               }
-               if (server->pop3 != NULL) {
-                       listener_close_fds(&server->pop3->listens);
-                       listener_close_fds(&server->pop3->ssl_listens);
-               }
+       if (master_set->imap != NULL) {
+               listener_close_fds(&master_set->imap->listens);
+               listener_close_fds(&master_set->imap->ssl_listens);
+       }
+       if (master_set->pop3 != NULL) {
+               listener_close_fds(&master_set->pop3->listens);
+               listener_close_fds(&master_set->pop3->ssl_listens);
        }
 }
index 531a15ab685e32c6fa82a5574e08004bf9ea8362..0bd5a6f2fc55441cdd86cf96ea109f6263757991 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef LISTENER_H
 #define LISTENER_H
 
-void listeners_open_fds(struct server_settings *old_set, bool retry);
+void listeners_open_fds(struct master_server_settings *old_set, bool retry);
 void listeners_close_fds(void);
 
 #endif
index bd7608e9f2938c4445a5b29e00747ee39a7241ba..363579ddf0144bdbc1b5f128470bb5daaee40470 100644 (file)
@@ -16,6 +16,7 @@
 #include "auth-process.h"
 #include "mail-process.h"
 #include "master-login-interface.h"
+#include "master-settings.h"
 #include "log.h"
 #include "ssl-init.h"
 
@@ -65,7 +66,7 @@ static void login_process_unref(struct login_process *p);
 static bool login_process_init_group(struct login_process *p);
 static void login_processes_start_missing(void *context);
 
-static void login_group_create(struct settings *set)
+static void login_group_create(struct master_settings *set)
 {
        struct login_group *group;
 
@@ -217,18 +218,14 @@ login_process_set_state(struct login_process *p, enum master_login_state state)
 
 static void login_process_groups_create(void)
 {
-       struct server_settings *server;
-
-       for (server = settings_root; server != NULL; server = server->next) {
-               if (server->imap != NULL)
-                       login_group_create(server->imap);
-               if (server->pop3 != NULL)
-                       login_group_create(server->pop3);
-       }
+       if (master_set->imap != NULL)
+               login_group_create(master_set->imap);
+       if (master_set->pop3 != NULL)
+               login_group_create(master_set->pop3);
 }
 
 static struct login_group *
-login_group_process_find(const char *name, enum mail_protocol protocol)
+login_group_process_find(enum mail_protocol protocol)
 {
        struct login_group *group;
 
@@ -236,8 +233,7 @@ login_group_process_find(const char *name, enum mail_protocol protocol)
                 login_process_groups_create();
 
        for (group = login_groups; group != NULL; group = group->next) {
-               if (strcmp(group->set->server->name, name) == 0 &&
-                   group->set->protocol == protocol)
+               if (group->set->protocol == protocol)
                        return group;
        }
 
@@ -247,7 +243,7 @@ login_group_process_find(const char *name, enum mail_protocol protocol)
 static bool login_process_read_group(struct login_process *p)
 {
        struct login_group *group;
-       const char *name, *proto;
+       const char *proto;
        unsigned char buf[256];
        enum mail_protocol protocol;
        unsigned int len;
@@ -272,15 +268,7 @@ static bool login_process_read_group(struct login_process *p)
        else if (len == 0 || (size_t)ret != len)
                i_error("login: Server name wasn't sent");
        else {
-               name = t_strndup(buf, len);
-               proto = strchr(name, '/');
-               if (proto == NULL) {
-                       proto = name;
-                       name = "default";
-               } else {
-                       name = t_strdup_until(name, proto++);
-               }
-
+               proto = t_strndup(buf, len);
                if (strcmp(proto, "imap") == 0)
                        protocol = MAIL_PROTOCOL_IMAP;
                else if (strcmp(proto, "pop3") == 0)
@@ -290,9 +278,9 @@ static bool login_process_read_group(struct login_process *p)
                        return FALSE;
                }
 
-               group = login_group_process_find(name, protocol);
+               group = login_group_process_find(protocol);
                if (group == NULL) {
-                       i_error("login: Unknown server name '%s'", name);
+                       i_error("login: No group for protocol '%s'", proto);
                        return FALSE;
                }
 
@@ -534,11 +522,9 @@ static void login_process_unref(struct login_process *p)
 
 static void login_process_init_env(struct login_group *group, pid_t pid)
 {
-       struct settings *set = group->set;
-       const struct auth_settings *auth;
-       bool require_cert;
+       struct master_settings *set = group->set;
 
-       child_process_init_env();
+       child_process_init_env(group->set);
 
        /* setup access environment - needs to be done after
           clean_child_process() since it clears environment. Don't set user
@@ -551,79 +537,17 @@ static void login_process_init_env(struct login_group *group, pid_t pid)
 
        env_put("DOVECOT_MASTER=1");
 
-       if (strcmp(set->ssl, "no") != 0) {
-               const char *ssl_key_password;
-
-               ssl_key_password = *set->ssl_key_password != '\0' ?
-                       set->ssl_key_password : ssl_manual_key_password;
-
-               if (*set->ssl_ca_file != '\0') {
-                       env_put(t_strconcat("SSL_CA_FILE=",
-                                           set->ssl_ca_file, NULL));
-               }
-               if (strcmp(set->ssl, "required") == 0)
-                       env_put("SSL_REQUIRED=1");
-               env_put(t_strconcat("SSL_CERT_FILE=",
-                                   set->ssl_cert_file, NULL));
-               env_put(t_strconcat("SSL_KEY_FILE=",
-                                   set->ssl_key_file, NULL));
-               env_put(t_strconcat("SSL_KEY_PASSWORD=",
-                                   ssl_key_password, NULL));
-               env_put("SSL_PARAM_FILE="SSL_PARAMETERS_FILENAME);
-               if (*set->ssl_cipher_list != '\0') {
-                       env_put(t_strconcat("SSL_CIPHER_LIST=",
-                                           set->ssl_cipher_list, NULL));
-               }
-               env_put(t_strconcat("SSL_CERT_USERNAME_FIELD=",
-                                   set->ssl_cert_username_field, NULL));
-               if (set->ssl_verify_client_cert)
-                       env_put("SSL_VERIFY_CLIENT_CERT=1");
-       }
-
-       if (set->disable_plaintext_auth)
-               env_put("DISABLE_PLAINTEXT_AUTH=1");
-       if (set->verbose_proctitle)
-               env_put("VERBOSE_PROCTITLE=1");
-       if (set->verbose_ssl)
-               env_put("VERBOSE_SSL=1");
-       if (set->server->auths->verbose)
-               env_put("VERBOSE_AUTH=1");
-       if (set->server->auths->debug)
-               env_put("AUTH_DEBUG=1");
-       require_cert = TRUE;
-       for (auth = set->server->auths; auth != NULL; auth = auth->next) {
-               if (!auth->ssl_require_client_cert)
-                       require_cert = FALSE;
-       }
-       if (require_cert)
-               env_put("SSL_REQUIRE_CLIENT_CERT=1");
-
-       if (set->login_process_per_connection) {
-               env_put("PROCESS_PER_CONNECTION=1");
-               env_put("MAX_CONNECTIONS=1");
-       } else {
-               env_put(t_strdup_printf("MAX_CONNECTIONS=%u",
-                                       set->login_max_connections));
+       master_settings_export_to_env(group->set);
+       if (ssl_manual_key_password != NULL) {
+               env_put(t_strconcat("SSL_MANUAL_KEY_PASSWORD=",
+                                   ssl_manual_key_password, NULL));
        }
 
        env_put(t_strconcat("PROCESS_UID=", dec2str(pid), NULL));
-       env_put(t_strconcat("GREETING=", set->login_greeting, NULL));
-       env_put(t_strconcat("LOG_FORMAT_ELEMENTS=",
-                           set->login_log_format_elements, NULL));
-       env_put(t_strconcat("LOG_FORMAT=", set->login_log_format, NULL));
-       env_put(t_strconcat("IMAP_ID_SEND=", set->imap_id_send, NULL));
-       env_put(t_strconcat("IMAP_ID_LOG=", set->imap_id_log, NULL));
-
        if (group->mail_process_type == PROCESS_TYPE_IMAP) {
-               env_put(t_strconcat("CAPABILITY_STRING=",
-                                   *set->imap_capability != '\0' ?
-                                   set->imap_capability :
+               env_put(t_strconcat("GENERATED_CAPABILITY=",
                                    set->imap_generated_capability, NULL));
        }
-       if (*set->login_trusted_networks != '\0') {
-               env_put(t_strconcat("TRUSTED_NETWORKS=",
-                                   set->login_trusted_networks, NULL));
-       }
        env_put(t_strconcat("LOGIN_DIR=", set->login_dir, NULL));
 }
 
index 5a25f5a44ce570c5740963c50aebcff1720c0d81..f567ac2a17f263b641488918a99fdb2110b21432 100644 (file)
@@ -8,7 +8,7 @@ struct login_group {
        int refcount;
 
        enum process_type mail_process_type;
-       struct settings *set;
+       struct master_settings *set;
 
        unsigned int processes;
        unsigned int listening_processes;
index 117b9de67189ce2536af9fc1fd9a30479d15c457..9f1db3840bffe69aded74a779aee33735b0525ff 100644 (file)
@@ -13,6 +13,7 @@
 #include "restrict-process-size.h"
 #include "home-expand.h"
 #include "var-expand.h"
+#include "settings-parser.h"
 #include "mail-process.h"
 #include "login-process.h"
 #include "log.h"
@@ -112,7 +113,7 @@ static void mail_process_group_free(struct mail_process_group *group)
        i_free(group);
 }
 
-static bool validate_uid_gid(struct settings *set, uid_t uid, gid_t gid,
+static bool validate_uid_gid(struct master_settings *set, uid_t uid, gid_t gid,
                             const char *user)
 {
        if (uid == 0) {
@@ -146,7 +147,7 @@ static bool validate_uid_gid(struct settings *set, uid_t uid, gid_t gid,
        return TRUE;
 }
 
-static bool validate_chroot(struct settings *set, const char *dir)
+static bool validate_chroot(struct master_settings *set, const char *dir)
 {
        const char *const *chroot_dirs;
 
@@ -214,257 +215,59 @@ has_missing_used_home(const char *str, const struct var_expand_table *table)
                var_has_key(str, 'h', "home");
 }
 
-static const char *
-expand_mail_env(const char *env, const struct var_expand_table *table)
-{
-       string_t *str;
-       const char *p;
-
-       str = t_str_new(256);
-
-       /* it's either type:data or just data */
-       p = strchr(env, ':');
-       if (p != NULL) {
-               while (env != p) {
-                       str_append_c(str, *env);
-                       env++;
-               }
-
-               str_append_c(str, *env++);
-       }
-
-       if (has_missing_used_home(env, table)) {
-               i_fatal("userdb didn't return a home directory, "
-                       "but mail location used it (%%h): %s", env);
-       }
-
-       /* expand %vars */
-       var_expand(str, env, table);
-       return str_c(str);
-}
-
 static void
-env_put_namespace(struct namespace_settings *ns, const char *default_location,
-                 const struct var_expand_table *table)
+mail_process_set_environment(struct master_settings *set,
+                            const struct var_expand_table *table)
 {
-       const char *location;
-       unsigned int i;
-       string_t *str;
-
-       if (default_location == NULL)
-               default_location = "";
 
-       for (i = 1; ns != NULL; i++, ns = ns->next) {
-               location = *ns->location != '\0' ? ns->location :
-                       default_location;
-               location = expand_mail_env(location, table);
-               env_put(t_strdup_printf("NAMESPACE_%u=%s", i, location));
-
-               if (ns->separator != NULL) {
-                       env_put(t_strdup_printf("NAMESPACE_%u_SEP=%s",
-                                               i, ns->separator));
-               }
-               if (ns->type != NULL) {
-                       env_put(t_strdup_printf("NAMESPACE_%u_TYPE=%s",
-                                               i, ns->type));
-               }
-               if (ns->alias_for != NULL) {
-                       env_put(t_strdup_printf("NAMESPACE_%u_ALIAS=%s",
-                                               i, ns->alias_for));
-               }
-               if (ns->prefix != NULL) {
-                       /* expand variables, eg. ~%u/ can be useful */
-                       str = t_str_new(256);
-                       str_printfa(str, "NAMESPACE_%u_PREFIX=", i);
-                       var_expand(str, ns->prefix, table);
-                       env_put(str_c(str));
-               }
-               if (ns->inbox)
-                       env_put(t_strdup_printf("NAMESPACE_%u_INBOX=1", i));
-               if (ns->hidden)
-                       env_put(t_strdup_printf("NAMESPACE_%u_HIDDEN=1", i));
-               if (strcmp(ns->list, "no") != 0) {
-                       env_put(t_strdup_printf("NAMESPACE_%u_LIST=%s",
-                                               i, ns->list));
-               }
-               if (ns->subscriptions)
-                       env_put(t_strdup_printf("NAMESPACE_%u_SUBSCRIPTIONS=1",
-                                               i));
-       }
-}
-
-static void
-mail_process_set_environment(struct settings *set, const char *mail,
-                            const struct var_expand_table *var_expand_table,
-                            bool exec_mail)
-{
-       const char *const *envs;
+       const char **envs;
        string_t *str;
        unsigned int i, count;
 
-       env_put(t_strconcat("MAIL_CACHE_FIELDS=",
-                           set->mail_cache_fields, NULL));
-       env_put(t_strconcat("MAIL_NEVER_CACHE_FIELDS=",
-                           set->mail_never_cache_fields, NULL));
-       env_put(t_strdup_printf("MAIL_CACHE_MIN_MAIL_COUNT=%u",
-                               set->mail_cache_min_mail_count));
-       env_put(t_strdup_printf("MAILBOX_IDLE_CHECK_INTERVAL=%u",
-                               set->mailbox_idle_check_interval));
-       env_put(t_strdup_printf("MAIL_MAX_KEYWORD_LENGTH=%u",
-                               set->mail_max_keyword_length));
-
-       if (set->protocol == MAIL_PROTOCOL_IMAP) {
-               env_put(t_strdup_printf("IMAP_MAX_LINE_LENGTH=%u",
-                                       set->imap_max_line_length));
-               if (*set->imap_capability != '\0') {
-                       env_put(t_strconcat("IMAP_CAPABILITY=",
-                                           set->imap_capability, NULL));
-               }
-               env_put(t_strconcat("IMAP_CLIENT_WORKAROUNDS=",
-                                   set->imap_client_workarounds, NULL));
-               env_put(t_strconcat("IMAP_LOGOUT_FORMAT=",
-                                   set->imap_logout_format, NULL));
-               env_put(t_strconcat("IMAP_ID_SEND=", set->imap_id_send, NULL));
-               env_put(t_strconcat("IMAP_ID_LOG=", set->imap_id_log, NULL));
-       }
-       if (set->protocol == MAIL_PROTOCOL_POP3) {
-               env_put(t_strconcat("POP3_CLIENT_WORKAROUNDS=",
-                                   set->pop3_client_workarounds, NULL));
-               env_put(t_strconcat("POP3_LOGOUT_FORMAT=",
-                                   set->pop3_logout_format, NULL));
-               if (set->pop3_no_flag_updates)
-                       env_put("POP3_NO_FLAG_UPDATES=1");
-               if (set->pop3_reuse_xuidl)
-                       env_put("POP3_REUSE_XUIDL=1");
-               if (set->pop3_enable_last)
-                       env_put("POP3_ENABLE_LAST=1");
-               if (set->pop3_lock_session)
-                       env_put("POP3_LOCK_SESSION=1");
-       }
-
-       /* We care about POP3 UIDL format in all process types */
-       env_put(t_strconcat("POP3_UIDL_FORMAT=", set->pop3_uidl_format, NULL));
-
-       if (set->mail_save_crlf)
-               env_put("MAIL_SAVE_CRLF=1");
-       if (set->mmap_disable)
-               env_put("MMAP_DISABLE=1");
-       if (set->dotlock_use_excl)
-               env_put("DOTLOCK_USE_EXCL=1");
-       if (set->fsync_disable)
-               env_put("FSYNC_DISABLE=1");
-       if (set->mail_nfs_storage)
-               env_put("MAIL_NFS_STORAGE=1");
-       if (set->mail_nfs_index)
-               env_put("MAIL_NFS_INDEX=1");
-       if (set->mailbox_list_index_disable)
-               env_put("MAILBOX_LIST_INDEX_DISABLE=1");
-       if (set->maildir_stat_dirs)
-               env_put("MAILDIR_STAT_DIRS=1");
-       if (set->maildir_copy_with_hardlinks)
-               env_put("MAILDIR_COPY_WITH_HARDLINKS=1");
-       if (set->maildir_copy_preserve_filename)
-               env_put("MAILDIR_COPY_PRESERVE_FILENAME=1");
-       if (set->mail_debug)
-               env_put("DEBUG=1");
-       if (set->mail_full_filesystem_access)
-               env_put("FULL_FILESYSTEM_ACCESS=1");
-       if (set->mbox_dirty_syncs)
-               env_put("MBOX_DIRTY_SYNCS=1");
-       if (set->mbox_very_dirty_syncs)
-               env_put("MBOX_VERY_DIRTY_SYNCS=1");
-       if (set->mbox_lazy_writes)
-               env_put("MBOX_LAZY_WRITES=1");
-       /* when we're not certain that the log fd points to the master
-          process's log pipe (dump-capability, --exec-mail), don't let
-          the imap process listen for stderr since it might break
-          (e.g. epoll_ctl() gives EPERM). */
-       if (set->shutdown_clients && !exec_mail)
-               env_put("STDERR_CLOSE_SHUTDOWN=1");
+       settings_var_expand(&master_setting_parser_info, set,
+                           system_pool, table);
+
        (void)umask(set->umask);
 
-       env_put(t_strconcat("LOCK_METHOD=", set->lock_method, NULL));
-       env_put(t_strconcat("MBOX_READ_LOCKS=", set->mbox_read_locks, NULL));
-       env_put(t_strconcat("MBOX_WRITE_LOCKS=", set->mbox_write_locks, NULL));
-       env_put(t_strdup_printf("MBOX_LOCK_TIMEOUT=%u",
-                               set->mbox_lock_timeout));
-       env_put(t_strdup_printf("MBOX_DOTLOCK_CHANGE_TIMEOUT=%u",
-                               set->mbox_dotlock_change_timeout));
-       env_put(t_strdup_printf("MBOX_MIN_INDEX_SIZE=%u",
-                               set->mbox_min_index_size));
-
-       env_put(t_strdup_printf("DBOX_ROTATE_SIZE=%u",
-                               set->dbox_rotate_size));
-       env_put(t_strdup_printf("DBOX_ROTATE_MIN_SIZE=%u",
-                               set->dbox_rotate_min_size));
-       env_put(t_strdup_printf("DBOX_ROTATE_DAYS=%u",
-                               set->dbox_rotate_days));
-
-       if (*set->mail_plugins != '\0') {
-               env_put(t_strconcat("MAIL_PLUGIN_DIR=",
-                                   set->mail_plugin_dir, NULL));
-               env_put(t_strconcat("MAIL_PLUGINS=", set->mail_plugins, NULL));
-       }
-
-       /* user given environment - may be malicious. virtual_user comes from
-          auth process, but don't trust that too much either. Some auth
-          mechanism might allow leaving extra data there. */
-       if ((mail == NULL || *mail == '\0') && *set->mail_location != '\0')
-               mail = expand_mail_env(set->mail_location, var_expand_table);
-       env_put(t_strconcat("MAIL=", mail, NULL));
-
-       if (set->server->namespaces != NULL) {
-               env_put_namespace(set->server->namespaces,
-                                 mail, var_expand_table);
+       if (array_is_created(&set->plugin_envs))
+               envs = array_get_modifiable(&set->plugin_envs, &count);
+       else {
+               count = 0;
+               envs = NULL;
        }
-
        str = t_str_new(256);
-       envs = array_get(&set->plugin_envs, &count);
        i_assert((count % 2) == 0);
        for (i = 0; i < count; i += 2) {
-               str_truncate(str, 0);
-               var_expand(str, envs[i+1], var_expand_table);
-
-               if (has_missing_used_home(envs[i+1], var_expand_table)) {
+               if (has_missing_used_home(envs[i+1], table)) {
                        i_error("userdb didn't return a home directory, "
                                "but it's used in plugin setting %s: %s",
                                envs[i], envs[i+1]);
                }
-
-               env_put(t_strconcat(t_str_ucase(envs[i]), "=",
-                                   str_c(str), NULL));
+               str_truncate(str, 0);
+               var_expand(str, envs[i+1], table);
+               envs[i+1] = t_strdup(str_c(str));
        }
+
+       master_settings_export_to_env(set);
 }
 
 void mail_process_exec(const char *protocol, const char **args)
 {
-       struct server_settings *server = settings_root;
        const struct var_expand_table *var_expand_table;
-       struct settings *set;
+       struct master_settings *set;
        const char *executable;
 
        if (strcmp(protocol, "ext") == 0) {
                /* external binary. section contains path for it. */
                if (*args == NULL)
                        i_fatal("External binary parameter not given");
-               set = server->defaults;
+               set = master_set->defaults;
                executable = *args;
        } else {
-               const char *section = *args;
-
-               if (section != NULL) {
-                       for (; server != NULL; server = server->next) {
-                               if (strcmp(server->name, section) == 0)
-                                       break;
-                       }
-                       if (server == NULL)
-                               i_fatal("Section not found: '%s'", section);
-               }
-
                if (strcmp(protocol, "imap") == 0)
-                       set = server->imap;
+                       set = master_set->imap;
                else if (strcmp(protocol, "pop3") == 0)
-                       set = server->pop3;
+                       set = master_set->pop3;
                else
                        i_fatal("Unknown protocol: '%s'", protocol);
                executable = set->mail_executable;
@@ -493,8 +296,7 @@ void mail_process_exec(const char *protocol, const char **args)
                env_put(str_c(str));
        }
 
-       mail_process_set_environment(set, getenv("MAIL"), var_expand_table,
-                                    TRUE);
+       mail_process_set_environment(set, var_expand_table);
        if (args == NULL)
                client_process_exec(executable, "");
        else
@@ -542,7 +344,7 @@ static void nfs_warn_if_found(const char *mail, const char *full_home_dir)
 }
 
 enum master_login_status
-create_mail_process(enum process_type process_type, struct settings *set,
+create_mail_process(enum process_type process_type, struct master_settings *set,
                    const struct mail_login_request *request,
                    const char *user, const char *const *args,
                    const unsigned char *data, bool dump_capability,
@@ -752,7 +554,7 @@ create_mail_process(enum process_type process_type, struct settings *set,
                log_set_prefix(log, str_c(str));
        }
 
-       child_process_init_env();
+       child_process_init_env(set);
 
        /* move the client socket into stdin and stdout fds, log to stderr */
        if (dup2(dump_capability ? null_fd : request->fd, 0) < 0)
@@ -825,8 +627,7 @@ create_mail_process(enum process_type process_type, struct settings *set,
                        i_fatal("chdir(/tmp) failed: %m");
        }
 
-       mail_process_set_environment(set, mail, var_expand_table,
-                                    dump_capability);
+       mail_process_set_environment(set, var_expand_table);
 
        /* extra args. uppercase key value. */
        args = array_get(&extra_args, &count);
@@ -851,7 +652,7 @@ create_mail_process(enum process_type process_type, struct settings *set,
        if (nfs_check) {
                /* ideally we should check all of the namespaces,
                   but for now don't bother. */
-               const char *mail_location = getenv("NAMESPACE_1");
+               const char *mail_location = getenv("NAMESPACE_1"); //FIXME
 
                if (mail_location == NULL)
                        mail_location = getenv("MAIL");
index f85a605ef01dcdce1a78e74a26d68f4836763378..1dd62d2f5b1a575c92fad2bbf9d13fcd8aa63978 100644 (file)
@@ -17,7 +17,7 @@ struct auth_master_reply;
 void mail_process_exec(const char *protocol, const char **args) ATTR_NORETURN;
 
 enum master_login_status
-create_mail_process(enum process_type process_type, struct settings *set,
+create_mail_process(enum process_type process_type, struct master_settings *set,
                    const struct mail_login_request *request,
                    const char *user, const char *const *args,
                    const unsigned char *data, bool dump_capability,
index e5f32b0f211b1af52fb297c77d5b970a3e6a2774..c2913785d1dc23c896ad92247a18d6fcd7ae78ae 100644 (file)
@@ -54,7 +54,7 @@ static void ATTR_NORETURN ATTR_FORMAT(3, 0)
 master_fatal_callback(enum log_type type, int status,
                      const char *format, va_list args)
 {
-       const struct settings *set = settings_root->defaults;
+       const struct master_settings *set = master_set->defaults;
        const char *path, *str;
        va_list args2;
        int fd;
@@ -82,7 +82,7 @@ master_fatal_callback(enum log_type type, int status,
 
 static void fatal_log_check(void)
 {
-       const struct settings *set = settings_root->defaults;
+       const struct master_settings *set = master_set->defaults;
        const char *path;
        char buf[1024];
        ssize_t ret;
@@ -107,12 +107,15 @@ static void fatal_log_check(void)
                i_error("unlink(%s) failed: %m", path);
 }
 
-static void auth_warning_print(const struct server_settings *set)
+static void auth_warning_print(const struct master_server_settings *set)
 {
+       struct master_auth_settings *const *auths;
+       unsigned int count;
        struct stat st;
 
        auth_success_written = stat(AUTH_SUCCESS_PATH, &st) == 0;
-       if (!auth_success_written && !set->auths->debug &&
+       auths = array_get(&set->defaults->auths, &count);
+       if (!auth_success_written && count > 0 && !auths[0]->debug &&
            strcmp(set->defaults->protocols, "none") != 0) {
                i_info("If you have trouble with authentication failures,\n"
                       "enable auth_debug setting. "
@@ -121,7 +124,7 @@ static void auth_warning_print(const struct server_settings *set)
        }
 }
 
-static void set_logfile(struct settings *set)
+static void set_logfile(struct master_settings *set)
 {
        int facility;
 
@@ -144,7 +147,9 @@ static void set_logfile(struct settings *set)
 
 static void settings_reload(void)
 {
-       struct server_settings *old_set = settings_root;
+       /* this old_set wrapping works because master settings are
+          alternatingly read using two different pools */
+       struct master_server_settings *set, *old_set = master_set;
 
        i_warning("SIGHUP received - reloading configuration");
 
@@ -156,12 +161,13 @@ static void settings_reload(void)
        /* see if hostname changed */
        hostpid_init();
 
-       if (!master_settings_read(configfile, FALSE, FALSE))
+       if (master_settings_read(configfile, &set) < 0 ||
+           !master_settings_check(set, FALSE, FALSE))
                i_warning("Invalid configuration, keeping old one");
        else {
                if (!IS_INETD())
                        listeners_open_fds(old_set, TRUE);
-                set_logfile(settings_root->defaults);
+                set_logfile(set->defaults);
        }
 }
 
@@ -183,10 +189,10 @@ static void sig_reload_settings(int signo ATTR_UNUSED,
 static void sig_reopen_logs(int signo ATTR_UNUSED,
                            void *context ATTR_UNUSED)
 {
-       set_logfile(settings_root->defaults);
+       set_logfile(master_set->defaults);
 }
 
-static bool have_stderr_set(struct settings *set)
+static bool have_stderr_set(struct master_settings *set)
 {
        if (*set->log_path != '\0' &&
            strcmp(set->log_path, "/dev/stderr") == 0)
@@ -199,17 +205,12 @@ static bool have_stderr_set(struct settings *set)
        return FALSE;
 }
 
-static bool have_stderr(struct server_settings *server)
+static bool have_stderr(struct master_server_settings *server)
 {
-       while (server != NULL) {
-               if (server->imap != NULL && have_stderr_set(server->imap))
-                       return TRUE;
-               if (server->pop3 != NULL && have_stderr_set(server->pop3))
-                       return TRUE;
-
-               server = server->next;
-       }
-
+       if (server->imap != NULL && have_stderr_set(server->imap))
+               return TRUE;
+       if (server->pop3 != NULL && have_stderr_set(server->pop3))
+               return TRUE;
        return FALSE;
 }
 
@@ -259,6 +260,44 @@ static void create_pid_file(const char *path)
        (void)close(fd);
 }
 
+static void pid_file_check_running(const struct master_settings *set)
+{
+       const char *path;
+       char buf[32];
+       int fd;
+       ssize_t ret;
+
+       path = t_strconcat(set->base_dir, "/master.pid", NULL);
+       fd = open(path, O_RDONLY);
+       if (fd == -1) {
+               if (errno == ENOENT)
+                       return;
+               i_fatal("open(%s) failed: %m", path);
+       }
+
+       ret = read(fd, buf, sizeof(buf));
+       if (ret <= 0) {
+               if (ret == 0)
+                       i_error("Empty PID file in %s, overriding", path);
+               else
+                       i_fatal("read(%s) failed: %m", path);
+       } else {
+               pid_t pid;
+
+               if (buf[ret-1] == '\n')
+                       ret--;
+               buf[ret] = '\0';
+               pid = atoi(buf);
+               if (pid == getpid() || (kill(pid, 0) < 0 && errno == ESRCH)) {
+                       /* doesn't exist */
+               } else {
+                       i_fatal("Dovecot is already running with PID %s "
+                               "(read from %s)", buf, path);
+               }
+       }
+       (void)close(fd);
+}
+
 static void main_log_startup(void)
 {
 #define STARTUP_STRING PACKAGE_NAME" v"VERSION" starting up"
@@ -277,9 +316,9 @@ static void main_init(bool log_error)
        /* deny file access from everyone else except owner */
         (void)umask(0077);
 
-       set_logfile(settings_root->defaults);
+       set_logfile(master_set->defaults);
        /* close stderr unless we're logging into /dev/stderr. */
-       if (!have_stderr(settings_root)) {
+       if (!have_stderr(master_set)) {
                if (dup2(null_fd, 2) < 0)
                        i_fatal("dup2(2) failed: %m");
        }
@@ -309,13 +348,13 @@ static void main_init(bool log_error)
        login_processes_init();
        mail_processes_init();
 
-       create_pid_file(t_strconcat(settings_root->defaults->base_dir,
+       create_pid_file(t_strconcat(master_set->defaults->base_dir,
                                    "/master.pid", NULL));
 }
 
 static void main_deinit(void)
 {
-       (void)unlink(t_strconcat(settings_root->defaults->base_dir,
+       (void)unlink(t_strconcat(master_set->defaults->base_dir,
                                 "/master.pid", NULL));
 
        login_processes_destroy_all();
@@ -337,7 +376,7 @@ static void main_deinit(void)
        closelog();
 }
 
-static void daemonize(struct settings *set)
+static void daemonize(struct master_settings *set)
 {
        pid_t pid;
 
@@ -468,6 +507,7 @@ static void print_build_options(void)
 int main(int argc, char *argv[])
 {
        /* parse arguments */
+       struct master_server_settings *set;
        const char *exec_protocol = NULL, **exec_args = NULL, *user, *home;
        bool foreground = FALSE, ask_key_pass = FALSE, log_error = FALSE;
        bool dump_config = FALSE, dump_config_nondefaults = FALSE;
@@ -541,28 +581,37 @@ int main(int argc, char *argv[])
        /* read and verify settings before forking */
        T_BEGIN {
                master_settings_init();
-               if (!master_settings_read(configfile, exec_protocol != NULL,
-                                         dump_config || log_error))
+               if (master_settings_read(configfile, &set) < 0)
                        i_fatal("Invalid configuration in %s", configfile);
        } T_END;
 
+       if (!log_error && !dump_config && exec_protocol == NULL)
+               pid_file_check_running(set->defaults);
+
+       if (!master_settings_check(set, exec_protocol != NULL,
+                                  dump_config || log_error))
+               i_fatal("Invalid configuration in %s", configfile);
+
        if (dump_config) {
                const char *info;
 
-               info = sysinfo_get(settings_root->defaults->mail_location);
+               info = sysinfo_get(master_set->defaults->mail_location);
                if (*info != '\0')
                        printf("# %s\n", info);
 
-               master_settings_dump(settings_root, dump_config_nondefaults);
-               return 0;
+               if (dump_config_nondefaults)
+                       client_process_exec(DOVECOT_CONFIG_BIN_PATH" -a", "");
+               else
+                       client_process_exec(DOVECOT_CONFIG_BIN_PATH" -n", "");
+               i_fatal("exec(%s) failed: %m", DOVECOT_CONFIG_BIN_PATH);
        }
 
-       if (ask_key_pass) T_BEGIN {
+       if (ask_key_pass && !log_error) T_BEGIN {
                const char *prompt;
 
                prompt = t_strdup_printf("Give the password for SSL key file "
                                         "%s: ",
-                                        settings_root->defaults->ssl_key_file);
+                                        master_set->defaults->ssl_key_file);
                askpass(prompt, ssl_manual_key_password,
                        sizeof(ssl_manual_key_password));
        } T_END;
@@ -591,9 +640,9 @@ int main(int argc, char *argv[])
                open_fds();
 
        fatal_log_check();
-       auth_warning_print(settings_root);
+       auth_warning_print(master_set);
        if (!foreground)
-               daemonize(settings_root->defaults);
+               daemonize(master_set->defaults);
        master_original_pid = getpid();
 
        ioloop = io_loop_create();
diff --git a/src/master/master-settings-defs.c b/src/master/master-settings-defs.c
deleted file mode 100644 (file)
index 6d7e3bd..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/* kludgy: this file is included from master-settings.c and from deliver */
-
-#undef DEF_STR
-#undef DEF_INT
-#undef DEF_BOOL
-#define DEF_STR(name) DEF_STRUCT_STR(name, settings)
-#define DEF_INT(name) DEF_STRUCT_INT(name, settings)
-#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, settings)
-
-static struct setting_def setting_defs[] = {
-       /* common */
-       DEF_STR(base_dir),
-       DEF_STR(log_path),
-       DEF_STR(info_log_path),
-       DEF_STR(log_timestamp),
-       DEF_STR(syslog_facility),
-
-       /* general */
-       DEF_STR(protocols),
-       DEF_STR(listen),
-       DEF_STR(ssl_listen),
-
-       DEF_STR(ssl),
-       DEF_STR(ssl_ca_file),
-       DEF_STR(ssl_cert_file),
-       DEF_STR(ssl_key_file),
-       DEF_STR(ssl_key_password),
-       DEF_INT(ssl_parameters_regenerate),
-       DEF_STR(ssl_cipher_list),
-       DEF_STR(ssl_cert_username_field),
-       DEF_BOOL(ssl_verify_client_cert),
-       DEF_BOOL(disable_plaintext_auth),
-       DEF_BOOL(verbose_ssl),
-       DEF_BOOL(shutdown_clients),
-       DEF_BOOL(nfs_check),
-       DEF_BOOL(version_ignore),
-
-       /* login */
-       DEF_STR(login_dir),
-       DEF_STR(login_executable),
-       DEF_STR(login_user),
-       DEF_STR(login_greeting),
-       DEF_STR(login_log_format_elements),
-       DEF_STR(login_log_format),
-
-       DEF_BOOL(login_process_per_connection),
-       DEF_BOOL(login_chroot),
-       DEF_STR(login_trusted_networks),
-
-       DEF_INT(login_process_size),
-       DEF_INT(login_processes_count),
-       DEF_INT(login_max_processes_count),
-       DEF_INT(login_max_connections),
-
-       /* mail */
-       DEF_STR(valid_chroot_dirs),
-       DEF_STR(mail_chroot),
-       DEF_INT(max_mail_processes),
-       DEF_INT(mail_max_userip_connections),
-       DEF_BOOL(verbose_proctitle),
-
-       DEF_INT(first_valid_uid),
-       DEF_INT(last_valid_uid),
-       DEF_INT(first_valid_gid),
-       DEF_INT(last_valid_gid),
-       DEF_STR(mail_access_groups),
-       DEF_STR(mail_privileged_group),
-       DEF_STR(mail_uid),
-       DEF_STR(mail_gid),
-
-       DEF_STR(mail_location),
-       DEF_STR(mail_cache_fields),
-       DEF_STR(mail_never_cache_fields),
-       DEF_INT(mail_cache_min_mail_count),
-       DEF_INT(mailbox_idle_check_interval),
-       DEF_BOOL(mail_debug),
-       DEF_BOOL(mail_full_filesystem_access),
-       DEF_INT(mail_max_keyword_length),
-       DEF_BOOL(mail_save_crlf),
-       DEF_BOOL(mmap_disable),
-       DEF_BOOL(dotlock_use_excl),
-       DEF_BOOL(fsync_disable),
-       DEF_BOOL(mail_nfs_storage),
-       DEF_BOOL(mail_nfs_index),
-       DEF_BOOL(mailbox_list_index_disable),
-       DEF_STR(lock_method),
-       DEF_BOOL(maildir_stat_dirs),
-       DEF_BOOL(maildir_copy_with_hardlinks),
-       DEF_BOOL(maildir_copy_preserve_filename),
-       DEF_STR(mbox_read_locks),
-       DEF_STR(mbox_write_locks),
-       DEF_INT(mbox_lock_timeout),
-       DEF_INT(mbox_dotlock_change_timeout),
-       DEF_INT(mbox_min_index_size),
-       DEF_BOOL(mbox_dirty_syncs),
-       DEF_BOOL(mbox_very_dirty_syncs),
-       DEF_BOOL(mbox_lazy_writes),
-       DEF_INT(dbox_rotate_size),
-       DEF_INT(dbox_rotate_min_size),
-       DEF_INT(dbox_rotate_days),
-       DEF_INT(umask),
-       DEF_BOOL(mail_drop_priv_before_exec),
-
-       DEF_STR(mail_executable),
-       DEF_INT(mail_process_size),
-       DEF_STR(mail_plugins),
-       DEF_STR(mail_plugin_dir),
-       DEF_STR(mail_log_prefix),
-       DEF_INT(mail_log_max_lines_per_sec),
-
-       /* imap */
-       DEF_INT(imap_max_line_length),
-       DEF_STR(imap_capability),
-       DEF_STR(imap_client_workarounds),
-       DEF_STR(imap_logout_format),
-       DEF_STR(imap_id_send),
-       DEF_STR(imap_id_log),
-
-       /* pop3 */
-       DEF_BOOL(pop3_no_flag_updates),
-       DEF_BOOL(pop3_enable_last),
-       DEF_BOOL(pop3_reuse_xuidl),
-       DEF_BOOL(pop3_lock_session),
-       DEF_STR(pop3_uidl_format),
-       DEF_STR(pop3_client_workarounds),
-       DEF_STR(pop3_logout_format),
-
-       /* dict */
-       DEF_STR(dict_db_config),
-       DEF_INT(dict_process_count),
-
-       { 0, NULL, 0 }
-};
index 078edc143e88f001d12e7125df4bfc82408d905d..f74a2301c122b12e40d6c639ed9b45b305bf017b 100644 (file)
@@ -4,6 +4,7 @@
 #include "array.h"
 #include "str.h"
 #include "istream.h"
+#include "env-util.h"
 #include "fd-close-on-exec.h"
 #include "safe-mkdir.h"
 #include "mkdir-parents.h"
@@ -11,7 +12,7 @@
 #include "syslog-util.h"
 #include "mail-process.h"
 #include "master-login-interface.h"
-#include "settings.h"
+#include "settings-parser.h"
 
 #include <stdio.h>
 #include <stddef.h>
@@ -19,6 +20,7 @@
 #include <dirent.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <ctype.h>
 #include <signal.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #  include <sys/resource.h>
 #endif
 
-enum settings_type {
-       SETTINGS_TYPE_ROOT,
-       SETTINGS_TYPE_SERVER,
-       SETTINGS_TYPE_AUTH,
-       SETTINGS_TYPE_AUTH_SOCKET,
-       SETTINGS_TYPE_AUTH_PASSDB,
-       SETTINGS_TYPE_AUTH_USERDB,
-        SETTINGS_TYPE_NAMESPACE,
-       SETTINGS_TYPE_SOCKET,
-       SETTINGS_TYPE_DICT,
-       SETTINGS_TYPE_PLUGIN
-};
+extern struct setting_parser_info master_auth_setting_parser_info;
+extern struct setting_parser_info master_setting_parser_info;
+extern struct setting_parser_info master_auth_socket_setting_parser_info;
 
-struct settings_parse_ctx {
-       enum settings_type type, parent_type;
-       enum mail_protocol protocol;
+#undef DEF
+#define DEF(type, name) \
+       { type, #name, offsetof(struct master_auth_socket_unix_settings, name), NULL }
 
-       struct server_settings *root, *server;
-       struct auth_settings *auth;
-       struct socket_settings *socket;
-       struct auth_socket_settings *auth_socket;
-       struct auth_passdb_settings *auth_passdb;
-       struct auth_userdb_settings *auth_userdb;
-        struct namespace_settings *namespace;
+static struct setting_define master_auth_socket_master_setting_defines[] = {
+       DEF(SET_STR, path),
 
-       int level;
+       SETTING_DEFINE_LIST_END
 };
 
-#include "master-settings-defs.c"
-
-#undef DEF_STR
-#undef DEF_INT
-#undef DEF_BOOL
-#define DEF_STR(name) DEF_STRUCT_STR(name, auth_settings)
-#define DEF_INT(name) DEF_STRUCT_INT(name, auth_settings)
-#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, auth_settings)
-
-static struct setting_def auth_setting_defs[] = {
-       DEF_STR(mechanisms),
-       DEF_STR(realms),
-       DEF_STR(default_realm),
-       DEF_INT(cache_size),
-       DEF_INT(cache_ttl),
-       DEF_INT(cache_negative_ttl),
-       DEF_STR(executable),
-       DEF_STR(user),
-       DEF_STR(chroot),
-       DEF_STR(username_chars),
-       DEF_STR(username_translation),
-       DEF_STR(username_format),
-       DEF_STR(master_user_separator),
-       DEF_STR(anonymous_username),
-       DEF_STR(krb5_keytab),
-       DEF_STR(gssapi_hostname),
-       DEF_STR(winbind_helper_path),
-       DEF_INT(failure_delay),
-
-       DEF_BOOL(verbose),
-       DEF_BOOL(debug),
-       DEF_BOOL(debug_passwords),
-       DEF_BOOL(ssl_require_client_cert),
-       DEF_BOOL(ssl_username_from_cert),
-       DEF_BOOL(use_winbind),
-
-       DEF_INT(count),
-       DEF_INT(worker_max_count),
-       DEF_INT(process_size),
-
-       { 0, NULL, 0 }
+static struct master_auth_socket_unix_settings master_auth_socket_master_default_settings = {
+       MEMBER(path) "auth-master"
 };
 
-#undef DEF_STR
-#undef DEF_INT
-#undef DEF_BOOL
-#define DEF_STR(name) DEF_STRUCT_STR(name, socket_settings)
-#define DEF_INT(name) DEF_STRUCT_INT(name, socket_settings)
-#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, socket_settings)
+struct setting_parser_info master_auth_socket_master_setting_parser_info = {
+       MEMBER(defines) master_auth_socket_master_setting_defines,
+       MEMBER(defaults) &master_auth_socket_master_default_settings,
+
+       MEMBER(parent) &master_auth_socket_setting_parser_info,
+       MEMBER(dynamic_parsers) NULL,
 
-static struct setting_def socket_setting_defs[] = {
-       DEF_STR(path),
-       DEF_INT(mode),
-       DEF_STR(user),
-       DEF_STR(group),
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) (size_t)-1,
+       MEMBER(struct_size) sizeof(struct master_auth_socket_unix_settings)
+};
 
-       { 0, NULL, 0 }
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+       { type, #name, offsetof(struct master_auth_socket_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+       { SET_DEFLIST, name, offsetof(struct master_auth_socket_settings, field), defines }
+static struct setting_define master_auth_socket_setting_defines[] = {
+       DEF(SET_STR, type),
+       DEFLIST(masters, "master", &master_auth_socket_master_setting_parser_info),
+
+       SETTING_DEFINE_LIST_END
 };
 
-static struct setting_def auth_socket_setting_defs[] = {
-       DEF_STRUCT_STR(type, auth_socket_settings),
+struct setting_parser_info master_auth_socket_setting_parser_info = {
+       MEMBER(defines) master_auth_socket_setting_defines,
+       MEMBER(defaults) NULL,
+
+       MEMBER(parent) &master_auth_setting_parser_info,
+       MEMBER(dynamic_parsers) NULL,
 
-       { 0, NULL, 0 }
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) offsetof(struct master_auth_socket_settings, type),
+       MEMBER(struct_size) sizeof(struct master_auth_socket_settings)
 };
 
-#undef DEF_STR
-#undef DEF_INT
-#undef DEF_BOOL
-#define DEF_STR(name) DEF_STRUCT_STR(name, auth_passdb_settings)
-#define DEF_INT(name) DEF_STRUCT_INT(name, auth_passdb_settings)
-#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, auth_passdb_settings)
-
-static struct setting_def auth_passdb_setting_defs[] = {
-       DEF_STR(driver),
-       DEF_STR(args),
-       DEF_BOOL(deny),
-       DEF_BOOL(pass),
-       DEF_BOOL(master),
-
-       { 0, NULL, 0 }
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+       { type, #name, offsetof(struct master_auth_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+       { SET_DEFLIST, name, offsetof(struct master_auth_settings, field), defines }
+
+static struct setting_define master_auth_setting_defines[] = {
+       DEF(SET_STR, name),
+       DEF(SET_STR, executable),
+       DEF(SET_STR, user),
+       DEF(SET_STR, chroot),
+       DEF(SET_UINT, count),
+       DEF(SET_UINT, process_size),
+       DEF(SET_STR, mechanisms),
+       DEF(SET_BOOL, debug),
+       DEFLIST(sockets, "socket", &master_auth_socket_setting_parser_info),
+
+       SETTING_DEFINE_LIST_END
 };
 
-static struct setting_def auth_userdb_setting_defs[] = {
-       DEF_STRUCT_STR(driver, auth_userdb_settings),
-       DEF_STRUCT_STR(args, auth_userdb_settings),
+static struct master_auth_settings master_auth_default_settings = {
+       MEMBER(name) "default",
+       MEMBER(executable) PKG_LIBEXECDIR"/dovecot-auth",
+       MEMBER(user) "root",
+       MEMBER(chroot) "",
+       MEMBER(count) 1,
+       MEMBER(mechanisms) "plain",
+       MEMBER(debug) FALSE,
+       MEMBER(process_size) 256
 
-       { 0, NULL, 0 }
+       /* .. */
 };
 
-#undef DEF_STR
-#undef DEF_INT
-#undef DEF_BOOL
-#define DEF_STR(name) DEF_STRUCT_STR(name, namespace_settings)
-#define DEF_INT(name) DEF_STRUCT_INT(name, namespace_settings)
-#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, namespace_settings)
-
-static struct setting_def namespace_setting_defs[] = {
-       DEF_STR(type),
-       DEF_STR(separator),
-       DEF_STR(prefix),
-       DEF_STR(location),
-       DEF_STR(alias_for),
-       DEF_BOOL(inbox),
-       DEF_BOOL(hidden),
-       DEF_STR(list),
-       DEF_BOOL(subscriptions),
-
-       { 0, NULL, 0 }
+struct setting_parser_info master_auth_setting_parser_info = {
+       MEMBER(defines) master_auth_setting_defines,
+       MEMBER(defaults) &master_auth_default_settings,
+
+       MEMBER(parent) &master_setting_parser_info,
+       MEMBER(dynamic_parsers) NULL,
+
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) offsetof(struct master_auth_settings, name),
+       MEMBER(struct_size) sizeof(struct master_auth_settings)
 };
 
-struct settings default_settings = {
-       MEMBER(server) NULL,
-       MEMBER(protocol) 0,
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+       { type, #name, offsetof(struct master_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+       { SET_DEFLIST, name, offsetof(struct master_settings, field), defines }
+
+static struct setting_define master_setting_defines[] = {
+       /* common */
+       DEF(SET_STR, base_dir),
+       DEF(SET_STR, log_path),
+       DEF(SET_STR, info_log_path),
+       DEF(SET_STR, log_timestamp),
+       DEF(SET_STR, syslog_facility),
+
+       /* general */
+       DEF(SET_STR, protocols),
+       DEF(SET_STR, listen),
+       DEF(SET_STR, ssl_listen),
+
+       DEF(SET_STR, ssl),
+       DEF(SET_STR, ssl_key_file),
+       DEF(SET_UINT, ssl_parameters_regenerate),
+       DEF(SET_BOOL, nfs_check),
+       DEF(SET_BOOL, version_ignore),
+
+       /* login */
+       DEF(SET_STR, login_dir),
+       DEF(SET_STR, login_executable),
+       DEF(SET_STR, login_user),
+
+       DEF(SET_BOOL, login_process_per_connection),
+       DEF(SET_BOOL, login_chroot),
+       DEF(SET_BOOL, disable_plaintext_auth),
+
+       DEF(SET_UINT, login_process_size),
+       DEF(SET_UINT, login_processes_count),
+       DEF(SET_UINT, login_max_processes_count),
+
+       /* mail */
+       DEF(SET_STR, valid_chroot_dirs),
+       DEF(SET_STR, mail_chroot),
+       DEF(SET_UINT, max_mail_processes),
+       DEF(SET_UINT, mail_max_userip_connections),
+       DEF(SET_BOOL, verbose_proctitle),
+
+       DEF(SET_UINT, first_valid_uid),
+       DEF(SET_UINT, last_valid_uid),
+       DEF(SET_UINT, first_valid_gid),
+       DEF(SET_UINT, last_valid_gid),
+       DEF(SET_STR, mail_access_groups),
+       DEF(SET_STR, mail_privileged_group),
+       DEF(SET_STR, mail_uid),
+       DEF(SET_STR, mail_gid),
+
+       DEF(SET_STR, mail_plugins),
+       DEF(SET_STR, imap_capability),
+
+       DEF(SET_STR_VARS, mail_location),
+       DEF(SET_BOOL, mail_debug),
+       DEF(SET_BOOL, mail_nfs_index),
+       DEF(SET_UINT, umask),
+       DEF(SET_BOOL, mail_drop_priv_before_exec),
+
+       DEF(SET_STR, mail_executable),
+       DEF(SET_UINT, mail_process_size),
+       DEF(SET_STR_VARS, mail_log_prefix),
+       DEF(SET_UINT, mail_log_max_lines_per_sec),
 
+       /* dict */
+       DEF(SET_STR, dict_db_config),
+       DEF(SET_UINT, dict_process_count),
+       DEFLIST(auths, "auth", &master_auth_setting_parser_info),
+       { SET_STRLIST, "dict", offsetof(struct master_settings, dicts), NULL },
+       { SET_STRLIST, "plugin", offsetof(struct master_settings, plugin_envs), NULL },
+
+       SETTING_DEFINE_LIST_END
+};
+
+struct master_settings master_default_settings = {
        /* common */
        MEMBER(base_dir) PKG_RUNDIR,
        MEMBER(log_path) "",
@@ -183,17 +224,8 @@ struct settings default_settings = {
        MEMBER(ssl_listen) "",
 
        MEMBER(ssl) "yes",
-       MEMBER(ssl_ca_file) "",
-       MEMBER(ssl_cert_file) SSLDIR"/certs/dovecot.pem",
        MEMBER(ssl_key_file) SSLDIR"/private/dovecot.pem",
-       MEMBER(ssl_key_password) "",
        MEMBER(ssl_parameters_regenerate) 168,
-       MEMBER(ssl_cipher_list) "",
-       MEMBER(ssl_cert_username_field) "commonName",
-       MEMBER(ssl_verify_client_cert) FALSE,
-       MEMBER(disable_plaintext_auth) TRUE,
-       MEMBER(verbose_ssl) FALSE,
-       MEMBER(shutdown_clients) TRUE,
        MEMBER(nfs_check) TRUE,
        MEMBER(version_ignore) FALSE,
 
@@ -201,18 +233,14 @@ struct settings default_settings = {
        MEMBER(login_dir) "login",
        MEMBER(login_executable) NULL,
        MEMBER(login_user) "dovecot",
-       MEMBER(login_greeting) PACKAGE_NAME" ready.",
-       MEMBER(login_log_format_elements) "user=<%u> method=%m rip=%r lip=%l %c",
-       MEMBER(login_log_format) "%$: %s",
 
        MEMBER(login_process_per_connection) TRUE,
        MEMBER(login_chroot) TRUE,
-       MEMBER(login_trusted_networks) "",
+       MEMBER(disable_plaintext_auth) TRUE,
 
        MEMBER(login_process_size) 64,
        MEMBER(login_processes_count) 3,
        MEMBER(login_max_processes_count) 128,
-       MEMBER(login_max_connections) 256,
 
        /* mail */
        MEMBER(valid_chroot_dirs) "",
@@ -229,68 +257,20 @@ struct settings default_settings = {
        MEMBER(mail_privileged_group) "",
        MEMBER(mail_uid) "",
        MEMBER(mail_gid) "",
+       MEMBER(mail_plugins) "",
+       MEMBER(imap_capability) "",
 
        MEMBER(mail_location) "",
-       MEMBER(mail_cache_fields) "",
-       MEMBER(mail_never_cache_fields) "imap.envelope",
-       MEMBER(mail_cache_min_mail_count) 0,
-       MEMBER(mailbox_idle_check_interval) 30,
        MEMBER(mail_debug) FALSE,
-       MEMBER(mail_full_filesystem_access) FALSE,
-       MEMBER(mail_max_keyword_length) 50,
-       MEMBER(mail_save_crlf) FALSE,
-#ifdef MMAP_CONFLICTS_WRITE
-       MEMBER(mmap_disable) TRUE,
-#else
-       MEMBER(mmap_disable) FALSE,
-#endif
-       MEMBER(dotlock_use_excl) TRUE,
-       MEMBER(fsync_disable) FALSE,
-       MEMBER(mail_nfs_storage) FALSE,
        MEMBER(mail_nfs_index) FALSE,
-       MEMBER(mailbox_list_index_disable) TRUE,
-       MEMBER(lock_method) "fcntl",
-       MEMBER(maildir_stat_dirs) FALSE,
-       MEMBER(maildir_copy_with_hardlinks) TRUE,
-       MEMBER(maildir_copy_preserve_filename) FALSE,
-       MEMBER(mbox_read_locks) "fcntl",
-       MEMBER(mbox_write_locks) "dotlock fcntl",
-       MEMBER(mbox_lock_timeout) 300,
-       MEMBER(mbox_dotlock_change_timeout) 120,
-       MEMBER(mbox_min_index_size) 0,
-       MEMBER(mbox_dirty_syncs) TRUE,
-       MEMBER(mbox_very_dirty_syncs) FALSE,
-       MEMBER(mbox_lazy_writes) TRUE,
-       MEMBER(dbox_rotate_size) 2048,
-       MEMBER(dbox_rotate_min_size) 16,
-       MEMBER(dbox_rotate_days) 1,
        MEMBER(umask) 0077,
        MEMBER(mail_drop_priv_before_exec) FALSE,
 
-       MEMBER(mail_executable) PKG_LIBEXECDIR"/imap",
+       MEMBER(mail_executable) NULL,
        MEMBER(mail_process_size) 256,
-       MEMBER(mail_plugins) "",
-       MEMBER(mail_plugin_dir) MODULEDIR"/imap",
        MEMBER(mail_log_prefix) "%Us(%u): ",
        MEMBER(mail_log_max_lines_per_sec) 10,
 
-       /* imap */
-       MEMBER(imap_max_line_length) 65536,
-       MEMBER(imap_capability) "",
-       MEMBER(imap_client_workarounds) "",
-       MEMBER(imap_logout_format) "bytes=%i/%o",
-       MEMBER(imap_id_send) "",
-       MEMBER(imap_id_log) "",
-
-       /* pop3 */
-       MEMBER(pop3_no_flag_updates) FALSE,
-       MEMBER(pop3_enable_last) FALSE,
-       MEMBER(pop3_reuse_xuidl) FALSE,
-       MEMBER(pop3_lock_session) FALSE,
-       MEMBER(pop3_uidl_format) "%08Xu%08Xv",
-       MEMBER(pop3_client_workarounds) "",
-       MEMBER(pop3_logout_format) "top=%t/%p, retr=%r/%b, del=%d/%m, size=%s",
-
        /* dict */
        MEMBER(dict_db_config) NULL,
        MEMBER(dict_process_count) 1,
@@ -298,78 +278,136 @@ struct settings default_settings = {
        /* .. */
 };
 
-struct auth_settings default_auth_settings = {
+struct setting_parser_info master_setting_parser_info = {
+       MEMBER(defines) master_setting_defines,
+       MEMBER(defaults) &master_default_settings,
+
        MEMBER(parent) NULL,
-       MEMBER(next) NULL,
+       MEMBER(dynamic_parsers) NULL,
 
-       MEMBER(name) NULL,
-       MEMBER(mechanisms) "plain",
-       MEMBER(realms) "",
-       MEMBER(default_realm) "",
-       MEMBER(cache_size) 0,
-       MEMBER(cache_ttl) 3600,
-       MEMBER(cache_negative_ttl) 3600,
-       MEMBER(executable) PKG_LIBEXECDIR"/dovecot-auth",
-       MEMBER(user) "root",
-       MEMBER(chroot) "",
-       MEMBER(username_chars) "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@",
-       MEMBER(username_translation) "",
-       MEMBER(username_format) "",
-       MEMBER(master_user_separator) "",
-       MEMBER(anonymous_username) "anonymous",
-       MEMBER(krb5_keytab) "",
-       MEMBER(gssapi_hostname) "",
-       MEMBER(winbind_helper_path) "/usr/bin/ntlm_auth",
-       MEMBER(failure_delay) 2,
-
-       MEMBER(verbose) FALSE,
-       MEMBER(debug) FALSE,
-       MEMBER(debug_passwords) FALSE,
-       MEMBER(ssl_require_client_cert) FALSE,
-       MEMBER(ssl_username_from_cert) FALSE,
-       MEMBER(use_winbind) FALSE,
+       MEMBER(parent_offset) (size_t)-1,
+       MEMBER(type_offset) (size_t)-1,
+       MEMBER(struct_size) sizeof(struct master_settings)
+};
 
-       MEMBER(count) 1,
-       MEMBER(worker_max_count) 30,
-       MEMBER(process_size) 256,
+static pool_t settings_pool, settings2_pool;
+struct master_server_settings *master_set = NULL;
 
-       /* .. */
-       MEMBER(uid) 0,
-       MEMBER(gid) 0,
-       MEMBER(passdbs) NULL,
-       MEMBER(userdbs) NULL,
-       MEMBER(sockets) NULL
-};
+#ifdef HAVE_MODULES
+static const char *
+get_process_capability(enum process_type ptype, struct master_settings *set)
+{
+       /* FIXME: pretty ugly code just for getting the capability
+          automatically */
+       static const char *args[] = {
+               "uid=65534",
+               "gid=65534",
+               "home=/tmp",
+               NULL
+       };
+       const char *pname = process_names[ptype];
+       enum master_login_status login_status;
+       struct mail_login_request request;
+       char buf[4096];
+       int fd[2], status;
+       ssize_t ret;
+       unsigned int pos;
+       uid_t uid;
+       pid_t pid;
 
-struct socket_settings default_socket_settings = {
-#define DEFAULT_MASTER_SOCKET_PATH "auth-master"
-#define DEFAULT_CLIENT_SOCKET_PATH "auth-client"
-       MEMBER(path) "",
-       MEMBER(mode) 0600,
-       MEMBER(user) "",
-       MEMBER(group) ""
-};
+       uid = geteuid();
+       if (uid != 0) {
+               /* use the current user */
+               args[0] = t_strdup_printf("uid=%s", dec2str(uid));
+               args[1] = t_strdup_printf("gid=%s", dec2str(getegid()));
+       }
 
-struct namespace_settings default_namespace_settings = {
-       MEMBER(parent) NULL,
-       MEMBER(next) NULL,
-       MEMBER(type) NULL,
-
-       MEMBER(separator) "",
-       MEMBER(prefix) "",
-       MEMBER(location) "",
-       MEMBER(alias_for) NULL,
-
-       MEMBER(inbox) FALSE,
-       MEMBER(hidden) FALSE,
-       MEMBER(list) "yes",
-       MEMBER(subscriptions) TRUE
-};
+       if (pipe(fd) < 0) {
+               i_error("pipe() failed: %m");
+               return NULL;
+       }
+       fd_close_on_exec(fd[0], TRUE);
+       fd_close_on_exec(fd[1], TRUE);
 
-static pool_t settings_pool, settings2_pool;
-struct server_settings *settings_root = NULL;
+       memset(&request, 0, sizeof(request));
+       request.fd = fd[1];
+       login_status = create_mail_process(ptype, set, &request,
+                                          "dump-capability", args, NULL, TRUE,
+                                          &pid);
+       if (login_status != MASTER_LOGIN_STATUS_OK) {
+               (void)close(fd[0]);
+               (void)close(fd[1]);
+               return NULL;
+       }
+       (void)close(fd[1]);
+
+       alarm(5);
+       if (wait(&status) == -1) {
+               i_fatal("%s dump-capability process %d got stuck",
+                       pname, (int)pid);
+       }
+       alarm(0);
+
+       if (status != 0) {
+               (void)close(fd[0]);
+               if (WIFSIGNALED(status)) {
+                       i_error("%s dump-capability process "
+                               "killed with signal %d",
+                               pname, WTERMSIG(status));
+               } else {
+                       i_error("%s dump-capability process returned %d",
+                               pname, WIFEXITED(status) ? WEXITSTATUS(status) :
+                               status);
+               }
+               return NULL;
+       }
+
+       pos = 0;
+       while ((ret = read(fd[0], buf + pos, sizeof(buf) - pos)) > 0)
+               pos += ret;
+
+       if (ret < 0) {
+               i_error("read(%s dump-capability process) failed: %m", pname);
+               (void)close(fd[0]);
+               return NULL;
+       }
+       (void)close(fd[0]);
+
+       if (pos == 0 || buf[pos-1] != '\n') {
+               i_error("%s dump-capability: Couldn't read capability "
+                       "(got %u bytes)", pname, pos);
+               return NULL;
+       }
+       buf[pos-1] = '\0';
+
+       return i_strdup(buf);
+}
+
+static bool get_imap_capability(struct master_settings *set)
+{
+       static const char *generated_capability = NULL;
+
+       if (generated_capability != NULL) {
+               /* Reloading configuration. Don't try to execute the imap
+                  process again. Too risky and the wait() call below will
+                  break it anyway. Just use the previous capability list we
+                  already had generated. */
+               set->imap_generated_capability =
+                       p_strdup(settings_pool, generated_capability);
+               return TRUE;
+       }
+
+       generated_capability = get_process_capability(PROCESS_TYPE_IMAP, set);
+       if (generated_capability == NULL)
+               return FALSE;
+
+       set->imap_generated_capability =
+               p_strdup(settings_pool, generated_capability);
+       return TRUE;
+}
+#endif
 
-static void fix_base_path(struct settings *set, const char **str)
+static void fix_base_path(struct master_settings *set, const char **str)
 {
        if (*str != NULL && **str != '\0' && **str != '/') {
                *str = p_strconcat(settings_pool,
@@ -415,7 +453,7 @@ static bool parse_gid(const char *str, gid_t *gid_r)
        return TRUE;
 }
 
-static bool get_login_uid(struct settings *set)
+static bool get_login_uid(struct master_settings *set)
 {
        struct passwd *pw;
 
@@ -432,23 +470,23 @@ static bool get_login_uid(struct settings *set)
                        dec2str(pw->pw_gid));
                return FALSE;
        }
-
        set->login_uid = pw->pw_uid;
        return TRUE;
 }
 
-static bool auth_settings_verify(struct auth_settings *auth)
+static bool auth_settings_verify(struct master_settings *set,
+                                struct master_auth_settings *auth)
 {
        struct passwd *pw;
-       struct auth_socket_settings *s;
+       struct master_auth_socket_settings *const *sockets;
+       unsigned int i, count;
 
        if ((pw = getpwnam(auth->user)) == NULL) {
                i_error("Auth user doesn't exist: %s", auth->user);
                return FALSE;
        }
 
-       if (auth->parent->defaults->login_uid == pw->pw_uid &&
-           master_uid != pw->pw_uid) {
+       if (set->login_uid == pw->pw_uid && master_uid != pw->pw_uid) {
                i_error("login_user %s (uid %s) must not be same as auth_user",
                        auth->user, dec2str(pw->pw_uid));
                return FALSE;
@@ -462,74 +500,22 @@ static bool auth_settings_verify(struct auth_settings *auth)
                return FALSE;
        }
 
-       fix_base_path(auth->parent->defaults, &auth->chroot);
+       fix_base_path(set, &auth->chroot);
        if (*auth->chroot != '\0' && access(auth->chroot, X_OK) < 0) {
                i_error("Can't access auth chroot directory %s: %m",
                        auth->chroot);
                return FALSE;
        }
 
-       if (auth->ssl_require_client_cert || auth->ssl_username_from_cert) {
-               /* if we require valid cert, make sure we also ask for it */
-               if (auth->parent->pop3 != NULL)
-                       auth->parent->pop3->ssl_verify_client_cert = TRUE;
-               if (auth->parent->imap != NULL)
-                       auth->parent->imap->ssl_verify_client_cert = TRUE;
-       }
-
-       for (s = auth->sockets; s != NULL; s = s->next) {
-               if (auth->count > 1 && strcmp(s->type, "listen") == 0) {
+       sockets = array_get(&auth->sockets, &count);
+       for (i = 0; i < count; i++) {
+               if (auth->count > 1 &&
+                   strcmp(sockets[i]->type, "listen") == 0) {
                        i_error("Currently auth process count must be 1 if "
                                "you're using auth socket listeners.");
                        return FALSE;
                }
-               fix_base_path(auth->parent->defaults, &s->master.path);
-               fix_base_path(auth->parent->defaults, &s->client.path);
-       }
-       return TRUE;
-}
-
-static bool namespace_settings_verify(struct server_settings *server,
-                                     struct namespace_settings *ns)
-{
-       struct namespace_settings *n;
-       const char *name;
-
-       name = ns->prefix != NULL ? ns->prefix : "";
-
-       if (ns->separator != NULL &&
-           ns->separator[0] != '\0' && ns->separator[1] != '\0') {
-               i_error("Namespace '%s': "
-                       "Hierarchy separator must be only one character long",
-                       name);
-               return FALSE;
-       }
-       if (strcmp(ns->list, "yes") != 0 &&
-           strcmp(ns->list, "no") != 0 &&
-           strcmp(ns->list, "children") != 0) {
-               i_error("Namespace '%s': Invalid list value: %s",
-                       name, ns->list);
-               return FALSE;
-       }
-
-       if (ns->alias_for != NULL) {
-               for (n = server->namespaces; n != ns; n = n->next) {
-                       if (strcmp(n->prefix, ns->alias_for) == 0)
-                               break;
-               }
-               if (n == ns) {
-                       i_error("Namespace '%s': alias_for points to "
-                               "unknown namespace: %s", name, ns->alias_for);
-                       return FALSE;
-               }
-               if (n->alias_for != NULL) {
-                       i_error("Namespace '%s': alias_for chaining isn't "
-                               "allowed: %s -> %s", name, ns->alias_for,
-                               n->alias_for);
-                       return FALSE;
-               }
        }
-
        return TRUE;
 }
 
@@ -547,7 +533,7 @@ static const char *get_directory(const char *path)
        }
 }
 
-static bool settings_is_active(struct settings *set)
+static bool settings_is_active(struct master_settings *set)
 {
        if (*set->protocols == '\0') {
                /* we're probably using this with --exec-mail */
@@ -565,36 +551,35 @@ static bool settings_is_active(struct settings *set)
        return TRUE;
 }
 
-static bool settings_have_connect_sockets(struct settings *set)
+static bool settings_have_connect_sockets(struct master_settings *set)
 {
-       struct auth_settings *auth;
-       struct server_settings *server;
-
-       for (server = set->server; server != NULL; server = server->next) {
-               for (auth = server->auths; auth != NULL; auth = auth->next) {
-                       if (auth->sockets != NULL &&
-                           strcmp(auth->sockets->type, "connect") == 0)
-                               return TRUE;
-               }
+       struct master_auth_settings *const *auths;
+       struct master_auth_socket_settings *const *sockets;
+       unsigned int i, count, count2;
+
+       auths = array_get(&set->auths, &count);
+       for (i = 0; i < count; i++) {
+               sockets = array_get(&auths[i]->sockets, &count2);
+               if (count2 > 0 && strcmp(sockets[0]->type, "connect") == 0)
+                       return TRUE;
        }
 
        return FALSE;
 }
 
-static bool settings_have_nonplaintext_auths(struct settings *set)
+static bool settings_have_nonplaintext_auths(struct master_settings *set)
 {
-       struct auth_settings *auth;
-       struct server_settings *server;
+       struct master_auth_settings *const *auths;
        const char *const *tmp;
+       unsigned int i, count;
 
-       for (server = set->server; server != NULL; server = server->next) {
-               for (auth = server->auths; auth != NULL; auth = auth->next) {
-                       tmp = t_strsplit_spaces(auth->mechanisms, " ");
-                       for (; *tmp != NULL; tmp++) {
-                               if (strcasecmp(*tmp, "PLAIN") != 0 &&
-                                   strcasecmp(*tmp, "LOGIN") != 0)
-                                       return TRUE;
-                       }
+       auths = array_get(&set->auths, &count);
+       for (i = 0; i < count; i++) {
+               tmp = t_strsplit_spaces(auths[i]->mechanisms, " ");
+               for (; *tmp != NULL; tmp++) {
+                       if (strcasecmp(*tmp, "PLAIN") != 0 &&
+                           strcasecmp(*tmp, "LOGIN") != 0)
+                               return TRUE;
                }
        }
 
@@ -654,143 +639,29 @@ static void unlink_auth_sockets(const char *path, const char *prefix)
        (void)closedir(dirp);
 }
 
-#ifdef HAVE_MODULES
-static const char *
-get_process_capability(enum process_type ptype, struct settings *set)
+static bool settings_verify(struct master_settings *set)
 {
-       /* FIXME: pretty ugly code just for getting the capability
-          automatically */
-       static const char *args[] = {
-               "uid=65534",
-               "gid=65534",
-               "home=/tmp",
-               NULL
-       };
-       const char *pname = process_names[ptype];
-       enum master_login_status login_status;
-       struct mail_login_request request;
-       char buf[4096];
-       int fd[2], status;
-       ssize_t ret;
-       unsigned int pos;
-       uid_t uid;
-       pid_t pid;
+       const char *dir;
+       int facility;
 
-       uid = geteuid();
-       if (uid != 0) {
-               /* use the current user */
-               args[0] = t_strdup_printf("uid=%s", dec2str(uid));
-               args[1] = t_strdup_printf("gid=%s", dec2str(getegid()));
-       }
+       if (!get_login_uid(set))
+               return FALSE;
 
-       if (pipe(fd) < 0) {
-               i_error("pipe() failed: %m");
-               return NULL;
-       }
-       fd_close_on_exec(fd[0], TRUE);
-       fd_close_on_exec(fd[1], TRUE);
+       set->mail_uid_t = (uid_t)-1;
+       set->mail_gid_t = (gid_t)-1;
+       set->mail_priv_gid_t = (gid_t)-1;
 
-       memset(&request, 0, sizeof(request));
-       request.fd = fd[1];
-       login_status = create_mail_process(ptype, set, &request,
-                                          "dump-capability", args, NULL, TRUE,
-                                          &pid);
-       if (login_status != MASTER_LOGIN_STATUS_OK) {
-               (void)close(fd[0]);
-               (void)close(fd[1]);
-               return NULL;
+       if (*set->mail_uid != '\0') {
+               if (!parse_uid(set->mail_uid, &set->mail_uid_t)) {
+                       i_error("Non-existing mail_uid: %s", set->mail_uid);
+                       return FALSE;
+               }
        }
-       (void)close(fd[1]);
-
-       alarm(5);
-       if (wait(&status) == -1) {
-               i_fatal("%s dump-capability process %d got stuck",
-                       pname, (int)pid);
-       }
-       alarm(0);
-
-       if (status != 0) {
-               (void)close(fd[0]);
-               if (WIFSIGNALED(status)) {
-                       i_error("%s dump-capability process "
-                               "killed with signal %d",
-                               pname, WTERMSIG(status));
-               } else {
-                       i_error("%s dump-capability process returned %d",
-                               pname, WIFEXITED(status) ? WEXITSTATUS(status) :
-                               status);
-               }
-               return NULL;
-       }
-
-       pos = 0;
-       while ((ret = read(fd[0], buf + pos, sizeof(buf) - pos)) > 0)
-               pos += ret;
-
-       if (ret < 0) {
-               i_error("read(%s dump-capability process) failed: %m", pname);
-               (void)close(fd[0]);
-               return NULL;
-       }
-       (void)close(fd[0]);
-
-       if (pos == 0 || buf[pos-1] != '\n') {
-               i_error("%s dump-capability: Couldn't read capability "
-                       "(got %u bytes)", pname, pos);
-               return NULL;
-       }
-       buf[pos-1] = '\0';
-
-       return i_strdup(buf);
-}
-
-static bool get_imap_capability(struct settings *set)
-{
-       static const char *generated_capability = NULL;
-
-       if (generated_capability != NULL) {
-               /* Reloading configuration. Don't try to execute the imap
-                  process again. Too risky and the wait() call below will
-                  break it anyway. Just use the previous capability list we
-                  already had generated. */
-               set->imap_generated_capability =
-                       p_strdup(settings_pool, generated_capability);
-               return TRUE;
-       }
-
-       generated_capability = get_process_capability(PROCESS_TYPE_IMAP, set);
-       if (generated_capability == NULL)
-               return FALSE;
-
-       set->imap_generated_capability =
-               p_strdup(settings_pool, generated_capability);
-       return TRUE;
-}
-#endif
-
-static bool settings_verify(struct settings *set)
-{
-       const char *dir;
-       int facility;
-
-       if (!get_login_uid(set))
-               return FALSE;
-
-       set->mail_uid_t = (uid_t)-1;
-       set->mail_gid_t = (gid_t)-1;
-       set->mail_priv_gid_t = (gid_t)-1;
-
-       if (*set->mail_uid != '\0') {
-               if (!parse_uid(set->mail_uid, &set->mail_uid_t)) {
-                       i_error("Non-existing mail_uid: %s", set->mail_uid);
-                       return FALSE;
-               }
-       }
-       if (*set->mail_gid != '\0') {
-               if (!parse_gid(set->mail_gid, &set->mail_gid_t)) {
-                       i_error("Non-existing mail_gid: %s", set->mail_uid);
-                       return FALSE;
-               }
+       if (*set->mail_gid != '\0') {
+               if (!parse_gid(set->mail_gid, &set->mail_gid_t)) {
+                       i_error("Non-existing mail_gid: %s", set->mail_uid);
+                       return FALSE;
+               }
        }
        if (*set->mail_privileged_group != '\0') {
                if (!parse_gid(set->mail_privileged_group,
@@ -839,28 +710,10 @@ static bool settings_verify(struct settings *set)
                i_error("ssl setting: Invalid value: %s", set->ssl);
                return FALSE;
        }
-#ifdef HAVE_SSL
+#ifndef HAVE_SSL
        if (strcmp(set->ssl, "no") != 0) {
-               if (*set->ssl_ca_file != '\0' &&
-                   access(set->ssl_ca_file, R_OK) < 0) {
-                       i_fatal("ssl_ca_file: Can't use %s: %m",
-                               set->ssl_ca_file);
-               }
 
-               if (access(set->ssl_cert_file, R_OK) < 0) {
-                       i_error("ssl_cert_file: Can't use %s: %m",
-                               set->ssl_cert_file);
-                       return FALSE;
-               }
 
-               if (access(set->ssl_key_file, R_OK) < 0) {
-                       i_error("ssl_key_file: Can't use %s: %m",
-                               set->ssl_key_file);
-                       return FALSE;
-               }
-       }
-#else
-       if (strcmp(set->ssl, "no") != 0) {
                i_error("SSL support not compiled in but ssl=%s", set->ssl);
                return FALSE;
        }
@@ -906,11 +759,8 @@ static bool settings_verify(struct settings *set)
                i_error("login_processes_count must be at least 1");
                return FALSE;
        }
-       if (set->login_max_connections < 1) {
-               i_error("login_max_connections must be at least 1");
-               return FALSE;
-       }
 
+#if 0 //FIXME
        if (set->mail_nfs_index && !set->mmap_disable) {
                i_error("mail_nfs_index=yes requires mmap_disable=yes");
                return FALSE;
@@ -919,7 +769,6 @@ static bool settings_verify(struct settings *set)
                i_error("mail_nfs_index=yes requires fsync_disable=no");
                return FALSE;
        }
-
 #ifdef HAVE_MODULES
        if (*set->mail_plugins != '\0' &&
            access(set->mail_plugin_dir, R_OK | X_OK) < 0) {
@@ -933,11 +782,12 @@ static bool settings_verify(struct settings *set)
                        "can't load plugins: %s", set->mail_plugins);
                return FALSE;
        }
+#endif
 #endif
        return TRUE;
 }
 
-static bool settings_do_fixes(struct settings *set)
+static bool settings_do_fixes(struct master_settings *set)
 {
        struct stat st;
 
@@ -987,7 +837,8 @@ static bool settings_do_fixes(struct settings *set)
        return TRUE;
 }
 
-static bool settings_fix(struct settings *set, bool nochecks, bool nofixes)
+static bool
+settings_fix(struct master_settings *set, bool nochecks, bool nofixes)
 {
        /* fix relative paths */
        fix_base_path(set, &set->login_dir);
@@ -999,474 +850,8 @@ static bool settings_fix(struct settings *set, bool nochecks, bool nofixes)
        return nofixes ? TRUE : settings_do_fixes(set);
 }
 
-static void pid_file_check_running(const char *path)
-{
-       char buf[32];
-       int fd;
-       ssize_t ret;
-
-       fd = open(path, O_RDONLY);
-       if (fd == -1) {
-               if (errno == ENOENT)
-                       return;
-               i_fatal("open(%s) failed: %m", path);
-       }
-
-       ret = read(fd, buf, sizeof(buf));
-       if (ret <= 0) {
-               if (ret == 0)
-                       i_error("Empty PID file in %s, overriding", path);
-               else
-                       i_fatal("read(%s) failed: %m", path);
-       } else {
-               pid_t pid;
-
-               if (buf[ret-1] == '\n')
-                       ret--;
-               buf[ret] = '\0';
-               pid = atoi(buf);
-               if (pid == getpid() || (kill(pid, 0) < 0 && errno == ESRCH)) {
-                       /* doesn't exist */
-               } else {
-                       i_fatal("Dovecot is already running with PID %s "
-                               "(read from %s)", buf, path);
-               }
-       }
-       (void)close(fd);
-}
-
-static struct auth_settings *
-auth_settings_new(struct server_settings *server, const char *name)
-{
-       struct auth_settings *auth;
-
-       auth = p_new(settings_pool, struct auth_settings, 1);
-
-       /* copy defaults */
-       *auth = server->auth_defaults;
-       auth->parent = server;
-       auth->name = p_strdup(settings_pool, name);
-
-       auth->next = server->auths;
-       server->auths = auth;
-
-       return auth;
-}
-
-static struct auth_settings *
-parse_new_auth(struct server_settings *server, const char *name,
-              const char **errormsg)
-{
-       struct auth_settings *auth;
-
-       if (strchr(name, '/') != NULL) {
-               *errormsg = "Authentication process name must not contain '/'";
-               return NULL;
-       }
-
-       for (auth = server->auths; auth != NULL; auth = auth->next) {
-               if (strcmp(auth->name, name) == 0) {
-                       *errormsg = "Authentication process already exists "
-                               "with the same name";
-                       return NULL;
-               }
-       }
-
-       return auth_settings_new(server, name);
-}
-
-static struct auth_passdb_settings *
-auth_passdb_settings_new(struct auth_settings *auth, const char *type)
-{
-       struct auth_passdb_settings *as, **as_p;
-
-       as = p_new(settings_pool, struct auth_passdb_settings, 1);
-
-       as->parent = auth;
-       as->driver = str_lcase(p_strdup(settings_pool, type));
-
-       as_p = &auth->passdbs;
-       while (*as_p != NULL)
-               as_p = &(*as_p)->next;
-       *as_p = as;
-
-       return as;
-}
-
-static struct auth_userdb_settings *
-auth_userdb_settings_new(struct auth_settings *auth, const char *type)
-{
-       struct auth_userdb_settings *as, **as_p;
-
-       as = p_new(settings_pool, struct auth_userdb_settings, 1);
-
-       as->parent = auth;
-       as->driver = str_lcase(p_strdup(settings_pool, type));
-
-       as_p = &auth->userdbs;
-       while (*as_p != NULL)
-               as_p = &(*as_p)->next;
-       *as_p = as;
-
-       return as;
-}
-
-static struct auth_socket_settings *
-auth_socket_settings_new(struct auth_settings *auth, const char *type)
-{
-       struct auth_socket_settings *as, **as_p;
-
-       as = p_new(settings_pool, struct auth_socket_settings, 1);
-
-       as->parent = auth;
-       as->type = str_lcase(p_strdup(settings_pool, type));
-       as->master = default_socket_settings;
-       as->client = default_socket_settings;
-
-       as->master.path = DEFAULT_MASTER_SOCKET_PATH;
-       as->client.path = DEFAULT_CLIENT_SOCKET_PATH;
-
-       as_p = &auth->sockets;
-       while (*as_p != NULL)
-               as_p = &(*as_p)->next;
-       *as_p = as;
-
-       return as;
-}
-
-static struct auth_socket_settings *
-parse_new_auth_socket(struct auth_settings *auth, const char *name,
-                     const char **errormsg)
-{
-       if (strcmp(name, "connect") != 0 && strcmp(name, "listen") != 0) {
-               *errormsg = "Unknown auth socket type";
-               return NULL;
-       }
-
-       if (auth->sockets != NULL && strcmp(name, "connect") == 0) {
-               *errormsg = "With connect auth socket no other sockets "
-                       "can be used in same auth section";
-               return NULL;
-       }
-
-       return auth_socket_settings_new(auth, name);
-}
-
-static struct namespace_settings *
-namespace_settings_new(struct server_settings *server, const char *type)
-{
-       struct namespace_settings *ns, **ns_p;
-
-       ns = p_new(settings_pool, struct namespace_settings, 1);
-       *ns = default_namespace_settings;
-
-       ns->parent = server;
-       ns->type = str_lcase(p_strdup(settings_pool, type));
-
-       ns_p = &server->namespaces;
-       while (*ns_p != NULL)
-               ns_p = &(*ns_p)->next;
-       *ns_p = ns;
-
-       return ns;
-}
-
-static struct namespace_settings *
-parse_new_namespace(struct server_settings *server, const char *name,
-                   const char **errormsg)
-{
-       if (strcasecmp(name, "private") != 0 &&
-           strcasecmp(name, "shared") != 0 &&
-           strcasecmp(name, "public") != 0) {
-               *errormsg = "Unknown namespace type";
-               return NULL;
-       }
-
-       return namespace_settings_new(server, name);
-}
-
-static const char *parse_setting(const char *key, const char *value,
-                                struct settings_parse_ctx *ctx)
-{
-       const char *error;
-
-       switch (ctx->type) {
-       case SETTINGS_TYPE_ROOT:
-       case SETTINGS_TYPE_SERVER:
-               error = NULL;
-               if (ctx->protocol == MAIL_PROTOCOL_ANY ||
-                   ctx->protocol == MAIL_PROTOCOL_IMAP) {
-                       error = parse_setting_from_defs(settings_pool,
-                                                       setting_defs,
-                                                       ctx->server->imap,
-                                                       key, value);
-               }
-
-               if (error == NULL &&
-                   (ctx->protocol == MAIL_PROTOCOL_ANY ||
-                    ctx->protocol == MAIL_PROTOCOL_POP3)) {
-                       error = parse_setting_from_defs(settings_pool,
-                                                       setting_defs,
-                                                       ctx->server->pop3,
-                                                       key, value);
-               }
-
-               if (error == NULL)
-                       return NULL;
-
-               if (strncmp(key, "auth_", 5) == 0) {
-                       return parse_setting_from_defs(settings_pool,
-                                                      auth_setting_defs,
-                                                      ctx->auth,
-                                                      key + 5, value);
-               }
-               return error;
-       case SETTINGS_TYPE_AUTH:
-               if (strncmp(key, "auth_", 5) == 0)
-                       key += 5;
-               return parse_setting_from_defs(settings_pool, auth_setting_defs,
-                                              ctx->auth, key, value);
-       case SETTINGS_TYPE_AUTH_SOCKET:
-               return parse_setting_from_defs(settings_pool,
-                                              auth_socket_setting_defs,
-                                              ctx->auth_socket, key, value);
-       case SETTINGS_TYPE_AUTH_PASSDB:
-               return parse_setting_from_defs(settings_pool,
-                                              auth_passdb_setting_defs,
-                                              ctx->auth_passdb, key, value);
-       case SETTINGS_TYPE_AUTH_USERDB:
-               return parse_setting_from_defs(settings_pool,
-                                              auth_userdb_setting_defs,
-                                              ctx->auth_userdb, key, value);
-       case SETTINGS_TYPE_NAMESPACE:
-               return parse_setting_from_defs(settings_pool,
-                                              namespace_setting_defs,
-                                              ctx->namespace, key, value);
-       case SETTINGS_TYPE_SOCKET:
-               return parse_setting_from_defs(settings_pool,
-                                              socket_setting_defs,
-                                              ctx->socket, key, value);
-       case SETTINGS_TYPE_DICT:
-               key = p_strdup(settings_pool, key);
-               value = p_strdup(settings_pool, value);
-
-               array_append(&ctx->server->dicts, &key, 1);
-               array_append(&ctx->server->dicts, &value, 1);
-               return NULL;
-       case SETTINGS_TYPE_PLUGIN:
-               key = p_strdup(settings_pool, key);
-               value = p_strdup(settings_pool, value);
-
-               if (ctx->protocol == MAIL_PROTOCOL_ANY ||
-                   ctx->protocol == MAIL_PROTOCOL_IMAP) {
-                       array_append(&ctx->server->imap->plugin_envs, &key, 1);
-                       array_append(&ctx->server->imap->plugin_envs,
-                                    &value, 1);
-               }
-               if (ctx->protocol == MAIL_PROTOCOL_ANY ||
-                   ctx->protocol == MAIL_PROTOCOL_POP3) {
-                       array_append(&ctx->server->pop3->plugin_envs, &key, 1);
-                       array_append(&ctx->server->pop3->plugin_envs,
-                                    &value, 1);
-               }
-               return NULL;
-       }
-
-       i_unreached();
-}
-
-static struct server_settings *
-create_new_server(const char *name,
-                 struct settings *imap_defaults,
-                 struct settings *pop3_defaults)
-{
-       struct server_settings *server;
-
-       server = p_new(settings_pool, struct server_settings, 1);
-       server->name = p_strdup(settings_pool, name);
-       server->imap = p_new(settings_pool, struct settings, 1);
-       server->pop3 = p_new(settings_pool, struct settings, 1);
-       server->auth_defaults = default_auth_settings;
-
-       *server->imap = *imap_defaults;
-       *server->pop3 = *pop3_defaults;
-
-       p_array_init(&server->dicts, settings_pool, 4);
-       p_array_init(&server->imap->plugin_envs, settings_pool, 8);
-       p_array_init(&server->pop3->plugin_envs, settings_pool, 8);
-
-       server->imap->server = server;
-       server->imap->protocol = MAIL_PROTOCOL_IMAP;
-       server->imap->login_executable = PKG_LIBEXECDIR"/imap-login";
-       server->imap->mail_executable = PKG_LIBEXECDIR"/imap";
-       server->imap->mail_plugin_dir = MODULEDIR"/imap";
-
-       server->pop3->server = server;
-       server->pop3->protocol = MAIL_PROTOCOL_POP3;
-       server->pop3->login_executable = PKG_LIBEXECDIR"/pop3-login";
-       server->pop3->mail_executable = PKG_LIBEXECDIR"/pop3";
-       server->pop3->mail_plugin_dir = MODULEDIR"/pop3";
-
-       return server;
-}
-
-static bool parse_section(const char *type, const char *name,
-                         struct settings_parse_ctx *ctx, const char **errormsg)
-{
-       struct server_settings *server;
-
-       if (type == NULL) {
-               /* section closing */
-               if (ctx->level-- > 0) {
-                       ctx->type = ctx->parent_type;
-                       ctx->protocol = MAIL_PROTOCOL_ANY;
-
-                       switch (ctx->type) {
-                       case SETTINGS_TYPE_AUTH_SOCKET:
-                               ctx->parent_type = SETTINGS_TYPE_AUTH;
-                               break;
-                       default:
-                               ctx->parent_type = SETTINGS_TYPE_ROOT;
-                               break;
-                       }
-               } else {
-                       ctx->type = SETTINGS_TYPE_ROOT;
-                       ctx->server = ctx->root;
-                       ctx->auth = &ctx->root->auth_defaults;
-                       ctx->namespace = NULL;
-               }
-               return TRUE;
-       }
-
-       ctx->level++;
-       ctx->parent_type = ctx->type;
-
-       if (strcmp(type, "server") == 0) {
-               if (ctx->type != SETTINGS_TYPE_ROOT) {
-                       *errormsg = "Server section not allowed here";
-                       return FALSE;
-               }
-
-               ctx->type = SETTINGS_TYPE_SERVER;
-               ctx->server = create_new_server(name, ctx->server->imap,
-                                               ctx->server->pop3);
-                server = ctx->root;
-               while (server->next != NULL)
-                       server = server->next;
-               server->next = ctx->server;
-               return TRUE;
-       }
-
-       if (strcmp(type, "protocol") == 0) {
-               if ((ctx->type != SETTINGS_TYPE_ROOT &&
-                    ctx->type != SETTINGS_TYPE_SERVER) ||
-                   ctx->level != 1) {
-                       *errormsg = "Protocol section not allowed here";
-                       return FALSE;
-               }
-
-               if (strcmp(name, "imap") == 0)
-                       ctx->protocol = MAIL_PROTOCOL_IMAP;
-               else if (strcmp(name, "pop3") == 0)
-                       ctx->protocol = MAIL_PROTOCOL_POP3;
-               else if (strcmp(name, "lda") == 0)
-                       ctx->protocol = MAIL_PROTOCOL_LDA;
-               else {
-                       *errormsg = "Unknown protocol name";
-                       return FALSE;
-               }
-               return TRUE;
-       }
-
-       if (strcmp(type, "auth") == 0) {
-               if (ctx->type != SETTINGS_TYPE_ROOT &&
-                   ctx->type != SETTINGS_TYPE_SERVER) {
-                       *errormsg = "Auth section not allowed here";
-                       return FALSE;
-               }
-
-               ctx->type = SETTINGS_TYPE_AUTH;
-               ctx->auth = parse_new_auth(ctx->server, name, errormsg);
-               return ctx->auth != NULL;
-       }
-
-       if (ctx->type == SETTINGS_TYPE_AUTH &&
-           strcmp(type, "socket") == 0) {
-               ctx->type = SETTINGS_TYPE_AUTH_SOCKET;
-               ctx->auth_socket = parse_new_auth_socket(ctx->auth,
-                                                        name, errormsg);
-               return ctx->auth_socket != NULL;
-       }
-
-       if (ctx->type == SETTINGS_TYPE_AUTH && strcmp(type, "passdb") == 0) {
-               ctx->type = SETTINGS_TYPE_AUTH_PASSDB;
-               ctx->auth_passdb = auth_passdb_settings_new(ctx->auth, name);
-               return TRUE;
-       }
-
-       if (ctx->type == SETTINGS_TYPE_AUTH && strcmp(type, "userdb") == 0) {
-               ctx->type = SETTINGS_TYPE_AUTH_USERDB;
-               ctx->auth_userdb = auth_userdb_settings_new(ctx->auth, name);
-               return TRUE;
-       }
-
-       if (ctx->type == SETTINGS_TYPE_AUTH_SOCKET) {
-               ctx->type = SETTINGS_TYPE_SOCKET;
-
-               if (strcmp(type, "master") == 0) {
-                       ctx->socket = &ctx->auth_socket->master;
-                       ctx->socket->used = TRUE;
-                       return TRUE;
-               }
-
-               if (strcmp(type, "client") == 0) {
-                       ctx->socket = &ctx->auth_socket->client;
-                       ctx->socket->used = TRUE;
-                       return TRUE;
-               }
-       }
-
-       if (strcmp(type, "namespace") == 0) {
-               if (ctx->type != SETTINGS_TYPE_ROOT &&
-                   ctx->type != SETTINGS_TYPE_SERVER) {
-                       *errormsg = "Namespace section not allowed here";
-                       return FALSE;
-               }
-
-               ctx->type = SETTINGS_TYPE_NAMESPACE;
-               ctx->namespace = parse_new_namespace(ctx->server, name,
-                                                    errormsg);
-               return ctx->namespace != NULL;
-       }
-
-       if (strcmp(type, "dict") == 0) {
-               if (ctx->type != SETTINGS_TYPE_ROOT &&
-                   ctx->type != SETTINGS_TYPE_SERVER) {
-                       *errormsg = "Plugin section not allowed here";
-                       return FALSE;
-               }
-
-               ctx->type = SETTINGS_TYPE_DICT;
-               return TRUE;
-       }
-
-       if (strcmp(type, "plugin") == 0) {
-               if (ctx->type != SETTINGS_TYPE_ROOT &&
-                   ctx->type != SETTINGS_TYPE_SERVER) {
-                       *errormsg = "Plugin section not allowed here";
-                       return FALSE;
-               }
-
-               ctx->type = SETTINGS_TYPE_PLUGIN;
-               return TRUE;
-       }
-
-       *errormsg = "Unknown section type";
-       return FALSE;
-}
-
 static void
-settings_warn_needed_fds(struct server_settings *server ATTR_UNUSED)
+settings_warn_needed_fds(struct master_server_settings *server ATTR_UNUSED)
 {
 #ifdef HAVE_SETRLIMIT
        struct rlimit rlim;
@@ -1477,341 +862,169 @@ settings_warn_needed_fds(struct server_settings *server ATTR_UNUSED)
 
        /* count only log pipes needed for login and mail processes. we need
           more, but they're the ones that can use up most of the fds */
-       for (; server != NULL; server = server->next) {
-               if (server->imap != NULL)
-                       fd_count += server->imap->login_max_processes_count;
-               if (server->pop3 != NULL)
-                       fd_count += server->pop3->login_max_processes_count;
-               fd_count += server->defaults->max_mail_processes;
-       }
+       if (server->imap != NULL)
+               fd_count += server->imap->login_max_processes_count;
+       if (server->pop3 != NULL)
+               fd_count += server->pop3->login_max_processes_count;
+       fd_count += server->defaults->max_mail_processes;
 
        if (rlim.rlim_cur < fd_count) {
                i_warning("fd limit %d is lower than what Dovecot can use under "
                          "full load (more than %u). Either grow the limit or "
                          "change login_max_processes_count and "
-                         "max_mail_processes settings",
+                         "max_mail_processes master_settings",
                          (int)rlim.rlim_cur, fd_count);
        }
 #endif
 }
 
-bool master_settings_read(const char *path, bool nochecks, bool nofixes)
+static void
+config_split_all_settings(struct master_settings *set, const char *input)
 {
-       struct settings_parse_ctx ctx;
-       struct server_settings *server, *prev;
-       struct auth_settings *auth;
-       struct namespace_settings *ns;
-       pool_t temp;
+       const char *p, *line;
+       string_t *str;
 
-       memset(&ctx, 0, sizeof(ctx));
+       str = t_str_new(256);
+       p_array_init(&set->all_settings, settings_pool, 256);
+       for (p = input; *p != '\n'; p++) {
+               str_truncate(str, 0);
+               for (; *p != '='; p++) {
+                       i_assert(*p != '\n' && *p != '\0');
+                       str_append_c(str, i_toupper(*p));
+               }
+               for (; *p != '\n'; p++) {
+                       i_assert(*p != '\0');
+                       str_append_c(str, *p);
+               }
+               line = p_strdup(settings_pool, str_c(str));
+               array_append(&set->all_settings, &line, 1);
+       }
+}
 
-       p_clear(settings_pool);
+static int config_exec(const char *path, const char *service,
+                      struct master_settings **set_r)
+{
+       struct setting_parser_context *parser;
+       string_t *all_settings;
+       int ret;
+
+       all_settings = str_new(default_pool, 10240);
+       parser = settings_parser_init(settings_pool,
+                                     &master_setting_parser_info,
+                                     SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
+       settings_parse_save_input(parser, all_settings);
+       if ((ret = settings_parse_exec(parser, DOVECOT_CONFIG_BIN_PATH,
+                                      path, service)) == 0) {
+               *set_r = settings_parser_get(parser);
+               config_split_all_settings(*set_r, str_c(all_settings));
+       }
+       settings_parser_deinit(&parser);
+       str_free(&all_settings);
+       return ret;
+}
 
-       ctx.type = SETTINGS_TYPE_ROOT;
-       ctx.protocol = MAIL_PROTOCOL_ANY;
-       ctx.server = ctx.root =
-               create_new_server("default",
-                                 &default_settings, &default_settings);
-       ctx.auth = &ctx.server->auth_defaults;
+int master_settings_read(const char *path,
+                        struct master_server_settings **set_r)
+{
+       struct master_server_settings *set;
 
-       if (!settings_read(path, NULL, parse_setting, parse_section, &ctx))
-               return FALSE;
+       p_clear(settings_pool);
+       set = p_new(settings_pool, struct master_server_settings, 1);
+
+       master_default_settings.mail_executable = NULL;
+       master_default_settings.login_executable = NULL;
+       if (config_exec(path, "", &set->defaults) < 0)
+               return -1;
+       set->defaults->protocol = MAIL_PROTOCOL_ANY;
+       set->defaults->server = set;
+
+       master_default_settings.mail_executable = PKG_LIBEXECDIR"/imap";
+       master_default_settings.login_executable = PKG_LIBEXECDIR"/imap-login";
+       if (config_exec(path, "imap", &set->imap) < 0)
+               return -1;
+       set->imap->protocol = MAIL_PROTOCOL_IMAP;
+       set->imap->server = set;
+
+       master_default_settings.mail_executable = PKG_LIBEXECDIR"/pop3";
+       master_default_settings.login_executable = PKG_LIBEXECDIR"/pop3-login";
+       if (config_exec(path, "pop3", &set->pop3) < 0)
+               return -1;
+       set->pop3->protocol = MAIL_PROTOCOL_POP3;
+       set->pop3->server = set;
+
+       *set_r = set;
+       return 0;
+}
 
-       if (ctx.level != 0) {
-               i_error("Missing '}'");
+bool master_settings_check(struct master_server_settings *set,
+                          bool nochecks, bool nofixes)
+{
+       struct master_auth_settings *const *auths;
+       unsigned int i, count;
+       pool_t temp;
+
+       if ((*set->imap->protocols == '\0' ||
+            *set->pop3->protocols == '\0') && !nochecks) {
+               i_error("protocols: No protocols given in configuration file");
                return FALSE;
        }
-
-       /* If server sections were defined, skip the root */
-       if (ctx.root->next != NULL)
-               ctx.root = ctx.root->next;
-
-       if (!nochecks && !nofixes) {
-               ctx.root->defaults = settings_is_active(ctx.root->imap) ?
-                       ctx.root->imap : ctx.root->pop3;
-
-               path = t_strconcat(ctx.root->defaults->base_dir,
-                                  "/master.pid", NULL);
-               pid_file_check_running(path);
+       /* --exec-mail is used if nochecks=TRUE. Allow it regardless
+          of what's in protocols setting. */
+       if (!settings_is_active(set->imap) && !nochecks) {
+               if (strcmp(set->imap->protocols, "none") == 0) {
+                       set->imap->protocol = MAIL_PROTOCOL_ANY;
+                       if (!settings_fix(set->imap, nochecks, nofixes))
+                               return FALSE;
+               }
+               set->imap = NULL;
+       } else {
+               if (!settings_fix(set->imap, nochecks, nofixes))
+                       return FALSE;
        }
 
-       prev = NULL;
-       for (server = ctx.root; server != NULL; server = server->next) {
-               if ((*server->imap->protocols == '\0' ||
-                    *server->pop3->protocols == '\0') && !nochecks) {
-                       i_error("protocols: No protocols given "
-                               "in configuration file");
+       if (!settings_is_active(set->pop3) && !nochecks)
+               set->pop3 = NULL;
+       else {
+               if (!settings_fix(set->pop3, nochecks, nofixes))
                        return FALSE;
-               }
-               /* --exec-mail is used if nochecks=TRUE. Allow it regardless
-                  of what's in protocols setting. */
-               if (!settings_is_active(server->imap) && !nochecks) {
-                       if (strcmp(server->imap->protocols, "none") == 0) {
-                               server->imap->protocol = MAIL_PROTOCOL_ANY;
-                               if (!settings_fix(server->imap, nochecks,
-                                                 nofixes))
-                                       return FALSE;
-                               server->defaults = server->imap;
-                       }
-                       server->imap = NULL;
-               } else {
-                       if (!settings_fix(server->imap, nochecks, nofixes))
-                               return FALSE;
-                       server->defaults = server->imap;
-               }
+       }
 
-               if (!settings_is_active(server->pop3) && !nochecks)
-                       server->pop3 = NULL;
-               else {
-                       if (!settings_fix(server->pop3, nochecks, nofixes))
-                               return FALSE;
-                       if (server->defaults == NULL)
-                               server->defaults = server->pop3;
+       if (!settings_fix(set->defaults, nochecks, nofixes))
+               return FALSE;
+
+       if (!nochecks) {
+               auths = array_get(&set->defaults->auths, &count);
+               if (count == 0) {
+                       i_error("Missing auth section");
+                       return FALSE;
                }
 
-               if (server->defaults == NULL) {
-                       if (prev == NULL)
-                               ctx.root = server->next;
-                       else
-                               prev->next = server->next;
-               } else {
-                       auth = server->auths;
-                       if (auth == NULL) {
-                               i_error("Missing auth section for server %s",
-                                       server->name);
+               for (i = 0; i < count; i++) {
+                       if (!auth_settings_verify(set->defaults, auths[i]))
                                return FALSE;
-                       }
-
-                       if (!nochecks) {
-                               for (; auth != NULL; auth = auth->next) {
-                                       if (!auth_settings_verify(auth))
-                                               return FALSE;
-                               }
-                               ns = server->namespaces;
-                               for (; ns != NULL; ns = ns->next) {
-                                       if (!namespace_settings_verify(server, ns))
-                                               return FALSE;
-                               }
-                       }
-                       prev = server;
                }
        }
 
-       if (ctx.root == NULL) {
-               /* We aren't actually checking them separately, but if it
-                  contains only invalid protocols we'll get here.. */
-               i_error("Invalid protocols given in configuration file");
-               return FALSE;
-       }
-
        if (!nochecks)
-               settings_warn_needed_fds(ctx.root);
+               settings_warn_needed_fds(set);
 
        /* settings ok, swap them */
        temp = settings_pool;
        settings_pool = settings2_pool;
        settings2_pool = temp;
 
-       settings_root = ctx.root;
+       master_set = set;
        return TRUE;
 }
 
-static void settings_dump(const struct setting_def *def, const void **sets,
-                         const char **set_names, unsigned int count,
-                         bool nondefaults, unsigned int indent)
+void master_settings_export_to_env(const struct master_settings *set)
 {
-       const char **str;
-       unsigned int i;
-
-       str = t_new(const char *, count);
-       for (; def->name != NULL; def++) {
-               bool same = TRUE;
-
-               switch (def->type) {
-               case SET_STR: {
-                       const char *const *strp;
-
-                       for (i = 0; i < count; i++) {
-                               strp = CONST_PTR_OFFSET(sets[i], def->offset);
-                               str[i] = *strp != NULL ? *strp : "";
-                       }
-                       break;
-               }
-               case SET_INT: {
-                       const unsigned int *n;
-
-                       for (i = 0; i < count; i++) {
-                               n = CONST_PTR_OFFSET(sets[i], def->offset);
-                               str[i] = dec2str(*n);
-                       }
-                       break;
-               }
-               case SET_BOOL: {
-                       const bool *b;
-
-                       for (i = 0; i < count; i++) {
-                               b = CONST_PTR_OFFSET(sets[i], def->offset);
-                               str[i] = *b ? "yes" : "no";
-                       }
-                       break;
-               }
-               }
-
-               for (i = 2; i < count; i++) {
-                       if (strcmp(str[i], str[i-1]) != 0)
-                               same = FALSE;
-               }
-               if (same) {
-                       if (!nondefaults || strcmp(str[0], str[1]) != 0) {
-                               for (i = 0; i < indent; i++)
-                                       putc(' ', stdout);
-                               printf("%s: %s\n", def->name, str[1]);
-                       }
-               } else {
-                       for (i = 0; i < indent; i++)
-                               putc(' ', stdout);
-                       for (i = 1; i < count; i++) {
-                               printf("%s(%s): %s\n", def->name,
-                                      set_names[i], str[i]);
-                       }
-               }
-       }
-}
-
-static void
-namespace_settings_dump(struct namespace_settings *ns, bool nondefaults)
-{
-       const void *sets[2];
-
-       sets[0] = t_malloc0(sizeof(struct namespace_settings));
-       for (; ns != NULL; ns = ns->next) {
-               printf("namespace:\n");
-               sets[1] = ns;
-               settings_dump(namespace_setting_defs, sets, NULL, 2,
-                             nondefaults, 2);
-       }
-}
-
-static void auth_settings_dump(struct auth_settings *auth, bool nondefaults)
-{
-       const struct auth_passdb_settings *passdb;
-       const struct auth_userdb_settings *userdb;
-       const struct auth_socket_settings *socket_set;
-       const void *sets[2], *sets2[2];
-       const void *empty_defaults;
-
-       empty_defaults = t_malloc0(sizeof(struct auth_passdb_settings) +
-                                  sizeof(struct auth_userdb_settings) +
-                                  sizeof(struct auth_socket_settings));
-
-       sets[0] = &default_auth_settings;
-       sets2[0] = empty_defaults;
-
-       for (; auth != NULL; auth = auth->next) {
-               printf("auth %s:\n", auth->name);
-               sets[1] = auth;
-               settings_dump(auth_setting_defs, sets, NULL, 2, nondefaults, 2);
-
-               passdb = auth->passdbs;
-               for (; passdb != NULL; passdb = passdb->next) {
-                       printf("  passdb:\n");
-                       sets2[1] = passdb;
-                       settings_dump(auth_passdb_setting_defs, sets2, NULL, 2,
-                                     nondefaults, 4);
-               }
-
-               userdb = auth->userdbs;
-               for (; userdb != NULL; userdb = userdb->next) {
-                       printf("  userdb:\n");
-                       sets2[1] = userdb;
-                       settings_dump(auth_userdb_setting_defs, sets2, NULL, 2,
-                                     nondefaults, 4);
-               }
-
-               socket_set = auth->sockets;
-               for (; socket_set != NULL; socket_set = socket_set->next) {
-                       printf("  socket:\n");
-                       sets2[1] = socket_set;
-                       settings_dump(auth_socket_setting_defs, sets2, NULL, 2,
-                                     nondefaults, 4);
-
-                       if (socket_set->client.used) {
-                               printf("    client:\n");
-                               sets2[1] = &socket_set->client;
-                               settings_dump(socket_setting_defs, sets2, NULL,
-                                             2, nondefaults, 6);
-                       }
-
-                       if (socket_set->master.used) {
-                               printf("    master:\n");
-                               sets2[1] = &socket_set->master;
-                               settings_dump(socket_setting_defs, sets2, NULL,
-                                             2, nondefaults, 6);
-                       }
-               }
-       }
-}
-
-static void plugin_settings_dump(const struct settings *set)
-{
-       const char *const *envs;
+       const char *const *sets;
        unsigned int i, count;
 
-       envs = array_get(&set->plugin_envs, &count);
-       i_assert((count % 2) == 0);
-
-       if (count == 0)
-               return;
-
-       printf("plugin:\n");
-       for (i = 0; i < count; i += 2)
-               printf("  %s: %s\n", envs[i], envs[i+1]);
-}
-
-static void dict_settings_dump(const struct server_settings *set)
-{
-       const char *const *dicts;
-       unsigned int i, count;
-
-       dicts = array_get(&set->dicts, &count);
-       i_assert((count % 2) == 0);
-
-       if (count == 0)
-               return;
-
-       printf("dict:\n");
-       for (i = 0; i < count; i += 2)
-               printf("  %s: %s\n", dicts[i], dicts[i+1]);
-}
-
-void master_settings_dump(struct server_settings *set, bool nondefaults)
-{
-       const void *sets[4];
-       const char *set_names[4];
-       unsigned int count;
-
-       sets[0] = &default_settings;
-       sets[1] = set->defaults;
-
-       set_names[0] = NULL;
-       set_names[1] = "default";
-
-       count = 2;
-       if (set->imap != NULL) {
-               sets[count] = set->imap;
-               set_names[count] = "imap";
-               count++;
-       }
-       if (set->pop3 != NULL) {
-               sets[count] = set->pop3;
-               set_names[count] = "pop3";
-               count++;
-       }
-       settings_dump(setting_defs, sets, set_names, count, nondefaults, 0);
-       namespace_settings_dump(set->namespaces, nondefaults);
-       auth_settings_dump(set->auths, nondefaults);
-       plugin_settings_dump(set->defaults);
-       dict_settings_dump(set);
+       sets = array_get(&set->all_settings, &count);
+       for (i = 0; i < count; i++)
+               env_put(sets[i]);
 }
 
 void master_settings_init(void)
index 9ffb981b1bee90e46cf520cb3f9991a4fdaa8a9b..3b168dcf0c4ccf57ba35f12ba2a1cbbf8189feb1 100644 (file)
@@ -3,6 +3,8 @@
 
 #include "network.h"
 
+#define DOVECOT_CONFIG_BIN_PATH BINDIR"/doveconf"
+
 enum mail_protocol {
         MAIL_PROTOCOL_ANY,
         MAIL_PROTOCOL_IMAP,
@@ -18,10 +20,36 @@ struct listener {
 };
 ARRAY_DEFINE_TYPE(listener, struct listener);
 
-struct settings {
-       struct server_settings *server;
-       enum mail_protocol protocol;
+struct master_auth_socket_unix_settings {
+       const char *path;
+};
+
+struct master_auth_socket_settings {
+       const char *type;
+
+       ARRAY_DEFINE(masters, struct master_auth_socket_unix_settings *);
+};
+
+struct master_auth_settings {
+       const char *name;
+       const char *executable;
+       const char *user;
+       const char *chroot;
+
+       unsigned int count;
+       unsigned int process_size;
+
+       const char *mechanisms;
+       bool debug;
+
+       ARRAY_DEFINE(sockets, struct master_auth_socket_settings *);
+
+       /* .. */
+       uid_t uid;
+       gid_t gid;
+};
 
+struct master_settings {
        /* common */
        const char *base_dir;
        const char *log_path;
@@ -35,17 +63,8 @@ struct settings {
        const char *ssl_listen;
 
        const char *ssl;
-       const char *ssl_ca_file;
-       const char *ssl_cert_file;
        const char *ssl_key_file;
-       const char *ssl_key_password;
        unsigned int ssl_parameters_regenerate;
-       const char *ssl_cipher_list;
-       const char *ssl_cert_username_field;
-       bool ssl_verify_client_cert;
-       bool disable_plaintext_auth;
-       bool verbose_ssl;
-       bool shutdown_clients;
        bool nfs_check;
        bool version_ignore;
 
@@ -53,18 +72,14 @@ struct settings {
        const char *login_dir;
        const char *login_executable;
        const char *login_user;
-       const char *login_greeting;
-       const char *login_log_format_elements;
-       const char *login_log_format;
 
        bool login_process_per_connection;
        bool login_chroot;
-       const char *login_trusted_networks;
+       bool disable_plaintext_auth;
 
        unsigned int login_process_size;
        unsigned int login_processes_count;
        unsigned int login_max_processes_count;
-       unsigned int login_max_connections;
 
        /* mail */
        const char *valid_chroot_dirs;
@@ -80,68 +95,34 @@ struct settings {
        const char *mail_uid;
        const char *mail_gid;
 
+       const char *mail_plugins;
+       const char *imap_capability;
+
        const char *mail_location;
-       const char *mail_cache_fields;
-       const char *mail_never_cache_fields;
-       unsigned int mail_cache_min_mail_count;
-       unsigned int mailbox_idle_check_interval;
        bool mail_debug;
-       bool mail_full_filesystem_access;
-       unsigned int mail_max_keyword_length;
-       bool mail_save_crlf;
-       bool mmap_disable;
-       bool dotlock_use_excl;
-       bool fsync_disable;
-       bool mail_nfs_storage;
        bool mail_nfs_index;
-       bool mailbox_list_index_disable;
-       const char *lock_method;
-       bool maildir_stat_dirs;
-       bool maildir_copy_with_hardlinks;
-       bool maildir_copy_preserve_filename;
-       const char *mbox_read_locks;
-       const char *mbox_write_locks;
-       unsigned int mbox_lock_timeout;
-       unsigned int mbox_dotlock_change_timeout;
-       unsigned int mbox_min_index_size;
-       bool mbox_dirty_syncs;
-       bool mbox_very_dirty_syncs;
-       bool mbox_lazy_writes;
-       unsigned int dbox_rotate_size;
-       unsigned int dbox_rotate_min_size;
-       unsigned int dbox_rotate_days;
        unsigned int umask;
        bool mail_drop_priv_before_exec;
 
        const char *mail_executable;
        unsigned int mail_process_size;
-       const char *mail_plugins;
-       const char *mail_plugin_dir;
        const char *mail_log_prefix;
        unsigned int mail_log_max_lines_per_sec;
 
-       /* imap */
-       unsigned int imap_max_line_length;
-       const char *imap_capability;
-       const char *imap_client_workarounds;
-       const char *imap_logout_format;
-       const char *imap_id_send;
-       const char *imap_id_log;
-
-       /* pop3 */
-       bool pop3_no_flag_updates;
-       bool pop3_enable_last;
-       bool pop3_reuse_xuidl;
-       bool pop3_lock_session;
-       const char *pop3_uidl_format;
-       const char *pop3_client_workarounds;
-       const char *pop3_logout_format;
-
        /* dict */
        const char *dict_db_config;
        unsigned int dict_process_count;
 
+       ARRAY_DEFINE(auths, struct master_auth_settings *);
+
+       ARRAY_DEFINE(dicts, const char *);
+       ARRAY_DEFINE(plugin_envs, const char *);
+
+#ifndef CONFIG_BINARY
        /* .. */
+       struct master_server_settings *server;
+       enum mail_protocol protocol;
+
        ARRAY_TYPE(listener) listens;
        ARRAY_TYPE(listener) ssl_listens;
 
@@ -149,125 +130,26 @@ struct settings {
        gid_t mail_gid_t, mail_priv_gid_t;
 
        const char *imap_generated_capability;
-
-       ARRAY_DEFINE(plugin_envs, const char *);
-};
-
-struct socket_settings {
-       const char *path;
-       unsigned int mode;
-       const char *user;
-       const char *group;
-
-       unsigned int used:1;
-};
-
-struct auth_socket_settings {
-       struct auth_settings *parent;
-       struct auth_socket_settings *next;
-
-       const char *type;
-       struct socket_settings master;
-        struct socket_settings client;
-};
-
-struct auth_passdb_settings {
-       struct auth_settings *parent;
-       struct auth_passdb_settings *next;
-
-       const char *driver;
-       const char *args;
-       bool deny;
-       bool pass;
-       bool master;
-};
-
-struct auth_userdb_settings {
-       struct auth_settings *parent;
-       struct auth_userdb_settings *next;
-
-       const char *driver;
-       const char *args;
-};
-
-struct auth_settings {
-       struct server_settings *parent;
-       struct auth_settings *next;
-
-       const char *name;
-       const char *mechanisms;
-       const char *realms;
-       const char *default_realm;
-       unsigned int cache_size;
-       unsigned int cache_ttl;
-       unsigned int cache_negative_ttl;
-       const char *executable;
-       const char *user;
-       const char *chroot;
-       const char *username_chars;
-       const char *username_translation;
-       const char *username_format;
-       const char *master_user_separator;
-       const char *anonymous_username;
-       const char *krb5_keytab;
-       const char *gssapi_hostname;
-       const char *winbind_helper_path;
-       unsigned int failure_delay;
-
-       bool verbose, debug, debug_passwords;
-       bool ssl_require_client_cert;
-       bool ssl_username_from_cert;
-       bool use_winbind;
-
-       unsigned int count;
-       unsigned int worker_max_count;
-       unsigned int process_size;
-
-       /* .. */
-       uid_t uid;
-       gid_t gid;
-        struct auth_passdb_settings *passdbs;
-        struct auth_userdb_settings *userdbs;
-       struct auth_socket_settings *sockets;
-};
-
-struct namespace_settings {
-       struct server_settings *parent;
-       struct namespace_settings *next;
-
-       const char *type;
-       const char *separator;
-       const char *prefix;
-       const char *location;
-       const char *alias_for;
-
-       bool inbox;
-       bool hidden;
-       const char *list;
-       bool subscriptions;
+       ARRAY_TYPE(const_string) all_settings;
+#endif
 };
 
-struct server_settings {
-       struct server_settings *next;
-
-       const char *name;
-       struct settings *defaults;
-       struct settings *imap;
-       struct settings *pop3;
-       struct auth_settings *auths;
-       struct auth_settings auth_defaults;
-        struct namespace_settings *namespaces;
-
-       ARRAY_DEFINE(dicts, const char *);
+struct master_server_settings {
+       struct master_settings *defaults;
+       struct master_settings *imap;
+       struct master_settings *pop3;
 
        gid_t login_gid;
 };
 
-extern struct server_settings *settings_root;
-
-bool master_settings_read(const char *path, bool nochecks, bool nofixes);
+extern struct master_server_settings *master_set;
+extern struct setting_parser_info master_setting_parser_info;
 
-void master_settings_dump(struct server_settings *set, bool nondefaults);
+int master_settings_read(const char *path,
+                        struct master_server_settings **set_r);
+bool master_settings_check(struct master_server_settings *set,
+                          bool nochecks, bool nofixes);
+void master_settings_export_to_env(const struct master_settings *set);
 
 void master_settings_init(void);
 void master_settings_deinit(void);
index 53e8eed293aa699cbf9b5720293cc082cb68b69e..bfb1ba43b304b98f601d70f610a862c68629a0dd 100644 (file)
@@ -60,7 +60,7 @@ static void start_generate_process(const char *fname)
        if (dup2(log_fd, 2) < 0)
                i_fatal("dup2(stderr) failed: %m");
 
-       child_process_init_env();
+       child_process_init_env(master_set->defaults);
        client_process_exec(t_strconcat(binpath, " "SSL_PARAMETERS_PERM_PATH,
                                        NULL), "");
        i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", binpath);
@@ -80,7 +80,7 @@ ssl_parameter_process_destroyed(struct child_process *process ATTR_UNUSED,
        i_free_and_null(generating_path);
 }
 
-static bool check_parameters_file_set(struct settings *set)
+static bool check_parameters_file_set(struct master_settings *set)
 {
        const char *path;
        struct stat st, st2;
@@ -141,16 +141,10 @@ static bool check_parameters_file_set(struct settings *set)
 
 void ssl_check_parameters_file(void)
 {
-       struct server_settings *server;
-
        if (generating_path != NULL)
                return;
 
-       for (server = settings_root; server != NULL; server = server->next) {
-               if (server->defaults != NULL &&
-                   !check_parameters_file_set(server->defaults))
-                       break;
-       }
+       (void)check_parameters_file_set(master_set->defaults);
 }
 
 static void check_parameters_file_timeout(void *context ATTR_UNUSED)
index 80b53bdd543a84cc4ce856c0ca246a7d264bff72..f7c9f0585ffb7c5121b0cbff612ad5e21ab94e7c 100644 (file)
@@ -533,7 +533,7 @@ static void acl_mailbox_list_init_default(struct mailbox_list *list)
                i_fatal("ACL backend initialization failed");
 
        flags = mailbox_list_get_flags(list);
-       if ((flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0) {
+       if (list->mail_set->mail_full_filesystem_access) {
                /* not necessarily, but safer to do this for now. */
                i_fatal("mail_full_filesystem_access=yes is "
                        "incompatible with ACLs");
index e5111228df421f55094121dfe1bd3fe0261d0192..2fb578efa50147e6f7385fc5c350c655807bb1aa 100644 (file)
@@ -52,7 +52,7 @@ static struct fts_backend *fts_backend_lucene_init(struct mailbox *box)
                                                          "INBOX");
                if (path == NULL) {
                        /* in-memory indexes */
-                       if ((box->storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0)
+                       if (box->storage->set->mail_debug)
                                i_info("fts squat: Disabled with in-memory indexes");
                        return NULL;
                }
index af9b513b38b08b29032f69720b44adf70ef8e7f9..c2a3d049483b1a4589522c66db1b4d6b323fbea6 100644 (file)
@@ -61,18 +61,17 @@ static struct fts_backend *fts_backend_squat_init(struct mailbox *box)
                                                  mailbox_get_name(box));
        if (*path == '\0') {
                /* in-memory indexes */
-               if ((storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0)
+               if (storage->set->mail_debug)
                        i_info("fts squat: Disabled with in-memory indexes");
                return NULL;
        }
 
        mailbox_get_status(box, STATUS_UIDVALIDITY, &status);
-       if ((storage->flags & (MAIL_STORAGE_FLAG_MMAP_DISABLE |
-                              MAIL_STORAGE_FLAG_MMAP_NO_WRITE)) != 0)
+       if (storage->set->mmap_disable || storage->set->mmap_no_write)
                flags |= SQUAT_INDEX_FLAG_MMAP_DISABLE;
-       if ((storage->flags & MAIL_STORAGE_FLAG_NFS_FLUSH_INDEX) != 0)
+       if (storage->set->mail_nfs_index)
                flags |= SQUAT_INDEX_FLAG_NFS_FLUSH;
-       if ((storage->flags & MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0)
+       if (storage->set->dotlock_use_excl)
                flags |= SQUAT_INDEX_FLAG_DOTLOCK_USE_EXCL;
 
        backend = i_new(struct squat_fts_backend, 1);
index 9dad700cb225ee9fb0f585baf5a37775a9e344a2..87176101a5ce0202c6310bdeef257b3d5f7dd1e2 100644 (file)
@@ -912,7 +912,7 @@ static void fts_box_backends_init(struct mailbox *box)
                        fbox->backend_fast = backend;
                }
        }
-       if ((box->storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0 &&
+       if (box->storage->set->mail_debug &&
            fbox->backend_substr == NULL && fbox->backend_fast == NULL)
                i_info("fts: No backends enabled by the fts setting");
 }
index 73ac5c2d4ffd88c8bc95e82e375721f9252a6d0f..550d8f0ddaf2202399ac1df3f146b34decfb2710 100644 (file)
@@ -48,6 +48,7 @@ static const struct imap_acl_letter_map imap_acl_letter_map[] = {
 
 const char *imap_acl_plugin_version = PACKAGE_VERSION;
 
+static void (*next_hook_client_created)(struct client **client);
 static bool acl_anyone_allow = FALSE;
 
 static struct mailbox *
@@ -465,6 +466,14 @@ static bool cmd_deleteacl(struct client_command_context *cmd)
        return TRUE;
 }
 
+static void imap_acl_client_created(struct client **client)
+{
+       str_append((*client)->capability_string, " ACL RIGHTS=texk");
+
+       if (next_hook_client_created != NULL)
+               next_hook_client_created(client);
+}
+
 void imap_acl_plugin_init(void)
 {
        const char *env;
@@ -476,13 +485,14 @@ void imap_acl_plugin_init(void)
        if (env != NULL)
                acl_anyone_allow = strcmp(env, "allow") == 0;
 
-       str_append(capability_string, " ACL RIGHTS=texk");
-
        command_register("LISTRIGHTS", cmd_listrights, 0);
        command_register("GETACL", cmd_getacl, 0);
        command_register("MYRIGHTS", cmd_myrights, 0);
        command_register("SETACL", cmd_setacl, 0);
        command_register("DELETEACL", cmd_deleteacl, 0);
+
+       next_hook_client_created = hook_client_created;
+       hook_client_created = imap_acl_client_created;
 }
 
 void imap_acl_plugin_deinit(void)
@@ -495,4 +505,6 @@ void imap_acl_plugin_deinit(void)
        command_unregister("SETACL");
        command_unregister("DELETEACL");
        command_unregister("LISTRIGHTS");
+
+       hook_client_created = next_hook_client_created;
 }
index f28222bed0807eb55f1853ee9e0f415bb52cb34c..67d618e1c39fc8dd89ce81ce15817a9db5567fb3 100644 (file)
@@ -14,6 +14,7 @@
 #define QUOTA_USER_SEPARATOR ':'
 
 const char *imap_quota_plugin_version = PACKAGE_VERSION;
+static void (*next_hook_client_created)(struct client **client);
 
 static const char *
 imap_quota_root_get_name(struct mail_user *user, struct mail_user *owner,
@@ -213,12 +214,22 @@ static bool cmd_setquota(struct client_command_context *cmd)
        return TRUE;
 }
 
+static void imap_quota_client_created(struct client **client)
+{
+       str_append((*client)->capability_string, " QUOTA");
+
+       if (next_hook_client_created != NULL)
+               next_hook_client_created(client);
+}
+
 void imap_quota_plugin_init(void)
 {
        command_register("GETQUOTAROOT", cmd_getquotaroot, 0);
        command_register("GETQUOTA", cmd_getquota, 0);
        command_register("SETQUOTA", cmd_setquota, 0);
-       str_append(capability_string, " QUOTA");
+
+       next_hook_client_created = hook_client_created;
+       hook_client_created = imap_quota_client_created;
 }
 
 void imap_quota_plugin_deinit(void)
@@ -226,4 +237,6 @@ void imap_quota_plugin_deinit(void)
        command_unregister("GETQUOTAROOT");
        command_unregister("GETQUOTA");
        command_unregister("SETQUOTA");
+
+       hook_client_created = next_hook_client_created;
 }
index 1e2901da067cf161ed9b671448ef0ec7838ca99f..7d16d85906c033b179fa5289d944e45252e9bc6d 100644 (file)
@@ -147,8 +147,7 @@ mbox_snarf_mailbox_open(struct mail_storage *storage, const char *name,
                        /* use ~/mbox as the INBOX */
                        name = mstorage->snarf_inbox_path;
                        use_snarfing = TRUE;
-                       storage->flags |= MAIL_STORAGE_FLAG_FULL_FS_ACCESS;
-                       list->flags |= MAILBOX_LIST_FLAG_FULL_FS_ACCESS;
+                       storage->set->mail_full_filesystem_access = TRUE;
                } else if (errno != ENOENT) {
                        mail_storage_set_critical(storage,
                                                  "stat(%s) failed: %m",
index c0f75df7c0fcd2d09d07632244f6868525b47d7c..2573c87b3acd8a499e88a9577a9c1c54fbda3069 100644 (file)
@@ -71,7 +71,7 @@ virtual_get_list_settings(struct mailbox_list_settings *list_set,
                          const char *data, struct mail_storage *storage,
                          const char **layout_r, const char **error_r)
 {
-       bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+       bool debug = storage->set->mail_debug;
 
        *layout_r = "fs";
 
@@ -146,8 +146,7 @@ static int virtual_create(struct mail_storage *_storage, const char *data,
                                storage, &storage->list_module_ctx);
 
        /* finish list init after we've overridden vfuncs */
-       mailbox_list_init(_storage->list, _storage->ns, &list_set,
-                         mail_storage_get_list_flags(_storage->flags));
+       mailbox_list_init(_storage->list, _storage->ns, &list_set, 0);
        return 0;
 }
 
@@ -619,6 +618,7 @@ struct mail_storage virtual_storage = {
        MEMBER(mailbox_is_file) FALSE,
 
        {
+               NULL,
                virtual_class_init,
                virtual_class_deinit,
                virtual_alloc,
index 3ac2fad3a2dc3e13f0c3a4bad56d7b530ff2dfe0..dfa3f17a8f96193c1d8a1af7759c1465b9a2b98c 100644 (file)
@@ -10,6 +10,7 @@ AM_CPPFLAGS = \
 pop3_login_LDADD = \
        ../login-common/liblogin-common.a \
        ../lib-auth/libauth.a \
+       ../lib-settings/libsettings.a \
        ../lib/liblib.a \
        $(SSL_LIBS)
 
index 0d28740514b1ebc8f64a67c3587383d8a95ecd2c..0d6ea3115986c01368d4b1245fe1c0a783465f34 100644 (file)
@@ -36,7 +36,7 @@ bool cmd_capa(struct pop3_client *client, const char *args ATTR_UNUSED)
 
        if (ssl_initialized && !client->common.tls)
                str_append(str, "STLS\r\n");
-       if (!disable_plaintext_auth || client->common.secured)
+       if (!login_settings->disable_plaintext_auth || client->common.secured)
                str_append(str, "USER\r\n");
 
        str_append(str, "SASL");
@@ -47,7 +47,8 @@ bool cmd_capa(struct pop3_client *client, const char *args ATTR_UNUSED)
                   c) we allow insecure authentication
                */
                if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
-                   (client->common.secured || !disable_plaintext_auth ||
+                   (client->common.secured ||
+                    !login_settings->disable_plaintext_auth ||
                     (mech[i].flags & MECH_SEC_PLAINTEXT) == 0)) {
                        str_append_c(str, ' ');
                        str_append(str, mech[i].name);
@@ -155,7 +156,7 @@ static bool client_handle_args(struct pop3_client *client,
                        master_user = *args + 7;
                else if (strncmp(*args, "user=", 5) == 0) {
                        /* already handled in login-common */
-               } else if (auth_debug) {
+               } else if (login_settings->auth_debug) {
                        i_info("Ignoring unknown passdb extra field: %s",
                               *args);
                }
@@ -270,8 +271,9 @@ bool cmd_auth(struct pop3_client *client, const char *args)
        const struct auth_mech_desc *mech;
        const char *mech_name, *p;
 
-       if (!client->common.secured && ssl_required) {
-               if (verbose_auth) {
+       if (!client->common.secured &&
+           strcmp(login_settings->ssl, "required") == 0) {
+               if (login_settings->verbose_auth) {
                        client_syslog(&client->common, "Login failed: "
                                      "SSL required for authentication");
                }
@@ -289,7 +291,8 @@ bool cmd_auth(struct pop3_client *client, const char *args)
                mech = auth_client_get_available_mechs(auth_client, &count);
                for (i = 0; i < count; i++) {
                        if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
-                           (client->common.secured || disable_plaintext_auth ||
+                           (client->common.secured ||
+                            login_settings->disable_plaintext_auth ||
                             (mech[i].flags & MECH_SEC_PLAINTEXT) == 0))
                                client_send_line(client, mech[i].name);
                }
@@ -321,10 +324,11 @@ bool cmd_auth(struct pop3_client *client, const char *args)
 
 static bool check_plaintext_auth(struct pop3_client *client)
 {
-       if (client->common.secured || !disable_plaintext_auth)
+       if (client->common.secured ||
+           !login_settings->disable_plaintext_auth)
                return TRUE;
 
-       if (verbose_auth) {
+       if (login_settings->verbose_auth) {
                client_syslog(&client->common, "Login failed: "
                              "Plaintext authentication disabled");
        }
@@ -394,7 +398,7 @@ bool cmd_apop(struct pop3_client *client, const char *args)
        const char *p;
 
        if (client->apop_challenge == NULL) {
-               if (verbose_auth) {
+               if (login_settings->verbose_auth) {
                        client_syslog(&client->common,
                                      "APOP failed: APOP not enabled");
                }
@@ -405,7 +409,7 @@ bool cmd_apop(struct pop3_client *client, const char *args)
        /* <username> <md5 sum in hex> */
        p = strchr(args, ' ');
        if (p == NULL || strlen(p+1) != 32) {
-               if (verbose_auth) {
+               if (login_settings->verbose_auth) {
                        client_syslog(&client->common,
                                      "APOP failed: Invalid parameters");
                }
@@ -421,7 +425,7 @@ bool cmd_apop(struct pop3_client *client, const char *args)
        buffer_append_c(apop_data, '\0');
 
        if (hex_to_binary(p+1, apop_data) < 0) {
-               if (verbose_auth) {
+               if (login_settings->verbose_auth) {
                        client_syslog(&client->common, "APOP failed: "
                                      "Invalid characters in MD5 response");
                }
index 076e9bc465d6807a12115f2cf29e8c8c40b5ff93..fca024a546e6a78d8483c04814dbb68047861ce3 100644 (file)
@@ -39,7 +39,8 @@ static void client_set_title(struct pop3_client *client)
 {
        const char *addr;
 
-       if (!verbose_proctitle || !process_per_connection)
+       if (!login_settings->verbose_proctitle ||
+           !login_settings->login_process_per_connection)
                return;
 
        addr = net_ip2addr(&client->common.ip);
@@ -225,6 +226,7 @@ void client_input(struct pop3_client *client)
 
 void client_destroy_oldest(void)
 {
+       unsigned int max_connections = login_settings->login_max_connections;
        struct client *client;
        struct pop3_client *destroy_buf[CLIENT_DESTROY_OLDEST_COUNT];
        unsigned int i, destroy_count;
@@ -286,7 +288,8 @@ static void client_auth_ready(struct pop3_client *client)
        client->io = io_add(client->common.fd, IO_READ, client_input, client);
 
        client->apop_challenge = get_apop_challenge(client);
-       client_send_line(client, t_strconcat("+OK ", greeting,
+       client_send_line(client, t_strconcat("+OK ",
+                                            login_settings->login_greeting,
                                             client->apop_challenge != NULL ?
                                             " " : NULL,
                                             client->apop_challenge, NULL));
index d65710c2d28c97c041239eec18f9ca134a68f4e5..12d82f69db0791eeb493bb63128b18b48dc7d3b9 100644 (file)
@@ -144,7 +144,7 @@ static int proxy_input_line(struct pop3_client *client,
        else
                client_send_line(client, line);
 
-       if (verbose_auth) {
+       if (login_settings->verbose_auth) {
                str = t_str_new(128);
                str_printfa(str, "proxy(%s): Login failed to %s:%u",
                            client->common.virtual_user,
index c33bf7a212c613691668f67b14f4cb02b1950134..f1cd0544eba26bbd4d2461da0bc525b8398b4f43 100644 (file)
@@ -4,6 +4,7 @@ pkglibexec_PROGRAMS = pop3
 
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
+       -I$(top_srcdir)/src/lib-settings \
        -I$(top_srcdir)/src/lib-dict \
        -I$(top_srcdir)/src/lib-mail \
        -I$(top_srcdir)/src/lib-storage \
@@ -20,6 +21,7 @@ unused_objects = \
 libs = \
        $(STORAGE_LIBS) \
        ../lib-dict/libdict.a \
+       ../lib-settings/libsettings.a \
        $(unused_objects)
 
 pop3_LDADD = \
@@ -32,13 +34,15 @@ pop3_DEPENDENCIES = $(libs)
 pop3_SOURCES = \
        client.c \
        commands.c \
-       main.c
+       main.c \
+       pop3-settings.c
 
 headers = \
        capability.h \
        client.h \
        commands.h \
-       common.h
+       common.h \
+       pop3-settings.h
 
 if INSTALL_HEADERS
   pkginc_libdir=$(pkgincludedir)/src/pop3
index 0da0be855f902a361e416d95b975c5757534b55b..5def08488d7f759466eead78a86ba570a92ce461 100644 (file)
@@ -138,7 +138,8 @@ static bool init_mailbox(struct client *client, const char **error_r)
        return FALSE;
 }
 
-struct client *client_create(int fd_in, int fd_out, struct mail_user *user)
+struct client *client_create(int fd_in, int fd_out, struct mail_user *user,
+                            const struct pop3_settings *set)
 {
        struct mail_storage *storage;
        const char *inbox;
@@ -152,6 +153,7 @@ struct client *client_create(int fd_in, int fd_out, struct mail_user *user)
        net_set_nonblock(fd_out, TRUE);
 
        client = i_new(struct client, 1);
+       client->set = set;
        client->fd_in = fd_in;
        client->fd_out = fd_out;
        client->input = i_stream_create_fd(fd_in, MAX_INBUF_SIZE, FALSE);
@@ -176,9 +178,9 @@ struct client *client_create(int fd_in, int fd_out, struct mail_user *user)
        storage = client->inbox_ns->storage;
 
        flags = MAILBOX_OPEN_POP3_SESSION;
-       if (no_flag_updates)
+       if (set->pop3_no_flag_updates)
                flags |= MAILBOX_OPEN_KEEP_RECENT;
-       if (lock_session)
+       if (set->pop3_lock_session)
                flags |= MAILBOX_OPEN_KEEP_LOCKED;
        client->mailbox = mailbox_open(&storage, "INBOX", NULL, flags);
        if (client->mailbox == NULL) {
@@ -236,7 +238,7 @@ static const char *client_stats(struct client *client)
        tab[8].value = dec2str(client->output->offset);
 
        str = t_str_new(128);
-       var_expand(str, logout_format, tab);
+       var_expand(str, client->set->pop3_logout_format, tab);
        return str_c(str);
 }
 
index 8e24c54a9a523a83ca3933cc9fb248dd3d7a1d7d..181f4e3bf350b32a38f7bf75625710b8ea6274ed 100644 (file)
@@ -44,6 +44,11 @@ struct client {
 
        unsigned char *deleted_bitmask;
 
+       /* settings: */
+       const struct pop3_settings *set;
+       enum client_workarounds workarounds;
+       enum uidl_keys uidl_keymask;
+
        unsigned int disconnected:1;
        unsigned int deleted:1;
        unsigned int waiting_input:1;
@@ -51,7 +56,8 @@ struct client {
 
 /* Create new client with specified input/output handles. socket specifies
    if the handle is a socket. */
-struct client *client_create(int fd_in, int fd_out, struct mail_user *user);
+struct client *client_create(int fd_in, int fd_out, struct mail_user *user,
+                            const struct pop3_settings *set);
 void client_destroy(struct client *client, const char *reason);
 
 /* Disconnect client connection */
index 162e2ce92225360d70f79b396c312aefbf105763..62b88c34dcb0f7c6249e4ce4f474fc484c2e9cb1 100644 (file)
@@ -8,6 +8,7 @@
 #include "var-expand.h"
 #include "message-size.h"
 #include "mail-storage.h"
+#include "mail-storage-settings.h"
 #include "mail-search-build.h"
 #include "capability.h"
 #include "commands.h"
@@ -321,7 +322,7 @@ static void fetch_callback(struct client *client)
                                add = '.';
                                break;
                        } else if (data[i] == '\0' &&
-                                  (client_workarounds &
+                                  (client->workarounds &
                                    WORKAROUND_OUTLOOK_NO_NULS) != 0) {
                                add = 0x80;
                                break;
@@ -359,7 +360,8 @@ static void fetch_callback(struct client *client)
                (void)o_stream_send(client->output, "\r\n", 2);
        }
 
-       if (!ctx->in_body && (client_workarounds & WORKAROUND_OE_NS_EOH) != 0) {
+       if (!ctx->in_body &&
+           (client->workarounds & WORKAROUND_OE_NS_EOH) != 0) {
                /* Add the missing end of headers line. */
                (void)o_stream_send(client->output, "\r\n", 2);
        }
@@ -408,7 +410,7 @@ static int fetch(struct client *client, unsigned int msgnum, uoff_t body_lines)
                return ret;
        }
 
-       if (body_lines == (uoff_t)-1 && !no_flag_updates) {
+       if (body_lines == (uoff_t)-1 && !client->set->pop3_no_flag_updates) {
                if ((mail_get_flags(ctx->mail) & MAIL_SEEN) == 0) {
                        /* mark the message seen with RETR command */
                        (void)mail_update_flags(ctx->mail,
@@ -463,7 +465,7 @@ static int cmd_rset(struct client *client, const char *args ATTR_UNUSED)
                client->deleted_size = 0;
        }
 
-       if (enable_last_command) {
+       if (client->set->pop3_enable_last) {
                /* remove all \Seen flags (as specified by RFC 1460) */
                search_args = pop3_search_build(client, 0);
                search_ctx = mailbox_search_init(client->trans,
@@ -518,7 +520,7 @@ struct cmd_uidl_context {
        unsigned int message;
 };
 
-static void pop3_get_uid(struct cmd_uidl_context *ctx,
+static void pop3_get_uid(struct client *client, struct cmd_uidl_context *ctx,
                         struct var_expand_table *tab, string_t *str)
 {
        char uid_str[MAX_INT_STRLEN];
@@ -530,18 +532,18 @@ static void pop3_get_uid(struct cmd_uidl_context *ctx,
                return;
        }
 
-       if (reuse_xuidl &&
+       if (client->set->pop3_reuse_xuidl &&
            mail_get_first_header(ctx->mail, "X-UIDL", &uidl) > 0) {
                str_append(str, uidl);
                return;
        }
 
-       if ((uidl_keymask & UIDL_UID) != 0) {
+       if ((client->uidl_keymask & UIDL_UID) != 0) {
                i_snprintf(uid_str, sizeof(uid_str), "%u",
                           ctx->mail->uid);
                tab[1].value = uid_str;
        }
-       if ((uidl_keymask & UIDL_MD5) != 0) {
+       if ((client->uidl_keymask & UIDL_MD5) != 0) {
                if (mail_get_special(ctx->mail, MAIL_FETCH_HEADER_MD5,
                                     &tab[2].value) < 0 ||
                    *tab[2].value == '\0') {
@@ -549,7 +551,7 @@ static void pop3_get_uid(struct cmd_uidl_context *ctx,
                        i_fatal("UIDL: Header MD5 not found");
                }
        }
-       if ((uidl_keymask & UIDL_FILE_NAME) != 0) {
+       if ((client->uidl_keymask & UIDL_FILE_NAME) != 0) {
                if (mail_get_special(ctx->mail,
                                     MAIL_FETCH_UIDL_FILE_NAME,
                                     &tab[3].value) < 0 ||
@@ -558,7 +560,7 @@ static void pop3_get_uid(struct cmd_uidl_context *ctx,
                        i_fatal("UIDL: File name not found");
                }
        }
-       var_expand(str, uidl_format, tab);
+       var_expand(str, client->set->pop3_uidl_format, tab);
 }
 
 static bool list_uids_iter(struct client *client, struct cmd_uidl_context *ctx)
@@ -592,7 +594,7 @@ static bool list_uids_iter(struct client *client, struct cmd_uidl_context *ctx)
                str_truncate(str, 0);
                str_printfa(str, ctx->message == 0 ? "%u " : "+OK %u ",
                            ctx->mail->seq);
-               pop3_get_uid(ctx, tab, str);
+               pop3_get_uid(client, ctx, tab, str);
 
                ret = client_send_line(client, "%s", str_c(str));
                if (ret < 0)
@@ -636,7 +638,7 @@ cmd_uidl_init(struct client *client, unsigned int message)
        ctx->message = message;
 
        wanted_fields = 0;
-       if ((uidl_keymask & UIDL_MD5) != 0)
+       if ((client->uidl_keymask & UIDL_MD5) != 0)
                wanted_fields |= MAIL_FETCH_HEADER_MD5;
 
        ctx->search_ctx = mailbox_search_init(client->trans, search_args, NULL);
@@ -692,7 +694,7 @@ int client_command_execute(struct client *client,
        case 'L':
                if (strcmp(name, "LIST") == 0)
                        return cmd_list(client, args);
-               if (strcmp(name, "LAST") == 0 && enable_last_command)
+               if (strcmp(name, "LAST") == 0 && client->set->pop3_enable_last)
                        return cmd_last(client, args);
                break;
        case 'N':
index 0679dbc35a745dff0906393be090f1a661a2bc07..e64e244d93319ae89a688e5ae4ec3f3964d1b842 100644 (file)
@@ -1,9 +1,6 @@
 #ifndef COMMON_H
 #define COMMON_H
 
-#include "lib.h"
-#include "client.h"
-
 enum client_workarounds {
        WORKAROUND_OUTLOOK_NO_NULS              = 0x01,
        WORKAROUND_OE_NS_EOH                    = 0x02
@@ -16,11 +13,11 @@ enum uidl_keys {
        UIDL_FILE_NAME          = 0x08
 };
 
+#include "lib.h"
+#include "client.h"
+#include "pop3-settings.h"
+
 extern struct ioloop *ioloop;
-extern enum client_workarounds client_workarounds;
-extern bool enable_last_command, no_flag_updates, reuse_xuidl, lock_session;
-extern const char *uidl_format, *logout_format;
-extern enum uidl_keys uidl_keymask;
 
 extern void (*hook_client_created)(struct client **client);
 
index 55873501a4094370723b098d95e28664c0cb14e6..d39dd2ba7f2533522c62f5b876b7184d10070731 100644 (file)
@@ -44,14 +44,6 @@ static struct module *modules = NULL;
 static char log_prefix[128]; /* syslog() needs this to be permanent */
 static struct io *log_io = NULL;
 
-enum client_workarounds client_workarounds = 0;
-bool enable_last_command = FALSE;
-bool no_flag_updates = FALSE;
-bool reuse_xuidl = FALSE;
-bool lock_session = FALSE;
-const char *uidl_format, *logout_format;
-enum uidl_keys uidl_keymask;
-
 static void sig_die(int signo, void *context ATTR_UNUSED)
 {
        /* warn about being killed because of some signal, except SIGINT (^C)
@@ -66,16 +58,15 @@ static void log_error_callback(void *context ATTR_UNUSED)
        io_loop_stop(ioloop);
 }
 
-static void parse_workarounds(void)
+static enum client_workarounds
+parse_workarounds(const struct pop3_settings *set)
 {
-        struct client_workaround_list *list;
-       const char *env, *const *str;
-
-       env = getenv("POP3_CLIENT_WORKAROUNDS");
-       if (env == NULL)
-               return;
+        enum client_workarounds client_workarounds = 0;
+       struct client_workaround_list *list;
+       const char *const *str;
 
-       for (str = t_strsplit_spaces(env, " ,"); *str != NULL; str++) {
+        str = t_strsplit_spaces(set->pop3_client_workarounds, " ,");
+       for (; *str != NULL; str++) {
                list = client_workaround_list;
                for (; list->name != NULL; list++) {
                        if (strcasecmp(*str, list->name) == 0) {
@@ -86,6 +77,7 @@ static void parse_workarounds(void)
                if (list->name == NULL)
                        i_fatal("Unknown client workaround: %s", *str);
        }
+       return client_workarounds;
 }
 
 static enum uidl_keys parse_uidl_keymask(const char *format)
@@ -150,7 +142,8 @@ static void open_logfile(void)
        i_set_failure_timestamp_format(getenv("LOGSTAMP"));
 }
 
-static void drop_privileges(void)
+static void main_preinit(const struct pop3_settings **set_r,
+                        const struct mail_user_settings **user_set_r)
 {
        const char *version;
 
@@ -164,24 +157,28 @@ static void drop_privileges(void)
        /* Log file or syslog opening probably requires roots */
        open_logfile();
 
-       /* Load the plugins before chrooting. Their init() is called later. */
-       if (getenv("MAIL_PLUGINS") != NULL) {
-               const char *plugin_dir = getenv("MAIL_PLUGIN_DIR");
+        mail_storage_init();
+       mail_storage_register_all();
+       mailbox_list_register_all();
 
-               if (plugin_dir == NULL)
-                       plugin_dir = MODULEDIR"/pop3";
-               modules = module_dir_load(plugin_dir, getenv("MAIL_PLUGINS"),
-                                         TRUE, version);
-       }
+       /* read settings after registering storages so they can have their
+          own setting definitions too */
+       pop3_settings_read(set_r, user_set_r);
+
+       /* Load the plugins before chrooting. Their init() is called later. */
+       modules = *(*set_r)->mail_plugins == '\0' ? NULL :
+               module_dir_load((*set_r)->mail_plugin_dir,
+                               (*set_r)->mail_plugins, TRUE, version);
 
        restrict_access_by_env(!IS_STANDALONE());
 }
 
-static bool main_init(void)
+static bool main_init(const struct pop3_settings *set,
+                     const struct mail_user_settings *user_set)
 {
        struct mail_user *user;
        struct client *client;
-       const char *str;
+       const char *str, *error;
        bool ret = TRUE;
 
        lib_signals_init();
@@ -193,12 +190,12 @@ static bool main_init(void)
        if (getenv("USER") == NULL)
                i_fatal("USER environment missing");
 
-       if (getenv("DEBUG") != NULL) {
+       if (set->mail_debug) {
                i_info("Effective uid=%s, gid=%s",
                       dec2str(geteuid()), dec2str(getegid()));
        }
 
-       if (getenv("STDERR_CLOSE_SHUTDOWN") != NULL) {
+       if (set->shutdown_clients) {
                /* If master dies, the log fd gets closed and we'll quit */
                log_io = io_add(STDERR_FILENO, IO_ERROR,
                                log_error_callback, NULL);
@@ -206,38 +203,26 @@ static bool main_init(void)
 
        dict_drivers_register_builtin();
        mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL);
-        mail_storage_init();
-       mail_storage_register_all();
-       mailbox_list_register_all();
        clients_init();
 
        module_dir_init(modules);
 
-       parse_workarounds();
-       enable_last_command = getenv("POP3_ENABLE_LAST") != NULL;
-       no_flag_updates = getenv("POP3_NO_FLAG_UPDATES") != NULL;
-       reuse_xuidl = getenv("POP3_REUSE_XUIDL") != NULL;
-       lock_session = getenv("POP3_LOCK_SESSION") != NULL;
-
-       uidl_format = getenv("POP3_UIDL_FORMAT");
-       if (uidl_format == NULL || *uidl_format == '\0')
-               uidl_format = "%08Xu%08Xv";
-       logout_format = getenv("POP3_LOGOUT_FORMAT");
-       if (logout_format == NULL)
-               logout_format = "top=%t/%p, retr=%r/%b, del=%d/%m, size=%s";
-       uidl_keymask = parse_uidl_keymask(uidl_format);
-       if (uidl_keymask == 0)
-               i_fatal("pop3_uidl_format setting doesn't contain any "
-                       "%% variables.");
-
-       user = mail_user_init(getenv("USER"));
+       user = mail_user_alloc(getenv("USER"), user_set);
        mail_user_set_home(user, getenv("HOME"));
-       if (mail_namespaces_init(user) < 0)
-               i_fatal("Namespace initialization failed");
+       if (mail_user_init(user, &error) < 0)
+               i_fatal("Mail user initialization failed: %s", error);
+       if (mail_namespaces_init(user, &error) < 0)
+               i_fatal("Namespace initialization failed: %s", error);
 
-       client = client_create(0, 1, user);
+       client = client_create(0, 1, user, set);
        if (client == NULL)
                return FALSE;
+       client->workarounds = parse_workarounds(set);
+       client->uidl_keymask = parse_uidl_keymask(set->pop3_uidl_format);
+       if (client->uidl_keymask == 0) {
+               i_fatal("pop3_uidl_format setting doesn't contain any "
+                       "%% variables.");
+       }
 
        if (!IS_STANDALONE())
                client_send_line(client, "+OK Logged in.");
@@ -272,8 +257,11 @@ static void main_deinit(void)
 
 int main(int argc ATTR_UNUSED, char *argv[], char *envp[])
 {
+       const struct pop3_settings *set;
+       const struct mail_user_settings *user_set;
+
 #ifdef DEBUG
-       if (getenv("LOGGED_IN") != NULL && getenv("GDB") == NULL)
+       if (!IS_STANDALONE() && getenv("GDB") == NULL)
                fd_debug_verify_leaks(3, 1024);
 #endif
        if (IS_STANDALONE() && getuid() == 0 &&
@@ -286,12 +274,12 @@ int main(int argc ATTR_UNUSED, char *argv[], char *envp[])
        /* NOTE: we start rooted, so keep the code minimal until
           restrict_access_by_env() is called */
        lib_init();
-       drop_privileges();
+       main_preinit(&set, &user_set);
 
         process_title_init(argv, envp);
        ioloop = io_loop_create();
 
-       if (main_init())
+       if (main_init(set, user_set))
                io_loop_run(ioloop);
        main_deinit();
 
diff --git a/src/pop3/pop3-settings.c b/src/pop3/pop3-settings.c
new file mode 100644 (file)
index 0000000..24c36b1
--- /dev/null
@@ -0,0 +1,101 @@
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "mail-storage-settings.h"
+#include "pop3-settings.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+       { type, #name, offsetof(struct pop3_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+       { SET_DEFLIST, name, offsetof(struct pop3_settings, field), defines }
+
+static struct setting_define pop3_setting_defines[] = {
+       DEF(SET_BOOL, mail_debug),
+       DEF(SET_BOOL, shutdown_clients),
+       DEF(SET_BOOL, verbose_proctitle),
+
+       DEF(SET_STR, mail_plugins),
+       DEF(SET_STR, mail_plugin_dir),
+       DEF(SET_STR_VARS, mail_log_prefix),
+
+       DEF(SET_BOOL, pop3_no_flag_updates),
+       DEF(SET_BOOL, pop3_enable_last),
+       DEF(SET_BOOL, pop3_reuse_xuidl),
+       DEF(SET_BOOL, pop3_lock_session),
+       DEF(SET_STR, pop3_client_workarounds),
+       DEF(SET_STR, pop3_logout_format),
+       DEF(SET_STR, pop3_uidl_format),
+
+       SETTING_DEFINE_LIST_END
+};
+
+static struct pop3_settings pop3_default_settings = {
+       MEMBER(mail_debug) FALSE,
+       MEMBER(shutdown_clients) FALSE,
+       MEMBER(verbose_proctitle) FALSE,
+
+       MEMBER(mail_plugins) "",
+       MEMBER(mail_plugin_dir) MODULEDIR"/pop3",
+       MEMBER(mail_log_prefix) "%Us(%u): ",
+
+       MEMBER(pop3_no_flag_updates) FALSE,
+       MEMBER(pop3_enable_last) FALSE,
+       MEMBER(pop3_reuse_xuidl) FALSE,
+       MEMBER(pop3_lock_session) FALSE,
+       MEMBER(pop3_client_workarounds) NULL,
+       MEMBER(pop3_logout_format) "top=%t/%p, retr=%r/%b, del=%d/%m, size=%s",
+       MEMBER(pop3_uidl_format) "%08Xu%08Xv"
+};
+
+struct setting_parser_info pop3_setting_parser_info = {
+       MEMBER(defines) pop3_setting_defines,
+       MEMBER(defaults) &pop3_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 pop3_settings)
+};
+
+static pool_t settings_pool = NULL;
+
+void pop3_settings_read(const struct pop3_settings **set_r,
+                       const struct mail_user_settings **user_set_r)
+{
+       static const struct setting_parser_info *roots[] = {
+                &pop3_setting_parser_info,
+                &mail_user_setting_parser_info
+       };
+       struct setting_parser_context *parser;
+       void **sets;
+
+       if (settings_pool == NULL)
+               settings_pool = pool_alloconly_create("pop3 settings", 1024);
+       else
+               p_clear(settings_pool);
+
+       mail_storage_namespace_defines_init(settings_pool);
+
+       parser = settings_parser_init_list(settings_pool,
+                               roots, N_ELEMENTS(roots),
+                               SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
+
+       settings_parse_set_expanded(parser, TRUE);
+       if (settings_parse_environ(parser) < 0) {
+               i_fatal("Error reading configuration: %s",
+                       settings_parser_get_error(parser));
+       }
+
+       sets = settings_parser_get_list(parser);
+       *set_r = sets[0];
+       *user_set_r = sets[1];
+       settings_parser_deinit(&parser);
+}
diff --git a/src/pop3/pop3-settings.h b/src/pop3/pop3-settings.h
new file mode 100644 (file)
index 0000000..9301b3c
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef POP3_SETTINGS_H
+#define POP3_SETTINGS_H
+
+struct mail_user_settings;
+
+struct pop3_settings {
+       bool mail_debug;
+       bool shutdown_clients;
+       bool verbose_proctitle;
+
+       const char *mail_plugins;
+       const char *mail_plugin_dir;
+       const char *mail_log_prefix;
+
+       /* pop3: */
+       bool pop3_no_flag_updates;
+       bool pop3_enable_last;
+       bool pop3_reuse_xuidl;
+       bool pop3_lock_session;
+       const char *pop3_client_workarounds;
+       const char *pop3_logout_format;
+       const char *pop3_uidl_format;
+};
+
+void pop3_settings_read(const struct pop3_settings **set_r,
+                       const struct mail_user_settings **user_set_r);
+
+#endif