[comp.sources.unix] v14i051: Network News Transfer Protocol, version 1.5, Part05/09

rsalz@bbn.com (Rich Salz) (04/20/88)

Submitted-by: Phil Lapsley <phil@ucbvax.berkeley.edu>
Posting-number: Volume 14, Issue 51
Archive-name: nntp1.5/part05

#! /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 5 (of 9)."
# Wrapped by rsalz@fig.bbn.com on Tue Apr 19 18:16:43 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f './README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./README'\"
else
echo shar: Extracting \"'./README'\" \(6865 characters\)
sed "s/^X//" >'./README' <<'END_OF_FILE'
NNTP README		January 23, 1988	For version 1.5 NNTP package
X
X[See the file CHANGES to see differences between this version and
older versions.]
X
INTRODUCTION
X
X     This package contains everything (well, most of it, I hope) that
you'll need to implement a remote news server running the NNTP protocol.
X
X     A brief tour of the directories and their programs:
X
X	server		Source for the NNTP news server daemon.
X
X	rrnpatches	Patches to rn #39 to allow remote news reading.
X
X	inews		A "mini-inews" written by Steven Grady
X			<grady@postgres.berkeley.edu> which allows
X		 	remote posting without changing much else.
X
X	xmit		An active transmission client for transferring
X			news, written by Erik Fair; see note below.
X
X	common		Common stuff (response codes, configuration info,
X			and some client library routines) for the
X			the news server and the clients.  The "conf.h"
X			file here needs to be edited to reflect
X			the peculiarities of your system.
X
X	support		Some support files and scripts.
X
X	doc		Documentation on the server, including manual
X			pages.  Manual pages for rrn are in rrn/.
X
X	xfer		A passive reception client which uses the
X			NEWNEWS command to retrieve news from a remote
X			server.  Written by Brian Kantor, this software
X			is UNSUPPORTED.
X
X     Each directory has associated with it a README file.
This file will try to give enough information for you to get things
running and installed, but the README in each directory has more
details for each subset of the NNTP package.  You may also want to print
a copy of doc/rfc977, which describes the NNTP protocol.
X
INTRODUCTION TO NNTP INSTALLATION
X
X     First, figure out what you are trying to do (this is good
advice under most circumstances, and it is especially apropos here).
NNTP can be used for two things:  (1) Remote news reading, where news
is stored on one machine and read from remote machines across a
high-speed local area network such as Ethernet, and (2) News transfer,
where news is transmitted to NNTP servers on remote machines over
either local or long-haul networks.
X
X     NNTP "server" machines are machines that have a full installation
of USENET news on them.  An NNTP process, the "server", allows remote
sites to connect to the server machine and read or transfer news.
The server machine DOES NOT NEED "reader client" software such as
X"rrn".  It MAY NEED "transmission client" software such as "nntpxmit"
if you want to use NNTP to transfer news.
X
X     NNTP "client" machines do not have a full installation of USENET
news on them.  They get their news from an NNTP server machine across
the network.  They DO have NNTP "reader clients" such as "rrn" installed
on them.
X
X     In summary,
X
X	>>> A full client installation of NNTP requires the following
X	    files (suitable for rdist, assuming standard directories):
X
NEWS = ( /usr/local/{Pnews,Rnmail,inews,rn,rrn,newsetup,newsgroups,lib/rn}
X	/usr/man/catl/{Pnews,Rnmail,rn,newsetup,newsgroups}.1 )
X
X	    You DO NOT need any of the normal news junk (e.g.,
X	    /usr/lib/news, postnews, checknews, readnews) on CLIENT
X	    systems.
X
X	    You DO need these on SERVER systems.
X
X     An important note:
X
X	The NNTP server assumes that the history file format
X	is 2.11 or 2.10.3; therefore you need 2.11 news on your
X	server machine.
X
X	>>>>> Get 2.11 news if you don't have it.
X
GENERAL INSTALLATION
X
X     Time for a general and cohesive Plan:
X
X     Regardless of whether you are making a server or a client NNTP
setup, you will have to edit common/conf.h to reflect your system's
setup.  So,
X
X     1. Look at common/README.  This will explain the stuff
X	needs to be tailored for your system in common/conf.h.
X	Make the necessary changes to reflect your system.
X
X	If you are running with System V or Excelan TCP/IP,
X	please read Stan Barber's instructions in common/README.SYSV
X
X	If you have an HPUX machine, please read common/README.HPUX
X
X     Now, at this point, what you do depends on whether you are
installing a server system or a client system.
X
SERVER INSTALLATION
X
X     2. Type "make server" in this directory.
X
X     3. Type "make install_server" in this directory.
X
CLIENT INSTALLATION
X
X     2. You must configure "rrn", the remote newsreading client.
X        cd into "rrnpatches", and read README_RRN.  This will explain
X        how to apply the patches supplied to turn rn #39 into rrn #39.
X
X     3. Type "make client" in this directory.
X
X     4. Type "make install_client" in this directory.
X
IF YOU HAVE PROBLEMS
X
X     You can get to me via electronic mail at the following addresses:
X
X	Internet:		phil@ucbvax.berkeley.edu
X	UUCP:			...!ucbvax!phil
X	Telephone (home):	(415) 848-8409
X	Telephone (work):	(415) 642-7447
X
X     I'm very interested in learning what hacks need to be made to
nntpd to get it to work on various systems, and certainly, if there are
outright bugs, please let me know.  Bug reports and fixes for nntp are
posted to the newsgroup "news.software.nntp".  Announcements of new
versions of nntp software are posted there too.
X
X     I'll support bugs caused by my additions/hacks to turn "rn" into
X"rrn" (hopefully Larry Wall will be supporting this soon...) but please
don't send me reports about things that were already in rn itself.
Also, if you add features to rrn, I probably am not interested in
supporting them unless they are really necessary; every change I make
to rrn is something that I have to hack into future releases of rn, so
the fewer changes, the better.
X
ACKNOWLEDGEMENTS
X
X     I'd like to thank the various people who both inspired and helped
to make NNTP a reality:  Erik Fair, whose criticism and suggestions
helped mold NNTP (and who wrote the active transmission client); Brian
Kantor, who really got me motivated enough to finish the thing, and
whose work on the RFC was *tremendous*; Steven Grady, who wrote the
inews interface (and wasted countless hours only to have his work
dashed periodically...); Mike Meyer, who beta tested the software and
pointed out numerous problems; Bob Henry, who let me have the resources
so that it got done; Peter Yee, who repeated enough good ideas to get
me to include them; all the folks who had patience with me and didn't
go off and write this themselves (jsq, you listening?  My thanks.);
Chuq von Rospach and the members of lan-news; Gene Spafford for
eliminating having to include 1 MB of source to rn by a set of patches;
Matt Thomas for adding support for DECNET; Stan Barber for adding
System V/Excelan support and putting up with my sloth; the kind folks
who beta tested version 1.4 and put up with stupid bugs and provided
helpful feedback, notably Craig Leres, Matt Thomas, Wengyik Yeong, and
Stan Barber; all the individuals who have reported bugs or suggested
improvements (see CHANGES for a list); and probably many other people
I've neglected to mention.  My thanks to all.
X
X						Phil Lapsley
X						26 February 1988
END_OF_FILE
if test 6865 -ne `wc -c <'./README'`; then
    echo shar: \"'./README'\" unpacked with wrong size!
