2012-09-27 [colin] 3.8.1cvs80
authorColin Leroy <colin@colino.net>
Thu, 27 Sep 2012 14:48:45 +0000 (14:48 +0000)
committerColin Leroy <colin@colino.net>
Thu, 27 Sep 2012 14:48:45 +0000 (14:48 +0000)
* 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.

ChangeLog
PATCHSETS
configure.ac
src/advsearch.c
src/etpan/imap-thread.c
src/etpan/imap-thread.h
src/imap.c

index 8425b7c..1969f5b 100644 (file)
--- 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
index afe02b9..c886b5d 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
 ( 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
index f804bb2..c6e4540 100644 (file)
@@ -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=
 
index 0e5ca69..686e241 100644 (file)
@@ -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;
index e7ad978..b0cd341 100644 (file)
@@ -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,
index 47b0bfa..83175a4 100644 (file)
@@ -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,
index eb0408c..6a959be 100644 (file)
@@ -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;
 }