2007-11-26 [colin] 3.1.0cvs30
authorColin Leroy <colin@colino.net>
Mon, 26 Nov 2007 22:30:58 +0000 (22:30 +0000)
committerColin Leroy <colin@colino.net>
Mon, 26 Nov 2007 22:30:58 +0000 (22:30 +0000)
* src/edittags.c
* src/folder.c
* src/folder.h
* src/imap.c
* src/messageview.c
* src/procmsg.c
* src/procmsg.h
* src/summaryview.c
* src/common/utils.c
* src/common/utils.h
* src/etpan/imap-thread.c
* src/etpan/imap-thread.h
Add IMAP tags support

15 files changed:
ChangeLog
PATCHSETS
configure.ac
src/common/utils.c
src/common/utils.h
src/edittags.c
src/etpan/imap-thread.c
src/etpan/imap-thread.h
src/folder.c
src/folder.h
src/imap.c
src/messageview.c
src/procmsg.c
src/procmsg.h
src/summaryview.c

index e9e4ff3c5955faf24e313ba8569e6094d8d7601c..3f525d27011f97b8a138d1ca85e23a589c007710 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2007-11-26 [colin]     3.1.0cvs30
+
+       * src/edittags.c
+       * src/folder.c
+       * src/folder.h
+       * src/imap.c
+       * src/messageview.c
+       * src/procmsg.c
+       * src/procmsg.h
+       * src/summaryview.c
+       * src/common/utils.c
+       * src/common/utils.h
+       * src/etpan/imap-thread.c
+       * src/etpan/imap-thread.h
+               Add IMAP tags support
+
 2007-11-26 [colin]     3.1.0cvs29
 
        * src/imap.c
index ebc08b69dbaac6f9b65007d1e6005704742b069b..52572cf17451c63562799a802843768017b03955 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
 ( cvs diff -u -r 1.2.2.24 -r 1.2.2.25 src/folder_item_prefs.c;  cvs diff -u -r 1.2.2.12 -r 1.2.2.13 src/folder_item_prefs.h;  ) > 3.1.0cvs27.patchset
 ( cvs diff -u -r 1.94.2.164 -r 1.94.2.165 src/messageview.c;  cvs diff -u -r 1.49.2.103 -r 1.49.2.104 src/procmime.c;  ) > 3.1.0cvs28.patchset
 ( cvs diff -u -r 1.179.2.198 -r 1.179.2.199 src/imap.c;  ) > 3.1.0cvs29.patchset
+( cvs diff -u -r 1.1.2.13 -r 1.1.2.14 src/edittags.c;  cvs diff -u -r 1.213.2.167 -r 1.213.2.168 src/folder.c;  cvs diff -u -r 1.87.2.50 -r 1.87.2.51 src/folder.h;  cvs diff -u -r 1.179.2.199 -r 1.179.2.200 src/imap.c;  cvs diff -u -r 1.94.2.165 -r 1.94.2.166 src/messageview.c;  cvs diff -u -r 1.150.2.105 -r 1.150.2.106 src/procmsg.c;  cvs diff -u -r 1.60.2.50 -r 1.60.2.51 src/procmsg.h;  cvs diff -u -r 1.395.2.339 -r 1.395.2.340 src/summaryview.c;  cvs diff -u -r 1.36.2.126 -r 1.36.2.127 src/common/utils.c;  cvs diff -u -r 1.20.2.55 -r 1.20.2.56 src/common/utils.h;  cvs diff -u -r 1.1.4.88 -r 1.1.4.89 src/etpan/imap-thread.c;  cvs diff -u -r 1.1.4.20 -r 1.1.4.21 src/etpan/imap-thread.h;  ) > 3.1.0cvs30.patchset
index 163a3f889bfc052b6447351136f41cb3d83f3e02..78756052e53663bff7c9a15f5a2adbeea6f2618e 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=1
 MICRO_VERSION=0
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=29
+EXTRA_VERSION=30
 EXTRA_RELEASE=
 EXTRA_GTK2_VERSION=
 
index c5d0d4c523eb13b20551a9b0fcac2d2f517ca590..3d822c4327f63ed235cb3de60a41e2492070b218 100644 (file)
@@ -1041,7 +1041,7 @@ void subst_char(gchar *str, gchar orig, gchar subst)
        }
 }
 
