Home arrow Delphi-Kylix arrow Page 3 - Creating a POP3 Server
DELPHI-KYLIX

Creating a POP3 Server


A POP3 server is a protocol that follows the RFC 1939 specification. It responds to a set of commands issued by a pop3 client. A POP3 Server is basically a go between, between a pop3 Client and a mail server.  In this article, we will create the code to respond to those commands issued by a pop3 client such as Microsoft Outlook or Eudora.

Author Info:
By: Leidago
Rating: 5 stars5 stars5 stars5 stars5 stars / 16
April 26, 2006
TABLE OF CONTENTS:
  1. · Creating a POP3 Server
  2. · Setting the database connections
  3. · Implementing the Commands
  4. · Implementing the Commands, continued
  5. · Conclusion

See Also:
print this article
SEARCH DEVARTICLES

TOOLS YOU CAN USE

advertisement
Creating a POP3 Server - Implementing the Commands
(Page 3 of 5 )

Once you have all of the components in place and connected, click on pops and go to the object inspector. Click on the events tab, double click on "OnCheckUser" and add the following code:

procedure TForm1.popsCheckUser(aContext: TIdContext;
  aServerContext: TIdPOP3ServerContext);
begin
coinitialize(nil);
 q2.Close;
//Search for the username and password in "users" table..
q2.SQL.Text := 'SELECT * from users WHERE uname=:user AND
upass=:pwd';
        q2.Parameters.ParamByName('user').Value :=
aServerContext.Username;
        q2.Parameters.ParamByName('pwd').Value :=
aServerContext.Password;
        q2.open;
//if the user is not found, display an error...       
if q2.RecordCount = 0 then raise Exception.Create('Authentication
failed');
 couninitialize;
end;

The above procedure checks whether the username and password exist in the database.

Next, we deal with the DELE(TE) command. The delete command is in the following format: DELE msgNo. Below is a example C(lient) request the S(erver) to delete msg numbers 1 and 2:

C: DELE 1
             S: +OK message 1 deleted
                ...
C: DELE 2
             S: -ERR message 2 already deleted

 

Double click on  OnDelete and add the following code:

procedure TForm1.popsDelete(aCmd: TIdCommand; AMsgNo: Integer);
var
n1,n2:integer;
Data:TStringList;
begin
 Data := TStringList.Create;
        try
            ado1.Open;
//Check if a valid message number has been requested...
            if (AMsgNo < 1) or (AMsgNo > ado1.RecordCount) then
                raise Exception.Create('invalid message number');
            ado1.RecNo := AMsgNo;
            n2:=ado1.Fieldbyname('mid').AsInteger;
            n1:=1;
//mark the message for deletion...
q2.Close;
q2.SQL.text:='UPDATE email SET ismarked=:num WHERE mid =:msgnum';
q2.Parameters.ParamByName('num').Value:=n1;
q2.Parameters.ParamByName('msgnum').Value:=n2;
q2.ExecSQL;
//Send a reply confirming that message has been deleted
            aCmd.Reply.SetReply(OK, 'message'+inttostr(amsgno)
+'deleted');
            aCmd.SendReply; // <-- YOU MUST DO THIS BEFORE
SENDING THE DATA
            //aCmd.Context.Connection.WriteRFCStrings(Data); //
<-- INCLUDESTHE TERMINATING '.' LINE
        finally
           FreeAndNil(Data);
        end;

Now, you do not actually delete the messages at this point. All that you do is mark them for deletion when the pop3client disconnects from the server. In the above code, to mark a message for deletion I insert "1" in the ismarked column of the table, so, when the pop3 client quits or disconnects, the server will automatically search for messages where the column ismarked is set to 1 for deletion. The way I checked the validity of the msgNo is by comparing the msgNo by the number of records (ado1.RecordCount) in the database. If the message number is  greater than the number of records, then an exception will be raised.

Next is the RSET command. This resets (unmarks) any messages previously marked for deletion in this session so that the QUIT command will not delete them. Below is a short example:

C: RSET
             S: +OK maildrop has 2 messages (320 octets)

That is the end of the example. Now for some real code:

procedure TForm1.popsReset(aCmd: TIdCommand);
var
n1,n2,i:integer;
begin
n1:=1;//marked for deletion
n2:=0;//not marked
q2.Close;
q2.SQL.text:='select * FROM email WHERE ismarked =:num';
q2.Parameters.ParamByName('num').Value:=n1;
q2.open;
//there are messages marked for deletion
if q2.RecordCount > 0 then begin
for i:= 1 to q2.RecordCount do begin
//reset unmark them
q2.Close;
q2.SQL.text:='UPDATE email SET ismarked=:num';
q2.Parameters.ParamByName('num').Value:=n2;
q2.ExecSQL;
end;
end;
 q2.Close;
//get the count of message that is NOT marked
q2.SQL.text:='select * FROM email WHERE ismarked =:num';
q2.Parameters.ParamByName('num').Value:=n2;
q2.open;
//Sent off the count of messages that is not marked
 aCmd.Reply.SetReply(OK, inttostr(q2.RecordCount)+' messages
available');
 aCmd.SendReply; // <-- YOU MUST DO THIS BEFORE SENDING THE DATA
end;

The LIST command lists all the messages with their message ID and the message size. Below is an example of the LIST command:       

             C: LIST
             S: +OK 2 messages (320 octets)
             S: 1 120
             S: 2 200
             S: .
               ...
             C: LIST 2
             S: +OK 2 200
               ...
             C: LIST 3
             S: -ERR no such message, only 2 messages in maildrop

That is the end of that example; now for some more code:

procedure TForm1.popsList(aCmd: TIdCommand; AMsgNo: Integer);
var
msgnum,thesize:integer;
begin
 CoInitialize(nil);
q2.Close;
q2.SQL.text:='SELECT SUM(msize) AS tsize from email';
q2.open;
//get the size of the total messages...
thesize:=q2.fieldbyname('tsize').AsInteger;
 q2.Close;
q2.SQL.text:='SELECT * from email';
q2.open;
//Get total number of messages
msgnum:= q2.recordcount;
//now, send a reply ...
aCmd.Reply.SetReply(OK, inttostr(msgnum) + ' messages  '+'('+inttostr(thesize) + ' octets)');
     aCmd.SendReply;
 q2.Close;
q2.SQL.text:='SELECT * from email';
q2.open;
q2.First;
while not q2.EOF do
begin
with aCmd.Context.Connection.IOHandler do
begin
WriteLn(inttostr(q2.RecNo{.Fieldbyname('mid').Value}) +' '+
inttostr(q2.Fieldbyname('msize').Value));
q2.Next;
end;//cmd
end;//w
aCmd.Context.Connection.IOHandler.writeln('.');
 CoUnInitialize;
end;

Sometimes pop3 clients include a msgNo with this command, in which case you will have to retrieve that specific message based on its msgNo. But generally this won't be the case.


blog comments powered by Disqus
DELPHI-KYLIX ARTICLES

- Loading an XML Document into the DOM
- Delphi Wrapper Classes and XML
- Delphi and the DOM
- Delphi and XML
- Internet Access: Client Service
- Finishing the Client for an Internet Access ...
- The Client for an Internet Access Control Ap...
- User Management for an Internet Access Contr...
- Important Procedures for an Internet Access ...
- Server Code for an Internet Access Control A...
- Constructing the Interface for an Internet A...
- Building a Server Application for an Interne...
- Building an Internet Access Control Applicat...
- Client Dataset: Working with Data Packets an...
- Using the Client Dataset in an N-Tiered Appl...

Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 



© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 4 - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials