aboutsummaryrefslogtreecommitdiff
path: root/libsylph
diff options
context:
space:
mode:
authorhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2005-12-19 06:41:50 +0000
committerhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2005-12-19 06:41:50 +0000
commitd55459c79d6ddfa0b006c5696d408a7e388cf8c8 (patch)
tree98e8ea35bfce5bc235adbc544de8aba1f754b8ac /libsylph
parent1ca5b9aa126b860d9198f85e44104f857513bef5 (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.am1
-rw-r--r--libsylph/filter.c108
-rw-r--r--libsylph/filter.h6
-rw-r--r--libsylph/folder.c17
-rw-r--r--libsylph/folder.h4
-rw-r--r--libsylph/virtual.c297
-rw-r--r--libsylph/virtual.h38
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__ */