]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveconf: With -p only protocol-specific settings are returned. -n and -a return...
authorTimo Sirainen <tss@iki.fi>
Thu, 30 Apr 2009 19:02:44 +0000 (15:02 -0400)
committerTimo Sirainen <tss@iki.fi>
Thu, 30 Apr 2009 19:02:44 +0000 (15:02 -0400)
--HG--
branch : HEAD

14 files changed:
src/config/Makefile.am
src/config/common.h [deleted file]
src/config/config-connection.c
src/config/config-connection.h
src/config/config-parser.c
src/config/config-parser.h
src/config/config-request.c [new file with mode: 0644]
src/config/config-request.h [new file with mode: 0644]
src/config/main.c
src/config/settings-get.pl
src/imap/imap-settings.c
src/lib-lda/lda-settings.c
src/lib-settings/settings-parser.h
src/pop3/pop3-settings.c

index 4b5f94218c7bcf9bc2171a60c7194fc110e0f332..0aa0686935dc53da3b0e544d4be0b9ac51fa48d9 100644 (file)
@@ -22,11 +22,11 @@ doveconf_SOURCES = \
        all-settings.c \
        config-connection.c \
        config-parser.c \
+       config-request.c \
        main.c
 
 noinst_HEADERS = \
        all-settings.h \
-       common.h \
        config-connection.h \
        config-parser.h
 
diff --git a/src/config/common.h b/src/config/common.h
deleted file mode 100644 (file)
index 3af205f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef COMMON_H
-#define COMMON_H
-
-#include "lib.h"
-
-extern ARRAY_TYPE(const_string) config_strings;
-
-#endif
index a9fc4e62889a5c01eb73fe67e27d7d278dbc71ae..b823f4a590d2968c08e35d49339c5ddee9d82a6e 100644 (file)
@@ -1,19 +1,18 @@
 /* Copyright (C) 2005-2009 Dovecot authors, see the included COPYING file */
 
-#include "common.h"
+#include "lib.h"
 #include "array.h"
-#include "str.h"
 #include "llist.h"
 #include "ioloop.h"
 #include "network.h"
 #include "istream.h"
 #include "ostream.h"
 #include "env-util.h"
+#include "config-request.h"
 #include "config-connection.h"
 
 #include <stdlib.h>
 #include <unistd.h>
-#include <fcntl.h>
 
 #define MAX_INBUF_SIZE 1024
 
@@ -46,24 +45,176 @@ config_connection_next_line(struct config_connection *conn)
        return t_strsplit(line, "\t");
 }
 
