2007-08-03 [paul] 2.10.0cvs85
[claws.git] / src / mh.c
index 000c6c468ead0adecfff72e0806757bc57265ae6..2b8f9cf68d2681340c2514c9f945a8789b63e9b0 100644 (file)
--- a/src/mh.c
+++ b/src/mh.c
@@ -1,10 +1,10 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws team
+ * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail 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
- * 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
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
-
-#undef MEASURE_TIME
-
-#ifdef MEASURE_TIME
-#  include <sys/time.h>
-#endif
+#include <time.h>
 
 #include "folder.h"
 #include "mh.h"
@@ -45,6 +40,7 @@
 #include "codeconv.h"
 #include "statusbar.h"
 #include "gtkutils.h"
+#include "timing.h"
 
 /* Define possible missing constants for Windows. */
 #ifdef G_OS_WIN32
@@ -134,8 +130,10 @@ static gboolean mh_scan_required   (Folder         *folder,
                                         FolderItem     *item);
 static int mh_item_close               (Folder         *folder,
                                         FolderItem     *item);
+#if 0
 static gint mh_get_flags               (Folder *folder, FolderItem *item,
                                         MsgInfoList *msginfo_list, GRelation *msgflags);
+#endif
 static void mh_write_sequences         (FolderItem     *item, gboolean remove_unseen);
 
 static FolderClass mh_class;
@@ -235,7 +233,7 @@ gboolean mh_scan_required(Folder *folder, FolderItem *item)
        return FALSE;
 }
 
-void mh_get_last_num(Folder *folder, FolderItem *item)
+static void mh_get_last_num(Folder *folder, FolderItem *item)
 {
        gchar *path;
        DIR *dp;
@@ -266,6 +264,8 @@ void mh_get_last_num(Folder *folder, FolderItem *item)
                        if (max < num)
                                max = num;
                }
+               if (num % 100 == 0)
+                       GTK_EVENTS_FLUSH();
        }
        closedir(dp);
 
@@ -308,7 +308,7 @@ gint mh_get_num_list(Folder *folder, FolderItem *item, GSList **list, gboolean *
        }
        closedir(dp);
 
-       item->mtime = time(NULL);
+       mh_set_mtime(item);
        return nummsgs;
 }
 
