[comp.sources.unix] v12i034: C News alpha release, Part09/14

rsalz@uunet.UU.NET (Rich Salz) (10/22/87)

Submitted-by: utzoo!henry (Henry Spencer)
Posting-number: Volume 12, Issue 34
Archive-name: cnews/part09



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 9 (of 14)."
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'newsbin.proto/maint/arbitron' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'newsbin.proto/maint/arbitron'\"
else
echo shar: Extracting \"'newsbin.proto/maint/arbitron'\" \(7860 characters\)
sed "s/^X//" >'newsbin.proto/maint/arbitron' <<'END_OF_FILE'
X#! /bin/sh
X# @(#)arbitron	2.4.2	06/05/87
X# arbitron -- this program produces rating sweeps for USENET.
X#
X# Usage: arbitron
X#
X# To use this program, edit the "configuration" section below so that the
X# information is correct for your site, and then run it. It will produce a
X# readership survey for your machine and mail that survey to decwrl, with
X# a cc to you.
X#
X# To participate in the international monthly ratings sweeps, 
X# run "arbitron" every month. I will run the statistics program on the last
X# day of each month; it will include any report that has reached it by that
X# time. To make sure your site's data is included, run the survey program no
X# later than the 20th day of each month.
X#
X# Brian Reid, DEC Western Research Lab, reid@decwrl
X# Updated and bugfixed by 
X#	Spencer Thomas, U.of Utah
X#	Geoff Kuenning, SAH Consulting
X# Updated to work with 2.10.1 and older news systems by
X#	Lindsay Cleveland, AT&T Technologies/Bell Labs
X# Made to work with 16-bit address spaces by
X#	Andy Walker, Maths Dept., University of Nottingham, UK
X# Nagging Bourne shell bug fixed by
X#	Tom Donahue, Rabbit Software Corp
X#
X# Note that the results of this program are dependent on the rate at which
X# you expire news.  If you are a small site that expires news rapidly, the
X# results may indicate fewer active readers than you actually have.
X#
X###########################################################################
X# Configuration information. Edit this section to reflect your site data. #
XTMPDIR=/tmp
XNEWS=/usr/lib/news
XSPOOL=/usr/spool/news
X
X# Make a crude stab at determining the system type. If your installation has
X# only one type of system, you can edit out the "if" statement and just turn
X# this into an assignment statement of the correct value.
Xif [ -d /usr/ucb ]
Xthen
X    STYPE="bsd"
Xelse
X    STYPE="usg"
Xfi
X
X# Range of /etc/passwd UID's that represent actual people (rather than
X# maintenance accounts or daemons or whatever)
XlowUID=5
XhighUID=9999
X
X# If you aren't running a distributed news system (nntpd & rrn, usually),
X# leave NEWSHOST blank. Else set it to the name of the host from which you
X# can rcp a copy of the active file.
XNEWSHOST=
X
X# uucp path: {ihnp4, decvax, ucbvax}!decwrl!netsurvey
Xsummarypath="netsurvey@decwrl.dec.com $USER"
X#summarypath="ihnp4!decwrl!netsurvey $USER"
X
X# We need to find the uucp name of your host. If this code doesn't work,
X# then just put it in literally like this:
X#	hostname="ihnp4"
X
Xcase $STYPE in
X	bsd) cmd='hostname || uuname -l';;
X	sysv)cmd='uname -n || uuname -l || hostname';;
X	*)   cmd='uuname -l';;
Xesac;
X
Xhostname=`sh -c "$cmd" 2>&-`
X
XPATH=$NEWS:/usr/ucb:/usr/bin:/bin
X############################################################################
Xexport PATH
X# ---------------------------------------------------------------------------
Xtrap "rm -f $TMPDIR/arb.*.$$; exit" 0 1 2 3 15
Xset `date`
Xdat="$2$6"
Xdestination="${MAILER-mail} $summarypath"
X
X################################
X# Here are several expressions, each of which figures out approximately how
X# many people use this machine. Comment out all but 1 of them; pick the one
X# you like best. Initially the most universal but least reliable of them is
X# uncommented.
X# # ###### Scheme #1: fast but usually returns too big a number
Xnusers=`awk -F: "BEGIN {N=0}\\$3>=$lowUID && \\$3<=$highUID{N=N+1}END{print N}" </etc/passwd`
X
X# # ###### Scheme #2 (works with BSD systems)
X#nusers=`last | sort -u +0 -1 | wc -l`
X
X# # ###### Scheme #3 (works with USG systems)
X#nusers=`who /etc/wtmp | sort -u +0 -1 | wc -l`
X
X################################
X#
X# Set up awk scripts;  these are too large to pass as arguments on most
X# systems.
X#
X# This awk script generates the actual output report.
X# We use 'sed' to substitute in the shell variables to save ourselves
X# endless hassle trying to find quoting/backslashing problems.
X#
X# The input to this script consists of two types of lines (pre-sorted):
X#
X#	(1) Active-file lines.  These have four fields:  newsgroup name,
X#	    first existing article, last article number, 'y' or 'n'
X#	    to allow/disallow posting.
X#			mod.mac 00001 00001 y
X#
X#	(2) .newsrc-derived lines.  These have three fields:  the newsgroup
X#	    name, the user name and the articles-read information.  The latter
X#	    can be arbitrarily complex.  It can also be arbitrarily long;
X#	    this can potentially break either awk or sed, in which
X#	    case the script will not work.
X#			mod.map joe 1-199
X#
X#	The script uses the type 1 lines to define the newsgroups
X#	and their active article ranges.  The .newsrc (type 2) lines are
X#	then used to deduce which users are reading that group (a group
X#	is being read if the last article seen is in that group's active
X#	article range).
X#
Xsed "/^#/d
X     s/NUSERS/$nusers/g
X     s/HOSTNAME/$hostname/g
X     s/DATE/$dat/g" > $TMPDIR/arb.fmt.$$ << 'DOG'
X# makereport -- utility for "arbitron". Early versions were copied from a
X# similar script distributed with "subscribers.sh" by Blonder, McCreery, and
X# Herron.
X#
X	BEGIN	{ rdrcount = 0 ; reader = "" ; grpcount = 0 ; realusers = 0}
X#
X# Active file line:  dispose of previous group (if any), record group, and
X# record first and last article numbers.  Set group's reader count to none.
X	NF == 4 { if (grpname != "") {
X			printf("%d %s\n",grpcount, grpname)
X		  }
X		  grpname = $1
X		  grpfirst = $3
X		  grplast = $2
X		  grpcount = 0
X		}
X#
X# .newsrc line.  Break out the final number, which is the last article that
X# has actually been read.  This is a pretty good indicator of the person's
X# true interest in the group.  If 'lastread' for the group is a current
X# (unexpired) article, record a reader for that group.  Finally, record
X# the user as a "real" user of the news system.
X#
X	NF == 3 { if ($1 != grpname) next;
X		  n1 = split($3, n2, "-")
X		  n3 = split(n2[n1], n4, ",")
X		  lastread = n4[n3]
X	if ((grpfirst != grplast) && (lastread >= grpfirst) && (lastread <= grplast)) {
X			grpcount++
X			if (realuser[$2] != 1) {
X			    realuser[$2] = 1
X			    realusers++
X			}
X		  }
X		}
X#
X# End of file.  Print the report in 2 columns.
X	END	{ printf("9999 Host\t\t%s\n","HOSTNAME")
X		  printf("9998 Users\t\t%d\n",NUSERS)
X		  printf("9997 NetReaders\t%d\n",realusers)
X		  printf("9996 ReportDate\t%s\n","DATE")
X		  printf("9995 SystemType\tnews-arbitron-2.4\n")
X# For reorganized network, report a group even if nobody reads it. This will
X# help us keep track of where the groups propagate.
X		  printf("%d %s\n",grpcount, grpname)
X		}
XDOG
X
Xcat >$TMPDIR/arb.pwd.$$ <<'MOUSE'
XBEGIN	{ seen["/"]=1; seen[""] = 1; }
X	{ if (seen[$6]!=1) {
X		printf("if [ -r %s/.newsrc ] ; then ", $6)
X		printf("sed -n '/: [0-9]/s/:/ %s/p' <%s/.newsrc; fi\n",$1,$6)
X		seen[$6]=1;
X	  }
X}
XMOUSE
X
X# First, make sure we have an active file
Xif [ -z "$NEWSHOST" ]
Xthen ACTIVE=$NEWS/active
Xelse ACTIVE=/tmp/arb.active.$$
X     rcp $NEWSHOST:$NEWS/active $ACTIVE
Xfi
X
Xif [ ! -s $ACTIVE ]
Xthen
X    echo arbitron: ACTIVE file missing or empty. Cannot continue.
X    exit 1
Xfi
X
X# Next, get the list of .newsrc files with duplicates and unreadable files
X# removed.
Xawk -F: -f $TMPDIR/arb.pwd.$$ </etc/passwd | sh >$TMPDIR/arb.tmp.$$
X
X# Check to make sure that we found some
Xif [ -s $TMPDIR/arb.tmp.$$ ]
Xthen # See if "active" file has 4 fields or only two (pre-2.10.2)
X     set `sed 1q < $ACTIVE`
X     if [ $# -eq 2 ]
X     then egrep  '^[a-z]*\.' $ACTIVE |
X	  while read group last
X	  do dir=`echo "$group" | sed 's;\.;/;g'`
X	     first=`ls $SPOOL/$dir | grep '^[0-9]*' | sort -n | sed 1q`
X	     case $STYPE in
X		usg) echo "$group $last ${first:-$last} X";;
X		  *) echo "$group $last ${first-$last} X"
X	     esac
X	  done
X     else egrep '^[a-z]*\.' $ACTIVE
X     fi |
X     sort - $TMPDIR/arb.tmp.$$ |
X     awk -f $TMPDIR/arb.fmt.$$ |
X     sort -nr |
X     sed '/^$/d
X	  s/^999[0-9] //' |
X     $destination
Xelse echo Unable to find any readable .newsrc files 2>&1
X     exit 1
Xfi
END_OF_FILE
if test 7860 -ne `wc -c <'newsbin.proto/maint/arbitron'`; then
    echo shar: \"'newsbin.proto/maint/arbitron'\" unpacked with wrong size!
fi
# end of 'newsbin.proto/maint/arbitron'
fi
if test -f 'rna/man/readnews.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rna/man/readnews.1'\"
else
echo shar: Extracting \"'rna/man/readnews.1'\" \(7338 characters\)
sed "s/^X//" >'rna/man/readnews.1' <<'END_OF_FILE'
X.TH READNEWS 1
X.SH NAME
Xnews, readnews \- read news articles
X.SH SYNOPSIS
X.B readnews
X.RB [ -n
Xnewsgroups]
X.RB [ -i ]
X.RB [ -clpC ]
X.RB [ -s [ -+?
X.RI [ group ]]]
X.RB [ -u
Xmessageid]
X.SH DESCRIPTION
X.I Readnews
Xwithout arguments enters command mode,
Xwhich allows printing of unread articles.
XThis is the normal way of using
X.IR readnews .
X.P
X.I Readnews
Xmaintains a
X.I .newsrc
Xfile in the user's home directory that specifies
Xall news articles already read.
XIt is updated at the end of each reading session.
X.P
XSome useful functions are available which don't use command mode.
XThe flags for these are:
X.TP
X.B -c
XCheck if there is news, and if so print `You have news.'.
XA line `readnews -c' is usually placed in the system
X.I .profile
X.RB (  /etc/profile ).
X.TP
X.B -C
XCheck if there is news, and print the groups and number of
Xarticles in each group to be read.
X.TP
X.B -l
XList the titles of available news articles.
X.TP
X.B -p
XPrint all articles on standard output,
Xand update
X.IR newsrc .
X.TP
X.B -s
XPrint the newsgroup subscription list.
X.TP
X.BI -s+ " group"
XAdd
X.I group
Xto the subscription list.
X.TP
X.BI -s- " group"
XSubtract
X.I group
Xfrom the subscription list.
X.TP
X.B -s?
XList currently active newsgroups.
X.P
XThe remaining flags determine article selection,
Xand may also appear in the
X.I .newsrc
Xfile.
XOptions may be specified in the
X.I .newsrc
Xfile by entering lines prefixed with the word `options',
Xfollowed by the options arguments.
XThis is most useful with the
X.B -n
Xflag, specifying the usual groups one wishes to subscribe to.
X.TP
X\fB-n \fInewsgroups\fR
XSelect all articles belonging to
X.IR newsgroups .
X.I newsgroups
Xis a comma separated list of newsgroup names.
XThe character `!' may be used to exclude certain groups,
Xand the word `all' can be used to match any group.
Xe.g. `-n all,!net.jokes'
X.TP
X.B -i
XIgnore
X.I .newsrc
Xfile. It is not read or updated.
XThis allows selection of articles that have already been read.
X.TP
X\fB-u \fImessageid\fR
XUnsubscribe to followup articles referring to
X.IR messageid .
X(This flag is usually only placed in the
X.I .newsrc
Xfile as a result of the `u' command.)
X.SH COMMANDS
XThis section details the commands available when
X.I readnews
Xis in command mode (no
X.B -clpsC
Xarguments).
XThe simplest way of using this mode, is to enter RETURN after every
Xprompt.
XThis will present to the user, a short heading for an article, then a prompt.
XTyping RETURN again will print the article body.
XTyping RETURN yet again will print the next heading, and so on.
XIf having read the heading, you don't wish to read the article, you may
Xtype `n' (or `+' or ';') which will take you directly to the next heading.
X.P
X.P
XAn article is treated as having been read, if either you have seen
Xthe article body, or typed `n' to skip over it.
X.P
XA number of commands operate on the `current' article.
XThis is defined as the article whose header you have most recently seen.
X.P
XThe commands to read news are:
X.TP
X.B RETURN
XEither print the current article,
Xor go to the next article and print its header.
X.TP
X\fBn\fR or \fB+\fR or \fB;\fR
XGo to the next article and print its header.
X.TP
X.B .
XPrint the current article.
X.TP
X.B -
XGo back to the previous article. This is a toggle, typing it
Xtwice returns you to the original article.
X.TP
X.I number
XGo to the article
X.I number
Xin the current newsgroup.
XLike the `-' command,
Xyou always return to the original article
Xafter reading the selected article.
X.TP
X\fBs \fR[\fIfile\fR]
XSave the current article, either in the specified file, or
Xin
X.BR $HOME/articles .
X.TP
X.B h
XPrint the current header (slightly more verbose than normal header).
X.TP
X.B H
XPrint the current header in full (very verbose).
X.TP
X\fBN \fR[\fInewsgroup\fR]
XGo to the next newsgroup, or to the specified newsgroup.
X.TP
X.B u
XUnsubscribe from all further followup articles on this topic.
X.TP
X.B U
XUnsubscribe from this newsgroup, and go to the next newsgroup.
X.TP
X\fB!\fIcommand\fB
XShell escape.
X.I Command
Xis executed.
XIf 
X.I command
Xis `!'
Xthe last escape command is executed.
X.TP
X\fBq\fR or \fBEOT\fR
XQuit.
XThe
X.I .newsrc
Xfile will be updated provided the flag
X.B -i
Xwas not specified.
X.TP
X.B x
XExit.
X.I .newsrc
Xis left unchanged (as if no articles had been read).
X.TP
X.B DEL
XAn interrupt will cause
X.I readnews
Xto terminate its current activity and return to command mode.
XAn interrupt in command mode will cause `Interrupt' to be printed,
Xand a subsequent interrupt will cause immediate exit (as in the `x' command).
X.P
XSome commands are available to send/reply or cancel news articles:
X.TP
X.B c
XCancel article. Only the author, or news administrator can do this.
X.IR postnews (1)
Xis called to do the actual cancelling.
X.TP
X.B r
XReply to sender of the current article by mail.
X.I Readnews
Xsets up the appropriate headers, and then calls
X.IR mail (1)
Xto send a reply to the sender.
X.TP
X.B f
XPost a followup to the current article.
X.I Readnews
Xsets up the appropriate headers, and then calls
X.IR postnews (1)
Xto post the followup article.
X.TP
X.B p
XPost an article on a new topic.
X.IR postnews (1)
Xis called to post the new article.
X.TP
X\fBm \fIperson\fB
XMail to
X.IR person .
X.P
XWhen replying by mail, or posting an article, the user
Xis prompted for certain headers, and then the text of the article or mail
Xitem is entered until a `.' or EOT is entered alone on a line.
XThen the article/mail is posted/mailed.
XOther commands are available:
X.TP
X\&\fB.e\fR
XEdit the message/article collected so far (see
X.IR ed (1)).
XThe 'To:' or 'cc:' fields may be changed if mailing.
XAfter editing further lines may be appended to the message.
X.TP
X\&\fB.i\fR
XInterpolate
Xthe current news article onto the end of the message.
XThe interpolated item
Xis indented by four spaces.
X.TP
X\&\fB.!\fIcmd\fR or \fB!\fIcmd\fR
XShell escape.
X.IR Cmd
Xis executed.
X.TP
X.B DEL
XCauses posting/mailing to be aborted, and the article entered so far
Xis saved in
X.B $HOME/dead.article
Xor
X.BR $HOME/dead.letter .
X.P
XIn order to permanently resubscribe to a newsgroup denied by `U',
Xor a series of followups denied by `u' it is necessary to understand
Xthe format of the
X.I .newsrc
Xfile.
XThe
X.I .newsrc
Xfile consists of two types of lines:
X.TP
Xoption lines
XThese start with the word `option' and contain the same arguments
Xas the
X.I readnews
Xcommand on the command line.
XFollowups are denied with `option -u <messageid>'.
XTo resubscribe to further followups, the correct options line must be deleted.
X.TP
Xread newsgroup lines
XThese have the format <newsgroup>`:' <number>, where
X<number> represents the last item number seen in that particular newsgroup.
XIf the newsgroup has been unsubscribed, the `:' is replaced by a `!'.
XTo resubscribe the `!' must be changed back to a `:'.
X.SH FILES
X.ta 24
X.nf
X$HOME/.newsrc	options and list of previously read articles
X%news	where the articles are kept
X/usr/lib/news/active	current newsgroups
X/usr/lib/news/help	help file
X.fi
X.SH SEE ALSO
Xpostnews(1), mail(1), ed(1), uusend(8), uurec(8).
X.SH BUGS
X.I Readnews
Xwith the
X.B -c
Xflag may say "You have news.", when the available article is a unsubscribed
Xfollowup article.
X.P
XYou may see followups, even if you have used the `u' command.
XThis is because many sites have faulty news programs, which do
Xnot follow the correct protocol, or the sender did not use the `r' command.
X.SH AUTHOR
XMichael Rourke, University of N.S.W (decvax!mulga!michaelr:elecvax)
END_OF_FILE
if test 7338 -ne `wc -c <'rna/man/readnews.1'`; then
    echo shar: \"'rna/man/readnews.1'\" unpacked with wrong size!
