Revision 2461

libsylph/filter.c (revision 2461)
54 54
	FLT_O_REGEX	= 1 << 2
55 55
} FilterOldFlag;
56 56

  
57
FilterInAddressBookFunc default_addrbook_func = NULL;
58

  
57 59
static gboolean filter_match_cond	(FilterCond	*cond,
58 60
					 MsgInfo	*msginfo,
59 61
					 GSList		*hlist,
60 62
					 FilterInfo	*fltinfo);
61 63
static gboolean filter_match_header_cond(FilterCond	*cond,
62 64
					 GSList		*hlist);
65
static gboolean filter_match_in_addressbook
66
					(FilterCond	*cond,
67
					 GSList		*hlist,
68
					 FilterInfo	*fltinfo);
63 69

  
64 70
static void filter_cond_free		(FilterCond	*cond);
65 71
static void filter_action_free		(FilterAction	*action);
......
388 394

  
389 395
	switch (cond->type) {
390 396
	case FLT_COND_HEADER:
397
		if (cond->match_type == FLT_IN_ADDRESSBOOK)
398
			return filter_match_in_addressbook(cond, hlist, fltinfo);
399
		else
400
			return filter_match_header_cond(cond, hlist);
391 401
	case FLT_COND_ANY_HEADER:
402
		return filter_match_header_cond(cond, hlist);
392 403
	case FLT_COND_TO_OR_CC:
393
		return filter_match_header_cond(cond, hlist);
404
		if (cond->match_type == FLT_IN_ADDRESSBOOK)
405
			return filter_match_in_addressbook(cond, hlist, fltinfo);
406
		else
407
			return filter_match_header_cond(cond, hlist);
394 408
	case FLT_COND_BODY:
395 409
		matched = procmime_find_string(msginfo, cond->str_value,
396 410
					       cond->match_func);
......
490 504
	return matched;
491 505
}
492 506

  
507
static gboolean filter_match_in_addressbook(FilterCond *cond, GSList *hlist,
508
					    FilterInfo *fltinfo)
509
{
510
	gboolean matched = FALSE;
511
	GSList *cur;
512
	Header *header;
513

  
514
	if (!default_addrbook_func)
515
		return FALSE;
516
	if (cond->type != FLT_COND_HEADER && cond->type != FLT_COND_TO_OR_CC)
517
		return FALSE;
518

  
519
	for (cur = hlist; cur != NULL; cur = cur->next) {
520
		header = (Header *)cur->data;
521

  
522
		if (cond->type == FLT_COND_HEADER) {
523
			if (!g_ascii_strcasecmp
524
				(header->name, cond->header_name)) {
525
				if (default_addrbook_func(header->body))
526
					matched = TRUE;
527
			}
528
		} else if (cond->type == FLT_COND_TO_OR_CC) {
529
			if (!g_ascii_strcasecmp(header->name, "To") ||
530
			    !g_ascii_strcasecmp(header->name, "Cc")) {
531
				if (default_addrbook_func(header->body))
532
					matched = TRUE;
533
			}
534
		}
535

  
536
		if (matched == TRUE)
537
			break;
538
	}
539

  
540
	if (FLT_IS_NOT_MATCH(cond->match_flag))
541
		matched = !matched;
542

  
543
	return matched;
544
}
545

  
493 546
gboolean filter_rule_requires_full_headers(FilterRule *rule)
494 547
{
495 548
	GSList *cur;
......
856 909
				       FLT_IS_NOT_MATCH(cond->match_flag)
857 910
				       ? "not-regex" : "regex");
858 911
				break;
912
			case FLT_IN_ADDRESSBOOK:
913
				strcpy(match_type,
914
				       FLT_IS_NOT_MATCH(cond->match_flag)
915
				       ? "not-in-addressbook" : "in-addressbook");
916
				break;
859 917
			default:
860 918
				match_type[0] = '\0';
861 919
				break;
......
1206 1264
	return rule;
1207 1265
}
1208 1266

  
1267
void filter_set_addressbook_func(FilterInAddressBookFunc func)
1268
{
1269
	default_addrbook_func = func;
1270
}
1271

  
1272
FilterInAddressBookFunc filter_get_addressbook_func(void)
1273
{
1274
	return default_addrbook_func;
1275
}
1276

  
1209 1277
FilterRule *filter_rule_new(const gchar *name, FilterBoolOp bool_op,
1210 1278
			    GSList *cond_list, GSList *action_list)
