Statistics
| Revision:

root / src / mh.c @ 491

History | View | Annotate | Download (32.2 kB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2005 Hiroyuki Yamamoto
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
#ifdef HAVE_CONFIG_H
21
#  include "config.h"
22
#endif
23
24
#include "defs.h"
25
26
#include <glib.h>
27
#include <glib/gi18n.h>
28
#include <dirent.h>
29
#include <sys/stat.h>
30
#include <time.h>
31
#include <unistd.h>
32
#include <string.h>
33
#include <errno.h>
34
35
#undef MEASURE_TIME
36
37
#include "folder.h"
38
#include "mh.h"
39
#include "procmsg.h"
40
#include "procheader.h"
41
#include "utils.h"
42
#include "prefs_common.h"
43
44
static void        mh_folder_init                (Folder                *folder,
45
                                         const gchar        *name,
46
                                         const gchar        *path);
47
48
static Folder        *mh_folder_new                (const gchar        *name,
49
                                         const gchar        *path);
50
static void     mh_folder_destroy        (Folder                *folder);
51
52
static GSList  *mh_get_msg_list                (Folder                *folder,
53
                                         FolderItem        *item,
54
                                         gboolean         use_cache);
55
static gchar   *mh_fetch_msg                (Folder                *folder,
56
                                         FolderItem        *item,
57
                                         gint                 num);
58
static MsgInfo *mh_get_msginfo                (Folder                *folder,
59
                                         FolderItem        *item,
60
                                         gint                 num);
61
static gint     mh_add_msg                (Folder                *folder,
62
                                         FolderItem        *dest,
63
                                         const gchar        *file,
64
                                         MsgFlags        *flags,
65
                                         gboolean         remove_source);
66
static gint     mh_add_msgs                (Folder                *folder,
67
                                         FolderItem        *dest,
68
                                         GSList                *file_list,
69
                                         gboolean         remove_source,
70
                                         gint                *first);
71
static gint     mh_move_msg                (Folder                *folder,
72
                                         FolderItem        *dest,
73
                                         MsgInfo        *msginfo);
74
static gint     mh_move_msgs                (Folder                *folder,
75
                                         FolderItem        *dest,
76
                                         GSList                *msglist);
77
static gint     mh_copy_msg                (Folder                *folder,
78
                                         FolderItem        *dest,
79
                                         MsgInfo        *msginfo);
80
static gint     mh_copy_msgs                (Folder                *folder,
81
                                         FolderItem        *dest,
82
                                         GSList                *msglist);
83
static gint     mh_remove_msg                (Folder                *folder,
84
                                         FolderItem        *item,
85
                                         MsgInfo        *msginfo);
86
static gint     mh_remove_all_msg        (Folder                *folder,
87
                                         FolderItem        *item);
88
static gboolean mh_is_msg_changed        (Folder                *folder,
89
                                         FolderItem        *item,
90
                                         MsgInfo        *msginfo);
91
static gint    mh_close                        (Folder                *folder,
92
                                         FolderItem        *item);
93
94
static gint    mh_scan_folder_full        (Folder                *folder,
95
                                         FolderItem        *item,
96
                                         gboolean         count_sum);
97
static gint    mh_scan_folder                (Folder                *folder,
98
                                         FolderItem        *item);
99
static gint    mh_scan_tree                (Folder                *folder);
100
101
static gint    mh_create_tree                (Folder                *folder);
102
static FolderItem *mh_create_folder        (Folder                *folder,
103
                                         FolderItem        *parent,
104
                                         const gchar        *name);
105
static gint    mh_rename_folder                (Folder                *folder,
106
                                         FolderItem        *item,
107
                                         const gchar        *name);
108
static gint    mh_move_folder                (Folder                *folder,
109
                                         FolderItem        *item,
110
                                         FolderItem        *new_parent);
111
static gint    mh_remove_folder                (Folder                *folder,
112
                                         FolderItem        *item);
113
114
static gchar   *mh_get_new_msg_filename                (FolderItem        *dest);
115
116
static gint        mh_do_move_msgs                        (Folder                *folder,
117
                                                 FolderItem        *dest,
118
                                                 GSList                *msglist);
119
120
static time_t  mh_get_mtime                        (FolderItem        *item);
121
static GSList  *mh_get_uncached_msgs                (GHashTable        *msg_table,
122
                                                 FolderItem        *item);
123
static MsgInfo *mh_parse_msg                        (const gchar        *file,
124
                                                 FolderItem        *item);
125
static void        mh_remove_missing_folder_items        (Folder                *folder);
126
static void        mh_scan_tree_recursive                (FolderItem        *item);
127
128
static gboolean mh_rename_folder_func                (GNode                *node,
129
                                                 gpointer         data);
130
131
static FolderClass mh_class =
132
{
133
        F_MH,
134
135
        mh_folder_new,
136
        mh_folder_destroy,
137
138
        mh_scan_tree,
139
        mh_create_tree,
140
141
        mh_get_msg_list,
142
        mh_fetch_msg,
143
        mh_get_msginfo,
144
        mh_add_msg,
145
        mh_add_msgs,
146
        mh_move_msg,
147
        mh_move_msgs,
148
        mh_copy_msg,
149
        mh_copy_msgs,
150
        mh_remove_msg,
151
        NULL,
152
        mh_remove_all_msg,
153
        mh_is_msg_changed,
154
        mh_close,
155
        mh_scan_folder,
156
157
        mh_create_folder,
158
        mh_rename_folder,
159
        mh_move_folder,
160
        mh_remove_folder,
161
};
162
163
164
FolderClass *mh_get_class(void)
165
{
166
        return &mh_class;
167
}
168
169
static Folder *mh_folder_new(const gchar *name, const gchar *path)
170
{
171
        Folder *folder;
172
173
        folder = (Folder *)g_new0(MHFolder, 1);
174
        mh_folder_init(folder, name, path);
175
176
        return folder;
177
}
178
179
static void mh_folder_destroy(Folder *folder)
180
{
181
        folder_local_folder_destroy(LOCAL_FOLDER(folder));
182
}
183
184
static void mh_folder_init(Folder *folder, const gchar *name, const gchar *path)
185
{
186
        folder->klass = mh_get_class();
187
        folder_local_folder_init(folder, name, path);
188
}
189
190
static GSList *mh_get_msg_list(Folder *folder, FolderItem *item,
191
                               gboolean use_cache)
192
{
193
        GSList *mlist;
194
        GHashTable *msg_table;
195
        time_t cur_mtime;
196
#ifdef MEASURE_TIME
197
        GTimer *timer;
198
#endif
199
200
        g_return_val_if_fail(item != NULL, NULL);
201
202
#ifdef MEASURE_TIME
203
        timer = g_timer_new();
204
#endif
205
206
        cur_mtime = mh_get_mtime(item);
207
208
        if (use_cache && item->mtime == cur_mtime) {
209
                debug_print("Folder is not modified.\n");
210
                mlist = procmsg_read_cache(item, FALSE);
211
                if (!mlist) {
212
                        mlist = mh_get_uncached_msgs(NULL, item);
213
                        if (mlist)
214
                                item->cache_dirty = TRUE;
215
                }
216
        } else if (use_cache) {
217
                GSList *newlist, *cur, *next;
218
                gboolean strict_cache_check = prefs_common.strict_cache_check;
219
220
                if (item->stype == F_QUEUE || item->stype == F_DRAFT)
221
                        strict_cache_check = TRUE;
222
223
                mlist = procmsg_read_cache(item, strict_cache_check);
224
                msg_table = procmsg_msg_hash_table_create(mlist);
225
                newlist = mh_get_uncached_msgs(msg_table, item);
226
                if (newlist)
227
                        item->cache_dirty = TRUE;
228
                if (msg_table)
229
                        g_hash_table_destroy(msg_table);
230
231
                if (!strict_cache_check) {
232
                        /* remove nonexistent messages */
233
                        for (cur = mlist; cur != NULL; cur = next) {
234
                                MsgInfo *msginfo = (MsgInfo *)cur->data;
235
                                next = cur->next;
236
                                if (!MSG_IS_CACHED(msginfo->flags)) {
237
                                        debug_print("removing nonexistent message %d from cache\n", msginfo->msgnum);
238
                                        mlist = g_slist_remove(mlist, msginfo);
239
                                        procmsg_msginfo_free(msginfo);
240
                                        item->cache_dirty = TRUE;
241
                                        item->mark_dirty = TRUE;
242
                                }
243
                        }
244
                }
245
246
                mlist = g_slist_concat(mlist, newlist);
247
        } else {
248
                mlist = mh_get_uncached_msgs(NULL, item);
249
                item->cache_dirty = TRUE;
250
        }
251
252
        item->mtime = cur_mtime;
253
254
        procmsg_set_flags(mlist, item);
255
256
        mlist = procmsg_sort_msg_list(mlist, item->sort_key, item->sort_type);
257
258
#ifdef MEASURE_TIME
259
        g_timer_stop(timer);
260
        g_print("%s: %s: elapsed time: %f sec\n",
261
                G_STRFUNC, item->path, g_timer_elapsed(timer, NULL));
262
        g_timer_destroy(timer);
263
#endif
264
        debug_print("cache_dirty: %d, mark_dirty: %d\n",
265
                    item->cache_dirty, item->mark_dirty);
266
267
        return mlist;
268
}
269
270
static gchar *mh_fetch_msg(Folder *folder, FolderItem *item, gint num)
271
{
272
        gchar *path;
273
        gchar *file;
274
275
        g_return_val_if_fail(item != NULL, NULL);
276
        g_return_val_if_fail(num > 0, NULL);
277
278
        if (item->last_num < 0 || num > item->last_num) {
279
                mh_scan_folder(folder, item);
280
                if (item->last_num < 0) return NULL;
281
        }
282
283
        g_return_val_if_fail(num <= item->last_num, NULL);
284
285
        path = folder_item_get_path(item);
286
        file = g_strconcat(path, G_DIR_SEPARATOR_S, itos(num), NULL);
287
        g_free(path);
288
        if (!is_file_exist(file)) {
289
                g_free(file);
290
                return NULL;
291
        }
292
293
        return file;
294
}
295
296
static MsgInfo *mh_get_msginfo(Folder *folder, FolderItem *item, gint num)
297
{
298
        MsgInfo *msginfo;
299
        gchar *file;
300
301
        g_return_val_if_fail(item != NULL, NULL);
302
        g_return_val_if_fail(num > 0, NULL);
303
304
        file = mh_fetch_msg(folder, item, num);
305
        if (!file) return NULL;
306
307
        msginfo = mh_parse_msg(file, item);
308
        if (msginfo)
309
                msginfo->msgnum = num;
310
311
        g_free(file);
312
313
        return msginfo;
314
}
315
316
static gchar *mh_get_new_msg_filename(FolderItem *dest)
317
{
318
        gchar *destfile;
319
        gchar *destpath;
320
321
        destpath = folder_item_get_path(dest);
322
        g_return_val_if_fail(destpath != NULL, NULL);
323
324
        if (!is_dir_exist(destpath))
325
                make_dir_hier(destpath);
326
327
        for (;;) {
328
                destfile = g_strdup_printf("%s%c%d", destpath, G_DIR_SEPARATOR,
329
                                           dest->last_num + 1);
330
                if (is_file_entry_exist(destfile)) {
331
                        dest->last_num++;
332
                        g_free(destfile);
333
                } else
334
                        break;
335
        }
336
337
        g_free(destpath);
338
339
        return destfile;
340
}
341
342
#define SET_DEST_MSG_FLAGS(fp, dest, n, fl)                                \
343
{                                                                        \
344
        MsgInfo newmsginfo;                                                \
345
                                                                        \
346
        newmsginfo.msgnum = n;                                                \
347
        newmsginfo.flags = fl;                                                \
348
        if (dest->stype == F_OUTBOX ||                                        \
349
            dest->stype == F_QUEUE  ||                                        \
350
            dest->stype == F_DRAFT  ||                                        \
351
            dest->stype == F_TRASH)                                        \
352
                MSG_UNSET_PERM_FLAGS(newmsginfo.flags,                        \
353
                                     MSG_NEW|MSG_UNREAD|MSG_DELETED);        \
354
                                                                        \
355
        if (fp)                                                                \
356
                procmsg_write_flags(&newmsginfo, fp);                        \
357
        else if (dest->opened)                                                \
358
                procmsg_add_flags(dest, n, newmsginfo.flags);                \
359
}
360
361
static gint mh_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
362
                       MsgFlags *flags, gboolean remove_source)