fi
# end of 'rna/man/readnews.1'
fi
if test -f 'rna/newsrc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rna/newsrc.c'\"
else
echo shar: Extracting \"'rna/newsrc.c'\" \(6581 characters\)
sed "s/^X//" >'rna/newsrc.c' <<'END_OF_FILE'
X/*
X * newsrc file handling
X */
X
X#include "defs.h"
X
Xstatic char nrcname[]	 = NEWSRC;
X
Xstatic char *rcname;		/* full pathname of .newsrc */
Xnewsrc *rc;			/* internal .newsrc */
Xchar *rcgrps;			/* subscription from .newsrc */
Xstatic newsrc *lastrc;		/* last newsrc struct in list */
Xstatic int rclineno;		/* current lineno in .newsrc */
Xstatic bool sortrc;		/* if we should sort on output */
X
Xstatic newsrc *findnewsrc();
X
Xreadnewsrc()
X{
X	register FILE *f;
X	static char option[] = "options";
X	char word[BUFSIZ], rest[BUFSIZ];
X	extern char *getenv();
X
X	if ((rcname = getenv("HOME")) == NULL)
X		error("No $HOME in environment.");
X	rcname = newstr3(rcname, "/", nrcname);
X	if ((f = fopen(rcname, "r")) == NULL)
X		return;
X
X	rclineno = 0;
X	while (getline(f, word, rest))
X		if (CMP(word, option) == 0)
X			dooptions(rest);
X		else
X			dorcline(word, rest);
X	(void) fclose(f);
X}
X
X/*
X * Read a line from f, put first word into w and the rest into r.
X * Discard trailing newline instead of storing it.
X * This is a poor design, as w & r are unchecked for overrun.
X */
Xstatic
Xgetline(f, w, r)
Xregister FILE *f;
Xchar *w, *r;
X{
X	register int c;
X	register char *s;
X
X	rclineno++;
X	s = w;
X	while ((c = getc(f)) != EOF && c != ' ' && c != '\t')
X		*s++ = c;			/* stash first word */
X	*s = '\0';
X
X	if (c != EOF) {
X		s = r;
X		while ((c = getc(f)) != EOF && c != '\n')
X			*s++ = c;		/* stash the rest */
X		*s = '\0';
X	}
X
X	if (c != '\n' && c != EOF)
X		error("Bad format: %s line %d: %s", rcname, rclineno, w);
X
X	return c != EOF;
X}
X
X/*
X * Parse s into words and simulate command line arguments with them.
X */
Xstatic
Xdooptions(s)
Xchar *s;
X{
X	register char *cp;
X	register int argc;
X	register char **argv;
X
X	cp = s;
X	while (isspace(*cp))
X		cp++;
X	if (!*cp)
X		return;
X
X	argc = 1;
X	argv = (char **) myalloc(sizeof(char *));
X	argv[argc - 1] = cp;
X	while (*cp && (cp = strpbrk(cp, " \t")) != NULL) {
X		while (*cp == ' ' || *cp == '\t')
X			*cp++ = '\0';
X		if (*cp) {
X			argc++;
X			argv = (char **) myrealloc((char *) argv,
X				argc * (int)sizeof(char *));
X			argv[argc - 1] = cp;
X		}
X	}
X	if (options(argc, argv, false))
X		error("Bad options: %s line %d: %s", rcname, rclineno, s);
X	free((char *) argv);
X}
X
X/*
X * Parse w & r together as a .newsrc newsgroup line.
X */
Xstatic
Xdorcline(w, r)
Xchar *w, *r;
X{
X	register char lastw;
X	register int len;
X	register newsrc	*np;
X
X	len = strlen(w);
X	lastw = w[len - 1];			/* save presumed colon or bang */
X	w[len - 1] = '\0';			/* nuke presumed colon */
X	while (*r == ' ' || *r == '\t')
X		r++;				/* skip extra whitespace */
X
X	/* kludges, hacks, etc. for compatibility with other readers */
X	if (strncmp(r, "1-", sizeof "1-"-1) == 0)
X		r += sizeof "1-"-1;		/* skip usual `1-' */
X	if (*r == '\0')				/* rn's: `news.trash: ' */
X		r = "0";			/* fake a zero */
X
X	if (lastw != ':' && lastw != NEGCHAR || !isdigit(*r))
X		error("Bad line: %s line %d: %s", rcname, rclineno, w);
X
X	np = NEW(newsrc);
X	np->n_subscribe = (bool) (lastw == ':');	/* colon or bang? */
X	np->n_next = NIL(newsrc);
X	np->n_last = atoi(r);			/* stash first number only */
X	np->n_name = newstr(w);			/* stash n.g. name */
X
X	if (rc == 0)
X		rc = np;
X	else
X		lastrc->n_next = np;
X	lastrc = np;
X}
X
X/*
X * for every group in active list, which belongs to the specified subscription
X * list, and has messages to be read, call func
X * if no mention in newsrc file, make new entry
X */
Xapply(alist, group, func, dolast)
Xactive *alist;
Xchar *group;
Xapplycom (*func)();
Xbool dolast;
X{
X	register active *ap;
X	register newsrc *np;
X	register applycom act;
X	register bool donesome;
X
X	donesome = false;
X	do {
X		act = stop;
X		for (ap = alist; ap; ap = ap->a_next) {
X			if (ap->a_seq == 0 || ap->a_low > ap->a_seq)
X				continue;	/* empty group */
X			if (!ngmatch(ap->a_name, group))
X				continue;
X			if ((np = findnewsrc(ap->a_name)) == NIL(newsrc)) {
X				np = NEW(newsrc);
X				np->n_name = newstr(ap->a_name);
X				np->n_next = NIL(newsrc);
X				np->n_last = 0;
X				np->n_subscribe = true;
X				if (!rc)
X					rc = np;
X				else
X					lastrc->n_next = np;
X				lastrc = np;
X			}
X			if (!np->n_subscribe)
X				continue;
X			/*
X			 * if we haven't read any news for a while (or at all),
X			 * or somehow seq got smaller (active corrupted?),
X			 * set last read to oldest available article
X			 */
X			if (ap->a_low - 1 > np->n_last || ap->a_seq < np->n_last)
X				np->n_last = ap->a_low - 1;
X			while (np->n_last < ap->a_seq) {
X				donesome = true;
X				switch (act = (*func)(ap, np, false, false)) {
X				case stop:		
X					return;
X				case next:		
X					continue;
X				case nextgroup:		
X					break;
X				case searchgroup:	
X					break;
X				}
X				break;
X			}				/* while */
X			if (act == searchgroup)
X				break;
X		}					/* for */
X		if (act != searchgroup && dolast && donesome)
X			act = (*func)(NIL(active), NIL(newsrc), true, false);
X	} while (act == searchgroup);
X}
X
X/*
X * find if a newrc entry exists,
X * taking advantange of the fact that requests should be
X * in the same order
X *
X * detect when the newsrc gets out of order
X * so it can be sorted at the end of the session
X */
Xstatic newsrc *
Xfindnewsrc(name)
Xregister char *name;
X{
X	register newsrc *np, *start;
X	register bool found;
X	static newsrc *nextp;
X
X	if (!rc)
X		return NIL(newsrc);
X
X	found = false;
X	np = nextp ? nextp : rc;
X	nextp = start = np;
X	do {
X		if (CMP(np->n_name, name) == 0) {
X			found = true;
X			break;
X		}
X		np = np->n_next;
X		if (!np)
X			np = rc;
X	} while (np != nextp);
X
X	if (!found)
X		return NIL(newsrc);
X	nextp = np->n_next;
X	if (np != start)
X		sortrc = true;
X	return np;
X}
X
X/*
X * rewrite the newsrc file
X */
Xwritenewsrc(alist)
Xactive *alist;
X{
X	register FILE *f;
X	register active	*ap;
X	register newsrc	*np;
X	register int i;
X	extern char **uflag;
X	extern int usize;
X
X	if (!rc && !uflag && (!rcgrps || !*rcgrps))
X		return;
X
X	signal(SIGINT, SIG_IGN);
X	signal(SIGQUIT, SIG_IGN);
X
X	f = fopenf(rcname, "w");
X	if (rcgrps && *rcgrps)
X		(void) fprintf(f, "options -n %s\n", rcgrps);
X	if (uflag) {
X		scanhist(uflag, usize);		/* forget id's not in history */
X		for (i = 0; i < usize; i++)	/* print whats left */
X			if (uflag[i])
X				(void) fprintf(f, "options -u %s\n", uflag[i]);
X	}
X	if (sortrc) {
X		/*
X		 * sort newsrc so next time we use it,
X		 * history/newsrc comparisons will be faster
X		 */
X		for (ap = alist; ap; ap = ap->a_next)
X			if (np = findnewsrc(ap->a_name))
X				writengline(f, np);
X	} else
X		for (np = rc; np; np = np->n_next)
X			writengline(f, np);
X	(void) fclose(f);
X}
X
Xstatic
Xwritengline(f, np)		/* write .newsrc n.g. line in normal form on f */
Xregister newsrc *np;
X{
X	(void) fprintf(f, "%s%c 1-%d\n", np->n_name,
X		(np->n_subscribe? ':': NEGCHAR), np->n_last);
X}
END_OF_FILE
if test 6581 -ne `wc -c <'rna/newsrc.c'`; then
    echo shar: \"'rna/newsrc.c'\" unpacked with wrong size!
