1stMud/CVS/
1stMud/area/CVS/
1stMud/backup/CVS/
1stMud/bin/
1stMud/bin/CVS/
1stMud/bin/extras/
1stMud/bin/extras/CVS/
1stMud/data/CVS/
1stMud/data/i3/CVS/
1stMud/doc/1stMud/
1stMud/doc/1stMud/CVS/
1stMud/doc/CVS/
1stMud/doc/Diku/
1stMud/doc/Diku/CVS/
1stMud/doc/MPDocs/CVS/
1stMud/doc/Merc/CVS/
1stMud/doc/Rom/
1stMud/doc/Rom/CVS/
1stMud/log/CVS/
1stMud/notes/
1stMud/notes/CVS/
1stMud/player/CVS/
1stMud/player/backup/CVS/
1stMud/player/deleted/CVS/
1stMud/src/CVS/
1stMud/src/config/CVS/
1stMud/src/h/CVS/
1stMud/src/o/CVS/
1stMud/win/CVS/
/**************************************************************************
*  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),strlen((string))))    	    	\
    	    {     	    	    	    	    	    	    	    	\
            telopt_debug(d,&buf[i],strlen((string))+(len)+telopt_lskip,false);\
            i += strlen((string)) - 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)
	{
	  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 '~':
	      d->inbuf[iStart++] = COLORCODE;
	      d->inbuf[iStart++] = '-';
	      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;
}