diff options
author | hiro <hiro@ee746299-78ed-0310-b773-934348b2243d> | 2005-12-19 06:41:50 +0000 |
---|---|---|
committer | hiro <hiro@ee746299-78ed-0310-b773-934348b2243d> | 2005-12-19 06:41:50 +0000 |
commit | d55459c79d6ddfa0b006c5696d408a7e388cf8c8 (patch) | |
tree | 98e8ea35bfce5bc235adbc544de8aba1f754b8ac /libsylph | |
parent | 1ca5b9aa126b860d9198f85e44104f857513bef5 (diff) |
implemented query search and virtual folder (merged from newsearch branch).
git-svn-id: svn://sylpheed.sraoss.jp/sylpheed/trunk@836 ee746299-78ed-0310-b773-934348b2243d
Diffstat (limited to 'libsylph')
-rw-r--r-- | libsylph/Makefile.am | 1 | ||||
-rw-r--r-- | libsylph/filter.c | 108 | ||||
-rw-r--r-- | libsylph/filter.h | 6 | ||||
-rw-r--r-- | libsylph/folder.c | 17 | ||||
-rw-r--r-- | libsylph/folder.h | 4 | ||||
-rw-r--r-- | libsylph/virtual.c | 297 | ||||
-rw-r--r-- | libsylph/virtual.h | 38 |
7 files changed, 437 insertions, 34 deletions
diff --git a/libsylph/Makefile.am b/libsylph/Makefile.am index 64c37b07..5df644bd 100644 --- a/libsylph/Makefile.am +++ b/libsylph/Makefile.am @@ -43,6 +43,7 @@ libsylph_la_SOURCES = \ unmime.c unmime.h \ utils.c utils.h \ uuencode.c uuencode.h \ + virtual.c virtual.h \ xml.c xml.h libsylph_la_LDFLAGS = diff --git a/libsylph/filter.c b/libsylph/filter.c index a7533bcc..dc2be18b 100644 --- a/libsylph/filter.c +++ b/libsylph/filter.c @@ -304,7 +304,6 @@ gboolean filter_match_rule(FilterRule *rule, MsgInfo *msginfo, GSList *hlist, gboolean matched; g_return_val_if_fail(rule->cond_list != NULL, FALSE); - g_return_val_if_fail(rule->action_list != NULL, FALSE); switch (rule->timing) { case FLT_TIMING_ANY: @@ -485,6 +484,8 @@ static gboolean filter_xml_node_func(GNode *node, gpointer data) gboolean enabled = TRUE; FilterRule *rule; FilterBoolOp bool_op = FLT_OR; + const gchar *target_folder = NULL; + gboolean recursive = FALSE; GSList *cond_list = NULL; GSList *action_list = NULL; GNode *child, *cond_child, *action_child; @@ -558,6 +559,12 @@ static gboolean filter_xml_node_func(GNode *node, gpointer data) type = attr->value; else if (!strcmp(attr->name, "name")) name = attr->value; + else if (!strcmp(attr->name, "recursive")) { + if (!strcmp(attr->value, "true")) + recursive = TRUE; + else + recursive = FALSE; + } } if (type) { @@ -583,6 +590,9 @@ static gboolean filter_xml_node_func(GNode *node, gpointer data) cond_type = FLT_COND_AGE_GREATER; STR_CASE("account-id") cond_type = FLT_COND_ACCOUNT; + STR_CASE("target-folder") + target_folder = value; + continue; STR_CASE_END cond = filter_cond_new(cond_type, match_type, match_flag, @@ -641,10 +651,14 @@ static gboolean filter_xml_node_func(GNode *node, gpointer data) action_list = g_slist_append(action_list, action); } - if (name && cond_list && action_list) { + if (name && cond_list) { rule = filter_rule_new(name, bool_op, cond_list, action_list); rule->timing = timing; rule->enabled = enabled; + if (target_folder) { + rule->target_folder = g_strdup(target_folder); + rule->recursive = recursive; + } *fltlist = g_slist_prepend(*fltlist, rule); } @@ -670,17 +684,41 @@ GSList *filter_xml_node_to_filter_list(GNode *node) return fltlist; } +GSList *filter_read_file(const gchar *file) +{ + GNode *node; + GSList *list; + + g_return_val_if_fail(file != NULL, NULL); + + debug_print("Reading %s\n", file); + + if (!is_file_exist(file)) + return NULL; + + node = xml_parse_file(file); + if (!node) { + g_warning("Can't parse %s\n", file); + return NULL; + } + + list = filter_xml_node_to_filter_list(node); + + xml_free_tree(node); + + return list; +} + void filter_read_config(void) { gchar *rcpath; - GNode *node; - FilterRule *rule; debug_print("Reading filter configuration...\n"); /* remove all previous filter list */ while (prefs_common.fltlist != NULL) { - rule = (FilterRule *)prefs_common.fltlist->data; + FilterRule *rule = (FilterRule *)prefs_common.fltlist->data; + filter_rule_free(rule); prefs_common.fltlist = g_slist_remove(prefs_common.fltlist, rule); @@ -688,22 +726,8 @@ void filter_read_config(void) rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_LIST, NULL); - if (!is_file_exist(rcpath)) { - g_free(rcpath); - return; - } - - node = xml_parse_file(rcpath); - if (!node) { - g_warning("Can't parse %s\n", rcpath); - g_free(rcpath); - return; - } + prefs_common.fltlist = filter_read_file(rcpath); g_free(rcpath); - - prefs_common.fltlist = filter_xml_node_to_filter_list(node); - - xml_free_tree(node); } #define NODE_NEW(tag, text) \ @@ -711,26 +735,23 @@ void filter_read_config(void) #define ADD_ATTR(name, value) \ xml_tag_add_attr(node->tag, xml_attr_new(name, value)) -void filter_write_config(void) +void filter_write_file(GSList *list, const gchar *file) { - gchar *rcpath; PrefFile *pfile; GSList *cur; - debug_print("Writing filter configuration...\n"); + g_return_if_fail(file != NULL); - rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_LIST, - NULL); - if ((pfile = prefs_file_open(rcpath)) == NULL) { - g_warning("failed to write filter configuration to file\n"); - g_free(rcpath); + if ((pfile = prefs_file_open(file)) == NULL) { + g_warning("failed to write filter configuration to file: %s\n", + file); return; } xml_file_put_xml_decl(pfile->fp); fputs("\n<filter>\n", pfile->fp); - for (cur = prefs_common.fltlist; cur != NULL; cur = cur->next) { + for (cur = list; cur != NULL; cur = cur->next) { FilterRule *rule = (FilterRule *)cur->data; GSList *cur_cond; GSList *cur_action; @@ -820,6 +841,17 @@ void filter_write_config(void) } } + if (rule->target_folder) { + XMLNode *node; + + NODE_NEW("target-folder", rule->target_folder); + ADD_ATTR("recursive", rule->recursive + ? "true" : "false"); + fputs(" ", pfile->fp); + xml_file_put_node(pfile->fp, node); + xml_free_node(node); + } + fputs(" </condition-list>\n", pfile->fp); fputs(" <action-list>\n", pfile->fp); @@ -888,14 +920,25 @@ void filter_write_config(void) fputs("</filter>\n", pfile->fp); - g_free(rcpath); - if (prefs_file_close(pfile) < 0) { - g_warning(_("failed to write configuration to file\n")); + g_warning("failed to write filter configuration to file: %s\n", + file); return; } } +void filter_write_config(void) +{ + gchar *rcpath; + + debug_print("Writing filter configuration...\n"); + + rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_LIST, + NULL); + filter_write_file(prefs_common.fltlist, rcpath); + g_free(rcpath); +} + #undef NODE_NEW #undef ADD_ATTR @@ -1399,6 +1442,7 @@ void filter_rule_free(FilterRule *rule) if (!rule) return; g_free(rule->name); + g_free(rule->target_folder); filter_cond_list_free(rule->cond_list); filter_action_list_free(rule->action_list); diff --git a/libsylph/filter.h b/libsylph/filter.h index 637991e6..7144d9cc 100644 --- a/libsylph/filter.h +++ b/libsylph/filter.h @@ -133,6 +133,9 @@ struct _FilterRule FilterTiming timing; gboolean enabled; + + gchar *target_folder; + gboolean recursive; }; struct _FilterInfo @@ -167,7 +170,10 @@ gboolean filter_rule_requires_full_headers (FilterRule *rule); /* read / write config */ GSList *filter_xml_node_to_filter_list (GNode *node); +GSList *filter_read_file (const gchar *file); void filter_read_config (void); +void filter_write_file (GSList *list, + const gchar *file); void filter_write_config (void); /* for old filterrc */ diff --git a/libsylph/folder.c b/libsylph/folder.c index 257f57c8..a86ca878 100644 --- a/libsylph/folder.c +++ b/libsylph/folder.c @@ -34,6 +34,7 @@ #include "imap.h" #include "news.h" #include "mh.h" +#include "virtual.h" #include "utils.h" #include "xml.h" #include "codeconv.h" @@ -819,6 +820,7 @@ void folder_set_missing_folders(void) CREATE_FOLDER_IF_NOT_EXIST(draft, DRAFT_DIR, F_DRAFT); CREATE_FOLDER_IF_NOT_EXIST(queue, QUEUE_DIR, F_QUEUE); CREATE_FOLDER_IF_NOT_EXIST(trash, TRASH_DIR, F_TRASH); + /* CREATE_FOLDER_IF_NOT_EXIST(junk, JUNK_DIR, F_JUNK); */ } } @@ -953,6 +955,11 @@ GSList *folder_item_get_msg_list(FolderItem *item, gboolean use_cache) g_return_val_if_fail(item != NULL, NULL); folder = item->folder; + + if (item->stype == F_VIRTUAL) + return virtual_get_class()->get_msg_list(folder, item, + use_cache); + return folder->klass->get_msg_list(folder, item, use_cache); } @@ -1259,6 +1266,12 @@ static gboolean folder_build_tree(GNode *node, gpointer data) stype = F_QUEUE; else if (!g_ascii_strcasecmp(attr->value, "trash")) stype = F_TRASH; +#if 0 + else if (!g_ascii_strcasecmp(attr->value, "junk")) + stype = F_JUNK; +#endif + else if (!g_ascii_strcasecmp(attr->value, "virtual")) + stype = F_VIRTUAL; } else if (!strcmp(attr->name, "name")) name = attr->value; else if (!strcmp(attr->name, "path")) @@ -1358,6 +1371,7 @@ static gboolean folder_build_tree(GNode *node, gpointer data) case F_DRAFT: folder->draft = item; break; case F_QUEUE: folder->queue = item; break; case F_TRASH: folder->trash = item; break; + /* case F_JUNK: folder->junk = item; break; */ default: break; } item->account = account; @@ -1479,7 +1493,8 @@ static void folder_write_list_recursive(GNode *node, gpointer data) static gchar *folder_type_str[] = {"mh", "mbox", "maildir", "imap", "news", "unknown"}; static gchar *folder_item_stype_str[] = {"normal", "inbox", "outbox", - "draft", "queue", "trash"}; + "draft", "queue", "trash", + "junk", "virtual"}; static gchar *sort_key_str[] = {"none", "number", "size", "date", "thread-date", "from", "subject", "score", "label", diff --git a/libsylph/folder.h b/libsylph/folder.h index 5fc097e9..13f99235 100644 --- a/libsylph/folder.h +++ b/libsylph/folder.h @@ -79,7 +79,9 @@ typedef enum F_OUTBOX, F_DRAFT, F_QUEUE, - F_TRASH + F_TRASH, + F_JUNK, + F_VIRTUAL } SpecialFolderItemType; typedef enum diff --git a/libsylph/virtual.c b/libsylph/virtual.c new file mode 100644 index 00000000..897a7070 --- /dev/null +++ b/libsylph/virtual.c @@ -0,0 +1,297 @@ +/* + * LibSylph -- E-Mail client library + * Copyright (C) 1999-2005 Hiroyuki Yamamoto + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "defs.h" + +#include <glib.h> +#include <glib/gi18n.h> +#include <dirent.h> +#include <sys/stat.h> +#include <time.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#undef MEASURE_TIME + +#include "folder.h" +#include "virtual.h" +#include "procmsg.h" +#include "procheader.h" +#include "filter.h" +#include "utils.h" + +typedef struct _VirtualSearchInfo VirtualSearchInfo; + +struct _VirtualSearchInfo { + FilterRule *rule; + GSList *mlist; +}; + +static void virtual_folder_init (Folder *folder, + const gchar *name, + const gchar *path); + +static GSList *virtual_search_folder (FilterRule *rule, + FolderItem *item); +static gboolean virtual_search_recursive_func + (GNode *node, + gpointer data); + +static Folder *virtual_folder_new (const gchar *name, + const gchar *path); +static void virtual_folder_destroy (Folder *folder); + +static GSList *virtual_get_msg_list (Folder *folder, + FolderItem *item, + gboolean use_cache); +static gchar *virtual_fetch_msg (Folder *folder, + FolderItem *item, + gint num); +static MsgInfo *virtual_get_msginfo (Folder *folder, + FolderItem *item, + gint num); +static gint virtual_close (Folder *folder, + FolderItem *item); + +static gint virtual_scan_folder (Folder *folder, + FolderItem *item); + +static FolderClass virtual_class = +{ + F_VIRTUAL, + + virtual_folder_new, + virtual_folder_destroy, + + NULL, + NULL, + + virtual_get_msg_list, + virtual_fetch_msg, + virtual_get_msginfo, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + virtual_close, + virtual_scan_folder, + + NULL, + NULL, + NULL, + NULL, +}; + + +FolderClass *virtual_get_class(void) +{ + return &virtual_class; +} + +static Folder *virtual_folder_new(const gchar *name, const gchar *path) +{ + Folder *folder; + + folder = (Folder *)g_new0(VirtualFolder, 1); + virtual_folder_init(folder, name, path); + + return folder; +} + +static void virtual_folder_destroy(Folder *folder) +{ + folder_local_folder_destroy(LOCAL_FOLDER(folder)); +} + +static void virtual_folder_init(Folder *folder, const gchar *name, + const gchar *path) +{ + folder->klass = virtual_get_class(); + folder_local_folder_init(folder, name, path); +} + +static GSList *virtual_search_folder(FilterRule *rule, FolderItem *item) +{ + GSList *match_list = NULL; + GSList *mlist; + GSList *cur; + FilterInfo fltinfo; + gboolean full_headers; + + g_return_val_if_fail(rule != NULL, NULL); + g_return_val_if_fail(item != NULL, NULL); + + /* prevent circular reference */ + if (item->stype == F_VIRTUAL) + return NULL; + + mlist = folder_item_get_msg_list(item, TRUE); + + memset(&fltinfo, 0, sizeof(FilterInfo)); + + debug_print("start query search: %s\n", item->path ? item->path : ""); + + full_headers = filter_rule_requires_full_headers(rule); + + for (cur = mlist; cur != NULL; cur = cur->next) { + MsgInfo *msginfo = (MsgInfo *)cur->data; + GSList *hlist; + + fltinfo.flags = msginfo->flags; + if (full_headers) { + gchar *file; + + file = procmsg_get_message_file(msginfo); + hlist = procheader_get_header_list_from_file(file); + g_free(file); + } else + hlist = procheader_get_header_list_from_msginfo + (msginfo); + if (!hlist) + continue; + + if (filter_match_rule(rule, msginfo, hlist, &fltinfo)) { + match_list = g_slist_prepend(match_list, msginfo); + cur->data = NULL; + } + + procheader_header_list_destroy(hlist); + } + + procmsg_msg_list_free(mlist); + + return g_slist_reverse(match_list); +} + +static gboolean virtual_search_recursive_func(GNode *node, gpointer data) +{ + VirtualSearchInfo *info = (VirtualSearchInfo *)data; + FolderItem *item; + GSList *mlist; + + g_return_val_if_fail(node->data != NULL, FALSE); + + item = FOLDER_ITEM(node->data); + + if (!item->path) + return FALSE; + + mlist = virtual_search_folder(info->rule, item); + info->mlist = g_slist_concat(info->mlist, mlist); + + return FALSE; +} + +static GSList *virtual_get_msg_list(Folder *folder, FolderItem *item, + gboolean use_cache) +{ + GSList *mlist = NULL; + GSList *flist; + GSList *cur; + FilterRule *rule; + gchar *rule_file; + gchar *path; + FolderItem *target; + gint new = 0, unread = 0, total = 0; + + g_return_val_if_fail(item != NULL, NULL); + g_return_val_if_fail(item->stype == F_VIRTUAL, NULL); + + path = folder_item_get_path(item); + rule_file = g_strconcat(path, G_DIR_SEPARATOR_S, "filter.xml", NULL); + flist = filter_read_file(rule_file); + g_free(rule_file); + + g_free(path); + + if (!flist) { + g_warning("filter rule not found\n"); + return NULL; + } + + rule = (FilterRule *)flist->data; + target = folder_find_item_from_identifier(rule->target_folder); + + if (!target || target == item) { + g_warning("invalid target folder\n"); + goto finish; + } + + if (rule->recursive) { + VirtualSearchInfo info; + + info.rule = rule; + info.mlist = NULL; + g_node_traverse(target->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, + virtual_search_recursive_func, &info); + mlist = info.mlist; + } else + mlist = virtual_search_folder(rule, target); + + for (cur = mlist; cur != NULL; cur = cur->next) { + MsgInfo *msginfo = (MsgInfo *)cur->data; + + if (MSG_IS_NEW(msginfo->flags)) + ++new; + if (MSG_IS_UNREAD(msginfo->flags)) + ++unread; + ++total; + } + + item->new = new; + item->unread = unread; + item->total = total; + item->updated = TRUE; + +finish: + filter_rule_list_free(flist); + return mlist; +} + +static gchar *virtual_fetch_msg(Folder *folder, FolderItem *item, gint num) +{ + return NULL; +} + +static MsgInfo *virtual_get_msginfo(Folder *folder, FolderItem *item, gint num) +{ + return NULL; +} + +static gint virtual_close(Folder *folder, FolderItem *item) +{ + return 0; +} + +static gint virtual_scan_folder(Folder *folder, FolderItem *item) +{ + /* do search */ + return 0; +} diff --git a/libsylph/virtual.h b/libsylph/virtual.h new file mode 100644 index 00000000..1a7ba38f --- /dev/null +++ b/libsylph/virtual.h @@ -0,0 +1,38 @@ +/* + * LibSylph -- E-Mail client library + * Copyright (C) 1999-2005 Hiroyuki Yamamoto + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __VIRTUAL_H__ +#define __VIRTUAL_H__ + +#include <glib.h> + +#include "folder.h" + +typedef struct _VirtualFolder VirtualFolder; + +#define VIRTUAL_FOLDER(obj) ((VirtualFolder *)obj) + +struct _VirtualFolder +{ + LocalFolder lfolder; +}; + +FolderClass *virtual_get_class (void); + +#endif /* __VIRTUAL_H__ */ |