using System; using System.Collections.Generic; using System.IO; using System.Net.Sockets; using System.Threading; namespace Mnemosyne.Irc { public delegate void CommandReceived(string ircCommand); public delegate void CommandSent(string ircCommand); public delegate void TopicSet(string ircChannel, string ircTopic); public delegate void TopicOwner(string ircChannel, string ircUser, string topicDate); public delegate void NamesList(string userNames); public delegate void ServerMessage(string serverMessage); 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 delegate void Disconnected(); public class IrcClient { public event CommandReceived CommandReceived; public event CommandSent CommandSent; public event TopicSet TopicSet; public event TopicOwner TopicOwner; public event NamesList NamesList; public event ServerMessage ServerMessage; public event Join Join; public event Part Part; public event Mode Mode; public event NickChange NickChange; public event Kick Kick; public event Quit Quit; public event Disconnected Disconnected; public string Server { get; set; } public int Port { get; set; } public string Nick { get; set; } public string NickPass { get; set; } public string User { get; set; } public string RealName { get; set; } public string Channel { get; set; } public bool IsInvisble { get; set; } public TcpClient Connection { get; set; } public NetworkStream Stream { get; set; } public StreamWriter Writer { get; set; } public StreamReader Reader { get; set; } public bool Connected { get; set; } public Dictionary> ChannelUsers { get; set; } private Thread listenThread; private bool disconnecting; public IrcClient(string nick, string nickPass, string channel) { Nick = nick; NickPass = nickPass; User = nick; RealName = "MnemosyneIrcBot"; Channel = channel; IsInvisble = false; Connected = false; disconnecting = false; ChannelUsers = new Dictionary>(); } public void Connect(string ircServer, int ircPort) { Server = ircServer; Port = ircPort; // Connect with the IRC server. Connection = new TcpClient(Server, Port); Stream = Connection.GetStream(); Reader = new StreamReader(Stream); Writer = new StreamWriter(Stream); // Authenticate our user string isInvisible = IsInvisble ? "8" : "0"; SendCommand(String.Format("USER {0} {1} * :{2}", User, isInvisible, RealName)); SetNick(Nick); Connected = true; // Listen for commands listenThread = new Thread(Listen); listenThread.Start(); } public void JoinChannel(string channel) { var channels = channel.Split(','); foreach (var chan in channels) { SendCommand(String.Format("JOIN {0}", chan)); } } public void LeaveChannel(string channel) { var channels = channel.Split(','); foreach (var chan in channels) { SendCommand(String.Format("PART {0}", chan)); } } public void GetChannelUsers(string channel) { if (!ChannelUsers.ContainsKey(channel)) { ChannelUsers.Add(channel, new List()); } else { ChannelUsers[channel].Clear(); } SendCommand(string.Format("NAMES {0}", channel)); } private void SetNick(string nick) { SendCommand(string.Format("NICK {0}", nick)); } private void SetPass(string nickPass) { SendCommand(string.Format("PRIVMSG NICKSERV IDENTIFY {0}", nickPass)); } public void GhostNick(string nick, string nickPass) { SetNick(nick + DateTime.Now.Ticks); SendCommand(string.Format("PRIVMSG NICKSERV GHOST {0} {1}", nick, nickPass)); SetNick(nick); SetNick(nickPass); } public void Disconnect() { disconnecting = true; Reader.Close(); } public void SendNotice(string user, string message) { SendCommand(string.Format("NOTICE {0} :{1}", user, message)); } public void SendMessage(string destination, string message) { SendCommand(string.Format("PRIVMSG {0} :{1}", destination, message)); } public void SendCommand(string ircCommand) { Writer.WriteLine(ircCommand); Writer.Flush(); if (CommandSent != null) CommandSent(ircCommand); } private void Listen() { while (!disconnecting) { string ircCommand; try { while (!disconnecting && (ircCommand = Reader.ReadLine()) != null) { if (CommandReceived != null) { CommandReceived(ircCommand); } string[] commandParts = ircCommand.Split(' '); if (commandParts[0].Substring(0, 1) == ":") { commandParts[0] = commandParts[0].Remove(0, 1); } if (commandParts[0].EndsWith(Server.Substring(Server.IndexOf('.')))) { // Server message switch (commandParts[1]) { case "001": RegisterUser(); break; case "332": IrcTopic(commandParts); break; case "333": IrcTopicOwner(commandParts); break; case "353": IrcNamesList(commandParts); break; case "366": /*this.IrcEndNamesList(commandParts);*/ break; case "372": /*this.IrcMOTD(commandParts);*/ break; case "376": /*this.IrcEndMOTD(commandParts);*/ break; default: IrcServerMessage(commandParts); break; } } else if (commandParts[0] == "PING") { // Server PING, send PONG back IrcPing(commandParts); } else { // Normal message string commandAction = commandParts[1]; switch (commandAction) { case "JOIN": IrcJoin(commandParts); break; case "PART": IrcPart(commandParts); break; case "MODE": IrcMode(commandParts); break; case "NICK": IrcNickChange(commandParts); break; case "KICK": IrcKick(commandParts); break; case "QUIT": IrcQuit(commandParts); break; } } } } catch (ObjectDisposedException) { //This means we got disconnected, carry on. } catch (IOException) { //Do nothing, this is probably because the stream closed. } Writer.Close(); Reader.Close(); Connection.Close(); if (Disconnected != null) { Disconnected(); } } Connected = false; disconnecting = false; } private void RegisterUser() { SetPass(NickPass); JoinChannel(Channel); } private void IrcTopic(string[] ircCommand) { string ircChannel = ircCommand[3]; string ircTopic = ""; for (int intI = 4; intI < ircCommand.Length; intI++) { ircTopic += ircCommand[intI] + " "; } if (TopicSet != null) { TopicSet(ircChannel, ircTopic.Remove(0, 1).Trim()); } } private void IrcTopicOwner(string[] ircCommand) { string ircChannel = ircCommand[3]; string ircUser = ircCommand[4].Split('!')[0]; string topicDate = ircCommand[5]; if (TopicOwner != null) { TopicOwner(ircChannel, ircUser, topicDate); } } private void IrcNamesList(string[] ircCommand) { string userNames = ""; for (int intI = 5; intI < ircCommand.Length; intI++) { userNames += ircCommand[intI] + " "; } if (NamesList != null) { NamesList(userNames.Remove(0, 1).Trim()); } } private void IrcServerMessage(string[] ircCommand) { string serverMessage = ""; for (int intI = 1; intI < ircCommand.Length; intI++) { serverMessage += ircCommand[intI] + " "; } if (ServerMessage != null) { ServerMessage(serverMessage.Trim()); } } private void IrcPing(string[] ircCommand) { string pingHash = ""; for (int intI = 1; intI < ircCommand.Length; intI++) { pingHash += ircCommand[intI] + " "; } SendCommand("PONG " + pingHash); } private void IrcJoin(string[] ircCommand) { string ircChannel = ircCommand[2]; string ircUser = ircCommand[0].Split('!')[0]; if (Join != null) { Join(ircChannel.Remove(0, 1), ircUser); } } private void IrcPart(string[] ircCommand) { string ircChannel = ircCommand[2]; string ircUser = ircCommand[0].Split('!')[0]; if (Part != null) { Part(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 (Mode != null) { Mode(ircChannel, ircUser, userMode.Trim()); } } private void IrcNickChange(string[] ircCommand) { string userOldNick = ircCommand[0].Split('!')[0]; string userNewNick = ircCommand[2].Remove(0, 1); if (NickChange != null) { NickChange(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 (Kick != null) { Kick(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 (Quit != null) { Quit(userQuit, quitMessage.Remove(0, 1).Trim()); } } } }