1stMud4.5.3/
1stMud4.5.3/backup/
1stMud4.5.3/bin/
1stMud4.5.3/bin/extras/
1stMud4.5.3/data/i3/
1stMud4.5.3/doc/1stMud/
1stMud4.5.3/doc/Diku/
1stMud4.5.3/doc/MPDocs/
1stMud4.5.3/doc/Rom/
1stMud4.5.3/notes/
/**************************************************************************
*  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
*  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
*                                                                         *
*  Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael         *
*  Chastain, Michael Quan, and Mitchell Tse.                              *
*                                                                         *
*  In order to use any part of this Merc Diku Mud, you must comply with   *
*  both the original Diku license in 'license.doc' as well the Merc       *
*  license in 'license.txt'.  In particular, you may not remove either of *
*  these copyright notices.                                               *
*                                                                         *
*  Much time and thought has gone into this software and you are          *
*  benefiting.  We hope that you share your changes too.  What goes       *
*  around, comes around.                                                  *
***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                        *
*       ROM has been brought to you by the ROM consortium                 *
*           Russ Taylor (rtaylor@hypercube.org)                           *
*           Gabrielle Taylor (gtaylor@hypercube.org)                      *
*           Brian Moore (zump@rom.org)                                    *
*       By using this code, you have agreed to follow the terms of the    *
*       ROM license, in the file Rom24/doc/rom.license                    *
***************************************************************************
*          1stMud ROM Derivative (c) 2001-2004 by Markanth                *
*            http://www.firstmud.com/  <markanth@firstmud.com>            *
*         By using this code you have agreed to follow the term of        *
*             the 1stMud license in ../doc/1stMud/LICENSE                 *
***************************************************************************/

#define TELOPTS        	1
#define TELCMDS        	1

#include "merc.h"
#include "telnet.h"

const char echo_off_str[] = {
	IAC, WILL, TELOPT_ECHO, NUL
};
const char echo_on_str[] = {
	IAC, WONT, TELOPT_ECHO, NUL
};
const char echo_dont[] = {
	IAC, DONT, TELOPT_ECHO, NUL
};
const char echo_do[] = {
	IAC, DO, TELOPT_ECHO, NUL
};

const char eor_do[] = {
	IAC, DO, TELOPT_EOR, NUL
};
const char eor_will[] = {
	IAC, WILL, TELOPT_EOR, NUL
};
const char eor_dont[] = {
	IAC, DONT, TELOPT_EOR, NUL
};
const char eor_wont[] = {
	IAC, WONT, TELOPT_EOR, NUL
};

const char iac_logout[] = {
	IAC, DO, TELOPT_LOGOUT, NUL
};

const char tspd_will[] = {
	IAC, WILL, TELOPT_TSPEED, NUL
};
const char tspd_do[] = {
	IAC, DO, TELOPT_TSPEED, NUL
};
const char tspd_wont[] = {
	IAC, WONT, TELOPT_TSPEED, NUL
};
const char tspd_dont[] = {
	IAC, DONT, TELOPT_TSPEED, NUL
};

const char naws_will[] = {
	IAC, WILL, TELOPT_NAWS, NUL
};
const char naws_dont[] = {
	IAC, DONT, TELOPT_NAWS, NUL
};
const char naws_do[] = {
	IAC, DO, TELOPT_NAWS, NUL
};
const char naws_wont[] = {
	IAC, WONT, TELOPT_NAWS, NUL
};
const char naws_sb[] = {
	IAC, SB, TELOPT_NAWS, NUL
};

const char iac_ip[] = {
	IAC, IP, NUL
};
const char iac_susp[] = {
	IAC, SUSP, NUL
};
const char iac_brk[] = {
	IAC, BREAK, NUL
};

const char iac_se[] = {
	IAC, SE, NUL
};

const char go_ahead_str[] = {
	IAC, GA, NUL
};
const char will_suppress_ga_str[] = {
	IAC, WILL, TELOPT_SGA, NUL
};
const char wont_suppress_ga_str[] = {
	IAC, WONT, TELOPT_SGA, NUL
};

#ifndef DISABLE_MCCP
const char compress1_will[] = {
	IAC, WILL, TELOPT_COMPRESS, NUL
};
const char compress1_do[] = {
	IAC, DO, TELOPT_COMPRESS, NUL
};
const char compress1_dont[] = {
	IAC, DONT, TELOPT_COMPRESS, NUL
};
const char compress1_wont[] = {
	IAC, WONT, TELOPT_COMPRESS, NUL
};