363
{
364
        GSList file_list;
365
        MsgFileInfo fileinfo;
366
367
        g_return_val_if_fail(file != NULL, -1);
368
369
        fileinfo.file = (gchar *)file;
370
        fileinfo.flags = flags;
371
        file_list.data = &fileinfo;
372
        file_list.next = NULL;
373
374
        return mh_add_msgs(folder, dest, &file_list, remove_source, NULL);
375
}
376
377
static gint mh_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
378
                        gboolean remove_source, gint *first)
379
{
380
        gchar *destfile;
381
        GSList *cur;
382
        MsgFileInfo *fileinfo;
383
        gint first_ = 0;
384
        FILE *fp;
385
386
        g_return_val_if_fail(dest != NULL, -1);
387
        g_return_val_if_fail(file_list != NULL, -1);
388
389
        if (dest->last_num < 0) {
390
                mh_scan_folder(folder, dest);
391
                if (dest->last_num < 0) return -1;
392
        }
393
394
        if ((((MsgFileInfo *)file_list->data)->flags == NULL &&
395
            file_list->next == NULL) || dest->opened)
396
                fp = NULL;
397
        else if ((fp = procmsg_open_mark_file(dest, DATA_APPEND)) == NULL)
398
                g_warning("Can't open mark file.\n");
399
400
        for (cur = file_list; cur != NULL; cur = cur->next) {
401
                fileinfo = (MsgFileInfo *)cur->data;
402
403
                destfile = mh_get_new_msg_filename(dest);
404
                if (destfile == NULL) return -1;
405
                if (first_ == 0 || first_ > dest->last_num + 1)
406
                        first_ = dest->last_num + 1;
407
408
#ifdef G_OS_UNIX
409
                if (link(fileinfo->file, destfile) < 0) {
410
#endif
411
                        if (copy_file(fileinfo->file, destfile, TRUE) < 0) {
412
                                g_warning(_("can't copy message %s to %s\n"),
413
                                          fileinfo->file, destfile);
414
                                g_free(destfile);
415
                                return -1;
416
                        }
417
#ifdef G_OS_UNIX
418
                }
419
#endif
420
421
                g_free(destfile);
422
                dest->last_num++;
423
                dest->total++;
424
                dest->updated = TRUE;
425
426
                if (fileinfo->flags) {
427
                        if (MSG_IS_RECEIVED(*fileinfo->flags)) {
428
                                if (dest->unmarked_num == 0)
429
                                        dest->new = 0;
430
                                dest->unmarked_num++;
431
                                procmsg_add_mark_queue(dest, dest->last_num,
432
                                                       *fileinfo->flags);
433
                        } else {
434
                                SET_DEST_MSG_FLAGS(fp, dest, dest->last_num,
435
                                                   *fileinfo->flags);
436
                        }
437
                        if (MSG_IS_NEW(*fileinfo->flags))
438
                                dest->new++;
439
                        if (MSG_IS_UNREAD(*fileinfo->flags))
440
                                dest->unread++;
441
                } else {
442
                        if (dest->unmarked_num == 0)
443
                                dest->new = 0;
444
                        dest->unmarked_num++;
445
                        dest->new++;
446
                        dest->unread++;
447
                }
448
        }
449
450
        if (fp) fclose(fp);
451
452
        if (first)
453
                *first = first_;
454
455
        if (remove_source) {
456
                for (cur = file_list; cur != NULL; cur = cur->next) {
457
                        fileinfo = (MsgFileInfo *)cur->data;
458
                        if (g_unlink(fileinfo->file) < 0)
459
                                FILE_OP_ERROR(fileinfo->file, "unlink");
460
                }
461
        }
462
463
        return dest->last_num;
464
}
465
466
static gint mh_do_move_msgs(Folder *folder, FolderItem *dest, GSList *msglist)
467
{
468
        FolderItem *src;
469
        gchar *srcfile;
470
        gchar *destfile;
471
        FILE *fp;
472
        GSList *cur;
473
        MsgInfo *msginfo;
474
475
        g_return_val_if_fail(dest != NULL, -1);
476
        g_return_val_if_fail(msglist != NULL, -1);
477
478
        if (dest->last_num < 0) {
479
                mh_scan_folder(folder, dest);
480
                if (dest->last_num < 0) return -1;
481
        }
482
483
        if (dest->opened)
484
                fp = NULL;
485
        else if ((fp = procmsg_open_mark_file(dest, DATA_APPEND)) == NULL)
486
                g_warning(_("Can't open mark file.\n"));
487
488
        for (cur = msglist; cur != NULL; cur = cur->next) {
489
                msginfo = (MsgInfo *)cur->data;
490
                src = msginfo->folder;
491
492
                if (src == dest) {
493
                        g_warning(_("the src folder is identical to the dest.\n"));
494
                        continue;
495
                }
496
                debug_print("Moving message %s%c%d to %s ...\n",
497
                            src->path, G_DIR_SEPARATOR, msginfo->msgnum,
498
                            dest->path);
499
500
                destfile = mh_get_new_msg_filename(dest);
501
                if (!destfile) break;
502
                srcfile = procmsg_get_message_file(msginfo);
503
504
                if (move_file(srcfile, destfile, FALSE) < 0) {
505
                        g_free(srcfile);
506
                        g_free(destfile);
507
                        break;
508
                }
509
510
                g_free(srcfile);
511
                g_free(destfile);
512
                src->total--;
513
                src->updated = TRUE;
514
                dest->last_num++;
515
                dest->total++;
516
                dest->updated = TRUE;
517
518
                if (fp) {
519
                        SET_DEST_MSG_FLAGS(fp, dest, dest->last_num,
520
                                           msginfo->flags);
521
                }
522
523
                if (MSG_IS_NEW(msginfo->flags)) {
524
                        src->new--;
525
                        dest->new++;
526
                }
527
                if (MSG_IS_UNREAD(msginfo->flags)) {
528
                        src->unread--;
529
                        dest->unread++;
530
                }
531
532
                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_INVALID);
533
        }