+static void
+config_request_output(const char *key, const char *value,
+                     bool list ATTR_UNUSED, void *context)
+{
+       struct ostream *output = context;
+
+       o_stream_send_str(output, key);
+       o_stream_send_str(output, "=");
+       o_stream_send_str(output, value);
+       o_stream_send_str(output, "\n");
+}
+
+struct config_request_get_string_ctx {
+       pool_t pool;
+       ARRAY_TYPE(const_string) strings;
+};
+
+static void
+config_request_get_strings(const char *key, const char *value,
+                          bool list, void *context)
+{
+       struct config_request_get_string_ctx *ctx = context;
+
+       value = p_strdup_printf(ctx->pool, list ? "-%s=%s" : "%s=%s",
+                               key, value);
+       array_append(&ctx->strings, &value, 1);
+}
+
+static int config_string_cmp(const void *p1, const void *p2)
+{
+       const char *s1 = *(const char *const *)p1;
+       const char *s2 = *(const char *const *)p2;
+       unsigned int i = 0;
+
+       while (s1[i] == s2[i]) {
+               if (s1[i] == '\0' || s1[i] == '=')
+                       return 0;
+               i++;
+       }
+
+       if (s1[i] == '=')
+               return -1;
+       if (s2[i] == '=')
+               return 1;
+       return s1[i] - s2[i];
+}
+
+static unsigned int prefix_stack_pop(ARRAY_TYPE(uint) *stack)
+{
+       const unsigned int *indexes;
+       unsigned int idx, count;
+
+       indexes = array_get(stack, &count);
+       idx = count <= 1 ? -1U : indexes[count-2];
+       array_delete(stack, count-1, 1);
+       return idx;
+}
+
+static void config_connection_request_human(struct ostream *output,
+                                           const char *service,
+                                           enum config_dump_flags flags)
+{
+       static const char *ident_str = "               ";
+       ARRAY_TYPE(const_string) prefixes_arr;
+       ARRAY_TYPE(uint) prefix_idx_stack;
+       struct config_request_get_string_ctx ctx;
+       const char **strings, *const *args, *p, *str, *const *prefixes;
+       const char *key, *value;
+       unsigned int i, j, count, len, prefix_count, skip_len;
+       unsigned int indent = 0, prefix_idx = -1U;
+
+       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);
+
+       strings = array_get_modifiable(&ctx.strings, &count);
+       qsort(strings, count, sizeof(*strings), config_string_cmp);
+
+       p_array_init(&prefixes_arr, ctx.pool, 32);
+       for (i = 0; i < count && strings[i][0] == '-'; i++) T_BEGIN {
+               p = strchr(strings[i], '=');
+               i_assert(p != NULL);
+               for (args = t_strsplit(p + 1, " "); *args != NULL; args++) {
+                       str = p_strdup_printf(ctx.pool, "%s/%s/",
+                                             t_strcut(strings[i]+1, '='),
+                                             *args);
+                       array_append(&prefixes_arr, &str, 1);
+               }
+       } T_END;
+       prefixes = array_get(&prefixes_arr, &prefix_count);
+
+       p_array_init(&prefix_idx_stack, ctx.pool, 8);
+       for (; i < count; i++) T_BEGIN {
+               value = strchr(strings[i], '=');
+               i_assert(value != NULL);
+               key = t_strdup_until(strings[i], value);
+               value++;
+
+               j = 0;
+               while (prefix_idx != -1U) {
+                       len = strlen(prefixes[prefix_idx]);
+                       if (strncmp(prefixes[prefix_idx], key, len) != 0) {
+                               prefix_idx = prefix_stack_pop(&prefix_idx_stack);
+                               indent--;
+                               o_stream_send(output, ident_str, indent*2);
+                               o_stream_send_str(output, "}\n");
+                       } else if (strchr(key + len, '/') == NULL) {
+                               /* keep the prefix */
+                               j = prefix_count;
+                               break;
+                       } else {
+                               /* subprefix */
+                               break;
+                       }
+               }
+               for (; j < prefix_count; j++) {
+                       len = strlen(prefixes[j]);
+                       if (strncmp(prefixes[j], key, len) == 0 &&
+                           strchr(key + len, '/') == NULL) {
+                               key += prefix_idx == -1U ? 0 :
+                                       strlen(prefixes[prefix_idx]);
+                               o_stream_send(output, ident_str, indent*2);
+                               o_stream_send_str(output, t_strcut(key, '/'));
+                               o_stream_send_str(output, " {\n");
+                               indent++;
+                               prefix_idx = j;
+                               array_append(&prefix_idx_stack, &prefix_idx, 1);
+                               break;
+                       }
+               }
+               skip_len = prefix_idx == -1U ? 0 : strlen(prefixes[prefix_idx]);
+               i_assert(strncmp(prefixes[prefix_idx], strings[i], skip_len) == 0);
+               o_stream_send(output, ident_str, indent*2);
+               key = strings[i] + skip_len;
+               value = strchr(key, '=');
+               o_stream_send(output, key, value-key);
+               o_stream_send_str(output, " = ");
+               o_stream_send_str(output, value+1);
+               o_stream_send(output, "\n", 1);
+       } T_END;
+
+       while (prefix_idx != -1U) {
+               prefix_idx = prefix_stack_pop(&prefix_idx_stack);
+               indent--;
+               o_stream_send(output, ident_str, indent*2);
+               o_stream_send_str(output, "}\n");
+       }
+
+       array_free(&ctx.strings);
+       pool_unref(&ctx.pool);
+}
+
 static void config_connection_request(struct config_connection *conn,
                                      const char *const *args,
                                      enum config_dump_flags flags)
 {
-       const char *const *strings;
-       unsigned int i, count;
-       string_t *str;
+       const char *service = "";
+
+       /* [<service> [<args>]] */
+       if (args[0] != NULL)
+               service = args[0];
 
-       /* <process> [<args>] */
-       str = t_str_new(256);
-       strings = array_get(&config_strings, &count);
        o_stream_cork(conn->output);
-       for (i = 0; i < count; i += 2) {
-               str_truncate(str, 0);
-               str_printfa(str, "%s=%s\n", strings[i], strings[i+1]);
-               o_stream_send(conn->output, str_data(str), str_len(str));
+       if ((flags & CONFIG_DUMP_FLAG_HUMAN) == 0) {
+               config_request_handle(service, flags, config_request_output,
+                                     conn->output);
+               o_stream_send_str(conn->output, "\n");
+       } else {
+               config_connection_request_human(conn->output, service, flags);
        }
-       o_stream_send_str(conn->output, "\n");
        o_stream_uncork(conn->output);
 }
 
@@ -138,22 +289,24 @@ void config_connection_dump_request(int fd, const char *service,
        const char *args[2] = { service, NULL };
 
        conn = config_connection_create(fd);
-        config_connection_request(conn, args, flags);
+       config_connection_request(conn, args, flags);
        config_connection_destroy(conn);
 }
 
-void config_connection_putenv(void)
+static void config_request_putenv(const char *key, const char *value,
+                                 bool list ATTR_UNUSED,
+                                 void *context ATTR_UNUSED)
 {
-       const char *const *strings;
-       unsigned int i, count;
-
-       strings = array_get(&config_strings, &count);
-       for (i = 0; i < count; i += 2) T_BEGIN {
-               env_put(t_strconcat(t_str_ucase(strings[i]), "=",
-                                   strings[i+1], NULL));
+       T_BEGIN {
+               env_put(t_strconcat(t_str_ucase(key), "=", value, NULL));
        } T_END;
 }
 
+void config_connection_putenv(const char *service)
+{
+       config_request_handle(service, 0, config_request_putenv, NULL);
+}
+
 void config_connections_destroy_all(void)
 {
        while (config_connections != NULL)
index ba3911891a5747a88621e01f28851bf479ba193c..b20d214682e44bc88d3c94ccf9bd98f73c0ec242 100644 (file)
@@ -1,17 +1,14 @@
 #ifndef CONFIG_CONNECTION_H
 #define CONFIG_CONNECTION_H
 
-enum config_dump_flags {
-       CONFIG_DUMP_FLAG_HUMAN          = 0x01,
-       CONFIG_DUMP_FLAG_DEFAULTS       = 0x02
-};
+enum config_dump_flags;
 
 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,
                                    enum config_dump_flags flags);
-void config_connection_putenv(void);
+void config_connection_putenv(const char *service);
 
 void config_connections_destroy_all(void);
 
index 594a6528a585c5a860999f8dee5d6c5025674afe..95e162c9b86d8f989ef5183f55af0f0624aa6131 100644 (file)
@@ -24,22 +24,15 @@ struct input_stack {
 };
 
 static const char *
-config_parse_line(pool_t pool, const char *key, const char *line,
+config_parse_line(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;
@@ -51,189 +44,6 @@ config_parse_line(pool_t pool, const char *key, const char *line,
        return found ? NULL : t_strconcat("Unknown setting: ", key, NULL);
 }
 
-struct settings_export_context {
-       pool_t pool;
-       ARRAY_TYPE(const_string) *dest;
-       string_t *value;
-       string_t *prefix;
-       struct hash_table *keys;
-       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;
-       const char *str;
-       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;
-                       const char *const *strings;
-
-                       if (!array_is_created(val))
-                               break;
-
-                       key = p_strconcat(ctx->pool, str_c(ctx->prefix),
-                                         def->key, NULL);
-
-                       if (hash_table_lookup(ctx->keys, key) != NULL) {
-                               /* already added all of these */
-                               break;
-                       }
-                       hash_table_insert(ctx->keys, key, key);
-
-                       str = key;
-                       array_append(ctx->dest, &str, 1);
-                       str = "0";
-                       array_append(ctx->dest, &str, 1);
-
-                       strings = array_get(val, &count);
-                       i_assert(count % 2 == 0);
-                       for (i = 0; i < count; i += 2) {
-                               str = p_strdup_printf(ctx->pool, "%s%s%c0%c%s",
-                                                     str_c(ctx->prefix),
-                                                     def->key,
-                                                     SETTINGS_SEPARATOR,
-                                                     SETTINGS_SEPARATOR,
-                                                     strings[i]);
-                               array_append(ctx->dest, &str, 1);
-                               str = p_strdup(ctx->pool, strings[i+1]);
-                               array_append(ctx->dest, &str, 1);
-                       }
-                       count = 0;
-                       break;
-               }
-               }
-               if (str_len(ctx->value) > 0) {
-                       key = p_strconcat(ctx->pool, str_c(ctx->prefix),
-                                         def->key, NULL);
-                       if (hash_table_lookup(ctx->keys, key) == NULL) {
-                               str = key;
-                               array_append(ctx->dest, &str, 1);
-                               str = p_strdup(ctx->pool, str_c(ctx->value));
-                               array_append(ctx->dest, &str, 1);
-                               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(pool_t pool, ARRAY_TYPE(const_string) *dest)
-{
-       struct config_setting_parser_list *l;
-       struct settings_export_context ctx;
-       const void *set;
-
-       memset(&ctx, 0, sizeof(ctx));
-       ctx.pool = pool;
-       ctx.dest = dest;
-       ctx.export_defaults = FALSE;
-       ctx.value = t_str_new(256);
-       ctx.prefix = t_str_new(64);
-       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);
-}
-
 static const char *info_type_name_find(const struct setting_parser_info *info)
 {
        unsigned int i;
@@ -261,9 +71,10 @@ fix_relative_path(const char *path, struct input_stack *input)
        return t_strconcat(t_strdup_until(input->path, p+1), path, NULL);
 }
 
-void config_parse_file(pool_t dest_pool, ARRAY_TYPE(const_string) *dest,
-                      const char *path, const char *service)
+void config_parse_file(const char *path, const char *service)
 {
+       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);
        ARRAY_TYPE(const_string) auth_defaults;
@@ -287,7 +98,12 @@ void config_parse_file(pool_t dest_pool, ARRAY_TYPE(const_string) *dest,
        t_array_init(&pathlen_stack, 10);
        t_array_init(&auth_defaults, 32);
 
-       errormsg = config_parse_line(pool, "0", "auth=0", &info);
+       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);
+       }
+
+       errormsg = config_parse_line("0", "auth=0", &info);
        i_assert(errormsg == NULL);
 
        memset(&root, 0, sizeof(root));
@@ -411,10 +227,10 @@ prevfile:
 
                                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);
+                               errormsg = config_parse_line(key + 5, str_c(str), &info);
                                array_append(&auth_defaults, &s, 1);
                        } else {
-                               errormsg = config_parse_line(pool, key, str_c(str), &info);
+                               errormsg = config_parse_line(key, str_c(str), &info);
                        }
                } else if (strcmp(key, "}") != 0 || *line != '\0') {
                        /* b) + errors */
@@ -458,7 +274,7 @@ prevfile:
                                if (cur_counter == 0 && strcmp(key, "auth") == 0) {
                                        /* already added this */
                                } else {
-                                       errormsg = config_parse_line(pool, key,
+                                       errormsg = config_parse_line(key,
                                                                     str_c(str), &info);
                                }
 
@@ -473,7 +289,7 @@ prevfile:
                                        str_append(str, type_name);
                                        str_append_c(str, '=');
                                        str_append(str, name);
-                                       errormsg = config_parse_line(pool, type_name,
+                                       errormsg = config_parse_line(type_name,
                                                                     str_c(str), &info);
 
                                        str_truncate(str, pathlen);
@@ -491,7 +307,7 @@ prevfile:
                                                p = strchr(lines[i], '=');
                                                str_append(str, lines[i]);
 
-                                               errormsg = config_parse_line(pool, t_strdup_until(lines[i], p), str_c(str), &info);
+                                               errormsg = config_parse_line(t_strdup_until(lines[i], p), str_c(str), &info);
                                                i_assert(errormsg == NULL);
                                        }
                                }
@@ -528,14 +344,9 @@ prevfile:
                goto prevfile;
 
        for (l = config_setting_parsers; l->module_name != NULL; l++) {
-               if (l->parser == NULL)
-                       continue;
-
                if (!settings_parser_check(l->parser, pool, &errormsg)) {
                        i_fatal("Error in configuration file %s: %s",
                                path, errormsg);
                }
        }
-
-       config_export(dest_pool, dest);
 }
