2006-07-06 [colin] 2.3.1cvs65
[claws.git] / src / folder.c
index 7e7ce021385782266169d53bd1f68d6c3c885817..acdb51ac5e83e644a70f604e63927e87eb6c9085 100644 (file)
@@ -54,6 +54,9 @@
 #include "remotefolder.h"
 #include "partial_download.h"
 #include "statusbar.h"
+#include "gtkutils.h"
+#include "timing.h"
+#include "compose.h"
 
 /* Dependecies to be removed ?! */
 #include "prefs_common.h"
@@ -88,7 +91,6 @@ static void folder_get_persist_prefs_recursive
                                        (GNode *node, GHashTable *pptable);
 static gboolean persist_prefs_free     (gpointer key, gpointer val, gpointer data);
 void folder_item_read_cache            (FolderItem *item);
-void folder_item_free_cache            (FolderItem *item);
 gint folder_item_scan_full             (FolderItem *item, gboolean filtering);
 static void folder_item_update_with_msg (FolderItem *item, FolderItemUpdateFlags update_flags,
                                          MsgInfo *msg);
@@ -197,6 +199,52 @@ void folder_init(Folder *folder, const gchar *name)
        folder->trash = NULL;
 }
 
+static void reset_parent_type(FolderItem *item, gpointer data) {
+       item->parent_stype = -1;
+}
+
+void folder_item_change_type(FolderItem *item, SpecialFolderItemType newtype)
+{
+       Folder *folder = NULL;
+       FolderUpdateData hookdata;
+
+       folder = item->folder;
+       /* unset previous root of newtype */
+       switch(newtype) {
+       case F_INBOX:
+               folder_item_change_type(folder->inbox, F_NORMAL);
+               folder->inbox = item;
+               break;
+       case F_OUTBOX:
+               folder_item_change_type(folder->outbox, F_NORMAL);
+               folder->outbox = item;
+               break;
+       case F_QUEUE:
+               folder_item_change_type(folder->queue, F_NORMAL);
+               folder->queue = item;
+               break;
+       case F_DRAFT:
+               folder_item_change_type(folder->draft, F_NORMAL);
+               folder->draft = item;
+               break;
+       case F_TRASH:
+               folder_item_change_type(folder->trash, F_NORMAL);
+               folder->trash = item;
+               break;
+       case F_NORMAL:
+       default:
+               break;
+       }
+       /* set new type for current folder and sons */
+       item->stype = newtype;
+       folder_func_to_all_folders(reset_parent_type, NULL);
+       
+       hookdata.folder = folder;
+       hookdata.update_flags = FOLDER_TREE_CHANGED;
+       hookdata.item = NULL;
+       hooks_invoke(FOLDER_UPDATE_HOOKLIST, &hookdata);
+}
+
 void folder_destroy(Folder *folder)
 {
        g_return_if_fail(folder != NULL);
@@ -412,7 +460,7 @@ void folder_item_destroy(FolderItem *item)
        }
 
        if (item->cache)
-               folder_item_free_cache(item);
+               folder_item_free_cache(item, TRUE);
        if (item->prefs)
                folder_item_prefs_free(item->prefs);
        g_free(item->name);
