]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
config: Send client a services names that have more specific settings.
authorTimo Sirainen <tss@iki.fi>
Fri, 19 Mar 2010 15:23:56 +0000 (17:23 +0200)
committerTimo Sirainen <tss@iki.fi>
Fri, 19 Mar 2010 15:23:56 +0000 (17:23 +0200)
--HG--
branch : HEAD

src/config/config-connection.c
src/config/config-filter.c
src/config/config-filter.h
src/config/config-parser.c
src/config/config-parser.h
src/config/config-request.c
src/lib-master/master-service-settings.c
src/lib-master/master-service-settings.h

index cae29225047b47f27058536668384bf14ec5716f..f78f44b69d0dd74256f94f6291b32e06d23b0d51 100644 (file)
@@ -115,6 +115,14 @@ static int config_connection_request(struct config_connection *conn,
        config_export_by_filter(ctx, &filter);
        config_export_get_output(ctx, &output);
 
+       if (output.specific_services != NULL) {
+               const char *const *s;
+
+               for (s = output.specific_services; *s != NULL; s++) {
+                       o_stream_send_str(conn->output,
+                               t_strdup_printf("service=%s\t", *s));
+               }
+       }
        if (output.service_uses_local)
                o_stream_send_str(conn->output, "service-uses-local\t");
        if (output.service_uses_remote)
index 2bd32cd189c8fb2273168cea2d4f7231f9cac409..d661d8425b38b56c3b2c26191ef4e6eabfda0881 100644 (file)
@@ -155,22 +155,60 @@ config_filter_parser_cmp_rev(struct config_filter_parser *const *p1,
        return -config_filter_parser_cmp(p1, p2);
 }
 
+static bool str_array_contains(ARRAY_TYPE(const_string) *arr, const char *str)
+{
+       const char *const *p;
+
+       array_foreach(arr, p) {
+               if (strcmp(*p, str) == 0)
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+static bool have_changed_settings(const struct config_filter_parser *parser,
+                                 const char *module)
+{
+       const unsigned char *changes;
+       unsigned int i, j, size;
+
+       for (i = 0; parser->parsers[i].root != NULL; i++) {
+               if (*module != '\0' &&
+                   !config_module_want_parser(module, parser->parsers[i].root))
+                       continue;
+
+               changes = settings_parser_get_changes(parser->parsers[i].parser);
+               size = parser->parsers[i].root->struct_size;
+               for (j = 0; j < size; j++) {
+                       if (changes[j] != 0)
+                               return TRUE;
+               }
+       }
+       return FALSE;
+}
+
 static struct config_filter_parser *const *
-config_filter_find_all(struct config_filter_context *ctx,
+config_filter_find_all(struct config_filter_context *ctx, const char *module,
                       const struct config_filter *filter,
                       struct master_service_settings_output *output_r)
 {
        ARRAY_TYPE(config_filter_parsers) matches;
+       ARRAY_TYPE(const_string) service_names;
        unsigned int i;
 
        memset(output_r, 0, sizeof(*output_r));
 
        t_array_init(&matches, 8);
+       t_array_init(&service_names, 8);
        for (i = 0; ctx->parsers[i] != NULL; i++) {
                const struct config_filter *mask = &ctx->parsers[i]->filter;
 
-               if (!config_filter_match_service(mask, filter))
+               if (!config_filter_match_service(mask, filter)) {
+                       if (!str_array_contains(&service_names, mask->service) &&
+                           have_changed_settings(ctx->parsers[i], module))
+                               array_append(&service_names, &mask->service, 1);
                        continue;
+               }
 
                if (mask->local_bits > 0)
                        output_r->service_uses_local = TRUE;
@@ -184,6 +222,11 @@ config_filter_find_all(struct config_filter_context *ctx,
                        array_append(&matches, &ctx->parsers[i], 1);
                }
        }
+       if (filter->service == NULL) {
+               (void)array_append_space(&service_names);
+               output_r->specific_services = array_idx(&service_names, 0);
+       }
+
        array_sort(&matches, config_filter_parser_cmp);
        (void)array_append_space(&matches);
        return array_idx(&matches, 0);
@@ -260,6 +303,7 @@ config_module_parser_apply_changes(struct config_module_parser *dest,
 }
 
 int config_filter_parsers_get(struct config_filter_context *ctx, pool_t pool,
+                             const char *module,
                              const struct config_filter *filter,
                              struct config_module_parser **parsers_r,
                              struct master_service_settings_output *output_r,
@@ -270,7 +314,7 @@ int config_filter_parsers_get(struct config_filter_context *ctx, pool_t pool,
        const char *error, **error_p;
        unsigned int i, count;
 
-       src = config_filter_find_all(ctx, filter, output_r);
+       src = config_filter_find_all(ctx, module, filter, output_r);
 
        /* all of them should have the same number of parsers.
           duplicate our initial parsers from the first match */
index e7dc9b611360f5eadc5e385d061cca6c8ca0374a..db2a5710159115ab691e72ca7610a57fd378e211 100644 (file)
@@ -29,6 +29,7 @@ void config_filter_add_all(struct config_filter_context *ctx,
 
 /* Build new parsers from all existing ones matching the given filter. */
 int config_filter_parsers_get(struct config_filter_context *ctx, pool_t pool,
+                             const char *module,
                              const struct config_filter *filter,
                              struct config_module_parser **parsers_r,
                              struct master_service_settings_output *output_r,
index e0c0196f4ea1b82f883a7c448a5d33271631ea73..caf417c0fcc5835a4c9b5ac4d626a16823d3c508 100644 (file)
@@ -300,7 +300,7 @@ config_all_parsers_check(struct config_parser_context *ctx,
        i_assert(count > 0 && parsers[count-1] == NULL);
        count--;
        for (i = 0; i < count && ret == 0; i++) {
-               if (config_filter_parsers_get(new_filter, tmp_pool,
+               if (config_filter_parsers_get(new_filter, tmp_pool, "",
                                              &parsers[i]->filter,
                                              &tmp_parsers, &output,
                                              error_r) < 0) {
@@ -850,3 +850,49 @@ void config_parse_load_modules(void)
                *default_services = new_services;
        }
 }
+
+static bool parsers_are_connected(const struct setting_parser_info *root,
+                                 const struct setting_parser_info *info)
+{
+       const struct setting_parser_info *p;
+       const struct setting_parser_info *const *dep;
+
+       /* 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++) {
+                       if (parsers_are_connected(*dep, info))
+                               return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+bool config_module_want_parser(const char *module,
+                              const struct setting_parser_info *root)
+{
+       struct config_module_parser *l;
+
+       if (strcmp(root->module_name, module) == 0)
+               return TRUE;
+       if (root == &master_service_setting_parser_info) {
+               /* everyone wants master service settings */
+               return TRUE;
+       }
+
+       for (l = config_module_parsers; l->root != NULL; l++) {
+               if (strcmp(l->root->module_name, module) != 0)
+                       continue;
+
+               /* see if we can find a way to get from the original parser
+                  to this parser */
+               if (parsers_are_connected(l->root, root))
+                       return TRUE;
+       }
+       return FALSE;
+}
index 47b9ee5fdcd9cb0465442dc529da0bb9feb0028d..aa2c3bd681eb641e5ed070c41b4db6e326b581a0 100644 (file)
@@ -18,4 +18,7 @@ int config_parse_file(const char *path, bool expand_values,
 
 void config_parse_load_modules(void);
 
+bool config_module_want_parser(const char *module,
+                              const struct setting_parser_info *root);
+
 #endif
index 41e9bd0d2009655827295182265fe6f5c71aa227..2f49d859cf11f671a69586b8f343e969c2a9eb99 100644 (file)
@@ -30,53 +30,6 @@ struct config_export_context {
        bool failed;
 };
 
-static bool parsers_are_connected(const struct setting_parser_info *root,
-                                 const struct setting_parser_info *info)
-{
-       const struct setting_parser_info *p;
-       const struct setting_parser_info *const *dep;
-
-       /* 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++) {
-                       if (parsers_are_connected(*dep, info))
-                               return TRUE;
-               }
-       }
-       return FALSE;
-}
-
-static bool
-config_module_parser_is_in_service(const struct config_module_parser *list,
-                                  const char *module)
-{
-       struct config_module_parser *l;
-
-       if (strcmp(list->root->module_name, module) == 0)
-               return TRUE;
-       if (list->root == &master_service_setting_parser_info) {
-               /* everyone wants master service settings */
-               return TRUE;
-       }
-
-       for (l = config_module_parsers; l->root != NULL; l++) {
-               if (strcmp(l->root->module_name, module) != 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;
-}
-
 bool config_export_type(string_t *str, const void *value,
                        const void *default_value,
                        enum setting_type type, bool dump_default,
@@ -343,6 +296,8 @@ config_export_init(const char *module, enum config_dump_scope scope,
        struct config_export_context *ctx;
        pool_t pool;
 
+       i_assert(module != NULL);
+
        pool = pool_alloconly_create("config export", 1024*64);
        ctx = p_new(pool, struct config_export_context, 1);
        ctx->pool = pool;
@@ -364,7 +319,8 @@ void config_export_by_filter(struct config_export_context *ctx,
 {
        const char *error;
 
-       if (config_filter_parsers_get(config_filter, ctx->pool, filter,
+       if (config_filter_parsers_get(config_filter, ctx->pool,
+                                     ctx->module, filter,
                                      &ctx->dup_parsers, &ctx->output,
                                      &error) < 0) {
                i_error("%s", error);
@@ -411,7 +367,7 @@ int config_export_finish(struct config_export_context **_ctx)
        for (i = 0; ctx->parsers[i].root != NULL; i++) {
                parser = &ctx->parsers[i];
                if (*ctx->module != '\0' &&
-                   !config_module_parser_is_in_service(parser, ctx->module))
+                   !config_module_want_parser(ctx->module, parser->root))
                        continue;
 
                settings_export(ctx, parser->root, FALSE,
index 0c519b374b9b7116555269864310c3e52e5302c4..4b9b7f36c510283ae422d4dac550c561ef7ab0bc 100644 (file)
@@ -230,22 +230,23 @@ master_service_apply_config_overrides(struct master_service *service,
 }
 
 static int
-config_read_reply_header(struct istream *input, const char *path,
+config_read_reply_header(struct istream *istream, const char *path, pool_t pool,
+                        const struct master_service_settings_input *input,
                         struct master_service_settings_output *output_r,
                         const char **error_r)
 {
        const char *line;
        ssize_t ret;
 
-       while ((ret = i_stream_read(input)) > 0) {
-               line = i_stream_next_line(input);
+       while ((ret = i_stream_read(istream)) > 0) {
+               line = i_stream_next_line(istream);
                if (line != NULL)
                        break;
        }
        if (ret <= 0) {
                if (ret == 0)
                        return 1;
-               *error_r = input->stream_errno != 0 ?
+               *error_r = istream->stream_errno != 0 ?
                        t_strdup_printf("read(%s) failed: %m", path) :
                        t_strdup_printf("read(%s) failed: EOF", path);
                return -1;
@@ -253,7 +254,9 @@ config_read_reply_header(struct istream *input, const char *path,
 
        T_BEGIN {
                const char *const *arg = t_strsplit(line, "\t");
+               ARRAY_TYPE(const_string) services;
 
+               p_array_init(&services, pool, 8);
                for (; *arg != NULL; arg++) {
                        if (strcmp(*arg, "service-uses-local") == 0)
                                output_r->service_uses_local = TRUE;
@@ -263,6 +266,14 @@ config_read_reply_header(struct istream *input, const char *path,
                                output_r->used_local = TRUE;
                        else if (strcmp(*arg, "used-remote") == 0)
                                output_r->used_remote = TRUE;
+                       else if (strncmp(*arg, "service=", 8) == 0) {
+                               const char *name = p_strdup(pool, *arg + 8);
+                               array_append(&services, &name, 1);
+                        }
+               }
+               if (input->service == NULL) {
+                       (void)array_append_space(&services);
+                       output_r->specific_services = array_idx(&services, 0);
                }
        } T_END;
        return 0;
@@ -332,6 +343,7 @@ int master_service_settings_read(struct master_service *service,
                do {
                        alarm(timeout - now);
                        ret = config_read_reply_header(istream, path,
+                                                      service->set_pool, input,
                                                       output_r, error_r);
                        if (ret == 0) {
                                ret = settings_parse_stream_read(parser,
index e159c8c3cecca5c60c8980b5b4eec366f0ca1fd7..2e824358d1fe517814d4b4aafbe8fd662deee459 100644 (file)
@@ -34,8 +34,13 @@ struct master_service_settings_input {
 };
 
 struct master_service_settings_output {
-       /* some settings for this service contain local/remote ip/host
-          specific settings. */
+       /* if service was not given for lookup, this contains names of services
+          that have more specific settings */
+       const char *const *specific_services;
+
+       /* some settings for this service (or if service was not given,
+          all services) contain local/remote ip/host specific settings
+          (but this lookup didn't necessarily return any of them). */
        unsigned int service_uses_local:1;
        unsigned int service_uses_remote:1;
        /* returned settings contain settings specific to given