Statistics
| Revision:

root / libsylph / mh.c @ 2326

History | View | Annotate | Download (41.9 kB)

1 1 hiro
/*
2 578 hiro
 * LibSylph -- E-Mail client library
3 2209 hiro
 * Copyright (C) 1999-2009 Hiroyuki Yamamoto
4 1 hiro
 *
5 578 hiro
 * This library is free software; you can redistribute it and/or
6 578 hiro
 * modify it under the terms of the GNU Lesser General Public
7 578 hiro
 * License as published by the Free Software Foundation; either
8 578 hiro
 * version 2.1 of the License, or (at your option) any later version.
9 1 hiro
 *
10 578 hiro
 * This library is distributed in the hope that it will be useful,
11 1 hiro
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 578 hiro
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 578 hiro
 * Lesser General Public License for more details.
14 1 hiro
 *
15 578 hiro
 * You should have received a copy of the GNU Lesser General Public
16 578 hiro
 * License along with this library; if not, write to the Free Software
17 578 hiro
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  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 461 hiro
#include <time.h>
31 1 hiro
#include <unistd.h>
32 1 hiro
#include <string.h>
33 1 hiro
#include <errno.h>
34 1 hiro
35 1084 Hiro
#ifdef G_OS_WIN32
36 1084 Hiro
#  include <windows.h>
37 1084 Hiro
#endif
38 1084 Hiro
39 462 hiro
#undef MEASURE_TIME
40 1 hiro
41 2164 hiro
#include "sylmain.h"
42 1 hiro
#include "folder.h"
43 1 hiro
#include "mh.h"
44 1 hiro
#include "procmsg.h"
45 1 hiro
#include "procheader.h"
46 1 hiro
#include "utils.h"
47 360 hiro
#include "prefs_common.h"
48 1 hiro
49 2274 hiro
#if USE_THREADS
50 2274 hiro
G_LOCK_DEFINE_STATIC(mh);
51 2274 hiro
#define S_LOCK(name)        {G_LOCK(name); g_print("mh: lock\n");}
52 2274 hiro
#define S_UNLOCK(name)        {G_UNLOCK(name); g_print("mh: unlock\n");}
53 2274 hiro
#else
54 2274 hiro
#define S_LOCK(name)
55 2274 hiro
#define S_UNLOCK(name)
56 2274 hiro
#endif
57 2274 hiro
58 1 hiro
static void        mh_folder_init                (Folder                *folder,
59 1 hiro
                                         const gchar        *name,
60 1 hiro
                                         const gchar        *path);
61 1 hiro
62 1 hiro
static Folder        *mh_folder_new                (const gchar        *name,
63 1 hiro
                                         const gchar        *path);
64 1 hiro
static void     mh_folder_destroy        (Folder                *folder);
65 1 hiro
66 1 hiro
static GSList  *mh_get_msg_list                (Folder                *folder,
67 1 hiro
                                         FolderItem        *item,
68 1 hiro
                                         gboolean         use_cache);
69 1491 hiro
static GSList  *mh_get_uncached_msg_list(Folder                *folder,
70 1491 hiro
                                         FolderItem        *item);
71 1 hiro
static gchar   *mh_fetch_msg                (Folder                *folder,
72 1 hiro
                                         FolderItem        *item,
73 1 hiro
                                         gint                 num);
74 1 hiro
static MsgInfo *mh_get_msginfo                (Folder                *folder,
75 1 hiro
                                         FolderItem        *item,
76 1 hiro
                                         gint                 num);
77 1 hiro
static gint     mh_add_msg                (Folder                *folder,
78 1 hiro
                                         FolderItem        *dest,
79 1 hiro
                                         const gchar        *file,
80 1 hiro
                                         MsgFlags        *flags,
81 1 hiro
                                         gboolean         remove_source);
82 1 hiro
static gint     mh_add_msgs                (Folder                *folder,
83 1 hiro
                                         FolderItem        *dest,
84 1 hiro
                                         GSList                *file_list,
85 1 hiro
                                         gboolean         remove_source,
86 1 hiro
                                         gint                *first);
87 2247 hiro
static gint     mh_add_msg_msginfo        (Folder                *folder,
88 2247 hiro
                                         FolderItem        *dest,
89 2247 hiro
                                         MsgInfo        *msginfo,
90 2247 hiro
                                         gboolean         remove_source);
91 2247 hiro
static gint     mh_add_msgs_msginfo        (Folder                *folder,
92 2247 hiro
                                         FolderItem        *dest,
93 2247 hiro
                                         GSList                *msglist,
94 2247 hiro
                                         gboolean         remove_source,
95 2247 hiro
                                         gint                *first);
96 1 hiro
static gint     mh_move_msg                (Folder                *folder,
97 1 hiro
                                         FolderItem        *dest,
98 1 hiro
                                         MsgInfo        *msginfo);
99 1 hiro
static gint     mh_move_msgs                (Folder                *folder,
100 1 hiro
                                         FolderItem        *dest,
101 1 hiro
                                         GSList                *msglist);
102 1 hiro
static gint     mh_copy_msg                (Folder                *folder,
103 1 hiro
                                         FolderItem        *dest,
104 1 hiro
                                         MsgInfo        *msginfo);
105 1 hiro
static gint     mh_copy_msgs                (Folder                *folder,
106 1 hiro
                                         FolderItem        *dest,
107 1 hiro
                                         GSList                *msglist);
108 1 hiro
static gint     mh_remove_msg                (Folder                *folder,
109 1 hiro
                                         FolderItem        *item,
110 1 hiro
                                         MsgInfo        *msginfo);
111 1 hiro
static gint     mh_remove_all_msg        (Folder                *folder,
112 1 hiro
                                         FolderItem        *item);
113 1 hiro
static gboolean mh_is_msg_changed        (Folder                *folder,
114 1 hiro
                                         FolderItem        *item,
115 1 hiro
                                         MsgInfo        *msginfo);
116 1 hiro
static gint    mh_close                        (Folder                *folder,
117 1 hiro
                                         FolderItem        *item);
118 1 hiro
119 1 hiro
static gint    mh_scan_folder_full        (Folder                *folder,
120 1 hiro
                                         FolderItem        *item,
121 1 hiro
                                         gboolean         count_sum);
122 1 hiro
static gint    mh_scan_folder                (Folder                *folder,
123 1 hiro
                                         FolderItem        *item);
124 1 hiro
static gint    mh_scan_tree                (Folder                *folder);
125 1 hiro
126 1 hiro
static gint    mh_create_tree                (Folder                *folder);
127 1 hiro
static FolderItem *mh_create_folder        (Folder                *folder,
128 1 hiro
                                         FolderItem        *parent,
129 1 hiro
                                         const gchar        *name);
130 1 hiro
static gint    mh_rename_folder                (Folder                *folder,
131 1 hiro
                                         FolderItem        *item,
132 1 hiro
                                         const gchar        *name);
133 389 hiro
static gint    mh_move_folder                (Folder                *folder,
134 389 hiro
                                         FolderItem        *item,
135 389 hiro
                                         FolderItem        *new_parent);
136 1 hiro
static gint    mh_remove_folder                (Folder                *folder,
137 1 hiro
                                         FolderItem        *item);
138 1 hiro
139 1 hiro
static gchar   *mh_get_new_msg_filename                (FolderItem        *dest);
140 1 hiro
141 1 hiro
static gint        mh_do_move_msgs                        (Folder                *folder,
142 1 hiro
                                                 FolderItem        *dest,
143 1 hiro
                                                 GSList                *msglist);
144 1 hiro
145 1 hiro
static time_t  mh_get_mtime                        (FolderItem        *item);
146 1 hiro
static GSList  *mh_get_uncached_msgs                (GHashTable        *msg_table,
147 1 hiro
                                                 FolderItem        *item);
148 1 hiro
static MsgInfo *mh_parse_msg                        (const gchar        *file,
149 1 hiro
                                                 FolderItem        *item);
150 1 hiro
static void        mh_remove_missing_folder_items        (Folder                *folder);
151 1 hiro
static void        mh_scan_tree_recursive                (FolderItem        *item);
152 1 hiro
153 1 hiro
static gboolean mh_rename_folder_func                (GNode                *node,
154 1 hiro
                                                 gpointer         data);
155 1 hiro
156 1 hiro
static FolderClass mh_class =
157 1 hiro
{
158 1 hiro
        F_MH,
159 1 hiro
160 1 hiro
        mh_folder_new,
161 1 hiro
        mh_folder_destroy,
162 1 hiro
163 1 hiro
        mh_scan_tree,
164 1 hiro
        mh_create_tree,
165 1 hiro
166 1 hiro
        mh_get_msg_list,
167 1491 hiro
        mh_get_uncached_msg_list,
168 1 hiro
        mh_fetch_msg,
169 1 hiro
        mh_get_msginfo,
170 1 hiro
        mh_add_msg,
171 1 hiro
        mh_add_msgs,
172 2247 hiro
        mh_add_msg_msginfo,
173 2247 hiro
        mh_add_msgs_msginfo,
174 1 hiro
        mh_move_msg,
175 1 hiro
        mh_move_msgs,
176 1 hiro
        mh_copy_msg,
177 1 hiro
        mh_copy_msgs,
178 1 hiro
        mh_remove_msg,
179 1 hiro
        NULL,
180 1 hiro
        mh_remove_all_msg,
181 1 hiro
        mh_is_msg_changed,
182 1 hiro
        mh_close,
183 1 hiro
        mh_scan_folder,
184 1 hiro
185 1 hiro
        mh_create_folder,
186 1 hiro
        mh_rename_folder,
187 389 hiro
        mh_move_folder,
188 1 hiro
        mh_remove_folder,
189 1 hiro
};
190 1 hiro
191 1 hiro
192 1 hiro
FolderClass *mh_get_class(void)
193 1 hiro
{
194 1 hiro
        return &mh_class;
195 1 hiro
}
196 1 hiro
197 1 hiro
static Folder *mh_folder_new(const gchar *name, const gchar *path)
198 1 hiro
{
199 1 hiro
        Folder *folder;
200 1 hiro
201 1 hiro
        folder = (Folder *)g_new0(MHFolder, 1);
202 1 hiro
        mh_folder_init(folder, name, path);
203 1 hiro
204 1 hiro
        return folder;
205 1 hiro
}
206 1 hiro
207 1 hiro
static void mh_folder_destroy(Folder *folder)
208 1 hiro
{
209 1 hiro
        folder_local_folder_destroy(LOCAL_FOLDER(folder));
210 1 hiro
}
211 1 hiro
212 1 hiro
static void mh_folder_init(Folder *folder, const gchar *name, const gchar *path)
213 1 hiro
{
214 1 hiro
        folder->klass = mh_get_class();
215 1 hiro
        folder_local_folder_init(folder, name, path);
216 1 hiro
}
217 1 hiro
218 1491 hiro
static GSList *mh_get_msg_list_full(Folder *folder, FolderItem *item,
219 1491 hiro
                                    gboolean use_cache, gboolean uncached_only)
220 1 hiro
{
221 1 hiro
        GSList *mlist;
222 1 hiro
        GHashTable *msg_table;
223 1 hiro
        time_t cur_mtime;
224 1491 hiro
        GSList *newlist = NULL;
225 1 hiro
#ifdef MEASURE_TIME
226 461 hiro
        GTimer *timer;
227 1 hiro
#endif
228 1 hiro
229 1 hiro
        g_return_val_if_fail(item != NULL, NULL);
230 1 hiro
231 2274 hiro
        S_LOCK(mh)
232 2274 hiro
233 461 hiro
#ifdef MEASURE_TIME
234 461 hiro
        timer = g_timer_new();
235 461 hiro
#endif
236 461 hiro
237 1 hiro
        cur_mtime = mh_get_mtime(item);
238 1 hiro
239 1 hiro
        if (use_cache && item->mtime == cur_mtime) {
240 1 hiro
                debug_print("Folder is not modified.\n");
241 1 hiro
                mlist = procmsg_read_cache(item, FALSE);
242 285 hiro
                if (!mlist) {
243 1 hiro
                        mlist = mh_get_uncached_msgs(NULL, item);
244 285 hiro
                        if (mlist)
245 285 hiro
                                item->cache_dirty = TRUE;
246 285 hiro
                }
247 1 hiro
        } else if (use_cache) {
248 1491 hiro
                GSList *cur, *next;
249 444 hiro
                gboolean strict_cache_check = prefs_common.strict_cache_check;
250 1 hiro
251 444 hiro
                if (item->stype == F_QUEUE || item->stype == F_DRAFT)
252 444 hiro
                        strict_cache_check = TRUE;
253 444 hiro
254 444 hiro
                mlist = procmsg_read_cache(item, strict_cache_check);
255 1 hiro
                msg_table = procmsg_msg_hash_table_create(mlist);
256 1 hiro
                newlist = mh_get_uncached_msgs(msg_table, item);
257 285 hiro
                if (newlist)
258 285 hiro
                        item->cache_dirty = TRUE;
259 1 hiro
                if (msg_table)
260 1 hiro
                        g_hash_table_destroy(msg_table);
261 1 hiro
262 444 hiro
                if (!strict_cache_check) {
263 360 hiro
                        /* remove nonexistent messages */
