- content_type_is_type - content_type_is_subtype - content_type_compare_param - content_type_has_param * Add ability to specify any of actions in user's settings, not only reject.tags/0.3.3
@@ -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 { |
@@ -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; |
@@ -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 | |||
*/ |
@@ -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 |
@@ -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); | |||
} |
@@ -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 |
@@ -27,6 +27,7 @@ | |||
#include "map.h" | |||
#include "main.h" | |||
#include "settings.h" | |||
#include "filter.h" | |||
#include "json/jansson.h" | |||
struct json_buf { | |||
@@ -36,6 +37,19 @@ struct json_buf { | |||
size_t buflen; | |||
}; | |||
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) | |||
{ | |||
@@ -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))); | |||
} | |||
} | |||
@@ -390,6 +430,47 @@ check_metric_settings (struct worker_task * task, struct metric * metric, double | |||
return FALSE; | |||
} | |||
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) | |||
{ |
@@ -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); | |||