Statistics
| Revision:

root / libsylph / virtual.c @ 3019

History | View | Annotate | Download (13.6 kB)

1 831 hiro
/*
2 831 hiro
 * LibSylph -- E-Mail client library
3 2634 hiro
 * Copyright (C) 1999-2010 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 2634 hiro
static gint    virtual_move_folder        (Folder                *folder,
112 2634 hiro
                                         FolderItem        *item,
113 2634 hiro
                                         FolderItem        *new_parent);
114 871 hiro
static gint    virtual_remove_folder        (Folder                *folder,
115 871 hiro
                                         FolderItem        *item);
116 871 hiro
117 831 hiro
static FolderClass virtual_class =
118 831 hiro
{
119 831 hiro
        F_VIRTUAL,
120 831 hiro
121 831 hiro
        virtual_folder_new,
122 831 hiro
        virtual_folder_destroy,
123 831 hiro
124 831 hiro
        NULL,
125 831 hiro
        NULL,
126 831 hiro
127 831 hiro
        virtual_get_msg_list,
128 1492 hiro
        NULL,
129 831 hiro
        virtual_fetch_msg,
130 831 hiro
        virtual_get_msginfo,
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
        NULL,
139 831 hiro
        NULL,
140 831 hiro
        NULL,
141 2247 hiro
        NULL,
142 2247 hiro
        NULL,
143 831 hiro
        virtual_close,
144 831 hiro
        virtual_scan_folder,
145 831 hiro
146 831 hiro
        NULL,
147 892 hiro
        virtual_rename_folder,
148 2634 hiro
        virtual_move_folder,
149 871 hiro
        virtual_remove_folder,
150 831 hiro
};
151 831 hiro
152 831 hiro
153 831 hiro
FolderClass *virtual_get_class(void)
154 831 hiro
{
155 831 hiro
        return &virtual_class;
156 831 hiro
}
157 831 hiro
158 831 hiro
static Folder *virtual_folder_new(const gchar *name, const gchar *path)
159 831 hiro
{
160 831 hiro
        Folder *folder;
161 831 hiro
162 831 hiro
        folder = (Folder *)g_new0(VirtualFolder, 1);
163 831 hiro
        virtual_folder_init(folder, name, path);
164 831 hiro
165 831 hiro
        return folder;
166 831 hiro
}
167 831 hiro
168 831 hiro
static void virtual_folder_destroy(Folder *folder)
169 831 hiro
{
170 831 hiro
        folder_local_folder_destroy(LOCAL_FOLDER(folder));
171 831 hiro
}
172 831 hiro
173 831 hiro
static void virtual_folder_init(Folder *folder, const gchar *name,
174 831 hiro
                                const gchar *path)
175 831 hiro
{
176 831 hiro
        folder->klass = virtual_get_class();
177 831 hiro
        folder_local_folder_init(folder, name, path);
178 831 hiro
}
179 831 hiro
180 869 hiro
guint sinfo_hash(gconstpointer key)
181 831 hiro
{
182 869 hiro
        const SearchCacheInfo *sinfo = key;
183 869 hiro
        guint h;
184 869 hiro
185 869 hiro
        h = (guint)sinfo->folder;
186 869 hiro
        h ^= sinfo->msgnum;
187 869 hiro
        h ^= (guint)sinfo->size;
188 869 hiro
        h ^= (guint)sinfo->mtime;
189 875 hiro
        /* h ^= (guint)sinfo->flags.tmp_flags; */
190 869 hiro
        h ^= (guint)sinfo->flags.perm_flags;
191 869 hiro
192 869 hiro
        /* g_print("path: %s, n = %u, hash = %u\n",
193 869 hiro
                   sinfo->folder->path, sinfo->msgnum, h); */
194 869 hiro
195 869 hiro
        return h;
