mbox folder / fix for filtering
authorHoà Viêt Dinh <dinh.viet.hoa@free.fr>
Wed, 23 May 2001 12:08:40 +0000 (12:08 +0000)
committerHoà Viêt Dinh <dinh.viet.hoa@free.fr>
Wed, 23 May 2001 12:08:40 +0000 (12:08 +0000)
18 files changed:
ChangeLog.claws
src/Makefile.am
src/defs.h
src/folder.c
src/folder.h
src/folderview.c
src/imap.c
src/mbox.c
src/mbox_folder.c [new file with mode: 0644]
src/mbox_folder.h [new file with mode: 0644]
src/prefs_display_header.c
src/prefs_folder_item.c
src/procheader.c
src/procheader.h
src/procmsg.h
src/summaryview.c
src/utils.c
src/utils.h

index 156e7d3..c52f8f7 100644 (file)
@@ -1,3 +1,31 @@
+2001-05-23 [hoa]
+
+       * src/Makefile.am
+               added mbox_folder.[ch]
+       * src/defs.h
+               mbox temporary folder
+       * src/folder.[ch]
+       * added src/mbox_folder.[ch]
+       * src/folderview.c
+       * src/procheader.[ch]
+               added mbox support
+       * src/mbox.c
+               bugfix for file incorporation filtering
+       * src/imap.c
+               enable creation of MBOX
+       * src/prefs_display_header.c
+               enable use of headers like "From "
+               something that should be fixed :
+                       displaying of such headers add an extra space
+       * src/prefs_folder_item.c
+               don't create folders because it is not necessary
+       * src/procmsg.h
+               added data field to MsgInfo for mbox internal use
+       * src/summaryview.c
+               added some support for mbox
+       * src/utils.[ch]
+               added get_mbox_cache_dir() function
+
 2001-05-23 [hiroyuki]
 
        * src/headerwindow.c
index 2c1b32e..32452ae 100644 (file)
@@ -85,7 +85,8 @@ sylpheed_SOURCES = \
        prefs_matcher.c prefs_matcher.h \
        prefs_scoring.c prefs_scoring.h \
        filtering.c filtering.h \
-       prefs_filtering.c prefs_filtering.h
+       prefs_filtering.c prefs_filtering.h \
+       mbox_folder.c mbox_folder.h
 
 EXTRA_DIST = \
        pixmaps/clip.xpm \
index 44a1c0a..40b607e 100644 (file)
@@ -42,6 +42,7 @@
 #define NEWS_CACHE_DIR         "newscache"
 #define GROUPLIST_FILE         "grouplist"
 #define IMAP_CACHE_DIR         "imapcache"
+#define MBOX_CACHE_DIR         "mboxcache"
 #define MIME_TMP_DIR           "mimetmp"
 #define COMMON_RC              "sylpheedrc"
 #define ACCOUNT_RC             "accountrc"
index 6d06c20..e77d2b7 100644 (file)
 #include "imap.h"
 #include "news.h"
 #include "mh.h"
+#include "mbox_folder.h"
 #include "utils.h"
 #include "xml.h"
 #include "codeconv.h"
 #include "prefs.h"
 #include "account.h"
 #include "prefs_account.h"
+#include "mbox_folder.h"
 
 static GList *folder_list = NULL;
 
@@ -49,6 +51,7 @@ static void folder_init               (Folder         *folder,
 static void local_folder_destroy       (LocalFolder    *lfolder);
 static void remote_folder_destroy      (RemoteFolder   *rfolder);
 static void mh_folder_destroy          (MHFolder       *folder);
+static void mbox_folder_destroy                (MboxFolder     *folder);
 static void imap_folder_destroy                (IMAPFolder     *folder);
 static void news_folder_destroy                (NewsFolder     *folder);
 
@@ -65,6 +68,9 @@ Folder *folder_new(FolderType type, const gchar *name, const gchar *path)
 
        name = name ? name : path;
        switch (type) {
+       case F_MBOX:
+               folder = mbox_folder_new(name, path);
+               break;
        case F_MH:
                folder = mh_folder_new(name, path);
                break;
@@ -94,8 +100,14 @@ Folder *mh_folder_new(const gchar *name, const gchar *path)
 
 Folder *mbox_folder_new(const gchar *name, const gchar *path)
 {
-       /* not yet implemented */
-       return NULL;
+       /* implementing */
+       Folder *folder;
+
+       folder = (Folder *)g_new0(MboxFolder, 1);
+       folder_init(folder, F_MBOX, name);
+       LOCAL_FOLDER(folder)->rootpath = g_strdup(path);
+
+       return folder;
 }
 
 Folder *maildir_folder_new(const gchar *name, const gchar *path)
@@ -214,6 +226,9 @@ void folder_destroy(Folder *folder)
        case F_MH:
                mh_folder_destroy(MH_FOLDER(folder));
                break;
+       case F_MBOX:
+               mbox_folder_destroy(MBOX_FOLDER(folder));
+               break;
        case F_IMAP:
                imap_folder_destroy(IMAP_FOLDER(folder));
                break;
@@ -246,11 +261,16 @@ void folder_add(Folder *folder)
                cur_folder = FOLDER(cur->data);
                if (folder->type == F_MH) {
                        if (cur_folder->type != F_MH) break;
+               } else if (folder->type == F_MBOX) {
+                       if (cur_folder->type != F_MH &&
+                           cur_folder->type != F_MBOX) break;
                } else if (folder->type == F_IMAP) {
                        if (cur_folder->type != F_MH &&
+                           cur_folder->type != F_MBOX &&
                            cur_folder->type != F_IMAP) break;
                } else if (folder->type == F_NEWS) {
                        if (cur_folder->type != F_MH &&
+                           cur_folder->type != F_MBOX &&
                            cur_folder->type != F_IMAP &&
                            cur_folder->type != F_NEWS) break;
                }
@@ -417,6 +437,16 @@ gchar *folder_item_get_path(FolderItem *item)
 
        if (FOLDER_TYPE(item->folder) == F_MH)
                folder_path = g_strdup(LOCAL_FOLDER(item->folder)->rootpath);
+       else if (FOLDER_TYPE(item->folder) == F_MBOX) {
+               path = mbox_get_virtual_path(item);
+               if (path == NULL)
+                       return NULL;
+               folder_path = g_strconcat(get_mbox_cache_dir(),
+                                         G_DIR_SEPARATOR_S, path, NULL);
+               g_free(path);
+
+               return folder_path;
+       }
        else if (FOLDER_TYPE(item->folder) == F_IMAP) {
                g_return_val_if_fail(item->folder->account != NULL, NULL);
                folder_path = g_strconcat(get_imap_cache_dir(),
@@ -463,6 +493,9 @@ void folder_item_scan(FolderItem *item)
        g_return_if_fail(item != NULL);
 
        folder = item->folder;
+
+       g_return_if_fail(folder->scan != NULL);
+
        folder->scan(folder, item);
 }
 
@@ -484,6 +517,10 @@ gchar *folder_item_fetch_msg(FolderItem *item, gint num)
        g_return_val_if_fail(item != NULL, NULL);
 
        folder = item->folder;
+
+       g_return_val_if_fail(folder->scan != NULL, NULL);
+       g_return_val_if_fail(folder->fetch_msg != NULL, NULL);
+
        if (item->last_num < 0) folder->scan(folder, item);
 
        return folder->fetch_msg(folder, item, num);
@@ -497,14 +534,19 @@ gint folder_item_add_msg(FolderItem *dest, const gchar *file,
 
        g_return_val_if_fail(dest != NULL, -1);
        g_return_val_if_fail(file != NULL, -1);
-       g_return_val_if_fail(dest->folder->add_msg != NULL, -1);
 
        folder = dest->folder;
+
+       g_return_val_if_fail(folder->scan != NULL, -1);
+       g_return_val_if_fail(folder->add_msg != NULL, -1);
+
        if (dest->last_num < 0) folder->scan(folder, dest);
 
        num = folder->add_msg(folder, dest, file, remove_source);
        if (num > 0) dest->last_num = num;
 
+       printf("%i\n", num);
+
        return num;
 }
 
@@ -517,6 +559,10 @@ gint folder_item_move_msg(FolderItem *dest, MsgInfo *msginfo)
        g_return_val_if_fail(msginfo != NULL, -1);
 
        folder = dest->folder;
+
+       g_return_val_if_fail(folder->scan != NULL, -1);
+       g_return_val_if_fail(folder->move_msg != NULL, -1);
+
        if (dest->last_num < 0) folder->scan(folder, dest);
 
        num = folder->move_msg(folder, dest, msginfo);
@@ -534,6 +580,10 @@ gint folder_item_move_msgs_with_dest(FolderItem *dest, GSList *msglist)
        g_return_val_if_fail(msglist != NULL, -1);
 
        folder = dest->folder;
+
+       g_return_val_if_fail(folder->scan != NULL, -1);
+       g_return_val_if_fail(folder->move_msgs_with_dest != NULL, -1);
+
        if (dest->last_num < 0) folder->scan(folder, dest);
 
        num = folder->move_msgs_with_dest(folder, dest, msglist);
@@ -551,6 +601,10 @@ gint folder_item_copy_msg(FolderItem *dest, MsgInfo *msginfo)
        g_return_val_if_fail(msginfo != NULL, -1);
 
        folder = dest->folder;
+
+       g_return_val_if_fail(folder->scan != NULL, -1);
+       g_return_val_if_fail(folder->copy_msg != NULL, -1);
+
        if (dest->last_num < 0) folder->scan(folder, dest);
 
        num = folder->copy_msg(folder, dest, msginfo);
@@ -568,6 +622,10 @@ gint folder_item_copy_msgs_with_dest(FolderItem *dest, GSList *msglist)
        g_return_val_if_fail(msglist != NULL, -1);
 
        folder = dest->folder;
+
+       g_return_val_if_fail(folder->scan != NULL, -1);
+       g_return_val_if_fail(folder->copy_msgs_with_dest != NULL, -1);
+
        if (dest->last_num < 0) folder->scan(folder, dest);
 
        num = folder->copy_msgs_with_dest(folder, dest, msglist);
@@ -583,6 +641,10 @@ gint folder_item_remove_msg(FolderItem *item, gint num)
        g_return_val_if_fail(item != NULL, -1);
 
        folder = item->folder;
+
+       g_return_val_if_fail(folder->scan != NULL, -1);
+       g_return_val_if_fail(folder->remove_msg != NULL, -1);
+
        if (item->last_num < 0) folder->scan(folder, item);
 
        return folder->remove_msg(folder, item, num);
@@ -593,6 +655,8 @@ gint folder_item_remove_all_msg(FolderItem *item)
        Folder *folder;
 
        g_return_val_if_fail(item != NULL, -1);
+       g_return_val_if_fail(folder->scan != NULL, -1);
+       g_return_val_if_fail(folder->remove_all_msg != NULL, -1);
 
        folder = item->folder;
        if (item->last_num < 0) folder->scan(folder, item);
@@ -607,6 +671,9 @@ gboolean folder_item_is_msg_changed(FolderItem *item, MsgInfo *msginfo)
        g_return_val_if_fail(item != NULL, FALSE);
 
        folder = item->folder;
+
+       g_return_val_if_fail(folder->is_msg_changed != NULL, -1);
+
        return folder->is_msg_changed(folder, item, msginfo);
 }
 
@@ -699,9 +766,29 @@ static void folder_init(Folder *folder, FolderType type, const gchar *name)
                folder->remove_folder       = imap_remove_folder;               
                break;
        case F_NEWS:
-               folder->get_msg_list = news_get_article_list;
-               folder->fetch_msg    = news_fetch_msg;
-               folder->scan         = news_scan_group;
+               folder->get_msg_list        = news_get_article_list;
+               folder->fetch_msg           = news_fetch_msg;
+               folder->scan                = news_scan_group;
+               break;
+       case F_MBOX:
+               folder->get_msg_list        = mbox_get_msg_list;
+               folder->fetch_msg           = mbox_fetch_msg;
+               folder->scan                = mbox_scan_folder;
+               folder->add_msg             = mbox_add_msg;
+               folder->remove_all_msg      = mbox_remove_all_msg;
+               folder->remove_msg          = mbox_remove_msg;
+               folder->update_mark         = mbox_update_mark;
+               folder->move_msg            = mbox_move_msg;
+               folder->move_msgs_with_dest = mbox_move_msgs_with_dest;
+
+               /*
+               folder->remove_msg          = mh_remove_msg;
+               folder->is_msg_changed      = mh_is_msg_changed;
+               folder->scan_tree           = mh_scan_tree;
+               folder->create_tree         = mh_create_tree;
+               folder->create_folder       = mh_create_folder;
+               folder->rename_folder       = mh_rename_folder;
+               folder->remove_folder       = mh_remove_folder;*/
                break;
        default:
        }
@@ -740,6 +827,11 @@ static void mh_folder_destroy(MHFolder *folder)
        local_folder_destroy(LOCAL_FOLDER(folder));
 }
 