const char compress2_will[] = {
	IAC, WILL, TELOPT_COMPRESS2, NUL
};
const char compress2_do[] = {
	IAC, DO, TELOPT_COMPRESS2, NUL
};
const char compress2_dont[] = {
	IAC, DONT, TELOPT_COMPRESS2, NUL
};
const char compress2_wont[] = {
	IAC, WONT, TELOPT_COMPRESS2, NUL
};
#endif

const char msp_will[] = {
	IAC, WILL, TELOPT_MSP, NUL
};
const char msp_do[] = {
	IAC, DO, TELOPT_MSP, NUL
};
const char msp_dont[] = {
	IAC, DONT, TELOPT_MSP, NUL
};
const char msp_wont[] = {
	IAC, WONT, TELOPT_MSP, NUL
};

const char mxp_will[] = {
	IAC, WILL, TELOPT_MXP, NUL
};
const char mxp_do[] = {
	IAC, DO, TELOPT_MXP, NUL
};
const char mxp_dont[] = {
	IAC, DONT, TELOPT_MXP, NUL
};
const char mxp_wont[] = {
	IAC, WONT, TELOPT_MXP, NUL
};

const char s_mxp_supports[] = {
	MXPMODE(1) "<SUPPORTS"
};
const char s_mxp_version[] = {
	MXPMODE(1) "<VERSION"
};

const char pueblo_str[] = { "PUEBLOCLIENT "
};
const char ptype_3klient[] = { "3klient "
};
const char imp_str[] = { "v1."
};

const char ttype_do[] = {
	IAC, DO, TELOPT_TTYPE, NUL
};
const char ttype_dont[] = {
	IAC, DONT, TELOPT_TTYPE, NUL
};
const char ttype_sb[] = {
	IAC, SB, TELOPT_TTYPE, NUL
};
const char ttype_send[] = {
	IAC, SB, TELOPT_TTYPE, SEND, IAC, SE, NUL
};
const char ttype_will[] = {
	IAC, WILL, TELOPT_TTYPE, NUL
};
const char ttype_wont[] = {
	IAC, WONT, TELOPT_TTYPE, NUL
};

const char binary_do[] = {
	IAC, DO, TELOPT_BINARY, NUL
};
const char binary_dont[] = {
	IAC, DONT, TELOPT_BINARY, NUL
};
const char binary_will[] = {
	IAC, WILL, TELOPT_BINARY, NUL
};
const char binary_wont[] = {
	IAC, WONT, TELOPT_BINARY, NUL
};

Proto(void init_mxp, (Descriptor *));
Proto(void mxp_support, (Descriptor *, int, unsigned char *));
Proto(void mxp_version, (Descriptor *, int, unsigned char *));

#define MTELOPT(string, command, len) \
        	    if (!memcmp(&buf[i],(string),(slen = strlen((string))))) \
        	    { \
    	    	    	    	telopt_debug(d,&buf[i],slen+(len)+telopt_lskip,false); \
    	    	    	    	i += slen - 1; \
    	    	    	    	(command); \
    	    	    	    	i += len; \
    	    	    	    	i += telopt_lskip; \
    	    	    	    	telopt_lskip = 0; \
    	    	    	    	continue; \
        	    }

#define MSTRING(string, command, len) \
        	    if (!memcmp(&buf[i],(string),strlen((string)))) \
        	    { \
    	    	    	    	(command); \
    	    	    	    	i += telopt_lskip; \
    	    	    	    	telopt_lskip = 0; \
    	    	    	    	continue; \
        	    }

void init_telnet(Descriptor * d)
{
	d_write(d, tspd_will, 0);

	return;
}

void telopt_init(Descriptor * d)
{

	d_write(d, eor_will, 0);

	d_write(d, ttype_do, 0);

	d_write(d, naws_do, 0);

#ifndef DISABLE_MCCP

	d_write(d, compress2_will, 0);

	d_write(d, compress1_will, 0);
#endif

	d_write(d, msp_will, 0);

	d_write(d, mxp_will, 0);

	d_write(d, binary_will, 0);

	return;
}

