📄 pop3prot.pas
字号:
write FOnUidlBegin;
property OnUidlEnd : TNotifyEvent read FOnUidlEnd
write FOnUidlEnd;
property OnUidlLine : TNotifyEvent read FOnUidlLine
write FOnUidlLine;
property OnHeaderEnd : TNotifyEvent read FOnHeaderEnd
write FOnHeaderEnd;
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 LocalAddr; {bb}
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 OnHeaderEnd;
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;
procedure TriggerResponse(Msg : String); override; { Angus }
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 := WSocket.AllocateHWnd(WndProc);
FWSocket := TWSocket.Create(nil);
FWSocket.OnSessionClosed := WSocketSessionClosed;
FProtocolState := pop3Disconnected;
FState := pop3Ready;
FLocalAddr := '0.0.0.0'; {bb}
FPort := 'pop3';
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
destructor TCustomPop3Cli.Destroy;
begin
if Assigned(FWSocket) then begin
FWSocket.Destroy;
FWSocket := nil;
end;
WSocket.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.LocalAddr := FLocalAddr; {bb}
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;
Remaining : Integer;
begin
{ Compute remaining space in our buffer. Preserve 3 bytes for CR/LF }
{ and nul terminating byte. }
Remaining := SizeOf(FReceiveBuffer) - FReceiveLen - 3;
if Remaining <= 0 then begin
{ Received message has a line longer than our buffer. This is not }
{ acceptable ! We will add a CR/LF to enable processing, but this }
{ will ALTER received message and could cause strange results. }
{ May be it is better to raise an exception ? }
FReceiveBuffer[SizeOf(FReceiveBuffer) - 3] := #13;
FReceiveBuffer[SizeOf(FReceiveBuffer) - 2] := #10;
Len := 2;
end
else begin
Len := FWSocket.Receive(@FReceiveBuffer[FReceiveLen], Remaining);
if Len <= 0 then
Exit;
end;
FReceiveBuffer[FReceiveLen + Len] := #0;
FReceiveLen := FReceiveLen + Len;
while FReceiveLen > 0 do begin
{ Search CRLF pair. We can't use Pos because it stops at first #0 }
I := 1;
while (I < FReceiveLen) and
(not((FReceiveBuffer[I - 1] = #13) and (FReceiveBuffer[I] = #10)))
do
Inc(I);
if I >= FReceiveLen then
break; { CRLF not found }
{ Found a CRLF. Extract data from buffer }
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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -