Statistics
| Revision:

root / libsylph / virtual.c @ 1637

History | View | Annotate | Download (13.2 kB)

1 831 hiro
/*
2 831 hiro
 * LibSylph -- E-Mail client library
3 1492 hiro
 * Copyright (C) 1999-2007 Hiroyuki Yamamoto
4 831 hiro
 *
5 831 hiro
 * This library is free software; you can redistribute it and/or
6 831 hiro
 * modify it under the terms of the GNU Lesser General Public
7 831 hiro
 * License as published by the Free Software Foundation; either
8 831 hiro
 * version 2.1 of the License, or (at your option) any later version.
9 831 hiro
 *
10 831 hiro
 * This library is distributed in the hope that it will be useful,
11 831 hiro
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 831 hiro
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 831 hiro
 * Lesser General Public License for more details.
14 831 hiro
 *
15 831 hiro
 * You should have received a copy of the GNU Lesser General Public
16 831 hiro
 * License along with this library; if not, write to the Free Software
17 831 hiro
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 831 hiro
 */
19 831 hiro
20 831 hiro
#ifdef HAVE_CONFIG_H
21 831 hiro
#  include "config.h"
22 831 hiro
#endif
23 831 hiro
24 831 hiro
#include "defs.h"
25 831 hiro
26 831 hiro
#include <glib.h>
27 831 hiro
#include <glib/gi18n.h>
28 831 hiro
#include <dirent.h>
29 831 hiro
#include <sys/stat.h>
30 831 hiro
#include <time.h>
31 831 hiro
#include <unistd.h>
32 831 hiro
#include <string.h>
33 831 hiro
#include <errno.h>
34 831 hiro
35 831 hiro
#undef MEASURE_TIME
36 831 hiro
37 831 hiro
#include "folder.h"
38 831 hiro
#include "virtual.h"
39 892 hiro
#include "mh.h"
40 831 hiro
#include "procmsg.h"
41 831 hiro
#include "procheader.h"
42 831 hiro
#include "filter.h"
43 831 hiro
#include "utils.h"
44 831 hiro
45 832 hiro
typedef struct _VirtualSearchInfo        VirtualSearchInfo;
46 869 hiro
typedef struct _SearchCacheInfo                SearchCacheInfo;
47 832 hiro
48 832 hiro
struct _VirtualSearchInfo {
49 832 hiro
        FilterRule *rule;
50 832 hiro
        GSList *mlist;
51 869 hiro
        GHashTable *search_cache_table;
52 869 hiro
        FILE *fp;
53 928 hiro
        gboolean requires_full_headers;
54 928 hiro
        gboolean exclude_trash;
55 832 hiro
};
56 832 hiro
57 869 hiro
struct _SearchCacheInfo {
58 869 hiro
        FolderItem *folder;
59 869 hiro
        guint msgnum;
60 869 hiro
        off_t size;
61 869 hiro
        time_t mtime;
62 869 hiro
        MsgFlags flags;
63 869 hiro
};
64 869 hiro
65 869 hiro
enum
66 869 hiro
{
67 869 hiro
        SCACHE_NOT_EXIST = 0,
68 869 hiro
        SCACHE_MATCHED = 1,
69 869 hiro
        SCACHE_NOT_MATCHED = 2
70 869 hiro
};
71 869 hiro
72 831 hiro
static void        virtual_folder_init        (Folder                *folder,
73 831 hiro
                                         const gchar        *name,
74 831 hiro
                                         const gchar        *path);
75 831 hiro
76 869 hiro
static GHashTable *virtual_read_search_cache
77 869 hiro
                                        (FolderItem        *item);
78 869 hiro
static void virtual_write_search_cache        (FILE                *fp,
79 869 hiro
                                         FolderItem        *item,
80 869 hiro
                                         MsgInfo        *msginfo,
81 869 hiro
                                         gint                 matched);
82 869 hiro
83 869 hiro
static GSList *virtual_search_folder        (VirtualSearchInfo        *info,
84 869 hiro
                                         FolderItem                *item);
85 832 hiro
static gboolean virtual_search_recursive_func
86 832 hiro
                                        (GNode                *node,
87 832 hiro
                                         gpointer         data);