fi
# end of 'rna/newsrc.c'
fi
if test -f 'rnews/fileart.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rnews/fileart.c'\"
else
echo shar: Extracting \"'rnews/fileart.c'\" \(6901 characters\)
sed "s/^X//" >'rnews/fileart.c' <<'END_OF_FILE'
X/*
X * fileart - file an article, given its temp file name and its headers
X * TODO: change in junk policy, suggested by gnu (has this been done already?):
X *	3 classes of ng: wanted, not wanted (!ng in sys -> ignore it),
X *		don't know it (not in active -> change to junk).
X * TODO: clean up packaging of fileart: push the 3-arg open caller into vers/*?
X */
X
X#include <stdio.h>
X#include <errno.h>
X#include <sys/types.h>
X
X#include "fcntl.h"			/* try to define O_* and F_* */
X
X#include "news.h"
X#include "newspaths.h"
X#include "active.h"
X#include "headers.h"
X#include "system.h"
X
X#ifndef F_OK
X#define F_OK 0
X#endif
X
X#define JUNK "junk"			/* name of lost+found ng. */
X#define CONTROL "control"
X
Xstatic long artnum;			/* asgnartnum sets artnum */
Xstatic int goodngs;			/* asgnartnum reads goodngs */
X
Xstatic int debug = NO;
X
Xfiledebug(state)		/* set debugging state */
Xint state;
X{
X	debug = state;
X}
X
X/*
X * TODO: new proposed junk policy:
X * delay until the end, then file *once* in junk if any ngs
X * were not in active but were in sys file subscription list.
X */
X/*
X * File the article in "*tfp" in the spool directory.
X * hdrs are the associated headers.  fileart fills in hdrs->h_files too.
X *
X * If openfirst is true, fill in h_tmpf with the name of the first link,
X * fopen it (into *tfp), and make any remaining links.
X * openfirst really means "Newsgroups:" has been seen.
X * Generates Xref: header if needed.
X */
Xint
Xfileart(hdrs, tfp, openfirst)
Xregister struct headers *hdrs;
XFILE **tfp;
Xint openfirst;
X{
X	register char *comma;
X	int status = ST_OKAY;
X	char *ng;			/* point at current newsgroup */
X	char artnumstr[MAXCOMP];	/* article number in ascii */
X	char group[MAXFILE];		/* a group */
X
X	if (hdrs->h_filed)
X		return status;
X	artnum = 0;
X	goodngs = 0;
X	/*
X	 * Store in spooldir.
X	 * Link temp file to spooldir/ng/article-number for each ng.
X	 */
X	for (ng = hdrs->h_ngs; ng != NULL; ng = comma) {
X		int lstatus = ST_OKAY;
X
X		comma = index(ng, NGSEP);
X		if (comma != NULL)
X			*comma = '\0';		/* restored below */
X		if (hdrs->h_ctlcmd != NULL)	/* ctl. msg.s go in CONTROL */
X			(void) strcpy(group, CONTROL);
X		else
X			(void) strcpy(group, ng); /* copy out newsgroup name */
X		if (comma != NULL)
X			*comma++ = NGSEP;	/* step past comma */
X
X		lstatus |= asgnartnum(hdrs, tfp, openfirst, group, artnumstr);
X		/*
X		 * No such group in active or link failed but our
X		 * subscription list permits this group,
X		 * so file it under "junk", if it exists.
X		 */
X		if ((artnum < 1 || lstatus != ST_OKAY) &&
X		    ngmatch(oursys()->sy_ngs, group)) {
X			(void) strcpy(group, JUNK);
X			lstatus = asgnartnum(hdrs, tfp, openfirst,
X				group, artnumstr);
X			/*
X			 * You could set ST_DROPPED here if you think
X			 * one might accidentally not have "junk"
X			 * in active.  I tend to think the absence
X			 * of "junk" would be deliberate, to prevent
X			 * filing of junk articles.
X			 */
X			if (artnum < 1 || lstatus != ST_OKAY)
X				lstatus |= ST_NUKED;	/* no junk ng */
X		}
X		if (artnum >= 1 && lstatus == ST_OKAY) {
X			/*
X			 * Article # was assigned and the link succeeded.
X			 * Update hdrs->h_files list for history.
X			 */
X			hdrs->h_filed = YES;			/* make a note */
X			if (hdrs->h_files[0] != '\0')
X				(void) strcat(hdrs->h_files, " ");
X			(void) strcat(hdrs->h_files, group);	/* normal case */
X			(void) strcat(hdrs->h_files, SFNDELIM);
X			(void) strcat(hdrs->h_files, artnumstr);
X			++goodngs;
X		}
X		status |= lstatus & ~ST_NUKED;
X	}
X	/*
X	 * No good ngs if article was accepted by our subscription list,
X	 * yet none of the groups are in our active file
X	 * (e.g. net.rec.drugs,net.chew-the-fat) & no junk group exists.
X	 *
X	 * TODO: could call asgnartnum here instead.  Hmmm...
X	 * Current policy makes a junk link for each bad group,
X	 * this would instead make one junk link, no matter how
X	 * many bad groups, and only if all are bad.
X	 * But we want to know *why* there are no good ngs; it could
X	 * be because they are all denied by our subscription list.
X	 * Again, could set ST_DROPPED here (no junk group).
X	 */
X	if (goodngs == 0)
X		status |= ST_NUKED;		/* TODO: complain: no good ngs? */
X	else if (goodngs > 1 && *tfp != NULL)	/* cross-posted? */
X		status |= emitxref(*tfp, hdrs);
X	return status;
X}
X
X/*
X * Assign a permanent name and article number to the temporary name hdrs->h_tmpf
X * in newsgroup "ng" & store the ascii form of the article number into "artnumstr",
X * returning the article number in "artnum".
X *
X * If openfirst is true and goodngs is zero, set inname to artname,
X * fopen artname and store the result through tfp.
X */
Xstatic int
Xasgnartnum(hdrs, tfp, openfirst, ng, artnumstr)
Xstruct headers *hdrs;
XFILE **tfp;
Xint openfirst;
Xchar *ng;
Xchar *artnumstr;
X{
X	register int status = ST_OKAY;
X	char *inname = hdrs->h_tmpf;
X	char slashng[MAXFILE];			/* a group, slashed */
X	extern int errno;
X
X#define openorlink(inname, artname, tfp, openfirst, goodngs) \
X    (openfirst && goodngs == 0? openlink(inname, artname, tfp): \
X    link(inname, artname) == 0)
X
X	(void) strcpy(slashng, ng);
X	mkfilenm(slashng);
X	while ((artnum = nxtartnum(ng)) >= 1) {
X		char artname[MAXFILE];		/* article file name */
X
X		(void) strcpy(artname, slashng);
X		(void) strcat(artname, SFNDELIM);
X		(void) sprintf(artnumstr, "%ld", artnum);
X		(void) strcat(artname, artnumstr);
X
X		/*
X		 * we changed directory to spooldir in main(),
X		 * so artname is relative to spooldir,
X		 * therefore artname can be used as is.
X		 */
X#ifdef notdef
X		(void) strcpy(artname, spoolfile(artname));
X#endif
X
X		if (debug && !(openfirst && goodngs == 0))
X			(void) fprintf(stderr, "about to link %s to %s... ",
X				inname, artname);
X		if (openorlink(inname, artname, tfp, openfirst, goodngs)) {
X			if (debug)
X				(void) fprintf(stderr, "success!\n");
X			break;		/* link succeeded */
X		} else {
X			/*
X			 * Link failed.  Maybe some directories are missing,
X			 * so create any missing directories and try again.
X			 */
X			if (debug)
X				warning("failed!", "");
X			(void) checkdir(artname, getuid(), getgid());
X			if (openorlink(inname, artname, tfp, openfirst, goodngs))
X				break;		/* link succeeded this time */
X			else if (errno != EEXIST) {
X				warning("can't link to %s", artname);
X				status |= ST_DROPPED;
X				break;
X			}
X			/*
X			 * Else artname exists.  It must be a numeric subgroup name,
X			 * such as net.micro.432; try another article.
X			 */
X		}
X	}
X	return status;
X}
X
X/*
X * Open artname, save the name on sp & the FILE pointer through tfp.
X */
Xstatic int
Xopenlink(sp, artname, tfp)
Xchar *sp;
Xchar *artname;
XFILE **tfp;
X{
X	(void) strcpy(sp, artname);	/* save a copy */
X#ifdef O_EXCL
X	/* This is the cheaper way. */
X	{
X	int fd = open(sp, O_WRONLY|O_CREAT|O_EXCL, 0666);
X
X	if (fd < 0)
X		*tfp = NULL;
X	else
X		*tfp = fdopen(fd, "w");
X	}
X#else
X	if (access(sp, F_OK) >= 0)	/* sp exists */
X		*tfp = NULL;		/* refuse to write on it */
X	else		
X		*tfp = fopen(sp, "w");	/* try to create it */
X#endif
X	return *tfp != NULL;
X}
END_OF_FILE
if test 6901 -ne `wc -c <'rnews/fileart.c'`; then
    echo shar: \"'rnews/fileart.c'\" unpacked with wrong size!
