[comp.sources.bugs] C News patch of 25-May-1990

henry@utzoo.uucp (Henry Spencer) (05/26/90)

There are a few fixes for real bugs here.  Relaynews now complains when
dbminit() fails, instead of relying on dbminit() to do it -- dbm did [barf]
but dbz does not.  Message-IDs in control-message commands are now checked
as stringently as the message-ID of the articles themselves -- null IDs in
commands used to mess up history.  Relaynews now balks if the history
files are unwritable -- it used to try to carry on, causing great confusion.
Inews (one of its helpers, actually) used to get slightly confused when
an entire article body consisted of lines with leading white space -- it
took them all as headers! -- and this is now fixed.  A rare bug in handling
of multiple sys lines for the same site has been fixed.  And the problem
with "doit.news" needing write permissions in the source directories to
build "explist.no" has been fixed.

Also...  "Viauuxcun" to send batches to sites that still want to see
"cunbatch" rather than "rnews".  Ihave/sendme batching no longer assumes
that inews is in NEWSPATH.  The batcher does much less locking, reducing
conflicts with relaynews.  Dbz's Makefile has been fixed to avoid some
unportable assumptions.  Expire now takes a -h option, telling it to expire
articles that are to be removed but hang onto ones that would be archived.
Doexpire uses -h if archiving space is short.  Doexpire notices if it was
invoked with -r, and doesn't bother with rebuild-space checks in that case.
Build's question-asking stuff now implements shell escapes.  Build now
standardizes its PATH to avoid funny local software.  Build is fussier
about quoting in its saved-answers file, to avoid trouble with sites that
have shell metacharacters (!) in their organization names.  Subst tempfile
names changed to avoid problems on systems with 14-character filenames.
NEWSCTL/active.times is documented, and active.to.times (which builds it)
is supplied.  And proper use of white space in the sys file is documented.
Plus usual minor cleanup work.

start of patch 25-May-1990
(suggested archive name: `pch25May90.Z')
this should be run with   patch -p0 <thisfile

Please do the following (there is no easy way we can convince
patch to do this automatically):
rm contrib/dbz
rm expire/superkludge

The following is a complete list of patches to date.

Prereq: 23-Jun-1989
Prereq: 7-Jul-1989
Prereq: 23-Jul-1989
Prereq: 22-Aug-1989
Prereq: 24-Aug-1989
Prereq: 14-Sep-1989
Prereq: 13-Nov-1989
Prereq: 10-Jan-1990
Prereq: 16-Jan-1990
Prereq: 17-Jan-1990
Prereq: 18-Jan-1990
Prereq: 12-Mar-1990
Prereq: 14-Apr-1990
Prereq: 15-Apr-1990
Prereq: 16-Apr-1990
*** PATCHDATES.old	Fri May 25 00:13:20 1990
--- PATCHDATES	Fri May 25 00:13:20 1990
***************
*** 1,15 ****
--- 1,16 ----
  23-Jun-1989
  7-Jul-1989
  23-Jul-1989
  22-Aug-1989
  24-Aug-1989
  14-Sep-1989
  13-Nov-1989
  10-Jan-1990
  16-Jan-1990
  17-Jan-1990
  18-Jan-1990
  12-Mar-1990
  14-Apr-1990
  15-Apr-1990
  16-Apr-1990
+ 25-May-1990

Changed files, if any:

*** cnpatch/old/README	Sat Apr 14 21:13:14 1990
--- README	Mon Apr 23 15:47:14 1990
***************
*** 1,3 ****
! This is C News, superseding assorted preliminary releases.  9 June 1989
  
  C News is a reimplementation of the transport and storage subsystems of the
--- 1,3 ----
! This is C News, superseding assorted preliminary releases.  23 April 1990
  
  C News is a reimplementation of the transport and storage subsystems of the
***************
*** 29,36 ****
  C News's files are fully compatible with those of B News for any program
  that does not read log files and does not inspect the middle field of the
! history file closely.  (The one major program that does is "nntp"; we include
! diffs for NNTP 1.5 which handle our middle-field format, interface it to
! our input subsystem, and generally make it quite a bit faster than the
! original.)  C News complies fully with RFC 1036 (nee RFC 850), the official
  definition of news interchange format.
  
--- 29,35 ----
  C News's files are fully compatible with those of B News for any program
  that does not read log files and does not inspect the middle field of the
! history file closely.  (The one major program that does is "nntp"; current
! versions (1.5.8 and later) include our C News support, including a significant
! speedup.)  C News complies fully with RFC 1036 (nee RFC 850), the official
  definition of news interchange format.
  
***************
*** 121,126 ****
  these overrides.
  
! Be warned that the nntp stuff in nntpdiffs, and the simple news reader in
! rna, have not been gone over very well to make sure that they use the
  standard configuration mechanisms.  Hardwired pathnames may be present there,
  and in general the stuff there is not well fitted into our automatic-install
--- 120,125 ----
  these overrides.
  
! Be warned that the simple news reader in
! rna has not been gone over very well to make sure that it uses the
  standard configuration mechanisms.  Hardwired pathnames may be present there,
  and in general the stuff there is not well fitted into our automatic-install

*** cnpatch/old/ROADMAP	Wed Jan 10 19:10:13 1990
--- ROADMAP	Mon Apr 23 15:47:11 1990
***************
*** 5,8 ****
--- 5,10 ----
  contrib	Software from other contributors, possibly useful but not really
  	an official part of C News.
+ dbz	a faster replacement for dbm for news programs which generates smaller
+ 	database files than dbm.
  doc	User documentation, including "install" which discusses how to
  	install C News.  Although the documentation is supplied as troff
***************
*** 38,43 ****
  man	Manual pages.
  misc	Miscellaneous internal utilities and maintenance programs.
- nntpdiffs	Amendments to NNTP version 1.5, for Internet users, to work
- 	with C News history-file format and to be a good deal faster.
  notebook	The C News Implementor's Notebook -- pieces of documentation
  	aimed more at gurus than novices.
--- 40,43 ----

*** cnpatch/old/batch/Makefile	Tue Jan 16 17:58:26 1990
--- batch/Makefile	Sat May 12 23:13:50 1990
***************
*** 17,21 ****
  PGMS=batcher batchih batchsm batchsplit comp compcun nocomp viainews viauux \
  	sendbatches compc7 c7encode viamail viapmail bencode compb viauuxz \
! 	viaemail viarsh viauuxl
  ALL = $(PGMS) batchparms
  
--- 17,21 ----
  PGMS=batcher batchih batchsm batchsplit comp compcun nocomp viainews viauux \
  	sendbatches compc7 c7encode viamail viapmail bencode compb viauuxz \
! 	viaemail viarsh viauuxl viauuxcun
  ALL = $(PGMS) batchparms
  
***************
*** 67,70 ****
--- 67,73 ----
  	sed '$$s/-r/-r -z/' viauux >$@
  
+ viauuxcun:	viauux
+ 	sed '$$s/rnews/cunbatch/' viauux >$@
+ 
  viaemail:	viamail
  	sed '$$s/rnews/enews/' viamail >$@
***************
*** 171,174 ****
  clean:
  	rm -rf out.going bin
! 	rm -f *.o test.* togo togo.* batchparms batcher batchsm 
  	rm -f batchlog batchlog.* c7encode bencode viauuxz viaemail
--- 174,177 ----
  clean:
  	rm -rf out.going bin
! 	rm -f *.o test.* togo togo.* batchparms batcher batchsm viauuxcun
  	rm -f batchlog batchlog.* c7encode bencode viauuxz viaemail

*** cnpatch/old/batch/batchih	Sun Jul 23 00:48:08 1989
--- batch/batchih	Sat May 12 22:51:25 1990
***************
*** 5,9 ****
  . ${NEWSCONFIG-/usr/lib/news/bin/config}
  
! PATH=$NEWSCTL/bin:$NEWSBIN/batch:$NEWSBIN:$NEWSPATH ; export PATH
  umask $NEWSUMASK
  
--- 5,9 ----
  . ${NEWSCONFIG-/usr/lib/news/bin/config}
  
! PATH=$NEWSCTL/bin:$NEWSBIN/batch:$NEWSBIN/inject:$NEWSBIN:$NEWSPATH ; export PATH
  umask $NEWSUMASK
  

*** cnpatch/old/batch/batchsplit	Tue Jan 16 17:58:26 1990
--- batch/batchsplit	Fri Apr 27 16:52:26 1990
***************
*** 29,48 ****
  umask $NEWSUMASK
  
! # Locking.
! lock="$NEWSCTL/LOCK"
! ltemp="$NEWSCTL/L.$$"
! echo $$ >$ltemp
! trap "rm -f $ltemp ; exit 0" 0 1 2 15
! while true
! do
! 	if newslock $ltemp $lock
! 	then
! 		trap "rm -f $ltemp $lock ; exit 0" 0 1 2 15
! 		break
! 	fi
! 	sleep 30
! done
! 
! # pick an input file, shuffling togo aside if needed, and unlock
  if test -s togo.next
  then
--- 29,33 ----
  umask $NEWSUMASK
  
! # pick an input file, shuffling togo aside (with locking) if needed
  if test -s togo.next
  then
***************
*** 52,55 ****
--- 37,56 ----
  	input=togo.more
  else
+ 	# Locking.
+ 	lock="$NEWSCTL/LOCK"
+ 	ltemp="$NEWSCTL/L.$$"
+ 	echo $$ >$ltemp
+ 	trap "rm -f $ltemp ; exit 0" 0 1 2 15
+ 	while true
+ 	do
+ 		if newslock $ltemp $lock
+ 		then
+ 			trap "rm -f $ltemp $lock ; exit 0" 0 1 2 15
+ 			break
+ 		fi
+ 		sleep 30
+ 	done
+ 
+ 	# Do it.
  	rm -f togo.more
  	mv togo togo.more
***************
*** 56,62 ****
  	>togo
  	input=togo.more
  fi
- trap 0 1 2 15
- rm -f $ltemp $lock
  
  # main processing
--- 57,65 ----
  	>togo
  	input=togo.more
+ 
+ 	# Unlock.
+ 	trap 0 1 2 15
+ 	rm -f $ltemp $lock
  fi
  
  # main processing

*** cnpatch/old/conf/ask	Tue Jan 16 17:58:23 1990
--- conf/ask	Fri Apr 27 17:59:13 1990
***************
*** 1,6 ****
  #! /bin/sh
- echo "$1 [$2]? " | tr -d '\012' >/dev/tty	# echo -n, sort of portably
  default="$2"
! read answer
  case "$answer" in
  '')	answer="$default"	;;
--- 1,18 ----
  #! /bin/sh
  default="$2"
! while :
! do
! 	echo "$1 [$2]? " | tr -d '\012' >/dev/tty	# echo -n, semiportably
! 	read answer
! 	case "$answer" in
! 	!*)	cmd="`expr \"$answer\" : '!\(.*\)'`"
! 		trap : 2
! 		${SHELL-/bin/sh} -c "$cmd"
! 		trap 2
! 		echo '!'
! 		;;
! 	*)	break	;;	# NOTE BREAK OUT
! 	esac
! done
  case "$answer" in
  '')	answer="$default"	;;

