A POP 3 Class
Written by Mike James   
Sunday, 14 March 2010
Article Index
A POP 3 Class
Log on and beyond
Headers

Logging on

The first public method that we need is something to get us logged on and connected. First we have to check that the necessary information to log on has been provided:

public bool LogOn()
{
if (URL == null) return false;
if (user == null) return false;
if (password == null) return false;

If the task cannot be performed the function simply returns false without any indication of why there is a problem.

As long as we have the necesary information we can attempt to connect to the POP 3 server:

 popTCP.Connect(URL, 110);

Notice that this instrcution will throw an exception if the server cannot be connected to. Assuming it works we can now get the network stream associated with the connection:

 popStream = popTCP.GetStream();

This is then used by the WaitFor(target) method which simply gets the response from the server and tests to see if it starts with the specified target to check that we have an "+OK" response:

 if(!WaitFor("+OK"))return false;

Following this we send the user name and password and wait for the "+OK" response in each case:

 Send("USER "+user);
if(!WaitFor("+OK"))return false;
Send("PASS "+password);
if(!WaitFor("+OK"))return false;
return true;
}

The sending of commands is handled by the private method “Send”. This adds a carriage return linefeed to the end of each string so automatically conforming to the POP3 protocol. It also uses the Encoding object to convert the Unicode string into ASCII which is the universal character code of the internet: Finally the networkstream is used to send the message. Once again if the server doesn't accept the data for any reason an exception is thrown:

private void Send(string message)
{
message = message + "\r\n";
byte[] buffer=new byte[1024];
Encoding.ASCII.GetBytes(
message,0,message.Length,buffer,0);
popStream.Write(
buffer,0,message.Length);
}

In most cases you need to implement the receiving of data from the server as an asynchronous task using the beginrecieve method. This allows you to keep the user interface responsive while waiting for the server to send back data. However, in this case we can let the timeout specified deal with problems of slow servers and simply use a blocking synchronous recieve method.  The “WaitFor” function will simply wait until there is a response from the server or the specified timeout elapses. If there is a response from the server it compares the start of the response with the target string and returns “true” or “false”. This makes it very easy to wait for “+OK” as the first three letters of every response from the server:

private bool WaitFor(string target)
{
 byte[] buffer = new byte[1024];
 int numread=0;
 if (popStream.CanRead)
 {
 numread=popStream.Read(
buffer, 0, 1024);
 }
 reply = Encoding.ASCII.GetString(
buffer, 0, numread);
 return reply.StartsWith(target);
}

Even though this is a fairly simple function there are some interesting points. The data retrieved in buffer is ASCII coded so it has to be converted to a Unicode string to be used within the rest of the system. This again is courtesy of the Encoding object.

After logon!

After calling the logon method the client can assume that it is talking to the server in question and can start to issue commands and get back information.

The next design question is how close the class should stick to POP3 and how much it should package the protocol to provide easier to use facilities. In some cases some pre-processing of the returned data is worth doing because what is required is obvious. In other cases the data is potentially complicated and it can be much more difficult to see what to do with it.

For example, in the case of the STAT command the part of the response that is most often needed is the number of email waiting so why not return this as a processed integer item rather than a string containing the complete response.

You might think that a function to return the headers from a specific email was also a good idea and that it would be worth processing the headers into separate fields of a user defined structure – but here is the problem. While some of the fields are standard – To:, From: and so on there are many other non-standard fields which the user might well want to process in some special way. If you decide to implement a GetHeader function so that it returns only the standard fields pre-packaged this makes it more difficult to see how to handle the non-standard fields. In this case it seems much better to drop the whole lot unprocessed in the hands of the client and let it separate out the header fields it actually needs.

The first thing that most client programs are going to want to know is the number of emails waiting. This is just a matter of issuing the STAT command and extracting the first returned value:

public int getNumberOfEmails()
{
 if (popTCP.Connected)
 {
 Send("STAT");
  if (!WaitFor("+OK")) return 0;
  return getNum(ref reply);
 }
 else
 {
  return 0;
 }
}

The only new routine used is the getNum function. This strips characters from the front of the string stored in reply and returns the first decimal value it finds. So for example,

string s = “first number 123 
second number 456”;
n = getNum(ref s);

will return 123 and change s to “second number 456”. Why change the value of s?

After all a function isn’t supposed to change the value of any of its parameters and to do so is generally considered bad programming? The reason is that it allows a second call to the function to extract the second number as in:

n = getNum(s);

which returns 456 and leaves s empty.

This is an example of a type of function which “uses up” its inputs and more or less treats the string as a sequential file that it reads its way through. A useful technique if used carefully.

The getNum function is fairly simple but it does involve some changing of data types from String to StringBuilder and to Char to make the manipulations work. First we need to convert the string input into a StringBuilder so that character manipulations are fast and efficient:

private int getNum(ref string data)
{
StringBuilder temp =
new StringBuilder(data);

Next we scan the StringBuilder for the first charcter that is a digit:

 while (temp.Length != 0 &
 !char.IsDigit(temp[0]))
{
temp.Remove(0, 1);
}

Notice that we have to end the loop if we reach the end of the StringBuilder without having found a digit. Notice too the way that the loop used the Remove method to strip off the first character until the first character is a digit.

If we didn't find a digit then we can simply return 0 as a default result:

if (temp.Length == 0) return 0;

If we did find a digit we can convert this into a value and start looping for more digits to build up the value:

 int val=0;
do
{
val=val*10+
(int)char.GetNumericValue(temp[0]);
temp.Remove(0, 1);
}while(temp.Length!=0 &
char.IsDigit(temp[0]));

Notice once againt the each time through the loop the first character is stripped off and the loop ends when the first character is a non-digit or the string has been exhausted. Finally we can convert the StringBuilder back to the string parameter and return the final result:

 data=temp.ToString();
 return val;
}

<ASIN: 0890069395>

<ASIN:1565924797>

<ASIN:0596007078>

<ASIN:1555582125>

<ASIN:059600012X>



Last Updated ( Tuesday, 16 March 2010 )
 
 

   
RSS feed of all content
I Programmer - full contents
Copyright © 2014 i-programmer.info. All Rights Reserved.
Joomla! is Free Software released under the GNU/GPL License.