[comp.sources.unix] v19i091: Cnews production release, Part14/19

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

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

: ---CUT HERE---
echo 'nntpdiffs/cdiff.1.5.5':
sed 's/^X//' >'nntpdiffs/cdiff.1.5.5' <<'!'
XOnly in .: Cnews.diff
XCommon subdirectories: ../nntp.1.5.5/common and ./common
XCommon subdirectories: ../nntp.1.5.5/doc and ./doc
XCommon subdirectories: ../nntp.1.5.5/inews and ./inews
XCommon subdirectories: ../nntp.1.5.5/rrnpatches and ./rrnpatches
XCommon subdirectories: ../nntp.1.5.5/server and ./server
XCommon subdirectories: ../nntp.1.5.5/support and ./support
XCommon subdirectories: ../nntp.1.5.5/xfer and ./xfer
XCommon subdirectories: ../nntp.1.5.5/xmit and ./xmit
Xdiff -c -r ../nntp.1.5.5/server/Makefile ./server/Makefile
X*** ../nntp.1.5.5/server/Makefile	Tue Jun  6 22:46:14 1989
X--- ./server/Makefile	Tue Jun  6 23:33:45 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 -c -r ../nntp.1.5.5/server/ihave.c ./server/ihave.c
X*** ../nntp.1.5.5/server/ihave.c	Tue Jun  6 22:46:12 1989
X--- ./server/ihave.c	Tue Jun  6 23:47:02 1989
X***************
X*** 52,59 ****
X  	    (void) strcat(errbuf, " NNTP server out of space. Try later.");
X  
X  	    retcode = 0;		/* indicates that an error occurred */
X! 	} else retcode =
X! 	    spawn(rnews, "rnews", (char *) 0, CONT_XFER, ERR_XFERFAIL, errbuf);
X  
X  	if (retcode <= 0)
X  		printf("%d %s\r\n", ERR_XFERFAIL, errbuf);
X--- 52,65 ----
X  	    (void) strcat(errbuf, " NNTP server out of space. Try later.");
X  
X  	    retcode = 0;		/* indicates that an error occurred */
X! 	} else 
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  
X  	if (retcode <= 0)
X  		printf("%d %s\r\n", ERR_XFERFAIL, errbuf);
Xdiff -c -r ../nntp.1.5.5/server/misc.c ./server/misc.c
X*** ../nntp.1.5.5/server/misc.c	Tue Jun  6 22:46:12 1989
X--- ./server/misc.c	Tue Jun  6 23:33:46 1989
X***************
X*** 80,86 ****
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--- 80,85 ----
X***************
X*** 113,122 ****
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--- 112,117 ----
Xdiff -c -r ../nntp.1.5.5/server/newnews.c ./server/newnews.c
X*** ../nntp.1.5.5/server/newnews.c	Tue Jun  6 22:48:36 1989
X--- ./server/newnews.c	Tue Jun  6 23:33:46 1989
X***************
X*** 249,257 ****
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--- 249,257 ----
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*** 258,264 ****
X--- 258,267 ----
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*** 321,326 ****
X--- 324,332 ----
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*** 328,363 ****
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--- 334,356 ----
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 -c -r ../nntp.1.5.5/server/serve.c ./server/serve.c
X*** ../nntp.1.5.5/server/serve.c	Tue Jun  6 22:48:36 1989
X--- ./server/serve.c	Tue Jun  6 23:41:46 1989
X***************
X*** 263,268 ****
X--- 263,279 ----
X  
X  	(void) fflush(stdout);
X  
X+   	(void) fflush(stdout);
X+ 
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*** 311,317 ****
X  #ifdef PROFILE
X  	profile();
X  #endif
X- 
X  	exit(0);
X  }
X  
X--- 322,327 ----
!
echo 'relay/regress/out/active':
sed 's/^X//' >'relay/regress/out/active' <<'!'
Xcontrol 0000000001 00000 y
Xjunk 0000000000 00000 y
Xfoo 0000000000 00000 y
Xbar 0000000000 00000 y
Xtest.a 0000000002 00000 y
Xtest.b 0000000002 00000 y
Xtest.c 0000000001 00000 y
Xbaz 0000000000 00000 y
!
echo 'relay/regress/out/art1':
sed 's/^X//' >'relay/regress/out/art1' <<'!'
XPath: host!user
XFrom: user@host
XMessage-ID: <#1@host>
XNewsgroups: test.a
X
X## This should appear in test/a/1
!
echo 'relay/regress/out/art2':
sed 's/^X//' >'relay/regress/out/art2' <<'!'
XPath: host!user
XFrom: user@host
XMessage-ID: <#2@host>
XNewsgroups: test.b
X
X## This should appear in test/b/1
!
echo 'relay/regress/out/art3':
sed 's/^X//' >'relay/regress/out/art3' <<'!'
XPath: host!user
XFrom: user@host
XMessage-ID: <#3@host>
XNewsgroups: test.a,test.b
X
X## This should appear in test/a/2
X## This should appear in test/b/2
!
echo 'relay/regress/out/art4':
sed 's/^X//' >'relay/regress/out/art4' <<'!'
XPath: host!user
XFrom: user@host
XMessage-ID: <#4@host>
XNewsgroups: test.c
X
XThis should get cancelled.
!
echo 'relay/regress/out/art5':
sed 's/^X//' >'relay/regress/out/art5' <<'!'
XPath: host!user
XFrom: user@host
XMessage-ID: <#5@host>
XNewsgroups: test.c
XControl: cancel <#4@host>
X
X## This should appear in test/c/2
!
echo 'relay/regress/out/batch':
sed 's/^X//' >'relay/regress/out/batch' <<'!'
X#! rnews 108
XPath: host!user
XFrom: user@host
XMessage-ID: <#1@host>
XNewsgroups: test.a
X
X## This should appear in test/a/1
X#! rnews 108
XPath: host!user
XFrom: user@host
XMessage-ID: <#2@host>
XNewsgroups: test.b
X
X## This should appear in test/b/1
X#! rnews 149
XPath: host!user
XFrom: user@host
XMessage-ID: <#3@host>
XNewsgroups: test.a,test.b
X
X## This should appear in test/a/2
X## This should appear in test/b/2
X#! rnews 101
XPath: host!user
XFrom: user@host
XMessage-ID: <#4@host>
XNewsgroups: test.c
X
XThis should get cancelled.
X#! rnews 134
XPath: host!user
XFrom: user@host
XMessage-ID: <#5@host>
XNewsgroups: test.c
XControl: cancel <#4@host>
X
X## This should appear in test/c/2
!
echo 'relay/regress/out/errlog':
sed 's/^X//' >'relay/regress/out/errlog' <<'!'
!
echo 'relay/regress/out/history':
sed 's/^X//' >'relay/regress/out/history' <<'!'
X<#1@host>	TIME~-	test.a/1
X<#2@host>	TIME~-	test.b/1
X<#3@host>	TIME~-	test.a/2 test.b/2
X<#4@host>	TIME~-	test.c/1
X<#5@host>	TIME~-	control/1
!
echo 'relay/regress/out/log':
sed 's/^X//' >'relay/regress/out/log' <<'!'
XTIME host + <#1@host> foo
XTIME host + <#2@host> foo
XTIME host + <#3@host> foo
XTIME host + <#4@host> foo
XTIME host + <#5@host> foo
!
echo 'relay/regress/out/run':
sed 's/^X//' >'relay/regress/out/run' <<'!'
X#! /bin/sh
X# run relaynews test
Xhere=`pwd`
XNEWSARTS=$here
XNEWSBIN=$here
XNEWSCTL=$here
Xexport NEWSARTS NEWSBIN NEWSCTL
X
X./relaynews -r <batch >stdout 2>stderr
Xecho $? >status
!
echo 'relay/regress/out/sys':
sed 's/^X//' >'relay/regress/out/sys' <<'!'
XME:all
Xfoo:all:f:/dev/null
!
echo 'relay/regress/out/whoami':
sed 's/^X//' >'relay/regress/out/whoami' <<'!'
Xhostb
!
echo 'relay/regress/out/stdout':
sed 's/^X//' >'relay/regress/out/stdout' <<'!'
!
echo 'relay/regress/out/stderr':
sed 's/^X//' >'relay/regress/out/stderr' <<'!'
!
echo 'relay/regress/out/test/a/1':
sed 's/^X//' >'relay/regress/out/test/a/1' <<'!'
XPath: hostb!host!user
XFrom: user@host
XMessage-ID: <#1@host>
XNewsgroups: test.a
X
X## This should appear in test/a/1
!
echo 'relay/regress/out/test/a/2':
sed 's/^X//' >'relay/regress/out/test/a/2' <<'!'
XXref: hostb test.a:2 test.b:2
XPath: hostb!host!user
XFrom: user@host
XMessage-ID: <#3@host>
XNewsgroups: test.a,test.b
X
X## This should appear in test/a/2
X## This should appear in test/b/2
!
echo 'relay/regress/out/test/b/1':
sed 's/^X//' >'relay/regress/out/test/b/1' <<'!'
XPath: hostb!host!user
XFrom: user@host
XMessage-ID: <#2@host>
XNewsgroups: test.b
X
X## This should appear in test/b/1
!
echo 'relay/regress/out/test/b/2':
sed 's/^X//' >'relay/regress/out/test/b/2' <<'!'
XXref: hostb test.a:2 test.b:2
XPath: hostb!host!user
XFrom: user@host
XMessage-ID: <#3@host>
XNewsgroups: test.a,test.b
X
X## This should appear in test/a/2
X## This should appear in test/b/2
!
echo 'relay/regress/out/control/1':
sed 's/^X//' >'relay/regress/out/control/1' <<'!'
XPath: hostb!host!user
XFrom: user@host
XMessage-ID: <#5@host>
XNewsgroups: test.c
XControl: cancel <#4@host>
X
X## This should appear in test/c/2
!
echo 'relay/regress/out/status':
sed 's/^X//' >'relay/regress/out/status' <<'!'
X0
!
echo 'relay/regress/regress':
sed 's/^X//' >'relay/regress/regress' <<'!'
X#! /bin/sh
XPATH=".:$PATH"
Xecho removing old dregs...
Xrm -rf tmp
Xecho making new working subtree...
Xmkdir tmp 2>/dev/null
Xchmod +x master/run
Xcp ../relaynews master/* tmp
Xcd tmp
Xchmod u+w *
Xecho running relaynews...
X./run
Xecho comparing output...
Xsed 's/^... .. ..:..:..\..../TIME/' log >.log && mv .log log
Xsed 's/	[0-9][0-9]*~/	TIME~/' history >.history && mv .history history
Xrm -f gmon.out history.* relaynews
X# diff -r ../out .
Xfor f in `find . -type f -print`
Xdo
X	cmp $f ../out/$f
Xdone
!
echo 'relay/regress/master/active':
sed 's/^X//' >'relay/regress/master/active' <<'!'
Xcontrol 0000000000 00000 y
Xjunk 0000000000 00000 y
Xfoo 0000000000 00000 y
Xbar 0000000000 00000 y
Xtest.a 0000000000 00000 y
Xtest.b 0000000000 00000 y
Xtest.c 0000000000 00000 y
Xbaz 0000000000 00000 y
!
echo 'relay/regress/master/art1':
sed 's/^X//' >'relay/regress/master/art1' <<'!'
XPath: host!user
XFrom: user@host
XMessage-ID: <#1@host>
XNewsgroups: test.a
X
X## This should appear in test/a/1
!
echo 'relay/regress/master/art2':
sed 's/^X//' >'relay/regress/master/art2' <<'!'
XPath: host!user
XFrom: user@host
XMessage-ID: <#2@host>
XNewsgroups: test.b
X
X## This should appear in test/b/1
!
echo 'relay/regress/master/art3':
sed 's/^X//' >'relay/regress/master/art3' <<'!'
XPath: host!user
XFrom: user@host
XMessage-ID: <#3@host>
XNewsgroups: test.a,test.b
X
X## This should appear in test/a/2
X## This should appear in test/b/2
!
echo 'relay/regress/master/art4':
sed 's/^X//' >'relay/regress/master/art4' <<'!'
XPath: host!user
XFrom: user@host
XMessage-ID: <#4@host>
XNewsgroups: test.c
X
XThis should get cancelled.
!
echo 'relay/regress/master/art5':
sed 's/^X//' >'relay/regress/master/art5' <<'!'
XPath: host!user
XFrom: user@host
XMessage-ID: <#5@host>
XNewsgroups: test.c
XControl: cancel <#4@host>
X
X## This should appear in test/c/2
!
echo 'relay/regress/master/batch':
sed 's/^X//' >'relay/regress/master/batch' <<'!'
X#! rnews 108
XPath: host!user
XFrom: user@host
XMessage-ID: <#1@host>
XNewsgroups: test.a
X
X## This should appear in test/a/1
X#! rnews 108
XPath: host!user
XFrom: user@host
XMessage-ID: <#2@host>
XNewsgroups: test.b
X
X## This should appear in test/b/1
X#! rnews 149
XPath: host!user
XFrom: user@host
XMessage-ID: <#3@host>
XNewsgroups: test.a,test.b
X
X## This should appear in test/a/2
X## This should appear in test/b/2
X#! rnews 101
XPath: host!user
XFrom: user@host
XMessage-ID: <#4@host>
XNewsgroups: test.c
X
XThis should get cancelled.
X#! rnews 134
XPath: host!user
XFrom: user@host
XMessage-ID: <#5@host>
XNewsgroups: test.c
XControl: cancel <#4@host>
X
X## This should appear in test/c/2
!
echo 'relay/regress/master/errlog':
sed 's/^X//' >'relay/regress/master/errlog' <<'!'
!
echo 'relay/regress/master/history':
sed 's/^X//' >'relay/regress/master/history' <<'!'
!
echo 'relay/regress/master/history.dir':
sed 's/^X//' >'relay/regress/master/history.dir' <<'!'
!
echo 'relay/regress/master/history.pag':
sed 's/^X//' >'relay/regress/master/history.pag' <<'!'
!
echo 'relay/regress/master/log':
sed 's/^X//' >'relay/regress/master/log' <<'!'
!
echo 'relay/regress/master/run':
sed 's/^X//' >'relay/regress/master/run' <<'!'
X#! /bin/sh
X# run relaynews test
Xhere=`pwd`
XNEWSARTS=$here
XNEWSBIN=$here
XNEWSCTL=$here
Xexport NEWSARTS NEWSBIN NEWSCTL
X
X./relaynews -r <batch >stdout 2>stderr
Xecho $? >status
!
echo 'relay/regress/master/sys':
sed 's/^X//' >'relay/regress/master/sys' <<'!'
XME:all
Xfoo:all:f:/dev/null
!
echo 'relay/regress/master/whoami':
sed 's/^X//' >'relay/regress/master/whoami' <<'!'
Xhostb
!
echo 'relay/README':
sed 's/^X//' >'relay/README' <<'!'
XThis is relaynews, the heart of C News:  article filing.
X
XIf you're starting here, you are in the wrong place:  go to ../conf and
Xrun "build".
X
XSubdirectories are:
X
Xads	some silliness
Xanews	stuff for conversion to and from the old A News format
Xaux	auxiliary programs of various kinds
Xctl	control-message shell files
Xaltctl	alternative, not recommended, versions of rmgroup and sendgroups
Xsh	shell files, including inews and postnews and their flunkies
Xregress	regression-test facilities for relaynews
X
Xihave.not.c is an alternate version of ihave.c for sites that specifically
Xwish to disable ihave/sendme (typically because of foolishness like
Xproprietary newsgroups).
X
XTo run a regression test, "make r".
!
echo 'relay/active.c':
sed 's/^X//' >'relay/active.c' <<'!'
X/*
X * active file access functions
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "libc.h"
X#include "news.h"
X#include "config.h"
X#include "active.h"
X
X/* ordinal numbers of fields */
X#define CURRFIELD 2		/* current article # */
X#define FLAGFIELD 4		/* y/n/m/x/= flag */
X
X/* flag field values */
X#define FLAGOKAY 'y'		/* ordinary unmoderated group */
X#define FLAGBAD 'n'		/* unmoderated but locally-restricted group */
X#define FLAGMOD 'm'		/* moderated group */
X#define FLAGNEVER 'x'		/* unwanted group: don't file in this one */
X#define FLAGGOTO '='		/* see another group (following) instead */
X
X/* imports */
Xextern char *actfind();
Xextern statust actfload(), actfsync(), actfwrnum();
X
X/* forwards */
Xextern char *findflag();
XFORWARD char *fieldfind();
X
X/* exports */
Xchar actrelnm[] = "active";
X
Xstatic FILE *actfp = NULL;
Xstatic struct lastngcache {
X	char *lnc_ng;			/* newsgroup name */
X	char *lnc_line;			/* matching active file line */
X} lnc = { NULL, NULL };
X
X/*
X * return a pointer to the active file entry for ng
X * (or a pointed-to group (by ``=group'')), or 0 if no entry exists.
X * since actlook is called repeatedly for the same newsgroup,
X * actlook caches the last newsgroup looked-up and the result.
X */
XSTATIC char *
Xactlook(ang)
Xregister char *ang;
X{
X	register char *ngline, *ng, *flag;
X	register int loopbreak = 100;
X
X	if (lnc.lnc_ng != NULL && STREQ(lnc.lnc_ng, ang))
X		return lnc.lnc_line;
X
X	if (actload() != ST_OKAY)
X		return NULL;
X	ng = strsave(ang);
X	while ((ngline = actfind(actfp, ng, strlen(ng))) != NULL &&
X	    (flag = findflag(ngline)) != NULL && *flag == FLAGGOTO &&
X	    --loopbreak > 0) {
X		free(ng);
X	    	ng = strsvto(flag+1, '\n');	/* follow "=ng" pointer */
X	}
X	if (loopbreak <= 0)			/* "infinite" loop broken */
X		ngline = NULL;
X
X	nnfree(&lnc.lnc_ng);
X	lnc.lnc_ng = ng;
X	lnc.lnc_line = ngline;
X	return ngline;
X}
X
X/*
X * Find the active entry for ng (or a pointed-to group (by ``=group''))
X * and add inc to its 2nd field (highest number).
X * Return the resultant number.
X */
Xlong
Xincartnum(ng, inc)
Xchar *ng;
Xint inc;
X{
X	char testnum[40];
X	register char *line = actlook(ng);
X	register long nextart = -1;
X
X	if (line != NULL) {
X		register char *artnum, *pastartnum;
X
X		pastartnum = artnum = fieldfind(line, CURRFIELD);
X		if (artnum == NULL)
X			return nextart;
X		while (isascii(*pastartnum) && isdigit(*pastartnum))
X			++pastartnum;
X		nextart = atol(artnum) + inc;
X
X		/* update active file article # in place, from nextart */
X		if (pastartnum-artnum > sizeof testnum ||
X		    !ltozan(testnum, nextart, pastartnum-artnum) ||
X		    !ltozan(artnum, nextart, pastartnum-artnum)) {
X			(void) fprintf(stderr,
X"%s: article number (%ld) too big for group `%s' active field of %d digits\n",
X				progname, nextart, ng, pastartnum-artnum);
X			return -1;
X		}
X
X		/* give the implementation a chance to write line to disk */
X		if (actfwrnum(actfp, line) != ST_OKAY) {
X			warning("can't update active file", "");
X			nextart = -1;
X		}
X	}
X	return nextart;
X}
X
X/*
X * Reload the active file cache.
X */
Xstatust
Xactload()
X{
X	register statust status = ST_OKAY;
X
X	if (actfp == NULL &&
X	    (actfp = fopenwclex(ctlfile(actrelnm), "r+")) == NULL)
X		status |= ST_DROPPED;
X	status |= actfload(actfp);
X	return status;
X}
X
X/*
X * Write back to disk the active file cache, if any, and flush the
X * last-newsgroup-cache, since it refers to the (now invalid) active file cache.
X */
Xstatust
Xactsync()
X{
X	register statust status = ST_OKAY;
X
X	if (actfp != NULL) {
X		lnc.lnc_ng = lnc.lnc_line = NULL;
X		status |= actfsync(actfp);
X		if (nfclose(actfp) == EOF || status != ST_OKAY) {
X			warning("error writing `%s'", ctlfile(actrelnm));
X			status |= ST_DROPPED;
X		}
X	}
X	actfp = NULL;
X	return status;
X}
X
X/*
X * Return YES iff any group in ngs (or a pointed-to group (by ``=group''))
X * matches thisflag.
X */
Xboolean
Xisflag(ngs, thisflag)
Xregister char *ngs;
Xint thisflag;
X{
X	register char *newng, *flag, *ng;
X	register boolean result = NO;
X
X	for (ng = ngs; !result && ng != NULL; ng = newng) {
X		newng = index(ng, NGSEP);
X		if (newng != NULL)
X			*newng = '\0';		/* restored below */
X
X		flag = findflag(actlook(ng));
X		if (flag != NULL && *flag == thisflag)
X			result = YES;
X
X		if (newng != NULL)
X			*newng++ = NGSEP;	/* point at next group */
X	}
X	return result;
X}
X
XSTATIC char *
Xfieldfind(ngline, fieldno)	/* return address of field "fieldno" in ngline */
Xregister char *ngline;
Xregister int fieldno;
X{
X	register int field;
X
X	for (field = 1; ngline != NULL && field < fieldno; ++field) {
X		ngline = index(ngline, ' ');
X		if (ngline != NULL)
X			ngline++;		/* point at next field */
X	}
X	return ngline;
X}
X
Xchar *
Xfindflag(ngline)		/* return address of flag field in ngline */
Xregister char *ngline;
X{
X	return fieldfind(ngline, FLAGFIELD);
X}
X
X/*
X * Are any groups in ngs moderated?
X */
Xboolean
Xmoderated(ngs)
Xregister char *ngs;
X{
X	return isflag(ngs, FLAGMOD);
X}
X
X/*
X * Are any groups in ngs unwanted?
X */
Xboolean
Xunwanted(ngs)
Xregister char *ngs;
X{
X	return isflag(ngs, FLAGNEVER);
X}
X
X/*
X * Return 0 or a malloced newsgroup name corresponding to "ong",
X * but without an "=" flag in its active file entry.
X * This is done by tracing the chain of "=ng" pointers (in actlook()), if any.
X */
Xchar *
Xrealngname(ong)
Xchar *ong;
X{
X	register char *ngline = actlook(ong);
X
X	if (ngline == NULL)
X		return NULL;			/* no such ong */
X	return strsvto(ngline, ' ');
X}
!
echo 'relay/active.h':
sed 's/^X//' >'relay/active.h' <<'!'
X/* imports from active.c */
Xextern statust actload(), actsync();
Xextern long incartnum();
Xextern char *realngname();
Xextern boolean isflag(), unwanted(), moderated();
X
X#define nxtartnum(ng) incartnum(ng, 1)
X#define prevartnum(ng) incartnum(ng, -1)
!
echo 'relay/ads/1':
sed 's/^X//' >'relay/ads/1' <<'!'
XINEWS. We have
Xthe technology
Xtoday to bring 'em
Xback tomorrow.
X
X    By the 1990s, fighter pilots will need an inte-
Xgrated electronic warfare suite that fuses the
Xcapabilities of multiple warning and response sys-
Xtems. Advanced technology that provides complete
Xprotection with greater reliability. That system is the
XIntegrated Electronic Warfare System - INEWS.
X    The TRW/Westinghouse Joint Venture is the
Xonly team that offers such a powerful combination
Xof advanced technologies and specific, long-term
Xexperience for INEWS.
X    Our Phase I and II VHSIC contracts, together
Xwith our VHSIC 1750A program, will increase pro-
Xcessing speed and memory and reduce space and
Xpower demands. Our wideband microwave trans-
Xmitters and receivers can make functional integra-
Xtion a cost-effective, operational reality. Our detector
Xtechnologies ensure instant warning of all fore-
Xseeable threats. And our expendables technology
Xprovides a wide range of threat-response options.
X    TRW and Westinghouse with
XHoneywell, Perkin-Elmer, and Tracor.
XThe team with the technology today
Xto bring 'em back tomorrow.
X
X  TRW
!
echo 'relay/ads/2':
sed 's/^X//' >'relay/ads/2' <<'!'
XINEWS. Technology on a totally different plane.
X
X    The Raytheon-Northrop joint
Xventure team brings state-of-the-art
Xtechnology to the competition for
Xthe Integrated Electronic Warfare
XSystem. INEWS will go aboard the
Xnext generation of tactical aircraft.
X    The combination of Raytheon
Xand Northrop unites their comple-
Xmentary capabilities in the design,
Xdevelopment and production of
Xinnovative EW systems.
X    Team members AT&T Tech-
Xnology Systems (Bell Labs), GTE,
XMagnavox and Tracor provide
Xadditional experience which is
Xkey to successful integration of
Xadvanced technologies.
X    No other EW team provides
Xthis same level of expertise in
Xradar systems, surface-to-air mis-
Xsiles and advanced tactical and
Xstrategic aircraft. Strengths that
Xare essential to INEWS develop-
Xment and support.
X    The Raytheon and Northrop
Xjoint venture team. Expertise on a
Xtotally different plane.
X
XRaytheon NORTHROP
XJoint venture program office
X6380 Hollister Avenue
XGoleta, CA 93117
!
echo 'relay/ads/3':
sed 's/^X//' >'relay/ads/3' <<'!'
XINEWS.
XTheir future
Xdepends on it.
X
XIn the 1990's and beyond, our pilots' survival and
Xtheir mission success will rely on an effective
XIntegrated Electronic Warfare Systems (INEWS).
XGuaranteeing the best INEWS for tomorrow
Xmeans selecting the right team to build it today.
X     With Honeywell, Perkin-Elmer, and Tracor,
Xthe TRW/Westinghouse team brings an un-
Xrivaled program and technology baseline to
XINEWS. Together we are concentrating on
Xsystem level development...providing risk
Xreduction where it counts: system software
Xand system integration.
X     Our team offers Ada on VHSIC, complete
XINEWS system simulation, expert system devel-
Xopment for full situation awareness and response
Xmanagement, and reliability and maintainability
Xrisk reduction to reduce operation and support
Xcosts while increasing system availability. The
XTRW/Westinghouse INEWS--reliable perform-
Xance to beat the threat, sustainable in conflict,
Xaffordable for a lifetime.
X    INEWS: The System for Their Future--
Xfrom TRW and Westinghouse.
X
X	TRW
!
echo 'relay/ads/README':
sed 's/^X//' >'relay/ads/README' <<'!'
XThese are reproduced verbatim from Aviation Week.
!
echo 'relay/anews/a.samp':
sed 's/^X//' >'relay/anews/a.samp' <<'!'
XA123@utcs.fun
Xnet.rec.drugs.crack
Xucbvax!ucbarpa!foo
XApr  1 00:00:00 1986
XWhee!
XBoy I like this stuff!
!
echo 'relay/anews/a.samp.to.b':
sed 's/^X//' >'relay/anews/a.samp.to.b' <<'!'
XMessage-ID: 123@utcs.fun
XNewsgroups: net.rec.drugs.crack
XPath: ucbvax!ucbarpa!foo
XFrom: ucbvax!ucbarpa!foo
XDate: Apr  1 00:00:00 1986
XSubject: Whee!
X
XBoy I like this stuff!
!
echo 'relay/anews/a.to.b':
sed 's/^X//' >'relay/anews/a.to.b' <<'!'
X#! /bin/sh
X# a.to.b: A-format news to B-format converter (thanks, Norman)
XPATH=/bin:/usr/bin:/usr/ucb; export PATH
X
Xsed '
X1s/^A/Message-ID: /
X2s/^/Newsgroups: /
X3{
Xs/^/Path: /p
Xs/Path/From/
X}
X4s/^/Date: /
X5{
Xs/^/Subject: /p
Xs/.*//
X}
X'
!
echo 'relay/anews/b.samp':
sed 's/^X//' >'relay/anews/b.samp' <<'!'
XPath: ucbvax!ucbarpa!foo
XFrom: ucbvax!ucbarpa!foo
XSubject: Whee!
XNewsgroups: net.rec.drugs.crack
XMessage-ID: 123@utcs.fun
XDate: Apr  1 00:00:00 1986
XHideous-Name: #@$%ucbarpa^edu&*foo
X
XBoy I like this stuff!
!
echo 'relay/anews/b.samp.to.a':
sed 's/^X//' >'relay/anews/b.samp.to.a' <<'!'
XA123@utcs.fun
Xnet.rec.drugs.crack
Xucbvax!ucbarpa!foo
XApr 1 00:00:00 1986
XWhee!
XBoy I like this stuff!
!
echo 'relay/anews/b.to.a':
sed 's/^X//' >'relay/anews/b.to.a' <<'!'
X#! /bin/sh
X# bnewstoa: B-format news to A-format converter (why, oh, why?) (thanks, Norman)
XPATH=/bin:/usr/bin:/usr/ucb; export PATH
X
Xawk '
XNR==1,/^$/	{		# headers: save A headers only
X	if ($0 ~ /^Message-ID: /)
X		msgid=$2
X	else if ($0 ~ /^Newsgroups: /)
X		ngs=$2
X	else if ($0 ~ /^Path: /)
X		path=$2
X	else if ($0 ~ /^Date: /) {
X		date = $2	# skip "Date:"
X		for (i = 3; i <= NF; i++)
X			date = date " " $i	# append remaining fields
X	} else if ($0 ~ /^Subject: /)
X		subj=$2
X	else if ($0 ~ /^$/) {	# end of headers: spew out A-format equivalent
X		print "A" msgid
X		print ngs
X		print path
X		print date
X		print subj
X		inbody = "yes"
X		noblanksyet = "yes"
X	}
X}
Xinbody=="yes"	{	# copy body except first blank line, if present
X	if ($0 ~ /^$/ && noblanksyet == "yes")
X		noblanksyet = "no"
X	else
X		print
X}
X'
!
echo 'relay/anews/README':
sed 's/^X//' >'relay/anews/README' <<'!'
XThese are some ill-documented utilities for converting between A News and
XB News formats.  Probably not of any interest to anyone any more, but we
Xinclude them just in case.
!
echo 'relay/article.c':
sed 's/^X//' >'relay/article.c' <<'!'
X/*
X * article creation and destruction
X */
X#include <stdio.h>
X#include <sys/types.h>
X#include "libc.h"
X#include "news.h"
X#include "headers.h"
X#include "article.h"
X
Xvoid
Xartinit(art)
Xregister struct article *art;
X{
X	art->a_status = ST_OKAY;
X	hdrinit(&art->h);
X	art->a_haccum = NULL;
X	art->a_hnext = NULL;
X	art->a_hpalloced = 0;
X	art->a_hpused = 0;
X	art->a_hptrs = NULL;
X	art->a_hbytesleft = 0;
X	art->a_files = NULL;
X	art->a_tmpf = NULL;
X	art->a_artf = NULL;
X	art->a_unlink = NO;
X	art->a_filed = NO;
X	art->a_xref = NO;
X	art->a_blvmax = NO;
X	art->a_charswritten = 0;
X	art->a_unread = 0;
X}
X
Xvoid
Xartfree(art)
Xregister struct article *art;
X{
X	freeheaders(&art->h);
X	/* a_haccum is currently not malloced */
X	art->a_hptrs = NULL;		/* don't free a_hptrs; see hdrsave() */
X	nnfree(&art->a_files);
X	nnfree(&art->a_tmpf);
X	if (art->a_artf != NULL) {
X		(void) fprintf(stderr, "%s: a_artf still open in artfree()\n",
X			progname);
X		if (nfclose(art->a_artf) == EOF) {
X			art->a_status |= ST_DROPPED;
X			warning("error closing %s", art->a_tmpf);
X		}
X		art->a_artf = NULL;
X	}
X}
!
echo 'relay/article.h':
sed 's/^X//' >'relay/article.h' <<'!'
X/*
X * All the information needed to describe an article as it is processed.
X */
X
X#define MINSHPTRS 30		/* initial value for sh_alloced */
X
Xstruct article {
X	statust a_status;	/* article status bits */
X	struct headers h;	/* strictly from headers in input: */
X	char *a_haccum;		/* accumulated output headers, if any */
X	char *a_hnext;		/* -> first free byte in a_haccum */
X	short a_hpalloced;	/* indices in a_hptrs */
X	short a_hpused;		/* indices currently in use */
X	char **a_hptrs;		/* -> array of ptrs to lines in a_haccum */
X	unsigned a_hbytesleft;	/* in a_haccum */
X	char *a_files;		/* filenames for history, added in filing, from h.h_ngs */
X	char *a_tmpf;		/* temp link name or first spool dir link */
X	FILE *a_artf;		/* stream corresponding to a_tmpf */
X	boolean a_unlink;	/* true iff a_tmpf should be unlinked when done */
X	boolean a_filed;	/* true iff article has been filed */
X	boolean a_xref;		/* true iff Xref: header generated yet */
X	boolean a_blvmax;	/* true iff a_unread is to be believed */
X	long a_charswritten;	/* into spool directory, for batcher */
X	long a_unread;		/* bytes of article input yet unread */
X};
X
X/* return name of at least one link, for printing in error messages, etc. */
X#define spoolnm(art) ((art)->a_unlink? (art)->a_tmpf: (art)->a_files)
X
X/* imports from article.c */
Xextern void artinit(), artfree();
!
echo 'relay/caches.c':
sed 's/^X//' >'relay/caches.c' <<'!'
X/*
X * cache control
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include "news.h"
X#include "active.h"
X#include "caches.h"
X#include "transmit.h"
X
Xstatust
Xloadcaches()				/* reload in-core caches from disk */
X{
X	return actload();
X}
X
Xstatust
Xsynccaches()				/* force in-core caches to disk */
X{
X	return actsync() | trclose();
X}
!
echo 'relay/caches.h':
sed 's/^X//' >'relay/caches.h' <<'!'
X/* imports from caches.c */
Xextern statust loadcaches(), synccaches();
!
echo 'relay/control.c':
sed 's/^X//' >'relay/control.c' <<'!'
X/*
X * Implement the Usenet control messages, as per RFC 1036 (nee 850).
X * These are fairly infrequent and can afford to be done by
X * separate programs.  They are:
X *
X * cancel message-ID	restricted to Sender: else From: or root, in theory
X * ihave message-ID-list remotesys	generate a sendme from message-ID-list
X * sendme message-ID-list remotesys	send articles named to remotesys
X * (ihave/sendme is semi-documented in the RFCs, kludgey and broken in B2.10.)
X *
X * newgroup groupname	must be Approved:
X * rmgroup groupname	must be Approved:; allow some local control over this
X * sendsys		mail to Reply-To: else From:
X * senduuname		ditto
X * version		ditto
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X
X#include "libc.h"
X#include "news.h"
X#include "config.h"
X#include "headers.h"
X#include "article.h"
X#include "caches.h"
X#include "history.h"
X
X#define NO_FILES ""
X#define SUBDIR binfile("ctl")		/* holds shell scripts */
X
X/*
X * These are shell meta-characters, except for /, which is included
X * since it allows people to escape from the control directory.
X */
X#define SHELLMETAS "<>|&;({$=*?[`'\"/"
X
X/* imports from news */
Xextern statust snufffiles(); 
Xextern void ihave(), sendme();
X
X/* forwards */
XFORWARD statust cancelart();
XFORWARD void runctlmsg(), bombctlmsg();
X
X/*
X * Implement control message specified in "art".
X * Because newgroup and rmgroup may modify the active file, for example,
X * we must flush in-core caches to disk first and reload them afterward.
X * We handle cancels in this process for speed and dbm access.
X * We handle ihave & sendme in this process for dbm access and
X * to work around syntax restrictions (<>).
X *
X * In future, one could pass header values to scripts as arguments or
X * in environment, as NEWS* variables, to save time in the scripts.
X */
Xvoid
Xctlmsg(art)
Xstruct article *art;
X{
X	int pid, deadpid;
X	int wstatus;
X	char *inname = art->a_tmpf, *ctlcmd = art->h.h_ctlcmd;
X	static char nmcancel[] = "cancel ";
X	static char nmihave[] = "ihave ";
X	static char nmsendme[] = "sendme ";
X
X	if (STREQN(ctlcmd, nmcancel, STRLEN(nmcancel))) {
X		art->a_status |= cancelart(ctlcmd + STRLEN(nmcancel));
X		return;
X	}
X	if (STREQN(ctlcmd, nmihave, STRLEN(nmihave))) {
X		ihave(ctlcmd + STRLEN(nmihave), art);
X		return;
X	}
X	if (STREQN(ctlcmd, nmsendme, STRLEN(nmsendme))) {
X		sendme(ctlcmd + STRLEN(nmsendme), art);
X		return;
X	}
X
X	art->a_status |= synccaches();
X	(void) fflush(stdout);
X	(void) fflush(stderr);
X
X	pid = fork();
X	if (pid == 0)				/* child? */
X		runctlmsg(ctlcmd, inname);
X	else if (pid == -1)
X		warning("fork failed", "");
X
X	/* lint complains about &wstatus on 4.2+BSD; too bad, lint's wrong. */
X	while ((deadpid = wait(&wstatus)) != pid && deadpid != -1)
X		;
X
X	/* wrong kid returned, fork failed or child screwed up? */
X	if (deadpid == -1 || pid == -1 || wstatus != 0)
X		art->a_status |= ST_DROPPED;	/* admin got err.msg. by mail */
X	art->a_status |= loadcaches();
X}
X
XSTATIC boolean
Xsafecmd(cmd)			/* true if it's safe to system(3) cmd */
Xchar *cmd;
X{
X	register char *s;
X
X	for (s = cmd; *s != '\0'; s++)
X		if (STREQN(s, "..", STRLEN("..")))
X			return NO;
X	for (s = SHELLMETAS; *s != '\0'; s++)
X		if (index(cmd, *s) != NULL)
X			return NO;
X	return YES;
X}
X
X/*
X * In theory (RFC 1036 nee 850), we should verify that the user issuing
X * the cancel (the Sender: of this article or From: if no Sender) is the
X * Sender: or From: of the original article or the local super-user.
X *
X * In practice, this is a lot of work and since anyone can forge news
X * (and thus cancel anything), not worth the effort.
X *
X * Ignore ST_ACCESS while cancelling an already-seen article since the
X * article may have been cancelled before or may have a fake history entry
X * because the cancel arrived before the article.
X *
X * If the article being cancelled has not been seen yet, generate a history
X * file entry for the cancelled article in case it arrives after the cancel
X * control.  The history file entry will cause the cancelled article to be
X * rejected as a duplicate.
X */
XSTATIC statust
Xcancelart(msgidstr)
Xchar *msgidstr;
X{
X	register char *wsp;
X	register char *msgid = strsave(msgidstr);
X	register int idbytes;
X	register char *wholemsgid = msgid;
X	register statust status = ST_OKAY;
X
X	/* skip leading whitespace in msgid */
X	while (*msgid != '\0' && isascii(*msgid) && isspace(*msgid))
X		++msgid;
X	/* replace trailing whitespace with NULs; `wsp >= msgid' is not safe */
X	idbytes = strlen(msgid);
X	for (wsp = msgid + idbytes - 1; idbytes-- > 0 &&
X	    isascii(*wsp) && isspace(*wsp); --wsp)
X		*wsp = '\0';
X
X	if (alreadyseen(msgid)) {
X		register char *histent, *filelist;
X
X		histent = gethistory(msgid);
X		if (histent != NULL && (filelist = findfiles(histent)) != NULL)
X			status |= snufffiles(filelist) & ~ST_ACCESS;
X	} else {
X		status |= fakehist(msgid, DEFEXP, NO_FILES);	/* start log */
X		(void) putchar('\n');		/* end log line */
X	}
X	free(wholemsgid);
X	return status;
X}
X
X/*
X * Execute a non-builtin control message by searching $NEWSCTL/bin and
X * $NEWSBIN/ctl for the command named by the control message.
X * runctlmsg is called from a child of relaynews, so it must always
X * call _exit() rather than exit() to avoid flushing stdio buffers.
X *
X * Enforce at least minimal security: the environment was standardised at
X * startup, including PATH and IFS; close non-standard file descriptors;
X * reject shell metacharacters in ctlcmd.
X */
XSTATIC void
Xrunctlmsg(ctlcmd, inname)			/* child process */
Xregister char *ctlcmd, *inname;
X{
X	register char *cmd;
X	register int cmdstat;
X
X	closeall(1);
X	if (!safecmd(ctlcmd)) {
X		(void) fprintf(stderr,
X		    "%s: control `%s' looks unsafe to execute\n", progname, ctlcmd);
X		_exit(1);
X	}
X	cmd = malloc((unsigned) STRLEN("PATH=") + strlen(ctlfile("bin")) +
X		STRLEN(":") + strlen(SUBDIR) + STRLEN(";") + strlen(ctlcmd) +
X		STRLEN(" <") + strlen(inname) + 1);
X	if (cmd == NULL) {
X		warning("can't allocate memory in runctlmsg", "");
X		_exit(1);
X	}
X	(void) strcpy(cmd, "PATH=");
X	(void) strcat(cmd, ctlfile("bin"));
X	(void) strcat(cmd, ":");
X	(void) strcat(cmd, SUBDIR);
X	(void) strcat(cmd, ";");
X	(void) strcat(cmd, ctlcmd);
X	(void) strcat(cmd, " <");
X	(void) strcat(cmd, inname);
X
X	cmdstat = system(cmd);
X	if (cmdstat != 0)
X		bombctlmsg(cmd, cmdstat);
X	free(cmd);
X	_exit(0);
X}
X
X/*
X * Notify the local news administrator by mail that "cmd" failed
X * with "cmdstat" status, and _exit with bad status (again avoid stdio
X * buffer flushing in the child).
X */
XSTATIC void
Xbombctlmsg(cmd, cmdstat)
Xchar *cmd;
Xint cmdstat;
X{
X	register char *mailcmd;
X	register FILE *mailf;
X	
X	mailcmd = malloc((unsigned)STRLEN("PATH=") + strlen(newspath()) +
X		STRLEN(" mail ") + strlen(newsmaster()) + 1);
X	if (mailcmd == NULL) {
X		warning("can't allocate memory in bombctlmsg", "");
X		_exit(1);
X	}
X	(void) sprintf(mailcmd, "PATH=%s mail %s", newspath(), newsmaster());
X	mailf = popen(mailcmd, "w");
X	if (mailf == NULL)
X		mailf = stderr;
X	(void) fprintf(mailf,
X		"%s: control message `%s' exited with status 0%o\n",
X		progname, cmd, cmdstat);
X	if (mailf != stderr)
X		(void) pclose(mailf);
X	free(mailcmd);
X	_exit(1);
X}
!
echo 'relay/control.h':
sed 's/^X//' >'relay/control.h' <<'!'
X/* imports from control.c */
Xextern void ctlmsg();
!
echo 'relay/cpu.h':
sed 's/^X//' >'relay/cpu.h' <<'!'
X/*
X * CPU-specific definitions
X */
X
X#ifndef MAXLONG
X#define MAXLONG ((long)(~(unsigned long)0 >> 1))
X#endif
!
echo 'relay/ctl/checkgroups':
sed 's/^X//' >'relay/ctl/checkgroups' <<'!'
X#! /bin/sh
X# checkgroups - check active file for missing or extra newsgroups.
X#	stdin must a checkgroups news article, sends mail to $NEWSMASTER
X#	after updating $nl/newsgroups from $nl/localgroups
X# based on v1.4 of 9/4/84
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
Xexport NEWSCTL NEWSBIN NEWSARTS
XPATH=$NEWSCTL/bin:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
X# generate newsgroups from localgroups & beheaded stdin (checkgroups article).
X# appending to newsgroups instead of overwriting is a hack,
X# but is about the best we can do until checkgroups is defined.
X(cat $NEWSCTL/localgroups; sed '1,/^$/d') >>$NEWSCTL/newsgroups
X# backup newsgroups, then strip duplicates
Xcp $NEWSCTL/newsgroups $NEWSCTL/newsgroups.bac || exit 1
Xsort -u -o $NEWSCTL/newsgroups $NEWSCTL/newsgroups.bac
X
X# generate list of approved newsgroups from $nl/newsgroups
X# [^.]*\. in next two egreps was net.|mod.|fa., which is inadequate - geoff
X(echo junk; echo control; sed 's/[ \	].*//' $NEWSCTL/newsgroups |
X	egrep "^([^.]*\.|general)") | sort -u >/tmp/$$a
X
X# generate list of locally-present newsgroups from $nl/active
Xegrep "^([^.]*\.|general|junk|control)" $NEWSCTL/active | sed 's/ .*//' |
X	sort -u >/tmp/$$b
X
X# compare 'em & note differences
Xcomm -13 /tmp/$$a /tmp/$$b >/tmp/$$remove
Xcomm -23 /tmp/$$a /tmp/$$b >/tmp/$$add
X
Xif test -s /tmp/$$remove; then
X	echo "The following newsgroups are not valid and should be removed."
X	sed "s/^/	/" /tmp/$$remove
X	echo ""
X	echo "You can do this by executing the commands:"
X	sed "s;.*;	 $NEWSBIN/maint/delgroup &;" /tmp/$$remove
X	echo ""
Xfi 2>&1 >/tmp/$$out
X
Xif test -s /tmp/$$add; then
X	echo "The following newsgroups were missing." # "and were added."
X	sed "s/^/	/" /tmp/$$add
X	echo ""
X
X#	for i in `cat /tmp/$$add`
X#	do
X# *** "Subject: cmsg " is a hideous botch of a kludge-hack; avoid it!
X#		inews -h <<!
X#Control: newgroup $i
X#Newsgroups: control
X#Subject: newgroup $i
X#Distribution: general
X#
X#Create $i locally.
X#!
X#	done
X
Xfi 2>&1 >>/tmp/$$out
X
Xif test -s /tmp/$$out; then
X	(echo "Subject: Problems with your active file"; echo "";
X	 cat /tmp/$$out) | mail $NEWSMASTER
Xfi
X
Xrm -f /tmp/$$*		# clean up temporaries
!
echo 'relay/ctl/newgroup':
sed 's/^X//' >'relay/ctl/newgroup' <<'!'
X#! /bin/sh
X# newgroup group flag - create group (4-field version: B-2.10.3+ compatible)
X#	subject to our sys file group pattern
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
Xexport NEWSCTL NEWSBIN NEWSARTS
XPATH=$NEWSCTL/bin:$NEWSBIN/relay:$NEWSBIN:$NEWSPATH ; export PATH # include mkpdir
Xumask $NEWSUMASK
X
XF=/tmp/nc$$
X
Xtrap "rm -f $F; exit 0" 0
Xcat >$F
X
X# unapproved ctl msg? then quit
Xgrep -s '^Approved:' $F >/dev/null || { rm -f $F; exit 0; }
X
XSENDER="`grep '^Sender:' $F | sed 's/^[^:]*: *//'`"
Xcase "$SENDER" in
X"")	SENDER="`grep '^From:' $F | sed 's/^[^:]*: *//' `" ;;
Xesac
X
Xgreppat="^`echo $1 | sed 's/\./\\\\./g' ` "
Xif grep -s "$greppat" $NEWSCTL/active >/dev/null; then	# group exists?
X	export SENDER
X	chamod "$1" "$2" 		# change moderated flag if needed
X	exit
Xfi
X
Xme="`newshostname`"
Xgngppat=`awk -f $NEWSBIN/relay/canonsys.awk $NEWSCTL/sys |
X	egrep "^($me|ME):" |
X	awk -F: '
X{
X	fields = split($2, field2, "/")	# split ngs/dists
X	print field2[1]			# print only ngs
X	exit
X}' `
X
Xif gngp -a "$gngppat" >/dev/null <<!
X$1
X!
Xthen			# no group in active, but sys file likes it: make it
X	case "$2" in
X	moderated)	flag=m ;;
X	*)		flag=y ;;
X	esac
X	echo "$1 0000000000 00000 $flag" >>$NEWSCTL/active
X	(echo "$1 `getdate now` $SENDER" >>$NEWSCTL/active.times)  # rn hook
X	# make the directory since rn will bitch if it's missing
X	mkpdir $NEWSARTS/`echo $1 | tr . / `
X	echo "newsgroup $1 was created by $SENDER." | mail $NEWSMASTER
Xfi
!
echo 'relay/ctl/rmgroup':
sed 's/^X//' >'relay/ctl/rmgroup' <<'!'
X#! /bin/sh
X# rmgroup group - snuff group
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
Xexport NEWSCTL NEWSBIN NEWSARTS
XPATH=$NEWSCTL/bin:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
XF=/tmp/nc$$
X
Xcat >$F
X
X# unapproved ctl msg? then quit
Xegrep '^Approved:' $F >/dev/null || { rm -f $F; exit 0; }
X
X# quit if no active entry
Xegrep "^`echo $1 | sed 's/\./\\\\./g'` " $NEWSCTL/active >/dev/null ||
X	{ rm -f $F; exit 0; }
X
XSENDER="`grep '^Sender:' $F | sed 's/^[^:]*: *//'`"
Xcase "$SENDER" in
X"")
X	SENDER="`grep '^From:' $F | sed 's/^[^:]*: *//'`"
X	;;
Xesac
X
X# tell the local usenet administrator to do it by hand
Xecho "rmgroup $1 says $SENDER" | mail $NEWSMASTER
X
Xrm -f $F*
!
echo 'relay/ctl/sendsys':
sed 's/^X//' >'relay/ctl/sendsys' <<'!'
X#! /bin/sh
X# sendsys - mail sys file to sender identified in stdin's headers
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
Xexport NEWSCTL NEWSBIN NEWSARTS
XPATH=$NEWSCTL/bin:$NEWSBIN/relay:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
XSENDER="`newsreply`"
X(echo "Subject: response from `newshostname` to your sendsys"; echo "";
Xcase "$1" in
X"")	cat $NEWSCTL/sys ;;
X*)	awk -f $NEWSBIN/relay/canonsys.awk $NEWSCTL/sys | egrep "^$1:" ;;
Xesac ) | mail "$SENDER"
Xecho "$NEWSCTL/sys file has been sent to $SENDER.  Remain calm." | mail $NEWSMASTER
!
echo 'relay/ctl/senduuname':
sed 's/^X//' >'relay/ctl/senduuname' <<'!'
X#! /bin/sh
X# senduuname - mail `uuname` to sender identified in stdin's headers
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
Xexport NEWSCTL NEWSBIN NEWSARTS
XPATH=$NEWSCTL/bin:$NEWSBIN/relay:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
XSENDER="`newsreply`"
X(echo "Subject: response to your senduuname"; echo ""; uuname) | mail "$SENDER"
Xecho "uuname output sent to $SENDER" | mail $NEWSMASTER
!
echo 'relay/ctl/version':
sed 's/^X//' >'relay/ctl/version' <<'!'
X#! /bin/sh
X# version - mail version id to sender identified in stdin's headers
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
Xexport NEWSCTL NEWSBIN NEWSARTS
XPATH=$NEWSCTL/bin:$NEWSBIN/relay:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
XSENDER="`newsreply`"
Xecho C | mail "$SENDER"
!
echo 'relay/aux/mailnews':
sed 's/^X//' >'relay/aux/mailnews' <<'!'
X#! /bin/sh
X# send news by mail, encoded for protection
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
X
XPATH=$NEWSCTL/bin:$NEWSBIN/batch:$NEWSBIN:$NEWSPATH ; export PATH
X
Xcase $# in
X0)	echo "Usage: $0 destination ..." >&2
X	exit 1
X	;;
Xesac
X
X( echo ; bencode ) | mail $*
!
echo 'relay/aux/sendnews':
sed 's/^X//' >'relay/aux/sendnews' <<'!'
X#! /bin/sh
X# sendnews destination... - protect & mail article on stdin to destinations
XPATH=/bin:/usr/bin; export PATH
X
Xcase $# in
X0)
X	echo "usage: $0 destination..." >&2
X	exit 1 ;;
Xesac
X(echo ''; sed 's/^/N/') | mail $*
!
echo 'relay/aux/canonsys.awk':
sed 's/^X//' >'relay/aux/canonsys.awk' <<'!'
X# canonicalise the sys file:
X# delete comments & leading whitespace, collapse continued lines
X# rewritten to avoid assignment to $0, which is broken in older awks
X/^/	{ thisln = $0 }
X/^#/	{ partline = ""; next }		# delete comments
X/^[\t ]/	{
X	for (s = substr(thisln, n); s ~ /^[\t ]/; s = substr(thisln, ++n))
X		;			# skip leading whitespace
X	thisln = s
X}
X/\\$/	{ partline = partline substr(thisln, 1, length(thisln)-1); next }
X{					# non-continued line
X	partline = partline thisln	# terminate the whole entry
X	if (partline != "")
X		print partline
X	partline = ""
X}
XEND	{
X	if (partline != "")
X		print partline		# flush any partial line
X}
!
echo 'relay/aux/chamod':
sed 's/^X//' >'relay/aux/chamod' <<'!'
X#!/bin/sh
X# chamod ng flag - change the "moderated" flag for ng to flag
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
Xexport NEWSCTL NEWSBIN NEWSARTS
XPATH=$NEWSCTL/bin:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
Xcase "$1" in
X"")
X	echo "$0: null newsgroup not permitted" >&2
X	exit 1
X	;;
Xesac
Xcase "$2" in
Xmoderated)	flag=m ;;
X*)		flag=y ;;
Xesac
X
Xaflag=`awk "/$1/"' { print $4 }' $NEWSCTL/active`
Xif test "$aflag" != "$flag" -a \( "$aflag" = m -o "$aflag" = y \); then
X	# old & new flags differ & old flag is m or y
X	# watch closely - shell quoting is tricky here
X	awk '
X$1 == "'$1'"	{			# this line is for first arg.
X	print $1, $2, $3, "'$flag'"
X	next
X}
X	{ print }
X' $NEWSCTL/active >$NEWSCTL/active.new
X	cp $NEWSCTL/active $NEWSCTL/active.old
X	cp $NEWSCTL/active.new $NEWSCTL/active
X	rm -f $NEWSCTL/active.new
X
X	case "$flag" in
X	m)	pfx="" ;;
X	*)	pfx=un ;;
X	esac
X	echo "newsgroup $1 was changed to ${pfx}moderated by $SENDER" |
X		mail $NEWSMASTER
Xfi
!
echo 'relay/aux/mkpdir':
sed 's/^X//' >'relay/aux/mkpdir' <<'!'
X#! /bin/sh
X# mkpdir dir ... - make directory and parents
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
Xexport NEWSCTL NEWSBIN NEWSARTS
XPATH=$NEWSCTL/bin:$NEWSBIN/relay:$NEWSBIN:$NEWSPATH ; export PATH	# must include this file's dir.
X
Xumask $NEWSUMASK
X
Xstatus=0
Xfor dir
Xdo
X	mkdir "$dir" 2>/dev/null
X	if test ! -d "$dir"; then
X		mkpdir "`echo $dir | sed 's;/[^/]*$;;'`"
X		mkdir "$dir"
X		if test ! -d "$dir"; then
X			status=1
X		fi
X	fi
Xdone
Xexit $status
!
echo 'relay/aux/newsreply':
sed 's/^X//' >'relay/aux/newsreply' <<'!'
X#! /bin/sh
X# newsreply - print return address from news article on stdin
X# This version assumes a domain mailer (user@host.domain works) or
X# "internet" in mailpaths file, unless $NEWSCTL/replyusepath exists.
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
Xexport NEWSCTL NEWSBIN NEWSARTS
XPATH=$NEWSCTL/bin:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
Xart=/tmp/nc$$
Xmroute=/tmp/ncm$$
X
Xcat >$art
X
Xif test -r $NEWSCTL/replyusepath
Xthen
X	sender="`grep '^Path:' $art | sed 's/^[^:]*://' `"
X	echo "$sender"
X	rm -f $art
X	exit 0
Xfi
X
X# pick out the appropriate header
Xsender="` grep '^Reply-To:' $art `"
Xcase "$sender" in
X"")	sender="` grep '^From:' $art `" ;;
Xesac
X
X# strip header keyword, full name & duplicate lines, print result.
X# this copes with "address", "address (full name)" and "full name <address>".
Xsender=` echo "$sender" | sed 's/^[^:]*:[	 ]*//
Xs/ (.*)//
Xs/.*<\(.*\)>/\1/
X1q' `
X
X# B 2.11 mailpaths/"internet" hack
Xcat $NEWSCTL/mailpaths |
X	while read ngpat route junk
X	do
X		case "$ngpat" in
X		internet)
X				echo "$route" >$mroute
X				break
X				;;
X		esac
X	done
Xif test -s $mroute; then
X	sed "s/%s/`
X		echo $sender | sed 's/\(.*\)@\(.*\)/\2!\1/'
X		`/" <$mroute	# the real B 2.11 hack: u@d -> route!d!u
Xelse
X	echo $sender
Xfi
X
Xrm -f $art $mroute
!
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.