88 832 hiro
89 831 hiro
static Folder        *virtual_folder_new        (const gchar        *name,
90 831 hiro
                                         const gchar        *path);
91 831 hiro
static void     virtual_folder_destroy        (Folder                *folder);
92 831 hiro
93 831 hiro
static GSList  *virtual_get_msg_list        (Folder                *folder,
94 831 hiro
                                         FolderItem        *item,
95 831 hiro
                                         gboolean         use_cache);
96 831 hiro
static gchar   *virtual_fetch_msg        (Folder                *folder,
97 831 hiro
                                         FolderItem        *item,
98 831 hiro
                                         gint                 num);
99 831 hiro
static MsgInfo *virtual_get_msginfo        (Folder                *folder,
100 831 hiro
                                         FolderItem        *item,
101 831 hiro
                                         gint                 num);
102 831 hiro
static gint    virtual_close                (Folder                *folder,
103 831 hiro
                                         FolderItem        *item);
104 831 hiro
105 831 hiro
static gint    virtual_scan_folder        (Folder                *folder,
106 831 hiro
                                         FolderItem        *item);
107 831 hiro
108 892 hiro
static gint    virtual_rename_folder        (Folder                *folder,
109 892 hiro
                                         FolderItem        *item,
110 892 hiro
                                         const gchar        *name);
111 871 hiro
static gint    virtual_remove_folder        (Folder                *folder,
112 871 hiro
                                         FolderItem        *item);
113 871 hiro
114 831 hiro
static FolderClass virtual_class =
115 831 hiro
{
116 831 hiro
        F_VIRTUAL,
117 831 hiro
118 831 hiro
        virtual_folder_new,
119 831 hiro
        virtual_folder_destroy,
120 831 hiro
121 831 hiro
        NULL,
122 831 hiro
        NULL,
123 831 hiro
124 831 hiro
        virtual_get_msg_list,
125 1492 hiro
        NULL,
126 831 hiro
        virtual_fetch_msg,
127 831 hiro
        virtual_get_msginfo,
128 831 hiro
        NULL,
129 831 hiro
        NULL,
130 831 hiro
        NULL,
131 831 hiro
        NULL,
132 831 hiro
        NULL,
133 831 hiro
        NULL,
134 831 hiro
        NULL,
135 831 hiro
        NULL,
136 831 hiro
        NULL,
137 831 hiro
        NULL,
138 831 hiro
        virtual_close,
139 831 hiro
        virtual_scan_folder,
140 831 hiro
141 831 hiro
        NULL,
142 892 hiro
        virtual_rename_folder,
143 831 hiro
        NULL,
144 871 hiro
        virtual_remove_folder,
145 831 hiro
};
146 831 hiro
147 831 hiro
148 831 hiro
FolderClass *virtual_get_class(void)
149 831 hiro
{
150 831 hiro
        return &virtual_class;
151 831 hiro
}
152 831 hiro
153 831 hiro
static Folder *virtual_folder_new(const gchar *name, const gchar *path)
154 831 hiro
{
155 831 hiro
        Folder *folder;
156 831 hiro
157 831 hiro
        folder = (Folder *)g_new0(VirtualFolder, 1);
158 831 hiro
        virtual_folder_init(folder, name, path);
159 831 hiro
160 831 hiro
        return folder;
161 831 hiro
}
162 831 hiro
163 831 hiro
static void virtual_folder_destroy(Folder *folder)
164 831 hiro
{
165 831 hiro
        folder_local_folder_destroy(LOCAL_FOLDER(folder));
166 831 hiro
}
167 831 hiro
168 831 hiro
static void virtual_folder_init(Folder *folder, const gchar *name,
169 831 hiro
                                const gchar *path)