*** cnpatch/old/conf/build	Sat Apr 14 21:13:15 1990
--- conf/build	Sat May 12 23:06:37 1990
***************
*** 1,4 ****
  #! /bin/sh
! PATH=:$PATH
  
  # configuration variables to remember for next time
--- 1,4 ----
  #! /bin/sh
! PATH=:/bin:/usr/bin
  
  # configuration variables to remember for next time
***************
*** 837,841 ****
  	echo "cp sys.proto sys"
  	echo "cd ../expire"
! 	echo "make explist.$archive && cp explist.$archive explist"
  	echo "cd ../conf"
  	case "$archive" in
--- 837,841 ----
  	echo "cp sys.proto sys"
  	echo "cd ../expire"
! 	echo "make explists && cp explist.$archive explist"
  	echo "cd ../conf"
  	case "$archive" in
***************
*** 977,981 ****
  		do
  			echo "$warn"
! 			eval "echo $v=\\\"\$$v\\\""
  		done
  	) >>$memory
--- 977,981 ----
  		do
  			echo "$warn"
! 			eval "echo $v=\\\"\"\$$v\"\\\""
  		done
  	) >>$memory

*** cnpatch/old/conf/setnewsids.c	Fri Jun 23 14:45:43 1989
--- conf/setnewsids.c	Sat Apr 21 21:50:04 1990
***************
*** 1,5 ****
  /*
!  * setnewsids - sets ids to news/news, execs relay/relaynews.  Should be setuid-root.
!  *	also add NEWSPERMS to the environment.
   */
  
--- 1,5 ----
  /*
!  * setnewsids - sets ids to news/news, execs relay/relaynews.  Should be
!  *	setuid-root.  also add NEWSPERMS to the environment.
   */
  
***************
*** 41,45 ****
  
  	/* setuid daemon prelude; various precautions */
! 	(void) umask(2);	/* undo silly umasks, ignore newsumask() */
  	(void) alarm(0);	/* cancel any pending alarm */
  	/*
--- 41,45 ----
  
  	/* setuid daemon prelude; various precautions */
! 	(void) umask(newsumask());
  	(void) alarm(0);	/* cancel any pending alarm */
  	/*

*** cnpatch/old/conf/subst	Tue Mar 13 13:41:17 1990
--- conf/subst	Sat May 12 23:09:30 1990
***************
*** 27,37 ****
  		file="`expr \"$f\" : '.*/\\([^/]*\\)'`"
  		dir="`expr \"$f\" : '\\(.*\\)/[^/]*'`"
! 		new="$dir/n.$file"
! 		old="$dir/o.$file"
  		;;
  
  		*)
! 		new="n.$f"
! 		old="o.$f"
  		;;
  	esac
--- 27,37 ----
  		file="`expr \"$f\" : '.*/\\([^/]*\\)'`"
  		dir="`expr \"$f\" : '\\(.*\\)/[^/]*'`"
! 		new="$dir/substtmp.new"
! 		old="$dir/substtmp.old"
  		;;
  
  		*)
! 		new="substtmp.new"
! 		old="substtmp.old"
  		;;
  	esac

*** cnpatch/old/conf/subst.gc	Tue Aug 22 14:47:44 1989
--- conf/subst.gc	Tue May  8 17:56:47 1990
***************
*** 17,18 ****
--- 17,20 ----
  rna/makefile
  rna/postnews
+ man/active.times.5
+ misc/act.to.times

*** cnpatch/old/conf/subst.hs	Tue Jan 16 17:58:28 1990
--- conf/subst.hs	Sat May 19 20:27:37 1990
***************
*** 13,17 ****
  expire/doexpire
  expire/mkhistory
- expire/superkludge
  expire/upact
  input/Makefile
--- 13,16 ----
***************
*** 46,47 ****
--- 45,47 ----
  expire/recovact
  misc/adddirs
+ batch/viauuxl

*** cnpatch/old/conf/yesno	Tue Jan 16 17:58:24 1990
--- conf/yesno	Fri Apr 27 17:59:44 1990
***************
*** 13,16 ****
--- 13,22 ----
  	esac
  	case "$answer" in
+ 	!*)	cmd="`expr \"$answer\" : '!\(.*\)'`"
+ 		trap : 2
+ 		${SHELL-/bin/sh} -c "$cmd"
+ 		trap 2
+ 		echo '!'
+ 		;;
  	yes|no)	break		;;	# NOTE BREAK OUT
  	*)	echo '???' >/dev/tty	;;

*** cnpatch/old/dbz/Makefile	Sat Apr 14 21:13:09 1990
--- dbz/Makefile	Tue May  1 13:50:07 1990
***************
*** 8,11 ****
--- 8,13 ----
  LINTFLAGS = -h $(FLAGS) $(DEBUG) $(RFC)
  LDFLAGS =
+ # workaround for System V make bug
+ SHELL = /bin/sh
  
  # database sizes for performance tests, regression, and regression prime-find
***************
*** 63,73 ****
  
  hist10:	fake
! 	fake -t -e 75 10000 >$@
  
  hist3.3:	fake
! 	fake -t -e 75 3300 >$@
  
  hist13:	fake
! 	fake -t -e 75 13000 >$@
  
  r:	rdbz $(RHIST) $(R2HIST) byteflip getmap revbytes altbytes
--- 65,75 ----
  
  hist10:	fake
! 	./fake -t -e 75 10000 >$@
  
  hist3.3:	fake
! 	./fake -t -e 75 3300 >$@
  
  hist13:	fake
! 	./fake -t -e 75 13000 >$@
  
  r:	rdbz $(RHIST) $(R2HIST) byteflip getmap revbytes altbytes
***************
*** 83,87 ****
  	mkdir xx
  	chmod -w xx
! 	rdbz -E 1000 -0 -M -i -S -u -U -C xx dbase
  	rmdir xx
  	sed '/>	0/d' $(RHIST) >dbase.used
--- 85,89 ----
  	mkdir xx
  	chmod -w xx
! 	./rdbz -E 1000 -0 -M -i -S -u -U -C xx dbase
  	rmdir xx
  	sed '/>	0/d' $(RHIST) >dbase.used
***************
*** 88,92 ****
  	test "`cat dbase.used | wc -l`" -eq "`sed -n '2s/ .*//p' dbase.dir`" ;
  	cp $(RHIST) dbase2
! 	rdbz -E 1000 -0 -p $(RPSIZE) -t '	' dbase2
  	cmp $(RHIST) dbase
  	cmp dbase dbase2
--- 90,94 ----
  	test "`cat dbase.used | wc -l`" -eq "`sed -n '2s/ .*//p' dbase.dir`" ;
  	cp $(RHIST) dbase2
! 	./rdbz -E 1000 -0 -p $(RPSIZE) -t '	' dbase2
  	cmp $(RHIST) dbase
  	cmp dbase dbase2
***************
*** 93,103 ****
  	cmp dbase.dir dbase2.dir
  	cmp dbase.pag dbase2.pag
! 	rdbz -E 1000 -0 -c dbase
! 	rdbz -E 1000 -0 -c -i -q -M -U dbase
  	: build a database and then add to it
  	sed 1000q $(RHIST) >dbase2
  	sed 1,1000d $(RHIST) >dbase2.add
! 	rdbz -E 1000 -0 dbase2
! 	rdbz -E 1000 -0 -a dbase2 dbase2.add
  	cmp dbase dbase2
  	cmp dbase.dir dbase2.dir
--- 95,105 ----
  	cmp dbase.dir dbase2.dir
  	cmp dbase.pag dbase2.pag
