add markfile declaration to appropriate functions when fchmod is not available
[claws.git] / src / mh.c
index 77e23251054e7d5c730589235fd9d0b753f50d3e..b9996810f6a34443649599d82f659862d2629ceb 100644 (file)
--- a/src/mh.c
+++ b/src/mh.c
@@ -26,6 +26,8 @@
 #include <glib.h>
 #include <dirent.h>
 #include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
 #include <errno.h>
 
 #undef MEASURE_TIME
@@ -128,7 +130,8 @@ gchar *mh_fetch_msg(Folder *folder, FolderItem *item, gint num)
        return file;
 }
 
-gint mh_add_msg(Folder *folder, FolderItem *dest, const gchar *file)
+gint mh_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
+               gboolean remove_source)
 {
        gchar *destpath;
        gchar *destfile;
@@ -143,12 +146,24 @@ gint mh_add_msg(Folder *folder, FolderItem *dest, const gchar *file)
 
        destpath = folder_item_get_path(dest);
        g_return_val_if_fail(destpath != NULL, -1);
+       if (!is_dir_exist(destpath))
+               make_dir_hier(destpath);
+
        destfile = g_strdup_printf("%s%c%d", destpath, G_DIR_SEPARATOR,
                                   dest->last_num + 1);
-       if (copy_file(file, destfile) < 0) {
-               g_warning(_("can't copy message %s to %s\n"), file, destfile);
-               g_free(destfile);
-               return -1;
+
+       if (link(file, destfile) < 0) {
+               if (copy_file(file, destfile) < 0) {
+                       g_warning(_("can't copy message %s to %s\n"),
+                                 file, destfile);
+                       g_free(destfile);
+                       return -1;
+               }
+       }
+
+       if (remove_source) {
+               if (unlink(file) < 0)
+                       FILE_OP_ERROR(file, "unlink");
        }
 
        g_free(destfile);
@@ -162,6 +177,8 @@ gint mh_move_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
        gchar *srcfile;
        gchar *destfile;
        FILE *fp;
+       gint filemode = 0;
+       PrefsFolderItem *prefs;
 
        g_return_val_if_fail(dest != NULL, -1);
        g_return_val_if_fail(msginfo != NULL, -1);
@@ -176,6 +193,8 @@ gint mh_move_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
                if (dest->last_num < 0) return -1;
        }
 
+       prefs = dest->prefs;
+
        destdir = folder_item_get_path(dest);
        if ((fp = procmsg_open_mark_file(destdir, TRUE)) == NULL)
                g_warning(_("Can't open mark file.\n"));
@@ -188,29 +207,21 @@ gint mh_move_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
                                   dest->last_num + 1);
        g_free(destdir);
 
-       if (is_file_exist(destfile)) {
-               g_warning(_("%s already exists."), destfile);
+       if (move_file(srcfile, destfile) < 0) {
                g_free(srcfile);
                g_free(destfile);
                if (fp) fclose(fp);
                return -1;
        }
 
-       if (rename(srcfile, destfile) < 0) {
-               if (EXDEV == errno) {
-                       if (copy_file(srcfile, destfile) < 0) {
-                               g_free(srcfile);
-                               g_free(destfile);
-                               return -1;
-                       }
-                       unlink(srcfile);
-               } else {
-                       FILE_OP_ERROR(srcfile, "rename");
-                       g_free(srcfile);
-                       g_free(destfile);
-                       if (fp) fclose(fp);
-                       return -1;
-               }
+       if (prefs && prefs->enable_folder_chmod && prefs->folder_chmod) {
+               if (chmod(destfile, prefs->folder_chmod) < 0)
+                       FILE_OP_ERROR(destfile, "chmod");
+
+               /* for mark file */
+               filemode = prefs->folder_chmod;
+               if (filemode & S_IRGRP) filemode |= S_IWGRP;
+               if (filemode & S_IROTH) filemode |= S_IWOTH;
        }
 
        g_free(srcfile);
@@ -226,10 +237,25 @@ gint mh_move_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
                    dest->stype == F_QUEUE  ||
                    dest->stype == F_DRAFT  ||
                    dest->stype == F_TRASH)
-                       MSG_UNSET_FLAGS(newmsginfo.flags,
-                                       MSG_NEW|MSG_UNREAD|MSG_DELETED);
+                       MSG_UNSET_PERM_FLAGS(newmsginfo.flags,
+                                            MSG_NEW|MSG_UNREAD|MSG_DELETED);
 
                procmsg_write_flags(&newmsginfo, fp);
+
+               if (filemode) {
+#if HAVE_FCHMOD
+                       fchmod(fileno(fp), filemode);
+#else
+                       gchar *markfile;
+
+                       markfile = folder_item_get_mark_file(dest);
+                       if (markfile) {
+                               chmod(markfile, filemode);
+                               g_free(markfile);
+                       }
+#endif
+               }
+
                fclose(fp);
        }
 
