talons

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

commit 7bb0e9b30d5e3e572dfbb9f8330aecd8bfec91cf
parent bd8a5595641a887f063a6e77978413ebd456e299
Author: Colin Leroy <colin@colino.net>
Date:   Thu, 27 Sep 2012 14:48:45 +0000

2012-09-27 [colin]	3.8.1cvs80

	* src/advsearch.c
	* src/imap.c
	* src/etpan/imap-thread.c
	* src/etpan/imap-thread.h
		Implement IMAP server search. Patch by
		Sean Buckheister again.

Diffstat:
MChangeLog | 9+++++++++
MPATCHSETS | 1+
Mconfigure.ac | 2+-
Msrc/advsearch.c | 3++-
Msrc/etpan/imap-thread.c | 219+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/etpan/imap-thread.h | 37++++++++++++++++++++++++++++++++++++-
Msrc/imap.c | 334++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
7 files changed, 531 insertions(+), 74 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,12 @@ +2012-09-27 [colin] 3.8.1cvs80 + + * src/advsearch.c + * src/imap.c + * src/etpan/imap-thread.c + * src/etpan/imap-thread.h + Implement IMAP server search. Patch by + Sean Buckheister again. + 2012-09-26 [colin] 3.8.1cvs79 * src/main.c diff --git a/PATCHSETS b/PATCHSETS @@ -4454,3 +4454,4 @@ ( cvs diff -u -r 1.15.2.72 -r 1.15.2.73 src/summary_search.c; cvs diff -u -r 1.1.2.115 -r 1.1.2.116 src/gtk/quicksearch.c; ) > 3.8.1cvs77.patchset ( cvs diff -u -r 1.75.2.76 -r 1.75.2.77 src/matcher.c; cvs diff -u -r 1.49.2.151 -r 1.49.2.152 src/procmime.c; cvs diff -u -r 1.17.2.30 -r 1.17.2.31 src/procmime.h; ) > 3.8.1cvs78.patchset ( cvs diff -u -r 1.115.2.258 -r 1.115.2.259 src/main.c; cvs diff -u -r 1.75.2.77 -r 1.75.2.78 src/matcher.c; cvs diff -u -r 1.39.2.22 -r 1.39.2.23 src/matcher.h; cvs diff -u -r 1.15.2.73 -r 1.15.2.74 src/summary_search.c; ) > 3.8.1cvs79.patchset +( cvs diff -u -r 1.1.2.3 -r 1.1.2.4 src/advsearch.c; cvs diff -u -r 1.179.2.264 -r 1.179.2.265 src/imap.c; cvs diff -u -r 1.1.4.121 -r 1.1.4.122 src/etpan/imap-thread.c; cvs diff -u -r 1.1.4.29 -r 1.1.4.30 src/etpan/imap-thread.h; ) > 3.8.1cvs80.patchset diff --git a/configure.ac b/configure.ac @@ -12,7 +12,7 @@ MINOR_VERSION=8 MICRO_VERSION=1 INTERFACE_AGE=0 BINARY_AGE=0 -EXTRA_VERSION=79 +EXTRA_VERSION=80 EXTRA_RELEASE= EXTRA_GTK2_VERSION= diff --git a/src/advsearch.c b/src/advsearch.c @@ -444,6 +444,7 @@ static gboolean search_filter_folder(MsgNumberList **msgnums, AdvancedSearch *se FolderItem *folderItem, gboolean onServer) { gint matched; + gboolean tried_server = onServer; matched = folder_item_search_msgs(folderItem->folder, folderItem, @@ -459,7 +460,7 @@ static gboolean search_filter_folder(MsgNumberList **msgnums, AdvancedSearch *se return FALSE; } - if (folderItem->folder->klass->supports_server_search && !onServer) { + if (folderItem->folder->klass->supports_server_search && tried_server && !onServer) { return search_filter_folder(msgnums, search, folderItem, onServer); } else { return TRUE; diff --git a/src/etpan/imap-thread.c b/src/etpan/imap-thread.c @@ -1554,6 +1554,7 @@ struct search_param { mailimap * imap; int type; struct mailimap_set * set; + IMAPSearchKey* key; }; struct search_result { @@ -1588,7 +1589,7 @@ static void search_run(struct etpan_thread_op * op) int r; struct mailimap_search_key * key = NULL; struct mailimap_search_key * uid_key = NULL; - struct mailimap_search_key * search_type_key; + struct mailimap_search_key * search_type_key = NULL; clist * search_result; param = op->param; @@ -1602,70 +1603,33 @@ static void search_run(struct etpan_thread_op * op) } else if (param->type == IMAP_SEARCH_TYPE_SIMPLE) { uid_key = mailimap_search_key_new_all(); } - search_type_key = NULL; switch (param->type) { case IMAP_SEARCH_TYPE_SIMPLE: search_type_key = NULL; break; - case IMAP_SEARCH_TYPE_SEEN: - search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_SEEN, - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, NULL, NULL, - NULL, 0, NULL, NULL, NULL); + search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_READ, NULL, NULL, 0); break; - case IMAP_SEARCH_TYPE_UNSEEN: - search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_UNSEEN, - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, NULL, NULL, - NULL, 0, NULL, NULL, NULL); + search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_UNREAD, NULL, NULL, 0); break; - case IMAP_SEARCH_TYPE_ANSWERED: - search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_ANSWERED, - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, NULL, NULL, - NULL, 0, NULL, NULL, NULL); + search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_REPLIED, NULL, NULL, 0); break; - case IMAP_SEARCH_TYPE_FLAGGED: - search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_FLAGGED, - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, NULL, NULL, - NULL, 0, NULL, NULL, NULL); + search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_MARKED, NULL, NULL, 0); break; case IMAP_SEARCH_TYPE_DELETED: - search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_DELETED, - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, NULL, NULL, - NULL, 0, NULL, NULL, NULL); + search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_DELETED, NULL, NULL, 0); break; case IMAP_SEARCH_TYPE_FORWARDED: - search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_KEYWORD, - NULL, NULL, NULL, NULL, NULL, - strdup(RTAG_FORWARDED), NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, NULL, NULL, - NULL, 0, NULL, NULL, NULL); + search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_TAG, NULL, RTAG_FORWARDED, 0); break; case IMAP_SEARCH_TYPE_SPAM: - search_type_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_KEYWORD, - NULL, NULL, NULL, NULL, NULL, - strdup(RTAG_JUNK), NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, NULL, NULL, - NULL, 0, NULL, NULL, NULL); + search_type_key = imap_search_new(IMAP_SEARCH_CRITERIA_TAG, NULL, RTAG_JUNK, 0); + break; + case IMAP_SEARCH_TYPE_KEYED: + search_type_key = param->key; break; } @@ -1702,7 +1666,7 @@ static void search_run(struct etpan_thread_op * op) debug_print("imap search run - end %i\n", result->error); } -int imap_threaded_search(Folder * folder, int search_type, +int imap_threaded_search(Folder * folder, int search_type, IMAPSearchKey* key, struct mailimap_set * set, clist ** search_result) { struct search_param param; @@ -1715,7 +1679,8 @@ int imap_threaded_search(Folder * folder, int search_type, param.imap = imap; param.set = set; param.type = search_type; - + param.key = key; + threaded_run(folder, &param, &result, search_run); if (result.error != MAILIMAP_NO_ERROR) @@ -1729,6 +1694,160 @@ int imap_threaded_search(Folder * folder, int search_type, } +struct _IMAPSearchKey { + struct mailimap_search_key* key; +}; + +IMAPSearchKey* imap_search_new(gint criteria, + const gchar *header, + const gchar *expr, + int value) +{ + char* sk_bcc = NULL; + struct mailimap_date* sk_before = NULL; + char* sk_body = NULL; + char* sk_cc = NULL; + char* sk_from = NULL; + char* sk_keyword = NULL; + struct mailimap_date* sk_on = NULL; + struct mailimap_date* sk_since = NULL; + char* sk_subject = NULL; + char* sk_text = NULL; + char* sk_to = NULL; + char* sk_unkeyword = NULL; + char* sk_header_name = NULL; + char* sk_header_value = NULL; + uint32_t sk_larger = 0; + struct mailimap_search_key* sk_not = NULL; + struct mailimap_search_key* sk_or1 = NULL; + struct mailimap_search_key* sk_or2 = NULL; + struct mailimap_date* sk_sentbefore = NULL; + struct mailimap_date* sk_senton = NULL; + struct mailimap_date* sk_sentsince = NULL; + uint32_t sk_smaller = 0; + struct mailimap_set* sk_uid = NULL; + struct mailimap_set* sk_set = NULL; + clist* sk_multiple = NULL; + int etpan_matcher_type; + + switch (criteria) { + case IMAP_SEARCH_CRITERIA_ALL: etpan_matcher_type = MAILIMAP_SEARCH_KEY_ALL; break; + case IMAP_SEARCH_CRITERIA_READ: etpan_matcher_type = MAILIMAP_SEARCH_KEY_SEEN; break; + case IMAP_SEARCH_CRITERIA_UNREAD: etpan_matcher_type = MAILIMAP_SEARCH_KEY_UNSEEN; break; + case IMAP_SEARCH_CRITERIA_NEW: etpan_matcher_type = MAILIMAP_SEARCH_KEY_NEW; break; + case IMAP_SEARCH_CRITERIA_MARKED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_FLAGGED; break; + case IMAP_SEARCH_CRITERIA_REPLIED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_ANSWERED; break; + case IMAP_SEARCH_CRITERIA_DELETED: etpan_matcher_type = MAILIMAP_SEARCH_KEY_DELETED; break; + + case IMAP_SEARCH_CRITERIA_TAG: + sk_keyword = strdup(expr); + etpan_matcher_type = MAILIMAP_SEARCH_KEY_KEYWORD; + break; + + case IMAP_SEARCH_CRITERIA_SUBJECT: + etpan_matcher_type = MAILIMAP_SEARCH_KEY_SUBJECT; + sk_subject = strdup(expr); + break; + + case IMAP_SEARCH_CRITERIA_TO: + etpan_matcher_type = MAILIMAP_SEARCH_KEY_TO; + sk_to = strdup(expr); + break; + + case IMAP_SEARCH_CRITERIA_CC: + etpan_matcher_type = MAILIMAP_SEARCH_KEY_CC; + sk_cc = strdup(expr); + break; + + case IMAP_SEARCH_CRITERIA_AGE_GREATER: + case IMAP_SEARCH_CRITERIA_AGE_LOWER: + { + struct tm tm; + time_t limit = time(NULL) - 60 * 60 * 24 * value; + + tzset(); + localtime_r(&limit, &tm); + if (criteria == IMAP_SEARCH_CRITERIA_AGE_GREATER) { + etpan_matcher_type = MAILIMAP_SEARCH_KEY_SENTBEFORE; + sk_sentbefore = mailimap_date_new(tm.tm_mday, tm.tm_mon, tm.tm_year + 1900); + } else { + etpan_matcher_type = MAILIMAP_SEARCH_KEY_SENTSINCE; + sk_sentsince = mailimap_date_new(tm.tm_mday, tm.tm_mon, tm.tm_year + 1900); + } + break; + } + + case IMAP_SEARCH_CRITERIA_BODY: + etpan_matcher_type = MAILIMAP_SEARCH_KEY_BODY; + sk_body = strdup(expr); + break; + + case IMAP_SEARCH_CRITERIA_MESSAGE: + etpan_matcher_type = MAILIMAP_SEARCH_KEY_TEXT; + sk_text = strdup(expr); + break; + + case IMAP_SEARCH_CRITERIA_HEADER: + etpan_matcher_type = MAILIMAP_SEARCH_KEY_HEADER; + sk_header_name = strdup(header); + sk_header_value = strdup(expr); + break; + + case IMAP_SEARCH_CRITERIA_FROM: + etpan_matcher_type = MAILIMAP_SEARCH_KEY_FROM; + sk_from = strdup(expr); + break; + + case IMAP_SEARCH_CRITERIA_SIZE_GREATER: + etpan_matcher_type = MAILIMAP_SEARCH_KEY_LARGER; + sk_larger = value; + break; + + case IMAP_SEARCH_CRITERIA_SIZE_SMALLER: + etpan_matcher_type = MAILIMAP_SEARCH_KEY_SMALLER; + sk_smaller = value; + break; + + default: + return NULL; + } + + return mailimap_search_key_new(etpan_matcher_type, + sk_bcc, sk_before, sk_body, sk_cc, sk_from, sk_keyword, + sk_on, sk_since, sk_subject, sk_text, sk_to, + sk_unkeyword, sk_header_name,sk_header_value, sk_larger, + sk_not, sk_or1, sk_or2, sk_sentbefore, sk_senton, + sk_sentsince, sk_smaller, sk_uid, sk_set, sk_multiple); +} + +IMAPSearchKey* imap_search_not(IMAPSearchKey* key) +{ + return mailimap_search_key_new_not(key); +} + +IMAPSearchKey* imap_search_or(IMAPSearchKey* l, IMAPSearchKey* r) +{ + return mailimap_search_key_new_or(l, r); +} + +IMAPSearchKey* imap_search_and(IMAPSearchKey* l, IMAPSearchKey* r) +{ + IMAPSearchKey* result = mailimap_search_key_new_multiple_empty(); + mailimap_search_key_multiple_add(result, l); + mailimap_search_key_multiple_add(result, r); + + return result; +} + +void imap_search_free(IMAPSearchKey* key) +{ + if (!key) + return; + + mailimap_search_key_free(key); +} + + static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att, uint32_t * puid, diff --git a/src/etpan/imap-thread.h b/src/etpan/imap-thread.h @@ -99,9 +99,44 @@ enum { IMAP_SEARCH_TYPE_DELETED, IMAP_SEARCH_TYPE_FORWARDED, IMAP_SEARCH_TYPE_SPAM, + + IMAP_SEARCH_TYPE_KEYED, +}; + +typedef struct mailimap_search_key IMAPSearchKey; + +enum { + IMAP_SEARCH_CRITERIA_ALL, + IMAP_SEARCH_CRITERIA_READ, + IMAP_SEARCH_CRITERIA_UNREAD, + IMAP_SEARCH_CRITERIA_NEW, + IMAP_SEARCH_CRITERIA_MARKED, + IMAP_SEARCH_CRITERIA_DELETED, + IMAP_SEARCH_CRITERIA_REPLIED, + IMAP_SEARCH_CRITERIA_TAG, + IMAP_SEARCH_CRITERIA_SUBJECT, + IMAP_SEARCH_CRITERIA_FROM, + IMAP_SEARCH_CRITERIA_TO, + IMAP_SEARCH_CRITERIA_CC, + IMAP_SEARCH_CRITERIA_AGE_GREATER, + IMAP_SEARCH_CRITERIA_AGE_LOWER, + IMAP_SEARCH_CRITERIA_BODY, + IMAP_SEARCH_CRITERIA_MESSAGE, + IMAP_SEARCH_CRITERIA_HEADER, + IMAP_SEARCH_CRITERIA_SIZE_GREATER, + IMAP_SEARCH_CRITERIA_SIZE_SMALLER, }; -int imap_threaded_search(Folder * folder, int search_type, +IMAPSearchKey* imap_search_new(gint criteria, + const gchar *header, + const gchar *expr, + int value); +IMAPSearchKey* imap_search_not(IMAPSearchKey* key); +IMAPSearchKey* imap_search_or(IMAPSearchKey* l, IMAPSearchKey* r); +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); int imap_threaded_fetch_uid(Folder * folder, uint32_t first_index, diff --git a/src/imap.c b/src/imap.c @@ -223,6 +223,14 @@ static gint imap_copy_msgs (Folder *folder, MsgInfoList *msglist, GHashTable *relation); +static gint search_msgs (Folder *folder, + FolderItem *container, + MsgNumberList **msgs, + gboolean *on_server, + MatcherList *predicate, + SearchProgressNotify progress_cb, + gpointer progress_data); + static gint imap_remove_msg (Folder *folder, FolderItem *item, gint uid); @@ -422,7 +430,7 @@ static GSList * imap_list_from_lep(IMAPFolder * folder, clist * list, const gchar * real_path, gboolean all); static GSList * imap_get_lep_set_from_numlist(IMAPFolder *folder, MsgNumberList *numlist); static GSList * imap_get_lep_set_from_msglist(IMAPFolder *folder, MsgInfoList *msglist); -static GSList * imap_uid_list_from_lep(clist * list); +static GSList * imap_uid_list_from_lep(clist * list, gint* length); static GSList * imap_uid_list_from_lep_tab(carray * list); static void imap_flags_hash_from_lep_uid_flags_tab(carray * list, GHashTable * hash, @@ -445,7 +453,7 @@ FolderClass *imap_get_class(void) imap_class.type = F_IMAP; imap_class.idstr = "imap"; imap_class.uistr = "IMAP4"; - imap_class.supports_server_search = FALSE; + imap_class.supports_server_search = TRUE; /* Folder functions */ imap_class.new_folder = imap_folder_new; @@ -477,7 +485,7 @@ FolderClass *imap_get_class(void) imap_class.add_msgs = imap_add_msgs; imap_class.copy_msg = imap_copy_msg; imap_class.copy_msgs = imap_copy_msgs; - imap_class.search_msgs = folder_item_search_msgs_local; + imap_class.search_msgs = search_msgs; imap_class.remove_msg = imap_remove_msg; imap_class.remove_msgs = imap_remove_msgs; imap_class.expunge = imap_expunge; @@ -1952,6 +1960,286 @@ static gint imap_copy_msgs(Folder *folder, FolderItem *dest, } +static IMAPSearchKey* search_make_key(MatcherProp* match, gboolean* is_all) +{ + if (match->matchtype == MATCHTYPE_MATCHCASE || match->matchtype == MATCHTYPE_MATCH) { + IMAPSearchKey* result = NULL; + gboolean invert = FALSE; + gint matchertype = match->criteria; + + if (is_all) { + *is_all = FALSE; + } + + switch (matchertype) { + case MATCHCRITERIA_NOT_NEW: invert = TRUE; matchertype = MATCHCRITERIA_NEW; break; + case MATCHCRITERIA_NOT_MARKED: invert = TRUE; matchertype = MATCHCRITERIA_MARKED; break; + case MATCHCRITERIA_NOT_FORWARDED: invert = TRUE; matchertype = MATCHCRITERIA_FORWARDED; break; + case MATCHCRITERIA_NOT_SPAM: invert = TRUE; matchertype = MATCHCRITERIA_SPAM; break; + case MATCHCRITERIA_NOT_SUBJECT: invert = TRUE; matchertype = MATCHCRITERIA_SUBJECT; break; + case MATCHCRITERIA_NOT_FROM: invert = TRUE; matchertype = MATCHCRITERIA_FROM; break; + case MATCHCRITERIA_NOT_TO: invert = TRUE; matchertype = MATCHCRITERIA_TO; break; + case MATCHCRITERIA_NOT_CC: invert = TRUE; matchertype = MATCHCRITERIA_CC; break; + case MATCHCRITERIA_NOT_REFERENCES: invert = TRUE; matchertype = MATCHCRITERIA_REFERENCES; break; + case MATCHCRITERIA_NOT_HEADER: invert = TRUE; matchertype = MATCHCRITERIA_HEADER; break; + case MATCHCRITERIA_NOT_TAG: invert = TRUE; matchertype = MATCHCRITERIA_TAG; break; + case MATCHCRITERIA_NOT_HEADERS_PART: invert = TRUE; matchertype = MATCHCRITERIA_HEADERS_PART; break; + case MATCHCRITERIA_NOT_MESSAGE: invert = TRUE; matchertype = MATCHCRITERIA_MESSAGE; break; + case MATCHCRITERIA_NOT_BODY_PART: invert = TRUE; matchertype = MATCHCRITERIA_BODY_PART; break; + case MATCHCRITERIA_NOT_TO_AND_NOT_CC: invert = TRUE; matchertype = MATCHCRITERIA_TO_OR_CC; break; + case MATCHCRITERIA_NOT_INREPLYTO: invert = TRUE; matchertype = MATCHCRITERIA_INREPLYTO; break; + } + + /* + * this aborts conversion even for predicates understood by the following code. + * while that might seem wasteful, claws local search for information listed below + * 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: + return NULL; + } + + /* the Message-ID header is also cached */ + if (matchertype == MATCHCRITERIA_HEADER && g_strcmp0("Message-ID", match->header) == 0) { + return NULL; + } + + switch (matchertype) { + case MATCHCRITERIA_FORWARDED: + result = imap_search_new(IMAP_SEARCH_CRITERIA_TAG, NULL, RTAG_FORWARDED, 0); + break; + + case MATCHCRITERIA_SPAM: + result = imap_search_new(IMAP_SEARCH_CRITERIA_TAG, NULL, RTAG_JUNK, 0); + break; + + case MATCHCRITERIA_INREPLYTO: + result = imap_search_new(IMAP_SEARCH_CRITERIA_HEADER, "In-Reply-To", match->expr, 0); + break; + + case MATCHCRITERIA_REFERENCES: + result = imap_search_new(IMAP_SEARCH_CRITERIA_HEADER, "References", match->expr, 0); + break; + + case MATCHCRITERIA_TO_OR_CC: + result = imap_search_or( + imap_search_new(IMAP_SEARCH_CRITERIA_TO, NULL, match->expr, 0), + imap_search_new(IMAP_SEARCH_CRITERIA_CC, NULL, match->expr, 0) + ); + break; + + case MATCHCRITERIA_HEADERS_PART: + result = imap_search_and( + imap_search_not(imap_search_new(IMAP_SEARCH_CRITERIA_BODY, NULL, match->expr, 0)), + imap_search_new(IMAP_SEARCH_CRITERIA_MESSAGE, NULL, match->expr, 0) + ); + break; + + case MATCHCRITERIA_SIZE_EQUAL: + result = imap_search_and( + imap_search_not(imap_search_new(IMAP_SEARCH_CRITERIA_SIZE_SMALLER, NULL, NULL, match->value)), + imap_search_not(imap_search_new(IMAP_SEARCH_CRITERIA_SIZE_GREATER, NULL, NULL, match->value)) + ); + break; + + case MATCHCRITERIA_NOT_UNREAD: + result = imap_search_new(IMAP_SEARCH_CRITERIA_READ, NULL, NULL, 0); + break; + + case MATCHCRITERIA_UNREAD: + result = imap_search_new(IMAP_SEARCH_CRITERIA_UNREAD, NULL, NULL, 0); + break; + + case MATCHCRITERIA_NEW: + result = imap_search_new(IMAP_SEARCH_CRITERIA_NEW, NULL, NULL, 0); + break; + + case MATCHCRITERIA_MARKED: + result = imap_search_new(IMAP_SEARCH_CRITERIA_MARKED, NULL, NULL, 0); + break; + + case MATCHCRITERIA_DELETED: + result = imap_search_new(IMAP_SEARCH_CRITERIA_DELETED, NULL, NULL, 0); + break; + + case MATCHCRITERIA_REPLIED: + result = imap_search_new(IMAP_SEARCH_CRITERIA_REPLIED, NULL, NULL, 0); + break; + + case MATCHCRITERIA_TAG: + result = imap_search_new(IMAP_SEARCH_CRITERIA_TAG, NULL, match->expr, 0); + break; + + case MATCHCRITERIA_SUBJECT: + result = imap_search_new(IMAP_SEARCH_CRITERIA_SUBJECT, NULL, match->expr, 0); + break; + + case MATCHCRITERIA_FROM: + result = imap_search_new(IMAP_SEARCH_CRITERIA_FROM, NULL, match->expr, 0); + break; + + case MATCHCRITERIA_TO: + result = imap_search_new(IMAP_SEARCH_CRITERIA_TO, NULL, match->expr, 0); + break; + + case MATCHCRITERIA_CC: + result = imap_search_new(IMAP_SEARCH_CRITERIA_CC, NULL, match->expr, 0); + break; + + case MATCHCRITERIA_AGE_GREATER: + result = imap_search_new(IMAP_SEARCH_CRITERIA_AGE_GREATER, NULL, NULL, match->value); + break; + + case MATCHCRITERIA_AGE_LOWER: + result = imap_search_new(IMAP_SEARCH_CRITERIA_AGE_LOWER, NULL, NULL, match->value); + break; + + case MATCHCRITERIA_BODY_PART: + result = imap_search_new(IMAP_SEARCH_CRITERIA_BODY, NULL, match->expr, 0); + break; + + case MATCHCRITERIA_MESSAGE: + result = imap_search_new(IMAP_SEARCH_CRITERIA_MESSAGE, NULL, match->expr, 0); + break; + + case MATCHCRITERIA_HEADER: + result = imap_search_new(IMAP_SEARCH_CRITERIA_HEADER, match->header, match->expr, 0); + break; + + case MATCHCRITERIA_SIZE_GREATER: + result = imap_search_new(IMAP_SEARCH_CRITERIA_SIZE_GREATER, NULL, NULL, match->value); + break; + + case MATCHCRITERIA_SIZE_SMALLER: + result = imap_search_new(IMAP_SEARCH_CRITERIA_SIZE_SMALLER, NULL, NULL, match->value); + break; + + default: + result = imap_search_new(IMAP_SEARCH_CRITERIA_ALL, NULL, NULL, 0); + if (is_all) { + *is_all = TRUE; + } + break; + } + + if (invert) { + result = imap_search_not(result); + if (is_all && *is_all) { + *is_all = FALSE; + } + } + + return result; + } + + return NULL; +} + +static gint search_msgs (Folder *folder, + FolderItem *container, + MsgNumberList **msgs, + gboolean *on_server, + MatcherList *predicate, + SearchProgressNotify progress_cb, + gpointer progress_data) +{ + IMAPSearchKey* key = NULL; + GSList* cur; + int result = -1; + clist* uidlist = NULL; + gboolean server_filtering_useless; + + if (on_server == NULL || !*on_server) { + return folder_item_search_msgs_local(folder, container, msgs, on_server, + predicate, progress_cb, progress_data); + } + + for (cur = predicate->matchers; cur != NULL; cur = cur->next) { + IMAPSearchKey* matcherPart = NULL; + MatcherProp* prop = (MatcherProp*) cur->data; + gboolean is_all; + + matcherPart = search_make_key(prop, &is_all); + + if (on_server) { + *on_server &= matcherPart != NULL && prop->matchtype == MATCHTYPE_MATCHCASE; + } + + if (matcherPart) { + if (key == NULL) { + key = matcherPart; + server_filtering_useless = is_all; + } else if (predicate->bool_and) { + key = imap_search_and(key, matcherPart); + server_filtering_useless &= is_all; + } else { + key = imap_search_or(key, matcherPart); + server_filtering_useless |= is_all; + } + } + } + + if (server_filtering_useless) { + imap_search_free(key); + key = NULL; + } + + if (key == NULL && progress_cb != NULL) { + GSList* cur; + GSList* list; + int count = 0; + + progress_cb(progress_data, TRUE, 0, 0, container->total_msgs); + progress_cb(progress_data, TRUE, container->total_msgs, 0, container->total_msgs); + + list = folder_item_get_msg_list(container); + for (cur = list; cur != NULL; cur = cur->next) { + *msgs = g_slist_prepend(*msgs, GUINT_TO_POINTER(((MsgInfo*) cur->data)->msgnum)); + count++; + } + *msgs = g_slist_reverse(*msgs); + return count; + } + + 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); + if (progress_cb) + progress_cb(progress_data, TRUE, container->total_msgs, 0, container->total_msgs); + + if (result == MAILIMAP_NO_ERROR) { + gint result = 0; + + *msgs = imap_uid_list_from_lep(uidlist, &result); + mailimap_search_result_free(uidlist); + + return result; + } else { + return -1; + } +} + + static gint imap_do_remove_msgs(Folder *folder, FolderItem *dest, MsgInfoList *msglist, GHashTable *relation) { @@ -3980,13 +4268,13 @@ static gint get_list_of_uids(IMAPSession *session, Folder *folder, IMAPFolderIte uidlist = NULL; if (folder->account && folder->account->low_bandwidth) { - r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SIMPLE, NULL, - &lep_uidlist); + r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SIMPLE, + NULL, NULL, &lep_uidlist); } if (r == MAILIMAP_NO_ERROR) { GSList * fetchuid_list = - imap_uid_list_from_lep(lep_uidlist); + imap_uid_list_from_lep(lep_uidlist, NULL); mailimap_search_result_free(lep_uidlist); uidlist = g_slist_concat(fetchuid_list, uidlist); @@ -4615,18 +4903,18 @@ static /*gint*/ void *imap_get_flags_thread(void *data) imapset = cur->data; if (reverse_seen) { - r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SEEN, + r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SEEN, NULL, full_search ? NULL:imapset, &lep_uidlist); } else { r = imap_threaded_search(folder, - IMAP_SEARCH_TYPE_UNSEEN, + IMAP_SEARCH_TYPE_UNSEEN, NULL, full_search ? NULL:imapset, &lep_uidlist); } if (r == MAILIMAP_NO_ERROR) { GSList * uidlist; - uidlist = imap_uid_list_from_lep(lep_uidlist); + uidlist = imap_uid_list_from_lep(lep_uidlist, NULL); mailimap_search_result_free(lep_uidlist); unseen = g_slist_concat(unseen, uidlist); @@ -4635,12 +4923,12 @@ static /*gint*/ void *imap_get_flags_thread(void *data) goto bail; } - r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_FLAGGED, + r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_FLAGGED, NULL, full_search ? NULL:imapset, &lep_uidlist); if (r == MAILIMAP_NO_ERROR) { GSList * uidlist; - uidlist = imap_uid_list_from_lep(lep_uidlist); + uidlist = imap_uid_list_from_lep(lep_uidlist, NULL); mailimap_search_result_free(lep_uidlist); flagged = g_slist_concat(flagged, uidlist); @@ -4650,12 +4938,12 @@ 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, + r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_ANSWERED, NULL, full_search ? NULL:imapset, &lep_uidlist); if (r == MAILIMAP_NO_ERROR) { GSList * uidlist; - uidlist = imap_uid_list_from_lep(lep_uidlist); + uidlist = imap_uid_list_from_lep(lep_uidlist, NULL); mailimap_search_result_free(lep_uidlist); answered = g_slist_concat(answered, uidlist); @@ -4665,12 +4953,12 @@ 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, + r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_FORWARDED, NULL, full_search ? NULL:imapset, &lep_uidlist); if (r == MAILIMAP_NO_ERROR) { GSList * uidlist; - uidlist = imap_uid_list_from_lep(lep_uidlist); + uidlist = imap_uid_list_from_lep(lep_uidlist, NULL); mailimap_search_result_free(lep_uidlist); forwarded = g_slist_concat(forwarded, uidlist); @@ -4681,12 +4969,12 @@ 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, + r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SPAM, NULL, full_search ? NULL:imapset, &lep_uidlist); if (r == MAILIMAP_NO_ERROR) { GSList * uidlist; - uidlist = imap_uid_list_from_lep(lep_uidlist); + uidlist = imap_uid_list_from_lep(lep_uidlist, NULL); mailimap_search_result_free(lep_uidlist); spam = g_slist_concat(spam, uidlist); @@ -4696,12 +4984,12 @@ static /*gint*/ void *imap_get_flags_thread(void *data) } } - r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_DELETED, + r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_DELETED, NULL, full_search ? NULL:imapset, &lep_uidlist); if (r == MAILIMAP_NO_ERROR) { GSList * uidlist; - uidlist = imap_uid_list_from_lep(lep_uidlist); + uidlist = imap_uid_list_from_lep(lep_uidlist, NULL); mailimap_search_result_free(lep_uidlist); deleted = g_slist_concat(deleted, uidlist); @@ -5236,10 +5524,11 @@ static GSList * imap_get_lep_set_from_msglist(IMAPFolder *folder, MsgInfoList *m return seq_list; } -static GSList * imap_uid_list_from_lep(clist * list) +static GSList * imap_uid_list_from_lep(clist * list, gint* length) { clistiter * iter; GSList * result; + gint len = 0; result = NULL; @@ -5250,9 +5539,12 @@ static GSList * imap_uid_list_from_lep(clist * list) puid = clist_content(iter); result = g_slist_prepend(result, GINT_TO_POINTER(* puid)); + len++; } result = g_slist_reverse(result); - } + } + if (length) + *length = len; return result; }