264 360 hiro
                        for (cur = mlist; cur != NULL; cur = next) {
265 360 hiro
                                MsgInfo *msginfo = (MsgInfo *)cur->data;
266 360 hiro
                                next = cur->next;
267 360 hiro
                                if (!MSG_IS_CACHED(msginfo->flags)) {
268 360 hiro
                                        debug_print("removing nonexistent message %d from cache\n", msginfo->msgnum);
269 360 hiro
                                        mlist = g_slist_remove(mlist, msginfo);
270 360 hiro
                                        procmsg_msginfo_free(msginfo);
271 360 hiro
                                        item->cache_dirty = TRUE;
272 360 hiro
                                        item->mark_dirty = TRUE;
273 360 hiro
                                }
274 360 hiro
                        }
275 360 hiro
                }
276 360 hiro
277 1 hiro
                mlist = g_slist_concat(mlist, newlist);
278 285 hiro
        } else {
279 1 hiro
                mlist = mh_get_uncached_msgs(NULL, item);
280 285 hiro
                item->cache_dirty = TRUE;
281 1491 hiro
                newlist = mlist;
282 285 hiro
        }
283 1 hiro
284 1 hiro
        procmsg_set_flags(mlist, item);
285 1 hiro
286 1576 Hiro
        if (!uncached_only)
287 1576 Hiro
                mlist = procmsg_sort_msg_list(mlist, item->sort_key,
288 1576 Hiro
                                              item->sort_type);
289 1 hiro
290 806 hiro
        if (item->mark_queue)
291 806 hiro
                item->mark_dirty = TRUE;
292 806 hiro
293 1 hiro
#ifdef MEASURE_TIME
294 461 hiro
        g_timer_stop(timer);
295 461 hiro
        g_print("%s: %s: elapsed time: %f sec\n",
296 461 hiro
                G_STRFUNC, item->path, g_timer_elapsed(timer, NULL));
297 461 hiro
        g_timer_destroy(timer);
298 1 hiro
#endif
299 293 hiro
        debug_print("cache_dirty: %d, mark_dirty: %d\n",
300 293 hiro
                    item->cache_dirty, item->mark_dirty);
301 1 hiro
302 806 hiro
        if (!item->opened) {
303 806 hiro
                item->mtime = cur_mtime;
304 806 hiro
                if (item->cache_dirty)
305 806 hiro
                        procmsg_write_cache_list(item, mlist);
306 806 hiro
                if (item->mark_dirty)
307 806 hiro
                        procmsg_write_flags_list(item, mlist);
308 806 hiro
        }
309 806 hiro
310 1491 hiro
        if (uncached_only) {
311 1491 hiro
                GSList *cur;
312 1491 hiro
313 1491 hiro
                if (newlist == NULL) {
314 1491 hiro
                        procmsg_msg_list_free(mlist);
315 2274 hiro
                        S_UNLOCK(mh)
316 1491 hiro
                        return NULL;
317 1491 hiro
                }
318 2274 hiro
                if (mlist == newlist) {
319 2274 hiro
                        S_UNLOCK(mh)
320 1491 hiro
                        return newlist;
321 2274 hiro
                }
322 1491 hiro
                for (cur = mlist; cur != NULL; cur = cur->next) {
323 1491 hiro
                        if (cur->next == newlist) {
324 1491 hiro
                                cur->next = NULL;
325 1491 hiro
                                procmsg_msg_list_free(mlist);
326 2274 hiro
                                S_UNLOCK(mh)
327 1491 hiro
                                return newlist;
328 1491 hiro
                        }
329 1491 hiro
                }
330 1491 hiro
                procmsg_msg_list_free(mlist);
331 2274 hiro
                S_UNLOCK(mh)
332 1491 hiro
                return NULL;
333 1491 hiro
        }
334 1491 hiro
335 2274 hiro
        S_UNLOCK(mh)
336 1 hiro
        return mlist;
337 1 hiro
}
338 1 hiro
339 1491 hiro
static GSList *mh_get_msg_list(Folder *folder, FolderItem *item,
340 1491 hiro
                               gboolean use_cache)
341 1491 hiro
{
342 1491 hiro
        return mh_get_msg_list_full(folder, item, use_cache, FALSE);
343 1491 hiro
}
344 1491 hiro
345 1491 hiro
static GSList *mh_get_uncached_msg_list(Folder *folder, FolderItem *item)
346 1491 hiro
{
347 1491 hiro
        return mh_get_msg_list_full(folder, item, TRUE, TRUE);
348 1491 hiro
}
349 1491 hiro
350 1 hiro
static gchar *mh_fetch_msg(Folder *folder, FolderItem *item, gint num)
351 1 hiro
{
352 1 hiro
        gchar *path;
353 1 hiro
        gchar *file;
354 2286 hiro
        gchar buf[16];
355 1 hiro
356 1 hiro
        g_return_val_if_fail(item != NULL, NULL);
357 1 hiro
        g_return_val_if_fail(num > 0, NULL);
358 1 hiro
359 1 hiro
        if (item->last_num < 0 || num > item->last_num) {
360 1 hiro
                mh_scan_folder(folder, item);
361 1 hiro
                if (item->last_num < 0) return NULL;
362 1 hiro
        }
363 1 hiro
364 1686 hiro
        if (num > item->last_num)
365 1686 hiro
                return NULL;
366 1 hiro
367 1 hiro
        path = folder_item_get_path(item);
368 2286 hiro
        file = g_strconcat(path, G_DIR_SEPARATOR_S, itos_buf(buf, num), NULL);
369 1 hiro
        g_free(path);
370 1 hiro
        if (!is_file_exist(file)) {
371 1 hiro
                g_free(file);
372 1 hiro
                return NULL;
373 1 hiro
        }
374 1 hiro
375 1 hiro
        return file;
376 1 hiro
}
377 1 hiro
378 1 hiro
static MsgInfo *mh_get_msginfo(Folder *folder, FolderItem *item, gint num)
379 1 hiro
{
380 1 hiro
        MsgInfo *msginfo;
381 1 hiro
        gchar *file;
382 1 hiro
383 1 hiro
        g_return_val_if_fail(item != NULL, NULL);
384 1 hiro
        g_return_val_if_fail(num > 0, NULL);
385 1 hiro
386 1 hiro
        file = mh_fetch_msg(folder, item, num);
387 1 hiro
        if (!file) return NULL;
388 1 hiro
389 1 hiro
        msginfo = mh_parse_msg(file, item);
390 1 hiro
        if (msginfo)
391 1 hiro
                msginfo->msgnum = num;
392 1 hiro
393 1 hiro
        g_free(file);
394 1 hiro
395 1 hiro
        return msginfo;
396 1 hiro
}
397 1 hiro
398 1 hiro
static gchar *mh_get_new_msg_filename(FolderItem *dest)
399 1 hiro
{
400 1 hiro
        gchar *destfile;
401 1 hiro
        gchar *destpath;
402 1 hiro
403 1 hiro
        destpath = folder_item_get_path(dest);
404 1 hiro
        g_return_val_if_fail(destpath != NULL, NULL);
405 1 hiro
406 1 hiro
        if (!is_dir_exist(destpath))
407 1 hiro
                make_dir_hier(destpath);
408 1 hiro
409 1 hiro
        for (;;) {
410 1 hiro
                destfile = g_strdup_printf("%s%c%d", destpath, G_DIR_SEPARATOR,
411 1 hiro
                                           dest->last_num + 1);
412 1 hiro
                if (is_file_entry_exist(destfile)) {
413 1 hiro
                        dest->last_num++;
414 1 hiro
                        g_free(destfile);
415 1 hiro
                } else
416 1 hiro
                        break;
417 1 hiro
        }
418 1 hiro
419 1 hiro
        g_free(destpath);
420 1 hiro
421 1 hiro
        return destfile;
422 1 hiro
}
423 1 hiro
424 1 hiro
#define SET_DEST_MSG_FLAGS(fp, dest, n, fl)                                \
425 1 hiro
{                                                                        \
426 1 hiro
        MsgInfo newmsginfo;                                                \
427 1 hiro
                                                                        \
428 1 hiro
        newmsginfo.msgnum = n;                                                \
429 1 hiro
        newmsginfo.flags = fl;                                                \
430 1 hiro
        if (dest->stype == F_OUTBOX ||                                        \
431 1 hiro
            dest->stype == F_QUEUE  ||                                        \
432 978 hiro
            dest->stype == F_DRAFT) {                                        \
433 1 hiro
                MSG_UNSET_PERM_FLAGS(newmsginfo.flags,                        \
434 1 hiro
                                     MSG_NEW|MSG_UNREAD|MSG_DELETED);        \
435 978 hiro
        } else if (dest->stype == F_TRASH) {                                \
436 978 hiro
                MSG_UNSET_PERM_FLAGS(newmsginfo.flags, MSG_DELETED);        \
437 978 hiro
        }                                                                \
438 1 hiro
                                                                        \
439 1 hiro
        if (fp)                                                                \
440 1 hiro
                procmsg_write_flags(&newmsginfo, fp);                        \
441 2249 hiro
        else                                                                 \
442 2249 hiro
                procmsg_add_mark_queue(dest, n, newmsginfo.flags);        \
443 1 hiro
}
444 1 hiro
445 1 hiro
static gint mh_add_msg(Folder *folder, FolderItem *dest, const gchar *file,
446 1 hiro
                       MsgFlags *flags, gboolean remove_source)
447 1 hiro
{
448 1 hiro
        GSList file_list;
449 1 hiro
        MsgFileInfo fileinfo;
450 1 hiro
451 1 hiro
        g_return_val_if_fail(file != NULL, -1);
452 1 hiro
453 1 hiro
        fileinfo.file = (gchar *)file;
454 1 hiro
        fileinfo.flags = flags;
455 1 hiro
        file_list.data = &fileinfo;
456 1 hiro
        file_list.next = NULL;
457 1 hiro
458 1 hiro
        return mh_add_msgs(folder, dest, &file_list, remove_source, NULL);
459 1 hiro
}
460 1 hiro
461 1 hiro
static gint mh_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
462 1 hiro
                        gboolean remove_source, gint *first)