index db088050ced58925a1d89f1b49d8b6bad40758fe..25ab580d2e3b5d789bd5f7faa92559f26c40476f 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef CONFIG_PARSER_H
 #define CONFIG_PARSER_H
 
-void config_parse_file(pool_t dest_pool, ARRAY_TYPE(const_string) *dest,
-                      const char *path, const char *service);
+void config_parse_file(const char *path, const char *service);
 
 #endif
diff --git a/src/config/config-request.c b/src/config/config-request.c
new file mode 100644 (file)
index 0000000..056974b
--- /dev/null
@@ -0,0 +1,236 @@
+/* Copyright (C) 2005-2009 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "hash.h"
+#include "ostream.h"
+#include "settings-parser.h"
+#include "all-settings.h"
+#include "config-request.h"
+
+struct settings_export_context {
+       pool_t pool;
+       string_t *value;
+       string_t *prefix;
+       struct hash_table *keys;
+       bool export_defaults;
+
+       config_request_callback_t *callback;
+       void *context;
+};
+
+static bool parsers_are_connected(struct setting_parser_info *root,
+                                 struct setting_parser_info *info)
+{
+       struct setting_parser_info *const *dep, *p;
+
+       /* we're trying to find info or its parents from root's dependencies. */
+
+       for (p = info; p != NULL; p = p->parent) {
+               if (p == root)
+                       return TRUE;
+       }
+
+       if (root->dependencies != NULL) {
+               for (dep = root->dependencies; *dep != NULL; dep++) {
+                       for (p = info; p != NULL; p = p->parent) {
+                               if (p == *dep)
+                                       return TRUE;
+                       }
+               }
+       }
+       return FALSE;
+}
+
+static bool
+config_setting_parser_is_in_service(struct config_setting_parser_list *list,
+                                   const char *service)
+{
+       struct config_setting_parser_list *l;
+
+       if (strcmp(list->module_name, service) == 0)
+               return TRUE;
+
+       for (l = config_setting_parsers; l->module_name != NULL; l++) {
+               if (strcmp(l->module_name, service) != 0)
+                       continue;
+
+               /* see if we can find a way to get from the original parser
+                  to this parser */
+               if (parsers_are_connected(l->root, list->root))
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+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;
+       const char *str;
+       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;
+                       const char *const *strings;
+
+                       if (!array_is_created(val))
+                               break;
+
+                       key = p_strconcat(ctx->pool, str_c(ctx->prefix),
+                                         def->key, NULL);
+
+                       if (hash_table_lookup(ctx->keys, key) != NULL) {
+                               /* already added all of these */
+                               break;
+                       }
+                       hash_table_insert(ctx->keys, key, key);
+                       ctx->callback(key, "0", TRUE, ctx->context);
+
+                       strings = array_get(val, &count);
+                       i_assert(count % 2 == 0);
+                       for (i = 0; i < count; i += 2) {
+                               str = p_strdup_printf(ctx->pool, "%s%s%c0%c%s",
+                                                     str_c(ctx->prefix),
+                                                     def->key,
+                                                     SETTINGS_SEPARATOR,
+                                                     SETTINGS_SEPARATOR,
+                                                     strings[i]);
+                               ctx->callback(str, strings[i+1], FALSE,
+                                             ctx->context);
+                       }
+                       count = 0;
+                       break;
+               }
+               }
+               if (str_len(ctx->value) > 0) {
+                       key = p_strconcat(ctx->pool, str_c(ctx->prefix),
+                                         def->key, NULL);
+                       if (hash_table_lookup(ctx->keys, key) == NULL) {
+                               ctx->callback(key, str_c(ctx->value),
+                                             def->type == SET_DEFLIST,
+                                             ctx->context);
+                               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);
+               }
+       }
+}
+
+void config_request_handle(const char *service, enum config_dump_flags flags,
+                          config_request_callback_t *callback, void *context)
+{
+       struct config_setting_parser_list *l;
+       struct settings_export_context ctx;
+
+       memset(&ctx, 0, sizeof(ctx));
+       ctx.pool = pool_alloconly_create("config request", 10240);
+       ctx.callback = callback;
+       ctx.context = context;
+       ctx.export_defaults = (flags & CONFIG_DUMP_FLAG_DEFAULTS) != 0;
+       ctx.value = t_str_new(256);
+       ctx.prefix = t_str_new(64);
+       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)) {
+                       settings_export(&ctx, l->root,
+                                       settings_parser_get(l->parser));
+               }
+       }
+       hash_table_destroy(&ctx.keys);
+       pool_unref(&ctx.pool);
+}
diff --git a/src/config/config-request.h b/src/config/config-request.h
new file mode 100644 (file)
index 0000000..73f4ab1
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef CONFIG_REQUEST_H
+#define CONFIG_REQUEST_H
+
+enum config_dump_flags {
+       CONFIG_DUMP_FLAG_HUMAN          = 0x01,
+       CONFIG_DUMP_FLAG_DEFAULTS       = 0x02
+};
+
+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,
+                          config_request_callback_t *callback, void *context);
+
+#endif
index da4cff525c5b4ed719f9f1732da318407ce8dc7a..61afd122447fb31e63ea0362ad9b32a261a466d4 100644 (file)
@@ -1,26 +1,21 @@
 /* Copyright (C) 2005-2009 Dovecot authors, see the included COPYING file */
 
