aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2010-02-10 09:31:53 +0000
committerhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2010-02-10 09:31:53 +0000
commit3f9703a3fd35f7d8b835c62869c0db74bd213e2f (patch)
treeacbaf735dc3a1d98d0322f6a5634ea51c7c1b707
parent6ab1d3cf538aa7f6c5385f7010e9a2d7e71b8dc0 (diff)
added a new filter match type: is (not) in addressbook.
git-svn-id: svn://sylpheed.sraoss.jp/sylpheed/trunk@2461 ee746299-78ed-0310-b773-934348b2243d
-rw-r--r--ChangeLog9
-rw-r--r--libsylph/filter.c77
-rw-r--r--libsylph/filter.h11
-rw-r--r--src/addressbook.c87
-rw-r--r--src/addressbook.h2
-rw-r--r--src/main.c1
-rw-r--r--src/prefs_filter_edit.c91
-rw-r--r--src/prefs_filter_edit.h5
8 files changed, 263 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index c5ae06cd..2f045866 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2010-02-10
+
+ * libsylph/filter.[ch]
+ src/prefs_filter_edit.[ch]
+ src/addressbook.[ch]
+ src/main.c: added a new filter match type: is (not) in addressbook.
+ addressbook_has_address(): new function for fast search of address
+ book by addresses.
+
2010-02-05
* src/setup.c: confirm on cancel. Modified messages.
diff --git a/libsylph/filter.c b/libsylph/filter.c
index 182fbb27..35bb9369 100644
--- a/libsylph/filter.c
+++ b/libsylph/filter.c
@@ -54,12 +54,18 @@ typedef enum
FLT_O_REGEX = 1 << 2
} FilterOldFlag;
+FilterInAddressBookFunc default_addrbook_func = NULL;
+
static gboolean filter_match_cond (FilterCond *cond,
MsgInfo *msginfo,
GSList *hlist,
FilterInfo *fltinfo);
static gboolean filter_match_header_cond(FilterCond *cond,
GSList *hlist);
+static gboolean filter_match_in_addressbook
+ (FilterCond *cond,
+ GSList *hlist,
+ FilterInfo *fltinfo);
static void filter_cond_free (FilterCond *cond);
static void filter_action_free (FilterAction *action);
@@ -388,9 +394,17 @@ static gboolean filter_match_cond(FilterCond *cond, MsgInfo *msginfo,
switch (cond->type) {
case FLT_COND_HEADER:
+ if (cond->match_type == FLT_IN_ADDRESSBOOK)
+ return filter_match_in_addressbook(cond, hlist, fltinfo);
+ else
+ return filter_match_header_cond(cond, hlist);
case FLT_COND_ANY_HEADER:
- case FLT_COND_TO_OR_CC:
return filter_match_header_cond(cond, hlist);
+ case FLT_COND_TO_OR_CC:
+ if (cond->match_type == FLT_IN_ADDRESSBOOK)
+ return filter_match_in_addressbook(cond, hlist, fltinfo);
+ else
+ return filter_match_header_cond(cond, hlist);
case FLT_COND_BODY:
matched = procmime_find_string(msginfo, cond->str_value,
cond->match_func);
@@ -490,6 +504,45 @@ static gboolean filter_match_header_cond(FilterCond *cond, GSList *hlist)
return matched;
}
+static gboolean filter_match_in_addressbook(FilterCond *cond, GSList *hlist,
+ FilterInfo *fltinfo)
+{
+ gboolean matched = FALSE;
+ GSList *cur;
+ Header *header;
+
+ if (!default_addrbook_func)
+ return FALSE;
+ if (cond->type != FLT_COND_HEADER && cond->type != FLT_COND_TO_OR_CC)
+ return FALSE;
+
+ for (cur = hlist; cur != NULL; cur = cur->next) {
+ header = (Header *)cur->data;
+
+ if (cond->type == FLT_COND_HEADER) {
+ if (!g_ascii_strcasecmp
+ (header->name, cond->header_name)) {
+ if (default_addrbook_func(header->body))
+ matched = TRUE;
+ }
+ } else if (cond->type == FLT_COND_TO_OR_CC) {
+ if (!g_ascii_strcasecmp(header->name, "To") ||
+ !g_ascii_strcasecmp(header->name, "Cc")) {
+ if (default_addrbook_func(header->body))
+ matched = TRUE;
+ }
+ }
+
+ if (matched == TRUE)
+ break;
+ }
+
+ if (FLT_IS_NOT_MATCH(cond->match_flag))
+ matched = !matched;
+
+ return matched;
+}
+
gboolean filter_rule_requires_full_headers(FilterRule *rule)
{
GSList *cur;
@@ -856,6 +909,11 @@ void filter_write_file(GSList *list, const gchar *file)
FLT_IS_NOT_MATCH(cond->match_flag)
? "not-regex" : "regex");
break;
+ case FLT_IN_ADDRESSBOOK:
+ strcpy(match_type,
+ FLT_IS_NOT_MATCH(cond->match_flag)
+ ? "not-in-addressbook" : "in-addressbook");
+ break;
default:
match_type[0] = '\0';
break;
@@ -1206,6 +1264,16 @@ FilterRule *filter_read_str(const gchar *str)
return rule;
}
+void filter_set_addressbook_func(FilterInAddressBookFunc func)
+{
+ default_addrbook_func = func;
+}
+
+FilterInAddressBookFunc filter_get_addressbook_func(void)
+{
+ return default_addrbook_func;
+}
+
FilterRule *filter_rule_new(const gchar *name, FilterBoolOp bool_op,
GSList *cond_list, GSList *action_list)
{
@@ -1253,6 +1321,8 @@ FilterCond *filter_cond_new(FilterCondType type,
cond->match_func = str_find_equal;
else
cond->match_func = str_case_find_equal;
+ } else if (match_type == FLT_IN_ADDRESSBOOK) {
+ cond->match_func = str_case_find_equal;
} else {
if (FLT_IS_CASE_SENS(match_flag))
cond->match_func = str_find;
@@ -1421,6 +1491,11 @@ void filter_rule_match_type_str_to_enum(const gchar *match_type,
} else if (!strcmp(match_type, "not-regex")) {
*type = FLT_REGEX;
*flag = FLT_NOT_MATCH;
+ } else if (!strcmp(match_type, "in-addressbook")) {
+ *type = FLT_IN_ADDRESSBOOK;
+ } else if (!strcmp(match_type, "not-in-addressbook")) {
+ *type = FLT_IN_ADDRESSBOOK;
+ *flag = FLT_NOT_MATCH;
} else if (!strcmp(match_type, "gt")) {
} else if (!strcmp(match_type, "lt")) {
*flag = FLT_NOT_MATCH;
diff --git a/libsylph/filter.h b/libsylph/filter.h
index 132810f5..35c43c70 100644
--- a/libsylph/filter.h
+++ b/libsylph/filter.h
@@ -1,6 +1,6 @@
/*
* LibSylph -- E-Mail client library
- * Copyright (C) 1999-2007 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2010 Hiroyuki Yamamoto
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -58,7 +58,8 @@ typedef enum
{
FLT_CONTAIN,
FLT_EQUAL,
- FLT_REGEX
+ FLT_REGEX,
+ FLT_IN_ADDRESSBOOK
} FilterMatchType;
typedef enum
@@ -110,6 +111,8 @@ typedef enum
#define FLT_IS_NOT_MATCH(flag) ((flag & FLT_NOT_MATCH) != 0)
#define FLT_IS_CASE_SENS(flag) ((flag & FLT_CASE_SENS) != 0)
+typedef gboolean (*FilterInAddressBookFunc) (const gchar *address);
+
struct _FilterCond
{
FilterCondType type;
@@ -193,6 +196,10 @@ void filter_write_config (void);
gchar *filter_get_str (FilterRule *rule);
FilterRule *filter_read_str (const gchar *str);
+void filter_set_addressbook_func (FilterInAddressBookFunc func);
+FilterInAddressBookFunc filter_get_addressbook_func
+ (void);
+
FilterRule *filter_rule_new (const gchar *name,
FilterBoolOp bool_op,
GSList *cond_list,
diff --git a/src/addressbook.c b/src/addressbook.c
index f7d9e9b5..2c95c580 100644
--- a/src/addressbook.c
+++ b/src/addressbook.c
@@ -333,6 +333,9 @@ static void addressbook_list_select_set (GList *row_list);
static void addressbook_import_ldif_cb (void);
static void addressbook_import_csv_cb (void);
+static void addressbook_modified (void);
+
+
static GtkItemFactoryEntry addressbook_entries[] =
{
{N_("/_File"), NULL, NULL, 0, "<Branch>"},
@@ -408,6 +411,7 @@ static GtkItemFactoryEntry addressbook_list_popup_entries[] =
{N_("/_Paste"), NULL, addressbook_paste_address_cb, 0, NULL}
};
+
void addressbook_open(Compose *target)
{
if (!addrbook.window) {
@@ -2181,7 +2185,7 @@ static void addressbook_edit_address_cb(gpointer data, guint action, GtkWidget *
if (addressbook_edit_person(abf, NULL, person, TRUE) == NULL)
return;
addressbook_reopen();
- invalidate_address_completion();
+ addressbook_modified();
return;
}
} else if (obj->type == ADDR_ITEM_PERSON) {
@@ -2191,7 +2195,7 @@ static void addressbook_edit_address_cb(gpointer data, guint action, GtkWidget *
if (addressbook_edit_person(abf, NULL, person, FALSE) == NULL)
return;
addressbook_reopen();
- invalidate_address_completion();
+ addressbook_modified();
return;
} else if (obj->type == ADDR_ITEM_GROUP) {
ItemGroup *itemGrp = (ItemGroup *)obj;
@@ -3237,7 +3241,7 @@ void addressbook_export_to_file( void ) {
}
/* Notify address completion of new data */
- invalidate_address_completion();
+ addressbook_modified();
}
}
@@ -4151,7 +4155,7 @@ static void addressbook_import_ldif_cb(void)
}
/* Notify address completion */
- invalidate_address_completion();
+ addressbook_modified();
}
/*
@@ -4191,9 +4195,84 @@ static void addressbook_import_csv_cb(void)
}
/* Notify address completion */
+ addressbook_modified();
+}
+
+/* **********************************************************************
+* Address Book Fast Search.
+* ***********************************************************************
+*/
+
+static GHashTable *addr_table;
+
+static gint load_address(const gchar *name, const gchar *address,
+ const gchar *nickname)
+{
+ gchar *addr;
+
+ if (!address)
+ return -1;
+
+ addr = g_ascii_strdown(address, -1);
+
+ if (g_hash_table_lookup(addr_table, addr) == NULL)
+ g_hash_table_insert(addr_table, addr, addr);
+ else
+ g_free(addr);
+
+ return 0;
+}
+
+static void addressbook_modified(void)
+{
+ if (addr_table) {
+ hash_free_strings(addr_table);
+ g_hash_table_destroy(addr_table);
+ addr_table = NULL;
+ }
+
invalidate_address_completion();
}
+gboolean addressbook_has_address(const gchar *address)
+{
+ GSList *list, *cur;
+ gchar *addr;
+ gboolean found = FALSE;
+
+ if (!address)
+ return FALSE;
+
+ debug_print("addressbook_has_address: check if addressbook has address: %s\n", address);
+
+ list = address_list_append(NULL, address);
+ if (!list)
+ return FALSE;
+
+ if (!addr_table) {
+ addr_table = g_hash_table_new(g_str_hash, g_str_equal);
+ addressbook_load_completion(load_address);
+ }
+
+ for (cur = list; cur != NULL; cur = cur->next) {
+ addr = g_ascii_strdown((gchar *)cur->data, -1);
+
+ if (g_hash_table_lookup(addr_table, addr)) {
+ found = TRUE;
+ debug_print("'%s' is in addressbook\n", addr);
+ } else {
+ found = FALSE;
+ g_free(addr);
+ break;
+ }
+ g_free(addr);
+ }
+
+ slist_free_strings(list);
+
+ return found;
+}
+
/*
* End of Source.
*/
diff --git a/src/addressbook.h b/src/addressbook.h
index 70a51da4..41d0cb37 100644
--- a/src/addressbook.h
+++ b/src/addressbook.h
@@ -49,4 +49,6 @@ gboolean addressbook_add_contact_autoreg(const gchar *name,
gboolean addressbook_load_completion ( gint (*callBackFunc) ( const gchar *, const gchar *, const gchar * ) );
+gboolean addressbook_has_address (const gchar *address);
+
#endif /* __ADDRESSBOOK_H__ */
diff --git a/src/main.c b/src/main.c
index f2ed5eac..1f11b213 100644
--- a/src/main.c
+++ b/src/main.c
@@ -257,6 +257,7 @@ int main(int argc, char *argv[])
CHDIR_EXIT_IF_FAIL(get_home_dir(), 1);
prefs_common_read_config();
+ filter_set_addressbook_func(addressbook_has_address);
filter_read_config();
prefs_actions_read_config();
prefs_display_header_read_config();
diff --git a/src/prefs_filter_edit.c b/src/prefs_filter_edit.c
index 9250cfb7..ac39deae 100644
--- a/src/prefs_filter_edit.c
+++ b/src/prefs_filter_edit.c
@@ -129,6 +129,8 @@ static void prefs_filter_edit_cancel (void);
static void prefs_filter_cond_activated_cb (GtkWidget *widget,
gpointer data);
+static void prefs_filter_match_activated_cb (GtkWidget *widget,
+ gpointer data);
static void prefs_filter_action_activated_cb (GtkWidget *widget,
gpointer data);
@@ -472,6 +474,8 @@ CondHBox *prefs_filter_edit_cond_hbox_create(FilterCondEdit *cond_edit)
GtkWidget *add_btn;
GtkWidget *del_img;
GtkWidget *add_img;
+ GtkWidget *match_menu_in_addr;
+ GtkWidget *match_menu_not_in_addr;
cond_hbox = g_new0(CondHBox, 1);
@@ -518,24 +522,31 @@ CondHBox *prefs_filter_edit_cond_hbox_create(FilterCondEdit *cond_edit)
gtk_widget_show(match_type_optmenu);
gtk_box_pack_start(GTK_BOX(hbox), match_type_optmenu, FALSE, FALSE, 0);
+#define MATCH_MENUITEM_ADD(str, action) \
+{ \
+ MENUITEM_ADD(menu, menuitem, str, action); \
+ g_signal_connect(G_OBJECT(menuitem), "activate", \
+ G_CALLBACK(prefs_filter_match_activated_cb), \
+ cond_hbox); \
+}
menu = gtk_menu_new();
gtk_widget_show(menu);
- MENUITEM_ADD(menu, menuitem, _("contains"),
- PF_MATCH_CONTAIN);
- MENUITEM_ADD(menu, menuitem, _("doesn't contain"),
- PF_MATCH_NOT_CONTAIN);
- MENUITEM_ADD(menu, menuitem, _("is"),
- PF_MATCH_EQUAL);
- MENUITEM_ADD(menu, menuitem, _("is not"),
- PF_MATCH_NOT_EQUAL);
+ MATCH_MENUITEM_ADD(_("contains"), PF_MATCH_CONTAIN);
+ MATCH_MENUITEM_ADD(_("doesn't contain"), PF_MATCH_NOT_CONTAIN);
+ MATCH_MENUITEM_ADD(_("is"), PF_MATCH_EQUAL);
+ MATCH_MENUITEM_ADD(_("is not"), PF_MATCH_NOT_EQUAL);
#if defined(USE_ONIGURUMA) || defined(HAVE_REGCOMP)
- MENUITEM_ADD(menu, menuitem, _("match to regex"),
- PF_MATCH_REGEX);
- MENUITEM_ADD(menu, menuitem, _("doesn't match to regex"),
- PF_MATCH_NOT_REGEX);
+ MATCH_MENUITEM_ADD(_("match to regex"), PF_MATCH_REGEX);
+ MATCH_MENUITEM_ADD(_("doesn't match to regex"), PF_MATCH_NOT_REGEX);
#endif
+ MATCH_MENUITEM_ADD(_("is in addressbook"), PF_MATCH_IN_ADDRESSBOOK);
+ match_menu_in_addr = menuitem;
+ MATCH_MENUITEM_ADD(_("isn't in addressbook"), PF_MATCH_NOT_IN_ADDRESSBOOK);
+ match_menu_not_in_addr = menuitem;
gtk_option_menu_set_menu(GTK_OPTION_MENU(match_type_optmenu), menu);
+#undef MATCH_MENUITEM_ADD
+
size_match_optmenu = gtk_option_menu_new();
gtk_widget_show(size_match_optmenu);
gtk_box_pack_start(GTK_BOX(hbox), size_match_optmenu, FALSE, FALSE, 0);
@@ -612,6 +623,8 @@ CondHBox *prefs_filter_edit_cond_hbox_create(FilterCondEdit *cond_edit)
cond_hbox->key_entry = key_entry;
cond_hbox->spin_btn = spin_btn;
cond_hbox->label = label;
+ cond_hbox->match_menu_in_addr = match_menu_in_addr;
+ cond_hbox->match_menu_not_in_addr = match_menu_not_in_addr;
cond_hbox->del_btn = del_btn;
cond_hbox->add_btn = add_btn;
cond_hbox->cur_type = PF_COND_HEADER;
@@ -841,6 +854,12 @@ void prefs_filter_edit_cond_hbox_set(CondHBox *hbox, FilterCond *cond)
else
match_type = PF_MATCH_REGEX;
break;
+ case FLT_IN_ADDRESSBOOK:
+ if (FLT_IS_NOT_MATCH(cond->match_flag))
+ match_type = PF_MATCH_NOT_IN_ADDRESSBOOK;
+ else
+ match_type = PF_MATCH_IN_ADDRESSBOOK;
+ break;
}
break;
case FLT_COND_UNREAD:
@@ -895,6 +914,10 @@ void prefs_filter_edit_cond_hbox_set(CondHBox *hbox, FilterCond *cond)
gtk_option_menu_set_history
(GTK_OPTION_MENU(hbox->status_match_optmenu),
status_type);
+
+ if (match_type == PF_MATCH_IN_ADDRESSBOOK ||
+ match_type == PF_MATCH_NOT_IN_ADDRESSBOOK)
+ gtk_widget_hide(hbox->key_entry);
}
void prefs_filter_edit_action_hbox_set(ActionHBox *hbox, FilterAction *action)
@@ -977,6 +1000,8 @@ void prefs_filter_edit_cond_hbox_select(CondHBox *hbox, CondMenuType type,
void prefs_filter_edit_set_cond_hbox_widgets(CondHBox *hbox, CondMenuType type)
{
+ MatchMenuType match_type;
+
switch (type) {
case PF_COND_HEADER:
case PF_COND_TO_OR_CC:
@@ -986,9 +1011,27 @@ void prefs_filter_edit_set_cond_hbox_widgets(CondHBox *hbox, CondMenuType type)
gtk_widget_hide(hbox->size_match_optmenu);
gtk_widget_hide(hbox->age_match_optmenu);
gtk_widget_hide(hbox->status_match_optmenu);
- gtk_widget_show(hbox->key_entry);
+ match_type = menu_get_option_menu_active_index
+ (GTK_OPTION_MENU(hbox->match_type_optmenu));
+ if (match_type == PF_MATCH_IN_ADDRESSBOOK ||
+ match_type == PF_MATCH_NOT_IN_ADDRESSBOOK)
+ gtk_widget_hide(hbox->key_entry);
+ else
+ gtk_widget_show(hbox->key_entry);
gtk_widget_hide(hbox->spin_btn);
gtk_widget_hide(hbox->label);
+ if (type == PF_COND_HEADER || type == PF_COND_TO_OR_CC) {
+ gtk_widget_show(hbox->match_menu_in_addr);
+ gtk_widget_show(hbox->match_menu_not_in_addr);
+ } else {
+ gtk_widget_hide(hbox->match_menu_in_addr);
+ gtk_widget_hide(hbox->match_menu_not_in_addr);
+ if (match_type == PF_MATCH_IN_ADDRESSBOOK ||
+ match_type == PF_MATCH_NOT_IN_ADDRESSBOOK) {
+ gtk_option_menu_set_history(GTK_OPTION_MENU(hbox->match_type_optmenu), 0);
+ gtk_widget_show(hbox->key_entry);
+ }
+ }
break;
case PF_COND_CMD_TEST:
gtk_widget_hide(hbox->match_type_optmenu);
@@ -1703,6 +1746,13 @@ FilterCond *prefs_filter_edit_cond_hbox_to_cond(CondHBox *hbox,
match_type = FLT_REGEX;
match_flag |= FLT_NOT_MATCH;
break;
+ case PF_MATCH_IN_ADDRESSBOOK:
+ match_type = FLT_IN_ADDRESSBOOK;
+ break;
+ case PF_MATCH_NOT_IN_ADDRESSBOOK:
+ match_type = FLT_IN_ADDRESSBOOK;
+ match_flag |= FLT_NOT_MATCH;
+ break;
default:
break;
}
@@ -2035,6 +2085,21 @@ static void prefs_filter_cond_activated_cb(GtkWidget *widget, gpointer data)
}
}
+static void prefs_filter_match_activated_cb(GtkWidget *widget, gpointer data)
+{
+ CondHBox *hbox = (CondHBox *)data;
+ GtkWidget *cond_type_menuitem;
+ CondMenuType cond_menu_type;
+
+ cond_type_menuitem = gtk_menu_get_active
+ (GTK_MENU(gtk_option_menu_get_menu
+ (GTK_OPTION_MENU(hbox->cond_type_optmenu))));
+ cond_menu_type = GPOINTER_TO_INT
+ (g_object_get_data(G_OBJECT(cond_type_menuitem), MENU_VAL_ID));
+
+ prefs_filter_edit_set_cond_hbox_widgets(hbox, cond_menu_type);
+}
+
static void prefs_filter_action_activated_cb(GtkWidget *widget, gpointer data)
{
ActionHBox *hbox = (ActionHBox *)data;
diff --git a/src/prefs_filter_edit.h b/src/prefs_filter_edit.h
index 7fdf2037..c6f056fa 100644
--- a/src/prefs_filter_edit.h
+++ b/src/prefs_filter_edit.h
@@ -55,6 +55,8 @@ typedef enum
PF_MATCH_NOT_EQUAL,
PF_MATCH_REGEX,
PF_MATCH_NOT_REGEX,
+ PF_MATCH_IN_ADDRESSBOOK,
+ PF_MATCH_NOT_IN_ADDRESSBOOK,
PF_MATCH_NONE
} MatchMenuType;
@@ -118,6 +120,9 @@ struct _CondHBox {
GtkWidget *spin_btn;
GtkWidget *label;
+ GtkWidget *match_menu_in_addr;
+ GtkWidget *match_menu_not_in_addr;
+
GtkWidget *del_btn;
GtkWidget *add_btn;