170 831 hiro
{
171 831 hiro
        folder->klass = virtual_get_class();
172 831 hiro
        folder_local_folder_init(folder, name, path);
173 831 hiro
}
174 831 hiro
175 869 hiro
guint sinfo_hash(gconstpointer key)
176 831 hiro
{
177 869 hiro
        const SearchCacheInfo *sinfo = key;
178 869 hiro
        guint h;
179 869 hiro
180 869 hiro
        h = (guint)sinfo->folder;
181 869 hiro
        h ^= sinfo->msgnum;
182 869 hiro
        h ^= (guint)sinfo->size;
183 869 hiro
        h ^= (guint)sinfo->mtime;
184 875 hiro
        /* h ^= (guint)sinfo->flags.tmp_flags; */
185 869 hiro
        h ^= (guint)sinfo->flags.perm_flags;
186 869 hiro
187 869 hiro
        /* g_print("path: %s, n = %u, hash = %u\n",
188 869 hiro
                   sinfo->folder->path, sinfo->msgnum, h); */
189 869 hiro
190 869 hiro
        return h;
191 869 hiro
}
192 869 hiro
193 869 hiro
gint sinfo_equal(gconstpointer v, gconstpointer v2)
194 869 hiro
{
195 869 hiro
        const SearchCacheInfo *s1 = v;
196 869 hiro
        const SearchCacheInfo *s2 = v2;
197 869 hiro
198 869 hiro
        return (s1->folder == s2->folder && s1->msgnum == s2->msgnum &&
199 869 hiro
                s1->size == s2->size && s1->mtime == s2->mtime &&
200 875 hiro
                /* s1->flags.tmp_flags == s2->flags.tmp_flags && */
201 869 hiro
                s1->flags.perm_flags == s2->flags.perm_flags);
202 869 hiro
}
203 869 hiro
204 869 hiro
#define READ_CACHE_DATA_INT(n, fp)                        \
205 869 hiro
{                                                        \
206 869 hiro
        guint32 idata;                                        \
207 869 hiro
                                                        \
208 869 hiro
        if (fread(&idata, sizeof(idata), 1, fp) != 1) {        \
209 869 hiro
                g_warning("Cache data is corrupted\n");        \
210 869 hiro
                fclose(fp);                                \
211 869 hiro
                return table;                                \
212 869 hiro
        } else                                                \
213 869 hiro
                n = idata;                                \
214 869 hiro
}
215 869 hiro
216 869 hiro
static GHashTable *virtual_read_search_cache(FolderItem *item)
217 869 hiro
{
218 869 hiro
        GHashTable *table;
219 869 hiro
        gchar *path, *file;
220 869 hiro
        FILE *fp;
221 869 hiro
        gchar *id;
222 875 hiro
        gint count = 0;
223 869 hiro
224 869 hiro
        g_return_val_if_fail(item != NULL, NULL);
225 869 hiro
226 869 hiro
        path = folder_item_get_path(item);
227 880 hiro
        file = g_strconcat(path, G_DIR_SEPARATOR_S, SEARCH_CACHE, NULL);
228 869 hiro
        debug_print("reading search cache: %s\n", file);
229 880 hiro
        fp = procmsg_open_data_file(file, SEARCH_CACHE_VERSION, DATA_READ,
230 880 hiro
                                    NULL, 0);
231 869 hiro
        g_free(file);
232 869 hiro
        g_free(path);
233 869 hiro
        if (!fp)
234 869 hiro
                return NULL;
235 869 hiro
236 869 hiro
        table = g_hash_table_new(sinfo_hash, sinfo_equal);
237 869 hiro
238 869 hiro
        while (procmsg_read_cache_data_str(fp, &id) == 0) {
239 869 hiro
                FolderItem *folder;
240 869 hiro
                guint32 msgnum;
241 869 hiro
                off_t size;
242 869 hiro
                time_t mtime;
243 869 hiro
                MsgFlags flags;
244 869 hiro
                gint matched;
245 869 hiro
                SearchCacheInfo *sinfo;
246 869 hiro
247 869 hiro
                folder = folder_find_item_from_identifier(id);
248 869 hiro
                g_free(id);
249 869 hiro
250 869 hiro
                while (fread(&msgnum, sizeof(msgnum), 1, fp) == 1) {
251 869 hiro
                        if (msgnum == 0)
252 869 hiro
                                break;
253 869 hiro
254 869 hiro
                        READ_CACHE_DATA_INT(size, fp);
255 869 hiro
                        READ_CACHE_DATA_INT(mtime, fp);
256 869 hiro
                        READ_CACHE_DATA_INT(flags.tmp_flags, fp);
257 869 hiro
                        READ_CACHE_DATA_INT(flags.perm_flags, fp);
258 869 hiro
                        READ_CACHE_DATA_INT(matched, fp);
259 869 hiro
260 869 hiro
                        if (folder) {
261 869 hiro
                                sinfo = g_new(SearchCacheInfo, 1);
262 869 hiro
                                sinfo->folder = folder;
263 869 hiro
                                sinfo->msgnum = msgnum;
264 869 hiro
                                sinfo->size = size;
265 869 hiro
                                sinfo->mtime = mtime;
266 869 hiro
                                sinfo->flags = flags;
267 869 hiro
                                g_hash_table_insert(table, sinfo,
268 869 hiro
                                                    GINT_TO_POINTER(matched));
269 875 hiro
                                ++count;
270 869 hiro
                        }
271 869 hiro
                }
272 869 hiro
        }
273 869 hiro
274 875 hiro
        debug_print("%d cache items read.\n", count);
275 875 hiro
276 869 hiro
        fclose(fp);
277 869 hiro
        return table;
278 869 hiro
}
279 869 hiro
280 869 hiro
static void virtual_write_search_cache(FILE *fp, FolderItem *item,
281 869 hiro
                                       MsgInfo *msginfo, gint matched)