fi
# end of 'rnews/fileart.c'
fi
if test -f 'rnews/procart.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rnews/procart.c'\"
else
echo shar: Extracting \"'rnews/procart.c'\" \(7574 characters\)
sed "s/^X//" >'rnews/procart.c' <<'END_OF_FILE'
X/*
X * process a single incoming article
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include "news.h"
X#include "active.h"
X#include "headers.h"
X#include "system.h"
X
X#ifndef COPYSIZE
X#ifdef pdp11
X#define COPYSIZE BUFSIZ
X#else
X#define COPYSIZE 8192
X#endif				/* pdp11 */
X#endif				/* COPYSIZE */
X
Xextern char *exclude;		/* for erik */
X
X/*
X * Copy the article on "in" to a temporary name in the news spool directory,
X * unlink temp name; *or* copy into the final names, if known earlier enough.
X * (Sets h_tmpf in or near mungehdrs() or hdrdump().)
X * If the spool file opened, install the article it contains.
X */
Xint
Xcpinsart(in, inname, maxima)
XFILE *in;
Xchar *inname;
Xlong maxima;
X{
X	int status = ST_OKAY;
X	FILE *tf = NULL;
X	struct headers hdrs;
X
X	hdrinit(&hdrs);
X	status |= copyart(in, inname, maxima, &tf, &hdrs);
X	if (status&ST_NUKED) {			/* no good ngs (in fileart) */
X		char *msgid = "", *ngs = "";
X
X		status &= ~ST_NUKED;		/* nuking isn't serious */
X		if (hdrs.h_msgid != NULL)
X			msgid = hdrs.h_msgid;	/* caution */
X		if (hdrs.h_ngs != NULL)
X			ngs = hdrs.h_ngs;	/* caution */
X		timestamp(stdout, (time_t *)NULL, (char **)NULL);
X		(void) printf(" refused %s bad groups in `%s' and no junk group\n",
X			msgid, ngs);
X	} else if (tf == NULL) {
X		warning("can't open spool file `%s'", hdrs.h_tmpf);
X		status |= ST_DROPPED;
X	} else {
X		status |= insart(tf, &hdrs);
X		(void) fclose(tf);
X	}
X	freeheaders(&hdrs);
X	return status;
X}
X
X/*
X * Copy the next charcnt bytes of "in" (may be not a disk file)
X * to a permanent file under a (possibly) temporary name.
X * Must munge certain headers on the way & remember certain values.
X * mungehdrs() or hdrdump() sets hdrs->h_tmpf & *tfp.
X */
X/* ARGSUSED inname */
Xstatic int
Xcopyart(in, inname, charcnt, tfp, hdrs)
Xregister FILE *in;
Xchar *inname;
Xregister long charcnt;
Xregister FILE **tfp;
Xstruct headers *hdrs;
X{
X	register int readcnt;
X	int status = ST_OKAY;
X	char *s = NULL;
X	char line[COPYSIZE];
X
X	hdrwretch();				/* reset the header parser */
X	/*
X	 * people think this loop is ugly; not sure why.
X	 * if the byte count is positive, read a line; if it doesn't return
X	 * EOF and is a header, then adjust byte count, eat and munge headers.
X	 * strlen(line) must be computed before hdrmutate is called, as it
X	 * removes newlines.
X	 */
X	while (charcnt > 0 &&
X	    (s = fgets(line, (int)min(sizeof line-1, charcnt)+1, in)) != NULL
X	    && ishdr(line)) {
X	    	charcnt -= strlen(line);
X		status |= hdrmutate(hdrs, line, tfp);	/* eat & munge headers */
X	    	/* hdrdump() counts hdrs->h_charswritten */
X	}
X	hdrdeflt(hdrs);
X
X	/* write any saved headers, trigger fileart */
X	status |= hdrdump(tfp, hdrs, YES);
X
X	/* Copy first body line. */
X	if (charcnt > 0 && s != NULL) {	/* fgets worked: not a header line */
X		register int linelen = strlen(line);
X
X		if (*tfp != NULL && fputs(line, *tfp) == EOF)
X			status = fulldisk(status|ST_DROPPED,
X				(hdrs->h_unlink? hdrs->h_tmpf: hdrs->h_files));
X		charcnt -= linelen;	
X		hdrs->h_charswritten += linelen;
X	}
X	/*
X	 * Copy at most "sizeof line" bytes at a time
X	 * and exactly charcnt bytes in total, barring EOF.
X	 */
X	for (; charcnt > 0 && !(status&ST_DISKFULL) &&
X	    (readcnt=fread(line, 1, (int)min(charcnt, sizeof line), in)) > 0;
X	    charcnt -= readcnt, hdrs->h_charswritten += readcnt)
X		if (*tfp != NULL && fwrite(line, 1, readcnt, *tfp) != readcnt)
X			status = fulldisk(status|ST_DROPPED,
X				(hdrs->h_unlink? hdrs->h_tmpf: hdrs->h_files));
X	if (*tfp != NULL && fflush(*tfp) == EOF)	/* force to disk */
X		status = fulldisk(status|ST_DROPPED,
X			(hdrs->h_unlink? hdrs->h_tmpf: hdrs->h_files));
X	if (charcnt > 0 && remote) {	/* TODO: don't use "remote" */
X		(void) fprintf(stderr, "%s: article %s short by %ld bytes\n",
X			progname, (hdrs->h_msgid != NULL? hdrs->h_msgid: ""),
X			(long)charcnt);
X		status |= ST_SHORT;	/* N.B.: do not uninstall this article */
X	}
X	return status;
X}
X
X/*
X * Read headers from "in".
X * Iff we haven't seen this article already and we like the groups,
X * install the article on "in" & hdrs->h_tmpf.
X * Rename hdrs->h_tmpf into the news spool directory.
X * Add history entries for the article.
X * Transmit the article, like a dose of clap, to our neighbours.
X * Process control mess(age)es.
X * Unlink hdrs->h_tmpf, if a temporary link.
X */
Xstatic int
Xinsart(in, hdrs)
XFILE *in;
Xstruct headers *hdrs;
X{
X	register int status = ST_OKAY;
X
X	status |= reject(hdrs);
X	if (status&(ST_DROPPED|ST_NUKED))
X		uninsart(hdrs);	/* remove existing links; give back assigned #s */
X	else {
X		/*
X		 * Ordinary filing: if not already filed,
X		 * make links to hdrs->h_tmpf (which will exist).
X		 */
X		status |= fileart(hdrs, &in, 0);	/* generates Xref: */
X		if (!(status&(ST_DROPPED|ST_NUKED))) {
X			status |= history(hdrs);	/* writes "received: " */
X			/* writes systems on stdout */
X			status |= transmit(hdrs, remote, exclude);
X			(void) putc('\n', stdout);	/* ends the line */
X			(void) fflush(stdout);		/* crash-proofness */
X			if (hdrs->h_ctlcmd != NULL)
X				status |= ctlmsg(hdrs);
X		}
X	}
X    	status &= ~ST_NUKED;			/* nuking is quite casual */
X	if (hdrs->h_unlink && unlink(hdrs->h_tmpf) < 0) {
X		warning("can't unlink `%s'", hdrs->h_tmpf);
X		status |= ST_ACCESS;
X	}
X	return status;
X}
X
X/*
X * Reject articles.  This can be arbitrarily picky.
X */
Xint
Xreject(hdrs)
Xregister struct headers *hdrs;
X{
X	if (alreadyseen(hdrs->h_msgid)) {
X		timestamp(stdout, (time_t *)NULL, (char **)NULL);
X		(void) printf(" refused %s duplicate\n", hdrs->h_msgid);
X	} else if (!ngmatch(oursys()->sy_ngs, hdrs->h_ngs)) {
X		timestamp(stdout, (time_t *)NULL, (char **)NULL);
X		(void) printf(" refused %s bad groups in %s\n",
X			hdrs->h_msgid, hdrs->h_ngs);
X	} else if (moderated(hdrs) && hdrs->h_approved == NULL) {
X		timestamp(stdout, (time_t *)NULL, (char **)NULL);
X		(void) printf(" refused %s unapproved article in moderated group(s) %s\n",
X			hdrs->h_msgid, hdrs->h_ngs);
X	} else
X		return ST_OKAY;
X	if (remote)		/* TODO: test this some other way */
X		return ST_NUKED;
X	else
X		return ST_NUKED|ST_DROPPED;	/* more serious if local */
X}
X
X/*
X * Remove hdrs->h_files (permanent names) and h_tmpf (temporary names),
X * and return assigned article numbers.
X */
Xuninsart(hdrs)
Xregister struct headers *hdrs;
X{
X	if (hdrs->h_unlink && hdrs->h_tmpf[0] != '\0') {	/* temp name */
X		(void) unlink(hdrs->h_tmpf);	/* I don't wanna know... */
X		hdrs->h_unlink = NO;
X	}
X	(void) snuffmayreturn(hdrs->h_files, YES);
X}
X
Xint
Xsnufffiles(filelist)		/* just unlink all files in filelist */
Xchar *filelist;
X{
X	return snuffmayreturn(filelist, NO);
X}
X
Xint
Xsnuffmayreturn(filelist, artret)	/* unlink all files in filelist (return artids?) */
Xchar *filelist;
Xint artret;
X{
X	register char *arts, *spacep, *slashp;
X	int status = ST_OKAY;
X	char artnm[MAXFILE];
X
X	/* this is a deadly tedious job and I really should automate it */
X	for (arts = filelist; arts != NULL && arts[0] != '\0';
X	     arts = (spacep == NULL? NULL: spacep+1)) {
X		spacep = index(arts, ' ');
X		if (spacep != NULL)
X			spacep[0] = '\0';	/* will be restored below */
X	     	(void) strcpy(artnm, arts);
X	     	if (spacep != NULL)
X	     		spacep[0] = ' ';	/* restore space */
X
X	     	slashp = index(artnm, FNDELIM);
X	     	if (slashp != NULL)
X	     		slashp[0] = '\0';	/* will be restored below */
X	     	if (artret)
X			(void) prevartnum(artnm);	/* return assigned # */
X	     	if (slashp != NULL)
X	     		slashp[0] = FNDELIM;	/* restore slash */
X
X	     	mkfilenm(artnm);
X		if (unlink(artnm) < 0) {	/* remove a link & hope */
X			(void) fprintf(stderr, "%s: can't unlink %s\n",
X				progname, artnm);
X	     		status |= ST_ACCESS;
X		}
X	}
X	return status;
X}
END_OF_FILE
if test 7574 -ne `wc -c <'rnews/procart.c'`; then
    echo shar: \"'rnews/procart.c'\" unpacked with wrong size!
