]> source.dussan.org Git - rspamd.git/commitdiff
* Make settings working
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Tue, 8 Sep 2009 16:13:29 +0000 (20:13 +0400)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Tue, 8 Sep 2009 16:13:29 +0000 (20:13 +0400)
rspamc.pl.in
src/cfg_file.l
src/cfg_file.y
src/cfg_utils.c
src/filter.c
src/main.h
src/protocol.c
src/settings.c
src/settings.h

index af2ea7a7e2397865f9133dd4dcdcb29bcd8f4d48..7e435bf36e1c10c8c10be41808e3e60e30d38fad 100755 (executable)
@@ -19,18 +19,20 @@ my %cfg = (
     'password'  =>  '',
     'control'   =>  0,
     'statfile'  =>  '',
+       'deliver_to'=>  '',
 );
 
 $main::VERSION = '@RSPAMD_VERSION@';
 
 sub HELP_MESSAGE {
     print <<EOD;
-Usage: rspamc.pl [-h host] [-p port] [-P password] [-c conf_file] [-s statfile] [command]
+Usage: rspamc.pl [-h host] [-p port] [-P password] [-c conf_file] [-s statfile] [-d user\@domain] [command]
 -h         host to connect or unix socket path
 -p         port to connect (not used with unix sockets)
--P         ask for control password
+-P         define control password
 -c         config file to parse
 -s         statfile to use for learn commands
+-d         define deliver-to header
 Version:   @RSPAMD_VERSION@
 EOD
 };