! 	./rdbz -E 1000 -0 -c dbase
! 	./rdbz -E 1000 -0 -c -i -q -M -U dbase
  	: build a database and then add to it
  	sed 1000q $(RHIST) >dbase2
  	sed 1,1000d $(RHIST) >dbase2.add
! 	./rdbz -E 1000 -0 dbase2
! 	./rdbz -E 1000 -0 -a dbase2 dbase2.add
  	cmp dbase dbase2
  	cmp dbase.dir dbase2.dir
***************
*** 104,125 ****
  	cmp dbase.pag dbase2.pag
  	: build based on existing one, test extraction and readonly files
! 	rdbz -E 1000 -0 -f dbase dbase2
  	test "`cat dbase.used | wc -l`" -eq "`awk 'NR==2{print $$1}' dbase2.dir`" ;
  	test "`cat dbase.used | wc -l`" -eq "`awk 'NR==2{print $$2}' dbase2.dir`" ;
  	chmod -w dbase2.dir dbase2.pag
! 	rdbz -E 1000 -x dbase2 dbase >dbase.temp
  	cmp dbase.used dbase.temp
  	: try some small case perversions
  	sed 's/\(@[^ 	]*\)A/\1a/' dbase >dbase.ick
! 	rdbz -E 1000 -x dbase2 dbase.ick >dbase.temp
  	cmp dbase.used dbase.temp
  	sed -n 's/A\([^ 	]*@\)/a\1/p' dbase >dbase.ick
! 	rdbz -x dbase2 dbase.ick >dbase.temp
  	test ! -s dbase.temp ;
  	rm -f dbase2.dir dbase2.pag
  	: try it without tags, case-insensitive, with case perversions
! 	rdbz -E 1000 -0 -p '0 b 1' dbase2
  	tr '[A-M][n-z]' '[a-m][N-Z]' <dbase2 >dbase.ick
! 	rdbz -E 1000 -x dbase2 dbase.ick >dbase.temp
  	cmp dbase.used dbase.temp
  	rm -f dbase.temp dbase.ick
--- 106,127 ----
  	cmp dbase.pag dbase2.pag
  	: build based on existing one, test extraction and readonly files
! 	./rdbz -E 1000 -0 -f dbase dbase2
  	test "`cat dbase.used | wc -l`" -eq "`awk 'NR==2{print $$1}' dbase2.dir`" ;
  	test "`cat dbase.used | wc -l`" -eq "`awk 'NR==2{print $$2}' dbase2.dir`" ;
  	chmod -w dbase2.dir dbase2.pag
! 	./rdbz -E 1000 -x dbase2 dbase >dbase.temp
  	cmp dbase.used dbase.temp
  	: try some small case perversions
  	sed 's/\(@[^ 	]*\)A/\1a/' dbase >dbase.ick
! 	./rdbz -E 1000 -x dbase2 dbase.ick >dbase.temp
  	cmp dbase.used dbase.temp
  	sed -n 's/A\([^ 	]*@\)/a\1/p' dbase >dbase.ick
! 	./rdbz -x dbase2 dbase.ick >dbase.temp
  	test ! -s dbase.temp ;
  	rm -f dbase2.dir dbase2.pag
  	: try it without tags, case-insensitive, with case perversions
! 	./rdbz -E 1000 -0 -p '0 b 1' dbase2
  	tr '[A-M][n-z]' '[a-m][N-Z]' <dbase2 >dbase.ick
! 	./rdbz -E 1000 -x dbase2 dbase.ick >dbase.temp
  	cmp dbase.used dbase.temp
  	rm -f dbase.temp dbase.ick
***************
*** 127,146 ****
  	awk -f revbytes dbase.dir >dbase2.dir
  	chmod +x getmap
! 	byteflip `getmap dbase.dir` `getmap dbase2.dir` <dbase.pag >dbase2.pag
  	cp dbase dbase2
! 	rdbz -E 1000 -0 -c dbase2
  	awk -f altbytes dbase.dir >dbase2.dir
  	dd conv=swab <dbase.pag >dbase2.pag
! 	rdbz -E 1000 -0 -c dbase2
  	cp dbase2 dbase3
! 	rdbz -E 1000 -0 -f dbase2 dbase3
! 	rdbz -E 1000 -0 -c dbase3
! 	test " `getmap dbase2.dir`" = " `getmap dbase3.dir`" ;
  	: test massive overflow, throw in case sensitivity and tag mask
  	cp $(R2HIST) dbase
! 	rdbz -E 1000 -0 -p '0 0 7ff00000' dbase
! 	rdbz -E 1000 -0 -cq dbase
  	sed 100q dbase | egrep '[aA].*	' | tr aA Aa >dbase.ick
! 	rdbz -x dbase dbase.ick >dbase.temp
  	test ! -s dbase.temp ;
  	: success!
--- 129,148 ----
  	awk -f revbytes dbase.dir >dbase2.dir
  	chmod +x getmap
! 	./byteflip `./getmap dbase.dir` `./getmap dbase2.dir` <dbase.pag >dbase2.pag
  	cp dbase dbase2
! 	./rdbz -E 1000 -0 -c dbase2
  	awk -f altbytes dbase.dir >dbase2.dir
  	dd conv=swab <dbase.pag >dbase2.pag
! 	./rdbz -E 1000 -0 -c dbase2
  	cp dbase2 dbase3
! 	./rdbz -E 1000 -0 -f dbase2 dbase3
! 	./rdbz -E 1000 -0 -c dbase3
! 	test " `./getmap dbase2.dir`" = " `./getmap dbase3.dir`" ;
  	: test massive overflow, throw in case sensitivity and tag mask
  	cp $(R2HIST) dbase
! 	./rdbz -E 1000 -0 -p '0 0 7ff00000' dbase
! 	./rdbz -E 1000 -0 -cq dbase
  	sed 100q dbase | egrep '[aA].*	' | tr aA Aa >dbase.ick
! 	./rdbz -x dbase dbase.ick >dbase.temp
  	test ! -s dbase.temp ;
  	: success!

*** cnpatch/old/expire/Makefile	Sat Apr 14 21:13:15 1990
--- expire/Makefile	Sat May 12 23:06:09 1990
***************
*** 9,13 ****
  	upact doexpire mkadir recovact
  DTR = README Makefile dircheck doexpire expire.c histdups histinfo.c \
! 	histslash.c mkdbm.c mkhistory pgood superkludge tgood upact \
  	mkadir updatemin.c recovact
  UPACT=upact
--- 9,13 ----
  	upact doexpire mkadir recovact
  DTR = README Makefile dircheck doexpire expire.c histdups histinfo.c \
! 	histslash.c mkdbm.c mkhistory pgood tgood upact \
  	mkadir updatemin.c recovact
  UPACT=upact
***************
*** 28,31 ****
--- 28,33 ----
  	cp $(THEM) $(NEWSBIN)/expire
  
+ explists:	explist.no explist.yes
+ 
  cmp:	$(THEM)
  	for f in $(THEM) ; do cmp $(NEWSBIN)/expire/$$f $$f ; done
***************
*** 198,202 ****
  
  # the regression test proper
! r:	$(THEM) $(UPACT) dircheck setup tgood pgood superkludge
  	chmod +x dircheck $(THEM)
  	$(RUN) -c explist
--- 200,204 ----
  
  # the regression test proper
! r:	$(THEM) $(UPACT) dircheck setup tgood pgood
  	chmod +x dircheck $(THEM)
  	$(RUN) -c explist
***************
*** 240,249 ****
  	test -r history.pag ;
  	test -r history.dir ;
- 	: "and that's mkhistory done, finally try superkludge"
- 	test -r arts/foo/1 ;
- 	test -r arts/foo/10 ;
- 	$(D) ./superkludge foo
- 	test ! -r arts/foo/1 ;
- 	test -r arts/foo/10 ;
  	: "success!"
  
--- 242,245 ----
***************
*** 269,274 ****
  
  tidy:
! 	rm -f junk history history.pag history.dir history.o active
! 	rm -f history.n* mon.out history.proto history.after test.out doit
  	rm -f active.old active.new explist lint active.after test.stderr
  	rm -rf arts arch arch2 arch3 nbin
--- 265,270 ----
  
  tidy:
! 	rm -f junk history history.pag history.dir history.o active active.tmp
! 	rm -f history.n* *mon.out history.proto history.after test.out doit
  	rm -f active.old active.new explist lint active.after test.stderr
  	rm -rf arts arch arch2 arch3 nbin

*** cnpatch/old/expire/README	Tue Mar 13 13:41:17 1990
--- expire/README	Wed Apr 18 14:27:58 1990
***************
*** 18,22 ****
  "make r" will compile everything and run a complex set of regression tests,
  checking the results automatically.  If nothing screams, there is a high
! probability that expire, upact, mkhistory, and superkludge are working.
  
  dircheck checks the results of expire regression testing.
--- 18,22 ----
  "make r" will compile everything and run a complex set of regression tests,
  checking the results automatically.  If nothing screams, there is a high
! probability that expire, upact, and mkhistory are working.
  
  dircheck checks the results of expire regression testing.
***************
*** 30,33 ****
  pgood and tgood are regression-test output-should-look-like-this files.
  mkadir is what expire invokes to create archiving subdirectories.
- superkludge is an old implementation of the Supersedes header, now
- 	superseded :-) by the full implementation in relaynews.
--- 30,31 ----