-static void subst_chars(gchar *str, gchar *orig, gchar subst)
+void subst_chars(gchar *str, gchar *orig, gchar subst)
 {
        register gchar *p = str;
 
index e94b4ca14624dcc6ca05aa26869165c4f961d4f3..7e0094d011eef51e8dd749e480cbf64c9cf4f06a 100644 (file)
@@ -312,6 +312,9 @@ void unfold_line                    (gchar          *str);
 void subst_char                                (gchar          *str,
                                         gchar           orig,
                                         gchar           subst);
+void subst_chars                       (gchar          *str,   
+                                        gchar          *orig, 
+                                        gchar          subst);
 void subst_for_filename                        (gchar          *str);
 void subst_for_shellsafe_filename      (gchar          *str);
 gboolean is_ascii_str                  (const gchar    *str);
index 5077633fa9e9e7a9a3c02368562caa9ff69dca2a..c76cde3748404eef1989eb8c3f0a60e7ff507380 100644 (file)
@@ -562,6 +562,7 @@ static void tag_apply_selected_edited(GtkCellRendererText *widget,
        gpointer tmp;
        gint tag_id;
        SummaryView *summaryview = NULL;
+       gboolean selected;
 
        if (mainwindow_get_mainwindow() != NULL)
                summaryview = mainwindow_get_mainwindow()->summaryview;
@@ -573,17 +574,29 @@ static void tag_apply_selected_edited(GtkCellRendererText *widget,
                return;
 
        gtk_tree_model_get(model, &iter,
+                          TAG_SELECTED, &selected,
                           TAG_DATA, &tmp,
                           -1);
 
        tag_id = GPOINTER_TO_INT(tmp);
+       
+       if (selected) {
+               if (summaryview)
+                       summary_set_tag(summaryview, -tag_id, NULL);
+       }
+       
        tags_update_tag(tag_id, new_text);
        
        gtk_list_store_set(GTK_LIST_STORE(model), &iter,
                           TAG_NAME, new_text,
                           -1);
-       if (summaryview)
-               summary_set_tag(summaryview, 0, NULL);
+       if (selected) {
+               if (summaryview)
+                       summary_set_tag(summaryview, tag_id, NULL);
+       } else  {
+               if (summaryview)
+                       summary_set_tag(summaryview, 0, NULL);
+       }       
 }
 
 static void apply_window_get_selected_state(gint tag, gboolean *selected, gboolean *selected_inconsistent)
index 14355a8ab44f37f424f824d8ac0a39d911f950a2..4a83b2b70ee2891a6a53f5def519cc6f8f5ca7e1 100644 (file)
@@ -1315,12 +1315,12 @@ static void select_run(struct etpan_thread_op * op)
 
 int imap_threaded_select(Folder * folder, const char * mb,
                         gint * exists, gint * recent, gint * unseen,
-                        guint32 * uid_validity)
+                        guint32 * uid_validity,gint *can_create_flags)
 {
        struct select_param param;
        struct select_result result;
        mailimap * imap;
-       
+
        debug_print("imap select - begin\n");
        
        imap = get_imap(folder);
@@ -1339,7 +1339,22 @@ int imap_threaded_select(Folder * folder, const char * mb,
        * recent = imap->imap_selection_info->sel_recent;
        * unseen = imap->imap_selection_info->sel_unseen;
        * uid_validity = imap->imap_selection_info->sel_uidvalidity;
-       
+       * can_create_flags = FALSE;
+
+       if (imap->imap_selection_info->sel_perm_flags) {
+               clistiter *cur =
+                       clist_begin(imap->imap_selection_info->sel_perm_flags);
+               for (; cur && !(*can_create_flags); cur = clist_next(cur)) {
+                       struct mailimap_flag_perm *flag = (struct mailimap_flag_perm *)clist_content(cur);
+                       if (flag->fl_type == MAILIMAP_FLAG_PERM_ALL)
+                               *can_create_flags = TRUE;
+                       else if (flag->fl_flag && 
+                                       flag->fl_flag->fl_type == 6 &&
+                                       !strcmp(flag->fl_flag->fl_data.fl_extension, "*"))
+                               *can_create_flags = TRUE; 
+                       
+               }
+       }
        debug_print("imap select - end\n");
        
        return result.error;
@@ -1812,7 +1827,7 @@ void imap_fetch_uid_list_free(carray * uid_list)
 
 
 
-static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn);
+static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, GSList **tags);
 
 static int
 result_to_uid_flags_list(clist * fetch_result, carray ** result)
@@ -1821,7 +1836,8 @@ result_to_uid_flags_list(clist * fetch_result, carray ** result)
        int r;
        int res;
        carray * tab;
-       
+       GSList *tags = NULL;
+
        tab = carray_new(128);
        if (tab == NULL) {
                res = MAILIMAP_ERROR_MEMORY;
@@ -1847,7 +1863,7 @@ result_to_uid_flags_list(clist * fetch_result, carray ** result)
                if (att_dyn == NULL)
                        continue;
                
-               flags = imap_flags_to_flags(att_dyn);
+               flags = imap_flags_to_flags(att_dyn, &tags);
                
                puid = malloc(sizeof(* puid));
                if (puid == NULL) {
@@ -1874,6 +1890,12 @@ result_to_uid_flags_list(clist * fetch_result, carray ** result)
                        res = MAILIMAP_ERROR_MEMORY;
                        goto free_list;
                }
+               r = carray_add(tab, tags, NULL);
+               if (r < 0) {
+                       free(pflags);
+                       res = MAILIMAP_ERROR_MEMORY;
+                       goto free_list;
+               }
        }
                
        * result = tab;
@@ -1882,6 +1904,8 @@ result_to_uid_flags_list(clist * fetch_result, carray ** result)
   
  free_list:
        imap_fetch_uid_flags_list_free(tab);
+       slist_free_strings(tags);
+       g_slist_free(tags);
  err:
        return res;
 }
@@ -2025,11 +2049,13 @@ void imap_fetch_uid_flags_list_free(carray * uid_flags_list)
 {
        unsigned int i;
        
-       for(i = 0 ; i < carray_count(uid_flags_list) ; i ++) {
+       for(i = 0 ; i < carray_count(uid_flags_list) ; i += 3) {
                void * data;
                
                data = carray_get(uid_flags_list, i);
                free(data);
+               data = carray_get(uid_flags_list, i + 1);
+               free(data);
        }
        carray_free(uid_flags_list);
 }
@@ -2348,12 +2374,13 @@ int imap_threaded_fetch_content(Folder * folder, uint32_t msg_index,
 
 
 
-static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn)
+static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, GSList **s_tags)
 {
        int flags;
        clist * flag_list;
        clistiter * cur;
-       
+       GSList *tags = NULL;
+
        flags = MSG_UNREAD;
        
        flag_list = att_dyn->att_list;
@@ -2382,10 +2409,18 @@ static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn)
                                flags &= ~MSG_UNREAD;
                                flags &= ~MSG_NEW;
                                break;
+                       case MAILIMAP_FLAG_KEYWORD:
+                               tags = g_slist_prepend(tags, g_strdup(flag_fetch->fl_flag->fl_data.fl_keyword));
+                               break;
                        }
                }
        }
-       
+       if (s_tags)
+               *s_tags = tags;
+       else {
+               slist_free_strings(tags);
+               g_slist_free(tags);
+       }
        return flags;
 }
 
@@ -2451,14 +2486,14 @@ static int imap_get_msg_att_info(struct mailimap_msg_att * msg_att,
 }
 
 static struct imap_fetch_env_info *
-fetch_to_env_info(struct mailimap_msg_att * msg_att)
+fetch_to_env_info(struct mailimap_msg_att * msg_att, GSList **tags)
 {
        struct imap_fetch_env_info * info;
        uint32_t uid;
        char * headers;
        size_t size;
        struct mailimap_msg_att_dynamic * att_dyn;
-       
+       GSList *s_tags = NULL;
        imap_get_msg_att_info(msg_att, &uid, &headers, &size,
                              &att_dyn);
        
@@ -2468,8 +2503,14 @@ fetch_to_env_info(struct mailimap_msg_att * msg_att)
        info->uid = uid;
        info->headers = strdup(headers);
        info->size = size;
-       info->flags = imap_flags_to_flags(att_dyn);
+       info->flags = imap_flags_to_flags(att_dyn, &s_tags);
        
+       if (tags)
+               *tags = s_tags;
+       else {
+               slist_free_strings(s_tags);
+               g_slist_free(s_tags);
+       }
        return info;
 }
 
