From: klovatt@klnet.UUCP (Keith Lovatt)
Newsgroups: comp.os.coherent
Subject: Re: inews
Date: 5 Oct 92 03:23:17 GMT
Organization: Lugroid Enterprises
X-Newsreader: Tin 1.1 PL4

root@rgm.com (System Administrator) writes:
: I've tracked my problem down to a couple of lines in the inews script.
: Could someone please post their WORKING inews script (from Cnews) here?
: 

It's more than just inews, it's also anne.jones and defhdrs.awk. Here they are:
Also, you need to set /etc/ATclock to be all executable.

Keith.
================================================================================
inews: (needs to be in /usr/lib/news)
================================================================================
#! /bin/sh
# inews [-p] [-debug k] [-x site] [-hMD] [-t subj] [-n ng] [-e exp] [-F ref] \
#  [-d dist] [-a mod] [-f from] [-o org] [-C ng] [file...] - inject news:
#	censor locally-posted article and field the "inews -C" kludge;
#	munge the articles, enforce feeble attempts at Usenet security,
#	generate lots of silly headers.
#
# Yes, it's big, slow and awkward.  The alternative is casting a lot of
# local policy in C.

# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
. ${NEWSCONFIG-/usr/lib/news/bin/config}
export NEWSCTL NEWSBIN NEWSARTS NEWSPATH NEWSUMASK NEWSMASTER NEWSCONFIG
PATH=$NEWSCTL/bin:$NEWSBIN/inject:$NEWSBIN/relay:$NEWSBIN:$NEWSPATH; export PATH
PASSEDFROM='';	export PASSEDFROM	# passed to anne.jones in environ.

debug=''			# flags
exclusion=''
hdrspresent=no
autopost=no
waitcmd='status=0'
relayopts=-i			# redirect stdout to log

input=/tmp/in$$in		# uncensored input
inhdrs=/tmp/in$$hdr		# generated by tear: headers
inbody=/tmp/in$$body		# generated by tear: body
censart=/tmp/in$$cens		# censored input
nglist=/tmp/in$$ngs		# newsgroups: list
modroute=/tmp/in$$route		# route to moderator's forwarder
exitflag=/tmp/in$$exit		# exit status, if present
outfile=/tmp/in$$out		# relaynews stdout
rmlist="$inhdrs $inbody $input $censart $nglist $modroute $exitflag $outfile"
#rmlist="/tmp/k.tmp"
grpok=/tmp/in$$grp		# flag file: groups okay if present

umask $NEWSUMASK

# "inews -p": invoke rnews
case "$1" in
-p)
	shift
	cat $* | relaynews -r	# feed directly to relaynews, seat belts off
	exit
	;;
esac

# process arguments: for options, cat headers onto $input; cat files onto $input
>$input
cleanup="test ! -f $HOME/dead.article -o -w $HOME/dead.article && cat $input >>$HOME/dead.article && { echo $0: article in $HOME/dead.article >&2; rm -f $rmlist; }; exit 1"
trap "$cleanup" 0 1 2 3 15
while :
do
	case $# in
	0)	break ;;		# arguments exhausted
	esac

	case "$1" in
	# peculiar to C news
	-debug)	shift; debug="$1" ;;
	-A)	autopost=yes ;;		# wait for free space
	-V)	relayopts= ;;		# verbose: don't redirect stdout (or stderr)
	-W)	waitcmd='wait; status=$?' ;;	# wait for completion
	# useful standard options
	-h)	hdrspresent=yes ;;
	-x)	shift; exclusion="-x $1" ;;	# you're welcome, erik (2.11)
	# silly options supplied by newsreaders
	-a)	shift; echo "Approved: $1" >>$input ;;
	-c)	shift; echo "Control: $1" >>$input ;;
	-d)	shift; echo "Distribution: $1" >>$input ;;
	-e)	shift; echo "Expires: $1" >>$input ;;
	-f)	shift; echo "From: $1" >>$input ;;
	-n)	shift; echo "Newsgroups: $1" >>$input ;;
	-r)	shift; echo "Reply-To: $1" >>$input ;;
	-t)	shift; echo "Subject: $1" >>$input ;;	# aka Title:
	-D)	# obsolete, undocumented: meant "don't check for recordings".
		# last present in B 2.10.1, invoked by readnews for followups.
		;;
	-F)	# undocumented in B 2.10.1, documented in B 2.11.
		shift; echo "References: $1" >>$input ;;
	-M)	# this apparently just sets From: to the author of the article
		# instead of the poster (moderator), by leaving the From: line
		# alone (under -h); easy to implement.
		;;

	# pass next options as environment variables to anne.jones
	-o)	shift; ORGANIZATION="$1"; export ORGANIZATION ;;

	-C)
		cat  >&2 <<eg
