[alt.sources] nntp

nelson@sun.soe.clarkson.edu (Russ Nelson) (07/14/89)

/*
 * nntp
 *
 * Connects to the specified nntp server.  Sends standard input to it,
 * and sends output to standard output as needed.
 * 
 * Written by Russell Nelson, 7-13-89.  No copyright claimed.
 * Based on nntpxfer by:
 *	Brian Kantor, UCSD 1986
 * (some bug fixes by ambar@athena.mit.edu)
 *
 * put it in nntp.1.5/nntp/nntp.c and compile.
 *
 * usage: nntp host command arguments
 *
 * example: nntp host sun.soe.clarkson.edu newnews alt.sources 890713 000000
 *
 */

#define DEBUG

#include <sys/types.h>
#include <sys/dir.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/resource.h>

#include <net/if.h>
#include <netinet/in.h>

#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <netdb.h>
#include <signal.h>

#include "../common/nntp.h"

char	*malloc();
char	*strcpy();
char	*strcat();
u_long	inet_addr();

extern int errno;
int server;			/* stream socket to the nntp server */
int debug=0;			/* true if we're debugging. */

main(argc, argv)
int argc;
char *argv[];
	{
	char buf[BUFSIZ];
	int connected = 0;		/* 1 = connected */
	int i;
	int omitupdate = 0;		/* 1 = don't update datetime */
	struct hostent *hp;
	struct servent *sp;
	struct sockaddr_in sin;
	char *hostname;

# define SKIPARG	while (*++(*argv)); --(*argv)
# define CLRARG		strncpy (*argv, BLANKS, strlen (*argv)); \
			while (*++(*argv)); --(*argv)
#define USAGE "usage: nntp [-d] [-d] [-hhostname] nntp-command"

	hostname = NULL;
	while (--argc > 0 && (*++argv)[0] == '-'){
		while (*++(*argv)){
			switch (**argv){
#if 0
			    case 'h':
				hostname = argv+1;
				SKIPARG;
				break;
#endif
			    case 'd':
				debug++;
				break;
			    default:
				fprintf (stderr, "%s\n", USAGE);
				exit (1);
			}
		}
	}

	if (!hostname)
		hostname = *argv++;

	sin.sin_addr.s_addr = inet_addr(hostname);
	if (sin.sin_addr.s_addr != -1) 
		{
		sin.sin_family = AF_INET;
		}
	else 
		{
		hp = gethostbyname(hostname);
		if (hp == NULL) 
			{
			(void) printf("%s: unknown host\n", hostname);
			exit(1);
			}

		sin.sin_family = hp->h_addrtype;
#ifdef	BSD43
		bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr,
			hp->h_length);
#else	BSD43
		bcopy(hp->h_addr, (caddr_t)&sin.sin_addr,
			hp->h_length);
#endif	BSD43
		}

	sp = getservbyname("nntp", "tcp");
	if (sp == NULL)
		{
		perror("nntp/tcp");
		exit(1);
		}

	sin.sin_port = sp->s_port;

	do	{
		server = socket(AF_INET, SOCK_STREAM, 0);
		if (server < 0) 
			{
			perror("nntpxfer: socket");
			exit(1);
			}

		if (connect(server, (struct sockaddr *)&sin, sizeof (sin)) < 0) 
			{
#ifdef	BSD43
			if (hp && hp->h_addr_list[1]) 
				{
				hp->h_addr_list++;
				bcopy(hp->h_addr_list[0],
				    (caddr_t)&sin.sin_addr, hp->h_length);
				(void) close(server);
				continue;
				}
#endif	BSD43
			perror("nntpxfer: connect");
			exit(1);
			}
		connected++;
		}
	while (connected == 0);

#ifdef DEBUG
	if(debug)
		(void) printf("connected to nntp server at %s\n", hostname);
#endif

	/*
	* ok, at this point we're connected to the nntp daemon 
	* at the distant host.
	*/

	/* get the greeting herald */
	(void) sockread(buf);
#ifdef DEBUG
	if(debug)
		(void) printf("%s\n", buf);
#endif
	if (buf[0] != '2')	/* uh-oh, something's wrong! */
		{
		(void) printf("protocol error: got '%s'\n", buf);
		(void) close(server);
		exit(1);
		}


	/* first, tell them we're a slave process to get priority */
	sockwrite("SLAVE");
	(void) sockread(buf);
