/tags/release-1-1-2/noffle/src/filter.c
C | 323 lines | 250 code | 53 blank | 20 comment | 54 complexity | 0c911605b7a0efec85770cb8e6130c25 MD5 | raw file
Possible License(s): GPL-2.0
- /*
- filter.c
-
- Article filtering.
-
- $Id: filter.c 331 2001-11-22 12:04:45Z mirkol $
- */
- #if HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <ctype.h>
- #include "common.h"
- #include "filter.h"
- #include "itemlist.h"
- #include "log.h"
- #include "wildmat.h"
- #include "group.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 );
- case RULE_POST_STATUS:
- if ( Grp_postAllow( thisGrp ) == r->data.postAllow )
- return TRUE;
- return FALSE;
- }
- ASSERT( FALSE ); /* Shouldn't get here */
- return 0; /* Keep compiler quiet */
- }
- /* 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, or a rule specifying the default
- * action 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 ] ) )
- {
- FilterAction action = filter.filters[ i ]->action;
-
- Log_dbg( LOG_DBG_FILTER,
- "Filter %d fired on message %s",
- i, Ov_msgId( ov ) );
- if ( action == FILTER_DEFAULT )
- break;
- else
- return action;
- }
- switch( mode )
- {
- case FULL: return FILTER_FULL;
- case THREAD: return FILTER_THREAD;
- case OVER: return FILTER_XOVER;
- }
- ASSERT( FALSE ); /* Shouldn't get here */
- return FILTER_FULL; /* Keep compiler quiet */
- }
- 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_DEFAULT;
- 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;
- }