C# process output redirection with plink (putty) - c#

This one is driving me nuts... I want to write a simple C# application (with GUI) that logs into our Cisco Wireless Lan Controller (short WLC) via SSH and creates guest users. This would be quite easy with SSH.NET if not Cisco for whatever reason decided to not allow non-interactive logon - meaning you can't pass on username and password but have to type it in at the console. Even worse: they put an additional (non-functional) user prompt in front of the actual user prompt. God...
Anyway I figured it out using plink.exe and it is working quite ok, however I want to inspect the terminal output so I can decide if some commands were executed correctly. I want to use the output for the login too as the prompt appears somewhat slow and I can't rely on constant timing.
I have found some articles about redirection of the output (eg Process.start: how to get the output?), but it's just not working. I was only able to collect the output when plink.exe has been closed, but I need to read the output live with plink still running.
Here's my code so far:
namespace WIFI
{
public class Program
{
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new myForm());
}
public static String ProcessInput(string user)
{
GlobalVar.hasError = false;
GlobalVar.status = "";
if (user.Length < 5 || user.Length > 10)
{
GlobalVar.status = "Username ungültig";
GlobalVar.hasError = true;
}
else
{
WLCconnection WLC = new WLCconnection();
WLC.ConnectWLC();
if (!GlobalVar.hasError) WLC.UserExists(user);
if (!GlobalVar.hasError) WLC.CreateUser(user);
WLC.CloseWLC();
}
return GlobalVar.status;
}
}
public static class GlobalVar
{
public static Boolean hasError;
public static String status;
}
public class WLCconnection
{
Process terminal = new Process();
StringBuilder terminalOutput = new StringBuilder();
Boolean telnet = Convert.ToBoolean(System.Configuration.ConfigurationManager.AppSettings["telnet"]);
String WLChostname = System.Configuration.ConfigurationManager.AppSettings["WLChostname"];
String WLCusername = System.Configuration.ConfigurationManager.AppSettings["WLCusername"];
String WLCpassword = System.Configuration.ConfigurationManager.AppSettings["WLCpassword"];
public void ConnectWLC()
{
terminal.StartInfo.FileName = #System.Configuration.ConfigurationManager.AppSettings["plinkpath"];
terminal.StartInfo.UseShellExecute = false;
terminal.StartInfo.RedirectStandardInput = true;
terminal.StartInfo.RedirectStandardOutput = true;
terminal.StartInfo.RedirectStandardError = true;
terminal.StartInfo.CreateNoWindow = true;
if (telnet) terminal.StartInfo.Arguments = "-telnet " + WLChostname;
else terminal.StartInfo.Arguments = "-ssh " + WLChostname;
terminal.OutputDataReceived += (s, e) => terminalOutput.Append(e.Data);
//terminal.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
terminal.ErrorDataReceived += (s, e) => terminalOutput.Append(e.Data);
//terminal.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
terminal.Start();
terminal.BeginOutputReadLine();
terminal.BeginErrorReadLine();
int runs = 0;
if (!telnet)
{
while (!terminalOutput.ToString().Contains("login as:") && !GlobalVar.hasError)
{
Thread.Sleep(500);
if (runs < 20) runs++;
else GlobalVar.hasError = true;
}
terminal.StandardInput.Write("workaroundSSHproblem\n");
}
runs = 0;
while (!terminalOutput.ToString().Contains("User:") && !GlobalVar.hasError)
{
Thread.Sleep(500);
if (runs < 20) runs++;
else GlobalVar.hasError = true;
}
terminal.StandardInput.Write(WLCusername + "\n");
runs = 0;
while (!terminalOutput.ToString().Contains("Password:") && !GlobalVar.hasError)
{
Thread.Sleep(500);
if (runs < 20) runs++;
else GlobalVar.hasError = true;
}
terminal.StandardInput.Write(WLCpassword + "\n");
}
public void CloseWLC()
{
terminal.StandardInput.WriteLine("logout");
terminal.WaitForExit();
terminal.CancelOutputRead();
terminal.Close();
terminal.Dispose();
}
public Boolean UserExists(String user)
{
int runs = 0;
while (!terminalOutput.ToString().Contains("(Cisco Controller) >") && !GlobalVar.hasError)
{
Thread.Sleep(500);
if (runs < 20) runs++;
else GlobalVar.hasError = true;
}
terminal.StandardInput.Write("show netuser detail " + user);
if (!terminalOutput.ToString().Contains("blabla"))
{
GlobalVar.status = "User " + user + " bereits aktiviert";
GlobalVar.hasError = true;
}
return GlobalVar.hasError;
}
public void CreateUser(String user)
{
int runs = 0;
while (!terminalOutput.ToString().Contains("(Cisco Controller) >") && !GlobalVar.hasError)
{
Thread.Sleep(500);
if (runs < 20) runs++;
else GlobalVar.hasError = true;
}
terminal.StandardInput.Write("config netuser add " + user + " " + System.Configuration.ConfigurationManager.AppSettings["guestpassword"] + " wlan 3 userType guest lifetime 86400");
if (!GlobalVar.hasError)
{
if (UserExists(user))
{
GlobalVar.status = "";
GlobalVar.hasError = false;
}
else
{
GlobalVar.status = "User " + user + " konnte nicht aktiviert werden";
GlobalVar.hasError = true;
}
}
}
protected void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
terminalOutput.Append(outLine.Data);
}
}
}
I'd really appreciate your help!