-#include "common.h"
+#include "lib.h"
 #include "array.h"
 #include "env-util.h"
 #include "master-service.h"
 #include "config-connection.h"
 #include "config-parser.h"
+#include "config-request.h"
 
 #include <stdlib.h>
 #include <unistd.h>
 
-ARRAY_TYPE(const_string) config_strings;
-
 static struct master_service *service;
-static pool_t config_pool;
 
 static void main_init(const char *service_name)
 {
-       config_pool = pool_alloconly_create("config parser", 10240);
-       p_array_init(&config_strings, config_pool, 256);
-       config_parse_file(config_pool, &config_strings,
-                         master_service_get_config_path(service),
+       config_parse_file(master_service_get_config_path(service),
                          service_name);
 }
 
@@ -67,16 +62,16 @@ int main(int argc, char *argv[])
 
        if (master_service_get_socket_count(service) > 0)
                master_service_run(service, client_connected);
-       else if (exec_args == NULL)
-               config_connection_dump_request(STDOUT_FILENO, "master", flags);
-       else {
-               config_connection_putenv();
+       else if (exec_args == NULL) {
+               config_connection_dump_request(STDOUT_FILENO,
+                                              service_name, flags);
+       } else {
+               config_connection_putenv(service_name);
                env_put("DOVECONF_ENV=1");
                execvp(exec_args[0], exec_args);
                i_fatal("execvp(%s) failed: %m", exec_args[0]);
        }
        config_connections_destroy_all();
-       pool_unref(&config_pool);
        master_service_deinit(&service);
         return 0;
 }
index 7dbcdf125e0b891f33363435a7f7f68bf087ba01..c98c9c6ba11a0407d71553b47e207c4a4f5adc38 100755 (executable)
@@ -31,7 +31,8 @@ foreach my $file (@ARGV) {
        $state++;
       } elsif (/^(static )?struct setting_parser_info (.*) = {/) {
        $state++;
-       $parsers{$2} = 1;
+       my $name = $2;
+       $parsers{$name} = 1 if ($name !~ /\*/);
       } elsif (/^extern struct setting_parser_info (.*);/) {
        $externs .= "extern struct setting_parser_info $1;\n";
       } elsif (/\/\* <settings checks> \*\//) {
index 3710f85cf974b4acc02fab7cfeb7b492e7cdfa84..f0bbf4ea2786d423ab4ea70f6aa5fe32a98e2eaa 100644 (file)
@@ -49,6 +49,11 @@ static struct imap_settings imap_default_settings = {
        MEMBER(imap_id_log) ""
 };
 
+static struct setting_parser_info *imap_setting_dependencies[] = {
+       &mail_user_setting_parser_info,
+       NULL
+};
+
 struct setting_parser_info imap_setting_parser_info = {
        MEMBER(defines) imap_setting_defines,
        MEMBER(defaults) &imap_default_settings,
@@ -59,5 +64,6 @@ struct setting_parser_info imap_setting_parser_info = {
        MEMBER(parent_offset) (size_t)-1,
        MEMBER(type_offset) (size_t)-1,
        MEMBER(struct_size) sizeof(struct imap_settings),
-       MEMBER(check_func) NULL
+       MEMBER(check_func) NULL,
+       MEMBER(dependencies) imap_setting_dependencies
 };
index 460d6207a771d2bd314b26411695ec2653e92aec..a5bbbcd43a39d30287f10b1985f5cc0472ab70bc 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "settings-parser.h"
+#include "mail-storage-settings.h"
 #include "lda-settings.h"
 
 #include <stddef.h>
@@ -42,6 +43,11 @@ static struct lda_settings lda_default_settings = {
        MEMBER(lda_mailbox_autosubscribe) FALSE
 };
 
+static struct setting_parser_info *lda_setting_dependencies[] = {
+       &mail_user_setting_parser_info,
+       NULL
+};
+
 struct setting_parser_info lda_setting_parser_info = {
        MEMBER(defines) lda_setting_defines,
        MEMBER(defaults) &lda_default_settings,
@@ -53,10 +59,11 @@ struct setting_parser_info lda_setting_parser_info = {
        MEMBER(type_offset) (size_t)-1,
        MEMBER(struct_size) sizeof(struct lda_settings),
 #ifdef CONFIG_BINARY
-       MEMBER(check_func) NULL
+       MEMBER(check_func) NULL,
 #else
-       MEMBER(check_func) lda_settings_check
+       MEMBER(check_func) lda_settings_check,
 #endif
+       MEMBER(dependencies) lda_setting_dependencies
 };
 
 static bool lda_settings_check(void *_set, pool_t pool ATTR_UNUSED,
index d3dd663c8eb0af03103331831b18f761cad4d497..e7e732fe33206367ba6c8e1a1d70102d269d41b4 100644 (file)
@@ -58,6 +58,8 @@ struct setting_parser_info {
        size_t type_offset;
        size_t struct_size;
        bool (*check_func)(void *set, pool_t pool, const char **error_r);
+       struct setting_parser_info *const *dependencies;
+
 };
 ARRAY_DEFINE_TYPE(setting_parser_info, struct setting_parser_info);
 
index a273fe3e43c05590f9be12bdecfed2d2b4198d7a..d16d69236ff616cb90aa740c03f2f9d9913fe3d4 100644 (file)
@@ -44,6 +44,11 @@ static struct pop3_settings pop3_default_settings = {
        MEMBER(pop3_logout_format) "top=%t/%p, retr=%r/%b, del=%d/%m, size=%s"
 };
 
+static struct setting_parser_info *pop3_setting_dependencies[] = {
+       &mail_user_setting_parser_info,
+       NULL
+};
+
 struct setting_parser_info pop3_setting_parser_info = {
        MEMBER(defines) pop3_setting_defines,
        MEMBER(defaults) &pop3_default_settings,
@@ -54,5 +59,6 @@ struct setting_parser_info pop3_setting_parser_info = {
        MEMBER(parent_offset) (size_t)-1,
        MEMBER(type_offset) (size_t)-1,
        MEMBER(struct_size) sizeof(struct pop3_settings),
-       MEMBER(check_func) NULL
+       MEMBER(check_func) NULL,
+       MEMBER(dependencies) pop3_setting_dependencies
 };