~ubuntu-branches/ubuntu/karmic/gtk-gnutella/karmic

« back to all changes in this revision

Viewing changes to src/filter.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Kleineidam
  • Date: 2004-05-22 15:26:55 UTC
  • Revision ID: james.westby@ubuntu.com-20040522152655-lyi6iaswmy4hq4wy
Tags: upstream-0.93.3.0
ImportĀ upstreamĀ versionĀ 0.93.3.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: filter.c,v 1.68 2004/01/15 23:51:48 wyldfire Exp $
 
3
 *
 
4
 * Copyright (c) 2001-2003, Raphael Manfredi, Richard Eckart
 
5
 *
 
6
 * GUI filtering functions.
 
7
 *
 
8
 *----------------------------------------------------------------------
 
9
 * This file is part of gtk-gnutella.
 
10
 *
 
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.
 
15
 *
 
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.
 
20
 *
 
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
 
23
 *  Foundation, Inc.:
 
24
 *      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
25
 *----------------------------------------------------------------------
 
26
 */
 
27
 
 
28
#include <sys/types.h>
 
29
#include <netinet/in.h>
 
30
#include <arpa/inet.h>
 
31
 
 
32
#include "filter.h"
 
33
#include "filter_gui.h"
 
34
#include "search_gui.h"
 
35
#include "gtk-missing.h"
 
36
 
 
37
#ifdef USE_GTK2
 
38
#include "interface-glade2.h"
 
39
#else
 
40
#include "interface-glade1.h"
 
41
#endif
 
42
 
 
43
#include "override.h"           /* Must be the last header included */
 
44
 
 
45
RCSID("$Id: filter.c,v 1.68 2004/01/15 23:51:48 wyldfire Exp $");
 
46
 
 
47
/*
 
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.
 
50
 */
 
51
#define FILTER_HIDE_ON_CLOSE
 
52
 
 
53
typedef struct shadow {
 
54
    filter_t *filter;
 
55
    GList *current;
 
56
    GList *removed;
 
57
    GList *added;
 
58
    gint32 refcount;
 
59
    guint16 flags;
 
60
    guint32 match_count;
 
61
    guint32 fail_count;
 
62
} shadow_t;
 
63
 
 
64
 
 
65
 
 
66
/*
 
67
 * Private functions prototypes
 
68
 */
 
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);
 
76
 
 
77
void dump_ruleset(GList *ruleset);
 
78
void dump_filter(filter_t *filter);
 
79
void dump_shadow(shadow_t *shadow);
 
80
 
 
81
/*
 
82
 * Public variables
 
83
 */
 
84
filter_t *work_filter = NULL;
 
85
 
 
86
/*
 
87
 * Private variables
 
88
 */
 
89
static GList *shadow_filters = NULL;
 
90
static gchar f_tmp[1024];
 
91
static GList *filters_added = NULL;
 
92
static GList *filters_removed = NULL;
 
93
 
 
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;
 
100
 
 
101
/* global filters */
 
102
filter_t *filter_global_pre = NULL;
 
103
filter_t *filter_global_post = NULL;
 
104
 
 
105
/* not static because needed in search_xml. */
 
106
GList *filters = NULL;
 
107
GList *filters_current = NULL;
 
108
 
 
109
 
 
110
/***
 
111
 *** Implementation
 
112
 ***/
 
113
void dump_ruleset(GList *ruleset)
 
114
{
 
115
    GList *r;
 
116
    gint n = 0;
 
117
 
 
118
    for (r = ruleset; r != NULL; r=r->next)
 
119
        printf("       rule %3d : %s\n", n, filter_rule_to_gchar(r->data));
 
120
}
 
121
 
 
122
void dump_filter(filter_t *filter)
 
123
{
 
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);
 
129
}
 
130
 
 
131
void dump_shadow(shadow_t *shadow)
 
132
{
 
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);
 
138
    printf("  Added:\n");
 
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);
 
146
}
 
147
 
 
148
 
 
149
 
 
150
/*
 
151
 * shadow_filter_eq:
 
152
 *
 
153
 * Comparator function to match a shadow and a filter.
 
154
 */
 
155
static gint shadow_filter_eq(const shadow_t *a, const filter_t *b)
 
156
{
 
157
    if((a != NULL) && (b != NULL)) {
 
158
        if(a->filter == b)
 
159
            return 0;
 
160
    }
 
161
 
 
162
    return 1;
 
163
}
 
164
 
 
165
 
 
166
 
 
167
/*
 
168
 * shadow_find:
 
169
 *
 
170
 * Get the shadow for the given filter. Returns NULL if the filter
 
171
 * does not have a shadow yet.
 
172
 */
 
173
static shadow_t *shadow_find(filter_t *f)
 
174
{
 
175
    GList * l;
 
176
 
 
177
    g_assert(f != NULL);
 
178
 
 
179
    l = g_list_find_custom
 
180
        (shadow_filters, f, (GCompareFunc) shadow_filter_eq);
 
181
 
 
182
    if (l != NULL) {
 
183
        if (gui_debug >= 6)
 
184
            printf("shadow found for: %s\n", f->name);
 
185
        return l->data;
 
186
    } else {
 
187
        if (gui_debug >= 6)
 
188
            printf("no shadow found for: %s\n", f->name);
 
189
        return NULL;
 
190
    }
 
191
}
 
192
 
 
193
 
 
194
 
 
195
/*
 
196
 * shadow_new:
 
197
 *
 
198
 * Creates a new shadow for a given filter and registers it with
 
199
 * our current shadow list.
 
200
 */
 
201
static shadow_t *shadow_new(filter_t *f)
 
202
{
 
203
    shadow_t *shadow;
 
204
 
 
205
    g_assert(f != NULL);
 
206
    g_assert(f->name != NULL);
 
207
 
 
208
    if (gui_debug >= 6)
 
209
        printf("creating shadow for: %s\n", f->name);
 
210
 
 
211
    shadow = g_new0(shadow_t, 1);
 
212
 
 
213
    shadow->filter   = f;
 
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;
 
219
 
 
220
    shadow_filters = g_list_append(shadow_filters, shadow);
 
221
 
 
222
    return shadow;
 
223
}
 
224
 
 
225
 
 
226
 
 
227
/*
 
228
 * shadow_cancel:
 
229
 *
 
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 
 
235
 * associated filter.
 
236
 */
 
237
static void shadow_cancel(shadow_t *shadow)
 
238
{
 
239
    GList *r;
 
240
 
 
241
    g_assert(shadow != NULL);
 
242
    g_assert(shadow->filter != NULL);
 
243
 
 
244
    if (gui_debug >= 6)
 
245
        printf("cancel shadow for filter: %s\n", shadow->filter->name);
 
246
 
 
247
    for (r = shadow->added; r != NULL; r = r->next)
 
248
        filter_free_rule(r->data);
 
249
 
 
250
    /* 
 
251
     * Since we cancel the shadow, we also free the added,
 
252
     * removed and current lists now. Then we remove the shadow
 
253
     * kill it also.
 
254
     */
 
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;
 
259
 
 
260
    shadow_filters = g_list_remove(shadow_filters, shadow);
 
261
    G_FREE_NULL(shadow);
 
262
}
 
263
 
 
264
 
 
265
 
 
266
/*
 
267
 * shadow_commit:
 
268
 *
 
269
 * Commit all the changes for a given shadow and then forget and free
 
270
 * it.
 
271
 */
 
272
static void shadow_commit(shadow_t *shadow)
 
273
{
 
274
    GList *f;
 
275
    filter_t *realf;
 
276
 
 
277
    g_assert(shadow != NULL);
 
278
    g_assert(shadow->filter != NULL); 
 
279
 
 
280
    realf = shadow->filter;
 
281
 
 
282
    if (gui_debug >= 6) {
 
283
        printf("committing shadow for filter:\n");
 
284
        dump_shadow(shadow);
 
285
    }
 
286
 
 
287
    /*
 
288
     * Free memory for all removed rules
 
289
     */
 
290
    for (f = shadow->removed; f != NULL; f = f->next)
 
291
        filter_free_rule(f->data);
 
292
 
 
293
    /*
 
294
     * Remove the SHADOW flag from all new rules.
 
295
     */
 
296
    for (f = shadow->added; f != NULL; f = f->next)
 
297
        clear_flags(((rule_t*) f->data)->flags, RULE_FLAG_SHADOW);
 
298
 
 
299
    /* 
 
300
     * We also free the memory of the filter->ruleset GList.
 
301
     * We don't need them anymore.
 
302
     */
 
303
    g_list_free(shadow->filter->ruleset);
 
304
 
 
305
    /*
 
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.
 
310
     */
 
311
    shadow->filter->ruleset = shadow->current;
 
312
 
 
313
    /*
 
314
     * Not forgetting to update the refcount. There is a chance
 
315
     * that this shadow only existed because of a change in the
 
316
     * refcount.
 
317
     */
 
318
    shadow->filter->refcount = shadow->refcount;
 
319
 
 
320
    shadow->filter->flags = shadow->flags; 
 
321
    
 
322
    /* 
 
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.
 
327
     */
 
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); 
 
333
    G_FREE_NULL(shadow);
 
334
 
 
335
    if (gui_debug >= 6) {
 
336
        printf("after commit filter looks like this\n");
 
337
        dump_filter(realf);
 
338
    }
 
339
}
 
340
 
 
341
 
 
342
 
 
343
/*
 
344
 * filter_refresh_display:
 
345
 *
 
346
 * Regenerates the filter tree and rules display from after a apply/revert.
 
347
 */
 
348
static void filter_refresh_display(GList *filter_list)
 
349
{
 
350
    GList *l;
 
351
 
 
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;
 
356
        shadow_t *shadow;
 
357
        GList *ruleset;
 
358
        gboolean enabled;
 
359
    
 
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);
 
365
                        
 
366
        filter_gui_filter_add(filter, ruleset);
 
367
        filter_gui_filter_set_enabled(filter, enabled);
 
368
    }
 
369
    filter_gui_thaw_filters();
 
370
}
 
371
 
 
372
 
 
373
 
 
374
/*
 
375
 * filter_open_dialog:
 
376
 *
 
377
 * Open and initialize the filter dialog.
 
378
 */
 
379
void filter_open_dialog(void) {
 
380
    search_t *current_search;
 
381
 
 
382
    current_search = search_gui_get_current_search();
 
383
 
 
384
    if (filter_dialog == NULL) {
 
385
        filter_dialog = filter_gui_create_dlg_filters();
 
386
        g_assert(filter_dialog != NULL);
 
387
   
 
388
        filter_gui_init();
 
389
        filter_refresh_display(filters_current);
 
390
    }
 
391
    
 
392
    if (current_search != NULL) {
 
393
        filter_set(current_search->filter);
 
394
    } else {
 
395
        filter_set(NULL);
 
396
    }
 
397
 
 
398
    filter_gui_show_dialog();
 
399
}
 
