]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
config handling fixes and improvements. Separated module/service lookups. Added suppo...
authorTimo Sirainen <tss@iki.fi>
Tue, 12 May 2009 00:10:30 +0000 (20:10 -0400)
committerTimo Sirainen <tss@iki.fi>
Tue, 12 May 2009 00:10:30 +0000 (20:10 -0400)
--HG--
branch : HEAD

18 files changed:
src/config/Makefile.am
src/config/all-settings.h
src/config/config-connection.c
src/config/config-filter.c [new file with mode: 0644]
src/config/config-filter.h [new file with mode: 0644]
src/config/config-parser.c
src/config/config-parser.h
src/config/config-request.c
src/config/config-request.h
src/config/doveconf.c
src/imap/main.c
src/lda/main.c
src/lib-master/master-service-settings.c
src/lib-master/master-service-settings.h
src/lib-storage/mail-storage-service.c
src/lib-storage/mail-storage-service.h
src/login-common/login-settings.c
src/pop3/main.c

index 141b6bd3a3114e24d691e366166cd8ea43058885..442fe91064cbb445a4fca4ecdb8a762337473a4b 100644 (file)
@@ -28,6 +28,7 @@ doveconf_DEPENDENCIES = $(LIBDOVECOT)
 common = \
        all-settings.c \
        config-connection.c \
+       config-filter.c \
        config-parser.c \
        config-request.c \
        sysinfo-get.c
@@ -43,6 +44,7 @@ doveconf_SOURCES = \
 noinst_HEADERS = \
        all-settings.h \
        config-connection.h \
+       config-filter.h \
        config-parser.h \
        config-request.h \
        sysinfo-get.h
index 58ad541abebe35a43376893fbd04f116f9394c1e..8060196a4ffef052f6bf489094d8426f32b585d0 100644 (file)
@@ -7,6 +7,7 @@ struct config_setting_parser_list {
        struct setting_parser_context *parser;
        void *settings;
 };
+ARRAY_DEFINE_TYPE(config_setting_parsers, struct config_setting_parser_list *);
 
 extern struct config_setting_parser_list config_setting_parsers[];
 