fi
# end of './README'
fi
if test -f './rrnpatches/Configure.pat' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./rrnpatches/Configure.pat'\"
else
echo shar: Extracting \"'./rrnpatches/Configure.pat'\" \(6499 characters\)
sed "s/^X//" >'./rrnpatches/Configure.pat' <<'END_OF_FILE'
X*** rn/Configure	Sun Mar 15 19:54:19 1987
X--- rrn/Configure	Thu Feb 25 20:56:09 1988
X***************
X*** 77,82
X  Log=''
X  Header=''
X  sitename=''
X  orgname=''
X  isadmin=''
X  newsadmin=''
X
X--- 77,83 -----
X  Log=''
X  Header=''
X  sitename=''
X+ domain=''
X  orgname=''
X  isadmin=''
X  newsadmin=''
X***************
X*** 117,122
X  phostname=''
X  hostcmd=''
X  norelay=''
X  CONFIG=''
X  
X  echo "Beginning of configuration questions for rn kit."
X
X--- 118,127 -----
X  phostname=''
X  hostcmd=''
X  norelay=''
X+ isrrn=''
X+ rrnserver=''
X+ serverfile=''
X+ NNTPSRC=''
X  CONFIG=''
X  
X  echo "Beginning of configuration questions for rn kit."
X***************
X*** 681,686
X      hostcmd=''
X  done
X  
X  : get organizaton name
X  longshots='/usr/src/new /usr/src/local /usr/local/src'
X  case "$orgname" in
X
X--- 686,725 -----
X      hostcmd=''
X  done
X  
X+ : try to deal with domains
X+ $cat << 'EOH'
X+ 
X+ Please enter your domain name.  This will be used in conjunction
X+ with the site name for return addresses on news articles and
X+ mail.  If you use the 4.3ism of having your domain in your
X+ hostname, all the posting programs will figure this out on the
X+ fly, so don't worry.
X+ 
X+ Examples of some valid domains:
X+ 
X+ 	uucp
X+ 	arpa
X+ 	berkeley.edu
X+ 	nsa.gov
X+ 
X+ EOH
X+ 
X+ dflt="uucp"
X+ $echo $n "Your domain: [$dflt] $c"
X+ . myread
X+ case "$ans" in
X+ '') domain="$dflt";;
X+ *)  domain="$ans" ;;
X+ esac
X+ 
X+ if $test $portable = "undef" ; then
X+ 	case $sitename in
X+ 	*.*)	;;
X+ 	*)	sitename=$sitename.$domain
X+ 		;;
X+ 	esac
X+ fi
X+ 
X  : get organizaton name
X  longshots='/usr/src/new /usr/src/local /usr/local/src'
X  case "$orgname" in
X***************
X*** 769,774
X      blurfl*) ;;
X      *) $echo "Directory $libexp not found";;
X      esac
X      echo $n "Where is your news library (~name okay)? [$dflt] $c"
X      . myread
X      case "$ans" in
X
X--- 808,817 -----
X      blurfl*) ;;
X      *) $echo "Directory $libexp not found";;
X      esac
X+     echo "(If you are building this as rrn, it is a good idea"
X+     echo "to make your news library directory the same as where the rn"
X+     echo "library directory is, usually /usr/local/lib/rn)"
X+     echo " "
X      echo $n "Where is your news library (~name okay)? [$dflt] $c"
X      . myread
X      case "$ans" in
X***************
X*** 1281,1287
X      fi
X  fi
X  
X! : locate spool directory
X  case "$spool" in
X  '')
X      dflt=/usr/spool/news
X
X--- 1324,1422 -----
X      fi
X  fi
X  
X! : locate spool directory and check if rrn
X! case "$isrrn" in
X! define)
X!     dflt="y";;
X! *)
X!     dflt="n";;
X! esac
X! isrrn=''
X! while $test -z "$isrrn" ; do
X!     $echo " "
X!     $echo $n "Do you want this built as remote rn (rrn)? [$dflt] $c"
X!     . myread
X!     case "$ans" in
X!     '') ans="$dflt";;
X!     esac
X!     case "$ans" in
X!     n*)
X! 	isrrn=undef;;
X!     y*)
X! 	isrrn=define
X! 	spool=/tmp
X! 	$echo "net.foobar 00001 00001 y" > .falseactive
X! 
X! 	case "$serverfile" in
X! 	'')  dflt="no default" ;;
X! 	*)   dflt="$serverfile";;
X! 	esac
X! 
X! 	$cat <<'EOM'
X! 
X! rrn determines the machine to use as a news server by two means:
X! 
X! 	1. It examines the environment variable NNTPSERVER for
X! 	   a machine name; this allows users to use server machines
X! 	   other than the default.
X! 
X! 	2. It looks in a file which contains the name of a server
X! 	   machine.
X! 
X! You must create the file mentioned in (2), above.  Simply put the name
X! of the machine you wish to use as your news server in this file.
X! If you really want, you can use # for comments and blank lines in
X! this file as well.
X! 
X! EOM
X! 
X! 	ans=''
X! 	while $test -z "$ans" ; do
X! 	$echo $n "Enter the name of the news server file: [$dflt] $c"
X! 	. myread
X! 	done
X! 	serverfile="$ans"
X! 
X! 	case "$rrnserver" in
X! 	'')  dflt="no default" ;;
X! 	*)   dflt="$rrnserver";;
X! 	esac
X! 
X! 	case "$NNTPSRC" in
X! 	'') dflt="no default";;
X! 	*)  dflt="$NNTPSRC";;
X! 	esac
X! 
X! 	ans='blurfl/dyick'
X! 	while $test ! -d "$ans"; do
X! 	    $echo $n "Enter the pathname of the NNTP source directory: [$dflt] $c"
X! 	    . myread
X! 	    case "$ans" in
X! 	    '') ans="$dflt";;
X! 	    esac
X! 	    ans=`filexp "$ans"`
X! 	    if $test ! -r $ans/common/nntp.h ; then
X! 		ans='blurfl/dyick'
X! 	    fi
X! 	done
X! 	NNTPSRC="$ans"
X! cat > server.h <<EOF_SERVE
X! #ifdef SERVER
X! 
X! EXT	char	*getserverbyfile();
X! EXT	int	server_init();
X! EXT	void	put_server();
X! EXT	int	get_server();
X! EXT	void	close_server();
X! 
X! #include "$NNTPSRC/common/nntp.h"
X! #endif
X! EOF_SERVE
X! 
X!     esac
X! 
X! done
X! 
X  case "$spool" in
X  '')
X      dflt=/usr/spool/news
X***************
X*** 1288,1294
X      ;;
X  *)  dflt="$spool";;
X  esac
X! ans='blurfl/dyick'
X  while $test ! -d $ans; do
X      $echo " "
X      case "$ans" in
X
X--- 1423,1432 -----
X      ;;
X  *)  dflt="$spool";;
X  esac
X! case "$isrrn" in
X! define)  ans=/tmp;;
X! *) ans='blurfl/dyick';;
X! esac
X  while $test ! -d $ans; do
X      $echo " "
X      case "$ans" in
X***************
X*** 1322,1328
X      ;;
X  *)  dflt="$active";;
X  esac
X! myactive='blurfl/dyick'
X  while $test ! -f "$myactive"; do
X      $echo " "
X      case "$myactive" in
X
X--- 1460,1469 -----
X      ;;
X  *)  dflt="$active";;
X  esac
X! case "$isrrn" in
X! define) myactive=.falseactive;;
X! *) myactive='blurfl/dyick'
X! esac
X  while $test ! -f "$myactive"; do
X      $echo " "
X      case "$myactive" in
X***************
X*** 1799,1804
X  Log='$Log'
X  Header='$Header'
X  sitename='$sitename'
X  orgname='$orgname'
X  isadmin='$isadmin'
X  newsadmin='$newsadmin'
X
X--- 1940,1946 -----
X  Log='$Log'
X  Header='$Header'
X  sitename='$sitename'
X+ domain='$domain'
X  orgname='$orgname'
X  isadmin='$isadmin'
X  newsadmin='$newsadmin'
X***************
X*** 1839,1844
X  phostname='$phostname'
X  hostcmd='$hostcmd'
X  norelay='$norelay'
X  CONFIG=true
X  EOT
X  
X
X--- 1981,1989 -----
X  phostname='$phostname'
X  hostcmd='$hostcmd'
X  norelay='$norelay'
X+ isrrn='$isrrn'
X+ rrnserver='$rrnserver'
X+ NNTPSRC='$NNTPSRC'
X  CONFIG=true
X  EOT
X  
X***************
X*** 1926,1931
X  #$douname	DOUNAME		/* do we have a uname function? */
X  #$phostname	PHOSTNAME "$hostcmd"	/* how to get host name with popen */
X  #$norelay     NORELAY         /* 2.10.3 doesn't have Relay-Version line */
X  EOT
X  
X  CONFIG=true
X
X--- 2071,2079 -----
X  #$douname	DOUNAME		/* do we have a uname function? */
X  #$phostname	PHOSTNAME "$hostcmd"	/* how to get host name with popen */
X  #$norelay     NORELAY         /* 2.10.3 doesn't have Relay-Version line */
X+ #$isrrn         SERVER          /* rrn server code */
X+ #$isrrn SERVER_HOST     "$rrnserver"
X+ #$isrrn SERVER_FILE	"$serverfile"
X  EOT
X  
X  CONFIG=true
END_OF_FILE
if test 6499 -ne `wc -c <'./rrnpatches/Configure.pat'`; then
    echo shar: \"'./rrnpatches/Configure.pat'\" unpacked with wrong size!
