000b9285e31dc35c6057eb9d934bf2a24b6a8ceb
[claws.git] / src / mbox_folder.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2001 Hiroyuki Yamamoto & The Sylpheed Claws Team
4  *
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.
9  *
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.
14  *
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.
18  */
19
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>
28
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"
35
36 #define MSGBUFSIZE      8192
37
38 static void     mbox_folder_init                (Folder         *folder,
39                                                  const gchar    *name,
40                                                  const gchar    *path);
41
42 static gboolean mbox_write_data(FILE * mbox_fp, FILE * new_fp,
43                                 gchar * new_filename, gint size);
44 static gboolean mbox_rewrite(gchar * mbox);
45 static gboolean mbox_purge_deleted(gchar * mbox);
46 static gchar * mbox_get_new_path(FolderItem * parent, gchar * name);
47 static gchar * mbox_get_folderitem_name(gchar * name);
48
49 MsgInfo *mbox_fetch_msginfo(Folder *folder, FolderItem *item, gint num);
50 gint mbox_get_num_list(Folder *folder, FolderItem *item, GSList **list);
51 gboolean mbox_check_msgnum_validity(Folder *folder, FolderItem *item);
52
53 Folder *mbox_folder_new(const gchar *name, const gchar *path)
54 {
55         Folder *folder;
56
57         folder = (Folder *)g_new0(MBOXFolder, 1);
58         mbox_folder_init(folder, name, path);
59
60         return folder;
61 }
62
63 void mbox_folder_destroy(MBOXFolder *folder)
64 {
65         folder_local_folder_destroy(LOCAL_FOLDER(folder));
66 }
67
68 static void mbox_folder_init(Folder *folder, const gchar *name, const gchar *path)
69 {
70         folder->type = F_MBOX;
71
72         folder_local_folder_init(folder, name, path);
73
74 /*
75         folder->get_msg_list        = mbox_get_msg_list;
76 */
77         folder->fetch_msg           = mbox_fetch_msg;
78         folder->fetch_msginfo       = mbox_fetch_msginfo;
79         folder->add_msg             = mbox_add_msg;
80         folder->copy_msg            = mbox_copy_msg;
81         folder->remove_msg          = mbox_remove_msg;
82         folder->remove_all_msg      = mbox_remove_all_msg;
83 /*
84         folder->scan                = mbox_scan_folder;
85 */
86         folder->get_num_list        = mbox_get_num_list;
87         folder->create_tree         = mbox_create_tree;
88         folder->create_folder       = mbox_create_folder;
89         folder->rename_folder       = mbox_rename_folder;
90         folder->remove_folder       = mbox_remove_folder;
91         folder->check_msgnum_validity
92                                     = mbox_check_msgnum_validity;
93 }
94
95 static void mbox_folder_create_parent(const gchar * path)
96 {
97         if (!is_file_exist(path)) {
98                 gchar * new_path;
99
100                 new_path = g_dirname(path);
101                 if (new_path[strlen(new_path) - 1] == G_DIR_SEPARATOR)
102                         new_path[strlen(new_path) - 1] = '\0';
103
104                 if (!is_dir_exist(new_path))
105                         make_dir_hier(new_path);
106                 g_free(new_path);
107                 
108         }
109 }
110
111
112 static gchar *mbox_folder_get_path(FolderItem *item)
113 {
114         gchar *folder_path;
115         gchar *path;
116
117         g_return_val_if_fail(item != NULL, NULL);
118
119         if (item->path && item->path[0] == G_DIR_SEPARATOR) {
120                 mbox_folder_create_parent(item->path);
121                 return g_strdup(item->path);
122         }
123
124         folder_path = g_strdup(LOCAL_FOLDER(item->folder)->rootpath);
125         g_return_val_if_fail(folder_path != NULL, NULL);
126
127         if (folder_path[0] == G_DIR_SEPARATOR) {
128                 if (item->path) {
129                         path = g_strconcat(folder_path, G_DIR_SEPARATOR_S,
130                                            item->path, NULL);
131                 }
132                 else
133                         path = g_strdup(folder_path);
134         } else {
135                 if (item->path)
136                         path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
137                                            folder_path, G_DIR_SEPARATOR_S,
138                                            item->path, NULL);
139                 else
140                         path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
141                                            folder_path, NULL);
142         }
143
144         g_free(folder_path);
145         
146         mbox_folder_create_parent(path);
147
148         return path;
149 }
150
151
152 /**********************************************************/
153 /*                                                        */
154 /*                   file lock                            */
155 /*                                                        */
156 /**********************************************************/
157
158
159 static GSList * file_lock = NULL;
160
161 static gboolean mbox_file_lock_file(gchar * base)
162 {
163         gchar *lockfile, *locklink;
164         gint retry = 0;
165         FILE *lockfp;
166
167         lockfile = g_strdup_printf("%s.%d", base, getpid());
168         if ((lockfp = fopen(lockfile, "wb")) == NULL) {
169                 FILE_OP_ERROR(lockfile, "fopen");
170                 g_warning(_("can't create lock file %s\n"), lockfile);
171                 g_warning(_("use 'flock' instead of 'file' if possible.\n"));
172                 g_free(lockfile);
173                 return FALSE;
174         }
175         
176         fprintf(lockfp, "%d\n", getpid());
177         fclose(lockfp);
178         
179         locklink = g_strconcat(base, ".lock", NULL);
180         while (link(lockfile, locklink) < 0) {
181                 FILE_OP_ERROR(lockfile, "link");
182                 if (retry >= 5) {
183                         g_warning(_("can't create %s\n"), lockfile);
184                         unlink(lockfile);
185                         g_free(lockfile);
186                         g_free(locklink);
187                         return -1;
188                 }
189                 if (retry == 0)
190                         g_warning(_("mailbox is owned by another"
191                                     " process, waiting...\n"));
192                 retry++;
193                 sleep(5);
194         }
195         unlink(lockfile);
196         g_free(lockfile);
197         g_free(locklink);
198         
199         return TRUE;
200 }
201
202 static gboolean mbox_fcntl_lockwrite_file(FILE * fp)
203 {
204         struct flock lck;
205
206         lck.l_type = F_WRLCK;
207         lck.l_whence = 0;
208         lck.l_start = 0;
209         lck.l_len = 0;
210         
211         if (fcntl(fileno(fp), F_SETLK, &lck) < 0)
212                 return FALSE;
213         else
214                 return TRUE;
215 }
216
217 static gboolean mbox_fcntl_lockread_file(FILE * fp)
218 {
219         struct flock lck;
220
221         lck.l_type = F_RDLCK;
222         lck.l_whence = 0;
223         lck.l_start = 0;
224         lck.l_len = 0;
225         
226         if (fcntl(fileno(fp), F_SETLK, &lck) < 0)
227                 return FALSE;
228         else
229                 return TRUE;
230 }
231
232 static gboolean mbox_fcntl_unlock_file(FILE * fp)
233 {
234         struct flock lck;
235
236         lck.l_type = F_UNLCK;
237         lck.l_whence = 0;
238         lck.l_start = 0;
239         lck.l_len = 0;
240         
241         if (fcntl(fileno(fp), F_SETLK, &lck) < 0)
242                 return FALSE;
243         else
244                 return TRUE;
245 }
246
247 static gboolean mbox_file_unlock_file(gchar * base)
248 {
249         gchar *lockfile;
250
251         lockfile = g_strdup_printf("%s.lock", base);
252         unlink(lockfile);
253         g_free(lockfile);
254
255         return TRUE;
256 }
257
258 static gboolean mbox_lockread_file(FILE * fp, gchar * base)
259 {
260         gboolean result;
261
262         result = mbox_fcntl_lockread_file(fp);
263         if (!result) {
264                 if ((result = mbox_file_lock_file(base)) == TRUE) {
265                         file_lock = g_slist_append(file_lock, g_strdup(base));
266                         debug_print("lockfile lock %s.\n", base);
267                 }
268                 else
269                         g_warning(_("could not lock read file %s\n"), base);
270         }
271         else
272                 debug_print("fcntl lock %s.\n", base);
273
274         return result;
275 }
276
277 static gboolean mbox_lockwrite_file(FILE * fp, gchar * base)
278 {
279         gboolean result;
280
281         result = mbox_fcntl_lockwrite_file(fp);
282         if (!result) {
283                 if ((result = mbox_file_lock_file(base)) == TRUE) {
284                         file_lock = g_slist_append(file_lock, g_strdup(base));
285                         debug_print("lockfile lock %s.\n", base);
286                 }
287                 else
288                         g_warning(_("could not lock write file %s\n"), base);
289         }
290         else
291                 debug_print("fcntl lock %s.\n", base);
292
293         return result;
294 }
295
296 static gboolean mbox_unlock_file(FILE * fp, gchar * base)
297 {
298         gboolean result = FALSE;
299         GSList * l;
300         gboolean unlocked = FALSE;
301
302         for(l = file_lock ; l != NULL ; l = g_slist_next(l)) {
303                 gchar * data = l->data;
304
305                 if (strcmp(data, base) == 0) {
306                         file_lock = g_slist_remove(file_lock, data);
307                         g_free(data);
308                         result = mbox_file_unlock_file(base);
309                         unlocked = TRUE;
310                         debug_print("lockfile unlock - %s.\n", base);
311                         break;
312                 }
313         }
314         
315         if (!unlocked) {
316                 result = mbox_fcntl_unlock_file(fp);
317                 debug_print("fcntl unlock - %s.\n", base);
318         }
319
320         return result;
321 }
322
323 /**********************************************************/
324 /*                                                        */
325 /*                   mbox parsing                         */
326 /*                                                        */
327 /**********************************************************/
328
329 #define MAILFILE_ERROR_NO_ERROR          0x000
330 #define MAILFILE_ERROR_FILE_NOT_FOUND    0x001
331 #define MAILFILE_ERROR_MEMORY            0x002
332 #define MAILFILE_ERROR_MESSAGE_NOT_FOUND 0x003
333
334 static int mailfile_error = MAILFILE_ERROR_NO_ERROR;
335
336 #define STATE_BEGIN       0x000
337 #define STATE_TEXT_READ   0x001
338 #define STATE_FROM_READ   0x002
339 #define STATE_FIELD_READ  0x003
340 #define STATE_END         0x004
341 #define STATE_END_OF_FILE 0x005
342 #define STATE_MEM_ERROR   0x006
343 #define STATE_TEXT_BEGIN  0x007
344
345 #define STATE_MASK        0x0FF /* filter state from functions */
346
347 #define STATE_RESTORE_POS       0x100 /* go back while reading */
348
349 typedef struct _mailfile mailfile;
350
351 struct _mailfile
352 {
353         gint count;
354         gchar * filename;
355         GList * msg_list;
356 };
357
358 struct _message
359 {
360         int msgnum;
361         int offset;
362         int header;
363         int content;
364         int end;
365         int marked;
366         gchar * messageid;
367         gchar * fromspace;
368         MsgFlags flags;
369         MsgFlags old_flags;
370         gboolean fetched;
371 };
372
373 #define MSG_IS_INVALID(msg) \
374         ((msg).perm_flags == (msg).tmp_flags && (msg).tmp_flags == -1)
375
376 #define MSG_SET_INVALID(msg) \
377         ((msg).perm_flags = (msg).tmp_flags = -1)
378
379 static int startFrom(char * s)
380 {
381         return (strncmp(s, "From ", 5) == 0);
382 }
383
384 static int startSpace(char * s)
385 {
386         return ((*s == ' ') || (*s == '\t'));
387 }
388
389 static int startEmpty(char * s)
390 {
391         return (*s == '\n');
392 }
393
394 static void free_msg_list(GList * l)
395 {
396         GList * elt = g_list_first(l);
397
398         while (elt)
399                 {
400                         g_free(elt->data);
401                         elt = g_list_next(elt);
402                 }
403
404         g_list_free(l);
405 }
406
407
408 static mailfile * mailfile_init_from_file(FILE * f, gchar * filename)
409 {
410         int state;
411         GList * msg_list = NULL;
412         char * r = NULL;
413         char s[256];
414         int lastpos = 0;
415         int former_pos = 0;
416         int ignore_next = 0;
417         int msgnum = 0;
418         struct _message * data = NULL;
419         mailfile * mf;
420
421         state = STATE_BEGIN;
422
423
424         while (state != STATE_END_OF_FILE) {
425                 if ((state & STATE_RESTORE_POS) == 0) {
426                         former_pos = lastpos;
427                         lastpos = ftell(f);
428
429                         r = fgets(s, 256, f);
430
431                         if (r != NULL && *r)
432                                 ignore_next = (s[strlen(s) - 1] != '\n');
433                         else
434                                 ignore_next = 0;
435                 }
436
437                 switch(state & 0x0F) {
438                 case STATE_BEGIN:
439                         if (r == NULL)
440                                 state = STATE_END_OF_FILE;
441                         else if (startFrom(s)) {
442                                 state = STATE_FROM_READ;
443
444                                 data = g_new0(struct _message, 1);
445                                 if (data == NULL) {
446                                         free_msg_list(msg_list);
447                                         return NULL;
448                                 }
449                                 
450                                 msgnum ++;
451                                 data->msgnum = msgnum;
452                                 data->offset = lastpos;
453                                 data->header = lastpos;
454                                 data->end = 0;
455                                 data->content = 0;
456                                 data->messageid = NULL;
457                                 data->fromspace = NULL;
458                                 MSG_SET_INVALID(data->flags);
459                                 MSG_SET_INVALID(data->old_flags);
460                                 data->fetched = FALSE;
461                                 msg_list = g_list_append(msg_list,
462                                                          (gpointer) data);
463                         }
464                         else
465                                 state = STATE_BEGIN;
466
467                         break;
468
469                 case STATE_TEXT_READ:
470                         if (r == NULL)
471                                 state = STATE_END;
472                         else if (startFrom(s))
473                                 state = STATE_END | STATE_RESTORE_POS;
474                         else
475                                 state = STATE_TEXT_READ;
476                         break;
477
478                 case STATE_TEXT_BEGIN:
479                         data->content = lastpos;
480                         if (r == NULL)
481                                 state = STATE_END;
482                         else if (startFrom(s)) {
483                                 state = STATE_END | STATE_RESTORE_POS;
484                         }
485                         else {
486                                 state = STATE_TEXT_READ;
487                         }
488                         break;
489           
490                 case STATE_FROM_READ:
491                         data->content = lastpos;
492                         if (r == NULL)
493                                 state = STATE_END;
494                         else if (startSpace(s))
495                                 state = STATE_FROM_READ;
496                         else if (startEmpty(s))
497                                 state = STATE_TEXT_READ;
498                         else
499                                 state = STATE_FIELD_READ;
500                         break;
501           
502                 case STATE_FIELD_READ:
503                         data->content = lastpos;
504                         if (r == NULL)
505                                 state = STATE_END;
506                         else if (startSpace(s))
507                                 state = STATE_FIELD_READ;
508                         else if (startEmpty(s)) {
509                                 state = STATE_TEXT_BEGIN;
510                         }
511                         else
512                                 state = STATE_FIELD_READ;
513                         break;
514                 }
515       
516                 if ((state & STATE_MASK) == STATE_END) {
517                         state = STATE_BEGIN | (state & STATE_RESTORE_POS);
518                         data->end = lastpos;
519                 }
520
521                 if (ignore_next) {
522                         do {
523                                 r = fgets(s, 256, f);
524                                 if (r == NULL || *r == '\0')
525                                         break;
526                         }
527                         while (s[strlen(s) - 1] != '\n');
528                 }
529         }
530
531         mf = (mailfile *) g_new0(struct _mailfile, 1);
532         if (mf == NULL) {
533                 free_msg_list(msg_list);
534                 mailfile_error = MAILFILE_ERROR_MEMORY;
535                 return NULL;
536         }
537
538         mf->msg_list = g_list_first(msg_list);
539
540         mf->filename = g_strdup(filename);
541         mf->count = msgnum;
542
543         mailfile_error = MAILFILE_ERROR_NO_ERROR;
544         
545         return mf;
546 }
547
548 static mailfile * mailfile_init(char * filename)
549 {
550
551         FILE * f;
552         mailfile * mf;
553   
554         f = fopen(filename, "rb");
555
556         if (f == NULL) {
557                 mailfile_error = MAILFILE_ERROR_FILE_NOT_FOUND;
558                 return NULL;
559         }
560
561         mbox_lockread_file(f, filename);
562
563         mf = mailfile_init_from_file(f, filename);
564
565         mbox_unlock_file(f, filename);
566
567         fclose(f);
568
569         return mf;
570 }
571
572 static void mailfile_done(mailfile * f)
573 {
574         free_msg_list(f->msg_list);
575         g_free(f->filename);
576
577         g_free(f);
578 }
579
580 /*
581 #define MAX_READ 4096
582
583 static char * readfile(char * filename, int offset, int max_offset)
584 {
585         char * message;
586         int size;
587         int pos;
588         int max;
589         int bread;
590         FILE * handle;
591
592         handle = fopen(filename, "rb");
593
594         if (handle == NULL) {
595                 mailfile_error = MAILFILE_ERROR_FILE_NOT_FOUND;
596                 return NULL;
597         }
598
599         size = max_offset - offset;
600
601         message = (char *) malloc(size + 1);
602         if (message == NULL) {
603                 fclose(handle);
604                 mailfile_error = MAILFILE_ERROR_MEMORY;
605                 return NULL;
606         }
607
608         fseek(handle, offset, SEEK_SET);
609
610         pos = 0;
611         while (pos < size) {
612                 if ((size - pos) > MAX_READ)
613                         max = MAX_READ;
614                 else
615                         max = (size - pos);
616
617                 bread = fread(message + pos, 1, max, handle);
618
619                 if (bread != -1)
620                         pos += bread;
621
622                 if (bread < max)
623                         break;
624         }
625
626         message[pos] = 0;
627
628         fclose(handle);
629
630         return message;
631 }
632
633 static char * mailfile_readmsg(mailfile f, int index)
634 {
635         GList * nth;
636         int max_offset;
637         int offset;
638         char * message;
639         struct _message * msginfo;
640
641         nth = g_list_nth(f->msg_list, index);
642
643         if (!nth) {
644                 mailfile_error = MAILFILE_ERROR_MESSAGE_NOT_FOUND;
645                 return NULL;
646         }
647
648         msginfo = (struct _message *)nth->data;
649
650         offset = msginfo->offset;
651         max_offset = msginfo->end;
652         message = readfile(f->filename, offset, max_offset);
653
654         mailfile_error = MAILFILE_ERROR_NO_ERROR;
655
656         return message;
657 }
658
659 static char * mailfile_readheader(mailfile f, int index)
660 {
661         GList * nth;
662         int max_offset;
663         int offset;
664         char * message;
665         struct _message * msginfo;
666
667         nth = g_list_nth(f->msg_list, index);
668
669         if (!nth) {
670                 mailfile_error = MAILFILE_ERROR_MESSAGE_NOT_FOUND;
671                 return NULL;
672         }
673
674         msginfo = (struct _message *)nth->data;
675
676         offset = msginfo->offset;
677         max_offset = msginfo->content;
678         message = readfile(f->filename, offset, max_offset);
679
680         mailfile_error = MAILFILE_ERROR_NO_ERROR;
681
682         return message;
683 }
684
685 static int mailfile_count(mailfile * f)
686 {
687         return g_list_length(f->msg_list);
688 }
689
690 static int mailfile_find_deleted(mailfile f, char * filename)
691 {
692         FILE * handle;
693
694         handle = fopen(filename, "rb");
695
696         while (elt) {
697                 struct _message m = elt->data;
698                 n = fread(&m.deleted, sizeof(int), 1, handle);
699                 if (!n)
700                         break;
701                 elt = g_list_next(elt);
702         }
703
704         fclose(handle);
705 }
706 */
707
708
709
710 /**********************************************************/
711 /*                                                        */
712 /*                   mbox cache operations                */
713 /*                                                        */
714 /**********************************************************/
715
716 struct _mboxcache {
717         gchar * filename;
718         mailfile * mf;
719         GPtrArray * tab_mf;
720         gint mtime;
721         gboolean modification;
722 };
723
724 typedef struct _mboxcache mboxcache;
725
726 static GHashTable * mbox_cache_table = NULL;
727
728 static MsgInfo *mbox_parse_msg(FILE * fp, struct _message * msg,
729                                FolderItem *item)
730 {
731         MsgInfo *msginfo;
732         MsgFlags flags = { 0, 0 };
733
734         MSG_SET_PERM_FLAGS(flags, MSG_NEW | MSG_UNREAD);
735
736         g_return_val_if_fail(fp != NULL, NULL);
737
738         if (item != NULL) {
739                 if (item->stype == F_QUEUE) {
740                         MSG_SET_TMP_FLAGS(flags, MSG_QUEUED);
741                 } else if (item->stype == F_DRAFT) {
742                         MSG_SET_TMP_FLAGS(flags, MSG_DRAFT);
743                 }
744         }
745
746         msginfo = procheader_parse_stream(fp, flags, FALSE, FALSE);
747
748         if (!msginfo) return NULL;
749
750         if (item != NULL) {
751                 msginfo->msgnum = msg->msgnum;
752                 msginfo->folder = item;
753         }
754
755         return msginfo;
756 }
757
758 static void mbox_cache_init()
759 {
760         mbox_cache_table = g_hash_table_new(g_str_hash, g_str_equal);
761 }
762
763 static void mbox_cache_free_mbox(mboxcache * cache)
764 {
765         g_hash_table_remove(mbox_cache_table, cache->filename);
766
767         if (cache->mf)
768                 mailfile_done(cache->mf);
769         if (cache->tab_mf)
770                 g_ptr_array_free(cache->tab_mf, FALSE);
771         if (cache->filename)
772                 g_free(cache->filename);
773         g_free(cache);
774 }
775
776 static void mbox_cache_get_msginfo_from_file(FILE * fp, GList * msg_list)
777 {
778         GList * l;
779         MsgInfo * msginfo;
780
781         for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
782                 struct _message * msg;
783
784                 msg = (struct _message *) l->data;
785
786                 fseek(fp, msg->header, SEEK_SET);
787                 msginfo = mbox_parse_msg(fp, msg, NULL);
788                 if (msginfo) {
789                         if (msginfo->msgid)
790                                 msg->messageid =
791                                         g_strdup(msginfo->msgid);
792                         if (msginfo->fromspace)
793                                 msg->fromspace =
794                                         g_strdup(msginfo->fromspace);
795                         msg->flags = msginfo->flags;
796                         msg->old_flags = msginfo->flags;
797
798                         procmsg_msginfo_free(msginfo);
799                 }
800         }
801 }
802
803 static void mbox_cache_get_msginfo(gchar * filename, GList * msg_list)
804 {
805         FILE * fp;
806
807         fp = fopen(filename, "rb");
808         if (fp == NULL)
809                 return;
810
811         mbox_cache_get_msginfo_from_file(fp, msg_list);
812         fclose(fp);
813 }
814
815 static mboxcache * mbox_cache_read_mbox(gchar * filename)
816 {
817         mboxcache * cache;
818         struct stat s;
819         mailfile * mf;
820         GList * l;
821
822         if (stat(filename, &s) < 0)
823                 return NULL;
824
825         mf = mailfile_init(filename);
826         if (mf == NULL)
827                 return NULL;
828
829         cache = g_new0(mboxcache, 1);
830
831         cache->mtime = s.st_mtime;
832         cache->mf = mf;
833         cache->filename = g_strdup(filename);
834         cache->modification = FALSE;
835
836         cache->tab_mf = g_ptr_array_new();
837         for(l = mf->msg_list ; l != NULL ; l = g_list_next(l))
838                 g_ptr_array_add(cache->tab_mf, l->data);
839
840         mbox_cache_get_msginfo(filename, mf->msg_list);
841
842         debug_print("read mbox - %s\n", filename);
843
844         return cache;
845 }
846
847 static mboxcache * mbox_cache_read_mbox_from_file(FILE * fp, gchar * filename)
848 {
849         mboxcache * cache;
850         struct stat s;
851         mailfile * mf;
852         GList * l;
853
854         if (stat(filename, &s) < 0)
855                 return NULL;
856
857         mf = mailfile_init_from_file(fp, filename);
858         if (mf == NULL)
859                 return NULL;
860
861         cache = g_new0(mboxcache, 1);
862
863         cache->mtime = s.st_mtime;
864         cache->mf = mf;
865         cache->filename = g_strdup(filename);
866
867         cache->tab_mf = g_ptr_array_new();
868         for(l = mf->msg_list ; l != NULL ; l = g_list_next(l))
869                 g_ptr_array_add(cache->tab_mf, l->data);
870
871         mbox_cache_get_msginfo_from_file(fp, mf->msg_list);
872
873         debug_print("read mbox from file - %s\n", filename);
874
875         return cache;
876 }
877
878 static void mbox_cache_insert_mbox(mboxcache * data)
879 {
880         if (mbox_cache_table == NULL)
881                 mbox_cache_init();
882
883         g_hash_table_insert(mbox_cache_table, data->filename, data);
884 }
885
886 static mboxcache * mbox_cache_get_mbox(gchar * filename)
887 {
888         if (mbox_cache_table == NULL)
889                 mbox_cache_init();
890
891         return g_hash_table_lookup(mbox_cache_table, filename);
892 }
893
894
895 static gint mbox_cache_get_count(gchar * filename)
896 {
897         mboxcache * cache;
898
899         cache = mbox_cache_get_mbox(filename);
900         if (cache == NULL)
901                 return -1;
902         if (cache->mf == NULL)
903                 return -1;
904         return cache->mf->count;
905 }
906
907 static GList * mbox_cache_get_msg_list(gchar * filename)
908 {
909         mboxcache * cache;
910
911         cache = mbox_cache_get_mbox(filename);
912
913         if (cache == NULL)
914                 return NULL;
915
916         if (cache->mf == NULL)
917                 return NULL;
918
919         return cache->mf->msg_list;
920 }
921
922 static void mbox_cache_synchronize_lists(GList * old_msg_list,
923                                          GList * new_msg_list)
924 {
925         GList * l;
926         GList * l2;
927
928         for(l2 = old_msg_list ; l2 != NULL ; l2 = g_list_next(l2)) {
929                 struct _message * msg2 = l2->data;
930
931                 if ((msg2->messageid == NULL) ||
932                     (msg2->fromspace == NULL))
933                         continue;
934
935                 for(l = new_msg_list ; l != NULL ; l = g_list_next(l)) {
936                         struct _message * msg = l->data;
937                         
938                         if ((msg->messageid == NULL) ||
939                             (msg->fromspace == NULL))
940                                 continue;
941
942                         if ((strcmp(msg->messageid, msg2->messageid) == 0) &&
943                             (strcmp(msg->fromspace, msg2->fromspace) == 0)) {
944                                 if (msg2->flags.perm_flags != msg2->old_flags.perm_flags) {
945                                         msg->flags = msg2->flags;
946                                         break;
947                                 }
948                         }
949                 }
950         }
951 }
952
953 static void mbox_cache_synchronize(gchar * filename, gboolean sync)
954 {
955         mboxcache * new_cache;
956         mboxcache * old_cache;
957         gboolean scan_new = TRUE;
958         struct stat s;
959
960         old_cache = mbox_cache_get_mbox(filename);
961
962         if (old_cache != NULL) {
963                 if (stat(filename, &s) < 0) {
964                         FILE_OP_ERROR(filename, "stat");
965                 } else if (old_cache->mtime == s.st_mtime) {
966                         debug_print("Folder is not modified.\n");
967                         scan_new = FALSE;
968                 }
969         }
970
971         if (scan_new) {
972                 /*              
973                 if (strstr(filename, "trash") == 0)
974                         printf("old_cache: %p %s\n", old_cache, filename);
975                         if (old_cache) {
976                                 printf("begin old\n");
977                                 for(l = old_cache->mf->msg_list ; l != NULL ;
978                                     l = g_list_next(l)) {
979                                         struct _message * msg = l->data;
980                                         printf("%p\n", msg);
981                                 }
982                                 printf("end old\n");
983                         }
984                 */              
985
986                 new_cache = mbox_cache_read_mbox(filename);
987
988                 /*
989                 if (strstr(filename, "trash") == 0) 
990                         printf("new_cache: %p %s\n", new_cache, filename);
991                         if (new_cache) {
992                                 printf("begin new\n");
993                                 for(l = new_cache->mf->msg_list ; l != NULL ;
994                                     l = g_list_next(l)) {
995                                         struct _message * msg = l->data;
996                                         printf("%p\n", msg);
997                                 }
998                                 printf("end new\n");
999                         }
1000                 */
1001
1002                 if (!new_cache)
1003                         return;
1004
1005                 if (sync && new_cache && old_cache)
1006                         mbox_cache_synchronize_lists(old_cache->mf->msg_list,
1007                                                      new_cache->mf->msg_list);
1008
1009                 if (old_cache != NULL)
1010                         mbox_cache_free_mbox(old_cache);
1011
1012                 if (new_cache) {
1013                         mbox_cache_insert_mbox(new_cache);
1014                         /*
1015                         printf("insert %p %s\n", new_cache, new_cache->filename);
1016                         printf("inserted %s %p\n", filename,
1017                                mbox_cache_get_mbox(filename));
1018                         */
1019                 }
1020         }
1021 }
1022
1023 static void mbox_cache_synchronize_from_file(FILE * fp, gchar * filename,
1024                                              gboolean sync)
1025 {
1026         mboxcache * new_cache;
1027         mboxcache * old_cache;
1028         gboolean scan_new = TRUE;
1029         struct stat s;
1030
1031         old_cache = mbox_cache_get_mbox(filename);
1032
1033         if (old_cache != NULL) {
1034                 if (stat(filename, &s) < 0) {
1035                         FILE_OP_ERROR(filename, "stat");
1036                 } else if (old_cache->mtime == s.st_mtime) {
1037                         debug_print("Folder is not modified.\n");
1038                         scan_new = FALSE;
1039                 }
1040         }
1041
1042
1043         if (scan_new) {
1044
1045                 /*
1046                 GList * l;
1047
1048                 if (strstr(filename, "trash") == 0)
1049                         printf("old_cache: %p %s\n", old_cache, filename);
1050
1051                         if (old_cache) {
1052                                 printf("begin old\n");
1053                                 for(l = old_cache->mf->msg_list ; l != NULL ;
1054                                     l = g_list_next(l)) {
1055                                         struct _message * msg = l->data;
1056                                         printf("%p\n", msg);
1057                                 }
1058                                 printf("end old\n");
1059                         }
1060                 */
1061                 
1062                 new_cache = mbox_cache_read_mbox_from_file(fp, filename);
1063
1064                 /*
1065                 if (strstr(filename, "trash") == 0) 
1066                         printf("new_cache: %p %s\n", new_cache, filename);
1067
1068                         if (new_cache) {
1069                                 printf("begin new\n");
1070                                 for(l = new_cache->mf->msg_list ; l != NULL ;
1071                                     l = g_list_next(l)) {
1072                                         struct _message * msg = l->data;
1073                                         printf("%p\n", msg);
1074                                 }
1075                                 printf("end new\n");
1076                         }
1077                 */
1078
1079                 if (!new_cache)
1080                         return;
1081
1082                 if (sync && new_cache && old_cache)
1083                         mbox_cache_synchronize_lists(old_cache->mf->msg_list,
1084                                                      new_cache->mf->msg_list);
1085
1086                 if (old_cache != NULL)
1087                         mbox_cache_free_mbox(old_cache);
1088
1089                 if (new_cache) {
1090                         mbox_cache_insert_mbox(new_cache);
1091                         /*
1092                         printf("insert %p %s\n", new_cache, new_cache->filename);
1093                         printf("inserted %s %p\n", filename,
1094                                mbox_cache_get_mbox(filename));
1095                         */
1096                 }
1097         }
1098 }
1099
1100 gboolean mbox_cache_msg_fetched(gchar * filename, gint num)
1101 {
1102         struct _message * msg;
1103         mboxcache * cache;
1104
1105         cache = mbox_cache_get_mbox(filename);
1106
1107         if (cache == NULL)
1108                 return FALSE;
1109
1110         msg = (struct _message *) g_ptr_array_index(cache->tab_mf,
1111                                                     num - 1);
1112         if (msg == NULL)
1113                 return FALSE;
1114
1115         return msg->fetched;
1116 }
1117
1118 void mbox_cache_msg_set_fetched(gchar * filename, gint num)
1119 {
1120         struct _message * msg;
1121         mboxcache * cache;
1122
1123         cache = mbox_cache_get_mbox(filename);
1124
1125         if (cache == NULL)
1126                 return;
1127
1128         msg = (struct _message *) g_ptr_array_index(cache->tab_mf,
1129                                                     num - 1);
1130         if (msg == NULL)
1131                 return;
1132
1133         msg->fetched = TRUE;
1134 }
1135
1136 struct _message * mbox_cache_get_msg(gchar * filename, gint num)
1137 {
1138         mboxcache * cache;
1139
1140         cache = mbox_cache_get_mbox(filename);
1141
1142         if (cache == NULL) {
1143                 return NULL;
1144         }
1145
1146         return (struct _message *) g_ptr_array_index(cache->tab_mf,
1147                                                      num - 1);
1148 }
1149
1150
1151 /**********************************************************/
1152 /*                                                        */
1153 /*                   mbox operations                      */
1154 /*                                                        */
1155 /**********************************************************/
1156
1157
1158 GSList *mbox_get_msg_list(Folder *folder, FolderItem *item, gboolean use_cache)
1159 {
1160         GSList *mlist;
1161         MsgInfo * msginfo;
1162         GList * l;
1163         FILE * fp;
1164         gchar * mbox_path;
1165
1166 #ifdef MEASURE_TIME
1167         struct timeval tv_before, tv_after, tv_result;
1168
1169         gettimeofday(&tv_before, NULL);
1170 #endif
1171
1172         mlist = NULL;
1173
1174         mbox_path = mbox_folder_get_path(item);
1175
1176         if (mbox_path == NULL)
1177                 return NULL;
1178
1179         mbox_purge_deleted(mbox_path);
1180
1181         fp = fopen(mbox_path, "rb");
1182         
1183         if (fp == NULL) {
1184                 g_free(mbox_path);
1185                 return NULL;
1186         }
1187
1188         mbox_lockread_file(fp, mbox_path);
1189
1190         mbox_cache_synchronize_from_file(fp, mbox_path, TRUE);
1191
1192         item->last_num = mbox_cache_get_count(mbox_path);
1193
1194         for(l = mbox_cache_get_msg_list(mbox_path) ; l != NULL ;
1195             l = g_list_next(l)) {
1196                 struct _message * msg;
1197
1198                 msg = (struct _message *) l->data;
1199
1200                 if (MSG_IS_INVALID(msg->flags) || !MSG_IS_REALLY_DELETED(msg->flags)) {
1201                         fseek(fp, msg->header, SEEK_SET);
1202
1203                         msginfo = mbox_parse_msg(fp, msg, item);
1204
1205                         if (!MSG_IS_INVALID(msg->flags))
1206                                 msginfo->flags = msg->flags;
1207                         else {
1208                                 msg->old_flags = msginfo->flags;
1209                                 msg->flags = msginfo->flags;
1210                         }
1211
1212                         mlist = g_slist_append(mlist, msginfo);
1213                 }
1214                 else {
1215                         MSG_SET_PERM_FLAGS(msg->flags, MSG_REALLY_DELETED);
1216                 }
1217         }
1218
1219         mbox_unlock_file(fp, mbox_path);
1220
1221         g_free(mbox_path);
1222
1223         fclose(fp);
1224
1225 #ifdef MEASURE_TIME
1226         gettimeofday(&tv_after, NULL);
1227
1228         timersub(&tv_after, &tv_before, &tv_result);
1229         g_print("mbox_get_msg_list: %s: elapsed time: %ld.%06ld sec\n",
1230                 mbox_path, tv_result.tv_sec, tv_result.tv_usec);
1231 #endif
1232
1233         return mlist;
1234 }
1235
1236 static gboolean mbox_extract_msg(FolderItem * item, gint msgnum,
1237                                  gchar * dest_filename)
1238 {
1239         struct _message * msg;
1240         gint offset;
1241         gint max_offset;
1242         gint size;
1243         FILE * src;
1244         FILE * dest;
1245         gboolean err;
1246         /*      GList * msg_list;*/
1247         gboolean already_fetched;
1248         gchar * mbox_path;
1249
1250         mbox_path = mbox_folder_get_path(item);
1251
1252         if (mbox_path == NULL)
1253                 return FALSE;
1254
1255         src = fopen(mbox_path, "rb");
1256         if (src == NULL) {
1257                 g_free(mbox_path);
1258                 return FALSE;
1259         }
1260
1261         mbox_lockread_file(src, mbox_path);
1262
1263         mbox_cache_synchronize_from_file(src, mbox_path, TRUE);
1264
1265         already_fetched = mbox_cache_msg_fetched(mbox_path, msgnum);
1266
1267         if (already_fetched) {
1268                 mbox_unlock_file(src, mbox_path);
1269                 fclose(src);
1270                 g_free(mbox_path);
1271                 return TRUE;
1272         }
1273
1274         msg = mbox_cache_get_msg(mbox_path, msgnum);
1275
1276         if (msg == NULL) {
1277                 mbox_unlock_file(src, mbox_path);
1278                 fclose(src);
1279                 g_free(mbox_path);
1280                 return FALSE;
1281         }
1282
1283         offset = msg->offset;
1284         max_offset = msg->end;
1285         
1286         size = max_offset - offset;
1287
1288         fseek(src, offset, SEEK_SET);
1289
1290         dest = fopen(dest_filename, "wb");
1291         if (dest == NULL) {
1292                 mbox_unlock_file(src, mbox_path);
1293                 fclose(src);
1294                 g_free(mbox_path);
1295                 return FALSE;
1296         }
1297
1298         if (change_file_mode_rw(dest, dest_filename) < 0) {
1299                 FILE_OP_ERROR(dest_filename, "chmod");
1300                 g_warning(_("can't change file mode\n"));
1301         }
1302
1303         if (!mbox_write_data(src, dest, dest_filename, size)) {
1304                 mbox_unlock_file(src, mbox_path);
1305                 fclose(dest);
1306                 fclose(src);
1307                 unlink(dest_filename);
1308                 g_free(mbox_path);
1309                 return FALSE;
1310         }
1311
1312         err = FALSE;
1313
1314         if (ferror(src)) {
1315                 FILE_OP_ERROR(mbox_path, "fread");
1316                 err = TRUE;
1317         }
1318
1319         mbox_cache_msg_set_fetched(mbox_path, msgnum);
1320
1321         if (fclose(dest) == -1) {
1322                 FILE_OP_ERROR(dest_filename, "fclose");
1323                 err = TRUE;
1324         }
1325
1326         mbox_unlock_file(src, mbox_path);
1327
1328         if (fclose(src) == -1) {
1329                 FILE_OP_ERROR(mbox_path, "fclose");
1330                 err = TRUE;
1331         }
1332
1333         g_free(mbox_path);
1334
1335         if (err) {
1336                 unlink(dest_filename);
1337                 return FALSE;
1338         }
1339
1340         return TRUE;
1341 }
1342
1343 gchar *mbox_fetch_msg(Folder *folder, FolderItem *item, gint num)
1344 {
1345         gchar *path;
1346         gchar *filename;
1347         
1348         g_return_val_if_fail(item != NULL, NULL);
1349
1350         path = folder_item_get_path(item);
1351         if (!is_dir_exist(path))
1352                 make_dir_hier(path);
1353
1354         filename = g_strconcat(path, G_DIR_SEPARATOR_S, itos(num), NULL);
1355
1356         g_free(path);
1357
1358         if (!mbox_extract_msg(item, num, filename)) {
1359                 g_free(filename);
1360                 return NULL;
1361         }
1362
1363         return filename;
1364 }
1365
1366 gint mbox_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
1367                   gboolean remove_source)
1368 {
1369         FILE * src_fp;
1370         FILE * dest_fp;
1371         gchar buf[BUFSIZ];
1372         gint old_size;
1373         gint n_read;
1374         gboolean err;
1375         gchar * mbox_path;
1376         gchar from_line[MSGBUFSIZE];
1377
1378         if (dest->last_num < 0) {
1379                 mbox_scan_folder(folder, dest);
1380                 if (dest->last_num < 0) return -1;
1381         }
1382
1383         src_fp = fopen(file, "rb");
1384         if (src_fp == NULL) {
1385                 return -1;
1386         }
1387
1388         mbox_path = mbox_folder_get_path(dest);
1389         if (mbox_path == NULL)
1390                 return -1;
1391
1392         dest_fp = fopen(mbox_path, "ab");
1393         if (dest_fp == NULL) {
1394                 fclose(src_fp);
1395                 g_free(mbox_path);
1396                 return -1;
1397         }
1398
1399         if (change_file_mode_rw(dest_fp, mbox_path) < 0) {
1400                 FILE_OP_ERROR(mbox_path, "chmod");
1401                 g_warning(_("can't change file mode\n"));
1402         }
1403
1404         old_size = ftell(dest_fp);
1405
1406         mbox_lockwrite_file(dest_fp, mbox_path);
1407
1408         if (fgets(from_line, sizeof(from_line), src_fp) == NULL) {
1409                 mbox_unlock_file(dest_fp, mbox_path);
1410                 g_warning(_("unvalid file - %s.\n"), file);
1411                 fclose(dest_fp);
1412                 fclose(src_fp);
1413                 g_free(mbox_path);
1414                 return -1;
1415         }
1416         
1417         if (strncmp(from_line, "From ", 5) != 0) {
1418                 struct stat s;
1419
1420                 if (stat(file, &s) < 0) {
1421                         mbox_unlock_file(dest_fp, mbox_path);
1422                         g_warning(_("invalid file - %s.\n"), file);
1423                         fclose(dest_fp);
1424                         fclose(src_fp);
1425                         g_free(mbox_path);
1426                         return -1;
1427                 }
1428
1429                 fprintf(dest_fp, "From - %s", ctime(&s.st_mtime));
1430         }
1431
1432         fputs(from_line, dest_fp);
1433
1434         while (1) {
1435                 n_read = fread(buf, 1, sizeof(buf), src_fp);
1436                 if ((n_read < (gint) sizeof(buf)) && ferror(src_fp))
1437                         break;
1438                 if (fwrite(buf, n_read, 1, dest_fp) < 1) {
1439                         mbox_unlock_file(dest_fp, mbox_path);
1440                         g_warning(_("writing to %s failed.\n"), mbox_path);
1441                         ftruncate(fileno(dest_fp), old_size);
1442                         fclose(dest_fp);
1443                         fclose(src_fp);
1444                         g_free(mbox_path);
1445                         return -1;
1446                 }
1447
1448                 if (n_read < (gint) sizeof(buf))
1449                         break;
1450         }
1451
1452         err = FALSE;
1453
1454         if (ferror(src_fp)) {
1455                 FILE_OP_ERROR(mbox_path, "fread");
1456         }
1457
1458         mbox_unlock_file(dest_fp, mbox_path);
1459
1460         if (fclose(src_fp) == -1) {
1461                 FILE_OP_ERROR(file, "fclose");
1462                 err = TRUE;
1463         }
1464
1465         if (fclose(dest_fp) == -1) {
1466                 FILE_OP_ERROR(mbox_path, "fclose");
1467                 g_free(mbox_path);
1468                 return -1;
1469         }
1470
1471         if (err) {
1472                 ftruncate(fileno(dest_fp), old_size);
1473                 g_free(mbox_path);
1474                 return -1;
1475         }
1476
1477         if (remove_source) {
1478                 if (unlink(file) < 0)
1479                         FILE_OP_ERROR(file, "unlink");
1480         }
1481
1482         g_free(mbox_path);
1483
1484         dest->last_num++;
1485         return dest->last_num;
1486
1487 }
1488
1489 gint mbox_remove_msg(Folder *folder, FolderItem *item, gint num)
1490 {
1491         struct _message * msg;
1492         gchar * mbox_path;
1493
1494         mbox_path = mbox_folder_get_path(item);
1495         if (mbox_path == NULL)
1496                 return -1;
1497
1498         mbox_cache_synchronize(mbox_path, TRUE);
1499
1500         msg = mbox_cache_get_msg(mbox_path, num);
1501
1502         g_free(mbox_path);
1503
1504         if (msg != NULL)
1505                 MSG_SET_PERM_FLAGS(msg->flags, MSG_REALLY_DELETED);
1506
1507         return 0;
1508 }
1509
1510 gint mbox_remove_all_msg(Folder *folder, FolderItem *item)
1511 {
1512         FILE * fp;
1513         gchar * mbox_path;
1514
1515         mbox_path = mbox_folder_get_path(item);
1516         if (mbox_path == NULL)
1517                 return -1;
1518
1519         fp = fopen(mbox_path, "wb");
1520         if (fp == NULL) {
1521                 g_free(mbox_path);
1522                 return -1;
1523         }
1524
1525         fclose(fp);
1526
1527         g_free(mbox_path);
1528
1529         return 0;
1530 }
1531
1532 /*
1533 gint mbox_move_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
1534 {
1535         gchar * filename;
1536         gint msgnum;
1537
1538         filename = mbox_fetch_msg(folder, msginfo->folder, msginfo->msgnum);
1539         if (filename == NULL)
1540                 return -1;
1541
1542         msgnum = mbox_add_msg(folder, dest, filename, TRUE);
1543
1544         if (msgnum != -1) {
1545                 MSG_SET_FLAGS(msginfo->flags, MSG_REALLY_DELETED);
1546                 mbox_change_flags(folder, msginfo->folder, msginfo);
1547         }
1548
1549         return msgnum;
1550 }
1551
1552 gint mbox_move_msgs_with_dest(Folder *folder, FolderItem *dest, GSList *msglist)
1553 {
1554         GSList * l;
1555         gchar * mbox_path = NULL;
1556
1557         for(l = msglist ; l != NULL ; l = g_slist_next(l)) {
1558                 MsgInfo * msginfo = (MsgInfo *) l->data;
1559
1560                 if (msginfo->folder && mbox_path == NULL)
1561                         mbox_path = mbox_folder_get_path(msginfo->folder);
1562
1563                 mbox_move_msg(folder, dest, msginfo);
1564         }
1565
1566         if (mbox_path) {
1567                 mbox_cache_synchronize(mbox_path);
1568                 g_free(mbox_path);
1569         }
1570
1571         mbox_path = mbox_folder_get_path(dest);
1572         mbox_cache_synchronize(mbox_path);
1573         g_free(mbox_path);
1574
1575         return dest->last_num;
1576 }
1577 */
1578
1579 /*
1580 gint mbox_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
1581 {
1582         gchar * filename;
1583         gint msgnum;
1584
1585         filename = mbox_fetch_msg(folder, msginfo->folder, msginfo->msgnum);
1586         if (filename == NULL)
1587                 return -1;
1588
1589         msgnum = mbox_add_msg(folder, dest, filename, FALSE);
1590
1591         return msgnum;
1592 }
1593
1594 gint mbox_copy_msgs_with_dest(Folder *folder, FolderItem *dest, GSList *msglist)
1595 {
1596         GSList * l;
1597         gchar * mbox_path = NULL;
1598
1599         for(l = msglist ; l != NULL ; l = g_slist_next(l)) {
1600                 MsgInfo * msginfo = (MsgInfo *) l->data;
1601
1602                 if (msginfo->folder && mbox_path == NULL)
1603                         mbox_path = mbox_folder_get_path(msginfo->folder);
1604
1605                 mbox_copy_msg(folder, dest, msginfo);
1606         }
1607
1608         if (mbox_path) {
1609                 mbox_cache_synchronize(mbox_path);
1610                 g_free(mbox_path);
1611         }
1612
1613         mbox_path = mbox_folder_get_path(dest);
1614         mbox_cache_synchronize(mbox_path);
1615         g_free(mbox_path);
1616
1617         return dest->last_num;
1618 }
1619 */
1620
1621 struct _copy_flags_info
1622 {
1623         gint num;
1624         MsgFlags flags;
1625 };
1626
1627 typedef struct _copy_flags_info CopyFlagsInfo;
1628
1629 GSList * copy_flags_data = NULL;
1630
1631 gint mbox_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
1632 {
1633         Folder * src_folder;
1634         gchar * filename;
1635         gint num;
1636         CopyFlagsInfo * flags_info;
1637
1638         src_folder = msginfo->folder->folder;
1639         
1640         g_return_val_if_fail(src_folder->fetch_msg != NULL, -1);
1641         
1642         /*
1643         mbox_path = mbox_folder_get_path(msginfo->folder);
1644         mbox_rewrite(mbox_path);
1645         g_free(mbox_path);
1646         */
1647
1648         filename = src_folder->fetch_msg(src_folder,
1649                                          msginfo->folder,
1650                                          msginfo->msgnum);
1651         if (filename == NULL)
1652                 return -1;
1653
1654         num = folder->add_msg(folder, dest, filename, FALSE);
1655
1656         /*
1657         mbox_path = mbox_folder_get_path(dest);
1658         msg = mbox_cache_get_msg(mbox_path, num);
1659         if (msg != NULL)
1660                 msg->flags = msginfo->flags;
1661         g_free(mbox_path);
1662         */
1663
1664         if (num == -1)
1665                 return -1;
1666
1667         flags_info = g_new0(CopyFlagsInfo, 1);
1668         flags_info->num = num;
1669         flags_info->flags = msginfo->flags;
1670         copy_flags_data = g_slist_append(copy_flags_data, flags_info);
1671
1672         return num;
1673 }
1674
1675 void mbox_finished_copy(Folder *folder, FolderItem *dest)
1676 {
1677         gchar * mbox_path;
1678         GSList * l;
1679         mboxcache * cache;
1680         
1681         mbox_path = mbox_folder_get_path(dest);
1682         if (mbox_path == NULL)
1683                 return;
1684
1685         mbox_cache_synchronize(mbox_path, TRUE);
1686
1687         for(l = copy_flags_data ; l != NULL ; l = g_slist_next(l)) {
1688                 CopyFlagsInfo * flags_info = l->data;
1689                 struct _message * msg;
1690
1691                 msg = mbox_cache_get_msg(mbox_path, flags_info->num);
1692                 if (msg != NULL)
1693                         msg->flags = flags_info->flags;
1694                 g_free(flags_info);
1695         }
1696
1697         if (copy_flags_data != NULL) {
1698                 cache = mbox_cache_get_mbox(mbox_path);
1699                 cache->modification = TRUE;
1700         }
1701
1702         g_slist_free(copy_flags_data);
1703         copy_flags_data = NULL;
1704
1705         mbox_rewrite(mbox_path);
1706
1707         g_free(mbox_path);
1708 }
1709
1710 void mbox_scan_folder(Folder *folder, FolderItem *item)
1711 {
1712         gchar *mbox_path;
1713         gint n_msg;
1714         mboxcache * cached;
1715         GList * l;
1716
1717         mbox_path = mbox_folder_get_path(item);
1718         if (mbox_path == NULL)
1719                 return;
1720
1721         mbox_cache_synchronize(mbox_path, TRUE);
1722
1723         cached = mbox_cache_get_mbox(mbox_path);
1724
1725         if (cached == NULL) {
1726                 item->new = 0;
1727                 item->unread = 0;
1728                 item->total = 0;
1729                 item->last_num = 0;
1730                 g_free(mbox_path);
1731                 return;
1732         }
1733
1734         n_msg = mbox_cache_get_count(mbox_path);
1735
1736         if (n_msg == 0) {
1737                 item->new = item->unread = item->total = 0;
1738         }
1739         else {
1740                 gint new = 0;
1741                 gint unread = 0;
1742                 gint total = 0;
1743
1744                 for(l = mbox_cache_get_msg_list(mbox_path) ; l != NULL ;
1745                     l = g_list_next(l)) {
1746                         struct _message * msg = (struct _message *) l->data;
1747                         if (!MSG_IS_REALLY_DELETED(msg->flags))
1748                                 total ++;
1749                         if (MSG_IS_NEW(msg->flags) && !MSG_IS_IGNORE_THREAD(msg->flags))
1750                                 new ++;
1751                         if (MSG_IS_UNREAD(msg->flags) && !MSG_IS_IGNORE_THREAD(msg->flags))
1752                                 unread ++;
1753                 }
1754                 
1755                 item->new = new;
1756                 item->unread = unread;
1757                 item->total = total;
1758         }
1759
1760         debug_print("Last number in dir %s = %d\n", mbox_path,
1761                     item->total);
1762         item->last_num = n_msg;
1763         g_free(mbox_path);
1764 }
1765
1766 gchar * mbox_get_virtual_path(FolderItem * item)
1767 {
1768         if (item == NULL)
1769                 return NULL;
1770
1771         if (item->parent == NULL) {
1772                 return NULL;
1773         }
1774         else {
1775                 gchar * parent_path;
1776                 gchar * result_path;
1777
1778                 parent_path = mbox_get_virtual_path(item->parent);
1779                 if (parent_path == NULL)
1780                         result_path = g_strdup(item->name);
1781                 else
1782                         result_path = g_strconcat(parent_path,
1783                                                   G_DIR_SEPARATOR_S,
1784                                                   item->name, NULL);
1785                 g_free(parent_path);
1786
1787                 return result_path;
1788         }
1789 }
1790
1791 static gboolean mbox_write_data(FILE * mbox_fp, FILE * new_fp,
1792                                 gchar * new_filename, gint size)
1793 {       
1794         gint n_read;
1795         gint pos;
1796         gchar buf[BUFSIZ];
1797         gint max;
1798
1799         pos = 0;
1800         while (pos < size) {
1801                 if ((size - pos) > (gint) sizeof(buf))
1802                         max = sizeof(buf);
1803                 else
1804                         max = (size - pos);
1805                 
1806                 n_read = fread(buf, 1, max, mbox_fp);
1807
1808                 if (n_read < max && ferror(mbox_fp)) {
1809                         return FALSE;
1810                 }
1811                 if (fwrite(buf, n_read, 1, new_fp) < 1) {
1812                         g_warning(_("writing to %s failed.\n"), new_filename);
1813                         return FALSE;
1814                 }
1815                 
1816                 if (n_read != -1)
1817                         pos += n_read;
1818                 
1819                 if (n_read < max)
1820                         break;
1821         }
1822         return TRUE;
1823 }
1824
1825 static gboolean mbox_write_message(FILE * mbox_fp, FILE * new_fp,
1826                                    gchar * new_filename,
1827                                    struct _message * msg)
1828 {
1829         gint size;
1830         GPtrArray * headers;
1831         gint i;
1832         
1833         fseek(mbox_fp, msg->header, SEEK_SET);
1834
1835         headers = procheader_get_header_array_asis(mbox_fp);
1836
1837         for (i = 0; i < (gint) headers->len; i++) {
1838                 Header * h = g_ptr_array_index(headers, i);
1839                 
1840                 if (!procheader_headername_equal(h->name, 
1841                                                  "Status") &&
1842                     !procheader_headername_equal(h->name, 
1843                                                  "X-Status")) {
1844                         fwrite(h->name, strlen(h->name),
1845                                1, new_fp);
1846                         if (h->name[strlen(h->name) - 1] != ' ')
1847                                 fwrite(" ", 1, 1, new_fp);
1848                         fwrite(h->body, strlen(h->body),
1849                                1, new_fp);
1850                         fwrite("\n", 1, 1, new_fp);
1851                 }
1852                 procheader_header_free(h);
1853                 g_ptr_array_remove_index(headers, i);
1854                 i--;
1855         }
1856
1857         g_ptr_array_free(headers, FALSE);
1858
1859         if (!MSG_IS_INVALID(msg->flags)) {
1860                 /* Status header */
1861                 fwrite("Status: ", strlen("Status: "), 1, new_fp);
1862                 if (!MSG_IS_UNREAD(msg->flags))
1863                         fwrite("R", 1, 1, new_fp);
1864                 fwrite("O", 1, 1, new_fp);
1865                 fwrite("\n", 1, 1, new_fp);
1866                 
1867                 /* X-Status header */
1868                 if (MSG_IS_REALLY_DELETED(msg->flags)
1869                 ||  MSG_IS_MARKED(msg->flags)
1870                 ||  MSG_IS_DELETED(msg->flags)
1871                 ||  MSG_IS_REPLIED(msg->flags)
1872                 ||  MSG_IS_FORWARDED(msg->flags)) {
1873                         fwrite("X-Status: ", strlen("X-Status: "), 1, new_fp);
1874                         if (MSG_IS_REALLY_DELETED(msg->flags))
1875                                 fwrite("D", 1, 1, new_fp); /* really deleted */
1876                         else {
1877                                 if (MSG_IS_MARKED(msg->flags))
1878                                         fwrite("F", 1, 1, new_fp);
1879                                 if (MSG_IS_DELETED(msg->flags))
1880                                         fwrite("d", 1, 1, new_fp);
1881                                 if (MSG_IS_REPLIED(msg->flags))
1882                                         fwrite("r", 1, 1, new_fp);
1883                                 if (MSG_IS_FORWARDED(msg->flags))
1884                                         fwrite("f", 1, 1, new_fp);
1885                         }
1886                         fwrite("\n", 1, 1, new_fp);
1887                 }
1888         }
1889
1890         fwrite("\n", 1, 1, new_fp);
1891
1892         size = msg->end - msg->content;
1893         fseek(mbox_fp, msg->content, SEEK_SET);
1894
1895         return mbox_write_data(mbox_fp, new_fp, new_filename, size);
1896 }
1897
1898 void mbox_update_mark(Folder * folder, FolderItem * item)
1899 {
1900         gchar * mbox_path;
1901
1902         mbox_path = mbox_folder_get_path(item);
1903         if (mbox_path == NULL)
1904                 return;
1905
1906         mbox_rewrite(mbox_path);
1907         g_free(mbox_path);
1908 }
1909
1910 void mbox_change_flags(Folder * folder, FolderItem * item, MsgInfo * info)
1911 {
1912         struct _message * msg;
1913         mboxcache * cache;
1914         gchar * mbox_path;
1915
1916         mbox_path = mbox_folder_get_path(item);
1917         if (mbox_path == NULL)
1918                 return;
1919
1920         msg = mbox_cache_get_msg(mbox_path, info->msgnum);
1921
1922         cache = mbox_cache_get_mbox(mbox_path);
1923
1924         g_free(mbox_path);
1925
1926         if ((msg == NULL) || (cache == NULL))
1927                 return;
1928
1929         msg->flags = info->flags;
1930
1931         cache->modification = TRUE;
1932                 
1933 }
1934
1935
1936 static gboolean mbox_rewrite(gchar * mbox)
1937 {
1938         FILE * mbox_fp;
1939         FILE * new_fp;
1940         gchar * new;
1941         GList * l;
1942         gboolean result;
1943         GList * msg_list;
1944         gint count;
1945         mboxcache * cache;
1946
1947         msg_list = mbox_cache_get_msg_list(mbox);
1948
1949         cache = mbox_cache_get_mbox(mbox);
1950         if (cache == NULL)
1951                 return FALSE;
1952
1953         if (!cache->modification) {
1954                 debug_print("no modification - %s\n", mbox);
1955                 return FALSE;
1956         }
1957
1958         debug_print("save modification - %s\n", mbox);
1959
1960         mbox_fp = fopen(mbox, "rb+");
1961         mbox_lockwrite_file(mbox_fp, mbox);
1962
1963         mbox_cache_synchronize_from_file(mbox_fp, mbox, TRUE);
1964
1965         new = g_strconcat(mbox, ".", itos((int) mbox), NULL);
1966         new_fp = fopen(new, "wb");
1967
1968         if (change_file_mode_rw(new_fp, new) < 0) {
1969                 FILE_OP_ERROR(new, "chmod");
1970                 g_warning(_("can't change file mode\n"));
1971         }
1972
1973         mbox_lockwrite_file(new_fp, new);
1974
1975         result = TRUE;
1976
1977         count = 0;
1978         msg_list = mbox_cache_get_msg_list(mbox);
1979         for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
1980                 struct _message * msg = (struct _message *) l->data;
1981                 if (!mbox_write_message(mbox_fp, new_fp, new, msg)) {
1982                         result = FALSE;
1983                         break;
1984                 }
1985                 count ++;
1986         }
1987
1988         unlink(mbox);
1989
1990         if (rename(new, mbox) == -1) {
1991                 g_warning(_("can't rename %s to %s\n"), new, mbox);
1992                 mbox_unlock_file(new_fp, new);
1993                 fclose(new_fp);
1994                 mbox_unlock_file(mbox_fp, mbox);
1995                 fclose(mbox_fp);
1996                 g_free(new);
1997                 return -1;
1998         }
1999
2000         if (change_file_mode_rw(new_fp, mbox) < 0) {
2001                 FILE_OP_ERROR(new, "chmod");
2002                 g_warning(_("can't change file mode\n"));
2003         }
2004
2005         mbox_unlock_file(new_fp, new);
2006
2007         fclose(new_fp);
2008
2009         mbox_unlock_file(mbox_fp, mbox);
2010
2011         fclose(mbox_fp);
2012
2013         debug_print("%i messages written - %s\n", count, mbox);
2014
2015         cache = mbox_cache_get_mbox(mbox);
2016
2017         if (cache != NULL)
2018                 cache->mtime = -1;
2019
2020         mbox_cache_synchronize(mbox, FALSE);
2021
2022         g_free(new);
2023         
2024         return result;
2025 }
2026
2027 static gboolean mbox_purge_deleted(gchar * mbox)
2028 {
2029         FILE * mbox_fp;
2030         FILE * new_fp;
2031         gchar * new;
2032         GList * l;
2033         gboolean result;
2034         gboolean modification = FALSE;
2035         GList * msg_list;
2036         gint count;
2037
2038         mbox_cache_synchronize(mbox, TRUE);
2039
2040         msg_list = mbox_cache_get_msg_list(mbox);
2041
2042         for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
2043                 struct _message * msg = (struct _message *) l->data;
2044                 if (!MSG_IS_INVALID(msg->flags) && MSG_IS_REALLY_DELETED(msg->flags)) {
2045                         modification = TRUE;
2046                         break;
2047                 }
2048         }
2049
2050         if (!modification) {
2051                 debug_print("no deleted messages - %s\n", mbox);
2052                 return FALSE;
2053         }
2054
2055         debug_print("purge deleted messages - %s\n", mbox);
2056
2057         mbox_fp = fopen(mbox, "rb+");
2058         mbox_lockwrite_file(mbox_fp, mbox);
2059
2060         mbox_cache_synchronize_from_file(mbox_fp, mbox, TRUE);
2061
2062         new = g_strconcat(mbox, ".", itos((int) mbox), NULL);
2063         new_fp = fopen(new, "wb");
2064
2065         if (change_file_mode_rw(new_fp, new) < 0) {
2066                 FILE_OP_ERROR(new, "chmod");
2067                 g_warning(_("can't change file mode\n"));
2068         }
2069
2070         mbox_lockwrite_file(new_fp, new);
2071
2072         result = TRUE;
2073
2074         count = 0;
2075         msg_list = mbox_cache_get_msg_list(mbox);
2076         for(l = msg_list ; l != NULL ; l = g_list_next(l)) {
2077                 struct _message * msg = (struct _message *) l->data;
2078                 if (MSG_IS_INVALID(msg->flags) || !MSG_IS_REALLY_DELETED(msg->flags)) {
2079                         if (!mbox_write_message(mbox_fp, new_fp, new, msg)) {
2080                                 result = FALSE;
2081                                 break;
2082                         }
2083                         count ++;
2084                 }
2085         }
2086
2087         unlink(mbox);
2088
2089         if (rename(new, mbox) == -1) {
2090                 g_warning(_("can't rename %s to %s\n"), new, mbox);
2091                 mbox_unlock_file(new_fp, new);
2092                 fclose(new_fp);
2093                 mbox_unlock_file(mbox_fp, mbox);
2094                 fclose(mbox_fp);
2095                 g_free(new);
2096                 return -1;
2097         }
2098
2099         if (change_file_mode_rw(new_fp, mbox) < 0) {
2100                 FILE_OP_ERROR(new, "chmod");
2101                 g_warning(_("can't change file mode\n"));
2102         }
2103
2104         mbox_unlock_file(new_fp, new);
2105
2106         fclose(new_fp);
2107
2108         mbox_unlock_file(mbox_fp, mbox);
2109
2110         fclose(mbox_fp);
2111
2112         debug_print("%i messages written - %s\n", count, mbox);
2113
2114         mbox_cache_synchronize(mbox, FALSE);
2115         g_free(new);
2116         return result;
2117 }
2118
2119 #define MAKE_DIR_IF_NOT_EXIST(dir) \
2120 { \
2121         if (!is_dir_exist(dir)) { \
2122                 if (is_file_exist(dir)) { \
2123                         g_warning(_("File `%s' already exists.\n" \
2124                                     "Can't create folder."), dir); \
2125                         return -1; \
2126                 } \
2127                 if (mkdir(dir, S_IRWXU) < 0) { \
2128                         FILE_OP_ERROR(dir, "mkdir"); \
2129                         return -1; \
2130                 } \
2131                 if (chmod(dir, S_IRWXU) < 0) \
2132                         FILE_OP_ERROR(dir, "chmod"); \
2133         } \
2134 }
2135
2136 gint mbox_create_tree(Folder *folder)
2137 {
2138         gchar *rootpath;
2139
2140         g_return_val_if_fail(folder != NULL, -1);
2141
2142         CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), -1);
2143         rootpath = LOCAL_FOLDER(folder)->rootpath;
2144         MAKE_DIR_IF_NOT_EXIST(rootpath);
2145         CHDIR_RETURN_VAL_IF_FAIL(rootpath, -1);
2146
2147         return 0;
2148 }
2149
2150 #undef MAKE_DIR_IF_NOT_EXIST
2151
2152 static gchar * mbox_get_new_path(FolderItem * parent, gchar * name)
2153 {
2154         gchar * path;
2155
2156         if (strchr(name, '/') == NULL) {
2157                 if (parent->path != NULL)
2158                         path = g_strconcat(parent->path, ".sbd", G_DIR_SEPARATOR_S, name, NULL);
2159                 else
2160                         path = g_strdup(name);
2161         }
2162         else
2163                 path = g_strdup(name);
2164
2165         return path;
2166 }
2167
2168 static gchar * mbox_get_folderitem_name(gchar * name)
2169 {
2170         gchar * foldername;
2171
2172         foldername = g_strdup(g_basename(name));
2173         
2174         return foldername;
2175 }
2176
2177 FolderItem *mbox_create_folder(Folder *folder, FolderItem *parent,
2178                                const gchar *name)
2179 {
2180         gchar * path;
2181         FolderItem *new_item;
2182         gchar * foldername;
2183
2184         g_return_val_if_fail(folder != NULL, NULL);
2185         g_return_val_if_fail(parent != NULL, NULL);
2186         g_return_val_if_fail(name != NULL, NULL);
2187
2188         path = mbox_get_new_path(parent, (gchar *) name);
2189
2190         foldername = mbox_get_folderitem_name((gchar *) name);
2191
2192         new_item = folder_item_new(folder, foldername, path);
2193         folder_item_append(parent, new_item);
2194
2195         if (!strcmp(name, "inbox")) {
2196                 new_item->stype = F_INBOX;
2197                 new_item->folder->inbox = new_item;
2198         } else if (!strcmp(name, "outbox")) {
2199                 new_item->stype = F_OUTBOX;
2200                 new_item->folder->outbox = new_item;
2201         } else if (!strcmp(name, "draft")) {
2202                 new_item->stype = F_DRAFT;
2203                 new_item->folder->draft = new_item;
2204         } else if (!strcmp(name, "queue")) {
2205                 new_item->stype = F_QUEUE;
2206                 new_item->folder->queue = new_item;
2207         } else if (!strcmp(name, "trash")) {
2208                 new_item->stype = F_TRASH;
2209                 new_item->folder->trash = new_item;
2210         }
2211         
2212         g_free(foldername);
2213         g_free(path);
2214         
2215         return new_item;
2216 }
2217
2218 gint mbox_rename_folder(Folder *folder, FolderItem *item, const gchar *name)
2219 {
2220         gchar * path;
2221         gchar * foldername;
2222
2223         g_return_val_if_fail(folder != NULL, -1);
2224         g_return_val_if_fail(item != NULL, -1);
2225         g_return_val_if_fail(item->path != NULL, -1);
2226         g_return_val_if_fail(name != NULL, -1);
2227
2228         path = mbox_get_new_path(item->parent, (gchar *) name);
2229         foldername = mbox_get_folderitem_name((gchar *) name);
2230
2231         if (rename(item->path, path) == -1) {
2232                 g_free(foldername);
2233                 g_free(path);
2234                 g_warning(_("Cannot rename folder item"));
2235
2236                 return -1;
2237         }
2238         else {
2239                 g_free(item->name);
2240                 g_free(item->path);
2241                 item->path = path;
2242                 item->name = foldername;
2243                 
2244                 return 0;
2245         }
2246 }
2247
2248 gint mbox_remove_folder(Folder *folder, FolderItem *item)
2249 {
2250         g_return_val_if_fail(folder != NULL, -1);
2251         g_return_val_if_fail(item != NULL, -1);
2252         g_return_val_if_fail(item->path != NULL, -1);
2253
2254         folder_item_remove(item);
2255         return 0;
2256 }
2257
2258 gint mbox_get_num_list(Folder *folder, FolderItem *item, GSList **mlist)
2259 {
2260         GList * l;
2261         FILE * fp;
2262         gchar * mbox_path;
2263         gint nummsgs = 0;
2264
2265         mbox_path = mbox_folder_get_path(item);
2266
2267         if (mbox_path == NULL)
2268                 return -1;
2269
2270         mbox_purge_deleted(mbox_path);
2271
2272         fp = fopen(mbox_path, "rb");
2273         
2274         if (fp == NULL) {
2275                 g_free(mbox_path);
2276                 return -1;
2277         }
2278
2279         mbox_lockread_file(fp, mbox_path);
2280
2281         mbox_cache_synchronize_from_file(fp, mbox_path, TRUE);
2282
2283         item->last_num = mbox_cache_get_count(mbox_path);
2284
2285         for(l = mbox_cache_get_msg_list(mbox_path) ; l != NULL ;
2286             l = g_list_next(l)) {
2287                 struct _message * msg;
2288
2289                 msg = (struct _message *) l->data;
2290
2291                 if (MSG_IS_INVALID(msg->flags) || !MSG_IS_REALLY_DELETED(msg->flags)) {
2292                         *mlist = g_slist_append(*mlist, GINT_TO_POINTER(msg->msgnum));
2293                         nummsgs++;
2294                 } else {
2295                         MSG_SET_PERM_FLAGS(msg->flags, MSG_REALLY_DELETED);
2296                 }
2297         }
2298
2299         mbox_unlock_file(fp, mbox_path);
2300
2301         g_free(mbox_path);
2302
2303         fclose(fp);
2304
2305         return nummsgs;
2306 }
2307
2308 MsgInfo *mbox_fetch_msginfo(Folder *folder, FolderItem *item, gint num)
2309 {
2310         gchar *mbox_path;
2311         struct _message *msg;
2312         FILE *src;
2313         MsgInfo *msginfo;
2314         
2315         g_return_val_if_fail(folder != NULL, NULL);
2316         g_return_val_if_fail(item != NULL, NULL);
2317
2318         mbox_path = mbox_folder_get_path(item);
2319
2320         g_return_val_if_fail(mbox_path != NULL, NULL);
2321         
2322         src = fopen(mbox_path, "rb");
2323         if (src == NULL) {
2324                 g_free(mbox_path);
2325                 return NULL;
2326         }
2327         mbox_lockread_file(src, mbox_path);
2328         mbox_cache_synchronize_from_file(src, mbox_path, TRUE);
2329
2330         msg = mbox_cache_get_msg(mbox_path, num);
2331         if (msg == NULL) {
2332                 mbox_unlock_file(src, mbox_path);
2333                 fclose(src);
2334                 g_free(mbox_path);
2335                 return NULL;
2336         }
2337         
2338         fseek(src, msg->header, SEEK_SET);
2339         msginfo = mbox_parse_msg(src, msg, item);
2340
2341         mbox_unlock_file(src, mbox_path);
2342         fclose(src);
2343         g_free(mbox_path);
2344
2345         return msginfo;
2346 }
2347
2348 gboolean mbox_check_msgnum_validity(Folder *folder, FolderItem *item)
2349 {
2350         mboxcache * old_cache;
2351         gboolean scan_new = TRUE;
2352         struct stat s;
2353         gchar *filename;
2354
2355         filename = mbox_folder_get_path(item);
2356         
2357         old_cache = mbox_cache_get_mbox(filename);
2358
2359         if (old_cache != NULL) {
2360                 if (stat(filename, &s) < 0) {
2361                         FILE_OP_ERROR(filename, "stat");
2362                 } else if (old_cache->mtime == s.st_mtime) {
2363                         debug_print("Folder is not modified.\n");
2364                         scan_new = FALSE;
2365                 }
2366         }
2367
2368         g_free(filename);
2369         
2370         return !scan_new;
2371 }
2372