www.pudn.com > pop3cli.zip > POP3PROT.PAS


{*_* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 
Author:       François PIETTE 
Object:       TPop3Cli class implements the POP3 protocol 
              (RFC-1225, RFC-1939) 
EMail:        francois.piette@pophost.eunet.be    francois.piette@rtfm.be 
              http://www.rtfm.be/fpiette 
Creation:     03 october 1997 
Version:      2.06 
Support:      Use the mailing list twsocket@rtfm.be See website for details. 
Legal issues: Copyright (C) 1997, 1998 by François PIETTE 
              Rue de Grady 24, 4053 Embourg, Belgium. Fax: +32-4-365.74.56 
               
 
              This software is provided 'as-is', without any express or 
              implied warranty.  In no event will the author be held liable 
              for any  damages arising from the use of this software. 
 
              Permission is granted to anyone to use this software for any 
              purpose, including commercial applications, and to alter it 
              and redistribute it freely, subject to the following 
              restrictions: 
 
              1. The origin of this software must not be misrepresented, 
                 you must not claim that you wrote the original software. 
                 If you use this software in a product, an acknowledgment 
                 in the product documentation would be appreciated but is 
                 not required. 
 
              2. Altered source versions must be plainly marked as such, and 
                 must not be misrepresented as being the original software. 
 
              3. This notice may not be removed or altered from any source 
                 distribution. 
 
              4. You must register this software by sending a picture postcard 
                 to the author. Use a nice stamp and mention your name, street 
                 address, EMail address and any comment you like to say. 
 
Updates: 
Sept 09, 1997 Modified TOP to be able to request 0 lines (bug reported by 
              damien@jetman.demon.co.uk) 
Oct 10, 1997  V1.10. Published ProtocolState property, made TOP command 
              complies with RFC-1939 as suggested by damien@jetman.demon.co.uk 
              Implemented the UIDL command. 
Oct 11, 1997  V1.11 Implemented the APOP command, but not tested because no 
              server available to test it. 
              Made internal error message look like POP3 error messages (-ERR) 
Oct 28, 1997  V1.12 Modified TWSocket to handle line buffer overflow and 
              TPop3Client to handle that in GetMultiLine. 
Jan 10, 1998  V1.13 Made FWSocket accessible with a read only property. This 
              eases DNSLookup without a supplementary TWSocket. 
              Added a Port property. 
Apr 01, 1998  V1.14 Adapted for BCB V3 
May 05, 1998  V1.15 Changed GetMultiLine to correctly handle double dots at 
              line start. 
Jun 01, 1998  V1.16 Ben Robinson  found that Last did'nt 
              update MsgNum and MsgSize. 
Aug 05, 1998  V2.00 New asynchronous version. 
Sep 19, 1998  V2.01 Corrected WSocketDataAvailable to count for the added 
              nul byte at the end of buffer. 
Nov 28, 1998  V2.02 Corrected exception triggered using highlevel function 
              when connection or DNS lookup failed (for example using Open). 
Dec 03, 1998  V2.03 Added SetErrorMessage in WSocketSessionConnected. 
Dec 22, 1998  V2.04 Handle exception when connecting (will be triggered when 
              an invalid port has been given). 
Feb 27, 1999  V2.05 Adde State property. 
Mar 07, 1999  V2.06 Made public property Connected. 
 
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
unit Pop3Prot; 
 
interface 
 
{$B-}           { Enable partial boolean evaluation   } 
{$T-}           { Untyped pointers                    } 
{$IFNDEF VER80} { Not for Delphi 1                    } 
    {$J+}       { Allow typed constant to be modified } 
{$ENDIF} 
{$IFDEF VER110} { C++ Builder V3.0                    } 
    {$ObjExportAll On} 
{$ENDIF} 
 
uses 
    WinTypes, WinProcs, SysUtils, Messages, Classes, Graphics, Controls, 
    Forms, Dialogs, Menus, WSocket, WinSock, MD5; 
 
const 
    Pop3CliVersion     = 206; 
    CopyRight : String = ' POP3 component (c) 97-98 F. Piette V2.06 '; 
{$IFDEF VER80} 
    { Delphi 1 has a 255 characters string limitation } 
    POP3_RCV_BUF_SIZE = 255; 
{$ELSE} 
    POP3_RCV_BUF_SIZE = 4096; 
{$ENDIF} 
    WM_POP3_REQUEST_DONE = WM_USER + 1; 
 
type 
    Pop3Exception = class(Exception); 
    TPop3Display  = procedure(Sender: TObject; Msg : String) of object; 
    TPop3ProtocolState  = (pop3Disconnected,  pop3WaitingUser, 
                           pop3WaitingPass,   pop3Transaction); 
    TPop3State    = (pop3Ready,         pop3DnsLookup,       pop3Connecting, 
                     pop3Connected,     pop3InternalReady, 
                     pop3WaitingBanner, pop3WaitingResponse, pop3Abort); 
    TPop3Request  = (pop3Connect, pop3User, pop3Pass, pop3RPop, pop3Quit, 
                     pop3Stat,    pop3List, pop3Retr, pop3Top,  pop3Dele, 
                     pop3Noop,    pop3Last, pop3RSet, pop3Uidl, pop3APop, 
                     pop3Open,    pop3Custom); 
    TPop3Fct      = (pop3FctNone,   pop3FctConnect, pop3FctUser, pop3FctPass, 
                     pop3FctRPop,   pop3FctQuit,    pop3FctAPop, pop3FctStat, 
                     pop3FctList, pop3FctUidl, pop3FctRetr, pop3FctTop, 
                     pop3FctDele, pop3FctNoop, pop3FctRSet, pop3FctLast); 
    TPop3FctSet   = set of TPop3Fct; 
    TPop3NextProc = procedure of object; 
    TPop3RequestDone        = procedure(Sender  : TObject; 
                                        RqType    : TPop3Request; 
                                        Error     : Word) of object; 
    TPop3Method   = function : boolean of object; 
    TCustomPop3Cli = class(TComponent) 
    private 
        FWSocket            : TWSocket; 
        FWindowHandle       : HWND; 
        FState              : TPop3State; 
        FNextProtocolState  : TPop3ProtocolState; 
        FProtocolState      : TPop3ProtocolState; 
        FConnected          : Boolean; 
        FRequestType        : TPop3Request; 
        FRequestDoneFlag    : Boolean; 
        FReceiveLen         : Integer; 
        FRequestResult      : Integer; 
        FStatusCode         : Integer; 
        FReceiveBuffer      : array [0..POP3_RCV_BUF_SIZE - 1] of char; 
        FNext               : TPop3NextProc; 
        FWhenConnected      : TPop3NextProc; 
        FFctSet             : TPop3FctSet; 
        FFctPrv             : TPop3Fct; 
        FHighLevelResult    : Integer; 
        FHighLevelFlag      : Boolean; 
        FNextRequest        : TPop3NextProc; 
        FLastResponseSave   : String; 
        FStatusCodeSave     : Integer; 
        FRestartFlag        : Boolean; 
        FDoneAsync          : TPop3NextProc; 
        FMultiLineLine      : TNotifyEvent; 
        FMultiLineEnd       : TNotifyEvent; 
        FMultiLineProcess   : TNotifyEvent; 
        FHost           : String; 
        FPort           : String; 
        FUserName       : String; 
        FPassWord       : String; 
        FLastResponse   : String; 
        FErrorMessage   : String; 
        FTimeStamp      : String; 
        FMsgCount       : Integer; 
        FMsgSize        : Integer; 
        FMsgNum         : Integer; 
        FMsgUidl        : String; 
        FMsgLines       : Integer; 
        FTag            : LongInt; 
 
        FOnDisplay      : TPop3Display; 
        FOnMessageBegin : TNotifyEvent; 
        FOnMessageEnd   : TNotifyEvent; 
        FOnMessageLine  : TNotifyEvent; 
        FOnListBegin    : TNotifyEvent; 
        FOnListEnd      : TNotifyEvent; 
        FOnListLine     : TNotifyEvent; 
        FOnUidlBegin    : TNotifyEvent; 
        FOnUidlEnd      : TNotifyEvent; 
        FOnUidlLine     : TNotifyEvent; 
        FOnStateChange      : TNotifyEvent; 
        FOnRequestDone      : TPop3RequestDone; 
        FOnResponse         : TPop3Display; 
        FOnSessionConnected : TSessionConnected; 
        FOnSessionClosed    : TSessionClosed; 
    protected 
        procedure   ExecAsync(RqType      : TPop3Request; 
                              Cmd         : String; 
                              NextState   : TPop3ProtocolState; 
                              DoneAsync   : TPop3NextProc); 
        procedure   NextExecAsync; 
        procedure   StartTransaction(OpCode      : String; 
                                     Params      : String; 
                                     RqType      : TPop3Request; 
                                     NextState   : TPop3ProtocolState; 
                                     DoneTrans   : TPop3NextProc); 
        procedure   StartMultiLine(aOnBegin : TNotifyEvent; 
                                   aOnLine  : TNotifyEvent; 
                                   aOnEnd   : TNotifyEvent; 
                                   aProcess : TNotifyEvent); 
        procedure   GetALine; 
        procedure   StatDone; 
        procedure   ListAllDone; 
        procedure   ListSingleDone; 
        procedure   UidlAllDone; 
        procedure   UidlSingleDone; 
        procedure   RetrDone; 
        procedure   LastDone; 
        procedure   WndProc(var MsgRec: TMessage); virtual; 
        procedure   WMPop3RequestDone(var msg: TMessage); 
                        message WM_POP3_REQUEST_DONE; 
        procedure   WSocketDnsLookupDone(Sender: TObject; Error: Word); 
        procedure   WSocketSessionConnected(Sender: TObject; Error: Word); 
        procedure   WSocketDataAvailable(Sender: TObject; Error: Word); 
        procedure   WSocketSessionClosed(Sender : TObject; Error : WORD); 
        procedure   DisplayLastResponse; 
        procedure   TriggerDisplay(Msg : String); 
        procedure   TriggerSessionConnected(Error : Word); virtual; 
        procedure   TriggerSessionClosed(Error : Word); 
        procedure   TriggerResponse(Msg : String); virtual; 
        procedure   TriggerStateChange; virtual; 
        procedure   TriggerRequestDone(Error: Word); virtual; 
        function    OkResponse : Boolean; 
        procedure   StateChange(NewState : TPop3State); 
        procedure   Notification(AComponent: TComponent; Operation: TOperation); override; 
        procedure   ClearErrorMessage; 
        procedure   SetErrorMessage; 
        procedure   Display(Msg : String); 
        procedure   SendCommand(Cmd : String); 
        function    ExtractNumbers(var N1 : Integer; var N2 : Integer) : Boolean; 
        function    ExtractUidl(var N1 : Integer; var N2 : String) : Boolean; 
        procedure   ProcessUidl(Sender : TObject); 
        procedure   ProcessList(Sender : TObject); 
        procedure   CheckReady; 
        procedure   DoHighLevelAsync; 
    public 
        constructor Create(AOwner : TComponent); override; 
        destructor  Destroy; override; 
        procedure   Connect; virtual; 
        procedure   Open; virtual; 
        procedure   User; virtual; 
        procedure   Pass; virtual; 
        procedure   RPop; virtual; 
        procedure   APop; virtual; 
        procedure   Quit; virtual; 
        procedure   Stat; virtual; 
        procedure   List; virtual; 
        procedure   Retr; virtual; 
        procedure   Top;  virtual; 
        procedure   Dele; virtual; 
        procedure   Noop; virtual; 
        procedure   Last; virtual; 
        procedure   RSet; virtual; 
        procedure   Uidl; virtual; 
        procedure   Abort; virtual; 
        procedure   HighLevelAsync(RqType : TPop3Request; Fcts : TPop3FctSet); 
 
        property WSocket : TWSocket                  read  FWSocket; 
        property Host : String                       read  FHost 
                                                     write FHost; 
        property Port : String                       read  FPort 
                                                     write FPort; 
        property UserName : String                   read  FUserName 
                                                     write FUserName; 
        property PassWord : String                   read  FPassWord 
                                                     write FPassWord; 
        property ErrorMessage  : String              read  FErrorMessage; 
        property LastResponse  : String              read  FLastResponse; 
        property State         : TPop3State          read  FState; 
        property Connected     : Boolean             read  FConnected; 
        property ProtocolState : TPop3ProtocolState  read  FProtocolState; 
        {:Updated by the Stat method with the number of 
          messages in the maildrop } 
        property MsgCount : Integer                  read  FMsgCount; 
        {:Updated by the Stat method with the total size 
          in byte for the messages in the maildrop } 
        property MsgSize : Integer                   read  FMsgSize; 
        {:This is the number of lines to display in the TOP command 
          Set to zero if you wants the default value } 
        property MsgLines : Integer                  read  FMsgLines 
                                                     write FMsgLines; 
        {:This is the message number which must be returned by the Retr 
          method. It is also updated by the Last method } 
        property MsgNum : Integer                    read  FMsgNum 
                                                     write FMsgNum; 
        property MsgUidl : String                    read  FMsgUidl; 
        property Tag : LongInt                       read  FTag 
                                                     write FTag; 
        property Handle  : HWND                      read  FWindowHandle; 
 
        property OnDisplay : TPop3Display            read  FOnDisplay 
                                                     write FOnDisplay; 
        property OnMessageBegin : TNotifyEvent       read  FOnMessageBegin 
                                                     write FOnMessageBegin; 
        property OnMessageEnd : TNotifyEvent         read  FOnMessageEnd 
                                                     write FOnMessageEnd; 
        property OnMessageLine : TNotifyEvent        read  FOnMessageLine 
                                                     write FOnMessageLine; 
        property OnListBegin : TNotifyEvent          read  FOnListBegin 
                                                     write FOnListBegin; 
        property OnListEnd : TNotifyEvent            read  FOnListEnd 
                                                     write FOnListEnd; 
        property OnListLine : TNotifyEvent           read  FOnListLine 
                                                     write FOnListLine; 
        property OnUidlBegin : TNotifyEvent          read  FOnUidlBegin 
                                                     write FOnUidlBegin; 
        property OnUidlEnd : TNotifyEvent            read  FOnUidlEnd 
                                                     write FOnUidlEnd; 
        property OnUidlLine : TNotifyEvent           read  FOnUidlLine 
                                                     write FOnUidlLine; 
        property OnStateChange : TNotifyEvent        read  FOnStateChange 
                                                     write FOnStateChange; 
        property OnRequestDone : TPop3RequestDone    read  FOnRequestDone 
                                                     write FOnRequestDone; 
        property OnResponse: TPop3Display            read  FOnResponse 
                                                     write FOnResponse; 
        property OnSessionConnected : TSessionConnected 
                                                     read  FOnSessionConnected 
                                                     write FOnSessionConnected; 
        property OnSessionClosed : TSessionClosed 
                                                     read  FOnSessionClosed 
                                                     write FOnSessionClosed; 
    end; 
 
    TPop3Cli = class(TCustomPop3Cli) 
    published 
        property Host; 
        property Port; 
        property UserName; 
        property PassWord; 
        property ErrorMessage; 
        property LastResponse; 
        property ProtocolState; 
        property MsgCount; 
        property MsgSize; 
        property MsgLines; 
        property MsgNum; 
        property MsgUidl; 
        property Tag; 
        property OnDisplay; 
        property OnMessageBegin; 
        property OnMessageEnd; 
        property OnMessageLine; 
        property OnListBegin; 
        property OnListEnd; 
        property OnListLine; 
        property OnUidlBegin; 
        property OnUidlEnd; 
        property OnUidlLine; 
        property OnStateChange; 
        property OnRequestDone; 
        property OnResponse; 
        property OnSessionConnected; 
        property OnSessionClosed; 
    end; 
 
    { TSyncPop3Cli add synchronous functions. You should avoid using this   } 
    { component because synchronous function, apart from being easy, result } 
    { in lower performance programs.                                        } 
    TSyncPop3Cli = class(TPop3Cli) 
    protected 
        FTimeout       : Integer;                 { Given in seconds } 
        FTimeStop      : LongInt;                 { Milli-seconds    } 
        FMultiThreaded : Boolean; 
        function WaitUntilReady : Boolean; virtual; 
        function Synchronize(Proc : TPop3NextProc) : Boolean; 
    public 
        constructor Create(AOwner : TComponent); override; 
        function    ConnectSync  : Boolean; virtual; 
        function    OpenSync     : Boolean; virtual; 
        function    UserSync     : Boolean; virtual; 
        function    PassSync     : Boolean; virtual; 
        function    RPopSync     : Boolean; virtual; 
        function    APopSync     : Boolean; virtual; 
        function    QuitSync     : Boolean; virtual; 
        function    StatSync     : Boolean; virtual; 
        function    ListSync     : Boolean; virtual; 
        function    RetrSync     : Boolean; virtual; 
        function    TopSync      : Boolean; virtual; 
        function    DeleSync     : Boolean; virtual; 
        function    NoopSync     : Boolean; virtual; 
        function    LastSync     : Boolean; virtual; 
        function    RSetSync     : Boolean; virtual; 
        function    UidlSync     : Boolean; virtual; 
        function    AbortSync    : Boolean; virtual; 
    published 
        property Timeout : Integer       read  FTimeout 
                                         write FTimeout; 
        property MultiThreaded : Boolean read  FMultiThreaded 
                                         write FMultiThreaded; 
    end; 
 
procedure Register; 
 
implementation 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
{$IFDEF VER80} 
procedure SetLength(var S: string; NewLength: Integer); 
begin 
    S[0] := chr(NewLength); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function RTrim(Str : String) : String; 
var 
    i : Integer; 
begin 
    i := Length(Str); 
    while (i > 0) and (Str[i] = ' ') do 
        i := i - 1; 
    Result := Copy(Str, 1, i); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function LTrim(Str : String) : String; 
var 
    i : Integer; 
begin 
    if Str[1] <> ' ' then             { Petite optimisation: pas d'espace   } 
        Result := Str 
    else begin 
        i := 1; 
        while (i <= Length(Str)) and (Str[i] = ' ') do 
            i := i + 1; 
        Result := Copy(Str, i, Length(Str) - i + 1); 
    end; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function Trim(Str : String) : String; 
begin 
    Result := LTrim(Rtrim(Str)); 
end; 
{$ENDIF} 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function stpblk(PValue : PChar) : PChar; 
begin 
    Result := PValue; 
    while Result^ in [' ', #9, #10, #13] do 
        Inc(Result); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function atoi(PValue : PChar) : Integer; 
begin 
    Result := 0; 
    PValue := stpblk(PValue); 
    while PValue^ in ['0'..'9'] do begin 
        Result := Result * 10 + ord(PValue^) - ord('0'); 
        Inc(PValue); 
    end; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
constructor TCustomPop3Cli.Create(AOwner : TComponent); 
begin 
    inherited Create(AOwner); 
    FWindowHandle            := AllocateHWnd(WndProc); 
    FWSocket                 := TWSocket.Create(nil); 
    FWSocket.OnSessionClosed := WSocketSessionClosed; 
    FProtocolState           := pop3Disconnected; 
    FState                   := pop3Ready; 
    FPort                    := 'pop3'; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
destructor TCustomPop3Cli.Destroy; 
begin 
    if Assigned(FWSocket) then begin 
        FWSocket.Destroy; 
        FWSocket := nil; 
    end; 
    DeallocateHWnd(FWindowHandle); 
    inherited Destroy; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.WndProc(var MsgRec: TMessage); 
begin 
     with MsgRec do begin 
         case Msg of 
         WM_POP3_REQUEST_DONE : WMPop3RequestDone(MsgRec); 
         else 
             Result := DefWindowProc(Handle, Msg, wParam, lParam); 
         end; 
    end; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.WMPop3RequestDone(var msg: TMessage); 
begin 
    if Assigned(FOnRequestDone) then 
        FOnRequestDone(Self, FRequestType, Msg.LParam); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.Notification(AComponent: TComponent; Operation: TOperation); 
begin 
    inherited Notification(AComponent, Operation); 
    if Operation = opRemove then begin 
        if AComponent = FWSocket then 
            FWSocket := nil; 
    end; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.WSocketDnsLookupDone(Sender: TObject; Error: Word); 
begin 
    if Error <> 0 then begin 
        FLastResponse  := '-ERR ' + WSocketErrorDesc(Error) + 
                          ' (Winsock error #' + IntToStr(Error) + ')'; 
        FStatusCode    := 500; 
        FRequestResult := Error;      { V2.02 } 
        SetErrorMessage; 
        TriggerRequestDone(Error); 
    end 
    else begin 
        FWSocket.Addr  := FWSocket.DnsResult; 
        FWSocket.Proto := 'tcp'; 
        FWSocket.Port  := FPort; 
        FWSocket.OnSessionConnected := WSocketSessionConnected; 
        FWSocket.OnDataAvailable    := WSocketDataAvailable; 
        StateChange(pop3Connecting); 
        try 
            FWSocket.Connect; 
        except 
            on E:Exception do begin 
                FLastResponse  := '-ERR ' + E.ClassName + ': ' + E.Message; 
                FStatusCode    := 500; 
                FRequestResult := FStatusCode; 
                SetErrorMessage; 
                TriggerRequestDone(FStatusCode); 
            end; 
        end 
    end; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.WSocketSessionConnected(Sender: TObject; Error: Word); 
begin 
    { Do not trigger the client SessionConnected from here. We must wait } 
    { to have received the server banner.                                } 
    if Error <> 0 then begin 
        FLastResponse  := '-ERR ' + WSocketErrorDesc(Error) + 
                          ' (Winsock error #' + IntToStr(Error) + ')'; 
        FStatusCode    := 500; 
        FConnected     := FALSE; 
        FRequestResult := Error;      { V2.02 } 
        SetErrorMessage;              { V2.03 } 
        TriggerRequestDone(Error); 
        FWSocket.Close; 
        StateChange(pop3Ready); 
    end 
    else begin 
        FConnected := TRUE; 
        StateChange(pop3WaitingBanner); 
    end; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.WSocketSessionClosed(Sender : TObject; Error : WORD); 
begin 
    FConnected := FALSE; 
    TriggerSessionClosed(Error); 
    TriggerRequestDone(WSAEINTR); 
    FProtocolState := pop3Disconnected; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.WSocketDataAvailable(Sender: TObject; Error: Word); 
var 
    Len  : Integer; 
    I, J : Integer; 
begin 
    Len := FWSocket.Receive(@FReceiveBuffer[FReceiveLen], 
                            sizeof(FReceiveBuffer) - FReceiveLen - 1); 
 
    if Len <= 0 then 
        Exit; 
 
    FReceiveBuffer[FReceiveLen + Len] := #0; 
    FReceiveLen := FReceiveLen + Len; 
 
    while FReceiveLen > 0 do begin 
        I := Pos(#13#10, FReceiveBuffer); 
        if I <= 0 then 
            break; 
        if I > FReceiveLen then 
            break; 
 
        FLastResponse := Copy(FReceiveBuffer, 1, I - 1); 
        TriggerResponse(FLastResponse); 
 
{$IFDEF DUMP} 
        FDumpBuf := '>|'; 
        FDumpStream.WriteBuffer(FDumpBuf[1], Length(FDumpBuf)); 
        FDumpStream.WriteBuffer(FLastResponse[1], Length(FLastResponse)); 
        FDumpBuf := '|' + #13#10; 
        FDumpStream.WriteBuffer(FDumpBuf[1], Length(FDumpBuf)); 
{$ENDIF} 
{$IFDEF VER80} 
        { Add a nul byte at the end of string for Delphi 1 } 
        FLastResponse[Length(FLastResponse) + 1] := #0; 
{$ENDIF} 
        FReceiveLen := FReceiveLen - I - 1; 
        if FReceiveLen > 0 then 
            Move(FReceiveBuffer[I + 1], FReceiveBuffer[0], FReceiveLen + 1); 
 
        if FState = pop3WaitingBanner then begin 
            DisplayLastResponse; 
            if not OkResponse then begin 
                SetErrorMessage; 
                FRequestResult := FStatusCode; 
                FWSocket.Close; 
                Exit; 
            end; 
            I := Pos('<', FLastResponse); 
            J := Pos('>', Copy(FLastResponse, I, Length(FLastREsponse))); 
            if (I > 0) and (J > 0) then 
                FTimeStamp := Copy(FLastResponse, I, J); 
 
            FProtocolState := pop3WaitingUser; 
            StateChange(pop3Connected); 
            TriggerSessionConnected(Error); 
 
            if Assigned(FWhenConnected) then 
                FWhenConnected 
            else begin 
                TriggerRequestDone(0); 
            end; 
        end 
        else if FState = pop3WaitingResponse then begin 
            if Assigned(FNext) then 
                FNext 
            else 
                raise Pop3Exception.Create('Program error: FNext is nil'); 
        end 
        else begin 
            { Unexpected data received } 
            DisplayLastResponse; 
        end; 
    end; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.TriggerResponse(Msg : String); 
begin 
    if Assigned(FOnResponse) then 
        FOnResponse(Self, Msg); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.TriggerStateChange; 
begin 
    if Assigned(FOnStateChange) then 
        FOnStateChange(Self); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.TriggerRequestDone(Error: Word); 
begin 
    if not FRequestDoneFlag then begin 
        FRequestDoneFlag := TRUE; 
        if Assigned(FNextRequest) then begin 
            if FState <> pop3Abort then 
                StateChange(pop3InternalReady); 
            FNextRequest; 
        end 
        else begin 
            StateChange(pop3Ready); 
            { Restore the lastresponse saved before quit command } 
            if FHighLevelFlag and (FStatusCodeSave >= 0) then begin 
                 FLastResponse := FLastResponseSave; 
                 FStatusCode   := FStatusCodeSave; 
            end; 
            FHighLevelFlag := FALSE; 
            PostMessage(Handle, WM_POP3_REQUEST_DONE, 0, Error); 
        end; 
    end; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.TriggerDisplay(Msg : String); 
begin 
    if Assigned(FOnDisplay) then 
        FOnDisplay(Self, Msg); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.TriggerSessionConnected(Error : Word); 
begin 
    if Assigned(FOnSessionConnected) then 
        FOnSessionConnected(Self, Error); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.TriggerSessionClosed(Error : Word); 
begin 
    if Assigned(FOnSessionClosed) then 
        FOnSessionClosed(Self, Error); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.DoHighLevelAsync; 
begin 
{$IFDEF TRACE} TriggerDisplay('! HighLevelAsync ' + IntToStr(FRequestResult)); {$ENDIF} 
    if FState = pop3Abort then begin 
        {$IFDEF TRACE} TriggerDisplay('! Abort detected'); {$ENDIF} 
        FFctSet := []; 
        FHighLevelResult := 426; 
        FErrorMessage    := '426 Operation aborted.'; 
    end; 
 
    FNextRequest := DoHighLevelAsync; 
 
    if FRequestResult <> 0 then begin 
        { Previous command had errors } 
        FHighLevelResult := FRequestResult; 
        if (FFctPrv = pop3FctQuit) or (not (pop3FctQuit in FFctSet)) then 
            FFctSet := [] 
        else 
            FFctSet := [pop3FctQuit]; 
    end; 
 
    if pop3FctConnect in FFctSet then begin 
        FFctPrv := pop3FctConnect; 
        FFctSet := FFctSet - [FFctPrv]; 
        Connect; 
        Exit; 
    end; 
 
    if pop3FctUser in FFctSet then begin 
        FFctPrv := pop3FctUser; 
        FFctSet := FFctSet - [FFctPrv]; 
        User; 
        Exit; 
    end; 
 
    if pop3FctPass in FFctSet then begin 
        FFctPrv := pop3FctPass; 
        FFctSet := FFctSet - [FFctPrv]; 
        Pass; 
        Exit; 
    end; 
 
    if pop3FctRPop in FFctSet then begin 
        FFctPrv := pop3FctRPop; 
        FFctSet := FFctSet - [FFctPrv]; 
        RPop; 
        Exit; 
    end; 
 
    if pop3FctDele in FFctSet then begin 
        FFctPrv := pop3FctDele; 
        FFctSet := FFctSet - [FFctPrv]; 
        Dele; 
        Exit; 
    end; 
 
    if pop3FctNoop in FFctSet then begin 
        FFctPrv := pop3FctNoop; 
        FFctSet := FFctSet - [FFctPrv]; 
        Noop; 
        Exit; 
    end; 
 
    if pop3FctList in FFctSet then begin 
        FFctPrv := pop3FctList; 
        FFctSet := FFctSet - [FFctPrv]; 
        List; 
        Exit; 
    end; 
 
    if pop3FctRSet in FFctSet then begin 
        FFctPrv := pop3FctRSet; 
        FFctSet := FFctSet - [FFctPrv]; 
        RSet; 
        Exit; 
    end; 
 
    if pop3FctAPop in FFctSet then begin 
        FFctPrv := pop3FctAPop; 
        FFctSet := FFctSet - [FFctPrv]; 
        APop; 
        Exit; 
    end; 
 
    if pop3FctRetr in FFctSet then begin 
        FFctPrv := pop3FctRetr; 
        FFctSet := FFctSet - [FFctPrv]; 
        Retr; 
        Exit; 
    end; 
 
    if pop3FctTop in FFctSet then begin 
        FFctPrv := pop3FctTop; 
        FFctSet := FFctSet - [FFctPrv]; 
        Top; 
        Exit; 
    end; 
 
    if pop3FctStat in FFctSet then begin 
        FFctPrv := pop3FctStat; 
        FFctSet := FFctSet - [FFctPrv]; 
        Stat; 
        Exit; 
    end; 
 
    if pop3FctUidl in FFctSet then begin 
        FFctPrv := pop3FctUidl; 
        FFctSet := FFctSet - [FFctPrv]; 
        Uidl; 
        Exit; 
    end; 
 
    if pop3FctLast in FFctSet then begin 
        FFctPrv := pop3FctLast; 
        FFctSet := FFctSet - [FFctPrv]; 
        Last; 
        Exit; 
    end; 
 
    if pop3FctQuit in FFctSet then begin 
        FFctPrv := pop3FctQuit; 
        FFctSet := FFctSet - [FFctPrv]; 
        Quit; 
        Exit; 
    end; 
 
    {$IFDEF TRACE} TriggerDisplay('! HighLevelAsync done'); {$ENDIF} 
    FFctSet          := []; 
    FNextRequest     := nil; 
    FRequestDoneFlag := FALSE; 
    TriggerRequestDone(FHighLevelResult); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.HighLevelAsync( 
    RqType : Tpop3Request; Fcts : Tpop3FctSet); 
begin 
    if FConnected and (pop3FctConnect in Fcts) then 
        raise pop3Exception.Create('pop3 component already connected'); 
    CheckReady; 
    FLastResponseSave := FLastResponse; 
    FStatusCodeSave   := -1; 
    FRequestType      := RqType; 
    FRequestResult    := 0; 
    FFctSet           := Fcts; 
    FFctPrv           := pop3FctNone; 
    FHighLevelResult  := 0; 
    FHighLevelFlag    := TRUE; 
    FLastResponse     := ''; 
    FErrorMessage     := ''; 
    FRestartFlag      := FALSE; 
    DoHighLevelAsync; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.ProcessUidl(Sender : TObject); 
begin 
    ExtractUidl(FMsgNum, FMsgUidl); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.ProcessList(Sender : TObject); 
begin 
    ExtractNumbers(FMsgNum, FMsgSize); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TCustomPop3Cli.ExtractUidl(var N1 : Integer; var N2 : String) : Boolean; 
var 
    p : PChar; 
begin 
    Result := FALSE; 
    N1     := 0; 
    N2     := ''; 
 
{$IFDEF VER80} 
    { Delphi 1 do not automatically nul terminate strings } 
    FLastResponse := FLastResponse + #0; 
{$ENDIF} 
 
    { Search for first digit in response } 
    p := @FLastResponse[1]; 
    while (p^ <> #0) and (not (p^ in ['0'..'9'])) do 
        Inc(p); 
    if p^ = #0 then { Invalid response, need a number } 
        Exit; 
 
    { Convert first number } 
    N1 := atoi(p); 
 
    { Search end of number } 
    while (p^ <> #0) and (p^ in ['0'..'9']) do 
        Inc(p); 
 
    { Search Uidl } 
    while (p^ = ' ') do 
        Inc(p); 
 
    { Copy UIDL } 
    while (p^ <> #0) and (p^ in [#33..#126]) do begin 
        N2 := N2 + p^; 
        Inc(p); 
    end; 
 
    Result := TRUE; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TCustomPop3Cli.ExtractNumbers(var N1 : Integer; var N2 : Integer) : Boolean; 
var 
    p : PChar; 
begin 
    Result := FALSE; 
 
{$IFDEF VER80} 
    { Delphi 1 do not automatically nul terminate strings } 
    FLastResponse := FLastResponse + #0; 
{$ENDIF} 
 
    { Search for first digit in response } 
    p := @FLastResponse[1]; 
    while (p^ <> #0) and (not (p^ in ['0'..'9'])) do 
        Inc(p); 
    if p^ = #0 then begin 
        { Invalid response, need a number } 
        N1 := 0; 
        N2 := 0; 
        Exit; 
    end; 
 
    { Convert first number } 
    N1 := atoi(p); 
 
    { Search end of number } 
    while (p^ <> #0) and (p^ in ['0'..'9']) do 
        Inc(p); 
 
    { Search next number } 
    p := stpblk(p); 
 
    if p^ = #0 then begin 
        { Invalid response, need a number } 
        N1 := 0; 
        N2 := 0; 
        Exit; 
    end; 
 
    N2     := atoi(p); 
    Result := TRUE; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.SendCommand(Cmd : String); 
begin 
    Display('> ' + Cmd); 
    Application.ProcessMessages; 
    FWSocket.SendStr(Cmd + #13 + #10); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TCustomPop3Cli.OkResponse : Boolean; 
begin 
    Result := ((Length(FLastResponse) > 0) and (FLastResponse[1] = '+')); 
    if Result then 
        FStatusCode := 0 
    else 
        FStatusCode := 500; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.Display(Msg : String); 
begin 
    if Assigned(FOnDisplay) then 
        FOnDisplay(Self, Msg); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.ClearErrorMessage; 
begin 
    FErrorMessage := ''; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.SetErrorMessage; 
begin 
    if FErrorMessage = '' then 
        FErrorMessage := FLastResponse; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.CheckReady; 
begin 
    if not (FState in [pop3Ready, pop3InternalReady]) then 
        raise pop3Exception.Create('POP3 component not ready'); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.StateChange(NewState : TPop3State); 
begin 
    if FState <> NewState then begin 
        FState := NewState; 
        TriggerStateChange; 
    end; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.DisplayLastResponse; 
begin 
     TriggerDisplay('< ' + FLastResponse); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.ExecAsync( 
    RqType      : TPop3Request; 
    Cmd         : String;             { Command to execute                     } 
    NextState   : TPop3ProtocolState; { Next protocol state in case of success } 
    DoneAsync   : TPop3NextProc);     { What to do when done                   } 
begin 
    CheckReady; 
 
    if not FConnected then 
        raise Pop3Exception.Create('POP3 component not connected'); 
 
    if not FHighLevelFlag then 
        FRequestType := RqType; 
 
    FRequestDoneFlag   := FALSE; 
    FNext              := NextExecAsync; 
    FNextProtocolState := NextState; 
    FDoneAsync         := DoneAsync; 
    StateChange(pop3WaitingResponse); 
    SendCommand(Cmd); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.NextExecAsync; 
begin 
    DisplayLastResponse; 
 
    if not OkResponse then begin 
        FRequestResult := FStatusCode; 
        SetErrorMessage; 
        TriggerRequestDone(FRequestResult); 
        Exit; 
    end; 
 
    FRequestResult := 0; 
    FProtocolState := FNextProtocolState; 
 
    if Assigned(FDoneAsync) then 
        FDoneAsync 
    else 
        TriggerRequestDone(FRequestResult); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.User; 
begin 
    if FProtocolState > pop3WaitingUser then begin 
        FErrorMessage := '-ERR USER command invalid now'; 
        Display(FErrorMessage); 
        raise Pop3Exception.Create(FErrorMessage); 
    end; 
 
    FFctPrv := pop3FctUser; 
    ExecAsync(pop3User, 'USER ' + Trim(FUserName), pop3WaitingPass, nil); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.Connect; 
begin 
    CheckReady; 
    if FConnected then 
        raise Pop3Exception.Create('POP3 component already connected'); 
 
    if not FHighLevelFlag then 
        FRequestType  := pop3Connect; 
 
    FRequestDoneFlag  := FALSE; 
    FReceiveLen       := 0; 
    FRequestResult    := 0; 
    StateChange(pop3DnsLookup); 
    FWSocket.OnDataSent      := nil; 
    FWSocket.OnDnsLookupDone := WSocketDnsLookupDone; 
    FWSocket.DnsLookup(FHost); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.Abort; 
begin 
    StateChange(pop3Abort); 
    FWSocket.CancelDnsLookup; 
    FWSocket.Abort; 
    StateChange(pop3Ready); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.Pass; 
begin 
    if FProtocolState > pop3WaitingPass then begin 
        FErrorMessage := '-ERR PASS command invalid now'; 
        Display(FErrorMessage); 
        raise Pop3Exception.Create(FErrorMessage); 
    end; 
 
    FFctPrv := pop3FctPass; 
    ExecAsync(pop3Pass, 'PASS ' + Trim(FPassWord), pop3Transaction, nil); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.RPop; 
begin 
    if FProtocolState > pop3WaitingPass then begin 
        FErrorMessage := '-ERR RPOP command invalid now'; 
        Display(FErrorMessage); 
        raise Pop3Exception.Create(FErrorMessage); 
    end; 
 
    FFctPrv := pop3FctRPop; 
    ExecAsync(pop3RPop, 'RPOP ' + Trim(FPassWord), pop3Transaction, nil); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.APop; 
begin 
    if FProtocolState <> pop3WaitingUser then begin 
        FErrorMessage := '-ERR APOP command invalid now'; 
        Display(FErrorMessage); 
        raise Pop3Exception.Create(FErrorMessage); 
    end; 
 
    if FTimeStamp = '' then begin 
        FErrorMessage := '-ERR Server do not support APOP (no timestamp)'; 
        Display(FErrorMessage); 
        raise Pop3Exception.Create(FErrorMessage); 
    end; 
 
    FFctPrv := pop3FctAPop; 
    ExecAsync(pop3APop, 'APOP ' + Trim(FUserName) + ' ' + 
                        StrMD5(FTimeStamp + FPassWord), 
                        pop3Transaction, nil); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.Quit; 
begin 
    CheckReady; 
    FFctPrv := pop3FctQuit; 
    if not FConnected then begin 
        { We are not connected, it's ok... } 
        FRequestType     := pop3Quit; 
        FRequestDoneFlag := FALSE; 
        TriggerRequestDone(0); 
        Exit; 
    end; 
    ExecAsync(pop3Quit, 'QUIT', pop3Disconnected, nil); { Should I force a FWSocket.Close } 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.Stat; 
begin 
    FFctPrv := pop3FctStat; 
    StartTransaction('STAT', '', pop3Stat, pop3Transaction, StatDone); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.StatDone; 
begin 
    ExtractNumbers(FMsgCount, FMsgSize); 
    TriggerRequestDone(FRequestResult); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.List; 
begin 
    FFctPrv := pop3FctList; 
    if FMsgNum <= 0 then 
        { Scan LIST command (all messages) } 
        StartTransaction('LIST', '', pop3List, pop3Transaction, ListAllDone) 
    else 
        { Single message LIST command } 
        StartTransaction('LIST', IntToStr(FMsgNum), pop3List, 
                         pop3Transaction, ListSingleDone); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.Uidl; 
begin 
    FFctPrv := pop3FctUidl; 
    if FMsgNum <= 0 then 
        { UIDL command (all messages) } 
        StartTransaction('UIDL', '', pop3Uidl, pop3Transaction, UidlAllDone) 
    else 
        { Single message UIDL command } 
        StartTransaction('UIDL', IntToStr(FMsgNum), pop3Uidl, 
                         pop3Transaction, UidlSingleDone); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.UidlAllDone; 
begin 
    StartMultiLine(FOnUidlBegin, FOnUidlLine, FOnUidlEnd, ProcessUidl); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.UidlSingleDone; 
begin 
    ExtractUidl(FMsgNum, FMsgUidl); 
    TriggerRequestDone(FRequestResult); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.ListSingleDone; 
begin 
    ExtractNumbers(FMsgNum, FMsgSize); 
    TriggerRequestDone(FRequestResult); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.ListAllDone; 
begin 
    StartMultiLine(FOnListBegin, FOnListLine, FOnListEnd, ProcessList); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.Retr; 
begin 
    FFctPrv := pop3FctRetr; 
    StartTransaction('RETR',   IntToStr(FMsgNum), 
                     pop3Retr, pop3Transaction, RetrDone); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.Top; 
begin 
    if FMsgLines < 0 then 
        raise Pop3Exception.Create('Invalid MsgLines for TOP command'); 
    FFctPrv := pop3FctTop; 
    StartTransaction('TOP', IntToStr(FMsgNum) + ' ' + IntToStr(FMsgLines), 
                     pop3Top, pop3Transaction, RetrDone); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.RetrDone; 
begin 
    StartMultiLine(FOnMessageBegin, FOnMessageLine, FOnMessageEnd, nil); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.Dele; 
begin 
    FFctPrv := pop3FctDele; 
    StartTransaction('DELE', IntToStr(FMsgNum), 
                     pop3Dele, pop3Transaction, nil); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.Noop; 
begin 
    FFctPrv := pop3FctNoop; 
    StartTransaction('NOOP', '', pop3Noop, pop3Transaction, nil); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.RSet; 
begin 
    FFctPrv := pop3FctRSet; 
    StartTransaction('RSET', '', pop3RSet, pop3Transaction, nil); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.Last; 
begin 
    FFctPrv := pop3FctLast; 
    StartTransaction('LAST', '', pop3Last, pop3Transaction, LastDone); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.LastDone; 
begin 
    ExtractNumbers(FMsgNum, FMsgSize); 
    TriggerRequestDone(FRequestResult); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.Open; 
begin 
    HighLevelAsync(pop3Open, [pop3FctConnect, pop3FctUser, pop3FctPass]); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.StartTransaction( 
    OpCode      : String; 
    Params      : String; 
    RqType      : TPop3Request; 
    NextState   : TPop3ProtocolState;  { Next protocol state in case of success} 
    DoneTrans   : TPop3NextProc);      { What to do when done                  } 
var 
    Cmd : String; 
begin 
    if FProtocolState <> pop3Transaction then begin 
        FErrorMessage := '-ERR ' + OpCode + ' command invalid now'; 
        Display(FErrorMessage); 
        raise Pop3Exception.Create(FErrorMessage); 
    end; 
 
    Cmd := OpCode; 
    if Params <> '' then 
        Cmd := Cmd + ' ' + Params; 
    ExecAsync(RqType, Cmd, NextState, DoneTrans); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.StartMultiLine( 
    aOnBegin : TNotifyEvent; 
    aOnLine  : TNotifyEvent; 
    aOnEnd   : TNotifyEvent; 
    aProcess : TNotifyEvent); 
begin 
    FMultiLineLine    := aOnLine; 
    FMultiLineEnd     := aOnEnd; 
    FMultiLineProcess := aProcess; 
 
    { Let the application know that the message is beginning } 
    if Assigned(aOnBegin) then 
        aOnBegin(Self); 
 
    FNext := GetALine; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure TCustomPop3Cli.GetALine; 
begin 
    { Check if we are still connected } 
    if not FConnected then begin 
        FErrorMessage  := '-ERR Disconneced unexpectedly'; 
        FRequestResult := 500; 
        Display(FErrorMessage); 
        TriggerRequestDone(FRequestResult); 
        Exit; 
    end; 
 
    { Check if end of message } 
    if FLastResponse = '.' then begin 
        { Let the application know that the message is finished } 
        if Assigned(FMultiLineEnd) then 
            FMultiLineEnd(Self); 
        FLastResponse := ''; 
        FNext         := nil; 
        TriggerRequestDone(0); 
        Exit; 
    end; 
 
    { Check if message contains end-of-message mark } 
    if (Length(FLastResponse) >= 2) and 
       (FLastResponse[1] = '.') and (FLastResponse[2] = '.') then 
        { Remove byte-stuff } 
        FLastResponse := Copy(FLastResponse, 2, Length(FLastResponse)); 
 
    { Additional process } 
    if Assigned(FMultiLineProcess) then 
        FMultiLineProcess(Self); 
 
    { Let the application process the message line } 
    if Assigned(FMultiLineLine) then 
        FMultiLineLine(Self); 
 
    { To process next line } 
    FNext := GetALine; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
constructor TSyncPop3Cli.Create(AOwner : TComponent); 
begin 
    inherited Create(AOwner); 
    FTimeout := 15; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.WaitUntilReady : Boolean; 
begin 
    Result := TRUE;           { Suppose success } 
    FTimeStop := Integer(GetTickCount) + FTimeout * 1000; 
    while TRUE do begin 
        if FState = pop3Ready then begin 
            { Back to ready state, the command is finiched } 
            Result := (FRequestResult = 0); 
            break; 
        end; 
 
        if  Application.Terminated or 
            ((FTimeout > 0) and (Integer(GetTickCount) > FTimeStop)) then begin 
            { Application is terminated or timeout occured } 
            inherited Abort; 
            FErrorMessage := '426 Timeout'; 
            FStatusCode   := 426; 
            Result        := FALSE; { Command failed } 
            break; 
        end; 
{$IFNDEF VER80} 
        if FMultiThreaded then 
            FWSocket.ProcessMessages 
        else 
{$ENDIF} 
            Application.ProcessMessages; 
{$IFNDEF VER80} 
        { Do not use 100% CPU, but slow down transfert on high speed LAN } 
        Sleep(0); 
{$ENDIF} 
    end; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.Synchronize(Proc : TPop3NextProc) : Boolean; 
begin 
    try 
        Proc; 
        Result := WaitUntilReady; 
    except 
        Result := FALSE; 
    end; 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.ConnectSync : Boolean; 
begin 
    Result := Synchronize(Connect); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.OpenSync : Boolean; 
begin 
    Result := Synchronize(Open); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.UserSync : Boolean; 
begin 
    Result := Synchronize(User); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.PassSync : Boolean; 
begin 
    Result := Synchronize(Pass); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.RetrSync : Boolean; 
begin 
    Result := Synchronize(Retr); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.DeleSync : Boolean; 
begin 
    Result := Synchronize(Dele); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.UidlSync : Boolean; 
begin 
    Result := Synchronize(Uidl); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.LastSync : Boolean; 
begin 
    Result := Synchronize(Last); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.RPopSync : Boolean; 
begin 
    Result := Synchronize(RPop); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.TopSync : Boolean; 
begin 
    Result := Synchronize(Top); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.ListSync : Boolean; 
begin 
    Result := Synchronize(List); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.StatSync : Boolean; 
begin 
    Result := Synchronize(Stat); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.QuitSync : Boolean; 
begin 
    Result := Synchronize(Quit); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.APopSync : Boolean; 
begin 
    Result := Synchronize(APop); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.AbortSync : Boolean; 
begin 
    Result := Synchronize(Abort); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.RSetSync : Boolean; 
begin 
    Result := Synchronize(RSet); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
function TSyncPop3Cli.NoopSync : Boolean; 
begin 
    Result := Synchronize(Noop); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
procedure Register; 
begin 
    RegisterComponents('FPiette', [TPop3Cli, TSyncPop3Cli]); 
end; 
 
 
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 
 
end.