@@ -244,6 +270,7 @@ gint mh_move_msgs_with_dest(Folder *folder, FolderItem *dest, GSList *msglist)
        FILE *fp;
        GSList *cur;
        MsgInfo *msginfo;
+       PrefsFolderItem *prefs;
 
        g_return_val_if_fail(dest != NULL, -1);
        g_return_val_if_fail(msglist != NULL, -1);
@@ -253,6 +280,8 @@ gint mh_move_msgs_with_dest(Folder *folder, FolderItem *dest, GSList *msglist)
                if (dest->last_num < 0) return -1;
        }
 
+       prefs = dest->prefs;
+
        destdir = folder_item_get_path(dest);
        if ((fp = procmsg_open_mark_file(destdir, TRUE)) == NULL)
                g_warning(_("Can't open mark file.\n"));
@@ -272,29 +301,12 @@ gint mh_move_msgs_with_dest(Folder *folder, FolderItem *dest, GSList *msglist)
                destfile = g_strdup_printf("%s%c%d", destdir, G_DIR_SEPARATOR,
                                           dest->last_num + 1);
 
-               if (is_file_exist(destfile)) {
-                       g_warning(_("%s already exists."), destfile);
+               if (move_file(srcfile, destfile) < 0) {
                        g_free(srcfile);
                        g_free(destfile);
                        break;
                }
 
-               if (rename(srcfile, destfile) < 0) {
-                       if (EXDEV == errno) {
-                               if (copy_file(srcfile, destfile) < 0) {
-                                       g_free(srcfile);
-                                       g_free(destfile);
-                                       break;
-                               }
-                               unlink(srcfile);
-                       } else {
-                               FILE_OP_ERROR(srcfile, "rename");
-                               g_free(srcfile);
-                               g_free(destfile);
-                               break;
-                       }
-               }
-
                g_free(srcfile);
                g_free(destfile);
                dest->last_num++;
@@ -308,8 +320,9 @@ gint mh_move_msgs_with_dest(Folder *folder, FolderItem *dest, GSList *msglist)
                            dest->stype == F_QUEUE  ||
                            dest->stype == F_DRAFT  ||
                            dest->stype == F_TRASH)
-                               MSG_UNSET_FLAGS(newmsginfo.flags,
-                                               MSG_NEW|MSG_UNREAD|MSG_DELETED);
+                               MSG_UNSET_PERM_FLAGS
+                                       (newmsginfo.flags,
+                                        MSG_NEW|MSG_UNREAD|MSG_DELETED);
 
                        procmsg_write_flags(&newmsginfo, fp);
                }
@@ -327,6 +340,8 @@ gint mh_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
        gchar *srcfile;
        gchar *destfile;
        FILE *fp;
+       gint filemode = 0;
+       PrefsFolderItem *prefs;
 
        g_return_val_if_fail(dest != NULL, -1);
        g_return_val_if_fail(msginfo != NULL, -1);
@@ -341,7 +356,12 @@ gint mh_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
                if (dest->last_num < 0) return -1;
        }
 
+       prefs = dest->prefs;
+
        destdir = folder_item_get_path(dest);
+       if (!is_dir_exist(destdir))
+               make_dir_hier(destdir);
+
        if ((fp = procmsg_open_mark_file(destdir, TRUE)) == NULL)
                g_warning(_("Can't open mark file.\n"));
 
@@ -353,6 +373,8 @@ gint mh_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
                                   dest->last_num + 1);
        g_free(destdir);
 
