using System;
using System.Threading;
using Microsoft.SPOT;
namespace WIFI
{
// A telnet server with minimal TELNET and ANSI support
public class TelnetServer
{
private const char IAC = (char)255; // Interpret as Command
private const char WILL = (char)251;
private const char WONT = (char)252;
private const char DO = (char)253;
private const char DONT = (char)254;
private const char ECHO = (char)1;
private const char SUPPRESSGOAHEAD = (char)3;
// When true, echo input data
public bool EchoEnabled { get; set; }
// Reference to the socket
private SimpleSocket _Sock;
// Local data buffer
private string _Buffer = "";
// Returns the amount of bytes waiting for this.Input()
public int InputBuffer { get { this._Read(); return this._Buffer.Length; } }
// The client address
public string RemoteAddress { get { return this._Sock.Hostname; } }
// Some commands, like color, will be buffered to avoid small data packets. This actually speeds up the server.
private string _WriteBuffer = "";
// Creates a new telnet server
public TelnetServer(SimpleSocket Socket)
{
this._Sock = Socket;
this.EchoEnabled = true;
// We handle our line endings ourself
this._Sock.LineEnding = "";
}
// Closes the connection
public void Close()
{
this._Sock.Close();
}
// True when there's a connection
public bool IsConnected { get { return this._Sock.IsConnected; } }
// Listens and waits until we have a connection
public void Listen()
{
this._Sock.Listen();
// We handle echoing ourselves
this._Write(new char[] { IAC, DONT, ECHO }, true);
this._Write(new char[] { IAC, WILL, ECHO }, true);
// We want to receive every byte when it's received, don't wait for it!
this._Write(new char[] { IAC, DO, SUPPRESSGOAHEAD }, true);
this._Write(new char[] { IAC, WILL, SUPPRESSGOAHEAD });
Thread.Sleep(100);
this._Read();
}
// Writes data to the client
private void _Write(string Data, bool Buffered = false)
{
if (Buffered)
{
this._WriteBuffer += Data;
}
else
{
string Out = this._WriteBuffer + Data;
this._WriteBuffer = "";
if (this.IsConnected) this._Sock.Send(Out);
}
}
// Writes data to the client
private void _Write(char[] Data, bool Buffered = false)
{
this._Write(new string(Data), Buffered);
}
// Sends a beep to the client
public void Beep()
{
this._Write("\x07");
}
// Reads data from the client
private void _Read()
{
string NewData = this._Sock.Receive();
if (NewData == "") return;
for (int i = 0; i < NewData.Length; ++i)
{
if (NewData[i] == IAC)
{
char Command = NewData[++i];
// Lets only support DO, DONT, WILL and WONT for now
if (Command == DO || Command == DONT || Command == WILL || Command == WONT)
{
// Lets see what the other party wants to tell us
char Option = NewData[++i];
// Server will echo
if (Command == DO && Option == ECHO) this._Write(new char[] { IAC, WILL, ECHO });
// Client shouldn't echo
else if (Command == WILL && Option == ECHO) this._Write(new char[] { IAC, DONT, ECHO });
// We will suppress go-aheads
else if (Command == DO && Option == SUPPRESSGOAHEAD) this._Write(new char[] { IAC, WILL, SUPPRESSGOAHEAD });
// Fine that you will ;-)
else if (Command == WILL) { /* Ignored */ }
// But I won't do the rest!
else this._Write(new char[] { IAC, WONT, Option });
}
}
else
{
// Backspace
if (NewData[i] == '\x08')
{
if (this._Buffer.Length > 0)
{
this._Buffer = this._Buffer.Substring(0, this._Buffer.Length - 1);
if (EchoEnabled) this._Write("\x08 \x08");
}
}
// Escape
else if (NewData[i] == '\x1b')
{
if (this._Buffer.Length > 0)
{
if (EchoEnabled)
for (int Cnt = 0; Cnt < this._Buffer.Length; ++Cnt)
this._Write("\x08 \x08");
this._Buffer = "";
}
}
// All other characters
else
{
this._Buffer += NewData[i];
if (EchoEnabled) this._Write(NewData.Substring(i, 1));
}
}
}
}
// Reads out input from the terminal
public string Input(int Length = 0, bool Blocking = true)
{
while (true)
{
if (!this.IsConnected) return "";
this._Read();
// Amount of bytes?
if (Length > 0 && this._Buffer.Length >= Length)
{
// Gets the data
string Data = this._Buffer.Substring(0, Length);
// Removes the data from the buffer
this._Buffer = this._Buffer.Substring(Length);
return Data;
}
// Carriage return?
int Pos = this._Buffer.IndexOf('\r');
if (Length == 0 && Pos >= 0)
{
// Gets the data
string Data = this._Buffer.Substring(0, Pos);
// Removes the data from the buffer
this._Buffer = this._Buffer.Substring(Pos + 1);
// Removes additional newline if sent
if (this._Buffer.Substring(0, 1) == "\n") this._Buffer = this._Buffer.Substring(1);
return Data;
}
// Ctrl+C ?
Pos = this._Buffer.IndexOf('\x03');
if (Length == 0 && Pos >= 0)
{
if (this.EchoEnabled) this.Print("\x08^C\r\n");
this._Buffer = "";
return "\x03";
}
// Do we disable blocking?
if (!Blocking) return "";
Thread.Sleep(100);
}
}
// Prints a text to the screen
public void Print(string Text, bool NoNewLine = false, bool Buffered = false)
{
if (NoNewLine)
this._Write(Text, Buffered);
else
this._Write(Text + "\r\n", Buffered);
}
// Clears the terminal's screen
public void ClearScreen()
{
this._Write("\x1b[2J");
}
// Available colors
public enum Colors
{
/// Black
Black = 0,
/// Blue
Blue = 1,
/// Green
Green = 2,
/// Cyan
Cyan = 3,
/// Red
Red = 4,
/// Magenta
Magenta = 5,
/// Brown/orange
Brown = 6,
/// White
White = 7,
/// Gray
Gray = 8,
/// Light blue
LightBlue = 9,
/// Light green
LightGreen = 10,
/// Light cyan
LightCyan = 11,
/// Light red
LightRed = 12,
/// Light magenta
LightMagenta = 13,
/// Yellow
Yellow = 14,
/// High-intensity white
HighIntensityWhite = 15,
/// The default of the terminal
TerminalDefault = 255,
}
// Sets the terminal colors
public void Color(Colors Foreground)
{
this.Color(Foreground, (Colors)17);
}
// Sets the terminal colors
public void Color(Colors Foreground, Colors Background)
{
string Data = "";
// Foreground color parameters
if ((int)Foreground == 0) Data += ";00;30"; // black
if ((int)Foreground == 1) Data += ";00;34"; // blue
if ((int)Foreground == 2) Data += ";00;32"; // green
if ((int)Foreground == 3) Data += ";00;36"; // cyan
if ((int)Foreground == 4) Data += ";00;31"; // red
if ((int)Foreground == 5) Data += ";00;35"; // magenta
if ((int)Foreground == 6) Data += ";00;33"; // brown
if ((int)Foreground == 7) Data += ";00;37"; // white
if ((int)Foreground == 8) Data += ";01;30"; // gray
if ((int)Foreground == 9) Data += ";01;34"; // light blue
if ((int)Foreground == 10) Data += ";01;32"; // light green
if ((int)Foreground == 11) Data += ";01;36"; // light cyan
if ((int)Foreground == 12) Data += ";01;31"; // light red
if ((int)Foreground == 13) Data += ";01;35"; // light magenta
if ((int)Foreground == 14) Data += ";01;33"; // yellow
if ((int)Foreground == 15) Data += ";01;37"; // high-intensity white
if ((int)Foreground == 255) Data += ";00;39";// Default color
// Background color parameters
if ((int)Background == 0) Data += ";40"; // black
if ((int)Background == 1) Data += ";44"; // blue
if ((int)Background == 2) Data += ";42"; // green
if ((int)Background == 3) Data += ";46"; // cyan
if ((int)Background == 4) Data += ";41"; // red
if ((int)Background == 5) Data += ";45"; // magenta
if ((int)Background == 6) Data += ";43"; // brown
if ((int)Background == 7) Data += ";47"; // white
if ((int)Background == 8) Data += ";40"; // black
if ((int)Background == 9) Data += ";44"; // blue
if ((int)Background == 10) Data += ";42"; // green
if ((int)Background == 11) Data += ";46"; // cyan
if ((int)Background == 12) Data += ";41"; // red
if ((int)Background == 13) Data += ";45"; // magenta
if ((int)Background == 14) Data += ";43"; // brown
if ((int)Background == 15) Data += ";47"; // white
if ((int)Background == 255) Data += ";49"; // Default color
if (Data != "")
this._Write("\x1b[" + Data.Substring(1) + "m", true);
}
// Moves the cursor position
public void Locate(int Line, int Column, bool Buffered = false)
{
this._Write("\x1b[" + Line.ToString() + ";" + Column.ToString() + "f", Buffered);
}
}
}