196 869 hiro
}
197 869 hiro
198 869 hiro
gint sinfo_equal(gconstpointer v, gconstpointer v2)
199 869 hiro
{
200 869 hiro
        const SearchCacheInfo *s1 = v;
201 869 hiro
        const SearchCacheInfo *s2 = v2;
202 869 hiro
203 869 hiro
        return (s1->folder == s2->folder && s1->msgnum == s2->msgnum &&
204 869 hiro
                s1->size == s2->size && s1->mtime == s2->mtime &&
205 875 hiro
                /* s1->flags.tmp_flags == s2->flags.tmp_flags && */
206 869 hiro
                s1->flags.perm_flags == s2->flags.perm_flags);
207 869 hiro
}
208 869 hiro
209 869 hiro
#define READ_CACHE_DATA_INT(n, fp)                        \
210 869 hiro
{                                                        \
211 869 hiro
        guint32 idata;                                        \
212 869 hiro
                                                        \
213 869 hiro
        if (fread(&idata, sizeof(idata), 1, fp) != 1) {        \
214 869 hiro
                g_warning("Cache data is corrupted\n");        \
215 869 hiro
                fclose(fp);                                \
216 869 hiro
                return table;                                \
217 869 hiro
        } else                                                \
218 869 hiro
                n = idata;                                \
219 869 hiro
}
220 869 hiro
221 869 hiro
static GHashTable *virtual_read_search_cache(FolderItem *item)
222 869 hiro
{
223 869 hiro
        GHashTable *table;
224 869 hiro
        gchar *path, *file;
225 869 hiro
        FILE *fp;
226 869 hiro
        gchar *id;
227 875 hiro
        gint count = 0;
228 869 hiro
229 869 hiro
        g_return_val_if_fail(item != NULL, NULL);
230 869 hiro
231 869 hiro
        path = folder_item_get_path(item);
232 880 hiro
        file = g_strconcat(path, G_DIR_SEPARATOR_S, SEARCH_CACHE, NULL);
233 869 hiro
        debug_print("reading search cache: %s\n", file);
234 880 hiro
        fp = procmsg_open_data_file(file, SEARCH_CACHE_VERSION, DATA_READ,
235 880 hiro
                                    NULL, 0);
236 869 hiro
        g_free(file);
237 869 hiro
        g_free(path);
238 869 hiro
        if (!fp)
239 869 hiro
                return NULL;
240 869 hiro
241 869 hiro
        table = g_hash_table_new(sinfo_hash, sinfo_equal);
242 869 hiro
243 869 hiro
        while (procmsg_read_cache_data_str(fp, &id) == 0) {
244 869 hiro
                FolderItem *folder;
245 869 hiro
                guint32 msgnum;
246 869 hiro
                off_t size;
247 869 hiro
                time_t mtime;
248 869 hiro
                MsgFlags flags;
249 869 hiro
                gint matched;
250 869 hiro
                SearchCacheInfo *sinfo;
251 869 hiro
252 869 hiro
                folder = folder_find_item_from_identifier(id);
253 869 hiro
                g_free(id);
254 869 hiro
255 869 hiro
                while (fread(&msgnum, sizeof(msgnum), 1, fp) == 1) {
256 869 hiro
                        if (msgnum == 0)
257 869 hiro
                                break;
258 869 hiro
259 869 hiro
                        READ_CACHE_DATA_INT(size, fp);
260 869 hiro
                        READ_CACHE_DATA_INT(mtime, fp);
261 869 hiro
                        READ_CACHE_DATA_INT(flags.tmp_flags, fp);
262 869 hiro
                        READ_CACHE_DATA_INT(flags.perm_flags, fp);
263 869 hiro
                        READ_CACHE_DATA_INT(matched, fp);
264 869 hiro
265 869 hiro
                        if (folder) {
266 869 hiro
                                sinfo = g_new(SearchCacheInfo, 1);
267 869 hiro
                                sinfo->folder = folder;
268 869 hiro
                                sinfo->msgnum = msgnum;
269 869 hiro
                                sinfo->size = size;
270 869 hiro
                                sinfo->mtime = mtime;
271 869 hiro
                                sinfo->flags = flags;
272 869 hiro
                                g_hash_table_insert(table, sinfo,
273 869 hiro
                                                    GINT_TO_POINTER(matched));
274 875 hiro
                                ++count;
275 869 hiro
                        }
276 869 hiro
                }
277 869 hiro
        }
278 869 hiro
279 875 hiro
        debug_print("%d cache items read.\n", count);
280 875 hiro
281 869 hiro
        fclose(fp);
282 869 hiro
        return table;
283 869 hiro
}
284 869 hiro
285 869 hiro
static void virtual_write_search_cache(FILE *fp, FolderItem *item,
286 869 hiro
                                       MsgInfo *msginfo, gint matched)