fi
# end of './rrnpatches/Configure.pat'
fi
if test -f './rrnpatches/rcstuff.c.pat' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./rrnpatches/rcstuff.c.pat'\"
else
echo shar: Extracting \"'./rrnpatches/rcstuff.c.pat'\" \(6131 characters\)
sed "s/^X//" >'./rrnpatches/rcstuff.c.pat' <<'END_OF_FILE'
X*** rn/rcstuff.c	Sun Mar 15 19:54:20 1987
X--- rrn/rcstuff.c	Fri May 29 09:33:43 1987
X***************
X*** 31,36
X  #include "intrp.h"
X  #include "only.h"
X  #include "rcln.h"
X  #include "INTERN.h"
X  #include "rcstuff.h"
X  
X
X--- 31,37 -----
X  #include "intrp.h"
X  #include "only.h"
X  #include "rcln.h"
X+ #include "server.h"
X  #include "INTERN.h"
X  #include "rcstuff.h"
X  
X***************
X*** 53,58
X      register bool foundany = FALSE;
X      char *some_buf;
X      long length;
X  
X  #ifdef HASHNG
X      for (i=0; i<HASHSIZ; i++)
X
X--- 54,62 -----
X      register bool foundany = FALSE;
X      char *some_buf;
X      long length;
X+ #ifdef SERVER
X+     char *cp;
X+ #endif SERVER
X  
X  #ifdef HASHNG
X      for (i=0; i<HASHSIZ; i++)
X***************
X*** 61,66
X  
X      /* make filenames */
X  
X      rcname = savestr(filexp(RCNAME));
X      rctname = savestr(filexp(RCTNAME));
X      rcbname = savestr(filexp(RCBNAME));
X
X--- 65,79 -----
X  
X      /* make filenames */
X  
X+ #ifdef SERVER
X+ 
X+     if (cp = getenv("NEWSRC"))
X+ 	rcname = savestr(filexp(cp));
X+     else
X+ 	rcname = savestr(filexp(RCNAME));
X+ 
X+ #else not SERVER
X+ 
X      rcname = savestr(filexp(RCNAME));
X  
X  #endif SERVER
X***************
X*** 62,67
X      /* make filenames */
X  
X      rcname = savestr(filexp(RCNAME));
X      rctname = savestr(filexp(RCTNAME));
X      rcbname = savestr(filexp(RCBNAME));
X      softname = savestr(filexp(SOFTNAME));
X
X--- 75,83 -----
X  #else not SERVER
X  
X      rcname = savestr(filexp(RCNAME));
X+ 
X+ #endif SERVER
X+ 
X      rctname = savestr(filexp(RCTNAME));
X      rcbname = savestr(filexp(RCBNAME));
X      softname = savestr(filexp(SOFTNAME));
X***************
X*** 224,229
X  /* returns TRUE if found or added, FALSE if not. */
X  /* assumes that we are chdir'ed to SPOOL */
X  
X  bool
X  get_ng(what,do_reloc)
X  char *what;
X
X--- 240,249 -----
X  /* returns TRUE if found or added, FALSE if not. */
X  /* assumes that we are chdir'ed to SPOOL */
X  
X+ #ifdef SERVER
X+ static int addnewbydefault = 0;
X+ #endif SERVER
X+ 
X  bool
X  get_ng(what,do_reloc)
X  char *what;
X***************
X*** 231,236
X  {
X      char *ntoforget;
X      char promptbuf[128];
X  
X  #ifdef VERBOSE
X      IF(verbose)
X
X--- 251,259 -----
X  {
X      char *ntoforget;
X      char promptbuf[128];
X+ #ifdef SERVER
X+     char ser_line[256];
X+ #endif SERVER
X  
X  #ifdef VERBOSE
X      IF(verbose)
X***************
X*** 248,253
X      set_ngname(what);
X      ng = find_ng(ngname);
X      if (ng == nextrcline) {		/* not in .newsrc? */
X  	if ((softptr[ng] = findact(buf,ngname,strlen(ngname),0L)) < 0 ) {
X  	    dingaling();
X  #ifdef VERBOSE
X
X--- 271,291 -----
X      set_ngname(what);
X      ng = find_ng(ngname);
X      if (ng == nextrcline) {		/* not in .newsrc? */
X+ 
X+ #ifdef SERVER
X+ 	sprintf(ser_line, "GROUP %s", ngname);
X+ 	put_server(ser_line);
X+ 	if (get_server(ser_line, sizeof(ser_line)) < 0) {
X+ 	    fprintf(stderr, "rrn: Unexpected close of server socket.\n");
X+ 	    finalize(1);
X+ 	}
X+ 	if (*ser_line != CHAR_OK) {
X+ 	    if (atoi(ser_line) != ERR_NOGROUP) {
X+ 		fprintf(stderr, "Server response to GROUP %s:\n%s\n",
X+ 		    ngname, ser_line);
X+ 	    }
X+ #else not SERVER
X+ 
X  	if ((softptr[ng] = findact(buf,ngname,strlen(ngname),0L)) < 0 ) {
X  
X  #endif SERVER
X***************
X*** 249,254
X      ng = find_ng(ngname);
X      if (ng == nextrcline) {		/* not in .newsrc? */
X  	if ((softptr[ng] = findact(buf,ngname,strlen(ngname),0L)) < 0 ) {
X  	    dingaling();
X  #ifdef VERBOSE
X  	    IF(verbose)
X
X--- 287,295 -----
X  #else not SERVER
X  
X  	if ((softptr[ng] = findact(buf,ngname,strlen(ngname),0L)) < 0 ) {
X+ 
X+ #endif SERVER
X+ 
X  	    dingaling();
X  #ifdef VERBOSE
X  	    IF(verbose)
X***************
X*** 261,266
X  	    sleep(2);
X  	    return FALSE;
X  	}
X  #ifdef VERBOSE
X  	IF(verbose)
X  	    sprintf(promptbuf,"\nNewsgroup %s not in .newsrc--add? [yn] ",ngname);
X
X--- 302,314 -----
X  	    sleep(2);
X  	    return FALSE;
X  	}
X+ #ifdef SERVER
X+ 	if (addnewbydefault) {
X+ 		printf("(Adding %s to end of your .newsrc)\n", ngname);
X+ 	        ng = add_newsgroup(ngname);
X+ 	        do_reloc = FALSE;
X+ 	} else {
X+ #endif SERVER
X  #ifdef VERBOSE
X  	IF(verbose)
X  	    sprintf(promptbuf,"\nNewsgroup %s not in .newsrc--add? [yn] ",ngname);
X***************
X*** 296,301
X  	    ng = add_newsgroup(ngname);
X  	    do_reloc = FALSE;
X  	}
X  	else {
X  	    fputs(hforhelp,stdout) FLUSH;
X  	    settle_down();
X
X--- 344,359 -----
X  	    ng = add_newsgroup(ngname);
X  	    do_reloc = FALSE;
X  	}
X+ #ifdef SERVER
X+ 	else if (*buf == 'Y') {
X+ 	    fputs(
X+ 	"(I'll add all new newsgroups to the end of your .newsrc.)\n", stdout);
X+ 	    addnewbydefault = 1;
X+ 	    printf("(Adding %s to end of your .newsrc)\n", ngname);
X+ 	    ng = add_newsgroup(ngname);
X+ 	    do_reloc = FALSE;
X+ 	}
X+ #endif SERVER
X  	else {
X  	    fputs(hforhelp,stdout) FLUSH;
X  	    settle_down();
X***************
X*** 301,306
X  	    settle_down();
X  	    goto reask_add;
X  	}
X      }
X      else if (rcchar[ng] == NEGCHAR) {	/* unsubscribed? */
X  #ifdef VERBOSE
X
X--- 359,367 -----
X  	    settle_down();
X  	    goto reask_add;
X  	}
X+ #ifdef SERVER
X+       }
X+ #endif SERVER
X      }
X      else if (rcchar[ng] == NEGCHAR) {	/* unsubscribed? */
X  #ifdef VERBOSE
X***************
X*** 453,458
X      if (newng < 0) {
X        reask_reloc:
X  	unflush_output();		/* disable any ^O in effect */
X  #ifdef VERBOSE
X  	IF(verbose)
X  	    printf("\nPut newsgroup where? [%s] ", dflt);
X
X--- 514,525 -----
X      if (newng < 0) {
X        reask_reloc:
X  	unflush_output();		/* disable any ^O in effect */
X+ #ifdef SERVER
X+ 	if (addnewbydefault) {
X+ 	    buf[0] = '$';
X+ 	    buf[1] = '\0';
X+ 	} else {
X+ #endif SERVER
X  #ifdef VERBOSE
X  	IF(verbose)
X  	    printf("\nPut newsgroup where? [%s] ", dflt);
X***************
X*** 465,470
X        reinp_reloc:
X  	eat_typeahead();
X  	getcmd(buf);
X  	if (errno || *buf == '\f') {
X  			    /* if return from stop signal */
X  	    goto reask_reloc;	/* give them a prompt again */
X
X--- 532,540 -----
X        reinp_reloc:
X  	eat_typeahead();
X  	getcmd(buf);
X+ #ifdef SERVER
X+ 	}
X+ #endif SERVER
X  	if (errno || *buf == '\f') {
X  			    /* if return from stop signal */
X  	    goto reask_reloc;	/* give them a prompt again */
END_OF_FILE
if test 6131 -ne `wc -c <'./rrnpatches/rcstuff.c.pat'`; then
    echo shar: \"'./rrnpatches/rcstuff.c.pat'\" unpacked with wrong size!
fi
# end of './rrnpatches/rcstuff.c.pat'
fi
if test -f './server/serve.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./server/serve.c'\"
else
echo shar: Extracting \"'./server/serve.c'\" \(6497 characters\)
sed "s/^X//" >'./server/serve.c' <<'END_OF_FILE'
X#ifndef lint
static char	*sccsid = "@(#)serve.c	1.29	(Berkeley) 2/6/88";
X#endif
X
X/*
X * Main server routine
X */
X
X#include "common.h"
X#include <signal.h>
X#ifdef USG
X#include <sys/times.h>
X#else
X#include <sys/time.h>
X#endif
X
X#ifdef LOG
X# ifndef USG
X#  include <sys/resource.h>
X# endif not USG
X#endif
X
extern	int	ahbs(), group(), help(), ihave();
extern	int	list(), newgroups(), newnews(), nextlast(), post();
extern	int	slave(), stat(), xhdr();
X
static struct cmdent {
X	char	*cmd_name;
X	int	(*cmd_fctn)();
X} cmdtbl[] = {
X	"article",	ahbs,
X	"body",		ahbs,
X	"group",	group,
X	"head",		ahbs,
X	"help",		help,
X	"ihave",	ihave,
X	"last",		nextlast,
X	"list",		list,
X	"newgroups",	newgroups,
X	"newnews",	newnews,
X	"next",		nextlast,
X	"post",		post,
X	"slave",	slave,
X	"stat",		ahbs,
X#ifdef XHDR
X	"xhdr",		xhdr,
X#endif XHDR
X};
X#define NUMCMDS (sizeof(cmdtbl) / sizeof(struct cmdent))
X
X
X/*
X * serve -- given a connection on stdin/stdout, serve
X *	a client, executing commands until the client
X *	says goodbye.
X *
X *	Parameters:	None.
X *
X *	Returns:	Exits.
X *
X *	Side effects:	Talks to client, does a lot of
X *			stuff.
X */
X
serve()
X{
X	char		line[NNTP_STRLEN];
X	char		host[MAXHOSTNAMELEN];
X	char		gdbuf[MAXBUFLEN];
X	char		**argp;
X	char		*timeptr, *cp;
X	int		argnum, i;
X	double		Tstart, Tfinish;
X	double		user, sys;
X#ifdef USG
X	time_t		start, finish;
X#else not USG
X	struct timeval	start, finish;
X#endif not USG
X	extern char	*ctime();
X#ifdef POSTER
X	struct passwd	*pp;
X#endif
X#ifdef LOG
X# ifdef USG
X	struct tms	cpu;
X# else not USG
X	struct rusage	me, kids;
X# endif not USG
X# ifdef TIMEOUT
X	void		timeout();
X# endif
X	
X	grps_acsd = arts_acsd = 0;
X#endif
X
X	/* Not all systems pass fd's 1 and 2 from inetd */
X
X	(void) close(1);
X	(void) close(2);
X	(void) dup(0);
X	(void) dup(0);
X
X	/* If we're ALONE, then we've already opened syslog */
X
X#ifndef ALONE
X# ifdef SYSLOG
X#  ifdef BSD_42
X	openlog("nntpd", LOG_PID);
X#  else
X	openlog("nntpd", LOG_PID, SYSLOG);
X#  endif
X# endif
X#endif
X
X#ifdef ALONE
X#ifndef USG
X	(void) signal(SIGCHLD, SIG_IGN);
X#endif not USG
X#endif
X
X	/* Ignore SIGPIPE, since we'll see closed connections with read */
X
X	(void) signal(SIGPIPE, SIG_IGN);
X
X	/* Get permissions and see if we can talk to this client */
X
X	host_access(&canread, &canpost, &canxfer, gdbuf);
X
X	if (gethostname(host, sizeof(host)) < 0)
X		(void) strcpy(host, "Amnesiac");
X
X	if (!canread && !canxfer) {
X		printf("%d %s NNTP server can't talk to you.  Goodbye.\r\n",
X			ERR_ACCESS, host);
X		(void) fflush(stdout);
X#ifdef LOG
X		syslog(LOG_INFO, "%s refused connection", hostname);
X#endif
X		exit(1);
X	}
X
X	/* If we can talk, proceed with initialization */
X
X	ngpermcount = get_nglist(&ngpermlist, gdbuf);
X
X#ifdef POSTER
X	pp = getpwnam(POSTER);
X	if (pp != NULL) {
X		uid_poster = pp->pw_uid;
X		gid_poster = pp->pw_gid;
X	} else
X#endif
X		uid_poster = gid_poster = 0;
X
X#ifndef FASTFORK
X	num_groups = 0;
X	num_groups = read_groups();	/* Read in the active file */
X#else
X	signal(SIGALRM, SIG_IGN);	/* Children don't deal with */
X					/* these things */
X#endif
X
X	art_fp = NULL;
X	argp = (char **) NULL;		/* for first time */
X
X#ifdef USG
X	(void) time(&start);
X	Tstart = (double) start;
X	timeptr = ctime(&start);
X#else not USG
X	(void) gettimeofday(&start, (struct timezone *)NULL);
X	Tstart = (double) start.tv_sec - ((double)start.tv_usec)/1000000.0;
X	timeptr = ctime(&start.tv_sec);
X#endif not USG
X	if ((cp = index(timeptr, '\n')) != NULL)
X		*cp = '\0';
X	else
X		timeptr = "Unknown date";
X
X	printf("%d %s NNTP server version %s ready at %s (%s).\r\n",
X		canpost ? OK_CANPOST : OK_NOPOST,
X		host, nntp_version,
X		timeptr,
X		canpost ? "posting ok" : "no posting");
X	(void) fflush(stdout);
X
X	/*
X	 * Now get commands one at a time and execute the
X	 * appropriate routine to deal with them.
X	 */
X
X#ifdef TIMEOUT
X	(void) signal(SIGALRM, timeout);
X	(void) alarm(TIMEOUT);
X#endif TIMEOUT
X
X	while (fgets(line, sizeof(line), stdin) != NULL) {
X#ifdef TIMEOUT
X		(void) alarm(0);
X#endif TIMEOUT
X
X		cp = index(line, '\r');		/* Zap CR-LF */
X		if (cp != NULL)
X			*cp = '\0';
X		else {
X			cp = index(line, '\n');
X			if (cp != NULL)
X				*cp = '\0';
X		}
X
X		if ((argnum = parsit(line, &argp)) == 0)
X			continue;		/* Null command */
X		else {
X			for (i = 0; i < NUMCMDS; ++i)
X				if (!strcasecmp(cmdtbl[i].cmd_name, argp[0]))
X					break;
X			if (i < NUMCMDS)
X				(*cmdtbl[i].cmd_fctn)(argnum, argp);
X			else {
X				if (!strcasecmp(argp[0], "quit"))
X					break;
X#ifdef LOG
X				syslog(LOG_INFO, "%s unrecognized %s",
X					hostname,
X					line);
X#endif
X				printf("%d Command unrecognized.\r\n",
X					ERR_COMMAND);
X				(void) fflush(stdout);
X			}
X		}
X#ifdef TIMEOUT
X		(void) alarm(TIMEOUT);
X#endif TIMEOUT
X	}
X
X	printf("%d %s closing connection.  Goodbye.\r\n", OK_GOODBYE, host);
X	(void) fflush(stdout);
X
X
X#ifdef LOG
X	if (ferror(stdout))
X		syslog(LOG_ERR, "%s disconnect: %m", hostname);
X
X#ifdef USG
X	(void) time(&finish);
X	Tfinish = (double) finish;
X
X#ifndef HZ
X#define	HZ	60.0	/* typical system clock ticks - param.h */
X#endif not HZ
X
X	(void) times(&cpu);
X	user = (double)(cpu.tms_utime + cpu.tms_cutime) / HZ;
X	sys  = (double)(cpu.tms_stime + cpu.tms_cstime) / HZ;
X#else not USG
X	(void) gettimeofday(&finish, (struct timezone *)NULL);
X	Tfinish = (double) finish.tv_sec - ((double)finish.tv_usec)/1000000.0;
X
X	(void) getrusage(RUSAGE_SELF, &me);
X	(void) getrusage(RUSAGE_CHILDREN, &kids);
X
X	user = (double) me.ru_utime.tv_sec + me.ru_utime.tv_usec/1000000.0 +
X		kids.ru_utime.tv_sec + kids.ru_utime.tv_usec/1000000.0;
X	sys = (double) me.ru_stime.tv_sec + me.ru_stime.tv_usec/1000000.0 +
X		kids.ru_stime.tv_sec + kids.ru_stime.tv_usec/1000000.0;
X#endif not USG
X	if (grps_acsd)
X		syslog(LOG_INFO, "%s exit %d articles %d groups",
X			hostname, arts_acsd, grps_acsd);
X	if (nn_told)
X		syslog(LOG_INFO, "%s newnews_stats told %d took %d",
X			hostname, nn_told, nn_took);
X	if (ih_accepted || ih_rejected || ih_failed)
X		syslog(LOG_INFO,
X			"%s ihave_stats accepted %d rejected %d failed %d",
X			hostname,
X			ih_accepted,
X			ih_rejected,
X			ih_failed);
X	(void) sprintf(line, "user %.1f system %.1f elapsed %.1f",
X		user, sys, Tfinish - Tstart);
X	syslog(LOG_INFO, "%s times %s", hostname, line);
X#endif LOG
X
X#ifdef PROFILE
X	profile();
X#endif
X
X	exit(0);
X}
X
X
X#ifdef TIMEOUT
X/*
X * No activity for TIMEOUT seconds, so print an error message
X * and close the connection.
X */
X
void
timeout()
X{
X	printf("%d Timeout after %d seconds, closing connection.\r\n",
X		ERR_FAULT, TIMEOUT);
X	(void) fflush(stdout);
X
X#ifdef LOG
X	syslog(LOG_ERR, "%s timeout", hostname);
X#endif LOG
X
X	exit(1);
X}
X#endif TIMEOUT
END_OF_FILE
if test 6497 -ne `wc -c <'./server/serve.c'`; then
    echo shar: \"'./server/serve.c'\" unpacked with wrong size!
fi
# end of './server/serve.c'
fi
if test -f './server/subnet.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./server/subnet.c'\"
else
echo shar: Extracting \"'./server/subnet.c'\" \(6358 characters\)
sed "s/^X//" >'./server/subnet.c' <<'END_OF_FILE'
X#ifndef lint
static	char	*sccsid = "@(#)subnet.c	1.5	(Berkeley) 1/4/88";
X#endif
X
X#include "../common/conf.h"
X
X#ifdef SUBNET
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#ifndef NETMASK
X#include <net/if.h>
X#endif
X#include <sys/ioctl.h>
X
X/*
X * The following routines provide a general interface for
X * subnet support.  Like the library function "inet_netof",
X * which returns the standard (i.e., non-subnet) network
X * portion of an internet address, "inet_snetof" returns
X * the subnetwork portion -- if there is one.  If there
X * isn't, it returns 0.
X *
X * Subnets, under 4.3, are specific to a given set of
X * machines -- right down to the network interfaces.
X * Because of this, the function "getifconf" must be
X * called first.  This routine builds a table listing
X * all the (internet) interfaces present on a machine,
X * along with their subnet masks.  Then when inet_snetof
X * is called, it can quickly scan this table.
X *
X * Unfortunately, there "ain't no graceful way" to handle
X * certain situations.  For example, the kernel permits
X * arbitrary subnet bits -- that is, you could have a
X * 22 bit network field and a 10 bit subnet field.
X * However, due to braindamage at the user level, in
X * such sterling routines as getnetbyaddr, you need to
X * have a subnet mask which is an even multiple of 8.
X * Unless you are running with class C subnets, in which
X * case it should be a multiple of 4.  Because of this rot,
X * if you have non-multiples of 4 bits of subnet, you should
X * define DAMAGED_NETMASK when you compile.  This will round
X * things off to a multiple of 8 bits.
X *
X * Finally, you may want subnet support even if your system doesn't
X * support the ioctls to get subnet mask information.  If you want
X * such a thing, you can define NETMASK to be a constant that is
X * the subnet mask for your network.
X *
X * And don't *even* get me started on how the definitions of the inet_foo()
X * routines changed between 4.2 and 4.3, making internet addresses
X * be unsigned long vs. struct in_addr.  Don't blame me if this
X * won't lint...
X */
X
X/*
X * One structure for each interface, containing
X * the network number and subnet mask, stored in HBO.
X */
struct in_if {
X	u_long	i_net;		/* Network number, shifted right */
X	u_long	i_subnetmask;	/* Subnet mask for this if */
X	int	i_bitshift;	/* How many bits right for outside */
X};
X
X/*
X * Table (eventually, once we malloc) of
X * internet interface subnet informaiton.
X */
static	struct in_if	*in_ifsni;
X
static	int		if_count;
X
X/*
X * Get the network interface configuration,
X * and squirrel away the network numbers and
X * subnet masks of each interface.  Return
X * number of interfaces found, or -1 on error.
X * N.B.: don't call this more than once...
X */
X
getifconf()
X{
X#ifndef NETMASK
X	register int	i, j;
X	int		s;
X	struct ifconf	ifc;
X	char		buf[1024];
X	register struct ifreq	*ifr;
X	u_long		inet_netof();
X	u_long		addr;
X
X	/*
X	 * Find out how many interfaces we have, and malloc
X	 * room for information about each one.
X	 */
X
X	s = socket(AF_INET, SOCK_DGRAM, 0);
X	if (s < 0)
X		return (-1);
X
X	ifc.ifc_buf = buf;
X	ifc.ifc_len = sizeof (buf);
X
X	if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
X		(void) close(s);
X		return (-1);
X	}
X
X	/*
X	 * if_count here is the count of possible
X	 * interfaces we may be interested in... actual
X	 * interfaces may be less (some may not be internet,
X	 * not all are necessarily up, etc.)
X	 */
X
X	if_count = ifc.ifc_len / sizeof (struct ifreq);
X
X	in_ifsni = (struct in_if *) malloc(if_count * sizeof (struct in_if));
X	if (in_ifsni == 0) {
X		(void) close(s);
X		return (-1);
X	}
X
X	for (i = j = 0; i < if_count; ++i) {
X		ifr = &ifc.ifc_req[i];
X		if (ioctl(s, SIOCGIFFLAGS, ifr) < 0)
X			continue;
X		if ((ifr->ifr_flags & IFF_UP) == 0)
X			continue;
X		if (ioctl(s, SIOCGIFADDR, ifr) < 0)
X			continue;
X		if (ifr->ifr_addr.sa_family != AF_INET)
X			continue;
X		addr = (*(struct sockaddr_in *)&ifr->ifr_addr).sin_addr.s_addr;
X		in_ifsni[j].i_net = inet_netof(addr);
X		if (ioctl(s, SIOCGIFNETMASK, ifr) < 0)
X			continue;
X		in_ifsni[j].i_subnetmask =
X		 ntohl((*(struct sockaddr_in *)&ifr->ifr_addr).sin_addr.s_addr);
X		/*
X		 * The following should "never happen".  But under SunOs
X		 * 3.4, along with the rest of their broken networking code,
X		 * SIOCGIFNETMASK can get a netmask which is 0.  There
X		 * really isn't anything that "right" that we can do
X		 * about it, so we'll set their subnet mask to be their
X		 * *net*work mask.  Which may or may not be right.
X		 */
X		if (in_ifsni[j].i_subnetmask == 0) {
X			addr = ntohl(addr);
X			if (IN_CLASSA(addr))
X				in_ifsni[j].i_subnetmask = IN_CLASSA_NET;
X			else if (IN_CLASSB(addr))
X				in_ifsni[j].i_subnetmask = IN_CLASSB_NET;
X			else if (IN_CLASSC(addr))
X				in_ifsni[j].i_subnetmask = IN_CLASSC_NET;
X			else			/* what to do ... */
X				in_ifsni[j].i_subnetmask = IN_CLASSC_NET;
X		} else
X			in_ifsni[j].i_bitshift = bsr(in_ifsni[j].i_subnetmask);
X		j++;
X	}
X
X	if_count = j;
X
X	(void) close(s);
X
X	return (if_count);
X
X#else	/* hard-coded subnets */
X
X	if_count = 1;
X
X	in_ifsni = (struct in_if *) malloc(if_count * sizeof (struct in_if));
X	if (in_ifsni == 0) {
X		return (-1);
X	}
X	in_ifsni[0].i_net = 0;
X	in_ifsni[0].i_subnetmask = NETMASK;
X	in_ifsni[0].i_bitshift = bsr(in_ifsni[0].i_subnetmask);
X	return (if_count);
X#endif
X}
X
X
X/*
X * Return the (sub)network number from an internet address.
X * "in" is in NBO, return value in host byte order.
X * If "in" is not a subnet, return 0.
X */
X
u_long
inet_snetof(in)
X	u_long	in;
X{
X	register int	j;
X	register u_long	i = ntohl(in);
X	register u_long	net;
X	u_long		inet_netof(), inet_lnaof();
X
X	net = inet_netof(in);
X
X	/*
X	 * Check whether network is a subnet;
X	 * if so, return subnet number.
X	 */
X	for (j = 0; j < if_count; ++j)
X#ifdef NETMASK
X		if (1) {
X#else
X		if (net == in_ifsni[j].i_net) {
X#endif
X			net = i & in_ifsni[j].i_subnetmask;
X			if (inet_lnaof(htonl(net)) == 0)
X				return (0);
X			else
X				return (net >> in_ifsni[j].i_bitshift);
X		}
X
X	return (0);
X}
X
X
X/*
X * Return the number of bits required to
X * shift right a mask into a getnetent-able entitity.
X */
X
bsr(mask)
X	register int	mask;
X{
X	register int	count = 0;
X
X	if (mask == 0)		/* "never happen", except with SunOs 3.4 */
X		return (0);
X
X	while ((mask & 1) == 0) {
X		++count;
X		mask >>= 1;
X	}
X#ifdef DAMAGED_NETMASK
X	count /= 8;			/* XXX gag retch puke barf */
X	count *= 8;
X#endif
X	return (count);
X}
X
X#endif
END_OF_FILE
if test 6358 -ne `wc -c <'./server/subnet.c'`; then
    echo shar: \"'./server/subnet.c'\" unpacked with wrong size!
fi
# end of './server/subnet.c'
fi
if test -f './xmit/get_tcp_conn.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./xmit/get_tcp_conn.c'\"
else
echo shar: Extracting \"'./xmit/get_tcp_conn.c'\" \(7210 characters\)
sed "s/^X//" >'./xmit/get_tcp_conn.c' <<'END_OF_FILE'
X/*
X** Routines to open a TCP connection
X**
X** New version that supports the old (pre 4.2 BSD) socket calls,
X** and systems with the old (pre 4.2 BSD) hostname lookup stuff.
X** Compile-time options are:
X**
X**	USG		- you're on System III/V (you have my sympathies)
X**	NONETDB		- old hostname lookup with rhost()
X**	OLDSOCKET	- different args for socket() and connect()
X**
X** Erik E. Fair <fair@ucbarpa.berkeley.edu>
X**
X*/
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <ctype.h>
X#include <stdio.h>
X#include "get_tcp_conn.h"
X#ifndef	NONETDB
X#include <netdb.h>
X#endif	NONETDB
X
extern	int	errno;
extern	char	*Pname;
extern	char	*errmsg();
X#ifndef	htons
extern	u_short	htons();
X#endif	htons
X#ifndef	NONETDB
extern	char	*inet_ntoa();
extern	u_long	inet_addr();
X#else
X/*
X * inet_addr for EXCELAN (which does not have it!)
X *
X */
u_long
inet_addr(cp)
register char	*cp;
X{
X	u_long val, base, n;
X	register char c;
X 	u_long octet[4], *octetptr = octet;
X#ifndef	htonl
X	extern	u_long	htonl();
X#endif	htonl
again:
X	/*
X	 * Collect number up to ``.''.
X	 * Values are specified as for C:
X	 * 0x=hex, 0=octal, other=decimal.
X	 */
X	val = 0; base = 10;
X	if (*cp == '0')
X		base = 8, cp++;
X	if (*cp == 'x' || *cp == 'X')
X		base = 16, cp++;
X	while (c = *cp) {
X		if (isdigit(c)) {
X			val = (val * base) + (c - '0');
X			cp++;
X			continue;
X		}
X		if (base == 16 && isxdigit(c)) {
X			val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
X			cp++;
X			continue;
X		}
X		break;
X	}
X	if (*cp == '.') {
X		/*
X		 * Internet format:
X		 *	a.b.c.d
X		 *	a.b.c	(with c treated as 16-bits)
X		 *	a.b	(with b treated as 24 bits)
X		 */
X		if (octetptr >= octet + 4)
X			return (-1);
X		*octetptr++ = val, cp++;
X		goto again;
X	}
X	/*
X	 * Check for trailing characters.
X	 */
X	if (*cp && !isspace(*cp))
X		return (-1);
X	*octetptr++ = val;
X	/*
X	 * Concoct the address according to
X	 * the number of octet specified.
X	 */
X	n = octetptr - octet;
X	switch (n) {
X
X	case 1:				/* a -- 32 bits */
X		val = octet[0];
X		break;
X
X	case 2:				/* a.b -- 8.24 bits */
X		val = (octet[0] << 24) | (octet[1] & 0xffffff);
X		break;
X
X	case 3:				/* a.b.c -- 8.8.16 bits */
X		val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
X			(octet[2] & 0xffff);
X		break;
X
X	case 4:				/* a.b.c.d -- 8.8.8.8 bits */
X		val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
X		      ((octet[2] & 0xff) << 8) | (octet[3] & 0xff);
X		break;
X
X	default:
X		return (-1);
X	}
X	val = htonl(val);
X	return (val);
X}
X
char *
inet_ntoa(in)
struct in_addr in;
X{
X	static char address[20];
X
X	sprintf(address, "%u.%u.%u.%u",
X			 (in.s_addr>>24)&0xff,
X			 (in.s_addr>>16)&0xff,
X			 (in.s_addr>>8 )&0xff,
X			 (in.s_addr    )&0xff);
X	return(address);
X}
X#endif	NONETDB
X
X#ifdef	USG
void
bcopy(s, d, l)
register caddr_t s, d;
register int l;
X{
X	while (l-- > 0)	*d++ = *s++;
X}
X#endif	USG
X
X/*
X** Take the name of an internet host in ASCII (this may either be its
X** official host name or internet number (with or without enclosing
X** backets [])), and return a list of internet addresses.
X**
X** returns NULL for failure to find the host name in the local database,
X** or for a bad internet address spec.
X*/
u_long **
name_to_address(host)
char	*host;
X{
X	static	u_long	*host_addresses[2];
X	static	u_long	haddr;
X
X	if (host == (char *)NULL) {
X		return((u_long **)NULL);
X	}
X
X	host_addresses[0] = &haddr;
X	host_addresses[1] = (u_long *)NULL;
X
X	/*
X	** Is this an ASCII internet address? (either of [10.0.0.78] or
X	** 10.0.0.78). We get away with the second test because hostnames
X	** and domain labels are not allowed to begin in numbers.
X	** (cf. RFC952, RFC882).
X	*/
X	if (*host == '[' || isdigit(*host)) {
X		char	namebuf[128];
X		register char	*cp = namebuf;
X
X		/*
X		** strip brackets [] or anything else we don't want.
X		*/
X		while(*host != '\0' && cp < &namebuf[sizeof(namebuf)]) {
X			if (isdigit(*host) || *host == '.')
X				*cp++ = *host++;	/* copy */
X			else
X				host++;			/* skip */
X		}
X		*cp = '\0';
X		haddr = inet_addr(namebuf);
X		return(&host_addresses[0]);
X	} else {
X#ifdef	NONETDB
X		extern	u_long	rhost();
X
X		/* lint is gonna bitch about this (comparing an unsigned?!) */
X		if ((haddr = rhost(&host)) == FAIL)
X			return((u_long **)NULL);	/* no such host */
X		return(&host_addresses[0]);
X#else
X		struct hostent	*hstp = gethostbyname(host);
X
X		if (hstp == NULL) {
X			return((u_long **)NULL);	/* no such host */
X		}
X
X		if (hstp->h_length != sizeof(u_long))
X			abort();	/* this is fundamental */
X#ifndef	h_addr
X		/* alignment problems (isn't dbm wonderful?) */
X		bcopy((caddr_t)hstp->h_addr, (caddr_t)&haddr, sizeof(haddr));
X		return(&host_addresses[0]);
X#else
X		return((u_long **)hstp->h_addr_list);
X#endif	h_addr
X#endif	NONETDB
X	}
X}
X
X/*
X** Get a service port number from a service name (or ASCII number)
X**
X** Return zero if something is wrong (that's a reserved port)
X*/
X#ifdef	NONETDB
static struct Services {
X	char	*name;
X	u_short	port;
X} Services[] = {
X	{"nntp",	IPPORT_NNTP},		/* RFC977 */
X	{"smtp",	IPPORT_SMTP},		/* RFC821 */
X	{"name",	IPPORT_NAMESERVER},	/* RFC881, RFC882, RFC883 */
X	{"time",	IPPORT_TIMESERVER},	/* RFC868 */
X	{"echo",	IPPORT_ECHO},		/* RFC862 */
X	{"discard",	IPPORT_DISCARD},	/* RFC863 */
X	{"daytime",	IPPORT_DAYTIME},	/* RFC867 */
X	{"login",	IPPORT_LOGINSERVER},	/* N/A - 4BSD specific */
X};
X#endif	NONETDB
X
u_short
gservice(serv, proto)
char	*serv, *proto;
X{
X	if (serv == (char *)NULL || proto == (char *)NULL)
X		return((u_short)0);
X
X	if (isdigit(*serv)) {
X		return(htons((u_short)(atoi(serv))));
X	} else {
X#ifdef	NONETDB
X		register int	i;
X
X		for(i = 0; i < (sizeof(Services) / sizeof(struct Services)); i++) {
X			if (strcmp(serv, Services[i].name) == 0)
X				return(htons(Services[i].port));
X		}
X		return((u_short)0);
X#else
X		struct servent	*srvp = getservbyname(serv, proto);
X
X		if (srvp == (struct servent *)NULL)
X			return((u_short)0);
X		return((u_short)srvp->s_port);
X#endif	NONETDB
X	}
X}
X
X/*
X** given a host name (either name or internet address) and service name
X** (or port number) (both in ASCII), give us a TCP connection to the
X** requested service at the requested host (or give us FAIL).
X*/
get_tcp_conn(host, serv)
char	*host, *serv;
X{
X	register int	sock;
X	u_long	**addrlist;
X	struct sockaddr_in	sadr;
X#ifdef	OLDSOCKET
X	struct sockproto	sp;
X
X	sp.sp_family	= (u_short)AF_INET;
X	sp.sp_protocol	= (u_short)IPPROTO_TCP;
X#endif	OLDSOCKET
X
X	if ((addrlist = name_to_address(host)) == (u_long **)NULL) {
X		return(NOHOST);
X	}
X
X	sadr.sin_family = (u_short)AF_INET;	/* Only internet for now */
X	if ((sadr.sin_port = gservice(serv, "tcp")) == 0)
X		return(NOSERVICE);
X
X	for(; *addrlist != (u_long *)NULL; addrlist++) {
X		bcopy((caddr_t)*addrlist, (caddr_t)&sadr.sin_addr,
X			sizeof(sadr.sin_addr));
X
X#ifdef	OLDSOCKET
X		if ((sock = socket(SOCK_STREAM, &sp, (struct sockaddr *)NULL, 0)) < 0)
X			return(FAIL);
X
X		if (connect(sock, (struct sockaddr *)&sadr) < 0) {
X#else
X		if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
X			return(FAIL);
X
X		if (connect(sock, (struct sockaddr *)&sadr, sizeof(sadr)) < 0) {
X#endif	OLDSOCKET
X			int	e_save = errno;
X
X			fprintf(stderr, "%s: %s [%s]: %s\n", Pname, host,
X				inet_ntoa(sadr.sin_addr), errmsg(errno));
X			(void) close(sock);	/* dump descriptor */
X			errno = e_save;
X		} else
X			return(sock);
X	}
X	return(FAIL);
X}
END_OF_FILE
if test 7210 -ne `wc -c <'./xmit/get_tcp_conn.c'`; then
    echo shar: \"'./xmit/get_tcp_conn.c'\" unpacked with wrong size!
fi
# end of './xmit/get_tcp_conn.c'
fi
if test -f './xmit/shlock.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./xmit/shlock.c'\"
else
echo shar: Extracting \"'./xmit/shlock.c'\" \(6278 characters\)
sed "s/^X//" >'./xmit/shlock.c' <<'END_OF_FILE'
X/*
X** Program to produce reliable locks for shell scripts.
X** Algorithmn suggested by Peter Honeyman, January 1984,
X** in connection with HoneyDanBer UUCP.
X**
X** I tried extending this to handle shared locks in November 1987,
X** and ran into to some fundamental problems:
X**
X**	Neither 4.3 BSD nor System V have an open(2) with locking,
X**	so that you can open a file and have it locked as soon as
X**	it's real; you have to make two system calls, and there's
X**	a race...
X**
X**	When removing dead process id's from a list in a file,
X**	you need to truncate the file (you don't want to create a
X**	new one; see above); unfortunately for the portability of
X**	this program, only 4.3 BSD has ftruncate(2).
X**
X** Erik E. Fair <fair@ucbarpa.berkeley.edu>, November 8, 1987
X*/
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <fcntl.h>			/* Needed on hpux */
X#include <sys/file.h>
X#include <errno.h>
X
X#define	LOCK_SET	0
X#define	LOCK_FAIL	1
X
X#define	FAIL		(-1)
X
X#define	TRUE	1
X#define	FALSE	0
X
X#ifdef USG
X#define	index	strchr
X#define	rindex	strrchr
X#endif
X
int	Debug = FALSE;
char	*Pname;
char	*USAGE = "%s: USAGE: shlock -f file -p pid [-d]\n";
char	*errmsg();
char	*xtmpfile();
X
X#define	dprintf	if (Debug) printf
X
extern	int	errno;
extern	char	*rindex();
extern	char	*strcpy();
extern	char	*strcat();
X
main(ac, av)
int	ac;
char	*av[];
X{
X	register int	x;
X	char	*file;
X	int	pid;
X
X	Pname = ((Pname = rindex(av[0], '/')) ? Pname + 1 : av[0]);
X
X	for(x = 1; x < ac; x++) {
X		if (av[x][0] == '-') {
X			switch(av[x][1]) {
X			case 'd':
X				Debug = TRUE;
X				break;
X			case 'p':
X				if (strlen(av[x]) > 2) {
X					pid = atoi(&av[x][2]);
X				} else {
X					pid = atoi(av[++x]);
X				}
X				break;
X			case 'f':
X				if (strlen(av[x]) > 2) {
X					file = &av[x][2];
X				} else {
X					file = av[++x];
X				}
X				break;
X			default:
X				fprintf(stderr, USAGE, Pname);
X				exit(LOCK_FAIL);
X			}
X		}
X	}
X	if (pid == 0 || file == (char *)NULL) {
X		fprintf(stderr, USAGE, Pname);
X		exit(LOCK_FAIL);
X	}
X
X	exit(mklock(file, pid) ? LOCK_SET : LOCK_FAIL);
X}
X
char *
errmsg(n)
register int	n;
X{
X	extern	int	sys_nerr;
X	extern 	char	*sys_errlist[];
X
X	return((n >= 0 && n < sys_nerr) ? sys_errlist[n] : "unknown error");
X}
X
mklock(file, pid)
char	*file;
int	pid;
X{
X	register char	*tmp;
X	register int	retcode = FALSE;
X	char	*e_unlk = "%s: unlink(%s): %s\n";
X
X	dprintf("%s: trying lock <%s> for process %d\n", Pname, file, pid);
X	if ((tmp = xtmpfile(file, pid)) == (char *)NULL)
X		return(FALSE);
X
linkloop:
X	if (link(tmp, file) < 0) {
X		switch(errno) {
X		case EEXIST:
X			dprintf("%s: lock <%s> already exists\n", Pname, file);
X			if (cklock(file)) {
X				dprintf("%s: extant lock is valid\n", Pname);
X				break;
X			} else {
X				dprintf("%s: lock is invalid, removing\n",
X					Pname);
X				if (unlink(file) < 0) {
X					fprintf(stderr, e_unlk,
X						Pname, file, errmsg(errno));
X					break;
X				}
X			}
X			/*
X			** I hereby profane the god of structured programming,
X			** Edsgar Dijkstra
X			*/
X			goto linkloop;
X		default:
X			fprintf(stderr, "%s: link(%s, %s): %s\n",
X				Pname, tmp, file, errmsg(errno));
X			break;
X		}
X	} else {
X		dprintf("%s: got lock <%s>\n", Pname, file);
X		retcode = TRUE;
X	}
X	if (unlink(tmp) < 0) {
X		fprintf(stderr, e_unlk, Pname, tmp, errmsg(errno));
X	}
X	return(retcode);
X}
X
X/*
X** Does the PID exist?
X** Send null signal to find out.
X*/
p_exists(pid)
int	pid;
X{
X	dprintf("%s: process %d is ", Pname, pid);
X	if (pid <= 0) {
X		dprintf("invalid\n");
X		return(FALSE);
X	}
X	if (kill(pid, 0) < 0) {
X		switch(errno) {
X		case ESRCH:
X			dprintf("dead\n");
X			return(FALSE);	/* pid does not exist */
X		case EPERM:
X			dprintf("alive\n");
X			return(TRUE);	/* pid exists */
X		default:
X			dprintf("state unknown: %s\n", errmsg(errno));
X			return(TRUE);	/* be conservative */
X		}
X	}
X	dprintf("alive\n");
X	return(TRUE);	/* pid exists */
X}
X
X/*
X** Check the validity of an existing lock file.
X**
X**	Read the PID out of the lock
X**	Send a null signal to determine whether that PID still exists
X**	Existence (or not) determines the validity of the lock.
X**
X**	Two bigs wins to this algorithmn:
X**
X**	o	Locks do not survive crashes of either the system or the
X**			application by any appreciable period of time.
X**
X**	o	No clean up to do if the system or application crashes.
X**
X*/
X
cklock(file)
char	*file;
X{
X	register int	fd = open(file, O_RDONLY);
X	register int	len;
X	char	buf[BUFSIZ];
X
X	dprintf("%s: checking extant lock <%s>\n", Pname, file);
X	if (fd < 0) {
X		fprintf(stderr,"%s: open(%s): %s\n", Pname, file, errmsg(errno));
X		return(TRUE);	/* might or might not; conservatism */
X	}
X
X	if ((len = read(fd, buf, sizeof(buf))) <= 0) {
X		close(fd);
X		dprintf("%s: lock file format error\n", Pname);
X		return(FALSE);
X	}
X	close(fd);
X	buf[len + 1] = '\0';
X	return(p_exists(atoi(buf)));
X}
X
X/*
X** Create a temporary file, all ready to lock with.
X** The file arg is so we get the filename right, if he
X** gave us a full path, instead of using the current directory
X** which might not be in the same filesystem.
X*/
char *
xtmpfile(file, pid)
char	*file;
int	pid;
X{
X	register int	fd;
X	register int	len;
X	char	*cp, buf[BUFSIZ];
X	static char	tempname[BUFSIZ];
X
X	sprintf(buf, "shlock%d", getpid());
X	if ((cp = rindex(strcpy(tempname, file), '/')) != (char *)NULL) {
X		*++cp = '\0';
X		(void) strcat(tempname, buf);
X	} else
X		(void) strcpy(tempname, buf);
X	dprintf("%s: temporary filename: %s\n", Pname, tempname);
X
X	sprintf(buf, "%d\n", pid);
X	len = strlen(buf);
openloop:
X	if ((fd = open(tempname, O_RDWR|O_CREAT|O_EXCL, 0644)) < 0) {
X		switch(errno) {
X		case EEXIST:
X			dprintf("%s: file %s exists already.\n",
X				Pname, tempname);
X			if (unlink(tempname) < 0) {
X				fprintf(stderr, "%s: unlink(%s): %s\n",
X					Pname, tempname, errmsg(errno));
X				return((char *)NULL);
X			}
X			/*
X			** Further profanity
X			*/
X			goto openloop;
X		default:
X			fprintf(stderr, "%s: open(%s): %s\n",
X				Pname, tempname, errmsg(errno));
X			return((char *)NULL);
X		}
X	}
X
X	/*
X	** Write the PID into the temporary file before attempting to link
X	** to the actual lock file. That way we have a valid lock the instant
X	** the link succeeds.
X	*/
X	if (write(fd, buf, len) < 0) {
X		fprintf(stderr, "%s: write(%s,%d): %s\n",
X			Pname, tempname, pid, errmsg(errno));
X		(void) close(fd);
X		return((char *)NULL);
X	}
X	(void) close(fd);
X	return(tempname);
X}
END_OF_FILE
if test 6278 -ne `wc -c <'./xmit/shlock.c'`; then
    echo shar: \"'./xmit/shlock.c'\" unpacked with wrong size!
fi
# end of './xmit/shlock.c'
fi
echo shar: End of archive 5 \(of 9\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 9 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.