aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/cfg_xml.c26
-rw-r--r--src/expressions.c327
-rw-r--r--src/filter.c74
-rw-r--r--src/filter.h4
-rw-r--r--src/protocol.c59
-rw-r--r--src/protocol.h3
-rw-r--r--src/settings.c93
-rw-r--r--src/settings.h2
8 files changed, 416 insertions, 172 deletions
diff --git a/src/cfg_xml.c b/src/cfg_xml.c
index 5e0d69a4c..2e762ba1e 100644
--- a/src/cfg_xml.c
+++ b/src/cfg_xml.c
@@ -690,28 +690,6 @@ worker_handle_bind (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GH
return TRUE;
}
-static inline gboolean
-check_action (const gchar *data, gint *result)
-{
- if (g_ascii_strncasecmp (data, "reject", sizeof ("reject") - 1) == 0) {
- *result = METRIC_ACTION_REJECT;
- }
- else if (g_ascii_strncasecmp (data, "greylist", sizeof ("greylist") - 1) == 0) {
- *result = METRIC_ACTION_GREYLIST;
- }
- else if (g_ascii_strncasecmp (data, "add_header", sizeof ("add_header") - 1) == 0) {
- *result = METRIC_ACTION_ADD_HEADER;
- }
- else if (g_ascii_strncasecmp (data, "rewrite_subject", sizeof ("rewrite_subject") - 1) == 0) {
- *result = METRIC_ACTION_REWRITE_SUBJECT;
- }
- else {
- msg_err ("unknown action for metric: %s", data);
- return FALSE;
- }
- return TRUE;
-}
-
gboolean
handle_metric_action (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset)
{
@@ -722,14 +700,14 @@ handle_metric_action (struct config_file *cfg, struct rspamd_xml_userdata *ctx,
/* First of all check whether we have data with weight (reject:50 for example) */
if ((p = strchr (data, ':')) == NULL) {
- if (check_action (data, &res)) {
+ if (check_action_str (data, &res)) {
metric->action = res;
return TRUE;
}
return FALSE;
}
else {
- if (!check_action (data, &res)) {
+ if (!check_action_str (data, &res)) {
return FALSE;
}
else {
diff --git a/src/expressions.c b/src/expressions.c
index 9d17a146c..c4fa738b5 100644
--- a/src/expressions.c
+++ b/src/expressions.c
@@ -1003,10 +1003,13 @@ rspamd_content_type_compare_param (struct worker_task * task, GList * args, void
gchar *param_name, *param_pattern;
const gchar *param_data;
struct rspamd_regexp *re;
- struct expression_argument *arg;
+ struct expression_argument *arg, *arg1;
GMimeObject *part;
- const GMimeContentType *ct;
+ GMimeContentType *ct;
gint r;
+ gboolean recursive = FALSE, result = FALSE;
+ GList *cur;
+ struct mime_part *cur_part;
if (args == NULL) {
msg_warn ("no parameters to function");
@@ -1022,45 +1025,83 @@ rspamd_content_type_compare_param (struct worker_task * task, GList * args, void
arg = get_function_arg (args->data, task, TRUE);
param_pattern = arg->data;
+
part = g_mime_message_get_mime_part (task->message);
if (part) {
- ct = g_mime_object_get_content_type (part);
+ ct = (GMimeContentType *)g_mime_object_get_content_type (part);
+ if (args->next) {
+ args = g_list_next (args);
+ arg1 = get_function_arg (args->data, task, TRUE);
+ if (g_ascii_strncasecmp (arg1->data, "true", sizeof ("true") - 1) == 0) {
+ recursive = TRUE;
+ }
+ }
+ else {
+ /*
+ * If user did not specify argument, let's assume that he wants
+ * recursive search if mime part is multipart/mixed
+ */
+ if (g_mime_content_type_is_type (ct, "multipart", "*")) {
+ recursive = TRUE;
+ }
+ }
+
+ if (recursive) {
+ cur = task->parts;
+ }
+
#ifndef GMIME24
g_object_unref (part);
#endif
+ for (;;) {
+ if ((param_data = g_mime_content_type_get_parameter ((GMimeContentType *)ct, param_name)) == NULL) {
+ result = FALSE;
+ }
+ if (*param_pattern == '/') {
+ /* This is regexp, so compile and create g_regexp object */
+ if ((re = re_cache_check (param_pattern, task->cfg->cfg_pool)) == NULL) {
+ re = parse_regexp (task->cfg->cfg_pool, param_pattern, task->cfg->raw_mode);
+ if (re == NULL) {
+ msg_warn ("cannot compile regexp for function");
+ return FALSE;
+ }
+ re_cache_add (param_pattern, re, task->cfg->cfg_pool);
+ }
+ if ((r = task_cache_check (task, re)) == -1) {
+ if (g_regex_match (re->regexp, param_data, 0, NULL) == TRUE) {
+ task_cache_add (task, re, 1);
+ return TRUE;
+ }
+ task_cache_add (task, re, 0);
+ }
+ else {
- if ((param_data = g_mime_content_type_get_parameter ((GMimeContentType *)ct, param_name)) == NULL) {
- return FALSE;
- }
- if (*param_pattern == '/') {
- /* This is regexp, so compile and create g_regexp object */
- if ((re = re_cache_check (param_pattern, task->cfg->cfg_pool)) == NULL) {
- re = parse_regexp (task->cfg->cfg_pool, param_pattern, task->cfg->raw_mode);
- if (re == NULL) {
- msg_warn ("cannot compile regexp for function");
- return FALSE;
}
- re_cache_add (param_pattern, re, task->cfg->cfg_pool);
}
- if ((r = task_cache_check (task, re)) == -1) {
- if (g_regex_match (re->regexp, param_data, 0, NULL) == TRUE) {
- task_cache_add (task, re, 1);
+ else {
+ /* Just do strcasecmp */
+ if (g_ascii_strcasecmp (param_data, param_pattern) == 0) {
return TRUE;
}
- task_cache_add (task, re, 0);
}
- else {
- return r == 1;
+ /* Get next part */
+ if (! recursive) {
+ return result;
}
- }
- else {
- /* Just do strcasecmp */
- if (g_ascii_strcasecmp (param_data, param_pattern) == 0) {
- return TRUE;
+ else if (cur != NULL) {
+ cur_part = cur->data;
+ if (cur_part->type != NULL) {
+ ct = cur_part->type;
+ }
+ cur = g_list_next (cur);
+ }
+ else {
+ /* All is done */
+ return result;
}
}
- }
+ }
return FALSE;
}
@@ -1070,9 +1111,12 @@ rspamd_content_type_has_param (struct worker_task * task, GList * args, void *un
{
gchar *param_name;
const gchar *param_data;
- struct expression_argument *arg;
+ struct expression_argument *arg, *arg1;
GMimeObject *part;
- const GMimeContentType *ct;
+ GMimeContentType *ct;
+ gboolean recursive = FALSE, result = FALSE;
+ GList *cur;
+ struct mime_part *cur_part;
if (args == NULL) {
msg_warn ("no parameters to function");
@@ -1080,18 +1124,55 @@ rspamd_content_type_has_param (struct worker_task * task, GList * args, void *un
}
arg = get_function_arg (args->data, task, TRUE);
param_name = arg->data;
+
part = g_mime_message_get_mime_part (task->message);
if (part) {
- ct = g_mime_object_get_content_type (part);
+ ct = (GMimeContentType *)g_mime_object_get_content_type (part);
+ if (args->next) {
+ args = g_list_next (args);
+ arg1 = get_function_arg (args->data, task, TRUE);
+ if (g_ascii_strncasecmp (arg1->data, "true", sizeof ("true") - 1) == 0) {
+ recursive = TRUE;
+ }
+ }
+ else {
+ /*
+ * If user did not specify argument, let's assume that he wants
+ * recursive search if mime part is multipart/mixed
+ */
+ if (g_mime_content_type_is_type (ct, "multipart", "*")) {
+ recursive = TRUE;
+ }
+ }
+
+ if (recursive) {
+ cur = task->parts;
+ }
+
#ifndef GMIME24
g_object_unref (part);
#endif
-
- debug_task ("checking %s param", param_name);
- param_data = g_mime_content_type_get_parameter ((GMimeContentType *)ct, param_name);
- if (param_data == NULL) {
- return FALSE;
+ for (;;) {
+ if ((param_data = g_mime_content_type_get_parameter ((GMimeContentType *)ct, param_name)) != NULL) {
+ return TRUE;
+ }
+ /* Get next part */
+ if (! recursive) {
+ return result;
+ }
+ else if (cur != NULL) {
+ cur_part = cur->data;
+ if (cur_part->type != NULL) {
+ ct = cur_part->type;
+ }
+ cur = g_list_next (cur);
+ }
+ else {
+ /* All is done */
+ return result;
+ }
}
+
}
return TRUE;
@@ -1100,58 +1181,95 @@ rspamd_content_type_has_param (struct worker_task * task, GList * args, void *un
gboolean
rspamd_content_type_is_subtype (struct worker_task *task, GList * args, void *unused)
{
- gchar *param_pattern;
+ gchar *param_pattern;
struct rspamd_regexp *re;
- struct expression_argument *arg;
+ struct expression_argument *arg, *arg1;
GMimeObject *part;
GMimeContentType *ct;
gint r;
+ gboolean recursive = FALSE, result = FALSE;
+ GList *cur;
+ struct mime_part *cur_part;
if (args == NULL) {
msg_warn ("no parameters to function");
return FALSE;
}
-
arg = get_function_arg (args->data, task, TRUE);
param_pattern = arg->data;
+
part = g_mime_message_get_mime_part (task->message);
if (part) {
ct = (GMimeContentType *)g_mime_object_get_content_type (part);
+ if (args->next) {
+ args = g_list_next (args);
+ arg1 = get_function_arg (args->data, task, TRUE);
+ if (g_ascii_strncasecmp (arg1->data, "true", sizeof ("true") - 1) == 0) {
+ recursive = TRUE;
+ }
+ }
+ else {
+ /*
+ * If user did not specify argument, let's assume that he wants
+ * recursive search if mime part is multipart/mixed
+ */
+ if (g_mime_content_type_is_type (ct, "multipart", "*")) {
+ recursive = TRUE;
+ }
+ }
+
+ if (recursive) {
+ cur = task->parts;
+ }
+
#ifndef GMIME24
g_object_unref (part);
#endif
+ for (;;) {
+ if (*param_pattern == '/') {
+ /* This is regexp, so compile and create g_regexp object */
+ if ((re = re_cache_check (param_pattern, task->cfg->cfg_pool)) == NULL) {
+ re = parse_regexp (task->cfg->cfg_pool, param_pattern, task->cfg->raw_mode);
+ if (re == NULL) {
+ msg_warn ("cannot compile regexp for function");
+ return FALSE;
+ }
+ re_cache_add (param_pattern, re, task->cfg->cfg_pool);
+ }
+ if ((r = task_cache_check (task, re)) == -1) {
+ if (g_regex_match (re->regexp, ct->subtype, 0, NULL) == TRUE) {
+ task_cache_add (task, re, 1);
+ return TRUE;
+ }
+ task_cache_add (task, re, 0);
+ }
+ else {
- if (ct == NULL ) {
- return FALSE;
- }
-
- if (*param_pattern == '/') {
- /* This is regexp, so compile and create g_regexp object */
- if ((re = re_cache_check (param_pattern, task->cfg->cfg_pool)) == NULL) {
- re = parse_regexp (task->cfg->cfg_pool, param_pattern, task->cfg->raw_mode);
- if (re == NULL) {
- msg_warn ("cannot compile regexp for function");
- return FALSE;
}
- re_cache_add (param_pattern, re, task->cfg->cfg_pool);
}
- if ((r = task_cache_check (task, re)) == -1) {
- if (g_regex_match (re->regexp, ct->subtype, 0, NULL) == TRUE) {
- task_cache_add (task, re, 1);
+ else {
+ /* Just do strcasecmp */
+ if (g_ascii_strcasecmp (ct->subtype, param_pattern) == 0) {
return TRUE;
}
- task_cache_add (task, re, 0);
}
- else {
- return r == 1;
+ /* Get next part */
+ if (! recursive) {
+ return result;
}
- }
- else {
- /* Just do strcasecmp */
- if (ct->subtype && g_ascii_strcasecmp (ct->subtype, param_pattern) == 0) {
- return TRUE;
+ else if (cur != NULL) {
+ cur_part = cur->data;
+ if (cur_part->type != NULL) {
+ ct = cur_part->type;
+ }
+ cur = g_list_next (cur);
+ }
+ else {
+ /* All is done */
+ return result;
}
}
+
}
return FALSE;
@@ -1160,59 +1278,96 @@ rspamd_content_type_is_subtype (struct worker_task *task, GList * args, void *un
gboolean
rspamd_content_type_is_type (struct worker_task * task, GList * args, void *unused)
{
- gchar *param_pattern;
+ gchar *param_pattern;
struct rspamd_regexp *re;
+ struct expression_argument *arg, *arg1;
GMimeObject *part;
GMimeContentType *ct;
- struct expression_argument *arg;
gint r;
+ gboolean recursive = FALSE, result = FALSE;
+ GList *cur;
+ struct mime_part *cur_part;
if (args == NULL) {
msg_warn ("no parameters to function");
return FALSE;
}
-
arg = get_function_arg (args->data, task, TRUE);
param_pattern = arg->data;
+
part = g_mime_message_get_mime_part (task->message);
if (part) {
ct = (GMimeContentType *)g_mime_object_get_content_type (part);
+ if (args->next) {
+ args = g_list_next (args);
+ arg1 = get_function_arg (args->data, task, TRUE);
+ if (g_ascii_strncasecmp (arg1->data, "true", sizeof ("true") - 1) == 0) {
+ recursive = TRUE;
+ }
+ }
+ else {
+ /*
+ * If user did not specify argument, let's assume that he wants
+ * recursive search if mime part is multipart/mixed
+ */
+ if (g_mime_content_type_is_type (ct, "multipart", "*")) {
+ recursive = TRUE;
+ }
+ }
+
+ if (recursive) {
+ cur = task->parts;
+ }
+
#ifndef GMIME24
g_object_unref (part);
#endif
+ for (;;) {
+ if (*param_pattern == '/') {
+ /* This is regexp, so compile and create g_regexp object */
+ if ((re = re_cache_check (param_pattern, task->cfg->cfg_pool)) == NULL) {
+ re = parse_regexp (task->cfg->cfg_pool, param_pattern, task->cfg->raw_mode);
+ if (re == NULL) {
+ msg_warn ("cannot compile regexp for function");
+ return FALSE;
+ }
+ re_cache_add (param_pattern, re, task->cfg->cfg_pool);
+ }
+ if ((r = task_cache_check (task, re)) == -1) {
+ if (g_regex_match (re->regexp, ct->type, 0, NULL) == TRUE) {
+ task_cache_add (task, re, 1);
+ return TRUE;
+ }
+ task_cache_add (task, re, 0);
+ }
+ else {
- if (ct == NULL) {
- return FALSE;
- }
-
- if (*param_pattern == '/') {
- /* This is regexp, so compile and create g_regexp object */
- if ((re = re_cache_check (param_pattern, task->cfg->cfg_pool)) == NULL) {
- re = parse_regexp (task->cfg->cfg_pool, param_pattern, task->cfg->raw_mode);
- if (re == NULL) {
- msg_warn ("cannot compile regexp for function");
- return FALSE;
}
- re_cache_add (param_pattern, re, task->cfg->cfg_pool);
}
- if ((r = task_cache_check (task, re)) == -1) {
- if (g_regex_match (re->regexp, ct->type, 0, NULL) == TRUE) {
- task_cache_add (task, re, 1);
+ else {
+ /* Just do strcasecmp */
+ if (g_ascii_strcasecmp (ct->type, param_pattern) == 0) {
return TRUE;
}
- task_cache_add (task, re, 0);
}
- else {
- return r == 1;
+ /* Get next part */
+ if (! recursive) {
+ return result;
}
- }
- else {
- /* Just do strcasecmp */
- if (ct->type && g_ascii_strcasecmp (ct->type, param_pattern) == 0) {
- return TRUE;
+ else if (cur != NULL) {
+ cur_part = cur->data;
+ if (cur_part->type != NULL) {
+ ct = cur_part->type;
+ }
+ cur = g_list_next (cur);
+ }
+ else {
+ /* All is done */
+ return result;
}
}
+
}
return FALSE;
diff --git a/src/filter.c b/src/filter.c
index 53beb762e..9cc6e542f 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -612,6 +612,80 @@ insert_headers (struct worker_task *task)
g_hash_table_foreach (task->results, insert_metric_header, task);
}
+gboolean
+check_action_str (const gchar *data, gint *result)
+{
+ if (g_ascii_strncasecmp (data, "reject", sizeof ("reject") - 1) == 0) {
+ *result = METRIC_ACTION_REJECT;
+ }
+ else if (g_ascii_strncasecmp (data, "greylist", sizeof ("greylist") - 1) == 0) {
+ *result = METRIC_ACTION_GREYLIST;
+ }
+ else if (g_ascii_strncasecmp (data, "add_header", sizeof ("add_header") - 1) == 0) {
+ *result = METRIC_ACTION_ADD_HEADER;
+ }
+ else if (g_ascii_strncasecmp (data, "rewrite_subject", sizeof ("rewrite_subject") - 1) == 0) {
+ *result = METRIC_ACTION_REWRITE_SUBJECT;
+ }
+ else {
+ msg_err ("unknown action for metric: %s", data);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+const gchar *
+str_action_metric (enum rspamd_metric_action action)
+{
+ switch (action) {
+ case METRIC_ACTION_REJECT:
+ return "reject";
+ case METRIC_ACTION_SOFT_REJECT:
+ return "soft reject";
+ case METRIC_ACTION_REWRITE_SUBJECT:
+ return "rewrite subject";
+ case METRIC_ACTION_ADD_HEADER:
+ return "add header";
+ case METRIC_ACTION_GREYLIST:
+ return "greylist";
+ case METRIC_ACTION_NOACTION:
+ return "no action";
+ }
+
+ return "unknown action";
+}
+
+gint
+check_metric_action (double score, double required_score, struct metric *metric)
+{
+ GList *cur;
+ struct metric_action *action, *selected_action = NULL;
+
+ if (score >= required_score) {
+ return metric->action;
+ }
+ else if (metric->actions == NULL) {
+ return METRIC_ACTION_NOACTION;
+ }
+ else {
+ cur = metric->actions;
+ while (cur) {
+ action = cur->data;
+ if (score >= action->score) {
+ selected_action = action;
+ }
+ cur = g_list_next (cur);
+ }
+ if (selected_action) {
+ return selected_action->action;
+ }
+ else {
+ return METRIC_ACTION_NOACTION;
+ }
+ }
+}
+
+
/*
* vi:ts=4
*/
diff --git a/src/filter.h b/src/filter.h
index bc8d98de5..2540d95e9 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -111,4 +111,8 @@ void make_composites (struct worker_task *task);
*/
double factor_consolidation_func (struct worker_task *task, const gchar *metric_name, const gchar *unused);
+gboolean check_action_str (const gchar *data, gint *result);
+const gchar *str_action_metric (enum rspamd_metric_action action);
+gint check_metric_action (double score, double required_score, struct metric *metric);
+
#endif
diff --git a/src/protocol.c b/src/protocol.c
index 6806c0ea3..6ef5e5d84 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -620,57 +620,6 @@ show_metric_symbols (struct metric_result *metric_res, struct metric_callback_da
return TRUE;
}
-const gchar *
-str_action_metric (enum rspamd_metric_action action)
-{
- switch (action) {
- case METRIC_ACTION_REJECT:
- return "reject";
- case METRIC_ACTION_SOFT_REJECT:
- return "soft reject";
- case METRIC_ACTION_REWRITE_SUBJECT:
- return "rewrite subject";
- case METRIC_ACTION_ADD_HEADER:
- return "add header";
- case METRIC_ACTION_GREYLIST:
- return "greylist";
- case METRIC_ACTION_NOACTION:
- return "no action";
- }
-
- return "unknown action";
-}
-
-gint
-check_metric_action (double score, double required_score, struct metric *metric)
-{
- GList *cur;
- struct metric_action *action, *selected_action = NULL;
-
- if (score >= required_score) {
- return metric->action;
- }
- else if (metric->actions == NULL) {
- return METRIC_ACTION_NOACTION;
- }
- else {
- cur = metric->actions;
- while (cur) {
- action = cur->data;
- if (score >= action->score) {
- selected_action = action;
- }
- cur = g_list_next (cur);
- }
- if (selected_action) {
- return selected_action->action;
- }
- else {
- return METRIC_ACTION_NOACTION;
- }
- }
-}
-
static void
show_metric_result (gpointer metric_name, gpointer metric_value, void *user_data)
{
@@ -682,7 +631,7 @@ show_metric_result (gpointer metric_name, gpointer metric_value, void *user_data
struct metric *m;
gint is_spam = 0;
double ms = 0, rs = 0;
- enum rspamd_metric_action action;
+ enum rspamd_metric_action action = METRIC_ACTION_NOACTION;
if (! cd->alive) {
return;
@@ -730,10 +679,14 @@ show_metric_result (gpointer metric_name, gpointer metric_value, void *user_data
ms = metric_res->metric->required_score;
rs = metric_res->metric->reject_score;
}
+ if (! check_metric_action_settings (task, metric_res->metric, metric_res->score, &action)) {
+ action = check_metric_action (metric_res->score, ms, metric_res->metric);
+ }
+
if (metric_res->score >= ms) {
is_spam = 1;
}
- action = check_metric_action (metric_res->score, ms, metric_res->metric);
+
if (task->proto == SPAMC_PROTO) {
r = rspamd_snprintf (outbuf, sizeof (outbuf), "Spam: %s ; %.2f / %.2f" CRLF, (is_spam) ? "True" : "False", metric_res->score, ms);
}
diff --git a/src/protocol.h b/src/protocol.h
index e40f6db85..05e25c45a 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -77,7 +77,4 @@ gboolean write_reply (struct worker_task *task) G_GNUC_WARN_UNUSED_RESULT;
*/
void register_protocol_command (const gchar *name, protocol_reply_func func);
-const gchar *str_action_metric (enum rspamd_metric_action action);
-gint check_metric_action (double score, double required_score, struct metric *metric);
-
#endif
diff --git a/src/settings.c b/src/settings.c
index e2998984d..edfc5a21d 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -27,6 +27,7 @@
#include "map.h"
#include "main.h"
#include "settings.h"
+#include "filter.h"
#include "json/jansson.h"
struct json_buf {
@@ -37,6 +38,19 @@ struct json_buf {
};
static void
+settings_actions_free (gpointer data)
+{
+ GList *cur = data;
+
+ while (cur) {
+ g_free (cur->data);
+ cur = g_list_next (cur);
+ }
+
+ g_list_free ((GList *)data);
+}
+
+static void
settings_free (gpointer data)
{
struct rspamd_settings *s = data;
@@ -104,10 +118,12 @@ void
json_fin_cb (memory_pool_t * pool, struct map_cb_data *data)
{
struct json_buf *jb;
- gint nelts, i, n, a;
- json_t *js, *cur_elt, *cur_nm, *it_val;
+ gint nelts, i, n, j;
+ json_t *js, *cur_elt, *cur_nm, *it_val, *act_it, *act_value;
json_error_t je;
+ struct metric_action *new_act;
struct rspamd_settings *cur_settings;
+ GList *cur_act;
gchar *cur_name;
void *json_it;
double *score;
@@ -156,6 +172,7 @@ json_fin_cb (memory_pool_t * pool, struct map_cb_data *data)
cur_settings = g_malloc (sizeof (struct rspamd_settings));
cur_settings->metric_scores = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
cur_settings->reject_scores = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ cur_settings->metric_actions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, settings_actions_free);
cur_settings->factors = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
cur_settings->whitelist = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
cur_settings->statfile_alias = NULL;
@@ -201,7 +218,29 @@ json_fin_cb (memory_pool_t * pool, struct map_cb_data *data)
if (it_val && json_is_number (it_val)) {
score = g_malloc (sizeof (double));
*score = json_number_value (it_val);
- g_hash_table_insert (cur_settings->metric_scores, g_strdup (json_object_iter_key (json_it)), score);
+ g_hash_table_insert (cur_settings->metric_scores,
+ g_strdup (json_object_iter_key (json_it)), score);
+ }
+ else if (it_val && json_is_object (it_val)) {
+ /* Assume this as actions hash */
+ cur_act = NULL;
+ act_it = json_object_iter (it_val);
+ while (act_it) {
+ act_value = json_object_iter_value (act_it);
+ if (it_val && json_is_number (act_value)) {
+ if (check_action_str (json_object_iter_key (act_it), &j)) {
+ new_act = g_malloc (sizeof (struct metric_action));
+ new_act->action = j;
+ new_act->score = json_number_value (act_value);
+ cur_act = g_list_prepend (cur_act, new_act);
+ }
+ }
+ act_it = json_object_iter_next (it_val, act_it);
+ }
+ if (cur_act != NULL) {
+ g_hash_table_insert (cur_settings->metric_actions,
+ g_strdup (json_object_iter_key (json_it)), cur_act);
+ }
}
json_it = json_object_iter_next (cur_nm, json_it);
}
@@ -225,10 +264,11 @@ json_fin_cb (memory_pool_t * pool, struct map_cb_data *data)
cur_nm = json_object_get (cur_elt, "whitelist");
if (cur_nm != NULL && json_is_array (cur_nm)) {
n = json_array_size(cur_nm);
- for(a = 0; a < n; a++) {
- it_val = json_array_get(cur_nm, a);
+ for(j = 0; j < n; j++) {
+ it_val = json_array_get(cur_nm, j);
if (it_val && json_is_string (it_val)) {
- g_hash_table_insert (cur_settings->whitelist, g_strdup (json_string_value (it_val)), g_strdup (json_string_value (it_val)));
+ g_hash_table_insert (cur_settings->whitelist,
+ g_strdup (json_string_value (it_val)), g_strdup (json_string_value (it_val)));
}
}
@@ -391,6 +431,47 @@ check_metric_settings (struct worker_task * task, struct metric * metric, double
}
gboolean
+check_metric_action_settings (struct worker_task *task, struct metric *metric, double score, enum rspamd_metric_action *result)
+{
+ struct rspamd_settings *us = NULL, *ds = NULL;
+ struct metric_action *act;
+ GList *cur;
+ enum rspamd_metric_action res = METRIC_ACTION_NOACTION;
+
+ if (check_setting (task, &us, &ds)) {
+ if (us != NULL) {
+ if ((cur = g_hash_table_lookup (us->metric_actions, metric->name)) != NULL) {
+ while (cur) {
+ act = cur->data;
+ if (score >= act->score) {
+ res = act->action;
+ }
+ cur = g_list_next (cur);
+ }
+ }
+ }
+ else if (ds != NULL) {
+ if ((cur = g_hash_table_lookup (ds->metric_actions, metric->name)) != NULL) {
+ while (cur) {
+ act = cur->data;
+ if (score >= act->score) {
+ res = act->action;
+ }
+ cur = g_list_next (cur);
+ }
+ }
+ }
+ }
+
+ if (res != METRIC_ACTION_NOACTION && result != NULL) {
+ *result = res;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
check_factor_settings (struct worker_task * task, const gchar *symbol, double *factor)
{
struct rspamd_settings *us = NULL, *ds = NULL;
diff --git a/src/settings.h b/src/settings.h
index a1d712a87..43b70c2f0 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -7,6 +7,7 @@
struct rspamd_settings {
GHashTable *metric_scores; /**< hash table of metric require scores for this setting */
GHashTable *reject_scores; /**< hash table of metric reject scores for this setting */
+ GHashTable *metric_actions; /**< hash table of metric actions for this setting */
GHashTable *factors; /**< hash table of new factors for this setting */
GHashTable *whitelist; /**< hash table of whitelist for this setting */
gchar *statfile_alias; /**< alias for statfile used */
@@ -17,6 +18,7 @@ struct rspamd_settings {
gboolean read_settings (const gchar *path, struct config_file *cfg, GHashTable *table);
void init_settings (struct config_file *cfg);
gboolean check_metric_settings (struct worker_task *task, struct metric *metric, double *score, double *rscore);
+gboolean check_metric_action_settings (struct worker_task *task, struct metric *metric, double score, enum rspamd_metric_action *result);
gboolean check_factor_settings (struct worker_task *task, const gchar *symbol, double *factor);
gboolean check_want_spam (struct worker_task *task);