*** cnpatch/old/expire/doexpire	Tue Mar 13 13:41:18 1990
--- expire/doexpire	Sun May 13 01:28:34 1990
***************
*** 20,54 ****
  fi
  
  if test " `spacefor 1 archive`" -le 0
  then
! 	echo "$0: not enough space for archiving" | mail "$NEWSMASTER"
! 	exit 1
  fi
  
  cd $NEWSCTL
! ropt=-r
! for counter in x x x x		# four tries
  do
! 	size="`sizeof history history.pag history.dir`"
! 	if test " `spacefor $size control`" -gt 0
  	then
  		ropt=
- 		break
  	fi
- 	sleep 600		# and hope it will improve
  done
! if test " $ropt" = " -r"
! then
! 	(
! 		echo "$0:"
! 		echo "	SEVERE SPACE SHORTAGE in $NEWSCTL !"
! 		echo "	Unable to rebuild history files due to insufficient"
! 		echo "	space for temporaries -- resorting to \`expire -r'."
! 		echo "	Growth of the history files will make things worse;"
! 		echo "	if shortage persists, human action is urgently needed."
! 	) | mail "$NEWSMASTER"
! fi
  
! expire $ropt $* $NEWSCTL/explist 2>/tmp/doex$$
  if test -s /tmp/doex$$
  then
--- 20,73 ----
  fi
  
+ hopt=
  if test " `spacefor 1 archive`" -le 0
  then
! 	(
! 		echo "$0:"
! 		echo "	Space shortage in archiving area!"
! 		echo "	Unable to archive old articles -- holding them in"
! 		echo "	current directories using \`expire -h'.  If shortage"
! 		echo "	persists, human action is urgently needed."
! 	) | mail "$NEWSMASTER"
! 	hopt=-h
  fi
  
  cd $NEWSCTL
! forcer=no
! for o
  do
! 	if test " $o" = " -r"
  	then
+ 		forcer=yes
  		ropt=
  	fi
  done
! case "$forcer" in
! no)	ropt=-r
! 	for counter in x x x x		# four tries
! 	do
! 		size="`sizeof history history.pag history.dir`"
! 		if test " `spacefor $size control`" -gt 0
! 		then
! 			ropt=
! 			break
! 		fi
! 		sleep 600		# and hope it will improve
! 	done
! 	if test " $ropt" = " -r"
! 	then
! 		(
! 			echo "$0:"
! 			echo "	SEVERE SPACE SHORTAGE in $NEWSCTL !"
! 			echo "	Unable to rebuild history files due to insufficient"
! 			echo "	space for temporaries -- resorting to \`expire -r'."
! 			echo "	Growth of the history files will make things worse;"
! 			echo "	if shortage persists, human action is urgently needed."
! 		) | mail "$NEWSMASTER"
! 	fi
! 	;;
! esac
  
! expire $ropt $hopt $* $NEWSCTL/explist 2>/tmp/doex$$
  if test -s /tmp/doex$$
  then

*** cnpatch/old/expire/expire.c	Sat Apr 14 21:13:16 1990
--- expire/expire.c	Mon Apr 30 15:15:02 1990
***************
*** 71,74 ****
--- 71,75 ----
  int verbose = 0;		/* report statistics */
  int rebuild = 1;		/* rebuild history files */
+ int holdarch = 0;		/* hold rather than archiving */
  int getdgrump = 0;		/* report un-getdate()able expiry dates */
  
***************
*** 162,166 ****
  	ftime(&ftnow);
  
! 	while ((c = getopt(argc, argv, "pa:sF:cn:tlvrVgd")) != EOF)
  		switch (c) {
  		case 'p':	/* print info line for archived articles */
--- 163,167 ----
  	ftime(&ftnow);
  
! 	while ((c = getopt(argc, argv, "pa:sF:cn:tlvrhgd")) != EOF)
  		switch (c) {
  		case 'p':	/* print info line for archived articles */
***************
*** 194,197 ****
--- 195,201 ----
  			rebuild = 0;
  			break;
+ 		case 'h':	/* hold all files meant to be archived */
+ 			holdarch = 1;
+ 			break;
  		case 'g':	/* report getdate() failures on expiry dates */
  			getdgrump = 1;
***************
*** 757,764 ****
  
  	/* and decide */
! 	if (shouldgo(recdate, expdate, ct))
! 		return(ct->dir);
! 	else
  		return(dont);
  }
  
--- 761,768 ----
  
  	/* and decide */
! 	if (!shouldgo(recdate, expdate, ct) || (holdarch && ct->dir != NULL))
  		return(dont);
+ 	else
+ 		return(ct->dir);
  }
  

*** cnpatch/old/h/news.h	Tue Mar 13 13:41:19 1990
--- h/news.h	Thu May 10 16:44:47 1990
***************
*** 55,58 ****
--- 55,59 ----
  #define ST_DISKFULL	(1<<5)	/* disk full - give up */
  #define ST_JUNKED	(1<<6)	/* article was accepted, but junked */
+ #define ST_NEEDATTN	(1<<7)	/* news system needs human attention - give up */
  
  /* newsgroup specific definitions */

*** cnpatch/old/man/expire.8	Tue Mar 13 13:41:22 1990
--- man/expire.8	Sun May 13 01:33:41 1990
***************
*** 7,11 ****
  .\" =()<.ds m @<NEWSMASTER>@>()=
  .ds m usenet
! .TH EXPIRE 8 "12 Jan 1990"
  .BY "C News"
  .SH NAME
--- 7,11 ----
  .\" =()<.ds m @<NEWSMASTER>@>()=
  .ds m usenet
! .TH EXPIRE 8 "12 May 1990"
  .BY "C News"
  .SH NAME
***************
*** 46,49 ****
--- 46,51 ----
  ] [
  .B \-g
+ ] [
+ .B \-h
  ]
  [ controlfile ]
***************
*** 199,202 ****
--- 201,210 ----
  temporary storage.)
  .TP
+ .BR \-h
+ do not expire any article which would be archived if it were expired.
+ Mostly for emergencies, so that \fIexpire\fR can be run
+ (to delete articles in non-archived groups)
+ even if space is short in archiving areas.
+ .TP
  .BR \-v
  verbose:
***************
*** 225,229 ****
  .I Doexpire
  checks whether another \fIdoexpire\fR is running,
! checks that there is enough disk space for expiry and archiving,
  invokes \fIexpire\fR with any \fIexpireoptions\fR given and with
  \fI\*c/explist\fR as the control file,
--- 233,237 ----
  .I Doexpire
  checks whether another \fIdoexpire\fR is running,
! checks that there is enough disk space,
  invokes \fIexpire\fR with any \fIexpireoptions\fR given and with
  \fI\*c/explist\fR as the control file,
***************
*** 230,236 ****
  and reports any difficulties by sending mail to \fI\*m\fR.
  This is usually better than just running \fIexpire\fR directly.
! If space is adequate for archiving but persistently inadequate for the
  temporaries needed for history rebuilding, \fIdoexpire\fR reports this
! and invokes \fIexpire\fR with the \fB\-r\fR option.
  .PP
  .I Mkhistory
--- 238,247 ----
  and reports any difficulties by sending mail to \fI\*m\fR.
  This is usually better than just running \fIexpire\fR directly.
! If space is not adequate for archiving, \fIdoexpire\fR reports this
! and invokes \fIexpire\fR with the \fB\-h\fR option.
! If \fB\-r\fR is not among the \fIexpireoptions\fR,
! and disk space is persistently inadequate for the
  temporaries needed for history rebuilding, \fIdoexpire\fR reports this
! and invokes \fIexpire\fR with the \fB\-r\fR option anyway.
  .PP
  .I Mkhistory
