aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2009-09-08 20:13:29 +0400
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2009-09-08 20:13:29 +0400
commitc6d4570aa00c93e6d142aaa8cd38a3c9ee29eb8f (patch)
tree51fd7b69c3cee4817daca44c15ea2576f3e37d68 /src
parent9af09b7467a4b9b7b2c9fbf1390b481e71bb07c6 (diff)
downloadrspamd-c6d4570aa00c93e6d142aaa8cd38a3c9ee29eb8f.tar.gz
rspamd-c6d4570aa00c93e6d142aaa8cd38a3c9ee29eb8f.zip
* Make settings working
Diffstat (limited to 'src')
-rw-r--r--src/cfg_file.l4
-rw-r--r--src/cfg_file.y34
-rw-r--r--src/cfg_utils.c2
-rw-r--r--src/filter.c43
-rw-r--r--src/main.h2
-rw-r--r--src/protocol.c38
-rw-r--r--src/settings.c161
-rw-r--r--src/settings.h6
8 files changed, 263 insertions, 27 deletions
diff --git a/src/cfg_file.l b/src/cfg_file.l
index 1fcf000f4..64c113a71 100644
--- a/src/cfg_file.l
+++ b/src/cfg_file.l
@@ -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;
diff --git a/src/cfg_file.y b/src/cfg_file.y
index 46b3bf110..19584be92 100644
--- a/src/cfg_file.y
+++ b/src/cfg_file.y
@@ -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
diff --git a/src/cfg_utils.c b/src/cfg_utils.c
index 21092356f..7d06e662c 100644
--- a/src/cfg_utils.c
+++ b/src/cfg_utils.c
@@ -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);
}
diff --git a/src/filter.c b/src/filter.c
index f35ed1dd6..34e487192 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -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);
diff --git a/src/main.h b/src/main.h
index ef9a29537..bfc78e888 100644
--- a/src/main.h
+++ b/src/main.h
@@ -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 */
diff --git a/src/protocol.c b/src/protocol.c
index 5374487df..176160381 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -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
diff --git a/src/settings.c b/src/settings.c
index f05f59b45..75ba04c76 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -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
*/
diff --git a/src/settings.h b/src/settings.h
index 8d2214ae1..696bd9d76 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -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