2007-08-08 [colin] 2.10.0cvs99
[claws.git] / src / imap.c
index 43656a1add4017b5cc35b6b0073552981b2658c0..ce86d94e6beafd55b42fbfc1950dce4a65e3369f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -13,8 +13,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
  */
 
 #ifdef HAVE_CONFIG_H
@@ -198,6 +198,9 @@ static gchar   *imap_fetch_msg_full (Folder         *folder,
                                         gint            uid,
                                         gboolean        headers,
                                         gboolean        body);
+static void    imap_remove_cached_msg  (Folder         *folder, 
+                                        FolderItem     *item, 
+                                        MsgInfo        *msginfo);
 static gint    imap_add_msg            (Folder         *folder,
                                         FolderItem     *dest,
                                         const gchar    *file, 
@@ -303,7 +306,7 @@ static gchar imap_get_path_separator                (IMAPSession    *session,
 static gchar *imap_get_real_path               (IMAPSession    *session,
                                                 IMAPFolder     *folder,
                                                 const gchar    *path);
-static void imap_synchronise           (FolderItem     *item);
+static void imap_synchronise           (FolderItem     *item, gint days);
 static gboolean imap_is_busy           (Folder *folder);
 
 static void imap_free_capabilities     (IMAPSession    *session);
@@ -401,6 +404,8 @@ static GSList * imap_get_lep_set_from_numlist(MsgNumberList *numlist);
 static GSList * imap_get_lep_set_from_msglist(MsgInfoList *msglist);
 static GSList * imap_uid_list_from_lep(clist * list);
 static GSList * imap_uid_list_from_lep_tab(carray * list);
+static void imap_flags_hash_from_lep_uid_flags_tab(carray * list,
+                                                  GHashTable * hash);
 static MsgInfo *imap_envelope_from_lep(struct imap_fetch_env_info * info,
                                       FolderItem *item);
 static void imap_lep_set_free(GSList *seq_list);
@@ -469,6 +474,7 @@ FolderClass *imap_get_class(void)
                imap_class.get_flags = imap_get_flags;
                imap_class.set_batch = imap_set_batch;
                imap_class.synchronise = imap_synchronise;
+               imap_class.remove_cached_msg = imap_remove_cached_msg;
 #ifdef USE_PTREAD
                pthread_mutex_init(&imap_mutex, NULL);
 #endif
@@ -789,8 +795,8 @@ static IMAPSession *imap_session_get(Folder *folder)
                        debug_print("disconnected!\n");
                        session = imap_reconnect_if_possible(folder, session);
                }
-               
-               session->cancelled = FALSE;
+               if (session)
+                       session->cancelled = FALSE;
        }
 
        rfolder->session = SESSION(session);
@@ -1004,6 +1010,26 @@ static guint get_file_size_with_crs(const gchar *filename)
        return cnt;
 }
 
