[evolution-data-server] Bug 768258 - Decode headers before passing to regex comparison



commit dcdf58b094b0028adbd5e0c1fe7c81f7bc7227db
Author: Milan Crha <mcrha redhat com>
Date:   Fri Jul 1 10:45:51 2016 +0200

    Bug 768258 - Decode headers before passing to regex comparison

 camel/camel-filter-search.c  |   41 ++---------
 camel/camel-folder-search.c  |   90 ++----------------------
 camel/camel-search-private.c |  157 ++++++++++++++++++++++++++++++++++++++++++
 camel/camel-search-private.h |    9 +++
 4 files changed, 181 insertions(+), 116 deletions(-)
---
diff --git a/camel/camel-filter-search.c b/camel/camel-filter-search.c
index 8b436f9..06173ad 100644
--- a/camel/camel-filter-search.c
+++ b/camel/camel-filter-search.c
@@ -259,8 +259,7 @@ check_header (struct _CamelSExp *f,
                        message = camel_filter_search_get_message (fms, f);
                        mime_part = CAMEL_MIME_PART (message);
 
-                       /* FIXME: what about Resent-To, Resent-Cc and Resent-From? */
-                       if (g_ascii_strcasecmp ("to", name) == 0 || g_ascii_strcasecmp ("cc", name) == 0 || 
g_ascii_strcasecmp ("from", name) == 0)
+                       if (camel_search_header_is_address (name))
                                type = CAMEL_SEARCH_TYPE_ADDRESS_ENCODED;
                        else if (message) {
                                ct = camel_mime_part_get_content_type (mime_part);
@@ -375,47 +374,23 @@ header_regex (struct _CamelSExp *f,
        CamelSExpResult *r = camel_sexp_result_new (f, CAMEL_SEXP_RES_BOOL);
        CamelMimeMessage *message;
        regex_t pattern;
-       const gchar *contents;
+       gchar *contents = NULL;
 
        message = camel_filter_search_get_message (fms, f);
 
        if (argc > 1 && argv[0]->type == CAMEL_SEXP_RES_STRING
-           && (contents = camel_medium_get_header (CAMEL_MEDIUM (message), argv[0]->value.string))
+           && (contents = camel_search_get_header_decoded (argv[0]->value.string,
+                   camel_medium_get_header (CAMEL_MEDIUM (message), argv[0]->value.string),
+                   camel_search_get_default_charset_from_message (message)))
            && camel_search_build_match_regex (&pattern, CAMEL_SEARCH_MATCH_REGEX | CAMEL_SEARCH_MATCH_ICASE, 
argc - 1, argv + 1, fms->error) == 0) {
                r->value.boolean = regexec (&pattern, contents, 0, NULL, 0) == 0;
                regfree (&pattern);
        } else
                r->value.boolean = FALSE;
 
-       return r;
-}
-
-static gchar *
-get_full_header (CamelMimeMessage *message)
-{
-       CamelMimePart *mime_part;
-       GString *str = g_string_new ("");
-       gchar   *ret;
-       struct _camel_header_raw *h;
-
-       mime_part = CAMEL_MIME_PART (message);
-
-       for (h = mime_part->headers; h; h = h->next) {
-               if (h->value != NULL) {
-                       g_string_append (str, h->name);
-                       if (isspace (h->value[0]))
-                               g_string_append (str, ":");
-                       else
-                               g_string_append (str, ": ");
-                       g_string_append (str, h->value);
-                       g_string_append_c (str, '\n');
-               }
-       }
+       g_free (contents);
 
-       ret = str->str;
-       g_string_free (str, FALSE);
-
-       return ret;
+       return r;
 }
 
 static CamelSExpResult *
@@ -432,7 +407,7 @@ header_full_regex (struct _CamelSExp *f,
        if (camel_search_build_match_regex (&pattern, CAMEL_SEARCH_MATCH_REGEX | CAMEL_SEARCH_MATCH_ICASE | 
CAMEL_SEARCH_MATCH_NEWLINE,
                                           argc, argv, fms->error) == 0) {
                message = camel_filter_search_get_message (fms, f);
-               contents = get_full_header (message);
+               contents = camel_search_get_all_headers_decoded (message);
                r->value.boolean = regexec (&pattern, contents, 0, NULL, 0) == 0;
                g_free (contents);
                regfree (&pattern);
diff --git a/camel/camel-folder-search.c b/camel/camel-folder-search.c
index 6cfe5d1..abf4a34 100644
--- a/camel/camel-folder-search.c
+++ b/camel/camel-folder-search.c
@@ -625,76 +625,6 @@ match_words_messages (CamelFolderSearch *search,
        return matches;
 }
 
-static const gchar *
-get_default_charset (CamelMimeMessage *msg)
-{
-       CamelContentType *ct;
-       const gchar *charset;
-
-       g_return_val_if_fail (msg != NULL, NULL);
-
-       ct = camel_mime_part_get_content_type (CAMEL_MIME_PART (msg));
-       charset = camel_content_type_param (ct, "charset");
-       if (!charset)
-               charset = "utf-8";
-
-       charset = camel_iconv_charset_name (charset);
-
-       return charset;
-}
-
-static gchar *
-get_header_decoded (const gchar *header_value,
-                    const gchar *default_charset)
-{
-       gchar *unfold, *decoded;
-
-       if (!header_value || !*header_value)
-               return NULL;
-
-       unfold = camel_header_unfold (header_value);
-       decoded = camel_header_decode_string (unfold, default_charset);
-       g_free (unfold);
-
-       return decoded;
-}
-
-static gchar *
-get_full_header (CamelMimeMessage *message,
-                 const gchar *default_charset)
-{
-       CamelMimePart *mp = CAMEL_MIME_PART (message);
-       GString *str = g_string_new ("");
-       struct _camel_header_raw *h;
-
-       for (h = mp->headers; h; h = h->next) {
-               if (h->value != NULL) {
-                       g_string_append (str, h->name);
-                       if (isspace (h->value[0]))
-                               g_string_append (str, ":");
-                       else
-                               g_string_append (str, ": ");
-                       if (g_ascii_strcasecmp (h->name, "From") == 0 ||
-                           g_ascii_strcasecmp (h->name, "To") == 0 ||
-                           g_ascii_strcasecmp (h->name, "CC") == 0 ||
-                           g_ascii_strcasecmp (h->name, "BCC") == 0 ||
-                           g_ascii_strcasecmp (h->name, "Subject") == 0) {
-                               gchar *decoded = get_header_decoded (h->value, default_charset);
-                               if (decoded)
-                                       g_string_append (str, decoded);
-                               else
-                                       g_string_append (str, h->value);
-                               g_free (decoded);
-                       } else {
-                               g_string_append (str, h->value);
-                       }
-                       g_string_append_c (str, '\n');
-               }
-       }
-
-       return g_string_free (str, FALSE);
-}
-
 static gint
 read_uid_callback (gpointer ref,
                    gint ncol,
@@ -1342,18 +1272,12 @@ folder_search_header_regex (CamelSExp *sexp,
                                CAMEL_SEARCH_MATCH_ICASE,
                                argc - 1, argv + 1,
                                search->priv->error) == 0) {
-                       gchar *decoded = NULL;
-                       const gchar *hader_name = argv[0]->value.string;
-
-                       if (g_ascii_strcasecmp (hader_name, "From") == 0 ||
-                           g_ascii_strcasecmp (hader_name, "To") == 0 ||
-                           g_ascii_strcasecmp (hader_name, "CC") == 0 ||
-                           g_ascii_strcasecmp (hader_name, "BCC") == 0 ||
-                           g_ascii_strcasecmp (hader_name, "Subject") == 0) {
-                               decoded = get_header_decoded (contents, get_default_charset (msg));
-                               if (decoded)
-                                       contents = decoded;
-                       }
+                       gchar *decoded;
+                       const gchar *header_name = argv[0]->value.string;
+
+                       decoded = camel_search_get_header_decoded (header_name, contents, 
camel_search_get_default_charset_from_message (msg));
+                       if (decoded)
+                               contents = decoded;
 
                        r->value.boolean = regexec (&pattern, contents, 0, NULL, 0) == 0;
                        regfree (&pattern);
@@ -1396,7 +1320,7 @@ folder_search_header_full_regex (CamelSExp *sexp,
                                search->priv->error) == 0) {
                        gchar *contents;
 
-                       contents = get_full_header (msg, get_default_charset (msg));
+                       contents = camel_search_get_all_headers_decoded (msg);
                        r->value.boolean = regexec (&pattern, contents, 0, NULL, 0) == 0;
 
                        g_free (contents);
diff --git a/camel/camel-search-private.c b/camel/camel-search-private.c
index 0126ef3..d68d86f 100644
--- a/camel/camel-search-private.c
+++ b/camel/camel-search-private.c
@@ -717,3 +717,160 @@ camel_search_words_free (struct _camel_search_words *words)
        g_free (words);
 }
 
+/**
+ * camel_search_header_is_address:
+ * @header_name: A header name, like "Subject"
+ *
+ * Returns: Whether the @header_name is a header with a mail address
+ *
+ * Since: 3.22
+ **/
+gboolean
+camel_search_header_is_address (const gchar *header_name)
+{
+       const gchar *headers[] = {
+               "Reply-To",
+               "From",
+               "To",
+               "Cc",
+               "Bcc",
+               "Resent-From",
+               "Resent-To",
+               "Resent-Cc",
+               "Resent-Bcc",
+               NULL };
+       gint ii;
+
+       if (!header_name || !*header_name)
+               return FALSE;
+
+       for (ii = 0; headers[ii]; ii++) {
+               if (g_ascii_strcasecmp (headers[ii], header_name) == 0)
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+/**
+ * camel_search_get_default_charset_from_message:
+ * @message: a #CamelMimeMessage
+ *
+ * Returns: Default charset of the @message; if none cannot be determined,
+ *    UTF-8 is returned.
+ *
+ * Since: 3.22
+ **/
+const gchar *
+camel_search_get_default_charset_from_message (CamelMimeMessage *message)
+{
+       CamelContentType *ct;
+       const gchar *charset;
+
+       g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+
+       ct = camel_mime_part_get_content_type (CAMEL_MIME_PART (message));
+       charset = camel_content_type_param (ct, "charset");
+       if (!charset)
+               charset = "utf-8";
+
+       charset = camel_iconv_charset_name (charset);
+
+       return charset;
+}
+
+/**
+ * camel_search_get_header_decoded:
+ * @header_name: the header name
+ * @header_value: the header value
+ * @default_charset: (nullable): the default charset to use for the decode, or %NULL
+ *
+ * Decodes @header_value, if needed, either from an address header
+ * or the Subject header. Other @header_name headers are returned
+ * as is.
+ *
+ * Returns: (transfer full): decoded header value, suitable for text comparison.
+ *    Free the returned pointer with g_free() when done with it.
+ *
+ * Since: 3.22
+ **/
+gchar *
+camel_search_get_header_decoded (const gchar *header_name,
+                                const gchar *header_value,
+                                const gchar *default_charset)
+{
+       gchar *unfold, *decoded;
+
+       if (!header_value || !*header_value)
+               return NULL;
+
+       unfold = camel_header_unfold (header_value);
+
+       if (g_ascii_strcasecmp (header_name, "Subject") == 0 ||
+           camel_search_header_is_address (header_name)) {
+               decoded = camel_header_decode_string (unfold, default_charset);
+       } else {
+               decoded = unfold;
+               unfold = NULL;
+       }
+
+       g_free (unfold);
+
+       return decoded;
+}
+
+/**
+ * camel_search_get_all_headers_decoded:
+ * @message: a #CamelMessage
+ *
+ * Returns: (transfer full): All headers of the @message, decoded where needed.
+ *    Free the returned pointer with g_free() when done with it.
+ *
+ * Since: 3.22
+ **/
+gchar *
+camel_search_get_all_headers_decoded (CamelMimeMessage *message)
+{
+       CamelMedium *medium;
+       GString *str;
+       GArray *headers;
+       const gchar *default_charset;
+       guint ii;
+
+       g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+
+       medium = CAMEL_MEDIUM (message);
+       headers = camel_medium_get_headers (medium);
+       if (!headers)
+               return NULL;
+
+       default_charset = camel_search_get_default_charset_from_message (message);
+       str = g_string_new ("");
+
+       for (ii = 0; ii < headers->len; ii++) {
+               CamelMediumHeader *header;
+               gchar *content;
+
+               header = &g_array_index (headers, CamelMediumHeader, ii);
+               if (!header->value)
+                       continue;
+
+               content = camel_search_get_header_decoded (header->name, header->value, default_charset);
+               if (!content)
+                       continue;
+
+               g_string_append (str, header->name);
+               if (isspace (content[0]))
+                       g_string_append (str, ":");
+               else
+                       g_string_append (str, ": ");
+               g_string_append (str, content);
+               g_string_append_c (str, '\n');
+
+               g_free (content);
+       }
+
+       camel_medium_free_headers (medium, headers);
+
+       return g_string_free (str, FALSE);
+}
diff --git a/camel/camel-search-private.h b/camel/camel-search-private.h
index 5256b6c..5fee6f7 100644
--- a/camel/camel-search-private.h
+++ b/camel/camel-search-private.h
@@ -100,6 +100,15 @@ struct _camel_search_words *
                camel_search_words_simple       (struct _camel_search_words *words);
 void           camel_search_words_free         (struct _camel_search_words *words);
 
+gboolean       camel_search_header_is_address  (const gchar *header_name);
+const gchar *  camel_search_get_default_charset_from_message
+                                               (CamelMimeMessage *message);
+gchar *                camel_search_get_header_decoded (const gchar *header_name,
+                                                const gchar *header_value,
+                                                const gchar *default_charset);
+gchar *                camel_search_get_all_headers_decoded
+                                               (CamelMimeMessage *message);
+
 G_END_DECLS
 
 #endif /* CAMEL_SEARCH_PRIVATE_H */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]