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