/*
* ----------------------------------------------------------------------
* 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;
}
}
}
}
}