[evolution-data-server] [IMAPx] Be able to search server with text with umlauts/UTF-8 letters



commit 5e5a4e6d471a3556b4d76a1228e6b4634f98b71b
Author: Milan Crha <mcrha redhat com>
Date:   Mon Aug 10 18:37:01 2015 +0200

    [IMAPx] Be able to search server with text with umlauts/UTF-8 letters

 camel/providers/imapx/camel-imapx-conn-manager.c |   93 +++++++++++++--
 camel/providers/imapx/camel-imapx-conn-manager.h |    4 +-
 camel/providers/imapx/camel-imapx-search.c       |  144 +++++++++++----------
 camel/providers/imapx/camel-imapx-server.c       |   24 +++-
 camel/providers/imapx/camel-imapx-server.h       |    4 +-
 camel/providers/imapx/camel-imapx-utils.c        |   15 +++
 camel/providers/imapx/camel-imapx-utils.h        |    2 +
 7 files changed, 202 insertions(+), 84 deletions(-)
---
diff --git a/camel/providers/imapx/camel-imapx-conn-manager.c 
b/camel/providers/imapx/camel-imapx-conn-manager.c
index eb20aa3..9aea32c 100644
--- a/camel/providers/imapx/camel-imapx-conn-manager.c
+++ b/camel/providers/imapx/camel-imapx-conn-manager.c
@@ -1954,14 +1954,73 @@ camel_imapx_conn_manager_update_quota_info_sync (CamelIMAPXConnManager *conn_man
        return success;
 }
 
