Windows automate telnet - c#

I would like to run a set of commands that would typically be run in telnet(from c#).
For example I would like to run the following
using System;
using System.Diagnostics;
namespace InteractWithConsoleApp
{
class Program
{
static void Main(string[] args)
{
ProcessStartInfo cmdStartInfo = new ProcessStartInfo();
cmdStartInfo.FileName = #"C:\Windows\System32\cmd.exe";
cmdStartInfo.RedirectStandardOutput = true;
cmdStartInfo.RedirectStandardError = true;
cmdStartInfo.RedirectStandardInput = true;
cmdStartInfo.UseShellExecute = false;
cmdStartInfo.CreateNoWindow = true;
Process cmdProcess = new Process();
cmdProcess.StartInfo = cmdStartInfo;
cmdProcess.ErrorDataReceived += cmd_Error;
cmdProcess.OutputDataReceived += cmd_DataReceived;
cmdProcess.EnableRaisingEvents = true;
cmdProcess.Start();
cmdProcess.BeginOutputReadLine();
cmdProcess.BeginErrorReadLine();
cmdProcess.StandardInput.WriteLine("telnet telehack.com");
int milliseconds = 2000;
System.Threading.Thread.Sleep(milliseconds);
cmdProcess.StandardInput.WriteLine("exit");
cmdProcess.StandardInput.WriteLine("exit");
cmdProcess.WaitForExit();
}
static void cmd_DataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(e.Data);
}
static void cmd_Error(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(e.Data);
}
}
}
and keep telnet open to run subsequent commands. For example for the question above I would like to run and receive the following output, but I don't receive any of the telnet output. It doesn't receive any output. This is related.
telnet telehack.com
> Connected to TELEHACK port 53
It is 2:33 pm on Tuesday, September 1, 2015 in Mountain View, California, USA.
There are 31 local users. There are 24906 hosts on the network.
May the command line live forever.
Command, one of the following:
? ac advent basic cal calc
ching clear clock cowsay date echo
eliza factor figlet finger fnord geoip
help hosts ipaddr joke login md5
morse newuser notes octopus phoon pig
ping primes privacy rain rand rfc
rig roll rot13 sleep starwars traceroute
units uptime usenet users uumap uupath
uuplot weather when zc zork zrun
.calc
calc>2+2
> 4

Based on comments I understand that you can use actual telnet protocol implementation instead of calling to telnet.exe, so
Form1.cs
using MinimalisticTelnet;
using System;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace Telnet
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private MinimalisticTelnet.TelnetConnection _tc;
private void Form1_Load(object sender, EventArgs e)
{
_tc = new TelnetConnection("telehack.com", 23);
}
private void timer1_Tick(object sender, EventArgs e)
{
ProcessOutput();
}
private void btnSendCommand_Click(object sender, EventArgs e)
{
if (_tc.IsConnected)
{
_tc.WriteLine(tbCommand.Text.Trim());
tbCommand.Clear();
tbCommand.Focus();
ProcessOutput();
}
}
private void ProcessOutput()
{
if (!_tc.IsConnected)
return;
var s = _tc.Read();
s = Regex.Replace(s, #"\x1b\[([0-9,A-Z]{1,2}(;[0-9]{1,2})?(;[0-9]{3})?)?[m|K]?", "");
tbOutput.AppendText(s);
}
}
}
TelnetInterface.cs
// minimalistic telnet implementation
// conceived by Tom Janssens on 2007/06/06 for codeproject
//
// http://www.corebvba.be
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
namespace MinimalisticTelnet
{
enum Verbs
{
WILL = 251,
WONT = 252,
DO = 253,
DONT = 254,
IAC = 255
}
enum Options
{
SGA = 3
}
class TelnetConnection
{
TcpClient tcpSocket;
int TimeOutMs = 100;
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 + Environment.NewLine);
}
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);
}
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;
}
}
}
}
}
This is Windows Forms app with 2 textboxes and 1 button and a timer (interval is 1000ms).
I've used code from CodeProject (linked in original question) with some changes to make it actually work.

Coding this may be hard. However, there are free tools out there for Telnet scripting, see Expect for one. If you have an C# application then perhaps your code could generate the Expect script and then run Expect?

Sending the information to telnet seems like it should be straightforward; use SendKeys(). The question becomes how to capture the output.
I found this YouTube video that should help: https://www.youtube.com/watch?v=BDTCviA-5M8
The solution in the video doesn't really address keeping the session open. I'm a bit outside my knowledge area here, but I believe you can start telnet in a worker thread, send commands to it with SendKeys(), capture the output as described in the video, then parse it.
Does that sufficiently resolve the requirement?

Related

How to Control Numato Ethernet Relay Module

