/
com/planet_ink/coffee_mud/Abilities/Common/
com/planet_ink/coffee_mud/Abilities/Diseases/
com/planet_ink/coffee_mud/Abilities/Druid/
com/planet_ink/coffee_mud/Abilities/Fighter/
com/planet_ink/coffee_mud/Abilities/Languages/
com/planet_ink/coffee_mud/Abilities/Misc/
com/planet_ink/coffee_mud/Abilities/Prayers/
com/planet_ink/coffee_mud/Abilities/Properties/
com/planet_ink/coffee_mud/Abilities/Skills/
com/planet_ink/coffee_mud/Abilities/Songs/
com/planet_ink/coffee_mud/Abilities/Spells/
com/planet_ink/coffee_mud/Abilities/Thief/
com/planet_ink/coffee_mud/Abilities/Traps/
com/planet_ink/coffee_mud/Behaviors/
com/planet_ink/coffee_mud/CharClasses/interfaces/
com/planet_ink/coffee_mud/Commands/
com/planet_ink/coffee_mud/Commands/interfaces/
com/planet_ink/coffee_mud/Common/
com/planet_ink/coffee_mud/Common/interfaces/
com/planet_ink/coffee_mud/Exits/interfaces/
com/planet_ink/coffee_mud/Items/Armor/
com/planet_ink/coffee_mud/Items/Basic/
com/planet_ink/coffee_mud/Items/CompTech/
com/planet_ink/coffee_mud/Items/MiscMagic/
com/planet_ink/coffee_mud/Items/Weapons/
com/planet_ink/coffee_mud/Items/interfaces/
com/planet_ink/coffee_mud/Libraries/
com/planet_ink/coffee_mud/Libraries/interfaces/
com/planet_ink/coffee_mud/Locales/
com/planet_ink/coffee_mud/MOBS/
com/planet_ink/coffee_mud/Races/
com/planet_ink/coffee_mud/Races/interfaces/
com/planet_ink/coffee_mud/WebMacros/
com/planet_ink/coffee_mud/WebMacros/interfaces/
com/planet_ink/coffee_mud/core/
com/planet_ink/coffee_mud/core/collections/
com/planet_ink/coffee_mud/core/interfaces/
com/planet_ink/coffee_mud/core/intermud/
com/planet_ink/coffee_mud/core/intermud/i3/
com/planet_ink/coffee_web/server/
com/planet_ink/siplet/applet/
lib/
resources/factions/
resources/fakedb/
resources/progs/autoplayer/
resources/quests/holidays/
web/
web/admin.templates/
web/admin/grinder/
web/admin/images/
web/clan.templates/
web/pub.templates/
web/pub/images/mxp/
web/pub/sounds/
web/pub/textedit/
package com.planet_ink.siplet.support;

import java.io.*;
import java.util.*;

import com.jcraft.jzlib.*;
import com.planet_ink.siplet.applet.Siplet;
import com.planet_ink.siplet.applet.Siplet.MSPStatus;
import com.planet_ink.siplet.support.MiniJSON.JSONObject;
import com.planet_ink.siplet.support.MiniJSON.MJSONException;