***************
*** 285,288 ****
--- 296,302 ----
  with the `=' feature, since the article numbers will collide with each
  other and expire doesn't do anything about this.
+ Note that archiving a newsgroup which has subgroups into
+ an `=' directory puts all the subgroups in the same directory as the parent!
+ (Specifying the group as `foo.bar,!foo.bar.all' will avoid this.)
  .PP
  .I Mkhistory

*** cnpatch/old/man/news.5	Tue Mar 13 13:41:23 1990
--- man/news.5	Tue May 22 13:20:27 1990
***************
*** 169,173 ****
  putting a
  .B \e
! at the end of the line.
  .PP
  Of the \fIsys\fR fields,
--- 169,185 ----
  putting a
  .B \e
! at the end of the current physical line.
! Spaces are permitted in
! .I sys
! only in
! comments,
! .I "transmission command"
! when it really is a command and not a filename,
! and,
! for B news compatibility,
! at the start of a continuation line
! (after a
! .B \e
! and a newline).
  .PP
  Of the \fIsys\fR fields,

*** cnpatch/old/man/newsbatch.8	Sat Apr 14 21:13:17 1990
--- man/newsbatch.8	Sat May 12 23:17:00 1990
***************
*** 7,11 ****
  .\" =()<.ds m @<NEWSMASTER>@>()=
  .ds m usenet
! .TH NEWSBATCH 8 "14 April 1990"
  .BY "C News"
  .SH NAME
--- 7,11 ----
  .\" =()<.ds m @<NEWSMASTER>@>()=
  .ds m usenet
! .TH NEWSBATCH 8 "12 May 1990"
  .BY "C News"
  .SH NAME
***************
*** 18,24 ****
  c7encode, bencode \- compressed-news-batch encoding
  .br
! viauux, viauuxz, viauuxl, viainews, viarsh \- news-batch transmission
  .br
  viamail, viaemail, viapmail \- news-batch transmission via mail
  .SH SYNOPSIS
  .B \*b/batch/sendbatches
--- 18,26 ----
  c7encode, bencode \- compressed-news-batch encoding
  .br
! viauux, viauuxz, viauuxcun, viauuxl \- news-batch transmission via uucp
  .br
  viamail, viaemail, viapmail \- news-batch transmission via mail
+ .br
+ viainews, viarsh \- news-batch transmission by misc. means
  .SH SYNOPSIS
  .B \*b/batch/sendbatches
***************
*** 70,89 ****
  site
  .br	
  .B \&.../viauuxl
  group
  .br
! .B \&.../viainews
  site
  .br
! .B \&.../viarsh
  site
  .br
! .B \&.../viamail
  site
  .br
! .B \&.../viaemail
  site
  .br
! .B \&.../viapmail
  site
  .SH DESCRIPTION
--- 72,94 ----
  site
  .br	
+ .B \&.../viauuxcun
+ site
+ .br	
  .B \&.../viauuxl
  group
  .br
! .B \&.../viamail
  site
  .br
! .B \&.../viaemail
  site
  .br
! .B \&.../viapmail
  site
  .br
! .B \&.../viainews
  site
  .br
! .B \&.../viarsh
  site
  .SH DESCRIPTION
***************
*** 215,219 ****
  Batch transmitters in the standard distribution are:
  .RS
! .IP viauux 9
  normal transmission via UUCP
  .IP viauuxz
--- 220,224 ----
  Batch transmitters in the standard distribution are:
  .RS
! .IP viauux 10
  normal transmission via UUCP
  .IP viauuxz
***************
*** 220,223 ****
--- 225,231 ----
  like \fIviauux\fR except with \fB\-z\fR option given to \fIuux\fR
  (for old UUCPs where don't-report-result-on-zero-status is not default)
+ .IP viauuxcun
+ like \fIviauux\fR except it invokes \fIcunbatch\fR rather than \fIrnews\fR
+ at the other end (for some very old news sites)
  .IP viauuxl
  multicast transmission using the \fB\-l\fR option of \fIuux\fR (not found
***************
*** 224,227 ****
--- 232,242 ----
  on all systems) to send the same batch to all systems listed in the
  file `\*c/sites.\fIgroup\fR'
+ .IP viamail
+ mail the batch to \fIsite\fB!rnews\fR
+ .IP viaemail
+ mail the batch to \fIsite\fB!enews\fR
+ .IP viapmail
+ mail the batch to \fIsite\fB!rnews\fR, attempting to
+ protect an unencoded batch against the vagaries of mailers
  .IP viainews
  feed the batch back to \fIinews\fR, ignoring the \fIsite\fR argument
***************
*** 232,242 ****
  (the directory containing \fIrnews\fR
  must be in the default PATH on \fIsite\fR)
- .IP viamail
- mail the batch to \fIsite\fB!rnews\fR
- .IP viaemail
- mail the batch to \fIsite\fB!enews\fR
- .IP viapmail
- mail the batch to \fIsite\fB!rnews\fR, attempting to
- protect an unencoded batch against the vagaries of mailers
  .RE
  .PP
--- 247,250 ----

*** cnpatch/old/man/newsmaint.8	Tue Mar 13 13:41:24 1990
--- man/newsmaint.8	Tue May  8 18:00:00 1990
***************
*** 7,11 ****
  .\" =()<.ds m @<NEWSMASTER>@>()=
  .ds m usenet
! .TH NEWSMAINT 8 "16 Jan 1990"
  .BY "C News"
  .SH NAME
--- 7,11 ----
  .\" =()<.ds m @<NEWSMASTER>@>()=
  .ds m usenet
! .TH NEWSMAINT 8 "8 May 1990"
  .BY "C News"
  .SH NAME
***************
*** 25,28 ****
--- 25,30 ----
  .br
  addfeed \- add a news feed
+ .br
+ act.to.times \- create active.times file for news readers
  .SH SYNOPSIS
  .B \*b/maint/newshist
***************
*** 52,55 ****
--- 54,60 ----
  ]
  site groups
+ .br
+ .B \*b/maint/act.to.times
+ activefile
  .SH DESCRIPTION
  These programs are utilities useful in maintaining a C News
***************
*** 119,122 ****
--- 124,137 ----
  this specifies the same groups as those fed to site `\fIname\fR',
  with the exception that `to.\fIname\fR' is rewritten to `to.\fIsite\fR'.
+ .PP
+ .I Act.to.times
+ emits (on standard output) a new
+ .I active.times
+ file (see
+ .IR active.times (5))
+ based on the contents of
+ .IR activefile ,
+ which should normally be
+ .IR \*c/active .
  .SH FILES
  .ta 6c

*** cnpatch/old/misc/Makefile	Sat Apr 14 21:13:18 1990
--- misc/Makefile	Tue May  8 17:56:09 1990
***************
*** 12,16 ****
  
  MAINTBIN=newshist
! MAINT = $(MAINTBIN) newsdaily newswatch newsboot locknews addgroup delgroup adddirs addfeed
  UTILBIN = gngp newslock ctime getdate canonhdr
  UTILS = $(UTILBIN) sizeof newshostname
--- 12,16 ----
  
  MAINTBIN=newshist
! MAINT = $(MAINTBIN) newsdaily newswatch newsboot locknews addgroup delgroup adddirs addfeed act.to.times
  UTILBIN = gngp newslock ctime getdate canonhdr
  UTILS = $(UTILBIN) sizeof newshostname

*** cnpatch/old/misc/newshist.c	Wed Jan 10 19:10:48 1990
--- misc/newshist.c	Thu May 24 23:53:49 1990
***************
*** 5,15 ****
  #include <stdio.h>
  #include "news.h"
  #include "history.h"
  
  char *progname;
  int debug;
- static char *histfile;		/* unused */
  int remote;			/* to satisfy rnews code */
  
  /*
   * main - parse arguments and handle options
--- 5,20 ----
  #include <stdio.h>
  #include "news.h"
+ #include "headers.h"
+ #include "article.h"
  #include "history.h"
  
+ /* exports */
  char *progname;
  int debug;
  int remote;			/* to satisfy rnews code */
+ boolean okrefusal = YES;	/* .. */
  
+ static char *histfile;		/* unused */
+ 
  /*
   * main - parse arguments and handle options
***************
*** 77,79 ****
--- 82,90 ----
  unprivileged()
  {
+ }
+ 
+ prefuse(art)
+ struct article *art;
+ {
+ 	/* temporary hack until the cleanup release */
  }

*** cnpatch/old/notebook/problems	Tue Mar 13 13:41:26 1990
--- notebook/problems	Sun May 13 01:23:18 1990
***************
*** 1,3 ****
! .DA "8 March 1990"
  .TL
  Known Porting Problems With C News
--- 1,3 ----
! .DA "12 May 1990"
  .TL
  Known Porting Problems With C News
***************
*** 220,223 ****
--- 220,228 ----
  A short-term solution is to use the ``null'' variant, sacrificing space
  checking for the sake of getting something working.
+ .PP
+ We're told that HP-UX 7.0 users are best advised to
+ choose the ``bsd'' variant of spacefor, and edit it to
+ call \fIbdf\fR instead of \fIdf\fR.
+ Similar approaches may be useful on other hybrid SysV/BSD systems.
  .SH
  Floating Point
***************
*** 236,239 ****
--- 241,246 ----
  badly enough to cripple it, without producing any error messages.
  The only fix is to compile \fIdbz\fR without \fB\-O\fR.
+ .PP
+ SCO Xenix/386 2.3 has the same problem.
  .SH
  nnafree and nnfree
***************
*** 375,376 ****
--- 382,440 ----
  .DE
  or so we are told.