@@ -783,16 +831,22 @@ void folder_scan_tree(Folder *folder, gboolean rebuild)
 {
        GHashTable *pptable;
        FolderUpdateData hookdata;
-       
+       Folder *old_folder = folder;
+
        if (!folder->klass->scan_tree)
                return;
        
        pptable = folder_persist_prefs_new(folder);
 
        if (rebuild)
-               folder_tree_destroy(folder);
+               folder_remove(folder);
 
-       folder->klass->scan_tree(folder);
+       if (folder->klass->scan_tree(folder) < 0) {
+               if (rebuild)
+                       folder_add(old_folder);
+               return;
+       } else if (rebuild)
+               folder_add(folder);
 
        hookdata.folder = folder;
        hookdata.update_flags = FOLDER_TREE_CHANGED;
@@ -1523,14 +1577,20 @@ void folder_item_process_open (FolderItem *item,
 
 gint folder_item_open(FolderItem *item)
 {
+       START_TIMING("folder_item_open"); 
        if (item->no_select)
                return -1;
 
+       if (item->scanning) {
+               debug_print("%s is scanning... \n", item->path ? item->path : item->name);
+               return -2;
+       }
+
        item->processing_pending = TRUE;
        folder_item_process_open (item, NULL, NULL, NULL);
        
        item->opened = TRUE;
-
+       END_TIMING();
        return 0;
 }
 
@@ -1682,11 +1742,14 @@ gint folder_item_scan_full(FolderItem *item, gboolean filtering)
        g_return_val_if_fail(folder != NULL, -1);
        g_return_val_if_fail(folder->klass->get_num_list != NULL, -1);
 
+       item->scanning = TRUE;
+
        debug_print("Scanning folder %s for cache changes.\n", item->path ? item->path : "(null)");
        
        /* Get list of messages for folder and cache */
        if (folder->klass->get_num_list(item->folder, item, &folder_list, &old_uids_valid) < 0) {
                debug_print("Error fetching list of message numbers\n");
+               item->scanning = FALSE;
                return(-1);
        }
 
@@ -1950,6 +2013,12 @@ gint folder_item_scan_full(FolderItem *item, gboolean filtering)
                g_hash_table_destroy(subject_table);
        }
        
+       if (item->new_msgs != newcnt || item->unread_msgs != unreadcnt
+       ||  item->total_msgs != totalcnt || item->marked_msgs != markedcnt
+       ||  item->unreadmarked_msgs != unreadmarkedcnt) {
+               update_flags |= F_ITEM_UPDATE_CONTENT;
+       }
+
        item->new_msgs = newcnt;
        item->unread_msgs = unreadcnt;
        item->total_msgs = totalcnt;
@@ -1961,6 +2030,8 @@ gint folder_item_scan_full(FolderItem *item, gboolean filtering)
        folder_item_update(item, update_flags);
        folder_item_update_thaw();
        
+       item->scanning = FALSE;
+
        return 0;
 }
 
@@ -2017,6 +2088,8 @@ gint folder_item_syncronize_flags(FolderItem *item)
        if (item->no_select)
                return -1;
 
+       item->scanning = TRUE;
+
        if (item->cache == NULL)
                folder_item_read_cache(item);
        
@@ -2029,6 +2102,8 @@ gint folder_item_syncronize_flags(FolderItem *item)
        
        g_slist_free(msglist);
 
+       item->scanning = FALSE;
+
        return ret;
 }
 
@@ -2054,24 +2129,26 @@ void folder_find_expired_caches(FolderItem *item, gpointer data)
        difftime = (gint) (time(NULL) - msgcache_get_last_access_time(item->cache));
        expiretime = prefs_common.cache_min_keep_time * 60;
        debug_print("Cache unused time: %d (Expire time: %d)\n", difftime, expiretime);
+
        if (difftime > expiretime && !item->opened && !item->processing_pending) {
                *folder_item_list = g_slist_insert_sorted(*folder_item_list, item, folder_cache_time_compare_func);
        }
 }
 
-void folder_item_free_cache(FolderItem *item)
+gboolean folder_item_free_cache(FolderItem *item, gboolean force)
 {
-       g_return_if_fail(item != NULL);
+       g_return_val_if_fail(item != NULL, TRUE);
        
        if (item->cache == NULL)
-               return;
+               return TRUE;
        
-       if (item->opened > 0)
-               return;
+       if (item->opened > 0 && !force)
+               return FALSE;
 
        folder_item_write_cache(item);
        msgcache_destroy(item->cache);
        item->cache = NULL;
+       return TRUE;
 }
 
 void folder_clean_cache_memory_force(void)
