Mercurial > noffle
annotate src/filter.c @ 194:a4e9a20e50e5 noffle
[svn] * docs/noffle.conf.5,src/configfile.c,src/filter.h,src/filter.c:
Contrary to the documentation, the action of a filter if not specified
was 'full'. Add a new 'default' action which makes the action that of the
group's subscription mode. Make this the default action, and allow
'default' to be specified explicitly as the action in the filter
definition. Adapted from patch submitted by Mirko Liss. Thanks, Mirko.
* docs/noffle.conf.5: Correct small typo.
author | bears |
---|---|
date | Tue, 30 Oct 2001 12:42:13 +0000 |
parents | fed1334d766b |
children | 24d4cd032da5 |
rev | line source |
---|---|
128 | 1 /* |
2 filter.c | |
3 | |
4 Article filtering. | |
5 | |
194
a4e9a20e50e5
[svn] * docs/noffle.conf.5,src/configfile.c,src/filter.h,src/filter.c:
bears
parents:
185
diff
changeset
|
6 $Id: filter.c 313 2001-10-30 12:42:13Z bears $ |
128 | 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 */ | |
185
fed1334d766b
[svn] * src/client.c: Change variable only used on constant to 'const'.
bears
parents:
128
diff
changeset
|
154 return 0; /* Keep compiler quiet */ |
128 | 155 } |
156 | |
157 /* Check a single filter to see if it fires. */ | |
158 static Bool | |
159 checkFilter( const char *thisGrp, const char *newsgroups, | |
160 const Over *ov, const Filter *f ) | |
161 { | |
162 int i; | |
163 | |
164 for ( i = 0; i < f->nRules; i++ ) | |
165 if ( ! checkRule( thisGrp, newsgroups, ov, &f->rules[i] ) ) | |
166 return FALSE; | |
167 | |
168 return TRUE; | |
169 } | |
170 | |
171 /* Add a filter to the list of filters. */ | |
172 void | |
173 Flt_addFilter( const Filter *f ) | |
174 { | |
175 ASSERT( f != NULL ); | |
176 | |
177 if ( ( filter.nFilters + 1 ) > filter.maxFilters ) | |
178 { | |
179 filter.filters = | |
180 ( const Filter ** ) realloc( filter.filters, | |
181 ( filter.maxFilters + 5 ) | |
182 * sizeof( Filter * ) ); | |
183 if ( filter.filters == NULL ) | |
184 { | |
185 Log_err( "Could not realloc filter list" ); | |
186 exit( EXIT_FAILURE ); | |
187 } | |
188 filter.maxFilters += 5; | |
189 } | |
190 filter.filters[ filter.nFilters++ ] = f; | |
191 } | |
192 | |
193 /* | |
194 * Run the rules over the supplied overview. If a specific rule fires, | |
194
a4e9a20e50e5
[svn] * docs/noffle.conf.5,src/configfile.c,src/filter.h,src/filter.c:
bears
parents:
185
diff
changeset
|
195 * returns its action. If no rule fires, or a rule specifying the default |
a4e9a20e50e5
[svn] * docs/noffle.conf.5,src/configfile.c,src/filter.h,src/filter.c:
bears
parents:
185
diff
changeset
|
196 * action fires, return the default read mode. |
128 | 197 */ |
198 FilterAction | |
199 Flt_checkFilters( const char *thisGrp, const char *newsgroups, | |
200 const Over *ov, FetchMode mode ) | |
201 { | |
202 int i; | |
203 | |
204 for ( i = 0; i < filter.nFilters; i++ ) | |
205 if ( checkFilter( thisGrp, newsgroups, ov, filter.filters[ i ] ) ) | |
206 { | |
194
a4e9a20e50e5
[svn] * docs/noffle.conf.5,src/configfile.c,src/filter.h,src/filter.c:
bears
parents:
185
diff
changeset
|
207 FilterAction action = filter.filters[ i ]->action; |
a4e9a20e50e5
[svn] * docs/noffle.conf.5,src/configfile.c,src/filter.h,src/filter.c:
bears
parents:
185
diff
changeset
|
208 |
185
fed1334d766b
[svn] * src/client.c: Change variable only used on constant to 'const'.
bears
parents:
128
diff
changeset
|
209 Log_dbg( LOG_DBG_FILTER, |
fed1334d766b
[svn] * src/client.c: Change variable only used on constant to 'const'.
bears
parents:
128
diff
changeset
|
210 "Filter %d fired on message %s", |
fed1334d766b
[svn] * src/client.c: Change variable only used on constant to 'const'.
bears
parents:
128
diff
changeset
|
211 i, Ov_msgId( ov ) ); |
194
a4e9a20e50e5
[svn] * docs/noffle.conf.5,src/configfile.c,src/filter.h,src/filter.c:
bears
parents:
185
diff
changeset
|
212 if ( action == FILTER_DEFAULT ) |
a4e9a20e50e5
[svn] * docs/noffle.conf.5,src/configfile.c,src/filter.h,src/filter.c:
bears
parents:
185
diff
changeset
|
213 break; |
a4e9a20e50e5
[svn] * docs/noffle.conf.5,src/configfile.c,src/filter.h,src/filter.c:
bears
parents:
185
diff
changeset
|
214 else |
a4e9a20e50e5
[svn] * docs/noffle.conf.5,src/configfile.c,src/filter.h,src/filter.c:
bears
parents:
185
diff
changeset
|
215 return action; |
128 | 216 } |
217 | |
218 switch( mode ) | |
219 { | |
220 case FULL: return FILTER_FULL; | |
221 case THREAD: return FILTER_THREAD; | |
222 case OVER: return FILTER_XOVER; | |
223 } | |
224 | |
225 ASSERT( FALSE ); /* Shouldn't get here */ | |
185
fed1334d766b
[svn] * src/client.c: Change variable only used on constant to 'const'.
bears
parents:
128
diff
changeset
|
226 return FILTER_FULL; /* Keep compiler quiet */ |
128 | 227 } |
228 | |
229 Filter * | |
230 new_Filter( void ) | |
231 { | |
232 Filter *f; | |
233 | |
234 if ( ! ( f = ( Filter * ) malloc( sizeof( Filter ) ) ) ) | |
235 { | |
236 Log_err( "Cannot allocate Filter" ); | |
237 exit( EXIT_FAILURE ); | |
238 } | |
239 f->nRules = 0; | |
240 f->maxRules = 0; | |
241 f->rules = NULL; | |
194
a4e9a20e50e5
[svn] * docs/noffle.conf.5,src/configfile.c,src/filter.h,src/filter.c:
bears
parents:
185
diff
changeset
|
242 f->action = FILTER_DEFAULT; |
128 | 243 return f; |
244 } | |
245 | |
246 void | |
247 del_Filter( Filter *f ) | |
248 { | |
249 if ( f == NULL ) | |
250 return; | |
251 | |
252 if ( f->rules != NULL ) | |
253 free( f->rules ); | |
254 free( f ); | |
255 } | |
256 | |
257 FilterAction | |
258 Flt_action( const Filter *f ) | |
259 { | |
260 return f->action; | |
261 } | |
262 | |
263 int | |
264 Flt_nRules( const Filter *f ) | |
265 { | |
266 return f->nRules; | |
267 } | |
268 | |
269 /* | |
270 * Do we have a rule requiring us to fetch the Newsgroups: headers of | |
271 * articles? | |
272 */ | |
273 Bool | |
274 Flt_getNewsgroups( void ) | |
275 { | |
276 return filter.needGroups; | |
277 } | |
278 | |
279 FilterRule | |
280 Flt_rule( const Filter *f, int ruleNo ) | |
281 { | |
282 ASSERT( ruleNo < f->nRules ); | |
283 return f->rules[ ruleNo ]; | |
284 } | |
285 | |
286 void | |
287 Flt_setAction( Filter *f, FilterAction action ) | |
288 { | |
289 f->action = action; | |
290 } | |
291 | |
292 void | |
293 Flt_addRule( Filter *f, FilterRule rule ) | |
294 { | |
295 /* Does the rule require Newsgroups: headers to be fetched? */ | |
296 if ( rule.type == RULE_NEWSGROUP || | |
297 ( rule.type >= RULE_XPOSTS_LT && rule.type <= RULE_XPOSTS_GT ) ) | |
298 filter.needGroups = TRUE; | |
299 | |
300 if ( f->nRules + 1 > f->maxRules ) | |
301 { | |
302 f->rules = | |
303 ( FilterRule * ) realloc( f->rules, | |
304 ( f->maxRules + 5 ) | |
305 * sizeof( FilterRule ) ); | |
306 | |
307 if ( f->rules == NULL ) | |
308 { | |
309 Log_err( "Could not realloc rule list" ); | |
310 exit( EXIT_FAILURE ); | |
311 } | |
312 f->maxRules += 5; | |
313 } | |
314 f->rules[ f->nRules++ ] = rule; | |
315 } | |
316 | |
317 |