]> source.dussan.org Git - rspamd.git/commitdiff
* Add 3 functions:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Mon, 30 Mar 2009 15:35:57 +0000 (19:35 +0400)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Mon, 30 Mar 2009 15:35:57 +0000 (19:35 +0400)
 - is_recipients_sorted
 - has_only_html_part
 - compare_recipients_distance
* Update documentation
* Fix build

README.utf8.txt
src/cfg_file.l
src/cfg_file.y
src/expressions.c
src/fuzzy.c
src/fuzzy.h
src/main.h
src/message.c

index 3ea18664ad969ea33ac9fb10208df366e15a1e1d..d328efa7ef7ac1c986a45fc6e0c5f0601900cda7 100644 (file)
@@ -147,3 +147,10 @@ SOME_SYMBOL = "${to_blah} & !(${from_blah} | ${subject_blah})"
   * content_type_is_type - сравнивает тип content-type с регулярным выражением или строкой
      content_type_is_type(text)
      content_type_is_subtype(/?.html/)
+  * regexp_match_number - принимает в качестве первого параметра число, которое означает порог сработавших регэкспов и 
+    список регэкспов или функций, которые должны проверяться. Если число сработавших регэкспов или функций больше порога,
+       функция возвращает TRUE, иначе - FALSE, например:
+       regexp_match_number(2, ${__RE1}, ${__RE2}, header_exists(Subject))
+  * has_only_html_part - функция возвращает TRUE, если в сообщении есть только одна HTML часть
+  * compare_recipients_distance - вычисляет процент схожих получателей письма. Принимает аргумент - порог в процентах похожести.
+  * is_recipients_sorted - возвращает TRUE, если список получателей сортирован (работает только если число получателей >= 5).
index 3224b4fdee094187d39b2d06447e63f843e0350a..8d347409f477355c3aaab4520f3bd21555b9816f 100644 (file)
@@ -11,7 +11,7 @@
 #ifdef WITH_LUA
 #include "lua.h"
 #else 
-#define add_luabuf(x) yyerror ("lua support diabled"); YYERROR
+#define add_luabuf(x) yyerror ("lua support diabled")
 #endif
 
 #define MAX_INCLUDE_DEPTH 10
@@ -157,6 +157,9 @@ yes|YES|no|NO|[yY]|[nN]                     yylval.flag=parse_flag(yytext); return FLAG;
 <module>\$[a-zA-Z_][a-zA-Z0-9_]+               yylval.string=strdup(yytext + 1); return VARIABLE;
 <module>\".+[^\\]\"    yylval.string=strdup(yytext + 1); yylval.string[strlen(yylval.string) - 1] = '\0'; unescape_quotes(yylval.string); return QUOTEDSTRING;
 
+<lua>\n                                                                        /* ignore EOL */;
+<lua>[ \t]+                                                            /* ignore whitespace */;
+<lua>[ \t]*#.*                                                 /* ignore comments */;
 <lua>^.endlua$                                                 BEGIN(INITIAL);
 <lua>.*                                                                        add_luabuf(yytext);
 
index b62b6b5b4cebd516c6910d6ac35b778b92125143..92b695d557440009666c74bc8d08bdc84cb966fc 100644 (file)
@@ -14,8 +14,6 @@
 #include "perl.h"
 #endif
 
-#define YYDEBUG 1
-
 extern struct config_file *cfg;
 extern int yylineno;
 extern char *yytext;
@@ -330,8 +328,10 @@ metricfunction:
                cur_metric->func_name = memory_pool_strdup (cfg->cfg_pool, $3);
 #ifdef WITH_LUA
                cur_metric->func = lua_consolidation_func;
-#else
+#elif !defined(WITHOUT_PERL)
                cur_metric->func = perl_consolidation_func;
+#else
+               yyerror ("yyparse: rspamd is not compiled with perl or lua, so it is not possible to use custom consolidation functions");
 #endif
        }
        ;