$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
Subject: newgroup $2
Newsgroups: $2

Non-empty.
!
eg
		exit 1
		;;
	-*)
		echo "$0: bad option $1" >&2
		exit 1
		;;
	*)					# is a filename; append file
		# B 2.11 kludge: assume -h if input starts with headers.
		# apparently the B 2.11 newsreaders assume this.
		tear /tmp/in$$ <$1
		if test -s $inhdrs; then
			hdrspresent=yes
		fi

		case "$hdrspresent" in
		no)	echo "" >>$input; hdrspresent=yes ;;
		esac
		# capture incoming news in case relaynews fails
		if cat $inhdrs $inbody >>$input; then
			: far out
		else
			echo "$0: lost news; cat status $?" >&2
			exit 1
		fi
		fileseen=yes
		;;
	esac
	shift		# pass option or filename (any value was done above)
done

# if no files named, read stdin
case "$fileseen" in
yes)	;;
*)
	# B 2.11 kludge: assume -h if input starts with headers
	# apparently the B 2.11 newsreaders assume this.
	tear /tmp/in$$
	if test -s $inhdrs; then
		hdrspresent=yes
	fi

	case "$hdrspresent" in
	no)	echo "" >>$input; hdrspresent=yes ;;
	esac
	# capture incoming news in case relaynews fails
	if cat $inhdrs $inbody >>$input; then
		: far out
	else
		echo "$0: lost news; cat status $?" >&2
		exit 1
	fi
	;;
esac
trap '' 1 2 15			# ignore signals to avoid losing articles

# run the remainder in the background for the benefit of impatient people
# who lack a window system
#(
trap "$cleanup" 0
tear /tmp/in$$ <$input		# output in $inhdrs and $inbody
# canonicalise header keyword capitalisation.
# greps for Control: and Approved: later assume this, as does defhdrs.awk.
canonhdr <$inhdrs >/tmp/in$$realtmp
mv /tmp/in$$realtmp $inhdrs
# pad zero-line articles, since old B [ir]news are confused by them
# and the news readers generate zero-line control messages, alas.
if test ! -s $inbody; then
	(echo ''; echo This article was probably generated by a buggy news reader.) >$inbody
fi

# deduce which tr we have: v6 or v7
case "`echo B | tr A-Z a-z `" in
b)	trversion=v7 ;;
B)	trversion=v6 ;;			# or System V
esac
export trversion

