Mercurial > noffle
view 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 source
/* 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; }