@@ -119,6 +121,9 @@ sub do_rspamc_command {
     print "Sending ". length ($input) ." bytes...\n";
 
     syswrite $sock, "$cfg{'command'} RSPAMC/1.0 $CRLF";
+       if ($cfg{'deliver_to'}) {
+               syswrite $sock, "Deliver-To: " . $cfg{'deliver_to'} . $CRLF;
+       }
     syswrite $sock, "Content-Length: " . length ($input) . $CRLF . $CRLF;
     syswrite $sock, $input;
     syswrite $sock, $CRLF;
@@ -222,7 +227,7 @@ sub do_control_command {
 }
 
 my %args;
-getopt('c:h:p:P:s:', \%args);
+getopt('c:h:p:P:s:d:', \%args);
 my $cmd = shift;
 my $do_parse_config = 1;
 
@@ -262,6 +267,9 @@ if (defined ($args{p})) {
 if (defined ($args{P})) {
     $cfg{'password'} = $args{P};
 }
+if (defined ($args{d})) {
+       $cfg{'deliver_to'} = $args{d};
+}
 
 if ($cmd =~ /(SYMBOLS|SCAN|PROCESS|CHECK|REPORT_IFSPAM|REPORT|URLS|EMAILS)/i) {
     $cfg{'command'} = $1;
index 1fcf000f47d3717cf1b3d13420343df47044d299..64c113a7139fc5c7795860a811e5651c1467b338 100644 (file)
@@ -55,6 +55,10 @@ servers                                                      return SERVERS;
 modules                                                        return MODULES;
 module_path                     return MODULE_PATH;
 
+settings                        return SETTINGS;
+user_settings                   return USER_SETTINGS;
+domain_settings                 return DOMAIN_SETTINGS;
+
 filters                                                        return FILTERS;
 factors                                                        return FACTORS;
 metric                                                 return METRIC;
index 46b3bf1107655f50284de447482956140d47c32a..19584be923fc26be1f23f2c48b349a8080ad4384 100644 (file)
@@ -9,6 +9,7 @@
 #include "classifiers/classifiers.h"
 #include "tokenizers/tokenizers.h"
 #include "view.h"
+#include "settings.h"
 #ifdef WITH_LUA
 #include "lua/lua_common.h"
 #else
@@ -57,6 +58,7 @@ struct rspamd_view *cur_view = NULL;
 %token DELIVERY LMTP ENABLED AGENT SECTION LUACODE RAW_MODE PROFILE_FILE COUNT
 %token  VIEW IP FROM SYMBOLS
 %token  AUTOLEARN MIN_MARK MAX_MARK
+%token  SETTINGS USER_SETTINGS DOMAIN_SETTINGS
 
 %type  <string>        STRING
 %type  <string>        VARIABLE
@@ -97,6 +99,7 @@ command       :
        | raw_mode
        | profile_file
        | view
+    | settings
        ;
 
 tempdir :
@@ -984,6 +987,37 @@ viewsymbols:
                }
        }
        ;
+
+settings:
+       SETTINGS OBRACE settingsbody EBRACE
+       ;
+
+settingsbody:
+       | settingscmd SEMICOLON
+       | settingsbody settingscmd SEMICOLON
+       ;
+
+settingscmd:
+       | usersettings
+       | domainsettings
+       ;
+
+usersettings:
+    USER_SETTINGS EQSIGN QUOTEDSTRING {
+        if (!read_settings ($3, cfg, cfg->user_settings)) {
+            yyerror ("yyparse: cannot read settings %s", $3);
+            YYERROR;
+        }
+    }
+    ;
+domainsettings:
+    DOMAIN_SETTINGS EQSIGN QUOTEDSTRING {
+        if (!read_settings ($3, cfg, cfg->domain_settings)) {
+            yyerror ("yyparse: cannot read settings %s", $3);
+            YYERROR;
+        }
+    }
+    ;
 %%
 /* 
  * vi:ts=4 
index 21092356f42def393909e50674bb89b8c9127f56..7d06e662c940cc591b04ee8854b2d0211e2784ab 100644 (file)
@@ -29,6 +29,7 @@
 #include "cfg_file.h"
 #include "main.h"
 #include "filter.h"
+#include "settings.h"
 #include "classifiers/classifiers.h"
 
 #define DEFAULT_SCORE 10.0
@@ -187,6 +188,7 @@ init_defaults (struct config_file *cfg)
        cfg->composite_symbols = g_hash_table_new (g_str_hash, g_str_equal);
        cfg->statfiles = g_hash_table_new (g_str_hash, g_str_equal);
        cfg->cfg_params = g_hash_table_new (g_str_hash, g_str_equal);
+       init_settings (cfg);
 
 }
 
index f35ed1dd690a71a3d0453a3de9a1623c2a8c908b..34e4871921c1e4a5d868b1b181116b4cf837666e 100644 (file)
@@ -34,6 +34,7 @@
 #include "cfg_file.h"
 #include "util.h"
 #include "expressions.h"
+#include "settings.h"
 #include "classifiers/classifiers.h"
 #include "tokenizers/tokenizers.h"
 
@@ -121,18 +122,23 @@ struct consolidation_callback_data {
 static void
 consolidation_callback (gpointer key, gpointer value, gpointer arg)
 {
-       double *factor;
+       double *factor, fs;
        struct symbol *s = (struct symbol *)value;
        struct consolidation_callback_data *data = (struct consolidation_callback_data *)arg;
-       
-       factor = g_hash_table_lookup (data->task->worker->srv->cfg->factors, key);
-       if (factor == NULL) {
-               msg_debug ("consolidation_callback: got %.2f score for metric %s, factor: 1", s->score, (char *)key);
-               data->score += s->score;
+
+       if (check_factor_settings (data->task, key, &fs)) {
+               data->score += fs * s->score;
        }
        else {
-               data->score += *factor * s->score;
-               msg_debug ("consolidation_callback: got %.2f score for metric %s, factor: %.2f", s->score, (char *)key, *factor);
+               factor = g_hash_table_lookup (data->task->worker->srv->cfg->factors, key);
+               if (factor == NULL) {
+                       msg_debug ("consolidation_callback: got %.2f score for metric %s, factor: 1", s->score, (char *)key);
+                       data->score += s->score;
+               }
+               else {
+                       data->score += *factor * s->score;
+                       msg_debug ("consolidation_callback: got %.2f score for metric %s, factor: %.2f", s->score, (char *)key, *factor);
+               }
        }
 }
 
@@ -229,11 +235,15 @@ static gboolean
 check_metric_is_spam (struct worker_task *task, struct metric *metric)
 {
        struct metric_result *res;
+       double ms;
 
        res = g_hash_table_lookup (task->results, metric->name);
        if (res) {
                metric_process_callback_forced (metric->name, res, task);
-               return res->score >= metric->required_score;
+               if (!check_metric_settings (task, metric, &ms)) {
+                       ms = metric->required_score;
+               }
+               return res->score >= ms;
        }
 
        return FALSE;
@@ -281,6 +291,11 @@ process_filters (struct worker_task *task)
                task->save.saved = 0;
                return continue_process_filters (task);
        }
+       /* Check want spam setting */
+       if (check_want_spam (task)) {
+               msg_info ("process_filters: disable check for message id <%s>, user wants spam", task->message_id);
+               return 1;
+       }
 
        /* Process metrics symbols */
        cur = task->worker->srv->cfg->metrics_list;
@@ -600,14 +615,18 @@ insert_metric_header (gpointer metric_name, gpointer metric_value, gpointer data
        char header_name[128], outbuf[1000];
        GList *symbols = NULL, *cur;
        struct metric_result *metric_res = (struct metric_result *)metric_value;
+       double ms;
        
        snprintf (header_name, sizeof (header_name), "X-Spam-%s", metric_res->metric->name);
 
-       if (metric_res->score >= metric_res->metric->required_score) {
-               r += snprintf (outbuf + r, sizeof (outbuf) - r, "yes; %.2f/%.2f; ", metric_res->score, metric_res->metric->required_score);
+       if (!check_metric_settings (task, metric_res->metric, &ms)) {
+               ms = metric_res->metric->required_score;
+       }
+       if (metric_res->score >= ms) {
+               r += snprintf (outbuf + r, sizeof (outbuf) - r, "yes; %.2f/%.2f; ", metric_res->score, ms);
        }
        else {
-               r += snprintf (outbuf + r, sizeof (outbuf) - r, "no; %.2f/%.2f; ", metric_res->score, metric_res->metric->required_score);
+               r += snprintf (outbuf + r, sizeof (outbuf) - r, "no; %.2f/%.2f; ", metric_res->score, ms);
        }
 
        symbols = g_hash_table_get_keys (metric_res->symbols);
index ef9a295371feae641aac8451e782792dea45ab79..bfc78e88808d75884d6c20210adb1015be3a24be 100644 (file)
@@ -180,6 +180,8 @@ struct worker_task {
        GList *rcpt;                                                                                            /**< recipients list                                                            */
        unsigned int nrcpt;                                                                                     /**< number of recipients                                                       */
        struct in_addr from_addr;                                                                       /**< client addr in numeric form                                        */
+       char *deliver_to;                                                                                       /**< address to deliver                                                         */
+       char *user;                                                                                                     /**< user to deliver                                                            */
        f_str_t *msg;                                                                                           /**< message buffer                                                                     */
        rspamd_io_dispatcher_t *dispatcher;                                                     /**< IO dispatcher object                                                       */
        memcached_ctx_t *memc_ctx;                                                                      /**< memcached context associated with task                     */
index 5374487df6dfc9695d88925a809fcee283c4abbf..176160381a3c88b408491d87df1a6df1e0c6517d 100644 (file)
@@ -26,6 +26,7 @@
 #include "main.h"
 #include "util.h"
 #include "cfg_file.h"
+#include "settings.h"
 
 /* Max line size as it is defined in rfc2822 */
 #define OUTBUFSIZ 1000
@@ -81,6 +82,7 @@
 #define QUEUE_ID_HEADER "Queue-ID"
 #define ERROR_HEADER "Error"
 #define USER_HEADER "User"
+#define DELIVER_TO_HEADER "Deliver-To"
 
 static GList *custom_commands = NULL;
 
@@ -255,6 +257,18 @@ parse_header (struct worker_task *task, f_str_t *line)
                                return -1;
                        }
                        break;
+               case 'd':
+               case 'D':
+                       /* Deliver-To */
+                       if (strncasecmp (headern, DELIVER_TO_HEADER, sizeof (DELIVER_TO_HEADER) - 1) == 0) {
+                               task->deliver_to = memory_pool_fstrdup (task->task_pool, line);
+                               msg_debug ("parse_header: read deliver-to header, value: %s", task->deliver_to);
+                       }
+                       else {
+                               msg_info ("parse_header: wrong header: %s", headern);
+                               return -1;
+                       }
+                       break;
                case 'h':
                case 'H':
                        /* helo */
@@ -337,6 +351,7 @@ parse_header (struct worker_task *task, f_str_t *line)
                case 'U':
                        if (strncasecmp (headern, USER_HEADER, sizeof (USER_HEADER) - 1) == 0) {
                                /* XXX: use this header somehow */
+                               task->user = memory_pool_fstrdup (task->task_pool, line);
                        }
                        else {
                                return -1;
@@ -495,36 +510,43 @@ show_metric_result (gpointer metric_name, gpointer metric_value, void *user_data
        struct metric_result *metric_res = (struct metric_result *)metric_value;
        struct metric *m;
        int is_spam = 0;
-
+       double ms;
+       
 
        if (metric_name == NULL || metric_value == NULL) {
                m = g_hash_table_lookup (task->cfg->metrics, "default");
+               if (!check_metric_settings (task, m, &ms)) {
+                       ms = m->required_score;
+               }
                if (task->proto == SPAMC_PROTO) {
                        r = snprintf (outbuf, sizeof (outbuf), "Spam: False ; 0 / %.2f" CRLF,
-                                               m != NULL ? m->required_score : 0);
+                                               m != NULL ? ms : 0);
                }
                else {
                        r = snprintf (outbuf, sizeof (outbuf), "Metric: default; False; 0 / %.2f" CRLF,
-                                               m != NULL ? m->required_score : 0);
+                                               m != NULL ? ms : 0);
                }
                cd->log_offset += snprintf (cd->log_buf + cd->log_offset, cd->log_size - cd->log_offset,
-                                               "(%s: F: [0/%.2f] [", "default", m != NULL ? m->required_score : 0); 
+                                               "(%s: F: [0/%.2f] [", "default", m != NULL ? ms : 0); 
        }
        else {
-               if (metric_res->score >= metric_res->metric->required_score) {
+               if (!check_metric_settings (task, metric_res->metric, &ms)) {
+                       ms = metric_res->metric->required_score;
+               }
+               if (metric_res->score >= ms) {
                        is_spam = 1;
                }
                if (task->proto == SPAMC_PROTO) {
                        r = snprintf (outbuf, sizeof (outbuf), "Spam: %s ; %.2f / %.2f" CRLF,
-                                               (is_spam) ? "True" : "False", metric_res->score, metric_res->metric->required_score);
+                                               (is_spam) ? "True" : "False", metric_res->score, ms);
                }
                else {
                        r = snprintf (outbuf, sizeof (outbuf), "Metric: %s; %s; %.2f / %.2f" CRLF, (char *)metric_name,
-                                               (is_spam) ? "True" : "False", metric_res->score, metric_res->metric->required_score);
+                                               (is_spam) ? "True" : "False", metric_res->score, ms);
                }
                cd->log_offset += snprintf (cd->log_buf + cd->log_offset, cd->log_size - cd->log_offset,
                                                "(%s: %s: [%.2f/%.2f] [", (char *)metric_name, is_spam ? "T" : "F", 
-                                               metric_res->score, metric_res->metric->required_score); 
+                                               metric_res->score, ms); 
        }
        if (task->cmd == CMD_PROCESS) {
 #ifndef GMIME24
index f05f59b456c1611a12d7bfe708cab7cbf2479f3f..75ba04c764809fe526f6008ec61fbb78903d629f 100644 (file)
@@ -73,9 +73,9 @@ json_read_cb (memory_pool_t *pool, u_char *chunk, size_t len, struct map_cb_data
 
        if (jb->buf == NULL) {
                /* Allocate memory for buffer */
-               jb->pos = jb->buf;
                jb->buflen = len * 2;
                jb->buf = g_malloc (jb->buflen);
+               jb->pos = jb->buf;
        }
 
        off = jb->pos - jb->buf;
@@ -87,7 +87,7 @@ json_read_cb (memory_pool_t *pool, u_char *chunk, size_t len, struct map_cb_data
                jb->pos = jb->buf + off;
        }
 
-       memcpy (chunk, jb->pos, len);
+       memcpy (jb->pos, chunk, len);
        jb->pos += len;
        
        /* Say not to copy any part of this buffer */
@@ -115,10 +115,21 @@ json_fin_cb (memory_pool_t *pool, struct map_cb_data *data)
                if (jb->buf) {
                        g_free (jb->buf);
                }
-               g_free (jb->buf);
+               g_free (jb);
        }
 
        /* Now parse json */
+       if (data->cur_data) {
+               jb = data->cur_data;
+       }
+       else {
+               msg_err ("json_fin_cb: no data read");
+               return;
+       }
+       if (jb->buf == NULL) {
+               msg_err ("json_fin_cb: no data read");
+               return;
+       }
        /* NULL terminate current buf */
        *jb->pos = '\0';
 
@@ -183,7 +194,7 @@ 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->factors, g_strdup (json_object_iter_key (json_it)), 
+                                       g_hash_table_insert (cur_settings->metric_scores, g_strdup (json_object_iter_key (json_it)), 
                                                                                        score);
                                }
                                json_it = json_object_iter_next(cur_nm, json_it);
