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