1211 1279
{
......
1253 1321
			cond->match_func = str_find_equal;
1254 1322
		else
1255 1323
			cond->match_func = str_case_find_equal;
1324
	} else if (match_type == FLT_IN_ADDRESSBOOK) {
1325
		cond->match_func = str_case_find_equal;
1256 1326
	} else {
1257 1327
		if (FLT_IS_CASE_SENS(match_flag))
1258 1328
			cond->match_func = str_find;
......
1421 1491
	} else if (!strcmp(match_type, "not-regex")) {
1422 1492
		*type = FLT_REGEX;
1423 1493
		*flag = FLT_NOT_MATCH;
1494
	} else if (!strcmp(match_type, "in-addressbook")) {
1495
		*type = FLT_IN_ADDRESSBOOK;
1496
	} else if (!strcmp(match_type, "not-in-addressbook")) {
1497
		*type = FLT_IN_ADDRESSBOOK;
1498
		*flag = FLT_NOT_MATCH;
1424 1499
	} else if (!strcmp(match_type, "gt")) {
1425 1500
	} else if (!strcmp(match_type, "lt")) {
1426 1501
		*flag = FLT_NOT_MATCH;
libsylph/filter.h (revision 2461)
1 1
/*
2 2
 * LibSylph -- E-Mail client library
3
 * Copyright (C) 1999-2007 Hiroyuki Yamamoto
3
 * Copyright (C) 1999-2010 Hiroyuki Yamamoto
4 4
 *
5 5
 * This library is free software; you can redistribute it and/or
6 6
 * modify it under the terms of the GNU Lesser General Public
......
58 58
{
59 59
	FLT_CONTAIN,
60 60
	FLT_EQUAL,
61
	FLT_REGEX
61
	FLT_REGEX,
62
	FLT_IN_ADDRESSBOOK
62 63
} FilterMatchType;
63 64

  
64 65
typedef enum
......
110 111
#define FLT_IS_NOT_MATCH(flag)	((flag & FLT_NOT_MATCH) != 0)
111 112
#define FLT_IS_CASE_SENS(flag)	((flag & FLT_CASE_SENS) != 0)
112 113

  
114
typedef gboolean (*FilterInAddressBookFunc)	(const gchar	*address);
115

  
113 116
struct _FilterCond
114 117
{
115 118
	FilterCondType type;
......
193 196
gchar *filter_get_str			(FilterRule		*rule);
194 197
FilterRule *filter_read_str		(const gchar		*str);
195 198

  
199
void filter_set_addressbook_func	(FilterInAddressBookFunc func);
200
FilterInAddressBookFunc filter_get_addressbook_func
201
					(void);
202

  
196 203
FilterRule *filter_rule_new		(const gchar		*name,
197 204
					 FilterBoolOp		 bool_op,
198 205
					 GSList			*cond_list,
src/addressbook.c (revision 2461)
333 333
static void addressbook_import_ldif_cb		(void);
334 334
static void addressbook_import_csv_cb		(void);
335 335

  
336
static void addressbook_modified		(void);
337

  
338

  
336 339
static GtkItemFactoryEntry addressbook_entries[] =
337 340
{
338 341
	{N_("/_File"),			NULL,	NULL, 0, "<Branch>"},
......
408 411
	{N_("/_Paste"),		NULL, addressbook_paste_address_cb, 0, NULL}
409 412
};
410 413

  
414

  
411 415
void addressbook_open(Compose *target)
412 416
{
413 417
	if (!addrbook.window) {
......
2181 2185
			if (addressbook_edit_person(abf, NULL, person, TRUE) == NULL)
2182 2186
				return;
2183 2187
			addressbook_reopen();
2184
			invalidate_address_completion();
2188
			addressbook_modified();
2185 2189
			return;
2186 2190
		}
2187 2191
	} else if (obj->type == ADDR_ITEM_PERSON) {
......
2191 2195
		if (addressbook_edit_person(abf, NULL, person, FALSE) == NULL)
2192 2196
			return;
2193 2197
		addressbook_reopen();
2194
		invalidate_address_completion();
2198
		addressbook_modified();
2195 2199
		return;
2196 2200
	} else if (obj->type == ADDR_ITEM_GROUP) {
2197 2201
		ItemGroup *itemGrp = (ItemGroup *)obj;
......
3237 3241
		}
3238 3242

  
3239 3243
		/* Notify address completion of new data */
3240
		invalidate_address_completion();
3244
		addressbook_modified();
3241 3245
	}
3242 3246
}
3243 3247

  
......
4151 4155
	}
4152 4156

  
4153 4157
	/* Notify address completion */
4154
	invalidate_address_completion();
4158
	addressbook_modified();
4155 4159
}
4156 4160

  
4157 4161
/*
......
4191 4195
	}
4192 4196

  
4193 4197
	/* Notify address completion */