@@ -456,6 +456,8 @@ static gint mh_copy_msgs(Folder *folder, FolderItem *dest, MsgInfoList *msglist,
                         GRelation *relation)
 {
        gboolean dest_need_scan = FALSE;
+       gboolean src_need_scan = FALSE;
+       FolderItem *src = NULL;
        gchar *srcfile;
        gchar *destfile;
        gint filemode = 0;
@@ -465,6 +467,8 @@ static gint mh_copy_msgs(Folder *folder, FolderItem *dest, MsgInfoList *msglist,
        gint curnum = 0, total = 0;
        gchar *srcpath = NULL;
        gboolean full_fetch = FALSE;
+       time_t last_dest_mtime = (time_t)0;
+       time_t last_src_mtime = (time_t)0;
 
        g_return_val_if_fail(dest != NULL, -1);
        g_return_val_if_fail(msglist != NULL, -1);
@@ -480,6 +484,10 @@ static gint mh_copy_msgs(Folder *folder, FolderItem *dest, MsgInfoList *msglist,
 
        if (msginfo->folder->folder != dest->folder)
                full_fetch = TRUE;
+       
+       if (FOLDER_TYPE(msginfo->folder->folder) == F_MH) {
+               src = msginfo->folder;
+       }
 
        if (dest->last_num < 0) {
                mh_get_last_num(folder, dest);
@@ -490,6 +498,14 @@ static gint mh_copy_msgs(Folder *folder, FolderItem *dest, MsgInfoList *msglist,
 
        srcpath = folder_item_get_path(msginfo->folder);
 
+       dest_need_scan = mh_scan_required(dest->folder, dest);
+       last_dest_mtime = dest->mtime;
+
+       if (src) {
+               src_need_scan = mh_scan_required(src->folder, src);
+               last_src_mtime = src->mtime;
+       }
+
        total = g_slist_length(msglist);
        if (total > 100) {
                if (MSG_IS_MOVE(msginfo->flags))
@@ -531,6 +547,7 @@ static gint mh_copy_msgs(Folder *folder, FolderItem *dest, MsgInfoList *msglist,
 
 
                if (MSG_IS_MOVE(msginfo->flags)) {
+                       msginfo->flags.tmp_flags &= ~MSG_MOVE_DONE;
                        if (move_file(srcfile, destfile, TRUE) < 0) {
                                FILE_OP_ERROR(srcfile, "move");
                                if (copy_file(srcfile, destfile, TRUE) < 0) {
@@ -539,6 +556,9 @@ static gint mh_copy_msgs(Folder *folder, FolderItem *dest, MsgInfoList *msglist,
                                        g_free(destfile);
                                        goto err_reset_status;
                                }
+                       } else {
+                               /* say unlinking's not necessary */
+                               msginfo->flags.tmp_flags |= MSG_MOVE_DONE;
                        }
                } else if (copy_file(srcfile, destfile, TRUE) < 0) {
                        FILE_OP_ERROR(srcfile, "copy");
@@ -565,10 +585,14 @@ static gint mh_copy_msgs(Folder *folder, FolderItem *dest, MsgInfoList *msglist,
        g_free(srcpath);
        mh_write_sequences(dest, TRUE);
 
-       dest_need_scan = mh_scan_required(dest->folder, dest);
-       if (!dest_need_scan)
-               dest->mtime = time(NULL);
-       
+       if (dest->mtime == last_dest_mtime && !dest_need_scan) {
+               mh_set_mtime(dest);
+       }
+
+       if (src && src->mtime == last_src_mtime && !src_need_scan) {
+               mh_set_mtime(src);
+       }
+
        if (total > 100) {
                statusbar_progress_all(0,0,0);
                statusbar_pop_all();
@@ -588,6 +612,7 @@ err_reset_status:
 static gint mh_remove_msg(Folder *folder, FolderItem *item, gint num)
 {
        gboolean need_scan = FALSE;
+       time_t last_mtime = (time_t)0;
        gchar *file;
 
        g_return_val_if_fail(item != NULL, -1);
@@ -596,6 +621,7 @@ static gint mh_remove_msg(Folder *folder, FolderItem *item, gint num)
        g_return_val_if_fail(file != NULL, -1);
 
        need_scan = mh_scan_required(folder, item);
+       last_mtime = item->mtime;
 
        if (g_unlink(file) < 0) {
                FILE_OP_ERROR(file, "unlink");
@@ -603,9 +629,9 @@ static gint mh_remove_msg(Folder *folder, FolderItem *item, gint num)
                return -1;
        }
 
-       if (!need_scan)
-               item->mtime = time(NULL);
-
+       if (item->mtime == last_mtime && !need_scan) {
+               mh_set_mtime(item);
+       }
        g_free(file);
        return 0;
 }
@@ -615,16 +641,37 @@ static gint mh_remove_msgs(Folder *folder, FolderItem *item,
 {
        gboolean need_scan = FALSE;
        gchar *path, *file;
+       time_t last_mtime = (time_t)0;
        MsgInfoList *cur;
+       gint total = 0, curnum = 0;
 
        g_return_val_if_fail(item != NULL, -1);
 
        path = folder_item_get_path(item);
        
+       need_scan = mh_scan_required(folder, item);
+       last_mtime = item->mtime;
+
+       total = g_slist_length(msglist);
+       if (total > 100) {
+               statusbar_print_all(_("Deleting messages..."));
+       }
+
        for (cur = msglist; cur; cur = cur->next) {
                MsgInfo *msginfo = (MsgInfo *)cur->data;
                if (msginfo == NULL)
                        continue;
+               if (MSG_IS_MOVE(msginfo->flags) && MSG_IS_MOVE_DONE(msginfo->flags)) {
+                       msginfo->flags.tmp_flags &= ~MSG_MOVE_DONE;
+                       continue;
+               }
+               if (total > 100) {
+                       statusbar_progress_all(curnum, total, 100);
+                       if (curnum % 100 == 0)
+                               GTK_EVENTS_FLUSH();
+                       curnum++;
+               }
+
                file = g_strconcat(path, G_DIR_SEPARATOR_S, itos(msginfo->msgnum), NULL);
                if (file == NULL)
                        continue;
@@ -637,10 +684,13 @@ static gint mh_remove_msgs(Folder *folder, FolderItem *item,
                g_free(file);
        }
 
-       need_scan = mh_scan_required(folder, item);
-
-       if (!need_scan)
-               item->mtime = time(NULL);
+       if (total > 100) {
+               statusbar_progress_all(0,0,0);
+               statusbar_pop_all();
+       }
+       if (item->mtime == last_mtime && !need_scan) {
+               mh_set_mtime(item);
+       }
 
        g_free(path);
        return 0;
@@ -714,7 +764,7 @@ static gint mh_scan_tree(Folder *folder)
                                    "Can't create folder.", dir); \
                        return -1; \
                } \
-               if (make_dir(dir) < 0) \
+               if (make_dir_hier(dir) < 0) \
                        return -1; \
        } \
 }
@@ -1024,12 +1074,12 @@ static void mh_scan_tree_recursive(FolderItem *item)
                entry = mh_filename_from_utf8(utf8entry);
 
                if (
-#if !defined(G_OS_WIN32) && defined(HAVE_DIRENT_D_TYPE)
+#if !defined(G_OS_WIN32) && !defined(MAEMO) && defined(HAVE_DIRENT_D_TYPE)
                        d->d_type == DT_DIR ||
                        (d->d_type == DT_UNKNOWN &&
 #endif
                        g_stat(entry, &s) == 0 && S_ISDIR(s.st_mode)
-#if !defined(G_OS_WIN32) && defined(HAVE_DIRENT_D_TYPE)
+#if !defined(G_OS_WIN32) && !defined(MAEMO) && defined(HAVE_DIRENT_D_TYPE)
                        )
 #endif
                   ) {
@@ -1039,10 +1089,13 @@ static void mh_scan_tree_recursive(FolderItem *item)
                        node = item->node;
                        for (node = node->children; node != NULL; node = node->next) {
                                FolderItem *cur_item = FOLDER_ITEM(node->data);
-                               if (!strcmp2(cur_item->path, entry)) {
+                               gchar *curpath = mh_filename_from_utf8(cur_item->path);
+                               if (!strcmp2(curpath, entry)) {
                                        new_item = cur_item;
+                                       g_free(curpath);
                                        break;
                                }
+                               g_free(curpath);
                        }
                        if (!new_item) {
                                debug_print("new folder '%s' found.\n", entry);
@@ -1088,7 +1141,7 @@ static void mh_scan_tree_recursive(FolderItem *item)
        closedir(dp);
 #endif
 
-       item->mtime = time(NULL);
+       mh_set_mtime(item);
 }
 
 static gboolean mh_rename_folder_func(GNode *node, gpointer data)
@@ -1125,7 +1178,7 @@ static gchar *mh_filename_from_utf8(const gchar *path)
        gchar *real_path = g_filename_from_utf8(path, -1, NULL, NULL, NULL);
 
        if (!real_path) {
-               g_warning("mh_filename_from_utf8: faild to convert character set\n");
+               g_warning("mh_filename_from_utf8: failed to convert character set\n");
                real_path = g_strdup(path);
        }
 
@@ -1136,7 +1189,7 @@ static gchar *mh_filename_to_utf8(const gchar *path)
 {
        gchar *utf8path = g_filename_to_utf8(path, -1, NULL, NULL, NULL);
        if (!utf8path) {
-               g_warning("mh_filename_to_utf8: faild to convert character set\n");
+               g_warning("mh_filename_to_utf8: failed to convert character set\n");
                utf8path = g_strdup(path);
        }
 
@@ -1183,6 +1236,7 @@ static gchar *get_unseen_seq_name(void)
        return seq_name;        
 }
 
+#if 0
 static gint mh_get_flags(Folder *folder, FolderItem *item,
                            MsgInfoList *msginfo_list, GRelation *msgflags)
 {
@@ -1278,6 +1332,7 @@ next_token:
 */
        return 0;
 }
+#endif
 
 static void mh_write_sequences(FolderItem *item, gboolean remove_unseen)
 {
@@ -1285,10 +1340,8 @@ static void mh_write_sequences(FolderItem *item, gboolean remove_unseen)
        FILE *mh_sequences_old_fp, *mh_sequences_new_fp;
        gchar buf[BUFFSIZE];
        gchar *path = NULL;
-/*
-       GTimer *timer = g_timer_new();
-       g_timer_start(timer);
-*/
+       START_TIMING("");
+
        if (!item)
                return;
        
@@ -1304,6 +1357,7 @@ static void mh_write_sequences(FolderItem *item, gboolean remove_unseen)
                MsgInfo *info = NULL;
                gint start = -1, end = -1;
                gchar *sequence = g_strdup("");
+               gint seq_len = 0;
                msglist = g_slist_sort(msglist, sort_cache_list_by_msgnum);
                cur = msglist;
                
@@ -1317,18 +1371,24 @@ static void mh_write_sequences(FolderItem *item, gboolean remove_unseen)
                                        end = info->msgnum;
                        } else {
                                if (start > 0 && end > 0) {
-                                       gchar *tmp = sequence;
+                                       gchar tmp[32];
+                                       gint tmp_len = 0;
                                        if (start != end)
-                                               sequence = g_strdup_printf("%s %d-%d ", tmp, start, end);
+                                               snprintf(tmp, 31, " %d-%d", start, end);
                                        else
-                                               sequence = g_strdup_printf("%s %d ", tmp, start);
-                                       g_free(tmp);
+                                               snprintf(tmp, 31, " %d", start);
+                                       
+                                       tmp_len = strlen(tmp);
+                                       sequence = g_realloc(sequence, seq_len+tmp_len+1);
+                                       strcpy(sequence+seq_len, tmp);
+                                       seq_len += tmp_len;
+
                                        start = end = -1;
                                }
                        }
                        cur = cur ? cur->next:NULL;
                } while (cur || (start > 0 && end > 0));
-               if (sequence && strlen(sequence)) {
+               if (sequence && *sequence) {
                        fprintf(mh_sequences_new_fp, "%s%s\n", 
                                        get_unseen_seq_name(), sequence);
                        debug_print("wrote unseen sequence: '%s%s'\n", 
@@ -1343,7 +1403,12 @@ static void mh_write_sequences(FolderItem *item, gboolean remove_unseen)
                        fclose(mh_sequences_old_fp);
                }
                
+               fflush(mh_sequences_new_fp);
+#if 0
+               fsync(fileno(mh_sequences_new_fp));
+#endif
                fclose(mh_sequences_new_fp);
+
                g_rename(mh_sequences_new, mh_sequences_old);
                g_free(sequence);
                procmsg_msg_list_free(msglist);
@@ -1351,15 +1416,39 @@ static void mh_write_sequences(FolderItem *item, gboolean remove_unseen)
        g_free(mh_sequences_old);
        g_free(mh_sequences_new);
        g_free(path);
-/*
-       g_timer_stop(timer);
-       printf("mh_get_flags: %f secs\n", g_timer_elapsed(timer, NULL));
-       g_timer_destroy(timer);
-*/
+
+       END_TIMING();
 }
 
 static int mh_item_close(Folder *folder, FolderItem *item)
 {
+       time_t last_mtime = (time_t)0;
+       gboolean need_scan = mh_scan_required(item->folder, item);
+       last_mtime = item->mtime;
+
        mh_write_sequences(item, FALSE);
+
+       if (item->mtime == last_mtime && !need_scan) {
+               mh_set_mtime(item);
+       }
+
        return 0;
 }
+
+void mh_set_mtime(FolderItem *item)
+{
+       struct stat s;
+       gchar *path = folder_item_get_path(item);
+
+       g_return_if_fail(path != NULL);
+
+       if (stat(path, &s) < 0) {
+               FILE_OP_ERROR(path, "stat");
+               g_free(path);
+               return;
+       }
+
+       item->mtime = s.st_mtime;
+       debug_print("MH: forced mtime of %s to %ld\n", item->name, item->mtime);
+       g_free(path);
+}