I have winforms application in c# and 8 channel numato ethernet relay module, I am able to connect using telnet using this library https://www.codeproject.com/Articles/19071/Quick-tool-A-minimalistic-Telnet-library with this defualt credential ip : 169.254.1.1
port: 23
un : admin
pw : admin
the problem is that when I send the command nothing happens.
here is the full code of the telnet lib.
// minimalistic telnet implementation
// conceived by Tom Janssens on 2007/06/06 for codeproject
//
// http://www.corebvba.be
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
namespace MinimalisticTelnet
{
enum Verbs {
WILL = 251,
WONT = 252,
DO = 253,
DONT = 254,
IAC = 255
}
enum Options
{
SGA = 3
}
class TelnetConnection
{
TcpClient tcpSocket;
int TimeOutMs = 100;
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);
}
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;
}
}
}
}
}
my form load code to connect to the device
using System;
using System.Net.Sockets;
using System.Windows.Forms;
using MinimalisticTelnet;
TelnetConnection tc;
private void Form1_Load(object sender, EventArgs e)
{
tc = new TelnetConnection("169.254.1.1", 23);
string s = tc.Login("admin", "admin", 100);
textBox1.Text = s;
}
button code to send command
private void button1_Click(object sender, EventArgs e)
{
if (tc.IsConnected)
{
tc.WriteLine("relay on 0");
textBox2.Text = tc.Read();
}
}

Console does not show the entire answar from serial port

I am working with BC66 modem from Quectel. On my program when I type some AT commands to the modem it can not show the entire response from the modem, but instead the reply of the AT command. see figur below:
Instead using an terminal program and type the AT commands i got the status of my request. See figure below:
This is what I am expecting in my program, but unfortunately not happened.
The code snip:
static void Main(string[] args)
{
if (InitPort() == true)
{
Console.WriteLine("Port initialized");
TestAT();
}
}
private static void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] data = new byte[serialPort.BytesToRead];
serialPort.Read(data, 0, data.Length);
Console.WriteLine(Encoding.ASCII.GetString(data));
//Console.WriteLine(serialPort.ReadExisting());
}
private static void TestAT()
{
for (int i = 0; i < 10; i++)
{
serialPort.Write("at");
Thread.Sleep(2000);
serialPort.Write("at+cereg");
Thread.Sleep(2000);
}
}
private static bool InitPort()
{
serialPort.PortName = "COM51";
serialPort.BaudRate = 115200;
serialPort.DataBits = 8;
serialPort.Parity = Parity.None;
serialPort.StopBits = StopBits.One;
serialPort.DataReceived += SerialPort_DataReceived;
try
{
serialPort.Open();
return true;
}
catch
{
return false;
}
}
Any suggestion on what is wrong?
As you can see here on page 7 you need to finish your commands with <CR><LF>.
The “AT” or “at” prefix must be set at the beginning of each command
line. Entering <CR> will terminate a command line.
in C# the equivalent is \r\n
As #Mong Zhu pointed out, you can achieve that by using
serialPort.WriteLine("at");

Launching application from server creates Open File for lifetime of application

