node = p_new(state->pool, struct event_filter_node, 1);
node->type = type;
node->op = op;
+ node->warned_type_mismatch = FALSE;
switch (type) {
case EVENT_FILTER_NODE_TYPE_LOGIC:
if (str_to_intmax(b, &node->field.value.intmax) == 0) {
/* Leave a hint that this is in fact a valid number. */
node->field.value_type = EVENT_FIELD_VALUE_TYPE_INTMAX;
+ node->type = EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT;
} else {
/* This field contains no valid number.
Either this is a string that contains a size unit, a
node->type = EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT;
break;
}
+
+ if (wildcard_is_literal(node->field.value.str))
+ node->type = EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT;
+ else if (strspn(b, "0123456789*?") == strlen(b))
+ node->type = EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD;
}
- if (wildcard_is_literal(node->field.value.str))
- node->type = EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT;
break;
case EVENT_FILTER_NODE_TYPE_EVENT_NAME_EXACT:
case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT:
+ case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD:
i_unreached();
}
EVENT_FILTER_NODE_TYPE_EVENT_CATEGORY, /* cat */
EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT, /* field */
EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD, /* field */
+ EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD, /* field */
};
enum event_filter_log_type {
struct event_category *ptr;
} category;
struct event_field field;
+
+ bool warned_type_mismatch:1;
};
bool event_filter_category_to_log_type(const char *name,
new->field.value.str = p_strdup(pool, old->field.value.str);
new->field.value.intmax = old->field.value.intmax;
new->field.value.timeval = old->field.value.timeval;
+ new->warned_type_mismatch = old->warned_type_mismatch;
return new;
}
break;
case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT:
case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD:
+ case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD:
str_append_c(dest, '"');
event_filter_append_escaped(dest, node->field.key);
str_append_c(dest, '"');
else
return wildcard_match_icase(field->value.str, wanted_field->value.str);
case EVENT_FIELD_VALUE_TYPE_INTMAX:
- if (wanted_field->value_type == EVENT_FIELD_VALUE_TYPE_INTMAX) {
+ if ((wanted_field->value_type != EVENT_FIELD_VALUE_TYPE_INTMAX) &&
+ (node->type != EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD)) {
+ if (!node->warned_type_mismatch) {
+ const char *name = event->sending_name;
+ /* Use i_warning to prevent event filter recursions. */
+ i_warning("Event filter matches integer field "
+ "'%s' against non-integer value '%s'. "
+ "(event=%s)",
+ wanted_field->key,
+ wanted_field->value.str,
+ name != NULL ? name : "");
+ node->warned_type_mismatch = TRUE;
+ }
+ return FALSE;
+ } else if (wanted_field->value_type == EVENT_FIELD_VALUE_TYPE_INTMAX) {
/* compare against an integer */
return event_filter_handle_numeric_operation(
node->op, field->value.intmax, wanted_field->value.intmax);
case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT:
return event_match_field(event, node, TRUE);
case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD:
+ case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD:
return event_match_field(event, node, FALSE);
}
case EVENT_FILTER_NODE_TYPE_EVENT_SOURCE_LOCATION:
case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT:
case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD:
+ case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD:
break;
case EVENT_FILTER_NODE_TYPE_EVENT_CATEGORY:
if (node->category.name == NULL)
filter = event_filter_create();
test_assert(event_filter_parse("number=fish", filter, &error) == 0);
+ test_expect_error_string("Event filter matches integer field 'number' "
+ "against non-integer value 'fish'");
test_assert(!event_filter_match(filter, e, &failure_ctx));
+ test_expect_no_more_errors();
event_filter_unref(&filter);
event_unref(&e);