400
 
 
401
 
 
402
 
 
403
/*
 
404
 * filter_close_dialog:
 
405
 *
 
406
 * Close the filter dialog. If commit is TRUE the changes
 
407
 * are committed, otherwise dropped.
 
408
 */
 
409
void filter_close_dialog(gboolean commit)
 
410
{
 
411
    if (commit) {
 
412
        filter_apply_changes();
 
413
    } else
 
414
        filter_revert_changes();
 
415
 
 
416
    if (filter_dialog != NULL) {
 
417
        gint32 coord[4] = {0, 0, 0, 0};
 
418
 
 
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]);
 
421
 
 
422
        gui_prop_set_guint32(PROP_FILTER_DLG_COORDS, (guint32 *) coord, 0, 4);
 
423
        
 
424
        filter_main_divider_pos =
 
425
            gtk_paned_get_position
 
426
                (GTK_PANED(lookup_widget(filter_dialog, "hpaned_filter_main")));
 
427
 
 
428
#ifdef FILTER_HIDE_ON_CLOSE        
 
429
        gtk_widget_hide(filter_dialog);
 
430
#else
 
431
        gtk_object_destroy(GTK_OBJECT(filter_dialog));
 
432
        filter_dialog = NULL;
 
433
#endif /* FILTER_HIDE_ON_CLOSE */
 
434
    }
 
435
}
 
436
 
 
437
 
 
438
 
 
439
/*
 
440
 * filter_duplicate_rule:
 
441
 *
 
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.
 
445
 */
 
446
rule_t *filter_duplicate_rule(rule_t *r)
 
447
{
 
448
    g_assert(r != NULL);
 
449
 
 
450
    switch(r->type) {
 
451
    case RULE_TEXT:
 
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);
 
455
    case RULE_IP:
 
456
        return filter_new_ip_rule
 
457
            (r->u.ip.addr, r->u.ip.mask, r->target, r->flags);
 
458
    case RULE_SIZE:
 
459
        return filter_new_size_rule
 
460
            (r->u.size.lower, r->u.size.upper, r->target, r->flags);
 
461
    case RULE_JUMP:
 
462
        return filter_new_jump_rule(r->target, r->flags);
 
463
    case RULE_SHA1:
 
464
        return filter_new_sha1_rule
 
465
            (r->u.sha1.hash, r->u.sha1.filename, r->target, r->flags);
 
466
    case RULE_FLAG:
 
467
        return filter_new_flag_rule
 
468
            (r->u.flag.stable, r->u.flag.busy, r->u.flag.push, 
 
469
            r->target, r->flags);
 
470
    case RULE_STATE:
 
471
        return filter_new_state_rule
 
472
            (r->u.state.display, r->u.state.download, r->target, r->flags);
 
473
    default:
 
474
        g_error("filter_duplicate_rule: unknown rule type: %d", r->type);
 
475
        return NULL;
 
476
    }
 
477
}
 
478
 
 
479
 
 
480
 
 
481
rule_t *filter_new_text_rule(gchar *match, gint type, 
 
482
    gboolean case_sensitive, filter_t *target, guint16 flags)
 
483
{
 
484
        rule_t *r;
 
485
    gchar *buf;
 
486
 
 
487
    g_assert(match != NULL);
 
488
    g_assert(target != NULL);
 
489
 
 
490
        r = g_new0(rule_t, 1);
 
491
 
 
492
        r->type                  = RULE_TEXT;
 
493
    r->flags                 = flags;
 
494
    r->target                = target;
 
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);
 
500
 
 
501
    if (!r->u.text.case_sensitive)
 
502
        strlower(r->u.text.match, r->u.text.match);
 
503
 
 
504
    buf = g_strdup(r->u.text.match);
 
505
 
 
506
        if (r->u.text.type == RULE_TEXT_WORDS) {
 
507
                gchar *s;
 
508
                GList *l = NULL;
 
509
 
 
510
                for (s = strtok(buf, " \t\n"); s; s = strtok(NULL, " \t\n"))
 
511
                        l = g_list_append(l, pattern_compile(s));
 
512
 
 
513
                r->u.text.u.words = l;
 
514
        } else 
 
515
    if (r->u.text.type == RULE_TEXT_REGEXP) {
 
516
                int err;
 
517
                regex_t *re;
 
518
 
 
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));
 
522
 
 
523
                if (err) {
 
524
                        gchar regbuf[1000];
 
525
                        regerror(err, re, regbuf, sizeof(regbuf));
 
526
 
 
527
                        g_warning(
 
528
                "problem in regular expression: %s"
 
529
                                "; falling back to substring match", buf);
 
530
 
 
531
                        r->u.text.type = RULE_TEXT_SUBSTR;
 
532
            G_FREE_NULL(re);
 
533
                } else {
 
534
                        r->u.text.u.re = re;
 
535
                }
 
536
        }
 
537
 
 
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);
 
541
 
 
542
    G_FREE_NULL(buf);
 
543
 
 
544
    return r;
 
545
}
 
546
 
 
547
 
 
548
 
 
549
rule_t *filter_new_ip_rule
 
550
    (guint32 addr, guint32 mask, filter_t *target, guint16 flags)
 
551
{
 
552
        rule_t *r;
 
553
 
 
554
    g_assert(target != NULL);
 
555
 
 
556
        r = g_new0(rule_t, 1);
 
557
 
 
558
        r->type = RULE_IP;
 
559
 
 
560
        r->u.ip.addr  = addr;
 
561
        r->u.ip.mask  = mask;
 
562
        r->u.ip.addr &= r->u.ip.mask;
 
563
    r->target     = target;
 
564
    r->flags      = flags;
 
565
    set_flags(r->flags, RULE_FLAG_VALID);
 
566
 
 
567
    return r;
 
568
}
 
569
 
 
570
 
 
571
 
 
572
rule_t *filter_new_size_rule
 
573
    (size_t lower, size_t upper, filter_t *target, guint16 flags)
 
574
{
 
575
        rule_t *f;
 
576
 
 
577
    g_assert(target != NULL);
 
578
 
 
579
    f = g_new0(rule_t, 1);
 
580
 
 
581
    f->type = RULE_SIZE;
 
582
 
 
583
    if (lower > upper) {
 
584
        f->u.size.lower = upper;
 
585
        f->u.size.upper = lower;
 
586
    } else {
 
587
        f->u.size.lower = lower;
 
588
        f->u.size.upper = upper;
 
589
    }
 
590
 
 
591
        f->target = target;
 
592
    f->flags  = flags;
 
593
    set_flags(f->flags, RULE_FLAG_VALID);
 
594
 
 
595
    return f;
 
596
}
 
597
 
 
598
 
 
599
 
 
600
 
 
601
rule_t *filter_new_jump_rule(filter_t *target, guint16 flags)
 
602
{
 
603
        rule_t *f;
 
604
 
 
605
    g_assert(target != NULL);
 
606
 
 
607
    f = g_new0(rule_t, 1);
 
608
 
 
609
    f->type = RULE_JUMP;
 
610
 
 
611
        f->target = target;
 
612
    f->flags  = flags;
 
613
    set_flags(f->flags, RULE_FLAG_VALID);
 
614
 
 
615
    return f;
 
616
}
 
617
 
 
618
 
 
619
 
 
620
 
 
621
rule_t *filter_new_sha1_rule
 
622
    (gchar *sha1, gchar *filename, filter_t *target, guint16 flags)
 
623
{
 
624
        rule_t *f;
 
625
 
 
626
    g_assert(target != NULL);
 
627
    g_assert(filename != NULL);
 
628
 
 
629
    f = g_new0(rule_t, 1);
 
630
 
 
631
    f->type = RULE_SHA1;
 
632
 
 
633
        f->target = target;
 
634
    if (sha1 != NULL)
 
635
        f->u.sha1.hash = g_memdup(sha1, SHA1_RAW_SIZE);
 
636
    f->u.sha1.filename = g_strdup(filename);
 
637
    f->flags  = flags;
 
638
    set_flags(f->flags, RULE_FLAG_VALID);
 
639
 
 
640
    return f;
 
641
}
 
642
 
 
643
 
 
644
 
 
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)
 
648
{
 
649
        rule_t *f;
 
650
 
 
651
    g_assert(target != NULL);
 
652
 
 
653
    f = g_new0(rule_t, 1);
 
654
 
 
655
    f->type = RULE_FLAG;
 
656
 
 
657
    f->u.flag.stable = stable;
 
658
    f->u.flag.busy = busy;
 
659
    f->u.flag.push = push;
 
660
        f->target = target;
 
661
    f->flags  = flags;
 
662
    set_flags(f->flags, RULE_FLAG_VALID);
 
663
 
 
664
    return f;
 
665
}
 
666
 
 
667
 
 
668
 
 
669
rule_t *filter_new_state_rule
 
670
    (enum filter_prop_state display, enum filter_prop_state download,
 
671
    filter_t *target, guint16 flags)
 
672
{
 
673
        rule_t *f;
 
674
 
 
675
    g_assert(target != NULL);
 
676
 
 
677
    f = g_new0(rule_t, 1);
 
678
 
 
679
    f->type = RULE_STATE;
 
680
 
 
681
    f->u.state.display = display;
 
682
    f->u.state.download = download;
 
683
        f->target = target;
 
684
    f->flags  = flags;
 
685
    set_flags(f->flags, RULE_FLAG_VALID);
 
686
 
 
687
    return f;
 
688
}
 
689
 
 
690
 
 
691
 
 
692
/*
 
693
 * filter_set:
 
694
 *
 
695
 * Start working on the given filter. Set this filter as 
 
696
 * work_filter so we can commit the changed rules to this
 
697
 * filter.
 
698
 */
 
699
void filter_set(filter_t *f)
 
700
{
 
701
    if (f != NULL) {
 
702
        shadow_t *shadow;
 
703
        gboolean removable;
 
704
        gboolean active;
 
705
        GList *ruleset;
 
706
    
 
707
        shadow = shadow_find(f);
 
708
        if (shadow != NULL) {
 
709
            removable = 
 
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;
 
714
        } else {
 
715
            removable = 
 
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;
 
720
        }
 
721
    
 
722
        filter_gui_filter_set(f, removable, active, ruleset);
 
723
    } else {
 
724
        filter_gui_filter_set(NULL, FALSE, FALSE, NULL);
 
725
    }
 
726
 
 
727
    /* 
 
728
     * don't want the work_filter to be selectable as a target
 
729
     * so we changed it... we have to rebuild.
 
730
     */
 
731
    filter_update_targets();
 
732
}
 
