[balsa/58-filter-on-reception] Various: Improve flag-only filtering




commit 283fef8b7e55b35d7bcd6329cffb79bd031bd91c
Author: Peter Bloomfield <PeterBloomfield bellsouth net>
Date:   Fri Aug 20 15:44:06 2021 -0400

    Various: Improve flag-only filtering
    
    Make libbalsa_condition_is_flag_only() a clean test of the condition, with
    no message matching. Introduce libbalsa_condition_try_flag_match()
    which does message matching, with a return value that reports
    whether the match is valid, but not necessarily whether the condition is
    flag-only.
    
    modified:   libbalsa/filter.c
    modified:   libbalsa/filter.h
    modified:   libbalsa/mailbox.c
    modified:   libbalsa/mailbox_local.c

 libbalsa/filter.c        | 115 ++++++++++++++++++++++++++++++++++-------------
 libbalsa/filter.h        |   7 +--
 libbalsa/mailbox.c       |  22 ++++-----
 libbalsa/mailbox_local.c |   5 +--
 4 files changed, 99 insertions(+), 50 deletions(-)
---
diff --git a/libbalsa/filter.c b/libbalsa/filter.c
index 91ae2be81..7caa41eec 100644
--- a/libbalsa/filter.c
+++ b/libbalsa/filter.c
@@ -380,54 +380,107 @@ libbalsa_condition_can_match(LibBalsaCondition * cond,
     }
 }
 
-/* Check whether a condition looks only at flags; if it does, test
- * whether the given message's flags match it, and return the result in
- * *match; used by mailbox backends to decide when the full
- * LibBalsaMessage is needed. */
+/*
+ * libbalsa_condition_is_flag_only:
+ *
+ * Check whether a condition looks only at flags
+ */
 gboolean
-libbalsa_condition_is_flag_only(LibBalsaCondition * cond,
-                                LibBalsaMailbox * mailbox,
-                                guint msgno,
-                               gboolean * match)
+libbalsa_condition_is_flag_only(LibBalsaCondition * cond)
 {
     gboolean retval;
-    gboolean left_match, right_match;
+
+    g_return_val_if_fail(cond != NULL, FALSE);
 
     switch (cond->type) {
     case CONDITION_FLAG:
-        if (match)
-            *match =
-                libbalsa_mailbox_msgno_has_flags(mailbox, msgno,
-                                                 cond->match.flags, 0);
         retval = TRUE;
         break;
+
+    case CONDITION_AND:
+    case CONDITION_OR:
+        retval = (libbalsa_condition_is_flag_only(cond->match.andor.left) &&
+                  libbalsa_condition_is_flag_only(cond->match.andor.right));
+        break;
+
+    default:
+        retval = FALSE;
+    }
+
+    return retval;
+}
+
+/*
+ * libbalsa_condition_try_flag_match:
+ *
+ * Try to decide whether a message matches the given condition,
+ * using only the message flags.
+ *
+ * Returns TRUE if the result was returned in *match. Note that this does
+ * not necessarily mean that the condition is completely flag-only.
+ * A FALSE return means that the match could not be decided using only
+ * message flags. The full LibBalsaMessage will be needed to decide the
+ * match.
+ */
+gboolean
+libbalsa_condition_try_flag_match(LibBalsaCondition *cond,
+                                  LibBalsaMailbox   *mailbox,
+                                  guint              msgno,
+                                  gboolean          *match)
+{
+    gboolean retval;
+    gboolean tmp_match;
+
+    g_return_val_if_fail(cond != NULL, FALSE);
+    g_return_val_if_fail(LIBBALSA_IS_MAILBOX(mailbox), FALSE);
+    g_return_val_if_fail(msgno > 0 && msgno <= libbalsa_mailbox_total_messages(mailbox), FALSE);
+    g_return_val_if_fail(match != NULL, FALSE);
+
+    switch (cond->type) {
+    case CONDITION_FLAG:
+        *match = libbalsa_mailbox_msgno_has_flags(mailbox, msgno, cond->match.flags, 0);
+        retval = TRUE;
+        break;
+
     case CONDITION_AND:
         retval =
-            libbalsa_condition_is_flag_only(cond->match.andor.left,
-                                            mailbox, msgno,
-                                           match ? &left_match : NULL)
-            && libbalsa_condition_is_flag_only(cond->match.andor.right,
-                                               mailbox, msgno,
-                                               match ? &right_match : NULL);
-        if (retval && match)
-            *match = left_match && right_match;
+            libbalsa_condition_try_flag_match(cond->match.andor.left, mailbox, msgno, &tmp_match);
+
+        if (retval) {
+            if (tmp_match) {
+                /* Left match succeeds, must check right condition */
+                retval =
+                    libbalsa_condition_try_flag_match(cond->match.andor.right,
+                                                       mailbox, msgno, &tmp_match);
+            }
+            if (retval)
+                *match = tmp_match;
+        }
+
         break;
+
     case CONDITION_OR:
         retval =
-            libbalsa_condition_is_flag_only(cond->match.andor.left,
-                                            mailbox, msgno,
-                                           match ? &left_match : NULL)
-            && libbalsa_condition_is_flag_only(cond->match.andor.right,
-                                               mailbox, msgno,
-                                               match ? &right_match : NULL);
-        if (retval && match)
-            *match = left_match || right_match;
+            libbalsa_condition_try_flag_match(cond->match.andor.left, mailbox, msgno, &tmp_match);
+
+        if (retval) {
+            if (!tmp_match) {
+                /* Left match fails, must check right condition */
+                retval =
+                    libbalsa_condition_try_flag_match(cond->match.andor.right,
+                                                      mailbox, msgno, &tmp_match);
+            }
+            if (retval)
+                *match = tmp_match;
+        }
+
         break;
+
     default:
-        return FALSE;
+        retval = FALSE;
     }
 
-    if (retval && match && cond->negate)
+    if (retval && cond->negate)
         *match = !*match;
 
     return retval;
diff --git a/libbalsa/filter.h b/libbalsa/filter.h
index 120e4931b..cbd8186d1 100644
--- a/libbalsa/filter.h
+++ b/libbalsa/filter.h
@@ -278,9 +278,10 @@ void filter_perror(const gchar * s);
 /* Test */
 gboolean libbalsa_condition_can_match(LibBalsaCondition * cond,
                                      LibBalsaMessage * message);
-gboolean libbalsa_condition_is_flag_only(LibBalsaCondition * cond,
-                                         LibBalsaMailbox * mailbox,
-                                         guint msgno, gboolean * match);
+gboolean libbalsa_condition_is_flag_only(LibBalsaCondition * cond);
+gboolean libbalsa_condition_try_flag_match(LibBalsaCondition * cond,
+                                           LibBalsaMailbox * mailbox,
+                                           guint msgno, gboolean * match);
 
 /* Compatibility */
 LibBalsaCondition *libbalsa_condition_new_2_0(const gchar *
diff --git a/libbalsa/mailbox.c b/libbalsa/mailbox.c
index 9c13f774f..ad959795e 100644
--- a/libbalsa/mailbox.c
+++ b/libbalsa/mailbox.c
@@ -810,8 +810,8 @@ libbalsa_mailbox_changed(LibBalsaMailbox * mailbox)
 /* libbalsa_mailbox_message_match:
  * Tests if message with msgno matches the conditions cached in the
  * search_iter: this is used
-   by the search code. It is a "virtual method", indeed IMAP has a
-   special way to implement it for speed/bandwidth reasons
+ * by the search code. It is a "virtual method", indeed IMAP has a
+ * special way to implement it for speed/bandwidth reasons
  */
 
 static gboolean
@@ -822,13 +822,11 @@ lbm_message_match(LibBalsaMailbox           *mailbox,
     LibBalsaMailboxPrivate *priv = libbalsa_mailbox_get_instance_private(mailbox);
     gboolean match;
 
-    if (libbalsa_condition_is_flag_only(search_iter->condition,
-                                        mailbox, msgno, &match))
-        return match;
-
-    priv->must_cache_message = TRUE;
-    match = LIBBALSA_MAILBOX_GET_CLASS(mailbox)->message_match(mailbox, msgno, search_iter);
-    priv->must_cache_message = FALSE;
+    if (!libbalsa_condition_try_flag_match(search_iter->condition, mailbox, msgno, &match)) {
+        priv->must_cache_message = TRUE;
+        match = LIBBALSA_MAILBOX_GET_CLASS(mailbox)->message_match(mailbox, msgno, search_iter);
+        priv->must_cache_message = FALSE;
+    }
 
     return match;
 }
@@ -913,8 +911,7 @@ lbm_run_filters_on_reception_idle_cb(LibBalsaMailbox * mailbox)
         LibBalsaFilter *filter = lst->data;
 
         if (filter->condition
-            && !libbalsa_condition_is_flag_only(filter->condition, NULL, 0,
-                                                NULL))
+            && !libbalsa_condition_is_flag_only(filter->condition))
             ++progress_count;
     }
 