+static void mbox_folder_destroy(MboxFolder *folder)
+{
+       local_folder_destroy(LOCAL_FOLDER(folder));
+}
+
 static void imap_folder_destroy(IMAPFolder *folder)
 {
        remote_folder_destroy(REMOTE_FOLDER(folder));
index 1a0cf80..9227f7f 100644 (file)
@@ -143,6 +143,11 @@ struct _Folder
                                         const gchar    *name);
        gint     (*remove_folder)       (Folder         *folder,
                                         FolderItem     *item);
+       void     (*update_mark)         (Folder         *folder,
+                                        FolderItem     *item);
+       void     (*change_flags)        (Folder         *folder,
+                                        FolderItem     *item,
+                                        MsgInfo        *info);
 };
 
 struct _LocalFolder
index 8c377fb..b4ea54f 100644 (file)
@@ -748,6 +748,8 @@ static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
                        switch (item->folder->type) {
                        case F_MH:
                                name = " (MH)"; break;
+                       case F_MBOX:
+                               name = " (mbox)"; break;
                        case F_IMAP:
                                name = " (IMAP4)"; break;
                        case F_NEWS:
index d9c72b1..b8f9695 100644 (file)
@@ -505,12 +505,14 @@ FolderItem *imap_create_folder(Folder *folder, FolderItem *parent,
        imappath = g_strdup(dirpath);
        /* imap_path_subst_slash_to_dot(imappath); */
 
-       ok = imap_create(SESSION(session)->sock, imappath);
-       if (ok != IMAP_SUCCESS) {
-               log_warning(_("can't create mailbox\n"));
-               g_free(imappath);
-               g_free(dirpath);
-               return NULL;
+       if (strcmp(name, "INBOX") != 0) {
+               ok = imap_create(SESSION(session)->sock, imappath);
+               if (ok != IMAP_SUCCESS) {
+                       log_warning(_("can't create mailbox\n"));
+                       g_free(imappath);
+                       g_free(dirpath);
+                       return NULL;
+               }
        }
 
        new_item = folder_item_new(name, dirpath);
index 7b30eef..ae55c97 100644 (file)
@@ -222,11 +222,13 @@ gint proc_mbox(FolderItem *dest, const gchar *mbox, GHashTable *folder_table)
                } else
                        dropfolder = dest;
 
-               if (msgnum = folder_item_add_msg(dropfolder, tmp_file, TRUE) < 0) {
+               if ((msgnum = folder_item_add_msg(dropfolder, tmp_file, TRUE)) < 0) {
                        fclose(mbox_fp);
                        unlink(tmp_file);
                        return -1;
                }
+
+               folder_item_scan(dropfolder);
                
                if (prefs_filtering != NULL) {
                        /* new filtering */
diff --git a/src/mbox_folder.c b/src/mbox_folder.c
new file mode 100644 (file)
index 0000000..d3243b9
--- /dev/null
@@ -0,0 +1,1485 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "mbox_folder.h"
+#include "folder.h"
+#include "procmsg.h"
+#include "procheader.h"
+#include "utils.h"
+#include "intl.h"
+
+static gboolean mbox_write_data(FILE * mbox_fp, FILE * new_fp,
+                               gchar * new_filename, gint size);
+
+
+/**********************************************************/
+/*                                                        */
+/*                   file lock                            */
+/*                                                        */
+/**********************************************************/
+
+
+static GSList * file_lock = NULL;
+
+static gboolean mbox_file_lock_file(gchar * base)
+{
+       gchar *lockfile, *locklink;
+       gint retry = 0;
+       FILE *lockfp;
+
+       lockfile = g_strdup_printf("%s.%d", base, getpid());
+       if ((lockfp = fopen(lockfile, "w")) == 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"));
+               g_free(lockfile);
+               return FALSE;
+       }
+       
+       fprintf(lockfp, "%d\n", getpid());
+       fclose(lockfp);
+       
+       locklink = g_strconcat(base, ".lock", NULL);
+       while (link(lockfile, locklink) < 0) {
+               FILE_OP_ERROR(lockfile, "link");
+               if (retry >= 5) {
+                       g_warning(_("can't create %s\n"), lockfile);
+                       unlink(lockfile);
+                       g_free(lockfile);
+                       return -1;
+               }
+               if (retry == 0)
+                       g_warning(_("mailbox is owned by another"
+                                   " process, waiting...\n"));
+               retry++;
+               sleep(5);
+       }
+       unlink(lockfile);
+       g_free(lockfile);
+
+       return TRUE;
+}
+
+static gboolean mbox_fcntl_lockwrite_file(FILE * fp)
+{
+       struct flock lck;
+
+       lck.l_type = F_WRLCK;
+       lck.l_whence = 0;
+       lck.l_start = 0;
+       lck.l_len = 0;
+       
+       if (fcntl(fileno(fp), F_SETLK, &lck) < 0)
+               return FALSE;
+       else
+               return TRUE;
+}
+
+static gboolean mbox_fcntl_lockread_file(FILE * fp)
+{
+       struct flock lck;
+
+       lck.l_type = F_RDLCK;
+       lck.l_whence = 0;
+       lck.l_start = 0;
+       lck.l_len = 0;
+       
+       if (fcntl(fileno(fp), F_SETLK, &lck) < 0)
+               return FALSE;
+       else
+               return TRUE;
+}
+
+static gboolean mbox_fcntl_unlock_file(FILE * fp)
+{
+       struct flock lck;
+
+       lck.l_type = F_UNLCK;
+       lck.l_whence = 0;
+       lck.l_start = 0;
+       lck.l_len = 0;
+       
+       if (fcntl(fileno(fp), F_SETLK, &lck) < 0)
+               return FALSE;
+       else
+               return TRUE;
+}
+
+static gboolean mbox_file_unlock_file(gchar * base)
+{
+       gchar *lockfile, *locklink;
+       gint retry = 0;
+       FILE *lockfp;
+
+       lockfile = g_strdup_printf("%s.lock", base);
+       unlink(lockfile);
+       g_free(lockfile);
+
+       return TRUE;
+}
+
+static gboolean mbox_lockread_file(FILE * fp, gchar * base)
+{
+       gboolean result;
+
+       result = mbox_fcntl_lockread_file(fp);
+       if (!result) {
+               if (result = mbox_file_lock_file(base)) {
+                       file_lock = g_slist_append(file_lock, g_strdup(base));
+                       debug_print("lockfile lock %s.\n", base);
+               }
+               else
+                       g_warning(_("could not lock read file %s\n"), base);
+       }
+       else
+               debug_print("fcntl lock %s.\n", base);
+
+       return result;
+}
+
+static gboolean mbox_lockwrite_file(FILE * fp, gchar * base)
+{
+       gboolean result;
+
+       result = mbox_fcntl_lockwrite_file(fp);
+       if (!result) {
+               if (result = mbox_file_lock_file(base)) {
+                       file_lock = g_slist_append(file_lock, g_strdup(base));
+                       debug_print("lockfile lock %s.\n", base);
+               }
+               else
+                       g_warning(_("could not lock write file %s\n"), base);
+       }
+       else
+               debug_print("fcntl lock %s.\n", base);
+
+       return result;
+}
+
+static gboolean mbox_unlock_file(FILE * fp, gchar * base)
+{
+       gboolean result;
+       GSList * l;
+       gboolean unlocked = FALSE;
+
+       for(l = file_lock ; l != NULL ; l = g_slist_next(l)) {
+               gchar * data = l->data;
+
+               if (strcmp(data, base) == 0) {
+                       file_lock = g_slist_remove(file_lock, data);
+                       g_free(data);
+                       result = mbox_file_unlock_file(base);
+                       unlocked = TRUE;
+                       break;
+               }
+       }
+       
+       if (!unlocked)
+               result = mbox_fcntl_unlock_file(fp);
+
+       return result;
+}
+
+/**********************************************************/
+/*                                                        */
+/*                   mbox parsing                         */
+/*                                                        */
+/**********************************************************/
+
+#define MAILFILE_ERROR_NO_ERROR          0x000
+#define MAILFILE_ERROR_FILE_NOT_FOUND    0x001
+#define MAILFILE_ERROR_MEMORY            0x002
+#define MAILFILE_ERROR_MESSAGE_NOT_FOUND 0x003
+
+static int mailfile_error = MAILFILE_ERROR_NO_ERROR;
+
+#define STATE_BEGIN       0x000
+#define STATE_TEXT_READ   0x001
+#define STATE_FROM_READ   0x002
+#define STATE_FIELD_READ  0x003
+#define STATE_END         0x004
+#define STATE_END_OF_FILE 0x005
+#define STATE_MEM_ERROR   0x006
+#define STATE_TEXT_BEGIN  0x007
+
+#define STATE_MASK        0x0FF // filter state from functions
+
+#define STATE_RESTORE_POS       0x100 // go back while reading
+
+typedef struct _mailfile mailfile;
+
+struct _mailfile
+{
+       gint count;
+       gchar * filename;
+       GList * msg_list;
+};
+
+struct _message
+{
+       int msgnum;
+       int deleted;
+       int offset;
+       int header;
+       int content;
+       int end;
+       int marked;
+       gchar * messageid;
+       gchar * fromspace;
+       MsgFlags flags;
+       gboolean fetched;
+};
+
+
+static int startFrom(char * s)
+{
+       return (strncmp(s, "From ", 5) == 0);
+}
+
+static int startSpace(char * s)
+{
+       return ((*s == ' ') || (*s == '\t'));
+}
+
+static int startEmpty(char * s)
+{
+       return (*s == '\n');
+}
+
+static void free_msg_list(GList * l)
+{
+       GList * elt = g_list_first(l);
+
+       while (elt)
+               {
+                       g_free(elt->data);
+                       elt = g_list_next(elt);
+               }
+
+       g_list_free(l);
+}
+
+
+static mailfile * mailfile_init_from_file(FILE * f, gchar * filename)
+{
+       int state;
+       GList * msg_list = NULL;
+       char * r;
+       char s[256];
+       int lastpos = 0;
+       int former_pos = 0;
+       int ignore_next = 0;
+       int msgnum = 0;
+       struct _message * data = NULL;
+       mailfile * mf;
+
+       state = STATE_BEGIN;
+
+       while (state != STATE_END_OF_FILE) {
+               if ((state & STATE_RESTORE_POS) == 0) {
+                       former_pos = lastpos;
+                       lastpos = ftell(f);
+
+                       r = fgets(s, 256, f);
+
+                       if (r != NULL && *r)
+                               ignore_next = (s[strlen(s) - 1] != '\n');
+                       else
+                               ignore_next = 0;
+               }
+
+               switch(state & 0x0F) {
+               case STATE_BEGIN:
+                       if (r == NULL)
+                               state = STATE_END_OF_FILE;
+                       else if (startFrom(s)) {
+                               state = STATE_FROM_READ;
+
+                               data = g_new0(struct _message, 1);
+                               if (data == NULL) {
+                                       free_msg_list(msg_list);
+                                       return NULL;
+                               }
+                               
+                               msgnum ++;
+                               data->msgnum = msgnum;
+                               data->offset = lastpos;
+                               data->header = lastpos;
+                               data->end = 0;
+                               data->content = 0;
+                               data->deleted = 0;
+                               data->messageid = NULL;
+                               data->fromspace = NULL;
+                               data->flags = -1;
+                               data->fetched = FALSE;
+                               msg_list = g_list_append(msg_list, (gpointer) data);
+                       }
+                       else
+                               state = STATE_BEGIN;
+
+                       break;
+
+               case STATE_TEXT_READ:
+                       if (r == NULL)
+                               state = STATE_END;
+                       else if (startFrom(s))
+                               state = STATE_END | STATE_RESTORE_POS;
+                       else
+                               state = STATE_TEXT_READ;
+                       break;
+
+               case STATE_TEXT_BEGIN:
+                       if (r == NULL)
+                               state = STATE_END;
+                       else if (startFrom(s)) {
+                               data->content = lastpos;
+
+                               state = STATE_END | STATE_RESTORE_POS;
+                       }
+                       else
+                               state = STATE_TEXT_READ;
+                       break;
+         
+               case STATE_FROM_READ:
+                       data->content = lastpos;
+                       if (r == NULL)
+                               state = STATE_END;
+                       else if (startSpace(s))
+                               state = STATE_FROM_READ;
+                       else if (startEmpty(s))
+                               state = STATE_TEXT_READ;
+                       else
+                               state = STATE_FIELD_READ;
+                       break;
+         
+               case STATE_FIELD_READ:
+                       data->content = lastpos;
+                       if (r == NULL)
+                               state = STATE_END;
+                       else if (startSpace(s))
+                               state = STATE_FIELD_READ;
+                       else if (startEmpty(s))
+                               state = STATE_TEXT_BEGIN;
+                       else
+                               state = STATE_FIELD_READ;
+                       break;
+               }
+      
+               if ((state & STATE_MASK) == STATE_END) {
+                       state = STATE_BEGIN | (state & STATE_RESTORE_POS);
+                       if (state & STATE_RESTORE_POS)
+                               data->end = former_pos;
+                       else
+                               data->end = lastpos;
+               }
+
+               if (ignore_next) {
+                       do {
+                               r = fgets(s, 256, f);
+                               if (r == NULL || *r == '\0')
+                                       break;
+                       }
+                       while (s[strlen(s) - 1] != '\n');
+               }
+       }
+
+       mf = (mailfile *) g_new0(struct _mailfile, 1);
+       if (mf == NULL) {
+               free_msg_list(msg_list);
+               mailfile_error = MAILFILE_ERROR_MEMORY;
+               return NULL;
+       }
+
+       mf->msg_list = msg_list;
+
+       mf->filename = g_strdup(filename);
+       mf->count = msgnum;
+
+       mailfile_error = MAILFILE_ERROR_NO_ERROR;
+
+       return mf;
+}
+
+static mailfile * mailfile_init(char * filename)
+{
+
+       FILE * f;
+       mailfile * mf;
+  
+       f = fopen(filename, "r");
+
+       if (f == NULL) {
+               mailfile_error = MAILFILE_ERROR_FILE_NOT_FOUND;
+               return NULL;
+       }
+
+       mbox_lockread_file(f, filename);
+
+       mf = mailfile_init_from_file(f, filename);
+
+       mbox_unlock_file(f, filename);
+
+       fclose(f);
+
+       return mf;
+}
+
+static void mailfile_done(mailfile * f)
+{
+       free_msg_list(f->msg_list);
+       g_free(f->filename);
+
+       g_free(f);
+}
+
+/*
+#define MAX_READ 4096
+
+static char * readfile(char * filename, int offset, int max_offset)
+{
+       char * message;
+       int size;
+       int pos;
+       int max;
+       int bread;
+       FILE * handle;
+
+       handle = fopen(filename, "r");
+
+       if (handle == NULL) {
+               mailfile_error = MAILFILE_ERROR_FILE_NOT_FOUND;
+               return NULL;
+       }
+
+       size = max_offset - offset;
+
+       message = (char *) malloc(size + 1);
+       if (message == NULL) {
+               fclose(handle);
+               mailfile_error = MAILFILE_ERROR_MEMORY;
+               return NULL;
+       }
+
+       fseek(handle, offset, SEEK_SET);
+
+       pos = 0;
+       while (pos < size) {
+               if ((size - pos) > MAX_READ)
+                       max = MAX_READ;
+               else
+                       max = (size - pos);
+
+               bread = fread(message + pos, 1, max, handle);
+
+               if (bread != -1)
+                       pos += bread;
+
+               if (bread < max)
+                       break;
+       }
+
+       message[pos] = 0;
+
+       fclose(handle);
+
+       return message;
+}
+
+static char * mailfile_readmsg(mailfile f, int index)
+{
+       GList * nth;
+       int max_offset;
+       int offset;
+       char * message;
+       struct _message * msginfo;
+
+       nth = g_list_nth(f->msg_list, index);
+
+       if (!nth) {
+               mailfile_error = MAILFILE_ERROR_MESSAGE_NOT_FOUND;
+               return NULL;
+       }
+
+       msginfo = (struct _message *)nth->data;
+
+       offset = msginfo->offset;
+       max_offset = msginfo->end;
+       message = readfile(f->filename, offset, max_offset);
+
+       mailfile_error = MAILFILE_ERROR_NO_ERROR;
+
+       return message;
+}
+
+static char * mailfile_readheader(mailfile f, int index)
+{
+       GList * nth;
+       int max_offset;
+       int offset;
+       char * message;
+       struct _message * msginfo;
+
+       nth = g_list_nth(f->msg_list, index);
+
+       if (!nth) {
+               mailfile_error = MAILFILE_ERROR_MESSAGE_NOT_FOUND;
+               return NULL;
+       }
+
+       msginfo = (struct _message *)nth->data;
+
+       offset = msginfo->offset;
+       max_offset = msginfo->content;
+       message = readfile(f->filename, offset, max_offset);
+
+       mailfile_error = MAILFILE_ERROR_NO_ERROR;
+
+       return message;
+}
+
+static int mailfile_count(mailfile * f)
+{
+       return g_list_length(f->msg_list);
+}
+
+static int mailfile_find_deleted(mailfile f, char * filename)
+{
+       FILE * handle;
+
+       handle = fopen(filename, "r");
+
+       while (elt) {
+               struct _message m = elt->data;
+               n = fread(&m.deleted, sizeof(int), 1, handle);
+               if (!n)
+                       break;
+               elt = g_list_next(elt);
+       }
+
+       fclose(handle);
+}
+*/
+
+
+
+/**********************************************************/
+/*                                                        */
+/*                   mbox cache operations                */
+/*                                                        */
+/**********************************************************/
+
+struct _mboxcache {
+       gchar * filename;
+       mailfile * mf;
+       gint mtime;
+};
+
+typedef struct _mboxcache mboxcache;
+
+static GHashTable * mbox_cache_table = NULL;
+static mboxcache * current_mbox = NULL;
+
+static void mbox_cache_init()
+{
+       mbox_cache_table = g_hash_table_new(g_str_hash, g_str_equal);
+}
+
+static void mbox_cache_done()
+{
+       g_hash_table_destroy(mbox_cache_table);
+}
+
+static void mbox_cache_free_mbox(mboxcache * cache)
+{
+       if (cache->filename)
+               g_free(cache->filename);
+       g_free(cache);
+}
+
+static mboxcache * mbox_cache_read_mbox(gchar * filename)
+{
+       mboxcache * cache;
+       struct stat s;
+       mailfile * mf;
+
+       if (stat(filename, &s) < 0)
+               return NULL;
+
+       mf = mailfile_init(filename);
+       if (mf == NULL)
+               return NULL;
+
+       cache = g_new0(mboxcache, 1);
+
+       cache->mtime = s.st_mtime;
+       cache->mf = mf;
+       cache->filename = g_strdup(filename);
+
+       return cache;
+}
+
+static mboxcache * mbox_cache_read_mbox_from_file(FILE * fp, gchar * filename)
+{
+       mboxcache * cache;
+       struct stat s;
+       mailfile * mf;
+
+       if (stat(filename, &s) < 0)
+               return NULL;
+
+       mf = mailfile_init_from_file(fp, filename);
+       if (mf == NULL)
+               return NULL;
+
+       cache = g_new0(mboxcache, 1);
+
+       cache->mtime = s.st_mtime;
+       cache->mf = mf;
+       cache->filename = g_strdup(filename);
+
+       return cache;
+}
+
+static void mbox_cache_insert_mbox(gchar * filename, mboxcache * data)
+{
+       if (mbox_cache_table == NULL)
+               mbox_cache_init();
+
+       g_hash_table_insert(mbox_cache_table, filename, data);
+}
+
+static mboxcache * mbox_cache_get_mbox(gchar * filename)
+{
+       if (mbox_cache_table == NULL)
+               mbox_cache_init();
+
+       return g_hash_table_lookup(mbox_cache_table, filename);
+}
+
+
+static gint mbox_cache_get_count(gchar * filename)
+{
+       mboxcache * cache;
+
+       cache = mbox_cache_get_mbox(filename);
+       if (cache == NULL)
+               return -1;
+       if (cache->mf == NULL)
+               return -1;
+       return cache->mf->count;
+}
+
+static gint mbox_cache_get_mtime(gchar * filename)
+{
+       mboxcache * cache;
+
+       cache = mbox_cache_get_mbox(filename);
+       if (cache == NULL)
+               return -1;
+       return cache->mtime;
+}
+
+static GList * mbox_cache_get_msg_list(gchar * filename)
+{
+       mboxcache * cache;
+
+       cache = mbox_cache_get_mbox(filename);
+
+       if (cache == NULL)
+               return NULL;
+
+       if (cache->mf == NULL)
+               return NULL;
+
+       return cache->mf->msg_list;
+}
+
+static void mbox_cache_synchronize_lists(GList * msg_new_list,
+                                        GList * msg_old_list)
+{
+       struct _message * msg_new;
+       struct _message * msg_old;
+       GList * l_new;
+       GList * l_old;
+
+       // could be improved with a hash table
+       for(l_old = msg_old_list ; l_old != NULL ;
+           l_old = g_list_next(l_old)) {
+               msg_old = (struct _message *) l_old->data;
+               
+               if ((msg_old->messageid == NULL) ||
+                   (msg_old->fromspace == NULL))
+                       continue;
+               
+               for(l_new = msg_new_list ; l_new != NULL ;
+                   l_new = g_list_next(l_new)) {
+                       msg_new = (struct _message *) l_new->data;
+                       
+                       if ((msg_new->messageid == NULL) ||
+                           (msg_new->fromspace == NULL))
+                               continue;
+                       
+                       if (!strcmp(msg_new->messageid, msg_old->messageid) &&
+                           !strcmp(msg_new->fromspace, msg_old->fromspace)) {
+                               // copy flags
+                               msg_new->deleted = msg_old->deleted;
+                               msg_new->flags = msg_old->flags;
+                               break;
+                       }
+               }
+       }
+}
+
+static void mbox_cache_synchronize(gchar * filename)
+{
+       mboxcache * new_cache;
+       mboxcache * old_cache;
+       gboolean scan_new = TRUE;
+       struct stat s;
+
+       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;
+               }
+       }
+
+       if (scan_new) {
+               new_cache = mbox_cache_read_mbox(filename);
+               
+               if (new_cache == NULL) {
+                       if (old_cache != NULL)
+                               mbox_cache_free_mbox(old_cache);
+                       return;
+               }
+
+               if (old_cache != NULL) {
+                       if ((old_cache->mf != NULL) &&
+                           (new_cache->mf != NULL))
+                               mbox_cache_synchronize_lists(new_cache->mf->msg_list, old_cache->mf->msg_list);
+                       mbox_cache_free_mbox(old_cache);
+               }
+       
+               mbox_cache_insert_mbox(filename, new_cache);
+       }
+}
+
+static void mbox_cache_synchronize_from_file(FILE * fp, gchar * filename)
+{
+       mboxcache * new_cache;
+       mboxcache * old_cache;
+       gboolean scan_new = TRUE;
+       struct stat s;
+
+       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;
+               }
+       }
+
+       if (scan_new) {
+               new_cache = mbox_cache_read_mbox_from_file(fp, filename);
+               
+               if (new_cache == NULL) {
+                       if (old_cache != NULL)
+                               mbox_cache_free_mbox(old_cache);
+                       return;
+               }
+
+               if (old_cache != NULL) {
+                       if ((old_cache->mf != NULL) &&
+                           (new_cache->mf != NULL))
+                               mbox_cache_synchronize_lists(new_cache->mf->msg_list, old_cache->mf->msg_list);
+                       mbox_cache_free_mbox(old_cache);
+               }
+       
+               mbox_cache_insert_mbox(filename, new_cache);
+       }
+}
+
+gboolean mbox_cache_msg_fetched(gchar * filename, gint num)
+{
+       GList * msg_list;
+       struct _message * msg;
+
+       msg_list = mbox_cache_get_msg_list(filename);
+       msg = (struct _message *) g_list_nth_data(msg_list, num - 1);
+
+       if (msg == NULL)
+               return FALSE;
+
+       return msg->fetched;
+}
+
+void mbox_cache_msg_set_fetched(gchar * filename, gint num)
+{
+       GList * msg_list;
+       struct _message * msg;
+
+       msg_list = mbox_cache_get_msg_list(filename);
+       if ((msg = (struct _message *) g_list_nth_data(msg_list, num - 1))
+           == NULL)
+               return;
+       msg->fetched = TRUE;
+}
+
+
+/**********************************************************/
+/*                                                        */
+/*                   mbox operations                      */
+/*                                                        */
+/**********************************************************/
+
+
+static MsgInfo *mbox_parse_msg(FILE * fp, gint msgnum, FolderItem *item)
+{
+       struct stat s;
+       MsgInfo *msginfo;
+       MsgFlags flags = MSG_NEW|MSG_UNREAD;
+
+       g_return_val_if_fail(item != NULL, NULL);
+       g_return_val_if_fail(fp != NULL, NULL);
+
+       if (item->stype == F_QUEUE) {
+               MSG_SET_FLAGS(flags, MSG_QUEUED);
+       } else if (item->stype == F_DRAFT) {
+               MSG_SET_FLAGS(flags, MSG_DRAFT);
+       }
+
+       msginfo = procheader_file_parse(fp, flags, FALSE);
+
+       if (!msginfo) return NULL;
+
+       msginfo->msgnum = msgnum;
+       msginfo->folder = item;
+
+       if (stat(item->path, &s) < 0) {
+               FILE_OP_ERROR(item->path, "stat");
+               msginfo->size = 0;
+               msginfo->mtime = 0;
+       } else {
+               msginfo->size = s.st_size;
+               msginfo->mtime = s.st_mtime;
+       }
+
+       return msginfo;
+}
+
+GSList *mbox_get_msg_list(Folder *folder, FolderItem *item, gboolean use_cache)
+{
+       GSList *mlist;
+       GHashTable *msg_table;
+       MsgFlags flags = MSG_NEW|MSG_UNREAD;
+       MsgInfo * msginfo;
+       GList * l;
+       FILE * fp;
+
+#ifdef MEASURE_TIME
+       struct timeval tv_before, tv_after, tv_result;
+
+       gettimeofday(&tv_before, NULL);
+#endif
+
+       mlist = NULL;
+
+       fp = fopen(item->path, "r");
+
+       mbox_lockread_file(fp, item->path);
+
+       mbox_cache_synchronize_from_file(fp, item->path);
+
+       if (mbox_cache_get_mbox(item->path) == NULL) {
+               g_warning(_("parsing of %s failed.\n"), item->path);
+               mbox_unlock_file(fp, item->path);
+               fclose(fp);
+               return NULL;
+       }
+
+       for(l = mbox_cache_get_msg_list(item->path) ; l != NULL ;
+           l = g_list_next(l)) {
+               struct _message * msg;
+
+               msg = (struct _message *) l->data;
+
+               if (!msg->deleted) {
+                       fseek(fp, msg->header, SEEK_SET);
+                       msginfo = mbox_parse_msg(fp, msg->msgnum, item);
+                       if (msginfo) {
+                               if (msginfo->msgid)
+                                       msg->messageid =
+                                               g_strdup(msginfo->msgid);
+                               if (msginfo->fromspace)
+                                       msg->fromspace =
+                                               g_strdup(msginfo->fromspace);
+                               msginfo->data = msg;
+                       }
+                       if (msg->flags != -1)
+                               msginfo->flags = msg->flags;
+                       mlist = g_slist_append(mlist, msginfo);
+               }
+       }
+
+       mbox_unlock_file(fp, item->path);
+
+       fclose(fp);
+
+#ifdef MEASURE_TIME
+       gettimeofday(&tv_after, NULL);
+
+       timersub(&tv_after, &tv_before, &tv_result);
+       g_print("mbox_get_msg_list: %s: elapsed time: %ld.%06ld sec\n",
+               item->path, tv_result.tv_sec, tv_result.tv_usec);
+#endif
+
+       return mlist;
+}
+
+static gboolean mbox_extract_msg(gchar * mbox_filename, gint msgnum,
+                                gchar * dest_filename)
+{
+       struct _message * msg;
+       gint offset;
+       gint max_offset;
+       gint size;
+       FILE * src;
+       FILE * dest;
+       gboolean err;
+       GList * msg_list;
+       gboolean already_fetched;
+
+       src = fopen(mbox_filename, "r");
+       if (src == NULL)
+               return FALSE;
+
+       mbox_lockread_file(src, mbox_filename);
+
+       mbox_cache_synchronize_from_file(src, mbox_filename);
+
+       already_fetched = mbox_cache_msg_fetched(mbox_filename, msgnum);
+
+       if (already_fetched) {
+               mbox_unlock_file(src, mbox_filename);
+               fclose(src);
+               return TRUE;
+       }
+
+       msg_list = mbox_cache_get_msg_list(mbox_filename);
+
+       msg = (struct _message *) g_list_nth_data(msg_list, msgnum - 1);
+
+       if (msg == NULL) {
+               mbox_unlock_file(src, mbox_filename);
+               fclose(src);
+               return FALSE;
+       }
+
+       offset = msg->offset;
+       max_offset = msg->end;
+       
+       size = max_offset - offset;
+
+       fseek(src, offset, SEEK_SET);
+
+       dest = fopen(dest_filename, "w");
+       if (dest == NULL) {
+               mbox_unlock_file(src, mbox_filename);
+               fclose(src);
+               return FALSE;
+       }
+
+       if (change_file_mode_rw(dest, dest_filename) < 0) {
+               FILE_OP_ERROR(dest_filename, "chmod");
+               g_warning(_("can't change file mode\n"));
+       }
+
+       if (!mbox_write_data(src, dest, dest_filename, size)) {
+               mbox_unlock_file(src, mbox_filename);
+               fclose(dest);
+               fclose(src);
+               unlink(dest_filename);
+               return FALSE;
+       }
+
+       err = FALSE;
+
+       if (ferror(src)) {
+               FILE_OP_ERROR(mbox_filename, "fread");
+               err = TRUE;
+       }
+
+       mbox_cache_msg_set_fetched(mbox_filename, msgnum);
+
+       if (fclose(dest) == -1) {
+               FILE_OP_ERROR(dest_filename, "fclose");
+               return FALSE;
+       }
+
+       mbox_unlock_file(src, mbox_filename);
+
+       if (fclose(src) == -1) {
+               FILE_OP_ERROR(mbox_filename, "fclose");
+               err = TRUE;
+       }
+
+       if (err) {
+               unlink(dest_filename);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+gchar *mbox_fetch_msg(Folder *folder, FolderItem *item, gint num)
+{
+       gchar *path;
+       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))
+               make_dir_hier(path);
+
+       filename = g_strconcat(path, G_DIR_SEPARATOR_S, itos(num), NULL);
+
+       g_free(path);
+
+       if (!mbox_extract_msg(item->path, num, filename)) {
+               g_free(filename);
+               return NULL;
+       }
+
+       return filename;
+}
+
+gint mbox_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
+                 gboolean remove_source)
+{
+       FILE * src_fp;
+       FILE * dest_fp;
+       gchar buf[BUFSIZ];
+       gint old_size;
+       gint n_read;
+       gboolean err;
+
+       if (dest->last_num < 0) {
+               mbox_scan_folder(folder, dest);
+               if (dest->last_num < 0) return -1;
+       }
+
+       src_fp = fopen(file, "r");
+       if (src_fp == NULL) {
+               return -1;
+       }
+
+       dest_fp = fopen(dest->path, "a");
+       if (dest_fp == NULL) {
+               fclose(src_fp);
+               return -1;
+       }
+       old_size = ftell(dest_fp);
+
+       mbox_lockwrite_file(dest_fp, dest->path);
+       
+       while (1) {
+               n_read = fread(buf, 1, sizeof(buf), src_fp);
+               if (n_read < sizeof(buf) && ferror(src_fp))
+                       break;
+               if (fwrite(buf, n_read, 1, dest_fp) < 1) {
+                       g_warning(_("writing to %s failed.\n"), dest->path);
+                       ftruncate(fileno(dest_fp), old_size);
+                       fclose(dest_fp);
+                       fclose(src_fp);
+                       return -1;
+               }
+
+               if (n_read < sizeof(buf))
+                       break;
+       }
+
+       err = FALSE;
+
+       if (ferror(src_fp)) {
+               FILE_OP_ERROR(dest->path, "fread");
+       }
+
+       mbox_unlock_file(src_fp, dest->path);
+
+       if (fclose(src_fp) == -1) {
+               FILE_OP_ERROR(file, "fclose");
+               err = TRUE;
+       }
+
+       if (fclose(dest_fp) == -1) {
+               FILE_OP_ERROR(dest->path, "fclose");
+               return -1;
+       }
+
+       if (err) {
+               ftruncate(fileno(dest_fp), old_size);
+               return -1;
+       }
+
+       if (remove_source) {
+               if (unlink(file) < 0)
+                       FILE_OP_ERROR(file, "unlink");
+       }
+
+       dest->last_num++;
+       return dest->last_num;
+
+}
+
+gint mbox_remove_msg(Folder *folder, FolderItem *item, gint num)
+{
+       struct _message * msg;
+       GList * msg_list;
+
+       mbox_cache_synchronize(item->path);
+
+       msg_list = mbox_cache_get_msg_list(item->path);
+
+       msg = (struct _message *) g_list_nth_data(msg_list,
+                                                 num - 1);
+       msg->deleted = 1;
+
+       /*
+       if (!mbox_rewrite(item->path)) {
+               printf("rewrite %s\n", item->path);
+               return -1;
+       }
+       */
+
+       return 0;
+}
+
+gint mbox_remove_all_msg(Folder *folder, FolderItem *item)
+{
+       FILE * fp;
+
+       fp = fopen(item->path, "w");
+       if (fp == NULL) {
+               return -1;
+       }
+
+       fclose(fp);
+
+       return 0;
+}
+
+gint mbox_move_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
+{
+       /*
+
+       mbox_cache_synchronize(item->path);
+
+       size = msg->end - msg->offset;
+
+       src = fopen(mbox_filename, "r");
+       if (src == NULL)
+               return FALSE;
+       fseek(src, msg->offset, SEEK_SET);
+
+       mbox_lockread_file(src, mbox_filename);
+
+       dest = fopen(dest_filename, "a");
+       if (dest == NULL) {
+               fclose(src);
+               return FALSE;
+       }
+
+       if (change_file_mode_rw(dest, dest_filename) < 0) {
+               FILE_OP_ERROR(dest_filename, "chmod");
+               g_warning(_("can't change file mode\n"));
+       }
+
+       if (!mbox_write_data(src, dest, dest_filename, size)) {
+                       fclose(dest);
+                       fclose(src);
+                       unlink(dest_filename);
+                       return FALSE;
+       }
+       
+       return -1;
+       */
+       gchar * filename;
+
+       filename = mbox_fetch_msg(folder, msginfo->folder, msginfo->msgnum);
+       if (filename == NULL)
+               return -1;
+
+       ((struct _message *) msginfo->data)->deleted = TRUE;
+
+       return mbox_add_msg(folder, dest, filename, TRUE);
+}
+
+gint mbox_move_msgs_with_dest(Folder *folder, FolderItem *dest, GSList *msglist)
+{
+       GSList * l;
+       gchar * path = NULL;
+
+       for(l = msglist ; l != NULL ; l = g_slist_next(l)) {
+               MsgInfo * msginfo = (MsgInfo *) l->data;
+
+               if (msginfo->folder)
+                       path = msginfo->folder->path;
+
+               mbox_move_msg(folder, dest, msginfo);
+       }
+
+       if (path) {
+               mbox_rewrite(path);
+               printf("fini\n");
+               mbox_cache_synchronize(path);
+       }
+       mbox_cache_synchronize(dest->path);
+
+       return dest->last_num;
+}
+
+void mbox_scan_folder(Folder *folder, FolderItem *item)
+{
+       gchar *path;
+       struct stat s;
+       gint max = 0;
+       gint num;
+       gint n_msg;
+       mboxcache * cached;
+
+       mbox_cache_synchronize(item->path);
+
+       cached = mbox_cache_get_mbox(item->path);
+
+       if (cached == NULL) {
+               item->new = 0;
+               item->unread = 0;
+               item->total = 0;
+               item->last_num = 0;
+               return;
+       }
+
+       n_msg = mbox_cache_get_count(item->path);
+
+       if (n_msg == 0)
+               item->new = item->unread = item->total = 0;
+       else {
+               gint new, unread, total;
+
+               //              procmsg_get_mark_sum(".", &new, &unread, &total);
+               if (n_msg > total) {
+                       new += n_msg - total;
+                       unread += n_msg - total;
+               }
+               item->new = new;
+               item->unread = unread;
+               item->total = n_msg;
+       }
+
+       debug_print(_("Last number in dir %s = %d\n"), item->path,
+                   item->total);
+       item->last_num = item->total;
+}
+
+gchar * mbox_get_virtual_path(FolderItem * item)
+{
+       if (item == NULL)
+               return NULL;
+
+       if (item->parent == NULL) {
+               return NULL;
+       }
+       else {
+               gchar * parent_path;
+               gchar * result_path;
+
+               parent_path = mbox_get_virtual_path(item->parent);
+               if (parent_path == NULL)
+                       result_path = g_strdup(item->name);
+               else
+                       result_path = g_strconcat(parent_path,
+                                                 G_DIR_SEPARATOR_S,
+                                                 item->name, NULL);
+               g_free(parent_path);
+
+               return result_path;
+       }
+}
+
+static gboolean mbox_write_data(FILE * mbox_fp, FILE * new_fp,
+                               gchar * new_filename, gint size)
+{      
+       gint n_read;
+       gint pos;
+       gchar buf[BUFSIZ];
+       gint max;
+
+       pos = 0;
+       while (pos < size) {
+               if ((size - pos) > sizeof(buf))
+                       max = sizeof(buf);
+               else
+                       max = (size - pos);
+               
+               n_read = fread(buf, 1, max, mbox_fp);
+               if (n_read < max && ferror(mbox_fp)) {
+                       return FALSE;
+               }
+               if (fwrite(buf, n_read, 1, new_fp) < 1) {
+                       g_warning(_("writing to %s failed.\n"), new_filename);
+                       return FALSE;
+               }
+               
+               if (n_read != -1)
+                       pos += n_read;
+               
+               if (n_read < max)
+                       break;
+       }
+       return TRUE;
+}
+
+static gboolean mbox_write_message(FILE * mbox_fp, FILE * new_fp,
+                           gchar * new_filename,
+                           struct _message * msg)
+{
+       GSList * headers;
+       GSList * cur;
+       gint size;
+       
+       fseek(mbox_fp, msg->header, SEEK_SET);
+       headers = procheader_get_header_list(mbox_fp);
+       for(cur = headers ; cur != NULL ;
+           cur = g_slist_next(cur)) {
+               Header * h = (Header *) cur->data;
+               
+               if (!procheader_headername_equal(h->name, 
+                                                "Status") &&
+                   !procheader_headername_equal(h->name, 
+                                                "X-Status")) {
+                       fwrite(h->name, strlen(h->name),
+                              1, new_fp);
+                       fwrite(" ", 1, 1, new_fp);
+                       fwrite(h->body, strlen(h->body),
+                              1, new_fp);
+                       fwrite("\r\n", 2, 1, new_fp);
+               }
+       }
+       fwrite("\r\n", 2, 1, new_fp);
+       
+       size = msg->end - msg->content;
+       fseek(mbox_fp, msg->content, SEEK_SET);
+
+       return mbox_write_data(mbox_fp, new_fp, new_filename, size);
+}
+
+void mbox_update_mark(Folder * folder, FolderItem * item)
+{
+       GList * msg_list;
+       GList * l;
+
+       /*      
+       msg_list = mbox_cache_get_msg_list(item->path);
+       
+       for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
+               struct _message * msg = (struct _message *) l->data;
+
+               if (msg->msginfo != NULL) {
+                       msg->flags = msg->msginfo->flags &
+                               MSG_PERMANENT_FLAG_MASK;
+               }
+       }
+       */
+}
+
+void mbox_change_flags(Folder * folder, FolderItem * item, MsgInfo * info)
+{
+       struct _message * msg = (struct _message *) info->data;
+
+       msg->flags = info->flags;
+}
+
+gboolean mbox_rewrite(gchar * mbox)
+{
+       FILE * mbox_fp;
+       FILE * new_fp;
+       gchar * new;
+       GList * l;
+       gboolean result;
+       gboolean modification = FALSE;
+       GList * msg_list;
+
+       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->deleted) {
+                       printf("modification\n");
+                       modification = TRUE;
+                       break;
+               }
+       }
+
+       if (!modification)
+               return FALSE;
+
+       mbox_fp = fopen(mbox, "r+");
+       mbox_lockwrite_file(mbox_fp, mbox);
+
+       mbox_cache_synchronize_from_file(mbox_fp, mbox);
+
+       new = g_strconcat(mbox, ".new", NULL);
+       new_fp = fopen(new, "w");
+
+       mbox_lockwrite_file(new_fp, new);
+
+       result = TRUE;
+
+       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->deleted)
+                       if (!mbox_write_message(mbox_fp, new_fp, new, msg)) {
+                               result = FALSE;
+                               break;
+                       }
+       }
+
+       unlink(mbox);
+
+       g_warning(_("can't rename %s to %s\n"), new, mbox);
+       if (rename(new_fp, mbox) == -1) {
+               g_warning(_("can't rename %s to %s\n"), new, mbox);
+               mbox_unlock_file(new_fp, new);
+               fclose(new_fp);
+               mbox_unlock_file(mbox_fp, mbox);
+               fclose(mbox_fp);
+               return -1;
+       }
+
+       mbox_unlock_file(new_fp, new);
+
+       fclose(new_fp);
+
+       mbox_unlock_file(mbox_fp, mbox);
+
+       fclose(mbox_fp);
+       return result;
+}
diff --git a/src/mbox_folder.h b/src/mbox_folder.h
new file mode 100644 (file)
index 0000000..38c5027
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef MBOX_FOLDER_H
+
+#define MBOX_FOLDER_H
+
+#include <glib.h>
+#include "folder.h"
+
+/*
+mailfile mailfile_init(char * filename);
+char * mailfile_readmsg(mailfile f, int index);
+char * mailfile_readheader(mailfile f, int index);
+void mailfile_done(mailfile f);
+int mailfile_count(mailfile f);
+*/
+
+GSList *mbox_get_msg_list(Folder *folder, FolderItem *item, gboolean use_cache);
+gchar *mbox_fetch_msg(Folder *folder, FolderItem *item, gint num);
+
+void mbox_scan_folder(Folder *folder, FolderItem *item);
+gchar * mbox_get_virtual_path(FolderItem * item);
+gint mbox_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
+                 gboolean remove_source);
+
+gint mbox_remove_all_msg(Folder *folder, FolderItem *item);
+gint mbox_remove_msg(Folder *folder, FolderItem *item, gint num);
+void mbox_update_mark(Folder * folder, FolderItem * item);
+gint mbox_move_msgs_with_dest(Folder *folder, FolderItem *dest,
+                             GSList *msglist);
+gint mbox_move_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo);
+
+#endif
index 86883d4..820a0c5 100644 (file)
@@ -401,7 +401,7 @@ void prefs_display_header_read_config(void)
        }
 
        while (fgets(buf, sizeof(buf), fp) != NULL) {
-               g_strchomp(buf);
+               g_strdelimit(buf, "\r\n", '\0');
                dp = display_header_prop_read_str(buf);
                if (dp)
                        prefs_common.disphdr_list =
index ce87c2f..177883d 100644 (file)
@@ -31,9 +31,10 @@ void prefs_folder_item_read_config(FolderItem * item)
        gchar * path;
 
        path = folder_item_get_path(item);
+       /*
        if (!is_dir_exist(path))
                make_dir_hier(path);
-
+       */
        prefs_read_config(param, path, FOLDERITEM_RC);
        g_free(path);
 
@@ -47,8 +48,10 @@ void prefs_folder_item_save_config(FolderItem * item)
        tmp_prefs = * item->prefs;
 
        path = folder_item_get_path(item);
+       /*
        if (!is_dir_exist(path))
                make_dir_hier(path);
+       */
 
        prefs_save_config(param, path, FOLDERITEM_RC);
        g_free(path);
index 49a03b5..561adad 100644 (file)
@@ -348,12 +348,13 @@ gboolean procheader_headername_equal(char * hdr1, char * hdr2)
 
        len1 = strlen(hdr1);
        len2 = strlen(hdr2);
-       if ((hdr1[len1 - 1] == ':') || (hdr1[len1 - 1] == ' '))
+       if (hdr1[len1 - 1] == ':')
                len1--;
-       if ((hdr2[len2 - 1] == ':') || (hdr2[len2 - 1] == ' '))
+       if (hdr2[len2 - 1] == ':')
                len2--;
        if (len1 != len2)
                return 0;
+
        return (g_strncasecmp(hdr1, hdr2, len1) == 0);
 }
 