fi
# end of 'rnews/procart.c'
fi
if test -f 'rnews/sys.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rnews/sys.c'\"
else
echo shar: Extracting \"'rnews/sys.c'\" \(6730 characters\)
sed "s/^X//" >'rnews/sys.c' <<'END_OF_FILE'
X/*
X * news sys file reading functions (in-memory version)
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "news.h"
X#include "newspaths.h"
X#include "system.h"
X
Xstatic FILE *fp = NULL;		/* descriptor for libfile("sys") */
Xstatic char filerelname[] = "sys";
X
Xstatic struct system *firstsys = NULL;	/* cache */
Xstatic struct system *currsys = NULL;	/* current system */
X
X/* forward decls */
Xchar *parsecolon();
X
Xstruct system *
Xoursys()			/* return our sys entry */
X{
X	register struct system *sys;
X	static struct system fakesys;
X	static struct system *thissys = NULL;
X
X	if (thissys != NULL)		/* in-core-only optimisation */
X		return thissys;
X	rewsys();
X	while ((sys = nextsys()) != NULL && !STREQ(sys->sy_name, hostname()))
X		;
X	if (sys == NULL) {		/* no entry; cook one up */
X		/* TODO: test this by some other means instead */
X		if (!remote)		/* no -p, local posting */
X			(void) fprintf(stderr,
X		"%s: no %s file - your news will not leave this machine\n",
X				progname, libfile(filerelname));
X		fakesys.sy_name = hostname();
X		fakesys.sy_ngs = "all";
X		fakesys.sy_flags = 0;
X		fakesys.sy_lochops = 0;
X		fakesys.sy_cmd = "";
X		fakesys.sy_next = NULL;
X		sys = &fakesys;
X	}
X	thissys = sys;			/* for future reference */
X	return sys;
X}
X
X/*
X * Returned pointer points at a static struct whose members
X * point at static storage.
X */
Xstruct system *
Xnextsys()				/* return next sys entry */
X{
X	struct system *retsys;
X
X	if (firstsys == NULL && fp == NULL)
X		if ((fp = fopenwclex(libfile(filerelname), "r")) == NULL)
X			return NULL;
X	if (fp != NULL && firstsys == NULL)	/* file open, no cache */
X		readsys();			/* read & parse fp */
X	retsys = currsys;			/* save current ptr. */
X	if (currsys != NULL)
X		currsys = currsys->sy_next;	/* advance current ptr. */
X	return retsys;
X}
X
Xrewsys()
X{
X	currsys = firstsys;
X}
X
Xstatic char *curr, *next;			/* parsing state */
X
XSTATIC
Xreadsys()
X{
X	register char *sysline;
X
X	rewind(fp);
X	/* read possibly continued lines of arbitrary length */
X	while ((sysline = cfgetms(fp)) != NULL) {
X		if (sysline[0] != '#' && sysline[0] != '\n') {	/* not a comment */
X			register struct system *sysp;
X			register char *slashp;
X			char *flagstring;
X
X			/* This storage is never freed. */
X			sysp = (struct system *) malloc(sizeof *sysp);
X			if (sysp == NULL)
X				errunlock("out of memory for system structs", "");
X
X			/* parse into sysp */
X			trim(sysline);
X			next = sysline;
X			parse(&sysp->sy_name);
X			parse(&sysp->sy_ngs);
X			parse(&flagstring);
X			parse(&sysp->sy_cmd);
X			/* could check for extra fields here */
X
X			parseflags(flagstring, sysp);
X			free(flagstring);		/* malloced by parse */
X			sysp->sy_next = NULL;
X
X			/* reparse for embedded slashes */
X			slashp = index(sysp->sy_name, '/');
X			if (slashp != NULL) {		/* parse name/excl1,excl2,... */
X				*slashp = '\0';		/* terminate name */
X				sysp->sy_excl = slashp + 1;
X			} else
X				sysp->sy_excl = NULL;	/* no exclusions */
X			slashp = index(sysp->sy_ngs, '/');
X			if (slashp != NULL) {		/* parse ngs/distrs */
X				*slashp = '\0';		/* terminate ngs */
X				sysp->sy_distr = slashp + 1;
X			} else
X				sysp->sy_distr = sysp->sy_ngs;
X
X			/* expand ME if any */
X			if (STREQ(sysp->sy_name, "ME")) {
X				free(sysp->sy_name);	/* malloced by parse */
X				sysp->sy_name = hostname();	/* NB not malloced */
X			}
X
X			/* fill in any defaults */
X
X			/*
X			 * If no batch file name was given, use the default
X			 * ($NEWSCTL/batch/b.system/togo).
X			 */ 
X			if (sysp->sy_flags&FLG_BATCH && sysp->sy_cmd[0] == '\0') {
X				char *deffile = emalloc((unsigned)STRLEN("batch/b.") +
X					strlen(sysp->sy_name) + STRLEN("/togo") + 1);
X
X				(void) strcpy(deffile, "batch/b.");
X				(void) strcat(deffile, sysp->sy_name);
X				(void) strcat(deffile, "/togo");
X				free(sysp->sy_cmd);	/* malloced by parse */
X				sysp->sy_cmd = libfile(deffile); /* NB not malloced */
X				free(deffile);
X			}
X			/*
X			 * If no command was given, use the default
X			 * (uux - -r -z system!rnews).
X			 * (This *is* yucky and uucp-version-dependent.)
X			 */ 
X			if (!(sysp->sy_flags&FLG_BATCH) && sysp->sy_cmd[0] == '\0') {
X				/* TODO: send mail to usenet, harassing him. */
X				/* TODO: search PATH including $NEWSCTL/syscmd */
X				free(sysp->sy_cmd);	/* malloced by parse */
X				sysp->sy_cmd = emalloc((unsigned)STRLEN("uux - -r -z ") +
X					strlen(sysp->sy_name) + STRLEN("!rnews") + 1);
X				(void) strcpy(sysp->sy_cmd, "uux - -r -z ");
X				(void) strcat(sysp->sy_cmd, sysp->sy_name);
X				(void) strcat(sysp->sy_cmd, "!rnews");
X			}
X
X			/* stash *sysp away on the tail of the current list */
X			if (firstsys == NULL)
X				firstsys = sysp;		/* 1st system */
X			else
X				currsys->sy_next = sysp;	/* tack on tail */
X			currsys = sysp;
X		}
X		free(sysline);
X	}
X	(void) fclose(fp);		/* file no longer needed */
X	fp = NULL;			/* mark file closed */
X	rewsys();
X}
X
XSTATIC
Xparse(into)
Xregister char **into;
X{
X	curr = next;
X	if (curr == NULL)
X		*into = strsave("");
X	else {
X		next = parsecolon(curr);
X		*into = strsave(curr);
X	}
X	/* *into is never freed. */
X	if (*into == NULL)
X		errunlock("out of memory for sys strings", "");
X}
X
XSTATIC char *
Xparsecolon(line)		/* return NULL or ptr. to byte after colon */
Xchar *line;
X{
X	register char *colon;
X
X	INDEX(line, ':', colon);
X	if (colon != NULL)
X		*colon++ = '\0';	/* turn colon into a NUL */
X	return colon;
X}
X
XSTATIC
Xparseflags(flags, sysp)
Xregister char *flags;			/* flags string */
Xregister struct system *sysp;		/* result here */
X{
X	sysp->sy_flags = 0;
X	sysp->sy_lochops = 0;		/* default L value */
X	for (; *flags != '\0'; flags++)
X		switch (*flags) {
X		case 'A':
X			errunlock("A news format not supported", "");
X			/* NOTREACHED */
X		case 'B':				/* mostly harmless */
X			break;
X		case 'f':
X			sysp->sy_flags |= FLG_SZBATCH;
X			break;
X		case 'F':
X			sysp->sy_flags |= FLG_BATCH;
X			break;
X		case 'I':				/* NNTP */
X			/* TODO: I sys flag: I-have, write msg-ids */
X			break;
X		case 'L':				/* Ln */
X			sysp->sy_flags |= FLG_LOCAL;
X			sysp->sy_lochops = 0;
X			if (isascii(flags[1]) && isdigit(flags[1])) {
X				sysp->sy_lochops *= 10;
X				sysp->sy_lochops += *++flags - '0';
X			}
X			break;
X		case 'm':
X			/* TODO: m sys flag: send only moderated groups */
X			break;
X		case 'N':
X			sysp->sy_flags |= FLG_IHAVE;
X			errunlock("N flag given but I-have/send-me is not supported", "");
X			/* NOTREACHED */
X		case 'u':
X			/* TODO: u sys flag: send only unmoderated groups */
X			break;
X		case 'U':			/* mostly harmless */
X			/* sysp->sy_flags |= FLG_PERM; */
X			break;
X		case 'H':			/* bugger off */
X		case 'S':			/* bugger off */
X		case 'M':			/* multicast: obs., see batcher */
X		case 'O':			/* multicast: obs., see batcher */
X		default:
X			errunlock("unknown sys flag `%c' given", *flags);
X			/* NOTREACHED */
X		}
X}
END_OF_FILE
if test 6730 -ne `wc -c <'rnews/sys.c'`; then
    echo shar: \"'rnews/sys.c'\" unpacked with wrong size!
fi
# end of 'rnews/sys.c'
fi
echo shar: End of archive 9 \(of 14\).
##  End of shell archiim7) file("