463 1 hiro
{
464 1 hiro
        gchar *destfile;
465 1 hiro
        GSList *cur;
466 1 hiro
        MsgFileInfo *fileinfo;
467 2253 hiro
        MsgInfo *msginfo;
468 1 hiro
        gint first_ = 0;
469 2253 hiro
        FILE *fp = NULL;
470 1 hiro
471 1 hiro
        g_return_val_if_fail(dest != NULL, -1);
472 1 hiro
        g_return_val_if_fail(file_list != NULL, -1);
473 1 hiro
474 1 hiro
        if (dest->last_num < 0) {
475 1 hiro
                mh_scan_folder(folder, dest);
476 1 hiro
                if (dest->last_num < 0) return -1;
477 1 hiro
        }
478 1 hiro
479 2274 hiro
        S_LOCK(mh)
480 2274 hiro
481 2253 hiro
        if (!dest->opened) {
482 2253 hiro
                if ((fp = procmsg_open_mark_file(dest, DATA_APPEND)) == NULL)
483 2253 hiro
                        g_warning("mh_add_msgs: can't open mark file.");
484 2253 hiro
        }
485 1 hiro
486 1 hiro
        for (cur = file_list; cur != NULL; cur = cur->next) {
487 2253 hiro
                MsgFlags flags = {MSG_NEW|MSG_UNREAD, 0};
488 2253 hiro
489 1 hiro
                fileinfo = (MsgFileInfo *)cur->data;
490 2253 hiro
                if (fileinfo->flags)
491 2253 hiro
                        flags = *fileinfo->flags;
492 2253 hiro
                msginfo = procheader_parse_file(fileinfo->file, flags, 0);
493 2253 hiro
                if (!msginfo) {
494 2253 hiro
                        if (fp) fclose(fp);
495 2274 hiro
                        S_UNLOCK(mh);
496 2253 hiro
                        return -1;
497 2253 hiro
                }
498 1 hiro
499 1 hiro
                destfile = mh_get_new_msg_filename(dest);
500 2274 hiro
                if (destfile == NULL) {
501 2274 hiro
                        S_UNLOCK(mh);
502 2253 hiro
                        return -1;
503 2274 hiro
                }
504 1 hiro
                if (first_ == 0 || first_ > dest->last_num + 1)
505 1 hiro
                        first_ = dest->last_num + 1;
506 1 hiro
507 2120 hiro
                if (syl_link(fileinfo->file, destfile) < 0) {
508 1 hiro
                        if (copy_file(fileinfo->file, destfile, TRUE) < 0) {
509 1 hiro
                                g_warning(_("can't copy message %s to %s\n"),
510 1 hiro
                                          fileinfo->file, destfile);
511 1 hiro
                                g_free(destfile);
512 2253 hiro
                                if (fp) fclose(fp);
513 2274 hiro
                                S_UNLOCK(mh);
514 1 hiro
                                return -1;
515 1 hiro
                        }
516 1 hiro
                }
517 1 hiro
518 2164 hiro
                g_signal_emit_by_name(syl_app_get(), "add-msg", dest, destfile, dest->last_num + 1);
519 2164 hiro
520 1 hiro
                g_free(destfile);
521 1 hiro
                dest->last_num++;
522 1 hiro
                dest->total++;
523 1 hiro
                dest->updated = TRUE;
524 744 hiro
                dest->mtime = 0;
525 1 hiro
526 2253 hiro
                if (MSG_IS_RECEIVED(flags)) {
527 2253 hiro
                        /* resets new flags of existing messages on
528 2253 hiro
                           received mode */
529 1 hiro
                        if (dest->unmarked_num == 0)
530 1 hiro
                                dest->new = 0;
531 1 hiro
                        dest->unmarked_num++;
532 2253 hiro
                        procmsg_add_mark_queue(dest, dest->last_num, flags);
533 2253 hiro
                } else {
534 2253 hiro
                        SET_DEST_MSG_FLAGS(fp, dest, dest->last_num, flags);
535 2253 hiro
                }
536 2253 hiro
                procmsg_add_cache_queue(dest, dest->last_num, msginfo);
537 2253 hiro
                if (MSG_IS_NEW(flags))
538 1 hiro
                        dest->new++;
539 2253 hiro
                if (MSG_IS_UNREAD(flags))
540 1 hiro
                        dest->unread++;
541 1 hiro
        }
542 1 hiro
543 2253 hiro
        if (fp)
544 2253 hiro
                fclose(fp);
545 1 hiro
546 1 hiro
        if (first)
547 1 hiro
                *first = first_;
548 1 hiro
549 1 hiro
        if (remove_source) {
550 1 hiro
                for (cur = file_list; cur != NULL; cur = cur->next) {
551 1 hiro
                        fileinfo = (MsgFileInfo *)cur->data;
552 478 hiro
                        if (g_unlink(fileinfo->file) < 0)
553 1 hiro
                                FILE_OP_ERROR(fileinfo->file, "unlink");
554 1 hiro
                }
555 1 hiro
        }
556 1 hiro
557 2274 hiro
        S_UNLOCK(mh);
558 1 hiro
        return dest->last_num;
559 1 hiro
}
560 1 hiro
561 2247 hiro
562 2247 hiro
static gint mh_add_msg_msginfo(Folder *folder, FolderItem *dest,
563 2247 hiro
                               MsgInfo *msginfo, gboolean remove_source)
564 2247 hiro
{
565 2247 hiro
        GSList msglist;
566 2247 hiro
567 2247 hiro
        g_return_val_if_fail(msginfo != NULL, -1);
568 2247 hiro
569 2247 hiro
        msglist.data = msginfo;
570 2247 hiro
        msglist.next = NULL;
571 2247 hiro
572 2247 hiro
        return mh_add_msgs_msginfo(folder, dest, &msglist, remove_source, NULL);
573 2247 hiro
}
574 2247 hiro
575 2247 hiro
static gint mh_add_msgs_msginfo(Folder *folder, FolderItem *dest,
576 2247 hiro
                                GSList *msglist, gboolean remove_source,
577 2247 hiro
                                gint *first)
578 2247 hiro
{
579 2247 hiro
        GSList *cur;
580 2247 hiro
        MsgInfo *msginfo;
581 2247 hiro
        gchar *srcfile;
582 2247 hiro
        gchar *destfile;
583 2247 hiro
        gint first_ = 0;
584 2247 hiro
        FILE *fp = NULL;
585 2247 hiro
586 2247 hiro
        g_return_val_if_fail(dest != NULL, -1);
587 2247 hiro
        g_return_val_if_fail(msglist != NULL, -1);
588 2247 hiro
589 2247 hiro
        if (dest->last_num < 0) {
590 2247 hiro
                mh_scan_folder(folder, dest);
591 2247 hiro
                if (dest->last_num < 0) return -1;
592 2247 hiro
        }
593 2247 hiro
594 2274 hiro
        S_LOCK(mh);
595 2274 hiro
596 2247 hiro
        if (!dest->opened) {
597 2247 hiro
                if ((fp = procmsg_open_mark_file(dest, DATA_APPEND)) == NULL)
598 2247 hiro
                        g_warning("mh_add_msgs_msginfo: can't open mark file.");
599 2247 hiro
        }
600 2247 hiro
601 2247 hiro
        for (cur = msglist; cur != NULL; cur = cur->next) {
602 2247 hiro
                msginfo = (MsgInfo *)cur->data;
603 2247 hiro
604 2247 hiro
                destfile = mh_get_new_msg_filename(dest);
605 2247 hiro
                if (!destfile) {
606 2247 hiro
                        if (fp) fclose(fp);
607 2274 hiro
                        S_UNLOCK(mh);
608 2247 hiro
                        return -1;
609 2247 hiro
                }
610 2247 hiro
                if (first_ == 0 || first_ > dest->last_num + 1)
611 2247 hiro
                        first_ = dest->last_num + 1;
612 2247 hiro
613 2247 hiro
                srcfile = procmsg_get_message_file(msginfo);
614 2247 hiro
                if (!srcfile) {
615 2247 hiro
                        if (fp) fclose(fp);
616 2247 hiro
                        g_free(destfile);
617 2274 hiro
                        S_UNLOCK(mh);
618 2247 hiro
                        return -1;
619 2247 hiro
                }
620 2247 hiro
                if (syl_link(srcfile, destfile) < 0) {
621 2247 hiro
                        if (copy_file(srcfile, destfile, TRUE) < 0) {
622 2247 hiro
                                g_warning("mh_add_msgs_msginfo: can't copy message %s to %s", srcfile, destfile);
623 2247 hiro
                                g_free(srcfile);
624 2247 hiro
                                g_free(destfile);
625 2247 hiro
                                if (fp) fclose(fp);
626 2274 hiro
                                S_UNLOCK(mh);
627 2247 hiro
                                return -1;
628 2247 hiro
                        }
629 2247 hiro
                }
630 2247 hiro
631 2247 hiro
                g_signal_emit_by_name(syl_app_get(), "add-msg", dest, destfile, dest->last_num + 1);
632 2247 hiro
633 2247 hiro
                g_free(srcfile);
634 2247 hiro
                g_free(destfile);
635 2247 hiro
                dest->last_num++;
636 2247 hiro
                dest->total++;
637 2247 hiro
                dest->updated = TRUE;
638 2247 hiro
                dest->mtime = 0;
639 2247 hiro
640 2247 hiro
                if (MSG_IS_RECEIVED(msginfo->flags)) {
641 2253 hiro
                        /* resets new flags of existing messages on
642 2253 hiro
                           received mode */
643 2247 hiro
                        if (dest->unmarked_num == 0)
644 2247 hiro
                                dest->new = 0;
645 2247 hiro
                        dest->unmarked_num++;
646 2247 hiro
                        procmsg_add_mark_queue(dest, dest->last_num,
647 2247 hiro
                                               msginfo->flags);
648 2247 hiro
                } else {
649 2247 hiro
                        SET_DEST_MSG_FLAGS(fp, dest, dest->last_num,
650 2247 hiro
                                           msginfo->flags);
651 2247 hiro
                }
652 2253 hiro
                procmsg_add_cache_queue(dest, dest->last_num, msginfo);
653 2247 hiro
                if (MSG_IS_NEW(msginfo->flags))
654 2247 hiro
                        dest->new++;
655 2247 hiro
                if (MSG_IS_UNREAD(msginfo->flags))
656 2247 hiro
                        dest->unread++;
657 2247 hiro
        }
658 2247 hiro
659 2253 hiro
        if (fp)
660 2253 hiro
                fclose(fp);
661 2247 hiro
662 2247 hiro
        if (first)
663 2247 hiro
                *first = first_;
664 2247 hiro
665 2247 hiro
        if (remove_source) {
666 2247 hiro
                for (cur = msglist; cur != NULL; cur = cur->next) {
667 2247 hiro
                        msginfo = (MsgInfo *)cur->data;
668 2247 hiro
                        srcfile = procmsg_get_message_file(msginfo);
669 2247 hiro
                        if (g_unlink(srcfile) < 0)
670 2247 hiro
                                FILE_OP_ERROR(srcfile, "unlink");
671 2247 hiro
                        g_free(srcfile);
672 2247 hiro
                }
673 2247 hiro
        }
674 2247 hiro
675 2274 hiro
        S_UNLOCK(mh);
676 2247 hiro
        return dest->last_num;
677 2247 hiro
}
678 2247 hiro
679 2247 hiro
680 1 hiro
static gint mh_do_move_msgs(Folder *folder, FolderItem *dest, GSList *msglist)
681 1 hiro
{
682 1 hiro
        FolderItem *src;
683 1 hiro
        gchar *srcfile;
684 1 hiro
        gchar *destfile;
685 1 hiro
        GSList *cur;
686 1 hiro
        MsgInfo *msginfo;
687 1 hiro
688 1 hiro
        g_return_val_if_fail(dest != NULL, -1);
689 1 hiro
        g_return_val_if_fail(msglist != NULL, -1);
690 1 hiro
691 1 hiro
        if (dest->last_num < 0) {
692 1 hiro
                mh_scan_folder(folder, dest);
693 1 hiro
                if (dest->last_num < 0) return -1;
694 1 hiro
        }
695 1 hiro
696 2274 hiro
        S_LOCK(mh);
697 2274 hiro
698 1 hiro
        for (cur = msglist; cur != NULL; cur = cur->next) {
699 1 hiro
                msginfo = (MsgInfo *)cur->data;
700 1 hiro
                src = msginfo->folder;
701 1 hiro
702 1 hiro
                if (src == dest) {
703 1 hiro
                        g_warning(_("the src folder is identical to the dest.\n"));
704 1 hiro
                        continue;
705 1 hiro
                }
706 1589 hiro
                debug_print("Moving message %s/%d to %s ...\n",
707 1589 hiro
                            src->path, msginfo->msgnum, dest->path);
708 1 hiro
709 1 hiro
                destfile = mh_get_new_msg_filename(dest);
710 1 hiro
                if (!destfile) break;
711 1 hiro
                srcfile = procmsg_get_message_file(msginfo);
712 1 hiro
713 2209 hiro
                /* g_signal_emit_by_name(syl_app_get(), "remove-msg", src, srcfile, msginfo->msgnum); */
714 2164 hiro
715 1 hiro
                if (move_file(srcfile, destfile, FALSE) < 0) {
716 1 hiro
                        g_free(srcfile);
717 1 hiro
                        g_free(destfile);
718 1 hiro
                        break;
719 1 hiro
                }
720 1 hiro
721 2164 hiro
                g_signal_emit_by_name(syl_app_get(), "add-msg", dest, destfile, dest->last_num + 1);
722 2209 hiro
                g_signal_emit_by_name(syl_app_get(), "remove-msg", src, srcfile, msginfo->msgnum);
723 2164 hiro
724 1 hiro
                g_free(srcfile);
725 1 hiro
                g_free(destfile);
726 1 hiro
                src->total--;
727 1 hiro
                src->updated = TRUE;
728 744 hiro
                src->mtime = 0;
729 1 hiro
                dest->last_num++;
730 1 hiro
                dest->total++;
731 1 hiro
                dest->updated = TRUE;
732 744 hiro
                dest->mtime = 0;
733 1 hiro
734 2249 hiro
                SET_DEST_MSG_FLAGS(NULL, dest, dest->last_num, msginfo->flags);
735 2249 hiro
                procmsg_add_cache_queue(dest, dest->last_num, msginfo);
736 1 hiro
737 1 hiro
                if (MSG_IS_NEW(msginfo->flags)) {
738 1 hiro
                        src->new--;
739 1 hiro
                        dest->new++;
740 1 hiro
                }
741 1 hiro
                if (MSG_IS_UNREAD(msginfo->flags)) {
742 1 hiro
                        src->unread--;
743 1 hiro
                        dest->unread++;
744 1 hiro
                }
745 1 hiro
746 1 hiro
                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_INVALID);
747 1 hiro
        }
