ftp.nice.ch/pub/next/unix/network/news/slrn0.9.0.0.s.tar.gz#/slrn/src/clientlib.c

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.