Brief Information about the April 8th CSIG Meeting
weSenders.cs - Windows SSL Sockets to Access IMAP eMail Account. by B. Arnold
The goal for this month is to recreate last months program in a Windows style dialog box format. The code will be nearly identical but it will now be a Windows application. See the screen-shot and description paragraphs below.
Welcome to the CSIG, a Special Interest Group of the ACGNJ. This is an exciting time for the C Language programming since Microsoft now has 4 different language compilers: C++, C++ Express, C-Sharp, and C-Sharp Express. These are all capable of creating Windows (tm) programs. (Some are FREE!)
New for this month is the following.
This c-sharp program impliments a simple IMAP communication program to collect all of
the email addresses that you have received with your IMAP account. (gmail, hotmail, etc.)
It uses Net.Security.SslStream, Secure Socket Layer, common to most IMAP providers.
The program demonstrates some simple IMAP communication code and produces a list of
"From:" addresses. I have over 5000 emails to process. The list is further processed by the
Windows "FIND" command and the GNU Utilities "UNIQ" command. http://unxutils.sourceforge.net/
My 5200 addresses were reduced to about 400 unique addresses. A C++ alternative will
also be discussed at the meeting.
This is a CLI DOT
NET program is coded using C-sharp (C#) and is very similar to C++. It
also still uses the
same DOT NET libraries. As can be seen in the above screen shot, the code and
libraries allow complete access to the inner workings of your eMail database on
your provider's server. The Micorsoft SSL library is extensive and may be seen
at
http://msdn.microsoft.com/en-us/library/system.net.security.sslstream The
IMAP eMail standard is quite rigorous and provides hundreds of options. The code
for this meeting provides only a glimpse of what's available. For added reading
check out the 108 page document at
http://tools.ietf.org/html/rfc3501
ReadLine WriteLine | StreamReader(path) | StreamWriter() | Sleep(3000) |
File.Create(aout) | int.Parse | try catch finally | ReadKey() |
StringBuilder() | sslStream.Read() | Encoding.UTF8.GetDecoder() | Append(chars) |
CREATE A WINDOWS APPLICATION FROM THE ORIGINAL.
1. Creating a new project in C-sharp. Create a “Windows Form Application”
2. Resize the dialog box to 800 by 600.
3. Change the background to color beige.
4. Select View Toolbox and position the toolbox conveniently.
5. Create a ListBox to cover the left 2/3 of the dialog box. Call it “results”.
6. Let’s add some text boxes for the IMAP server account and password, etc. We have actually had 5 things with both labels and text boxes. Just highlight the first pair created, copy, and then paste the pair 4 times more.
7. Now add a big GO button with a font of 36 points.
8. Create a title “Windows eSender” at 24 points.
9. Create a Load Event for the main dialog box window. This creates a stub of a procedure in the source.
10. Put some of the code from the original program in there to read the parameters from the data file.
11. Change all “Console.WriteLine” to “MessageBox.Show”.
12. Change simple string variables like “imapserver “ to variable.text.
13. Create a Click Event for the GO button and add the rest of the code.
14. Now compile and correct any remaining errors like “static” procedures. Change them to “private”.
From the Microsoft documentation: SSL protocols help to provide confidentiality and integrity checking for messages transmitted using an SslStream. An SSL connection, such as that provided by SslStream, should be used when communicating sensitive information between a client and a server. Using an SslStream helps to prevent anyone from reading and tampering with information while it is in transit on the network.
There are a number of ways to refer to Microsoft's latest compilers and code. Here's what Wikipedia says: The Common Language Infrastructure (CLI) is an open specification developed by Microsoft that describes the executable code and runtime environment that form the core of the Microsoft .NET Framework. The specification defines an environment that allows multiple high-level languages to be used on different computer platforms without being rewritten for specific architectures.
Microsoft .Net Framework 4.5 |
C++ 9.0, etc. |
.Net 4.5, etc. |
CLI |
Common Language Infrastructure |
Sample Code
// eSenders.cs by B.Arnold 3/18/2014
/* ---------------------------------------------------
* This c-sharp program impliments a simple IMAP communication program to collect all of
* the email addresses that you have received with your IMAP account. (gmail, hotmail, etc.)
* It uses Net.Security.SslStream, Secure Socket Layer, common to most IMAP providers.
* The program demonstrates some simple IMAP communication code and produces a list of
* "From:" addresses. I have over 5000 emails to process. The list is further processed by the
* Windows "FIND" command and the GNU Utilities "UNIQ" command. http://unxutils.sourceforge.net/
* My 5200 addresses were reduced to about 400 unique addresses. A C++ alternative will
* also be discussed at the meeting.
*
* After running the program, issue the following filter commands:
* FIND "From: " emailresponse.txt >email1.txt
* SORT <email1.txt >email2.txt
* UNIQ -u email2.txt >email3.txt
*/
// SAMPLE OUTPUT
// * 2925 FETCH (BODY[HEADER.FIELDS (FROM)] {45}
// From: laksdfhl lkjsdh <kjlkhdf@gmail.com>
// )
// <EOF> OK FETCH completed
// * 2926 FETCH (BODY[HEADER.FIELDS (FROM)] {69}
// From: "LightInTheBox.Com" <auto-confirm@system.lightinthebox.com>
// )
// <EOF> OK FETCH completed
// * 2927 FETCH (BODY[HEADER.FIELDS (FROM)] {53}
// From: "IEEE ComSoc Meetings" <noreply@comsoc.org>
// )
using System;
using System.IO;
using System.Text;
using System.Net.Sockets;
using System.Net.Security;
namespace eSenders
{
class Program
{
static System.IO.StreamWriter sw = null;
static System.Net.Sockets.TcpClient tcpc = null;
static System.Net.Security.SslStream ssl = null;
static string path, aout;
static string imapserver, imapport, username, password;
static void Main(string[] args)
{
try
{
path = Environment.CurrentDirectory + "\\eSenders.txt";
aout = Environment.CurrentDirectory + "\\emailresponse.txt";
Console.WriteLine(
" eSenders.exe Version 1.03 by B.Arnold\n" +
" -------------------------------------\n" +
" Output file, emailresponse.txt, must be further processed by FIND and UNIQ to \n" +
" produce a list of \"From:\" addresses from an IMAP email provider: gmail, etc.\n");
if (!System.IO.File.Exists(path))
{
Console.WriteLine(
" ERROR: The file eSenders.txt was not found.\n" +
" Please create this text file with the following\n" +
" information on 4 consecutive lines:\n\n" +
" IMAP server name. ie imap.gmail.com\n" +
" IMAP port. ie 993\n" +
" User name\n" +
" User password\n");
System.Threading.Thread.Sleep(3000);
return;
}
//
// READ THE SMALL DATA FILE CONTAINING THE SIGNON INFORMATION
//
int count = 0;
using (StreamReader sr = new StreamReader(path)) // closed automatically.
{
if (sr.Peek() >= 0) { imapserver = sr.ReadLine(); ++count; }
if (sr.Peek() >= 0) { imapport = sr.ReadLine(); ++count; }
if (sr.Peek() >= 0) { username = sr.ReadLine(); ++count; }
if (sr.Peek() >= 0) { password = sr.ReadLine(); ++count; }
}
if (count < 4)
{
Console.WriteLine("Data error in file eSenders.txt\n");
System.Threading.Thread.Sleep(3000);
return;
}
Console.WriteLine(imapserver + "\n" + imapport + "\n" + username + "\n" + "********");
Console.WriteLine("----------------------------------------------------------------------");
//
// SIGN ONTO THE GMAIL, ETC. SERVER USING SSL AUTHENTICATION
//
sw = new System.IO.StreamWriter(System.IO.File.Create(aout));
tcpc = new System.Net.Sockets.TcpClient(imapserver, Convert.ToInt32(imapport));
ssl = new System.Net.Security.SslStream(tcpc.GetStream());
ssl.AuthenticateAsClient(imapserver);
receiveResponse("<EOF> LOGIN " + username + " " + password + "\r\n");
receiveResponse("<EOF> LIST " + "\"\"" + " \"*\"" + "\r\n");
receiveResponse("<EOF> SELECT INBOX\r\n");
receiveResponse("<EOF> STATUS INBOX (MESSAGES)\r\n");
Console.WriteLine("\n Enter the last email number to fetch :");
int number = int.Parse(Console.ReadLine());
int i;
for (i = 1; i <= number; i++)
{
receiveResponse("<EOF> FETCH " + i + " BODY.PEEK[HEADER.FIELDS (FROM)]\r\n");
}
receiveResponse("<EOF> LOGOUT\r\n");
}
catch (Exception ex)
{
Console.WriteLine("error: " + ex.Message);
}
finally
{
if (sw != null)
{
sw.Close(); sw.Dispose();
}
if (ssl != null)
{
ssl.Close(); ssl.Dispose();
}
if (tcpc != null)
{
tcpc.Close();
}
}
Console.WriteLine("ok");
Console.ReadKey();
}
//
// GET SERVER RESPONSE AND SEND TO SCREEN AND aout FILE.
//
static void receiveResponse(string command)
{
if (command.Length < 1) return;
// Set timeouts for the read and write to 5 seconds.
ssl.ReadTimeout = 5000;
ssl.WriteTimeout = 5000;
// Write a message to the server.
byte[] message = Encoding.UTF8.GetBytes(command);
ssl.Write(message);
string data = ReadMessage(ssl); // get data from server
Console.Write(data);
sw.Write(data); // out to data file
}
//
// READ THE RETURN MESSAGE OR DATA FROM THE SERVER
// http://msdn.microsoft.com/en-us/library/system.net.security.sslstream.read(v=vs.110).aspx
//
static string ReadMessage(SslStream sslStream)
{
// Read the message sent by the server.
// The end of the message is signaled using the
// "<EOF>" marker.
byte[] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = -1;
do
{
bytes = sslStream.Read(buffer, 0, buffer.Length);
// Use Decoder class to convert from bytes to UTF8
// in case a character spans two buffers.
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
decoder.GetChars(buffer, 0, bytes, chars, 0);
messageData.Append(chars);
// Check for EOF.
if (messageData.ToString().IndexOf("<EOF>") != -1)
{
break;
}
} while (bytes != 0);
return messageData.ToString();
}
}
}
SOURCE CODE
For help, email me at b a r n o l d @ i e e e . o r gBack to C++ Main Page