+       dest->op_count--;
+
        if (is_file_exist(destfile)) {
                g_warning(_("%s already exists."), destfile);
                g_free(srcfile);
@@ -369,6 +391,16 @@ gint mh_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
                return -1;
        }
 
+       if (prefs && prefs->enable_folder_chmod && prefs->folder_chmod) {
+               if (chmod(destfile, prefs->folder_chmod) < 0)
+                       FILE_OP_ERROR(destfile, "chmod");
+
+               /* for mark file */
+               filemode = prefs->folder_chmod;
+               if (filemode & S_IRGRP) filemode |= S_IWGRP;
+               if (filemode & S_IROTH) filemode |= S_IWOTH;
+       }
+
        g_free(srcfile);
        g_free(destfile);
        dest->last_num++;
@@ -382,15 +414,75 @@ gint mh_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
                    dest->stype == F_QUEUE  ||
                    dest->stype == F_DRAFT  ||
                    dest->stype == F_TRASH)
-                       MSG_UNSET_FLAGS(newmsginfo.flags,
-                                       MSG_NEW|MSG_UNREAD|MSG_DELETED);
+                       MSG_UNSET_PERM_FLAGS(newmsginfo.flags,
+                                            MSG_NEW|MSG_UNREAD|MSG_DELETED);
                procmsg_write_flags(&newmsginfo, fp);
+
+               if (filemode) {
+#if HAVE_FCHMOD
+                       fchmod(fileno(fp), filemode);
+#else
+                       gchar *markfile;
+
+                       markfile = folder_item_get_mark_file(dest);
+                       if (markfile) {
+                               chmod(markfile, filemode);
+                               g_free(markfile);
+                       }
+#endif
+               }
+
                fclose(fp);
        }
 
        return dest->last_num;
 }
 
+/*
+gint mh_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
+{
+       Folder * src_folder;
+       gchar * filename;
+       gint num;
+       gchar * destdir;
+       FILE * fp;
+
+       src_folder = msginfo->folder->folder;
+       
+       g_return_val_if_fail(src_folder->fetch_msg != NULL, -1);
+       
+       filename = src_folder->fetch_msg(src_folder,
+                                        msginfo->folder,
+                                        msginfo->msgnum);
+       if (filename == NULL)
+               return -1;
+
+       num = folder->add_msg(folder, dest, filename, FALSE);
+
+       destdir = folder_item_get_path(dest);
+       if ((fp = procmsg_open_mark_file(destdir, TRUE)) == NULL)
+               g_warning(_("Can't open mark file.\n"));
+
+       if (fp) {
+               MsgInfo newmsginfo;
+
+               newmsginfo.msgnum = dest->last_num;
+               newmsginfo.flags = msginfo->flags;
+               if (dest->stype == F_OUTBOX ||
+                   dest->stype == F_QUEUE  ||
+                   dest->stype == F_DRAFT  ||
+                   dest->stype == F_TRASH)
+                       MSG_UNSET_FLAGS(newmsginfo.flags,
+                                       MSG_NEW|MSG_UNREAD|MSG_DELETED);
+
+               procmsg_write_flags(&newmsginfo, fp);
+               fclose(fp);
+       }
+       
+       return num;
+}
+*/
+
 gint mh_copy_msgs_with_dest(Folder *folder, FolderItem *dest, GSList *msglist)
 {
        gchar *destdir;
@@ -409,6 +501,9 @@ gint mh_copy_msgs_with_dest(Folder *folder, FolderItem *dest, GSList *msglist)
        }
 
        destdir = folder_item_get_path(dest);
+       if (!is_dir_exist(destdir))
+               make_dir_hier(destdir);
+
        if ((fp = procmsg_open_mark_file(destdir, TRUE)) == NULL)
                g_warning(_("Can't open mark file.\n"));
 
@@ -454,8 +549,9 @@ gint mh_copy_msgs_with_dest(Folder *folder, FolderItem *dest, GSList *msglist)
                            dest->stype == F_QUEUE  ||
                            dest->stype == F_DRAFT  ||
                            dest->stype == F_TRASH)
