dovecot-2.0: config: Several fixes. Now per-ip settings work pro...

dovecot at dovecot.org dovecot at dovecot.org
Thu Sep 3 23:36:52 EEST 2009


details:   http://hg.dovecot.org/dovecot-2.0/rev/f9ca1a1ebcf8
changeset: 9859:f9ca1a1ebcf8
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Sep 03 16:36:38 2009 -0400
description:
config: Several fixes. Now per-ip settings work properly.
doveconf parameters were also changed. Now it's possible to ask
configuration for a specified filter.

diffstat:

7 files changed, 320 insertions(+), 210 deletions(-)
src/config/config-connection.c |    7 
src/config/config-filter.c     |  129 ++++++++++++++---
src/config/config-filter.h     |   14 +
src/config/config-parser.c     |  288 +++++++++++++++++++---------------------
src/config/config-request.c    |   43 ++++-
src/config/config-request.h    |    7 
src/config/doveconf.c          |   42 ++++-

diffs (truncated from 812 to 300 lines):

diff -r 2e502c0e23e7 -r f9ca1a1ebcf8 src/config/config-connection.c
--- a/src/config/config-connection.c	Thu Sep 03 16:35:19 2009 -0400
+++ b/src/config/config-connection.c	Thu Sep 03 16:36:38 2009 -0400
@@ -102,8 +102,11 @@ static int config_connection_request(str
 	}
 
 	o_stream_cork(conn->output);
-	config_request_handle(&filter, module, 0, config_request_output,
-			      conn->output);
+	if (config_request_handle(&filter, module, CONFIG_DUMP_SCOPE_SET, FALSE,
+				  config_request_output, conn->output) < 0) {
+		config_connection_destroy(conn);
+		return -1;
+	}
 	o_stream_send_str(conn->output, "\n");
 	o_stream_uncork(conn->output);
 	return 0;
diff -r 2e502c0e23e7 -r f9ca1a1ebcf8 src/config/config-filter.c
--- a/src/config/config-filter.c	Thu Sep 03 16:35:19 2009 -0400
+++ b/src/config/config-filter.c	Thu Sep 03 16:36:38 2009 -0400
@@ -2,12 +2,13 @@
 
 #include "lib.h"
 #include "array.h"
+#include "settings-parser.h"
 #include "config-parser.h"
 #include "config-filter.h"
 
 struct config_filter_context {
 	pool_t pool;
-	struct config_filter_parser_list *const *parsers;
+	struct config_filter_parser *const *parsers;
 };
 
 bool config_filter_match(const struct config_filter *mask,
@@ -75,47 +76,123 @@ void config_filter_deinit(struct config_
 }
 
 void config_filter_add_all(struct config_filter_context *ctx,
-			   struct config_filter_parser_list *const *parsers)
+			   struct config_filter_parser *const *parsers)
 {
 	ctx->parsers = parsers;
 }
 
-static int filter_cmp(const struct config_filter *f1,
-		      const struct config_filter *f2)
+static int
+config_filter_parser_cmp(struct config_filter_parser *const *p1,
+			 struct config_filter_parser *const *p2)
 {
-	int ret;
+	const struct config_filter *f1 = &(*p1)->filter, *f2 = &(*p2)->filter;
 
-	ret = f2->remote_bits - f1->remote_bits;
-	if (ret != 0)
-		return ret;
+	/* remote_ip and local_ips are first, although it doesn't really
+	   matter which one comes first */
+	if (f1->local_bits > f2->local_bits)
+		return -1;
+	if (f1->local_bits < f2->local_bits)
+		return 1;
 
-	ret = f2->local_bits - f1->local_bits;
-	if (ret != 0)
-		return ret;
+	if (f1->remote_bits > f2->remote_bits)
+		return -1;
+	if (f1->remote_bits < f2->remote_bits)
+		return 1;
 
-	if (f1->service != NULL)
+	if (f1->service != NULL && f2->service == NULL)
 		return -1;
-	else
+	if (f1->service == NULL && f2->service != NULL)
 		return 1;
+	return 0;
 }
 