@@ -204,12 +215,15 @@ json_fin_cb (memory_pool_t *pool, struct map_cb_data *data)
 gboolean
 read_settings (const char *path, struct config_file *cfg, GHashTable *table)
 {
-       struct json_buf *jb = g_malloc (sizeof (struct json_buf));
+       struct json_buf *jb = g_malloc (sizeof (struct json_buf)), **pjb;
+
+       pjb = g_malloc (sizeof (struct json_buf *));
        
        jb->table = table;
        jb->buf = NULL;
+       *pjb = jb;
 
-       if (!add_map (path, json_read_cb, json_fin_cb, (void **)&jb)) {
+       if (!add_map (path, json_read_cb, json_fin_cb, (void **)pjb)) {
                msg_err ("read_settings: cannot add map %s", path);
                return FALSE;
        }
@@ -224,6 +238,141 @@ init_settings (struct config_file *cfg)
        cfg->user_settings = g_hash_table_new_full (rspamd_strcase_hash, rspamd_strcase_equal, g_free, settings_free);
 }
 
+static gboolean
+check_setting (struct worker_task *task, struct rspamd_settings **user_settings, struct rspamd_settings **domain_settings)
+{
+       char *field = NULL, *domain = NULL;
+
+       if (task->deliver_to != NULL) {
+               /* First try to use deliver-to field */
+               field = task->deliver_to;
+       }
+       else if (task->user != NULL) {
+               /* Then user field */
+               field = task->user;
+       }
+       else if (task->rcpt != NULL) {
+               /* Then first recipient */
+               field = task->rcpt->data;
+       }
+       else {
+               return FALSE;
+       }
+
+       domain = strchr (field, '@');
+       if (domain == NULL) {
+               /* First try to search in first recipient */
+               if (task->rcpt) {
+                       domain = strchr (task->rcpt->data, '@');
+               }
+       }
+       if (domain != NULL) {
+               domain ++;
+       }
+       
+       /* First try to search per-user settings */
+       if (field != NULL) {
+               *user_settings = g_hash_table_lookup (task->cfg->user_settings, field);
+       }
+       if (domain != NULL) {
+               *domain_settings = g_hash_table_lookup (task->cfg->domain_settings, domain);
+       }
+
+       if (*domain_settings != NULL || *user_settings != NULL) {
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+gboolean 
+check_metric_settings (struct worker_task *task, struct metric *metric, double *score)
+{
+       struct rspamd_settings *us, *ds;
+       double *sc;
+
+       if (check_setting (task, &us, &ds)) {
+               if (us != NULL) {
+                       /* First search in user's settings */
+                       if ((sc = g_hash_table_lookup (us->metric_scores, metric->name)) != NULL) {
+                               *score = *sc;
+                               return TRUE;
+                       }
+                       /* Now check in domain settings */
+                       if (ds && (sc = g_hash_table_lookup (ds->metric_scores, metric->name)) != NULL) {
+                               *score = *sc;
+                               return TRUE;
+                       }
+               }
+               else if (ds != NULL) {
+                       if ((sc = g_hash_table_lookup (ds->metric_scores, metric->name)) != NULL) {
+                               *score = *sc;
+                               return TRUE;
+                       }
+               }
+       }
+       
+       return FALSE;
+}
+
+gboolean 
+check_factor_settings (struct worker_task *task, const char *symbol, double *factor)
+{
+       struct rspamd_settings *us, *ds;
+       double *fc;
+
+       if (check_setting (task, &us, &ds)) {
+               if (us != NULL) {
+                       /* First search in user's settings */
+                       if ((fc = g_hash_table_lookup (us->factors, symbol)) != NULL) {
+                               *factor = *fc;
+                               return TRUE;
+                       }
+                       /* Now check in domain settings */
+                       if (ds && (fc = g_hash_table_lookup (ds->factors, symbol)) != NULL) {
+                               *factor = *fc;
+                               return TRUE;
+                       }
+               }
+               else if (ds != NULL) {
+                       if ((fc = g_hash_table_lookup (ds->factors, symbol)) != NULL) {
+                               *factor = *fc;
+                               return TRUE;
+                       }
+               }
+       }
+       
+       return FALSE;
+
+}
+
+
+gboolean 
+check_want_spam (struct worker_task *task)
+{
+       struct rspamd_settings *us, *ds;
+
+       if (check_setting (task, &us, &ds)) {
+               if (us != NULL) {
+                       /* First search in user's settings */
+                       if (us->want_spam) {
+                               return TRUE;
+                       }
+                       /* Now check in domain settings */
+                       if (ds && ds->want_spam) {
+                               return TRUE;
+                       }
+               }
+               else if (ds != NULL) {
+                       if (ds->want_spam) {
+                               return TRUE;
+                       }
+               }
+       }
+       
+       return FALSE;
+}
+
 /* 
  * vi:ts=4 
  */
index 8d2214ae199c1b862917d7b4e26c69f23eb66dc4..696bd9d76c2433c01f192cb1501afde72720eff7 100644 (file)
@@ -12,6 +12,10 @@ struct rspamd_settings {
 };
 
 
-int read_settings (const char *path, struct config_file *cfg, GHashTable *table);
+gboolean read_settings (const char *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);
+gboolean check_factor_settings (struct worker_task *task, const char *symbol, double *factor);
+gboolean check_want_spam (struct worker_task *task);
 
 #endif