282 869 hiro
{
283 869 hiro
        if (!item && !msginfo) {
284 869 hiro
                WRITE_CACHE_DATA_INT(0, fp);
285 869 hiro
                return;
286 869 hiro
        }
287 869 hiro
288 869 hiro
        if (item) {
289 869 hiro
                gchar *id;
290 869 hiro
291 869 hiro
                id = folder_item_get_identifier(item);
292 869 hiro
                if (id) {
293 869 hiro
                        WRITE_CACHE_DATA(id, fp);
294 869 hiro
                        g_free(id);
295 869 hiro
                }
296 869 hiro
        }
297 869 hiro
298 869 hiro
        if (msginfo) {
299 869 hiro
                WRITE_CACHE_DATA_INT(msginfo->msgnum, fp);
300 869 hiro
                WRITE_CACHE_DATA_INT(msginfo->size, fp);
301 869 hiro
                WRITE_CACHE_DATA_INT(msginfo->mtime, fp);
302 875 hiro
                WRITE_CACHE_DATA_INT
303 875 hiro
                        ((msginfo->flags.tmp_flags & MSG_CACHED_FLAG_MASK), fp);
304 869 hiro
                WRITE_CACHE_DATA_INT(msginfo->flags.perm_flags, fp);
305 869 hiro
                WRITE_CACHE_DATA_INT(matched, fp);
306 869 hiro
        }
307 869 hiro
}
308 869 hiro
309 869 hiro
static void search_cache_free_func(gpointer key, gpointer value, gpointer data)
310 869 hiro
{
311 869 hiro
        g_free(key);
312 869 hiro
}
313 869 hiro
314 869 hiro
static void virtual_search_cache_free(GHashTable *table)
315 869 hiro
{
316 869 hiro
        if (table) {
317 869 hiro
                g_hash_table_foreach(table, search_cache_free_func, NULL);
318 869 hiro
                g_hash_table_destroy(table);
319 869 hiro
        }
320 869 hiro
}
321 869 hiro
322 869 hiro
static GSList *virtual_search_folder(VirtualSearchInfo *info, FolderItem *item)
323 869 hiro
{
324 831 hiro
        GSList *match_list = NULL;
325 831 hiro
        GSList *mlist;
326 831 hiro
        GSList *cur;
327 831 hiro
        FilterInfo fltinfo;
328 875 hiro
        gint count = 1, total, ncachehit = 0;
329 848 hiro
        GTimeVal tv_prev, tv_cur;
330 831 hiro
331 869 hiro
        g_return_val_if_fail(info != NULL, NULL);
332 869 hiro
        g_return_val_if_fail(info->rule != NULL, NULL);
333 831 hiro
        g_return_val_if_fail(item != NULL, NULL);
334 848 hiro
        g_return_val_if_fail(item->path != NULL, NULL);
335 831 hiro
336 832 hiro
        /* prevent circular reference */
337 832 hiro
        if (item->stype == F_VIRTUAL)
338 832 hiro
                return NULL;
339 832 hiro
340 848 hiro
        g_get_current_time(&tv_prev);
341 848 hiro
        status_print(_("Searching %s ..."), item->path);
342 848 hiro
343 831 hiro
        mlist = folder_item_get_msg_list(item, TRUE);
344 848 hiro
        total = g_slist_length(mlist);
345 831 hiro
346 831 hiro
        memset(&fltinfo, 0, sizeof(FilterInfo));
347 831 hiro
348 848 hiro
        debug_print("start query search: %s\n", item->path);
349 831 hiro
350 869 hiro
        virtual_write_search_cache(info->fp, item, NULL, 0);
351 869 hiro
352 831 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
353 831 hiro
                MsgInfo *msginfo = (MsgInfo *)cur->data;
354 831 hiro
                GSList *hlist;
355 831 hiro
356 848 hiro
                g_get_current_time(&tv_cur);
357 848 hiro
                if (tv_cur.tv_sec > tv_prev.tv_sec ||
358 848 hiro
                    tv_cur.tv_usec - tv_prev.tv_usec >
359 848 hiro
                    PROGRESS_UPDATE_INTERVAL * 1000) {
360 848 hiro
                        status_print(_("Searching %s (%d / %d)..."),
361 848 hiro
                                     item->path, count, total);
362 848 hiro
                        tv_prev = tv_cur;
363 848 hiro
                }
364 848 hiro
                ++count;
365 848 hiro
366 869 hiro
                if (info->search_cache_table) {
367 869 hiro
                        gint matched;
368 869 hiro
                        SearchCacheInfo sinfo;
369 869 hiro
370 869 hiro
                        sinfo.folder = item;
371 869 hiro
                        sinfo.msgnum = msginfo->msgnum;
372 869 hiro
                        sinfo.size = msginfo->size;
373 869 hiro
                        sinfo.mtime = msginfo->mtime;
374 869 hiro
                        sinfo.flags = msginfo->flags;
375 869 hiro
376 869 hiro
                        matched = (gint)g_hash_table_lookup
377 869 hiro
                                (info->search_cache_table, &sinfo);
378 869 hiro
                        if (matched == SCACHE_MATCHED) {
379 869 hiro
                                match_list = g_slist_prepend
380 869 hiro
                                        (match_list, msginfo);
381 869 hiro
                                cur->data = NULL;
382 869 hiro
                                virtual_write_search_cache(info->fp, NULL,
383 869 hiro
                                                           msginfo, matched);
384 875 hiro
                                ++ncachehit;
385 869 hiro
                                continue;
386 869 hiro
                        } else if (matched == SCACHE_NOT_MATCHED) {
387 869 hiro
                                virtual_write_search_cache(info->fp, NULL,
388 869 hiro
                                                           msginfo, matched);
389 875 hiro
                                ++ncachehit;
390 869 hiro
                                continue;
391 869 hiro
                        }
392 869 hiro
                }
393 869 hiro
394 831 hiro
                fltinfo.flags = msginfo->flags;
395 928 hiro
                if (info->requires_full_headers) {
396 831 hiro
                        gchar *file;
397 831 hiro
398 831 hiro
                        file = procmsg_get_message_file(msginfo);
399 831 hiro
                        hlist = procheader_get_header_list_from_file(file);
400 831 hiro
                        g_free(file);
401 831 hiro
                } else
402 831 hiro
                        hlist = procheader_get_header_list_from_msginfo
403 831 hiro
                                (msginfo);
404 831 hiro
                if (!hlist)
405 831 hiro
                        continue;
406 831 hiro
407 869 hiro
                if (filter_match_rule(info->rule, msginfo, hlist, &fltinfo)) {
408 831 hiro
                        match_list = g_slist_prepend(match_list, msginfo);
409 831 hiro
                        cur->data = NULL;
410 869 hiro
                        virtual_write_search_cache(info->fp, NULL, msginfo,
411 869 hiro
                                                   SCACHE_MATCHED);
412 869 hiro
                } else {
413 869 hiro
                        virtual_write_search_cache(info->fp, NULL, msginfo,
414 869 hiro
                                                   SCACHE_NOT_MATCHED);
415 831 hiro
                }
416 831 hiro
417 831 hiro
                procheader_header_list_destroy(hlist);
418 831 hiro
        }
