/* * ---------------------------------------------------------------------- * Name parseIrcData.cs ( parseIrcData ) * * Description The parseIrcData class makes use of regular * expressions and basic string manipulation * methods in order to parse a raw string sent by an * IRC server. * * Version 1.00 [BETA] * * Started 23/03/2006 * * Finished 29/03/2006 * * Updated 11/04/2006 * * Update notes I carried out a complete rework of the code and * added support for the +h halfop command * * Resources MSDN * * Author Tom Wadeson * --------------------------------------------------------------------- */ using System; using System.Text; using System.Text.RegularExpressions; namespace SlimIRC { public class parseIrcData { // Modes Per Line (Default: 6) public static int ModesPL = 6; // Trigger information private string _Nick; private string _Ident; private string _Host; // Details private string _CMD; private string _Target; private string _Modes; private string _ModeLine; // Misc private string _Limit; private string _Key; private string _PingID; // New Nick (When a Nick is changed) private string _NNick; // Voice & De-voice Nicks private string[] _VNick = new string[ ModesPL ]; private string[] _DVNick = new string[ ModesPL ]; // Op & De-op Nicks private string[] _ONick = new string[ ModesPL ]; private string[] _DONick = new string[ ModesPL ]; // Half-Op & De-Half-Op Nicks (Note: This does not comply to the IRC RFCs) private string[] _HONick = new string[ ModesPL ]; private string[] _DHONick = new string[ ModesPL ]; // Ban Hosts & Unban Hosts private string[] _BHost = new string[ ModesPL ]; private string[] _UBHost = new string[ ModesPL ]; // Used to refer to the user kicked from a given channel private string _KNick; // Used to refer to user messages ( PRIVMSG, Kick Message, Quit Message, Part Message, Topic ) private string _Message = ""; // Used to refer to individual 'words' of a string sent by the server private string[] _Token; /* Regular Expressions */ // Regex pattern to retrieve user's Nick private Regex ptnNick = new Regex( @"(?<=:)\S*(?=!)" ); // Regex pattern to retrieve user's Ident private Regex ptnIdent = new Regex( @"(?<=!)\S*(?=@)" ); // Regex pattern to retrieve user's Host private Regex ptnHost = new Regex( @"(?<=@)\S*" ); // Regex pattern to retrieve variable Message private Regex ptnMessage = new Regex( @"(?<=:).*" ); // Regex to check if an ACTION or CTCP event exists within a PRIVMSG private Regex ptnSpecial = new Regex( @"(?<=)\w*" ); // Regex to retrieve an ACTION message private Regex ptnActMsg = new Regex( @"(?<=:ACTION).*(?=)" ); // Regex to retrieve a PingID from a CTCP Ping request private Regex ptnPingID = new Regex( @"(?<=PING).*(?=)" ); /* These "Event Bool"s are false by default. The parsing engine will change an "Event Bool"'s * value to true if a particular event has occured. * * For Example: * * ":TuB!tub@TuB.users.netgamers.org PRIVMSG #test :Hello, World!" * * The above line would be interpreted by the parsing engine and would as such be registered * with its relevant "Event Bool". In this case, the "Event Bool" which would be set is PrivMsg. * * This feature is more or less the core of this class and it allows for rapid development of IRC * applications due to the fact that a developer is able to simply check an "Event Bool"'s status * and act accordingly. * * if ( x.PrivMsg ) { Console.WriteLine( "A PrivMsg has been sent!" ); } */ public bool Ping = false; public bool PrivMsg = false; public bool Action = false; public bool Notice = false; public bool CTCPPing = false; public bool CTCPVersion = false; public bool CTCPTime = false; public bool Part = false; public bool Kick = false; public bool Quit = false; public bool Join = false; public bool Mode = false; public bool Op = false; public bool Deop = false; public bool Voice = false; public bool Devoice = false; public bool Halfop = false; public bool Dehalfop = false; public bool Ban = false; public bool Unban = false; public bool Topic = false; public bool CNick = false; /* Public Gets */ // User's Nick public string Nick { get { return this._Nick; } } // User's Ident public string Ident { get { return this._Ident; } } // User's Host public string Host { get { return this._Host; } } // [CMD] Command (Event - PRIVMSG, KICK, MODE, etc) public string CMD { get { return this._CMD; } } // Target (#Channel or direct PRIVMSG) public string Target { get { return this._Target; } } // Message public string Message { get { return this._Message; } } // Modes set/unset public string Modes { get { return this._Modes; } } // Mode Line public string ModeLine { get { return this._ModeLine; } } // Limit parameter (+l) public string Limit { get { return this._Limit; } } // Key parameter (+k) public string Key { get { return this._Key; } } // PingID public string PingID { get { return this._PingID; } } // New Nick public string NNick { get { return this._NNick; } } // Kick Nick public string KNick { get { return this._KNick; } } // Nicks granted +v public string[] VNick { get { return this._VNick; } } // Nicks dealt -v public string[] DVNick { get { return this._DVNick; } } // Nicks granted +o public string[] ONick { get { return this._ONick; } } // Nicks dealt -o public string[] DONick { get { return this._DONick; } } // Nicks granted +h public string[] HONick { get { return this._HONick; } } // Nicks dealt -h public string[] DHONick { get { return this._DHONick; } } // Host of Ban public string[] BHost { get { return this._BHost; } } // Host of Unban public string[] UBHost { get { return this._UBHost; } } // Token public string[] Token { get { return this._Token; } } /* Class Constructor */ public parseIrcData ( string line ) { // Apply ptnNick to "line", assign _Nick if ( this.ptnNick.IsMatch( line ) ) { this._Nick = this.ptnNick.Match( line ).ToString(); } // Apply ptnIdent to "line", assign _Ident if ( this.ptnIdent.IsMatch( line ) ) { this._Ident = this.ptnIdent.Match( line ).ToString(); } // Apply ptnHost to "line", assign _Host if ( this.ptnHost.IsMatch( line ) ) { this._Host = this.ptnHost.Match( line ).ToString(); } // Split line at " " if ( line.IndexOf( " " ) > 0 ) { this._Token = line.Split( new Char[] { ' ' } ); } // Assign a value to _CMD, assuming a command exists if ( this._Token.Length >= 2 ) { this._CMD = this.Token[1]; } // Assign a value to _Target, assuming a target exists if ( this._Token.Length >= 3 ) { this._Target = this.Token[2]; } /* Mode Handling (Eeek!) */ if ( this.CMD == "MODE" ) { // Set the Mode Event Bool to true this.Mode = true; // Set the modes to the _Modes member this._Modes = this.Token[ 3 ]; // Set ModeLine for (int a = 3; a < this.Token.Length; a++) { this._ModeLine += this.Token[a] + " "; } this._ModeLine = this._ModeLine.TrimEnd(); int currentParam = 3; bool minus = false; bool plus = false;; for ( int a = 0; a < this.Modes.Length; a++ ) { if ( this.Modes[a] == '-' ) { minus = true; plus = false; continue; } if ( this.Modes[a] == '+' ) { plus = true; minus = false; continue; } switch ( this.Modes[a] ) { case 'o': // Handles Op and Deop Modes currentParam++; if ( minus ) { this.addDeopToArray( this.Token[ currentParam ] ); this.Deop = true; } if ( plus ) { this.addOpToArray( this.Token[ currentParam ] ); this.Op = true; } break; case 'v': // Handles Voice and Devoice Modes currentParam++; if ( minus ) { this.addDevoiceToArray( this.Token[ currentParam ] ); this.Devoice = true; } if ( plus ) { this.addVoiceToArray( this.Token[ currentParam ] ); this.Voice = true; } break; case 'b': // Handles Bans and Unbans currentParam++; if ( minus ) { this.addUnbanhostToArray( this.Token[ currentParam ] ); this.Unban = true; } if ( plus ) { this.addBanhostToArray( this.Token[ currentParam ] ); this.Ban = true; } break; case 'h': // Handles Halfop and Dehalfop Modes currentParam++; if ( minus ) { this.addHalfopToArray( this.Token[ currentParam ] ); this.Dehalfop = true; } if ( plus ) { this.addDehalfopToArray( this.Token[ currentParam ] ); this.Halfop = true; } break; case 'k': // Handles +/-k Modes currentParam++; this._Key = this.Token[ currentParam ]; break; case 'l': // Handles +/-l (Limit) Modes if (plus) { currentParam++; this._Limit = this.Token[currentParam]; } break; } } } /* PRIVMSG CMD */ if ( this.CMD == "PRIVMSG" ) { for ( int a = 3; a < this.Token.Length; a++ ) { this._Message += this.Token[a] + " "; } this._Message = this._Message.TrimEnd(); if ( this.ptnMessage.IsMatch( this._Message ) ) { this._Message = this.ptnMessage.Match( this._Message ).ToString(); } // ACTION, CTCP: Version, Time, Ping support if ( this.ptnSpecial.IsMatch( this._Message ) ) { // ACTION if ( this.ptnSpecial.Match( this._Message ).ToString() == "ACTION" ) { this.Action = true; this._Message = this.ptnActMsg.Match( this._Message ).ToString().Trim(); } // CTCP VERSION if ( this.ptnSpecial.Match( this._Message ).ToString() == "VERSION" ) { this.CTCPVersion = true; } // CTCP TIME if ( this.ptnSpecial.Match( this._Message ).ToString() == "TIME" ) { this.CTCPTime = true; } // CTCP PING if ( this.ptnSpecial.Match( this._Message ).ToString() == "PING" ) { this.CTCPPing = true; if ( this.ptnPingID.IsMatch( this._Message ) ) { this._PingID = this.ptnPingID.Match( this._Message ).ToString().Trim(); } } } // PRIVMSG else { this.PrivMsg = true; } } /* NOTICE CMD */ if (this.CMD == "KICK") { this.Notice = true; for (int a = 3; a < this.Token.Length; a++) { this._Message += this.Token[a] + " "; } this._Message = this._Message.TrimEnd(); if (this.ptnMessage.IsMatch(this._Message)) { this._Message = this.ptnMessage.Match(this._Message).ToString(); } } /* KICK CMD */ if ( this.CMD == "KICK" ) { this.Kick = true; this._KNick = this.Token[ 3 ]; for (int a = 4; a < this.Token.Length; a++) { this._Message += this.Token[a] + " "; } this._Message = this._Message.TrimEnd(); if (this.ptnMessage.IsMatch(this._Message)) { this._Message = this.ptnMessage.Match(this._Message).ToString(); } } /* QUIT CMD */ if ( this.CMD == "QUIT" ) { this.Quit = true; for (int a = 2; a < this.Token.Length; a++) { this._Message += this.Token[a] + " "; } this._Message = this._Message.TrimEnd(); if (this.ptnMessage.IsMatch(this._Message)) { this._Message = this.ptnMessage.Match(this._Message).ToString(); } } /* PART CMD */ if ( this.CMD == "PART" ) { this.Part = true; for (int a = 3; a < this.Token.Length; a++) { this._Message += this.Token[a] + " "; } this._Message = this._Message.TrimEnd(); if (this.ptnMessage.IsMatch(this._Message)) { this._Message = this.ptnMessage.Match(this._Message).ToString(); } } /* TOPIC CMD */ if ( this.CMD == "TOPIC" ) { this.Topic = true; for (int a = 3; a < this.Token.Length; a++) { this._Message += this.Token[a] + " "; } this._Message = this._Message.TrimEnd(); if (this.ptnMessage.IsMatch(this._Message)) { this._Message = this.ptnMessage.Match(this._Message).ToString(); } } /* JOIN CMD */ if ( this.CMD == "JOIN" ) { this.Join = true; } /* PING CMD */ if ( this.Token[0] == "PING" ) { this.Ping = true; this._PingID = this.Token[1]; } /* CHANGE NICK CMD */ if ( this.CMD == "NICK" ) { this.CNick = true; if ( this.ptnMessage.IsMatch( this.Token[2] ) ) { this._NNick = this.ptnMessage.Match( this.Token[2] ).ToString(); } } } /* The members listed below allow for dynamic appending to * their relative arrays */ // Add Op Nick private void addOpToArray( string nick ) { for ( int a = 0; a < this.ONick.Length; a++ ) { if ( this.ONick[a] == null ) { this.ONick[a] = nick; break; } } } // Add Deop Nick private void addDeopToArray( string nick ) { for ( int a = 0; a < this.DONick.Length; a++ ) { if ( this.DONick[a] == null ) { this.DONick[a] = nick; break; } } } // Add Voice Nick private void addVoiceToArray( string nick ) { for ( int a = 0; a < this.VNick.Length; a++ ) { if ( this.VNick[a] == null ) { this.VNick[a] = nick; break; } } } // Add Devoice Nick private void addDevoiceToArray( string nick ) { for ( int a = 0; a < this.DVNick.Length; a++ ) { if ( this.DVNick[a] == null ) { this.DVNick[a] = nick; break; } } } // Add Halfop Nick private void addHalfopToArray( string nick ) { for ( int a = 0; a < this.HONick.Length; a++ ) { if ( this.HONick[a] == null ) { this.HONick[a] = nick; break; } } } // Add Dehalfop Nick private void addDehalfopToArray( string nick ) { for ( int a = 0; a < this.DHONick.Length; a++ ) { if ( this.DHONick[a] == null ) { this.DHONick[a] = nick; break; } } } // Add Ban Host private void addBanhostToArray( string host ) { for ( int a = 0; a < this.BHost.Length; a++ ) { if ( this.BHost[a] == null ) { this.BHost[a] = host; break; } } } // Add Unban Host private void addUnbanhostToArray( string host ) { for ( int a = 0; a < this.UBHost.Length; a ++ ) { if ( this.UBHost[a] == null ) { this.UBHost[a] = host; break; } } } } }