/******************************************************************************
 * 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_telopts.c,v 1.2 2001/03/19 14:54:06 mickey Exp $ */

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

/*** Globals ***/

extern	u_char subopt_buf[];
extern	u_char *sub_bufptr;
extern	u_char *sub_endptr;
extern	char *topts[];

extern	u_short	tel_option[];
extern	u_short	do_dont_response[];
extern	u_short will_wont_response[];

extern	VP vp;
extern	VD vd;

/*** Code ***/

void dooption(u_char opcode)
{
	int ok = 0;

	if(will_wont_response[opcode])
	{
		--will_wont_response[opcode];
		if(will_wont_response[opcode] && my_state_is_will(opcode))
			--will_wont_response[opcode];
	}

	if(!will_wont_response[opcode] && my_want_state_is_wont(opcode))
	{
		if(TOPT_OK(opcode))
			log(VLOG_DEBUG, "(REQ) DO %s", TOPT(opcode));
		else
			log(VLOG_DEBUG, "(REQ) DO %d", opcode);


		/* In case we are willing to use   */
		/* the specified option, we set    */
		/* ok, and reply with WILL option. */
		/* Otherwise we will always reject */
		/* the request, and reply WONT opt */

		switch(opcode)
		{
			case TELOPT_TTYPE:	ok++;
						break;
			case TELOPT_BINARY:	ok++;
						break;
			case TELOPT_ECHO:	ok++;
						break;
			case TELOPT_SGA:	ok++;
						break;
				default:	break;
		}

		if(ok)
		{
			set_my_want_state_will(opcode);
			send_will(opcode, 1);
		}
		else
		{
			will_wont_response[opcode]++;
			send_wont(opcode, 1);
		}
	}
	else
	{
		if(TOPT_OK(opcode))
			log(VLOG_DEBUG, "(ACK) DO %s", TOPT(opcode));
		else
			log(VLOG_DEBUG, "(ACK) DO %d", opcode);
	}

	set_my_state_will(opcode);
}

void dontoption(u_char opcode)
{
	if(will_wont_response[opcode])
	{
		--will_wont_response[opcode];
		if(will_wont_response[opcode] && my_state_is_wont(opcode))
			--will_wont_response[opcode];
	}

	if(!will_wont_response[opcode] && my_want_state_is_will(opcode))
	{
		if(TOPT_OK(opcode))
			log(VLOG_DEBUG, "(REQ) DONT %s", TOPT(opcode));
		else
			log(VLOG_DEBUG, "(REQ) DONT %d", opcode);

		/* REMEMBER: It should always be o.k to turn off */
		/*           some set of options.                */

		switch(opcode)
		{
			case TELOPT_BINARY:	/* The client wants           */
						/* us to do only 7 bits ...   */
						/* tse tse tse ...            */

						break;

			case TELOPT_ECHO:	/* We are not willing to turn */
						/* off our echo, but let the  */
						/* client think, we did so.   */

						break;
			default:		break;
		}

		set_my_want_state_wont(opcode);

		if(my_state_is_will(opcode))
			send_wont(opcode, 1);
	}
	else
	{
		if(TOPT_OK(opcode))
			log(VLOG_DEBUG, "(ACK) DONT %s", TOPT(opcode));
		else
			log(VLOG_DEBUG, "(ACK) DONT %d", opcode);
	}

	set_my_state_wont(opcode);
}

void willoption(u_char opcode)
{
	int ok = 0;

	if(do_dont_response[opcode])
	{
		--do_dont_response[opcode];
		if(do_dont_response[opcode] && his_state_is_will(opcode))
			--do_dont_response[opcode];
	}

	if(!do_dont_response[opcode])
	{
		if(his_want_state_is_wont(opcode))
		{
			/* requests of client side */

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

			switch(opcode)
			{
				case TELOPT_SGA:	ok++;
							break;
				case TELOPT_BINARY:	ok++;
							break;
				case TELOPT_TTYPE:	ok++;
							break;
				default:		break;
			}

			if(ok)
			{
				set_his_want_state_will(opcode);
				send_do(opcode, 1);
			}
			else
			{
				do_dont_response[opcode]++;
				send_dont(opcode, 1);
			}
		}
		else
		{
			/* confirmation of our own requests */

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

			switch(opcode)
			{
				case TELOPT_ECHO:	/* ARGH!! Client responded  */
							/* with WILL ECHO. Since we */
							/* don't want the client to */
							/* echo our chars, let us   */
							/* turn it off right away.  */

							send_dont(TELOPT_ECHO, 1);
							break;
				default:		break;
			}
		}
	}

	set_his_state_will(opcode);
}

void wontoption(u_char opcode)
{
	if(do_dont_response[opcode])
	{
		--do_dont_response[opcode];
		if(do_dont_response[opcode] && his_state_is_wont(opcode))
			--do_dont_response[opcode];
	}

	if(!do_dont_response[opcode])
	{
		if(his_want_state_is_will(opcode))
		{
			/* requests of client side */

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

			switch(opcode)
			{
				case TELOPT_BINARY:	break;
				default:		break;
			}

			set_his_want_state_wont(opcode);

			if(his_state_is_will(opcode))
				send_dont(opcode, 1);
		}
		else
		{
			/* confirmation of our own requests */

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

			switch(opcode)
			{
				default:		break;
			}
		}
	}

	set_his_state_wont(opcode);
}

void handle_suboption(void)
{
	static char lasttype[128];
	char tmp[128];
	char *fuseltmp = &tmp[0];

	u_short x;
	u_short y;

	u_short cmd;

	/*
	 * This indeed IS --> STRAIGHTFORWARD!
	 */

	cmd = SUB_GET();

	switch(cmd)
	{
		case TELOPT_NAWS:	x = (0x100 * SUB_GET());
					x += SUB_GET();
					y = (0x100 * SUB_GET());
					y += SUB_GET();

					log(VLOG_INFO, "Reported screen size: %dx%d", x, y);

					sprintf(vd.env_cols, "COLUMNS=%d", x);

					putenv(vd.env_cols);

					sprintf(vd.env_lines, "LINES=%d", y);

					putenv(vd.env_lines);

					resize();

					log(VLOG_INFO, "Changed screen size to %dx%d", x, y);

					break;
		case TELOPT_TTYPE:	if((x = SUB_GET()) == TELQUAL_SEND)
					{
						/*
						 * Terminal type? What terminal type?
						 * We are cool, so we respond simply
						 * with 'network' ;-)
						 */

						printf("%c%c%c%cnetwork%c%c",
							IAC, SB, TELOPT_TTYPE,
							TELQUAL_IS, IAC, SE);

						log(VLOG_DEBUG, "(TTYPE) Reporting terminal type network");
					}
					else if(x == TELQUAL_IS)
					{
						while(!(SUB_EOF() || (y = SUB_GET()) == IAC))
						{
							*fuseltmp++ = y;
						}

						*fuseltmp = '\0';

						str_lower(tmp);

						log(VLOG_INFO, "Reported terminaltype is %s", tmp);

						if(check_termtype(tmp) == 1)
						{
							strcpy(vd.env_term, tmp);
							vp.emulation = (char *)&vd.env_term;
							vd.emu_ok = 0xff;
						}
						else if(strcmp(lasttype, tmp))
						{
							strcpy(lasttype, tmp);
							printf("%c%c%c%c%c%c", IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE);
						}
						else
						{
							strcpy(vd.env_term, FALLBACK_TTYPE);
							vp.emulation = (char *)&vd.env_term;
							vd.emu_ok = 0xff;
							printf("\r\nUnable to negotiate common terminaltype for this telnet session.\r\n");
							printf("Falling back to %s\r\n", FALLBACK_TTYPE);

							log(VLOG_INFO, "Could not negotiate common terminal type.");
							log(VLOG_INFO, "Falling back to %s", FALLBACK_TTYPE);
						}
					}
					else
					{
						log(VLOG_INFO, "(TTYPE) Huh?");
					}

					break; 
		default:		log(VLOG_INFO, "Unknown sub command: $%02x", cmd);
					break;
	}
}


syntax highlighted by Code2HTML, v. 0.9.1