+ .SH
+ Binary-Mode Fopen
+ .PP
+ In several places, the new
+ \fIdbz\fR
+ uses ANSI C ``binary mode'' fopen codes, e.g.
+ `fopen(...,\ "r+b")'.
+ The text/binary distinction involved is meaningless
+ under Unix, and most Unix implementations just ignore trailing nonsense in
+ the second argument of
+ \fIfopen\fR,
+ so it all works out nicely.
+ .PP
+ Unfortunately... at least one version of DEC's Ultrix objects to the `b's,
+ we are told.
+ Sigh.
+ DEC will have to fix this to make their systems ANSI
+ compatible, but heaven only knows how long that will take.
+ .PP
+ Meanwhile, the fix is to delete the `b's in the second arguments of the
+ \fIfopen\fRs
+ in three places in
+ \fIdbminit()\fR
+ in
+ \fIdbz/dbz.c\fR,
+ if your system has
+ this particular bit of brain damage.
+ .SH
+ size_t
+ .PP
+ Some systems, notably from Microport, do not define the
+ \fIsize_t\fR type in the \fI<sys/types.h>\fR header.
+ Worse, the \fIsize_t\fR in that header doesn't necessarily bear any
+ relationship to the ANSI C \fIsize_t\fR.
+ This causes trouble in the \fIdbz\fR library in particular.
+ The proper type for \fIsize_t\fR is whatever the C \fIsizeof\fR
+ operator returns, nominally an unsigned type which is large enough to
+ contain the size of any memory object.
+ We think nothing relies too heavily on it being unsigned.
+ Note that \fIsize_t\fR must also be suitable for use in the two middle
+ arguments of \fIfread\fR and \fIfwrite\fR, the last argument of
+ \fImemcpy\fR, \fImemchr\fR, and \fImemcmp\fR,
+ and the argument of \fImalloc\fR.
+ .SH
+ Background Processes vs. csh
+ .PP
+ \fIInews\fR runs much of its processing in the background.
+ We are told that this can hit problems, in some circumstances,
+ with \fIcsh\fR's manipulations of signals, terminal modes, etc etc.
+ We prefer a standard shell, and have made no attempt to understand the
+ C shell's weirdnesses.
+ We're aware that well-written programs can fail
+ under the C shell due to bizarre problems with weird signals, etc., but
+ we class this as the fault of the C shell and its co-conspirators and
+ decline to contort our programs to compensate for its failings.
+ We do
+ sympathize with people victimized by it, but can be of no practical help.

*** cnpatch/old/relay/history.c	Tue Mar 13 13:41:28 1990
--- relay/history.c	Thu May 24 23:53:56 1990
***************
*** 62,68 ****
--- 62,72 ----
  extern datum fetch();
  
+ /* other imports */
+ extern boolean okrefusal;	/* flag from command line */
+ 
  /* forward decls */
  FORWARD datum getposhist();
  FORWARD void mkhistent(), sanitise(), subsanitise();
+ void decline();
  
  STATIC void
***************
*** 89,96 ****
  		/* else fp==NULL and fopenwclex just complained */
  
  		if (fp != NULL && dbminit(filename) < 0) {
! 			/* no luck. dbminit will have just honked */
  			(void) nfclose(fp);	/* close ascii file */
! 			fp = NULL;		/* and mark it */
  		}
  	}
--- 93,107 ----
  		/* else fp==NULL and fopenwclex just complained */
  
+ 		errno = 0;
  		if (fp != NULL && dbminit(filename) < 0) {
! 			/*
! 			 * no luck.  dbm's dbminit will have just honked (on
! 			 * stdout, alas) but dbz's won't have, so bitch.
! 			 */
! 			warning(
! 		"database files for `%s' incomprehensible or unavailable",
! 				filename);
  			(void) nfclose(fp);	/* close ascii file */
! 			fp = NULL;		/* and mark it closed */
  		}
  	}
***************
*** 143,147 ****
  		if (fseek(fp, pos, SEEK_SET) != -1 &&
  		    (histent = fgetms(fp)) != NULL)
! 			return histent;
  	}
  	return NULL;
--- 154,158 ----
  		if (fseek(fp, pos, SEEK_SET) != -1 &&
  		    (histent = fgetms(fp)) != NULL)
! 			return histent;		/* could note move from EOF */
  	}
  	return NULL;
***************
*** 185,188 ****
--- 196,201 ----
  	time_t now;
  
+ 	if (!msgidok(art))		/* complains in log if unhappy */
+ 		return;			/* refuse to corrupt history */
  	msgid = strsave(nullify(art->h.h_msgid));
  	sanitise(msgid);	/* RFC 1036 forbids whitespace in msg-ids */
***************
*** 199,208 ****
  		now = time(&now);
  	if (!openhist())
! 		art->a_status |= ST_DROPPED;	/* fall through and return */
  	else if (!writable) {
  		(void) fprintf(stderr, "%s: no write permission on `%s'\n",
  			progname, filename);
! 		art->a_status |= ST_DROPPED;
  	} else if (fseek(fp, 0L, SEEK_END) == -1) {
  		warning("can't seek to end of `%s'", filename);
  		art->a_status |= ST_DROPPED;
--- 212,222 ----
  		now = time(&now);
  	if (!openhist())
! 		art->a_status |= ST_DROPPED|ST_NEEDATTN;	/* serious */
  	else if (!writable) {
  		(void) fprintf(stderr, "%s: no write permission on `%s'\n",
  			progname, filename);
! 		art->a_status |= ST_DROPPED|ST_NEEDATTN;	/* serious */
  	} else if (fseek(fp, 0L, SEEK_END) == -1) {
+ 		/* could avoid fseek if still at EOF */
  		warning("can't seek to end of `%s'", filename);
  		art->a_status |= ST_DROPPED;
***************
*** 213,216 ****
--- 227,258 ----
  }
  
+ void
+ decline(art)					/* mark art as undesirable */
+ struct article *art;
+ {
+ 	art->a_status |= ST_REFUSED|(okrefusal? 0: ST_DROPPED);
+ }
+ 
+ int
+ msgidok(art)					/* if bad, complain in log */
+ register struct article *art;
+ {
+ 	register char *msgid = art->h.h_msgid;
+ 
+ 	if (msgid == NULL || msgid[0] == '\0') {
+ 		prefuse(art);
+ 		(void) printf("missing Message-ID\n");
+ 	} else if (strchr(msgid, ' ') != NULL || strchr(msgid, '\t') != NULL) {
+ 		prefuse(art);
+ 		(void) printf("whitespace in Message-ID\n");
+ 	} else if (msgid[0] != '<' || msgid[strlen(msgid)-1] != '>') {
+ 		prefuse(art);
+ 		(void) printf("Message-ID not bracketed by <>\n");
+ 	} else
+ 		return YES;
+ 	decline(art);
+ 	return NO;
+ }
+ 
  /*
   * Internal interface to generate a history file entry,
***************
*** 229,233 ****
  	datum msgidkey, posdatum;
  										
! 	pos = ftell(fp);			/* get seek ptr for dbm */
  	if (fprintf(fp, "%s%c%ld%c%s", msgid, FIELDSEP, now, SUBFIELDSEP, expiry)
  	    == EOF)
--- 271,275 ----
  	datum msgidkey, posdatum;
  										
! 	pos = ftell(fp);  /* get seek ptr for dbm; could keep track instead */
  	if (fprintf(fp, "%s%c%ld%c%s", msgid, FIELDSEP, now, SUBFIELDSEP, expiry)
  	    == EOF)

*** cnpatch/old/relay/makefile	Tue Jan 16 17:58:41 1990
--- relay/makefile	Mon May 14 14:13:32 1990
***************
*** 19,27 ****
  COPTS= -O # -pg -g
  CFLAGS=$(DEFINES) $(COPTS)
! DBM = -ldbm
  LIBS= $(DBM)
  LINT=lint
  LINTFLAGS=-haz $(DEFINES)
! LLIBS=-llocal
  # I wish I could make lint shut the fk up about some things.  Grrr!
  LINTFILT=egrep -v '(possible pointer|long assign|nnfree|getdate|:$$)'
--- 19,27 ----
  COPTS= -O # -pg -g
  CFLAGS=$(DEFINES) $(COPTS)
! DBM = # -ldbm
  LIBS= $(DBM)
  LINT=lint
  LINTFLAGS=-haz $(DEFINES)
! LLIBS=-llocal -lmalloc
  # I wish I could make lint shut the fk up about some things.  Grrr!
  LINTFILT=egrep -v '(possible pointer|long assign|nnfree|getdate|:$$)'
***************
*** 98,106 ****
  	-egrep TODO ../lib*/*.[ch] | tr -s " \11" " " >>$@
  
- v7 v8 v9 usg bsd42:
- 	test -d libos && exit 1
- 	mv lib$@ libos # or ln -s lib$@ libos
- 	make
- 
  print: printc printnonc
  	touch $@
--- 98,101 ----
***************
*** 111,117 ****
  	pr $(PROPTS) $? | $P
  	touch $@
- distr: $(FILES)
- 	(echo relaynews update of `date`; echo ""; bundle $?) | /bin/mail cnews-updates
- 	touch $@
  clean:
  	rm -f core a.out relaynews *.o	
--- 106,109 ----
***************
*** 120,124 ****
  r:	relaynews
  	chmod +x regress/regress
! 	cd regress; ./regress
  	
  # header dependencies follow
--- 112,116 ----
  r:	relaynews
  	chmod +x regress/regress
! 	(cd regress; ./regress)
  	
  # header dependencies follow

*** cnpatch/old/relay/msgs.c	Tue Jun 20 19:01:26 1989
--- relay/msgs.c	Thu May 10 16:45:00 1990
***************
*** 11,15 ****
  
  void
! fulldisk(art, file)		/* complain once & set ST_DISKFULL */
  register struct article *art;
  char *file;
--- 11,15 ----
  
  void
! fulldisk(art, file)			/* complain once & set status bits */
  register struct article *art;
  char *file;
***************
*** 20,27 ****
  
  statust
! prfulldisk(file)		/* complain once & return bad status */
  char *file;
  {
  	warning("error writing `%s', probably the disk filled", file);
! 	return ST_DISKFULL|ST_DROPPED;
  }
--- 20,27 ----
  
  statust
! prfulldisk(file)			/* complain & return bad status */
  char *file;
  {
  	warning("error writing `%s', probably the disk filled", file);
! 	return ST_DISKFULL|ST_NEEDATTN|ST_DROPPED;
  }

*** cnpatch/old/relay/procart.c	Sat Apr 14 21:13:19 1990
--- relay/procart.c	Thu May 24 23:53:53 1990
***************
*** 32,37 ****
  
  extern char *exclude;		/* for erik */
- extern boolean okrefusal;	/* flag from command line */
  
  /* forwards */
  extern void tossorfile(), surveydamage(), reject(), prefuse(), uninsart();
--- 32,39 ----
  
  extern char *exclude;		/* for erik */
  
+ /* imports */
+ extern void decline();
+ 
  /* forwards */
  extern void tossorfile(), surveydamage(), reject(), prefuse(), uninsart();
***************
*** 64,68 ****
  	/*
  	 * copyart() may reject() the article, and may fill the disk.
! 	 * it calls fileart and logs rejected articles.
  	 */
  	copyart(artp, in, inname);
--- 66,70 ----
  	/*
  	 * copyart() may reject() the article, and may fill the disk.
! 	 * it calls fileart and logs rejected articles.  it may call uninsart.
  	 */
  	copyart(artp, in, inname);
***************
*** 211,215 ****
  		art->a_charswritten += bodylen;
  	}