@@ -427,12 +428,33 @@ enum
        H_IN_REPLY_TO   = 8,
        H_CONTENT_TYPE  = 9,
        H_SEEN          = 10,
-       H_X_FACE        = 11,
-       H_DISPOSITION_NOTIFICATION_TO = 12,
-       H_RETURN_RECEIPT_TO = 13
+       H_STATUS        = 11,
+       H_X_STATUS      = 12,
+       H_X_FACE        = 13,
+       H_FROM_SPACE    = 14,
+       H_DISPOSITION_NOTIFICATION_TO = 15,
+       H_RETURN_RECEIPT_TO = 16
 };
 
 MsgInfo *procheader_parse(const gchar *file, MsgFlags flags, gboolean full)
+{
+       FILE *fp;
+       MsgInfo *msginfo;
+
+       if ((fp = fopen(file, "r")) == NULL) {
+               FILE_OP_ERROR(file, "fopen");
+               return NULL;
+       }
+
+       msginfo = procheader_file_parse(fp, flags, full);
+
+       fclose(fp);
+
+       return msginfo;
+}
+
+MsgInfo *procheader_file_parse(FILE * fp, MsgFlags flags,
+                              gboolean full)
 {
        static HeaderEntry hentry_full[] = {{"Date:",           NULL, FALSE},
                                           {"From:",            NULL, TRUE},
@@ -445,7 +467,10 @@ MsgInfo *procheader_parse(const gchar *file, MsgFlags flags, gboolean full)
                                           {"In-Reply-To:",     NULL, FALSE},
                                           {"Content-Type:",    NULL, FALSE},
                                           {"Seen:",            NULL, FALSE},
+                                          {"Status:",          NULL, FALSE},
+                                          {"X-Status:",        NULL, FALSE},
                                           {"X-Face:",          NULL, FALSE},
+                                          {"From ",            NULL, FALSE},
                                           {"Disposition-Notification-To:", NULL, FALSE},
                                           {"Return-Receipt-To:", NULL, FALSE},
                                           {NULL,               NULL, FALSE}};
@@ -461,9 +486,11 @@ MsgInfo *procheader_parse(const gchar *file, MsgFlags flags, gboolean full)
                                            {"In-Reply-To:",    NULL, FALSE},
                                            {"Content-Type:",   NULL, FALSE},
                                            {"Seen:",           NULL, FALSE},
+                                           {"Status:",         NULL, FALSE},
+                                           {"X-Status:",       NULL, FALSE},
+                                           {"From ",           NULL, FALSE},
                                            {NULL,              NULL, FALSE}};