534
535
        if (fp) fclose(fp);
536
537
        return dest->last_num;
538
}
539
540
static gint mh_move_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
541
{
542
        GSList msglist;
543
544
        g_return_val_if_fail(msginfo != NULL, -1);
545
546
        msglist.data = msginfo;
547
        msglist.next = NULL;
548
549
        return mh_move_msgs(folder, dest, &msglist);
550
}
551
552
static gint mh_move_msgs(Folder *folder, FolderItem *dest, GSList *msglist)
553
{
554
        MsgInfo *msginfo;
555
        GSList *file_list;
556
        gint ret = 0;
557
        gint first;
558
559
        msginfo = (MsgInfo *)msglist->data;
560
        if (folder == msginfo->folder->folder)
561
                return mh_do_move_msgs(folder, dest, msglist);
562
563
        file_list = procmsg_get_message_file_list(msglist);
564
        g_return_val_if_fail(file_list != NULL, -1);
565
566
        ret = mh_add_msgs(folder, dest, file_list, FALSE, &first);
567
568
        procmsg_message_file_list_free(file_list);
569
570
        if (ret != -1)
571
                ret = folder_item_remove_msgs(msginfo->folder, msglist);
572
573
        return ret;
574
}
575
576
static gint mh_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
577
{
578
        GSList msglist;
579
580
        g_return_val_if_fail(msginfo != NULL, -1);
581
582
        msglist.data = msginfo;
583
        msglist.next = NULL;
584
585
        return mh_copy_msgs(folder, dest, &msglist);
586
}
587
588
static gint mh_copy_msgs(Folder *folder, FolderItem *dest, GSList *msglist)
589
{
590
        gchar *srcfile;
591
        gchar *destfile;
592
        FILE *fp;
593
        GSList *cur;
594
        MsgInfo *msginfo;
595
596
        g_return_val_if_fail(dest != NULL, -1);
597
        g_return_val_if_fail(msglist != NULL, -1);
598
599
        if (dest->last_num < 0) {
600
                mh_scan_folder(folder, dest);
601
                if (dest->last_num < 0) return -1;
602
        }
603
604
        if (dest->opened)
605
                fp = NULL;
606
        else if ((fp = procmsg_open_mark_file(dest, DATA_APPEND)) == NULL)
607
                g_warning(_("Can't open mark file.\n"));
608
609
        for (cur = msglist; cur != NULL; cur = cur->next) {
610
                msginfo = (MsgInfo *)cur->data;
611
612
                if (msginfo->folder == dest) {
613
                        g_warning(_("the src folder is identical to the dest.\n"));
614
                        continue;
615
                }
616
                debug_print(_("Copying message %s%c%d to %s ...\n"),
617
                            msginfo->folder->path, G_DIR_SEPARATOR,
618
                            msginfo->msgnum, dest->path);
619
620
                destfile = mh_get_new_msg_filename(dest);
621
                if (!destfile) break;
622
                srcfile = procmsg_get_message_file(msginfo);
623
624
                if (copy_file(srcfile, destfile, TRUE) < 0) {
625
                        FILE_OP_ERROR(srcfile, "copy");
626
                        g_free(srcfile);
627
                        g_free(destfile);
628
                        break;
629
                }
630
631
                g_free(srcfile);
632
                g_free(destfile);
633
                dest->last_num++;
634
                dest->total++;
635
                dest->updated = TRUE;
636
637
                if (fp) {
638
                        SET_DEST_MSG_FLAGS(fp, dest, dest->last_num,
639
                                           msginfo->flags);
640
                }
641
642
                if (MSG_IS_NEW(msginfo->flags))
643
                        dest->new++;
644
                if (MSG_IS_UNREAD(msginfo->flags))
645
                        dest->unread++;
646
        }
647
648
        if (fp) fclose(fp);
649
650
        return dest->last_num;
651
}
652
653
static gint mh_remove_msg(Folder *folder, FolderItem *item, MsgInfo *msginfo)
654
{
655
        gchar *file;
656
657
        g_return_val_if_fail(item != NULL, -1);
658
659
        file = mh_fetch_msg(folder, item, msginfo->msgnum);
660
        g_return_val_if_fail(file != NULL, -1);
661
662
        if (g_unlink(file) < 0) {
663
                FILE_OP_ERROR(file, "unlink");
664
                g_free(file);
665
                return -1;
666
        }
667
        g_free(file);
668
669
        item->total--;
670
        item->updated = TRUE;
671
        if (MSG_IS_NEW(msginfo->flags))
672
                item->new--;
673
        if (MSG_IS_UNREAD(msginfo->flags))
674
                item->unread--;
675
        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_INVALID);
