return 0;
}
+static void
+config_filter_write_hierarchical(string_t *str,
+ const struct config_filter *filter)
+{
+ if (filter == NULL || !filter->filter_hierarchical)
+ return;
+ if (str_len(str) > 0)
+ str_append_c(str, '/');
+ str_append(str, filter->filter_name);
+ config_filter_write_hierarchical(str, filter->parent);
+}
+
static void
config_dump_full_append_filter_query(string_t *str,
const struct config_filter *filter,
- bool leaf)
+ bool leaf, bool parent_hierarchical)
{
if (filter->service != NULL) {
if (filter->service[0] != '!') {
}
str_append(str, " AND ");
} else if (filter->filter_name != NULL) {
+ const char *filter_name = filter->filter_name;
+
+ if (!parent_hierarchical &&
+ filter->filter_hierarchical &&
+ filter->parent->filter_hierarchical) {
+ /* beginning of a hierarchical filter. */
+ string_t *str = t_str_new(128);
+ config_filter_write_hierarchical(str, filter);
+ filter_name = str_c(str);
+ } else if (parent_hierarchical &&
+ filter->filter_hierarchical) {
+ /* hierarchical filter was already written. */
+ return;
+ }
+
str_printfa(str, SETTINGS_EVENT_FILTER_NAME"=\"%s\" AND ",
- wildcard_str_escape(filter->filter_name));
+ wildcard_str_escape(filter_name));
}
}
const struct config_filter *filter)
{
bool leaf = TRUE;
+ bool parent_hierarchical = FALSE;
do {
- config_dump_full_append_filter_query(str, filter, leaf);
+ config_dump_full_append_filter_query(str, filter, leaf,
+ parent_hierarchical);
leaf = FALSE;
+ parent_hierarchical = filter->filter_hierarchical;
filter = filter->parent;
} while (filter != NULL);
/* named_filter { .. } */
const char *filter_name;
bool filter_name_array;
+ /* This filter is hierarchical. If a child event is also hierarchical,
+ their filter_names will be merged into one filter path when dumping
+ the config. */
+ bool filter_hierarchical;
};
struct config_filter_parser {
case SET_FILTER_ARRAY:
break;
case SET_FILTER_NAME:
+ case SET_FILTER_HIERARCHY:
ctx->error = p_strdup_printf(ctx->pool,
"Setting is a named filter, use '%s {'", def->key);
return -1;
return FALSE;
def = &all_infos[config_key->info_idx]->defines[config_key->define_idx];
- if (def->type != SET_FILTER_NAME && def->type != SET_FILTER_ARRAY)
+ if (def->type != SET_FILTER_NAME &&
+ def->type != SET_FILTER_HIERARCHY &&
+ def->type != SET_FILTER_ARRAY)
return FALSE;
*def_r = def;
break;
struct config_module_parser *l =
&ctx->cur_section->module_parsers[config_key->info_idx];
- if (l->info->defines[config_key->define_idx].type != SET_FILTER_NAME)
+ if (l->info->defines[config_key->define_idx].type != SET_FILTER_NAME &&
+ l->info->defines[config_key->define_idx].type != SET_FILTER_HIERARCHY)
break;
ctx->cur_section->filter.filter_name =
else
filter->remote_host = p_strdup(ctx->pool, value);
} else if (config_is_filter_name(ctx, key, &filter_def)) {
- if (filter_def->type == SET_FILTER_NAME) {
+ if (filter_def->type == SET_FILTER_NAME ||
+ filter_def->type == SET_FILTER_HIERARCHY) {
if (value[0] != '\0' || line->value_quoted) {
ctx->error = p_strdup_printf(ctx->pool,
"%s { } must not have a section name",
key);
return TRUE;
}
- if (parent->filter_name != NULL &&
- !parent->filter_name_array) {
- ctx->error = p_strdup_printf(ctx->pool,
- "Nested named filters not allowed: %s { %s { .. } }",
- parent->filter_name, key);
- return FALSE;
- }
+ if (filter_def->type == SET_FILTER_HIERARCHY)
+ filter->filter_hierarchical = TRUE;
filter->filter_name = p_strdup(ctx->pool, key);
} else {
if (parent->filter_name != NULL &&
break;
}
case SET_FILTER_NAME:
+ case SET_FILTER_HIERARCHY:
case SET_ALIAS:
break;
}
break;
}
case SET_FILTER_NAME:
+ case SET_FILTER_HIERARCHY:
settings_parser_set_error(ctx, t_strdup_printf(
"Setting is a named filter, use '%s {'", key));
return -1;
/* try to find the exact key */
def = setting_define_find(ctx->info, key);
- if (def != NULL && (def->type != SET_FILTER_NAME ||
+ if (def != NULL && ((def->type != SET_FILTER_NAME &&
+ def->type != SET_FILTER_HIERARCHY) ||
allow_filter_name)) {
*def_r = def;
return TRUE;
SET_BOOLLIST, /* of type ARRAY_TYPE(const_string) - guaranteed NULL-terminted */
SET_ALIAS, /* alias name for above setting definition */
SET_FILTER_NAME,
+ SET_FILTER_HIERARCHY,
SET_FILTER_ARRAY,
};
enum setting_flags {
str_printfa(filter_string, SETTINGS_EVENT_FILTER_NAME"=\"%s\"",
wildcard_str_escape(last_filter_key));
break;
+ case SET_FILTER_HIERARCHY: {
+ /* add the full repeated hierarchy here */
+ const char *next;
+
+ str_printfa(filter_string, SETTINGS_EVENT_FILTER_NAME"=\"%s",
+ wildcard_str_escape(part));
+ while (str_begins(p + 1, part, &next) &&
+ next[0] == SETTINGS_SEPARATOR) {
+ str_append_c(filter_string, '/');
+ str_append(filter_string,
+ wildcard_str_escape(part));
+ p = next;
+ }
+ str_append_c(filter_string, '"');
+
+ last_filter_key = t_strdup_until(set->key, p);
+ last_filter_value = NULL;
+ break;
+ }
case SET_FILTER_ARRAY: {
const char *value = p + 1;
p = strchr(value, SETTINGS_SEPARATOR);
filter_name_required = TRUE;
} else if (filter_key != NULL) {
filter_name = filter_key;
+ event_strlist_append(lookup_event, SETTINGS_EVENT_FILTER_NAME,
+ filter_name);
filter_name_required = TRUE;
}