restemplate/indy/Protocols/IdIRC.pas

2941 lines
112 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$
}
{
2003-11-Jul:
Original author: Sergio Perry
Matthew Elzer - bug fixes & modifications
}
unit IdIRC;
{
Based on TIRCClient component by Steve Williams (stevewilliams@kromestudios.com)
ported to Indy by Daaron Dwyer (ddwyer@ncic.com)
}
{ Based on RFC 2812 }
interface
{$i IdCompilerDefines.inc}
uses
Classes,
IdAssignedNumbers, IdContext, IdCmdTCPClient, IdCommandHandlers,
IdIOHandler, IdGlobal, IdException;
type
TIdIRC = class;
TIdIRCUserMode = (amAway, amInvisible, amWallops, amRestricted, amOperator, amLocalOperator, amReceiveServerNotices);
TIdIRCUserModes = set of TIdIRCUserMode;
TIdIRCStat = (stServerConnectionsList, stCommandUsageCount, stOperatorList, stUpTime);
{ -WELCOME- }
TIdIRCServerMsgEvent = procedure(ASender: TIdContext; const AMsg: String) of object;
TIdIRCMyInfoEvent = procedure(ASender: TIdContext; const AServer, AVersion, AUserModes, AChanModes, AExtra: String) of object;
TIdIRCBounceEvent = procedure(ASender: TIdContext; const AHost: String; APort: Integer; const AInfo: String) of object;
TIdIRCISupportEvent = procedure(ASender: TIdContext; AParameters: TStrings) of object;
{ -PING- }
TIdIRCPingPongEvent = procedure(ASender: TIdContext) of object;
{ -MESSAGE- }
TIdIRCPrivMessageEvent = procedure(ASender: TIdContext; const ANickname, AHost, ATarget, AMessage: String) of object;
{ -NOTICE- }
TIdIRCNoticeEvent = procedure(ASender: TIdContext; const ANickname, AHost, ATarget, ANotice: String) of object;
{ -REHASH- }
TIdIRCRehashEvent = procedure(ASender: TIdContext; const ANickname, AHost: String) of object;
{ -SUMMON- }
TIdIRCSummonEvent = procedure(ASender: TIdContext; const ANickname, AHost: String) of object;
{ -WALLOPS- }
TIdIRCWallopsEvent = procedure(ASender: TIdContext; const ANickname, AHost, AMessage: String) of object;
{ -ISON- }
TIdIRCIsOnIRCEvent = procedure(ASender: TIdContext; const ANickname, AHost: String) of object;
{ -AWAY- }
TIdIRCAwayEvent = procedure(ASender: TIdContext; const ANickname, AHost, AAwayMessage: String; UserAway: Boolean) of object;
{ -JOIN- }
TIdIRCJoinEvent = procedure(ASender: TIdContext; const ANickname, AHost, AChannel: String) of object;
{ -PART- }
TIdIRCPartEvent = procedure(ASender: TIdContext; const ANickname, AHost, AChannel, APartMessage: String) of object;
{ -TOPIC- }
TIdIRCTopicEvent = procedure(ASender: TIdContext; const ANickname, AHost, AChannel, ATopic: String) of object;
{ -KICK- }
TIdIRCKickEvent = procedure(ASender: TIdContext; const ANickname, AHost, AChannel, ATarget, AReason: String) of object;
{ -MOTD- }
TIdIRCMOTDEvent = procedure(ASender: TIdContext; AMOTD: TStrings) of object;
{ -TRACE- }
TIdIRCServerTraceEvent = procedure(ASender: TIdContext; ATraceInfo: TStrings) of object;
{ -OPER- }
TIdIRCOpEvent = procedure(ASender: TIdContext; const ANickname, AChannel, AHost: String) of object;
{ -INV- }
TIdIRCInvitingEvent = procedure(ASender: TIdContext; const ANickname, AHost: String) of object;
TIdIRCInviteEvent = procedure(ASender: TIdContext; const ANickname, AHost, ATarget, AChannel: String) of object;
{ -LIST- }
TIdIRCChanBANListEvent = procedure(ASender: TIdContext; const AChannel: String; ABanList: TStrings) of object;
TIdIRCChanEXCListEvent = procedure(ASender: TIdContext; const AChannel: String; AExceptList: TStrings) of object;
TIdIRCChanINVListEvent = procedure(ASender: TIdContext; const AChannel: String; AInviteList: TStrings) of object;
TIdIRCServerListEvent = procedure(ASender: TIdContext; AServerList: TStrings) of object;
TIdIRCNickListEvent = procedure(ASender: TIdContext; const AChannel: String; ANicknameList: TStrings) of object;
{ -STATS- }
TIdIRCServerUsersEvent = procedure(ASender: TIdContext; AUsers: TStrings) of object;
TIdIRCServerStatsEvent = procedure(ASender: TIdContext; AStatus: TStrings) of object;
TIdIRCKnownServerNamesEvent = procedure(ASender: TIdContext; AKnownServers: TStrings) of object;
{ -INFO- }
TIdIRCAdminInfoRecvEvent = procedure(ASender: TIdContext; AAdminInfo: TStrings) of object;
TIdIRCUserInfoRecvEvent = procedure(ASender: TIdContext; const AUserInfo: String) of object;
{ -WHO- }
TIdIRCWhoEvent = procedure(ASender: TIdContext; AWhoResults: TStrings) of object;
TIdIRCWhoIsEvent = procedure(ASender: TIdContext; AWhoIsResults: TStrings) of object;
TIdIRCWhoWasEvent = procedure(ASender: TIdContext; AWhoWasResults: TStrings) of object;
{ Mode }
TIdIRCChanModeEvent = procedure(ASender: TIdContext; const ANickname, AHost, AChannel, AMode, AParams: String) of object;
TIdIRCUserModeEvent = procedure(ASender: TIdContext; const ANickname, AHost, AMode: String) of object;
{ -CTCP- }
TIdIRCCTCPQueryEvent = procedure(ASender: TIdContext; const ANickname, AHost, ATarget, ACommand, AParams: String) of object;
TIdIRCCTCPReplyEvent = procedure(ASender: TIdContext; const ANickname, AHost, ATarget, ACommand, AParams: String) of object;
{ -DCC- }
TIdIRCDCCChatEvent = procedure(ASender: TIdContext; const ANickname, AHost: String; APort: Integer) of object;
TIdIRCDCCSendEvent = procedure(ASender: TIdContext; const ANickname, AHost, AFilename: String; APort: TIdPort; AFileSize: Int64) of object;
TIdIRCDCCResumeEvent = procedure(ASender: TIdContext; const ANickname, AHost, AFilename: String; APort: TIdPort; AFilePos: Int64) of object;
TIdIRCDCCAcceptEvent = procedure(ASender: TIdContext; const ANickname, AHost, AFilename: String; APort: TIdPort; AFilePos: Int64) of object;
{ -Errors- }
TIdIRCServerErrorEvent = procedure(ASender: TIdContext; AErrorCode: Integer; const AErrorMessage: String) of object;
TIdIRCNickErrorEvent = procedure(ASender: TIdContext; AError: Integer) of object;
TIdIRCKillErrorEvent = procedure(ASender: TIdContext) of object;
{ Other }
TIdIRCNicknameChangedEvent = procedure(ASender: TIdContext; const AOldNickname, AHost, ANewNickname: String) of object;
TIdIRCKillEvent = procedure(ASender: TIdContext; const ANickname, AHost, ATargetNickname, AReason: String) of object;
TIdIRCQuitEvent = procedure(ASender: TIdContext; const ANickname, AHost, AReason: String) of object;
TIdIRCSvrQuitEvent = procedure(ASender: TIdContext; const ANickname, AHost, AServer, AReason: String) of object;
TIdIRCSvrTimeEvent = procedure(ASender: TIdContext; const AHost, ATime: String) of object;
TIdIRCServiceEvent = procedure(ASender: TIdContext) of object;
TIdIRCSvrVersionEvent = procedure(ASender: TIdContext; const AVersion, AHost, AComments: String) of object;
TIdIRCRawEvent = procedure(ASender: TIdContext; AIn: Boolean; const AMessage: String) of object;
EIdIRCError = class(EIdException);
TIdIRCReplies = class(TPersistent)
protected
FFinger: String;
FVersion: String;
FUserInfo: String;
FClientInfo: String;
public
constructor Create;
procedure Assign(Source: TPersistent); override;
published
property Finger: String read FFinger write FFinger;
property Version: String read FVersion write FVersion;
property UserInfo: String read FUserInfo write FUserInfo;
property ClientInfo: String read FClientInfo write FClientInfo;
end;
TIdIRC = class(TIdCmdTCPClient)
protected
FNickname: String;
FAltNickname: String;
FAltNickUsed: Boolean;
//
FUsername: String;
FRealName: String;
FPassword: String;
FUserMode: TIdIRCUserModes;
FUserAway: Boolean;
FReplies: TIdIRCReplies;
//
FSenderNick: String;
FSenderHost: String;
//
FBans: TStrings;
FExcepts: TStrings;
FInvites: TStrings;
FLinks: TStrings;
FMotd: TStrings;
FNames: TStrings;
FWho: TStrings;
FWhoIs: TStrings;
FWhoWas: TStrings;
FSvrList: TStrings;
FUsers: TStrings;
//
FOnSWelcome: TIdIRCServerMsgEvent;
FOnYourHost: TIdIRCServerMsgEvent;
FOnSCreated: TIdIRCServerMsgEvent;
FOnMyInfo: TIdIRCMyInfoEvent;
FOnBounce: TIdIRCBounceEvent;
FOnISupport: TIdIRCISupportEvent;
FOnSError: TIdIRCServerMsgEvent;
FOnPingPong: TIdIRCPingPongEvent;
FOnPrivMessage: TIdIRCPrivMessageEvent;
FOnNotice: TIdIRCNoticeEvent;
FOnRehash: TIdIRCRehashEvent;
FOnSummon: TIdIRCSummonEvent;
FOnWallops: TIdIRCWallopsEvent;
FOnIsOnIRC: TIdIRCIsOnIRCEvent;
FOnAway: TIdIRCAwayEvent;
FOnJoin: TIdIRCJoinEvent;
FOnPart: TIdIRCPartEvent;
FOnTopic: TIdIRCTopicEvent;
FOnKick: TIdIRCKickEvent;
FOnMOTD: TIdIRCMOTDEvent;
FOnTrace: TIdIRCServerTraceEvent;
FOnOp: TIdIRCOpEvent;
FOnInviting: TIdIRCInvitingEvent;
FOnInvite: TIdIRCInviteEvent;
FOnBANList: TIdIRCChanBANListEvent;
FOnEXCList: TIdIRCChanEXCListEvent;
FOnINVList: TIdIRCChanINVListEvent;
FOnSvrList: TIdIRCServerListEvent;
FOnNickList: TIdIRCNickListEvent;
FOnSvrUsers: TIdIRCServerUsersEvent;
FOnSvrStats: TIdIRCServerStatsEvent;
FOnKnownSvrs: TIdIRCKnownServerNamesEvent;
FOnAdminInfo: TIdIRCAdminInfoRecvEvent;
FOnUserInfo: TIdIRCUserInfoRecvEvent;
FOnWho: TIdIRCWhoEvent;
FOnWhoIs: TIdIRCWhoIsEvent;
FOnWhoWas: TIdIRCWhoWasEvent;
FOnChanMode: TIdIRCChanModeEvent;
FOnUserMode: TIdIRCUserModeEvent;
FOnCTCPQry: TIdIRCCTCPQueryEvent;
FOnCTCPRep: TIdIRCCTCPReplyEvent;
FOnDCCChat: TIdIRCDCCChatEvent;
FOnDCCSend: TIdIRCDCCSendEvent;
FOnDCCResume: TIdIRCDCCResumeEvent;
FOnDCCAccept: TIdIRCDCCAcceptEvent;
FOnServerError: TIdIRCServerErrorEvent;
FOnNickError: TIdIRCNickErrorEvent;
FOnKillError: TIdIRCKillErrorEvent;
FOnNickChange: TIdIRCNicknameChangedEvent;
FOnKill: TIdIRCKillEvent;
FOnQuit: TIdIRCQuitEvent;
FOnSvrQuit: TIdIRCSvrQuitEvent;
FOnSvrTime: TIdIRCSvrTimeEvent;
FOnService: TIdIRCServiceEvent;
FOnSvrVersion: TIdIRCSvrVersionEvent;
FOnRaw: TIdIRCRawEvent;
//
function GetUsedNickname: String;
procedure SetNickname(const AValue: String);
procedure SetUsername(const AValue: String);
procedure SetIdIRCUserMode(AValue: TIdIRCUserModes);
procedure SetIdIRCReplies(AValue: TIdIRCReplies);
function GetUserMode: String;
procedure ParseDCC(AContext: TIdContext; const ADCC: String);
//Command handlers
procedure DoBeforeCmd(ASender: TIdCommandHandlers; var AData: string; AContext: TIdContext);
procedure DoReplyUnknownCommand(AContext: TIdContext; ALine: string); override;
procedure DoBounce(ASender: TIdCommand; ALegacy: Boolean);
procedure CommandPRIVMSG(ASender: TIdCommand);
procedure CommandNOTICE(ASender: TIdCommand);
procedure CommandJOIN(ASender: TIdCommand);
procedure CommandPART(ASender: TIdCommand);
procedure CommandKICK(ASender: TIdCommand);
procedure CommandMODE(ASender: TIdCommand);
procedure CommandNICK(ASender: TIdCommand);
procedure CommandQUIT(ASender: TIdCommand);
procedure CommandSQUIT(ASender: TIdCommand);
procedure CommandINVITE(ASender: TIdCommand);
procedure CommandKILL(ASender: TIdCommand);
procedure CommandPING(ASender: TIdCommand);
procedure CommandERROR(ASender: TIdCommand);
procedure CommandWALLOPS(ASender: TIdCommand);
procedure CommandTOPIC(ASender: TIdCommand);
procedure CommandWELCOME(ASender: TIdCommand);
procedure CommandYOURHOST(ASender: TIdCommand);
procedure CommandCREATED(ASender: TIdCommand);
procedure CommandMYINFO(ASender: TIdCommand);
procedure CommandISUPPORT(ASender: TIdCommand);
procedure CommandBOUNCE(ASender: TIdCommand);
procedure CommandUSERHOST(ASender: TIdCommand);
procedure CommandISON(ASender: TIdCommand);
procedure CommandWHOIS(ASender: TIdCommand);
procedure CommandENDOFWHOIS(ASender: TIdCommand);
procedure CommandWHOWAS(ASender: TIdCommand);
procedure CommandENDOFWHOWAS(ASender: TIdCommand);
procedure CommandLISTSTART(ASender: TIdCommand);
procedure CommandLIST(ASender: TIdCommand);
procedure CommandLISTEND(ASender: TIdCommand);
procedure CommandAWAY(ASender: TIdCommand);
procedure CommandINVITING(ASender: TIdCommand);
procedure CommandSUMMONING(ASender: TIdCommand);
procedure CommandINVITELIST(ASender: TIdCommand);
procedure CommandENDOFINVITELIST(ASender: TIdCommand);
procedure CommandEXCEPTLIST(ASender: TIdCommand);
procedure CommandENDOFEXCEPTLIST(ASender: TIdCommand);
procedure CommandWHOREPLY(ASender: TIdCommand);
procedure CommandENDOFWHO(ASender: TIdCommand);
procedure CommandNAMEREPLY(ASender: TIdCommand);
procedure CommandENDOFNAMES(ASender: TIdCommand);
procedure CommandLINKS(ASender: TIdCommand);
procedure CommandENDOFLINKS(ASender: TIdCommand);
procedure CommandBANLIST(ASender: TIdCommand);
procedure CommandENDOFBANLIST(ASender: TIdCommand);
procedure CommandINFO(ASender: TIdCommand);
procedure CommandENDOFINFO(ASender: TIdCommand);
procedure CommandMOTD(ASender: TIdCommand);
procedure CommandENDOFMOTD(ASender: TIdCommand);
procedure CommandREHASHING(ASender: TIdCommand);
procedure CommandUSERSSTART(ASender: TIdCommand);
procedure CommandUSERS(ASender: TIdCommand);
procedure CommandENDOFUSERS(ASender: TIdCommand);
procedure CommandENDOFSTATS(ASender: TIdCommand);
procedure CommandSERVLIST(ASender: TIdCommand);
procedure CommandSERVLISTEND(ASender: TIdCommand);
procedure CommandTIME(ASender: TIdCommand);
procedure CommandSERVICE(ASender: TIdCommand);
procedure CommandVERSION(ASender: TIdCommand);
procedure CommandCHANMODE(ASender: TIdCommand);
procedure CommandOPER(ASender: TIdCommand);
procedure CommandNICKINUSE(ASender: TIdCommand);
//
procedure AssignIRCClientCommands;
function GetCmdHandlerClass: TIdCommandHandlerClass; override;
procedure SetIOHandler(AValue: TIdIOHandler); override;
procedure InitComponent; override;
public
destructor Destroy; override;
//
procedure Connect; override;
procedure Disconnect(const AReason: String = ''); reintroduce;
//
function IsChannel(const AChannel: String): Boolean;
function IsOp(const ANickname: String): Boolean;
function IsVoice(const ANickname: String): Boolean;
procedure Raw(const ALine: String);
procedure Say(const ATarget, AMsg: String);
procedure Notice(const ATarget, AMsg: String);
procedure Action(const ATarget, AMsg: String);
procedure CTCPQuery(const ATarget, ACommand, AParameters: String);
procedure CTCPReply(const ATarget, ACTCP, AReply: String);
procedure Join(const AChannel: String; const AKey: String ='');
procedure Part(const AChannel: String; const AReason: String = '');
procedure Kick(const AChannel, ANickname: String; const AReason: String = '');
procedure SetChannelMode(const AChannel, AMode: String; const AParams: String = '');
procedure SetUserMode(const ANickname, AMode: String);
procedure GetChannelTopic(const AChannel: String);
procedure SetChannelTopic(const AChannel, ATopic: String);
procedure SetAway(const AMsg: String);
procedure Op(const AChannel, ANickname: String);
procedure Deop(const AChannel, ANickname: String);
procedure Voice(const AChannel, ANickname: String);
procedure Devoice(const AChannel, ANickname: String);
procedure Ban(const AChannel, AHostmask: String);
procedure Unban(const AChannel, AHostmask: String);
procedure RegisterService(const ANickname, ADistribution, AInfo: String; AType: Integer);
procedure ListChannelNicknames(const AChannel: String; const ATarget: String = '');
procedure ListChannel(const AChannel: String; const ATarget: String = '');
procedure Invite(const ANickname, AChannel: String);
procedure GetMessageOfTheDay(const ATarget: String = '');
procedure GetNetworkStatus(const AHostMask: String = ''; const ATarget: String = '');
procedure GetServerVersion(const ATarget: String = '');
procedure GetServerStatus(AQuery: TIdIRCStat; const ATarget: String = '');
procedure ListKnownServerNames(const ARemoteHost: String = ''; const AHostMask: String = '');
procedure QueryServerTime(const ATarget: String = '');
procedure RequestServerConnect(const ATargetHost: String; APort: Integer; const ARemoteHost: String = '');
procedure TraceServer(const ATarget: String = '');
procedure GetAdminInfo(const ATarget: String = '');
procedure GetServerInfo(const ATarget: String = '');
procedure ListNetworkServices(const AHostMask: String = ''; const AType: String = '');
procedure QueryService(const AServiceName, AMessage: String);
procedure Who(const AMask: String; AOnlyAdmins: Boolean);
procedure WhoIs(const AMask: String; const ATarget: String = '');
procedure WhoWas(const ANickname: String; ACount: Integer = -1; const ATarget: String = '');
procedure Kill(const ANickname, AComment: String);
procedure Ping(const AServer1: String; const AServer2: String = '');
procedure Pong(const AServer1: String; const AServer2: String = '');
procedure Error(const AMessage: String);
procedure ReHash;
procedure Die;
procedure Restart;
procedure Summon(const ANickname: String; const ATarget: String = ''; const AChannel: String = '');
procedure ListServerUsers(const ATarget: String = '');
procedure SayWALLOPS(const AMessage: String);
procedure GetUserInfo(const ANickname: String);
procedure GetUsersInfo(const ANicknames: array of String);
procedure IsOnIRC(const ANickname: String); overload;
procedure IsOnIRC(const ANicknames: array of String); overload;
procedure BecomeOp(const ANickname, APassword: String);
procedure SQuit(const AHost, AComment: String);
procedure SetChannelLimit(const AChannel: String; ALimit: Integer);
procedure SetChannelKey(const AChannel, AKey: String);
//
property Away: Boolean read FUserAway;
published
property Nickname: String read FNickname write SetNickname;
property AltNickname: String read FAltNickname write FAltNickname;
property UsedNickname: String read GetUsedNickname; // returns Nickname or AltNickname
property Username: String read FUsername write SetUsername;
property RealName: String read FRealName write FRealName;
property Password: String read FPassword write FPassword;
property Port default IdPORT_IRC;
property Replies: TIdIRCReplies read FReplies write SetIdIRCReplies;
property UserMode: TIdIRCUserModes read FUserMode write SetIdIRCUserMode;
{ Events }
property OnServerWelcome: TIdIRCServerMsgEvent read FOnSWelcome write FOnSWelcome;
property OnYourHost: TIdIRCServerMsgEvent read FOnYourHost write FOnYourHost;
property OnServerCreated: TIdIRCServerMsgEvent read FOnSCreated write FOnSCreated;
property OnMyInfo: TIdIRCMyInfoEvent read FOnMyInfo write FOnMyInfo;
property OnBounce: TIdIRCBounceEvent read FOnBounce write FOnBounce;
property OnISupport: TIdIRCISupportEvent read FOnISupport write FOnISupport;
property OnPingPong: TIdIRCPingPongEvent read FOnPingPong write FOnPingPong;
property OnPrivateMessage: TIdIRCPrivMessageEvent read FOnPrivMessage write FOnPrivMessage;
property OnNotice: TIdIRCNoticeEvent read FOnNotice write FOnNotice;
property OnRehash: TIdIRCRehashEvent read FOnRehash write FOnRehash;
property OnSummon: TIdIRCSummonEvent read FOnSummon write FOnSummon;
property OnWallops: TIdIRCWallopsEvent read FOnWallops write FOnWallops;
property OnIsOnIRC: TIdIRCIsOnIRCEvent read FOnIsOnIRC write FOnIsOnIRC;
property OnAway: TIdIRCAwayEvent read FOnAway write FOnAway;
property OnJoin: TIdIRCJoinEvent read FOnJoin write FOnJoin;
property OnPart: TIdIRCPartEvent read FOnPart write FOnPart;
property OnTopic: TIdIRCTopicEvent read FOnTopic write FOnTopic;
property OnKick: TIdIRCKickEvent read FOnKick write FOnKick;
property OnMOTD: TIdIRCMOTDEvent read FOnMOTD write FOnMOTD;
property OnTrace: TIdIRCServerTraceEvent read FOnTrace write FOnTrace;
property OnOp: TIdIRCOpEvent read FOnOp write FOnOp;
property OnInviting: TIdIRCInvitingEvent read FOnInviting write FOnInviting;
property OnInvite: TIdIRCInviteEvent read FOnInvite write FOnInvite;
property OnBanListReceived: TIdIRCChanBANListEvent read FOnBANList write FOnBANList;
property OnExceptionListReceived: TIdIRCChanEXCListEvent read FOnEXCList write FOnEXCList;
property OnInvitationListReceived: TIdIRCChanINVListEvent read FOnINVList write FOnINVList;
property OnServerListReceived: TIdIRCServerListEvent read FOnSvrList write FOnSvrList;
property OnNicknamesListReceived: TIdIRCNickListEvent read FOnNickList write FOnNickList;
property OnServerUsersListReceived: TIdIRCServerUsersEvent read FOnSvrUsers write FOnSvrUsers;
property OnServerStatsReceived: TIdIRCServerStatsEvent read FOnSvrStats write FOnSvrStats;
property OnKnownServersListReceived: TIdIRCKnownServerNamesEvent read FOnKnownSvrs write FOnKnownSvrs;
property OnAdminInfoReceived: TIdIRCAdminInfoRecvEvent read FOnAdminInfo write FOnAdminInfo;
property OnUserInfoReceived: TIdIRCUserInfoRecvEvent read FOnUserInfo write FOnUserInfo;
property OnWho: TIdIRCWhoEvent read FOnWho write FOnWho;
property OnWhoIs: TIdIRCWhoIsEvent read FOnWhoIs write FOnWhoIs;
property OnWhoWas: TIdIRCWhoWasEvent read FOnWhoWas write FOnWhoWas;
property OnChannelMode: TIdIRCChanModeEvent read FOnChanMode write FOnChanMode;
property OnUserMode: TIdIRCUserModeEvent read FOnUserMode write FOnUserMode;
property OnCTCPQuery: TIdIRCCTCPQueryEvent read FOnCTCPQry write FOnCTCPQry;
property OnCTCPReply: TIdIRCCTCPReplyEvent read FOnCTCPRep write FOnCTCPRep;
property OnDCCChat: TIdIRCDCCChatEvent read FOnDCCChat write FOnDCCChat;
property OnDCCSend: TIdIRCDCCSendEvent read FOnDCCSend write FOnDCCSend;
property OnDCCResume: TIdIRCDCCResumeEvent read FOnDCCResume write FOnDCCResume;
property OnDCCAccept: TIdIRCDCCAcceptEvent read FOnDCCAccept write FOnDCCAccept;
property OnServerError: TIdIRCServerErrorEvent read FOnServerError write FOnServerError;
property OnNicknameError: TIdIRCNickErrorEvent read FOnNickError write FOnNickError;
property OnKillError: TIdIRCKillErrorEvent read FOnKillError write FOnKillError;
property OnNicknameChange: TIdIRCNicknameChangedEvent read FOnNickChange write FOnNickChange;
property OnKill: TIdIRCKillEvent read FOnKill write FOnKill;
property OnQuit: TIdIRCQuitEvent read FOnQuit write FOnQuit;
property OnServerQuit: TIdIRCSvrQuitEvent read FOnSvrQuit write FOnSvrQuit;
property OnServerTime: TIdIRCSvrTimeEvent read FOnSvrTime write FOnSvrTime;
property OnService: TIdIRCServiceEvent read FOnService write FOnService;
property OnServerVersion: TIdIRCSvrVersionEvent read FOnSvrVersion write FOnSvrVersion;
property OnRaw: TIdIRCRawEvent read FOnRaw write FOnRaw;
end;
implementation
uses
IdGlobalProtocols, IdResourceStringsProtocols, IdSSL,
IdStack, IdBaseComponent, SysUtils;
const
IdIRCCTCP: array[0..11] of String = ('ACTION', 'SOUND', 'PING', 'FINGER', {do not localize}
'USERINFO', 'VERSION', 'CLIENTINFO', 'TIME', 'ERROR', 'DCC', 'SED', 'ERRMSG'); {do not localize}
MQuote = #16;
XDelim = #1;
XQuote = #92;
{ TIdIRCReplies }
constructor TIdIRCReplies.Create;
begin
inherited Create;
//
end;
procedure TIdIRCReplies.Assign(Source: TPersistent);
var
LSource: TIdIRCReplies;
begin
if Source is TIdIRCReplies then
begin
LSource := TIdIRCReplies(Source);
FFinger := LSource.Finger;
FFinger := LSource.Finger;
FVersion := LSource.Version;
FUserInfo := LSource.UserInfo;
FClientInfo := LSource.ClientInfo;
end else begin
inherited Assign(Source);
end;
end;
{ TIdIRC }
// RLebeau 1/7/2010: SysUtils.TrimLeft() removes all characters < #32, but
// CTC requires character #1, so don't remove that character when parsing
// IRC parameters in FetchIRCParam()...
//
function IRCTrimLeft(const S: string): string;
var
I, L: Integer;
begin
L := Length(S);
I := 1;
while (I <= L) and (S[I] <= ' ') and (S[I] <> XDelim) do begin
Inc(I);
end;
Result := Copy(S, I, Maxint);
end;
function FetchIRCParam(var S: String): String;
var
LTmp: String;
begin
LTmp := IRCTrimLeft(S);
if TextStartsWith(LTmp, ':') then
begin
Result := Copy(LTmp, 2, MaxInt);
S := '';
end else
begin
Result := Fetch(LTmp, ' ');
S := IRCTrimLeft(LTmp);
end;
end;
function IRCQuote(const S: String): String;
begin
// IMPORTANT! MQuote needs to be the first character in the replacement
// list, otherwise it will end up being double-escaped if the other
// character get replaced, which will produce the wrong output!!
Result := StringsReplace(S, [MQuote, #0, LF, CR], [MQuote+MQuote, MQuote+'0', MQuote+'n', MQuote+'r']);
end;
{$IFDEF STRING_IS_IMMUTABLE}
function FindCharInSB(const ASB: TIdStringBuilder; AChar: Char; AStart: Integer): Integer;
begin
for Result := AStart to ASB.Length-1 do begin
if ASB[Result] = AChar then begin
Exit;
end;
end;
Result := -1;
end;
{$ENDIF}
function IRCUnquote(const S: String): String;
var
I, L: Integer;
{$IFDEF STRING_IS_IMMUTABLE}
LSB: TIdStringBuilder;
{$ENDIF}
begin
{$IFDEF STRING_IS_IMMUTABLE}
LSB := TIdStringBuilder.Create(S);
L := LSB.Length;
I := 0;
while I < L do begin
I := FindCharInSB(LSB, MQuote, I);
if I = -1 then begin
Break;
end;
LSB.Remove(I, 1);
Dec(L);
if I >= L then begin
Break;
end;
case LSB[I] of
'0': LSB[I] := #0;
'n': LSB[I] := LF;
'r': LSB[I] := CR;
end;
Inc(I);
end;
Result := LSB.ToString;
{$ELSE}
Result := S;
L := Length(Result);
I := 1;
while I <= L do begin
I := PosIdx(MQuote, Result, I);
if I = 0 then begin
Break;
end;
IdDelete(Result, I, 1);
Dec(L);
if I > L then begin
Break;
end;
case Result[I] of
'0': Result[I] := #0;
'n': Result[I] := LF;
'r': Result[I] := CR;
end;
Inc(I);
end;
{$ENDIF}
end;
function CTCPQuote(const S: String): String;
begin
Result := StringsReplace(S, [XDelim, XQuote], [XQuote+'a', XQuote+XQuote]);
end;
function CTCPUnquote(const S: String): String;
var
I, L: Integer;
{$IFDEF STRING_IS_IMMUTABLE}
LSB: TIdStringBuilder;
{$ENDIF}
begin
{$IFDEF STRING_IS_IMMUTABLE}
LSB := TIdStringBuilder.Create(S);
L := LSB.Length;
I := 0;
while I < L do begin
I := FindCharInSB(LSB, XQuote, I);
if I = -1 then begin
Break;
end;
LSB.Remove(I, 1);
Dec(L);
if I >= L then begin
Break;
end;
if LSB[I] = 'a' then begin
LSB[I] := XDelim;
end;
Inc(I);
end;
Result := LSB.ToString;
{$ELSE}
Result := S;
L := Length(Result);
I := 1;
while I <= L do begin
I := PosIdx(XQuote, Result, I);
if I = 0 then begin
Break;
end;
IdDelete(Result, I, 1);
Dec(L);
if I > L then begin
Break;
end;
if Result[I] = 'a' then begin
Result[I] := XDelim;
end;
Inc(I);
end;
{$ENDIF}
end;
procedure ExtractCTCPs(var AText: String; CTCPs: TStrings);
var
LTmp: String;
I, J, K: Integer;
begin
I := 1;
repeat
J := PosIdx(XDelim, AText, I);
if J = 0 then begin
Break;
end;
K := PosIdx(XDelim, AText, J+1);
if K = 0 then begin
Break;
end;
LTmp := Copy(AText, J+1, K-J-1);
LTmp := CTCPUnquote(LTmp);
CTCPs.Add(LTmp);
IdDelete(AText, J, (K-J)+1);
I := J;
until False;
end;
type
TIdIRCCommandHandler = class(TIdCommandHandler)
public
procedure DoParseParams(AUnparsedParams: string; AParams: TStrings); override;
end;
procedure TIdIRCCommandHandler.DoParseParams(AUnparsedParams: string; AParams: TStrings);
begin
AParams.Clear;
while AUnparsedParams <> '' do begin
AParams.Add(FetchIRCParam(AUnparsedParams));
end;
end;
function TIdIRC.GetCmdHandlerClass: TIdCommandHandlerClass;
begin
Result := TIdIRCCommandHandler;
end;
procedure TIdIRC.InitComponent;
begin
inherited InitComponent;
//
FReplies := TIdIRCReplies.Create;
Port := IdPORT_IRC;
FUserMode := [];
// 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.
CommandHandlers.PerformReplies := False;
// RLebeau 3/11/08: most of the command handlers should parse parameters by default
CommandHandlers.ParseParamsDefault := True;
if not IsDesignTime then begin
AssignIRCClientCommands;
end;
end;
destructor TIdIRC.Destroy;
begin
FreeAndNil(FReplies);
FreeAndNil(FBans);
FreeAndNil(FExcepts);
FreeAndNil(FInvites);
FreeAndNil(FLinks);
FreeAndNil(FMotd);
FreeAndNil(FNames);
FreeAndNil(FWho);
FreeAndNil(FWhoIs);
FreeAndNil(FWhoWas);
FreeAndNil(FSvrList);
FreeAndNil(FUsers);
inherited Destroy;
end;
function TIdIRC.GetUserMode: String;
const
IdIRCUserModeChars: array[TIdIRCUserMode] of Char = ('a', 'i', 'w', 'r', 'o', 'O', 's'); {do not localize}
var
i: TIdIRCUserMode;
begin
if FUserMode <> [] then
begin
Result := '+';
for i := amAway to amReceiveServerNotices do begin
if i in FUserMode then begin
Result := Result + IdIRCUserModeChars[i];
end;
end;
end else begin
Result := '0';
end;
end;
procedure TIdIRC.Connect;
begin
// I doubt that there is explicit SSL support in the IRC protocol
if (IOHandler is TIdSSLIOHandlerSocketBase) then begin
(IOHandler as TIdSSLIOHandlerSocketBase).PassThrough := False;
end;
inherited Connect;
//
try
FAltNickUsed := False;
if FPassword <> '' then begin
Raw(IndyFormat('PASS %s', [FPassword])); {do not localize}
end;
SetNickname(FNickname);
SetUsername(FUsername);
except
on E: EIdSocketError do begin
inherited Disconnect;
IndyRaiseOuterException(EIdIRCError.Create(RSIRCCannotConnect));
end;
end;
end;
procedure TIdIRC.Disconnect(const AReason: String = '');
begin
try
Raw(IndyFormat('QUIT :%s', [AReason])); {do not localize}
finally
inherited Disconnect;
end;
end;
procedure TIdIRC.Raw(const ALine: String);
begin
if Connected then begin
if Assigned(FOnRaw) then begin
FOnRaw(nil, False, ALine);
end;
IOHandler.WriteLn(IRCQuote(ALine));
end;
end;
procedure TIdIRC.AssignIRCClientCommands;
var
LCommandHandler: TIdCommandHandler;
begin
{ Text commands }
//PRIVMSG Nickname/#channel :message
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'PRIVMSG'; {do not localize}
LCommandHandler.OnCommand := CommandPRIVMSG;
LCommandHandler.ParseParams := False;
//NOTICE Nickname/#channel :message
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'NOTICE'; {do not localize}
LCommandHandler.OnCommand := CommandNOTICE;
LCommandHandler.ParseParams := False;
//JOIN #channel
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'JOIN'; {do not localize}
LCommandHandler.OnCommand := CommandJOIN;
//PART #channel
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'PART'; {do not localize}
LCommandHandler.OnCommand := CommandPART;
//KICK #channel target :reason
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'KICK'; {do not localize}
LCommandHandler.OnCommand := CommandKICK;
//MODE Nickname/#channel +/-modes parameters...
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'MODE'; {do not localize}
LCommandHandler.OnCommand := CommandMODE;
LCommandHandler.ParseParams := False;
//NICK newNickname
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'NICK'; {do not localize}
LCommandHandler.OnCommand := CommandNICK;
//QUIT :reason
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'QUIT'; {do not localize}
LCommandHandler.OnCommand := CommandQUIT;
//SQUIT server :reason
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'SQUIT'; {do not localize}
LCommandHandler.OnCommand := CommandSQUIT;
//INVITE Nickname :#channel
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'INVITE'; {do not localize}
LCommandHandler.OnCommand := CommandINVITE;
//KILL Nickname :reason
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'KILL'; {do not localize}
LCommandHandler.OnCommand := CommandKILL;
//PING server
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'PING'; {do not localize}
LCommandHandler.OnCommand := CommandPING;
//WALLOPS :message
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'WALLOPS'; {do not localize}
LCommandHandler.OnCommand := CommandWALLOPS;
LCommandHandler.ParseParams := False;
//TOPIC
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'TOPIC'; {do not localize}
LCommandHandler.OnCommand := CommandTOPIC;
//ERROR message
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := 'ERROR'; {do not localize}
LCommandHandler.OnCommand := CommandERROR;
LCommandHandler.ParseParams := False;
{ Numeric commands, refer to http://www.alien.net.au/irc/irc2numerics.html }
//RPL_WELCOME
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '001'; {do not localize}
LCommandHandler.OnCommand := CommandWELCOME;
LCommandHandler.ParseParams := False;
//RPL_YOURHOST
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '002'; {do not localize}
LCommandHandler.OnCommand := CommandYOURHOST;
//RPL_CREATED
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '003'; {do not localize}
LCommandHandler.OnCommand := CommandCREATED;
//RPL_MYINFO
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '004'; {do not localize}
LCommandHandler.OnCommand := CommandMYINFO;
LCommandHandler.ParseParams := False;
//RPL_BOUNCE (deprecated), RPL_ISUPPORT (new)
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '005'; {do not localize}
//LCommandHandler.OnCommand := CommandBOUNCE; // deprecated
LCommandHandler.OnCommand := CommandISUPPORT;
{ TODO:
008 RPL_SNOMASK ircu Server notice mask (hex)
009 RPL_STATMEMTOT ircu
014 RPL_YOURCOOKIE Hybrid?
042 RPL_YOURID IRCnet
043 RPL_SAVENICK IRCnet :<info> Sent to the client when their nickname was forced to change due to a collision
050 RPL_ATTEMPTINGJUNC aircd
051 RPL_ATTEMPTINGREROUTE aircd
200 RPL_TRACELINK RFC1459 Link <version>[.<debug_level>] <destination> <next_server> [V<protocol_version> <link_uptime_in_seconds> <backstream_sendq> <upstream_sendq>] See RFC
201 RPL_TRACECONNECTING RFC1459 Try. <class> <server> See RFC
202 RPL_TRACEHANDSHAKE RFC1459 H.S. <class> <server> See RFC
203 RPL_TRACEUNKNOWN RFC1459 ???? <class> [<connection_address>] See RFC
204 RPL_TRACEOPERATOR RFC1459 Oper <class> <nick> See RFC
205 RPL_TRACEUSER RFC1459 User <class> <nick> See RFC
206 RPL_TRACESERVER RFC1459 Serv <class> <int>S <int>C <server> <nick!user|*!*>@<host|server> [V<protocol_version>] See RFC
207 RPL_TRACESERVICE RFC2812 Service <class> <name> <type> <active_type> See RFC
208 RPL_TRACENEWTYPE RFC1459 <newtype> 0 <client_name> See RFC
209 RPL_TRACECLASS RFC2812 Class <class> <count> See RFC
210 RPL_TRACERECONNECT RFC2812
210 RPL_STATS aircd Used instead of having multiple stats numerics
211 RPL_STATSLINKINFO RFC1459 <linkname> <sendq> <sent_msgs> <sent_bytes> <recvd_msgs> <rcvd_bytes> <time_open> Reply to STATS (See RFC)
212 RPL_STATSCOMMANDS RFC1459 <command> <count> [<byte_count> <remote_count>] Reply to STATS (See RFC)
213 RPL_STATSCLINE RFC1459 C <host> * <name> <port> <class> Reply to STATS (See RFC)
214 RPL_STATSNLINE RFC1459 N <host> * <name> <port> <class> Reply to STATS (See RFC), Also known as RPL_STATSOLDNLINE (ircu, Unreal)
215 RPL_STATSILINE RFC1459 I <host> * <host> <port> <class> Reply to STATS (See RFC)
216 RPL_STATSKLINE RFC1459 K <host> * <username> <port> <class> Reply to STATS (See RFC)
217 RPL_STATSQLINE RFC1459
217 RPL_STATSPLINE ircu
218 RPL_STATSYLINE
}
// RPL_BOUNCE (new)
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '010'; {do not localize}
LCommandHandler.OnCommand := CommandBOUNCE;
//RPL_ENDOFSTATS
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '219'; {do not localize}
LCommandHandler.OnCommand := CommandENDOFSTATS;
{TODO:
221 RPL_UMODEIS RFC1459 <user_modes> [<user_mode_params>] Information about a user's own modes. Some daemons have extended the mode command and certain modes take parameters (like channel modes).
}
//RPL_SERVLIST
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '234'; {do not localize}
LCommandHandler.OnCommand := CommandSERVLIST;
//RPL_SERVLISTEND
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '235'; {do not localize}
LCommandHandler.OnCommand := CommandSERVLISTEND;
{TODO:
236 RPL_STATSVERBOSE ircu Verbose server list?
237 RPL_STATSENGINE ircu Engine name?
239 RPL_STATSIAUTH IRCnet
241 RPL_STATSLLINE RFC1459 L <hostmask> * <servername> <maxdepth> Reply to STATS (See RFC)
242 RPL_STATSUPTIME RFC1459 :Server Up <days> days <hours>:<minutes>:<seconds> Reply to STATS (See RFC)
243 RPL_STATSOLINE RFC1459 O <hostmask> * <nick> [:<info>] Reply to STATS (See RFC); The info field is an extension found in some IRC daemons, which returns info such as an e-mail address or the name/job of an operator
244 RPL_STATSHLINE RFC1459 H <hostmask> * <servername> Reply to STATS (See RFC)
245 RPL_STATSSLINE Bahamut, IRCnet, Hybrid
250 RPL_STATSCONN ircu, Unreal
251 RPL_LUSERCLIENT RFC1459 :There are <int> users and <int> invisible on <int> servers Reply to LUSERS command, other versions exist (eg. RFC2812); Text may vary.
252 RPL_LUSEROP RFC1459 <int> :<info> Reply to LUSERS command - Number of IRC operators online
253 RPL_LUSERUNKNOWN RFC1459 <int> :<info> Reply to LUSERS command - Number of unknown/unregistered connections
254 RPL_LUSERCHANNELS RFC1459 <int> :<info> Reply to LUSERS command - Number of channels formed
255 RPL_LUSERME RFC1459 :I have <int> clients and <int> servers Reply to LUSERS command - Information about local connections; Text may vary.
256 RPL_ADMINME RFC1459 <server> :<info> Start of an RPL_ADMIN* reply. In practise, the server parameter is often never given, and instead the info field contains the text 'Administrative info about <server>'. Newer daemons seem to follow the RFC and output the server's hostname in the 'server' parameter, but also output the server name in the text as per traditional daemons.
257 RPL_ADMINLOC1 RFC1459 :<admin_location> Reply to ADMIN command (Location, first line)
258 RPL_ADMINLOC2 RFC1459 :<admin_location> Reply to ADMIN command (Location, second line)
259 RPL_ADMINEMAIL RFC1459 :<email_address> Reply to ADMIN command (E-mail address of administrator)
261 RPL_TRACELOG RFC1459 File <logfile> <debug_level> See RFC
263 RPL_TRYAGAIN RFC2812 <command> :<info> When a server drops a command without processing it, it MUST use this reply. Also known as RPL_LOAD_THROTTLED and RPL_LOAD2HI, I'm presuming they do the same thing.
265 RPL_LOCALUSERS aircd, Hybrid, Hybrid, Bahamut Also known as RPL_CURRENT_LOCAL
266 RPL_GLOBALUSERS aircd, Hybrid, Hybrid, Bahamut Also known as RPL_CURRENT_GLOBAL
267 RPL_START_NETSTAT aircd
268 RPL_NETSTAT aircd
269 RPL_END_NETSTAT aircd
270 RPL_PRIVS ircu
271 RPL_SILELIST ircu
272 RPL_ENDOFSILELIST ircu
273 RPL_NOTIFY aircd
276 RPL_VCHANEXIST
277 RPL_VCHANLIST
278 RPL_VCHANHELP
280 RPL_GLIST ircu
296 RPL_CHANINFO_KICKS aircd
299 RPL_END_CHANINFO aircd
300 RPL_NONE RFC1459 Dummy reply, supposedly only used for debugging/testing new features, however has appeared in production daemons.
}
//RPL_AWAY
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '301'; {do not localize}
LCommandHandler.OnCommand := CommandAWAY;
//RPL_USERHOST
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '302'; {do not localize}
LCommandHandler.OnCommand := CommandUSERHOST;
LCommandHandler.ParseParams := False;
//RPL_ISON
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '303'; {do not localize}
LCommandHandler.OnCommand := CommandISON;
//RPL_UNAWAY
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '305'; {do not localize}
LCommandHandler.OnCommand := CommandAWAY;
//RPL_NOWAWAY
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '306'; {do not localize}
LCommandHandler.OnCommand := CommandAWAY;
//RPL_WHOISUSER
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '311'; {do not localize}
LCommandHandler.OnCommand := CommandWHOIS;
//RPL_WHOISSERVER
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '312'; {do not localize}
LCommandHandler.OnCommand := CommandWHOIS;
//RPL_WHOISOPERATOR
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '313'; {do not localize}
LCommandHandler.OnCommand := CommandWHOIS;
//RPL_WHOWASUSER
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '314';
LCommandHandler.OnCommand := CommandWHOWAS;
//RPL_ENDOFWHO
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '315'; {do not localize}
LCommandHandler.OnCommand := CommandENDOFWHO;
//RPL_WHOISIDLE
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '317'; {do not localize}
LCommandHandler.OnCommand := CommandWHOIS;
//RPL_ENDOFWHOIS
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '318'; {do not localize}
LCommandHandler.OnCommand := CommandENDOFWHOIS;
//RPL_WHOISCHANNELS
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '319'; {do not localize}
LCommandHandler.OnCommand := CommandWHOIS;
{TODO:
320 RPL_WHOISVIRT AustHex
320 RPL_WHOIS_HIDDEN Anothernet
320 RPL_WHOISSPECIAL Unreal
}
//RPL_LISTSTART
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '321'; {do not localize}
LCommandHandler.OnCommand := CommandLISTSTART;
//RPL_LIST
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '322'; {do not localize}
LCommandHandler.OnCommand := CommandLIST;
//RPL_LISTEND
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '323'; {do not localize}
LCommandHandler.OnCommand := CommandLISTEND;
//RPL_CHANMODEIS
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '324'; {do not localize}
LCommandHandler.OnCommand := CommandCHANMODE;
//RPL_UNIQOPIS
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '325'; {do not localize}
//LCommandHandler.OnCommand := CommandUNIQOP;
{TODO:
326 RPL_NOCHANPASS
327 RPL_CHPASSUNKNOWN
328 RPL_CHANNEL_URL Bahamut, AustHex
329 RPL_CREATIONTIME Bahamut
}
//RPL_NOTOPIC
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '331'; {do not localize}
LCommandHandler.OnCommand := CommandTOPIC;
//RPL_TOPIC
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '332';
LCommandHandler.OnCommand := CommandTOPIC;
{TODO:
333 RPL_TOPICWHOTIME ircu
339 RPL_BADCHANPASS
340 RPL_USERIP ircu
}
//RPL_INVITING
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '341'; {do not localize}
LCommandHandler.OnCommand := CommandINVITING;
//RPL_SUMMONING
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '342'; {do not localize}
LCommandHandler.OnCommand := CommandSUMMONING;
{TODO:
345 RPL_INVITED GameSurge <channel> <user being invited> <user issuing invite> :<user being invited> has been invited by <user issuing invite> Sent to users on a channel when an INVITE command has been issued
}
//RPL_INVITELIST
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '346'; {do not localize}
LCommandHandler.OnCommand := CommandINVITELIST;
//RPL_ENDOFINVITELIST
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '347'; {do not localize}
LCommandHandler.OnCommand := CommandENDOFINVITELIST;
//RPL_EXCEPTLIST
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '348'; {do not localize}
LCommandHandler.OnCommand := CommandEXCEPTLIST;
//RPL_ENDOFEXCEPTLIST
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '349'; {do not localize}
LCommandHandler.OnCommand := CommandENDOFEXCEPTLIST;
//RPL_VERSION
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '351'; {do not localize}
LCommandHandler.OnCommand := CommandVERSION;
//RPL_WHOREPLY
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '352'; {do not localize}
LCommandHandler.OnCommand := CommandWHOREPLY;
//RPL_NAMEREPLY
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '353'; {do not localize}
LCommandHandler.OnCommand := CommandNAMEREPLY;
{ TODO:
354 RPL_WHOSPCRPL ircu Reply to WHO, however it is a 'special' reply because it is returned using a non-standard (non-RFC1459) format. The format is dictated by the command given by the user, and can vary widely. When this is used, the WHO command was invoked in its 'extended' form, as announced by the 'WHOX' ISUPPORT tag.
355 RPL_NAMREPLY_ QuakeNet ( '=' / '*' / '@' ) <channel> ' ' : [ '@' / '+' ] <nick> *( ' ' [ '@' / '+' ] <nick> ) Reply to the "NAMES -d" command - used to show invisible users (when the channel is set +D, QuakeNet relative). The proper define name for this numeric is unknown at this time Also see #353.
}
//RPL_LINKS
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '364'; {do not localize}
LCommandHandler.OnCommand := CommandLINKS;
//RPL_ENDOFLINKS
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '365'; {do not localize}
LCommandHandler.OnCommand := CommandENDOFLINKS;
//RPL_ENDOFNAMES
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '366'; {do not localize}
LCommandHandler.OnCommand := CommandENDOFNAMES;
// RPL_BANLIST
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '367'; {do not localize}
LCommandHandler.OnCommand := CommandBANLIST;
//RPL_ENDOFBANLIST
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '368'; {do not localize}
LCommandHandler.OnCommand := CommandENDOFBANLIST;
//RPL_ENDOFWHOWAS
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '369'; {do not localize}
LCommandHandler.OnCommand := CommandENDOFWHOWAS;
//RPL_INFO
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '371'; {do not localize}
LCommandHandler.OnCommand := CommandINFO;
//RPL_MOTD
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '372'; {do not localize}
LCommandHandler.OnCommand := CommandMOTD;
//RPL_ENDOFINFO
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '374'; {do not localize}
LCommandHandler.OnCommand := CommandENDOFINFO;
LCommandHandler.ParseParams := False;
//RPL_MOTDSTART
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '375'; {do not localize}
LCommandHandler.OnCommand := CommandMOTD;
//RPL_ENDOFMOTD
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '376'; {do not localize}
LCommandHandler.OnCommand := CommandENDOFMOTD;
//RPL_YOUREOPER
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '381'; {do not localize}
//LCommandHandler.OnCommand := CommandYOUAREOPER;
//RPL_REHASHING
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '382'; {do not localize}
LCommandHandler.OnCommand := CommandREHASHING;
//RPL_YOUARESERVICE
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '383'; {do not localize}
LCommandHandler.OnCommand := CommandSERVICE;
{TODO:
385 RPL_NOTOPERANYMORE AustHex, Hybrid, Unreal
388 RPL_ALIST Unreal
389 RPL_ENDOFALIST Unreal
}
//RPL_TIME
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '391'; {do not localize}
LCommandHandler.OnCommand := CommandTIME;
//RPL_USERSSTART
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '392'; {do not localize}
LCommandHandler.OnCommand := CommandUSERSSTART;
//RPL_USERS
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '393'; {do not localize}
LCommandHandler.OnCommand := CommandUSERS;
//RPL_ENDOFUSERS
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '394'; {do not localize}
LCommandHandler.OnCommand := CommandENDOFUSERS;
//RPL_NOUSERS
LCommandHandler := CommandHandlers.Add;
LCommandHandler.Command := '395'; {do not localize}
LCommandHandler.OnCommand := CommandUSERS;
//ERR_NICKNAMEINUSE
LCommandHandler := CommandHandlers.Add;
// 433 ERR_NICKNAMEINUSE RFC1459 <nick> :<reason>
// Returned by the NICK command when the given nickname is already in use
LCommandHandler.Command := '433'; {do not localize}
LCommandHandler.OnCommand := CommandNICKINUSE;
{TODO:
396 RPL_HOSTHIDDEN Undernet Reply to a user when user mode +x (host masking) was set successfully
400 ERR_UNKNOWNERROR <command> [<?>] :<info> Sent when an error occured executing a command, but it is not specifically known why the command could not be executed.
401 ERR_NOSUCHNICK RFC1459 <nick> :<reason> Used to indicate the nickname parameter supplied to a command is currently unused
402 ERR_NOSUCHSERVER RFC1459 <server> :<reason> Used to indicate the server name given currently doesn't exist
403 ERR_NOSUCHCHANNEL RFC1459 <channel> :<reason> Used to indicate the given channel name is invalid, or does not exist
404 ERR_CANNOTSENDTOCHAN RFC1459 <channel> :<reason> Sent to a user who does not have the rights to send a message to a channel
405 ERR_TOOMANYCHANNELS RFC1459 <channel> :<reason> Sent to a user when they have joined the maximum number of allowed channels and they tried to join another channel
406 ERR_WASNOSUCHNICK RFC1459 <nick> :<reason> Returned by WHOWAS to indicate there was no history information for a given nickname
407 ERR_TOOMANYTARGETS RFC1459 <target> :<reason> The given target(s) for a command are ambiguous in that they relate to too many targets
408 ERR_NOSUCHSERVICE RFC2812 <service_name> :<reason> Returned to a client which is attempting to send an SQUERY (or other message) to a service which does not exist
409 ERR_NOORIGIN RFC1459 :<reason> PING or PONG message missing the originator parameter which is required since these commands must work without valid prefixes
411 ERR_NORECIPIENT RFC1459 :<reason> Returned when no recipient is given with a command
412 ERR_NOTEXTTOSEND RFC1459 :<reason> Returned when NOTICE/PRIVMSG is used with no message given
413 ERR_NOTOPLEVEL RFC1459 <mask> :<reason> Used when a message is being sent to a mask without being limited to a top-level domain (i.e. * instead of *.au)
414 ERR_WILDTOPLEVEL RFC1459 <mask> :<reason> Used when a message is being sent to a mask with a wild-card for a top level domain (i.e. *.*)
415 ERR_BADMASK RFC2812 <mask> :<reason> Used when a message is being sent to a mask with an invalid syntax
416 ERR_TOOMANYMATCHES IRCnet <command> [<mask>] :<info> Returned when too many matches have been found for a command and the output has been truncated. An example would be the WHO command, where by the mask '*' would match everyone on the network! Ouch!
416 ERR_QUERYTOOLONG ircu Same as ERR_TOOMANYMATCHES
419 ERR_LENGTHTRUNCATED aircd
421 ERR_UNKNOWNCOMMAND RFC1459 <command> :<reason> Returned when the given command is unknown to the server (or hidden because of lack of access rights)
422 ERR_NOMOTD RFC1459 :<reason> Sent when there is no MOTD to send the client
423 ERR_NOADMININFO RFC1459 <server> :<reason> Returned by a server in response to an ADMIN request when no information is available. RFC1459 mentions this in the list of numerics. While it's not listed as a valid reply in section 4.3.7 ('Admin command'), it's confirmed to exist in the real world.
424 ERR_FILEERROR RFC1459 :<reason> Generic error message used to report a failed file operation during the processing of a command
425 ERR_NOOPERMOTD Unreal
429 ERR_TOOMANYAWAY Bahamut
430 ERR_EVENTNICKCHANGE AustHex Returned by NICK when the user is not allowed to change their nickname due to a channel event (channel mode +E)
431 ERR_NONICKNAMEGIVEN RFC1459 :<reason> Returned when a nickname parameter expected for a command isn't found
432 ERR_ERRONEUSNICKNAME RFC1459 <nick> :<reason> Returned after receiving a NICK message which contains a nickname which is considered invalid, such as it's reserved ('anonymous') or contains characters considered invalid for nicknames. This numeric is misspelt, but remains with this name for historical reasons :)
436 ERR_NICKCOLLISION RFC1459 <nick> :<reason> Returned by a server to a client when it detects a nickname collision
439 ERR_TARGETTOOFAST ircu Also known as many other things, RPL_INVTOOFAST, RPL_MSGTOOFAST etc
440 ERR_SERVICESDOWN Bahamut, Unreal
441 ERR_USERNOTINCHANNEL RFC1459 <nick> <channel> :<reason> Returned by the server to indicate that the target user of the command is not on the given channel
442 ERR_NOTONCHANNEL RFC1459 <channel> :<reason> Returned by the server whenever a client tries to perform a channel effecting command for which the client is not a member
443 ERR_USERONCHANNEL RFC1459 <nick> <channel> [:<reason>] Returned when a client tries to invite a user to a channel they're already on
444 ERR_NOLOGIN RFC1459 <user> :<reason> Returned by the SUMMON command if a given user was not logged in and could not be summoned
445 ERR_SUMMONDISABLED RFC1459 :<reason> Returned by SUMMON when it has been disabled or not implemented
446 ERR_USERSDISABLED RFC1459 :<reason> Returned by USERS when it has been disabled or not implemented
447 ERR_NONICKCHANGE Unreal
449 ERR_NOTIMPLEMENTED Undernet Unspecified Returned when a requested feature is not implemented (and cannot be completed)
451 ERR_NOTREGISTERED RFC1459 :<reason> Returned by the server to indicate that the client must be registered before the server will allow it to be parsed in detail
452 ERR_IDCOLLISION
453 ERR_NICKLOST
455 ERR_HOSTILENAME Unreal
456 ERR_ACCEPTFULL
457 ERR_ACCEPTEXIST
458 ERR_ACCEPTNOT
459 ERR_NOHIDING Unreal Not allowed to become an invisible operator?
460 ERR_NOTFORHALFOPS Unreal
461 ERR_NEEDMOREPARAMS RFC1459 <command> :<reason> Returned by the server by any command which requires more parameters than the number of parameters given
462 ERR_ALREADYREGISTERED RFC1459 :<reason> Returned by the server to any link which attempts to register again
463 ERR_NOPERMFORHOST RFC1459 :<reason> Returned to a client which attempts to register with a server which has been configured to refuse connections from the client's host
464 ERR_PASSWDMISMATCH RFC1459 :<reason> Returned by the PASS command to indicate the given password was required and was either not given or was incorrect
465 ERR_YOUREBANNEDCREEP RFC1459 :<reason> Returned to a client after an attempt to register on a server configured to ban connections from that client
466 ERR_YOUWILLBEBANNED RFC1459 Sent by a server to a user to inform that access to the server will soon be denied
467 ERR_KEYSET RFC1459 <channel> :<reason> Returned when the channel key for a channel has already been set
468 ERR_INVALIDUSERNAME ircu
468 ERR_ONLYSERVERSCANCHANGE Bahamut, Unreal
469 ERR_LINKSET Unreal
470 ERR_LINKCHANNEL Unreal
470 ERR_KICKEDFROMCHAN aircd
471 ERR_CHANNELISFULL RFC1459 <channel> :<reason> Returned when attempting to join a channel which is set +l and is already full
472 ERR_UNKNOWNMODE RFC1459 <char> :<reason> Returned when a given mode is unknown
473 ERR_INVITEONLYCHAN RFC1459 <channel> :<reason> Returned when attempting to join a channel which is invite only without an invitation
474 ERR_BANNEDFROMCHAN RFC1459 <channel> :<reason> Returned when attempting to join a channel a user is banned from
475 ERR_BADCHANNELKEY RFC1459 <channel> :<reason> Returned when attempting to join a key-locked channel either without a key or with the wrong key
476 ERR_BADCHANMASK RFC2812 <channel> :<reason> The given channel mask was invalid
478 ERR_BANLISTFULL RFC2812 <channel> <char> :<reason> Returned when a channel access list (i.e. ban list etc) is full and cannot be added to
479 ERR_BADCHANNAME Hybrid
479 ERR_LINKFAIL Unreal
481 ERR_NOPRIVILEGES RFC1459 :<reason> Returned by any command requiring special privileges (eg. IRC operator) to indicate the operation was unsuccessful
482 ERR_CHANOPRIVSNEEDED RFC1459 <channel> :<reason> Returned by any command requiring special channel privileges (eg. channel operator) to indicate the operation was unsuccessful
483 ERR_CANTKILLSERVER RFC1459 :<reason> Returned by KILL to anyone who tries to kill a server
485 ERR_UNIQOPRIVSNEEDED RFC2812 :<reason> Any mode requiring 'channel creator' privileges returns this error if the client is attempting to use it while not a channel creator on the given channel
488 ERR_TSLESSCHAN IRCnet
491 ERR_NOOPERHOST RFC1459 :<reason> Returned by OPER to a client who cannot become an IRC operator because the server has been configured to disallow the client's host
493 ERR_NOFEATURE ircu
494 ERR_BADFEATURE ircu
495 ERR_BADLOGTYPE ircu
496 ERR_BADLOGSYS ircu
497 ERR_BADLOGVALUE ircu
498 ERR_ISOPERLCHAN ircu
499 ERR_CHANOWNPRIVNEEDED Unreal Works just like ERR_CHANOPRIVSNEEDED except it indicates that owner status (+q) is needed. Also see #482.
501 ERR_UMODEUNKNOWNFLAG RFC1459 :<reason> Returned by the server to indicate that a MODE message was sent with a nickname parameter and that the mode flag sent was not recognised
502 ERR_USERSDONTMATCH RFC1459 :<reason> Error sent to any user trying to view or change the user mode for a user other than themselves
503 ERR_GHOSTEDCLIENT Hybrid
504 ERR_USERNOTONSERV
511 ERR_SILELISTFULL ircu
512 ERR_TOOMANYWATCH Bahamut Also known as ERR_NOTIFYFULL (aircd), I presume they are the same
513 ERR_BADPING ircu Also known as ERR_NEEDPONG (Unreal/Ultimate) for use during registration, however it's not used in Unreal (and might not be used in Ultimate either).
515 ERR_BADEXPIRE ircu
516 ERR_DONTCHEAT ircu
517 ERR_DISABLED ircu <command> :<info/reason>
522 ERR_WHOSYNTAX Bahamut
523 ERR_WHOLIMEXCEED Bahamut
525 ERR_REMOTEPFX CAPAB USERCMDPFX <nickname> :<reason> Proposed.
526 ERR_PFXUNROUTABLE CAPAB USERCMDPFX <nickname> :<reason> Proposed.
550 ERR_BADHOSTMASK QuakeNet
551 ERR_HOSTUNAVAIL QuakeNet
552 ERR_USINGSLINE QuakeNet
600 RPL_LOGON Bahamut, Unreal
601 RPL_LOGOFF Bahamut, Unreal
602 RPL_WATCHOFF Bahamut, Unreal
603 RPL_WATCHSTAT Bahamut, Unreal
604 RPL_NOWON Bahamut, Unreal
605 RPL_NOWOFF Bahamut, Unreal
606 RPL_WATCHLIST Bahamut, Unreal
607 RPL_ENDOFWATCHLIST Bahamut, Unreal
608 RPL_WATCHCLEAR Ultimate
611 RPL_ISLOCOP Ultimate
612 RPL_ISNOTOPER Ultimate
613 RPL_ENDOFISOPER Ultimate
618 RPL_DCCLIST
624 RPL_OMOTDSTART Ultimate
625 RPL_OMOTD Ultimate
626 RPL_ENDOFO Ultimate
630 RPL_SETTINGS Ultimate
631 RPL_ENDOFSETTINGS Ultimate
660 RPL_TRACEROUTE_HOP KineIRCd <target> <hop#> [<address> [<hostname> | '*'] <usec_ping>] Returned from the TRACEROUTE IRC-Op command when tracerouting a host
661 RPL_TRACEROUTE_START KineIRCd <target> <target_FQDN> <target_address> <max_hops> Start of an RPL_TRACEROUTE_HOP list
662 RPL_MODECHANGEWARN KineIRCd ['+' | '-']<mode_char> :<warning> Plain text warning to the user about turning on or off a user mode. If no '+' or '-' prefix is used for the mode char, '+' is presumed.
663 RPL_CHANREDIR KineIRCd <old_chan> <new_chan> :<info> Used to notify the client upon JOIN that they are joining a different channel than expected because the IRC Daemon has been set up to map the channel they attempted to join to the channel they eventually will join.
664 RPL_SERVMODEIS KineIRCd <server> <modes> <parameters>.. Reply to MODE <servername>. KineIRCd supports server modes to simplify configuration of servers; Similar to RPL_CHANNELMODEIS
665 RPL_OTHERUMODEIS KineIRCd <nickname> <modes> Reply to MODE <nickname> to return the user-modes of another user to help troubleshoot connections, etc. Similar to RPL_UMODEIS, however including the target
666 RPL_ENDOF_GENERIC KineIRCd <command> [<parameter> ...] :<info> Generic response for new lists to save numerics.
670 RPL_WHOWASDETAILS KineIRCd <nick> <type> :<information> Returned by WHOWAS to return extended information (if available). The type field is a number indication what kind of information.
671 RPL_WHOISSECURE KineIRCd <nick> <type> [:<info>] Reply to WHOIS command - Returned if the target is connected securely, eg. type may be TLSv1, or SSLv2 etc. If the type is unknown, a '*' may be used.
672 RPL_UNKNOWNMODES Ithildin <modes> :<info> Returns a full list of modes that are unknown when a client issues a MODE command (rather than one numeric per mode)
673 RPL_CANNOTSETMODES Ithildin <modes> :<info> Returns a full list of modes that cannot be set when a client issues a MODE command
678 RPL_LUSERSTAFF KineIRCd <staff_online_count> :<info> Reply to LUSERS command - Number of network staff (or 'helpers') online (differs from Local/Global operators). Similar format to RPL_LUSEROP
679 RPL_TIMEONSERVERIS KineIRCd <seconds> [<nanoseconds> | '0'] <timezone> <flags> :<info> Optionally sent upon connection, and/or sent as a reply to the TIME command. This returns the time on the server in a uniform manner. The seconds (and optionally nanoseconds) is the time since the UNIX Epoch, and is used since many existing timestamps in the IRC-2 protocol are done this way (i.e. ban lists). The timezone is hours and minutes each of Greenwich ('[+/-]HHMM'). Since all timestamps sent from the server are in a similar format, this numeric is designed to give clients the ability to provide accurate timestamps to their users.
682 RPL_NETWORKS KineIRCd <name> <through_name> <hops> :<info> A reply to the NETWORKS command when requesting a list of known networks (within the IIRC domain).
687 RPL_YOURLANGUAGEIS KineIRCd <code(s)> :<info> Reply to the LANGUAGE command, informing the client of the language(s) it has set
688 RPL_LANGUAGE KineIRCd <code> <revision> <maintainer> <flags> * :<info> A language reply to LANGUAGE when requesting a list of known languages
689 RPL_WHOISSTAFF KineIRCd :<info> The user is a staff member. The information may explain the user's job role, or simply state that they are a part of the network staff. Staff members are not IRC operators, but rather people who have special access in association with network services. KineIRCd uses this numeric instead of the existing numerics due to the overwhelming number of conflicts.
690 RPL_WHOISLANGUAGE KineIRCd <nick> <language codes> Reply to WHOIS command - A list of languages someone can speak. The language codes are comma delimitered.
702 RPL_MODLIST RatBox <?> 0x<?> <?> <?> Output from the MODLIST command
703 RPL_ENDOFMODLIST RatBox :<text> Terminates MODLIST output
704 RPL_HELPSTART RatBox <command> :<text> Start of HELP command output
705 RPL_HELPTXT RatBox <command> :<text> Output from HELP command
706 RPL_ENDOFHELP RatBox <command> :<text> End of HELP command output
708 RPL_ETRACEFULL RatBox <?> <?> <?> <?> <?> <?> <?> :<?> Output from 'extended' trace
709 RPL_ETRACE RatBox <?> <?> <?> <?> <?> <?> :<?> Output from 'extended' trace
710 RPL_KNOCK RatBox <channel> <nick>!<user>@<host> :<text> Message delivered using KNOCK command
711 RPL_KNOCKDLVR RatBox <channel> :<text> Message returned from using KNOCK command
712 ERR_TOOMANYKNOCK RatBox <channel> :<text> Message returned when too many KNOCKs for a channel have been sent by a user
713 ERR_CHANOPEN RatBox <channel> :<text> Message returned from KNOCK when the channel can be freely joined by the user
714 ERR_KNOCKONCHAN RatBox <channel> :<text> Message returned from KNOCK when the user has used KNOCK on a channel they have already joined
715 ERR_KNOCKDISABLED RatBox :<text> Returned from KNOCK when the command has been disabled
716 RPL_TARGUMODEG RatBox <nick> :<info> Sent to indicate the given target is set +g (server-side ignore)
717 RPL_TARGNOTIFY RatBox <nick> :<info> Sent following a PRIVMSG/NOTICE to indicate the target has been notified of an attempt to talk to them while they are set +g
718 RPL_UMODEGMSG RatBox <nick> <user>@<host> :<info> Sent to a user who is +g to inform them that someone has attempted to talk to them (via PRIVMSG/NOTICE), and that they will need to be accepted (via the ACCEPT command) before being able to talk to them
720 RPL_OMOTDSTART RatBox :<text> IRC Operator MOTD header, sent upon OPER command
721 RPL_OMOTD RatBox :<text> IRC Operator MOTD text (repeated, usually)
722 RPL_ENDOFOMOTD RatBox :<text> IRC operator MOTD footer
723 ERR_NOPRIVS RatBox <command> :<text> Returned from an oper command when the IRC operator does not have the relevant operator privileges.
724 RPL_TESTMARK RatBox <nick>!<user>@<host> <?> <?> :<text> Reply from an oper command reporting how many users match a given user@host mask
725 RPL_TESTLINE RatBox <?> <?> <?> :<?> Reply from an oper command reporting relevant I/K lines that will match a given user@host
726 RPL_NOTESTLINE RatBox <?> :<text> Reply from oper command reporting no I/K lines match the given user@host
771 RPL_XINFO Ithildin Used to send 'eXtended info' to the client, a replacement for the STATS command to send a large variety of data and minimise numeric pollution.
773 RPL_XINFOSTART Ithildin Start of an RPL_XINFO list
774 RPL_XINFOEND Ithildin Termination of an RPL_XINFO list
972 ERR_CANNOTDOCOMMAND Unreal Works similarly to all of KineIRCd's CANNOT* numerics. This one indicates that a command could not be performed for an arbitrary reason. For example, a halfop trying to kick an op.
973 ERR_CANNOTCHANGEUMODE KineIRCd <mode_char> :<reason> Reply to MODE when a user cannot change a user mode
974 ERR_CANNOTCHANGECHANMODE KineIRCd <mode_char> :<reason> Reply to MODE when a user cannot change a channel mode
975 ERR_CANNOTCHANGESERVERMODE KineIRCd <mode_char> :<reason> Reply to MODE when a user cannot change a server mode
976 ERR_CANNOTSENDTONICK KineIRCd <nick> :<reason> Returned from NOTICE, PRIVMSG or other commands to notify the user that they cannot send a message to a particular client. Similar to ERR_CANNOTSENDTOCHAN. KineIRCd uses this in conjunction with user-mode +R to allow users to block people who are not identified to services (spam avoidance)
977 ERR_UNKNOWNSERVERMODE KineIRCd <modechar> :<info> Returned by MODE to inform the client they used an unknown server mode character.
979 ERR_SERVERMODELOCK KineIRCd <target> :<info> Returned by MODE to inform the client the server has been set mode +L by an administrator to stop server modes being changed
980 ERR_BADCHARENCODING KineIRCd <command> <charset> :<info> Returned by any command which may have had the given data modified because one or more glyphs were incorrectly encoded in the current charset (given). Such a use would be where an invalid UTF-8 sequence was given which may be considered insecure, or defines a character which is invalid within that context. For safety reasons, the invalid character is not returned to the client.
981 ERR_TOOMANYLANGUAGES KineIRCd <max_langs> :<info> Returned by the LANGUAGE command to tell the client they cannot set as many languages as they have requested. To assist the client, the maximum languages which can be set at one time is given, and the language settings are not changed.
982 ERR_NOLANGUAGE KineIRCd <language_code> :<info> Returned by the LANGUAGE command to tell the client it has specified an unknown language code.
983 ERR_TEXTTOOSHORT KineIRCd <command> :<info> Returned by any command requiring text (such as a message or a reason), which was not long enough to be considered valid. This was created initially to combat '/wallops foo' abuse, but is also used by DIE and RESTART commands to attempt to encourage meaningful reasons.
999 ERR_NUMERIC_ERR Bahamut
}
FCommandHandlers.OnBeforeCommandHandler := DoBeforeCmd;
end;
{ Command handlers }
procedure TIdIRC.DoBeforeCmd(ASender: TIdCommandHandlers; var AData: string; AContext: TIdContext);
var
LTmp: String;
begin
AData := IRCUnquote(AData);
// ":nickname!user@host"
if TextStartsWith(AData, ':') then begin
LTmp := Fetch(AData, ' ');
Delete(LTmp, 1, 1); // remove ':'
FSenderNick := Fetch(LTmp, '!');
FSenderHost := LTmp;
end else begin
FSenderNick := '';
FSenderHost := '';
end;
if Assigned(FOnRaw) then begin
FOnRaw(AContext, True, AData);
end;
end;
procedure TIdIRC.DoReplyUnknownCommand(AContext: TIdContext; ALine: string);
var
ACmdCode: Integer;
begin
ACmdCode := IndyStrToInt(Fetch(ALine, ' '), -1);
//
case ACmdCode of
6,
7:
begin
//MAP
end;
5,
400..424,
437..502:
begin
if Assigned(FOnServerError) then begin
OnServerError(AContext, ACmdCode, ALine);
end;
end;
431..432,
436:
begin
if Assigned(FOnNickError) then begin
OnNicknameError(AContext, ACmdCode);
end;
end;
end;
end;
procedure TIdIRC.CommandPRIVMSG(ASender: TIdCommand);
var
LTmp, LTarget, LData, LCTCP: String;
I: Integer;
CTCPList: TStringList;
begin
LTmp := ASender.UnparsedParams;
LTarget := FetchIRCParam(LTmp);
LData := FetchIRCParam(LTmp);
CTCPList := TStringList.Create;
try
ExtractCTCPs(LData, CTCPList);
if CTCPList.Count = 0 then begin
if Assigned(FOnPrivMessage) then begin
OnPrivateMessage(ASender.Context, FSenderNick, FSenderHost, LTarget, LData);
end;
end else
begin
if (LData <> '') and Assigned(FOnPrivMessage) then begin
OnPrivateMessage(ASender.Context, FSenderNick, FSenderHost, LTarget, LData);
end;
for I := 0 to CTCPList.Count - 1 do begin
LData := CTCPList[I];
LCTCP := Fetch(LData, ' ');
case PosInStrArray(LCTCP, IdIRCCTCP) of
0: { ACTION }
begin
{
if Assigned(FOnAction) then begin
FOnAction(ASender.Context, FSenderNick, FSenderHost, LTarget, LData);
end;
}
if Assigned(FOnCTCPQry) then begin
FOnCTCPQry(ASender.Context, FSenderNick, FSenderHost, LTarget, LCTCP, LData);
end;
// RLebeau: CTCP ACTION does not send a reply back
//CTCPReply(FSenderNick, 'ERRMSG', LCTCP +' ' + LData + ' unknown query'); {do not localize}
end;
1: { SOUND }
begin
{
if Assigned(FOnSound) then begin
FOnSound(ASender.Context, FSenderNick, FSenderHost, LTarget, LData);
end;
}
if Assigned(FOnCTCPQry) then begin
FOnCTCPQry(ASender.Context, FSenderNick, FSenderHost, LTarget, LCTCP, LData);
end;
CTCPReply(FSenderNick, 'ERRMSG', LCTCP +' ' + LData + ' unknown query'); {do not localize}
end;
2: { PING }
begin
{
LTmp := '';
if Assigned(FOnPing) then begin
FOnPing(ASender.Context, LTmp);
end;
if LTmp = '' then begin
LTmp := DateTimeToStr(Now);
end;
CTCPReply(FSenderNick, LCTCP, ':' + LTmp);
}
if Assigned(FOnCTCPQry) then begin
FOnCTCPQry(ASender.Context, FSenderNick, FSenderHost, LTarget, LCTCP, LData);
end;
// AWinkelsdorf 3/10/2010 ToDo: CTCP Ping might need a CTIME result but
// many clients do not send the required CTIME with the Ping Query...
CTCPReply(FSenderNick, LCTCP, DateTimeToStr(Now)); {do not localize}
end;
3: { FINGER }
begin
CTCPReply(FSenderNick, LCTCP, Replies.Finger); {do not localize}
end;
4: { USERINFO }
begin
CTCPReply(FSenderNick, LCTCP, Replies.UserInfo); {do not localize}
end;
5: { VERSION }
begin
CTCPReply(FSenderNick, LCTCP, Replies.Version); {do not localize}
end;
6: { CLIENTINFO }
begin
// TODO: add OnClientInfoQuery event to handle per-command queries
CTCPReply(FSenderNick, LCTCP, Replies.ClientInfo); {do not localize}
end;
7: { TIME }
begin
CTCPReply(FSenderNick, LCTCP, DateTimeToStr(Now));
end;
8: { ERROR }
begin
CTCPReply(FSenderNick, LCTCP, LData + ' No Error'); {do not localize}
end;
9: { DCC }
begin
ParseDCC(ASender.Context, LData);
end;
10: { SED }
begin
//ParseSED(AContext, LData);
if Assigned(FOnCTCPQry) then begin
FOnCTCPQry(ASender.Context, FSenderNick, FSenderHost, LTarget, LCTCP, LData);
end;
CTCPReply(FSenderNick, LCTCP, LData + ' unknown query'); {do not localize}
end;
11: { ERRMSG }
begin
CTCPReply(FSenderNick, LCTCP, LData + ' No Error'); {do not localize}
end;
else
begin
if Assigned(FOnCTCPQry) then begin
FOnCTCPQry(ASender.Context, FSenderNick, FSenderHost, LTarget, LCTCP, LData);
end;
CTCPReply(FSenderNick, LCTCP, LData + ' unknown query'); {do not localize}
end;
end;
end;
end;
finally
CTCPList.Free;
end;
end;
procedure TIdIRC.CommandNOTICE(ASender: TIdCommand);
var
LTmp, LTarget, LData, LCTCP: String;
I: Integer;
CTCPList: TStringList;
begin
LTmp := ASender.UnparsedParams;
LTarget := FetchIRCParam(LTmp);
LData := FetchIRCParam(LTmp);
CTCPList := TStringList.Create;
try
ExtractCTCPs(LData, CTCPList);
if CTCPList.Count = 0 then begin
if Assigned(FOnNotice) then begin
OnNotice(ASender.Context, FSenderNick, FSenderHost, LTarget, LData);
end;
end else
begin
if (LData <> '') and Assigned(FOnNotice) then begin
OnNotice(ASender.Context, FSenderNick, FSenderHost, LTarget, LData);
end;
for I := 0 to CTCPList.Count - 1 do begin
LData := CTCPList[I];
LCTCP := Fetch(LData, ' ');
case PosInStrArray(LCTCP, IdIRCCTCP) of
0: { ACTION }
begin
{
if Assigned(FOnAction) then begin
FOnAction(ASender.Context, FSenderNick, FSenderHost, LTarget, LData);
end;
}
if Assigned(FOnCTCPRep) then begin
FOnCTCPRep(ASender.Context, FSenderNick, FSenderHost, LTarget, LCTCP, LData);
end;
end;
9: { DCC }
begin
ParseDCC(ASender.Context, LData);
end;
10: { SED }
begin
//ParseSED(AContext, LData);
if Assigned(FOnCTCPRep) then begin
FOnCTCPRep(ASender.Context, FSenderNick, FSenderHost, LTarget, LCTCP, LData);
end;
end;
else
if Assigned(FOnCTCPRep) then begin
FOnCTCPRep(ASender.Context, FSenderNick, FSenderHost, LTarget, LCTCP, LData);
end;
end;
end;
end;
finally
CTCPList.Free;
end;
end;
procedure TIdIRC.CommandJOIN(ASender: TIdCommand);
begin
if Assigned(FOnJoin) then begin
OnJoin(ASender.Context, FSenderNick, FSenderHost, ASender.Params[0]);
end;
end;
procedure TIdIRC.CommandPART(ASender: TIdCommand);
var
LChannel, LMsg: string;
begin
if Assigned(FOnPart) then begin
if ASender.Params.Count > 0 then begin
LChannel := ASender.Params[0];
end;
if ASender.Params.Count > 1 then begin
LMsg := ASender.Params[1];
end;
OnPart(ASender.Context, FSenderNick, FSenderHost, LChannel, LMsg);
end;
end;
procedure TIdIRC.CommandKICK(ASender: TIdCommand);
var
LChannel, LTarget, LReason: string;
begin
if Assigned(FOnKick) then begin
if ASender.Params.Count > 0 then begin
LChannel := ASender.Params[0];
end;
if ASender.Params.Count > 1 then begin
LTarget := ASender.Params[1];
end;
if ASender.Params.Count > 2 then begin
LReason := ASender.Params[2];
end;
OnKick(ASender.Context, FSenderNick, FSenderHost, LChannel, LTarget, LReason);
end;
end;
procedure TIdIRC.CommandMODE(ASender: TIdCommand);
var
LTmp, LParam: String;
begin
LTmp := ASender.UnparsedParams;
LParam := FetchIRCParam(LTmp);
if IsChannel(LParam) then begin
if Assigned(FOnChanMode) then begin
OnChannelMode(ASender.Context, FSenderNick, FSenderHost, LParam, LTmp, '');
end;
end
else if Assigned(FOnUserMode) then begin
OnUserMode(ASender.Context, FSenderNick, FSenderHost, LTmp);
end;
end;
procedure TIdIRC.CommandNICK(ASender: TIdCommand);
begin
if Assigned(FOnNickChange) then begin
OnNicknameChange(ASender.Context, FSenderNick, FSenderHost, ASender.Params[0]);
end;
end;
procedure TIdIRC.CommandQUIT(ASender: TIdCommand);
var
LReason: string;
begin
if Assigned(FOnQuit) then begin
if ASender.Params.Count > 0 then begin
LReason := ASender.Params[0];
end;
OnQuit(ASender.Context, FSenderNick, FSenderHost, LReason);
end;
end;
procedure TIdIRC.CommandSQUIT(ASender: TIdCommand);
var
LServer, LComment: string;
begin
if Assigned(FOnSvrQuit) then begin
if ASender.Params.Count > 0 then begin
LServer := ASender.Params[0];
end;
if ASender.Params.Count > 1 then begin
LComment := ASender.Params[1];
end;
OnServerQuit(ASender.Context, FSenderNick, FSenderHost, LServer, LComment);
end;
end;
procedure TIdIRC.CommandINVITE(ASender: TIdCommand);
begin
if Assigned(FOnInvite) then begin
OnInvite(ASender.Context, FSenderNick, FSenderHost, ASender.Params[0], ASender.Params[1]);
end;
end;
procedure TIdIRC.CommandKILL(ASender: TIdCommand);
var
LTarget, LReason: string;
begin
if Assigned(FOnKill) then begin
if ASender.Params.Count > 0 then begin
LTarget := ASender.Params[0];
end;
if ASender.Params.Count > 1 then begin
LReason := ASender.Params[1];
end;
OnKill(ASender.Context, FSenderNick, FSenderHost, LTarget, LReason);
end;
end;
procedure TIdIRC.CommandPING(ASender: TIdCommand);
var
LServer1: String;
begin
if ASender.Params.Count > 0 then begin
LServer1 := ASender.Params[0];
end;
Pong(LServer1);
if Assigned(FOnPingPong) then begin
OnPingPong(ASender.Context);
end;
end;
procedure TIdIRC.CommandWALLOPS(ASender: TIdCommand);
var
LTmp: string;
begin
if Assigned(FOnWallops) then begin
LTmp := ASender.UnparsedParams;
OnWallops(ASender.Context, FSenderNick, FSenderHost, FetchIRCParam(LTmp));
end;
end;
procedure TIdIRC.CommandTOPIC(ASender: TIdCommand);
var
LChannel, LTopic: String;
begin
if Assigned(FOnTopic) then
begin
if ASender.Params.Count > 0 then begin
LChannel := ASender.Params[0];
end;
if (ASender.CommandHandler.Command <> '331') and (ASender.Params.Count > 1) then begin {do not localize}
LTopic := ASender.Params[1];
end else begin
LTopic := '';
end;
OnTopic(ASender.Context, FSenderNick, FSenderHost, LChannel, LTopic);
end;
end;
procedure TIdIRC.CommandWELCOME(ASender: TIdCommand);
var
LTmp: string;
begin
if Assigned(FOnSWelcome) then begin
LTmp := ASender.UnparsedParams;
OnServerWelcome(ASender.Context, FetchIRCParam(LTmp));
end;
end;
procedure TIdIRC.CommandERROR(ASender: TIdCommand);
var
LTmp: String;
begin
if Assigned(FOnServerError) then begin
LTmp := ASender.UnparsedParams;
OnServerError(ASender.Context, 0, FetchIRCParam(LTmp));
end;
end;
procedure TIdIRC.CommandYOURHOST(ASender: TIdCommand);
var
LTmp: String;
begin
if Assigned(FOnYourHost) then begin
LTmp := ASender.UnparsedParams;
OnYourHost(ASender.Context, FetchIRCParam(LTmp));
end;
end;
procedure TIdIRC.CommandCREATED(ASender: TIdCommand);
var
LTmp: string;
begin
if Assigned(FOnSCreated) then begin
LTmp := ASender.UnparsedParams;
OnServerCreated(ASender.Context, FetchIRCParam(LTmp));
end;
end;
procedure TIdIRC.CommandMYINFO(ASender: TIdCommand);
var
LTmp, LServer, LVersion, LUserModes, LChanModes: String;
begin
if Assigned(FOnMyInfo) then begin
LTmp := ASender.UnparsedParams;
LServer := FetchIRCParam(LTmp);
LVersion := FetchIRCParam(LTmp);
LUserModes := FetchIRCParam(LTmp);
LChanModes := FetchIRCParam(LTmp);
// TODO: <channel_modes_with_params> <user_modes_with_params> <server_modes> <server_modes_with_params>
OnMyInfo(ASender.Context, LServer, LVersion, LUserModes, LChanModes, LTmp);
end;
end;
procedure TIdIRC.DoBounce(ASender: TIdCommand; ALegacy: Boolean);
var
LHost, LPort, LInfo: string;
begin
if Assigned(FOnBounce) then begin
if ALegacy then begin
LInfo := ASender.Params[0];
LHost := FetchIRCParam(LInfo);
LPort := FetchIRCParam(LInfo);
end else
begin
LHost := ASender.Params[0];
LPort := ASender.Params[1];
if ASender.Params.Count > 2 then begin
LInfo := ASender.Params[2];
end;
end;
// TODO: reconnect automatically
OnBounce(ASender.Context, LHost, IndyStrToInt(LPort, 0), LInfo);
end;
end;
procedure TIdIRC.CommandISUPPORT(ASender: TIdCommand);
var
LParams: TStringList;
I: Integer;
begin
if ASender.Params.Count = 1 then begin
DoBounce(ASender, True); // legacy, deprecated
Exit;
end;
if Assigned(FOnISupport) then
begin
LParams := TStringList.Create;
try
for I := 1 to ASender.Params.Count-1 do // skip nickname
begin
LParams.Add(ASender.Params[I]);
end;
OnISupport(ASender.Context, LParams);
finally
LParams.Free;
end;
end;
end;
procedure TIdIRC.CommandBOUNCE(ASender: TIdCommand);
begin
DoBounce(ASender, False);
end;
procedure TIdIRC.CommandAWAY(ASender: TIdCommand);
var
LCmd: Integer;
begin
LCmd := IndyStrToInt(ASender.CommandHandler.Command, 0);
case LCmd of
301:
begin
if Assigned(FOnAway) then begin
OnAway(ASender.Context, FSenderNick, FSenderHost, ASender.Params[0], True);
end;
end;
305, 306:
begin
FUserAway := (LCmd = 306);
if Assigned(FOnAway) then begin
OnAway(ASender.Context, GetUsedNickname, '', ASender.Params[0], FUserAway);
end;
end;
end;
end;
procedure TIdIRC.CommandUSERHOST(ASender: TIdCommand);
begin
if Assigned(FOnUserInfo) then begin
OnUserInfoReceived(ASender.Context, ASender.UnparsedParams);
end;
end;
procedure TIdIRC.CommandISON(ASender: TIdCommand);
begin
if Assigned(FOnIsOnIRC) then begin
OnIsOnIRC(ASender.Context, FSenderNick, FSenderHost);
end;
end;
procedure TIdIRC.CommandWHOIS(ASender: TIdCommand);
begin
if not Assigned(FWhoIs) then begin
FWhoIs := TStringList.Create;
end;
FWhoIs.Add(ASender.Params[0]);
end;
procedure TIdIRC.CommandENDOFWHOIS(ASender: TIdCommand);
begin
CommandWHOIS(ASender);
if Assigned(FOnWhoIs) then begin
OnWhoIs(ASender.Context, FWhoIs);
end;
FWhoIs.Clear;
end;
procedure TIdIRC.CommandWHOWAS(ASender: TIdCommand);
begin
if not Assigned(FWhoWas) then begin
FWhoWas := TStringList.Create;
end;
FWhoWas.Add(ASender.Params[0]);
end;
procedure TIdIRC.CommandENDOFWHOWAS(ASender: TIdCommand);
begin
CommandWHOWAS(ASender);
if Assigned(FOnWhoWas) then begin
OnWhoWas(ASender.Context, FWhoWas);
end;
FWhoWas.Clear;
end;
procedure TIdIRC.CommandLISTSTART(ASender: TIdCommand);
begin
if not Assigned(FSvrList) then begin
FSvrList := TStringList.Create;
end else begin
FSvrList.Clear;
end;
end;
procedure TIdIRC.CommandLIST(ASender: TIdCommand);
begin
if not Assigned(FSvrList) then begin
FSvrList := TStringList.Create;
end;
FSvrList.Add(ASender.Params[0] + ' ' + ASender.Params[1] + ' ' + ASender.Params[2]); {do not localize}
end;
procedure TIdIRC.CommandLISTEND(ASender: TIdCommand);
begin
CommandLIST(ASender);
if Assigned(FOnSvrList) then begin
OnServerListReceived(ASender.Context, FSvrList);
end;
FSvrList.Clear;
end;
procedure TIdIRC.CommandINVITING(ASender: TIdCommand);
begin
if Assigned(FOnInviting) then begin
OnInviting(ASender.Context, FSenderNick, FSenderHost);
end;
end;
procedure TIdIRC.CommandSUMMONING(ASender: TIdCommand);
begin
if Assigned(FOnSummon) then begin
OnSummon(ASender.Context, FSenderNick, FSenderHost);
end;
end;
procedure TIdIRC.CommandINVITELIST(ASender: TIdCommand);
begin
if not Assigned(FInvites) then begin
FInvites := TStringList.Create;
end;
// TODO: use a collection instead
FInvites.Add(ASender.Params[0] + ' ' + ASender.Params[1]); {do not localize}
end;
procedure TIdIRC.CommandENDOFINVITELIST(ASender: TIdCommand);
begin
if not Assigned(FInvites) then begin
FInvites := TStringList.Create;
end;
FInvites.Add(ASender.Params[0]);
if Assigned(FOnINVList) then begin
OnInvitationListReceived(ASender.Context, FSenderNick, FInvites);
end;
FInvites.Clear;
end;
procedure TIdIRC.CommandEXCEPTLIST(ASender: TIdCommand);
begin
if not Assigned(FExcepts) then begin
FExcepts := TStringList.Create;
end;
// TODO: use a collection instead
FExcepts.Add(ASender.Params[0] + ' ' + ASender.Params[1]); {do not localize}
end;
procedure TIdIRC.CommandENDOFEXCEPTLIST(ASender: TIdCommand);
begin
if not Assigned(FExcepts) then begin
FExcepts := TStringList.Create;
end;
FExcepts.Add(ASender.Params[0]);
if Assigned(FOnEXCList) then begin
OnExceptionListReceived(ASender.Context, FSenderNick, FExcepts);
end;
FExcepts.Clear;
end;
procedure TIdIRC.CommandWHOREPLY(ASender: TIdCommand);
begin
if not Assigned(FWho) then begin
FWho := TStringList.Create;
end;
FWho.Add(''); // TODO
end;
procedure TIdIRC.CommandENDOFWHO(ASender: TIdCommand);
begin
if not Assigned(FWho) then begin
FWho := TStringList.Create;
end;
FWho.Add(ASender.Params[0]);
if Assigned(FOnWho) then begin
OnWho(ASender.Context, FWho);
end;
FWho.Clear;
end;
procedure TIdIRC.CommandNAMEREPLY(ASender: TIdCommand);
var
i: Integer;
LNames: string;
LNameList: TStringList;
begin
if not Assigned(FNames) then begin
FNames := TStringList.Create;
end;
// AWinkelsdorf 3/10/2010 Rewrote logic to split Names into single Lines of FNames
if ASender.Params.Count >= 4 then begin // Names are in [3]
LNames := StringsReplace(ASender.Params[3], [' '], [',']); {do not localize}
LNameList := TStringList.Create;
try
LNameList.CommaText := LNames;
for i := 0 to LNameList.Count - 1 do
begin
if LNameList[i] <> '' then
FNames.Add(LNameList[i]);
end;
finally
LNameList.Free;
end;
end else begin
FNames.Add(ASender.Params[0]);
end;
end;
procedure TIdIRC.CommandENDOFNAMES(ASender: TIdCommand);
var
LChannel: string;
begin
if not Assigned(FNames) then begin
FNames := TStringList.Create;
end;
LChannel := '';
if ASender.Params.Count > 0 then begin
LChannel := ASender.Params[1];
end;
if Assigned(FOnNickList) then begin
OnNicknamesListReceived(ASender.Context, LChannel, FNames);
end;
FNames.Clear;
end;
procedure TIdIRC.CommandLINKS(ASender: TIdCommand);
var
LHopCnt, LInfo: String;
begin
if not Assigned(FLinks) then begin
FLinks := TStringList.Create;
end;
LInfo := ASender.Params[2];
LHopCnt := Fetch(LInfo);
// TODO: use a collection instead
FLinks.Add(ASender.Params[0] + ' ' + ASender.Params[1] + ' ' + LHopCnt + ' ' + LInfo); {do not localize}
end;
procedure TIdIRC.CommandENDOFLINKS(ASender: TIdCommand);
begin
if not Assigned(FLinks) then begin
FLinks := TStringList.Create;
end;
FLinks.Add(ASender.Params[0]);
if Assigned(FOnKnownSvrs) then begin
OnKnownServersListReceived(ASender.Context, FLinks);
end;
FLinks.Clear;
end;
procedure TIdIRC.CommandBANLIST(ASender: TIdCommand);
begin
if not Assigned(FBans) then begin
FBans := TStringList.Create;
end;
// TODO: use a collection instead
FBans.Add(ASender.Params[0] + ' ' + ASender.Params[1]); {do not localize}
end;
procedure TIdIRC.CommandENDOFBANLIST(ASender: TIdCommand);
begin
if not Assigned(FBans) then begin
FBans := TStringList.Create;
end;
FBans.Add(ASender.Params[0]);
if Assigned(FOnBanList) then begin
OnBanListReceived(ASender.Context, FSenderNick, FBans);
end;
FBans.Clear;
end;
procedure TIdIRC.CommandINFO(ASender: TIdCommand);
begin
// TODO
end;
procedure TIdIRC.CommandENDOFINFO(ASender: TIdCommand);
begin
if Assigned(FOnUserInfo) then begin
OnUserInfoReceived(ASender.Context, ASender.UnparsedParams);
end;
end;
procedure TIdIRC.CommandMOTD(ASender: TIdCommand);
begin
if not Assigned(FMotd) then begin
FMotd := TStringList.Create;
end;
FMotd.Add(ASender.Params[0]);
end;
procedure TIdIRC.CommandENDOFMOTD(ASender: TIdCommand);
begin
if not Assigned(FMotd) then begin
FMotd := TStringList.Create;
end;
if Assigned(FOnMOTD) then begin
OnMOTD(ASender.Context, FMotd);
end;
FMotd.Clear;
end;
procedure TIdIRC.CommandREHASHING(ASender: TIdCommand);
begin
if Assigned(FOnRehash) then begin
OnRehash(ASender.Context, FSenderNick, FSenderHost);
end;
end;
procedure TIdIRC.CommandUSERSSTART(ASender: TIdCommand);
begin
if not Assigned(FUsers) then begin
FUsers := TStringList.Create;
end else begin
FUsers.Clear;
end;
end;
procedure TIdIRC.CommandUSERS(ASender: TIdCommand);
begin
if ASender.CommandHandler.Command = '393' then {do not localize}
begin
if not Assigned(FUsers) then begin
FUsers := TStringList.Create;
end;
// TODO: use a collection instead
FUsers.Add(ASender.Params[0] + ' ' + ASender.Params[1] + ' ' + ASender.Params[2]); {do not localize}
end;
end;
procedure TIdIRC.CommandENDOFUSERS(ASender: TIdCommand);
begin
if not Assigned(FUsers) then begin
FUsers := TStringList.Create;
end;
if Assigned(FOnSvrUsers) then begin
OnServerUsersListReceived(ASender.Context, FUsers);
end;
FUsers.Clear;
end;
procedure TIdIRC.CommandENDOFSTATS(ASender: TIdCommand);
begin
if Assigned(FOnSvrStats) then begin
OnServerStatsReceived(ASender.Context, nil); // TODO
end;
end;
procedure TIdIRC.CommandSERVLIST(ASender: TIdCommand);
begin
// <name> <server> <mask> <type> <hopcount> <info>
end;
procedure TIdIRC.CommandSERVLISTEND(ASender: TIdCommand);
begin
// <mask> <type> :<info>
end;
procedure TIdIRC.CommandTIME(ASender: TIdCommand);
var
LServer, LTimeString: String;
begin
if Assigned(FOnSvrTime) then begin
LServer := ASender.Params[0];
case ASender.Params.Count of
2: begin // "<server> :<time string>"
LTimeString := ASender.Params[1];
end;
4: begin // "<server> <timestamp> <offset> :<time string>" or "<server> <timezone name> <microseconds> :<time string>"
LTimeString := IndyFormat('%s %s %s', [ASender.Params[1], ASender.Params[2], ASender.Params[3]]); {do not localize}
end;
7: begin // "<server> <year> <month> <day> <hour> <minute> <second>"
LTimeString := IndyFormat('%s %s %s %s %s %s', {do not localize}
[ASender.Params[1], ASender.Params[2], ASender.Params[3],
ASender.Params[4], ASender.Params[5], ASender.Params[6]]);
end;
end;
OnServerTime(ASender.Context, LServer, LTimeString);
end;
end;
procedure TIdIRC.CommandSERVICE(ASender: TIdCommand);
begin
if Assigned(FOnService) then begin
OnService(ASender.Context);
end;
end;
procedure TIdIRC.CommandVERSION(ASender: TIdCommand);
begin
if Assigned(FOnSvrVersion) then begin
OnServerVersion(ASender.Context, ASender.Params[0], ASender.Params[1], ASender.Params[2]);
end;
end;
procedure TIdIRC.CommandCHANMODE(ASender: TIdCommand);
begin
if Assigned(FOnChanMode) then begin
OnChannelMode(ASender.Context, FSenderNick, FSenderHost, ASender.Params[0], ASender.Params[1], ASender.Params[2]);
end;
end;
procedure TIdIRC.CommandOPER(ASender: TIdCommand);
begin
if Assigned(FOnOp) then begin
OnOp(ASender.Context, FSenderNick, FSenderHost, ASender.Params[0]);
end;
end;
procedure TIdIRC.CommandNICKINUSE(ASender: TIdCommand);
begin
if ASender.CommandHandler.Command = '433' then {do not localize}
begin
if (Connected) and (FAltNickname <> '') then
begin
if not FAltNickUsed then begin
// try only once using AltNickname (FAltNickUsed is cleared in .Connect)
SetNickname(FAltNickname);
FAltNickUsed := True;
end
else
begin
// already tried to use AltNickName...
if Assigned(FOnNickError) then begin
OnNicknameError(ASender.Context, IndyStrToInt(ASender.CommandHandler.Command));
end;
end;
end;
end;
end;
procedure TIdIRC.ParseDCC(AContext: TIdContext; const ADCC: String);
const
IdIRCDCC: array[0..3] of String = ('SEND', 'CHAT', 'RESUME', 'ACCEPT'); {do not localize}
var
LTmp, LType, LArg, LAddr, LPort, LSize: String;
begin
LTmp := ADCC;
LType := FetchIRCParam(LTmp);
LArg := FetchIRCParam(LTmp);
LAddr := FetchIRCParam(LTmp);
LPort := FetchIRCParam(LTmp);
LSize := FetchIRCParam(LTmp);
//
case PosInStrArray(LType, IdIRCDCC) of
0: {SEND}
begin
if Assigned(FOnDCCSend) then begin
FOnDCCSend(AContext, FSenderNick, LAddr, ExtractFileName(LArg), IndyStrToInt(LPort), IndyStrToInt64(LSize));
end;
end;
1: {CHAT}
begin
if Assigned(FOnDCCChat) then begin
FOnDCCChat(AContext, FSenderNick, LAddr, IndyStrToInt(LPort));
end;
end;
2: {RESUME}
begin
if Assigned(FOnDCCResume) then begin
FOnDCCResume(AContext, FSenderNick, LAddr, LArg, IndyStrToInt(LPort), IndyStrToInt64(LSize));
end;
end;
3: {ACCEPT}
begin
if Assigned(FOnDCCAccept) then begin
FOnDCCAccept(AContext, FSenderNick, LAddr, LArg, IndyStrToInt(LPort), IndyStrToInt64(LSize));
end;
end;
end;
end;
function TIdIRC.GetUsedNickname: String;
begin
if FAltNickUsed then
Result := FAltNickname
else
Result := FNickname;
end;
procedure TIdIRC.SetNickname(const AValue: String);
begin
if not Connected then begin
FNickname := AValue;
end else begin
Raw(IndyFormat('NICK %s', [AValue])); {do not localize}
end;
end;
procedure TIdIRC.SetUsername(const AValue: String);
begin
if not Connected then begin
FUsername := AValue;
end else begin
Raw(IndyFormat('USER %s %s %s :%s', [AValue, GetUserMode, '*', FRealName])); {do not localize}
end;
end;
procedure TIdIRC.SetIdIRCUserMode(AValue: TIdIRCUserModes);
begin
FUserMode := AValue;
end;
procedure TIdIRC.SetIdIRCReplies(AValue: TIdIRCReplies);
begin
FReplies.Assign(AValue);
end;
function TIdIRC.IsChannel(const AChannel: String): Boolean;
begin
//Result := (Length(AChannel) > 0) and CharIsInSet(AChannel, 1, ['&','#','+','!']); {do not localize}
Result := CharIsInSet(AChannel, 1, '&#+!'); {do not localize}
end;
function TIdIRC.IsOp(const ANickname: String): Boolean;
begin
Result := TextStartsWith(ANickname, '@');
end;
function TIdIRC.IsVoice(const ANickname: String): Boolean;
begin
Result := TextEndsWith(ANickname, '+');
end;
procedure TIdIRC.Say(const ATarget, AMsg: String);
begin
Raw(IndyFormat('PRIVMSG %s :%s', [ATarget, AMsg])); {do not localize}
end;
procedure TIdIRC.Notice(const ATarget, AMsg: String);
begin
Raw(IndyFormat('NOTICE %s :%s', [ATarget, AMsg])); {do not localize}
end;
procedure TIdIRC.Action(const ATarget, AMsg: String);
begin
CTCPQuery(ATarget, 'ACTION', AMsg); {do not localize}
end;
procedure TIdIRC.CTCPQuery(const ATarget, ACommand, AParameters: String);
var
LTmp: String;
begin
LTmp := UpperCase(ACommand);
if AParameters <> '' then begin
LTmp := LTmp + ' ' + AParameters;
end;
Say(ATarget, XDelim+CTCPQuote(LTmp)+XDelim); {do not localize}
end;
procedure TIdIRC.CTCPReply(const ATarget, ACTCP, AReply: String);
var
LTmp: String;
begin
LTmp := ACTCP;
if AReply <> '' then begin
LTmp := LTmp + ' ' + AReply;
end;
Notice(ATarget, XDelim+CTCPQuote(LTmp)+XDelim); {do not localize}
end;
procedure TIdIRC.Join(const AChannel: String; const AKey: String = '');
begin
if IsChannel(AChannel) then begin
if AKey <> '' then begin
Raw(IndyFormat('JOIN %s %s', [AChannel, AKey])) {do not localize}
end else begin
Raw(IndyFormat('JOIN %s', [AChannel])); {do not localize}
end;
end;
end;
procedure TIdIRC.Part(const AChannel: String; const AReason: String = '');
begin
if IsChannel(AChannel) then begin
if AReason <> '' then begin
Raw(IndyFormat('PART %s :%s', [AChannel, AReason])) {do not localize}
end else begin
Raw(IndyFormat('PART %s', [AChannel])); {do not localize}
end;
end;
end;
procedure TIdIRC.Kick(const AChannel, ANickname: String; const AReason: String = '');
begin
if IsChannel(AChannel) then begin
if AReason <> '' then begin
Raw(IndyFormat('KICK %s %s :%s', [AChannel, ANickname, AReason])); {do not localize}
end else begin
Raw(IndyFormat('KICK %s %s', [AChannel, ANickname])); {do not localize}
end;
end;
end;
procedure TIdIRC.SetChannelMode(const AChannel, AMode: String; const AParams: String = '');
begin
if IsChannel(AChannel) then begin
if AParams = '' then begin
Raw(IndyFormat('MODE %s %s', [AChannel, AMode])); {do not localize}
end else begin
Raw(IndyFormat('MODE %s %s %s', [AChannel, AMode, AParams])); {do not localize}
end;
end;
end;
procedure TIdIRC.SetUserMode(const ANickname, AMode: String);
begin
Raw(IndyFormat('MODE %s %s', [ANickname, AMode])); {do not localize}
end;
procedure TIdIRC.GetChannelTopic(const AChannel: String);
begin
if IsChannel(AChannel) then begin
Raw(IndyFormat('TOPIC %s', [AChannel])); {do not localize}
end;
end;
procedure TIdIRC.SetChannelTopic(const AChannel, ATopic: String);
begin
if IsChannel(AChannel) then begin
Raw(IndyFormat('TOPIC %s :%s', [AChannel, ATopic])); {do not localize}
end;
end;
procedure TIdIRC.SetAway(const AMsg: String);
begin
if AMsg <> '' then begin
Raw(IndyFormat('AWAY :%s', [AMsg])); {do not localize}
end else begin
Raw('AWAY'); {do not localize}
end;
end;
procedure TIdIRC.Op(const AChannel, ANickname: String);
begin
SetChannelMode(AChannel, '+o', ANickname); {do not localize}
end;
procedure TIdIRC.Deop(const AChannel, ANickname: String);
begin
SetChannelMode(AChannel, '-o', ANickname); {do not localize}
end;
procedure TIdIRC.Voice(const AChannel, ANickname: String);
begin
SetChannelMode(AChannel, '+v', ANickname); {do not localize}
end;
procedure TIdIRC.Devoice(const AChannel, ANickname: String);
begin
SetChannelMode(AChannel, '-v', ANickname); {do not localize}
end;
procedure TIdIRC.Ban(const AChannel, AHostmask: String);
begin
SetChannelMode(AChannel, '+b', AHostmask); {do not localize}
end;
procedure TIdIRC.Unban(const AChannel, AHostmask: String);
begin
SetChannelMode(AChannel, '-b', AHostmask); {do not localize}
end;
procedure TIdIRC.RegisterService(const ANickname, ADistribution, AInfo: String; AType: Integer);
begin
Raw(IndyFormat('SERVICE %s * %s %s 0 :%s', {do not localize}
[ANickname, ADistribution, AType, AInfo]));
end;
procedure TIdIRC.ListChannelNicknames(const AChannel: String; const ATarget: String = '');
begin
if IsChannel(AChannel) then begin
if ATarget <> '' then begin
Raw(IndyFormat('NAMES %s %s', [AChannel, ATarget])); {do not localize}
end else begin
Raw(IndyFormat('NAMES %s', [AChannel])); {do not localize}
end;
end;
end;
procedure TIdIRC.ListChannel(const AChannel: String; const ATarget: String = '');
begin
if IsChannel(AChannel) then begin
if ATarget <> '' then begin
Raw(IndyFormat('LIST %s %s', [AChannel, ATarget])); {do not localize}
end else begin
Raw(IndyFormat('LIST %s', [AChannel])); {do not localize}
end;
end;
end;
procedure TIdIRC.Invite(const ANickname, AChannel: String);
begin
if IsChannel(AChannel) then begin
Raw(IndyFormat('INVITE %s %s', [ANickname, AChannel])); {do not localize}
end;
end;
procedure TIdIRC.GetMessageOfTheDay(const ATarget: String = '');
begin
if ATarget <> '' then begin
Raw(IndyFormat('MOTD %s', [ATarget])); {do not localize}
end else begin
Raw('MOTD'); {do not localize}
end;
end;
procedure TIdIRC.GetNetworkStatus(const AHostMask: String = ''; const ATarget: String = '');
begin
if (AHostMask = '') and (ATarget = '') then begin
Raw('LUSERS'); {do not localize}
end
else if AHostMask = '' then begin
Raw(IndyFormat('LUSERS %s', [ATarget])); {do not localize}
end
else if ATarget = '' then begin
Raw(IndyFormat('LUSERS %s', [AHostMask])); {do not localize}
end else begin
Raw(IndyFormat('LUSERS %s %s', [AHostMask, ATarget])); {do not localize}
end;
end;
procedure TIdIRC.GetServerVersion(const ATarget: String = '');
begin
if ATarget = '' then begin
Raw('VERSION'); {do not localize}
end else begin
Raw(IndyFormat('VERSION %s', [ATarget])); {do not localize}
end;
end;
procedure TIdIRC.GetServerStatus(AQuery: TIdIRCStat; const ATarget: String = '');
const
IdIRCStatChars: array[TIdIRCStat] of Char = ('l', 'm', 'o', 'u'); {do not localize}
begin
if ATarget <> '' then begin
Raw(IndyFormat('STATS %s %s', [IdIRCStatChars[AQuery], ATarget])); {do not localize}
end else begin
Raw(IndyFormat('STATS %s', [IdIRCStatChars[AQuery]])); {do not localize}
end;
end;
procedure TIdIRC.ListKnownServerNames(const ARemoteHost: String = ''; const AHostMask: String = '');
begin
if (ARemoteHost = '') and (AHostMask = '') then begin
Raw('LINKS'); {do not localize}
end
else if ARemoteHost = '' then begin
Raw(IndyFormat('LINKS %s', [AHostMask])); {do not localize}
end else begin
Raw(IndyFormat('LINKS %s %s', [ARemoteHost, AHostMask])); {do not localize}
end;
end;
procedure TIdIRC.QueryServerTime(const ATarget: String = '');
begin
if ATarget <> '' then begin
Raw(IndyFormat('TIME %s', [ATarget])); {do not localize}
end else begin
Raw('TIME'); {do not localize}
end;
end;
procedure TIdIRC.RequestServerConnect(const ATargetHost: String; APort: Integer;
const ARemoteHost: String = '');
begin
if ARemoteHost <> '' then begin
Raw(IndyFormat('CONNECT %s %d %s', [ATargetHost, APort, ARemoteHost])); {do not localize}
end else begin
Raw(IndyFormat('CONNECT %s %d', [ATargetHost, APort])); {do not localize}
end;
end;
procedure TIdIRC.TraceServer(const ATarget: String = '');
begin
if ATarget <> '' then begin
Raw(IndyFormat('TRACE %s', [ATarget])); {do not localize}
end else begin
Raw('TRACE'); {do not localize}
end;
end;
procedure TIdIRC.GetAdminInfo(const ATarget: String = '');
begin
if ATarget <> '' then begin
Raw(IndyFormat('ADMIN %s', [ATarget])); {do not localize}
end else begin
Raw('ADMIN'); {do not localize}
end;
end;
procedure TIdIRC.GetServerInfo(const ATarget: String = '');
begin
if ATarget <> '' then begin
Raw(IndyFormat('INFO %s', [ATarget])); {do not localize}
end else begin
Raw('INFO'); {do not localize}
end;
end;
procedure TIdIRC.ListNetworkServices(const AHostMask: String = ''; const AType: String = '');
begin
if (AHostMask = '') and (AType = '') then begin
Raw('SERVLIST'); {do not localize}
end
else if AType <> '' then begin
Raw(IndyFormat('SERVLIST %s %s', [AHostMask, AType])); {do not localize}
end else begin
Raw(IndyFormat('SERVLIST %s', [AHostMask])); {do not localize}
end;
end;
procedure TIdIRC.QueryService(const AServiceName, AMessage: String);
begin
Raw(IndyFormat('SQUERY %s :%s', [AServiceName, AMessage])); {do not localize}
end;
procedure TIdIRC.Who(const AMask: String; AOnlyAdmins: Boolean);
begin
if (AMask = '') and (not AOnlyAdmins) then begin
Raw('WHO'); {do not localize}
end
else if AOnlyAdmins then begin
Raw(IndyFormat('WHO %s o', [AMask])); {do not localize}
end else begin
Raw(IndyFormat('WHO %s', [AMask])); {do not localize}
end;
end;
procedure TIdIRC.WhoIs(const AMask: String; const ATarget: String = '');
begin
if ATarget <> '' then begin
Raw(IndyFormat('WHOIS %s %s', [ATarget, AMask])); {do not localize}
end else begin
Raw(IndyFormat('WHOIS %s', [AMask])); {do not localize}
end;
end;
procedure TIdIRC.WhoWas(const ANickname: String; ACount: Integer = -1; const ATarget: String = '');
begin
if (ATarget = '') and (ACount < 0) then begin
Raw(IndyFormat('WHOWAS %s', [ANickname])); {do not localize}
end
else if ATarget <> '' then begin
Raw(IndyFormat('WHOWAS %s %d %s', [ANickname, ACount, ATarget])); {do not localize}
end
else begin
Raw(IndyFormat('WHOWAS %s %d', [ANickname, ACount])); {do not localize}
end;
end;
procedure TIdIRC.Kill(const ANickname, AComment: String);
begin
Raw(IndyFormat('KILL %s :%s', [ANickname, AComment])); {do not localize}
end;
procedure TIdIRC.Ping(const AServer1: String; const AServer2: String = '');
begin
if AServer2 <> '' then begin
Raw(IndyFormat('PING %s %s', [AServer1, AServer2])); {do not localize}
end else begin
Raw(IndyFormat('PING %s', [AServer1])); {do not localize}
end;
end;
procedure TIdIRC.Pong(const AServer1: String; const AServer2: String = '');
begin
if AServer2 <> '' then begin
Raw(IndyFormat('PONG %s %s', [AServer1, AServer2])); {do not localize}
end else begin
Raw(IndyFormat('PONG %s', [AServer1])); {do not localize}
end;
end;
procedure TIdIRC.Error(const AMessage: String);
begin
Raw(IndyFormat('ERROR :%s', [AMessage])); {do not localize}
end;
procedure TIdIRC.ReHash;
begin
Raw('REHASH'); {do not localize}
end;
procedure TIdIRC.Die;
begin
Raw('DIE'); {do not localize}
end;
procedure TIdIRC.Restart;
begin
Raw('RESTART'); {do not localize}
end;
procedure TIdIRC.Summon(const ANickname: String; const ATarget: String = '';
const AChannel: String = '');
begin
if (ATarget = '') and (AChannel = '') then begin
Raw(IndyFormat('SUMMON %s', [ANickname])); {do not localize}
end
else if AChannel <> '' then
begin
if IsChannel(AChannel) then begin
Raw(IndyFormat('SUMMON %s %s %s', [ANickname, ATarget, AChannel])); {do not localize}
end;
end else begin
Raw(IndyFormat('SUMMON %s %s', [ANickname, ATarget])); {do not localize}
end;
end;
procedure TIdIRC.ListServerUsers(const ATarget: String = '');
begin
if ATarget <> '' then begin
Raw(IndyFormat('USERS %s', [ATarget])); {do not localize}
end else begin
Raw('USERS'); {do not localize}
end;
end;
procedure TIdIRC.SayWALLOPS(const AMessage: String);
begin
Raw(IndyFormat('WALLOPS :%s', [AMessage])); {do not localize}
end;
procedure TIdIRC.GetUserInfo(const ANickname: String);
begin
Raw(IndyFormat('USERHOST %s', [ANickname])); {do not localize}
end;
procedure TIdIRC.GetUsersInfo(const ANicknames: array of string);
var
I: Integer;
S: string;
begin
if Length(ANicknames) > 0 then
begin
for I := Low(ANicknames) to High(ANicknames) do begin
S := S + ' ' + ANicknames[I]; {do not localize}
end;
Raw(IndyFormat('USERHOST%s', [S])); {do not localize}
end;
end;
procedure TIdIRC.IsOnIRC(const ANickname: String);
begin
Raw(IndyFormat('ISON %s', [ANickname])); {do not localize}
end;
procedure TIdIRC.IsOnIRC(const ANicknames: array of String);
var
I: Integer;
S: string;
begin
if Length(ANicknames) > 0 then
begin
for I := Low(ANicknames) to High(ANicknames) do begin
S := S + ' ' + ANicknames[I]; {do not localize}
end;
Raw(IndyFormat('ISON%s', [S])); {do not localize}
end;
end;
procedure TIdIRC.BecomeOp(const ANickname, APassword: String);
begin
Raw(IndyFormat('OPER %s %s', [ANickname, APassword])); {do not localize}
end;
procedure TIdIRC.SQuit(const AHost, AComment: String);
begin
Raw(IndyFormat('SQUIT %s :%s', [AHost, AComment])); {do not localize}
end;
procedure TIdIRC.SetChannelLimit(const AChannel: String; ALimit: Integer);
begin
SetChannelMode(AChannel, '+l', IntToStr(ALimit)); {do not localize}
end;
procedure TIdIRC.SetChannelKey(const AChannel, AKey: String);
begin
SetChannelMode(AChannel, '+k', AKey); {do not localize}
end;
procedure TIdIRC.SetIOHandler(AValue: TIdIOHandler);
begin
inherited SetIOHandler(AValue);
//we do it this way so that if a user is using a custom value <> default, the port
//is not set when the IOHandler is changed.
if (IOHandler is TIdSSLIOHandlerSocketBase) then begin
if Port = IdPORT_IRC then begin
Port := IdPORT_IRCS;
end;
end else begin
if Port = IdPORT_IRCS then begin
Port := IdPORT_IRC;
end;
end;
end;
end.