summaryrefslogtreecommitdiffstats
path: root/src/filter.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2008-11-01 18:01:05 +0300
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2008-11-01 18:01:05 +0300
commit2aa9c74f1c449da92f6faf870f8cc801a83bb08b (patch)
tree33f0f941f08583fd0c4c3653cadde8d6ce8426c2 /src/filter.c
parentcc5343692b448c27485a24ea7f1b24d714bb82f6 (diff)
downloadrspamd-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.c336
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);
+}