# post with new headers and .signature
(anne.jones <$inhdrs		# bash headers
 lines="`			# sop to msb, just uncomment to use
 (sed 1d $inbody;	# take out the first (blank) line
 if test -r $HOME/.signature; then
 	echo '-- '
 	sed 4q $HOME/.signature
 fi) | wc -l `"
 echo Lines: $lines

 # strip invisible chars from body, a la B news.  bells and escapes are right out.
 case "$trversion" in
 v7)	tr -d  '\1-\7\13\15-\37' ;;
 v6)	tr -d '[\1-\7]\13[\15-\37]' ;;
 esac <$inbody

 if test -r $HOME/.signature; then
	echo "-- "; sed 4q $HOME/.signature	# glue on first bit of signature
 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
if grep -s '^Control:' $inhdrs >/dev/null; then
	echo "control"			# a dreadful hack around all.all.ctl
else
	sed -n \
	    -e '/^Newsgroups:[	 ]/{'	\
	    -e 's/^Newsgroups:[	 ]*\(.*\)$/\1/p'	\
	    -e 'q'	\
	    -e '}' <$inhdrs
fi >$nglist

if test ! -s $nglist; then		# no Newsgroups:
	exit 1				# anne.jones will have already complained
fi

# look up groups in active, to determine disposition of this message.
# n, x and (unapproved) m flags are dealt with on the spot; if none are
# seen, the article is posted normally.
# escape egrep metacharacters.  In theory one could add " ' ` \ to the list.
#egreppat="^(` sed -e 's/[.+*()|[]/\\\\&/gp' -e 's/,/|/g' <$nglist `) "
egreppat="^(` sed -e 's/[.+*()|[]/&/gp' -e 's/,/|/g' <$nglist `) "
egrep "$egreppat" $NEWSCTL/active >/dev/null || { echo "$0: `cat $nglist` matches no groups in $NEWSCTL/active" >&2
	exit 1
}
rm -f $grpok
egrep "$egreppat" $NEWSCTL/active |	
	(while read ng high low flag junk	# look at next group's active entry
	do
		>>$grpok
		case "$flag" in
		[nx])
			echo "$0: sorry, $ng may not be posted to locally." >&2
			trap 0		# this is a child process - no cleanup here
			echo 1 >$exitflag
			exit 1		# dregs in /tmp/in$$*
			;;
		m)
			if grep -s '^Approved:[	 ]' $inhdrs >/dev/null; then
				:		# just post normally
			else
				# un-Approved article: mail it to the moderator(s).
				# look for a route for this group.
				# a dreadful B 2.11 hack: backbone == all
				(sed 's/^backbone[	 ]/all /' \
							$NEWSCTL/mailpaths |
						gngp -a -r "`cat $nglist`";
						echo 'default	%s') |
					sed -n -e "1{s/^[^	 ]*[	 ][	 ]*//" -e "s/%s/` echo $ng | tr . - `/;p;q;}" >$modroute
				moderator="`cat $modroute `"
				echo "mailing your article to $moderator"
				mail "$moderator" <$censart
				trap 0	# this is a child process - no cleanup here
				echo 0 >$exitflag
				exit 0
			fi
			;;

			# "" matches short active entries,
			#	to be backward compatible.
			# * matches garbage flags, to be cautious.
		y|""|*)
			# okay so far, but wait until we see all Newsgroups:.
			;;
		esac
	done
	trap 0					# paranoia - no clean up
	)
if test ! -r $grpok; then
	echo "$0: no active groups in `cat $nglist`" >&2
	exit 1			# abnormal exit - cleans up, makes dead.article
fi
rm -f $grpok
if test -f $exitflag; then
	exitstatus="`cat $exitflag`"
	case "$exitstatus" in
	0)	rm -f $rmlist; trap 0 ;; # normal exit - cleanup, no dead.article
	esac
	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
case "$autopost" in
no)
	if test "`spacefor 1 articles`" -le 0; then
		echo "$0: too little space free on $NEWSARTS" >&2
		exit 1			# dregs in /tmp/in$$* for trap 0
	fi
	;;
*)
	iter=0
	while test "`spacefor 1 articles`" -le 0 -o "`spacefor 1 control`" -le 0
	do
		sleep 30
		iter=`expr $iter + 1`
		case "$iter" in
		3)
			mail "$NEWSMASTER" <<!
Subject: free space too low on $NEWSARTS

There is too little free space on $NEWSARTS for inews to run comfortably.
!
			;;
		esac
	done
	;;
esac

# to get here, we must have seen no n, x, nor (unapproved) m flags.
# <$censart is used rather than a pipe to work around a bug in the 4.2 sh
# which made it sometimes return the wrong exit status (that of anne.jones).
# execute relaynews commands on the server, for the sake of locking.
# may not use "exec" or sh will leave /tmp/sh* files from here docs in /tmp.
me="`hostname`"
server=`cat $NEWSCTL/server 2>/dev/null`
case "$server" in
"")	server="$me" ;;			# if no server file, assume this is it
esac
case "$me" in
$server)
	relaynews $relayopts -s $exclusion -d "$debug" <$censart
	status=$?
