diff options
author | hiro <hiro@ee746299-78ed-0310-b773-934348b2243d> | 2010-02-10 09:31:53 +0000 |
---|---|---|
committer | hiro <hiro@ee746299-78ed-0310-b773-934348b2243d> | 2010-02-10 09:31:53 +0000 |
commit | 3f9703a3fd35f7d8b835c62869c0db74bd213e2f (patch) | |
tree | acbaf735dc3a1d98d0322f6a5634ea51c7c1b707 | |
parent | 6ab1d3cf538aa7f6c5385f7010e9a2d7e71b8dc0 (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-- | ChangeLog | 9 | ||||
-rw-r--r-- | libsylph/filter.c | 77 | ||||
-rw-r--r-- | libsylph/filter.h | 11 | ||||
-rw-r--r-- | src/addressbook.c | 87 | ||||
-rw-r--r-- | src/addressbook.h | 2 | ||||
-rw-r--r-- | src/main.c | 1 | ||||
-rw-r--r-- | src/prefs_filter_edit.c | 91 | ||||
-rw-r--r-- | src/prefs_filter_edit.h | 5 |
8 files changed, 263 insertions, 20 deletions
@@ -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__ */ @@ -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; |