-const struct config_filter_parser_list *
-config_filter_find(struct config_filter_context *ctx,
-		   const struct config_filter *filter)
+static struct config_filter_parser *const *
+config_filter_find_all(struct config_filter_context *ctx,
+		       const struct config_filter *filter)
 {
-	struct config_filter_parser_list *best = NULL;
+	ARRAY_TYPE(config_filter_parsers) matches;
 	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. */
+	t_array_init(&matches, 8);
 	for (i = 0; ctx->parsers[i] != NULL; i++) {
-		if (!config_filter_match(&ctx->parsers[i]->filter, filter))
-			continue;
+		if (config_filter_match(&ctx->parsers[i]->filter, filter))
+			array_append(&matches, &ctx->parsers[i], 1);
+	}
+	array_sort(&matches, config_filter_parser_cmp);
+	(void)array_append_space(&matches);
+	return array_idx(&matches, 0);
+}
 
-		if (best == NULL ||
-		    filter_cmp(&best->filter, &ctx->parsers[i]->filter) > 0)
-			best = ctx->parsers[i];
+static bool
+config_filter_is_superset(const struct config_filter *sup,
+			  const struct config_filter *filter)
+{
+	/* assume that both of the filters match the same subset, so we don't
+	   need to compare IPs and service name. */
+	if (sup->local_bits < filter->local_bits)
+		return FALSE;
+	if (sup->remote_bits < filter->remote_bits)
+		return FALSE;
+	if (sup->service != NULL && filter->service == NULL)
+		return FALSE;
+	return TRUE;
+}
+
+static int
+config_module_parser_apply_changes(struct config_module_parser *dest,
+				   const struct config_filter_parser *src,
+				   pool_t pool, const char **error_r)
+{
+	unsigned int i;
+
+	for (i = 0; dest[i].module_name != NULL; i++) {
+		if (settings_parser_apply_changes(dest[i].parser,
+						  src->parsers[i].parser, pool,
+						  error_r) < 0) {
+			*error_r = t_strdup_printf("Conflict in setting %s",
+						   *error_r);
+			return -1;
+		}
 	}
-	return best;
+	return 0;
 }
+
+int config_filter_get_parsers(struct config_filter_context *ctx, pool_t pool,
+			      const struct config_filter *filter,
+			      const struct config_module_parser **parsers_r,
+			      const char **error_r)
+{
+	struct config_filter_parser *const *src;
+	struct config_module_parser *dest;
+	const char *error, **error_p;
+	unsigned int i, count;
+
+	src = config_filter_find_all(ctx, filter);
+
+	/* all of them should have the same number of parsers.
+	   duplicate our initial parsers from the first match */
+	for (count = 0; src[0]->parsers[count].module_name != NULL; count++) ;
+	dest = p_new(pool, struct config_module_parser, count + 1);
+	for (i = 0; i < count; i++) {
+		dest[i] = src[0]->parsers[i];
+		dest[i].parser =
+			settings_parser_dup(src[0]->parsers[i].parser, pool);
+	}
+
+	/* apply the changes from rest of the matches */
+	for (i = 1; src[i] != NULL; i++) {
+		if (config_filter_is_superset(&src[i-1]->filter,
+					      &src[i]->filter))
+			error_p = NULL;
+		else
+			error_p = &error;
+
+		if (config_module_parser_apply_changes(dest, src[i], pool,
+						       error_p) < 0) {
+			*error_r = error;
+			return -1;
+		}
+	}
+	*parsers_r = dest;
+	return 0;
+}
diff -r 2e502c0e23e7 -r f9ca1a1ebcf8 src/config/config-filter.h
--- a/src/config/config-filter.h	Thu Sep 03 16:35:19 2009 -0400
+++ b/src/config/config-filter.h	Thu Sep 03 16:36:38 2009 -0400
@@ -9,23 +9,25 @@ struct config_filter {
 	unsigned int local_bits, remote_bits;
 };
 
