* src/filter.c
[claws.git] / src / mbox_folder.c
index ded6482..a0d4097 100644 (file)
@@ -1,3 +1,22 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2001 Hiroyuki Yamamoto & 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
 #include <unistd.h>
 #include <fcntl.h>
 #include <glib.h>
 
 #define MSGBUFSIZE     8192
 
+static void    mbox_folder_init                (Folder         *folder,
+                                                const gchar    *name,
+                                                const gchar    *path);
+
 static gboolean mbox_write_data(FILE * mbox_fp, FILE * new_fp,
                                gchar * new_filename, gint size);
 static gboolean mbox_rewrite(gchar * mbox);
@@ -23,7 +46,51 @@ static gboolean mbox_purge_deleted(gchar * mbox);
 static gchar * mbox_get_new_path(FolderItem * parent, gchar * name);
 static gchar * mbox_get_folderitem_name(gchar * name);
 
+MsgInfo *mbox_fetch_msginfo(Folder *folder, FolderItem *item, gint num);
+GSList *mbox_get_num_list(Folder *folder, FolderItem *item);
+gboolean mbox_check_msgnum_validity(Folder *folder, FolderItem *item);
+
+Folder *mbox_folder_new(const gchar *name, const gchar *path)
+{
+       Folder *folder;
+
+       folder = (Folder *)g_new0(MBOXFolder, 1);
+       mbox_folder_init(folder, name, path);
+
+       return folder;
+}
+
+void mbox_folder_destroy(MBOXFolder *folder)
+{
+       folder_local_folder_destroy(LOCAL_FOLDER(folder));
+}
+
+static void mbox_folder_init(Folder *folder, const gchar *name, const gchar *path)
+{
+       folder->type = F_MBOX;
 
+       folder_local_folder_init(folder, name, path);
+
+/*
+       folder->get_msg_list        = mbox_get_msg_list;
+*/
+       folder->fetch_msg           = mbox_fetch_msg;
+       folder->fetch_msginfo       = mbox_fetch_msginfo;
+       folder->add_msg             = mbox_add_msg;
+       folder->copy_msg            = mbox_copy_msg;
+       folder->remove_msg          = mbox_remove_msg;
+       folder->remove_all_msg      = mbox_remove_all_msg;
+/*
+       folder->scan                = mbox_scan_folder;
+*/
+       folder->get_num_list        = mbox_get_num_list;
+       folder->create_tree         = mbox_create_tree;
+       folder->create_folder       = mbox_create_folder;
+       folder->rename_folder       = mbox_rename_folder;
+       folder->remove_folder       = mbox_remove_folder;
+       folder->check_msgnum_validity
+                                   = mbox_check_msgnum_validity;
+}
 
 static gchar * mbox_folder_create_parent(const gchar * path)
 {
@@ -98,7 +165,7 @@ static gboolean mbox_file_lock_file(gchar * base)
        FILE *lockfp;
 
        lockfile = g_strdup_printf("%s.%d", base, getpid());
-       if ((lockfp = fopen(lockfile, "w")) == NULL) {
+       if ((lockfp = fopen(lockfile, "wb")) == NULL) {
                FILE_OP_ERROR(lockfile, "fopen");
                g_warning(_("can't create lock file %s\n"), lockfile);
                g_warning(_("use 'flock' instead of 'file' if possible.\n"));
@@ -301,6 +368,11 @@ struct _message
        gboolean fetched;
 };
 
+#define MSG_IS_INVALID(msg) \
+       ((msg).perm_flags == (msg).tmp_flags && (msg).tmp_flags == -1)
+
+#define MSG_SET_INVALID(msg) \
+       ((msg).perm_flags = (msg).tmp_flags = -1)
 
 static int startFrom(char * s)
 {
@@ -381,8 +453,8 @@ static mailfile * mailfile_init_from_file(FILE * f, gchar * filename)
                                data->content = 0;
                                data->messageid = NULL;
                                data->fromspace = NULL;
-                               data->flags = -1;
-                               data->old_flags = -1;
+                               MSG_SET_INVALID(data->flags);
+                               MSG_SET_INVALID(data->old_flags);
                                data->fetched = FALSE;
                                msg_list = g_list_append(msg_list,
                                                         (gpointer) data);
@@ -477,7 +549,7 @@ static mailfile * mailfile_init(char * filename)
        FILE * f;
        mailfile * mf;
   
-       f = fopen(filename, "r");
+       f = fopen(filename, "rb");
 
        if (f == NULL) {
                mailfile_error = MAILFILE_ERROR_FILE_NOT_FOUND;
@@ -515,7 +587,7 @@ static char * readfile(char * filename, int offset, int max_offset)
        int bread;
        FILE * handle;
 
-       handle = fopen(filename, "r");
+       handle = fopen(filename, "rb");
 
        if (handle == NULL) {
                mailfile_error = MAILFILE_ERROR_FILE_NOT_FOUND;
@@ -617,7 +689,7 @@ static int mailfile_find_deleted(mailfile f, char * filename)
 {
        FILE * handle;
 
-       handle = fopen(filename, "r");
+       handle = fopen(filename, "rb");
 
        while (elt) {
                struct _message m = elt->data;
@@ -655,19 +727,21 @@ static MsgInfo *mbox_parse_msg(FILE * fp, struct _message * msg,
                               FolderItem *item)
 {
        MsgInfo *msginfo;
-       MsgFlags flags = MSG_NEW|MSG_UNREAD;
+       MsgFlags flags = { 0, 0 };
+
+       MSG_SET_PERM_FLAGS(flags, MSG_NEW | MSG_UNREAD);
 
        g_return_val_if_fail(fp != NULL, NULL);
 
        if (item != 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_file_parse(fp, flags, FALSE);
+       msginfo = procheader_parse_stream(fp, flags, FALSE, FALSE);
 
        if (!msginfo) return NULL;
 
@@ -733,7 +807,7 @@ static void mbox_cache_get_msginfo(gchar * filename, GList * msg_list)
 {
        FILE * fp;
 
-       fp = fopen(filename, "r");
+       fp = fopen(filename, "rb");
        if (fp == NULL)
                return;
 
@@ -880,9 +954,7 @@ static void mbox_cache_synchronize_lists(GList * old_msg_list,
 
                        if ((strcmp(msg->messageid, msg2->messageid) == 0) &&
                            (strcmp(msg->fromspace, msg2->fromspace) == 0)) {
-                               if ((msg2->flags & MSG_PERMANENT_FLAG_MASK) !=
-                                   (msg2->old_flags &
-                                    MSG_PERMANENT_FLAG_MASK)) {
+                               if (msg2->flags.perm_flags != msg2->old_flags.perm_flags) {
                                        msg->flags = msg2->flags;
                                        break;
                                }
@@ -1121,7 +1193,7 @@ GSList *mbox_get_msg_list(Folder *folder, FolderItem *item, gboolean use_cache)
 
        mbox_purge_deleted(mbox_path);
 
-       fp = fopen(mbox_path, "r");
+       fp = fopen(mbox_path, "rb");
        
        if (fp == NULL) {
                g_free(mbox_path);
@@ -1140,12 +1212,12 @@ GSList *mbox_get_msg_list(Folder *folder, FolderItem *item, gboolean use_cache)
 
                msg = (struct _message *) l->data;
 
-               if (msg->flags == -1 || !MSG_IS_REALLY_DELETED(msg->flags)) {
+               if (MSG_IS_INVALID(msg->flags) || !MSG_IS_REALLY_DELETED(msg->flags)) {
                        fseek(fp, msg->header, SEEK_SET);
 
                        msginfo = mbox_parse_msg(fp, msg, item);
 
-                       if (msg->flags != -1)
+                       if (!MSG_IS_INVALID(msg->flags))
                                msginfo->flags = msg->flags;
                        else {
                                msg->old_flags = msginfo->flags;
@@ -1155,7 +1227,7 @@ GSList *mbox_get_msg_list(Folder *folder, FolderItem *item, gboolean use_cache)
                        mlist = g_slist_append(mlist, msginfo);
                }
                else {
-                       msg->flags = MSG_REALLY_DELETED;
+                       MSG_SET_PERM_FLAGS(msg->flags, MSG_REALLY_DELETED);
                }
        }
 
@@ -1195,7 +1267,7 @@ static gboolean mbox_extract_msg(FolderItem * item, gint msgnum,
        if (mbox_path == NULL)
                return FALSE;
 
-       src = fopen(mbox_path, "r");
+       src = fopen(mbox_path, "rb");
        if (src == NULL) {
                g_free(mbox_path);
                return FALSE;
@@ -1230,7 +1302,7 @@ static gboolean mbox_extract_msg(FolderItem * item, gint msgnum,
 
        fseek(src, offset, SEEK_SET);
 
-       dest = fopen(dest_filename, "w");
+       dest = fopen(dest_filename, "wb");
        if (dest == NULL) {
                mbox_unlock_file(src, mbox_path);
                fclose(src);
@@ -1289,7 +1361,6 @@ gchar *mbox_fetch_msg(Folder *folder, FolderItem *item, gint num)
        gchar *filename;
        
        g_return_val_if_fail(item != NULL, NULL);
-       g_return_val_if_fail(num > 0 && num <= item->last_num, NULL);
 
        path = folder_item_get_path(item);
        if (!is_dir_exist(path))
@@ -1324,7 +1395,7 @@ gint mbox_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
                if (dest->last_num < 0) return -1;
        }
 
-       src_fp = fopen(file, "r");
+       src_fp = fopen(file, "rb");
        if (src_fp == NULL) {
                return -1;
        }
@@ -1333,7 +1404,7 @@ gint mbox_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
        if (mbox_path == NULL)
                return -1;
 
-       dest_fp = fopen(mbox_path, "a");
+       dest_fp = fopen(mbox_path, "ab");
        if (dest_fp == NULL) {
                fclose(src_fp);
                g_free(mbox_path);
@@ -1363,7 +1434,7 @@ gint mbox_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
 
                if (stat(file, &s) < 0) {
                        mbox_unlock_file(dest_fp, mbox_path);
-                       g_warning(_("unvalid file - %s.\n"), file);
+                       g_warning(_("invalid file - %s.\n"), file);
                        fclose(dest_fp);
                        fclose(src_fp);
                        g_free(mbox_path);
@@ -1444,9 +1515,9 @@ gint mbox_remove_msg(Folder *folder, FolderItem *item, gint num)
        msg = mbox_cache_get_msg(mbox_path, num);
 
        g_free(mbox_path);
-       
+
        if (msg != NULL)
-               MSG_SET_FLAGS(msg->flags, MSG_REALLY_DELETED);
+               MSG_SET_PERM_FLAGS(msg->flags, MSG_REALLY_DELETED);
 
        return 0;
 }
@@ -1460,7 +1531,7 @@ gint mbox_remove_all_msg(Folder *folder, FolderItem *item)
        if (mbox_path == NULL)
                return -1;
 
-       fp = fopen(mbox_path, "w");
+       fp = fopen(mbox_path, "wb");
        if (fp == NULL) {
                g_free(mbox_path);
                return -1;
@@ -1693,9 +1764,9 @@ void mbox_scan_folder(Folder *folder, FolderItem *item)
                        struct _message * msg = (struct _message *) l->data;
                        if (!MSG_IS_REALLY_DELETED(msg->flags))
                                total ++;
-                       if (MSG_IS_NEW(msg->flags))
+                       if (MSG_IS_NEW(msg->flags) && !MSG_IS_IGNORE_THREAD(msg->flags))
                                new ++;
-                       if (MSG_IS_UNREAD(msg->flags))
+                       if (MSG_IS_UNREAD(msg->flags) && !MSG_IS_IGNORE_THREAD(msg->flags))
                                unread ++;
                }
                
@@ -1803,7 +1874,7 @@ static gboolean mbox_write_message(FILE * mbox_fp, FILE * new_fp,
 
        g_ptr_array_free(headers, FALSE);
 
-       if (msg->flags != -1) {
+       if (!MSG_IS_INVALID(msg->flags)) {
                /* Status header */
                fwrite("Status: ", strlen("Status: "), 1, new_fp);
                if (!MSG_IS_UNREAD(msg->flags))
@@ -1812,9 +1883,11 @@ static gboolean mbox_write_message(FILE * mbox_fp, FILE * new_fp,
                fwrite("\n", 1, 1, new_fp);
                
                /* X-Status header */
-               if (msg->flags & 
-                   (MSG_REALLY_DELETED | MSG_MARKED | MSG_DELETED
-                    | MSG_REPLIED | MSG_FORWARDED)) {
+               if (MSG_IS_REALLY_DELETED(msg->flags)
+               ||  MSG_IS_MARKED(msg->flags)
+               ||  MSG_IS_DELETED(msg->flags)
+               ||  MSG_IS_REPLIED(msg->flags)
+               ||  MSG_IS_FORWARDED(msg->flags)) {
                        fwrite("X-Status: ", strlen("X-Status: "), 1, new_fp);
                        if (MSG_IS_REALLY_DELETED(msg->flags))
                                fwrite("D", 1, 1, new_fp); /* really deleted */
@@ -1901,13 +1974,13 @@ static gboolean mbox_rewrite(gchar * mbox)
 
        debug_print(_("save modification - %s\n"), mbox);
 
-       mbox_fp = fopen(mbox, "r+");
+       mbox_fp = fopen(mbox, "rb+");
        mbox_lockwrite_file(mbox_fp, mbox);
 
        mbox_cache_synchronize_from_file(mbox_fp, mbox, TRUE);
 
        new = g_strconcat(mbox, ".", itos((int) mbox), NULL);
-       new_fp = fopen(new, "w");
+       new_fp = fopen(new, "wb");
 
        if (change_file_mode_rw(new_fp, new) < 0) {
                FILE_OP_ERROR(new, "chmod");
@@ -1982,7 +2055,7 @@ static gboolean mbox_purge_deleted(gchar * mbox)
 
        for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
                struct _message * msg = (struct _message *) l->data;
-               if (msg->flags != -1 && MSG_IS_REALLY_DELETED(msg->flags)) {
+               if (!MSG_IS_INVALID(msg->flags) && MSG_IS_REALLY_DELETED(msg->flags)) {
                        modification = TRUE;
                        break;
                }
@@ -1995,13 +2068,13 @@ static gboolean mbox_purge_deleted(gchar * mbox)
 
        debug_print(_("purge deleted messages - %s\n"), mbox);
 
-       mbox_fp = fopen(mbox, "r+");
+       mbox_fp = fopen(mbox, "rb+");
        mbox_lockwrite_file(mbox_fp, mbox);
 
        mbox_cache_synchronize_from_file(mbox_fp, mbox, TRUE);
 
        new = g_strconcat(mbox, ".", itos((int) mbox), NULL);
-       new_fp = fopen(new, "w");
+       new_fp = fopen(new, "wb");
 
        if (change_file_mode_rw(new_fp, new) < 0) {
                FILE_OP_ERROR(new, "chmod");
@@ -2016,7 +2089,7 @@ static gboolean mbox_purge_deleted(gchar * mbox)
        msg_list = mbox_cache_get_msg_list(mbox);
        for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
                struct _message * msg = (struct _message *) l->data;
-               if (msg->flags == -1 || !MSG_IS_REALLY_DELETED(msg->flags)) {
+               if (MSG_IS_INVALID(msg->flags) || !MSG_IS_REALLY_DELETED(msg->flags)) {
                        if (!mbox_write_message(mbox_fp, new_fp, new, msg)) {
                                result = FALSE;
                                break;
@@ -2129,7 +2202,7 @@ FolderItem *mbox_create_folder(Folder *folder, FolderItem *parent,
 
        foldername = mbox_get_folderitem_name((gchar *) name);
 
-       new_item = folder_item_new(foldername, path);
+       new_item = folder_item_new(folder, foldername, path);
        folder_item_append(parent, new_item);
 
        if (!strcmp(name, "inbox")) {
@@ -2195,3 +2268,119 @@ gint mbox_remove_folder(Folder *folder, FolderItem *item)
        return 0;
 }
 
+GSList *mbox_get_num_list(Folder *folder, FolderItem *item)
+{
+       GSList *mlist;
+       GList * l;
+       FILE * fp;
+       gchar * mbox_path;
+
+       mlist = NULL;
+
+       mbox_path = mbox_folder_get_path(item);
+
+       if (mbox_path == NULL)
+               return NULL;
+
+       mbox_purge_deleted(mbox_path);
+
+       fp = fopen(mbox_path, "rb");
+       
+       if (fp == NULL) {
+               g_free(mbox_path);
+               return NULL;
+       }
+
+       mbox_lockread_file(fp, mbox_path);
+
+       mbox_cache_synchronize_from_file(fp, mbox_path, TRUE);
+
+       item->last_num = mbox_cache_get_count(mbox_path);
+
+       for(l = mbox_cache_get_msg_list(mbox_path) ; l != NULL ;
+           l = g_list_next(l)) {
+               struct _message * msg;
+
+               msg = (struct _message *) l->data;
+
+               if (MSG_IS_INVALID(msg->flags) || !MSG_IS_REALLY_DELETED(msg->flags)) {
+                       mlist = g_slist_append(mlist, GINT_TO_POINTER(msg->msgnum));
+               } else {
+                       MSG_SET_PERM_FLAGS(msg->flags, MSG_REALLY_DELETED);
+               }
+       }
+
+       mbox_unlock_file(fp, mbox_path);
+
+       g_free(mbox_path);
+
+       fclose(fp);
+
+       return mlist;
+}
+
+MsgInfo *mbox_fetch_msginfo(Folder *folder, FolderItem *item, gint num)
+{
+       gchar *mbox_path;
+       struct _message *msg;
+       FILE *src;
+       MsgInfo *msginfo;
+       
+       g_return_val_if_fail(folder != NULL, NULL);
+       g_return_val_if_fail(item != NULL, NULL);
+
+       mbox_path = mbox_folder_get_path(item);
+
+       g_return_val_if_fail(mbox_path != NULL, NULL);
+       
+       src = fopen(mbox_path, "rb");
+       if (src == NULL) {
+               g_free(mbox_path);
+               return NULL;
+       }
+       mbox_lockread_file(src, mbox_path);
+       mbox_cache_synchronize_from_file(src, mbox_path, TRUE);
+
+       msg = mbox_cache_get_msg(mbox_path, num);
+       if (msg == NULL) {
+               mbox_unlock_file(src, mbox_path);
+               fclose(src);
+               g_free(mbox_path);
+               return NULL;
+       }
+       
+       fseek(src, msg->header, SEEK_SET);
+       msginfo = mbox_parse_msg(src, msg, item);
+
+       mbox_unlock_file(src, mbox_path);
+       fclose(src);
+       g_free(mbox_path);
+
+       return msginfo;
+}
+
+gboolean mbox_check_msgnum_validity(Folder *folder, FolderItem *item)
+{
+       mboxcache * old_cache;
+       gboolean scan_new = TRUE;
+       struct stat s;
+       gchar *filename;
+
+       filename = mbox_folder_get_path(item);
+       
+       old_cache = mbox_cache_get_mbox(filename);
+
+       if (old_cache != NULL) {
+               if (stat(filename, &s) < 0) {
+                       FILE_OP_ERROR(filename, "stat");
+               } else if (old_cache->mtime == s.st_mtime) {
+                       debug_print("Folder is not modified.\n");
+                       scan_new = FALSE;
+               }
+       }
+
+       g_free(filename);
+       
+       return !scan_new;
+}
+