@@ -936,8 +933,7 @@ lbm_run_filters_on_reception_idle_cb(LibBalsaMailbox * mailbox)
         if (filter->condition == NULL)
             continue;
 
-        use_progress = !libbalsa_condition_is_flag_only(filter->condition,
-                                                        NULL, 0, NULL);
+        use_progress = !libbalsa_condition_is_flag_only(filter->condition);
 
         search_iter = libbalsa_mailbox_search_iter_new(filter->condition);
 
diff --git a/libbalsa/mailbox_local.c b/libbalsa/mailbox_local.c
index f16959bf1..6be46e760 100644
--- a/libbalsa/mailbox_local.c
+++ b/libbalsa/mailbox_local.c
@@ -366,8 +366,7 @@ libbalsa_mailbox_local_load_message(LibBalsaMailboxLocal * local,
     view_filter = libbalsa_mailbox_get_view_filter(mailbox, FALSE);
     if (view_filter == NULL)
         match = TRUE;
-    else if (!libbalsa_condition_is_flag_only(view_filter,
-                                              mailbox, msgno, &match))
+    else if (!libbalsa_condition_try_flag_match(view_filter, mailbox, msgno, &match))
         match = message_match_real(mailbox, msgno, view_filter);
 
     if (match)
@@ -1290,7 +1289,7 @@ lbm_local_update_view_filter(LibBalsaMailbox * mailbox,
 
     total = libbalsa_mailbox_total_messages(mailbox);
     if (view_filter
-        && !libbalsa_condition_is_flag_only(view_filter, NULL, 0, NULL)) {
+        && !libbalsa_condition_is_flag_only(view_filter)) {
         gchar *text;
 
         text = g_strdup_printf(_("Filtering %s"), libbalsa_mailbox_get_name(mailbox));


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