419 831 hiro
420 875 hiro
        debug_print("%d cache hits (%d total)\n", ncachehit, total);
421 875 hiro
422 869 hiro
        virtual_write_search_cache(info->fp, NULL, NULL, 0);
423 831 hiro
        procmsg_msg_list_free(mlist);
424 831 hiro
425 831 hiro
        return g_slist_reverse(match_list);
426 831 hiro
}
427 831 hiro
428 832 hiro
static gboolean virtual_search_recursive_func(GNode *node, gpointer data)
429 832 hiro
{
430 832 hiro
        VirtualSearchInfo *info = (VirtualSearchInfo *)data;
431 832 hiro
        FolderItem *item;
432 832 hiro
        GSList *mlist;
433 832 hiro
434 832 hiro
        g_return_val_if_fail(node->data != NULL, FALSE);
435 832 hiro
436 832 hiro
        item = FOLDER_ITEM(node->data);
437 832 hiro
438 832 hiro
        if (!item->path)
439 832 hiro
                return FALSE;
440 928 hiro
        if (info->exclude_trash && item->stype == F_TRASH)
441 928 hiro
                return FALSE;
442 832 hiro
443 869 hiro
        mlist = virtual_search_folder(info, item);
444 832 hiro
        info->mlist = g_slist_concat(info->mlist, mlist);
445 832 hiro
446 832 hiro
        return FALSE;
447 832 hiro
}
448 832 hiro
449 831 hiro
static GSList *virtual_get_msg_list(Folder *folder, FolderItem *item,
450 831 hiro
                                    gboolean use_cache)