4198
	addressbook_modified();
4199
}
4200

  
4201
/* **********************************************************************
4202
* Address Book Fast Search.
4203
* ***********************************************************************
4204
*/
4205

  
4206
static GHashTable *addr_table;
4207

  
4208
static gint load_address(const gchar *name, const gchar *address,
4209
			 const gchar *nickname)
4210
{
4211
	gchar *addr;
4212

  
4213
	if (!address)
4214
		return -1;
4215

  
4216
	addr = g_ascii_strdown(address, -1);
4217

  
4218
	if (g_hash_table_lookup(addr_table, addr) == NULL)
4219
		g_hash_table_insert(addr_table, addr, addr);
4220
	else
4221
		g_free(addr);
4222

  
4223
	return 0;
4224
}
4225

  
4226
static void addressbook_modified(void)
4227
{
4228
	if (addr_table) {
4229
		hash_free_strings(addr_table);
4230
		g_hash_table_destroy(addr_table);
4231
		addr_table = NULL;
4232
	}
4233

  
4194 4234
	invalidate_address_completion();
4195 4235
}
4196 4236

  
4237
gboolean addressbook_has_address(const gchar *address)
4238
{
4239
	GSList *list, *cur;
4240
	gchar *addr;
4241
	gboolean found = FALSE;
4242

  
4243
	if (!address)
4244
		return FALSE;
4245

  
4246
	debug_print("addressbook_has_address: check if addressbook has address: %s\n", address);
4247

  
4248
	list = address_list_append(NULL, address);
4249
	if (!list)
4250
		return FALSE;
4251

  
4252
	if (!addr_table) {
4253
		addr_table = g_hash_table_new(g_str_hash, g_str_equal);
4254
		addressbook_load_completion(load_address);
4255
	}
4256

  
4257
	for (cur = list; cur != NULL; cur = cur->next) {
4258
		addr = g_ascii_strdown((gchar *)cur->data, -1);
4259

  
4260
		if (g_hash_table_lookup(addr_table, addr)) {
4261
			found = TRUE;
4262
			debug_print("'%s' is in addressbook\n", addr);
4263
		} else {
4264
			found = FALSE;
4265
			g_free(addr);
4266
			break;
4267
		}
4268
		g_free(addr);
4269
	}
4270

  
4271
	slist_free_strings(list);
4272

  
4273
	return found;
4274
}
4275

  
4197 4276
/*
4198 4277
* End of Source.
4199 4278
*/
src/addressbook.h (revision 2461)
49 49

  
50 50
gboolean addressbook_load_completion	( gint (*callBackFunc) ( const gchar *, const gchar *, const gchar * ) );
51 51

  
52
gboolean addressbook_has_address	(const gchar	*address);
53

  
52 54
#endif /* __ADDRESSBOOK_H__ */
src/main.c (revision 2461)
257 257
	CHDIR_EXIT_IF_FAIL(get_home_dir(), 1);
258 258

  
259 259
	prefs_common_read_config();
260
	filter_set_addressbook_func(addressbook_has_address);
260 261
	filter_read_config();
261 262
	prefs_actions_read_config();
262 263
	prefs_display_header_read_config();
src/prefs_filter_edit.c (revision 2461)
129 129

  
130 130
static void prefs_filter_cond_activated_cb	(GtkWidget	*widget,
131 131
						 gpointer	 data);
132
static void prefs_filter_match_activated_cb	(GtkWidget	*widget,
133
						 gpointer	 data);
132 134
static void prefs_filter_action_activated_cb	(GtkWidget	*widget,
133 135
						 gpointer	 data);
134 136

  
......
472 474
	GtkWidget *add_btn;
473 475
	GtkWidget *del_img;
474 476
	GtkWidget *add_img;
477
	GtkWidget *match_menu_in_addr;
478
	GtkWidget *match_menu_not_in_addr;
475 479

  
476 480
	cond_hbox = g_new0(CondHBox, 1);
477 481

  
......
518 522
	gtk_widget_show(match_type_optmenu);
519 523
	gtk_box_pack_start(GTK_BOX(hbox), match_type_optmenu, FALSE, FALSE, 0);
520 524

  
525
#define MATCH_MENUITEM_ADD(str, action)					    \
526
{									    \
527
	MENUITEM_ADD(menu, menuitem, str, action);			    \
528
	g_signal_connect(G_OBJECT(menuitem), "activate",		    \
529
			 G_CALLBACK(prefs_filter_match_activated_cb),	    \
530
			 cond_hbox);					    \
531
}
521 532
	menu = gtk_menu_new();
