comparison src/filter.c @ 128:8897b7e3b108 noffle

[svn] Add article filtering
author bears
date Wed, 09 Aug 2000 22:19:17 +0100
parents
children fed1334d766b
comparison
equal deleted inserted replaced
127:3c71e28c8eef 128:8897b7e3b108
1 /*
2 filter.c
3
4 Article filtering.
5
6 $Id: filter.c 189 2000-08-09 21:19:17Z bears $
7 */
8
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include "filter.h"
14
15 #include <ctype.h>
16 #include "common.h"
17 #include "itemlist.h"
18 #include "log.h"
19 #include "wildmat.h"
20
21 struct
22 {
23 int nFilters;
24 int maxFilters;
25 const Filter **filters;
26 Bool needGroups;
27 } filter = { 0, 0, NULL, FALSE };
28
29 static unsigned long
30 countGroups( const char *grps )
31 {
32 unsigned long res;
33
34 res = 1;
35 while ( *grps != '\0' )
36 {
37 if ( *grps == ',' )
38 res++;
39 grps++;
40 }
41
42 return res;
43 }
44 static unsigned long
45 countRefs( const char *refs )
46 {
47 unsigned long res;
48 Bool inRef;
49
50 res = 0;
51 inRef = FALSE;
52
53 while ( *refs != '\0' )
54 {
55 if ( inRef )
56 {
57 if ( *refs == '>' )
58 {
59 inRef = FALSE;
60 res++;
61 }
62 }
63 else if ( *refs == '<' )
64 inRef = TRUE;
65 refs++;
66 }
67
68 return res;
69 }
70
71 /* Check a single rule to see if it passes. */
72 static Bool
73 checkRule( const char *thisGrp, const char *newsgroups,
74 const Over *ov, const FilterRule *r )
75 {
76 unsigned long ul;
77 ItemList *grps;
78 const char *p;
79
80 switch( r->type )
81 {
82 case RULE_NEWSGROUP:
83 if ( Wld_match( thisGrp, r->data.grp ) )
84 return TRUE;
85 if ( newsgroups != NULL )
86 {
87 grps = new_Itl( newsgroups, " ,\t" );
88 for ( p = Itl_first( grps ); p != NULL; p = Itl_next( grps ) )
89 if ( Wld_match( p, r->data.grp ) )
90 return TRUE;
91 del_Itl( grps );
92 }
93 return FALSE;
94
95 case RULE_SUBJECT:
96 return ( regexec( &r->data.regex, Ov_subj( ov ), 0, NULL, 0 ) == 0 );
97
98 case RULE_FROM:
99 return ( regexec( &r->data.regex, Ov_from( ov ), 0, NULL, 0 ) == 0 );
100
101 case RULE_BYTES_LT:
102 return ( Ov_bytes( ov ) < r->data.amount );
103
104 case RULE_BYTES_EQ:
105 return ( Ov_bytes( ov ) == r->data.amount );
106
107 case RULE_BYTES_GT:
108 return ( Ov_bytes( ov ) > r->data.amount );
109
110 case RULE_LINES_LT:
111 return ( Ov_lines( ov ) < r->data.amount );
112
113 case RULE_LINES_EQ:
114 return ( Ov_lines( ov ) == r->data.amount );
115
116 case RULE_LINES_GT:
117 return ( Ov_lines( ov ) > r->data.amount );
118
119 case RULE_MSGID:
120 return ( regexec( &r->data.regex, Ov_msgId( ov ), 0, NULL, 0 ) == 0 );
121
122 case RULE_NOREFS_LT:
123 ul = countRefs( Ov_ref( ov ) );
124 return ( ul < r->data.amount );
125
126 case RULE_NOREFS_EQ:
127 ul = countRefs( Ov_ref( ov ) );
128 return ( ul == r->data.amount );
129
130 case RULE_NOREFS_GT:
131 ul = countRefs( Ov_ref( ov ) );
132 return ( ul > r->data.amount );
133
134 case RULE_XPOSTS_LT:
135 if ( newsgroups == NULL )
136 return FALSE;
137 ul = countGroups( newsgroups );
138 return ( ul < r->data.amount );
139
140 case RULE_XPOSTS_EQ:
141 if ( newsgroups == NULL )
142 return FALSE;
143 ul = countGroups( newsgroups );
144 return ( ul == r->data.amount );
145
146 case RULE_XPOSTS_GT:
147 if ( newsgroups == NULL )
148 return FALSE;
149 ul = countGroups( newsgroups );
150 return ( ul > r->data.amount );
151 }
152
153 ASSERT( FALSE ); /* Shouldn't get here */
154 }
155
156 /* Check a single filter to see if it fires. */
157 static Bool
158 checkFilter( const char *thisGrp, const char *newsgroups,
159 const Over *ov, const Filter *f )
160 {
161 int i;
162
163 for ( i = 0; i < f->nRules; i++ )
164 if ( ! checkRule( thisGrp, newsgroups, ov, &f->rules[i] ) )
165 return FALSE;
166
167 return TRUE;
168 }
169
170 /* Add a filter to the list of filters. */
171 void
172 Flt_addFilter( const Filter *f )
173 {
174 ASSERT( f != NULL );
175
176 if ( ( filter.nFilters + 1 ) > filter.maxFilters )
177 {
178 filter.filters =
179 ( const Filter ** ) realloc( filter.filters,
180 ( filter.maxFilters + 5 )
181 * sizeof( Filter * ) );
182 if ( filter.filters == NULL )
183 {
184 Log_err( "Could not realloc filter list" );
185 exit( EXIT_FAILURE );
186 }
187 filter.maxFilters += 5;
188 }
189 filter.filters[ filter.nFilters++ ] = f;
190 }
191
192 /*
193 * Run the rules over the supplied overview. If a specific rule fires,
194 * returns its action. If no rule fires, return the default read mode.
195 */
196 FilterAction
197 Flt_checkFilters( const char *thisGrp, const char *newsgroups,
198 const Over *ov, FetchMode mode )
199 {
200 int i;
201
202 for ( i = 0; i < filter.nFilters; i++ )
203 if ( checkFilter( thisGrp, newsgroups, ov, filter.filters[ i ] ) )
204 {
205 Log_dbg( "Filter %d fired on message %s", i, Ov_msgId( ov ) );
206 return filter.filters[ i ]->action;
207 }
208
209 switch( mode )
210 {
211 case FULL: return FILTER_FULL;
212 case THREAD: return FILTER_THREAD;
213 case OVER: return FILTER_XOVER;
214 }
215
216 ASSERT( FALSE ); /* Shouldn't get here */
217 }
218
219 Filter *
220 new_Filter( void )
221 {
222 Filter *f;
223
224 if ( ! ( f = ( Filter * ) malloc( sizeof( Filter ) ) ) )
225 {
226 Log_err( "Cannot allocate Filter" );
227 exit( EXIT_FAILURE );
228 }
229 f->nRules = 0;
230 f->maxRules = 0;
231 f->rules = NULL;
232 f->action = FILTER_FULL;
233 return f;
234 }
235
236 void
237 del_Filter( Filter *f )
238 {
239 if ( f == NULL )
240 return;
241
242 if ( f->rules != NULL )
243 free( f->rules );
244 free( f );
245 }
246
247 FilterAction
248 Flt_action( const Filter *f )
249 {
250 return f->action;
251 }
252
253 int
254 Flt_nRules( const Filter *f )
255 {
256 return f->nRules;
257 }
258
259 /*
260 * Do we have a rule requiring us to fetch the Newsgroups: headers of
261 * articles?
262 */
263 Bool
264 Flt_getNewsgroups( void )
265 {
266 return filter.needGroups;
267 }
268
269 FilterRule
270 Flt_rule( const Filter *f, int ruleNo )
271 {
272 ASSERT( ruleNo < f->nRules );
273 return f->rules[ ruleNo ];
274 }
275
276 void
277 Flt_setAction( Filter *f, FilterAction action )
278 {
279 f->action = action;
280 }
281
282 void
283 Flt_addRule( Filter *f, FilterRule rule )
284 {
285 /* Does the rule require Newsgroups: headers to be fetched? */
286 if ( rule.type == RULE_NEWSGROUP ||
287 ( rule.type >= RULE_XPOSTS_LT && rule.type <= RULE_XPOSTS_GT ) )
288 filter.needGroups = TRUE;
289
290 if ( f->nRules + 1 > f->maxRules )
291 {
292 f->rules =
293 ( FilterRule * ) realloc( f->rules,
294 ( f->maxRules + 5 )
295 * sizeof( FilterRule ) );
296
297 if ( f->rules == NULL )
298 {
299 Log_err( "Could not realloc rule list" );
300 exit( EXIT_FAILURE );
301 }
302 f->maxRules += 5;
303 }
304 f->rules[ f->nRules++ ] = rule;
305 }
306
307