void telopt_debug(Descriptor * d, unsigned char *string, int length,
				  bool send)
{
	int i, j;
	static char buf[MSL];
	unsigned int c;
	bool sb = false;

	if (!d)
		return;

	sprintf(buf, "Telopt: [%d][%s][ ", d->descriptor,
			(send) ? "send" : "recv");

	if (string[0] != IAC)
		return;

	for (i = 0; i < length; i++)
	{
		c = string[i];

		if (TELCMD_OK(c))
		{
			sprintf(buf + strlen(buf), "%s ", TELCMD(c));

			if (c == SB)
				sb = true;
			if (c == SE)
				sb = false;

			continue;
		}
		else if (TELOPT_OK(c))
		{
			sprintf(buf + strlen(buf), "%s ", TELOPT(c));

			if (sb && c == TELOPT_NAWS)
			{
				for (j = 0; j < 4; j++)
				{
					i++;
					c = string[i];
					sprintf(buf + strlen(buf), "%u ", c);
				}
			}

			if (sb && c == TELOPT_TTYPE)
			{
				i++;
				c = string[i];
				if (c == SEND)
				{
					strcat(buf, "SEND ");
				}
				else if (c == IS)
				{
					strcat(buf, "IS ");
					do
					{
						i++;
						c = string[i];
						sprintf(buf + strlen(buf), "%c", c);
					}
					while (c != IAC);
					strcat(buf, " ");
				}
				else
				{
					sprintf(buf + strlen(buf), "%u ", c);
				}
			}

			continue;
		}
		else
		{
			sprintf(buf + strlen(buf), "%u ", c);
		}
	}

	sprintf(buf + strlen(buf), "]");
	wiznet(buf, NULL, NULL, WIZ_TELNET, false, MAX_LEVEL - 2);
	return;
}

void telopt_ignore(void)
{
	return;
}

void telopt_send(Descriptor * d, const char *string, int len)
{
	d_write(d, string, len);
	return;
}

void telopt_close(Descriptor * d)
{
	wiznet("IAC IP/SUSP received, closing link to $N.", CH(d), NULL,
		   WIZ_LINKS, true, 0);
	close_socket(d);
	return;
}

void telopt_eor(Descriptor * d, bool state)
{
	if (state)
		SetBit(d->desc_flags, DESC_TELOPT_EOR);
	else
		RemBit(d->desc_flags, DESC_TELOPT_EOR);
	return;
}

void telopt_msp(Descriptor * d, bool state)
{
	if (state)
		SetBit(d->desc_flags, DESC_MSP);
	else
		RemBit(d->desc_flags, DESC_MSP);
	return;
}

void telopt_mxp(Descriptor * d, bool state)
{
	if (state)
	{
		SetBit(d->desc_flags, DESC_MXP);
		init_mxp(d);
	}
	else
	{
		RemBit(d->desc_flags, DESC_MXP);
	}
	return;
}

#ifndef DISABLE_MCCP
void telopt_compress(Descriptor * d, bool state, int version)
{
	if (d->out_compress)
		return;

	if (state)
		compressStart(d, version);
	else
		compressEnd(d, version);
	return;
}
#endif

void telopt_echo(Descriptor * d, bool state)
{
	if (state)
		SetBit(d->desc_flags, DESC_TELOPT_ECHO);
	else
		RemBit(d->desc_flags, DESC_TELOPT_ECHO);
	return;
}

int telopt_unknown(Descriptor * d, unsigned int c, char t, bool quiet)
{
	char buf[MSL];
	char cmd[MIL];
	char opt[MIL];
	char rev;
	char len = 1;

	if (c == '\n' || c == '\r' || c == NUL)
		return 0;

	if (TELCMD_OK(c))
	{
		sprintf(cmd, "%s", TELCMD(c));
		if (c == IAC)
			len = 1;

		else if (c >= SB)
			len = 2;

		else
			len = 1;

	}

	if (!quiet)
	{
		if (TELCMD_OK(c))
			sprintf(cmd, "%s", TELCMD(c));
		else
			sprintf(cmd, "[%u]", c);

		if (TELOPT_OK(t))
			sprintf(opt, "%s", TELOPT(t));
		else if (TELCMD_OK(t))
			sprintf(opt, "%s", TELCMD(t));
#ifndef DISABLE_MCCP

		else if (t == TELOPT_COMPRESS)
			sprintf(opt, "COMPRESS-1");
		else if (t == TELOPT_COMPRESS2)
			sprintf(opt, "COMPRESS-2");
#endif

		else if (t == TELOPT_MSP)
			sprintf(opt, "MSP");
		else if (t == TELOPT_MXP)
			sprintf(opt, "MXP");
		else
			sprintf(opt, "[%u]", t);

		switch (c)
		{
			case WILL:
				rev = WONT;
				break;
			case WONT:
				rev = DONT;
				break;
			case DONT:
				rev = WONT;
				break;
			case DO:
				rev = DONT;
				break;
			default:
				rev = c;
				break;
		}
		sprintf(buf, "%c%c%c", IAC, rev, t);
		d_write(d, buf, 0);
		logf("Unknown to client: IAC %s %s", cmd, opt);
	}
	return len;
}

void telopt_naws_do(Descriptor * d)
{
	if (IsSet(d->desc_flags, DESC_TELOPT_NAWS))
		return;

	d_write(d, naws_do, 0);
	return;
}

void telopt_naws(Descriptor * d, int i, unsigned char *inbuf)
{
	int x = 0, y = 0, t1, t2;

	SetBit(d->desc_flags, DESC_TELOPT_NAWS);

	t1 = inbuf[i + 1];
	t2 = inbuf[i + 2];
	x = t2 + (t1 * 16);

	t1 = inbuf[i + 3];
	t2 = inbuf[i + 4];
	y = t2 + (t1 * 16);

	d->scr_width = Range(10, x, 250);
	d->scr_height = Range(10, y, 250);

	return;
}

void telopt_ttype(Descriptor * d, int i, int len, unsigned char *inbuf)
{
	int n;
	int skip = 0;

	d->ttype[0] = NUL;

	SetBit(d->desc_flags, DESC_TELOPT_TTYPE);

	for (n = 0; n <= len; n++)
	{
		if (inbuf[n + i + 2] == IAC)
		{
			if (inbuf[n + i + 3] == SE)
			{
				telopt_lskip = skip;
				return;
			}
		}
		else
		{
			if (n < 59)
			{
				d->ttype[n] = inbuf[n + i + 2];
				d->ttype[n + 1] = NUL;
			}
			skip++;
		}
	}

	return;
}

void telopt_binary(Descriptor * d, bool state)
{
	if (state)
		SetBit(d->desc_flags, DESC_TELOPT_BINARY);
	else
		RemBit(d->desc_flags, DESC_TELOPT_BINARY);
	return;
}

void pueblo_client(Descriptor * d, int i, unsigned char *inbuf)
{
	char *buf = (char *) &inbuf[i];
	char send[MSL];

	sscanf(buf, "PUEBLOCLIENT %lf", &d->pueblo_vers);

	telopt_lskip = strlen(buf);

	SetBit(d->desc_flags, DESC_PUEBLO);

	sprintf(send, NEWLINE "Pueblo version %.2f detected...", d->pueblo_vers);
	d_write(d, send, 0);

	return;
}

void portal_3klient(Descriptor * d, int i, unsigned char *inbuf)
{
	char *buf = (char *) &inbuf[i];
	static char tbuf[MSL];
	int n;

	SetBit(d->desc_flags, DESC_TELOPT_TTYPE);
	SetBit(d->desc_flags, DESC_PORTAL);

	sscanf(buf, "3klient %u~%s \r \n", &d->portal.keycode, tbuf);

	for (n = 0; tbuf != NUL; n++)
		if (isdigit(tbuf[n]))
			break;

	snprintf(d->portal.version, 20, "Portal %s", &tbuf[n]);

	telopt_lskip = strlen(buf);

	d_print(d, NEWLINE "Portal GT Detected...");

	return;

}

void fire_client(Descriptor * d, int i, unsigned char *inbuf)
{
	char *buf = (char *) &inbuf[i];
	int vers;

	SetBit(d->desc_flags, DESC_IMP);

	sscanf(buf, "v1.%2d", &vers);

	telopt_lskip = strlen(buf);

	d->imp_vers = (double) ((vers * .01) + 1);
	d_printf(d, NEWLINE "Fire Client version v%.2f detected...", d->imp_vers);

	return;
}

void process_telnet(Descriptor * d, int len, unsigned char *buf)
{
	int i;
	int iStart = strlen(d->inbuf);

	if (len <= 0)
		return;

	for (i = 0; i <= len; i++)
	{
		if (buf[i] == IAC)
		{
			int slen;

			switch (buf[i + 1])
			{
				case IAC:
					continue;
					break;

				case DO:
					MTELOPT(tspd_do, telopt_init(d), 0);
					MTELOPT(eor_do, telopt_eor(d, true), 0);
					MTELOPT(echo_do, telopt_echo(d, true), 0);
#ifndef DISABLE_MCCP

					MTELOPT(compress2_do, telopt_compress(d, true, 2), 0);
					MTELOPT(compress1_do, telopt_compress(d, true, 1), 0);
#endif

					MTELOPT(msp_do, telopt_msp(d, true), 0);
					MTELOPT(mxp_do, telopt_mxp(d, true), 0);
					MTELOPT(ttype_do, telopt_ignore(), 0);
					MTELOPT(binary_do, telopt_binary(d, true), 1);
					MTELOPT(iac_logout, telopt_ignore(), 0);
					break;

				case DONT:
					MTELOPT(tspd_dont, telopt_init(d), 0);
#ifndef DISABLE_MCCP

					MTELOPT(compress2_dont, telopt_compress(d, false, 2), 0);
					MTELOPT(compress1_dont, telopt_compress(d, false, 1), 0);
#endif

					MTELOPT(msp_dont, telopt_msp(d, false), 0);
					MTELOPT(mxp_dont, telopt_mxp(d, false), 0);
					MTELOPT(ttype_dont, telopt_ignore(), 0);
					MTELOPT(binary_dont, telopt_binary(d, false), 1);
					MTELOPT(echo_dont, telopt_echo(d, false), 0);
					MTELOPT(eor_dont, telopt_eor(d, false), 0);
					break;

				case WILL:
					MTELOPT(naws_will, telopt_naws_do(d), 0);
					MTELOPT(tspd_will, telopt_init(d), 0);
#ifndef DISABLE_MCCP

					MTELOPT(compress2_will, telopt_compress(d, true, 2), 0);
					MTELOPT(compress1_will, telopt_compress(d, true, 1), 0);
#endif

					MTELOPT(eor_will, telopt_eor(d, true), 0);
					MTELOPT(msp_will, telopt_msp(d, true), 0);
					MTELOPT(mxp_will, telopt_mxp(d, true), 0);
					MTELOPT(ttype_will, telopt_send(d, ttype_send, 6), 0);
					MTELOPT(binary_will, telopt_binary(d, true), 1);
					break;

				case WONT:
					MTELOPT(naws_wont, telopt_ignore(), 0);
					MTELOPT(tspd_wont, telopt_init(d), 0);
					MTELOPT(eor_wont, telopt_eor(d, false), 0);
#ifndef DISABLE_MCCP

					MTELOPT(compress2_wont, telopt_compress(d, false, 2), 0);
					MTELOPT(compress1_wont, telopt_compress(d, false, 1), 0);
#endif

					MTELOPT(mxp_wont, telopt_mxp(d, false), 0);
					MTELOPT(msp_wont, telopt_msp(d, false), 0);
					MTELOPT(ttype_wont, telopt_ignore(), 0);
					MTELOPT(binary_wont, telopt_binary(d, false), 1);
					break;

				case SB:
					MTELOPT(naws_sb, telopt_naws(d, i, buf), 6);
					MTELOPT(ttype_sb, telopt_ttype(d, i, len, buf), 1);
					break;

				case IP:

					MTELOPT(iac_ip, telopt_close(d), 0);
					break;

				case SUSP:
					MTELOPT(iac_susp, telopt_close(d), 0);
					break;

				case BREAK:

					MTELOPT(iac_brk, telopt_ignore(), 0);
					break;

				case SE:

					MTELOPT(iac_se, telopt_ignore(), 0);
					break;

				default:

					i += telopt_unknown(d, buf[i + 1], buf[i + 2], false);
					break;
			}
		}
		else
		{
			if (buf[i] == 'P' && buf[i + 1] == 'U')
				MSTRING(pueblo_str, pueblo_client(d, i, buf), 0);

			if (buf[i] == '3' && buf[i + 1] == 'k')
				MSTRING(ptype_3klient, portal_3klient(d, i, buf), 0);

			if (buf[i] == 'v' && buf[i + 1] == '1')
				MSTRING(imp_str, fire_client(d, i, buf), 0);

			if (buf[i] == ESCc && buf[i + 1] == '[')
			{
				MSTRING(s_mxp_version, mxp_version(d, i, buf), 0);
				MSTRING(s_mxp_supports, mxp_support(d, i + 4, buf), 0);
			}

			switch (buf[i])
			{
				case '~':
					if (!MudFlag(DISABLE_TILDE_CONVERSION))
					{
						d->inbuf[iStart++] = COLORCODE;
						d->inbuf[iStart++] = '-';
					}
					else
						d->inbuf[iStart++] = buf[i];
					break;

				default:
					d->inbuf[iStart++] = buf[i];
					break;
			}
		}
	}
	return;
}

void set_desc_flags(Descriptor * d)
{
	CharData *ch = CH(d);

	if (!ch)
		return;

	if (IsSet(d->desc_flags, DESC_TELOPT_EOR))
		SetBit(ch->comm, COMM_TELNET_EOR);
	else
		RemBit(ch->comm, COMM_TELNET_EOR);

	if (IsSet(ch->comm, COMM_NOCOLOR))
		RemBit(d->desc_flags, DESC_COLOR);

	return;
}