Click here to Skip to main content
15,892,927 members
Articles / Multimedia / GDI+

Terminal Control Project (C# VT100 SSH Telnet)

Rate me:
Please Sign up or sign in to vote.
4.68/5 (25 votes)
14 Mar 20062 min read 322.1K   12.3K   79  
An article on implementing Telnet and SSH, and displaying it on a VT100 Terminal Emulation control created using GDI+.
using System;
using System.Collections.Specialized;
using System.Windows.Forms;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Drawing;

namespace WalburySoftware
{
	public class TerminalEmulator : Control
	{
		#region Public Properties
		public int Rows
		{
			get
			{
				return this._rows;
			}
			set
			{
			}
		}
		public int Columns
		{
			get
			{
				return this._cols;
			}
			set
			{
			}
		}
		public ConnectionTypes ConnectionType
		{
			get
			{
				return this._ConnectionType;
			}
			set
			{
				this._ConnectionType = value;
			}
		}
		public string Hostname
		{
			get
			{
				return this._hostname;
			}
			set
			{
				this._hostname = value;
			}
		}
		public string Username
		{
			get
			{
				return this._username;
			}
			set
			{
				this._username = value;
			}
		}
		public string Password
		{
			get
			{
				return this._password;
			}
			set
			{
				this._password = value;
			}
		}
		#endregion
		#region Public Methods
		public StringCollection ScreenScrape(int StartRow, int StartColumn, int EndRow, int EndColumn)
		{
			StringCollection ScrapedText = new StringCollection();


			return ScrapedText;
		}
		public void Write (byte[] data, int offset, int length)
		{
			string sReceived = Encoding.ASCII.GetString(data, offset, length);
			

			
			this.Invoke(this.RxdTextEvent, new System.String[] {System.String.Copy (sReceived)});
			this.Invoke(this.RefreshEvent);
		}
		public void Connect ()
		{
			switch (this.ConnectionType)
			{
				case ConnectionTypes.Telnet:
				{
					this.ConnectTelnet(this.Hostname);
					break;
				}
				case ConnectionTypes.SSH1:
				{
					break;
				}
				case ConnectionTypes.SSH2:
				{
					this.ConnectSSH2(this.Hostname, this.Username, this.Password);
					break;
				}
				default:
				{
					break;
				}
			}
		}
		#endregion
		#region public enums
		public enum ConnectionTypes
		{
			Telnet,
			SSH1,
			SSH2,
		}
		#endregion
		#region Fields
		private ConnectionTypes             _ConnectionType;
		private string						_hostname;       // used for connecting to SSH
		private string						_username;       // maybe
		private string						_password;
		private ContextMenu					contextMenu1;    // rightclick menu
		private MenuItem					mnuCopy;
		private MenuItem					mnuPaste;
		private MenuItem					mnuCopyPaste;
		private System.Drawing.Point		BeginDrag;       // used in Mouse Selecting Text
		private System.Drawing.Point		EndDrag;         // used in mouse selecting text
		private string						TextAtCursor;    // used to store Cursortext while scrolling
		private int							LastVisibleLine; // used for scrolling
		private System.AsyncCallback		callbackProc;
		private System.AsyncCallback		callbackEndDispatch;
		private System.Net.Sockets.Socket	CurSocket;
		private System.Boolean				XOFF    = false;
		private System.String				OutBuff = "";
		private Reader						reader;
		private int							ScrollbackBufferSize;
		private StringCollection			ScrollbackBuffer;
		private uc_Parser                    Parser         = null;
		private uc_TelnetParser              NvtParser      = null;
		private uc_Keyboard                  Keyboard       = null;
		private uc_TabStops                  TabStops       = null;
		private System.Drawing.Bitmap        EraseBitmap    = null;
		private System.Drawing.Graphics      EraseBuffer    = null;
		private System.Char[][]              CharGrid       = null;
		private CharAttribStruct[][]         AttribGrid     = null;
		private CharAttribStruct             CharAttribs;
		private System.Int32                 _cols;
		private System.Int32                 _rows;
		private System.Int32                 TopMargin;
		private System.Int32                 BottomMargin;
		private System.String                TypeFace      = FontFamily.GenericMonospace.GetName(0);
		private System.Drawing.FontStyle     TypeStyle     = System.Drawing.FontStyle.Regular;
		private System.Int32                 TypeSize      = 8;
		private System.Drawing.Size          CharSize;
		private System.Int32                 UnderlinePos; 
		private uc_Caret                     Caret;
		private System.Collections.ArrayList SavedCarets;
		private System.Drawing.Point         DrawStringOffset;
		private System.Drawing.Color         FGColor;
		private System.Drawing.Color         BoldColor;
		private System.Drawing.Color         BlinkColor;
		private uc_Chars                     G0;
		private uc_Chars                     G1;
		private uc_Chars                     G2;
		private uc_Chars                     G3;
		private  uc_Mode                      Modes;
		private uc_VertScrollBar             VertScrollBar;
		#endregion
		#region Delegates
		private delegate void NvtParserEventHandler (object Sender, NvtParserEventArgs e);
		private delegate void KeyboardEventHandler (object Sender, System.String e);
		private delegate void RefreshEventHandler ();
		private delegate void RxdTextEventHandler (System.String sReceived);
		private delegate void CaretOffEventHandler ();
		private delegate void CaretOnEventHandler ();
		private delegate void ParserEventHandler (object Sender, ParserEventArgs e);
		#endregion
		#region Events
		private event RefreshEventHandler RefreshEvent;
		private event RxdTextEventHandler RxdTextEvent;
		private event CaretOffEventHandler CaretOffEvent;
		private event CaretOnEventHandler CaretOnEvent;
		#endregion
		#region Constructors

		public TerminalEmulator ()
		{ 
		
			this.ScrollbackBufferSize = 3000;
			this.ScrollbackBuffer = new StringCollection();

			// set the display options
			this.SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer, true);

			this.Keyboard       = new uc_Keyboard (this);
			this.Parser         = new uc_Parser   ();
			this.NvtParser      = new uc_TelnetParser   ();
			this.Caret          = new uc_Caret    ();
			this.Modes          = new uc_Mode ();
			this.TabStops       = new uc_TabStops ();
			this.SavedCarets    = new System.Collections.ArrayList ();

			//this.Name       = "ACK-TERM";
			//this.Text       = "ACK-TERM";

			this.Caret.Pos  = new System.Drawing.Point (0, 0); 
			this.CharSize   = new System.Drawing.Size ();
			this.Font       = new System.Drawing.Font (this.TypeFace, this.TypeSize, this.TypeStyle);
			//this.Font       = new System.Drawing.Font(FontFamily.GenericMonospace, 8.5F);

			//this.FGColor      = System.Drawing.Color.FromArgb (200, 200, 200);
			this.FGColor      = System.Drawing.Color.GreenYellow;
			this.BackColor    = System.Drawing.Color.FromArgb (0, 0, 160);
			this.BoldColor    = System.Drawing.Color.FromArgb (255, 255, 255);
			this.BlinkColor   = System.Drawing.Color.Red;

			this.G0 = new uc_Chars (uc_Chars.Sets.ASCII);
			this.G1 = new uc_Chars (uc_Chars.Sets.ASCII);
			this.G2 = new uc_Chars (uc_Chars.Sets.DECSG);
			this.G3 = new uc_Chars (uc_Chars.Sets.DECSG);

			this.CharAttribs.GL = G0;
			this.CharAttribs.GR = G2;
			this.CharAttribs.GS = null;

			this.GetFontInfo ();

			// Create and initialize contextmenu
			this.contextMenu1 = new ContextMenu();
			this.mnuCopy = new MenuItem("Copy");
			this.mnuPaste = new MenuItem("Paste");
			this.mnuCopyPaste = new MenuItem("Copy and Paste");
			this.contextMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
																						 this.mnuCopyPaste,
																						 this.mnuPaste,
																						 this.mnuCopy});
			this.mnuCopy.Index = 0;
			this.mnuPaste.Index = 1;
			this.mnuCopyPaste.Index = 2;
			this.ContextMenu = this.contextMenu1;
			this.mnuCopy.Click += new System.EventHandler(this.mnuCopy_Click);
			this.mnuPaste.Click += new System.EventHandler(this.mnuPaste_Click);
			this.mnuCopyPaste.Click += new System.EventHandler(this.mnuCopyPaste_Click);


			// Create and initialize a VScrollBar.
			VertScrollBar = new uc_VertScrollBar();
			VertScrollBar.Scroll += new System.Windows.Forms.ScrollEventHandler(this.HandleScroll);

			// Dock the scroll bar to the right side of the form.
			VertScrollBar.Dock = System.Windows.Forms.DockStyle.Right;
    
			// Add the scroll bar to the form.
			Controls.Add (VertScrollBar);

			// create the character grid (rows by columns). This is a shadow of what's displayed
			// Set the window size to match
			this.SetSize (24, 80);

			this.Parser.ParserEvent       += new ParserEventHandler    (CommandRouter);
			this.Keyboard.KeyboardEvent   += new KeyboardEventHandler  (DispatchMessage);
			this.NvtParser.NvtParserEvent += new NvtParserEventHandler (TelnetInterpreter);
			this.RefreshEvent             += new RefreshEventHandler   (ShowBuffer);
			this.CaretOffEvent            += new CaretOffEventHandler  (this.CaretOff);
			this.CaretOnEvent             += new CaretOnEventHandler   (this.CaretOn);
			this.RxdTextEvent             += new RxdTextEventHandler   (this.NvtParser.ParseString);

			this.BeginDrag = new System.Drawing.Point();
			this.EndDrag   = new System.Drawing.Point();
			
			this.ConnectionType = ConnectionTypes.Telnet; // default
			
		}

		#endregion
		#region Overrides
		protected override void OnResize (System.EventArgs e)
		{
			this.Font       = new System.Drawing.Font (this.TypeFace, this.TypeSize, this.TypeStyle);
			// reset scrollbar values
			this.SetScrollBarValues();

			// capture text at cursor b/c it's not in the scrollback buffer yet
			string TextAtCursor = "";
			for (int x = 0; x < this._cols; x++)
			{
				char CurChar = this.CharGrid[this.Caret.Pos.Y][x];

				if (CurChar == '\0')
				{
					continue;
				}
				TextAtCursor = TextAtCursor + Convert.ToString(CurChar);
			}

			
			
			// calculate new rows and columns
			int columns = this.ClientSize.Width / this.CharSize.Width - 1;
			int rows = this.ClientSize.Height / this.CharSize.Height;

			// make sure at least 1 row and 1 col or Control will throw
			if (rows < 5)
			{
				rows = 5;
				this.Height = this.CharSize.Height * rows;
			}

			// make sure at least 1 row and 1 col or Control will throw
			if (columns < 5)
			{
				columns = 5;
				this.Width = this.CharSize.Width * columns;
			}
			
			// make sure the bottom of this doesn't exceed bottom of parent client area
			// for some reason it was getting stuck like that
			if (this.Parent != null)
				if (this.Bottom > this.Parent.ClientSize.Height)
					this.Height = this.Parent.ClientSize.Height - this.Top;

			// reset the char grid
			this.SetSize(rows, columns);

			//Console.WriteLine(Convert.ToString(rows) + " rows. " + Convert.ToString(this.ScrollbackBuffer.Count + " buffer lines"));
			
			// populate char grid from ScrollbackBuffer

			// parse through ScrollbackBuffer from the end
			// ScrollbackBuffer[0] is the "oldest" string
			// chargrid[0] is the top row on the display
			StringCollection visiblebuffer = new StringCollection();
			for (int i = this.ScrollbackBuffer.Count - 1; i >= 0; i--)
			{
				
				
				visiblebuffer.Insert(0, this.ScrollbackBuffer[i]);

				// don't parse more strings than our display can show
				if (visiblebuffer.Count >= rows - 1) // rows -1 to leave line for cursor space
					break;
			}

			int lastline  = 0;
			for (int i = 0; i < visiblebuffer.Count; i++)
			{
				//Console.WriteLine("Writing string to display: " + visiblebuffer[i]);
				for (int column = 0; column < columns; column++)
				{
					//this.CharGrid[i][column] = '0';
					if (column > visiblebuffer[i].Length - 1)
						continue;
					this.CharGrid[i][column] = visiblebuffer[i].ToCharArray()[column];

				}
				lastline = i;
			
			}

			// replace cursor text
			for (int column = 0; column < columns; column++)
			{
				if (column > TextAtCursor.Length - 1)
					continue;
				this.CharGrid[lastline+1][column] = TextAtCursor.ToCharArray()[column];
			
			}

			this.CaretToAbs(lastline+1, TextAtCursor.Length);
			this.Refresh();
			
			base.OnResize(e);
			
		}
			
		protected override void OnPaint (System.Windows.Forms.PaintEventArgs e)
		{
			e.Graphics.SmoothingMode     = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
			e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault;
			e.Graphics.TextContrast      = 0;
			e.Graphics.PixelOffsetMode   = System.Drawing.Drawing2D.PixelOffsetMode.Half;

			this.WipeScreen (e.Graphics);
			this.Redraw     (e.Graphics);
			this.ShowCaret  (e.Graphics);
		}

		protected override void OnPaintBackground (System.Windows.Forms.PaintEventArgs e)
		{
		}

		protected override void WndProc (ref System.Windows.Forms.Message m)
		{
			// Listen for operating system messages and handle the key events.
			switch (m.Msg)
			{
				case WMCodes.WM_KEYDOWN:
				case WMCodes.WM_SYSKEYDOWN:
				case WMCodes.WM_KEYUP:
				case WMCodes.WM_SYSKEYUP:
				case WMCodes.WM_SYSCHAR:
				case WMCodes.WM_CHAR:
					this.Keyboard.KeyDown (m);
					break;

				default:
					// don't do any default handling for the aforementioned events
					// this means things like keyboard shortcut events are ignored
					base.WndProc (ref m);
					break;               
			}
		}

		protected override void OnMouseMove (MouseEventArgs CurArgs)
		{
			if (CurArgs.Button != MouseButtons.Left)
				return;

			//Console.WriteLine(Convert.ToString(CurArgs.X) + "," + Convert.ToString(CurArgs.Y));
			this.EndDrag.X = CurArgs.X;
			this.EndDrag.Y = CurArgs.Y;

			int endCol = this.EndDrag.X / this.CharSize.Width;
			int endRow = this.EndDrag.Y / this.CharSize.Height;

			int begCol = this.BeginDrag.X / this.CharSize.Width;
			int begRow = this.BeginDrag.Y / this.CharSize.Height;


			// reset highlights
			for (int iRow = 0; iRow < this._rows; iRow++)
				for (int iCol = 0; iCol < this._cols; iCol++)
					this.AttribGrid[iRow][iCol].IsInverse = false;


			if (endRow < begRow) // we're parsing backwards
			{
				int i = endRow;
				endRow = begRow;
				begRow = i;
				for (int curRow = begRow; curRow <= endRow; curRow++)
				{
					if (curRow <= 0)
						continue;

					for (int curCol = 0; curCol < this._cols; curCol++)
					{
						// don't select if nothing is there
						if (this.CharGrid[curRow][curCol] == '\0')
							continue;

						// on first row, make sure we start at begCol
						if (curRow == begRow && curCol < endCol)
							continue;		
						
						// on last row, don't pass the end col
						if (curRow == endRow && curCol == begCol)
						{
							this.AttribGrid[curRow][curCol].IsInverse = true;
							break;
						}

						this.AttribGrid[curRow][curCol].IsInverse = true;
					}
				}
				this.Refresh();
				return;
			}

			if (endCol < begCol && begRow == endRow) // we're parsing backwards, but only on one row
			{
				int i = endCol;
				endCol = begCol;
				begCol = i;
			}

			// parse the rows affected and highlight them
			// endRow/endCol are where the mouse is now
			// begRow/begCol are where the mouse was when the button was pushed
			for (int curRow = begRow; curRow <= endRow; curRow++)
			{
				if (curRow >= this._rows)
					break;

				for (int curCol = 0; curCol < this._cols; curCol++)
				{			
					// don't select if nothing is there
					if (this.CharGrid[curRow][curCol] == '\0')
						continue;

					// on first row, make sure we start at begCol
					if (curRow == begRow && curCol < begCol)
						continue;		

					// on last row, don't pass the end col
					if (curRow == endRow && curCol == endCol)
					{
						this.AttribGrid[curRow][curCol].IsInverse = true;
						break;
					}
					this.AttribGrid[curRow][curCol].IsInverse = true;
				}
			}
			this.Refresh();
		}
		
		protected override void OnMouseUp (MouseEventArgs CurArgs)
		{
			if (CurArgs.Button == System.Windows.Forms.MouseButtons.Left)
			{

				if (this.BeginDrag.X == CurArgs.X && this.BeginDrag.Y == CurArgs.Y)
				{	// reset highlights
					for (int iRow = 0; iRow < this._rows; iRow++)
						for (int iCol = 0; iCol < this._cols; iCol++)
							this.AttribGrid[iRow][iCol].IsInverse = false;
					this.Refresh();
				}				
			}
		
		}

		protected override void OnMouseDown (System.Windows.Forms.MouseEventArgs CurArgs)
		{
			this.Focus();
			
			//Font tmp      = new System.Drawing.Font(FontFamily.GenericMonospace, 8.5F);
			//Graphics g = this.CreateGraphics();
			//g.DrawString("the quick brown fox jumps over the lazy dog", this.Font,Brushes.GreenYellow, 0,0);
			//g.DrawString("*******************************************", tmp,Brushes.GreenYellow, 0,0);
			//g.DrawString("This system is private and may only be accessed if authorized.", this.Font,Brushes.GreenYellow, 0,0);
			
			//
			//if (CurArgs.Button == System.Windows.Forms.MouseButtons.Right)
			//{
			//	// Get the clipboard text
			//	System.Windows.Forms.IDataObject CurDataObject = System.Windows.Forms.Clipboard.GetDataObject ();
			  
			//	if(CurDataObject.GetDataPresent (System.Windows.Forms.DataFormats.Text)) 
			//	{
			//		if (CurDataObject.GetData (System.Windows.Forms.DataFormats.Text) != null)
			//		{
			//			this.DispatchMessage (
			//				this, 
			//				CurDataObject.GetData (System.Windows.Forms.DataFormats.Text).ToString ()); 
			//		}
			//	}
			//}
 
			if (CurArgs.Button == System.Windows.Forms.MouseButtons.Left)
			{
				// begin select
				this.BeginDrag.X = CurArgs.X;
				this.BeginDrag.Y = CurArgs.Y;
			}
			
			
			base.OnMouseDown (CurArgs);
		}

		protected override void OnFontChanged (EventArgs e)
		{
			//MessageBox.Show(this.Font.Name + " " + Convert.ToString(this.Font.Size));


		}
		#endregion
		#region Private Methods
		private void ConnectTelnet(string HostName)
		{
			this.Focus();

			System.Int32           port    = 23;
			//System.Net.IPHostEntry IPHost  = System.Net.Dns.GetHostEntry(HostName); 
			System.Net.IPHostEntry IPHost = System.Net.Dns.GetHostByName(HostName);
			System.Net.IPAddress[] addr    = IPHost.AddressList; 
        
			try
			{
				// Create New Socket 
				this.CurSocket = new System.Net.Sockets.Socket (
					System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, 
					System.Net.Sockets.ProtocolType.Tcp);

				// Create New EndPoint
				System.Net.IPEndPoint iep  = new System.Net.IPEndPoint(addr[0],port);  

				// This is a non blocking IO
				this.CurSocket.Blocking        = false ;    

				// Begin Asyncronous Connection
				this.CurSocket.BeginConnect (iep,  new System.AsyncCallback (ConnectCallback), CurSocket) ;                
			}
			catch (System.Exception CurException)
			{
				//System.Console.WriteLine ("Connect: " + CurException.Message);
				MessageBox.Show(CurException.Message);
			}
		}
		private void ConnectSSH2(string hostname, string username, string password)
		{
			// connect ssh
			this.Focus();
			Routrek.SSHC.SSHConnection _conn;
			Routrek.SSHC.SSHConnectionParameter f = new Routrek.SSHC.SSHConnectionParameter();
			f.UserName = username;
			f.Password = password;
			f.Protocol = Routrek.SSHC.SSHProtocol.SSH2;
			
			f.AuthenticationType = Routrek.SSHC.AuthenticationType.Password;
			f.WindowSize = 0x1000;
			this.reader = new Reader(this);
			Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			//s.Blocking = false;
			IPAddress ip;
			try
			{
				ip = Dns.GetHostByName(hostname).AddressList[0];
			}
			catch
			{
				MessageBox.Show("Unable to resolve HostName");
				return;
			}

			//s.Connect(new IPEndPoint(IPAddress.Parse("0.0.0.0"), 22));
			s.Connect(new IPEndPoint(ip, 22));
			_conn = Routrek.SSHC.SSHConnection.Connect(f, reader, s);
			reader._conn = _conn;
			Routrek.SSHC.SSHChannel ch = _conn.OpenShell(reader);
			reader._pf = ch;
			Routrek.SSHC.SSHConnectionInfo ci = _conn.ConnectionInfo;
		}
		private void mnuCopy_Click (object sender, System.EventArgs e)
		{
			Point start = new Point();
			Point stop  = new Point();
			bool FoundStart = false;
			bool FoundStop = false;

			// find coordinates of Highlighted Text
			for (int row = 0; row < this._rows; row++)
			{
				for (int col = 0; col < this._cols; col++)
				{
					if (FoundStart == false && this.AttribGrid[row][col].IsInverse == true)
					{
						start.X = col;
						start.Y = row;
						FoundStart = true;
					}

					// this next check will first find the first non-inverse coord with a
					// character in it. If it happens to be at the beginning of a line, 
					// then we'll back up and stop at the last char in the prev line
					if (FoundStart == true && 
						FoundStop == false && 
						this.AttribGrid[row][col].IsInverse == false &&
						this.CharGrid[row][col] != '\0'
						)
					{
						stop.X = col - 1;
						stop.Y = row;
						FoundStop = true;
						// here we back up if col == 0
						if (col == 0)
						{
							// make sure we don't have a null row
							// this shouldn't throw
							row--;
							while (this.CharGrid[row][0] == '\0')
								row--;
							for (col = 0; col < this._cols; col++) // parse the row
							{
								if (this.CharGrid[row][col] == '\0') // we found the end
								{
									stop.X = col - 1;
									stop.Y = row;
								}
							}
						}
						break;
					}

					if (FoundStop == true && FoundStart == true)
						break;
				} // column parse
				// if we get to this point without finding a match, and we're on the last row
				// we should include the last row and stop here
				if (FoundStart == true && FoundStop == false && row == this._rows -1)
				{
					for (int col = 0; col < this._cols; col++) // parse the row
					{
						if (this.CharGrid[row][col] == '\0') // we found the end
						{
							stop.X = col - 1;
							stop.Y = row;
						}
					}
				}
			} // row parse
			Console.WriteLine("start.Y " + Convert.ToString(start.Y) +
				             " start.X " + Convert.ToString(start.X) +
				             " stop.Y "  + Convert.ToString(stop.Y)  +
				             " stop.X "  + Convert.ToString(stop.X));

			StringCollection sc = this.ScreenScrape (start.Y, start.X, stop.Y, stop.X);
			foreach (string s in sc)
			{
				Console.WriteLine(s);
			}

		}
		private void mnuPaste_Click (object sender, System.EventArgs e)
		{}
		private void mnuCopyPaste_Click (object sender, System.EventArgs e)
		{}
		private void HandleScroll(Object sender, ScrollEventArgs se)
		{
			// capture text at cursor
			if (this.Caret.IsOff)
			{
			}
			else
			{
				this.TextAtCursor = "";
				for (int x = 0; x < this._cols; x++)
				{
					char CurChar = this.CharGrid[this.Caret.Pos.Y][x];
					if (CurChar == '\0')
					{
						continue;
					}
					this.TextAtCursor = this.TextAtCursor + Convert.ToString(CurChar);
				}
			}
	
			switch (se.Type)
			{
				case ScrollEventType.SmallIncrement: // down
					this.LastVisibleLine += 1;
					break;
				case ScrollEventType.SmallDecrement: // up
					this.LastVisibleLine += -1;
					break;
				default:
					return;
			}

			// make sure we don't set LastVisibleLine past the end of the StringCollection
			// LastVisibleLine is relative to the last line in the StringCollection
			// 0 is the Last element
			if (this.LastVisibleLine > 0)
			{
				this.LastVisibleLine = 0;
			}

			if (this.LastVisibleLine < (0 - this.ScrollbackBuffer.Count) + (this._rows))
			{
				this.LastVisibleLine = (0 - this.ScrollbackBuffer.Count) + (this._rows)-1;
			}


			int columns = this._cols;
			int rows    = this._rows;
			
			this.SetSize(rows, columns);

			StringCollection visiblebuffer = new StringCollection();
			for (int i = this.ScrollbackBuffer.Count - 1 + this.LastVisibleLine; i >= 0; i--)
			{
				visiblebuffer.Insert(0, this.ScrollbackBuffer[i]);

				// don't parse more strings than our display can show
				if (visiblebuffer.Count >= rows - 1) // rows -1 to leave line for cursor space
					break;
			}

			//int lastline = (0 - this.ScrollbackBuffer.Count) + (this.Rows);
			//int lastline = this.LastVisibleLine;
			for (int i = 0; i < visiblebuffer.Count; i++)
			{
				//Console.WriteLine("Writing string to display: " + visiblebuffer[i]);
				for (int column = 0; column < columns; column++)
				{
					//this.CharGrid[i][column] = '0';
					if (column > visiblebuffer[i].Length - 1)
						continue;
					this.CharGrid[i][column] = visiblebuffer[i].ToCharArray()[column];

				}
				// if we're displaying the last line in scrollbackbuffer, then
				// replace the cursor and the text on the cursor line
				//System.Console.WriteLine(Convert.ToString(lastline) + " " + Convert.ToString(this.ScrollbackBuffer.Count));
				if (this.LastVisibleLine == 0)
				{
					this.CaretOn();
					//this.CaretToAbs(0,0);
					for (int column = 0; column < this._cols; column++)
					{
						if (column > this.TextAtCursor.Length - 1)
							continue;
						this.CharGrid[this._rows - 1][column] = this.TextAtCursor.ToCharArray()[column];
					}
					this.CaretToAbs(this._rows - 1, this.TextAtCursor.Length);
				}
				else
				{
					this.CaretOff();
				}
			}

			this.Refresh();
		}
		private void SetScrollBarValues()
		{
			// Set the Maximum, Minimum, LargeChange and SmallChange properties.
			this.VertScrollBar.Minimum = 0;
			
			// if the scrollbackbuffer is empty, there's nothing to scroll
			if (this.ScrollbackBuffer.Count == 0)
			{
				this.VertScrollBar.Maximum = 0;
				return;
			}

			// If the offset does not make the Maximum less than zero, set its value.    
			if ((this.ScrollbackBuffer.Count * this.CharSize.Height) - this.Height > 0)
			{

				this.VertScrollBar.Maximum = this.ScrollbackBuffer.Count * this.CharSize.Height - this.Height;
			}

			// If the HScrollBar is visible, adjust the Maximum of the 
			// VSCrollBar to account for the width of the HScrollBar.
			//if(this.hScrollBar1.Visible)
			//{
			//	this.vScrollBar1.Maximum += this.hScrollBar1.Height;
			//}
			this.VertScrollBar.LargeChange = this.VertScrollBar.Maximum / this.CharSize.Height * 10;
			this.VertScrollBar.SmallChange = this.VertScrollBar.Maximum / this.CharSize.Height;
			// Adjust the Maximum value to make the raw Maximum value 
			// attainable by user interaction.
			this.VertScrollBar.Maximum += this.VertScrollBar.LargeChange;

		}
		private void ConnectCallback (System.IAsyncResult ar)
		{
			try
			{
				// Get The connection socket from the callback
				System.Net.Sockets.Socket sock1 = (System.Net.Sockets.Socket) ar.AsyncState;

				if (sock1.Connected) 
				{
					uc_CommsStateObject StateObject = new uc_CommsStateObject ();

					StateObject.Socket = sock1;
    
					// Assign Callback function to read from Asyncronous Socket
					callbackProc = new System.AsyncCallback (OnReceivedData);

					// Begin reading data asyncronously
					sock1.BeginReceive (StateObject.Buffer, 0, StateObject.Buffer.Length, 
						System.Net.Sockets.SocketFlags.None, callbackProc, StateObject);
				}
			}

			catch (System.Exception CurException)
			{
				//System.Console.WriteLine ("ConnectCallback: " + CurException.Message);
				MessageBox.Show(CurException.Message);
			}
		}

		private void OnReceivedData (System.IAsyncResult ar)
		{
			// Get The connection socket from the callback
			uc_CommsStateObject StateObject = (uc_CommsStateObject) ar.AsyncState;

			// Get The data , if any
			int nBytesRec = StateObject.Socket.EndReceive (ar);        

			if ( nBytesRec > 0 )
			{
				string sReceived = "";

				for (int i = 0; i < nBytesRec; i++)
				{
					sReceived += System.Convert.ToChar (StateObject.Buffer[i]).ToString ();
				}

				this.Invoke (this.RxdTextEvent, new System.String[] {System.String.Copy (sReceived)});
				this.Invoke (this.RefreshEvent);

				// Re-Establish the next asyncronous receveived data callback as
				StateObject.Socket.BeginReceive (StateObject.Buffer, 0, StateObject.Buffer.Length, 
					System.Net.Sockets.SocketFlags.None, new System.AsyncCallback (OnReceivedData) , StateObject);
			}
			else
			{
				// If no data was recieved then the connection is probably dead
				//System.Console.WriteLine ("Disconnected", StateObject.Socket.RemoteEndPoint);

				StateObject.Socket.Shutdown (System.Net.Sockets.SocketShutdown.Both);

				StateObject.Socket.Close ();
			}
		}
		
		private void DispatchMessage (System.Object sender, string strText)
		{
			//Console.WriteLine(strText);
			if (this.XOFF == true)
			{
				// store the characters in the outputbuffer
				OutBuff += strText;
				return;
			}

			int i = 0;

			try
			{
				System.Byte[] smk = new System.Byte[strText.Length];

				if (OutBuff != "")
				{
					strText = OutBuff + strText;
					OutBuff = "";
				}

				for (i=0; i < strText.Length ; i++)
				{
					System.Byte ss = System.Convert.ToByte (strText[i]);
					smk[i] = ss ;
				}

				if (callbackEndDispatch == null)
				{
					callbackEndDispatch = new System.AsyncCallback (EndDispatchMessage);
				}

				if (this.CurSocket == null)
				{
					try
					{
						reader._pf.Transmit(smk);
					}
					catch
					{
						MessageBox.Show("error communicating with socket");
					}				
				}
				else
				{
					try
					{
						System.IAsyncResult ar = this.CurSocket.BeginSend (
							smk, 
							0, 
							smk.Length, 
							System.Net.Sockets.SocketFlags.None, 
							callbackEndDispatch, 
							this.CurSocket);
					}
					catch
					{
						MessageBox.Show("error communicating with socket");
					}
				}

			}
			catch (System.Exception CurException)
			{
				//System.Console.WriteLine ("DispatchMessage: " + CurException.Message);
				//System.Console.WriteLine ("DispatchMessage: Character is " + System.Convert.ToInt32 (strText[i]));
				//System.Console.WriteLine ("DispatchMessage: String is " + strText);
				MessageBox.Show("DispatchMessage: " + CurException.Message);
				MessageBox.Show("DispatchMessage: Character is " + System.Convert.ToInt32 (strText[i]));
				MessageBox.Show("DispatchMessage: String is " + strText);
			}
		}

		private void EndDispatchMessage (System.IAsyncResult ar)
		{
			try
			{
				System.Net.Sockets.Socket Sock =  (System.Net.Sockets.Socket) ar.AsyncState;

				Sock.EndSend (ar);
			}
			catch (System.Exception CurException)
			{
				//System.Console.WriteLine ("EndDispatchMessage: " + CurException.Message);
				MessageBox.Show("EndDispatchMessage: " + CurException.Message);
			}
		}		
		private void PrintChar (System.Char CurChar)
		{
			if (this.Caret.EOL == true)
			{
				if ((this.Modes.Flags & uc_Mode.AutoWrap) == uc_Mode.AutoWrap)
				{
					this.LineFeed ();
					this.CarriageReturn ();
					this.Caret.EOL = false;
				}
			}

			System.Int32 X = this.Caret.Pos.X;
			System.Int32 Y = this.Caret.Pos.Y;

			this.AttribGrid[Y][X] = this.CharAttribs;

			if (this.CharAttribs.GS != null)
			{
				CurChar = uc_Chars.Get (CurChar, this.AttribGrid[Y][X].GS.Set, this.AttribGrid[Y][X].GR.Set);

				if (this.CharAttribs.GS.Set == uc_Chars.Sets.DECSG) this.AttribGrid[Y][X].IsDECSG = true;

				this.CharAttribs.GS = null;
			}
			else
			{
				CurChar = uc_Chars.Get (CurChar, this.AttribGrid[Y][X].GL.Set, this.AttribGrid[Y][X].GR.Set);

				if (this.CharAttribs.GL.Set == uc_Chars.Sets.DECSG) this.AttribGrid[Y][X].IsDECSG = true;
			}   

			this.CharGrid[Y][X] = CurChar;

			this.CaretRight ();
		}

		private System.Drawing.Point GetDrawStringOffset (System.Drawing.Graphics CurGraphics, System.Int32 X, System.Int32 Y, System.Char CurChar)
		{
			// DrawString doesn't actually print where you tell it to but instead consistently prints
			// with an offset. This is annoying when the other draw commands do not print with an offset
			// this method returns a point defining the offset so we can take it off the printstring command.

			System.Drawing.CharacterRange[] characterRanges =
		   {
			   new System.Drawing.CharacterRange(0, 1)
		   };
 
			System.Drawing.RectangleF layoutRect = new System.Drawing.RectangleF (X, Y, 100, 100);

			System.Drawing.StringFormat stringFormat = new System.Drawing.StringFormat();

			stringFormat.SetMeasurableCharacterRanges(characterRanges);

			System.Drawing.Region[] stringRegions = new System.Drawing.Region[1];

			stringRegions = CurGraphics.MeasureCharacterRanges(
				CurChar.ToString (),
				this.Font,
				layoutRect,
				stringFormat);

			System.Drawing.RectangleF measureRect1 = stringRegions[0].GetBounds (CurGraphics);

			return new System.Drawing.Point ((int) (measureRect1.X + 0.5), (int) (measureRect1.Y + 0.5));
		}
        
		private System.Drawing.Point GetCharSize (System.Drawing.Graphics CurGraphics)
		{
			// DrawString doesn't actually print where you tell it to but instead consistently prints
			// with an offset. This is annoying when the other draw commands do not print with an offset
			// this method returns a point defining the offset so we can take it off the printstring command.

			System.Drawing.CharacterRange[] characterRanges =
		   {
			   new System.Drawing.CharacterRange(0, 1)
		   };
 
			System.Drawing.RectangleF layoutRect = new System.Drawing.RectangleF (0, 0, 100, 100);

			System.Drawing.StringFormat stringFormat = new System.Drawing.StringFormat();

			stringFormat.SetMeasurableCharacterRanges(characterRanges);

			System.Drawing.Region[] stringRegions = new System.Drawing.Region[1];

			stringRegions = CurGraphics.MeasureCharacterRanges(
				"A",
				this.Font,
				layoutRect,
				stringFormat);

			System.Drawing.RectangleF measureRect1 = stringRegions[0].GetBounds (CurGraphics);

			return new System.Drawing.Point ((int) (measureRect1.Width + 0.5), (int) (measureRect1.Height + 0.5));
		}

		private void AssignColors (CharAttribStruct CurAttribs, ref System.Drawing.Color CurFGColor, ref System.Drawing.Color CurBGColor)
		{

			CurFGColor = this.FGColor; 
			CurBGColor = this.BackColor;

			if (CurAttribs.IsBlinking == true)
			{
				CurFGColor = this.BlinkColor;
			}

			// bold takes precedence over the blink color
			if (CurAttribs.IsBold == true)
			{
				CurFGColor = this.BoldColor;
			}

			if (CurAttribs.UseAltColor == true)
			{
				CurFGColor = CurAttribs.AltColor;
			}

			// alternate color takes precedence over the bold color
			if (CurAttribs.UseAltBGColor == true)
			{
				CurBGColor = CurAttribs.AltBGColor;
			}

			if (CurAttribs.IsInverse == true)
			{
				System.Drawing.Color TmpColor = CurBGColor;

				CurBGColor = CurFGColor;
				CurFGColor = TmpColor;
			}

			// If light background is on and we're not using alt colors
			// reverse the colors
			if ((this.Modes.Flags & uc_Mode.LightBackground) > 0 &&
				CurAttribs.UseAltColor == false && CurAttribs.UseAltBGColor == false)
			{

				System.Drawing.Color TmpColor = CurBGColor;

				CurBGColor = CurFGColor;
				CurFGColor = TmpColor;
			}
		}

		private void ShowChar (System.Drawing.Graphics CurGraphics, System.Char CurChar, System.Int32 Y, System.Int32 X, CharAttribStruct CurAttribs)
		{
			if (CurChar == '\0')
			{
				return;
			}

			System.Drawing.Color CurFGColor = System.Drawing.Color.White; 
			System.Drawing.Color CurBGColor = System.Drawing.Color.Black;

			this.AssignColors (CurAttribs, ref CurFGColor, ref CurBGColor);

			if ((CurBGColor != this.BackColor && (this.Modes.Flags & uc_Mode.LightBackground) == 0) ||
				(CurBGColor != this.FGColor   && (this.Modes.Flags & uc_Mode.LightBackground) > 0))
			{

				// Erase the current Character underneath the cursor postion
				this.EraseBuffer.Clear (CurBGColor);

				// paint a rectangle over the cursor position in the character's BGColor
				CurGraphics.DrawImageUnscaled (
					this.EraseBitmap, 
					X, 
					Y);
			}

			if (CurAttribs.IsUnderscored)
			{
				CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
					X,                       Y + this.UnderlinePos,   
					X + this.CharSize.Width, Y + this.UnderlinePos);
			}   

			if ((CurAttribs.IsDECSG == true) &&
				(CurChar == 'l' ||
				CurChar == 'q' ||
				CurChar == 'w' ||
				CurChar == 'k' ||
				CurChar == 'x' ||
				CurChar == 't' ||
				CurChar == 'n' ||
				CurChar == 'u' ||
				CurChar == 'm' ||
				CurChar == 'v' ||
				CurChar == 'j' ||
				CurChar == '`'))
			{
				this.ShowSpecialChar (
					CurGraphics,
					CurChar, 
					Y,
					X,
					CurFGColor,
					CurBGColor);

				return;               
			}

			CurGraphics.DrawString (
				CurChar.ToString (), 
				this.Font, 
				new System.Drawing.SolidBrush (CurFGColor),
				X - this.DrawStringOffset.X,
				Y - this.DrawStringOffset.Y);

		}

		private void ShowSpecialChar (System.Drawing.Graphics CurGraphics, System.Char CurChar, System.Int32 Y, System.Int32 X, System.Drawing.Color CurFGColor, System.Drawing.Color CurBGColor)
		{
			if (CurChar == '\0')
			{
				return;
			}

			switch (CurChar)
			{
				case '`': // diamond
					System.Drawing.Point[] CurPoints = new System.Drawing.Point[4];

					CurPoints[0] = new System.Drawing.Point (X + this.CharSize.Width/2, Y + this.CharSize.Height/6);
					CurPoints[1] = new System.Drawing.Point (X + 5*this.CharSize.Width/6, Y + this.CharSize.Height/2);
					CurPoints[2] = new System.Drawing.Point (X + this.CharSize.Width/2, Y + 5*this.CharSize.Height/6);
					CurPoints[3] = new System.Drawing.Point (X + this.CharSize.Width/6, Y + this.CharSize.Height/2);

					CurGraphics.FillPolygon (
						new System.Drawing.SolidBrush (CurFGColor),
						CurPoints);   
					break;

				case 'l': // top left bracket
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X + this.CharSize.Width/2 -1,   Y + this.CharSize.Height/2,   
						X + this.CharSize.Width,     Y + this.CharSize.Height/2);
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X + this.CharSize.Width/2,   Y + this.CharSize.Height/2,   
						X + this.CharSize.Width/2,   Y + this.CharSize.Height);
					break;

				case 'q': // horizontal line
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X,                           Y + this.CharSize.Height/2,   
						X + this.CharSize.Width,     Y + this.CharSize.Height/2);
					break;

				case 'w': // top tee-piece
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X,                         Y + this.CharSize.Height/2,   
						X + this.CharSize.Width,   Y + this.CharSize.Height/2);
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X + this.CharSize.Width/2, Y + this.CharSize.Height/2,   
						X + this.CharSize.Width/2, Y + this.CharSize.Height);
					break;

				case 'k': // top right bracket
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X,                         Y + this.CharSize.Height/2,   
						X + this.CharSize.Width/2, Y + this.CharSize.Height/2);
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X + this.CharSize.Width/2, Y + this.CharSize.Height/2,   
						X + this.CharSize.Width/2, Y + this.CharSize.Height);
					break;

				case 'x': // vertical line
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X + this.CharSize.Width/2, Y,   
						X + this.CharSize.Width/2, Y + this.CharSize.Height);
					break;

				case 't': // left hand tee-piece
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X + this.CharSize.Width/2, Y,   
						X + this.CharSize.Width/2, Y + this.CharSize.Height);
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X + this.CharSize.Width/2, Y + this.CharSize.Height/2,   
						X + this.CharSize.Width,   Y + this.CharSize.Height/2);
					break;

				case 'n': // cross piece
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X + this.CharSize.Width/2, Y,   
						X + this.CharSize.Width/2, Y + this.CharSize.Height);
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X,                         Y + this.CharSize.Height/2,   
						X + this.CharSize.Width,   Y + this.CharSize.Height/2);
					break;

				case 'u': // right hand tee-piece
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X,                         Y + this.CharSize.Height/2,   
						X + this.CharSize.Width/2, Y + this.CharSize.Height/2);
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X + this.CharSize.Width/2, Y,   
						X + this.CharSize.Width/2, Y + this.CharSize.Height);
					break;

				case 'm': // bottom left bracket
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X + this.CharSize.Width/2, Y + this.CharSize.Height/2,   
						X + this.CharSize.Width,   Y + this.CharSize.Height/2);
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X + this.CharSize.Width/2, Y,   
						X + this.CharSize.Width/2, Y + this.CharSize.Height/2);
					break;

				case 'v': // bottom tee-piece
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X,                         Y + this.CharSize.Height/2,   
						X + this.CharSize.Width,   Y + this.CharSize.Height/2);
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X + this.CharSize.Width/2, Y,   
						X + this.CharSize.Width/2, Y + this.CharSize.Height/2);
					break;

				case 'j': // bottom right bracket
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X,                         Y + this.CharSize.Height/2,   
						X + this.CharSize.Width/2, Y + this.CharSize.Height/2);
					CurGraphics.DrawLine (new System.Drawing.Pen (CurFGColor, 1),
						X + this.CharSize.Width/2, Y,   
						X + this.CharSize.Width/2, Y + this.CharSize.Height/2);
					break;

				default:
					break;
			}

		}

		private void WipeScreen (System.Drawing.Graphics CurGraphics)
		{
			// clear the screen buffer area
			if ((this.Modes.Flags & uc_Mode.LightBackground) > 0)
			{
				CurGraphics.Clear (this.FGColor);
			}
			else
			{
				CurGraphics.Clear (this.BackColor);
			}
		}

		private void ClearDown (System.Int32 Param)
		{
			System.Int32 X = this.Caret.Pos.X;
			System.Int32 Y = this.Caret.Pos.Y;

			switch (Param)
			{
				case 0: // from cursor to bottom inclusive

					System.Array.Clear (this.CharGrid[Y],   X, this.CharGrid[Y].Length   - X);
					System.Array.Clear (this.AttribGrid[Y], X, this.AttribGrid[Y].Length - X);

					for (int i = Y + 1; i < this._rows; i++)
					{
						System.Array.Clear (this.CharGrid[i],   0, this.CharGrid[i].Length);
						System.Array.Clear (this.AttribGrid[i], 0, this.AttribGrid[i].Length);
					}
					break;

				case 1: // from top to cursor inclusive

					System.Array.Clear (this.CharGrid[Y],   0, X + 1);
					System.Array.Clear (this.AttribGrid[Y], 0, X + 1);

					for (int i = 0; i < Y; i++)
					{
						System.Array.Clear (this.CharGrid[i],   0, this.CharGrid[i].Length);
						System.Array.Clear (this.AttribGrid[i], 0, this.AttribGrid[i].Length);
					}
					break;

				case 2: // entire screen

					for (int i = 0; i < this._rows; i++)
					{
						System.Array.Clear (this.CharGrid[i],   0, this.CharGrid[i].Length);
						System.Array.Clear (this.AttribGrid[i], 0, this.AttribGrid[i].Length);
					}
					break;

				default:
					break;
			}
		}

		private void ClearRight (System.Int32 Param)
		{
			System.Int32 X = this.Caret.Pos.X;
			System.Int32 Y = this.Caret.Pos.Y;

			switch (Param)
			{
				case 0: // from cursor to end of line inclusive

					System.Array.Clear (this.CharGrid[Y],   X, this.CharGrid[Y].Length   - X);
					System.Array.Clear (this.AttribGrid[Y], X, this.AttribGrid[Y].Length - X);
					break;

				case 1: // from beginning to cursor inclusive
					System.Array.Clear (this.CharGrid[Y],   0, X + 1);
					System.Array.Clear (this.AttribGrid[Y], 0, X + 1);
					break;

				case 2: // entire line
					System.Array.Clear (this.CharGrid[Y],   0, this.CharGrid[Y].Length);
					System.Array.Clear (this.AttribGrid[Y], 0, this.AttribGrid[Y].Length);
					break;

				default:
					break;
			}
		}

		private void ShowBuffer ()
		{
			this.Invalidate ();
		}

		private void Redraw (System.Drawing.Graphics CurGraphics)
		{
			System.Drawing.Point CurPoint;

			System.Char CurChar;


			// refresh the screen
			for (System.Int32 Y = 0; Y < this._rows; Y++)
			{
				for (System.Int32 X = 0; X < this._cols; X++)
				{
					CurChar = this.CharGrid[Y][X];

					if (CurChar == '\0')
					{
						continue;
					}

					CurPoint = new System.Drawing.Point (
						X * this.CharSize.Width,
						Y * this.CharSize.Height);

					this.ShowChar (
						CurGraphics,
						CurChar, 
						CurPoint.Y,
						CurPoint.X,
						this.AttribGrid[Y][X]);		
				}
				
			} 
		}		

		private void NvtSendWill (System.Char CurChar)
		{
			DispatchMessage (this, "\xFF\xFB" + CurChar.ToString ());
		}

		private void NvtSendWont (System.Char CurChar)
		{
			DispatchMessage (this, "\xFF\xFC" + CurChar.ToString ());
		}

		private void NvtSendDont (System.Char CurChar)
		{
			DispatchMessage (this, "\xFF\xFE" + CurChar.ToString ());
		}

		private void NvtSendDo (System.Char CurChar)
		{
			DispatchMessage (this, "\xFF\xFD" + CurChar.ToString ());
		}

		private void NvtSendSubNeg (System.Char CurChar, System.String CurString)
		{
			DispatchMessage (this, "\xFF\xFA" + CurChar.ToString () + "\x00" + CurString + "\xFF\xF0");
		}

		private void NvtExecuteChar (System.Char CurChar)
		{
			switch (CurChar)
			{
				default:
					//System.Console.WriteLine ("Telnet command {0} encountered", CurChar);
					break;
			}
		}            	
		private void TelnetInterpreter (object Sender, NvtParserEventArgs e)
		{
			switch (e.Action)
			{
				case NvtActions.SendUp:
					this.Parser.ParseString (e.CurChar.ToString ());
					break;
				case NvtActions.Execute:
					this.NvtExecuteChar (e.CurChar);
					break;
				default:
					break;
			}

			// if the sequence is a DO message
			if (e.CurSequence.StartsWith ("\xFD"))
			{
				System.Char CurCmd = System.Convert.ToChar (e.CurSequence.Substring (1, 1));

				switch (CurCmd)
				{
						// 24 - terminal type 
					case '\x18':
						NvtSendWill (CurCmd);
						break;

					default:
						NvtSendWont (CurCmd);
						//System.Console.Write ("unsupported telnet DO sequence {0} happened\n", 
						//System.Convert.ToInt32 (System.Convert.ToChar (e.CurSequence.Substring (1,1))));
						break;
				}
			}

			// if the sequence is a WILL message
			if (e.CurSequence.StartsWith ("\xFB"))
			{
				System.Char CurCmd = System.Convert.ToChar (e.CurSequence.Substring (1, 1));

				switch (CurCmd)
				{
					case '\x01': // echo
						NvtSendDo (CurCmd);
						break;

					default:
						NvtSendDont (CurCmd);
						//System.Console.Write ("unsupported telnet WILL sequence {0} happened\n", 
						//System.Convert.ToInt32 (System.Convert.ToChar (e.CurSequence.Substring (1,1))));
						break;
				}
			}

			// if the sequence is a SUBNEGOTIATE message
			if (e.CurSequence.StartsWith ("\xFA"))
			{
				if (e.CurSequence[2] != '\x01')
				{
					// not interested in data from host just yet as we don't ask for it at the moment
					return;
				}

				System.Char CurCmd = System.Convert.ToChar (e.CurSequence.Substring (1, 1));

				switch (CurCmd)
				{
						// 24 - terminal type 
					case '\x18':
						NvtSendSubNeg (CurCmd, "vt220");
						break;

					default:
						NvtSendSubNeg (CurCmd, "");
						System.Console.Write ("unsupported telnet SUBNEG sequence {0} happened\n", 
							System.Convert.ToInt32 (System.Convert.ToChar (e.CurSequence.Substring (1,1))));
						break;
				}
			}
		}

		private void CarriageReturn () 
		{
			this.CaretToAbs (this.Caret.Pos.Y, 0);
		}

		private void Tab () 
		{
			for (System.Int32 i = 0; i < this.TabStops.Columns.Length; i++)
			{
				if (i > this.Caret.Pos.X && this.TabStops.Columns[i]  == true)
				{
					this.CaretToAbs (this.Caret.Pos.Y, i);
					return;
				}
			}

			this.CaretToAbs (this.Caret.Pos.Y, this._cols -1);
			return;
		}

		private void TabSet ()
		{
			this.TabStops.Columns[this.Caret.Pos.X] = true;
		}

		private void ClearTabs (uc_Params CurParams) // TBC 
		{
			System.Int32 Param = 0;

			if (CurParams.Count () > 0)
			{
				Param = System.Convert.ToInt32 (CurParams.Elements[0]);
			}

			switch (Param)
			{
				case 0: // Current Position
					this.TabStops.Columns[this.Caret.Pos.X] = false;
					break;

				case 3: // All Tabs
					for (int i = 0; i < this.TabStops.Columns.Length; i++)
					{
						this.TabStops.Columns[i] = false;
					}
					break;

				default:
					break;
			}
		}

		private void ReverseLineFeed ()
		{

			// if we're at the top of the scroll region (top margin)
			if (this.Caret.Pos.Y == this.TopMargin)
			{
				// we need to add a new line at the top of the screen margin
				// so shift all the rows in the scroll region down in the array and
				// insert a new row at the top
                
				int i;

   
				for (i = this.BottomMargin; i > this.TopMargin; i--)
				{
					this.CharGrid[i]   = this.CharGrid[i - 1];
					this.AttribGrid[i] = this.AttribGrid[i - 1];
				}

				this.CharGrid[this.TopMargin] = new System.Char[this._cols];

				this.AttribGrid[this.TopMargin] = new CharAttribStruct[this._cols];
			}

			this.CaretUp ();
		}

		private void InsertLine (uc_Params CurParams)
		{

			// if we're not in the scroll region then bail
			if (this.Caret.Pos.Y < this.TopMargin ||
				this.Caret.Pos.Y > this.BottomMargin)
			{
				return;
			}

			System.Int32 NbrOff = 1;

			if (CurParams.Count () > 0)
			{
				NbrOff = System.Convert.ToInt32 (CurParams.Elements[0]);
			}

			while (NbrOff > 0)
			{ 

				// Shift all the rows from the current row to the bottom margin down one place
				for (int i = this.BottomMargin; i > this.Caret.Pos.Y; i--)
				{
					this.CharGrid[i]   = this.CharGrid[i - 1];
					this.AttribGrid[i] = this.AttribGrid[i - 1];
				}
                 

				this.CharGrid[this.Caret.Pos.Y]   = new System.Char[this._cols];
				this.AttribGrid[this.Caret.Pos.Y] = new CharAttribStruct[this._cols];

				NbrOff--;
			}

		}

		private void DeleteLine (uc_Params CurParams)
		{
			// if we're not in the scroll region then bail
			if (this.Caret.Pos.Y < this.TopMargin ||
				this.Caret.Pos.Y > this.BottomMargin)
			{
				return;
			}

			System.Int32 NbrOff = 1;

			if (CurParams.Count () > 0)
			{
				NbrOff = System.Convert.ToInt32 (CurParams.Elements[0]);
			}

			while (NbrOff > 0)
			{ 

				// Shift all the rows from below the current row to the bottom margin up one place
				for (int i = this.Caret.Pos.Y; i < this.BottomMargin; i++)
				{
					this.CharGrid[i]   = this.CharGrid[i + 1];
					this.AttribGrid[i] = this.AttribGrid[i + 1];
				}

				this.CharGrid[this.BottomMargin]   = new System.Char[this._cols];
				this.AttribGrid[this.BottomMargin] = new CharAttribStruct[this._cols];

				NbrOff--;
			}
		}

		private void LineFeed ()
		{
			this.SetScrollBarValues();

			// capture the new line into the scrollback buffer
			if (this.ScrollbackBuffer.Count < this.ScrollbackBufferSize)
			{
				
			}
			else 
			{
				this.ScrollbackBuffer.RemoveAt(0);
			}


			string s = "";
			for (int x = 0; x < this._cols; x++)
			{
				char CurChar = this.CharGrid[this.Caret.Pos.Y][x];

				if (CurChar == '\0')
				{
					continue;
				}
				s = s + Convert.ToString(CurChar);
			}
			this.ScrollbackBuffer.Add(s);
			//System.Console.WriteLine("there are " + Convert.ToString(this.ScrollbackBuffer.Count) + " lines in the scrollback buffer");
			//System.Console.WriteLine(s);



			if (this.Caret.Pos.Y == this.BottomMargin || this.Caret.Pos.Y == this._rows - 1)
			{
				// we need to add a new line so shift all the rows up in the array and
				// insert a new row at the bottom
                
				int i;

				for (i = this.TopMargin; i < this.BottomMargin; i++)
				{
					this.CharGrid[i]   = this.CharGrid[i + 1];
					this.AttribGrid[i] = this.AttribGrid[i + 1];
				}

				this.CharGrid[i]   = new System.Char[this._cols];
				this.AttribGrid[i] = new CharAttribStruct[this._cols];

			}

			this.CaretDown ();




		}

		private void Index (System.Int32 Param)
		{
			if (Param == 0) Param = 1;

			for (int i = 0; i < Param; i++)
			{
				this.LineFeed ();
			}
		}

		private void ReverseIndex (System.Int32 Param)
		{
			if (Param == 0) Param = 1;

			for (int i = 0; i < Param; i++)
			{
				this.ReverseLineFeed ();
			}
		}

		private void CaretOff ()
		{
			if (this.Caret.IsOff == true)
			{
				return;
			}

			this.Caret.IsOff = true;
		}

		private void CaretOn ()
		{
			if (this.Caret.IsOff == false)
			{
				return;
			}

			this.Caret.IsOff = false;

		}

		private void ShowCaret (System.Drawing.Graphics CurGraphics)
		{
			System.Int32 X = this.Caret.Pos.X;
			System.Int32 Y = this.Caret.Pos.Y;

			if (this.Caret.IsOff == true)
			{
				return;
			}

			// paint a rectangle over the cursor position
			CurGraphics.DrawImageUnscaled (
				this.Caret.Bitmap, 
				X * (int) this.CharSize.Width, 
				Y * (int) this.CharSize.Height);

			// if we don't have a char to redraw then leave
			if (this.CharGrid[Y][X] == '\0')
			{
				return;
			}

			CharAttribStruct CurAttribs = new CharAttribStruct ();

			CurAttribs.UseAltColor = true;

			CurAttribs.GL = this.AttribGrid[Y][X].GL;
			CurAttribs.GR = this.AttribGrid[Y][X].GR;
			CurAttribs.GS = this.AttribGrid[Y][X].GS;

			if (this.AttribGrid[Y][X].UseAltBGColor == false)
			{
				CurAttribs.AltColor = this.BackColor;
			}
			else if (this.AttribGrid[Y][X].UseAltBGColor == true)
			{
				CurAttribs.AltColor = this.AttribGrid[Y][X].AltBGColor;
			}

			CurAttribs.IsUnderscored = this.AttribGrid[Y][X].IsUnderscored;
			CurAttribs.IsDECSG       = this.AttribGrid[Y][X].IsDECSG;
 
			// redispay the current char in the background colour
			this.ShowChar (
				CurGraphics,
				this.CharGrid[Y][X], 
				Caret.Pos.Y * this.CharSize.Height,
				Caret.Pos.X * this.CharSize.Width,
				CurAttribs);
		}

		private void CaretUp ()
		{
			this.Caret.EOL = false;

			if ((this.Caret.Pos.Y > 0              && (this.Modes.Flags & uc_Mode.OriginRelative) == 0) ||
				(this.Caret.Pos.Y > this.TopMargin && (this.Modes.Flags & uc_Mode.OriginRelative) >  0))
			{
				this.Caret.Pos.Y -= 1;
			}
		}

		private void CaretDown ()
		{
			this.Caret.EOL = false;

			if ((this.Caret.Pos.Y < this._rows - 1     && (this.Modes.Flags & uc_Mode.OriginRelative) == 0) ||
				(this.Caret.Pos.Y < this.BottomMargin && (this.Modes.Flags & uc_Mode.OriginRelative)  > 0))
			{
				this.Caret.Pos.Y += 1;
			}
		}

		private void CaretLeft ()
		{
			this.Caret.EOL = false;

			if (this.Caret.Pos.X > 0)
			{
				this.Caret.Pos.X -= 1;
			}
		}

		private void CaretRight ()
		{
			if (this.Caret.Pos.X < this._cols - 1)
			{
				this.Caret.Pos.X += 1;
				this.Caret.EOL = false;
			}
			else
			{
				this.Caret.EOL = true;
			}
		}

		private void CaretToRel (System.Int32 Y, System.Int32 X) 
		{
 
			this.Caret.EOL = false;
			/* This code is used when we get a cursor position command from
				   the host. Even if we're not in relative mode we use this as this will
				   sort that out for us. The ToAbs code is used internally by this prog 
				   but is smart enough to stay within the margins if the originrelative 
				   flagis set. */

			if ((this.Modes.Flags & uc_Mode.OriginRelative) == 0)
			{
				this.CaretToAbs (Y, X);
				return;
			}

			/* the origin mode is relative so add the top and left margin
				   to Y and X respectively */
			Y += this.TopMargin;

			if (X < 0)
			{
				X = 0;
			}

			if (X > this._cols - 1)
			{
				X = this._cols - 1;
			}
 
			if (Y < this.TopMargin)
			{
				Y = this.TopMargin;
			}

			if (Y > this.BottomMargin)
			{
				Y = this.BottomMargin;
			}

			this.Caret.Pos.Y = Y;
			this.Caret.Pos.X = X;
		}

		private void CaretToAbs (System.Int32 Y, System.Int32 X)
		{ 
			this.Caret.EOL = false;

			if (X < 0)
			{
				X = 0;
			}

			if (X > this._cols - 1)
			{
				X = this._cols - 1;
			}

			if (Y < 0 && (this.Modes.Flags & uc_Mode.OriginRelative) == 0)
			{
				Y = 0;
			}

			if (Y < this.TopMargin && (this.Modes.Flags & uc_Mode.OriginRelative) > 0)
			{
				Y = this.TopMargin;
			}

			if (Y > this._rows - 1 && (this.Modes.Flags & uc_Mode.OriginRelative) == 0)
			{
				Y = this._rows - 1;
			}

			if (Y > this.BottomMargin && (this.Modes.Flags & uc_Mode.OriginRelative) > 0)
			{
				Y = this.BottomMargin;
			}

			this.Caret.Pos.Y = Y;
			this.Caret.Pos.X = X;
		}

		private void CommandRouter (object Sender, ParserEventArgs e)
		{


			switch (e.Action)
			{
				case Actions.Print:
					this.PrintChar (e.CurChar);
					//System.Console.Write ("{0}", e.CurChar);
					break;

				case Actions.Execute:
					this.ExecuteChar (e.CurChar);
					break;

				case Actions.Dispatch:
					break;

				default:
					break;
			}

			System.Int32 Param = 0;

			System.Int32 Inc = 1; // increment

			switch (e.CurSequence)
			{
				case "":
					break;

				case "\x1b" + "7": //DECSC Save Cursor position and attributes
					this.SavedCarets.Add (new uc_CaretAttribs (
						this.Caret.Pos,
						this.G0.Set, 
						this.G1.Set, 
						this.G2.Set, 
						this.G3.Set, 
						this.CharAttribs));
                                              
					break;

				case "\x1b" + "8": //DECRC Restore Cursor position and attributes
					this.Caret.Pos   = ((uc_CaretAttribs) this.SavedCarets[this.SavedCarets.Count - 1]).Pos;
					this.CharAttribs = ((uc_CaretAttribs) this.SavedCarets[this.SavedCarets.Count - 1]).Attribs;

					this.G0.Set = ((uc_CaretAttribs) this.SavedCarets[this.SavedCarets.Count - 1]).G0Set;
					this.G1.Set = ((uc_CaretAttribs) this.SavedCarets[this.SavedCarets.Count - 1]).G1Set;
					this.G2.Set = ((uc_CaretAttribs) this.SavedCarets[this.SavedCarets.Count - 1]).G2Set;
					this.G3.Set = ((uc_CaretAttribs) this.SavedCarets[this.SavedCarets.Count - 1]).G3Set;

					this.SavedCarets.RemoveAt (this.SavedCarets.Count - 1);

					break;

				case "\x1b~": //LS1R Locking Shift G1 -> GR
					this.CharAttribs.GR = G1;
					break;

				case "\x1bn": //LS2 Locking Shift G2 -> GL
					this.CharAttribs.GL = G2;
					break;

				case "\x1b}": //LS2R Locking Shift G2 -> GR
					this.CharAttribs.GR = G2;
					break;

				case "\x1bo": //LS3 Locking Shift G3 -> GL
					this.CharAttribs.GL = G3;
					break;

				case "\x1b|": //LS3R Locking Shift G3 -> GR
					this.CharAttribs.GR = G3;
					break;

				case "\x1b#8": //DECALN
					e.CurParams.Elements.Add ("1");
					e.CurParams.Elements.Add (this._rows.ToString ());
					this.SetScrollRegion (e.CurParams);

					// put E's on the entire screen
					for (int y = 0; y < this._rows; y++)
					{
						this.CaretToAbs (y, 0);

						for (int x = 0; x < this._cols; x++)
						{
							this.PrintChar ('E');
						}
					}
					break; 

				case "\x1b=": // Keypad to Application mode
					this.Modes.Flags = this.Modes.Flags | uc_Mode.KeypadAppln;
					break;

				case "\x1b>": // Keypad to Numeric mode
					this.Modes.Flags = this.Modes.Flags ^ uc_Mode.KeypadAppln;
					break;

				case "\x1b[B": // CUD

					if (e.CurParams.Count () > 0) 
					{
						Inc = System.Convert.ToInt32 (e.CurParams.Elements[0]); 
					}

					if (Inc == 0) Inc = 1;

					this.CaretToAbs (this.Caret.Pos.Y + Inc, this.Caret.Pos.X);
					break;

				case "\x1b[A": // CUU

					if (e.CurParams.Count () > 0) 
					{
						Inc = System.Convert.ToInt32 (e.CurParams.Elements[0]); 
					}

					if (Inc == 0) Inc = 1;

					this.CaretToAbs (this.Caret.Pos.Y - Inc, this.Caret.Pos.X);
					break;

				case "\x1b[C": // CUF

					if (e.CurParams.Count () > 0) 
					{
						Inc = System.Convert.ToInt32 (e.CurParams.Elements[0]); 
					}

					if (Inc == 0) Inc = 1;

					this.CaretToAbs (this.Caret.Pos.Y, this.Caret.Pos.X + Inc);
					break;

				case "\x1b[D": // CUB

					if (e.CurParams.Count () > 0) 
					{
						Inc = System.Convert.ToInt32 (e.CurParams.Elements[0]); 
					}

					if (Inc == 0) Inc = 1;

					this.CaretToAbs (this.Caret.Pos.Y, this.Caret.Pos.X - Inc);
					break;

				case "\x1b[H": // CUP
				case "\x1b[f": // HVP

					System.Int32 X = 0;
					System.Int32 Y = 0;

					if (e.CurParams.Count () > 0) 
					{
						Y = System.Convert.ToInt32 (e.CurParams.Elements[0]) - 1; 
					}

					if (e.CurParams.Count () > 1)
					{
						X = System.Convert.ToInt32 (e.CurParams.Elements[1]) - 1;
					}

					this.CaretToRel (Y, X);
					break;

				case "\x1b[J":

					if (e.CurParams.Count () > 0) 
					{
						Param = System.Convert.ToInt32 (e.CurParams.Elements[0]); 
					}

					this.ClearDown (Param);
					break;

				case "\x1b[K":

					if (e.CurParams.Count () > 0) 
					{
						Param = System.Convert.ToInt32 (e.CurParams.Elements[0]); 
					}

					this.ClearRight (Param);
					break;

				case "\x1b[L": // INSERT LINE
					this.InsertLine (e.CurParams);
					break;

				case "\x1b[M": // DELETE LINE
					this.DeleteLine (e.CurParams);
					break;

				case "\x1bN": // SS2 Single Shift (G2 -> GL)
					this.CharAttribs.GS = this.G2;
					break;

				case "\x1bO": // SS3 Single Shift (G3 -> GL)
					this.CharAttribs.GS = this.G3;
					//System.Console.WriteLine ("SS3: GS = {0}", this.CharAttribs.GS);
					break;

				case "\x1b[m":
					this.SetCharAttribs (e.CurParams);
					break;

				case "\x1b[?h":
					this.SetqmhMode (e.CurParams);
					break;

				case "\x1b[?l":
					this.SetqmlMode (e.CurParams);
					break;

				case "\x1b[c": // DA Device Attributes
					//                    this.DispatchMessage (this, "\x1b[?64;1;2;6;7;8;9c");
					this.DispatchMessage (this, "\x1b[?6c");
					break;

				case "\x1b[g":
					this.ClearTabs (e.CurParams);
					break;

				case "\x1b[h":
					this.SethMode (e.CurParams);
					break;

				case "\x1b[l":
					this.SetlMode (e.CurParams);
					break;

				case "\x1b[r": // DECSTBM Set Top and Bottom Margins
					this.SetScrollRegion (e.CurParams);
					break;

				case "\x1b[t": // DECSLPP Set Lines Per Page

					if (e.CurParams.Count () > 0) 
					{
						Param = System.Convert.ToInt32 (e.CurParams.Elements[0]); 
					}

					if (Param > 0) this.SetSize (Param, this._cols);

					break;

				case "\x1b" + "D": // IND

					if (e.CurParams.Count () > 0) 
					{
						Param = System.Convert.ToInt32 (e.CurParams.Elements[0]); 
					}

					this.Index (Param);
					break;

				case "\x1b" + "E": // NEL
					this.LineFeed ();
					this.CarriageReturn ();
					break;

				case "\x1bH": // HTS
					this.TabSet ();
					break;

				case "\x1bM": // RI
					if (e.CurParams.Count () > 0) 
					{
						Param = System.Convert.ToInt32 (e.CurParams.Elements[0]); 
					}

					this.ReverseIndex (Param);
					break;

				default:
					//System.Console.Write ("unsupported VT sequence {0} happened\n", e.CurSequence);
					break;
                
			}

			if (e.CurSequence.StartsWith ("\x1b("))
			{
				this.SelectCharSet (ref this.G0.Set, e.CurSequence.Substring (2));
			}
			else if (e.CurSequence.StartsWith ("\x1b-") ||
				e.CurSequence.StartsWith ("\x1b)"))
			{
				this.SelectCharSet (ref this.G1.Set, e.CurSequence.Substring (2));
			}
			else if (e.CurSequence.StartsWith ("\x1b.") ||
				e.CurSequence.StartsWith ("\x1b*"))
			{
				this.SelectCharSet (ref this.G2.Set, e.CurSequence.Substring (2));
			}
			else if (e.CurSequence.StartsWith ("\x1b/") ||
				e.CurSequence.StartsWith ("\x1b+"))
			{
				this.SelectCharSet (ref this.G3.Set, e.CurSequence.Substring (2));
			}
		}

		private void SelectCharSet (ref uc_Chars.Sets CurTarget, System.String CurString)
		{
			switch (CurString)
			{
				case "B":
					CurTarget = uc_Chars.Sets.ASCII;
					break;

				case "%5":
					CurTarget = uc_Chars.Sets.DECS;
					break;

				case "0":
					CurTarget = uc_Chars.Sets.DECSG;
					break;

				case ">":
					CurTarget = uc_Chars.Sets.DECTECH;
					break;

				case "<":
					CurTarget = uc_Chars.Sets.DECSG;
					break;

				case "A":
					if ((this.Modes.Flags & uc_Mode.National) == 0)
					{
						CurTarget = uc_Chars.Sets.ISOLatin1S;
					}
					else
					{
						CurTarget = uc_Chars.Sets.NRCUK;
					}
					break;

				case "4":
					//                    CurTarget = uc_Chars.Sets.NRCDutch;
					break;

				case "5":
					CurTarget = uc_Chars.Sets.NRCFinnish;
					break;

				case "R":
					CurTarget = uc_Chars.Sets.NRCFrench;
					break;

				case "9":
					CurTarget = uc_Chars.Sets.NRCFrenchCanadian;
					break;

				case "K":
					CurTarget = uc_Chars.Sets.NRCGerman;
					break;

				case "Y":
					CurTarget = uc_Chars.Sets.NRCItalian;
					break;

				case "6":
					CurTarget = uc_Chars.Sets.NRCNorDanish;
					break;

				case "'":
					CurTarget = uc_Chars.Sets.NRCNorDanish;
					break;

				case "%6":
					CurTarget = uc_Chars.Sets.NRCPortuguese;
					break;

				case "Z":
					CurTarget = uc_Chars.Sets.NRCSpanish;
					break;

				case "7":
					CurTarget = uc_Chars.Sets.NRCSwedish;
					break;

				case "=":
					CurTarget = uc_Chars.Sets.NRCSwiss;
					break;

				default:
					break;
			}
		}

		private void SetqmhMode (uc_Params CurParams) // set mode for ESC?h command
		{
			System.Int32 OptInt = 0;

			foreach (System.String CurOption in CurParams.Elements)
			{
				try 
				{
					OptInt = System.Convert.ToInt32 (CurOption);
				}
				catch (System.Exception CurException)
				{
					//System.Console.WriteLine (CurException.Message);
					MessageBox.Show(CurException.Message);
				}

				switch (OptInt) 
				{
					case 1: // set cursor keys to application mode
						this.Modes.Flags = this.Modes.Flags | uc_Mode.CursorAppln;
						break;

					case 2: // lock the keyboard
						this.Modes.Flags = this.Modes.Flags | uc_Mode.Locked;
						break;

					case 3: // set terminal to 132 column mode
						this.SetSize (this._rows, 132);
						break;

					case 5: // Light Background Mode
						this.Modes.Flags = this.Modes.Flags | uc_Mode.LightBackground;
						this.RefreshEvent ();
						break;

					case 6: // Origin Mode Relative
						this.Modes.Flags = this.Modes.Flags | uc_Mode.OriginRelative;
						this.CaretToRel (0, 0);
						break;

					case 7: // Autowrap On
						this.Modes.Flags = this.Modes.Flags | uc_Mode.AutoWrap;
						break;

					case 8: // AutoRepeat On
						this.Modes.Flags = this.Modes.Flags | uc_Mode.Repeat;
						break;

					case 42: // DECNRCM Multinational Charset
						this.Modes.Flags = this.Modes.Flags | uc_Mode.National;
						break;

					case 66: // Numeric Keypad Application Mode On
						this.Modes.Flags = this.Modes.Flags | uc_Mode.KeypadAppln;
						break;

					default:
						break;
				} 
			}
		}

		private void SetqmlMode (uc_Params CurParams) // set mode for ESC?l command
		{
			System.Int32 OptInt = 0;

			foreach (System.String CurOption in CurParams.Elements)
			{
				try 
				{
					OptInt = System.Convert.ToInt32 (CurOption);
				}
				catch (System.Exception CurException)
				{
					//System.Console.WriteLine (CurException.Message);
					MessageBox.Show(CurException.Message);
				}

				switch (OptInt) 
				{
					case 1: // set cursor keys to normal cursor mode
						this.Modes.Flags = this.Modes.Flags & ~uc_Mode.CursorAppln;
						break;

					case 2: // unlock the keyboard
						this.Modes.Flags = this.Modes.Flags & ~uc_Mode.Locked;
						break;

					case 3: // set terminal to 80 column mode
						this.SetSize (this._rows, 80);
						break;

					case 5: // Dark Background Mode
						this.Modes.Flags = this.Modes.Flags & ~uc_Mode.LightBackground;
						this.RefreshEvent ();
						break;

					case 6: // Origin Mode Absolute
						this.Modes.Flags = this.Modes.Flags & ~uc_Mode.OriginRelative;
						this.CaretToAbs (0, 0);
						break;

					case 7: // Autowrap Off
						this.Modes.Flags = this.Modes.Flags & ~uc_Mode.AutoWrap;
						break;

					case 8: // AutoRepeat Off
						this.Modes.Flags = this.Modes.Flags & ~uc_Mode.Repeat;
						break;

					case 42: // DECNRCM National Charset
						this.Modes.Flags = this.Modes.Flags & ~uc_Mode.National;
						break;

					case 66: // Numeric Keypad Application Mode On
						this.Modes.Flags = this.Modes.Flags & ~uc_Mode.KeypadAppln;
						break;

					default:
						break;
				} 
			}
		}

		private void SethMode (uc_Params CurParams) // set mode for ESC?h command
		{
			System.Int32 OptInt = 0;

			foreach (System.String CurOption in CurParams.Elements)
			{
				try 
				{
					OptInt = System.Convert.ToInt32 (CurOption);
				}
				catch (System.Exception CurException)
				{
					//System.Console.WriteLine (CurException.Message);
					MessageBox.Show(CurException.Message);
				}

				switch (OptInt) 
				{
					case 1: // set local echo off
						this.Modes.Flags = this.Modes.Flags | uc_Mode.LocalEchoOff;
						break;

					default:
						break;
				} 
			}
		}

		private void SetlMode (uc_Params CurParams) // set mode for ESC?l command
		{
			System.Int32 OptInt = 0;

			foreach (System.String CurOption in CurParams.Elements)
			{
				try 
				{
					OptInt = System.Convert.ToInt32 (CurOption);
				}
				catch (System.Exception CurException)
				{
					//System.Console.WriteLine (CurException.Message);
					MessageBox.Show(CurException.Message);
				}

				switch (OptInt) 
				{
					case 1: // set LocalEcho on
						this.Modes.Flags = this.Modes.Flags & ~uc_Mode.LocalEchoOff;
						break;

					default:
						break;
				} 
			}
		}

		private void SetScrollRegion (uc_Params CurParams)
		{
			if (CurParams.Count () > 0) 
			{
				this.TopMargin = System.Convert.ToInt32 (CurParams.Elements[0]) - 1; 
			}

			if (CurParams.Count () > 1)
			{
				this.BottomMargin = System.Convert.ToInt32 (CurParams.Elements[1]) - 1;
			}

			if (this.BottomMargin == 0)
			{
				this.BottomMargin = this._rows - 1;
			}

			if (this.TopMargin < 0)
			{
				this.BottomMargin = 0;
			}
		}

		private void ClearCharAttribs ()
		{
			this.CharAttribs.IsBold          = false;
			this.CharAttribs.IsDim           = false;
			this.CharAttribs.IsUnderscored   = false;
			this.CharAttribs.IsBlinking      = false;
			this.CharAttribs.IsInverse       = false;
			this.CharAttribs.IsPrimaryFont   = false;
			this.CharAttribs.IsAlternateFont = false;
			this.CharAttribs.UseAltBGColor   = false;
			this.CharAttribs.UseAltColor     = false;
			this.CharAttribs.AltColor        = System.Drawing.Color.White;
			this.CharAttribs.AltBGColor      = System.Drawing.Color.Black;
		}

		private void SetCharAttribs (uc_Params CurParams)
		{
			if (CurParams.Count () < 1)
			{
				this.ClearCharAttribs ();
				return;
			}

			for (int i = 0; i < CurParams.Count (); i++)
			{  
				switch (System.Convert.ToInt32 (CurParams.Elements[i]))
				{
					case 0:
						this.ClearCharAttribs ();
						break;

					case 1:
						this.CharAttribs.IsBold = true;
						break;

					case 4:
						this.CharAttribs.IsUnderscored = true;
						break;

					case 5:
						this.CharAttribs.IsBlinking = true;
						break;

					case 7:
						this.CharAttribs.IsInverse = true;
						break;

					case 22:
						this.CharAttribs.IsBold = false;
						break;

					case 24:
						this.CharAttribs.IsUnderscored = false;
						break;

					case 25:
						this.CharAttribs.IsBlinking = false;
						break;

					case 27:
						this.CharAttribs.IsInverse = false;
						break;

					case 30:
						this.CharAttribs.UseAltColor = true;
						this.CharAttribs.AltColor = System.Drawing.Color.Black;
						break;

					case 31:
						this.CharAttribs.UseAltColor = true;
						this.CharAttribs.AltColor = System.Drawing.Color.Red;
						break;

					case 32:
						this.CharAttribs.UseAltColor = true;
						this.CharAttribs.AltColor = System.Drawing.Color.Green;
						break;

					case 33:
						this.CharAttribs.UseAltColor = true;
						this.CharAttribs.AltColor = System.Drawing.Color.Yellow;
						break;

					case 34:
						this.CharAttribs.UseAltColor = true;
						this.CharAttribs.AltColor = System.Drawing.Color.Blue;
						break;

					case 35:
						this.CharAttribs.UseAltColor = true;
						this.CharAttribs.AltColor = System.Drawing.Color.Magenta;
						break;

					case 36:
						this.CharAttribs.UseAltColor = true;
						this.CharAttribs.AltColor = System.Drawing.Color.Cyan;
						break;

					case 37:
						this.CharAttribs.UseAltColor = true;
						this.CharAttribs.AltColor = System.Drawing.Color.White;
						break;

					case 40:
						this.CharAttribs.UseAltBGColor = true;
						this.CharAttribs.AltBGColor = System.Drawing.Color.Black;
						break;

					case 41:
						this.CharAttribs.UseAltBGColor = true;
						this.CharAttribs.AltBGColor = System.Drawing.Color.Red;
						break;

					case 42:
						this.CharAttribs.UseAltBGColor = true;
						this.CharAttribs.AltBGColor = System.Drawing.Color.Green;
						break;

					case 43:
						this.CharAttribs.UseAltBGColor = true;
						this.CharAttribs.AltBGColor = System.Drawing.Color.Yellow;
						break;

					case 44:
						this.CharAttribs.UseAltBGColor = true;
						this.CharAttribs.AltBGColor = System.Drawing.Color.Blue;
						break;

					case 45:
						this.CharAttribs.UseAltBGColor = true;
						this.CharAttribs.AltBGColor = System.Drawing.Color.Magenta;
						break;

					case 46:
						this.CharAttribs.UseAltBGColor = true;
						this.CharAttribs.AltBGColor = System.Drawing.Color.Cyan;
						break;

					case 47:
						this.CharAttribs.UseAltBGColor = true;
						this.CharAttribs.AltBGColor = System.Drawing.Color.White;
						break;

					default:
						break;
				}
			}                            
		}

		private void ExecuteChar (System.Char CurChar)
		{
			switch (CurChar)
			{
				case '\x05': // ENQ request for the answerback message
					this.DispatchMessage (this, "vt220");
					break;

				case '\x07': // BEL ring my bell
					// this.BELL;
					break;

				case '\x08': // BS back space
					this.CaretLeft ();
					break;

				case '\x09': // HT Horizontal Tab
					this.Tab ();
					break;

				case '\x0A': // LF  LineFeed
				case '\x0B': // VT  VerticalTab
				case '\x0C': // FF  FormFeed
				case '\x84': // IND Index
					this.LineFeed ();
					break;

				case '\x0D': // CR CarriageReturn
					this.CarriageReturn ();
					break;

				case '\x0E': // SO maps G1 into GL
					this.CharAttribs.GL = this.G1;
					break;

				case '\x0F': // SI maps G0 into GL
					this.CharAttribs.GL = this.G0;
					break;

				case '\x11': // DC1/XON continue sending characters
					this.XOFF = false;
					this.DispatchMessage (this, "");
					break;                    

				case '\x13': // DC3/XOFF stop sending characters
					this.XOFF = true;
					break;                    

				case '\x85': // NEL Next line (same as line feed and carriage return)
					this.LineFeed ();
					this.CaretToAbs (this.Caret.Pos.Y, 0);
					break;

				case '\x88': // HTS Horizontal tab set 
					this.TabSet ();
					break;

				case '\x8D': // RI Reverse Index 
					this.ReverseLineFeed ();
					break;

				case '\x8E': // SS2 Single Shift (G2 -> GL)
					this.CharAttribs.GS = this.G2;
					break;

				case '\x8F': // SS3 Single Shift (G3 -> GL)
					this.CharAttribs.GS = this.G3;
					break;

				default:
					break;
			}
		}            		
		
		private void SetSize (System.Int32 Rows, System.Int32 Columns)
		{
			this._rows    = Rows;
			this._cols = Columns;

			this.TopMargin    = 0;
			this.BottomMargin = Rows - 1;

			//this.ClientSize = new System.Drawing.Size (
			//	System.Convert.ToInt32 (this.CharSize.Width  * this.Columns + 2) + this.VertScrollBar.Width,
			//	System.Convert.ToInt32 (this.CharSize.Height * this.Rows    + 2));

			// create the character grid (rows by columns) this is a shadow of what's displayed
			this.CharGrid = new System.Char[Rows][];

			this.Caret.Pos.X = 0;
			this.Caret.Pos.Y = 0;

			for (int i = 0; i < this.CharGrid.Length; i++)
			{
				this.CharGrid[i]   = new System.Char[Columns];
			}

			this.AttribGrid = new CharAttribStruct[Rows][];

			for (int i = 0; i < this.AttribGrid.Length; i++)
			{
				this.AttribGrid[i]   = new CharAttribStruct[Columns];
			}
		}

		private void GetFontInfo ()
		{
			System.Drawing.Graphics tmpGraphics = this.CreateGraphics ();

			// get the offset that the moron Graphics.Drawstring method adds by default
			this.DrawStringOffset = this.GetDrawStringOffset (tmpGraphics, 0, 0, 'A');

			// get the size of the character using the same type of method
			System.Drawing.Point tmpPoint = this.GetCharSize (tmpGraphics);

			this.CharSize.Width  = tmpPoint.X; // make a little breathing room
			this.CharSize.Height = tmpPoint.Y;
			
			//Graphics g = this.CreateGraphics();
			//SizeF size = g.MeasureString("_", this.Font);
			//this.CharSize.Width = (int) size.Width;
			//this.CharSize.Height = (int) size.Height;

			tmpGraphics.Dispose ();

			this.UnderlinePos = this.CharSize.Height - 2;

			this.Caret.Bitmap    =  new System.Drawing.Bitmap (this.CharSize.Width, this.CharSize.Height);
			this.Caret.Buffer    =  System.Drawing.Graphics.FromImage (this.Caret.Bitmap);
			this.Caret.Buffer.Clear (System.Drawing.Color.FromArgb (255, 181, 106));
			this.EraseBitmap     =  new System.Drawing.Bitmap (this.CharSize.Width, this.CharSize.Height);
			this.EraseBuffer     =  System.Drawing.Graphics.FromImage (this.EraseBitmap);

			
		}

		private void OnClickFont (System.Object Sender, System.EventArgs e)
		{
			System.Windows.Forms.FontDialog fontDialog = new System.Windows.Forms.FontDialog ();

			fontDialog.FixedPitchOnly = true;
			fontDialog.ShowEffects    = false;
			fontDialog.Font           = this.Font;

			if (fontDialog.ShowDialog () != System.Windows.Forms.DialogResult.Cancel)
			{
				// Change the font
				this.Font = fontDialog.Font;

				this.GetFontInfo ();

				this.ClientSize = new System.Drawing.Size (
					System.Convert.ToInt32 (this.CharSize.Width  * this._cols + 2) + this.VertScrollBar.Width,
					System.Convert.ToInt32 (this.CharSize.Height * this._rows    + 2));
			};
		}

		#endregion
		#region Private Classes
		private class uc_CommsStateObject
		{
			public System.Net.Sockets.Socket Socket;
			public System.Byte[]             Buffer;

			public uc_CommsStateObject ()
			{
				this.Buffer = new System.Byte[8192];
			}
		}
		
		private class uc_TabStops
		{
			public System.Boolean[] Columns;

			public uc_TabStops ()
			{
				Columns = new System.Boolean[256];

				Columns[8]   = true;
				Columns[16]  = true;
				Columns[24]  = true;
				Columns[32]  = true;
				Columns[40]  = true;
				Columns[48]  = true;
				Columns[56]  = true;
				Columns[64]  = true;
				Columns[72]  = true;
				Columns[80]  = true;
				Columns[88]  = true;
				Columns[96]  = true;
				Columns[104] = true;
				Columns[112] = true;
				Columns[120] = true;
				Columns[128] = true;
			}
		}
		private class uc_CaretAttribs
		{
			public System.Drawing.Point Pos;
			public uc_Chars.Sets        G0Set;
			public uc_Chars.Sets        G1Set;
			public uc_Chars.Sets        G2Set;
			public uc_Chars.Sets        G3Set;
			public CharAttribStruct     Attribs;

			public uc_CaretAttribs (
				System.Drawing.Point p1,
				uc_Chars.Sets        p2,
				uc_Chars.Sets        p3,
				uc_Chars.Sets        p4,
				uc_Chars.Sets        p5,
				CharAttribStruct          p6)
			{
				this.Pos     = p1;
				this.G0Set   = p2;
				this.G1Set   = p3;
				this.G2Set   = p4;
				this.G3Set   = p5;
				this.Attribs = p6;
			}
		}

		private class uc_Chars
		{
			public struct uc_CharSet 
			{
				public uc_CharSet (System.Int32 p1, System.Int16 p2)
				{
					Location  = p1;
					UnicodeNo = p2;
				}

				public System.Int32 Location;
				public System.Int16 UnicodeNo;
			}

			public uc_Chars.Sets Set;

			public uc_Chars (uc_Chars.Sets p1)
			{
				this.Set = p1;
			}

			public static System.Char Get (System.Char CurChar, uc_Chars.Sets GL, uc_Chars.Sets GR)
			{
				uc_CharSet[] CurSet;

				// I'm assuming the left hand in use table will always have a 00-7F char set in it
				if (System.Convert.ToInt32 (CurChar) < 128)
				{
					switch (GL)
					{
						case uc_Chars.Sets.ASCII:
							CurSet = uc_Chars.ASCII;
							break;

						case uc_Chars.Sets.DECSG:
							CurSet = uc_Chars.DECSG;
							break;

						case uc_Chars.Sets.NRCUK:
							CurSet = uc_Chars.NRCUK;
							break;

						case uc_Chars.Sets.NRCFinnish:
							CurSet = uc_Chars.NRCFinnish;
							break;

						case uc_Chars.Sets.NRCFrench:
							CurSet = uc_Chars.NRCFrench;
							break;

						case uc_Chars.Sets.NRCFrenchCanadian:
							CurSet = uc_Chars.NRCFrenchCanadian;
							break;

						case uc_Chars.Sets.NRCGerman:
							CurSet = uc_Chars.NRCGerman;
							break;

						case uc_Chars.Sets.NRCItalian:
							CurSet = uc_Chars.NRCItalian;
							break;

						case uc_Chars.Sets.NRCNorDanish:
							CurSet = uc_Chars.NRCNorDanish;
							break;

						case uc_Chars.Sets.NRCPortuguese:
							CurSet = uc_Chars.NRCPortuguese;
							break;

						case uc_Chars.Sets.NRCSpanish:
							CurSet = uc_Chars.NRCSpanish;
							break;

						case uc_Chars.Sets.NRCSwedish:
							CurSet = uc_Chars.NRCSwedish;
							break;

						case uc_Chars.Sets.NRCSwiss:
							CurSet = uc_Chars.NRCSwiss;
							break;

						default:
							CurSet = uc_Chars.ASCII;
							break;
					}
				}
					// I'm assuming the right hand in use table will always have a 80-FF char set in it
				else
				{
					switch (GR)
					{
						case uc_Chars.Sets.ISOLatin1S:
							CurSet = uc_Chars.ISOLatin1S;
							break;

						case uc_Chars.Sets.DECS:
							CurSet = uc_Chars.DECS;
							break;

						default:
							CurSet = uc_Chars.DECS;
							break;
					}
				}

				for (System.Int32 i = 0; i < CurSet.Length; i++)
				{
					if (CurSet[i].Location == System.Convert.ToInt32 (CurChar))
					{
						System.Byte[] CurBytes = System.BitConverter.GetBytes (CurSet[i].UnicodeNo);
						System.Char[] NewChars = System.Text.Encoding.Unicode.GetChars (CurBytes);

						return NewChars[0];
					}

				}

				return CurChar;
			}

			public static uc_CharSet[] DECSG =
		{
			new uc_CharSet (0x5F, 0x0020), // Blank (I've used space here so you may want to change this)
			//            new uc_CharSet (0x60, 0x25C6), // Filled Diamond 
			new uc_CharSet (0x61, 0x0000), // Pi over upsidedown Pi ?  
			new uc_CharSet (0x62, 0x2409), // HT symbol 
			new uc_CharSet (0x63, 0x240C), // LF Symbol  
			new uc_CharSet (0x64, 0x240D), // CR Symbol  
			new uc_CharSet (0x65, 0x240A), // LF Symbol  
			new uc_CharSet (0x66, 0x00B0), // Degree  
			new uc_CharSet (0x67, 0x00B1), // Plus over Minus  
			new uc_CharSet (0x68, 0x2424), // NL Symbol  
			new uc_CharSet (0x69, 0x240B), // VT Symbol 
			//            new uc_CharSet (0x6A, 0x2518), // Bottom Right Box 
			//            new uc_CharSet (0x6B, 0x2510), // Top Right Box
			//            new uc_CharSet (0x6C, 0x250C), // TopLeft Box
			//            new uc_CharSet (0x6D, 0x2514), // Bottom Left Box
			//            new uc_CharSet (0x6E, 0x253C), // Cross Piece
			new uc_CharSet (0x6F, 0x23BA), // Scan Line 1
			new uc_CharSet (0x70, 0x25BB), // Scan Line 3
			//            new uc_CharSet (0x71, 0x2500), // Horizontal Line (scan line 5 as well?)
			new uc_CharSet (0x72, 0x23BC), // Scan Line 7 
			new uc_CharSet (0x73, 0x23BD), // Scan Line 9 
			//            new uc_CharSet (0x74, 0x251C), // Left Tee Piece
			//            new uc_CharSet (0x75, 0x2524), // Right Tee Piece
			//            new uc_CharSet (0x76, 0x2534), // Bottom Tee Piece
			//            new uc_CharSet (0x77, 0x252C), // Top Tee Piece
			//            new uc_CharSet (0x78, 0x2502), // Vertical Line
			new uc_CharSet (0x79, 0x2264), // Less than or equal  
			new uc_CharSet (0x7A, 0x2265), // Greater than or equal 
			new uc_CharSet (0x7B, 0x03A0), // Capital Pi
			new uc_CharSet (0x7C, 0x2260), // Not Equal 
			new uc_CharSet (0x7D, 0x00A3), // Pound Sign 
			new uc_CharSet (0x7E, 0x00B7), // Middle Dot 
			};

			public static uc_CharSet[] DECS =
		{
			new uc_CharSet (0xA8, 0x0020), // Currency Sign
			new uc_CharSet (0xD7, 0x0152), // latin small ligature OE 
			new uc_CharSet (0xDD, 0x0178), // Capital Y with diaeresis
			new uc_CharSet (0xF7, 0x0153), // latin small ligature oe 
			new uc_CharSet (0xFD, 0x00FF), // Lowercase y with diaeresis
			};

			public static uc_CharSet[] ASCII = // same as Basic Latin
		{
			new uc_CharSet (0x00, 0x0000), //
			};

			public static uc_CharSet[] NRCUK = // UK National Replacement
		{
			new uc_CharSet (0x23, 0x00A3), //
			};

			public static uc_CharSet[] NRCFinnish = // Finnish National Replacement
		{
			new uc_CharSet (0x5B, 0x00C4), // A with diearesis
			new uc_CharSet (0x5C, 0x00D6), // O with diearesis
			new uc_CharSet (0x5D, 0x00C5), // A with hollow dot above
			new uc_CharSet (0x5E, 0x00DC), // U with diearesis
			new uc_CharSet (0x60, 0x00E9), // e with accute accent
			new uc_CharSet (0x7B, 0x00E4), // a with diearesis
			new uc_CharSet (0x7C, 0x00F6), // o with diearesis
			new uc_CharSet (0x7D, 0x00E5), // a with hollow dot above
			new uc_CharSet (0x7E, 0x00FC), // u with diearesis
			};

			public static uc_CharSet[] NRCFrench = // French National Replacement
		{
			new uc_CharSet (0x23, 0x00A3), // Pound Sign
			new uc_CharSet (0x40, 0x00E0), // a with grav accent
			new uc_CharSet (0x5B, 0x00B0), // Degree Symbol
			new uc_CharSet (0x5C, 0x00E7), // little cedila
			new uc_CharSet (0x5D, 0x00A7), // funny s (technical term)
			new uc_CharSet (0x7B, 0x00E9), // e with accute accent
			new uc_CharSet (0x7C, 0x00F9), // u with grav accent
			new uc_CharSet (0x7D, 0x00E8), // e with grav accent
			new uc_CharSet (0x7E, 0x00A8), // diearesis
			};

			public static uc_CharSet[] NRCFrenchCanadian = // French Canadian National Replacement
		{
			new uc_CharSet (0x40, 0x00E0), // a with grav accent
			new uc_CharSet (0x5B, 0x00E2), // a with circumflex
			new uc_CharSet (0x5C, 0x00E7), // little cedila
			new uc_CharSet (0x5D, 0x00EA), // e with circumflex
			new uc_CharSet (0x5E, 0x00CE), // i with circumflex
			new uc_CharSet (0x60, 0x00F4), // o with circumflex
			new uc_CharSet (0x7B, 0x00E9), // e with accute accent
			new uc_CharSet (0x7C, 0x00F9), // u with grav accent
			new uc_CharSet (0x7D, 0x00E8), // e with grav accent
			new uc_CharSet (0x7E, 0x00FB), // u with circumflex
			};

			public static uc_CharSet[] NRCGerman = // German National Replacement
		{
			new uc_CharSet (0x40, 0x00A7), // funny s
			new uc_CharSet (0x5B, 0x00C4), // A with diearesis
			new uc_CharSet (0x5C, 0x00D6), // O with diearesis
			new uc_CharSet (0x5D, 0x00DC), // U with diearesis
			new uc_CharSet (0x7B, 0x00E4), // a with diearesis
			new uc_CharSet (0x7C, 0x00F6), // o with diearesis
			new uc_CharSet (0x7D, 0x00FC), // u with diearesis
			new uc_CharSet (0x7E, 0x00DF), // funny B
			};

			public static uc_CharSet[] NRCItalian = // Italian National Replacement
		{
			new uc_CharSet (0x23, 0x00A3), // pound sign
			new uc_CharSet (0x40, 0x00A7), // funny s
			new uc_CharSet (0x5B, 0x00B0), // Degree Symbol
			new uc_CharSet (0x5C, 0x00E7), // little cedilla
			new uc_CharSet (0x5D, 0x00E9), // e with accute accent
			new uc_CharSet (0x60, 0x00F9), // u with grav accent
			new uc_CharSet (0x7B, 0x00E0), // a with grav accent
			new uc_CharSet (0x7C, 0x00F2), // o with grav accent
			new uc_CharSet (0x7D, 0x00E8), // e with grav accent
			new uc_CharSet (0x7E, 0x00CC), // I with grav accent
			};

			public static uc_CharSet[] NRCNorDanish = // Norwegian Danish National Replacement
		{
			new uc_CharSet (0x5B, 0x00C6), // AE ligature
			new uc_CharSet (0x5C, 0x00D8), // O with strikethough
			new uc_CharSet (0x5D, 0x00D8), // O with strikethough
			new uc_CharSet (0x5D, 0x00C5), // A with hollow dot above
			new uc_CharSet (0x7B, 0x00E6), // ae ligature
			new uc_CharSet (0x7C, 0x00F8), // o with strikethough
			new uc_CharSet (0x7D, 0x00F8), // o with strikethough
			new uc_CharSet (0x7D, 0x00E5), // a with hollow dot above
			};

			public static uc_CharSet[] NRCPortuguese = // Portuguese National Replacement
		{
			new uc_CharSet (0x5B, 0x00C3), // A with tilde
			new uc_CharSet (0x5C, 0x00C7), // big cedilla
			new uc_CharSet (0x5D, 0x00D5), // O with tilde
			new uc_CharSet (0x7B, 0x00E3), // a with tilde
			new uc_CharSet (0x7C, 0x00E7), // little cedilla
			new uc_CharSet (0x7D, 0x00F6), // o with tilde
			};

			public static uc_CharSet[] NRCSpanish = // Spanish National Replacement
		{
			new uc_CharSet (0x23, 0x00A3), // pound sign
			new uc_CharSet (0x40, 0x00A7), // funny s
			new uc_CharSet (0x5B, 0x00A1), // I with dot
			new uc_CharSet (0x5C, 0x00D1), // N with tilde
			new uc_CharSet (0x5D, 0x00BF), // Upside down question mark
			new uc_CharSet (0x7B, 0x0060), // back single quote
			new uc_CharSet (0x7C, 0x00B0), // Degree Symbol
			new uc_CharSet (0x7D, 0x00F1), // n with tilde
			new uc_CharSet (0x7E, 0x00E7), // small cedilla
			};

			public static uc_CharSet[] NRCSwedish = // Swedish National Replacement
		{
			new uc_CharSet (0x40, 0x00C9), // E with acute
			new uc_CharSet (0x5B, 0x00C4), // A with diearesis
			new uc_CharSet (0x5C, 0x00D6), // O with diearesis
			new uc_CharSet (0x5D, 0x00C5), // A with hollow dot above
			new uc_CharSet (0x5E, 0x00DC), // U with diearesis
			new uc_CharSet (0x60, 0x00E9), // e with accute accent
			new uc_CharSet (0x7B, 0x00E4), // a with diearesis
			new uc_CharSet (0x7C, 0x00F6), // o with diearesis
			new uc_CharSet (0x7D, 0x00E5), // a with hollow dot above
			new uc_CharSet (0x7E, 0x00FC), // u with diearesis
			};

			public static uc_CharSet[] NRCSwiss = // Swiss National Replacement
		{
			new uc_CharSet (0x23, 0x00F9), // u with grav accent
			new uc_CharSet (0x40, 0x00E0), // a with grav accent
			new uc_CharSet (0x5B, 0x00E9), // e with accute accent
			new uc_CharSet (0x5C, 0x00E7), // small cedilla
			new uc_CharSet (0x5D, 0x00EA), // e with circumflex
			new uc_CharSet (0x5E, 0x00CE), // i with circumflex
			new uc_CharSet (0x5F, 0x00E8), // e with grav accent
			new uc_CharSet (0x60, 0x00F4), // o with circumflex
			new uc_CharSet (0x7B, 0x00E4), // a with diearesis
			new uc_CharSet (0x7C, 0x00F6), // o with diearesis
			new uc_CharSet (0x7D, 0x00FC), // u with diearesis
			new uc_CharSet (0x7E, 0x00FB), // u with circumflex
			};

			public static uc_CharSet[] ISOLatin1S = // Same as Latin-1 Supplemental
		{
			new uc_CharSet (0x00, 0x0000) //
		};

			public enum Sets
			{
				None,
				DECSG,
				DECTECH,
				DECS,
				ASCII,
				ISOLatin1S,
				NRCUK,
				NRCFinnish,
				NRCFrench,
				NRCFrenchCanadian,
				NRCGerman,
				NRCItalian,
				NRCNorDanish,
				NRCPortuguese,
				NRCSpanish,
				NRCSwedish,
				NRCSwiss
			}
		}

		private class uc_Caret
		{
			public System.Drawing.Point    Pos;
			public System.Drawing.Color    Color  = System.Drawing.Color.FromArgb (255, 181,106);
			public System.Drawing.Bitmap   Bitmap = null;
			public System.Drawing.Graphics Buffer = null;
			public System.Boolean          IsOff  = false;
			public System.Boolean          EOL    = false;

			public uc_Caret ()
			{
				this.Pos = new System.Drawing.Point (0, 0);
			}
		}

		private class WMCodes
		{
			public const int WM_KEYFIRST    = 0x0100;
			public const int WM_KEYDOWN     = 0x0100;
			public const int WM_KEYUP       = 0x0101;
			public const int WM_CHAR        = 0x0102;
			public const int WM_DEADCHAR    = 0x0103;
			public const int WM_SYSKEYDOWN  = 0x0104;
			public const int WM_SYSKEYUP    = 0x0105;
			public const int WM_SYSCHAR     = 0x0106;
			public const int WM_SYSDEADCHAR = 0x0107;
			public const int WM_KEYLAST     = 0x0108;
		}

		private class uc_Mode
		{
			public static System.UInt32 Locked          = 1;           // Unlocked           = off 
			public static System.UInt32 BackSpace       = 2;           // Delete             = off 
			public static System.UInt32 NewLine         = 4;           // Line Feed          = off 
			public static System.UInt32 Repeat          = 8;           // No Repeat          = off 
			public static System.UInt32 AutoWrap        = 16;          // No AutoWrap        = off 
			public static System.UInt32 CursorAppln     = 32;          // Std Cursor Codes   = off 
			public static System.UInt32 KeypadAppln     = 64;          // Std Numeric Codes  = off 
			public static System.UInt32 DataProcessing  = 128;         // Typewriter         = off 
			public static System.UInt32 PositionReports = 256;         // CharacterCodes     = off
			public static System.UInt32 LocalEchoOff    = 512;         // LocalEchoOn        = off
			public static System.UInt32 OriginRelative  = 1024;        // OriginAbsolute     = off
			public static System.UInt32 LightBackground = 2048;        // DarkBackground     = off
			public static System.UInt32 National        = 4096;        // Multinational      = off
			public static System.UInt32 Any             = 0x80000000;  // Any Flags

			public System.UInt32 Flags;

			public uc_Mode (System.UInt32 InitialFlags)
			{
				this.Flags = InitialFlags;
			} 

			public uc_Mode ()
			{
				this.Flags = 0;
			} 
		}

		private class uc_Keyboard 
		{
			public event KeyboardEventHandler KeyboardEvent;

			private System.Boolean LastKeyDownSent  = false; // next WM_CHAR ignored if true 
			private bool AltIsDown    = false;
			private bool ShiftIsDown  = false;
			private bool CtrlIsDown   = false;

			private TerminalEmulator Parent;
    
			private uc_KeyMap KeyMap = new uc_KeyMap ();
    
			public uc_Keyboard (TerminalEmulator p1)
			{
				this.Parent = p1;
			}
    
			public void KeyDown (System.Windows.Forms.Message KeyMess)
			{
				System.Byte[] lBytes;
				System.Byte[] wBytes;
				System.UInt16 KeyValue    = 0; 
				System.UInt16 RepeatCount = 0; 
				System.Byte   ScanCode    = 0; 
				System.Byte   AnsiChar    = 0;
				System.UInt16 UniChar     = 0;
				System.Byte   Flags       = 0;
    
    
				lBytes = System.BitConverter.GetBytes (KeyMess.LParam.ToInt32 ());
				wBytes = System.BitConverter.GetBytes (KeyMess.WParam.ToInt32 ());
				RepeatCount = System.BitConverter.ToUInt16 (lBytes, 0);
				ScanCode    = lBytes[2];
				Flags       = lBytes[3];
    
				// key down messages send the scan code in wParam whereas
				// key press messages send the char and unicode values in this word
				if (KeyMess.Msg == WMCodes.WM_SYSKEYDOWN ||
					KeyMess.Msg == WMCodes.WM_KEYDOWN)
				{
					KeyValue = System.BitConverter.ToUInt16 (wBytes, 0);
    
					// set the key down flags. I know you can get alt from lparam flags
					// but this feels more consistent
					switch (KeyValue)
					{
						case 16:  // Shift Keys
						case 160: // L Shift Key
						case 161: // R Shift Keys
							this.ShiftIsDown = true;
							return;
    
						case 17:  // Ctrl Keys
						case 162: // L Ctrl Key
						case 163: // R Ctrl Key
							this.CtrlIsDown = true; 
							return;
    
						case 18:  // Alt Keys (Menu)
						case 164: // L Alt Key
						case 165: // R Ctrl Key
							this.AltIsDown = true; 
							return;
    
						default:
							break;
					}
    
					System.String Modifier = "Key";
    
					if (this.ShiftIsDown)
					{
						Modifier = "Shift"; 
					}
					else if (this.CtrlIsDown)
					{
						Modifier = "Ctrl";
					} 
					else if (this.AltIsDown)
					{
						Modifier = "Alt"; 
					}
    
					// the key pressed was not a modifier so check for an override string
					System.String OutString = KeyMap.Find (ScanCode, System.Convert.ToBoolean (Flags & 0x01), Modifier, Parent.Modes.Flags);

					this.LastKeyDownSent = false;

					if (OutString != "")
					{
						// Flag the event so that the associated WM_CHAR event (if any) is ignored
						this.LastKeyDownSent = true;

                    
						//Parent.NvtParser.ParseString (OutString); 
						//this.Parent.Invalidate ();
                    

						KeyboardEvent (this, OutString); 
					} 
    
				}
				else if (KeyMess.Msg == WMCodes.WM_SYSKEYUP ||
					KeyMess.Msg == WMCodes.WM_KEYUP)
				{
					KeyValue = System.BitConverter.ToUInt16 (wBytes, 0);
    
					switch (KeyValue)
					{
						case 16:  // Shift Keys
						case 160: // L Shift Key
						case 161: // R Shift Keys
							this.ShiftIsDown = false; 
							break;
    
						case 17:  // Ctrl Keys
						case 162: // L Ctrl Key
						case 163: // R Ctrl Key
							this.CtrlIsDown = false; 
							break;
    
						case 18:  // Alt Keys (Menu)
						case 164: // L Alt Key
						case 165: // R Ctrl Key
							this.AltIsDown = false; 
							break;
    
						default:
							break;
					}
				}
    
				else if (KeyMess.Msg == WMCodes.WM_SYSCHAR ||
					KeyMess.Msg == WMCodes.WM_CHAR)
				{
					AnsiChar    = wBytes[0];
					UniChar     = System.BitConverter.ToUInt16 (wBytes, 0);
    
    
					// if there's a string mapped to this key combo we want to ignore the character
					// as it has been overriden in the keydown event
    
					// only send the windows generated char if there was no custom
					// string sent by the keydown event
					if (this.LastKeyDownSent == false)
					{
						// send the character straight to the host if we haven't already handled the actual key press
						KeyboardEvent (this, System.Convert.ToChar (AnsiChar).ToString ()); 
					}
				}
    
				//System.Console.Write ("AnsiChar = {0} Result = {1} ScanCode = {2} KeyValue = {3} Flags = {4} Repeat = {5}\n ", 
				//AnsiChar, KeyMess.Result, ScanCode, KeyValue, Flags, RepeatCount);
			}
    
			private class uc_KeyInfo
			{
				public System.UInt16  ScanCode;
				public System.Boolean ExtendFlag;
				public System.String  Modifier;
				public System.String  OutString;
				public System.UInt32  Flag;
				public System.UInt32  FlagValue;
        
				public uc_KeyInfo (
					System.UInt16  p1,
					System.Boolean p2,
					System.String  p3,
					System.String  p4,
					System.UInt32  p5,
					System.UInt32  p6)
				{
					ScanCode    = p1;
					ExtendFlag  = p2;
					Modifier    = p3;
					OutString   = p4;
					Flag        = p5;
					FlagValue   = p6;
				}
			}

			private class uc_KeyMap
			{
				public System.Collections.ArrayList Elements = new System.Collections.ArrayList ();
        
				public uc_KeyMap () 
				{
					this.SetToDefault ();
				}
        
				// set the key mapping up to emulate most keys on a vt420
				public void SetToDefault ()
				{
					// add the default key mappings here
					Elements.Clear ();
        
					// TOPNZ Customisations these should be commented out
					//Elements.Add (new uc_KeyInfo (15,  false, "Shift", "\x1B[OI~", uc_Mode.Any,       0)); //ShTab
					//Elements.Add (new uc_KeyInfo (63,  false, "Key",   "\x1BOT",   uc_Mode.Any,       0)); //F5
					//Elements.Add (new uc_KeyInfo (64,  false, "Key",   "\x1BOU",   uc_Mode.Any,       0)); //F6
					//Elements.Add (new uc_KeyInfo (65,  false, "Key",   "\x1BOV",   uc_Mode.Any,       0)); //F7
					//Elements.Add (new uc_KeyInfo (66,  false, "Key",   "\x1BOW",   uc_Mode.Any,       0)); //F8
					//Elements.Add (new uc_KeyInfo (67,  false, "Key",   "\x1BOX",   uc_Mode.Any,       0)); //F9
					//Elements.Add (new uc_KeyInfo (68,  false, "Key",   "\x1BOY",   uc_Mode.Any,       0)); //F10
					//Elements.Add (new uc_KeyInfo (59,  false, "Shift", "\x1B[25~", uc_Mode.Any,       0)); //ShF1
					//Elements.Add (new uc_KeyInfo (60,  false, "Shift", "\x1B[26~", uc_Mode.Any,       0)); //ShF2
					//Elements.Add (new uc_KeyInfo (61,  false, "Shift", "\x1B[28~", uc_Mode.Any,       0)); //ShF3
					//Elements.Add (new uc_KeyInfo (62,  false, "Shift", "\x1B[29~", uc_Mode.Any,       0)); //ShF4
					//Elements.Add (new uc_KeyInfo (63,  false, "Shift", "\x1B[31~", uc_Mode.Any,       0)); //ShF5
					//Elements.Add (new uc_KeyInfo (64,  false, "Shift", "\x1B[32~", uc_Mode.Any,       0)); //ShF6
					//Elements.Add (new uc_KeyInfo (65,  false, "Shift", "\x1B[33~", uc_Mode.Any,       0)); //ShF7
					//Elements.Add (new uc_KeyInfo (66,  false, "Shift", "\x1B[34~", uc_Mode.Any,       0)); //ShF8
					//Elements.Add (new uc_KeyInfo (67,  false, "Shift", "\x1B[36~", uc_Mode.Any,       0)); //ShF9
					//Elements.Add (new uc_KeyInfo (68,  false, "Shift", "\x1B[37~", uc_Mode.Any,       0)); //ShF10
					//Elements.Add (new uc_KeyInfo (87,  false, "Shift", "\x1B[38~", uc_Mode.Any,       0)); //ShF11
					//Elements.Add (new uc_KeyInfo (88,  false, "Shift", "\x1B[39~", uc_Mode.Any,       0)); //ShF12


					// this is the initial list of keyboard codes
					Elements.Add (new uc_KeyInfo (15,  false, "Shift", "\x1B[Z",   uc_Mode.Any,         0)); //ShTab
					Elements.Add (new uc_KeyInfo (28,  false, "Key",   "\x0D",     uc_Mode.Any,         0)); //Return
					Elements.Add (new uc_KeyInfo (59,  false, "Key",   "\x1BOP",   uc_Mode.Any,         0)); //F1->PF1
					Elements.Add (new uc_KeyInfo (60,  false, "Key",   "\x1BOQ",   uc_Mode.Any,         0)); //F2->PF2
					Elements.Add (new uc_KeyInfo (61,  false, "Key",   "\x1BOR",   uc_Mode.Any,         0)); //F3->PF3
					Elements.Add (new uc_KeyInfo (62,  false, "Key",   "\x1BOS",   uc_Mode.Any,         0)); //F4->PF4
					Elements.Add (new uc_KeyInfo (63,  false, "Key",   "\x1B[15~", uc_Mode.Any,         0)); //F5
					Elements.Add (new uc_KeyInfo (64,  false, "Key",   "\x1B[17~", uc_Mode.Any,         0)); //F6
					Elements.Add (new uc_KeyInfo (65,  false, "Key",   "\x1B[18~", uc_Mode.Any,         0)); //F7
					Elements.Add (new uc_KeyInfo (66,  false, "Key",   "\x1B[19~", uc_Mode.Any,         0)); //F8
					Elements.Add (new uc_KeyInfo (67,  false, "Key",   "\x1B[20~", uc_Mode.Any,         0)); //F9
					Elements.Add (new uc_KeyInfo (68,  false, "Key",   "\x1B[21~", uc_Mode.Any,         0)); //F10
					Elements.Add (new uc_KeyInfo (87,  false, "Key",   "\x1B[23~", uc_Mode.Any,         0)); //F11
					Elements.Add (new uc_KeyInfo (88,  false, "Key",   "\x1B[24~", uc_Mode.Any,         0)); //F12
					Elements.Add (new uc_KeyInfo (61,  false, "Shift", "\x1B[25~", uc_Mode.Any,         0)); //ShF3 ->F13
					Elements.Add (new uc_KeyInfo (62,  false, "Shift", "\x1B[26~", uc_Mode.Any,         0)); //ShF4 ->F14
					Elements.Add (new uc_KeyInfo (63,  false, "Shift", "\x1B[28~", uc_Mode.Any,         0)); //ShF5 ->F15
					Elements.Add (new uc_KeyInfo (64,  false, "Shift", "\x1B[29~", uc_Mode.Any,         0)); //ShF6 ->F16
					Elements.Add (new uc_KeyInfo (65,  false, "Shift", "\x1B[31~", uc_Mode.Any,         0)); //ShF7 ->F17
					Elements.Add (new uc_KeyInfo (66,  false, "Shift", "\x1B[32~", uc_Mode.Any,         0)); //ShF8 ->F18
					Elements.Add (new uc_KeyInfo (67,  false, "Shift", "\x1B[33~", uc_Mode.Any,         0)); //ShF9 ->F19
					Elements.Add (new uc_KeyInfo (68,  false, "Shift", "\x1B[34~", uc_Mode.Any,         0)); //ShF10->F20
					Elements.Add (new uc_KeyInfo (87,  false, "Shift", "\x1B[28~", uc_Mode.Any,         0)); //ShF11->Help
					Elements.Add (new uc_KeyInfo (88,  false, "Shift", "\x1B[29~", uc_Mode.Any,         0)); //ShF12->Do
					Elements.Add (new uc_KeyInfo (71,  true,  "Key",   "\x1B[1~",  uc_Mode.Any,         0)); //Home
					Elements.Add (new uc_KeyInfo (82,  true,  "Key",   "\x1B[2~",  uc_Mode.Any,         0)); //Insert
					Elements.Add (new uc_KeyInfo (83,  true,  "Key",   "\x1B[3~",  uc_Mode.Any,         0)); //Delete
					Elements.Add (new uc_KeyInfo (79,  true,  "Key",   "\x1B[4~",  uc_Mode.Any,         0)); //End
					Elements.Add (new uc_KeyInfo (73,  true,  "Key",   "\x1B[5~",  uc_Mode.Any,         0)); //PageUp
					Elements.Add (new uc_KeyInfo (81,  true,  "Key",   "\x1B[6~",  uc_Mode.Any,         0)); //PageDown
					Elements.Add (new uc_KeyInfo (72,  true,  "Key",   "\x1B[A",   uc_Mode.CursorAppln, 0)); //CursorUp
					Elements.Add (new uc_KeyInfo (80,  true,  "Key",   "\x1B[B",   uc_Mode.CursorAppln, 0)); //CursorDown
					Elements.Add (new uc_KeyInfo (77,  true,  "Key",   "\x1B[C",   uc_Mode.CursorAppln, 0)); //CursorKeyRight
					Elements.Add (new uc_KeyInfo (75,  true,  "Key",   "\x1B[D",   uc_Mode.CursorAppln, 0)); //CursorKeyLeft
					Elements.Add (new uc_KeyInfo (72,  true,  "Key",   "\x1BOA",   uc_Mode.CursorAppln, 1)); //CursorUp
					Elements.Add (new uc_KeyInfo (80,  true,  "Key",   "\x1BOB",   uc_Mode.CursorAppln, 1)); //CursorDown
					Elements.Add (new uc_KeyInfo (77,  true,  "Key",   "\x1BOC",   uc_Mode.CursorAppln, 1)); //CursorKeyRight
					Elements.Add (new uc_KeyInfo (75,  true,  "Key",   "\x1BOD",   uc_Mode.CursorAppln, 1)); //CursorKeyLeft
					Elements.Add (new uc_KeyInfo (82,  false, "Key",   "\x1BOp",   uc_Mode.KeypadAppln, 1)); //Keypad0
					Elements.Add (new uc_KeyInfo (79,  false, "Key",   "\x1BOq",   uc_Mode.KeypadAppln, 1)); //Keypad1
					Elements.Add (new uc_KeyInfo (80,  false, "Key",   "\x1BOr",   uc_Mode.KeypadAppln, 1)); //Keypad2
					Elements.Add (new uc_KeyInfo (81,  false, "Key",   "\x1BOs",   uc_Mode.KeypadAppln, 1)); //Keypad3
					Elements.Add (new uc_KeyInfo (75,  false, "Key",   "\x1BOt",   uc_Mode.KeypadAppln, 1)); //Keypad4
					Elements.Add (new uc_KeyInfo (76,  false, "Key",   "\x1BOu",   uc_Mode.KeypadAppln, 1)); //Keypad5
					Elements.Add (new uc_KeyInfo (77,  false, "Key",   "\x1BOv",   uc_Mode.KeypadAppln, 1)); //Keypad6
					Elements.Add (new uc_KeyInfo (71,  false, "Key",   "\x1BOw",   uc_Mode.KeypadAppln, 1)); //Keypad7
					Elements.Add (new uc_KeyInfo (72,  false, "Key",   "\x1BOx",   uc_Mode.KeypadAppln, 1)); //Keypad8
					Elements.Add (new uc_KeyInfo (73,  false, "Key",   "\x1BOy",   uc_Mode.KeypadAppln, 1)); //Keypad9
					Elements.Add (new uc_KeyInfo (74,  false, "Key",   "\x1BOm",   uc_Mode.KeypadAppln, 1)); //Keypad-
					Elements.Add (new uc_KeyInfo (78,  false, "Key",   "\x1BOl",   uc_Mode.KeypadAppln, 1)); //Keypad+ (use instead of comma)
					Elements.Add (new uc_KeyInfo (83,  false, "Key",   "\x1BOn",   uc_Mode.KeypadAppln, 1)); //Keypad.
					Elements.Add (new uc_KeyInfo (28,  true,  "Key",   "\x1BOM",   uc_Mode.KeypadAppln, 1)); //Keypad Enter
					Elements.Add (new uc_KeyInfo (03,  false, "Ctrl",  "\x00",     uc_Mode.Any,         0)); //Ctrl2->Null
					Elements.Add (new uc_KeyInfo (57,  false, "Ctrl",  "\x00",     uc_Mode.Any,         0)); //CtrlSpaceBar->Null
					Elements.Add (new uc_KeyInfo (04,  false, "Ctrl",  "\x1B",     uc_Mode.Any,         0)); //Ctrl3->Escape
					Elements.Add (new uc_KeyInfo (05,  false, "Ctrl",  "\x1C",     uc_Mode.Any,         0)); //Ctrl4->FS
					Elements.Add (new uc_KeyInfo (06,  false, "Ctrl",  "\x1D",     uc_Mode.Any,         0)); //Ctrl5->GS
					Elements.Add (new uc_KeyInfo (07,  false, "Ctrl",  "\x1E",     uc_Mode.Any,         0)); //Ctrl6->RS
					Elements.Add (new uc_KeyInfo (08,  false, "Ctrl",  "\x1F",     uc_Mode.Any,         0)); //Ctrl7->US
					Elements.Add (new uc_KeyInfo (09,  false, "Ctrl",  "\x7F",     uc_Mode.Any,         0)); //Ctrl8->DEL
				}
        
				public System.String Find (
					System.UInt16  ScanCode, 
					System.Boolean ExtendFlag, 
					System.String  Modifier,
					System.UInt32  ModeFlags)
				{
					System.String OutString = "";
        
					for (int i=0; i < Elements.Count; i++)
					{
						uc_KeyInfo Element = (uc_KeyInfo) Elements[i];
        
						if (Element.ScanCode      == ScanCode   && 
							Element.ExtendFlag    == ExtendFlag &&
							Element.Modifier      == Modifier   &&
							(Element.Flag == uc_Mode.Any ||
							((Element.Flag & ModeFlags) ==  Element.Flag && Element.FlagValue == 1) ||
							((Element.Flag & ModeFlags) ==  0            && Element.FlagValue == 0)))
						{
							OutString = Element.OutString;
							return OutString;
						}
					}
        
					return OutString;
				}
			}
		}

		private class uc_VertScrollBar : System.Windows.Forms.VScrollBar
		{
			public uc_VertScrollBar ()
			{
				this.SetStyle (System.Windows.Forms.ControlStyles.Selectable, false);
				this.Maximum = 0;
				
			}
		}

		private class uc_Params
		{
			public System.Collections.ArrayList Elements = new System.Collections.ArrayList ();
  
			public uc_Params ()
			{
			}
    
			public System.Int32 Count () 
			{
				return this.Elements.Count;
			}
    
			public void Clear ()
			{
				this.Elements.Clear ();
			}
    
			public void Add (System.Char CurChar)
			{
				if (this.Count () < 1)
				{
					this.Elements.Add ("0");
				}
 
				if (CurChar == ';')
				{
					this.Elements.Add ("0");
				}
				else
				{
					int i = this.Elements.Count - 1;
					this.Elements[i] = ((System.String) this.Elements[i] + CurChar.ToString ());
				}
			}
		}
		/// <summary>
		/// This class provides functionality to parse the VT control characters fed
		/// to the terminal from the host machine and fire off the appropriate actions
		/// It implements Paul William's excellent VT500-Series Parser Model. 
		/// Paul's model can be found at vt100.net
		/// </summary>
		private class uc_Parser
		{
			public event ParserEventHandler ParserEvent;

			States State = States.Ground;
			System.Char   CurChar     = '\0';
			System.String CurSequence = "";
        
			System.Collections.ArrayList ParamList = new System.Collections.ArrayList ();
			uc_CharEvents        CharEvents        = new uc_CharEvents ();
			uc_StateChangeEvents StateChangeEvents = new uc_StateChangeEvents ();
			uc_Params            CurParams         = new uc_Params ();

			public uc_Parser ()
			{
			}
        
			// Every character received is treated as an event which could change the state of
			// the parser. The following section finds out which event or state change this character
			// should trigger and also finds out where we should store the incoming character.
			// The character may be a command, part of a sequence or a parameter; or it might just need
			// binning.
			// The sequence is: state change, store character, do action.
			public void ParseString (System.String InString)
			{
				States        NextState        = States.None;
				Actions       NextAction       = Actions.None;
				Actions       StateExitAction  = Actions.None;
				Actions       StateEntryAction = Actions.None;
    
				foreach (System.Char C in InString)
				{
					this.CurChar = C;
   
					// Get the next state and associated action based 
					// on the current state and char event
					CharEvents.GetStateEventAction (State, CurChar, ref NextState, ref NextAction);
    
					// execute any actions arising from leaving the current state
					if  (NextState != States.None && NextState != this.State)
					{
						// check for state exit actions
						StateChangeEvents.GetStateChangeAction (this.State, Transitions.Exit, ref StateExitAction);
    
						// Process the exit action
						if (StateExitAction != Actions.None) DoAction (StateExitAction);
    
					}
    
					// process the action specified
					if (NextAction != Actions.None) DoAction (NextAction);
    
					// set the new parser state and execute any actions arising entering the new state
					if  (NextState != States.None && NextState != this.State)
					{
						// change the parsers state attribute
						this.State = NextState;
    
						// check for state entry actions
						StateChangeEvents.GetStateChangeAction (this.State, Transitions.Entry, ref StateExitAction);
    
						// Process the entry action
						if (StateEntryAction != Actions.None) DoAction (StateEntryAction);
					}
				}
			}
        
			private void DoAction (Actions NextAction)
			{
				// Manage the contents of the Sequence and Param Variables
				switch (NextAction)
				{
					case Actions.Dispatch:
					case Actions.Collect:
						this.CurSequence += CurChar.ToString ();
						break;
    
					case Actions.NewCollect:
						this.CurSequence = CurChar.ToString ();
						this.CurParams.Clear ();
						break;
    
					case Actions.Param:
						this.CurParams.Add (CurChar);
						break;
    
					default:
						break;
				}
    
				// send the external event requests
				switch (NextAction)
				{
					case Actions.Dispatch:
					case Actions.Execute:
					case Actions.Put:
					case Actions.OscStart:
					case Actions.OscPut:
					case Actions.OscEnd:
					case Actions.Hook:
					case Actions.Unhook:
					case Actions.Print:

						//                    System.Console.Write ("Sequence = {0}, Char = {1}, PrmCount = {2}, State = {3}, NextAction = {4}\n",
						//                        this.CurSequence, this.CurChar.ToString (), this.CurParams.Count ().ToString (), 
						//                        this.State.ToString (), NextAction.ToString ());

						ParserEvent (this, new ParserEventArgs (NextAction, CurChar, CurSequence, CurParams));
						break;
    
					default:
						break; 
				}
    
    
				switch (NextAction)
				{
					case Actions.Dispatch:
						this.CurSequence = "";
						this.CurParams.Clear ();
						break;
					default:
						break;
				}
			}
    
			private enum States 
			{
				None               = 0,
				Ground             = 1,
				EscapeIntrmdt      = 2,
				Escape             = 3,
				CsiEntry           = 4,
				CsiIgnore          = 5,
				CsiParam           = 6,
				CsiIntrmdt         = 7,
				OscString          = 8,
				SosPmApcString     = 9,
				DcsEntry           = 10,
				DcsParam           = 11,
				DcsIntrmdt         = 12,
				DcsIgnore          = 13,
				DcsPassthrough     = 14,
				Anywhere           = 16
			}
        
			private enum Transitions 
			{
				None  = 0,
				Entry = 1,
				Exit  = 2
			}
        
			private struct uc_StateChangeInfo
			{
				public States        State;
				public Transitions   Transition;    // the next state we are going to 
				public Actions       NextAction;
        
				public uc_StateChangeInfo (
					States      p1,
					Transitions p2,
					Actions     p3)
				{
					this.State      = p1;
					this.Transition = p2;
					this.NextAction = p3;
				}
			}
    
			private class uc_StateChangeEvents 
			{
				private uc_StateChangeInfo[] Elements = 
			{
				new uc_StateChangeInfo (States.OscString,      Transitions.Entry, Actions.OscStart),
				new uc_StateChangeInfo (States.OscString,      Transitions.Exit,  Actions.OscEnd),
				new uc_StateChangeInfo (States.DcsPassthrough, Transitions.Entry, Actions.Hook),
				new uc_StateChangeInfo (States.DcsPassthrough, Transitions.Exit,  Actions.Unhook)
			};
        
				public uc_StateChangeEvents ()
				{
				}
        
				public System.Boolean GetStateChangeAction (
					States      State, 
					Transitions Transition,
					ref Actions     NextAction)
				{
					uc_StateChangeInfo Element;
        
					for (System.Int32 i = 0; i < Elements.Length; i++)
					{
						Element = Elements[i];
        
						if (State      == Element.State &&
							Transition == Element.Transition)
						{
							NextAction = Element.NextAction;
							return true;
						}
					}
                    
					return false;
				} 
			}
    
			private struct uc_CharEventInfo
			{
				public States        CurState;
				public System.Char   CharFrom;
				public System.Char   CharTo;
				public Actions       NextAction;
				public States        NextState;  // the next state we are going to 
        
				public uc_CharEventInfo (
					States  p1,
					System.Char   p2,
					System.Char   p3,
					Actions p4,
					States  p5)
				{
					this.CurState   = p1;
					this.CharFrom   = p2;
					this.CharTo     = p3;
					this.NextAction = p4;
					this.NextState  = p5;
				}
			}
        
			private class uc_CharEvents 
			{
				public System.Boolean GetStateEventAction (
					States        CurState, 
					System.Char   CurChar, 
					ref States    NextState,
					ref Actions   NextAction)
				{
					uc_CharEventInfo Element;
    
					// Codes A0-FF are treated exactly the same way as 20-7F
					// so we can keep are state table smaller by converting before we look
					// up the event associated with the character
    
					if (CurChar >= '\xA0' &&
						CurChar <= '\xFF')
					{
						CurChar -= '\x80';
					}
        
					for (System.Int32 i = 0; i < uc_CharEvents.Elements.Length; i++)
					{
						Element = uc_CharEvents.Elements[i];
        
						if (CurChar  >= Element.CharFrom &&
							CurChar  <= Element.CharTo   &&
							(CurState == Element.CurState || Element.CurState == States.Anywhere))
						{
							NextState  = Element.NextState;
							NextAction = Element.NextAction;
							return true;
						}
					}
                    
					return false;
				}

				public uc_CharEvents ()
				{
				}

				public static uc_CharEventInfo[] Elements = 
			{
				new uc_CharEventInfo (States.Anywhere,      '\x1B', '\x1B', Actions.NewCollect, States.Escape),
				new uc_CharEventInfo (States.Anywhere,      '\x18', '\x18', Actions.Execute,    States.Ground),
				new uc_CharEventInfo (States.Anywhere,      '\x1A', '\x1A', Actions.Execute,    States.Ground),
				new uc_CharEventInfo (States.Anywhere,      '\x1A', '\x1A', Actions.Execute,    States.Ground),
				new uc_CharEventInfo (States.Anywhere,      '\x80', '\x8F', Actions.Execute,    States.Ground),
				new uc_CharEventInfo (States.Anywhere,      '\x91', '\x97', Actions.Execute,    States.Ground),
				new uc_CharEventInfo (States.Anywhere,      '\x99', '\x99', Actions.Execute,    States.Ground),
				new uc_CharEventInfo (States.Anywhere,      '\x9A', '\x9A', Actions.Execute,    States.Ground),
				new uc_CharEventInfo (States.Anywhere,      '\x9C', '\x9C', Actions.Execute,    States.Ground),
				new uc_CharEventInfo (States.Anywhere,      '\x98', '\x98', Actions.None,       States.SosPmApcString),
				new uc_CharEventInfo (States.Anywhere,      '\x9E', '\x9F', Actions.None,       States.SosPmApcString),
				new uc_CharEventInfo (States.Anywhere,      '\x90', '\x90', Actions.NewCollect, States.DcsEntry),
				new uc_CharEventInfo (States.Anywhere,      '\x9D', '\x9D', Actions.None,       States.OscString),
				new uc_CharEventInfo (States.Anywhere,      '\x9B', '\x9B', Actions.NewCollect, States.CsiEntry),
				new uc_CharEventInfo (States.Ground,        '\x00', '\x17', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.Ground,        '\x00', '\x17', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.Ground,        '\x19', '\x19', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.Ground,        '\x1C', '\x1F', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.Ground,        '\x20', '\x7F', Actions.Print,      States.None),
				new uc_CharEventInfo (States.Ground,        '\x80', '\x8F', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.Ground,        '\x91', '\x9A', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.Ground,        '\x9C', '\x9C', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.EscapeIntrmdt, '\x00', '\x17', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.EscapeIntrmdt, '\x19', '\x19', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.EscapeIntrmdt, '\x1C', '\x1F', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.EscapeIntrmdt, '\x20', '\x2F', Actions.Collect,    States.None),
				new uc_CharEventInfo (States.EscapeIntrmdt, '\x30', '\x7E', Actions.Dispatch,   States.Ground),
				new uc_CharEventInfo (States.Escape,        '\x00', '\x17', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.Escape,        '\x19', '\x19', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.Escape,        '\x1C', '\x1F', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.Escape,        '\x58', '\x58', Actions.None,       States.SosPmApcString),
				new uc_CharEventInfo (States.Escape,        '\x5E', '\x5F', Actions.None,       States.SosPmApcString),
				new uc_CharEventInfo (States.Escape,        '\x50', '\x50', Actions.Collect,    States.DcsEntry),
				new uc_CharEventInfo (States.Escape,        '\x5D', '\x5D', Actions.None,       States.OscString),
				new uc_CharEventInfo (States.Escape,        '\x5B', '\x5B', Actions.Collect,    States.CsiEntry),
				new uc_CharEventInfo (States.Escape,        '\x30', '\x4F', Actions.Dispatch,   States.Ground),
				new uc_CharEventInfo (States.Escape,        '\x51', '\x57', Actions.Dispatch,   States.Ground),
				new uc_CharEventInfo (States.Escape,        '\x59', '\x5A', Actions.Dispatch,   States.Ground),
				new uc_CharEventInfo (States.Escape,        '\x5C', '\x5C', Actions.Dispatch,   States.Ground),
				new uc_CharEventInfo (States.Escape,        '\x60', '\x7E', Actions.Dispatch,   States.Ground),
				new uc_CharEventInfo (States.Escape,        '\x20', '\x2F', Actions.Collect,    States.EscapeIntrmdt),
				new uc_CharEventInfo (States.CsiEntry,      '\x00', '\x17', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.CsiEntry,      '\x19', '\x19', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.CsiEntry,      '\x1C', '\x1F', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.CsiEntry,      '\x20', '\x2F', Actions.Collect,    States.CsiIntrmdt),
				new uc_CharEventInfo (States.CsiEntry,      '\x3A', '\x3A', Actions.None,       States.CsiIgnore),
				new uc_CharEventInfo (States.CsiEntry,      '\x3C', '\x3F', Actions.Collect,    States.CsiParam),
				new uc_CharEventInfo (States.CsiEntry,      '\x3C', '\x3F', Actions.Collect,    States.CsiParam),
				new uc_CharEventInfo (States.CsiEntry,      '\x30', '\x39', Actions.Param,      States.CsiParam),
				new uc_CharEventInfo (States.CsiEntry,      '\x3B', '\x3B', Actions.Param,      States.CsiParam),
				new uc_CharEventInfo (States.CsiEntry,      '\x3C', '\x3F', Actions.Collect,    States.CsiParam),
				new uc_CharEventInfo (States.CsiEntry,      '\x40', '\x7E', Actions.Dispatch,   States.Ground),
				new uc_CharEventInfo (States.CsiParam,      '\x00', '\x17', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.CsiParam,      '\x19', '\x19', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.CsiParam,      '\x1C', '\x1F', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.CsiParam,      '\x30', '\x39', Actions.Param,      States.None),
				new uc_CharEventInfo (States.CsiParam,      '\x3B', '\x3B', Actions.Param,      States.None),
				new uc_CharEventInfo (States.CsiParam,      '\x3A', '\x3A', Actions.None,       States.CsiIgnore),
				new uc_CharEventInfo (States.CsiParam,      '\x3C', '\x3F', Actions.None,       States.CsiIgnore),
				new uc_CharEventInfo (States.CsiParam,      '\x20', '\x2F', Actions.Collect,    States.CsiIntrmdt),
				new uc_CharEventInfo (States.CsiParam,      '\x40', '\x7E', Actions.Dispatch,   States.Ground),
				new uc_CharEventInfo (States.CsiIgnore,     '\x00', '\x17', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.CsiIgnore,     '\x19', '\x19', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.CsiIgnore,     '\x1C', '\x1F', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.CsiIgnore,     '\x40', '\x7E', Actions.None,       States.Ground),
				new uc_CharEventInfo (States.CsiIntrmdt,    '\x00', '\x17', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.CsiIntrmdt,    '\x19', '\x19', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.CsiIntrmdt,    '\x1C', '\x1F', Actions.Execute,    States.None),
				new uc_CharEventInfo (States.CsiIntrmdt,    '\x20', '\x2F', Actions.Collect,    States.None),
				new uc_CharEventInfo (States.CsiIntrmdt,    '\x30', '\x3F', Actions.None,       States.CsiIgnore),
				new uc_CharEventInfo (States.CsiIntrmdt,    '\x40', '\x7E', Actions.Dispatch,   States.Ground),
				new uc_CharEventInfo (States.SosPmApcString,'\x9C', '\x9C', Actions.None,       States.Ground),
				new uc_CharEventInfo (States.DcsEntry,      '\x20', '\x2F', Actions.Collect,    States.DcsIntrmdt),
				new uc_CharEventInfo (States.DcsEntry,      '\x3A', '\x3A', Actions.None,       States.DcsIgnore),
				new uc_CharEventInfo (States.DcsEntry,      '\x30', '\x39', Actions.Param,      States.DcsParam),
				new uc_CharEventInfo (States.DcsEntry,      '\x3B', '\x3B', Actions.Param,      States.DcsParam),
				new uc_CharEventInfo (States.DcsEntry,      '\x3C', '\x3F', Actions.Collect,    States.DcsParam),
				new uc_CharEventInfo (States.DcsEntry,      '\x40', '\x7E', Actions.None,       States.DcsPassthrough),
				new uc_CharEventInfo (States.DcsIntrmdt,    '\x30', '\x3F', Actions.None,       States.DcsIgnore),
				new uc_CharEventInfo (States.DcsIntrmdt,    '\x40', '\x7E', Actions.None,       States.DcsPassthrough),
				new uc_CharEventInfo (States.DcsIgnore,     '\x9C', '\x9C', Actions.None,       States.Ground),
				new uc_CharEventInfo (States.DcsParam,      '\x30', '\x39', Actions.Param,      States.None),
				new uc_CharEventInfo (States.DcsParam,      '\x3B', '\x3B', Actions.Param,      States.None),
				new uc_CharEventInfo (States.DcsParam,      '\x20', '\x2F', Actions.Collect,    States.DcsIntrmdt),
				new uc_CharEventInfo (States.DcsParam,      '\x3A', '\x3A', Actions.None,       States.DcsIgnore),
				new uc_CharEventInfo (States.DcsParam,      '\x3C', '\x3F', Actions.None,       States.DcsIgnore),
				new uc_CharEventInfo (States.DcsPassthrough,'\x00', '\x17', Actions.Put,        States.None),
				new uc_CharEventInfo (States.DcsPassthrough,'\x19', '\x19', Actions.Put,        States.None),
				new uc_CharEventInfo (States.DcsPassthrough,'\x1C', '\x1F', Actions.Put,        States.None),
				new uc_CharEventInfo (States.DcsPassthrough,'\x20', '\x7E', Actions.Put,        States.None),
				new uc_CharEventInfo (States.DcsPassthrough,'\x9C', '\x9C', Actions.None,       States.Ground),
				new uc_CharEventInfo (States.OscString,     '\x20', '\x7F', Actions.OscPut,     States.None),
				new uc_CharEventInfo (States.OscString,     '\x9C', '\x9C', Actions.None,       States.Ground)
			};
			}
		}    

		private class uc_TelnetParser
		{
			public event NvtParserEventHandler NvtParserEvent;
			States State = States.Ground;
			System.Char   CurChar     = '\0';
			System.String CurSequence = "";
        
			System.Collections.ArrayList ParamList = new System.Collections.ArrayList ();
			uc_CharEvents        CharEvents        = new uc_CharEvents ();
			uc_StateChangeEvents StateChangeEvents = new uc_StateChangeEvents ();
			uc_Params            CurParams         = new uc_Params ();

			public uc_TelnetParser ()
			{
			}

			public void ParseString (System.String InString)
			{
				States        NextState        = States.None;
				NvtActions    NextAction       = NvtActions.None;
				NvtActions    StateExitAction  = NvtActions.None;
				NvtActions    StateEntryAction = NvtActions.None;
    
				foreach (System.Char C in InString)
				{
					this.CurChar = C;
   
					// Get the next state and associated action based 
					// on the current state and char event
					CharEvents.GetStateEventAction (State, CurChar, ref NextState, ref NextAction);
    
					// execute any actions arising from leaving the current state
					if  (NextState != States.None && NextState != this.State)
					{
						// check for state exit actions
						StateChangeEvents.GetStateChangeAction (this.State, Transitions.Exit, ref StateExitAction);
    
						// Process the exit action
						if (StateExitAction != NvtActions.None) DoAction (StateExitAction);
    
					}
    
					// process the action specified
					if (NextAction != NvtActions.None) DoAction (NextAction);
    
					// set the new parser state and execute any actions arising entering the new state
					if  (NextState != States.None && NextState != this.State)
					{
						// change the parsers state attribute
						this.State = NextState;
    
						// check for state entry actions
						StateChangeEvents.GetStateChangeAction (this.State, Transitions.Entry, ref StateExitAction);
    
						// Process the entry action
						if (StateEntryAction != NvtActions.None) DoAction (StateEntryAction);
					}
				}
			}
        
			private void DoAction (NvtActions NextAction)
			{
				// Manage the contents of the Sequence and Param Variables
				switch (NextAction)
				{
					case NvtActions.Dispatch:
					case NvtActions.Collect:
						this.CurSequence += CurChar.ToString ();
						break;
    
					case NvtActions.NewCollect:
						this.CurSequence = CurChar.ToString ();
						this.CurParams.Clear ();
						break;
    
					case NvtActions.Param:
						this.CurParams.Add (CurChar);
						break;
    
					default:
						break;
				}
    
				// send the external event requests
				switch (NextAction)
				{
					case NvtActions.Dispatch:

						//                    System.Console.Write ("Sequence = {0}, Char = {1}, PrmCount = {2}, State = {3}, NextAction = {4}\n",
						//                        this.CurSequence, (int) this.CurChar, this.CurParams.Count (), 
						//                        this.State, NextAction);

						NvtParserEvent (this, new NvtParserEventArgs (NextAction, CurChar, CurSequence, CurParams));
						break;

					case NvtActions.Execute:
					case NvtActions.SendUp:
						NvtParserEvent (this, new NvtParserEventArgs (NextAction, CurChar, CurSequence, CurParams));
    
						//                    System.Console.Write ("Sequence = {0}, Char = {1}, PrmCount = {2}, State = {3}, NextAction = {4}\n",
						//                        this.CurSequence, (int) this.CurChar, this.CurParams.Count (), 
						//                        this.State, NextAction);
						break;
					default:
						break; 
				}
    
    
				switch (NextAction)
				{
					case NvtActions.Dispatch:
						this.CurSequence = "";
						this.CurParams.Clear ();
						break;

					default:
						break;
				}
			}
    
			private enum States 
			{
				None              = 0,
				Ground            = 1,
				Command           = 2,
				Anywhere          = 3,
				Synch             = 4,
				Negotiate         = 5,  
				SynchNegotiate    = 6,  
				SubNegotiate      = 7,  
				SubNegValue       = 8,  
				SubNegParam       = 9,  
				SubNegEnd         = 10,  
				SynchSubNegotiate = 11,  
			}
        
			private enum Transitions 
			{
				None  = 0,
				Entry = 1,
				Exit  = 2,
			}
        
			private struct uc_StateChangeInfo
			{
				public States        State;
				public Transitions   Transition;    // the next state we are going to 
				public NvtActions    NextAction;
        
				public uc_StateChangeInfo (
					States      p1,
					Transitions p2,
					NvtActions  p3)
				{
					this.State      = p1;
					this.Transition = p2;
					this.NextAction = p3;
				}
			}
    
			private class uc_StateChangeEvents 
			{
				private uc_StateChangeInfo[] Elements = 
			{
				new uc_StateChangeInfo (States.None, Transitions.None, NvtActions.None),
				};
        
				public uc_StateChangeEvents ()
				{
				}
        
				public System.Boolean GetStateChangeAction (
					States      State, 
					Transitions Transition,
					ref NvtActions  NextAction)
				{
					uc_StateChangeInfo Element;
        
					for (System.Int32 i = 0; i < Elements.Length; i++)
					{
						Element = Elements[i];
        
						if (State      == Element.State &&
							Transition == Element.Transition)
						{
							NextAction = Element.NextAction;
							return true;
						}
					}
                    
					return false;
				} 
			}
    
			private struct uc_CharEventInfo
			{
				public States        CurState;
				public System.Char   CharFrom;
				public System.Char   CharTo;
				public NvtActions    NextAction;
				public States        NextState;  // the next state we are going to 
        
				public uc_CharEventInfo (
					States  p1,
					System.Char   p2,
					System.Char   p3,
					NvtActions    p4,
					States  p5)
				{
					this.CurState   = p1;
					this.CharFrom   = p2;
					this.CharTo     = p3;
					this.NextAction = p4;
					this.NextState  = p5;
				}
			}
        
			private class uc_CharEvents 
			{
				public System.Boolean GetStateEventAction (
					States         CurState, 
					System.Char    CurChar, 
					ref States     NextState,
					ref NvtActions NextAction)
				{
					uc_CharEventInfo Element;
    
        
					for (System.Int32 i = 0; i < uc_CharEvents.Elements.Length; i++)
					{
						Element = uc_CharEvents.Elements[i];
        
						if (CurChar  >= Element.CharFrom &&
							CurChar  <= Element.CharTo   &&
							(CurState == Element.CurState || Element.CurState == States.Anywhere))
						{
							NextState  = Element.NextState;
							NextAction = Element.NextAction;
							return true;
						}
					}
                    
					return false;
				}

				public uc_CharEvents ()
				{
				}

				public static uc_CharEventInfo[] Elements = 
			{
				new uc_CharEventInfo (States.Ground,       (char) 000, (char) 254, NvtActions.SendUp,     States.None),
				new uc_CharEventInfo (States.Ground,       (char) 255, (char) 255, NvtActions.None,       States.Command),
				new uc_CharEventInfo (States.Command,      (char) 000, (char) 239, NvtActions.SendUp,     States.Ground),
				new uc_CharEventInfo (States.Command,      (char) 240, (char) 241, NvtActions.None,       States.Ground),
				new uc_CharEventInfo (States.Command,      (char) 242, (char) 249, NvtActions.Execute,    States.Ground),
				new uc_CharEventInfo (States.Command,      (char) 250, (char) 250, NvtActions.NewCollect, States.SubNegotiate),
				new uc_CharEventInfo (States.Command,      (char) 251, (char) 254, NvtActions.NewCollect, States.Negotiate),
				new uc_CharEventInfo (States.Command,      (char) 255, (char) 255, NvtActions.SendUp,     States.Ground),
				new uc_CharEventInfo (States.SubNegotiate, (char) 000, (char) 255, NvtActions.Collect,    States.SubNegValue),
				new uc_CharEventInfo (States.SubNegValue,  (char) 000, (char) 001, NvtActions.Collect,    States.SubNegParam),
				new uc_CharEventInfo (States.SubNegValue,  (char) 002, (char) 255, NvtActions.None,       States.Ground),
				new uc_CharEventInfo (States.SubNegParam,  (char) 000, (char) 254, NvtActions.Param,      States.None),
				new uc_CharEventInfo (States.SubNegParam,  (char) 255, (char) 255, NvtActions.None,       States.SubNegEnd),
				new uc_CharEventInfo (States.SubNegEnd,    (char) 000, (char) 239, NvtActions.None,       States.Ground),
				new uc_CharEventInfo (States.SubNegEnd,    (char) 240, (char) 240, NvtActions.Dispatch,   States.Ground),
				new uc_CharEventInfo (States.SubNegEnd,    (char) 241, (char) 254, NvtActions.None,       States.Ground),
				new uc_CharEventInfo (States.SubNegEnd,    (char) 255, (char) 255, NvtActions.Param,      States.SubNegParam),
				new uc_CharEventInfo (States.Negotiate,    (char) 000, (char) 255, NvtActions.Dispatch,   States.Ground),
				};
			}
		}

		#endregion
		#region Private Structs
		private struct ParserEventArgs 
		{
			public Actions           Action;
			public System.Char       CurChar;
			public System.String     CurSequence;
			public uc_Params         CurParams;

			public ParserEventArgs (
				Actions           p1,
				System.Char       p2,
				System.String     p3,
				uc_Params         p4)
			{
				Action       = p1;
				CurChar      = p2;
				CurSequence  = p3;
				CurParams    = p4;
			}
		}

		private struct CharAttribStruct
		{
			public System.Boolean       IsBold;
			public System.Boolean       IsDim;
			public System.Boolean       IsUnderscored;
			public System.Boolean       IsBlinking;
			public System.Boolean       IsInverse;
			public System.Boolean       IsPrimaryFont;
			public System.Boolean       IsAlternateFont;
			public System.Boolean       UseAltColor;
			public System.Drawing.Color AltColor;
			public System.Boolean       UseAltBGColor;
			public System.Drawing.Color AltBGColor;
			public uc_Chars             GL;
			public uc_Chars             GR;
			public uc_Chars             GS;
			public System.Boolean       IsDECSG;

			public CharAttribStruct ( 
				System.Boolean       p1,
				System.Boolean       p2,
				System.Boolean       p3,
				System.Boolean       p4,
				System.Boolean       p5,
				System.Boolean       p6,
				System.Boolean       p7,
				System.Boolean       p12,
				System.Drawing.Color p13,
				System.Boolean       p14,
				System.Drawing.Color p15,
				uc_Chars             p16,
				uc_Chars             p17,
				uc_Chars             p18,
				System.Boolean       p19)
			{
				IsBold          = p1;
				IsDim           = p2;
				IsUnderscored   = p3;
				IsBlinking      = p4;
				IsInverse       = p5;
				IsPrimaryFont   = p6;
				IsAlternateFont = p7;
				UseAltColor     = p12;
				AltColor        = p13;
				UseAltBGColor   = p14;
				AltBGColor      = p15;
				GL              = p16;
				GR              = p17;
				GS              = p18;
				IsDECSG         = p19;
			}

		}    

		private struct NvtParserEventArgs 
		{
			public NvtActions        Action;
			public System.Char       CurChar;
			public System.String     CurSequence;
			public uc_Params         CurParams;

			public NvtParserEventArgs (
				NvtActions        p1,
				System.Char       p2,
				System.String     p3,
				uc_Params         p4)
			{
				Action       = p1;
				CurChar      = p2;
				CurSequence  = p3;
				CurParams    = p4;
			}
		}

		#endregion
		#region Private Enums
		private enum NvtCommand 
		{
			SE    = 240, 
			NOP   = 241, 
			DM    = 242, 
			BREAK = 243, 
			IP    = 244, 
			AO    = 245, 
			AYT   = 246, 
			EC    = 247, 
			EL    = 248, 
			GA    = 249, 
			SB    = 250, 
			WILL  = 251, 
			WONT  = 252, 
			DO    = 253, 
			DONT  = 254, 
			IAC   = 255, 
		}
    
		private enum NvtOption
		{
			ECHO     = 1,   // echo
			SGA      = 3,   // suppress go ahead
			STATUS   = 5,   // status
			TM       = 6,   // timing mark
			TTYPE    = 24,  // terminal type
			NAWS     = 31,  // window size
			TSPEED   = 32,  // terminal speed
			LFLOW    = 33,  // remote flow control
			LINEMODE = 34,  // linemode
			ENVIRON  = 36,  // environment variables
		}

		private enum NvtActions 
		{
			None       = 0,
			SendUp     = 1,
			Dispatch   = 2,
			Collect    = 4,
			NewCollect = 5,
			Param      = 6,
			Execute    = 7,
		}

		private enum Actions 
		{
			None       = 0,
			Dispatch   = 1,
			Execute    = 2,
			Ignore     = 3,
			Collect    = 4,
			NewCollect = 5,
			Param      = 6,
			OscStart   = 8,
			OscPut     = 9,
			OscEnd     = 10,
			Hook       = 11,
			Unhook     = 12,
			Put        = 13,
			Print      = 14
		}

		#endregion
	}
	#region Routrek SSH Reader Class
	class Reader : Routrek.SSHC.ISSHConnectionEventReceiver, Routrek.SSHC.ISSHChannelEventReceiver 
	{
		private TerminalEmulator Terminal;
		public Reader (object obj)
		{
			Terminal = (TerminalEmulator) obj;
		}
		public Routrek.SSHC.SSHConnection _conn;
		public bool _ready;
		public void OnData(byte[] data, int offset, int length) 
		{
			Terminal.Write(data, offset, length);
			//rtb.AppendText(Encoding.ASCII.GetString(data, offset, length));
			//System.Console.Write(Encoding.ASCII.GetString(data, offset, length));
		}
		public void OnDebugMessage(bool always_display, byte[] data) 
		{
			//Debug.WriteLine("DEBUG: "+ Encoding.ASCII.GetString(data));
		}
		public void OnIgnoreMessage(byte[] data) 
		{
			//Debug.WriteLine("Ignore: "+ Encoding.ASCII.GetString(data));
		}
		public void OnAuthenticationPrompt(string[] msg) 
		{
			//Debug.WriteLine("Auth Prompt "+msg[0]);
		}

		public void OnError(Exception error, string msg) 
		{
			//Debug.WriteLine("ERROR: "+ msg);
		}
		public void OnChannelClosed() 
		{
			//Debug.WriteLine("Channel closed");
			_conn.Disconnect("");
			//_conn.AsyncReceive(this);
		}
		public void OnChannelEOF() 
		{
			_pf.Close();
			//Debug.WriteLine("Channel EOF");
		}
		public void OnExtendedData(int type, byte[] data) 
		{
			//Debug.WriteLine("EXTENDED DATA");
		}
		public void OnConnectionClosed() 
		{
			//Debug.WriteLine("Connection closed");
		}
		public void OnUnknownMessage(byte type, byte[] data) 
		{
			//Debug.WriteLine("Unknown Message " + type);
		}
		public void OnChannelReady() 
		{
			_ready = true;
		}
		public void OnChannelError(Exception error, string msg) 
		{
			//Debug.WriteLine("Channel ERROR: "+ msg);
		}
		public void OnMiscPacket(byte type, byte[] data, int offset, int length) 
		{
		}

		public Routrek.SSHC.PortForwardingCheckResult CheckPortForwardingRequest(string host, int port, string originator_host, int originator_port) 
		{
			Routrek.SSHC.PortForwardingCheckResult r = new Routrek.SSHC.PortForwardingCheckResult();
			r.allowed = true;
			r.channel = this;
			return r;
		}
		public void EstablishPortforwarding(Routrek.SSHC.ISSHChannelEventReceiver rec, Routrek.SSHC.SSHChannel channel) 
		{
			_pf = channel;
		}

		public Routrek.SSHC.SSHChannel _pf;
	}
	#endregion
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions