using System; using System.IO; using System.Net; using System.Net.Sockets; using System.Text; using System.Collections; public class Bot { public static void Main(string[] args) { IcbBot b = new IcbBot(); if (args.Length < 4) { Console.Error.Write("bot.exe server-hostname port nickname group\n"); Environment.Exit(1); } b.DoIt(args[0], Int32.Parse(args[1]), args[2], args[3]); } } class IcbBot { // so, string.Join takes a string, but string.Split takes a char... static char [] sep = { '\x01' }; static char [] wht = { ' ', '\t', '\n', '\r' }; static Hashtable PacketTypes; StreamReader r; StreamWriter w; public IcbBot() { PacketTypes = new Hashtable(); PacketTypes.Add("a", "Login"); PacketTypes.Add("b", "Public"); PacketTypes.Add("c", "Private"); PacketTypes.Add("d", "Status"); PacketTypes.Add("e", "Error"); PacketTypes.Add("g", "Exit"); PacketTypes.Add("h", "Command"); PacketTypes.Add("i", "Command"); PacketTypes.Add("j", "Protocol"); PacketTypes.Add("k", "Beep"); PacketTypes.Add("l", "Ping"); PacketTypes.Add("m", "Pong"); } public void DoIt(string host, int port, string nick, string group) { TcpClient c; NetworkStream stream; char [] crap = new char[1024]; string cmd; int len; c = new TcpClient(); c.Connect(host, port); Console.WriteLine("connected to {0}:{1}", host, port); stream = c.GetStream(); // Except it's more like us-ascii than ISO-8859-1. r = new StreamReader(stream, new Latin1Encoding()); w = new StreamWriter(stream, new Latin1Encoding()); r.Read(crap, 0, 1); len = (int)crap[0]; r.Read(crap, 1, len); cmd = ParseAndDisplay(crap); Login(w, nick, group); for (;;) { r.Read(crap, 0, 1); len = (int)crap[0]; r.Read(crap, 1, len); cmd = ParseAndDisplay(crap); if (cmd == "quit") { r.Close(); w.Close(); c.Close(); Console.WriteLine("quitting."); Environment.Exit(0); } } } string ParseAndDisplay(char [] data) { int len = (int)data[0]; string type = data[1].ToString(); string str = new string(data, 1, len); int null_pos = str.IndexOf("\x00"); string [] input = str.Split(sep); if (PacketTypes.Contains(type)) type = (string)PacketTypes[type]; else type = "Unknown message!"; input[0] = input[0].Substring(1); Console.WriteLine(type + ": " + string.Join(" ", input)); // right now, the only "command" we watch for is a private message // telling us to quit. if (type == "Private") { if (input[1].IndexOf("quit oinking!") != -1) return "quit"; else if (input[1].IndexOf("msg ") == 0) sendPrivate(input[1]); else if (input[1].IndexOf("say ") == 0) sendPublic(input[1]); else if (input[1].IndexOf("goto-group ") == 0) gotoGroup(input[1]); else if (input[1].IndexOf("cmd: ") == 0) cmd(input[1]); return ""; } else if (len < null_pos) { // got to be a better way string cont = new string(data, len, null_pos); return ParseAndDisplay(cont.ToCharArray()); } else return ""; } void Login(StreamWriter s, string nick, string group) { string [] outstr = { nick, nick, group, "login", "", "pil\x00" }; string str = string.Join(sep[0].ToString(), outstr); char len = (char)(str.Length + 1); s.Write(len.ToString() + "a" + str); s.Flush(); } void sendPrivate(string message) { string [] split = message.Split(wht, 2); string [] msg = { "m", split[1] + "\x00" }; string str = string.Join(sep[0].ToString(), msg); char len = (char)(str.Length + 1); w.Write(len.ToString() + "h" + str); w.Flush(); } void sendPublic(string message) { string [] split = message.Split(wht, 2); string str = split[1] + "\x00"; char len = (char)(str.Length + 1); w.Write(len.ToString() + "b" + str); w.Flush(); } void gotoGroup(string message) { string [] split = message.Split(wht, 2); string [] msg = { "g", split[1] + "\x00" }; string str = string.Join(sep[0].ToString(), msg); char len = (char)(str.Length + 1); w.Write(len.ToString() + "h" + str); w.Flush(); } void cmd(string message) { string [] split = message.Split(wht, 3); string [] msg = { split[1], split[2] + "\x00" }; string str = string.Join(sep[0].ToString(), msg); char len = (char)(str.Length + 1); w.Write(len.ToString() + "h" + str); w.Flush(); } }