[comp.sources.unix] v19i090: Cnews production release, Part13/19

rsalz@uunet.uu.net (Rich Salz) (06/28/89)

Submitted-by: utzoo!henry
Posting-number: Volume 19, Issue 90
Archive-name: cnews2/part13

: ---CUT HERE---
echo 'nntpdiffs/src/misc.c':
sed 's/^X//' >'nntpdiffs/src/misc.c' <<'!'
X#ifndef lint
Xstatic char	*sccsid = "@(#)misc.c	1.25	(Berkeley) 2/6/88";
X#endif
X
X#include "../common/conf.h"
X
X#include "common.h"
X
X/*
X * open_valid_art -- determine if a given article name is valid;
X *		if it is, return a file pointer to the open article,
X *		along with a unique id of the article.
X *
X *	Parameters:	"artname" is a string containing the
X *			name of the article.
X *			"id" is space for us to put the article
X *			id in.
X *
X *	Returns:	File pointer to the open article if the
X *			article is valid; NULL otherwise
X *
X *	Side effects:	None.
X */
X
XFILE *
Xopen_valid_art(artname, id)
X	char		*artname;
X	char		*id;
X{
X	static int	crnt_art_num;
X	static char	crnt_art_id[MAXBUFLEN];
X	int		fd;
X	struct stat	statbuf;
X
X	if (art_fp != NULL) {
X		if (crnt_art_num == atoi(artname)) {
X			if (fseek(art_fp, (long) 0, 0) < 0)
X				close_crnt();
X			else {
X				(void) strcpy(id, crnt_art_id);
X				return (art_fp);
X			}
X		} else 
X			close_crnt();
X	}
X
X	art_fp = fopen(artname, "r");
X
X	if (art_fp == NULL)
X		return (NULL);
X
X	fd = fileno(art_fp);
X
X	if (fstat(fd, &statbuf) < 0) {
X		close_crnt();
X		return (NULL);
X	}
X
X	if ((statbuf.st_mode & S_IFREG) != S_IFREG) {
X		close_crnt();
X		return (NULL);
X	}
X
X	get_id(art_fp, id);
X	(void) strcpy(crnt_art_id, id);
X	crnt_art_num = atoi(artname);
X	return (art_fp);
X}
X
X
X/*
X * gethistent -- return the path name of an article if it's
X * in the history file.
X *
X *	Parameters:	"msg_id" is the message ID of the
X *			article, enclosed in <>'s.
X *
X *	Returns:	A char pointer to a static data area
X *			containing the full pathname of the
X *			article, or NULL if the message-id is not
X *			in thef history file.
X *
X *	Side effects:	opens dbm database
X *			(only once, keeps it open after that).
X */
X
X#ifndef NDBM
X# ifndef DBM
X#  ifndef USGHIST
X#   define USGHIST
X#  endif not USGHIST
X# endif not DBM
X#endif not DBM
X
Xchar *
Xgethistent(msg_id)
X	char		*msg_id;
X{
X	char		line[MAXBUFLEN];
X	char		*tmp;
X	register char	*cp;
X	long		ltmp;
X	static char	path[MAXPATHLEN];
X#ifdef USGHIST
X	char		*histfile();
X	register int	len;
X#else not USGHIST
X#ifdef DBM
X	static int	dbopen = 0;
X	datum		fetch();
X#else not DBM
X	static DBM	*db = NULL;	/* History file, dbm version */
X#endif DBM
X	datum		 key, content;
X#endif USGHIST
X	static FILE	*hfp = NULL;	/* history file, text version */
X
X#ifdef USGHIST
X	hfp = fopen(histfile(msg_id), "r");
X	if (hfp == NULL) {
X#ifdef SYSLOG
X		syslog(LOG_ERR, "gethistent: histfile: %m");
X#endif SYSLOG
X		return (NULL);
X	}
X
X	len = strlen(msg_id);
X	while (fgets(line, sizeof (line), hfp))
X		if (!strncasecmp(msg_id, line, len))
X			break;
X
X	if (feof(hfp)) {
X		(void) fclose(hfp);
X		return (NULL);
X	}
X#else not USGHIST
X#ifdef DBM
X	if (!dbopen) {
X		if (dbminit(historyfile) < 0) {
X#ifdef SYSLOG
X			syslog(LOG_ERR, "openartbyid: dbminit %s: %m",
X				historyfile);
X#endif SYSLOG
X			return (NULL);
X		} else
X			dbopen = 1;
X	}
X#else	/* ndbm */
X	if (db == NULL) {
X		db = dbm_open(historyfile, O_RDONLY, 0);
X		if (db == NULL) {
X#ifdef SYSLOG
X			syslog(LOG_ERR, "openartbyid: dbm_open %s: %m",
X				historyfile);
X#endif SYSLOG
X			return (NULL);
X		}
X	}
X#endif DBM
X
X	key.dptr = msg_id;
X	key.dsize = strlen(msg_id) + 1;
X
X#ifdef DBM
X	content = fetch(key);
X#else	/* ndbm */
X	content = dbm_fetch(db, key);
X#endif DBM
X	if (content.dptr == NULL)
X		return (NULL);
X
X	if (hfp == NULL) {
X		hfp = fopen(historyfile, "r");
X		if (hfp == NULL) {
X#ifdef SYSLOG
X			syslog(LOG_ERR, "message: fopen %s: %m",
X				historyfile);
X#endif SYSLOG
X			return (NULL);
X		}
X	}
X
X	bcopy(content.dptr, (char *)&ltmp, sizeof (long));
X	if (fseek(hfp, ltmp, 0) < 0) {
X#ifdef SYSLOG
X		syslog(LOG_ERR, "message: fseek: %m");
X#endif SYSLOG
X		return (NULL);
X	}
X
X	(void) fgets(line, sizeof(line), hfp);
X#endif USGHIST
X
X	if ((cp = index(line, '\n')) != NULL)
X		*cp = '\0';
X	cp = index(line, '\t');
X	if (cp != NULL)
X		cp = index(cp+1, '\t');
X	if (cp == NULL) {
X#ifdef SYSLOG
X		syslog(LOG_ERR,
X		"message: malformed line in history file at %ld bytes, id %s",
X			ltmp, msg_id);
X#endif SYSLOG
X		return (NULL);
X	}
X	tmp = cp+1;
X
X	if ((cp = index(tmp, ' ')) != NULL)
X		*cp = '\0';
X	
X	while ((cp = index(tmp, '.')) != NULL)
X		*cp = '/';
X
X	(void) strcpy(path, spooldir);
X	(void) strcat(path, "/");
X	(void) strcat(path, tmp);
X
X	return (path);
X}
X
X/*
X * openartbyid -- open an article by message-id.
X *
X *	Arguments:	"msg_id" is the message-id of the article
X *			to open.
X *
X *	Returns:	File pointer to opened article, or NULL if
X *			the article was not in the history file or
X *			could not be opened.
X *
X *	Side effects:	Opens article.
X */
X
XFILE *
Xopenartbyid(msg_id)
X	char	*msg_id;
X{
X	char	*path;
X
X	path = gethistent(msg_id);
X	if (path != NULL)
X		return (fopen(path, "r"));
X	else
X		return (NULL);
X}
X
X
X/*
X * check_ngperm -- check to see if they're allowed to see this
X * article by matching Newsgroups: and Distribution: line.
X *
X *	Parameters:	"fp" is the file pointer of this article.
X *
X *	Returns:	0 if they're not allowed to see it.
X *			1 if they are.
X *
X *	Side effects:	None.
X */
X
Xcheck_ngperm(fp)
X	register FILE	*fp;
X{
X	char		buf[MAXBUFLEN];
X	register char	*cp;
X	static char	**ngarray;
X	int		ngcount;
X
X	if (ngpermcount == 0)
X		return (1);
X
X	while (fgets(buf, sizeof (buf), fp) != NULL) {
X		if (buf[0] == '\n')		/* End of header */
X			break;
X		if (buf[0] != 'N' && buf[0] != 'n')
X			continue;
X		cp = index(buf, '\n');
X		if (cp)
X			*cp = '\0';
X		cp = index(buf, ':');
X		if (cp == NULL)
X			continue;
X		*cp = '\0';
X		if (!strcasecmp(buf, "newsgroups")) {
X			ngcount = get_nglist(&ngarray, cp+2);
X			break;
X		}
X	}
X
X	(void) rewind(fp);
X
X	if (ngcount == 0)	/* Either no newgroups or null entry */
X		return (1);
X
X	return (ngmatch(s1strneql, ALLBUT,
X		ngpermlist, ngpermcount, ngarray, ngcount));
X}
X
X
X/*
X * spew -- spew out the contents of a file to stdout, doing
X * the necessary cr-lf additions at the end.  Finish with
X * a "." on a line by itself, and an fflush(stdout).
X *
X *	Parameters:	"how" tells what part of the file we
X *			want spewed:
X *				ARTICLE   The entire thing.
X *				HEAD	  Just the first part.
X *				BODY	  Just the second part.
X *			"fp" is the open file to spew from.
X *
X *	Returns:	Nothing.
X *
X *	Side effects:	Changes current position in file.
X */
X
Xspew(fp, how)
X	FILE		*fp;
X	int		how;
X{
X	char		line[NNTP_STRLEN];
X	register char	*cp;
X
X#ifdef LOG
X	++arts_acsd;
X#endif
X
X	if (how == STAT) {
X		(void) fflush(stdout);
X		return;
X	}
X
X	while (fgets(line, sizeof(line)-6, fp) != NULL && *line != '\n') {
X		if (how == BODY)	/* We need to skip this anyway */
X			continue;
X		cp = index(line, '\n');
X		if (cp != NULL)
X			*cp = '\0';
X		if (*line == '.')
X			putchar('.');
X		putline(line);
X		if (cp == NULL) {
X			for (;;) {
X				if ((fgets(line, sizeof(line)-6, fp) == NULL)
X				    || (index(line, '\n') != NULL))
X					break;
X			}
X		}
X	}
X
X	if (how == HEAD) {
X		putchar('.');
X		putchar('\r');
X		putchar('\n');
X		(void) fflush(stdout);
X		return;
X	} else if (how == ARTICLE) {
X		putchar('\r');
X		putchar('\n');
X	}
X
X	while (fgets(line, sizeof(line)-6, fp) != NULL) {
X		cp = index(line, '\n');
X		if (cp != NULL)
X			*cp = '\0';
X		if (*line == '.')
X			putchar('.');
X		putline(line);
X
X		if (cp == NULL) {
X			for (;;) {
X				if ((fgets(line, sizeof(line)-6, fp) == NULL)
X				    || (index(line, '\n') != NULL))
X					break;
X			}
X		}
X	}
X	putchar('.');
X	putchar('\r');
X	putchar('\n');
X	(void) fflush(stdout);
X}
X
X
X/*
X * get_id -- get the message id of the current article.
X *
X *	Parameters:	"art_fp" is a pointer to the open file.
X *			"id" is space for the message ID.
X *
X *	Returns:	Nothing.
X *
X *	Side effects:	Seeks and rewinds on "art_fp".
X *			Changes space pointed to by "id".
X */
X
Xget_id(art_fp, id)
X	register FILE	*art_fp;
X	char		*id;
X{
X	char		line[MAXBUFLEN];
X	register char	*cp;
X
X	while (fgets(line, sizeof(line), art_fp) != NULL) {
X		if (*line == '\n')
X			break;
X		if (*line == 'M' || *line == 'm') {	/* "Message-ID" */
X			if ((cp = index(line, ' ')) != NULL) {
X				*cp = '\0';
X				if (!strcasecmp(line, "Message-ID:")) {
X					(void) strcpy(id, cp + 1);
X					if ((cp = index(id, '\n')) != NULL)
X						*cp = '\0';
X					(void) rewind(art_fp);
X					return;
X				}
X			}
X		}
X	}
X	(void) rewind(art_fp);
X	(void) strcpy(id, "<0>");
X}
X		
X
X/*
X * close_crnt -- close the current article file pointer, if it's
X *	open.
X *
X *	Parameters:	None.
X *
X *	Returns:	Nothing.
X *
X *	Side effects:	Closes "art_fp" if it's open; sets "art_fp" to NULL.
X */
X
Xclose_crnt()
X{
X	if (art_fp != NULL)
X		(void) fclose(art_fp);
X	art_fp = NULL;
X}
X
X
X/*
X * findart -- find an article number in the article array.
X *
X *	Parameters:	"artname" is a string containing
X *			the name of the article.
X *
X *	Returns:	An index into "art_array",
X *			or -1 if "artname" isn't in "art_array".
X *			
X *	Side effects:	None.
X *
X *	Improvement:	Replace this linear search with a binary one.
X */
X
Xfindart(artname)
X	char		*artname;
X{
X	register int	i, artnum;
X
X	artnum = atoi(artname);
X
X	for (i = 0; i < num_arts; ++i)
X		if (art_array[i] == artnum)
X			return(i);
X
X	return (-1);
X}
X
X
X/*
X * get_distlist -- return a nicely set up array of distribution groups
X * along with a count, when given an NNTP-spec distribution list
X * in the form <dist1,dist2,...,distn>.
X *
X *	Parameters:		"array" is storage for our array,
X *				set to point at some static data.
X *				"list" is the NNTP distribution list.
X *
X *	Returns:		Number of distributions found.
X *				-1 on error.
X *
X *	Side effects:		Changes static data area.
X */
X
Xget_distlist(array, list)
X	char		***array;
X	char		*list;
X{
X	char		*cp;
X	int		distcount;
X	static char	**dist_list = (char **) NULL;
X
X	if (list[0] != '<')
X		return (-1);
X
X	cp = index(list + 1, '>');
X	if (cp != NULL)
X		*cp = '\0';
X	else
X		return (-1);
X
X	for (cp = list + 1; *cp != '\0'; ++cp)
X		if (*cp == ',')
X			*cp = ' ';
X	distcount = parsit(list + 1, &dist_list);
X	*array = dist_list;
X	return (distcount);
X}
X
X
X/*
X * lower -- convert a character to lower case, if it's upper case.
X *
X *	Parameters:	"c" is the character to be
X *			converted.
X *
X *	Returns:	"c" if the character is not
X *			upper case, otherwise the lower
X *			case eqivalent of "c".
X *
X *	Side effects:	None.
X */
X
Xchar
Xlower(c)
X	register char	c;
X{
X	if (isascii(c) && isupper(c))
X		c = c - 'A' + 'a';
X	return (c);
X}
X
X
X/* the following is from news 2.11 */
X
X#ifdef USG
X/*
X** Generate the appropriate history subfile name
X*/
Xchar *
Xhistfile(hline)
Xchar *hline;
X{
X	char chr;	/* least significant digit of article number */
X	static char subfile[BUFSIZ];
X
X	chr = findhfdigit(hline);
X	sprintf(subfile, "%s.d/%c", HISTORY_FILE, chr);
X	return subfile;
X}
X
Xfindhfdigit(fn)
Xchar *fn;
X{
X	register char *p;
X	register int chr;
X
X	p = index(fn, '@');
X	if (p != NULL && p > fn)
X		chr = *(p - 1);
X	else
X		chr = '0';
X	if (!isdigit(chr))
X		chr = '0';
X	return chr;
X}
Xbcopy(s, d, l)
X	register char *s, *d;
X	register int l;
X{
X	while (l-- > 0)
X		*d++ = *s++;
X}
X
Xbcmp(s1, s2, l)
X	register char *s1, *s2;
X	register int l;
X{
X	if (l == 0)
X		return (0);
X
X	do
X		if (*s1++ != *s2++)
X			break;
X	while (--l);
X
X	return (l);
X}
X
Xbzero(p, l)
X	register char *p;
X	register int l;
X{
X	while (l-- > 0)
X		*p++ = 0;
X}
X
Xdup2(x,y)
Xint x,y;
X{ 
X	close(y); 
X	return(fcntl(x, F_DUPFD,y ));
X}
X#endif USG
!
echo 'nntpdiffs/src/newnews.c':
sed 's/^X//' >'nntpdiffs/src/newnews.c' <<'!'
X#ifndef lint
Xstatic char	*sccsid = "@(#)newnews.c	1.19	(Berkeley) 2/6/88";
X#endif
X
X#include "common.h"
X#include "time.h"
X
X#ifdef LOG
Xint	nn_told = 0;
Xint	nn_took = 0;
X#endif
X
X
X/*
X * NEWNEWS newsgroups date time ["GMT"] [<distributions>]
X *
X * Return the message-id's of any news articles past
X * a certain date and time, within the specified distributions.
X *
X */
X
Xnewnews(argc, argv)
X	register int	argc;
X	char		*argv[];
X{
X	register char	*cp, *ngp;
X	char		*key;
X	char		datebuf[32];
X	char		line[MAXBUFLEN];
X	char		**distlist, **histlist;
X	static char	**nglist;
X	int		distcount, ngcount, histcount;
X	int		all;
X	FILE		*fp;
X	long		date;
X	long		dtol();
X	char		*ltod();
X#ifdef USG
X	FILE		*tmplst;
X	int		i;
X	char		*tmpfile;
X#endif USG
X
X	if (argc < 4) {
X		printf("%d Usage: NEWNEWS newsgroups yymmdd hhmmss [\"GMT\"] [<distributions>].\r\n",
X			ERR_CMDSYN);
X		(void) fflush(stdout);
X		return;
X	}
X
X#ifdef LOG
X	sprintf(line, "%s newnews %s %s %s %s %s",
X		hostname,
X		argv[1],
X		argv[2],
X		argv[3],
X		(argc >= 5 && *argv[4] == 'G') ? "GMT" : "local",
X		(argc >= 5 && *argv[argc-1] == '<') ? argv[argc-1] : "none");
X	syslog(LOG_INFO, line);
X#endif
X
X	all = (argv[1][0] == '*' && argv[1][1] == '\0');
X	if (!all) {
X		ngcount = get_nglist(&nglist, argv[1]);
X		if (ngcount == 0) {
X			printf("%d Bogus newsgroup specifier: %s\r\n",
X				ERR_CMDSYN, argv[1]);
X			(void) fflush(stdout);
X			return;
X		}
X	}
X
X	/*	    YYMMDD		    HHMMSS	*/
X	if (strlen(argv[2]) != 6 || strlen(argv[3]) != 6) {
X		printf("%d Date/time must be in form YYMMDD HHMMSS.\r\n",
X			ERR_CMDSYN);
X		(void) fflush(stdout);
X		return;
X	}
X
X	(void) strcpy(datebuf, argv[2]);
X	(void) strcat(datebuf, argv[3]);
X
X	argc -= 4;
X	argv += 4;
X
X	/*
X	 * Flame on.  The history file is not stored in GMT, but
X	 * in local time.  So we have to convert GMT to local time
X	 * if we're given GMT, otherwise we need only chop off the
X	 * the seconds.  Such braindamage.
X	 */
X
X	key = datebuf;		/* Unless they specify GMT */
X
X	if (argc > 0) {
X		if (!strcasecmp(*argv, "GMT")) { /* Which we handle here */
X			date = dtol(datebuf);
X			if (date < 0) {
X				printf("%d Invalid date specification.\r\n",
X					ERR_CMDSYN);
X				(void) fflush(stdout);
X				return;
X			}
X			date = gmt_to_local(date);
X			key = ltod(date);
X			++argv;
X			--argc;
X		}
X	}
X
X	/* So, key now points to the local time, but we need to zap secs */
X
X	key[10] = '\0';
X
X	distcount = 0;
X	if (argc > 0) {
X		distcount = get_distlist(&distlist, *argv);
X		if (distcount < 0) {
X			printf("%d Bad distribution list: %s\r\n", ERR_CMDSYN,
X				*argv);
X			(void) fflush(stdout);
X			return;
X		}
X	}
X
X#ifdef USG
X    if ((tmpfile = mktemp("/tmp/listXXXXXX")) == NULL ||
X		(tmplst = fopen(tmpfile, "w+")) == NULL) {
X	printf("%d Cannot process history file.\r\n", ERR_FAULT);
X	(void) fflush(stdout);
X	return;
X    }
X
X    for (i = 0; i < 9; i++) {
X		sprintf(historyfile, "%s.d/%d", HISTORY_FILE, i);
X#endif USG
X
X	fp = fopen(historyfile, "r");
X	if (fp == NULL) {
X#ifdef SYSLOG
X		syslog(LOG_ERR, "newnews: fopen %s: %m", historyfile);
X#endif
X#ifndef USG
X		printf("%d Cannot open history file.\r\n", ERR_FAULT);
X		(void) fflush(stdout);
X		return;
X#else USG
X		continue;
X#endif USG
X	}
X
X#ifndef USG
X	printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
X#endif not USG
X
X	if (seekuntil(fp, key, line, sizeof (line)) < 0) {
X#ifndef USG
X		printf(".\r\n");
X		(void) fflush(stdout);
X#endif not USG
X		(void) fclose(fp);
X#ifndef USG
X		return;
X#else USG
X		continue;
X#endif USG
X	}
X
X/*
X * History file looks like:
X *
X * <1569@emory.UUCP>	01/22/86 09:19	net.micro.att/899 ucb.general/2545 
X *		     ^--tab            ^--tab		 ^--space         ^sp\0
X * Sometimes the newsgroups are missing; we try to be robust and
X * ignore such bogosity.  We tackle this by our usual parse routine,
X * and break the list of articles in the history file into an argv
X * array with one newsgroup per entry.
X */
X
X	do {
X		if ((cp = index(line, '\t')) == NULL)
X			continue;
X
X		if ((ngp = index(cp+1, '\t')) == NULL)	/* 2nd tab */
X			continue;
X		++ngp;			/* Points at newsgroup list */
X		if (*ngp == '\n')
X			continue;
X		histcount = get_histlist(&histlist, ngp);
X		if (histcount == 0)
X			continue;
X
X		/*
X		 * For each newsgroup on this line in the history
X		 * file, check it against the newsgroup names we're given.
X		 * If it matches, then see if we're hacking distributions.
X		 * If so, open the file and match the distribution line.
X		 */
X
X		if (!all)
X			if (!ngmatch(restreql, 0, nglist, ngcount,
X			    histlist, histcount))
X				continue;
X
X		if (distcount)
X			if (!distmatch(distlist, distcount, histlist, histcount))
X				continue;
X
X		*cp = '\0';
X#ifdef USG
X		fputs(line, tmplst);
X		fputc('\n', tmplst);
X#else not USG
X		putline(line);
X#endif not USG
X#ifdef LOG
X		nn_told++;
X#endif
X	} while (fgets(line, sizeof(line), fp) != NULL);
X
X#ifndef USG
X	putchar('.');
X	putchar('\r');
X	putchar('\n');
X	(void) fflush(stdout);
X#endif
X	(void) fclose(fp);
X#ifdef USG
X    }
X    printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
X    rewind(tmplst);
X    while (fgets(line, sizeof(line), tmplst) != NULL)
X            putline(line);
X    putchar('.');
X    putchar('\r');
X    putchar('\n');
X    (void) fflush(stdout);
X    (void) fclose(tmplst);
X    (void) unlink(tmpfile);
X#endif USG
X}
X
X
X/*
X * seekuntil -- seek through the history file looking for
X * a line with date "key".  Get that line, and return.
X *
X *	Parameters:	"fp" is the active file.
X *			"key" is the date, in form YYMMDDHHMM (no SS)
X *			"line" is storage for the first line we find.
X *
X *	Returns:	-1 on error, 0 otherwise.
X *
X *	Side effects:	Seeks in history file, modifies line.
X */
X
Xseekuntil(fp, akey, line, linesize)
X	FILE		*fp;
X	char		*akey;
X	char		*line;
X	int		linesize;
X{
X	char		datetime[32];
X	register int	c;
X	register long	top, bot, mid;
X	extern long dtol();
X	char key[30];
X
X	(void) sprintf(key, "%ld", dtol(akey));	/* akey -> time_t in ascii */
X	bot = 0;
X	(void) fseek(fp, 0L, 2);
X	top = ftell(fp);
X	for(;;) {
X		mid = (top+bot)/2;
X		(void) fseek(fp, mid, 0);
X		do {
X			c = getc(fp);
X			mid++;
X		} while (c != EOF && c!='\n');
X		if (!getword(fp, datetime, line, linesize)) {
X			return (-1);
X		}
X		switch (compare(key, datetime)) {
X		case -2:
X		case -1:
X		case 0:
X			if (top <= mid)
X				break;
X			top = mid;
X			continue;
X		case 1:
X		case 2:
X			bot = mid;
X			continue;
X		}
X		break;
X	}
X	(void) fseek(fp, bot, 0);
X	while(ftell(fp) < top) {
X		if (!getword(fp, datetime, line, linesize)) {
X			return (-1);
X		}
X		switch(compare(key, datetime)) {
X		case -2:
X		case -1:
X		case 0:
X			break;
X		case 1:
X		case 2:
X			continue;
X		}
X		break;
X	}
X
X	return (0);
X}
X
X
Xcompare(s, t)
X	register char *s, *t;
X{
X	for (; *s == *t; s++, t++)
X		if (*s == 0)
X			return(0);
X	return (*s == 0 ? -1:
X		*t == 0 ? 1:
X		*s < *t ? -2:
X		2);
X}
X
X
X/*
X * C news version of getword.
X */
Xgetword(fp, w, line, linesize)
X	FILE		*fp;
X	register char	*w;
X	char		*line;
X	int		linesize;
X{
X	register char	*cp;
X	extern char *index();
X
X	if (fgets(line, linesize, fp) == NULL)
X		return (0);
X	w[0] = '\0';				/* in case of bad format */
X	if (cp = index(line, '\t')) {		/* find 2nd field */
X		register char *endp;
X
X		*cp++ = '\0';
X		endp = index(cp, '~');		/* end of date-received */
X		if (endp == NULL)
X			endp = index(cp, '\t');	/* end of expiry */
X		if (endp != NULL) {
X			(void) strncpy(w, cp, endp - cp);
X			w[endp - cp] = '\0';
X		}
X	}
X	return (1);
X}
X
X
X/*
X * distmatch -- see if a file matches a set of distributions.
X * We have to do this by (yech!) opening the file, finding
X * the Distribution: line, if it has one, and seeing if the
X * things match.
X *
X *	Parameters:	"distlist" is the distribution list
X *			we want.
X *			"distcount" is the count of distributions in it.
X *			"grouplist" is the list of groups (articles)
X *			for this line of the history file.  Note that
X *			this isn't quite a filename.
X *			"groupcount" is the count of groups in it.
X *			
X *	Returns:	1 if the article is in the given distribution.
X *			0 otherwise.
X */
X
Xdistmatch(distlist, distcount, grouplist, groupcount)
X	char		*distlist[];
X	int		distcount;
X	char		*grouplist[];
X	int		groupcount;
X{
X	register char	c;
X	register char	*cp;
X	register FILE	*fp;
X	register int	i, j;
X	char		buf[MAXBUFLEN];
X
X	(void) strcpy(buf, spooldir);
X	(void) strcat(buf, "/");
X	(void) strcat(buf, grouplist[0]);
X
X	for (cp = buf; *cp; cp++)
X		if (*cp == '.')
X			*cp = '/';
X
X	fp = fopen(buf, "r");
X	if (fp == NULL) {
X#ifdef SYSLOG
X		syslog(LOG_ERR, "distmatch: fopen %s: %m", buf);
X#endif
X		return (0);
X	}
X
X	while (fgets(buf, sizeof (buf), fp) != NULL) {
X		if ((c = buf[0]) == '\n')		/* End of header */
X			break;
X		if (c != 'd' && c != 'D')
X			continue;
X		cp = index(cp + 1, '\n');
X		if (cp)
X			*cp = '\0';
X		cp = index(buf, ':');
X		if (cp == NULL)
X			continue;
X		*cp = '\0';
X		if (!strcasecmp(buf, "distribution")) {
X			for (i = 0; i < distcount; ++i) {
X				if (!strcasecmp(cp + 2, distlist[i])) {
X					(void) fclose(fp);
X					return (1);
X				}
X			}
X			(void) fclose(fp);
X			return (0);
X		}
X	}
X
X	(void) fclose(fp);
X
X	/*
X	 * We've finished the header with no distribution field.
X	 * So we'll assume that the distribution is the characters
X	 * up to the first dot in the newsgroup name.
X	 */
X
X	for (i = 0; i < groupcount; i++) {
X		cp = index(grouplist[i], '.');
X		if (cp)
X			*cp = '\0';
X		for (j = 0; j < distcount; j++)
X			if (!strcasecmp(grouplist[i], distlist[j]))
X				return (1);
X	}
X		
X	return (0);
X}
X
X
X/*
X * get_histlist -- return a nicely set up array of newsgroups
X * (actually, net.foo.bar/article_num) along with a count.
X *
X *	Parameters:		"array" is storage for our array,
X *				set to point at some static data.
X *				"list" is the history file newsgroup list.
X *
X *	Returns:		Number of group specs found.
X *
X *	Side effects:		Changes static data area.
X */
X
Xget_histlist(array, list)
X	char		***array;
X	char		*list;
X{
X	register int	histcount;
X	register char	*cp;
X	static	char	**hist_list = (char **) NULL;
X
X	cp = index(list, '\n');
X	if (cp)
X		*cp-- = '\0';
X	histcount = parsit(list, &hist_list);
X	*array = hist_list;
X	return (histcount);
X}
X
X
X/*
X * get_nglist -- return a nicely set up array of newsgroups
X * along with a count, when given an NNTP-spec newsgroup list
X * in the form ng1,ng2,ng...
X *
X *	Parameters:		"array" is storage for our array,
X *				set to point at some static data.
X *				"list" is the NNTP newsgroup list.
X *
X *	Returns:		Number of group specs found.
X *
X *	Side effects:		Changes static data area.
X */
X
Xget_nglist(array, list)
X	char		***array;
X	char		*list;
X{
X	register char	*cp;
X	register int	ngcount;
X
X	for (cp = list; *cp != '\0'; ++cp)
X		if (*cp == ',')
X			*cp = ' ';
X
X	ngcount = parsit(list, array);
X
X	return (ngcount);
X}
!
echo 'nntpdiffs/src/serve.c':
sed 's/^X//' >'nntpdiffs/src/serve.c' <<'!'
X#ifndef lint
Xstatic char	*sccsid = "@(#)serve.c	1.29	(Berkeley) 2/6/88";
X#endif
X
X/*
X * Main server routine
X */
X
X#include "common.h"
X#include <signal.h>
X#ifdef USG
X#include <sys/times.h>
X#else
X#include <sys/time.h>
X#endif
X
X#ifdef LOG
X# ifndef USG
X#  include <sys/resource.h>
X# endif not USG
X#endif
X
Xextern	int	ahbs(), group(), help(), ihave();
Xextern	int	list(), newgroups(), newnews(), nextlast(), post();
Xextern	int	slave(), stat(), xhdr();
X
Xstatic struct cmdent {
X	char	*cmd_name;
X	int	(*cmd_fctn)();
X} cmdtbl[] = {
X	"article",	ahbs,
X	"body",		ahbs,
X	"group",	group,
X	"head",		ahbs,
X	"help",		help,
X	"ihave",	ihave,
X	"last",		nextlast,
X	"list",		list,
X	"newgroups",	newgroups,
X	"newnews",	newnews,
X	"next",		nextlast,
X	"post",		post,
X	"slave",	slave,
X	"stat",		ahbs,
X#ifdef XHDR
X	"xhdr",		xhdr,
X#endif XHDR
X};
X#define NUMCMDS (sizeof(cmdtbl) / sizeof(struct cmdent))
X
X
X/*
X * serve -- given a connection on stdin/stdout, serve
X *	a client, executing commands until the client
X *	says goodbye.
X *
X *	Parameters:	None.
X *
X *	Returns:	Exits.
X *
X *	Side effects:	Talks to client, does a lot of
X *			stuff.
X */
X
Xserve()
X{
X	char		line[NNTP_STRLEN];
X	char		host[MAXHOSTNAMELEN];
X	char		gdbuf[MAXBUFLEN];
X	char		**argp;
X	char		*timeptr, *cp;
X	int		argnum, i;
X	double		Tstart, Tfinish;
X	double		user, sys;
X#ifdef USG
X	time_t		start, finish;
X#else not USG
X	struct timeval	start, finish;
X#endif not USG
X	extern char	*ctime();
X#ifdef POSTER
X	struct passwd	*pp;
X#endif
X#ifdef LOG
X# ifdef USG
X	struct tms	cpu;
X# else not USG
X	struct rusage	me, kids;
X# endif not USG
X# ifdef TIMEOUT
X	void		timeout();
X# endif
X	
X	grps_acsd = arts_acsd = 0;
X#endif
X
X	/* Not all systems pass fd's 1 and 2 from inetd */
X
X	(void) close(1);
X	(void) close(2);
X	(void) dup(0);
X	(void) dup(0);
X
X	/* If we're ALONE, then we've already opened syslog */
X
X#ifndef ALONE
X# ifdef SYSLOG
X#  ifdef BSD_42
X	openlog("nntpd", LOG_PID);
X#  else
X	openlog("nntpd", LOG_PID, SYSLOG);
X#  endif
X# endif
X#endif
X
X#ifdef ALONE
X#ifndef USG
X	(void) signal(SIGCHLD, SIG_IGN);
X#endif not USG
X#endif
X
X	/* Ignore SIGPIPE, since we'll see closed connections with read */
X
X	(void) signal(SIGPIPE, SIG_IGN);
X
X	/* Get permissions and see if we can talk to this client */
X
X	host_access(&canread, &canpost, &canxfer, gdbuf);
X
X	if (gethostname(host, sizeof(host)) < 0)
X		(void) strcpy(host, "Amnesiac");
X
X	if (!canread && !canxfer) {
X		printf("%d %s NNTP server can't talk to you.  Goodbye.\r\n",
X			ERR_ACCESS, host);
X		(void) fflush(stdout);
X#ifdef LOG
X		syslog(LOG_INFO, "%s refused connection", hostname);
X#endif
X		exit(1);
X	}
X
X	/* If we can talk, proceed with initialization */
X
X	ngpermcount = get_nglist(&ngpermlist, gdbuf);
X
X#ifdef POSTER
X	pp = getpwnam(POSTER);
X	if (pp != NULL) {
X		uid_poster = pp->pw_uid;
X		gid_poster = pp->pw_gid;
X	} else
X#endif
X		uid_poster = gid_poster = 0;
X
X#ifndef FASTFORK
X	num_groups = 0;
X	num_groups = read_groups();	/* Read in the active file */
X#else
X	signal(SIGALRM, SIG_IGN);	/* Children don't deal with */
X					/* these things */
X#endif
X
X	art_fp = NULL;
X	argp = (char **) NULL;		/* for first time */
X
X#ifdef USG
X	(void) time(&start);
X	Tstart = (double) start;
X	timeptr = ctime(&start);
X#else not USG
X	(void) gettimeofday(&start, (struct timezone *)NULL);
X	Tstart = (double) start.tv_sec - ((double)start.tv_usec)/1000000.0;
X	timeptr = ctime(&start.tv_sec);
X#endif not USG
X	if ((cp = index(timeptr, '\n')) != NULL)
X		*cp = '\0';
X	else
X		timeptr = "Unknown date";
X
X	printf("%d %s NNTP server version %s ready at %s (%s).\r\n",
X		canpost ? OK_CANPOST : OK_NOPOST,
X		host, nntp_version,
X		timeptr,
X		canpost ? "posting ok" : "no posting");
X	(void) fflush(stdout);
X
X	/*
X	 * Now get commands one at a time and execute the
X	 * appropriate routine to deal with them.
X	 */
X
X#ifdef TIMEOUT
X	(void) signal(SIGALRM, timeout);
X	(void) alarm(TIMEOUT);
X#endif TIMEOUT
X
X	while (fgets(line, sizeof(line), stdin) != NULL) {
X#ifdef TIMEOUT
X		(void) alarm(0);
X#endif TIMEOUT
X
X		cp = index(line, '\r');		/* Zap CR-LF */
X		if (cp != NULL)
X			*cp = '\0';
X		else {
X			cp = index(line, '\n');
X			if (cp != NULL)
X				*cp = '\0';
X		}
X
X		if ((argnum = parsit(line, &argp)) == 0)
X			continue;		/* Null command */
X		else {
X			for (i = 0; i < NUMCMDS; ++i)
X				if (!strcasecmp(cmdtbl[i].cmd_name, argp[0]))
X					break;
X			if (i < NUMCMDS)
X				(*cmdtbl[i].cmd_fctn)(argnum, argp);
X			else {
X				if (!strcasecmp(argp[0], "quit"))
X					break;
X#ifdef LOG
X				syslog(LOG_INFO, "%s unrecognized %s",
X					hostname,
X					line);
X#endif
X				printf("%d Command unrecognized.\r\n",
X					ERR_COMMAND);
X				(void) fflush(stdout);
X			}
X		}
X#ifdef TIMEOUT
X		(void) alarm(TIMEOUT);
X#endif TIMEOUT
X	}
X
X	printf("%d %s closing connection.  Goodbye.\r\n", OK_GOODBYE, host);
X	(void) fflush(stdout);
X#ifndef UNBATCHED_INPUT
X	{
X		char errbuf[2 * NNTP_STRLEN];
X
X		enqpartbatch(CONT_XFER, ERR_XFERFAIL, errbuf);
X	}
X#endif
X
X
X#ifdef LOG
X	if (ferror(stdout))
X		syslog(LOG_ERR, "%s disconnect: %m", hostname);
X
X#ifdef USG
X	(void) time(&finish);
X	Tfinish = (double) finish;
X
X#ifndef HZ
X#define	HZ	60.0	/* typical system clock ticks - param.h */
X#endif not HZ
X
X	(void) times(&cpu);
X	user = (double)(cpu.tms_utime + cpu.tms_cutime) / HZ;
X	sys  = (double)(cpu.tms_stime + cpu.tms_cstime) / HZ;
X#else not USG
X	(void) gettimeofday(&finish, (struct timezone *)NULL);
X	Tfinish = (double) finish.tv_sec - ((double)finish.tv_usec)/1000000.0;
X
X	(void) getrusage(RUSAGE_SELF, &me);
X	(void) getrusage(RUSAGE_CHILDREN, &kids);
X
X	user = (double) me.ru_utime.tv_sec + me.ru_utime.tv_usec/1000000.0 +
X		kids.ru_utime.tv_sec + kids.ru_utime.tv_usec/1000000.0;
X	sys = (double) me.ru_stime.tv_sec + me.ru_stime.tv_usec/1000000.0 +
X		kids.ru_stime.tv_sec + kids.ru_stime.tv_usec/1000000.0;
X#endif not USG
X	if (grps_acsd)
X		syslog(LOG_INFO, "%s exit %d articles %d groups",
X			hostname, arts_acsd, grps_acsd);
X	if (nn_told)
X		syslog(LOG_INFO, "%s newnews_stats told %d took %d",
X			hostname, nn_told, nn_took);
X	if (ih_accepted || ih_rejected || ih_failed)
X		syslog(LOG_INFO,
X			"%s ihave_stats accepted %d rejected %d failed %d",
X			hostname,
X			ih_accepted,
X			ih_rejected,
X			ih_failed);
X	(void) sprintf(line, "user %.1f system %.1f elapsed %.1f",
X		user, sys, Tfinish - Tstart);
X	syslog(LOG_INFO, "%s times %s", hostname, line);
X#endif LOG
X
X#ifdef PROFILE
X	profile();
X#endif
X	exit(0);
X}
X
X
X#ifdef TIMEOUT
X/*
X * No activity for TIMEOUT seconds, so print an error message
X * and close the connection.
X */
X
Xvoid
Xtimeout()
X{
X	printf("%d Timeout after %d seconds, closing connection.\r\n",
X		ERR_FAULT, TIMEOUT);
X	(void) fflush(stdout);
X
X#ifdef LOG
X	syslog(LOG_ERR, "%s timeout", hostname);
X#endif LOG
X
X	exit(1);
X}
X#endif TIMEOUT
!
echo 'nntpdiffs/src.allnew/batch.c':
sed 's/^X//' >'nntpdiffs/src.allnew/batch.c' <<'!'
X/*
X * rnews - setuid-news fake rnews for nntp: appends article to a batch with
X *	a fixed name under in.coming.  if batch is too big or old, rename
X *	batch to be an input candidate and kick off a newsrun to process
X *	the batch.  the batch file is locked during appending.
X * Cooperates with C news input subsystem.
X *	newsboot must be told to run partial batches left at a crash.
X */
X#include "../common/conf.h"
X#include "common.h"
X#include <signal.h>
X
X#define TOOBIG 300000L		/* batch > TOOBIG bytes, kick rnews */
X#define TOOOLD (5*60)		/* batch > TOOOLD seconds old, kick rnews */
X#define COPYSIZE 8192		/* bytes to copy at one time */
X#define MAXDIGITS 25		/* lg(maxlongint) + epsilon */
X#define MAXSTR 1024
X
X#define INDIR		artfile("in.coming")
X#define BATCHFILE	artfile("in.coming/nntp.XXXXXX")
X#define NEWSRUN		binfile("input/newsrun")
X
X#define YES 1
X#define NO 0
X
X/* imports */
Xextern time_t time();
Xextern char *malloc(), *mktemp(), *index(), *rindex();
X
X/* forwards */
Xstatic char *artfile(), *binfile(), *strsave();
Xstatic void error(), warning();
Xstatic int xfer_timeout();
X
X/* private data */
Xstatic char tempfile[256];
Xstatic int xfer_lines, old_xfer_lines;
X
Xstatic char art[COPYSIZE];		/* entire article, if it fits */
Xstatic char *endart = art;		/* points just past end of article */
Xstatic int incore = YES;
X
Xstatic struct batch_file {
X	char *name;
X	FILE *file;
X	char isopen;
X	time_t start;			/* time of creation */
X	off_t size;			/* current size */
X} btch = { NULL, NULL, NO, 0, 0 };
X
Xchar *progname = "nntpd";
X
X#ifndef lint
Xstatic	char	*sccsid = "@(#)batch.c	1.5	(Toronto) 31/4/89";
X#endif
X
X/*
X * stash stdin (up to ".") on the end of the batch input file.
X * kick newsrun if the batch is non-empty and too big or too old.
X *
X * Parameters:
X *	"cont_code" is the response code to transmit on successful startup.
X *	"err_code" is the response code to transmit when something goes wrong.
X *
X * Returns: -1 on non-zero return from child, 0 on error before fork/exec, 1 else.
X * Side effects: Creates and removes temporary file; accepts input from client.
X *		Can time out if XFER_TIMEOUT is defined.
X */
Xint
Xbatch_input_article(cont_code, err_code, errbuf)
Xint cont_code, err_code;
Xchar *errbuf;
X{
X	int status = 1;			/* okay status */
X
X	/* protect locking */
X	signal(SIGINT, SIG_IGN);
X	signal(SIGQUIT, SIG_IGN);
X	signal(SIGHUP, SIG_IGN);
X
X	if (btch.name == NULL) {
X		/* BATCHFILE may trigger unprivileged() */
X		btch.name = mktemp(strsave(BATCHFILE));
X	}
X	if (btch.name == NULL)
X		return 0;
X#ifdef notdef
X	(void) setgid(getegid());
X	(void) setuid(geteuid());
X#endif
X	tempfile[0] = '\0';
X	if (!cpstdin(cont_code, err_code, errbuf))	/* may create tempfile */
X		return 0;
X#ifdef POSTER
X	(void) chown(tempfile, uid_poster, gid_poster);
X#endif
X	status = appbatch();
X	if (tempfile[0] != '\0')
X		(void) unlink(tempfile);
X	if (status == 1 && oktorunbatch())
X		status = enqueue(cont_code, err_code, errbuf);
X	return status;
X}
X
Xint						/* boolean */
Xoktorunbatch()
X{
X	struct stat stbuf;
X
X	if (!btch.isopen || fstat(fileno(btch.file), &stbuf) < 0)
X		return NO;
X	btch.size = stbuf.st_size;
X	return btch.size > TOOBIG ||
X		btch.size > 0 && time((time_t *)NULL) - btch.start > TOOOLD;
X}
X
X/*
X * Copy standard input (up to a "." line) to art, if it fits,
X * else to a temporary file.
X */
X/* ARGSUSED errbuf */
Xstatic int					/* boolean: got article ok? */
Xcpstdin(cont_code, err_code, errbuf)
Xint cont_code, err_code;
Xchar *errbuf;
X{
X	register FILE *tfp = NULL;
X	register char *cp, *realline;
X	char line[NNTP_STRLEN];
X	int toobig = NO;
X	int (*otimeout)();
X
X	/* TODO: is this right?  used to open here, with errors here */
X	printf("%d Ok\r\n", cont_code);
X	(void) fflush(stdout);
X
X	xfer_lines = old_xfer_lines = 0;
X	incore = YES;
X	art[0] = '\0';
X	endart = art;
X#ifdef XFER_TIMEOUT
X	otimeout = signal(SIGALRM, xfer_timeout);
X	(void) alarm(XFER_TIMEOUT);
X#endif
X	while (fgets(line, sizeof line, stdin) != NULL) {
X		xfer_lines++;
X		if ((cp = rindex(line, '\r')) != NULL ||
X		    (cp = rindex(line, '\n')) != NULL)
X			*cp = '\0';			/* nuke CRLF */
X		if (line[0] == '.' && line[1] == '\0')
X			break;				/* article end: exit */
X		/* remove hidden dot if present */
X		realline = (line[0] == '.'? line+1: line);
X		if (toobig) {				/* straight to disk */
X			(void) fputs(realline, tfp);
X			(void) putc('\n', tfp);
X		} else {
X			int len = strlen(realline);
X
X			/*
X			 * Does art have room to append realline + \n\0?
X			 * If not, open temp file and dump art & realline there.
X			 */
X			if (sizeof art - (endart - art) < len + 1 + 1) {
X				(void) strcpy(tempfile, "/tmp/rpostXXXXXX");
X				(void) mktemp(tempfile);
X				tfp = fopen(tempfile, "w");
X				if (tfp == NULL) {
X					printf("%d Cannot create temporary file.\r\n",
X						err_code);
X					(void) fflush(stdout);
X					return 0;
X				}
X#ifdef OK_IN_MIDDLE_OKAY
X				else {
X					printf("%d Ok\r\n", cont_code);
X					(void) fflush(stdout);
X				}
X#endif
X				(void) fwrite(art, 1, endart - art, tfp);
X				toobig = YES;
X				incore = NO;
X				art[0] = '\0';
X				endart = art;
X				(void) fputs(realline, tfp);
X				(void) putc('\n', tfp);
X			} else {
X				/* fits: append realline\n to art at endart */
X				(void) strcpy(endart, realline);
X				endart += len;
X				*endart++ = '\n';
X				*endart = '\0';
X			}
X		}
X	}
X	if (tfp != NULL)
X		(void) fclose(tfp);
X#ifdef XFER_TIMEOUT
X	(void) alarm(0);
X	(void) signal(SIGALRM, otimeout);
X#endif
X
X	/* See if the connection got closed somehow... */
X	if (line[0] != '.' && line[1] != '\0') {
X		if (tempfile[0] != '\0')
X			(void) unlink(tempfile);
X#ifdef LOG
X		syslog(LOG_ERR, "%s spawn: EOF before period on line by itself",
X			hostname);
X#else
X		syslog(LOG_ERR, "spawn: EOF before period on line by itself");
X#endif
X		return 0;
X	}
X	return 1;
X}
X
Xstatic int
Xxfer_timeout()
X{
X#ifdef XFER_TIMEOUT
X	if (old_xfer_lines < xfer_lines) {
X		old_xfer_lines = xfer_lines;
X		(void) alarm(XFER_TIMEOUT);
X		return;
X	}
X	/* Timed out. */
X	printf("%d timeout after %d seconds, closing connection.\r\n",
X		ERR_FAULT, XFER_TIMEOUT);
X	fflush(stdout);
X#ifdef LOG
X	syslog(LOG_ERR, "%s transfer_timeout", hostname);
X#endif LOG
X	(void) unlink(tempfile);
X	exit(1);
X#endif XFER_TIMEOUT
X}
X
X/*
X * Append "#! rnews count" and art (or tempfile) to batch file, locking assumed.
X * If batch file is too big or too old (but not empty), feed it to newsrun.
X */
Xstatic int					/* same as batch_input_article */
Xappbatch()
X{
X	register FILE *tfp = NULL;
X	register int bytes = 0;
X	int status = 1;				/* okay status */
X	long size = 0;
X	char artbuf[COPYSIZE];
X	struct stat stbuf;
X
X	if (btch.file == NULL) {
X		btch.file = fopen(btch.name, "a");
X		if (btch.file == NULL)
X			return 0;
X		btch.isopen = YES;
X		btch.size = 0;
X		btch.start = time(&btch.start);
X	}
X
X	/* find article size and write the article */
X	if (incore)
X		size = endart - art;
X	else {
X		tfp = fopen(tempfile, "r");
X		if (tfp == NULL)
X			return 0;
X		if (fstat(fileno(tfp), &stbuf) >= 0)
X			size = stbuf.st_size;
X	}
X	(void) fprintf(btch.file, "#! rnews %ld\n", size);
X
X	/* copy the article to the batch file */
X	if (incore)
X		(void) fwrite(art, 1, endart - art, btch.file);
X	else {
X		while ((bytes = fread(artbuf, 1, sizeof artbuf, tfp)) > 0)
X			if (fwrite(artbuf, 1, bytes, btch.file) != bytes) {
X				warning("can't write %s", btch.name);
X				status = 0;	/* hmm, #! count is off */
X				break;
X			}
X		(void) fclose(tfp);
X	}
X	if (fflush(btch.file) == EOF) {
X		warning("can't write %s", btch.name);
X		status = 0;
X	}
X	return status;
X}
X
X/*
X * Enqueue any partial batch.  Called before exit.
X */
Xenqpartbatch(cont_code, err_code, errbuf)
Xint cont_code, err_code;
Xchar *errbuf;
X{
X	struct stat stbuf;
X
X	if (btch.isopen && fstat(fileno(btch.file), &stbuf) >= 0) {
X		if (btch.size > 0)
X			enqueue(cont_code, err_code, errbuf);
X		else {
X			(void) fclose(btch.file);
X			btch.file = NULL;
X			btch.isopen = NO;
X			(void) unlink(btch.name);	/* remove empty batch */
X		}
X	}
X}
X
X/* 
X * insert the batch file into the input subsystem queue by renaming
X * it to an all-numeric name, then kick newsrun to process it.
X * locks btch.name as appropriate.
X */
Xstatic int					/* same as batch_input_article */
Xenqueue(cont_code, err_code, errbuf)
Xint cont_code, err_code;
Xchar *errbuf;
X{
X	time_t now;
X	int pid, wpid, status, fd, exitstat;
X	char permname[MAXDIGITS], *number = permname, *newsrun;
X	struct stat stbuf;
X
X	(void) fclose(btch.file);
X	btch.file = NULL;
X	btch.isopen = NO;
X	btch.start = 0;
X	btch.size = 0;
X
X	(void) fflush(stdout);
X	(void) fflush(stderr);
X	pid = fork();
X	if (pid == -1) {
X		warning("can't fork", "");
X		return 0;
X	} else if (pid != 0) {			/* parent */
X		while ((wpid = wait(&status)) != -1 && wpid != pid)
X			;
X		exitstat = (status>>8)&0377;
X		if (exitstat != 0) {
X			syslog(LOG_ERR, "%s: enqueue returned exit status 0%o",
X				progname, exitstat);
X			strcpy(errbuf, "enqueue failed to run newsrun\n");
X		}
X		return exitstat != 0? -1 :1;
X	}
X
X	/* child: must exit */
X	for (fd = 3; fd < 20; fd++)
X		(void) close(fd);
X	if (chdir(INDIR) < 0) {
X		syslog(LOG_ERR, "%s: chdir(%s) failed", progname, INDIR);
X		nerror("can't change directory to %s", INDIR);
X	}
X
X	/* rename btch.name to a number so newsrun will see it */
X	sprintf(number, "%ld", (long)time(&now));
X	while (link(btch.name, permname) < 0) {
X		if (stat(btch.name, &stbuf) < 0)
X			break;
X		sleep(2);
X		sprintf(number, "%ld", (long)time(&now));
X	}
X	if (unlink(btch.name) < 0)
X		vanished(btch.name);
X
X	signal(SIGINT, SIG_IGN);
X	signal(SIGQUIT, SIG_IGN);
X	signal(SIGHUP, SIG_IGN);
X	(void) fflush(stdout);
X	(void) fflush(stderr);
X	newsrun = strsave(NEWSRUN);
X	if (newsrun == NULL)
X		newsrun = "/usr/lib/newsbin/input/newsrun";
X	execl(newsrun, newsrun, (char *)NULL);
X	syslog(LOG_ERR, "%s: can't run %s", progname, newsrun);
X	error("attempt to run %s failed!", newsrun);
X	exit(1);
X	/* NOTREACHED */
X}
X
Xvanished(s)					/* grieve for s, nerror [exit] */
Xchar *s;
X{
X	syslog(LOG_ERR, "%s: %s vanished underfoot!", progname, s);
X	nerror("%s vanished underfoot!", s);	/* unlocks, exits */
X}
X
Xstatic
Xnerror(fmt, s)				/* error, unused to be with unlock */
Xchar *fmt, *s;
X{
X	error(fmt, s);
X}
X
X/* C news library starts here */
X
X/*
X * error - print best error message possible and exit
X */
Xstatic void warning();
X
Xstatic void
Xerror(s1, s2)
Xchar *s1;
Xchar *s2;
X{
X	warning(s1, s2);
X	exit(1);
X}
X
X/*
X * warning - print best error message possible and clear errno
X */
Xextern int errno, sys_nerr;
Xextern char *sys_errlist[];
Xextern char *progname;
Xextern char *getenv();
X
Xstatic void
Xwarning(s1, s2)
Xchar *s1;
Xchar *s2;
X{
X	char *cmdname;
X
X	(void) fflush(stdout);				/* hack */
X	cmdname = getenv("CMDNAME");
X	if (cmdname != NULL && *cmdname != '\0')
X		fprintf(stderr, "%s:", cmdname);	/* No space after :. */
X	if (progname != NULL)
X		fprintf(stderr, "%s: ", progname);
X	fprintf(stderr, s1, s2);
X	if (errno > 0 && errno < sys_nerr)
X		fprintf(stderr, " (%s)", sys_errlist[errno]);
X	fprintf(stderr, "\n");
X	errno = 0;
X}
X
Xvoid
Xunprivileged()
X{
X	(void) setgid(getgid());
X	(void) setuid(getuid());
X}
X
Xstatic char *
Xartfile(s)
Xchar *s;
X{
X	static char name[MAXSTR];
X
X	strcpy(name, "/usr/spool/news/");
X	strcat(name, s);
X	return name;
X}
X
Xstatic char *
Xbinfile(s)
Xchar *s;
X{
X	static char name[MAXSTR];
X
X	strcpy(name, "/usr/lib/newsbin/");
X	strcat(name, s);
X	return name;
X}
X
X#ifdef notdef
Xstatic char *
Xctlfile(s)
Xchar *s;
X{
X	static char name[MAXSTR];
X
X	strcpy(name, "/usr/lib/news/");
X	strcat(name, s);
X	return name;
X}
X#endif
X
Xstatic char *
Xstrsave(s)
Xregister char *s;
X{
X	register char *news = malloc((unsigned)(strlen(s) + 1));
X
X	if (news != NULL)
X		strcpy(news, s);
X	return news;
X}
X
X#ifndef SYSLOG
X/* VARARGS 2 */
Xstatic
Xsyslog(level, fmt)
Xint level;
Xchar *fmt;
X{
X}
X#endif
X
!
echo 'nntpdiffs/cdiff.1.5.0':
sed 's/^X//' >'nntpdiffs/cdiff.1.5.0' <<'!'
XCommon subdirectories: ../nntp.1.5.0/common and ./common
XCommon subdirectories: ../nntp.1.5.0/doc and ./doc
XCommon subdirectories: ../nntp.1.5.0/inews and ./inews
XOnly in .: nntp.1.5.C.diff
XCommon subdirectories: ../nntp.1.5.0/rrnpatches and ./rrnpatches
XCommon subdirectories: ../nntp.1.5.0/server and ./server
XCommon subdirectories: ../nntp.1.5.0/support and ./support
XCommon subdirectories: ../nntp.1.5.0/xfer and ./xfer
XCommon subdirectories: ../nntp.1.5.0/xmit and ./xmit
Xdiff -r -c ../nntp.1.5.0/server/Makefile ./server/Makefile
X*** ../nntp.1.5.0/server/Makefile	Fri Feb 26 02:47:58 1988
X--- ./server/Makefile	Tue Jun  6 23:15:49 1989
X***************
X*** 3,8 ****
X--- 3,9 ----
X  #
X  
X  SRVROBJ = main.o serve.o access.o access_inet.o access_dnet.o active.o \
X+ 	batch.o \
X  	ahbs.o globals.o group.o help.o ihave.o list.o misc.o netaux.o \
X  	newgroups.o newnews.o nextlast.o ngmatch.o post.o parsit.o scandir.o \
X  	slave.o spawn.o strcasecmp.o subnet.o time.o xhdr.o fakesyslog.o \
X***************
X*** 9,14 ****
X--- 10,16 ----
X  	../common/version.o
X  
X  SRVRSRC = main.c serve.c access.c access_inet.c access_dnet.c active.c \
X+ 	batch.c \
X  	ahbs.c globals.c group.c help.c ihave.c list.c misc.c netaux.c \
X  	newgroups.c newnews.c nextlast.c ngmatch.c post.c parsit.c scandir.c \
X  	slave.c spawn.c strcasecmp.c subnet.c time.c xhdr.c fakesyslog.c \
X***************
X*** 19,25 ****
X  SRCS	= ${SRVRSRC}
X  
X  # -ldbm here if you've #define'ed DBM in ../common/conf.h
X! LIBS	=
X  
X  CFLAGS	= -O
X  
X--- 21,27 ----
X  SRCS	= ${SRVRSRC}
X  
X  # -ldbm here if you've #define'ed DBM in ../common/conf.h
X! LIBS	= -ldbm
X  
X  CFLAGS	= -O
X  
XOnly in ./server: batch.c
Xdiff -r -c ../nntp.1.5.0/server/ihave.c ./server/ihave.c
X*** ../nntp.1.5.0/server/ihave.c	Tue Jan 12 02:53:11 1988
X--- ./server/ihave.c	Tue Jun  6 23:15:52 1989
X***************
X*** 43,49 ****
X  		return;
X  	}
X  		
X! 	retcode = spawn(rnews, "rnews", (char *) 0, CONT_XFER, ERR_XFERFAIL, errbuf);
X  	if (retcode <= 0)
X  		printf("%d %s\r\n", ERR_XFERFAIL, errbuf);
X  	else if (retcode > 0)
X--- 43,55 ----
X  		return;
X  	}
X  		
X! #ifdef UNBATCHED_INPUT
X! 	retcode = spawn(rnews, "rnews", (char *) 0, CONT_XFER,
X! 		ERR_XFERFAIL, errbuf);
X! #else
X! 	/* C news input hook */
X! 	retcode = batch_input_article(CONT_XFER, ERR_XFERFAIL, errbuf);
X! #endif
X  	if (retcode <= 0)
X  		printf("%d %s\r\n", ERR_XFERFAIL, errbuf);
X  	else if (retcode > 0)
Xdiff -r -c ../nntp.1.5.0/server/misc.c ./server/misc.c
X*** ../nntp.1.5.0/server/misc.c	Sun Feb  7 01:29:33 1988
X--- ./server/misc.c	Tue Jun  6 23:15:54 1989
X***************
X*** 82,88 ****
X   *
X   *	Side effects:	opens dbm database
X   *			(only once, keeps it open after that).
X-  *			Converts "msg_id" to lower case.
X   */
X  
X  #ifndef NDBM
X--- 82,87 ----
X***************
X*** 115,124 ****
X  	datum		 key, content;
X  #endif USGHIST
X  	static FILE	*hfp = NULL;	/* history file, text version */
X- 
X- 	for (cp = msg_id; *cp != '\0'; ++cp)
X- 		if (isupper(*cp))
X- 			*cp = tolower(*cp);
X  
X  #ifdef USGHIST
X  	hfp = fopen(histfile(msg_id), "r");
X--- 114,119 ----
Xdiff -r -c ../nntp.1.5.0/server/newnews.c ./server/newnews.c
X*** ../nntp.1.5.0/server/newnews.c	Sat Feb  6 20:29:07 1988
X--- ./server/newnews.c	Tue Jun  6 23:15:57 1989
X***************
X*** 255,263 ****
X   *	Side effects:	Seeks in history file, modifies line.
X   */
X  
X! seekuntil(fp, key, line, linesize)
X  	FILE		*fp;
X! 	char		*key;
X  	char		*line;
X  	int		linesize;
X  {
X--- 255,263 ----
X   *	Side effects:	Seeks in history file, modifies line.
X   */
X  
X! seekuntil(fp, akey, line, linesize)
X  	FILE		*fp;
X! 	char		*akey;
X  	char		*line;
X  	int		linesize;
X  {
X***************
X*** 264,270 ****
X--- 264,273 ----
X  	char		datetime[32];
X  	register int	c;
X  	register long	top, bot, mid;
X+ 	extern long dtol();
X+ 	char key[30];
X  
X+ 	(void) sprintf(key, "%ld", dtol(akey));	/* akey -> time_t in ascii */
X  	bot = 0;
X  	(void) fseek(fp, 0L, 2);
X  	top = ftell(fp);
X***************
X*** 327,332 ****
X--- 330,338 ----
X  }
X  
X  
X+ /*
X+  * C news version of getword.
X+  */
X  getword(fp, w, line, linesize)
X  	FILE		*fp;
X  	register char	*w;
X***************
X*** 334,369 ****
X  	int		linesize;
X  {
X  	register char	*cp;
X  
X  	if (fgets(line, linesize, fp) == NULL)
X  		return (0);
X! 	if (cp = index(line, '\t')) {
X! /*
X!  * The following gross hack is present because the history file date
X!  * format is braindamaged.  They like "mm/dd/yy hh:mm", which is useless
X!  * for relative comparisons of dates using something like atoi() or
X!  * strcmp.  So, this changes their format into yymmddhhmm.  Sigh.
X!  *
X!  * 12345678901234	("x" for cp[x])
X!  * mm/dd/yy hh:mm 	(their lousy representation)
X!  * yymmddhhmm		(our good one)
X!  * 0123456789		("x" for w[x])
X!  */
X! 		*cp = '\0';
X! 		(void) strncpy(w, cp+1, 15);
X! 		w[0] = cp[7];		/* Years */
X! 		w[1] = cp[8];
X! 		w[2] = cp[1];		/* Months */
X! 		w[3] = cp[2];
X! 		w[4] = cp[4];		/* Days */
X! 		w[5] = cp[5];
X! 		w[6] = cp[10];		/* Hours */
X! 		w[7] = cp[11];
X! 		w[8] = cp[13];		/* Minutes */
X! 		w[9] = cp[14];
X! 		w[10] = '\0';
X! 	} else
X! 		w[0] = '\0';
X  	return (1);
X  }
X  
X--- 340,362 ----
X  	int		linesize;
X  {
X  	register char	*cp;
X+ 	extern char *index();
X  
X  	if (fgets(line, linesize, fp) == NULL)
X  		return (0);
X! 	w[0] = '\0';				/* in case of bad format */
X! 	if (cp = index(line, '\t')) {		/* find 2nd field */
X! 		register char *endp;
X! 
X! 		*cp++ = '\0';
X! 		endp = index(cp, '~');		/* end of date-received */
X! 		if (endp == NULL)
X! 			endp = index(cp, '\t');	/* end of expiry */
X! 		if (endp != NULL) {
X! 			(void) strncpy(w, cp, endp - cp);
X! 			w[endp - cp] = '\0';
X! 		}
X! 	}
X  	return (1);
X  }
X  
Xdiff -r -c ../nntp.1.5.0/server/serve.c ./server/serve.c
X*** ../nntp.1.5.0/server/serve.c	Thu Feb 25 22:49:21 1988
X--- ./server/serve.c	Tue Jun  6 23:16:00 1989
X***************
X*** 237,244 ****
X--- 237,251 ----
X  
X  	printf("%d %s closing connection.  Goodbye.\r\n", OK_GOODBYE, host);
X  	(void) fflush(stdout);
X+ #ifndef UNBATCHED_INPUT
X+ 	{
X+ 		char errbuf[2 * NNTP_STRLEN];
X  
X+ 		enqpartbatch(CONT_XFER, ERR_XFERFAIL, errbuf);
X+ 	}
X+ #endif
X  
X+ 
X  #ifdef LOG
X  	if (ferror(stdout))
X  		syslog(LOG_ERR, "%s disconnect: %m", hostname);
X***************
X*** 287,293 ****
X  #ifdef PROFILE
X  	profile();
X  #endif
X- 
X  	exit(0);
X  }
X  
X--- 294,299 ----
!
echo done


-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.