[news.software.nntp] XBATCH - transfer compressed batches via NNTP

sjg@melb.bull.oz.au (Simon J. Gerraty) (04/02/91)

Sorry for the long delay,  this article contains the patches to
nntpd  to add the XBATCH command.  We use this to receive
compressed batches from the US.  Your mileage may vary but we
have seen our news transfer times drop from 12+ hours to 2-3
hours using XBATCH.

As indicated in the README.XBATCH file the NNTPD version 2 draft
describes a BATCH command that should obsolete XBATCH, but you
can have XBATCH now anyway.

The following article (I may split it in two) contains the
XBATCH client software developed by Frank Mayhar
fmayhar@hermes.ladc.bull.com

We would of course like to be kept informed of changes,
improvements bug fixes etc.  Hopefully you will find this simple
to install (as we have real jobs to do, so would hope not to
have to many "it won't go in" qestions :-)

Enjoy!

#! /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 shell archive."
# Contents:  README.XBATCH xbatch.diffs
# Wrapped by sjg@taureau.melb.bull.oz.au on Tue Apr  2 12:51:57 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README.XBATCH -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README.XBATCH\"
else
echo shar: Extracting \"README.XBATCH\" \(3622 characters\)
sed "s/^X//" >README.XBATCH <<'END_OF_README.XBATCH'
XXBATCH README		April 2, 1991  (NNTP 1.5.10)
X
XThe file xbatch.diffs contains patches to 
X./common/nntp.h
X./server/help.c
X./server/access.c
X./server/batch.c
X./server/serve.c
X 
Xthat implement a new NNTP server command XBATCH.
X
XXBATCH allows transfer of complete batches via NNTP.
XThe batches are not intererated by nntp in any way at all.  They
Xare simply received and enqueued for injection into news.
X
XThe aim is of course to be able to transfer compressed batches
Xvia NNTP.  XBATCH achieves this admirably.  There has been
Xdiscussion in the news about the benefits of compressed batches
Xvs ihave/sendme etc.  The concensus seemed to be that compressed
Xbatches were not needed.  However it seemed to me that most folk
Xholding that opinion were probably at sites with nice fast
Xreliable IP links.
X
Xtaureau.melb.bull.oz.au receives news from ladcgw.ladc.bull.com
X(LA) via a NNTP.  The link at times is very slow and sometimes
Xunreliable.  At one stage we had to severely restrict the feed
Xto be able to transfer a days worth of news within 24 hours!
XUsing compressed batches via XBATCH, the same amount of news
Xis typically transferred in 2-3 hours.
X
XThe server patches were done by myself.  I have allowed for the
Xaddition of extra permission checks for xbatch, but have not
Ximplemented them myself.  The other major change is that NNTPD
Xdoes not fork newsrun each time in enqueues a batch (using
Xxbatch the normal NNTPD behavior remains for normal usage).
X
XThe xbatch client software was developed by Frank Mayhar
Xfmayhar@hermes.ladc.bull.com,  it is contained in a separate
Xshell archive complete with Manual pages etc.  See the README
Xfile and man pages for details of the client side.
X
XThe functionality provided by XBATCH will (hopefully) soon be
Xreplaced by the BATCH command of the NNTP v2 specification.
XXBATCH is simple to install and is dedicated to the Public
XDomain in the hope it should prove a useful interim solution to
Xthose with slow or unreliable IP links.
X
XBelow is the description of xbatch from the source:
X
XNAME:
X     xbatch - accept complete batches
X
XSYNOPSIS:
X     xbatch size
X     
XDESCRIPTION:
X     This function receives complete batches from the client 
X     and injects them into the Cnews input queue.  It uses 
X     the same enqueue() routine as the normal 
X     batch_input_article().   However, for efficiency this 
X     routine disables the exec'ing of "newsrun".
X
X     xbatch takes a single argument "nbytes" which is the 
X     size in bytes of the batch to be transfered.  NNTP is 
X     expected to simpy copy and enqueue this many bytes from 
X     stdin. 
X     
X     Using xbatch, the time taken to transfer news from 
X     ladcgw.ladc.bull.com to taureau.melb.bull.oz.au 
X     is reduced by a number of hours.
X     
X     The possible? client/server conversations look like:
X     C: XBATCH nbytes
X     S: 339 Ok
X     C: sends "nbytes" of data
X     S: 239 Batch transfered successfully.
X     
X     The client has the option of sending another batch.
X     
X     C: XBATCH nbytes
X     S: 339 Ok
X     C: sends "nbytes" of data
X     S: 436 xbatch failed: [extra data]
X     
X     The client can try to re-send the current batch.
X     The following can happen any time, and may well occur 
X     after a failed transfer.
X     
X     C: XBATCH nbytes
X     S: 400 xbatch failed: [extra data], goodbye.
X
X     The client should call back later.
X     
X     C: XBATCH nbytes
X     S: 449 Sorry, you are not allowed to transfer batches.
X     
X     The client should not bother trying again.
X
X     Please send copies of updates to this code to:
X     <sjg@melb.bull.oz.au>
X     
XRETURN VALUE:
X     None
X
X
X
END_OF_README.XBATCH
if test 3622 -ne `wc -c <README.XBATCH`; then
    echo shar: \"README.XBATCH\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f xbatch.diffs -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"xbatch.diffs\"
