{ $Project$ $Workfile$ $Revision$ $DateUTC$ $Id$ This file is part of the Indy (Internet Direct) project, and is offered under the dual-licensing agreement described on the Indy website. (http://www.indyproject.org/) Copyright: (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved. } { $Log$ } { Rev 1.36 2/8/05 5:59:04 PM RLebeau Updated various CommandHandlers to call TIdReply.SetReply() instead of setting the Code and Text properties individually Rev 1.35 12/2/2004 4:23:56 PM JPMugaas Adjusted for changes in Core. Rev 1.34 7/6/2004 4:53:38 PM DSiders Corrected spelling of Challenge in properties, methods, types. Rev 1.33 6/16/04 12:54:16 PM RLebeau Removed redundant localization comments Rev 1.31 6/16/04 12:31:08 PM RLebeau compiler error Rev 1.30 6/16/04 12:13:04 PM RLebeau Added overrides for CreateExceptionReply, CreateGreeting, CreateHelpReply, CreateMaxConnectionReply, and CreateReplyUnknownCommand methods Rev 1.29 5/16/04 5:25:22 PM RLebeau Added GetReplyClass() and GetRepliesClass() overrides. Rev 1.28 3/1/2004 1:08:36 PM JPMugaas Fixed for new code. Rev 1.27 2004.02.03 5:44:14 PM czhower Name changes Rev 1.26 1/29/2004 9:14:46 AM JPMugaas POP3Server should now compile in DotNET. Rev 1.25 1/21/2004 3:27:08 PM JPMugaas InitComponent Rev 1.24 10/25/2003 06:52:16 AM JPMugaas Updated for new API changes and tried to restore some functionality. Rev 1.23 10/24/2003 4:38:00 PM DSiders Added localization comments. Modified to use OK and ERR constants in response messages. Rev 1.22 2003.10.21 9:13:12 PM czhower Now compiles. Rev 1.21 2003.10.12 4:04:18 PM czhower compile todos Rev 1.20 9/19/2003 03:30:20 PM JPMugaas Now should compile again. Rev 1.19 7/9/2003 10:59:16 PM BGooijen Added IdCommandHandlers to the uses-clause Rev 1.18 5/30/2003 9:05:14 PM BGooijen changed numeric replycodes to text reply codes Rev 1.17 5/30/2003 8:49:48 PM BGooijen Changed TextCode to Code Rev 1.16 5/26/2003 04:28:22 PM JPMugaas Removed GenerateReply and ParseResponse calls because those functions are being removed. Rev 1.15 5/26/2003 12:24:02 PM JPMugaas Rev 1.14 5/25/2003 03:46:00 AM JPMugaas Rev 1.13 5/21/2003 2:25:06 PM BGooijen changed due to change in IdCmdTCPServer from ExceptionReplyCode: Integer to ExceptionReply: TIdReply Rev 1.12 5/20/2003 10:58:24 AM JPMugaas SetExceptionReplyCode now validated by TIdReplyPOP3. This way, it can only accept our integer codes for +OK, -ERR, and +. Rev 1.11 5/19/2003 08:59:30 PM JPMugaas Now uses new reply object for all commands. Rev 1.9 5/15/2003 08:30:32 AM JPMugaas Rev 1.9 5/15/2003 07:38:50 AM JPMugaas No longer adds a challenge banner to the main Greeting TIdRFCReply. Rev 1.8 5/13/2003 08:12:12 PM JPMugaas Rev 1.7 5/13/2003 12:43:20 PM JPMugaas APOP redesigned so that it will handle the Challenge in the banner and do the hashes itself. A Challenge will be displayed in the banner if the APOP event is used. Rev 1.6 3/20/2003 07:22:28 AM JPMugaas Rev 1.5 3/17/2003 02:25:30 PM JPMugaas Updated to use new TLS framework. Now can require that users use TLS. Note that this setting create an incompatiability with Norton AntiVirus because that does act as a "man in the middle" when intercepting E-Mail for virus scanning. Rev 1.4 3/14/2003 10:44:34 PM BGooijen Removed warnings, changed StartSSL to PassThrough:=false; Rev 1.2 3/13/2003 10:05:30 AM JPMugaas Updated component to work with the new SSL restructure. Rev 1.1 2/6/2003 03:18:20 AM JPMugaas Updated components that compile with Indy 10. Rev 1.0 11/13/2002 07:58:28 AM JPMugaas 28-Sep-2002: Bas Gooijen - Added CAPA and STLS (RFC 2449 and 2595) - Added ImplicitTLS 02-May-2002: Andy Neillans - Bug Fix 551116 -Sys. StrToInt needed 'Sys.Trimming# 30-Apr-2002: Allen O'Neill. - Failsafe .. added check for ParamCount in reading Username and password - previously if either were sent in blank we got an IndexOutOfBounds error. 13-Apr-2002: - Corrections :) And some Greeting.Text / And other response, glitches 3-Apr-2002: - Minor changes. (Greeting.Text) 1-Apr-2002: - Completed rewrite! At Last! 15-Feb-2002: Andy - Started rewrite for use of CommandHandlers 13-Jan-2002: -Fixed Sys.Formatting bug. 26-Dec-2000: -Andrew Neillans found a bug on line 157. Originally it was if Assigned(OnCommandLIST) then OnCommandRETR(...). Changed to OnCommandLIST(...). Thanks Andrew! 29-Oct-2000: -I discovered I really shouldn't program at night. The error wasn't that it shouldn't be Succ (Because it should), but because I forgot to implement LIST 27-Oct-2000: -Fixed a dumb bug. Originally coded command parsing as Succ(PosInStrArray) Should be just PosInStrArray b/c it is not a dynamic array. The bounds are constant. 25-Oct-2000: -Created Unit. -Created new IdPOP3Server Server Component according to RFC 1939 } unit IdPOP3Server; interface {$i IdCompilerDefines.inc} { Indy POP3 Server Original Programmer: Luke Croteau Current Maintainer: Andrew Neillans No Copyright. Code is given to the Indy Pit Crew. Quick Notes: A few of the methods return a default message number if a number isn't entered. The LIST, DELE, RETR, UIDL, and TOP command will return a -1 in the parameters if the value isn't specified by the client. Some functions require this capability. For example, the LIST command can operate either by a certain message number or a with no arguments. See RFC1939 for details. } uses Classes, IdAssignedNumbers, IdCommandHandlers, IdContext, IdCustomTCPServer, IdCmdTCPServer, IdException, IdExplicitTLSClientServerBase, IdGlobal, IdReply, IdTCPServer, IdServerIOHandler, IdMailBox, IdBaseComponent, IdTCPConnection, IdYarn; { We can not port APOP to NET due to the use of GetSystemClock and a process ID Kudzu: Why not? .NET can get these..... } const DEF_POP3_IMPLICIT_TLS = False; type TIdPOP3ServerContext = class(TIdServerContext) protected // what needs to be stored... fUsername : String; fPassword : String; fAuthenticated: boolean; fAPOP3Challenge : String; // function GetUsingTLS: Boolean; function GetCanUseExplicitTLS: Boolean; function GetTLSIsRequired: Boolean; public // Any functions for vars property APOP3Challenge: string read FAPOP3Challenge write FAPOP3Challenge; property Authenticated: boolean read fAuthenticated; property Username: string read fUsername; property Password: string read fPassword; property UsingTLS: Boolean read GetUsingTLS; property CanUseExplicitTLS: Boolean read GetCanUseExplicitTLS; property TLSIsRequired: Boolean read GetTLSIsRequired; end; TIdPOP3ServerNoParamEvent = procedure (aCmd: TIdCommand) of object; TIdPOP3ServerStatEvent = procedure(aCmd: TIdCommand; out oCount: integer; out oSize: Int64) of object; TIdPOP3ServerMessageNumberEvent = procedure (aCmd: TIdCommand; AMsgNo :Integer) of object; TIdPOP3ServerLogin = procedure(aContext: TIdContext; aServerContext: TIdPOP3ServerContext) of object; TIdPOP3ServerCAPACommandEvent = procedure(aContext: TIdContext; aCapabilities: TStrings) of object; //Note that we require the users valid password so we can hash it with the Challenge we greeted the user with. TIdPOP3ServerAPOPCommandEvent = procedure (aCmd: TIdCommand; aMailboxID: String; var vUsersPassword: String) of object; TIdPOP3ServerTOPCommandEvent = procedure (aCmd: TIdCommand; aMsgNo: Integer; aLines: Integer) of object; EIdPOP3ServerException = class(EIdException); EIdPOP3ImplicitTLSRequiresSSL = class(EIdPOP3ServerException); TIdPOP3Server = class(TIdExplicitTLSServer) protected fCommandLogin : TIdPOP3ServerLogin; fCommandList, fCommandRetr, fCommandDele, fCommandUIDL : TIdPOP3ServerMessageNumberEvent; fCommandTop : TIdPOP3ServerTOPCommandEvent; fCommandQuit: TIdPOP3ServerNoParamEvent; fCommandStat: TIdPOP3ServerStatEvent; fCommandRset : TIdPOP3ServerNoParamEvent; fCommandAPOP : TIdPOP3ServerAPOPCommandEvent; fCommandCapa : TIdPOP3ServerCAPACommandEvent; function IsAuthed(aCmd: TIdCommand; aAssigned: boolean): boolean; procedure MustUseTLS(aCmd: TIdCommand); // CommandHandlers procedure CommandUser(aCmd: TIdCommand); procedure CommandPass(aCmd: TIdCommand); procedure CommandList(aCmd: TIdCommand); procedure CommandRetr(aCmd: TIdCommand); procedure CommandDele(aCmd: TIdCommand); procedure CommandQuit(aCmd: TIdCommand); procedure CommandAPOP(aCmd: TIdCommand); procedure CommandStat(aCmd: TIdCommand); procedure CommandRset(aCmd: TIdCommand); procedure CommandTop(aCmd: TIdCommand); procedure CommandUIDL(aCmd: TIdCommand); procedure CommandSTLS(aCmd: TIdCommand); procedure CommandCAPA(aCmd: TIdCommand); function CreateExceptionReply: TIdReply; override; function CreateGreeting: TIdReply; override; function CreateHelpReply: TIdReply; override; function CreateMaxConnectionReply: TIdReply; override; function CreateReplyUnknownCommand: TIdReply; override; procedure InitializeCommandHandlers; override; procedure DoReplyUnknownCommand(AContext: TIdContext; ALine: string); override; function GetReplyClass: TIdReplyClass; override; function GetRepliesClass: TIdRepliesClass; override; procedure SendGreeting(AContext : TIdContext; AGreeting : TIdReply); override; procedure InitComponent; override; published property DefaultPort default IdPORT_POP3; // These procedures / functions are exposed property OnCheckUser : TIdPOP3ServerLogin read fCommandLogin write fCommandLogin; property OnList : TIdPOP3ServerMessageNumberEvent read fCommandList write fCommandList; property OnRetrieve : TIdPOP3ServerMessageNumberEvent read fCommandRetr write fCommandRetr; property OnDelete : TIdPOP3ServerMessageNumberEvent read fCommandDele write fCommandDele; property OnUIDL : TIdPOP3ServerMessageNumberEvent read fCommandUidl write fCommandUidl; property OnStat: TIdPOP3ServerStatEvent read fCommandStat write fCommandStat; property OnTop : TIdPOP3ServerTOPCommandEvent read fCommandTop write fCommandTop; property OnReset : TIdPOP3ServerNoParamEvent read fCommandRset write fCommandRset; property OnQuit : TIdPOP3ServerNoParamEvent read fCommandQuit write fCommandQuit; property OnAPOP : TIdPOP3ServerAPOPCommandEvent read fCommandApop write fCommandApop; property OnCAPA : TIdPOP3ServerCAPACommandEvent read fCommandCapa write fCommandCapa; property UseTLS; end; implementation uses IdFIPS, IdGlobalProtocols, IdHash, IdHashMessageDigest, IdReplyPOP3, IdResourceStringsProtocols, IdSSL, IdStack, SysUtils; procedure TIdPOP3Server.DoReplyUnknownCommand(AContext: TIdContext; ALine: string); var LReply: TIdReply; LLine : String; begin LLine := ALine; // RLebeau 03/17/2007: TIdCmdTCPServer.DoReplyUnknownCommand() adds the // offending command as a multi-line response generically for all servers. // POP3 Error replies are not mult-line, however, so overriding the // behavior here to not do that! LReply := FReplyClass.CreateWithReplyTexts(nil, ReplyTexts); try LReply.SetReply(ST_ERR, IndyFormat(RSPOP3SvrUnknownCmdFmt, [Fetch(LLine)])); AContext.Connection.IOHandler.Write(LReply.FormattedReply); finally FreeAndNil(LReply); end; end; procedure TIdPOP3Server.InitializeCommandHandlers; var LCommandHandler: TIdCommandHandler; begin inherited; LCommandHandler := CommandHandlers.Add; LCommandHandler.Command := 'USER'; {do not localize} LCommandHandler.OnCommand := CommandUSER; LCommandHandler.NormalReply.Code := ST_OK; LCommandHandler.ExceptionReply.Code := ST_ERR; LCommandHandler.ParseParams := True; LCommandHandler := CommandHandlers.Add; LCommandHandler.Command := 'PASS'; {do not localize} LCommandHandler.OnCommand := CommandPass; LCommandHandler.NormalReply.Code := ST_OK; LCommandHandler.ExceptionReply.Code := ST_ERR; LCommandHandler.ParseParams := True; LCommandHandler := CommandHandlers.Add; LCommandHandler.Command := 'LIST'; {do not localize} LCommandHandler.OnCommand := CommandList; LCommandHandler.NormalReply.Code := ST_OK; LCommandHandler.ExceptionReply.Code := ST_ERR; LCommandHandler.ParseParams := True; LCommandHandler := CommandHandlers.Add; LCommandHandler.Command := 'RETR'; {do not localize} LCommandHandler.OnCommand := CommandRetr; LCommandHandler.NormalReply.Code := ST_OK; LCommandHandler.ExceptionReply.Code := ST_ERR; LCommandHandler.ParseParams := True; LCommandHandler := CommandHandlers.Add; LCommandHandler.Command := 'DELE'; {do not localize} LCommandHandler.OnCommand := CommandDele; LCommandHandler.NormalReply.Code := ST_OK; LCommandHandler.ExceptionReply.Code := ST_ERR; LCommandHandler.ParseParams := True; LCommandHandler := CommandHandlers.Add; LCommandHandler.Command := 'UIDL'; {do not localize} LCommandHandler.OnCommand := CommandUIDL; LCommandHandler.NormalReply.Code := ST_OK; LCommandHandler.ExceptionReply.Code := ST_ERR; LCommandHandler.ParseParams := True; LCommandHandler := CommandHandlers.Add; LCommandHandler.Command := 'STAT'; {do not localize} LCommandHandler.OnCommand := CommandSTAT; LCommandHandler.NormalReply.Code := ST_OK; LCommandHandler.ExceptionReply.Code := ST_ERR; LCommandHandler.ParseParams := False; LCommandHandler := CommandHandlers.Add; LCommandHandler.Command := 'TOP'; {do not localize} LCommandHandler.OnCommand := CommandTOP; LCommandHandler.NormalReply.Code := ST_OK; LCommandHandler.ExceptionReply.Code := ST_ERR; LCommandHandler.ParseParams := True; LCommandHandler := CommandHandlers.Add; LCommandHandler.Command := 'NOOP'; {do not localize} LCommandHandler.NormalReply.SetReply(ST_OK, RSPOP3SvrNoOp); LCommandHandler.ExceptionReply.Code := ST_ERR; LCommandHandler.ParseParams := False; LCommandHandler := CommandHandlers.Add; LCommandHandler.Command := 'APOP'; {do not localize} LCommandHandler.OnCommand := CommandAPOP; LCommandHandler.NormalReply.Code := ST_OK; LCommandHandler.ExceptionReply.Code := ST_ERR; LCommandHandler.ParseParams := True; LCommandHandler := CommandHandlers.Add; LCommandHandler.Command := 'RSET'; {do not localize} LCommandHandler.NormalReply.SetReply(ST_OK, RSPOP3SvrReset); LCommandHandler.ExceptionReply.Code := ST_ERR; LCommandHandler.OnCommand := CommandRset; LCommandHandler.ParseParams := False; LCommandHandler := CommandHandlers.Add; LCommandHandler.Command := 'QUIT'; {do not localize} LCommandHandler.OnCommand := CommandQuit; LCommandHandler.Disconnect := True; LCommandHandler.NormalReply.SetReply(ST_OK, RSPOP3SvrClosingConnection); LCommandHandler.ExceptionReply.Code := ST_ERR; LCommandHandler.ParseParams := False; LCommandHandler := CommandHandlers.Add; LCommandHandler.Command := 'STLS'; {do not localize} LCommandHandler.NormalReply.Code := ST_OK; LCommandHandler.ExceptionReply.Code := ST_ERR; LCommandHandler.OnCommand := CommandSTLS; LCommandHandler := CommandHandlers.Add; LCommandHandler.Command := 'CAPA'; {do not localize} LCommandHandler.NormalReply.Code := ST_OK; LCommandHandler.ExceptionReply.Code := ST_ERR; LCommandHandler.OnCommand := CommandCAPA; end; { Command Handler Functions here } procedure TIdPOP3Server.CommandUser(aCmd: TIdCommand); var LContext: TIdPOP3ServerContext; begin LContext := TIdPOP3ServerContext(aCmd.Context); if LContext.TLSIsRequired then begin MustUseTLS(aCmd); Exit; end; if aCmd.Params.Count > 0 then begin LContext.fUsername := aCmd.Params.Strings[0]; end; aCmd.Reply.SetReply(ST_OK, RSPOP3SvrPasswordRequired); end; procedure TIdPOP3Server.CommandPass(aCmd: TIdCommand); var LContext: TIdPOP3ServerContext; begin LContext := TIdPOP3ServerContext(aCmd.Context); if LContext.TLSIsRequired then begin MustUseTLS(aCmd); Exit; end; if aCmd.Params.Count > 0 then begin LContext.fPassword := aCmd.Params.Strings[0]; end; if Assigned(OnCheckUser) then begin OnCheckUser(aCmd.Context, LContext); end; LContext.fAuthenticated := True; aCmd.Reply.SetReply(ST_OK, RSPOP3SvrLoginOk); end; procedure TIdPOP3Server.CommandList(aCmd: TIdCommand); begin if IsAuthed(aCmd, Assigned(fCommandList)) then begin OnList(aCmd, IndyStrToInt(aCmd.Params.Text, -1)); end; end; procedure TIdPOP3Server.CommandRetr(aCmd: TIdCommand); begin if IsAuthed(aCmd, Assigned(fCommandRetr)) then begin OnRetrieve(aCmd, IndyStrToInt(aCmd.Params[0])); end; end; procedure TIdPOP3Server.CommandDele(aCmd: TIdCommand); begin if IsAuthed(aCmd, Assigned(fCommandDele)) then begin OnDelete(aCmd, IndyStrToInt(aCmd.Params.Text)); end; end; procedure TIdPOP3Server.CommandQuit(aCmd: TIdCommand); begin if Assigned(fCommandQuit) then begin OnQuit(aCmd); end; end; procedure TIdPOP3Server.CommandAPOP(aCmd: TIdCommand); var LContext: TIdPOP3ServerContext; LValidPassword : String; LValidHash : String; LMD5: TIdHashMessageDigest5; begin LContext := TIdPOP3ServerContext(aCmd.Context); if LContext.Authenticated then begin aCmd.Reply.SetReply(ST_ERR, RSPOP3SvrWrongState); Exit; end; if LContext.TLSIsRequired then begin MustUseTLS(aCmd); Exit; end; if not Assigned(fCommandAPOP) then begin aCmd.Reply.SetReply(ST_ERR, IndyFormat(RSPOP3SVRNotHandled, ['APOP'])); {do not localize} Exit; end; OnAPOP(aCmd, aCmd.Params.Strings[0], LValidPassword); LMD5 := TIdHashMessageDigest5.Create; try LValidHash := IndyLowerCase(LMD5.HashStringAsHex(LContext.APOP3Challenge + LValidPassword)); finally LMD5.Free; end; LContext.fAuthenticated := (LValidHash = aCmd.Params[1]); // User to set return state of LThread.State as required. if not LContext.Authenticated then begin aCmd.Reply.SetReply(ST_ERR, RSPOP3SvrLoginFailed); end else begin aCmd.Reply.SetReply(ST_OK, RSPOP3SvrLoginOk); end; end; function TIdPOP3Server.IsAuthed(aCmd: TIdCommand; aAssigned: boolean): boolean; begin Result := TIdPOP3ServerContext(aCmd.Context).Authenticated; if Result then begin Result := aAssigned; if not Result then begin aCmd.Reply.SetReply(ST_ERR, IndyFormat(RSPOP3SVRNotHandled, [aCmd.CommandHandler.Command])); {do not localize} end; end else begin aCmd.Reply.SetReply(ST_ERR, RSPOP3SvrLoginFirst); end; end; procedure TIdPOP3Server.CommandStat(aCmd: TIdCommand); var xCount: Integer; xSize: Int64; begin // TODO: Need to make all use this form if IsAuthed(aCmd, Assigned(fCommandStat)) then begin OnStat(aCmd, xCount, xSize); aCmd.Reply.SetReply(ST_OK, IntToStr(xCount) + ' ' + IntToStr(xSize)); end; end; procedure TIdPOP3Server.CommandRset(aCmd: TIdCommand); begin if IsAuthed(aCmd, assigned(fCommandRSET)) then begin OnReset(aCmd); end; end; procedure TIdPOP3Server.CommandTop(aCmd: TIdCommand); var xMsgNo: integer; xLines: integer; begin if IsAuthed(aCmd, Assigned(fCommandTop)) then begin if aCmd.Params.Count = 2 then begin xMsgNo := IndyStrToInt(aCmd.Params.Strings[0], 0); xLines := IndyStrToInt(aCmd.Params.Strings[1], -1); if (xMsgNo >= 1) and (xLines >= 0) then begin OnTop(aCmd, xMsgNo, xLines); Exit; end; end; aCmd.Reply.SetReply(ST_ERR, RSPOP3SvrInvalidSyntax); end; end; procedure TIdPOP3Server.CommandUIDL(aCmd: TIdCommand); begin if IsAuthed(aCmd, Assigned(fCommandUidl)) then begin OnUidl(aCmd,IndyStrToInt(aCmd.Params.Text, -1)) end; end; procedure TIdPOP3Server.CommandSTLS(aCmd: TIdCommand); var LContext: TIdPOP3ServerContext; begin LContext := TIdPOP3ServerContext(aCmd.Context); if LContext.CanUseExplicitTLS then begin if LContext.UsingTLS then begin // we are already using TLS aCmd.Reply.SetReply(ST_ERR, RSPOP3SvrNotPermittedWithTLS); Exit; end; if LContext.Authenticated then begin //STLS only allowed in auth-state aCmd.Reply.SetReply(ST_ERR, RSPOP3SvrNotInThisState); Exit; end; aCmd.Reply.SetReply(ST_OK, RSPOP3SvrbeginTLSNegotiation); aCmd.SendReply; TIdSSLIOHandlerSocketBase(aCmd.Context.Connection.IOHandler).PassThrough := False; end else begin aCmd.Reply.SetReply(ST_ERR, IndyFormat(RSPOP3SVRNotHandled, ['STLS'])); {do not localize} end; end; procedure TIdPOP3Server.CommandCAPA(aCmd: TIdCommand); var LContext: TIdPOP3ServerContext; begin LContext := TIdPOP3ServerContext(aCmd.Context); aCmd.Reply.SetReply(ST_OK, RSPOP3SvrCapaList); // RLebeau: in case no capabilities are specified, the terminating '.' still has to be sent. aCmd.SendEmptyResponse := True; if LContext.CanUseExplicitTLS and (not LContext.UsingTLS) then begin aCmd.Response.Add('STLS'); {do not localize} end; if Assigned(fCommandTop) then begin aCmd.Response.Add('TOP'); {do not localize} end; if Assigned(fCommandUidl) then begin aCmd.Response.Add('UIDL'); {do not localize} end; aCmd.Response.Add('USER'); {do not localize} // aCmd.Response.Add('SASL ......'); // like 'SASL CRAM-MD5 KERBEROS_V4' if Assigned(fCommandCapa) then begin OnCAPA(aCmd.Context, aCmd.Response); end; end; { Constructor / Destructors } procedure TIdPOP3Server.InitComponent; begin inherited; FContextClass := TIdPOP3ServerContext; FRegularProtPort := IdPORT_POP3; FImplicitTLSProtPort := IdPORT_POP3S; DefaultPort := IdPORT_POP3; end; function TIdPOP3Server.CreateExceptionReply: TIdReply; begin Result := TIdReplyPOP3.CreateWithReplyTexts(nil, ReplyTexts); Result.SetReply(ST_ERR, RSPOP3SvrInternalError); end; function TIdPOP3Server.CreateGreeting: TIdReply; begin Result := TIdReplyPOP3.CreateWithReplyTexts(nil, ReplyTexts); Result.SetReply(ST_OK, RSPOP3SvrWelcome); end; function TIdPOP3Server.CreateHelpReply: TIdReply; begin Result := TIdReplyPOP3.CreateWithReplyTexts(nil, ReplyTexts); Result.SetReply(ST_OK, RSPOP3SvrHelpFollows); end; function TIdPOP3Server.CreateMaxConnectionReply: TIdReply; begin Result := TIdReplyPOP3.CreateWithReplyTexts(nil, ReplyTexts); Result.SetReply(ST_ERR, RSPOP3SvrTooManyCons); end; function TIdPOP3Server.CreateReplyUnknownCommand: TIdReply; begin Result := TIdReplyPOP3.CreateWithReplyTexts(nil, ReplyTexts); Result.SetReply(ST_ERR, RSPOP3SvrUnknownCmd); end; function TIdPOP3Server.GetReplyClass: TIdReplyClass; begin Result := TIdReplyPOP3; end; function TIdPOP3Server.GetRepliesClass: TIdRepliesClass; begin Result := TIdRepliesPOP3; end; { TIdPOP3ServerContext } function TIdPOP3ServerContext.GetUsingTLS: Boolean; begin Result := Connection.IOHandler is TIdSSLIOHandlerSocketBase; if Result then begin Result := not TIdSSLIOHandlerSocketBase(Connection.IOHandler).PassThrough; end; end; function TIdPOP3ServerContext.GetCanUseExplicitTLS: Boolean; begin Result := Connection.IOHandler is TIdSSLIOHandlerSocketBase; if Result then begin Result := TIdPOP3Server(Server).UseTLS in ExplicitTLSVals; end; end; function TIdPOP3ServerContext.GetTLSIsRequired: Boolean; begin Result := TIdPOP3Server(Server).UseTLS = utUseRequireTLS; if Result then begin Result := not UsingTLS; end; end; procedure TIdPOP3Server.MustUseTLS(aCmd: TIdCommand); begin aCmd.Reply.SetReply(ST_ERR, RSPOP3SvrMustUseSTLS); aCmd.Disconnect := True; end; procedure TIdPOP3Server.SendGreeting(AContext: TIdContext; AGreeting: TIdReply); var LThread : TIdPOP3ServerContext; LGreeting : TIdReplyPOP3; begin // AGreeting.Code := ST_OK; {do not localize} if ( not GetFIPSMode ) and Assigned(fCommandAPOP) then begin LThread := TIdPOP3ServerContext(AContext); LGreeting := TIdReplyPOP3.Create(nil); try LThread.APOP3Challenge := '<'+ {do not localize} IntToStr(Abs( CurrentProcessId )) + '.'+IntToStr(Abs( GetClockValue ))+'@'+ GStack.HostName +'>'; {do not localize} if AGreeting.Text.Count > 0 then begin LGreeting.Text.Add(AGreeting.Text[0] + ' ' + LThread.APOP3Challenge); {do not localize} end else begin LGreeting.Text.Add(RSPOP3SvrWelcomeAPOP + LThread.APOP3Challenge); end; LGreeting.Code := ST_OK; AContext.Connection.IOHandler.Write(LGreeting.FormattedReply); finally FreeAndNil(LGreeting); end; end else begin inherited SendGreeting(AContext, AGreeting); end; end; end.