! 	for (; art->a_unread > 0 && !(art->a_status&ST_DISKFULL) && !feof(in) &&
  	    (readcnt=fread(block, 1, (int)min(art->a_unread, COPYSIZE), in)) > 0;
  	    art->a_unread -= readcnt, art->a_charswritten += readcnt)
--- 213,217 ----
  		art->a_charswritten += bodylen;
  	}
! 	for (; art->a_unread > 0 && !(art->a_status&ST_NEEDATTN) && !feof(in) &&
  	    (readcnt=fread(block, 1, (int)min(art->a_unread, COPYSIZE), in)) > 0;
  	    art->a_unread -= readcnt, art->a_charswritten += readcnt)
***************
*** 222,228 ****
  
  /*
!  * If not yet uninstalled, and the disk filled, uninstall this article
!  * to remove any zero-length links and decrement the active article number.
!  * The ST_DISKFULL status will prevent a history entry from being generated.
   */
  void
--- 224,231 ----
  
  /*
!  * If not yet uninstalled, and the disk filled (or the news system was found
!  * to be otherwise unwell), uninstall this article
!  * to remove any (zero-length) links and decrement the active article number.
!  * The ST_NEEDATTN status will prevent a history entry being generated later.
   */
  void
***************
*** 237,241 ****
  		art->a_status |= ST_SHORT;	/* NB.: don't uninstall this art. */
  	}
! 	if (*installedp && art->a_status&ST_DISKFULL) {
  		uninsart(art);
  		*installedp = NO;
--- 240,244 ----
  		art->a_status |= ST_SHORT;	/* NB.: don't uninstall this art. */
  	}
! 	if (*installedp && art->a_status&ST_NEEDATTN) {
  		uninsart(art);
  		*installedp = NO;
***************
*** 253,257 ****
  
  /*
!  * Install the article on art->a_tmpf or art->a_files:
   * The article should have been accepted and filed in copyart().
   * Add history entries for the article.  Log arrival.
--- 256,261 ----
  
  /*
!  * If nothing has gone wrong yet,
!  * install the article on art->a_tmpf or art->a_files:
   * The article should have been accepted and filed in copyart().
   * Add history entries for the article.  Log arrival.
***************
*** 264,278 ****
  register struct article *art;
  {
! 	if (!(art->a_status&(ST_DROPPED|ST_REFUSED|ST_DISKFULL))) {
  		if (!art->a_filed)			/* paranoia */
  			(void) fprintf(stderr, "%s: %s not filed by copyart!\n",
  				progname, art->h.h_msgid);
! 		history(art, STARTLOG);
! 		transmit(art, exclude);		/* writes systems on stdout */
! 		(void) putchar('\n');		/* ends the log line */
! 		ctlmsg(art);
! #ifdef notdef					/* it's only a log file! */
! 		(void) fflush(stdout);		/* crash-proofness */
  #endif
  	}
  	art->a_status &= ~ST_REFUSED;	/* refusal is quite casual & common */
--- 268,286 ----
  register struct article *art;
  {
! 	if (!(art->a_status&(ST_DROPPED|ST_REFUSED|ST_NEEDATTN))) {
  		if (!art->a_filed)			/* paranoia */
  			(void) fprintf(stderr, "%s: %s not filed by copyart!\n",
  				progname, art->h.h_msgid);
! 		history(art, STARTLOG);		/* history may be unwritable */
! 		if (art->a_status&(ST_DROPPED|ST_REFUSED|ST_NEEDATTN))
! 			uninsart(art);		/* it was; can't keep the article */
! 		else {
! 			transmit(art, exclude);	/* writes systems on stdout */
! 			(void) putchar('\n');	/* ends the log line */
! 			ctlmsg(art);		/* NCMP */
! #ifdef FLUSHLOG
! 			(void) fflush(stdout);	/* crash-proofness */
  #endif
+ 		}
  	}
  	art->a_status &= ~ST_REFUSED;	/* refusal is quite casual & common */
***************
*** 297,311 ****
  		prefuse(art);
  		(void) printf("no Path: header\n");
! 	} else if (msgid == NULL || msgid[0] == '\0') {
  		prefuse(art);
- 		(void) printf("missing Message-ID\n");
- 	} else if (strchr(msgid, ' ') != NULL || strchr(msgid, '\t') != NULL) {
- 		prefuse(art);
- 		(void) printf("whitespace in Message-ID\n");
- 	} else if (msgid[0] != '<' || msgid[strlen(msgid)-1] != '>') {
- 		prefuse(art);
- 		(void) printf("Message-ID not bracketed by <>\n");
- 	} else if (alreadyseen(msgid)) {
- 		prefuse(art);
  		(void) printf("duplicate\n");
  	} else if (path != NULL && hopcount(path) > 0 &&
--- 305,312 ----
  		prefuse(art);
  		(void) printf("no Path: header\n");
! 	} else if (!msgidok(art))
! 		/* already complained */ ;
! 	else if (alreadyseen(msgid)) {
  		prefuse(art);
  		(void) printf("duplicate\n");
  	} else if (path != NULL && hopcount(path) > 0 &&
***************
*** 328,334 ****
  	} else
  		return;			/* art was accepted */
! 	art->a_status |= ST_REFUSED;
! 	if (!okrefusal)
! 		art->a_status |= ST_DROPPED;
  }
  
--- 329,333 ----
  	} else
  		return;			/* art was accepted */
! 	decline(art);
  }
  
***************
*** 349,354 ****
   * a_tmpf (temporary name if a_unlink set), and return assigned article #'s.
   * If a_unlink isn't set, a_tmpf is a copy of the first link in art->a_files.
!  * Must be called before history() is called, else there will be a
!  * history entry for the article, but no spool files.
   */
  void
--- 348,354 ----
   * a_tmpf (temporary name if a_unlink set), and return assigned article #'s.
   * If a_unlink isn't set, a_tmpf is a copy of the first link in art->a_files.
!  * Must be called before history() is called (or after it has failed),
!  * else there will be a history entry for the article, but no spool files.
!  * insart() need not be called first.
   */
  void

*** cnpatch/old/relay/relaynews.c	Sat Apr 14 21:13:20 1990
--- relay/relaynews.c	Thu May 10 16:45:02 1990
***************
*** 26,34 ****
   * too wasteful; use the batched form instead (see the ihave sys flag
   * ("I") instead).
-  *
-  * Portability vs SystemV.  relaynews uses dbm(3) and makes no apologies
-  * for so doing.  Imitation UNIX (registered trademark of AT&T in the
-  * United States) brand operating systems that lack dbm are going to
-  * have to use my incredibly slow dbm simulation, or another.
   */
  
--- 26,29 ----
***************
*** 147,151 ****
  	register char *newpath;
  
! 	(void) umask(2);		/* undo silly umasks, ignore newsumask() */
  	(void) alarm(0);		/* cancel any pending alarm */
  	newpath = malloc((unsigned)(STRLEN("PATH=")+strlen(newspath())+SIZENUL));
--- 142,146 ----
  	register char *newpath;
  
! 	(void) umask(newsumask());
  	(void) alarm(0);		/* cancel any pending alarm */
  	newpath = malloc((unsigned)(STRLEN("PATH=")+strlen(newspath())+SIZENUL));
***************
*** 462,466 ****
  	long charcnt;
  
! 	while (!(status&ST_DISKFULL) && (c = getc(in)) != EOF) {
  		(void) ungetc(c, in);
  		while ((line = fgetms(in)) != NULL &&
--- 457,461 ----
  	long charcnt;
  
! 	while (!(status&ST_NEEDATTN) && (c = getc(in)) != EOF) {
  		(void) ungetc(c, in);
  		while ((line = fgetms(in)) != NULL &&

*** cnpatch/old/relay/sh/inews	Sat Apr 14 21:13:20 1990
--- relay/sh/inews	Mon Apr 23 15:51:08 1990
***************
*** 88,94 ****
  
  	-C)
! 		echo "$0: you either want to use addgroup (see newsaux(8)) to make" >&2
! 		echo "$0: $2 locally or this to make it network-wide:" >&2
! 		cat <<eg
  inews -h <<'!'
  Control: newgroup $2
--- 88,94 ----
  
  	-C)
! 		cat <<eg >&2
! $0: you either want to use addgroup (see newsaux(8)) to make
! $0: $2 locally, or this to make it network-wide:
  inews -h <<'!'
  Control: newgroup $2
***************
*** 199,202 ****
--- 199,204 ----
   fi) >$censart
  
+ ### the article is fully assembled now in $censart ###
+ 
  # to post or to mail? that is the question; whether 'tis nobler in the mind
  # to suffer the slings and arrows of outrageous mailers - Bill Shakespeare
***************
*** 252,255 ****
--- 254,258 ----
  						>$modroute
  				moderator="`cat $modroute `"
+ 				# TODO: next line confuses nn; change to stdout?
  				echo "$0: mailing your article to $moderator" >&2
  				mail "$moderator" <$censart
***************
*** 282,285 ****
--- 285,290 ----
  	exit $exitstatus	# trap 0 may cleanup, make dead.article
  fi
+ 
+ ### if the article was mailed, that happened above; posting will happen below ###
  
  # deal with inadequate free space

*** cnpatch/old/relay/sh/tear	Tue Jun 20 19:01:37 1989
--- relay/sh/tear	Sun May 13 01:15:45 1990
***************
*** 21,25 ****
  *)	args="$@" ;;
  esac