-
-       FILE *fp;
+       
        MsgInfo *msginfo;
        gchar buf[BUFFSIZE], tmp[BUFFSIZE];
        gchar *reference = NULL;
@@ -474,10 +501,6 @@ MsgInfo *procheader_parse(const gchar *file, MsgFlags flags, gboolean full)
 
        hentry = full ? hentry_full : hentry_short;
 
-       if ((fp = fopen(file, "r")) == NULL) {
-               FILE_OP_ERROR(file, "fopen");
-               return NULL;
-       }
        if (MSG_IS_QUEUED(flags)) {
                while (fgets(buf, sizeof(buf), fp) != NULL)
                        if (buf[0] == '\r' || buf[0] == '\n') break;
@@ -490,6 +513,7 @@ MsgInfo *procheader_parse(const gchar *file, MsgFlags flags, gboolean full)
        while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, hentry))
               != -1) {
                hp = buf + strlen(hentry[hnum].name);
+
                while (*hp == ' ' || *hp == '\t') hp++;
 
                switch (hnum) {
@@ -588,13 +612,27 @@ MsgInfo *procheader_parse(const gchar *file, MsgFlags flags, gboolean full)
                        if (msginfo->returnreceiptto) break;
                        msginfo->returnreceiptto = g_strdup(hp);
                        break;
+               case H_STATUS:
+                       if (strchr(hp, 'R') != NULL)
+                               MSG_UNSET_FLAGS(msginfo->flags, MSG_UNREAD);
+                       if (strchr(hp, 'O') != NULL)
+                               MSG_UNSET_FLAGS(msginfo->flags, MSG_NEW);
+                       if (strchr(hp, 'U') != NULL)
+                               MSG_SET_FLAGS(msginfo->flags, MSG_UNREAD);
+                       break;
+               case H_X_STATUS:
+                       if (strchr(hp, 'X') != NULL)
+                               MSG_SET_FLAGS(msginfo->flags, MSG_MARKED);
+                       break;
+               case H_FROM_SPACE:
+                       if (msginfo->fromspace) break;
+                       msginfo->fromspace = g_strdup(hp);
+                       break;
                default:
                }
        }
        msginfo->inreplyto = reference;
 
