leafnode  1.12.0
About: Leafnode is a store & forward NNTP proxy for small (dialup) sites.
  Fossies Dox: leafnode-1.12.0.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

applyfilter.c
Go to the documentation of this file.
1/*
2 * apply filter file to all files in a newsgroup
3 *
4 * Written by Cornelius Krasel <krasel@wpxx02.toxi.uni-wuerzburg.de>.
5 * Copyright 1999.
6 *
7 * Modified and copyright of the modifications 2002 by Matthias Andree
8 * <matthias.andree@gmx.de> and Ralf Wildenhues <ralf.wildenhues@gmx.de>
9 *
10 * Modified and copyright of the modifications 2002 - 2021 by Matthias Andree
11 *
12 * See file COPYING for restrictions on the use of this software.
13 */
14
15#include "leafnode.h"
16#include "ln_log.h"
17
18#include <sys/stat.h>
19#include <sys/types.h>
20#include <ctype.h>
21#include "system.h"
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <utime.h>
27
28#define MAXHEADERSIZE 2047
29
30int debug = 0;
32
33/* read from file f into malloced buffer *bufp of size *size
34 * up to delim or EOF. Buffer is adjusted to fit input.
35 * return pointer to match or end of file, NULL in case of error
36 */
37static /*@null@*/ /*@dependent@*/ char *
38readtodelim(FILE *f, const char *name, /*@unique@*/ /*@observer@*/ const char *delim,
39 char **bufp, size_t *size)
40{
41 size_t dlen = strlen(delim) - 1;
42 size_t nread, res;
43 char *k;
44
45 nread = 0;
46 if (*size < 1 || *bufp == NULL)
47 *bufp = critmalloc((*size = MAXHEADERSIZE), "readtodelim");
48
49 /*@+loopexec@*/
50 for (;;) {
51 res = fread(*bufp + nread, 1, *size - nread - 1, f);
52 (*bufp)[nread + res] = '\0';
53 /* skip as much as possible */
54 k = strstr(nread > dlen ? *bufp + nread - dlen : *bufp, delim);
55 if (ferror(f)) {
56 printf("error reading %s\n", name);
57 clearerr(f);
58 return k;
59 }
60 nread += res;
61 if (feof(f)) {
62 clearerr(f);
63 return k != NULL ? k : *bufp + nread;
64 }
65 if (k != NULL) {
66 return k;
67 }
68 /* must read more */
69 *bufp = critrealloc(*bufp, (*size)*=2, "readtodelim");
70 }
71 /*@=loopexec@*/
72}
73
74/** unfold a header string \a t in-place.
75 * CRLF are converted to LF. */
76static void unfold(char *t)
77{
78 char *i;
79
80 for (i = t; *i ; i++) {
81 if (i[0] == '\r' && i[1] == '\n')
82 continue;
83 if (i[0] == '\n'
84 && (i[1] == ' ' || i[1] == '\t'))
85 continue;
86 *t = *i;
87 t++;
88 }
89 *t = '\0';
90}
91
92/* read article headers, cut off body
93 * return 0 for success, -1 for error, -2 for article without body
94 */
95static int
96readheaders(FILE *f, /*@unique@*/ const char *name, char **bufp, size_t *size)
97{
98 char *k = readtodelim(f, name, "\n\n", bufp, size);
99 if (k != NULL) {
100 /* unfold lines */
101 unfold(*bufp);
102 if (*k == '\0')
103 return -2;
104 else {
105 k[1] = '\0';
106 return 0;
107 }
108 } else {
109 return -1;
110 }
111}
112
113int
114main(int argc, char *argv[])
115{
116 const char c[] = "-\\|/";
117 int i, score, option, deleted, kept;
118 unsigned long n;
119 char *msgid;
120 char *l;
121 size_t lsize;
122 const char *msgidpath = "";
123 FILE *f;
124 DIR *d;
125 struct dirent *de;
126 struct stat st;
127 struct utimbuf u;
128 struct newsgroup *g;
129
130 myopenlog("applyfilter");
131
132 if (!initvars(argv[0]))
133 exit(1);
134
135 while ((option = getopt(argc, argv, "v")) != -1) {
136 if (option == 'v')
137 verbose++;
138 else {
139 printf("Usage: %s newsgroup\n", argv[0]);
140 exit(1);
141 }
142 }
143
144 if (argv[optind] == NULL) {
145 printf("Usage: %s newsgroup\n", argv[0]);
146 exit(1);
147 }
148
149 if (!readconfig(0)) {
150 printf("Reading configuration failed, exiting "
151 "(see syslog for more information).\n");
152 exit(2);
153 }
154 freeservers();
155
156 if (filterfile)
158 else {
159 printf("Nothing to filter -- no filterfile found.\n");
160 freeconfig();
161 exit(0);
162 }
163
164 if (try_lock(timeout_lock)) {
165 printf("Cannot obtain lock file, aborting.\n");
166 exit(1);
167 }
168
169 readactive();
170 if (!active) {
171 printf("Problem reading active file.\n");
172 freeconfig();
173 exit(1);
174 }
175
176 g = findgroup(argv[optind]);
177 if (!g) {
178 printf("Newsgroups %s not found in active file.\n", argv[optind]);
179 unlink(lockfile);
180 exit(1);
181 }
182
183 /* to automatically rise the low water mark, we reset g->first to
184 * ULONG_MAX. */
185 g->first = ULONG_MAX;
186 /* We used to do g->last = 0; but that can severely confuse news
187 * readers, we don't ever want to decrease the high water mark. */
188 if (!chdirgroup(g->name, FALSE)) {
189 printf("No such newsgroup: %s\n", g->name);
190 unlink(lockfile);
191 exit(1);
192 }
193 if (!(d = opendir("."))) {
194 printf("Unable to open directory for newsgroup %s\n", g->name);
195 unlink(lockfile);
196 exit(1);
197 }
198
199 i = 0;
200 deleted = 0;
201 kept = 0;
202 lsize = MAXHEADERSIZE + 1;
203 l = critmalloc(lsize, "Space for article");
204 while ((de = readdir(d)) != NULL) {
205 if (!isdigit((unsigned char)de->d_name[0])) {
206 /* no need to stat file */
207 continue;
208 }
209 switch (verbose) {
210 case 1:{
211 printf("%c\b", c[i % 4]);
212 fflush(stdout);
213 i++;
214 break;
215 }
216 case 2:{
217 printf("%s\n", de->d_name);
218 }
219 }
220 if ((f = fopen(de->d_name, "r")) != NULL
221 && fstat(fileno(f), &st) == 0
222 && S_ISREG(st.st_mode))
223 {
224 switch (readheaders(f, de->d_name, &l, &lsize)) {
225 case 0:
226 case -2:
227 score = dofilter((unsigned char *)l);
228 break;
229 case -1:
230 score = -1; /* FIXME: how to handle read error? */
231 break;
232 default:
233 /* this branch will never be executed, but
234 * eliminates a compiler warning */
235 score = 0;
236 break;
237 }
238
239 if (score) {
240 msgid = fgetheader(f, "Message-ID:");
241 fclose(f);
242 unlink(de->d_name);
243 /* delete stuff in message.id directory as well */
244 if (msgid) {
245 msgidpath = lookup(msgid);
246 if ((stat(msgidpath, &st) == 0) /* RATS: ignore */
247 && (st.st_nlink < 2)) {
248 if (unlink(msgidpath) == 0)
249 deleted++;
250 }
251 free(msgid);
252 }
253 if (verbose)
254 printf("%s %s deleted\n", de->d_name, msgidpath);
255 } else {
256 fclose(f);
257 n = strtoul(de->d_name, NULL, 10);
258 if (n) {
259 if (n < g->first)
260 g->first = n;
261 if (n > g->last)
262 g->last = n;
263 }
264 u.actime = st.st_atime;
265 u.modtime = st.st_mtime;
266 utime(de->d_name, &u);
267 kept++;
268 }
269 } else {
270 if (f) {
272 "could not stat %s or not a regular file\n",
273 de->d_name);
274 (void)fclose(f);
275 } else {
276 ln_log(LNLOG_SERR, LNLOG_CARTICLE, "could not open %s\n",
277 de->d_name);
278 }
279 }
280 }
281 closedir(d);
282 free(l);
283 if (g->first > g->last) {
284 /* group is empty */
285 g->first = g->last + 1;
286 }
287 if (writeactive()) ln_log(LNLOG_SERR, LNLOG_CTOP, "Error writing groupinfo.");
289 unlink(lockfile);
290 printf("%d article%s deleted, %d kept.\n", deleted, PLURAL(deleted), kept);
291
292 if (verbose)
293 printf("Updating .overview file\n");
294 getxover();
295 freexover();
296 freeconfig();
297 exit(0);
298}
void readactive(void)
Definition: activutil.c:373
void freeactive(struct newsgroup *act)
Definition: activutil.c:351
struct newsgroup * findgroup(const char *name)
Definition: activutil.c:260
int writeactive(void)
Definition: activutil.c:269
struct newsgroup * active
Definition: activutil.c:40
int verbose
Definition: applyfilter.c:31
int main(int argc, char *argv[])
Definition: applyfilter.c:114
static char * readtodelim(FILE *f, const char *name, const char *delim, char **bufp, size_t *size)
Definition: applyfilter.c:38
static void unfold(char *t)
Definition: applyfilter.c:76
static int readheaders(FILE *f, const char *name, char **bufp, size_t *size)
Definition: applyfilter.c:96
#define MAXHEADERSIZE
Definition: applyfilter.c:28
int debug
Definition: applyfilter.c:30
char * fgetheader(FILE *f, const char *header)
Definition: artutil.c:27
char * filterfile
Definition: configutil.c:88
unsigned long timeout_lock
Definition: configutil.c:92
void freeservers(void)
Definition: configutil.c:695
int readconfig(int logtostderr)
Definition: configutil.c:208
void freeconfig(void)
Definition: configutil.c:722
char * critrealloc(char *a, size_t size, const char *message)
Definition: critmem.c:79
char * critmalloc(size_t size, const char *message)
Definition: critmem.c:61
void readfilter(char *fifi)
Definition: filterutil.c:33
int dofilter(unsigned char *h)
Definition: filterutil.c:87
#define PLURAL(no)
Definition: leafnode.h:35
void freexover(void)
Definition: xoverutil.c:396
void myopenlog(const char *ident)
Definition: syslog.c:24
int initvars(char *progname)
Definition: miscutil.c:143
const char * lookup(const char *msgid)
Definition: miscutil.c:306
#define FALSE
Definition: leafnode.h:32
const char * lockfile
int try_lock(unsigned long)
Definition: lockfile.c:200
int chdirgroup(const char *group, int creatdir)
Definition: miscutil.c:446
int getxover(void)
Definition: xoverutil.c:415
void ln_log(int sev, int ctx, const char *format,...)
Definition: ln_log.c:103
#define LNLOG_SERR
Definition: ln_log.h:13
#define LNLOG_CTOP
Definition: ln_log.h:22
#define LNLOG_CARTICLE
Definition: ln_log.h:25
const char * name
Definition: miscutil.c:126
unsigned long first
Definition: leafnode.h:122
char * name
Definition: leafnode.h:124
unsigned long last
Definition: leafnode.h:123
#define dirent
Definition: system.h:21