index 957c43c5c9a081e6ebf408a16c7bc7d86c51e484..3fff36fbd1b192bb182fbea654588b47e6cda3fa 100644 (file)
@@ -37,6 +37,9 @@ gboolean rspamd_content_type_has_param (struct worker_task *task, GList *args);
 gboolean rspamd_content_type_is_subtype (struct worker_task *task, GList *args);
 gboolean rspamd_content_type_is_type (struct worker_task *task, GList *args);
 gboolean rspamd_parts_distance (struct worker_task *task, GList *args);
+gboolean rspamd_recipients_distance (struct worker_task *task, GList *args);
+gboolean rspamd_has_only_html_part (struct worker_task *task, GList *args);
+gboolean rspamd_is_recipients_sorted (struct worker_task *task, GList *args);
 
 /*
  * List of internal functions of rspamd
@@ -48,11 +51,14 @@ static struct _fl {
 } rspamd_functions_list[] = {
        { "compare_encoding", rspamd_compare_encoding },
        { "compare_parts_distance", rspamd_parts_distance },
+       { "compare_recipients_distance", rspamd_recipients_distance },
        { "content_type_compare_param", rspamd_content_type_compare_param },
        { "content_type_has_param", rspamd_content_type_has_param },
        { "content_type_is_subtype", rspamd_content_type_is_subtype },
        { "content_type_is_type", rspamd_content_type_is_type },
+       { "has_only_html_part", rspamd_has_only_html_part },
        { "header_exists", rspamd_header_exists },
+       { "is_recipients_sorted", rspamd_is_recipients_sorted },
 };
 
 static struct _fl *list_ptr = &rspamd_functions_list[0];
@@ -916,6 +922,144 @@ rspamd_content_type_is_type (struct worker_task *task, GList *args)
        return FALSE;
 }
 
+struct addr_list {
+       const char *name;
+       const char *addr;
+};
+
+#define COMPARE_RCPT_LEN 3
+#define MIN_RCPT_TO_COMPARE 5
+
+gboolean 
+rspamd_recipients_distance (struct worker_task *task, GList *args)
+{
+       struct expression_argument *arg;
+       InternetAddressList *cur;
+       InternetAddress *addr;
+       double threshold;
+       struct addr_list *ar;
+       int num, i, j, hits = 0, total = 0;
+       
+       if (args == NULL) {
+               msg_warn ("rspamd_content_type_compare_param: no parameters to function");
+               return FALSE;
+       }
+       
+       arg = args->data;
+       threshold = strtod ((char *)arg->data, NULL);
+
+       num = internet_address_list_length (task->rcpts);
+       if (num < MIN_RCPT_TO_COMPARE) {
+               return FALSE;
+       }
+       ar = memory_pool_alloc (task->task_pool, num * sizeof (struct addr_list));
+
+       /* Fill array */
+       cur = task->rcpts;
+       i = 0;
+       while (cur) {
+               addr = internet_address_list_get_address (cur);
+               ar[i].name = internet_address_get_name (addr);
+               ar[i].addr = internet_address_get_addr (addr);
+               cur = internet_address_list_next (cur);
+       }
+
+       /* Cycle all elements in array */
+       for (i = 0; i < num; i ++) {
+               for (j = i + 1; j < num; j ++) {
+                       if (g_ascii_strncasecmp (ar[i].name, ar[j].name, COMPARE_RCPT_LEN) == 0) {
+                               hits ++;
+                       }
+                       if (g_ascii_strcasecmp (ar[i].addr, ar[j].addr) == 0) {
+                               hits ++;
+                       }
+                       total ++;
+               }
+       }
+
+       if ((double)total / (double)hits >= threshold) {
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+gboolean 
+rspamd_has_only_html_part (struct worker_task *task, GList *args)
+{
+       struct mime_text_part *p;
+       GList *cur;
+       gboolean res = FALSE;
+
+       cur = g_list_first (task->text_parts);
+       while (cur) {
+               p = cur->data;
+               if (p->is_html) {
+                       res = TRUE;
+               }
+               else {
+                       res = FALSE;
+                       break;
+               }
+               cur = g_list_next (cur);
+       }
+
+       return res;
+}
+
+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};
+       
+       /* Do not check to short address lists */
+       if (internet_address_list_length (ia) < MIN_RCPT_TO_COMPARE) {
+               return FALSE;
+       }
+
+       cur = ia;
+       while (cur) {
+               addr = internet_address_list_get_address (cur);
+               current.name = internet_address_get_name (addr);
+               current.addr = internet_address_get_addr (addr);
+               if (previous.name != NULL) {
+                       if (g_ascii_strcasecmp (current.name, previous.name) < 0) {
+                               res = FALSE;
+                               break;
+                       }
+                       if (g_ascii_strcasecmp (current.addr, previous.addr) < 0) {
+                               res = FALSE;
+                               break;
+                       }
+               }
+               previous.name = current.name;
+               previous.addr = current.addr;
+               cur = internet_address_list_next (cur);
+       }
+
+       return res;
+}
+
+gboolean
+rspamd_is_recipients_sorted (struct worker_task *task, GList *args)
+{
+       /* Check all types of addresses */
+       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) {
+               return TRUE;
+       }
+       if (is_recipient_list_sorted (g_mime_message_get_recipients (task->message, GMIME_RECIPIENT_TYPE_CC)) == TRUE) {
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
 /*
  * vi:ts=4
  */
index ecd1af64ff01bc661fe78b8b4e9907cf46dd8486..a53ed929de4a1a3a2203b304d364c7ee91a1858e 100644 (file)
@@ -107,7 +107,7 @@ fuzzy_update (fuzzy_hash_t *h, char c)
  *
  * Replace cost is normally 1, and 2 with nonzero xcost.
  */
-static uint32_t
+uint32_t
 lev_distance (char *s1, int len1, char *s2, int len2)
 {      
        int i;
index 50d1a9110e3df7a09a84ae17a59847b6409f11d1..4895e6c53179c76d2ddc1b88afb3db8cc9964e31 100644 (file)
@@ -37,5 +37,7 @@ fuzzy_hash_t * fuzzy_init_byte_array (GByteArray *in, memory_pool_t *pool);
  */
 int fuzzy_compare_hashes (fuzzy_hash_t *h1, fuzzy_hash_t *h2);
 
+uint32_t lev_distance (char *s1, int len1, char *s2, int len2);
+
 
 #endif
index 431ed8f4b33d34481ad910063cdfa061fcbbdc0f..ab785fa5a647f348b23259e558234110e8fd55d5 100644 (file)
@@ -173,6 +173,7 @@ struct worker_task {
        memcached_ctx_t *memc_ctx;                                                                      /**< memcached context associated with task                     */
        int parts_count;                                                                                        /**< mime parts count                                                           */
        GMimeMessage *message;                                                                          /**< message, parsed with GMime                                         */
+       InternetAddressList *rcpts;                                                                     /**< list of all recipients                                             */
        GList *parts;                                                                                           /**< list of parsed parts                                                       */
        GList *text_parts;                                                                                      /**< list of text parts                                                         */
        char *raw_headers;                                                                                      /**< list of raw headers                                                        */
index c35659366e3a381c1bb16b5e91729c9f22515a82..156bd18292645702a629b1edb163880a22381074 100644 (file)
@@ -406,6 +406,11 @@ process_message (struct worker_task *task)
                memory_pool_add_destructor (task->task_pool, (pool_destruct_func)g_free, task->raw_headers);
        }
 
+       task->rcpts = g_mime_message_get_all_recipients (message);
+       if (task->rcpts) {
+               memory_pool_add_destructor (task->task_pool, (pool_destruct_func)internet_address_list_destroy, task->rcpts);
+       }
+
        task->worker->srv->stat->messages_scanned ++;
 
        /* free the parser (and the stream) */