676
677
        if (msginfo->msgnum == item->last_num)
678
                mh_scan_folder_full(folder, item, FALSE);
679
680
        return 0;
681
}
682
683
static gint mh_remove_all_msg(Folder *folder, FolderItem *item)
684
{
685
        gchar *path;
686
        gint val;
687
688
        g_return_val_if_fail(item != NULL, -1);
689
690
        path = folder_item_get_path(item);
691
        g_return_val_if_fail(path != NULL, -1);
692
        val = remove_all_numbered_files(path);
693
        g_free(path);
694
        if (val == 0) {
695
                item->new = item->unread = item->total = 0;
696
                item->last_num = 0;
697
                item->updated = TRUE;
698
        }
699
700
        return val;
701
}
702
703
static gboolean mh_is_msg_changed(Folder *folder, FolderItem *item,
704
                                  MsgInfo *msginfo)
705
{
706
        struct stat s;
707
708
        if (g_stat(itos(msginfo->msgnum), &s) < 0 ||
709
            msginfo->size  != s.st_size ||
710
            msginfo->mtime != s.st_mtime)
711
                return TRUE;
712
713
        return FALSE;
714
}
715
716
static gint mh_close(Folder *folder, FolderItem *item)
717
{
718
        return 0;
719
}
720
721
static gint mh_scan_folder_full(Folder *folder, FolderItem *item,
722
                                gboolean count_sum)
