initial message templates support
[claws.git] / src / mbox_folder.c
blob8c5f7ece91cf393e2fb5f4a768a895284fd7a4f3
1 /*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2001 Hiroyuki Yamamoto & The Sylpheed Claws Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <glib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
29 #include "mbox_folder.h"
30 #include "folder.h"
31 #include "procmsg.h"
32 #include "procheader.h"
33 #include "utils.h"
34 #include "intl.h"
36 #define MSGBUFSIZE 8192
38 static gboolean mbox_write_data(FILE * mbox_fp, FILE * new_fp,
39 gchar * new_filename, gint size);
40 static gboolean mbox_rewrite(gchar * mbox);
41 static gboolean mbox_purge_deleted(gchar * mbox);
42 static gchar * mbox_get_new_path(FolderItem * parent, gchar * name);
43 static gchar * mbox_get_folderitem_name(gchar * name);
47 static gchar * mbox_folder_create_parent(const gchar * path)
49 if (!is_file_exist(path)) {
50 gchar * new_path;
52 new_path = g_dirname(path);
53 if (new_path[strlen(new_path) - 1] == G_DIR_SEPARATOR)
54 new_path[strlen(new_path) - 1] = '\0';
56 if (!is_dir_exist(new_path))
57 make_dir_hier(new_path);
58 g_free(new_path);
64 static gchar *mbox_folder_get_path(FolderItem *item)
66 gchar *folder_path;
67 gchar *path;
69 g_return_val_if_fail(item != NULL, NULL);
71 if (item->path && item->path[0] == G_DIR_SEPARATOR) {
72 mbox_folder_create_parent(item->path);
73 return g_strdup(item->path);
76 folder_path = g_strdup(LOCAL_FOLDER(item->folder)->rootpath);
77 g_return_val_if_fail(folder_path != NULL, NULL);
79 if (folder_path[0] == G_DIR_SEPARATOR) {
80 if (item->path) {
81 path = g_strconcat(folder_path, G_DIR_SEPARATOR_S,
82 item->path, NULL);
84 else
85 path = g_strdup(folder_path);
86 } else {
87 if (item->path)
88 path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
89 folder_path, G_DIR_SEPARATOR_S,
90 item->path, NULL);
91 else
92 path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
93 folder_path, NULL);
96 g_free(folder_path);
98 mbox_folder_create_parent(path);
100 return path;
104 /**********************************************************/
105 /* */
106 /* file lock */
107 /* */
108 /**********************************************************/
111 static GSList * file_lock = NULL;
113 static gboolean mbox_file_lock_file(gchar * base)
115 gchar *lockfile, *locklink;
116 gint retry = 0;
117 FILE *lockfp;
119 lockfile = g_strdup_printf("%s.%d", base, getpid());
120 if ((lockfp = fopen(lockfile, "w")) == NULL) {
121 FILE_OP_ERROR(lockfile, "fopen");
122 g_warning(_("can't create lock file %s\n"), lockfile);
123 g_warning(_("use 'flock' instead of 'file' if possible.\n"));
124 g_free(lockfile);
125 return FALSE;
128 fprintf(lockfp, "%d\n", getpid());
129 fclose(lockfp);
131 locklink = g_strconcat(base, ".lock", NULL);
132 while (link(lockfile, locklink) < 0) {
133 FILE_OP_ERROR(lockfile, "link");
134 if (retry >= 5) {
135 g_warning(_("can't create %s\n"), lockfile);
136 unlink(lockfile);
137 g_free(lockfile);
138 return -1;
140 if (retry == 0)
141 g_warning(_("mailbox is owned by another"
142 " process, waiting...\n"));
143 retry++;
144 sleep(5);
146 unlink(lockfile);
147 g_free(lockfile);
149 return TRUE;
152 static gboolean mbox_fcntl_lockwrite_file(FILE * fp)
154 struct flock lck;
156 lck.l_type = F_WRLCK;
157 lck.l_whence = 0;
158 lck.l_start = 0;
159 lck.l_len = 0;
161 if (fcntl(fileno(fp), F_SETLK, &lck) < 0)
162 return FALSE;
163 else
164 return TRUE;
167 static gboolean mbox_fcntl_lockread_file(FILE * fp)
169 struct flock lck;
171 lck.l_type = F_RDLCK;
172 lck.l_whence = 0;
173 lck.l_start = 0;
174 lck.l_len = 0;
176 if (fcntl(fileno(fp), F_SETLK, &lck) < 0)
177 return FALSE;
178 else
179 return TRUE;
182 static gboolean mbox_fcntl_unlock_file(FILE * fp)
184 struct flock lck;
186 lck.l_type = F_UNLCK;
187 lck.l_whence = 0;
188 lck.l_start = 0;
189 lck.l_len = 0;
191 if (fcntl(fileno(fp), F_SETLK, &lck) < 0)
192 return FALSE;
193 else
194 return TRUE;
197 static gboolean mbox_file_unlock_file(gchar * base)
199 gchar *lockfile;
201 lockfile = g_strdup_printf("%s.lock", base);
202 unlink(lockfile);
203 g_free(lockfile);
205 return TRUE;
208 static gboolean mbox_lockread_file(FILE * fp, gchar * base)
210 gboolean result;
212 result = mbox_fcntl_lockread_file(fp);
213 if (!result) {
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);
218 else
219 g_warning(_("could not lock read file %s\n"), base);
221 else
222 debug_print("fcntl lock %s.\n", base);
224 return result;
227 static gboolean mbox_lockwrite_file(FILE * fp, gchar * base)
229 gboolean result;
231 result = mbox_fcntl_lockwrite_file(fp);
232 if (!result) {
233 if ((result = mbox_file_lock_file(base)) == TRUE) {
234 file_lock = g_slist_append(file_lock, g_strdup(base));
235 debug_print("lockfile lock %s.\n", base);
237 else
238 g_warning(_("could not lock write file %s\n"), base);
240 else
241 debug_print("fcntl lock %s.\n", base);
243 return result;
246 static gboolean mbox_unlock_file(FILE * fp, gchar * base)
248 gboolean result = FALSE;
249 GSList * l;
250 gboolean unlocked = FALSE;
252 for(l = file_lock ; l != NULL ; l = g_slist_next(l)) {
253 gchar * data = l->data;
255 if (strcmp(data, base) == 0) {
256 file_lock = g_slist_remove(file_lock, data);
257 g_free(data);
258 result = mbox_file_unlock_file(base);
259 unlocked = TRUE;
260 debug_print("lockfile unlock - %s.\n", base);
261 break;
265 if (!unlocked) {
266 result = mbox_fcntl_unlock_file(fp);
267 debug_print("fcntl unlock - %s.\n", base);
270 return result;
273 /**********************************************************/
274 /* */
275 /* mbox parsing */
276 /* */
277 /**********************************************************/
279 #define MAILFILE_ERROR_NO_ERROR 0x000
280 #define MAILFILE_ERROR_FILE_NOT_FOUND 0x001
281 #define MAILFILE_ERROR_MEMORY 0x002
282 #define MAILFILE_ERROR_MESSAGE_NOT_FOUND 0x003
284 static int mailfile_error = MAILFILE_ERROR_NO_ERROR;
286 #define STATE_BEGIN 0x000
287 #define STATE_TEXT_READ 0x001
288 #define STATE_FROM_READ 0x002
289 #define STATE_FIELD_READ 0x003
290 #define STATE_END 0x004
291 #define STATE_END_OF_FILE 0x005
292 #define STATE_MEM_ERROR 0x006
293 #define STATE_TEXT_BEGIN 0x007
295 #define STATE_MASK 0x0FF /* filter state from functions */
297 #define STATE_RESTORE_POS 0x100 /* go back while reading */
299 typedef struct _mailfile mailfile;
301 struct _mailfile
303 gint count;
304 gchar * filename;
305 GList * msg_list;
308 struct _message
310 int msgnum;
311 int offset;
312 int header;
313 int content;
314 int end;
315 int marked;
316 gchar * messageid;
317 gchar * fromspace;
318 MsgFlags flags;
319 MsgFlags old_flags;
320 gboolean fetched;
323 #define MSG_IS_INVALID(msg) \
324 ((msg).perm_flags == (msg).tmp_flags && (msg).tmp_flags == -1)
326 #define MSG_SET_INVALID(msg) \
327 ((msg).perm_flags = (msg).tmp_flags = -1)
329 static int startFrom(char * s)
331 return (strncmp(s, "From ", 5) == 0);
334 static int startSpace(char * s)
336 return ((*s == ' ') || (*s == '\t'));
339 static int startEmpty(char * s)
341 return (*s == '\n');
344 static void free_msg_list(GList * l)
346 GList * elt = g_list_first(l);
348 while (elt)
350 g_free(elt->data);
351 elt = g_list_next(elt);
354 g_list_free(l);
358 static mailfile * mailfile_init_from_file(FILE * f, gchar * filename)
360 int state;
361 GList * msg_list = NULL;
362 char * r = NULL;
363 char s[256];
364 int lastpos = 0;
365 int former_pos = 0;
366 int ignore_next = 0;
367 int msgnum = 0;
368 struct _message * data = NULL;
369 mailfile * mf;
371 state = STATE_BEGIN;
374 while (state != STATE_END_OF_FILE) {
375 if ((state & STATE_RESTORE_POS) == 0) {
376 former_pos = lastpos;
377 lastpos = ftell(f);
379 r = fgets(s, 256, f);
381 if (r != NULL && *r)
382 ignore_next = (s[strlen(s) - 1] != '\n');
383 else
384 ignore_next = 0;
387 switch(state & 0x0F) {
388 case STATE_BEGIN:
389 if (r == NULL)
390 state = STATE_END_OF_FILE;
391 else if (startFrom(s)) {
392 state = STATE_FROM_READ;
394 data = g_new0(struct _message, 1);
395 if (data == NULL) {
396 free_msg_list(msg_list);
397 return NULL;
400 msgnum ++;
401 data->msgnum = msgnum;
402 data->offset = lastpos;
403 data->header = lastpos;
404 data->end = 0;
405 data->content = 0;
406 data->messageid = NULL;
407 data->fromspace = NULL;
408 MSG_SET_INVALID(data->flags);
409 MSG_SET_INVALID(data->old_flags);
410 data->fetched = FALSE;
411 msg_list = g_list_append(msg_list,
412 (gpointer) data);
414 else
415 state = STATE_BEGIN;
417 break;
419 case STATE_TEXT_READ:
420 if (r == NULL)
421 state = STATE_END;
422 else if (startFrom(s))
423 state = STATE_END | STATE_RESTORE_POS;
424 else
425 state = STATE_TEXT_READ;
426 break;
428 case STATE_TEXT_BEGIN:
429 data->content = lastpos;
430 if (r == NULL)
431 state = STATE_END;
432 else if (startFrom(s)) {
433 state = STATE_END | STATE_RESTORE_POS;
435 else {
436 state = STATE_TEXT_READ;
438 break;
440 case STATE_FROM_READ:
441 data->content = lastpos;
442 if (r == NULL)
443 state = STATE_END;
444 else if (startSpace(s))
445 state = STATE_FROM_READ;
446 else if (startEmpty(s))
447 state = STATE_TEXT_READ;
448 else
449 state = STATE_FIELD_READ;
450 break;
452 case STATE_FIELD_READ:
453 data->content = lastpos;
454 if (r == NULL)
455 state = STATE_END;
456 else if (startSpace(s))
457 state = STATE_FIELD_READ;
458 else if (startEmpty(s)) {
459 state = STATE_TEXT_BEGIN;
461 else
462 state = STATE_FIELD_READ;
463 break;
466 if ((state & STATE_MASK) == STATE_END) {
467 state = STATE_BEGIN | (state & STATE_RESTORE_POS);
468 data->end = lastpos;
471 if (ignore_next) {
472 do {
473 r = fgets(s, 256, f);
474 if (r == NULL || *r == '\0')
475 break;
477 while (s[strlen(s) - 1] != '\n');
481 mf = (mailfile *) g_new0(struct _mailfile, 1);
482 if (mf == NULL) {
483 free_msg_list(msg_list);
484 mailfile_error = MAILFILE_ERROR_MEMORY;
485 return NULL;
488 mf->msg_list = g_list_first(msg_list);
490 mf->filename = g_strdup(filename);
491 mf->count = msgnum;
493 mailfile_error = MAILFILE_ERROR_NO_ERROR;
495 return mf;
498 static mailfile * mailfile_init(char * filename)
501 FILE * f;
502 mailfile * mf;
504 f = fopen(filename, "r");
506 if (f == NULL) {
507 mailfile_error = MAILFILE_ERROR_FILE_NOT_FOUND;
508 return NULL;
511 mbox_lockread_file(f, filename);
513 mf = mailfile_init_from_file(f, filename);
515 mbox_unlock_file(f, filename);
517 fclose(f);
519 return mf;
522 static void mailfile_done(mailfile * f)
524 free_msg_list(f->msg_list);
525 g_free(f->filename);
527 g_free(f);
531 #define MAX_READ 4096
533 static char * readfile(char * filename, int offset, int max_offset)
535 char * message;
536 int size;
537 int pos;
538 int max;
539 int bread;
540 FILE * handle;
542 handle = fopen(filename, "r");
544 if (handle == NULL) {
545 mailfile_error = MAILFILE_ERROR_FILE_NOT_FOUND;
546 return NULL;
549 size = max_offset - offset;
551 message = (char *) malloc(size + 1);
552 if (message == NULL) {
553 fclose(handle);
554 mailfile_error = MAILFILE_ERROR_MEMORY;
555 return NULL;
558 fseek(handle, offset, SEEK_SET);
560 pos = 0;
561 while (pos < size) {
562 if ((size - pos) > MAX_READ)
563 max = MAX_READ;
564 else
565 max = (size - pos);
567 bread = fread(message + pos, 1, max, handle);
569 if (bread != -1)
570 pos += bread;
572 if (bread < max)
573 break;
576 message[pos] = 0;
578 fclose(handle);
580 return message;
583 static char * mailfile_readmsg(mailfile f, int index)
585 GList * nth;
586 int max_offset;
587 int offset;
588 char * message;
589 struct _message * msginfo;
591 nth = g_list_nth(f->msg_list, index);
593 if (!nth) {
594 mailfile_error = MAILFILE_ERROR_MESSAGE_NOT_FOUND;
595 return NULL;
598 msginfo = (struct _message *)nth->data;
600 offset = msginfo->offset;
601 max_offset = msginfo->end;
602 message = readfile(f->filename, offset, max_offset);
604 mailfile_error = MAILFILE_ERROR_NO_ERROR;
606 return message;
609 static char * mailfile_readheader(mailfile f, int index)
611 GList * nth;
612 int max_offset;
613 int offset;
614 char * message;
615 struct _message * msginfo;
617 nth = g_list_nth(f->msg_list, index);
619 if (!nth) {
620 mailfile_error = MAILFILE_ERROR_MESSAGE_NOT_FOUND;
621 return NULL;
624 msginfo = (struct _message *)nth->data;
626 offset = msginfo->offset;
627 max_offset = msginfo->content;
628 message = readfile(f->filename, offset, max_offset);
630 mailfile_error = MAILFILE_ERROR_NO_ERROR;
632 return message;
635 static int mailfile_count(mailfile * f)
637 return g_list_length(f->msg_list);
640 static int mailfile_find_deleted(mailfile f, char * filename)
642 FILE * handle;
644 handle = fopen(filename, "r");
646 while (elt) {
647 struct _message m = elt->data;
648 n = fread(&m.deleted, sizeof(int), 1, handle);
649 if (!n)
650 break;
651 elt = g_list_next(elt);
654 fclose(handle);
660 /**********************************************************/
661 /* */
662 /* mbox cache operations */
663 /* */
664 /**********************************************************/
666 struct _mboxcache {
667 gchar * filename;
668 mailfile * mf;
669 GPtrArray * tab_mf;
670 gint mtime;
671 gboolean modification;
674 typedef struct _mboxcache mboxcache;
676 static GHashTable * mbox_cache_table = NULL;
678 static MsgInfo *mbox_parse_msg(FILE * fp, struct _message * msg,
679 FolderItem *item)
681 MsgInfo *msginfo;
682 MsgFlags flags = { 0, 0 };
684 MSG_SET_PERM_FLAGS(flags, MSG_NEW | MSG_UNREAD);
686 g_return_val_if_fail(fp != NULL, NULL);
688 if (item != NULL) {
689 if (item->stype == F_QUEUE) {
690 MSG_SET_TMP_FLAGS(flags, MSG_QUEUED);
691 } else if (item->stype == F_DRAFT) {
692 MSG_SET_TMP_FLAGS(flags, MSG_DRAFT);
696 msginfo = procheader_file_parse(fp, flags, FALSE);
698 if (!msginfo) return NULL;
700 if (item != NULL) {
701 msginfo->msgnum = msg->msgnum;
702 msginfo->folder = item;
705 return msginfo;
708 static void mbox_cache_init()
710 mbox_cache_table = g_hash_table_new(g_str_hash, g_str_equal);
713 static void mbox_cache_done()
715 g_hash_table_destroy(mbox_cache_table);
718 static void mbox_cache_free_mbox(mboxcache * cache)
720 g_hash_table_remove(mbox_cache_table, cache->filename);
722 if (cache->mf)
723 mailfile_done(cache->mf);
724 if (cache->tab_mf)
725 g_ptr_array_free(cache->tab_mf, FALSE);
726 if (cache->filename)
727 g_free(cache->filename);
728 g_free(cache);
731 static void mbox_cache_get_msginfo_from_file(FILE * fp, GList * msg_list)
733 GList * l;
734 MsgInfo * msginfo;
736 for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
737 struct _message * msg;
739 msg = (struct _message *) l->data;
741 fseek(fp, msg->header, SEEK_SET);
742 msginfo = mbox_parse_msg(fp, msg, NULL);
743 if (msginfo) {
744 if (msginfo->msgid)
745 msg->messageid =
746 g_strdup(msginfo->msgid);
747 if (msginfo->fromspace)
748 msg->fromspace =
749 g_strdup(msginfo->fromspace);
750 msg->flags = msginfo->flags;
751 msg->old_flags = msginfo->flags;
753 procmsg_msginfo_free(msginfo);
758 static void mbox_cache_get_msginfo(gchar * filename, GList * msg_list)
760 FILE * fp;
762 fp = fopen(filename, "r");
763 if (fp == NULL)
764 return;
766 mbox_cache_get_msginfo_from_file(fp, msg_list);
767 fclose(fp);
770 static mboxcache * mbox_cache_read_mbox(gchar * filename)
772 mboxcache * cache;
773 struct stat s;
774 mailfile * mf;
775 GList * l;
777 if (stat(filename, &s) < 0)
778 return NULL;
780 mf = mailfile_init(filename);
781 if (mf == NULL)
782 return NULL;
784 cache = g_new0(mboxcache, 1);
786 cache->mtime = s.st_mtime;
787 cache->mf = mf;
788 cache->filename = g_strdup(filename);
789 cache->modification = FALSE;
791 cache->tab_mf = g_ptr_array_new();
792 for(l = mf->msg_list ; l != NULL ; l = g_list_next(l))
793 g_ptr_array_add(cache->tab_mf, l->data);
795 mbox_cache_get_msginfo(filename, mf->msg_list);
797 debug_print(_("read mbox - %s\n"), filename);
799 return cache;
802 static mboxcache * mbox_cache_read_mbox_from_file(FILE * fp, gchar * filename)
804 mboxcache * cache;
805 struct stat s;
806 mailfile * mf;
807 GList * l;
809 if (stat(filename, &s) < 0)
810 return NULL;
812 mf = mailfile_init_from_file(fp, filename);
813 if (mf == NULL)
814 return NULL;
816 cache = g_new0(mboxcache, 1);
818 cache->mtime = s.st_mtime;
819 cache->mf = mf;
820 cache->filename = g_strdup(filename);
822 cache->tab_mf = g_ptr_array_new();
823 for(l = mf->msg_list ; l != NULL ; l = g_list_next(l))
824 g_ptr_array_add(cache->tab_mf, l->data);
826 mbox_cache_get_msginfo_from_file(fp, mf->msg_list);
828 debug_print(_("read mbox from file - %s\n"), filename);
830 return cache;
833 static void mbox_cache_insert_mbox(mboxcache * data)
835 if (mbox_cache_table == NULL)
836 mbox_cache_init();
838 g_hash_table_insert(mbox_cache_table, data->filename, data);
841 static mboxcache * mbox_cache_get_mbox(gchar * filename)
843 if (mbox_cache_table == NULL)
844 mbox_cache_init();
846 return g_hash_table_lookup(mbox_cache_table, filename);
850 static gint mbox_cache_get_count(gchar * filename)
852 mboxcache * cache;
854 cache = mbox_cache_get_mbox(filename);
855 if (cache == NULL)
856 return -1;
857 if (cache->mf == NULL)
858 return -1;
859 return cache->mf->count;
862 static gint mbox_cache_get_mtime(gchar * filename)
864 mboxcache * cache;
866 cache = mbox_cache_get_mbox(filename);
867 if (cache == NULL)
868 return -1;
869 return cache->mtime;
872 static GList * mbox_cache_get_msg_list(gchar * filename)
874 mboxcache * cache;
876 cache = mbox_cache_get_mbox(filename);
878 if (cache == NULL)
879 return NULL;
881 if (cache->mf == NULL)
882 return NULL;
884 return cache->mf->msg_list;
887 static void mbox_cache_synchronize_lists(GList * old_msg_list,
888 GList * new_msg_list)
890 GList * l;
891 GList * l2;
893 for(l2 = old_msg_list ; l2 != NULL ; l2 = g_list_next(l2)) {
894 struct _message * msg2 = l2->data;
896 if ((msg2->messageid == NULL) ||
897 (msg2->fromspace == NULL))
898 continue;
900 for(l = new_msg_list ; l != NULL ; l = g_list_next(l)) {
901 struct _message * msg = l->data;
903 if ((msg->messageid == NULL) ||
904 (msg->fromspace == NULL))
905 continue;
907 if ((strcmp(msg->messageid, msg2->messageid) == 0) &&
908 (strcmp(msg->fromspace, msg2->fromspace) == 0)) {
909 if (msg2->flags.perm_flags != msg2->old_flags.perm_flags) {
910 msg->flags = msg2->flags;
911 break;
918 static void mbox_cache_synchronize(gchar * filename, gboolean sync)
920 mboxcache * new_cache;
921 mboxcache * old_cache;
922 gboolean scan_new = TRUE;
923 struct stat s;
925 old_cache = mbox_cache_get_mbox(filename);
927 if (old_cache != NULL) {
928 if (stat(filename, &s) < 0) {
929 FILE_OP_ERROR(filename, "stat");
930 } else if (old_cache->mtime == s.st_mtime) {
931 debug_print("Folder is not modified.\n");
932 scan_new = FALSE;
936 if (scan_new) {
937 GList * l;
940 if (strstr(filename, "trash") == 0)
941 printf("old_cache: %p %s\n", old_cache, filename);
942 if (old_cache) {
943 printf("begin old\n");
944 for(l = old_cache->mf->msg_list ; l != NULL ;
945 l = g_list_next(l)) {
946 struct _message * msg = l->data;
947 printf("%p\n", msg);
949 printf("end old\n");
953 new_cache = mbox_cache_read_mbox(filename);
956 if (strstr(filename, "trash") == 0)
957 printf("new_cache: %p %s\n", new_cache, filename);
958 if (new_cache) {
959 printf("begin new\n");
960 for(l = new_cache->mf->msg_list ; l != NULL ;
961 l = g_list_next(l)) {
962 struct _message * msg = l->data;
963 printf("%p\n", msg);
965 printf("end new\n");
969 if (!new_cache)
970 return;
972 if (sync && new_cache && old_cache)
973 mbox_cache_synchronize_lists(old_cache->mf->msg_list,
974 new_cache->mf->msg_list);
976 if (old_cache != NULL)
977 mbox_cache_free_mbox(old_cache);
979 if (new_cache) {
980 mbox_cache_insert_mbox(new_cache);
982 printf("insert %p %s\n", new_cache, new_cache->filename);
983 printf("inserted %s %p\n", filename,
984 mbox_cache_get_mbox(filename));
990 static void mbox_cache_synchronize_from_file(FILE * fp, gchar * filename,
991 gboolean sync)
993 mboxcache * new_cache;
994 mboxcache * old_cache;
995 gboolean scan_new = TRUE;
996 struct stat s;
998 old_cache = mbox_cache_get_mbox(filename);
1000 if (old_cache != NULL) {
1001 if (stat(filename, &s) < 0) {
1002 FILE_OP_ERROR(filename, "stat");
1003 } else if (old_cache->mtime == s.st_mtime) {
1004 debug_print("Folder is not modified.\n");
1005 scan_new = FALSE;
1010 if (scan_new) {
1013 GList * l;
1015 if (strstr(filename, "trash") == 0)
1016 printf("old_cache: %p %s\n", old_cache, filename);
1018 if (old_cache) {
1019 printf("begin old\n");
1020 for(l = old_cache->mf->msg_list ; l != NULL ;
1021 l = g_list_next(l)) {
1022 struct _message * msg = l->data;
1023 printf("%p\n", msg);
1025 printf("end old\n");
1029 new_cache = mbox_cache_read_mbox_from_file(fp, filename);
1032 if (strstr(filename, "trash") == 0)
1033 printf("new_cache: %p %s\n", new_cache, filename);
1035 if (new_cache) {
1036 printf("begin new\n");
1037 for(l = new_cache->mf->msg_list ; l != NULL ;
1038 l = g_list_next(l)) {
1039 struct _message * msg = l->data;
1040 printf("%p\n", msg);
1042 printf("end new\n");
1046 if (!new_cache)
1047 return;
1049 if (sync && new_cache && old_cache)
1050 mbox_cache_synchronize_lists(old_cache->mf->msg_list,
1051 new_cache->mf->msg_list);
1053 if (old_cache != NULL)
1054 mbox_cache_free_mbox(old_cache);
1056 if (new_cache) {
1057 mbox_cache_insert_mbox(new_cache);
1059 printf("insert %p %s\n", new_cache, new_cache->filename);
1060 printf("inserted %s %p\n", filename,
1061 mbox_cache_get_mbox(filename));
1067 gboolean mbox_cache_msg_fetched(gchar * filename, gint num)
1069 struct _message * msg;
1070 mboxcache * cache;
1072 cache = mbox_cache_get_mbox(filename);
1074 if (cache == NULL)
1075 return FALSE;
1077 msg = (struct _message *) g_ptr_array_index(cache->tab_mf,
1078 num - 1);
1079 if (msg == NULL)
1080 return FALSE;
1082 return msg->fetched;
1085 void mbox_cache_msg_set_fetched(gchar * filename, gint num)
1087 struct _message * msg;
1088 mboxcache * cache;
1090 cache = mbox_cache_get_mbox(filename);
1092 if (cache == NULL)
1093 return;
1095 msg = (struct _message *) g_ptr_array_index(cache->tab_mf,
1096 num - 1);
1097 if (msg == NULL)
1098 return;
1100 msg->fetched = TRUE;
1103 struct _message * mbox_cache_get_msg(gchar * filename, gint num)
1105 mboxcache * cache;
1107 cache = mbox_cache_get_mbox(filename);
1109 if (cache == NULL) {
1110 return NULL;
1113 return (struct _message *) g_ptr_array_index(cache->tab_mf,
1114 num - 1);
1118 /**********************************************************/
1119 /* */
1120 /* mbox operations */
1121 /* */
1122 /**********************************************************/
1125 GSList *mbox_get_msg_list(Folder *folder, FolderItem *item, gboolean use_cache)
1127 GSList *mlist;
1128 MsgInfo * msginfo;
1129 GList * l;
1130 FILE * fp;
1131 gchar * mbox_path;
1133 #ifdef MEASURE_TIME
1134 struct timeval tv_before, tv_after, tv_result;
1136 gettimeofday(&tv_before, NULL);
1137 #endif
1139 mlist = NULL;
1141 mbox_path = mbox_folder_get_path(item);
1143 if (mbox_path == NULL)
1144 return NULL;
1146 mbox_purge_deleted(mbox_path);
1148 fp = fopen(mbox_path, "r");
1150 if (fp == NULL) {
1151 g_free(mbox_path);
1152 return NULL;
1155 mbox_lockread_file(fp, mbox_path);
1157 mbox_cache_synchronize_from_file(fp, mbox_path, TRUE);
1159 item->last_num = mbox_cache_get_count(mbox_path);
1161 for(l = mbox_cache_get_msg_list(mbox_path) ; l != NULL ;
1162 l = g_list_next(l)) {
1163 struct _message * msg;
1165 msg = (struct _message *) l->data;
1167 if (MSG_IS_INVALID(msg->flags) || !MSG_IS_REALLY_DELETED(msg->flags)) {
1168 fseek(fp, msg->header, SEEK_SET);
1170 msginfo = mbox_parse_msg(fp, msg, item);
1172 if (!MSG_IS_INVALID(msg->flags))
1173 msginfo->flags = msg->flags;
1174 else {
1175 msg->old_flags = msginfo->flags;
1176 msg->flags = msginfo->flags;
1179 mlist = g_slist_append(mlist, msginfo);
1181 else {
1182 MSG_SET_PERM_FLAGS(msg->flags, MSG_REALLY_DELETED);
1186 mbox_unlock_file(fp, mbox_path);
1188 g_free(mbox_path);
1190 fclose(fp);
1192 #ifdef MEASURE_TIME
1193 gettimeofday(&tv_after, NULL);
1195 timersub(&tv_after, &tv_before, &tv_result);
1196 g_print("mbox_get_msg_list: %s: elapsed time: %ld.%06ld sec\n",
1197 mbox_path, tv_result.tv_sec, tv_result.tv_usec);
1198 #endif
1200 return mlist;
1203 static gboolean mbox_extract_msg(FolderItem * item, gint msgnum,
1204 gchar * dest_filename)
1206 struct _message * msg;
1207 gint offset;
1208 gint max_offset;
1209 gint size;
1210 FILE * src;
1211 FILE * dest;
1212 gboolean err;
1213 /* GList * msg_list;*/
1214 gboolean already_fetched;
1215 gchar * mbox_path;
1217 mbox_path = mbox_folder_get_path(item);
1219 if (mbox_path == NULL)
1220 return FALSE;
1222 src = fopen(mbox_path, "r");
1223 if (src == NULL) {
1224 g_free(mbox_path);
1225 return FALSE;
1228 mbox_lockread_file(src, mbox_path);
1230 mbox_cache_synchronize_from_file(src, mbox_path, TRUE);
1232 already_fetched = mbox_cache_msg_fetched(mbox_path, msgnum);
1234 if (already_fetched) {
1235 mbox_unlock_file(src, mbox_path);
1236 fclose(src);
1237 g_free(mbox_path);
1238 return TRUE;
1241 msg = mbox_cache_get_msg(mbox_path, msgnum);
1243 if (msg == NULL) {
1244 mbox_unlock_file(src, mbox_path);
1245 fclose(src);
1246 g_free(mbox_path);
1247 return FALSE;
1250 offset = msg->offset;
1251 max_offset = msg->end;
1253 size = max_offset - offset;
1255 fseek(src, offset, SEEK_SET);
1257 dest = fopen(dest_filename, "w");
1258 if (dest == NULL) {
1259 mbox_unlock_file(src, mbox_path);
1260 fclose(src);
1261 g_free(mbox_path);
1262 return FALSE;
1265 if (change_file_mode_rw(dest, dest_filename) < 0) {
1266 FILE_OP_ERROR(dest_filename, "chmod");
1267 g_warning(_("can't change file mode\n"));
1270 if (!mbox_write_data(src, dest, dest_filename, size)) {
1271 mbox_unlock_file(src, mbox_path);
1272 fclose(dest);
1273 fclose(src);
1274 unlink(dest_filename);
1275 g_free(mbox_path);
1276 return FALSE;
1279 err = FALSE;
1281 if (ferror(src)) {
1282 FILE_OP_ERROR(mbox_path, "fread");
1283 err = TRUE;
1286 mbox_cache_msg_set_fetched(mbox_path, msgnum);
1288 if (fclose(dest) == -1) {
1289 FILE_OP_ERROR(dest_filename, "fclose");
1290 err = TRUE;
1293 mbox_unlock_file(src, mbox_path);
1295 if (fclose(src) == -1) {
1296 FILE_OP_ERROR(mbox_path, "fclose");
1297 err = TRUE;
1300 g_free(mbox_path);
1302 if (err) {
1303 unlink(dest_filename);
1304 return FALSE;
1307 return TRUE;
1310 gchar *mbox_fetch_msg(Folder *folder, FolderItem *item, gint num)
1312 gchar *path;
1313 gchar *filename;
1315 g_return_val_if_fail(item != NULL, NULL);
1316 g_return_val_if_fail(num > 0 && num <= item->last_num, NULL);
1318 path = folder_item_get_path(item);
1319 if (!is_dir_exist(path))
1320 make_dir_hier(path);
1322 filename = g_strconcat(path, G_DIR_SEPARATOR_S, itos(num), NULL);
1324 g_free(path);
1326 if (!mbox_extract_msg(item, num, filename)) {
1327 g_free(filename);
1328 return NULL;
1331 return filename;
1334 gint mbox_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
1335 gboolean remove_source)
1337 FILE * src_fp;
1338 FILE * dest_fp;
1339 gchar buf[BUFSIZ];
1340 gint old_size;
1341 gint n_read;
1342 gboolean err;
1343 gchar * mbox_path;
1344 gchar from_line[MSGBUFSIZE];
1346 if (dest->last_num < 0) {
1347 mbox_scan_folder(folder, dest);
1348 if (dest->last_num < 0) return -1;
1351 src_fp = fopen(file, "r");
1352 if (src_fp == NULL) {
1353 return -1;
1356 mbox_path = mbox_folder_get_path(dest);
1357 if (mbox_path == NULL)
1358 return -1;
1360 dest_fp = fopen(mbox_path, "a");
1361 if (dest_fp == NULL) {
1362 fclose(src_fp);
1363 g_free(mbox_path);
1364 return -1;
1367 if (change_file_mode_rw(dest_fp, mbox_path) < 0) {
1368 FILE_OP_ERROR(mbox_path, "chmod");
1369 g_warning(_("can't change file mode\n"));
1372 old_size = ftell(dest_fp);
1374 mbox_lockwrite_file(dest_fp, mbox_path);
1376 if (fgets(from_line, sizeof(from_line), src_fp) == NULL) {
1377 mbox_unlock_file(dest_fp, mbox_path);
1378 g_warning(_("unvalid file - %s.\n"), file);
1379 fclose(dest_fp);
1380 fclose(src_fp);
1381 g_free(mbox_path);
1382 return -1;
1385 if (strncmp(from_line, "From ", 5) != 0) {
1386 struct stat s;
1388 if (stat(file, &s) < 0) {
1389 mbox_unlock_file(dest_fp, mbox_path);
1390 g_warning(_("unvalid file - %s.\n"), file);
1391 fclose(dest_fp);
1392 fclose(src_fp);
1393 g_free(mbox_path);
1394 return -1;
1397 fprintf(dest_fp, "From - %s", ctime(&s.st_mtime));
1400 fputs(from_line, dest_fp);
1402 while (1) {
1403 n_read = fread(buf, 1, sizeof(buf), src_fp);
1404 if ((n_read < (gint) sizeof(buf)) && ferror(src_fp))
1405 break;
1406 if (fwrite(buf, n_read, 1, dest_fp) < 1) {
1407 mbox_unlock_file(dest_fp, mbox_path);
1408 g_warning(_("writing to %s failed.\n"), mbox_path);
1409 ftruncate(fileno(dest_fp), old_size);
1410 fclose(dest_fp);
1411 fclose(src_fp);
1412 g_free(mbox_path);
1413 return -1;
1416 if (n_read < (gint) sizeof(buf))
1417 break;
1420 err = FALSE;
1422 if (ferror(src_fp)) {
1423 FILE_OP_ERROR(mbox_path, "fread");
1426 mbox_unlock_file(dest_fp, mbox_path);
1428 if (fclose(src_fp) == -1) {
1429 FILE_OP_ERROR(file, "fclose");
1430 err = TRUE;
1433 if (fclose(dest_fp) == -1) {
1434 FILE_OP_ERROR(mbox_path, "fclose");
1435 g_free(mbox_path);
1436 return -1;
1439 if (err) {
1440 ftruncate(fileno(dest_fp), old_size);
1441 g_free(mbox_path);
1442 return -1;
1445 if (remove_source) {
1446 if (unlink(file) < 0)
1447 FILE_OP_ERROR(file, "unlink");
1450 g_free(mbox_path);
1452 dest->last_num++;
1453 return dest->last_num;
1457 gint mbox_remove_msg(Folder *folder, FolderItem *item, gint num)
1459 struct _message * msg;
1460 gchar * mbox_path;
1462 mbox_path = mbox_folder_get_path(item);
1463 if (mbox_path == NULL)
1464 return -1;
1466 mbox_cache_synchronize(mbox_path, TRUE);
1468 msg = mbox_cache_get_msg(mbox_path, num);
1470 g_free(mbox_path);
1472 if (msg != NULL)
1473 MSG_SET_PERM_FLAGS(msg->flags, MSG_REALLY_DELETED);
1475 return 0;
1478 gint mbox_remove_all_msg(Folder *folder, FolderItem *item)
1480 FILE * fp;
1481 gchar * mbox_path;
1483 mbox_path = mbox_folder_get_path(item);
1484 if (mbox_path == NULL)
1485 return -1;
1487 fp = fopen(mbox_path, "w");
1488 if (fp == NULL) {
1489 g_free(mbox_path);
1490 return -1;
1493 fclose(fp);
1495 g_free(mbox_path);
1497 return 0;
1501 gint mbox_move_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
1503 gchar * filename;
1504 gint msgnum;
1506 filename = mbox_fetch_msg(folder, msginfo->folder, msginfo->msgnum);
1507 if (filename == NULL)
1508 return -1;
1510 msgnum = mbox_add_msg(folder, dest, filename, TRUE);
1512 if (msgnum != -1) {
1513 MSG_SET_FLAGS(msginfo->flags, MSG_REALLY_DELETED);
1514 mbox_change_flags(folder, msginfo->folder, msginfo);
1517 return msgnum;
1520 gint mbox_move_msgs_with_dest(Folder *folder, FolderItem *dest, GSList *msglist)
1522 GSList * l;
1523 gchar * mbox_path = NULL;
1525 for(l = msglist ; l != NULL ; l = g_slist_next(l)) {
1526 MsgInfo * msginfo = (MsgInfo *) l->data;
1528 if (msginfo->folder && mbox_path == NULL)
1529 mbox_path = mbox_folder_get_path(msginfo->folder);
1531 mbox_move_msg(folder, dest, msginfo);
1534 if (mbox_path) {
1535 mbox_cache_synchronize(mbox_path);
1536 g_free(mbox_path);
1539 mbox_path = mbox_folder_get_path(dest);
1540 mbox_cache_synchronize(mbox_path);
1541 g_free(mbox_path);
1543 return dest->last_num;
1548 gint mbox_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
1550 gchar * filename;
1551 gint msgnum;
1553 filename = mbox_fetch_msg(folder, msginfo->folder, msginfo->msgnum);
1554 if (filename == NULL)
1555 return -1;
1557 msgnum = mbox_add_msg(folder, dest, filename, FALSE);
1559 return msgnum;
1562 gint mbox_copy_msgs_with_dest(Folder *folder, FolderItem *dest, GSList *msglist)
1564 GSList * l;
1565 gchar * mbox_path = NULL;
1567 for(l = msglist ; l != NULL ; l = g_slist_next(l)) {
1568 MsgInfo * msginfo = (MsgInfo *) l->data;
1570 if (msginfo->folder && mbox_path == NULL)
1571 mbox_path = mbox_folder_get_path(msginfo->folder);
1573 mbox_copy_msg(folder, dest, msginfo);
1576 if (mbox_path) {
1577 mbox_cache_synchronize(mbox_path);
1578 g_free(mbox_path);
1581 mbox_path = mbox_folder_get_path(dest);
1582 mbox_cache_synchronize(mbox_path);
1583 g_free(mbox_path);
1585 return dest->last_num;
1589 struct _copy_flags_info
1591 gint num;
1592 MsgFlags flags;
1595 typedef struct _copy_flags_info CopyFlagsInfo;
1597 GSList * copy_flags_data = NULL;
1599 gint mbox_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
1601 Folder * src_folder;
1602 gchar * filename;
1603 gint num;
1604 gchar * destdir;
1605 gchar * mbox_path;
1606 struct _message * msg;
1607 CopyFlagsInfo * flags_info;
1609 src_folder = msginfo->folder->folder;
1611 g_return_val_if_fail(src_folder->fetch_msg != NULL, -1);
1614 mbox_path = mbox_folder_get_path(msginfo->folder);
1615 mbox_rewrite(mbox_path);
1616 g_free(mbox_path);
1619 filename = src_folder->fetch_msg(src_folder,
1620 msginfo->folder,
1621 msginfo->msgnum);
1622 if (filename == NULL)
1623 return -1;
1625 num = folder->add_msg(folder, dest, filename, FALSE);
1628 mbox_path = mbox_folder_get_path(dest);
1629 msg = mbox_cache_get_msg(mbox_path, num);
1630 if (msg != NULL)
1631 msg->flags = msginfo->flags;
1632 g_free(mbox_path);
1635 if (num == -1)
1636 return -1;
1638 flags_info = g_new0(CopyFlagsInfo, 1);
1639 flags_info->num = num;
1640 flags_info->flags = msginfo->flags;
1641 copy_flags_data = g_slist_append(copy_flags_data, flags_info);
1643 return num;
1646 void mbox_finished_copy(Folder *folder, FolderItem *dest)
1648 gchar * mbox_path;
1649 GSList * l;
1650 mboxcache * cache;
1652 mbox_path = mbox_folder_get_path(dest);
1653 if (mbox_path == NULL)
1654 return;
1656 mbox_cache_synchronize(mbox_path, TRUE);
1658 for(l = copy_flags_data ; l != NULL ; l = g_slist_next(l)) {
1659 CopyFlagsInfo * flags_info = l->data;
1660 struct _message * msg;
1662 msg = mbox_cache_get_msg(mbox_path, flags_info->num);
1663 if (msg != NULL)
1664 msg->flags = flags_info->flags;
1665 g_free(flags_info);
1668 if (copy_flags_data != NULL) {
1669 cache = mbox_cache_get_mbox(mbox_path);
1670 cache->modification = TRUE;
1673 g_slist_free(copy_flags_data);
1674 copy_flags_data = NULL;
1676 mbox_rewrite(mbox_path);
1678 g_free(mbox_path);
1681 void mbox_scan_folder(Folder *folder, FolderItem *item)
1683 gchar *mbox_path;
1684 gint n_msg;
1685 mboxcache * cached;
1686 GList * l;
1688 mbox_path = mbox_folder_get_path(item);
1689 if (mbox_path == NULL)
1690 return;
1692 mbox_cache_synchronize(mbox_path, TRUE);
1694 cached = mbox_cache_get_mbox(mbox_path);
1696 if (cached == NULL) {
1697 item->new = 0;
1698 item->unread = 0;
1699 item->total = 0;
1700 item->last_num = 0;
1701 g_free(mbox_path);
1702 return;
1705 n_msg = mbox_cache_get_count(mbox_path);
1707 if (n_msg == 0) {
1708 item->new = item->unread = item->total = 0;
1710 else {
1711 gint new = 0;
1712 gint unread = 0;
1713 gint total = 0;
1715 for(l = mbox_cache_get_msg_list(mbox_path) ; l != NULL ;
1716 l = g_list_next(l)) {
1717 struct _message * msg = (struct _message *) l->data;
1718 if (!MSG_IS_REALLY_DELETED(msg->flags))
1719 total ++;
1720 if (MSG_IS_NEW(msg->flags) /*&& !MSG_IS_IGNORE_THREAD(msg->flags)*/)
1721 new ++;
1722 if (MSG_IS_UNREAD(msg->flags) /*&& !MSG_IS_IGNORE_THREAD(msg->flags)*/)
1723 unread ++;
1726 item->new = new;
1727 item->unread = unread;
1728 item->total = total;
1731 debug_print(_("Last number in dir %s = %d\n"), mbox_path,
1732 item->total);
1733 item->last_num = n_msg;
1734 g_free(mbox_path);
1737 gchar * mbox_get_virtual_path(FolderItem * item)
1739 if (item == NULL)
1740 return NULL;
1742 if (item->parent == NULL) {
1743 return NULL;
1745 else {
1746 gchar * parent_path;
1747 gchar * result_path;
1749 parent_path = mbox_get_virtual_path(item->parent);
1750 if (parent_path == NULL)
1751 result_path = g_strdup(item->name);
1752 else
1753 result_path = g_strconcat(parent_path,
1754 G_DIR_SEPARATOR_S,
1755 item->name, NULL);
1756 g_free(parent_path);
1758 return result_path;
1762 static gboolean mbox_write_data(FILE * mbox_fp, FILE * new_fp,
1763 gchar * new_filename, gint size)
1765 gint n_read;
1766 gint pos;
1767 gchar buf[BUFSIZ];
1768 gint max;
1770 pos = 0;
1771 while (pos < size) {
1772 if ((size - pos) > (gint) sizeof(buf))
1773 max = sizeof(buf);
1774 else
1775 max = (size - pos);
1777 n_read = fread(buf, 1, max, mbox_fp);
1779 if (n_read < max && ferror(mbox_fp)) {
1780 return FALSE;
1782 if (fwrite(buf, n_read, 1, new_fp) < 1) {
1783 g_warning(_("writing to %s failed.\n"), new_filename);
1784 return FALSE;
1787 if (n_read != -1)
1788 pos += n_read;
1790 if (n_read < max)
1791 break;
1793 return TRUE;
1796 static gboolean mbox_write_message(FILE * mbox_fp, FILE * new_fp,
1797 gchar * new_filename,
1798 struct _message * msg)
1800 gint size;
1801 GPtrArray * headers;
1802 gint i;
1804 fseek(mbox_fp, msg->header, SEEK_SET);
1806 headers = procheader_get_header_array_asis(mbox_fp);
1808 for (i = 0; i < (gint) headers->len; i++) {
1809 Header * h = g_ptr_array_index(headers, i);
1811 if (!procheader_headername_equal(h->name,
1812 "Status") &&
1813 !procheader_headername_equal(h->name,
1814 "X-Status")) {
1815 fwrite(h->name, strlen(h->name),
1816 1, new_fp);
1817 if (h->name[strlen(h->name) - 1] != ' ')
1818 fwrite(" ", 1, 1, new_fp);
1819 fwrite(h->body, strlen(h->body),
1820 1, new_fp);
1821 fwrite("\n", 1, 1, new_fp);
1823 procheader_header_free(h);
1824 g_ptr_array_remove_index(headers, i);
1825 i--;
1828 g_ptr_array_free(headers, FALSE);
1830 if (!MSG_IS_INVALID(msg->flags)) {
1831 /* Status header */
1832 fwrite("Status: ", strlen("Status: "), 1, new_fp);
1833 if (!MSG_IS_UNREAD(msg->flags))
1834 fwrite("R", 1, 1, new_fp);
1835 fwrite("O", 1, 1, new_fp);
1836 fwrite("\n", 1, 1, new_fp);
1838 /* X-Status header */
1839 if (MSG_IS_REALLY_DELETED(msg->flags)
1840 || MSG_IS_MARKED(msg->flags)
1841 || MSG_IS_DELETED(msg->flags)
1842 || MSG_IS_REPLIED(msg->flags)
1843 || MSG_IS_FORWARDED(msg->flags)) {
1844 fwrite("X-Status: ", strlen("X-Status: "), 1, new_fp);
1845 if (MSG_IS_REALLY_DELETED(msg->flags))
1846 fwrite("D", 1, 1, new_fp); /* really deleted */
1847 else {
1848 if (MSG_IS_MARKED(msg->flags))
1849 fwrite("F", 1, 1, new_fp);
1850 if (MSG_IS_DELETED(msg->flags))
1851 fwrite("d", 1, 1, new_fp);
1852 if (MSG_IS_REPLIED(msg->flags))
1853 fwrite("r", 1, 1, new_fp);
1854 if (MSG_IS_FORWARDED(msg->flags))
1855 fwrite("f", 1, 1, new_fp);
1857 fwrite("\n", 1, 1, new_fp);
1861 fwrite("\n", 1, 1, new_fp);
1863 size = msg->end - msg->content;
1864 fseek(mbox_fp, msg->content, SEEK_SET);
1866 return mbox_write_data(mbox_fp, new_fp, new_filename, size);
1869 void mbox_update_mark(Folder * folder, FolderItem * item)
1871 gchar * mbox_path;
1873 mbox_path = mbox_folder_get_path(item);
1874 if (mbox_path == NULL)
1875 return;
1877 mbox_rewrite(mbox_path);
1878 g_free(mbox_path);
1881 void mbox_change_flags(Folder * folder, FolderItem * item, MsgInfo * info)
1883 struct _message * msg;
1884 mboxcache * cache;
1885 gchar * mbox_path;
1887 mbox_path = mbox_folder_get_path(item);
1888 if (mbox_path == NULL)
1889 return;
1891 msg = mbox_cache_get_msg(mbox_path, info->msgnum);
1893 cache = mbox_cache_get_mbox(mbox_path);
1895 g_free(mbox_path);
1897 if ((msg == NULL) || (cache == NULL))
1898 return;
1900 msg->flags = info->flags;
1902 cache->modification = TRUE;
1906 static gboolean mbox_rewrite(gchar * mbox)
1908 FILE * mbox_fp;
1909 FILE * new_fp;
1910 gchar * new;
1911 GList * l;
1912 gboolean result;
1913 GList * msg_list;
1914 gint count;
1915 mboxcache * cache;
1917 msg_list = mbox_cache_get_msg_list(mbox);
1919 cache = mbox_cache_get_mbox(mbox);
1920 if (cache == NULL)
1921 return FALSE;
1923 if (!cache->modification) {
1924 debug_print(_("no modification - %s\n"), mbox);
1925 return FALSE;
1928 debug_print(_("save modification - %s\n"), mbox);
1930 mbox_fp = fopen(mbox, "r+");
1931 mbox_lockwrite_file(mbox_fp, mbox);
1933 mbox_cache_synchronize_from_file(mbox_fp, mbox, TRUE);
1935 new = g_strconcat(mbox, ".", itos((int) mbox), NULL);
1936 new_fp = fopen(new, "w");
1938 if (change_file_mode_rw(new_fp, new) < 0) {
1939 FILE_OP_ERROR(new, "chmod");
1940 g_warning(_("can't change file mode\n"));
1943 mbox_lockwrite_file(new_fp, new);
1945 result = TRUE;
1947 count = 0;
1948 msg_list = mbox_cache_get_msg_list(mbox);
1949 for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
1950 struct _message * msg = (struct _message *) l->data;
1951 if (!mbox_write_message(mbox_fp, new_fp, new, msg)) {
1952 result = FALSE;
1953 break;
1955 count ++;
1958 unlink(mbox);
1960 if (rename(new, mbox) == -1) {
1961 g_warning(_("can't rename %s to %s\n"), new, mbox);
1962 mbox_unlock_file(new_fp, new);
1963 fclose(new_fp);
1964 mbox_unlock_file(mbox_fp, mbox);
1965 fclose(mbox_fp);
1966 return -1;
1969 if (change_file_mode_rw(new_fp, mbox) < 0) {
1970 FILE_OP_ERROR(new, "chmod");
1971 g_warning(_("can't change file mode\n"));
1974 mbox_unlock_file(new_fp, new);
1976 fclose(new_fp);
1978 mbox_unlock_file(mbox_fp, mbox);
1980 fclose(mbox_fp);
1982 debug_print(_("%i messages written - %s\n"), count, mbox);
1984 cache = mbox_cache_get_mbox(mbox);
1986 if (cache != NULL)
1987 cache->mtime = -1;
1989 mbox_cache_synchronize(mbox, FALSE);
1991 return result;
1994 static gboolean mbox_purge_deleted(gchar * mbox)
1996 FILE * mbox_fp;
1997 FILE * new_fp;
1998 gchar * new;
1999 GList * l;
2000 gboolean result;
2001 gboolean modification = FALSE;
2002 GList * msg_list;
2003 gint count;
2005 mbox_cache_synchronize(mbox, TRUE);
2007 msg_list = mbox_cache_get_msg_list(mbox);
2009 for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
2010 struct _message * msg = (struct _message *) l->data;
2011 if (MSG_IS_INVALID(msg->flags) && MSG_IS_REALLY_DELETED(msg->flags)) {
2012 modification = TRUE;
2013 break;
2017 if (!modification) {
2018 debug_print(_("no deleted messages - %s\n"), mbox);
2019 return FALSE;
2022 debug_print(_("purge deleted messages - %s\n"), mbox);
2024 mbox_fp = fopen(mbox, "r+");
2025 mbox_lockwrite_file(mbox_fp, mbox);
2027 mbox_cache_synchronize_from_file(mbox_fp, mbox, TRUE);
2029 new = g_strconcat(mbox, ".", itos((int) mbox), NULL);
2030 new_fp = fopen(new, "w");
2032 if (change_file_mode_rw(new_fp, new) < 0) {
2033 FILE_OP_ERROR(new, "chmod");
2034 g_warning(_("can't change file mode\n"));
2037 mbox_lockwrite_file(new_fp, new);
2039 result = TRUE;
2041 count = 0;
2042 msg_list = mbox_cache_get_msg_list(mbox);
2043 for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
2044 struct _message * msg = (struct _message *) l->data;
2045 if (MSG_IS_INVALID(msg->flags) || !MSG_IS_REALLY_DELETED(msg->flags)) {
2046 if (!mbox_write_message(mbox_fp, new_fp, new, msg)) {
2047 result = FALSE;
2048 break;
2050 count ++;
2054 unlink(mbox);
2056 if (rename(new, mbox) == -1) {
2057 g_warning(_("can't rename %s to %s\n"), new, mbox);
2058 mbox_unlock_file(new_fp, new);
2059 fclose(new_fp);
2060 mbox_unlock_file(mbox_fp, mbox);
2061 fclose(mbox_fp);
2062 return -1;
2065 if (change_file_mode_rw(new_fp, mbox) < 0) {
2066 FILE_OP_ERROR(new, "chmod");
2067 g_warning(_("can't change file mode\n"));
2070 mbox_unlock_file(new_fp, new);
2072 fclose(new_fp);
2074 mbox_unlock_file(mbox_fp, mbox);
2076 fclose(mbox_fp);
2078 debug_print(_("%i messages written - %s\n"), count, mbox);
2080 mbox_cache_synchronize(mbox, FALSE);
2082 return result;
2085 #define MAKE_DIR_IF_NOT_EXIST(dir) \
2087 if (!is_dir_exist(dir)) { \
2088 if (is_file_exist(dir)) { \
2089 g_warning(_("File `%s' already exists.\n" \
2090 "Can't create folder."), dir); \
2091 return -1; \
2093 if (mkdir(dir, S_IRWXU) < 0) { \
2094 FILE_OP_ERROR(dir, "mkdir"); \
2095 return -1; \
2097 if (chmod(dir, S_IRWXU) < 0) \
2098 FILE_OP_ERROR(dir, "chmod"); \
2102 gint mbox_create_tree(Folder *folder)
2104 gchar *rootpath;
2106 g_return_val_if_fail(folder != NULL, -1);
2108 CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), -1);
2109 rootpath = LOCAL_FOLDER(folder)->rootpath;
2110 MAKE_DIR_IF_NOT_EXIST(rootpath);
2111 CHDIR_RETURN_VAL_IF_FAIL(rootpath, -1);
2113 return 0;
2116 #undef MAKE_DIR_IF_NOT_EXIST
2118 static gchar * mbox_get_new_path(FolderItem * parent, gchar * name)
2120 gchar * path;
2122 if (strchr(name, '/') == NULL) {
2123 if (parent->path != NULL)
2124 path = g_strconcat(parent->path, ".sbd", G_DIR_SEPARATOR_S, name, NULL);
2125 else
2126 path = g_strdup(name);
2128 else
2129 path = g_strdup(name);
2131 return path;
2134 static gchar * mbox_get_folderitem_name(gchar * name)
2136 gchar * foldername;
2138 foldername = g_strdup(g_basename(name));
2140 return foldername;
2143 FolderItem *mbox_create_folder(Folder *folder, FolderItem *parent,
2144 const gchar *name)
2146 gchar * path;
2147 FolderItem *new_item;
2148 gchar * foldername;
2150 g_return_val_if_fail(folder != NULL, NULL);
2151 g_return_val_if_fail(parent != NULL, NULL);
2152 g_return_val_if_fail(name != NULL, NULL);
2154 path = mbox_get_new_path(parent, (gchar *) name);
2156 foldername = mbox_get_folderitem_name((gchar *) name);
2158 new_item = folder_item_new(foldername, path);
2159 folder_item_append(parent, new_item);
2161 if (!strcmp(name, "inbox")) {
2162 new_item->stype = F_INBOX;
2163 new_item->folder->inbox = new_item;
2164 } else if (!strcmp(name, "outbox")) {
2165 new_item->stype = F_OUTBOX;
2166 new_item->folder->outbox = new_item;
2167 } else if (!strcmp(name, "draft")) {
2168 new_item->stype = F_DRAFT;
2169 new_item->folder->draft = new_item;
2170 } else if (!strcmp(name, "queue")) {
2171 new_item->stype = F_QUEUE;
2172 new_item->folder->queue = new_item;
2173 } else if (!strcmp(name, "trash")) {
2174 new_item->stype = F_TRASH;
2175 new_item->folder->trash = new_item;
2178 g_free(foldername);
2179 g_free(path);
2181 return new_item;
2184 gint mbox_rename_folder(Folder *folder, FolderItem *item, const gchar *name)
2186 gchar * path;
2187 gchar * foldername;
2189 g_return_val_if_fail(folder != NULL, -1);
2190 g_return_val_if_fail(item != NULL, -1);
2191 g_return_val_if_fail(item->path != NULL, -1);
2192 g_return_val_if_fail(name != NULL, -1);
2194 path = mbox_get_new_path(item->parent, (gchar *) name);
2195 foldername = mbox_get_folderitem_name((gchar *) name);
2197 if (rename(item->path, path) == -1) {
2198 g_free(foldername);
2199 g_free(path);
2200 g_warning(_("Cannot rename folder item"));
2202 return -1;
2204 else {
2205 g_free(item->name);
2206 g_free(item->path);
2207 item->path = path;
2208 item->name = foldername;
2210 return 0;
2214 gint mbox_remove_folder(Folder *folder, FolderItem *item)
2216 g_return_val_if_fail(folder != NULL, -1);
2217 g_return_val_if_fail(item != NULL, -1);
2218 g_return_val_if_fail(item->path != NULL, -1);
2220 folder_item_remove(item);
2221 return 0;