683 lines
22 KiB
Plaintext
683 lines
22 KiB
Plaintext
{
|
|
$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,
|
|
IdBaseComponent, 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.
|