1: /*
2: * This software is Copyright (c) 1986 by Rick Adams.
3: *
4: * Permission is hereby granted to copy, reproduce, redistribute or
5: * otherwise use this software as long as: there is no monetary
6: * profit gained specifically from the use or reproduction or this
7: * software, it is not sold, rented, traded or otherwise marketed, and
8: * this copyright notice is included prominently in any copy
9: * made.
10: *
11: * The author make no claims as to the fitness or correctness of
12: * this software for any use whatsoever, and it is provided as is.
13: * Any use of this software is at the user's own risk.
14: *
15: * checknews - news checking program
16: */
17:
18: #ifdef SCCSID
19: static char *SccsId = "@(#)checknews.c 2.24 1/17/86";
20: #endif /* SCCSID */
21:
22: char *Progname = "checknews"; /* used by xerror */
23:
24: #include "params.h"
25:
26: char bfr[LBUFLEN]; /* general-use scratch area */
27: char optbuf[BUFLEN]; /* NEWSOPTS buffer */
28: int line = -1, y, e, n, q;
29: int verbose; /* For debugging. */
30: int nflag; /* for spec. newsgroup */
31: char narggrp[BUFLEN]; /* spec newsgroup */
32: FILE *rcfp, *actfp;
33: char newsrc[BUFLEN],*rcline[LINES],rcbuf[LBUFLEN],*argvrc[LINES];
34: struct hbuf ;
35: char coptbuf[BUFLEN],datebuf[BUFLEN];
36: int mode = 1;
37: #ifndef SHELL
38: char *SHELL;
39: #endif
40:
41: main(argc, argv)
42: int argc;
43: register char **argv;
44: {
45: register char *ptr; /* pointer to rest of buffer */
46: char *user, *home;
47: struct passwd *pw;
48: struct group *gp;
49: int sflag = 0, optflag = FALSE, space = FALSE;
50: int i;
51:
52: y = 0;
53: n = 0;
54: e = 0;
55: q = 0;
56: nflag = 0;
57: pathinit();
58: if (--argc > 0) {
59: for (argv++; **argv; ++*argv) {
60: switch(**argv) {
61: case 'y':
62: y++;
63: break;
64: case 'q':
65: q++;
66: break;
67: case 'v':
68: verbose++;
69: break;
70: case 'n':
71: n++;
72: break;
73: case 'N':
74: nflag++;
75: strcpy(narggrp,argv[1]);
76: strcat(narggrp,",");
77: break;
78: case 'e':
79: case 'f':
80: e++;
81: break;
82: }
83: }
84: }
85: if (!n && !e && !y && !q)
86: y++;
87: if (nflag)
88: argv++;
89:
90: #ifndef V6
91: if ((user = getenv("USER")) == NULL)
92: user = getenv("LOGNAME");
93: if ((home = getenv("HOME")) == NULL)
94: home = getenv("LOGDIR");
95: if (user == NULL || home == NULL)
96: getuser();
97: else {
98: username = AllocCpy(user);
99: userhome = AllocCpy(home);
100: }
101: if (ptr = getenv("NEWSOPTS"))
102: strcpy(rcbuf, ptr);
103: else
104: *rcbuf = '\0';
105: if (*rcbuf) {
106: strcat(rcbuf, " \1");
107: ptr = rcbuf;
108: while (*++ptr)
109: if (isspace(*ptr))
110: *ptr = '\0';
111: for (ptr = rcbuf;; ptr++) {
112: if (!*ptr)
113: continue;
114: if (*ptr == '\1')
115: break;
116: if (++line > LINES)
117: xerror("Too many options.");
118: if ((rcline[line] = malloc(strlen(ptr) + 1)) == NULL)
119: xerror("Not enough memory.");
120: argvrc[line] = rcline[line];
121: strcpy(rcline[line], ptr);
122: while (*ptr)
123: ptr++;
124: }
125: }
126: #else
127: getuser();
128: #endif
129: ptr = getenv("NEWSRC");
130: if (ptr == NULL)
131: sprintf(newsrc, "%s/%s", userhome, NEWSRC);
132: else
133: strcpy(newsrc, ptr);
134: if ((rcfp = fopen(newsrc, "r")) != NULL) {
135: while (fgets(rcbuf, LBUFLEN, rcfp) != NULL) {
136: if (!(space = isspace(*rcbuf)))
137: optflag = FALSE;
138: if (!strncmp(rcbuf, "options ", 8))
139: optflag = TRUE;
140: if (optflag) {
141: strcat(rcbuf, "\1");
142: if (space)
143: ptr = rcbuf - 1;
144: else
145: ptr = &rcbuf[7];
146: while (*++ptr)
147: if (isspace(*ptr))
148: *ptr = '\0';
149: if (space)
150: ptr = rcbuf;
151: else
152: ptr = &rcbuf[8];
153: for (;; ptr++) {
154: if (!*ptr)
155: continue;
156: if (*ptr == '\1')
157: break;
158: if (++line > LINES)
159: xerror("Too many options.");
160: if ((rcline[line] = malloc(strlen(ptr) + 1)) == NULL)
161: xerror("Not enough memory.");
162: argvrc[line] = rcline[line];
163: strcpy(rcline[line], ptr);
164: while (*ptr)
165: ptr++;
166: }
167: }
168: }
169: fclose(rcfp);
170: }
171: header.nbuf[0] = 0;
172: if (line != -1) {
173: #ifdef DEBUG
174: for (i = 0; i <= line; i++)
175: fprintf(stderr, "options: %s\n", rcline[i]);
176: #endif
177: process(line+2, argvrc);
178: do {
179: #ifdef DEBUG
180: fprintf(stderr, "Freeing %d\n", line);
181: #endif
182: free(rcline[line]);
183: } while (line--);
184: }
185:
186: if (!*header.nbuf) {
187: strcpy(header.nbuf, DFLTSUB);
188: ngcat(header.nbuf);
189: }
190: strcat(header.nbuf, ADMSUB);
191: ngcat(header.nbuf);
192: if (*header.nbuf)
193: lcase(header.nbuf);
194: makehimask(header.nbuf, "junk");
195: makehimask(header.nbuf, "control");
196: makehimask(header.nbuf, "test");
197: if (access(newsrc, 0)) {
198: if (verbose > 1)
199: printf("No newsrc\n");
200: yep(argv);
201: }
202: if ((rcfp = fopen(newsrc, "r")) == NULL)
203: xerror("Cannot open .newsrc file");
204: while (fgets(rcbuf, LBUFLEN, rcfp) != NULL) {
205: if (!nstrip(rcbuf))
206: xerror(".newsrc line too long");
207: if (++line >= LINES)
208: xerror("Too many .newsrc lines");
209: if ((rcline[line] = malloc(strlen(rcbuf)+1)) == NULL)
210: xerror("Not enough memory");
211: strcpy(rcline[line], rcbuf);
212: }
213: if ((actfp = fopen(ACTIVE, "r")) == NULL)
214: xerror("Cannot open active newsgroups file");
215:
216: #ifdef DEBUG
217: fprintf(stderr, "header.nbuf = %s\n", header.nbuf);
218: #endif
219: nchk(argv);
220: exit(0);
221: }
222:
223: nchk(argv)
224: char **argv;
225: {
226: register int i;
227: register char *ptr;
228: long l;
229: long narts;
230: char saveptr;
231: char aline[100];
232:
233: #ifdef DEBUG
234: fprintf(stderr, "nchk()\n");
235: #endif
236: while (fgets(aline, sizeof aline, actfp) != NULL) {
237: sscanf(aline, "%s %ld", bfr, &narts);
238: #ifdef DEBUG
239: fprintf(stderr, "bfr = '%s'\n", bfr);
240: #endif
241: ngcat(bfr);
242: if (!ngmatch(bfr, nflag ? narggrp : header.nbuf))
243: continue;
244: ngdel(bfr);
245: i = findrcline(bfr);
246: if (i < 0) {
247: if (verbose>1)
248: printf("No newsrc line for newsgroup %s\n", bfr);
249: strcpy(rcbuf, " 0");
250: } else
251: strcpy(rcbuf, rcline[i]);
252: ptr = rcbuf;
253:
254: if (index(rcbuf, '!') != NULL)
255: continue;
256: if (index(rcbuf, ',') != NULL) {
257: if (verbose > 1)
258: printf("Comma in %s newsrc line\n", bfr);
259: yep(argv);
260: }
261: while (*ptr)
262: ptr++;
263: while (!isdigit(*--ptr) && *ptr != ':' && ptr >= rcbuf)
264: ;
265: if (*ptr == ':')
266: continue;
267: if (ptr < rcbuf) {
268: if (verbose > 1)
269: printf("Ran off beginning of %s newsrc line.\n", bfr);
270: yep(argv);
271: }
272: while (isdigit(*--ptr))
273: ;
274: sscanf(++ptr, "%ld", &l);
275: if (narts > l) {
276: if (verbose) {
277: printf("News: %s ...\n", bfr);
278: if (verbose < 2)
279: y = 0;
280: }
281: yep(argv);
282: }
283: contin:;
284: }
285: if (n)
286: printf("No news is good news.\n");
287: }
288:
289: yep(argv)
290: char **argv;
291: {
292: if (y) {
293: if (verbose)
294: printf("There is probably news");
295: else
296: printf("There is news");
297: if (nflag) {
298: narggrp[strlen(narggrp)-1] = '.';
299: printf(" in %s\n",narggrp);
300: }
301: else
302: printf(".\n");
303: }
304: if (e) {
305: #ifdef V6
306: execv("/usr/bin/readnews", argv);
307: #else
308: execvp("readnews", argv);
309: #endif
310: perror("Cannot exec readnews.");
311: }
312: if (q)
313: exit(1);
314: else
315: exit(0);
316: }
317:
318: xerror(message, arg1, arg2)
319: char *message;
320: int arg1, arg2;
321: {
322: char buffer[128];
323:
324: sprintf(buffer, message, arg1, arg2);
325: fprintf(stderr, "checknews: %s.\n", buffer);
326: exit(1);
327: }
328:
329: /*
330: * Append NGDELIM to string.
331: */
332: ngcat(s)
333: register char *s;
334: {
335: if (*s) {
336: while (*s++);
337: s -= 2;
338: if (*s++ == NGDELIM)
339: return;
340: }
341: *s++ = NGDELIM;
342: *s = '\0';
343: }
344:
345: /*
346: * News group matching.
347: *
348: * nglist is a list of newsgroups.
349: * sublist is a list of subscriptions.
350: * sublist may have "meta newsgroups" in it.
351: * All fields are NGDELIM separated,
352: * and there is an NGDELIM at the end of each argument.
353: *
354: * Currently implemented glitches:
355: * sublist uses 'all' like shell uses '*', and '.' like shell '/'.
356: * If subscription X matches Y, it also matches Y.anything.
357: */
358: ngmatch(nglist, sublist)
359: register char *nglist, *sublist;
360: {
361: register char *n, *s;
362: register int rc;
363:
364: rc = FALSE;
365: for (n = nglist; *n != '\0' && rc == FALSE;) {
366: for (s = sublist; *s != '\0';) {
367: if (*s != NEGCHAR)
368: rc |= ptrncmp(s, n);
369: else
370: rc &= ~ptrncmp(s+1, n);
371: while (*s++ != NGDELIM);
372: }
373: while (*n++ != NGDELIM);
374: }
375: return(rc);
376: }
377:
378: /*
379: * Compare two newsgroups for equality.
380: * The first one may be a "meta" newsgroup.
381: */
382: ptrncmp(ng1, ng2)
383: register char *ng1, *ng2;
384: {
385: while (*ng1 != NGDELIM) {
386: if (ng1[0]=='a' && ng1[1]=='l' && ng1[2]=='l') {
387: ng1 += 3;
388: while (*ng2 != NGDELIM && *ng2 != '.')
389: if (ptrncmp(ng1, ng2++))
390: return(TRUE);
391: return (ptrncmp(ng1, ng2));
392: } else if (*ng1++ != *ng2++)
393: return(FALSE);
394: }
395: return (*ng2 == '.' || *ng2 == NGDELIM);
396: }
397:
398: /*
399: * Get user name and home directory.
400: */
401: getuser()
402: {
403: static int flag = TRUE;
404: register struct passwd *p;
405:
406: if (flag) {
407: if ((p = getpwuid(getuid())) == NULL)
408: xerror("Cannot get user's name");
409: if (username == NULL || *username == '\0')
410: username = AllocCpy(p->pw_name);
411: userhome = AllocCpy(p->pw_dir);
412: flag = FALSE;
413: }
414: }
415:
416: /*
417: * Strip trailing newlines, blanks, and tabs from 's'.
418: * Return TRUE if newline was found, else FALSE.
419: */
420: nstrip(s)
421: register char *s;
422: {
423: register char *p;
424: register int rc;
425:
426: rc = FALSE;
427: p = s;
428: while (*p)
429: if (*p++ == '\n')
430: rc = TRUE;
431: while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t'));
432: *++p = '\0';
433: return(rc);
434: }
435:
436: /*
437: * Delete trailing NGDELIM.
438: */
439: ngdel(s)
440: register char *s;
441: {
442: if (*s++) {
443: while (*s++);
444: s -= 2;
445: if (*s == NGDELIM)
446: *s = '\0';
447: }
448: }
449:
450: lcase(s)
451: register char *s;
452: {
453: register char *ptr;
454:
455: for (ptr = s; *ptr; ptr++)
456: if (isupper(*ptr))
457: *ptr = tolower(*ptr);
458: }
459:
460: /*
461: * finds the line in your .newsrc file (actually the in-core "rcline"
462: * copy of it) and returns the index into the array where it was found.
463: * -1 means it didn't find it.
464: *
465: * We play clever games here to make this faster. It's inherently
466: * quadratic - we spend lots of CPU time here because we search through
467: * the whole .newsrc for each line. The "prev" variable remembers where
468: * the last match was found; we start the search there and loop around
469: * to the beginning, in the hopes that the calls will be roughly in order.
470: */
471: int
472: findrcline(name)
473: char *name;
474: {
475: register char *p, *ptr;
476: register int cur;
477: register int i;
478: register int top;
479: static int prev = 0;
480:
481: top = line; i = prev;
482: loop:
483: for (; i <= top; i++) {
484: for (p = name, ptr = rcline[i]; (cur = *p++); ) {
485: if (cur != *ptr++)
486: goto contin2;
487: }
488: if (*ptr != ':' && *ptr != '!')
489: continue;
490: prev = i;
491: return i;
492: contin2:
493: ;
494: }
495: if (i > line && line > prev-1) {
496: i = 0;
497: top = prev-1;
498: goto loop;
499: }
500: return -1;
501: }
502:
503: /*
504: * Forbid newsgroup ng, unless he asked for it in nbuf.
505: */
506: makehimask(nbuf, ng)
507: char *nbuf, *ng;
508: {
509: if (!findex(nbuf, ng)) {
510: ngcat(nbuf);
511: strcat(nbuf, "!");
512: strcat(nbuf, ng);
513: ngcat(nbuf);
514: }
515: }
516:
517: /*
518: * Return true if the string searchfor is in string, but not if preceded by !.
519: */
520: findex(string, searchfor)
521: char *string, *searchfor;
522: {
523: register char first;
524: register char *p;
525:
526: first = *searchfor;
527: for (p=index(string, first); p; p = index(p+1, first)) {
528: if (p>string && p[-1] != '!' && strncmp(p, searchfor, strlen(searchfor)) == 0)
529: return TRUE;
530: }
531: return FALSE;
532: }
533:
534: xxit(i)
535: {
536: exit(i);
537: }