For whom it may be of any help: I solved it using SSH.NET again, but this time not using the built in functions to login in but by using in combination with ShellStream to manually process in- and output. Working great so far.

Related

How can i capture https respond via fiddlercore?

I have download fiddlercore DEMO,and i try to use it in my application whitch was depends on WPF,then i hava a question that in my application i can't capture https responds resources?
enter image description here
my code just under below:
using Fiddler;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
namespace operateToolWPF.Utils
{
public class MyFiddler
{
static Proxy oSecureEndpoint;
static string sSecureEndpointHostname = "localhost";
static int iSecureEndpointPort = 7777;
public List<Fiddler.Session> oAllSessions { get; set; }
public void DoQuit()
{
if (null != oSecureEndpoint) oSecureEndpoint.Dispose();
Fiddler.FiddlerApplication.Shutdown();
//Thread.Sleep(500);
}
private string CalcResponseSize(Session oS)
{
if (null == oS.oResponse) return String.Empty;
var cBytesOut = 0;
if (null != oS.responseBodyBytes) cBytesOut += oS.responseBodyBytes.Length;
if ((null != oS.oResponse) && (null != oS.oResponse.headers)) cBytesOut +=
oS.oResponse.headers.ByteCount();
return cBytesOut.ToString();
}
public void WriteSessionList(List<Fiddler.Session> oAllSessions)
{
ConsoleColor oldColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("Session list contains...");
try
{
Monitor.Enter(oAllSessions);
foreach (Session oS in oAllSessions)
{
Console.Write(String.Format("{0} {1} {2} {3} {4} {5} {6}\n", oS.id, oS.oRequest.headers.HTTPMethod, oS.fullUrl, oS.responseCode, oS.oResponse.MIMEType, (oS.Timers.ClientBeginResponse - oS.Timers.ClientBeginRequest), CalcResponseSize(oS)));
}
}
finally
{
Monitor.Exit(oAllSessions);
}
Console.WriteLine();
Console.ForegroundColor = oldColor;
}
public void DoFiddler()
{
oAllSessions = new List<Fiddler.Session>();
//if (!Fiddler.CertMaker.rootCertExists())
//{
// if (!Fiddler.CertMaker.createRootCert())
// {
// throw new Exception("Unable to create cert for FiddlerCore.");
// }
//}
//if (!Fiddler.CertMaker.rootCertIsTrusted())
//{
// if (!Fiddler.CertMaker.trustRootCert())
// {
// throw new Exception("Unable to install FiddlerCore's cert.");
// }
//}
#region AttachEventListeners
Fiddler.FiddlerApplication.OnNotification += delegate(object sender, NotificationEventArgs oNEA) {
Console.WriteLine("** NotifyUser: " + oNEA.NotifyString);
};
Fiddler.FiddlerApplication.Log.OnLogString += delegate(object sender, LogEventArgs oLEA) {
Console.WriteLine("** LogString: " + oLEA.LogString);
};
Fiddler.FiddlerApplication.BeforeRequest += delegate(Fiddler.Session oS)
{
//Console.WriteLine("Fiddler.FiddlerApplication.BeforeRequest");
oS.bBufferResponse = true;
Monitor.Enter(oAllSessions);
oAllSessions.Add(oS);
//Console.Write(String.Format("{0} {1} {2} {3} {4} {5} {6}\n", oS.id, oS.oRequest.headers.HTTPMethod, oS.fullUrl, oS.responseCode, oS.oResponse.MIMEType, (oS.Timers.ClientBeginResponse - oS.Timers.ClientBeginRequest), CalcResponseSize(oS)));
Monitor.Exit(oAllSessions);
oS["X-AutoAuth"] = "(default)";
if ((oS.oRequest.pipeClient.LocalPort == iSecureEndpointPort) && (oS.hostname == sSecureEndpointHostname))
{
oS.utilCreateResponseAndBypassServer();
oS.oResponse.headers.SetStatus(200, "Ok");
oS.oResponse["Content-Type"] = "text/html; charset=UTF-8";
oS.oResponse["Cache-Control"] = "private, max-age=0";
oS.utilSetResponseBody("<html><body>Request for httpS://" + sSecureEndpointHostname + ":" + iSecureEndpointPort.ToString() + " received. Your request was:<br /><plaintext>" + oS.oRequest.headers.ToString());
}
};
Fiddler.FiddlerApplication.AfterSessionComplete += delegate(Fiddler.Session oS)
{
//Console.WriteLine("Fiddler.FiddlerApplication.AfterSessionComplete");
//Console.Title = ("Session list contains: " + oAllSessions.Count.ToString() + " sessions");
//DoQuit();
};
// Tell the system console to handle CTRL+C by calling our method that
// gracefully shuts down the FiddlerCore.
//
// Note, this doesn't handle the case where the user closes the window with the close button.
// See http://geekswithblogs.net/mrnat/archive/2004/09/23/11594.aspx for info on that...
//
#endregion AttachEventListeners
string sSAZInfo = "NoSAZ";
#if SAZ_SUPPORT
sSAZInfo = Assembly.GetAssembly(typeof(Ionic.Zip.ZipFile)).FullName;
DNZSAZProvider.fnObtainPwd = () =>
{
Console.WriteLine("Enter the password (or just hit Enter to cancel):");
string sResult = Console.ReadLine();
Console.WriteLine();
return sResult;
};
FiddlerApplication.oSAZProvider = new DNZSAZProvider();
#endif
Console.WriteLine(String.Format("Starting {0} ({1})...", Fiddler.FiddlerApplication.GetVersionString(), sSAZInfo));
Fiddler.CONFIG.IgnoreServerCertErrors = false;
FiddlerApplication.Prefs.SetBoolPref("fiddler.network.streaming.abortifclientaborts", true);
FiddlerCoreStartupFlags oFCSF = FiddlerCoreStartupFlags.Default;
int iPort = 8877;
Fiddler.FiddlerApplication.Startup(iPort, oFCSF);
FiddlerApplication.Log.LogFormat("Created endpoint listening on port {0}", iPort);
FiddlerApplication.Log.LogFormat("Starting with settings: [{0}]", oFCSF);
FiddlerApplication.Log.LogFormat("Gateway: {0}", CONFIG.UpstreamGateway.ToString());
oSecureEndpoint = FiddlerApplication.CreateProxyEndpoint(iSecureEndpointPort, true, sSecureEndpointHostname);
if (null != oSecureEndpoint)
{
FiddlerApplication.Log.LogFormat("Created secure endpoint listening on port {0}, using a HTTPS certificate for '{1}'", iSecureEndpointPort, sSecureEndpointHostname);
}
}
}
}
who can help me ?Thanks!
i Hope this solve all u vr Problem in this Demo application he has Clearly explained how to track the HTTP and HTTPS request.. For HTTP You can directly listen to the AfterSessionComplete event but for HTTPS you need to install the Fiddler core certificate this
https://weblog.west-wind.com/posts/2014/jul/29/using-fiddlercore-to-capture-http-requests-with-net

