* src/folder.c
[claws.git] / src / folder.c
index 10b2444ac6e71a33fe6dd0261b6fc877be463bb8..38fd83fbf39ad8758488b6182055c62fd3683b7b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2002 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
  *
  * 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
@@ -108,7 +108,7 @@ Folder *folder_new(FolderClass *klass, const gchar *name, const gchar *path)
        /* Create root folder item */
        item = folder_item_new(folder, name, NULL);
        item->folder = folder;
-       folder->node = g_node_new(item);
+       folder->node = item->node = g_node_new(item);
        folder->data = NULL;
 
        return folder;
@@ -202,6 +202,7 @@ FolderItem *folder_item_new(Folder *folder, const gchar *name, const gchar *path
        item->threaded  = TRUE;
        item->ret_rcpt  = FALSE;
        item->opened    = FALSE;
+       item->node = NULL;
        item->parent = NULL;
        item->folder = NULL;
        item->account = NULL;
@@ -216,19 +217,22 @@ FolderItem *folder_item_new(Folder *folder, const gchar *name, const gchar *path
 
 void folder_item_append(FolderItem *parent, FolderItem *item)
 {
-       GNode *node;
-
        g_return_if_fail(parent != NULL);
        g_return_if_fail(parent->folder != NULL);
+       g_return_if_fail(parent->node != NULL);
        g_return_if_fail(item != NULL);
 
-       node = parent->folder->node;
-       node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, parent);
-       g_return_if_fail(node != NULL);
-
        item->parent = parent;
        item->folder = parent->folder;
-       g_node_append_data(node, item);
+       item->node = g_node_append_data(parent->node, item);
+}
+
+static gboolean folder_item_remove_func(GNode *node, gpointer data)
+{
+       FolderItem *item = FOLDER_ITEM(node->data);
+
+       folder_item_destroy(item);
+       return FALSE;
 }
 
 void folder_item_remove(FolderItem *item)
@@ -237,22 +241,53 @@ void folder_item_remove(FolderItem *item)
 
        g_return_if_fail(item != NULL);
        g_return_if_fail(item->folder != NULL);
+       g_return_if_fail(item->node != NULL);
 
-       node = item->folder->node;
-       node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
-       g_return_if_fail(node != NULL);
+       node = item->node;
 
-       /* TODO: free all FolderItem's first */
        if (item->folder->node == node)
                item->folder->node = NULL;
+
+       g_node_traverse(node, G_POST_ORDER, G_TRAVERSE_ALL, -1,
+                       folder_item_remove_func, NULL);
        g_node_destroy(node);
 }
 