287 869 hiro
{
288 869 hiro
        if (!item && !msginfo) {
289 869 hiro
                WRITE_CACHE_DATA_INT(0, fp);
290 869 hiro
                return;
291 869 hiro
        }
292 869 hiro
293 869 hiro
        if (item) {
294 869 hiro
                gchar *id;
295 869 hiro
296 869 hiro
                id = folder_item_get_identifier(item);
297 869 hiro
                if (id) {
298 869 hiro
                        WRITE_CACHE_DATA(id, fp);
299 869 hiro
                        g_free(id);
300 869 hiro
                }
301 869 hiro
        }
302 869 hiro
303 869 hiro
        if (msginfo) {
304 869 hiro
                WRITE_CACHE_DATA_INT(msginfo->msgnum, fp);
305 869 hiro
                WRITE_CACHE_DATA_INT(msginfo->size, fp);
306 869 hiro
                WRITE_CACHE_DATA_INT(msginfo->mtime, fp);
307 875 hiro
                WRITE_CACHE_DATA_INT
308 875 hiro
                        ((msginfo->flags.tmp_flags & MSG_CACHED_FLAG_MASK), fp);
309 869 hiro
                WRITE_CACHE_DATA_INT(msginfo->flags.perm_flags, fp);
310 869 hiro
                WRITE_CACHE_DATA_INT(matched, fp);
311 869 hiro
        }
312 869 hiro
}
313 869 hiro
314 869 hiro
static void search_cache_free_func(gpointer key, gpointer value, gpointer data)
315 869 hiro
{
316 869 hiro
        g_free(key);
317 869 hiro
}
318 869 hiro
319 869 hiro
static void virtual_search_cache_free(GHashTable *table)
320 869 hiro
{
321 869 hiro
        if (table) {
322 869 hiro
                g_hash_table_foreach(table, search_cache_free_func, NULL);
323 869 hiro
                g_hash_table_destroy(table);
324 869 hiro
        }
325 869 hiro
}
326 869 hiro
327 869 hiro
static GSList *virtual_search_folder(VirtualSearchInfo *info, FolderItem *item)
328 869 hiro
{
329 831 hiro
        GSList *match_list = NULL;
330 831 hiro
        GSList *mlist;
331 831 hiro
        GSList *cur;
332 831 hiro
        FilterInfo fltinfo;
333 875 hiro
        gint count = 1, total, ncachehit = 0;
334 848 hiro
        GTimeVal tv_prev, tv_cur;
335 831 hiro
336 869 hiro
        g_return_val_if_fail(info != NULL, NULL);
337 869 hiro
        g_return_val_if_fail(info->rule != NULL, NULL);
338 831 hiro
        g_return_val_if_fail(item != NULL, NULL);
339 848 hiro
        g_return_val_if_fail(item->path != NULL, NULL);
340 831 hiro
341 832 hiro
        /* prevent circular reference */
342 832 hiro
        if (item->stype == F_VIRTUAL)
343 832 hiro
                return NULL;
344 832 hiro
345 848 hiro
        g_get_current_time(&tv_prev);
346 848 hiro
        status_print(_("Searching %s ..."), item->path);
347 848 hiro
348 831 hiro
        mlist = folder_item_get_msg_list(item, TRUE);
349 848 hiro
        total = g_slist_length(mlist);
350 831 hiro
351 831 hiro
        memset(&fltinfo, 0, sizeof(FilterInfo));
352 831 hiro
353 848 hiro
        debug_print("start query search: %s\n", item->path);
354 831 hiro
355 869 hiro
        virtual_write_search_cache(info->fp, item, NULL, 0);
356 869 hiro
357 831 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
358 831 hiro
                MsgInfo *msginfo = (MsgInfo *)cur->data;
359 831 hiro
                GSList *hlist;
360 831 hiro
361 848 hiro
                g_get_current_time(&tv_cur);
362 848 hiro
                if (tv_cur.tv_sec > tv_prev.tv_sec ||
363 848 hiro
                    tv_cur.tv_usec - tv_prev.tv_usec >
364 848 hiro
                    PROGRESS_UPDATE_INTERVAL * 1000) {
365 848 hiro
                        status_print(_("Searching %s (%d / %d)..."),
366 848 hiro
                                     item->path, count, total);
367 848 hiro
                        tv_prev = tv_cur;
368 848 hiro
                }
369 848 hiro
                ++count;
370 848 hiro
371 869 hiro
                if (info->search_cache_table) {
372 869 hiro
                        gint matched;
373 869 hiro
                        SearchCacheInfo sinfo;
374 869 hiro
375 869 hiro
                        sinfo.folder = item;
376 869 hiro
                        sinfo.msgnum = msginfo->msgnum;
377 869 hiro
                        sinfo.size = msginfo->size;
378 869 hiro
                        sinfo.mtime = msginfo->mtime;
379 869 hiro
                        sinfo.flags = msginfo->flags;
380 869 hiro
381 869 hiro
                        matched = (gint)g_hash_table_lookup
382 869 hiro
                                (info->search_cache_table, &sinfo);
383 869 hiro
                        if (matched == SCACHE_MATCHED) {
384 869 hiro
                                match_list = g_slist_prepend
385 869 hiro
                                        (match_list, msginfo);
386 869 hiro
                                cur->data = NULL;
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
                        } else if (matched == SCACHE_NOT_MATCHED) {
392 869 hiro
                                virtual_write_search_cache(info->fp, NULL,
393 869 hiro
                                                           msginfo, matched);
394 875 hiro
                                ++ncachehit;
395 869 hiro
                                continue;
396 869 hiro
                        }
397 869 hiro
                }
398 869 hiro
399 831 hiro
                fltinfo.flags = msginfo->flags;
400 928 hiro
                if (info->requires_full_headers) {
401 831 hiro
                        gchar *file;
402 831 hiro
403 831 hiro
                        file = procmsg_get_message_file(msginfo);
404 831 hiro
                        hlist = procheader_get_header_list_from_file(file);
405 831 hiro
                        g_free(file);
406 831 hiro
                } else
407 831 hiro
                        hlist = procheader_get_header_list_from_msginfo
408 831 hiro
                                (msginfo);
409 831 hiro
                if (!hlist)
410 831 hiro
                        continue;
411 831 hiro
412 869 hiro
                if (filter_match_rule(info->rule, msginfo, hlist, &fltinfo)) {
413 831 hiro
                        match_list = g_slist_prepend(match_list, msginfo);
414 831 hiro
                        cur->data = NULL;
415 869 hiro
                        virtual_write_search_cache(info->fp, NULL, msginfo,
416 869 hiro
                                                   SCACHE_MATCHED);
417 869 hiro
                } else {
418 869 hiro
                        virtual_write_search_cache(info->fp, NULL, msginfo,
419 869 hiro
                                                   SCACHE_NOT_MATCHED);
420 831 hiro
                }
421 831 hiro
422 831 hiro
                procheader_header_list_destroy(hlist);
423 831 hiro
        }
424 831 hiro
425 875 hiro
        debug_print("%d cache hits (%d total)\n", ncachehit, total);
426 875 hiro
427 869 hiro
        virtual_write_search_cache(info->fp, NULL, NULL, 0);
428 831 hiro
        procmsg_msg_list_free(mlist);
429 831 hiro
430 831 hiro
        return g_slist_reverse(match_list);
431 831 hiro
}
432 831 hiro
433 832 hiro
static gboolean virtual_search_recursive_func(GNode *node, gpointer data)
434 832 hiro
{
435 832 hiro
        VirtualSearchInfo *info = (VirtualSearchInfo *)data;
436 832 hiro
        FolderItem *item;
437 832 hiro
        GSList *mlist;
438 832 hiro
439 832 hiro
        g_return_val_if_fail(node->data != NULL, FALSE);
440 832 hiro
441 832 hiro
        item = FOLDER_ITEM(node->data);
442 832 hiro
443 832 hiro
        if (!item->path)
444 832 hiro
                return FALSE;
445 928 hiro
        if (info->exclude_trash && item->stype == F_TRASH)
446 928 hiro
                return FALSE;
447 832 hiro
448 869 hiro
        mlist = virtual_search_folder(info, item);
449 832 hiro
        info->mlist = g_slist_concat(info->mlist, mlist);
450 832 hiro
451 832 hiro
        return FALSE;
452 832 hiro
}
453 832 hiro
454 831 hiro
static GSList *virtual_get_msg_list(Folder *folder, FolderItem *item,
455 831 hiro
                                    gboolean use_cache)