Auto BrithdayMail send by using services

Hello I try to create auto emails send by service file but there is some problem.
this is BrithdayEmailService.cs file.
namespace BirthdayEmailSevice
{
partial class BirthdayEmailService : ServiceBase
{
private Timer scheduleTimer = null;
private DateTime lastRun;
private bool flag;
public BirthdayEmailService()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("EmailSource"))
{
System.Diagnostics.EventLog.CreateEventSource("EmailSource", "EmailLog");
}
eventLogEmail.Source = "EmailSource";
eventLogEmail.Log = "EmailLog";
scheduleTimer = new Timer();
scheduleTimer.Interval = 1 * 5 * 60 * 1000;
scheduleTimer.Elapsed += new ElapsedEventHandler(scheduleTimer_Elapsed);
}
protected override void OnStart(string[] args)
{
flag = true;
lastRun = DateTime.Now;
scheduleTimer.Start();
eventLogEmail.WriteEntry("Started");
}
protected void scheduleTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (flag == true)
{
ServiceEmailMethod();
lastRun = DateTime.Now;
flag = false;
}
else if (flag == false)
{
if (lastRun.Date < DateTime.Now.Date)
{
ServiceEmailMethod();
}
}
}
private void ServiceEmailMethod()
{
eventLogEmail.WriteEntry("In Sending Email Method");
EmailComponent.GetEmailIdsFromDB getEmails = new EmailComponent.GetEmailIdsFromDB();
getEmails.connectionString = ConfigurationManager.ConnectionStrings["CustomerDBConnectionString"].ConnectionString;
getEmails.storedProcName = "GetBirthdayBuddiesEmails";
System.Data.DataSet ds = getEmails.GetEmailIds();
EmailComponent.Email email = new EmailComponent.Email();
email.fromEmail = "example#gmail.com";
email.fromName = "example Name";
email.subject = "Birthday Wishes";
email.smtpServer = "smtp.gmail.com";
email.smtpCredentials = new System.Net.NetworkCredential("example1#gmail.com", "example1 password");
foreach (System.Data.DataRow dr in ds.Tables[0].Rows)
{
email.messageBody = "<h4>Hello " + dr["CustomerName"].ToString() + "</h4><br/><h3>We Wish you a very Happy" +
"Birthday to You!!! Have a bash...</h3><br/><h4>Thank you.</h4>";
bool result = email.SendEmailAsync(dr["CustomerEmail"].ToString(), dr["CustomerName"].ToString());
if (result == true)
{
eventLogEmail.WriteEntry("Message Sent SUCCESS to - " + dr["CustomerEmail"].ToString() +
" - " + dr["CustomerName"].ToString());
}
else
{
eventLogEmail.WriteEntry("Message Sent FAILED to - " + dr["CustomerEmail"].ToString() +
" - " + dr["CustomerName"].ToString());
}
}
}
}
On scheduleTimer = new Timer(); got error
(This member is defined more than one)
Error:
Ambiguity between 'BirthdayEmailService.BirthdayEmailService.scheduleTimer' and 'BirthdayEmailService.BirthdayEmailService.scheduleTimer'
Also got error on BirthdayEmailService.Designer.cs this is file of design tool of service
error is :
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.eventLogEmail = new System.Diagnostics.EventLog();
**this.scheduleTimer = new System.Windows.Forms.Timer(this.components);**
((System.ComponentModel.ISupportInitialize)(this.eventLogEmail)).BeginInit();
//
// BirthdayEmailService
//
this.ServiceName = "BirthdayEmailService";
((System.ComponentModel.ISupportInitialize)(this.eventLogEmail)).EndInit();
}
those part is bold there is getting error as same as.
(This member is defined more than one)
Error:
Ambiguity between 'BirthdayEmailService.BirthdayEmailService.scheduleTimer' and 'BirthdayEmailService.BirthdayEmailService.scheduleTimer'
It could be because the name of the class and the namespace are the same one. See this post.