733
 
 
734
 
 
735
 
 
736
/*
 
737
 * filter_close_search:
 
738
 *
 
739
 * Clear the searches shadow, update the combobox and the filter
 
740
 * bound to this search (search->ruleser).
 
741
 */
 
742
void filter_close_search(search_t *s)
 
743
{
 
744
    shadow_t *shadow;
 
745
 
 
746
    g_assert(s != NULL);
 
747
    g_assert(s->filter != NULL);
 
748
 
 
749
    if (gui_debug >= 6)
 
750
        printf("closing search (freeing filter): %s\n", s->query);
 
751
 
 
752
    shadow = shadow_find(s->filter);
 
753
    if (shadow != NULL) {
 
754
                GList *copy;
 
755
 
 
756
                copy = g_list_copy(shadow->removed);
 
757
                G_LIST_FOREACH_SWAPPED(copy, filter_append_rule_to_session, s->filter);
 
758
        g_list_free(copy);
 
759
 
 
760
                copy = g_list_copy(shadow->added);
 
761
                G_LIST_FOREACH_SWAPPED(copy,
 
762
                        filter_remove_rule_from_session, s->filter);
 
763
        g_list_free(copy);
 
764
 
 
765
        shadow_cancel(shadow);
 
766
    }          
 
767
 
 
768
    /*
 
769
     * If this is the filter currently worked on, clear the display.
 
770
     */
 
771
    if (s->filter == work_filter)
 
772
        filter_set(NULL);
 
773
 
 
774
    filter_gui_filter_remove(s->filter);
 
775
 
 
776
    filter_free(s->filter);
 
777
    s->filter = NULL;
 
778
}
 
779
 
 
780
 
 
781
 
 
782
/*
 
783
 * filter_apply_changes:
 
784
 *
 
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
 
790
 * search.
 
791
 */
 
792
void filter_apply_changes(void) 
 
793
{
 
794
    GList *s;
 
795
 
 
796
    /*
 
797
     * Free memory for all removed filters;
 
798
     */
 
799
    for (s = shadow_filters; s != NULL; s = shadow_filters)
 
800
        shadow_commit((shadow_t*)s->data);
 
801
 
 
802
    g_list_free(filters);
 
803
    filters = g_list_copy(filters_current);
 
804
 
 
805
    /*
 
806
     * Remove the SHADOW flag from all added filters
 
807
     */
 
808
    for (s = filters_added; s != NULL; s = s->next)
 
809
        clear_flags(((filter_t *)s->data)->flags, FILTER_FLAG_SHADOW);
 
810
 
 
811
    g_list_free(filters_added);
 
812
    filters_added = NULL;
 
813
    
 
814
    /*
 
815
     * Free all removed filters. Don't iterate since filter_free removes
 
816
     * the filter from filters_removed.
 
817
     */
 
818
    for (s = filters_removed; s != NULL; s = filters_removed) {
 
819
        filter_free(s->data);
 
820
    }
 
821
    g_assert(filters_removed == NULL);
 
822
 
 
823
    filter_update_targets();
 
824
    filter_set(work_filter);
 
825
}
 
826
 
 
827
 
 
828
 
 
829
/*
 
830
 * filter_revert_changes:
 
831
 *
 
832
 * Free the ressources for all added filters and forget all shadows.
 
833
 * A running session will not be ended by this.
 
834
 */
 
835
void filter_revert_changes(void)
 
836
{
 
837
    GList *s;
 
838
    gint n;
 
839
 
 
840
    if (gui_debug >= 5)
 
841
        printf("Canceling all changes to filters/rules\n");
 
842
 
 
843
    filter_gui_freeze_filters();
 
844
    filter_gui_freeze_rules();
 
845
 
 
846
    /*
 
847
     * Free memory for all added filters and for the shadows.
 
848
     */
 
849
    for (s = shadow_filters; s != NULL; s = shadow_filters)
 
850
        shadow_cancel((shadow_t *)s->data);
 
851
 
 
852
    if (g_list_find(filters, work_filter) != NULL)
 
853
        filter_set(work_filter);
 
854
    else
 
855
        filter_set(NULL);
 
856
 
 
857
    g_list_free(filters_current);
 
858
    filters_current = g_list_copy(filters);
 
859
    
 
860
    /*
 
861
     * Free and remove all added filters. We don't iterate explicitly,
 
862
     * because filter_free removes the added filter from filters_added
 
863
     * for us.
 
864
     */
 
865
    n = 0;
 
866
    for (s = filters_added; s != NULL; s = filters_added) {
 
867
        filter_t *filter = (filter_t *) s->data;
 
868
    
 
869
        filter_gui_filter_remove(filter);
 
870
        filter_free(filter);
 
871
    }
 
872
    g_assert(filters_added == NULL);
 
873
 
 
874
    /*
 
875
     * Restore all removed filters.
 
876
     */
 
877
    for (s = filters_removed; s != NULL; s = s->next) {
 
878
        filter_t *filter = (filter_t *) s->data;
 
879
 
 
880
        filter_gui_filter_add(filter, filter->ruleset);
 
881
    }
 
882
    g_list_free(filters_removed);
 
883
    filters_removed = NULL;
 
884
 
 
885
    /*
 
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.
 
889
     */
 
890
    for (s = filters_current; s != NULL; s = g_list_next(s)) {
 
891
        filter_t *filter = (filter_t *) s->data;
 
892
 
 
893
        filter_gui_update_rule_count(filter, filter->ruleset);
 
894
        filter_gui_filter_set_enabled(filter, filter_is_active(filter));
 
895
    }
 
896
 
 
897
    filter_gui_thaw_rules();
 
898
    filter_gui_thaw_filters();
 
899
    
 
900
    filter_update_targets();
 
901
}
 
902
 
 
903
 
 
904
 
 
905
/*
 
906
 * filter_rule_condition_to_gchar:
 
907
 *
 
908
 * Convert a rule condition to a human readable string.
 
909
 */
 
910
gchar *filter_rule_condition_to_gchar(const rule_t *r)
 
911
{
 
912
    static gchar tmp[256];
 
913
 
 
914
    g_assert(r != NULL);
 
915
    
 
916
    switch (r->type) {
 
917
    case RULE_TEXT:
 
918
        switch (r->u.text.type) {
 
919
        case RULE_TEXT_PREFIX:
 
920
                gm_snprintf(
 
921
                tmp, sizeof(tmp), 
 
922
                "If filename begins with \"%s\" %s",
 
923
                r->u.text.match,
 
924
                r->u.text.case_sensitive ? "(case sensitive)" : "");
 
925
            break;
 
926
        case RULE_TEXT_WORDS:
 
927
                gm_snprintf(
 
928
                tmp, sizeof(tmp), 
 
929
                "If filename contains the words \"%s\" %s",
 
930
                r->u.text.match,
 
931
                r->u.text.case_sensitive ? "(case sensitive)" : "");
 
932
            break;
 
933
        case RULE_TEXT_SUFFIX:
 
934
                gm_snprintf(
 
935
                tmp, sizeof(tmp), 
 
936
                "If filename ends with \"%s\" %s",
 
937
                r->u.text.match,
 
938
                r->u.text.case_sensitive ? "(case sensitive)" : "");
 
939
            break;
 
940
        case RULE_TEXT_SUBSTR:
 
941
                gm_snprintf(
 
942
                tmp, sizeof(tmp), 
 
943
                "If filename contains the substring \"%s\" %s",
 
944
                r->u.text.match,
 
945
                r->u.text.case_sensitive ? "(case sensitive)" : "");
 
946
            break;
 
947
        case RULE_TEXT_REGEXP:
 
948
                gm_snprintf(
 
949
                tmp, sizeof(tmp), 
 
950
                "If filename matches the regex \"%s\" %s",
 
951
                r->u.text.match,
 
952
                r->u.text.case_sensitive ? "(case sensitive)" : "");
 
953
            break;
 
954
        case RULE_TEXT_EXACT:
 
955
                gm_snprintf(
 
956
                tmp, sizeof(tmp), 
 
957
                "If filename is \"%s\" %s",
 
958
                r->u.text.match,
 
959
                r->u.text.case_sensitive ? "(case sensitive)" : "");
 
960
            break;
 
961
        default:
 
962
            g_error("filter_rule_condition_to_gchar:" 
 
963
                    "unknown text rule type: %d", r->u.text.type);
 
964
        };
 
965
        break;
 
966
    case RULE_IP:
 
967
        {
 
968
            gchar *mask;
 
969
            gchar *addr;
 
970
 
 
971
            mask = g_strdup(ip_to_gchar(r->u.ip.mask));
 
972
            addr = g_strdup(ip_to_gchar(r->u.ip.addr));
 
973
 
 
974
            gm_snprintf(tmp, sizeof(tmp), 
 
975
                "If IP address matches %s/%s", addr, mask);
 
976
 
 
977
            G_FREE_NULL(addr);
 
978
            G_FREE_NULL(mask);
 
979
        }
 
980
        break;
 
981
    case RULE_SIZE:
 
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));
 
990
        else {
 
991
            gchar *s1;
 
992
            gchar *s2;
 
993
 
 
994
            s1 = g_strdup(short_size(r->u.size.lower));
 
995
            s2 = g_strdup(short_size(r->u.size.upper));
 
996
    
 
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);
 
1000
 
 
1001
            G_FREE_NULL(s1);
 
1002
            G_FREE_NULL(s2);
 
1003
        }
 
1004
        break;
 
1005
    case RULE_SHA1:
 
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);
 
1009
        } else 
 
1010
            gm_snprintf(tmp, sizeof(tmp), "If urn:sha1 is not available");
 
1011
        break;
 
1012
    case RULE_JUMP:
 
1013
        gm_snprintf(
 
1014
            tmp, sizeof(tmp), 
 
1015
            "Always");
 
1016
        break;
 
1017
    case RULE_FLAG:
 