-struct config_filter_parser_list {
+struct config_filter_parser {
 	struct config_filter filter;
 	/* NULL-terminated array of parsers */
 	struct config_module_parser *parsers;
 };
+ARRAY_DEFINE_TYPE(config_filter_parsers, struct config_filter_parser *);
 
 struct config_filter_context *config_filter_init(pool_t pool);
 void config_filter_deinit(struct config_filter_context **ctx);
 
 /* Replace filter's parsers with given parser list. */
 void config_filter_add_all(struct config_filter_context *ctx,
-			   struct config_filter_parser_list *const *parsers);
+			   struct config_filter_parser *const *parsers);
 
-/* Find the filter that best matches what we have. */
-const struct config_filter_parser_list *
-config_filter_find(struct config_filter_context *ctx,
-		   const struct config_filter *filter);
+/* Build new parsers from all existing ones matching the given filter. */
+int config_filter_get_parsers(struct config_filter_context *ctx, pool_t pool,
+			      const struct config_filter *filter,
+			      const struct config_module_parser **parsers_r,
+			      const char **error_r);
 
 /* Returns TRUE if filter matches mask. */
 bool config_filter_match(const struct config_filter *mask,
diff -r 2e502c0e23e7 -r f9ca1a1ebcf8 src/config/config-parser.c
--- a/src/config/config-parser.c	Thu Sep 03 16:35:19 2009 -0400
+++ b/src/config/config-parser.c	Thu Sep 03 16:36:38 2009 -0400
@@ -23,9 +23,12 @@
 
 #define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
 
-struct config_filter_stack {
-	struct config_filter_stack *prev;
+struct config_section_stack {
+	struct config_section_stack *prev;
+
 	struct config_filter filter;
+	/* module_name=NULL-terminated list of parsers */
+	struct config_module_parser *parsers;
 	unsigned int pathlen;
 };
 
@@ -41,15 +44,17 @@ 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_module_parsers) cur_parsers;
+	ARRAY_DEFINE(all_parsers, struct config_filter_parser *);
 	struct config_module_parser *root_parsers;
-	struct config_filter_stack *cur_filter;
+	struct config_section_stack *cur_section;
 	struct input_stack *cur_input;
 
 	struct config_filter_context *filter;
 };
+
+static const enum settings_parser_flags settings_parser_flags =
+	SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS |
+	SETTINGS_PARSER_FLAG_TRACK_CHANGES;
 
 struct config_module_parser *config_module_parsers;
 struct config_filter_context *config_filter;
@@ -93,15 +98,15 @@ static void config_add_type(struct setti
 }
 
 static int
-config_parsers_parse_line(struct config_module_parser *parsers,
-			  const char *key, const char *line,
-			  const char *section_name, const char **error_r)
+config_apply_line(struct parser_context *ctx, const char *key,
+		  const char *line, const char *section_name,
+		  const char **error_r)
 {
 	struct config_module_parser *l;
 	bool found = FALSE;
 	int ret;
 
-	for (l = parsers; l->module_name != NULL; l++) {
+	for (l = ctx->cur_section->parsers; l->module_name != NULL; l++) {
 		ret = settings_parse_line(l->parser, line);
 		if (ret > 0) {
 			found = TRUE;
@@ -116,23 +121,6 @@ config_parsers_parse_line(struct config_
 		*error_r = t_strconcat("Unknown setting: ", key, NULL);
 		return -1;
 	}
-	return 0;
-}
-
-static int
-config_apply_line(struct parser_context *ctx, const char *key,
-		  const char *line, const char *section_name,
-		  const char **error_r)
-{
-	struct config_module_parser *const *parsers;
-	unsigned int i, count;
-
-	parsers = array_get(&ctx->cur_parsers, &count);
-	for (i = 0; i < count; i++) {
-		if (config_parsers_parse_line(parsers[i], key, line,
-					      section_name, error_r) < 0)
-			return -1;
-	}


More information about the dovecot-cvs mailing list