522 533
	gtk_widget_show(menu);
523
	MENUITEM_ADD(menu, menuitem, _("contains"),
524
		     PF_MATCH_CONTAIN);
525
	MENUITEM_ADD(menu, menuitem, _("doesn't contain"),
526
		     PF_MATCH_NOT_CONTAIN);
527
	MENUITEM_ADD(menu, menuitem, _("is"),
528
		     PF_MATCH_EQUAL);
529
	MENUITEM_ADD(menu, menuitem, _("is not"),
530
		     PF_MATCH_NOT_EQUAL);
534
	MATCH_MENUITEM_ADD(_("contains"),               PF_MATCH_CONTAIN);
535
	MATCH_MENUITEM_ADD(_("doesn't contain"),        PF_MATCH_NOT_CONTAIN);
536
	MATCH_MENUITEM_ADD(_("is"),                     PF_MATCH_EQUAL);
537
	MATCH_MENUITEM_ADD(_("is not"),                 PF_MATCH_NOT_EQUAL);
531 538
#if defined(USE_ONIGURUMA) || defined(HAVE_REGCOMP)
532
	MENUITEM_ADD(menu, menuitem, _("match to regex"),
533
		     PF_MATCH_REGEX);
534
	MENUITEM_ADD(menu, menuitem, _("doesn't match to regex"),
535
		     PF_MATCH_NOT_REGEX);
539
	MATCH_MENUITEM_ADD(_("match to regex"),         PF_MATCH_REGEX);
540
	MATCH_MENUITEM_ADD(_("doesn't match to regex"), PF_MATCH_NOT_REGEX);
536 541
#endif
542
	MATCH_MENUITEM_ADD(_("is in addressbook"),      PF_MATCH_IN_ADDRESSBOOK);
543
	match_menu_in_addr = menuitem;
544
	MATCH_MENUITEM_ADD(_("isn't in addressbook"),   PF_MATCH_NOT_IN_ADDRESSBOOK);
545
	match_menu_not_in_addr = menuitem;
537 546
	gtk_option_menu_set_menu(GTK_OPTION_MENU(match_type_optmenu), menu);
538 547

  
548
#undef MATCH_MENUITEM_ADD
549

  
539 550
	size_match_optmenu = gtk_option_menu_new();
540 551
	gtk_widget_show(size_match_optmenu);
541 552
	gtk_box_pack_start(GTK_BOX(hbox), size_match_optmenu, FALSE, FALSE, 0);
......
612 623
	cond_hbox->key_entry = key_entry;
613 624
	cond_hbox->spin_btn = spin_btn;
614 625
	cond_hbox->label = label;
626
	cond_hbox->match_menu_in_addr = match_menu_in_addr;
627
	cond_hbox->match_menu_not_in_addr = match_menu_not_in_addr;
615 628
	cond_hbox->del_btn = del_btn;
616 629
	cond_hbox->add_btn = add_btn;
617 630
	cond_hbox->cur_type = PF_COND_HEADER;
......
841 854
			else
842 855
				match_type = PF_MATCH_REGEX;
843 856
			break;
857
		case FLT_IN_ADDRESSBOOK:
858
			if (FLT_IS_NOT_MATCH(cond->match_flag))
859
				match_type = PF_MATCH_NOT_IN_ADDRESSBOOK;
860
			else
861
				match_type = PF_MATCH_IN_ADDRESSBOOK;
862
			break;
844 863
		}
845 864
		break;
846 865
	case FLT_COND_UNREAD:
......
895 914
		gtk_option_menu_set_history
896 915
			(GTK_OPTION_MENU(hbox->status_match_optmenu),
897 916
			 status_type);
917

  
918
	if (match_type == PF_MATCH_IN_ADDRESSBOOK ||
919
	    match_type == PF_MATCH_NOT_IN_ADDRESSBOOK)
920
		gtk_widget_hide(hbox->key_entry);