I launch a program located on one of my file servers. After launching the program it shows as an Open file in Computer Management.
Is there a way I can close this open file while my program runs so it doesn't show up in Computer Management?
My code is below. I'd be happy to take suggestions on improving my program, but I'm really just looking for a solution to stop all these Open Files from appearing.
Program.cs -- starts the program, handles logic to launch my application
using System;
using System.Windows.Forms;
using System.Diagnostics;
namespace IT_TaskbarApp
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
string programName = "TEG System Helper";
//Process[] proc = Process.GetProcessesByName(programName);
if (Process.GetProcessesByName(programName).Length == 1)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Primary());
}
else
{
foreach (Process p in Process.GetProcessesByName(programName))
{
if (Process.GetCurrentProcess().Id != p.Id)
{
p.CloseMainWindow();
p.Close();
p.Kill();
p.Dispose();
}
}
Main();
}
}
}
}
Primary.cs -- creates an icon in the system icons which I can use to send notifications and easily access utilities within our organization
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
namespace IT_TaskbarApp
{
public partial class Primary : Form
{
private NotifyIcon notifyIcon;
private ContextMenu contextMenu;
private MenuItem[] menuItem = new MenuItem[8];
private IContainer components;
//private Boolean SendNotices = true;
private DateTime startTime = DateTime.Now;
private DateTime currentTime;
private Icon tegroupIcon = new Icon(Assembly.GetExecutingAssembly().GetManifestResourceStream("IT_TaskbarApp.Src.tegroup.ico"));
private string prevNotification = "";
private bool isRunning = true;
private BackgroundWorker bgNotify = new BackgroundWorker();
private const string programName = "TEG System Helper";
public Primary()
{
this.FormClosing += Primary_FormClosing; //remove ghost icon in taskbar
ForeColor = Color.Blue;
BackColor = Color.Green;
components = new Container();
contextMenu = new ContextMenu();
for (int i = 0; i < menuItem.Length; i++)
{
menuItem[i] = new MenuItem();
menuItem[i].Index = i;
menuItem[i].Click += new EventHandler(LoadProcess);
}
menuItem[0].Text = programName;
menuItem[1].Text = "Knowledge Base";
menuItem[2].Text = "Policies";
menuItem[3].Text = "Feedback";
menuItem[4].Text = "Global Shop Search";
menuItem[5].Text = "-";
menuItem[6].Text = "Submit Ticket";
menuItem[7].Text = "Send Email";
//initialize contextMenu
contextMenu.MenuItems.AddRange(menuItem);
// Create the NotifyIcon.
notifyIcon = new NotifyIcon(components)
{
Icon = tegroupIcon,
BalloonTipIcon = new ToolTipIcon(),
ContextMenu = contextMenu, //the menu when right clicked
Text = programName,
Visible = true,
BalloonTipTitle = programName,
};
notifyIcon.DoubleClick += new EventHandler(Icon_DoubleClick);
InitializeComponent();
bgNotify.WorkerSupportsCancellation = true;
bgNotify.WorkerReportsProgress = true;
bgNotify.DoWork += NotifyUser;
bgNotify.ProgressChanged += SendNotice;
//bgNotify.RunWorkerCompleted += BgNotify_RunWorkerCompleted; //enable this to perform an action when the thread dies
bgNotify.RunWorkerAsync();
//Thread tNotify = new Thread();
}
#region SupportedFunctions
private void NotifyUser(object Sender, EventArgs e)
{
Console.WriteLine("enter");
while (isRunning)
{
currentTime = DateTime.Now;
#region DisplayCurrentTime
if (currentTime.Hour < 10 || currentTime.Minute < 10)
{
if (currentTime.Hour < 10)
{
if (currentTime.Minute < 10)
{
Console.WriteLine("0{0}:0{1}", currentTime.Hour, currentTime.Minute);
}
else
{
Console.WriteLine("0{0}:{1}", currentTime.Hour, currentTime.Minute);
}
}
else
{
if (currentTime.Minute < 10)
{
Console.WriteLine("{0}:0{1}", currentTime.Hour, currentTime.Minute);
}
}
}
else
{
Console.WriteLine("{0}:{1}", currentTime.Hour, currentTime.Minute);
}
#endregion
FileStream fs = new FileStream("\\\\te-admin\\public\\TaskbarNotices.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string noticeText = sr.ReadToEnd();
sr.Close();
fs.Close();
if (noticeText != "" && noticeText != prevNotification)
{
prevNotification = noticeText;
bgNotify.ReportProgress(1);
}
else
{
bgNotify.ReportProgress(2);
}
Console.WriteLine("Inner Text: {0} TOF: {1}", noticeText, noticeText != "");
Thread.Sleep(10000);
}
}
private void SendNotice(object Sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage == 1)
{
Console.WriteLine("notification sent");
this.notifyIcon.BalloonTipText = prevNotification;
this.notifyIcon.ShowBalloonTip(1500);
}
}
private void LoadProcess(object Sender, EventArgs e)
{
if (Sender is MenuItem)
{
MenuItem tempMenu = Sender as MenuItem;
string ProgramTag = "http://";
switch (tempMenu.Index)
{
case 0: //home page
ProgramTag += "teg";
break;
case 1: //docviewer
ProgramTag += "teg/docViewer";
break;
case 2: //policies
ProgramTag += "teg/Policies";
break;
case 3: //feedback
ProgramTag += "teg/Feedback";
break;
case 4: //inventory search
ProgramTag = "http://searchglobalshop/inventory/index.aspx";
break;
case 6: //submit ticket
ProgramTag = "https://timberlandgroup.on.spiceworks.com/portal/tickets";
break;
case 7: //send email
string sendto = "admin#tewinch.com";
string emailSubject = "Assistance Request";
string emailBody = "";
string mailto = string.Format("mailto:{0}?Subject={1}&Body={2}", sendto, emailSubject, emailBody);
ProgramTag = Uri.EscapeUriString(mailto);
break;
}
/*
Try to launch the choice the user made with the default processing method.
Should the default method fail we try to control how the process is run.
We open internet explorer and then we show them what to do otherwise.
*/
#region LaunchSelectedProcess
try
{
if (ProgramTag != "" && ProgramTag != "http://")
Process.Start(ProgramTag);
}
catch (System.ComponentModel.Win32Exception)
{
try
{
if (ProgramTag.StartsWith("http://") || ProgramTag.StartsWith("https://"))
Process.Start("iexplore.exe", ProgramTag);
}
catch (System.ComponentModel.Win32Exception)
{
Process.Start("control.exe", "/name Microsoft.DefaultPrograms");
string message = "";
if (tempMenu.Index <= 6)
{
message = "You must have a default browser set\n\tClick [Set Default Program]\n";
if (Environment.OSVersion.ToString().Contains("NT 10.")) //windows 10
{
message += "\tUnder [Web Browser] Edge is currently set as default\n\tClick on Microsoft Edge\n\tSelect the browser you use";
}
else //windows 7 -- "NT 6.1")
{
message += "Select the browser you use\n\tClick [Set this program as default]";
}
}
else
{
if (Environment.OSVersion.ToString().Contains("NT 10.")) //windows 10
{
message += "Please setup a default email application";
}
}
message += "\n\nIf this issue persists please contact your Administrator.\nPhone: 519-537-6262\nEmail: admin#tewinch.com";
MessageBox.Show(message, "Application Warning", MessageBoxButtons.OK, MessageBoxIcon.Information);
//if ( == DialogResult.OK)
}
}
#endregion
}
}
private void Icon_DoubleClick(object Sender, EventArgs e)
{
Process.Start("http://teg");
}
#endregion
#region BuiltFunctions
private void Primary_FormClosing(object sender, FormClosingEventArgs e)
{
notifyIcon.Icon = null;
notifyIcon.Dispose();
isRunning = false;
Dispose(true);
}
private void InitializeComponent()
{
this.SuspendLayout();
//
// Primary
//
this.Icon = tegroupIcon;
this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.CausesValidation = false;
this.ClientSize = new System.Drawing.Size(120, 23);
this.ControlBox = false;
this.Enabled = false;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Primary";
this.Opacity = 0D;
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.WindowState = System.Windows.Forms.FormWindowState.Minimized;
this.ResumeLayout(false);
}
protected override void Dispose(bool disposing)
{
// Clean up any components being used.
if (disposing)
if (components != null)
components.Dispose();
base.Dispose(disposing);
}
#endregion
}
}
Instead of cancelling the program on start up, I kill the other running instances of the program. The idea is that if any issues arise with the program I just launch another instance and resolve the issues. Right now not much can go wrong but we will be developing this program to complete many more tasks in the future.
The only area I can see which would keep a file open is when I pull an Embedded Resource tegroup.ico I was looking to see if I missed something while opening this, but I couldn't see a way to close the ManifestResourceStream after reading it in.
Any tips/suggestions would be wonderful but again, I really just want to know if there's a way I can close these Open Files
Example below
Open File after app launch
I might be trying to solve something which is a known result of using Application.Run() if this is the case then please suggest alternatives I can use. My other ideas would be loading the program into memory and launching it locally, using the .exe on the server as a starting point for this method though.
I believe that Windows doesn't load an entire executable into ram. It isn't just about files from the resource section of a PE file. Portions of the exe are only loaded when referenced and even after loading everything there is to load, Windows will maintain an open file handle until the process closes. Trying to close that handle yourself is a bad idea.
c/c++ allow a "SWAPFILE" flag to be specified that tells windows to put the whole thing into the page file but I don't know how you would do that with c# and I don't know if that would even stop windows from keeping the handle open anyways (I doubt it).
If this is truly important, iffin' I were your exe... I would:
Check a mutex for an existing running instance, exit if exist
Check where I was running from.
If running from temp, set a mutex that I am running and just run.
If not running from temp, copy myself to %temp%, start that copy, and exit.
Good luck.