#	echo "status $? from relaynews" >>/tmp/inewsdebug # DEBUG
	;;
*)
	# send article+commands to remote shell, including clean up
	(echo "sed 's/^-//' >/tmp/irsh\$\$ <<'!'"	# remove guard
	 sed 's/^[^A-EG-Za-z0-9]/-&/' $censart	# prepend guard
	 echo !
	 cat <<!
PATH=$PATH relaynews $relayopts -s $exclusion -d "$debug" </tmp/irsh\$\$
!
	 echo 'echo status $?'
	 echo 'rm -f /tmp/irsh$$') |
		rsh $server /bin/sh >$outfile

	status=`sed -n '/^status /s///p' $outfile `
	sed '/^status /d' $outfile	# print relaynews's stdout
	;;
esac
case "$status" in
0)
	rm -f $rmlist			# far out, it worked: clean up
	if test ! -f $NEWSCTL/sys; then
		echo "$0: $NEWSCTL/sys missing; your news can't leave this machine" >&2
	fi
	trap 0				# normal exit: cleanup done
	;;
esac
exit $status				# trap 0 may cleanup, make dead.article
#) &
eval $waitcmd				# wait & get status if -W given
trap 0					# let the background run on unmolested
exit $status
================================================================================
anne.jones:
================================================================================
#! /bin/sh
# anne.jones [file...] - censor headers: munge locally-generated headers in
#  files, enforce feeble attempts at Usenet security, generate lots of silly
#  headers.
# (after the notorious ring-leader of the Ontario Film and Video Review Board
# (nee Ontario Board of Censors), Ontario's very own Mrs. Mary Whitehouse.)
# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
. ${NEWSCONFIG-/usr/lib/news/bin/config}
export NEWSCTL NEWSBIN NEWSARTS
PATH=$NEWSCTL/bin:$NEWSBIN/inject:$NEWSBIN:$NEWSPATH ; export PATH
umask $NEWSUMASK

# pass 0 - dredge up defaults
case "$trversion" in
v[67])	;;
*)	echo "$0: trversion is nonsense or missing from environment" >&2
	exit 1 ;;
esac
if test -r $NEWSCTL/mailname; then
	mailname="`tr -d ' \11' <$NEWSCTL/mailname`"
else
	mailname="`newshostname`"
	case "$mailname" in
	*.*)	;;			# not a uucp host name
	*)	mailname="$mailname.uucp" ;;	# probably a uucp host name
	esac
fi
# badsites="pucc.bitnet!"		# tailor, syntax is "host1!host2!...host3!"
host="$mailname"

# dig up user's name (a simple task, you'd think, but you'd be wrong)
case "$LOGNAME" in
"")
	# "who am i" on many Unixes does "ttyname(0)" and "getpwuid(getuid())"
	# if that fails - it can be confused by empty utmp entries (per jerqs);
	# "who am i </dev/null" yields your userid, not your login name.
	# "tty" does "ttyname(0)"; also fallible.
	# So, emulate a slightly-modified V7 getlogin(3) (actually ttyslot(3)):
	# look for tty on /dev/tty, stdin, stdout, stderr (actually via ttyname(3)).
	for fd in 3 0 1 2			# 3 is /dev/tty on V8
	do
		if test -t $fd; then
			case "$USER" in
			"")	USER="`who am i <&$fd |	\
				 sed -e 's/[	 ].*//' -e '/!/s/^.*!//' `" ;;
			esac
		fi
	done
	case "$USER" in		# last resort: use userid
	"")	USER="`who am i </dev/null |	\
		 sed -e 's/[	 ].*//' -e '/!/s/^.*!//' `" ;;
	esac
	;;
