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 */