void RecentCommand(CommandDetails command) { if (command.Arguments.Count == 0) { Chat(command.Channel.Name, command.Pinger + ColorGeneral + "That command is written as: " + ColorHighlightMajor + Prefixes[0] + command.Name + " <name>"); Chat(command.Channel.Name, ColorGeneral + "For example, " + ColorHighlightMajor + Prefixes[0] + command.Name + " mcmonkey"); return; } IRCUser user = new IRCUser(command.Arguments[0]); string seen = user.GetSeen(1); if (seen == null) { Chat(command.Channel.Name, command.Pinger + ColorGeneral + "I've never seen that user!"); return; } Chat(command.Channel.Name, command.Pinger + ColorGeneral + "I last saw " + ColorHighlightMajor + user.Name + ColorGeneral + " at " + ColorHighlightMinor + seen, 3); for (int i = 2; i <= 5; i++) { seen = user.GetSeen(i); if (seen != null) { Chat(command.Channel.Name, command.Pinger + ColorGeneral + "Previously, I saw " + ColorHighlightMajor + user.Name + ColorGeneral + " at " + ColorHighlightMinor + seen, 3); } } }
public void MessageCommand(CommandDetails command) { if (command.Arguments.Count <= 1) { Chat(command.Channel.Name, command.Pinger + ColorGeneral + "That command is written as: " + ColorHighlightMajor + Prefixes[0] + command.Name + " <name> <message>"); Chat(command.Channel.Name, ColorGeneral + "For example, " + ColorHighlightMajor + Prefixes[0] + command.Name + " mcmonkey Hi, how are you?"); return; } if (!IRCUser.Exists(command.Arguments[0])) { Chat(command.Channel.Name, command.Pinger + ColorGeneral + "I have never seen that user."); return; } IRCUser user = new IRCUser(command.Arguments[0]); user.SendReminder(command.User.Name + ": " + Utilities.Concat(command.Arguments, 1), DateTime.Now); Chat(command.Channel.Name, command.Pinger + ColorGeneral + "Message stored."); }
public void ReminderCommand(CommandDetails command) { if (command.Arguments.Count <= 2) { Chat(command.Channel.Name, command.Pinger + ColorGeneral + "That command is written as: " + ColorHighlightMajor + Prefixes[0] + command.Name + " <name> <time> <message>"); Chat(command.Channel.Name, ColorGeneral + "For example, " + ColorHighlightMajor + Prefixes[0] + command.Name + " mcmonkey 1d Download the code update"); return; } if (!IRCUser.Exists(command.Arguments[0])) { Chat(command.Channel.Name, command.Pinger + ColorGeneral + "I have never seen that user."); return; } IRCUser user = new IRCUser(command.Arguments[0]); TimeSpan rel = Utilities.StringToDuration(command.Arguments[1]); user.SendReminder(command.User.Name + ": " + Utilities.Concat(command.Arguments, 2), DateTime.Now.Add(rel)); Chat(command.Channel.Name, command.Pinger + ColorGeneral + "Reminder stored."); }
void SeenCommand(CommandDetails command) { if (command.Arguments.Count == 0) { Chat(command.Channel.Name, command.Pinger + ColorGeneral + "That command is written as: " + ColorHighlightMajor + Prefixes[0] + command.Name + " <name>"); Chat(command.Channel.Name, ColorGeneral + "For example, " + ColorHighlightMajor + Prefixes[0] + command.Name +" mcmonkey"); return; } IRCUser user = new IRCUser(command.Arguments[0]); string seen = user.GetSeen(1); if (seen == null) { Logger.Output(LogType.DEBUG, "Never before seen " + user.Name); Chat(command.Channel.Name, command.Pinger + ColorGeneral + "I've never seen that user!"); return; } Chat(command.Channel.Name, command.Pinger + ColorGeneral + "I last saw " + ColorHighlightMajor + user.Name + ColorGeneral + " at " + ColorHighlightMinor + seen, 3); }
void MCPingCommand(CommandDetails command) { if (command.Arguments.Count <= 0) { Chat(command.Channel.Name, command.Pinger + ColorGeneral + "That command is written as: " + ColorHighlightMajor + Prefixes[0] + command.Name + " <Minecraft server IP address>"); return; } IRCUser user = new IRCUser(command.Arguments[0]); string IP = user.Settings.ReadString("general.minecraft_server_ip", null); if (IP == null) { IP = command.Arguments[0]; } ushort port = 0; if (IP.Contains(':')) { string[] dat = IP.Split(new char[] { ':' }, 2); IP = dat[0]; port = Utilities.StringToUShort(dat[1]); } if (port == 0) { try { DnsQueryRequest dqr = new DnsQueryRequest(); DnsQueryResponse resp = dqr.Resolve("_minecraft._tcp." + IP, NsType.SRV, NsClass.ANY, ProtocolType.Tcp); if (resp != null) { for (int i = 0; i < resp.AdditionalRRecords.Count; i++) { if (resp.AdditionalRRecords[i] is SrvRecord) { port = (ushort)((SrvRecord)resp.AdditionalRRecords[i]).Port; } } for (int i = 0; i < resp.Answers.Length; i++) { if (resp.Answers[i] is SrvRecord) { port = (ushort)((SrvRecord)resp.Answers[i]).Port; } } } else { Logger.Output(LogType.DEBUG, "Null SRV record."); } if (port == 0) { port = (ushort)25565; } } catch (Exception ex) { Logger.Output(LogType.ERROR, "Pinging a SRV record for a minecraft server: " + ex.ToString()); port = 25565; } } Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { Stopwatch Timer = new Stopwatch(); Timer.Reset(); Timer.Start(); sock.SendBufferSize = 8192; sock.ReceiveBufferSize = 8192 * 10; sock.ReceiveTimeout = 3000; sock.SendTimeout = 3000; IAsyncResult result = sock.BeginConnect(IP, port, null, null); bool timeout = !result.AsyncWaitHandle.WaitOne(5000, true); if (timeout) { throw new Exception("Connection timed out"); } if (!sock.Connected) { throw new Exception("Failed to connect"); } byte[] address = UTF8.GetBytes(IP); int packlen = 1 + 1 + 1 + address.Length + 2 + 1; byte[] send = new byte[1 + packlen + 1 + 1]; byte[] portbytes = BitConverter.GetBytes(port).Reverse().ToArray(); send[0] = (byte)packlen; // packet length send[1] = (byte)0x00; // Packet ID send[2] = (byte)0x04; // Protocol Version send[3] = (byte)address.Length; // Address string length address.CopyTo(send, 4); // Address string portbytes.CopyTo(send, address.Length + 4); // Port send[address.Length + 6] = (byte)0x01; // Next state send[address.Length + 7] = (byte)0x01; // Next packet length send[address.Length + 8] = (byte)0x00; // Empty state request packet ~ packet ID sock.Send(send); int length = 0; // Packet size -> packet ID -> JSON length for (int x = 0; x < 2; x++) { length = 0; int j = 0; while (true) { byte[] recd = new byte[1]; sock.Receive(recd, 1, SocketFlags.None); int k = recd[0]; length |= (k & 0x7F) << j++ * 7; if (j > 5) throw new Exception("VarInt too big"); if ((k & 0x80) != 128) break; if (Timer.ElapsedMilliseconds > 7000) throw new Exception("Timeout while reading response"); } if (x == 0) { byte[] resp = new byte[1]; sock.Receive(resp, 1, SocketFlags.None); } } int gotten = 0; byte[] response = new byte[length]; while (gotten < length) { byte[] gotbit = new byte[length - gotten]; int newgot = sock.Receive(gotbit, length - gotten, SocketFlags.None); gotbit.CopyTo(response, gotten); gotten += newgot; if (Timer.ElapsedMilliseconds > 7000) throw new Exception("Timeout while reading response"); } string fullresponse = UTF8.GetString(response); int ind = fullresponse.IndexOf('{'); if (ind < 0) { throw new Exception("Invalid response packet - is that an actual minecraft server?"); } fullresponse = fullresponse.Substring(ind); Dictionary<string, dynamic> dict = new JavaScriptSerializer().Deserialize<Dictionary<string, dynamic>>(fullresponse.Trim()); string version = dict["version"]["name"].ToString(); string versionnum = dict["version"]["protocol"].ToString(); string players_on = dict["players"]["online"].ToString(); string players_max = dict["players"]["max"].ToString(); string description; if (dict["description"] is Dictionary<String, Object>) { description = dict["description"]["text"].ToString(); } else { description = dict["description"].ToString(); } Chat(command.Channel.Name, command.Pinger + ColorGeneral + "Server: " + IP + ":" + port.ToString() + ", MOTD: '" + Utilities.mctoirc(description) + ColorGeneral + "', players: " + players_on + "/" + players_max + ", version: " + Utilities.mctoirc(version)); } catch (Exception ex) { Logger.Output(LogType.DEBUG, "Pinging minecraft server: " + ex.ToString()); Chat(command.Channel.Name, command.Pinger + ColorGeneral + "Couldn't ping server: internal exception: " + ex.Message); } finally { sock.Close(); } }
/// <summary> /// Connects to the IRC server and runs the bot. /// </summary> void ConnectAndRun() { Logger.Output(LogType.INFO, "Connecting to " + ServerAddress + ":" + ServerPort + " as user " + Name + "..."); IRCSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IRCSocket.Connect(ServerAddress, ServerPort); Logger.Output(LogType.INFO, "Connected to " + IRCSocket.RemoteEndPoint.ToString()); string host = Configuration.ReadString("dircbot.irc-servers." + ServerName + ".host", "unknown"); SendCommand("USER", Name + " " + host + " " + host + " :" + Name); SendCommand("NICK", Name); string receivedAlready = string.Empty; while (true) { if ((DateTime.Now.Hour == 6 || DateTime.Now.Hour == 18) && DateTime.Now.Minute >= 29 && DateTime.Now.Minute <= 31 && DateTime.Now.Subtract(Started).TotalMinutes > 10) { Restart(); } long timePassed = 0; bool pinged = false; Stopwatch sw = new Stopwatch(); sw.Start(); while (IRCSocket.Available <= 0) { sw.Stop(); timePassed += sw.ElapsedMilliseconds; if (timePassed > 60 * 1000 && !pinged) { SendCommand("PING", Utilities.random.Next(10000).ToString()); pinged = true; } if (timePassed > 120 * 1000) { throw new Exception("Ping timed out!"); } sw.Reset(); sw.Start(); Thread.Sleep(1); } int avail = IRCSocket.Available; byte[] receivedNow = new byte[avail > 1024 ? 1024: avail]; IRCSocket.Receive(receivedNow, receivedNow.Length, SocketFlags.None); string got = UTF8.GetString(receivedNow).Replace("\r", ""); receivedAlready += got; while (receivedAlready.Contains('\n')) { int index = receivedAlready.IndexOf('\n'); string message = receivedAlready.Substring(0, index); receivedAlready = receivedAlready.Substring(index + 1); Logger.Output(LogType.DEBUG, "Received message: " + message); List<string> data = message.Split(' ').ToList(); string user = ""; string command = data[0]; if (command.StartsWith(":")) { user = command.Substring(1); data.RemoveAt(0); if (data.Count > 0) { command = data[0]; data.RemoveAt(0); } else { command = "null"; } } try { switch (command.ToLower()) { case "ping": // Respond to server-given PING's { SendCommand("PONG", data.Count > 0 ? data[1] : null); } break; case "433": // Nickname In Use { SendCommand("NICK", Name + "_" + Utilities.random.Next(999)); SendCommand("NS", "identify " + Name + " " + Configuration.Read("dircbot.irc-servers." + ServerName + ".nickserv.password", "")); SendCommand("NS", "ghost " + Name); SendCommand("NICK", Name); } break; case "376": // End of MOTD -> Ready To Join And Identify { SendCommand("NS", "identify " + Configuration.Read("dircbot.irc-servers." + ServerName + ".nickserv.password", "")); Channels.Clear(); foreach (string channel in BaseChannels) { SendCommand("JOIN", "#" + channel); Logger.Output(LogType.INFO, "Join Channel: #" + channel.ToLower()); IRCChannel chan = new IRCChannel() { Name = "#" + channel.ToLower() }; Channels.Add(chan); } } break; case "477": // Error joining channel resending = true; Task.Factory.StartNew(() => { Thread.Sleep(5000); foreach (string channel in BaseChannels) { SendCommand("JOIN", "#" + channel); } resending = false; }); break; case "332": // Topic for channel { if (!resending) { Task.Factory.StartNew(() => { Thread.Sleep(5000); foreach (string achannel in BaseChannels) { SendCommand("JOIN", "#" + achannel); } resending = false; }); } resending = true; string channel = data[1].ToLower(); string topic = Utilities.Concat(data, 2).Substring(1); Logger.Output(LogType.INFO, "Topic for channel: " + channel); foreach (IRCChannel chan in Channels) { if (channel == chan.Name) { chan.Topic += topic; break; } } } break; case "topic": // Fresh topic set on channel { // TODO: RECORD } break; case "join": // Someone joined { string channel = data[0].ToLower(); foreach (IRCChannel chan in Channels) { if (channel == chan.Name) { IRCUser newuser = new IRCUser(user); SeenUser(newuser.Name, newuser.IP); chan.Users.Add(newuser); Logger.Output(LogType.DEBUG, "Recognizing join of " + newuser.Name + " into " + chan.Name); if (Configuration.ReadString("dircbot.irc-servers." + ServerName + ".channels." + chan.Name.Replace("#", "") + ".greet", "false").StartsWith("t")) { foreach (string msg in Configuration.ReadStringList("dircbot.irc-servers." + ServerName + ".channels." + chan.Name.Replace("#", "") + ".greeting")) { Notice(newuser.Name, msg.Replace("<BASE>", ColorGeneral).Replace("<MAJOR>", ColorHighlightMajor).Replace("<MINOR>", ColorHighlightMinor)); } } break; } } } break; case "mode": // User mode set { // TODO: RECORD } break; case "353": // User list for channel { string channel = data[2].ToLower(); List<string> users = new List<string>(data); users.RemoveRange(0, 4); Logger.Output(LogType.INFO, "User list for channel: " + channel); foreach (IRCChannel chan in Channels) { if (channel == chan.Name) { chan.Users.Add(new IRCUser(Name + "!" + Name + "@")); foreach (string usr in users) { Logger.Output(LogType.DEBUG, "Recognize user " + usr); chan.Users.Add(new IRCUser(usr)); } break; } } } break; case "part": // Someone left the channel { string channel = data[0].ToLower(); foreach (IRCChannel chan in Channels) { if (channel == chan.Name) { IRCUser quitter = new IRCUser(user); string name = quitter.Name.ToLower(); for (int i = 0; i < chan.Users.Count; i++) { if (chan.Users[i].Name.ToLower() == name) { Logger.Output(LogType.DEBUG, "Recognizing leave of " + chan.Users[i].Name + " from " + chan.Name); chan.Users.RemoveAt(i--); break; } } break; } } } break; // TODO: Kick case "quit": // Someone left the server { IRCUser quitter = new IRCUser(user); string name = quitter.Name.ToLower(); // quitreason = concat(data, 0).substring(1); foreach (IRCChannel chan in Channels) { for (int i = 0; i < chan.Users.Count; i++) { if (chan.Users[i].Name.ToLower() == name) { Logger.Output(LogType.DEBUG, "Recognizing quit of " + chan.Users[i].Name + " from " + chan.Name); chan.Users.RemoveAt(i--); break; } } } } break; case "nick": // Someone changed their name { IRCUser renamer = new IRCUser(user); string nicknew = data[0].Substring(1); string name = renamer.Name.ToLower(); renamer.SetSeen("renaming to " + nicknew); foreach (IRCChannel chan in Channels) { for (int i = 0; i < chan.Users.Count; i++) { if (chan.Users[i].Name.ToLower() == name) { Logger.Output(LogType.DEBUG, "Recognizing rename of " + chan.Users[i].Name + " to " + nicknew); SeenUser(nicknew, renamer.IP); IRCUser theusr = chan.Users[i]; chan.Users.RemoveAt(i--); chan.Users.Add(new IRCUser(nicknew + "!" + theusr.Ident + "@" + theusr.IP) { Voice = theusr.Voice, OP = theusr.OP, EverHadVoice = theusr.EverHadVoice }); break; } } } } break; case "privmsg": // Chat message { string channel = data[0].ToLower(); data[1] = data[1].Substring(1); string privmsg = Utilities.Concat(data, 1); bool isPM = !channel.StartsWith("#"); Logger.Output(LogType.INFO, "User " + user + " spoke in channel " + channel + ", saying " + privmsg); if (isPM && privmsg == actionchr + "VERSION" + actionchr) { Notice(user.Substring(0, user.IndexOf('!')), actionchr.ToString() + "VERSION " + Configuration.Read("dircbot.version", "DenizenBot vMisconfigured") + actionchr.ToString()); } else if (isPM && privmsg.StartsWith(actionchr + "PING ")) { Notice(user.Substring(0, user.IndexOf('!')), privmsg); } IRCChannel chan = null; foreach (IRCChannel chann in Channels) { if (chann.Name == channel) { chan = chann; } } if (chan == null) { break; } IRCUser iuser = chan.GetUser(user); OnMessage(channel, iuser.Name, privmsg); if (privmsg.StartsWith(actionchr + "ACTION ")) { RecentMessages.Insert(0, new IRCMessage(chan, iuser, privmsg.Substring((actionchr + "ACTION ").Length, privmsg.Length - 1 - (actionchr + "ACTION ").Length), true)); goto post_s; } Match match = Regex.Match(privmsg, "^s/([^/]+)/([^/]+)/?([^\\s/]+)?", RegexOptions.IgnoreCase); if (match.Success) { string value = match.Groups[1].Value; string s_user = match.Groups[3].Success ? match.Groups[3].Value : null; foreach (IRCMessage msg in RecentMessages) { if (msg.Channel.Name != chan.Name || (s_user != null && s_user.ToLower() != msg.User.Name.ToLower())) { continue; } if (Regex.Match(msg.Message, value, RegexOptions.IgnoreCase).Success) { msg.Message = Regex.Replace(msg.Message, value, match.Groups[2].Value, RegexOptions.IgnoreCase); string prefix = msg.Action ? "* " + msg.User.Name + " " : "<" + msg.User.Name + "> "; Chat(chan.Name, ColorGeneral + prefix + msg.Message); goto post_s; } } } RecentMessages.Insert(0, new IRCMessage(chan, iuser, privmsg)); post_s: if (Configuration.ReadString("dircbot.irc-servers." + ServerName + ".channels." + chan.Name.Replace("#", "") + ".link_read", "false").StartsWith("t")) { foreach (string str in data) { if (str.StartsWith("http://") || str.StartsWith("https://")) { Task.Factory.StartNew(() => { try { LowTimeoutWebclient ltwc = new LowTimeoutWebclient(); ltwc.Encoding = UTF8; string web = ltwc.DownloadString(str); if (web.Contains("<title>") && web.Contains("</title>")) { web = web.Substring(web.IndexOf("<title>") + 7); web = web.Substring(0, web.IndexOf("</title>")); web = web.Replace("\r", "").Replace("\n", ""); web = web.Replace("<", "<").Replace(">", ">"); web = web.Replace(""", "\"").Replace("&", (char)0x01 + "amp"); string webtitle = ""; bool flip = false; for (int x = 0; x < web.Length; x++) { if (web[x] == '&') { flip = true; continue; } else if (web[x] == ';') { if (flip) { flip = false; continue; } } else if (web[x] == ' ' && x > 0 && web[x - 1] == ' ') { continue; } if (!flip) { webtitle += web[x].ToString(); } } webtitle = webtitle.Trim().Replace((char)0x01 + "amp", "&"); Chat(chan.Name, ColorGeneral + "Title --> " + ColorHighlightMinor + webtitle.Trim(), 1); } } catch (Exception ex) { Logger.Output(LogType.DEBUG, "Failed to read webpage " + str + ": " + ex.ToString()); } }); } } } if (iuser == null) { Logger.Output(LogType.INFO, "Null user sent message to channel!"); break; } if (string.IsNullOrEmpty(iuser.IP)) { iuser.ParseMask(user); } CheckReminders(iuser, chan); if (Configuration.ReadString("dircbot.irc-servers." + ServerName + ".channels." + chan.Name.Replace("#", "") + ".record_seen", "false").StartsWith("t")) { Task.Factory.StartNew(() => { try { iuser.SetSeen("in " + chan.Name + ", saying " + privmsg); } catch (Exception ex) { Logger.Output(LogType.ERROR, "SEEN user " + iuser.OriginalMask + ": " + ex.ToString()); } }); } if (Configuration.ReadString("dircbot.irc-servers." + ServerName + ".channels." + chan.Name.Replace("#", "") + ".has_log_page", "false").StartsWith("t")) { Log(chan.Name, Utilities.FormatDate(DateTime.Now) + " <" + iuser.Name + "> " + privmsg); } bool cmd = false; List<string> cmds = new List<string>(data); cmds.RemoveAt(0); string cmdlow = cmds[0].ToLower(); if (cmdlow.StartsWith(Name.ToLower())) { Logger.Output(LogType.DEBUG, "Was pinged by " + cmdlow); cmd = true; cmds.RemoveAt(0); } else { foreach (string prefix in Prefixes) { if (cmdlow.StartsWith(prefix.ToLower())) { cmd = true; cmds[0] = cmds[0].Substring(prefix.Length); Logger.Output(LogType.DEBUG, "Recognized " + prefix + " in " + cmds[0]); break; } } } if (cmd) { CommandDetails details = new CommandDetails(); details.Name = cmds[0]; cmds.RemoveAt(0); details.Arguments = cmds; details.Channel = chan; details.User = iuser; details.Pinger = ""; Logger.Output(LogType.INFO, "Try command " + details.Name + " for " + details.User.Name); if (cmds.Count > 0) { string cmdlast = cmds[cmds.Count - 1]; if (cmdlast.Contains("@")) { string pingme = cmdlast.Replace("@", ""); IRCUser usr = chan.GetUser(pingme); if (usr != null) { details.Pinger = usr.Name + ": "; cmds.RemoveAt(cmds.Count - 1); } } } new Task(() => { try { TryCommand(details); } catch (Exception ex) { if (ex is ThreadAbortException) { throw ex; } Logger.Output(LogType.ERROR, "Command parsing of " + details.Name + ":: " + ex.ToString()); } }).Start(); } } break; case "notice": // NOTICE message break; default: break; } } catch (Exception ex) { if (ex is SocketException) { throw ex; } Logger.Output(LogType.ERROR, "Error: " + ex.ToString()); } } } }
public IRCMessage(IRCChannel channel, IRCUser user, string message, bool action = false) { Channel = channel; User = user; Message = message; Action = action; }
public void CheckReminders(IRCUser user, IRCChannel channel) { List<string> rem = user.GetReminders(); if (rem.Count > 30) { Chat(channel.Name, user.Name + ": You are about to receive " + rem.Count + " messages. Please tell an admin if you are being spammed!"); } if (rem.Count > 0) { Chat(channel.Name, user.Name + ": I have messages for you!"); Task.Factory.StartNew(() => { for (int i = 0; i < rem.Count; i++) { Notice(user.Name, rem[i]); Thread.Sleep(500); } }); } }
void MCPingCommand(CommandDetails command) { if (command.Arguments.Count <= 0) { Chat(command.Channel.Name, command.Pinger + ColorGeneral + "That command is written as: " + ColorHighlightMajor + Prefixes[0] + command.Name + " <Minecraft server IP address>"); return; } IRCUser user = new IRCUser(command.Arguments[0]); string IP = user.Settings.ReadString("general.minecraft_server_ip", null); if (IP == null) { IP = command.Arguments[0]; } ushort port = 0; if (IP.Contains(':')) { string[] dat = IP.Split(new char[] { ':' }, 2); IP = dat[0]; port = Utilities.StringToUShort(dat[1]); } if (port == 0) { try { DnsQueryRequest dqr = new DnsQueryRequest(); DnsQueryResponse resp = dqr.Resolve("_minecraft._tcp." + IP, NsType.SRV, NsClass.ANY, ProtocolType.Tcp); if (resp != null) { for (int i = 0; i < resp.AdditionalRRecords.Count; i++) { if (resp.AdditionalRRecords[i] is SrvRecord) { port = (ushort)((SrvRecord)resp.AdditionalRRecords[i]).Port; } } for (int i = 0; i < resp.Answers.Length; i++) { if (resp.Answers[i] is SrvRecord) { port = (ushort)((SrvRecord)resp.Answers[i]).Port; } } } else { Logger.Output(LogType.DEBUG, "Null SRV record."); } if (port == 0) { port = (ushort)25565; } } catch (Exception ex) { Logger.Output(LogType.ERROR, "Pinging a SRV record for a minecraft server: " + ex.ToString()); port = 25565; } } Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { Stopwatch Timer = new Stopwatch(); Timer.Reset(); Timer.Start(); sock.SendBufferSize = 8192; sock.ReceiveBufferSize = 8192 * 10; sock.ReceiveTimeout = 3000; sock.SendTimeout = 3000; IAsyncResult result = sock.BeginConnect(IP, port, null, null); bool timeout = !result.AsyncWaitHandle.WaitOne(5000, true); if (timeout) { throw new Exception("Connection timed out"); } if (!sock.Connected) { throw new Exception("Failed to connect"); } byte[] address = UTF8.GetBytes(IP); int packlen = 1 + 1 + 1 + address.Length + 2 + 1; byte[] send = new byte[1 + packlen + 1 + 1]; byte[] portbytes = BitConverter.GetBytes(port).Reverse().ToArray(); send[0] = (byte)packlen; // packet length send[1] = (byte)0x00; // Packet ID send[2] = (byte)0x04; // Protocol Version send[3] = (byte)address.Length; // Address string length address.CopyTo(send, 4); // Address string portbytes.CopyTo(send, address.Length + 4); // Port send[address.Length + 6] = (byte)0x01; // Next state send[address.Length + 7] = (byte)0x01; // Next packet length send[address.Length + 8] = (byte)0x00; // Empty state request packet ~ packet ID sock.Send(send); int length = 0; // Packet size -> packet ID -> JSON length for (int x = 0; x < 2; x++) { length = 0; int j = 0; while (true) { byte[] recd = new byte[1]; sock.Receive(recd, 1, SocketFlags.None); int k = recd[0]; length |= (k & 0x7F) << j++ *7; if (j > 5) { throw new Exception("VarInt too big"); } if ((k & 0x80) != 128) { break; } if (Timer.ElapsedMilliseconds > 7000) { throw new Exception("Timeout while reading response"); } } if (x == 0) { byte[] resp = new byte[1]; sock.Receive(resp, 1, SocketFlags.None); } } int gotten = 0; byte[] response = new byte[length]; while (gotten < length) { byte[] gotbit = new byte[length - gotten]; int newgot = sock.Receive(gotbit, length - gotten, SocketFlags.None); gotbit.CopyTo(response, gotten); gotten += newgot; if (Timer.ElapsedMilliseconds > 7000) { throw new Exception("Timeout while reading response"); } } string fullresponse = UTF8.GetString(response); int ind = fullresponse.IndexOf('{'); if (ind < 0) { throw new Exception("Invalid response packet - is that an actual minecraft server?"); } fullresponse = fullresponse.Substring(ind); Dictionary <string, dynamic> dict = new JavaScriptSerializer().Deserialize <Dictionary <string, dynamic> >(fullresponse.Trim()); string version = dict["version"]["name"].ToString(); string versionnum = dict["version"]["protocol"].ToString(); string players_on = dict["players"]["online"].ToString(); string players_max = dict["players"]["max"].ToString(); string description; if (dict["description"] is Dictionary <String, Object> ) { description = dict["description"]["text"].ToString(); } else { description = dict["description"].ToString(); } Chat(command.Channel.Name, command.Pinger + ColorGeneral + "Server: " + IP + ":" + port.ToString() + ", MOTD: '" + Utilities.mctoirc(description) + ColorGeneral + "', players: " + players_on + "/" + players_max + ", version: " + Utilities.mctoirc(version)); } catch (Exception ex) { Logger.Output(LogType.DEBUG, "Pinging minecraft server: " + ex.ToString()); Chat(command.Channel.Name, command.Pinger + ColorGeneral + "Couldn't ping server: internal exception: " + ex.Message); } finally { sock.Close(); } }
public void ReadLogs() { string[] logsets = Directory.GetFileSystemEntries(Environment.CurrentDirectory + "/data/logs"); foreach (string channel in logsets) { Logger.Output(LogType.DEBUG, "Found channel: " + channel); string[] years = Directory.GetFileSystemEntries(channel); foreach (string str_year in years) { Logger.Output(LogType.DEBUG, "Found year: " + str_year); string[] months = Directory.GetFileSystemEntries(str_year); foreach (string str_month in months) { Logger.Output(LogType.DEBUG, "Found month: " + str_month); string[] days = Directory.GetFileSystemEntries(str_month); foreach (string str_day in days) { try { Logger.Output(LogType.DEBUG, "Found day: " + str_day); string file = File.ReadAllText(str_day); string[] file_split = file.Split('\n'); bool reading = false; for (int i = 0; i < file_split.Length; i++) { if (!reading && file_split[i].Trim() == "") { reading = true; } else if (reading) { string data = file_split[i]; bool is_old = data.StartsWith(C_S_COLOR + ""); for (int x = 0; x < 16; x++) { data = data.Replace(C_S_COLOR + Utilities.FormatNumber(x), ""); } string[] splits = data.Replace(" AM", "").Replace(" PM", "").Split(new char[] { ' ' }, 4); if (splits.Length == 4) { string[] date = splits[0].Split('/'); string[] time = splits[1].Split(':'); if (time.Length != 3) { Logger.Output(LogType.DEBUG, "Found " + splits[1] + " instead of a 3-length timestamp"); } else if (splits[2].StartsWith("<") && splits[2].EndsWith(">") && !splits[3].StartsWith("*")) { string name = splits[2].Substring(1, splits[2].Length - 2); string message = splits[3]; IRCUser user = new IRCUser(name); string sy = str_year.Substring(str_year.LastIndexOf('\\') + 1).Replace(".log", ""); sy = sy.Substring(sy.LastIndexOf('/') + 1); string sm = str_month.Substring(str_month.LastIndexOf('\\') + 1).Replace(".log", ""); sm = sm.Substring(sm.LastIndexOf('/') + 1); string sd = str_day.Substring(str_day.LastIndexOf('\\') + 1).Replace(".log", ""); sd = sd.Substring(sd.LastIndexOf('/') + 1); int y = Utilities.StringToInt(sy); int m = Utilities.StringToInt(sm); int d = Utilities.StringToInt(sd); DateTime dt = new DateTime(y, m, d, Utilities.StringToInt(time[0]), Utilities.StringToInt(time[1]), Utilities.StringToInt(time[2])); string ch = channel.Substring(channel.LastIndexOf('\\') + 1); ch = ch.Substring(ch.LastIndexOf('/') + 1); user.SetSeen("in #" + ch + ", saying " + message, dt); } else if (splits[2] == "*" && splits[3].EndsWith(") joined.")) { int ind = splits[3].IndexOf(' '); string name = splits[3].Substring(0, ind); string ip = splits[3].Substring(ind + 1, ((splits[3].Length - ") joined.".Length) - ind) - 1); SeenUser(name, ip, false); } } } } } catch (Exception ex) { Logger.Output(LogType.ERROR, "Failed to read " + str_year + "/" + str_month + "/" + str_day + ": " + ex.ToString()); } } } } } saveSeenList(); Chat("#monkeybot", ColorGeneral + "Finished reading log files."); }