diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2014-07-23 12:45:28 +0100 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2014-07-23 12:45:28 +0100 |
commit | e0483657ff6cf1adc828ccce457814d61fe90a0d (patch) | |
tree | 5183e4163f40b81b3e7d5f51488d360883782154 /src/libmime | |
parent | 7962087e808fb824aa3af6d41d02abc92916ba1e (diff) | |
download | rspamd-e0483657ff6cf1adc828ccce457814d61fe90a0d.tar.gz rspamd-e0483657ff6cf1adc828ccce457814d61fe90a0d.zip |
Unify code style.
Diffstat (limited to 'src/libmime')
-rw-r--r-- | src/libmime/expressions.c | 553 | ||||
-rw-r--r-- | src/libmime/expressions.h | 53 | ||||
-rw-r--r-- | src/libmime/filter.c | 529 | ||||
-rw-r--r-- | src/libmime/filter.h | 68 | ||||
-rw-r--r-- | src/libmime/images.c | 56 | ||||
-rw-r--r-- | src/libmime/images.h | 2 | ||||
-rw-r--r-- | src/libmime/message.c | 918 | ||||
-rw-r--r-- | src/libmime/message.h | 17 | ||||
-rw-r--r-- | src/libmime/smtp_proto.c | 799 | ||||
-rw-r--r-- | src/libmime/smtp_proto.h | 24 | ||||
-rw-r--r-- | src/libmime/smtp_utils.c | 220 | ||||
-rw-r--r-- | src/libmime/smtp_utils.h | 5 |
12 files changed, 1986 insertions, 1258 deletions
diff --git a/src/libmime/expressions.c b/src/libmime/expressions.c index 5d19626bb..c17388315 100644 --- a/src/libmime/expressions.c +++ b/src/libmime/expressions.c @@ -22,36 +22,56 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" -#include "util.h" #include "cfg_file.h" -#include "main.h" -#include "message.h" -#include "fuzzy.h" +#include "config.h" +#include "diff.h" #include "expressions.h" +#include "fuzzy.h" #include "html.h" #include "lua/lua_common.h" -#include "diff.h" +#include "main.h" +#include "message.h" +#include "util.h" -gboolean rspamd_compare_encoding (struct rspamd_task *task, GList * args, void *unused); -gboolean rspamd_header_exists (struct rspamd_task *task, GList * args, void *unused); -gboolean rspamd_parts_distance (struct rspamd_task *task, GList * args, void *unused); -gboolean rspamd_recipients_distance (struct rspamd_task *task, GList * args, void *unused); -gboolean rspamd_has_only_html_part (struct rspamd_task *task, GList * args, void *unused); -gboolean rspamd_is_recipients_sorted (struct rspamd_task *task, GList * args, void *unused); -gboolean rspamd_compare_transfer_encoding (struct rspamd_task *task, GList * args, void *unused); -gboolean rspamd_is_html_balanced (struct rspamd_task *task, GList * args, void *unused); -gboolean rspamd_has_html_tag (struct rspamd_task *task, GList * args, void *unused); -gboolean rspamd_has_fake_html (struct rspamd_task *task, GList * args, void *unused); +gboolean rspamd_compare_encoding (struct rspamd_task *task, + GList * args, + void *unused); +gboolean rspamd_header_exists (struct rspamd_task *task, + GList * args, + void *unused); +gboolean rspamd_parts_distance (struct rspamd_task *task, + GList * args, + void *unused); +gboolean rspamd_recipients_distance (struct rspamd_task *task, + GList * args, + void *unused); +gboolean rspamd_has_only_html_part (struct rspamd_task *task, + GList * args, + void *unused); +gboolean rspamd_is_recipients_sorted (struct rspamd_task *task, + GList * args, + void *unused); +gboolean rspamd_compare_transfer_encoding (struct rspamd_task *task, + GList * args, + void *unused); +gboolean rspamd_is_html_balanced (struct rspamd_task *task, + GList * args, + void *unused); +gboolean rspamd_has_html_tag (struct rspamd_task *task, + GList * args, + void *unused); +gboolean rspamd_has_fake_html (struct rspamd_task *task, + GList * args, + void *unused); /* * List of internal functions of rspamd * Sorted by name to use bsearch */ static struct _fl { - const gchar *name; - rspamd_internal_func_t func; - void *user_data; + const gchar *name; + rspamd_internal_func_t func; + void *user_data; } rspamd_functions_list[] = { {"compare_encoding", rspamd_compare_encoding, NULL}, {"compare_parts_distance", rspamd_parts_distance, NULL}, @@ -65,30 +85,32 @@ static struct _fl { {"is_recipients_sorted", rspamd_is_recipients_sorted, NULL} }; -static struct _fl *list_ptr = &rspamd_functions_list[0]; -static guint32 functions_number = sizeof (rspamd_functions_list) / sizeof (struct _fl); -static gboolean list_allocated = FALSE; +static struct _fl *list_ptr = &rspamd_functions_list[0]; +static guint32 functions_number = sizeof (rspamd_functions_list) / + sizeof (struct _fl); +static gboolean list_allocated = FALSE; /* Bsearch routine */ static gint fl_cmp (const void *s1, const void *s2) { - struct _fl *fl1 = (struct _fl *)s1; - struct _fl *fl2 = (struct _fl *)s2; + struct _fl *fl1 = (struct _fl *)s1; + struct _fl *fl2 = (struct _fl *)s2; return strcmp (fl1->name, fl2->name); } /* Cache for regular expressions that are used in functions */ -void * +void * re_cache_check (const gchar *line, rspamd_mempool_t *pool) { - GHashTable *re_cache; - + GHashTable *re_cache; + re_cache = rspamd_mempool_get_variable (pool, "re_cache"); if (re_cache == NULL) { re_cache = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); - rspamd_mempool_set_variable (pool, "re_cache", re_cache, (rspamd_mempool_destruct_t)g_hash_table_destroy); + rspamd_mempool_set_variable (pool, "re_cache", re_cache, + (rspamd_mempool_destruct_t)g_hash_table_destroy); return NULL; } return g_hash_table_lookup (re_cache, line); @@ -97,13 +119,14 @@ re_cache_check (const gchar *line, rspamd_mempool_t *pool) void re_cache_add (const gchar *line, void *pointer, rspamd_mempool_t *pool) { - GHashTable *re_cache; - + GHashTable *re_cache; + re_cache = rspamd_mempool_get_variable (pool, "re_cache"); if (re_cache == NULL) { re_cache = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); - rspamd_mempool_set_variable (pool, "re_cache", re_cache, (rspamd_mempool_destruct_t)g_hash_table_destroy); + rspamd_mempool_set_variable (pool, "re_cache", re_cache, + (rspamd_mempool_destruct_t)g_hash_table_destroy); } g_hash_table_insert (re_cache, (gpointer)line, pointer); @@ -112,7 +135,7 @@ re_cache_add (const gchar *line, void *pointer, rspamd_mempool_t *pool) void re_cache_del (const gchar *line, rspamd_mempool_t *pool) { - GHashTable *re_cache; + GHashTable *re_cache; re_cache = rspamd_mempool_get_variable (pool, "re_cache"); @@ -126,17 +149,19 @@ re_cache_del (const gchar *line, rspamd_mempool_t *pool) * Functions for parsing expressions */ struct expression_stack { - gchar op; - struct expression_stack *next; + gchar op; + struct expression_stack *next; }; /* - * Push operand or operator to stack + * Push operand or operator to stack */ static struct expression_stack * -push_expression_stack (rspamd_mempool_t * pool, struct expression_stack *head, gchar op) +push_expression_stack (rspamd_mempool_t * pool, + struct expression_stack *head, + gchar op) { - struct expression_stack *new; + struct expression_stack *new; new = rspamd_mempool_alloc (pool, sizeof (struct expression_stack)); new->op = op; new->next = head; @@ -149,8 +174,8 @@ push_expression_stack (rspamd_mempool_t * pool, struct expression_stack *head, g static gchar delete_expression_stack (struct expression_stack **head) { - struct expression_stack *cur; - gchar res; + struct expression_stack *cur; + gchar res; if (*head == NULL) return 0; @@ -185,7 +210,7 @@ logic_priority (gchar a) * Return FALSE if symbol is not operation symbol (operand) * Return TRUE if symbol is operation symbol */ -static gboolean +static gboolean is_operation_symbol (gchar *a) { switch (*a) { @@ -197,19 +222,22 @@ is_operation_symbol (gchar *a) return TRUE; case 'O': case 'o': - if (g_ascii_strncasecmp (a, "or", sizeof ("or") - 1) == 0&& g_ascii_isspace (a[2])) { + if (g_ascii_strncasecmp (a, "or", + sizeof ("or") - 1) == 0 && g_ascii_isspace (a[2])) { return TRUE; } break; case 'A': case 'a': - if (g_ascii_strncasecmp (a, "and", sizeof ("and") - 1) == 0&& g_ascii_isspace (a[3])) { + if (g_ascii_strncasecmp (a, "and", + sizeof ("and") - 1) == 0 && g_ascii_isspace (a[3])) { return TRUE; } break; case 'N': case 'n': - if (g_ascii_strncasecmp (a, "not", sizeof ("not") - 1) == 0 && g_ascii_isspace (a[3])) { + if (g_ascii_strncasecmp (a, "not", + sizeof ("not") - 1) == 0 && g_ascii_isspace (a[3])) { return TRUE; } break; @@ -259,7 +287,7 @@ op_to_char (gchar *a, gchar **next) /* * Return TRUE if symbol can be regexp flag */ -static gboolean +static gboolean is_regexp_flag (gchar a) { switch (a) { @@ -284,9 +312,14 @@ is_regexp_flag (gchar a) } static void -insert_expression (rspamd_mempool_t * pool, struct expression **head, gint type, gchar op, void *operand, const gchar *orig) +insert_expression (rspamd_mempool_t * pool, + struct expression **head, + gint type, + gchar op, + void *operand, + const gchar *orig) { - struct expression *new, *cur; + struct expression *new, *cur; new = rspamd_mempool_alloc (pool, sizeof (struct expression)); new->type = type; @@ -311,11 +344,11 @@ insert_expression (rspamd_mempool_t * pool, struct expression **head, gint type, } } -static struct expression * +static struct expression * maybe_parse_expression (rspamd_mempool_t * pool, gchar *line) { - struct expression *expr; - gchar *p = line; + struct expression *expr; + gchar *p = line; while (*p) { if (is_operation_symbol (p)) { @@ -336,17 +369,17 @@ maybe_parse_expression (rspamd_mempool_t * pool, gchar *line) * Make inverse polish record for specified expression * Memory is allocated from given pool */ -struct expression * +struct expression * parse_expression (rspamd_mempool_t * pool, gchar *line) { - struct expression *expr = NULL; - struct expression_stack *stack = NULL; - struct expression_function *func = NULL; - struct expression *arg; - GQueue *function_stack; - gchar *p, *c, *str, op, newop, *copy, *next; - gboolean in_regexp = FALSE; - gint brackets = 0; + struct expression *expr = NULL; + struct expression_stack *stack = NULL; + struct expression_function *func = NULL; + struct expression *arg; + GQueue *function_stack; + gchar *p, *c, *str, op, newop, *copy, *next; + gboolean in_regexp = FALSE; + gint brackets = 0; enum { SKIP_SPACES, @@ -396,7 +429,12 @@ parse_expression (rspamd_mempool_t * pool, gchar *line) while (stack && stack->op != '(') { op = delete_expression_stack (&stack); if (op != '(') { - insert_expression (pool, &expr, EXPR_OPERATION, op, NULL, copy); + insert_expression (pool, + &expr, + EXPR_OPERATION, + op, + NULL, + copy); } } if (stack) { @@ -421,15 +459,23 @@ parse_expression (rspamd_mempool_t * pool, gchar *line) else { newop = op_to_char (p, &next); if (newop != '\0') { - if (logic_priority (stack->op) < logic_priority (newop)) { + if (logic_priority (stack->op) < + logic_priority (newop)) { stack = push_expression_stack (pool, stack, newop); } else { /* Pop all operations that have higher priority than this one */ - while ((stack != NULL) && (logic_priority (stack->op) >= logic_priority (newop))) { + while ((stack != NULL) && + (logic_priority (stack->op) >= + logic_priority (newop))) { op = delete_expression_stack (&stack); if (op != '(') { - insert_expression (pool, &expr, EXPR_OPERATION, op, NULL, copy); + insert_expression (pool, + &expr, + EXPR_OPERATION, + op, + NULL, + copy); } } stack = push_expression_stack (pool, stack, newop); @@ -459,7 +505,8 @@ parse_expression (rspamd_mempool_t * pool, gchar *line) case READ_REGEXP_FLAGS: if (!is_regexp_flag (*p) || *(p + 1) == '\0') { if (c != p) { - if ((is_regexp_flag (*p) || *p == '/') && *(p + 1) == '\0') { + if ((is_regexp_flag (*p) || *p == + '/') && *(p + 1) == '\0') { p++; } str = rspamd_mempool_alloc (pool, p - c + 2); @@ -467,7 +514,12 @@ parse_expression (rspamd_mempool_t * pool, gchar *line) g_strstrip (str); msg_debug ("found regexp: %s", str); if (strlen (str) > 0) { - insert_expression (pool, &expr, EXPR_REGEXP, 0, str, copy); + insert_expression (pool, + &expr, + EXPR_REGEXP, + 0, + str, + copy); } } c = p; @@ -486,7 +538,9 @@ parse_expression (rspamd_mempool_t * pool, gchar *line) p++; } else if (*p == '(') { - func = rspamd_mempool_alloc (pool, sizeof (struct expression_function)); + func = + rspamd_mempool_alloc (pool, + sizeof (struct expression_function)); func->name = rspamd_mempool_alloc (pool, p - c + 1); func->args = NULL; rspamd_strlcpy (func->name, c, (p - c + 1)); @@ -586,14 +640,14 @@ parse_expression (rspamd_mempool_t * pool, gchar *line) /* * Rspamd regexp utility functions */ -struct rspamd_regexp * +struct rspamd_regexp * parse_regexp (rspamd_mempool_t * pool, const gchar *line, gboolean raw_mode) { - const gchar *begin, *end, *p, *src, *start; - gchar *dbegin, *dend; - struct rspamd_regexp *result, *check; - gint regexp_flags = G_REGEX_OPTIMIZE | G_REGEX_NO_AUTO_CAPTURE; - GError *err = NULL; + const gchar *begin, *end, *p, *src, *start; + gchar *dbegin, *dend; + struct rspamd_regexp *result, *check; + gint regexp_flags = G_REGEX_OPTIMIZE | G_REGEX_NO_AUTO_CAPTURE; + GError *err = NULL; if (line == NULL) { msg_err ("cannot parse NULL line"); @@ -621,7 +675,7 @@ parse_regexp (rspamd_mempool_t * pool, const gchar *line, gboolean raw_mode) end = p; break; } - p --; + p--; } if (end) { result->header = rspamd_mempool_alloc (pool, end - line + 1); @@ -650,7 +704,9 @@ parse_regexp (rspamd_mempool_t * pool, const gchar *line, gboolean raw_mode) } else { /* We got header name earlier but have not found // expression, so it is invalid regexp */ - msg_warn ("got no header name (eg. header=) but without corresponding regexp, %s", src); + msg_warn ( + "got no header name (eg. header=) but without corresponding regexp, %s", + src); return NULL; } /* Find end */ @@ -695,7 +751,7 @@ parse_regexp (rspamd_mempool_t * pool, const gchar *line, gboolean raw_mode) result->is_raw = TRUE; p++; break; - /* Type flags */ + /* Type flags */ case 'H': if (result->type == REGEXP_NONE) { result->type = REGEXP_HEADER; @@ -728,13 +784,13 @@ parse_regexp (rspamd_mempool_t * pool, const gchar *line, gboolean raw_mode) break; case 'T': result->is_test = TRUE; - p ++; + p++; break; case 'S': result->is_strong = TRUE; - p ++; + p++; break; - /* Stop flags parsing */ + /* Stop flags parsing */ default: p = NULL; break; @@ -751,9 +807,12 @@ parse_regexp (rspamd_mempool_t * pool, const gchar *line, gboolean raw_mode) } /* Avoid multiply regexp structures for similar regexps */ - if ((check = (struct rspamd_regexp *)re_cache_check (result->regexp_text, pool)) != NULL) { + if ((check = + (struct rspamd_regexp *)re_cache_check (result->regexp_text, + pool)) != NULL) { /* Additional check for headers */ - if (result->type == REGEXP_HEADER || result->type == REGEXP_RAW_HEADER) { + if (result->type == REGEXP_HEADER || result->type == + REGEXP_RAW_HEADER) { if (result->header && check->header) { if (strcmp (result->header, check->header) == 0) { return check; @@ -769,20 +828,31 @@ parse_regexp (rspamd_mempool_t * pool, const gchar *line, gboolean raw_mode) result->raw_regexp = result->regexp; } else { - result->raw_regexp = g_regex_new (dbegin, regexp_flags | G_REGEX_RAW, 0, &err); - rspamd_mempool_add_destructor (pool, (rspamd_mempool_destruct_t) g_regex_unref, (void *)result->raw_regexp); - } - rspamd_mempool_add_destructor (pool, (rspamd_mempool_destruct_t) g_regex_unref, (void *)result->regexp); + result->raw_regexp = g_regex_new (dbegin, + regexp_flags | G_REGEX_RAW, + 0, + &err); + rspamd_mempool_add_destructor (pool, + (rspamd_mempool_destruct_t) g_regex_unref, + (void *)result->raw_regexp); + } + rspamd_mempool_add_destructor (pool, + (rspamd_mempool_destruct_t) g_regex_unref, + (void *)result->regexp); *dend = '/'; if (result->regexp == NULL || err != NULL) { - msg_warn ("could not read regexp: %s while reading regexp %s", err->message, src); + msg_warn ("could not read regexp: %s while reading regexp %s", + err->message, + src); return NULL; } if (result->raw_regexp == NULL || err != NULL) { - msg_warn ("could not read raw regexp: %s while reading regexp %s", err->message, src); + msg_warn ("could not read raw regexp: %s while reading regexp %s", + err->message, + src); return NULL; } @@ -792,13 +862,19 @@ parse_regexp (rspamd_mempool_t * pool, const gchar *line, gboolean raw_mode) } gboolean -call_expression_function (struct expression_function * func, struct rspamd_task * task, lua_State *L) +call_expression_function (struct expression_function * func, + struct rspamd_task * task, + lua_State *L) { - struct _fl *selected, key; + struct _fl *selected, key; key.name = func->name; - selected = bsearch (&key, list_ptr, functions_number, sizeof (struct _fl), fl_cmp); + selected = bsearch (&key, + list_ptr, + functions_number, + sizeof (struct _fl), + fl_cmp); if (selected == NULL) { /* Try to check lua function */ return FALSE; @@ -807,21 +883,26 @@ call_expression_function (struct expression_function * func, struct rspamd_task return selected->func (task, func->args, selected->user_data); } -struct expression_argument * -get_function_arg (struct expression *expr, struct rspamd_task *task, gboolean want_string) +struct expression_argument * +get_function_arg (struct expression *expr, + struct rspamd_task *task, + gboolean want_string) { - GQueue *stack; - gsize cur, op1, op2; - struct expression_argument *res; - struct expression *it; + GQueue *stack; + gsize cur, op1, op2; + struct expression_argument *res; + struct expression *it; if (expr == NULL) { msg_warn ("NULL expression passed"); return NULL; } if (expr->next == NULL) { - res = rspamd_mempool_alloc (task->task_pool, sizeof (struct expression_argument)); - if (expr->type == EXPR_REGEXP || expr->type == EXPR_STR || expr->type == EXPR_REGEXP_PARSED) { + res = + rspamd_mempool_alloc (task->task_pool, + sizeof (struct expression_argument)); + if (expr->type == EXPR_REGEXP || expr->type == EXPR_STR || expr->type == + EXPR_REGEXP_PARSED) { res->type = EXPRESSION_ARGUMENT_NORMAL; res->data = expr->content.operand; } @@ -831,27 +912,36 @@ get_function_arg (struct expression *expr, struct rspamd_task *task, gboolean wa res->data = GSIZE_TO_POINTER (cur); } else { - msg_warn ("cannot parse argument: it contains operator or bool expression that is not wanted"); + msg_warn ( + "cannot parse argument: it contains operator or bool expression that is not wanted"); return NULL; } return res; } else if (!want_string) { - res = rspamd_mempool_alloc (task->task_pool, sizeof (struct expression_argument)); + res = + rspamd_mempool_alloc (task->task_pool, + sizeof (struct expression_argument)); res->type = EXPRESSION_ARGUMENT_BOOL; stack = g_queue_new (); it = expr; while (it) { - if (it->type == EXPR_REGEXP || it->type == EXPR_REGEXP_PARSED || it->type == EXPR_STR) { + if (it->type == EXPR_REGEXP || it->type == EXPR_REGEXP_PARSED || + it->type == EXPR_STR) { g_queue_free (stack); res->type = EXPRESSION_ARGUMENT_EXPR; res->data = expr; return res; } else if (it->type == EXPR_FUNCTION) { - cur = (gsize) call_expression_function ((struct expression_function *)it->content.operand, task, NULL); - debug_task ("function %s returned %s", ((struct expression_function *)it->content.operand)->name, cur ? "true" : "false"); + cur = + (gsize) call_expression_function ((struct + expression_function + *)it->content.operand, task, NULL); + debug_task ("function %s returned %s", + ((struct expression_function *)it->content.operand)->name, + cur ? "true" : "false"); } else if (it->type == EXPR_OPERATION) { if (g_queue_is_empty (stack)) { @@ -901,9 +991,11 @@ get_function_arg (struct expression *expr, struct rspamd_task *task, gboolean wa } void -register_expression_function (const gchar *name, rspamd_internal_func_t func, void *user_data) +register_expression_function (const gchar *name, + rspamd_internal_func_t func, + void *user_data) { - static struct _fl *new; + static struct _fl *new; functions_number++; @@ -924,7 +1016,7 @@ register_expression_function (const gchar *name, rspamd_internal_func_t func, vo gboolean rspamd_compare_encoding (struct rspamd_task *task, GList * args, void *unused) { - struct expression_argument *arg; + struct expression_argument *arg; if (args == NULL || task == NULL) { return FALSE; @@ -943,8 +1035,8 @@ rspamd_compare_encoding (struct rspamd_task *task, GList * args, void *unused) gboolean rspamd_header_exists (struct rspamd_task * task, GList * args, void *unused) { - struct expression_argument *arg; - GList *headerlist; + struct expression_argument *arg; + GList *headerlist; if (args == NULL || task == NULL) { return FALSE; @@ -957,7 +1049,10 @@ rspamd_header_exists (struct rspamd_task * task, GList * args, void *unused) } debug_task ("try to get header %s", (gchar *)arg->data); - headerlist = message_get_header (task->task_pool, task->message, (gchar *)arg->data, FALSE); + headerlist = message_get_header (task->task_pool, + task->message, + (gchar *)arg->data, + FALSE); if (headerlist) { g_list_free (headerlist); return TRUE; @@ -967,20 +1062,20 @@ rspamd_header_exists (struct rspamd_task * task, GList * args, void *unused) /* * This function is designed to find difference between text/html and text/plain parts - * It takes one argument: difference threshold, if we have two text parts, compare + * It takes one argument: difference threshold, if we have two text parts, compare * its hashes and check for threshold, if value is greater than threshold, return TRUE * and return FALSE otherwise. */ gboolean rspamd_parts_distance (struct rspamd_task * task, GList * args, void *unused) { - gint threshold, threshold2 = -1, diff; - struct mime_text_part *p1, *p2; - GList *cur; - struct expression_argument *arg; - GMimeObject *parent; - const GMimeContentType *ct; - gint *pdiff; + gint threshold, threshold2 = -1, diff; + struct mime_text_part *p1, *p2; + GList *cur; + struct expression_argument *arg; + GMimeObject *parent; + const GMimeContentType *ct; + gint *pdiff; if (args == NULL) { debug_task ("no threshold is specified, assume it 100"); @@ -991,7 +1086,8 @@ rspamd_parts_distance (struct rspamd_task * task, GList * args, void *unused) arg = get_function_arg (args->data, task, TRUE); threshold = strtoul ((gchar *)arg->data, NULL, 10); if (errno != 0) { - msg_info ("bad numeric value for threshold \"%s\", assume it 100", (gchar *)args->data); + msg_info ("bad numeric value for threshold \"%s\", assume it 100", + (gchar *)args->data); threshold = 100; } if (args->next) { @@ -999,17 +1095,22 @@ rspamd_parts_distance (struct rspamd_task * task, GList * args, void *unused) errno = 0; threshold2 = strtoul ((gchar *)arg->data, NULL, 10); if (errno != 0) { - msg_info ("bad numeric value for threshold \"%s\", ignore it", (gchar *)arg->data); + msg_info ("bad numeric value for threshold \"%s\", ignore it", + (gchar *)arg->data); threshold2 = -1; } } } - if ((pdiff = rspamd_mempool_get_variable (task->task_pool, "parts_distance")) != NULL) { + if ((pdiff = + rspamd_mempool_get_variable (task->task_pool, + "parts_distance")) != NULL) { diff = *pdiff; if (diff != -1) { if (threshold2 > 0) { - if (diff >= MIN (threshold, threshold2) && diff < MAX (threshold, threshold2)) { + if (diff >= + MIN (threshold, + threshold2) && diff < MAX (threshold, threshold2)) { return TRUE; } } @@ -1042,32 +1143,52 @@ rspamd_parts_distance (struct rspamd_task * task, GList * args, void *unused) parent = p1->parent; ct = g_mime_object_get_content_type (parent); #ifndef GMIME24 - if (ct == NULL || ! g_mime_content_type_is_type (ct, "multipart", "alternative")) { + if (ct == NULL || + !g_mime_content_type_is_type (ct, "multipart", "alternative")) { #else - if (ct == NULL || ! g_mime_content_type_is_type ((GMimeContentType *)ct, "multipart", "alternative")) { + if (ct == NULL || + !g_mime_content_type_is_type ((GMimeContentType *)ct, + "multipart", "alternative")) { #endif - debug_task ("two parts are not belong to multipart/alternative container, skip check"); - rspamd_mempool_set_variable (task->task_pool, "parts_distance", pdiff, NULL); + debug_task ( + "two parts are not belong to multipart/alternative container, skip check"); + rspamd_mempool_set_variable (task->task_pool, + "parts_distance", + pdiff, + NULL); return FALSE; } } else { - debug_task ("message contains two parts but they are in different multi-parts"); - rspamd_mempool_set_variable (task->task_pool, "parts_distance", pdiff, NULL); + debug_task ( + "message contains two parts but they are in different multi-parts"); + rspamd_mempool_set_variable (task->task_pool, + "parts_distance", + pdiff, + NULL); return FALSE; } if (!p1->is_empty && !p2->is_empty) { if (p1->diff_str != NULL && p2->diff_str != NULL) { - diff = compare_diff_distance_normalized (p1->diff_str, p2->diff_str); + diff = compare_diff_distance_normalized (p1->diff_str, + p2->diff_str); } else { diff = fuzzy_compare_parts (p1, p2); } - debug_task ("got likeliness between parts of %d%%, threshold is %d%%", diff, threshold); + debug_task ( + "got likeliness between parts of %d%%, threshold is %d%%", + diff, + threshold); *pdiff = diff; - rspamd_mempool_set_variable (task->task_pool, "parts_distance", pdiff, NULL); + rspamd_mempool_set_variable (task->task_pool, + "parts_distance", + pdiff, + NULL); if (threshold2 > 0) { - if (diff >= MIN (threshold, threshold2) && diff < MAX (threshold, threshold2)) { + if (diff >= + MIN (threshold, + threshold2) && diff < MAX (threshold, threshold2)) { return TRUE; } } @@ -1077,41 +1198,51 @@ rspamd_parts_distance (struct rspamd_task * task, GList * args, void *unused) } } } - else if ((p1->is_empty && !p2->is_empty) || (!p1->is_empty && p2->is_empty)) { + else if ((p1->is_empty && + !p2->is_empty) || (!p1->is_empty && p2->is_empty)) { /* Empty and non empty parts are different */ *pdiff = 0; - rspamd_mempool_set_variable (task->task_pool, "parts_distance", pdiff, NULL); + rspamd_mempool_set_variable (task->task_pool, + "parts_distance", + pdiff, + NULL); return TRUE; } } else { - debug_task ("message has too many text parts, so do not try to compare them with each other"); - rspamd_mempool_set_variable (task->task_pool, "parts_distance", pdiff, NULL); + debug_task ( + "message has too many text parts, so do not try to compare them with each other"); + rspamd_mempool_set_variable (task->task_pool, + "parts_distance", + pdiff, + NULL); return FALSE; } - rspamd_mempool_set_variable (task->task_pool, "parts_distance", pdiff, NULL); + rspamd_mempool_set_variable (task->task_pool, "parts_distance", pdiff, + NULL); return FALSE; } struct addr_list { - const gchar *name; - const gchar *addr; + const gchar *name; + const gchar *addr; }; #define COMPARE_RCPT_LEN 3 #define MIN_RCPT_TO_COMPARE 7 gboolean -rspamd_recipients_distance (struct rspamd_task *task, GList * args, void *unused) +rspamd_recipients_distance (struct rspamd_task *task, GList * args, + void *unused) { - struct expression_argument *arg; - InternetAddressList *cur; - InternetAddress *addr; - double threshold; - struct addr_list *ar; - gchar *c; - gint num, i, j, hits = 0, total = 0; + struct expression_argument *arg; + InternetAddressList *cur; + InternetAddress *addr; + double threshold; + struct addr_list *ar; + gchar *c; + gint num, i, j, hits = 0, total = 0; if (args == NULL) { msg_warn ("no parameters to function"); @@ -1122,7 +1253,9 @@ rspamd_recipients_distance (struct rspamd_task *task, GList * args, void *unused errno = 0; threshold = strtod ((gchar *)arg->data, NULL); if (errno != 0) { - msg_warn ("invalid numeric value '%s': %s", (gchar *)arg->data, strerror (errno)); + msg_warn ("invalid numeric value '%s': %s", + (gchar *)arg->data, + strerror (errno)); return FALSE; } @@ -1133,14 +1266,17 @@ rspamd_recipients_distance (struct rspamd_task *task, GList * args, void *unused if (num < MIN_RCPT_TO_COMPARE) { return FALSE; } - ar = rspamd_mempool_alloc0 (task->task_pool, num * sizeof (struct addr_list)); + ar = + rspamd_mempool_alloc0 (task->task_pool, num * + sizeof (struct addr_list)); /* Fill array */ cur = task->rcpts; #ifdef GMIME24 - for (i = 0; i < num; i ++) { + for (i = 0; i < num; i++) { addr = internet_address_list_get_address (cur, i); - ar[i].name = rspamd_mempool_strdup (task->task_pool, internet_address_get_name (addr)); + ar[i].name = rspamd_mempool_strdup (task->task_pool, + internet_address_get_name (addr)); if (ar[i].name != NULL && (c = strchr (ar[i].name, '@')) != NULL) { *c = '\0'; ar[i].addr = c + 1; @@ -1151,7 +1287,8 @@ rspamd_recipients_distance (struct rspamd_task *task, GList * args, void *unused while (cur) { addr = internet_address_list_get_address (cur); if (addr && internet_address_get_type (addr) == INTERNET_ADDRESS_NAME) { - ar[i].name = rspamd_mempool_strdup (task->task_pool, internet_address_get_addr (addr)); + ar[i].name = rspamd_mempool_strdup (task->task_pool, + internet_address_get_addr (addr)); if (ar[i].name != NULL && (c = strchr (ar[i].name, '@')) != NULL) { *c = '\0'; ar[i].addr = c + 1; @@ -1168,11 +1305,14 @@ rspamd_recipients_distance (struct rspamd_task *task, GList * args, void *unused /* Cycle all elements in array */ for (i = 0; i < num; i++) { for (j = i + 1; j < num; j++) { - if (ar[i].name && ar[j].name && g_ascii_strncasecmp (ar[i].name, ar[j].name, COMPARE_RCPT_LEN) == 0) { + if (ar[i].name && ar[j].name && + g_ascii_strncasecmp (ar[i].name, ar[j].name, + COMPARE_RCPT_LEN) == 0) { /* Common name part */ hits++; } - else if (ar[i].addr && ar[j].addr && g_ascii_strcasecmp (ar[i].addr, ar[j].addr) == 0) { + else if (ar[i].addr && ar[j].addr && + g_ascii_strcasecmp (ar[i].addr, ar[j].addr) == 0) { /* Common address part, but different name */ hits++; } @@ -1188,11 +1328,12 @@ rspamd_recipients_distance (struct rspamd_task *task, GList * args, void *unused } gboolean -rspamd_has_only_html_part (struct rspamd_task * task, GList * args, void *unused) +rspamd_has_only_html_part (struct rspamd_task * task, GList * args, + void *unused) { - struct mime_text_part *p; - GList *cur; - gboolean res = FALSE; + struct mime_text_part *p; + GList *cur; + gboolean res = FALSE; cur = g_list_first (task->text_parts); while (cur) { @@ -1210,30 +1351,34 @@ rspamd_has_only_html_part (struct rspamd_task * task, GList * args, void *unused return res; } -static gboolean +static gboolean is_recipient_list_sorted (const InternetAddressList * ia) { - const InternetAddressList *cur; - InternetAddress *addr; - gboolean res = TRUE; - struct addr_list current = { NULL, NULL }, previous = { - NULL, NULL}; + const InternetAddressList *cur; + InternetAddress *addr; + gboolean res = TRUE; + struct addr_list current = { NULL, NULL }, previous = { + NULL, NULL + }; #ifdef GMIME24 - gint num, i; + gint num, i; #endif /* Do not check to short address lists */ - if (internet_address_list_length ((InternetAddressList *)ia) < MIN_RCPT_TO_COMPARE) { + if (internet_address_list_length ((InternetAddressList *)ia) < + MIN_RCPT_TO_COMPARE) { return FALSE; } #ifdef GMIME24 num = internet_address_list_length ((InternetAddressList *)ia); cur = ia; - for (i = 0; i < num; i ++) { - addr = internet_address_list_get_address ((InternetAddressList *)cur, i); + for (i = 0; i < num; i++) { + addr = + internet_address_list_get_address ((InternetAddressList *)cur, i); current.addr = (gchar *)internet_address_get_name (addr); if (previous.addr != NULL) { - if (current.addr && g_ascii_strcasecmp (current.addr, previous.addr) < 0) { + if (current.addr && + g_ascii_strcasecmp (current.addr, previous.addr) < 0) { res = FALSE; break; } @@ -1247,7 +1392,8 @@ is_recipient_list_sorted (const InternetAddressList * ia) if (internet_address_get_type (addr) == INTERNET_ADDRESS_NAME) { current.addr = internet_address_get_addr (addr); if (previous.addr != NULL) { - if (current.addr && g_ascii_strcasecmp (current.addr, previous.addr) < 0) { + if (current.addr && + g_ascii_strcasecmp (current.addr, previous.addr) < 0) { res = FALSE; break; } @@ -1262,16 +1408,21 @@ is_recipient_list_sorted (const InternetAddressList * ia) } gboolean -rspamd_is_recipients_sorted (struct rspamd_task * task, GList * args, void *unused) +rspamd_is_recipients_sorted (struct rspamd_task * task, + GList * args, + void *unused) { /* Check all types of addresses */ - if (is_recipient_list_sorted (g_mime_message_get_recipients (task->message, GMIME_RECIPIENT_TYPE_TO)) == TRUE) { + if (is_recipient_list_sorted (g_mime_message_get_recipients (task->message, + GMIME_RECIPIENT_TYPE_TO)) == TRUE) { return TRUE; } - if (is_recipient_list_sorted (g_mime_message_get_recipients (task->message, GMIME_RECIPIENT_TYPE_BCC)) == TRUE) { + if (is_recipient_list_sorted (g_mime_message_get_recipients (task->message, + GMIME_RECIPIENT_TYPE_BCC)) == TRUE) { return TRUE; } - if (is_recipient_list_sorted (g_mime_message_get_recipients (task->message, GMIME_RECIPIENT_TYPE_CC)) == TRUE) { + if (is_recipient_list_sorted (g_mime_message_get_recipients (task->message, + GMIME_RECIPIENT_TYPE_CC)) == TRUE) { return TRUE; } @@ -1279,15 +1430,17 @@ rspamd_is_recipients_sorted (struct rspamd_task * task, GList * args, void *unus } gboolean -rspamd_compare_transfer_encoding (struct rspamd_task * task, GList * args, void *unused) +rspamd_compare_transfer_encoding (struct rspamd_task * task, + GList * args, + void *unused) { - GMimeObject *part; + GMimeObject *part; #ifndef GMIME24 - GMimePartEncodingType enc_req, part_enc; + GMimePartEncodingType enc_req, part_enc; #else - GMimeContentEncoding enc_req, part_enc; + GMimeContentEncoding enc_req, part_enc; #endif - struct expression_argument *arg; + struct expression_argument *arg; if (args == NULL) { msg_warn ("no parameters to function"); @@ -1324,7 +1477,9 @@ rspamd_compare_transfer_encoding (struct rspamd_task * task, GList * args, void #endif - debug_task ("got encoding in part: %d and compare with %d", (gint)part_enc, (gint)enc_req); + debug_task ("got encoding in part: %d and compare with %d", + (gint)part_enc, + (gint)enc_req); #ifndef GMIME24 g_object_unref (part); #endif @@ -1342,9 +1497,9 @@ rspamd_compare_transfer_encoding (struct rspamd_task * task, GList * args, void gboolean rspamd_is_html_balanced (struct rspamd_task * task, GList * args, void *unused) { - struct mime_text_part *p; - GList *cur; - gboolean res = TRUE; + struct mime_text_part *p; + GList *cur; + gboolean res = TRUE; cur = g_list_first (task->text_parts); while (cur) { @@ -1366,15 +1521,15 @@ rspamd_is_html_balanced (struct rspamd_task * task, GList * args, void *unused) } struct html_callback_data { - struct html_tag *tag; - gboolean *res; + struct html_tag *tag; + gboolean *res; }; -static gboolean +static gboolean search_html_node_callback (GNode * node, gpointer data) { - struct html_callback_data *cd = data; - struct html_node *nd; + struct html_callback_data *cd = data; + struct html_node *nd; nd = node->data; if (nd) { @@ -1390,12 +1545,12 @@ search_html_node_callback (GNode * node, gpointer data) gboolean rspamd_has_html_tag (struct rspamd_task * task, GList * args, void *unused) { - struct mime_text_part *p; - GList *cur; - struct expression_argument *arg; - struct html_tag *tag; - gboolean res = FALSE; - struct html_callback_data cd; + struct mime_text_part *p; + GList *cur; + struct expression_argument *arg; + struct html_tag *tag; + gboolean res = FALSE; + struct html_callback_data cd; if (args == NULL) { msg_warn ("no parameters to function"); @@ -1405,7 +1560,8 @@ rspamd_has_html_tag (struct rspamd_task * task, GList * args, void *unused) arg = get_function_arg (args->data, task, TRUE); tag = get_tag_by_name (arg->data); if (tag == NULL) { - msg_warn ("unknown tag type passed as argument: %s", (gchar *)arg->data); + msg_warn ("unknown tag type passed as argument: %s", + (gchar *)arg->data); return FALSE; } @@ -1416,7 +1572,12 @@ rspamd_has_html_tag (struct rspamd_task * task, GList * args, void *unused) while (cur && res == FALSE) { p = cur->data; if (!p->is_empty && p->is_html && p->html_nodes) { - g_node_traverse (p->html_nodes, G_PRE_ORDER, G_TRAVERSE_ALL, -1, search_html_node_callback, &cd); + g_node_traverse (p->html_nodes, + G_PRE_ORDER, + G_TRAVERSE_ALL, + -1, + search_html_node_callback, + &cd); } cur = g_list_next (cur); } @@ -1428,9 +1589,9 @@ rspamd_has_html_tag (struct rspamd_task * task, GList * args, void *unused) gboolean rspamd_has_fake_html (struct rspamd_task * task, GList * args, void *unused) { - struct mime_text_part *p; - GList *cur; - gboolean res = FALSE; + struct mime_text_part *p; + GList *cur; + gboolean res = FALSE; cur = g_list_first (task->text_parts); diff --git a/src/libmime/expressions.h b/src/libmime/expressions.h index 954cc74f7..1ba02d956 100644 --- a/src/libmime/expressions.h +++ b/src/libmime/expressions.h @@ -16,8 +16,8 @@ struct rspamd_regexp; * Rspamd expression function */ struct expression_function { - gchar *name; /**< name of function */ - GList *args; /**< its args */ + gchar *name; /**< name of function */ + GList *args; /**< its args */ }; /** @@ -28,30 +28,31 @@ struct expression_argument { EXPRESSION_ARGUMENT_NORMAL, EXPRESSION_ARGUMENT_BOOL, EXPRESSION_ARGUMENT_EXPR, - } type; /**< type of argument (text or other function) */ - void *data; /**< pointer to its data */ + } type; /**< type of argument (text or other function) */ + void *data; /**< pointer to its data */ }; -/** - * Logic expression +/** + * Logic expression */ struct expression { - enum { + enum { EXPR_REGEXP, - EXPR_OPERATION, - EXPR_FUNCTION, - EXPR_STR, + EXPR_OPERATION, + EXPR_FUNCTION, + EXPR_STR, EXPR_REGEXP_PARSED, - } type; /**< expression type */ + } type; /**< expression type */ union { void *operand; gchar operation; - } content; /**< union for storing operand or operation code */ - const gchar *orig; /**< original line */ - struct expression *next; /**< chain link */ + } content; /**< union for storing operand or operation code */ + const gchar *orig; /**< original line */ + struct expression *next; /**< chain link */ }; -typedef gboolean (*rspamd_internal_func_t)(struct rspamd_task *, GList *args, void *user_data); +typedef gboolean (*rspamd_internal_func_t)(struct rspamd_task *, GList *args, + void *user_data); /** * Parse regexp line to regexp structure @@ -59,7 +60,9 @@ typedef gboolean (*rspamd_internal_func_t)(struct rspamd_task *, GList *args, vo * @param line incoming line * @return regexp structure or NULL in case of error */ -struct rspamd_regexp* parse_regexp (rspamd_mempool_t *pool, const gchar *line, gboolean raw_mode); +struct rspamd_regexp * parse_regexp (rspamd_mempool_t *pool, + const gchar *line, + gboolean raw_mode); /** * Parse composites line to composites structure (eg. "SYMBOL1&SYMBOL2|!SYMBOL3") @@ -67,7 +70,7 @@ struct rspamd_regexp* parse_regexp (rspamd_mempool_t *pool, const gchar *line, g * @param line incoming line * @return expression structure or NULL in case of error */ -struct expression* parse_expression (rspamd_mempool_t *pool, gchar *line); +struct expression * parse_expression (rspamd_mempool_t *pool, gchar *line); /** * Call specified fucntion and return boolean result @@ -76,14 +79,18 @@ struct expression* parse_expression (rspamd_mempool_t *pool, gchar *line); * @param L lua specific state * @return TRUE or FALSE depending on function result */ -gboolean call_expression_function (struct expression_function *func, struct rspamd_task *task, lua_State *L); +gboolean call_expression_function (struct expression_function *func, + struct rspamd_task *task, + lua_State *L); /** * Register specified function to rspamd internal functions list * @param name name of function * @param func pointer to function */ -void register_expression_function (const gchar *name, rspamd_internal_func_t func, void *user_data); +void register_expression_function (const gchar *name, + rspamd_internal_func_t func, + void *user_data); /** * Add regexp to regexp cache @@ -111,7 +118,9 @@ void re_cache_del (const gchar *line, rspamd_mempool_t *pool); * @param pointer regexp data * @param result numeric result of this regexp */ -void task_cache_add (struct rspamd_task *task, struct rspamd_regexp *re, gint32 result); +void task_cache_add (struct rspamd_task *task, + struct rspamd_regexp *re, + gint32 result); /** * Check regexp in cache @@ -128,6 +137,8 @@ gint32 task_cache_check (struct rspamd_task *task, struct rspamd_regexp *re); * @param want_string return NULL if argument is not a string * @return expression argument structure or NULL if failed */ -struct expression_argument *get_function_arg (struct expression *expr, struct rspamd_task *task, gboolean want_string); +struct expression_argument * get_function_arg (struct expression *expr, + struct rspamd_task *task, + gboolean want_string); #endif diff --git a/src/libmime/filter.c b/src/libmime/filter.c index 2068c79e3..f296617cf 100644 --- a/src/libmime/filter.c +++ b/src/libmime/filter.c @@ -22,18 +22,18 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "binlog.h" +#include "cfg_file.h" +#include "classifiers/classifiers.h" #include "config.h" -#include "mem_pool.h" +#include "diff.h" +#include "expressions.h" #include "filter.h" #include "main.h" +#include "mem_pool.h" #include "message.h" -#include "cfg_file.h" -#include "util.h" -#include "expressions.h" -#include "binlog.h" -#include "diff.h" -#include "classifiers/classifiers.h" #include "tokenizers/tokenizers.h" +#include "util.h" #ifdef WITH_LUA # include "lua/lua_common.h" @@ -44,44 +44,56 @@ #ifndef PARAM_H_HAS_BITSET /* Bit map related macros. */ #define NBBY 8 /* number of bits in a byte */ -#define setbit(a,i) (((unsigned char *)(a))[(i)/NBBY] |= 1<<((i)%NBBY)) -#define clrbit(a,i) (((unsigned char *)(a))[(i)/NBBY] &= ~(1<<((i)%NBBY))) +#define setbit(a, \ + i) (((unsigned char *)(a))[(i) / NBBY] |= 1 << ((i) % NBBY)) +#define clrbit(a, \ + i) (((unsigned char *)(a))[(i) / NBBY] &= ~(1 << ((i) % NBBY))) #define isset(a,i) \ - (((const unsigned char *)(a))[(i)/NBBY] & (1<<((i)%NBBY))) + (((const unsigned char *)(a))[(i) / NBBY] & (1 << ((i) % NBBY))) #define isclr(a,i) \ - ((((const unsigned char *)(a))[(i)/NBBY] & (1<<((i)%NBBY))) == 0) + ((((const unsigned char *)(a))[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) #endif -#define BITSPERBYTE (8*sizeof (gchar)) -#define NBYTES(nbits) (((nbits) + BITSPERBYTE - 1) / BITSPERBYTE) +#define BITSPERBYTE (8 * sizeof (gchar)) +#define NBYTES(nbits) (((nbits) + BITSPERBYTE - 1) / BITSPERBYTE) -static inline GQuark +static inline GQuark filter_error_quark (void) { return g_quark_from_static_string ("g-filter-error-quark"); } static void -insert_metric_result (struct rspamd_task *task, struct metric *metric, const gchar *symbol, - double flag, GList * opts, gboolean single) +insert_metric_result (struct rspamd_task *task, + struct metric *metric, + const gchar *symbol, + double flag, + GList * opts, + gboolean single) { - struct metric_result *metric_res; - struct symbol *s; - gdouble *weight, w; + struct metric_result *metric_res; + struct symbol *s; + gdouble *weight, w; metric_res = g_hash_table_lookup (task->results, metric->name); if (metric_res == NULL) { /* Create new metric chain */ - metric_res = rspamd_mempool_alloc (task->task_pool, sizeof (struct metric_result)); - metric_res->symbols = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); + metric_res = + rspamd_mempool_alloc (task->task_pool, + sizeof (struct metric_result)); + metric_res->symbols = g_hash_table_new (rspamd_str_hash, + rspamd_str_equal); metric_res->checked = FALSE; - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) g_hash_table_unref, metric_res->symbols); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) g_hash_table_unref, + metric_res->symbols); metric_res->metric = metric; metric_res->grow_factor = 0; metric_res->score = 0; - g_hash_table_insert (task->results, (gpointer) metric->name, metric_res); + g_hash_table_insert (task->results, (gpointer) metric->name, + metric_res); } - + weight = g_hash_table_lookup (metric->symbols, symbol); if (weight == NULL) { w = 0.0; @@ -94,7 +106,7 @@ insert_metric_result (struct rspamd_task *task, struct metric *metric, const gch if ((s = g_hash_table_lookup (metric_res->symbols, symbol)) != NULL) { if (s->options && opts && opts != s->options) { /* Append new options */ - s->options = g_list_concat (s->options, g_list_copy(opts)); + s->options = g_list_concat (s->options, g_list_copy (opts)); /* * Note that there is no need to add new destructor of GList as elements of appended * GList are used directly, so just free initial GList @@ -102,7 +114,8 @@ insert_metric_result (struct rspamd_task *task, struct metric *metric, const gch } else if (opts) { s->options = g_list_copy (opts); - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) g_list_free, s->options); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) g_list_free, s->options); } if (!single) { /* Handle grow factor */ @@ -139,7 +152,8 @@ insert_metric_result (struct rspamd_task *task, struct metric *metric, const gch if (opts) { s->options = g_list_copy (opts); - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) g_list_free, s->options); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) g_list_free, s->options); } else { s->options = NULL; @@ -147,22 +161,30 @@ insert_metric_result (struct rspamd_task *task, struct metric *metric, const gch g_hash_table_insert (metric_res->symbols, (gpointer) symbol, s); } - debug_task ("symbol %s, score %.2f, metric %s, factor: %f", symbol, s->score, metric->name, w); - + debug_task ("symbol %s, score %.2f, metric %s, factor: %f", + symbol, + s->score, + metric->name, + w); + } #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30)) -static GStaticMutex result_mtx = G_STATIC_MUTEX_INIT; +static GStaticMutex result_mtx = G_STATIC_MUTEX_INIT; #else G_LOCK_DEFINE (result_mtx); #endif static void -insert_result_common (struct rspamd_task *task, const gchar *symbol, double flag, GList * opts, gboolean single) +insert_result_common (struct rspamd_task *task, + const gchar *symbol, + double flag, + GList * opts, + gboolean single) { - struct metric *metric; - struct cache_item *item; - GList *cur, *metric_list; + struct metric *metric; + struct cache_item *item; + GList *cur, *metric_list; /* Avoid concurrenting inserting of results */ #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30)) @@ -173,7 +195,7 @@ insert_result_common (struct rspamd_task *task, const gchar *symbol, double flag metric_list = g_hash_table_lookup (task->cfg->metrics_symbols, symbol); if (metric_list) { cur = metric_list; - + while (cur) { metric = cur->data; insert_metric_result (task, metric, symbol, flag, opts, single); @@ -182,7 +204,12 @@ insert_result_common (struct rspamd_task *task, const gchar *symbol, double flag } else { /* Insert symbol to default metric */ - insert_metric_result (task, task->cfg->default_metric, symbol, flag, opts, single); + insert_metric_result (task, + task->cfg->default_metric, + symbol, + flag, + opts, + single); } /* Process cache item */ @@ -206,21 +233,27 @@ insert_result_common (struct rspamd_task *task, const gchar *symbol, double flag /* Insert result that may be increased on next insertions */ void -insert_result (struct rspamd_task *task, const gchar *symbol, double flag, GList * opts) +insert_result (struct rspamd_task *task, + const gchar *symbol, + double flag, + GList * opts) { insert_result_common (task, symbol, flag, opts, task->cfg->one_shot_mode); } /* Insert result as a single option */ void -insert_result_single (struct rspamd_task *task, const gchar *symbol, double flag, GList * opts) +insert_result_single (struct rspamd_task *task, + const gchar *symbol, + double flag, + GList * opts) { insert_result_common (task, symbol, flag, opts, TRUE); } static gboolean check_metric_settings (struct rspamd_task *task, struct metric *metric, - double *score) + double *score) { const ucl_object_t *mobj, *reject; double val; @@ -243,11 +276,11 @@ check_metric_settings (struct rspamd_task *task, struct metric *metric, } /* Return true if metric has score that is more than spam score for it */ -static gboolean +static gboolean check_metric_is_spam (struct rspamd_task *task, struct metric *metric) { - struct metric_result *res; - double ms; + struct metric_result *res; + double ms; /* Avoid concurrency while checking results */ #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30)) @@ -280,9 +313,9 @@ check_metric_is_spam (struct rspamd_task *task, struct metric *metric) gint process_filters (struct rspamd_task *task) { - GList *cur; - struct metric *metric; - gpointer item = NULL; + GList *cur; + struct metric *metric; + gpointer item = NULL; /* Process metrics symbols */ while (call_symbol_callback (task, task->cfg->cache, &item)) { @@ -291,8 +324,8 @@ process_filters (struct rspamd_task *task) while (cur) { metric = cur->data; if (!task->pass_all_filters && - metric->actions[METRIC_ACTION_REJECT].score > 0 && - check_metric_is_spam (task, metric)) { + metric->actions[METRIC_ACTION_REJECT].score > 0 && + check_metric_is_spam (task, metric)) { task->state = WRITE_REPLY; return 1; } @@ -307,22 +340,22 @@ process_filters (struct rspamd_task *task) struct composites_data { - struct rspamd_task *task; - struct metric_result *metric_res; - GTree *symbols_to_remove; - guint8 *checked; + struct rspamd_task *task; + struct metric_result *metric_res; + GTree *symbols_to_remove; + guint8 *checked; }; struct symbol_remove_data { - struct symbol *ms; - gboolean remove_weight; - gboolean remove_symbol; + struct symbol *ms; + gboolean remove_weight; + gboolean remove_symbol; }; static gint remove_compare_data (gconstpointer a, gconstpointer b) { - const gchar *ca = a, *cb = b; + const gchar *ca = a, *cb = b; return strcmp (ca, cb); } @@ -330,16 +363,16 @@ remove_compare_data (gconstpointer a, gconstpointer b) static void composites_foreach_callback (gpointer key, gpointer value, void *data) { - struct composites_data *cd = (struct composites_data *)data; - struct rspamd_composite *composite = value, *ncomp; - struct expression *expr; - GQueue *stack; - GList *symbols = NULL, *s; - gsize cur, op1, op2; - gchar logbuf[256], *sym, *check_sym; - gint r; - struct symbol *ms; - struct symbol_remove_data *rd; + struct composites_data *cd = (struct composites_data *)data; + struct rspamd_composite *composite = value, *ncomp; + struct expression *expr; + GQueue *stack; + GList *symbols = NULL, *s; + gsize cur, op1, op2; + gchar logbuf[256], *sym, *check_sym; + gint r; + struct symbol *ms; + struct symbol_remove_data *rd; expr = composite->expr; @@ -355,16 +388,19 @@ composites_foreach_callback (gpointer key, gpointer value, void *data) /* Find corresponding symbol */ sym = expr->content.operand; if (*sym == '~' || *sym == '-') { - sym ++; + sym++; } if (g_hash_table_lookup (cd->metric_res->symbols, sym) == NULL) { cur = 0; - if ((ncomp = g_hash_table_lookup (cd->task->cfg->composite_symbols, sym)) != NULL) { + if ((ncomp = + g_hash_table_lookup (cd->task->cfg->composite_symbols, + sym)) != NULL) { /* Set checked for this symbol to avoid cyclic references */ if (isclr (cd->checked, ncomp->id)) { setbit (cd->checked, composite->id); composites_foreach_callback (sym, ncomp, cd); - if (g_hash_table_lookup (cd->metric_res->symbols, sym) != NULL) { + if (g_hash_table_lookup (cd->metric_res->symbols, + sym) != NULL) { cur = 1; } } @@ -412,7 +448,11 @@ composites_foreach_callback (gpointer key, gpointer value, void *data) if (op1) { /* Remove all symbols that are in composite symbol */ s = g_list_first (symbols); - r = rspamd_snprintf (logbuf, sizeof (logbuf), "<%s>, insert symbol %s instead of symbols: ", cd->task->message_id, key); + r = rspamd_snprintf (logbuf, + sizeof (logbuf), + "<%s>, insert symbol %s instead of symbols: ", + cd->task->message_id, + key); while (s) { sym = s->data; if (*sym == '~' || *sym == '-') { @@ -425,18 +465,23 @@ composites_foreach_callback (gpointer key, gpointer value, void *data) if (ms == NULL) { /* Try to process other composites */ - if ((ncomp = g_hash_table_lookup (cd->task->cfg->composite_symbols, check_sym)) != NULL) { + if ((ncomp = + g_hash_table_lookup (cd->task->cfg->composite_symbols, + check_sym)) != NULL) { /* Set checked for this symbol to avoid cyclic references */ if (isclr (cd->checked, ncomp->id)) { setbit (cd->checked, composite->id); composites_foreach_callback (check_sym, ncomp, cd); - ms = g_hash_table_lookup (cd->metric_res->symbols, check_sym); + ms = g_hash_table_lookup (cd->metric_res->symbols, + check_sym); } } } if (ms != NULL) { - rd = rspamd_mempool_alloc (cd->task->task_pool, sizeof (struct symbol_remove_data)); + rd = + rspamd_mempool_alloc (cd->task->task_pool, + sizeof (struct symbol_remove_data)); rd->ms = ms; if (G_UNLIKELY (*sym == '~')) { rd->remove_weight = FALSE; @@ -451,7 +496,9 @@ composites_foreach_callback (gpointer key, gpointer value, void *data) rd->remove_weight = TRUE; } if (!g_tree_lookup (cd->symbols_to_remove, rd)) { - g_tree_insert (cd->symbols_to_remove, (gpointer)ms->name, rd); + g_tree_insert (cd->symbols_to_remove, + (gpointer)ms->name, + rd); } } else { @@ -459,10 +506,16 @@ composites_foreach_callback (gpointer key, gpointer value, void *data) } if (s->next) { - r += rspamd_snprintf (logbuf + r, sizeof (logbuf) -r, "%s, ", s->data); + r += rspamd_snprintf (logbuf + r, + sizeof (logbuf) - r, + "%s, ", + s->data); } else { - r += rspamd_snprintf (logbuf + r, sizeof (logbuf) -r, "%s", s->data); + r += rspamd_snprintf (logbuf + r, + sizeof (logbuf) - r, + "%s", + s->data); } s = g_list_next (s); } @@ -479,12 +532,13 @@ composites_foreach_callback (gpointer key, gpointer value, void *data) return; } -static gboolean -check_autolearn (struct statfile_autolearn_params *params, struct rspamd_task *task) +static gboolean +check_autolearn (struct statfile_autolearn_params *params, + struct rspamd_task *task) { - gchar *metric_name = DEFAULT_METRIC; - struct metric_result *metric_res; - GList *cur; + gchar *metric_name = DEFAULT_METRIC; + struct metric_result *metric_res; + GList *cur; if (params->metric != NULL) { metric_name = (gchar *)params->metric; @@ -502,12 +556,16 @@ check_autolearn (struct statfile_autolearn_params *params, struct rspamd_task *t } else { /* Process score of metric */ - if ((params->threshold_min != 0 && metric_res->score > params->threshold_min) || (params->threshold_max != 0 && metric_res->score < params->threshold_max)) { + if ((params->threshold_min != 0 && metric_res->score > + params->threshold_min) || + (params->threshold_max != 0 && metric_res->score < + params->threshold_max)) { /* Now check for specific symbols */ if (params->symbols) { cur = params->symbols; while (cur) { - if (g_hash_table_lookup (metric_res->symbols, cur->data) == NULL) { + if (g_hash_table_lookup (metric_res->symbols, + cur->data) == NULL) { return FALSE; } cur = g_list_next (cur); @@ -522,28 +580,47 @@ check_autolearn (struct statfile_autolearn_params *params, struct rspamd_task *t } void -process_autolearn (struct rspamd_statfile_config *st, struct rspamd_task *task, GTree * tokens, struct classifier *classifier, gchar *filename, struct classifier_ctx *ctx) +process_autolearn (struct rspamd_statfile_config *st, + struct rspamd_task *task, + GTree * tokens, + struct classifier *classifier, + gchar *filename, + struct classifier_ctx *ctx) { - stat_file_t *statfile; - struct rspamd_statfile_config *unused; + stat_file_t *statfile; + struct rspamd_statfile_config *unused; if (check_autolearn (st->autolearn, task)) { if (tokens) { /* Take care of subject */ tokenize_subject (task, &tokens); - msg_info ("message with id <%s> autolearned statfile '%s'", task->message_id, filename); - + msg_info ("message with id <%s> autolearned statfile '%s'", + task->message_id, + filename); + /* Get or create statfile */ - statfile = get_statfile_by_symbol (task->worker->srv->statfile_pool, ctx->cfg, - st->symbol, &unused, TRUE); - + statfile = get_statfile_by_symbol (task->worker->srv->statfile_pool, + ctx->cfg, + st->symbol, + &unused, + TRUE); + if (statfile == NULL) { return; } - classifier->learn_func (ctx, task->worker->srv->statfile_pool, st->symbol, tokens, TRUE, NULL, 1., NULL); + classifier->learn_func (ctx, + task->worker->srv->statfile_pool, + st->symbol, + tokens, + TRUE, + NULL, + 1., + NULL); maybe_write_binlog (ctx->cfg, st, statfile, tokens); - statfile_pool_plan_invalidate (task->worker->srv->statfile_pool, DEFAULT_STATFILE_INVALIDATE_TIME, DEFAULT_STATFILE_INVALIDATE_JITTER); + statfile_pool_plan_invalidate (task->worker->srv->statfile_pool, + DEFAULT_STATFILE_INVALIDATE_TIME, + DEFAULT_STATFILE_INVALIDATE_JITTER); } } } @@ -551,8 +628,8 @@ process_autolearn (struct rspamd_statfile_config *st, struct rspamd_task *task, static gboolean composites_remove_symbols (gpointer key, gpointer value, gpointer data) { - struct composites_data *cd = data; - struct symbol_remove_data *rd = value; + struct composites_data *cd = data; + struct symbol_remove_data *rd = value; if (rd->remove_symbol) { g_hash_table_remove (cd->metric_res->symbols, key); @@ -567,17 +644,22 @@ composites_remove_symbols (gpointer key, gpointer value, gpointer data) static void composites_metric_callback (gpointer key, gpointer value, gpointer data) { - struct rspamd_task *task = (struct rspamd_task *)data; - struct composites_data *cd = rspamd_mempool_alloc (task->task_pool, sizeof (struct composites_data)); - struct metric_result *metric_res = (struct metric_result *)value; + struct rspamd_task *task = (struct rspamd_task *)data; + struct composites_data *cd = + rspamd_mempool_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; cd->symbols_to_remove = g_tree_new (remove_compare_data); - cd->checked = rspamd_mempool_alloc0 (task->task_pool, NBYTES (g_hash_table_size (task->cfg->composite_symbols))); + cd->checked = + rspamd_mempool_alloc0 (task->task_pool, + NBYTES (g_hash_table_size (task->cfg->composite_symbols))); /* Process hash table */ - g_hash_table_foreach (task->cfg->composite_symbols, composites_foreach_callback, cd); + g_hash_table_foreach (task->cfg->composite_symbols, + composites_foreach_callback, + cd); /* Remove symbols that are in composites */ g_tree_foreach (cd->symbols_to_remove, composites_remove_symbols, cd); @@ -599,30 +681,32 @@ struct classifiers_cbdata { static void classifiers_callback (gpointer value, void *arg) { - struct classifiers_cbdata *cbdata = arg; - struct rspamd_task *task; - struct rspamd_classifier_config *cl = value; - struct classifier_ctx *ctx; - struct mime_text_part *text_part, *p1, *p2; - struct rspamd_statfile_config *st; - GTree *tokens = NULL; - GList *cur; - f_str_t c; - gchar *header = NULL; - gint *dist = NULL, diff; - gboolean is_twopart = FALSE; - + struct classifiers_cbdata *cbdata = arg; + struct rspamd_task *task; + struct rspamd_classifier_config *cl = value; + struct classifier_ctx *ctx; + struct mime_text_part *text_part, *p1, *p2; + struct rspamd_statfile_config *st; + GTree *tokens = NULL; + GList *cur; + f_str_t c; + gchar *header = NULL; + gint *dist = NULL, diff; + gboolean is_twopart = FALSE; + task = cbdata->task; if ((header = g_hash_table_lookup (cl->opts, "header")) != NULL) { - cur = message_get_header (task->task_pool, task->message, header, FALSE); + cur = + message_get_header (task->task_pool, task->message, header, FALSE); if (cur) { - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t)g_list_free, cur); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t)g_list_free, cur); } } else { cur = g_list_first (task->text_parts); - dist = rspamd_mempool_get_variable (task->task_pool, "parts_distance"); + dist = rspamd_mempool_get_variable (task->task_pool, "parts_distance"); if (cur != NULL && cur->next != NULL && cur->next->next == NULL) { is_twopart = TRUE; } @@ -635,7 +719,8 @@ classifiers_callback (gpointer value, void *arg) c.len = strlen (cur->data); if (c.len > 0) { c.begin = cur->data; - if (!cl->tokenizer->tokenize_func (cl->tokenizer, task->task_pool, &c, &tokens, FALSE, FALSE, NULL)) { + if (!cl->tokenizer->tokenize_func (cl->tokenizer, + task->task_pool, &c, &tokens, FALSE, FALSE, NULL)) { msg_info ("cannot tokenize input"); return; } @@ -651,7 +736,9 @@ classifiers_callback (gpointer value, void *arg) /* Compare part's content */ if (*dist >= COMMON_PART_FACTOR) { - msg_info ("message <%s> has two common text parts, ignore the last one", task->message_id); + msg_info ( + "message <%s> has two common text parts, ignore the last one", + task->message_id); break; } } @@ -659,21 +746,25 @@ classifiers_callback (gpointer value, void *arg) p1 = cur->prev->data; p2 = text_part; if (p1->diff_str != NULL && p2->diff_str != NULL) { - diff = compare_diff_distance (p1->diff_str, p2->diff_str); + diff = + compare_diff_distance (p1->diff_str, p2->diff_str); } else { diff = fuzzy_compare_parts (p1, p2); } if (diff >= COMMON_PART_FACTOR) { - msg_info ("message <%s> has two common text parts, ignore the last one", task->message_id); + msg_info ( + "message <%s> has two common text parts, ignore the last one", + task->message_id); break; } } c.begin = (gchar *)text_part->content->data; c.len = text_part->content->len; /* Tree would be freed at task pool freeing */ - if (!cl->tokenizer->tokenize_func (cl->tokenizer, task->task_pool, &c, &tokens, - FALSE, text_part->is_utf, text_part->urls_offset)) { + if (!cl->tokenizer->tokenize_func (cl->tokenizer, + task->task_pool, &c, &tokens, + FALSE, text_part->is_utf, text_part->urls_offset)) { msg_info ("cannot tokenize input"); return; } @@ -692,12 +783,20 @@ classifiers_callback (gpointer value, void *arg) if (cbdata->nL != NULL) { rspamd_mutex_lock (cbdata->nL->m); - cl->classifier->classify_func (ctx, task->worker->srv->statfile_pool, tokens, task, cbdata->nL->L); + cl->classifier->classify_func (ctx, + task->worker->srv->statfile_pool, + tokens, + task, + cbdata->nL->L); rspamd_mutex_unlock (cbdata->nL->m); } else { /* Non-threaded case */ - cl->classifier->classify_func (ctx, task->worker->srv->statfile_pool, tokens, task, task->cfg->lua_state); + cl->classifier->classify_func (ctx, + task->worker->srv->statfile_pool, + tokens, + task, + task->cfg->lua_state); } /* Autolearning */ @@ -707,7 +806,12 @@ classifiers_callback (gpointer value, void *arg) if (st->autolearn) { if (check_autolearn (st->autolearn, task)) { /* Process autolearn */ - process_autolearn (st, task, tokens, cl->classifier, st->path, ctx); + process_autolearn (st, + task, + tokens, + cl->classifier, + st->path, + ctx); } } cur = g_list_next (cur); @@ -718,7 +822,7 @@ classifiers_callback (gpointer value, void *arg) void process_statfiles (struct rspamd_task *task) { - struct classifiers_cbdata cbdata; + struct classifiers_cbdata cbdata; if (task->is_skipped) { return; @@ -726,7 +830,8 @@ process_statfiles (struct rspamd_task *task) if (task->tokens == NULL) { task->tokens = g_hash_table_new (g_direct_hash, g_direct_equal); - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t)g_hash_table_unref, task->tokens); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t)g_hash_table_unref, task->tokens); } cbdata.task = task; cbdata.nL = NULL; @@ -739,9 +844,9 @@ process_statfiles (struct rspamd_task *task) void process_statfiles_threaded (gpointer data, gpointer user_data) { - struct rspamd_task *task = (struct rspamd_task *)data; - struct lua_locked_state *nL = user_data; - struct classifiers_cbdata cbdata; + struct rspamd_task *task = (struct rspamd_task *)data; + struct lua_locked_state *nL = user_data; + struct classifiers_cbdata cbdata; if (task->is_skipped) { remove_async_thread (task->s); @@ -750,7 +855,8 @@ process_statfiles_threaded (gpointer data, gpointer user_data) if (task->tokens == NULL) { task->tokens = g_hash_table_new (g_direct_hash, g_direct_equal); - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t)g_hash_table_unref, task->tokens); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t)g_hash_table_unref, task->tokens); } cbdata.task = task; @@ -760,18 +866,22 @@ process_statfiles_threaded (gpointer data, gpointer user_data) } static void -insert_metric_header (gpointer metric_name, gpointer metric_value, gpointer data) +insert_metric_header (gpointer metric_name, gpointer metric_value, + gpointer data) { #ifndef GLIB_HASH_COMPAT - struct rspamd_task *task = (struct rspamd_task *)data; - gint r = 0; + struct rspamd_task *task = (struct rspamd_task *)data; + gint r = 0; /* Try to be rfc2822 compatible and avoid long headers with folding */ - gchar header_name[128], outbuf[1000]; - GList *symbols = NULL, *cur; - struct metric_result *metric_res = (struct metric_result *)metric_value; - double ms; + gchar header_name[128], outbuf[1000]; + GList *symbols = NULL, *cur; + struct metric_result *metric_res = (struct metric_result *)metric_value; + double ms; - rspamd_snprintf (header_name, sizeof (header_name), "X-Spam-%s", metric_res->metric->name); + rspamd_snprintf (header_name, + sizeof (header_name), + "X-Spam-%s", + metric_res->metric->name); if (!check_metric_settings (task, metric_res->metric, &ms)) { ms = metric_res->metric->actions[METRIC_ACTION_REJECT].score; @@ -800,7 +910,8 @@ insert_metric_header (gpointer metric_name, gpointer metric_value, gpointer data } g_list_free (symbols); #ifdef GMIME24 - g_mime_object_append_header (GMIME_OBJECT (task->message), header_name, outbuf); + g_mime_object_append_header (GMIME_OBJECT ( + task->message), header_name, outbuf); #else g_mime_message_add_header (task->message, header_name, outbuf); #endif @@ -820,13 +931,16 @@ 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) { + 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) { + 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) { + else if (g_ascii_strncasecmp (data, "rewrite_subject", + sizeof ("rewrite_subject") - 1) == 0) { *result = METRIC_ACTION_REWRITE_SUBJECT; } else { @@ -861,9 +975,9 @@ str_action_metric (enum rspamd_metric_action action) gint check_metric_action (double score, double required_score, struct metric *metric) { - struct metric_action *action, *selected_action = NULL; - double max_score = 0; - int i; + struct metric_action *action, *selected_action = NULL; + double max_score = 0; + int i; if (score >= required_score) { return METRIC_ACTION_REJECT; @@ -872,7 +986,7 @@ check_metric_action (double score, double required_score, struct metric *metric) return METRIC_ACTION_NOACTION; } else { - for (i = METRIC_ACTION_REJECT; i < METRIC_ACTION_MAX; i ++) { + for (i = METRIC_ACTION_REJECT; i < METRIC_ACTION_MAX; i++) { action = &metric->actions[i]; if (action->score < 0) { continue; @@ -894,24 +1008,26 @@ check_metric_action (double score, double required_score, struct metric *metric) gboolean learn_task (const gchar *statfile, struct rspamd_task *task, GError **err) { - GList *cur, *ex; - struct rspamd_classifier_config *cl; - struct classifier_ctx *cls_ctx; - gchar *s; - f_str_t c; - GTree *tokens = NULL; - struct rspamd_statfile_config *st; - stat_file_t *stf; - gdouble sum; - struct mime_text_part *part, *p1, *p2; - gboolean is_utf = FALSE, is_twopart = FALSE; - gint diff; + GList *cur, *ex; + struct rspamd_classifier_config *cl; + struct classifier_ctx *cls_ctx; + gchar *s; + f_str_t c; + GTree *tokens = NULL; + struct rspamd_statfile_config *st; + stat_file_t *stf; + gdouble sum; + struct mime_text_part *part, *p1, *p2; + gboolean is_utf = FALSE, is_twopart = FALSE; + gint diff; /* Load classifier by symbol */ cl = g_hash_table_lookup (task->cfg->classifiers_symbols, statfile); if (cl == NULL) { - g_set_error (err, filter_error_quark(), 1, "Statfile %s is not configured in any classifier", statfile); + g_set_error (err, + filter_error_quark (), 1, "Statfile %s is not configured in any classifier", + statfile); return FALSE; } @@ -919,7 +1035,8 @@ learn_task (const gchar *statfile, struct rspamd_task *task, GError **err) if ((s = g_hash_table_lookup (cl->opts, "header")) != NULL) { cur = message_get_header (task->task_pool, task->message, s, FALSE); if (cur) { - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t)g_list_free, cur); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t)g_list_free, cur); } } else { @@ -959,7 +1076,9 @@ learn_task (const gchar *statfile, struct rspamd_task *task, GError **err) diff = fuzzy_compare_parts (p1, p2); } if (diff >= COMMON_PART_FACTOR) { - msg_info ("message <%s> has two common text parts, ignore the last one", task->message_id); + msg_info ( + "message <%s> has two common text parts, ignore the last one", + task->message_id); break; } } @@ -968,7 +1087,8 @@ learn_task (const gchar *statfile, struct rspamd_task *task, GError **err) if (!cl->tokenizer->tokenize_func ( cl->tokenizer, task->task_pool, &c, &tokens, FALSE, is_utf, ex)) { - g_set_error (err, filter_error_quark(), 2, "Cannot tokenize message"); + g_set_error (err, + filter_error_quark (), 2, "Cannot tokenize message"); return FALSE; } cur = g_list_next (cur); @@ -976,8 +1096,10 @@ learn_task (const gchar *statfile, struct rspamd_task *task, GError **err) /* Handle messages without text */ if (tokens == NULL) { - g_set_error (err, filter_error_quark(), 3, "Cannot tokenize message, no text data"); - msg_info ("learn failed for message <%s>, no tokens to extract", task->message_id); + g_set_error (err, + filter_error_quark (), 3, "Cannot tokenize message, no text data"); + msg_info ("learn failed for message <%s>, no tokens to extract", + task->message_id); return FALSE; } @@ -986,7 +1108,7 @@ learn_task (const gchar *statfile, struct rspamd_task *task, GError **err) /* Init classifier */ cls_ctx = cl->classifier->init_func ( - task->task_pool, cl); + task->task_pool, cl); /* Get or create statfile */ stf = get_statfile_by_symbol (task->worker->srv->statfile_pool, cl, statfile, &st, TRUE); @@ -997,12 +1119,17 @@ learn_task (const gchar *statfile, struct rspamd_task *task, GError **err) statfile, tokens, TRUE, &sum, 1.0, err)) { if (*err) { - msg_info ("learn failed for message <%s>, learn error: %s", task->message_id, (*err)->message); + msg_info ("learn failed for message <%s>, learn error: %s", + task->message_id, + (*err)->message); return FALSE; } else { - g_set_error (err, filter_error_quark(), 4, "Learn failed, unknown learn classifier error"); - msg_info ("learn failed for message <%s>, unknown learn error", task->message_id); + g_set_error (err, + filter_error_quark (), 4, + "Learn failed, unknown learn classifier error"); + msg_info ("learn failed for message <%s>, unknown learn error", + task->message_id); return FALSE; } } @@ -1010,25 +1137,31 @@ learn_task (const gchar *statfile, struct rspamd_task *task, GError **err) task->worker->srv->stat->messages_learned++; maybe_write_binlog (cl, st, stf, tokens); - msg_info ("learn success for message <%s>, for statfile: %s, sum weight: %.2f", - task->message_id, statfile, sum); + msg_info ( + "learn success for message <%s>, for statfile: %s, sum weight: %.2f", + task->message_id, + statfile, + sum); statfile_pool_plan_invalidate (task->worker->srv->statfile_pool, - DEFAULT_STATFILE_INVALIDATE_TIME, - DEFAULT_STATFILE_INVALIDATE_JITTER); + DEFAULT_STATFILE_INVALIDATE_TIME, + DEFAULT_STATFILE_INVALIDATE_JITTER); return TRUE; } gboolean -learn_task_spam (struct rspamd_classifier_config *cl, struct rspamd_task *task, gboolean is_spam, GError **err) +learn_task_spam (struct rspamd_classifier_config *cl, + struct rspamd_task *task, + gboolean is_spam, + GError **err) { - GList *cur, *ex; - struct classifier_ctx *cls_ctx; - f_str_t c; - GTree *tokens = NULL; - struct mime_text_part *part, *p1, *p2; - gboolean is_utf = FALSE, is_twopart = FALSE; - gint diff; + GList *cur, *ex; + struct classifier_ctx *cls_ctx; + f_str_t c; + GTree *tokens = NULL; + struct mime_text_part *part, *p1, *p2; + gboolean is_utf = FALSE, is_twopart = FALSE; + gint diff; cur = g_list_first (task->text_parts); if (cur != NULL && cur->next != NULL && cur->next->next == NULL) { @@ -1061,7 +1194,9 @@ learn_task_spam (struct rspamd_classifier_config *cl, struct rspamd_task *task, diff = fuzzy_compare_parts (p1, p2); } if (diff >= COMMON_PART_FACTOR) { - msg_info ("message <%s> has two common text parts, ignore the last one", task->message_id); + msg_info ( + "message <%s> has two common text parts, ignore the last one", + task->message_id); break; } } @@ -1069,7 +1204,8 @@ learn_task_spam (struct rspamd_classifier_config *cl, struct rspamd_task *task, if (!cl->tokenizer->tokenize_func ( cl->tokenizer, task->task_pool, &c, &tokens, FALSE, is_utf, ex)) { - g_set_error (err, filter_error_quark(), 2, "Cannot tokenize message"); + g_set_error (err, + filter_error_quark (), 2, "Cannot tokenize message"); return FALSE; } cur = g_list_next (cur); @@ -1077,8 +1213,10 @@ learn_task_spam (struct rspamd_classifier_config *cl, struct rspamd_task *task, /* Handle messages without text */ if (tokens == NULL) { - g_set_error (err, filter_error_quark(), 3, "Cannot tokenize message, no text data"); - msg_info ("learn failed for message <%s>, no tokens to extract", task->message_id); + g_set_error (err, + filter_error_quark (), 3, "Cannot tokenize message, no text data"); + msg_info ("learn failed for message <%s>, no tokens to extract", + task->message_id); return FALSE; } @@ -1087,18 +1225,23 @@ learn_task_spam (struct rspamd_classifier_config *cl, struct rspamd_task *task, /* Init classifier */ cls_ctx = cl->classifier->init_func ( - task->task_pool, cl); + task->task_pool, cl); /* Learn */ if (!cl->classifier->learn_spam_func ( cls_ctx, task->worker->srv->statfile_pool, tokens, task, is_spam, task->cfg->lua_state, err)) { if (*err) { - msg_info ("learn failed for message <%s>, learn error: %s", task->message_id, (*err)->message); + msg_info ("learn failed for message <%s>, learn error: %s", + task->message_id, + (*err)->message); return FALSE; } else { - g_set_error (err, filter_error_quark(), 4, "Learn failed, unknown learn classifier error"); - msg_info ("learn failed for message <%s>, unknown learn error", task->message_id); + g_set_error (err, + filter_error_quark (), 4, + "Learn failed, unknown learn classifier error"); + msg_info ("learn failed for message <%s>, unknown learn error", + task->message_id); return FALSE; } } @@ -1106,14 +1249,14 @@ learn_task_spam (struct rspamd_classifier_config *cl, struct rspamd_task *task, task->worker->srv->stat->messages_learned++; msg_info ("learn success for message <%s>", - task->message_id); + task->message_id); statfile_pool_plan_invalidate (task->worker->srv->statfile_pool, - DEFAULT_STATFILE_INVALIDATE_TIME, - DEFAULT_STATFILE_INVALIDATE_JITTER); + DEFAULT_STATFILE_INVALIDATE_TIME, + DEFAULT_STATFILE_INVALIDATE_JITTER); return TRUE; } -/* - * vi:ts=4 +/* + * vi:ts=4 */ diff --git a/src/libmime/filter.h b/src/libmime/filter.h index 2891ebd00..f0a343483 100644 --- a/src/libmime/filter.h +++ b/src/libmime/filter.h @@ -14,7 +14,8 @@ struct rspamd_task; struct rspamd_settings; struct rspamd_classifier_config; -typedef double (*metric_cons_func)(struct rspamd_task *task, const gchar *metric_name, const gchar *func_name); +typedef double (*metric_cons_func)(struct rspamd_task *task, + const gchar *metric_name, const gchar *func_name); typedef void (*filter_func)(struct rspamd_task *task); enum filter_type { C_FILTER, PERL_FILTER }; @@ -23,17 +24,17 @@ enum filter_type { C_FILTER, PERL_FILTER }; * Filter structure */ struct filter { - gchar *func_name; /**< function name */ - enum filter_type type; /**< filter type (c or perl) */ - module_t *module; + gchar *func_name; /**< function name */ + enum filter_type type; /**< filter type (c or perl) */ + module_t *module; }; /** * Rspamd symbol */ struct symbol { - double score; /**< symbol's score */ - GList *options; /**< list of symbol's options */ + double score; /**< symbol's score */ + GList *options; /**< list of symbol's options */ const gchar *name; }; @@ -46,25 +47,25 @@ struct metric_action { * Common definition of metric */ struct metric { - const gchar *name; /**< name of metric */ - gchar *func_name; /**< name of consolidation function */ - metric_cons_func func; /**< c consolidation function */ - double grow_factor; /**< grow factor for metric */ - GHashTable *symbols; /**< weights of symbols in metric */ - GHashTable *descriptions; /**< descriptions of symbols in metric */ + const gchar *name; /**< name of metric */ + gchar *func_name; /**< name of consolidation function */ + metric_cons_func func; /**< c consolidation function */ + double grow_factor; /**< grow factor for metric */ + GHashTable *symbols; /**< weights of symbols in metric */ + GHashTable *descriptions; /**< descriptions of symbols in metric */ struct metric_action actions[METRIC_ACTION_MAX]; /**< all actions of the metric */ - gchar *subject; /**< subject rewrite string */ + gchar *subject; /**< subject rewrite string */ }; /** * Result of metric processing */ struct metric_result { - struct metric *metric; /**< pointer to metric structure */ - double score; /**< total score */ - GHashTable *symbols; /**< symbols of metric */ - gboolean checked; /**< whether metric result is consolidated */ - double grow_factor; /**< current grow factor */ + struct metric *metric; /**< pointer to metric structure */ + double score; /**< total score */ + GHashTable *symbols; /**< symbols of metric */ + gboolean checked; /**< whether metric result is consolidated */ + double grow_factor; /**< current grow factor */ }; /** @@ -102,7 +103,10 @@ void process_statfiles_threaded (gpointer data, gpointer user_data); * @param flag numeric weight for symbol * @param opts list of symbol's options */ -void insert_result (struct rspamd_task *task, const gchar *symbol, double flag, GList *opts); +void insert_result (struct rspamd_task *task, + const gchar *symbol, + double flag, + GList *opts); /** * Insert a single result to task @@ -112,7 +116,10 @@ void insert_result (struct rspamd_task *task, const gchar *symbol, double flag, * @param flag numeric weight for symbol * @param opts list of symbol's options */ -void insert_result_single (struct rspamd_task *task, const gchar *symbol, double flag, GList *opts); +void insert_result_single (struct rspamd_task *task, + const gchar *symbol, + double flag, + GList *opts); /** * Process all results and form composite metrics from existent metrics as it is defined in config @@ -121,13 +128,15 @@ void insert_result_single (struct rspamd_task *task, const gchar *symbol, double void make_composites (struct rspamd_task *task); /** - * Default consolidation function for metric, it get all symbols and multiply symbol + * Default consolidation function for metric, it get all symbols and multiply symbol * weight by some factor that is specified in config. Default factor is 1. * @param task worker's task that present message from user * @param metric_name name of metric * @return result metric weight */ -double factor_consolidation_func (struct rspamd_task *task, const gchar *metric_name, const gchar *unused); +double factor_consolidation_func (struct rspamd_task *task, + const gchar *metric_name, + const gchar *unused); /* * Learn specified statfile with message in a task @@ -136,7 +145,9 @@ double factor_consolidation_func (struct rspamd_task *task, const gchar *metric_ * @param err pointer to GError * @return true if learn succeed */ -gboolean learn_task (const gchar *statfile, struct rspamd_task *task, GError **err); +gboolean learn_task (const gchar *statfile, + struct rspamd_task *task, + GError **err); /* * Learn specified statfile with message in a task @@ -145,7 +156,10 @@ gboolean learn_task (const gchar *statfile, struct rspamd_task *task, GError **e * @param err pointer to GError * @return true if learn succeed */ -gboolean learn_task_spam (struct rspamd_classifier_config *cl, struct rspamd_task *task, gboolean is_spam, GError **err); +gboolean learn_task_spam (struct rspamd_classifier_config *cl, + struct rspamd_task *task, + gboolean is_spam, + GError **err); /* * Get action from a string @@ -155,11 +169,13 @@ gboolean check_action_str (const gchar *data, gint *result); /* * Return textual representation of action enumeration */ -const gchar *str_action_metric (enum rspamd_metric_action action); +const gchar * str_action_metric (enum rspamd_metric_action action); /* * Get action for specific metric */ -gint check_metric_action (double score, double required_score, struct metric *metric); +gint check_metric_action (double score, + double required_score, + struct metric *metric); #endif diff --git a/src/libmime/images.c b/src/libmime/images.c index ff07bbd72..3b2ceecd1 100644 --- a/src/libmime/images.c +++ b/src/libmime/images.c @@ -32,19 +32,20 @@ static const guint8 jpg_sig2[] = {'J', 'F', 'I', 'F'}; static const guint8 gif_signature[] = {'G', 'I', 'F', '8'}; static const guint8 bmp_signature[] = {'B', 'M'}; -static void process_image (struct rspamd_task *task, struct mime_part *part); +static void process_image (struct rspamd_task *task, struct mime_part *part); void process_images (struct rspamd_task *task) { - GList *cur; - struct mime_part *part; + GList *cur; + struct mime_part *part; cur = task->parts; while (cur) { part = cur->data; - if (g_mime_content_type_is_type (part->type, "image", "*") && part->content->len > 0) { + if (g_mime_content_type_is_type (part->type, "image", + "*") && part->content->len > 0) { process_image (task, part); } cur = g_list_next (cur); @@ -85,9 +86,9 @@ detect_image_type (GByteArray *data) static struct rspamd_image * process_png_image (struct rspamd_task *task, GByteArray *data) { - struct rspamd_image *img; - guint32 t; - guint8 *p; + struct rspamd_image *img; + guint32 t; + guint8 *p; if (data->len < 24) { msg_info ("bad png detected (maybe striped): <%s>", task->message_id); @@ -119,10 +120,10 @@ process_png_image (struct rspamd_task *task, GByteArray *data) static struct rspamd_image * process_jpg_image (struct rspamd_task *task, GByteArray *data) { - guint8 *p; - guint16 t; - gsize remain; - struct rspamd_image *img; + guint8 *p; + guint16 t; + gsize remain; + struct rspamd_image *img; img = rspamd_mempool_alloc (task->task_pool, sizeof (struct rspamd_image)); img->type = IMAGE_TYPE_JPG; @@ -131,15 +132,16 @@ process_jpg_image (struct rspamd_task *task, GByteArray *data) p = data->data; remain = data->len; /* In jpeg we should find any data stream (ff c0 .. ff c3) and extract its height and width */ - while (remain --) { - if (*p == 0xFF && remain > 8 && (*(p + 1) >= 0xC0 && *(p + 1) <= 0xC3)) { + while (remain--) { + if (*p == 0xFF && remain > 8 && + (*(p + 1) >= 0xC0 && *(p + 1) <= 0xC3)) { memcpy (&t, p + 5, sizeof (guint16)); img->height = ntohs (t); memcpy (&t, p + 7, sizeof (guint16)); img->width = ntohs (t); return img; } - p ++; + p++; } return NULL; @@ -148,9 +150,9 @@ process_jpg_image (struct rspamd_task *task, GByteArray *data) static struct rspamd_image * process_gif_image (struct rspamd_task *task, GByteArray *data) { - struct rspamd_image *img; - guint8 *p; - guint16 t; + struct rspamd_image *img; + guint8 *p; + guint16 t; if (data->len < 10) { msg_info ("bad gif detected (maybe striped): <%s>", task->message_id); @@ -162,7 +164,7 @@ process_gif_image (struct rspamd_task *task, GByteArray *data) img->data = data; p = data->data + 6; - memcpy (&t, p, sizeof (guint16)); + memcpy (&t, p, sizeof (guint16)); img->width = GUINT16_FROM_LE (t); memcpy (&t, p + 2, sizeof (guint16)); img->height = GUINT16_FROM_LE (t); @@ -173,9 +175,9 @@ process_gif_image (struct rspamd_task *task, GByteArray *data) static struct rspamd_image * process_bmp_image (struct rspamd_task *task, GByteArray *data) { - struct rspamd_image *img; - gint32 t; - guint8 *p; + struct rspamd_image *img; + gint32 t; + guint8 *p; @@ -188,7 +190,7 @@ process_bmp_image (struct rspamd_task *task, GByteArray *data) img->type = IMAGE_TYPE_BMP; img->data = data; p = data->data + 18; - memcpy (&t, p, sizeof (gint32)); + memcpy (&t, p, sizeof (gint32)); img->width = abs (GINT32_FROM_LE (t)); memcpy (&t, p + 4, sizeof (gint32)); img->height = abs (GINT32_FROM_LE (t)); @@ -199,8 +201,8 @@ process_bmp_image (struct rspamd_task *task, GByteArray *data) static void process_image (struct rspamd_task *task, struct mime_part *part) { - enum known_image_types type; - struct rspamd_image *img = NULL; + enum known_image_types type; + struct rspamd_image *img = NULL; if ((type = detect_image_type (part->content)) != IMAGE_TYPE_UNKNOWN) { switch (type) { case IMAGE_TYPE_PNG: @@ -223,9 +225,9 @@ process_image (struct rspamd_task *task, struct mime_part *part) if (img != NULL) { debug_task ("detected %s image of size %ud x %ud in message <%s>", - image_type_str (img->type), - img->width, img->height, - task->message_id); + image_type_str (img->type), + img->width, img->height, + task->message_id); img->filename = part->filename; task->images = g_list_prepend (task->images, img); } diff --git a/src/libmime/images.h b/src/libmime/images.h index c43941ebc..5648f030f 100644 --- a/src/libmime/images.h +++ b/src/libmime/images.h @@ -28,6 +28,6 @@ void process_images (struct rspamd_task *task); /* * Get textual representation of an image's type */ -const gchar *image_type_str (enum known_image_types type); +const gchar * image_type_str (enum known_image_types type); #endif /* IMAGES_H_ */ diff --git a/src/libmime/message.c b/src/libmime/message.c index 4567869e9..c6de73782 100644 --- a/src/libmime/message.c +++ b/src/libmime/message.c @@ -22,26 +22,30 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" -#include "util.h" -#include "main.h" -#include "message.h" #include "cfg_file.h" +#include "config.h" #include "html.h" #include "images.h" +#include "main.h" +#include "message.h" +#include "util.h" #define RECURSION_LIMIT 30 #define UTF8_CHARSET "UTF-8" -GByteArray * -strip_html_tags (struct rspamd_task *task, rspamd_mempool_t * pool, struct mime_text_part *part, GByteArray * src, gint *stateptr) +GByteArray * +strip_html_tags (struct rspamd_task *task, + rspamd_mempool_t * pool, + struct mime_text_part *part, + GByteArray * src, + gint *stateptr) { - uint8_t *p, *rp, *tbegin = NULL, *end, c, lc; - gint br, i = 0, depth = 0, in_q = 0; - gint state = 0; - GByteArray *buf; - GNode *level_ptr = NULL; - gboolean erase = FALSE; + uint8_t *p, *rp, *tbegin = NULL, *end, c, lc; + gint br, i = 0, depth = 0, in_q = 0; + gint state = 0; + GByteArray *buf; + GNode *level_ptr = NULL; + gboolean erase = FALSE; if (stateptr) state = *stateptr; @@ -71,11 +75,11 @@ strip_html_tags (struct rspamd_task *task, rspamd_mempool_t * pool, struct mime_ } else if (state == 1) { /* Opening bracket without closing one */ - p --; + p--; while (g_ascii_isspace (*p) && p > src->data) { - p --; + p--; } - p ++; + p++; goto unbreak_tag; } break; @@ -115,13 +119,19 @@ strip_html_tags (struct rspamd_task *task, rspamd_mempool_t * pool, struct mime_ } unbreak_tag: switch (state) { - case 1: /* HTML/XML */ + case 1: /* HTML/XML */ lc = '>'; in_q = state = 0; - erase = !add_html_node (task, pool, part, tbegin, p - tbegin, end - tbegin, &level_ptr); + erase = !add_html_node (task, + pool, + part, + tbegin, + p - tbegin, + end - tbegin, + &level_ptr); break; - case 2: /* PHP */ + case 2: /* PHP */ if (!br && lc != '\"' && *(p - 1) == '?') { in_q = state = 0; } @@ -131,7 +141,7 @@ unbreak_tag: in_q = state = 0; break; - case 4: /* JavaScript/CSS/etc... */ + case 4: /* JavaScript/CSS/etc... */ if (p >= src->data + 2 && *(p - 1) == '-' && *(p - 2) == '-') { in_q = state = 0; } @@ -158,7 +168,8 @@ unbreak_tag: else if (state == 0 && !erase) { *(rp++) = c; } - if (state && p != src->data && *(p - 1) != '\\' && (!in_q || *p == in_q)) { + if (state && p != src->data && *(p - 1) != '\\' && + (!in_q || *p == in_q)) { if (in_q) { in_q = 0; } @@ -182,7 +193,8 @@ unbreak_tag: break; case '-': - if (state == 3 && p >= src->data + 2 && *(p - 1) == '-' && *(p - 2) == '!') { + if (state == 3 && p >= src->data + 2 && *(p - 1) == '-' && + *(p - 2) == '!') { state = 4; } else { @@ -204,11 +216,14 @@ unbreak_tag: if (state == 3 && p > src->data + 6 && g_ascii_tolower (*(p - 1)) == 'p' && g_ascii_tolower (*(p - 2)) == 'y' - && g_ascii_tolower (*(p - 3)) == 't' && g_ascii_tolower (*(p - 4)) == 'c' && g_ascii_tolower (*(p - 5)) == 'o' && g_ascii_tolower (*(p - 6)) == 'd') { + && g_ascii_tolower (*(p - 3)) == 't' && + g_ascii_tolower (*(p - 4)) == 'c' && + g_ascii_tolower (*(p - 5)) == 'o' && + g_ascii_tolower (*(p - 6)) == 'd') { state = 1; break; } - /* fall-through */ + /* fall-through */ case 'l': @@ -216,14 +231,15 @@ unbreak_tag: * state == 2 (PHP). Switch back to HTML. */ - if (state == 2 && p > src->data + 2 && *(p - 1) == 'm' && *(p - 2) == 'x') { + if (state == 2 && p > src->data + 2 && *(p - 1) == 'm' && + *(p - 2) == 'x') { state = 1; break; } - /* fall-through */ + /* fall-through */ default: - reg_char: +reg_char: if (state == 0 && !erase) { *(rp++) = c; } @@ -252,9 +268,11 @@ unbreak_tag: } static void -parse_qmail_recv (rspamd_mempool_t * pool, gchar *line, struct received_header *r) +parse_qmail_recv (rspamd_mempool_t * pool, + gchar *line, + struct received_header *r) { - gchar *s, *p, t; + gchar *s, *p, t; /* We are interested only with received from network headers */ if ((p = strstr (line, "from network")) == NULL) { @@ -269,7 +287,7 @@ parse_qmail_recv (rspamd_mempool_t * pool, gchar *line, struct received_header * /* format is ip/host */ s = p; if (*p) { - while (g_ascii_isdigit (*++p) || *p == '.'); + while (g_ascii_isdigit (*++p) || *p == '.') ; if (*p != '/') { r->is_error = 1; return; @@ -280,7 +298,8 @@ parse_qmail_recv (rspamd_mempool_t * pool, gchar *line, struct received_header * *p = '/'; /* Now try to parse hostname */ s = ++p; - while (g_ascii_isalnum (*p) || *p == '.' || *p == '-' || *p == '_') { + while (g_ascii_isalnum (*p) || *p == '.' || *p == '-' || *p == + '_') { p++; } t = *p; @@ -292,9 +311,11 @@ parse_qmail_recv (rspamd_mempool_t * pool, gchar *line, struct received_header * } static void -parse_recv_header (rspamd_mempool_t * pool, gchar *line, struct received_header *r) +parse_recv_header (rspamd_mempool_t * pool, + gchar *line, + struct received_header *r) { - gchar *p, *s, t, **res = NULL; + gchar *p, *s, t, **res = NULL; enum { RSPAMD_RECV_STATE_INIT = 0, RSPAMD_RECV_STATE_FROM, @@ -305,8 +326,8 @@ parse_recv_header (rspamd_mempool_t * pool, gchar *line, struct received_header RSPAMD_RECV_STATE_SKIP_SPACES, RSPAMD_RECV_STATE_ERROR } state = RSPAMD_RECV_STATE_INIT, - next_state = RSPAMD_RECV_STATE_INIT; - gboolean is_exim = FALSE; + next_state = RSPAMD_RECV_STATE_INIT; + gboolean is_exim = FALSE; g_strstrip (line); p = line; @@ -314,16 +335,18 @@ parse_recv_header (rspamd_mempool_t * pool, gchar *line, struct received_header while (*p) { switch (state) { - /* Initial state, search for from */ + /* Initial state, search for from */ case RSPAMD_RECV_STATE_INIT: if (*p == 'f' || *p == 'F') { - if (g_ascii_tolower (*++p) == 'r' && g_ascii_tolower (*++p) == 'o' && g_ascii_tolower (*++p) == 'm') { + if (g_ascii_tolower (*++p) == 'r' && g_ascii_tolower (*++p) == + 'o' && g_ascii_tolower (*++p) == 'm') { p++; state = RSPAMD_RECV_STATE_SKIP_SPACES; next_state = RSPAMD_RECV_STATE_FROM; } } - else if (g_ascii_tolower (*p) == 'b' && g_ascii_tolower (*(p + 1)) == 'y') { + else if (g_ascii_tolower (*p) == 'b' && + g_ascii_tolower (*(p + 1)) == 'y') { state = RSPAMD_RECV_STATE_IP_BLOCK; } else { @@ -332,7 +355,7 @@ parse_recv_header (rspamd_mempool_t * pool, gchar *line, struct received_header return; } break; - /* Read hostname */ + /* Read hostname */ case RSPAMD_RECV_STATE_FROM: if (*p == '[') { /* This should be IP address */ @@ -341,7 +364,8 @@ parse_recv_header (rspamd_mempool_t * pool, gchar *line, struct received_header next_state = RSPAMD_RECV_STATE_IP_BLOCK; s = ++p; } - else if (g_ascii_isalnum (*p) || *p == '.' || *p == '-' || *p == '_') { + else if (g_ascii_isalnum (*p) || *p == '.' || *p == '-' || *p == + '_') { p++; } else { @@ -353,10 +377,11 @@ parse_recv_header (rspamd_mempool_t * pool, gchar *line, struct received_header next_state = RSPAMD_RECV_STATE_IP_BLOCK; } break; - /* Try to extract additional info */ + /* Try to extract additional info */ case RSPAMD_RECV_STATE_IP_BLOCK: /* Try to extract ip or () info or by */ - if (g_ascii_tolower (*p) == 'b' && g_ascii_tolower (*(p + 1)) == 'y') { + if (g_ascii_tolower (*p) == 'b' && g_ascii_tolower (*(p + 1)) == + 'y') { p += 2; /* Skip spaces after by */ state = RSPAMD_RECV_STATE_SKIP_SPACES; @@ -378,11 +403,11 @@ parse_recv_header (rspamd_mempool_t * pool, gchar *line, struct received_header p++; } break; - /* We are in () block. Here can be found real hostname and real ip, this is written by some MTA */ + /* We are in () block. Here can be found real hostname and real ip, this is written by some MTA */ case RSPAMD_RECV_STATE_BRACES_BLOCK: /* End of block */ if (g_ascii_isalnum (*p) || *p == '.' || *p == '-' || - *p == '_' || *p == ':') { + *p == '_' || *p == ':') { p++; } else if (*p == '[') { @@ -404,41 +429,45 @@ parse_recv_header (rspamd_mempool_t * pool, gchar *line, struct received_header next_state = RSPAMD_RECV_STATE_BRACES_BLOCK; } else if (p - s == 4 && memcmp (s, "helo=", 5) == 0) { - p ++; + p++; is_exim = TRUE; - if (r->real_hostname == NULL && r->from_hostname != NULL) { + if (r->real_hostname == NULL && r->from_hostname != + NULL) { r->real_hostname = r->from_hostname; } s = p; - while (*p != ')' && !g_ascii_isspace (*p) && *p != '\0') { - p ++; + while (*p != ')' && !g_ascii_isspace (*p) && *p != + '\0') { + p++; } if (p > s) { - r->from_hostname = rspamd_mempool_alloc (pool, p - s + 1); + r->from_hostname = rspamd_mempool_alloc (pool, + p - s + 1); rspamd_strlcpy (r->from_hostname, s, p - s + 1); } } else if (p - s == 4 && memcmp (s, "port=", 5) == 0) { - p ++; + p++; is_exim = TRUE; while (g_ascii_isdigit (*p)) { - p ++; + p++; } state = RSPAMD_RECV_STATE_SKIP_SPACES; next_state = RSPAMD_RECV_STATE_BRACES_BLOCK; } else if (*p == '=' && is_exim) { /* Just skip unknown pairs */ - p ++; - while (!g_ascii_isspace (*p) && *p != ')' && *p != '\0') { - p ++; + p++; + while (!g_ascii_isspace (*p) && *p != ')' && *p != + '\0') { + p++; } state = RSPAMD_RECV_STATE_SKIP_SPACES; next_state = RSPAMD_RECV_STATE_BRACES_BLOCK; } else { /* skip all */ - while (*p++ != ')' && *p != '\0'); + while (*p++ != ')' && *p != '\0') ; state = RSPAMD_RECV_STATE_IP_BLOCK; } } @@ -457,13 +486,13 @@ parse_recv_header (rspamd_mempool_t * pool, gchar *line, struct received_header continue; } if (*p == ')') { - p ++; + p++; state = RSPAMD_RECV_STATE_SKIP_SPACES; next_state = RSPAMD_RECV_STATE_IP_BLOCK; } } else if (*p == ')') { - p ++; + p++; state = RSPAMD_RECV_STATE_SKIP_SPACES; next_state = RSPAMD_RECV_STATE_IP_BLOCK; } @@ -473,11 +502,11 @@ parse_recv_header (rspamd_mempool_t * pool, gchar *line, struct received_header } } break; - /* Got by word */ + /* Got by word */ case RSPAMD_RECV_STATE_BY_BLOCK: /* Here can be only hostname */ if ((g_ascii_isalnum (*p) || *p == '.' || *p == '-' - || *p == '_') && p[1] != '\0') { + || *p == '_') && p[1] != '\0') { p++; } else { @@ -499,7 +528,8 @@ parse_recv_header (rspamd_mempool_t * pool, gchar *line, struct received_header } else if (r->from_ip == NULL && r->real_ip != NULL) { r->from_ip = r->real_ip; - if (r->real_hostname == NULL && r->from_hostname != NULL) { + if (r->real_hostname == NULL && r->from_hostname != + NULL) { r->real_hostname = r->from_hostname; } } @@ -508,10 +538,10 @@ parse_recv_header (rspamd_mempool_t * pool, gchar *line, struct received_header } break; - /* Extract ip */ + /* Extract ip */ case RSPAMD_RECV_STATE_PARSE_IP: while (g_ascii_isxdigit (*p) || *p == '.' || *p == ':') { - p ++; + p++; } if (*p != ']') { /* Not an ip in fact */ @@ -527,7 +557,7 @@ parse_recv_header (rspamd_mempool_t * pool, gchar *line, struct received_header } break; - /* Skip spaces */ + /* Skip spaces */ case RSPAMD_RECV_STATE_SKIP_SPACES: if (!g_ascii_isspace (*p)) { state = next_state; @@ -552,10 +582,10 @@ parse_recv_header (rspamd_mempool_t * pool, gchar *line, struct received_header static void process_raw_headers (struct rspamd_task *task) { - struct raw_header *new = NULL, *lp; - gchar *p, *c, *tmp, *tp; - gint state = 0, l, next_state = 100, err_state = 100, t_state; - gboolean valid_folding = FALSE; + struct raw_header *new = NULL, *lp; + gchar *p, *c, *tmp, *tp; + gint state = 0, l, next_state = 100, err_state = 100, t_state; + gboolean valid_folding = FALSE; p = task->raw_headers_str; c = p; @@ -577,13 +607,15 @@ process_raw_headers (struct rspamd_task *task) case 1: /* We got something like header's name */ if (*p == ':') { - new = rspamd_mempool_alloc0 (task->task_pool, sizeof (struct raw_header)); + new = + rspamd_mempool_alloc0 (task->task_pool, + sizeof (struct raw_header)); l = p - c; tmp = rspamd_mempool_alloc (task->task_pool, l + 1); rspamd_strlcpy (tmp, c, l + 1); new->name = tmp; new->empty_separator = TRUE; - p ++; + p++; state = 2; c = p; } @@ -593,7 +625,7 @@ process_raw_headers (struct rspamd_task *task) next_state = 0; } else { - p ++; + p++; } break; case 2: @@ -601,11 +633,11 @@ process_raw_headers (struct rspamd_task *task) if (*p == '\t') { new->tab_separated = TRUE; new->empty_separator = FALSE; - p ++; + p++; } else if (*p == ' ') { new->empty_separator = FALSE; - p ++; + p++; } else if (*p == '\n' || *p == '\r') { /* Process folding */ @@ -643,7 +675,7 @@ process_raw_headers (struct rspamd_task *task) state = 4; } else { - p ++; + p++; } break; case 4: @@ -652,16 +684,16 @@ process_raw_headers (struct rspamd_task *task) tmp = rspamd_mempool_alloc (task->task_pool, l + 1); tp = tmp; t_state = 0; - while (l --) { + while (l--) { if (t_state == 0) { /* Before folding */ if (*c == '\n' || *c == '\r') { t_state = 1; - c ++; - *tp ++ = ' '; + c++; + *tp++ = ' '; } else { - *tp ++ = *c ++; + *tp++ = *c++; } } else if (t_state == 1) { @@ -671,18 +703,19 @@ process_raw_headers (struct rspamd_task *task) } else { t_state = 0; - *tp ++ = *c ++; + *tp++ = *c++; } } } /* Strip last space that can be added by \r\n parsing */ if (*(tp - 1) == ' ') { - tp --; + tp--; } *tp = '\0'; new->value = tmp; new->next = NULL; - if ((lp = g_hash_table_lookup (task->raw_headers, new->name)) != NULL) { + if ((lp = + g_hash_table_lookup (task->raw_headers, new->name)) != NULL) { while (lp->next != NULL) { lp = lp->next; } @@ -698,7 +731,8 @@ process_raw_headers (struct rspamd_task *task) /* Header has only name, no value */ new->next = NULL; new->value = ""; - if ((lp = g_hash_table_lookup (task->raw_headers, new->name)) != NULL) { + if ((lp = + g_hash_table_lookup (task->raw_headers, new->name)) != NULL) { while (lp->next != NULL) { lp = lp->next; } @@ -717,12 +751,12 @@ process_raw_headers (struct rspamd_task *task) } else { if (*p == '\r' || *p == '\n') { - p ++; + p++; valid_folding = FALSE; } else if (*p == '\t' || *p == ' ') { /* Valid folding */ - p ++; + p++; valid_folding = TRUE; } else { @@ -742,24 +776,24 @@ process_raw_headers (struct rspamd_task *task) /* Fail state, skip line */ if (*p == '\r') { if (*(p + 1) == '\n') { - p ++; + p++; } - p ++; + p++; state = next_state; } else if (*p == '\n') { if (*(p + 1) == '\r') { - p ++; + p++; } - p ++; + p++; state = next_state; } else if (*(p + 1) == '\0') { state = next_state; - p ++; + p++; } else { - p ++; + p++; } break; } @@ -769,45 +803,62 @@ process_raw_headers (struct rspamd_task *task) static void free_byte_array_callback (void *pointer) { - GByteArray *arr = (GByteArray *) pointer; + GByteArray *arr = (GByteArray *) pointer; g_byte_array_free (arr, TRUE); } -static GByteArray * -convert_text_to_utf (struct rspamd_task *task, GByteArray * part_content, GMimeContentType * type, struct mime_text_part *text_part) +static GByteArray * +convert_text_to_utf (struct rspamd_task *task, + GByteArray * part_content, + GMimeContentType * type, + struct mime_text_part *text_part) { - GError *err = NULL; - gsize read_bytes, write_bytes; - const gchar *charset; - gchar *res_str; - GByteArray *result_array; + GError *err = NULL; + gsize read_bytes, write_bytes; + const gchar *charset; + gchar *res_str; + GByteArray *result_array; if (task->cfg->raw_mode) { text_part->is_raw = TRUE; return part_content; } - if ((charset = g_mime_content_type_get_parameter (type, "charset")) == NULL) { + if ((charset = + g_mime_content_type_get_parameter (type, "charset")) == NULL) { text_part->is_raw = TRUE; return part_content; } - if (g_ascii_strcasecmp (charset, "utf-8") == 0 || g_ascii_strcasecmp (charset, "utf8") == 0) { + if (g_ascii_strcasecmp (charset, + "utf-8") == 0 || g_ascii_strcasecmp (charset, "utf8") == 0) { if (g_utf8_validate (part_content->data, part_content->len, NULL)) { text_part->is_raw = FALSE; text_part->is_utf = TRUE; return part_content; } else { - msg_info ("<%s>: contains invalid utf8 characters, assume it as raw", task->message_id); + msg_info ( + "<%s>: contains invalid utf8 characters, assume it as raw", + task->message_id); text_part->is_raw = TRUE; return part_content; } } - res_str = g_convert_with_fallback (part_content->data, part_content->len, UTF8_CHARSET, charset, NULL, &read_bytes, &write_bytes, &err); + res_str = g_convert_with_fallback (part_content->data, + part_content->len, + UTF8_CHARSET, + charset, + NULL, + &read_bytes, + &write_bytes, + &err); if (res_str == NULL) { - msg_warn ("<%s>: cannot convert from %s to utf8: %s", task->message_id, charset, err ? err->message : "unknown problem"); + msg_warn ("<%s>: cannot convert from %s to utf8: %s", + task->message_id, + charset, + err ? err->message : "unknown problem"); text_part->is_raw = TRUE; return part_content; } @@ -815,7 +866,9 @@ convert_text_to_utf (struct rspamd_task *task, GByteArray * part_content, GMimeC result_array = rspamd_mempool_alloc (task->task_pool, sizeof (GByteArray)); result_array->data = res_str; result_array->len = write_bytes; - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) g_free, res_str); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) g_free, + res_str); text_part->is_raw = FALSE; text_part->is_utf = TRUE; @@ -823,31 +876,43 @@ convert_text_to_utf (struct rspamd_task *task, GByteArray * part_content, GMimeC } static void -process_text_part (struct rspamd_task *task, GByteArray *part_content, GMimeContentType *type, - GMimeObject *part, GMimeObject *parent, gboolean is_empty) +process_text_part (struct rspamd_task *task, + GByteArray *part_content, + GMimeContentType *type, + GMimeObject *part, + GMimeObject *parent, + gboolean is_empty) { - struct mime_text_part *text_part; - const gchar *cd; + struct mime_text_part *text_part; + const gchar *cd; /* Skip attachements */ #ifndef GMIME24 cd = g_mime_part_get_content_disposition (GMIME_PART (part)); - if (cd && g_ascii_strcasecmp (cd, "attachment") == 0 && !task->cfg->check_text_attachements) { + if (cd && + g_ascii_strcasecmp (cd, + "attachment") == 0 && !task->cfg->check_text_attachements) { debug_task ("skip attachments for checking as text parts"); return; } #else cd = g_mime_object_get_disposition (GMIME_OBJECT (part)); - if (cd && g_ascii_strcasecmp (cd, GMIME_DISPOSITION_ATTACHMENT) == 0 && !task->cfg->check_text_attachements) { + if (cd && + g_ascii_strcasecmp (cd, + GMIME_DISPOSITION_ATTACHMENT) == 0 && + !task->cfg->check_text_attachements) { debug_task ("skip attachments for checking as text parts"); return; } #endif - if (g_mime_content_type_is_type (type, "text", "html") || g_mime_content_type_is_type (type, "text", "xhtml")) { + if (g_mime_content_type_is_type (type, "text", + "html") || g_mime_content_type_is_type (type, "text", "xhtml")) { debug_task ("got urls from text/html part"); - text_part = rspamd_mempool_alloc0 (task->task_pool, sizeof (struct mime_text_part)); + text_part = + rspamd_mempool_alloc0 (task->task_pool, + sizeof (struct mime_text_part)); text_part->is_html = TRUE; if (is_empty) { text_part->is_empty = TRUE; @@ -856,18 +921,26 @@ process_text_part (struct rspamd_task *task, GByteArray *part_content, GMimeCont task->text_parts = g_list_prepend (task->text_parts, text_part); return; } - text_part->orig = convert_text_to_utf (task, part_content, type, text_part); + text_part->orig = convert_text_to_utf (task, + part_content, + type, + text_part); text_part->is_balanced = TRUE; text_part->html_nodes = NULL; text_part->parent = parent; - text_part->content = strip_html_tags (task, task->task_pool, text_part, text_part->orig, NULL); + text_part->content = strip_html_tags (task, + task->task_pool, + text_part, + text_part->orig, + NULL); if (text_part->html_nodes == NULL) { url_parse_text (task->task_pool, task, text_part, FALSE); } else { - decode_entitles (text_part->content->data, &text_part->content->len); + decode_entitles (text_part->content->data, + &text_part->content->len); url_parse_text (task->task_pool, task, text_part, FALSE); #if 0 url_parse_text (task->task_pool, task, text_part, TRUE); @@ -875,13 +948,17 @@ process_text_part (struct rspamd_task *task, GByteArray *part_content, GMimeCont } fuzzy_init_part (text_part, task->task_pool, task->cfg->max_diff); - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) free_byte_array_callback, text_part->content); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) free_byte_array_callback, + text_part->content); task->text_parts = g_list_prepend (task->text_parts, text_part); } else if (g_mime_content_type_is_type (type, "text", "*")) { debug_task ("got urls from text/plain part"); - text_part = rspamd_mempool_alloc0 (task->task_pool, sizeof (struct mime_text_part)); + text_part = + rspamd_mempool_alloc0 (task->task_pool, + sizeof (struct mime_text_part)); text_part->is_html = FALSE; text_part->parent = parent; if (is_empty) { @@ -891,7 +968,10 @@ process_text_part (struct rspamd_task *task, GByteArray *part_content, GMimeCont task->text_parts = g_list_prepend (task->text_parts, text_part); return; } - text_part->orig = convert_text_to_utf (task, part_content, type, text_part); + text_part->orig = convert_text_to_utf (task, + part_content, + type, + text_part); text_part->content = text_part->orig; url_parse_text (task->task_pool, task, text_part, FALSE); fuzzy_init_part (text_part, task->task_pool, task->cfg->max_diff); @@ -901,18 +981,20 @@ process_text_part (struct rspamd_task *task, GByteArray *part_content, GMimeCont #ifdef GMIME24 static void -mime_foreach_callback (GMimeObject * parent, GMimeObject * part, gpointer user_data) +mime_foreach_callback (GMimeObject * parent, + GMimeObject * part, + gpointer user_data) #else static void mime_foreach_callback (GMimeObject * part, gpointer user_data) #endif { - struct rspamd_task *task = (struct rspamd_task *)user_data; - struct mime_part *mime_part; - GMimeContentType *type; - GMimeDataWrapper *wrapper; - GMimeStream *part_stream; - GByteArray *part_content; + struct rspamd_task *task = (struct rspamd_task *)user_data; + struct mime_part *mime_part; + GMimeContentType *type; + GMimeDataWrapper *wrapper; + GMimeStream *part_stream; + GByteArray *part_content; task->parts_count++; @@ -921,7 +1003,7 @@ mime_foreach_callback (GMimeObject * part, gpointer user_data) /* find out what class 'part' is... */ if (GMIME_IS_MESSAGE_PART (part)) { /* message/rfc822 or message/news */ - GMimeMessage *message; + GMimeMessage *message; /* g_mime_message_foreach_part() won't descend into child message parts, so if we want to count any @@ -957,11 +1039,13 @@ mime_foreach_callback (GMimeObject * part, gpointer user_data) else if (GMIME_IS_MULTIPART (part)) { /* multipart/mixed, multipart/alternative, multipart/related, multipart/signed, multipart/encrypted, etc... */ task->parser_parent_part = part; -#ifndef GMIME24 +#ifndef GMIME24 debug_task ("detected multipart part"); /* we'll get to finding out if this is a signed/encrypted multipart later... */ if (task->parser_recursion++ < RECURSION_LIMIT) { - g_mime_multipart_foreach ((GMimeMultipart *) part, mime_foreach_callback, task); + g_mime_multipart_foreach ((GMimeMultipart *) part, + mime_foreach_callback, + task); } else { msg_err ("endless recursion detected: %d", task->parser_recursion); @@ -972,17 +1056,21 @@ mime_foreach_callback (GMimeObject * part, gpointer user_data) else if (GMIME_IS_PART (part)) { /* a normal leaf part, could be text/plain or image/jpeg etc */ #ifdef GMIME24 - type = (GMimeContentType *) g_mime_object_get_content_type (GMIME_OBJECT (part)); + type = (GMimeContentType *) g_mime_object_get_content_type (GMIME_OBJECT ( + part)); #else - type = (GMimeContentType *) g_mime_part_get_content_type (GMIME_PART (part)); + type = + (GMimeContentType *) g_mime_part_get_content_type (GMIME_PART (part)); #endif if (type == NULL) { msg_warn ("type of part is unknown, assume text/plain"); type = g_mime_content_type_new ("text", "plain"); #ifdef GMIME24 - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) g_object_unref, type); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) g_object_unref, type); #else - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) g_mime_content_type_destroy, type); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) g_mime_content_type_destroy, type); #endif } wrapper = g_mime_part_get_content_object (GMIME_PART (part)); @@ -992,29 +1080,45 @@ mime_foreach_callback (GMimeObject * part, gpointer user_data) if (wrapper != NULL) { #endif part_stream = g_mime_stream_mem_new (); - if (g_mime_data_wrapper_write_to_stream (wrapper, part_stream) != -1) { - g_mime_stream_mem_set_owner (GMIME_STREAM_MEM (part_stream), FALSE); - part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM (part_stream)); + if (g_mime_data_wrapper_write_to_stream (wrapper, + part_stream) != -1) { + g_mime_stream_mem_set_owner (GMIME_STREAM_MEM ( + part_stream), FALSE); + part_content = g_mime_stream_mem_get_byte_array (GMIME_STREAM_MEM ( + part_stream)); g_object_unref (part_stream); - mime_part = rspamd_mempool_alloc (task->task_pool, sizeof (struct mime_part)); + mime_part = + rspamd_mempool_alloc (task->task_pool, + sizeof (struct mime_part)); mime_part->type = type; mime_part->content = part_content; mime_part->parent = task->parser_parent_part; - mime_part->filename = g_mime_part_get_filename (GMIME_PART (part)); - debug_task ("found part with content-type: %s/%s", type->type, type->subtype); + mime_part->filename = g_mime_part_get_filename (GMIME_PART ( + part)); + debug_task ("found part with content-type: %s/%s", + type->type, + type->subtype); task->parts = g_list_prepend (task->parts, mime_part); /* Skip empty parts */ - process_text_part (task, part_content, type, part, task->parser_parent_part, (part_content->len <= 0)); + process_text_part (task, + part_content, + type, + part, + task->parser_parent_part, + (part_content->len <= 0)); } else { - msg_warn ("write to stream failed: %d, %s", errno, strerror (errno)); + msg_warn ("write to stream failed: %d, %s", errno, + strerror (errno)); } #ifndef GMIME24 g_object_unref (wrapper); #endif } else { - msg_warn ("cannot get wrapper for mime part, type of part: %s/%s", type->type, type->subtype); + msg_warn ("cannot get wrapper for mime part, type of part: %s/%s", + type->type, + type->subtype); } } else { @@ -1025,7 +1129,7 @@ mime_foreach_callback (GMimeObject * part, gpointer user_data) static void destroy_message (void *pointer) { - GMimeMessage *msg = pointer; + GMimeMessage *msg = pointer; msg_debug ("freeing pointer %p", msg); g_object_unref (msg); @@ -1034,33 +1138,34 @@ destroy_message (void *pointer) gint process_message (struct rspamd_task *task) { - GMimeMessage *message; - GMimeParser *parser; - GMimeStream *stream; - GByteArray *tmp; - GList *first, *cur; - GMimePart *part; - GMimeDataWrapper *wrapper; - struct received_header *recv; - gchar *mid, *url_str, *p, *end, *url_end; - struct uri *subject_url; - gsize len; - gint rc; + GMimeMessage *message; + GMimeParser *parser; + GMimeStream *stream; + GByteArray *tmp; + GList *first, *cur; + GMimePart *part; + GMimeDataWrapper *wrapper; + struct received_header *recv; + gchar *mid, *url_str, *p, *end, *url_end; + struct uri *subject_url; + gsize len; + gint rc; tmp = rspamd_mempool_alloc (task->task_pool, sizeof (GByteArray)); tmp->data = task->msg->str; tmp->len = task->msg->len; stream = g_mime_stream_mem_new_with_byte_array (tmp); - /* - * This causes g_mime_stream not to free memory by itself as it is memory allocated by - * pool allocator - */ + /* + * This causes g_mime_stream not to free memory by itself as it is memory allocated by + * pool allocator + */ g_mime_stream_mem_set_owner (GMIME_STREAM_MEM (stream), FALSE); if (task->is_mime) { - debug_task ("construct mime parser from string length %d", (gint)task->msg->len); + debug_task ("construct mime parser from string length %d", + (gint)task->msg->len); /* create a new parser object to parse the stream */ parser = g_mime_parser_new_with_stream (stream); g_object_unref (stream); @@ -1074,7 +1179,8 @@ process_message (struct rspamd_task *task) } task->message = message; - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) destroy_message, task->message); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) destroy_message, task->message); /* Save message id for future use */ task->message_id = g_mime_message_get_message_id (task->message); @@ -1101,7 +1207,8 @@ process_message (struct rspamd_task *task) } #ifdef GMIME24 - task->raw_headers_str = g_mime_object_get_headers (GMIME_OBJECT (task->message)); + task->raw_headers_str = + g_mime_object_get_headers (GMIME_OBJECT (task->message)); #else task->raw_headers_str = g_mime_message_get_headers (task->message); #endif @@ -1109,10 +1216,13 @@ process_message (struct rspamd_task *task) process_images (task); /* Parse received headers */ - first = message_get_header (task->task_pool, message, "Received", FALSE); + first = + message_get_header (task->task_pool, message, "Received", FALSE); cur = first; while (cur) { - recv = rspamd_mempool_alloc0 (task->task_pool, sizeof (struct received_header)); + recv = + rspamd_mempool_alloc0 (task->task_pool, + sizeof (struct received_header)); parse_recv_header (task->task_pool, cur->data, recv); task->received = g_list_prepend (task->received, recv); cur = g_list_next (cur); @@ -1122,16 +1232,21 @@ process_message (struct rspamd_task *task) } if (task->raw_headers_str) { - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) g_free, task->raw_headers_str); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) g_free, task->raw_headers_str); process_raw_headers (task); } task->rcpts = g_mime_message_get_all_recipients (message); if (task->rcpts) { #ifdef GMIME24 - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) g_object_unref, task->rcpts); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) g_object_unref, + task->rcpts); #else - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) internet_address_list_destroy, task->rcpts); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) internet_address_list_destroy, + task->rcpts); #endif } @@ -1149,26 +1264,33 @@ process_message (struct rspamd_task *task) /* Construct part for it */ part = g_mime_part_new_with_type ("text", "html"); #ifdef GMIME24 - wrapper = g_mime_data_wrapper_new_with_stream (stream, GMIME_CONTENT_ENCODING_8BIT); + wrapper = g_mime_data_wrapper_new_with_stream (stream, + GMIME_CONTENT_ENCODING_8BIT); #else - wrapper = g_mime_data_wrapper_new_with_stream (stream, GMIME_PART_ENCODING_8BIT); + wrapper = g_mime_data_wrapper_new_with_stream (stream, + GMIME_PART_ENCODING_8BIT); #endif g_mime_part_set_content_object (part, wrapper); g_mime_message_set_mime_part (task->message, GMIME_OBJECT (part)); /* Register destructors */ - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) g_object_unref, wrapper); - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) g_object_unref, part); - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) destroy_message, task->message); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) g_object_unref, wrapper); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) g_object_unref, part); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) destroy_message, task->message); /* Now parse in a normal way */ task->parser_recursion = 0; #ifdef GMIME24 g_mime_message_foreach (task->message, mime_foreach_callback, task); #else - g_mime_message_foreach_part (task->message, mime_foreach_callback, task); + g_mime_message_foreach_part (task->message, mime_foreach_callback, + task); #endif /* Generate message ID */ mid = g_mime_utils_generate_message_id ("localhost.localdomain"); - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t) g_free, mid); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t) g_free, mid); g_mime_message_set_message_id (task->message, mid); task->message_id = mid; task->queue_id = mid; @@ -1182,7 +1304,10 @@ process_message (struct rspamd_task *task) if (task->rcpt) { cur = task->rcpt; while (cur) { - g_mime_message_add_recipient (task->message, GMIME_RECIPIENT_TYPE_TO, NULL, (gchar *)cur->data); + g_mime_message_add_recipient (task->message, + GMIME_RECIPIENT_TYPE_TO, + NULL, + (gchar *)cur->data); cur = g_list_next (cur); } } @@ -1198,22 +1323,29 @@ process_message (struct rspamd_task *task) while (p < end) { /* Search to the end of url */ - if (url_try_text (task->task_pool, p, end - p, NULL, &url_end, &url_str, FALSE)) { + if (url_try_text (task->task_pool, p, end - p, NULL, &url_end, + &url_str, FALSE)) { if (url_str != NULL) { - subject_url = rspamd_mempool_alloc0 (task->task_pool, sizeof (struct uri)); + subject_url = rspamd_mempool_alloc0 (task->task_pool, + sizeof (struct uri)); if (subject_url != NULL) { /* Try to parse url */ rc = parse_uri (subject_url, url_str, task->task_pool); - if ((rc == URI_ERRNO_OK || rc == URI_ERRNO_NO_SLASHES || rc == URI_ERRNO_NO_HOST_SLASH) && - subject_url->hostlen > 0) { + if ((rc == URI_ERRNO_OK || rc == URI_ERRNO_NO_SLASHES || + rc == URI_ERRNO_NO_HOST_SLASH) && + subject_url->hostlen > 0) { if (subject_url->protocol != PROTOCOL_MAILTO) { if (!g_tree_lookup (task->urls, subject_url)) { - g_tree_insert (task->urls, subject_url, subject_url); + g_tree_insert (task->urls, + subject_url, + subject_url); } } } else if (rc != URI_ERRNO_OK) { - msg_info ("extract of url '%s' failed: %s", url_str, url_strerror (rc)); + msg_info ("extract of url '%s' failed: %s", + url_str, + url_strerror (rc)); } } } @@ -1231,15 +1363,15 @@ process_message (struct rspamd_task *task) } struct gmime_raw_header { - struct raw_header *next; - gchar *name; - gchar *value; + struct raw_header *next; + gchar *name; + gchar *value; }; typedef struct _GMimeHeader { - GHashTable *hash; - GHashTable *writers; - struct raw_header *headers; + GHashTable *hash; + GHashTable *writers; + struct raw_header *headers; } local_GMimeHeader; @@ -1261,13 +1393,20 @@ enum { */ #ifndef GMIME24 static void -header_iterate (rspamd_mempool_t * pool, struct gmime_raw_header *h, GList ** ret, const gchar *field, gboolean strong) +header_iterate (rspamd_mempool_t * pool, + struct gmime_raw_header *h, + GList ** ret, + const gchar *field, + gboolean strong) { while (h) { if (G_LIKELY (!strong)) { - if (h->value && !g_ascii_strncasecmp (field, h->name, strlen (field))) { + if (h->value && + !g_ascii_strncasecmp (field, h->name, strlen (field))) { if (pool != NULL) { - *ret = g_list_prepend (*ret, rspamd_mempool_strdup (pool, h->value)); + *ret = + g_list_prepend (*ret, + rspamd_mempool_strdup (pool, h->value)); } else { *ret = g_list_prepend (*ret, g_strdup (h->value)); @@ -1277,7 +1416,9 @@ header_iterate (rspamd_mempool_t * pool, struct gmime_raw_header *h, GList ** re else { if (h->value && !strncmp (field, h->name, strlen (field))) { if (pool != NULL) { - *ret = g_list_prepend (*ret, rspamd_mempool_strdup (pool, h->value)); + *ret = + g_list_prepend (*ret, + rspamd_mempool_strdup (pool, h->value)); } else { *ret = g_list_prepend (*ret, g_strdup (h->value)); @@ -1289,11 +1430,15 @@ header_iterate (rspamd_mempool_t * pool, struct gmime_raw_header *h, GList ** re } #else static void -header_iterate (rspamd_mempool_t * pool, GMimeHeaderList * ls, GList ** ret, const gchar *field, gboolean strong) +header_iterate (rspamd_mempool_t * pool, + GMimeHeaderList * ls, + GList ** ret, + const gchar *field, + gboolean strong) { /* Use iterator in case of gmime 2.4 */ - GMimeHeaderIter *iter; - const gchar *name; + GMimeHeaderIter *iter; + const gchar *name; if (ls == NULL) { *ret = NULL; @@ -1301,27 +1446,38 @@ header_iterate (rspamd_mempool_t * pool, GMimeHeaderList * ls, GList ** ret, con } iter = g_mime_header_iter_new (); - if (g_mime_header_list_get_iter (ls, iter) && g_mime_header_iter_first (iter)) { + if (g_mime_header_list_get_iter (ls, + iter) && g_mime_header_iter_first (iter)) { /* Iterate throught headers */ while (g_mime_header_iter_is_valid (iter)) { name = g_mime_header_iter_get_name (iter); if (G_LIKELY (!strong)) { if (!g_ascii_strncasecmp (field, name, strlen (name))) { if (pool != NULL) { - *ret = g_list_prepend (*ret, rspamd_mempool_strdup (pool, g_mime_header_iter_get_value (iter))); + *ret = + g_list_prepend (*ret, + rspamd_mempool_strdup (pool, + g_mime_header_iter_get_value (iter))); } else { - *ret = g_list_prepend (*ret, g_strdup (g_mime_header_iter_get_value (iter))); + *ret = + g_list_prepend (*ret, + g_strdup (g_mime_header_iter_get_value (iter))); } } } else { if (!strncmp (field, name, strlen (name))) { if (pool != NULL) { - *ret = g_list_prepend (*ret, rspamd_mempool_strdup (pool, g_mime_header_iter_get_value (iter))); + *ret = + g_list_prepend (*ret, + rspamd_mempool_strdup (pool, + g_mime_header_iter_get_value (iter))); } else { - *ret = g_list_prepend (*ret, g_strdup (g_mime_header_iter_get_value (iter))); + *ret = + g_list_prepend (*ret, + g_strdup (g_mime_header_iter_get_value (iter))); } } } @@ -1336,12 +1492,12 @@ header_iterate (rspamd_mempool_t * pool, GMimeHeaderList * ls, GList ** ret, con struct multipart_cb_data { - GList *ret; - rspamd_mempool_t *pool; - const gchar *field; - gboolean try_search; - gboolean strong; - gint rec; + GList *ret; + rspamd_mempool_t *pool; + const gchar *field; + gboolean try_search; + gboolean strong; + gint rec; }; #define MAX_REC 10 @@ -1353,21 +1509,21 @@ multipart_iterate (GMimeObject * parent, GMimeObject * part, gpointer user_data) multipart_iterate (GMimeObject * part, gpointer user_data) #endif { - struct multipart_cb_data *data = user_data; + struct multipart_cb_data *data = user_data; #ifndef GMIME24 - struct gmime_raw_header *h; + struct gmime_raw_header *h; #endif - GList *l = NULL; + GList *l = NULL; if (data->try_search && part != NULL && GMIME_IS_PART (part)) { #ifdef GMIME24 - GMimeHeaderList *ls; + GMimeHeaderList *ls; ls = g_mime_object_get_header_list (GMIME_OBJECT (part)); header_iterate (data->pool, ls, &l, data->field, data->strong); #else h = (struct gmime_raw_header *)part->headers->headers; - header_iterate (data->pool, h, &l, data->field, data->strong); + header_iterate (data->pool, h, &l, data->field, data->strong); #endif if (l == NULL) { /* Header not found, abandon search results */ @@ -1382,21 +1538,26 @@ multipart_iterate (GMimeObject * part, gpointer user_data) else if (data->try_search && GMIME_IS_MULTIPART (part)) { /* Maybe endless recursion here ? */ if (data->rec++ < MAX_REC) { - g_mime_multipart_foreach (GMIME_MULTIPART (part), multipart_iterate, data); + g_mime_multipart_foreach (GMIME_MULTIPART ( + part), multipart_iterate, data); } else { - msg_info ("maximum recurse limit is over, stop recursing, %d", data->rec); + msg_info ("maximum recurse limit is over, stop recursing, %d", + data->rec); data->try_search = FALSE; } } } -static GList * -local_message_get_header (rspamd_mempool_t * pool, GMimeMessage * message, const gchar *field, gboolean strong) +static GList * +local_message_get_header (rspamd_mempool_t * pool, + GMimeMessage * message, + const gchar *field, + gboolean strong) { - GList *gret = NULL; - GMimeObject *part; - struct multipart_cb_data cb = { + GList *gret = NULL; + GMimeObject *part; + struct multipart_cb_data cb = { .try_search = TRUE, .rec = 0, .ret = NULL, @@ -1406,7 +1567,7 @@ local_message_get_header (rspamd_mempool_t * pool, GMimeMessage * message, const cb.strong = strong; #ifndef GMIME24 - struct gmime_raw_header *h; + struct gmime_raw_header *h; if (field == NULL) { return NULL; @@ -1418,14 +1579,18 @@ local_message_get_header (rspamd_mempool_t * pool, GMimeMessage * message, const if (gret == NULL) { /* Try to iterate with mime part headers */ - msg_debug ("iterate over headers of mime part to find header %s", field); + msg_debug ("iterate over headers of mime part to find header %s", + field); part = g_mime_message_get_mime_part (message); if (part) { h = (struct gmime_raw_header *)part->headers->headers; header_iterate (pool, h, &gret, field, strong); if (gret == NULL && GMIME_IS_MULTIPART (part)) { - msg_debug ("iterate over headers of each multipart's subparts %s", field); - g_mime_multipart_foreach (GMIME_MULTIPART (part), multipart_iterate, &cb); + msg_debug ( + "iterate over headers of each multipart's subparts %s", + field); + g_mime_multipart_foreach (GMIME_MULTIPART ( + part), multipart_iterate, &cb); if (cb.ret != NULL) { gret = cb.ret; } @@ -1438,7 +1603,7 @@ local_message_get_header (rspamd_mempool_t * pool, GMimeMessage * message, const return gret; #else - GMimeHeaderList *ls; + GMimeHeaderList *ls; ls = g_mime_object_get_header_list (GMIME_OBJECT (message)); header_iterate (pool, ls, &gret, field, strong); @@ -1449,7 +1614,8 @@ local_message_get_header (rspamd_mempool_t * pool, GMimeMessage * message, const ls = g_mime_object_get_header_list (GMIME_OBJECT (part)); header_iterate (pool, ls, &gret, field, strong); if (gret == NULL && GMIME_IS_MULTIPART (part)) { - g_mime_multipart_foreach (GMIME_MULTIPART (part), multipart_iterate, &cb); + g_mime_multipart_foreach (GMIME_MULTIPART ( + part), multipart_iterate, &cb); if (cb.ret != NULL) { gret = cb.ret; } @@ -1466,17 +1632,18 @@ local_message_get_header (rspamd_mempool_t * pool, GMimeMessage * message, const } /** -* g_mime_message_set_date_from_string: Set the message sent-date -* @message: MIME Message -* @string: A string of date -* -* Set the sent-date on a MIME Message. -**/ + * g_mime_message_set_date_from_string: Set the message sent-date + * @message: MIME Message + * @string: A string of date + * + * Set the sent-date on a MIME Message. + **/ void -local_mime_message_set_date_from_string (GMimeMessage * message, const gchar * string) +local_mime_message_set_date_from_string (GMimeMessage * message, + const gchar * string) { - time_t date; - gint offset = 0; + time_t date; + gint offset = 0; date = g_mime_utils_header_decode_date (string, &offset); g_mime_message_set_date (message, date, offset); @@ -1485,14 +1652,14 @@ local_mime_message_set_date_from_string (GMimeMessage * message, const gchar * s /* * Replacements for standart gmime functions but converting adresses to IA */ -static const gchar * +static const gchar * local_message_get_sender (GMimeMessage * message) { - gchar *res; - const gchar *from = g_mime_message_get_sender (message); - InternetAddressList *ia; + gchar *res; + const gchar *from = g_mime_message_get_sender (message); + InternetAddressList *ia; -#ifndef GMIME24 +#ifndef GMIME24 ia = internet_address_parse_string (from); #else ia = internet_address_list_parse_string (from); @@ -1501,7 +1668,7 @@ local_message_get_sender (GMimeMessage * message) return NULL; } res = internet_address_list_to_string (ia, FALSE); -#ifndef GMIME24 +#ifndef GMIME24 internet_address_list_destroy (ia); #else g_object_unref (ia); @@ -1510,14 +1677,14 @@ local_message_get_sender (GMimeMessage * message) return res; } -static const gchar * +static const gchar * local_message_get_reply_to (GMimeMessage * message) { - gchar *res; - const gchar *from = g_mime_message_get_reply_to (message); - InternetAddressList *ia; + gchar *res; + const gchar *from = g_mime_message_get_reply_to (message); + InternetAddressList *ia; -#ifndef GMIME24 +#ifndef GMIME24 ia = internet_address_parse_string (from); #else ia = internet_address_list_parse_string (from); @@ -1526,7 +1693,7 @@ local_message_get_reply_to (GMimeMessage * message) return NULL; } res = internet_address_list_to_string (ia, FALSE); -#ifndef GMIME24 +#ifndef GMIME24 internet_address_list_destroy (ia); #else g_object_unref (ia); @@ -1537,122 +1704,161 @@ local_message_get_reply_to (GMimeMessage * message) #ifdef GMIME24 -# define ADD_RECIPIENT_TEMPLATE(type,def) \ -static void \ -local_message_add_recipients_from_string_##type (GMimeMessage *message, const gchar *string, const gchar *value) \ -{ \ - InternetAddressList *il, *new; \ - \ - il = g_mime_message_get_recipients (message, (def)); \ - new = internet_address_list_parse_string (string); \ - internet_address_list_append (il, new); \ -} \ - -ADD_RECIPIENT_TEMPLATE (to, GMIME_RECIPIENT_TYPE_TO) - ADD_RECIPIENT_TEMPLATE (cc, GMIME_RECIPIENT_TYPE_CC) - ADD_RECIPIENT_TEMPLATE (bcc, GMIME_RECIPIENT_TYPE_BCC) -# define GET_RECIPIENT_TEMPLATE(type,def) \ -static InternetAddressList* \ -local_message_get_recipients_##type (GMimeMessage *message, const gchar *unused) \ -{ \ - return g_mime_message_get_recipients (message, (def)); \ -} - GET_RECIPIENT_TEMPLATE (to, GMIME_RECIPIENT_TYPE_TO) - GET_RECIPIENT_TEMPLATE (cc, GMIME_RECIPIENT_TYPE_CC) - GET_RECIPIENT_TEMPLATE (bcc, GMIME_RECIPIENT_TYPE_BCC) +# define ADD_RECIPIENT_TEMPLATE(type,def) \ + static void \ + local_message_add_recipients_from_string_ ## type (GMimeMessage * message, \ + const gchar * string, \ + const gchar * value) \ + { \ + InternetAddressList *il, *new; \ + \ + il = g_mime_message_get_recipients (message, (def)); \ + new = internet_address_list_parse_string (string); \ + internet_address_list_append (il, new); \ + } \ + +ADD_RECIPIENT_TEMPLATE (to, GMIME_RECIPIENT_TYPE_TO) +ADD_RECIPIENT_TEMPLATE (cc, GMIME_RECIPIENT_TYPE_CC) +ADD_RECIPIENT_TEMPLATE (bcc, GMIME_RECIPIENT_TYPE_BCC) +# define GET_RECIPIENT_TEMPLATE(type,def) \ + static InternetAddressList * \ + local_message_get_recipients_ ## type (GMimeMessage * message, \ + const gchar * unused) \ + { \ + return g_mime_message_get_recipients (message, (def)); \ + } +GET_RECIPIENT_TEMPLATE (to, GMIME_RECIPIENT_TYPE_TO) +GET_RECIPIENT_TEMPLATE (cc, GMIME_RECIPIENT_TYPE_CC) +GET_RECIPIENT_TEMPLATE (bcc, GMIME_RECIPIENT_TYPE_BCC) #endif /* different declarations for different types of set and get functions */ - typedef const gchar *(*GetFunc) (GMimeMessage * message); - typedef InternetAddressList *(*GetRcptFunc) (GMimeMessage * message, const gchar *type); - typedef GList *(*GetListFunc) (rspamd_mempool_t * pool, GMimeMessage * message, const gchar *type, gboolean strong); - typedef void (*SetFunc) (GMimeMessage * message, const gchar *value); - typedef void (*SetListFunc) (GMimeMessage * message, const gchar *field, const gchar *value); +typedef const gchar *(*GetFunc) (GMimeMessage * message); +typedef InternetAddressList *(*GetRcptFunc) (GMimeMessage * message, + const gchar *type); +typedef GList *(*GetListFunc) (rspamd_mempool_t * pool, GMimeMessage * message, + const gchar *type, gboolean strong); +typedef void (*SetFunc) (GMimeMessage * message, const gchar *value); +typedef void (*SetListFunc) (GMimeMessage * message, const gchar *field, + const gchar *value); /** different types of functions -* -* FUNC_CHARPTR -* - function with no arguments -* - get returns gchar* -* -* FUNC_IA (from Internet Address) -* - function with additional "field" argument from the fieldfunc table, -* - get returns Glist* -* -* FUNC_LIST -* - function with additional "field" argument (given arbitrary header field name) -* - get returns Glist* -**/ - enum { - FUNC_CHARPTR = 0, - FUNC_CHARFREEPTR, - FUNC_IA, - FUNC_LIST - }; + * + * FUNC_CHARPTR + * - function with no arguments + * - get returns gchar* + * + * FUNC_IA (from Internet Address) + * - function with additional "field" argument from the fieldfunc table, + * - get returns Glist* + * + * FUNC_LIST + * - function with additional "field" argument (given arbitrary header field name) + * - get returns Glist* + **/ +enum { + FUNC_CHARPTR = 0, + FUNC_CHARFREEPTR, + FUNC_IA, + FUNC_LIST +}; /** -* fieldfunc struct: structure of MIME fields and corresponding get and set -* functions. -**/ - static struct { - gchar *name; - GetFunc func; - GetRcptFunc rcptfunc; - GetListFunc getlistfunc; - SetFunc setfunc; - SetListFunc setlfunc; - gint functype; - } fieldfunc[] = + * fieldfunc struct: structure of MIME fields and corresponding get and set + * functions. + **/ +static struct { + gchar *name; + GetFunc func; + GetRcptFunc rcptfunc; + GetListFunc getlistfunc; + SetFunc setfunc; + SetListFunc setlfunc; + gint functype; +} fieldfunc[] = { { - "From", local_message_get_sender, NULL, NULL, g_mime_message_set_sender, NULL, FUNC_CHARFREEPTR}, { - "Reply-To", local_message_get_reply_to, NULL, NULL, g_mime_message_set_reply_to, NULL, FUNC_CHARFREEPTR}, + "From", local_message_get_sender, NULL, NULL, g_mime_message_set_sender, + NULL, FUNC_CHARFREEPTR + }, { + "Reply-To", local_message_get_reply_to, NULL, NULL, + g_mime_message_set_reply_to, NULL, FUNC_CHARFREEPTR + }, #ifndef GMIME24 { - "To", NULL, (GetRcptFunc) g_mime_message_get_recipients, NULL, NULL, (SetListFunc) g_mime_message_add_recipients_from_string, FUNC_IA}, { - "Cc", NULL, (GetRcptFunc) g_mime_message_get_recipients, NULL, NULL, (SetListFunc) g_mime_message_add_recipients_from_string, FUNC_IA}, { - "Bcc", NULL, (GetRcptFunc) g_mime_message_get_recipients, NULL, NULL, (SetListFunc) g_mime_message_add_recipients_from_string, FUNC_IA}, { - "Date", (GetFunc) g_mime_message_get_date_string, NULL, NULL, local_mime_message_set_date_from_string, NULL, FUNC_CHARFREEPTR}, + "To", NULL, (GetRcptFunc) g_mime_message_get_recipients, NULL, NULL, + (SetListFunc) g_mime_message_add_recipients_from_string, FUNC_IA + }, { + "Cc", NULL, (GetRcptFunc) g_mime_message_get_recipients, NULL, NULL, + (SetListFunc) g_mime_message_add_recipients_from_string, FUNC_IA + }, { + "Bcc", NULL, (GetRcptFunc) g_mime_message_get_recipients, NULL, NULL, + (SetListFunc) g_mime_message_add_recipients_from_string, FUNC_IA + }, { + "Date", (GetFunc) g_mime_message_get_date_string, NULL, NULL, + local_mime_message_set_date_from_string, NULL, FUNC_CHARFREEPTR + }, #else { - "To", NULL, local_message_get_recipients_to, NULL, NULL, local_message_add_recipients_from_string_to, FUNC_IA}, { - "Cc", NULL, local_message_get_recipients_cc, NULL, NULL, local_message_add_recipients_from_string_cc, FUNC_IA}, { - "Bcc", NULL, local_message_get_recipients_bcc, NULL, NULL, local_message_add_recipients_from_string_bcc, FUNC_IA}, { - "Date", (GetFunc)g_mime_message_get_date_as_string, NULL, NULL, local_mime_message_set_date_from_string, NULL, FUNC_CHARFREEPTR}, + "To", NULL, local_message_get_recipients_to, NULL, NULL, + local_message_add_recipients_from_string_to, FUNC_IA + }, { + "Cc", NULL, local_message_get_recipients_cc, NULL, NULL, + local_message_add_recipients_from_string_cc, FUNC_IA + }, { + "Bcc", NULL, local_message_get_recipients_bcc, NULL, NULL, + local_message_add_recipients_from_string_bcc, FUNC_IA + }, { + "Date", (GetFunc)g_mime_message_get_date_as_string, NULL, NULL, + local_mime_message_set_date_from_string, NULL, FUNC_CHARFREEPTR + }, #endif { - "Subject", g_mime_message_get_subject, NULL, NULL, g_mime_message_set_subject, NULL, FUNC_CHARPTR}, { - "Message-Id", g_mime_message_get_message_id, NULL, NULL, g_mime_message_set_message_id, NULL, FUNC_CHARPTR}, + "Subject", g_mime_message_get_subject, NULL, NULL, + g_mime_message_set_subject, NULL, FUNC_CHARPTR + }, { + "Message-Id", g_mime_message_get_message_id, NULL, NULL, + g_mime_message_set_message_id, NULL, FUNC_CHARPTR + }, #ifndef GMIME24 { - NULL, NULL, NULL, local_message_get_header, NULL, g_mime_message_add_header, FUNC_LIST} + NULL, NULL, NULL, local_message_get_header, NULL, + g_mime_message_add_header, FUNC_LIST + } #else { - NULL, NULL, NULL, local_message_get_header, NULL, (SetListFunc)g_mime_object_append_header, FUNC_LIST} + NULL, NULL, NULL, local_message_get_header, NULL, + (SetListFunc)g_mime_object_append_header, FUNC_LIST + } #endif }; /** -* message_set_header: set header of any type excluding special (Content- and MIME-Version:) -**/ + * message_set_header: set header of any type excluding special (Content- and MIME-Version:) + **/ void -message_set_header (GMimeMessage * message, const gchar *field, const gchar *value) +message_set_header (GMimeMessage * message, + const gchar *field, + const gchar *value) { - gint i; + gint i; - if (!g_ascii_strcasecmp (field, "MIME-Version:") || !g_ascii_strncasecmp (field, "Content-", 8)) { + if (!g_ascii_strcasecmp (field, + "MIME-Version:") || !g_ascii_strncasecmp (field, "Content-", 8)) { return; } for (i = 0; i <= HEADER_UNKNOWN; ++i) { - if (!fieldfunc[i].name || !g_ascii_strncasecmp (field, fieldfunc[i].name, strlen (fieldfunc[i].name))) { + if (!fieldfunc[i].name || + !g_ascii_strncasecmp (field, fieldfunc[i].name, + strlen (fieldfunc[i].name))) { switch (fieldfunc[i].functype) { case FUNC_CHARPTR: - (*(fieldfunc[i].setfunc)) (message, value); + (*(fieldfunc[i].setfunc))(message, value); break; case FUNC_IA: - (*(fieldfunc[i].setlfunc)) (message, fieldfunc[i].name, value); + (*(fieldfunc[i].setlfunc))(message, fieldfunc[i].name, value); break; case FUNC_LIST: - (*(fieldfunc[i].setlfunc)) (message, field, value); + (*(fieldfunc[i].setlfunc))(message, field, value); break; } break; @@ -1662,37 +1868,45 @@ message_set_header (GMimeMessage * message, const gchar *field, const gchar *val /** -* message_get_header: returns the list of 'any header' values -* (except of unsupported yet Content- and MIME-Version special headers) -* -* You should free the GList list by yourself. -**/ -GList * -message_get_header (rspamd_mempool_t * pool, GMimeMessage * message, const gchar *field, gboolean strong) + * message_get_header: returns the list of 'any header' values + * (except of unsupported yet Content- and MIME-Version special headers) + * + * You should free the GList list by yourself. + **/ +GList * +message_get_header (rspamd_mempool_t * pool, + GMimeMessage * message, + const gchar *field, + gboolean strong) { - gint i; - gchar *ret = NULL, *ia_string; - GList *gret = NULL; - InternetAddressList *ia_list = NULL, *ia; + gint i; + gchar *ret = NULL, *ia_string; + GList *gret = NULL; + InternetAddressList *ia_list = NULL, *ia; for (i = 0; i <= HEADER_UNKNOWN; ++i) { - if (!fieldfunc[i].name || !g_ascii_strncasecmp (field, fieldfunc[i].name, strlen (fieldfunc[i].name))) { + if (!fieldfunc[i].name || + !g_ascii_strncasecmp (field, fieldfunc[i].name, + strlen (fieldfunc[i].name))) { switch (fieldfunc[i].functype) { case FUNC_CHARFREEPTR: - ret = (gchar *)(*(fieldfunc[i].func)) (message); + ret = (gchar *)(*(fieldfunc[i].func))(message); break; case FUNC_CHARPTR: - ret = (gchar *)(*(fieldfunc[i].func)) (message); + ret = (gchar *)(*(fieldfunc[i].func))(message); break; case FUNC_IA: - ia_list = (*(fieldfunc[i].rcptfunc)) (message, field); + ia_list = (*(fieldfunc[i].rcptfunc))(message, field); ia = ia_list; #ifndef GMIME24 while (ia && ia->address) { - ia_string = internet_address_to_string ((InternetAddress *) ia->address, FALSE); + ia_string = internet_address_to_string ( + (InternetAddress *) ia->address, + FALSE); if (pool != NULL) { - rspamd_mempool_add_destructor (pool, (rspamd_mempool_destruct_t) g_free, ia_string); + rspamd_mempool_add_destructor (pool, + (rspamd_mempool_destruct_t) g_free, ia_string); } gret = g_list_prepend (gret, ia_string); ia = ia->next; @@ -1700,16 +1914,21 @@ message_get_header (rspamd_mempool_t * pool, GMimeMessage * message, const gchar #else i = internet_address_list_length (ia); while (--i >= 0) { - ia_string = internet_address_to_string (internet_address_list_get_address (ia, i), FALSE); + ia_string = internet_address_to_string (internet_address_list_get_address ( + ia, + i), + FALSE); if (pool != NULL) { - rspamd_mempool_add_destructor (pool, (rspamd_mempool_destruct_t) g_free, ia_string); + rspamd_mempool_add_destructor (pool, + (rspamd_mempool_destruct_t) g_free, ia_string); } gret = g_list_prepend (gret, ia_string); } #endif break; case FUNC_LIST: - gret = (*(fieldfunc[i].getlistfunc)) (pool, message, field, strong); + gret = + (*(fieldfunc[i].getlistfunc))(pool, message, field, strong); break; } break; @@ -1730,11 +1949,13 @@ message_get_header (rspamd_mempool_t * pool, GMimeMessage * message, const gchar return gret; } -GList* -message_get_raw_header (struct rspamd_task *task, const gchar *field, gboolean strong) +GList * +message_get_raw_header (struct rspamd_task *task, + const gchar *field, + gboolean strong) { - GList *gret = NULL; - struct raw_header *rh; + GList *gret = NULL; + struct raw_header *rh; rh = g_hash_table_lookup (task->raw_headers, field); @@ -1757,7 +1978,8 @@ message_get_raw_header (struct rspamd_task *task, const gchar *field, gboolean s } if (gret != NULL) { - rspamd_mempool_add_destructor (task->task_pool, (rspamd_mempool_destruct_t)g_list_free, gret); + rspamd_mempool_add_destructor (task->task_pool, + (rspamd_mempool_destruct_t)g_list_free, gret); } return gret; diff --git a/src/libmime/message.h b/src/libmime/message.h index 5e27579d1..fdb987c8c 100644 --- a/src/libmime/message.h +++ b/src/libmime/message.h @@ -30,7 +30,7 @@ struct mime_text_part { GByteArray *orig; GByteArray *content; GNode *html_nodes; - GList *urls_offset; /**< list of offsets of urls */ + GList *urls_offset; /**< list of offsets of urls */ fuzzy_hash_t *fuzzy; fuzzy_hash_t *double_fuzzy; GMimeObject *parent; @@ -57,7 +57,7 @@ struct raw_header { }; /** - * Process message with all filters/statfiles, extract mime parts, urls and + * Process message with all filters/statfiles, extract mime parts, urls and * call metrics consolidation functions * @param task worker_task object * @return 0 if we have delayed filters to process and 1 if we have finished with processing @@ -67,7 +67,9 @@ gint process_message (struct rspamd_task *task); /* * Set header with specified name and value */ -void message_set_header (GMimeMessage *message, const gchar *field, const gchar *value); +void message_set_header (GMimeMessage *message, + const gchar *field, + const gchar *value); /* * Get a list of header's values with specified header's name @@ -77,7 +79,10 @@ void message_set_header (GMimeMessage *message, const gchar *field, const gchar * @param strong if this flag is TRUE header's name is case sensitive, otherwise it is not * @return A list of header's values or NULL. If list is not NULL it MUST be freed. If pool is NULL elements must be freed as well. */ -GList* message_get_header (rspamd_mempool_t *pool, GMimeMessage *message, const gchar *field, gboolean strong); +GList * message_get_header (rspamd_mempool_t *pool, + GMimeMessage *message, + const gchar *field, + gboolean strong); /* * Get a list of header's values with specified header's name using raw headers @@ -86,6 +91,8 @@ GList* message_get_header (rspamd_mempool_t *pool, GMimeMessage *message, const * @param strong if this flag is TRUE header's name is case sensitive, otherwise it is not * @return A list of header's values or NULL. Unlike previous function it is NOT required to free list or values. I should rework one of these functions some time. */ -GList* message_get_raw_header (struct rspamd_task *task, const gchar *field, gboolean strong); +GList * message_get_raw_header (struct rspamd_task *task, + const gchar *field, + gboolean strong); #endif diff --git a/src/libmime/smtp_proto.c b/src/libmime/smtp_proto.c index 3af1c3910..3c8395784 100644 --- a/src/libmime/smtp_proto.c +++ b/src/libmime/smtp_proto.c @@ -22,21 +22,24 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "cfg_file.h" #include "config.h" #include "main.h" -#include "cfg_file.h" -#include "util.h" #include "smtp.h" #include "smtp_proto.h" #include "smtp_utils.h" +#include "util.h" -gchar * -make_smtp_error (rspamd_mempool_t *pool, gint error_code, const gchar *format, ...) +gchar * +make_smtp_error (rspamd_mempool_t *pool, + gint error_code, + const gchar *format, + ...) { - va_list vp; - gchar *result = NULL, *p; - size_t len; - + va_list vp; + gchar *result = NULL, *p; + size_t len; + va_start (vp, format); len = g_printf_string_upper_bound (format, vp); va_end (vp); @@ -53,7 +56,9 @@ make_smtp_error (rspamd_mempool_t *pool, gint error_code, const gchar *format, . gboolean -parse_smtp_command (struct smtp_session *session, f_str_t *line, struct smtp_command **cmd) +parse_smtp_command (struct smtp_session *session, + f_str_t *line, + struct smtp_command **cmd) { enum { SMTP_PARSE_START = 0, @@ -61,11 +66,11 @@ parse_smtp_command (struct smtp_session *session, f_str_t *line, struct smtp_com SMTP_PARSE_ARGUMENT, SMTP_PARSE_DONE } state; - gchar *p, *c, ch, cmd_buf[4]; - guint i; - f_str_t *arg = NULL; - struct smtp_command *pcmd; - + gchar *p, *c, ch, cmd_buf[4]; + guint i; + f_str_t *arg = NULL; + struct smtp_command *pcmd; + if (line->len == 0) { return FALSE; } @@ -76,125 +81,129 @@ parse_smtp_command (struct smtp_session *session, f_str_t *line, struct smtp_com *cmd = rspamd_mempool_alloc0 (session->pool, sizeof (struct smtp_command)); pcmd = *cmd; - for (i = 0; i < line->len; i ++, p ++) { + for (i = 0; i < line->len; i++, p++) { ch = *p; switch (state) { - case SMTP_PARSE_START: - if (ch == ' ' || ch == ':' || ch == CR || ch == LF || i == line->len - 1) { - if (i == line->len - 1) { - p ++; + case SMTP_PARSE_START: + if (ch == ' ' || ch == ':' || ch == CR || ch == LF || i == + line->len - 1) { + if (i == line->len - 1) { + p++; + } + if (p - c == 4) { + cmd_buf[0] = g_ascii_toupper (c[0]); + cmd_buf[1] = g_ascii_toupper (c[1]); + cmd_buf[2] = g_ascii_toupper (c[2]); + cmd_buf[3] = g_ascii_toupper (c[3]); + + if (memcmp (cmd_buf, "HELO", 4) == 0) { + pcmd->command = SMTP_COMMAND_HELO; } - if (p - c == 4) { - cmd_buf[0] = g_ascii_toupper (c[0]); - cmd_buf[1] = g_ascii_toupper (c[1]); - cmd_buf[2] = g_ascii_toupper (c[2]); - cmd_buf[3] = g_ascii_toupper (c[3]); - - if (memcmp (cmd_buf, "HELO", 4) == 0) { - pcmd->command = SMTP_COMMAND_HELO; - } - else if (memcmp (cmd_buf, "EHLO", 4) == 0) { - pcmd->command = SMTP_COMMAND_EHLO; - } - else if (memcmp (cmd_buf, "MAIL", 4) == 0) { - pcmd->command = SMTP_COMMAND_MAIL; - } - else if (memcmp (cmd_buf, "RCPT", 4) == 0) { - pcmd->command = SMTP_COMMAND_RCPT; - } - else if (memcmp (cmd_buf, "DATA", 4) == 0) { - pcmd->command = SMTP_COMMAND_DATA; - } - else if (memcmp (cmd_buf, "QUIT", 4) == 0) { - pcmd->command = SMTP_COMMAND_QUIT; - } - else if (memcmp (cmd_buf, "NOOP", 4) == 0) { - pcmd->command = SMTP_COMMAND_NOOP; - } - else if (memcmp (cmd_buf, "EXPN", 4) == 0) { - pcmd->command = SMTP_COMMAND_EXPN; - } - else if (memcmp (cmd_buf, "RSET", 4) == 0) { - pcmd->command = SMTP_COMMAND_RSET; - } - else if (memcmp (cmd_buf, "HELP", 4) == 0) { - pcmd->command = SMTP_COMMAND_HELP; - } - else if (memcmp (cmd_buf, "VRFY", 4) == 0) { - pcmd->command = SMTP_COMMAND_VRFY; - } - else { - msg_info ("invalid command: %*s", 4, cmd_buf); - return FALSE; - } + else if (memcmp (cmd_buf, "EHLO", 4) == 0) { + pcmd->command = SMTP_COMMAND_EHLO; } - else { - /* Invalid command */ - msg_info ("invalid command: %*s", 4, c); - return FALSE; + else if (memcmp (cmd_buf, "MAIL", 4) == 0) { + pcmd->command = SMTP_COMMAND_MAIL; } - /* Now check what we have */ - if (ch == ' ' || ch == ':') { - state = SMTP_PARSE_SPACES; + else if (memcmp (cmd_buf, "RCPT", 4) == 0) { + pcmd->command = SMTP_COMMAND_RCPT; } - else if (ch == CR) { - state = SMTP_PARSE_DONE; + else if (memcmp (cmd_buf, "DATA", 4) == 0) { + pcmd->command = SMTP_COMMAND_DATA; } - else if (ch == LF) { - return TRUE; + else if (memcmp (cmd_buf, "QUIT", 4) == 0) { + pcmd->command = SMTP_COMMAND_QUIT; + } + else if (memcmp (cmd_buf, "NOOP", 4) == 0) { + pcmd->command = SMTP_COMMAND_NOOP; + } + else if (memcmp (cmd_buf, "EXPN", 4) == 0) { + pcmd->command = SMTP_COMMAND_EXPN; + } + else if (memcmp (cmd_buf, "RSET", 4) == 0) { + pcmd->command = SMTP_COMMAND_RSET; + } + else if (memcmp (cmd_buf, "HELP", 4) == 0) { + pcmd->command = SMTP_COMMAND_HELP; + } + else if (memcmp (cmd_buf, "VRFY", 4) == 0) { + pcmd->command = SMTP_COMMAND_VRFY; + } + else { + msg_info ("invalid command: %*s", 4, cmd_buf); + return FALSE; } } - else if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { - msg_info ("invalid letter code in SMTP command: %d", (gint)ch); + else { + /* Invalid command */ + msg_info ("invalid command: %*s", 4, c); return FALSE; } - break; - case SMTP_PARSE_SPACES: - if (ch == CR) { + /* Now check what we have */ + if (ch == ' ' || ch == ':') { + state = SMTP_PARSE_SPACES; + } + else if (ch == CR) { state = SMTP_PARSE_DONE; } else if (ch == LF) { - goto end; + return TRUE; } - else if (ch != ' ' && ch != ':') { - state = SMTP_PARSE_ARGUMENT; - arg = rspamd_mempool_alloc (session->pool, sizeof (f_str_t)); - c = p; - } - break; - case SMTP_PARSE_ARGUMENT: - if (ch == ' ' || ch == ':' || ch == CR || ch == LF || i == line->len - 1) { - if (i == line->len - 1 && (ch != ' ' && ch != CR && ch != LF)) { - p ++; - } - arg->len = p - c; - arg->begin = rspamd_mempool_alloc (session->pool, arg->len); - memcpy (arg->begin, c, arg->len); - pcmd->args = g_list_prepend (pcmd->args, arg); - if (ch == ' ' || ch == ':') { - state = SMTP_PARSE_SPACES; - } - else if (ch == CR) { - state = SMTP_PARSE_DONE; - } - else { - goto end; - } + } + else if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { + msg_info ("invalid letter code in SMTP command: %d", (gint)ch); + return FALSE; + } + break; + case SMTP_PARSE_SPACES: + if (ch == CR) { + state = SMTP_PARSE_DONE; + } + else if (ch == LF) { + goto end; + } + else if (ch != ' ' && ch != ':') { + state = SMTP_PARSE_ARGUMENT; + arg = rspamd_mempool_alloc (session->pool, sizeof (f_str_t)); + c = p; + } + break; + case SMTP_PARSE_ARGUMENT: + if (ch == ' ' || ch == ':' || ch == CR || ch == LF || i == + line->len - 1) { + if (i == line->len - 1 && (ch != ' ' && ch != CR && ch != LF)) { + p++; + } + arg->len = p - c; + arg->begin = rspamd_mempool_alloc (session->pool, arg->len); + memcpy (arg->begin, c, arg->len); + pcmd->args = g_list_prepend (pcmd->args, arg); + if (ch == ' ' || ch == ':') { + state = SMTP_PARSE_SPACES; + } + else if (ch == CR) { + state = SMTP_PARSE_DONE; } - break; - case SMTP_PARSE_DONE: - if (ch == LF) { + else { goto end; } - msg_info ("CR without LF in SMTP command"); - return FALSE; + } + break; + case SMTP_PARSE_DONE: + if (ch == LF) { + goto end; + } + msg_info ("CR without LF in SMTP command"); + return FALSE; } } end: if (pcmd->args) { pcmd->args = g_list_reverse (pcmd->args); - rspamd_mempool_add_destructor (session->pool, (rspamd_mempool_destruct_t)g_list_free, pcmd->args); + rspamd_mempool_add_destructor (session->pool, + (rspamd_mempool_destruct_t)g_list_free, + pcmd->args); } return TRUE; } @@ -202,14 +211,14 @@ end: static gboolean check_smtp_path (f_str_t *path) { - guint i; - gchar *p; + guint i; + gchar *p; p = path->begin; if (*p != '<' || path->len < 2) { return FALSE; } - for (i = 0; i < path->len; i++, p ++) { + for (i = 0; i < path->len; i++, p++) { if (*p == '>' && i != path->len - 1) { return FALSE; } @@ -221,7 +230,7 @@ check_smtp_path (f_str_t *path) gboolean parse_smtp_helo (struct smtp_session *session, struct smtp_command *cmd) { - f_str_t *arg; + f_str_t *arg; if (cmd->args == NULL) { session->error = SMTP_ERROR_BAD_ARGUMENTS; @@ -256,8 +265,8 @@ parse_smtp_helo (struct smtp_session *session, struct smtp_command *cmd) gboolean parse_smtp_from (struct smtp_session *session, struct smtp_command *cmd) { - f_str_t *arg; - GList *cur = cmd->args; + f_str_t *arg; + GList *cur = cmd->args; if (cmd->args == NULL) { session->error = SMTP_ERROR_BAD_ARGUMENTS; @@ -266,10 +275,10 @@ parse_smtp_from (struct smtp_session *session, struct smtp_command *cmd) arg = cur->data; /* First argument MUST be FROM */ if (arg->len != 4 || ( - g_ascii_toupper (arg->begin[0]) != 'F' || - g_ascii_toupper (arg->begin[1]) != 'R' || - g_ascii_toupper (arg->begin[2]) != 'O' || - g_ascii_toupper (arg->begin[3]) != 'M')) { + g_ascii_toupper (arg->begin[0]) != 'F' || + g_ascii_toupper (arg->begin[1]) != 'R' || + g_ascii_toupper (arg->begin[2]) != 'O' || + g_ascii_toupper (arg->begin[3]) != 'M')) { session->error = SMTP_ERROR_BAD_ARGUMENTS; return FALSE; } @@ -294,8 +303,8 @@ parse_smtp_from (struct smtp_session *session, struct smtp_command *cmd) gboolean parse_smtp_rcpt (struct smtp_session *session, struct smtp_command *cmd) { - f_str_t *arg; - GList *cur = cmd->args; + f_str_t *arg; + GList *cur = cmd->args; if (cmd->args == NULL) { session->error = SMTP_ERROR_BAD_ARGUMENTS; @@ -304,8 +313,8 @@ parse_smtp_rcpt (struct smtp_session *session, struct smtp_command *cmd) arg = cur->data; /* First argument MUST be FROM */ if (arg->len != 2 || ( - g_ascii_toupper (arg->begin[0]) != 'T' || - g_ascii_toupper (arg->begin[1]) != 'O')) { + g_ascii_toupper (arg->begin[0]) != 'T' || + g_ascii_toupper (arg->begin[1]) != 'O')) { session->error = SMTP_ERROR_BAD_ARGUMENTS; return FALSE; } @@ -332,7 +341,7 @@ parse_smtp_rcpt (struct smtp_session *session, struct smtp_command *cmd) static gint check_smtp_ustream_reply (f_str_t *in, gchar success_code) { - gchar *p; + gchar *p; /* Check for 250 at the begin of line */ if (in->len >= sizeof ("220 ") - 1) { @@ -357,13 +366,13 @@ check_smtp_ustream_reply (f_str_t *in, gchar success_code) size_t smtp_upstream_write_list (GList *args, gchar *buf, size_t buflen) { - GList *cur = args; - size_t r = 0; - f_str_t *arg; + GList *cur = args; + size_t r = 0; + f_str_t *arg; while (cur && r < buflen - 3) { arg = cur->data; - r += rspamd_snprintf (buf + r, buflen - r, " %V", arg); + r += rspamd_snprintf (buf + r, buflen - r, " %V", arg); cur = g_list_next (cur); } @@ -374,288 +383,351 @@ smtp_upstream_write_list (GList *args, gchar *buf, size_t buflen) return r; } -gboolean +gboolean smtp_upstream_write_socket (void *arg) { - struct smtp_session *session = arg; - + struct smtp_session *session = arg; + if (session->upstream_state == SMTP_STATE_IN_SENDFILE) { session->upstream_state = SMTP_STATE_AFTER_DATA; - return rspamd_dispatcher_write (session->upstream_dispatcher, CRLF DATA_END_TRAILER, sizeof (CRLF DATA_END_TRAILER) - 1, FALSE, TRUE); + return rspamd_dispatcher_write (session->upstream_dispatcher, + CRLF DATA_END_TRAILER, + sizeof (CRLF DATA_END_TRAILER) - 1, + FALSE, + TRUE); } return TRUE; } -gboolean +gboolean smtp_upstream_read_socket (f_str_t * in, void *arg) { - struct smtp_session *session = arg; - gchar outbuf[BUFSIZ]; - gint r; - + struct smtp_session *session = arg; + gchar outbuf[BUFSIZ]; + gint r; + msg_debug ("in: %V, state: %d", in, session->upstream_state); switch (session->upstream_state) { - case SMTP_STATE_GREETING: - r = check_smtp_ustream_reply (in, '2'); - if (r == -1) { - session->error = rspamd_mempool_alloc (session->pool, in->len + 1); - rspamd_strlcpy (session->error, in->begin, in->len + 1); - /* XXX: assume upstream errors as critical errors */ - session->state = SMTP_STATE_CRITICAL_ERROR; - rspamd_dispatcher_restore (session->dispatcher); - if (! rspamd_dispatcher_write (session->dispatcher, session->error, in->len, FALSE, TRUE)) { - goto err; - } - if (! rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - 1, FALSE, TRUE)) { - goto err; - } - destroy_session (session->s); - return FALSE; + case SMTP_STATE_GREETING: + r = check_smtp_ustream_reply (in, '2'); + if (r == -1) { + session->error = rspamd_mempool_alloc (session->pool, in->len + 1); + rspamd_strlcpy (session->error, in->begin, in->len + 1); + /* XXX: assume upstream errors as critical errors */ + session->state = SMTP_STATE_CRITICAL_ERROR; + rspamd_dispatcher_restore (session->dispatcher); + if (!rspamd_dispatcher_write (session->dispatcher, session->error, + in->len, FALSE, TRUE)) { + goto err; } - else if (r == 1) { - if (session->ctx->use_xclient) { - r = rspamd_snprintf (outbuf, sizeof (outbuf), "XCLIENT NAME=%s ADDR=%s" CRLF, - session->resolved ? session->hostname : "[UNDEFINED]", - inet_ntoa (session->client_addr)); - session->upstream_state = SMTP_STATE_HELO; - return rspamd_dispatcher_write (session->upstream_dispatcher, outbuf, r, FALSE, FALSE); - } - else { - session->upstream_state = SMTP_STATE_FROM; - if (session->helo) { - r = rspamd_snprintf (outbuf, sizeof (outbuf), "%s %s" CRLF, - session->esmtp ? "EHLO" : "HELO", - session->helo); - } - else { - return smtp_upstream_read_socket (in, arg); - } - return rspamd_dispatcher_write (session->upstream_dispatcher, outbuf, r, FALSE, FALSE); - } + if (!rspamd_dispatcher_write (session->dispatcher, CRLF, + sizeof (CRLF) - 1, FALSE, TRUE)) { + goto err; } - break; - case SMTP_STATE_HELO: - r = check_smtp_ustream_reply (in, '2'); - if (r == -1) { - session->error = rspamd_mempool_alloc (session->pool, in->len + 1); - rspamd_strlcpy (session->error, in->begin, in->len + 1); - /* XXX: assume upstream errors as critical errors */ - session->state = SMTP_STATE_CRITICAL_ERROR; - rspamd_dispatcher_restore (session->dispatcher); - if (! rspamd_dispatcher_write (session->dispatcher, session->error, in->len, FALSE, TRUE)) { - goto err; - } - if (! rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - 1, FALSE, TRUE)) { - goto err; - } - destroy_session (session->s); - return FALSE; + destroy_session (session->s); + return FALSE; + } + else if (r == 1) { + if (session->ctx->use_xclient) { + r = rspamd_snprintf (outbuf, + sizeof (outbuf), + "XCLIENT NAME=%s ADDR=%s" CRLF, + session->resolved ? session->hostname : "[UNDEFINED]", + inet_ntoa (session->client_addr)); + session->upstream_state = SMTP_STATE_HELO; + return rspamd_dispatcher_write (session->upstream_dispatcher, + outbuf, + r, + FALSE, + FALSE); } - else if (r == 1) { + else { session->upstream_state = SMTP_STATE_FROM; if (session->helo) { - r = rspamd_snprintf (outbuf, sizeof (outbuf), "%s %s" CRLF, - session->esmtp ? "EHLO" : "HELO", - session->helo); + r = rspamd_snprintf (outbuf, sizeof (outbuf), "%s %s" CRLF, + session->esmtp ? "EHLO" : "HELO", + session->helo); } else { return smtp_upstream_read_socket (in, arg); } - return rspamd_dispatcher_write (session->upstream_dispatcher, outbuf, r, FALSE, FALSE); + return rspamd_dispatcher_write (session->upstream_dispatcher, + outbuf, + r, + FALSE, + FALSE); } - break; - case SMTP_STATE_FROM: - r = check_smtp_ustream_reply (in, '2'); - if (r == -1) { - session->error = rspamd_mempool_alloc (session->pool, in->len + 1); - rspamd_strlcpy (session->error, in->begin, in->len + 1); - /* XXX: assume upstream errors as critical errors */ - session->state = SMTP_STATE_CRITICAL_ERROR; - rspamd_dispatcher_restore (session->dispatcher); - if (! rspamd_dispatcher_write (session->dispatcher, session->error, in->len, FALSE, TRUE)) { - goto err; - } - if (! rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - 1, FALSE, TRUE)) { - goto err; - } - destroy_session (session->s); - return FALSE; + } + break; + case SMTP_STATE_HELO: + r = check_smtp_ustream_reply (in, '2'); + if (r == -1) { + session->error = rspamd_mempool_alloc (session->pool, in->len + 1); + rspamd_strlcpy (session->error, in->begin, in->len + 1); + /* XXX: assume upstream errors as critical errors */ + session->state = SMTP_STATE_CRITICAL_ERROR; + rspamd_dispatcher_restore (session->dispatcher); + if (!rspamd_dispatcher_write (session->dispatcher, session->error, + in->len, FALSE, TRUE)) { + goto err; } - else if (r == 1) { - r = rspamd_snprintf (outbuf, sizeof (outbuf), "MAIL FROM: "); - r += smtp_upstream_write_list (session->from, outbuf + r, sizeof (outbuf) - r); - session->upstream_state = SMTP_STATE_RCPT; - return rspamd_dispatcher_write (session->upstream_dispatcher, outbuf, r, FALSE, FALSE); + if (!rspamd_dispatcher_write (session->dispatcher, CRLF, + sizeof (CRLF) - 1, FALSE, TRUE)) { + goto err; } - break; - case SMTP_STATE_RCPT: - r = check_smtp_ustream_reply (in, '2'); - if (r == -1) { - session->error = rspamd_mempool_alloc (session->pool, in->len + 1); - rspamd_strlcpy (session->error, in->begin, in->len + 1); - /* XXX: assume upstream errors as critical errors */ - session->state = SMTP_STATE_CRITICAL_ERROR; - rspamd_dispatcher_restore (session->dispatcher); - if (! rspamd_dispatcher_write (session->dispatcher, session->error, in->len, FALSE, TRUE)) { - goto err; - } - if (! rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - 1, FALSE, TRUE)) { - goto err; - } - destroy_session (session->s); - return FALSE; + destroy_session (session->s); + return FALSE; + } + else if (r == 1) { + session->upstream_state = SMTP_STATE_FROM; + if (session->helo) { + r = rspamd_snprintf (outbuf, sizeof (outbuf), "%s %s" CRLF, + session->esmtp ? "EHLO" : "HELO", + session->helo); } - else if (r == 1) { - r = rspamd_snprintf (outbuf, sizeof (outbuf), "RCPT TO: "); - session->cur_rcpt = g_list_first (session->rcpt); - r += smtp_upstream_write_list (session->cur_rcpt->data, outbuf + r, sizeof (outbuf) - r); - session->cur_rcpt = g_list_next (session->cur_rcpt); - session->upstream_state = SMTP_STATE_BEFORE_DATA; - return rspamd_dispatcher_write (session->upstream_dispatcher, outbuf, r, FALSE, FALSE); + else { + return smtp_upstream_read_socket (in, arg); } - break; - case SMTP_STATE_BEFORE_DATA: - r = check_smtp_ustream_reply (in, '2'); - if (r == -1) { - session->error = rspamd_mempool_alloc (session->pool, in->len + 1); - rspamd_strlcpy (session->error, in->begin, in->len + 1); - rspamd_dispatcher_restore (session->dispatcher); - if (! rspamd_dispatcher_write (session->dispatcher, session->error, in->len, FALSE, TRUE)) { - goto err; - } - if (! rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - 1, FALSE, TRUE)) { - goto err; - } - if (session->cur_rcpt) { - session->rcpt = g_list_delete_link (session->rcpt, session->cur_rcpt); - } - else { - session->rcpt = g_list_delete_link (session->rcpt, session->rcpt); - } - session->errors ++; - session->state = SMTP_STATE_RCPT; - return TRUE; - } - else if (r == 1) { - if (session->cur_rcpt != NULL) { - r = rspamd_snprintf (outbuf, sizeof (outbuf), "RCPT TO: "); - r += smtp_upstream_write_list (session->cur_rcpt, outbuf + r, sizeof (outbuf) - r); - session->cur_rcpt = g_list_next (session->cur_rcpt); - if (! rspamd_dispatcher_write (session->upstream_dispatcher, outbuf, r, FALSE, FALSE)) { - goto err; - } - } - else { - session->upstream_state = SMTP_STATE_DATA; - rspamd_dispatcher_pause (session->upstream_dispatcher); - } - session->error = rspamd_mempool_alloc (session->pool, in->len + 1); - rspamd_strlcpy (session->error, in->begin, in->len + 1); - /* Write to client */ - if (! rspamd_dispatcher_write (session->dispatcher, session->error, in->len, FALSE, TRUE)) { - goto err; - } - if (! rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - 1, FALSE, TRUE)) { - goto err; - } - if (session->state == SMTP_STATE_WAIT_UPSTREAM) { - rspamd_dispatcher_restore (session->dispatcher); - session->state = SMTP_STATE_RCPT; - } + return rspamd_dispatcher_write (session->upstream_dispatcher, + outbuf, + r, + FALSE, + FALSE); + } + break; + case SMTP_STATE_FROM: + r = check_smtp_ustream_reply (in, '2'); + if (r == -1) { + session->error = rspamd_mempool_alloc (session->pool, in->len + 1); + rspamd_strlcpy (session->error, in->begin, in->len + 1); + /* XXX: assume upstream errors as critical errors */ + session->state = SMTP_STATE_CRITICAL_ERROR; + rspamd_dispatcher_restore (session->dispatcher); + if (!rspamd_dispatcher_write (session->dispatcher, session->error, + in->len, FALSE, TRUE)) { + goto err; } - break; - case SMTP_STATE_DATA: - r = check_smtp_ustream_reply (in, '3'); - if (r == -1) { - session->error = rspamd_mempool_alloc (session->pool, in->len + 1); - rspamd_strlcpy (session->error, in->begin, in->len + 1); - /* XXX: assume upstream errors as critical errors */ - session->state = SMTP_STATE_CRITICAL_ERROR; - rspamd_dispatcher_restore (session->dispatcher); - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { - goto err; - } - if (! rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - 1, FALSE, TRUE)) { - goto err; - } - destroy_session (session->s); - return FALSE; + if (!rspamd_dispatcher_write (session->dispatcher, CRLF, + sizeof (CRLF) - 1, FALSE, TRUE)) { + goto err; } - else if (r == 1) { - if (! make_smtp_tempfile (session)) { - session->error = SMTP_ERROR_FILE; - session->state = SMTP_STATE_CRITICAL_ERROR; - rspamd_dispatcher_restore (session->dispatcher); - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { - goto err; - } - destroy_session (session->s); - return FALSE; - } - session->state = SMTP_STATE_AFTER_DATA; - session->error = SMTP_ERROR_DATA_OK; - rspamd_dispatcher_restore (session->dispatcher); - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { + destroy_session (session->s); + return FALSE; + } + else if (r == 1) { + r = rspamd_snprintf (outbuf, sizeof (outbuf), "MAIL FROM: "); + r += + smtp_upstream_write_list (session->from, + outbuf + r, + sizeof (outbuf) - r); + session->upstream_state = SMTP_STATE_RCPT; + return rspamd_dispatcher_write (session->upstream_dispatcher, + outbuf, + r, + FALSE, + FALSE); + } + break; + case SMTP_STATE_RCPT: + r = check_smtp_ustream_reply (in, '2'); + if (r == -1) { + session->error = rspamd_mempool_alloc (session->pool, in->len + 1); + rspamd_strlcpy (session->error, in->begin, in->len + 1); + /* XXX: assume upstream errors as critical errors */ + session->state = SMTP_STATE_CRITICAL_ERROR; + rspamd_dispatcher_restore (session->dispatcher); + if (!rspamd_dispatcher_write (session->dispatcher, session->error, + in->len, FALSE, TRUE)) { + goto err; + } + if (!rspamd_dispatcher_write (session->dispatcher, CRLF, + sizeof (CRLF) - 1, FALSE, TRUE)) { + goto err; + } + destroy_session (session->s); + return FALSE; + } + else if (r == 1) { + r = rspamd_snprintf (outbuf, sizeof (outbuf), "RCPT TO: "); + session->cur_rcpt = g_list_first (session->rcpt); + r += smtp_upstream_write_list (session->cur_rcpt->data, + outbuf + r, + sizeof (outbuf) - r); + session->cur_rcpt = g_list_next (session->cur_rcpt); + session->upstream_state = SMTP_STATE_BEFORE_DATA; + return rspamd_dispatcher_write (session->upstream_dispatcher, + outbuf, + r, + FALSE, + FALSE); + } + break; + case SMTP_STATE_BEFORE_DATA: + r = check_smtp_ustream_reply (in, '2'); + if (r == -1) { + session->error = rspamd_mempool_alloc (session->pool, in->len + 1); + rspamd_strlcpy (session->error, in->begin, in->len + 1); + rspamd_dispatcher_restore (session->dispatcher); + if (!rspamd_dispatcher_write (session->dispatcher, session->error, + in->len, FALSE, TRUE)) { + goto err; + } + if (!rspamd_dispatcher_write (session->dispatcher, CRLF, + sizeof (CRLF) - 1, FALSE, TRUE)) { + goto err; + } + if (session->cur_rcpt) { + session->rcpt = g_list_delete_link (session->rcpt, + session->cur_rcpt); + } + else { + session->rcpt = + g_list_delete_link (session->rcpt, session->rcpt); + } + session->errors++; + session->state = SMTP_STATE_RCPT; + return TRUE; + } + else if (r == 1) { + if (session->cur_rcpt != NULL) { + r = rspamd_snprintf (outbuf, sizeof (outbuf), "RCPT TO: "); + r += smtp_upstream_write_list (session->cur_rcpt, + outbuf + r, + sizeof (outbuf) - r); + session->cur_rcpt = g_list_next (session->cur_rcpt); + if (!rspamd_dispatcher_write (session->upstream_dispatcher, + outbuf, r, FALSE, FALSE)) { goto err; } + } + else { + session->upstream_state = SMTP_STATE_DATA; rspamd_dispatcher_pause (session->upstream_dispatcher); - rspamd_set_dispatcher_policy (session->dispatcher, BUFFER_LINE, 0); - session->dispatcher->strip_eol = FALSE; - return TRUE; } - break; - case SMTP_STATE_AFTER_DATA: session->error = rspamd_mempool_alloc (session->pool, in->len + 1); rspamd_strlcpy (session->error, in->begin, in->len + 1); - session->state = SMTP_STATE_DATA; - rspamd_dispatcher_restore (session->dispatcher); - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { + /* Write to client */ + if (!rspamd_dispatcher_write (session->dispatcher, session->error, + in->len, FALSE, TRUE)) { goto err; } - if (! rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - 1, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, CRLF, + sizeof (CRLF) - 1, FALSE, TRUE)) { goto err; } - if (! rspamd_dispatcher_write (session->upstream_dispatcher, "QUIT" CRLF, sizeof ("QUIT" CRLF) - 1, FALSE, TRUE)) { + if (session->state == SMTP_STATE_WAIT_UPSTREAM) { + rspamd_dispatcher_restore (session->dispatcher); + session->state = SMTP_STATE_RCPT; + } + } + break; + case SMTP_STATE_DATA: + r = check_smtp_ustream_reply (in, '3'); + if (r == -1) { + session->error = rspamd_mempool_alloc (session->pool, in->len + 1); + rspamd_strlcpy (session->error, in->begin, in->len + 1); + /* XXX: assume upstream errors as critical errors */ + session->state = SMTP_STATE_CRITICAL_ERROR; + rspamd_dispatcher_restore (session->dispatcher); + if (!rspamd_dispatcher_write (session->dispatcher, session->error, + 0, FALSE, TRUE)) { goto err; } - session->upstream_state = SMTP_STATE_END; - return TRUE; - break; - case SMTP_STATE_END: - r = check_smtp_ustream_reply (in, '5'); - if (r == -1) { - session->error = rspamd_mempool_alloc (session->pool, in->len + 1); - rspamd_strlcpy (session->error, in->begin, in->len + 1); - /* XXX: assume upstream errors as critical errors */ + if (!rspamd_dispatcher_write (session->dispatcher, CRLF, + sizeof (CRLF) - 1, FALSE, TRUE)) { + goto err; + } + destroy_session (session->s); + return FALSE; + } + else if (r == 1) { + if (!make_smtp_tempfile (session)) { + session->error = SMTP_ERROR_FILE; session->state = SMTP_STATE_CRITICAL_ERROR; rspamd_dispatcher_restore (session->dispatcher); - if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { - goto err; - } - if (! rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - 1, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, + session->error, 0, FALSE, TRUE)) { goto err; } destroy_session (session->s); return FALSE; } - else { - remove_normal_event (session->s, (event_finalizer_t)smtp_upstream_finalize_connection, session); + session->state = SMTP_STATE_AFTER_DATA; + session->error = SMTP_ERROR_DATA_OK; + rspamd_dispatcher_restore (session->dispatcher); + if (!rspamd_dispatcher_write (session->dispatcher, session->error, + 0, FALSE, TRUE)) { + goto err; } - return FALSE; - break; - default: - msg_err ("got upstream reply at unexpected state: %d, reply: %V", session->upstream_state, in); + rspamd_dispatcher_pause (session->upstream_dispatcher); + rspamd_set_dispatcher_policy (session->dispatcher, BUFFER_LINE, 0); + session->dispatcher->strip_eol = FALSE; + return TRUE; + } + break; + case SMTP_STATE_AFTER_DATA: + session->error = rspamd_mempool_alloc (session->pool, in->len + 1); + rspamd_strlcpy (session->error, in->begin, in->len + 1); + session->state = SMTP_STATE_DATA; + rspamd_dispatcher_restore (session->dispatcher); + if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0, + FALSE, TRUE)) { + goto err; + } + if (!rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - + 1, FALSE, TRUE)) { + goto err; + } + if (!rspamd_dispatcher_write (session->upstream_dispatcher, "QUIT" CRLF, + sizeof ("QUIT" CRLF) - 1, FALSE, TRUE)) { + goto err; + } + session->upstream_state = SMTP_STATE_END; + return TRUE; + break; + case SMTP_STATE_END: + r = check_smtp_ustream_reply (in, '5'); + if (r == -1) { + session->error = rspamd_mempool_alloc (session->pool, in->len + 1); + rspamd_strlcpy (session->error, in->begin, in->len + 1); + /* XXX: assume upstream errors as critical errors */ session->state = SMTP_STATE_CRITICAL_ERROR; rspamd_dispatcher_restore (session->dispatcher); - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, session->error, + 0, FALSE, TRUE)) { goto err; } - if (! rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - 1, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, CRLF, + sizeof (CRLF) - 1, FALSE, TRUE)) { goto err; } destroy_session (session->s); return FALSE; + } + else { + remove_normal_event (session->s, + (event_finalizer_t)smtp_upstream_finalize_connection, + session); + } + return FALSE; + break; + default: + msg_err ("got upstream reply at unexpected state: %d, reply: %V", + session->upstream_state, + in); + session->state = SMTP_STATE_CRITICAL_ERROR; + rspamd_dispatcher_restore (session->dispatcher); + if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0, + FALSE, TRUE)) { + goto err; + } + if (!rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - + 1, FALSE, TRUE)) { + goto err; + } + destroy_session (session->s); + return FALSE; } return TRUE; @@ -664,20 +736,24 @@ err: return FALSE; } -void +void smtp_upstream_err_socket (GError *err, void *arg) { - struct smtp_session *session = arg; + struct smtp_session *session = arg; - msg_info ("abnormally closing connection with upstream %s, error: %s", session->upstream->name, err->message); + msg_info ("abnormally closing connection with upstream %s, error: %s", + session->upstream->name, + err->message); session->error = SMTP_ERROR_UPSTREAM; session->state = SMTP_STATE_CRITICAL_ERROR; /* XXX: assume upstream errors as critical errors */ rspamd_dispatcher_restore (session->dispatcher); - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, + TRUE)) { return; } - if (! rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - 1, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - 1, + FALSE, TRUE)) { return; } upstream_fail (&session->upstream->up, session->session_time); @@ -687,10 +763,11 @@ smtp_upstream_err_socket (GError *err, void *arg) void smtp_upstream_finalize_connection (gpointer data) { - struct smtp_session *session = data; - + struct smtp_session *session = data; + if (session->state != SMTP_STATE_CRITICAL_ERROR) { - if (! rspamd_dispatcher_write (session->upstream_dispatcher, "QUIT" CRLF, 0, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->upstream_dispatcher, "QUIT" CRLF, + 0, FALSE, TRUE)) { msg_warn ("cannot send correctly closing message to upstream"); } } diff --git a/src/libmime/smtp_proto.h b/src/libmime/smtp_proto.h index 42fecd255..7c5787926 100644 --- a/src/libmime/smtp_proto.h +++ b/src/libmime/smtp_proto.h @@ -6,12 +6,14 @@ /* SMTP errors */ #define SMTP_ERROR_BAD_COMMAND "500 Syntax error, command unrecognized" CRLF -#define SMTP_ERROR_BAD_ARGUMENTS "501 Syntax error in parameters or arguments" CRLF +#define SMTP_ERROR_BAD_ARGUMENTS "501 Syntax error in parameters or arguments" \ + CRLF #define SMTP_ERROR_SEQUENCE "503 Bad sequence of commands" CRLF #define SMTP_ERROR_RECIPIENTS "554 No valid recipients" CRLF #define SMTP_ERROR_UNIMPLIMENTED "502 Command not implemented" CRLF #define SMTP_ERROR_LIMIT "505 Too many errors. Aborting." CRLF -#define SMTP_ERROR_UPSTREAM "421 Service not available, closing transmission channel" CRLF +#define SMTP_ERROR_UPSTREAM \ + "421 Service not available, closing transmission channel" CRLF #define SMTP_ERROR_FILE "420 Service not available, filesystem error" CRLF #define SMTP_ERROR_OK "250 Requested mail action okay, completed" CRLF #define SMTP_ERROR_DATA_OK "354 Start mail input; end with <CRLF>.<CRLF>" CRLF @@ -43,27 +45,35 @@ struct smtp_command { /* * Generate SMTP error message */ -gchar * make_smtp_error (rspamd_mempool_t *pool, gint error_code, const gchar *format, ...); +gchar * make_smtp_error (rspamd_mempool_t *pool, + gint error_code, + const gchar *format, + ...); /* * Parse a single SMTP command */ -gboolean parse_smtp_command (struct smtp_session *session, f_str_t *line, struct smtp_command **cmd); +gboolean parse_smtp_command (struct smtp_session *session, + f_str_t *line, + struct smtp_command **cmd); /* * Parse HELO command */ -gboolean parse_smtp_helo (struct smtp_session *session, struct smtp_command *cmd); +gboolean parse_smtp_helo (struct smtp_session *session, + struct smtp_command *cmd); /* * Parse MAIL command */ -gboolean parse_smtp_from (struct smtp_session *session, struct smtp_command *cmd); +gboolean parse_smtp_from (struct smtp_session *session, + struct smtp_command *cmd); /* * Parse RCPT command */ -gboolean parse_smtp_rcpt (struct smtp_session *session, struct smtp_command *cmd); +gboolean parse_smtp_rcpt (struct smtp_session *session, + struct smtp_command *cmd); /* Upstream SMTP */ diff --git a/src/libmime/smtp_utils.c b/src/libmime/smtp_utils.c index 8ed169fa7..a4fb4582e 100644 --- a/src/libmime/smtp_utils.c +++ b/src/libmime/smtp_utils.c @@ -22,15 +22,15 @@ */ #include "config.h" -#include "main.h" #include "filter.h" +#include "main.h" #include "smtp.h" #include "smtp_proto.h" void free_smtp_session (gpointer arg) { - struct smtp_session *session = arg; + struct smtp_session *session = arg; if (session) { if (session->task) { @@ -60,12 +60,17 @@ free_smtp_session (gpointer arg) gboolean create_smtp_upstream_connection (struct smtp_session *session) { - struct smtp_upstream *selected; + struct smtp_upstream *selected; /* Try to select upstream */ - selected = (struct smtp_upstream *)get_upstream_round_robin (session->ctx->upstreams, - session->ctx->upstream_num, sizeof (struct smtp_upstream), - session->session_time, DEFAULT_UPSTREAM_ERROR_TIME, DEFAULT_UPSTREAM_DEAD_TIME, DEFAULT_UPSTREAM_MAXERRORS); + selected = (struct smtp_upstream *)get_upstream_round_robin ( + session->ctx->upstreams, + session->ctx->upstream_num, + sizeof (struct smtp_upstream), + session->session_time, + DEFAULT_UPSTREAM_ERROR_TIME, + DEFAULT_UPSTREAM_DEAD_TIME, + DEFAULT_UPSTREAM_MAXERRORS); if (selected == NULL) { msg_err ("no upstreams suitable found"); return FALSE; @@ -74,19 +79,32 @@ create_smtp_upstream_connection (struct smtp_session *session) session->upstream = selected; /* Now try to create socket */ - session->upstream_sock = make_universal_socket (selected->addr, selected->port, SOCK_STREAM, TRUE, FALSE, FALSE); + session->upstream_sock = make_universal_socket (selected->addr, + selected->port, + SOCK_STREAM, + TRUE, + FALSE, + FALSE); if (session->upstream_sock == -1) { msg_err ("cannot make a connection to %s", selected->name); upstream_fail (&selected->up, session->session_time); return FALSE; } /* Create a dispatcher for upstream connection */ - session->upstream_dispatcher = rspamd_create_dispatcher (session->ev_base, session->upstream_sock, BUFFER_LINE, - smtp_upstream_read_socket, smtp_upstream_write_socket, smtp_upstream_err_socket, - &session->ctx->smtp_timeout, session); + session->upstream_dispatcher = rspamd_create_dispatcher (session->ev_base, + session->upstream_sock, + BUFFER_LINE, + smtp_upstream_read_socket, + smtp_upstream_write_socket, + smtp_upstream_err_socket, + &session->ctx->smtp_timeout, + session); session->state = SMTP_STATE_WAIT_UPSTREAM; session->upstream_state = SMTP_STATE_GREETING; - register_async_event (session->s, (event_finalizer_t)smtp_upstream_finalize_connection, session, g_quark_from_static_string ("smtp proxy")); + register_async_event (session->s, + (event_finalizer_t)smtp_upstream_finalize_connection, + session, + g_quark_from_static_string ("smtp proxy")); return TRUE; } @@ -98,7 +116,8 @@ smtp_send_upstream_message (struct smtp_session *session) session->upstream_state = SMTP_STATE_IN_SENDFILE; session->state = SMTP_STATE_WAIT_UPSTREAM; - if (! rspamd_dispatcher_sendfile (session->upstream_dispatcher, session->temp_fd, session->temp_size)) { + if (!rspamd_dispatcher_sendfile (session->upstream_dispatcher, + session->temp_fd, session->temp_size)) { msg_err ("sendfile failed: %s", strerror (errno)); goto err; } @@ -107,7 +126,8 @@ smtp_send_upstream_message (struct smtp_session *session) err: session->error = SMTP_ERROR_FILE; session->state = SMTP_STATE_CRITICAL_ERROR; - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, + TRUE)) { return FALSE; } destroy_session (session->s); @@ -115,32 +135,35 @@ err: } struct smtp_metric_callback_data { - struct smtp_session *session; - enum rspamd_metric_action action; - struct metric_result *res; - gchar *log_buf; - gint log_offset; - gint log_size; - gboolean alive; + struct smtp_session *session; + enum rspamd_metric_action action; + struct metric_result *res; + gchar *log_buf; + gint log_offset; + gint log_size; + gboolean alive; }; static void smtp_metric_symbols_callback (gpointer key, gpointer value, void *user_data) { - struct smtp_metric_callback_data *cd = user_data; + struct smtp_metric_callback_data *cd = user_data; - cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset, cd->log_size - cd->log_offset, "%s,", (gchar *)key); + cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset, + cd->log_size - cd->log_offset, + "%s,", + (gchar *)key); } static void smtp_metric_callback (gpointer key, gpointer value, gpointer ud) { struct smtp_metric_callback_data *cd = ud; - struct metric_result *metric_res = value; - enum rspamd_metric_action action = METRIC_ACTION_NOACTION; - double ms = 0, rs = 0; - gboolean is_spam = FALSE; - struct rspamd_task *task; + struct metric_result *metric_res = value; + enum rspamd_metric_action action = METRIC_ACTION_NOACTION; + double ms = 0, rs = 0; + gboolean is_spam = FALSE; + struct rspamd_task *task; task = cd->session->task; @@ -152,8 +175,10 @@ smtp_metric_callback (gpointer key, gpointer value, gpointer ud) ms = metric_res->metric->actions[METRIC_ACTION_REJECT].score; rs = metric_res->metric->actions[METRIC_ACTION_REJECT].score; } - if (! check_metric_action_settings (task, metric_res, metric_res->score, &action)) { - action = check_metric_action (metric_res->score, ms, metric_res->metric); + if (!check_metric_action_settings (task, metric_res, metric_res->score, + &action)) { + action = + check_metric_action (metric_res->score, ms, metric_res->metric); } #endif if (metric_res->score >= ms) { @@ -165,42 +190,70 @@ smtp_metric_callback (gpointer key, gpointer value, gpointer ud) } if (!task->is_skipped) { - cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset, cd->log_size - cd->log_offset, "(%s: %c (%s): [%.2f/%.2f/%.2f] [", - (gchar *)key, is_spam ? 'T' : 'F', str_action_metric (action), metric_res->score, ms, rs); + cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset, + cd->log_size - cd->log_offset, + "(%s: %c (%s): [%.2f/%.2f/%.2f] [", + (gchar *)key, + is_spam ? 'T' : 'F', + str_action_metric (action), + metric_res->score, + ms, + rs); } else { - cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset, cd->log_size - cd->log_offset, "(%s: %c (default): [%.2f/%.2f/%.2f] [", - (gchar *)key, 'S', metric_res->score, ms, rs); + cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset, + cd->log_size - cd->log_offset, + "(%s: %c (default): [%.2f/%.2f/%.2f] [", + (gchar *)key, + 'S', + metric_res->score, + ms, + rs); } - g_hash_table_foreach (metric_res->symbols, smtp_metric_symbols_callback, cd); + g_hash_table_foreach (metric_res->symbols, smtp_metric_symbols_callback, + cd); /* Remove last , from log buf */ if (cd->log_buf[cd->log_offset - 1] == ',') { cd->log_buf[--cd->log_offset] = '\0'; } #ifdef HAVE_CLOCK_GETTIME - cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset, cd->log_size - cd->log_offset, "]), len: %z, time: %s,", - task->msg->len, calculate_check_time (&task->tv, &task->ts, task->cfg->clock_res, &task->scan_milliseconds)); + cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset, + cd->log_size - cd->log_offset, + "]), len: %z, time: %s,", + task->msg->len, + calculate_check_time (&task->tv, &task->ts, task->cfg->clock_res, + &task->scan_milliseconds)); #else - cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset, cd->log_size - cd->log_offset, "]), len: %z, time: %s,", - task->msg->len, calculate_check_time (&task->tv, task->cfg->clock_res, &task->scan_milliseconds)); + cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset, + cd->log_size - cd->log_offset, + "]), len: %z, time: %s,", + task->msg->len, + calculate_check_time (&task->tv, task->cfg->clock_res, + &task->scan_milliseconds)); #endif } gboolean make_smtp_tempfile (struct smtp_session *session) { - gsize r; + gsize r; r = strlen (session->cfg->temp_dir) + sizeof ("/rspamd-XXXXXX"); session->temp_name = rspamd_mempool_alloc (session->pool, r); - rspamd_snprintf (session->temp_name, r, "%s%crspamd-XXXXXX", session->cfg->temp_dir, G_DIR_SEPARATOR); + rspamd_snprintf (session->temp_name, + r, + "%s%crspamd-XXXXXX", + session->cfg->temp_dir, + G_DIR_SEPARATOR); #ifdef HAVE_MKSTEMP /* Umask is set before */ session->temp_fd = mkstemp (session->temp_name); #else - session->temp_fd = g_mkstemp_full (session->temp_name, O_RDWR, S_IWUSR | S_IRUSR); + session->temp_fd = g_mkstemp_full (session->temp_name, + O_RDWR, + S_IWUSR | S_IRUSR); #endif if (session->temp_fd == -1) { msg_err ("mkstemp error: %s", strerror (errno)); @@ -214,23 +267,28 @@ make_smtp_tempfile (struct smtp_session *session) gboolean write_smtp_reply (struct smtp_session *session) { - gchar logbuf[1024], *new_subject; - const gchar *old_subject; + gchar logbuf[1024], *new_subject; + const gchar *old_subject; struct smtp_metric_callback_data cd; - GMimeStream *stream; - gint old_fd, sublen; + GMimeStream *stream; + gint old_fd, sublen; /* Check metrics */ cd.session = session; cd.action = METRIC_ACTION_NOACTION; cd.res = NULL; cd.log_buf = logbuf; - cd.log_offset = rspamd_snprintf (logbuf, sizeof (logbuf), "id: <%s>, qid: <%s>, ", - session->task->message_id, session->task->queue_id); + cd.log_offset = rspamd_snprintf (logbuf, + sizeof (logbuf), + "id: <%s>, qid: <%s>, ", + session->task->message_id, + session->task->queue_id); cd.log_size = sizeof (logbuf); if (session->task->user) { - cd.log_offset += rspamd_snprintf (logbuf + cd.log_offset, sizeof (logbuf) - cd.log_offset, - "user: %s, ", session->task->user); + cd.log_offset += rspamd_snprintf (logbuf + cd.log_offset, + sizeof (logbuf) - cd.log_offset, + "user: %s, ", + session->task->user); } g_hash_table_foreach (session->task->results, smtp_metric_callback, &cd); @@ -238,22 +296,26 @@ write_smtp_reply (struct smtp_session *session) msg_info ("%s", logbuf); if (cd.action <= METRIC_ACTION_REJECT) { - if (! rspamd_dispatcher_write (session->dispatcher, session->ctx->reject_message, 0, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, + session->ctx->reject_message, 0, FALSE, TRUE)) { return FALSE; } - if (! rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - 1, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) - + 1, FALSE, TRUE)) { return FALSE; } destroy_session (session->s); return FALSE; } - else if (cd.action <= METRIC_ACTION_ADD_HEADER || cd.action <= METRIC_ACTION_REWRITE_SUBJECT) { + else if (cd.action <= METRIC_ACTION_ADD_HEADER || cd.action <= + METRIC_ACTION_REWRITE_SUBJECT) { old_fd = session->temp_fd; - if (! make_smtp_tempfile (session)) { + if (!make_smtp_tempfile (session)) { session->error = SMTP_ERROR_FILE; session->state = SMTP_STATE_CRITICAL_ERROR; rspamd_dispatcher_restore (session->dispatcher); - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, session->error, + 0, FALSE, TRUE)) { goto err; } destroy_session (session->s); @@ -266,7 +328,11 @@ write_smtp_reply (struct smtp_session *session) if (old_subject != NULL) { sublen = strlen (old_subject) + sizeof (SPAM_SUBJECT); new_subject = rspamd_mempool_alloc (session->pool, sublen); - rspamd_snprintf (new_subject, sublen, "%s%s", SPAM_SUBJECT, old_subject); + rspamd_snprintf (new_subject, + sublen, + "%s%s", + SPAM_SUBJECT, + old_subject); } else { new_subject = SPAM_SUBJECT; @@ -275,21 +341,26 @@ write_smtp_reply (struct smtp_session *session) } else if (cd.action <= METRIC_ACTION_ADD_HEADER) { #ifndef GMIME24 - g_mime_message_add_header (session->task->message, "X-Spam", "true"); + g_mime_message_add_header (session->task->message, "X-Spam", + "true"); #else - g_mime_object_append_header (GMIME_OBJECT (session->task->message), "X-Spam", "true"); + g_mime_object_append_header (GMIME_OBJECT ( + session->task->message), "X-Spam", "true"); #endif } stream = g_mime_stream_fs_new (session->temp_fd); g_mime_stream_fs_set_owner (GMIME_STREAM_FS (stream), FALSE); close (old_fd); - if (g_mime_object_write_to_stream (GMIME_OBJECT (session->task->message), stream) == -1) { - msg_err ("cannot write MIME object to stream: %s", strerror (errno)); + if (g_mime_object_write_to_stream (GMIME_OBJECT (session->task->message), + stream) == -1) { + msg_err ("cannot write MIME object to stream: %s", + strerror (errno)); session->error = SMTP_ERROR_FILE; session->state = SMTP_STATE_CRITICAL_ERROR; rspamd_dispatcher_restore (session->dispatcher); - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, session->error, + 0, FALSE, TRUE)) { goto err; } destroy_session (session->s); @@ -302,7 +373,8 @@ write_smtp_reply (struct smtp_session *session) err: session->error = SMTP_ERROR_FILE; session->state = SMTP_STATE_CRITICAL_ERROR; - if (! rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, TRUE)) { + if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE, + TRUE)) { return FALSE; } destroy_session (session->s); @@ -310,29 +382,33 @@ err: } gboolean -parse_upstreams_line (rspamd_mempool_t *pool, struct smtp_upstream *upstreams, const gchar *line, gsize *count) +parse_upstreams_line (rspamd_mempool_t *pool, + struct smtp_upstream *upstreams, + const gchar *line, + gsize *count) { - gchar **strv, *p, *t, *tt, *err_str; - guint32 num, i; - struct smtp_upstream *cur; - gchar resolved_path[PATH_MAX]; + gchar **strv, *p, *t, *tt, *err_str; + guint32 num, i; + struct smtp_upstream *cur; + gchar resolved_path[PATH_MAX]; strv = g_strsplit_set (line, ",; ", -1); num = g_strv_length (strv); if (num >= MAX_SMTP_UPSTREAMS) { - msg_err ("cannot define %d upstreams %d is max", num, MAX_SMTP_UPSTREAMS); + msg_err ("cannot define %d upstreams %d is max", num, + MAX_SMTP_UPSTREAMS); return FALSE; } *count = 0; - for (i = 0; i < num; i ++) { + for (i = 0; i < num; i++) { p = strv[i]; cur = &upstreams[*count]; if ((t = strrchr (p, ':')) != NULL && (tt = strchr (p, ':')) != t) { /* Assume that after last `:' we have weigth */ *t = '\0'; - t ++; + t++; errno = 0; cur->up.priority = strtoul (t, &err_str, 10); if (errno != 0 || (err_str && *err_str != '\0')) { @@ -349,15 +425,15 @@ parse_upstreams_line (rspamd_mempool_t *pool, struct smtp_upstream *upstreams, c return FALSE; } cur->name = rspamd_mempool_strdup (pool, resolved_path); - (*count) ++; + (*count)++; } else { - if (! rspamd_parse_host_port (pool, p, &cur->addr, &cur->port)) { + if (!rspamd_parse_host_port (pool, p, &cur->addr, &cur->port)) { g_strfreev (strv); return FALSE; } cur->name = rspamd_mempool_strdup (pool, p); - (*count) ++; + (*count)++; } } diff --git a/src/libmime/smtp_utils.h b/src/libmime/smtp_utils.h index 652b6759f..c09729180 100644 --- a/src/libmime/smtp_utils.h +++ b/src/libmime/smtp_utils.h @@ -58,6 +58,9 @@ void free_smtp_session (gpointer arg); * @param count targeted count * @return */ -gboolean parse_upstreams_line (rspamd_mempool_t *pool, struct smtp_upstream *upstreams, const gchar *line, gsize *count); +gboolean parse_upstreams_line (rspamd_mempool_t *pool, + struct smtp_upstream *upstreams, + const gchar *line, + gsize *count); #endif /* SMTP_UTILS_H_ */ |