This is clientlib.c in view mode; [Download] [Up]
/* -*- mode: C; mode: fold */ /* * This software is Copyright 1991 by Stan Barber. * * Permission is hereby granted to copy, reproduce, redistribute or otherwise * use this software as long as: there is no monetary profit gained * specifically from the use or reproduction or this software, it is not * sold, rented, traded or otherwise marketed, and this copyright notice is * included prominently in any copy made. * * The author make no claims as to the fitness or correctness of this software * for any use whatsoever, and it is provided as is. Any use of this software * is at the user's own risk. * */ /* Modified 'server_init' by John E. Davis for use by slrn. */ /* * NNTP client routines. */ /* * Include configuration parameters only if we're made in the nntp tree. */ #if 0 # define DEBUG_FILE "slrn.log" #endif #include "config.h" #include "features.h" #include <stdio.h> #include <string.h> #ifdef HAVE_UNISTD_H # include <unistd.h> #endif #ifdef HAVE_STDLIB_H # include <stdlib.h> #endif #include <sys/types.h> #ifdef VMS /*{{{ VMS includes */ # include <signal.h> # ifdef MULTINET # include "multinet_root:[multinet.include.vms]inetiodef.h" # include "multinet_root:[multinet.include.sys]types.h" # else # if NETLIB # include <descrip.h> # include <types.h> # include <iodef.h> # include <stsdef.h> # include "netlib_dir:netlibdef.h" # define NNTP_PORT 119 # define INIT_SDESC(dsc, len, ptr) {(dsc).dsc$b_dtype = DSC$K_DTYPE_T;\ (dsc).dsc$b_class = DSC$K_CLASS_S; (dsc).dsc$w_length = (len);\ (dsc).dsc$a_pointer = (ptr);} # else # include <types.h> # include <iodef.h> # define NNTP_PORT 119 # endif # endif /*}}}*/ #endif #include <ctype.h> #ifdef TLI /*{{{ TLI includes */ # include <fcntl.h> # include <tiuser.h> # include <stropts.h> # include <sys/socket.h> # define SLRN_LOADED_SYS_SOCKET_H # ifdef WIN_TCP # include <sys/in.h> # else # include <netinet/in.h> # define SLRN_LOADED_NETINET_IN_H # endif # define IPPORT_NNTP ((unsigned short) 119) # include <netdb.h> /* All TLI implementations may not have this */ /*}}}*/ #else /* !TLI */ # ifdef VMS /*{{{ More VMS includes */ # ifdef MULTINET # include "multinet_root:[multinet.include]netdb.h" # include "multinet_root:[multinet.include.sys]socket.h" # include "multinet_root:[multinet.include.netinet]in.h" # define SLRN_LOADED_NETINET_IN_H # define SLRN_LOADED_SYS_SOCKET_H # endif # ifdef NETLIB # include <descrip.h> # include "netlib_dir:netlibdef.h" # endif # ifdef UCX # include <netdb.h> # include <socket.h> # include <in.h> # endif /*}}}*/ # else /* !VMS */ # include <sys/socket.h> # include <netinet/in.h> # define SLRN_LOADED_NETINET_IN_H # define SLRN_LOADED_SYS_SOCKET_H # ifndef EXCELAN # include <netdb.h> # endif /* !EXCELAN */ # endif /* !VMS */ #endif /* !TLI */ #ifdef HAVE_SYS_SOCKET_H # ifndef SLRN_LOADED_SYS_SOCKET_H # include <sys/socket.h> # define SLRN_LOADED_SYS_SOCKET_H # endif #endif #ifdef HAVE_NETINET_IN_H # ifndef SLRN_LOADED_NETINET_IN_H # include <netinet/in.h> # define SLRN_LOADED_NETINET_IN_H # endif #endif #ifdef HAVE_ARPA_INET_H # ifndef SLRN_LOADED_ARPA_INET_H # include <arpa/inet.h> # define SLRN_LOADED_ARPA_INET_H # endif #endif #ifdef VMS /*{{{ VMS #defines */ # ifdef MULTINET # define netread socket_read # define sock_write socket_write # define netclose socket_close # else # if NETLIB # define netread netlib_read # define sock_write netlib_write # define netclose netlib_close # else # define netread read # define sock_write write # define netclose close # endif # endif /*}}}*/ # endif /* VMS */ #ifndef NETLIB # define SERVER_READ_FP ser_rd_fp # define SERVER_WRITE_FP ser_wr_fp #else # define SERVER_READ_FP ipctx # define SERVER_WRITE_FP ipctx #endif #ifdef EXCELAN /*{{{ EXCELAN defines */ # define NNTP_PORT ((unsigned short) 119) # if __STDC__ int connect(int, struct sockaddr *); unsigned short htons(unsigned short); unsigned long rhost(char **); int rresvport( int ); int socket( int, struct sockproto *, struct sockaddr_in *, int ); # endif /*}}}*/ #endif #ifdef DECNET # include <netdnet/dn.h> # include <netdnet/dnetdb.h> #endif /* DECNET */ #include "server.h" #include "misc.h" #ifndef NNTP_PORT # define NNTP_PORT 119 #endif #ifdef NEEDS_EXTERN_DECLARATIONS # define DECLARE_EXTERN(x) extern x; #else # define DECLARE_EXTERN(x) #endif #ifdef VMS # ifdef NETLIB static void *ipctx; # else static int ser_rd_fp = -1, ser_wr_fp = -1; # endif #else static FILE *ser_rd_fp = NULL; static FILE *ser_wr_fp = NULL; #endif #ifdef DEBUG_FILE static FILE *Debug_Fp; #endif static int Server_Has_Been_Closed = 1; static void client_close_server(void); static int client_get_server(char *, int); static int get_tcp_socket(char *, int); /*{{{ client_server_init */ /* * client_server_init Get a connection to the remote news server. * * Parameters: "machine" is the machine to connect to. * * Returns: -1 on error * server's initial response code on success. * * Side effects: Connects to server. * "ser_rd_fp" and "ser_wr_fp" are fp's * for reading and writing to server. */ static int client_server_init(char *machine, int port, char *line, int len) { int sockt_rd, sockt_wr; #ifdef DECNET char *cp; if (Server_Has_Been_Closed == 0) client_close_server (); cp = slrn_strchr(machine, ':'); if (cp && cp[1] == ':') { *cp = '\0'; sockt_rd = get_dnet_socket(machine); } else sockt_rd = get_tcp_socket(machine, port); #else if (Server_Has_Been_Closed == 0) client_close_server (); sockt_rd = get_tcp_socket (machine, port); #endif if (sockt_rd < 0) return (-1); #ifdef VMS # ifndef NETLIB ser_rd_fp = ser_wr_fp = sockt_rd; # endif #else /* * Now we'll make file pointers (i.e., buffered I/O) out of * the socket file descriptor. Note that we can't just * open a fp for reading and writing -- we have to open * up two separate fp's, one for reading, one for writing. */ if ((ser_rd_fp = fdopen(sockt_rd, "r")) == NULL) { perror("client_server_init: fdopen #1"); return (-1); } sockt_wr = dup(sockt_rd); # ifdef TLI if (t_sync(sockt_rd) < 0) { /* Sync up new fd with TLI */ t_error("client_server_init: t_sync"); ser_rd_fp = NULL; /* from above */ return (-1); } # endif if ((ser_wr_fp = fdopen(sockt_wr, "w")) == NULL) { perror("client_server_init: fdopen #2"); ser_rd_fp = NULL; /* from above */ return (-1); } #endif /* VMS */ /* Now get the server's signon message */ #ifdef DEBUG_FILE Debug_Fp = fopen (DEBUG_FILE, "w"); #endif Server_Has_Been_Closed = 0; (void) client_get_server(line, len); return (atoi(line)); } /*}}}*/ /*{{{ get_tcp_socket */ /* * get_tcp_socket -- get us a socket connected to the news server. * * Parameters: "machine" is the machine the server is running on. * * Returns: Socket connected to the news server if * all is ok, else -1 on error. * * Side effects: Connects to server. * * Errors: Printed via perror. */ static int get_tcp_socket(char *machine, int nntpport) { #ifndef NETLIB int s = -1; struct sockaddr_in s_in; #endif #ifdef TLI char *t_alloc(); struct t_call *callptr; /* * Create a TCP transport endpoint. */ if ((s = t_open("/dev/tcp", O_RDWR, (struct t_info*) 0)) < 0) { t_error("t_open: can't t_open /dev/tcp"); return(-1); } if(t_bind(s, (struct t_bind *)0, (struct t_bind *)0) < 0) { t_error("t_bind"); t_close(s); return(-1); } memset ((char *) &s_in, 0, sizeof(s_in)); s_in.sin_family = AF_INET; if (nntpport < 0) nntpport = NNTP_PORT; s_in.sin_port = htons((unsigned short) nntpport); if (!isdigit(*machine) || (long)(s_in.sin_addr.s_addr = inet_addr(machine)) == -1) { struct hostent *gethostbyname(), *hp; if((hp = gethostbyname(machine)) == NULL) { fprintf(stderr,"gethostbyname: %s: host unknown\n", machine); t_close(s); return(-1); } memcpy ((char *) &s_in.sin_addr, hp->h_addr, hp->h_length); } /* * Allocate a t_call structure and initialize it. * Let t_alloc() initialize the addr structure of the t_call structure. */ if ((callptr = (struct t_call *) t_alloc(s,T_CALL,T_ADDR)) == NULL) { t_error("t_alloc"); t_close(s); return(-1); } callptr->addr.maxlen = sizeof(s_in); callptr->addr.len = sizeof(s_in); callptr->addr.buf = (char *) &s_in; callptr->opt.len = 0; /* no options */ callptr->udata.len = 0; /* no user data with connect */ /* * Connect to the server. */ if (t_connect(s, callptr, (struct t_call *) 0) < 0) { t_error("t_connect"); t_close(s); return(-1); } /* * Now replace the timod module with the tirdwr module so that * standard read() and write() system calls can be used on the * descriptor. */ if (ioctl(s, I_POP, (char *) 0) < 0) { perror("I_POP(timod)"); t_close(s); return(-1); } if (ioctl(s, I_PUSH, "tirdwr") < 0) { perror("I_PUSH(tirdwr)"); t_close(s); return(-1); } #else /* !TLI */ # ifdef NETLIB unsigned short port, nntp_port; struct dsc$descriptor ndsc, dsc; struct INADDRDEF addr; struct SINDEF s_in; unsigned int rc, size; if (nntpport < 0) nntpport = NNTP_PORT; nntp_port = (unsigned short) nntpport; port = netlib_hton_word(&nntp_port); rc = netlib_socket(&ipctx); if (!$VMS_STATUS_SUCCESS(rc)) return(-1); if (isdigit(*machine)) { INIT_SDESC(dsc, strlen(machine), machine); rc = netlib_strtoaddr(&dsc, &addr); if (!$VMS_STATUS_SUCCESS(rc)) return(-1); s_in.sin_w_family = NETLIB_K_AF_INET; s_in.sin_w_port = netlib_hton_word(&nntp_port); s_in.sin_x_addr.inaddr_l_addr = addr.inaddr_l_addr; memset(&s_in.sin_x_mbz, 0, 8); size = sizeof(struct SINDEF); rc = netlib_connect(&ipctx, &s_in, &size, 0,0,0); if (!$VMS_STATUS_SUCCESS(rc)) { netlib_close(&ipctx); return(-1); } } else { INIT_SDESC(ndsc, strlen(machine), machine); rc = netlib_connect_by_name(&ipctx, &ndsc, &nntp_port); if (!$VMS_STATUS_SUCCESS(rc)) { netlib_close(&ipctx); return(-1); } } return(0); # else # ifndef EXCELAN struct servent *sp; struct hostent *hp; # ifdef VMS # else DECLARE_EXTERN(struct servent *getservbyname()) DECLARE_EXTERN(struct hostent *gethostbyname()) # endif # ifdef h_addr int x = 0; register char **cp; static char *alist[1]; # endif /* h_addr */ static struct hostent def; static struct in_addr defaddr; static char namebuf[ 256 ]; DECLARE_EXTERN(unsigned long inet_addr()) # ifndef UCX struct servent sp_buffer; if (nntpport >= 0) { sp = &sp_buffer; memset ((char *) sp, 0, sizeof (struct servent)); sp->s_port = htons((unsigned short)nntpport); } else { if ((sp = getservbyname("nntp", "tcp")) == NULL) { fprintf(stderr, "nntp/tcp: Unknown service.\n"); return (-1); } } # else if (nntpport < 0) nntpport = NNTP_PORT; sp = (struct servent *)malloc(sizeof(struct servent)); sp->s_port = htons((unsigned short)nntpport); # endif /* If not a raw ip address, try nameserver */ if (!isdigit(*machine) || (long)(defaddr.s_addr = inet_addr(machine)) == -1) hp = gethostbyname(machine); else { /* Raw ip address, fake */ (void) strcpy(namebuf, machine); def.h_name = namebuf; # ifdef h_addr def.h_addr_list = alist; # endif def.h_addr = (char *)&defaddr; def.h_length = sizeof(struct in_addr); def.h_addrtype = AF_INET; def.h_aliases = 0; hp = &def; } if (hp == NULL) { fprintf(stderr, "%s: Unknown host.\n", machine); return (-1); } memset ((char *) &s_in, 0, sizeof(s_in)); s_in.sin_family = hp->h_addrtype; s_in.sin_port = sp->s_port; # else /* EXCELAN */ memset ((char *) &s_in, 0, sizeof(s_in)); s_in.sin_family = AF_INET; # endif /* EXCELAN */ /* * The following is kinda gross. The name server under 4.3 * returns a list of addresses, each of which should be tried * in turn if the previous one fails. However, 4.2 hostent * structure doesn't have this list of addresses. * Under 4.3, h_addr is a #define to h_addr_list[0]. * We use this to figure out whether to include the NS specific * code... */ # ifdef h_addr /* get a socket and initiate connection -- use multiple addresses */ for (cp = hp->h_addr_list; cp && *cp; cp++) { s = socket(hp->h_addrtype, SOCK_STREAM, 0); if (s < 0) { perror("socket"); return (-1); } memcpy ((char *)&s_in.sin_addr, *cp, hp->h_length); if (x < 0) fprintf(stderr, "trying %s\n", (char *) inet_ntoa(s_in.sin_addr)); x = connect(s, (struct sockaddr *)&s_in, sizeof (s_in)); if (x == 0) break; fprintf(stderr, "connection to %s: ", (char *) inet_ntoa(s_in.sin_addr)); perror(""); (void) close(s); } if (x < 0) { fprintf(stderr, "giving up...\n"); return (-1); } # else /* no name server */ # ifdef EXCELAN if ((s = socket(SOCK_STREAM,(struct sockproto *)NULL,&s_in,SO_KEEPALIVE)) < 0) { /* Get the socket */ perror("socket"); return (-1); } memset ((char *) &s_in, 0, sizeof(s_in)); s_in.sin_family = AF_INET; if (nntpport < 0) nntpport = NNTP_PORT; s_in.sin_port = htons((unsigned short) nntpport); /* set up addr for the connect */ if ((s_in.sin_addr.s_addr = rhost(&machine)) == -1) { fprintf(stderr, "%s: Unknown host.\n", machine); return (-1); } /* And then connect */ if (connect(s, (struct sockaddr *)&s_in) < 0) { perror("connect"); (void) close(s); return (-1); } # else /* not EXCELAN */ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); return (-1); } /* And then connect */ memcpy ((char *) &s_in.sin_addr, hp->h_addr, hp->h_length); if (connect(s, (struct sockaddr *) &s_in, sizeof(s_in)) < 0) { perror("connect"); (void) close(s); return (-1); } # endif /* !EXCELAN */ # endif /* !h_addr */ # endif /* !NETLIB */ #endif /* !TLI */ #ifndef NETLIB return (s); #endif } /*}}}*/ #ifdef DECNET /*{{{ get_dnet_socket */ /* * get_dnet_socket -- get us a socket connected to the news server. * * Parameters: "machine" is the machine the server is running on. * * Returns: Socket connected to the news server if * all is ok, else -1 on error. * * Side effects: Connects to server. * * Errors: Printed via nerror. */ get_dnet_socket(machine) char *machine; { int s, area, node; struct sockaddr_dn sdn; struct nodeent *getnodebyname(), *np; memset ((char *) &sdn, 0, sizeof(sdn)); switch (s = sscanf( machine, "%d%*[.]%d", &area, &node )) { case 1: node = area; area = 0; case 2: node += area*1024; sdn.sdn_add.a_len = 2; sdn.sdn_family = AF_DECnet; sdn.sdn_add.a_addr[0] = node % 256; sdn.sdn_add.a_addr[1] = node / 256; break; default: if ((np = getnodebyname(machine)) == NULL) { fprintf(stderr, "%s: Unknown host.\n", machine); return (-1); } else { memcpy((char *) sdn.sdn_add.a_addr, np->n_addr, np->n_length); sdn.sdn_add.a_len = np->n_length; sdn.sdn_family = np->n_addrtype; } break; } sdn.sdn_objnum = 0; sdn.sdn_flags = 0; sdn.sdn_objnamel = strlen("NNTP"); memcpy (&sdn.sdn_objname[0], "NNTP", sdn.sdn_objnamel); if ((s = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) { nerror("socket"); return (-1); } /* And then connect */ if (connect(s, (struct sockaddr *) &sdn, sizeof(sdn)) < 0) { nerror("connect"); close(s); return (-1); } return (s); } /*}}}*/ #endif /*{{{ client_put_server */ /* * client_put_server -- send a line of text to the server, terminating it * with CR and LF, as per ARPA standard. * * Parameters: "string" is the string to be sent to the * server. * * Returns: Nothing. * * Side effects: Talks to the server. * * Note: This routine flushes the buffer each time * it is called. For large transmissions * (i.e., posting news) don't use it. Instead, * do the fprintf's yourself, and then a final * fflush. */ static int client_put_server(char *string) { #ifdef VMS char *cp; # ifdef NETLIB int rc; struct dsc$descriptor dsc; unsigned short retlen; # endif #endif if (Server_Has_Been_Closed) return -1; #ifdef DEBUG_FILE if (Debug_Fp != NULL) fprintf(Debug_Fp, ">>> %s\n", string); #endif #ifdef VMS # ifndef NETLIB cp = (char *)malloc(strlen(string)+4); sprintf(cp, "%s\r\n", string); netwrite(SERVER_WRITE_FP, cp, strlen(cp)); /* sock_write(ser_wr_fp, cp, strlen(cp)); */ free(cp); # else INIT_SDESC(dsc, strlen(string), string); rc = netlib_writeline(&ipctx, &dsc); if (!(rc & 1)) return(-1); # endif /* !NETLIB */ #else if ((EOF == fputs (string, ser_wr_fp)) || (EOF == fputs ("\r\n", ser_wr_fp)) || (EOF == fflush(ser_wr_fp))) return -1; #endif return 0; } /*}}}*/ /*{{{ client_get_server */ /* * client_get_server -- get a line of text from the server. Strips * CR's and LF's. * * Parameters: "string" has the buffer space for the * line received. * "size" is the size of the buffer. * * Returns: -1 on error, 0 otherwise. * * Side effects: Talks to server, changes contents of "string". */ #if defined(VMS) && !defined(NETLIB) /*{{{ client_get_server (vms version) */ static void cancel_read (int sig_unused) { slrn_exit_error("\nCANCEL_READ: NNTP read failed."); } # define TIMEOUT 60 # define BUFSIZE 8192 static char buffer[BUFSIZE]; static int bufread = 0; static int client_get_server(char *string, int size) { register char *cp; int status, nb, len, count; struct { unsigned short status; unsigned short count; unsigned int undef; } r_iosb; if (Server_Has_Been_Closed) return -1; if (!bufread) { signal(SIGALRM,cancel_read); alarm(TIMEOUT); nb = netread(SERVER_READ_FP, buffer, BUFSIZE); alarm(0); if (nb <= 0) return(-1); bufread = nb; buffer[bufread] = '\0'; # ifdef DEBUG_FILE if (Debug_Fp != NULL) fprintf(Debug_Fp, "<<<<< %s\n", buffer); # endif } *string = '\0'; count=0; while (((cp = strstr(buffer, "\r\n")) == NULL) && (count < 5)) { count++; strncpy(string, buffer, strlen(buffer)); string[strlen(buffer)] = '\0'; bufread=0; memset(buffer, 0, BUFSIZE); signal(SIGALRM,cancel_read); alarm(TIMEOUT); nb = netread(SERVER_READ_FP, buffer, BUFSIZE); alarm(0); if (nb <= 0) { # ifdef DEBUG_FILE if (Debug_Fp != NULL) fprintf(Debug_Fp, "**** %s\n", string); # endif return(0); } bufread = nb; buffer[bufread] = '\0'; } /* while */ *cp = '\0'; cp += 2; bufread = strlen(cp); strcat(string, buffer); if (bufread > 0) { memmove(buffer, cp, bufread); buffer[bufread] = '\0'; } else memset(buffer, 0, BUFSIZE); # ifdef DEBUG_FILE if (Debug_Fp != NULL) fprintf(Debug_Fp, "<<< %s\n", string); # endif return (0); } /*}}}*/ #else /* !VMS || NETLIB */ # ifdef NETLIB /*{{{ client_get_server (NETLIB) */ # define TIMEOUT 60 static int client_get_server(char *string, int size) { register char *cp; int rc; struct dsc$descriptor dsc; unsigned short retlen; INIT_SDESC(dsc, size, string); if (Server_Has_Been_Closed) return -1; rc = netlib_readline(&ipctx, &dsc, &retlen, 0, 0); if (!(rc & 1)) return (-1); string[retlen] = '\0'; # ifdef DEBUG_FILE if (Debug_Fp != NULL) fprintf(Debug_Fp, "<<< %s\n", string); # endif return (0); } /*}}}*/ # else /* !VMS && !NETLIB */ /*{{{ client_get_server (Unix, OS/2) */ static int client_get_server(char *string, int size) { register char *cp; if (Server_Has_Been_Closed) return -1; if (fgets(string, size, ser_rd_fp) == NULL) return (-1); if ((cp = slrn_strchr(string, '\r')) != NULL) *cp = '\0'; else if ((cp = slrn_strchr(string, '\n')) != NULL) *cp = '\0'; # ifdef DEBUG_FILE if (Debug_Fp != NULL) fprintf(Debug_Fp, "<<< %s\n", string); # endif return (0); } /*}}}*/ # endif /* !NETLIB */ #endif /* !VMS || NETLIB */ /*}}}*/ /*{{{ client_close_server */ /* * client_close_server -- close the connection to the server, after sending * the "quit" command. * * Parameters: None. * * Returns: Nothing. * * Side effects: Closes the connection with the server. * You can't use "client_put_server" or "client_get_server" * after this routine is called. */ static void client_close_server(void) { char ser_line[256]; if (Server_Has_Been_Closed) return; #ifdef VMS # ifndef NETLIB if (ser_wr_fp <= 0 || ser_rd_fp <= 0) return; # else if (ipctx == NULL) return; # endif #else if (ser_wr_fp == NULL || ser_rd_fp == NULL) return; #endif if (-1 != client_put_server("QUIT")) (void) client_get_server(ser_line, sizeof(ser_line)); #ifdef NETLIB netclose(&ipctx); #else # ifdef VMS netclose(ser_rd_fp); netclose(ser_wr_fp); # else (void) fclose(ser_wr_fp); (void) fclose(ser_rd_fp); # endif #endif Server_Has_Been_Closed = 1; } /*}}}*/ #ifdef VMS /*{{{ VMS netwrite */ # ifdef NETLIB static int netwrite(void *sockt, char *string, int len) { struct dsc$descriptor dsc; int rc; struct NETLIBIOSBDEF iosb; INIT_SDESC(dsc, len, string); netlib_write(&sockt, &dsc, 0,0, &iosb,0,0); if ($VMS_STATUS_SUCCESS(rc)) { return(iosb.iosb_w_count); } else return(-1); } # else static int netwrite(int sockt, char *string, int len) { # ifdef DEBUG_FILE if (Debug_Fp != NULL) fprintf(Debug_Fp, ">>> %s\n", string); # endif return(sock_write(sockt, string, len)); } # endif /* !NETLIB */ /*}}}*/ #endif /* VMS */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.