2006-02-06 [colin] 2.0.0cvs21
[claws.git] / src / folder.c
index 7b136962e5d0a065fb7d08f55a78c1904f0fdfce..08f4339c00385a2732b3813a09cf0f61acfc6f6a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2005 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws team
  *
  * 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
@@ -31,6 +31,9 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <stdlib.h>
+#ifdef WIN32
+#include <w32lib.h>
+#endif
 
 #include "folder.h"
 #include "session.h"
 #include "prefs_common.h"
 #include "prefs_account.h"
 
+/* Define possible missing constants for Windows. */
+#ifdef G_OS_WIN32
+# ifndef S_IRGRP
+# define S_IRGRP 0
+# define S_IWGRP 0
+# endif
+# ifndef S_IROTH
+# define S_IROTH 0
+# define S_IWOTH 0
+# endif
+#endif
+
 static GList *folder_list = NULL;
 static GSList *class_list = NULL;
 static GSList *folder_unloaded_list = NULL;
@@ -707,7 +722,7 @@ gint folder_read_list(void)
        }
 
        xml_free_tree(node);
-       if (folder_list)
+       if (folder_list || folder_unloaded_list)
                return 0;
        else
                return -1;
@@ -768,7 +783,7 @@ gboolean folder_scan_tree_func(GNode *node, gpointer data)
        return FALSE;
 }
 
-void folder_scan_tree(Folder *folder)
+void folder_scan_tree(Folder *folder, gboolean rebuild)
 {
        GHashTable *pptable;
        FolderUpdateData hookdata;
@@ -778,11 +793,9 @@ void folder_scan_tree(Folder *folder)
        
        pptable = folder_persist_prefs_new(folder);
 
-       /*
-        * should be changed and tree update should be done without 
-        * destroying the tree first
-        */
-       folder_tree_destroy(folder);
+       if (rebuild)
+               folder_tree_destroy(folder);
+
        folder->klass->scan_tree(folder);
 
        hookdata.folder = folder;
@@ -1255,6 +1268,17 @@ Folder *folder_get_default_folder(void)
        return folder_list ? FOLDER(folder_list->data) : NULL;
 }
 
+gboolean folder_have_mailbox (void)
+{
+       GList *cur;
+       for (cur = folder_list; cur != NULL; cur = g_list_next(cur)) {
+               Folder *folder = FOLDER(cur->data);
+               if (folder->inbox && folder->outbox)
+                       return TRUE;
+       }
+       return FALSE;
+}
+
 FolderItem *folder_get_default_inbox(void)
 {
        GList *flist;
@@ -1461,28 +1485,48 @@ static gint folder_sort_folder_list(gconstpointer a, gconstpointer b)
        return (gint_a - gint_b);
 }
 
-gint folder_item_open(FolderItem *item)
+void folder_item_process_open (FolderItem *item,
+                                void (*before_proc_func)(gpointer data),
+                                void (*after_proc_func)(gpointer data),
+                                gpointer data)
 {
        gchar *buf;
-       g_return_val_if_fail(item->no_select == FALSE, -1);
-
+       if (item == NULL)
+               return;
        if((item->folder->klass->scan_required != NULL) &&
           (item->folder->klass->scan_required(item->folder, item))) {
                folder_item_scan_full(item, TRUE);
+       } else {
+               folder_item_syncronize_flags(item);
        }
-       folder_item_syncronize_flags(item);
        
        /* Processing */
        buf = g_strdup_printf(_("Processing (%s)...\n"), 
                              item->path ? item->path : item->name);
        debug_print("%s\n", buf);
        g_free(buf);
-       
+
+       if (before_proc_func)
+               before_proc_func(data);
+
        folder_item_apply_processing(item);
 
-       item->opened = TRUE;
+       if (after_proc_func)
+               after_proc_func(data);
 
        debug_print("done.\n");
+       item->processing_pending = FALSE;
+       return; 
+}
+
+gint folder_item_open(FolderItem *item)
+{
+       g_return_val_if_fail(item->no_select == FALSE, -1);
+
+       item->processing_pending = TRUE;
+       folder_item_process_open (item, NULL, NULL, NULL);
+       
+       item->opened = TRUE;
 
        return 0;
 }
@@ -1578,6 +1622,7 @@ static gint syncronize_flags(FolderItem *item, MsgInfoList *msglist)
 
        relation = g_relation_new(2);
        g_relation_index(relation, 0, g_direct_hash, g_direct_equal);