1018
        {
 
1019
            gchar *busy_str = "";
 
1020
            gchar *push_str = "";
 
1021
            gchar *stable_str = "";
 
1022
            gchar *s1 = "";
 
1023
            gchar *s2 = "";
 
1024
            gboolean b = FALSE;
 
1025
 
 
1026
            switch (r->u.flag.busy) {
 
1027
            case RULE_FLAG_SET:
 
1028
                busy_str = "busy is set";
 
1029
                b = TRUE;
 
1030
                break;
 
1031
            case RULE_FLAG_UNSET:
 
1032
                busy_str = "busy is not set";
 
1033
                b = TRUE;
 
1034
                break;
 
1035
            case RULE_FLAG_IGNORE:
 
1036
                break;
 
1037
            }
 
1038
    
 
1039
            switch (r->u.flag.push) {
 
1040
            case RULE_FLAG_SET:
 
1041
                if (b) s1 = ", ";
 
1042
                push_str = "push is set";
 
1043
                b = TRUE;
 
1044
                break;
 
1045
            case RULE_FLAG_UNSET:
 
1046
                if (b) s1 = ", ";
 
1047
                push_str = "push is not set";
 
1048
                b = TRUE;
 
1049
                break;
 
1050
            case RULE_FLAG_IGNORE:
 
1051
                break;
 
1052
            }
 
1053
    
 
1054
            switch (r->u.flag.stable) {
 
1055
            case RULE_FLAG_SET:
 
1056
                if (b) s2 = ", ";
 
1057
                stable_str = "stable is set";
 
1058
                b = TRUE;
 
1059
                break;
 
1060
            case RULE_FLAG_UNSET:
 
1061
                if (b) s2 = ", ";
 
1062
                stable_str = "stable is not set";
 
1063
                b = TRUE;
 
1064
                break;
 
1065
            case RULE_FLAG_IGNORE:
 
1066
                break;
 
1067
            }
 
1068
 
 
1069
            if (b)
 
1070
                gm_snprintf(
 
1071
                    tmp, sizeof(tmp),
 
1072
                    "If flag %s%s%s%s%s", 
 
1073
                    busy_str, s1, push_str, s2, stable_str);
 
1074
            else
 
1075
                 gm_snprintf(
 
1076
                    tmp, sizeof(tmp),
 
1077
                    "Always (all flags ignored)");
 
1078
        }
 
1079
        break;
 
1080
    case RULE_STATE:
 
1081
        {
 
1082
            gchar *display_str = "";
 
1083
            gchar *download_str = "";
 
1084
            gchar *s1 = "";
 
1085
            gboolean b = FALSE;
 
1086
 
 
1087
            switch (r->u.state.display) {
 
1088
            case FILTER_PROP_STATE_UNKNOWN:
 
1089
                display_str = "DISPLAY is undefined";
 
1090
                b = TRUE;
 
1091
                break;
 
1092
            case FILTER_PROP_STATE_DO:
 
1093
                display_str = "DISPLAY";
 
1094
                b = TRUE;
 
1095
                break;
 
1096
            case FILTER_PROP_STATE_DONT:
 
1097
                display_str = "DON'T DISPLAY";
 
1098
                b = TRUE;
 
1099
                break;
 
1100
            case FILTER_PROP_STATE_IGNORE:
 
1101
                break;
 
1102
            default:
 
1103
                g_assert_not_reached();
 
1104
            }
 
1105
    
 
1106
            switch (r->u.state.download) {
 
1107
            case FILTER_PROP_STATE_UNKNOWN:
 
1108
                if (b) s1 = ", ";
 
1109
                download_str = "DOWNLOAD is undefined";
 
1110
                b = TRUE;
 
1111
                break;
 
1112
            case FILTER_PROP_STATE_DO:
 
1113
                if (b) s1 = ", ";
 
1114
                download_str = "DOWNLOAD";
 
1115
                b = TRUE;
 
1116
                break;
 
1117
            case FILTER_PROP_STATE_DONT:
 
1118
                if (b) s1 = ", ";
 
1119
                download_str = "DON'T DOWNLOAD";
 
1120
                b = TRUE;
 
1121
                break;
 
1122
            case FILTER_PROP_STATE_IGNORE:
 
1123
                break;
 
1124
            default:
 
1125
                g_assert_not_reached();
 
1126
            }
 
1127
     
 
1128
            if (b)
 
1129
                gm_snprintf(
 
1130
                    tmp, sizeof(tmp),
 
1131
                    "If flag %s%s%s", 
 
1132
                    display_str, s1, download_str);
 
1133
            else
 
1134
                 gm_snprintf(
 
1135
                    tmp, sizeof(tmp),
 
1136
                    "Always (all states ignored)");
 
1137
        }
 
1138
        break;
 
1139
    default:
 
1140
        g_error("filter_rule_condition_to_gchar: "
 
1141
                "unknown rule type: %d", r->type);
 
1142
        return NULL;
 
1143
    };
 
1144
 
 
1145
    return tmp;
 
1146
}
 
1147
 
 
1148
 
 
1149
 
 
1150
/*
 
1151
 * filter_rule_to_gchar:
 
1152
 *
 
1153
 * Convert the filter to a human readable string.
 
1154
 */
 
1155
gchar *filter_rule_to_gchar(rule_t *r) 
 
1156
{
 
1157
    gchar *cond;
 
1158
 
 
1159
    g_assert(r != NULL);
 
1160
 
 
1161
    cond = g_strdup(filter_rule_condition_to_gchar(r));
 
1162
 
 
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)",
 
1166
        cond,
 
1167
        RULE_IS_VALID(r) ? r->target->name : "(invalid)");
 
1168
 
 
1169
    G_FREE_NULL(cond);
 
1170
  
 
1171
    return f_tmp;
 
1172
}
 
1173
 
 
1174
 
 
1175
 
 
1176
/*
 
1177
 * filter_new:
 
1178
 *
 
1179
 * Create a new filter with the given name.
 
1180
 */
 
1181
filter_t *filter_new(gchar *name)
 
1182
{
 
1183
    filter_t *f;
 
1184
 
 
1185
    g_assert(name != NULL);
 
1186
 
 
1187
    f = g_new0(filter_t, 1);
 
1188
    f->name = g_strdup(name);
 
1189
    f->ruleset = NULL;
 
1190
    f->search = NULL;
 
1191
    f->visited = FALSE;
 
1192
    set_flags(f->flags, FILTER_FLAG_ACTIVE);
 
1193
 
 
1194
    return f;
 
1195
}
 
1196
 
 
1197
 
 
1198
 
 
1199
/*
 
1200
 * filter_add_to_session:
 
1201
 *
 
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.
 
1204
 */
 
1205
void filter_add_to_session(filter_t *f)
 
1206
{
 
1207
    g_assert(g_list_find(filters_current, f) == NULL);
 
1208
    g_assert(f != NULL);
 
1209
   
 
1210
 
 
1211
    /*
 
1212
     * Either remove from removed or add to added list.
 
1213
     */
 
1214
    if (g_list_find(filters_removed, f) != NULL)
 
1215
        filters_removed = g_list_remove(filters_removed, f);
 
1216
    else {
 
1217
        filters_added = g_list_append(filters_added, f);
 
1218
 
 
1219
        /*
 
1220
         * Since the filter is new and not yet used for filtering
 
1221
         * we set the FILTER_FLAG_SHADOW flag.
 
1222
         */
 
1223
        set_flags(f->flags, FILTER_FLAG_SHADOW);
 
1224
    }
 
1225
 
 
1226
    filters_current = g_list_append(filters_current, f);
 
1227
 
 
1228
    filter_gui_filter_add(f, f->ruleset);
 
1229
}
 
1230
 
 
1231
 
 
1232
 
 
1233
/*
 
1234
 * filter_new_for_search:
 
1235
 *
 
1236
 * Create a new filter bound to a search and register it.
 
1237
 */
 
1238
void filter_new_for_search(search_t *s)
 
1239
{
 
1240
    filter_t *f;
 
1241
 
 
1242
    g_assert(s != NULL);
 
1243
    g_assert(s->query != NULL);
 
1244
 
 
1245
    f = g_new0(filter_t, 1);
 
1246
    f->name = g_strdup(s->query);
 
1247
    f->ruleset = NULL;
 
1248
    f->search = NULL;
 
1249
    f->visited = FALSE;
 
1250
    set_flags(f->flags, FILTER_FLAG_ACTIVE);
 
1251
 
 
1252
    /*
 
1253
     * Add filter to current and session lists
 
1254
     */
 
1255
    filters = g_list_append(filters, f);
 
1256
    filters_current = g_list_append(filters_current, f);
 
1257
 
 
1258
    /*
 
1259
     * Crosslink filter and search
 
1260
     */
 
1261
    f->search = s;
 
1262
    s->filter = f;
 
1263
 
 
1264
    /*
 
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.
 
1267
     */
 
1268
    filter_gui_filter_add(f, f->ruleset);
 
1269
}
 
1270
 
 
1271
 
 
1272
 
 
1273
/*
 
1274
 * filter_remove_from_session:
 
1275
 *
 
1276
 * Mark the given filter as removed and delete it when the
 
1277
 * dialog changes are committed.
 
1278
 */
 
1279
void filter_remove_from_session(filter_t *f) 
 
1280
{
 
1281
    g_assert(g_list_find(filters_removed, f) == NULL);
 
1282
    g_assert(g_list_find(filters_current, f) != NULL);
 
1283
 
 
1284
    /*
 
1285
     * Either remove from added list or add to removed list.
 
1286
     */
 
1287
    if (g_list_find(filters_added, f) != NULL)
 
1288
        filters_added = g_list_remove(filters_added, f);
 
1289
    else
 
1290
        filters_removed = g_list_append(filters_removed, f);
 
1291
 
 
1292
    filters_current = g_list_remove(filters_current, f);
 
1293
 
 
1294
    /*
 
1295
     * If this is the filter currently worked on, clear the display.
 
1296
     */
 
1297
    if (work_filter == f) 
 
1298
        filter_set(NULL);
 
1299
 
 
1300
    filter_gui_filter_remove(f);
 
1301
}
 
1302
 
 
1303
 
 
1304
 
 
1305
/*
 
1306
 * filter_free:
 
1307
 *
 
1308
 * Frees a filter and the filters assiciated with it and
 
1309
 * unregisters it from current and session filter lists.
 
1310
 */
 
1311
static void filter_free(filter_t *f) 
 
1312
{
 
1313
    GList *copy;
 
1314
 
 
1315
    g_assert(f != NULL);
 
1316
 
 
1317
    if (shadow_find(f) != NULL)
 
1318
        g_error("Unable to free shadowed filter \"%s\" with refcount %d",
 
1319
            f->name, f->refcount);
 
1320
 
 
1321
    if (f->refcount != 0)
 
1322
        g_error("Unable to free referenced filter \"%s\" with refcount %d",
 
1323
            f->name, f->refcount);
 
1324
    
 
1325
    /*
 
1326
     * Remove the filter from current and session data
 
1327
     */
 
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);
 
1336
 
 
1337
        copy = g_list_copy(f->ruleset);
 
1338
        G_LIST_FOREACH_SWAPPED(copy, filter_remove_rule, f);
 
1339
    g_list_free(copy);
 
1340
 
 
1341
    G_FREE_NULL(f->name);
 
1342
    G_FREE_NULL(f);
 
1343
}
 
1344
 
 
1345
 
 
1346
 
 
1347
/*
 
1348
 * filter_free_rule:
 
1349
 *
 
1350
 * Free memory reserved by rule respecting the type of the rule.
 
1351
 */
 
1352
void filter_free_rule(rule_t *r)
 
1353
{
 
1354
    g_assert(r != NULL);
 
1355
 
 
1356
    if (gui_debug >= 6)
 
1357
        printf("freeing rule: %s\n", filter_rule_to_gchar(r));
 
1358
 
 
1359
    switch (r->type) {
 
1360
    case RULE_TEXT:
 
1361
        G_FREE_NULL(r->u.text.match);
 
1362
 
 
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;
 
1368
            break;
 
1369
        case RULE_TEXT_SUBSTR:
 
1370
            pattern_free(r->u.text.u.pattern);
 
1371
            r->u.text.u.pattern = NULL;
 
1372
            break;
 
1373
        case RULE_TEXT_REGEXP:
 
1374
            regfree(r->u.text.u.re);
 
1375
            r->u.text.u.re = NULL;
 
1376
            break;
 
1377
        case RULE_TEXT_PREFIX:
 
1378
        case RULE_TEXT_SUFFIX:
 
1379
        case RULE_TEXT_EXACT:
 
1380
            break;
 
1381
        default:
 
1382
            g_error("filter_free_rule: unknown text rule type: %d", r->u.text.type);
 
1383
        }
 
1384
        break;
 
1385
    case RULE_SHA1:
 
1386
        G_FREE_NULL(r->u.sha1.hash);
 
1387
        G_FREE_NULL(r->u.sha1.filename);
 
1388
        break;
 
1389
    case RULE_SIZE:
 
1390
    case RULE_JUMP:
 
1391
    case RULE_IP:
 
1392
    case RULE_FLAG:
 
1393
    case RULE_STATE:
 
1394
        break;
 
1395
    default:
 
1396
        g_error("filter_free_rule: unknown rule type: %d", r->type);
 
1397
    }
 
1398
        G_FREE_NULL(r);
 
1399
}
 
1400
 
 
1401
 
 
1402
 
 
1403
/*
 
1404
 * filter_append_rule:
 
1405
 *
 
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.
 
1409
 */
 
1410
void filter_append_rule(filter_t *f, rule_t * const r)
 
1411
{
 
1412
    shadow_t *shadow;
 
1413
    shadow_t *target_shadow;
 
1414
 
 
1415
    g_assert(f != NULL);
 
1416
    g_assert(r != NULL);
 
1417
    g_assert(r->target != NULL);
 
1418
 
 
1419
    shadow = shadow_find(f);
 
1420
    target_shadow = shadow_find(r->target);
 
1421
 
 
1422
    if (g_list_find(f->ruleset, r) != NULL)
 
1423
        g_error("rule already exists in filter \"%s\"", f->name);
 
1424
 
 
1425
    if ((shadow != NULL) && g_list_find(shadow->current, r))
 
1426
        g_error("rule already exists in shadow for filter \"%s\"",
 
1427
            f->name);
 
1428
 
 
1429
    /*
 
1430
     * We add the rule to the filter increase the refcount on the target.
 
1431
     */
 
1432
    f->ruleset = g_list_append(f->ruleset, r);
 
1433
    r->target->refcount ++;
 
1434
    if (gui_debug >= 6)
 
1435
        printf("increased refcount on \"%s\" to %d\n",
 
1436
            r->target->name, r->target->refcount);
 
1437
 
 
1438
    /*
 
1439
     * If a shadow for our filter exists, we add it there also.
 
1440
     */
 
1441
    if (shadow != NULL)
 
1442
        shadow->current = g_list_append(shadow->current, r);
 
1443
 
 
1444
    /*
 
1445
     * If a shadow for the target exists, we increase refcount there too.
 
1446
     */
 
1447
    if (target_shadow != NULL) {
 
1448
        target_shadow->refcount ++;
 
1449
 
 
1450
        if (gui_debug >= 6)
 
1451
            printf("increased refcount on shadow of \"%s\" to %d\n",
 
1452
                target_shadow->filter->name, target_shadow->refcount);
 
1453
    }
 
1454
    
 
1455
    /*
 
1456
     * Update dialog if necessary.
 
1457
     */
 
1458
    {
 
1459
        GList *ruleset;
 
1460
 
 
1461
        ruleset = (shadow != NULL) ? shadow->current : f->ruleset;
 
1462
 
 
1463
        if (work_filter == f)
 
1464
            filter_gui_set_ruleset(ruleset);
 
1465
        filter_gui_update_rule_count(f, ruleset);
 
1466
    }
 
1467
}
 
1468
 
 
1469
 
 
1470
 
 
1471
/*
 
1472
 * filter_append_rule_to_session:
 
1473
 *
 
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
 
1476
 * the shadow.
 
1477
 */
 
1478
void filter_append_rule_to_session(filter_t *f, rule_t * const r)
 
1479
{
 
1480
    shadow_t *shadow = NULL;
 
1481
    shadow_t *target_shadow = NULL;
 
1482
 
 
1483
    g_assert(r != NULL);
 
1484
    g_assert(f != NULL);
 
1485
    g_assert(r->target != NULL);
 
1486
 
 
1487
    if (gui_debug >= 4)
 
1488
        printf("appending rule to filter: %s <- %s (%p)\n",
 
1489
            f->name, filter_rule_to_gchar(r), r->target);
 
1490
 
 
1491
    /*
 
1492
     * The rule is added to a session, so we set the shadow flag.
 
1493
     */
 
1494
    set_flags(r->flags, RULE_FLAG_SHADOW);
 
1495
 
 
1496
    /*
 
1497
     * Create a new shadow if necessary.
 
1498
     */
 
1499
    shadow = shadow_find(f);
 
1500
    if (shadow == NULL)
 
1501
        shadow = shadow_new(f);
 
1502
    else {
 
1503
        /*
 
1504
         * You can never add a filter to a shadow or filter
 
1505
         * twice!
 
1506
         */
 
1507
        g_assert(g_list_find(shadow->current, r) == NULL);
 
1508
    }
 
1509
 
 
1510
    if (g_list_find(shadow->removed, r) == NULL) {
 
1511
        shadow->added = g_list_append(shadow->added, r);
 
1512
    } else {
 
1513
        shadow->removed = g_list_remove(shadow->removed, r);
 
1514
    }
 
1515
    shadow->current = g_list_append(shadow->current, r);
 
1516
 
 
1517
    /*
 
1518
     * We need to increase the refcount on the target.
 
1519
     */
 
1520
    target_shadow = shadow_find(r->target);
 
1521
    if (target_shadow == NULL)
 
1522
        target_shadow = shadow_new(r->target);
 
1523
 
 
1524
    target_shadow->refcount ++;
 
1525
    if (gui_debug >= 6)
 
1526
        printf("increased refcount on shadow of \"%s\" to %d\n",
 
1527
            target_shadow->filter->name, target_shadow->refcount);
 
1528
 
 
1529
    /*
 
1530
     * Update dialog if necessary.
 
1531
     */
 
1532
    if (work_filter == f)
 
1533
        filter_gui_set_ruleset(shadow->current);
 
1534
    filter_gui_update_rule_count(f, shadow->current);
 
1535
}
 
1536
 
 
1537
 
 
1538
 
 
1539
/*
 
1540
 * filter_remove_rule:
 
1541
 *
 
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.
 
1546
 */
 
1547
void filter_remove_rule(filter_t *f, rule_t *r)
 
1548
{
 
1549
    shadow_t *shadow;
 
1550
    shadow_t *target_shadow;
 
1551
    gboolean in_shadow_current;
 
1552
    gboolean in_shadow_removed;
 
1553
    gboolean in_filter;
 
1554
 
 
1555
    g_assert(f != NULL);
 
1556
    g_assert(r != NULL);
 
1557
    g_assert(r->target != NULL);
 
1558
 
 
1559
    shadow = shadow_find(f);
 
1560
    target_shadow = shadow_find(r->target);
 
1561
 
 
1562
    in_filter = g_list_find(f->ruleset, r) != NULL;
 
1563
 
 
1564
    /*
 
1565
     * We need to check where the rule is actually located... in the
 
1566
     * shadow, in the real filter or in both.
 
1567
     */
 
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;
 
1571
    } else {
 
1572
        /*
 
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.
 
1575
         */
 
1576
        in_shadow_current = in_filter; 
 
1577
        in_shadow_removed = FALSE;
 
1578
    }
 
1579
 
 
1580
    /*
 
1581
     * We have to purge the rule from the shadow where necessary.
 
1582
     */
 
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);
 
1586
    }
 
1587
 
 
1588
    if (in_shadow_removed && (shadow != NULL))
 
1589
       shadow->removed = g_list_remove(shadow->removed, r);
 
1590
 
 
1591
    if (in_filter)
 
1592
        f->ruleset = g_list_remove(f->ruleset, r);
 
1593
 
 
1594
    /*
 
1595
     * Now we need to clean up the refcounts that may have been
 
1596
     * caused by this rule. We have these possibilities:
 
1597
     *
 
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
 
1617
     *   
 
1618
     * Possibilities:
 
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
 
1621
          added back)
 
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.
 
1632
     *
 
1633
     * Failures:
 
1634
     * A) a rule can never be in shadow->added and shadow->removed at 
 
1635
     *    the same time.
 
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
 
1644
     *    filter.
 
1645
     */
 
1646
    if (in_filter) {
 
1647
        r->target->refcount --;
 
1648
 
 
1649
        if (gui_debug >= 6)
 
1650
            printf("decreased refcount on \"%s\" to %d\n",
 
1651
                r->target->name, r->target->refcount);
 
1652
    }
 
1653
 
 
1654
    if (in_shadow_current) {
 
1655
        if (target_shadow != NULL) {
 
1656
            target_shadow->refcount --;
 
1657
        
 
1658
            if (gui_debug >= 6)
 
1659
                printf("decreased refcount on shadow of \"%s\" to %d\n",
 
1660
                    target_shadow->filter->name, target_shadow->refcount);
 
1661
        }
 
1662
    }
 
1663
 
 
1664
    if (!in_filter && !in_shadow_current) {
 
1665
        g_warning("rule unknown in context: aborting removal without freeing");
 
1666
        return;
 
1667
    }
 
1668
 
 
1669
    filter_free_rule(r);
 