748 1 hiro
749 2249 hiro
        if (!dest->opened) {
750 2249 hiro
                procmsg_flush_mark_queue(dest, NULL);
751 2249 hiro
                procmsg_flush_cache_queue(dest, NULL);
752 2249 hiro
        }
753 1 hiro
754 2274 hiro
        S_UNLOCK(mh);
755 1 hiro
        return dest->last_num;
756 1 hiro
}
757 1 hiro
758 1 hiro
static gint mh_move_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
759 1 hiro
{
760 1 hiro
        GSList msglist;
761 1 hiro
762 1 hiro
        g_return_val_if_fail(msginfo != NULL, -1);
763 1 hiro
764 1 hiro
        msglist.data = msginfo;
765 1 hiro
        msglist.next = NULL;
766 1 hiro
767 1 hiro
        return mh_move_msgs(folder, dest, &msglist);
768 1 hiro
}
769 1 hiro
770 1 hiro
static gint mh_move_msgs(Folder *folder, FolderItem *dest, GSList *msglist)
771 1 hiro
{
772 1 hiro
        MsgInfo *msginfo;
773 1 hiro
        gint ret = 0;
774 1 hiro
        gint first;
775 1 hiro
776 1 hiro
        msginfo = (MsgInfo *)msglist->data;
777 1 hiro
        if (folder == msginfo->folder->folder)
778 1 hiro
                return mh_do_move_msgs(folder, dest, msglist);
779 1 hiro
780 2249 hiro
        ret = mh_add_msgs_msginfo(folder, dest, msglist, FALSE, &first);
781 1 hiro
782 1 hiro
        if (ret != -1)
783 1 hiro
                ret = folder_item_remove_msgs(msginfo->folder, msglist);
784 1 hiro
785 1 hiro
        return ret;
786 1 hiro
}
787 1 hiro
788 1 hiro
static gint mh_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo)
789 1 hiro
{
790 1 hiro
        GSList msglist;
791 1 hiro
792 1 hiro
        g_return_val_if_fail(msginfo != NULL, -1);
793 1 hiro
794 1 hiro
        msglist.data = msginfo;
795 1 hiro
        msglist.next = NULL;
796 1 hiro
797 1 hiro
        return mh_copy_msgs(folder, dest, &msglist);
798 1 hiro
}
799 1 hiro
800 1 hiro
static gint mh_copy_msgs(Folder *folder, FolderItem *dest, GSList *msglist)
801 1 hiro
{
802 1 hiro
        gchar *srcfile;
803 1 hiro
        gchar *destfile;
804 1 hiro
        GSList *cur;
805 1 hiro
        MsgInfo *msginfo;
806 1 hiro
807 1 hiro
        g_return_val_if_fail(dest != NULL, -1);
808 1 hiro
        g_return_val_if_fail(msglist != NULL, -1);
809 1 hiro
810 1 hiro
        if (dest->last_num < 0) {
811 1 hiro
                mh_scan_folder(folder, dest);
812 1 hiro
                if (dest->last_num < 0) return -1;
813 1 hiro
        }
814 1 hiro
815 2274 hiro
        S_LOCK(mh);
816 2274 hiro
817 1 hiro
        for (cur = msglist; cur != NULL; cur = cur->next) {
818 1 hiro
                msginfo = (MsgInfo *)cur->data;
819 1 hiro
820 1 hiro
                if (msginfo->folder == dest) {
821 1 hiro
                        g_warning(_("the src folder is identical to the dest.\n"));
822 1 hiro
                        continue;
823 1 hiro
                }
824 1589 hiro
                debug_print(_("Copying message %s/%d to %s ...\n"),
825 1589 hiro
                            msginfo->folder->path, msginfo->msgnum, dest->path);
826 1 hiro
827 1 hiro
                destfile = mh_get_new_msg_filename(dest);
828 1 hiro
                if (!destfile) break;
829 1 hiro
                srcfile = procmsg_get_message_file(msginfo);
830 1 hiro
831 1 hiro
                if (copy_file(srcfile, destfile, TRUE) < 0) {
832 1 hiro
                        FILE_OP_ERROR(srcfile, "copy");
833 1 hiro
                        g_free(srcfile);
834 1 hiro
                        g_free(destfile);
835 1 hiro
                        break;
836 1 hiro
                }
837 1 hiro
838 2164 hiro
                g_signal_emit_by_name(syl_app_get(), "add-msg", dest, destfile, dest->last_num + 1);
839 2164 hiro
840 1 hiro
                g_free(srcfile);
841 1 hiro
                g_free(destfile);
842 1 hiro
                dest->last_num++;
843 1 hiro
                dest->total++;
844 1 hiro
                dest->updated = TRUE;
845 744 hiro
                dest->mtime = 0;
846 1 hiro
847 2249 hiro
                SET_DEST_MSG_FLAGS(NULL, dest, dest->last_num, msginfo->flags);
848 2249 hiro
                procmsg_add_cache_queue(dest, dest->last_num, msginfo);
849 1 hiro
850 1 hiro
                if (MSG_IS_NEW(msginfo->flags))
851 1 hiro
                        dest->new++;
852 1 hiro
                if (MSG_IS_UNREAD(msginfo->flags))
853 1 hiro
                        dest->unread++;
854 1 hiro
        }
855 1 hiro
856 2249 hiro
        if (!dest->opened) {
857 2249 hiro
                procmsg_flush_mark_queue(dest, NULL);
858 2249 hiro
                procmsg_flush_cache_queue(dest, NULL);
859 2249 hiro
        }
860 1 hiro
861 2274 hiro
        S_UNLOCK(mh);
862 1 hiro
        return dest->last_num;
863 1 hiro
}
864 1 hiro
865 1 hiro
static gint mh_remove_msg(Folder *folder, FolderItem *item, MsgInfo *msginfo)
866 1 hiro
{
867 1 hiro
        gchar *file;
868 1 hiro
869 1 hiro
        g_return_val_if_fail(item != NULL, -1);
870 1 hiro
871 1 hiro
        file = mh_fetch_msg(folder, item, msginfo->msgnum);
872 1 hiro
        g_return_val_if_fail(file != NULL, -1);
873 1 hiro
874 2164 hiro
        g_signal_emit_by_name(syl_app_get(), "remove-msg", item, file, msginfo->msgnum);
875 2164 hiro
876 2274 hiro
        S_LOCK(mh);
877 2274 hiro
878 478 hiro
        if (g_unlink(file) < 0) {
879 1 hiro
                FILE_OP_ERROR(file, "unlink");
880 1 hiro
                g_free(file);
881 2274 hiro
                S_UNLOCK(mh);
882 1 hiro
                return -1;
883 1 hiro
        }
884 1 hiro
        g_free(file);
885 1 hiro
886 1 hiro
        item->total--;
887 1 hiro
        item->updated = TRUE;
888 744 hiro
        item->mtime = 0;
889 1 hiro
        if (MSG_IS_NEW(msginfo->flags))
890 1 hiro
                item->new--;
891 1 hiro
        if (MSG_IS_UNREAD(msginfo->flags))
892 1 hiro
                item->unread--;
893 1 hiro
        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_INVALID);
894 1 hiro
895 2274 hiro
        S_UNLOCK(mh);
896 2274 hiro
897 1 hiro
        if (msginfo->msgnum == item->last_num)
898 338 hiro
                mh_scan_folder_full(folder, item, FALSE);
899 1 hiro
900 1 hiro
        return 0;
901 1 hiro
}
902 1 hiro
903 1 hiro
static gint mh_remove_all_msg(Folder *folder, FolderItem *item)
904 1 hiro
{
905 1 hiro
        gchar *path;
906 1 hiro
        gint val;
907 1 hiro
908 1 hiro
        g_return_val_if_fail(item != NULL, -1);
909 1 hiro
910 1 hiro
        path = folder_item_get_path(item);
911 1 hiro
        g_return_val_if_fail(path != NULL, -1);
912 2164 hiro
        g_signal_emit_by_name(syl_app_get(), "remove-all-msg", item);
913 2274 hiro
914 2274 hiro
        S_LOCK(mh);
915 2274 hiro
916 1 hiro
        val = remove_all_numbered_files(path);
917 1 hiro
        g_free(path);
918 1 hiro
        if (val == 0) {
919 1 hiro
                item->new = item->unread = item->total = 0;
920 1 hiro
                item->last_num = 0;
921 1 hiro
                item->updated = TRUE;
922 744 hiro
                item->mtime = 0;
923 1 hiro
        }
924 1 hiro
925 2274 hiro
        S_UNLOCK(mh);
926 2274 hiro
927 1 hiro
        return val;
928 1 hiro
}
929 1 hiro
930 1 hiro
static gboolean mh_is_msg_changed(Folder *folder, FolderItem *item,
931 1 hiro
                                  MsgInfo *msginfo)
