wsh/
wsh/binsrc/
wsh/docs/help/
wsh/docs/old/
wsh/etc/
wsh/src/util/
/* 	telnet.c    Routines for simple telnet negotiation       */

#include	"tcp.h"

#ifdef TELNET
#define TELOPTS
#include	<arpa/telnet.h>
#else
#include	"telnet.h"
#endif

#ifdef SHORT_IAC
#undef WILL
#define WILL	(-5)
#undef WONT
#define WONT	(-4)
#undef DO
#define DO	(-3)
#undef DONT
#define DONT	(-2)
#undef IAC
#define IAC	(-1)
#endif /* SHORT_IAC */

int istelnet=0;		/* Is this a telnet connection? */

static void print_opts(nego_str)
char nego_str[];
{
	char *opt_str, opt_ind[24];

	switch (nego_str[1])
	{
		case WILL: opt_str="WILL";
			   break;
		case WONT: opt_str="WONT";
			   break;
		case DO:   opt_str="DO";
			   break;
		case DONT: opt_str="DONT";
			   break;
		default:   opt_str="??";
	}

	if ( nego_str[2] < 22 )
		strcpy(opt_ind, telopts[nego_str[2]]);
	else
		sprintf(opt_ind, "%d", nego_str[2]);

	fprintf(stderr, "%s %s\r\n", opt_str, opt_ind);

	return;
}
	
/* Routine to initialize the telnet options.  The structure of
   the arguments is hardcoded, be sure to get it right. */

#define NORMAL 		0
#define AT_IAC 		1
#define AT_IAC_A	2

static int status=NORMAL;  	/* Current status of telnet negotiation */

static int OPTIONS[126];

void init_telnet(sockfd, will_echo)
int will_echo;
{
	int i;
	char sendstr[3];

	istelnet=0;	/* Initialize istelnet to not a telnet connection */

	/* Send initializing negotiations */
	status=NORMAL;
	sendstr[0]=IAC;

	sendstr[1]=WILL;
	sendstr[2]=TELOPT_SGA;
	write(sockfd, sendstr, 3);

	if ( netdebug )
	{
		fprintf(stderr, "Sent: ");
		print_opts(sendstr);
	}

	for ( i=0; i<=126; ++i )
	{
		switch (i) 
		{
			case TELOPT_ECHO: if ( will_echo )
						OPTIONS[i]=WILL;
					  else
                                                OPTIONS[i]=WONT;
					  break;
			case TELOPT_SGA:  OPTIONS[i]=WILL;
					  break;
			default: OPTIONS[i]=WONT;
		}
	}

	sendstr[1]=OPTIONS[TELOPT_ECHO];
	sendstr[2]=TELOPT_ECHO;
	write(sockfd, sendstr, 3);

	if ( netdebug )
	{
		fprintf(stderr, "Sent: ");
		print_opts(sendstr);
	}
	return;
}

/* Routine to perform telnet negotiation. It takes a Buf_Len 
   structure and a socket file descriptor.  It checks the buffer 
   for telnet negotiation, negotiates, and returns a Buf_Len 
   structure with the modified buffer  */

struct Buf_Len modified;

static char sent[2]={IAC};	/* The negotiation sent */
static char reply[2]={IAC};	/* The negotiation reply */

struct Buf_Len *negotiate(sockfd, recvd)
int sockfd;
struct Buf_Len *recvd;
{
	int i, j=0;

	modified.len=0;

	for ( i=0; i<recvd->len; ++i )
	{
		switch (status)
		{
			case AT_IAC:	status=AT_IAC_A;
					sent[1]=recvd->buffer[i];
					break;
			case AT_IAC_A:	status=NORMAL;
					sent[2]=recvd->buffer[i];
					if ( netdebug )
					{
						fprintf(stderr, "Received: ");
						print_opts(sent);
					}
					if ( sent[1] == DO )
					{
						reply[1]=OPTIONS[sent[2]];
						reply[2]=sent[2];
						write(sockfd, reply, 3);

						if ( netdebug )
						{
						     fprintf(stderr, "Sent: ");
						     print_opts(reply);
						}
					}
					break;
			case NORMAL:	switch (recvd->buffer[i])
					{
						case IAC: if ( ! istelnet )
								istelnet=1;
							  status=AT_IAC;
							  continue;
						default:  status=NORMAL;
							  modified.buffer[j++]=recvd->buffer[i];
							  ++modified.len;
							  break;
					}
					break;
			default: fprintf(stderr,"status error: %d\r\n",status);
				 break;
		}
	}
	return(&modified);
}