1670
    
 
1671
    /*
 
1672
     * Update dialog if necessary.
 
1673
     */
 
1674
     {
 
1675
        GList *ruleset;
 
1676
 
 
1677
        ruleset = (shadow != NULL) ? shadow->current : f->ruleset;
 
1678
 
 
1679
        if (work_filter == f)
 
1680
            filter_gui_set_ruleset(ruleset);
 
1681
        filter_gui_update_rule_count(f, ruleset);
 
1682
    }
 
1683
}
 
1684
 
 
1685
 
 
1686
/*
 
1687
 * filter_remove_rule_from_session:
 
1688
 *
 
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.
 
1693
 */
 
1694
void filter_remove_rule_from_session(filter_t *f, rule_t * const r)
 
1695
{
 
1696
    shadow_t *shadow;
 
1697
    shadow_t *target_shadow;
 
1698
    GList *l = NULL;
 
1699
       
 
1700
    g_assert(r != NULL);
 
1701
    g_assert(f != NULL);
 
1702
 
 
1703
    if (gui_debug >= 4)
 
1704
        printf("removing rule in filter: %s -> %s\n", 
 
1705
            f->name, filter_rule_to_gchar(r));
 
1706
 
 
1707
    /*
 
1708
     * Create a new shadow if necessary.
 
1709
     */
 
1710
    shadow = shadow_find(f);
 
1711
    if (shadow == NULL)
 
1712
        shadow = shadow_new(f);
 
1713
 
 
1714
    g_assert(g_list_find(shadow->current, r) != NULL);
 
1715
 
 
1716
    shadow->current = g_list_remove(shadow->current, r);
 
1717
 
 
1718
    /*
 
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
 
1721
     * after that.
 
1722
     */
 
1723
    target_shadow = shadow_find(r->target);
 
1724
    if (target_shadow == NULL)
 
1725
        target_shadow = shadow_new(r->target);
 
1726
 
 
1727
    target_shadow->refcount --;
 
1728
    if (gui_debug >= 6)
 
1729
        printf("decreased refcount on shadow of \"%s\" to %d\n",
 
1730
            target_shadow->filter->name, target_shadow->refcount);
 
1731
 
 
1732
    l = g_list_find(shadow->added, r);
 
1733
    if (l != NULL) {
 
1734
        /*
 
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.
 
1738
         */
 
1739
        if (gui_debug >= 4)
 
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);
 
1744
    } else {
 
1745
        /*
 
1746
         * The rule was not added, so it must be existent.
 
1747
         * If it is, we remember it on shadow->removed.
 
1748
         */
 
1749
        g_assert(g_list_find(shadow->removed, r) == NULL);
 
1750
 
 
1751
        if (gui_debug >= 4)
 
1752
            printf("while removing from %s: adding to removed: %s\n",
 
1753
                f->name, filter_rule_to_gchar(r));
 
1754
      
 
1755
        shadow->removed = g_list_append(shadow->removed, r);
 
1756
    }
 
1757
 
 
1758
    /*
 
1759
     * Update dialog if necessary.
 
1760
     */
 
1761
    if (work_filter == f)
 
1762
        filter_gui_set_ruleset(shadow->current);
 
1763
    filter_gui_update_rule_count(f, shadow->current);
 
1764
}
 
1765
 
 
1766
 
 
1767
 
 
1768
/*
 
1769
 * filter_replace_rule_in_session:
 
1770
 *
 
1771
 * Replaces filter rule A with filter rule B in filter . A
 
1772
 * must already be in the shadow and B must not! 
 
1773
 *
 
1774
 * CAUTION: ACTUALLY B MUST NOT BE IN ANY OTHER SEARCH !!!
 
1775
 *
 
1776
 * The memory for A is freed in the process.
 
1777
 */
 
1778
void filter_replace_rule_in_session(filter_t *f, 
 
1779
    rule_t * const old_rule, rule_t * const new_rule)
 
1780
{
 
1781
    GList *filter;
 
1782
    GList *added;
 
1783
    shadow_t *shadow;
 
1784
    shadow_t *target_shadow;
 
1785
 
 
1786
    g_assert(old_rule != new_rule);
 
1787
    g_assert(old_rule != NULL);
 
1788
    g_assert(new_rule != NULL);
 
1789
 
 
1790
    /*
 
1791
     * Create a new shadow if necessary.
 
1792
     */
 
1793
    shadow = shadow_find(f);
 
1794
    if (shadow == NULL)
 
1795
        shadow = shadow_new(f);
 
1796
 
 
1797
    /*
 
1798
     * Find the list node where we have to replace the
 
1799
     * rule.
 
1800
     */
 
1801
    filter = g_list_find(shadow->current, old_rule);
 
1802
    g_assert(filter != NULL);
 
1803
 
 
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));
 
1807
 
 
1808
        printf("replacing rules (old <- new): %s <- %s\n", f1, f2);
 
1809
 
 
1810
        G_FREE_NULL(f1);
 
1811
        G_FREE_NULL(f2);
 
1812
    }
 
1813
 
 
1814
    /*
 
1815
     * In any case we have to reduce the refcount on the old rule's
 
1816
     * target.
 
1817
     */
 
1818
    target_shadow = shadow_find(old_rule->target);
 
1819
    if (target_shadow == NULL)
 
1820
        target_shadow = shadow_new(old_rule->target);
 
1821
 
 
1822
    target_shadow->refcount --;
 
1823
    if (gui_debug >= 6)
 
1824
        printf("decreased refcount on shadow of \"%s\" to %d\n",
 
1825
            target_shadow->filter->name, target_shadow->refcount);
 
1826
 
 
1827
    /*
 
1828
     * Find wether the node to be replaced is in shadow->added. 
 
1829
     * If so, we may free the memory of the old rule.
 
1830
     */
 
1831
    added = g_list_find(shadow->added, old_rule);
 
1832
 
 
1833
    if (added != NULL) {
 
1834
        /*
 
1835
         * If it was added, then free and remove the rule.
 
1836
         */
 
1837
        shadow->added = g_list_remove(shadow->added, old_rule);
 
1838
        filter_free_rule(old_rule);
 
1839
    } else {
 
1840
        /*
 
1841
         * If the filter was not added, then it must be marked
 
1842
         * for begin removed.
 
1843
         */
 
1844
        shadow->removed = g_list_append(shadow->removed, old_rule);
 
1845
    }
 
1846
     
 
1847
    /*
 
1848
     * The new rule can't be in the original filter, so we mark it
 
1849
     * as added.
 
1850
     */
 
1851
    shadow->added = g_list_append(shadow->added, new_rule);
 
1852
    set_flags(new_rule->flags, RULE_FLAG_SHADOW);
 
1853
 
 
1854
    /*
 
1855
     * And we also need to increase the refcount on the new rule's
 
1856
     * target
 
1857
     */
 
1858
    target_shadow = shadow_find(new_rule->target);
 
1859
    if (target_shadow == NULL)
 
1860
        target_shadow = shadow_new(new_rule->target);
 
1861
 
 
1862
    target_shadow->refcount ++;
 
1863
    if (gui_debug >= 6)
 
1864
        printf("increased refcount on shadow of \"%s\" to %d\n",
 
1865
            target_shadow->filter->name, target_shadow->refcount);
 
1866
        
 
1867
    /*
 
1868
     * In shadow->current we just replace the rule.
 
1869
     */
 
1870
    filter->data = new_rule;
 
1871
    
 
1872
    /*
 
1873
     * Update dialog if necessary.
 
1874
     */
 
1875
    if (work_filter == f)
 
1876
        filter_gui_set_ruleset(shadow->current);
 
1877
}
 
1878
 
 
1879
 
 
1880
 
 
1881
/*
 
1882
 * filter_adapt_order:
 
1883
 *
 
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.
 
1891
 */
 
1892
void filter_adapt_order(void)
 
1893
{
 
1894
    GList *neworder = NULL;
 
1895
    gint row;
 
1896
    shadow_t *shadow;
 
1897
    GtkCList *clist;
 
1898
 
 
1899
    if (!work_filter || filter_dialog == NULL)
 
1900
        return;
 
1901
   
 
1902
    clist = GTK_CLIST(lookup_widget(filter_dialog, "clist_filter_rules"));
 
1903
 
 
1904
    /*
 
1905
     * Create a new shadow if necessary.
 
1906
     */
 
1907
    shadow = shadow_find(work_filter);
 
1908
    if (shadow == NULL)
 
1909
        shadow = shadow_new(work_filter);
 
1910
 
 
1911
    /*
 
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
 
1915
     * row data.
 
1916
     */
 
1917
    g_list_free(shadow->current);
 
1918
 
 
1919
    for (row = 0; row < clist->rows; row ++) {
 
1920
        filter_t *f;
 
1921
 
 
1922
        f = gtk_clist_get_row_data(clist, row);
 
1923
        g_assert(f != NULL);
 
1924
        
 
1925
        neworder = g_list_append(neworder, f);
 
1926
    }
 
1927
 
 
1928
    shadow->current = neworder;
 
1929
}
 
1930
 
 
1931
 
 
1932
#define MATCH_RULE(filter, r, res)                                \
 
1933
    (res)->props_set ++;                                          \
 
1934
    (r)->match_count ++;                                          \
 
1935
    (prop_count) ++;                                              \
 
1936
    (r)->target->match_count ++;                                  \
 
1937
                                                                  \
 
1938
    if (gui_debug >= 10)                                                 \
 
1939
        printf("matched rule: %s\n", filter_rule_to_gchar((r)));
 
1940
   
 
1941
/*
 
1942
 * filter_apply:
 
1943
 *
 
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.
 
1947
 */
 
1948
static int filter_apply
 
1949
    (filter_t *filter, struct record *rec, filter_result_t *res)
 