+static gchar **
+imapx_copy_strv (const gchar * const *words)
+{
+       gchar **copy;
+       gint ii;
+
+       if (!words || !*words)
+               return NULL;
+
+       copy = g_new0 (gchar *, g_strv_length ((gchar **) words) + 1);
+
+       for (ii = 0; words[ii]; ii++) {
+               copy[ii] = g_strdup (words[ii]);
+       }
+
+       copy[ii] = NULL;
+
+       return copy;
+}
+
+static gboolean
+imapx_equal_strv (const gchar * const *words1,
+                 const gchar * const *words2)
+{
+       gint ii;
+
+       if (words1 == words2)
+               return TRUE;
+
+       if (!words1 || !words2)
+               return FALSE;
+
+       for (ii = 0; words1[ii] && words2[ii]; ii++) {
+               if (g_strcmp0 (words1[ii], words2[ii]) != 0)
+                       return FALSE;
+       }
+
+       return !words1[ii] && !words2[ii];
+}
+
+struct UidSearchJobData {
+       gchar *criteria_prefix;
+       gchar *search_key;
+       gchar **words;
+};
+
+static void
+uid_search_job_data_free (gpointer ptr)
+{
+       struct UidSearchJobData *job_data = ptr;
+
+       if (ptr) {
+               g_free (job_data->criteria_prefix);
+               g_free (job_data->search_key);
+               g_strfreev (job_data->words);
+               g_free (job_data);
+       }
+}
+
 static gboolean
 imapx_conn_manager_uid_search_run_sync (CamelIMAPXJob *job,
                                        CamelIMAPXServer *server,
                                        GCancellable *cancellable,
                                        GError **error)
 {
+       struct UidSearchJobData *job_data;
        CamelIMAPXMailbox *mailbox;
-       const gchar *criteria;
        GPtrArray *uids = NULL;
        GError *local_error = NULL;
 
@@ -1971,10 +2030,11 @@ imapx_conn_manager_uid_search_run_sync (CamelIMAPXJob *job,
        mailbox = camel_imapx_job_get_mailbox (job);
        g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
 
-       criteria = camel_imapx_job_get_user_data (job);
-       g_return_val_if_fail (criteria != NULL, FALSE);
+       job_data = camel_imapx_job_get_user_data (job);
+       g_return_val_if_fail (job_data != NULL, FALSE);
 
-       uids = camel_imapx_server_uid_search_sync (server, mailbox, criteria, cancellable, &local_error);
+       uids = camel_imapx_server_uid_search_sync (server, mailbox, job_data->criteria_prefix,
+               job_data->search_key, (const gchar * const *) job_data->words, cancellable, &local_error);
 
        camel_imapx_job_set_result (job, uids != NULL, uids, local_error, uids ? (GDestroyNotify) 
g_ptr_array_free : NULL);
 
@@ -1988,7 +2048,7 @@ static gboolean
 imapx_conn_manager_uid_search_matches (CamelIMAPXJob *job,
                                       CamelIMAPXJob *other_job)
 {
-       const gchar *job_criteria, *other_job_criteria;
+       struct UidSearchJobData *job_data, *other_job_data;
 
        g_return_val_if_fail (job != NULL, FALSE);
        g_return_val_if_fail (other_job != NULL, FALSE);
@@ -1997,31 +2057,44 @@ imapx_conn_manager_uid_search_matches (CamelIMAPXJob *job,
            camel_imapx_job_get_kind (job) != camel_imapx_job_get_kind (other_job))
                return FALSE;
 
-       job_criteria = camel_imapx_job_get_user_data (job);
-       other_job_criteria = camel_imapx_job_get_user_data (other_job);
+       job_data = camel_imapx_job_get_user_data (job);
+       other_job_data = camel_imapx_job_get_user_data (other_job);
+
+       if (!job_data || !other_job_data)
+               return job_data == other_job_data;
 
-       return g_strcmp0 (job_criteria, other_job_criteria) == 0;
+       return g_strcmp0 (job_data->criteria_prefix, other_job_data->criteria_prefix) == 0 &&
+              g_strcmp0 (job_data->search_key, other_job_data->search_key) == 0 &&
+              imapx_equal_strv ((const gchar * const  *) job_data->words, (const gchar * const  *) 
other_job_data->words);
 }
 
 GPtrArray *
 camel_imapx_conn_manager_uid_search_sync (CamelIMAPXConnManager *conn_man,
                                          CamelIMAPXMailbox *mailbox,
-                                         const gchar *criteria,
+                                         const gchar *criteria_prefix,
+                                         const gchar *search_key,
+                                         const gchar * const *words,
                                          GCancellable *cancellable,
                                          GError **error)
 {
+       struct UidSearchJobData *job_data;
        GPtrArray *uids = NULL;
        CamelIMAPXJob *job;
        gboolean success;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
 
+       job_data = g_new0 (struct UidSearchJobData, 1);
+       job_data->criteria_prefix = g_strdup (criteria_prefix);
+       job_data->search_key = g_strdup (search_key);
+       job_data->words = imapx_copy_strv (words);
+
        job = camel_imapx_job_new (CAMEL_IMAPX_JOB_UID_SEARCH, mailbox,
                imapx_conn_manager_uid_search_run_sync,
                imapx_conn_manager_uid_search_matches,
                NULL);
 
-       camel_imapx_job_set_user_data (job, g_strdup (criteria), g_free);
+       camel_imapx_job_set_user_data (job, job_data, uid_search_job_data_free);
 
        success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
        if (success) {
diff --git a/camel/providers/imapx/camel-imapx-conn-manager.h 
b/camel/providers/imapx/camel-imapx-conn-manager.h
index 3fc5beb..f0edd54 100644
--- a/camel/providers/imapx/camel-imapx-conn-manager.h
+++ b/camel/providers/imapx/camel-imapx-conn-manager.h
@@ -176,7 +176,9 @@ gboolean    camel_imapx_conn_manager_update_quota_info_sync
 GPtrArray *    camel_imapx_conn_manager_uid_search_sync
                                                (CamelIMAPXConnManager *conn_man,
                                                 CamelIMAPXMailbox *mailbox,
-                                                const gchar *criteria,
+                                                const gchar *criteria_prefix,
+                                                const gchar *search_key,
+                                                const gchar * const *words,
                                                 GCancellable *cancellable,
                                                 GError **error);
 
diff --git a/camel/providers/imapx/camel-imapx-search.c b/camel/providers/imapx/camel-imapx-search.c
index b1359f0..edf9929 100644
--- a/camel/providers/imapx/camel-imapx-search.c
+++ b/camel/providers/imapx/camel-imapx-search.c
@@ -15,8 +15,13 @@
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include "camel-imapx-search.h"
 
+#include <string.h>
 #include <camel/camel.h>
 #include <camel/camel-search-private.h>
 
@@ -154,7 +159,9 @@ static CamelSExpResult *
 imapx_search_process_criteria (CamelSExp *sexp,
                                CamelFolderSearch *search,
                                CamelIMAPXStore *imapx_store,
-                               const GString *criteria,
+                               const GString *criteria_prefix,
+                              const gchar *search_key,
+                              const GPtrArray *words,
                                const gchar *from_function)
 {
        CamelSExpResult *result;
@@ -181,7 +188,8 @@ imapx_search_process_criteria (CamelSExp *sexp,
                g_warn_if_fail (imapx_store != NULL);
 
                conn_man = camel_imapx_store_get_conn_manager (imapx_store);
-               uids = camel_imapx_conn_manager_uid_search_sync (conn_man, mailbox, criteria->str, 
imapx_search->priv->cancellable, &local_error);
+               uids = camel_imapx_conn_manager_uid_search_sync (conn_man, mailbox, criteria_prefix->str, 
search_key,
+                       words ? (const gchar * const *) words->pdata : NULL, imapx_search->priv->cancellable, 
&local_error);
 
                g_clear_object (&imapx_store);
                g_object_unref (mailbox);
@@ -279,6 +287,58 @@ imapx_search_match_all (CamelSExp *sexp,
        return result;
 }
 
+static GPtrArray *
+imapx_search_gather_words (CamelSExpResult **argv,
+                          gint from_index,
+                          gint argc)
+{
+       GPtrArray *ptrs;
+       GHashTable *words_hash;
+       GHashTableIter iter;
+       gpointer key, value;
+       gint ii, jj;
+
+       g_return_val_if_fail (argv != 0, NULL);
+
+       words_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+       for (ii = from_index; ii < argc; ii++) {
+               struct _camel_search_words *words;
+
+               if (argv[ii]->type != CAMEL_SEXP_RES_STRING)
+                       continue;
+
+               /* Handle multiple search words within a single term. */
+               words = camel_search_words_split ((const guchar *) argv[ii]->value.string);
+
+               for (jj = 0; jj < words->len; jj++) {
+                       const gchar *word = words->words[jj]->word;
+
+                       g_hash_table_insert (words_hash, g_strdup (word), NULL);
+               }
+
+               camel_search_words_free (words);
+       }
+
+       ptrs = g_ptr_array_new_full (g_hash_table_size (words_hash), g_free);
+
+       g_hash_table_iter_init (&iter, words_hash);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               g_ptr_array_add (ptrs, g_strdup (key));
+       }
+
+       if (ptrs->len == 0) {
+               g_ptr_array_free (ptrs, TRUE);
+               ptrs = NULL;
+       } else {
+               g_ptr_array_add (ptrs, NULL);
+       }
+
+       g_hash_table_destroy (words_hash);
+
+       return ptrs;
+}
+
 static CamelSExpResult *
 imapx_search_body_contains (CamelSExp *sexp,
                             gint argc,
@@ -289,7 +349,7 @@ imapx_search_body_contains (CamelSExp *sexp,
        CamelIMAPXStore *imapx_store;
        CamelSExpResult *result;
        GString *criteria;
-       gint ii, jj;
+       GPtrArray *words;
 
        /* Always do body-search server-side */
        if (imapx_search->priv->local_data_search) {
@@ -326,39 +386,12 @@ imapx_search_body_contains (CamelSExp *sexp,
                g_string_append_printf (criteria, "UID %s", uid);
        }
 
-       for (ii = 0; ii < argc; ii++) {
-               struct _camel_search_words *words;
-               const guchar *term;
-
-               if (argv[ii]->type != CAMEL_SEXP_RES_STRING)
-                       continue;
-
-               /* Handle multiple search words within a single term. */
-               term = (const guchar *) argv[ii]->value.string;
-               words = camel_search_words_split (term);
-
-               for (jj = 0; jj < words->len; jj++) {
-                       gchar *cp;
+       words = imapx_search_gather_words (argv, 0, argc);
 
-                       if (criteria->len > 0)
-                               g_string_append_c (criteria, ' ');
-
-                       g_string_append (criteria, "BODY \"");
-
-                       cp = words->words[jj]->word;
-                       for (; *cp != '\0'; cp++) {
-                               if (*cp == '\\' || *cp == '"')
-                                       g_string_append_c (criteria, '\\');
-                               g_string_append_c (criteria, *cp);
-                       }
-
-                       g_string_append_c (criteria, '"');
-               }
-       }
-
-       result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, G_STRFUNC);
+       result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, "BODY", words, 
G_STRFUNC);
 
        g_string_free (criteria, TRUE);
+       g_ptr_array_free (words, TRUE);
        g_object_unref (imapx_store);
 
        return result;
@@ -384,7 +417,8 @@ imapx_search_header_contains (CamelSExp *sexp,
        CamelSExpResult *result;
        const gchar *headername, *command = NULL;
        GString *criteria;
-       gint ii, jj;
+       gchar *search_key = NULL;
+       GPtrArray *words;
 
        /* Match nothing if empty argv or empty summary. */
        if (argc <= 1 ||
@@ -441,45 +475,17 @@ imapx_search_header_contains (CamelSExp *sexp,
        else if (g_ascii_strcasecmp (headername, "Subject") == 0)
                command = "SUBJECT";
 
-       for (ii = 1; ii < argc; ii++) {
-               struct _camel_search_words *words;
-               const guchar *term;
-
-               if (argv[ii]->type != CAMEL_SEXP_RES_STRING)
-                       continue;
-
-               /* Handle multiple search words within a single term. */
-               term = (const guchar *) argv[ii]->value.string;
-               words = camel_search_words_split (term);
-
-               for (jj = 0; jj < words->len; jj++) {
-                       gchar *cp;
-
-                       if (criteria->len > 0)
-                               g_string_append_c (criteria, ' ');
-
-                       if (command)
-                               g_string_append (criteria, command);
-                       else
-                               g_string_append_printf (criteria, "HEADER \"%s\"", headername);
-
-                       g_string_append (criteria, " \"");
+       words = imapx_search_gather_words (argv, 1, argc);
 
-                       cp = words->words[jj]->word;
-                       for (; *cp != '\0'; cp++) {
-                               if (*cp == '\\' || *cp == '"')
-                                       g_string_append_c (criteria, '\\');
-                               g_string_append_c (criteria, *cp);
-                       }
-
-                       g_string_append_c (criteria, '"');
-               }
-       }
+       if (!command)
+               search_key = g_strdup_printf ("HEADER \"%s\"", headername);
 
-       result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, G_STRFUNC);
+       result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, command ? command : 
search_key, words, G_STRFUNC);
 
        g_string_free (criteria, TRUE);
+       g_ptr_array_free (words, TRUE);
        g_object_unref (imapx_store);
+       g_free (search_key);
 
        return result;
 }
@@ -561,7 +567,7 @@ imapx_search_header_exists (CamelSExp *sexp,
                g_string_append_printf (criteria, "HEADER \"%s\" \"\"", headername);
        }
 
-       result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, G_STRFUNC);
+       result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, NULL, NULL, G_STRFUNC);
 
        g_string_free (criteria, TRUE);
        g_object_unref (imapx_store);
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 77e8aae..321daf1 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -5716,24 +5716,42 @@ camel_imapx_server_update_quota_info_sync (CamelIMAPXServer *is,
 GPtrArray *
 camel_imapx_server_uid_search_sync (CamelIMAPXServer *is,
                                    CamelIMAPXMailbox *mailbox,
-                                   const gchar *criteria,
+                                   const gchar *criteria_prefix,
+                                   const gchar *search_key,
+                                   const gchar * const *words,
                                    GCancellable *cancellable,
                                    GError **error)
 {
        CamelIMAPXCommand *ic;
        GArray *uid_search_results;
        GPtrArray *results = NULL;
+       gint ii;
+       gboolean need_charset = FALSE;
        gboolean success;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
        g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
-       g_return_val_if_fail (criteria != NULL, NULL);
+       g_return_val_if_fail (criteria_prefix != NULL, NULL);
 
        success = camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error);
        if (!success)
                return FALSE;
 
-       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_UID_SEARCH, "UID SEARCH %t", criteria);
+       for (ii = 0; !need_charset && words && words[ii]; ii++) {
+               need_charset = !imapx_util_all_is_ascii (words[ii]);
+       }
+
+       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_UID_SEARCH, "UID SEARCH");
+       if (need_charset)
+               camel_imapx_command_add (ic, " CHARSET UTF-8");
+       if (criteria_prefix && *criteria_prefix)
+               camel_imapx_command_add (ic, " %t", criteria_prefix);
+
+       if (search_key && words) {
+               for (ii = 0; words[ii]; ii++) {
+                       camel_imapx_command_add (ic, " %t %s", search_key, words[ii]);
+               }
+       }
 
        success = camel_imapx_server_process_command_sync (is, ic, _("Search failed"), cancellable, error);
 
diff --git a/camel/providers/imapx/camel-imapx-server.h b/camel/providers/imapx/camel-imapx-server.h
index c47dcf8..45823dd 100644
--- a/camel/providers/imapx/camel-imapx-server.h
+++ b/camel/providers/imapx/camel-imapx-server.h
@@ -267,7 +267,9 @@ gboolean    camel_imapx_server_update_quota_info_sync
 GPtrArray *    camel_imapx_server_uid_search_sync
                                                (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
-                                                const gchar *criteria,
+                                                const gchar *criteria_prefix,
+                                                const gchar *search_key,
+                                                const gchar * const *words,
                                                 GCancellable *cancellable,
                                                 GError **error);
 gboolean       camel_imapx_server_schedule_idle_sync
diff --git a/camel/providers/imapx/camel-imapx-utils.c b/camel/providers/imapx/camel-imapx-utils.c
index a9db565..e94c968 100644
--- a/camel/providers/imapx/camel-imapx-utils.c
+++ b/camel/providers/imapx/camel-imapx-utils.c
@@ -3282,3 +3282,18 @@ imapx_get_temp_uid (void)
 
        return res;
 }
+
+gboolean
+imapx_util_all_is_ascii (const gchar *str)
+{
+       gint ii;
+       gboolean all_ascii = TRUE;
+
+       g_return_val_if_fail (str != NULL, FALSE);
+
+       for (ii = 0; str[ii] && all_ascii; ii++) {
+               all_ascii = str[ii] > 0;
+       }
+
+       return all_ascii;
+}
diff --git a/camel/providers/imapx/camel-imapx-utils.h b/camel/providers/imapx/camel-imapx-utils.h
index 43738ff..dba0235 100644
--- a/camel/providers/imapx/camel-imapx-utils.h
+++ b/camel/providers/imapx/camel-imapx-utils.h
@@ -393,6 +393,8 @@ gchar *             imapx_path_to_physical          (const gchar *prefix,
                                                 const gchar *vpath);
 gchar *                imapx_get_temp_uid              (void);
 
+gboolean       imapx_util_all_is_ascii         (const gchar *str);
+
 G_END_DECLS
 
 #endif /* CAMEL_IMAPX_UTILS_H */


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