456 831 hiro
{
457 831 hiro
        GSList *mlist = NULL;
458 831 hiro
        GSList *flist;
459 832 hiro
        GSList *cur;
460 831 hiro
        FilterRule *rule;
461 869 hiro
        gchar *path;
462 831 hiro
        gchar *rule_file;
463 869 hiro
        gchar *cache_file;
464 831 hiro
        FolderItem *target;
465 832 hiro
        gint new = 0, unread = 0, total = 0;
466 869 hiro
        VirtualSearchInfo info;
467 831 hiro
468 831 hiro
        g_return_val_if_fail(item != NULL, NULL);
469 831 hiro
        g_return_val_if_fail(item->stype == F_VIRTUAL, NULL);
470 831 hiro
471 831 hiro
        path = folder_item_get_path(item);
472 831 hiro
        rule_file = g_strconcat(path, G_DIR_SEPARATOR_S, "filter.xml", NULL);
473 831 hiro
        flist = filter_read_file(rule_file);
474 831 hiro
        g_free(rule_file);
475 831 hiro
476 831 hiro
        g_free(path);
477 831 hiro
478 831 hiro
        if (!flist) {
479 831 hiro
                g_warning("filter rule not found\n");
480 831 hiro
                return NULL;
481 831 hiro
        }
482 831 hiro
483 831 hiro
        rule = (FilterRule *)flist->data;
484 831 hiro
        target = folder_find_item_from_identifier(rule->target_folder);
485 831 hiro
486 831 hiro
        if (!target || target == item) {
487 831 hiro
                g_warning("invalid target folder\n");
488 831 hiro
                goto finish;
489 831 hiro
        }
490 831 hiro
491 869 hiro
        info.rule = rule;
492 869 hiro
        info.mlist = NULL;
493 869 hiro
        if (use_cache)
494 869 hiro
                info.search_cache_table = virtual_read_search_cache(item);
495 869 hiro
        else
496 869 hiro
                info.search_cache_table = NULL;
497 869 hiro
498 869 hiro
        path = folder_item_get_path(item);
499 880 hiro
        cache_file = g_strconcat(path, G_DIR_SEPARATOR_S, SEARCH_CACHE, NULL);
500 880 hiro
        info.fp = procmsg_open_data_file(cache_file, SEARCH_CACHE_VERSION,
501 880 hiro
                                         DATA_WRITE, NULL, 0);
502 869 hiro
        g_free(cache_file);
503 869 hiro
        g_free(path);
504 869 hiro
        if (!info.fp)
505 869 hiro
                goto finish;
506 869 hiro
507 928 hiro
        info.requires_full_headers =
508 928 hiro
                filter_rule_requires_full_headers(rule);
509 928 hiro
510 832 hiro
        if (rule->recursive) {
511 928 hiro
                if (target->stype == F_TRASH)
512 928 hiro
                        info.exclude_trash = FALSE;
513 928 hiro
                else
514 928 hiro
                        info.exclude_trash = TRUE;
515 928 hiro
        } else
516 928 hiro
                info.exclude_trash = FALSE;
517 928 hiro
518 928 hiro
        if (rule->recursive) {
519 832 hiro
                g_node_traverse(target->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
520 832 hiro
                                virtual_search_recursive_func, &info);
521 832 hiro
                mlist = info.mlist;
522 832 hiro
        } else
523 869 hiro
                mlist = virtual_search_folder(&info, target);
524 832 hiro
525 869 hiro
        fclose(info.fp);
526 869 hiro
        virtual_search_cache_free(info.search_cache_table);
527 869 hiro
528 832 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
529 832 hiro
                MsgInfo *msginfo = (MsgInfo *)cur->data;
530 832 hiro
531 832 hiro
                if (MSG_IS_NEW(msginfo->flags))
532 832 hiro
                        ++new;
533 832 hiro
                if (MSG_IS_UNREAD(msginfo->flags))
534 832 hiro
                        ++unread;
535 832 hiro
                ++total;
536 832 hiro
        }
