2007-08-09 [colin] 2.10.0cvs109
[claws.git] / src / folder.c
index 47d87d8cc14ed04c8f6af07a7755da6df6a32a81..8e06c7a6a34aa5b7ae48b6ceabd006d4748a4fee 100644 (file)
@@ -4,7 +4,7 @@
  *
  * 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
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -13,8 +13,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * 
  */
 
 #ifdef HAVE_CONFIG_H
@@ -57,6 +57,7 @@
 #include "gtkutils.h"
 #include "timing.h"
 #include "compose.h"
+#include "main.h"
 
 /* Dependecies to be removed ?! */
 #include "prefs_common.h"
@@ -83,6 +84,7 @@ void folder_init              (Folder         *folder,
 
 static gchar *folder_item_get_cache_file       (FolderItem     *item);
 static gchar *folder_item_get_mark_file        (FolderItem     *item);
+static gchar *folder_item_get_tags_file        (FolderItem     *item);
 static gchar *folder_get_list_path     (void);
 static GNode *folder_get_xml_node      (Folder         *folder);
 static Folder *folder_get_from_xml     (GNode          *node);
@@ -213,6 +215,9 @@ void folder_item_change_type(FolderItem *item, SpecialFolderItemType newtype)
        Folder *folder = NULL;
        FolderUpdateData hookdata;
 
+       if (item == NULL)
+               return;
+
        folder = item->folder;
        /* unset previous root of newtype */
        switch(newtype) {
@@ -573,6 +578,10 @@ void folder_item_set_xml(Folder *folder, FolderItem *item, XMLTag *tag)
                                item->sort_key = SORT_BY_TO;
                        else if (!strcmp(attr->value, "locked"))
                                item->sort_key = SORT_BY_LOCKED;
+                       else if (!strcmp(attr->value, "tags"))
+                               item->sort_key = SORT_BY_TAGS;
+                       else if (!strcmp(attr->value, "thread_date"))
+                               item->sort_key = SORT_BY_THREAD_DATE;
                } else if (!strcmp(attr->name, "sort_type")) {
                        if (!strcmp(attr->value, "ascending"))
                                item->sort_type = SORT_ASCENDING;
@@ -586,8 +595,14 @@ void folder_item_set_xml(Folder *folder, FolderItem *item, XMLTag *tag)
                                g_warning("account_id: %s not found\n", attr->value);
                        else
                                item->account = account;
-               } else if (!strcmp(attr->name, "apply_sub"))
+               } else if (!strcmp(attr->name, "apply_sub")) {
                        item->apply_sub = *attr->value == '1' ? TRUE : FALSE;
+               } else if (!strcmp(attr->name, "last_seen")) {
+                       if (!claws_crashed())
+                               item->last_seen = atoi(attr->value);
+                       else
+                               item->last_seen = 0;
+               }
        }
 }
 
@@ -598,7 +613,7 @@ XMLTag *folder_item_get_xml(Folder *folder, FolderItem *item)
        static gchar *sort_key_str[] = {"none", "number", "size", "date",
                                        "from", "subject", "score", "label",
                                        "mark", "unread", "mime", "to", 
-                                       "locked"};
+                                       "locked", "tags", "thread_date" };
        XMLTag *tag;
        gchar *value;
 
@@ -640,6 +655,8 @@ XMLTag *folder_item_get_xml(Folder *folder, FolderItem *item)
        if (item->apply_sub)
                xml_tag_add_attr(tag, xml_attr_new("apply_sub", "1"));
 
+       xml_tag_add_attr(tag, xml_attr_new_int("last_seen", item->last_seen));
+
        return tag;
 }
 
@@ -1779,6 +1796,7 @@ static gint syncronize_flags(FolderItem *item, MsgInfoList *msglist)
                MsgPermFlags permflags = 0;
                gboolean skip;
 
+               folder_item_update_freeze();
                for (cur = msglist; cur != NULL; cur = g_slist_next(cur)) {
                        msginfo = (MsgInfo *) cur->data;
                
@@ -1796,6 +1814,7 @@ static gint syncronize_flags(FolderItem *item, MsgInfoList *msglist)
                                        ~permflags & msginfo->flags.perm_flags, 0);
                        }
                }
+               folder_item_update_thaw();
        }
        folder_item_set_batch(item, FALSE);
        g_relation_destroy(relation);   
@@ -2075,6 +2094,9 @@ gint folder_item_scan_full(FolderItem *item, gboolean filtering)
                if (!MSG_IS_IGNORE_THREAD(msginfo->flags) && procmsg_msg_has_flagged_parent(msginfo, MSG_IGNORE_THREAD)) {
                        procmsg_msginfo_change_flags(msginfo, MSG_IGNORE_THREAD, 0, MSG_NEW | MSG_UNREAD, 0);
                }