else
echo shar: Extracting \"xbatch.diffs\" \(14658 characters\)
sed "s/^X//" >xbatch.diffs <<'END_OF_xbatch.diffs'
X*** ./common/nntp.h.orig	Tue Apr  2 10:44:06 1991
X--- ./common/nntp.h	Mon Feb 11 11:45:39 1991
X***************
X*** 2,7 ****
X--- 2,8 ----
X   * Response codes for NNTP server
X   *
X   * @(#)$Header: nntp.h,v 1.8 90/07/05 02:08:31 sob Exp $
X+  * @(#)nntp.h	1.2 91/02/11 12:45:37 (root)
X   *
X   * First digit:
X   *
X***************
X*** 45,55 ****
X--- 46,58 ----
X  #define	OK_NEWNEWS	230	/* New articles by message-id follow */
X  #define	OK_NEWGROUPS	231	/* New newsgroups follow */
X  #define	OK_XFERED	235	/* Article transferred successfully */
X+ #define	OK_XBATCHED	239	/* Batch transferred successfully */
X  #define	OK_POSTED	240	/* Article posted successfully */
X  #define	OK_AUTHSYS	280	/* Authorization system ok */
X  #define	OK_AUTH		281	/* Authorization (user/pass) ok */
X  
X  #define	CONT_XFER	335	/* Continue to send article */
X+ #define	CONT_XBATCH	339	/* Continue to send batch */
X  #define	CONT_POST	340	/* Continue to post article */
X  #define	NEED_AUTHINFO	380	/* authorization is required */
X  #define	NEED_AUTHDATA	381	/* <type> authorization data required */
X***************
X*** 67,72 ****
X--- 70,76 ----
X  #define	ERR_XFERRJCT	437	/* Article rejected, don't resend */
X  #define	ERR_NOPOST	440	/* Posting not allowed */
X  #define	ERR_POSTFAIL	441	/* Posting failed */
X+ #define	ERR_NOXBATCH	449	/* Batch transfer not allowed */
X  #define	ERR_NOAUTH	480	/* authorization required for command */
X  #define	ERR_AUTHSYS	481	/* Authorization system invalid */
X  #define	ERR_AUTHREJ	482	/* Authorization data rejected */
X*** ./server/help.c.orig	Tue Apr  2 10:32:30 1991
X--- ./server/help.c	Mon Feb 11 11:20:51 1991
X***************
X*** 21,28 ****
X  	printf("NEXT        POST         QUIT\r\n");
X  	printf("STAT        NEWGROUPS    HELP\r\n");
X  	printf("IHAVE       NEWNEWS      SLAVE\r\n");
X! 	printf("\r\nAdditionally, the following extention is supported:\r\n\r\n");
X  	printf("XHDR        Retrieve a single header line from a range of articles.\r\n");
X  	printf("\r\n");
X  	printf("Bugs to Stan Barber (Internet: nntp@tmc.edu; UUCP: ...!bcm!nntp)\r\n");
X  	printf(".\r\n");
X--- 21,29 ----
X  	printf("NEXT        POST         QUIT\r\n");
X  	printf("STAT        NEWGROUPS    HELP\r\n");
X  	printf("IHAVE       NEWNEWS      SLAVE\r\n");
X! 	printf("\r\nAdditionally, the following extentions are supported:\r\n\r\n");
X  	printf("XHDR        Retrieve a single header line from a range of articles.\r\n");
X+ 	printf("XBATCH <size> Transfer prepared news batches.\r\n");
X  	printf("\r\n");
X  	printf("Bugs to Stan Barber (Internet: nntp@tmc.edu; UUCP: ...!bcm!nntp)\r\n");
X  	printf(".\r\n");
X*** ./server/access.c.orig	Tue Apr  2 10:32:28 1991
X--- ./server/access.c	Mon Feb 11 11:21:16 1991
X***************
X*** 1,5 ****
X  #ifndef lint
X! static char	*sccsid = "@(#)$Header: access.c,v 1.23 90/08/10 22:58:39 sob Exp $";
X  #endif
X  
X  #include "common.h"
X--- 1,8 ----
X  #ifndef lint
X! static char	*sccsid[] ={
X! "@(#)$Header: access.c,v 1.23 90/08/10 22:58:39 sob Exp $",
X! "@(#)access.c	1.2 91/02/11 12:18:54 (root)"
X! };
X  #endif
X  
X  #include "common.h"
X***************
X*** 26,32 ****
X   *
X   *			"canxfer" is a pointer to storage for
X   *			an integer,which we set to 1 if the
X!  *			client can transfer news, 0 otherwise.
X   *
X   *			"gdlist" is a comma separated list of
X   *			newsgroups/distributions which the client
X--- 29,37 ----
X   *
X   *			"canxfer" is a pointer to storage for
X   *			an integer,which we set to 1 if the
X!  *			client can transfer news, 2 if they can 
X!  *                      send batches for passing straight to 
X!  *                      rnews,  0 otherwise.
X   *
X   *			"gdlist" is a comma separated list of
X   *			newsgroups/distributions which the client
X***************
X*** 70,75 ****
X--- 75,83 ----
X  
X  #ifdef DEBUG
X  	*canread = *canpost = *canxfer = 1;
X+ #ifdef XBATCH
X+ 	*canxfer = 2;
X+ #endif
X  	return;
X  #endif
X  
X***************
X*** 208,213 ****
X--- 216,225 ----
X  			(void) strcpy(gdlist, groups);
X  		}
X  	}
X+ #ifdef XBATCH
X+ 		if (*canxfer)
X+ 		  *canxfer = 2;
X+ #endif
X  /*
X   * The access check expects there to be spaces between the group names.
X   * In the access file, there are commas between the groupnames.
X*** ./server/batch.c.orig	Tue Apr  2 10:32:29 1991
X--- ./server/batch.c	Mon Feb 11 11:44:51 1991
X***************
X*** 1,5 ****
X  #ifndef lint
X! static	char	*rcsid = "@(#)Header: batch.c,v 1.5 90/08/02 13:32:10 sob Exp $";
X  #endif
X  /*
X   * Batch subroutine for Cnews.
X--- 1,8 ----
X  #ifndef lint
X! static	char	*rcsid[] = {
X! "@(#)Header: batch.c,v 1.5 90/08/02 13:32:10 sob Exp $",
X! "@(#)batch.c	1.3 91/02/11 12:44:48 (root)"
X! };
X  #endif
X  /*
X   * Batch subroutine for Cnews.
X***************
X*** 55,60 ****
X--- 58,65 ----
X  	off_t size;			/* current size */
X  } btch = { NULL, NULL, NO, 0, 0 };
X  
X+ static int do_newsrun=0;	/* don't do it  */
X+ 
X  /*
X   * stash stdin (up to ".") on the end of the batch input file.
X   * kick newsrun if the batch is non-empty and too big or too old.
X***************
X*** 85,90 ****
X--- 90,96 ----
X  	}
X  	if (btch.name == NULL)
X  		return 0;
X+ 
X  	tempfile[0] = '\0';
X  #ifdef UMASK
X  	(void) umask(UMASK);
X***************
X*** 99,105 ****
X  	if (tempfile[0] != '\0')
X  		(void) unlink(tempfile);
X  	if (status == 1 && oktorunbatch())
X! 		status = enqueue(cont_code, err_code, errbuf);
X  	return status;
X  }
X  
X--- 105,114 ----
X  	if (tempfile[0] != '\0')
X  		(void) unlink(tempfile);
X  	if (status == 1 && oktorunbatch())
X! 	{
X! 	  do_newsrun++;
X! 	  status = enqueue(cont_code, err_code, errbuf);
X! 	}
X  	return status;
X  }
X  
X***************
X*** 314,320 ****
X  
X  	if (btch.isopen && fstat(fileno(btch.file), &stbuf) >= 0) {
X  		if (btch.size > 0)
X! 			enqueue(cont_code, err_code, errbuf);
X  		else {
X  			(void) fclose(btch.file);
X  			btch.file = NULL;
X--- 323,331 ----
X  
X  	if (btch.isopen && fstat(fileno(btch.file), &stbuf) >= 0) {
X  		if (btch.size > 0)
X! 		{
X! 		  enqueue(cont_code, err_code, errbuf);
X! 		}
X  		else {
X  			(void) fclose(btch.file);
X  			btch.file = NULL;
X***************
X*** 408,413 ****
X--- 419,426 ----
X  	signal(SIGHUP, SIG_IGN);
X  	(void) fflush(stdout);
X  	(void) fflush(stderr);
X+ 	if (!do_newsrun)
X+ 	  exit(0);		/* that's all */
X  	newsrun = strsave(NEWSRUN);
X  	if (newsrun == NULL)
X  		newsrun = "/usr/lib/newsbin/input/newsrun";
X***************
X*** 438,440 ****
X--- 451,703 ----
X  #endif
X  
X  
X+ #ifdef XBATCH
X+ #ifndef DFUNIT
X+ # define DFUNIT 1024
X+ #endif
X+ 
X+ /* NAME:
X+  *	xbatch - accept complete batches
X+  *
X+  * SYNOPSIS:
X+  *      xbatch size
X+  *      
X+  * DESCRIPTION:
X+  *      This function receives complete batches from the client 
X+  *      and injects them into the Cnews input queue.  It uses 
X+  *      the same enqueue() routine as the normal 
X+  *      batch_input_article().   However, for efficiency this 
X+  *      routine disables the exec'ing of "newsrun".
X+  *
X+  *      xbatch takes a single argument "nbytes" which is the 
X+  *      size in bytes of the batch to be transfered.  NNTP is 
X+  *      expected to simpy copy and enqueue this many bytes from 
X+  *      stdin. 
X+  *      
X+  *      Using xbatch, the time taken to transfer news from 
X+  *      ladcgw.ladc.bull.com to taureau.melb.bull.oz.au 
X+  *      is reduced by a number of hours.
X+  *      
X+  *      The possible? client/server conversations look like:
X+  *      C: XBATCH nbytes
X+  *      S: 339 Ok
X+  *      C: sends "nbytes" of data
X+  *      S: 239 Batch transfered successfully.
X+  *      
X+  *      The client has the option of sending another batch.
X+  *      
X+  *      C: XBATCH nbytes
X+  *      S: 339 Ok
X+  *      C: sends "nbytes" of data
X+  *      S: 436 xbatch failed: [extra data]
X+  *      
X+  *      The client can try to re-send the current batch.
X+  *      The following can happen any time, and may well occur 
X+  *      after a failed transfer.
X+  *      
X+  *      C: XBATCH nbytes
X+  *      S: 400 xbatch failed: [extra data], goodbye.
X+  *
X+  *      The client should call back later.
X+  *      
X+  *      C: XBATCH nbytes
X+  *      S: 449 Sorry, you are not allowed to transfer batches.
X+  *      
X+  *      The client should not bother trying again.
X+  * 
X+  *      Please send copies of updates to this code to:
X+  *      <sjg@melb.bull.oz.au>
X+  *      
X+  * RETURN VALUE:
X+  *      None
X+  */
X+ void
X+ xbatch(argc, argv)
X+   int	argc;
X+   char	*argv[];
X+ {
X+   char		errbuf[2 * NNTP_STRLEN];
X+   int		retcode = 1;
X+   size_t	nbytes;
X+   
X+   if (canxfer < 2)
X+   {
X+     printf("%d Sorry, you are not allowed to transfer batches.\r\n",
X+ 	   ERR_NOXBATCH);
X+ #ifdef LOG
X+     syslog(LOG_INFO, "%s xbatch rejected", hostname);
X+ #endif
X+     (void) fflush(stdout);
X+     return ;
X+   }
X+   if (argc > 1)
X+     nbytes = atoi(argv[1]);
X+   else
X+     nbytes = 0;
X+   if (nbytes <= 0)
X+   {
X+     printf("%d Invalid or missing size for xbatch.\r\n",
X+ 	   ERR_CMDSYN);
X+     (void) fflush(stdout);
X+     return ;
X+   }
X+   if (!space(MINFREE + (nbytes / DFUNIT)))
X+   {
X+     /* force error reporting code into sending */
X+     /* an out-of-space error message	       */
X+     if (gethostname(errbuf, MAXHOSTNAMELEN) < 0)
X+       (void) strcpy(errbuf, "Amnesiac");
X+     
X+     (void) strcat(errbuf, " NNTP server out of space. Try later.");
X+     
X+     retcode = 0;		/* indicates that an error occurred */
X+   }
X+   do_newsrun=0;			/* don't do newsrun */
X+   if (btch.isopen)
X+   {
X+     enqpartbatch(INF_DEBUG, INF_DEBUG, errbuf);
X+     if (btch.isopen)
X+     {
X+       if (gethostname(errbuf, MAXHOSTNAMELEN) < 0)
X+ 	(void) strcpy(errbuf, "Amnesiac");
X+       (void) strcat(errbuf, " NNTP server can't prepare batch. Try Later.");
X+       retcode = -1;		/* a problem */
X+     }
X+   }
X+   if (retcode == 1)
X+   {
X+     /* 
X+      * Ok, we can now try and receive the batch.
X+      */
X+     retcode = get_xbatch(CONT_XBATCH, errbuf, nbytes);
X+   }
X+   switch (retcode)
X+   {
X+   case -1:
X+     printf("%d xbatch failed: %s, goodbye\r\n", ERR_GOODBYE, errbuf);
X+     break;
X+   case 0:
X+     printf("%d xbatch failed: %s\r\n", ERR_XFERFAIL, errbuf);
X+     break;
X+   default:
X+     printf("%d Batch transfered successfully.\r\n", OK_XBATCHED);
X+     break;
X+   }
X+   (void) fflush(stdout);
X+   
X+ #ifdef LOG
X+   syslog(LOG_INFO, "%s xbatch %s", hostname,
X+ 	 retcode == > 0 ? "succeeded" : "failed");
X+ #endif
X+   return ;
X+ }
X+ 
X+ int
X+ get_xbatch(cont_code, errbuf, nbytes)
X+   int	cont_code;
X+   char	*errbuf;
X+   size_t nbytes;
X+ {
X+   char		buf[512];
X+   int 		status = 1;			/* okay status */
X+   size_t	count=0;
X+   register int	icnt, ocnt;
X+   
X+   /* protect locking */
X+   signal(SIGINT, SIG_IGN);
X+   signal(SIGQUIT, SIG_IGN);
X+   signal(SIGHUP, SIG_IGN);
X+ 
X+   if (btch.name == NULL)
X+   {
X+     /* BATCH_FILE may trigger unprivileged() */
X+     btch.name = mktemp(strsave(BATCH_FILE));
X+   }
X+   if (btch.name == NULL)
X+     return 0;
X+ #ifdef UMASK
X+   (void) umask(UMASK);
X+ #endif
X+   if (btch.file == NULL)
X+   {
X+     btch.file = fopen(btch.name, "a");
X+     if (btch.file == NULL)
X+     {
X+ #ifdef SYSLOG
X+       syslog(LOG_ERR,"xbatch(): %s: %m", btch.name);
X+ #endif
X+       return 0;
X+     }
X+     btch.isopen = YES;
X+     btch.size = 0;
X+     btch.start = time(&btch.start);
X+   }
X+   printf("%d Ok\r\n", cont_code);
X+   (void) fflush(stdout);
X+ #ifdef XFER_TIMEOUT
X+   signal(SIGALRM, xfer_timeout);
X+   (void) alarm(XFER_TIMEOUT);
X+ #endif
X+   while (count < nbytes)
X+   {
X+     if ((ocnt = nbytes - count) > sizeof (buf))
X+       ocnt = sizeof (buf);
X+     if ((icnt = fread(buf, sizeof (char), ocnt, stdin)) > 0)
X+     {
X+       if ((ocnt = fwrite(buf, sizeof (char), icnt, btch.file)) == icnt)
X+       {
X+ 	count += ocnt;
X+       }
X+       else
X+       {
X+ #ifdef DEBUG
X+ 	printf("%d xbatch: ocnt == %d != icnt == %d\r\n",
X+ 	       INF_DEBUG, ocnt, icnt);
X+ 	(void) fflush(stdout);
X+ #endif /* DEBUG */
X+ 	break;
X+       }
X+     }
X+     else
X+     {
X+ #ifdef DEBUG
X+       printf("%d xbatch: looking for %d, got icnt == %d\r\n",
X+ 	     INF_DEBUG, ocnt, icnt);
X+       (void) fflush(stdout);
X+ #endif /* DEBUG */
X+       break;
X+     }
X+   }
X+   (void) fflush(btch.file);
X+   (void) fclose(btch.file);
X+ #ifdef XFER_TIMEOUT
X+   (void) alarm(0);
X+   (void) signal(SIGALRM, SIG_DFL);
X+ #endif
X+   
X+   if (count < nbytes)
X+   {
X+     sprintf(errbuf, "xbatch: short by %d bytes",
X+ 	    nbytes - count);
X+ #ifdef SYSLOG
X+ #ifdef LOG
X+     syslog(LOG_ERR, "%s %s", hostname, errbuf);
X+ #else
X+     syslog(LOG_ERR, errbuf);
X+ #endif
X+ #endif
X+     unlink(btch.name);		/* toss it. */
X+     btch.file = NULL;
X+     btch.isopen = NO;
X+     btch.start = 0;
X+     btch.size = 0;
X+     return 0;
X+   }
X+ #ifdef DEBUG
X+   printf("%d Got that, please wait a tick while I pass it on.\r\n",
X+ 	 INF_DEBUG);
X+   (void) fflush(stdout);
X+ #endif /* DEBUG */
X+   return (enqueue(INF_DEBUG, INF_DEBUG, errbuf) == 1);
X+ }
X+ #endif /* XBATCH */
X*** ./server/serve.c.orig	Tue Apr  2 10:32:31 1991
X--- ./server/serve.c	Mon Feb 11 11:21:03 1991
X***************
X*** 1,5 ****
X  #ifndef lint
X! static char	*sccsid = "@(#)$Header: serve.c,v 1.35 90/08/11 21:33:10 sob Exp $";
X  #endif
X  
X  /*
X--- 1,8 ----
X  #ifndef lint
X! static char	*sccsid[] = {
X! "@(#)$Header: serve.c,v 1.35 90/08/11 21:33:10 sob Exp $",
X! "@(#)serve.c	1.2 91/02/11 12:21:01 (root)"
X! };
X  #endif
X  
X  /*
X***************
X*** 40,45 ****
X--- 43,51 ----
X  extern	int	ahbs(), group(), help(), ihave();
X  extern	int	list(), newgroups(), newnews(), nextlast(), post();
X  extern	int	slave(), stat(), xhdr();
X+ #ifdef XBATCH
X+ extern  void	xbatch();
X+ #endif
X  
X  extern int errno;
X  
X***************
X*** 74,79 ****
X--- 80,88 ----
X  #ifdef XHDR
X  	"xhdr",		0,	xhdr,
X  #endif /* XHDR */
X+ #ifdef XBATCH
X+ 	"xbatch",	0,	xbatch,
X+ #endif
X  };
X  #define NUMCMDS (sizeof(cmdtbl) / sizeof(struct cmdent))
X  
X***************
X*** 239,251 ****
X  		*cp = '\0';
X  	else
X  		timeptr = "Unknown date";
X! #ifdef AUTH
X! 	printf("%d %s NNTP[auth] server version %s ready at %s (%s).\r\n",
X  #else
X! 	printf("%d %s NNTP server version %s ready at %s (%s).\r\n",
X  #endif
X  		canpost ? OK_CANPOST : OK_NOPOST,
X! 		host, nntp_version,
X  		timeptr,
X  		canpost ? "posting ok" : "no posting");
X  	(void) fflush(stdout);
X--- 248,270 ----
X  		*cp = '\0';
X  	else
X  		timeptr = "Unknown date";
X! 
X! 	line[0] = '\0';
X! #if defined(AUTH) && defined(XBATCH)
X! 	strcpy(line, "[xbatch,auth]");
X  #else
X! # ifdef XBATCH
X! 	strcpy(line, "[xbatch]");
X! # else
X! #   ifdef AUTH
X! 	strcpy(line, "[auth]");
X! #   endif
X! # endif
X  #endif
X+ 	
X+ 	printf("%d %s NNTP%s server version %s ready at %s (%s).\r\n",
X  		canpost ? OK_CANPOST : OK_NOPOST,
X! 		host, line, nntp_version,
X  		timeptr,
X  		canpost ? "posting ok" : "no posting");
X  	(void) fflush(stdout);
END_OF_xbatch.diffs
if test 14658 -ne `wc -c <xbatch.diffs`; then
    echo shar: \"xbatch.diffs\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0


-- 
Simon J. Gerraty        <sjg@sun0.melb.bull.oz.au>      (work)
                        <sjg@zen.void.oz.au>            (home)

#include <disclaimer>   /* imagine something *very* witty here */

sjg@melb.bull.oz.au (Simon J. Gerraty) (04/02/91)

This article contains the XBATCH client software, that does all
the work of transferring compressed (or any other kind) of
batches via NNTP.

>From fmayhar@hermes.ladc.bull.com Tue Apr  2 11:13:12 1991
>Return-Path: <fmayhar@hermes.ladc.bull.com>
>From: fmayhar@hermes.ladc.bull.com (Frank Mayhar)

AND, here's the nntpbatch shar, that I've been promising you:
------------Chop chop------------
#! /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 1 (of 1)."
# Contents:  MANIFEST Makefile README get_tcp_conn.c get_tcp_conn.h
#   nntpbatch.1 nntpbatch.c nntpbatch.h nntpqueue.csh remote.c
#   shlock.c sysexits.h viaxbatch xmitauth.c
# Wrapped by fmayhar@hermes on Wed Mar  6 17:25:19 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f MANIFEST -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"MANIFEST\"
else
echo shar: Extracting \"MANIFEST\" \(534 characters\)
sed "s/^X//" >MANIFEST <<'END_OF_MANIFEST'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                  1	This shipping list
X Makefile                  1	
X README                    1	
X get_tcp_conn.c            1	
X get_tcp_conn.h            1	
X nntpbatch.1               1	
X nntpbatch.c               1	
X nntpbatch.h               1	
X nntpqueue.csh             1	
X remote.c                  1	
X shlock.c                  1	
X sysexits.h                1	
X viaxbatch                 1	
X xmitauth.c                1	
END_OF_MANIFEST
if test 534 -ne `wc -c <MANIFEST`; then
    echo shar: \"MANIFEST\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(1470 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X#
X# Makefile for nntpbatch
X#
X
XSRVRSRC = nntpbatch.c remote.c get_tcp_conn.c xmitauth.c ../server/fakesyslog.c ../server/strcasecmp.c
X
XSRVROBJ = nntpbatch.o remote.o get_tcp_conn.o xmitauth.o fakesyslog.o strcasecmp.o
X
XSRVRINC = ../common/conf.h ../common/nntp.h nntpbatch.h get_tcp_conn.h \
X	sysexits.h ../common/nntp.h ../server/fakesyslog.h
X
XSRCS	= ${SRVRSRC}
X
XLIBS	=
X
X# Use the following definition if you're going to be feeding a Bull DPX/2.
XDEFS	= -DBRAINDEAD_DPX2_FIX
X#DEFS	=
X
XCFLAGS	= -O ${DEFS}
X
X# Where nntpbatch is going to live
X
XDESTDIR	= /usr/lib/news
X
Xall:	nntpbatch shlock
X
Xnntpbatch: ${SRVROBJ} ${SRVRINC}
X	${CC} ${CFLAGS} -o nntpbatch ${SRVROBJ} ${LIBS}
X
Xshlock: shlock.c
X	cc ${CFLAGS} -o shlock shlock.c
X
X${SRVROBJ}: ${SRVRINC}
X
Xinstall: nntpbatch shlock
X	cp nntpbatch ${DESTDIR}/nntpbatch
X	cp shlock ${DESTDIR}/shlock
X	chmod 755 ${DESTDIR}/nntpbatch
X	chmod 755 ${DESTDIR}/shlock
X
Xlint:
X	lint ${SRVRSRC}
X
Xclean:
X	-rm -f *.o nntpbatch shlock make*.out a.out
X
Xdistrib: clean
X	rm -rf RCS save tags
X
Xcheck:
X	ci -l *.[ch] Makefile
X
Xtags:	${SRVRSRC} ${SRVRINC}
X	ctags ${SRVRSRC} ${SRVRINC}
X
Xfakesyslog.o: ../server/fakesyslog.c ../server/fakesyslog.h
X	${CC} ${CFLAGS} -c ../server/fakesyslog.c
X
Xstrcasecmp.o: ../server/strcasecmp.c 
X	${CC} ${CFLAGS} -c ../server/strcasecmp.c
X
Xnntpbatch.o: nntpbatch.c nntpbatch.h ../common/conf.h
X
Xget_tcp_conn.o: get_tcp_conn.c get_tcp_conn.h ../common/conf.h
X
Xremote.o: remote.c nntpbatch.h get_tcp_conn.h ../common/conf.h
END_OF_Makefile
if test 1470 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(1456 characters\)
sed "s/^X//" >README <<'END_OF_README'
X     The program "nntpbatch" is a batch transmission client written by
XFrame Mayhar (fmayhar@hermes.ladc.bull.com).  A larger comment on its
Xinner workings can be found by looking at the man page
X
X     To use nntpbatch, you should edit your news sys file to have
Xan entry like this:
X
X#
X# NASA Ames Research Center
X#
Xnike:ucb,uc,mod,to.nike/all:f:
X
XThis will place names of news articles in the ucb, uc, and mod
Xnewsgroups in the file "~news/out.going/nike/togo".  The C News
Xsendbatch program then picks up those articles and processes them
Xaccording to your batchparms file, passing them to the viaxbatch script
Xwhich places them in your nntp spool directory.
X
XPeriodically, you should have crontab run "nntpqueue" to transmit the
Xnews.  A good choice for "periodically" is every 15 or 20 minutes.
Xnntpqueue depends on the program "shlock", which make should have made
Xalready.  Also, nntpqueue and viaxbatch will need to be customized for
Xyour system.  Fortunately, both are pretty straightforward.
X
X     nntpbatch has an option "-s" which *supresses* statistic
Xlogging via syslog.  Additionally, the "-d" option is available
Xfor debugging.
X
X     Please forward comments/suggestions for improvement/bugs to
Xfmayhar@hermes.ladc.bull.com.
X
X     Note that almost all of this code was blatantly stolen from
Xthe nntpxmit source and related scripts, by Erik Fair, Mel Pleasant,
Xet al.  The shlock program was lifted unchanged from their nntpxmit
Xdistribution.
END_OF_README
if test 1456 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f get_tcp_conn.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"get_tcp_conn.c\"
else
echo shar: Extracting \"get_tcp_conn.c\" \(7238 characters\)
sed "s/^X//" >get_tcp_conn.c <<'END_OF_get_tcp_conn.c'
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 "../common/conf.h"
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
Xextern	int	errno;
Xextern	char	*Pname;
Xextern	char	*errmsg();
X#ifndef	htons
Xextern	u_short	htons();
X#endif	htons
X#ifndef	NONETDB
Xextern	char	*inet_ntoa();
Xextern	u_long	inet_addr();
X#else
X/*
X * inet_addr for EXCELAN (which does not have it!)
X *
X */
Xu_long
Xinet_addr(cp)
Xregister 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
Xagain:
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
Xchar *
Xinet_ntoa(in)
Xstruct 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
Xvoid
Xbcopy(s, d, l)
Xregister caddr_t s, d;
Xregister 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*/
Xu_long **
Xname_to_address(host)
Xchar	*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
Xstatic 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
Xu_short
Xgservice(serv, proto)
Xchar	*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*/
Xget_tcp_conn(host, serv)
Xchar	*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_get_tcp_conn.c
if test 7238 -ne `wc -c <get_tcp_conn.c`; then
    echo shar: \"get_tcp_conn.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f get_tcp_conn.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"get_tcp_conn.h\"
else
echo shar: Extracting \"get_tcp_conn.h\" \(590 characters\)
sed "s/^X//" >get_tcp_conn.h <<'END_OF_get_tcp_conn.h'
X/*
X** Return codes from get_tcp_conn().
X*/
X#ifndef	FAIL
X#define FAIL		(-1)		/* routine failed */
X#endif
X#define	NOHOST		(FAIL-1)	/* no such host */
X#define	NOSERVICE	(FAIL-2)	/* no such service */
X
X#ifndef NULL
X#define	NULL	0
X#endif
X
X#ifdef USG	/* brain-dead USG compilers can't deal with typedef */
X#define bcopy(a,b,c)   memcpy(b,a,c)
X#ifndef M_XENIX
X#ifndef dgux
X#define	u_long	unsigned long
X#define	u_short	unsigned short
X#endif
X#endif
X#endif
X
X#ifdef	EXCELAN
X#define	NONETDB
X#define	OLDSOCKET
X#endif
X
X#ifdef	NONETDB
X#define	IPPORT_NNTP	119		/* NNTP is on TCP port 119 */
X#endif	NONETDB
END_OF_get_tcp_conn.h
if test 590 -ne `wc -c <get_tcp_conn.h`; then
    echo shar: \"get_tcp_conn.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f nntpbatch.1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"nntpbatch.1\"
else
echo shar: Extracting \"nntpbatch.1\" \(3410 characters\)
sed "s/^X//" >nntpbatch.1 <<'END_OF_nntpbatch.1'
X.TH NNTPBATCH 1 netnews/NNTP
X.SH NAME
X.I nntpbatch
X\- transmit netnews batches to a remote NNTP server using the XBATCH extension
X.SH SYNOPSIS
X.I nntpbatch
X[
X.B \-d
X]
X[
X.B \-s
X]
X[
X.B \-T
X]
X[
X.B \-F
X]
X[
X.B \-D
X] hostname file [file ...]
X.SH DESCRIPTION
X.PP
X.I Nntpbatch
Xoffers netnews batches [RFC850] named on the command line to a remote NNTP (Network News Transfer Protocol,
X[RFC977]) server, using the XBATCH extension.
X.PP
XThe command line arguments are processed sequentially, and the flags
Xcan thus be toggled several times during one invocation of the
Xprogram, by giving the options more than once.
XThe options are:
X.IP  "hostname file [file ...]"
XThe name of the remote host, followed by the names of files containing batches destined for that host.
XThe hostname may be an internet address in dotted
Xformat (e.g. 10.2.0.78, [10.0.0.78]).  If the -F flag was given, hostname may be omitted.
X.IP -s
XToggles reporting of transfer statistics (how many articles we
Xoffered them, how many they accepted, etc).
X.br
XDefault is
X.B ON.
X.IP -d
XToggles DEBUG output on stderr.
XThis can be used to see exactly what the two systems are saying to
Xeach other, except for the actual article text.
X.br
XDefault is
X.B OFF.
X.PP
XThe next options set the underlying transport protocol that
X.I nntpbatch
Xuses.
XThe NNTP specification assumes a TCP-style transport protocol
Xunderlies it (i.e. a reliable, flow-controlled, full-duplex byte
Xstream).
X.I Nntpbatch
Xassumes that after doing some magic to get a descriptor, 
Xit can do read(2) and write(2) calls (and use stdio) to move data
Xand check for errors.
XBy default, 
X.I nntpbatch
Xwill use TCP/IP (DoD Internet Protocol suite).
X.IP -T
XSets transport protocol to TCP/IP for all remaining
Xtransfers (unless reset by other transport flags).
XDefault transport.
X.IP -D
XSets transport protocol to DECNET for all remaining
Xtransfers (unless reset by other transport flags).
X.IP -F
XThis says that the hostname is a file descriptor number, already
Xopen to a remote server (with some reliable protocol underneath)
Xthat was passed to
X.I nntpbatch
Xthrough a fork(2).
X.SH "THEORY OF OPERATION"
X.PP
X.I Nntpbatch
Ximplements batches transmission using the XBATCH extension to NNTP,
Xby Simon Gerraty (sjg@sun0.melb.bull.oz.au).
XRoughly, the protocol is
X.IP 1.
Xstat the batch file
Xand send the command XBATCH <batch size in bytes> to the remote.
X.IP 2.
XThe remote will then say either "I'm ready for the batch" or indicate some sort of failure.
X.IP 3.
XIf the response was positive,
X.I nntpbatch
Xsends the batch, as a stream of bytes.  Note that it does not use SMTP [RFC821] text transmission conventions
X(i.e. CRLF line terminators, and dot escaping).  Care must therefore be taken to send exactly the number of bytes specified in the XBATCH command.
X.IP 4.
X.I Nntpbatch
Xwaits for the remote to say whether the batch was successfully
Xaccepted or not.
XIf the transfer failed (whether due to network problems or to a problem with the NNTP server),
X.I nntpbatch
Xwill abort, keeping the batch file for a future transmission attempt.  Otherwise, the batch file is deleted and nntpbatch process the next batch.
X.SH FILES
X/tmp/nntpbatchXXXXXX
X.SH AUTHOR
XFrank Mayhar (fmayhar@hermes.ladc.bull.com)
X.SH "SEE ALSO"
Xinews(1),
X.br
XRFC977 \- Network News Transfer Protocol (NNTP),
X.br
XRFC850 \- USENET Article Format standard,
X.br
XRFC821 \- Simple Mail Transfer Protocol (SMTP),
X.SH BUGS
X.PP
XNone.  (Ha!)
END_OF_nntpbatch.1
if test 3410 -ne `wc -c <nntpbatch.1`; then
    echo shar: \"nntpbatch.1\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f nntpbatch.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"nntpbatch.c\"
else
echo shar: Extracting \"nntpbatch.c\" \(11631 characters\)
sed "s/^X//" >nntpbatch.c <<'END_OF_nntpbatch.c'
X/* nntpbatch - transmit netnews batches across the internet with nntp
X**
X** This program is for transmitting netnews batches between sites
X** that offer the NNTP service, internet style.
X*/
X
X#include "../common/conf.h"
X#include "nntpbatch.h"
X#include <stdio.h>
X#include <errno.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/time.h>
X#if defined(BSD_42) || defined(BSD_43)
X#include <sys/resource.h>
X#else
X#include <sys/times.h>
Xextern	time_t	time();
X#endif
X#include <sys/file.h>
X#include <fcntl.h>
X#include <signal.h>
X#ifdef USG
X#include "sysexits.h"
X#else
X#include <sysexits.h>
X#endif
X#ifdef	SYSLOG
X#ifdef FAKESYSLOG
X#include "../server/fakesyslog.h"
X#else
X#include <syslog.h>
X#endif
X#endif	SYSLOG
X#include "../common/nntp.h"
X
X#define	MAXFNAME	BUFSIZ	/* maximum filename size - big enough? */
X#define	FCLOSE(fp)	(void) fclose(fp); (fp) = (FILE *)NULL
X
XFILE	*getfp();
Xchar	*errmsg();
Xvoid	requeue();
XSIGRET	catchsig();
Xvoid	restsig();
Xvoid	logstats();
Xvoid	log();
Xint	interrupted();
X
X/*
X** Globals that certain things need.
X**
X** Various subroutines want the program name to report errors.
X** The queue file, queue file pointer and current article name are
X** there to write out the state of the queue file from a signal handler
X** (that is, the list of unsent and (possibly) failed articles) so
X** that when next we try sending to a given remote site, we don't send
X** stuff we've already sent.
X*/
Xchar	*Pname;			/* this program's invocation name */
Xchar	*Host;			/* current remote host */
Xchar	*Qfile;			/* current batch file we're operating on */
XFILE	*Qfp;			/* the (FILE *) for above */
Xu_long	BSize;			/* Size of the current batch file */
X
X/*
X** Some flags, toggled by arguments
X*/
X#define	TOGGLE(boolean)	(boolean) = !(boolean)
Xchar	Debug = FALSE;
Xchar	Report_Stats = TRUE;
X
Xchar	*USAGE = "USAGE: nntpbatch [-d][-s][-T][-F][-D] hostname file [file ...]";
Xchar	*Fmt = "%s localhost %s[%d]: %s\n";
Xchar	*E_fopen = "fopen(%s, \"%s\"): %s";
Xchar	*E_unlk = "unlink(%s): %s";
X
Xstruct {
X	u_long	offered;
X	u_long	succeeded;
X	u_long	succ_bytes;
X	u_long	failed;
X} Stats = {0L, 0L, 0L};
X
Xdouble Tbegin, Tend;		/* transfer timestamps */
X
Xextern	int	errno;
Xextern 	int	strncmp();
Xextern	char	*rindex();
Xextern	char	*index();
Xextern	char	*mktemp();
Xextern	char	*strcpy();
X
X#ifdef	USG
Xvoid
Xbzero(s, l)
Xregister caddr_t s;
Xregister int	l;
X{
X	while(l-- > 0) *s++ = 0;
X}
X#endif	USG
X
Xmain(ac, av)
Xint	ac;
Xchar	*av[];
X{
X	register int	i;
X	int	transport = T_IP_TCP;	/* default is IP/TCP */
X	char **flist;
X#if	defined(BSD_42) || defined(BSD_43)
X	struct timeval tod;
X	struct timezone tz;
X
X	(void) gettimeofday(&tod, &tz);
X	Tbegin = tod.tv_sec + (double)tod.tv_usec/1000000.;
X#else
X	Tbegin = (double) time((time_t *)NULL);
X#endif
X
X	Pname = ((Pname = rindex(av[0],'/')) ? Pname + 1 : av[0]);
X	
X	if (ac < 3) {
X		fprintf(stderr, "%s: %s\n", Pname, USAGE);
X		exit(EX_USAGE);
X		}
X
X#ifdef	SYSLOG
X	/* 4.2 BSD openlog has only two args */
X#ifdef	BSD_42
X	(void) openlog(Pname, LOG_PID);
X#else
X	(void) openlog(Pname, LOG_PID, SYSLOG);
X#endif	BSD_42
X#endif	SYSLOG
X
X	i = 1;
X	ac--;
X	while (av[i][0] == '-') {
X		switch(av[i][1]) {
X			case 'T':
X				transport = T_IP_TCP;
X				break;
X			case 'D':
X				transport = T_DECNET;
X				break;
X			case 'F':
X				transport = T_FD;
X				break;
X			case 's':
X				TOGGLE(Report_Stats);
X				break;
X			case 'd':
X				TOGGLE(Debug);
X				break;
X			default:
X				fprintf(stderr, "%s: no such option: -%c\n",
X					Pname, av[i][1]);
X				fprintf(stderr, "%s: %s\n", Pname, USAGE);
X				exit(EX_USAGE);
X			}
X		ac--;
X		i++;
X		}
X
X	if (ac < 2) {
X		fprintf(stderr, "%s: %s\n", Pname, USAGE);
X		exit(EX_USAGE);
X		}
X
X	if (transport != T_FD)
X		Host = av[i++];
X	flist = &av[i];
X
X	bzero((caddr_t)&Stats, sizeof(Stats));
X	if (sendbatches(Host, transport, flist) && Report_Stats)
X		logstats();
X	exit(EX_OK);
X}
X
X/*
X** Calculate how much time we've used,
X** and report that (and the transfer statistics).
X**
X*/
Xvoid logstats()
X{
X	static double ouser = 0.0, osys = 0.0;
X	double user, sys;
X	char buf[BUFSIZ];
X#if	defined(BSD_42) || defined(BSD_43)
X	struct rusage self, kids;
X	struct timeval tod;
X	struct timezone tzdummy;
X
X	(void) getrusage(RUSAGE_SELF, &self);
X	(void) getrusage(RUSAGE_CHILDREN, &kids);
X	(void) gettimeofday(&tod, &tzdummy);
X
X	Tend = tod.tv_sec + (double)tod.tv_usec/1000000.;
X
X	user = self.ru_utime.tv_sec + kids.ru_utime.tv_sec +
X		(double) self.ru_utime.tv_usec/1000000. +
X		(double) kids.ru_utime.tv_usec/1000000.;
X	
X	sys = self.ru_stime.tv_sec + kids.ru_stime.tv_sec +
X		(double) self.ru_stime.tv_usec/1000000. +
X		(double) kids.ru_stime.tv_usec/1000000.;
X#else
X#define	HZ	60.0	/* typical system clock ticks - param.h */
X	struct tms	cpu;
X
X	(void) times(&cpu);
X
X	Tend = (double) time((time_t *)NULL);
X	user = (double)(cpu.tms_utime + cpu.tms_cutime) / HZ;
X	sys  = (double)(cpu.tms_stime + cpu.tms_cstime) / HZ;
X#endif
X	sprintf(buf,
X		"%s batches %lu offered, %lu succeeded ( %lu bytes ), %lu failed",
X		Host, Stats.offered, Stats.succeeded, Stats.succ_bytes,
X		Stats.failed);
X	log(L_INFO, buf);
X	sprintf(buf, "%s xbatch user %.1f system %.1f elapsed %.1f",
X		Host, (user - ouser), (sys - osys), (Tend - Tbegin));
X	log(L_INFO, buf);
X	/* reset reference point */
X	Tbegin = Tend;	
X	ouser = user;
X	osys = sys;
X}
X
X/*
X** Given a hostname to connect to, and a file containing a (possibly compressed)
X** netnews batch, send the file to the named host using NNTP.
X**
X** Return code is:
X**	TRUE	- the batch was successfully transferred.
X**
X**	FALSE	- the transfer failed.
X*/
Xsendbatches(host, transport, files)
Xchar	*host, **files;
Xint	transport;
X{
X	register FILE	*fp;
X	register int	retcode;
X#ifdef	FTRUNCATE
X	char	*mode = "r+";		/* so we can use ftruncate() */
X#else
X	char	*mode = "r";
X#endif	FTRUNCATE
X	char	buf[BUFSIZ];
X
X	/*
X	** Open a connection to the remote server
X	*/
X	if (hello(host, transport) == FAIL)
X		return(FALSE);
X	catchsig(interrupted);
X	do {
X		Qfile = *files++;
X		if ((Qfp = fopen(Qfile, mode)) == (FILE *)NULL) {
X			sprintf(buf, E_fopen, Qfile, mode, errmsg(errno));
X			log(L_WARNING, buf);
X			return(FALSE);
X			}
X
X		/*
X		** interlock with other copies of this process.
X		** non-blocking.
X		*/
X		if (!lockfd(fileno(Qfp), Qfile, DONT_BLOCK)) {
X			FCLOSE(Qfp);
X			return(FALSE);
X			}
X
X		dprintf(stderr, "%s: sending %s\n", Pname, Qfile);
X
X		if (retcode = sendbatch(host, Qfp)) {
X			if (unlink(Qfile) < 0) {
X				sprintf(buf, E_unlk, Qfile, errmsg(errno));
X				log(L_WARNING, buf);
X				retcode = FALSE;
X				}
X			}
X		Qfile = (char *)NULL;
X		FCLOSE(Qfp);
X		} while (*files != (char *)NULL && retcode);
X	goodbye(retcode ? WAIT : DONT_WAIT);
X	return(TRUE);
X}
X
X/*
X** Perform one transfer operation:
X**	Give XBATCH command
X**	Wait for reply, and send batch if it's OK.
X**	Wait for transfer confirmation, return TRUE if
X**		he got it OK, FALSE if he didn't.
X**	Watch all network I/O for errors, return FALSE if
X**		the connection fails and we have to cleanup.
X*/
Xsendbatch(host, fp)
Xchar	*host;
XFILE	*fp;
X{
X	register int	code;
X	char	buf[BUFSIZ];
X	char	*e_xbatch = "%s batch: %s";
X
X	switch(code = xbatch(fp)) {
X		case CONT_XBATCH:
X		/*
X		** They want it. Give it to 'em.
X		*/
X			if (!sendfile(fp)) {
X				sprintf(buf, e_xbatch, host, errmsg(errno));
X				log(L_NOTICE, buf);
X				Stats.failed++;
X				return(FALSE);
X				}
X		/*
X		** Did the article transfer OK?
X		** Stay tuned to this same socket to find out!
X		*/
X			while ((code = readreply(buf, sizeof(buf))) >= 100 && code < 200)
X				;
X			if (code != OK_XBATCHED) {
X				Stats.failed++;
X				if (code < 0) {
X					if (errno > 0) {
X						sprintf(buf, e_xbatch, host, errmsg(errno));
X						log(L_NOTICE, buf);
X						}
X					else {
X						char errbuf[BUFSIZ];
X						sprintf(errbuf, e_xbatch, host, buf);
X						log(L_NOTICE, errbuf);
X						}
X					}
X				return(FALSE);
X				}
X			Stats.succeeded++;
X			Stats.succ_bytes += BSize;
X			break;
X		case ERR_NOXBATCH:
X			/* They don't let us do XBATCH xfers. */
X			sprintf(buf,e_xbatch,host,"No XBATCH access.");
X			log(L_NOTICE,buf);
X			Stats.failed++;
X			return(FALSE);
X		default:
X			if (code < 0) {
X				if (errno > 0) {
X					sprintf(buf, e_xbatch, host, errmsg(errno));
X					log(L_NOTICE, buf);
X					}
X				else {
X					sprintf(buf, e_xbatch, host, "ihave");
X					log(L_NOTICE, buf);
X					}
X				}
X			else {
X				sprintf(buf, "%s improper response to XBATCH: %d", host, code);
X				log(L_WARNING, buf);
X				}
X			Stats.failed++;
X			return(FALSE);
X		}
X	return(TRUE);
X}
X
Xchar *
Xerrmsg(code)
Xint code;
X{
X	extern int sys_nerr;
X	extern char *sys_errlist[];
X	static char ebuf[6+5+1];
X
X	if (code > sys_nerr || code < 0) {
X		(void) sprintf(ebuf, "Error %d", code);
X		return ebuf;
X	} else
X		return sys_errlist[code];
X}
X
X/*
X** Stat the file containing a netnews batch and send the XBATCH command
X** containing the file size.
X*/
Xxbatch(fp)
XFILE	*fp;
X{
X	register int	code;
X	register char	*id;
X	char	buf[BUFSIZ];
X	struct stat sbuf;
X
X	if (fstat(fileno(fp),&sbuf) < 0) {
X		sprintf(buf, "Can't stat batch file: %s",errmsg(errno));
X		log(L_DEBUG,buf);
X		return(ERR_XFERFAIL);
X		}
Xagain:
X	sprintf(buf, "XBATCH %d", sbuf.st_size);
X	Stats.offered++;
X	BSize = sbuf.st_size;
X	code = converse(buf, sizeof(buf));
X#ifdef AUTH
X	if (code == ERR_NOAUTH) {
X		xmitauth(Host);
X		goto again;
X		}
X#endif
X	return(code);
X}
X
X/*
X** OK, clean up any mess
X*/
Xcleanup()
X{
X	dprintf(stderr, "%s: cleanup()\n", Pname);
X	if (Qfp == (FILE *)NULL || Qfile == (char *)NULL)
X		return;
X	Stats.failed++;
X	FCLOSE(Qfp);
X} 
X
X/*
X** Signal stuff
X**
X** There's probably too much stuff to do in this signal
X** handler, but we're going to exit anyway...
X*/
Xinterrupted(sig)
Xint	sig;
X{
X	char buf[BUFSIZ];
X
X#ifndef RELSIG
X	catchsig(SIG_IGN);	/* for System V - hope we're quick enough */
X#endif	RELSIG
X	sprintf(buf, "%s signal %d", Host, sig);
X	log(L_NOTICE, buf);
X	cleanup();
X	if (Report_Stats)
X		logstats();
X	goodbye(DONT_WAIT);
X	exit(EX_TEMPFAIL);
X}
X
Xstruct {
X	int	signo;
X	ifunp	state;
X} SigList[] = {
X	{SIGHUP},
X	{SIGINT},
X	{SIGQUIT},
X	{SIGTERM},
X	{NULL}
X};
X
XSIGRET
Xcatchsig(handler)
Xifunp	handler;
X{
X	register int	i;
X
X	if (handler != SIG_IGN) {
X		for(i = 0; SigList[i].signo != NULL; i++) {
X			SigList[i].state = signal(SigList[i].signo, handler);
X		}
X	} else {
X		for(i = 0; SigList[i].signo != NULL; i++) {
X			(void) signal(SigList[i].signo, handler);
X		}
X	}
X}
X
Xvoid
Xrestsig()
X{
X	register int	i;
X
X	for(i = 0; SigList[i].signo != NULL; i++) {
X		if (SigList[i].state != (ifunp)(-1))
X			(void) signal(SigList[i].signo, SigList[i].state);
X	}
X}
X
X/*
X** log stuff
X*/
Xvoid
Xlog(importance, error)
Xint	importance;
Xchar	*error;
X{
X	FILE	*report = (importance == L_INFO ? stdout : stderr);
X	fprintf(report, "%s: %s\n", Pname, error);
X#ifdef	SYSLOG
X	switch(importance) {
X#ifdef LOG
X	case L_DEBUG:	importance = LOG_DEBUG;		break;
X#endif
X	case L_INFO:	importance = LOG_INFO;		break;
X	case L_NOTICE:	importance = LOG_NOTICE;	break;
X	case L_WARNING:	importance = LOG_WARNING;	break;
X	default:	importance = LOG_DEBUG;		break;
X	}
X	syslog(importance, error);
X#endif	SYSLOG
X}
X
X/*
X** Lock a file descriptor
X**
X** NOTE: if the appropriate system calls are unavailable,
X** this subroutine is a no-op.
X*/
Xlockfd(fd, file, non_blocking)
Xint	fd, non_blocking;
Xchar	*file;			/* just for error reporting */
X{
X	char	buf[BUFSIZ];
X#ifdef	USG
X#ifdef	F_TLOCK
X	if (lockf(fd, (non_blocking ? F_TLOCK : F_LOCK), 0) < 0) {
X		if (errno != EACCES) {
X			sprintf(buf, "lockf(%s): %s\n", file, errmsg(errno));
X			log(L_WARNING, buf);
X		}
X		return(FALSE);
X	}
X#endif	F_TLOCK
X#else
X#ifdef	LOCK_EX
X	if (flock(fd, LOCK_EX|(non_blocking ? LOCK_NB : 0)) < 0) {
X		if (errno != EWOULDBLOCK) {
X			sprintf(buf, "flock(%s): %s\n", file, errmsg(errno));
X			log(L_WARNING, buf);
X		}
X		return(FALSE);
X	}
X#endif	LOCK_EX
X#endif	USG
X	return(TRUE);
X}
END_OF_nntpbatch.c
if test 11631 -ne `wc -c <nntpbatch.c`; then
    echo shar: \"nntpbatch.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f nntpbatch.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"nntpbatch.h\"
else
echo shar: Extracting \"nntpbatch.h\" \(1361 characters\)
sed "s/^X//" >nntpbatch.h <<'END_OF_nntpbatch.h'
X/*
X** Random stuff needed for nntpxmit
X**
X** This file also contains a lot of assumptions about what features
X** are available on the local system - if something is not working
X** to your liking, look them over carefully.
X*/
X
X#ifdef MMAP
X#include <sys/mman.h>
X#include <sys/stat.h>
X#endif MMAP
X
X#ifdef SIGRET
X#undef SIGRET
X#endif
X#define SIGRET void	/* Newfangled signal() returns void, old returns int */
X
Xtypedef	SIGRET	(*ifunp)();	/* pointer to function that returns */
X				/* whatever signal() returns */
X
X#define	dprintf	if (Debug) fprintf
X
X#ifdef TIMEOUT
X#undef TIMEOUT
X#endif
X#define	TIMEOUT	3600		/* seconds to read timeout in sfgets */
X
X#ifndef	TRUE
X#define	TRUE	1
X#define	FALSE	0
X#endif
X
X/* in goodbye() wait (or not) for QUIT response */
X#define	WAIT		TRUE
X#define	DONT_WAIT	FALSE
X
X/* in lockfd(), blocking, or non_blocking */
X#define	BLOCK		FALSE
X#define	DONT_BLOCK	TRUE
X
X#ifndef FAIL
X#define	FAIL		(-1)
X#endif
X
X
X/* DECNET support is only there if the DECNET compile-time option defined */
X#define	T_IP_TCP	1	/* transport is IP/TCP */
X#define	T_DECNET	2	/* transport is DECNET */
X#define	T_FD		3	/* transport is a descriptor */
X
X/* for syslog, if we compile it in */
X#define	L_DEBUG		1
X#define	L_INFO		2
X#define	L_NOTICE	3
X#define	L_WARNING	4
X
X
X#ifdef	BSD_42			/* look at all these goodies we get! */
X#define	FTRUNCATE
X#define	RELSIG
X#endif	BSD4_2
X
END_OF_nntpbatch.h
if test 1361 -ne `wc -c <nntpbatch.h`; then
    echo shar: \"nntpbatch.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f nntpqueue.csh -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"nntpqueue.csh\"
else
echo shar: Extracting \"nntpqueue.csh\" \(1208 characters\)
sed "s/^X//" >nntpqueue.csh <<'END_OF_nntpqueue.csh'
X#!/bin/csh -f
X#
X# What we have here is a csh script for sending netnews batches to NNTP sites.
X# Be sure to set libdir, path, and spooldir to the proper places.  This script
X# expects spooldir to contain a subdirectory for each host that is fed.  The
X# 'viaxbatch' creates these subdirectories as needed; this script removes
X# those subdirectories when they become empty.  This eliminates a little
X# extra work, at the expense of more I/O activity.  Note that the batch files
X# themselves are expected to begin with a digit, and are in fact generated
X# that way by the viaxbatch script, using the C News getdate utility.
X#
Xset libdir=/usr/local/news
Xset path=( /usr/local/newsbin/etc /usr/ucb /usr/bin /bin $path )
Xset spooldir=/var/spool/nntp
Xset pname=$0
Xset pname=$pname:t
Xecho ${pname}: "[$$]" begin `date`
Xumask 022
Xforeach host ( `ls $spooldir` )
X	cd $spooldir/${host}
X	set lock=NNTP_LOCK.${host}
X	shlock -p $$ -f ${lock}
X	if ($status == 0) then
X		echo ${pname}: "[$$]" begin ${host}
X		time nntpbatch ${host} [0-9]*
X		echo ${pname}: "[$$]" end ${host}
X		rm -f ${lock}
X		cd ..
X		rmdir ${host}
X	else
X		echo ${pname}: "[$$]" ${host} locked by "[`cat ${lock}`]"
X	endif
Xend
Xecho ${pname}: "[$$]" end `date`
END_OF_nntpqueue.csh
if test 1208 -ne `wc -c <nntpqueue.csh`; then
    echo shar: \"nntpqueue.csh\" unpacked with wrong size!
fi
chmod +x nntpqueue.csh
# end of overwriting check
fi
if test -f remote.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"remote.c\"
else
echo shar: Extracting \"remote.c\" \(9446 characters\)
sed "s/^X//" >remote.c <<'END_OF_remote.c'
X/*
X** remote communication routines for NNTP/SMTP style communication.
X**
X************
X** This version has been modified to support mmap()'ing of article files
X** on systems that support it.
X**
X** David Robinson (david@elroy.jpl.nasa.gov) and
X** Steve Groom (stevo@elroy.jpl.nasa.gov), June 30, 1989.
X**
X************
X**
X**	sendcmd		- return TRUE on error.
X**
X**	readreply	- return reply code or FAIL for error;
X**				modifies buffer passed to it.
X**
X**	converse	- sendcmd() & readreply();
X**				return reply code or FAIL for error;
X**				modifies buffer passed to it.
X**
X**	hello		- establish connection with remote;
X**				check greeting code.
X**
X**	goodbye		- give QUIT command, and shut down connection.
X**
X**	sfgets		- safe fgets(); does fgets with TIMEOUT.
X**			  (N.B.: possibly unportable stdio macro ref in here)
X**
X**	sendfile	- send a binary file.
X**
X** Erik E. Fair <fair@ucbarpa.berkeley.edu>
X*/
X#include "../common/conf.h"
X#include "nntpbatch.h"
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <errno.h>
X#include <stdio.h>
X#include <ctype.h>
X#include <setjmp.h>
X#include <signal.h>
X#ifdef dgux
X#define _IOERR  _IO_ERR
X#endif
X#ifdef SYSLOG
X#ifdef FAKESYSLOG
X#include "../server/fakesyslog.h"
X#else
X#include <syslog.h>
X#endif
X#endif
X#include "get_tcp_conn.h"
X#include "../common/nntp.h"
X
Xstatic	jmp_buf	SFGstack;
XFILE	*rmt_rd;
XFILE	*rmt_wr;
Xchar	*sfgets();
X
Xextern	int	errno;
Xextern	char	Debug;
Xextern	char	*errmsg();
Xextern	char	*strcpy();
Xextern	void	log();
X
X/*
X** send cmd to remote, terminated with a CRLF.
X*/
Xsendcmd(cmd)
Xchar	*cmd;
X{
X	if (cmd == (char *)NULL)
X		return(TRUE);	/* error */
X	dprintf(stderr, ">>> %s\n", cmd);	/* DEBUG */
X	(void) fprintf(rmt_wr, "%s\r\n", cmd);
X	(void) fflush(rmt_wr);
X	return(ferror(rmt_wr));
X}
X
X/*
X** read a reply line from the remote server and return the code number
X** as an integer, and the message in a buffer supplied by the caller.
X** Returns FAIL if something went wrong.
X*/
Xreadreply(buf, size)
Xregister char	*buf;
Xint	size;
X{
X	register char	*cp;
X	register int	len;
X
X	if (buf == (char *)NULL || size <= 0)
X		return(FAIL);
X
X	/*
X	** make sure it's invalid, unless we say otherwise
X	*/
X	buf[0] = '\0';
X
X	/*
X	** read one line from the remote
X	*/
X	if (sfgets(buf, size, rmt_rd) == NULL)
X		return(FAIL);	/* error reading from remote */
X
X	/*
X	** Make sure that what the remote sent us had a CRLF at the end
X	** of the line, and then null it out.
X	*/
X	if ((len = strlen(buf)) > 2 && *(cp = &buf[len - 2]) == '\r' &&
X		*(cp + 1) == '\n')
X	{
X		*cp = '\0';
X	} else
X		return(FAIL);	/* error reading from remote */
X
X	dprintf(stderr, "%s\n", buf);	/* DEBUG */
X	/*
X	** Skip any non-digits leading the response code 
X	** and then convert the code from ascii to integer for
X	** return from this routine.
X	*/
X	cp = buf;
X	while(*cp != '\0' && isascii(*cp) && !isdigit(*cp))
X		cp++;	/* skip anything leading */
X
X	if (*cp == '\0' || !isascii(*cp))
X		return(FAIL);	/* error reading from remote */
X
X	return(atoi(cp));
X}
X
X/*
X** send a command to the remote, and wait for a response
X** returns the response code, and the message in the buffer
X*/
Xconverse(buf, size)
Xchar	*buf;
Xint	size;
X{
X	register int	resp;
X
X	if (sendcmd(buf))
X		return(FAIL);	/* Ooops! Something went wrong in xmit */
X	/*
X	** Skip the silly 100 series messages, since they're not the
X	** final response we can expect
X	*/
X	while((resp = readreply(buf, size)) >= 100 && resp < 200)
X		continue;
X	return(resp);
X}
X
X/*
X** Contact the remote server and set up the two global FILE pointers
X** to that descriptor.
X**
X** I can see the day when this routine will have 8 args:  one for
X** hostname, and one for each of the seven ISO Reference Model layers
X** for networking. A curse upon those involved with the ISO protocol
X** effort: may they be forced to use the network that they will create,
X** as opposed to something that works (like the Internet).
X*/
Xhello(host, transport)
Xchar	*host;
Xint	transport;
X{ char	*service;
X	char	*rmode = "r";
X	char	*wmode = "w";
X	char	*e_fdopen = "fdopen(%d, \"%s\"): %s";
X	int	socket0, socket1;	/* to me (bad pun) */
X	char	buf[BUFSIZ];
X
X	switch(transport) {
X	case T_IP_TCP:
X		service = "nntp";
X		socket0 = get_tcp_conn(host, service);
X		break;
X	case T_DECNET:
X#ifdef DECNET
X		(void) signal(SIGPIPE, SIG_IGN);
X		service = "NNTP";
X		socket0 = dnet_conn(host, service, 0, 0, 0, 0, 0);
X		if (socket0 < 0) {
X			switch(errno) {
X			case EADDRNOTAVAIL:
X				socket0 = NOHOST;
X				break;
X			case ESRCH:
X				socket0 = NOSERVICE;
X				break;
X			}
X		}
X		break;
X#else
X		log(L_WARNING, "no DECNET support compiled in");
X		return(FAIL);
X#endif
X	case T_FD:
X		service = "with a smile";
X		socket0 = atoi(host);
X		break;
X	}
X
X	if (socket0 < 0) {
X		switch(socket0) {
X		case NOHOST:
X			sprintf(buf, "%s host unknown", host);
X			log(L_WARNING, buf);
X			return(FAIL);
X		case NOSERVICE:
X			sprintf(buf, "%s service unknown: %s", host, service);
X			log(L_WARNING, buf);
X			return(FAIL);
X		case FAIL:
X			sprintf(buf, "%s hello: %s", host, errmsg(errno));
X			log(L_NOTICE, buf);
X			return(FAIL);
X		}
X	}
X
X	if ((socket1 = dup(socket0)) < 0) {
X		sprintf(buf, "dup(%d): %s", socket0, errmsg(errno));
X		log(L_WARNING, buf);
X		(void) close(socket0);
X		return(FAIL);
X	}
X
X	if ((rmt_rd = fdopen(socket0, rmode)) == (FILE *)NULL) {
X		sprintf(buf, e_fdopen, socket0, rmode);
X		log(L_WARNING, buf);
X		(void) close(socket0);
X		(void) close(socket1);
X		return(FAIL);
X	}
X
X	if ((rmt_wr = fdopen(socket1, wmode)) == (FILE *)NULL) {
X		sprintf(buf, e_fdopen, socket1, wmode);
X		log(L_WARNING, buf);
X		(void) fclose(rmt_rd);
X		rmt_rd = (FILE *)NULL;
X		(void) close(socket1);
X		return(FAIL);
X	}
X
X	switch(readreply(buf, sizeof(buf))) {
X	case OK_CANPOST:
X	case OK_NOPOST:
X		if (ferror(rmt_rd)) {
X			goodbye(DONT_WAIT);
X			return(FAIL);
X		}
X		break;
X	default:
X		if (buf[0] != '\0') {
X			char	err[BUFSIZ];
X
X			sprintf(err, "%s greeted us with %s", host, buf);
X			log(L_NOTICE, err);
X		}
X		goodbye(DONT_WAIT);
X		return(FAIL);
X	}
X	return(NULL);
X}
X
X/*
X** Say goodbye to the nice remote server.
X**
X** We trap SIGPIPE because the socket might already be gone.
X*/
Xgoodbye(wait_for_reply)
Xint	wait_for_reply;
X{
X	register ifunp	pstate = signal(SIGPIPE, SIG_IGN);
X
X	if (sendcmd("QUIT"))
X		wait_for_reply = FALSE;	/* override, something's wrong. */
X	/*
X	** I don't care what they say to me; this is just being polite.
X	*/
X	if (wait_for_reply) {
X		char	buf[BUFSIZ];
X
X		(void) readreply(buf, sizeof(buf));
X	}
X	(void) fclose(rmt_rd);
X	rmt_rd = (FILE *)NULL;
X	(void) fclose(rmt_wr);
X	rmt_wr = (FILE *)NULL;
X	if (pstate != (ifunp)(-1));
X		(void) signal(SIGPIPE, pstate);
X}
X
Xstatic SIGRET
Xto_sfgets()
X{
X	longjmp(SFGstack, 1);
X}
X
X/*
X** `Safe' fgets, ala sendmail. This fgets will timeout after some
X** period of time, on the assumption that if the remote did not
X** return, they're gone.
X** WARNING: contains a possibly unportable reference to stdio
X** error macros.
X*/
Xchar *
Xsfgets(buf, size, fp)
Xchar	*buf;
Xint	size;
XFILE	*fp;
X{
X	register char	*ret;
X	int	esave;
X
X	if (buf == (char *)NULL || size <= 0 || fp == (FILE *)NULL)
X		return((char *)NULL);
X	if (setjmp(SFGstack)) {
X		(void) alarm(0);		/* reset alarm clock */
X		(void) signal(SIGALRM, SIG_DFL);
X#ifdef apollo
X		fp->_flag |= _SIERR;
X#else
X		fp->_flag |= _IOERR;		/* set stdio error */
X#endif
X#ifndef ETIMEDOUT
X		errno = EPIPE;			/* USG doesn't have ETIMEDOUT */
X#else
X		errno = ETIMEDOUT;		/* connection timed out */
X#endif
X		return((char *)NULL);		/* bad read, remote time out */
X	}
X	(void) signal(SIGALRM, to_sfgets);
X	(void) alarm(TIMEOUT);
X	ret = fgets(buf, size, fp);
X	esave = errno;
X	(void) alarm(0);			/* reset alarm clock */
X	(void) signal(SIGALRM, SIG_DFL);	/* reset SIGALRM */
X	errno = esave;
X	return(ret);
X}
X
X/*
X** send the contents of an open file descriptor to the remote.
X** Return FALSE if something went wrong.
X*/
Xsendfile(fp)
XFILE	*fp;
X{
X	register int	c;
X	register int	padsize;
X	register FILE	*remote = rmt_wr;
X#ifdef BRAINDEAD_DPX2_FIX
X	static char buf[512] = { '\0' };
X#endif
X#ifdef MMAP
X	register char *mbufr,*mptr;
X        long offset;
X        struct stat sbuf;
X#endif MMAP
X
X/*
X** I'm using putc() instead of fputc();
X** why do a subroutine call when you don't have to?
X** Besides, this ought to give the C preprocessor a work-out.
X*/
X#ifndef MMAP
X#define	PUTC(c)						\
X	if (putc(c, remote) == EOF)			\
X		return(FALSE)
X#endif !MMAP
X
X	if (fp == (FILE *)NULL)
X		return(FALSE);
X
X#ifdef MMAP
X#ifdef BRAINDEAD_DPX2_FIX
X	if (!buf[0])
X		for (c = 0; c < 512; buf[c++] = '\n')
X			;
X#endif
X	/* map the article into memory */
X	(void) fstat(fileno(fp), &sbuf);
X        mbufr = mmap (0, sbuf.st_size, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
X        if(mbufr == (char *) -1){
X		sprintf(buf, "sendfile: mmap failed: %s", errmsg(errno));
X		log(L_NOTICE, buf);
X                return(FALSE);
X		}
X
X        mptr = mbufr;		/* start of article in memory */
X	if (fwrite(mptr,1,sbuf.st_size,remote) < sbuf.st_size) {
X		(void) munmap (mbufr, sbuf.st_size);
X		return(FALSE);
X		}
X#ifdef BRAINDEAD_DPX2_FIX
X	if (sbuf.st_size % 512 > 0) {
X		padsize = 512 - (sbuf.st_size % 512);
X        	if (fwrite(buf,1,padsize,remote) < padsize) {
X                	(void) munmap (mbufr, sbuf.st_size);
X                	return(FALSE);
X                	}
X		}
X#endif
X	(void)fflush(remote);
X	(void)munmap(mbufr, sbuf.st_size);
X	return(TRUE);
X#else !MMAP
X	/*
X	** the second test makes no sense to me,
X	** but System V apparently needed it...
X	*/
X	while((c = fgetc(fp)) != EOF && !feof(fp)) {
X		PUTC(c);
X		}
X	return (ferror(fp) == 0);
X#endif !MMAP
X}
END_OF_remote.c
if test 9446 -ne `wc -c <remote.c`; then
    echo shar: \"remote.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f shlock.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"shlock.c\"
else
echo shar: Extracting \"shlock.c\" \(7101 characters\)
sed "s/^X//" >shlock.c <<'END_OF_shlock.c'
X#ifndef lint
Xstatic char * rcsid = "@(#)$Header: shlock.c,v 1.2 90/01/15 01:37:33 sob Exp $";
X#endif
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** Extensions for UUCP style locks (i.e. pid is an int in the file,
X** rather than an ASCII string). Also fix long standing bug with
X** full file systems and temporary files.
X**
X** Erik E. Fair <fair@apple.com>, November 12, 1989
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#include "../common/conf.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
Xint	Debug = FALSE;
Xchar	*Pname;
Xchar	*USAGE = "%s: USAGE: shlock -f file -p pid [-d][-u]\n";
Xchar	*E_unlk = "%s: unlink(%s): %s\n";
Xchar	*E_open = "%s: open(%s): %s\n";
X
Xchar	*errmsg();
Xchar	*xtmpfile();
X
X#define	dprintf	if (Debug) printf
X
Xextern	int	errno;
Xextern	char	*rindex();
Xextern	char	*strcpy();
Xextern	char	*strcat();
X
Xmain(ac, av)
Xint	ac;
Xchar	*av[];
X{
X	register int	x;
X	char	*file;
X	int	pid;
X	int	uucpstyle = FALSE;	/* indicating UUCP style locks */
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 'u':
X				uucpstyle = TRUE;
X				break;
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, uucpstyle) ? LOCK_SET : LOCK_FAIL);
X}
X
Xchar *
Xerrmsg(n)
Xregister 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
Xmklock(file, pid, uucpstyle)
Xchar	*file;
Xint	pid;
X{
X	register char	*tmp;
X	register int	retcode = FALSE;
X
X	dprintf("%s: trying lock <%s> for process %d\n", Pname, file, pid);
X	if ((tmp = xtmpfile(file, pid, uucpstyle)) == (char *)NULL)
X		return(FALSE);
X
Xlinkloop:
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, uucpstyle)) {
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*/
Xp_exists(pid)
Xint	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
Xcklock(file, uucpstyle)
Xchar	*file;
Xint	uucpstyle;
X{
X	register int	fd = open(file, O_RDONLY);
X	register int	len;
X	int	pid;
X	char	buf[BUFSIZ];
X
X	dprintf("%s: checking extant lock <%s>\n", Pname, file);
X	if (fd < 0) {
X		fprintf(stderr, E_open, Pname, file, errmsg(errno));
X		return(TRUE);	/* might or might not; conservatism */
X	}
X
X	if (uucpstyle ?
X		((len = read(fd, &pid, sizeof(pid))) != sizeof(pid)) :
X		((len = read(fd, buf, sizeof(buf))) <= 0))
X	{
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(uucpstyle ? pid : 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*/
Xchar *
Xxtmpfile(file, pid, uucpstyle)
Xchar	*file;
Xint	pid, uucpstyle;
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);
Xopenloop:
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, E_unlk,
X					Pname, tempname, errmsg(errno));
X				return((char *)NULL);
X			}
X			/*
X			** Further profanity
X			*/
X			goto openloop;
X		default:
X			fprintf(stderr, E_open,
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 (uucpstyle ?
X		(write(fd, &pid, sizeof(pid)) != sizeof(pid)) :
X		(write(fd, buf, len) < 0))
X	{
X		fprintf(stderr, "%s: write(%s,%d): %s\n",
X			Pname, tempname, pid, errmsg(errno));
X		(void) close(fd);
X		if (unlink(tempname) < 0) {
X			fprintf(stderr, E_unlk,
X				Pname, tempname, errmsg(errno));
X		}
X		return((char *)NULL);
X	}
X	(void) close(fd);
X	return(tempname);
X}
END_OF_shlock.c
if test 7101 -ne `wc -c <shlock.c`; then
    echo shar: \"shlock.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f sysexits.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"sysexits.h\"
else
echo shar: Extracting \"sysexits.h\" \(4212 characters\)
sed "s/^X//" >sysexits.h <<'END_OF_sysexits.h'
X/*
X * Copyright (c) 1987 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X *	@(#)sysexits.h	4.3 (Berkeley) 12/15/87
X */
X
X/*
X**  SYSEXITS.H -- Exit status codes for system programs.
X**
X**	This include file attempts to categorize possible error
X**	exit statuses for system programs, notably delivermail
X**	and the Berkeley network.
X**
X**	Error numbers begin at EX__BASE to reduce the possibility of
X**	clashing with other exit statuses that random programs may
X**	already return.  The meaning of the codes is approximately
X**	as follows:
X**
X**	EX_USAGE -- The command was used incorrectly, e.g., with
X**		the wrong number of arguments, a bad flag, a bad
X**		syntax in a parameter, or whatever.
X**	EX_DATAERR -- The input data was incorrect in some way.
X**		This should only be used for user's data & not
X**		system files.
X**	EX_NOINPUT -- An input file (not a system file) did not
X**		exist or was not readable.  This could also include
X**		errors like "No message" to a mailer (if it cared
X**		to catch it).
X**	EX_NOUSER -- The user specified did not exist.  This might
X**		be used for mail addresses or remote logins.
X**	EX_NOHOST -- The host specified did not exist.  This is used
X**		in mail addresses or network requests.
X**	EX_UNAVAILABLE -- A service is unavailable.  This can occur
X**		if a support program or file does not exist.  This
X**		can also be used as a catchall message when something
X**		you wanted to do doesn't work, but you don't know
X**		why.
X**	EX_SOFTWARE -- An internal software error has been detected.
X**		This should be limited to non-operating system related
X**		errors as possible.
X**	EX_OSERR -- An operating system error has been detected.
X**		This is intended to be used for such things as "cannot
X**		fork", "cannot create pipe", or the like.  It includes
X**		things like getuid returning a user that does not
X**		exist in the passwd file.
X**	EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
X**		etc.) does not exist, cannot be opened, or has some
X**		sort of error (e.g., syntax error).
X**	EX_CANTCREAT -- A (user specified) output file cannot be
X**		created.
X**	EX_IOERR -- An error occurred while doing I/O on some file.
X**	EX_TEMPFAIL -- temporary failure, indicating something that
X**		is not really an error.  In sendmail, this means
X**		that a mailer (e.g.) could not create a connection,
X**		and the request should be reattempted later.
X**	EX_PROTOCOL -- the remote system returned something that
X**		was "not possible" during a protocol exchange.
X**	EX_NOPERM -- You did not have sufficient permission to
X**		perform the operation.  This is not intended for
X**		file system problems, which should use NOINPUT or
X**		CANTCREAT, but rather for higher level permissions.
X**		For example, kre uses this to restrict who students
X**		can send mail to.
X**
X**	Maintained by Eric Allman (eric@berkeley, ucbvax!eric) --
X**		please mail changes to me.
X**
X**			@(#)sysexits.h	4.3		12/15/87
X*/
X
X# define EX_OK		0	/* successful termination */
X
X# define EX__BASE	64	/* base value for error messages */
X
X# define EX_USAGE	64	/* command line usage error */
X# define EX_DATAERR	65	/* data format error */
X# define EX_NOINPUT	66	/* cannot open input */
X# define EX_NOUSER	67	/* addressee unknown */
X# define EX_NOHOST	68	/* host name unknown */
X# define EX_UNAVAILABLE	69	/* service unavailable */
X# define EX_SOFTWARE	70	/* internal software error */
X# define EX_OSERR	71	/* system error (e.g., can't fork) */
X# define EX_OSFILE	72	/* critical OS file missing */
X# define EX_CANTCREAT	73	/* can't create (user) output file */
X# define EX_IOERR	74	/* input/output error */
X# define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
X# define EX_PROTOCOL	76	/* remote error in protocol */
X# define EX_NOPERM	77	/* permission denied */
END_OF_sysexits.h
if test 4212 -ne `wc -c <sysexits.h`; then
    echo shar: \"sysexits.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f viaxbatch -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"viaxbatch\"
else
echo shar: Extracting \"viaxbatch\" \(472 characters\)
sed "s/^X//" >viaxbatch <<'END_OF_viaxbatch'
X#!/bin/sh
X#
X# This is the NNTP XBATCH spooler for C News.  B News would need some other
X# mechanism.
X#
X# Be sure to set SPOOLDIR to the proper place, and modify nntpqueue.csh
X# accordingly.
X#
XSPOOLDIR=/var/spool/nntp/$1
X
Xif [ ! -d ${SPOOLDIR} ]
Xthen
X	mkdir ${SPOOLDIR}
Xfi
XDATE=`date`
XXBATCHF=`/usr/local/newsbin/getdate "${DATE}"`
X# make sure the batch file is unique
Xwhile [ -f ${SPOOLDIR}/${XBATCHF} ]
Xdo
X  XBATCHF=`expr ${XBATCHF} + 1`
Xdone
Xcat >${SPOOLDIR}/${XBATCHF}
END_OF_viaxbatch
if test 472 -ne `wc -c <viaxbatch`; then
    echo shar: \"viaxbatch\" unpacked with wrong size!
fi
chmod +x viaxbatch
# end of overwriting check
fi
if test -f xmitauth.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"xmitauth.c\"
else
echo shar: Extracting \"xmitauth.c\" \(1172 characters\)
sed "s/^X//" >xmitauth.c <<'END_OF_xmitauth.c'
X#include <stdio.h>
X#include "../common/conf.h"
X#include "../common/nntp.h"
X#include "nntpbatch.h"
X
X#ifdef AUTH
X
Xextern char Debug;
Xextern int converse();
X
XFILE *sys;
X
Xxmitauth(host)
Xchar *host;
X	{
X	char remote[64], user[16], pass[16];
X	char buf[1024];
X	int i;
X	char savedebug;
X
X	sys = fopen(PASSFILE, "r");
X	if (sys == NULL)
X		{
X		exit(1);
X		}
X	
X	while(fgets(buf, sizeof(buf), sys))
X		{
X		if (buf[0] == '#')
X			continue;
X		
X		i = sscanf(buf,"%s %s %s", remote, user, pass);
X		/* malformed entry? */
X		if (i != 3)
X			{
X			log(L_NOTICE,"malformed entry in nntp.sys");
X			continue;
X			}
X		
X		/* right host? */
X		if (!strcasecmp(remote,host))
X			break;
X		}
X	if (feof(sys))
X		{
X		sprintf(buf,"host %s authinfo not in nntp.sys", host);
X		log(L_NOTICE, buf);
X		exit(1);
X		}
X	
X	sprintf(buf,"authinfo user %s", user);
X	if (converse(buf, sizeof(buf)) != NEED_AUTHDATA)
X		{
X		log(L_NOTICE, buf);
X		exit(1);
X		}
X	
X	/* don't display the password even if debug is on */
X	savedebug = Debug;
X	Debug = FALSE;
X
X	sprintf(buf,"authinfo pass %s", pass);
X	if (converse(buf, sizeof(buf)) != OK_AUTH)
X		{
X		log(L_NOTICE, buf);
X		exit(1);
X		}
X	
X	Debug = savedebug;
X
X	fclose(sys);
X	}
X
X#endif AUTH
X
END_OF_xmitauth.c
if test 1172 -ne `wc -c <xmitauth.c`; then
    echo shar: \"xmitauth.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 1 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Frank Mayhar  fmayhar@hermes.ladc.bull.com (..!{uunet,hacgate}!ladcgw!fmayhar)
              Bull HN Information Systems Inc.  Los Angeles Development Center
              5250 W. Century Blvd., LA, CA  90045    Phone:  (213) 216-6241


-- 
Simon J. Gerraty        <sjg@sun0.melb.bull.oz.au>      (work)
                        <sjg@zen.void.oz.au>            (home)

#include <disclaimer>   /* imagine something *very* witty here */