+       folder_item_set_batch(item, TRUE);
        if ((ret = item->folder->klass->get_flags(
            item->folder, item, msglist, relation)) == 0) {
                GTuples *tuples;
@@ -1603,6 +1648,7 @@ static gint syncronize_flags(FolderItem *item, MsgInfoList *msglist)
                        }
                }
        }
+       folder_item_set_batch(item, FALSE);
        g_relation_destroy(relation);   
 
        return ret;
@@ -1628,7 +1674,7 @@ 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);
 
-       debug_print("Scanning folder %s for cache changes.\n", item->path);
+       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) {
@@ -1783,15 +1829,19 @@ gint folder_item_scan_full(FolderItem *item, gboolean filtering)
        g_slist_free(folder_list);
 
        if (new_list != NULL) {
+               GSList *tmp_list = NULL;
                newmsg_list = get_msginfos(item, new_list);
                g_slist_free(new_list);
+               tmp_list = g_slist_concat(g_slist_copy(exists_list), g_slist_copy(newmsg_list));
+               syncronize_flags(item, tmp_list);
+               g_slist_free(tmp_list);
+       } else {
+               syncronize_flags(item, exists_list);
        }
 
-       syncronize_flags(item, exists_list);
-
        folder_item_update_freeze();
        if (newmsg_list != NULL) {
-               GSList *elem;
+               GSList *elem, *to_filter = NULL;
                int total = g_slist_length(newmsg_list), cur = 0;
                
                if ((filtering == TRUE) &&
@@ -1811,10 +1861,17 @@ gint folder_item_scan_full(FolderItem *item, gboolean filtering)
                            (item->folder->account != NULL) && 
                            (item->folder->account->filter_on_recv) &&
                            procmsg_msginfo_filter(msginfo))
-                               procmsg_msginfo_free(msginfo);
+                               to_filter = g_slist_append(to_filter, msginfo);
                        else
                                exists_list = g_slist_prepend(exists_list, msginfo);
                }
+               filtering_move_and_copy_msgs(to_filter);
+               for (elem = to_filter; elem; elem = g_slist_next(elem)) {
+                       MsgInfo *msginfo = (MsgInfo *)elem->data;
+                       procmsg_msginfo_free(msginfo);
+               }
+
+               g_slist_free(to_filter);
                g_slist_free(newmsg_list);
 
                statusbar_progress_all(0,0,0);
@@ -2159,7 +2216,8 @@ void msginfo_set_mime_flags(GNode *node, gpointer data)
        MsgInfo *msginfo = data;
        MimeInfo *mimeinfo = node->data;
        
-       if (mimeinfo->disposition == DISPOSITIONTYPE_ATTACHMENT) {
+       if (mimeinfo->disposition == DISPOSITIONTYPE_ATTACHMENT
+        && (!mimeinfo->subtype ||  strcmp(mimeinfo->subtype, "pgp-signature"))) {
                procmsg_msginfo_set_flags(msginfo, 0, MSG_HAS_ATTACHMENT);
        } else if (mimeinfo->disposition == DISPOSITIONTYPE_UNKNOWN && 
                 mimeinfo->type != MIMETYPE_TEXT &&
@@ -2277,8 +2335,8 @@ gint folder_item_fetch_all_msg(FolderItem *item)
        g_return_val_if_fail(item != NULL, -1);
        g_return_val_if_fail(item->no_select == FALSE, -1);
 
-       debug_print("fetching all messages in %s ...\n", item->path);
-       statusbar_print_all(_("Fetching all messages in %s ...\n"), item->path);
+       debug_print("fetching all messages in %s ...\n", item->path ? item->path : "(null)");
+       statusbar_print_all(_("Fetching all messages in %s ...\n"), item->path ? item->path : "(null)");
 
        folder = item->folder;
 
@@ -2407,6 +2465,10 @@ static void add_msginfo_to_cache(FolderItem *item, MsgInfo *newmsginfo, MsgInfo
        item->total_msgs++;
 
        folder_item_update_freeze();
+
+       if (!item->cache)
+               folder_item_read_cache(item);
+
        msgcache_add_msg(item->cache, newmsginfo);
        copy_msginfo_flags(flagsource, newmsginfo);
        folder_item_update_with_msg(item,  F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_ADDMSG, newmsginfo);
@@ -2606,8 +2668,10 @@ FolderItem *folder_item_move_recursive(FolderItem *src, FolderItem *dest)
                src->folder->klass->remove_folder(src->folder, src);
        folder_write_list();
 
-       if (old_id != NULL && new_id != NULL)
+       if (old_id != NULL && new_id != NULL) {
                prefs_filtering_rename_path(old_id, new_id);
+               account_rename_path(old_id, new_id);
+       }
        g_free(old_id);
        g_free(new_id);
        
@@ -2719,8 +2783,20 @@ static gint do_copy_msgs(FolderItem *dest, GSList *msglist, gboolean remove_sour
                        return -1;
                }
        } else {
-               for (l = msglist ; l != NULL ; l = g_slist_next(l)) {
-                       MsgInfo * msginfo = (MsgInfo *) l->data;
+               MsgInfo * msginfo;
+               l = msglist;
+
+               /* immediately stop if src and dest folders are identical */
+               if (l != NULL) {
+                       msginfo = (MsgInfo *) l->data;
+                       if (msginfo != NULL && msginfo->folder == dest) {
+                               g_relation_destroy(relation);
+                               return -1;
+                       }
+               }
+
+               for (; l != NULL ; l = g_slist_next(l)) {
+                       msginfo = (MsgInfo *) l->data;
 
                        num = folder->klass->copy_msg(folder, dest, msginfo);
                        if (num > 0)
@@ -2730,6 +2806,42 @@ static gint do_copy_msgs(FolderItem *dest, GSList *msglist, gboolean remove_sour
                }
        }
 
+       if (remove_source) {
+               MsgInfo *msginfo = (MsgInfo *) msglist->data;
+               FolderItem *item = msginfo->folder;
+               /*
+                * Remove source messages from their folders if
+                * copying was successfull and update folder
+                * message counts
+                */
+               if (item->folder->klass->remove_msgs) {
+                       item->folder->klass->remove_msgs(item->folder,
+                                                               msginfo->folder,
+                                                               msglist,
+                                                               relation);
+               }
+               for (l = msglist; l != NULL; l = g_slist_next(l)) {
+                       GTuples *tuples;
+                       msginfo = (MsgInfo *) l->data;
+                       item = msginfo->folder;
+
+                       tuples = g_relation_select(relation, msginfo, 0);
+                       num = GPOINTER_TO_INT(g_tuples_index(tuples, 0, 1));
+                       g_tuples_destroy(tuples);
+
+                       if (g_slist_find(not_moved, msginfo))
+                               continue;
+
+                       if ((num >= 0) && (item->folder->klass->remove_msg != NULL)) {
+                               if (!item->folder->klass->remove_msgs)
+                                       item->folder->klass->remove_msg(item->folder,
+                                                               msginfo->folder,
+                                                               msginfo->msgnum);
+                               remove_msginfo_from_cache(item, msginfo);
+                       }
+               }
+       }
+
        /* Read cache for dest folder */
        if (!dest->cache) folder_item_read_cache(dest);
 
@@ -2784,42 +2896,6 @@ static gint do_copy_msgs(FolderItem *dest, GSList *msglist, gboolean remove_sour
                }
        }
 
-       if (remove_source) {
-               MsgInfo *msginfo = (MsgInfo *) msglist->data;
-               FolderItem *item = msginfo->folder;
-               /*
-                * Remove source messages from their folders if
-                * copying was successfull and update folder
-                * message counts
-                */
-               if (item->folder->klass->remove_msgs) {
-                       item->folder->klass->remove_msgs(item->folder,
-                                                               msginfo->folder,
-                                                               msglist,
-                                                               relation);
-               }
-               for (l = msglist; l != NULL; l = g_slist_next(l)) {
-                       GTuples *tuples;
-                       msginfo = (MsgInfo *) l->data;
-                       item = msginfo->folder;
-
-                       tuples = g_relation_select(relation, msginfo, 0);
-                       num = GPOINTER_TO_INT(g_tuples_index(tuples, 0, 1));
-                       g_tuples_destroy(tuples);
-
-                       if (g_slist_find(not_moved, msginfo))
-                               continue;
-
-                       if ((num >= 0) && (item->folder->klass->remove_msg != NULL)) {
-                               if (!item->folder->klass->remove_msgs)
-                                       item->folder->klass->remove_msg(item->folder,
-                                                               msginfo->folder,
-                                                               msginfo->msgnum);
-                               remove_msginfo_from_cache(item, msginfo);
-                       }
-               }
-       }
-
        g_relation_destroy(relation);
        if (not_moved != NULL) {
                g_slist_free(not_moved);
@@ -3309,7 +3385,10 @@ static void folder_create_processing_folder(void)
        g_assert(processing_folder != NULL);
 
        debug_print("tmpparentroot %s\n", LOCAL_FOLDER(processing_folder)->rootpath);
-       if (LOCAL_FOLDER(processing_folder)->rootpath[0] == '/')
+        /* FIXME: [W32] The code below does not correctly merge
+           relative filenames; there should be a function to handle
+           this.  */
+       if (!is_relative_filename(LOCAL_FOLDER(processing_folder)->rootpath))
                tmpname = g_strconcat(LOCAL_FOLDER(processing_folder)->rootpath,
                                      G_DIR_SEPARATOR_S, PROCESSING_FOLDER_ITEM,
                                      NULL);
@@ -3547,6 +3626,7 @@ static void folder_item_update_func(FolderItem *item, gpointer data)
        if (item->update_flags) {
                source.item = item;
                source.update_flags = item->update_flags;
+               source.msg = NULL;
                hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &source);                             
                item->update_flags = 0;
        }
@@ -3586,10 +3666,8 @@ static void folder_item_want_synchronise_func(FolderItem *item, gpointer data)
        WantSyncData *want_sync_data = (WantSyncData *)data;
        
        if (want_sync_data->folder == NULL || item->folder == want_sync_data->folder) {
-               if(item->prefs->offlinesync && item->folder->klass->synchronise)
-                       want_sync_data->want_sync = TRUE;
-               else
-                       want_sync_data->want_sync = FALSE;
+               if (item->prefs->offlinesync && item->folder->klass->synchronise)
+                       want_sync_data->want_sync |= TRUE;
        }
 }
 
@@ -3598,6 +3676,7 @@ gboolean folder_want_synchronise(Folder *folder)
        WantSyncData *want_sync_data = g_new0(WantSyncData, 1);
        gboolean result;
        want_sync_data->folder = folder;
+       want_sync_data->want_sync = FALSE;
        
        folder_func_to_all_folders(folder_item_want_synchronise_func, want_sync_data);
        result = want_sync_data->want_sync;
@@ -3644,7 +3723,8 @@ gboolean folder_has_parent_of_type(FolderItem *item,
                        && item != cur) {
                                debug_print("set item %s parent type to %d "
                                        "even if %s is F_INBOX\n",
-                                       item->path, 0, cur->path);
+                                       item->path ? item->path : "(null)",
+                                       0, cur->path);
                                item->parent_stype = F_NORMAL;
                                break;
                        }
@@ -3654,8 +3734,9 @@ gboolean folder_has_parent_of_type(FolderItem *item,
                                item->parent_stype = cur->parent_stype;
                                debug_print("set item %s parent type to %d "
                                        "from %s's parent type\n",
-                                       item->path, cur->parent_stype, 
-                                       cur->path);
+                                       item->path ? item->path : "(null)",
+                                       cur->parent_stype ? cur->parent_stype : 0, 
+                                       cur->path ? cur->path : "(null)");
                                break;
                        }
                        /* we found a parent that has a special type. That's 
@@ -3663,7 +3744,9 @@ gboolean folder_has_parent_of_type(FolderItem *item,
                        if (cur->stype != F_NORMAL) {
                                debug_print("set item %s parent type to %d "
                                        "from %s's type\n",
-                                       item->path, cur->stype, cur->path);
+                                       item->path ? item->path : "(null)",
+                                       cur->stype ? cur->stype : 0, 
+                                       cur->path ? cur->path : "(null)");
                                cur->parent_stype = cur->stype;
                                item->parent_stype = cur->stype;
                                break;
@@ -3675,11 +3758,25 @@ gboolean folder_has_parent_of_type(FolderItem *item,
                 * normal. */
                if (item->parent_stype == -1) {
                        debug_print("set item %s to 0 from default\n", 
-                               item->path);
+                               item->path ? item->path : "(null)");
                        item->parent_stype = F_NORMAL;
                }
        }
        return FALSE;
 }
 
+gboolean folder_subscribe (const gchar *uri)
+{
+       GList *cur;
+       for (cur = folder_get_list(); cur != NULL; cur = g_list_next(cur)) {
+               Folder *folder = (Folder *) cur->data;
+
+               if (folder->klass->subscribe
+               &&  folder->klass->subscribe(folder, uri)) {
+                       return TRUE;
+               }
+       }
+       return FALSE;
+
+}
 #undef PUT_ESCAPE_STR