Statistics
| Revision:

root / src / mh.c @ 206

History | View | Annotate | Download (28.3 kB)

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