2008-02-18 [colin] 3.3.0cvs16
[claws.git] / src / imap.c
index 5a535a9940dddf0889aba289227186ef168bd816..8b52e8a843ffb1d431464e30e906887eabea2371 100644 (file)
@@ -70,6 +70,7 @@
 #include "imap-thread.h"
 #include "account.h"
 #include "tags.h"
+#include "main.h"
 
 typedef struct _IMAPFolder     IMAPFolder;
 typedef struct _IMAPSession    IMAPSession;
@@ -130,20 +131,12 @@ struct _IMAPNameSpace
 
 #define IMAPBUFSIZE    8192
 
-typedef enum
-{
-       IMAP_FLAG_SEEN          = 1 << 0,
-       IMAP_FLAG_ANSWERED      = 1 << 1,
-       IMAP_FLAG_FLAGGED       = 1 << 2,
-       IMAP_FLAG_DELETED       = 1 << 3,
-       IMAP_FLAG_DRAFT         = 1 << 4
-} IMAPFlags;
-
 #define IMAP_IS_SEEN(flags)    ((flags & IMAP_FLAG_SEEN) != 0)
 #define IMAP_IS_ANSWERED(flags)        ((flags & IMAP_FLAG_ANSWERED) != 0)
 #define IMAP_IS_FLAGGED(flags) ((flags & IMAP_FLAG_FLAGGED) != 0)
 #define IMAP_IS_DELETED(flags) ((flags & IMAP_FLAG_DELETED) != 0)
 #define IMAP_IS_DRAFT(flags)   ((flags & IMAP_FLAG_DRAFT) != 0)
+#define IMAP_IS_FORWARDED(flags)       ((flags & IMAP_FLAG_FORWARDED) != 0)
 
 
 #define IMAP4_PORT     143
@@ -178,6 +171,7 @@ struct _IMAPFolderItem
 
        GHashTable *tags_set_table;
        GHashTable *tags_unset_table;
+       GSList *ok_flags;
 
 };
 
