diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2013-09-11 17:20:03 +0100 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2013-09-11 17:20:03 +0100 |
commit | 29c04315424483ba6d033d1811254528c94e9ec5 (patch) | |
tree | d74f5719eea2355744a2b9938c308c0047254d0f | |
parent | cfaddb2c383a9066f8105245f3459cc1e8ff87d1 (diff) | |
download | rspamd-29c04315424483ba6d033d1811254528c94e9ec5.tar.gz rspamd-29c04315424483ba6d033d1811254528c94e9ec5.zip |
Add metrics handler for rcl.
-rw-r--r-- | src/cfg_rcl.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/cfg_rcl.c b/src/cfg_rcl.c index f5d5bab2e..b6a08657a 100644 --- a/src/cfg_rcl.c +++ b/src/cfg_rcl.c @@ -23,6 +23,7 @@ #include "cfg_rcl.h" #include "main.h" +#include "settings.h" /* * Common section handlers @@ -186,6 +187,192 @@ rspamd_rcl_options_handler (struct config_file *cfg, rspamd_cl_object_t *obj, return rspamd_rcl_section_parse_defaults (section, cfg, obj, cfg, err); } +static gint +rspamd_symbols_group_find_func (gconstpointer a, gconstpointer b) +{ + const struct symbols_group *gr = a; + const gchar *uv = b; + + return g_ascii_strcasecmp (gr->name, uv); +} + +/** + * Insert a symbol to the metric + * @param cfg + * @param metric + * @param obj symbol rcl object (either float value or an object) + * @param err + * @return + */ +static gboolean +rspamd_rcl_insert_symbol (struct config_file *cfg, struct metric *metric, + rspamd_cl_object_t *obj, GError **err) +{ + const gchar *group = "ungrouped", *description = NULL; + gdouble symbol_score, *score_ptr; + rspamd_cl_object_t *val; + struct symbols_group *sym_group; + struct symbol_def *sym_def; + GList *metric_list, *group_list; + + /* + * We allow two type of definitions: + * symbol = weight + * or + * symbol { + * weight = ...; + * description = ...; + * group = ...; + * } + */ + if (rspamd_cl_obj_todouble_safe (obj, &symbol_score)) { + description = NULL; + } + else if (obj->type == RSPAMD_CL_OBJECT) { + HASH_FIND_STR (obj, "score", val); + if (val == NULL || !rspamd_cl_obj_todouble_safe (val, &symbol_score)) { + g_set_error (err, CFG_RCL_ERROR, EINVAL, "invalid symbol score: %s", obj->key); + return FALSE; + } + HASH_FIND_STR (obj, "description", val); + if (val != NULL) { + description = rspamd_cl_obj_tostring (val); + } + HASH_FIND_STR (obj, "group", val); + if (val != NULL) { + rspamd_cl_obj_tostring_safe (val, &group); + } + } + else { + g_set_error (err, CFG_RCL_ERROR, EINVAL, "invalid symbol type: %s", obj->key); + return FALSE; + } + + sym_def = memory_pool_alloc (cfg->cfg_pool, sizeof (struct symbol_def)); + score_ptr = memory_pool_alloc (cfg->cfg_pool, sizeof (gdouble)); + + *score_ptr = symbol_score; + sym_def->weight_ptr = score_ptr; + sym_def->name = memory_pool_strdup (cfg->cfg_pool, obj->key); + sym_def->description = (gchar *)description; + + g_hash_table_insert (metric->symbols, sym_def->name, score_ptr); + + if ((metric_list = g_hash_table_lookup (cfg->metrics_symbols, sym_def->name)) == NULL) { + metric_list = g_list_prepend (NULL, metric); + memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func)g_list_free, metric_list); + g_hash_table_insert (cfg->metrics_symbols, sym_def->name, metric_list); + } + else { + /* Slow but keep start element of list in safe */ + if (!g_list_find (metric_list, metric)) { + metric_list = g_list_append (metric_list, metric); + } + } + + /* Search for symbol group */ + group_list = g_list_find_custom (cfg->symbols_groups, group, rspamd_symbols_group_find_func); + if (group_list == NULL) { + /* Create new group */ + sym_group = memory_pool_alloc (cfg->cfg_pool, sizeof (struct symbols_group)); + sym_group->name = memory_pool_strdup (cfg->cfg_pool, group); + sym_group->symbols = NULL; + cfg->symbols_groups = g_list_prepend (cfg->symbols_groups, sym_group); + } + else { + sym_group = group_list->data; + } + /* Insert symbol */ + sym_group->symbols = g_list_prepend (sym_group->symbols, sym_def); + + return TRUE; +} + +static gboolean +rspamd_rcl_metric_handler (struct config_file *cfg, rspamd_cl_object_t *obj, + gpointer ud, struct rspamd_rcl_section *section, GError **err) +{ + rspamd_cl_object_t *val, *lobj, *cur, *tmp; + const gchar *metric_name, *subject_name; + struct metric *metric; + struct metric_action *action; + gdouble action_score, grow_factor; + gint action_value; + gboolean new = TRUE; + + lobj = obj->value.ov; + + HASH_FIND_STR (lobj, "name", val); + if (val == NULL || !rspamd_cl_obj_tostring_safe (val, &metric_name)) { + metric_name = DEFAULT_METRIC; + } + + metric = g_hash_table_lookup (cfg->metrics, metric_name); + if (metric == NULL) { + metric = check_metric_conf (cfg, metric); + } + else { + new = FALSE; + } + + /* Handle actions */ + HASH_FIND_STR (lobj, "actions", val); + if (val != NULL) { + if (val->type != RSPAMD_CL_OBJECT) { + g_set_error (err, CFG_RCL_ERROR, EINVAL, "actions must be an object"); + return FALSE; + } + HASH_ITER (hh, val, cur, tmp) { + if (!check_action_str (cur->key, &action_value) || + !rspamd_cl_obj_todouble_safe (cur, &action_score)) { + g_set_error (err, CFG_RCL_ERROR, EINVAL, "invalid action definition: %s", cur->key); + return FALSE; + } + action = memory_pool_alloc (cfg->cfg_pool, sizeof (struct metric_action)); + action->action = action_value; + action->score = action_score; + metric->actions = g_list_prepend (metric->actions, action); + } + } + else if (new) { + g_set_error (err, CFG_RCL_ERROR, EINVAL, "metric %s has no actions", metric_name); + return FALSE; + } + + /* Handle symbols */ + HASH_FIND_STR (lobj, "symbols", val); + if (val != NULL) { + if (val->type == RSPAMD_CL_ARRAY) { + val = val->value.ov; + } + if (val->type != RSPAMD_CL_OBJECT) { + g_set_error (err, CFG_RCL_ERROR, EINVAL, "symbols must be an object"); + return FALSE; + } + HASH_ITER (hh, val, cur, tmp) { + if (!rspamd_rcl_insert_symbol (cfg, metric, cur, err)) { + return FALSE; + } + } + } + + HASH_FIND_STR (lobj, "grow_factor", val); + if (val && rspamd_cl_obj_todouble_safe (val, &grow_factor)) { + metric->grow_factor = grow_factor; + } + + HASH_FIND_STR (lobj, "subject", val); + if (val && rspamd_cl_obj_tostring_safe (val, &subject_name)) { + metric->subject = (gchar *)subject_name; + } + + /* Insert the resulting metric */ + g_hash_table_insert (cfg->metrics, metric->name, metric); + cfg->metrics_list = g_list_prepend (cfg->metrics_list, metric); + + return TRUE; +} + /** * Fake handler to parse default options only, uses struct cfg_file as pointer * for default handlers @@ -317,6 +504,11 @@ rspamd_rcl_config_init (void) rspamd_rcl_add_default_handler (sub, "use_mlock", rspamd_rcl_parse_struct_boolean, G_STRUCT_OFFSET (struct config_file, mlock_statfile_pool), 0); + /** + * Metric section + */ + sub = rspamd_rcl_add_section (new, "metric", rspamd_rcl_metric_handler, RSPAMD_CL_OBJECT, + FALSE, TRUE); return new; } |