v14i052: Network News Transfer Protocol, version 1.5, Part06/09
Rich Salz
rsalz at bbn.com
Thu Apr 21 08:06:47 AEST 1988
Submitted-by: Phil Lapsley <phil at ucbvax.berkeley.edu>
Posting-number: Volume 14, Issue 52
Archive-name: nntp1.5/part06
#! /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 6 (of 9)."
# Contents: ./CHANGES ./common/clientlib.c ./server/newnews.c
# ./xfer/nntpxfer.c ./xmit/remote.c
# Wrapped by rsalz at fig.bbn.com on Tue Apr 19 18:16:45 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f './CHANGES' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'./CHANGES'\"
else
echo shar: Extracting \"'./CHANGES'\" \(9242 characters\)
sed "s/^X//" >'./CHANGES' <<'END_OF_FILE'
X
X This file describes the changes which have been made in NNTP
since the initial release. Individuals who either reported or
inspired the bug/bug fix are in square brackets.
X
X1.5 February 26, 1988
X
X New top level Makefile. [Casey Leedom, casey at lll-crg.llnl.gov]
X
X Now using strcasecmp/strncasecmp instead of streql/strneql.
X Due credit is given to the University of California at [sic]
X Berkeley for the use of this software. :-)
X
X Combined common/response_codes.h and common/rfc977.h into
X common/nntp.h.
X
X Better fix for getifnetmask ioctl returning 0 netmask.
X
X Patch to Configure to handle domains for non-portable code.
X [Brad Smith, brad at saturn.ucsc.edu]
X
X New version of nntpxmit with article retransmission.
X [Erik Fair, fair at ucbarpa.Berkeley.EDU].
X
X System V compatability; will now compile on Hockey-Pux (HPUX).
X [Stan Barber, sob%soma.tmc.edu at tmc.edu]
X
X EXCELAN TCP support. [Stan Barber, sob%soma.tmc.edu at tmc.edu]
X
X server/subnet.c now supports compiled-in netmasks.
X This is useful if you want subnet support on machines
X that don't have the necessary ioctls for determining
X network masks on a per-interface basis.
X
X Fake syslog support included for real this time.
X
X1.4 October 15, 1987
X
X Reorganized documentation directory. Thanks for the
X extraction stuff, Stan. [Stan Barber, sob%%soma.uucp at rice.edu]
X
X Added transfer timeouts. [Steve Schoch, schoch at ames.arpa]
X
X Fixed a problem with IHAVE which allowed a remote machine to
X repeatedly feed you articles that you expired (although all
X you'd do with them is throw them away).
X [Fred Avolio, avolio at decuac.dec.com]
X
X DECNet support (see server/dnet_access.c and common/clientlib.c).
X [Matt Thomas, thomas%syrah.dec at decwrl.dec.com]
X
X Fixed serious joe code in distribution checks in NEWNEWS.
X
X NEWNEWS statistics.
X
X Newsgroup security.
X
X Performance enhancements (about 2x better for article xfers).
X
X xhdr command added to improve performance on subject searches.
X
X Compiled-in server name no longer supported.
X
X common/clientlib.c/getserverbyfile() now looks at the
X environment variable NNTPSERVER before checking the file.
X
X inews/inews.c now limits .signature files to MAX_SIGNATURE lines.
X
X server/misc.c/spawn() now returns the error output of rnews/inews
X alone with the posting failed code. This is in turn printed by
X inews/inews.c so the user has some idea of why his article wasn't
X accepted.
X
X rn patches now for patchlevel #40
X Bug fix: rrn no longer leaves droppings in /tmp
X "Skipping unavailable article" problems fixed
X Support for 4.3 TIOCGWINSZ ioctl [sam at okeeffe.berkeley.edu]
X Configure asks for domains
X Pnews/Rnmail understand hostnames with .'s in them.
X Makefile fixes [harvard!lownlab!kiely]
X
X PYRAMID #defines removed, as it is all being done by default now.
X
X inews/inews.c now exits 0, since before it had a random exit
X status, causing pyramids to choke. [forys at boulder.colorado.edu]
X
X server/server.c now logs user/system/elapsed time as floats
X instead of ints. [rick at seismo.css.gov]
X
X server/ihave.c no longer logs every message id transfered but
X instead keeps statistics which are logged at the end.
X [rick at seismo.css.gov]
X
X server/serve.c now times out after TIMEOUT seconds of idleness.
X
X server/access.c converts remote hostname to lower case
X when logging, in case you have a nameserver which is helping you.
X
X server/misc.c/getartbyid now reports message-id's when
X it encounters a malformed line in the history file.
X [gds at spam.istc.sri.com]
X
X inews/inews.c had an uninitialized variable, which
X could cause trouble. [jwp%chem at sdcsvax.ucsd.edu]
X
X common/clientlib.c now understands 4.3 nameserver
X multiple addresses, and tries them all before
X giving up.
X
X common/clientlib.c has has 2 new functions:
X "getserverbyfile" opens a given file and returns
X the name of the server given in the file to use
X for news. "handle_server_response" prints informative
X messages based on the initial connection response code.
X
X server/access.c now is case insensitive when checking
X for host read/xfer permissions.
X
X server/misc.c/spawn didn't check for a closed connection
X while receiving input from client. As a result, truncated
X news articles could be received.
X
X server/newnews.c had a printf which was missing an
X argument. [louie at trantor.umd.edu]
X
X Added fake syslog facility to server. Code is in
X server/fakesyslog.c. [mckenny at sri-unix.arpa]
X
X Fixed length argument to accept() in server/main.c
X [mckenny at sri-unix.arpa]
X
X Now uses pipe to rnews so as to get rnews output for debugging.
X Also chowns temporary file to POSTER's uid and gid.
X [mckenny at sri-unix.arpa]
X
X Fixed bugs in server/netaux.c to close syslog fd.
X [mckenny at sri-unix.arpa]
X
X Made bcopy() standard in server/misc.c [kre at munnari.OZ]
X
X Documentation changes to make certain things about client
X installation clearer. [munnari!charlie.oz!craig]
X
X1.3 30 June 1986
X
X rrn is no longer included as complete source, but
X rather as a set of context diffs and a program to
X apply them to your rn source. Many thanks go to
X Gene Spafford for an outstanding job doing this.
X [spaf at gatech.csnet]
X
X The dreaded kill/save bug is fixed; rn was passing
X /bin/sh too many open file descriptors. Thanks and a tip of the
X proverbial hat to Chris Maio! Change to rrn/util.c.
X [chris at columbia.edu]
X
X Fixed a bug in rrn/artio.c which caused an assertion
X failure on line 114 of artio.c; artopen was returning
X Nullfp without closing the fp associated with the
X bogus article. [genrad!ens at eddie.mit.edu, beorn at ic.berkeley.edu]
X
X Added #define PYRAMID in common/conf.h, added some
X #ifdef PYRAMID code in server/misc.c to deal with
X Pyramids not initializing static data to 0, as well
X as an fseek problem. [spaf at gatech.CSNET]
X
X Another wait bug fixed in spawn() in server/misc.c.
X
X Added a required \r in post.c.
X
X Added signal(SIGCHLD, SIG_IGN) to server/serve.c,
X to fix exit status problem with ALONE defined.
X
X Statistics logging now returns sum of the nntpd and
X its children for process time. server/main.c
X [fair at ucbarpa.berkeley.edu]
X
X Subnet support for access file finally added.
X server/subnet.c added, common/conf.h now has
X #defines for SUBNET, DAMAGED_NETMASK.
X
X inews/inews.c now generates a from line with the UUCP
X name instead of always using gethostname(). common/conf.h
X changed to add #defines for UUNAME, GHNAME.
X [jwang at atrp.mit.edu]
X
X Added LIBS to Makefile. [soma!sob at rice.edu]
X
X1.2c 17 May 1986
X
X Support for Masscomp added (#define MASSCOMP in ../common/conf.h).
X [soma!sob at rice.edu]
X
X Syslog output now requires SYSLOG to be defined in ../common/conf.h.
X This is handy on systems which, for some reason or another,
X don't have syslog. [soma!sob at rice.edu]
X
X server/post.c had arguments reversed in a printf. [salex at rice.edu]
X
X rrn/common.h had PIPESAVER misdefined. [cspencer at bbncc5.arpa]
X
X server/group.c was missing a \r in a printf. [lear at rutgers.edu]
X
X xmit/nntpxmit.c is a new version. Highlights include
X improved error reactions and logging info. [fair at ucbarpa.berkeley.edu]
X
X xmit/nntpsend is a shell script for sending news via nntp
X in a sane manner, with locking. [pleasant at topaz.rutgers.edu,
X fair at ucbarpa.berkeley.edu] The locking mechanism is provided
X courtesy of Mr. Fair's "shlock.c", in xmit/shlock.c.
X
X support/nntp_awk produces weekly reports from the nntp server
X logging output. [fair at ucbarpa.berkeley.edu]
X
X Makefile (in this directory) would do a "make install" as
X the default action; it now prints a helpful message.
X [arnold at cgl.ucsf.edu]
X
X server/Makefile and support/Makefile had needless dependencies
X in them; if you didn't do a make depend, you'd have problems
X on a 4.2 system. The server and support stuff now depend only
X on their own .h files. [arnold at cgl.ucsf.edu]
X
X1.2b 13 April 1986
X
X common/clientlib.c stupidly had some debugging printfs
X enabled.
X
X rrn/{artio.c,head.c} had sprintf("... %d", foo) where "foo"
X was a long. %d -> %ld. [cspencer at bbncc5.arpa]
X
X server/time.c had an order of evaluation problem in the
X macro "twodigtoi". [fletcher at tzec.cs.utexas.edu, among others.]
X
X server/common.h included <dbm.h> if DBM was defined,
X caused multiply-defined NULL's. [cda at opal.berkeley.edu,
X pleasant at topaz.rutgers.edu, among others.]
X
X server/active.c would lose because variable "i" would be
X at the end of the group array if it was called on a timer
X interrupt. "i" now set to zero properly. This only occurs
X if FASTFORK is defined. [cda at opal.berkeley.edu]
X
X1.2a 20 March 1986
X
X common/conf.h defined MAX_GROUPS as 300; this was too low on
X some machines. Upped to 450. [solex at rice.edu, beorn at ic.berkeley.edu]
X
X rrn/Makefile.sh had .c instead of .o for OBJS and SRCS
X respectively. Also had cc -o ../common/clientlib.o (see below).
X
X inews/inews.c had (char *) 0 for gets(), which made SUN's upset.
X Changed to simply NULL. [brian at sdcsvax.ucsd.edu]
X
X inews/Makefile had cc -o ../common/clientlib.o which some
X machines don't do. [brian at sdcsvax.ucsd.edu]
X
X common/clientlib.c has "untp" instead of "nntp".
X
X server/active.c made more robust about reading active file
X if active file is longer than MAX_GROUPS.
X
X server/common.h included common/conf.h after checking for
X DBM, which caused some problems. [soma!sob at rice.edu]
X
X1.2 15 March 1986
X
X Released.
END_OF_FILE
if test 9242 -ne `wc -c <'./CHANGES'`; then
echo shar: \"'./CHANGES'\" unpacked with wrong size!
fi
# end of './CHANGES'
fi
if test -f './common/clientlib.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'./common/clientlib.c'\"
else
echo shar: Extracting \"'./common/clientlib.c'\" \(10189 characters\)
sed "s/^X//" >'./common/clientlib.c' <<'END_OF_FILE'
X#ifndef lint
static char *sccsid = "@(#)clientlib.c 1.9 (Berkeley) 2/25/88";
X#endif
X
X/*
X * NNTP client routines.
X */
X
X/*
X * Include configuration parameters only if we're made in the nntp tree.
X */
X
X#ifdef NNTPSRC
X#include "../common/conf.h"
X#endif NNTPSRC
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#ifndef EXCELAN
X# include <netdb.h>
X#endif not EXCELAN
X
X#ifdef USG
X# define index strchr
X#endif USG
X
X#ifdef EXCELAN
X# define IPPORT_NNTP 119
X#endif
X
X#ifdef DECNET
X#include <netdnet/dn.h>
X#include <netdnet/dnetdb.h>
X#endif DECNET
X
X#include "nntp.h"
X
FILE *ser_rd_fp = NULL;
FILE *ser_wr_fp = NULL;
X
X/*
X * getserverbyfile Get the name of a server from a named file.
X * Handle white space and comments.
X * Use NNTPSERVER environment variable if set.
X *
X * Parameters: "file" is the name of the file to read.
X *
X * Returns: Pointer to static data area containing the
X * first non-ws/comment line in the file.
X * NULL on error (or lack of entry in file).
X *
X * Side effects: None.
X */
X
char *
getserverbyfile(file)
char *file;
X{
X register FILE *fp;
X register char *cp;
X static char buf[256];
X char *index();
X char *getenv();
X char *strcpy();
X
X if (cp = getenv("NNTPSERVER")) {
X (void) strcpy(buf, cp);
X return (buf);
X }
X
X if (file == NULL)
X return (NULL);
X
X fp = fopen(file, "r");
X if (fp == NULL)
X return (NULL);
X
X while (fgets(buf, sizeof (buf), fp) != NULL) {
X if (*buf == '\n' || *buf == '#')
X continue;
X cp = index(buf, '\n');
X if (cp)
X *cp = '\0';
X (void) fclose(fp);
X return (buf);
X }
X
X (void) fclose(fp);
X return (NULL); /* No entry */
X}
X
X
X/*
X * server_init Get a connection to the remote news server.
X *
X * Parameters: "machine" is the machine to connect to.
X *
X * Returns: -1 on error
X * server's initial response code on success.
X *
X * Side effects: Connects to server.
X * "ser_rd_fp" and "ser_wr_fp" are fp's
X * for reading and writing to server.
X */
X
server_init(machine)
char *machine;
X{
X int sockt_rd, sockt_wr;
X char line[256];
X char *index();
X#ifdef DECNET
X char *cp;
X
X cp = index(machine, ':');
X
X if (cp && cp[1] == ':') {
X *cp = '\0';
X sockt_rd = get_dnet_socket(machine);
X } else
X sockt_rd = get_tcp_socket(machine);
X#else
X sockt_rd = get_tcp_socket(machine);
X#endif
X
X if (sockt_rd < 0)
X return (-1);
X
X /*
X * Now we'll make file pointers (i.e., buffered I/O) out of
X * the socket file descriptor. Note that we can't just
X * open a fp for reading and writing -- we have to open
X * up two separate fp's, one for reading, one for writing.
X */
X
X if ((ser_rd_fp = fdopen(sockt_rd, "r")) == NULL) {
X perror("server_init: fdopen #1");
X return (-1);
X }
X
X sockt_wr = dup(sockt_rd);
X if ((ser_wr_fp = fdopen(sockt_wr, "w")) == NULL) {
X perror("server_init: fdopen #2");
X ser_rd_fp = NULL; /* from above */
X return (-1);
X }
X
X /* Now get the server's signon message */
X
X (void) get_server(line, sizeof(line));
X return (atoi(line));
X}
X
X
X/*
X * get_tcp_socket -- get us a socket connected to the news server.
X *
X * Parameters: "machine" is the machine the server is running on.
X *
X * Returns: Socket connected to the news server if
X * all is ok, else -1 on error.
X *
X * Side effects: Connects to server.
X *
X * Errors: Printed via perror.
X */
X
get_tcp_socket(machine)
char *machine;
X{
X int s;
X struct sockaddr_in sin;
X#ifndef EXCELAN
X struct servent *getservbyname(), *sp;
X struct hostent *gethostbyname(), *hp;
X#ifdef h_addr
X int x = 0;
X register char **cp;
X#endif h_addr
X
X if ((sp = getservbyname("nntp", "tcp")) == NULL) {
X fprintf(stderr, "nntp/tcp: Unknown service.\n");
X return (-1);
X }
X
X if ((hp = gethostbyname(machine)) == NULL) {
X fprintf(stderr, "%s: Unknown host.\n", machine);
X return (-1);
X }
X
X bzero((char *) &sin, sizeof(sin));
X sin.sin_family = hp->h_addrtype;
X sin.sin_port = sp->s_port;
X#else EXCELAN
X bzero((char *) &sin, sizeof(sin));
X sin.sin_family = AF_INET;
X sin.sin_port = htons(IPPORT_NNTP);
X#endif EXCELAN
X
X /*
X * The following is kinda gross. The name server under 4.3
X * returns a list of addresses, each of which should be tried
X * in turn if the previous one fails. However, 4.2 hostent
X * structure doesn't have this list of addresses.
X * Under 4.3, h_addr is a #define to h_addr_list[0].
X * We use this to figure out whether to include the NS specific
X * code...
X */
X
X#ifdef h_addr
X
X /* get a socket and initiate connection -- use multiple addresses */
X
X for (cp = hp->h_addr_list; cp && *cp; cp++) {
X s = socket(hp->h_addrtype, SOCK_STREAM, 0);
X if (s < 0) {
X perror("socket");
X return (-1);
X }
X bcopy(*cp, (char *)&sin.sin_addr, hp->h_length);
X
X if (x < 0)
X fprintf(stderr, "trying %s\n", inet_ntoa(sin.sin_addr));
X x = connect(s, (struct sockaddr *)&sin, sizeof (sin));
X if (x == 0)
X break;
X fprintf(stderr, "connection to %s: ", inet_ntoa(sin.sin_addr));
X perror("");
X (void) close(s);
X }
X if (x < 0) {
X fprintf(stderr, "giving up...\n");
X return (-1);
X }
X#else /* no name server */
X#ifdef EXCELAN
X if ((s = rresvport(SO_KEEPALIVE)) < 0)
X {
X /* Get the socket */
X perror("socket");
X return (-1);
X }
X /* set up addr for the connect */
X sin.sin_addr.s_addr = rhost(machine);
X if (sin.sin_addr.s_addr < 0){
X fprintf(stderr, "%s: Unknown host.\n", machine);
X return (-1);
X }
X /* And then connect */
X
X if (connect(s, &sin) < 0) {
X perror("connect");
X (void) close(s);
X return (-1);
X }
X#else not EXCELAN
X if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
X perror("socket");
X return (-1);
X }
X
X /* And then connect */
X
X bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
X if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
X perror("connect");
X (void) close(s);
X return (-1);
X }
X
X#endif not EXCELAN
X#endif
X
X return (s);
X}
X
X#ifdef DECNET
X/*
X * get_dnet_socket -- get us a socket connected to the news server.
X *
X * Parameters: "machine" is the machine the server is running on.
X *
X * Returns: Socket connected to the news server if
X * all is ok, else -1 on error.
X *
X * Side effects: Connects to server.
X *
X * Errors: Printed via nerror.
X */
X
get_dnet_socket(machine)
char *machine;
X{
X int s, area, node;
X struct sockaddr_dn sdn;
X struct nodeent *getnodebyname(), *np;
X
X bzero((char *) &sdn, sizeof(sdn));
X
X switch (s = sscanf( machine, "%d%*[.]%d", &area, &node )) {
X case 1:
X node = area;
X area = 0;
X case 2:
X node += area*1024;
X sdn.sdn_add.a_len = 2;
X sdn.sdn_family = AF_DECnet;
X sdn.sdn_add.a_addr[0] = node % 256;
X sdn.sdn_add.a_addr[1] = node / 256;
X break;
X default:
X if ((np = getnodebyname(machine)) == NULL) {
X fprintf(stderr,
X "%s: Unknown host.\n", machine);
X return (-1);
X } else {
X bcopy(np->n_addr,
X (char *) sdn.sdn_add.a_addr,
X np->n_length);
X sdn.sdn_add.a_len = np->n_length;
X sdn.sdn_family = np->n_addrtype;
X }
X break;
X }
X sdn.sdn_objnum = 0;
X sdn.sdn_flags = 0;
X sdn.sdn_objnamel = strlen("NNTP");
X bcopy("NNTP", &sdn.sdn_objname[0], sdn.sdn_objnamel);
X
X if ((s = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) {
X nerror("socket");
X return (-1);
X }
X
X /* And then connect */
X
X if (connect(s, (struct sockaddr *) &sdn, sizeof(sdn)) < 0) {
X nerror("connect");
X close(s);
X return (-1);
X }
X
X return (s);
X}
X#endif
X
X
X
X/*
X * handle_server_response
X *
X * Print some informative messages based on the server's initial
X * response code. This is here so inews, rn, etc. can share
X * the code.
X *
X * Parameters: "response" is the response code which the
X * server sent us, presumably from "server_init",
X * above.
X * "server" is the news server we got the
X * response code from.
X *
X * Returns: -1 if the error is fatal (and we should exit).
X * 0 otherwise.
X *
X * Side effects: None.
X */
X
handle_server_response(response, server)
int response;
char *server;
X{
X switch (response) {
X case OK_NOPOST: /* fall through */
X printf(
X "NOTE: This machine does not have permission to post articles.\n");
X printf(
X " Please don't waste your time trying.\n\n");
X
X case OK_CANPOST:
X return (0);
X break;
X
X case ERR_ACCESS:
X printf(
X "This machine does not have permission to use the %s news server.\n",
X server);
X return (-1);
X break;
X
X default:
X printf("Unexpected response code from %s news server: %d\n",
X server, response);
X return (-1);
X break;
X }
X /*NOTREACHED*/
X}
X
X
X/*
X * put_server -- send a line of text to the server, terminating it
X * with CR and LF, as per ARPA standard.
X *
X * Parameters: "string" is the string to be sent to the
X * server.
X *
X * Returns: Nothing.
X *
X * Side effects: Talks to the server.
X *
X * Note: This routine flushes the buffer each time
X * it is called. For large transmissions
X * (i.e., posting news) don't use it. Instead,
X * do the fprintf's yourself, and then a final
X * fflush.
X */
X
void
put_server(string)
char *string;
X{
X#ifdef DEBUG
X fprintf(stderr, ">>> %s\n", string);
X#endif
X fprintf(ser_wr_fp, "%s\r\n", string);
X (void) fflush(ser_wr_fp);
X}
X
X
X/*
X * get_server -- get a line of text from the server. Strips
X * CR's and LF's.
X *
X * Parameters: "string" has the buffer space for the
X * line received.
X * "size" is the size of the buffer.
X *
X * Returns: -1 on error, 0 otherwise.
X *
X * Side effects: Talks to server, changes contents of "string".
X */
X
get_server(string, size)
char *string;
int size;
X{
X register char *cp;
X char *index();
X
X if (fgets(string, size, ser_rd_fp) == NULL)
X return (-1);
X
X if ((cp = index(string, '\r')) != NULL)
X *cp = '\0';
X else if ((cp = index(string, '\n')) != NULL)
X *cp = '\0';
X#ifdef DEBUG
X fprintf(stderr, "<<< %s\n", string);
X#endif
X
X return (0);
X}
X
X
X/*
X * close_server -- close the connection to the server, after sending
X * the "quit" command.
X *
X * Parameters: None.
X *
X * Returns: Nothing.
X *
X * Side effects: Closes the connection with the server.
X * You can't use "put_server" or "get_server"
X * after this routine is called.
X */
X
void
close_server()
X{
X char ser_line[256];
X
X if (ser_wr_fp == NULL || ser_rd_fp == NULL)
X return;
X
X put_server("QUIT");
X (void) get_server(ser_line, sizeof(ser_line));
X
X (void) fclose(ser_wr_fp);
X (void) fclose(ser_rd_fp);
X}
X
X#ifdef USG
bzero(p, l)
X register char *p;
X register int l;
X{
X while (l-- > 0)
X *p++ = 0;
X}
X#endif USG
END_OF_FILE
if test 10189 -ne `wc -c <'./common/clientlib.c'`; then
echo shar: \"'./common/clientlib.c'\" unpacked with wrong size!
fi
# end of './common/clientlib.c'
fi
if test -f './server/newnews.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'./server/newnews.c'\"
else
echo shar: Extracting \"'./server/newnews.c'\" \(10834 characters\)
sed "s/^X//" >'./server/newnews.c' <<'END_OF_FILE'
X#ifndef lint
static char *sccsid = "@(#)newnews.c 1.19 (Berkeley) 2/6/88";
X#endif
X
X#include "common.h"
X#include "time.h"
X
X#ifdef LOG
int nn_told = 0;
int nn_took = 0;
X#endif
X
X
X/*
X * NEWNEWS newsgroups date time ["GMT"] [<distributions>]
X *
X * Return the message-id's of any news articles past
X * a certain date and time, within the specified distributions.
X *
X */
X
newnews(argc, argv)
X register int argc;
X char *argv[];
X{
X register char *cp, *ngp;
X char *key;
X char datebuf[32];
X char line[MAXBUFLEN];
X char **distlist, **histlist;
X static char **nglist;
X int distcount, ngcount, histcount;
X int all;
X FILE *fp;
X long date;
X long dtol();
X char *ltod();
X#ifdef USG
X FILE *tmplst;
X int i;
X char *tmpfile;
X#endif USG
X
X if (argc < 4) {
X printf("%d Usage: NEWNEWS newsgroups yymmdd hhmmss [\"GMT\"] [<distributions>].\r\n",
X ERR_CMDSYN);
X (void) fflush(stdout);
X return;
X }
X
X#ifdef LOG
X sprintf(line, "%s newnews %s %s %s %s %s",
X hostname,
X argv[1],
X argv[2],
X argv[3],
X (argc >= 5 && *argv[4] == 'G') ? "GMT" : "local",
X (argc >= 5 && *argv[argc-1] == '<') ? argv[argc-1] : "none");
X syslog(LOG_INFO, line);
X#endif
X
X all = (argv[1][0] == '*' && argv[1][1] == '\0');
X if (!all) {
X ngcount = get_nglist(&nglist, argv[1]);
X if (ngcount == 0) {
X printf("%d Bogus newsgroup specifier: %s\r\n",
X ERR_CMDSYN, argv[1]);
X (void) fflush(stdout);
X return;
X }
X }
X
X /* YYMMDD HHMMSS */
X if (strlen(argv[2]) != 6 || strlen(argv[3]) != 6) {
X printf("%d Date/time must be in form YYMMDD HHMMSS.\r\n",
X ERR_CMDSYN);
X (void) fflush(stdout);
X return;
X }
X
X (void) strcpy(datebuf, argv[2]);
X (void) strcat(datebuf, argv[3]);
X
X argc -= 4;
X argv += 4;
X
X /*
X * Flame on. The history file is not stored in GMT, but
X * in local time. So we have to convert GMT to local time
X * if we're given GMT, otherwise we need only chop off the
X * the seconds. Such braindamage.
X */
X
X key = datebuf; /* Unless they specify GMT */
X
X if (argc > 0) {
X if (!strcasecmp(*argv, "GMT")) { /* Which we handle here */
X date = dtol(datebuf);
X if (date < 0) {
X printf("%d Invalid date specification.\r\n",
X ERR_CMDSYN);
X (void) fflush(stdout);
X return;
X }
X date = gmt_to_local(date);
X key = ltod(date);
X ++argv;
X --argc;
X }
X }
X
X /* So, key now points to the local time, but we need to zap secs */
X
X key[10] = '\0';
X
X distcount = 0;
X if (argc > 0) {
X distcount = get_distlist(&distlist, *argv);
X if (distcount < 0) {
X printf("%d Bad distribution list: %s\r\n", ERR_CMDSYN,
X *argv);
X (void) fflush(stdout);
X return;
X }
X }
X
X#ifdef USG
X if ((tmpfile = mktemp("/tmp/listXXXXXX")) == NULL ||
X (tmplst = fopen(tmpfile, "w+")) == NULL) {
X printf("%d Cannot process history file.\r\n", ERR_FAULT);
X (void) fflush(stdout);
X return;
X }
X
X for (i = 0; i < 9; i++) {
X sprintf(historyfile, "%s.d/%d", HISTORY_FILE, i);
X#endif USG
X
X fp = fopen(historyfile, "r");
X if (fp == NULL) {
X#ifdef SYSLOG
X syslog(LOG_ERR, "newnews: fopen %s: %m", historyfile);
X#endif
X#ifndef USG
X printf("%d Cannot open history file.\r\n", ERR_FAULT);
X (void) fflush(stdout);
X return;
X#else USG
X continue;
X#endif USG
X }
X
X#ifndef USG
X printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
X#endif not USG
X
X if (seekuntil(fp, key, line, sizeof (line)) < 0) {
X#ifndef USG
X printf(".\r\n");
X (void) fflush(stdout);
X#endif not USG
X (void) fclose(fp);
X#ifndef USG
X return;
X#else USG
X continue;
X#endif USG
X }
X
X/*
X * History file looks like:
X *
X * <1569 at emory.UUCP> 01/22/86 09:19 net.micro.att/899 ucb.general/2545
X * ^--tab ^--tab ^--space ^sp\0
X * Sometimes the newsgroups are missing; we try to be robust and
X * ignore such bogosity. We tackle this by our usual parse routine,
X * and break the list of articles in the history file into an argv
X * array with one newsgroup per entry.
X */
X
X do {
X if ((cp = index(line, '\t')) == NULL)
X continue;
X
X if ((ngp = index(cp+1, '\t')) == NULL) /* 2nd tab */
X continue;
X ++ngp; /* Points at newsgroup list */
X if (*ngp == '\n')
X continue;
X histcount = get_histlist(&histlist, ngp);
X if (histcount == 0)
X continue;
X
X /*
X * For each newsgroup on this line in the history
X * file, check it against the newsgroup names we're given.
X * If it matches, then see if we're hacking distributions.
X * If so, open the file and match the distribution line.
X */
X
X if (!all)
X if (!ngmatch(restreql, 0, nglist, ngcount,
X histlist, histcount))
X continue;
X
X if (distcount)
X if (!distmatch(distlist, distcount, histlist, histcount))
X continue;
X
X *cp = '\0';
X#ifdef USG
X fputs(line, tmplst);
X fputc('\n', tmplst);
X#else not USG
X putline(line);
X#endif not USG
X#ifdef LOG
X nn_told++;
X#endif
X } while (fgets(line, sizeof(line), fp) != NULL);
X
X#ifndef USG
X putchar('.');
X putchar('\r');
X putchar('\n');
X (void) fflush(stdout);
X#endif
X (void) fclose(fp);
X#ifdef USG
X }
X printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
X rewind(tmplst);
X while (fgets(line, sizeof(line), tmplst) != NULL)
X putline(line);
X putchar('.');
X putchar('\r');
X putchar('\n');
X (void) fflush(stdout);
X (void) fclose(tmplst);
X (void) unlink(tmpfile);
X#endif USG
X}
X
X
X/*
X * seekuntil -- seek through the history file looking for
X * a line with date "key". Get that line, and return.
X *
X * Parameters: "fp" is the active file.
X * "key" is the date, in form YYMMDDHHMM (no SS)
X * "line" is storage for the first line we find.
X *
X * Returns: -1 on error, 0 otherwise.
X *
X * Side effects: Seeks in history file, modifies line.
X */
X
seekuntil(fp, key, line, linesize)
X FILE *fp;
X char *key;
X char *line;
X int linesize;
X{
X char datetime[32];
X register int c;
X register long top, bot, mid;
X
X bot = 0;
X (void) fseek(fp, 0L, 2);
X top = ftell(fp);
X for(;;) {
X mid = (top+bot)/2;
X (void) fseek(fp, mid, 0);
X do {
X c = getc(fp);
X mid++;
X } while (c != EOF && c!='\n');
X if (!getword(fp, datetime, line, linesize)) {
X return (-1);
X }
X switch (compare(key, datetime)) {
X case -2:
X case -1:
X case 0:
X if (top <= mid)
X break;
X top = mid;
X continue;
X case 1:
X case 2:
X bot = mid;
X continue;
X }
X break;
X }
X (void) fseek(fp, bot, 0);
X while(ftell(fp) < top) {
X if (!getword(fp, datetime, line, linesize)) {
X return (-1);
X }
X switch(compare(key, datetime)) {
X case -2:
X case -1:
X case 0:
X break;
X case 1:
X case 2:
X continue;
X }
X break;
X }
X
X return (0);
X}
X
X
compare(s, t)
X register char *s, *t;
X{
X for (; *s == *t; s++, t++)
X if (*s == 0)
X return(0);
X return (*s == 0 ? -1:
X *t == 0 ? 1:
X *s < *t ? -2:
X 2);
X}
X
X
getword(fp, w, line, linesize)
X FILE *fp;
X register char *w;
X char *line;
X int linesize;
X{
X register char *cp;
X
X if (fgets(line, linesize, fp) == NULL)
X return (0);
X if (cp = index(line, '\t')) {
X/*
X * The following gross hack is present because the history file date
X * format is braindamaged. They like "mm/dd/yy hh:mm", which is useless
X * for relative comparisons of dates using something like atoi() or
X * strcmp. So, this changes their format into yymmddhhmm. Sigh.
X *
X * 12345678901234 ("x" for cp[x])
X * mm/dd/yy hh:mm (their lousy representation)
X * yymmddhhmm (our good one)
X * 0123456789 ("x" for w[x])
X */
X *cp = '\0';
X (void) strncpy(w, cp+1, 15);
X w[0] = cp[7]; /* Years */
X w[1] = cp[8];
X w[2] = cp[1]; /* Months */
X w[3] = cp[2];
X w[4] = cp[4]; /* Days */
X w[5] = cp[5];
X w[6] = cp[10]; /* Hours */
X w[7] = cp[11];
X w[8] = cp[13]; /* Minutes */
X w[9] = cp[14];
X w[10] = '\0';
X } else
X w[0] = '\0';
X return (1);
X}
X
X
X/*
X * distmatch -- see if a file matches a set of distributions.
X * We have to do this by (yech!) opening the file, finding
X * the Distribution: line, if it has one, and seeing if the
X * things match.
X *
X * Parameters: "distlist" is the distribution list
X * we want.
X * "distcount" is the count of distributions in it.
X * "grouplist" is the list of groups (articles)
X * for this line of the history file. Note that
X * this isn't quite a filename.
X * "groupcount" is the count of groups in it.
X *
X * Returns: 1 if the article is in the given distribution.
X * 0 otherwise.
X */
X
distmatch(distlist, distcount, grouplist, groupcount)
X char *distlist[];
X int distcount;
X char *grouplist[];
X int groupcount;
X{
X register char c;
X register char *cp;
X register FILE *fp;
X register int i, j;
X char buf[MAXBUFLEN];
X
X (void) strcpy(buf, spooldir);
X (void) strcat(buf, "/");
X (void) strcat(buf, grouplist[0]);
X
X for (cp = buf; *cp; cp++)
X if (*cp == '.')
X *cp = '/';
X
X fp = fopen(buf, "r");
X if (fp == NULL) {
X#ifdef SYSLOG
X syslog(LOG_ERR, "distmatch: fopen %s: %m", buf);
X#endif
X return (0);
X }
X
X while (fgets(buf, sizeof (buf), fp) != NULL) {
X if ((c = buf[0]) == '\n') /* End of header */
X break;
X if (c != 'd' && c != 'D')
X continue;
X cp = index(cp + 1, '\n');
X if (cp)
X *cp = '\0';
X cp = index(buf, ':');
X if (cp == NULL)
X continue;
X *cp = '\0';
X if (!strcasecmp(buf, "distribution")) {
X for (i = 0; i < distcount; ++i) {
X if (!strcasecmp(cp + 2, distlist[i])) {
X (void) fclose(fp);
X return (1);
X }
X }
X (void) fclose(fp);
X return (0);
X }
X }
X
X (void) fclose(fp);
X
X /*
X * We've finished the header with no distribution field.
X * So we'll assume that the distribution is the characters
X * up to the first dot in the newsgroup name.
X */
X
X for (i = 0; i < groupcount; i++) {
X cp = index(grouplist[i], '.');
X if (cp)
X *cp = '\0';
X for (j = 0; j < distcount; j++)
X if (!strcasecmp(grouplist[i], distlist[j]))
X return (1);
X }
X
X return (0);
X}
X
X
X/*
X * get_histlist -- return a nicely set up array of newsgroups
X * (actually, net.foo.bar/article_num) along with a count.
X *
X * Parameters: "array" is storage for our array,
X * set to point at some static data.
X * "list" is the history file newsgroup list.
X *
X * Returns: Number of group specs found.
X *
X * Side effects: Changes static data area.
X */
X
get_histlist(array, list)
X char ***array;
X char *list;
X{
X register int histcount;
X register char *cp;
X static char **hist_list = (char **) NULL;
X
X cp = index(list, '\n');
X if (cp)
X *cp-- = '\0';
X histcount = parsit(list, &hist_list);
X *array = hist_list;
X return (histcount);
X}
X
X
X/*
X * get_nglist -- return a nicely set up array of newsgroups
X * along with a count, when given an NNTP-spec newsgroup list
X * in the form ng1,ng2,ng...
X *
X * Parameters: "array" is storage for our array,
X * set to point at some static data.
X * "list" is the NNTP newsgroup list.
X *
X * Returns: Number of group specs found.
X *
X * Side effects: Changes static data area.
X */
X
get_nglist(array, list)
X char ***array;
X char *list;
X{
X register char *cp;
X register int ngcount;
X
X for (cp = list; *cp != '\0'; ++cp)
X if (*cp == ',')
X *cp = ' ';
X
X ngcount = parsit(list, array);
X
X return (ngcount);
X}
END_OF_FILE
if test 10834 -ne `wc -c <'./server/newnews.c'`; then
echo shar: \"'./server/newnews.c'\" unpacked with wrong size!
fi
# end of './server/newnews.c'
fi
if test -f './xfer/nntpxfer.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'./xfer/nntpxfer.c'\"
else
echo shar: Extracting \"'./xfer/nntpxfer.c'\" \(10068 characters\)
sed "s/^X//" >'./xfer/nntpxfer.c' <<'END_OF_FILE'
X/*
X * nntpxfer
X *
X * Connects to the specified nntp server, and transfers all new news
X * since the last successful invocation.
X *
X * last successful invocation date and time are stored in a file at
X * /usr/spool/news/nntp.<hostname> as
X * groups YYMMDD HHMMSS distributions\n
X * in case you need to edit it. You can also override this on
X * the command line in the same format, in which case the file won't
X * be updated.
X *
X * Brian Kantor, UCSD 1986
X * (some bug fixes by ambar at athena.mit.edu)
X */
X
X#define DEBUG
X
X/* you'd think that 4096 articles at one go is enough.... */
X#define MAXARTS 4096
X
X#include <sys/types.h>
X#include <sys/dir.h>
X#include <sys/socket.h>
X#include <sys/stat.h>
X#include <sys/ioctl.h>
X#include <sys/file.h>
X#include <sys/time.h>
X#include <sys/wait.h>
X#include <sys/resource.h>
X
X#include <net/if.h>
X#include <netinet/in.h>
X
X#include <stdio.h>
X#include <errno.h>
X#include <ctype.h>
X#include <netdb.h>
X#include <signal.h>
X#include <dbm.h>
X
X#define INEWS "/usr/lib/news/inews -p"
X#define HIST "/usr/lib/news/history"
X
char *malloc();
char *strcpy();
char *strcat();
long time();
u_long inet_addr();
X
extern int errno;
char *artlist[MAXARTS];
int server; /* stream socket to the nntp server */
int newart, dupart, misart;
X
main(argc, argv)
int argc;
char *argv[];
X {
X FILE *dtfile; /* where last xfer date/time stored */
X char buf[BUFSIZ];
X char lastdate[16];
X char distributions[BUFSIZ];
X char dtname[128];
X char newsgroups[BUFSIZ];
X char lasttime[16];
X int connected = 0; /* 1 = connected */
X int i;
X int omitupdate = 0; /* 1 = don't update datetime */
X long clock;
X long newdate, newtime;
X struct hostent *hp;
X struct servent *sp;
X struct sockaddr_in sin;
X struct tm *now;
X
X /* OPTIONS
X argv[1] MUST be the host name
X argv[2-4] MAY be "newsgroups YYMMDD HHMMSS"
X argv[5] MAY be distributions
X (otherwise use 2-4/5 from the file
X "/usr/spool/news/nntp.hostname")
X */
X
X if (argc != 2 && argc != 5 && argc != 6)
X {
X (void) printf("Usage: %s host [groups YYMMDD HHMMSS [<dist>]]\n",
X argv[0]);
X exit(1);
X }
X
X if (argc > 2)
X {
X omitupdate++;
X (void) strcpy(newsgroups, argv[2]);
X (void) strcpy(lastdate, argv[3]);
X (void) strcpy(lasttime, argv[4]);
X (void) strcpy(distributions, "");
X if (argc > 5)
X (void) strcpy(distributions, argv[5]);
X }
X else
X {
X (void) strcpy(dtname, "/usr/spool/news/nntp.");
X (void) strcat(dtname, argv[1]);
X dtfile = fopen(dtname, "r");
X if (dtfile == NULL)
X {
X (void) printf("%s not found; using * 860101 000000 \n",
X dtname);
X (void) strcpy(newsgroups, "*");
X (void) strcpy(lastdate, "860101");
X (void) strcpy(lasttime, "000000");
X (void) strcpy(distributions, "");
X }
X else
X {
X if (fscanf(dtfile, "%s %s %s %s",
X newsgroups, lastdate, lasttime, distributions) < 3)
X {
X (void) printf("%s invalid; using * 860101 000000\n",
X dtname);
X (void) strcpy(newsgroups, "*");
X (void) strcpy(lastdate, "860101");
X (void) strcpy(lasttime, "000000");
X (void) strcpy(distributions, "");
X }
X (void) fclose(dtfile);
X }
X clock = time((long *)0);
X now = gmtime(&clock);
X newdate = (now->tm_year * 10000) +
X ((now->tm_mon + 1) * 100) + now->tm_mday;
X newtime = (now->tm_hour * 10000) +
X (now->tm_min * 100) + now->tm_sec;
X }
X
X#ifdef DEBUG
X (void) printf("newsgroups = '%s'\n", newsgroups);
X (void) printf("date = '%s'\n", lastdate);
X (void) printf("time = '%s'\n", lasttime);
X (void) printf("distributions = '%s'\n", distributions);
X (void) printf("now is = %06d %06d\n", newdate, newtime);
X#endif
X
X if (dbminit(HIST) < 0)
X {
X perror("couldn't open history file");
X exit(1);
X }
X
X sin.sin_addr.s_addr = inet_addr(argv[1]);
X if (sin.sin_addr.s_addr != -1)
X {
X sin.sin_family = AF_INET;
X }
X else
X {
X hp = gethostbyname(argv[1]);
X if (hp == NULL)
X {
X (void) printf("%s: unknown host\n", argv[1]);
X exit(1);
X }
X
X sin.sin_family = hp->h_addrtype;
X#ifdef BSD43
X bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr,
X hp->h_length);
X#else BSD43
X bcopy(hp->h_addr, (caddr_t)&sin.sin_addr,
X hp->h_length);
X#endif BSD43
X }
X
X sp = getservbyname("nntp", "tcp");
X if (sp == NULL)
X {
X perror("nntp/tcp");
X exit(1);
X }
X
X sin.sin_port = sp->s_port;
X
X do {
X server = socket(AF_INET, SOCK_STREAM, 0);
X if (server < 0)
X {
X perror("nntpxfer: socket");
X exit(1);
X }
X
X if (connect(server, (struct sockaddr *)&sin, sizeof (sin)) < 0)
X {
X#ifdef BSD43
X if (hp && hp->h_addr_list[1])
X {
X hp->h_addr_list++;
X bcopy(hp->h_addr_list[0],
X (caddr_t)&sin.sin_addr, hp->h_length);
X (void) close(server);
X continue;
X }
X#endif BSD43
X perror("nntpxfer: connect");
X exit(1);
X }
X connected++;
X }
X while (connected == 0);
X
X#ifdef DEBUG
X (void) printf("connected to nntp server at %s\n", argv[1]);
X#endif
X /*
X * ok, at this point we're connected to the nntp daemon
X * at the distant host.
X */
X
X /* get the greeting herald */
X (void) sockread(buf);
X#ifdef DEBUG
X (void) printf("%s\n", buf);
X#endif
X if (buf[0] != '2') /* uh-oh, something's wrong! */
X {
X (void) printf("protocol error: got '%s'\n", buf);
X (void) close(server);
X exit(1);
X }
X
X
X /* first, tell them we're a slave process to get priority */
X sockwrite("SLAVE");
X (void) sockread(buf);
X#ifdef DEBUG
X (void) printf("%s\n", buf);
X#endif
X if (buf[0] != '2') /* uh-oh, something's wrong! */
X {
X (void) printf("protocol error: got '%s'\n", buf);
X (void) close(server);
X exit(1);
X }
X
X /* now, ask for a list of new articles */
X if (strlen(distributions))
X (void) sprintf(buf,"NEWNEWS %s %s %s GMT <%s>",
X newsgroups, lastdate, lasttime, distributions);
X else
X (void) sprintf(buf,"NEWNEWS %s %s %s GMT",
X newsgroups, lastdate, lasttime);
X sockwrite(buf);
X (void) sockread(buf);
X#ifdef DEBUG
X (void) printf("%s\n", buf);
X#endif
X if (buf[0] != '2') /* uh-oh, something's wrong! */
X {
X (void) printf("protocol error: got '%s'\n", buf);
X (void) close(server);
X exit(1);
X }
X /* and here comes the list, terminated with a "." */
X#ifdef DEBUG
X (void) printf("data\n");
X#endif
X while (1)
X {
X (void) sockread(buf);
X if (!strcmp(buf,"."))
X break;
X if (wewant(buf))
X {
X if (newart > MAXARTS)
X {
X omitupdate++;
X continue;
X }
X artlist[newart] = malloc((unsigned)(strlen(buf)+1));
X (void) strcpy(artlist[newart], buf);
X newart++;
X }
X else
X dupart++;
X }
X#ifdef DEBUG
X (void) printf(".\n%d new, %d dup articles\n", newart, dupart);
X#endif
X
X /* now that we know which articles we want, retrieve them */
X for (i=1; i < newart; i++)
X (void) artfetch(artlist[i]);
X
X#ifdef DEBUG
X (void) printf("%d missing articles\n", misart);
X#endif
X /* we're all done, so tell them goodbye */
X sockwrite("QUIT");
X (void) sockread(buf);
X#ifdef DEBUG
X (void) printf("%s\n", buf);
X#endif
X if (buf[0] != '2') /* uh-oh, something's wrong! */
X {
X (void) printf("error: got '%s'\n", buf);
X (void) close(server);
X exit(1);
X }
X (void) close(server);
X
X /* do we want to update the timestamp file? */
X if (!omitupdate)
X {
X (void) sprintf(buf, "%s %06d %06d %s\n",
X newsgroups, newdate, newtime, distributions);
X#ifdef DEBUG
X (void) printf("updating %s:\n\t%s\n", dtname, buf);
X#endif
X dtfile = fopen(dtname, "w");
X if (dtfile == NULL)
X {
X perror(dtname);
X exit(1);
X }
X (void) fputs(buf,dtfile);
X (void) fclose(dtfile);
X }
X exit(0);
X}
X
artfetch(articleid)
char *articleid;
X {
X int lines = 0;
X char buf[BUFSIZ];
X FILE *inews;
X
X /* now, ask for the article */
X (void) sprintf(buf,"ARTICLE %s", articleid);
X sockwrite(buf);
X (void) sockread(buf);
X#ifdef DEBUG
X (void) printf("%s\n", buf);
X#endif
X if (buf[0] == '4') /* missing article, just skipit */
X {
X misart++;
X return(0);
X }
X
X if (buf[0] != '2') /* uh-oh, something's wrong! */
X {
X (void) printf("protocol error: got '%s'\n", buf);
X (void) close(server);
X exit(1);
X }
X#ifdef DEBUG
X (void) printf("command: %s\n", INEWS);
X#endif
X if ( (inews = popen(INEWS, "w")) == NULL)
X {
X perror(INEWS);
X exit(1);
X }
X
X /* and here comes the article, terminated with a "." */
X#ifdef DEBUG
X (void) printf("data\n");
X#endif
X while (1)
X {
X (void) sockread(buf);
X if (buf[0] == '.' && buf[1] == '\0')
X break;
X lines++;
X (void) strcat(buf,"\n");
X (void) fputs(((buf[0] == '.') ? buf + 1 : buf),
X inews);
X }
X#ifdef DEBUG
X (void) printf(".\n%d lines\n", lines);
X#endif
X (void) fflush(inews);
X (void) pclose(inews);
X return(0);
X }
X
int
sockread(buf)
char *buf;
X {
X char c;
X int j = 0;
X#ifdef BSD43
X fd_set rf;
X#else BSD43
X int rf;
X#endif BSD43
X struct timeval tv;
X int r;
X char *p = buf;
X
X while ( 1 )
X {
X tv.tv_sec = 1800; /* 15 minutes */
X tv.tv_usec = 0L;
X#ifdef BSD43
X FD_ZERO(&rf);
X FD_SET(server, &rf);
X#else BSD43
X rf = 1 << server;
X#endif BSD43
X r = select(20, (fd_set *)&rf, (fd_set *)0, (fd_set *)&rf, &tv);
X
X if (r < 0)
X {
X if (errno == EINTR)
X continue;
X perror("getsock select");
X exit(1);
X }
X if (r == 0)
X {
X printf("read timed out.\n");
X exit(1);
X }
X
X if (read(server, &c, 1) <= 0)
X break;
X
X /* mask off any chance parity bits */
X *p = c & 0x7f;
X
X /* look for end of line (== LF) */
X if (c == 0x0a)
X {
X if (j > 0 && *(p-1) == 0x0d)
X *(p-1) = '\0';
X else
X *p = '\0';
X return(strlen(buf));
X }
X j++; p++;
X }
X perror("sockread");
X (void) close(server);
X exit(1);
X /* NOTREACHED */
X }
X
sockwrite(buf)
char *buf;
X {
X register int sz;
X char buf2[BUFSIZ];
X#ifdef DEBUG
X (void) printf(">>> %s\n", buf);
X#endif
X (void) strcpy(buf2,buf);
X (void) strcat(buf2,"\r\n");
X sz = strlen(buf2);
X if (write(server,buf2,sz) != sz)
X {
X (void) printf("write error on server socket\n");
X (void) close(server);
X exit(1);
X }
X }
X
int
wewant(articleid)
char *articleid;
X {
X datum k, d;
X char id[BUFSIZ];
X char *p;
X
X /* remove any case sensitivity */
X (void) strcpy(id, articleid);
X p = id;
X while (*p)
X {
X if (isupper(*p))
X *p = tolower(*p);
X p++;
X }
X
X k.dptr = id;
X k.dsize = strlen(articleid) + 1;
X
X d = fetch(k);
X
X if (d.dptr)
X {
X#ifdef DEBUG
X (void) printf("dup: '%s'\n", articleid);
X#endif
X return(0);
X }
X
X#ifdef DEBUG
X (void) printf("new: '%s'\n", articleid);
X#endif
X return(1);
X }
END_OF_FILE
if test 10068 -ne `wc -c <'./xfer/nntpxfer.c'`; then
echo shar: \"'./xfer/nntpxfer.c'\" unpacked with wrong size!
fi
# end of './xfer/nntpxfer.c'
fi
if test -f './xmit/remote.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'./xmit/remote.c'\"
else
echo shar: Extracting \"'./xmit/remote.c'\" \(9250 characters\)
sed "s/^X//" >'./xmit/remote.c' <<'END_OF_FILE'
X/*
X** remote communication routines for NNTP/SMTP style communication.
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** rfgets - remote fgets() (calls sfgets());
X** does SMTP dot escaping and
X** \r\n -> \n conversion.
X**
X** sendfile - send a file with SMTP dot escaping and
X** \n -> \r\n conversion.
X**
X** Erik E. Fair <fair at ucbarpa.berkeley.edu>
X*/
X
X#include "nntpxmit.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 SYSLOG
X#include <syslog.h>
X#endif
X#include "get_tcp_conn.h"
X#include "nntp.h"
X
static jmp_buf SFGstack;
FILE *rmt_rd;
FILE *rmt_wr;
char *sfgets();
char *rfgets();
X
extern int errno;
extern char Debug;
extern char *errmsg();
extern char *strcpy();
extern void log();
X
X/*
X** send cmd to remote, terminated with a CRLF.
X*/
sendcmd(cmd)
char *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*/
readreply(buf, size)
register char *buf;
int 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*/
converse(buf, size)
char *buf;
int 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*/
hello(host, transport)
char *host;
int 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*/
goodbye(wait_for_reply)
int 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
static
to_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*/
char *
sfgets(buf, size, fp)
char *buf;
int size;
FILE *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** Remote fgets - converts CRLF to \n, and returns NULL on `.' EOF from
X** the remote. Otherwise it returns its first argument, like fgets(3).
X*/
char *
rfgets(buf, size, fp)
char *buf;
int size;
FILE *fp;
X{
X register char *cp = buf;
X register int len;
X
X if (buf == (char *)NULL || size <= 0 || fp == (FILE *)NULL)
X return((char *)NULL);
X *cp = '\0';
X if (sfgets(buf, size, fp) == (char *)NULL)
X return((char *)NULL);
X
X /* <CRLF> => '\n' */
X if ((len = strlen(buf)) > 2 && *(cp = &buf[len - 2]) == '\r') {
X *cp++ = '\n';
X *cp = '\0';
X }
X
X /* ".\n" => EOF */
X cp = buf;
X if (*cp++ == '.' && *cp == '\n') {
X return((char *)NULL); /* EOF */
X }
X
X /* Dot escaping */
X if (buf[0] == '.')
X (void) strcpy(&buf[0], &buf[1]);
X return(buf);
X}
X
X/*
X** send the contents of an open file descriptor to the remote,
X** with appropriate RFC822 filtering (e.g. CRLF line termination,
X** and dot escaping). Return FALSE if something went wrong.
X*/
sendfile(fp)
FILE *fp;
X{
X register int c;
X register FILE *remote = rmt_wr;
X register int nl = TRUE; /* assume we start on a new line */
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#define PUTC(c) if (putc(c, remote) == EOF) return(FALSE)
X
X if (fp == (FILE *)NULL)
X return(FALSE);
X
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 switch(c) {
X case '\n':
X PUTC('\r'); /* \n -> \r\n */
X PUTC(c);
X nl = TRUE; /* for dot escaping */
X break;
X case '.':
X if (nl) {
X PUTC(c); /* add a dot */
X nl = FALSE;
X }
X PUTC(c);
X break;
X default:
X PUTC(c);
X nl = FALSE;
X break;
X }
X }
X if (!nl) {
X PUTC('\r');
X PUTC('\n');
X }
X return( !(sendcmd(".") || ferror(fp)) );
X}
END_OF_FILE
if test 9250 -ne `wc -c <'./xmit/remote.c'`; then
echo shar: \"'./xmit/remote.c'\" unpacked with wrong size!
fi
# end of './xmit/remote.c'
fi
echo shar: End of archive 6 \(of 9\).
cp /dev/null ark6isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 9 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
More information about the Comp.sources.unix
mailing list