aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--ChangeLog.ja13
-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
-rw-r--r--src/folderview.c29
-rw-r--r--src/mainwindow.c9
-rw-r--r--src/prefs_filter_edit.c7
-rw-r--r--src/prefs_filter_edit.h19
-rw-r--r--src/prefs_folder_item.c3
-rw-r--r--src/summary_search.c1156
-rw-r--r--src/summary_search.h4
-rw-r--r--src/summaryview.c2
17 files changed, 1337 insertions, 390 deletions
diff --git a/ChangeLog b/ChangeLog
index 064cf165..6059a7c8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
2005-12-19
+ * libsylph/virtual.[ch]
+ libsylph/folder.[ch]
+ libsylph/filter.[ch]
+ libsylph/Makefile.am
+ src/summary_search.[ch]
+ src/prefs_folder_item.c
+ src/summaryview.c
+ src/folderview.c
+ src/mainwindow.c
+ src/prefs_filter_edit.[ch]: implemented query search and virtual
+ folder.
+
+2005-12-19
+
* libsylph/codeconv.[ch]: support nonstandard encoding
"ks_c_5601-1987" (thanks to Yoo Chung).
diff --git a/ChangeLog.ja b/ChangeLog.ja
index 47e17a66..050b6e03 100644
--- a/ChangeLog.ja
+++ b/ChangeLog.ja
@@ -1,5 +1,18 @@
2005-12-19
+ * libsylph/virtual.[ch]
+ libsylph/folder.[ch]
+ libsylph/filter.[ch]
+ libsylph/Makefile.am
+ src/summary_search.[ch]
+ src/prefs_folder_item.c
+ src/summaryview.c
+ src/folderview.c
+ src/mainwindow.c
+ src/prefs_filter_edit.[ch]: クエリ検索と仮想フォルダを実装。
+
+2005-12-19
+
* libsylph/codeconv.[ch]: 非標準なエンコーディング "ks_c_5601-1987"
に対応(Yoo Chung さん thanks)。
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__ */
diff --git a/src/folderview.c b/src/folderview.c
index 43ff7732..42965160 100644
--- a/src/folderview.c
+++ b/src/folderview.c
@@ -105,6 +105,7 @@ static GdkPixbuf *folderopen_pixbuf;
static GdkPixbuf *foldernoselect_pixbuf;
static GdkPixbuf *draft_pixbuf;
static GdkPixbuf *trash_pixbuf;
+static GdkPixbuf *virtual_pixbuf;
static void folderview_set_columns (FolderView *folderview);
@@ -516,6 +517,7 @@ void folderview_init(FolderView *folderview)
&foldernoselect_pixbuf);
stock_pixbuf_gdk(treeview, STOCK_PIXMAP_DRAFT, &draft_pixbuf);
stock_pixbuf_gdk(treeview, STOCK_PIXMAP_TRASH, &trash_pixbuf);
+ stock_pixbuf_gdk(treeview, STOCK_PIXMAP_GROUP, &virtual_pixbuf);
}
void folderview_reflect_prefs(FolderView *folderview)
@@ -1170,6 +1172,19 @@ static void folderview_update_row(FolderView *folderview, GtkTreeIter *iter)
!strcmp2(item->name, DRAFT_DIR) ? _("Drafts") :
item->name);
break;
+#if 0
+ case F_JUNK:
+ pixbuf = folder_pixbuf;
+ open_pixbuf = folderopen_pixbuf;
+ name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
+ !strcmp2(item->name, JUNK_DIR) ? _("Junk") :
+ item->name);
+ break;
+#endif
+ case F_VIRTUAL:
+ pixbuf = open_pixbuf = virtual_pixbuf;
+ name = g_strdup(item->name);
+ break;
default:
if (item->no_select) {
pixbuf = open_pixbuf = foldernoselect_pixbuf;
@@ -1540,14 +1555,13 @@ static gboolean folderview_menu_popup(FolderView *folderview,
if (folderview->mainwin->lock_count == 0) {
new_folder = TRUE;
folder_property = TRUE;
+ search_folder = TRUE;
if (item->parent == NULL) {
update_tree = remove_tree = TRUE;
} else {
if (gtkut_tree_row_reference_equal
- (folderview->selected, folderview->opened)) {
+ (folderview->selected, folderview->opened))
update_summary = TRUE;
- search_folder = TRUE;
- }
}
if (FOLDER_IS_LOCAL(folder) || FOLDER_TYPE(folder) == F_IMAP) {
if (item->parent == NULL)
@@ -1562,6 +1576,9 @@ static gboolean folderview_menu_popup(FolderView *folderview,
if (item->parent != NULL)
delete_folder = TRUE;
}
+ if (item->stype == F_VIRTUAL) {
+ rename_folder = delete_folder = TRUE;
+ }
if (FOLDER_TYPE(folder) == F_IMAP ||
FOLDER_TYPE(folder) == F_NEWS) {
if (item->parent != NULL && item->no_select == FALSE)
@@ -2608,7 +2625,11 @@ static void folderview_rm_news_server_cb(FolderView *folderview, guint action,
static void folderview_search_cb(FolderView *folderview, guint action,
GtkWidget *widget)
{
- summary_search(folderview->summaryview);
+ FolderItem *item;
+
+ item = folderview_get_selected_item(folderview);
+ if (item)
+ summary_search(folderview->summaryview, item);
}
static void folderview_property_cb(FolderView *folderview, guint action,
diff --git a/src/mainwindow.c b/src/mainwindow.c
index 19afdda3..d7f90d19 100644
--- a/src/mainwindow.c
+++ b/src/mainwindow.c
@@ -2758,9 +2758,12 @@ static void app_exit_cb(MainWindow *mainwin, guint action, GtkWidget *widget)
static void search_cb(MainWindow *mainwin, guint action, GtkWidget *widget)
{
- if (action == 1)
- summary_search(mainwin->summaryview);
- else
+ if (action == 1) {
+ FolderItem *item;
+
+ item = folderview_get_selected_item(mainwin->folderview);
+ summary_search(mainwin->summaryview, item);
+ } else
message_search(mainwin->messageview);
}
diff --git a/src/prefs_filter_edit.c b/src/prefs_filter_edit.c
index 52821448..af804aed 100644
--- a/src/prefs_filter_edit.c
+++ b/src/prefs_filter_edit.c
@@ -335,6 +335,7 @@ FilterCondEdit *prefs_filter_edit_cond_edit_create(void)
cond_edit->cond_hbox_list = NULL;
cond_edit->hdr_list = NULL;
cond_edit->rule_hdr_list = NULL;
+ cond_edit->add_hbox = NULL;
return cond_edit;
}
@@ -1243,6 +1244,8 @@ static void prefs_filter_edit_add_rule_cond(FilterCondEdit *cond_edit,
hbox = prefs_filter_edit_cond_hbox_create(cond_edit);
prefs_filter_edit_set_cond_hbox_widgets(hbox, PF_COND_HEADER);
prefs_filter_edit_insert_cond_hbox(cond_edit, hbox, -1);
+ if (cond_edit->add_hbox)
+ cond_edit->add_hbox(hbox);
return;
}
@@ -1252,6 +1255,8 @@ static void prefs_filter_edit_add_rule_cond(FilterCondEdit *cond_edit,
hbox = prefs_filter_edit_cond_hbox_create(cond_edit);
prefs_filter_edit_cond_hbox_set(hbox, cond);
prefs_filter_edit_insert_cond_hbox(cond_edit, hbox, -1);
+ if (cond_edit->add_hbox)
+ cond_edit->add_hbox(hbox);
}
}
@@ -1964,6 +1969,8 @@ static void prefs_filter_cond_add_cb(GtkWidget *widget, gpointer data)
new_hbox = prefs_filter_edit_cond_hbox_create(cond_edit);
prefs_filter_edit_set_cond_hbox_widgets(new_hbox, PF_COND_HEADER);
prefs_filter_edit_insert_cond_hbox(cond_edit, new_hbox, index + 1);
+ if (cond_edit->add_hbox)
+ cond_edit->add_hbox(new_hbox);
}
static void prefs_filter_action_del_cb(GtkWidget *widget, gpointer data)
diff --git a/src/prefs_filter_edit.h b/src/prefs_filter_edit.h
index fd720fa2..dbc967f3 100644
--- a/src/prefs_filter_edit.h
+++ b/src/prefs_filter_edit.h
@@ -24,6 +24,10 @@
#include "filter.h"
+typedef struct _FilterCondEdit FilterCondEdit;
+typedef struct _CondHBox CondHBox;
+typedef struct _ActionHBox ActionHBox;
+
typedef enum
{
PF_COND_HEADER,
@@ -81,15 +85,18 @@ typedef enum
PF_ACTION_NONE
} ActionMenuType;
-typedef struct _FilterCondEdit {
+struct _FilterCondEdit {
GtkWidget *cond_vbox;
GSList *cond_hbox_list;
GSList *hdr_list;
GSList *rule_hdr_list;
-} FilterCondEdit;
-typedef struct _CondHBox {
+ /* callback */
+ void (*add_hbox) (CondHBox *hbox);
+};
+
+struct _CondHBox {
GtkWidget *hbox;
GtkWidget *cond_type_optmenu;
@@ -107,9 +114,9 @@ typedef struct _CondHBox {
gchar *cur_header_name;
FilterCondEdit *cond_edit;
-} CondHBox;
+};
-typedef struct _ActionHBox {
+struct _ActionHBox {
GtkWidget *hbox;
GtkWidget *action_type_optmenu;
@@ -125,7 +132,7 @@ typedef struct _ActionHBox {
GtkWidget *del_btn;
GtkWidget *add_btn;
-} ActionHBox;
+};
FilterRule *prefs_filter_edit_open (FilterRule *rule,
diff --git a/src/prefs_folder_item.c b/src/prefs_folder_item.c
index fefe44bc..9d777eba 100644
--- a/src/prefs_folder_item.c
+++ b/src/prefs_folder_item.c
@@ -561,6 +561,9 @@ static void prefs_folder_item_apply_cb(GtkWidget *widget,
prev_item = folder->trash;
folder->trash = item;
break;
+ default:
+ type = item->stype;
+ break;
}
item->stype = type;
diff --git a/src/summary_search.c b/src/summary_search.c
index c388944a..d6a76017 100644
--- a/src/summary_search.c
+++ b/src/summary_search.c
@@ -40,69 +40,139 @@
#include <gtk/gtkmenuitem.h>
#include <gtk/gtkstock.h>
#include <gtk/gtktreemodel.h>
+#include <gtk/gtkliststore.h>
+#include <gtk/gtktreeview.h>
#include <gtk/gtktreeselection.h>
+#include <gtk/gtkcellrenderertext.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "main.h"
#include "summary_search.h"
+#include "prefs_filter_edit.h"
#include "summaryview.h"
#include "messageview.h"
#include "mainwindow.h"
+#include "folderview.h"
#include "menu.h"
#include "utils.h"
#include "gtkutils.h"
#include "manage_window.h"
#include "alertpanel.h"
+#include "foldersel.h"
+#include "procmsg.h"
+#include "procheader.h"
+#include "folder.h"
+#include "filter.h"
+#include "prefs_filter.h"
+#include "prefs_filter_edit.h"
+
+enum
+{
+ COL_FOLDER,
+ COL_SUBJECT,
+ COL_FROM,
+ COL_DATE,
+ COL_MSGINFO,
+ N_COLS
+};
static struct SummarySearchWindow {
GtkWidget *window;
GtkWidget *bool_optmenu;
- GtkWidget *from_entry;
- GtkWidget *to_entry;
- GtkWidget *subject_entry;
- GtkWidget *body_entry;
+ FilterCondEdit *cond_edit;
+
+ GtkWidget *folder_entry;
+ GtkWidget *folder_btn;
+ GtkWidget *subfolder_checkbtn;
GtkWidget *case_checkbtn;
+ GtkWidget *treeview;
+ GtkListStore *store;
+
+ GtkWidget *status_label;
+
GtkWidget *clear_btn;
+ GtkWidget *search_btn;
+ GtkWidget *save_btn;
GtkWidget *close_btn;
- GtkWidget *all_btn;
- GtkWidget *prev_btn;
- GtkWidget *next_btn;
SummaryView *summaryview;
+
+ FilterRule *rule;
+ gboolean requires_full_headers;
+
+ gboolean on_search;
+ gboolean cancelled;
} search_window;
+typedef struct {
+ GtkWidget *window;
+
+ GtkWidget *folder_entry;
+ GtkWidget *name_entry;
+
+ gboolean cancelled;
+ gboolean finished;
+} SummarySearchSaveDialog;
+
static void summary_search_create (void);
-static void summary_search_execute (gboolean backward,
- gboolean search_all);
+static FilterRule *summary_search_dialog_to_rule
+ (const gchar *name,
+ FolderItem **item);
+
+static void summary_search_query (void);
+static void summary_search_folder (FolderItem *item);
+
+static gboolean summary_search_recursive_func (GNode *node,
+ gpointer data);
+
+static void summary_search_append_msg (MsgInfo *msginfo);
+static void summary_search_clear_list (void);
+
+static void summary_search_hbox_added (CondHBox *hbox);
+
+static void row_activated (GtkTreeView *treeview,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ gpointer data);
+
+static gboolean row_selected (GtkTreeSelection *selection,
+ GtkTreeModel *model,
+ GtkTreePath *path,
+ gboolean cur_selected,
+ gpointer data);
static void summary_search_clear (GtkButton *button,
gpointer data);
-static void summary_search_prev_clicked (GtkButton *button,
+static void summary_select_folder (GtkButton *button,
+ gpointer data);
+static void summary_search_clicked (GtkButton *button,
gpointer data);
-static void summary_search_next_clicked (GtkButton *button,
+static void summary_search_save (GtkButton *button,
gpointer data);
-static void summary_search_all_clicked (GtkButton *button,
+static void summary_search_close (GtkButton *button,
gpointer data);
-static void from_activated (void);
-static void to_activated (void);
-static void subject_activated (void);
-static void body_activated (void);
+static void summary_search_entry_activated (GtkWidget *widget,
+ gpointer data);
+static gint summary_search_deleted (GtkWidget *widget,
+ GdkEventAny *event,
+ gpointer data);
static gboolean key_pressed (GtkWidget *widget,
GdkEventKey *event,
gpointer data);
-void summary_search(SummaryView *summaryview)
+void summary_search(SummaryView *summaryview, FolderItem *item)
{
+ gchar *id;
+
if (!search_window.window)
summary_search_create();
else
@@ -110,8 +180,14 @@ void summary_search(SummaryView *summaryview)
search_window.summaryview = summaryview;
- gtk_widget_grab_focus(search_window.next_btn);
- gtk_widget_grab_focus(search_window.subject_entry);
+ if (item) {
+ id = folder_item_get_identifier(item);
+ gtk_entry_set_text(GTK_ENTRY(search_window.folder_entry), id);
+ g_free(id);
+ } else
+ gtk_entry_set_text(GTK_ENTRY(search_window.folder_entry), "");
+
+ gtk_widget_grab_focus(search_window.search_btn);
gtk_widget_show(search_window.window);
}
@@ -124,42 +200,51 @@ static void summary_search_create(void)
GtkWidget *bool_menu;
GtkWidget *menuitem;
GtkWidget *clear_btn;
+ GtkWidget *search_btn;
- GtkWidget *table1;
- GtkWidget *from_label;
- GtkWidget *from_entry;
- GtkWidget *to_label;
- GtkWidget *to_entry;
- GtkWidget *subject_label;
- GtkWidget *subject_entry;
- GtkWidget *body_label;
- GtkWidget *body_entry;
+ GtkWidget *scrolledwin;
+ FilterCondEdit *cond_edit;
+ CondHBox *cond_hbox;
+
+ GtkWidget *folder_hbox;
+ GtkWidget *folder_label;
+ GtkWidget *folder_entry;
+ GtkWidget *folder_btn;
GtkWidget *checkbtn_hbox;
+ GtkWidget *subfolder_checkbtn;
GtkWidget *case_checkbtn;
+ GtkWidget *treeview;
+ GtkListStore *store;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ GtkTreeSelection *selection;
+
GtkWidget *confirm_area;
+
+ GtkWidget *status_label;
+
+ GtkWidget *hbbox;
+ GtkWidget *save_btn;
GtkWidget *close_btn;
- GtkWidget *all_btn;
- GtkWidget *prev_btn;
- GtkWidget *next_btn;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW (window), _("Search messages"));
- gtk_widget_set_size_request(window, 450, -1);
+ gtk_widget_set_size_request(window, 600, -1);
gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, TRUE);
gtk_container_set_border_width(GTK_CONTAINER (window), 8);
g_signal_connect(G_OBJECT(window), "delete_event",
- G_CALLBACK(gtk_widget_hide_on_delete), NULL);
+ G_CALLBACK(summary_search_deleted), NULL);
g_signal_connect(G_OBJECT(window), "key_press_event",
G_CALLBACK(key_pressed), NULL);
MANAGE_WINDOW_SIGNALS_CONNECT(window);
- vbox1 = gtk_vbox_new (FALSE, 0);
+ vbox1 = gtk_vbox_new (FALSE, 6);
gtk_widget_show (vbox1);
gtk_container_add (GTK_CONTAINER (window), vbox1);
- bool_hbox = gtk_hbox_new(FALSE, 4);
+ bool_hbox = gtk_hbox_new(FALSE, 12);
gtk_widget_show(bool_hbox);
gtk_box_pack_start(GTK_BOX(vbox1), bool_hbox, FALSE, FALSE, 0);
@@ -168,389 +253,778 @@ static void summary_search_create(void)
gtk_box_pack_start(GTK_BOX(bool_hbox), bool_optmenu, FALSE, FALSE, 0);
bool_menu = gtk_menu_new();
- MENUITEM_ADD(bool_menu, menuitem, _("Match any of the following"), 0);
- MENUITEM_ADD(bool_menu, menuitem, _("Match all of the following"), 1);
+ MENUITEM_ADD(bool_menu, menuitem, _("Match any of the following"),
+ FLT_OR);
+ MENUITEM_ADD(bool_menu, menuitem, _("Match all of the following"),
+ FLT_AND);
gtk_option_menu_set_menu(GTK_OPTION_MENU(bool_optmenu), bool_menu);
+ hbbox = gtk_hbutton_box_new();
+ gtk_widget_show(hbbox);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing(GTK_BOX(hbbox), 6);
+ gtk_box_pack_end(GTK_BOX(bool_hbox), hbbox, FALSE, FALSE, 0);
+
clear_btn = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
gtk_widget_show(clear_btn);
- gtk_box_pack_end(GTK_BOX(bool_hbox), clear_btn, FALSE, FALSE, 0);
-
- table1 = gtk_table_new (4, 3, FALSE);
- gtk_widget_show (table1);
- gtk_box_pack_start (GTK_BOX (vbox1), table1, TRUE, TRUE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (table1), 4);
- gtk_table_set_row_spacings (GTK_TABLE (table1), 8);
- gtk_table_set_col_spacings (GTK_TABLE (table1), 8);
-
- from_entry = gtk_entry_new ();
- gtk_widget_show (from_entry);
- gtk_table_attach (GTK_TABLE (table1), from_entry, 1, 3, 0, 1,
- GTK_EXPAND|GTK_FILL, 0, 0, 0);
- g_signal_connect(G_OBJECT(from_entry), "activate",
- G_CALLBACK(from_activated), NULL);
-
- to_entry = gtk_entry_new ();
- gtk_widget_show (to_entry);
- gtk_table_attach (GTK_TABLE (table1), to_entry, 1, 3, 1, 2,
- GTK_EXPAND|GTK_FILL, 0, 0, 0);
- g_signal_connect(G_OBJECT(to_entry), "activate",
- G_CALLBACK(to_activated), NULL);
-
- subject_entry = gtk_entry_new ();
- gtk_widget_show (subject_entry);
- gtk_table_attach (GTK_TABLE (table1), subject_entry, 1, 3, 2, 3,
- GTK_EXPAND|GTK_FILL, 0, 0, 0);
- g_signal_connect(G_OBJECT(subject_entry), "activate",
- G_CALLBACK(subject_activated), NULL);
-
- body_entry = gtk_entry_new ();
- gtk_widget_show (body_entry);
- gtk_table_attach (GTK_TABLE (table1), body_entry, 1, 3, 3, 4,
- GTK_EXPAND|GTK_FILL, 0, 0, 0);
- g_signal_connect(G_OBJECT(body_entry), "activate",
- G_CALLBACK(body_activated), NULL);
-
- from_label = gtk_label_new (_("From:"));
- gtk_widget_show (from_label);
- gtk_table_attach (GTK_TABLE (table1), from_label, 0, 1, 0, 1,
- GTK_FILL, 0, 0, 0);
- gtk_label_set_justify (GTK_LABEL (from_label), GTK_JUSTIFY_RIGHT);
- gtk_misc_set_alignment (GTK_MISC (from_label), 1, 0.5);
-
- to_label = gtk_label_new (_("To:"));
- gtk_widget_show (to_label);
- gtk_table_attach (GTK_TABLE (table1), to_label, 0, 1, 1, 2,
- GTK_FILL, 0, 0, 0);
- gtk_label_set_justify (GTK_LABEL (to_label), GTK_JUSTIFY_RIGHT);
- gtk_misc_set_alignment (GTK_MISC (to_label), 1, 0.5);
-
- subject_label = gtk_label_new (_("Subject:"));
- gtk_widget_show (subject_label);
- gtk_table_attach (GTK_TABLE (table1), subject_label, 0, 1, 2, 3,
- GTK_FILL, 0, 0, 0);
- gtk_label_set_justify (GTK_LABEL (subject_label), GTK_JUSTIFY_RIGHT);
- gtk_misc_set_alignment (GTK_MISC (subject_label), 1, 0.5);
-
- body_label = gtk_label_new (_("Body:"));
- gtk_widget_show (body_label);
- gtk_table_attach (GTK_TABLE (table1), body_label, 0, 1, 3, 4,
- GTK_FILL, 0, 0, 0);
- gtk_label_set_justify (GTK_LABEL (body_label), GTK_JUSTIFY_RIGHT);
- gtk_misc_set_alignment (GTK_MISC (body_label), 1, 0.5);
-
- checkbtn_hbox = gtk_hbox_new (FALSE, 8);
+ gtk_box_pack_start(GTK_BOX(hbbox), clear_btn, FALSE, FALSE, 0);
+
+ search_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
+ GTK_WIDGET_SET_FLAGS(search_btn, GTK_CAN_DEFAULT);
+ gtk_widget_show(search_btn);
+ gtk_box_pack_start(GTK_BOX(hbbox), search_btn, FALSE, FALSE, 0);
+ gtk_widget_grab_default(search_btn);
+
+ scrolledwin = gtk_scrolled_window_new(NULL, NULL);
+ gtk_widget_show(scrolledwin);
+ gtk_box_pack_start(GTK_BOX(vbox1), scrolledwin, FALSE, FALSE, 0);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_set_size_request(scrolledwin, -1, 120);
+
+ cond_edit = prefs_filter_edit_cond_edit_create();
+ cond_edit->add_hbox = summary_search_hbox_added;
+ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolledwin),
+ cond_edit->cond_vbox);
+ prefs_filter_set_header_list(NULL);
+ prefs_filter_edit_set_header_list(cond_edit, NULL);
+ cond_hbox = prefs_filter_edit_cond_hbox_create(cond_edit);
+ prefs_filter_edit_set_cond_hbox_widgets(cond_hbox, PF_COND_HEADER);
+ prefs_filter_edit_insert_cond_hbox(cond_edit, cond_hbox, -1);
+ if (cond_edit->add_hbox)
+ cond_edit->add_hbox(cond_hbox);
+
+ folder_hbox = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (folder_hbox);
+ gtk_box_pack_start (GTK_BOX (vbox1), folder_hbox, FALSE, FALSE, 0);
+
+ folder_label = gtk_label_new (_("Folder:"));
+ gtk_widget_show (folder_label);
+ gtk_box_pack_start (GTK_BOX (folder_hbox), folder_label,
+ FALSE, FALSE, 0);
+
+ folder_entry = gtk_entry_new ();
+ gtk_widget_show (folder_entry);
+ gtk_box_pack_start (GTK_BOX (folder_hbox), folder_entry, TRUE, TRUE, 0);
+
+ folder_btn = gtk_button_new_with_label("...");
+ gtk_widget_show (folder_btn);
+ gtk_box_pack_start (GTK_BOX (folder_hbox), folder_btn, FALSE, FALSE, 0);
+
+ checkbtn_hbox = gtk_hbox_new (FALSE, 12);
gtk_widget_show (checkbtn_hbox);
- gtk_box_pack_start (GTK_BOX (vbox1), checkbtn_hbox, TRUE, TRUE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (checkbtn_hbox), 8);
+ gtk_box_pack_start (GTK_BOX (vbox1), checkbtn_hbox, FALSE, FALSE, 0);
+
+ subfolder_checkbtn =
+ gtk_check_button_new_with_label (_("Search subfolders"));
+ gtk_widget_show (subfolder_checkbtn);
+ gtk_box_pack_start (GTK_BOX (checkbtn_hbox), subfolder_checkbtn,
+ FALSE, FALSE, 0);
case_checkbtn = gtk_check_button_new_with_label (_("Case sensitive"));
gtk_widget_show (case_checkbtn);
gtk_box_pack_start (GTK_BOX (checkbtn_hbox), case_checkbtn,
FALSE, FALSE, 0);
- confirm_area = gtk_hbutton_box_new();
- gtk_widget_show (confirm_area);
- gtk_button_box_set_layout(GTK_BUTTON_BOX(confirm_area),
- GTK_BUTTONBOX_END);
- gtk_box_set_spacing(GTK_BOX(confirm_area), 6);
+ scrolledwin = gtk_scrolled_window_new(NULL, NULL);
+ gtk_box_pack_start(GTK_BOX(vbox1), scrolledwin, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
+ GTK_SHADOW_IN);
+ gtk_widget_set_size_request(scrolledwin, -1, 150);
+
+ store = gtk_list_store_new(N_COLS,
+ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_POINTER);
+ treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+ g_object_unref(store);
+ gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
+ g_signal_connect(G_OBJECT(treeview), "row-activated",
+ G_CALLBACK(row_activated), NULL);
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
+ gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
+ gtk_tree_selection_set_select_function(selection, row_selected,
+ NULL, NULL);
+
+ gtk_container_add(GTK_CONTAINER(scrolledwin), treeview);
+
+#define APPEND_COLUMN(label, col, width) \
+{ \
+ renderer = gtk_cell_renderer_text_new(); \
+ column = gtk_tree_view_column_new_with_attributes \
+ (label, renderer, "text", col, NULL); \
+ gtk_tree_view_column_set_resizable(column, TRUE); \
+ if (width) { \
+ gtk_tree_view_column_set_sizing \
+ (column, GTK_TREE_VIEW_COLUMN_FIXED); \
+ gtk_tree_view_column_set_fixed_width(column, width); \
+ } \
+ gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); \
+}
- close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
- GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
- gtk_box_pack_start(GTK_BOX(confirm_area), close_btn, TRUE, TRUE, 0);
- gtk_widget_show(close_btn);
+ APPEND_COLUMN(_("Folder"), COL_FOLDER, 0);
+ APPEND_COLUMN(_("Subject"), COL_SUBJECT, 200);
+ APPEND_COLUMN(_("From"), COL_FROM, 180);
+ APPEND_COLUMN(_("Date"), COL_DATE, 0);
+
+ gtk_widget_show_all(scrolledwin);
- all_btn = gtk_button_new_from_stock(_("Find all"));
- GTK_WIDGET_SET_FLAGS(all_btn, GTK_CAN_DEFAULT);
- gtk_box_pack_start(GTK_BOX(confirm_area), all_btn, TRUE, TRUE, 0);
- gtk_widget_show(all_btn);
+ confirm_area = gtk_hbox_new(FALSE, 12);
+ gtk_widget_show(confirm_area);
+ gtk_box_pack_start(GTK_BOX(vbox1), confirm_area, FALSE, FALSE, 0);
- prev_btn = gtk_button_new_from_stock(GTK_STOCK_GO_BACK);
- GTK_WIDGET_SET_FLAGS(prev_btn, GTK_CAN_DEFAULT);
- gtk_box_pack_start(GTK_BOX(confirm_area), prev_btn, TRUE, TRUE, 0);
- gtk_widget_show(prev_btn);
+ status_label = gtk_label_new("");
+ gtk_widget_show(status_label);
+ gtk_box_pack_start(GTK_BOX(confirm_area), status_label,
+ FALSE, FALSE, 0);
- next_btn = gtk_button_new_from_stock(GTK_STOCK_GO_FORWARD);
- GTK_WIDGET_SET_FLAGS(next_btn, GTK_CAN_DEFAULT);
- gtk_box_pack_start(GTK_BOX(confirm_area), next_btn, TRUE, TRUE, 0);
- gtk_widget_show(next_btn);
+ hbbox = gtk_hbutton_box_new();
+ gtk_widget_show(hbbox);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing(GTK_BOX(hbbox), 6);
+ gtk_box_pack_end(GTK_BOX(confirm_area), hbbox, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (vbox1), confirm_area, FALSE, FALSE, 0);
- gtk_widget_grab_default(next_btn);
+ save_btn = gtk_button_new_with_mnemonic(_("_Save as search folder"));
+ gtk_box_pack_start(GTK_BOX(hbbox), save_btn, FALSE, FALSE, 0);
+ gtk_widget_show(save_btn);
+
+ close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+ GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
+ gtk_box_pack_start(GTK_BOX(hbbox), close_btn, FALSE, FALSE, 0);
+ gtk_widget_show(close_btn);
g_signal_connect(G_OBJECT(clear_btn), "clicked",
G_CALLBACK(summary_search_clear), NULL);
- g_signal_connect(G_OBJECT(all_btn), "clicked",
- G_CALLBACK(summary_search_all_clicked), NULL);
- g_signal_connect(G_OBJECT(prev_btn), "clicked",
- G_CALLBACK(summary_search_prev_clicked), NULL);
- g_signal_connect(G_OBJECT(next_btn), "clicked",
- G_CALLBACK(summary_search_next_clicked), NULL);
- g_signal_connect_closure
- (G_OBJECT(close_btn), "clicked",
- g_cclosure_new_swap(G_CALLBACK(gtk_widget_hide),
- window, NULL),
- FALSE);
+ g_signal_connect(G_OBJECT(folder_btn), "clicked",
+ G_CALLBACK(summary_select_folder), NULL);
+ g_signal_connect(G_OBJECT(search_btn), "clicked",
+ G_CALLBACK(summary_search_clicked), NULL);
+ g_signal_connect(G_OBJECT(save_btn), "clicked",
+ G_CALLBACK(summary_search_save), NULL);
+ g_signal_connect(G_OBJECT(close_btn), "clicked",
+ G_CALLBACK(summary_search_close), NULL);
search_window.window = window;
search_window.bool_optmenu = bool_optmenu;
- search_window.from_entry = from_entry;
- search_window.to_entry = to_entry;
- search_window.subject_entry = subject_entry;
- search_window.body_entry = body_entry;
+
+ search_window.cond_edit = cond_edit;
+
+ search_window.folder_entry = folder_entry;
+ search_window.folder_btn = folder_btn;
+ search_window.subfolder_checkbtn = subfolder_checkbtn;
search_window.case_checkbtn = case_checkbtn;
+
+ search_window.treeview = treeview;
+ search_window.store = store;
+
+ search_window.status_label = status_label;
+
search_window.clear_btn = clear_btn;
+ search_window.search_btn = search_btn;
+ search_window.save_btn = save_btn;
search_window.close_btn = close_btn;
- search_window.all_btn = all_btn;
- search_window.prev_btn = prev_btn;
- search_window.next_btn = next_btn;
}
-static void summary_search_execute(gboolean backward, gboolean search_all)
+static FilterRule *summary_search_dialog_to_rule(const gchar *name,
+ FolderItem **item)
{
- SummaryView *summaryview = search_window.summaryview;
- GtkTreeModel *model;
- GtkTreeIter iter;
- MsgInfo *msginfo;
- gboolean bool_and;
+ const gchar *id;
+ FolderItem *item_;
+ FilterBoolOp bool_op = FLT_OR;
+ gboolean recursive;
gboolean case_sens;
- gboolean all_searched = FALSE;
- gboolean matched;
- gboolean body_matched;
- const gchar *from_str, *to_str, *subject_str, *body_str;
- StrFindFunc str_find_func;
- gboolean valid;
-
- if (summary_is_locked(summaryview)) return;
- summary_lock(summaryview);
-
- model = GTK_TREE_MODEL(summaryview->store);
-
- bool_and = menu_get_option_menu_active_index
+ GSList *cond_list = NULL;
+ FilterCond *cond;
+ FilterRule *rule;
+ GSList *cur;
+
+ id = gtk_entry_get_text(GTK_ENTRY(search_window.folder_entry));
+ item_ = folder_find_item_from_identifier(id);
+ if (!item_)
+ return NULL;
+ if (item)
+ *item = item_;
+
+ bool_op = menu_get_option_menu_active_index
(GTK_OPTION_MENU(search_window.bool_optmenu));
+ recursive = gtk_toggle_button_get_active
+ (GTK_TOGGLE_BUTTON(search_window.subfolder_checkbtn));
case_sens = gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON(search_window.case_checkbtn));
- if (case_sens)
- str_find_func = str_find;
- else
- str_find_func = str_case_find;
-
- from_str = gtk_entry_get_text(GTK_ENTRY(search_window.from_entry));
- to_str = gtk_entry_get_text(GTK_ENTRY(search_window.to_entry));
- subject_str = gtk_entry_get_text(GTK_ENTRY(search_window.subject_entry));
- body_str = gtk_entry_get_text(GTK_ENTRY(search_window.body_entry));
-
- if (search_all) {
- summary_unselect_all(summaryview);
- valid = gtk_tree_model_get_iter_first(model, &iter);
- backward = FALSE;
- } else if (!summaryview->selected) {
- if (backward)
- valid = gtkut_tree_model_get_iter_last(model, &iter);
- else
- valid = gtk_tree_model_get_iter_first(model, &iter);
- if (!valid) {
- summary_unlock(summaryview);
- return;
- }
- } else {
- valid = gtkut_tree_row_reference_get_iter
- (model, summaryview->selected, &iter);
- if (!valid) {
- summary_unlock(summaryview);
- return;
+ for (cur = search_window.cond_edit->cond_hbox_list; cur != NULL;
+ cur = cur->next) {
+ CondHBox *hbox = (CondHBox *)cur->data;
+ gchar *error_msg;
+
+ cond = prefs_filter_edit_cond_hbox_to_cond(hbox, case_sens,
+ &error_msg);
+ if (cond) {
+ cond_list = g_slist_append(cond_list, cond);
+ } else {
+ if (!error_msg)
+ error_msg = _("Invalid condition exists.");
+ alertpanel_error("%s", error_msg);
+ filter_cond_list_free(cond_list);
+ return NULL;
}
+ }
- if (backward)
- valid = gtkut_tree_model_prev(model, &iter);
- else
- valid = gtkut_tree_model_next(model, &iter);
+ if (!cond_list)
+ return NULL;
+
+ rule = filter_rule_new(name, bool_op, cond_list, NULL);
+ rule->target_folder = g_strdup(id);
+ rule->recursive = recursive;
+
+ return rule;
+}
+
+static void summary_search_query(void)
+{
+ FolderItem *item;
+
+ if (search_window.on_search)
+ return;
+
+ search_window.on_search = TRUE;
+
+ search_window.rule = summary_search_dialog_to_rule("Query rule", &item);
+ if (!search_window.rule) {
+ search_window.on_search = FALSE;
+ return;
}
+ search_window.requires_full_headers =
+ filter_rule_requires_full_headers(search_window.rule);
- if (*body_str)
- main_window_cursor_wait(summaryview->mainwin);
+ search_window.cancelled = FALSE;
- for (;;) {
- if (!valid) {
- gchar *str;
- AlertValue val;
+ gtk_button_set_label(GTK_BUTTON(search_window.search_btn),
+ GTK_STOCK_STOP);
+ summary_search_clear_list();
- if (search_all) {
- break;
- }
+ if (search_window.rule->recursive)
+ g_node_traverse(item->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+ summary_search_recursive_func, NULL);
+ else
+ summary_search_folder(item);
- if (all_searched) {
- alertpanel_message
- (_("Search failed"),
- _("Search string not found."),
- ALERT_WARNING);
- break;
- }
+ filter_rule_free(search_window.rule);
+ search_window.rule = NULL;
+ search_window.requires_full_headers = FALSE;
- if (backward)
- str = _("Beginning of list reached; continue from end?");
- else
- str = _("End of list reached; continue from beginning?");
-
- val = alertpanel(_("Search finished"), str,
- GTK_STOCK_YES, GTK_STOCK_NO, NULL);
- if (G_ALERTDEFAULT == val) {
- if (backward)
- valid = gtkut_tree_model_get_iter_last
- (model, &iter);
- else
- valid = gtk_tree_model_get_iter_first
- (model, &iter);
- all_searched = TRUE;
- manage_window_focus_in(search_window.window,
- NULL, NULL);
- } else
- break;
- }
+ gtk_button_set_label(GTK_BUTTON(search_window.search_btn),
+ GTK_STOCK_FIND);
+ gtk_label_set_text(GTK_LABEL(search_window.status_label), _("Done."));
- gtk_tree_model_get(model, &iter, S_COL_MSG_INFO, &msginfo, -1);
- body_matched = FALSE;
+ if (search_window.cancelled)
+ debug_print("* query search cancelled.\n");
+ debug_print("query search finished.\n");
- if (bool_and) {
- matched = TRUE;
- if (*from_str) {
- if (!msginfo->from ||
- !str_find_func(msginfo->from, from_str))
- matched = FALSE;
- }
- if (matched && *to_str) {
- if (!msginfo->to ||
- !str_find_func(msginfo->to, to_str))
- matched = FALSE;
- }
- if (matched && *subject_str) {
- if (!msginfo->subject ||
- !str_find_func(msginfo->subject, subject_str))
- matched = FALSE;
- }
- if (matched && *body_str) {
- if (procmime_find_string(msginfo, body_str,
- str_find_func))
- body_matched = TRUE;
- else
- matched = FALSE;
- }
- if (matched && !*from_str && !*to_str &&
- !*subject_str && !*body_str)
- matched = FALSE;
- } else {
- matched = FALSE;
- if (*from_str && msginfo->from) {
- if (str_find_func(msginfo->from, from_str))
- matched = TRUE;
- }
- if (!matched && *to_str && msginfo->to) {
- if (str_find_func(msginfo->to, to_str))
- matched = TRUE;
- }
- if (!matched && *subject_str && msginfo->subject) {
- if (str_find_func(msginfo->subject, subject_str))
- matched = TRUE;
- }
- if (!matched && *body_str) {
- if (procmime_find_string(msginfo, body_str,
- str_find_func)) {
- matched = TRUE;
- body_matched = TRUE;
- }
- }
- }
+ search_window.on_search = FALSE;
+ search_window.cancelled = FALSE;
+}
- if (matched) {
- if (search_all) {
- gtk_tree_selection_select_iter
- (summaryview->selection, &iter);
- } else {
- if (messageview_is_visible
- (summaryview->messageview)) {
- summary_unlock(summaryview);
- summary_select_row
- (summaryview, &iter,
- TRUE, TRUE);
- summary_lock(summaryview);
- if (body_matched) {
- messageview_search_string
- (summaryview->messageview,
- body_str, case_sens);
- }
- } else {
- summary_select_row
- (summaryview, &iter,
- FALSE, TRUE);
- }
- break;
- }
+static void summary_search_folder(FolderItem *item)
+{
+ gchar *folder_name, *str;
+ GSList *mlist;
+ FilterInfo fltinfo;
+ GSList *cur;
+ gint count = 1, total;
+ GTimeVal tv_prev, tv_cur;
+
+ if (!item->path)
+ return;
+
+ folder_name = g_path_get_basename(item->path);
+ str = g_strdup_printf(_("Searching %s ..."), folder_name);
+ gtk_label_set_text(GTK_LABEL(search_window.status_label), str);
+ g_free(str);
+ g_get_current_time(&tv_prev);
+ ui_update();
+
+ if (search_window.cancelled) {
+ g_free(folder_name);
+ return;
+ }
+
+ mlist = folder_item_get_msg_list(item, TRUE);
+ total = g_slist_length(mlist);
+
+ memset(&fltinfo, 0, sizeof(FilterInfo));
+
+ debug_print("requires_full_headers: %d\n",
+ search_window.requires_full_headers);
+ debug_print("start query search: %s\n", item->path ? item->path : "");
+
+ for (cur = mlist; cur != NULL; cur = cur->next) {
+ MsgInfo *msginfo = (MsgInfo *)cur->data;
+ GSList *hlist;
+
+ g_get_current_time(&tv_cur);
+ if (tv_cur.tv_sec > tv_prev.tv_sec ||
+ tv_cur.tv_usec - tv_prev.tv_usec >
+ PROGRESS_UPDATE_INTERVAL * 1000) {
+ str = g_strdup_printf(_("Searching %s (%d / %d)..."),
+ folder_name, count, total);
+ gtk_label_set_text
+ (GTK_LABEL(search_window.status_label), str);
+ g_free(str);
+ ui_update();
+ tv_prev = tv_cur;
+ }
+ ++count;
+
+ if (search_window.cancelled)
+ break;
+
+ fltinfo.flags = msginfo->flags;
+ if (search_window.requires_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(search_window.rule, msginfo, hlist,
+ &fltinfo)) {
+ summary_search_append_msg(msginfo);
+ cur->data = NULL;
}
- if (backward)
- valid = gtkut_tree_model_prev(model, &iter);
- else
- valid = gtkut_tree_model_next(model, &iter);
+ procheader_header_list_destroy(hlist);
}
- if (*body_str)
- main_window_cursor_normal(summaryview->mainwin);
+ procmsg_msg_list_free(mlist);
+ g_free(folder_name);
+}
- summary_unlock(summaryview);
+static gboolean summary_search_recursive_func(GNode *node, gpointer data)
+{
+ FolderItem *item;
+
+ g_return_val_if_fail(node->data != NULL, FALSE);
+
+ item = FOLDER_ITEM(node->data);
+
+ if (!item->path)
+ return FALSE;
+
+ summary_search_folder(item);
+
+ if (search_window.cancelled)
+ return TRUE;
+
+ return FALSE;
+}
+
+static void summary_search_append_msg(MsgInfo *msginfo)
+{
+ GtkListStore *store = search_window.store;
+ GtkTreeIter iter;
+ gchar *folder;
+ gchar date_buf[80];
+ const gchar *subject, *from, *date;
+ gchar *id;
+
+ id = folder_item_get_identifier(msginfo->folder);
+ folder = g_path_get_basename(id);
+ g_free(id);
+ subject = msginfo->subject ? msginfo->subject : _("(No Subject)");
+ from = msginfo->from ? msginfo->from : _("(No From)");
+ if (msginfo->date_t) {
+ procheader_date_get_localtime(date_buf, sizeof(date_buf),
+ msginfo->date_t);
+ date = date_buf;
+ } else if (msginfo->date)
+ date = msginfo->date;
+ else
+ date = _("(No Date)");
+
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter,
+ COL_FOLDER, folder,
+ COL_SUBJECT, subject,
+ COL_FROM, from,
+ COL_DATE, date,
+ COL_MSGINFO, msginfo,
+ -1);
+
+ g_free(folder);
+}
+
+static void summary_search_clear_list(void)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model = GTK_TREE_MODEL(search_window.store);
+ MsgInfo *msginfo;
+
+ if (!gtk_tree_model_get_iter_first(model, &iter))
+ return;
+
+ do {
+ gtk_tree_model_get(model, &iter, COL_MSGINFO, &msginfo, -1);
+ procmsg_msginfo_free(msginfo);
+ } while (gtk_tree_model_iter_next(model, &iter));
+
+ gtk_list_store_clear(search_window.store);
+}
+
+static void summary_search_hbox_added(CondHBox *hbox)
+{
+ g_signal_connect(hbox->key_entry, "activate",
+ G_CALLBACK(summary_search_entry_activated), NULL);
+}
+
+static void row_activated(GtkTreeView *treeview, GtkTreePath *path,
+ GtkTreeViewColumn *column, gpointer data)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model = GTK_TREE_MODEL(search_window.store);
+ MsgInfo *msginfo;
+ MessageView *msgview;
+
+ if (!gtk_tree_model_get_iter(model, &iter, path))
+ return;
+
+ gtk_tree_model_get(model, &iter, COL_MSGINFO, &msginfo, -1);
+ msgview = messageview_create_with_new_window();
+ messageview_show(msgview, msginfo, FALSE);
+}
+
+static gboolean row_selected(GtkTreeSelection *selection,
+ GtkTreeModel *model, GtkTreePath *path,
+ gboolean cur_selected, gpointer data)
+{
+ return TRUE;
}
static void summary_search_clear(GtkButton *button, gpointer data)
{
- gtk_editable_delete_text(GTK_EDITABLE(search_window.from_entry),
- 0, -1);
- gtk_editable_delete_text(GTK_EDITABLE(search_window.to_entry),
- 0, -1);
- gtk_editable_delete_text(GTK_EDITABLE(search_window.subject_entry),
- 0, -1);
- gtk_editable_delete_text(GTK_EDITABLE(search_window.body_entry),
- 0, -1);
+ CondHBox *cond_hbox;
+
+ prefs_filter_edit_clear_cond_edit(search_window.cond_edit);
+ prefs_filter_set_header_list(NULL);
+ prefs_filter_edit_set_header_list(search_window.cond_edit, NULL);
+ cond_hbox = prefs_filter_edit_cond_hbox_create(search_window.cond_edit);
+ prefs_filter_edit_set_cond_hbox_widgets(cond_hbox, PF_COND_HEADER);
+ prefs_filter_edit_insert_cond_hbox
+ (search_window.cond_edit, cond_hbox, -1);
+ if (search_window.cond_edit->add_hbox)
+ search_window.cond_edit->add_hbox(cond_hbox);
+
+ gtk_label_set_text(GTK_LABEL(search_window.status_label), "");
+
+ summary_search_clear_list();
}
-static void summary_search_prev_clicked(GtkButton *button, gpointer data)
+static void summary_select_folder(GtkButton *button, gpointer data)
{
- summary_search_execute(TRUE, FALSE);
+ FolderItem *item;
+ gchar *id;
+
+ item = foldersel_folder_sel(NULL, FOLDER_SEL_ALL, NULL);
+ if (!item)
+ return;
+
+ id = folder_item_get_identifier(item);
+ if (id) {
+ gtk_entry_set_text(GTK_ENTRY(search_window.folder_entry), id);
+ g_free(id);
+ }
}
-static void summary_search_next_clicked(GtkButton *button, gpointer data)
+static void summary_search_clicked(GtkButton *button, gpointer data)
{
- summary_search_execute(FALSE, FALSE);
+ if (search_window.on_search)
+ search_window.cancelled = TRUE;
+ else
+ summary_search_query();
}
-static void summary_search_all_clicked(GtkButton *button, gpointer data)
+static gint summary_search_save_dialog_deleted(GtkWidget *widget,
+ GdkEventAny *event,
+ gpointer data)
{
- summary_search_execute(FALSE, TRUE);
+ SummarySearchSaveDialog *dialog = (SummarySearchSaveDialog *)data;
+
+ dialog->cancelled = TRUE;
+ dialog->finished = TRUE;
+ return TRUE;
}
-static void from_activated(void)
+static gint summary_search_save_dialog_key_pressed(GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer data)
{
- gtk_widget_grab_focus(search_window.to_entry);
+ SummarySearchSaveDialog *dialog = (SummarySearchSaveDialog *)data;
+
+ if (event && event->keyval == GDK_Escape) {
+ dialog->cancelled = TRUE;
+ dialog->finished = TRUE;
+ }
+ return FALSE;
}
-static void to_activated(void)
+static void summary_search_save_dialog_select_folder(GtkButton *button,
+ gpointer data)
{
- gtk_widget_grab_focus(search_window.subject_entry);
+ SummarySearchSaveDialog *dialog = (SummarySearchSaveDialog *)data;
+ FolderItem *item;
+ gchar *id;
+
+ item = foldersel_folder_sel(NULL, FOLDER_SEL_ALL, NULL);
+ if (!item)
+ return;
+
+ id = folder_item_get_identifier(item);
+ if (id) {
+ gtk_entry_set_text(GTK_ENTRY(dialog->folder_entry), id);
+ g_free(id);
+ }
}
-static void subject_activated(void)
+static void summary_search_save_ok(GtkButton *button, gpointer data)
{
- gtk_button_clicked(GTK_BUTTON(search_window.next_btn));
+ SummarySearchSaveDialog *dialog = (SummarySearchSaveDialog *)data;
+
+ dialog->finished = TRUE;
}
-static void body_activated(void)
+static void summary_search_save_cancel(GtkButton *button, gpointer data)
{
- gtk_button_clicked(GTK_BUTTON(search_window.next_btn));
+ SummarySearchSaveDialog *dialog = (SummarySearchSaveDialog *)data;
+
+ dialog->cancelled = TRUE;
+ dialog->finished = TRUE;
+}
+
+static SummarySearchSaveDialog *summary_search_save_dialog_create(void)
+{
+ SummarySearchSaveDialog *dialog;
+ GtkWidget *window;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *label;
+ GtkWidget *folder_entry;
+ GtkWidget *folder_btn;
+ GtkWidget *name_entry;
+
+ GtkWidget *confirm_area;
+ GtkWidget *hbbox;
+ GtkWidget *cancel_btn;
+ GtkWidget *ok_btn;
+
+ dialog = g_new0(SummarySearchSaveDialog, 1);
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(window), _("Save as search folder"));
+ gtk_widget_set_size_request(window, 400, -1);
+ gtk_container_set_border_width(GTK_CONTAINER(window), 8);
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+ gtk_window_set_modal(GTK_WINDOW(window), TRUE);
+ gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, FALSE);
+ g_signal_connect(G_OBJECT(window), "delete_event",
+ G_CALLBACK(summary_search_save_dialog_deleted),
+ dialog);
+ g_signal_connect(G_OBJECT(window), "key_press_event",
+ G_CALLBACK(summary_search_save_dialog_key_pressed),
+ dialog);
+ MANAGE_WINDOW_SIGNALS_CONNECT(window);
+ manage_window_set_transient(GTK_WINDOW(window));
+
+ vbox = gtk_vbox_new(FALSE, 8);
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+
+ hbox = gtk_hbox_new(FALSE, 8);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new(_("Location:"));
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+ folder_entry = gtk_entry_new();
+ gtk_box_pack_start(GTK_BOX(hbox), folder_entry, TRUE, TRUE, 0);
+
+ folder_btn = gtk_button_new_with_label("...");
+ gtk_box_pack_start(GTK_BOX(hbox), folder_btn, FALSE, FALSE, 0);
+ g_signal_connect(G_OBJECT(folder_btn), "clicked",
+ G_CALLBACK(summary_search_save_dialog_select_folder),
+ dialog);
+
+ hbox = gtk_hbox_new(FALSE, 8);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new(_("Folder name:"));
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+ name_entry = gtk_entry_new();
+ gtk_box_pack_start(GTK_BOX(hbox), name_entry, TRUE, TRUE, 0);
+
+ confirm_area = gtk_hbox_new(FALSE, 12);
+ gtk_box_pack_end(GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
+
+ gtkut_stock_button_set_create(&hbbox,
+ &ok_btn, GTK_STOCK_OK,
+ &cancel_btn, GTK_STOCK_CANCEL,
+ NULL, NULL);
+ gtk_box_pack_end(GTK_BOX(confirm_area), hbbox, FALSE, FALSE, 0);
+ g_signal_connect(G_OBJECT(ok_btn), "clicked",
+ G_CALLBACK(summary_search_save_ok), dialog);
+ g_signal_connect(G_OBJECT(cancel_btn), "clicked",
+ G_CALLBACK(summary_search_save_cancel), dialog);
+
+ gtk_widget_show_all(window);
+
+ dialog->window = window;
+ dialog->folder_entry = folder_entry;
+ dialog->name_entry = name_entry;
+ dialog->cancelled = FALSE;
+ dialog->finished = FALSE;
+
+ return dialog;
+}
+
+static void summary_search_save_dialog_destroy(SummarySearchSaveDialog *dialog)
+{
+ gtk_widget_destroy(dialog->window);
+ g_free(dialog);
+}
+
+static FolderItem *summary_search_create_vfolder(FolderItem *parent,
+ const gchar *name)
+{
+ gchar *path;
+ gchar *fs_name;
+ gchar *fullpath;
+ FolderItem *item;
+
+ g_return_val_if_fail(parent != NULL, NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+
+ path = folder_item_get_path(parent);
+ fs_name = g_filename_from_utf8(name, -1, NULL, NULL, NULL);
+ fullpath = g_strconcat(path, G_DIR_SEPARATOR_S,
+ fs_name ? fs_name : name, NULL);
+ g_free(fs_name);
+ g_free(path);
+
+ if (make_dir_hier(fullpath) < 0) {
+ g_free(fullpath);
+ return NULL;
+ }
+
+ if (parent->path)
+ path = g_strconcat(parent->path, G_DIR_SEPARATOR_S, name, NULL);
+ else
+ path = g_strdup(name);
+
+ item = folder_item_new(name, path);
+ item->stype = F_VIRTUAL;
+ folder_item_append(parent, item);
+
+ g_free(path);
+
+ return item;
+}
+
+static void summary_search_vfolder_update_rule(FolderItem *item)
+{
+ GSList list;
+ FilterRule *rule;
+ gchar *file;
+ gchar *path;
+
+ rule = summary_search_dialog_to_rule(item->name, NULL);
+ list.data = rule;
+ list.next = NULL;
+
+ path = folder_item_get_path(item);
+ file = g_strconcat(path, G_DIR_SEPARATOR_S, FILTER_LIST, NULL);
+ filter_write_file(&list, file);
+ g_free(file);
+ g_free(path);
+
+ filter_rule_free(rule);
+}
+
+static void summary_search_save(GtkButton *button, gpointer data)
+{
+ SummarySearchSaveDialog *dialog;
+
+ dialog = summary_search_save_dialog_create();
+
+ while (!dialog->finished)
+ gtk_main_iteration();
+
+ if (!dialog->cancelled) {
+ const gchar *id, *name;
+ FolderItem *parent, *item;
+
+ id = gtk_entry_get_text(GTK_ENTRY(dialog->folder_entry));
+ parent = folder_find_item_from_identifier(id);
+ name = gtk_entry_get_text(GTK_ENTRY(dialog->name_entry));
+ if (parent && name && *name) {
+ if (folder_find_child_item_by_name(parent, name)) {
+ alertpanel_error
+ (_("The folder `%s' already exists."),
+ name);
+ } else {
+ item = summary_search_create_vfolder
+ (parent, name);
+ if (item) {
+ summary_search_vfolder_update_rule
+ (item);
+ folderview_append_item(folderview_get(),
+ NULL, item,
+ TRUE);
+ folder_write_list();
+ }
+ }
+ }
+ }
+
+ summary_search_save_dialog_destroy(dialog);
+}
+
+static void summary_search_close(GtkButton *button, gpointer data)
+{
+ if (search_window.on_search)
+ search_window.cancelled = TRUE;
+ gtk_widget_hide(search_window.window);
+}
+
+static void summary_search_entry_activated(GtkWidget *widget, gpointer data)
+{
+ gtk_button_clicked(GTK_BUTTON(search_window.search_btn));
+}
+
+static gint summary_search_deleted(GtkWidget *widget, GdkEventAny *event,
+ gpointer data)
+{
+ gtk_button_clicked(GTK_BUTTON(search_window.close_btn));
+ return TRUE;
}
static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
gpointer data)
{
- if (event && event->keyval == GDK_Escape)
- gtk_widget_hide(search_window.window);
+ if (event && event->keyval == GDK_Escape) {
+ if (search_window.on_search)
+ gtk_button_clicked
+ (GTK_BUTTON(search_window.search_btn));
+ else
+ gtk_button_clicked(GTK_BUTTON(search_window.close_btn));
+ return TRUE;
+ }
return FALSE;
}
diff --git a/src/summary_search.h b/src/summary_search.h
index 8e3fcc0c..2b0d3cc6 100644
--- a/src/summary_search.h
+++ b/src/summary_search.h
@@ -23,7 +23,9 @@
#include <glib.h>
#include "summaryview.h"
+#include "folder.h"
-void summary_search (SummaryView *summaryview);
+void summary_search (SummaryView *summaryview,
+ FolderItem *item);
#endif /* __SUMMARY_SEARCH_H__ */
diff --git a/src/summaryview.c b/src/summaryview.c
index 498d965e..214c735d 100644
--- a/src/summaryview.c
+++ b/src/summaryview.c
@@ -649,7 +649,7 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item,
buf = NULL;
if (!item || !item->path || !item->parent || item->no_select ||
- (FOLDER_TYPE(item->folder) == F_MH &&
+ (FOLDER_TYPE(item->folder) == F_MH && item->stype != F_VIRTUAL &&
((buf = folder_item_get_path(item)) == NULL ||
change_dir(buf) < 0))) {
g_free(buf);