Blob Blame History Raw
From fb5dfe31f4985cf3b42eba899fd71f3cf2d256bf Mon Sep 17 00:00:00 2001
From: Milan Crha <mcrha@redhat.com>
Date: Thu, 11 Jun 2020 19:06:29 +0200
Subject: [PATCH 4/5] I#982 - 'Message contains'-search broken in 3.36.3

Closes https://gitlab.gnome.org/GNOME/evolution/-/issues/982
---
 src/e-util/e-filter-rule.c           | 111 +++++++++++++++++++++++----
 src/mail/message-list.c              |  18 ++---
 src/mail/searchtypes.xml.in          |   8 +-
 src/modules/mail/e-mail-shell-view.c |   2 +-
 4 files changed, 107 insertions(+), 32 deletions(-)

diff --git a/src/e-util/e-filter-rule.c b/src/e-util/e-filter-rule.c
index 2ec1d8dfc1..72bfc6af5e 100644
--- a/src/e-util/e-filter-rule.c
+++ b/src/e-util/e-filter-rule.c
@@ -811,9 +811,16 @@ filter_rule_xml_decode (EFilterRule *rule,
 }
 
 static void
-filter_rule_build_code (EFilterRule *rule,
-                        GString *out)
+filter_rule_build_code_for_parts (EFilterRule *rule,
+				  GList *parts,
+				  gboolean without_match_all,
+				  gboolean force_match_all,
+				  GString *out)
 {
+	g_return_if_fail (rule != NULL);
+	g_return_if_fail (parts != NULL);
+	g_return_if_fail (out != NULL);
+
 	switch (rule->threading) {
 	case E_FILTER_THREAD_NONE:
 		break;
@@ -831,25 +838,97 @@ filter_rule_build_code (EFilterRule *rule,
 		break;
 	}
 
-	if (rule->threading != E_FILTER_THREAD_NONE)
+	if ((rule->threading != E_FILTER_THREAD_NONE && !without_match_all) || force_match_all)
 		g_string_append (out, "(match-all ");
 
-	switch (rule->grouping) {
-	case E_FILTER_GROUP_ALL:
-		g_string_append (out, " (and\n  ");
-		break;
-	case E_FILTER_GROUP_ANY:
-		g_string_append (out, " (or\n  ");
-		break;
-	default:
-		g_warning ("Invalid grouping");
+	if (parts->next) {
+		switch (rule->grouping) {
+		case E_FILTER_GROUP_ALL:
+			g_string_append (out, " (and\n  ");
+			break;
+		case E_FILTER_GROUP_ANY:
+			g_string_append (out, " (or\n  ");
+			break;
+		default:
+			g_warning ("Invalid grouping");
+		}
+	}
+
+	e_filter_part_build_code_list (parts, out);
+
+	if (parts->next)
+		g_string_append (out, ")\n");
+
+	if (rule->threading != E_FILTER_THREAD_NONE) {
+		if (without_match_all && !force_match_all)
+			g_string_append (out, ")\n");
+		else
+			g_string_append (out, "))\n");
+	} else if (force_match_all) {
+		g_string_append (out, ")\n");
+	}
+}
+
+static void
+filter_rule_build_code (EFilterRule *rule,
+                        GString *out)
+{
+	GList *link;
+	gboolean has_body_search = FALSE;
+
+	if (!rule->parts)
+		return;
+
+	for (link = rule->parts; link && !has_body_search; link = g_list_next (link)) {
+		EFilterPart *part = link->data;
+
+		has_body_search = g_strcmp0 (part->name, "body") == 0;
 	}
 
-	e_filter_part_build_code_list (rule->parts, out);
-	g_string_append (out, ")\n");
+	if (has_body_search) {
+		GList *body_searches = NULL, *other_searches = NULL;
 
-	if (rule->threading != E_FILTER_THREAD_NONE)
-		g_string_append (out, "))\n");
+		for (link = rule->parts; link; link = g_list_next (link)) {
+			EFilterPart *part = link->data;
+
+			if (g_strcmp0 (part->name, "body") == 0) {
+				body_searches = g_list_prepend (body_searches, part);
+			} else {
+				other_searches = g_list_prepend (other_searches, part);
+			}
+		}
+
+		if (other_searches && body_searches) {
+			switch (rule->grouping) {
+			case E_FILTER_GROUP_ALL:
+				g_string_append (out, "(and ");
+				break;
+			case E_FILTER_GROUP_ANY:
+				g_string_append (out, "(or ");
+				break;
+			default:
+				g_warning ("Invalid grouping");
+			}
+
+			body_searches = g_list_reverse (body_searches);
+			other_searches = g_list_reverse (other_searches);
+
+			filter_rule_build_code_for_parts (rule, other_searches, FALSE, TRUE, out);
+
+			g_string_append_c (out, ' ');
+
+			filter_rule_build_code_for_parts (rule, body_searches, TRUE, FALSE, out);
+
+			g_string_append_c (out, ')');
+		} else {
+			filter_rule_build_code_for_parts (rule, rule->parts, FALSE, FALSE, out);
+		}
+
+		g_list_free (body_searches);
+		g_list_free (other_searches);
+	} else {
+		filter_rule_build_code_for_parts (rule, rule->parts, FALSE, FALSE, out);
+	}
 }
 
 static void
diff --git a/src/mail/message-list.c b/src/mail/message-list.c
index 01b7528850..2c5741a139 100644
--- a/src/mail/message-list.c
+++ b/src/mail/message-list.c
@@ -6176,7 +6176,7 @@ message_list_regen_thread (GSimpleAsyncResult *simple,
 	/* The 'expr' should be enclosed in "(match-all ...)", thus the search traverses
 	   folder content, but also try to not repeat it, to avoid unnecessary performance hits. */
 	if (regen_data->search != NULL) {
-		gboolean is_match_all = g_str_has_prefix (regen_data->search, "(match-all ");
+		gboolean is_match_all = g_str_has_prefix (regen_data->search, "(match-all ") && !strstr (regen_data->search, "(body-contains ");
 		gboolean is_match_threads = strstr (regen_data->search, "(match-threads ") != NULL;
 
 		if (expr->len == 0) {
@@ -6186,25 +6186,21 @@ message_list_regen_thread (GSimpleAsyncResult *simple,
 				g_string_prepend (expr, "(match-all ");
 				g_string_append_c (expr, ')');
 			}
-		} else if (is_match_threads) {
+		} else if (is_match_threads || !is_match_all) {
 			/* The "match-threads" cannot be below "match-all". */
 			g_string_prepend (expr, "(and (match-all ");
 			g_string_append (expr, ") ");
 			g_string_append (expr, regen_data->search);
 			g_string_append_c (expr, ')');
 		} else {
+			const gchar *stripped_search = regen_data->search + 11; /* strlen ("(match-all ") */
+			gint len = strlen (stripped_search);
+
 			g_string_prepend (expr, "(match-all (and ");
 			g_string_append_c (expr, ' ');
 
-			if (is_match_all) {
-				const gchar *stripped_search = regen_data->search + 11; /* strlen ("(match-all ") */
-				gint len = strlen (stripped_search);
-
-				if (len > 0 && stripped_search[len - 1] == ')') {
-					g_string_append_len (expr, stripped_search, len - 1);
-				} else {
-					g_string_append (expr, regen_data->search);
-				}
+			if (len > 0 && stripped_search[len - 1] == ')') {
+				g_string_append_len (expr, stripped_search, len - 1);
 			} else {
 				g_string_append (expr, regen_data->search);
 			}
diff --git a/src/mail/searchtypes.xml.in b/src/mail/searchtypes.xml.in
index e03e28e60f..d0362d59dd 100644
--- a/src/mail/searchtypes.xml.in
+++ b/src/mail/searchtypes.xml.in
@@ -728,10 +728,6 @@
           <value name="subject-type" type="option" value="contains"/>
           <value name="subject" type="string"/>
         </part>
-        <part name="body">
-          <value name="body-type" type="option" value="contains"/>
-          <value name="word" type="string"/>
-        </part>
         <part name="sender">
           <value name="sender-type" type="option" value="contains"/>
           <value name="sender" type="string"/>
@@ -740,6 +736,10 @@
           <value name="recipient-type" type="option" value="contains"/>
           <value name="recipient" type="address"/>
         </part>
+        <part name="body">
+          <value name="body-type" type="option" value="contains"/>
+          <value name="word" type="string"/>
+        </part>
       </partset>
       <sources/>
     </rule>
diff --git a/src/modules/mail/e-mail-shell-view.c b/src/modules/mail/e-mail-shell-view.c
index 8dcca65eca..be72de3441 100644
--- a/src/modules/mail/e-mail-shell-view.c
+++ b/src/modules/mail/e-mail-shell-view.c
@@ -752,7 +752,7 @@ filter:
 
 	/* Apply selected filter. */
 
-	if (query && *query && !g_str_has_prefix (query, "(match-all ") && !strstr (query, "(match-threads ")) {
+	if (query && *query && !strstr (query, "(match-all ") && !strstr (query, "(match-threads ")) {
 		/* Make sure the query is enclosed in "(match-all ...)", to traverse the folders' content */
 		temp = g_strconcat ("(match-all ", query, ")", NULL);
 		g_free (query);
-- 
2.27.0