Mercurial > noffle
annotate src/filter.c @ 191:28488e0e3630 noffle
[svn] * src/group.h,src/group.c,src/noffle.c,src/server.c: Grp_setLastAccess is
only ever called with last param as time(NULL), so remove it and call
time() inside the implementation of Grp_setLastAccess.
* src/client.c,src/group.h,src/group.c,src/noffle.c,src/post.c: Groups are
automatically unsubscribed when the last access to the group is older
than a particular threshold. However, for very low traffic groups, the
last access may exceed the threshold simply because there has been no new
article posted. In this case, rather than unsubscribe, update the group
last access time. This means that groups are now only unsubscribed if
the last access exceeds the threshold AND articles have arrived in the
group since. Add Grp_setLastPostTime() to track the last time an article
arrived in the group.
author | bears |
---|---|
date | Sat, 20 Oct 2001 14:23:46 +0100 |
parents | fed1334d766b |
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 |