# HG changeset patch # User Timo Sirainen # Date 1269012236 -7200 # Node ID 30e2d65eb67a0a23e3c0e63a60c42c04cac02a09 # Parent edd11ffa467c42adb71fb9e2d4bcda37ea61ce52 config: Send client a services names that have more specific settings. diff -r edd11ffa467c -r 30e2d65eb67a src/config/config-connection.c --- a/src/config/config-connection.c Fri Mar 19 16:44:38 2010 +0200 +++ b/src/config/config-connection.c Fri Mar 19 17:23:56 2010 +0200 @@ -115,6 +115,14 @@ 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) diff -r edd11ffa467c -r 30e2d65eb67a src/config/config-filter.c --- a/src/config/config-filter.c Fri Mar 19 16:44:38 2010 +0200 +++ b/src/config/config-filter.c Fri Mar 19 17:23:56 2010 +0200 @@ -155,22 +155,60 @@ 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 @@ 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 @@ } 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 @@ 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 */ diff -r edd11ffa467c -r 30e2d65eb67a src/config/config-filter.h --- a/src/config/config-filter.h Fri Mar 19 16:44:38 2010 +0200 +++ b/src/config/config-filter.h Fri Mar 19 17:23:56 2010 +0200 @@ -29,6 +29,7 @@ /* 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, diff -r edd11ffa467c -r 30e2d65eb67a src/config/config-parser.c --- a/src/config/config-parser.c Fri Mar 19 16:44:38 2010 +0200 +++ b/src/config/config-parser.c Fri Mar 19 17:23:56 2010 +0200 @@ -300,7 +300,7 @@ 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 @@ *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; +} diff -r edd11ffa467c -r 30e2d65eb67a src/config/config-parser.h --- a/src/config/config-parser.h Fri Mar 19 16:44:38 2010 +0200 +++ b/src/config/config-parser.h Fri Mar 19 17:23:56 2010 +0200 @@ -18,4 +18,7 @@ void config_parse_load_modules(void); +bool config_module_want_parser(const char *module, + const struct setting_parser_info *root); + #endif diff -r edd11ffa467c -r 30e2d65eb67a src/config/config-request.c --- a/src/config/config-request.c Fri Mar 19 16:44:38 2010 +0200 +++ b/src/config/config-request.c Fri Mar 19 17:23:56 2010 +0200 @@ -30,53 +30,6 @@ 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 @@ 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 @@ { 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 @@ 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, diff -r edd11ffa467c -r 30e2d65eb67a src/lib-master/master-service-settings.c --- a/src/lib-master/master-service-settings.c Fri Mar 19 16:44:38 2010 +0200 +++ b/src/lib-master/master-service-settings.c Fri Mar 19 17:23:56 2010 +0200 @@ -230,22 +230,23 @@ } 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 @@ 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 @@ 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 @@ 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, diff -r edd11ffa467c -r 30e2d65eb67a src/lib-master/master-service-settings.h --- a/src/lib-master/master-service-settings.h Fri Mar 19 16:44:38 2010 +0200 +++ b/src/lib-master/master-service-settings.h Fri Mar 19 17:23:56 2010 +0200 @@ -34,8 +34,13 @@ }; 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