-       fclose(fp);
-
        return msginfo;
 }
 
index f6292e4..7f8571c 100644 (file)
@@ -63,6 +63,8 @@ void procheader_get_header_fields     (FILE           *fp,
 MsgInfo *procheader_parse              (const gchar    *file,
                                         MsgFlags        flags,
                                         gboolean        full);
+MsgInfo *procheader_file_parse(FILE * fp, MsgFlags flags,
+                              gboolean full);
 
 gchar *procheader_get_fromname         (const gchar    *str);
 
index 8ae883b..b7ed120 100644 (file)
@@ -126,6 +126,7 @@ struct _MsgInfo
        gchar *returnreceiptto;
 
        gchar *references;
+       gchar *fromspace;
 
        gint score;
        gint threadscore;
@@ -133,6 +134,8 @@ struct _MsgInfo
        /* used only for encrypted messages */
        gchar *plaintext_file;
        guint decryption_failed : 1;
+
+       void * data;
 };
 
 GHashTable *procmsg_msg_hash_table_create      (GSList         *mlist);
index be121c7..e803131 100644 (file)
@@ -1518,6 +1518,9 @@ gint summary_write_cache(SummaryView *summaryview)
        if (!summaryview->folder_item || !summaryview->folder_item->path)
                return -1;
 