C# - client 1 receive different data from server than what client 2 sent

I have a problem and none of my fellow colleagues are willing to help me so I'm asking someone if he can help me -
I have a project on c# forms to create a client (the lecturer gave us the python code of the server - just passing the data from player to player) that will play a game of cards with another client(player).
the player clicks on a card and it randomly chooses a card and send it to the server in a specific protocol.
The first message from the first player who clicks on the card is sent and received fine.
The problem is shown after the second player clicks on a card -
he sends the data to the server, BUT the second player receives a byte array of zeros - 0000.
I've been searching for answers but didn't found and I'm really desperate. Can someone help me please.
Client Code which I wrote :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Resources;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Threading;
namespace HW6_GuyYoffe
{
public partial class Form1 : Form
{
//connection
bool connected, connectionSucceed = false;
TcpClient client;
NetworkStream clientStream;
byte[] buffer = new byte[MSG_SIZE];
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), PORT_NUMBER);
//game
public int ansFromUser = 0;
string oppCard, userCard;
int userScore = 0, oppScore = 0;
bool cardChosen;
readonly object key = new object();
public Form1()
{
//creates the form
}
//generate card images on the screen
private void GenerateCards(int numOfCards, int startX, int startY)
{
//creates the cards on the screen
}
// called when user clicks a card
private void ClickOnCard(System.Windows.Forms.PictureBox currentPic)
{
//code...
buffer = new ASCIIEncoding().GetBytes("1" + userCard); //usercard - the random card of the current user
clientStream.Write(buffer, 0, buffer.Length);//send to server the chosen card
clientStream.Flush();
Array.Clear(buffer, 0, buffer.Length);
lock (key)
{
cardChosen = true;
Monitor.Pulse(key);
}
}
//called when form is created
public void PlayGame(object sender, EventArgs e)
{
client = new TcpClient();
ansFromUser = OK;
StartThread();
}
//main function
private void TalkToServer(IPEndPoint serverEndPoint)
{
if (ansFromUser != CLOSE_PROGRAM)
{
if (!connected)
ConnectToServer(serverEndPoint); //connect to server - pretty obvious
if (ansFromUser == CLOSE_PROGRAM)
{
BeginInvoke((MethodInvoker)delegate { this.Dispose(); });
return;
}
do
{
int bytesRead = 0;
try
{
Array.Clear(buffer, 0, buffer.Length);
bytesRead = clientStream.Read(buffer, 0, 4); //waits for 4 bytes from server
//// HERE is the problem - in the second time a clients sends his pick the buffer is 0000 - [0,0,0,0]
}
catch (Exception err3)
{
///error
}
if (bytesRead > 0)
{
string input = new ASCIIEncoding().GetString(buffer); //converts byte array to string
if (!connected)
{
if (input == "0000") //start game message
{
//starts game
}
else
{
//error
}
}
else
{
if (input == "2000") //end game message
{
ansFromUser = CLOSE_PROGRAM;
this.Dispose();
}
else if (input[0] == '1')//recieving the opponent's card
{
oppCard = input.Substring(1); //without the message type
int result = OpponentCard();
userScore += result;
oppScore -= result;
}
else
{
//error
}
}
else
{
///error
break;
}
}
Array.Clear(buffer, 0, buffer.Length);
} while (ansFromUser == OK); //while answer isn't end
}
}
//uses another form. Shows the error that have occurred and asks the user if he wants to try again. If so - tries again
private void ErrorMsgBox(string errorDetails)
{
ErrorBox errMsgBox = new ErrorBox(this, errorDetails);
errMsgBox.ShowDialog();
}
private void ConnectToServer(IPEndPoint serverEndPoint)
{
// connect to server
}
private int OpponentCard()
{
const int WIN = 1;
const int TIE = 0;
const int LOOSE = -1;
int result;
lock (key)
{
while (!cardChosen) //wait until opponent and user chose cards
Monitor.Wait(key);
Monitor.Pulse(key); //card is chosen
cardChosen = false; //reset
}
int oppCardNum = int.Parse(oppCard.Substring(0, 2));
int userCardNum = int.Parse(userCard.Substring(0, 2));
//...
result = oppCardNum < userCardNum ? WIN : (oppCardNum == userCardNum ? TIE : LOOSE); //returns the result
return result;
}
private void StartThread()
{
if (ansFromUser != CLOSE_PROGRAM)
{
Thread serverStart = new Thread(() => TalkToServer(serverEndPoint)); //passing the thread the parameters
serverStart.Start();
}
}
}
}
and if someone wants to see - the python server code -
import socket
import select
import Queue
PORT = 8820
HOST = '127.0.0.1'
server = socket.socket()
server.setblocking(0)
server.bind((HOST,PORT))
client = []
while True:
print "new game loop"
clients_connected = 0
server.listen(2)
#Sockets from which we expect to read or write to
inputs = [server]
#waiting for both the connextion to be established
while clients_connected < 2:
readable, writeable, exceptional = select.select(inputs,inputs,inputs)
#handle inputs
for s in readable:
if s is server:
#A readable server socket is ready to accept a connection
conn, addr = s.accept()
print "one connection has been established"
conn.setblocking(0)
inputs.append(conn)
clients_connected = clients_connected + 1
else:
data = s.recv(4)
if not data:
#Interpert empty result as closed connection
print "closing"
#stop listening for input and output
inputs.remove(s)
s.close()
clients_connected = clients_connected - 1
print "both connections has been established"
inputs.remove(server)
initiated = 0
#making sure both of the clients got initializtion message "0000"
while initiated < 2:
readable, writeable, exceptional = select.select(inputs,inputs,inputs)
for s in writeable:
s.send("0000")
initiated = initiated + 1
print "game started"
#Main loop - forwarding messages between the clients
while inputs:
readable, writeable, exceptional = select.select(inputs,inputs,inputs)
#handle inputs
for s in readable:
if s is server:
print "ERROR! can't initiate another connection after the game has been started!"
#Recieve data from the client
data = s.recv(4)
if data:
#A readable client socket has data
print "recieved",data,"from",s.getpeername()
if data != "0000":
#making sure the data isn't initialization message, in case it is the sever will ignore it
#broadcast the recived message:
for o in inputs:
if o is not s:
o.send(data)
else:
#Interpert empty result as closed connection
print "closing"
#stop listening for input and output
inputs.remove(s)
s.close()
for s in exceptional:
print "handling exceptions for",s.getpeername()
inputs.remove(s)
s.close()
HOPE SOMEBODY WILL SEE THIS AND HELP ME...