451 831 hiro
{
452 831 hiro
        GSList *mlist = NULL;
453 831 hiro
        GSList *flist;
454 832 hiro
        GSList *cur;
455 831 hiro
        FilterRule *rule;
456 869 hiro
        gchar *path;
457 831 hiro
        gchar *rule_file;
458 869 hiro
        gchar *cache_file;
459 831 hiro
        FolderItem *target;
460 832 hiro
        gint new = 0, unread = 0, total = 0;
461 869 hiro
        VirtualSearchInfo info;
462 831 hiro
463 831 hiro
        g_return_val_if_fail(item != NULL, NULL);
464 831 hiro
        g_return_val_if_fail(item->stype == F_VIRTUAL, NULL);
465 831 hiro
466 831 hiro
        path = folder_item_get_path(item);
467 831 hiro
        rule_file = g_strconcat(path, G_DIR_SEPARATOR_S, "filter.xml", NULL);
468 831 hiro
        flist = filter_read_file(rule_file);
469 831 hiro
        g_free(rule_file);
470 831 hiro
471 831 hiro
        g_free(path);
472 831 hiro
473 831 hiro
        if (!flist) {
474 831 hiro
                g_warning("filter rule not found\n");
475 831 hiro
                return NULL;
476 831 hiro
        }
477 831 hiro
478 831 hiro
        rule = (FilterRule *)flist->data;
479 831 hiro
        target = folder_find_item_from_identifier(rule->target_folder);
480 831 hiro
481 831 hiro
        if (!target || target == item) {
482 831 hiro
                g_warning("invalid target folder\n");
483 831 hiro
                goto finish;
484 831 hiro
        }
485 831 hiro
486 869 hiro
        info.rule = rule;
487 869 hiro
        info.mlist = NULL;
488 869 hiro
        if (use_cache)
489 869 hiro
                info.search_cache_table = virtual_read_search_cache(item);
490 869 hiro
        else
491 869 hiro
                info.search_cache_table = NULL;
492 869 hiro
493 869 hiro
        path = folder_item_get_path(item);
494 880 hiro
        cache_file = g_strconcat(path, G_DIR_SEPARATOR_S, SEARCH_CACHE, NULL);
495 880 hiro
        info.fp = procmsg_open_data_file(cache_file, SEARCH_CACHE_VERSION,
496 880 hiro
                                         DATA_WRITE, NULL, 0);
497 869 hiro
        g_free(cache_file);
498 869 hiro
        g_free(path);
499 869 hiro
        if (!info.fp)
500 869 hiro
                goto finish;
501 869 hiro
502 928 hiro
        info.requires_full_headers =
503 928 hiro
                filter_rule_requires_full_headers(rule);
504 928 hiro
505 832 hiro
        if (rule->recursive) {
506 928 hiro
                if (target->stype == F_TRASH)
507 928 hiro
                        info.exclude_trash = FALSE;
508 928 hiro
                else
509 928 hiro
                        info.exclude_trash = TRUE;
510 928 hiro
        } else
511 928 hiro
                info.exclude_trash = FALSE;
512 928 hiro
513 928 hiro
        if (rule->recursive) {
514 832 hiro
                g_node_traverse(target->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
515 832 hiro
                                virtual_search_recursive_func, &info);
516 832 hiro
                mlist = info.mlist;
517 832 hiro
        } else
518 869 hiro
                mlist = virtual_search_folder(&info, target);
519 832 hiro
520 869 hiro
        fclose(info.fp);
521 869 hiro
        virtual_search_cache_free(info.search_cache_table);
522 869 hiro
523 832 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
524 832 hiro
                MsgInfo *msginfo = (MsgInfo *)cur->data;
525 832 hiro
526 832 hiro
                if (MSG_IS_NEW(msginfo->flags))
527 832 hiro
                        ++new;
528 832 hiro
                if (MSG_IS_UNREAD(msginfo->flags))
529 832 hiro
                        ++unread;
530 832 hiro
                ++total;
531 832 hiro
        }
