2.9BSD/usr/contrib/news/src/checknews.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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;
}