1950
{
 
1951
    size_t namelen;
 
1952
        char *l_name;
 
1953
    GList *list;
 
1954
    gint prop_count = 0;
 
1955
    gboolean do_abort = FALSE;
 
1956
 
 
1957
    g_assert(filter != NULL);
 
1958
    g_assert(rec != NULL);
 
1959
    g_assert(res != NULL);
 
1960
 
 
1961
    /*
 
1962
     * We only try to prevent circles or the filter is inactive.
 
1963
     */
 
1964
    if ((filter->visited == TRUE) || !filter_is_active(filter)) {
 
1965
        return 0;
 
1966
    }
 
1967
 
 
1968
    filter->visited = TRUE;
 
1969
 
 
1970
    list = filter->ruleset;
 
1971
 
 
1972
        namelen = strlen(rec->name);
 
1973
        l_name = g_malloc(sizeof(char) * (namelen + 1));
 
1974
        strlower(l_name, rec->name);
 
1975
 
 
1976
        list = g_list_first(list);
 
1977
        while ((list != NULL) && (res->props_set < MAX_FILTER_PROP) && !do_abort) {
 
1978
                size_t n;
 
1979
                int i;
 
1980
                rule_t *r; 
 
1981
        gboolean match = FALSE;
 
1982
 
 
1983
        r = (rule_t *)list->data;
 
1984
        if (gui_debug >= 10)
 
1985
            printf("trying to match against: %s\n", filter_rule_to_gchar(r));
 
1986
 
 
1987
        if (RULE_IS_ACTIVE(r)) {
 
1988
            switch (r->type) {
 
1989
            case RULE_JUMP:
 
1990
                match = TRUE;
 
1991
                break;
 
1992
            case RULE_TEXT:
 
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)
 
1997
                        match = TRUE;
 
1998
                    break;
 
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)
 
2002
                        match = TRUE;
 
2003
                    break;
 
2004
                case RULE_TEXT_WORDS:   /* Contains ALL the words */
 
2005
                    {
 
2006
                        GList *l;
 
2007
                                                gboolean failed = FALSE;
 
2008
        
 
2009
                        for (
 
2010
                            l = g_list_first(r->u.text.u.words);
 
2011
                            l && !failed; 
 
2012
                            l = g_list_next(l)
 
2013
                        ) {
 
2014
                            if (
 
2015
                                                                pattern_qsearch((cpattern_t *)l->data,
 
2016
                                 r->u.text.case_sensitive ? rec->name : l_name,
 
2017
                                                                 0, 0, qs_any) == NULL
 
2018
                                                        )
 
2019
                                failed = TRUE;
 
2020
                        }
 
2021
 
 
2022
                                                match = !failed;
 
2023
                    }
 
2024
                    break;
 
2025
                case RULE_TEXT_SUFFIX:
 
2026
                    n = r->u.text.matchlen;
 
2027
                    if (namelen > n
 
2028
                        && strcmp((r->u.text.case_sensitive
 
2029
                               ? rec->name : l_name) + namelen
 
2030
                              - n, r->u.text.match) == 0)
 
2031
                        match = TRUE;
 
2032
                    break;
 
2033
                case RULE_TEXT_SUBSTR: 
 
2034
                    if (
 
2035
                                                pattern_qsearch(r->u.text.u.pattern,
 
2036
                                r->u.text.case_sensitive ? rec->name : l_name,
 
2037
                                                                0, 0, qs_any) != NULL
 
2038
                                        )
 
2039
                        match = TRUE;
 
2040
                    break;
 
2041
                case RULE_TEXT_REGEXP:
 
2042
                    if ((i = regexec(r->u.text.u.re, rec->name,
 
2043
                             0, NULL, 0)) == 0)
 
2044
                        match = TRUE;
 
2045
                    if (i == REG_ESPACE)
 
2046
                        g_warning("regexp memory overflow");
 
2047
                    break;
 
2048
                default:
 
2049
                    g_error("Unknown text rule type: %d",
 
2050
                        r->u.text.type);
 
2051
                }
 
2052
                break;
 
2053
            case RULE_IP:
 
2054
                if ((rec->results_set->ip & r->u.ip.mask) == r->u.ip.addr)
 
2055
                    match = TRUE;
 
2056
                break;
 
2057
            case RULE_SIZE:
 
2058
                if (rec->size >= r->u.size.lower && 
 
2059
                    rec->size <= r->u.size.upper)
 
2060
                    match = TRUE;
 
2061
                break;
 
2062
            case RULE_SHA1:
 
2063
                if (rec->sha1 == r->u.sha1.hash)
 
2064
                    match = TRUE;
 
2065
                else if ((rec->sha1 != NULL) &&  r->u.sha1.hash != NULL)
 
2066
                    if (memcmp(rec->sha1, r->u.sha1.hash, SHA1_RAW_SIZE) == 0)
 
2067
                        match = TRUE;
 
2068
                break;
 
2069
            case RULE_FLAG:
 
2070
                {
 
2071
                    gboolean stable_match;
 
2072
                    gboolean busy_match;
 
2073
                    gboolean push_match;
 
2074
    
 
2075
                    stable_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);
 
2081
 
 
2082
                    busy_match =
 
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);
 
2088
                
 
2089
                    push_match = 
 
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);
 
2095
                     
 
2096
                    match = stable_match && busy_match && push_match;
 
2097
                }
 
2098
                break;
 
2099
            case RULE_STATE:
 
2100
                {
 
2101
                    gboolean display_match;
 
2102
                    gboolean download_match;
 
2103
 
 
2104
                    display_match =
 
2105
                        (r->u.state.display == FILTER_PROP_STATE_IGNORE) ||
 
2106
                        (res->props[FILTER_PROP_DISPLAY].state 
 
2107
                            == r->u.state.display);
 
2108
                    
 
2109
                    download_match = 
 
2110
                        (r->u.state.download == FILTER_PROP_STATE_IGNORE) ||
 
2111
                        (res->props[FILTER_PROP_DOWNLOAD].state
 
2112
                            == r->u.state.download);
 
2113
            
 
2114
                    match = display_match && download_match;
 
2115
                }
 
2116
                break;
 
2117
            default:
 
2118
                g_error("Unknown rule type: %d", r->type);
 
2119
                break;
 
2120
            }
 
2121
        }
 
2122
        /*
 
2123
         * If negate is set, we invert the meaning of match.
 
2124
         */
 
2125
 
 
2126
                if (RULE_IS_NEGATED(r) && RULE_IS_ACTIVE(r))
 
2127
                        match = !match;
 
2128
 
 
2129
        /*
 
2130
         * Try to match the builtin rules, but don't act on matches
 
2131
         * that would change a result property that was already
 
2132
         * defined.
 
2133
         */
 
2134
        if (match) {
 
2135
            if (r->target == filter_return) {
 
2136
                do_abort = TRUE;
 
2137
                r->match_count ++;
 
2138
                r->target->match_count ++;
 
2139
            } else
 
2140
            if ((r->target == filter_show)) {
 
2141
                if (!res->props[FILTER_PROP_DISPLAY].state) {
 
2142
 
 
2143
                    res->props[FILTER_PROP_DISPLAY].state =
 
2144
                        FILTER_PROP_STATE_DO;
 
2145
 
 
2146
                    MATCH_RULE(filter, r, res);
 
2147
                }
 
2148
            } else 
 
2149
            if (r->target == filter_drop) {
 
2150
                if (!res->props[FILTER_PROP_DISPLAY].state) {
 
2151
 
 
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);
 
2156
 
 
2157
                    MATCH_RULE(filter, r, res);
 
2158
                }
 
2159
            } else 
 
2160
            if (r->target == filter_download){
 
2161
                if (!res->props[FILTER_PROP_DOWNLOAD].state) {
 
2162
                
 
2163
                    res->props[FILTER_PROP_DOWNLOAD].state =
 
2164
                        FILTER_PROP_STATE_DO;
 
2165
 
 
2166
                    MATCH_RULE(filter, r, res);
 
2167
                }
 
2168
            } else 
 
2169
            if (r->target == filter_nodownload) {
 
2170
                if (!res->props[FILTER_PROP_DOWNLOAD].state) {
 
2171
                
 
2172
                    res->props[FILTER_PROP_DOWNLOAD].state =
 
2173
                        FILTER_PROP_STATE_DONT;
 
2174
 
 
2175
                    MATCH_RULE(filter, r, res);
 
2176
                }
 
2177
            } else {
 
2178
                /*
 
2179
                 * We have a matched rule the target is not a builtin
 
2180
                 * rule, so it must be a subchain. We gosub.
 
2181
                 */
 
2182
                prop_count += filter_apply(r->target, rec, res);
 
2183
                r->match_count ++;
 
2184
            }
 
2185
        } else {
 
2186
            r->fail_count ++;
 
2187
        }
 
2188
 
 
2189
                list = g_list_next(list);
 
2190
        }
 
2191
    G_FREE_NULL(l_name);
 
2192
 
 
2193
    filter->visited = FALSE;
 
2194
    filter->fail_count += MAX_FILTER_PROP - prop_count;
 
2195
    filter->match_count += prop_count;
 
2196
    return prop_count;
 
2197
}
 
2198
 
 
2199
 
 
2200
 
 
2201
/*
 
2202
 * filter_record:
 
2203
 *
 
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.
 
2207
 */
 
2208
filter_result_t *filter_record(search_t *sch, record_t *rec)
 
2209
{
 
2210
    gboolean filtered;
 
2211
    filter_result_t *result;
 
2212
    gint i;
 
2213
 
 
2214
    g_assert(sch != NULL);
 
2215
    g_assert(rec != NULL);
 
2216
 
 
2217
    /*
 
2218
     * Initialize all properties with FILTER_PROP_STATE_UNKNOWN and
 
2219
     * the props_set count with 0;
 
2220
     */
 
2221
    result = g_new0(filter_result_t, 1);
 
2222
 
 
2223
    filtered =  
 
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));
 
2230
 
 
2231
    filter_apply(filter_global_pre, rec, result);
 
2232
 
 
2233
    /*
 
2234
     * If not decided check if the filters for this search apply.
 
2235
     */
 
2236
    if (result->props_set < MAX_FILTER_PROP)
 
2237
        filter_apply(sch->filter, rec, result);
 
2238
 
 
2239
    /*
 
2240
     * If it has not yet been decided, try the global filter
 
2241
     */
 
2242
        if (result->props_set < MAX_FILTER_PROP)
 
2243
                filter_apply(filter_global_post, rec, result);
 
2244
    
 
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");
 
2250
    }
 
2251
    */
 
2252
 
 
2253
    /*
 
2254
     * Set the defaults for the props that are still in UNKNOWN state.
 
2255
     */
 
2256
    for (i = 0; i < MAX_FILTER_PROP; i ++) {
 
2257
        switch(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 ++;
 
2263
            }
 
2264
            break;
 
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 ++;
 
2270
            }
 
2271
            break;
 
2272
        }
 
2273
    }
 
2274
 
 
2275
        return result;
 
2276
}
 
2277
 
 
2278
 
 
2279
 
 
2280
/*
 
2281
 * filters_shutdown
 
2282
 *
 
2283
 * Free global filters and save state.
 
2284
 */
 
2285
void filter_shutdown(void)
 
2286
{
 
2287
    GList *f;
 
2288
 
 
2289
    if (gui_debug >= 5)
 
2290
        printf("shutting down filters\n");
 
2291
 
 
2292
    /*
 
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.
 
2300
     */
 
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);
 
