Introduction
rEmail is a set of tutorials I am writing, describing how I am building tools to download, interpret and send email messages (Including attachments). rTCPIP
is the first of the set. It is a very simple class that uses Windows Sockets to establish and communicate over TCP/IP connections. The future rEmail articles will build on this one and anyone using the fullest only needs to download the source of the latest article and they will have everything they need.
This article may seem like it has an extremely small amount of content. I am writing an article starting with such a basic subject for a number of reasons:
- What always kills me when using CodeProject tutorials is that, I download the code and get hundreds of errors. I spend hours correcting the errors instead of learning the subject I am actually interested in. What I prefer doing is a bit by bit approach. Write something, test it and see it working, write the next bit, test that etc. I hope to allow readers to follow this approach instead of throwing the whole lot at them at once.
- I am giving tutorials describing how to use components I am developing that someone using the final email project wouldn’t need to know. This is important because some of the later standards used (MIME, SMTP) are complex. I do not intend to produce a complete implementation rather just implement what I need. In theory, someone could gain some insight into the methods I use to solve the problems and could extend the code to deal with parts I haven’t implemented.
- This is a work in progress. I am aware that the code referenced in this article may change by the time I publish future articles. This may cause problems. When I have finished the whole project, I plan to come back and rewrite these articles.
Using the code
This is a quick description of how to use the code. It involves creating a console application that connects to a mail server. The effect will be the same as launching Telnet, typing open mail.hostname.com 110, reading the server greeting then sending the QUIT signal.
Download and unzip the code.
- Create a new Hello world C++ Win32 Console Application (I called mine xxtest).
- Project -> Settings, and make sure ws2_32.lib is linked to in all configurations.
- Project -> Insert project into workspace and add the rTCPIP project you downloaded to this workspace.
- Set the active project to xxtest, then Project -> Dependencies and make xxtest dependent on rTCPIP.
- Compiling at this point should work fine.
Add a #include
directive at the tope of xxtest.cpp to point to rTCPIP_Connection.h.
#include "../rTCPIP/rTCPIP_Connection.h"
Compile this to ensure that you have made no mistakes so far.
Add this code to your main function (Replace mail.somehost.com with your email server's address, and 110 with a different port number if you need to).
rTCPIP_Connection *pCon = new rTCPIP_Connection("mail.somehost.com",110);
if (!pCon->Valid()) {
delete pCon;
printf("Couldn't Get a Connection\n");
return 0;
};
delete pCon;
The construction of this class establishes a connection, and if this has been successful, the destruction will close a connection. I use a stage method in my constructor to determine which bits were successful and where it has failed. You can use the Valid
function to check if the class connected OK or not.
If it has failed, you can use GetStatus
to retrieve a number. Rather than document what the numbers mean, I have decided to leave the reader to look at the constructor method of the class themselves as the meanings will be obvious. This code should compile and run. If you can’t get a connection, check your firewall settings. Also, try using Telnet to connect to determine where the problem is occurring.
Now add the following code above the last delete statement:
char m_buf[512];
pCon->recv_msg(m_buf,512);
printf("Recieved %s from the server\n",m_buf);
Now run the program. You will notice that there is a lot of junk after the message we got back from the server. This is caused by C++ using ‘\0’ as a terminator and the network using “\n\r”. This problem is simply solved by terminating the string properly. I have a function to do this, Terminate
, alter the code so that it reads:
char m_buf[512];
pCon->recv_msg(m_buf,512);
pCon->Terminate(m_buf,512);
printf("Recieved %s from the server\n",m_buf);
Warning: When displaying things for debugging purposes, remember that Terminate
will alter the string you have just received. I always copy it to another string in my debug code when I want to display it. Also, using this method will, only display the first line from the server.
Finally, let's tell the server to close the connection and read it’s response. Add the following before the final delete line:
pCon->send_msg("QUIT\n",5);
pCon->recv_msg(m_buf,512);
pCon->Terminate(m_buf,512);
printf("Recieved %s from the server\n",m_buf);
This sends the quit message to the server and reads the response. Note the \n at the end of the line. RFC 1939 says it should be a CRLF pair, (\r\n) but in my experiments, I have found that sometimes this doesn’t seem to work for me but just using \n does.
Again, you can compile and run the code here.
You have seen all but two of the functions in the class. You can replace the send message line with:
sprintf(m_buf,"QUIT");
pCon->send_msg_cstr(m_buf);
This has two advantages. You don’t have to count how many characters you are sending. (It will send all characters up till the ‘\0’ character, and it automatically adds the terminator for you. The disadvantage is that you can’t send it a string literal. You have to copy the string into a buffer first.
So, the complete program to test out this class was:
rTCPIP_Connection *pCon = new rTCPIP_Connection("mail.metcarob.com",110);
if (!pCon->Valid()) {
delete pCon;
printf("Couldn't Get a Connection\n");
return 0;
};
char m_buf[512];
pCon->recv_msg(m_buf,512);
pCon->Terminate(m_buf,512);
printf("Recieved %s from the server\n",m_buf);
sprintf(m_buf,"QUIT");
pCon->send_msg_cstr(m_buf);
pCon->recv_msg(m_buf,512);
pCon->Terminate(m_buf,512);
printf("Recieved %s from the server\n",m_buf);
delete pCon;
printf("Hello World!\n");
return 0;
I hope you didn’t get sore fingers typing that!!!
Points of Interest
While working out how to receive multi line messages from the server, I thought it would be nice if I could check and see if there was any data on the buffer to read, so I added the DataToBeRead
function which in theory should tell me this.
In fact, I found it didn’t work. Sometimes it reports data to read when there is no data to be read. (Causing annoying program hangs while it waits for data) other times it insists there is no data to be read and my next line of code successfully reads the server response – Weird!!
History
No further articles in the rEmail series have yet been written.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.