talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

commit ddf3aca80e577ae0131b0e034ee080810b1fa996
parent a32c2d6d5ddbe098b589776d023426ad46e59142
Author: Colin Leroy <colin@colino.net>
Date:   Wed, 28 Nov 2012 09:39:37 +0000

2012-11-28 [colin]	3.9.0cvs26

	* src/imap.c
	* src/etpan/imap-thread.c
	* src/etpan/imap-thread.h
		Try locale's charset and UTF-7 on server-side
		searches when UTF-8 fails. Also, don't even
		mention a charset if searching for an ASCII
		string.

Diffstat:
MChangeLog | 10++++++++++
MPATCHSETS | 1+
Mconfigure.ac | 2+-
Msrc/etpan/imap-thread.c | 9+++++----
Msrc/etpan/imap-thread.h | 2+-
Msrc/imap.c | 162++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
6 files changed, 149 insertions(+), 37 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,13 @@ +2012-11-28 [colin] 3.9.0cvs26 + + * src/imap.c + * src/etpan/imap-thread.c + * src/etpan/imap-thread.h + Try locale's charset and UTF-7 on server-side + searches when UTF-8 fails. Also, don't even + mention a charset if searching for an ASCII + string. + 2012-11-27 [colin] 3.9.0cvs25 * src/main.c diff --git a/PATCHSETS b/PATCHSETS @@ -4523,3 +4523,4 @@ ( cvs diff -u -r 1.1.4.12 -r 1.1.4.13 src/gtk/manage_window.c; ) > 3.9.0cvs23.patchset ( cvs diff -u -r 1.9.2.58 -r 1.9.2.59 src/common/ssl.c; ) > 3.9.0cvs24.patchset ( cvs diff -u -r 1.115.2.264 -r 1.115.2.265 src/main.c; ) > 3.9.0cvs25.patchset +( cvs diff -u -r 1.179.2.268 -r 1.179.2.269 src/imap.c; cvs diff -u -r 1.1.4.126 -r 1.1.4.127 src/etpan/imap-thread.c; cvs diff -u -r 1.1.4.30 -r 1.1.4.31 src/etpan/imap-thread.h; ) > 3.9.0cvs26.patchset diff --git a/configure.ac b/configure.ac @@ -12,7 +12,7 @@ MINOR_VERSION=9 MICRO_VERSION=0 INTERFACE_AGE=0 BINARY_AGE=0 -EXTRA_VERSION=25 +EXTRA_VERSION=26 EXTRA_RELEASE= EXTRA_GTK2_VERSION= diff --git a/src/etpan/imap-thread.c b/src/etpan/imap-thread.c @@ -1553,6 +1553,7 @@ int imap_threaded_examine(Folder * folder, const char * mb, struct search_param { mailimap * imap; int type; + const char *charset; struct mailimap_set * set; IMAPSearchKey* key; }; @@ -1591,7 +1592,6 @@ static void search_run(struct etpan_thread_op * op) struct mailimap_search_key * uid_key = NULL; struct mailimap_search_key * search_type_key = NULL; clist * search_result; - static const char *charset = NULL; param = op->param; result = op->result; @@ -1630,7 +1630,6 @@ static void search_run(struct etpan_thread_op * op) search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_TAG, NULL, RTAG_JUNK, 0); break; case IMAP_SEARCH_TYPE_KEYED: - charset = "UTF-8"; search_type_key = param->key; break; } @@ -1655,7 +1654,7 @@ static void search_run(struct etpan_thread_op * op) } else { mailstream_logger = imap_logger_uid; - r = mailimap_uid_search(param->imap, charset, key, &search_result); + r = mailimap_uid_search(param->imap, param->charset, key, &search_result); mailstream_logger = imap_logger_cmd; @@ -1669,7 +1668,8 @@ static void search_run(struct etpan_thread_op * op) } int imap_threaded_search(Folder * folder, int search_type, IMAPSearchKey* key, - struct mailimap_set * set, clist ** search_result) + const char *charset, struct mailimap_set * set, + clist ** search_result) { struct search_param param; struct search_result result; @@ -1680,6 +1680,7 @@ int imap_threaded_search(Folder * folder, int search_type, IMAPSearchKey* key, imap = get_imap(folder); param.imap = imap; param.set = set; + param.charset = charset; param.type = search_type; param.key = key; diff --git a/src/etpan/imap-thread.h b/src/etpan/imap-thread.h @@ -137,7 +137,7 @@ IMAPSearchKey* imap_search_and(IMAPSearchKey* l, IMAPSearchKey* r); void imap_search_free(IMAPSearchKey* search); int imap_threaded_search(Folder * folder, int search_type, IMAPSearchKey* key, - struct mailimap_set * set, clist ** result); + const char *charset, struct mailimap_set * set, clist ** result); int imap_threaded_fetch_uid(Folder * folder, uint32_t first_index, carray ** result); diff --git a/src/imap.c b/src/imap.c @@ -95,6 +95,8 @@ struct _IMAPFolder gchar last_seen_separator; guint refcnt; guint max_set_size; + const gchar *search_charset; + gboolean search_charset_supported; }; struct _IMAPSession @@ -749,6 +751,8 @@ static void imap_folder_init(Folder *folder, const gchar *name, { folder_remote_folder_init((Folder *)folder, name, path); IMAP_FOLDER(folder)->max_set_size = IMAP_SET_MAX_COUNT; + IMAP_FOLDER(folder)->search_charset_supported = TRUE; + IMAP_FOLDER(folder)->search_charset = "UTF-8"; } static FolderItem *imap_folder_item_new(Folder *folder) @@ -1957,6 +1961,32 @@ static gint imap_copy_msgs(Folder *folder, FolderItem *dest, return ret; } +static gboolean imap_matcher_type_is_local(gint matchertype) +{ + switch (matchertype) { + case MATCHCRITERIA_FROM: + case MATCHCRITERIA_TO: + case MATCHCRITERIA_CC: + case MATCHCRITERIA_TO_OR_CC: + case MATCHCRITERIA_SUBJECT: + case MATCHCRITERIA_REFERENCES: + case MATCHCRITERIA_INREPLYTO: + case MATCHCRITERIA_AGE_GREATER: + case MATCHCRITERIA_AGE_LOWER: + case MATCHCRITERIA_FORWARDED: + case MATCHCRITERIA_SPAM: + case MATCHCRITERIA_UNREAD: + case MATCHCRITERIA_NEW: + case MATCHCRITERIA_MARKED: + case MATCHCRITERIA_REPLIED: + case MATCHCRITERIA_DELETED: + case MATCHCRITERIA_SIZE_GREATER: + case MATCHCRITERIA_SIZE_SMALLER: + case MATCHCRITERIA_SIZE_EQUAL: + return TRUE; + } + return FALSE; +} static IMAPSearchKey* search_make_key(MatcherProp* match, gboolean* is_all) { @@ -1994,28 +2024,8 @@ static IMAPSearchKey* search_make_key(MatcherProp* match, gboolean* is_all) * has proven faster than IMAP search plus network roundtrips. once this changes, * consider removing these exceptions. */ - switch (matchertype) { - case MATCHCRITERIA_FROM: - case MATCHCRITERIA_TO: - case MATCHCRITERIA_CC: - case MATCHCRITERIA_TO_OR_CC: - case MATCHCRITERIA_SUBJECT: - case MATCHCRITERIA_REFERENCES: - case MATCHCRITERIA_INREPLYTO: - case MATCHCRITERIA_AGE_GREATER: - case MATCHCRITERIA_AGE_LOWER: - case MATCHCRITERIA_FORWARDED: - case MATCHCRITERIA_SPAM: - case MATCHCRITERIA_UNREAD: - case MATCHCRITERIA_NEW: - case MATCHCRITERIA_MARKED: - case MATCHCRITERIA_REPLIED: - case MATCHCRITERIA_DELETED: - case MATCHCRITERIA_SIZE_GREATER: - case MATCHCRITERIA_SIZE_SMALLER: - case MATCHCRITERIA_SIZE_EQUAL: + if (imap_matcher_type_is_local(matchertype)) return NULL; - } /* the Message-ID header is also cached */ if (matchertype == MATCHCRITERIA_HEADER && g_strcmp0("Message-ID", match->header) == 0) { @@ -2157,6 +2167,70 @@ static IMAPSearchKey* search_make_key(MatcherProp* match, gboolean* is_all) return NULL; } +static void imap_change_search_charset(IMAPFolder *folder) +{ + /* If server supports charset in searches, but the last used one failed, + * changed to the next preferred charset. If none are still available, + * disable charset searches. + * Charsets are tried in the following order: + * UTF-8, locale's charset, UTF-7. + */ + + if (folder->search_charset_supported) { + if (folder->search_charset && !strcmp(folder->search_charset, "UTF-8")) + folder->search_charset = conv_get_locale_charset_str_no_utf8(); + else if (folder->search_charset && !strcmp(folder->search_charset, conv_get_locale_charset_str_no_utf8())) + folder->search_charset = "UTF-7"; + else { + folder->search_charset = NULL; + folder->search_charset_supported = FALSE; + } + } +} + +static MatcherProp *imap_matcher_prop_set_charset(IMAPFolder *folder, + MatcherProp *utf8_prop, + gchar **charset) +{ + /* If the match is going to be done locally, or the criteria is on + * tag (special-cased to modified-UTF-7), or the expression searched + * is ASCII, don't bother converting. + */ + if (imap_matcher_type_is_local(utf8_prop->criteria) + || utf8_prop->criteria == MATCHCRITERIA_TAG + || utf8_prop->criteria == MATCHCRITERIA_NOT_TAG + || is_ascii_str(utf8_prop->expr)) + return matcherprop_new(utf8_prop->criteria, + utf8_prop->header, + utf8_prop->matchtype, + utf8_prop->expr, + utf8_prop->value); + else { + gchar *conv_expr = NULL; + + /* If the search is server-side and the server doesn't support + * searching with the charsets we handle, bail out. + */ + if (folder->search_charset_supported == FALSE) + return NULL; + + /* Else, convert. */ + if (*charset == NULL) + *charset = g_strdup(folder->search_charset); + + conv_expr = conv_codeset_strdup(utf8_prop->expr, CS_UTF_8, *charset); + + if (conv_expr == NULL) + conv_expr = g_strdup(utf8_prop->expr); + + return matcherprop_new(utf8_prop->criteria, + utf8_prop->header, + utf8_prop->matchtype, + conv_expr, + utf8_prop->value); + } +} + static gint search_msgs (Folder *folder, FolderItem *container, MsgNumberList **msgs, @@ -2171,6 +2245,7 @@ static gint search_msgs (Folder *folder, clist* uidlist = NULL; gboolean server_filtering_useless = FALSE; IMAPSession *session; + gchar *charset_to_use = NULL; if (on_server == NULL || !*on_server) { return folder_item_search_msgs_local(folder, container, msgs, on_server, @@ -2181,8 +2256,17 @@ static gint search_msgs (Folder *folder, IMAPSearchKey* matcherPart = NULL; MatcherProp* prop = (MatcherProp*) cur->data; gboolean is_all; + MatcherProp *imap_prop = imap_matcher_prop_set_charset(IMAP_FOLDER(folder), prop, &charset_to_use); + + if (imap_prop == NULL) { + /* Couldn't convert matcherprop to IMAP - probably not ascii + * and server doesn't support the charsets we do. */ + return -1; + } + + matcherPart = search_make_key(imap_prop, &is_all); - matcherPart = search_make_key(prop, &is_all); + matcherprop_free(imap_prop); if (on_server) { *on_server &= matcherPart != NULL && prop->matchtype == MATCHTYPE_MATCHCASE; @@ -2235,7 +2319,7 @@ static gint search_msgs (Folder *folder, if (progress_cb) progress_cb(progress_data, TRUE, 0, 0, container->total_msgs); - result = imap_threaded_search(folder, IMAP_SEARCH_TYPE_KEYED, key, NULL, &uidlist); + result = imap_threaded_search(folder, IMAP_SEARCH_TYPE_KEYED, key, charset_to_use, NULL, &uidlist); if (progress_cb) progress_cb(progress_data, TRUE, container->total_msgs, 0, container->total_msgs); @@ -2243,9 +2327,25 @@ static gint search_msgs (Folder *folder, gint result = 0; *msgs = imap_uid_list_from_lep(uidlist, &result); + mailimap_search_result_free(uidlist); + if (charset_to_use != NULL) + g_free(charset_to_use); + return result; + } else if (charset_to_use != NULL) { + /* If search failed and was on an 8-bit string, try the next + * available charset to search if there still are some. + */ + g_free(charset_to_use); + + imap_change_search_charset(IMAP_FOLDER(folder)); + if (IMAP_FOLDER(folder)->search_charset_supported) + return search_msgs(folder, container, msgs, on_server, predicate, + progress_cb, progress_data); + else + return -1; } else { return -1; } @@ -4278,7 +4378,7 @@ static gint get_list_of_uids(IMAPSession *session, Folder *folder, IMAPFolderIte if (folder->account && folder->account->low_bandwidth) { r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SIMPLE, - NULL, NULL, &lep_uidlist); + NULL, NULL, NULL, &lep_uidlist); } if (r == MAILIMAP_NO_ERROR) { @@ -4913,12 +5013,12 @@ static /*gint*/ void *imap_get_flags_thread(void *data) imapset = cur->data; if (reverse_seen) { r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SEEN, NULL, - full_search ? NULL:imapset, &lep_uidlist); + NULL, full_search ? NULL:imapset, &lep_uidlist); } else { r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_UNSEEN, NULL, - full_search ? NULL:imapset, &lep_uidlist); + NULL, full_search ? NULL:imapset, &lep_uidlist); } if (r == MAILIMAP_NO_ERROR) { GSList * uidlist; @@ -4933,7 +5033,7 @@ static /*gint*/ void *imap_get_flags_thread(void *data) } r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_FLAGGED, NULL, - full_search ? NULL:imapset, &lep_uidlist); + NULL, full_search ? NULL:imapset, &lep_uidlist); if (r == MAILIMAP_NO_ERROR) { GSList * uidlist; @@ -4948,7 +5048,7 @@ static /*gint*/ void *imap_get_flags_thread(void *data) if (fitem->opened || fitem->processing_pending || fitem == folder->inbox) { r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_ANSWERED, NULL, - full_search ? NULL:imapset, &lep_uidlist); + NULL, full_search ? NULL:imapset, &lep_uidlist); if (r == MAILIMAP_NO_ERROR) { GSList * uidlist; @@ -4963,7 +5063,7 @@ static /*gint*/ void *imap_get_flags_thread(void *data) if (flag_ok(IMAP_FOLDER_ITEM(fitem), IMAP_FLAG_FORWARDED)) { r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_FORWARDED, NULL, - full_search ? NULL:imapset, &lep_uidlist); + NULL, full_search ? NULL:imapset, &lep_uidlist); if (r == MAILIMAP_NO_ERROR) { GSList * uidlist; @@ -4979,7 +5079,7 @@ static /*gint*/ void *imap_get_flags_thread(void *data) if (flag_ok(IMAP_FOLDER_ITEM(fitem), IMAP_FLAG_SPAM)) { r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SPAM, NULL, - full_search ? NULL:imapset, &lep_uidlist); + NULL, full_search ? NULL:imapset, &lep_uidlist); if (r == MAILIMAP_NO_ERROR) { GSList * uidlist; @@ -4994,7 +5094,7 @@ static /*gint*/ void *imap_get_flags_thread(void *data) } r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_DELETED, NULL, - full_search ? NULL:imapset, &lep_uidlist); + NULL, full_search ? NULL:imapset, &lep_uidlist); if (r == MAILIMAP_NO_ERROR) { GSList * uidlist;