]> source.dussan.org Git - rspamd.git/commitdiff
Add headers folding routine.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 8 Sep 2015 12:41:48 +0000 (13:41 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 8 Sep 2015 12:41:48 +0000 (13:41 +0100)
src/client/rspamc.c
src/libutil/str_util.c
src/libutil/str_util.h

index 98ef61a48d5e4f7244b12020e518672c72d8de10..a3d67a8076e6de2f8ea23be9a7648580262a3678 100644 (file)
@@ -858,8 +858,10 @@ rspamc_mime_output (FILE *out, ucl_object_t *result, GString *input, GError *err
        GByteArray ar;
        GMimeParser *parser;
        GMimeMessage *message;
-       const ucl_object_t *metric, *res;
+       const ucl_object_t *cur, *metric, *res;
+       ucl_object_iter_t it = NULL;
        const gchar *action = "no action";
+       GString *symbuf;
        gint act;
        gdouble score = 0.0, required_score = 0.0;
        gchar scorebuf[32];
@@ -935,6 +937,26 @@ rspamc_mime_output (FILE *out, ucl_object_t *result, GString *input, GError *err
                g_mime_object_append_header (GMIME_OBJECT (message), "X-Spam-Level",
                                scorebuf);
 
+               /* Short description of all symbols */
+               symbuf = g_string_sized_new (64);
+
+               while ((cur = ucl_iterate_object (metric, &it, true)) != NULL) {
+
+                       if (ucl_object_type (cur) == UCL_OBJECT) {
+                               rspamd_printf_gstring (symbuf, "%s,", ucl_object_key (cur));
+                       }
+               }
+               /* Trim the last comma */
+               if (symbuf->str[symbuf->len - 1] == ',') {
+                       g_string_erase (symbuf, symbuf->len - 1, 1);
+               }
+
+               sc = g_mime_utils_header_encode_text (symbuf->str);
+               g_mime_object_append_header (GMIME_OBJECT (message), "X-Spam-Symbols",
+                               sc);
+               g_free (sc);
+               g_string_free (symbuf, TRUE);
+
                if (json || raw) {
                        /* We also append json data as a specific header */
                        if (json) {
index 75a200db59d4d1559b5e346cedc5c91d040a2bc7..844962c2510fab20977f7817ade4c4fa47893d84 100644 (file)
@@ -863,3 +863,167 @@ rspamd_strings_levenshtein_distance (const gchar *s1, gsize s1len,
 
        return column[s1len];
 }
+
+GString *
+rspamd_header_value_fold (const gchar *name, const gchar *value)
+{
+       GString *res;
+       const guint fold_max = 76;
+       guint cur_len;
+       const gchar *p, *c;
+       gboolean first_token = TRUE;
+       enum {
+               fold_before,
+               fold_after
+       } fold_type;
+       enum {
+               read_token,
+               read_quoted,
+               after_quote,
+               fold_token,
+       } state = read_token, next_state = read_token;
+
+       g_assert (name != NULL);
+       g_assert (value != NULL);
+
+       res = g_string_sized_new (strlen (value));
+
+       c = value;
+       p = c;
+       /* name:<WSP> */
+       cur_len = strlen (name) + 2;
+
+       while (*p) {
+               switch (state) {
+               case read_token:
+                       if (*p == ',' || *p == ';') {
+                               /* We have something similar to the token's end, so check len */
+                               if (cur_len > fold_max * 0.8 && cur_len < fold_max) {
+                                       /* We want fold */
+                                       fold_type = fold_after;
+                                       state = fold_token;
+                                       next_state = read_token;
+                               }
+                               else if (cur_len > fold_max && !first_token) {
+                                       fold_type = fold_before;
+                                       state = fold_token;
+                                       next_state = read_token;
+                               }
+                               else {
+                                       g_string_append_len (res, c, p - c);
+                                       c = p;
+                                       first_token = FALSE;
+                               }
+                               p ++;
+                       }
+                       else if (*p == '"') {
+                               /* Fold before quoted tokens */
+                               g_string_append_len (res, c, p - c);
+                               c = p;
+                               state = read_quoted;
+                       }
+                       else if (*p == '\r') {
+                               /* Reset line length */
+                               cur_len = 0;
+
+                               while (g_ascii_isspace (*p)) {
+                                       p ++;
+                               }
+
+                               g_string_append_len (res, c, p - c);
+                               c = p;
+                       }
+                       else if (g_ascii_isspace (*p)) {
+                               if (cur_len > fold_max * 0.8 && cur_len < fold_max) {
+                                       /* We want fold */
+                                       fold_type = fold_after;
+                                       state = fold_token;
+                                       next_state = read_token;
+                               }
+                               else if (cur_len > fold_max && !first_token) {
+                                       fold_type = fold_before;
+                                       state = fold_token;
+                                       next_state = read_token;
+                               }
+                               else {
+                                       g_string_append_len (res, c, p - c);
+                                       c = p;
+                                       first_token = FALSE;
+                                       p ++;
+                               }
+                       }
+                       else {
+                               p ++;
+                               cur_len ++;
+                       }
+                       break;
+               case fold_token:
+                       /* Here, we have token start at 'c' and token end at 'p' */
+                       if (fold_type == fold_after) {
+                               g_string_append_len (res, c, p - c);
+                               g_string_append_len (res, "\r\n\t", 3);
+
+                               /* Skip space if needed */
+                               if (g_ascii_isspace (*p)) {
+                                       p ++;
+                               }
+                       }
+                       else {
+                               /* Skip space if needed */
+                               if (g_ascii_isspace (*c)) {
+                                       c ++;
+                               }
+
+                               g_string_append_len (res, "\r\n\t", 3);
+                               g_string_append_len (res, c, p - c);
+                       }
+
+                       c = p;
+                       state = next_state;
+                       cur_len = 0;
+                       first_token = TRUE;
+                       break;
+
+               case read_quoted:
+                       if (p != c && *p == '"') {
+                               state = after_quote;
+                       }
+                       p ++;
+                       cur_len ++;
+                       break;
+
+               case after_quote:
+                       state = read_token;
+                       /* Skip one more character after the quote */
+                       p ++;
+                       cur_len ++;
+                       g_string_append_len (res, c, p - c);
+                       c = p;
+                       first_token = TRUE;
+                       break;
+               }
+       }
+
+       /* Last token */
+       switch (state) {
+       case read_token:
+               if (cur_len > fold_max && !first_token) {
+                       g_string_append_len (res, "\r\n\t", 3);
+                       g_string_append_len (res, c, p - c);
+               }
+               else {
+                       g_string_append_len (res, c, p - c);
+               }
+               break;
+       case read_quoted:
+       case after_quote:
+               g_string_append_len (res, c, p - c);
+               break;
+
+       default:
+               g_assert (p == c);
+               break;
+       }
+
+       return res;
+}
index f8d9dd4dcad5267b6b3109de5eda5f6a7818b11b..dcccc3d25bdddbd5f66a194fd4af9be5fdbbda3c 100644 (file)
@@ -162,4 +162,12 @@ gsize rspamd_decode_url (gchar *dst, const gchar *src, gsize size);
 gint rspamd_strings_levenshtein_distance (const gchar *s1, gsize s1len,
                const gchar *s2, gsize s2len);
 
+/**
+ * Fold header using rfc822 rules, return new GString from the previous one
+ * @param name name of header (used just for folding)
+ * @param value value of header
+ * @return new GString with the folded value
+ */
+GString * rspamd_header_value_fold (const gchar *name, const gchar *value);
+
 #endif /* SRC_LIBUTIL_STR_UTIL_H_ */