898 921
}
899 922

  
900 923
void prefs_filter_edit_action_hbox_set(ActionHBox *hbox, FilterAction *action)
......
977 1000

  
978 1001
void prefs_filter_edit_set_cond_hbox_widgets(CondHBox *hbox, CondMenuType type)
979 1002
{
1003
	MatchMenuType match_type;
1004

  
980 1005
	switch (type) {
981 1006
	case PF_COND_HEADER:
982 1007
	case PF_COND_TO_OR_CC:
......
986 1011
		gtk_widget_hide(hbox->size_match_optmenu);
987 1012
		gtk_widget_hide(hbox->age_match_optmenu);
988 1013
		gtk_widget_hide(hbox->status_match_optmenu);
989
		gtk_widget_show(hbox->key_entry);
1014
		match_type = menu_get_option_menu_active_index
1015
			(GTK_OPTION_MENU(hbox->match_type_optmenu));
1016
		if (match_type == PF_MATCH_IN_ADDRESSBOOK ||
1017
		    match_type == PF_MATCH_NOT_IN_ADDRESSBOOK)
1018
			gtk_widget_hide(hbox->key_entry);
1019
		else
1020
			gtk_widget_show(hbox->key_entry);
990 1021
		gtk_widget_hide(hbox->spin_btn);
991 1022
		gtk_widget_hide(hbox->label);
1023
		if (type == PF_COND_HEADER || type == PF_COND_TO_OR_CC) {
1024
			gtk_widget_show(hbox->match_menu_in_addr);
1025
			gtk_widget_show(hbox->match_menu_not_in_addr);
1026
		} else {
1027
			gtk_widget_hide(hbox->match_menu_in_addr);
1028
			gtk_widget_hide(hbox->match_menu_not_in_addr);
1029
			if (match_type == PF_MATCH_IN_ADDRESSBOOK ||
1030
			    match_type == PF_MATCH_NOT_IN_ADDRESSBOOK) {
1031
				gtk_option_menu_set_history(GTK_OPTION_MENU(hbox->match_type_optmenu), 0);
1032
				gtk_widget_show(hbox->key_entry);
1033
			}
1034
		}
992 1035
		break;
993 1036
	case PF_COND_CMD_TEST:
994 1037
		gtk_widget_hide(hbox->match_type_optmenu);
......
1703 1746
		match_type = FLT_REGEX;
1704 1747
		match_flag |= FLT_NOT_MATCH;
1705 1748
		break;
1749
	case PF_MATCH_IN_ADDRESSBOOK:
1750
		match_type = FLT_IN_ADDRESSBOOK;
1751
		break;
1752
	case PF_MATCH_NOT_IN_ADDRESSBOOK:
1753
		match_type = FLT_IN_ADDRESSBOOK;
1754
		match_flag |= FLT_NOT_MATCH;
1755
		break;
1706 1756
	default:
1707 1757
		break;
1708 1758
	}
......
2035 2085
	}
2036 2086
}
2037 2087

  
2088
static void prefs_filter_match_activated_cb(GtkWidget *widget, gpointer data)
2089
{
2090
	CondHBox *hbox = (CondHBox *)data;
2091
	GtkWidget *cond_type_menuitem;
2092
	CondMenuType cond_menu_type;
2093

  
2094
	cond_type_menuitem = gtk_menu_get_active
2095
		(GTK_MENU(gtk_option_menu_get_menu
2096
			(GTK_OPTION_MENU(hbox->cond_type_optmenu))));
2097
	cond_menu_type = GPOINTER_TO_INT
2098
		(g_object_get_data(G_OBJECT(cond_type_menuitem), MENU_VAL_ID));
2099

  
2100
	prefs_filter_edit_set_cond_hbox_widgets(hbox, cond_menu_type);
2101
}
2102

  
2038 2103
static void prefs_filter_action_activated_cb(GtkWidget *widget, gpointer data)
2039 2104
{
2040 2105
	ActionHBox *hbox = (ActionHBox *)data;
src/prefs_filter_edit.h (revision 2461)
55 55
	PF_MATCH_NOT_EQUAL,
56 56
	PF_MATCH_REGEX,
57 57
	PF_MATCH_NOT_REGEX,
58
	PF_MATCH_IN_ADDRESSBOOK,
59
	PF_MATCH_NOT_IN_ADDRESSBOOK,
58 60
	PF_MATCH_NONE
59 61
} MatchMenuType;
60 62

  
......
118 120
	GtkWidget *spin_btn;
119 121
	GtkWidget *label;
120 122

  
123
	GtkWidget *match_menu_in_addr;
124
	GtkWidget *match_menu_not_in_addr;
125

  
121 126
	GtkWidget *del_btn;
122 127
	GtkWidget *add_btn;
123 128

  
ChangeLog (revision 2461)
1
2010-02-10
2

  
3
	* libsylph/filter.[ch]
4
	  src/prefs_filter_edit.[ch]
5
	  src/addressbook.[ch]
6
	  src/main.c: added a new filter match type: is (not) in addressbook.
7
	  addressbook_has_address(): new function for fast search of address
8
	  book by addresses.
9

  
1 10
2010-02-05
2 11

  
3 12
	* src/setup.c: confirm on cancel. Modified messages.

Also available in: Unified diff