@@ -2104,13 +2181,16 @@ void folder_clean_cache_memory(FolderItem *protected_item)
                listitem = folder_item_list;
                while((listitem != NULL) && (memusage > (prefs_common.cache_max_mem_usage * 1024))) {
                        FolderItem *item = (FolderItem *)(listitem->data);
+                       gint cache_size = 0;
                        if (item == protected_item) {
                                listitem = listitem->next;
                                continue;
                        }
                        debug_print("Freeing cache memory for %s\n", item->path ? item->path : item->name);
-                       memusage -= msgcache_get_memory_usage(item->cache);
-                       folder_item_free_cache(item);
+                       cache_size = msgcache_get_memory_usage(item->cache);
+                       if (folder_item_free_cache(item, FALSE))
+                               memusage -= cache_size;
+
                        listitem = listitem->next;
                }
                g_slist_free(folder_item_list);
@@ -2120,7 +2200,7 @@ void folder_clean_cache_memory(FolderItem *protected_item)
 void folder_item_read_cache(FolderItem *item)
 {
        gchar *cache_file, *mark_file;
-       
+       START_TIMING("folder_item_read_cache");
        g_return_if_fail(item != NULL);
 
        if (item->path != NULL) {
@@ -2164,7 +2244,7 @@ void folder_item_read_cache(FolderItem *item)
        } else {
                item->cache = msgcache_new();
        }
-
+       END_TIMING();
        folder_clean_cache_memory(item);
 }
 
@@ -2271,7 +2351,12 @@ void msginfo_set_mime_flags(GNode *node, gpointer data)
                if (!mimeinfo->subtype 
                ||  strcmp(mimeinfo->subtype, "pgp-signature"))
                        procmsg_msginfo_set_flags(msginfo, 0, MSG_HAS_ATTACHMENT);
-       }
+       } else if (mimeinfo->disposition == DISPOSITIONTYPE_INLINE &&
+               strcmp(mimeinfo->subtype, "pgp-signature") && 
+               (procmime_mimeinfo_get_parameter(mimeinfo, "name") != NULL ||
+                procmime_mimeinfo_get_parameter(mimeinfo, "filename") != NULL)) {
+               procmsg_msginfo_set_flags(msginfo, 0, MSG_HAS_ATTACHMENT);
+       } 
 
        /* don't descend below top level message for signed and encrypted info */
        if (mimeinfo->type == MIMETYPE_MESSAGE)
@@ -2323,6 +2408,7 @@ gchar *folder_item_fetch_msg(FolderItem *item, gint num)
                                procmsg_msginfo_set_flags(msginfo, 0, MSG_SCANNED);
                        }
                }
+               procmsg_msginfo_free(msginfo);
        }
 
        return msgfile;
@@ -2365,6 +2451,7 @@ gchar *folder_item_fetch_msg_full(FolderItem *item, gint num, gboolean headers,
                                procmsg_msginfo_set_flags(msginfo, 0, MSG_SCANNED);
                        }
                }
+               procmsg_msginfo_free(msginfo);
        }
 
        return msgfile;