! exec awk 'inbody == 0 && $0 ~ /^([ \t]|[^ \t]*:)/ { print >hdr; next }
  					{ inbody = 1; print >body }
  ' hdr="$hdr" body="$body" $args
--- 21,25 ----
  *)	args="$@" ;;
  esac
! exec awk 'inbody == 0 && ($0 ~ /^[^ \t]*:/ || ($0 ~ /^[ \t]/ && NR > 1)) { print >hdr; next }
  					{ inbody = 1; print >body }
  ' hdr="$hdr" body="$body" $args

*** cnpatch/old/relay/sys.c	Tue Jan 16 17:58:42 1990
--- relay/sys.c	Thu May 10 16:43:51 1990
***************
*** 25,29 ****
  /* forward decls */
  FORWARD char *parsecolon(), *reparse();
! FORWARD void readsys(), parsesysln(), parse(), parseflags();
  
  /* exports */
--- 25,29 ----
  /* forward decls */
  FORWARD char *parsecolon(), *reparse();
! FORWARD void readsys(), parsesysln(), parse(), parseflags(), newartfile();
  
  /* exports */
***************
*** 176,184 ****
  		(void) strcat(deffile, sysp->sy_name);
  		(void) strcat(deffile, BTCHSFX);
! 		free(sysp->sy_cmd);	/* malloced by parse */
! 		sysp->sy_cmd = strsave(fullartfile(deffile));
! 		free(deffile);
! 	}
! 	if (sysp->sy_flags&FLG_BATCH && sysp->sy_cmd[0] != FNDELIM) {
  		register char *absfile = nemalloc((unsigned) STRLEN(BTCHDIR) +
  			strlen(sysp->sy_cmd) + SIZENUL);
--- 176,182 ----
  		(void) strcat(deffile, sysp->sy_name);
  		(void) strcat(deffile, BTCHSFX);
! 		/* frees old sysp->sy_cmd, deffile */
! 		newartfile(sysp, deffile);
! 	} else if (sysp->sy_flags&FLG_BATCH && sysp->sy_cmd[0] != FNDELIM) {
  		register char *absfile = nemalloc((unsigned) STRLEN(BTCHDIR) +
  			strlen(sysp->sy_cmd) + SIZENUL);
***************
*** 186,195 ****
  		(void) strcpy(absfile, BTCHDIR);
  		(void) strcat(absfile, sysp->sy_cmd);
  		free(sysp->sy_cmd);	/* malloced by parse */
- 		sysp->sy_cmd = strsave(artfile(absfile));
- 		free(absfile);
- 	}
- 	if (!(sysp->sy_flags&FLG_BATCH) && sysp->sy_cmd[0] == '\0') {
- 		free(sysp->sy_cmd);	/* malloced by parse */
  		sysp->sy_cmd = nemalloc((unsigned) STRLEN(CMDPFX) +
  			strlen(sysp->sy_name) + STRLEN(CMDSFX) + SIZENUL);
--- 184,191 ----
  		(void) strcpy(absfile, BTCHDIR);
  		(void) strcat(absfile, sysp->sy_cmd);
+ 		/* frees old sysp->sy_cmd, absfile */
+ 		newartfile(sysp, absfile);
+ 	} else if (!(sysp->sy_flags&FLG_BATCH) && sysp->sy_cmd[0] == '\0') {
  		free(sysp->sy_cmd);	/* malloced by parse */
  		sysp->sy_cmd = nemalloc((unsigned) STRLEN(CMDPFX) +
  			strlen(sysp->sy_name) + STRLEN(CMDSFX) + SIZENUL);
***************
*** 198,201 ****
--- 194,207 ----
  		(void) strcat(sysp->sy_cmd, CMDSFX);
  	}
+ }
+ 
+ STATIC void
+ newartfile(sysp, file)		/* replace sysp->sy_cmd with artfile(file) */
+ register struct system *sysp;
+ register char *file;
+ {
+ 	free(sysp->sy_cmd);		/* malloced by parse */
+ 	sysp->sy_cmd = strsave(artfile(file));
+ 	free(file);
  }
  

*** cnpatch/old/relay/trbatch.c	Tue Mar 13 13:41:30 1990
--- relay/trbatch.c	Fri May  4 14:42:10 1990
***************
*** 97,102 ****
  }
  
  statust
! bffkclose(ord)				/* close ord's batchfile, if fake */
  int ord;
  {
--- 97,103 ----
  }
  
+ /* ARGSUSED ord */
  statust
! bffkclose(ord)			/* close current (ord's) batchfile, if fake */
  int ord;
  {
***************
*** 103,107 ****
  	register statust status = ST_OKAY;
  
! 	if (ord >= NOPENBFS)
  		status |= bfclose(&fakebatf);
  	return status;
--- 104,108 ----
  	register statust status = ST_OKAY;
  
! 	if (fakebatf.bf_str != NULL)
  		status |= bfclose(&fakebatf);
  	return status;

Files that are new:

new man/active.times.5 (patch can't create, so diff against null):
Index: man/active.times.5
*** cnpatch/old/man/active.times.5	Fri May 25 00:18:01 1990
--- man/active.times.5	Tue May  8 18:00:10 1990
***************
*** 0 ****
--- 1,82 ----
+ .\" =()<.ds a @<NEWSARTS>@>()=
+ .ds a /usr/spool/news
+ .\" =()<.ds b @<NEWSBIN>@>()=
+ .ds b /usr/lib/newsbin
+ .\" =()<.ds c @<NEWSCTL>@>()=
+ .ds c /usr/lib/news
+ .\" =()<.ds m @<NEWSMASTER>@>()=
+ .ds m usenet
+ .TH ACTIVE.TIMES 5 "8 May 1990"
+ .BY "C News"
+ .SH NAME
+ active.times \- newsgroup creation times and creators
+ .SH DESCRIPTION
+ The
+ .I active.times
+ file records the arrival of new newsgroups by time and creator.
+ This provides a quick
+ way for newsreaders to tell when new groups have arrived,
+ without weird heuristics and time/space expensive schemes
+ like storing old lists of
+ newsgroups and comparing them to the
+ .I active
+ file.
+ .PP
+ When a new newsgroup is created by C News,
+ via
+ .I \*b/ctl/newgroup
+ or
+ .IR \*b/maint/addgroup ,
+ the group name, time of group creation, and identity of the creator
+ are appended to the
+ .I \*c/active.times
+ file.
+ The time is that returned by 
+ .I \*b/maint/getdate
+ and on Unix systems
+ is the number of seconds since January 1, 1970,
+ 00:00, GMT.
+ The identity of the creator is taken from the
+ .B Sender:
+ or
+ .B From:
+ headers in the control message for groups added with
+ .IR \*b/ctl/newgroup ,
+ and from the environment variable USER
+ (if any; the default identity is ``unknown'')
+ for groups created with
+ .IR \*b/maint/addgroup .
+ .PP
+ Each line in the file is of the form
+ .PP
+ .nf
+ .in +0.5i
+ .ft B
+ newsgroup creation-time creator
+ .ft R
+ .in -0.5i
+ .fi
+ .PP
+ The file must always be sorted in increasing order of the creation-time field.
+ The scripts only append to the file, which normally suffices to ensure this.
+ (It is assumed that time on the machine does not jump backward!)
+ .PP
+ An initial version of
+ .I active.times
+ for already existing newsgroups,
+ with all times equal to the time of its creation
+ and all creators ``unknown'',
+ can be built using
+ .I \*b/maint/act.to.times
+ (see
+ .IR newsmaint (8)).
+ .SH FILES
+ .nf
+ \*c/active.times
+ \*b/maint/addgroup
+ \*b/maint/act.to.times
+ \*b/ctl/newgroup
+ .fi
+ .SH HISTORY
+ Conceived and implemented
+ by Mark Moraes and Geoff Collyer as part of the C News project.

new misc/act.to.times (patch can't create, so diff against null):
Index: misc/act.to.times
*** cnpatch/old/misc/act.to.times	Fri May 25 00:18:01 1990
--- misc/act.to.times	Tue May  8 17:44:38 1990
***************
*** 0 ****
--- 1,9 ----
+ # act.to.times [file...] - turn an active file into a active.times file inaccurately
+ # =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
+ . ${NEWSCONFIG-/usr/lib/news/bin/config}
+ # export NEWSCTL NEWSBIN NEWSARTS
+ PATH=$NEWSCTL/bin:$NEWSBIN:$NEWSPATH ; export PATH
+ umask $NEWSUMASK
+ 
+ now=`getdate now`
+ cat $* | sed "s/ .*/ $now unknown/"


end of patch 25-May-1990
-- 
Life is too short to spend    |     Henry Spencer at U of Toronto Zoology
debugging Intel parts. -Van J.| uunet!attcan!utzoo!henry henry@zoo.toronto.edu