From 5918d234654b3944a14b1f647d78f26bfc34afa9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ho=C3=A0=20Vi=C3=AAt=20Dinh?= Date: Wed, 23 May 2001 12:08:40 +0000 Subject: [PATCH] mbox folder / fix for filtering --- ChangeLog.claws | 28 + src/Makefile.am | 3 +- src/defs.h | 1 + src/folder.c | 104 ++- src/folder.h | 5 + src/folderview.c | 2 + src/imap.c | 14 +- src/mbox.c | 4 +- src/mbox_folder.c | 1485 ++++++++++++++++++++++++++++++++++++ src/mbox_folder.h | 31 + src/prefs_display_header.c | 2 +- src/prefs_folder_item.c | 5 +- src/procheader.c | 64 +- src/procheader.h | 2 + src/procmsg.h | 3 + src/summaryview.c | 3 + src/utils.c | 11 + src/utils.h | 1 + 18 files changed, 1739 insertions(+), 29 deletions(-) create mode 100644 src/mbox_folder.c create mode 100644 src/mbox_folder.h diff --git a/ChangeLog.claws b/ChangeLog.claws index 156e7d3ad..c52f8f7d4 100644 --- a/ChangeLog.claws +++ b/ChangeLog.claws @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index 2c1b32e38..32452aee8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/defs.h b/src/defs.h index 44a1c0a97..40b607e70 100644 --- a/src/defs.h +++ b/src/defs.h @@ -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" diff --git a/src/folder.c b/src/folder.c index 6d06c207f..e77d2b727 100644 --- a/src/folder.c +++ b/src/folder.c @@ -33,12 +33,14 @@ #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)); diff --git a/src/folder.h b/src/folder.h index 1a0cf8036..9227f7fdc 100644 --- a/src/folder.h +++ b/src/folder.h @@ -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 diff --git a/src/folderview.c b/src/folderview.c index 8c377fbf4..b4ea54fd2 100644 --- a/src/folderview.c +++ b/src/folderview.c @@ -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: diff --git a/src/imap.c b/src/imap.c index d9c72b148..b8f9695e8 100644 --- a/src/imap.c +++ b/src/imap.c @@ -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); diff --git a/src/mbox.c b/src/mbox.c index 7b30eefc6..ae55c9759 100644 --- a/src/mbox.c +++ b/src/mbox.c @@ -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 index 000000000..d3243b942 --- /dev/null +++ b/src/mbox_folder.c @@ -0,0 +1,1485 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 000000000..38c5027fb --- /dev/null +++ b/src/mbox_folder.h @@ -0,0 +1,31 @@ +#ifndef MBOX_FOLDER_H + +#define MBOX_FOLDER_H + +#include +#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 diff --git a/src/prefs_display_header.c b/src/prefs_display_header.c index 86883d4c6..820a0c533 100644 --- a/src/prefs_display_header.c +++ b/src/prefs_display_header.c @@ -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 = diff --git a/src/prefs_folder_item.c b/src/prefs_folder_item.c index ce87c2fbd..177883d3f 100644 --- a/src/prefs_folder_item.c +++ b/src/prefs_folder_item.c @@ -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); diff --git a/src/procheader.c b/src/procheader.c index 49a03b57b..561adad52 100644 --- a/src/procheader.c +++ b/src/procheader.c @@ -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; } diff --git a/src/procheader.h b/src/procheader.h index f6292e48c..7f8571cbb 100644 --- a/src/procheader.h +++ b/src/procheader.h @@ -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); diff --git a/src/procmsg.h b/src/procmsg.h index 8ae883b50..b7ed1208d 100644 --- a/src/procmsg.h +++ b/src/procmsg.h @@ -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); diff --git a/src/summaryview.c b/src/summaryview.c index be121c7fa..e80313165 100644 --- a/src/summaryview.c +++ b/src/summaryview.c @@ -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) { diff --git a/src/utils.c b/src/utils.c index 4d2910a2d..9640b28da 100644 --- a/src/utils.c +++ b/src/utils.c @@ -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; diff --git a/src/utils.h b/src/utils.h index 790865fc9..27e7a9876 100644 --- a/src/utils.h +++ b/src/utils.h @@ -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); -- 2.25.1