723
{
724
        gchar *path;
725
        DIR *dp;
726
        struct dirent *d;
727
        gint max = 0;
728
        gint num;
729
        gint n_msg = 0;
730
731
        g_return_val_if_fail(item != NULL, -1);
732
733
        debug_print("mh_scan_folder(): Scanning %s ...\n", item->path);
734
735
        path = folder_item_get_path(item);
736
        g_return_val_if_fail(path != NULL, -1);
737
        if (change_dir(path) < 0) {
738
                g_free(path);
739
                return -1;
740
        }
741
        g_free(path);
742
743
        if ((dp = opendir(".")) == NULL) {
744
                FILE_OP_ERROR(item->path, "opendir");
745
                return -1;
746
        }
747
748
        if (folder->ui_func)
749
                folder->ui_func(folder, item, folder->ui_func_data);
750
751
        while ((d = readdir(dp)) != NULL) {
752
                if ((num = to_number(d->d_name)) > 0 &&
753
                    dirent_is_regular_file(d)) {
754
                        n_msg++;
755
                        if (max < num)
756
                                max = num;
757
                }
758
        }
759
760
        closedir(dp);
761
762
        if (n_msg == 0)
763
                item->new = item->unread = item->total = 0;
764
        else if (count_sum) {
765
                gint new, unread, total, min, max_;
766
767
                procmsg_get_mark_sum
768
                        (item, &new, &unread, &total, &min, &max_, 0);
769
770
                if (n_msg > total) {
771
                        item->unmarked_num = new = n_msg - total;
772
                        unread += n_msg - total;
773
                } else
774
                        item->unmarked_num = 0;
775
776
                item->new = new;
777
                item->unread = unread;
778
                item->total = n_msg;
779
        }
780
781
        item->updated = TRUE;
782
783
        debug_print(_("Last number in dir %s = %d\n"), item->path, max);
784
        item->last_num = max;
785
786
        return 0;
787
}
788
789
static gint mh_scan_folder(Folder *folder, FolderItem *item)
790
{
791
        return mh_scan_folder_full(folder, item, TRUE);
792
}
793
794
static gint mh_scan_tree(Folder *folder)
795
{
796
        FolderItem *item;
797
        gchar *rootpath;
798
799
        g_return_val_if_fail(folder != NULL, -1);
800
801
        if (!folder->node) {
802
                item = folder_item_new(folder->name, NULL);
803
                item->folder = folder;
804
                folder->node = item->node = g_node_new(item);
805
        } else
806
                item = FOLDER_ITEM(folder->node->data);
807
808
        rootpath = folder_item_get_path(item);
809
        if (change_dir(rootpath) < 0) {
810
                g_free(rootpath);
811
                return -1;
812
        }
813
        g_free(rootpath);
814
815
        mh_create_tree(folder);
816
        mh_remove_missing_folder_items(folder);
817
        mh_scan_tree_recursive(item);
818
819
        return 0;
820
}
821
822
#define MAKE_DIR_IF_NOT_EXIST(dir) \
823
{ \
824
        if (!is_dir_exist(dir)) { \
825
                if (is_file_exist(dir)) { \
826
                        g_warning(_("File `%s' already exists.\n" \
827
                                    "Can't create folder."), dir); \
828
                        return -1; \
829
                } \
830
                if (make_dir(dir) < 0) \
831
                        return -1; \
832
        } \
833
}
834
835
static gint mh_create_tree(Folder *folder)
836
{
837
        gchar *rootpath;
838
839
        g_return_val_if_fail(folder != NULL, -1);
840
841
        CHDIR_RETURN_VAL_IF_FAIL(get_mail_base_dir(), -1);
842
        rootpath = LOCAL_FOLDER(folder)->rootpath;
843
        MAKE_DIR_IF_NOT_EXIST(rootpath);
844
        CHDIR_RETURN_VAL_IF_FAIL(rootpath, -1);
845
        MAKE_DIR_IF_NOT_EXIST(INBOX_DIR);
846
        MAKE_DIR_IF_NOT_EXIST(OUTBOX_DIR);
847
        MAKE_DIR_IF_NOT_EXIST(QUEUE_DIR);
848
        MAKE_DIR_IF_NOT_EXIST(DRAFT_DIR);
849
        MAKE_DIR_IF_NOT_EXIST(TRASH_DIR);
850
851
        return 0;
852
}
853
854
#undef MAKE_DIR_IF_NOT_EXIST
855
856
static FolderItem *mh_create_folder(Folder *folder, FolderItem *parent,
857
                                    const gchar *name)
858
{
859
        gchar *path;
860
        gchar *fs_name;
861
        gchar *fullpath;
862
        FolderItem *new_item;
863
864
        g_return_val_if_fail(folder != NULL, NULL);
865
        g_return_val_if_fail(parent != NULL, NULL);
866
        g_return_val_if_fail(name != NULL, NULL);
867
868
        path = folder_item_get_path(parent);
869
        fs_name = g_filename_from_utf8(name, -1, NULL, NULL, NULL);
870
        fullpath = g_strconcat(path, G_DIR_SEPARATOR_S,
871
                               fs_name ? fs_name : name, NULL);
872
        g_free(fs_name);
873
        g_free(path);
874
875
        if (make_dir(fullpath) < 0) {
876
                g_free(fullpath);
877
                return NULL;
878
        }
879
880
        g_free(fullpath);
881
882
        if (parent->path)
883
                path = g_strconcat(parent->path, G_DIR_SEPARATOR_S, name,
884
                                   NULL);
885
        else
886
                path = g_strdup(name);
887
        new_item = folder_item_new(name, path);
888
        folder_item_append(parent, new_item);
889
        g_free(path);
890
891
        return new_item;
892
}
893
894
static gint mh_move_folder_real(Folder *folder, FolderItem *item,
895
                                FolderItem *new_parent, const gchar *name)