932 1 hiro
{
933 1 hiro
        struct stat s;
934 2286 hiro
        gchar buf[16];
935 1 hiro
936 2286 hiro
        if (g_stat(itos_buf(buf, msginfo->msgnum), &s) < 0 ||
937 1 hiro
            msginfo->size  != s.st_size ||
938 1 hiro
            msginfo->mtime != s.st_mtime)
939 1 hiro
                return TRUE;
940 1 hiro
941 1 hiro
        return FALSE;
942 1 hiro
}
943 1 hiro
944 1 hiro
static gint mh_close(Folder *folder, FolderItem *item)
945 1 hiro
{
946 1 hiro
        return 0;
947 1 hiro
}
948 1 hiro
949 1085 Hiro
#ifdef G_OS_WIN32
950 1085 Hiro
struct wfddata {
951 1085 Hiro
        WIN32_FIND_DATAA wfda;
952 1085 Hiro
        WIN32_FIND_DATAW wfdw;
953 1085 Hiro
        DWORD file_attr;
954 1085 Hiro
        gchar *file_name;
955 1085 Hiro
};
956 1085 Hiro
957 1086 Hiro
static HANDLE find_first_file(const gchar *path, struct wfddata *wfd)
958 1085 Hiro
{
959 1085 Hiro
        HANDLE hfind;
960 1085 Hiro
961 1085 Hiro
        if (G_WIN32_HAVE_WIDECHAR_API()) {
962 1086 Hiro
                if (path) {
963 1086 Hiro
                        gchar *wildcard_path;
964 1086 Hiro
                        wchar_t *wpath;
965 1086 Hiro
966 1086 Hiro
                        wildcard_path = g_strconcat(path, "\\*", NULL);
967 1086 Hiro
                        wpath = g_utf8_to_utf16(wildcard_path, -1,
968 1086 Hiro
                                                NULL, NULL, NULL);
969 1086 Hiro
                        if (wpath) {
970 1086 Hiro
                                hfind = FindFirstFileW(wpath, &wfd->wfdw);
971 1086 Hiro
                                g_free(wpath);
972 1086 Hiro
                        } else
973 1086 Hiro
                                hfind = INVALID_HANDLE_VALUE;
974 1086 Hiro
                        g_free(wildcard_path);
975 1086 Hiro
                } else
976 1086 Hiro
                        hfind = FindFirstFileW(L"*", &wfd->wfdw);
977 1086 Hiro
978 1085 Hiro
                if (hfind != INVALID_HANDLE_VALUE) {
979 1085 Hiro
                        wfd->file_attr = wfd->wfdw.dwFileAttributes;
980 1085 Hiro
                        wfd->file_name = g_utf16_to_utf8(wfd->wfdw.cFileName, -1,
981 1085 Hiro
                                                         NULL, NULL, NULL);
982 1085 Hiro
                }
983 1085 Hiro
        } else {
984 1086 Hiro
                if (path) {
985 1086 Hiro
                        gchar *wildcard_path;
986 1086 Hiro
                        gchar *cp_path;
987 1086 Hiro
988 1086 Hiro
                        wildcard_path = g_strconcat(path, "\\*", NULL);
989 1086 Hiro
                        cp_path = g_locale_from_utf8(wildcard_path, -1,
990 1086 Hiro
                                                     NULL, NULL, NULL);
991 1086 Hiro
                        if (cp_path) {
992 1086 Hiro
                                hfind = FindFirstFileA(cp_path, &wfd->wfda);
993 1086 Hiro
                                g_free(cp_path);
994 1086 Hiro
                        } else
995 1086 Hiro
                                hfind = INVALID_HANDLE_VALUE;
996 1086 Hiro
                        g_free(wildcard_path);
997 1086 Hiro
                } else
998 1086 Hiro
                        hfind = FindFirstFileA("*", &wfd->wfda);
999 1086 Hiro
1000 1085 Hiro
                if (hfind != INVALID_HANDLE_VALUE) {
1001 1085 Hiro
                        wfd->file_attr = wfd->wfda.dwFileAttributes;
1002 1086 Hiro
                        wfd->file_name = g_locale_to_utf8(wfd->wfda.cFileName,
1003 1086 Hiro
                                                          -1, NULL, NULL, NULL);
1004 1085 Hiro
                }
1005 1085 Hiro
        }
1006 1085 Hiro
1007 1085 Hiro
        return hfind;
1008 1085 Hiro
}
1009 1085 Hiro
1010 1085 Hiro
static BOOL find_next_file(HANDLE hfind, struct wfddata *wfd)
1011 1085 Hiro
{
1012 1085 Hiro
        BOOL retval;
1013 1085 Hiro
1014 1085 Hiro
        if (G_WIN32_HAVE_WIDECHAR_API()) {
1015 1085 Hiro
                retval = FindNextFileW(hfind, &wfd->wfdw);
1016 1085 Hiro
                if (retval) {
1017 1085 Hiro
                        wfd->file_attr = wfd->wfdw.dwFileAttributes;
1018 1085 Hiro
                        wfd->file_name = g_utf16_to_utf8(wfd->wfdw.cFileName, -1,
1019 1085 Hiro
                                                         NULL, NULL, NULL);
1020 1085 Hiro
                }
1021 1085 Hiro
        } else {
1022 1085 Hiro
                retval = FindNextFileA(hfind, &wfd->wfda);
1023 1085 Hiro
                if (retval) {
1024 1085 Hiro
                        wfd->file_attr = wfd->wfda.dwFileAttributes;
1025 1086 Hiro
                        wfd->file_name = g_locale_to_utf8(wfd->wfda.cFileName,
1026 1086 Hiro
                                                          -1, NULL, NULL, NULL);
1027 1085 Hiro
                }
1028 1085 Hiro
        }
1029 1085 Hiro
1030 1085 Hiro
        return retval;
1031 1085 Hiro
}
1032 1085 Hiro
#endif
1033 1085 Hiro
1034 1 hiro
static gint mh_scan_folder_full(Folder *folder, FolderItem *item,
1035 1 hiro
                                gboolean count_sum)
