Mercurial > noffle
annotate src/filter.c @ 185:fed1334d766b noffle
[svn] * src/client.c: Change variable only used on constant to 'const'.
* src/filter.c: Add a couple of 'return's after ASSERT() to remove
compiler warnings about functions needing returns.
* NEWS,TODO,configure,configure.in,noffle.conf.example,docs/NOTES,
docs/noffle.conf.5,src/client.c,src/configfile.c,src/content.c,
src/control.c,src/database.c,src/fetch.c,src/fetchlist.c,src/filter.c,
src/group.c,src/lock.c,src/log.c,src/log.h,src/noffle.c,src/outgoing.c,
src/post.c,src/protocol.c,src/request.c,src/server.c,src/util.c:
Debug logging is always compiled and selected via noffle.conf. All debug
logs are classified as all, none, config, control, expire, fetch,
filter, newsbase, noffle, post, protocol, requests and server.
author | bears |
---|---|
date | Sun, 05 Aug 2001 09:24:22 +0100 |
parents | 8897b7e3b108 |
children | a4e9a20e50e5 |
rev | line source |
---|---|
128 | 1 /* |
2 filter.c | |
3 | |
4 Article filtering. | |
5 | |
185
fed1334d766b
[svn] * src/client.c: Change variable only used on constant to 'const'.
bears
parents:
128
diff
changeset
|
6 $Id: filter.c 300 2001-08-05 08:24:22Z 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, | |
195 * returns its action. If no rule fires, return the default read mode. | |
196 */ | |
197 FilterAction | |
198 Flt_checkFilters( const char *thisGrp, const char *newsgroups, | |
199 const Over *ov, FetchMode mode ) | |
200 { | |
201 int i; | |
202 | |
203 for ( i = 0; i < filter.nFilters; i++ ) | |
204 if ( checkFilter( thisGrp, newsgroups, ov, filter.filters[ i ] ) ) | |
205 { | |
185
fed1334d766b
[svn] * src/client.c: Change variable only used on constant to 'const'.
bears
parents:
128
diff
changeset
|
206 Log_dbg( LOG_DBG_FILTER, |
fed1334d766b
[svn] * src/client.c: Change variable only used on constant to 'const'.
bears
parents:
128
diff
changeset
|
207 "Filter %d fired on message %s", |
fed1334d766b
[svn] * src/client.c: Change variable only used on constant to 'const'.
bears
parents:
128
diff
changeset
|
208 i, Ov_msgId( ov ) ); |
128 | 209 return filter.filters[ i ]->action; |
210 } | |
211 | |
212 switch( mode ) | |
213 { | |
214 case FULL: return FILTER_FULL; | |
215 case THREAD: return FILTER_THREAD; | |
216 case OVER: return FILTER_XOVER; | |
217 } | |
218 | |
219 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
|
220 return FILTER_FULL; /* Keep compiler quiet */ |
128 | 221 } |
222 | |
223 Filter * | |
224 new_Filter( void ) | |
225 { | |
226 Filter *f; | |
227 | |
228 if ( ! ( f = ( Filter * ) malloc( sizeof( Filter ) ) ) ) | |
229 { | |
230 Log_err( "Cannot allocate Filter" ); | |
231 exit( EXIT_FAILURE ); | |
232 } | |
233 f->nRules = 0; | |
234 f->maxRules = 0; | |
235 f->rules = NULL; | |
236 f->action = FILTER_FULL; | |
237 return f; | |
238 } | |
239 | |
240 void | |
241 del_Filter( Filter *f ) | |
242 { | |
243 if ( f == NULL ) | |
244 return; | |
245 | |
246 if ( f->rules != NULL ) | |
247 free( f->rules ); | |
248 free( f ); | |
249 } | |
250 | |
251 FilterAction | |
252 Flt_action( const Filter *f ) | |
253 { | |
254 return f->action; | |
255 } | |
256 | |
257 int | |
258 Flt_nRules( const Filter *f ) | |
259 { | |
260 return f->nRules; | |
261 } | |
262 | |
263 /* | |
264 * Do we have a rule requiring us to fetch the Newsgroups: headers of | |
265 * articles? | |
266 */ | |
267 Bool | |
268 Flt_getNewsgroups( void ) | |
269 { | |
270 return filter.needGroups; | |
271 } | |
272 | |
273 FilterRule | |
274 Flt_rule( const Filter *f, int ruleNo ) | |
275 { | |
276 ASSERT( ruleNo < f->nRules ); | |
277 return f->rules[ ruleNo ]; | |
278 } | |
279 | |
280 void | |
281 Flt_setAction( Filter *f, FilterAction action ) | |
282 { | |
283 f->action = action; | |
284 } | |
285 | |
286 void | |
287 Flt_addRule( Filter *f, FilterRule rule ) | |
288 { | |
289 /* Does the rule require Newsgroups: headers to be fetched? */ | |
290 if ( rule.type == RULE_NEWSGROUP || | |
291 ( rule.type >= RULE_XPOSTS_LT && rule.type <= RULE_XPOSTS_GT ) ) | |
292 filter.needGroups = TRUE; | |
293 | |
294 if ( f->nRules + 1 > f->maxRules ) | |
295 { | |
296 f->rules = | |
297 ( FilterRule * ) realloc( f->rules, | |
298 ( f->maxRules + 5 ) | |
299 * sizeof( FilterRule ) ); | |
300 | |
301 if ( f->rules == NULL ) | |
302 { | |
303 Log_err( "Could not realloc rule list" ); | |
304 exit( EXIT_FAILURE ); | |
305 } | |
306 f->maxRules += 5; | |
307 } | |
308 f->rules[ f->nRules++ ] = rule; | |
309 } | |
310 | |
311 |