diff options
Diffstat (limited to 'src/filter.c')
-rw-r--r-- | src/filter.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/src/filter.c b/src/filter.c new file mode 100644 index 0000000..9af451f --- /dev/null +++ b/src/filter.c @@ -0,0 +1,181 @@ +/* iksemel (XML parser for Jabber) +** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net> +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU Lesser General Public License. +*/ + +#include "common.h" +#include "iksemel.h" + +struct iksrule_struct { + struct iksrule_struct *next, *prev; + ikstack *s; + void *user_data; + iksFilterHook *filterHook; + char *id; + char *from; + char *ns; + int score; + int rules; + enum ikstype type; + enum iksubtype subtype; +}; + +struct iksfilter_struct { + iksrule *rules; + iksrule *last_rule; +}; + +iksfilter * +iks_filter_new (void) +{ + iksfilter *f; + + f = iks_malloc (sizeof (iksfilter)); + if (!f) return NULL; + memset (f, 0, sizeof (iksfilter)); + + return f; +} + +iksrule * +iks_filter_add_rule (iksfilter *f, iksFilterHook *filterHook, void *user_data, ...) +{ + ikstack *s; + iksrule *rule; + va_list ap; + int type; + + s = iks_stack_new (sizeof (iksrule), DEFAULT_RULE_CHUNK_SIZE); + if (!s) return NULL; + rule = iks_stack_alloc (s, sizeof (iksrule)); + memset (rule, 0, sizeof (iksrule)); + rule->s = s; + rule->user_data = user_data; + rule->filterHook = filterHook; + + va_start (ap, user_data); + while (1) { + type = va_arg (ap, int); + if (IKS_RULE_DONE == type) break; + rule->rules += type; + switch (type) { + case IKS_RULE_TYPE: + rule->type = va_arg (ap, int); + break; + case IKS_RULE_SUBTYPE: + rule->subtype = va_arg (ap, int); + break; + case IKS_RULE_ID: + rule->id = iks_stack_strdup (s, va_arg (ap, char *), 0); + break; + case IKS_RULE_NS: + rule->ns = iks_stack_strdup (s, va_arg (ap, char *), 0); + break; + case IKS_RULE_FROM: + rule->from = iks_stack_strdup (s, va_arg (ap, char *), 0); + break; + case IKS_RULE_FROM_PARTIAL: + rule->from = iks_stack_strdup (s, va_arg (ap, char *), 0); + break; + } + } + va_end (ap); + + if (!f->rules) f->rules = rule; + if (f->last_rule) f->last_rule->next = rule; + rule->prev = f->last_rule; + f->last_rule = rule; + return rule; +} + +void +iks_filter_remove_rule (iksfilter *f, iksrule *rule) +{ + if (rule->prev) rule->prev->next = rule->next; + if (rule->next) rule->next->prev = rule->prev; + if (f->rules == rule) f->rules = rule->next; + if (f->last_rule == rule) f->last_rule = rule->prev; + iks_stack_delete (rule->s); +} + +void +iks_filter_remove_hook (iksfilter *f, iksFilterHook *filterHook) +{ + iksrule *rule, *tmp; + + rule = f->rules; + while (rule) { + tmp = rule->next; + if (rule->filterHook == filterHook) iks_filter_remove_rule (f, rule); + rule = tmp; + } +} + +void +iks_filter_packet (iksfilter *f, ikspak *pak) +{ + iksrule *rule, *max_rule; + int fail, score, max_score; + + rule = f->rules; + max_rule = NULL; + max_score = 0; + while (rule) { + score = 0; + fail = 0; + if (rule->rules & IKS_RULE_TYPE) { + if (rule->type == pak->type) score += 1; else fail = 1; + } + if (rule->rules & IKS_RULE_SUBTYPE) { + if (rule->subtype == pak->subtype) score += 2; else fail = 1; + } + if (rule->rules & IKS_RULE_ID) { + if (iks_strcmp (rule->id, pak->id) == 0) score += 16; else fail = 1; + } + if (rule->rules & IKS_RULE_NS) { + if (iks_strcmp (rule->ns, pak->ns) == 0) score += 4; else fail = 1; + } + if (rule->rules & IKS_RULE_FROM) { + if (pak->from && iks_strcmp (rule->from, pak->from->full) == 0) score += 8; else fail = 1; + } + if (rule->rules & IKS_RULE_FROM_PARTIAL) { + if (pak->from && iks_strcmp (rule->from, pak->from->partial) == 0) score += 8; else fail = 1; + } + if (fail != 0) score = 0; + rule->score = score; + if (score > max_score) { + max_rule = rule; + max_score = score; + } + rule = rule->next; + } + while (max_rule) { + if (IKS_FILTER_EAT == max_rule->filterHook (max_rule->user_data, pak)) return; + max_rule->score = 0; + max_rule = NULL; + max_score = 0; + rule = f->rules; + while (rule) { + if (rule->score > max_score) { + max_rule = rule; + max_score = rule->score; + } + rule = rule->next; + } + } +} + +void +iks_filter_delete (iksfilter *f) +{ + iksrule *rule, *tmp; + + rule = f->rules; + while (rule) { + tmp = rule->next; + iks_stack_delete (rule->s); + rule = tmp; + } + iks_free (f); +} |