896
{
897
        gchar *oldpath;
898
        gchar *newpath;
899
        gchar *dirname;
900
        gchar *new_dir;
901
        gchar *name_;
902
        gchar *utf8_name;
903
        gchar *paths[2];
904
905
        g_return_val_if_fail(folder != NULL, -1);
906
        g_return_val_if_fail(item != NULL, -1);
907
        g_return_val_if_fail(folder == item->folder, -1);
908
        g_return_val_if_fail(item->path != NULL, -1);
909
        g_return_val_if_fail(new_parent != NULL || name != NULL, -1);
910
        if (new_parent) {
911
                g_return_val_if_fail(item != new_parent, -1);
912
                g_return_val_if_fail(item->parent != new_parent, -1);
913
                g_return_val_if_fail(item->folder == new_parent->folder, -1);
914
                if (g_node_is_ancestor(item->node, new_parent->node)) {
915
                        g_warning("folder to be moved is ancestor of new parent\n");
916
                        return -1;
917
                }
918
        }
919
920
        oldpath = folder_item_get_path(item);
921
        if (new_parent) {
922
                if (name) {
923
                        name_ = g_filename_from_utf8(name, -1, NULL, NULL,
924
                                                     NULL);
925
                        if (!name_)
926
                                name_ = g_strdup(name);
927
                        utf8_name = g_strdup(name);
928
                } else {
929
                        name_ = g_path_get_basename(oldpath);
930
                        utf8_name = g_filename_to_utf8(name_, -1, NULL, NULL,
931
                                                       NULL);
932
                        if (!utf8_name)
933
                                utf8_name = g_strdup(name_);
934
                }
935
                new_dir = folder_item_get_path(new_parent);
936
                newpath = g_strconcat(new_dir, G_DIR_SEPARATOR_S, name_, NULL);
937
                g_free(new_dir);
938
        } else {
939
                name_ = g_filename_from_utf8(name, -1, NULL, NULL, NULL);
940
                utf8_name = g_strdup(name);
941
                dirname = g_dirname(oldpath);
942
                newpath = g_strconcat(dirname, G_DIR_SEPARATOR_S,
943
                                      name_ ? name_ : name, NULL);
944
                g_free(dirname);
945
        }
946
        g_free(name_);
947
948
        if (is_file_entry_exist(newpath)) {
949
                g_warning("%s already exists\n", newpath);
950
                g_free(oldpath);
951
                g_free(newpath);
952
                g_free(utf8_name);
953
                return -1;
954
        }
955
956
        debug_print("mh_move_folder: rename(%s, %s)\n", oldpath, newpath);
957
958
        if (g_rename(oldpath, newpath) < 0) {
959
                FILE_OP_ERROR(oldpath, "rename");
960
                g_free(oldpath);
961
                g_free(newpath);
962
                g_free(utf8_name);
963
                return -1;
964
        }
965
966
        g_free(oldpath);
967
        g_free(newpath);
968
969
        if (new_parent) {
970
                g_node_unlink(item->node);
971
                g_node_append(new_parent->node, item->node);
972
                item->parent = new_parent;
973
                if (new_parent->path != NULL) {
974
                        newpath = g_strconcat(new_parent->path,
975
                                              G_DIR_SEPARATOR_S, utf8_name,
976
                                              NULL);
977
                        g_free(utf8_name);
978
                } else
979
                        newpath = utf8_name;
980
        } else {
981
                if (strchr(item->path, G_DIR_SEPARATOR) != NULL) {
982
                        dirname = g_dirname(item->path);
983
                        newpath = g_strconcat(dirname, G_DIR_SEPARATOR_S,
984
                                              utf8_name, NULL);
985
                        g_free(dirname);
986
                        g_free(utf8_name);
987
                } else
988
                        newpath = utf8_name;
989
        }
990
991
        if (name) {
992
                g_free(item->name);
993
                item->name = g_strdup(name);
994
        }
995
996
        paths[0] = g_strdup(item->path);
997
        paths[1] = newpath;
998
        g_node_traverse(item->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
999
                        mh_rename_folder_func, paths);
1000
1001
        g_free(paths[0]);
1002
        g_free(paths[1]);
1003
1004
        return 0;
1005
}
1006
1007
static gint mh_move_folder(Folder *folder, FolderItem *item,
1008
                           FolderItem *new_parent)
1009
{
1010
        return mh_move_folder_real(folder, item, new_parent, NULL);
1011
}
1012
1013
static gint mh_rename_folder(Folder *folder, FolderItem *item,
1014
                             const gchar *name)
1015
{
1016
        return mh_move_folder_real(folder, item, NULL, name);
1017
}
1018
1019
static gint mh_remove_folder(Folder *folder, FolderItem *item)
1020
{
1021
        gchar *path;
1022
1023
        g_return_val_if_fail(folder != NULL, -1);
1024
        g_return_val_if_fail(item != NULL, -1);
1025
        g_return_val_if_fail(item->path != NULL, -1);
1026
1027
        path = folder_item_get_path(item);
1028
        if (remove_dir_recursive(path) < 0) {
1029
                g_warning("can't remove directory `%s'\n", path);
1030
                g_free(path);
1031
                return -1;
1032
        }
1033
1034
        g_free(path);
1035
        folder_item_remove(item);
1036
        return 0;
1037
}
1038
1039
1040
static time_t mh_get_mtime(FolderItem *item)
1041
{
1042
        gchar *path;
1043
        struct stat s;
1044
1045
        path = folder_item_get_path(item);
1046
        if (g_stat(path, &s) < 0) {
1047
                FILE_OP_ERROR(path, "stat");
1048
                return -1;
1049
        } else {
1050
                return MAX(s.st_mtime, s.st_ctime);
1051
        }
1052
}
1053
1054
static GSList *mh_get_uncached_msgs(GHashTable *msg_table, FolderItem *item)
1055
{
1056
        gchar *path;
1057
        DIR *dp;
1058
        struct dirent *d;
1059
        GSList *newlist = NULL;
1060
        GSList *last = NULL;
1061
        MsgInfo *msginfo;
1062
        gint n_newmsg = 0;
1063
        gint num;
1064
1065
        g_return_val_if_fail(item != NULL, NULL);
1066
1067
        path = folder_item_get_path(item);
1068
        g_return_val_if_fail(path != NULL, NULL);
1069
        if (change_dir(path) < 0) {
1070
                g_free(path);
1071
                return NULL;
1072
        }
1073
        g_free(path);
1074
1075
        if ((dp = opendir(".")) == NULL) {
1076
                FILE_OP_ERROR(item->path, "opendir");
1077
                return NULL;
1078
        }
1079
1080
        debug_print("Searching uncached messages...\n");
1081
1082
        if (msg_table) {
1083
                while ((d = readdir(dp)) != NULL) {
1084
                        if ((num = to_number(d->d_name)) <= 0) continue;
1085
1086
                        msginfo = g_hash_table_lookup
1087
                                (msg_table, GUINT_TO_POINTER(num));
1088
1089
                        if (msginfo) {
1090
                                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_CACHED);
1091
                        } else {
1092
                                /* not found in the cache (uncached message) */
1093
                                msginfo = mh_parse_msg(d->d_name, item);
1094
                                if (!msginfo) continue;
1095
1096
                                if (!newlist)
1097
                                        last = newlist =
1098
                                                g_slist_append(NULL, msginfo);
1099
                                else {
1100
                                        last = g_slist_append(last, msginfo);
1101
                                        last = last->next;
1102
                                }
1103
                                n_newmsg++;
1104
                        }
1105
                }
1106
        } else {
1107
                /* discard all previous cache */
1108
                while ((d = readdir(dp)) != NULL) {
1109
                        if (to_number(d->d_name) <= 0) continue;
1110
1111
                        msginfo = mh_parse_msg(d->d_name, item);
1112
                        if (!msginfo) continue;
1113
1114
                        if (!newlist)
1115
                                last = newlist = g_slist_append(NULL, msginfo);
1116
                        else {
1117
                                last = g_slist_append(last, msginfo);
1118
                                last = last->next;
1119
                        }
1120
                        n_newmsg++;
1121
                }
1122
        }