1036 1 hiro
{
1037 1 hiro
        gchar *path;
1038 977 hiro
#ifdef G_OS_WIN32
1039 1085 Hiro
        struct wfddata wfd;
1040 1084 Hiro
        HANDLE hfind;
1041 977 hiro
#else
1042 1 hiro
        DIR *dp;
1043 1 hiro
        struct dirent *d;
1044 977 hiro
#endif
1045 1 hiro
        gint max = 0;
1046 1 hiro
        gint num;
1047 1 hiro
        gint n_msg = 0;
1048 1 hiro
1049 1 hiro
        g_return_val_if_fail(item != NULL, -1);
1050 1 hiro
1051 1 hiro
        debug_print("mh_scan_folder(): Scanning %s ...\n", item->path);
1052 1 hiro
1053 2274 hiro
        S_LOCK(mh);
1054 2274 hiro
1055 1 hiro
        path = folder_item_get_path(item);
1056 2274 hiro
        if (!path) {
1057 2274 hiro
                S_UNLOCK(mh);
1058 2274 hiro
                return -1;
1059 2274 hiro
        }
1060 1 hiro
        if (change_dir(path) < 0) {
1061 1 hiro
                g_free(path);
1062 2274 hiro
                S_UNLOCK(mh);
1063 1 hiro
                return -1;
1064 1 hiro
        }
1065 1 hiro
        g_free(path);
1066 1 hiro
1067 977 hiro
#ifdef G_OS_WIN32
1068 1086 Hiro
        if ((hfind = find_first_file(NULL, &wfd)) == INVALID_HANDLE_VALUE) {
1069 977 hiro
                g_warning("failed to open directory\n");
1070 977 hiro
#else
1071 1 hiro
        if ((dp = opendir(".")) == NULL) {
1072 1 hiro
                FILE_OP_ERROR(item->path, "opendir");
1073 977 hiro
#endif
1074 2274 hiro
                S_UNLOCK(mh);
1075 1 hiro
                return -1;
1076 1 hiro
        }
1077 1 hiro
1078 1 hiro
        if (folder->ui_func)
1079 1 hiro
                folder->ui_func(folder, item, folder->ui_func_data);
1080 1 hiro
1081 977 hiro
#ifdef G_OS_WIN32
1082 1084 Hiro
        do {
1083 1085 Hiro
                if ((wfd.file_attr &
1084 1084 Hiro
                     (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0) {
1085 1085 Hiro
                        if (wfd.file_name) {
1086 1085 Hiro
                                if ((num = to_number(wfd.file_name)) > 0) {
1087 1084 Hiro
                                        n_msg++;
1088 1084 Hiro
                                        if (max < num)
1089 1084 Hiro
                                                max = num;
1090 1084 Hiro
                                }
1091 1084 Hiro
                        }
1092 977 hiro
                }
1093 977 hiro
1094 1085 Hiro
                if (wfd.file_name) {
1095 1085 Hiro
                        g_free(wfd.file_name);
1096 1085 Hiro
                        wfd.file_name = NULL;
1097 1085 Hiro
                }
1098 1085 Hiro
        } while (find_next_file(hfind, &wfd));
1099 1085 Hiro
1100 1084 Hiro
        FindClose(hfind);
1101 977 hiro
#else
1102 1 hiro
        while ((d = readdir(dp)) != NULL) {
1103 20 hiro
                if ((num = to_number(d->d_name)) > 0 &&
1104 1 hiro
                    dirent_is_regular_file(d)) {
1105 1 hiro
                        n_msg++;
1106 1 hiro
                        if (max < num)
1107 1 hiro
                                max = num;
1108 1 hiro
                }
1109 1 hiro
        }
1110 1 hiro
1111 1 hiro
        closedir(dp);
1112 977 hiro
#endif
1113 1 hiro
1114 1 hiro
        if (n_msg == 0)
1115 1 hiro
                item->new = item->unread = item->total = 0;
1116 1 hiro
        else if (count_sum) {
1117 1 hiro
                gint new, unread, total, min, max_;
1118 1 hiro
1119 1 hiro
                procmsg_get_mark_sum
1120 1 hiro
                        (item, &new, &unread, &total, &min, &max_, 0);
1121 1 hiro
1122 1 hiro
                if (n_msg > total) {
1123 1 hiro
                        item->unmarked_num = new = n_msg - total;
1124 1 hiro
                        unread += n_msg - total;
1125 1 hiro
                } else
1126 1 hiro
                        item->unmarked_num = 0;
1127 1 hiro
1128 1 hiro
                item->new = new;
1129 1 hiro
                item->unread = unread;
1130 1 hiro
                item->total = n_msg;
1131 2247 hiro
1132 2247 hiro
                if (item->cache_queue && !item->opened) {
1133 2247 hiro
                        procmsg_flush_cache_queue(item, NULL);
1134 2247 hiro
                }
1135 1 hiro
        }
1136 1 hiro
1137 1 hiro
        item->updated = TRUE;
1138 744 hiro
        item->mtime = 0;
1139 1 hiro
1140 1084 Hiro
        debug_print("Last number in dir %s = %d\n", item->path, max);
1141 1 hiro
        item->last_num = max;
1142 1 hiro
1143 2274 hiro
        S_UNLOCK(mh);
1144 1 hiro
        return 0;
1145 1 hiro
}
1146 1 hiro
1147 1 hiro
static gint mh_scan_folder(Folder *folder, FolderItem *item)
1148 1 hiro
{
1149 1 hiro
        return mh_scan_folder_full(folder, item, TRUE);
1150 1 hiro
}
1151 1 hiro
1152 1 hiro
static gint mh_scan_tree(Folder *folder)
1153 1 hiro
{
1154 1 hiro
        FolderItem *item;
1155 1 hiro
        gchar *rootpath;
1156 1 hiro
1157 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
1158 1 hiro
1159 2274 hiro
        S_LOCK(mh);
1160 2274 hiro
1161 1 hiro
        if (!folder->node) {
1162 1 hiro
                item = folder_item_new(folder->name, NULL);
1163 1 hiro
                item->folder = folder;
1164 1 hiro
                folder->node = item->node = g_node_new(item);
1165 1 hiro
        } else
1166 1 hiro
                item = FOLDER_ITEM(folder->node->data);
1167 1 hiro
1168 1 hiro
        rootpath = folder_item_get_path(item);
1169 1 hiro
        if (change_dir(rootpath) < 0) {
1170 1 hiro
                g_free(rootpath);
1171 2274 hiro
                S_UNLOCK(mh);
1172 1 hiro
                return -1;
1173 1 hiro
        }
1174 1 hiro
        g_free(rootpath);
1175 1 hiro
1176 1 hiro
        mh_create_tree(folder);
1177 1 hiro
        mh_remove_missing_folder_items(folder);
1178 1 hiro
        mh_scan_tree_recursive(item);
1179 1 hiro
1180 2274 hiro
        S_UNLOCK(mh);
1181 1 hiro
        return 0;
1182 1 hiro
}
1183 1 hiro
1184 1 hiro
#define MAKE_DIR_IF_NOT_EXIST(dir) \
1185 1 hiro
{ \
1186 1 hiro
        if (!is_dir_exist(dir)) { \
1187 1 hiro
                if (is_file_exist(dir)) { \
1188 1 hiro
                        g_warning(_("File `%s' already exists.\n" \
1189 1 hiro
                                    "Can't create folder."), dir); \
1190 1 hiro
                        return -1; \
1191 1 hiro
                } \
1192 1 hiro
                if (make_dir(dir) < 0) \
1193 1 hiro
                        return -1; \
1194 1 hiro
        } \
1195 1 hiro
}
1196 1 hiro
1197 618 hiro
#define MAKE_DIR_HIER_IF_NOT_EXIST(dir) \
1198 618 hiro
{ \
1199 618 hiro
        if (!is_dir_exist(dir)) { \
1200 618 hiro
                if (is_file_exist(dir)) { \
1201 618 hiro
                        g_warning(_("File `%s' already exists.\n" \
1202 618 hiro
                                    "Can't create folder."), dir); \
1203 618 hiro
                        return -1; \
1204 618 hiro
                } \
1205 618 hiro
                if (make_dir_hier(dir) < 0) \
1206 618 hiro
                        return -1; \
1207 618 hiro
        } \
1208 618 hiro
}
1209 618 hiro
1210 1 hiro
static gint mh_create_tree(Folder *folder)
1211 1 hiro
{
1212 1 hiro
        gchar *rootpath;
1213 1 hiro
1214 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
1215 1 hiro
1216 484 hiro
        CHDIR_RETURN_VAL_IF_FAIL(get_mail_base_dir(), -1);
1217 1 hiro
        rootpath = LOCAL_FOLDER(folder)->rootpath;
1218 618 hiro
        MAKE_DIR_HIER_IF_NOT_EXIST(rootpath);
1219 1 hiro
        CHDIR_RETURN_VAL_IF_FAIL(rootpath, -1);
1220 1 hiro
        MAKE_DIR_IF_NOT_EXIST(INBOX_DIR);
1221 1 hiro
        MAKE_DIR_IF_NOT_EXIST(OUTBOX_DIR);
1222 1 hiro
        MAKE_DIR_IF_NOT_EXIST(QUEUE_DIR);
1223 1 hiro
        MAKE_DIR_IF_NOT_EXIST(DRAFT_DIR);
1224 1 hiro
        MAKE_DIR_IF_NOT_EXIST(TRASH_DIR);
1225 1 hiro
1226 1 hiro
        return 0;
1227 1 hiro
}
1228 1 hiro
1229 1 hiro
#undef MAKE_DIR_IF_NOT_EXIST
1230 618 hiro
#undef MAKE_DIR_HIER_IF_NOT_EXIST
1231 1 hiro
1232 1 hiro
static FolderItem *mh_create_folder(Folder *folder, FolderItem *parent,
1233 1 hiro
                                    const gchar *name)
1234 1 hiro
{
1235 1 hiro
        gchar *path;
1236 1 hiro
        gchar *fs_name;
1237 1 hiro
        gchar *fullpath;
1238 1 hiro
        FolderItem *new_item;
1239 1 hiro
1240 1 hiro
        g_return_val_if_fail(folder != NULL, NULL);
1241 1 hiro
        g_return_val_if_fail(parent != NULL, NULL);
1242 1 hiro
        g_return_val_if_fail(name != NULL, NULL);
1243 1 hiro
1244 2274 hiro
        S_LOCK(mh);
1245 2274 hiro
1246 1 hiro
        path = folder_item_get_path(parent);
1247 1 hiro
        fs_name = g_filename_from_utf8(name, -1, NULL, NULL, NULL);
1248 1 hiro
        fullpath = g_strconcat(path, G_DIR_SEPARATOR_S,
1249 1 hiro
                               fs_name ? fs_name : name, NULL);
1250 1 hiro
        g_free(fs_name);
1251 1 hiro
        g_free(path);
1252 1 hiro
1253 618 hiro
        if (make_dir_hier(fullpath) < 0) {
1254 1 hiro
                g_free(fullpath);
1255 2274 hiro
                S_UNLOCK(mh);
1256 1 hiro
                return NULL;
1257 1 hiro
        }
1258 1 hiro
1259 1 hiro
        g_free(fullpath);
1260 1 hiro
1261 1568 hiro
        /* path is a logical folder path */
1262 1 hiro
        if (parent->path)
1263 1568 hiro
                path = g_strconcat(parent->path, "/", name, NULL);
1264 1 hiro
        else
1265 1 hiro
                path = g_strdup(name);
1266 1 hiro
        new_item = folder_item_new(name, path);
1267 1 hiro
        folder_item_append(parent, new_item);
1268 1 hiro
        g_free(path);
1269 1 hiro
1270 2274 hiro
        S_UNLOCK(mh);
1271 1 hiro
        return new_item;
1272 1 hiro
}
1273 1 hiro
1274 391 hiro
static gint mh_move_folder_real(Folder *folder, FolderItem *item,
1275 391 hiro
                                FolderItem *new_parent, const gchar *name)
1276 1 hiro
{
1277 618 hiro
        gchar *rootpath;
1278 1 hiro
        gchar *oldpath;
1279 1 hiro
        gchar *newpath;
1280 391 hiro
        gchar *dirname;
1281 389 hiro
        gchar *new_dir;
1282 391 hiro
        gchar *name_;
1283 389 hiro
        gchar *utf8_name;
1284 389 hiro
        gchar *paths[2];
1285 2164 hiro
        gchar *old_id, *new_id;
1286 389 hiro
1287 389 hiro
        g_return_val_if_fail(folder != NULL, -1);
1288 389 hiro
        g_return_val_if_fail(item != NULL, -1);
1289 389 hiro
        g_return_val_if_fail(folder == item->folder, -1);
1290 391 hiro
        g_return_val_if_fail(item->path != NULL, -1);
1291 391 hiro
        g_return_val_if_fail(new_parent != NULL || name != NULL, -1);
1292 391 hiro
        if (new_parent) {
1293 391 hiro
                g_return_val_if_fail(item != new_parent, -1);
1294 391 hiro
                g_return_val_if_fail(item->parent != new_parent, -1);
1295 391 hiro
                g_return_val_if_fail(item->folder == new_parent->folder, -1);
1296 391 hiro
                if (g_node_is_ancestor(item->node, new_parent->node)) {
1297 391 hiro
                        g_warning("folder to be moved is ancestor of new parent\n");
1298 391 hiro
                        return -1;
1299 391 hiro
                }
1300 389 hiro
        }
1301 389 hiro
1302 2274 hiro
        S_LOCK(mh);
1303 2274 hiro
1304 389 hiro
        oldpath = folder_item_get_path(item);
1305 391 hiro
        if (new_parent) {
1306 391 hiro
                if (name) {
1307 391 hiro
                        name_ = g_filename_from_utf8(name, -1, NULL, NULL,
1308 391 hiro
                                                     NULL);
1309 391 hiro
                        if (!name_)
1310 391 hiro
                                name_ = g_strdup(name);
1311 391 hiro
                        utf8_name = g_strdup(name);
1312 391 hiro
                } else {
1313 391 hiro
                        name_ = g_path_get_basename(oldpath);
1314 391 hiro
                        utf8_name = g_filename_to_utf8(name_, -1, NULL, NULL,
1315 391 hiro
                                                       NULL);
1316 391 hiro
                        if (!utf8_name)
1317 391 hiro
                                utf8_name = g_strdup(name_);
1318 391 hiro
                }
1319 391 hiro
                new_dir = folder_item_get_path(new_parent);
1320 391 hiro
                newpath = g_strconcat(new_dir, G_DIR_SEPARATOR_S, name_, NULL);
1321 391 hiro
                g_free(new_dir);
1322 391 hiro
        } else {
1323 391 hiro
                name_ = g_filename_from_utf8(name, -1, NULL, NULL, NULL);
1324 389 hiro
                utf8_name = g_strdup(name);
1325 391 hiro
                dirname = g_dirname(oldpath);
1326 391 hiro
                newpath = g_strconcat(dirname, G_DIR_SEPARATOR_S,
1327 391 hiro
                                      name_ ? name_ : name, NULL);
1328 391 hiro
                g_free(dirname);
1329 391 hiro
        }
1330 391 hiro
        g_free(name_);
1331 389 hiro
1332 389 hiro
        if (is_file_entry_exist(newpath)) {
1333 389 hiro
                g_warning("%s already exists\n", newpath);
1334 389 hiro
                g_free(oldpath);
1335 389 hiro
                g_free(newpath);
1336 389 hiro
                g_free(utf8_name);
1337 2274 hiro
                S_UNLOCK(mh);
1338 389 hiro
                return -1;
1339 389 hiro
        }
1340 389 hiro
1341 618 hiro
        rootpath = folder_get_path(folder);
1342 618 hiro
        if (change_dir(rootpath) < 0) {
1343 618 hiro
                g_free(rootpath);
1344 618 hiro
                g_free(oldpath);
1345 618 hiro
                g_free(newpath);
1346 618 hiro
                g_free(utf8_name);
1347 2274 hiro
                S_UNLOCK(mh);
1348 618 hiro
                return -1;
1349 618 hiro
        }
1350 618 hiro
        g_free(rootpath);
1351 618 hiro
1352 389 hiro
        debug_print("mh_move_folder: rename(%s, %s)\n", oldpath, newpath);
1353 389 hiro
1354 478 hiro
        if (g_rename(oldpath, newpath) < 0) {
1355 389 hiro
                FILE_OP_ERROR(oldpath, "rename");
1356 389 hiro
                g_free(oldpath);
1357 389 hiro
                g_free(newpath);
1358 389 hiro
                g_free(utf8_name);
1359 2274 hiro
                S_UNLOCK(mh);
1360 389 hiro
                return -1;
1361 389 hiro
        }
1362 389 hiro
1363 389 hiro
        g_free(oldpath);
1364 389 hiro
        g_free(newpath);
1365 389 hiro
1366 2164 hiro
        old_id = folder_item_get_identifier(item);
1367 2164 hiro
1368 391 hiro
        if (new_parent) {
1369 391 hiro
                g_node_unlink(item->node);
1370 391 hiro
                g_node_append(new_parent->node, item->node);
1371 391 hiro
                item->parent = new_parent;
1372 391 hiro
                if (new_parent->path != NULL) {
1373 1589 hiro
                        newpath = g_strconcat(new_parent->path, "/", utf8_name,
1374 391 hiro
                                              NULL);
1375 391 hiro
                        g_free(utf8_name);
1376 391 hiro
                } else
1377 391 hiro
                        newpath = utf8_name;
1378 391 hiro
        } else {
1379 1589 hiro
                if (strchr(item->path, '/') != NULL) {
1380 391 hiro
                        dirname = g_dirname(item->path);
1381 1589 hiro
                        newpath = g_strconcat(dirname, "/", utf8_name, NULL);
1382 391 hiro
                        g_free(dirname);
1383 391 hiro
                        g_free(utf8_name);
1384 391 hiro
                } else
1385 391 hiro
                        newpath = utf8_name;
1386 391 hiro
        }
1387 389 hiro
1388 391 hiro
        if (name) {
1389 391 hiro
                g_free(item->name);
1390 391 hiro
                item->name = g_strdup(name);
1391 391 hiro
        }
1392 389 hiro
1393 389 hiro
        paths[0] = g_strdup(item->path);
1394 389 hiro
        paths[1] = newpath;
1395 389 hiro
        g_node_traverse(item->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1396 389 hiro
                        mh_rename_folder_func, paths);
1397 389 hiro
1398 389 hiro
        g_free(paths[0]);
1399 389 hiro
        g_free(paths[1]);
1400 389 hiro
1401 2164 hiro
        new_id = folder_item_get_identifier(item);
1402 2164 hiro
        g_signal_emit_by_name(syl_app_get(), "move-folder", item, old_id,
1403 2164 hiro
                              new_id);
1404 2164 hiro
        g_free(new_id);
1405 2164 hiro
        g_free(old_id);
1406 2164 hiro
1407 2274 hiro
        S_UNLOCK(mh);
1408 389 hiro
        return 0;
1409 389 hiro
}
1410 389 hiro
1411 391 hiro
static gint mh_move_folder(Folder *folder, FolderItem *item,
1412 391 hiro
                           FolderItem *new_parent)
1413 391 hiro
{
1414 391 hiro
        return mh_move_folder_real(folder, item, new_parent, NULL);
1415 391 hiro
}
1416 391 hiro
1417 391 hiro
static gint mh_rename_folder(Folder *folder, FolderItem *item,
1418 391 hiro
                             const gchar *name)
1419 391 hiro
{
1420 391 hiro
        return mh_move_folder_real(folder, item, NULL, name);
1421 391 hiro
}
1422 391 hiro
1423 1 hiro
static gint mh_remove_folder(Folder *folder, FolderItem *item)
1424 1 hiro
{
1425 1 hiro
        gchar *path;
1426 1 hiro
1427 1 hiro
        g_return_val_if_fail(folder != NULL, -1);
1428 1 hiro
        g_return_val_if_fail(item != NULL, -1);
1429 1 hiro
        g_return_val_if_fail(item->path != NULL, -1);
1430 1 hiro
1431 2274 hiro
        S_LOCK(mh);
1432 2274 hiro
1433 1 hiro
        path = folder_item_get_path(item);
1434 1 hiro
        if (remove_dir_recursive(path) < 0) {
1435 1 hiro
                g_warning("can't remove directory `%s'\n", path);
1436 1 hiro
                g_free(path);
1437 2274 hiro
                S_UNLOCK(mh);
1438 1 hiro
                return -1;
1439 1 hiro
        }
1440 1 hiro
1441 1 hiro
        g_free(path);
1442 2164 hiro
        g_signal_emit_by_name(syl_app_get(), "remove-folder", item);
1443 1 hiro
        folder_item_remove(item);
1444 2274 hiro
1445 2274 hiro
        S_UNLOCK(mh);
1446 1 hiro
        return 0;
1447 1 hiro
}
1448 1 hiro
1449 1 hiro
1450 1 hiro
static time_t mh_get_mtime(FolderItem *item)
1451 1 hiro
{
1452 1 hiro
        gchar *path;
1453 1 hiro
        struct stat s;
1454 1 hiro
1455 1 hiro
        path = folder_item_get_path(item);
1456 478 hiro
        if (g_stat(path, &s) < 0) {
1457 1 hiro
                FILE_OP_ERROR(path, "stat");
1458 2274 hiro
                g_free(path);
1459 1 hiro
                return -1;
1460 1 hiro
        } else {
1461 2274 hiro
                g_free(path);
1462 1 hiro
                return MAX(s.st_mtime, s.st_ctime);
1463 1 hiro
        }
1464 1 hiro
}
1465 1 hiro
1466 1 hiro
static GSList *mh_get_uncached_msgs(GHashTable *msg_table, FolderItem *item)
1467 1 hiro
{
1468 1 hiro
        gchar *path;
1469 977 hiro
        GDir *dp;
1470 977 hiro
        const gchar *dir_name;
1471 1 hiro
        GSList *newlist = NULL;
1472 1 hiro
        GSList *last = NULL;
1473 1 hiro
        MsgInfo *msginfo;
1474 1 hiro
        gint n_newmsg = 0;
1475 1 hiro
        gint num;
1476 2230 hiro
        Folder *folder;
1477 1 hiro
1478 1 hiro
        g_return_val_if_fail(item != NULL, NULL);
1479 2230 hiro
        g_return_val_if_fail(item->folder != NULL, NULL);
1480 1 hiro
1481 2230 hiro
        folder = item->folder;
1482 2230 hiro
1483 1 hiro
        path = folder_item_get_path(item);
1484 1 hiro
        g_return_val_if_fail(path != NULL, NULL);
1485 1 hiro
        if (change_dir(path) < 0) {
1486 1 hiro
                g_free(path);
1487 1 hiro
                return NULL;
1488 1 hiro
        }
1489 1 hiro
        g_free(path);
1490 1 hiro
1491 977 hiro
        if ((dp = g_dir_open(".", 0, NULL)) == NULL) {
1492 1 hiro
                FILE_OP_ERROR(item->path, "opendir");
1493 1 hiro
                return NULL;
1494 1 hiro
        }
1495 1 hiro
1496 1 hiro
        debug_print("Searching uncached messages...\n");
1497 1 hiro
1498 1 hiro
        if (msg_table) {
1499 2230 hiro
                gint count = 0;
1500 2230 hiro
1501 977 hiro
                while ((dir_name = g_dir_read_name(dp)) != NULL) {
1502 977 hiro
                        if ((num = to_number(dir_name)) <= 0) continue;
1503 1 hiro
1504 1 hiro
                        msginfo = g_hash_table_lookup
1505 1 hiro
                                (msg_table, GUINT_TO_POINTER(num));
1506 1 hiro
1507 360 hiro
                        if (msginfo) {
1508 360 hiro
                                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_CACHED);
1509 360 hiro
                        } else {
1510 1 hiro
                                /* not found in the cache (uncached message) */
1511 977 hiro
                                msginfo = mh_parse_msg(dir_name, item);
1512 1 hiro
                                if (!msginfo) continue;
1513 1 hiro
1514 1 hiro
                                if (!newlist)
1515 1 hiro
                                        last = newlist =
1516 1 hiro
                                                g_slist_append(NULL, msginfo);
1517 1 hiro
                                else {
1518 1 hiro
                                        last = g_slist_append(last, msginfo);
1519 1 hiro
                                        last = last->next;
1520 1 hiro
                                }
1521 1 hiro
                                n_newmsg++;
1522 1 hiro
                        }
1523 2230 hiro
1524 2230 hiro
                        count++;
1525 2230 hiro
                        if (folder->ui_func)
1526 2230 hiro
                                folder->ui_func(folder, item, folder->ui_func_data ? folder->ui_func_data : GINT_TO_POINTER(count));
1527 1 hiro
                }
1528 1 hiro
        } else {
1529 1 hiro
                /* discard all previous cache */
1530 977 hiro
                while ((dir_name = g_dir_read_name(dp)) != NULL) {
1531 977 hiro
                        if (to_number(dir_name) <= 0) continue;
1532 1 hiro
1533 977 hiro
                        msginfo = mh_parse_msg(dir_name, item);
1534 1 hiro
                        if (!msginfo) continue;
1535 1 hiro
1536 1 hiro
                        if (!newlist)
1537 1 hiro
                                last = newlist = g_slist_append(NULL, msginfo);
1538 1 hiro
                        else {
1539 1 hiro
                                last = g_slist_append(last, msginfo);
1540 1 hiro
                                last = last->next;
1541 1 hiro
                        }
1542 1 hiro
                        n_newmsg++;
1543 2230 hiro
                        if (folder->ui_func)
1544 2230 hiro
                                folder->ui_func(folder, item, folder->ui_func_data ? folder->ui_func_data : GINT_TO_POINTER(n_newmsg));
1545 1 hiro
                }
1546 1 hiro
        }
1547 1 hiro
1548 977 hiro
        g_dir_close(dp);
1549 1 hiro
1550 1 hiro
        if (n_newmsg)
1551 1 hiro
                debug_print("%d uncached message(s) found.\n", n_newmsg);
1552 1 hiro
        else
1553 1 hiro
                debug_print("done.\n");
1554 1 hiro
1555 1 hiro
        /* sort new messages in numerical order */
1556 1 hiro
        if (newlist && item->sort_key == SORT_BY_NONE) {
1557 1 hiro
                debug_print("Sorting uncached messages in numerical order...\n");
1558 1 hiro
                newlist = g_slist_sort
1559 1 hiro
                        (newlist, (GCompareFunc)procmsg_cmp_msgnum_for_sort);
1560 1 hiro
                debug_print("done.\n");
1561 1 hiro
        }
1562 1 hiro
1563 1 hiro
        return newlist;
1564 1 hiro
}
1565 1 hiro
1566 1 hiro
static MsgInfo *mh_parse_msg(const gchar *file, FolderItem *item)
1567 1 hiro
{
1568 1 hiro
        MsgInfo *msginfo;
1569 1 hiro
        MsgFlags flags;
1570 1 hiro
1571 1 hiro
        g_return_val_if_fail(item != NULL, NULL);
1572 1 hiro
        g_return_val_if_fail(file != NULL, NULL);
1573 1 hiro
1574 1 hiro
        flags.perm_flags = MSG_NEW|MSG_UNREAD;
1575 1 hiro
        flags.tmp_flags = 0;
1576 1 hiro
1577 1 hiro
        if (item->stype == F_QUEUE) {
1578 1 hiro
                MSG_SET_TMP_FLAGS(flags, MSG_QUEUED);
1579 1 hiro
        } else if (item->stype == F_DRAFT) {
1580 1 hiro
                MSG_SET_TMP_FLAGS(flags, MSG_DRAFT);
1581 1 hiro
        }
1582 1 hiro
1583 1 hiro
        msginfo = procheader_parse_file(file, flags, FALSE);
1584 1 hiro
        if (!msginfo) return NULL;
1585 1 hiro
1586 1 hiro
        msginfo->msgnum = atoi(file);
1587 1 hiro
        msginfo->folder = item;
1588 1 hiro
1589 1 hiro
        return msginfo;
1590 1 hiro
}
1591 1 hiro
1592 1 hiro
#if 0
1593 1 hiro
static gboolean mh_is_maildir_one(const gchar *path, const gchar *dir)
1594 1 hiro
{
1595 1 hiro
        gchar *entry;
1596 1 hiro
        gboolean result;
1597 1 hiro
1598 1 hiro
        entry = g_strconcat(path, G_DIR_SEPARATOR_S, dir, NULL);
1599 1 hiro
        result = is_dir_exist(entry);
1600 1 hiro
        g_free(entry);
1601 1 hiro
1602 1 hiro
        return result;
1603 1 hiro
}
1604 1 hiro
1605 1 hiro
/*
1606 1 hiro
 * check whether PATH is a Maildir style mailbox.
1607 1 hiro
 * This is the case if the 3 subdir: new, cur, tmp are existing.
1608 1 hiro
 * This functon assumes that entry is an directory
1609 1 hiro
 */
1610 1 hiro
static gboolean mh_is_maildir(const gchar *path)
1611 1 hiro
{
1612 1 hiro
        return mh_is_maildir_one(path, "new") &&
1613 1 hiro
               mh_is_maildir_one(path, "cur") &&
1614 1 hiro
               mh_is_maildir_one(path, "tmp");
1615 1 hiro
}
1616 1 hiro
#endif
1617 1 hiro
1618 1 hiro
static gboolean mh_remove_missing_folder_items_func(GNode *node, gpointer data)
1619 1 hiro
{
1620 1 hiro
        FolderItem *item;
1621 1 hiro
        gchar *path;
1622 1 hiro
1623 1 hiro
        g_return_val_if_fail(node->data != NULL, FALSE);
1624 1 hiro
1625 1 hiro
        if (G_NODE_IS_ROOT(node))
1626 1 hiro
                return FALSE;
1627 1 hiro
1628 1 hiro
        item = FOLDER_ITEM(node->data);
1629 1 hiro
1630 1049 hiro
#if 0
1631 1049 hiro
        if (item->path && strchr(item->path, '/')) {
1632 1049 hiro
                debug_print("folder '%s' includes Unix path separator. removing...\n", item->path);
1633 1049 hiro
                folder_item_remove(item);
1634 1049 hiro
                return FALSE;
1635 1049 hiro
        }
1636 1049 hiro
#endif
1637 1049 hiro
1638 1 hiro
        path = folder_item_get_path(item);
1639 1 hiro
        if (!is_dir_exist(path)) {
1640 1 hiro
                debug_print("folder '%s' not found. removing...\n", path);
1641 1 hiro
                folder_item_remove(item);
1642 1 hiro
        }
1643 1 hiro
        g_free(path);
1644 1 hiro
1645 1 hiro
        return FALSE;
1646 1 hiro
}
1647 1 hiro
1648 1 hiro
static void mh_remove_missing_folder_items(Folder *folder)
1649 1 hiro
{
1650 1 hiro
        g_return_if_fail(folder != NULL);
1651 1 hiro
1652 1 hiro
        debug_print("searching missing folders...\n");
1653 1 hiro
1654 1 hiro
        g_node_traverse(folder->node, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1655 1 hiro
                        mh_remove_missing_folder_items_func, folder);
1656 1 hiro
}
1657 1 hiro
1658 1 hiro
static void mh_scan_tree_recursive(FolderItem *item)
1659 1 hiro
{
1660 1 hiro
        Folder *folder;
1661 479 hiro
#ifdef G_OS_WIN32
1662 1086 Hiro
        struct wfddata wfd;
1663 1086 Hiro
        HANDLE hfind;
1664 479 hiro
#else
1665 1 hiro
        DIR *dp;
1666 1 hiro
        struct dirent *d;
1667 1086 Hiro
        struct stat s;
1668 479 hiro
#endif
1669 479 hiro
        const gchar *dir_name;
1670 1 hiro
        gchar *fs_path;
1671 1 hiro
        gchar *entry;
1672 1 hiro
        gchar *utf8entry;
1673 1 hiro
        gchar *utf8name;
1674 1 hiro
        gint n_msg = 0;
1675 1 hiro
1676 1 hiro
        g_return_if_fail(item != NULL);
1677 1 hiro
        g_return_if_fail(item->folder != NULL);
1678 1 hiro
1679 1086 Hiro
        if (item->stype == F_VIRTUAL)
1680 1086 Hiro
                return;
1681 1086 Hiro
1682 1 hiro
        folder = item->folder;
1683 1 hiro
1684 1 hiro
        fs_path = item->path ?
1685 1 hiro
                g_filename_from_utf8(item->path, -1, NULL, NULL, NULL)
1686 1 hiro
                : g_strdup(".");
1687 1 hiro
        if (!fs_path)
1688 1 hiro
                fs_path = g_strdup(item->path);
1689 479 hiro
#ifdef G_OS_WIN32
1690 1086 Hiro
        hfind = find_first_file(fs_path, &wfd);
1691 1086 Hiro
        if (hfind == INVALID_HANDLE_VALUE) {
1692 479 hiro
                g_warning("failed to open directory: %s\n", fs_path);
1693 479 hiro
                g_free(fs_path);
1694 479 hiro
                return;
1695 479 hiro
        }
1696 479 hiro
#else
1697 1 hiro
        dp = opendir(fs_path);
1698 1 hiro
        if (!dp) {
1699 1 hiro
                FILE_OP_ERROR(fs_path, "opendir");
1700 1 hiro
                g_free(fs_path);
1701 1 hiro
                return;
1702 1 hiro
        }
1703 479 hiro
#endif
1704 1 hiro
        g_free(fs_path);
1705 1 hiro
1706 1 hiro
        debug_print("scanning %s ...\n",
1707 1 hiro
                    item->path ? item->path
1708 1 hiro
                    : LOCAL_FOLDER(item->folder)->rootpath);
1709 1 hiro
        if (folder->ui_func)
1710 1 hiro
                folder->ui_func(folder, item, folder->ui_func_data);
1711 1 hiro
1712 479 hiro
#ifdef G_OS_WIN32
1713 1086 Hiro
        do {
1714 1086 Hiro
                if (!wfd.file_name) continue;
1715 1086 Hiro
                if (wfd.file_name[0] == '.') {
1716 1086 Hiro
                        g_free(wfd.file_name);
1717 1086 Hiro
                        wfd.file_name = NULL;
1718 1086 Hiro
                        continue;
1719 1086 Hiro
                }
1720 1086 Hiro
                dir_name = utf8name = wfd.file_name;
1721 1086 Hiro
                wfd.file_name = NULL;
1722 479 hiro
#else
1723 1 hiro
        while ((d = readdir(dp)) != NULL) {
1724 479 hiro
                dir_name = d->d_name;
1725 479 hiro
                if (dir_name[0] == '.') continue;
1726 1 hiro
1727 479 hiro
                utf8name = g_filename_to_utf8(dir_name, -1, NULL, NULL, NULL);
1728 1 hiro
                if (!utf8name)
1729 479 hiro
                        utf8name = g_strdup(dir_name);
1730 1086 Hiro
#endif
1731 1 hiro
1732 1589 hiro
                if (item->path) {
1733 1589 hiro
                        utf8entry = g_strconcat(item->path, "/", utf8name,
1734 1589 hiro
                                                NULL);
1735 1589 hiro
                } else
1736 1 hiro
                        utf8entry = g_strdup(utf8name);
1737 1 hiro
                entry = g_filename_from_utf8(utf8entry, -1, NULL, NULL, NULL);
1738 1 hiro
                if (!entry)
1739 1 hiro
                        entry = g_strdup(utf8entry);
1740 1589 hiro
#ifdef G_OS_WIN32
1741 1589 hiro
                subst_char(entry, '/', G_DIR_SEPARATOR);
1742 1589 hiro
#endif
1743 1 hiro
1744 1 hiro
                if (
1745 1086 Hiro
#ifdef G_OS_WIN32
1746 1086 Hiro
                        (wfd.file_attr & FILE_ATTRIBUTE_DIRECTORY) != 0
1747 1086 Hiro
#else
1748 1086 Hiro
#if HAVE_DIRENT_D_TYPE
1749 1 hiro
                        d->d_type == DT_DIR ||
1750 1513 hiro
                        ((d->d_type == DT_UNKNOWN || d->d_type == DT_LNK) &&
1751 1 hiro
#endif
1752 478 hiro
                        g_stat(entry, &s) == 0 && S_ISDIR(s.st_mode)
1753 1086 Hiro
#if HAVE_DIRENT_D_TYPE
1754 1 hiro
                        )
1755 1 hiro
#endif
1756 1086 Hiro
#endif /* G_OS_WIN32 */
1757 1 hiro
                   ) {
1758 1 hiro
                        FolderItem *new_item = NULL;
1759 1 hiro
                        GNode *node;
1760 1 hiro
1761 479 hiro
#ifndef G_OS_WIN32
1762 380 hiro
                        if (g_utf8_validate(utf8name, -1, NULL) == FALSE) {
1763 380 hiro
                                g_warning(_("Directory name\n"
1764 380 hiro
                                            "'%s' is not a valid UTF-8 string.\n"
1765 380 hiro
                                            "Maybe the locale encoding is used for filename.\n"
1766 380 hiro
                                            "If that is the case, you must set the following environmental variable\n"
1767 380 hiro
                                            "(see README for detail):\n"
1768 380 hiro
                                            "\n"
1769 380 hiro
                                            "\tG_FILENAME_ENCODING=@locale\n"),
1770 380 hiro
                                          utf8name);
1771 380 hiro
                                g_free(entry);
1772 380 hiro
                                g_free(utf8entry);
1773 380 hiro
                                g_free(utf8name);
1774 380 hiro
                                continue;
1775 380 hiro
                        }
1776 479 hiro
#endif /* G_OS_WIN32 */
1777 1 hiro
1778 1 hiro
                        node = item->node;
1779 1 hiro
                        for (node = node->children; node != NULL; node = node->next) {
1780 1 hiro
                                FolderItem *cur_item = FOLDER_ITEM(node->data);
1781 1 hiro
                                if (!strcmp2(cur_item->path, utf8entry)) {
1782 1 hiro
                                        new_item = cur_item;
1783 1 hiro
                                        break;
1784 1 hiro
                                }
1785 1 hiro
                        }
1786 1 hiro
                        if (!new_item) {
1787 1589 hiro
                                debug_print("new folder '%s' found.\n",
1788 1589 hiro
                                            utf8entry);
1789 1 hiro
                                new_item = folder_item_new(utf8name, utf8entry);
1790 1 hiro
                                folder_item_append(item, new_item);
1791 1 hiro
                        }
1792 1 hiro
1793 1 hiro
                        if (!item->path) {
1794 1 hiro
                                if (!folder->inbox &&
1795 479 hiro
                                    !strcmp(dir_name, INBOX_DIR)) {
1796 1 hiro
                                        new_item->stype = F_INBOX;
1797 1 hiro
                                        folder->inbox = new_item;
1798 1 hiro
                                } else if (!folder->outbox &&
1799 479 hiro
                                           !strcmp(dir_name, OUTBOX_DIR)) {
1800 1 hiro
                                        new_item->stype = F_OUTBOX;
1801 1 hiro
                                        folder->outbox = new_item;
1802 1 hiro
                                } else if (!folder->draft &&
1803 479 hiro
                                           !strcmp(dir_name, DRAFT_DIR)) {
1804 1 hiro
                                        new_item->stype = F_DRAFT;
1805 1 hiro
                                        folder->draft = new_item;
1806 1 hiro
                                } else if (!folder->queue &&
1807 479 hiro
                                           !strcmp(dir_name, QUEUE_DIR)) {
1808 1 hiro
                                        new_item->stype = F_QUEUE;
1809 1 hiro
                                        folder->queue = new_item;
1810 1 hiro
                                } else if (!folder->trash &&
1811 479 hiro
                                           !strcmp(dir_name, TRASH_DIR)) {
1812 1 hiro
                                        new_item->stype = F_TRASH;
1813 1 hiro
                                        folder->trash = new_item;
1814 1 hiro
                                }
1815 1 hiro
                        }
1816 1 hiro
1817 1 hiro
                        mh_scan_tree_recursive(new_item);
1818 479 hiro
                } else if (to_number(dir_name) > 0) n_msg++;
1819 1 hiro
1820 1 hiro
                g_free(entry);
1821 1 hiro
                g_free(utf8entry);
1822 1 hiro
                g_free(utf8name);
1823 1086 Hiro
#ifdef G_OS_WIN32
1824 1086 Hiro
        } while (find_next_file(hfind, &wfd));
1825 1086 Hiro
#else
1826 1 hiro
        }
1827 1086 Hiro
#endif
1828 1 hiro
1829 479 hiro
#ifdef G_OS_WIN32
1830 1086 Hiro
        FindClose(hfind);
1831 479 hiro
#else
1832 1 hiro
        closedir(dp);
1833 479 hiro
#endif
1834 1 hiro
1835 1 hiro
        if (item->path) {
1836 1 hiro
                gint new, unread, total, min, max;
1837 1 hiro
1838 1 hiro
                procmsg_get_mark_sum
1839 1 hiro
                        (item, &new, &unread, &total, &min, &max, 0);
1840 1 hiro
                if (n_msg > total) {
1841 1 hiro
                        new += n_msg - total;
1842 1 hiro
                        unread += n_msg - total;
1843 1 hiro
                }
1844 1 hiro
                item->new = new;
1845 1 hiro
                item->unread = unread;
1846 1 hiro
                item->total = n_msg;
1847 1 hiro
                item->updated = TRUE;
1848 744 hiro
                item->mtime = 0;
1849 1 hiro
        }
1850 1 hiro
}
1851 1 hiro
1852 1 hiro
static gboolean mh_rename_folder_func(GNode *node, gpointer data)
1853 1 hiro
{
1854 1 hiro
        FolderItem *item = node->data;
1855 1 hiro
        gchar **paths = data;
1856 1 hiro
        const gchar *oldpath = paths[0];
1857 1 hiro
        const gchar *newpath = paths[1];
1858 1 hiro
        gchar *base;
1859 1 hiro
        gchar *new_itempath;
1860 1 hiro
        gint oldpathlen;
1861 1 hiro
1862 1 hiro
        oldpathlen = strlen(oldpath);
1863 1 hiro
        if (strncmp(oldpath, item->path, oldpathlen) != 0) {
1864 1 hiro
                g_warning("path doesn't match: %s, %s\n", oldpath, item->path);
1865 1 hiro
                return TRUE;
1866 1 hiro
        }
1867 1 hiro
1868 1 hiro
        base = item->path + oldpathlen;
1869 1589 hiro
        while (*base == '/') base++;
1870 1 hiro
        if (*base == '\0')
1871 1 hiro
                new_itempath = g_strdup(newpath);
1872 1 hiro
        else
1873 1589 hiro
                new_itempath = g_strconcat(newpath, "/", base, NULL);
1874 1 hiro
        g_free(item->path);
1875 1 hiro
        item->path = new_itempath;
1876 1 hiro
1877 1 hiro
        return FALSE;
1878 1 hiro
}