BSD 4_2 release
[unix-history] / usr / src / new / new / news / src / checknews.c
/*
* checknews - news checking program
*/
static char *SccsId = "@(#)checknews.c 2.15 5/3/83";
#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <ctype.h>
#include "defs.h"
#include "header.h"
char bfr[BUFLEN]; /* general-use scratch area */
char optbuf[BUFLEN]; /* NEWSOPTS buffer */
char username[BUFLEN]; /* user's login name */
char userhome[BUFLEN]; /* user's home directory */
char SPOOL[BUFLEN]; /* spool directory */
char LIB[BUFLEN]; /* library directory */
char ACTIVE[BUFLEN]; /* active newsgroups file */
char *NEWSU = NEWSUSR; /* login name for netnews */
char *NEWSG = NEWSGRP; /* group name for netnews */
int line = -1, y, e, n, q;
int verbose; /* For debugging. */
FILE *rcfp,*actfp;
char newsrc[BUFLEN],*rcline[LINES],rcbuf[LBUFLEN],*argvrc[LINES];
struct passwd *getpwuid();
char *malloc(),*getenv(), *index();
struct hbuf header;
char coptbuf[BUFLEN],datebuf[BUFLEN];
int mode = 1;
#ifndef SHELL
char *SHELL;
#endif
main(argc, argv)
int argc;
register char **argv;
{
register char *ptr; /* pointer to rest of buffer */
char *user, *home;
struct passwd *pw;
struct group *gp;
int sflag = 0, optflag = FALSE, space = FALSE;
int i;
y = 0;
n = 0;
e = 0;
q = 0;
pathinit();
if (--argc > 0) {
for (argv++; **argv; ++*argv) {
switch(**argv) {
case 'y':
y++;
break;
case 'q':
q++;
break;
case 'v':
verbose++;
break;
case 'n':
n++;
break;
case 'e':
case 'f':
e++;
break;
}
}
}
if (!n && !e && !y && !q)
y++;
#ifndef V6
if ((user = getenv("USER")) == NULL)
user = getenv("LOGNAME");
if ((home = getenv("HOME")) == NULL)
home = getenv("LOGDIR");
if (user == NULL || home == NULL)
getuser();
else {
strcpy(username, user);
strcpy(userhome, home);
}
if (ptr = getenv("NEWSOPTS"))
strcpy(rcbuf, ptr);
else
*rcbuf = '\0';
if (*rcbuf) {
strcat(rcbuf, " \1");
ptr = rcbuf;
while (*++ptr)
if (isspace(*ptr))
*ptr = '\0';
for (ptr = rcbuf;; ptr++) {
if (!*ptr)
continue;
if (*ptr == '\1')
break;
if (++line > LINES)
xerror("Too many options.\n");
if ((rcline[line] = malloc(strlen(ptr) + 1)) == NULL)
xerror("Not enough memory.\n");
argvrc[line] = rcline[line];
strcpy(rcline[line], ptr);
while (*ptr)
ptr++;
}
}
#else
getuser();
#endif
ptr = getenv("NEWSRC");
if (ptr == NULL)
sprintf(newsrc, "%s/%s", userhome, NEWSRC);
else
strcpy(newsrc, ptr);
if ((rcfp = fopen(newsrc, "r")) != NULL) {
while (fgets(rcbuf, LBUFLEN, rcfp) != NULL) {
if (!(space = isspace(*rcbuf)))
optflag = FALSE;
if (!strncmp(rcbuf, "options ", 8))
optflag = TRUE;
if (optflag) {
strcat(rcbuf, "\1");
if (space)
ptr = rcbuf - 1;
else
ptr = &rcbuf[7];
while (*++ptr)
if (isspace(*ptr))
*ptr = '\0';
if (space)
ptr = rcbuf;
else
ptr = &rcbuf[8];
for (;; ptr++) {
if (!*ptr)
continue;
if (*ptr == '\1')
break;
if (++line > LINES)
xerror("Too many options.\n");
if ((rcline[line] = malloc(strlen(ptr) + 1)) == NULL)
xerror("Not enough memory.\n");
argvrc[line] = rcline[line];
strcpy(rcline[line], ptr);
while (*ptr)
ptr++;
}
}
}
fclose(rcfp);
}
header.nbuf[0] = 0;
if (line != -1) {
#ifdef DEBUG
for (i = 0; i <= line; i++)
fprintf(stderr, "options: %s\n", rcline[i]);
#endif
process(line+2, argvrc);
do {
#ifdef DEBUG
fprintf(stderr, "Freeing %d\n", line);
#endif
free(rcline[line]);
} while (line--);
}
if (!*header.nbuf) {
strcpy(header.nbuf, DFLTSUB);
ngcat(header.nbuf);
}
strcat(header.nbuf, ADMSUB);
ngcat(header.nbuf);
if (*header.nbuf)
lcase(header.nbuf);
makehimask(header.nbuf, "junk");
makehimask(header.nbuf, "control");
makehimask(header.nbuf, "test");
if (access(newsrc, 0)) {
if (verbose>1)
printf("No newsrc\n");
yep(argv);
}
if ((rcfp = fopen(newsrc, "r")) == NULL)
xerror("Cannot open .newsrc file");
while (fgets(rcbuf, LBUFLEN, rcfp) != NULL) {
if (!nstrip(rcbuf))
xerror(".newsrc line too long");
if (++line >= LINES)
xerror("Too many .newsrc lines");
if ((rcline[line] = malloc(strlen(rcbuf)+1)) == NULL)
xerror("Not enough memory");
strcpy(rcline[line], rcbuf);
}
if ((actfp = fopen(ACTIVE, "r")) == NULL)
xerror("Cannot open active newsgroups file");
#ifdef DEBUG
fprintf(stderr, "header.nbuf = %s\n", header.nbuf);
#endif
nchk(argv);
exit(0);
}
nchk(argv)
char **argv;
{
register int i;
register char *ptr;
int l;
long narts;
char saveptr;
char aline[100];
#ifdef DEBUG
fprintf(stderr, "nchk()\n");
#endif
while (fgets(aline, sizeof aline, actfp) != NULL) {
sscanf(aline, "%s %ld", bfr, &narts);
#ifdef DEBUG
fprintf(stderr, "bfr = '%s'\n", bfr);
#endif
ngcat(bfr);
if (!ngmatch(bfr, header.nbuf))
continue;
ngdel(bfr);
i = findrcline(bfr);
if (i < 0) {
if (verbose>1)
printf("No newsrc line for newsgroup %s\n", bfr);
strcpy(rcbuf, " 0");
} else
strcpy(rcbuf, rcline[i]);
ptr = rcbuf;
if (index(rcbuf, '!') != NULL)
continue;
if (index(rcbuf, ',') != NULL) {
if (verbose>1)
printf("Comma in %s newsrc line\n", bfr);
yep(argv);
}
while (*ptr)
ptr++;
while (!isdigit(*--ptr) && ptr >= rcbuf)
;
if (ptr < rcbuf) {
if (verbose>1)
printf("Ran off beginning of %s newsrc line.\n", bfr);
yep(argv);
}
while (isdigit(*--ptr))
;
sscanf(++ptr, "%d", &l);
if (narts > l) {
if (verbose) {
printf("News: %s ...\n", bfr);
if (verbose < 2)
y = 0;
}
yep(argv);
}
contin:;
}
if (n)
printf("No news is good news.\n");
}
yep(argv)
char **argv;
{
if (y)
if (verbose)
printf("There is probably news.\n");
else
printf("There is news.\n");
if (e) {
#ifdef V6
execv("/usr/bin/readnews", argv);
#else
execvp("readnews", argv);
#endif
fprintf(stderr, "Cannot exec readnews.\n");
}
if (q)
exit(1);
else
exit(0);
}
xerror(message, arg1, arg2)
char *message;
int arg1, arg2;
{
char buffer[128];
sprintf(buffer, message, arg1, arg2);
fprintf(stderr, "checknews: %s.\n", buffer);
exit(1);
}
/*
* Append NGDELIM to string.
*/
ngcat(s)
register char *s;
{
if (*s) {
while (*s++);
s -= 2;
if (*s++ == NGDELIM)
return;
}
*s++ = NGDELIM;
*s = '\0';
}
/*
* News group matching.
*
* nglist is a list of newsgroups.
* sublist is a list of subscriptions.
* sublist may have "meta newsgroups" in it.
* All fields are NGDELIM separated,
* and there is an NGDELIM at the end of each argument.
*
* Currently implemented glitches:
* sublist uses 'all' like shell uses '*', and '.' like shell '/'.
* If subscription X matches Y, it also matches Y.anything.
*/
ngmatch(nglist, sublist)
register char *nglist, *sublist;
{
register char *n, *s;
register int rc;
rc = FALSE;
for (n = nglist; *n != '\0' && rc == FALSE;) {
for (s = sublist; *s != '\0';) {
if (*s != NEGCHAR)
rc |= ptrncmp(s, n);
else
rc &= ~ptrncmp(s+1, n);
while (*s++ != NGDELIM);
}
while (*n++ != NGDELIM);
}
return(rc);
}
/*
* Compare two newsgroups for equality.
* The first one may be a "meta" newsgroup.
*/
ptrncmp(ng1, ng2)
register char *ng1, *ng2;
{
while (*ng1 != NGDELIM) {
if (ng1[0]=='a' && ng1[1]=='l' && ng1[2]=='l') {
ng1 += 3;
while (*ng2 != NGDELIM && *ng2 != '.')
if (ptrncmp(ng1, ng2++))
return(TRUE);
return (ptrncmp(ng1, ng2));
} else if (*ng1++ != *ng2++)
return(FALSE);
}
return (*ng2 == '.' || *ng2 == NGDELIM);
}
/*
* Get user name and home directory.
*/
getuser()
{
static int flag = TRUE;
register struct passwd *p;
if (flag) {
if ((p = getpwuid(getuid())) == NULL)
xerror("Cannot get user's name");
if (username[0] == 0)
strcpy(username, p->pw_name);
strcpy(userhome, p->pw_dir);
flag = FALSE;
}
}
/*
* Strip trailing newlines, blanks, and tabs from 's'.
* Return TRUE if newline was found, else FALSE.
*/
nstrip(s)
register char *s;
{
register char *p;
register int rc;
rc = FALSE;
p = s;
while (*p)
if (*p++ == '\n')
rc = TRUE;
while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t'));
*++p = '\0';
return(rc);
}
/*
* Delete trailing NGDELIM.
*/
ngdel(s)
register char *s;
{
if (*s++) {
while (*s++);
s -= 2;
if (*s == NGDELIM)
*s = '\0';
}
}
lcase(s)
register char *s;
{
register char *ptr;
for (ptr = s; *ptr; ptr++)
if (isupper(*ptr))
*ptr = tolower(*ptr);
}
/*
* finds the line in your .newsrc file (actually the in-core "rcline"
* copy of it) and returns the index into the array where it was found.
* -1 means it didn't find it.
*
* We play clever games here to make this faster. It's inherently
* quadratic - we spend lots of CPU time here because we search through
* the whole .newsrc for each line. The "prev" variable remembers where
* the last match was found; we start the search there and loop around
* to the beginning, in the hopes that the calls will be roughly in order.
*/
int
findrcline(name)
char *name;
{
register char *p, *ptr;
register int cur;
register int i;
register int top;
static int prev = 0;
top = line; i = prev;
loop:
for (; i <= top; i++) {
for (p = name, ptr = rcline[i]; (cur = *p++); ) {
if (cur != *ptr++)
goto contin2;
}
if (*ptr != ':' && *ptr != '!')
continue;
prev = i;
return i;
contin2:
;
}
if (i > line && line > prev-1) {
i = 0;
top = prev-1;
goto loop;
}
return -1;
}
/*
* Forbid newsgroup ng, unless he asked for it in nbuf.
*/
makehimask(nbuf, ng)
char *nbuf, *ng;
{
if (!findex(nbuf, ng)) {
ngcat(nbuf);
strcat(nbuf, "!");
strcat(nbuf, ng);
ngcat(nbuf);
}
}
/*
* Return true if the string searchfor is in string, but not if preceeded by !.
*/
findex(string, searchfor)
char *string, *searchfor;
{
register char first;
register char *p;
first = *searchfor;
for (p=index(string, first); p; p = index(p+1, first)) {
if (p>string && p[-1] != '!' && strncmp(p, searchfor, strlen(searchfor)) == 0)
return TRUE;
}
return FALSE;
}