*)	USER="$LOGNAME" ;;
esac
case "$NAME" in
"")
	if test -s $HOME/.name; then
		NAME=`cat $HOME/.name`
	else
		#daemon:No login:0:0:Daemon:/usr/spool:
		#NAME=`(grep "^$USER:" /etc/passwd || ypmatch "$USER" passwd) |	\
		#	sed 's/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:]*\).*$/\1/'  `
		NAME=`(grep "^$USER:" /etc/passwd || ypmatch "$USER" passwd)`
		NAME="`echo $NAME |	\
			sed 	-e 's/^[^:]*:[^:]*:[^:]*:[^:]*://' \
				-e 's/:.*//'`"
		# tailor: for BTL RJE format, add
		#	| sed -e 's/^[^-]*- *//' -e 's/ *(.*$//'
		# otherwise for Berkeley format, use this
		# (courtesy Rayan Zachariassen):
		case "$NAME" in
		*'&'*)
			# generate Capitalised login name
			NM=`echo "$USER" | sed -e 's/^\(.\)\(.*\)/\1:\2/'`
			NM1=`expr "$NM" : '\(.\):.*' |	\
				case "$trversion" in	\
				v7)	tr a-z A-Z ;;	\
				v6)	tr '[a-z]' '[A-Z]' ;;	\
				esac	\
				`
			NMR=`expr "$NM" : '.:\(.*\)'`
			CAPNM="$NM1$NMR"
			# turn & into Capitalised login name
			NAME=`echo "$NAME" | sed "s:&:$CAPNM:"`
			;;
		esac
	fi
	;;
esac
case "$NAME" in
"")	fullname="" ;;		# no full name, leave it off
*)	fullname=" ($NAME)" ;;
esac
reallyfrom="$USER@$host$fullname"
FROM="$reallyfrom"

# generate a few defaults.
# RFC 1036 requests a GMT Date:, despite it being hard to read.
# Compensate for V6 Uglix date (no -u) tarted up with all that TZ goo.
#date="`	
#	set ''\`TZ=GMT0 date\`	# give TZ to see if (Uglix) date responds
#	case \"$5\" in
#	GMT)	echo $* ;;	# Uglix date or V7 date with GMT local time
#	*)	date -u ;;	# must be V7 date command, it ignored TZ
#	esac
#`"				# for defdate, defmsgid

date="`date -u`"		# Coherent

case "$ORGANIZATION" in
"")	deforg="`sed 1q $NEWSCTL/organi[sz]ation`" ;;	# look in a file
*)	deforg="$ORGANIZATION" ;;	# look in environment
esac

# give defaults and headers to awk
defpath="$badsites$USER" 
deffrom="$FROM" 
deforg="$deforg" 
#defdate="` set $date; echo $1, $3 $2 \` echo $6 | sed 's/^..//' \` $4 $5`" 
defdate="`set $date; echo $1, $3 $2 $5 $4 $6`"
#defdate="$date"	# Coherent
#defdate="`date -u`"	# Coherent
defmsgid="<`/etc/ATclock`@$host>"	# Coherent
# echo $defmsgid >$HOME/k.lis
cat > /tmp/defhdrs.awk.$$ << _EOF_
BEGIN 	{ 
	defpath="$defpath"
	deffrom="$deffrom"
	deforg="$deforg"
	defdate="$defdate"
	defmsgid="$defmsgid"
	}
_EOF_
cat $NEWSBIN/inject/defhdrs.awk >> /tmp/defhdrs.awk.$$

# strip invisible chars, a la B news; turn tabs to spaces (RFC1036)
case "$trversion" in
v7)	TR="tr -d  '\1-\7\13\15-\37'" ;;
v6)	TR="tr -d '[\1-\7]\13[\15-\37]'" ;;
esac 
cat | $TR | sed 's/:	/: /' | awk -f /tmp/defhdrs.awk.$$ -
================================================================================
defhdrs.awk:
================================================================================
# defhdrs.awk
# pass 1 - note presence | absence of certain headers
# a header keyword: remember it and its value
/:/ {
	hdrval[$1] = $0
	keyword=$1
	next
}
# a continuation: concatenate this line to the value
	{ hdrval[keyword] = hdrval[keyword] "\n" $0 }