+       if (summaryview->folder_item->folder->update_mark != NULL)
+               summaryview->folder_item->folder->update_mark(summaryview->folder_item->folder, summaryview->folder_item);
+
        cachefile = folder_item_get_cache_file(summaryview->folder_item);
        g_return_val_if_fail(cachefile != NULL, -1);
        if ((fps.cache_fp = fopen(cachefile, "w")) == NULL) {
index 4d2910a..9640b28 100644 (file)
@@ -1119,6 +1119,17 @@ gchar *get_imap_cache_dir(void)
        return imap_cache_dir;
 }
 
+gchar *get_mbox_cache_dir(void)
+{
+       static gchar *mbox_cache_dir = NULL;
+
+       if (!mbox_cache_dir)
+               mbox_cache_dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                                            MBOX_CACHE_DIR, NULL);
+
+       return mbox_cache_dir;
+}
+
 gchar *get_mime_tmp_dir(void)
 {
        static gchar *mime_tmp_dir = NULL;
index 790865f..27e7a98 100644 (file)
@@ -238,6 +238,7 @@ gchar *get_home_dir         (void);
 gchar *get_rc_dir              (void);
 gchar *get_news_cache_dir      (void);
 gchar *get_imap_cache_dir      (void);
+gchar *get_mbox_cache_dir      (void);
 gchar *get_mime_tmp_dir                (void);
 gchar *get_tmp_file            (void);
 gchar *get_domain_name         (void);