Mercurial > noffle
diff src/filter.c @ 128:8897b7e3b108 noffle
[svn] Add article filtering
author | bears |
---|---|
date | Wed, 09 Aug 2000 22:19:17 +0100 |
parents | |
children | fed1334d766b |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/filter.c Wed Aug 09 22:19:17 2000 +0100 @@ -0,0 +1,307 @@ +/* + filter.c + + Article filtering. + + $Id: filter.c 189 2000-08-09 21:19:17Z bears $ +*/ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include "filter.h" + +#include <ctype.h> +#include "common.h" +#include "itemlist.h" +#include "log.h" +#include "wildmat.h" + +struct +{ + int nFilters; + int maxFilters; + const Filter **filters; + Bool needGroups; +} filter = { 0, 0, NULL, FALSE }; + +static unsigned long +countGroups( const char *grps ) +{ + unsigned long res; + + res = 1; + while ( *grps != '\0' ) + { + if ( *grps == ',' ) + res++; + grps++; + } + + return res; +} +static unsigned long +countRefs( const char *refs ) +{ + unsigned long res; + Bool inRef; + + res = 0; + inRef = FALSE; + + while ( *refs != '\0' ) + { + if ( inRef ) + { + if ( *refs == '>' ) + { + inRef = FALSE; + res++; + } + } + else if ( *refs == '<' ) + inRef = TRUE; + refs++; + } + + return res; +} + +/* Check a single rule to see if it passes. */ +static Bool +checkRule( const char *thisGrp, const char *newsgroups, + const Over *ov, const FilterRule *r ) +{ + unsigned long ul; + ItemList *grps; + const char *p; + + switch( r->type ) + { + case RULE_NEWSGROUP: + if ( Wld_match( thisGrp, r->data.grp ) ) + return TRUE; + if ( newsgroups != NULL ) + { + grps = new_Itl( newsgroups, " ,\t" ); + for ( p = Itl_first( grps ); p != NULL; p = Itl_next( grps ) ) + if ( Wld_match( p, r->data.grp ) ) + return TRUE; + del_Itl( grps ); + } + return FALSE; + + case RULE_SUBJECT: + return ( regexec( &r->data.regex, Ov_subj( ov ), 0, NULL, 0 ) == 0 ); + + case RULE_FROM: + return ( regexec( &r->data.regex, Ov_from( ov ), 0, NULL, 0 ) == 0 ); + + case RULE_BYTES_LT: + return ( Ov_bytes( ov ) < r->data.amount ); + + case RULE_BYTES_EQ: + return ( Ov_bytes( ov ) == r->data.amount ); + + case RULE_BYTES_GT: + return ( Ov_bytes( ov ) > r->data.amount ); + + case RULE_LINES_LT: + return ( Ov_lines( ov ) < r->data.amount ); + + case RULE_LINES_EQ: + return ( Ov_lines( ov ) == r->data.amount ); + + case RULE_LINES_GT: + return ( Ov_lines( ov ) > r->data.amount ); + + case RULE_MSGID: + return ( regexec( &r->data.regex, Ov_msgId( ov ), 0, NULL, 0 ) == 0 ); + + case RULE_NOREFS_LT: + ul = countRefs( Ov_ref( ov ) ); + return ( ul < r->data.amount ); + + case RULE_NOREFS_EQ: + ul = countRefs( Ov_ref( ov ) ); + return ( ul == r->data.amount ); + + case RULE_NOREFS_GT: + ul = countRefs( Ov_ref( ov ) ); + return ( ul > r->data.amount ); + + case RULE_XPOSTS_LT: + if ( newsgroups == NULL ) + return FALSE; + ul = countGroups( newsgroups ); + return ( ul < r->data.amount ); + + case RULE_XPOSTS_EQ: + if ( newsgroups == NULL ) + return FALSE; + ul = countGroups( newsgroups ); + return ( ul == r->data.amount ); + + case RULE_XPOSTS_GT: + if ( newsgroups == NULL ) + return FALSE; + ul = countGroups( newsgroups ); + return ( ul > r->data.amount ); + } + + ASSERT( FALSE ); /* Shouldn't get here */ +} + +/* Check a single filter to see if it fires. */ +static Bool +checkFilter( const char *thisGrp, const char *newsgroups, + const Over *ov, const Filter *f ) +{ + int i; + + for ( i = 0; i < f->nRules; i++ ) + if ( ! checkRule( thisGrp, newsgroups, ov, &f->rules[i] ) ) + return FALSE; + + return TRUE; +} + +/* Add a filter to the list of filters. */ +void +Flt_addFilter( const Filter *f ) +{ + ASSERT( f != NULL ); + + if ( ( filter.nFilters + 1 ) > filter.maxFilters ) + { + filter.filters = + ( const Filter ** ) realloc( filter.filters, + ( filter.maxFilters + 5 ) + * sizeof( Filter * ) ); + if ( filter.filters == NULL ) + { + Log_err( "Could not realloc filter list" ); + exit( EXIT_FAILURE ); + } + filter.maxFilters += 5; + } + filter.filters[ filter.nFilters++ ] = f; +} + +/* + * Run the rules over the supplied overview. If a specific rule fires, + * returns its action. If no rule fires, return the default read mode. + */ +FilterAction +Flt_checkFilters( const char *thisGrp, const char *newsgroups, + const Over *ov, FetchMode mode ) +{ + int i; + + for ( i = 0; i < filter.nFilters; i++ ) + if ( checkFilter( thisGrp, newsgroups, ov, filter.filters[ i ] ) ) + { + Log_dbg( "Filter %d fired on message %s", i, Ov_msgId( ov ) ); + return filter.filters[ i ]->action; + } + + switch( mode ) + { + case FULL: return FILTER_FULL; + case THREAD: return FILTER_THREAD; + case OVER: return FILTER_XOVER; + } + + ASSERT( FALSE ); /* Shouldn't get here */ +} + +Filter * +new_Filter( void ) +{ + Filter *f; + + if ( ! ( f = ( Filter * ) malloc( sizeof( Filter ) ) ) ) + { + Log_err( "Cannot allocate Filter" ); + exit( EXIT_FAILURE ); + } + f->nRules = 0; + f->maxRules = 0; + f->rules = NULL; + f->action = FILTER_FULL; + return f; +} + +void +del_Filter( Filter *f ) +{ + if ( f == NULL ) + return; + + if ( f->rules != NULL ) + free( f->rules ); + free( f ); +} + +FilterAction +Flt_action( const Filter *f ) +{ + return f->action; +} + +int +Flt_nRules( const Filter *f ) +{ + return f->nRules; +} + +/* + * Do we have a rule requiring us to fetch the Newsgroups: headers of + * articles? + */ +Bool +Flt_getNewsgroups( void ) +{ + return filter.needGroups; +} + +FilterRule +Flt_rule( const Filter *f, int ruleNo ) +{ + ASSERT( ruleNo < f->nRules ); + return f->rules[ ruleNo ]; +} + +void +Flt_setAction( Filter *f, FilterAction action ) +{ + f->action = action; +} + +void +Flt_addRule( Filter *f, FilterRule rule ) +{ + /* Does the rule require Newsgroups: headers to be fetched? */ + if ( rule.type == RULE_NEWSGROUP || + ( rule.type >= RULE_XPOSTS_LT && rule.type <= RULE_XPOSTS_GT ) ) + filter.needGroups = TRUE; + + if ( f->nRules + 1 > f->maxRules ) + { + f->rules = + ( FilterRule * ) realloc( f->rules, + ( f->maxRules + 5 ) + * sizeof( FilterRule ) ); + + if ( f->rules == NULL ) + { + Log_err( "Could not realloc rule list" ); + exit( EXIT_FAILURE ); + } + f->maxRules += 5; + } + f->rules[ f->nRules++ ] = rule; +} + +