예제 #1
0
        public static void cmd_part(Bot bot, String ns, String[] args, String msg, String from, dAmnPacket packet)
        {
            var c = ns;

            if (args.Length != 2)
            {
                // Ignore this for now.
                //bot.Say(ns, String.Format("<b>&raquo; Usage:</b> {0}part #channel", bot.Config.Trigger));
            }
            else
            {
                if (!args[1].StartsWith("#"))
                {
                    bot.Say(ns, "<b>&raquo; Invalid channel!</b> Channels should start with a #");
                    return;
                }

                c = args[1];
            }

            lock (CommandChannels["part"])
            {
                CommandChannels["part"].Add(ns);
            }

            bot.Part(c);
        }
예제 #2
0
        public static void cmd_cycle(Bot bot, String ns, String[] args, String msg, String from, dAmnPacket packet)
        {
            var chan = "";

            if (args.Length > 1 && args[1].StartsWith("#"))
            {
                chan = args[1];
            }
            else
            {
                chan = ns;
            }

            String cpns = Tools.FormatNamespace(chan, Types.NamespaceFormat.Packet).ToLower();

            if (!Core.ChannelData.ContainsKey(cpns))
            {
                bot.Say(ns, "<b>&raquo; It doesn't look like I'm in that channel.</b>");
                return;
            }

            lock (CommandChannels["part"])
            {
                CommandChannels["part"].Add(ns);
            }

            lock (CommandChannels["join"])
            {
                CommandChannels["join"].Add(ns);
            }

            bot.Part(cpns);
            bot.Join(cpns);
        }
예제 #3
0
        /// <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>&raquo; 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>&raquo; 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("&", "&amp;"));
                                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>&raquo; 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>&raquo; 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>&raquo; 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>&raquo; 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>&raquo; 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));
                    }
                }
            }
        }