532 832 hiro
533 832 hiro
        item->new = new;
534 832 hiro
        item->unread = unread;
535 832 hiro
        item->total = total;
536 832 hiro
        item->updated = TRUE;
537 832 hiro
538 831 hiro
finish:
539 831 hiro
        filter_rule_list_free(flist);
540 831 hiro
        return mlist;
541 831 hiro
}
542 831 hiro
543 831 hiro
static gchar *virtual_fetch_msg(Folder *folder, FolderItem *item, gint num)
544 831 hiro
{
545 831 hiro
        return NULL;
546 831 hiro
}
547 831 hiro
548 831 hiro
static MsgInfo *virtual_get_msginfo(Folder *folder, FolderItem *item, gint num)
549 831 hiro
{
550 831 hiro
        return NULL;
551 831 hiro
}
552 831 hiro
553 831 hiro
static gint virtual_close(Folder *folder, FolderItem *item)
554 831 hiro
{
555 831 hiro
        return 0;
556 831 hiro
}
557 831 hiro
558 831 hiro
static gint virtual_scan_folder(Folder *folder, FolderItem *item)
559 831 hiro
{
560 831 hiro
        return 0;
561 831 hiro
}
562 871 hiro
563 892 hiro
static gint virtual_rename_folder(Folder *folder, FolderItem *item,
564 892 hiro
                                  const gchar *name)
565 892 hiro
{
566 892 hiro
        g_return_val_if_fail(item != NULL, -1);
567 892 hiro
        g_return_val_if_fail(item->stype == F_VIRTUAL, -1);
568 892 hiro
569 892 hiro
        return mh_get_class()->rename_folder(folder, item, name);
570 892 hiro
}
571 892 hiro
572 871 hiro
static gint virtual_remove_folder(Folder *folder, FolderItem *item)
573 871 hiro
{
574 871 hiro
        gchar *path;
575 871 hiro
576 875 hiro
        g_return_val_if_fail(item != NULL, -1);
577 871 hiro
        g_return_val_if_fail(item->stype == F_VIRTUAL, -1);
578 871 hiro
579 871 hiro
        path = folder_item_get_path(item);
580 871 hiro
        if (remove_dir_recursive(path) < 0) {
581 871 hiro
                g_warning("can't remove directory '%s'\n", path);
582 871 hiro
                g_free(path);
583 871 hiro
                return -1;
584 871 hiro
        }
585 871 hiro
586 871 hiro
        g_free(path);
587 871 hiro
        folder_item_remove(item);
588 871 hiro
        return 0;
589 871 hiro
}