| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682 |
- {
- $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/1/05 12:37:48 AM RLebeau
- Removed IdCommandHandlersEnabledDefault variable, no longer used.
- Rev 1.35 1/3/05 4:43:20 PM RLebeau
- Changed use of AnsiSameText() to use TextIsSame() instead
- Rev 1.34 12/17/04 12:54:04 PM RLebeau
- Updated TIdCommandHandler.Check() to not match misspelled commands when a
- CmdDelimiter is specified.
- Rev 1.33 12/10/04 1:48:04 PM RLebeau
- Bug fix for TIdCommandHandler.DoCommand()
- Rev 1.32 10/26/2004 8:42:58 PM JPMugaas
- Should be more portable with new references to TIdStrings and TIdStringList.
- Rev 1.31 6/17/2004 2:19:50 AM JPMugaas
- Problem with unparsed parameters. The initial deliniator between the command
- and reply was being added to Unparsed Params leading some strange results and
- command failures.
- Rev 1.30 6/6/2004 11:44:34 AM JPMugaas
- Removed a temporary workaround for a Telnet Sequences issue in the
- TIdFTPServer. That workaround is no longer needed as we fixed the issue
- another way.
- Rev 1.29 5/16/04 5:20:22 PM RLebeau
- Removed local variable from TIdCommandHandler constructor, no longer used
- Rev 1.28 2004.03.03 3:19:52 PM czhower
- sorted
- Rev 1.27 3/3/2004 4:59:40 AM JPMugaas
- Updated for new properties.
- Rev 1.26 3/2/2004 8:10:36 AM JPMugaas
- HelpHide renamed to HelpVisable.
- Rev 1.25 3/2/2004 6:37:36 AM JPMugaas
- Updated with properties for more comprehensive help systems.
- Rev 1.24 2004.03.01 7:13:40 PM czhower
- Comaptibilty fix.
- Rev 1.23 2004.03.01 5:12:26 PM czhower
- -Bug fix for shutdown of servers when connections still existed (AV)
- -Implicit HELP support in CMDserver
- -Several command handler bugs
- -Additional command handler functionality.
- Rev 1.22 2004.02.29 9:49:06 PM czhower
- Bug fix, and now responses are also write buffered.
- Rev 1.21 2004.02.03 4:17:10 PM czhower
- For unit name changes.
- Rev 1.20 1/29/04 10:00:40 PM RLebeau
- Added setter methods to various TIdReply properties
- Rev 1.19 2003.12.31 7:31:58 PM czhower
- AnsiSameText --> TextIsSame
- Rev 1.18 10/19/2003 11:36:52 AM DSiders
- Added localization comments where setting response codes.
- Rev 1.17 2003.10.18 9:33:26 PM czhower
- Boatload of bug fixes to command handlers.
- Rev 1.16 2003.10.18 8:07:12 PM czhower
- Fixed bug with defaults.
- Rev 1.15 2003.10.18 8:03:58 PM czhower
- Defaults for codes
- Rev 1.14 10/5/2003 03:06:18 AM JPMugaas
- Should compile.
- Rev 1.13 8/9/2003 3:52:44 PM BGooijen
- TIdCommandHandlers can now create any TIdCommandHandler descendant. this
- makes it possible to override TIdCommandHandler.check and check for the
- command a different way ( binary commands, protocols where the string doesn't
- start with the command )
- Rev 1.12 8/2/2003 2:22:54 PM SPerry
- Fixed OnCommandHandlersException problem
- Rev 1.11 8/2/2003 1:43:08 PM SPerry
- Modifications to get command handlers to work
- Rev 1.9 7/30/2003 10:18:30 PM SPerry
- Fixed AV when creating commandhandler (again) -- for some reason the bug
- fixed in Rev. 1.7 was still there.
- Rev 1.8 7/30/2003 8:31:58 PM SPerry
- Fixed AV with LFReplyClass.
- Rev 1.4 7/9/2003 10:55:26 PM BGooijen
- Restored all features
- Rev 1.3 7/9/2003 04:36:10 PM JPMugaas
- You now can override the TIdReply with your own type. This should illiminate
- some warnings about some serious issues. TIdReply is ONLY a base class with
- virtual methods.
- Rev 1.2 7/9/2003 01:43:22 PM JPMugaas
- Should now compile.
- Rev 1.1 7/9/2003 2:56:44 PM SPerry
- Added OnException event
- Rev 1.0 7/6/2003 4:47:38 PM SPerry
- Units that use Command handlers
- }
- unit IdCommandHandlers;
- {
- Original author: Chad Z. Hower
- Separate Unit : Sergio Perry
- }
- interface
- {$I IdCompilerDefines.inc}
- //Put FPC into Delphi mode
- uses
- Classes,
- IdComponent, IdReply, IdGlobal,
- IdContext, IdReplyRFC;
- const
- IdEnabledDefault = True;
- // DO NOT change this default (ParseParams). Many servers rely on this
- IdParseParamsDefault = True;
- IdHelpVisibleDef = True;
- type
- TIdCommandHandlers = class;
- TIdCommandHandler = class;
- TIdCommand = class;
- { Events }
- TIdCommandEvent = procedure(ASender: TIdCommand) of object;
- TIdAfterCommandHandlerEvent = procedure(ASender: TIdCommandHandlers;
- AContext: TIdContext) of object;
- TIdBeforeCommandHandlerEvent = procedure(ASender: TIdCommandHandlers;
- var AData: string; AContext: TIdContext) of object;
- TIdCommandHandlersExceptionEvent = procedure(ACommand: String; AContext: TIdContext) of object;
- { TIdCommandHandler }
- TIdCommandHandler = class(TCollectionItem)
- protected
- FCmdDelimiter: Char;
- FCommand: string;
- {$IFDEF USE_OBJECT_ARC}
- // When ARC is enabled, object references MUST be valid objects.
- // It is common for users to store non-object values, though, so
- // we will provide separate properties for those purposes
- //
- // TODO; use TValue instead of separating them
- //
- FDataObject: TObject;
- FDataValue: PtrInt;
- {$ELSE}
- FData: TObject;
- {$ENDIF}
- FDescription: TStrings;
- FDisconnect: boolean;
- FEnabled: boolean;
- FExceptionReply: TIdReply;
- FHelpSuperScript : String; //may be something like * or + which should appear in help
- FHelpVisible : Boolean;
- FName: string;
- FNormalReply: TIdReply;
- FOnCommand: TIdCommandEvent;
- FParamDelimiter: Char;
- FParseParams: Boolean;
- FReplyClass : TIdReplyClass;
- FResponse: TStrings;
- FTag: integer;
- //
- function GetDisplayName: string; override;
- procedure SetDescription(AValue: TStrings);
- procedure SetExceptionReply(AValue: TIdReply);
- procedure SetNormalReply(AValue: TIdReply);
- procedure SetResponse(AValue: TStrings);
- public
- function Check(const AData: string; AContext: TIdContext): boolean; virtual;
- procedure DoCommand(const AData: string; AContext: TIdContext; AUnparsedParams: string); virtual;
- procedure DoParseParams(AUnparsedParams: string; AParams: TStrings); virtual;
- constructor Create(ACollection: TCollection); override;
- destructor Destroy; override;
- // function GetNamePath: string; override;
- function NameIs(const ACommand: string): Boolean;
- //
- {$IFDEF USE_OBJECT_ARC}
- property DataObject: TObject read FDataObject write FDataObject;
- property DataValue: PtrInt read FDataValue write FDataValue;
- {$ELSE}
- property Data: TObject read FData write FData;
- {$ENDIF}
- published
- property CmdDelimiter: Char read FCmdDelimiter write FCmdDelimiter;
- property Command: string read FCommand write FCommand;
- property Description: TStrings read FDescription write SetDescription;
- property Disconnect: boolean read FDisconnect write FDisconnect;
- property Enabled: boolean read FEnabled write FEnabled default IdEnabledDefault;
- property ExceptionReply: TIdReply read FExceptionReply write SetExceptionReply;
- property Name: string read FName write FName;
- property NormalReply: TIdReply read FNormalReply write SetNormalReply;
- property ParamDelimiter: Char read FParamDelimiter write FParamDelimiter;
- property ParseParams: Boolean read FParseParams write FParseParams;
- property Response: TStrings read FResponse write SetResponse;
- property Tag: Integer read FTag write FTag;
- //
- property HelpSuperScript : String read FHelpSuperScript write FHelpSuperScript; //may be something like * or + which should appear in help
- property HelpVisible : Boolean read FHelpVisible write FHelpVisible default IdHelpVisibleDef;
- property OnCommand: TIdCommandEvent read FOnCommand write FOnCommand;
- end;
- TIdCommandHandlerClass = class of TIdCommandHandler;
- { TIdCommandHandlers }
- TIdCommandHandlers = class(TOwnedCollection)
- protected
- FBase: TIdComponent;
- FExceptionReply: TIdReply;
- FOnAfterCommandHandler: TIdAfterCommandHandlerEvent;
- FOnBeforeCommandHandler: TIdBeforeCommandHandlerEvent;
- FOnCommandHandlersException: TIdCommandHandlersExceptionEvent;
- FParseParamsDef: Boolean;
- FPerformReplies: Boolean;
- FReplyClass: TIdReplyClass;
- FReplyTexts: TIdReplies;
- //
- procedure DoAfterCommandHandler(AContext: TIdContext);
- procedure DoBeforeCommandHandler(AContext: TIdContext; var VLine: string);
- procedure DoOnCommandHandlersException(const ACommand: String; AContext: TIdContext);
- function GetItem(AIndex: Integer): TIdCommandHandler;
- // This is used instead of the OwnedBy property directly calling GetOwner because
- // D5 dies with internal errors and crashes
- // function GetOwnedBy: TIdPersistent;
- procedure SetItem(AIndex: Integer; const AValue: TIdCommandHandler);
- public
- function Add: TIdCommandHandler;
- constructor Create(
- ABase: TIdComponent;
- AReplyClass: TIdReplyClass;
- AReplyTexts: TIdReplies;
- AExceptionReply: TIdReply = nil;
- ACommandHandlerClass: TIdCommandHandlerClass = nil
- ); reintroduce;
- function HandleCommand(AContext: TIdContext; var VCommand: string): Boolean; virtual;
- //
- property Base: TIdComponent read FBase;
- property Items[AIndex: Integer]: TIdCommandHandler read GetItem write SetItem;
- // OwnedBy is used so as not to conflict with Owner in D6
- //property OwnedBy: TIdPersistent read GetOwnedBy;
- property ParseParamsDefault: Boolean read FParseParamsDef write FParseParamsDef;
- property PerformReplies: Boolean read FPerformReplies write FPerformReplies;
- property ReplyClass: TIdReplyClass read FReplyClass;
- property ReplyTexts: TIdReplies read FReplyTexts;
- //
- property OnAfterCommandHandler: TIdAfterCommandHandlerEvent read FOnAfterCommandHandler
- write FOnAfterCommandHandler;
- // Occurs in the context of the peer thread
- property OnBeforeCommandHandler: TIdBeforeCommandHandlerEvent read FOnBeforeCommandHandler
- write FOnBeforeCommandHandler;
- property OnCommandHandlersException: TIdCommandHandlersExceptionEvent read FOnCommandHandlersException
- write FOnCommandHandlersException;
- end;
- { TIdCommand }
- TIdCommand = class(TObject)
- protected
- FCommandHandler: TIdCommandHandler;
- FDisconnect: Boolean;
- FParams: TStrings;
- FPerformReply: Boolean;
- FRawLine: string;
- FReply: TIdReply;
- FResponse: TStrings;
- FContext: TIdContext;
- FUnparsedParams: string;
- FSendEmptyResponse: Boolean;
- //
- procedure DoCommand; virtual;
- procedure SetReply(AValue: TIdReply);
- procedure SetResponse(AValue: TStrings);
- public
- constructor Create(AOwner: TIdCommandHandler); virtual;
- destructor Destroy; override;
- procedure SendReply;
- //
- property CommandHandler: TIdCommandHandler read FCommandHandler;
- property Disconnect: Boolean read FDisconnect write FDisconnect;
- property PerformReply: Boolean read FPerformReply write FPerformReply;
- property Params: TStrings read FParams;
- property RawLine: string read FRawLine;
- property Reply: TIdReply read FReply write SetReply;
- property Response: TStrings read FResponse write SetResponse;
- property Context: TIdContext read FContext;
- property UnparsedParams: string read FUnparsedParams;
- property SendEmptyResponse: Boolean read FSendEmptyResponse write FSendEmptyResponse;
- end;//TIdCommand
- implementation
- uses
- SysUtils;
- { TIdCommandHandlers }
- constructor TIdCommandHandlers.Create(
- ABase: TIdComponent;
- AReplyClass: TIdReplyClass;
- AReplyTexts: TIdReplies;
- AExceptionReply: TIdReply = nil;
- ACommandHandlerClass: TIdCommandHandlerClass = nil
- );
- begin
- if ACommandHandlerClass = nil then begin
- ACommandHandlerClass := TIdCommandHandler;
- end;
- inherited Create(ABase, ACommandHandlerClass);
- FBase := ABase;
- FExceptionReply := AExceptionReply;
- FParseParamsDef := IdParseParamsDefault;
- FPerformReplies := True; // RLebeau: default to legacy behavior
- FReplyClass := AReplyClass;
- FReplyTexts := AReplyTexts;
- end;
- function TIdCommandHandlers.Add: TIdCommandHandler;
- begin
- Result := TIdCommandHandler(inherited Add);
- end;
- function TIdCommandHandlers.HandleCommand(AContext: TIdContext;
- var VCommand: string): Boolean;
- var
- i, j: Integer;
- begin
- j := Count - 1;
- Result := False;
- DoBeforeCommandHandler(AContext, VCommand); try
- i := 0;
- while i <= j do begin
- if Items[i].Enabled then begin
- Result := Items[i].Check(VCommand, AContext);
- if Result then begin
- Break;
- end;
- end;
- Inc(i);
- end;
- finally DoAfterCommandHandler(AContext); end;
- end;
- procedure TIdCommandHandlers.DoAfterCommandHandler(AContext: TIdContext);
- begin
- if Assigned(OnAfterCommandHandler) then begin
- OnAfterCommandHandler(Self, AContext);
- end;
- end;
- procedure TIdCommandHandlers.DoBeforeCommandHandler(AContext: TIdContext;
- var VLine: string);
- begin
- if Assigned(OnBeforeCommandHandler) then begin
- OnBeforeCommandHandler(Self, VLine, AContext);
- end;
- end;
- procedure TIdCommandHandlers.DoOnCommandHandlersException(const ACommand: String;
- AContext: TIdContext);
- begin
- if Assigned(FOnCommandHandlersException) then begin
- OnCommandHandlersException(ACommand, AContext);
- end;
- end;
- function TIdCommandHandlers.GetItem(AIndex: Integer): TIdCommandHandler;
- begin
- Result := TIdCommandHandler(inherited Items[AIndex]);
- end;
- {
- function TIdCommandHandlers.GetOwnedBy: TIdPersistent;
- begin
- Result := GetOwner;
- end;
- }
- procedure TIdCommandHandlers.SetItem(AIndex: Integer; const AValue: TIdCommandHandler);
- begin
- inherited SetItem(AIndex, AValue);
- end;
- { TIdCommandHandler }
- procedure TIdCommandHandler.DoCommand(const AData: string; AContext: TIdContext; AUnparsedParams: string);
- var
- LCommand: TIdCommand;
- begin
- LCommand := TIdCommand.Create(Self);
- try
- LCommand.FRawLine := AData;
- LCommand.FContext := AContext;
- LCommand.FUnparsedParams := AUnparsedParams;
- if ParseParams then begin
- DoParseParams(AUnparsedParams, LCommand.Params);
- end;
- // RLebeau 2/21/08: for the IRC protocol, RFC 2812 section 2.4 says that
- // clients are not allowed to issue numeric replies for server-issued
- // commands. Added the PerformReplies property so TIdIRC can specify
- // that behavior.
- if Collection is TIdCommandHandlers then begin
- LCommand.PerformReply := TIdCommandHandlers(Collection).PerformReplies;
- end;
- try
- if (LCommand.Reply.Code = '') and (NormalReply.Code <> '') then begin
- LCommand.Reply.Assign(NormalReply);
- end;
- //if code<>'' before DoCommand, then it breaks exception handling
- Assert(LCommand.Reply.Code <> '');
- LCommand.DoCommand;
- if LCommand.Reply.Code = '' then begin
- LCommand.Reply.Assign(NormalReply);
- end;
- // UpdateText here in case user wants to add to it. SendReply also gets it in case
- // a different reply is sent (ie exception, etc), or the user changes the code in the event
- LCommand.Reply.UpdateText;
- except
- on E: Exception do begin
- // If there is an unhandled exception, we override all replies
- // If nothing specified to override with, we throw the exception again.
- // If the user wants a custom value on exception other, its their responsibility
- // to catch it before it reaches us
- LCommand.Reply.Clear;
- if LCommand.PerformReply then begin
- // Try from command handler first
- if ExceptionReply.Code <> '' then begin
- LCommand.Reply.Assign(ExceptionReply);
- // If still no go, from server
- // Can be nil though. Typically only servers pass it in
- end else if (Collection is TIdCommandHandlers) and (TIdCommandHandlers(Collection).FExceptionReply <> nil) then begin
- LCommand.Reply.Assign(TIdCommandHandlers(Collection).FExceptionReply);
- end;
- if LCommand.Reply.Code <> '' then begin
- //done this way in case an exception message has more than one line.
- //otherwise you could get something like this:
- //
- // 550 System Error. Code: 2
- // The system cannot find the file specified
- //
- //and the second line would throw off some clients.
- LCommand.Reply.Text.Text := E.Message;
- //Reply.Text.Add(E.Message);
- LCommand.SendReply;
- end else begin
- raise;
- end;
- end else begin
- raise;
- end;
- end else begin
- raise;
- end;
- end;
- if LCommand.PerformReply then begin
- LCommand.SendReply;
- end;
- if (LCommand.Response.Count > 0) or LCommand.SendEmptyResponse then begin
- AContext.Connection.WriteRFCStrings(LCommand.Response);
- end else if Response.Count > 0 then begin
- AContext.Connection.WriteRFCStrings(Response);
- end;
- finally
- try
- if LCommand.Disconnect then begin
- AContext.Connection.Disconnect;
- end;
- finally
- LCommand.Free;
- end;
- end;
- end;
- procedure TIdCommandHandler.DoParseParams(AUnparsedParams: string; AParams: TStrings);
- // AUnparsedParams is not preparsed and is completely left up to the command handler. This will
- // allow for future expansion such as multiple delimiters etc, and allow the logic to properly
- // remain in each of the command handler implementations. In the future there may be a base type
- // and multiple descendants
- begin
- AParams.Clear;
- SplitDelimitedString(AUnparsedParams, AParams, FParamDelimiter <> #32, FParamDelimiter);
- end;
- function TIdCommandHandler.Check(const AData: string; AContext: TIdContext): boolean;
- // AData is not preparsed and is completely left up to the command handler. This will allow for
- // future expansion such as wild cards etc, and allow the logic to properly remain in each of the
- // command handler implementations. In the future there may be a base type and multiple descendants
- var
- LUnparsedParams: string;
- begin
- LUnparsedParams := '';
- Result := TextIsSame(AData, Command); // Command by itself
- if not Result then begin
- if CmdDelimiter <> #0 then begin
- Result := TextStartsWith(AData, Command + CmdDelimiter);
- if Result then begin
- LUnparsedParams := Copy(AData, Length(Command) + 2, MaxInt);
- end;
- end else begin
- // Dont strip any part of the params out.. - just remove the command purely on length and
- // no delim
- Result := TextStartsWith(AData, Command);
- if Result then begin
- LUnparsedParams := Copy(AData, Length(Command) + 1, MaxInt);
- end;
- end;
- end;
- if Result then begin
- DoCommand(AData, AContext, LUnparsedParams);
- end;
- end;
- constructor TIdCommandHandler.Create(ACollection: TCollection);
- begin
- inherited Create(ACollection);
- FReplyClass := TIdCommandHandlers(ACollection).ReplyClass;
- if FReplyClass = nil then begin
- FReplyClass := TIdReplyRFC;
- end;
- FCmdDelimiter := #32;
- FEnabled := IdEnabledDefault;
- FName := ClassName + IntToStr(ID);
- FParamDelimiter := #32;
- FParseParams := TIdCommandHandlers(ACollection).ParseParamsDefault;
- FResponse := TStringList.Create;
- FDescription := TStringList.Create;
- FNormalReply := FReplyClass.CreateWithReplyTexts(nil, TIdCommandHandlers(ACollection).ReplyTexts);
- if FNormalReply is TIdReplyRFC then begin
- FNormalReply.Code := '200'; {do not localize}
- end;
- FHelpVisible := IdHelpVisibleDef;
- // Dont initialize, pulls from CmdTCPServer for defaults
- FExceptionReply := FReplyClass.CreateWithReplyTexts(nil, TIdCommandHandlers(ACollection).ReplyTexts);
- end;
- destructor TIdCommandHandler.Destroy;
- begin
- FreeAndNil(FResponse);
- FreeAndNil(FNormalReply);
- FreeAndNil(FDescription);
- FreeAndNil(FExceptionReply);
- inherited Destroy;
- end;
- function TIdCommandHandler.GetDisplayName: string;
- begin
- if Command = '' then begin
- Result := Name;
- end else begin
- Result := Command;
- end;
- end;
- {
- function TIdCommandHandler.GetNamePath: string;
- begin
- if Collection <> nil then begin
- // OwnedBy is used because D4/D5 dont expose Owner on TOwnedCollection but D6 does
- Result := TIdCommandHandlers(Collection).OwnedBy.GetNamePath + '.' + Name;
- end else begin
- Result := inherited GetNamePath;
- end;
- end;
- }
- function TIdCommandHandler.NameIs(const ACommand: string): Boolean;
- begin
- Result := TextIsSame(ACommand, FName);
- end;
- procedure TIdCommandHandler.SetExceptionReply(AValue: TIdReply);
- begin
- FExceptionReply.Assign(AValue);
- end;
- procedure TIdCommandHandler.SetNormalReply(AValue: TIdReply);
- begin
- FNormalReply.Assign(AValue);
- end;
- procedure TIdCommandHandler.SetResponse(AValue: TStrings);
- begin
- FResponse.Assign(AValue);
- end;
- procedure TIdCommandHandler.SetDescription(AValue: TStrings);
- begin
- FDescription.Assign(AValue);
- end;
- { TIdCommand }
- constructor TIdCommand.Create(AOwner: TIdCommandHandler);
- begin
- inherited Create;
- FParams := TStringList.Create;
- FReply := AOwner.FReplyClass.CreateWithReplyTexts(nil, TIdCommandHandlers(AOwner.Collection).ReplyTexts);
- FResponse := TStringList.Create;
- FCommandHandler := AOwner;
- FDisconnect := AOwner.Disconnect;
- end;
- destructor TIdCommand.Destroy;
- begin
- FreeAndNil(FReply);
- FreeAndNil(FResponse);
- FreeAndNil(FParams);
- inherited Destroy;
- end;
- procedure TIdCommand.DoCommand;
- begin
- if Assigned(CommandHandler.OnCommand) then begin
- CommandHandler.OnCommand(Self);
- end;
- end;
- procedure TIdCommand.SendReply;
- begin
- PerformReply := False;
- Reply.UpdateText;
- Context.Connection.IOHandler.Write(Reply.FormattedReply);
- end;
- procedure TIdCommand.SetReply(AValue: TIdReply);
- begin
- FReply.Assign(AValue);
- end;
- procedure TIdCommand.SetResponse(AValue: TStrings);
- begin
- FResponse.Assign(AValue);
- end;
- end.
|