Issue
I have a C# WPF application that is making a Telnet connection to write some content to a file on a Linux system from a Windows system. So say I have some text like this.
Here is a bit\tof text \r\n Followed by a new line.
Here is generally how the code goes:
string ipAddress = "11.11.11.11";
int port = 66;
TelnetConnection tc = new TelnetConnection(ipAddress, port);
string s = tc.Login("root", "password", 100);
string prompt = s.TrimEnd();
if (prompt != "$" && prompt != "#"){
throw new Exception("Connection failed");
}
tc.WriteLine("echo $'Here is a bit\tof text \r\n Followed by a new line.' >> MyFile.txt");
Here is the TelnetConnection class I use:\
enum Verbs
{
WILL = 251,
WONT = 252,
DO = 253,
DONT = 254,
IAC = 255
}
enum Options
{
SGA = 3
}
class TelnetConnection
{
TcpClient tcpSocket;
int TimeOutMs = 10;
public TelnetConnection(string Hostname, int Port)
{
tcpSocket = new TcpClient(Hostname, Port);
}
public string Login(string Username, string Password, int LoginTimeOutMs)
{
int oldTimeOutMs = TimeOutMs;
TimeOutMs = LoginTimeOutMs;
string s = Read();
if (!s.TrimEnd().EndsWith(":"))
throw new Exception("Failed to connect : no login prompt");
WriteLine(Username);
s += Read();
if (!s.TrimEnd().EndsWith(":"))
throw new Exception("Failed to connect : no password prompt");
WriteLine(Password);
s += Read();
TimeOutMs = oldTimeOutMs;
return s;
}
public void WriteLine(string cmd)
{
Write(cmd + "\n");
}
public void Write(string cmd)
{
if (!tcpSocket.Connected) return;
byte[] buf = System.Text.ASCIIEncoding.ASCII.GetBytes(cmd.Replace("\0xFF", "\0xFF\0xFF"));
tcpSocket.GetStream().Write(buf, 0, buf.Length);
System.Threading.Thread.Sleep(1000);
}
public string Read()
{
if (!tcpSocket.Connected) return null;
StringBuilder sb = new StringBuilder();
do
{
ParseTelnet(sb);
System.Threading.Thread.Sleep(TimeOutMs);
} while (tcpSocket.Available > 0);
return sb.ToString();
}
public bool IsConnected
{
get { return tcpSocket.Connected; }
}
void ParseTelnet(StringBuilder sb)
{
while (tcpSocket.Available > 0)
{
int input = tcpSocket.GetStream().ReadByte();
switch (input)
{
case -1:
break;
case (int)Verbs.IAC:
// interpret as command
int inputverb = tcpSocket.GetStream().ReadByte();
if (inputverb == -1) break;
switch (inputverb)
{
case (int)Verbs.IAC:
//literal IAC = 255 escaped, so append char 255 to string
sb.Append(inputverb);
break;
case (int)Verbs.DO:
case (int)Verbs.DONT:
case (int)Verbs.WILL:
case (int)Verbs.WONT:
// reply to all commands with "WONT", unless it is SGA (suppres go ahead)
int inputoption = tcpSocket.GetStream().ReadByte();
if (inputoption == -1) break;
tcpSocket.GetStream().WriteByte((byte)Verbs.IAC);
if (inputoption == (int)Options.SGA)
tcpSocket.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WILL : (byte)Verbs.DO);
else
tcpSocket.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WONT : (byte)Verbs.DONT);
tcpSocket.GetStream().WriteByte((byte)inputoption);
break;
default:
break;
}
break;
default:
sb.Append((char)input);
break;
}
}
}
}
When I go to check the file the it is written to like this
Here is a bitof text
Followed by a new line.
So the tab character isn't even read, but the new line is for some reason. Any ideas?
Solution
The correct answer is given by @Johannes Krackowizer but the explanation is missing a detail: the 'TelnetConnection' isn't a file. What you are doing is typing to the remote computer. @Greg M also mentions this.
When you send \t
in your string, you are sending a literal <tab>
character. The computer at the other end is trying to finish typing a file name for you because that's what happens when you hit <tab>
. If you want to get a tab back you need to send a \
and a t
. The t
you can just send, but the \
needs to be sent as \\
because \
is an escape character, as you know. So send:
"echo $'Here is a bit\\tof text \r\n Followed by a new line.' >> MyFile.txt"
Note the bit\\tof
with two backslashes. So why does \r\n
work? Because it's <Enter>
and <Ctrl>+<Enter>
, and the string you are typing is being typed within single quotes. When you use single quotes you can hit <Enter>
and keep typing until you are done and end with the final '
.
As others have mentioned, printf
is generally preferred:
"printf $'Here is a bit\\tof text \r\n Followed by a new line.\n' >> MyFile.txt"
Next, in your code, the backslash should also be escaped, so you probably need to escape those characters as well:
tc.WriteLine("printf $'Here is a bit\\\\tof text \\r\\n Followed by a new line.\\n' >> MyFile.txt");
Answered By - rand'Chris Answer Checked By - Terry (WPSolving Volunteer)