context: // VncSharp - .NET VNC Client Library
  // Copyright (C) 2008 David Humphrey
  //
  // This program is free software; you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation; either version 2 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program; if not, write to the Free Software
  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  
  using System;
  using System.Diagnostics;
  using System.Drawing;
  using System.IO;
  using System.Linq;
  using System.Net.Sockets;
  using System.Text;
  using System.Threading;
  using VncSharp.zlib.NET;
  // ReSharper disable ArrangeAccessorOwnerBody
  
  namespace VncSharp
  {
  	/// <summary>
  	/// Contains methods and properties to handle all aspects of the RFB Protocol versions 3.3 - 3.8.
  	/// </summary>
  	public class RfbProtocol
  	{
  		#region Constants
  		// ReSharper disable InconsistentNaming
  		// Version Constants
  		private const string RFB_VERSION_ZERO			= "RFB 000.000\n";
  
  		// Timeout Constants
  		public const int RECEIVE_TIMEOUT				= 15000;
  		public const int SEND_TIMEOUT					= 15000;
  		
  		// Encoding Constants
  		public const int RAW_ENCODING 					= 0;
  		public const int COPYRECT_ENCODING 				= 1;
  		public const int RRE_ENCODING 					= 2;
  		public const int CORRE_ENCODING					= 4;
  		public const int HEXTILE_ENCODING 				= 5;
  		public const int ZRLE_ENCODING 					= 16;
  
  		// Server to Client Message-Type constants
  		public const int FRAMEBUFFER_UPDATE 			= 0;
  		public const int SET_COLOUR_MAP_ENTRIES			= 1;
  		public const int BELL 							= 2;
  		public const int SERVER_CUT_TEXT 				= 3;
  
  		// Client to Server Message-Type constants
  		private const byte SET_PIXEL_FORMAT 			= 0;
  		private const byte SET_ENCODINGS 				= 2;
  		private const byte FRAMEBUFFER_UPDATE_REQUEST 	= 3;
  		private const byte KEY_EVENT 					= 4;
  		private const byte POINTER_EVENT 				= 5;
  		private const byte CLIENT_CUT_TEXT 				= 6;
  
          // Keyboard constants
  		public const int XK_BackSpace 	= 0xFF08;
  		public const int XK_Tab 		= 0xFF09;
  		public const int XK_Clear 		= 0xFF0B;
  		public const int XK_Return 		= 0xFF0D;
  		public const int XK_Pause 		= 0xFF13;
  		public const int XK_Sys_Req 	= 0xFF15;
  		public const int XK_Escape 		= 0xFF1B;
  		public const int XK_Home 		= 0xFF50;
  		public const int XK_Left 		= 0xFF51;
  		public const int XK_Up 			= 0xFF52;
  		public const int XK_Right 		= 0xFF53;
  		public const int XK_Down 		= 0xFF54;
  		public const int XK_Prior 		= 0xFF55;
  		public const int XK_Next 		= 0xFF56;
  		public const int XK_End 		= 0xFF57;
  		public const int XK_Select 		= 0xFF60;
  		public const int XK_Print 		= 0xFF61;
  		public const int XK_Execute 	= 0xFF62;
  		public const int XK_Insert 		= 0xFF63;
  		public const int XK_Menu 		= 0xFF67;
  		public const int XK_Cancel 		= 0xFF69;
  		public const int XK_Help 		= 0xFF6A;
  		public const int XK_Break 		= 0xFF6B;
  		public const int XK_F1 			= 0xFFBE;
  		public const int XK_F2 			= 0xFFBF;
  		public const int XK_F3 			= 0xFFC0;
  		public const int XK_F4 			= 0xFFC1;
  		public const int XK_F5 			= 0xFFC2;
  		public const int XK_F6 			= 0xFFC3;
  		public const int XK_F7 			= 0xFFC4;
  		public const int XK_F8 			= 0xFFC5;
  		public const int XK_F9 			= 0xFFC6;
  		public const int XK_F10 		= 0xFFC7;
  		public const int XK_F11 		= 0xFFC8;
  		public const int XK_F12 		= 0xFFC9;
  		public const int XK_Shift_L 	= 0xFFE1;
  		public const int XK_Shift_R 	= 0xFFE2;
  		public const int XK_Control_L 	= 0xFFE3;
  		public const int XK_Control_R 	= 0xFFE4;
  		public const int XK_Meta_L 		= 0xFFE7;
  		public const int XK_Meta_R 		= 0xFFE8;
  		public const int XK_Alt_L 		= 0xFFE9;
  		public const int XK_Alt_R 		= 0xFFEA;
  		public const int XK_Super_L 	= 0xFFEB;
  		public const int XK_Super_R 	= 0xFFEC;
  		public const int XK_Hyper_L 	= 0xFFED;
  		public const int XK_Hyper_R 	= 0xFFEE;
  		public const int XK_Delete 		= 0xFFFF;
  
  		// ReSharper restore InconsistentNaming
  		#endregion
  
  		private int verMajor;	// Major version of Protocol--probably 3
  		private int verMinor;	// Minor version of Protocol--probably 3, 7, or 8
  
  		private TcpClient tcp;			// Network object used to communicate with host
  		private NetworkStream stream;	// Stream object used to send/receive data
  		private BinaryWriter writer;	// sent and received, so these handle this.
  
  		/// <summary>
  		/// Gets the Protocol Version of the remote VNC Host--probably 3.3, 3.7, or 3.8.
  		/// </summary>
  		public float ServerVersion
  		{
  			get { return verMajor + verMinor * 0.1f; }
  		}
  
  		/// <summary>
  		/// Gets or sets the proxy identifier to be send when using UltraVNC's repeater functionality
  		/// </summary>
  		/// <value>
  		/// The proxy identifier.
  		/// </value>
  		// ReSharper disable once UnusedAutoPropertyAccessor.Local
  		private int ProxyID { get; set; }
  
  		public BinaryReader Reader { get; private set; }
  
  		public ZRLECompressedReader ZrleReader { get; private set; }
  
  	    /// <summary>
  		/// Attempt to connect to a remote VNC Host.
  		/// </summary>
  		/// <param name="host">The IP Address or Host Name of the VNC Host.</param>
  		/// <param name="port">The Port number on which to connect.  Usually this will be 5900, except in the case that the VNC Host is running on a different Display, in which case the Display number should be added to 5900 to determine the correct port.</param>
  		public void Connect(string host, int port)
  		{
  			if (host == null) throw new ArgumentNullException(nameof(host));
  
  			// Try to connect, passing any exceptions up to the caller, and if successful, 
  			// wrap a big endian Binary Reader and Binary Writer around the resulting stream.
  			tcp = new TcpClient {NoDelay = true}; // turn-off Nagle's Algorithm for better interactive performance with host.
  
  			tcp.ReceiveTimeout = RECEIVE_TIMEOUT; // set receive timeout (15s default)
  			tcp.SendTimeout = SEND_TIMEOUT;    // set send timeout to (15s default)
  			tcp.Connect(host, port);
  			stream = tcp.GetStream();
  
  			stream.ReadTimeout = RECEIVE_TIMEOUT; // set read timeout to (15s default)
  			stream.WriteTimeout = SEND_TIMEOUT;// set write timeout to (15s default)
  
  			// Most of the RFB protocol uses Big-Endian byte order, while
  			// .NET uses Little-Endian. These wrappers convert between the
  			// two.  See BigEndianReader and BigEndianWriter below for more details.
  			Reader = new BigEndianBinaryReader(stream);
  			writer = new BigEndianBinaryWriter(stream);
  			ZrleReader = new ZRLECompressedReader(stream);
  		}
  
  		/// <summary>
  		/// Closes the connection to the remote host.
  		/// </summary>
  		public void Close()
  		{
  			try {
  				writer.Close();
  				Reader.Close();
  				stream.Close();
  				tcp.Close();
  			} catch (Exception ex) {
  				Debug.Fail(ex.Message);
  			}
  		}
  		
  		/// <summary>
  		/// Reads VNC Host Protocol Version message (see RFB Doc v. 3.8 section 6.1.1)
  		/// </summary>
  		/// <exception cref="NotSupportedException">Thrown if the version of the host is not known or supported.</exception>
  		public void ReadProtocolVersion()
  		{
  			var b = Reader.ReadBytes(12);
  			string a = "";
  			string s = "";
  			for (int x = 0; x < 12; x++)
  				a += $"{b[x]} ";
  			for (int x = 0; x < 12; x++)
  				s += $"{Convert.ToChar(b[x])} ";
  
  			// As of the time of writing, the only supported versions are 3.3, 3.7, and 3.8.
  			if (Encoding.ASCII.GetString(b) == RFB_VERSION_ZERO) // Repeater functionality
  			{
  				verMajor = 0;
  				verMinor = 0;
  			}
  			// Added support for RealVNC 4.001 (Linux VNC Server) - Supports 3.8 Protocol
  
gt: 			else if (b[0] == 82 &&		// R