/*
   Copyright 2005-2016 Bo Zimmerman

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

	   http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

public class TelnetFilter
{
	public final static boolean	debugChars				= false;
	public final static boolean	debugTelnetCodes		= false;

	protected static final char	IAC_SE					= 240;
	protected static final char	IAC_					= 255;
	protected static final char	IAC_SB					= 250;
	protected static final char	IAC_DO					= 253;
	protected static final char	IAC_WILL				= 251;
	protected static final char	IAC_WONT				= 252;
	protected static final char	IAC_DONT				= 254;
	protected static final char	IAC_MSDP				= 69;
	protected static final char	IAC_GMCP				= 201;
	protected static final char	IAC_MSP					= 90;
	protected static final char	IAC_MXP					= 91;
	protected static final char	IAC_GA					= 249;
	protected static final char	IAC_NOP					= 241;
	protected static final char	TELNET_ATCP				= 200;
	protected static final char	TELNET_GMCP				= 201;
	protected static final char	TELOPT_BINARY			= 0;
	protected static final char	TELOPT_EOR				= 25;
	protected static final char	TELOPT_ECHO				= 1;
	protected static final char	TELOPT_NAWS				= 31;
	protected static final char	TELOPT_LOGOUT			= 18;
	protected static final char	TELOPT_TTYPE			= 24;
	protected static final char	TELOPT_TSPEED			= 32;
	protected static final char	MCCP_COMPRESS			= 85;
	protected static final char	MCCP_COMPRESS2			= 86;
	protected static final char	TELOPT_NEWENVIRONMENT	= 39;

	private static String		defaultBackground		= "black";
	private static String		defaultForeground		= "white";
	private static String[]		colorCodes1				= { // 30-37
														"black", // black
			"#993300", // red
			"green", // green
			"#999966", // brown
			"#000099", // blue
			"purple", // purple
			"darkcyan", // cyan
			"lightgrey"								};							// grey
	private static String[]		colorCodes2				= { "gray", // dark grey
			"red", // light red
			"lightgreen", // light green
			"yellow", // yellow
			"blue", // light blue
			"violet", // light purple
			"cyan", // light cyan
			"white"									};							// white

	protected String			lastBackground			= null;
	protected String			lastForeground			= null;
	protected boolean			blinkOn					= false;
	protected boolean			fontOn					= false;
	protected boolean			boldOn					= false;
	protected boolean			underlineOn				= false;
	protected boolean			italicsOn				= false;
	private Siplet				codeBase				= null;
	protected boolean			comment					= false;

	protected MSPStatus			neverSupportMSP			= MSPStatus.Internal;
	protected boolean			neverSupportMXP			= false;
	protected boolean			neverSupportMSDP		= false;
	protected boolean			neverSupportGMCP		= false;
	protected boolean			neverSupportMCCP		= false;
	protected boolean			MSPsupport				= false;
	protected boolean			MSDPsupport				= false;
	protected boolean			GMCPsupport				= false;
	protected boolean			MXPsupport				= false;
	protected boolean			MCCPsupport				= false;
	private final StringBuilder	msdpInforms				= new StringBuilder("");
	private final StringBuilder	gmcpInforms				= new StringBuilder("");

	private final MSP			mspModule				= new MSP();
	private final MSDP			msdpModule				= new MSDP();
	private final GMCP			gmcpModule				= new GMCP();
	private final MXP			mxpModule				= new MXP();

	private TelnetFilter()
	{
	}

	public TelnetFilter(Siplet codebase)
	{
		this();
		codeBase = codebase;
	}

	public static String getSipletVersion()
	{
		return Siplet.VERSION_MAJOR + "." + Siplet.VERSION_MINOR;
	}

	public String getEnquedResponses()
	{
		return (MXPsupport() ? mxpModule.getAnyResponses() : "");
	}

	public String getEnquedJScript()
	{
		return ((mxpModule != null) ? mxpModule.getAnyJScript() : "") + ((mspModule != null) ? mspModule.getAnyJScript() : "");
	}

	public boolean MSPsupport()
	{
		return MSPsupport;
	}

	public void setMSPSupport(boolean truefalse)
	{
		MSPsupport = truefalse;
	}

	public boolean MXPsupport()
	{
		return MXPsupport;
	}

	public void setMXPSupport(boolean truefalse)
	{
		MXPsupport = truefalse;
	}

	public boolean MCCPsupport()
	{
		return MCCPsupport;
	}

	public void setMCCPSupport(boolean truefalse)
	{
		MCCPsupport = truefalse;
	}

	public boolean MSDPsupport()
	{
		return MSDPsupport;
	}

	public void setMSDPSupport(boolean truefalse)
	{
		MSDPsupport = truefalse;
	}

	public boolean GMCPsupport()
	{
		return GMCPsupport;
	}

	public void setGMCPSupport(boolean truefalse)
	{
		GMCPsupport = truefalse;
	}

	public void setNeverMXPSupport(boolean truefalse)
	{
		neverSupportMXP = truefalse;
	}

	public void setNeverMSPSupport(MSPStatus status)
	{
		neverSupportMSP = status;
	}

	public void setNeverMCCPSupport(boolean truefalse)
	{
		neverSupportMCCP = truefalse;
	}

	public void setNeverMSDPSupport(boolean truefalse)
	{
		neverSupportMSDP = truefalse;
	}

	public void setNeverGMCPSupport(boolean truefalse)
	{
		neverSupportGMCP = truefalse;
	}

	public boolean isUIonHold()
	{
		return MXPsupport() && mxpModule.isUIonHold();
	}

	private String blinkOff()
	{
		if (blinkOn)
		{
			blinkOn = false;
			return "</BLINK>";
		}
		return "";
	}

	private String underlineOff()
	{
		if (underlineOn)
		{
			underlineOn = false;
			return "</U>";
		}
		return "";
	}

	private String fontOff()
	{
		if (fontOn)
		{
			setLastBackground(defaultBackground);
			setLastForeground(defaultForeground);
			fontOn = false;
			return "</FONT>";
		}
		return "";
	}

	private String italicsOff()
	{
		if (italicsOn)
		{
			italicsOn = false;
			return "</I>";
		}
		return "";
	}

	private String allOff()
	{
		final StringBuffer off = new StringBuffer("");
		off.append(blinkOff());
		off.append(underlineOff());
		off.append(fontOff());
		off.append(italicsOff());
		return off.toString();
	}

	public String getMsdpHtml()
	{
		synchronized (msdpInforms)
		{
			if (msdpInforms.length() == 0)
				return "";
			final String bah = msdpInforms.toString();
			msdpInforms.setLength(0);
			return "<BR><PRE>" + bah + "</PRE><BR>";
		}
	}

	public String getGmcpHtml()
	{
		synchronized (gmcpInforms)
		{
			if (gmcpInforms.length() == 0)
				return "";
			final String bah = gmcpInforms.toString();
			gmcpInforms.setLength(0);
			return "<BR><PRE>" + bah + "</PRE>";
		}
	}

	public static int getColorCodeIndex(String word)
	{
		if (word == null)
			word = defaultForeground;
		for (int i = 0; i < colorCodes1.length; i++)
		{
			if (word.equalsIgnoreCase(colorCodes1[i]))
				return (40 + i);
		}
		for (int i = 0; i < colorCodes2.length; i++)
		{
			if (word.equalsIgnoreCase(colorCodes2[i]))
				return (30 + i);
		}
		return 30;
	}

	public static int getRelativeColorCodeIndex(String word)
	{
		final int x = getColorCodeIndex(word);
		if (x < 40)
			return x - 30;
		if (x > 50)
			return x % 10;
		return x - 40;
	}

	private void setLastBackground(String val)
	{
		if (MXPsupport())
			mxpModule.lastBackground = val;
		else
			lastBackground = val;
	}

	private void setLastForeground(String val)
	{
		if (MXPsupport())
			mxpModule.lastForeground = val;
		else
			lastForeground = val;
	}

	private String lastBackground()
	{
		return MXPsupport() ? mxpModule.lastBackground : lastBackground;
	}

	private String lastForeground()
	{
		return MXPsupport() ? mxpModule.lastForeground : lastForeground;
	}

	private String escapeTranslate(String escapeString)
	{
		if (escapeString.endsWith("m"))
		{
			final Vector<String> V = Util.parseSemicolons(escapeString.substring(0, escapeString.length() - 1), true);
			final StringBuffer str = new StringBuffer("");
			String s = null;
			int code = 0;
			String background = null;
			String foreground = null;
			for (int i = 0; i < V.size(); i++)
			{
				s = V.elementAt(i);
				code = Util.s0_int(s);
				switch (code)
				{
				case 0:
					if (i == (V.size() - 1))
						str.append(allOff());
					boldOn = false;
					break;
				case 1:
					boldOn = true;
					if ((V.size() == 1) && (lastForeground() != null))
						foreground = colorCodes2[getRelativeColorCodeIndex(lastForeground())];
					break;
				case 4:
				{
					if (!underlineOn)
					{
						underlineOn = true;
						str.append("<U>");
					}
					break;
				}
				case 5:
				{
					if (!blinkOn)
					{
						blinkOn = true;
						str.append("<BLINK>");
					}
					break;
				}
				case 6:
				{
					if (!italicsOn)
					{
						italicsOn = true;
						str.append("<I>");
					}
					break;
				}
				case 7:
				{
					// this is reverse on, and requires a wierd color reversal
					// from whatever the previous colors were.
					// do it later
					break;
				}
				case 8:
				{
					background = defaultBackground;
					foreground = defaultBackground;
					break;
				}
				case 22:
					str.append(allOff());
					break;
				case 24:
					str.append(underlineOff());
					break;
				case 25:
					str.append(blinkOff());
					break;
				case 26:
					str.append(italicsOff());
					break;
				case 30:
				case 31:
				case 32:
				case 33:
				case 34:
				case 35:
				case 36:
				case 37:
					foreground = boldOn ? colorCodes2[code - 30] : colorCodes1[code - 30];
					break;
				case 39:
					foreground = defaultForeground;
					break;
				case 40:
				case 41:
				case 42:
				case 43:
				case 44:
				case 45:
				case 46:
				case 47:
					background = colorCodes1[code - 40];
					break;
				case 49:
					background = defaultForeground;
					break;
				}
				if ((background != null) || (foreground != null))
				{
					if (lastBackground() == null)
						setLastBackground(defaultBackground);
					if (lastForeground() == null)
						setLastForeground(defaultForeground);
					if (background == null)
						background = lastBackground();
					if (foreground == null)
						foreground = lastForeground();

					if ((!lastBackground().equals(background)) || (!lastForeground().equals(foreground)))
					{
						str.append(fontOff());
						setLastBackground(background);
						setLastForeground(foreground);
						fontOn = true;
						if (MXPsupport())
							str.append("<FONT COLOR=" + foreground + " BACK=" + background + ">");
						else
							str.append("<FONT STYLE=\"color: " + foreground + ";background-color: " + background + "\">");
					}
				}
			}
			return str.toString();
		}
		return escapeString;
	}

	public static final char[]	mccppattern	= { IAC_, IAC_SB, MCCP_COMPRESS2, IAC_, IAC_SE };
	public int					patDex		= 0;

	public void TelnetRead(StringBuffer buf, InputStream rawin, BufferedReader in[]) throws InterruptedIOException, IOException
	{
		final char c = (char) in[0].read();
		if (mccppattern[patDex] == c)
		{
			patDex++;
			if ((patDex >= mccppattern.length) && (!neverSupportMCCP))
			{
				while (rawin.available() > 0)
					rawin.read();
				final ZInputStream zIn = new ZInputStream(rawin);
				if (debugTelnetCodes)
					System.out.println("MCCP compression started");
				in[0] = new BufferedReader(new InputStreamReader(zIn));
				patDex = 0;
			}
			return;
		}
		else 
		if (patDex > 0)
		{
			for (int i = 0; i < patDex; i++)
				buf.append(mccppattern[i]);
			patDex = 0;
		}
		buf.append(c);
		if (c == 65535)
			throw new java.io.InterruptedIOException("ARGH!");
	}

	public int TelenetFilter(StringBuffer buf, DataOutputStream response, InputStream rawin, BufferedReader[] in) throws IOException
	{
		int i = 0;
		while (i < buf.length())
		{
			switch (buf.charAt(i))
			{
			case 0:
				buf.delete(i, i + 1);
				break;
			case IAC_:
			{
				if (debugTelnetCodes)
					System.out.println("Got IAC in " + i + "/" + buf.length());
				if (i >= buf.length() - 2)
					return i;
				if (debugTelnetCodes)
					System.out.println("Receiving " + (int) buf.charAt(i + 1));
				final int oldI = i;
				int end = oldI + 3;
				switch (buf.charAt(++i))
				{
				case IAC_SB:
				{
					final ByteArrayOutputStream subOptionData = new ByteArrayOutputStream();
					final int subOptionCode = buf.charAt(++i);
					if (debugTelnetCodes)
						System.out.println("Got sub-option " + subOptionCode);
					int last = 0;
					while ((i < (buf.length() - 1)) && ((last = buf.charAt(++i)) != -1))
					{
						if ((last == IAC_) && (i < (buf.length() - 1)))
						{
							last = buf.charAt(++i);
							if (last == IAC_)
							{
								subOptionData.write(IAC_); // this is iac iac --
															// escape, dup type
															// thing?
							}
							else 
							if (last == IAC_SE)
								break;
						}
						else
							subOptionData.write((char) last);
					}
					end = i + 1;
					if (debugTelnetCodes)
						System.out.println("Got SB " + subOptionCode);
					if (subOptionCode == TELOPT_TTYPE)
					{
						if (debugTelnetCodes)
							System.out.println("Responding with termtype.");
						final byte[] data = new byte[6];
						data[0] = (short) 's';
						data[1] = (short) 'i';
						data[2] = (short) 'p';
						data[3] = (short) 'l';
						data[4] = (short) 'e';
						data[5] = (short) 't';
						response.writeBytes("" + IAC_ + IAC_SB + TELOPT_TTYPE + (char) 0);
						response.write(data);
						response.writeBytes("" + IAC_ + IAC_SE);
						response.flush();
					}
					else 
					if (subOptionCode == TELOPT_NAWS)
					{
						if (debugTelnetCodes)
							System.out.println("Responding with screen size.");
						final byte[] data = new byte[4];
						data[1] = 80;
						data[3] = 25;
						response.writeBytes("" + IAC_ + IAC_SB + TELOPT_NAWS);
						response.write(data);
						response.writeBytes("" + IAC_ + IAC_SE);
						response.flush();
					}
					else
					if (subOptionCode == MCCP_COMPRESS2)
					{
						// probably need to handle this earlier
					}
					else 
					if (subOptionCode == IAC_MSDP)
					{
						final String received = this.msdpModule.msdpReceive(subOptionData.toByteArray());
						synchronized (msdpInforms)
						{
							msdpInforms.append(received);
						}
						if (debugTelnetCodes)
							System.out.println("Got MSDP: " + received);
					}
					else 
					if (subOptionCode == IAC_GMCP)
					{
						final String received = this.gmcpModule.gmcpReceive(subOptionData.toByteArray());
						synchronized (gmcpInforms)
						{
							gmcpInforms.append(received + "\n");
						}
						if (debugTelnetCodes)
							System.out.println("Got GMCP: " + received);
					}
					break;
				}
				case IAC_WILL:
					i++;
					if (buf.charAt(i) == TELOPT_NAWS)
					{
						if (debugTelnetCodes)
							System.out.println("Responding with screen size to WILL NAWS.");
						final byte[] data = new byte[4];
						data[1] = 80;
						data[3] = 25;
						response.writeBytes("" + IAC_ + IAC_SB + TELOPT_NAWS);
						response.write(data);
						response.writeBytes("" + IAC_ + IAC_SE);
						break;
					}
					else 
					if (buf.charAt(i) == IAC_MSP)
					{
						if (debugTelnetCodes)
							System.out.println("Got WILL MSP!");
						if (neverSupportMSP == MSPStatus.Disabled)
						{
							if (MSPsupport())
							{
								if (debugTelnetCodes)
									System.out.println("Sent DONT MSP!");
								response.writeBytes("" + IAC_ + IAC_DONT + IAC_MSP);
								response.flush();
								setMSPSupport(false);
							}
						}
						else 
						if (!MSPsupport())
						{
							if (debugTelnetCodes)
								System.out.println("Sent DO MSP!");
							response.writeBytes("" + IAC_ + IAC_DO + IAC_MSP);
							response.flush();
							setMSPSupport(true);
						}
					}
					else 
					if (buf.charAt(i) == IAC_MSDP)
					{
						if (debugTelnetCodes)
							System.out.println("Got WILL MSDP!");
						if (neverSupportMSDP)
						{
							if (MSDPsupport())
							{
								if (debugTelnetCodes)
									System.out.println("Sent DONT MSDP!");
								response.writeBytes("" + IAC_ + IAC_DONT + IAC_MSDP);
								response.flush();
								setMSDPSupport(false);
							}
						}
						else 
						if (!MSDPsupport())
						{
							if (debugTelnetCodes)
								System.out.println("Sent DO MSDP!");
							response.writeBytes("" + IAC_ + IAC_DO + IAC_MSDP);
							response.flush();
							setMSDPSupport(true);
						}
					}
					else 
					if (buf.charAt(i) == IAC_GMCP)
					{
						if (debugTelnetCodes)
							System.out.println("Got WILL GMCP!");
						if (neverSupportGMCP)
						{
							if (GMCPsupport())
							{
								if (debugTelnetCodes)
									System.out.println("Sent DONT GMCP!");
								response.writeBytes("" + IAC_ + IAC_DONT + IAC_GMCP);
								response.flush();
								setGMCPSupport(false);
							}
						}
						else 
						if (!GMCPsupport())
						{
							if (debugTelnetCodes)
								System.out.println("Sent DO GMCP!");
							response.writeBytes("" + IAC_ + IAC_DO + IAC_GMCP);
							response.flush();
							setGMCPSupport(true);
							response.writeBytes("" + IAC_ + IAC_SB + IAC_GMCP);
							response.writeBytes("core.hello {\"client\":\"siplet\",\"version\":" + Siplet.VERSION_MAJOR + "}");
							response.writeBytes("" + IAC_ + IAC_SE);
						}
					}
					else 
					if (buf.charAt(i) == IAC_MXP)
					{
						if (debugTelnetCodes)
							System.out.println("Got WILL MXP!");
						if (neverSupportMXP)
						{
							if (MXPsupport())
							{
								if (debugTelnetCodes)
									System.out.println("Send DONT MXP!");
								response.writeBytes("" + IAC_ + IAC_DONT + IAC_MXP);
								response.flush();
								setMXPSupport(false);
							}
						}
						else 
						if (!MXPsupport())
						{
							if (debugTelnetCodes)
								System.out.println("Send DO MXP!");
							response.writeBytes("" + IAC_ + IAC_DO + IAC_MXP);
							response.flush();
							setMXPSupport(true);
						}
					}
					else 
					if (buf.charAt(i) == MCCP_COMPRESS2)
					{
						if (debugTelnetCodes)
							System.out.println("Got WILL COMPRESS2!");
						if (neverSupportMCCP)
						{
							if (MCCPsupport())
							{
								if (debugTelnetCodes)
									System.out.println("Send DONT COMPRESS2!");
								response.writeBytes("" + IAC_ + IAC_DONT + MCCP_COMPRESS2);
								response.flush();
								setMXPSupport(false);
							}
						}
						else 
						if (!MCCPsupport())
						{
							if (debugTelnetCodes)
								System.out.println("Send DO MCCP!");
							response.writeBytes("" + IAC_ + IAC_DO + MCCP_COMPRESS2);
							response.flush();
							setMCCPSupport(true);
						}
					}
					else 
					if (buf.charAt(i) == TELOPT_LOGOUT)
					{
						// goot for you serverdude
					}
					else 
					if (buf.charAt(i) != TELOPT_BINARY)
					{
						if (debugTelnetCodes)
							System.out.println("Sent DONT " + ((int) buf.charAt(i)) + "!");
						response.writeBytes("" + IAC_ + IAC_DONT + buf.charAt(i));
						response.flush();
					}
					break;
				case IAC_WONT:
					i++;
					if (buf.charAt(i) == IAC_MSP)
					{
						if (debugTelnetCodes)
							System.out.println("Got WONT MSP!");
						if (MSPsupport())
						{
							if (debugTelnetCodes)
								System.out.println("Sent DONT MSP!");
							response.writeBytes("" + IAC_ + IAC_DONT + IAC_MSP);
							response.flush();
							setMSPSupport(false);
						}
					}
					else 
					if (buf.charAt(i) == IAC_MSDP)
					{
						if (debugTelnetCodes)
							System.out.println("Got WONT MSDP!");
						if (MSDPsupport())
						{
							if (debugTelnetCodes)
								System.out.println("Sent DONT MSDP!");
							response.writeBytes("" + IAC_ + IAC_DONT + IAC_MSDP);
							response.flush();
							setMSDPSupport(false);
						}
					}
					else 
					if (buf.charAt(i) == IAC_GMCP)
					{
						if (debugTelnetCodes)
							System.out.println("Got WONT GMCP!");
						if (GMCPsupport())
						{
							if (debugTelnetCodes)
								System.out.println("Sent DONT GMCP!");
							response.writeBytes("" + IAC_ + IAC_DONT + IAC_GMCP);
							response.flush();
							setGMCPSupport(false);
						}
					}
					else 
					if (buf.charAt(i) == IAC_MXP)
					{
						if (debugTelnetCodes)
							System.out.println("Got WONT MXP!");
						if (MXPsupport())
						{
							if (debugTelnetCodes)
								System.out.println("Sent DONT MXP!");
							response.writeBytes("" + IAC_ + IAC_DONT + IAC_MXP);
							response.flush();
							setMXPSupport(false);
							if (mxpModule != null)
								mxpModule.shutdownMXP();
						}
					}
					break;
				case IAC_DO:
					i++;
					if (buf.charAt(i) == IAC_MSP)
					{
						if (debugTelnetCodes)
							System.out.println("Got DO MSP!");
						if (neverSupportMSP == MSPStatus.Disabled)
						{
							if (MSPsupport())
							{
								if (debugTelnetCodes)
									System.out.println("Sent WONT MSP!");
								response.writeBytes("" + IAC_ + IAC_WONT + IAC_MSP);
								response.flush();
								setMSPSupport(false);
							}
						}
						else 
						if (!MSPsupport())
						{
							if (debugTelnetCodes)
								System.out.println("Sent WILL MSP!");
							response.writeBytes("" + IAC_ + IAC_WILL + IAC_MSP);
							response.flush();
							setMSPSupport(true);
						}
					}
					else 
					if (buf.charAt(i) == IAC_GMCP)
					{
						if (debugTelnetCodes)
							System.out.println("Got DO GMCP!");
						if (neverSupportGMCP)
						{
							if (GMCPsupport())
							{
								if (debugTelnetCodes)
									System.out.println("Sent WONT GMCP!");
								response.writeBytes("" + IAC_ + IAC_WONT + IAC_GMCP);
								response.flush();
								setGMCPSupport(false);
							}
						}
						else 
						if (!GMCPsupport())
						{
							if (debugTelnetCodes)
								System.out.println("Sent WILL GMCP!");
							response.writeBytes("" + IAC_ + IAC_WILL + IAC_GMCP);
							response.flush();
							setGMCPSupport(true);
						}
					}
					else 
					if (buf.charAt(i) == TELOPT_LOGOUT)
					{
						// good for you serverdude
					}
					else 
					if (buf.charAt(i) == IAC_MXP)
					{
						if (debugTelnetCodes)
							System.out.println("Got DO MXP!");
						if (neverSupportMXP)
						{
							if (MXPsupport())
							{
								if (debugTelnetCodes)
									System.out.println("Sent WONT MXP!");
								response.writeBytes("" + IAC_ + IAC_WONT + IAC_MXP);
								response.flush();
								setMXPSupport(false);
							}
						}
						else 
						if (!MXPsupport())
						{
							response.writeBytes("" + IAC_ + IAC_WILL + IAC_MXP);
							if (debugTelnetCodes)
								System.out.println("Sent WILL MXP!");
							response.flush();
							setMXPSupport(true);
						}
					}
					else 
					if (buf.charAt(i) != TELOPT_BINARY)
					{
						if (debugTelnetCodes)
							System.out.println("Send WONT " + (int) buf.charAt(i) + "!");
						response.writeBytes("" + IAC_ + IAC_WONT + buf.charAt(i));
						response.flush();
					}
					break;
				case IAC_DONT:
					i++;
					if (buf.charAt(i) == IAC_MSP)
					{
						if (debugTelnetCodes)
							System.out.println("Got DONT MSP!");
						if (MSPsupport())
						{
							if (debugTelnetCodes)
								System.out.println("Sent WONT MSP!");
							response.writeBytes("" + IAC_ + IAC_WONT + IAC_MSP);
							response.flush();
							setMSPSupport(false);
						}
					}
					else 
					if (buf.charAt(i) == IAC_MXP)
					{
						if (MXPsupport())
						{
							if (debugTelnetCodes)
								System.out.println("Sent WONT MXP!");
							response.writeBytes("" + IAC_ + IAC_WONT + IAC_MXP);
							response.flush();
							setMXPSupport(false);
							if (mxpModule != null)
								mxpModule.shutdownMXP();
						}
					}
					break;
				case IAC_GA:
				case IAC_NOP:
					end = oldI + 2;
					break;
				}
				buf.delete(oldI, end);
				i = oldI - 1;
				break;
			}
			}
			i++;
		}
		return buf.length();
	}

	// filters out color codes -> <FONT>
	// CRS -> <BR>
	// SPACES -> &nbsp;
	// < -> &lt;
	// TELNET codes -> response outputstream
	public int HTMLFilter(StringBuffer buf)
	{
		int i = 0;
		final boolean[] eolEater = new boolean[1];
		while (i < buf.length())
		{
			if (debugChars)
				System.out.println(">" + buf.charAt(i));
			if (comment)
			{
				if (((i + 3) < buf.length()) && buf.substring(i, i + 3).equals("-->"))
				{
					comment = false;
					i += 3;
				}
			}
			else 
			if ((MXPsupport() && (mxpModule.eatTextUntilNextEOLN()) && (buf.charAt(i) != '\n') && (buf.charAt(i) != '\r')))
			{
				buf.deleteCharAt(i);
				i--;
			}
			else
				switch (buf.charAt(i))
				{
				case '!':
					if ((i < buf.length() - 3) && (buf.charAt(i + 1) == '!'))
					{
						if (MSPsupport())
						{
							final int endl = mspModule.process(buf, i, codeBase, neverSupportMSP == MSPStatus.External);
							if (endl == -1)
								i--;
							else 
							if (endl > 0)
								return endl;
						}
					}
					break;
				case '&':
				{
					if (!MXPsupport())
					{
						buf.insert(i + 1, "amp;");
						i += 4;
					}
					else
					{
						final int x = mxpModule.processEntity(buf, i, null, true);
						if (x == Integer.MAX_VALUE)
							return i;
						i += x;
					}
					break;
				}
				case ' ':
					buf.setCharAt(i, '&');
					buf.insert(i + 1, "nbsp;");
					i += 5;
					break;
				case '>':
					buf.setCharAt(i, '&');
					buf.insert(i + 1, "gt;");
					i += 3;
					break;
				case '<':
					if (!MXPsupport())
					{
						buf.setCharAt(i, '&');
						buf.insert(i + 1, "lt;");
						i += 3;
					}
					else 
					if (((i + 4) < buf.length()) && (buf.substring(i + 1, i + 4).equals("!--")))
						comment = true;
					else
					{
						final int x = mxpModule.processTag(buf, i);
						if (x == Integer.MAX_VALUE)
							return i;
						i += x;
					}
					break;
				case '\n':
				{
					if (MXPsupport())
					{
						final int x = mxpModule.newlineDetected(buf, i + 1, eolEater);
						if (eolEater[0])
							buf.deleteCharAt(i);
						else
						{
							buf.setCharAt(i, '<');
							buf.insert(i + 1, "BR>");
							i += 3;
						}
						i += x;
					}
					else
					{
						buf.setCharAt(i, '<');
						buf.insert(i + 1, "BR>");
						i += 3;
					}
					break;
				}
				case '\r':
					buf.deleteCharAt(i);
					i--;
					break;
				case IAC_:
				{
					if (i >= buf.length() - 3)
						return i;
					break;
				}
				case '\033':
				{
					final int savedI = i;
					if (i == buf.length() - 1)
						return i;
					if (buf.charAt(++i) != '[')
						buf.setCharAt(i, ' ');
					else
					{
						boolean quote = false;
						while (((++i) < buf.length()) && ((quote) || (!Character.isLetter(buf.charAt(i)))))
						{
							if (buf.charAt(i) == '"')
								quote = !quote;
						}
						if (i == buf.length())
							return savedI;
						final String oldStr = buf.substring(savedI + 2, i + 1);
						final String translate = escapeTranslate(oldStr);
						if (translate.equals(oldStr))
						{
							final int x = mxpModule.escapeTranslate(oldStr, buf, savedI);
							if (x == Integer.MAX_VALUE)
								return i;
							i = savedI + x;
						}
						else 
						if (!translate.equals(oldStr))
						{
							buf.replace(savedI, i + 1, translate);
							i = savedI + translate.length() - 1;
						}
					}
				}
					break;
				}
			i++;
		}
		return buf.length();
	}

	public final byte[] peruseInput(final String data)
	{
		if (data == null)
			return null;
		try
		{
			if (data.startsWith("\\"))
			{
				final int x = data.indexOf(' ');
				if (x < 0)
					return data.getBytes("UTF-8");
				final String cmd = data.substring(1, x).toUpperCase().trim();
				final String rest = data.substring(x + 1).trim();
				if (cmd.equalsIgnoreCase("MSDP"))
				{
					try
					{
						final byte[] newOutput = this.msdpModule.convertStringToMsdp(rest);
						if (newOutput != null)
							return newOutput;
					}
					catch (final MJSONException e)
					{
						if (debugTelnetCodes)
							System.out.println("JSON Parse Error: " + e.getMessage());
					}
					return null;
				}
				else 
				if (cmd.equalsIgnoreCase("GMCP"))
				{
					try
					{
						final byte[] newOutput = gmcpModule.convertStringToGmcp(rest);
						if (newOutput != null)
							return newOutput;
					}
					catch (final MJSONException e)
					{
						if (debugTelnetCodes)
							System.out.println("JSON Parse Error: " + e.getMessage());
					}
					return null;
				}
				else
					return data.getBytes("UTF-8");
			}
			return data.getBytes("UTF-8");
		}
		catch (final UnsupportedEncodingException e)
		{
			return data.getBytes();
		}
	}
}