Advertisement
Guest User

Untitled

a guest
Jan 22nd, 2018
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pascal 79.90 KB | None | 0 0
  1. unit EvilIrc;
  2.  
  3. interface
  4.  
  5. uses
  6.     Windows, Classes, SysUtils, EvilStrings, EvilWinUtils, EvilClasses, EvilTCPSocket;
  7.  
  8. const
  9.     CWHO: string     = 'WHO';
  10.     CTIME: string    = 'TIME';
  11.     CPASS: string    = 'PASS';
  12.     CNICK: string    = 'NICK';
  13.     CUSER: string    = 'USER';
  14.     CPING: string    = 'PING';
  15.     CPONG: string    = 'PONG';
  16.     CJOIN: string    = 'JOIN';
  17.     CPART: string    = 'PART';
  18.     CKICK: string    = 'KICK';
  19.     CMODE: string    = 'MODE';
  20.     CQUIT: string    = 'QUIT';
  21.     CKILL: string    = 'KILL';
  22.     CWHOIS: string   = 'WHOIS';
  23.     CTOPIC: string   = 'TOPIC';
  24.     CNAMES: string   = 'NAMES';
  25.     CERROR: string   = 'ERROR';
  26.     CINVITE: string  = 'INVITE';
  27.     CNOTICE: string  = 'NOTICE';
  28.     CACTION: string  = 'ACTION';
  29.     CFINGER: string  = 'FINGER';
  30.     CVERSION: string = 'VERSION';
  31.     CWALLOPS: string = 'WALLOPS';
  32.     CPRIVMSG: string = 'PRIVMSG';
  33.  
  34.     CBold: char      = #$02;
  35.     CColor: char     = #$03;
  36.     COrdinary: char  = #$0F;
  37.     CReverse: char   = #$16;
  38.     CItalic: char    = #$1D;
  39.     CUnderline: char = #$1F;
  40.  
  41. type
  42.     { Forward declarations }
  43.     TIrcNickname            = class;
  44.     TIrcNicknameList        = class;
  45.     TIrcChannelNickname     = class;
  46.     TIrcChannelNicknameList = class;
  47.     TIrcChannel             = class;
  48.     TIrcChannelList         = class;
  49.     TIrcIAL                 = class;
  50.     TIrc                    = class;
  51.  
  52.     { Misc types }
  53.     TIrcChanMode  = (cmOwner, cmAdmin, cmOperator, cmHelper, cmVoice);
  54.     TIrcChanModes = set of TIrcChanMode;
  55.  
  56.     { TIrcMsgParser }
  57.     TIrcMsgParser = class
  58.     strict private
  59.     type
  60.         TSourceType = (stServer, stUser, stNotPresent);
  61.  
  62.         TWordMarker = record
  63.             Start: integer;
  64.             Length: integer;
  65.         end;
  66.     strict private
  67.         FRaw           : string; { Parsed IRC command }
  68.         FSourceType    : TSourceType;
  69.         FSource        : TWordMarker;
  70.         FSourceNickName: TWordMarker;
  71.         FSourceUserName: TWordMarker;
  72.         FSourceHostName: TWordMarker;
  73.         FCommand       : TWordMarker;
  74.         FParams        : TWordMarker;
  75.         FParamsArray   : array of TWordMarker;
  76.         FParamCount    : integer;
  77.         FTrailings     : TWordMarker;
  78.         FTrailingsArray: array of TWordMarker;
  79.         FTrailingCount : integer;
  80.         function GetParam(aIndex: integer): string;
  81.         function GetTrailing(aIndex: integer): string;
  82.     private
  83.         procedure AddParam(const aStart, aLength: integer);
  84.         procedure AddTrailing(const aStart, aLength: integer);
  85.         procedure Clear;
  86.     public
  87.         constructor Create;
  88.         destructor Destroy; override;
  89.  
  90.         function Parse(const aRaw: string): boolean;
  91.         { Parses a RAW IRC message }
  92.         property Raw: string read FRaw; { Returns the last RAW passed to Parse(); }
  93.  
  94.         property SourceType: TSourceType read FSourceType; { Type of message source prefix. }
  95.         function Source: string;
  96.         { Returns the message source, if present; Client or server that sent the message. }
  97.         function SourceNickName: string;
  98.         { Returns NickName from Source if Source is a Client, full source string otherwise }
  99.         function SourceUserName: string;
  100.         { Returns UserName from Source if Source is a Client, full source string otherwise }
  101.         function SourceHostName: string;
  102.         { Returns HostName from Source if Source is a Client, full source string otherwise }
  103.  
  104.         function Command: string;
  105.         { Returns IRC Command that was parsed from RAW }
  106.  
  107.         property Param[aIndex: integer]: string read GetParam;
  108.         { Array of parsed Parameters. This excludes trailing Parameters }
  109.         property ParamCount: integer read FParamCount; { Number of parsed Parameters. }
  110.         function Params: string;                       { Returns all Parameters as a single string }
  111.         function ParamsFrom(const aIndex: integer): string;
  112.         { Returns parameters from and including token at aIndex. }
  113.  
  114.         property Trailing[aIndex: integer]: string read GetTrailing; { Array of parsed trailing Parameters. }
  115.         property TrailingCount: integer read FTrailingCount;         { Number of parsed trailing Parameters. }
  116.         function Trailings: string;
  117.         { Returns all trailing Parameters as a single string }
  118.         function TrailingsFrom(const aIndex: integer): string;
  119.         { Returns trailing parameters from and including token at aIndex. }
  120.  
  121.         function AllParams: string;
  122.         { Returns all middle and trailing params as a single string. }
  123.     end;
  124.  
  125.     { TIrcNickname }
  126.     { Contains info about a nickname }
  127.     TIrcNickname = class
  128.     private
  129.         FNicknameList: TIrcNicknameList;
  130.         FNickname    : string;
  131.         FUsername    : string;
  132.         FRealname    : string;
  133.         FHostname    : string;
  134.         FUserMode    : string;
  135.         FIdentified  : boolean;
  136.         FIrcOp       : boolean;
  137.         FBot         : boolean;
  138.         FAway        : boolean;
  139.         FHops        : byte;
  140.         FLeaf        : string;
  141.         procedure SetNickname(const Value: string);
  142.         procedure SetRealName(const Value: string);
  143.         procedure SetUsername(const Value: string);
  144.         procedure SetHostname(const Value: string);
  145.         procedure SetUsermode(const Value: string);
  146.     public
  147.         constructor Create(aList: TIrcNicknameList);
  148.         destructor Destroy; override;
  149.         procedure Assign(aSource: TIrcNickname);
  150.  
  151.         procedure UpdateHostmask(const aHostmask: string);
  152.         function GetHostMask: string; overload;
  153.         function GetHostMask(const aType: byte): string; overload;
  154.     public
  155.         function IsOwner(const aChannel: string): boolean;
  156.         function IsAdmin(const aChannel: string): boolean;
  157.         function IsChanop(const aChannel: string): boolean;
  158.         function IsHelper(const aChannel: string): boolean;
  159.         function IsVoice(const aChannel: string): boolean;
  160.         function IsRegular(const aChannel: string): boolean;
  161.  
  162.         function IsOnChannel(const aChannel: string): boolean;
  163.         function IsIdentified(const aNick: string): boolean;
  164.  
  165.         property Nickname: string read FNickname write SetNickname;
  166.         property Username: string read FUsername write SetUsername;
  167.         property Realname: string read FRealname write SetRealName;
  168.         property Hostname: string read FHostname write SetHostname;
  169.         property Usermode: string read FUserMode write SetUsermode;
  170.  
  171.         property Identified: boolean read FIdentified write FIdentified;
  172.         property IrcOp: boolean read FIrcOp write FIrcOp;
  173.         property Bot: boolean read FBot write FBot;
  174.         property Away: boolean read FAway write FAway;
  175.         property Hops: byte read FHops write FHops;
  176.         property Leaf: string read FLeaf write FLeaf;
  177.     end;
  178.  
  179.     { TIrcNicknameList }
  180.     { Contains and manages a list of TIrcNickname for TInternalAddressList }
  181.     TIrcNicknameList = class
  182.     private
  183.         FIAL      : TIrcIAL;
  184.         FNicknames: array of TIrcNickname;
  185.         FCount    : integer;
  186.     protected
  187.         procedure Exchange(aIndexA, aIndexB: integer);
  188.         procedure QuickSort(aStart, aEnd: integer);
  189.         function GetInsertIndex(const aNickname: string): integer;
  190.     public
  191.         constructor Create(aIAL: TIrcIAL);
  192.         destructor Destroy; override;
  193.  
  194.         function Add(const aNickname: string): TIrcNickname;
  195.         procedure Del(const aNickname: string);
  196.         function IndexOf(const aNickname: string): integer;
  197.         function Find(const aNickname: string): TIrcNickname;
  198.         procedure Sort;
  199.         procedure Clear;
  200.  
  201.         property IAL: TIrcIAL read FIAL;
  202.     end;
  203.  
  204.     { TIrcChannelNickname }
  205.     { Contains info about a nickname on a channel }
  206.     TIrcChannelNickname = class
  207.     private
  208.         FChannelNicknameList: TIrcChannelNicknameList;
  209.         FNickname           : TIrcNickname;
  210.         FChanModes          : TIrcChanModes;
  211.     public
  212.         constructor Create(aList: TIrcChannelNicknameList);
  213.         procedure Assign(aSource: TIrcChannelNickname);
  214.  
  215.         property Nickname: TIrcNickname read FNickname write FNickname;
  216.         property ChanModes: TIrcChanModes read FChanModes write FChanModes;
  217.     end;
  218.  
  219.     { TIrcChannel }
  220.     { Contains and manages a list of TIrcChannelNickname for TIrcChannel }
  221.     TIrcChannelNicknameList = class
  222.     private
  223.         FChannel  : TIrcChannel;
  224.         FNicknames: array of TIrcChannelNickname;
  225.         FCount    : integer;
  226.         function GetNickname(const aIndex: integer): TIrcChannelNickname;
  227.         procedure SetNickname(const aIndex: integer; const Value: TIrcChannelNickname);
  228.     protected
  229.         procedure Exchange(aIndexA, aIndexB: integer);
  230.         procedure QuickSort(aStart, aEnd: integer);
  231.         function GetInsertIndex(const aNickname: string): integer;
  232.     public
  233.         constructor Create(aChannel: TIrcChannel);
  234.         destructor Destroy; override;
  235.  
  236.         function Add(aNickname: TIrcNickname; const aChanModes: TIrcChanModes = []): TIrcChannelNickname;
  237.         procedure Del(const aNickname: string);
  238.         function IndexOf(const aNickname: string): integer;
  239.         function Find(const aNickname: string): TIrcChannelNickname;
  240.         procedure Sort;
  241.         procedure Clear;
  242.  
  243.         property Nicknames[const aIndex: integer]: TIrcChannelNickname read GetNickname write SetNickname;
  244.         property Count: integer read FCount;
  245.         property Channel: TIrcChannel read FChannel;
  246.     end;
  247.  
  248.     { TIrcChannel }
  249.     { Contains info about a channel }
  250.     TIrcChannel = class
  251.     private
  252.         FChannelList        : TIrcChannelList;
  253.         FTopic              : string;
  254.         FTopicSetBy         : string;
  255.         FTopicSetOn         : TDateTime;
  256.         FModes              : string;
  257.         FChannelName        : string;
  258.         FChannelNicknameList: TIrcChannelNicknameList;
  259.     public
  260.         constructor Create(aList: TIrcChannelList);
  261.         destructor Destroy; override;
  262.         procedure Assign(aSource: TIrcChannel);
  263.  
  264.         property ChannelName: string read FChannelName write FChannelName;
  265.         property Topic: string read FTopic write FTopic;
  266.         property TopicSetBy: string read FTopicSetBy write FTopicSetBy;
  267.         property TopicSetOn: TDateTime read FTopicSetOn write FTopicSetOn;
  268.         property Modes: string read FModes write FModes;
  269.  
  270.         property Nicknames: TIrcChannelNicknameList read FChannelNicknameList write FChannelNicknameList;
  271.     end;
  272.  
  273.     { TIrcChannelList }
  274.     { Contains and manages a list of TIrcChannel for TInternalAddressList }
  275.     TIrcChannelList = class
  276.     private
  277.         FIAL     : TIrcIAL;
  278.         FChannels: array of TIrcChannel;
  279.         FCount   : integer;
  280.     protected
  281.         procedure Exchange(aIndexA, aIndexB: integer);
  282.         procedure QuickSort(aStart, aEnd: integer);
  283.         function GetInsertIndex(const aChannel: string): integer;
  284.     public
  285.         constructor Create(aIAL: TIrcIAL);
  286.         destructor Destroy; override;
  287.  
  288.         function Add(const aChannel: string): TIrcChannel;
  289.         procedure Del(const aChannel: string);
  290.         function IndexOf(const aChannel: string): integer;
  291.         function Find(const aChannel: string): TIrcChannel;
  292.         procedure Sort;
  293.         procedure Clear;
  294.  
  295.         property IAL: TIrcIAL read FIAL;
  296.     end;
  297.  
  298.     { TInternalAddressList }
  299.     TIrcIAL = class(TPersistent)
  300.     private
  301.         FIrc             : TIrc;
  302.         FEnabled         : boolean;
  303.         FNicknameList    : TIrcNicknameList;
  304.         FChannelList     : TIrcChannelList;
  305.         FTokenizer       : TTokenizer;
  306.         FDetailedTracking: boolean;
  307.         procedure SetEnabled(const Value: boolean);
  308.         function GetNicknameByName(const aNickname: string): TIrcNickname;
  309.         function GetNicknameByIndex(const aIndex: integer): TIrcNickname;
  310.         procedure SetNicknameByIndex(const aIndex: integer; const Value: TIrcNickname);
  311.         function GetNicknameCount: integer;
  312.         function GetChannelByName(const aChannel: string): TIrcChannel;
  313.         function GetChannelByIndex(const aIndex: integer): TIrcChannel;
  314.         procedure SetChannelByIndex(const aIndex: integer; const Value: TIrcChannel);
  315.         function GetChannelCount: integer;
  316.     protected
  317.         procedure NickJoinedChannel(const aNickname, aHostmask, aChannel: string);
  318.         procedure NickPartedChannel(const aNickname, aChannel: string);
  319.         procedure NickKickedFromChannel(const aNickname, aChannel: string);
  320.         procedure NickChange(const aOldNickname, aNewNickname: string);
  321.         procedure NickQuit(const aNickname: string);
  322.         procedure NamesList(const aChannel, aNamesList: string);
  323.         procedure WhoText(const aText: string);
  324.         procedure NickIsIdentified(const aNickname: string);
  325.     public
  326.         constructor Create(aIrc: TIrc);
  327.         destructor Destroy; override;
  328.  
  329.         function IsNicknameIdentified(const aNickname: string): boolean;
  330.     public
  331.         procedure Clear;
  332.  
  333.         property Nickname[const aNickname: string]: TIrcNickname read GetNicknameByName;
  334.         property Nicknames[const aIndex: integer]: TIrcNickname read GetNicknameByIndex write SetNicknameByIndex;
  335.         property NicknameCount: integer read GetNicknameCount;
  336.  
  337.         property Channel[const aChannel: string]: TIrcChannel read GetChannelByName;
  338.         property Channels[const aIndex: integer]: TIrcChannel read GetChannelByIndex write SetChannelByIndex;
  339.         property ChannelCount: integer read GetChannelCount;
  340.  
  341.     published
  342.         property Enabled         : boolean read FEnabled write SetEnabled default True;
  343.         property DetailedTracking: boolean read FDetailedTracking write FDetailedTracking default True;
  344.  
  345.         property IRC: TIrc read FIrc;
  346.     end;
  347.  
  348.     { Events }
  349.     TOnIrcEvent        = procedure(aClient: TIrc) of object;
  350.     TOnIrcTextEvent    = procedure(aClient: TIrc; const aText: string) of object;
  351.     TOnIrcRaw          = procedure(aClient: TIrc; const aCmd: string; const aIn: boolean; var aBlockIt: boolean) of object;
  352.     TOnIrcJoin         = procedure(aClient: TIrc; const aNick, aHost, aChannel: string) of object;
  353.     TOnIrcPart         = procedure(aClient: TIrc; const aNick, aHost, aChannel, aReason: string) of object;
  354.     TOnIrcKick         = procedure(aClient: TIrc; const aKicker, aKicked, aChannel, aReason: string) of object;
  355.     TOnIrcKill         = procedure(aClient: TIrc; const aKiller, aKilled, aReason: string) of object;
  356.     TOnIrcQuit         = procedure(aClient: TIrc; const aNick, aHost, aReason: string) of object;
  357.     TOnIrcPrivMsg      = procedure(aClient: TIrc; const aFromNick, aFromHost, aTarget, aText: string) of object;
  358.     TOnIrcServerNotice = procedure(aClient: TIrc; const aSource, aText: string) of object;
  359.     TOnIrcCTCP         = procedure(aClient: TIrc; const aFromNick, aFromHost, aTarget, aCommand, aParameters: string) of object;
  360.     TOnNick            = procedure(aClient: TIrc; const aOldNick, aNewNick, aHost: string) of object;
  361.     TOnMode            = procedure(aClient: TIrc; const aSource, aTarget, aMode: string) of object;
  362.     TOnIrcStatus       = procedure(aClient: TIrc; const aStatus: string) of object;
  363.     TOnIrcError        = procedure(aClient: TIrc; const aError: string) of object;
  364.  
  365.     { TIrc }
  366.     TIrc = class(TCustomTCPSocket)
  367.     private
  368.         { Settings }
  369.         FNickname           : string;
  370.         FRealname           : string;
  371.         FUsername           : string;
  372.         FPassword           : string;
  373.         FAltNicknames       : TStrings;
  374.         FUserMode           : string;
  375.         FRejoinWhenKicked   : boolean;
  376.         FReconnectWhenKilled: boolean;
  377.     private
  378.         { Workers }
  379.         FIAL          : TIrcIAL;
  380.         FTokenizer    : TTokenizer;
  381.         FParser       : TIrcMsgParser;
  382.         FIncompleteCmd: string;
  383.         { Partial command on incomplete socket recv until next recv. }
  384.     private
  385.         { Events }
  386.         FOnRaw          : TOnIrcRaw;
  387.         FOnServerWelcome: TOnIrcEvent;
  388.         FOnCTCP         : TOnIrcCTCP;
  389.         FOnJoin         : TOnIrcJoin;
  390.         FOnPrivMsg      : TOnIrcPrivMsg;
  391.         FOnNotice       : TOnIrcPrivMsg;
  392.         FOnQuit         : TOnIrcQuit;
  393.         FOnPart         : TOnIrcPart;
  394.         FOnKick         : TOnIrcKick;
  395.         FOnNick         : TOnNick;
  396.         FOnKill         : TOnIrcKill;
  397.         FOnServerNotice : TOnIrcServerNotice;
  398.         FOnMode         : TOnMode;
  399.         { Set/Get }
  400.         procedure SetNickname(const Value: string);
  401.         procedure SetRealName(const Value: string);
  402.         procedure SetUsername(const Value: string);
  403.         procedure SetPassword(const Value: string);
  404.         procedure SetAltNicknames(const Value: TStrings);
  405.         procedure SetUsermode(const Value: string);
  406.         procedure SetRejoinWhenKicked(const Value: boolean);
  407.         procedure SetReconnectWhenKilled(const Value: boolean);
  408.     protected
  409.         { Overriden events }
  410.         procedure EventConnect(const aError: word); override;
  411.         procedure EventClose(const aError: word; const aClosedByRemote: boolean); override;
  412.         procedure EventRead(const aError: word); override;
  413.  
  414.         { Introduced events }
  415.         procedure EventRaw(const aCmd: string; const aIn: boolean; var aBlockIt: boolean); virtual;
  416.         procedure EventServerWelcome; virtual;
  417.         procedure EventJoin(const aNick, aHost, aChannel: string); virtual;
  418.         procedure EventPart(const aNick, aHost, aChannel, aReason: string); virtual;
  419.         procedure EventKick(const aKicker, aKicked, aChannel, aReason: string); virtual;
  420.         procedure EventQuit(const aNick, aHost, aReason: string); virtual;
  421.         procedure EventKill(const aKiller, aKilled, aReason: string); virtual;
  422.         procedure EventPrivMsg(const aFromNick, aFromHost, aTarget, aText: string); virtual;
  423.         procedure EventNotice(const aFromNick, aFromHost, aTarget, aText: string); virtual;
  424.         procedure EventServerNotice(const aSource, aText: string); virtual;
  425.         procedure EventCTCP(const aFromNick, aFromHost, aTarget, aCommand, aParameters: string); virtual;
  426.         procedure EventNick(const aOldNick, aNewNick, aHost: string); virtual;
  427.         procedure EventMode(const aSource, aTarget, aMode: string); virtual;
  428.  
  429.         { Funcs }
  430.         procedure ParseCommand(const aLine: string);
  431.     public
  432.         constructor Create(aOwner: TComponent); override;
  433.         destructor Destroy; override;
  434.         procedure Assign(aSource: TPersistent); override;
  435.  
  436.         procedure Raw(const aText: string);
  437.         { Sends raw text, terminates with CRLF. }
  438.  
  439.         { IRC Commands }
  440.         procedure CmdJoin(const aChannel: string; const aKey: string = CEmpty);
  441.         procedure CmdPart(const aChannel: string; const aPartMsg: string = CEmpty);
  442.         procedure CmdMsg(const aTarget, aMessage: string);
  443.         procedure CmdNotice(const aTarget, aMessage: string);
  444.         procedure CmdNick(const aNewNickname: string);
  445.         procedure CmdKill(const aNick, aReason: string);
  446.         procedure CmdMode(const aMode: string);
  447.         procedure CmdWho(const aTarget: string; const aOptionalParams: string = CEmpty);
  448.         procedure CmdWhois(const aTarget: string);
  449.     published
  450.         { Inherited Props }
  451.         property AddressFamily;
  452.         property SocketState;
  453.         property ReceiveBufferSize;
  454.         property BindHost;
  455.         property BindPort;
  456.         property RemoteHost;
  457.         property RemotePort;
  458.         property ProxyHost;
  459.         property ProxyPort;
  460.         property ProxyType;
  461.         property SSLType;
  462.         property SSLPrivateKeyFile;
  463.         property SSLCertificateChainFile;
  464.         property SSLTrustedAuthoritiesFile;
  465.         property SSLVerifyCertificate;
  466.         property ConnectTimeout;
  467.         property ConnectRetryDelay;
  468.         property ConnectRetryCount;
  469.         property ReconnectOnError;
  470.         property ReconnectOnClose;
  471.  
  472.         { Introduced props }
  473.         property Nickname           : string read FNickname write SetNickname;
  474.         property Username           : string read FUsername write SetUsername;
  475.         property Realname           : string read FRealname write SetRealName;
  476.         property Password           : string read FPassword write SetPassword;
  477.         property Usermode           : string read FUserMode write SetUsermode;
  478.         property AltNicknames       : TStrings read FAltNicknames write SetAltNicknames;
  479.         property IAL                : TIrcIAL read FIAL;
  480.         property RejoinWhenKicked   : boolean read FRejoinWhenKicked write SetRejoinWhenKicked default True;
  481.         property ReconnectWhenKilled: boolean read FReconnectWhenKilled write SetReconnectWhenKilled default True;
  482.  
  483.         { Inherited events }
  484.         property OnResolving;
  485.         property OnResolved;
  486.         property OnConnecting;
  487.         property OnConnectTimeout;
  488.         property OnConnected;
  489.         property OnDisconnected;
  490.         property OnError;
  491.  
  492.         { Introduced events }
  493.         property OnRaw          : TOnIrcRaw read FOnRaw write FOnRaw;
  494.         property OnServerWelcome: TOnIrcEvent read FOnServerWelcome write FOnServerWelcome;
  495.         property OnJoin         : TOnIrcJoin read FOnJoin write FOnJoin;
  496.         property OnPart         : TOnIrcPart read FOnPart write FOnPart;
  497.         property OnKick         : TOnIrcKick read FOnKick write FOnKick;
  498.         property OnQuit         : TOnIrcQuit read FOnQuit write FOnQuit;
  499.         property OnKill         : TOnIrcKill read FOnKill write FOnKill;
  500.         property OnPrivMsg      : TOnIrcPrivMsg read FOnPrivMsg write FOnPrivMsg;
  501.         property OnNotice       : TOnIrcPrivMsg read FOnNotice write FOnNotice;
  502.         property OnServerNotice : TOnIrcServerNotice read FOnServerNotice write FOnServerNotice;
  503.         property OnCTCP         : TOnIrcCTCP read FOnCTCP write FOnCTCP;
  504.         property OnNick         : TOnNick read FOnNick write FOnNick;
  505.         property OnMode         : TOnMode read FOnMode write FOnMode;
  506.     end;
  507.  
  508. function SplitNickAndChanmodes(const aText: string; var aChanModes: TIrcChanModes; var aNickname: string): boolean;
  509.  
  510. implementation
  511.  
  512. function SplitNickAndChanmodes(const aText: string; var aChanModes: TIrcChanModes; var aNickname: string): boolean;
  513. var
  514.     i: integer;
  515.     l: integer;
  516. begin
  517.     l := Length(aText);
  518.     if (l = 0) then
  519.         Exit(False)
  520.     else
  521.     begin
  522.         i          := 1;
  523.         aChanModes := [];
  524.         aNickname  := CEmpty;
  525.     end;
  526.  
  527.     while (i <= l) do
  528.     begin
  529.         if (aText[i] = '~') then
  530.             Include(aChanModes, cmOwner)
  531.         else
  532.             if (aText[i] = '&') then
  533.                 Include(aChanModes, cmAdmin)
  534.             else
  535.                 if (aText[i] = '@') then
  536.                     Include(aChanModes, cmOperator)
  537.                 else
  538.                     if (aText[i] = '%') then
  539.                         Include(aChanModes, cmHelper)
  540.                     else
  541.                         if (aText[i] = '+') then
  542.                             Include(aChanModes, cmVoice)
  543.                         else
  544.                         begin
  545.                             aNickname := TextCopy(aText, i, MaxInt);
  546.                             Exit(True);
  547.                         end;
  548.         Inc(i);
  549.     end;
  550. end;
  551.  
  552. { TELIrc.TELIrcMsgParser }
  553.  
  554. constructor TIrcMsgParser.Create;
  555. begin
  556.     Clear;
  557. end;
  558.  
  559. destructor TIrcMsgParser.Destroy;
  560. begin
  561.     Clear;
  562.     inherited;
  563. end;
  564.  
  565. procedure TIrcMsgParser.AddParam(const aStart, aLength: integer);
  566. begin
  567.     Inc(FParamCount);
  568.     SetLength(FParamsArray, FParamCount);
  569.     FParamsArray[FParamCount - 1].Start  := aStart;
  570.     FParamsArray[FParamCount - 1].Length := aLength;
  571. end;
  572.  
  573. procedure TIrcMsgParser.AddTrailing(const aStart, aLength: integer);
  574. begin
  575.     Inc(FTrailingCount);
  576.     SetLength(FTrailingsArray, FTrailingCount);
  577.     FTrailingsArray[FTrailingCount - 1].Start  := aStart;
  578.     FTrailingsArray[FTrailingCount - 1].Length := aLength;
  579. end;
  580.  
  581. procedure TIrcMsgParser.Clear;
  582. begin
  583.     FRaw := CEmpty;
  584.  
  585.     FSourceType    := stNotPresent;
  586.     FSource.Start  := 0;
  587.     FSource.Length := 0;
  588.  
  589.     FSourceNickName.Start  := 0;
  590.     FSourceNickName.Length := 0;
  591.     FSourceUserName.Start  := 0;
  592.     FSourceUserName.Length := 0;
  593.     FSourceHostName.Start  := 0;
  594.     FSourceHostName.Length := 0;
  595.  
  596.     FCommand.Start  := 0;
  597.     FCommand.Length := 0;
  598.  
  599.     FParams.Start  := 0;
  600.     FParams.Length := 0;
  601.     SetLength(FParamsArray, 0);
  602.     FParamCount := 0;
  603.  
  604.     FTrailings.Start  := 0;
  605.     FTrailings.Length := 0;
  606.     SetLength(FTrailingsArray, 0);
  607.     FTrailingCount := 0;
  608. end;
  609.  
  610. function TIrcMsgParser.Parse(const aRaw: string): boolean;
  611. var
  612.     a: integer; // Copy start/Last Copy end position.
  613.     b: integer; // Parse cursor.
  614.     t: integer; // Temp cursor.
  615.     l: integer; // Length of input string.
  616.  
  617.     function DoTrim: boolean;
  618.     begin
  619.         Result := False;
  620.         while (b <= l) do
  621.         begin
  622.             if (b > l) then
  623.                 Exit(False);
  624.             if (FRaw[b] <= CSpace) then
  625.                 Inc(b)
  626.             else
  627.             begin
  628.                 a := b;
  629.                 Exit(True);
  630.             end;
  631.         end;
  632.     end;
  633.  
  634.     function FindSpace: boolean;
  635.     begin
  636.         b      := TextPos(FRaw, CSpace, True, b);
  637.         Result := (b <> 0);
  638.     end;
  639.  
  640. begin
  641.     // <message> ::=
  642.     //
  643.     // [':' <prefix> <SPACE> ] <command> <Trailing> <crlf>
  644.     //
  645.     // <prefix> ::=
  646.     // <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
  647.     //
  648.     // <command> ::=
  649.     // <letter> { <letter> } | <number> <number> <number>
  650.     //
  651.     // <SPACE> ::=
  652.     // ' ' { ' ' }
  653.     //
  654.     // <Trailing> ::=
  655.     // <SPACE> [ ':' <Trailings> | <middle> <Trailing> ]
  656.     //
  657.     // <middle> ::=
  658.     // <Any *non-empty* sequence of octets not including SPACE or NUL or CR or LF, the first of which may not be ':'>
  659.     //
  660.     // <Trailings> ::=
  661.     // <Any, possibly *empty*, sequence of octets not including NUL or CR or LF>
  662.     //
  663.     // <crlf> ::=
  664.     // CR LF
  665.  
  666.     { Check and initialize }
  667.     Result := False;
  668.     l      := Length(aRaw);
  669.     if (l = 0) then
  670.         Exit;
  671.  
  672.     Clear;
  673.     FRaw := aRaw;
  674.     a    := 1;
  675.     b    := 1;
  676.  
  677.     if (DoTrim = False) then
  678.         Exit;
  679.  
  680.     { Optional Message Source Prefix. }
  681.     if (FRaw[b] = CColon) then
  682.     begin
  683.         if (FindSpace = False) then
  684.             Exit;
  685.  
  686.         Inc(a);
  687.         FSource.Start  := a;
  688.         FSource.Length := (b - a);
  689.  
  690.         { If msg source is an user, split it to <nick>!<user>@<host>. }
  691.         t := TextPos(FRaw, CExclam, True, a);
  692.         if (t > 0) and (t < b) then
  693.         begin
  694.             FSourceNickName.Start  := a;
  695.             FSourceNickName.Length := (t - a);
  696.  
  697.             a := t;
  698.             Inc(a);
  699.             t := TextPos(FRaw, CMonkey, True, a);
  700.             if (t > 0) and (t < b) then
  701.             begin
  702.                 FSourceUserName.Start  := a;
  703.                 FSourceUserName.Length := (t - a);
  704.  
  705.                 a := t;
  706.                 Inc(a);
  707.                 t := TextPos(FRaw, CSpace, True, a);
  708.                 if (t = b) then
  709.                 begin
  710.                     FSourceHostName.Start  := a;
  711.                     FSourceHostName.Length := (t - a);
  712.  
  713.                     FSourceType := stUser;
  714.                 end;
  715.             end;
  716.         end
  717.         else
  718.             FSourceType := stServer;
  719.  
  720.         a := b;
  721.  
  722.         { Trim }
  723.         if (DoTrim = False) then
  724.             Exit;
  725.     end;
  726.  
  727.     { Parse out command }
  728.     if (FindSpace) then
  729.     begin
  730.         FCommand.Start  := a;
  731.         FCommand.Length := (b - a);
  732.  
  733.         a := b;
  734.         { If no params, exit. }
  735.         if (DoTrim = False) then
  736.             Exit(True);
  737.     end
  738.     else
  739.     begin
  740.         { If no params, exit }
  741.         FCommand.Start  := a;
  742.         FCommand.Length := (l - a);
  743.         Exit(True);
  744.     end;
  745.  
  746.     { Parse parameters }
  747.  
  748.     { If there are trailing params, parse middle first }
  749.     t := TextPos(FRaw, CColon, True, a);
  750.     if (t <> 0) then
  751.     begin
  752.         FParams.Start  := a;
  753.         FParams.Length := (t - a);
  754.         // Get the pre-Trailings params.
  755.         while (b < t) and (FindSpace) do
  756.         begin
  757.             AddParam(a, b - a);
  758.             Inc(b);
  759.             a := b;
  760.         end;
  761.  
  762.         // If no space before Trailings colon..
  763.         if (a < t) then
  764.             AddParam(a, t - a);
  765.  
  766.         // Move cursor to start of Trailings.
  767.         a := t + 1;
  768.         b := a;
  769.     end
  770.     else
  771.     begin
  772.         FParams.Start  := a;
  773.         FParams.Length := (l + 1 - a);
  774.     end;
  775.  
  776.     if (t <> 0) then
  777.     begin
  778.         FTrailings.Start  := t + 1;
  779.         FTrailings.Length := (l + 1 - a);
  780.     end;
  781.  
  782.     while (FindSpace) do
  783.     begin
  784.         if (t <> 0) then
  785.             AddTrailing(a, b - a)
  786.         else
  787.             AddParam(a, b - a);
  788.         Inc(b);
  789.         a := b;
  790.     end;
  791.  
  792.     // Last chunk.
  793.     if (b < l) then
  794.     begin
  795.         if (t <> 0) then
  796.             AddTrailing(a, MaxInt)
  797.         else
  798.             AddParam(a, MaxInt);
  799.     end;
  800.  
  801.     // Done.
  802.     Result := True;
  803. end;
  804.  
  805. function TIrcMsgParser.Source: string;
  806. begin
  807.     if (FSource.Length = 0) then
  808.         Result := CEmpty
  809.     else
  810.         Result := TextCopy(FRaw, FSource.Start, FSource.Length);
  811. end;
  812.  
  813. function TIrcMsgParser.SourceNickName: string;
  814. begin
  815.     if (FSourceNickName.Length = 0) then
  816.         Result := CEmpty
  817.     else
  818.         Result := TextCopy(FRaw, FSourceNickName.Start, FSourceNickName.Length);
  819. end;
  820.  
  821. function TIrcMsgParser.SourceUserName: string;
  822. begin
  823.     if (FSourceUserName.Length = 0) then
  824.         Result := CEmpty
  825.     else
  826.         Result := TextCopy(FRaw, FSourceUserName.Start, FSourceUserName.Length);
  827. end;
  828.  
  829. function TIrcMsgParser.SourceHostName: string;
  830. begin
  831.     if (FSourceHostName.Length = 0) then
  832.         Result := CEmpty
  833.     else
  834.         Result := TextCopy(FRaw, FSourceHostName.Start, FSourceHostName.Length);
  835. end;
  836.  
  837. function TIrcMsgParser.Command: string;
  838. begin
  839.     if (FCommand.Length = 0) then
  840.         Result := CEmpty
  841.     else
  842.         Result := TextCopy(FRaw, FCommand.Start, FCommand.Length);
  843. end;
  844.  
  845. function TIrcMsgParser.Params: string;
  846. begin
  847.     if (FParams.Length = 0) then
  848.         Result := CEmpty
  849.     else
  850.         Result := Trim(TextCopy(FRaw, FParams.Start, FParams.Length));
  851. end;
  852.  
  853. function TIrcMsgParser.ParamsFrom(const aIndex: integer): string;
  854. begin
  855.     if (aIndex < 0) or (aIndex >= FParamCount) then
  856.         Result := CEmpty
  857.     else
  858.         Result := TextCopy(FRaw, FParamsArray[aIndex].Start, MaxInt);
  859. end;
  860.  
  861. function TIrcMsgParser.Trailings: string;
  862. begin
  863.     if (FTrailings.Length = 0) then
  864.         Result := CEmpty
  865.     else
  866.         Result := TextCopy(FRaw, FTrailings.Start, FTrailings.Length);
  867. end;
  868.  
  869. function TIrcMsgParser.TrailingsFrom(const aIndex: integer): string;
  870. begin
  871.     if (aIndex < 0) or (aIndex >= FTrailingCount) then
  872.         Result := CEmpty
  873.     else
  874.         Result := TextCopy(FRaw, FTrailingsArray[aIndex].Start, MaxInt);
  875. end;
  876.  
  877. function TIrcMsgParser.AllParams: string;
  878. begin
  879.     if (FParams.Length > 0) then
  880.         Result := Params
  881.     else
  882.         Result := CEmpty;
  883.  
  884.     if (FParams.Length > 0) then
  885.     begin
  886.         if (FTrailings.Length > 0) then
  887.             Result := Result + CSpace + Trailings;
  888.     end
  889.     else
  890.     begin
  891.         if (FTrailings.Length > 0) then
  892.             Result := Trailings;
  893.     end;
  894. end;
  895.  
  896. function TIrcMsgParser.GetParam(aIndex: integer): string;
  897. begin
  898.     if (aIndex < 0) or (aIndex >= FParamCount) then
  899.         Result := CEmpty
  900.     else
  901.         Result := TextCopy(FRaw, FParamsArray[aIndex].Start, FParamsArray[aIndex].Length);
  902. end;
  903.  
  904. function TIrcMsgParser.GetTrailing(aIndex: integer): string;
  905. begin
  906.     if (aIndex < 0) or (aIndex >= FTrailingCount) then
  907.         Result := CEmpty
  908.     else
  909.         Result := TextCopy(FRaw, FTrailingsArray[aIndex].Start, FTrailingsArray[aIndex].Length);
  910. end;
  911.  
  912. { TIrcNickname }
  913.  
  914. function TIrcNickname.GetHostMask: string;
  915. begin
  916.     if (FNickname = CEmpty) or (FUsername = CEmpty) or (FHostname = CEmpty) then
  917.         Exit(CEmpty);
  918.  
  919.     Result := FNickname + CExclam + FUsername + CMonkey + FHostname;
  920. end;
  921.  
  922. procedure TIrcNickname.Assign(aSource: TIrcNickname);
  923. begin
  924.  
  925. end;
  926.  
  927. constructor TIrcNickname.Create(aList: TIrcNicknameList);
  928. begin
  929.     FNicknameList := aList;
  930.  
  931.     FIdentified := False;
  932.     FIrcOp      := False;
  933.     FBot        := False;
  934.     FAway       := False;
  935.     FHops       := 0;
  936. end;
  937.  
  938. destructor TIrcNickname.Destroy;
  939. begin
  940.  
  941.     inherited;
  942. end;
  943.  
  944. procedure TIrcNickname.UpdateHostmask(const aHostmask: string);
  945. begin
  946.  
  947. end;
  948.  
  949. function TIrcNickname.GetHostMask(const aType: byte): string;
  950. begin
  951.     if (FNickname = CEmpty) or (FUsername = CEmpty) or (FHostname = CEmpty) then
  952.         Exit(CEmpty);
  953.  
  954.     case aType of
  955.         0:
  956.         Result := FNickname + CExclam + CAsterisk + CMonkey + CAsterisk;
  957.         // nick!*@*
  958.         1:
  959.         Result := CAsterisk + CExclam + FUsername + CMonkey + CAsterisk;
  960.         // *!user@*
  961.         2:
  962.         Result := CAsterisk + CExclam + CAsterisk + CMonkey + FHostname;
  963.         // *!*@host
  964.         3:
  965.         Result := FNickname + CExclam + FUsername + CMonkey + CAsterisk;
  966.         // nick!user@*
  967.         4:
  968.         Result := CAsterisk + CExclam + FUsername + CMonkey + FHostname;
  969.         // *!user@host
  970.         5:
  971.         Result := FNickname + CExclam + CAsterisk + CMonkey + FHostname;
  972.         // nick!*@host
  973.         else
  974.         Result := FNickname + CExclam + FUsername + CMonkey + FHostname;
  975.         // nick!user@host
  976.     end;
  977. end;
  978.  
  979. function TIrcNickname.IsAdmin(const aChannel: string): boolean;
  980. begin
  981.  
  982. end;
  983.  
  984. function TIrcNickname.IsChanop(const aChannel: string): boolean;
  985. begin
  986.  
  987. end;
  988.  
  989. function TIrcNickname.IsHelper(const aChannel: string): boolean;
  990. begin
  991.  
  992. end;
  993.  
  994. function TIrcNickname.IsIdentified(const aNick: string): boolean;
  995. begin
  996.  
  997. end;
  998.  
  999. function TIrcNickname.IsOnChannel(const aChannel: string): boolean;
  1000. begin
  1001.  
  1002. end;
  1003.  
  1004. function TIrcNickname.IsOwner(const aChannel: string): boolean;
  1005. begin
  1006.  
  1007. end;
  1008.  
  1009. function TIrcNickname.IsRegular(const aChannel: string): boolean;
  1010. begin
  1011.  
  1012. end;
  1013.  
  1014. function TIrcNickname.IsVoice(const aChannel: string): boolean;
  1015. begin
  1016.  
  1017. end;
  1018.  
  1019. procedure TIrcNickname.SetHostname(const Value: string);
  1020. begin
  1021.     FHostname := Value;
  1022. end;
  1023.  
  1024. procedure TIrcNickname.SetNickname(const Value: string);
  1025. begin
  1026.     FNickname := Value;
  1027. end;
  1028.  
  1029. procedure TIrcNickname.SetRealName(const Value: string);
  1030. begin
  1031.     FRealname := Value;
  1032. end;
  1033.  
  1034. procedure TIrcNickname.SetUsermode(const Value: string);
  1035. begin
  1036.     FUserMode := Value;
  1037. end;
  1038.  
  1039. procedure TIrcNickname.SetUsername(const Value: string);
  1040. begin
  1041.     FUsername := Value;
  1042. end;
  1043.  
  1044. { TIrcNicknameList }
  1045.  
  1046. constructor TIrcNicknameList.Create(aIAL: TIrcIAL);
  1047. begin
  1048.     FIAL   := aIAL;
  1049.     FCount := 0;
  1050. end;
  1051.  
  1052. destructor TIrcNicknameList.Destroy;
  1053. begin
  1054.     Clear;
  1055.     inherited;
  1056. end;
  1057.  
  1058. function TIrcNicknameList.Add(const aNickname: string): TIrcNickname;
  1059. var
  1060.     nick       : TIrcNickname;
  1061.     insertIndex: integer;
  1062. begin
  1063.     insertIndex := GetInsertIndex(aNickname);
  1064.     if (insertIndex = -1) then
  1065.     begin
  1066.         FIAL.FIrc.EventError(Format('TIrcNicknameList.Add: Failed to add nickname "%s". Already exists.', [aNickname]));
  1067.         Exit;
  1068.     end;
  1069.  
  1070.     nick          := TIrcNickname.Create(Self);
  1071.     nick.Nickname := aNickname;
  1072.  
  1073.     SetLength(FNicknames, FCount + 1);
  1074.     if (insertIndex < FCount) then
  1075.         System.Move(FNicknames[insertIndex], FNicknames[insertIndex + 1], (FCount - insertIndex) * SizeOf(TIrcNickname));
  1076.     FNicknames[insertIndex] := nick;
  1077.     Inc(FCount);
  1078.     Result := nick;
  1079.     FIAL.IRC.CmdWho(aNickname);
  1080.     if (FIAL.DetailedTracking) then
  1081.         FIAL.IRC.CmdWhois(aNickname);
  1082. end;
  1083.  
  1084. procedure TIrcNicknameList.Del(const aNickname: string);
  1085. var
  1086.     idx: integer;
  1087. begin
  1088.     idx := IndexOf(aNickname);
  1089.     if (idx <> -1) then
  1090.     begin
  1091.         Dec(FCount);
  1092.         if (idx < FCount) then
  1093.             System.Move(FNicknames[idx + 1], FNicknames[idx], (FCount - idx) * SizeOf(TIrcNickname));
  1094.         SetLength(FNicknames, FCount);
  1095.     end;
  1096. end;
  1097.  
  1098. function TIrcNicknameList.IndexOf(const aNickname: string): integer;
  1099. var
  1100.     lowIndex    : integer;
  1101.     highIndex   : integer;
  1102.     centerIndex : integer;
  1103.     compareValue: integer;
  1104. begin
  1105.     lowIndex  := 0;
  1106.     highIndex := FCount - 1;
  1107.  
  1108.     while (lowIndex <= highIndex) do
  1109.     begin
  1110.         centerIndex  := (lowIndex + highIndex) div 2;
  1111.         compareValue := CompareText(aNickname, FNicknames[centerIndex].Nickname);
  1112.  
  1113.         if (compareValue < 0) then
  1114.         begin
  1115.             highIndex := centerIndex - 1;
  1116.         end
  1117.         else
  1118.         begin
  1119.             if (compareValue = 0) then
  1120.             begin
  1121.                 Exit(centerIndex);
  1122.             end
  1123.             else
  1124.             begin
  1125.                 if (compareValue > 0) then
  1126.                     lowIndex := centerIndex + 1;
  1127.             end;
  1128.         end;
  1129.     end;
  1130.     Result := -1;
  1131. end;
  1132.  
  1133. function TIrcNicknameList.Find(const aNickname: string): TIrcNickname;
  1134. var
  1135.     idx: integer;
  1136. begin
  1137.     idx := IndexOf(aNickname);
  1138.     if (idx = -1) then
  1139.         Result := nil
  1140.     else
  1141.         Result := FNicknames[idx];
  1142. end;
  1143.  
  1144. procedure TIrcNicknameList.Sort;
  1145. begin
  1146.     QuickSort(0, FCount - 1);
  1147. end;
  1148.  
  1149. procedure TIrcNicknameList.Clear;
  1150. var
  1151.     i: integer;
  1152. begin
  1153.     for i := 0 to FCount - 1 do
  1154.         FNicknames[i].Free;
  1155.     SetLength(FNicknames, 0);
  1156.     FCount := 0;
  1157. end;
  1158.  
  1159. procedure TIrcNicknameList.Exchange(aIndexA, aIndexB: integer);
  1160. var
  1161.     temp: TIrcNickname;
  1162. begin
  1163.     temp                := FNicknames[aIndexB];
  1164.     FNicknames[aIndexB] := FNicknames[aIndexA];
  1165.     FNicknames[aIndexA] := temp;
  1166. end;
  1167.  
  1168. procedure TIrcNicknameList.QuickSort(aStart, aEnd: integer);
  1169. var
  1170.     a: integer;
  1171.     i: integer;
  1172.     j: integer;
  1173.     p: integer;
  1174. begin
  1175.     if (FCount <= 1) then
  1176.         Exit;
  1177.     a := aStart;
  1178.     repeat
  1179.         i := a;
  1180.         j := aEnd;
  1181.         p := (a + aEnd) shr 1;
  1182.         repeat
  1183.             while (CompareText(FNicknames[i].Nickname, FNicknames[p].Nickname) < 0) do
  1184.                 Inc(i);
  1185.             while (CompareText(FNicknames[j].Nickname, FNicknames[p].Nickname) > 0) do
  1186.                 Dec(j);
  1187.             if (i <= j) then
  1188.             begin
  1189.                 if (i <> j) then
  1190.                     Exchange(i, j);
  1191.                 if (p = i) then
  1192.                     p := j
  1193.                 else
  1194.                     if (p = j) then
  1195.                         p := i;
  1196.                 Inc(i);
  1197.                 Dec(j);
  1198.             end;
  1199.         until (i > j);
  1200.         if (a < j) then
  1201.             QuickSort(a, j);
  1202.         a := i;
  1203.     until (i >= aEnd);
  1204. end;
  1205.  
  1206. function TIrcNicknameList.GetInsertIndex(const aNickname: string): integer;
  1207. var
  1208.     lowIndex    : integer;
  1209.     highIndex   : integer;
  1210.     centerIndex : integer;
  1211.     compareValue: integer;
  1212. begin
  1213.     lowIndex  := 0;
  1214.     highIndex := FCount - 1;
  1215.  
  1216.     while (lowIndex <= highIndex) do
  1217.     begin
  1218.         centerIndex  := (lowIndex + highIndex) div 2;
  1219.         compareValue := CompareText(aNickname, FNicknames[centerIndex].Nickname);
  1220.  
  1221.         if (compareValue < 0) then
  1222.         begin
  1223.             highIndex := centerIndex - 1;
  1224.         end
  1225.         else
  1226.         begin
  1227.             if (compareValue = 0) then
  1228.             begin
  1229.                 Result := -1;
  1230.                 FIAL.FIrc.EventError('TIrcNicknameList.GetInsertIndex: Nickname already exists.');
  1231.                 Exit;
  1232.             end
  1233.             else
  1234.             begin
  1235.                 if (compareValue > 0) then
  1236.                     lowIndex := centerIndex + 1;
  1237.             end;
  1238.         end;
  1239.     end;
  1240.     Result := lowIndex;
  1241. end;
  1242.  
  1243. { TIrcChannelNickname }
  1244.  
  1245. constructor TIrcChannelNickname.Create(aList: TIrcChannelNicknameList);
  1246. begin
  1247.     FChannelNicknameList := aList;
  1248.     FNickname            := nil;
  1249.     FChanModes           := [];
  1250. end;
  1251.  
  1252. procedure TIrcChannelNickname.Assign(aSource: TIrcChannelNickname);
  1253. begin
  1254.     Nickname  := aSource.Nickname;
  1255.     ChanModes := aSource.ChanModes;
  1256. end;
  1257.  
  1258. { TIrcChannelNicknameList }
  1259.  
  1260. constructor TIrcChannelNicknameList.Create(aChannel: TIrcChannel);
  1261. begin
  1262.     FChannel := aChannel;
  1263.     FCount   := 0;
  1264. end;
  1265.  
  1266. destructor TIrcChannelNicknameList.Destroy;
  1267. begin
  1268.     Clear;
  1269.     inherited;
  1270. end;
  1271.  
  1272. function TIrcChannelNicknameList.Add(aNickname: TIrcNickname; const aChanModes: TIrcChanModes): TIrcChannelNickname;
  1273. var
  1274.     nick       : TIrcChannelNickname;
  1275.     insertIndex: integer;
  1276. begin
  1277.     insertIndex := GetInsertIndex(aNickname.Nickname);
  1278.     if (insertIndex = -1) then
  1279.     begin
  1280.         Channel.FChannelList.IAL.FIrc.EventError('TIrcChannelNicknameList.Add: Failed to add nickname. Already exists.');
  1281.         Exit;
  1282.     end;
  1283.  
  1284.     nick           := TIrcChannelNickname.Create(Self);
  1285.     nick.Nickname  := aNickname;
  1286.     nick.ChanModes := aChanModes;
  1287.  
  1288.     SetLength(FNicknames, FCount + 1);
  1289.     if (insertIndex < FCount) then
  1290.         System.Move(FNicknames[insertIndex], FNicknames[insertIndex + 1], (FCount - insertIndex) * SizeOf(TIrcChannelNickname));
  1291.     FNicknames[insertIndex] := nick;
  1292.     Inc(FCount);
  1293.     Result := nick;
  1294. end;
  1295.  
  1296. procedure TIrcChannelNicknameList.Del(const aNickname: string);
  1297. var
  1298.     idx: integer;
  1299. begin
  1300.     idx := IndexOf(aNickname);
  1301.     if (idx <> -1) then
  1302.     begin
  1303.         Dec(FCount);
  1304.         if (idx < FCount) then
  1305.             System.Move(FNicknames[idx + 1], FNicknames[idx], (FCount - idx) * SizeOf(TIrcChannelNickname));
  1306.         SetLength(FNicknames, FCount);
  1307.     end;
  1308. end;
  1309.  
  1310. function TIrcChannelNicknameList.IndexOf(const aNickname: string): integer;
  1311. var
  1312.     lowIndex    : integer;
  1313.     highIndex   : integer;
  1314.     centerIndex : integer;
  1315.     compareValue: integer;
  1316. begin
  1317.     lowIndex  := 0;
  1318.     highIndex := FCount - 1;
  1319.  
  1320.     while (lowIndex <= highIndex) do
  1321.     begin
  1322.         centerIndex  := (lowIndex + highIndex) div 2;
  1323.         compareValue := CompareText(aNickname, FNicknames[centerIndex].Nickname.Nickname);
  1324.  
  1325.         if (compareValue < 0) then
  1326.         begin
  1327.             highIndex := centerIndex - 1;
  1328.         end
  1329.         else
  1330.         begin
  1331.             if (compareValue = 0) then
  1332.             begin
  1333.                 Exit(centerIndex);
  1334.             end
  1335.             else
  1336.             begin
  1337.                 if (compareValue > 0) then
  1338.                     lowIndex := centerIndex + 1;
  1339.             end;
  1340.         end;
  1341.     end;
  1342.     Result := -1;
  1343. end;
  1344.  
  1345. function TIrcChannelNicknameList.Find(const aNickname: string): TIrcChannelNickname;
  1346. var
  1347.     idx: integer;
  1348. begin
  1349.     idx := IndexOf(aNickname);
  1350.     if (idx = -1) then
  1351.         Result := nil
  1352.     else
  1353.         Result := FNicknames[idx];
  1354. end;
  1355.  
  1356. procedure TIrcChannelNicknameList.Sort;
  1357. begin
  1358.     QuickSort(0, FCount - 1);
  1359. end;
  1360.  
  1361. procedure TIrcChannelNicknameList.Clear;
  1362. var
  1363.     i: integer;
  1364. begin
  1365.     for i := 0 to FCount - 1 do
  1366.         FNicknames[i].Free;
  1367.     SetLength(FNicknames, 0);
  1368.     FCount := 0;
  1369. end;
  1370.  
  1371. procedure TIrcChannelNicknameList.Exchange(aIndexA, aIndexB: integer);
  1372. var
  1373.     temp: TIrcChannelNickname;
  1374. begin
  1375.     temp                := FNicknames[aIndexB];
  1376.     FNicknames[aIndexB] := FNicknames[aIndexA];
  1377.     FNicknames[aIndexA] := temp;
  1378. end;
  1379.  
  1380. procedure TIrcChannelNicknameList.QuickSort(aStart, aEnd: integer);
  1381. var
  1382.     a: integer;
  1383.     i: integer;
  1384.     j: integer;
  1385.     p: integer;
  1386. begin
  1387.     if (FCount <= 1) then
  1388.         Exit;
  1389.     a := aStart;
  1390.     repeat
  1391.         i := a;
  1392.         j := aEnd;
  1393.         p := (a + aEnd) shr 1;
  1394.         repeat
  1395.             while (CompareText(FNicknames[i].Nickname.Nickname, FNicknames[p].Nickname.Nickname) < 0) do
  1396.                 Inc(i);
  1397.             while (CompareText(FNicknames[j].Nickname.Nickname, FNicknames[p].Nickname.Nickname) > 0) do
  1398.                 Dec(j);
  1399.             if (i <= j) then
  1400.             begin
  1401.                 if (i <> j) then
  1402.                     Exchange(i, j);
  1403.                 if (p = i) then
  1404.                     p := j
  1405.                 else
  1406.                     if (p = j) then
  1407.                         p := i;
  1408.                 Inc(i);
  1409.                 Dec(j);
  1410.             end;
  1411.         until (i > j);
  1412.         if (a < j) then
  1413.             QuickSort(a, j);
  1414.         a := i;
  1415.     until (i >= aEnd);
  1416. end;
  1417.  
  1418. function TIrcChannelNicknameList.GetInsertIndex(const aNickname: string): integer;
  1419. var
  1420.     lowIndex    : integer;
  1421.     highIndex   : integer;
  1422.     centerIndex : integer;
  1423.     compareValue: integer;
  1424. begin
  1425.     lowIndex  := 0;
  1426.     highIndex := FCount - 1;
  1427.  
  1428.     while (lowIndex <= highIndex) do
  1429.     begin
  1430.         centerIndex  := (lowIndex + highIndex) div 2;
  1431.         compareValue := CompareText(aNickname, FNicknames[centerIndex].Nickname.Nickname);
  1432.  
  1433.         if (compareValue < 0) then
  1434.         begin
  1435.             highIndex := centerIndex - 1;
  1436.         end
  1437.         else
  1438.         begin
  1439.             if (compareValue = 0) then
  1440.             begin
  1441.                 Result := -1;
  1442.                 Channel.FChannelList.IAL.FIrc.EventError('TIrcChannelNicknameList.GetInsertIndex: Nickname already exists.');
  1443.                 Exit;
  1444.             end
  1445.             else
  1446.             begin
  1447.                 if (compareValue > 0) then
  1448.                     lowIndex := centerIndex + 1;
  1449.             end;
  1450.         end;
  1451.     end;
  1452.     Result := lowIndex;
  1453. end;
  1454.  
  1455. function TIrcChannelNicknameList.GetNickname(const aIndex: integer): TIrcChannelNickname;
  1456. begin
  1457.     if (aIndex < 0) or (aIndex >= FCount) then
  1458.     begin
  1459.         FChannel.FChannelList.FIAL.FIrc.EventError(Format('TIrcChannelNicknameList.GetNickname(%d) out of bounds(%d).', [aIndex, FCount]));
  1460.         Exit(nil);
  1461.     end;
  1462.     Result := FNicknames[aIndex];
  1463. end;
  1464.  
  1465. procedure TIrcChannelNicknameList.SetNickname(const aIndex: integer; const Value: TIrcChannelNickname);
  1466. begin
  1467.     if (aIndex < 0) or (aIndex >= FCount) then
  1468.     begin
  1469.         FChannel.FChannelList.FIAL.FIrc.EventError(Format('TIrcChannelNicknameList.SetNickname(%d) out of bounds(%d).', [aIndex, FCount]));
  1470.         Exit;
  1471.     end;
  1472.     FNicknames[aIndex].Assign(Value);
  1473. end;
  1474.  
  1475. { TIrcChannel }
  1476.  
  1477. constructor TIrcChannel.Create(aList: TIrcChannelList);
  1478. begin
  1479.     FChannelList         := aList;
  1480.     FChannelNicknameList := TIrcChannelNicknameList.Create(Self);
  1481. end;
  1482.  
  1483. destructor TIrcChannel.Destroy;
  1484. begin
  1485.     FChannelNicknameList.Free;
  1486.     inherited;
  1487. end;
  1488.  
  1489. procedure TIrcChannel.Assign(aSource: TIrcChannel);
  1490. begin
  1491.  
  1492. end;
  1493.  
  1494. { TIrcChannelList }
  1495.  
  1496. constructor TIrcChannelList.Create(aIAL: TIrcIAL);
  1497. begin
  1498.     FIAL   := aIAL;
  1499.     FCount := 0;
  1500. end;
  1501.  
  1502. destructor TIrcChannelList.Destroy;
  1503. begin
  1504.     Clear;
  1505.     inherited;
  1506. end;
  1507.  
  1508. function TIrcChannelList.Add(const aChannel: string): TIrcChannel;
  1509. var
  1510.     Channel    : TIrcChannel;
  1511.     insertIndex: integer;
  1512. begin
  1513.     insertIndex := GetInsertIndex(aChannel);
  1514.     if (insertIndex = -1) then
  1515.     begin
  1516.         FIAL.FIrc.EventError('TIrcChannelList.Add: Failed to add channel. Already exists.');
  1517.         Exit;
  1518.     end;
  1519.  
  1520.     Channel             := TIrcChannel.Create(Self);
  1521.     Channel.ChannelName := aChannel;
  1522.  
  1523.     SetLength(FChannels, FCount + 1);
  1524.     if (insertIndex < FCount) then
  1525.         System.Move(FChannels[insertIndex], FChannels[insertIndex + 1], (FCount - insertIndex) * SizeOf(TIrcChannel));
  1526.     FChannels[insertIndex] := Channel;
  1527.     Inc(FCount);
  1528.     Result := Channel;
  1529. end;
  1530.  
  1531. procedure TIrcChannelList.Del(const aChannel: string);
  1532. var
  1533.     idx: integer;
  1534. begin
  1535.     idx := IndexOf(aChannel);
  1536.     if (idx <> -1) then
  1537.     begin
  1538.         Dec(FCount);
  1539.         if (idx < FCount) then
  1540.             System.Move(FChannels[idx + 1], FChannels[idx], (FCount - idx) * SizeOf(TIrcChannel));
  1541.         SetLength(FChannels, FCount);
  1542.     end;
  1543. end;
  1544.  
  1545. function TIrcChannelList.IndexOf(const aChannel: string): integer;
  1546. var
  1547.     lowIndex    : integer;
  1548.     highIndex   : integer;
  1549.     centerIndex : integer;
  1550.     compareValue: integer;
  1551. begin
  1552.     lowIndex  := 0;
  1553.     highIndex := FCount - 1;
  1554.  
  1555.     while (lowIndex <= highIndex) do
  1556.     begin
  1557.         centerIndex  := (lowIndex + highIndex) div 2;
  1558.         compareValue := CompareText(aChannel, FChannels[centerIndex].ChannelName);
  1559.  
  1560.         if (compareValue < 0) then
  1561.         begin
  1562.             highIndex := centerIndex - 1;
  1563.         end
  1564.         else
  1565.         begin
  1566.             if (compareValue = 0) then
  1567.             begin
  1568.                 Exit(centerIndex);
  1569.             end
  1570.             else
  1571.             begin
  1572.                 if (compareValue > 0) then
  1573.                     lowIndex := centerIndex + 1;
  1574.             end;
  1575.         end;
  1576.     end;
  1577.     Result := -1;
  1578. end;
  1579.  
  1580. function TIrcChannelList.Find(const aChannel: string): TIrcChannel;
  1581. var
  1582.     idx: integer;
  1583. begin
  1584.     idx := IndexOf(aChannel);
  1585.     if (idx = -1) then
  1586.         Result := nil
  1587.     else
  1588.         Result := FChannels[idx];
  1589. end;
  1590.  
  1591. procedure TIrcChannelList.Sort;
  1592. begin
  1593.     QuickSort(0, FCount - 1);
  1594. end;
  1595.  
  1596. procedure TIrcChannelList.Clear;
  1597. var
  1598.     i: integer;
  1599. begin
  1600.     for i := 0 to FCount - 1 do
  1601.         FChannels[i].Free;
  1602.     SetLength(FChannels, 0);
  1603.     FCount := 0;
  1604. end;
  1605.  
  1606. procedure TIrcChannelList.Exchange(aIndexA, aIndexB: integer);
  1607. var
  1608.     temp: TIrcChannel;
  1609. begin
  1610.     temp               := FChannels[aIndexB];
  1611.     FChannels[aIndexB] := FChannels[aIndexA];
  1612.     FChannels[aIndexA] := temp;
  1613. end;
  1614.  
  1615. procedure TIrcChannelList.QuickSort(aStart, aEnd: integer);
  1616. var
  1617.     a: integer;
  1618.     i: integer;
  1619.     j: integer;
  1620.     p: integer;
  1621. begin
  1622.     if (FCount <= 1) then
  1623.         Exit;
  1624.     a := aStart;
  1625.     repeat
  1626.         i := a;
  1627.         j := aEnd;
  1628.         p := (a + aEnd) shr 1;
  1629.         repeat
  1630.             while (CompareText(FChannels[i].ChannelName, FChannels[p].ChannelName) < 0) do
  1631.                 Inc(i);
  1632.             while (CompareText(FChannels[j].ChannelName, FChannels[p].ChannelName) > 0) do
  1633.                 Dec(j);
  1634.             if (i <= j) then
  1635.             begin
  1636.                 if (i <> j) then
  1637.                     Exchange(i, j);
  1638.                 if (p = i) then
  1639.                     p := j
  1640.                 else
  1641.                     if (p = j) then
  1642.                         p := i;
  1643.                 Inc(i);
  1644.                 Dec(j);
  1645.             end;
  1646.         until (i > j);
  1647.         if (a < j) then
  1648.             QuickSort(a, j);
  1649.         a := i;
  1650.     until (i >= aEnd);
  1651. end;
  1652.  
  1653. function TIrcChannelList.GetInsertIndex(const aChannel: string): integer;
  1654. var
  1655.     lowIndex    : integer;
  1656.     highIndex   : integer;
  1657.     centerIndex : integer;
  1658.     compareValue: integer;
  1659. begin
  1660.     lowIndex  := 0;
  1661.     highIndex := FCount - 1;
  1662.  
  1663.     while (lowIndex <= highIndex) do
  1664.     begin
  1665.         centerIndex  := (lowIndex + highIndex) div 2;
  1666.         compareValue := CompareText(aChannel, FChannels[centerIndex].ChannelName);
  1667.  
  1668.         if (compareValue < 0) then
  1669.         begin
  1670.             highIndex := centerIndex - 1;
  1671.         end
  1672.         else
  1673.         begin
  1674.             if (compareValue = 0) then
  1675.             begin
  1676.                 Result := -1;
  1677.                 FIAL.FIrc.EventError('TIrcChannelList.GetInsertIndex: Channel already exists.');
  1678.                 Exit;
  1679.             end
  1680.             else
  1681.             begin
  1682.                 if (compareValue > 0) then
  1683.                     lowIndex := centerIndex + 1;
  1684.             end;
  1685.         end;
  1686.     end;
  1687.     Result := lowIndex;
  1688. end;
  1689.  
  1690. { TIrcIAL }
  1691.  
  1692. constructor TIrcIAL.Create(aIrc: TIrc);
  1693. begin
  1694.     FIrc := aIrc;
  1695.  
  1696.     FTokenizer := TTokenizer.Create;
  1697.  
  1698.     FNicknameList     := TIrcNicknameList.Create(Self);
  1699.     FChannelList      := TIrcChannelList.Create(Self);
  1700.     FEnabled          := True;
  1701.     FDetailedTracking := True;
  1702. end;
  1703.  
  1704. destructor TIrcIAL.Destroy;
  1705. begin
  1706.     FChannelList.Free;
  1707.     FNicknameList.Free;
  1708.     Clear;
  1709.     FTokenizer.Free;
  1710. end;
  1711.  
  1712. procedure TIrcIAL.Clear;
  1713. begin
  1714.     FNicknameList.Clear;
  1715.     FChannelList.Clear;
  1716. end;
  1717.  
  1718. procedure TIrcIAL.NickJoinedChannel(const aNickname, aHostmask, aChannel: string);
  1719. var
  1720.     nick    : TIrcNickname;
  1721.     chan    : TIrcChannel;
  1722.     channick: TIrcChannelNickname;
  1723. begin
  1724.     nick := FNicknameList.Find(aNickname);
  1725.     if (nick = nil) then
  1726.         nick := FNicknameList.Add(aNickname);
  1727.     nick.UpdateHostmask(aHostmask);
  1728.  
  1729.     chan := FChannelList.Find(aChannel);
  1730.     if (chan = nil) then
  1731.         chan := FChannelList.Add(aChannel);
  1732.  
  1733.     channick := chan.Nicknames.Find(aNickname);
  1734.     if (channick <> nil) then
  1735.         Exit;
  1736.  
  1737.     channick := chan.Nicknames.Add(nick);
  1738. end;
  1739.  
  1740. procedure TIrcIAL.NickPartedChannel(const aNickname, aChannel: string);
  1741. var
  1742.     chan: TIrcChannel;
  1743. begin
  1744.     chan := FChannelList.Find(aChannel);
  1745.     if (chan = nil) then
  1746.         chan := FChannelList.Add(aChannel);
  1747.  
  1748.     chan.Nicknames.Del(aNickname);
  1749.  
  1750.     if (chan.Nicknames.Count = 0) then
  1751.         FChannelList.Del(chan.ChannelName);
  1752. end;
  1753.  
  1754. procedure TIrcIAL.NickChange(const aOldNickname, aNewNickname: string);
  1755. var
  1756.     nick: TIrcNickname;
  1757.     i   : integer;
  1758. begin
  1759.     nick := FNicknameList.Find(aOldNickname);
  1760.     if (nick = nil) then
  1761.         nick := FNicknameList.Add(aOldNickname);
  1762.  
  1763.     nick.Nickname := aNewNickname;
  1764.  
  1765.     FNicknameList.Sort;
  1766.     for i := 0 to FChannelList.FCount - 1 do
  1767.         FChannelList.FChannels[i].Nicknames.Sort;
  1768. end;
  1769.  
  1770. procedure TIrcIAL.NickIsIdentified(const aNickname: string);
  1771. var
  1772.     nick: TIrcNickname;
  1773. begin
  1774.     nick := FNicknameList.Find(aNickname);
  1775.     if (nick <> nil) then
  1776.         nick.Identified := True;
  1777. end;
  1778.  
  1779. procedure TIrcIAL.NickKickedFromChannel(const aNickname, aChannel: string);
  1780. begin
  1781.     NickPartedChannel(aNickname, aChannel);
  1782. end;
  1783.  
  1784. procedure TIrcIAL.NickQuit(const aNickname: string);
  1785. var
  1786.     i: integer;
  1787. begin
  1788.     FNicknameList.Del(aNickname);
  1789.     for i := 0 to FChannelList.FCount - 1 do
  1790.         FChannelList.FChannels[i].Nicknames.Del(aNickname);
  1791. end;
  1792.  
  1793. procedure TIrcIAL.NamesList(const aChannel, aNamesList: string);
  1794. var
  1795.     tkn    : TTokenizer;
  1796.     i      : integer;
  1797.     nick   : TIrcNickname;
  1798.     chan   : TIrcChannel;
  1799.     channick: TIrcChannelNickname;
  1800.     nickstr: string;
  1801.     chmode : TIrcChanModes;
  1802. begin
  1803.     chan := FChannelList.Find(aChannel);
  1804.     if (chan = nil) then
  1805.         FChannelList.Add(aChannel);
  1806.  
  1807.     FTokenizer.Split(aNamesList, CSpace, [soCSSep]);
  1808.     for i := 0 to FTokenizer.Count - 1 do
  1809.     begin
  1810.         SplitNickAndChanmodes(FTokenizer[i], chmode, nickstr);
  1811.         nick := FNicknameList.Find(nickstr);
  1812.         if (nick = nil) then
  1813.             nick := FNicknameList.Add(nickstr);
  1814.         channick := chan.Nicknames.Find(nickstr);
  1815.         if (channick = nil) then
  1816.             chan.Nicknames.Add(nick, chmode)
  1817.         else
  1818.             channick.ChanModes := chmode;
  1819.     end;
  1820. end;
  1821.  
  1822. function TIrcIAL.IsNicknameIdentified(const aNickname: string): boolean;
  1823. var
  1824.     nick: TIrcNickname;
  1825. begin
  1826.     nick := FNicknameList.Find(aNickname);
  1827.     if (nick <> nil) then
  1828.         Result := nick.Identified
  1829.     else
  1830.         Result := False;
  1831. end;
  1832.  
  1833. function TIrcIAL.GetNicknameByName(const aNickname: string): TIrcNickname;
  1834. begin
  1835.     Result := FNicknameList.Find(aNickname);
  1836. end;
  1837.  
  1838. function TIrcIAL.GetNicknameByIndex(const aIndex: integer): TIrcNickname;
  1839. begin
  1840.     if (aIndex < 0) or (aIndex >= FNicknameList.FCount) then
  1841.     begin
  1842.         IRC.EventError(Format('TIrcIAL.GetNicknameByIndex(%d) out of bounds(%d).', [aIndex, FNicknameList.FCount]));
  1843.         Exit(nil);
  1844.     end;
  1845.     Result := FNicknameList.FNicknames[aIndex];
  1846. end;
  1847.  
  1848. function TIrcIAL.GetNicknameCount: integer;
  1849. begin
  1850.     Result := FNicknameList.FCount;
  1851. end;
  1852.  
  1853. function TIrcIAL.GetChannelByName(const aChannel: string): TIrcChannel;
  1854. begin
  1855.     Result := FChannelList.Find(aChannel);
  1856. end;
  1857.  
  1858. function TIrcIAL.GetChannelByIndex(const aIndex: integer): TIrcChannel;
  1859. begin
  1860.     if (aIndex < 0) or (aIndex >= FChannelList.FCount) then
  1861.     begin
  1862.         IRC.EventError(Format('TIrcIAL.GetChannelByIndex(%d) out of bounds(%d).', [aIndex, FChannelList.FCount]));
  1863.         Exit(nil);
  1864.     end;
  1865.     Result := FChannelList.FChannels[aIndex];
  1866. end;
  1867.  
  1868. function TIrcIAL.GetChannelCount: integer;
  1869. begin
  1870.     Result := FChannelList.FCount;
  1871. end;
  1872.  
  1873. procedure TIrcIAL.SetNicknameByIndex(const aIndex: integer; const Value: TIrcNickname);
  1874. begin
  1875.     if (aIndex < 0) or (aIndex >= FNicknameList.FCount) then
  1876.     begin
  1877.         IRC.EventError(Format('TIrcIAL.SetNicknameByIndex(%d) out of bounds(%d).', [aIndex, FNicknameList.FCount]));
  1878.         Exit;
  1879.     end;
  1880.     FNicknameList.FNicknames[aIndex].Assign(Value);
  1881. end;
  1882.  
  1883. procedure TIrcIAL.WhoText(const aText: string);
  1884. var
  1885.     nick: TIrcNickname;
  1886. begin
  1887.     FTokenizer.Split(aText, CSpace, [soCSSep]);
  1888.     nick := FNicknameList.Find(FTokenizer[4]);
  1889.     if (nick = nil) then
  1890.         Exit;
  1891.  
  1892.     nick.Username := FTokenizer[1];
  1893.     nick.Hostname := FTokenizer[2];
  1894.     nick.Leaf     := FTokenizer[3];
  1895.     if (TextInText(FTokenizer[5], 'G', True)) then
  1896.         nick.Away := True;
  1897.     if (TextInText(FTokenizer[5], '*', True)) then
  1898.         nick.IrcOp := True;
  1899.     nick.Hops      := StrToIntDef(TextRight(FTokenizer[6], Length(FTokenizer[6]) - 1), 0);
  1900.     nick.Realname  := FTokenizer.FromToken(7);
  1901. end;
  1902.  
  1903. procedure TIrcIAL.SetChannelByIndex(const aIndex: integer; const Value: TIrcChannel);
  1904. begin
  1905.     if (aIndex < 0) or (aIndex >= FChannelList.FCount) then
  1906.     begin
  1907.         IRC.EventError(Format('TIrcIAL.SetChannelByIndex(%d) out of bounds(%d).', [aIndex, FChannelList.FCount]));
  1908.         Exit;
  1909.     end;
  1910.     FChannelList.FChannels[aIndex].Assign(Value);
  1911. end;
  1912.  
  1913. procedure TIrcIAL.SetEnabled(const Value: boolean);
  1914. begin
  1915.     if (FEnabled = Value) then
  1916.         Exit;
  1917.     FEnabled := Value;
  1918. end;
  1919.  
  1920. { TIrc }
  1921.  
  1922. constructor TIrc.Create(aOwner: TComponent);
  1923. begin
  1924.     inherited Create(aOwner);
  1925.     FAltNicknames := TStringList.Create;
  1926.     FTokenizer    := TTokenizer.Create;
  1927.     FParser       := TIrcMsgParser.Create;
  1928.     FUserMode     := '+ix';
  1929.  
  1930.     FIAL := TIrcIAL.Create(Self);
  1931.  
  1932.     FRejoinWhenKicked    := True;
  1933.     FReconnectWhenKilled := True;
  1934. end;
  1935.  
  1936. destructor TIrc.Destroy;
  1937. begin
  1938.     FIAL.Free;
  1939.     FAltNicknames.Free;
  1940.     FParser.Free;
  1941.     FTokenizer.Free;
  1942.     inherited;
  1943. end;
  1944.  
  1945. procedure TIrc.Assign(aSource: TPersistent);
  1946. begin
  1947.     if (aSource is TIrc) then
  1948.     begin
  1949.         Nickname            := TIrc(aSource).Nickname;
  1950.         Username            := TIrc(aSource).Username;
  1951.         Realname            := TIrc(aSource).Realname;
  1952.         Password            := TIrc(aSource).Password;
  1953.         Usermode            := TIrc(aSource).Usermode;
  1954.         RejoinWhenKicked    := TIrc(aSource).RejoinWhenKicked;
  1955.         ReconnectWhenKilled := TIrc(aSource).ReconnectWhenKilled;
  1956.         AltNicknames.Assign(TIrc(aSource).AltNicknames);
  1957.     end
  1958.     else
  1959.         inherited;
  1960. end;
  1961.  
  1962. procedure TIrc.EventClose(const aError: word; const aClosedByRemote: boolean);
  1963. begin
  1964.     inherited;
  1965.     FIAL.Clear;
  1966. end;
  1967.  
  1968. procedure TIrc.EventConnect(const aError: word);
  1969. begin
  1970.     inherited;
  1971.  
  1972.     { Client Registration }
  1973.     if (FPassword <> CEmpty) then
  1974.         Raw('PASS' + CSpace + FPassword);
  1975.     Raw('NICK' + CSpace + FNickname);
  1976.     // Usermode gets stripped of any space separated flags to retain proper format
  1977.     // If there are any flags in UserMode you have to call CmdMode again after 001
  1978.     // Some flags are Oper only so..
  1979.     Raw('USER' + CSpace + FUsername + CSpace + TextFetchLeft(FUserMode, CSpace, True) + CSpace + CAsterisk + CSpace + CColon + FRealname);
  1980. end;
  1981.  
  1982. procedure TIrc.EventCTCP(const aFromNick, aFromHost, aTarget, aCommand, aParameters: string);
  1983. begin
  1984.     if (Assigned(FOnCTCP)) then
  1985.         FOnCTCP(Self, aFromNick, aFromHost, aTarget, aCommand, aParameters);
  1986. end;
  1987.  
  1988. procedure TIrc.EventJoin(const aNick, aHost, aChannel: string);
  1989. begin
  1990.     if (IAL.Enabled) then
  1991.         IAL.NickJoinedChannel(aNick, aHost, aChannel);
  1992.  
  1993.     if (Assigned(FOnJoin)) then
  1994.         FOnJoin(Self, FParser.SourceNickName, FParser.Source, FParser.AllParams);
  1995. end;
  1996.  
  1997. procedure TIrc.EventKick(const aKicker, aKicked, aChannel, aReason: string);
  1998. begin
  1999.     if (IAL.Enabled) then
  2000.         IAL.NickKickedFromChannel(aKicked, aChannel);
  2001.  
  2002.     if (Assigned(FOnKick)) then
  2003.         FOnKick(Self, aKicker, aKicked, aChannel, aReason);
  2004. end;
  2005.  
  2006. procedure TIrc.EventKill(const aKiller, aKilled, aReason: string);
  2007. begin
  2008.     if (Assigned(FOnKill)) then
  2009.         FOnKill(Self, aKiller, aKilled, aReason);
  2010. end;
  2011.  
  2012. procedure TIrc.EventMode(const aSource, aTarget, aMode: string);
  2013. begin
  2014.     if (Assigned(FOnMode)) then
  2015.         FOnMode(Self, aSource, aTarget, aMode);
  2016. end;
  2017.  
  2018. procedure TIrc.EventNick(const aOldNick, aNewNick, aHost: string);
  2019. begin
  2020.     if (Assigned(FOnNick)) then
  2021.         FOnNick(Self, aOldNick, aNewNick, aHost);
  2022. end;
  2023.  
  2024. procedure TIrc.EventNotice(const aFromNick, aFromHost, aTarget, aText: string);
  2025. begin
  2026.     if (Assigned(FOnNotice)) then
  2027.         FOnNotice(Self, aFromNick, aFromHost, aTarget, aText);
  2028. end;
  2029.  
  2030. procedure TIrc.EventPart(const aNick, aHost, aChannel, aReason: string);
  2031. begin
  2032.     if (IAL.Enabled) then
  2033.         IAL.NickPartedChannel(aNick, aChannel);
  2034.  
  2035.     if (Assigned(FOnPart)) then
  2036.         FOnPart(Self, aNick, aHost, aChannel, aReason);
  2037. end;
  2038.  
  2039. procedure TIrc.EventPrivMsg(const aFromNick, aFromHost, aTarget, aText: string);
  2040. begin
  2041.     if (Assigned(FOnPrivMsg)) then
  2042.         FOnPrivMsg(Self, aFromNick, aFromHost, aTarget, aText);
  2043. end;
  2044.  
  2045. procedure TIrc.EventQuit(const aNick, aHost, aReason: string);
  2046. begin
  2047.     if (Assigned(FOnQuit)) then
  2048.         FOnQuit(Self, aNick, aHost, aReason);
  2049. end;
  2050.  
  2051. procedure TIrc.EventRaw(const aCmd: string; const aIn: boolean; var aBlockIt: boolean);
  2052. begin
  2053.     if (Assigned(FOnRaw)) then
  2054.         FOnRaw(Self, aCmd, aIn, aBlockIt);
  2055. end;
  2056.  
  2057. procedure TIrc.EventRead(const aError: word);
  2058. var
  2059.     s: string;
  2060.     i: integer;
  2061. begin
  2062.     inherited;
  2063.  
  2064.     while (RecvString(s)) do
  2065.     begin
  2066.         { Split on CRLF }
  2067.         if (FIncompleteCmd <> CEmpty) then
  2068.         begin
  2069.             { If there was incomplete command present in last parse prepend that to received data. }
  2070.             FTokenizer.Split(FIncompleteCmd + s, CCrLf, [soCSSep]);
  2071.             FIncompleteCmd := CEmpty;
  2072.         end
  2073.         else
  2074.             { Otherwise split the incoming data. }
  2075.             FTokenizer.Split(s, CCrLf, [soCSQot, soCSSep]);
  2076.  
  2077.         { Check if last token is CRLF terminated/command was complete this time }
  2078.         if (TextRight(s, 2) = CCrLf) then
  2079.         begin
  2080.             { If received data was CRLF terminated parse all commands now. }
  2081.             for i := 0 to FTokenizer.Count - 1 do
  2082.                 ParseCommand(FTokenizer[i]);
  2083.         end
  2084.         else
  2085.         begin
  2086.             { Otherwise add last token as incomplete command if not CRLF terminated }
  2087.             if (FTokenizer.Count = 1) then
  2088.                 FIncompleteCmd := FTokenizer[0]
  2089.             else
  2090.             begin
  2091.                 if (FTokenizer.Count <> 0) then
  2092.                 begin
  2093.                     for i := 0 to FTokenizer.Count - 2 do
  2094.                         ParseCommand(FTokenizer[i]);
  2095.                     FIncompleteCmd := FTokenizer[FTokenizer.Count - 1];
  2096.                 end;
  2097.             end;
  2098.         end;
  2099.     end;
  2100. end;
  2101.  
  2102. procedure TIrc.EventServerNotice(const aSource, aText: string);
  2103. begin
  2104.     if (Assigned(FOnServerNotice)) then
  2105.         FOnServerNotice(Self, aSource, aText);
  2106. end;
  2107.  
  2108. procedure TIrc.EventServerWelcome;
  2109. begin
  2110.     if (Assigned(FOnServerWelcome)) then
  2111.         FOnServerWelcome(Self);
  2112. end;
  2113.  
  2114. procedure TIrc.ParseCommand(const aLine: string);
  2115. var
  2116.     block : boolean;
  2117.     cmd   : string;
  2118.     Params: string;
  2119. begin
  2120.     { Fire event }
  2121.     if (Assigned(FOnRaw)) then
  2122.     begin
  2123.         block := False;
  2124.         FOnRaw(Self, aLine, True, block);
  2125.         if (block) then
  2126.             Exit;
  2127.     end;
  2128.  
  2129.     FParser.Parse(aLine);
  2130.  
  2131.     if (SameText(FParser.Command, CPING)) then
  2132.     begin
  2133.         if (FParser.TrailingCount > 0) then
  2134.             Raw(CPONG + CSpace + CColon + FParser.Trailings)
  2135.         else
  2136.             Raw(CPONG);
  2137.         Exit;
  2138.     end;
  2139.  
  2140.     if (SameText(FParser.Command, CJOIN)) then
  2141.     begin
  2142.         EventJoin(FParser.SourceNickName, FParser.Source, FParser.AllParams);
  2143.         Exit;
  2144.     end;
  2145.  
  2146.     if (SameText(FParser.Command, CPART)) then
  2147.     begin
  2148.         EventPart(FParser.SourceNickName, FParser.Source, FParser.Param[0], FParser.Trailings);
  2149.         Exit;
  2150.     end;
  2151.  
  2152.     if (SameText(FParser.Command, CKICK)) then
  2153.     begin
  2154.         EventKick(FParser.SourceNickName, FParser.Param[1], FParser.Param[0], FParser.Trailings);
  2155.  
  2156.         { Auto rejoin }
  2157.         if (SameText(FParser.Param[1], FNickname)) then
  2158.             if (FRejoinWhenKicked) then
  2159.                 CmdJoin(FParser.Param[0]);
  2160.         Exit;
  2161.     end;
  2162.  
  2163.     if (SameText(FParser.Command, CQUIT)) then
  2164.     begin
  2165.         EventQuit(FParser.SourceNickName, FParser.Source, FParser.Trailings);
  2166.         Exit;
  2167.     end;
  2168.  
  2169.     if (SameText(FParser.Command, CKILL)) then
  2170.     begin
  2171.         EventKill(FParser.Source, FParser.Param[0], FParser.Trailings);
  2172.         Exit;
  2173.     end;
  2174.  
  2175.     if (SameText(FParser.Command, CNICK)) then
  2176.     begin
  2177.         EventNick(FParser.SourceNickName, FParser.Param[0], FParser.Source);
  2178.         Exit;
  2179.     end;
  2180.  
  2181.     if (SameText(FParser.Command, CMODE)) then
  2182.     begin
  2183.         // -> :evilworks!evilworks@staff.anonops.li MODE #evilden +i
  2184.         // -> :evilworks!evilworks@staff.anonops.li MODE #evilden -i
  2185.         // -> :evilworks!evilworks@staff.anonops.li MODE #evilden +i
  2186.         // -> :evilworks!evilworks@staff.anonops.li MODE #evilden +DM-i+o win32
  2187.         // -> :evilworks!evilworks@staff.anonops.li MODE #evilden -DM+i-o win32
  2188.         // -> :evilworks!evilworks@staff.anonops.li MODE #evilden +DM-i+o win32
  2189.         // -> :evilworks!evilworks@staff.anonops.li MODE #evilden -DM+i-o win32
  2190.         // -> :evilworks!evilworks@staff.anonops.li MODE #evilden +DM-i+ov win32 evilworks
  2191.         //
  2192.         // <- :evilworks!evilworks@evil.machine MODE #anonops +i-i
  2193.         //
  2194.         // -> shitstorm.anonops.in MODE evilworks -i
  2195.         // <- :evilworks!evilworks@evil.machine MODE evilworks -i
  2196.  
  2197.         // -> shitstorm.anonops.in SAMODE p0ke -i
  2198.         // <- :shitstorm.anonops.in NOTICE evilworks :*** ANNOUNCEMENT: evilworks used SAMODE: p0ke -i
  2199.         EventMode(FParser.Source, FParser.Param[0], FParser.ParamsFrom(1));
  2200.         Exit;
  2201.     end;
  2202.  
  2203.     if (SameText(FParser.Command, CPRIVMSG)) then
  2204.     begin
  2205.         if (TextEnclosed(FParser.Trailings, #01, True)) then
  2206.         begin
  2207.             Params := TextUnEnclose(FParser.Trailings, #01, True);
  2208.             cmd    := TextExtractLeft(Params, CSpace, True, True);
  2209.             EventCTCP(FParser.SourceNickName, FParser.Source, FParser.Param[0], cmd, Params);
  2210.         end
  2211.         else
  2212.             EventPrivMsg(FParser.SourceNickName, FParser.Source, FParser.Param[0], FParser.Trailings);
  2213.         Exit;
  2214.     end;
  2215.  
  2216.     if (SameText(FParser.Command, CNOTICE)) then
  2217.     begin
  2218.         if (TextEnclosed(FParser.Trailings, #01, True)) then
  2219.         begin
  2220.             cmd    := TextRight(FParser.Trailing[0], Length(FParser.Trailing[0]) - 1);
  2221.             Params := TextLeft(FParser.TrailingsFrom(1), Length(FParser.TrailingsFrom(1)) - 1);
  2222.             EventCTCP(FParser.SourceNickName, FParser.Source, FParser.Param[0], cmd, Params);
  2223.         end
  2224.         else
  2225.         begin
  2226.             if (FParser.SourceType = stServer) then
  2227.                 EventServerNotice(FParser.Source, FParser.Trailings)
  2228.             else
  2229.                 EventNotice(FParser.SourceNickName, FParser.Source, FParser.Param[0], FParser.Trailings);
  2230.         end;
  2231.         Exit;
  2232.     end;
  2233.  
  2234.     if (SameText(FParser.Command, CERROR)) then
  2235.     begin
  2236.  
  2237.         Exit;
  2238.     end;
  2239.  
  2240.     if (SameText(FParser.Command, CINVITE)) then
  2241.     begin
  2242.         // -> :evilworks!evilworks@evil.machine INVITE win32 :#evilden
  2243.         Exit;
  2244.     end;
  2245.  
  2246.     if (SameText(FParser.Command, CWALLOPS)) then
  2247.     begin
  2248.  
  2249.         Exit;
  2250.     end;
  2251.  
  2252.     case StrToIntDef(FParser.Command, -1) of
  2253.  
  2254.         // WHOIS
  2255.         // 311 evilworks evilworks evilworks evil.machine * :Jesus H. Christ
  2256.         // 378 evilworks evilworks :is connecting from evilworks@188.129.127.120 188.129.127.120
  2257.         // 319 evilworks evilworks :@#opers #ascii #operationpayback #lounge #anonops #antisec @#help #OperationGreenRights #operationfreedom #opnewblood @#Programmers #radiopayback #reporter #services #setup #target #voice #occupywallstreet @#vhost @#kill #idle ~#cuntx
  2258.         // 312 evilworks evilworks shitstorm.anonops.in :dammit im not gay!
  2259.         // 313 evilworks evilworks :is an IRC operator
  2260.         // 379 evilworks evilworks :is using modes +BHWiorsw +ACDFGJKLNOQTVXacdfgjklnoqtvx
  2261.         // 335 evilworks evilworks :is a bot on AnonOps
  2262.         // 330 evilworks evilworks evilworks :is logged in as
  2263.         // 307 evilworks evilworks :is a registered nick
  2264.         // 671 evilworks evilworks :is using a secure connection
  2265.         // 317 evilworks evilworks 346 1318374597 :seconds idle, signon time
  2266.         // 318 evilworks evilworks :End of /WHOIS list.
  2267.  
  2268.         001:
  2269.         begin
  2270.             EventServerWelcome;
  2271.             { :corey.anonops.in 001 win32 :Welcome to the AnonOps IRC Network win32!win32@188.129.57.61 }
  2272.         end;
  2273.  
  2274.         002:
  2275.         begin
  2276.             { :corey.anonops.in 002 win32 :Your host is corey.anonops.in, running version InspIRCd-2.0 }
  2277.         end;
  2278.  
  2279.         003:
  2280.         begin
  2281.             { :corey.anonops.in 003 win32 :This server was created 00:58:35 Sep  6 2011 }
  2282.         end;
  2283.  
  2284.         004:
  2285.         begin
  2286.             { :corey.anonops.in 004 win32 corey.anonops.in InspIRCd-2.0 BHIRSWghiorswx ACDFIKLMNOQRSTYabcfhijklmnopqrstuvz FILYabfhjkloqv }
  2287.         end;
  2288.  
  2289.         005:
  2290.         begin
  2291.             { :corey.anonops.in 005 win32 AWAYLEN=31 CALLERID=g CASEMAPPING=rfc1459 CHANMODES=IYb,k,FLfjl,ACDKMNOQRSTcimnprstuz CHANTYPES=# CHARSET=ascii ELIST=MU EXTBAN=,ACNOQRSTcmz FNC INVEX=I KICKLEN=151 MAP MAXBANS=60 :are supported by this server }
  2292.             { :corey.anonops.in 005 win32 MAXCHANNELS=50 MAXPARA=32 MAXTARGETS=20 MODES=20 NETWORK=AnonOps NICKLEN=32 OVERRIDE PREFIX=(qaohv)~&@%+ SECURELIST SSL=93.114.44.112:6697 STARTTLS STATUSMSG=~&@%+ TOPICLEN=308 :are supported by this server }
  2293.             { :corey.anonops.in 005 win32 VBANLIST WALLCHOPS WALLVOICES WATCH=32 :are supported by this server }
  2294.         end;
  2295.  
  2296.         042:
  2297.         begin
  2298.             { :corey.anonops.in 042 win32 750AACQH7 :your unique ID }
  2299.         end;
  2300.  
  2301.         251:
  2302.         begin
  2303.             { :corey.anonops.in 251 win32 :There are 52 users and 469 invisible on 8 servers }
  2304.         end;
  2305.  
  2306.         252:
  2307.         begin
  2308.             { :corey.anonops.in 252 win32 8 :operator(s) online }
  2309.         end;
  2310.  
  2311.         253:
  2312.         begin
  2313.             { :corey.anonops.in 253 win32 1 :unknown connections }
  2314.         end;
  2315.  
  2316.         254:
  2317.         begin
  2318.             { :corey.anonops.in 254 win32 195 :channels formed }
  2319.         end;
  2320.  
  2321.         255:
  2322.         begin
  2323.             { :corey.anonops.in 255 win32 :I have 411 clients and 1 servers }
  2324.         end;
  2325.  
  2326.         265:
  2327.         begin
  2328.             { :corey.anonops.in 265 win32 :Current Local Users: 411  Max: 541 }
  2329.         end;
  2330.  
  2331.         266:
  2332.         begin
  2333.             { :corey.anonops.in 266 win32 :Current Global Users: 521  Max: 679 }
  2334.         end;
  2335.  
  2336.         307:
  2337.         begin
  2338.             if (FIAL.Enabled) then
  2339.                 FIAL.NickIsIdentified(FParser.Param[1]);
  2340.             // <- :shitstorm.anonops.in 307 evilworks evilworks :is a registered nick
  2341.         end;
  2342.  
  2343.         311:
  2344.         begin
  2345.             // <- :shitstorm.anonops.in 311 evilworks evilworks evilworks evil.machine * :Jesus H. Christ
  2346.         end;
  2347.  
  2348.         312:
  2349.         begin
  2350.             { WHOWAS and WHOIS }
  2351.             // <- :shitstorm.anonops.in 312 evilworks evilworks shitstorm.anonops.in :Mon Oct 10 03:09:02 2011
  2352.             // <- :shitstorm.anonops.in 312 evilworks evilworks shitstorm.anonops.in :dammit im not gay!
  2353.         end;
  2354.  
  2355.         313:
  2356.         begin
  2357.             // <- :shitstorm.anonops.in 313 evilworks evilworks :is an IRC operator
  2358.         end;
  2359.  
  2360.         314:
  2361.         begin
  2362.             { WHOWAS reply }
  2363.             // <- :shitstorm.anonops.in 314 evilworks evilworks evilworks evil.machine * :Jesus H. Christ
  2364.         end;
  2365.  
  2366.         315:
  2367.         begin
  2368.             { RPL_ENDOFWHOLIST }
  2369.             // <- :shitstorm.anonops.in 315 evilworks evilworks :End of /WHO list.
  2370.         end;
  2371.  
  2372.         317:
  2373.         begin
  2374.             // <source> 317 <replyto> <subject> <idletime> <signon time> :<time description>
  2375.             // <- :shitstorm.anonops.in 317 evilworks evilworks 346 1318374597 :seconds idle, signon time
  2376.         end;
  2377.  
  2378.         318:
  2379.         begin
  2380.             // <- :shitstorm.anonops.in 318 evilworks evilworks :End of /WHOIS list.
  2381.         end;
  2382.  
  2383.         319:
  2384.         begin
  2385.             { RPL_WHOISCHANNELS }
  2386.             // <- :shitstorm.anonops.in 319 evilworks evilworks :@#opers #ascii #operationpayback #lounge #anonops #antisec @#help #OperationGreenRights #operationfreedom #opnewblood @#Programmers #radiopayback #reporter #services #setup #target #voice #occupywallstreet @#vhost @#kill #idle ~#cuntx
  2387.         end;
  2388.  
  2389.         321:
  2390.         begin
  2391.             { RPL_LISTSTART - :src 321 tgt chan :usrs nam }
  2392.         end;
  2393.  
  2394.         322:
  2395.         begin
  2396.             { RPL_LIST }
  2397.         end;
  2398.  
  2399.         324:
  2400.         begin
  2401.             { Channel modes }
  2402.             // <- :shitstorm.anonops.in 324 evilworks #anonops +CDSTnrt
  2403.         end;
  2404.  
  2405.         329:
  2406.         begin
  2407.             { Channel creation date }
  2408.             // <- :shitstorm.anonops.in 329 evilworks #anonops 1305236043
  2409.         end;
  2410.  
  2411.         330:
  2412.         begin
  2413.             // <- :shitstorm.anonops.in 330 evilworks evilworks evilworks :is logged in as
  2414.         end;
  2415.  
  2416.         331:
  2417.         begin
  2418.             { RPL_NOTOPIC }
  2419.         end;
  2420.  
  2421.         332:
  2422.         begin
  2423.             { RPL_TOPIC }
  2424.             { :corey.anonops.in 332 win32 #anonops :Some topic text here }
  2425.         end;
  2426.  
  2427.         333:
  2428.         begin
  2429.             { Topic set by }
  2430.             { :corey.anonops.in 333 win32 #anonops Jupiler 1317771878 }
  2431.         end;
  2432.  
  2433.         335:
  2434.         begin
  2435.             // <- :shitstorm.anonops.in 335 evilworks evilworks :is a bot on AnonOps
  2436.         end;
  2437.  
  2438.         341:
  2439.         begin
  2440.             { RPL_INVITING }
  2441.         end;
  2442.  
  2443.         352:
  2444.         begin
  2445.             { RPL_WHOREPLY }
  2446.             if (FIAL.Enabled) then
  2447.                 FIAL.WhoText(FParser.ParamsFrom(1));
  2448.             // <server> XXX <replyto> <#channel> <ident> <host> <server> <nickname> <flags> :<hopcount> <realname>
  2449.             // <- :shitstorm.anonops.in 352 evilworks #ascii evilworks evil.machine shitstorm.anonops.in evilworks H* :0 Jesus H. Christ
  2450.             // <- :shitstorm.anonops.in 352 evilworks #anonops p ke shitstorm.anonops.in p0ke G*& :0 Soet :3
  2451.             // <- :shitstorm.anonops.in 352 evilworks #anonops blowmeh AN-2d8.ges.d9fja7.IP corey.anonops.in DiggerNicks G :0 I'm probably your dad
  2452.         end;
  2453.  
  2454.         353:
  2455.         begin
  2456.             { RPL_NAMEREPLY }
  2457.             { Replies to /names }
  2458.             if (IAL.Enabled) then
  2459.             begin
  2460.                 if (TextBegins(FParser.Param[1], '#')) then
  2461.                     IAL.NamesList(FParser.Param[1], FParser.Trailings)
  2462.                 else
  2463.                     if (TextBegins(FParser.Param[2], '#')) then
  2464.                         IAL.NamesList(FParser.Param[2], FParser.Trailings);
  2465.             end;
  2466.             { :corey.anonops.in 353 win32 = #anonops :SpecialBit &Thought_Criminal @mnx }
  2467.         end;
  2468.  
  2469.         366:
  2470.         begin
  2471.             { END OF NAMES LIST }
  2472.             { :corey.anonops.in 366 win32 #anonops :End of /NAMES list. }
  2473.         end;
  2474.  
  2475.         372:
  2476.         begin
  2477.             { MOTD line }
  2478.             { :corey.anonops.in 372 win32 :A HERPA DINKA DURR }
  2479.         end;
  2480.  
  2481.         375:
  2482.         begin
  2483.             { MOTD start }
  2484.             { :corey.anonops.in 375 win32 :corey.anonops.in message of the day }
  2485.         end;
  2486.  
  2487.         376:
  2488.         begin
  2489.             { MOTD end }
  2490.             { :corey.anonops.in 376 win32 :End of message of the day. }
  2491.         end;
  2492.  
  2493.         378:
  2494.         begin
  2495.             // <- :shitstorm.anonops.in 378 evilworks evilworks :is connecting from evilworks@188.129.127.120 188.129.127.120
  2496.         end;
  2497.  
  2498.         379:
  2499.         begin
  2500.             // <- :shitstorm.anonops.in 379 evilworks evilworks :was connecting from *@188.129.125.34
  2501.             // <- :shitstorm.anonops.in 379 evilworks evilworks :is using modes +BHWiorsw +ACDFGJKLNOQTVXacdfgjklnoqtvx
  2502.         end;
  2503.  
  2504.         396:
  2505.         begin
  2506.             { WHOWAS END }
  2507.             { :corey.anonops.in 396 win32 AN-0jb.13v.2j3fss.IP :is now your displayed host }
  2508.             // <- :shitstorm.anonops.in 369 evilworks evilworks :End of WHOWAS
  2509.         end;
  2510.  
  2511.         401:
  2512.         begin
  2513.             { PrivMsg error }
  2514.             // <- :shitstorm.anonops.in 401 cuntX #cuntX:smeg :No such nick/channel
  2515.         end;
  2516.  
  2517.         481:
  2518.         begin
  2519.             // <- :shitstorm.anonops.in 481 cuntX :Permission Denied - Only operators may set user mode s
  2520.         end;
  2521.  
  2522.         482:
  2523.         begin
  2524.             { :corey.anonops.in 482 win32 #evilden :You must have a registered nickname to create a new channel }
  2525.         end;
  2526.  
  2527.         671:
  2528.         begin
  2529.             // <- :shitstorm.anonops.in 671 evilworks evilworks :is using a secure connection
  2530.         end;
  2531.  
  2532.     end; { case }
  2533. end;
  2534.  
  2535. procedure TIrc.Raw(const aText: string);
  2536. var
  2537.     block: boolean;
  2538. begin
  2539.     { Fire event }
  2540.     if (Assigned(FOnRaw)) then
  2541.     begin
  2542.         block := False;
  2543.         FOnRaw(Self, aText, False, block);
  2544.         if (block) then
  2545.             Exit;
  2546.     end;
  2547.  
  2548.     SendLine(aText);
  2549. end;
  2550.  
  2551. procedure TIrc.CmdJoin(const aChannel, aKey: string);
  2552. begin
  2553.     if (aKey <> CEmpty) then
  2554.         Raw(CJOIN + CSpace + aChannel + CSpace + aKey)
  2555.     else
  2556.         Raw(CJOIN + CSpace + aChannel);
  2557. end;
  2558.  
  2559. procedure TIrc.CmdKill(const aNick, aReason: string);
  2560. begin
  2561.     Raw(CKILL + CSpace + aNick + CSpace + CColon + aReason);
  2562. end;
  2563.  
  2564. procedure TIrc.CmdPart(const aChannel, aPartMsg: string);
  2565. begin
  2566.     if (aPartMsg <> CEmpty) then
  2567.         Raw(CPART + CSpace + aChannel + CSpace + CColon + aPartMsg)
  2568.     else
  2569.         Raw(CPART + CSpace + aChannel);
  2570. end;
  2571.  
  2572. procedure TIrc.CmdWho(const aTarget, aOptionalParams: string);
  2573. begin
  2574.     if (aOptionalParams <> CEmpty) then
  2575.         Raw(CWHO + CSpace + aTarget + CSpace + aOptionalParams)
  2576.     else
  2577.         Raw(CWHO + CSpace + aTarget);
  2578. end;
  2579.  
  2580. procedure TIrc.CmdWhois(const aTarget: string);
  2581. begin
  2582.     Raw(CWHOIS + CSpace + aTarget + CSpace + aTarget);
  2583. end;
  2584.  
  2585. procedure TIrc.CmdMode(const aMode: string);
  2586. begin
  2587.     Raw(CMODE + CSpace + CNICK + aMode);
  2588. end;
  2589.  
  2590. procedure TIrc.CmdMsg(const aTarget, aMessage: string);
  2591. begin
  2592.     Raw(CPRIVMSG + CSpace + aTarget + CSpace + CColon + aMessage);
  2593. end;
  2594.  
  2595. procedure TIrc.CmdNotice(const aTarget, aMessage: string);
  2596. begin
  2597.     Raw(CNOTICE + CSpace + aTarget + CSpace + CColon + aMessage);
  2598. end;
  2599.  
  2600. procedure TIrc.CmdNick(const aNewNickname: string);
  2601. begin
  2602.     Raw(CNICK + CSpace + aNewNickname);
  2603. end;
  2604.  
  2605. procedure TIrc.SetPassword(const Value: string);
  2606. begin
  2607.     if (FPassword = Value) then
  2608.         Exit;
  2609.     FPassword := Value;
  2610. end;
  2611.  
  2612. procedure TIrc.SetAltNicknames(const Value: TStrings);
  2613. begin
  2614.     FAltNicknames.Assign(Value);
  2615. end;
  2616.  
  2617. procedure TIrc.SetNickname(const Value: string);
  2618. begin
  2619.     if (FNickname = Value) then
  2620.         Exit;
  2621.     FNickname := Value;
  2622.     CmdNick(FNickname);
  2623. end;
  2624.  
  2625. procedure TIrc.SetRealName(const Value: string);
  2626. begin
  2627.     if (SocketState <> ssDisconnected) then
  2628.         Exit;
  2629.     if (FRealname = Value) then
  2630.         Exit;
  2631.     FRealname := Value;
  2632. end;
  2633.  
  2634. procedure TIrc.SetReconnectWhenKilled(const Value: boolean);
  2635. begin
  2636.     if (FReconnectWhenKilled = Value) then
  2637.         Exit;
  2638.     FReconnectWhenKilled := Value;
  2639. end;
  2640.  
  2641. procedure TIrc.SetRejoinWhenKicked(const Value: boolean);
  2642. begin
  2643.     if (FRejoinWhenKicked = Value) then
  2644.         Exit;
  2645.     FRejoinWhenKicked := Value;
  2646. end;
  2647.  
  2648. procedure TIrc.SetUsermode(const Value: string);
  2649. begin
  2650.     if (FUserMode = Value) then
  2651.         Exit;
  2652.     FUserMode := Value;
  2653.     if (TextLeft(FUserMode, 1) <> CPlus) then
  2654.         FUserMode := CPlus + FUserMode;
  2655.     if (SocketState = ssConnected) then
  2656.         CmdMode(FUserMode);
  2657. end;
  2658.  
  2659. procedure TIrc.SetUsername(const Value: string);
  2660. begin
  2661.     if (SocketState <> ssDisconnected) then
  2662.         Exit;
  2663.     if (FUsername = Value) then
  2664.         Exit;
  2665.     FUsername := Value;
  2666. end;
  2667.  
  2668. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement