2005-09-14 [paul] 1.9.14cvs26
[claws.git] / src / mh.c
index 33a63068198af0eba32a80daa94a8c740713b5cd..e56b9dd3e9bca2a8a4111ae033816481b63e64e8 100644 (file)
--- a/src/mh.c
+++ b/src/mh.c
@@ -24,6 +24,7 @@
 #include "defs.h"
 
 #include <glib.h>
+#include <glib/gi18n.h>
 #include <dirent.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -36,7 +37,6 @@
 #  include <sys/time.h>
 #endif
 
-#include "intl.h"
 #include "folder.h"
 #include "mh.h"
 #include "procmsg.h"
@@ -107,6 +107,9 @@ static gboolean mh_rename_folder_func               (GNode          *node,
 static gchar   *mh_item_get_path               (Folder *folder, 
                                                 FolderItem *item);
 
+static gboolean mh_scan_required       (Folder         *folder,
+                                        FolderItem     *item);
+
 static FolderClass mh_class;
 
 FolderClass *mh_get_class(void)
@@ -130,6 +133,7 @@ FolderClass *mh_get_class(void)
                mh_class.rename_folder = mh_rename_folder;
                mh_class.remove_folder = mh_remove_folder;
                mh_class.get_num_list = mh_get_num_list;
+               mh_class.scan_required = mh_scan_required;
                
                /* Message functions */
                mh_class.get_msginfo = mh_get_msginfo;
@@ -167,6 +171,38 @@ static void mh_folder_init(Folder *folder, const gchar *name, const gchar *path)
 
 }
 
+gboolean mh_scan_required(Folder *folder, FolderItem *item)
+{
+       gchar *path;
+       struct stat s;
+
+       path = folder_item_get_path(item);
+       g_return_val_if_fail(path != NULL, FALSE);
+
+       if (stat(path, &s) < 0) {
+               FILE_OP_ERROR(path, "stat");
+               g_free(path);
+               return FALSE;
+       }
+
+       if ((s.st_mtime > item->mtime) &&
+               (s.st_mtime - 3600 != item->mtime)) {
+               debug_print("MH scan required, folder updated: %s (%ld > %ld)\n",
+                           path,
+                           (long int) s.st_mtime,
+                           (long int) item->mtime);
+               g_free(path);
+               return TRUE;
+       }
+
+       debug_print("MH scan not required: %s (%ld <= %ld)\n",
+                   path,
+                   (long int) s.st_mtime,
+                   (long int) item->mtime);
+       g_free(path);
+       return FALSE;
+}
+
 void mh_get_last_num(Folder *folder, FolderItem *item)
 {
        gchar *path;
@@ -215,7 +251,7 @@ gint mh_get_num_list(Folder *folder, FolderItem *item, GSList **list, gboolean *
 
        g_return_val_if_fail(item != NULL, -1);
 
-       debug_print("mh_get_last_num(): Scanning %s ...\n", item->path);
+       debug_print("mh_get_num_list(): Scanning %s ...\n", item->path);
 
        *old_uids_valid = TRUE;
 
@@ -240,6 +276,7 @@ gint mh_get_num_list(Folder *folder, FolderItem *item, GSList **list, gboolean *
        }
        closedir(dp);
 
+       item->mtime = time(NULL);
        return nummsgs;
 }
 
@@ -256,9 +293,10 @@ static gchar *mh_fetch_msg(Folder *folder, FolderItem *item, gint num)
 
        if (!is_file_exist(file)) {
                g_free(file);
+               g_free(path);
                return NULL;
        }
-
+       g_free(path);
        return file;
 }
 
@@ -347,14 +385,19 @@ static gint mh_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
                destfile = mh_get_new_msg_filename(dest);
                if (destfile == NULL) return -1;
 
+#ifdef G_OS_UNIX
                if (link(fileinfo->file, destfile) < 0) {
+#endif
                        if (copy_file(fileinfo->file, destfile, TRUE) < 0) {
                                g_warning(_("can't copy message %s to %s\n"),
                                          fileinfo->file, destfile);
                                g_free(destfile);
                                return -1;
                        }
+#ifdef G_OS_UNIX
                }
+#endif
+
                if (relation != NULL)
                        g_relation_insert(relation, fileinfo, GINT_TO_POINTER(dest->last_num + 1));
                g_free(destfile);
@@ -366,6 +409,7 @@ static gint mh_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
 
 static gint mh_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
 {
+       gboolean dest_need_scan = FALSE;
        gchar *srcfile;
        gchar *destfile;
        gint filemode = 0;
@@ -399,12 +443,19 @@ static gint mh_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
        
 
        if ((MSG_IS_QUEUED(msginfo->flags) || MSG_IS_DRAFT(msginfo->flags))
-       &&  dest->stype != F_QUEUE && dest->stype != F_DRAFT) {
+       && !folder_has_parent_of_type(dest, F_QUEUE)
+       && !folder_has_parent_of_type(dest, F_DRAFT)) {
                if (procmsg_remove_special_headers(srcfile, destfile) !=0) {
                        g_free(srcfile);
                        g_free(destfile);
                        return -1;
                }
+       } else if (!(MSG_IS_QUEUED(msginfo->flags) || MSG_IS_DRAFT(msginfo->flags))
+       && (folder_has_parent_of_type(dest, F_QUEUE)
+        || folder_has_parent_of_type(dest, F_DRAFT))) {
+               g_free(srcfile);
+               g_free(destfile);
+               return -1;
        } else if (copy_file(srcfile, destfile, TRUE) < 0) {
                FILE_OP_ERROR(srcfile, "copy");
                g_free(srcfile);
@@ -412,6 +463,10 @@ static gint mh_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
                return -1;
        }
 
+       dest_need_scan = mh_scan_required(dest->folder, dest);
+       if (!dest_need_scan)
+               dest->mtime = time(NULL);
+
 
        if (prefs && prefs->enable_folder_chmod && prefs->folder_chmod) {
                if (chmod(destfile, prefs->folder_chmod) < 0)
@@ -432,6 +487,7 @@ static gint mh_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
 
 static gint mh_remove_msg(Folder *folder, FolderItem *item, gint num)
 {
+       gboolean need_scan = FALSE;
        gchar *file;
 
        g_return_val_if_fail(item != NULL, -1);
@@ -439,12 +495,17 @@ static gint mh_remove_msg(Folder *folder, FolderItem *item, gint num)
        file = mh_fetch_msg(folder, item, num);
        g_return_val_if_fail(file != NULL, -1);
 
-       if (unlink(file) < 0) {
+       need_scan = mh_scan_required(folder, item);
+
+       if (g_unlink(file) < 0) {
                FILE_OP_ERROR(file, "unlink");
                g_free(file);
                return -1;
        }
 
+       if (!need_scan)
+               item->mtime = time(NULL);
+
        g_free(file);
        return 0;
 }
@@ -469,9 +530,11 @@ static gboolean mh_is_msg_changed(Folder *folder, FolderItem *item,
 {
        struct stat s;
 
-       if (stat(itos(msginfo->msgnum), &s) < 0 ||
-           msginfo->size  != s.st_size ||
-           msginfo->mtime != s.st_mtime)
+       if (g_stat(itos(msginfo->msgnum), &s) < 0 ||
+           msginfo->size  != s.st_size || (
+               (msginfo->mtime - s.st_mtime != 0) &&
+               (msginfo->mtime - s.st_mtime != 3600) &&
+               (msginfo->mtime - s.st_mtime != -3600)))
                return TRUE;
 
        return FALSE;
@@ -524,7 +587,7 @@ static gint mh_create_tree(Folder *folder)
 
        g_return_val_if_fail(folder != NULL, -1);
 
-       CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), -1);
+       CHDIR_RETURN_VAL_IF_FAIL(get_mail_base_dir(), -1);
        rootpath = LOCAL_FOLDER(folder)->rootpath;
        MAKE_DIR_IF_NOT_EXIST(rootpath);
        CHDIR_RETURN_VAL_IF_FAIL(rootpath, -1);
@@ -542,7 +605,7 @@ static gint mh_create_tree(Folder *folder)
 static gchar *mh_item_get_path(Folder *folder, FolderItem *item)
 {
        gchar *folder_path, *path;
-
+       gchar *real_path;
        g_return_val_if_fail(folder != NULL, NULL);
        g_return_val_if_fail(item != NULL, NULL);
 
@@ -565,8 +628,16 @@ static gchar *mh_item_get_path(Folder *folder, FolderItem *item)
                                            folder_path, NULL);
         }
        g_free(folder_path);
+       real_path = mh_filename_from_utf8(path);
+       if (!is_dir_exist(real_path) && is_dir_exist(path)) {
+               /* mmh, older version did put utf8 filenames instead of
+                * the correct encoding */
+               rename(path, real_path);
+               folder_item_scan(item);
+       }
 
-       return path;
+       g_free(path);
+       return real_path;
 }
 
 static FolderItem *mh_create_folder(Folder *folder, FolderItem *parent,
@@ -612,7 +683,7 @@ static FolderItem *mh_create_folder(Folder *folder, FolderItem *parent,
        path = folder_item_get_path(new_item);
        mh_sequences_filename = g_strconcat(path, G_DIR_SEPARATOR_S,
                                            ".mh_sequences", NULL);
-       if ((mh_sequences_file = fopen(mh_sequences_filename, "a+b")) != NULL) {
+       if ((mh_sequences_file = g_fopen(mh_sequences_filename, "a+b")) != NULL) {
                fclose(mh_sequences_file);
        }
        g_free(mh_sequences_filename);
@@ -644,7 +715,7 @@ static gint mh_rename_folder(Folder *folder, FolderItem *item,
        newpath = g_strconcat(dirname, G_DIR_SEPARATOR_S, real_name, NULL);
        g_free(real_name);
 
-       if (rename(oldpath, newpath) < 0) {
+       if (g_rename(oldpath, newpath) < 0) {
                FILE_OP_ERROR(oldpath, "rename");
                g_free(oldpath);
                g_free(newpath);
@@ -706,9 +777,9 @@ static MsgInfo *mh_parse_msg(const gchar *file, FolderItem *item)
        flags.perm_flags = MSG_NEW|MSG_UNREAD;
        flags.tmp_flags = 0;
 
-       if (item->stype == F_QUEUE) {
+       if (folder_has_parent_of_type(item, F_QUEUE)) {
                MSG_SET_TMP_FLAGS(flags, MSG_QUEUED);
-       } else if (item->stype == F_DRAFT) {
+       } else if (folder_has_parent_of_type(item, F_DRAFT)) {
                MSG_SET_TMP_FLAGS(flags, MSG_DRAFT);
        }
 
@@ -782,8 +853,13 @@ static void mh_remove_missing_folder_items(Folder *folder)
 static void mh_scan_tree_recursive(FolderItem *item)
 {
        Folder *folder;
+#ifdef G_OS_WIN32
+       GDir *dir;
+#else
        DIR *dp;
        struct dirent *d;
+#endif
+       const gchar *dir_name;
        struct stat s;
        gchar *real_path, *entry, *utf8entry, *utf8name;
        gint n_msg = 0;
@@ -794,11 +870,20 @@ static void mh_scan_tree_recursive(FolderItem *item)
        folder = item->folder;
 
        real_path = item->path ? mh_filename_from_utf8(item->path) : g_strdup(".");
+#ifdef G_OS_WIN32
+       dir = g_dir_open(real_path, 0, NULL);
+       if (!dir) {
+               g_warning("failed to open directory: %s\n", real_path);
+               g_free(real_path);
+               return;
+       }
+#else
        dp = opendir(real_path);
        if (!dp) {
                FILE_OP_ERROR(real_path, "opendir");
                return;
        }
+#endif
        g_free(real_path);
 
        debug_print("scanning %s ...\n",
@@ -807,10 +892,15 @@ static void mh_scan_tree_recursive(FolderItem *item)
        if (folder->ui_func)
                folder->ui_func(folder, item, folder->ui_func_data);
 
+#ifdef G_OS_WIN32
+       while ((dir_name = g_dir_read_name(dir)) != NULL) {
+#else
        while ((d = readdir(dp)) != NULL) {
-               if (d->d_name[0] == '.') continue;
+               dir_name = d->d_name;
+#endif
+               if (dir_name[0] == '.') continue;
 
-               utf8name = mh_filename_to_utf8(d->d_name);
+               utf8name = mh_filename_to_utf8(dir_name);
                if (item->path)
                        utf8entry = g_strconcat(item->path, G_DIR_SEPARATOR_S,
                                                utf8name, NULL);
@@ -819,12 +909,12 @@ static void mh_scan_tree_recursive(FolderItem *item)
                entry = mh_filename_from_utf8(utf8entry);
 
                if (
-#ifdef HAVE_DIRENT_D_TYPE
+#if !defined(G_OS_WIN32) && defined(HAVE_DIRENT_D_TYPE)
                        d->d_type == DT_DIR ||
                        (d->d_type == DT_UNKNOWN &&
 #endif
-                       stat(entry, &s) == 0 && S_ISDIR(s.st_mode)
-#ifdef HAVE_DIRENT_D_TYPE
+                       g_stat(entry, &s) == 0 && S_ISDIR(s.st_mode)
+#if !defined(G_OS_WIN32) && defined(HAVE_DIRENT_D_TYPE)
                        )
 #endif
                   ) {
@@ -856,37 +946,43 @@ static void mh_scan_tree_recursive(FolderItem *item)
 
                        if (!item->path) {
                                if (!folder->inbox &&
-                                   !strcmp(d->d_name, INBOX_DIR)) {
+                                   !strcmp(dir_name, INBOX_DIR)) {
                                        new_item->stype = F_INBOX;
                                        folder->inbox = new_item;
                                } else if (!folder->outbox &&
-                                          !strcmp(d->d_name, OUTBOX_DIR)) {
+                                          !strcmp(dir_name, OUTBOX_DIR)) {
                                        new_item->stype = F_OUTBOX;
                                        folder->outbox = new_item;
                                } else if (!folder->draft &&
-                                          !strcmp(d->d_name, DRAFT_DIR)) {
+                                          !strcmp(dir_name, DRAFT_DIR)) {
                                        new_item->stype = F_DRAFT;
                                        folder->draft = new_item;
                                } else if (!folder->queue &&
-                                          !strcmp(d->d_name, QUEUE_DIR)) {
+                                          !strcmp(dir_name, QUEUE_DIR)) {
                                        new_item->stype = F_QUEUE;
                                        folder->queue = new_item;
                                } else if (!folder->trash &&
-                                          !strcmp(d->d_name, TRASH_DIR)) {
+                                          !strcmp(dir_name, TRASH_DIR)) {
                                        new_item->stype = F_TRASH;
                                        folder->trash = new_item;
                                }
                        }
 
                        mh_scan_tree_recursive(new_item);
-               } else if (to_number(d->d_name) != -1) n_msg++;
+               } else if (to_number(dir_name) > 0) n_msg++;
 
                g_free(entry);
                g_free(utf8entry);
                g_free(utf8name);
        }
 
+#ifdef G_OS_WIN32
+       g_dir_close(dir);
+#else
        closedir(dp);
+#endif
+
+       item->mtime = time(NULL);
 
 /*
        if (item->path) {
@@ -934,34 +1030,23 @@ static gboolean mh_rename_folder_func(GNode *node, gpointer data)
        return FALSE;
 }
 
-#warning FIXME_GTK2 /* should we use g_filename_from_utf8()? */
 static gchar *mh_filename_from_utf8(const gchar *path)
 {
-       const gchar *src_codeset = CS_UTF_8;
-       const gchar *dest_codeset = conv_get_current_charset_str();
-       gchar *real_path;
+       gchar *real_path = g_filename_from_utf8(path, -1, NULL, NULL, NULL);
 
-       real_path = conv_codeset_strdup(path, src_codeset, dest_codeset);
        if (!real_path) {
                g_warning("mh_filename_from_utf8: faild to convert character set\n");
-               /* FIXME: show dialog? */
                real_path = g_strdup(path);
        }
 
        return real_path;
 }
 
-#warning FIXME_GTK2 /* should we use g_filename_to_utf8()? */
 static gchar *mh_filename_to_utf8(const gchar *path)
 {
-       const gchar *src_codeset = conv_get_current_charset_str();
-       const gchar *dest_codeset = CS_UTF_8;
-       gchar *utf8path;
-
-       utf8path = conv_codeset_strdup(path, src_codeset, dest_codeset);
+       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");
-               /* FIXME: show dialog? */
                utf8path = g_strdup(path);
        }