public static void cmd_kick(Bot bot, String ns, String[] args, String msg, String from, dAmnPacket packet) { String helpmsg = String.Format("<b>» Usage:</b> {0}kick <i>[#channel]</i> username <i>[reason]</i>", bot.Config.Trigger); if (args.Length < 2) { bot.Say(ns, helpmsg); } else { String chan, who, reason; if (!args[1].StartsWith("#")) { chan = ns; who = args[1]; reason = (args.Length >= 3 ? ": " + msg.Substring(6 + who.Length) : ""); } else if (args.Length >= 3) { chan = args[1]; who = args[2]; reason = (args.Length >= 4 ? ": " + msg.Substring(7 + who.Length + chan.Length) : ""); } else { bot.Say(ns, helpmsg); return; } lock (CommandChannels["kick"]) { CommandChannels["kick"].Add(ns); } bot.Kick(chan, who, "<b>" + from + "</b>" + reason); } }
/// <summary> /// Parses BDS messages /// </summary> /// <param name="bot">Bot instance</param> /// <param name="packet">Packet object</param> public void ParseBDS(Bot bot, dAmnPacket packet) { if (packet.Parameter == "chat:Botdom" && packet.Body.ToLower().StartsWith("<abbr title=\"" + bot.Config.Username.ToLower() + ": botcheck\"></abbr>")) { String hash = Tools.md5((bot.Config.Trigger + packet.Arguments["from"] + bot.Config.Username).Replace(" ", "").ToLower()); bot.Say(packet.Parameter, String.Format("Beep! <abbr title=\"botresponse: {0} {1} {2} {3} {4} {5}\"></abbr>", packet.Arguments["from"], bot.Config.Owner, Program.BotName, Program.Version, hash, bot.Config.Trigger)); return; } // Not from DS? Ignore it. if (packet.Parameter.ToLower() != "chat:datashare" && packet.Parameter.ToLower() != "chat:dsgateway" && !syncing) return; // Doesn't contain segments? Ignore it. if (!packet.Body.Contains(":")) return; String msg = packet.Body; String[] bits = msg.Split(':'); String ns = packet.Parameter; String from = packet.Arguments["from"]; String username = bot.Config.Username; String trigger = bot.Config.Trigger; String owner = bot.Config.Owner; bool from_policebot = IsPoliceBot(from, packet.Parameter); if (bits[0] == "BDS") { if (bits.Length >= 3 && bits[1] == "SYNC") { if (bits.Length == 4 && bits[2] == "REQUEST" && bits[3].ToLower() == username.ToLower()) { if (!syncing && !isrequester && IsPoliceBot(username, "chat:DataShare", true)) { syncwith = from.ToLower(); bot.NPSay(ns, String.Format("BDS:SYNC:RESPONSE:{0},{1},{2}", from, BDBHash(), _botinfo_database.Count)); } } else if (bits[2] == "BEGIN" && !isrequester && ns.StartsWith("pchat:") && syncing && ns.ToLower().Contains(syncwith) && from.ToLower() != username.ToLower()) { bots_synced = 0; clients_synced = 0; foreach (var x in _botinfo_database.Values) { bot.NPSay(ns, String.Format("BDS:SYNC:INFO:{0},{1},{2},{3}/{4},{5},{6}", x.Name, x.Owner, x.Type, x.Version, x.BDSVersion, x.Modified, x.Trigger)); bots_synced++; if (bots_synced % 100 == 0) System.Threading.Thread.Sleep(250); } foreach (var x in _clientinfo_database.Values) { bot.NPSay(ns, String.Format("BDS:SYNC:CLIENTINFO:{0},{1},{2}/{3},{4}", x.Name, x.Type, x.Version, x.BDSVersion, x.Modified)); clients_synced++; if (clients_synced % 100 == 0) System.Threading.Thread.Sleep(250); } bot.NPSay(ns, "BDS:SYNC:FINISHED"); bot.NPSay(ns, "BDS:LINK:CLOSED"); bot.Part(ns); syncwith = ""; bots_synced = 0; clients_synced = 0; syncing = false; } else if (bits.Length == 4 && bits[2] == "RESPONSE") { if (!bits[3].Contains(",")) return; String[] data = bits[3].Split(','); if (data.Length != 3) return; if (data[0].ToLower() != username.ToLower()) return; if (data[1] != BDBHash()) { syncwith = from.ToLower(); bot.NPSay(ns, "BDS:LINK:REQUEST:" + from); } else { bot.NPSay(ns, "BDS:SYNC:OKAY:" + from); syncing = false; } } else if (bits[2] == "FINISHED") { if (syncrns != "") { syncwatch.Stop(); bot.Say(syncrns, String.Format("<b>» Finished syncing for {0} bot{1} and {2} client{3} took <abbr title=\"{4}\">{5}</abbr></b>", bots_synced, bots_synced == 1 ? "" : "s", clients_synced, clients_synced == 1 ? "" : "s", syncwatch.Elapsed, Tools.FormatTime((ulong)syncwatch.Elapsed.TotalSeconds))); } syncwith = ""; syncrns = ""; bots_synced = 0; clients_synced = 0; bot.NPSay(ns, "BDS:LINK:CLOSED"); bot.Part(ns); syncing = false; isrequester = false; } else if (bits.Length >= 4 && bits[2] == "INFO") { if (!bits[3].Contains(",")) return; String input = String.Empty; for (byte b = 3; b < bits.Length; b++) { if (b >= bits.Length - 1) input += bits[b]; else input += bits[b] + ":"; } String[] data = input.Split(','); if (data.Length < 6 || !data[3].Contains("/")) return; String who = data[0].ToLower(); String[] versions = data[3].Split('/'); String botver = versions[0]; ulong ts = Bot.EpochTimestamp; String trig = data[5]; double bdsver = 0.0; // trigger contains a comma? if (data.Length > 6) { trig = String.Empty; for (int b = 6; b < data.Length; b++) { if (b >= data.Length - 1) trig += data[b]; else trig += data[b] + ","; } } if (!Double.TryParse(versions[1], out bdsver)) bdsver = 0.2; Types.BotInfo bot_info = new Types.BotInfo(data[0], data[1], data[2], botver, trig, bdsver, ts); if (!_botinfo_database.ContainsKey(who)) _botinfo_database.Add(who, bot_info); else _botinfo_database[who] = bot_info; if (Program.Debug) ConIO.Write("Updated information for bot: " + data[0], "BDS"); bots_synced++; } else if (bits.Length >= 4 && bits[2] == "CLIENTINFO") { if (!bits[3].Contains(",")) return; String input = String.Empty; for (byte b = 3; b < bits.Length; b++) { if (b >= bits.Length - 1) input += bits[b]; else input += bits[b] + ":"; } String[] data = input.Split(','); if (data.Length < 4 || !data[2].Contains("/")) return; String who = data[0].ToLower(); String[] versions = data[2].Split('/'); String clientver = versions[0]; ulong ts = Bot.EpochTimestamp; double bdsver = 0.0; if (!Double.TryParse(versions[1], out bdsver)) bdsver = 0.2; Types.ClientInfo client_info = new Types.ClientInfo(data[0], data[1], clientver, bdsver, ts); if (!_clientinfo_database.ContainsKey(who)) _clientinfo_database.Add(who, client_info); else _clientinfo_database[who] = client_info; if (Program.Debug) ConIO.Write("Updated information for client: " + data[0], "BDS"); clients_synced++; } } else if (bits.Length >= 3 && bits[1] == "LINK") { if (bits.Length == 4 && bits[3].ToLower() == username.ToLower()) { if (bits[2] == "ACCEPT" && from.ToLower() == syncwith) { bot.Join(Tools.FormatPCNS(from, username)); } else if (bits[2] == "REJECT" && from.ToLower() == syncwith) { syncwith = ""; syncing = false; isrequester = false; } else if (bits[2] == "REQUEST" && !syncing && from.ToLower() == syncwith) { syncing = true; bot.NPSay(ns, "BDS:LINK:ACCEPT:" + from); bot.Join(Tools.FormatPCNS(from, username)); } } } else if (bits.Length >= 4 && bits[1] == "SEEN" && IsPoliceBot(username, pboverride: true)) { if (bits[2] == "REQUEST" && bits[3].Contains(',')) { var payload = bits[3].Split(','); if (payload.Length >= 2 && payload[0].ToLower() == username.ToLower()) { var who = payload[1].ToLower(); if (!BDS._seen_database.ContainsKey(who)) bot.NPSay(ns, "BDS:SEEN:NODATA:" + from + "," + payload[1]); else { var info = BDS._seen_database[who]; bot.NPSay(ns, String.Format("BDS:SEEN:RESPONSE:{0},{1},{2},{3},{4}", from, info.Name, info.Type, info.Channel, info.Timestamp)); } } } else if (bits[2] == "PROVIDER" && bits[3].ToLower() == username.ToLower()) { if (!SeenProviders.Contains(from.ToLower()) && IsPoliceBot(from, ns)) SeenProviders.Add(from.ToLower()); } } else if (bits.Length >= 4 && bits[1] == "PROVIDER" && bits[2] == "CAPS" && IsPoliceBot(username, pboverride: true)) { if (bits[3].Contains(',') && from.ToLower() != username.ToLower()) { var payload = new List<String>(bits[3].ToLower().Split(',')); if (payload.Contains("seen")) bot.NPSay(ns, "BDS:SEEN:PROVIDER:" + from); } else if (bits[3].ToLower() == "seen") { bot.NPSay(ns, "BDS:SEEN:PROVIDER:" + from); } } else if (bits.Length >= 3 && bits[1] == "BOTCHECK") { if (bits[2] == "OK" && bits.Length >= 4 && bits[3].ToLower() == username.ToLower()) { if (!from_policebot || from.ToLower() == username.ToLower()) return; if (!IsPoliceBot(username, "chat:DSGateway", true)) bot.Part("chat:DSGateWay"); bot.Join("chat:DataShare"); } else if (bits[2] == "DENIED" && bits.Length >= 4 && bits[3].ToLower().StartsWith(username.ToLower() + ',')) { if (!from_policebot) return; // Look for a valid string if (!bits[3].Contains(",")) return; String input = String.Empty; for (byte b = 3; b < bits.Length; b++) { if (b >= bits.Length - 1) input += bits[b]; else input += bits[b] + ":"; } String reason = input.Substring(username.Length + 1); ConIO.Warning("#DataShare", "Denied access: " + reason); bot.Part("chat:DSGateway"); } else if (bits[2] == "ALL" || (bits.Length >= 4 && bits[2] == "DIRECT" && bits[3].ToLower() == username.ToLower())) { // If it's not a police bot, return. if (bits[2] == "ALL" && !from_policebot) return; String hashkey = Tools.md5((trigger + from + username).Replace(" ", "").ToLower()); bot.NPSay(ns, String.Format("BDS:BOTCHECK:RESPONSE:{0},{1},{2},{3}/{4},{5},{6}", from, owner, Program.BotName, Program.Version, Version, hashkey, trigger)); } else if (bits[2] == "DIRECT" && bits[3].ToLower().Contains(",")) { List<String> bots = new List<String>(bits[3].ToLower().Split(new char[] { ',' })); if (bots.Contains(username.ToLower())) { String hashkey = Tools.md5((trigger + from + username).Replace(" ", "").ToLower()); bot.NPSay(ns, String.Format("BDS:BOTCHECK:RESPONSE:{0},{1},{2},{3}/{4},{5},{6}", from, owner, Program.BotName, Program.Version, Version, hashkey, trigger)); } } else if (bits[2] == "RESPONSE" && bits.Length >= 4) { // Look for a valid string if (!bits[3].Contains(",")) return; // Possibly add privclass/client checks // Handle it String input = String.Empty; for (byte b = 3; b < bits.Length; b++) { if (b >= bits.Length - 1) input += bits[b]; else input += bits[b] + ":"; } String[] data = input.Split(','); // Invalid data if (data.Length < 6 || !data[3].Contains("/")) return; String[] versions = data[3].Split('/'); String botver = versions[0]; String hash = data[4]; String trig = data[5]; double bdsver = 0.0; // trigger contains a comma? if (data.Length > 6) { trig = String.Empty; for (int b = 6; b < data.Length; b++) { if (b >= data.Length - 1) trig += data[b]; else trig += data[b] + ","; } } if (!Double.TryParse(versions[1], out bdsver)) bdsver = 0.2; Types.BotInfo bot_info = new Types.BotInfo(from, data[1], data[2], botver, trig, bdsver, Bot.EpochTimestamp); String hashkey = Tools.md5((trig + data[0] + from).ToLower().Replace(" ", "")).ToLower(); ClearKickTimers(from); if (hashkey != hash) { // Invalid hash supplied // For now, we ignore this. Though I'd like to see policebots send and error like: // BDS:BOTCHECK:ERROR:INVALID_RESPONSE_HASH // Police bot stuff. if ((ns == "chat:DSGateway" || ns == "chat:DataShare") && IsPoliceBot(username, ns)) { if (ns == "chat:DSGateway") bot.NPSay(ns, "BDS:BOTCHECK:DENIED:" + from + ",Invalid BDS:BOTCHECK"); bot.Kick(ns, from, "No response to or invalid BDS:BOTCHECK. If you are not a bot, please do not join this room. Thanks."); bot.Promote("chat:DataShare", from, "BrokenBots"); if (!Kicks.ContainsKey(from)) Kicks.Add(from, new KickInfo()); Kicks[from].Kick(); if (Kicks[from].Count >= 3) { bot.Ban(ns, from); var t = new Timer(5000); t.Elapsed += delegate { bot.UnBan(ns, from); }; t.Start(); } } if (Program.Debug) ConIO.Warning("BDS", "Invalid hash for bot: " + from); } else { // Police bot stuff. if ((ns == "chat:DSGateway" || ns == "chat:DataShare") && IsPoliceBot(username, ns)) { if (ns == "chat:DSGateway") { if (!GateChecks.Contains(from)) GateChecks.Add(from); bot.NPSay(ns, "BDS:BOTCHECK:OK:" + from); } bot.Promote("chat:DataShare", from, "Bots"); } lock (_botinfo_database) { if (_botinfo_database.ContainsKey(from.ToLower())) { _botinfo_database[from.ToLower()] = bot_info; if (Program.Debug) ConIO.Write("Updated database for bot: " + from, "BDS"); } else { _botinfo_database.Add(from.ToLower(), bot_info); if (Program.Debug) ConIO.Write("Added bot to database: " + from, "BDS"); } } } } else if (bits[2] == "CLIENT" && bits.Length >= 4) { // Look for a valid string if (!bits[3].Contains(",")) return; // Handle it String input = String.Empty; for (byte b = 3; b < bits.Length; b++) { if (b >= bits.Length - 1) input += bits[b]; else input += bits[b] + ":"; } String[] data = input.Split(','); // Invalid data if (data.Length < 4) return; String name = data[1]; String[] vers; String ver = String.Empty; String hash = data[3]; double bdsver = 0.0; if (data[2].Contains('/')) { vers = data[2].Split('/'); ver = vers[0]; if (!Double.TryParse(vers[vers.Length - 1], out bdsver)) bdsver = 0.2; if (vers.Length > 2) ver = data[2].Substring(0, data[2].LastIndexOf('/')); } else { ver = data[2]; } Types.ClientInfo client_info = new ClientInfo(from, name, ver, bdsver, Bot.EpochTimestamp); String hashkey = String.Empty; if (bdsver == 0.0) { hashkey = Tools.md5((name + ver + from + data[0]).Replace(" ", "").ToLower()).ToLower(); } else { hashkey = Tools.md5((name + ver + "/" + bdsver + from + data[0]).Replace(" ", "").ToLower()).ToLower(); } ClearKickTimers(from); if (hashkey != hash) { // Invalid hash supplied // For now, we ignore this. Though I'd like to see policebots send and error like: // BDS:BOTCHECK:ERROR:INVALID_RESPONSE_HASH // Police bot stuff. if ((ns == "chat:DSGateway" || ns == "chat:DataShare") && IsPoliceBot(username, ns)) { if (ns == "chat:DSGateway") bot.NPSay(ns, "BDS:BOTCHECK:DENIED:" + from + ",Invalid BDS:BOTCHECK"); bot.Kick(ns, from, "No response to or invalid BDS:BOTCHECK. If you are not a bot, please do not join this room. Thanks."); bot.Promote("chat:DataShare", from, "BrokenClients"); if (!Kicks.ContainsKey(from)) Kicks.Add(from, new KickInfo()); Kicks[from].Kick(); if (Kicks[from].Count >= 3) { bot.Ban(ns, from); var t = new Timer(5000); t.Elapsed += delegate { bot.UnBan(ns, from); }; t.Start(); } } if (Program.Debug) ConIO.Warning("BDS", "Invalid hash for client: " + from); } else { // Police bot stuff. if ((ns == "chat:DSGateway" || ns == "chat:DataShare") && IsPoliceBot(username, ns)) { if (ns == "chat:DSGateway") { if (!GateChecks.Contains(from)) GateChecks.Add(from); bot.NPSay(ns, "BDS:BOTCHECK:OK:" + from); } bot.Promote("chat:DataShare", from, "Clients"); } lock (_clientinfo_database) { if (_clientinfo_database.ContainsKey(from.ToLower())) { _clientinfo_database[from.ToLower()] = client_info; if (Program.Debug) ConIO.Write("Updated database for client: " + from, "BDS"); } else { _clientinfo_database.Add(from.ToLower(), client_info); if (Program.Debug) ConIO.Write("Added client to database: " + from, "BDS"); } } } } else if (bits.Length >= 4 && bits[2] == "INFO") { if (!bits[3].Contains(",")) return; // Handle it String input = String.Empty; for (byte b = 3; b < bits.Length; b++) { if (b >= bits.Length - 1) input += bits[b]; else input += bits[b] + ":"; } String[] data = input.Split(','); // Invalid data if (data.Length < 5 || !data[2].Contains("/")) return; String[] versions = data[2].Split('/'); String botver = versions[0]; String trig = data[4]; double bdsver = 0.0; // trigger contains a comma? if (data.Length > 5) { trig = String.Empty; for (int b = 5; b < data.Length; b++) { if (b >= data.Length - 1) trig += data[b]; else trig += data[b] + ","; } } if (!Double.TryParse(versions[1], out bdsver)) bdsver = 0.2; Types.BotInfo bot_info = new Types.BotInfo(data[0], data[3], data[1], botver, trig, bdsver, Bot.EpochTimestamp); lock (_botinfo_database) { if (_botinfo_database.ContainsKey(data[0].ToLower())) { _botinfo_database[data[0].ToLower()] = bot_info; if (Program.Debug) ConIO.Write("Updated database for bot: " + data[0], "BDS"); } else { _botinfo_database.Add(data[0].ToLower(), bot_info); if (Program.Debug) ConIO.Write("Added bot to database: " + data[0], "BDS"); } } lock (_info_requests) { if (_info_requests.ContainsKey(data[0].ToLower())) { String chan = _info_requests[data[0].ToLower()]; _info_requests.Remove(data[0].ToLower()); String output = String.Format("<b>» Information on :dev{0}:</b><br/>", bot_info.Name); output += String.Format("<b>Bot type:</b> {0}<br/>", bot_info.Type); output += String.Format("<b>Bot version:</b> {0}<br/>", bot_info.Version); output += String.Format("<b>Bot owner:</b> :dev{0}:<br/>", bot_info.Owner); output += String.Format("<b>Bot trigger:</b> <b><code>{0}</code></b><br/>", bot_info.Trigger.Replace("&", "&")); output += String.Format("<b>BDS version:</b> {0}<br/>", bot_info.BDSVersion); bot.Say(chan, output); } } } else if (bits.Length >= 4 && bits[2] == "CLIENTINFO") { if (!bits[3].Contains(",")) return; // Handle it String input = String.Empty; for (byte b = 3; b < bits.Length; b++) { if (b >= bits.Length - 1) input += bits[b]; else input += bits[b] + ":"; } String[] data = input.Split(','); // Invalid data if (data.Length < 3) return; String name = data[1]; String[] vers = data[2].Split('/'); String ver = vers[0]; double bdsver = 0.2; if (!Double.TryParse(vers[vers.Length - 1], out bdsver)) bdsver = 0.2; if (vers.Length > 2) ver = data[2].Substring(0, data[2].LastIndexOf('/')); Types.ClientInfo client_info = new ClientInfo(data[0], name, ver, bdsver, Bot.EpochTimestamp); lock (_clientinfo_database) { if (_clientinfo_database.ContainsKey(data[0].ToLower())) { _clientinfo_database[data[0].ToLower()] = client_info; if (Program.Debug) ConIO.Write("Updated database for client: " + data[0], "BDS"); } else { _clientinfo_database.Add(data[0].ToLower(), client_info); if (Program.Debug) ConIO.Write("Added client to database: " + data[0], "BDS"); } } lock (_info_requests) { if (_info_requests.ContainsKey(data[0].ToLower())) { String chan = _info_requests[data[0].ToLower()]; _info_requests.Remove(data[0].ToLower()); String output = String.Format("<b>» Information on :dev{0}:</b><br/>", client_info.Name); output += String.Format("<b>Client type:</b> {0}<br/>", client_info.Type); output += String.Format("<b>Client version:</b> {0}", client_info.Version); bot.Say(chan, output); } } } else if (bits.Length >= 4 && bits[2] == "NODATA") { // Ignore data from non-police bots if (!from_policebot) return; lock (_info_requests) { if (_info_requests.ContainsKey(bits[3].ToLower())) { String chan = _info_requests[bits[3].ToLower()]; _info_requests.Remove(bits[3].ToLower()); bot.Say(chan, "<b>» Bot/client doesn't exist:</b> " + bits[3]); } } } else if (bits.Length >= 4 && bits[2] == "BADBOT") { // Ignore data from non-police bots if (!from_policebot) return; if (!bits[3].Contains(",")) return; String[] data = bits[3].Split(','); lock (_info_requests) { if (_info_requests.ContainsKey(data[0].ToLower())) { String chan = _info_requests[data[0].ToLower()]; _info_requests.Remove(data[0].ToLower()); bot.Say(chan, "<b>» Bot is banned:</b> " + data[0]); } } // Maybe store this later. } else if (bits.Length >= 4 && bits[2] == "BADCLIENT") { // Ignore data from non-police bots if (!from_policebot) return; if (!bits[3].Contains(",")) return; String[] data = bits[3].Split(','); lock (_info_requests) { if (_info_requests.ContainsKey(data[0].ToLower())) { String chan = _info_requests[data[0].ToLower()]; _info_requests.Remove(data[0].ToLower()); bot.Say(chan, "<b>» Client is banned:</b> " + data[0]); } } // Maybe store this later. } } else if (bits.Length >= 4 && bits[1] == "BOTDEF") { if (bits[2] == "REQUEST" && bits[3] == username.ToLower()) { // If it's not the police bot, return. if (from_policebot) return; String hashkey = Tools.md5((from + Program.BotName + "DivinityArcane").ToLower()); bot.NPSay(ns, String.Format("BDS:BOTDEF:RESPONSE:{0},{1},{2},{3},{4},{5}", from, Program.BotName, "C#", "DivinityArcane", "http://botdom.com/wiki/LulzBot", hashkey)); } } else if (bits.Length >= 4 && bits[1] == "TRANSLATE" && bits[2] == "RESPONSE") { // Ignore data from non-police bots if (!from_policebot) return; if (!bits[3].Contains(",")) return; String input = String.Empty; for (byte b = 3; b < bits.Length; b++) { if (b >= bits.Length - 1) input += bits[b]; else input += bits[b] + ":"; } String[] data = input.Split(','); if (data[0].ToLower() != username.ToLower() || data.Length < 3) return; lock (_translate_requests) { if (_translate_requests.Contains(data[1])) { int id = _translate_requests.IndexOf(data[1]); String chan = _translate_requests[id]; _translate_requests.RemoveAt(id); bot.Say(chan, "<b>» Translated text:</b> " + Tools.HtmlEncode(Encoding.UTF8.GetString(Convert.FromBase64String(data[2])))); } } } } else if (bits[0] == "LDS") { if (bits.Length >= 4 && bits[1] == "UPDATE") { if (bits[2] == "PING" && bits[3].ToLower() == username.ToLower()) { bot.NPSay(ns, String.Format("LDS:UPDATE:PONG:{0},{1},{2}", from, Program.BotName, Program.Version)); } else if (bits[2] == "NOTIFY") { if (from_policebot || from.ToLower() == "divinityarcane") { if (bits[3].Contains(",")) { String[] pars = bits[3].Split(new char[] { ',' }); if (pars.Length == 3 && pars[0].ToLower() == username.ToLower()) { int secs = 0; bool ok = int.TryParse(pars[2], out secs); if (ok) { ConIO.Notice(String.Format("A new version of lulzBot is available: version {0} (Released {1} ago)", pars[1], Tools.FormatTime((ulong)(Tools.Timestamp() - secs)))); //ConIO.Notice(String.Format("To update, use the update command.")); } } } } } } else if (bits.Length >= 3 && bits[1] == "BOTCHECK") { if (bits[2] == "ALL") { if (from_policebot || from.ToLower() == "divinityarcane") { // from, owner, botname, botversion, uptime, disconnects, bytes_sent, bytes_received bot.NPSay(ns, String.Format("LDS:BOTCHECK:RESPONSE:{0},{1},{2},{3},{4},{5},{6},{7}", from, owner, Program.BotName, Program.Version, bot.uptime, Program.Disconnects, Program.bytes_sent, Program.bytes_received)); } } else if (bits.Length >= 4 && bits[2] == "DIRECT" && bits[3].ToLower() == username.ToLower()) { // from, owner, botname, botversion, uptime, disconnects, bytes_sent, bytes_received bot.NPSay(ns, String.Format("LDS:BOTCHECK:RESPONSE:{0},{1},{2},{3},{4},{5},{6},{7}", from, owner, Program.BotName, Program.Version, bot.uptime, Program.Disconnects, Program.bytes_sent, Program.bytes_received)); } } } }