10 #include "mbox_folder.h"
13 #include "procheader.h"
17 #define MSGBUFSIZE 8192
19 static gboolean mbox_write_data(FILE * mbox_fp, FILE * new_fp,
20 gchar * new_filename, gint size);
21 static gboolean mbox_rewrite(gchar * mbox);
22 static gboolean mbox_purge_deleted(gchar * mbox);
23 static gchar * mbox_get_new_path(FolderItem * parent, gchar * name);
24 static gchar * mbox_get_folderitem_name(gchar * name);
28 static gchar * mbox_folder_create_parent(const gchar * path)
30 if (!is_file_exist(path)) {
33 new_path = g_dirname(path);
34 if (new_path[strlen(new_path) - 1] == G_DIR_SEPARATOR)
35 new_path[strlen(new_path) - 1] = '\0';
37 if (!is_dir_exist(new_path))
38 make_dir_hier(new_path);
45 static gchar *mbox_folder_get_path(FolderItem *item)
50 g_return_val_if_fail(item != NULL, NULL);
52 if (item->path && item->path[0] == G_DIR_SEPARATOR) {
53 mbox_folder_create_parent(item->path);
54 return g_strdup(item->path);
57 folder_path = g_strdup(LOCAL_FOLDER(item->folder)->rootpath);
58 g_return_val_if_fail(folder_path != NULL, NULL);
60 if (folder_path[0] == G_DIR_SEPARATOR) {
62 path = g_strconcat(folder_path, G_DIR_SEPARATOR_S,
66 path = g_strdup(folder_path);
69 path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
70 folder_path, G_DIR_SEPARATOR_S,
73 path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
79 mbox_folder_create_parent(path);
85 /**********************************************************/
89 /**********************************************************/
92 static GSList * file_lock = NULL;
94 static gboolean mbox_file_lock_file(gchar * base)
96 gchar *lockfile, *locklink;
100 lockfile = g_strdup_printf("%s.%d", base, getpid());
101 if ((lockfp = fopen(lockfile, "w")) == NULL) {
102 FILE_OP_ERROR(lockfile, "fopen");
103 g_warning(_("can't create lock file %s\n"), lockfile);
104 g_warning(_("use 'flock' instead of 'file' if possible.\n"));
109 fprintf(lockfp, "%d\n", getpid());
112 locklink = g_strconcat(base, ".lock", NULL);
113 while (link(lockfile, locklink) < 0) {
114 FILE_OP_ERROR(lockfile, "link");
116 g_warning(_("can't create %s\n"), lockfile);
122 g_warning(_("mailbox is owned by another"
123 " process, waiting...\n"));
133 static gboolean mbox_fcntl_lockwrite_file(FILE * fp)
137 lck.l_type = F_WRLCK;
142 if (fcntl(fileno(fp), F_SETLK, &lck) < 0)
148 static gboolean mbox_fcntl_lockread_file(FILE * fp)
152 lck.l_type = F_RDLCK;
157 if (fcntl(fileno(fp), F_SETLK, &lck) < 0)
163 static gboolean mbox_fcntl_unlock_file(FILE * fp)
167 lck.l_type = F_UNLCK;
172 if (fcntl(fileno(fp), F_SETLK, &lck) < 0)
178 static gboolean mbox_file_unlock_file(gchar * base)
182 lockfile = g_strdup_printf("%s.lock", base);
189 static gboolean mbox_lockread_file(FILE * fp, gchar * base)
193 result = mbox_fcntl_lockread_file(fp);
195 if ((result = mbox_file_lock_file(base)) == TRUE) {
196 file_lock = g_slist_append(file_lock, g_strdup(base));
197 debug_print("lockfile lock %s.\n", base);
200 g_warning(_("could not lock read file %s\n"), base);
203 debug_print("fcntl lock %s.\n", base);
208 static gboolean mbox_lockwrite_file(FILE * fp, gchar * base)
212 result = mbox_fcntl_lockwrite_file(fp);
214 if ((result = mbox_file_lock_file(base)) == TRUE) {
215 file_lock = g_slist_append(file_lock, g_strdup(base));
216 debug_print("lockfile lock %s.\n", base);
219 g_warning(_("could not lock write file %s\n"), base);
222 debug_print("fcntl lock %s.\n", base);
227 static gboolean mbox_unlock_file(FILE * fp, gchar * base)
229 gboolean result = FALSE;
231 gboolean unlocked = FALSE;
233 for(l = file_lock ; l != NULL ; l = g_slist_next(l)) {
234 gchar * data = l->data;
236 if (strcmp(data, base) == 0) {
237 file_lock = g_slist_remove(file_lock, data);
239 result = mbox_file_unlock_file(base);
241 debug_print("lockfile unlock - %s.\n", base);
247 result = mbox_fcntl_unlock_file(fp);
248 debug_print("fcntl unlock - %s.\n", base);
254 /**********************************************************/
258 /**********************************************************/
260 #define MAILFILE_ERROR_NO_ERROR 0x000
261 #define MAILFILE_ERROR_FILE_NOT_FOUND 0x001
262 #define MAILFILE_ERROR_MEMORY 0x002
263 #define MAILFILE_ERROR_MESSAGE_NOT_FOUND 0x003
265 static int mailfile_error = MAILFILE_ERROR_NO_ERROR;
267 #define STATE_BEGIN 0x000
268 #define STATE_TEXT_READ 0x001
269 #define STATE_FROM_READ 0x002
270 #define STATE_FIELD_READ 0x003
271 #define STATE_END 0x004
272 #define STATE_END_OF_FILE 0x005
273 #define STATE_MEM_ERROR 0x006
274 #define STATE_TEXT_BEGIN 0x007
276 #define STATE_MASK 0x0FF /* filter state from functions */
278 #define STATE_RESTORE_POS 0x100 /* go back while reading */
280 typedef struct _mailfile mailfile;
305 static int startFrom(char * s)
307 return (strncmp(s, "From ", 5) == 0);
310 static int startSpace(char * s)
312 return ((*s == ' ') || (*s == '\t'));
315 static int startEmpty(char * s)
320 static void free_msg_list(GList * l)
322 GList * elt = g_list_first(l);
327 elt = g_list_next(elt);
334 static mailfile * mailfile_init_from_file(FILE * f, gchar * filename)
337 GList * msg_list = NULL;
344 struct _message * data = NULL;
350 while (state != STATE_END_OF_FILE) {
351 if ((state & STATE_RESTORE_POS) == 0) {
352 former_pos = lastpos;
355 r = fgets(s, 256, f);
358 ignore_next = (s[strlen(s) - 1] != '\n');
363 switch(state & 0x0F) {
366 state = STATE_END_OF_FILE;
367 else if (startFrom(s)) {
368 state = STATE_FROM_READ;
370 data = g_new0(struct _message, 1);
372 free_msg_list(msg_list);
377 data->msgnum = msgnum;
378 data->offset = lastpos;
379 data->header = lastpos;
382 data->messageid = NULL;
383 data->fromspace = NULL;
385 data->old_flags = -1;
386 data->fetched = FALSE;
387 msg_list = g_list_append(msg_list,
395 case STATE_TEXT_READ:
398 else if (startFrom(s))
399 state = STATE_END | STATE_RESTORE_POS;
401 state = STATE_TEXT_READ;
404 case STATE_TEXT_BEGIN:
405 data->content = lastpos;
408 else if (startFrom(s)) {
409 state = STATE_END | STATE_RESTORE_POS;
412 state = STATE_TEXT_READ;
416 case STATE_FROM_READ:
417 data->content = lastpos;
420 else if (startSpace(s))
421 state = STATE_FROM_READ;
422 else if (startEmpty(s))
423 state = STATE_TEXT_READ;
425 state = STATE_FIELD_READ;
428 case STATE_FIELD_READ:
429 data->content = lastpos;
432 else if (startSpace(s))
433 state = STATE_FIELD_READ;
434 else if (startEmpty(s)) {
435 state = STATE_TEXT_BEGIN;
438 state = STATE_FIELD_READ;
442 if ((state & STATE_MASK) == STATE_END) {
443 state = STATE_BEGIN | (state & STATE_RESTORE_POS);
449 r = fgets(s, 256, f);
450 if (r == NULL || *r == '\0')
453 while (s[strlen(s) - 1] != '\n');
457 mf = (mailfile *) g_new0(struct _mailfile, 1);
459 free_msg_list(msg_list);
460 mailfile_error = MAILFILE_ERROR_MEMORY;
464 mf->msg_list = g_list_first(msg_list);
466 mf->filename = g_strdup(filename);
469 mailfile_error = MAILFILE_ERROR_NO_ERROR;
474 static mailfile * mailfile_init(char * filename)
480 f = fopen(filename, "r");
483 mailfile_error = MAILFILE_ERROR_FILE_NOT_FOUND;
487 mbox_lockread_file(f, filename);
489 mf = mailfile_init_from_file(f, filename);
491 mbox_unlock_file(f, filename);
498 static void mailfile_done(mailfile * f)
500 free_msg_list(f->msg_list);
507 #define MAX_READ 4096
509 static char * readfile(char * filename, int offset, int max_offset)
518 handle = fopen(filename, "r");
520 if (handle == NULL) {
521 mailfile_error = MAILFILE_ERROR_FILE_NOT_FOUND;
525 size = max_offset - offset;
527 message = (char *) malloc(size + 1);
528 if (message == NULL) {
530 mailfile_error = MAILFILE_ERROR_MEMORY;
534 fseek(handle, offset, SEEK_SET);
538 if ((size - pos) > MAX_READ)
543 bread = fread(message + pos, 1, max, handle);
559 static char * mailfile_readmsg(mailfile f, int index)
565 struct _message * msginfo;
567 nth = g_list_nth(f->msg_list, index);
570 mailfile_error = MAILFILE_ERROR_MESSAGE_NOT_FOUND;
574 msginfo = (struct _message *)nth->data;
576 offset = msginfo->offset;
577 max_offset = msginfo->end;
578 message = readfile(f->filename, offset, max_offset);
580 mailfile_error = MAILFILE_ERROR_NO_ERROR;
585 static char * mailfile_readheader(mailfile f, int index)
591 struct _message * msginfo;
593 nth = g_list_nth(f->msg_list, index);
596 mailfile_error = MAILFILE_ERROR_MESSAGE_NOT_FOUND;
600 msginfo = (struct _message *)nth->data;
602 offset = msginfo->offset;
603 max_offset = msginfo->content;
604 message = readfile(f->filename, offset, max_offset);
606 mailfile_error = MAILFILE_ERROR_NO_ERROR;
611 static int mailfile_count(mailfile * f)
613 return g_list_length(f->msg_list);
616 static int mailfile_find_deleted(mailfile f, char * filename)
620 handle = fopen(filename, "r");
623 struct _message m = elt->data;
624 n = fread(&m.deleted, sizeof(int), 1, handle);
627 elt = g_list_next(elt);
636 /**********************************************************/
638 /* mbox cache operations */
640 /**********************************************************/
647 gboolean modification;
650 typedef struct _mboxcache mboxcache;
652 static GHashTable * mbox_cache_table = NULL;
654 static MsgInfo *mbox_parse_msg(FILE * fp, struct _message * msg,
658 MsgFlags flags = MSG_NEW|MSG_UNREAD;
660 g_return_val_if_fail(fp != NULL, NULL);
663 if (item->stype == F_QUEUE) {
664 MSG_SET_FLAGS(flags, MSG_QUEUED);
665 } else if (item->stype == F_DRAFT) {
666 MSG_SET_FLAGS(flags, MSG_DRAFT);
670 msginfo = procheader_file_parse(fp, flags, FALSE);
672 if (!msginfo) return NULL;
675 msginfo->msgnum = msg->msgnum;
676 msginfo->folder = item;
682 static void mbox_cache_init()
684 mbox_cache_table = g_hash_table_new(g_str_hash, g_str_equal);
687 static void mbox_cache_done()
689 g_hash_table_destroy(mbox_cache_table);
692 static void mbox_cache_free_mbox(mboxcache * cache)
694 g_hash_table_remove(mbox_cache_table, cache->filename);
697 mailfile_done(cache->mf);
699 g_ptr_array_free(cache->tab_mf, FALSE);
701 g_free(cache->filename);
705 static void mbox_cache_get_msginfo_from_file(FILE * fp, GList * msg_list)
710 for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
711 struct _message * msg;
713 msg = (struct _message *) l->data;
715 fseek(fp, msg->header, SEEK_SET);
716 msginfo = mbox_parse_msg(fp, msg, NULL);
720 g_strdup(msginfo->msgid);
721 if (msginfo->fromspace)
723 g_strdup(msginfo->fromspace);
724 msg->flags = msginfo->flags;
725 msg->old_flags = msginfo->flags;
727 procmsg_msginfo_free(msginfo);
732 static void mbox_cache_get_msginfo(gchar * filename, GList * msg_list)
736 fp = fopen(filename, "r");
740 mbox_cache_get_msginfo_from_file(fp, msg_list);
744 static mboxcache * mbox_cache_read_mbox(gchar * filename)
751 if (stat(filename, &s) < 0)
754 mf = mailfile_init(filename);
758 cache = g_new0(mboxcache, 1);
760 cache->mtime = s.st_mtime;
762 cache->filename = g_strdup(filename);
763 cache->modification = FALSE;
765 cache->tab_mf = g_ptr_array_new();
766 for(l = mf->msg_list ; l != NULL ; l = g_list_next(l))
767 g_ptr_array_add(cache->tab_mf, l->data);
769 mbox_cache_get_msginfo(filename, mf->msg_list);
771 debug_print(_("read mbox - %s\n"), filename);
776 static mboxcache * mbox_cache_read_mbox_from_file(FILE * fp, gchar * filename)
783 if (stat(filename, &s) < 0)
786 mf = mailfile_init_from_file(fp, filename);
790 cache = g_new0(mboxcache, 1);
792 cache->mtime = s.st_mtime;
794 cache->filename = g_strdup(filename);
796 cache->tab_mf = g_ptr_array_new();
797 for(l = mf->msg_list ; l != NULL ; l = g_list_next(l))
798 g_ptr_array_add(cache->tab_mf, l->data);
800 mbox_cache_get_msginfo_from_file(fp, mf->msg_list);
802 debug_print(_("read mbox from file - %s\n"), filename);
807 static void mbox_cache_insert_mbox(mboxcache * data)
809 if (mbox_cache_table == NULL)
812 g_hash_table_insert(mbox_cache_table, data->filename, data);
815 static mboxcache * mbox_cache_get_mbox(gchar * filename)
817 if (mbox_cache_table == NULL)
820 return g_hash_table_lookup(mbox_cache_table, filename);
824 static gint mbox_cache_get_count(gchar * filename)
828 cache = mbox_cache_get_mbox(filename);
831 if (cache->mf == NULL)
833 return cache->mf->count;
836 static gint mbox_cache_get_mtime(gchar * filename)
840 cache = mbox_cache_get_mbox(filename);
846 static GList * mbox_cache_get_msg_list(gchar * filename)
850 cache = mbox_cache_get_mbox(filename);
855 if (cache->mf == NULL)
858 return cache->mf->msg_list;
861 static void mbox_cache_synchronize_lists(GList * old_msg_list,
862 GList * new_msg_list)
867 for(l2 = old_msg_list ; l2 != NULL ; l2 = g_list_next(l2)) {
868 struct _message * msg2 = l2->data;
870 if ((msg2->messageid == NULL) ||
871 (msg2->fromspace == NULL))
874 for(l = new_msg_list ; l != NULL ; l = g_list_next(l)) {
875 struct _message * msg = l->data;
877 if ((msg->messageid == NULL) ||
878 (msg->fromspace == NULL))
881 if ((strcmp(msg->messageid, msg2->messageid) == 0) &&
882 (strcmp(msg->fromspace, msg2->fromspace) == 0)) {
883 if ((msg2->flags & MSG_PERMANENT_FLAG_MASK) !=
885 MSG_PERMANENT_FLAG_MASK)) {
886 msg->flags = msg2->flags;
894 static void mbox_cache_synchronize(gchar * filename, gboolean sync)
896 mboxcache * new_cache;
897 mboxcache * old_cache;
898 gboolean scan_new = TRUE;
901 old_cache = mbox_cache_get_mbox(filename);
903 if (old_cache != NULL) {
904 if (stat(filename, &s) < 0) {
905 FILE_OP_ERROR(filename, "stat");
906 } else if (old_cache->mtime == s.st_mtime) {
907 debug_print("Folder is not modified.\n");
916 if (strstr(filename, "trash") == 0)
917 printf("old_cache: %p %s\n", old_cache, filename);
919 printf("begin old\n");
920 for(l = old_cache->mf->msg_list ; l != NULL ;
921 l = g_list_next(l)) {
922 struct _message * msg = l->data;
929 new_cache = mbox_cache_read_mbox(filename);
932 if (strstr(filename, "trash") == 0)
933 printf("new_cache: %p %s\n", new_cache, filename);
935 printf("begin new\n");
936 for(l = new_cache->mf->msg_list ; l != NULL ;
937 l = g_list_next(l)) {
938 struct _message * msg = l->data;
948 if (sync && new_cache && old_cache)
949 mbox_cache_synchronize_lists(old_cache->mf->msg_list,
950 new_cache->mf->msg_list);
952 if (old_cache != NULL)
953 mbox_cache_free_mbox(old_cache);
956 mbox_cache_insert_mbox(new_cache);
958 printf("insert %p %s\n", new_cache, new_cache->filename);
959 printf("inserted %s %p\n", filename,
960 mbox_cache_get_mbox(filename));
966 static void mbox_cache_synchronize_from_file(FILE * fp, gchar * filename,
969 mboxcache * new_cache;
970 mboxcache * old_cache;
971 gboolean scan_new = TRUE;
974 old_cache = mbox_cache_get_mbox(filename);
976 if (old_cache != NULL) {
977 if (stat(filename, &s) < 0) {
978 FILE_OP_ERROR(filename, "stat");
979 } else if (old_cache->mtime == s.st_mtime) {
980 debug_print("Folder is not modified.\n");
991 if (strstr(filename, "trash") == 0)
992 printf("old_cache: %p %s\n", old_cache, filename);
995 printf("begin old\n");
996 for(l = old_cache->mf->msg_list ; l != NULL ;
997 l = g_list_next(l)) {
998 struct _message * msg = l->data;
1001 printf("end old\n");
1005 new_cache = mbox_cache_read_mbox_from_file(fp, filename);
1008 if (strstr(filename, "trash") == 0)
1009 printf("new_cache: %p %s\n", new_cache, filename);
1012 printf("begin new\n");
1013 for(l = new_cache->mf->msg_list ; l != NULL ;
1014 l = g_list_next(l)) {
1015 struct _message * msg = l->data;
1016 printf("%p\n", msg);
1018 printf("end new\n");
1025 if (sync && new_cache && old_cache)
1026 mbox_cache_synchronize_lists(old_cache->mf->msg_list,
1027 new_cache->mf->msg_list);
1029 if (old_cache != NULL)
1030 mbox_cache_free_mbox(old_cache);
1033 mbox_cache_insert_mbox(new_cache);
1035 printf("insert %p %s\n", new_cache, new_cache->filename);
1036 printf("inserted %s %p\n", filename,
1037 mbox_cache_get_mbox(filename));
1043 gboolean mbox_cache_msg_fetched(gchar * filename, gint num)
1045 struct _message * msg;
1048 cache = mbox_cache_get_mbox(filename);
1053 msg = (struct _message *) g_ptr_array_index(cache->tab_mf,
1058 return msg->fetched;
1061 void mbox_cache_msg_set_fetched(gchar * filename, gint num)
1063 struct _message * msg;
1066 cache = mbox_cache_get_mbox(filename);
1071 msg = (struct _message *) g_ptr_array_index(cache->tab_mf,
1076 msg->fetched = TRUE;
1079 struct _message * mbox_cache_get_msg(gchar * filename, gint num)
1083 cache = mbox_cache_get_mbox(filename);
1085 if (cache == NULL) {
1089 return (struct _message *) g_ptr_array_index(cache->tab_mf,
1094 /**********************************************************/
1096 /* mbox operations */
1098 /**********************************************************/
1101 GSList *mbox_get_msg_list(Folder *folder, FolderItem *item, gboolean use_cache)
1110 struct timeval tv_before, tv_after, tv_result;
1112 gettimeofday(&tv_before, NULL);
1117 mbox_path = mbox_folder_get_path(item);
1119 if (mbox_path == NULL)
1122 mbox_purge_deleted(mbox_path);
1124 fp = fopen(mbox_path, "r");
1131 mbox_lockread_file(fp, mbox_path);
1133 mbox_cache_synchronize_from_file(fp, mbox_path, TRUE);
1135 item->last_num = mbox_cache_get_count(mbox_path);
1137 for(l = mbox_cache_get_msg_list(mbox_path) ; l != NULL ;
1138 l = g_list_next(l)) {
1139 struct _message * msg;
1141 msg = (struct _message *) l->data;
1143 if (msg->flags == -1 || !MSG_IS_REALLY_DELETED(msg->flags)) {
1144 fseek(fp, msg->header, SEEK_SET);
1146 msginfo = mbox_parse_msg(fp, msg, item);
1148 if (msg->flags != -1)
1149 msginfo->flags = msg->flags;
1151 msg->old_flags = msginfo->flags;
1152 msg->flags = msginfo->flags;
1155 mlist = g_slist_append(mlist, msginfo);
1158 msg->flags = MSG_REALLY_DELETED;
1162 mbox_unlock_file(fp, mbox_path);
1169 gettimeofday(&tv_after, NULL);
1171 timersub(&tv_after, &tv_before, &tv_result);
1172 g_print("mbox_get_msg_list: %s: elapsed time: %ld.%06ld sec\n",
1173 mbox_path, tv_result.tv_sec, tv_result.tv_usec);
1179 static gboolean mbox_extract_msg(FolderItem * item, gint msgnum,
1180 gchar * dest_filename)
1182 struct _message * msg;
1189 /* GList * msg_list;*/
1190 gboolean already_fetched;
1193 mbox_path = mbox_folder_get_path(item);
1195 if (mbox_path == NULL)
1198 src = fopen(mbox_path, "r");
1204 mbox_lockread_file(src, mbox_path);
1206 mbox_cache_synchronize_from_file(src, mbox_path, TRUE);
1208 already_fetched = mbox_cache_msg_fetched(mbox_path, msgnum);
1210 if (already_fetched) {
1211 mbox_unlock_file(src, mbox_path);
1217 msg = mbox_cache_get_msg(mbox_path, msgnum);
1220 mbox_unlock_file(src, mbox_path);
1226 offset = msg->offset;
1227 max_offset = msg->end;
1229 size = max_offset - offset;
1231 fseek(src, offset, SEEK_SET);
1233 dest = fopen(dest_filename, "w");
1235 mbox_unlock_file(src, mbox_path);
1241 if (change_file_mode_rw(dest, dest_filename) < 0) {
1242 FILE_OP_ERROR(dest_filename, "chmod");
1243 g_warning(_("can't change file mode\n"));
1246 if (!mbox_write_data(src, dest, dest_filename, size)) {
1247 mbox_unlock_file(src, mbox_path);
1250 unlink(dest_filename);
1258 FILE_OP_ERROR(mbox_path, "fread");
1262 mbox_cache_msg_set_fetched(mbox_path, msgnum);
1264 if (fclose(dest) == -1) {
1265 FILE_OP_ERROR(dest_filename, "fclose");
1269 mbox_unlock_file(src, mbox_path);
1271 if (fclose(src) == -1) {
1272 FILE_OP_ERROR(mbox_path, "fclose");
1279 unlink(dest_filename);
1286 gchar *mbox_fetch_msg(Folder *folder, FolderItem *item, gint num)
1291 g_return_val_if_fail(item != NULL, NULL);
1292 g_return_val_if_fail(num > 0 && num <= item->last_num, NULL);
1294 path = folder_item_get_path(item);
1295 if (!is_dir_exist(path))
1296 make_dir_hier(path);
1298 filename = g_strconcat(path, G_DIR_SEPARATOR_S, itos(num), NULL);
1302 if (!mbox_extract_msg(item, num, filename)) {
1310 gint mbox_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
1311 gboolean remove_source)
1320 gchar from_line[MSGBUFSIZE];
1322 if (dest->last_num < 0) {
1323 mbox_scan_folder(folder, dest);
1324 if (dest->last_num < 0) return -1;
1327 src_fp = fopen(file, "r");
1328 if (src_fp == NULL) {
1332 mbox_path = mbox_folder_get_path(dest);
1333 if (mbox_path == NULL)
1336 dest_fp = fopen(mbox_path, "a");
1337 if (dest_fp == NULL) {
1343 if (change_file_mode_rw(dest_fp, mbox_path) < 0) {
1344 FILE_OP_ERROR(mbox_path, "chmod");
1345 g_warning(_("can't change file mode\n"));
1348 old_size = ftell(dest_fp);
1350 mbox_lockwrite_file(dest_fp, mbox_path);
1352 if (fgets(from_line, sizeof(from_line), src_fp) == NULL) {
1353 mbox_unlock_file(dest_fp, mbox_path);
1354 g_warning(_("unvalid file - %s.\n"), file);
1361 if (strncmp(from_line, "From ", 5) != 0) {
1364 if (stat(file, &s) < 0) {
1365 mbox_unlock_file(dest_fp, mbox_path);
1366 g_warning(_("unvalid file - %s.\n"), file);
1373 fprintf(dest_fp, "From - %s", ctime(&s.st_mtime));
1376 fputs(from_line, dest_fp);
1379 n_read = fread(buf, 1, sizeof(buf), src_fp);
1380 if ((n_read < (gint) sizeof(buf)) && ferror(src_fp))
1382 if (fwrite(buf, n_read, 1, dest_fp) < 1) {
1383 mbox_unlock_file(dest_fp, mbox_path);
1384 g_warning(_("writing to %s failed.\n"), mbox_path);
1385 ftruncate(fileno(dest_fp), old_size);
1392 if (n_read < (gint) sizeof(buf))
1398 if (ferror(src_fp)) {
1399 FILE_OP_ERROR(mbox_path, "fread");
1402 mbox_unlock_file(dest_fp, mbox_path);
1404 if (fclose(src_fp) == -1) {
1405 FILE_OP_ERROR(file, "fclose");
1409 if (fclose(dest_fp) == -1) {
1410 FILE_OP_ERROR(mbox_path, "fclose");
1416 ftruncate(fileno(dest_fp), old_size);
1421 if (remove_source) {
1422 if (unlink(file) < 0)
1423 FILE_OP_ERROR(file, "unlink");
1429 return dest->last_num;
1433 gint mbox_remove_msg(Folder *folder, FolderItem *item, gint num)
1435 struct _message * msg;
1438 mbox_path = mbox_folder_get_path(item);
1439 if (mbox_path == NULL)
1442 mbox_cache_synchronize(mbox_path, TRUE);
1444 msg = mbox_cache_get_msg(mbox_path, num);
1449 MSG_SET_FLAGS(msg->flags, MSG_REALLY_DELETED);
1454 gint mbox_remove_all_msg(Folder *folder, FolderItem *item)
1459 mbox_path = mbox_folder_get_path(item);
1460 if (mbox_path == NULL)
1463 fp = fopen(mbox_path, "w");
1477 gint mbox_move_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
1482 filename = mbox_fetch_msg(folder, msginfo->folder, msginfo->msgnum);
1483 if (filename == NULL)
1486 msgnum = mbox_add_msg(folder, dest, filename, TRUE);
1489 MSG_SET_FLAGS(msginfo->flags, MSG_REALLY_DELETED);
1490 mbox_change_flags(folder, msginfo->folder, msginfo);
1496 gint mbox_move_msgs_with_dest(Folder *folder, FolderItem *dest, GSList *msglist)
1499 gchar * mbox_path = NULL;
1501 for(l = msglist ; l != NULL ; l = g_slist_next(l)) {
1502 MsgInfo * msginfo = (MsgInfo *) l->data;
1504 if (msginfo->folder && mbox_path == NULL)
1505 mbox_path = mbox_folder_get_path(msginfo->folder);
1507 mbox_move_msg(folder, dest, msginfo);
1511 mbox_cache_synchronize(mbox_path);
1515 mbox_path = mbox_folder_get_path(dest);
1516 mbox_cache_synchronize(mbox_path);
1519 return dest->last_num;
1524 gint mbox_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
1529 filename = mbox_fetch_msg(folder, msginfo->folder, msginfo->msgnum);
1530 if (filename == NULL)
1533 msgnum = mbox_add_msg(folder, dest, filename, FALSE);
1538 gint mbox_copy_msgs_with_dest(Folder *folder, FolderItem *dest, GSList *msglist)
1541 gchar * mbox_path = NULL;
1543 for(l = msglist ; l != NULL ; l = g_slist_next(l)) {
1544 MsgInfo * msginfo = (MsgInfo *) l->data;
1546 if (msginfo->folder && mbox_path == NULL)
1547 mbox_path = mbox_folder_get_path(msginfo->folder);
1549 mbox_copy_msg(folder, dest, msginfo);
1553 mbox_cache_synchronize(mbox_path);
1557 mbox_path = mbox_folder_get_path(dest);
1558 mbox_cache_synchronize(mbox_path);
1561 return dest->last_num;
1565 struct _copy_flags_info
1571 typedef struct _copy_flags_info CopyFlagsInfo;
1573 GSList * copy_flags_data = NULL;
1575 gint mbox_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
1577 Folder * src_folder;
1582 struct _message * msg;
1583 CopyFlagsInfo * flags_info;
1585 src_folder = msginfo->folder->folder;
1587 g_return_val_if_fail(src_folder->fetch_msg != NULL, -1);
1590 mbox_path = mbox_folder_get_path(msginfo->folder);
1591 mbox_rewrite(mbox_path);
1595 filename = src_folder->fetch_msg(src_folder,
1598 if (filename == NULL)
1601 num = folder->add_msg(folder, dest, filename, FALSE);
1604 mbox_path = mbox_folder_get_path(dest);
1605 msg = mbox_cache_get_msg(mbox_path, num);
1607 msg->flags = msginfo->flags;
1614 flags_info = g_new0(CopyFlagsInfo, 1);
1615 flags_info->num = num;
1616 flags_info->flags = msginfo->flags;
1617 copy_flags_data = g_slist_append(copy_flags_data, flags_info);
1622 void mbox_finished_copy(Folder *folder, FolderItem *dest)
1628 mbox_path = mbox_folder_get_path(dest);
1629 if (mbox_path == NULL)
1632 mbox_cache_synchronize(mbox_path, TRUE);
1634 for(l = copy_flags_data ; l != NULL ; l = g_slist_next(l)) {
1635 CopyFlagsInfo * flags_info = l->data;
1636 struct _message * msg;
1638 msg = mbox_cache_get_msg(mbox_path, flags_info->num);
1640 msg->flags = flags_info->flags;
1644 if (copy_flags_data != NULL) {
1645 cache = mbox_cache_get_mbox(mbox_path);
1646 cache->modification = TRUE;
1649 g_slist_free(copy_flags_data);
1650 copy_flags_data = NULL;
1652 mbox_rewrite(mbox_path);
1657 void mbox_scan_folder(Folder *folder, FolderItem *item)
1664 mbox_path = mbox_folder_get_path(item);
1665 if (mbox_path == NULL)
1668 mbox_cache_synchronize(mbox_path, TRUE);
1670 cached = mbox_cache_get_mbox(mbox_path);
1672 if (cached == NULL) {
1681 n_msg = mbox_cache_get_count(mbox_path);
1684 item->new = item->unread = item->total = 0;
1691 for(l = mbox_cache_get_msg_list(mbox_path) ; l != NULL ;
1692 l = g_list_next(l)) {
1693 struct _message * msg = (struct _message *) l->data;
1694 if (!MSG_IS_REALLY_DELETED(msg->flags))
1696 if (MSG_IS_NEW(msg->flags))
1698 if (MSG_IS_UNREAD(msg->flags))
1703 item->unread = unread;
1704 item->total = total;
1707 debug_print(_("Last number in dir %s = %d\n"), mbox_path,
1709 item->last_num = n_msg;
1713 gchar * mbox_get_virtual_path(FolderItem * item)
1718 if (item->parent == NULL) {
1722 gchar * parent_path;
1723 gchar * result_path;
1725 parent_path = mbox_get_virtual_path(item->parent);
1726 if (parent_path == NULL)
1727 result_path = g_strdup(item->name);
1729 result_path = g_strconcat(parent_path,
1732 g_free(parent_path);
1738 static gboolean mbox_write_data(FILE * mbox_fp, FILE * new_fp,
1739 gchar * new_filename, gint size)
1747 while (pos < size) {
1748 if ((size - pos) > (gint) sizeof(buf))
1753 n_read = fread(buf, 1, max, mbox_fp);
1755 if (n_read < max && ferror(mbox_fp)) {
1758 if (fwrite(buf, n_read, 1, new_fp) < 1) {
1759 g_warning(_("writing to %s failed.\n"), new_filename);
1772 static gboolean mbox_write_message(FILE * mbox_fp, FILE * new_fp,
1773 gchar * new_filename,
1774 struct _message * msg)
1777 GPtrArray * headers;
1780 fseek(mbox_fp, msg->header, SEEK_SET);
1782 headers = procheader_get_header_array_asis(mbox_fp);
1784 for (i = 0; i < (gint) headers->len; i++) {
1785 Header * h = g_ptr_array_index(headers, i);
1787 if (!procheader_headername_equal(h->name,
1789 !procheader_headername_equal(h->name,
1791 fwrite(h->name, strlen(h->name),
1793 if (h->name[strlen(h->name) - 1] != ' ')
1794 fwrite(" ", 1, 1, new_fp);
1795 fwrite(h->body, strlen(h->body),
1797 fwrite("\n", 1, 1, new_fp);
1799 procheader_header_free(h);
1800 g_ptr_array_remove_index(headers, i);
1804 g_ptr_array_free(headers, FALSE);
1806 if (msg->flags != -1) {
1808 fwrite("Status: ", strlen("Status: "), 1, new_fp);
1809 if (!MSG_IS_UNREAD(msg->flags))
1810 fwrite("R", 1, 1, new_fp);
1811 fwrite("O", 1, 1, new_fp);
1812 fwrite("\n", 1, 1, new_fp);
1814 /* X-Status header */
1816 (MSG_REALLY_DELETED | MSG_MARKED | MSG_DELETED
1817 | MSG_REPLIED | MSG_FORWARDED)) {
1818 fwrite("X-Status: ", strlen("X-Status: "), 1, new_fp);
1819 if (MSG_IS_REALLY_DELETED(msg->flags))
1820 fwrite("D", 1, 1, new_fp); /* really deleted */
1822 if (MSG_IS_MARKED(msg->flags))
1823 fwrite("F", 1, 1, new_fp);
1824 if (MSG_IS_DELETED(msg->flags))
1825 fwrite("d", 1, 1, new_fp);
1826 if (MSG_IS_REPLIED(msg->flags))
1827 fwrite("r", 1, 1, new_fp);
1828 if (MSG_IS_FORWARDED(msg->flags))
1829 fwrite("f", 1, 1, new_fp);
1831 fwrite("\n", 1, 1, new_fp);
1835 fwrite("\n", 1, 1, new_fp);
1837 size = msg->end - msg->content;
1838 fseek(mbox_fp, msg->content, SEEK_SET);
1840 return mbox_write_data(mbox_fp, new_fp, new_filename, size);
1843 void mbox_update_mark(Folder * folder, FolderItem * item)
1847 mbox_path = mbox_folder_get_path(item);
1848 if (mbox_path == NULL)
1851 mbox_rewrite(mbox_path);
1855 void mbox_change_flags(Folder * folder, FolderItem * item, MsgInfo * info)
1857 struct _message * msg;
1861 mbox_path = mbox_folder_get_path(item);
1862 if (mbox_path == NULL)
1865 msg = mbox_cache_get_msg(mbox_path, info->msgnum);
1867 cache = mbox_cache_get_mbox(mbox_path);
1871 if ((msg == NULL) || (cache == NULL))
1874 msg->flags = info->flags;
1876 cache->modification = TRUE;
1880 static gboolean mbox_rewrite(gchar * mbox)
1891 msg_list = mbox_cache_get_msg_list(mbox);
1893 cache = mbox_cache_get_mbox(mbox);
1897 if (!cache->modification) {
1898 debug_print(_("no modification - %s\n"), mbox);
1902 debug_print(_("save modification - %s\n"), mbox);
1904 mbox_fp = fopen(mbox, "r+");
1905 mbox_lockwrite_file(mbox_fp, mbox);
1907 mbox_cache_synchronize_from_file(mbox_fp, mbox, TRUE);
1909 new = g_strconcat(mbox, ".", itos((int) mbox), NULL);
1910 new_fp = fopen(new, "w");
1912 if (change_file_mode_rw(new_fp, new) < 0) {
1913 FILE_OP_ERROR(new, "chmod");
1914 g_warning(_("can't change file mode\n"));
1917 mbox_lockwrite_file(new_fp, new);
1922 msg_list = mbox_cache_get_msg_list(mbox);
1923 for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
1924 struct _message * msg = (struct _message *) l->data;
1925 if (!mbox_write_message(mbox_fp, new_fp, new, msg)) {
1934 if (rename(new, mbox) == -1) {
1935 g_warning(_("can't rename %s to %s\n"), new, mbox);
1936 mbox_unlock_file(new_fp, new);
1938 mbox_unlock_file(mbox_fp, mbox);
1943 if (change_file_mode_rw(new_fp, mbox) < 0) {
1944 FILE_OP_ERROR(new, "chmod");
1945 g_warning(_("can't change file mode\n"));
1948 mbox_unlock_file(new_fp, new);
1952 mbox_unlock_file(mbox_fp, mbox);
1956 debug_print(_("%i messages written - %s\n"), count, mbox);
1958 cache = mbox_cache_get_mbox(mbox);
1963 mbox_cache_synchronize(mbox, FALSE);
1968 static gboolean mbox_purge_deleted(gchar * mbox)
1975 gboolean modification = FALSE;
1979 mbox_cache_synchronize(mbox, TRUE);
1981 msg_list = mbox_cache_get_msg_list(mbox);
1983 for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
1984 struct _message * msg = (struct _message *) l->data;
1985 if (msg->flags != -1 && MSG_IS_REALLY_DELETED(msg->flags)) {
1986 modification = TRUE;
1991 if (!modification) {
1992 debug_print(_("no deleted messages - %s\n"), mbox);
1996 debug_print(_("purge deleted messages - %s\n"), mbox);
1998 mbox_fp = fopen(mbox, "r+");
1999 mbox_lockwrite_file(mbox_fp, mbox);
2001 mbox_cache_synchronize_from_file(mbox_fp, mbox, TRUE);
2003 new = g_strconcat(mbox, ".", itos((int) mbox), NULL);
2004 new_fp = fopen(new, "w");
2006 if (change_file_mode_rw(new_fp, new) < 0) {
2007 FILE_OP_ERROR(new, "chmod");
2008 g_warning(_("can't change file mode\n"));
2011 mbox_lockwrite_file(new_fp, new);
2016 msg_list = mbox_cache_get_msg_list(mbox);
2017 for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
2018 struct _message * msg = (struct _message *) l->data;
2019 if (msg->flags == -1 || !MSG_IS_REALLY_DELETED(msg->flags)) {
2020 if (!mbox_write_message(mbox_fp, new_fp, new, msg)) {
2030 if (rename(new, mbox) == -1) {
2031 g_warning(_("can't rename %s to %s\n"), new, mbox);
2032 mbox_unlock_file(new_fp, new);
2034 mbox_unlock_file(mbox_fp, mbox);
2039 if (change_file_mode_rw(new_fp, mbox) < 0) {
2040 FILE_OP_ERROR(new, "chmod");
2041 g_warning(_("can't change file mode\n"));
2044 mbox_unlock_file(new_fp, new);
2048 mbox_unlock_file(mbox_fp, mbox);
2052 debug_print(_("%i messages written - %s\n"), count, mbox);
2054 mbox_cache_synchronize(mbox, FALSE);
2059 #define MAKE_DIR_IF_NOT_EXIST(dir) \
2061 if (!is_dir_exist(dir)) { \
2062 if (is_file_exist(dir)) { \
2063 g_warning(_("File `%s' already exists.\n" \
2064 "Can't create folder."), dir); \
2067 if (mkdir(dir, S_IRWXU) < 0) { \
2068 FILE_OP_ERROR(dir, "mkdir"); \
2071 if (chmod(dir, S_IRWXU) < 0) \
2072 FILE_OP_ERROR(dir, "chmod"); \
2076 gint mbox_create_tree(Folder *folder)
2080 g_return_val_if_fail(folder != NULL, -1);
2082 CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), -1);
2083 rootpath = LOCAL_FOLDER(folder)->rootpath;
2084 MAKE_DIR_IF_NOT_EXIST(rootpath);
2085 CHDIR_RETURN_VAL_IF_FAIL(rootpath, -1);
2090 #undef MAKE_DIR_IF_NOT_EXIST
2092 static gchar * mbox_get_new_path(FolderItem * parent, gchar * name)
2096 if (strchr(name, '/') == NULL) {
2097 if (parent->path != NULL)
2098 path = g_strconcat(parent->path, ".sbd", G_DIR_SEPARATOR_S, name, NULL);
2100 path = g_strdup(name);
2103 path = g_strdup(name);
2108 static gchar * mbox_get_folderitem_name(gchar * name)
2112 foldername = g_strdup(g_basename(name));
2117 FolderItem *mbox_create_folder(Folder *folder, FolderItem *parent,
2121 FolderItem *new_item;
2124 g_return_val_if_fail(folder != NULL, NULL);
2125 g_return_val_if_fail(parent != NULL, NULL);
2126 g_return_val_if_fail(name != NULL, NULL);
2128 path = mbox_get_new_path(parent, (gchar *) name);
2130 foldername = mbox_get_folderitem_name((gchar *) name);
2132 new_item = folder_item_new(foldername, path);
2133 folder_item_append(parent, new_item);
2135 if (!strcmp(name, "inbox")) {
2136 new_item->stype = F_INBOX;
2137 new_item->folder->inbox = new_item;
2138 } else if (!strcmp(name, "outbox")) {
2139 new_item->stype = F_OUTBOX;
2140 new_item->folder->outbox = new_item;
2141 } else if (!strcmp(name, "draft")) {
2142 new_item->stype = F_DRAFT;
2143 new_item->folder->draft = new_item;
2144 } else if (!strcmp(name, "queue")) {
2145 new_item->stype = F_QUEUE;
2146 new_item->folder->queue = new_item;
2147 } else if (!strcmp(name, "trash")) {
2148 new_item->stype = F_TRASH;
2149 new_item->folder->trash = new_item;
2158 gint mbox_rename_folder(Folder *folder, FolderItem *item, const gchar *name)
2163 g_return_val_if_fail(folder != NULL, -1);
2164 g_return_val_if_fail(item != NULL, -1);
2165 g_return_val_if_fail(item->path != NULL, -1);
2166 g_return_val_if_fail(name != NULL, -1);
2168 path = mbox_get_new_path(item->parent, (gchar *) name);
2169 foldername = mbox_get_folderitem_name((gchar *) name);
2171 if (rename(item->path, path) == -1) {
2174 g_warning(_("Cannot rename folder item"));
2182 item->name = foldername;
2188 gint mbox_remove_folder(Folder *folder, FolderItem *item)
2190 g_return_val_if_fail(folder != NULL, -1);
2191 g_return_val_if_fail(item != NULL, -1);
2192 g_return_val_if_fail(item->path != NULL, -1);
2194 folder_item_remove(item);