+void folder_item_remove_children(FolderItem *item)
+{
+       GNode *node, *next;
+
+       g_return_if_fail(item != NULL);
+       g_return_if_fail(item->folder != NULL);
+       g_return_if_fail(item->node != NULL);
+
+       node = item->node->children;
+       while (node != NULL) {
+               next = node->next;
+               folder_item_remove(FOLDER_ITEM(node->data));
+               node = next;
+       }
+}
+
 void folder_item_destroy(FolderItem *item)
 {
+       Folder *folder;
+
        g_return_if_fail(item != NULL);
 
-       debug_print("Destroying folder item %s\n", item->path);
+       folder = item->folder;
+       if (folder) {
+               if (folder->inbox == item)
+                       folder->inbox = NULL;
+               else if (folder->outbox == item)
+                       folder->outbox = NULL;
+               else if (folder->draft == item)
+                       folder->draft = NULL;
+               else if (folder->queue == item)
+                       folder->queue = NULL;
+               else if (folder->trash == item)
+                       folder->trash = NULL;
+       }
 
        if (item->cache)
                folder_item_free_cache(item);
@@ -300,21 +335,12 @@ gboolean folder_tree_destroy_func(GNode *node, gpointer data) {
 void folder_tree_destroy(Folder *folder)
 {
        g_return_if_fail(folder != NULL);
-       g_return_if_fail(folder->node != NULL);
        
        prefs_scoring_clear_folder(folder);
        prefs_filtering_clear_folder(folder);
 
-       g_node_traverse(folder->node, G_POST_ORDER, G_TRAVERSE_ALL, -1, folder_tree_destroy_func, NULL);
        if (folder->node)
-               g_node_destroy(folder->node);
-
-       folder->inbox = NULL;
-       folder->outbox = NULL;
-       folder->draft = NULL;
-       folder->queue = NULL;
-       folder->trash = NULL;
-       folder->node = NULL;
+               folder_item_remove(FOLDER_ITEM(folder->node->data));
 }
 
 void folder_add(Folder *folder)
@@ -1014,7 +1040,7 @@ static gint folder_sort_folder_list(gconstpointer a, gconstpointer b)
 
 gint folder_item_open(FolderItem *item)
 {
-       if(((FOLDER_TYPE(item->folder) == F_IMAP) && !item->no_select) || (FOLDER_TYPE(item->folder) == F_NEWS)) {
+       if((item->folder->klass->scan_required != NULL) && (item->folder->klass->scan_required(item->folder, item))) {
                folder_item_scan_full(item, TRUE);
        }
 
@@ -1078,7 +1104,7 @@ gint folder_item_scan_full(FolderItem *item, gboolean filtering)
        GSList *newmsg_list = NULL;
        guint newcnt = 0, unreadcnt = 0, totalcnt = 0, unreadmarkedcnt = 0;
        guint cache_max_num, folder_max_num, cache_cur_num, folder_cur_num;
-       gboolean update_flags = 0;
+       gboolean update_flags = 0, old_uids_valid = FALSE;
     
        g_return_val_if_fail(item != NULL, -1);
        if (item->path == NULL) return -1;
@@ -1091,13 +1117,12 @@ gint folder_item_scan_full(FolderItem *item, gboolean filtering)
        debug_print("Scanning folder %s for cache changes.\n", item->path);
 
        /* Get list of messages for folder and cache */
-       if (folder->klass->get_num_list(item->folder, item, &folder_list) < 0) {
+       if (folder->klass->get_num_list(item->folder, item, &folder_list, &old_uids_valid) < 0) {
                debug_print("Error fetching list of message numbers\n");
                return(-1);
        }
 
-       if (!folder->klass->check_msgnum_validity || 
-           folder->klass->check_msgnum_validity(folder, item)) {
+       if (old_uids_valid) {
                if (!item->cache)
                        folder_item_read_cache(item);
                cache_list = msgcache_get_msg_list(item->cache);
@@ -1670,6 +1695,7 @@ gint folder_item_add_msg(FolderItem *dest, const gchar *file,
        g_return_val_if_fail(dest != NULL, -1);
        g_return_val_if_fail(file != NULL, -1);
  
+       fileinfo.msginfo = NULL;
         fileinfo.file = (gchar *)file;
         fileinfo.flags = flags;
         file_list.data = &fileinfo;
@@ -1684,7 +1710,7 @@ gint folder_item_add_msgs(FolderItem *dest, GSList *file_list,
         Folder *folder;
         gint ret, num, lastnum = -1;
        GSList *file_cur;
-       MsgNumberList *newnum_list = NULL, *newnum_cur = NULL;
+       GRelation *relation;
        MsgFileInfo *fileinfo = NULL;
        gboolean folderscan = FALSE;
 
@@ -1694,10 +1720,13 @@ gint folder_item_add_msgs(FolderItem *dest, GSList *file_list,
 
         folder = dest->folder;
 
+       relation = g_relation_new(2);
+       g_relation_index(relation, 0, g_direct_hash, g_direct_equal);
+
        if (folder->klass->add_msgs != NULL) {
-               ret = folder->klass->add_msgs(folder, dest, file_list, &newnum_list);
+               ret = folder->klass->add_msgs(folder, dest, file_list, relation);
                if (ret < 0) {
-                       g_slist_free(newnum_list);
+                       g_relation_destroy(relation);
                        return ret;
                }
        } else {
@@ -1706,19 +1735,20 @@ gint folder_item_add_msgs(FolderItem *dest, GSList *file_list,
 
                        ret = folder->klass->add_msg(folder, dest, fileinfo->file, fileinfo->flags);
                        if (ret < 0) {
-                               g_slist_free(newnum_list);
+                               g_relation_destroy(relation);
                                return ret;
                        }
-                       newnum_list = g_slist_append(newnum_list, GINT_TO_POINTER(ret));
+                       g_relation_insert(relation, fileinfo, GINT_TO_POINTER(ret));
                }
        }
 
-       for (newnum_cur = newnum_list, file_cur = file_list;
-            newnum_cur != NULL && file_cur != NULL;
-            newnum_cur = g_slist_next(newnum_cur), file_cur = g_slist_next(file_cur)) {
+       for (file_cur = file_list; file_cur != NULL; file_cur = g_slist_next(file_cur)) {
+               GTuples *tuples;
 
-               num = GPOINTER_TO_INT(newnum_cur->data);
                fileinfo = (MsgFileInfo *) file_cur->data;
+               tuples = g_relation_select(relation, fileinfo, 0);
+               num = GPOINTER_TO_INT(g_tuples_index(tuples, 0, 1));
+               g_tuples_destroy(tuples);
 
                if (num >= 0) {
                        MsgInfo *newmsginfo;
@@ -1753,7 +1783,7 @@ gint folder_item_add_msgs(FolderItem *dest, GSList *file_list,
                }
        }
 
-       g_slist_free(newnum_list);
+       g_relation_destroy(relation);
 
         return lastnum;
 }
@@ -1801,7 +1831,7 @@ FolderItem *folder_item_move_recursive (FolderItem *src, FolderItem *dest)
        /* move messages */
        log_message(_("Moving %s to %s...\n"), 
                        src->name, new_item->path);
-       folder_item_move_msgs_with_dest(new_item, mlist);
+       folder_item_move_msgs(new_item, mlist);
        
        /*copy prefs*/
        folder_item_prefs_copy_prefs(src, new_item);
@@ -1889,14 +1919,6 @@ gint folder_item_move_to(FolderItem *src, FolderItem *dest, FolderItem **new_ite
                return F_MOVE_FAILED;
        }
        
-       /* update rules */
-       src_node = g_node_find(src->folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, src);
-       if (src_node) 
-               g_node_destroy(src_node);
-       else
-               debug_print("can't remove node: it's null!\n");
-       /* not to much worry if remove fails, move has been done */
-       
        g_free(src_identifier);
        g_free(dst_identifier);
        g_free(phys_srcpath);
@@ -1913,7 +1935,7 @@ gint folder_item_move_msg(FolderItem *dest, MsgInfo *msginfo)
        gint ret;
 
        list = g_slist_append(list, msginfo);
-       ret = folder_item_move_msgs_with_dest(dest, list);
+       ret = folder_item_move_msgs(dest, list);
        g_slist_free(list);
        
        return ret;
@@ -1945,13 +1967,13 @@ gint folder_item_move_msgs_with_dest(FolderItem *dest, GSList *msglist)
  * \param dest Destination folder
  * \param msglist List of messages
  */
-gint folder_item_move_msgs_with_dest(FolderItem *dest, GSList *msglist)
+gint folder_item_move_msgs(FolderItem *dest, GSList *msglist)
 {
        Folder *folder;
-       GSList *newmsgnums = NULL;
-       GSList *l, *l2;
+       GSList *l;
        gint num, lastnum = -1;
        gboolean folderscan = FALSE;
+       GRelation *relation;
 
        g_return_val_if_fail(dest != NULL, -1);
        g_return_val_if_fail(msglist != NULL, -1);
@@ -1960,13 +1982,16 @@ gint folder_item_move_msgs_with_dest(FolderItem *dest, GSList *msglist)
 
        g_return_val_if_fail(folder->klass->copy_msg != NULL, -1);
 
+       relation = g_relation_new(2);
+       g_relation_index(relation, 0, g_direct_hash, g_direct_equal);
+
        /* 
         * Copy messages to destination folder and 
         * store new message numbers in newmsgnums
         */
        if (folder->klass->copy_msgs != NULL) {
-               if (folder->klass->copy_msgs(folder, dest, msglist, &newmsgnums) < 0) {
-                       g_slist_free(newmsgnums);
+               if (folder->klass->copy_msgs(folder, dest, msglist, relation) < 0) {
+                       g_relation_destroy(relation);
                        return -1;
                }
        } else {
@@ -1974,7 +1999,7 @@ gint folder_item_move_msgs_with_dest(FolderItem *dest, GSList *msglist)
                        MsgInfo * msginfo = (MsgInfo *) l->data;
 
                        num = folder->klass->copy_msg(folder, dest, msginfo);
-                       newmsgnums = g_slist_append(newmsgnums, GINT_TO_POINTER(num));
+                       g_relation_insert(relation, msginfo, GINT_TO_POINTER(num));
                }
        }
 
@@ -1985,12 +2010,13 @@ gint folder_item_move_msgs_with_dest(FolderItem *dest, GSList *msglist)
         * Fetch new MsgInfos for new messages in dest folder,
         * add them to the msgcache and update folder message counts
         */
-       for (l = msglist, l2 = newmsgnums; 
-            l != NULL && l2 != NULL;
-            l = g_slist_next(l), l2 = g_slist_next(l2)) {
+       for (l = msglist; l != NULL; l = g_slist_next(l)) {
                MsgInfo *msginfo = (MsgInfo *) l->data;
+                GTuples *tuples;
 
-               num = GPOINTER_TO_INT(l2->data);
+                tuples = g_relation_select(relation, msginfo, 0);
+                num = GPOINTER_TO_INT(g_tuples_index(tuples, 0, 1));
+                g_tuples_destroy(tuples);
 
                if (num >= 0) {
                        MsgInfo *newmsginfo;
@@ -2029,14 +2055,14 @@ gint folder_item_move_msgs_with_dest(FolderItem *dest, GSList *msglist)
         * copying was successfull and update folder
         * message counts
         */
-       l2 = newmsgnums;
-       for (l = msglist, l2 = newmsgnums;
-            l != NULL && l2 != NULL;
-            l = g_slist_next(l), l2 = g_slist_next(l2)) {
+       for (l = msglist; l != NULL; l = g_slist_next(l)) {
                MsgInfo *msginfo = (MsgInfo *) l->data;
                FolderItem *item = msginfo->folder;
+                GTuples *tuples;
 
-               num = GPOINTER_TO_INT(l2->data);
+                tuples = g_relation_select(relation, msginfo, 0);
+                num = GPOINTER_TO_INT(g_tuples_index(tuples, 0, 1));
+                g_tuples_destroy(tuples);
 
                if ((num >= 0) && (item->folder->klass->remove_msg != NULL)) {
                        item->folder->klass->remove_msg(item->folder,
@@ -2046,11 +2072,10 @@ gint folder_item_move_msgs_with_dest(FolderItem *dest, GSList *msglist)
                }
        }
 
-
        if (folder->klass->finished_copy)
                folder->klass->finished_copy(folder, dest);
 
-       g_slist_free(newmsgnums);
+       g_relation_destroy(relation);
        return lastnum;
 }
 
@@ -2083,7 +2108,7 @@ gint folder_item_copy_msg(FolderItem *dest, MsgInfo *msginfo)
        msglist.data = msginfo;
        msglist.next = NULL;
        
-       return folder_item_copy_msgs_with_dest(dest, &msglist);
+       return folder_item_copy_msgs(dest, &msglist);
 }
 
 /*
@@ -2106,13 +2131,13 @@ gint folder_item_copy_msgs_with_dest(FolderItem *dest, GSList *msglist)
 }
 */
 
-gint folder_item_copy_msgs_with_dest(FolderItem *dest, GSList *msglist)
+gint folder_item_copy_msgs(FolderItem *dest, GSList *msglist)
 {
        Folder *folder;
        gint num, lastnum = -1;
-       GSList *newmsgnums = NULL;
-       GSList *l, *l2;
+       GSList *l;
        gboolean folderscan = FALSE;
+       GRelation *relation;
 
        g_return_val_if_fail(dest != NULL, -1);
        g_return_val_if_fail(msglist != NULL, -1);
@@ -2121,13 +2146,16 @@ gint folder_item_copy_msgs_with_dest(FolderItem *dest, GSList *msglist)
  
        g_return_val_if_fail(folder->klass->copy_msg != NULL, -1);
 
+        relation = g_relation_new(2);
+        g_relation_index(relation, 0, g_direct_hash, g_direct_equal);
+
        /*
         * Copy messages to destination folder and 
         * store new message numbers in newmsgnums
         */
        if (folder->klass->copy_msgs != NULL) {
-               if (folder->klass->copy_msgs(folder, dest, msglist, &newmsgnums) < 0) {
-                       g_slist_free(newmsgnums);
+               if (folder->klass->copy_msgs(folder, dest, msglist, relation) < 0) {
+                       g_relation_destroy(relation);
                        return -1;
                }
        } else {
@@ -2135,7 +2163,7 @@ gint folder_item_copy_msgs_with_dest(FolderItem *dest, GSList *msglist)
                        MsgInfo * msginfo = (MsgInfo *) l->data;
 
                        num = folder->klass->copy_msg(folder, dest, msginfo);
-                       newmsgnums = g_slist_append(newmsgnums, GINT_TO_POINTER(num));
+                       g_relation_insert(relation, msginfo, GINT_TO_POINTER(num));
                }
        }
 
@@ -2146,12 +2174,13 @@ gint folder_item_copy_msgs_with_dest(FolderItem *dest, GSList *msglist)
         * Fetch new MsgInfos for new messages in dest folder,
         * add them to the msgcache and update folder message counts
         */
-       for (l = msglist, l2 = newmsgnums;
-            l != NULL && l2 != NULL;
-            l = g_slist_next(l), l2 = g_slist_next(l2)) {
+       for (l = msglist; l != NULL; l = g_slist_next(l)) {
                MsgInfo *msginfo = (MsgInfo *) l->data;
+                GTuples *tuples;
 
-               num = GPOINTER_TO_INT(l2->data);
+                tuples = g_relation_select(relation, msginfo, 0);
+                num = GPOINTER_TO_INT(g_tuples_index(tuples, 0, 1));
+                g_tuples_destroy(tuples);
 
                if (num >= 0) {
                        MsgInfo *newmsginfo;
@@ -2189,7 +2218,8 @@ gint folder_item_copy_msgs_with_dest(FolderItem *dest, GSList *msglist)
        if (folder->klass->finished_copy)
                folder->klass->finished_copy(folder, dest);
 
-       g_slist_free(newmsgnums);
+       g_relation_destroy(relation);
+
        return lastnum;
 }
 
@@ -2461,6 +2491,7 @@ static gboolean folder_build_tree(GNode *node, gpointer data)
        item->ret_rcpt  = ret_rcpt;
        item->sort_key  = sort_key;
        item->sort_type = sort_type;
+       item->node = node;
        item->parent = FOLDER_ITEM(node->parent->data);
        item->folder = folder;
        switch (stype) {
@@ -2484,6 +2515,7 @@ static gboolean folder_build_tree(GNode *node, gpointer data)
 static gboolean folder_read_folder_func(GNode *node, gpointer data)
 {
        Folder *folder;
+       FolderItem *item;
        XMLNode *xmlnode;
        GList *list;
        FolderClass *class = NULL;
@@ -2534,16 +2566,18 @@ static gboolean folder_read_folder_func(GNode *node, gpointer data)
        folder->account = account;
        if (account != NULL)
                account->folder = REMOTE_FOLDER(folder);
-       node->data = folder->node->data;
+       item = FOLDER_ITEM(folder->node->data);
+       node->data = item;
+       item->node = node;
        g_node_destroy(folder->node);
        folder->node = node;
        folder_add(folder);
-       FOLDER_ITEM(node->data)->collapsed = collapsed;
-       FOLDER_ITEM(node->data)->thread_collapsed = thread_collapsed;
-       FOLDER_ITEM(node->data)->threaded  = threaded;
-       FOLDER_ITEM(node->data)->account   = account;
-       FOLDER_ITEM(node->data)->apply_sub = apply_sub;
-       FOLDER_ITEM(node->data)->ret_rcpt  = ret_rcpt;
+       item->collapsed = collapsed;
+       item->thread_collapsed = thread_collapsed;
+       item->threaded  = threaded;
+       item->account   = account;
+       item->apply_sub = apply_sub;
+       item->ret_rcpt  = ret_rcpt;
 
        g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
                        folder_build_tree, folder);