END {
	# pass 2 - cogitate & omit & emit headers
	emptyhdrre = "^[^\t ]*:[\t ]*$"
	subjname = "Subject:"
	ctlname = "Control:"
	ngname = "Newsgroups:"
	msgidname = "Message-ID:"
	typoname =  "Message-Id:"
	pathname = "Path:"
	datename = "Date:"
	fromname = "From:"
	orgname = "Organization:"
	distrname = "Distribution:"
	sendername = "Sender:"

	# nullify headers with empty contents
	for (i in hdrval)
		if (hdrval[i] ~ /^[^\t ]*:[\t ]*$/)
			hdrval[i] = ""

	# fill in missing headers
	if (hdrval[typoname] != "") {	# spelling hack
		hdrval[msgidname] = hdrval[typoname]
		hdrval[typoname] = ""
		# fix spelling: Message-Id: -> Message-ID:
		nf = split(hdrval[msgidname], fields);	# bust up
		fields[1] = msgidname;		# fix spelling
		hdrval[msgidname] = fields[1];	# reassemble...
		for (i = 2; i <= nf; i++)
			hdrval[msgidname] = hdrval[msgidname] " " fields[i]
	}
	if (hdrval[pathname] == "")
		hdrval[pathname] = pathname " " defpath
	if (hdrval[msgidname] == "")
		hdrval[msgidname] = msgidname " " defmsgid
	if (hdrval[datename] == "")
		hdrval[datename] = datename " " defdate
	if (hdrval[orgname] == "")
		hdrval[orgname] = orgname " " deforg
	if (hdrval[fromname] == "")
		hdrval[fromname] = fromname " " deffrom
	else if (hdrval[sendername] == "")
		hdrval[sendername] = sendername " " deffrom

	# replace user's headers (if any) [this is not currently done]

	# snuff some headers
	distworld = distrname " world"
	if (hdrval[distrname] == distworld)
		hdrval[distrname] = ""

	# the vile cmsg hack, for the sake of the news readers *only*
	if (hdrval[ctlname] == "" && substr(hdrval[subjname], 1, 14) == "Subject: cmsg ")
		hdrval[ctlname] = ctlname " " substr(hdrval[subjname], 15)

	# warn if no Newsgroups:
	if (hdrval[ngname] == "")
		print "no newsgroups header!" | "cat >&2"

	# field the all.all.ctl hack, for the sake of the backward only:
	# clone Subject: to make Control:
	if (hdrval[ctlname] == "" && hdrval[ngname] ~ /\.ctl(,|$)/)
		hdrval[ctlname] = ctlname " " substr(hdrval[subjname], 8)

	# reorder & emit headers

	# favour Control: & Newsgroups: for future benefit of rnews
	if (hdrval[ctlname] != "") {
		print hdrval[ctlname]
		hdrval[ctlname] = ""	# no Control: to print now
	}
	if (hdrval[ngname] != "") {
		print hdrval[ngname]
		hdrval[ngname] = ""	# no Newsgroups: to print now
	}

	# B inews kludgery: print Path: before From: to avoid confusing it
	if (hdrval[pathname] != "") {
		print hdrval[pathname]
		hdrval[pathname] = ""	# no Path: to print now
	}
	if (hdrval[fromname] != "") {
		print hdrval[fromname]
		hdrval[fromname] = ""	# no From: to print now
	}

	# have pity on readers: put Subject: next
	if (hdrval[subjname] != "") {
		print hdrval[subjname]
		hdrval[subjname] = ""	# no Subject: to print now
	}

	# have pity on readers: put Message-ID: next
	if (hdrval[msgidname] != "") {
		print hdrval[msgidname]
		hdrval[msgidname] = ""	# no Subject: to print now
	}

	# print misc. non-empty headers in random order
	for (i in hdrval)
		if (hdrval[i] != "" && hdrval[i] !~ /^[^\t ]*:[\t ]*$/)
			print hdrval[i]
}
================================================================================
-- 
Keith Lovatt                 	|	Scarborough, Ontario, Canada
r-node.gts.org!klovatt@klnet	|	Phone: +1 416 293 0292
doe.utoronto.ca!klovatt@klnet	|    "You can never find a Lugroid
klovatt@terranet.cts.com	|	when you really need one"
Newsgroups: comp.os.coherent