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;
+}
+
+