537 832 hiro
538 832 hiro
        item->new = new;
539 832 hiro
        item->unread = unread;
540 832 hiro
        item->total = total;
541 832 hiro
        item->updated = TRUE;
542 832 hiro
543 831 hiro
finish:
544 831 hiro
        filter_rule_list_free(flist);
545 831 hiro
        return mlist;
546 831 hiro
}
547 831 hiro
548 831 hiro
static gchar *virtual_fetch_msg(Folder *folder, FolderItem *item, gint num)
549 831 hiro
{
550 831 hiro
        return NULL;
551 831 hiro
}
552 831 hiro
553 831 hiro
static MsgInfo *virtual_get_msginfo(Folder *folder, FolderItem *item, gint num)
554 831 hiro
{
555 831 hiro
        return NULL;
556 831 hiro
}
557 831 hiro
558 831 hiro
static gint virtual_close(Folder *folder, FolderItem *item)
559 831 hiro
{
560 831 hiro
        return 0;
561 831 hiro
}
562 831 hiro
563 831 hiro
static gint virtual_scan_folder(Folder *folder, FolderItem *item)
564 831 hiro
{
565 831 hiro
        return 0;
566 831 hiro
}
567 871 hiro
568 892 hiro
static gint virtual_rename_folder(Folder *folder, FolderItem *item,
569 892 hiro
                                  const gchar *name)
570 892 hiro
{
571 892 hiro
        g_return_val_if_fail(item != NULL, -1);
572 892 hiro
        g_return_val_if_fail(item->stype == F_VIRTUAL, -1);
573 892 hiro
574 892 hiro
        return mh_get_class()->rename_folder(folder, item, name);
575 892 hiro
}
576 892 hiro
577 2634 hiro
static gint virtual_move_folder(Folder *folder, FolderItem *item,
578 2634 hiro
                                FolderItem *new_parent)
579 2634 hiro
{
580 2634 hiro
        g_return_val_if_fail(item != NULL, -1);
581 2634 hiro
        g_return_val_if_fail(item->stype == F_VIRTUAL, -1);
582 2634 hiro
583 2634 hiro
        return mh_get_class()->move_folder(folder, item, new_parent);
584 2634 hiro
}
585 2634 hiro
586 871 hiro
static gint virtual_remove_folder(Folder *folder, FolderItem *item)
587 871 hiro
{
588 871 hiro
        gchar *path;
589 871 hiro
590 875 hiro
        g_return_val_if_fail(item != NULL, -1);
591 871 hiro
        g_return_val_if_fail(item->stype == F_VIRTUAL, -1);
592 871 hiro
593 871 hiro
        path = folder_item_get_path(item);
594 871 hiro
        if (remove_dir_recursive(path) < 0) {
595 871 hiro
                g_warning("can't remove directory '%s'\n", path);
596 871 hiro
                g_free(path);
597 871 hiro
                return -1;
598 871 hiro
        }
599 871 hiro
600 871 hiro
        g_free(path);
601 871 hiro
        folder_item_remove(item);
602 871 hiro
        return 0;
603 871 hiro
}