+static void imap_remove_cached_msg(Folder *folder, FolderItem *item, MsgInfo *msginfo)
+{
+       gchar *path, *filename;
+
+       path = folder_item_get_path(item);
+
+       if (!is_dir_exist(path)) {
+               g_free(path);
+               return;
+       }
+
+       filename = g_strconcat(path, G_DIR_SEPARATOR_S, itos(msginfo->msgnum), NULL);
+       g_free(path);
+
+       if (is_file_exist(filename)) {
+               g_unlink(filename);
+       }
+       g_free(filename);
+}
+
 static gchar *imap_fetch_msg_full(Folder *folder, FolderItem *item, gint uid,
                                  gboolean headers, gboolean body)
 {
@@ -1149,6 +1175,41 @@ static gint imap_add_msg(Folder *folder, FolderItem *dest,
        return ret;
 }
 
+static gint imap_get_msg_from_local(Folder *folder, FolderItem *dest, const gchar *real_file)
+{
+       /* don't get session, already done. */
+       MsgInfo *msginfo;
+       MsgFlags flags = {0, 0};
+       gint msgnum = 0;
+       msginfo = procheader_parse_file(real_file, flags, FALSE, FALSE);
+
+       if (msginfo && msginfo->msgid) {
+               GSList *msglist = folder_item_get_msg_list(dest);
+               GSList *cur;
+               gint found_num = 0;
+
+               /* gets last matching mail with msgid. Slower than by msgid but gets the
+                * most recent one */
+               for (cur = msglist ; cur != NULL ; cur = cur->next) {
+                       MsgInfo * r_msginfo;
+
+                       r_msginfo = (MsgInfo *) cur->data;
+                       
+                       if (r_msginfo->msgid && !strcmp(r_msginfo->msgid,msginfo->msgid)) {
+                               if (found_num < r_msginfo->msgnum) {
+                                       found_num = r_msginfo->msgnum;
+                               }
+                       }
+                       procmsg_msginfo_free(r_msginfo);
+               }
+               msgnum = found_num;
+               g_slist_free(msglist);
+
+       }
+       procmsg_msginfo_free(msginfo);
+       return msgnum;
+}
+
 static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
                   GRelation *relation)
 {
@@ -1159,7 +1220,7 @@ static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
        MsgFileInfo *fileinfo;
        gint ok;
        gint curnum = 0, total = 0;
-
+       gboolean missing_uids = FALSE;
 
        g_return_val_if_fail(folder != NULL, -1);
        g_return_val_if_fail(dest != NULL, -1);
@@ -1216,6 +1277,11 @@ static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
                        debug_print("appended new message as %d\n", new_uid);
                        /* put the local file in the imapcache, so that we don't
                         * have to fetch it back later. */
+                       
+                       if (new_uid == 0) {
+                               missing_uids = TRUE;
+                               debug_print("Missing UID (0)\n");
+                       }
                        if (new_uid > 0) {
                                gchar *cache_path = folder_item_get_path(dest);
                                if (!is_dir_exist(cache_path))
@@ -1225,7 +1291,7 @@ static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
                                                cache_path, G_DIR_SEPARATOR_S, 
                                                itos(new_uid), NULL);
                                        copy_file(real_file, cache_file, TRUE);
-                                       debug_print("copied to cache: %s\n", cache_file);
+                                       debug_print("got UID %d, copied to cache: %s\n", new_uid, cache_file);
                                        g_free(cache_file);
                                }
                                g_free(cache_path);
@@ -1235,20 +1301,56 @@ static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
                if (relation != NULL)
                        g_relation_insert(relation, fileinfo->msginfo != NULL ? 
                                          (gpointer) fileinfo->msginfo : (gpointer) fileinfo,
-                                         GINT_TO_POINTER(dest->last_num + 1));
-               if (new_uid == 0) {
-                       new_uid = dest->last_num+1;
-               }
+                                         GINT_TO_POINTER(new_uid));
                if (last_uid < new_uid) {
                        last_uid = new_uid;
                }
 
                g_free(real_file);
        }
+       
+       if (missing_uids) {
+               unlock_session(IMAP_SESSION(REMOTE_FOLDER(folder)->session));
+               folder_item_scan_full(dest, FALSE);
+               lock_session(IMAP_SESSION(REMOTE_FOLDER(folder)->session));
+               for (cur = file_list; cur != NULL; cur = cur->next) {
+                       guint32 new_uid = 0;
+                       fileinfo = (MsgFileInfo *)cur->data;
+                       
+                       if (!fileinfo->file)
+                               continue;
+
+                       new_uid = imap_get_msg_from_local(folder, dest, fileinfo->file);
+                       debug_print("new uid %d from scanning\n", new_uid);
+                       if (new_uid > 0) {
+                               gchar *cache_path = folder_item_get_path(dest);
+                               if (!is_dir_exist(cache_path))
+                                       make_dir_hier(cache_path);
+                               if (is_dir_exist(cache_path)) {
+                                       gchar *cache_file = g_strconcat(
+                                               cache_path, G_DIR_SEPARATOR_S, 
+                                               itos(new_uid), NULL);
+                                       copy_file(fileinfo->file, cache_file, TRUE);
+                                       debug_print("copied to cache: %s\n", cache_file);
+                                       g_free(cache_file);
+                               }
+                               g_free(cache_path);
+                               g_relation_delete(relation, fileinfo->msginfo != NULL ? 
+                                                 (gpointer) fileinfo->msginfo : (gpointer) fileinfo,
+                                                 0);
+
+                               g_relation_insert(relation, fileinfo->msginfo != NULL ? 
+                                                 (gpointer) fileinfo->msginfo : (gpointer) fileinfo,
+                                                 GINT_TO_POINTER(new_uid));
+                       }
+                       if (last_uid < new_uid) {
+                               last_uid = new_uid;
+                       }
+               }
+       }
        statusbar_progress_all(0,0,0);
        statusbar_pop_all();
        
