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.