1123
1124
        closedir(dp);
1125
1126
        if (n_newmsg)
1127
                debug_print("%d uncached message(s) found.\n", n_newmsg);
1128
        else
1129
                debug_print("done.\n");
1130
1131
        /* sort new messages in numerical order */
1132
        if (newlist && item->sort_key == SORT_BY_NONE) {
1133
                debug_print("Sorting uncached messages in numerical order...\n");
1134
                newlist = g_slist_sort
1135
                        (newlist, (GCompareFunc)procmsg_cmp_msgnum_for_sort);
1136
                debug_print("done.\n");
1137
        }
1138
1139
        return newlist;
1140
}
1141
1142
static MsgInfo *mh_parse_msg(const gchar *file, FolderItem *item)
1143
{
1144
        MsgInfo *msginfo;
1145
        MsgFlags flags;
1146
1147
        g_return_val_if_fail(item != NULL, NULL);
1148
        g_return_val_if_fail(file != NULL, NULL);
1149
1150
        flags.perm_flags = MSG_NEW|MSG_UNREAD;
1151
        flags.tmp_flags = 0;
1152
1153
        if (item->stype == F_QUEUE) {
1154
                MSG_SET_TMP_FLAGS(flags, MSG_QUEUED);
1155
        } else if (item->stype == F_DRAFT) {
1156
                MSG_SET_TMP_FLAGS(flags, MSG_DRAFT);
1157
        }
1158
1159
        msginfo = procheader_parse_file(file, flags, FALSE);
1160
        if (!msginfo) return NULL;
1161
1162
        msginfo->msgnum = atoi(file);
1163
        msginfo->folder = item;
1164
1165
        return msginfo;
1166
}
1167
1168
#if 0
1169
static gboolean mh_is_maildir_one(const gchar *path, const gchar *dir)
1170
{
1171
        gchar *entry;
1172
        gboolean result;
1173
1174
        entry = g_strconcat(path, G_DIR_SEPARATOR_S, dir, NULL);
1175
        result = is_dir_exist(entry);
1176
        g_free(entry);
1177
1178
        return result;
1179
}
1180
1181
/*
1182
 * check whether PATH is a Maildir style mailbox.
1183
 * This is the case if the 3 subdir: new, cur, tmp are existing.
1184
 * This functon assumes that entry is an directory
1185
 */
