/******************************************************************************
 * This file is part of a software distribution, which is furnished under the *
 * terms of a license.  Use of this software  by any means is subject to this *
 * license  and  signifies  the  acceptance of  the  licensing  terms  stated *
 * therein. Please see  the file LICENSE in the  top-level directory  of this *
 * software  distribution  for detailed copyright  disclaimers  and licensing *
 * terms.                                                                     *
 ******************************************************************************
 * Copryight (c) by Andreas S. Wetzel - All rights reserved.                  *
 ******************************************************************************/

/* $Id: vd_telproto.c,v 1.2 2001/03/19 14:54:06 mickey Exp $ */

#include <vchat.h>
#include <if_telnet.h>
#include <proto_vchatd.h>

#if HAVE_SYS_SELECT_H
  #include <sys/select.h>
#endif

/*** Globals ***/

char *topts[NTOPTS+1] =
{
	"BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", "STATUS",
	"TIMING MARK", "RCTE", "NAOL", "NAOP", "NAOCRD", "NAOHTS", "NAOHTD",
	"NAOFFD", "NAOVTS", "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT",
	"BYTE MACRO", "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT",
	"SEND_LOCATION", "TERMINAL TYPE", "END OF RECORD", "TACACS UID",
	"OUTPUT MARKING", "TTYLOC", "3270 REGIME", "X.3 PAD", "NAWS",
	"TSPEED", "LFLOW", "LINEMODE", "XDISPLOC", "OLD-ENVIRON",
	"AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON", 0
};

u_char	subopt_buf[SUB_BUFSIZE];

u_char	*sub_bufptr = &subopt_buf[0];
u_char	*sub_endptr = &subopt_buf[0];

u_short	tel_option[256];
u_short	do_dont_response[256];
u_short	will_wont_response[256];

/*** Externals ***/

extern VP vp;
extern VD vd;

/*** Code ***/

void send_do(int opcode, int bypass)
{
	if(!bypass)
	{
		/* Don't send request if already in  */
		/* requested state and no responses  */
		/* open, or if we already requested  */
		/* that state.                       */

		if((!do_dont_response[opcode] && his_state_is_will(opcode))
		|| his_want_state_is_will(opcode))
		{
			return;
		}

		set_his_want_state_will(opcode);
		++do_dont_response[opcode];
	}

	printf("%c%c%c", IAC, DO, opcode);

	if(TOPT_OK(opcode))
		log(VLOG_DEBUG, "(SND) DO %s", TOPT(opcode));
	else
		log(VLOG_DEBUG, "(SND) DO %d", opcode);
}

void send_dont(int opcode, int bypass)
{
	if(!bypass)
	{
		/* Don't send request if already in  */
		/* requested state and no responses  */
		/* open, or if we already requested  */
		/* that state.                       */

		if((!do_dont_response[opcode] && his_state_is_wont(opcode))
		|| his_want_state_is_wont(opcode))
		{
			return;
		}

		set_his_want_state_wont(opcode);
		++do_dont_response[opcode];
	}

	printf("%c%c%c", IAC, DONT, opcode);

	if(TOPT_OK(opcode))
		log(VLOG_DEBUG, "(SND) DONT %s", TOPT(opcode));
	else
		log(VLOG_DEBUG, "(SND) DONT %d", opcode);
}

void send_will(int opcode, int bypass)
{
        if(!bypass)
        {
                /* Don't send request if already in  */
                /* requested state and no responses  */
                /* open, or if we already requested  */
                /* that state.                       */

                if((!will_wont_response[opcode] && my_state_is_will(opcode))
                || my_want_state_is_will(opcode))
                {
                        return;
                }

                set_my_want_state_will(opcode);
                ++will_wont_response[opcode];
        }

        printf("%c%c%c", IAC, WILL, opcode);

        if(TOPT_OK(opcode))
                log(VLOG_DEBUG, "(SND) WILL %s", TOPT(opcode));
	else
		log(VLOG_DEBUG, "(SND) WILL %d", opcode);
}

void send_wont(int opcode, int bypass)
{
	if(!bypass)
	{
		/* Don't send request if already in  */
		/* requested state and no responses  */
		/* open, or if we already requested  */
		/* that state.                       */

		if((!will_wont_response[opcode] && my_state_is_wont(opcode))
		|| my_want_state_is_wont(opcode))
		{
			return;
		}

		set_my_want_state_wont(opcode);
		++will_wont_response[opcode];
	}

	printf("%c%c%c", IAC, WONT, opcode);

	if(TOPT_OK(opcode))
		log(VLOG_DEBUG, "(SND) WONT %s", TOPT(opcode));
	else
		log(VLOG_DEBUG, "(SND) WONT %d", opcode);
}

int request_termtype(void)
{
	send_do(TELOPT_TTYPE, 0);
	send_do(TELOPT_NAWS, 0);

	while(his_will_wont_differs(TELOPT_TTYPE)
	|| his_will_wont_differs(TELOPT_NAWS))
	{
		if(cmd_loop() == -1)
			return(-1);
	}

	if(his_state_is_will(TELOPT_TTYPE))
	{
		printf("%c%c%c%c%c%c", IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE);

		while(!vd.emu_ok)
		{
			if(cmd_loop() == -1)
				return(-1);
		}
	}
	else
	{
		strcpy(vd.env_term, DEFAULT_TTYPE);
		vp.emulation = (char *)&vd.env_term;
		vd.emu_ok = 0xff;
		log(VLOG_INFO, "Client side does not support TTYPE option - defaulting to %s.", vp.emulation);
	}
#if 0
	if(his_state_is_will(TELOPT_NAWS))
	{
		printf("%c%c%c%c%c%c", IAC, SB, TELOPT_NAWS, TELQUAL_SEND, IAC, SE);
	}
#endif

	return(0);
}

int cmd_loop(void)
{
	fd_set rfdset;

	int ret, c;

	u_char rcvbuf[512];

	u_char *bufptr = &rcvbuf[0];

	struct timeval tm;

	tm.tv_sec = 0;
	tm.tv_usec = 350000;	/* 0.2 sec */

	FD_ZERO(&rfdset);
	FD_SET(0, &rfdset);

	if((ret = select(1, (fd_set *) &rfdset, (fd_set *) NULL, (fd_set *) NULL,(struct timeval *)&tm)) == -1)
	{
		log(VLOG_ERR, "cmd_loop(): error in select();");
		return(-1);
	}
	else if(ret)
	{
		if(FD_ISSET(0, &rfdset))
		{
			if((ret = read(0, &rcvbuf, 512)) == -1)
			{
				log(VLOG_ERR, "cmd_loop: read error (%s)", strerror(errno));
				return(-1);
			}
			else if(!ret)
			{
				log(VLOG_ERR, "cmd_loop: broken pipe");
				return(-1);
			}

			while(ret)
			{
				if((c = tel_filter(*bufptr++)))
				{
					log(VLOG_ERR, "cmd_loop(): unwanted user character $%02x", c);
					ungetc(c, stdin);
				}
				--ret;
			}
		}
	}
#ifdef DEBUG
	else
	{
		log(VLOG_DEBUG, "cmd_loop(): Timeout");
	}
#endif

	return(0);
}


syntax highlighted by Code2HTML, v. 0.9.1