-                               MSG_UNSET_FLAGS(newmsginfo.flags,
-                                               MSG_NEW|MSG_UNREAD|MSG_DELETED);
+                               MSG_UNSET_PERM_FLAGS
+                                       (newmsginfo.flags,
+                                        MSG_NEW|MSG_UNREAD|MSG_DELETED);
                        procmsg_write_flags(&newmsginfo, fp);
                }
        }
@@ -488,32 +584,16 @@ gint mh_remove_msg(Folder *folder, FolderItem *item, gint num)
 gint mh_remove_all_msg(Folder *folder, FolderItem *item)
 {
        gchar *path;
-       DIR *dp;
-       struct dirent *d;
+       gint val;
 
        g_return_val_if_fail(item != NULL, -1);
 
        path = folder_item_get_path(item);
        g_return_val_if_fail(path != NULL, -1);
-       if (change_dir(path) < 0) {
-               g_free(path);
-               return -1;
-       }
+       val = remove_all_numbered_files(path);
        g_free(path);
 
-       if ((dp = opendir(".")) == NULL) {
-               FILE_OP_ERROR(item->path, "opendir");
-               return -1;
-       }
-
-       while ((d = readdir(dp)) != NULL) {
-               if (to_number(d->d_name) < 0) continue;
-               if (unlink(d->d_name) < 0)
-                       FILE_OP_ERROR(d->d_name, "unlink");
-       }
-
-       closedir(dp);
-       return 0;
+       return val;
 }
 
 gboolean mh_is_msg_changed(Folder *folder, FolderItem *item, MsgInfo *msginfo)
@@ -540,6 +620,8 @@ void mh_scan_folder(Folder *folder, FolderItem *item)
 
        g_return_if_fail(item != NULL);
 
+       debug_print("mh_scan_folder(): Scanning %s ...\n", item->path);
+
        path = folder_item_get_path(item);
        g_return_if_fail(path != NULL);
        if (change_dir(path) < 0) {
@@ -659,6 +741,9 @@ FolderItem *mh_create_folder(Folder *folder, FolderItem *parent,
        g_return_val_if_fail(name != NULL, NULL);
 
        path = folder_item_get_path(parent);
+       if (!is_dir_exist(path))
+               make_dir_hier(path);
+
        fullpath = g_strconcat(path, G_DIR_SEPARATOR_S, name, NULL);
        g_free(path);
 
@@ -698,6 +783,9 @@ gint mh_rename_folder(Folder *folder, FolderItem *item, const gchar *name)
        g_return_val_if_fail(name != NULL, -1);
 
        oldpath = folder_item_get_path(item);
+       if (!is_dir_exist(oldpath))
+               make_dir_hier(oldpath);
+
        dirname = g_dirname(oldpath);
        newpath = g_strconcat(dirname, G_DIR_SEPARATOR_S, name, NULL);
        g_free(dirname);
@@ -856,15 +944,18 @@ static MsgInfo *mh_parse_msg(const gchar *file, FolderItem *item)
 {
        struct stat s;
        MsgInfo *msginfo;
-       MsgFlags flags = MSG_NEW|MSG_UNREAD;
+       MsgFlags flags;
+
+       flags.perm_flags = MSG_NEW|MSG_UNREAD;
+       flags.tmp_flags = 0;
 
        g_return_val_if_fail(item != NULL, NULL);
        g_return_val_if_fail(file != NULL, NULL);
 
        if (item->stype == F_QUEUE) {
-               MSG_SET_FLAGS(flags, MSG_QUEUED);
+               MSG_SET_TMP_FLAGS(flags, MSG_QUEUED);
        } else if (item->stype == F_DRAFT) {
-               MSG_SET_FLAGS(flags, MSG_DRAFT);
+               MSG_SET_TMP_FLAGS(flags, MSG_DRAFT);
        }
 
        msginfo = procheader_parse(file, flags, FALSE);
@@ -887,7 +978,7 @@ static MsgInfo *mh_parse_msg(const gchar *file, FolderItem *item)
 
 static gboolean mh_is_maildir_one(const gchar *path, const gchar *dir)
 {
-       char *entry;
+       gchar *entry;
        gboolean result;
 
        entry = g_strconcat(path, G_DIR_SEPARATOR_S, dir, NULL);