#ifdef DEBUG
	if(debug)
		(void) printf("%s\n", buf);
#endif
	if (buf[0] != '2')	/* uh-oh, something's wrong! */
		{
		(void) printf("protocol error: got '%s'\n", buf);
		(void) close(server);
		exit(1);
		}

	/* now, build their command and send it */
	strcpy(buf, "");
	while (*argv) {
		strcat(buf, *argv++);
		if (*argv)
			strcat(buf, " ");
	}
	sockwrite(buf);
	(void) sockread(buf);
#ifdef DEBUG
	if(debug)
		(void) printf("%s\n", buf);
#endif
	/* now we see if we need to read from stdin or write to stdout */
	switch(atoi(buf)){

	    case INF_HELP:
	    case OK_GROUPS:
	    case OK_ARTICLE:
	    case OK_HEAD:
	    case OK_BODY:
	    case OK_NEWNEWS:
	    case OK_NEWGROUPS:

#ifdef DEBUG
		if(debug)
			(void) printf("receive data\n");
#endif
		for(;;){
			(void) sockread(buf);
			if (buf[0] == '.' && buf[1] == '\0')
				break;
			(void) strcat(buf,"\n");
			(void) fputs(((buf[0] == '.') ? buf + 1 : buf),
				   stdout);
		}
		break;
	    case CONT_XFER:
	    case CONT_POST:

#ifdef DEBUG
		if(debug)
			(void) printf("send data\n");
#endif
		buf[0] = '.';
		while (gets(buf+1)){
			(void) sockwrite(((buf[1] == '.') ? buf : buf + 1));
		}
		sockwrite(".");
		break;
	}

	/* we're all done, so tell them goodbye */
	sockwrite("QUIT");
	(void) sockread(buf);
#ifdef DEBUG
	if(debug)
		(void) printf("%s\n", buf);
#endif
	if (buf[0] != '2'){	/* uh-oh, something's wrong! */
		(void) printf("error: got '%s'\n", buf);
		(void) close(server);
		exit(1);
	}
	(void) close(server);

	exit(0);
}


int
sockread(buf)
char *buf;
{
	char c;
	int j = 0;
#ifdef BSD43
	fd_set rf;
#else BSD43
	int rf;
#endif BSD43
	struct timeval tv;
	int r;
	char *p = buf;

	for (;;){
		tv.tv_sec = 1800;	/* 15 minutes */
		tv.tv_usec = 0L;
#ifdef BSD43
		FD_ZERO(&rf);
		FD_SET(server, &rf);
#else BSD43
		rf = 1 << server;
#endif BSD43
		r = select(20, (fd_set *)&rf, (fd_set *)0, (fd_set *)&rf, &tv);

		if (r < 0){
			if (errno == EINTR)
				continue;
			perror("getsock select");
			exit(1);
		}
		if (r == 0){
			printf("read timed out.\n");
			exit(1);
		}

		if (read(server, &c, 1) <= 0)
			break;

		/* mask off any chance parity bits */
		*p = c & 0x7f;

		/* look for end of line (== LF) */
		if (c == 0x0a){
			if (j > 0 && *(p-1) == 0x0d)
				*(p-1) = '\0';
			else
				*p = '\0';
#ifdef DEBUG
			if(debug > 1)
				(void) printf("<<< %s\n", buf);
#endif
			return(strlen(buf));
		}
		j++; p++;
	}
	perror("sockread");
	(void) close(server);
	exit(1);
	/* NOTREACHED */
}

sockwrite(buf)
char *buf;
{
	register int sz;
	char buf2[BUFSIZ];
#ifdef DEBUG
	if(debug > 1)
		(void) printf(">>> %s\n", buf);
#endif
	(void) strcpy(buf2,buf);
	(void) strcat(buf2,"\r\n");
	sz = strlen(buf2);
	if (write(server,buf2,sz) != sz){
		(void) printf("write error on server socket\n");
		(void) close(server);
		exit(1);
	}
}
-- 
--russ (nelson@clutx [.bitnet | .clarkson.edu])
I'm not the NRA, and I vote twice.