SMS connecting to a phone from C# and getting a response

I wrote code to send an SMS using my GSM phone which is attached to the computer through COM port. The code is below.
The problem is I do see that it is in the outbox of the phone and it actually appears to have been sent, but when I contact the recipient they say that I have not received the message.
I test the phone, and I create and send a message using only the phone and it works perfectly. However, when I do this with my code, it APPEARS to have been sent, and I am getting all the correct AT COMMAND responses from the phone, but the message is actually NOT sent.
Here is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO.Ports;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
SerialPort serialPort1;
int m_iTxtMsgState = 0;
const int NUM_MESSAGE_STATES = 4;
const string RESERVED_COM_1 = "COM1";
const string RESERVED_COM_4 = "COM4";
public Form1()
{
InitializeComponent();
this.Closing += new CancelEventHandler(Form1_Closing);
}
private void Form1_Load(object sender, EventArgs e)
{
serialPort1 = new SerialPort(GetUSBComPort());
if (serialPort1.IsOpen)
{
serialPort1.Close();
}
serialPort1.Open();
//ThreadStart myThreadDelegate = new ThreadStart(ReceiveAndOutput);
//Thread myThread = new Thread(myThreadDelegate);
//myThread.Start();
this.serialPort1.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
}
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
serialPort1.Close();
}
private void SendLine(string sLine)
{
serialPort1.Write(sLine);
sLine = sLine.Replace("\u001A", "");
consoleOut.Text += sLine;
}
public void DoWork()
{
ProcessMessageState();
}
public void ProcessMessageState()
{
switch (m_iTxtMsgState)
{
case 0:
m_iTxtMsgState = 1;
SendLine("AT\r\n"); //NOTE: SendLine must be the last thing called in all of these!
break;
case 1:
m_iTxtMsgState = 2;
SendLine("AT+CMGF=1\r\n");
break;
case 2:
m_iTxtMsgState = 3;
SendLine("AT+CMGW=" + Convert.ToChar(34) + "+9737387467" + Convert.ToChar(34) + "\r\n");
break;
case 3:
m_iTxtMsgState = 4;
SendLine("A simple demo of SMS text messaging." + Convert.ToChar(26));
break;
case 4:
m_iTxtMsgState = 5;
break;
case 5:
m_iTxtMsgState = NUM_MESSAGE_STATES;
break;
}
}
private string GetStoredSMSID()
{
return null;
}
/* //I don't think this part does anything
private void serialPort1_DataReceived_1(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string response = serialPort1.ReadLine();
this.BeginInvoke(new MethodInvoker(() => textBox1.AppendText(response + "\r\n")));
}
*/
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
Thread.Sleep(500);
char[] msg;
msg = new char[613];
int iNumToRead = serialPort1.BytesToRead;
serialPort1.Read(msg, 0, iNumToRead);
string response = new string(msg);
this.BeginInvoke(new MethodInvoker(() => textBox1.AppendText(response + "\r\n")));
serialPort1.DiscardInBuffer();
if (m_iTxtMsgState == 4)
{
int pos_cmgw = response.IndexOf("+CMGW:");
string cmgw_num = response.Substring(pos_cmgw + 7, 4);
SendLine("AT+CMSS=" + cmgw_num + "\r\n");
//stop listening to messages received
}
if (m_iTxtMsgState < NUM_MESSAGE_STATES)
{
ProcessMessageState();
}
}
catch
{ }
}
private void button1_Click(object sender, EventArgs e)
{
m_iTxtMsgState = 0;
DoWork();
}
private void button2_Click(object sender, EventArgs e)
{
string[] sPorts = SerialPort.GetPortNames();
foreach (string port in sPorts)
{
consoleOut.Text += port + "\r\n";
}
}
private string GetUSBComPort()
{
string[] sPorts = SerialPort.GetPortNames();
foreach (string port in sPorts)
{
if (port != RESERVED_COM_1
&& port != RESERVED_COM_4)
{
return port;
}
}
return null;
}
}
This is my code that works (tested) with U9 Telia cellular modem:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Configuration;
using UsbEject.Library;
using Utils;
namespace Hardware
{
public class TeliaModem : IDisposable
{
public delegate void NewSmsHandler(InboundSMS sms);
public event NewSmsHandler OnNewSMS;
#region private data
System.IO.Ports.SerialPort modemPort;
Timeouter _lastModemKeepAlive;
private delegate void DataReceivedDelegate();
private DataReceivedDelegate dataReceivedDelegate;
Queue<OutboundSMS> _outSmses = new Queue<OutboundSMS>();
enum ModemState
{
Error = -1, NotInitialized, PowerUp, Initializing, Idle,
SendingSMS, KeepAliveAwaitingResponse
};
Timeouter ModemStateTimeouter = new Timeouter(timeout_s: 10, autoReset: false);
ModemState _modemState = ModemState.NotInitialized;
ModemState CurrentModemState
{
get
{
return _modemState;
}
set
{
_modemState = value;
ModemStateTimeouter.Reset();
NihLog.Write(NihLog.Level.Debug, "State changed to: " + value.ToString());
}
}
private System.Windows.Forms.Control _mainThreadOwnder;
#endregion
public TeliaModem(System.Windows.Forms.Control mainThreadOwnder)
{
_mainThreadOwnder = mainThreadOwnder;
dataReceivedDelegate = new DataReceivedDelegate(OnDataReceived);
}
public void SendSMS(string phone, string text)
{
_outSmses.Enqueue(new OutboundSMS(phone, text));
HeartBeat();
}
private void SendSmsNow()
{
OutboundSMS sms = _outSmses.Peek();
sms.Attempt++;
if (sms.Attempt > sms.MaxTries)
{
NihLog.Write(NihLog.Level.Error, "Failure to send after " + sms.MaxTries + " tries");
_outSmses.Dequeue();
return;
}
NihLog.Write(NihLog.Level.Info, "Sending SMS: " + sms.ToString());
WriteToModem("AT+CMGS=\"" + sms.Destination + "\"\r");
System.Threading.Thread.Sleep(500);
WriteToModem(sms.Text);
byte[] buffer = new byte[1];
buffer[0] = 26; // ^Z
modemPort.Write(buffer, offset:0, count:1);
CurrentModemState = ModemState.SendingSMS;
}
public void Dispose()
{
UninitModem();
}
public void HeartBeat()
{
if (CurrentModemState == ModemState.NotInitialized)
{
TryInitModem();
return;
}
if (IsTransitionalState(CurrentModemState) && ModemStateTimeouter.IsTimedOut())
{
NihLog.Write(NihLog.Level.Error, "Modem error. Timed out during " + CurrentModemState);
CurrentModemState = ModemState.Error;
return;
}
if (CurrentModemState == ModemState.Idle && _lastModemKeepAlive.IsTimedOut())
{
// Send keepalive
WriteToModem("AT\r");
CurrentModemState = ModemState.KeepAliveAwaitingResponse;
return;
}
if (CurrentModemState == ModemState.Error)
{
NihLog.Write(NihLog.Level.Debug, "Reenumerating modem...");
UninitModem();
return;
}
if (_outSmses.Count != 0 && CurrentModemState == ModemState.Idle)
{
SendSmsNow();
return;
}
}
private string pendingData;
private void OnDataReceived()
{
// Called in the main thread
string nowWhat = modemPort.ReadExisting();
pendingData += nowWhat;
string[] lines = pendingData.Split(new string[] { "\r\n" }, StringSplitOptions.None);
if (lines.Length == 0)
{
pendingData = string.Empty;
return;
}
else
{
pendingData = lines[lines.Length - 1];
}
// This happens in main thread.
for (int i = 0; i < lines.Length - 1; i++)
{
string line = lines[i];
if (line.Length >= 5 && line.Substring(0, 5) == "+CMT:")
{
// s+= read one more line
if (i == lines.Length - 1) // no next line
{
pendingData = line + "\r\n" + pendingData; // unread the line
continue;
}
string line2 = lines[++i];
NihLog.Write(NihLog.Level.Debug, "RX " + line);
NihLog.Write(NihLog.Level.Debug, "RX " + line2);
InboundSMS sms = new InboundSMS();
sms.ParseCMT(line, line2);
if(OnNewSMS != null)
OnNewSMS(sms);
}
else // Not a composite
NihLog.Write(NihLog.Level.Debug, "RX " + line);
if (line == "OK")
{
OnModemResponse(true);
}
else if (line == "ERROR")
{
OnModemResponse(false);
NihLog.Write(NihLog.Level.Error, "Modem error");
}
}
}
private void ProcessSmsResult(bool ok)
{
if (!ok)
{
OutboundSMS sms = _outSmses.Peek();
if (sms.Attempt < sms.MaxTries)
{
NihLog.Write(NihLog.Level.Info, "Retrying sms...");
return;
}
NihLog.Write(NihLog.Level.Error, "Failed to send SMS: " + sms.ToString());
}
_outSmses.Dequeue();
}
private void OnModemResponse(bool ok)
{
if (CurrentModemState == ModemState.SendingSMS)
ProcessSmsResult(ok);
if (!ok)
{
NihLog.Write(NihLog.Level.Error, "Error during state " + CurrentModemState.ToString());
CurrentModemState = ModemState.Error;
return;
}
switch (CurrentModemState)
{
case ModemState.NotInitialized:
return;
case ModemState.PowerUp:
WriteToModem("ATE0;+CMGF=1;+CSCS=\"IRA\";+CNMI=1,2\r");
CurrentModemState = ModemState.Initializing;
break;
case ModemState.Initializing:
case ModemState.SendingSMS:
case ModemState.KeepAliveAwaitingResponse:
CurrentModemState = ModemState.Idle;
break;
}
}
private void CloseU9TelitNativeApp()
{
bool doneSomething;
do
{
doneSomething = false;
Process[] processes = Process.GetProcessesByName("wirelesscard");
foreach (Process p in processes)
{
p.CloseMainWindow();
doneSomething = true;
NihLog.Write(NihLog.Level.Info, "Killed native U9 app");
System.Threading.Thread.Sleep(1000); // Will not wait if no native app is started
}
} while (doneSomething);
}
void WriteToModem(string s)
{
modemPort.Write(s);
NihLog.Write(NihLog.Level.Debug, "TX " + s);
}
void UninitModem()
{
if (modemPort != null)
modemPort.Dispose();
modemPort = null;
CurrentModemState = ModemState.NotInitialized;
}
private bool IsTransitionalState(ModemState ms)
{
return ms == ModemState.Initializing
|| ms == ModemState.SendingSMS
|| ms == ModemState.PowerUp
|| ms == ModemState.KeepAliveAwaitingResponse;
}
Timeouter _initFailureTimeout =
new Timeouter(timeout_s: 10, autoReset:false, timedOut:true);
void TryInitModem()
{
// Try pistoning the modem with higher frequency. This does no harm (such as redundant logging)
PrepareU9Modem(); // Will do nothing if modem is okay
if (!_initFailureTimeout.IsTimedOut())
return; // Don't try too frequently
if (modemPort != null)
return;
const string modemPortName = "Basecom HS-USB NMEA 9000";
const int speed = 115200;
string portName = Hardware.Misc.SerialPortFromFriendlyName(modemPortName);
if (portName == null)
{
NihLog.Write(NihLog.Level.Error, "Modem not found (yet). ");
_initFailureTimeout.Reset();
return;
}
NihLog.Write(NihLog.Level.Info, string.Format("Found modem port \"{0}\" at {1}", modemPortName, portName));
modemPort = new System.IO.Ports.SerialPort(portName, speed);
modemPort.ReadTimeout = 3000;
modemPort.NewLine = "\r\n";
modemPort.Open();
modemPort.DiscardInBuffer();
modemPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(delegate { _mainThreadOwnder.Invoke(dataReceivedDelegate); }); // called in different thread!
_lastModemKeepAlive = new Timeouter(60, true);
WriteToModem("AT+CFUN=1\r");
CurrentModemState = ModemState.PowerUp;
}
void CheatU9Telit()
{
// U9 telit appears as USB CDrom on the bus, until disk eject is sent.
// Then, it reappears as normal stuff.
VolumeDeviceClass volumeDeviceClass = new VolumeDeviceClass();
foreach (Volume device in volumeDeviceClass.Devices)
{
if (device.FriendlyName == "PCL HSUPA Modem USB Device")
{
NihLog.Write(NihLog.Level.Info, "Trying to initialize: " + device.FriendlyName);
device.EjectCDRomNoUI();
}
}
}
void PrepareU9Modem()
{
CloseU9TelitNativeApp(); // Closes the autorun native app
CheatU9Telit();
}
}
public class OutboundSMS
{
public string Destination;
public string Text;
public int MaxTries;
public int Attempt = 0;
public OutboundSMS(string dest, string txt)
{
Destination = dest;
Text = txt;
MaxTries = 3;
}
override public string ToString()
{
if(Attempt > 1)
return string.Format("\"{0}\" to {1}, attempt {2}",
Text, Destination, Attempt);
else
return string.Format("\"{0}\" to {1}",
Text, Destination);
}
}
public class InboundSMS
{
public string SourcePhone;
public DateTime ReceiveTime;
public string Text;
public void ParseCMT(string line1, string line2)
{
string[] fields = line1.Split(new char[] { ',', ' ', '/', ':', '"' });
if (fields.Length < 12)
throw new ApplicationException("CMT message too short. Expected 2 fields");
SourcePhone = fields[3];
ReceiveTime = DateTime.Parse("20" + fields[7] + "-" + fields[8] + "-" + fields[9] + " " + fields[10] + ":" + fields[11] + ":" + fields[12].Substring(0, 2)); //test carefully
Text = line2;
}
};
}
Usage example in a winforms application:
Hardware.TeliaModem _modem;
public Form1()
{
InitializeComponent();
_modem = new Hardware.TeliaModem(this);
_modem.OnNewSMS += new Hardware.TeliaModem.NewSmsHandler(ProcessNewSMS);
_timer.Interval = 1000; // milliseconds
_timer.Tick += new EventHandler(OnTimerTick);
_timer.Start();
}
To send an SMS:
_modem.SendSMS(sms.SourcePhone, "Aircon is now " + BoolToString.ON_OFF(_aircon.On));
On timer event, once every second:
private void OnTimerTick(object o, EventArgs e)
{
_modem.HeartBeat();
}
This is registered as Winforms timer handler, so that modem will not have a thread.
Some utility classes used:
namespace Utils
{
public class StopWatch
{
protected DateTime _resetTime;
public StopWatch() { Reset(); }
public void Reset() { _resetTime = DateTime.Now; }
public double TotalSeconds { get { return (DateTime.Now - _resetTime).TotalSeconds; } }
public TimeSpan Time { get { return DateTime.Now - _resetTime; } }
};
public class Timeouter : StopWatch
{
private bool _autoReset;
private double _timeout_s;
public Timeouter(double timeout_s, bool autoReset, bool timedOut = false)
{
_timeout_s = timeout_s;
_autoReset = autoReset;
if (timedOut)
_resetTime -= TimeSpan.FromSeconds(_timeout_s + 1); // This is surely timed out, as requested
}
public bool IsTimedOut()
{
if (_timeout_s == double.PositiveInfinity)
return false;
bool timedout = this.TotalSeconds >= _timeout_s;
if (timedout && _autoReset)
Reset();
return timedout;
}
public void Reset(double timeout_s) { _timeout_s = timeout_s; Reset(); }
public double TimeLeft { get { return _timeout_s - TotalSeconds; } }
}
}
I implemented this in order to turn on air conditioner with SMS (yeah, I live in a hot country). It works. Please feel free to use any of this code.
Enjoy.
Microsoft provides a pretty decent VB.Net example in a KB article "How to access serial and parallel ports by using Visual Basic .NET". I'm not sure what your phone returns, however, if you change the buffer loop in the example, you can at least print out the reply:
MSComm1.Output = "AT" & Chr(13)
Console.WriteLine("Send the attention command to the modem.")
Console.WriteLine("Wait for the data to come back to the serial port...")
' Make sure that the modem responds with "OK".
' Wait for the data to come back to the serial port.
Do
Buffer = Buffer & MSComm1.Input
Console.WriteLine("Found: {0}", Buffer)
Loop Until InStr(Buffer, "OK" & vbCrLf)
GSMComm is a C# library that will allow you to easily interact with a GSM mobile in text or PDU mode. (The site also has a bunch of testing utilities)
Working with GSM modem to send SMS has never been a good idea as such. Here's a checklist to make sure your SMS is sent out properly.
You are sending the SMS in text mode. Try sending it in PDU mode.
Try this library http://phonemanager.codeplex.com/
Do you change SMSC number before sending out the SMS, if so make sure the SMSC is correct.
Also make sure your SIM card has enough credits to let you send outbound SMS.
Check the network status especially when you're sending out SMS from your program. This might be a problem.
I recommend you checkout the Lite edition of NowSMS gateway that comes for free and lets you work with GSM modem very continently. NowSMS will give you api abstraction over a GSM modem connection, so you wil just need to call the Http Api of NowSMS gateway, rest will be taken care by the NowSMS gateway.
Above all this, if your end-users are going to remain internet connected while using your application or if your application is web-based and hosted over internet, I strongly recoomend to do away with GSM modem option and opt-in for reliable Http SMS gateway service providers.

Categories