Line 0
Link Here
|
|
|
1 |
--- rnews.c 2002-05-18 20:21:26.000000000 +0100 |
2 |
+++ rnews.c 2002-09-08 12:50:41.000000000 +0100 |
3 |
@@ -2,6 +2,8 @@ |
4 |
* S-News version 0.1.9 - A Simple News Server |
5 |
* Copyright (C) 1998 Christopher John Purnell |
6 |
* cjp@lost.org.uk |
7 |
+ * Supersedes/cancel modifications (C) 2002 Tony Houghton |
8 |
+ * tony@realh.co.uk |
9 |
* |
10 |
* This program is free software; you can redistribute it and/or modify |
11 |
* it under the terms of the GNU General Public License as published by |
12 |
@@ -50,6 +52,8 @@ |
13 |
|
14 |
#include "snews.h" |
15 |
|
16 |
+#define DEBLOG(a) /* fprintf a */ |
17 |
+ |
18 |
struct header |
19 |
{ |
20 |
struct header *next; |
21 |
@@ -78,14 +82,23 @@ |
22 |
static FILE *open_lock(char *); |
23 |
static int file_name(struct header *,char *,unsigned); |
24 |
static GDBM_FILE open_history(char *,int); |
25 |
+static int read_string(FILE *,char *,unsigned); |
26 |
+static void delete_msg(const char *); |
27 |
+static int whole_string(struct header_pointer *,char *,unsigned); |
28 |
+static int read_line(FILE *,char *,unsigned); |
29 |
+static int isolate_addr(char *); |
30 |
|
31 |
static char *progname; |
32 |
static char fqdn[BUFLEN]; |
33 |
static char msgid[BUFLEN]; |
34 |
static char article[BUFLEN]; |
35 |
+static char vsender[BUFLEN]; |
36 |
+static char cancel[BUFLEN]; |
37 |
static char queue=0,approved=0; |
38 |
+static int cancel_only; |
39 |
|
40 |
struct header junk = { 0, "junk", 0 }; |
41 |
+struct header control_cancel = { 0, "control.cancel", 0 }; |
42 |
|
43 |
int main(int argc,char **argv) |
44 |
{ |
45 |
@@ -95,6 +108,16 @@ |
46 |
|
47 |
set_ug_id(); |
48 |
|
49 |
+ /* For logging, remove this in release */ |
50 |
+ /* |
51 |
+ i = open("/var/log/news/rnews", O_WRONLY|O_CREAT|O_APPEND, 0644); |
52 |
+ if (i) |
53 |
+ { |
54 |
+ close(2); |
55 |
+ dup2(i, 2); |
56 |
+ } |
57 |
+ */ |
58 |
+ |
59 |
progname = argv[0]; |
60 |
|
61 |
if (get_fqdn()) |
62 |
@@ -116,12 +139,18 @@ |
63 |
return (1); |
64 |
} |
65 |
|
66 |
+ cancel[0] = 0; |
67 |
+ vsender[0] = 0; |
68 |
+ cancel_only = 0; |
69 |
+ |
70 |
if (!(hdr = read_header())) |
71 |
return (1); |
72 |
|
73 |
if (!(ngrp = parse_header(hdr))) |
74 |
return (1); |
75 |
|
76 |
+ DEBLOG((stderr, "Message-ID: %s\n", msgid)); |
77 |
+ |
78 |
if (!(fp = open_lock(CONFDIR"/active.n"))) |
79 |
{ |
80 |
perror(progname); |
81 |
@@ -130,8 +159,16 @@ |
82 |
|
83 |
if (!(i = chk_article(msgid))) |
84 |
{ |
85 |
- if (!(ngrp = update_active(CONFDIR"/active",CONFDIR"/active.n", |
86 |
- fp,ngrp))) |
87 |
+ DEBLOG((stderr, "chk_article OK\n")); |
88 |
+ if (cancel_only) |
89 |
+ { |
90 |
+ ngrp = update_active(CONFDIR"/active", |
91 |
+ CONFDIR"/active.n", |
92 |
+ fp,&control_cancel); |
93 |
+ DEBLOG((stderr, "cancel_only, ngrp = %d\n", ngrp)); |
94 |
+ } |
95 |
+ else if (!(ngrp = update_active(CONFDIR"/active", |
96 |
+ CONFDIR"/active.n",fp,ngrp))) |
97 |
{ |
98 |
rewind(fp); |
99 |
if (ftruncate(fileno(fp),0)) |
100 |
@@ -144,8 +181,11 @@ |
101 |
i = !ngrp; |
102 |
} |
103 |
|
104 |
+ DEBLOG((stderr, "After chk_article and update_active, result = %d (0 is good)\n", i)); |
105 |
+ |
106 |
if (fclose(fp) || i || write_article(hdr,ngrp)) |
107 |
{ |
108 |
+ DEBLOG((stderr, "fclose || i || write_article failed\n")); |
109 |
unlink(CONFDIR"/active.n"); |
110 |
return (1); |
111 |
} |
112 |
@@ -158,6 +198,9 @@ |
113 |
return (1); |
114 |
} |
115 |
|
116 |
+ if (cancel[0]) |
117 |
+ delete_msg(cancel); |
118 |
+ |
119 |
if (!queue) return (0); |
120 |
|
121 |
execl(QNEWSPATH,QNEWSARG0,article,0); |
122 |
@@ -301,11 +344,79 @@ |
123 |
{ |
124 |
approved=1; |
125 |
} |
126 |
+ else if (!strncasecmp(hdr->line,"Sender:",7)) |
127 |
+ { |
128 |
+ hp.hdr = hdr; |
129 |
+ hp.ptr = hdr->line+7; |
130 |
+ if (whole_string(&hp,vsender,BUFLEN)<=0) |
131 |
+ { |
132 |
+ fprintf(stderr,"%s: bad Sender\n", |
133 |
+ progname); |
134 |
+ return (0); |
135 |
+ } |
136 |
+ DEBLOG((stderr, "Found Sender: %s\n", vsender)); |
137 |
+ } |
138 |
+ else if (!vsender[0] && !strncasecmp(hdr->line,"From:",5)) |
139 |
+ { |
140 |
+ hp.hdr = hdr; |
141 |
+ hp.ptr = hdr->line+5; |
142 |
+ if (whole_string(&hp,vsender,BUFLEN)<=0) |
143 |
+ { |
144 |
+ fprintf(stderr,"%s: bad From\n", |
145 |
+ progname); |
146 |
+ return (0); |
147 |
+ } |
148 |
+ DEBLOG((stderr, "Found From: %s\n", vsender)); |
149 |
+ } |
150 |
+ else if (!strncasecmp(hdr->line,"Supersedes:",11)) |
151 |
+ { |
152 |
+ hp.hdr = hdr; |
153 |
+ hp.ptr = hdr->line+11; |
154 |
+ if (whole_string(&hp,cancel,BUFLEN)<=0) |
155 |
+ { |
156 |
+ fprintf(stderr,"%s: bad Supersedes\n", |
157 |
+ progname); |
158 |
+ return (0); |
159 |
+ } |
160 |
+ DEBLOG((stderr, "Found Supersedes: %s\n", cancel)); |
161 |
+ } |
162 |
+ else if (!strncasecmp(hdr->line,"Control: cancel",15)) |
163 |
+ { |
164 |
+ hp.hdr = hdr; |
165 |
+ hp.ptr = hdr->line+15; |
166 |
+ if (whole_string(&hp,cancel,BUFLEN)<=0) |
167 |
+ { |
168 |
+ fprintf(stderr,"%s: bad cancel\n", |
169 |
+ progname); |
170 |
+ return (0); |
171 |
+ } |
172 |
+ DEBLOG((stderr, "Found cancel: %s\n", cancel)); |
173 |
+ cancel_only = 1; |
174 |
+ } |
175 |
+ else if (!strncasecmp(hdr->line,"Also-Control: cancel",20)) |
176 |
+ { |
177 |
+ hp.hdr = hdr; |
178 |
+ hp.ptr = hdr->line+20; |
179 |
+ if (whole_string(&hp,cancel,BUFLEN)<=0) |
180 |
+ { |
181 |
+ fprintf(stderr,"%s: bad cancel\n", |
182 |
+ progname); |
183 |
+ return (0); |
184 |
+ } |
185 |
+ DEBLOG((stderr, "Found also-cancel: %s\n", cancel)); |
186 |
+ } |
187 |
|
188 |
} |
189 |
hdr = hdr->next; |
190 |
} |
191 |
|
192 |
+ if (vsender[0]) |
193 |
+ { |
194 |
+ int ires=isolate_addr(vsender); |
195 |
+ DEBLOG((stderr,"vsender address = %s (result %d)\n", |
196 |
+ vsender,ires)); |
197 |
+ } |
198 |
+ |
199 |
return (*msgid?ret:0); |
200 |
} |
201 |
|
202 |
@@ -597,7 +708,10 @@ |
203 |
int ret; |
204 |
|
205 |
if (!(dbf = open_history(CONFDIR"/history",GDBM_READER))) |
206 |
+ { |
207 |
+ DEBLOG((stderr, "chk_article: Couldn't open history\n")); |
208 |
return (1); |
209 |
+ } |
210 |
|
211 |
key.dsize = strlen(key.dptr = id) + 1; |
212 |
|
213 |
@@ -605,6 +719,7 @@ |
214 |
|
215 |
gdbm_close(dbf); |
216 |
|
217 |
+ DEBLOG((stderr, "chk_article: %s exists: %d\n", id, ret)); |
218 |
return (ret); |
219 |
} |
220 |
|
221 |
@@ -642,3 +757,232 @@ |
222 |
} |
223 |
return (dbf); |
224 |
} |
225 |
+ |
226 |
+/* Added by Tony Houghton <tony@realh.co.uk>, mostly copied from expire.c */ |
227 |
+ |
228 |
+static void delete_msg(const char *msgid) |
229 |
+{ |
230 |
+ char buf[BUFLEN]; |
231 |
+ char sender[BUFLEN]; |
232 |
+ struct stat st; |
233 |
+ FILE *fp; |
234 |
+ GDBM_FILE dbf; |
235 |
+ datum key,value; |
236 |
+ char *file; |
237 |
+ |
238 |
+ DEBLOG((stderr, "Deleting %s\n", msgid)); |
239 |
+ if (!(dbf = open_history(CONFDIR"/history",GDBM_READER))) |
240 |
+ return; |
241 |
+ key.dsize = strlen(key.dptr = (char *) msgid) + 1; |
242 |
+ value = gdbm_fetch(dbf, key); |
243 |
+ if ((file = value.dptr) == NULL) |
244 |
+ return; |
245 |
+ DEBLOG((stderr, "Filename is %s\n", file)); |
246 |
+ |
247 |
+ if (!(fp = fopen(file,"r"))) |
248 |
+ { |
249 |
+ if (errno != ENOENT) |
250 |
+ perror(file); |
251 |
+ free(file); |
252 |
+ return; |
253 |
+ } |
254 |
+ |
255 |
+ if (fstat(fileno(fp),&st)) |
256 |
+ { |
257 |
+ perror(file); |
258 |
+ free(file); |
259 |
+ return; |
260 |
+ } |
261 |
+ |
262 |
+ sender[0] = 0; |
263 |
+ while (fgets(buf,6,fp)) |
264 |
+ { |
265 |
+ if (!sender[0] && !strcasecmp(buf,"From:")) |
266 |
+ { |
267 |
+ if (read_line(fp,sender,BUFLEN) <= 0) |
268 |
+ { |
269 |
+ fclose(fp); |
270 |
+ fprintf(stderr,"%s: bad From header\n",file); |
271 |
+ free(file); |
272 |
+ return; |
273 |
+ } |
274 |
+ DEBLOG((stderr, "From: %s\n", sender)); |
275 |
+ } |
276 |
+ else if (!strcasecmp(buf,"Sende") && fgetc(fp) == 'r' && |
277 |
+ fgetc(fp) == ':') |
278 |
+ { |
279 |
+ if (read_line(fp,sender,BUFLEN) <= 0) |
280 |
+ { |
281 |
+ fclose(fp); |
282 |
+ fprintf(stderr,"%s: bad Sender\n",file); |
283 |
+ free(file); |
284 |
+ return; |
285 |
+ } |
286 |
+ DEBLOG((stderr, "Sender: %s\n", sender)); |
287 |
+ } |
288 |
+ else if (buf[0] == '\n') |
289 |
+ break; |
290 |
+ } |
291 |
+ rewind(fp); |
292 |
+ if (isolate_addr(sender) == -1) |
293 |
+ { |
294 |
+ fprintf(stderr,"Invalid sender, can't cancel\n"); |
295 |
+ free(file); |
296 |
+ fclose(fp); |
297 |
+ return; |
298 |
+ } |
299 |
+ DEBLOG((stderr,"Sender address = %s\n",sender)); |
300 |
+ |
301 |
+ if (strcasecmp(sender,vsender)) |
302 |
+ { |
303 |
+ fprintf(stderr,"Wrong sender, can't cancel\n"); |
304 |
+ free(file); |
305 |
+ fclose(fp); |
306 |
+ return; |
307 |
+ } |
308 |
+ |
309 |
+ while (fgets(buf,6,fp)) |
310 |
+ { |
311 |
+ char *cp; |
312 |
+ int c; |
313 |
+ |
314 |
+ if (strcasecmp(buf,"Xref:")) |
315 |
+ { |
316 |
+ if ((cp = strchr(buf,'\n'))) |
317 |
+ { |
318 |
+ if (cp == buf) break; |
319 |
+ } |
320 |
+ else |
321 |
+ { |
322 |
+ while ((c = fgetc(fp)) != EOF && c != '\n'); |
323 |
+ if (c == EOF) break; |
324 |
+ } |
325 |
+ } |
326 |
+ else |
327 |
+ { |
328 |
+ if ((read_string(fp,buf,BUFLEN) <= 0) || |
329 |
+ strcasecmp(buf,fqdn)) |
330 |
+ { |
331 |
+ fclose(fp); |
332 |
+ fprintf(stderr,"%s: bad Xref line\n",file); |
333 |
+ free(file); |
334 |
+ return; |
335 |
+ } |
336 |
+ |
337 |
+ while ((c = read_string(fp,buf,BUFLEN))) |
338 |
+ { |
339 |
+ if (c < 0) |
340 |
+ { |
341 |
+ fclose(fp); |
342 |
+ fprintf(stderr,"%s: bad Xref line\n", |
343 |
+ file); |
344 |
+ free(file); |
345 |
+ return; |
346 |
+ } |
347 |
+ |
348 |
+ cp = buf; |
349 |
+ while ((c = *cp)) |
350 |
+ { |
351 |
+ if (c == '.' || c ==':') |
352 |
+ *cp = '/'; |
353 |
+ ++cp; |
354 |
+ } |
355 |
+ |
356 |
+ if (strcmp(file,buf) && |
357 |
+ unlink(buf) && errno != ENOENT) |
358 |
+ { |
359 |
+ perror(buf); |
360 |
+ fclose(fp); |
361 |
+ free(file); |
362 |
+ return; |
363 |
+ } |
364 |
+ } |
365 |
+ |
366 |
+ break; |
367 |
+ } |
368 |
+ } |
369 |
+ if (ferror(fp)) |
370 |
+ { |
371 |
+ perror(file); |
372 |
+ free(file); |
373 |
+ fclose(fp); |
374 |
+ return; |
375 |
+ } |
376 |
+ |
377 |
+ fclose(fp); |
378 |
+ if (unlink(file)) |
379 |
+ perror(file); |
380 |
+ free(file); |
381 |
+} |
382 |
+ |
383 |
+static int read_string(FILE *fp,char *str,unsigned len) |
384 |
+{ |
385 |
+ int c; |
386 |
+ unsigned i=0; |
387 |
+ |
388 |
+ while ((c = fgetc(fp)) != EOF && c != '\n' && isspace(c)); |
389 |
+ |
390 |
+ while (c != EOF && !isspace(c)) |
391 |
+ { |
392 |
+ str[i]=c; |
393 |
+ if (++i>=len) return (-1); |
394 |
+ c = fgetc(fp); |
395 |
+ } |
396 |
+ str[i]='\0'; |
397 |
+ |
398 |
+ return (i); |
399 |
+} |
400 |
+ |
401 |
+static int whole_string(struct header_pointer *hp,char *str,unsigned len) |
402 |
+{ |
403 |
+ unsigned i=0; |
404 |
+ unsigned char c; |
405 |
+ |
406 |
+ while ((c = next_char(hp)) && isspace(c)); |
407 |
+ |
408 |
+ while (c && c != '\n') |
409 |
+ { |
410 |
+ str[i]=c; |
411 |
+ if (++i>=len) return (-1); |
412 |
+ c = next_char(hp); |
413 |
+ } |
414 |
+ str[i]='\0'; |
415 |
+ |
416 |
+ return (i); |
417 |
+} |
418 |
+ |
419 |
+static int read_line(FILE *fp,char *str,unsigned len) |
420 |
+{ |
421 |
+ int c; |
422 |
+ unsigned i=0; |
423 |
+ |
424 |
+ while ((c = fgetc(fp)) != EOF && c != '\n' && isspace(c)); |
425 |
+ |
426 |
+ while (c != EOF && c != '\n') |
427 |
+ { |
428 |
+ str[i]=c; |
429 |
+ if (++i>=len) return (-1); |
430 |
+ c = fgetc(fp); |
431 |
+ } |
432 |
+ str[i]='\0'; |
433 |
+ |
434 |
+ return (i); |
435 |
+} |
436 |
+ |
437 |
+static int isolate_addr(char *str) |
438 |
+{ |
439 |
+ char *at; |
440 |
+ unsigned len; |
441 |
+ |
442 |
+ if (!(at=strchr(str,'@'))) |
443 |
+ return -1; |
444 |
+ while (at != str && !isspace(*(at-1)) && *(at-1) != '<') |
445 |
+ --at; |
446 |
+ for (len = 0; |
447 |
+ len <= strlen(at) && !isspace(at[len]) && at[len] !='>'; |
448 |
+ ++len); |
449 |
+ memmove(str,at,len); |
450 |
+ str[len]=0; |
451 |
+ return 0; |
452 |
+} |
453 |
+ |