@@ -2481,7 +2522,7 @@ imap_fetch_result_to_envelop_list(clist * fetch_result,
        unsigned int i;
        carray * env_list;
        i = 0;
-  
+       GSList *tags = NULL;
        env_list = carray_new(16);
   
        for(cur = clist_begin(fetch_result) ; cur != NULL ;
@@ -2491,10 +2532,11 @@ imap_fetch_result_to_envelop_list(clist * fetch_result,
     
                msg_att = clist_content(cur);
 
-               env_info = fetch_to_env_info(msg_att);
+               env_info = fetch_to_env_info(msg_att, &tags);
                if (!env_info)
                        return MAILIMAP_ERROR_MEMORY;
                carray_add(env_list, env_info, NULL);
+               carray_add(env_list, tags, NULL);
        }
   
        * p_env_list = env_list;
@@ -2704,7 +2746,7 @@ void imap_fetch_env_free(carray * env_list)
 {
        unsigned int i;
        
-       for(i = 0 ; i < carray_count(env_list) ; i ++) {
+       for(i = 0 ; i < carray_count(env_list) ; i += 2) {
                struct imap_fetch_env_info * env_info;
                
                env_info = carray_get(env_list, i);
index ead7b23308b1d1eae2e9a46f4908384d821ea43a..88d4ded6017a2f11ad781db6a45acd0fd3d608fe 100644 (file)
@@ -68,7 +68,7 @@ int imap_threaded_rename(Folder * folder,
 int imap_threaded_delete(Folder * folder, const char * mb);
 int imap_threaded_select(Folder * folder, const char * mb,
                         gint * exists, gint * recent, gint * unseen,
-                        guint32 * uid_validity);
+                        guint32 * uid_validity, gint * can_create_flags);
 int imap_threaded_examine(Folder * folder, const char * mb,
                          gint * exists, gint * recent, gint * unseen,
                          guint32 * uid_validity);
index 8d299aeeac79726e844200a1f4c7d40aeb36e148..2f268f51165c78e20812b8d3b5b1df41d6cc65ce 100644 (file)
@@ -3498,6 +3498,27 @@ void folder_item_change_msg_flags(FolderItem *item, MsgInfo *msginfo, MsgPermFla
        }
 }
 
+void folder_item_commit_tags(FolderItem *item, MsgInfo *msginfo, GSList *tags_set, GSList *tags_unset)
+{
+       Folder *folder = NULL;
+
+       if (!msginfo)
+               return;
+       if (!item)
+               return;
+       if (!tags_set && !tags_unset)
+               return;
+
+       folder = item->folder;
+       if (!folder)
+               return;
+       
+       if (folder->klass->commit_tags == NULL)
+               return;
+       
+       folder->klass->commit_tags(item, msginfo, tags_set, tags_unset);
+}
+
 gboolean folder_item_is_msg_changed(FolderItem *item, MsgInfo *msginfo)
 {
        Folder *folder;
index 5f960296eb2f5e5364ac3d1692f48b4af492e29f..dd3faec249efe43ae99fb6d23f54762da518c562 100644 (file)
@@ -617,6 +617,10 @@ struct _FolderClass
        void            (*remove_cached_msg)    (Folder         *folder,
                                                 FolderItem     *item,
                                                 MsgInfo        *msginfo);
+       void            (*commit_tags)          (FolderItem     *item,
+                                                MsgInfo        *msginfo,
+                                                GSList         *tags_set,
+                                                GSList         *tags_unset);
 };
 
 struct _FolderItem
@@ -865,4 +869,6 @@ gboolean folder_get_sort_type               (Folder         *folder,
                                         FolderSortType *sort_type);
 void folder_item_synchronise           (FolderItem *item);
 void folder_item_discard_cache         (FolderItem *item);
+void folder_item_commit_tags(FolderItem *item, MsgInfo *msginfo, GSList *tags_set, GSList *tags_unset);
+
 #endif /* __FOLDER_H__ */
index d09da6b894cb441e02a4ea26caca1d60f322f70f..fd3c81a641dbaf32d911c1d5d068140375ffae50 100644 (file)
@@ -69,6 +69,7 @@
 #include "msgcache.h"
 #include "imap-thread.h"
 #include "account.h"
+#include "tags.h"
 
 typedef struct _IMAPFolder     IMAPFolder;
 typedef struct _IMAPSession    IMAPSession;
@@ -152,6 +153,12 @@ typedef enum
 
 #define IMAP_CMD_LIMIT 1000
 
+enum {
+       ITEM_CAN_CREATE_FLAGS_UNKNOWN = 0,
+       ITEM_CAN_CREATE_FLAGS,
+       ITEM_CANNOT_CREATE_FLAGS
+};
+
 struct _IMAPFolderItem
 {
        FolderItem item;
@@ -167,6 +174,11 @@ struct _IMAPFolderItem
        guint32 last_sync;
        gboolean should_update;
        gboolean should_trash_cache;
+       gint can_create_flags;
+
+       GHashTable *tags_set_table;
+       GHashTable *tags_unset_table;
+
 };
 
 static XMLTag *imap_item_get_xml(Folder *folder, FolderItem *item);
@@ -277,14 +289,16 @@ static void imap_set_batch                (Folder         *folder,
 static gint imap_set_message_flags     (IMAPSession    *session,
                                         MsgNumberList  *numlist,
                                         IMAPFlags       flags,
+                                        GSList         *tags,
                                         gboolean        is_set);
 static gint imap_select                        (IMAPSession    *session,
                                         IMAPFolder     *folder,
-                                        const gchar    *path,
+                                        FolderItem     *item,
                                         gint           *exists,
                                         gint           *recent,
                                         gint           *unseen,
                                         guint32        *uid_validity,
+                                        gint           *can_create_flags,
                                         gboolean        block);
 static gint imap_status                        (IMAPSession    *session,
                                         IMAPFolder     *folder,
@@ -295,6 +309,10 @@ static gint imap_status                    (IMAPSession    *session,
                                         guint32        *uid_validity,
                                         gint           *unseen,
                                         gboolean        block);
+static void    imap_commit_tags        (FolderItem     *item, 
+                                        MsgInfo        *msginfo,
+                                        GSList         *set_tags,
+                                        GSList         *unset_tags);
 
 static gchar imap_get_path_separator           (IMAPSession    *session,
                                                 IMAPFolder     *folder,
@@ -324,6 +342,7 @@ static gint imap_cmd_select (IMAPSession    *session,
                                 gint           *recent,
                                 gint           *unseen,
                                 guint32        *uid_validity,
+                                gint           *can_create_flags,
                                 gboolean        block);
 static gint imap_cmd_close     (IMAPSession    *session);
 static gint imap_cmd_examine   (IMAPSession    *session,
@@ -359,14 +378,15 @@ static gint imap_cmd_copy       (IMAPSession *session,
 static gint imap_cmd_store     (IMAPSession    *session,
                                 struct mailimap_set * set,
                                 IMAPFlags flags,
+                                GSList *tags,
                                 int do_add);
 static gint imap_cmd_expunge   (IMAPSession    *session);
 
 static void imap_path_separator_subst          (gchar          *str,
                                                 gchar           separator);
 
-static gchar *imap_utf8_to_modified_utf7       (const gchar    *from);
-static gchar *imap_modified_utf7_to_utf8       (const gchar    *mutf7_str);
+static gchar *imap_utf8_to_modified_utf7       (const gchar    *from, gboolean change_spaces);
+static gchar *imap_modified_utf7_to_utf8       (const gchar    *mutf7_str, gboolean change_spaces);
 
 static gboolean imap_rename_folder_func                (GNode          *node,
                                                 gpointer        data);
@@ -404,11 +424,12 @@ static GSList * imap_get_lep_set_from_msglist(IMAPFolder *folder, MsgInfoList *m
 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);
+                                                  GHashTable * hash,
+                                                  GHashTable *tags_hash);
 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);
+static struct mailimap_flag_list * imap_flag_to_lep(IMAPFlags flags, GSList *tags);
 
 typedef struct _hashtable_data {
        GSList *msglist;
@@ -473,6 +494,7 @@ FolderClass *imap_get_class(void)
                imap_class.set_batch = imap_set_batch;
                imap_class.synchronise = imap_synchronise;
                imap_class.remove_cached_msg = imap_remove_cached_msg;
+               imap_class.commit_tags = imap_commit_tags;
 #ifdef USE_PTREAD
                pthread_mutex_init(&imap_mutex, NULL);
 #endif
@@ -1219,6 +1241,120 @@ static void imap_remove_cached_msg(Folder *folder, FolderItem *item, MsgInfo *ms
        g_free(filename);
 }
 
+typedef struct _TagsData {
+       gchar *str;
+       GSList *msglist;
+       IMAPFolderItem *item;
+} TagsData;
+
+static void imap_commit_tags(FolderItem *item, MsgInfo *msginfo, GSList *tags_set, GSList *tags_unset)
+{
+       IMAPSession *session;
+       gint ok, can_create_tags;
+       Folder *folder = NULL;
+       TagsData *ht_data = NULL;
+       GSList *cur;
+
+       g_return_if_fail(item != NULL);
+       g_return_if_fail(msginfo != NULL);
+
+       folder = item->folder;
+       debug_print("getting session...\n");
+       session = imap_session_get(folder);
+       
+       if (!session) {
+               debug_print("can't get session\n");
+               return;
+       }
+
+       ok = imap_select(session, IMAP_FOLDER(folder), item,
+                        NULL, NULL, NULL, NULL, &can_create_tags, FALSE);
+
+       if (ok != MAILIMAP_NO_ERROR) {
+               imap_handle_error(SESSION(session), ok);
+               return;
+       }
+
+       
+       if (IMAP_FOLDER_ITEM(item)->can_create_flags != ITEM_CAN_CREATE_FLAGS)
+               return;
+       
+       if (IMAP_FOLDER_ITEM(item)->batching) {
+               /* instead of performing an UID STORE command for each message change,
+                * as a lot of them can change "together", we just fill in hashtables
+                * and defer the treatment so that we're able to send only one
+                * command.
+                */
+               debug_print("IMAP batch mode on, deferring tags change\n");
+               for (cur = tags_set; cur; cur = cur->next) {
+                       gint cur_tag = GPOINTER_TO_INT(cur->data);
+                       if (cur_tag) {
+                               ht_data = g_hash_table_lookup(IMAP_FOLDER_ITEM(item)->tags_set_table, 
+                                       GINT_TO_POINTER(cur_tag));
+                               if (ht_data == NULL) {
+                                       ht_data = g_new0(TagsData, 1);
+                                       ht_data->str = g_strdup(tags_get_tag(cur_tag));
+                                       ht_data->item = IMAP_FOLDER_ITEM(item);
+                                       g_hash_table_insert(IMAP_FOLDER_ITEM(item)->tags_set_table, 
+                                               GINT_TO_POINTER(cur_tag), ht_data);
+                               }
+                               ht_data->msglist = g_slist_prepend(ht_data->msglist, GINT_TO_POINTER(msginfo->msgnum));
+                       } 
+               }
+               for (cur = tags_unset; cur; cur = cur->next) {
+                       gint cur_tag = GPOINTER_TO_INT(cur->data);
+                       if (cur_tag) {
+                               ht_data = g_hash_table_lookup(IMAP_FOLDER_ITEM(item)->tags_unset_table, 
+                                       GINT_TO_POINTER(cur_tag));
+                               if (ht_data == NULL) {
+                                       ht_data = g_new0(TagsData, 1);
+                                       ht_data->str = g_strdup(tags_get_tag(cur_tag));
+                                       ht_data->item = IMAP_FOLDER_ITEM(item);
+                                       g_hash_table_insert(IMAP_FOLDER_ITEM(item)->tags_unset_table, 
+                                               GINT_TO_POINTER(cur_tag), ht_data);
+                               }
+                               ht_data->msglist = g_slist_prepend(ht_data->msglist, GINT_TO_POINTER(msginfo->msgnum));
+                       }
+               }
+       } else {
+               GSList *list_set = NULL;
+               GSList *list_unset = NULL;
+               GSList numlist;
+               
+               numlist.data = GINT_TO_POINTER(msginfo->msgnum);
+               numlist.next = NULL;
+       
+               debug_print("IMAP changing tags NOW\n");
+               for (cur = tags_set; cur; cur = cur->next) {
+                       gint cur_tag = GPOINTER_TO_INT(cur->data);
+                       const gchar *str = tags_get_tag(cur_tag);
+                       list_set = g_slist_prepend(list_set, g_strdup(str));
+               }
+               if (list_set) {
+                       ok = imap_set_message_flags(session, &numlist, 0, list_set, TRUE);
+                       slist_free_strings(list_set);
+                       g_slist_free(list_set);
+                       if (ok != MAILIMAP_NO_ERROR) {
+                               return;
+                       }
+               }
+
+               for (cur = tags_unset; cur; cur = cur->next) {
+                       gint cur_tag = GPOINTER_TO_INT(cur->data);
+                       const gchar *str = tags_get_tag(cur_tag);
+                       list_unset = g_slist_prepend(list_unset, g_strdup(str));
+               }
+               if (list_unset) {
+                       ok = imap_set_message_flags(session, &numlist, 0, list_unset, FALSE);
+                       slist_free_strings(list_unset);
+                       g_slist_free(list_unset);
+                       if (ok != MAILIMAP_NO_ERROR) {
+                               return;
+                       }
+               }
+       }
+}
+
 static gchar *imap_fetch_msg_full(Folder *folder, FolderItem *item, gint uid,
                                  gboolean headers, gboolean body)
 {
@@ -1292,8 +1428,8 @@ static gchar *imap_fetch_msg_full(Folder *folder, FolderItem *item, gint uid,
        lock_session(session); /* unlocked later in the function */
 
        debug_print("IMAP fetching messages\n");
-       ok = imap_select(session, IMAP_FOLDER(folder), item->path,
-                        NULL, NULL, NULL, NULL, FALSE);
+       ok = imap_select(session, IMAP_FOLDER(folder), item,
+                        NULL, NULL, NULL, NULL, NULL, FALSE);
        if (ok != MAILIMAP_NO_ERROR) {
                g_warning("can't select mailbox %s\n", item->path);
                g_free(filename);
@@ -1518,8 +1654,8 @@ static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
        }
        if (missing_uids) {
                gint a;
-               ok = imap_select(session, IMAP_FOLDER(folder), dest->path,
-                        &a, NULL, NULL, NULL, FALSE);
+               ok = imap_select(session, IMAP_FOLDER(folder), dest,
+                        &a, NULL, NULL, NULL, NULL, FALSE);
        }
        return last_uid;
 }
@@ -1606,8 +1742,8 @@ static gint imap_do_copy_msgs(Folder *folder, FolderItem *dest,
 
        lock_session(session); /* unlocked later in the function */
 
-       ok = imap_select(session, IMAP_FOLDER(folder), msginfo->folder->path,
-                        NULL, NULL, NULL, NULL, FALSE);
+       ok = imap_select(session, IMAP_FOLDER(folder), msginfo->folder,
+                        NULL, NULL, NULL, NULL, NULL, FALSE);
        if (ok != MAILIMAP_NO_ERROR) {
                return ok;
        }
@@ -1788,8 +1924,8 @@ static gint imap_do_remove_msgs(Folder *folder, FolderItem *dest,
 
        msginfo = (MsgInfo *)msglist->data;
 
-       ok = imap_select(session, IMAP_FOLDER(folder), msginfo->folder->path,
-                        NULL, NULL, NULL, NULL, FALSE);
+       ok = imap_select(session, IMAP_FOLDER(folder), msginfo->folder,
+                        NULL, NULL, NULL, NULL, NULL, FALSE);
        if (ok != MAILIMAP_NO_ERROR) {
                return ok;
        }
@@ -1807,7 +1943,7 @@ static gint imap_do_remove_msgs(Folder *folder, FolderItem *dest,
 
        if (numlist != NULL) {
                ok = imap_set_message_flags
-                       (session, numlist, IMAP_FLAG_DELETED, TRUE);
+                       (session, numlist, IMAP_FLAG_DELETED, NULL, TRUE);
                if (ok != MAILIMAP_NO_ERROR) {
                        log_warning(LOG_PROTOCOL, _("can't set deleted flags\n"));
                        return ok;
@@ -2366,7 +2502,7 @@ static FolderItem *imap_create_folder(Folder *folder, FolderItem *parent,
 
        /* keep trailing directory separator to create a folder that contains
           sub folder */
-       imap_path = imap_utf8_to_modified_utf7(dirpath);
+       imap_path = imap_utf8_to_modified_utf7(dirpath, FALSE);
 
        strtailchomp(dirpath, '/');
        Xstrdup_a(new_name, name, {
@@ -2519,7 +2655,7 @@ static gint imap_rename_folder(Folder *folder, FolderItem *item,
        } else
                newpath = g_strdup(name);
 
-       real_newpath = imap_utf8_to_modified_utf7(newpath);
+       real_newpath = imap_utf8_to_modified_utf7(newpath, FALSE);
        imap_path_separator_subst(real_newpath, separator);
 
        ok = imap_cmd_rename(session, real_oldpath, real_newpath);
@@ -2718,14 +2854,40 @@ static void *imap_get_uncached_messages_thread(void *data)
                session_set_access_time(SESSION(session));
 
                count = 0;
-               for(i = 0 ; i < carray_count(env_list) ; i ++) {
+               for(i = 0 ; i < carray_count(env_list) ; i += 2) {
                        struct imap_fetch_env_info * info;
                        MsgInfo * msginfo;
-                       
+                       GSList *tags = NULL, *cur = NULL;
                        info = carray_get(env_list, i);
+                       tags = carray_get(env_list, i+1);
                        msginfo = imap_envelope_from_lep(info, item);
-                       if (msginfo == NULL)
+                       if (msginfo == NULL) {
+                               slist_free_strings(tags);
+                               g_slist_free(tags);
                                continue;
+                       }
+                       if (tags != NULL) {
+                               g_slist_free(msginfo->tags);
+                               msginfo->tags = NULL;
+                       }
+                       for (cur = tags; cur; cur = cur->next) {
+                               gchar *real_tag = imap_modified_utf7_to_utf8(cur->data, FALSE);
+                               gint id = 0;
+                               id = tags_get_id_for_str(real_tag);
+                               if (id == -1) {
+                                       id = tags_add_tag(real_tag);
+                                       tags_write_tags();
+                                       main_window_reflect_tags_changes(mainwindow_get_mainwindow());
+                               }
+                               if (!g_slist_find(msginfo->tags, GINT_TO_POINTER(id))) {
+                                       msginfo->tags = g_slist_append(
+                                                       msginfo->tags,
+                                                       GINT_TO_POINTER(id));
+                               }
+                               g_free(real_tag);
+                       }
+                       slist_free_strings(tags);
+                       g_slist_free(tags);
                        msginfo->folder = item;
                        if (!newlist)
                                llast = newlist = g_slist_append(newlist, msginfo);
@@ -2929,7 +3091,7 @@ static gchar *imap_get_real_path(IMAPSession *session, IMAPFolder *folder, const
        g_return_val_if_fail(folder != NULL, NULL);
        g_return_val_if_fail(path != NULL, NULL);
 
-       real_path = imap_utf8_to_modified_utf7(path);
+       real_path = imap_utf8_to_modified_utf7(path, FALSE);
        separator = imap_get_path_separator(session, folder, path);
        imap_path_separator_subst(real_path, separator);
 
@@ -2939,6 +3101,7 @@ static gchar *imap_get_real_path(IMAPSession *session, IMAPFolder *folder, const
 static gint imap_set_message_flags(IMAPSession *session,
                                   MsgNumberList *numlist,
                                   IMAPFlags flags,
+                                  GSList *tags,
                                   gboolean is_set)
 {
        gint ok = 0;
@@ -2973,7 +3136,7 @@ static gint imap_set_message_flags(IMAPSession *session,
                statusbar_progress_all(set_item->set_first, total, 1);
 
                ok = imap_cmd_store(session, imapset,
-                                   flags, is_set);
+                                   flags, tags, is_set);
                statusbar_progress_all(set_item->set_last, total, 1);
                if (ok != MAILIMAP_NO_ERROR && folder->max_set_size > 20) {
                        /* reduce max set size */
@@ -3005,19 +3168,32 @@ typedef struct _select_data {
 } select_data;
 
 static gint imap_select(IMAPSession *session, IMAPFolder *folder,
-                       const gchar *path,
+                       FolderItem *item,
                        gint *exists, gint *recent, gint *unseen,
-                       guint32 *uid_validity, gboolean block)
+                       guint32 *uid_validity, gint *can_create_flags,
+                       gboolean block)
 {
        gchar *real_path;
        gint ok;
        gint exists_, recent_, unseen_;
        guint32 uid_validity_;
-       
-       if (!exists && !recent && !unseen && !uid_validity) {
+       gint can_create_flags_;
+       const gchar *path = item ? item->path:NULL;
+
+       if (!item) {
+               return MAILIMAP_ERROR_BAD_STATE;
+       }
+
+       if (!exists && !recent && !unseen && !uid_validity && !can_create_flags) {
                if (session->mbox && strcmp(session->mbox, path) == 0)
                        return MAILIMAP_NO_ERROR;
        }
+       if (!exists && !recent && !unseen && !uid_validity && can_create_flags) {
+               if (session->mbox && strcmp(session->mbox, path) == 0) {
+                       if (IMAP_FOLDER_ITEM(item)->can_create_flags != ITEM_CAN_CREATE_FLAGS_UNKNOWN)
+                               return MAILIMAP_NO_ERROR;
+               }
+       }
        if (!exists)
                exists = &exists_;
        if (!recent)
@@ -3026,6 +3202,8 @@ static gint imap_select(IMAPSession *session, IMAPFolder *folder,
                unseen = &unseen_;
        if (!uid_validity)
                uid_validity = &uid_validity_;
+       if (!can_create_flags)
+               can_create_flags = &can_create_flags_;
 
        g_free(session->mbox);
        session->mbox = NULL;
@@ -3036,7 +3214,7 @@ static gint imap_select(IMAPSession *session, IMAPFolder *folder,
        real_path = imap_get_real_path(session, folder, path);
 
        ok = imap_cmd_select(session, real_path,
-                            exists, recent, unseen, uid_validity, block);
+                            exists, recent, unseen, uid_validity, can_create_flags, block);
        if (ok != MAILIMAP_NO_ERROR) {
                log_warning(LOG_PROTOCOL, _("can't select folder: %s\n"), real_path);
        } else {
@@ -3047,9 +3225,14 @@ static gint imap_select(IMAPSession *session, IMAPFolder *folder,
                session->expunge = 0;
                session->unseen = *unseen;
                session->uid_validity = *uid_validity;
-               debug_print("select: exists %d recent %d expunge %d uid_validity %d\n", 
+               debug_print("select: exists %d recent %d expunge %d uid_validity %d can_create_flags %d\n", 
                        session->exists, session->recent, session->expunge,
-                       session->uid_validity);
+                       session->uid_validity, *can_create_flags);
+       }
+       if (can_create_flags) {
+               IMAP_FOLDER_ITEM(item)->can_create_flags = ITEM_CAN_CREATE_FLAGS;
+       } else {
+               IMAP_FOLDER_ITEM(item)->can_create_flags = ITEM_CANNOT_CREATE_FLAGS;
        }
        g_free(real_path);
 
@@ -3281,12 +3464,13 @@ 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, gboolean block)
+                           guint32 *uid_validity, gint *can_create_flags,
+                           gboolean block)
 {
        int r;
 
        r = imap_threaded_select(session->folder, folder,
-                                exists, recent, unseen, uid_validity);
+                                exists, recent, unseen, uid_validity, can_create_flags);
        if (r != MAILIMAP_NO_ERROR) {
                imap_handle_error(SESSION(session), r);
                debug_print("select err %d\n", r);
@@ -3443,7 +3627,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);
+       flag_list = imap_flag_to_lep(flags, NULL);
        lock_session(session);
        r = imap_threaded_append(session->folder, destfolder,
                         file, flag_list, (int *)new_uid);
@@ -3480,14 +3664,14 @@ static gint imap_cmd_copy(IMAPSession *session, struct mailimap_set * set,
 }
 
 static gint imap_cmd_store(IMAPSession *session, struct mailimap_set * set,
-                          IMAPFlags flags, int do_add)
+                          IMAPFlags flags, GSList *tags, int do_add)
 {
        int r;
-       struct mailimap_flag_list * flag_list;
+       struct mailimap_flag_list * flag_list = NULL;
        struct mailimap_store_att_flags * store_att_flags;
        
-       flag_list = imap_flag_to_lep(flags);
-       
+       flag_list = imap_flag_to_lep(flags, tags);
+
        if (do_add)
                store_att_flags =
                        mailimap_store_att_flags_new_add_flags_silent(flag_list);
@@ -3571,7 +3755,7 @@ static char base64chars[] =
  *     (worst case: 8 octets UTF-7 becomes 9 octets UTF-8)
  */
 static char*
-imap_modified_utf7_to_utf8(const char *mbox)
+imap_modified_utf7_to_utf8(const char *mbox, gboolean change_spaces)
 {
   unsigned c, i, bitcount;
   unsigned long ucs4, utf16, bitbuf;
@@ -3595,7 +3779,10 @@ imap_modified_utf7_to_utf8(const char *mbox)
     /* deal with literal characters and &- */
     if (c != '&' || *src == '-') {
       /* encode literally */
-      *dst++ = c;
+      if (change_spaces && c == '_')
+       *dst++ = ' ';
+      else
+        *dst++ = c;
       /* skip over the '-' if this is an &- sequence */
       if (c == '&') ++src;
     } else {
@@ -3660,7 +3847,7 @@ imap_modified_utf7_to_utf8(const char *mbox)
  *  coded URLs
  */
 static char*
-imap_utf8_to_modified_utf7(const char *src)
+imap_utf8_to_modified_utf7(const char *src, gboolean change_spaces)
 {
   unsigned int utf8pos, utf8total, c, utf7mode, bitstogo, utf16flag;
   unsigned long ucs4 = 0, bitbuf = 0;
@@ -3677,7 +3864,7 @@ imap_utf8_to_modified_utf7(const char *src)
   while ((c = (unsigned char)*src) != '\0') {
     ++src;
     /* normal character? */
-    if (c >= ' ' && c <= '~') {
+    if (c >= ' ' && c <= '~' && (c != '_' || !change_spaces)) {
       /* switch out of UTF-7 mode */
       if (utf7mode) {
         if (bitstogo) {
@@ -3689,7 +3876,10 @@ imap_utf8_to_modified_utf7(const char *src)
         bitstogo = 0;
         utf8total= 0;
       }
-      *dst++ = c;
+      if (change_spaces && c == ' ')
+        *dst++ = '_';
+      else
+       *dst++ = c;
       /* encode '&' as '&-' */
       if (c == '&') {
         *dst++ = '-';
@@ -3812,8 +4002,8 @@ static gint get_list_of_uids(IMAPSession *session, Folder *folder, IMAPFolderIte
                return -1;
        }
 
-       ok = imap_select(session, IMAP_FOLDER(folder), item->item.path,
-                        NULL, NULL, NULL, NULL, TRUE);
+       ok = imap_select(session, IMAP_FOLDER(folder), FOLDER_ITEM(item),
+                        NULL, NULL, NULL, NULL, NULL, TRUE);
        if (ok != MAILIMAP_NO_ERROR) {
                return -1;
        }
@@ -4010,8 +4200,8 @@ GSList *imap_get_msginfos(Folder *folder, FolderItem *item,
        lock_session(session); /* unlocked later in the function */
 
        debug_print("IMAP getting msginfos\n");
-       ok = imap_select(session, IMAP_FOLDER(folder), item->path,
-                        NULL, NULL, NULL, NULL, FALSE);
+       ok = imap_select(session, IMAP_FOLDER(folder), item,
+                        NULL, NULL, NULL, NULL, NULL, FALSE);
        if (ok != MAILIMAP_NO_ERROR) {
                return NULL;
        }
@@ -4231,8 +4421,8 @@ void imap_change_flags(Folder *folder, FolderItem *item, MsgInfo *msginfo, MsgPe
                return;
        }
 
-       if ((ok = imap_select(session, IMAP_FOLDER(folder), msginfo->folder->path,
-           NULL, NULL, NULL, NULL, FALSE)) != MAILIMAP_NO_ERROR) {
+       if ((ok = imap_select(session, IMAP_FOLDER(folder), msginfo->folder,
+           NULL, NULL, NULL, NULL, NULL, FALSE)) != MAILIMAP_NO_ERROR) {
                return;
        }
        numlist.next = NULL;
@@ -4271,14 +4461,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, TRUE);
+                       ok = imap_set_message_flags(session, &numlist, flags_set, NULL, TRUE);
                        if (ok != MAILIMAP_NO_ERROR) {
                                return;
                        }
                }
 
                if (flags_unset) {
-                       ok = imap_set_message_flags(session, &numlist, flags_unset, FALSE);
+                       ok = imap_set_message_flags(session, &numlist, flags_unset, NULL, FALSE);
                        if (ok != MAILIMAP_NO_ERROR) {
                                return;
                        }
@@ -4303,8 +4493,8 @@ static gint imap_remove_msg(Folder *folder, FolderItem *item, gint uid)
        session = imap_session_get(folder);
        if (!session) return -1;
 
-       ok = imap_select(session, IMAP_FOLDER(folder), item->path,
-                        NULL, NULL, NULL, NULL, FALSE);
+       ok = imap_select(session, IMAP_FOLDER(folder), item,
+                        NULL, NULL, NULL, NULL, NULL, FALSE);
        if (ok != MAILIMAP_NO_ERROR) {
                return ok;
        }
@@ -4312,7 +4502,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, TRUE);
+               (session, &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;
@@ -4390,6 +4580,7 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
        gint ok;
        int r = MAILIMAP_NO_ERROR;
        GHashTable *flags_hash = NULL;
+       GHashTable *tags_hash = NULL;
        gboolean full_search = stuff->full_search;
        GSList *sorted_list = NULL;
        GSList *unseen = NULL, *answered = NULL, *flagged = NULL, *deleted = NULL;
@@ -4410,8 +4601,8 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
 
        lock_session(session);
        if (!selected_folder) {
-               ok = imap_select(session, IMAP_FOLDER(folder), fitem->path,
-                       &exists_cnt, NULL, &unseen_cnt, NULL, TRUE);
+               ok = imap_select(session, IMAP_FOLDER(folder), fitem,
+                       &exists_cnt, NULL, &unseen_cnt, NULL, NULL, TRUE);
                if (ok != MAILIMAP_NO_ERROR) {
                        stuff->done = TRUE;
                        return GINT_TO_POINTER(-1);
@@ -4514,8 +4705,9 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
        } 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);
+                       flags_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
+                       tags_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
+                       imap_flags_hash_from_lep_uid_flags_tab(lep_uidtab, flags_hash, tags_hash);
                        imap_fetch_uid_flags_list_free(lep_uidtab);
                } else {
                        imap_handle_error(SESSION(session), r);
@@ -4570,13 +4762,9 @@ bail:
                        }
                } 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);
+                               flags = GPOINTER_TO_INT(g_hash_table_lookup(flags_hash, 
+                                               GINT_TO_POINTER(msginfo->msgnum)));
                        }
 
                        if ((flags & MSG_UNREAD) == 0)
@@ -4584,6 +4772,33 @@ bail:
                        else if (wasnew)
                                flags |= MSG_NEW;
                        flags |= oldflags;
+                       
+                       if (tags_hash != NULL) {
+                               GSList *tags = g_hash_table_lookup(tags_hash, GINT_TO_POINTER(msginfo->msgnum));
+                               GSList *cur;
+                               if (tags != NULL) {
+                                       g_slist_free(msginfo->tags);
+                                       msginfo->tags = NULL;
+                               }
+                               for (cur = tags; cur; cur = cur->next) {
+                                       gchar *real_tag = imap_modified_utf7_to_utf8(cur->data, FALSE);
+                                       gint id = 0;
+                                       id = tags_get_id_for_str(real_tag);
+                                       if (id == -1) {
+                                               id = tags_add_tag(real_tag);
+                                               tags_write_tags();
+                                               main_window_reflect_tags_changes(mainwindow_get_mainwindow());
+                                       }
+                                       if (!g_slist_find(msginfo->tags, GINT_TO_POINTER(id))) {
+                                               msginfo->tags = g_slist_append(
+                                                               msginfo->tags,
+                                                               GINT_TO_POINTER(id));
+                                       }
+                                       g_free(real_tag);
+                               }
+                               slist_free_strings(tags);
+                               g_slist_free(tags);
+                       }
                }
 
                g_relation_insert(msgflags, msginfo, GINT_TO_POINTER(flags));
@@ -4591,6 +4806,8 @@ bail:
        
        if (flags_hash)
                g_hash_table_destroy(flags_hash);
+       if (tags_hash)
+               g_hash_table_destroy(tags_hash);
 
        imap_lep_set_free(seq_list);
        g_slist_free(flagged);
@@ -4664,11 +4881,53 @@ static gboolean process_flags(gpointer key, gpointer value, gpointer user_data)
        
        lock_session(session);
        if (session) {
-               ok = imap_select(session, IMAP_FOLDER(item->folder), item->path,
-                        NULL, NULL, NULL, NULL, FALSE);
+               ok = imap_select(session, IMAP_FOLDER(item->folder), item,
+                        NULL, NULL, NULL, NULL, NULL, FALSE);
+       }
+       if (ok == MAILIMAP_NO_ERROR) {
+               ok = imap_set_message_flags(session, data->msglist, flags_value, NULL, flags_set);
+       } else {
+               g_warning("can't select mailbox %s\n", item->path);
+       }
+
+       if (!is_fatal(ok))
+               unlock_session(session);
+
+       g_slist_free(data->msglist);    
+       g_free(data);
+       return TRUE;
+}
+
+static gboolean process_tags(gpointer key, gpointer value, gpointer user_data)
+{
+       gboolean tags_set = GPOINTER_TO_INT(user_data);
+       TagsData *data = (TagsData *)value;
+       IMAPFolderItem *_item = data->item;
+       FolderItem *item = (FolderItem *)_item;
+       gchar *str = data->str;
+       gint ok = MAILIMAP_ERROR_BAD_STATE;
+       IMAPSession *session = NULL;
+       
+       debug_print("getting session...\n");
+       session = imap_session_get(item->folder);
+
+       data->msglist = g_slist_reverse(data->msglist);
+       
+       debug_print("IMAP %ssetting tags %s for %d messages\n",
+               tags_set?"":"un",
+               str,
+               g_slist_length(data->msglist));
+       
+       lock_session(session);
+       if (session) {
+               ok = imap_select(session, IMAP_FOLDER(item->folder), item,
+                        NULL, NULL, NULL, NULL, NULL, FALSE);
        }
        if (ok == MAILIMAP_NO_ERROR) {
-               ok = imap_set_message_flags(session, data->msglist, flags_value, flags_set);
+               GSList list;
+               list.data = str;
+               list.next = NULL;
+               ok = imap_set_message_flags(session, data->msglist, 0, &list, tags_set);
        } else {
                g_warning("can't select mailbox %s\n", item->path);
        }
@@ -4677,6 +4936,7 @@ static gboolean process_flags(gpointer key, gpointer value, gpointer user_data)
                unlock_session(session);
 
        g_slist_free(data->msglist);    
+       g_free(data->str);
        g_free(data);
        return TRUE;
 }
@@ -4693,6 +4953,16 @@ static void process_hashtable(IMAPFolderItem *item)
                g_hash_table_destroy(item->flags_unset_table);
                item->flags_unset_table = NULL;
        }
+       if (item->tags_set_table) {
+               g_hash_table_foreach_remove(item->tags_set_table, process_tags, GINT_TO_POINTER(TRUE));
+               g_hash_table_destroy(item->tags_set_table);
+               item->tags_set_table = NULL;
+       }
+       if (item->tags_unset_table) {
+               g_hash_table_foreach_remove(item->tags_unset_table, process_tags, GINT_TO_POINTER(FALSE));
+               g_hash_table_destroy(item->tags_unset_table);
+               item->tags_unset_table = NULL;
+       }
        
 }
 
@@ -4715,6 +4985,12 @@ static void imap_set_batch (Folder *folder, FolderItem *_item, gboolean batch)
                if (!item->flags_unset_table) {
                        item->flags_unset_table = g_hash_table_new(NULL, g_direct_equal);
                }
+               if (!item->tags_set_table) {
+                       item->tags_set_table = g_hash_table_new(NULL, g_direct_equal);
+               }
+               if (!item->tags_unset_table) {
+                       item->tags_unset_table = g_hash_table_new(NULL, g_direct_equal);
+               }
                session = imap_session_get(folder);
                if (session) {
                        imap_refresh_sensitivity(session);
@@ -4830,8 +5106,8 @@ static GSList * imap_list_from_lep(IMAPFolder * folder,
                        dup_name[strlen(dup_name)-1] = '\0';
                }
                
-               loc_name = imap_modified_utf7_to_utf8(base);
-               loc_path = imap_modified_utf7_to_utf8(dup_name);
+               loc_name = imap_modified_utf7_to_utf8(base, FALSE);
+               loc_path = imap_modified_utf7_to_utf8(dup_name, FALSE);
                
                new_item = folder_item_new(FOLDER(folder), loc_name, loc_path);
                if ((flags & ETPAN_IMAP_MB_NOINFERIORS) != 0)
@@ -4976,24 +5252,25 @@ static GSList * imap_uid_list_from_lep_tab(carray * list)
 }
 
 static void imap_flags_hash_from_lep_uid_flags_tab(carray * list,
-                                                  GHashTable * hash)
+                                                  GHashTable * hash,
+                                                  GHashTable * tags_hash)
 {
        unsigned int i;
        GSList * result;
        
        result = NULL;
        
-       for(i = 0 ; i < carray_count(list) ; i += 2) {
+       for(i = 0 ; i < carray_count(list) ; i += 3) {
                uint32_t * puid;
                int * pflags;
-               gint * pguid;
+               GSList *tags;
                
                puid = carray_get(list, i);
                pflags = carray_get(list, i + 1);
-               pguid = malloc(sizeof(* pguid));
-               * pguid = * puid;
+               tags = carray_get(list, i + 2);
                
-               g_hash_table_insert(hash, pguid, GINT_TO_POINTER(* pflags));
+               g_hash_table_insert(hash, GINT_TO_POINTER(*puid), GINT_TO_POINTER(* pflags));
+               g_hash_table_insert(tags_hash, GINT_TO_POINTER(*puid), tags);
        }
 }
 
@@ -5041,10 +5318,11 @@ 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)
+static struct mailimap_flag_list * imap_flag_to_lep(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))
@@ -5063,6 +5341,15 @@ static struct mailimap_flag_list * imap_flag_to_lep(IMAPFlags flags)
                mailimap_flag_list_add(flag_list,
                                       mailimap_flag_new_draft());
        
+       for (; cur; cur = cur->next) {
+               gchar *enc_str = 
+                       imap_utf8_to_modified_utf7(cur->data, TRUE);
+               g_strstrip(enc_str);
+       
+               mailimap_flag_list_add(flag_list,
+                       mailimap_flag_new_flag_keyword(enc_str));
+       }
+
        return flag_list;
 }
 
index 4ac31f879c05696269ee7fff475b3f9c0a0b355e..8625ad16f767de633f6591ffd2b36f18d320b781 100644 (file)
@@ -865,7 +865,7 @@ static gint disposition_notification_send(MsgInfo *msginfo)
                extract_address(orig_to);
        }
        if (msginfo->subject) {
-               enc_sub = g_malloc0(strlen(msginfo->subject)*2);
+               enc_sub = g_malloc0(strlen(msginfo->subject)*8);
                qp_encode_line(enc_sub, (const guchar *)msginfo->subject);
                g_strstrip(enc_sub);
        }
index 0173070140aad82a42cd079036378f4c25ef2767..d4c12d7a6749d310409416c38fc451a9db83e336 100644 (file)
@@ -2416,6 +2416,8 @@ gchar *procmsg_msginfo_get_tags_str(MsgInfo *msginfo)
 
 void procmsg_msginfo_update_tags(MsgInfo *msginfo, gboolean set, gint id)
 {
+       GSList changed;
+
        if (id == 0)
                return;
 
@@ -2423,16 +2425,26 @@ void procmsg_msginfo_update_tags(MsgInfo *msginfo, gboolean set, gint id)
                msginfo->tags = g_slist_remove(
                                        msginfo->tags,
                                        GINT_TO_POINTER(id));
+               changed.data = GINT_TO_POINTER(id);
+               changed.next = NULL;
+               folder_item_commit_tags(msginfo->folder, msginfo, NULL, &changed);
        } else {
-               if (!g_slist_find(msginfo->tags, GINT_TO_POINTER(id)))
+               if (!g_slist_find(msginfo->tags, GINT_TO_POINTER(id))) {
                        msginfo->tags = g_slist_append(
                                        msginfo->tags,
                                        GINT_TO_POINTER(id));
+               }
+               changed.data = GINT_TO_POINTER(id);
+               changed.next = NULL;
+               folder_item_commit_tags(msginfo->folder, msginfo, &changed, NULL);
        }
+       
 }
 
 void procmsg_msginfo_clear_tags(MsgInfo *msginfo)
 {
-       g_slist_free(msginfo->tags);
+       GSList *unset = msginfo->tags;
        msginfo->tags = NULL;
+       folder_item_commit_tags(msginfo->folder, msginfo, NULL, unset);
+       g_slist_free(unset);
 }
index 0a1175c456bc09ae16f5e476a6e651ab28079d2a..f221ba89c0fb309916bbac0b75fd4cd9a48f0c0a 100644 (file)
@@ -384,4 +384,5 @@ gboolean procmsg_is_sending(void);
 gchar *procmsg_msginfo_get_tags_str(MsgInfo *msginfo);
 void procmsg_msginfo_update_tags(MsgInfo *msginfo, gboolean set, gint id);
 void procmsg_msginfo_clear_tags(MsgInfo *msginfo);
+void procmsg_msginfo_commit_tags(GSList *msglist);
 #endif /* __PROCMSG_H__ */
index 54795ea09159846ee0d96a411aaa89c1a76ddc20..4ec8fef80fb55611187f4c75ff594a1c9ba2ffe0 100644 (file)
@@ -5311,7 +5311,6 @@ static gboolean summary_set_row_tag(SummaryView *summaryview, GtkCTreeNode *row,
 
        procmsg_msginfo_update_tags(msginfo, set, id);
        
-       
        if (summaryview->col_state[summaryview->col_pos[S_COL_TAGS]].visible) {
                tags_str = procmsg_msginfo_get_tags_str(msginfo);
                gtk_ctree_node_set_text(ctree, row, 
@@ -5337,10 +5336,12 @@ void summary_set_tag(SummaryView *summaryview, gint tag_id,
        gboolean froze = FALSE;
        gboolean redisplay = FALSE;
        START_LONG_OPERATION(summaryview, FALSE);
+       folder_item_set_batch(summaryview->folder_item, TRUE);
        for (cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next) {
                redisplay |= summary_set_row_tag(summaryview,
                                           GTK_CTREE_NODE(cur->data), FALSE, set, real_id);
        }
+       folder_item_set_batch(summaryview->folder_item, FALSE);
        END_LONG_OPERATION(summaryview);
        if (redisplay)
                summary_redisplay_msg(summaryview);