I want to achieve same functionality as like this one :
Notify C# Client, when SMTP Server receive a new Email
This is working fine. That method "NewMessageReceived" call successfully on every new mail receive.
But problem is that i can't fetch mail. I only got total count of INBOX in this method.
This code using the library : MailSystem.net
My Code as following :
Imap4Client _imap;
public static int cnt = 0;
protected void Application_Start(object sender, EventArgs e)
{
var worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(StartIdleProcess);
if (worker.IsBusy)
worker.CancelAsync();
worker.RunWorkerAsync();
}
private void StartIdleProcess(object sender, DoWorkEventArgs e)
{
if (_imap != null && _imap.IsConnected)
{
_imap.StopIdle();
_imap.Disconnect();
}
_imap = new Imap4Client();
_imap.ConnectSsl(ConfigurationManager.AppSettings["IncomingServerName"], Convert.ToInt32(ConfigurationManager.AppSettings["InPort"]));
_imap.Login(ConfigurationManager.AppSettings["EmailAddress"], ConfigurationManager.AppSettings["Password"]);
var inbox = _imap.SelectMailbox("INBOX");
_imap.NewMessageReceived += new NewMessageReceivedEventHandler(NewMessageReceived);
inbox.Subscribe();
_imap.StartIdle();
}
public static void NewMessageReceived(object source, NewMessageReceivedEventArgs e)
{
cnt = e.MessageCount; //Inbox Count
//here i want to fetch all unread mail from inbox
}
I have found following solution to fetch unread mail:
http://mailsystem.codeplex.com/discussions/651129
It is saying me to use MailKit library. As i am already using MailSystem.net library , is there any way to achieve my requirement by using only one library ?
I am ready to use any other library also.
Please give me suggestion. Thanks
Yes, got it with single library : MailKit
Look at following code of global.asax file:
static CancellationTokenSource _done;
ImapClient _imap;
protected void Application_Start(object sender, EventArgs e)
{
var worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(StartIdleProcess);
if (worker.IsBusy)
worker.CancelAsync();
worker.RunWorkerAsync();
}
private void StartIdleProcess(object sender, DoWorkEventArgs e)
{
_imap = new ImapClient();
_imap.Connect(ConfigurationManager.AppSettings["IncomingServerName"], Convert.ToInt32(ConfigurationManager.AppSettings["InPort"]), Convert.ToBoolean(ConfigurationManager.AppSettings["IncomingIsSSL"]));
_imap.AuthenticationMechanisms.Remove("XOAUTH");
_imap.Authenticate(ConfigurationManager.AppSettings["EmailAddress"], ConfigurationManager.AppSettings["Password"]);
_imap.Inbox.Open(FolderAccess.ReadWrite);
_imap.Inbox.MessagesArrived += Inbox_MessagesArrived;
_done = new CancellationTokenSource();
_imap.Idle(_done.Token);
}
static void Inbox_MessagesArrived(object sender, EventArgs e)
{
var folder = (ImapFolder)sender;
//_done.Cancel(); // Stop idle process
using (var client = new ImapClient())
{
client.Connect(ConfigurationManager.AppSettings["IncomingServerName"], Convert.ToInt32(ConfigurationManager.AppSettings["InPort"]), Convert.ToBoolean(ConfigurationManager.AppSettings["IncomingIsSSL"]));
// disable OAuth2 authentication unless you are actually using an access_token
client.AuthenticationMechanisms.Remove("XOAUTH2");
client.Authenticate(ConfigurationManager.AppSettings["EmailAddress"], ConfigurationManager.AppSettings["Password"]);
int tmpcnt = 0;
client.Inbox.Open(FolderAccess.ReadWrite);
foreach (var uid in client.Inbox.Search(SearchQuery.NotSeen))
{
try
{
var message = client.Inbox.GetMessage(uid);
client.Inbox.SetFlags(uid, MessageFlags.Seen, true);
List<byte[]> listAttachment = new List<byte[]>();
if (message.Attachments.Count() > 0)
{
foreach (var objAttach in message.Attachments)
{
using (MemoryStream ms = new MemoryStream())
{
((MimeKit.ContentObject)(((MimeKit.MimePart)(objAttach)).ContentObject)).Stream.CopyTo(ms);
byte[] objByte = ms.ToArray();
listAttachment.Add(objByte);
}
}
}
string subject = message.Subject;
string text = message.TextBody;
var hubContext = GlobalHost.ConnectionManager.GetHubContext<myHub>();
hubContext.Clients.All.modify("fromMail", text);
tmpcnt++;
}
catch (Exception)
{ }
}
client.Disconnect(true);
}
}
Now, i am able to receive new mail arrival event and also able to fetch unread mail in that event. Thanks MailKit.
Related
I'm currently working on an interface between C# and an arduino project. I'm using the serial port to send and receive messages from the arduino and so far everything looks fine.
However I came to a point, where I want to send a string to the arduino and wait for a response until I'm going to send over the next string.
I figured that I cannot simply timeout here since my RichTextField is also going to freeze and the "OK*" message cannot be read from there.
I've read about some other solutions online but since I'm very new to C# I hope that somebody can point me in the right direction.
Best regards
//Edited the post with a full code example:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
namespace interface_test
{
public partial class Form1 : Form
{
string serialDataIn;
public Form1()
{
InitializeComponent();
Enable_Console();
comboBox_baudRate.Text = "115200";
comboBox_comPort.Text = "COM3";
string[] portLists = SerialPort.GetPortNames();
comboBox_comPort.Items.AddRange(portLists);
}
private void Form1_Load(object sender, EventArgs e)
{
}
/* erase textbox contents */
private void button_clearLog_Click(object sender, EventArgs e)
{
richTextBox_receiveMsg.Text = "";
}
/* listening to the serial port */
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
serialDataIn = serialPort1.ReadExisting();
this.Invoke(new EventHandler(ShowData));
}
/* process the serial data */
public void ShowData(object sender, EventArgs e)
{
string trimmedMsg = serialDataIn;
richTextBox_receiveMsg.Text += trimmedMsg;
if (trimmedMsg.Contains("Initialization done."))
{
button_detectCEM.Enabled = false;
}
}
/* open COM-port to arduino */
private void button_openCom_Click(object sender, EventArgs e)
{
try
{
serialPort1.PortName = comboBox_comPort.Text;
serialPort1.BaudRate = Convert.ToInt32(comboBox_baudRate.Text);
serialPort1.Open();
Enable_Console();
button_detectCEM.Enabled = true;
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
/* close COM-port to arduino */
private void button_closeCom_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
try
{
serialPort1.Close();
Enable_Console();
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
}
private void button_fileBrowser_Click(object sender, EventArgs e)
{
openAndWrite();
}
public void openAndWrite()
{
/* load a .txt file */
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.InitialDirectory = "c:\\";
openFileDialog1.Filter = "TXT files (*.txt)|*.txt";
openFileDialog1.FilterIndex = 0;
openFileDialog1.RestoreDirectory = true;
string selectedFile = "";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
selectedFile = openFileDialog1.FileName;
}
/* parse file and store it in data[] */
byte[] data;
using (FileStream fsSource = new FileStream(selectedFile, FileMode.Open, FileAccess.Read))
{
data = new byte[fsSource.Length];
int numBytesToRead = (int)fsSource.Length;
int numBytesRead = 0;
while (numBytesToRead > 0)
{
// Read may return anything from 0 to numBytesToRead.
int n = fsSource.Read(data, numBytesRead, numBytesToRead);
// Break when the end of the file is reached.
if (n == 0)
break;
numBytesRead += n;
numBytesToRead -= n;
}
numBytesToRead = data.Length;
}
for (int i = 0; i < BitConverter.ToInt32(blockLength, 0); i++)
{
data[i] = data[offset + i];
}
/* write data block */
offset = 0;
while (offset < data.Length)
{
byte[] dataString = new byte[6];
string blockMsg = "FFFFFF";
int start = offset;
offset += 6;
if (offset > data.Length) offset = data.Length;
for (int i = 0; i < 6; i++)
{
if ((start + i) < data.Length) dataString[i] = data[start + i];
}
blockMsg += BitConverter.ToString(dataString).Replace("-", string.Empty);
blockMsg += "*";
serialPort1.Write(blockMsg);
//Wait for "OK*" before next Message...
}
}
}
}
}
There's a few ways that you could solve this. My approach would be to make use of the TaskCompletionSource class and a lambda function. Here's a rough example, you'll need to make the method containing this code async, and potentially have it return a Task to await it all the way up the chain.
var tcs = new TaskCompletionSource<string>();
serialPort1.DataReceived += (s, e) =>
{
SerialPort sp = (SerialPort)s;
string newData = sp.ReadExisting();
tcs.SetResult(newData);
}
serialPort1.Write(Msg);
var dataFromPort = await tcs.Task;
I'm away from an IDE, nor do I have access to all your code, so without the wider context it's hard to know exactly what else you might need. But I've done some Arduino work in the past, and this is how I solved the problem.
EDIT :: Thinking about it, you might (test it first) run into a problem because that event isn't being unsubscribed from and the code is running in a loop. IF that turns out to be a problem, you could make use of C#'s Local Functions to handle the event subscription, like this:
var tcs = new TaskCompletionSource<string>();
void localHandler(object s, SerialDataReceivedEventArgs e)
{
serialPort1.DataReceived -= localHandler;
SerialPort sp = (SerialPort)s;
string newData = sp.ReadExisting();
tcs.SetResult(newData);
};
serialPort1.DataReceived += localHandler
serialPort1.Write(Msg);
var dataFromPort = await tcs.Task;
It might look a little strange, but it's certainly cleaner (IMO) then needing to keep track of instance variables and manually manage threads.
EDIT2 :: Tested when I was sat at a computer, if I understand your requirement correctly, this should do everything you need.
This may take you in the right direction.
It might be useful in this case to separate the data received from the display update thread. Since the data received is an event, it will be coming in on its own thread, likely from some component - in this case the serial port.
The form, and all the display objects on it, run on a single thread, owned by the form.
You can use a timer as a background thread to make the leap between what was received and what you want to do/display.
For example, one way is to use a concurrent queue and a timer to poll the status of the queue.
using System.Collections.Concurrent;
private ConcurrentQueue<string> dataIn = new ConcurrentQueue<string>();
private System.Threading.Timer timer = new System.Threading.Timer(CheckQue,null,TimeSpan.FromSeconds(1),TimeSpan.FromSeconds(1));
private void CheckQue(object state)
{
while(dataIn.TryDequeue(out var data))
{
ShowData(data);
if (data.Contains("OK*"))
{
//Do Something
//Better yet raise an event that does something
Msg += BitConverter.ToString(dataString).Replace("-", string.Empty);
Msg += "*";
serialPort1.Write(Msg);
}
}
}
Then modify your above code to add to the queue when data is received
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
dataIn.Enqueue(SerialPort1.ReadExisting());
}
And since your using a windows form, you need to make sure you don't get a cross-threaded operation when updating it, by marshaling the update onto the form's thread like so.
public static void ShowData(string data)
{
if (this.InvokeRequired)
{
var del = new MethodInvoker(() => ShowData(data));
try
{
this.Invoke(del);
return;
}
catch
{ }
}
richTextBox_receiveMsg.Text += data;
}
EDIT based on your revised question:
To modify for sending blocks of a file you could added another Que
private ConcurrentQueue<string> dataOut = new ConcurrentQueue<string>();
Then when you read the file, do whatever processing you need and put the final output in the queue and finish by sending the first block.
public void openAndWrite()
{
/* load a .txt file */
.
.
.
while (offset < data.Length)
{
.
.
blockMsg += BitConverter.ToString(dataString).Replace("-", string.Empty);
blockMsg += "*";
dataOut.Enqueue(blockMsg);
}
SendBlock();
}
Where SendBlock looks like this
private void SendBlock()
{
if(dataOut.TryDequeue(out var data))
{
serialPort1.Write(data);
}
}
Then just modify the timer handler to send blocks as needed
private void CheckQue(object state)
{
while (dataIn.TryDequeue(out var data))
{
ShowData(data);
if (data.Contains("OK*"))
{
SendBlock();
}
}
}
I am using the Google Drive API to download files from Google Drive, it works fine, but I want to do more pause and resume functionality.
I read the instructions page of Google and found support for partial downloads (https://developers.google.com/drive/api/v3/manage-downloads), they said "You can specify the portion of the file you want to dowload by using a byte range with the Range header", but I don't know how to do it, who can help me?
This is my code:
string fileId;
string path;
long bytes;
private void DownloadWorker_DoWork(object sender, DoWorkEventArgs e)
{
DriveService ds = GetService();
var request = ds.Files.Get(fileId);
using (var stream = new MemoryStream())
{
request.MediaDownloader.ProgressChanged += (Google.Apis.Download.IDownloadProgress progress) =>
{
switch (progress.Status)
{
case Google.Apis.Download.DownloadStatus.Downloading:
{
bytes = progress.BytesDownloaded;
GoogleDrive.ReportProgress((int)bytes);
break;
}
case Google.Apis.Download.DownloadStatus.Completed:
{
SaveStream(stream);
break;
}
case Google.Apis.Download.DownloadStatus.Failed:
{
break;
}
}
};
request.Download(stream);
}
}
private void DownloadWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = e.ProgressPercentage.ToString();
}
private void DownloadWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
private void SaveStream(MemoryStream stream)
{
long exlength = 0;
if (System.IO.File.Exists(path))
{
var fileInfo = new FileInfo(path);
exlength = fileInfo.Length;
}
var fileMode = exlength > 0 ? FileMode.Append : FileMode.Create;
using (FileStream file = new FileStream(path, fileMode, FileAccess.Write))
{
stream.WriteTo(file);
}
}
private void Button1_Click(object sender, EventArgs e)
{
fileId = "1P2KckTacknNDsONttlzL4GPLSLldzCbA";
path = "D:\\Data.zip";
GoogleDrive.RunWorkerAsync();
}
There is already an answer similar to what you want to achieve here [1] but with an export request. Basically, after you get the request (and before you send it) you need to set the Range header as stated in the link you posted. For your case it would be like this:
DriveService ds = GetService();
var request = ds.Files.Get(fileId);
//Set the range header
request.Headers.Range = new RangeHeaderValue(from, to);
//More codeā¦
//Send the request
request.Download(stream);
[1] C# - Downloading from Google Drive in byte chunks
I have this C# code that does not do the job. This code should run a code when the download is complete. But it does not work.
Code:
private void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
ZipFile.ExtractToDirectory("web/data/main/web.zip", "web/");
}
private void flatToggle2_CheckedChanged(object sender)
{
if (flatToggle2.Checked)
{
//Create File
Directory.CreateDirectory("web/data/main/");
timer2.Start();
bunifuProgressBar1.Show();
bunifuCustomLabel1.Show();
//Downloand
using (var client = new WebClient())
{
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(DownloadFileCompleted);
client.DownloadFile("https://www.apachelounge.com/download/VC15/binaries/httpd-2.4.29-Win64-VC15.zip", "web/data/main/web.zip");
}
}
else
{
}
}
This is the code that does not work
private void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
ZipFile.ExtractToDirectory("web/data/main/web.zip", "web/");
}
I tried to run this code without the Unzip but it did not work so I need help with this code.
Looking at the documentation, DownloadFile() is synchronous, so there is no callback needed. Try instead just:
using (var client = new WebClient())
{
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(DownloadFileCompleted);
client.DownloadFile("https://www.apachelounge.com/download/VC15/binaries/httpd-2.4.29-Win64-VC15.zip", "web/data/main/web.zip");
ZipFile.ExtractToDirectory("web/data/main/web.zip", "web/");
}
This should suffice.
I am bascially trying to make a barebones IRC client with C#, WinForms, and TcpClient that will display raw data from the irc server onto the the text area (textbox1). However I am struggling on the updating code (reading the stream from the server). Right now I have a timer that runs a function (listener) that reads from the TCP stream every 100ms. However my application freezes and the cursor disapeears, and the application hangs trying to grab more data. So what would be a better updating function?
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.IO;
using System.Net.Sockets;
namespace LogernIRC
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//Variables
TcpClient client;
StreamReader sr;
StreamWriter sw;
//Functions
public void connect(string host)
{
client = new TcpClient(host, 6667);
sr = new StreamReader(client.GetStream());
sw = new StreamWriter(client.GetStream());
}
public void write(string str)
{
textBox1.Text += str;
}
public void sendData(string str)
{
sw.WriteLine(str);
sw.Flush();
}
public void listener()
{
string data = sr.ReadLine();
write(data);
}
//End Functions
private void Form1_Load(object sender, EventArgs e)
{
//Initialize
write("Welcome to LogernIRC. Type \"/help\" for help with commands.\r\n");
}
private void button1_Click(object sender, EventArgs e) //Submit button clicked
{
//TextBox 1 is the text area , textbox 2 is the message/command area
//Command Area
if (textBox2.Text == "/help")
{
write("Help:\r\n/connect Connect to IRC server\r\n/help Display this help menu\r\n/join Join channel");
}
if (textBox2.Text.StartsWith("/connect"))
{
write("\r\nConnecting to " + textBox2.Text.Split(' ')[1] + " on port 6667...");
connect(textBox2.Text.Split(' ')[1]);
}
if (textBox2.Text.StartsWith("/join"))
{
write("\r\nJoining channel " + textBox2.Text.Split(' ')[1]);
}
if (textBox2.Text == "/test")
{
timer1.Start();
connect("irc.freenode.net");
write("\r\nActivating test function...");
sendData("NICK Logern");
sendData("USER Logern 0 * :LOGERN");
listener();
}
}
private void timer1_Tick(object sender, EventArgs e)
{
//Read Data
listener();
}
}
}
The delay happens when your timer event is raised, but there's no data to read. It will just sit and wait until there is. The best way to address the issue is to use asynchronous operations to handle the I/O. For example:
public Form1()
{
InitializeComponent();
}
//Variables
TcpClient client;
StreamReader sr;
StreamWriter sw;
//Functions
public void connect(string host)
{
client = new TcpClient(host, 6667);
sr = new StreamReader(client.GetStream());
sw = new StreamWriter(client.GetStream());
}
public void write(string str)
{
textBox1.Text += str;
}
public void sendData(string str)
{
sw.WriteLine(str);
sw.Flush();
}
public async Task listener()
{
try
{
string data
while ((data = await sr.ReadLineAsync()) != null)
{
write(data);
}
}
catch (ObjectDisposedException)
{
// socket was closed forcefully
}
}
//End Functions
private void Form1_Load(object sender, EventArgs e)
{
//Initialize
write("Welcome to LogernIRC. Type \"/help\" for help with commands.\r\n");
}
private void button1_Click(object sender, EventArgs e) //Submit button clicked
{
//TextBox 1 is the text area , textbox 2 is the message/command area
//Command Area
if (textBox2.Text == "/help")
{
write("Help:\r\n/connect Connect to IRC server\r\n/help Display this help menu\r\n/join Join channel");
}
if (textBox2.Text.StartsWith("/connect"))
{
write("\r\nConnecting to " + textBox2.Text.Split(' ')[1] + " on port 6667...");
connect(textBox2.Text.Split(' ')[1]);
}
if (textBox2.Text.StartsWith("/join"))
{
write("\r\nJoining channel " + textBox2.Text.Split(' ')[1]);
}
if (textBox2.Text == "/test")
{
connect("irc.freenode.net");
// initiate async reading (storing the returned Task in a variable
// prevents the compiler from complaining that we don't await the
// call).
var _ = listener();
write("\r\nActivating test function...");
sendData("NICK Logern");
sendData("USER Logern 0 * :LOGERN");
}
}
The above example leaves out some error-checking and other niceties, but it's the basic idea of what you want to do.
It's not running async, right? So the UI will lock up until the loop is done. You're looping forever, right? That's pretty common with IRC bots/clients; I've done it myself.
If so, and if you're using NET 4.0 and above, you could try this:
await Task.Run(()=> { CodeThatLoopsForever(); });
Let me try to explain it better. Let's say for example you have a function like this:
private void Connect()
{
while (true)
{
// Do socket listening
}
}
And you call it from clicking a button, like this:
private void btn_Connect_Click(object sender, EventArgs e)
{
Connect();
}
You could just change that button code to this:
private async void btn_Connect_Click(object sender, EventArgs e)
{
await Task.Run(()=> { Connect(); });
}
Hope this helps!
UPDATE: .NET 4.0 and above!
I've looked in many places for this but still haven't found a solution. What I'm trying to achieve is being able to use BackgroundWorker on a timed basis. Here's an example:
public Main()
{
isDbAvail = new BackgroundWorker();
isDbAvail.DoWork += isOnline;
isDbAvail.RunWorkerCompleted += rewriteOnlineStatus;
}
private void rewriteOnlineStatus(object sender, RunWorkerCompletedEventArgs e)
{
Subs.Connection connection = new Subs.Connection();
changeStatus(connection.isDbAvail());
}
private void isOnline(object sender, DoWorkEventArgs e)
{
while (true)
{
Console.WriteLine("Checking database connection");
System.Threading.Thread.Sleep(8000);
}
}
public void changeStatus(bool status)
{
if (status)
{
serverStatusVal.Text = "Connected";
serverStatusVal.ForeColor = System.Drawing.Color.DarkGreen;
}
else
{
serverStatusVal.Text = "Not connected";
serverStatusVal.ForeColor = System.Drawing.Color.Red;
}
}
What's happening here is that the isOnline method checks if there is a connection to the database (just an example) every 8 seconds and changes the text accordingly. What I've noticed though, is that the while loop inside the isOnline method causes the rewriteOnlineStatus method never to fire because it runs indefinitely. Is there another workaround to this?
I suggest you use BackgroundWorker.ReportProgress, and check connectivity in the background thread.
Something like this:
public Main()
{
isDbAvail = new BackgroundWorker();
isDbAvail.WorkerReportsProgress = true;
isDbAvail.DoWork += isOnline;
isDbAvail.ProgressChanged += rewriteOnlineStatus;
isDbAvail.RunWorkerAsync();
}
private void rewriteOnlineStatus(object sender, ProgressChangedEventArgs e)
{
changeStatus((bool)e.UserState);
}
private void isOnline(object sender, DoWorkEventArgs e)
{
while (true)
{
Console.WriteLine("Checking database connection");
Subs.Connection connection = new Subs.Connection();
isDbAvail.ReportProgress(0, connection.isDbAvail);
System.Threading.Thread.Sleep(8000);
}
}
Now the BackgroundWorker is doing the work, and reporting back to the UI thread via ProgressChanged.