/// <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("&lt;", "<").Replace("&gt;", ">");
                                                     web = web.Replace("&quot;", "\"").Replace("&amp;", (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;
 }
Beispiel #3
0
 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);
             }
         });
     }
 }
Beispiel #5
0
        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);
                    }
                });
            }
        }
Beispiel #6
0
        /// <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, 2);
                                        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("&lt;", "<").Replace("&gt;", ">");
                                                        web             = web.Replace("&quot;", "\"").Replace("&amp;", (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());
                    }
                }
            }
        }