[evolution-data-server] [IMAPx] Be able to search server with text with umlauts/UTF-8 letters
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] [IMAPx] Be able to search server with text with umlauts/UTF-8 letters
- Date: Mon, 10 Aug 2015 16:37:31 +0000 (UTC)
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]