// Shamelessly stolen from "cIRC", a demo-IRC-bot i found somewhere on the net // // Made some corrections/modifications on it, so it's not completely original :) // // All the following code should conform to the following spcifications: // RFC 1413 - Identification Protocol // RFC 2810 - IRC Architecture // RFC 2811 - IRC Channel Management // RFC 2812 - IRC Client Protocol // RFC 2813 - IRC Server Protocol using System; using System.Net; using System.Net.Sockets; using System.IO; using System.Threading; namespace System.Net { public delegate void CommandReceived(string IrcCommand); public delegate void TopicSet(string IrcChannel, string IrcTopic); public delegate void NamesList(string UserNames); public delegate void EndNamesList(); public delegate void ServerMessage(string ServerMessage); public delegate void MOTD (string motd); public delegate void EndMOTD (); public delegate void Join(string IrcChannel, string IrcUser); public delegate void Part(string IrcChannel, string IrcUser); public delegate void Mode(string IrcChannel, string IrcUser, string UserMode); public delegate void NickChange(string UserOldNick, string UserNewNick); public delegate void Kick(string IrcChannel, string UserKicker, string UserKicked, string KickMessage); public delegate void Quit(string UserQuit, string QuitMessage); public class IRC { public event CommandReceived eventReceiving; public event TopicSet eventTopicSet; public event NamesList eventNamesList; public event EndNamesList eventEndNamesList; public event ServerMessage eventServerMessage; public event MOTD eventMOTD; public event EndMOTD eventEndMOTD; public event Join eventJoin; public event Part eventPart; public event Mode eventMode; public event NickChange eventNickChange; public event Kick eventKick; public event Quit eventQuit; // All the defined errors (without network-stuff) public enum ErrorReplies { NoSuchNick = 401, // " :No such nick/channel" NoSuchServer = 402, // " :No such server" NoSuchChannel = 403, // " :No such channel" CannotSendToChan = 404, // " :Cannot send to channel" TooManyChannels = 405, // " :You have joined too many channels" WasNoSuchNick = 406, // " :There was no such nickname" TooManyTargets = 407, // " :Duplicate recipients. No message delivered" NoOrigin = 409, // ":No origin specified" NoRecipient = 411, // ":No recipient given ()" NoTextToSend = 412, // ":No text to send" NoTopLevel = 413, // " :No toplevel domain specified" WildTopLevel = 414, // " :Wildcard in toplevel domain" UnknownCommand = 421, // " :Unknown command" NoMotd = 422, // ":MOTD File is missing" NoAdminInfo = 423, // " :No administrative info available" FileError = 424, // ":File error doing on " NoNicknameGiven = 431, // ":No nickname given" ErroneusNickname = 432, // " :Erroneus nickname" NicknameInUse = 433, // " :Nickname is already in use" NickCollision = 436, // " :Nickname collision KILL" UserNotInChannel = 441, // " :They aren't on that channel" NotInChannel = 442, // " :You're not on that channel" UserOnChannel = 443, // " :is already on channel" NoLogin = 444, // " :User not logged in" SummonDisabled = 445, // ":SUMMON has been disabled" UsersDisabled = 446, // ":USERS has been disabled" NotRegistered = 451, // ":You have not registered" NeedMoreParams = 461, // " :Not enough parameters" AlreadyRegistered = 462, // ":You may not reregister" NoOperFromHost = 463, // ":Your host isn't among the privileged" PasswordMismatch = 464, // ":Password incorrect" YoureBannedCreep = 465, // ":You are banned from this server" KeySet = 467, // " :Channel key already set" ChannelIsFull = 471, // " :Cannot join channel (+l)" UnknownMode = 472, // " :is unknown mode char to me" InviteOnlyChan = 473, // " :Cannot join channel (+i)" BannedFromChan = 474, // " :Cannot join channel (+b)" BadChannelKey = 475, // " :Cannot join channel (+k)" NoPrivileges = 481, // ":Permission Denied- You're not an IRC operator" ChanOpPrivIsNeeded = 482, // " :You're not channel operator" CantKillServer = 483, // ":You cant kill a server!" NoOperHost = 491, // ":No O-lines for your host" UmodeUnknownFlag = 501, // ":Unknown MODE flag" UsersDontMatch = 502 // ":Cant change mode for other users" }; public enum Replies { Welcome = 001, // "Welcome to the Internet Relay Network !@", new in RFC2812 YourHost = 002, // "Your host is , running version ", new in RFC2812 Created = 003, // "This server was created ", new in RFC2812 MyInfo = 004, // " ", new in RFC2812 Bounce = 005, // "Try server , port ", new in RFC2812 None = 300, // Dummy reply number. Not used. Userhost = 302, // ":*1 *( " " )" IsOn = 303, // ":*1 *( " " )" Away = 301, // " :" Unaway = 305, // ":You are no longer marked as being away" NowAway = 306, // ":You have been marked as being away" WhoisUser = 311, // " * :" WhoisServer = 312, // " :" WhoisOperator = 313, // " :is an IRC operator" WhoisIdle = 317, // " :seconds idle" EndOfWhois = 318, // " :End of /WHOIS list" WhoisChannels = 319, // " :{[@|+]}" WhoWasUser = 314, // " * :" EndOfWhoWas = 369, // " :End of WHOWAS" ListStart = 321, // "Channel :Users Name" List = 322, // " <# visible> :" ListEnd = 323, // ":End of /LIST" ChannelModeIs = 324, // " " NoTopic = 331, // " :No topic is set" Topic = 332, // " :" Inviting = 341, // " " Summoning = 342, // " :Summoning user to IRC" Version = 351, // ". :" WhoReply = 352, // " [*][@|+] : " EndOfWho = 315, // " :End of /WHO list" NameReply = 353, // " :[[@|+] [[@|+] [...]]]" EndOfNames = 366, // " :End of /NAMES list" Links = 364, // " : " EndOfLinks = 365, // " :End of /LINKS list" BanList = 367, // " " EndOfBanList = 368, // " :End of channel ban list" Info = 371, // ":" EndOfInfo = 374, // ":End of /INFO list" MotdStart = 375, // ":- Message of the day - " Motd = 372, // ":- " EndOfMotd = 376, // ":End of /MOTD command" YoureOper = 381, // ":You are now an IRC operator" Rehashing = 382, // " :Rehashing" Time = 391, // " :" UsersStart = 392, // ":UserID Terminal Host" Users = 393, // ":%-8s %-9s %-8s" EndOfUsers = 394, // ":End of users" NoUsers = 395 // ":Nobody logged in" } private string ircServer; private int ircPort; private string ircNick; private string ircUser; private string ircRealName; private string ircChannel; private bool isInvisible; private TcpClient ircConnection; private NetworkStream ircStream; private StreamWriter ircWriter; private StreamReader ircReader; public string IrcServer { get { return this.ircServer; } set { this.ircServer = value; } } public int IrcPort { get { return this.ircPort; } set { this.ircPort = value; } } public string IrcNick { get { return this.ircNick; } set { this.ircNick = value; } } public string IrcUser { get { return this.ircUser; } set { this.ircUser = value; } } public string IrcRealName { get { return this.ircRealName; } set { this.ircRealName = value; } } public string IrcChannel { get { return this.ircChannel; } set { this.ircChannel = value; } } public bool IsInvisble { get { return this.isInvisible; } set { this.isInvisible = value; } } public TcpClient IrcConnection { get { return this.ircConnection; } set { this.ircConnection = value; } } public NetworkStream IrcStream { get { return this.ircStream; } set { this.ircStream = value; } } public StreamWriter IrcWriter { get { return this.ircWriter; } set { this.ircWriter = value; } } public StreamReader IrcReader { get { return this.ircReader; } set { this.ircReader = value; } } public IRC(string IrcNick, string IrcChannel) { this.IrcNick = IrcNick; this.IrcUser = System.Environment.MachineName; this.IrcRealName = "cIRC v1.0"; this.IrcChannel = IrcChannel; this.IsInvisble = false; } public void Connect(string IrcServer, int IrcPort) { this.IrcServer = IrcServer; this.IrcPort = IrcPort; // Connect with the IRC server. this.IrcConnection = new TcpClient(this.IrcServer, this.IrcPort); this.IrcStream = this.IrcConnection.GetStream(); this.IrcReader = new StreamReader(this.IrcStream); this.IrcWriter = new StreamWriter(this.IrcStream); // Authenticate our user string isInvisible = this.IsInvisble ? "8" : "0"; this.IrcWriter.WriteLine(String.Format("USER {0} {1} * :{2}", this.IrcUser, isInvisible, this.IrcRealName)); this.IrcWriter.Flush(); this.IrcWriter.WriteLine(String.Format("NICK {0}", this.IrcNick)); this.IrcWriter.Flush(); this.IrcWriter.WriteLine(String.Format("JOIN {0}", this.IrcChannel)); this.IrcWriter.Flush(); // Listen for commands while (true) { string ircCommand; while ((ircCommand = this.IrcReader.ReadLine()) != null) { if (eventReceiving != null) { this.eventReceiving(ircCommand); } string[] commandParts = new string[ircCommand.Split(' ').Length]; commandParts = ircCommand.Split(' '); if (commandParts[0].Substring(0, 1) == ":") { commandParts[0] = commandParts[0].Remove(0, 1); } if (commandParts[1] == "002") { // fetch the correct servername // ex: irc.freenode.net -> brown.freenode.net/kornbluth.freenode.net/... // irc.bluewin.ch -> irc1.bluewin.ch/irc2.bluewin.ch this.IrcServer = (commandParts[6].Split('['))[0]; } if (commandParts[0] == this.IrcServer) { try { // Server message switch (Int32.Parse(commandParts[1])) { case (int) Replies.Topic: this.IrcTopic(commandParts); break; case (int) Replies.NameReply: this.IrcNamesList(commandParts); break; case (int) Replies.EndOfNames: this.IrcEndNamesList(); break; case (int) Replies.Motd: this.IrcMOTD(commandParts); break; case (int) Replies.EndOfMotd: this.IrcEndMOTD(); break; default: this.IrcServerMessage(commandParts); break; } } catch (FormatException ex) // because of Int32.Parse() {} } else if (commandParts[0] == "PING") { // Server PING, send PONG back this.IrcPing(commandParts); } else { // Normal message string commandAction = commandParts[1]; switch (commandAction) { case "JOIN": this.IrcJoin(commandParts); break; case "PART": this.IrcPart(commandParts); break; case "MODE": this.IrcMode(commandParts); break; case "NICK": this.IrcNickChange(commandParts); break; case "KICK": this.IrcKick(commandParts); break; case "QUIT": this.IrcQuit(commandParts); break; } } } this.IrcWriter.Close(); this.IrcReader.Close(); this.IrcConnection.Close(); } } private void IrcTopic(string[] IrcCommand) { string IrcChannel = IrcCommand[3]; string IrcTopic = ""; for (int intI = 4; intI < IrcCommand.Length; intI++) { IrcTopic += IrcCommand[intI] + " "; } if (eventTopicSet != null) { this.eventTopicSet(IrcChannel, IrcTopic.Remove(0, 1).Trim()); } } private void IrcNamesList(string[] IrcCommand) { string UserNames = ""; for (int intI = 5; intI < IrcCommand.Length; intI++) { UserNames += IrcCommand[intI] + " "; } if (eventNamesList != null) { this.eventNamesList(UserNames.Remove(0, 1).Trim()); } } private void IrcEndNamesList () { if (eventEndNamesList != null) { this.eventEndNamesList(); } } private void IrcServerMessage(string[] IrcCommand) { string ServerMessage = ""; for (int intI = 1; intI < IrcCommand.Length; intI++) { ServerMessage += IrcCommand[intI] + " "; } if (eventServerMessage != null) { this.eventServerMessage(ServerMessage.Trim()); } } private void IrcMOTD (string[] IrcCommand) { string motd = ""; for (int intI = 3; intI < IrcCommand.Length; intI++) { motd += IrcCommand[intI] + " "; } if (eventMOTD != null) { this.eventMOTD(motd.Trim()); } } private void IrcEndMOTD() { if (eventEndMOTD != null) { this.eventEndMOTD(); } } private void IrcPing (string[] IrcCommand) { string PingHash = ""; for (int intI = 1; intI < IrcCommand.Length; intI++) { PingHash += IrcCommand[intI] + " "; } this.IrcWriter.WriteLine("PONG " + PingHash); this.IrcWriter.Flush(); } private void IrcJoin(string[] IrcCommand) { string IrcChannel = IrcCommand[2]; string IrcUser = IrcCommand[0].Split('!')[0]; if (eventJoin != null) { this.eventJoin(IrcChannel.Remove(0, 1), IrcUser); } } private void IrcPart(string[] IrcCommand) { string IrcChannel = IrcCommand[2]; string IrcUser = IrcCommand[0].Split('!')[0]; if (eventPart != null) { this.eventPart(IrcChannel, IrcUser); } } private void IrcMode(string[] IrcCommand) { string IrcChannel = IrcCommand[2]; string IrcUser = IrcCommand[0].Split('!')[0]; string UserMode = ""; for (int intI = 3; intI < IrcCommand.Length; intI++) { UserMode += IrcCommand[intI] + " "; } if (UserMode.Substring(0, 1) == ":") { UserMode = UserMode.Remove(0, 1); } if (eventMode != null) { this.eventMode(IrcChannel, IrcUser, UserMode.Trim()); } } private void IrcNickChange(string[] IrcCommand) { string UserOldNick = IrcCommand[0].Split('!')[0]; string UserNewNick = IrcCommand[2].Remove(0, 1); if (eventNickChange != null) { this.eventNickChange(UserOldNick, UserNewNick); } } private void IrcKick(string[] IrcCommand) { string UserKicker = IrcCommand[0].Split('!')[0]; string UserKicked = IrcCommand[3]; string IrcChannel = IrcCommand[2]; string KickMessage = ""; for (int intI = 4; intI < IrcCommand.Length; intI++) { KickMessage += IrcCommand[intI] + " "; } if (eventKick != null) { this.eventKick(IrcChannel, UserKicker, UserKicked, KickMessage.Remove(0, 1).Trim()); } } private void IrcQuit(string[] IrcCommand) { string UserQuit = IrcCommand[0].Split('!')[0]; string QuitMessage = ""; for (int intI = 2; intI < IrcCommand.Length; intI++) { QuitMessage += IrcCommand[intI] + " "; } if (eventQuit != null) { this.eventQuit(UserQuit, QuitMessage.Remove(0, 1).Trim()); } } } }