@@ -2732,7 +2819,7 @@ gint folder_item_move_to(FolderItem *src, FolderItem *dest, FolderItem **new_ite
 {
        FolderItem *tmp = folder_item_parent(dest);
        gchar * src_identifier, * dst_identifier;
-       gchar * phys_srcpath, * phys_dstpath;
+       gchar * phys_srcpath, * phys_dstpath, *tmppath;
        
        while (tmp) {
                if (tmp == src) {
@@ -2760,10 +2847,12 @@ gint folder_item_move_to(FolderItem *src, FolderItem *dest, FolderItem **new_ite
        }
 
        phys_srcpath = folder_item_get_path(src);
-       phys_dstpath = g_strconcat(folder_item_get_path(dest),
+       tmppath = folder_item_get_path(dest);
+       phys_dstpath = g_strconcat(tmppath,
                       G_DIR_SEPARATOR_S,
                       g_path_get_basename(phys_srcpath),
                       NULL);
+       g_free(tmppath);
 
        if (folder_item_parent(src) == dest || src == dest) {
                g_free(src_identifier);
@@ -2799,6 +2888,8 @@ static gint do_copy_msgs(FolderItem *dest, GSList *msglist, gboolean remove_sour
        gboolean folderscan = FALSE;
        GRelation *relation;
        GSList *not_moved = NULL;
+       gint total = 0, curmsg = 0;
+       MsgInfo *msginfo = NULL;
 
        g_return_val_if_fail(dest != NULL, -1);
        g_return_val_if_fail(msglist != NULL, -1);
@@ -2809,6 +2900,40 @@ static gint do_copy_msgs(FolderItem *dest, GSList *msglist, gboolean remove_sour
        if (dest->no_select)
                return -1;
 
+       msginfo = (MsgInfo *)msglist->data;
+       
+       if (!msginfo)
+               return -1;
+       
+       if (!MSG_IS_QUEUED(msginfo->flags) && 
+           MSG_IS_DRAFT(msginfo->flags) && 
+           folder_has_parent_of_type(dest, F_QUEUE)) {
+               GSList *cur = msglist;
+               gboolean queue_err = FALSE;
+               for (; cur; cur = cur->next) {
+                       Compose *compose = NULL;
+                       FolderItem *queue = dest;
+                       int val = 0;
+                       
+                       msginfo = (MsgInfo *)cur->data;
+                       compose = compose_reedit(msginfo, TRUE);
+                       if (compose == NULL) {
+                               queue_err = TRUE;
+                               continue;
+                       }
+                       val = compose_queue(compose, NULL, &queue, NULL,
+                                       FALSE);
+                       if (val < 0) {
+                               queue_err = TRUE;
+                       } else if (remove_source) {
+                               folder_item_remove_msg(msginfo->folder, msginfo->msgnum);
+                       }
+                       if (val == 0)
+                               compose_close(compose);
+               }
+               return queue_err ? -1:0;
+       }
+
        relation = g_relation_new(2);
        g_relation_index(relation, 0, g_direct_hash, g_direct_equal);
        g_relation_index(relation, 1, g_direct_hash, g_direct_equal);
@@ -2905,6 +3030,8 @@ static gint do_copy_msgs(FolderItem *dest, GSList *msglist, gboolean remove_sour
                folderscan = TRUE;
        }
 
+       statusbar_print_all(_("Updating cache for %s..."), dest->path ? dest->path : "(null)");
+       total = g_slist_length(msglist);
        for (l = msglist; l != NULL; l = g_slist_next(l)) {
                MsgInfo *msginfo = (MsgInfo *) l->data;
                 GTuples *tuples;
@@ -2913,6 +3040,10 @@ static gint do_copy_msgs(FolderItem *dest, GSList *msglist, gboolean remove_sour
                 num = GPOINTER_TO_INT(g_tuples_index(tuples, 0, 1));
                 g_tuples_destroy(tuples);
 
+               statusbar_progress_all(curmsg++,total, 100);
+               if (curmsg % 100 == 0)
+                       GTK_EVENTS_FLUSH();
+
                if (num >= 0) {
                        MsgInfo *newmsginfo = NULL;
 
@@ -2951,6 +3082,8 @@ static gint do_copy_msgs(FolderItem *dest, GSList *msglist, gboolean remove_sour
                                lastnum = num;
                }
        }
+       statusbar_progress_all(0,0,0);
+       statusbar_pop_all();
 
        g_relation_destroy(relation);
        if (not_moved != NULL) {
@@ -3113,7 +3246,7 @@ gint folder_item_remove_all_msg(FolderItem *item)
                result = folder->klass->remove_all_msg(folder, item);
 
                if (result == 0) {
-                       folder_item_free_cache(item);
+                       folder_item_free_cache(item, TRUE);
                        item->cache = msgcache_new();
                }
        } else {
@@ -3343,6 +3476,9 @@ static GNode *folder_get_xml_node(Folder *folder)
        xmlnode = xml_node_new(tag, NULL);
 
        node = g_node_new(xmlnode);
+       
+       g_return_val_if_fail (folder->node != NULL, NULL);
+       
        if (folder->node->children) {
                GNode *cur;