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