2304
 
 
2305
        /*
 
2306
         * Since filter_remove_rule modifies filter->ruleset, we
 
2307
         * have to copy the ruleset before we start puring.
 
2308
         */
 
2309
 
 
2310
        /*
 
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. 
 
2314
         */
 
2315
 
 
2316
                G_LIST_FOREACH_SWAPPED(copy, filter_remove_rule, filter);
 
2317
        g_list_free(copy);
 
2318
    }
 
2319
 
 
2320
    /*
 
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
 
2324
     * global filters;
 
2325
     */
 
2326
    for (f = filters; f != NULL; f = filters)
 
2327
        filter_free(f->data);
 
2328
}
 
2329
 
 
2330
 
 
2331
 
 
2332
/*
 
2333
 * filter_init
 
2334
 *
 
2335
 * Initialize global filters.
 
2336
 */
 
2337
void filter_init(void)
 
2338
{
 
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");
 
2346
 
 
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);
 
2354
 
 
2355
    filters_current = g_list_copy(filters);
 
2356
 
 
2357
    popup_filter_rule = create_popup_filter_rule();
 
2358
}
 
2359
 
 
2360
 
 
2361
 
 
2362
/*
 
2363
 * filter_update_targets:
 
2364
 *
 
2365
 * Trigger a rebuild of the target combos.
 
2366
 */
 
2367
void filter_update_targets(void)
 
2368
{
 
2369
    filter_gui_rebuild_target_combos(filters_current);
 
2370
}
 
2371
 
 
2372
 
 
2373
 
 
2374
/*
 
2375
 * filter_timer:
 
2376
 *
 
2377
 * Periodically update the filter display with current data
 
2378
 */
 
2379
void filter_timer(void)
 
2380
{
 
2381
    filter_gui_update_filter_stats();
 
2382
    filter_gui_update_rule_stats();
 
2383
}
 
2384
 
 
2385
 
 
2386
 
 
2387
/*
 
2388
 * filter_rule_reset_stats:
 
2389
 *
 
2390
 * Reset the rule stats for a given rule.
 
2391
 */
 
2392
inline void filter_rule_reset_stats(rule_t *rule)
 
2393
{
 
2394
    g_assert(rule != NULL);
 
2395
 
 
2396
    rule->match_count = rule->fail_count = 0;
 
2397
}
 
2398
 
 
2399
 
 
2400
 
 
2401
/*
 
2402
 * filter_reset_stats:
 
2403
 *
 
2404
 * Reset the stats for a given filter.
 
2405
 */
 
2406
inline void filter_reset_stats(filter_t *filter)
 
2407
{
 
2408
    g_assert(filter != NULL);
 
2409
 
 
2410
    filter->match_count = filter->fail_count = 0;
 
2411
}
 
2412
 
 
2413
 
 
2414
 
 
2415
/*
 
2416
 * filter_set_enabled:
 
2417
 *
 
2418
 * Change the "enabled" flag of a filter.
 
2419
 */
 
2420
void filter_set_enabled(filter_t *filter, gboolean active)
 
2421
{
 
2422
    shadow_t *shadow;
 
2423
    static gboolean locked = FALSE;
 
2424
 
 
2425
    g_assert(filter != NULL);
 
2426
 
 
2427
    if (locked)
 
2428
        return;
 
2429
 
 
2430
    locked = TRUE;
 
2431
 
 
2432
    shadow = shadow_find(filter);
 
2433
    if (shadow == NULL)
 
2434
        shadow = shadow_new(filter);
 
2435
    
 
2436
    if (active) {
 
2437
        set_flags(shadow->flags, FILTER_FLAG_ACTIVE);
 
2438
    } else {
 
2439
        clear_flags(shadow->flags, FILTER_FLAG_ACTIVE);
 
2440
    }
 
2441
 
 
2442
    filter_gui_filter_set_enabled(work_filter, active);
 
2443
 
 
2444
    locked = FALSE;
 
2445
}
 
2446
 
 
2447
/*
 
2448
 * filter_free_properties:
 
2449
 *
 
2450
 * Free a filter_result returned by filter_record
 
2451
 * after it has been processed.
 
2452
 */
 
2453
void filter_free_result(filter_result_t *res)
 
2454
{
 
2455
    gint i;
 
2456
 
 
2457
    g_assert(res != NULL);
 
2458
 
 
2459
    /*
 
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.
 
2463
     */
 
2464
    for (i = 0; i < MAX_FILTER_PROP; i ++) {
 
2465
        switch (i) {
 
2466
        case FILTER_PROP_DISPLAY:
 
2467
            break;
 
2468
        case FILTER_PROP_DOWNLOAD:
 
2469
            break;
 
2470
        default:
 
2471
            g_assert_not_reached();
 
2472
        };
 
2473
    }
 
2474
 
 
2475
    G_FREE_NULL(res);
 
2476
}
 
2477
 
 
2478
/*
 
2479
 * filter_is_valid_in_session:
 
2480
 *
 
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.
 
2484
 */
 
2485
gboolean filter_is_valid_in_session(filter_t *f)
 
2486
{
 
2487
    if (f == NULL)
 
2488
        return FALSE;
 
2489
    else
 
2490
        return g_list_find(filters_current, f) != NULL;
 
2491
}
 
2492
 
 
2493
/*
 
2494
 * filter_find_by_name_in_session:
 
2495
 *
 
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.
 
2499
 */
 
2500
filter_t *filter_find_by_name_in_session(gchar *name)
 
2501
{
 
2502
    GList *l;
 
2503
 
 
2504
    for (l = filters_current; l != NULL; l = l->next) {
 
2505
        filter_t *filter = (filter_t *) l->data;
 
2506
 
 
2507
        if (strcmp(filter->name, name) == 0)
 
2508
            return filter;
 
2509
    }
 
2510
    return NULL;
 
2511
}
 
2512
 
 
2513
gboolean filter_is_global(filter_t *f)
 
2514
{
 
2515
    return ((f == filter_global_pre) || (f == filter_global_post));
 
2516
}
 
2517
 
 
2518
gboolean filter_is_builtin(filter_t *f)
 
2519
{
 
2520
    return ((f == filter_show) || (f == filter_drop) || 
 
2521
            (f == filter_download) || (f == filter_nodownload) ||
 
2522
            (f == filter_return));
 
2523
}
 
2524
 
 
2525
inline filter_t *filter_get_drop_target(void)
 
2526
{
 
2527
    return filter_drop;
 
2528
}
 
2529
 
 
2530
inline filter_t *filter_get_show_target(void)
 
2531
{
 
2532
    return filter_show;
 
2533
}
 
2534
 
 
2535
inline filter_t *filter_get_download_target(void)
 
2536
{
 
2537
    return filter_download;
 
2538
}
 
2539
 
 
2540
inline filter_t *filter_get_nodownload_target(void)
 
2541
{
 
2542
    return filter_nodownload;
 
2543
}
 
2544
 
 
2545
inline filter_t *filter_get_return_target(void)
 
2546
{
 
2547
    return filter_return;
 
2548
}
 
2549
 
 
2550
inline filter_t *filter_get_global_pre(void)
 
2551
{
 
2552
    return filter_global_pre;
 
2553
}
 
2554
 
 
2555
inline filter_t *filter_get_global_post(void)
 
2556
{
 
2557
    return filter_global_post;
 
2558
}
 
2559
 
 
2560
/*
 
2561
 * Adds a drop SHA1 rule to specified filter.
 
2562
 */
 
2563
void filter_add_drop_sha1_rule(record_t *rec, filter_t *filter)
 
2564
{
 
2565
    rule_t *rule;
 
2566
 
 
2567
    g_assert(rec != NULL);
 
2568
    g_assert(filter != NULL);
 
2569
 
 
2570
    rule = filter_new_sha1_rule(rec->sha1, rec->name,
 
2571
        filter_get_drop_target(), RULE_FLAG_ACTIVE);
 
2572
 
 
2573
    filter_append_rule(filter, rule);
 
2574
}
 
2575
 
 
2576
/*
 
2577
 * Adds a drop filename rule to specified filter.
 
2578
 */
 
2579
void filter_add_drop_name_rule(record_t *rec, filter_t *filter)
 
2580
{
 
2581
    rule_t *rule;
 
2582
 
 
2583
    g_assert(rec != NULL);
 
2584
    g_assert(filter != NULL);
 
2585
 
 
2586
    rule = filter_new_text_rule(rec->name, RULE_TEXT_EXACT, TRUE,
 
2587
        filter_get_drop_target(), RULE_FLAG_ACTIVE);
 
2588
 
 
2589
    filter_append_rule(filter, rule);
 
2590
}
 
2591
 
 
2592
/*
 
2593
 * Adds a drop host rule to specified filter.
 
2594
 */
 
2595
void filter_add_drop_host_rule(record_t *rec, filter_t *filter)
 
2596
{
 
2597
    rule_t *rule;
 
2598
 
 
2599
    g_assert(rec != NULL);
 
2600
    g_assert(filter != NULL);
 
2601
 
 
2602
    rule = filter_new_ip_rule(rec->results_set->ip, 0xFFFFFFFF,
 
2603
        filter_get_drop_target(), RULE_FLAG_ACTIVE);
 
2604
 
 
2605
    filter_append_rule(filter, rule);
 
2606
}
 
2607
 
 
2608
/*
 
2609
 * Adds a download SHA1 rule to specified filter.
 
2610
 */
 
2611
void filter_add_download_sha1_rule(record_t *rec, filter_t *filter)
 
2612
{
 
2613
    g_assert(rec != NULL);
 
2614
    g_assert(filter != NULL);
 
2615
 
 
2616
    if (rec->sha1) {
 
2617
        rule_t *rule;
 
2618
 
 
2619
        rule = filter_new_sha1_rule(rec->sha1, rec->name,
 
2620
            filter_get_download_target(), RULE_FLAG_ACTIVE);
 
2621
 
 
2622
        filter_append_rule(filter, rule);
 
2623
    }
 
2624
}
 
2625
 
 
2626
/*
 
2627
 * Adds a download filename rule to specified filter.
 
2628
 */
 
2629
void filter_add_download_name_rule(record_t *rec, filter_t *filter)
 
2630
{
 
2631
    rule_t *rule;
 
2632
 
 
2633
    g_assert(rec != NULL);
 
2634
    g_assert(filter != NULL);
 
2635
 
 
2636
    rule = filter_new_text_rule(rec->name, RULE_TEXT_EXACT, TRUE,
 
2637
        filter_get_download_target(), RULE_FLAG_ACTIVE);
 
2638
 
 
2639
    filter_append_rule(filter, rule);
 
2640
}