+               if (!MSG_IS_WATCH_THREAD(msginfo->flags) && procmsg_msg_has_flagged_parent(msginfo, MSG_WATCH_THREAD)) {
+                       procmsg_msginfo_set_flags(msginfo, MSG_WATCH_THREAD, 0);
+               }
                if(prefs_common.thread_by_subject && !msginfo->inreplyto &&
                        !msginfo->references && !MSG_IS_IGNORE_THREAD(msginfo->flags) &&
                        (parent_msginfo = subject_table_lookup(subject_table, msginfo->subject)))
@@ -2279,15 +2301,48 @@ void folder_clean_cache_memory(FolderItem *protected_item)
        }
 }
 
+static void folder_item_remove_cached_msg(FolderItem *item, MsgInfo *msginfo)
+{
+       Folder *folder = item->folder;
+
+       g_return_if_fail(folder != NULL);
+
+       if (folder->klass->remove_cached_msg == NULL)
+               return;
+       
+       folder->klass->remove_cached_msg(folder, item, msginfo);
+}
+
+static void folder_item_clean_local_files(FolderItem *item, gint days)
+{
+       g_return_if_fail(item != NULL);
+       g_return_if_fail(item->folder != NULL);
+
+       if (FOLDER_TYPE(item->folder) == F_IMAP ||
+           FOLDER_TYPE(item->folder) == F_NEWS) {
+               GSList *msglist = folder_item_get_msg_list(item);
+               GSList *cur;
+               time_t t = time(NULL);
+               for (cur = msglist; cur; cur = cur->next) {
+                       MsgInfo *msginfo = (MsgInfo *)cur->data;
+                       gint age = (t - msginfo->date_t) / (60*60*24);
+                       if (age > days)
+                               folder_item_remove_cached_msg(item, msginfo);
+               }
+               procmsg_msg_list_free(msglist);
+       }
+}
+
 static void folder_item_read_cache(FolderItem *item)
 {
-       gchar *cache_file, *mark_file;
+       gchar *cache_file, *mark_file, *tags_file;
        START_TIMING("");
        g_return_if_fail(item != NULL);
 
        if (item->path != NULL) {
                cache_file = folder_item_get_cache_file(item);
                mark_file = folder_item_get_mark_file(item);
+               tags_file = folder_item_get_tags_file(item);
                item->cache = msgcache_read_cache(item, cache_file);
                if (!item->cache) {
                        MsgInfoList *list, *cur;
@@ -2321,8 +2376,11 @@ static void folder_item_read_cache(FolderItem *item)
                } else
                        msgcache_read_mark(item->cache, mark_file);
 
+               msgcache_read_tags(item->cache, tags_file);
+
                g_free(cache_file);
                g_free(mark_file);
+               g_free(tags_file);
        } else {
                item->cache = msgcache_new();
        }
@@ -2332,7 +2390,7 @@ static void folder_item_read_cache(FolderItem *item)
 
 void folder_item_write_cache(FolderItem *item)
 {
-       gchar *cache_file, *mark_file;
+       gchar *cache_file, *mark_file, *tags_file;
        FolderItemPrefs *prefs;
        gint filemode = 0;
        gchar *id;
@@ -2353,7 +2411,8 @@ void folder_item_write_cache(FolderItem *item)
 
        cache_file = folder_item_get_cache_file(item);
        mark_file = folder_item_get_mark_file(item);
-       if (msgcache_write(cache_file, mark_file, item->cache) < 0) {
+       tags_file = folder_item_get_tags_file(item);
+       if (msgcache_write(cache_file, mark_file, tags_file, item->cache) < 0) {
                prefs = item->prefs;
                if (prefs && prefs->enable_folder_chmod && prefs->folder_chmod) {
                        /* for cache file */
@@ -2372,6 +2431,7 @@ void folder_item_write_cache(FolderItem *item)
 
        g_free(cache_file);
        g_free(mark_file);
+       g_free(tags_file);
 }
 
 MsgInfo *folder_item_get_msginfo(FolderItem *item, gint num)
@@ -2525,7 +2585,11 @@ gchar *folder_item_fetch_msg_full(FolderItem *item, gint num, gboolean headers,
        if (folder->klass->fetch_msg_full == NULL)
                return folder_item_fetch_msg(item, num);
 
-       msgfile = folder->klass->fetch_msg_full(folder, item, num, 
+       if (item->prefs->offlinesync && prefs_common.real_time_sync)
+               msgfile = folder->klass->fetch_msg_full(folder, item, num, 
+                                               TRUE, TRUE);
+       else
+               msgfile = folder->klass->fetch_msg_full(folder, item, num, 
                                                headers, body);
 
        if (msgfile != NULL) {
@@ -2590,6 +2654,8 @@ gint folder_item_fetch_all_msg(FolderItem *item)
                                        folder->ui_func_data ?
                                        folder->ui_func_data :
                                        GINT_TO_POINTER(num));
+               if (num % 50 == 0)
+                       GTK_EVENTS_FLUSH();
 
                msg = folder_item_fetch_msg(item, msginfo->msgnum);
                if (!msg) {
@@ -2622,10 +2688,27 @@ static gint folder_item_get_msg_num_by_file(FolderItem *dest, const gchar *file)
 
        if ((folder_has_parent_of_type(dest, F_QUEUE)) || 
            (folder_has_parent_of_type(dest, F_DRAFT)))
-               while (fgets(buf, sizeof(buf), fp) != NULL)
+               while (fgets(buf, sizeof(buf), fp) != NULL) {
+                       /* new way */
+                       if ((!strncmp(buf, "X-Claws-End-Special-Headers: 1",
+                               strlen("X-Claws-End-Special-Headers:"))) ||
+                           (!strncmp(buf, "X-Sylpheed-End-Special-Headers: 1",
+                               strlen("X-Sylpheed-End-Special-Headers:"))))
+                               break;
+                       /* old way */
                        if (buf[0] == '\r' || buf[0] == '\n') break;
+                       /* from other mailers */
+                       if (!strncmp(buf, "Date: ", 6)
+                       ||  !strncmp(buf, "To: ", 4)
+                       ||  !strncmp(buf, "From: ", 6)
+                       ||  !strncmp(buf, "Subject: ", 9)) {
+                               rewind(fp);
+                               break;
+                       }
+               }
 
        procheader_get_header_fields(fp, hentry);
+       debug_print("looking for %s\n", hentry[0].body);
        if (hentry[0].body) {
                extract_parenthesis(hentry[0].body, '<', '>');
                remove_space(hentry[0].body);
@@ -2670,6 +2753,9 @@ static void copy_msginfo_flags(MsgInfo *source, MsgInfo *dest)
        if (procmsg_msg_has_flagged_parent(dest, MSG_IGNORE_THREAD))
                perm_flags |= MSG_IGNORE_THREAD;
 
+       if (procmsg_msg_has_flagged_parent(dest, MSG_WATCH_THREAD))
+               perm_flags |= MSG_WATCH_THREAD;
+
        /* Unset tmp flags that should not be copied */
        tmp_flags &= ~(MSG_MOVE | MSG_COPY | MSG_MOVE_DONE);
 
@@ -2680,6 +2766,11 @@ static void copy_msginfo_flags(MsgInfo *source, MsgInfo *dest)
                                  ~dest->flags.tmp_flags  & tmp_flags,
                                   dest->flags.perm_flags & ~perm_flags,
                                   dest->flags.tmp_flags  & ~tmp_flags);
+       
+       if (source && source->tags) {
+               g_slist_free(dest->tags);
+               dest->tags = g_slist_copy(source->tags);
+       }
 }
 
 static void add_msginfo_to_cache(FolderItem *item, MsgInfo *newmsginfo, MsgInfo *flagsource)
@@ -2807,6 +2898,7 @@ gint folder_item_add_msgs(FolderItem *dest, GSList *file_list,
                                        folderscan = TRUE;
                                }
                                num = folder_item_get_msg_num_by_file(dest, fileinfo->file);
+                               debug_print("got num %d\n", num);
                        }
 
                        if (num > lastnum)
@@ -3165,7 +3257,17 @@ static gint do_copy_msgs(FolderItem *dest, GSList *msglist, gboolean remove_sour
                if (num >= 0) {
                        MsgInfo *newmsginfo = NULL;
 
-                       if (folderscan) {
+                       if (!folderscan && num > 0) {
+                               newmsginfo = get_msginfo(dest, num);
+                               if (newmsginfo != NULL) {
+                                       add_msginfo_to_cache(dest, newmsginfo, msginfo);
+                               }
+                       }
+                       if (newmsginfo == NULL) {
+                               if (!folderscan) {
+                                       folder_item_scan_full(dest, FALSE);
+                                       folderscan = TRUE;
+                               }
                                if (msginfo->msgid != NULL) {
                                        newmsginfo = folder_item_get_msginfo_by_msgid(dest, msginfo->msgid);
                                        if (newmsginfo != NULL) {
@@ -3173,11 +3275,6 @@ static gint do_copy_msgs(FolderItem *dest, GSList *msglist, gboolean remove_sour
                                                num = newmsginfo->msgnum;
                                        }
                                }
-                       } else {
-                               newmsginfo = get_msginfo(dest, num);
-                               if (newmsginfo != NULL) {
-                                       add_msginfo_to_cache(dest, newmsginfo, msginfo);
-                               }
                        }
 
                        if (msginfo->planned_download 
@@ -3421,6 +3518,7 @@ static gchar *folder_item_get_cache_file(FolderItem *item)
 {
        gchar *path;
        gchar *file;
+       gchar *old_file;
 
        g_return_val_if_fail(item != NULL, NULL);
        g_return_val_if_fail(item->path != NULL, NULL);
@@ -3430,6 +3528,11 @@ static gchar *folder_item_get_cache_file(FolderItem *item)
        if (!is_dir_exist(path))
                make_dir_hier(path);
        file = g_strconcat(path, G_DIR_SEPARATOR_S, CACHE_FILE, NULL);
+       old_file = g_strconcat(path, G_DIR_SEPARATOR_S, OLD_CACHE_FILE, NULL);
+
+       if (!is_file_exist(file) && is_file_exist(old_file))
+               move_file(old_file, file, FALSE);
+       g_free(old_file);
        g_free(path);
 
        return file;
@@ -3439,6 +3542,7 @@ static gchar *folder_item_get_mark_file(FolderItem *item)
 {
        gchar *path;
        gchar *file;
+       gchar *old_file;
 
        g_return_val_if_fail(item != NULL, NULL);
        g_return_val_if_fail(item->path != NULL, NULL);
@@ -3448,6 +3552,48 @@ static gchar *folder_item_get_mark_file(FolderItem *item)
        if (!is_dir_exist(path))
                make_dir_hier(path);
        file = g_strconcat(path, G_DIR_SEPARATOR_S, MARK_FILE, NULL);
+       old_file = g_strconcat(path, G_DIR_SEPARATOR_S, OLD_MARK_FILE, NULL);
+
+       if (!is_file_exist(file) && is_file_exist(old_file))
+               move_file(old_file, file, FALSE);
+       g_free(old_file);
+       g_free(path);
+
+       return file;
+}
+
+static gchar *folder_item_get_tags_file(FolderItem *item)
+{
+       gchar *path;
+       gchar *identifier;
+       gchar *file;
+
+       /* we save tags files in rc_dir, because tagsrc is there too,
+        * and storing tags directly in the mailboxes would give strange
+        * result when using another Claws mailbox from another install
+        * with different tags. */
+
+       g_return_val_if_fail(item != NULL, NULL);
+
+       identifier = folder_item_get_identifier(item);
+       g_return_val_if_fail(identifier != NULL, NULL);
+
+#ifdef G_OS_WIN32
+       while (strchr(identifier, '/'))
+               *strchr(identifier, '/') = '\\';
+#endif
+
+       path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                          "tagsdb", G_DIR_SEPARATOR_S,
+                          identifier, NULL);
+       
+       g_free(identifier);
+                          
+       if (!is_dir_exist(path))
+               make_dir_hier(path);
+
+       file = g_strconcat(path, G_DIR_SEPARATOR_S, TAGS_FILE, NULL);
+       
        g_free(path);
 
        return file;
@@ -3881,6 +4027,8 @@ void folder_item_apply_processing(FolderItem *item)
                 /* apply post global rules */
                filter_message_by_msginfo(post_global_processing, msginfo, NULL,
                                FILTERING_POST_PROCESSING, NULL);
+               if (curmsg % 1000 == 0)
+                       GTK_EVENTS_FLUSH();
        }
        prefs_common.apply_per_account_filtering_rules = last_apply_per_account;
 
@@ -3984,7 +4132,11 @@ void folder_item_synchronise(FolderItem *item)
                return;
        if (item->prefs->offlinesync && item->folder->klass->synchronise) {
                statusbar_print_all(_("Synchronising %s for offline use...\n"), item->path ? item->path : "(null)");
-               item->folder->klass->synchronise(item);
+               item->folder->klass->synchronise(item, 
+                       item->prefs->offlinesync_days);
+               if (item->prefs->offlinesync_days > 0 &&
+                   item->prefs->remove_old_bodies)
+                       folder_item_clean_local_files(item, item->prefs->offlinesync_days);
                statusbar_pop_all();
        }
 }