diff options
author | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2008-11-01 18:01:05 +0300 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2008-11-01 18:01:05 +0300 |
commit | 2aa9c74f1c449da92f6faf870f8cc801a83bb08b (patch) | |
tree | 33f0f941f08583fd0c4c3653cadde8d6ce8426c2 /src/filter.c | |
parent | cc5343692b448c27485a24ea7f1b24d714bb82f6 (diff) | |
download | rspamd-2aa9c74f1c449da92f6faf870f8cc801a83bb08b.tar.gz rspamd-2aa9c74f1c449da92f6faf870f8cc801a83bb08b.zip |
* Reorganize structure of source files
* Adopt build system for new structure
--HG--
rename : cfg_file.h => src/cfg_file.h
rename : cfg_file.l => src/cfg_file.l
rename : cfg_file.y => src/cfg_file.y
rename : cfg_utils.c => src/cfg_utils.c
rename : controller.c => src/controller.c
rename : filter.c => src/filter.c
rename : filter.h => src/filter.h
rename : fstring.c => src/fstring.c
rename : fstring.h => src/fstring.h
rename : main.c => src/main.c
rename : main.h => src/main.h
rename : mem_pool.c => src/mem_pool.c
rename : mem_pool.h => src/mem_pool.h
rename : memcached-test.c => src/memcached-test.c
rename : memcached.c => src/memcached.c
rename : memcached.h => src/memcached.h
rename : perl.c => src/perl.c
rename : perl.h => src/perl.h
rename : plugins/regexp.c => src/plugins/regexp.c
rename : plugins/surbl.c => src/plugins/surbl.c
rename : protocol.c => src/protocol.c
rename : protocol.h => src/protocol.h
rename : upstream.c => src/upstream.c
rename : upstream.h => src/upstream.h
rename : url.c => src/url.c
rename : url.h => src/url.h
rename : util.c => src/util.c
rename : util.h => src/util.h
rename : worker.c => src/worker.c
Diffstat (limited to 'src/filter.c')
-rw-r--r-- | src/filter.c | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/src/filter.c b/src/filter.c new file mode 100644 index 000000000..d1edbb930 --- /dev/null +++ b/src/filter.c @@ -0,0 +1,336 @@ +#include <sys/types.h> +#include <glib.h> +#include <string.h> +#include <stdlib.h> + +#include "mem_pool.h" +#include "filter.h" +#include "main.h" +#include "cfg_file.h" +#include "perl.h" + +void +insert_result (struct worker_task *task, const char *metric_name, const char *symbol, u_char flag) +{ + struct metric *metric; + struct metric_result *metric_res; + + metric = g_hash_table_lookup (task->worker->srv->cfg->metrics, metric_name); + if (metric == NULL) { + return; + } + + metric_res = g_hash_table_lookup (task->results, metric_name); + + if (metric_res == NULL) { + /* Create new metric chain */ + metric_res = memory_pool_alloc (task->task_pool, sizeof (struct metric_result)); + metric_res->symbols = g_hash_table_new (g_str_hash, g_str_equal); + memory_pool_add_destructor (task->task_pool, (pool_destruct_func)g_hash_table_destroy, metric_res->symbols); + metric_res->metric = metric; + g_hash_table_insert (task->results, (gpointer)metric_name, metric_res); + } + + g_hash_table_insert (metric_res->symbols, (gpointer)symbol, GSIZE_TO_POINTER (flag)); +} + +/* + * Default consolidation function based on factors in config file + */ +double +factor_consolidation_func (struct worker_task *task, const char *metric_name) +{ + struct metric_result *metric_res; + double *factor; + double res = 0.; + GList *symbols = NULL, *cur; + + metric_res = g_hash_table_lookup (task->results, metric_name); + if (metric_res == NULL) { + return res; + } + + symbols = g_hash_table_get_keys (metric_res->symbols); + cur = g_list_first (symbols); + while (cur) { + factor = g_hash_table_lookup (task->worker->srv->cfg->factors, cur->data); + if (factor == NULL) { + /* Default multiplier is 1 */ + res ++; + } + else { + res += *factor; + } + cur = g_list_next (cur); + } + + g_list_free (symbols); + + return res; +} + +/* + * Call perl or C module function for specified part of message + */ +static void +call_filter_by_name (struct worker_task *task, const char *name, enum script_type sc_type, enum filter_type filt_type) +{ + struct module_ctx *c_module; + + switch (filt_type) { + case C_FILTER: + c_module = g_hash_table_lookup (task->worker->srv->cfg->c_modules, name); + if (c_module) { + switch (filt_type) { + case SCRIPT_HEADER: + c_module->header_filter (task); + break; + case SCRIPT_MIME: + c_module->mime_filter (task); + break; + case SCRIPT_URL: + c_module->url_filter (task); + break; + case SCRIPT_MESSAGE: + c_module->message_filter (task); + break; + } + } + break; + case PERL_FILTER: + switch (filt_type) { + case SCRIPT_HEADER: + perl_call_header_filter (name, task); + break; + case SCRIPT_MIME: + perl_call_mime_filter (name, task); + break; + case SCRIPT_URL: + perl_call_url_filter (name, task); + break; + case SCRIPT_MESSAGE: + perl_call_message_filter (name, task); + break; + } + break; + } +} + +static void +metric_process_callback (gpointer key, gpointer value, void *data) +{ + struct worker_task *task = (struct worker_task *)data; + struct metric_result *metric_res = (struct metric_result *)value; + + if (metric_res->metric->func != NULL) { + metric_res->score = metric_res->metric->func (task, metric_res->metric->name); + } + else { + metric_res->score = factor_consolidation_func (task, metric_res->metric->name); + } +} + +static int +continue_process_filters (struct worker_task *task) +{ + struct filter *cur = task->save.entry; + + cur = LIST_NEXT (cur, next); + /* Note: no breaks in this case! */ + switch (task->save.type) { + case SCRIPT_HEADER: + while (cur) { + call_filter_by_name (task, cur->func_name, cur->type, SCRIPT_HEADER); + if (task->save.saved) { + task->save.entry = cur; + task->save.type = SCRIPT_HEADER; + return 0; + } + cur = LIST_NEXT (cur, next); + } + /* Process mime filters */ + cur = LIST_FIRST (&task->worker->srv->cfg->mime_filters); + case SCRIPT_MIME: + while (cur) { + call_filter_by_name (task, cur->func_name, cur->type, SCRIPT_MIME); + if (task->save.saved) { + task->save.entry = cur; + task->save.type = SCRIPT_MIME; + return 0; + } + cur = LIST_NEXT (cur, next); + } + /* Process url filters */ + cur = LIST_FIRST (&task->worker->srv->cfg->url_filters); + case SCRIPT_URL: + while (cur) { + call_filter_by_name (task, cur->func_name, cur->type, SCRIPT_URL); + if (task->save.saved) { + task->save.entry = cur; + task->save.type = SCRIPT_URL; + return 0; + } + cur = LIST_NEXT (cur, next); + } + /* Process message filters */ + cur = LIST_FIRST (&task->worker->srv->cfg->message_filters); + case SCRIPT_MESSAGE: + while (cur) { + call_filter_by_name (task, cur->func_name, cur->type, SCRIPT_MESSAGE); + if (task->save.saved) { + task->save.entry = cur; + task->save.type = SCRIPT_MESSAGE; + return 0; + } + cur = LIST_NEXT (cur, next); + } + /* All done */ + return 1; + } +} + +int +process_filters (struct worker_task *task) +{ + struct filter *cur; + + if (task->save.saved) { + task->save.saved = 0; + return continue_process_filters (task); + } + + /* Process filters in order that they are listed in config file */ + LIST_FOREACH (cur, &task->worker->srv->cfg->header_filters, next) { + call_filter_by_name (task, cur->func_name, cur->type, SCRIPT_HEADER); + if (task->save.saved) { + task->save.entry = cur; + task->save.type = SCRIPT_HEADER; + return 0; + } + } + + LIST_FOREACH (cur, &task->worker->srv->cfg->mime_filters, next) { + call_filter_by_name (task, cur->func_name, cur->type, SCRIPT_MIME); + if (task->save.saved) { + task->save.entry = cur; + task->save.type = SCRIPT_MIME; + return 0; + } + } + + LIST_FOREACH (cur, &task->worker->srv->cfg->url_filters, next) { + call_filter_by_name (task, cur->func_name, cur->type, SCRIPT_URL); + if (task->save.saved) { + task->save.entry = cur; + task->save.type = SCRIPT_URL; + return 0; + } + } + + LIST_FOREACH (cur, &task->worker->srv->cfg->message_filters, next) { + call_filter_by_name (task, cur->func_name, cur->type, SCRIPT_MESSAGE); + if (task->save.saved) { + task->save.entry = cur; + task->save.type = SCRIPT_MESSAGE; + return 0; + } + } + + /* Process all metrics */ + g_hash_table_foreach (task->results, metric_process_callback, task); + return 1; +} + +struct composites_data { + struct worker_task *task; + struct metric_result *metric_res; +}; + +static void +composites_foreach_callback (gpointer key, gpointer value, void *data) +{ + struct composites_data *cd = (struct composites_data *)data; + struct expression *expr = (struct expression *)value; + GQueue *stack; + GList *symbols = NULL, *s; + gsize cur, op1, op2; + + stack = g_queue_new (); + + while (expr) { + if (expr->type == EXPR_OPERAND) { + /* Find corresponding symbol */ + if (g_hash_table_lookup (cd->metric_res->symbols, expr->content.operand) == NULL) { + cur = 0; + } + else { + cur = 1; + symbols = g_list_append (symbols, expr->content.operand); + } + g_queue_push_head (stack, GSIZE_TO_POINTER (cur)); + } + else { + if (g_queue_is_empty (stack)) { + /* Queue has no operands for operation, exiting */ + g_list_free (symbols); + g_queue_free (stack); + return; + } + switch (expr->content.operation) { + case '!': + op1 = GPOINTER_TO_SIZE (g_queue_pop_head (stack)); + op1 = !op1; + g_queue_push_head (stack, GSIZE_TO_POINTER (op1)); + break; + case '&': + op1 = GPOINTER_TO_SIZE (g_queue_pop_head (stack)); + op2 = GPOINTER_TO_SIZE (g_queue_pop_head (stack)); + g_queue_push_head (stack, GSIZE_TO_POINTER (op1 && op2)); + case '|': + op1 = GPOINTER_TO_SIZE (g_queue_pop_head (stack)); + op2 = GPOINTER_TO_SIZE (g_queue_pop_head (stack)); + g_queue_push_head (stack, GSIZE_TO_POINTER (op1 || op2)); + default: + expr = expr->next; + continue; + } + } + expr = expr->next; + } + if (!g_queue_is_empty (stack)) { + op1 = GPOINTER_TO_SIZE (g_queue_pop_head (stack)); + if (op1) { + /* Remove all symbols that are in composite symbol */ + s = g_list_first (symbols); + while (s) { + g_hash_table_remove (cd->metric_res->symbols, s->data); + s = g_list_next (s); + } + /* Add new symbol */ + g_hash_table_insert (cd->metric_res->symbols, key, GSIZE_TO_POINTER (op1)); + } + } + + g_queue_free (stack); + g_list_free (symbols); + + return; +} + +static void +composites_metric_callback (gpointer key, gpointer value, void *data) +{ + struct worker_task *task = (struct worker_task *)data; + struct composites_data *cd = memory_pool_alloc (task->task_pool, sizeof (struct composites_data)); + struct metric_result *metric_res = (struct metric_result *)value; + + cd->task = task; + cd->metric_res = (struct metric_result *)metric_res; + + g_hash_table_foreach (task->cfg->composite_symbols, composites_foreach_callback, cd); +} + +void make_composites (struct worker_task *task) +{ + g_hash_table_foreach (task->results, composites_metric_callback, task); +} |