index a7064a0b7ca88121b392e0126e1627f949003b70..151fae71b355f794a84f1498cf1b0ca6de51b1d8 100644 (file)
@@ -56,16 +56,34 @@ config_request_output(const char *key, const char *value,
 static void config_connection_request(struct config_connection *conn,
                                      const char *const *args)
 {
-       const char *service = "";
+       struct config_filter filter;
+       const char *module = "";
 
        /* [<args>] */
+       memset(&filter, 0, sizeof(filter));
        for (; *args != NULL; args++) {
                if (strncmp(*args, "service=", 8) == 0)
-                       service = *args + 8;
+                       filter.service = *args + 8;
+               else if (strncmp(*args, "module=", 7) == 0)
+                       module = *args + 7;
+               else if (strncmp(*args, "lip=", 4) == 0) {
+                       if (net_addr2ip(*args + 4, &filter.local_net) == 0) {
+                               filter.local_bits =
+                                       IPADDR_IS_V4(&filter.local_net) ?
+                                       32 : 128;
+                       }
+               } else if (strncmp(*args, "rip=", 4) == 0) {
+                       if (net_addr2ip(*args + 4, &filter.remote_net) == 0) {
+                               filter.remote_bits =
+                                       IPADDR_IS_V4(&filter.remote_net) ?
+                                       32 : 128;
+                       }
+               }
        }
 
        o_stream_cork(conn->output);
-       config_request_handle(service, 0, config_request_output, conn->output);
+       config_request_handle(&filter, module, 0, config_request_output,
+                             conn->output);
        o_stream_send_str(conn->output, "\n");
        o_stream_uncork(conn->output);
 }
diff --git a/src/config/config-filter.c b/src/config/config-filter.c
new file mode 100644 (file)
index 0000000..8fd0c6a
--- /dev/null
@@ -0,0 +1,120 @@
+/* Copyright (C) 2005-2009 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "config-filter.h"
+
+struct config_filter_context {
+       pool_t pool;
+       struct config_filter_parser_list *const *parsers;
+};
+
+bool config_filter_match(const struct config_filter *mask,
+                        const struct config_filter *filter)
+{
+       if (mask->service != NULL) {
+               if (filter->service == NULL)
+                       return FALSE;
+               if (strcasecmp(filter->service, mask->service) != 0)
+                       return FALSE;
+       }
+       /* FIXME: it's not comparing full masks */
+       if (mask->remote_bits != 0) {
+               if (filter->remote_bits == 0)
+                       return FALSE;
+               if (!net_is_in_network(&filter->remote_net, &mask->remote_net,
+                                      mask->remote_bits))
+                       return FALSE;
+       }
+       if (mask->local_bits != 0) {
+               if (filter->local_bits == 0)
+                       return FALSE;
+               if (!net_is_in_network(&filter->local_net, &mask->local_net,
+                                      mask->local_bits))
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+bool config_filters_equal(const struct config_filter *f1,
+                         const struct config_filter *f2)
+{
+       if (null_strcmp(f1->service, f2->service) != 0)
+               return FALSE;
+
+       if (f1->remote_bits != f2->remote_bits)
+               return FALSE;
+       if (!net_ip_compare(&f1->remote_net, &f2->remote_net))
+               return FALSE;
+
+       if (f1->local_bits != f2->local_bits)
+               return FALSE;
+       if (!net_ip_compare(&f1->local_net, &f2->local_net))
+               return FALSE;
+
+       return TRUE;
+}
+
+struct config_filter_context *config_filter_init(pool_t pool)
+{
+       struct config_filter_context *ctx;
+
+       ctx = p_new(pool, struct config_filter_context, 1);
+       ctx->pool = pool;
+       return ctx;
+}
+
+void config_filter_deinit(struct config_filter_context **_ctx)
+{
+       struct config_filter_context *ctx = *_ctx;
+
+       *_ctx = NULL;
+
+       pool_unref(&ctx->pool);
+}
+
+void config_filter_add_all(struct config_filter_context *ctx,
+                          struct config_filter_parser_list *const *parsers)
+{
+       ctx->parsers = parsers;
+}
+
+static int filter_cmp(const struct config_filter *f1,
+                     const struct config_filter *f2)
+{
+       int ret;
+
+       ret = f2->remote_bits - f1->remote_bits;
+       if (ret != 0)
+               return ret;
+
+       ret = f2->local_bits - f1->local_bits;
+       if (ret != 0)
+               return ret;
+
+       if (f1->service != NULL)
+               return -1;
+       else
+               return 1;
+}
+
+const struct config_setting_parser_list *
+config_filter_match_parsers(struct config_filter_context *ctx,
+                           const struct config_filter *filter)
+{
+       struct config_filter_parser_list *best = NULL;
+       unsigned int i;
+
+       /* find the filter that best matches what we have.
+          FIXME: this can't really work. we'd want to merge changes from
+          different matches.. requires something larger after all. */
+       for (i = 0; ctx->parsers[i] != NULL; i++) {
+               if (!config_filter_match(&ctx->parsers[i]->filter, filter))
+                       continue;
+
+               if (best == NULL ||
+                   filter_cmp(&best->filter, &ctx->parsers[i]->filter) > 0)
+                       best = ctx->parsers[i];
+       }
+       return best == NULL ? NULL : best->parser_list;
+}
diff --git a/src/config/config-filter.h b/src/config/config-filter.h
new file mode 100644 (file)
index 0000000..de184a2
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef CONFIG_FILTER_H
+#define CONFIG_FILTER_H
+
+#include "network.h"
+#include "all-settings.h"
+
+struct config_filter {
+       const char *service;
+       struct ip_addr local_net, remote_net;
+       unsigned int local_bits, remote_bits;
+};
+
+struct config_filter_parser_list {
+       struct config_filter filter;
+       struct config_setting_parser_list *parser_list;
+};
+
+struct config_filter_context *config_filter_init(pool_t pool);
+void config_filter_deinit(struct config_filter_context **ctx);
+
+void config_filter_add_all(struct config_filter_context *ctx,
+                          struct config_filter_parser_list *const *parsers);
+
+const struct config_setting_parser_list *
+config_filter_match_parsers(struct config_filter_context *ctx,
+                           const struct config_filter *filter);
+
+/* Returns TRUE if filter matches mask. */
+bool config_filter_match(const struct config_filter *mask,
+                        const struct config_filter *filter);
+/* Returns TRUE if two filters are fully equal. */
+bool config_filters_equal(const struct config_filter *f1,
+                         const struct config_filter *f2);
+
+#endif
index aff6a43d053e96bff58bc15f5562c353c37e67df..8150ac6a606ca7d5df19062a4068e44c7d794d04 100644 (file)
@@ -7,7 +7,7 @@
 #include "strescape.h"
 #include "istream.h"
 #include "settings-parser.h"
-#include "all-settings.h"
+#include "config-filter.h"
 #include "config-parser.h"
 
 #include <unistd.h>
 
 #define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
 
+struct config_filter_stack {
+       struct config_filter_stack *prev;
+       struct config_filter filter;
+       unsigned int pathlen;
+};
+
 struct input_stack {
        struct input_stack *prev;
 
@@ -23,6 +29,21 @@ struct input_stack {
        unsigned int linenum;
 };
 
+struct parser_context {
+       pool_t pool;
+       const char *path;
+
+       ARRAY_DEFINE(all_parsers, struct config_filter_parser_list *);
+       /* parsers matching cur_filter */
+       ARRAY_TYPE(config_setting_parsers) cur_parsers;
+       struct config_filter_stack *cur_filter;
+       struct input_stack *cur_input;
+
+       struct config_filter_context *filter;
+};
+
+struct config_filter_context *config_filter;
+
 static const char *info_type_name_find(const struct setting_parser_info *info)
 {
        unsigned int i;
@@ -62,13 +83,15 @@ static void config_add_type(struct setting_parser_context *parser,
 }
 
 static const char *
-config_parse_line(const char *key, const char *line, const char *section_name)
+config_parsers_parse_line(struct config_setting_parser_list *parsers,
+                         const char *key, const char *line,
+                         const char *section_name)
 {
        struct config_setting_parser_list *l;
        bool found = FALSE;
        int ret;
 
-       for (l = config_setting_parsers; l->module_name != NULL; l++) {
+       for (l = parsers; l->module_name != NULL; l++) {
                ret = settings_parse_line(l->parser, line);
                if (ret > 0) {
                        found = TRUE;
@@ -81,6 +104,21 @@ config_parse_line(const char *key, const char *line, const char *section_name)
        return found ? NULL : t_strconcat("Unknown setting: ", key, NULL);
 }
 
+static const char *
+config_parse_line(struct config_setting_parser_list *const *all_parsers,
+                 const char *key, const char *line, const char *section_name)
+{
+       const char *ret;
+
+       for (; *all_parsers != NULL; all_parsers++) {
+               ret = config_parsers_parse_line(*all_parsers, key, line,
+                                               section_name);
+               if (ret != NULL)
+                       return ret;
+       }
+       return NULL;
+}
+
 static const char *
 fix_relative_path(const char *path, struct input_stack *input)
 {
@@ -96,14 +134,122 @@ fix_relative_path(const char *path, struct input_stack *input)
        return t_strconcat(t_strdup_until(input->path, p+1), path, NULL);
 }
 
+static struct config_setting_parser_list *
+config_setting_parser_list_dup(pool_t pool,
+                              const struct config_setting_parser_list *src)
+{
+       struct config_setting_parser_list *dest;
+       unsigned int i, count;
+
+       for (count = 0; src[count].module_name != NULL; count++) ;
+
+       dest = p_new(pool, struct config_setting_parser_list, count + 1);
+       for (i = 0; i < count; i++) {
+               dest[i] = src[i];
+               dest[i].parser = settings_parser_dup(src[i].parser, pool);
+       }
+       return dest;
+}
+
+static struct config_filter_parser_list *
+config_add_new_parser(struct parser_context *ctx)
+{
+       struct config_filter_parser_list *parser;
+       struct config_setting_parser_list *const *cur_parsers;
+       unsigned int count;
+
+       parser = p_new(ctx->pool, struct config_filter_parser_list, 1);
+       parser->filter = ctx->cur_filter->filter;
+
+       cur_parsers = array_get(&ctx->cur_parsers, &count);
+       if (count == 0) {
+               /* first one */
+               parser->parser_list = config_setting_parsers;
+       } else {
+               /* duplicate the first settings list */
+               parser->parser_list =
+                       config_setting_parser_list_dup(ctx->pool,
+                                                      cur_parsers[0]);
+       }
+
+       array_append(&ctx->all_parsers, &parser, 1);
+       return parser;
+}
+
+static void config_add_new_filter(struct parser_context *ctx)
+{
+       struct config_filter_stack *filter;
+
+       filter = p_new(ctx->pool, struct config_filter_stack, 1);
+       filter->prev = ctx->cur_filter;
+       filter->filter = ctx->cur_filter->filter;
+       ctx->cur_filter = filter;
+}
+
+static struct config_setting_parser_list *const *
+config_update_cur_parsers(struct parser_context *ctx)
+{
+       struct config_filter_parser_list *const *all_parsers;
+       unsigned int i, count;
+       bool full_found = FALSE;
+
+       array_clear(&ctx->cur_parsers);
+
+       all_parsers = array_get(&ctx->all_parsers, &count);
+       for (i = 0; i < count; i++) {
+               if (!config_filter_match(&ctx->cur_filter->filter,
+                                        &all_parsers[i]->filter))
+                       continue;
+
+               if (config_filters_equal(&all_parsers[i]->filter,
+                                        &ctx->cur_filter->filter)) {
+                       array_insert(&ctx->cur_parsers, 0,
+                                    &all_parsers[i]->parser_list, 1);
+                       full_found = TRUE;
+               } else {
+                       array_append(&ctx->cur_parsers,
+                                    &all_parsers[i]->parser_list, 1);
+               }
+       }
+       i_assert(full_found);
+       (void)array_append_space(&ctx->cur_parsers);
+       return array_idx(&ctx->cur_parsers, 0);
+}
+
+static void
+config_filter_parser_list_check(struct parser_context *ctx,
+                               struct config_filter_parser_list *parser)
+{
+       struct config_setting_parser_list *l = parser->parser_list;
+       const char *errormsg;
+
+       for (; l->module_name != NULL; l++) {
+               if (!settings_parser_check(l->parser, ctx->pool, &errormsg)) {
+                       i_fatal("Error in configuration file %s: %s",
+                               ctx->path, errormsg);
+               }
+       }
+}
+
+static void
+config_all_parsers_check(struct parser_context *ctx)
+{
+       struct config_filter_parser_list *const *parsers;
+       unsigned int i, count;
+
+       parsers = array_get(&ctx->all_parsers, &count);
+       for (i = 0; i < count; i++)
+               config_filter_parser_list_check(ctx, parsers[i]);
+}
+
 void config_parse_file(const char *path)
 {
        enum settings_parser_flags parser_flags =
                 SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS;
-       struct input_stack root, *input, *new_input;
-       ARRAY_DEFINE(pathlen_stack, unsigned int);
+       struct input_stack root, *new_input;
        ARRAY_TYPE(const_string) auth_defaults;
-       struct config_setting_parser_list *l;
+       struct config_setting_parser_list *l, *const *parsers;
+       struct parser_context ctx;
        unsigned int pathlen = 0;
        unsigned int counter = 0, auth_counter = 0, cur_counter;
        const char *errormsg, *name;
@@ -111,38 +257,46 @@ void config_parse_file(const char *path)
        int fd, ret;
        string_t *str, *full_line;
        size_t len;
-       pool_t pool;
 
-       pool = pool_alloconly_create("config file parser", 10240);
+       memset(&ctx, 0, sizeof(ctx));
+       ctx.pool = pool_alloconly_create("config file parser", 10240);
+       ctx.path = path;
 
        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);
 
        for (l = config_setting_parsers; l->module_name != NULL; l++) {
                i_assert(l->parser == NULL);
-               l->parser = settings_parser_init(pool, l->root, parser_flags);
+               l->parser = settings_parser_init(ctx.pool, l->root, parser_flags);
        }
 
-       errormsg = config_parse_line("0", "auth=0", NULL);
+       t_array_init(&ctx.cur_parsers, 128);
+       p_array_init(&ctx.all_parsers, ctx.pool, 128);
+       ctx.cur_filter = p_new(ctx.pool, struct config_filter_stack, 1);
+       config_add_new_parser(&ctx);
+       parsers = config_update_cur_parsers(&ctx);
+
+       errormsg = config_parse_line(parsers, "0", "auth=0", NULL);
+       i_assert(errormsg == NULL);
+       errormsg = config_parse_line(parsers, "name", "auth/0/name=default", NULL);
        i_assert(errormsg == NULL);
 
        memset(&root, 0, sizeof(root));
        root.path = path;
-       input = &root;
+       ctx.cur_input = &root;
 
        str = t_str_new(256);
        full_line = t_str_new(512);
        errormsg = NULL;
 newfile:
-       input->input = i_stream_create_fd(fd, (size_t)-1, TRUE);
-       i_stream_set_return_partial_line(input->input, TRUE);
+       ctx.cur_input->input = i_stream_create_fd(fd, (size_t)-1, TRUE);
+       i_stream_set_return_partial_line(ctx.cur_input->input, TRUE);
 prevfile:
-       while ((line = i_stream_read_next_line(input->input)) != NULL) {
-               input->linenum++;
+       while ((line = i_stream_read_next_line(ctx.cur_input->input)) != NULL) {
+               ctx.cur_input->linenum++;
 
                /* @UNSAFE: line is modified */
 
@@ -204,8 +358,8 @@ prevfile:
                        struct input_stack *tmp;
                        const char *path;
 
-                       path = fix_relative_path(line, input);
-                       for (tmp = input; tmp != NULL; tmp = tmp->prev) {
+                       path = fix_relative_path(line, ctx.cur_input);
+                       for (tmp = ctx.cur_input; tmp != NULL; tmp = tmp->prev) {
                                if (strcmp(tmp->path, path) == 0)
                                        break;
                        }
@@ -213,9 +367,9 @@ prevfile:
                                errormsg = "Recursive include";
                        } else if ((fd = open(path, O_RDONLY)) != -1) {
                                new_input = t_new(struct input_stack, 1);
-                               new_input->prev = input;
+                               new_input->prev = ctx.cur_input;
                                new_input->path = t_strdup(path);
-                               input = new_input;
+                               ctx.cur_input = new_input;
                                goto newfile;
                        } else {
                                /* failed, but ignore failures with include_try. */
@@ -249,10 +403,10 @@ prevfile:
 
                                str_truncate(str, 0);
                                str_printfa(str, "auth/0/%s=%s", key + 5, line);
-                               errormsg = config_parse_line(key + 5, str_c(str), NULL);
+                               errormsg = config_parse_line(parsers, key + 5, str_c(str), NULL);
                                array_append(&auth_defaults, &s, 1);
                        } else {
-                               errormsg = config_parse_line(key, str_c(str), NULL);
+                               errormsg = config_parse_line(parsers, key, str_c(str), NULL);
                        }
                } else if (strcmp(key, "}") != 0 || *line != '\0') {
                        /* b) + errors */
@@ -274,26 +428,46 @@ prevfile:
 
                        if (*line != '{')
                                errormsg = "Expecting '='";
+
+                       config_add_new_filter(&ctx);
+                       ctx.cur_filter->pathlen = pathlen;
                        if (strcmp(key, "protocol") == 0) {
-                               array_append(&pathlen_stack, &pathlen, 1);
+                               ctx.cur_filter->filter.service =
+                                       p_strdup(ctx.pool, name);
+                               config_add_new_parser(&ctx);
+                               parsers = config_update_cur_parsers(&ctx);
+                       } else if (strcmp(key, "local_ip") == 0) {
+                               if (net_parse_range(name, &ctx.cur_filter->filter.local_net,
+                                                   &ctx.cur_filter->filter.local_bits) < 0)
+                                       errormsg = "Invalid network mask";
+                               config_add_new_parser(&ctx);
+                               parsers = config_update_cur_parsers(&ctx);
+                       } else if (strcmp(key, "remote_ip") == 0) {
+                               if (net_parse_range(name, &ctx.cur_filter->filter.remote_net,
+                                                   &ctx.cur_filter->filter.remote_bits) < 0)
+                                       errormsg = "Invalid network mask";
+                               config_add_new_parser(&ctx);
+                               parsers = config_update_cur_parsers(&ctx);
                        } else {
-                               array_append(&pathlen_stack, &pathlen, 1);
-
                                str_truncate(str, pathlen);
                                str_append(str, key);
                                pathlen = str_len(str);
 
-                               if (strcmp(key, "auth") == 0)
+                               if (strcmp(key, "auth") == 0) {
                                        cur_counter = auth_counter++;
-                               else
+                                       if (cur_counter == 0 && strcmp(name, "default") != 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(key, str_c(str), name);
+                                       errormsg = config_parse_line(parsers, key, str_c(str), name);
                                }
 
                                str_truncate(str, pathlen);
@@ -314,43 +488,39 @@ prevfile:
                                                p = strchr(lines[i], '=');
                                                str_append(str, lines[i]);
 
-                                               errormsg = config_parse_line(t_strdup_until(lines[i], p), str_c(str), NULL);
+                                               errormsg = config_parse_line(parsers, t_strdup_until(lines[i], p), str_c(str), NULL);
                                                i_assert(errormsg == NULL);
                                        }
                                }
                        }
                } else {
                        /* c) */
-                       unsigned int pathlen_count;
-                       const unsigned int *arr;
-
-                       arr = array_get(&pathlen_stack, &pathlen_count);
-                       if (pathlen_count == 0)
+                       if (ctx.cur_filter->prev == NULL)
                                errormsg = "Unexpected '}'";
                        else {
-                               pathlen = arr[pathlen_count - 1];
-                               array_delete(&pathlen_stack,
-                                            pathlen_count - 1, 1);
+                               pathlen = ctx.cur_filter->pathlen;
+                               ctx.cur_filter = ctx.cur_filter->prev;
+                               parsers = config_update_cur_parsers(&ctx);
                        }
                }
 
                if (errormsg != NULL) {
                        i_fatal("Error in configuration file %s line %d: %s",
-                               input->path, input->linenum, errormsg);
+                               ctx.cur_input->path, ctx.cur_input->linenum,
+                               errormsg);
                        break;
                }
                str_truncate(full_line, 0);
        }
 
-       i_stream_destroy(&input->input);
-       input = input->prev;
-       if (line == NULL && input != NULL)
+       i_stream_destroy(&ctx.cur_input->input);
+       ctx.cur_input = ctx.cur_input->prev;
+       if (line == NULL && ctx.cur_input != NULL)
                goto prevfile;
 
-       for (l = config_setting_parsers; l->module_name != NULL; l++) {
-               if (!settings_parser_check(l->parser, pool, &errormsg)) {
-                       i_fatal("Error in configuration file %s: %s",
-                               path, errormsg);
-               }
-       }
+       config_all_parsers_check(&ctx);
+
+       (void)array_append_space(&ctx.all_parsers);
+       config_filter = config_filter_init(ctx.pool);
+       config_filter_add_all(config_filter, array_idx(&ctx.all_parsers, 0));
 }
index f90b3929c3365a5e917ed2c71f2bff34999c32ba..f4b154204a1f69e7c0810d3deb67f9b77d3ad9e7 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef CONFIG_PARSER_H
 #define CONFIG_PARSER_H
 
+extern struct config_filter_context *config_filter;
+
 void config_parse_file(const char *path);
 
 #endif
index d25db084f385767f32c241bf4c0655469658dd93..954d62c190659528785d91175b3280cef1b6acb1 100644 (file)
@@ -8,6 +8,7 @@
 #include "settings-parser.h"
 #include "master-service-settings.h"
 #include "all-settings.h"
+#include "config-parser.h"
 #include "config-request.h"
 
 struct settings_export_context {
@@ -45,12 +46,12 @@ static bool parsers_are_connected(struct setting_parser_info *root,
 }
 
 static bool
-config_setting_parser_is_in_service(struct config_setting_parser_list *list,
-                                   const char *service)
+config_setting_parser_is_in_service(const struct config_setting_parser_list *list,
+                                   const char *module)
 {
        struct config_setting_parser_list *l;
 
-       if (strcmp(list->module_name, service) == 0)
+       if (strcmp(list->module_name, module) == 0)
                return TRUE;
        if (list->root == &master_service_setting_parser_info) {
                /* everyone wants master service settings */
@@ -58,7 +59,7 @@ config_setting_parser_is_in_service(struct config_setting_parser_list *list,
        }
 
        for (l = config_setting_parsers; l->module_name != NULL; l++) {
-               if (strcmp(l->module_name, service) != 0)
+               if (strcmp(l->module_name, module) != 0)
                        continue;
 
                /* see if we can find a way to get from the original parser
@@ -213,10 +214,11 @@ static void settings_export(struct settings_export_context *ctx,
        }
 }
 
-void config_request_handle(const char *service, enum config_dump_flags flags,
+void config_request_handle(const struct config_filter *filter,
+                          const char *module, enum config_dump_flags flags,
                           config_request_callback_t *callback, void *context)
 {
-       struct config_setting_parser_list *l;
+       const struct config_setting_parser_list *l;
        struct settings_export_context ctx;
 
        memset(&ctx, 0, sizeof(ctx));
@@ -229,9 +231,10 @@ void config_request_handle(const char *service, enum config_dump_flags flags,
        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 (*service == '\0' ||
-                   config_setting_parser_is_in_service(l, service)) {
+       l = config_filter_match_parsers(config_filter, filter);
+       for (; l->module_name != NULL; l++) {
+               if (*module == '\0' ||
+                   config_setting_parser_is_in_service(l, module)) {
                        settings_export(&ctx, l->root,
                                        settings_parser_get(l->parser));
                }
index 978fa3a518ba36a9e0063b1807305a9595d21bda..6e7a0e62ab8d99f43ec4b8009b3b6b4aaf79b783 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef CONFIG_REQUEST_H
 #define CONFIG_REQUEST_H
 
+#include "config-filter.h"
+
 enum config_dump_flags {
        CONFIG_DUMP_FLAG_DEFAULTS       = 0x01
 };
@@ -8,7 +10,8 @@ enum config_dump_flags {
 typedef void config_request_callback_t(const char *key, const char *value,
                                       bool list, void *context);
 
-void config_request_handle(const char *service, enum config_dump_flags flags,
+void config_request_handle(const struct config_filter *filter,
+                          const char *module, enum config_dump_flags flags,
                           config_request_callback_t *callback, void *context);
 
 #endif
index 202a9cb241e6b2df779a109dc10a912ab0009f09..42257c2157f2ad7098ce380e5970116238b89004 100644 (file)
@@ -65,7 +65,8 @@ static unsigned int prefix_stack_pop(ARRAY_TYPE(uint) *stack)
 }
 
 static void config_connection_request_human(struct ostream *output,
-                                           const char *service,
+                                           const struct config_filter *filter,
+                                           const char *module,
                                            enum config_dump_flags flags)
 {
        static const char *ident_str = "               ";
@@ -79,7 +80,8 @@ static void config_connection_request_human(struct ostream *output,
 
        ctx.pool = pool_alloconly_create("config human strings", 10240);
        i_array_init(&ctx.strings, 256);
-       config_request_handle(service, flags, config_request_get_strings, &ctx);
+       config_request_handle(filter, module, flags,
+                             config_request_get_strings, &ctx);
 
        strings = array_get_modifiable(&ctx.strings, &count);
        qsort(strings, count, sizeof(*strings), config_string_cmp);
@@ -158,13 +160,15 @@ static void config_connection_request_human(struct ostream *output,
        pool_unref(&ctx.pool);
 }
 
-static void config_dump_human(const char *service, enum config_dump_flags flags)
+static void config_dump_human(const struct config_filter *filter,
+                             const char *module,
+                             enum config_dump_flags flags)
 {
        struct ostream *output;
 
        output = o_stream_create_fd(STDOUT_FILENO, 0, FALSE);
        o_stream_cork(output);
-       config_connection_request_human(output, service, flags);
+       config_connection_request_human(output, filter, module, flags);
        o_stream_uncork(output);
 }
 
@@ -202,25 +206,30 @@ static const char *get_mail_location(void)
 int main(int argc, char *argv[])
 {
        enum config_dump_flags flags = CONFIG_DUMP_FLAG_DEFAULTS;
-       const char *getopt_str, *config_path, *service_name = "";
+       const char *getopt_str, *config_path, *module = "";
+       struct config_filter filter;
        char **exec_args = NULL;
        int c;
 
+       memset(&filter, 0, sizeof(filter));
        service = master_service_init("config", MASTER_SERVICE_FLAG_STANDALONE,
                                      argc, argv);
        i_set_failure_prefix("doveconf: ");
-       getopt_str = t_strconcat("anp:e", master_service_getopt_string(), NULL);
+       getopt_str = t_strconcat("am:np:e", master_service_getopt_string(), NULL);
        while ((c = getopt(argc, argv, getopt_str)) > 0) {
                if (c == 'e')
                        break;
                switch (c) {
                case 'a':
                        break;
+               case 'm':
+                       module = optarg;
+                       break;
                case 'n':
                        flags &= ~CONFIG_DUMP_FLAG_DEFAULTS;
                        break;
                case 'p':
-                       service_name = optarg;
+                       filter.service = optarg;
                        break;
                default:
                        if (!master_service_parse_option(service, c, optarg))
@@ -248,10 +257,10 @@ int main(int argc, char *argv[])
                if (*info != '\0')
                        printf("# %s\n", info);
                fflush(stdout);
-               config_dump_human(service_name, flags);
+               config_dump_human(&filter, module, flags);
        } else {
                env_put("DOVECONF_ENV=1");
-               config_request_handle(service_name, 0,
+               config_request_handle(&filter, module, 0,
                                      config_request_putenv, NULL);
                execvp(exec_args[0], exec_args);
                i_fatal("execvp(%s) failed: %m", exec_args[0]);
index 60df1238bec51cd786354c9725b82cee1fa6caa8..69246c660de33d1dec6e281d828a09f6e23f3957 100644 (file)
@@ -186,6 +186,8 @@ int main(int argc, char *argv[], char *envp[])
        }
 
        memset(&input, 0, sizeof(input));
+       input.module = "imap";
+       input.service = "imap";
        input.username = getenv("USER");
        if (input.username == NULL) {
                if (IS_STANDALONE())
index 060311146aeeecb270b91fa381642b35875de736..bcc1f3ef667d7739e485ddb7bff74b948aa8aa40 100644 (file)
@@ -315,6 +315,8 @@ int main(int argc, char *argv[])
        }
 
        memset(&service_input, 0, sizeof(service_input));
+       service_input.module = "lda";
+       service_input.service = "lda";
        service_input.username = user;
 
        service_flags |= MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT;
index 98f7da5dad05b93a510a005956c483b20f3c399f..a234ebed94b79a7409a81bf39121756cf8a4f0ca 100644 (file)
@@ -124,8 +124,11 @@ master_service_read_config(struct master_service *service,
                string_t *str;
 
                str = t_str_new(128);
-               str_append(str, CONFIG_HANDSHAKE);
-               str_printfa(str, "REQ\tservice=%s", service->name);
+               str_append(str, CONFIG_HANDSHAKE"REQ");
+               if (input->module != NULL)
+                       str_printfa(str, "\tmodule=%s", input->module);
+               if (input->service != NULL)
+                       str_printfa(str, "\tservice=%s", input->service);
                if (input->username != NULL)
                        str_printfa(str, "\tuser=%s", input->username);
                if (input->local_ip.family != 0) {
@@ -269,6 +272,7 @@ int master_service_settings_read_simple(struct master_service *service,
 
        memset(&input, 0, sizeof(input));
        input.roots = roots;
+       input.module = service->name;
        return master_service_settings_read(service, &input, error_r);
 }
 
index c253a49a5c44be5e5ef38251c736093e3a7b93e7..2c9c6853ea9835fc218cfa43976ab1628dc6f750 100644 (file)
@@ -20,6 +20,8 @@ struct master_service_settings_input {
        const struct dynamic_settings_parser *dyn_parsers;
        bool preserve_home;
 
+       const char *module;
+       const char *service;
        const char *username;
        struct ip_addr local_ip, remote_ip;
 };
index 7429455e9d17f0f5cfe1f5cb5ff7ba6d63799e38..3b844176673a7260be0cdda725f06a90bc8d4eec 100644 (file)
@@ -334,6 +334,8 @@ mail_storage_service_init_settings(struct master_service *service,
        set_input.dyn_parsers = mail_storage_get_dynamic_parsers();
        set_input.preserve_home = preserve_home;
        if (input != NULL) {
+               set_input.module = input->module;
+               set_input.service = input->service;
                set_input.username = input->username;
                set_input.local_ip = input->local_ip;
                set_input.remote_ip = input->remote_ip;
index 4933f5c1778e8ee3ca4ed0907bd4c8c5426bfc99..ab95130caf84b8de2f9b70baf2d6708ff60660e2 100644 (file)
@@ -17,6 +17,8 @@ enum mail_storage_service_flags {
 };
 
 struct mail_storage_service_input {
+       const char *module;
+       const char *service;
        const char *username;
        struct ip_addr local_ip, remote_ip;
 };
index 559f2b4edd3f685c41df9da81b3e8942cdff95a3..ecfb9109fcec7ced05e06900d118feb3fa7387c4 100644 (file)
@@ -1,6 +1,6 @@
 /* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
 
-#include "lib.h"
+#include "common.h"
 #include "settings-parser.h"
 #include "master-service-settings.h"
 #include "login-settings.h"
@@ -178,11 +178,16 @@ struct login_settings *login_settings_read(struct master_service *service)
                &login_setting_parser_info,
                NULL
        };
+       struct master_service_settings_input input;
        const char *error;
        void **sets;
 
-       if (master_service_settings_read_simple(service, set_roots,
-                                               &error) < 0)
+       memset(&input, 0, sizeof(input));
+       input.roots = set_roots;
+       input.module = "login";
+       input.service = login_protocol;
+
+       if (master_service_settings_read(service, &input, &error) < 0)
                i_fatal("Error reading configuration: %s", error);
 
        sets = master_service_settings_get_others(service);
index acd2f2c649fabce40f981381e1d203905ca488c3..76ccb3153a71450f15bb670e8a7e961662d95199 100644 (file)
@@ -112,6 +112,8 @@ int main(int argc, char *argv[], char *envp[])
        }
 
        memset(&input, 0, sizeof(input));
+       input.module = "pop3";
+       input.service = "pop3";
        input.username = getenv("USER");
        if (input.username == NULL) {
                if (IS_STANDALONE())