1186
static gboolean mh_is_maildir(const gchar *path)
1187
{
1188
        return mh_is_maildir_one(path, "new") &&
1189
               mh_is_maildir_one(path, "cur") &&
1190
               mh_is_maildir_one(path, "tmp");
1191
}
1192
#endif
1193
1194
static gboolean mh_remove_missing_folder_items_func(GNode *node, gpointer data)
1195
{
1196
        FolderItem *item;
1197
        gchar *path;
1198
1199
        g_return_val_if_fail(node->data != NULL, FALSE);
1200
1201
        if (G_NODE_IS_ROOT(node))
1202
                return FALSE;
1203
1204
        item = FOLDER_ITEM(node->data);
1205
1206
        path = folder_item_get_path(item);
1207
        if (!is_dir_exist(path)) {
1208
                debug_print("folder '%s' not found. removing...\n", path);
1209
                folder_item_remove(item);
1210
        }
1211
        g_free(path);
1212
1213
        return FALSE;
1214
}
1215
1216
static void mh_remove_missing_folder_items(Folder *folder)
1217
{
1218
        g_return_if_fail(folder != NULL);
1219
1220
        debug_print("searching missing folders...\n");
1221
1222
        g_node_traverse(folder->node, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1223
                        mh_remove_missing_folder_items_func, folder);
1224
}
1225
1226
static void mh_scan_tree_recursive(FolderItem *item)
1227
{
1228
        Folder *folder;
1229
#ifdef G_OS_WIN32
1230
        GDir *dir;
1231
#else
1232
        DIR *dp;
1233
        struct dirent *d;
1234
#endif
1235
        const gchar *dir_name;
1236
        struct stat s;
1237
        gchar *fs_path;
1238
        gchar *entry;
1239
        gchar *utf8entry;
1240
        gchar *utf8name;
1241
        gint n_msg = 0;
1242
1243
        g_return_if_fail(item != NULL);
1244
        g_return_if_fail(item->folder != NULL);
1245
1246
        folder = item->folder;
1247
1248
        fs_path = item->path ?
1249
                g_filename_from_utf8(item->path, -1, NULL, NULL, NULL)
1250
                : g_strdup(".");
1251
        if (!fs_path)
1252
                fs_path = g_strdup(item->path);
1253
#ifdef G_OS_WIN32
1254
        dir = g_dir_open(fs_path, 0, NULL);
1255
        if (!dir) {
1256
                g_warning("failed to open directory: %s\n", fs_path);
1257
                g_free(fs_path);
1258
                return;
1259
        }
1260
#else
1261
        dp = opendir(fs_path);
1262
        if (!dp) {
1263
                FILE_OP_ERROR(fs_path, "opendir");
1264
                g_free(fs_path);
1265
                return;
1266
        }
1267
#endif
1268
        g_free(fs_path);
1269
1270
        debug_print("scanning %s ...\n",
1271
                    item->path ? item->path
1272
                    : LOCAL_FOLDER(item->folder)->rootpath);
1273
        if (folder->ui_func)
1274
                folder->ui_func(folder, item, folder->ui_func_data);
1275
1276
#ifdef G_OS_WIN32
1277
        while ((dir_name = g_dir_read_name(dir)) != NULL) {
1278
#else
1279
        while ((d = readdir(dp)) != NULL) {
1280
                dir_name = d->d_name;
1281
#endif
1282
                if (dir_name[0] == '.') continue;
1283
1284
                utf8name = g_filename_to_utf8(dir_name, -1, NULL, NULL, NULL);
1285
                if (!utf8name)
1286
                        utf8name = g_strdup(dir_name);
1287
1288
                if (item->path)
1289
                        utf8entry = g_strconcat(item->path, G_DIR_SEPARATOR_S,
1290
                                                utf8name, NULL);
1291
                else
1292
                        utf8entry = g_strdup(utf8name);
1293
                entry = g_filename_from_utf8(utf8entry, -1, NULL, NULL, NULL);
1294
                if (!entry)
1295
                        entry = g_strdup(utf8entry);
1296
1297
                if (
1298
#if !defined(G_OS_WIN32) && defined(HAVE_DIRENT_D_TYPE)
1299
                        d->d_type == DT_DIR ||
1300
                        (d->d_type == DT_UNKNOWN &&
1301
#endif
1302
                        g_stat(entry, &s) == 0 && S_ISDIR(s.st_mode)
1303
#if !defined(G_OS_WIN32) && defined(HAVE_DIRENT_D_TYPE)
1304
                        )
1305
#endif
1306
                   ) {
1307
                        FolderItem *new_item = NULL;
1308
                        GNode *node;
1309
1310
#if 0
1311
                        if (mh_is_maildir(entry)) {
1312
                                g_free(entry);
1313
                                g_free(utf8entry);
1314
                                g_free(utf8name);
1315
                                continue;
1316
                        }
1317
#endif
1318
1319
#ifndef G_OS_WIN32
1320
                        if (g_utf8_validate(utf8name, -1, NULL) == FALSE) {
1321
                                g_warning(_("Directory name\n"
1322
                                            "'%s' is not a valid UTF-8 string.\n"
1323
                                            "Maybe the locale encoding is used for filename.\n"
1324
                                            "If that is the case, you must set the following environmental variable\n"
1325
                                            "(see README for detail):\n"
1326
                                            "\n"
1327
                                            "\tG_FILENAME_ENCODING=@locale\n"),
1328
                                          utf8name);
1329
                                g_free(entry);
1330
                                g_free(utf8entry);
1331
                                g_free(utf8name);
1332
                                continue;
1333
                        }
1334
#endif /* G_OS_WIN32 */
1335
1336
                        node = item->node;
1337
                        for (node = node->children; node != NULL; node = node->next) {
1338
                                FolderItem *cur_item = FOLDER_ITEM(node->data);
1339
                                if (!strcmp2(cur_item->path, utf8entry)) {
1340
                                        new_item = cur_item;
1341
                                        break;
1342
                                }
1343
                        }
1344
                        if (!new_item) {
1345
                                debug_print("new folder '%s' found.\n", entry);
1346
                                new_item = folder_item_new(utf8name, utf8entry);
1347
                                folder_item_append(item, new_item);
1348
                        }
1349
1350
                        if (!item->path) {
1351
                                if (!folder->inbox &&
1352
                                    !strcmp(dir_name, INBOX_DIR)) {
1353
                                        new_item->stype = F_INBOX;
1354
                                        folder->inbox = new_item;
1355
                                } else if (!folder->outbox &&
1356
                                           !strcmp(dir_name, OUTBOX_DIR)) {
1357
                                        new_item->stype = F_OUTBOX;
1358
                                        folder->outbox = new_item;
1359
                                } else if (!folder->draft &&
1360
                                           !strcmp(dir_name, DRAFT_DIR)) {
1361
                                        new_item->stype = F_DRAFT;
1362
                                        folder->draft = new_item;
1363
                                } else if (!folder->queue &&
1364
                                           !strcmp(dir_name, QUEUE_DIR)) {
1365
                                        new_item->stype = F_QUEUE;
1366
                                        folder->queue = new_item;
1367
                                } else if (!folder->trash &&
1368
                                           !strcmp(dir_name, TRASH_DIR)) {
1369
                                        new_item->stype = F_TRASH;
1370
                                        folder->trash = new_item;
1371
                                }
1372
                        }
1373
1374
                        mh_scan_tree_recursive(new_item);
1375
                } else if (to_number(dir_name) > 0) n_msg++;
1376
1377
                g_free(entry);
1378
                g_free(utf8entry);
1379
                g_free(utf8name);
1380
        }
1381
1382
#ifdef G_OS_WIN32
1383
        g_dir_close(dir);
1384
#else
1385
        closedir(dp);
1386
#endif
1387
1388
        if (item->path) {
1389
                gint new, unread, total, min, max;
1390
1391
                procmsg_get_mark_sum
1392
                        (item, &new, &unread, &total, &min, &max, 0);
1393
                if (n_msg > total) {
1394
                        new += n_msg - total;
1395
                        unread += n_msg - total;
1396
                }
1397
                item->new = new;
1398
                item->unread = unread;
1399
                item->total = n_msg;
1400
                item->updated = TRUE;
1401
        }
1402
}
1403
1404
static gboolean mh_rename_folder_func(GNode *node, gpointer data)
1405
{
1406
        FolderItem *item = node->data;
1407
        gchar **paths = data;
1408
        const gchar *oldpath = paths[0];
1409
        const gchar *newpath = paths[1];
1410
        gchar *base;
1411
        gchar *new_itempath;
1412
        gint oldpathlen;
1413
1414
        oldpathlen = strlen(oldpath);
1415
        if (strncmp(oldpath, item->path, oldpathlen) != 0) {
1416
                g_warning("path doesn't match: %s, %s\n", oldpath, item->path);
1417
                return TRUE;
1418
        }
1419
1420
        base = item->path + oldpathlen;
1421
        while (*base == G_DIR_SEPARATOR) base++;
1422
        if (*base == '\0')
1423
                new_itempath = g_strdup(newpath);
1424
        else
1425
                new_itempath = g_strconcat(newpath, G_DIR_SEPARATOR_S, base,
1426
                                           NULL);
1427
        g_free(item->path);
1428
        item->path = new_itempath;
1429
1430
        return FALSE;
1431
}