-       imap_cmd_expunge(session);
        unlock_session(session);
        
        g_free(destdir);
@@ -1256,6 +1358,32 @@ static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
        return last_uid;
 }
 
+static GSList *flatten_mailimap_set(struct mailimap_set * set) 
+{
+       GSList *result = NULL;
+       clistiter *list;
+       int start, end, t;
+       GSList *cur;
+
+       for (list = clist_begin(set->set_list); list; list = clist_next(list)) {
+               struct mailimap_set_item *item = (struct mailimap_set_item *)clist_content(list);
+               start = item->set_first;
+               end = item->set_last;
+               for (t = start; t <= end; t++) {
+                       result = g_slist_prepend(result, GINT_TO_POINTER(t));
+               }
+       }
+       result = g_slist_reverse(result);
+       if (debug_get_mode()) {
+               debug_print("flat imap set: ");
+               for (cur = result; cur; cur = cur->next) {
+                       debug_print("%d ", GPOINTER_TO_INT(cur->data));
+               }
+               debug_print("\n");
+       }
+       
+       return result;
+}
 static gint imap_do_copy_msgs(Folder *folder, FolderItem *dest, 
                              MsgInfoList *msglist, GRelation *relation)
 {
@@ -1338,16 +1466,23 @@ static gint imap_do_copy_msgs(Folder *folder, FolderItem *dest,
                        &source, &dest);
                
                if (ok == IMAP_SUCCESS) {
-                       if (single && relation && source && dest) {
-                               clistiter *l = clist_begin(source->set_list);
-                               struct mailimap_set_item *i = (struct mailimap_set_item *)clist_content(l);
-                               int snum = i->set_first;
-                               int dnum = 0;
-                               l = clist_begin(dest->set_list);
-                               i = (struct mailimap_set_item *)clist_content(l);
-                               dnum = i->set_first;
-                               g_relation_insert(uid_mapping, GINT_TO_POINTER(snum), 
-                                       GINT_TO_POINTER(dnum));
+                       if (relation && source && dest) {
+                               GSList *s_list = flatten_mailimap_set(source);
+                               GSList *d_list = flatten_mailimap_set(dest);
+                               GSList *s_cur, *d_cur;
+                               if (g_slist_length(s_list) == g_slist_length(d_list)) {
+
+                                       for (s_cur = s_list, d_cur = d_list; 
+                                            s_cur && d_cur; 
+                                            s_cur = s_cur->next, d_cur = d_cur->next) {
+                                               g_relation_insert(uid_mapping, s_cur->data, d_cur->data);
+                                       }
+
+                               } else {
+                                       debug_print("hhhmm, source list length != dest list length.\n");
+                               }
+                               g_slist_free(s_list);
+                               g_slist_free(d_list);
                        }
                }
 
@@ -1379,7 +1514,7 @@ static gint imap_do_copy_msgs(Folder *folder, FolderItem *dest,
                                          GINT_TO_POINTER(num));
                        if (num > last_num)
                                last_num = num;
-                       debug_print("copied new message as %d\n", num);
+                       debug_print("copied message %d as %d\n", msginfo->msgnum, num);
                        /* put the local file in the imapcache, so that we don't
                         * have to fetch it back later. */
                        if (num > 0) {
@@ -3330,8 +3465,8 @@ static void *get_list_of_uids_thread(void *data)
        gint ok, nummsgs = 0, lastuid_old;
        IMAPSession *session;
        GSList *uidlist, *elem;
+       int r = -1;
        clist * lep_uidlist;
-       int r;
 
        session = stuff->session;
        if (session == NULL) {
@@ -3348,32 +3483,34 @@ static void *get_list_of_uids_thread(void *data)
 
        uidlist = NULL;
        
-       r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SIMPLE, NULL,
+       if (folder->account && folder->account->low_bandwidth) {
+               r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SIMPLE, NULL,
                                 &lep_uidlist);
+       }
        
        if (r == MAILIMAP_NO_ERROR) {
-               GSList * fetchuid_list;
-               
-               fetchuid_list =
+               GSList * fetchuid_list =
                        imap_uid_list_from_lep(lep_uidlist);
                mailimap_search_result_free(lep_uidlist);
                
                uidlist = g_slist_concat(fetchuid_list, uidlist);
-       }
-       else {
-               GSList * fetchuid_list;
+       } else {
                carray * lep_uidtab;
-               
-               r = imap_threaded_fetch_uid(folder, item->lastuid + 1,
-                                           &lep_uidtab);
+               r = imap_threaded_fetch_uid(folder, 1,
+                                   &lep_uidtab);
                if (r == MAILIMAP_NO_ERROR) {
-                       fetchuid_list =
+                       GSList * fetchuid_list =
                                imap_uid_list_from_lep_tab(lep_uidtab);
                        imap_fetch_uid_list_free(lep_uidtab);
                        uidlist = g_slist_concat(fetchuid_list, uidlist);
                }
        }
        
+       if (r != MAILIMAP_NO_ERROR) {
+               stuff->done = TRUE;
+               return GINT_TO_POINTER(-1);
+       }
+
        lastuid_old = item->lastuid;
        *msgnum_list = g_slist_copy(item->uid_list);
        nummsgs = g_slist_length(*msgnum_list);
@@ -3650,8 +3787,9 @@ GSList *imap_get_msginfos(Folder *folder, FolderItem *item,
                                int i;
                                for (i = startnum; i <= lastnum; ++i) {
                                        gchar *file;
-                       
+                                       unlock_session(session);
                                        file = imap_fetch_msg(folder, item, i);
+                                       lock_session(session);
                                        if (file != NULL) {
                                                MsgInfo *msginfo = imap_parse_msg(file, item);
                                                if (msginfo != NULL) {
@@ -3973,39 +4111,34 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
 {
        get_flags_data *stuff = (get_flags_data *)data;
        Folder *folder = stuff->folder;
-       FolderItem *item = stuff->item;
+       FolderItem *fitem = (FolderItem *) stuff->item;
        MsgInfoList *msginfo_list = stuff->msginfo_list;
        GRelation *msgflags = stuff->msgflags;
-       gboolean full_search = stuff->full_search;
+       GSList *elem;
+       carray * lep_uidtab;
        IMAPSession *session;
+       gint ok;
+       int r;
+       GHashTable *flags_hash = NULL;
+       gboolean full_search = stuff->full_search;
        GSList *sorted_list = NULL;
        GSList *unseen = NULL, *answered = NULL, *flagged = NULL, *deleted = NULL;
        GSList *p_unseen, *p_answered, *p_flagged, *p_deleted;
-       GSList *elem;
        GSList *seq_list, *cur;
        gboolean reverse_seen = FALSE;
-       GString *cmd_buf;
-       gint ok;
-       gint exists_cnt, unseen_cnt;
        gboolean selected_folder;
+       gint exists_cnt, unseen_cnt;
        
-       if (folder == NULL || item == NULL) {
-               stuff->done = TRUE;
-               return GINT_TO_POINTER(-1);
-       }
-
-       debug_print("getting session...\n");
        session = imap_session_get(folder);
        if (session == NULL) {
                stuff->done = TRUE;
                return GINT_TO_POINTER(-1);
        }
-
        selected_folder = (session->mbox != NULL) &&
-                         (!strcmp(session->mbox, item->path));
+                         (!strcmp(session->mbox, fitem->path));
 
        if (!selected_folder) {
-               ok = imap_select(session, IMAP_FOLDER(folder), item->path,
+               ok = imap_select(session, IMAP_FOLDER(folder), fitem->path,
                        &exists_cnt, NULL, &unseen_cnt, NULL, TRUE);
                if (ok != IMAP_SUCCESS) {
                        stuff->done = TRUE;
@@ -4017,12 +4150,10 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
                        reverse_seen = TRUE;
        } 
        else {
-               if (item->unread_msgs > item->total_msgs / 2)
+               if (fitem->unread_msgs > fitem->total_msgs / 2)
                        reverse_seen = TRUE;
        }
 
-       cmd_buf = g_string_new(NULL);
-
        sorted_list = g_slist_sort(g_slist_copy(msginfo_list), compare_msginfo);
        if (!full_search) {
                seq_list = imap_get_lep_set_from_msglist(msginfo_list);
@@ -4032,54 +4163,32 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
                seq_list = g_slist_append(NULL, set);
        }
 
-       for (cur = seq_list; cur != NULL; cur = g_slist_next(cur)) {
-               struct mailimap_set * imapset;
-               clist * lep_uidlist;
-               int r;
-               
-               imapset = cur->data;
-               if (reverse_seen) {
-                       r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SEEN,
-                                                full_search ? NULL:imapset, &lep_uidlist);
-               }
-               else {
-                       r = imap_threaded_search(folder,
-                                                IMAP_SEARCH_TYPE_UNSEEN,
-                                                full_search ? NULL:imapset, &lep_uidlist);
-               }
-               if (r == MAILIMAP_NO_ERROR) {
-                       GSList * uidlist;
-                       
-                       uidlist = imap_uid_list_from_lep(lep_uidlist);
-                       mailimap_search_result_free(lep_uidlist);
-                       
-                       unseen = g_slist_concat(unseen, uidlist);
-               }
-               
-               r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_FLAGGED,
-                                        full_search ? NULL:imapset, &lep_uidlist);
-               if (r == MAILIMAP_NO_ERROR) {
-                       GSList * uidlist;
+       if (folder->account && folder->account->low_bandwidth) {
+               for (cur = seq_list; cur != NULL; cur = g_slist_next(cur)) {
+                       struct mailimap_set * imapset;
+                       clist * lep_uidlist;
+                       int r;
 
-                       uidlist = imap_uid_list_from_lep(lep_uidlist);
-                       mailimap_search_result_free(lep_uidlist);
-
-                       flagged = g_slist_concat(flagged, uidlist);
-               }
-
-               if (item->opened || item->processing_pending || item == folder->inbox) {
-                       r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_ANSWERED,
-                                                full_search ? NULL:imapset, &lep_uidlist);
+                       imapset = cur->data;
+                       if (reverse_seen) {
+                               r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SEEN,
+                                                        full_search ? NULL:imapset, &lep_uidlist);
+                       }
+                       else {
+                               r = imap_threaded_search(folder,
+                                                        IMAP_SEARCH_TYPE_UNSEEN,
+                                                        full_search ? NULL:imapset, &lep_uidlist);
+                       }
                        if (r == MAILIMAP_NO_ERROR) {
                                GSList * uidlist;
 
                                uidlist = imap_uid_list_from_lep(lep_uidlist);
                                mailimap_search_result_free(lep_uidlist);
 
-                               answered = g_slist_concat(answered, uidlist);
+                               unseen = g_slist_concat(unseen, uidlist);
                        }
 
-                       r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_DELETED,
+                       r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_FLAGGED,
                                                 full_search ? NULL:imapset, &lep_uidlist);
                        if (r == MAILIMAP_NO_ERROR) {
                                GSList * uidlist;
@@ -4087,56 +4196,110 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
                                uidlist = imap_uid_list_from_lep(lep_uidlist);
                                mailimap_search_result_free(lep_uidlist);
 
-                               deleted = g_slist_concat(deleted, uidlist);
+                               flagged = g_slist_concat(flagged, uidlist);
                        }
-               }
-       }
 
-       p_unseen = unseen;
-       p_answered = answered;
-       p_flagged = flagged;
-       p_deleted = deleted;
+                       if (fitem->opened || fitem->processing_pending || fitem == folder->inbox) {
+                               r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_ANSWERED,
+                                                        full_search ? NULL:imapset, &lep_uidlist);
+                               if (r == MAILIMAP_NO_ERROR) {
+                                       GSList * uidlist;
+
+                                       uidlist = imap_uid_list_from_lep(lep_uidlist);
+                                       mailimap_search_result_free(lep_uidlist);
 
+                                       answered = g_slist_concat(answered, uidlist);
+                               }
+
+                               r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_DELETED,
+                                                        full_search ? NULL:imapset, &lep_uidlist);
+                               if (r == MAILIMAP_NO_ERROR) {
+                                       GSList * uidlist;
+
+                                       uidlist = imap_uid_list_from_lep(lep_uidlist);
+                                       mailimap_search_result_free(lep_uidlist);
+
+                                       deleted = g_slist_concat(deleted, uidlist);
+                               }
+                       }
+               }
+               p_unseen = unseen;
+               p_answered = answered;
+               p_flagged = flagged;
+               p_deleted = deleted;
+
+       } else {
+               r = imap_threaded_fetch_uid_flags(folder, 1, &lep_uidtab);
+               if (r == MAILIMAP_NO_ERROR) {
+                       flags_hash = g_hash_table_new_full(g_int_hash, g_int_equal, free, NULL);
+                       imap_flags_hash_from_lep_uid_flags_tab(lep_uidtab, flags_hash);
+                       imap_fetch_uid_flags_list_free(lep_uidtab);
+               }
+       }
        for (elem = sorted_list; elem != NULL; elem = g_slist_next(elem)) {
                MsgInfo *msginfo;
-               MsgPermFlags flags;
+               MsgPermFlags flags, oldflags;
                gboolean wasnew;
-               
+
                msginfo = (MsgInfo *) elem->data;
                flags = msginfo->flags.perm_flags;
                wasnew = (flags & MSG_NEW);
-               if (item->opened || item->processing_pending || item == folder->inbox) {
-                       flags &= ~((reverse_seen ? 0 : MSG_UNREAD | MSG_NEW) | MSG_REPLIED | MSG_MARKED);
-               } else {
-                       flags &= ~((reverse_seen ? 0 : MSG_UNREAD | MSG_NEW | MSG_MARKED));
-               }
-               if (reverse_seen)
-                       flags |= MSG_UNREAD | (wasnew ? MSG_NEW : 0);
-               if (gslist_find_next_num(&p_unseen, msginfo->msgnum) == msginfo->msgnum) {
-                       if (!reverse_seen) {
-                               flags |= MSG_UNREAD | (wasnew ? MSG_NEW : 0);
+               oldflags = flags & ~(MSG_NEW|MSG_UNREAD|MSG_REPLIED|MSG_MARKED|MSG_DELETED);
+
+               if (folder->account && folder->account->low_bandwidth) {
+                       if (fitem->opened || fitem->processing_pending || fitem == folder->inbox) {
+                               flags &= ~((reverse_seen ? 0 : MSG_UNREAD | MSG_NEW) | MSG_REPLIED | MSG_MARKED);
                        } else {
-                               flags &= ~(MSG_UNREAD | MSG_NEW);
+                               flags &= ~((reverse_seen ? 0 : MSG_UNREAD | MSG_NEW | MSG_MARKED));
+                       }
+                       if (reverse_seen)
+                               flags |= MSG_UNREAD | (wasnew ? MSG_NEW : 0);
+                       if (gslist_find_next_num(&p_unseen, msginfo->msgnum) == msginfo->msgnum) {
+                               if (!reverse_seen) {
+                                       flags |= MSG_UNREAD | (wasnew ? MSG_NEW : 0);
+                               } else {
+                                       flags &= ~(MSG_UNREAD | MSG_NEW);
+                               }
                        }
-               }
-               
-               if (gslist_find_next_num(&p_flagged, msginfo->msgnum) == msginfo->msgnum)
-                       flags |= MSG_MARKED;
-               else
-                       flags &= ~MSG_MARKED;
 
-               if (item->opened || item->processing_pending || item == folder->inbox) {
-                       if (gslist_find_next_num(&p_answered, msginfo->msgnum) == msginfo->msgnum)
-                               flags |= MSG_REPLIED;
-                       else
-                               flags &= ~MSG_REPLIED;
-                       if (gslist_find_next_num(&p_deleted, msginfo->msgnum) == msginfo->msgnum)
-                               flags |= MSG_DELETED;
+                       if (gslist_find_next_num(&p_flagged, msginfo->msgnum) == msginfo->msgnum)
+                               flags |= MSG_MARKED;
                        else
-                               flags &= ~MSG_DELETED;
+                               flags &= ~MSG_MARKED;
+
+                       if (fitem->opened || fitem->processing_pending || fitem == folder->inbox) {
+                               if (gslist_find_next_num(&p_answered, msginfo->msgnum) == msginfo->msgnum)
+                                       flags |= MSG_REPLIED;
+                               else
+                                       flags &= ~MSG_REPLIED;
+                               if (gslist_find_next_num(&p_deleted, msginfo->msgnum) == msginfo->msgnum)
+                                       flags |= MSG_DELETED;
+                               else
+                                       flags &= ~MSG_DELETED;
+                       }
+               } else {
+                       if (flags_hash != NULL) {
+                               gint * puid;
+
+                               puid = malloc(sizeof(* puid));
+                               * puid = msginfo->msgnum;
+
+                               flags = GPOINTER_TO_INT(g_hash_table_lookup(flags_hash, puid));
+                               free(puid);
+                       }
+
+                       if ((flags & MSG_UNREAD) == 0)
+                               flags &= ~MSG_NEW;
+                       else if (wasnew)
+                               flags |= MSG_NEW;
+                       flags |= oldflags;
                }
+
                g_relation_insert(msgflags, msginfo, GINT_TO_POINTER(flags));
        }
+       
+       if (flags_hash)
+               g_hash_table_destroy(flags_hash);
 
        imap_lep_set_free(seq_list);
        g_slist_free(flagged);
@@ -4144,10 +4307,9 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
        g_slist_free(answered);
        g_slist_free(unseen);
        g_slist_free(sorted_list);
-       g_string_free(cmd_buf, TRUE);
 
-       stuff->done = TRUE;
        unlock_session(session);
+       stuff->done = TRUE;
        return GINT_TO_POINTER(0);
 }
 
@@ -4511,6 +4673,28 @@ static GSList * imap_uid_list_from_lep_tab(carray * list)
        return result;
 }
 
+static void imap_flags_hash_from_lep_uid_flags_tab(carray * list,
+                                                  GHashTable * hash)
+{
+       unsigned int i;
+       GSList * result;
+       
+       result = NULL;
+       
+       for(i = 0 ; i < carray_count(list) ; i += 2) {
+               uint32_t * puid;
+               int * pflags;
+               gint * pguid;
+               
+               puid = carray_get(list, i);
+               pflags = carray_get(list, i + 1);
+               pguid = malloc(sizeof(* pguid));
+               * pguid = * puid;
+               
+               g_hash_table_insert(hash, pguid, GINT_TO_POINTER(* pflags));
+       }
+}
+
 static MsgInfo *imap_envelope_from_lep(struct imap_fetch_env_info * info,
                                       FolderItem *item)
 {
@@ -4632,7 +4816,8 @@ void imap_cancel_all(void)
                                imap_threaded_cancel(folder);
                                rfolder = (RemoteFolder *) folder;
                                imap_session = (IMAPSession *) rfolder->session;
-                               imap_session->cancelled = 1;
+                               if (imap_session)
+                                       imap_session->cancelled = 1;
                        }
                }
        }
@@ -4773,15 +4958,17 @@ gboolean imap_cancel_all_enabled(void)
 
 #endif
 
-void imap_synchronise(FolderItem *item) 
+void imap_synchronise(FolderItem *item, gint days
 {
+#ifdef HAVE_LIBETPAN
        if (IMAP_FOLDER_ITEM(item)->last_sync == IMAP_FOLDER_ITEM(item)->last_change) {
                debug_print("%s already synced\n", item->path?item->path:item->name);
                return;
        }
        debug_print("syncing %s\n", item->path?item->path:item->name);
-       imap_gtk_synchronise(item);
+       imap_gtk_synchronise(item, days);
        IMAP_FOLDER_ITEM(item)->last_sync = IMAP_FOLDER_ITEM(item)->last_change;
+#endif
 }
 
 static void imap_item_set_xml(Folder *folder, FolderItem *item, XMLTag *tag)