]> source.dussan.org Git - rspamd.git/commitdiff
* Add ability to recursive scan over multipart's parts for functions:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Wed, 20 Oct 2010 18:26:34 +0000 (22:26 +0400)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Wed, 20 Oct 2010 18:26:34 +0000 (22:26 +0400)
 - 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.

src/cfg_xml.c
src/expressions.c
src/filter.c
src/filter.h
src/protocol.c
src/protocol.h
src/settings.c
src/settings.h

index 5e0d69a4cc28d0791fd3a4f0b04d82aef3b2ebf5..2e762ba1e02286f118a37a846b0295598bac16b2 100644 (file)
@@ -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 {
index 9d17a146cd8c441e4b819d66d7ca9bbf60dec441..c4fa738b52f5ac81b81211b72e9e0eda88df3909 100644 (file)
@@ -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;
index 53beb762ed82485a09b701f8aed19485912e74cf..9cc6e542f834be93ef23aa3b8324026b3f67cd01 100644 (file)
@@ -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 
  */
index bc8d98de5933c9929a89d3d916425f25f523f36c..2540d95e9cbf007584d11aa40bb6d826a15906d2 100644 (file)
@@ -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
index 6806c0ea363d01419166c10408468742ec178827..6ef5e5d8491acf22e06f4952745d72265f678d72 100644 (file)
@@ -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);
                }
index e40f6db85e54f3853f7647eb8adc9bec9e716f06..05e25c45afe6558549f138bc960fa9d4984d9a41 100644 (file)
@@ -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
index e2998984d5e8b9205e273a0104706c490fc22869..edfc5a21d849cf0d9a262151ac48690f1c07658e 100644 (file)
@@ -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)
 {
index a1d712a8722a55062e9d7d96e055ccbc45ccb86c..43b70c2f04fc1bca35189efd9e71010f7b21e7bd 100644 (file)
@@ -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);