Windows Services (error 1053) event log trigger

I am new to programming and I have this project due on coming Tuesday. What I am trying to do is if a user enters a wrong password on the logon screen the cam takes the picture. I tried to implement my code in services but it gives me error 1053. I was wondering if somebody could fix this code for me or if file watcher is of use in my code. Please help!
namespace SampleWS
{
public partial class Service1 : ServiceBase
{
private WebCam camera;
public Service1()
{
InitializeComponent();
}
public void OnDebug()
{
OnStart(null);
}
protected virtual void OnPause(string[] args)
{
bool infinite = false;
LogonChecker(infinite);
}
protected virtual void OnContinue(string[] args)
{
bool infinite = true;
LogonChecker(infinite);
}
protected override void OnStart(string[] args)
{
bool infinite = true;
LogonChecker(infinite);
}
protected override void OnStop()
{
bool infinite = false;
LogonChecker(infinite);
}
DateTime mytime = DateTime.MinValue;
public void LogonChecker(bool infinity)
{
string queryString =
"<QueryList>" +
" <Query Id=\"\" Path=\"Security\">" +
" <Select Path=\"Security\">" +
" *[System[(Level <= 0) and" +
" TimeCreated[timediff(#SystemTime) <= 86400000]]]" +
" </Select>" +
" <Suppress Path=\"Application\">" +
" *[System[(Level = 0)]]" +
" </Suppress>" +
" <Select Path=\"System\">" +
" *[System[(Level=1 or Level=2 or Level=3) and" +
" TimeCreated[timediff(#SystemTime) <= 86400000]]]" +
" </Select>" +
" </Query>" +
"</QueryList>";
camera = new WebCam();
while (infinity)
{
EventLogQuery eventsQuery = new EventLogQuery("Security", PathType.LogName, queryString);
eventsQuery.ReverseDirection = true;
EventLogReader logReader = new EventLogReader(eventsQuery);
EventRecord eventInstance;
Int32 eventexists3 = new Int32();
EventLog mylog = new EventLog();
for (eventInstance = logReader.ReadEvent(); null != eventInstance; eventInstance = logReader.ReadEvent())
{
eventexists3 = eventInstance.Id.CompareTo(4625);
if (eventexists3 == 0)
{
if (eventInstance.TimeCreated.Value > mytime)
{
mytime = eventInstance.TimeCreated.Value;
camera.Connect();
Image image = camera.GetBitmap();
image.Save(#"D:\Audio\testimage3.jpg");
camera.Disconnect();
eventInstance = null;
break;
}
}
EventLogRecord logRecord = (EventLogRecord)eventInstance;
LogonChecker(infinity);
}
}
}
}
}
Despite my comment, this is easy. Check what the error 1053 means:
ERROR_SERVICE_REQUEST_TIMEOUT
1053 (0x41D)
The service did not respond to the start or control request in a timely fashion.
Your overrides of ServiceBase methods like OnStart need to return as soon as possible. If you want to perform any ongoing work either subscribe to events or spin up a worker thread.
The .NET documentation on MSDN doesn't really cover much about the execution model of services, for this you need to look at the Win32 documentation: About Services.

My C# multi-threaded console application seems to not be multithreaded

Here's my C# console program that uses Powerpoint to convert ppt files to folders of pngs. This is supposed to be an automated process that runs on its own server.
I expect that as soon as a thread creates an image from a file, it should immediately remove the images and the source file.
The actual behavior is that, if five threads are running, it'll wait for five folders of images to be created before any thread can move any files. I'm able to see the images being created, and compare that with the Console readout, so I can see that a thread isn't trying to move the file.
Only after all the other threads have made their images, will any thread try to move the files. I suspect this is wrong.
This is an Amazon EC2 Medium instance, and it appears to max out the CPU, so five threads might be too much for this.
I also find that I can hardly use Windows Explorer while this program is running.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using Microsoft.Office.Core;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using System.Diagnostics;
using System.Timers;
namespace converter
{
class Program
{
public static int threadLimit=0;
public static int currThreads = 0;
static void Main(string[] args)
{
var inDir = args[0];
var outDir = args[1]+"\\";
var procDir = args[2]+"\\";
Int32.TryParse(args[3],out threadLimit);
Thread[] converterThreads = new Thread[threadLimit];
while (true)
{
System.Threading.Thread.Sleep(1000);
var filePaths = Directory.GetFiles(inDir, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".pptx") && !s.Contains("~$") || s.EndsWith(".ppt") && !s.Contains("~$"));
var arrPaths = filePaths.ToArray();
for(var i=0; i< arrPaths.Length; i++)
{
if (currThreads < threadLimit && currThreads < arrPaths.Length)
{
Console.WriteLine("currThreads= " + currThreads + " paths found= " + arrPaths.Length);
try
{
var fileNameWithoutExtension = arrPaths[currThreads].Replace(inDir, "").Replace(".pptx", "").Replace(".ppt", "").Replace("\\", "");
var filenameWithExtension = arrPaths[currThreads].Substring(arrPaths[currThreads].LastIndexOf("\\") + 1);
var dir = arrPaths[currThreads].Replace(".pptx", "").Replace(".ppt", "");
Conversion con = new Conversion(arrPaths[currThreads], dir, outDir, procDir, filenameWithExtension, fileNameWithoutExtension);
converterThreads[i] = new Thread(new ThreadStart(con.convertPpt));
converterThreads[i].Start();
Console.WriteLine(converterThreads[i].ManagedThreadId + " is converting " + fileNameWithoutExtension);
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to convert {0} ", arrPaths[i]) + e);
}
}
}
for (var i = 0; i < converterThreads.Length; i++)
{
if (converterThreads[i] != null)
{
if (!converterThreads[i].IsAlive)
{
converterThreads[i].Abort();
converterThreads[i].Join(1);
Console.WriteLine("thread " + converterThreads[i].ManagedThreadId + " finished, "+currThreads+" remaining");
converterThreads[i] = null;
}
}
}
if (currThreads == 0)
{
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
}
}
}
class Logger{
static void toLog(String msg)
{
//TODO: log file
}
}
class Conversion{
static int numberOfThreads=0;
String input;
String output;
String outDir;
String process;
String nameWith;
String nameWithout;
int elapsedTime;
System.Timers.Timer time;
public Conversion(String input, String output, String outDir, String processDir, String nameWith, String nameWithout)
{
this.input = input;
this.output = output;
this.outDir = outDir;
process = processDir;
this.nameWith = nameWith;
this.nameWithout = nameWithout;
numberOfThreads++;
Console.WriteLine("number of threads running: " + numberOfThreads);
Program.currThreads = numberOfThreads;
time = new System.Timers.Timer(1000);
time.Start();
time.Elapsed += new ElapsedEventHandler(OnTimedEvent);
elapsedTime = 0;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
elapsedTime++;
}
public void convertPpt()
{
var app = new PowerPoint.Application();
var pres = app.Presentations;
try
{
var file = pres.Open(input, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse);
file.SaveAs(output, Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType.ppSaveAsPNG, MsoTriState.msoTrue);
file.Close();
app.Quit();
Console.WriteLine("file converted " + input);
}
catch (Exception e)
{
Console.WriteLine("convertPpt failed");
}
moveFile();
moveDir();
}
public void moveFile()
{
Console.WriteLine("moving" + input);
try
{
System.Threading.Thread.Sleep(500);
Console.WriteLine(string.Format("moving {0} to {1}", input, process + nameWith));
if (File.Exists(process + nameWith))
{
File.Replace(input, process + nameWith, null);
}
else
{
File.Move(input, process + nameWith);
}
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to move the file {0} ", input) + e);
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
}
public void moveDir()
{
Console.WriteLine("moving dir " + output);
try
{
System.Threading.Thread.Sleep(500);
Console.WriteLine(string.Format("moving dir {0} to {1} ", output, outDir + nameWithout));
if (Directory.Exists(outDir + nameWithout))
{
Directory.Delete(outDir + nameWithout, true);
}
if (Directory.Exists(output))
{
Directory.Move(output, outDir + nameWithout);
}
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to move the directory {0} ", output) + e);
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
finally
{
numberOfThreads--;
Program.currThreads = numberOfThreads;
Console.WriteLine("took " + elapsedTime + "seconds");
}
}
}
}
Every 1000ms you get a list of files in inDir and potentially start a thread to process each file. You have very complex logic surrounding whether or not to start a new thread, and how to manage the lifetime of the thread.
The logic is too complex for me to spot the error without debugging the code. However, I would propose an alternative.
Have a single thread watch for new files and place the file path into a BlockingCollection of files for processing. That thread does nothing else.
Have N additional threads that retrieve file paths from the BlockingCollection and process them.
This is known as a Producer / Consumer pattern and is ideal for what you are doing.
The example code at the bottom of the linked MSDN page shows an implementation example.
On a side note, you are catching and swallowing Exception e3. Don't catch something you will not handle, it hides problems.

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