@@ -287,6 +281,7 @@ static void imap_set_batch          (Folder         *folder,
                                         FolderItem     *item,
                                         gboolean        batch);
 static gint imap_set_message_flags     (IMAPSession    *session,
+                                        IMAPFolderItem *item,
                                         MsgNumberList  *numlist,
                                         IMAPFlags       flags,
                                         GSList         *tags,
@@ -343,6 +338,7 @@ static gint imap_cmd_select (IMAPSession    *session,
                                 gint           *unseen,
                                 guint32        *uid_validity,
                                 gint           *can_create_flags,
+                                GSList         **ok_flags,
                                 gboolean        block);
 static gint imap_cmd_close     (IMAPSession    *session);
 static gint imap_cmd_examine   (IMAPSession    *session,
@@ -365,6 +361,7 @@ static gint imap_cmd_fetch  (IMAPSession    *sock,
                                 gboolean        headers,
                                 gboolean        body);
 static gint imap_cmd_append    (IMAPSession    *session,
+                                IMAPFolderItem *item,
                                 const gchar    *destfolder,
                                 const gchar    *file,
                                 IMAPFlags       flags,
@@ -376,6 +373,7 @@ static gint imap_cmd_copy       (IMAPSession *session,
                                 struct mailimap_set ** source,
                                 struct mailimap_set ** dest);
 static gint imap_cmd_store     (IMAPSession    *session,
+                                IMAPFolderItem *item,
                                 struct mailimap_set * set,
                                 IMAPFlags flags,
                                 GSList *tags,
@@ -426,7 +424,7 @@ static void imap_flags_hash_from_lep_uid_flags_tab(carray * list,
 static MsgInfo *imap_envelope_from_lep(struct imap_fetch_env_info * info,
                                       FolderItem *item);
 static void imap_lep_set_free(GSList *seq_list);
-static struct mailimap_flag_list * imap_flag_to_lep(IMAPFlags flags, GSList *tags);
+static struct mailimap_flag_list * imap_flag_to_lep(IMAPFolderItem *item, IMAPFlags flags, GSList *tags);
 
 typedef struct _hashtable_data {
        GSList *msglist;
@@ -846,6 +844,9 @@ static gint imap_auth(IMAPSession *session, const gchar *user, const gchar *pass
        case IMAP_AUTH_CRAM_MD5:
                ok = imap_cmd_login(session, user, pass, "CRAM-MD5");
                break;
+       case IMAP_AUTH_DIGEST_MD5:
+               ok = imap_cmd_login(session, user, pass, "DIGEST-MD5");
+               break;
        case IMAP_AUTH_LOGIN:
                ok = imap_cmd_login(session, user, pass, "LOGIN");
                break;
@@ -856,14 +857,19 @@ static gint imap_auth(IMAPSession *session, const gchar *user, const gchar *pass
                debug_print("capabilities:\n"
                                "\t ANONYMOUS %d\n"
                                "\t CRAM-MD5 %d\n"
+                               "\t DIGEST-MD5 %d\n"
                                "\t LOGIN %d\n"
                                "\t GSSAPI %d\n", 
                        imap_has_capability(session, "ANONYMOUS"),
                        imap_has_capability(session, "CRAM-MD5"),
+                       imap_has_capability(session, "DIGEST-MD5"),
                        imap_has_capability(session, "LOGIN"),
                        imap_has_capability(session, "GSSAPI"));
                if (imap_has_capability(session, "CRAM-MD5"))
                        ok = imap_cmd_login(session, user, pass, "CRAM-MD5");
+               if ((ok == MAILIMAP_ERROR_BAD_STATE ||
+                    ok == MAILIMAP_ERROR_LOGIN) && imap_has_capability(session, "DIGEST-MD5"))
+                       ok = imap_cmd_login(session, user, pass, "DIGEST-MD5");
                if ((ok == MAILIMAP_ERROR_BAD_STATE ||
                     ok == MAILIMAP_ERROR_LOGIN) && imap_has_capability(session, "GSSAPI"))
                        ok = imap_cmd_login(session, user, pass, "GSSAPI");
@@ -881,6 +887,12 @@ static gint imap_auth(IMAPSession *session, const gchar *user, const gchar *pass
                                     "CRAM-MD5 SASL plugin is installed.");
                } 
 
+               if (type == IMAP_AUTH_DIGEST_MD5) {
+                       ext_info = _("\n\nDIGEST-MD5 logins only work if libetpan has been "
+                                    "compiled with SASL support and the "
+                                    "DIGEST-MD5 SASL plugin is installed.");
+               } 
+
                if (time(NULL) - last_login_err > 10) {
                        if (!prefs_common.no_recv_err_panel) {
                                alertpanel_error(_("Connection to %s failed: "
@@ -994,8 +1006,11 @@ static IMAPSession *imap_session_get(Folder *folder)
                        debug_print("disconnected!\n");
                        if (!is_fatal(r))
                                session = imap_reconnect_if_possible(folder, session);
-                       else
+                       else {
+                               rfolder->session = NULL;
+                               rfolder->connecting = FALSE;
                                session = imap_session_get(folder);
+                       }
                }
                if (session)
                        session->cancelled = FALSE;
@@ -1042,13 +1057,16 @@ static IMAPSession *imap_session_new(Folder * folder,
 
        imap_init(folder);
        statuswindow_print_all(_("Connecting to IMAP4 server: %s..."), folder->account->recv_server);
+#ifndef G_OS_WIN32
        if (account->set_tunnelcmd) {
                r = imap_threaded_connect_cmd(folder,
                                              account->tunnelcmd,
                                              account->recv_server,
                                              port);
        }
-       else {
+       else 
+#endif
+       {
 #if (defined(USE_OPENSSL) || defined (USE_GNUTLS))
                if (ssl_type == SSL_TUNNEL) {
                        r = imap_threaded_connect_ssl(folder,
@@ -1328,7 +1346,8 @@ static void imap_commit_tags(FolderItem *item, MsgInfo *msginfo, GSList *tags_se
                        list_set = g_slist_prepend(list_set, g_strdup(str));
                }
                if (list_set) {
-                       ok = imap_set_message_flags(session, &numlist, 0, list_set, TRUE);
+                       ok = imap_set_message_flags(session, 
+                               IMAP_FOLDER_ITEM(item), &numlist, 0, list_set, TRUE);
                        slist_free_strings(list_set);
                        g_slist_free(list_set);
                        if (ok != MAILIMAP_NO_ERROR) {
@@ -1342,7 +1361,8 @@ static void imap_commit_tags(FolderItem *item, MsgInfo *msginfo, GSList *tags_se
                        list_unset = g_slist_prepend(list_unset, g_strdup(str));
                }
                if (list_unset) {
-                       ok = imap_set_message_flags(session, &numlist, 0, list_unset, FALSE);
+                       ok = imap_set_message_flags(session, 
+                               IMAP_FOLDER_ITEM(item), &numlist, 0, list_unset, FALSE);
                        slist_free_strings(list_unset);
                        g_slist_free(list_unset);
                        if (ok != MAILIMAP_NO_ERROR) {
@@ -1578,8 +1598,11 @@ static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
                                iflags |= IMAP_FLAG_FLAGGED;
                        if (MSG_IS_REPLIED(*fileinfo->flags))
                                iflags |= IMAP_FLAG_ANSWERED;
+                       if (MSG_IS_FORWARDED(*fileinfo->flags))
+                               iflags |= IMAP_FLAG_FORWARDED;
                        if (!MSG_IS_UNREAD(*fileinfo->flags))
                                iflags |= IMAP_FLAG_SEEN;
+                       
                }
                
                if (real_file == NULL)
@@ -1591,7 +1614,7 @@ static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
                    folder_has_parent_of_type(dest, F_TRASH))
                        iflags |= IMAP_FLAG_SEEN;
 
-               ok = imap_cmd_append(session, destdir, real_file, iflags, 
+               ok = imap_cmd_append(session, IMAP_FOLDER_ITEM(dest), destdir, real_file, iflags, 
                                     &new_uid);
 
                if (ok != MAILIMAP_NO_ERROR) {
@@ -1940,7 +1963,7 @@ static gint imap_do_remove_msgs(Folder *folder, FolderItem *dest,
 
        if (numlist != NULL) {
                ok = imap_set_message_flags
-                       (session, numlist, IMAP_FLAG_DELETED, NULL, TRUE);
+                       (session, IMAP_FOLDER_ITEM(msginfo->folder), numlist, IMAP_FLAG_DELETED, NULL, TRUE);
                if (ok != MAILIMAP_NO_ERROR) {
                        log_warning(LOG_PROTOCOL, _("can't set deleted flags\n"));
                        return ok;
@@ -2813,7 +2836,7 @@ static void *imap_get_uncached_messages_thread(void *data)
        GSList *newlist = NULL;
        GSList *llast = NULL;
        GSList *seq_list, *cur;
-       gboolean got_alien_tags;
+       gboolean got_alien_tags = FALSE;
 
        debug_print("uncached_messages\n");
        
@@ -2871,6 +2894,7 @@ static void *imap_get_uncached_messages_thread(void *data)
                                gchar *real_tag = imap_modified_utf7_to_utf8(cur->data, TRUE);
                                gint id = 0;
                                id = tags_get_id_for_str(real_tag);
+                               printf("tag %s %d\n", real_tag, id);
                                if (id == -1) {
                                        id = tags_add_tag(real_tag);
                                        got_alien_tags = TRUE;
@@ -3100,6 +3124,7 @@ static gchar *imap_get_real_path(IMAPSession *session, IMAPFolder *folder, const
 }
 
 static gint imap_set_message_flags(IMAPSession *session,
+                                  IMAPFolderItem *item,
                                   MsgNumberList *numlist,
                                   IMAPFlags flags,
                                   GSList *tags,
@@ -3136,7 +3161,7 @@ static gint imap_set_message_flags(IMAPSession *session,
 
                statusbar_progress_all(set_item->set_first, total, 1);
 
-               ok = imap_cmd_store(session, imapset,
+               ok = imap_cmd_store(session, item, imapset,
                                    flags, tags, is_set);
                statusbar_progress_all(set_item->set_last, total, 1);
                if (ok != MAILIMAP_NO_ERROR && folder->max_set_size > 20) {
@@ -3214,8 +3239,11 @@ static gint imap_select(IMAPSession *session, IMAPFolder *folder,
 
        real_path = imap_get_real_path(session, folder, path);
 
+       g_slist_free(IMAP_FOLDER_ITEM(item)->ok_flags);
+       IMAP_FOLDER_ITEM(item)->ok_flags = NULL;
        ok = imap_cmd_select(session, real_path,
-                            exists, recent, unseen, uid_validity, can_create_flags, block);
+                            exists, recent, unseen, uid_validity, can_create_flags, 
+                            &(IMAP_FOLDER_ITEM(item)->ok_flags), block);
        if (ok != MAILIMAP_NO_ERROR) {
                log_warning(LOG_PROTOCOL, _("can't select folder: %s\n"), real_path);
        } else {
@@ -3466,12 +3494,12 @@ static gint imap_cmd_starttls(IMAPSession *session)
 static gint imap_cmd_select(IMAPSession *session, const gchar *folder,
                            gint *exists, gint *recent, gint *unseen,
                            guint32 *uid_validity, gint *can_create_flags,
-                           gboolean block)
+                           GSList **ok_flags, gboolean block)
 {
        int r;
 
        r = imap_threaded_select(session->folder, folder,
-                                exists, recent, unseen, uid_validity, can_create_flags);
+                                exists, recent, unseen, uid_validity, can_create_flags, ok_flags);
        if (r != MAILIMAP_NO_ERROR) {
                imap_handle_error(SESSION(session), r);
                debug_print("select err %d\n", r);
@@ -3619,7 +3647,9 @@ static gint imap_cmd_fetch(IMAPSession *session, guint32 uid,
 }
 
 
-static gint imap_cmd_append(IMAPSession *session, const gchar *destfolder,
+static gint imap_cmd_append(IMAPSession *session, 
+                           IMAPFolderItem *item,
+                           const gchar *destfolder,
                            const gchar *file, IMAPFlags flags, 
                            guint32 *new_uid)
 {
@@ -3628,7 +3658,7 @@ static gint imap_cmd_append(IMAPSession *session, const gchar *destfolder,
        
        g_return_val_if_fail(file != NULL, MAILIMAP_ERROR_BAD_STATE);
 
-       flag_list = imap_flag_to_lep(flags, NULL);
+       flag_list = imap_flag_to_lep(item, flags, NULL);
        lock_session(session);
        r = imap_threaded_append(session->folder, destfolder,
                         file, flag_list, (int *)new_uid);
@@ -3664,14 +3694,16 @@ static gint imap_cmd_copy(IMAPSession *session, struct mailimap_set * set,
        return MAILIMAP_NO_ERROR;
 }
 
-static gint imap_cmd_store(IMAPSession *session, struct mailimap_set * set,
+static gint imap_cmd_store(IMAPSession *session, 
+                          IMAPFolderItem *item,
+                          struct mailimap_set * set,
                           IMAPFlags flags, GSList *tags, int do_add)
 {
        int r;
        struct mailimap_flag_list * flag_list = NULL;
        struct mailimap_store_att_flags * store_att_flags;
        
-       flag_list = imap_flag_to_lep(flags, tags);
+       flag_list = imap_flag_to_lep(item, flags, tags);
 
        if (do_add)
                store_att_flags =
@@ -3802,8 +3834,11 @@ static gint get_list_of_uids(IMAPSession *session, Folder *folder, IMAPFolderIte
                uidlist = g_slist_concat(fetchuid_list, uidlist);
        } else {
                carray * lep_uidtab;
-               if (r != -1) /* inited */
+               if (r != -1) /* inited */
                        imap_handle_error(SESSION(session), r);
+                       if (is_fatal(r))
+                               return -1;
+               }
                r = imap_threaded_fetch_uid(folder, 1,
                                    &lep_uidtab);
                if (r == MAILIMAP_NO_ERROR) {
@@ -4179,6 +4214,11 @@ void imap_change_flags(Folder *folder, FolderItem *item, MsgInfo *msginfo, MsgPe
        if ( MSG_IS_REPLIED(msginfo->flags) && !(newflags & MSG_REPLIED))
                flags_unset |= IMAP_FLAG_ANSWERED;
 
+       if (!MSG_IS_FORWARDED(msginfo->flags) &&  (newflags & MSG_FORWARDED))
+               flags_set |= IMAP_FLAG_FORWARDED;
+       if ( MSG_IS_FORWARDED(msginfo->flags) && !(newflags & MSG_FORWARDED))
+               flags_unset |= IMAP_FLAG_FORWARDED;
+
        if (!MSG_IS_DELETED(msginfo->flags) &&  (newflags & MSG_DELETED))
                flags_set |= IMAP_FLAG_DELETED;
        if ( MSG_IS_DELETED(msginfo->flags) && !(newflags & MSG_DELETED))
@@ -4237,14 +4277,14 @@ void imap_change_flags(Folder *folder, FolderItem *item, MsgInfo *msginfo, MsgPe
        } else {
                debug_print("IMAP changing flags\n");
                if (flags_set) {
-                       ok = imap_set_message_flags(session, &numlist, flags_set, NULL, TRUE);
+                       ok = imap_set_message_flags(session, IMAP_FOLDER_ITEM(item), &numlist, flags_set, NULL, TRUE);
                        if (ok != MAILIMAP_NO_ERROR) {
                                return;
                        }
                }
 
                if (flags_unset) {
-                       ok = imap_set_message_flags(session, &numlist, flags_unset, NULL, FALSE);
+                       ok = imap_set_message_flags(session, IMAP_FOLDER_ITEM(item), &numlist, flags_unset, NULL, FALSE);
                        if (ok != MAILIMAP_NO_ERROR) {
                                return;
                        }
@@ -4278,7 +4318,7 @@ static gint imap_remove_msg(Folder *folder, FolderItem *item, gint uid)
        numlist.data = GINT_TO_POINTER(uid);
        
        ok = imap_set_message_flags
-               (session, &numlist, IMAP_FLAG_DELETED, NULL, TRUE);
+               (session, IMAP_FOLDER_ITEM(item), &numlist, IMAP_FLAG_DELETED, NULL, TRUE);
        if (ok != MAILIMAP_NO_ERROR) {
                log_warning(LOG_PROTOCOL, _("can't set deleted flags: %d\n"), uid);
                return ok;
@@ -4325,6 +4365,19 @@ static guint gslist_find_next_num(MsgNumberList **list, guint num)
        return elem != NULL ? GPOINTER_TO_INT(elem->data) : (gint)-1;
 }
 
+static gboolean flag_ok(IMAPFolderItem *item, guint flag)
+{
+       if (item->ok_flags && g_slist_find(item->ok_flags, GUINT_TO_POINTER(flag))) {
+               debug_print("flag %d is OK\n", flag);
+               return TRUE;
+       }
+       if (item->can_create_flags == ITEM_CAN_CREATE_FLAGS) {
+               debug_print("creating flags is OK\n");
+               return TRUE;
+       }
+       return FALSE;
+}
+
 /*
  * NEW and DELETED flags are not syncronized
  * - The NEW/RECENT flags in IMAP folders can not really be directly
@@ -4359,8 +4412,8 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
        GHashTable *tags_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 *unseen = NULL, *answered = NULL, *flagged = NULL, *deleted = NULL, *forwarded = NULL;
+       GSList *p_unseen, *p_answered, *p_flagged, *p_deleted, *p_forwarded;
        GSList *seq_list, *cur;
        gboolean reverse_seen = FALSE;
        gboolean selected_folder;
@@ -4459,6 +4512,22 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
                                        goto bail;
                                }
 
+                               if (flag_ok(IMAP_FOLDER_ITEM(fitem), IMAP_FLAG_FORWARDED)) {
+                                       r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_FORWARDED,
+                                                                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);
+
+                                               forwarded = g_slist_concat(forwarded, uidlist);
+                                       } else {
+                                               imap_handle_error(SESSION(session), r);
+                                               goto bail;
+                                       }
+                               }
+
                                r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_DELETED,
                                                         full_search ? NULL:imapset, &lep_uidlist);
                                if (r == MAILIMAP_NO_ERROR) {
@@ -4476,6 +4545,7 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
                }
                p_unseen = unseen;
                p_answered = answered;
+               p_forwarded = forwarded;
                p_flagged = flagged;
                p_deleted = deleted;
 
@@ -4504,11 +4574,11 @@ bail:
                msginfo = (MsgInfo *) elem->data;
                flags = msginfo->flags.perm_flags;
                wasnew = (flags & MSG_NEW);
-               oldflags = flags & ~(MSG_NEW|MSG_UNREAD|MSG_REPLIED|MSG_MARKED|MSG_DELETED);
+               oldflags = flags & ~(MSG_NEW|MSG_UNREAD|MSG_REPLIED|MSG_FORWARDED|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);
+                               flags &= ~((reverse_seen ? 0 : MSG_UNREAD | MSG_NEW) | MSG_REPLIED | MSG_FORWARDED | MSG_MARKED);
                        } else {
                                flags &= ~((reverse_seen ? 0 : MSG_UNREAD | MSG_NEW | MSG_MARKED));
                        }
@@ -4532,6 +4602,10 @@ bail:
                                        flags |= MSG_REPLIED;
                                else
                                        flags &= ~MSG_REPLIED;
+                               if (gslist_find_next_num(&p_forwarded, msginfo->msgnum) == msginfo->msgnum)
+                                       flags |= MSG_FORWARDED;
+                               else
+                                       flags &= ~MSG_FORWARDED;
                                if (gslist_find_next_num(&p_deleted, msginfo->msgnum) == msginfo->msgnum)
                                        flags |= MSG_DELETED;
                                else
@@ -4595,6 +4669,7 @@ bail:
        g_slist_free(flagged);
        g_slist_free(deleted);
        g_slist_free(answered);
+       g_slist_free(forwarded);
        g_slist_free(unseen);
        g_slist_free(sorted_list);
 
@@ -4667,7 +4742,8 @@ static gboolean process_flags(gpointer key, gpointer value, gpointer user_data)
                         NULL, NULL, NULL, NULL, NULL, FALSE);
        }
        if (ok == MAILIMAP_NO_ERROR) {
-               ok = imap_set_message_flags(session, data->msglist, flags_value, NULL, flags_set);
+               ok = imap_set_message_flags(session, IMAP_FOLDER_ITEM(item),
+                       data->msglist, flags_value, NULL, flags_set);
        } else {
                g_warning("can't select mailbox %s\n", item->path);
        }
@@ -4709,7 +4785,8 @@ static gboolean process_tags(gpointer key, gpointer value, gpointer user_data)
                GSList list;
                list.data = str;
                list.next = NULL;
-               ok = imap_set_message_flags(session, data->msglist, 0, &list, tags_set);
+               ok = imap_set_message_flags(session, IMAP_FOLDER_ITEM(item),
+                       data->msglist, 0, &list, tags_set);
        } else {
                g_warning("can't select mailbox %s\n", item->path);
        }
@@ -5100,28 +5177,31 @@ static void imap_lep_set_free(GSList *seq_list)
        g_slist_free(seq_list);
 }
 
-static struct mailimap_flag_list * imap_flag_to_lep(IMAPFlags flags, GSList *tags)
+static struct mailimap_flag_list * imap_flag_to_lep(IMAPFolderItem *item, IMAPFlags flags, GSList *tags)
 {
        struct mailimap_flag_list * flag_list;
        GSList *cur = tags;
 
        flag_list = mailimap_flag_list_new_empty();
        
-       if (IMAP_IS_SEEN(flags))
+       if (IMAP_IS_SEEN(flags) && flag_ok(item, IMAP_FLAG_SEEN))
                mailimap_flag_list_add(flag_list,
                                       mailimap_flag_new_seen());
-       if (IMAP_IS_ANSWERED(flags))
+       if (IMAP_IS_ANSWERED(flags) && flag_ok(item, IMAP_FLAG_ANSWERED))
                mailimap_flag_list_add(flag_list,
                                       mailimap_flag_new_answered());
-       if (IMAP_IS_FLAGGED(flags))
+       if (IMAP_IS_FLAGGED(flags) && flag_ok(item, IMAP_FLAG_FLAGGED))
                mailimap_flag_list_add(flag_list,
                                       mailimap_flag_new_flagged());
-       if (IMAP_IS_DELETED(flags))
+       if (IMAP_IS_DELETED(flags) && flag_ok(item, IMAP_FLAG_DELETED))
                mailimap_flag_list_add(flag_list,
                                       mailimap_flag_new_deleted());
-       if (IMAP_IS_DRAFT(flags))
+       if (IMAP_IS_DRAFT(flags) && flag_ok(item, IMAP_FLAG_DRAFT))
                mailimap_flag_list_add(flag_list,
                                       mailimap_flag_new_draft());
+       if (IMAP_IS_FORWARDED(flags) && flag_ok(item, IMAP_FLAG_FORWARDED))
+               mailimap_flag_list_add(flag_list,
+                                      mailimap_flag_new_flag_keyword(strdup("$Forwarded")));
        
        for (; cur; cur = cur->next) {
                gchar *enc_str = 
@@ -5148,6 +5228,25 @@ void imap_folder_ref(Folder *folder)
 void imap_disconnect_all(void)
 {
        GList *list;
+       gboolean short_timeout;
+#ifdef HAVE_NETWORKMANAGER_SUPPORT
+       GError *error;
+#endif
+
+#ifdef HAVE_NETWORKMANAGER_SUPPORT
+       error = NULL;
+       short_timeout = !networkmanager_is_online(&error);
+       if(error) {
+               short_timeout = TRUE;
+               g_error_free(error);
+       }
+#else
+       short_timeout = TRUE;
+#endif
+
+       if(short_timeout)
+               imap_main_set_timeout(1);
+
        for (list = account_get_list(); list != NULL; list = list->next) {
                PrefsAccount *account = list->data;
                if (account->protocol == A_IMAP4) {
@@ -5161,6 +5260,9 @@ void imap_disconnect_all(void)
                        }
                }
        }
+
+       if(short_timeout)
+               imap_main_set_timeout(prefs_common.io_timeout_secs);
 }
 
 void imap_folder_unref(Folder *folder)