This article is the beginning of eMail reception from VFP, complemented with the previous articles on eMail sending from VFP. In order to do this, we shall have to use the POP3 protocol (Post Office Protocol 3)
Objetives
We will continue some of the points mentioned in the previous article, in order to be able to implement message reception.
The points to be developed are:
POP3 authentication
Authentication in POP3 servers is mandatory, different from SMTP which is optional, for which reason data from the user must be sent to the server, so it autenticates it and allows the examination of all messages stored in the inbox.
The POP3 protocol has several methods for authentication, of which we are going to examine two: flat authentication and MD5. To do this we shall have to use the commands from the previous article, USER/PASS and APOP.
Flat authentication
This type of authentication is very simple, as in the case of SMTP: the data are transferred in a flat manner to the server and the latter validates the data and responds whether they are or not valid.
USER ianni_roberto@server.com.ar +OK password required for user ianni_roberto@server.com.ar PASS 123456789 -ERR [AUTH] Authentication failed
As can be seen in this example, we first pass the user name to the server and it answers saying that it is waiting for the user password. Then, POP3 has to reply "+OK" or "-ERR". This gives us an indication whether the data sent to the server are valid or, in case "-ERR" is returned, almost always it is accompanied by a descriptive message with the reason the error occurred, in this case, an authentication error ( "[AUTH] Authentication failed" ).
As seen, this type of authentication is really very simple but also not very safe, because any person could catch the packages traveling through the network, and get very easily the user name and password.
MD5 authentication
This type of validation guards against someone listening in the network and catching the information package being sent, with user name and password, to the POP3 server. If this person could get the package, it would be of little use to him, because the information sent is not clear, and is only valid in the context of the connection already made, between the client (who sent the password) and the POP3 server (receiving the password). This means that the password sent changes every time a connection to the POP3 occurs.
In order to send the password in the MD5 format, the APOP command should be used. As already seen this command includes the USER and PASS commands, receiving the user name as the parameter, as well as the password, both in a flat manner.
APOP ianni_roberto@server.com.ar 65c28d9c3edff5d31b644225287885b2 +OK
As seen in the example, we first send the user name to the APOP command, which is the same we send it with the USER command. Then we send a separation space, and as a last parameter, we send the user password in MD5 format.
This MD5 formatted password is the one that changes with every connection made on the POP3 server. This is based on the way the password is generated in this format.
In order to correctly generate the password, the POP3 server sends us the following information, when we obtain the connection: a series of numbers and a time stamp, which it combines with our password using the MD5 algorithm. The result is a series of letters and numbers through which we cannot return to the original password.
Connection example:
telnet 127.0.0.1 110
Welcome to the POP3 server, version 1.1.0.1.9 beta <123654789> APOP ianni_roberto@server.com.ar 65c28d9c3edff5d31b644225287885b2 +OK
In the example we can see how we connect to the POP3 server and, in establishing the conversation, the server sends a first line where it greets us and indicates the time stamp we need for the MD5 verification.
The time stamp is always surrounded by the greater and less than signs "<>" and in some cases, it can also have letters, in addition to the numbers. We then generate a password, joining the original password to the server time stamp. This is the password we send to the server. In order to verify this password, the server does the same thing: it generates a password with the timestamp sent plus the original password sent by the user. If the data are equal, the password is real.
Then we take the number sent by the server "123654789" and join it to the password "MiClave". When we apply the algorithm we get as a result the temporary password "65c28d9c3edff5d31b644225287885b2" which is the one being sent to the server.
I implemented the algorithm in C++, within the FLL FoxUtils library, with an exposed function called EncodeMD5. I did this in C++, not because of any limitation in VFP, but for comfort in writing the algorithm, because it has a lot of bit level management.
In the FoxUtils.prg class we shall implement a new method called StringEncodeMD5, which will be in charge of calling the FLL function, that result being the one we shall send to the POP3 as a temporary user password.
DEFINE CLASS WPop3 AS CUSTOM OLEPUBLIC ... *|-- MD5 authentication.- lsPassMD5 = This.m_ObjUtils.StringEncodeMD5( ALLTRIM( This.m_sTimeStamp ) ; + ALLTRIM( This.m_PassPOP3 ) ) IF( This.m_SocketConn.Enviar( "APOP " + ALLTRIM( This.m_UsrPOP3 ) ; + " " + ALLTRIM( lsPassMD5 ) + ENTER ) ) IF( !This.VerificarRespuesta( THIS.m_SocketConn.Recibir(), NO_ERRORS ) ) This.m_Error = "User or password invalid" RETURN .F. ENDIF ENDIF ... ENDDEFINE DEFINE CLASS FoxUtils AS Custom ... PROCEDURE StringEncodeMD5( lsToEncode ) RETURN( EncodeMD5( lsToEncode ) ) ENDPROC ... ENDDEFINE
MD5 algorithm
With what we have seen thus far, we can say, without many details, that the MD5 (Message-Digest Algorithm) is a hash function, also called "one-way" because given a text (a bytes sequence) a unique value is returned, but starting with that unique value the original text. Hence the name "one way or one address". For those of you who know CRC, you will realize that it is the same thing, but with another algorithm.
In order to implement it within the FLL, we have something like this:
FoxInfo myFoxInfo[] = { {"EncodeMD5", (FPFI) EncodeMD5, 1, "C"}, };
I do not want to go into too much detail, because it would be too long and the sense of this article would be lost. The point here is to explain how to receive POP3 messages, but I give you the implementation in the FLL so you can see it, and the theory behind it all at http://www.faqs.org/rfcs/rfc1321.html.
eMail parsing
As seen in the previous article, when we ask the POP3 server to give us a message, it returns a string containing the whole email, so in order to obtain the detail information on who sends the message, at what time, to whom reply, how many attachments have to be parsed in the string, etc., we use this code:
RETR 1 +OK Return-Path: Delivered-To: CI-ianni_roberto@server.com.ar Received: (qmail 2516 invoked from network); 31 Aug 2004 10:55:57 -0000 Received: from unknown (HELO postino9.prima.com.ar) (172.16.1.100) by cumeil13.int.prima.com.ar with SMTP; 31 Aug 2004 10:55:57 -0000 Received: (qmail 63214 invoked by uid 10006); 31 Aug 2004 10:55:57 -0000 Received: (Antivirus 0e1d36106fc2798aa1704741707bfb9c); 31 Aug 2004 10:55:57 -0000 Received: (qmail 63186 invoked from network); 31 Aug 2004 10:55:56 -0000 Received: from unknown (HELO hotmail.com) (64.4.47.34) by postino9.prima.com.ar with SMTP; 31 Aug 2004 10:55:56 -0000 Received: from mail pickup service by hotmail.com with Microsoft SMTPSVC; Tue, 31 Aug 2004 03:55:54 -0700 Received: from 201.254.49.143 by by9fd.bay9.hotmail.msn.com with HTTP; Tue, 31 Aug 2004 10:55:54 GMT X-Originating-IP: [201.254.49.143] X-Originating-Email: [ianni_roberto@hotmail.com] X-Sender: ianni_roberto@hotmail.com From: "Roberto Ianni" To: ianni_roberto@server.com.ar Bcc: Subject: Test POP3 Date: Tue, 31 Aug 2004 07:55:54 -0300 Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_4c56_2fea_2f76" Message-ID: X-OriginalArrivalTime: 31 Aug 2004 10:55:54.0449 (UTC) FILETIME=[16679C10:01C48F49] This is a multi-part message in MIME format.
This simple example on how the server returns a message, through the RETR command, allows us to see that each line is separated by an ENTER and that each one has an identifier and a value: "To: ianni_roberto@server.com.ar". In this case "To" is the identifier and "ianni_roberto@server.com.ar" is the value.
Suppose we want to obtain the subject from the message. We would have to examine line by line until we found the "Subject:" identifier and the value of this identifier would be the subject that the person originating the email placed there. Here is a simple implementation:
PROTECTED ObtenerLineHeader( lsFindLine, lsLine ) lnPos = ATCLINE( lsFindLine, This.m_MailHeader ) IF( lnPos > 0 ) lsLine = MLINE( This.m_MailHeader, lnPos ) ELSE lsLine = "" RETURN .F. ENDIF ENDPROC
As we can see, the ObtenerLineHeader method is not complex at all.The only thing it does is use ATCLINE on the property containing the string returned by the POP3 server and, if found, it returns the whole line, with the identifier and the value. We would only have to obtain the line value.
So now we would have to get the subject, the only thing we want to know.
sVal = SPACE(20) oMail.ObtenerLineHeader( "Subject:", @sVal )
We would have to repeat this procedure to obtain all the values from the message, such as the date, the message-ID , the x-sender, etc.
Conclusion
As seen, the points analyzed here are not complex at all and allowed us to understand two POP3 authentication mechanisms. We also understood how to obtain the values we wanted from the string formed by the message. With these foundations we are ready to get the BodyParts of the message, either the message body or the attached files.