2
* $Id: filter.c,v 1.68 2004/01/15 23:51:48 wyldfire Exp $
4
* Copyright (c) 2001-2003, Raphael Manfredi, Richard Eckart
6
* GUI filtering functions.
8
*----------------------------------------------------------------------
9
* This file is part of gtk-gnutella.
11
* gtk-gnutella is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License as published by
13
* the Free Software Foundation; either version 2 of the License, or
14
* (at your option) any later version.
16
* gtk-gnutella is distributed in the hope that it will be useful,
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
* GNU General Public License for more details.
21
* You should have received a copy of the GNU General Public License
22
* along with gtk-gnutella; if not, write to the Free Software
24
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
*----------------------------------------------------------------------
28
#include <sys/types.h>
29
#include <netinet/in.h>
30
#include <arpa/inet.h>
33
#include "filter_gui.h"
34
#include "search_gui.h"
35
#include "gtk-missing.h"
38
#include "interface-glade2.h"
40
#include "interface-glade1.h"
43
#include "override.h" /* Must be the last header included */
45
RCSID("$Id: filter.c,v 1.68 2004/01/15 23:51:48 wyldfire Exp $");
48
* If FILTER_HIDE_ON_CLOSE is defined, the filter dialog is only hidden
49
* when the dialog is close instead the of the dialog being destroyed.
51
#define FILTER_HIDE_ON_CLOSE
53
typedef struct shadow {
67
* Private functions prototypes
69
static gint shadow_filter_eq(const shadow_t *a, const filter_t *b);
70
static shadow_t *shadow_new(filter_t *s);
71
static shadow_t *shadow_find(filter_t *s);
72
static int filter_apply(filter_t *, record_t *, filter_result_t *);
73
static void filter_remove_rule(filter_t *f, rule_t *r);
74
static void filter_free(filter_t *filter);
75
static void filter_refresh_display(GList *filter_list);
77
void dump_ruleset(GList *ruleset);
78
void dump_filter(filter_t *filter);
79
void dump_shadow(shadow_t *shadow);
84
filter_t *work_filter = NULL;
89
static GList *shadow_filters = NULL;
90
static gchar f_tmp[1024];
91
static GList *filters_added = NULL;
92
static GList *filters_removed = NULL;
94
/* built-in targets */
95
filter_t *filter_drop = NULL;
96
filter_t *filter_show = NULL;
97
filter_t *filter_download = NULL;
98
filter_t *filter_nodownload = NULL;
99
filter_t *filter_return = NULL;
102
filter_t *filter_global_pre = NULL;
103
filter_t *filter_global_post = NULL;
105
/* not static because needed in search_xml. */
106
GList *filters = NULL;
107
GList *filters_current = NULL;
113
void dump_ruleset(GList *ruleset)
118
for (r = ruleset; r != NULL; r=r->next)
119
printf(" rule %3d : %s\n", n, filter_rule_to_gchar(r->data));
122
void dump_filter(filter_t *filter)
124
g_assert(filter != NULL);
125
printf("Filter name : %s\n", filter->name);
126
printf(" bound : %p\n", filter->search);
127
printf(" refcount : %d\n", filter->refcount);
128
dump_ruleset(filter->ruleset);
131
void dump_shadow(shadow_t *shadow)
133
g_assert(shadow != NULL);
134
printf("Shadow for filt : %s\n", shadow->filter->name);
135
printf(" bound : %p\n", shadow->filter->search);
136
printf(" refcount : %d\n", shadow->refcount);
137
printf(" flt. ref : %d\n", shadow->filter->refcount);
139
dump_ruleset(shadow->added);
140
printf(" Removed:\n");
141
dump_ruleset(shadow->removed);
142
printf(" Current:\n");
143
dump_ruleset(shadow->current);
144
printf(" Original:\n");
145
dump_ruleset(shadow->filter->ruleset);
153
* Comparator function to match a shadow and a filter.
155
static gint shadow_filter_eq(const shadow_t *a, const filter_t *b)
157
if((a != NULL) && (b != NULL)) {
170
* Get the shadow for the given filter. Returns NULL if the filter
171
* does not have a shadow yet.
173
static shadow_t *shadow_find(filter_t *f)
179
l = g_list_find_custom
180
(shadow_filters, f, (GCompareFunc) shadow_filter_eq);
184
printf("shadow found for: %s\n", f->name);
188
printf("no shadow found for: %s\n", f->name);
198
* Creates a new shadow for a given filter and registers it with
199
* our current shadow list.
201
static shadow_t *shadow_new(filter_t *f)
206
g_assert(f->name != NULL);
209
printf("creating shadow for: %s\n", f->name);
211
shadow = g_new0(shadow_t, 1);
214
shadow->current = g_list_copy(f->ruleset);
215
shadow->added = NULL;
216
shadow->removed = NULL;
217
shadow->refcount = f->refcount;
218
shadow->flags = f->flags;
220
shadow_filters = g_list_append(shadow_filters, shadow);
230
* Forgets all about a given shadow and free's ressourcs for it.
231
* At this point we can no longer assume that the shadow->current
232
* field contains a valid pointer. We may have been called to
233
* clean up a shadow for a filter whose ruleset has already been
234
* cleared. We don't clean up any memory that is owned by the
237
static void shadow_cancel(shadow_t *shadow)
241
g_assert(shadow != NULL);
242
g_assert(shadow->filter != NULL);
245
printf("cancel shadow for filter: %s\n", shadow->filter->name);
247
for (r = shadow->added; r != NULL; r = r->next)
248
filter_free_rule(r->data);
251
* Since we cancel the shadow, we also free the added,
252
* removed and current lists now. Then we remove the shadow
255
g_list_free(shadow->removed);
256
g_list_free(shadow->added);
257
g_list_free(shadow->current);
258
shadow->removed = shadow->added = shadow->current = NULL;
260
shadow_filters = g_list_remove(shadow_filters, shadow);
269
* Commit all the changes for a given shadow and then forget and free
272
static void shadow_commit(shadow_t *shadow)
277
g_assert(shadow != NULL);
278
g_assert(shadow->filter != NULL);
280
realf = shadow->filter;
282
if (gui_debug >= 6) {
283
printf("committing shadow for filter:\n");
288
* Free memory for all removed rules
290
for (f = shadow->removed; f != NULL; f = f->next)
291
filter_free_rule(f->data);
294
* Remove the SHADOW flag from all new rules.
296
for (f = shadow->added; f != NULL; f = f->next)
297
clear_flags(((rule_t*) f->data)->flags, RULE_FLAG_SHADOW);
300
* We also free the memory of the filter->ruleset GList.
301
* We don't need them anymore.
303
g_list_free(shadow->filter->ruleset);
306
* Now the actual filter is corrupted, because
307
* we have freed memory its rules.
308
* But we have a copy of the ruleset without exactly those
309
* rules we freed now. We use this as new ruleset.
311
shadow->filter->ruleset = shadow->current;
314
* Not forgetting to update the refcount. There is a chance
315
* that this shadow only existed because of a change in the
318
shadow->filter->refcount = shadow->refcount;
320
shadow->filter->flags = shadow->flags;
323
* Now that we have actually commited the changes for this
324
* shadow, we remove this shadow from our shadow list
325
* and free it's ressources. Note that we do not free
326
* shadow->current because this is the new filter ruleset.
328
g_list_free(shadow->added);
329
g_list_free(shadow->removed);
330
shadow->added = shadow->removed = shadow->current = NULL;
331
shadow->filter = NULL;
332
shadow_filters = g_list_remove(shadow_filters, shadow);
335
if (gui_debug >= 6) {
336
printf("after commit filter looks like this\n");
344
* filter_refresh_display:
346
* Regenerates the filter tree and rules display from after a apply/revert.
348
static void filter_refresh_display(GList *filter_list)
352
filter_gui_freeze_filters();
353
filter_gui_filter_clear_list();
354
for (l = filter_list; l != NULL; l = l->next) {
355
filter_t *filter = (filter_t *)l->data;
360
shadow = shadow_find(filter);
361
ruleset = (shadow != NULL) ? shadow->current : filter->ruleset;
362
enabled = (shadow != NULL) ?
363
filter_is_active(shadow) :
364
filter_is_active(filter);
366
filter_gui_filter_add(filter, ruleset);
367
filter_gui_filter_set_enabled(filter, enabled);
369
filter_gui_thaw_filters();
375
* filter_open_dialog:
377
* Open and initialize the filter dialog.
379
void filter_open_dialog(void) {
380
search_t *current_search;
382
current_search = search_gui_get_current_search();
384
if (filter_dialog == NULL) {
385
filter_dialog = filter_gui_create_dlg_filters();
386
g_assert(filter_dialog != NULL);
389
filter_refresh_display(filters_current);
392
if (current_search != NULL) {
393
filter_set(current_search->filter);
398
filter_gui_show_dialog();
404
* filter_close_dialog:
406
* Close the filter dialog. If commit is TRUE the changes
407
* are committed, otherwise dropped.
409
void filter_close_dialog(gboolean commit)
412
filter_apply_changes();
414
filter_revert_changes();
416
if (filter_dialog != NULL) {
417
gint32 coord[4] = {0, 0, 0, 0};
419
gdk_window_get_root_origin(filter_dialog->window, &coord[0], &coord[1]);
420
gdk_drawable_get_size(filter_dialog->window, &coord[2], &coord[3]);
422
gui_prop_set_guint32(PROP_FILTER_DLG_COORDS, (guint32 *) coord, 0, 4);
424
filter_main_divider_pos =
425
gtk_paned_get_position
426
(GTK_PANED(lookup_widget(filter_dialog, "hpaned_filter_main")));
428
#ifdef FILTER_HIDE_ON_CLOSE
429
gtk_widget_hide(filter_dialog);
431
gtk_object_destroy(GTK_OBJECT(filter_dialog));
432
filter_dialog = NULL;
433
#endif /* FILTER_HIDE_ON_CLOSE */
440
* filter_duplicate_rule:
442
* returns a new rule created with information based on the given rule
443
* with the appropriate filter_new_*_rule call. Defaults set by those
444
* calls (like RULE_FLAG_VALID) will also apply to the the returned rule.
446
rule_t *filter_duplicate_rule(rule_t *r)
452
return filter_new_text_rule
453
(r->u.text.match, r->u.text.type, r->u.text.case_sensitive,
454
r->target, r->flags);
456
return filter_new_ip_rule
457
(r->u.ip.addr, r->u.ip.mask, r->target, r->flags);
459
return filter_new_size_rule
460
(r->u.size.lower, r->u.size.upper, r->target, r->flags);
462
return filter_new_jump_rule(r->target, r->flags);
464
return filter_new_sha1_rule
465
(r->u.sha1.hash, r->u.sha1.filename, r->target, r->flags);
467
return filter_new_flag_rule
468
(r->u.flag.stable, r->u.flag.busy, r->u.flag.push,
469
r->target, r->flags);
471
return filter_new_state_rule
472
(r->u.state.display, r->u.state.download, r->target, r->flags);
474
g_error("filter_duplicate_rule: unknown rule type: %d", r->type);
481
rule_t *filter_new_text_rule(gchar *match, gint type,
482
gboolean case_sensitive, filter_t *target, guint16 flags)
487
g_assert(match != NULL);
488
g_assert(target != NULL);
490
r = g_new0(rule_t, 1);
495
r->u.text.case_sensitive = case_sensitive;
496
r->u.text.type = type;
497
r->u.text.match = g_strdup(match);
498
r->u.text.matchlen = strlen(match);
499
set_flags(r->flags, RULE_FLAG_VALID);
501
if (!r->u.text.case_sensitive)
502
strlower(r->u.text.match, r->u.text.match);
504
buf = g_strdup(r->u.text.match);
506
if (r->u.text.type == RULE_TEXT_WORDS) {
510
for (s = strtok(buf, " \t\n"); s; s = strtok(NULL, " \t\n"))
511
l = g_list_append(l, pattern_compile(s));
513
r->u.text.u.words = l;
515
if (r->u.text.type == RULE_TEXT_REGEXP) {
519
re = g_new0(regex_t, 1);
520
err = regcomp(re, buf,
521
REG_EXTENDED|REG_NOSUB|(r->u.text.case_sensitive ? 0 : REG_ICASE));
525
regerror(err, re, regbuf, sizeof(regbuf));
528
"problem in regular expression: %s"
529
"; falling back to substring match", buf);
531
r->u.text.type = RULE_TEXT_SUBSTR;
538
/* no "else" because REGEXP can fall back here */
539
if (r->u.text.type == RULE_TEXT_SUBSTR)
540
r->u.text.u.pattern = pattern_compile(buf);
549
rule_t *filter_new_ip_rule
550
(guint32 addr, guint32 mask, filter_t *target, guint16 flags)
554
g_assert(target != NULL);
556
r = g_new0(rule_t, 1);
562
r->u.ip.addr &= r->u.ip.mask;
565
set_flags(r->flags, RULE_FLAG_VALID);
572
rule_t *filter_new_size_rule
573
(size_t lower, size_t upper, filter_t *target, guint16 flags)
577
g_assert(target != NULL);
579
f = g_new0(rule_t, 1);
584
f->u.size.lower = upper;
585
f->u.size.upper = lower;
587
f->u.size.lower = lower;
588
f->u.size.upper = upper;
593
set_flags(f->flags, RULE_FLAG_VALID);
601
rule_t *filter_new_jump_rule(filter_t *target, guint16 flags)
605
g_assert(target != NULL);
607
f = g_new0(rule_t, 1);
613
set_flags(f->flags, RULE_FLAG_VALID);
621
rule_t *filter_new_sha1_rule
622
(gchar *sha1, gchar *filename, filter_t *target, guint16 flags)
626
g_assert(target != NULL);
627
g_assert(filename != NULL);
629
f = g_new0(rule_t, 1);
635
f->u.sha1.hash = g_memdup(sha1, SHA1_RAW_SIZE);
636
f->u.sha1.filename = g_strdup(filename);
638
set_flags(f->flags, RULE_FLAG_VALID);
645
rule_t *filter_new_flag_rule
646
(enum rule_flag_action stable, enum rule_flag_action busy,
647
enum rule_flag_action push, filter_t *target, guint16 flags)
651
g_assert(target != NULL);
653
f = g_new0(rule_t, 1);
657
f->u.flag.stable = stable;
658
f->u.flag.busy = busy;
659
f->u.flag.push = push;
662
set_flags(f->flags, RULE_FLAG_VALID);
669
rule_t *filter_new_state_rule
670
(enum filter_prop_state display, enum filter_prop_state download,
671
filter_t *target, guint16 flags)
675
g_assert(target != NULL);
677
f = g_new0(rule_t, 1);
679
f->type = RULE_STATE;
681
f->u.state.display = display;
682
f->u.state.download = download;
685
set_flags(f->flags, RULE_FLAG_VALID);
695
* Start working on the given filter. Set this filter as
696
* work_filter so we can commit the changed rules to this
699
void filter_set(filter_t *f)
707
shadow = shadow_find(f);
708
if (shadow != NULL) {
710
(shadow->refcount == 0) && !filter_is_builtin(f) &&
711
!filter_is_global(f) && !filter_is_bound(f);
712
active = filter_is_active(shadow);
713
ruleset = shadow->current;
716
(f->refcount == 0) && !filter_is_builtin(f) &&
717
!filter_is_global(f) && !filter_is_bound(f);
718
active = filter_is_active(f);
719
ruleset = f->ruleset;
722
filter_gui_filter_set(f, removable, active, ruleset);
724
filter_gui_filter_set(NULL, FALSE, FALSE, NULL);
728
* don't want the work_filter to be selectable as a target
729
* so we changed it... we have to rebuild.
731
filter_update_targets();
737
* filter_close_search:
739
* Clear the searches shadow, update the combobox and the filter
740
* bound to this search (search->ruleser).
742
void filter_close_search(search_t *s)
747
g_assert(s->filter != NULL);
750
printf("closing search (freeing filter): %s\n", s->query);
752
shadow = shadow_find(s->filter);
753
if (shadow != NULL) {
756
copy = g_list_copy(shadow->removed);
757
G_LIST_FOREACH_SWAPPED(copy, filter_append_rule_to_session, s->filter);
760
copy = g_list_copy(shadow->added);
761
G_LIST_FOREACH_SWAPPED(copy,
762
filter_remove_rule_from_session, s->filter);
765
shadow_cancel(shadow);
769
* If this is the filter currently worked on, clear the display.
771
if (s->filter == work_filter)
774
filter_gui_filter_remove(s->filter);
776
filter_free(s->filter);
783
* filter_apply_changes:
785
* Go through all the shadow filters, and commit the recorded
786
* changes to the assosicated filter. We walk through the
787
* shadow->current list. Every item in shadow->removed will be
788
* removed from the searchs filter and the memory will be freed.
789
* Then shadow->current will be set as the new filter for that
792
void filter_apply_changes(void)
797
* Free memory for all removed filters;
799
for (s = shadow_filters; s != NULL; s = shadow_filters)
800
shadow_commit((shadow_t*)s->data);
802
g_list_free(filters);
803
filters = g_list_copy(filters_current);
806
* Remove the SHADOW flag from all added filters
808
for (s = filters_added; s != NULL; s = s->next)
809
clear_flags(((filter_t *)s->data)->flags, FILTER_FLAG_SHADOW);
811
g_list_free(filters_added);
812
filters_added = NULL;
815
* Free all removed filters. Don't iterate since filter_free removes
816
* the filter from filters_removed.
818
for (s = filters_removed; s != NULL; s = filters_removed) {
819
filter_free(s->data);
821
g_assert(filters_removed == NULL);
823
filter_update_targets();
824
filter_set(work_filter);
830
* filter_revert_changes:
832
* Free the ressources for all added filters and forget all shadows.
833
* A running session will not be ended by this.
835
void filter_revert_changes(void)
841
printf("Canceling all changes to filters/rules\n");
843
filter_gui_freeze_filters();
844
filter_gui_freeze_rules();
847
* Free memory for all added filters and for the shadows.
849
for (s = shadow_filters; s != NULL; s = shadow_filters)
850
shadow_cancel((shadow_t *)s->data);
852
if (g_list_find(filters, work_filter) != NULL)
853
filter_set(work_filter);
857
g_list_free(filters_current);
858
filters_current = g_list_copy(filters);
861
* Free and remove all added filters. We don't iterate explicitly,
862
* because filter_free removes the added filter from filters_added
866
for (s = filters_added; s != NULL; s = filters_added) {
867
filter_t *filter = (filter_t *) s->data;
869
filter_gui_filter_remove(filter);
872
g_assert(filters_added == NULL);
875
* Restore all removed filters.
877
for (s = filters_removed; s != NULL; s = s->next) {
878
filter_t *filter = (filter_t *) s->data;
880
filter_gui_filter_add(filter, filter->ruleset);
882
g_list_free(filters_removed);
883
filters_removed = NULL;
886
* Update the rulecounts. Since we don't have any shadows anymore, we
887
* can just use f->ruleset. Also update the 'enabled' state of the
888
* filters while we are at it.
890
for (s = filters_current; s != NULL; s = g_list_next(s)) {
891
filter_t *filter = (filter_t *) s->data;
893
filter_gui_update_rule_count(filter, filter->ruleset);
894
filter_gui_filter_set_enabled(filter, filter_is_active(filter));
897
filter_gui_thaw_rules();
898
filter_gui_thaw_filters();
900
filter_update_targets();
906
* filter_rule_condition_to_gchar:
908
* Convert a rule condition to a human readable string.
910
gchar *filter_rule_condition_to_gchar(const rule_t *r)
912
static gchar tmp[256];
918
switch (r->u.text.type) {
919
case RULE_TEXT_PREFIX:
922
"If filename begins with \"%s\" %s",
924
r->u.text.case_sensitive ? "(case sensitive)" : "");
926
case RULE_TEXT_WORDS:
929
"If filename contains the words \"%s\" %s",
931
r->u.text.case_sensitive ? "(case sensitive)" : "");
933
case RULE_TEXT_SUFFIX:
936
"If filename ends with \"%s\" %s",
938
r->u.text.case_sensitive ? "(case sensitive)" : "");
940
case RULE_TEXT_SUBSTR:
943
"If filename contains the substring \"%s\" %s",
945
r->u.text.case_sensitive ? "(case sensitive)" : "");
947
case RULE_TEXT_REGEXP:
950
"If filename matches the regex \"%s\" %s",
952
r->u.text.case_sensitive ? "(case sensitive)" : "");
954
case RULE_TEXT_EXACT:
957
"If filename is \"%s\" %s",
959
r->u.text.case_sensitive ? "(case sensitive)" : "");
962
g_error("filter_rule_condition_to_gchar:"
963
"unknown text rule type: %d", r->u.text.type);
971
mask = g_strdup(ip_to_gchar(r->u.ip.mask));
972
addr = g_strdup(ip_to_gchar(r->u.ip.addr));
974
gm_snprintf(tmp, sizeof(tmp),
975
"If IP address matches %s/%s", addr, mask);
982
if (r->u.size.lower == 0)
983
gm_snprintf(tmp, sizeof(tmp),
984
"If filesize is smaller than %d (%s)",
985
(gint) r->u.size.upper, short_size(r->u.size.upper));
986
else if (r->u.size.upper == r->u.size.lower)
987
gm_snprintf(tmp, sizeof(tmp),
988
"If filesize is exactly %d (%s)",
989
(gint) r->u.size.upper, short_size(r->u.size.upper));
994
s1 = g_strdup(short_size(r->u.size.lower));
995
s2 = g_strdup(short_size(r->u.size.upper));
997
gm_snprintf(tmp, sizeof(tmp),
998
"If filesize is between %d and %d (%s - %s)",
999
(gint) r->u.size.lower, (int)r->u.size.upper, s1, s2);
1006
if (r->u.sha1.hash != NULL) {
1007
gm_snprintf(tmp, sizeof(tmp), "If urn:sha1 is same as for \"%s\"",
1008
r->u.sha1.filename);
1010
gm_snprintf(tmp, sizeof(tmp), "If urn:sha1 is not available");
1019
gchar *busy_str = "";
1020
gchar *push_str = "";
1021
gchar *stable_str = "";
1026
switch (r->u.flag.busy) {
1028
busy_str = "busy is set";
1031
case RULE_FLAG_UNSET:
1032
busy_str = "busy is not set";
1035
case RULE_FLAG_IGNORE:
1039
switch (r->u.flag.push) {
1042
push_str = "push is set";
1045
case RULE_FLAG_UNSET:
1047
push_str = "push is not set";
1050
case RULE_FLAG_IGNORE:
1054
switch (r->u.flag.stable) {
1057
stable_str = "stable is set";
1060
case RULE_FLAG_UNSET:
1062
stable_str = "stable is not set";
1065
case RULE_FLAG_IGNORE:
1072
"If flag %s%s%s%s%s",
1073
busy_str, s1, push_str, s2, stable_str);
1077
"Always (all flags ignored)");
1082
gchar *display_str = "";
1083
gchar *download_str = "";
1087
switch (r->u.state.display) {
1088
case FILTER_PROP_STATE_UNKNOWN:
1089
display_str = "DISPLAY is undefined";
1092
case FILTER_PROP_STATE_DO:
1093
display_str = "DISPLAY";
1096
case FILTER_PROP_STATE_DONT:
1097
display_str = "DON'T DISPLAY";
1100
case FILTER_PROP_STATE_IGNORE:
1103
g_assert_not_reached();
1106
switch (r->u.state.download) {
1107
case FILTER_PROP_STATE_UNKNOWN:
1109
download_str = "DOWNLOAD is undefined";
1112
case FILTER_PROP_STATE_DO:
1114
download_str = "DOWNLOAD";
1117
case FILTER_PROP_STATE_DONT:
1119
download_str = "DON'T DOWNLOAD";
1122
case FILTER_PROP_STATE_IGNORE:
1125
g_assert_not_reached();
1132
display_str, s1, download_str);
1136
"Always (all states ignored)");
1140
g_error("filter_rule_condition_to_gchar: "
1141
"unknown rule type: %d", r->type);
1151
* filter_rule_to_gchar:
1153
* Convert the filter to a human readable string.
1155
gchar *filter_rule_to_gchar(rule_t *r)
1159
g_assert(r != NULL);
1161
cond = g_strdup(filter_rule_condition_to_gchar(r));
1163
gm_snprintf(f_tmp, sizeof(f_tmp), "%s%s %s jump to \"%s\"",
1164
RULE_IS_NEGATED(r) ? "(Negated) " : "",
1165
RULE_IS_ACTIVE(r) ? "" : "(deactivated)",
1167
RULE_IS_VALID(r) ? r->target->name : "(invalid)");
1179
* Create a new filter with the given name.
1181
filter_t *filter_new(gchar *name)
1185
g_assert(name != NULL);
1187
f = g_new0(filter_t, 1);
1188
f->name = g_strdup(name);
1192
set_flags(f->flags, FILTER_FLAG_ACTIVE);
1200
* filter_add_to_session:
1202
* Add a filter to the current editing session. Never try to add
1203
* a filter twice. Returns a error code on failure and 0 on success.
1205
void filter_add_to_session(filter_t *f)
1207
g_assert(g_list_find(filters_current, f) == NULL);
1208
g_assert(f != NULL);
1212
* Either remove from removed or add to added list.
1214
if (g_list_find(filters_removed, f) != NULL)
1215
filters_removed = g_list_remove(filters_removed, f);
1217
filters_added = g_list_append(filters_added, f);
1220
* Since the filter is new and not yet used for filtering
1221
* we set the FILTER_FLAG_SHADOW flag.
1223
set_flags(f->flags, FILTER_FLAG_SHADOW);
1226
filters_current = g_list_append(filters_current, f);
1228
filter_gui_filter_add(f, f->ruleset);
1234
* filter_new_for_search:
1236
* Create a new filter bound to a search and register it.
1238
void filter_new_for_search(search_t *s)
1242
g_assert(s != NULL);
1243
g_assert(s->query != NULL);
1245
f = g_new0(filter_t, 1);
1246
f->name = g_strdup(s->query);
1250
set_flags(f->flags, FILTER_FLAG_ACTIVE);
1253
* Add filter to current and session lists
1255
filters = g_list_append(filters, f);
1256
filters_current = g_list_append(filters_current, f);
1259
* Crosslink filter and search
1265
* It's important to add the filter here, because it was not
1266
* bound before and would have been sorted in as a free filter.
1268
filter_gui_filter_add(f, f->ruleset);
1274
* filter_remove_from_session:
1276
* Mark the given filter as removed and delete it when the
1277
* dialog changes are committed.
1279
void filter_remove_from_session(filter_t *f)
1281
g_assert(g_list_find(filters_removed, f) == NULL);
1282
g_assert(g_list_find(filters_current, f) != NULL);
1285
* Either remove from added list or add to removed list.
1287
if (g_list_find(filters_added, f) != NULL)
1288
filters_added = g_list_remove(filters_added, f);
1290
filters_removed = g_list_append(filters_removed, f);
1292
filters_current = g_list_remove(filters_current, f);
1295
* If this is the filter currently worked on, clear the display.
1297
if (work_filter == f)
1300
filter_gui_filter_remove(f);
1308
* Frees a filter and the filters assiciated with it and
1309
* unregisters it from current and session filter lists.
1311
static void filter_free(filter_t *f)
1315
g_assert(f != NULL);
1317
if (shadow_find(f) != NULL)
1318
g_error("Unable to free shadowed filter \"%s\" with refcount %d",
1319
f->name, f->refcount);
1321
if (f->refcount != 0)
1322
g_error("Unable to free referenced filter \"%s\" with refcount %d",
1323
f->name, f->refcount);
1326
* Remove the filter from current and session data
1328
if (g_list_find(filters, f) != NULL)
1329
filters = g_list_remove(filters, f);
1330
if (g_list_find(filters_current, f) != NULL)
1331
filters_current = g_list_remove(filters_current, f);
1332
if (g_list_find(filters_added, f) != NULL)
1333
filters_added = g_list_remove(filters_added, f);
1334
if (g_list_find(filters_removed, f) != NULL)
1335
filters_removed = g_list_remove(filters_removed, f);
1337
copy = g_list_copy(f->ruleset);
1338
G_LIST_FOREACH_SWAPPED(copy, filter_remove_rule, f);
1341
G_FREE_NULL(f->name);
1350
* Free memory reserved by rule respecting the type of the rule.
1352
void filter_free_rule(rule_t *r)
1354
g_assert(r != NULL);
1357
printf("freeing rule: %s\n", filter_rule_to_gchar(r));
1361
G_FREE_NULL(r->u.text.match);
1363
switch (r->u.text.type) {
1364
case RULE_TEXT_WORDS:
1365
g_list_foreach(r->u.text.u.words, (GFunc)pattern_free, NULL);
1366
g_list_free(r->u.text.u.words);
1367
r->u.text.u.words = NULL;
1369
case RULE_TEXT_SUBSTR:
1370
pattern_free(r->u.text.u.pattern);
1371
r->u.text.u.pattern = NULL;
1373
case RULE_TEXT_REGEXP:
1374
regfree(r->u.text.u.re);
1375
r->u.text.u.re = NULL;
1377
case RULE_TEXT_PREFIX:
1378
case RULE_TEXT_SUFFIX:
1379
case RULE_TEXT_EXACT:
1382
g_error("filter_free_rule: unknown text rule type: %d", r->u.text.type);
1386
G_FREE_NULL(r->u.sha1.hash);
1387
G_FREE_NULL(r->u.sha1.filename);
1396
g_error("filter_free_rule: unknown rule type: %d", r->type);
1404
* filter_append_rule:
1406
* Append a new rule to a filter. If necessary also update the shadow.
1407
* The addition of the rule can not be cancelled by canceling the
1408
* shadow. If no shadow for the filters exists, none is created.
1410
void filter_append_rule(filter_t *f, rule_t * const r)
1413
shadow_t *target_shadow;
1415
g_assert(f != NULL);
1416
g_assert(r != NULL);
1417
g_assert(r->target != NULL);
1419
shadow = shadow_find(f);
1420
target_shadow = shadow_find(r->target);
1422
if (g_list_find(f->ruleset, r) != NULL)
1423
g_error("rule already exists in filter \"%s\"", f->name);
1425
if ((shadow != NULL) && g_list_find(shadow->current, r))
1426
g_error("rule already exists in shadow for filter \"%s\"",
1430
* We add the rule to the filter increase the refcount on the target.
1432
f->ruleset = g_list_append(f->ruleset, r);
1433
r->target->refcount ++;
1435
printf("increased refcount on \"%s\" to %d\n",
1436
r->target->name, r->target->refcount);
1439
* If a shadow for our filter exists, we add it there also.
1442
shadow->current = g_list_append(shadow->current, r);
1445
* If a shadow for the target exists, we increase refcount there too.
1447
if (target_shadow != NULL) {
1448
target_shadow->refcount ++;
1451
printf("increased refcount on shadow of \"%s\" to %d\n",
1452
target_shadow->filter->name, target_shadow->refcount);
1456
* Update dialog if necessary.
1461
ruleset = (shadow != NULL) ? shadow->current : f->ruleset;
1463
if (work_filter == f)
1464
filter_gui_set_ruleset(ruleset);
1465
filter_gui_update_rule_count(f, ruleset);
1472
* filter_append_rule_to_session:
1474
* Append a new rule to the filter shadow. This call will fail
1475
* with an assertion error if the rule is already existing in
1478
void filter_append_rule_to_session(filter_t *f, rule_t * const r)
1480
shadow_t *shadow = NULL;
1481
shadow_t *target_shadow = NULL;
1483
g_assert(r != NULL);
1484
g_assert(f != NULL);
1485
g_assert(r->target != NULL);
1488
printf("appending rule to filter: %s <- %s (%p)\n",
1489
f->name, filter_rule_to_gchar(r), r->target);
1492
* The rule is added to a session, so we set the shadow flag.
1494
set_flags(r->flags, RULE_FLAG_SHADOW);
1497
* Create a new shadow if necessary.
1499
shadow = shadow_find(f);
1501
shadow = shadow_new(f);
1504
* You can never add a filter to a shadow or filter
1507
g_assert(g_list_find(shadow->current, r) == NULL);
1510
if (g_list_find(shadow->removed, r) == NULL) {
1511
shadow->added = g_list_append(shadow->added, r);
1513
shadow->removed = g_list_remove(shadow->removed, r);
1515
shadow->current = g_list_append(shadow->current, r);
1518
* We need to increase the refcount on the target.
1520
target_shadow = shadow_find(r->target);
1521
if (target_shadow == NULL)
1522
target_shadow = shadow_new(r->target);
1524
target_shadow->refcount ++;
1526
printf("increased refcount on shadow of \"%s\" to %d\n",
1527
target_shadow->filter->name, target_shadow->refcount);
1530
* Update dialog if necessary.
1532
if (work_filter == f)
1533
filter_gui_set_ruleset(shadow->current);
1534
filter_gui_update_rule_count(f, shadow->current);
1540
* filter_remove_rule:
1542
* Removes a rule directly. The removal can not be reversed by
1543
* cancelling the shadow. The filter is removed from the active
1544
* filter and from a potentially existing shadow as well.
1545
* If no shadow exists, no shadow is created.
1547
void filter_remove_rule(filter_t *f, rule_t *r)
1550
shadow_t *target_shadow;
1551
gboolean in_shadow_current;
1552
gboolean in_shadow_removed;
1555
g_assert(f != NULL);
1556
g_assert(r != NULL);
1557
g_assert(r->target != NULL);
1559
shadow = shadow_find(f);
1560
target_shadow = shadow_find(r->target);
1562
in_filter = g_list_find(f->ruleset, r) != NULL;
1565
* We need to check where the rule is actually located... in the
1566
* shadow, in the real filter or in both.
1568
if (shadow != NULL) {
1569
in_shadow_current = g_list_find(shadow->current, r) != NULL;
1570
in_shadow_removed = g_list_find(shadow->removed, r) != NULL;
1573
* If there is no shadow, we pretend that the shadow is
1574
* equal to the filter, so we set in_shadow_current to in_filter.
1576
in_shadow_current = in_filter;
1577
in_shadow_removed = FALSE;
1581
* We have to purge the rule from the shadow where necessary.
1583
if (in_shadow_current && (shadow != NULL)) {
1584
shadow->current = g_list_remove(shadow->current, r);
1585
shadow->added = g_list_remove(shadow->added, r);
1588
if (in_shadow_removed && (shadow != NULL))
1589
shadow->removed = g_list_remove(shadow->removed, r);
1592
f->ruleset = g_list_remove(f->ruleset, r);
1595
* Now we need to clean up the refcounts that may have been
1596
* caused by this rule. We have these possibilities:
1598
* in in shadow in shadow in shadow | refcounted in
1599
* filter current added removed | filter | shadow
1600
* ------------------------------------------------------------
1601
* yes yes yes yes | - failure A -
1602
* yes yes yes no | - failure C -
1603
* yes yes no yes | - failure D -
1604
* 1 yes yes no no | yes yes
1605
* yes no yes yes | - failure A -
1606
* yes no yes no | - failure B -
1607
* 2 yes no no yes | yes no
1608
* yes no no no | - failure E -
1609
* no yes yes yes | - failure A -
1610
* 3 no yes yes no | no yes
1611
* no yes no yes | - failure D -
1612
* no yes no no | - failure F -
1613
* no no yes yes | - failure A -
1614
* no no yes no | - failure B -
1615
* no no no yes | - failure G -
1616
* 4 no no no no | no no
1619
* 1) the rule has been there when the shadow was created and
1620
* has not been removed since then. (Or has been removed and
1622
* 2) the rule has been there when the shadow was created, but
1623
* was removed from the shadow. The target shadow already
1624
* knows that so we only need to remove from the target filter
1625
* to bring the target shadow and the target filter in sync.
1626
* 3) the rule was added during the session. When it was added
1627
* a shadow for the target has also been created to increase
1628
* the refcount on that. We don't know wether the shadow contains
1629
* other changes, but we must reduce the refcount on that shadow.
1630
* 4) the rule is neither in the shadow nor in the filter, we
1631
* issue a warning and do nothing.
1634
* A) a rule can never be in shadow->added and shadow->removed at
1636
* B) a rule can not be in added but not in current
1637
* C) a rule can't be added if it was already in the original filter
1638
* D) a rule can't be in current and also in removed
1639
* E) if a rule is in the original filter but not in current it
1640
* must have been removed
1641
* F) if the rule is in current but not in the original filter, it
1642
* must have been added.
1643
* G) if a rule is in removed, it must have been in the original
1647
r->target->refcount --;
1650
printf("decreased refcount on \"%s\" to %d\n",
1651
r->target->name, r->target->refcount);
1654
if (in_shadow_current) {
1655
if (target_shadow != NULL) {
1656
target_shadow->refcount --;
1659
printf("decreased refcount on shadow of \"%s\" to %d\n",
1660
target_shadow->filter->name, target_shadow->refcount);
1664
if (!in_filter && !in_shadow_current) {
1665
g_warning("rule unknown in context: aborting removal without freeing");
1669
filter_free_rule(r);
1672
* Update dialog if necessary.
1677
ruleset = (shadow != NULL) ? shadow->current : f->ruleset;
1679
if (work_filter == f)
1680
filter_gui_set_ruleset(ruleset);
1681
filter_gui_update_rule_count(f, ruleset);
1687
* filter_remove_rule_from_session:
1689
* Remove rule from a filter shadow. This call will fail
1690
* with an assertion error if the rule has already been
1691
* removed from the shadow or if it never was in the shadow.
1692
* The memory associated with the rule will be freed.
1694
void filter_remove_rule_from_session(filter_t *f, rule_t * const r)
1697
shadow_t *target_shadow;
1700
g_assert(r != NULL);
1701
g_assert(f != NULL);
1704
printf("removing rule in filter: %s -> %s\n",
1705
f->name, filter_rule_to_gchar(r));
1708
* Create a new shadow if necessary.
1710
shadow = shadow_find(f);
1712
shadow = shadow_new(f);
1714
g_assert(g_list_find(shadow->current, r) != NULL);
1716
shadow->current = g_list_remove(shadow->current, r);
1719
* We need to decrease the refcount on the target. We need to do this
1720
* now because soon the rule may be freed and we may not access it
1723
target_shadow = shadow_find(r->target);
1724
if (target_shadow == NULL)
1725
target_shadow = shadow_new(r->target);
1727
target_shadow->refcount --;
1729
printf("decreased refcount on shadow of \"%s\" to %d\n",
1730
target_shadow->filter->name, target_shadow->refcount);
1732
l = g_list_find(shadow->added, r);
1735
* The rule was added only to the shadow and was
1736
* not committed. We removed it from the added list
1737
* and free the ressources.
1740
printf("while removing from %s: removing from added: %s\n",
1741
f->name, filter_rule_to_gchar(r));
1742
shadow->added = g_list_remove(shadow->added, r);
1743
filter_free_rule(r);
1746
* The rule was not added, so it must be existent.
1747
* If it is, we remember it on shadow->removed.
1749
g_assert(g_list_find(shadow->removed, r) == NULL);
1752
printf("while removing from %s: adding to removed: %s\n",
1753
f->name, filter_rule_to_gchar(r));
1755
shadow->removed = g_list_append(shadow->removed, r);
1759
* Update dialog if necessary.
1761
if (work_filter == f)
1762
filter_gui_set_ruleset(shadow->current);
1763
filter_gui_update_rule_count(f, shadow->current);
1769
* filter_replace_rule_in_session:
1771
* Replaces filter rule A with filter rule B in filter . A
1772
* must already be in the shadow and B must not!
1774
* CAUTION: ACTUALLY B MUST NOT BE IN ANY OTHER SEARCH !!!
1776
* The memory for A is freed in the process.
1778
void filter_replace_rule_in_session(filter_t *f,
1779
rule_t * const old_rule, rule_t * const new_rule)
1784
shadow_t *target_shadow;
1786
g_assert(old_rule != new_rule);
1787
g_assert(old_rule != NULL);
1788
g_assert(new_rule != NULL);
1791
* Create a new shadow if necessary.
1793
shadow = shadow_find(f);
1795
shadow = shadow_new(f);
1798
* Find the list node where we have to replace the
1801
filter = g_list_find(shadow->current, old_rule);
1802
g_assert(filter != NULL);
1804
if (gui_debug >= 4) {
1805
gchar * f1 = g_strdup(filter_rule_to_gchar(old_rule));
1806
gchar * f2 = g_strdup(filter_rule_to_gchar(new_rule));
1808
printf("replacing rules (old <- new): %s <- %s\n", f1, f2);
1815
* In any case we have to reduce the refcount on the old rule's
1818
target_shadow = shadow_find(old_rule->target);
1819
if (target_shadow == NULL)
1820
target_shadow = shadow_new(old_rule->target);
1822
target_shadow->refcount --;
1824
printf("decreased refcount on shadow of \"%s\" to %d\n",
1825
target_shadow->filter->name, target_shadow->refcount);
1828
* Find wether the node to be replaced is in shadow->added.
1829
* If so, we may free the memory of the old rule.
1831
added = g_list_find(shadow->added, old_rule);
1833
if (added != NULL) {
1835
* If it was added, then free and remove the rule.
1837
shadow->added = g_list_remove(shadow->added, old_rule);
1838
filter_free_rule(old_rule);
1841
* If the filter was not added, then it must be marked
1842
* for begin removed.
1844
shadow->removed = g_list_append(shadow->removed, old_rule);
1848
* The new rule can't be in the original filter, so we mark it
1851
shadow->added = g_list_append(shadow->added, new_rule);
1852
set_flags(new_rule->flags, RULE_FLAG_SHADOW);
1855
* And we also need to increase the refcount on the new rule's
1858
target_shadow = shadow_find(new_rule->target);
1859
if (target_shadow == NULL)
1860
target_shadow = shadow_new(new_rule->target);
1862
target_shadow->refcount ++;
1864
printf("increased refcount on shadow of \"%s\" to %d\n",
1865
target_shadow->filter->name, target_shadow->refcount);
1868
* In shadow->current we just replace the rule.
1870
filter->data = new_rule;
1873
* Update dialog if necessary.
1875
if (work_filter == f)
1876
filter_gui_set_ruleset(shadow->current);
1882
* filter_adapt_order:
1884
* Reorders the filter according to the order in the user's
1885
* table in the gui. This should only be used after the
1886
* user has reordered the table. It can not properly cope
1887
* with added or deleted items. This will also only work
1888
* if a filter is currently being displayed in the table.
1889
* If the filter dialog has not been initialized or not
1890
* filter is currently worked on, it will silently fail.
1892
void filter_adapt_order(void)
1894
GList *neworder = NULL;
1899
if (!work_filter || filter_dialog == NULL)
1902
clist = GTK_CLIST(lookup_widget(filter_dialog, "clist_filter_rules"));
1905
* Create a new shadow if necessary.
1907
shadow = shadow_find(work_filter);
1909
shadow = shadow_new(work_filter);
1912
* Assumption: every rule in shadow->current is also
1913
* bound to a row in the filter table. So we can free
1914
* this list and rebuild it in the right order from the
1917
g_list_free(shadow->current);
1919
for (row = 0; row < clist->rows; row ++) {
1922
f = gtk_clist_get_row_data(clist, row);
1923
g_assert(f != NULL);
1925
neworder = g_list_append(neworder, f);
1928
shadow->current = neworder;
1932
#define MATCH_RULE(filter, r, res) \
1933
(res)->props_set ++; \
1934
(r)->match_count ++; \
1936
(r)->target->match_count ++; \
1938
if (gui_debug >= 10) \
1939
printf("matched rule: %s\n", filter_rule_to_gchar((r)));
1944
* returns the number of properties set with this filter chain.
1945
* a property which was already set is not set again. The res
1946
* argument is changed depending on the rules that match.
1948
static int filter_apply
1949
(filter_t *filter, struct record *rec, filter_result_t *res)
1954
gint prop_count = 0;
1955
gboolean do_abort = FALSE;
1957
g_assert(filter != NULL);
1958
g_assert(rec != NULL);
1959
g_assert(res != NULL);
1962
* We only try to prevent circles or the filter is inactive.
1964
if ((filter->visited == TRUE) || !filter_is_active(filter)) {
1968
filter->visited = TRUE;
1970
list = filter->ruleset;
1972
namelen = strlen(rec->name);
1973
l_name = g_malloc(sizeof(char) * (namelen + 1));
1974
strlower(l_name, rec->name);
1976
list = g_list_first(list);
1977
while ((list != NULL) && (res->props_set < MAX_FILTER_PROP) && !do_abort) {
1981
gboolean match = FALSE;
1983
r = (rule_t *)list->data;
1984
if (gui_debug >= 10)
1985
printf("trying to match against: %s\n", filter_rule_to_gchar(r));
1987
if (RULE_IS_ACTIVE(r)) {
1993
switch (r->u.text.type) {
1994
case RULE_TEXT_EXACT:
1995
if (strcmp(r->u.text.case_sensitive ? rec->name : l_name,
1996
r->u.text.match) == 0)
1999
case RULE_TEXT_PREFIX:
2000
if (strncmp(r->u.text.case_sensitive ? rec->name : l_name,
2001
r->u.text.match, r->u.text.matchlen) == 0)
2004
case RULE_TEXT_WORDS: /* Contains ALL the words */
2007
gboolean failed = FALSE;
2010
l = g_list_first(r->u.text.u.words);
2015
pattern_qsearch((cpattern_t *)l->data,
2016
r->u.text.case_sensitive ? rec->name : l_name,
2017
0, 0, qs_any) == NULL
2025
case RULE_TEXT_SUFFIX:
2026
n = r->u.text.matchlen;
2028
&& strcmp((r->u.text.case_sensitive
2029
? rec->name : l_name) + namelen
2030
- n, r->u.text.match) == 0)
2033
case RULE_TEXT_SUBSTR:
2035
pattern_qsearch(r->u.text.u.pattern,
2036
r->u.text.case_sensitive ? rec->name : l_name,
2037
0, 0, qs_any) != NULL
2041
case RULE_TEXT_REGEXP:
2042
if ((i = regexec(r->u.text.u.re, rec->name,
2045
if (i == REG_ESPACE)
2046
g_warning("regexp memory overflow");
2049
g_error("Unknown text rule type: %d",
2054
if ((rec->results_set->ip & r->u.ip.mask) == r->u.ip.addr)
2058
if (rec->size >= r->u.size.lower &&
2059
rec->size <= r->u.size.upper)
2063
if (rec->sha1 == r->u.sha1.hash)
2065
else if ((rec->sha1 != NULL) && r->u.sha1.hash != NULL)
2066
if (memcmp(rec->sha1, r->u.sha1.hash, SHA1_RAW_SIZE) == 0)
2071
gboolean stable_match;
2072
gboolean busy_match;
2073
gboolean push_match;
2076
((r->u.flag.busy == RULE_FLAG_SET) &&
2077
(rec->results_set->status & ST_BUSY)) ||
2078
((r->u.flag.busy == RULE_FLAG_UNSET) &&
2079
!(rec->results_set->status & ST_BUSY)) ||
2080
(r->u.flag.busy == RULE_FLAG_IGNORE);
2083
((r->u.flag.push == RULE_FLAG_SET) &&
2084
(rec->results_set->status & ST_FIREWALL)) ||
2085
((r->u.flag.push == RULE_FLAG_UNSET) &&
2086
!(rec->results_set->status & ST_FIREWALL)) ||
2087
(r->u.flag.push == RULE_FLAG_IGNORE);
2090
((r->u.flag.stable == RULE_FLAG_SET) &&
2091
(rec->results_set->status & ST_UPLOADED)) ||
2092
((r->u.flag.stable == RULE_FLAG_UNSET) &&
2093
!(rec->results_set->status & ST_UPLOADED)) ||
2094
(r->u.flag.stable == RULE_FLAG_IGNORE);
2096
match = stable_match && busy_match && push_match;
2101
gboolean display_match;
2102
gboolean download_match;
2105
(r->u.state.display == FILTER_PROP_STATE_IGNORE) ||
2106
(res->props[FILTER_PROP_DISPLAY].state
2107
== r->u.state.display);
2110
(r->u.state.download == FILTER_PROP_STATE_IGNORE) ||
2111
(res->props[FILTER_PROP_DOWNLOAD].state
2112
== r->u.state.download);
2114
match = display_match && download_match;
2118
g_error("Unknown rule type: %d", r->type);
2123
* If negate is set, we invert the meaning of match.
2126
if (RULE_IS_NEGATED(r) && RULE_IS_ACTIVE(r))
2130
* Try to match the builtin rules, but don't act on matches
2131
* that would change a result property that was already
2135
if (r->target == filter_return) {
2138
r->target->match_count ++;
2140
if ((r->target == filter_show)) {
2141
if (!res->props[FILTER_PROP_DISPLAY].state) {
2143
res->props[FILTER_PROP_DISPLAY].state =
2144
FILTER_PROP_STATE_DO;
2146
MATCH_RULE(filter, r, res);
2149
if (r->target == filter_drop) {
2150
if (!res->props[FILTER_PROP_DISPLAY].state) {
2152
res->props[FILTER_PROP_DISPLAY].state =
2153
FILTER_PROP_STATE_DONT;
2154
res->props[FILTER_PROP_DISPLAY].user_data =
2155
GINT_TO_POINTER(RULE_IS_SOFT(r) ? 1 : 0);
2157
MATCH_RULE(filter, r, res);
2160
if (r->target == filter_download){
2161
if (!res->props[FILTER_PROP_DOWNLOAD].state) {
2163
res->props[FILTER_PROP_DOWNLOAD].state =
2164
FILTER_PROP_STATE_DO;
2166
MATCH_RULE(filter, r, res);
2169
if (r->target == filter_nodownload) {
2170
if (!res->props[FILTER_PROP_DOWNLOAD].state) {
2172
res->props[FILTER_PROP_DOWNLOAD].state =
2173
FILTER_PROP_STATE_DONT;
2175
MATCH_RULE(filter, r, res);
2179
* We have a matched rule the target is not a builtin
2180
* rule, so it must be a subchain. We gosub.
2182
prop_count += filter_apply(r->target, rec, res);
2189
list = g_list_next(list);
2191
G_FREE_NULL(l_name);
2193
filter->visited = FALSE;
2194
filter->fail_count += MAX_FILTER_PROP - prop_count;
2195
filter->match_count += prop_count;
2204
* Check a particular record against the search filter and the global
2205
* filters. Returns a filter_property_t array with MAX_FILTER_PROP
2206
* rows. This must be freed with filter_free_properties.
2208
filter_result_t *filter_record(search_t *sch, record_t *rec)
2211
filter_result_t *result;
2214
g_assert(sch != NULL);
2215
g_assert(rec != NULL);
2218
* Initialize all properties with FILTER_PROP_STATE_UNKNOWN and
2219
* the props_set count with 0;
2221
result = g_new0(filter_result_t, 1);
2224
((sch->filter->ruleset != NULL) &&
2225
filter_is_active(sch->filter)) ||
2226
((filter_global_pre->ruleset != NULL) &&
2227
filter_is_active(filter_global_pre)) ||
2228
((filter_global_post->ruleset != NULL) &&
2229
filter_is_active(sch->filter));
2231
filter_apply(filter_global_pre, rec, result);
2234
* If not decided check if the filters for this search apply.
2236
if (result->props_set < MAX_FILTER_PROP)
2237
filter_apply(sch->filter, rec, result);
2240
* If it has not yet been decided, try the global filter
2242
if (result->props_set < MAX_FILTER_PROP)
2243
filter_apply(filter_global_post, rec, result);
2245
/* FIXME: this does no longer give useful output
2246
if (gui_debug >= 5) {
2247
printf("result %d for search \"%s\" matching \"%s\" (%s)\n",
2248
r, sch->query, rec->name,
2249
filtered ? "filtered" : "unfiltered");
2254
* Set the defaults for the props that are still in UNKNOWN state.
2256
for (i = 0; i < MAX_FILTER_PROP; i ++) {
2258
case FILTER_PROP_DISPLAY:
2259
if (!result->props[i].state) {
2260
result->props[i].state =
2261
FILTER_PROP_STATE_DO;
2262
result->props_set ++;
2265
case FILTER_PROP_DOWNLOAD:
2266
if (!result->props[i].state) {
2267
result->props[i].state =
2268
FILTER_PROP_STATE_DONT;
2269
result->props_set ++;
2283
* Free global filters and save state.
2285
void filter_shutdown(void)
2290
printf("shutting down filters\n");
2293
* It is important that all searches have already been closed.
2294
* Since it is not allowd to use a bound filter as a target,
2295
* a bound filter will always have a refcount of 0. So it is
2296
* not a problem just closing the searches.
2297
* But for the free filters, we have to prune all rules before
2298
* we may free the filers, because we have to reduce the
2299
* refcount on every filter to 0 before we are allowed to free it.
2301
for (f = filters; f != NULL; f = f->next) {
2302
filter_t *filter = (filter_t*) f->data;
2303
GList *copy = g_list_copy(filter->ruleset);
2306
* Since filter_remove_rule modifies filter->ruleset, we
2307
* have to copy the ruleset before we start puring.
2311
* We don't want to create any shadows again since a
2312
* shadowed filter may not be freed, so we use
2313
* filter_remove_rule.
2316
G_LIST_FOREACH_SWAPPED(copy, filter_remove_rule, filter);
2321
* Now we remove the filters. So we may not traverse. We just
2322
* free the first filter until none is left. This will also
2323
* clean up the builtin filters (filter_drop/show) and the
2326
for (f = filters; f != NULL; f = filters)
2327
filter_free(f->data);
2335
* Initialize global filters.
2337
void filter_init(void)
2339
filter_global_pre = filter_new("Global (pre)");
2340
filter_global_post = filter_new("Global (post)");
2341
filter_show = filter_new("DISPLAY");
2342
filter_drop = filter_new("DON'T DISPLAY");
2343
filter_download = filter_new("DOWNLOAD");
2344
filter_nodownload = filter_new("DON'T DOWNLOAD");
2345
filter_return = filter_new("RETURN");
2347
filters = g_list_append(filters, filter_global_pre);
2348
filters = g_list_append(filters, filter_global_post);
2349
filters = g_list_append(filters, filter_show);
2350
filters = g_list_append(filters, filter_drop);
2351
filters = g_list_append(filters, filter_download);
2352
filters = g_list_append(filters, filter_nodownload);
2353
filters = g_list_append(filters, filter_return);
2355
filters_current = g_list_copy(filters);
2357
popup_filter_rule = create_popup_filter_rule();
2363
* filter_update_targets:
2365
* Trigger a rebuild of the target combos.
2367
void filter_update_targets(void)
2369
filter_gui_rebuild_target_combos(filters_current);
2377
* Periodically update the filter display with current data
2379
void filter_timer(void)
2381
filter_gui_update_filter_stats();
2382
filter_gui_update_rule_stats();
2388
* filter_rule_reset_stats:
2390
* Reset the rule stats for a given rule.
2392
inline void filter_rule_reset_stats(rule_t *rule)
2394
g_assert(rule != NULL);
2396
rule->match_count = rule->fail_count = 0;
2402
* filter_reset_stats:
2404
* Reset the stats for a given filter.
2406
inline void filter_reset_stats(filter_t *filter)
2408
g_assert(filter != NULL);
2410
filter->match_count = filter->fail_count = 0;
2416
* filter_set_enabled:
2418
* Change the "enabled" flag of a filter.
2420
void filter_set_enabled(filter_t *filter, gboolean active)
2423
static gboolean locked = FALSE;
2425
g_assert(filter != NULL);
2432
shadow = shadow_find(filter);
2434
shadow = shadow_new(filter);
2437
set_flags(shadow->flags, FILTER_FLAG_ACTIVE);
2439
clear_flags(shadow->flags, FILTER_FLAG_ACTIVE);
2442
filter_gui_filter_set_enabled(work_filter, active);
2448
* filter_free_properties:
2450
* Free a filter_result returned by filter_record
2451
* after it has been processed.
2453
void filter_free_result(filter_result_t *res)
2457
g_assert(res != NULL);
2460
* Since every property type can need a special handling
2461
* for freeing the user data, we handle that here. Currently
2462
* no property needs this.
2464
for (i = 0; i < MAX_FILTER_PROP; i ++) {
2466
case FILTER_PROP_DISPLAY:
2468
case FILTER_PROP_DOWNLOAD:
2471
g_assert_not_reached();
2479
* filter_is_valid_in_session:
2481
* Checks wether a filter is existant in a filter editing session.
2482
* If no session is started it checks wether the filter is valid
2483
* in outside the session.
2485
gboolean filter_is_valid_in_session(filter_t *f)
2490
return g_list_find(filters_current, f) != NULL;
2494
* filter_find_by_name_in_session:
2496
* Returns the filter with the given name in the session if it
2497
* exists, otherwise returns NULL. If no session is started, it
2498
* looks in the normal filter list.
2500
filter_t *filter_find_by_name_in_session(gchar *name)
2504
for (l = filters_current; l != NULL; l = l->next) {
2505
filter_t *filter = (filter_t *) l->data;
2507
if (strcmp(filter->name, name) == 0)
2513
gboolean filter_is_global(filter_t *f)
2515
return ((f == filter_global_pre) || (f == filter_global_post));
2518
gboolean filter_is_builtin(filter_t *f)
2520
return ((f == filter_show) || (f == filter_drop) ||
2521
(f == filter_download) || (f == filter_nodownload) ||
2522
(f == filter_return));
2525
inline filter_t *filter_get_drop_target(void)
2530
inline filter_t *filter_get_show_target(void)
2535
inline filter_t *filter_get_download_target(void)
2537
return filter_download;
2540
inline filter_t *filter_get_nodownload_target(void)
2542
return filter_nodownload;
2545
inline filter_t *filter_get_return_target(void)
2547
return filter_return;
2550
inline filter_t *filter_get_global_pre(void)
2552
return filter_global_pre;
2555
inline filter_t *filter_get_global_post(void)
2557
return filter_global_post;
2561
* Adds a drop SHA1 rule to specified filter.
2563
void filter_add_drop_sha1_rule(record_t *rec, filter_t *filter)
2567
g_assert(rec != NULL);
2568
g_assert(filter != NULL);
2570
rule = filter_new_sha1_rule(rec->sha1, rec->name,
2571
filter_get_drop_target(), RULE_FLAG_ACTIVE);
2573
filter_append_rule(filter, rule);
2577
* Adds a drop filename rule to specified filter.
2579
void filter_add_drop_name_rule(record_t *rec, filter_t *filter)
2583
g_assert(rec != NULL);
2584
g_assert(filter != NULL);
2586
rule = filter_new_text_rule(rec->name, RULE_TEXT_EXACT, TRUE,
2587
filter_get_drop_target(), RULE_FLAG_ACTIVE);
2589
filter_append_rule(filter, rule);
2593
* Adds a drop host rule to specified filter.
2595
void filter_add_drop_host_rule(record_t *rec, filter_t *filter)
2599
g_assert(rec != NULL);
2600
g_assert(filter != NULL);
2602
rule = filter_new_ip_rule(rec->results_set->ip, 0xFFFFFFFF,
2603
filter_get_drop_target(), RULE_FLAG_ACTIVE);
2605
filter_append_rule(filter, rule);
2609
* Adds a download SHA1 rule to specified filter.
2611
void filter_add_download_sha1_rule(record_t *rec, filter_t *filter)
2613
g_assert(rec != NULL);
2614
g_assert(filter != NULL);
2619
rule = filter_new_sha1_rule(rec->sha1, rec->name,
2620
filter_get_download_target(), RULE_FLAG_ACTIVE);
2622
filter_append_rule(filter, rule);
2627
* Adds a download filename rule to specified filter.
2629
void filter_add_download_name_rule(record_t *rec, filter_t *filter)
2633
g_assert(rec != NULL);
2634
g_assert(filter != NULL);
2636
rule = filter_new_text_rule(rec->name, RULE_TEXT_EXACT, TRUE,
2637
filter_get_download_target(), RULE_FLAG_ACTIVE);
2639
filter_append_rule(filter, rule);