Skip to main content
Code Review

Return to Question

Notice removed Draw attention by RubberDuck
Bounty Ended with Heslacher's answer chosen by RubberDuck
added 185 characters in body
Source Link
  • (削除) The code is very unoptimised; rampant if-nesting, tons of methods, etc. Not very efficient or aesthetically pleasing. (削除ここまで) Solved this for a while!
  • The method of storing user objects is slow. Having to write the whole file over again with each change seems very inefficient, but I'm unsure of a superior method (This is a bit better since it now only commits one write operation per message).
  • The code is unmodular; making a change often requires a stop of the debugging process.
  • There is very little utility to the bot. Small list of commands, seems somewhat dry/worthless.

I'm certainly a fan of receiving direct feedback, but if you can also provide a resource where someone has created a very efficient/complex/powerful IRC bot I'd very much enjoy taking a look at the code. Also, suggestion of features would help quite a bit, as I'm very unimaginative myself.

  • (削除) The code is very unoptimised; rampant if-nesting, tons of methods, etc. Not very efficient or aesthetically pleasing. (削除ここまで) Solved this for a while!
  • The method of storing user objects is slow. Having to write the whole file over again with each change seems very inefficient, but I'm unsure of a superior method (This is a bit better since it now only commits one write operation per message).
  • The code is unmodular; making a change often requires a stop of the debugging process.

I'm certainly a fan of receiving direct feedback, but if you can also provide a resource where someone has created a very efficient/complex/powerful IRC bot I'd very much enjoy taking a look at the code.

  • (削除) The code is very unoptimised; rampant if-nesting, tons of methods, etc. Not very efficient or aesthetically pleasing. (削除ここまで) Solved this for a while!
  • The method of storing user objects is slow. Having to write the whole file over again with each change seems very inefficient, but I'm unsure of a superior method (This is a bit better since it now only commits one write operation per message).
  • The code is unmodular; making a change often requires a stop of the debugging process.
  • There is very little utility to the bot. Small list of commands, seems somewhat dry/worthless.

I'm certainly a fan of receiving direct feedback, but if you can also provide a resource where someone has created a very efficient/complex/powerful IRC bot I'd very much enjoy taking a look at the code. Also, suggestion of features would help quite a bit, as I'm very unimaginative myself.

Notice added Draw attention by RubberDuck
Bounty Started worth 200 reputation by RubberDuck
refractored code to be more efficient and far cleaner
Source Link

Interface IRCBot inherits from

using System;
namespace IRCBot {
 internal interface IModule
 {
 void OnChannelMessage(ChannelMessage e);
 }
 internal class ChannelMessage
 {
 public DateTime Time;
 public string
 Nickname,
 Realname,
 Hostname,
 Type,
 Recipient,
 Args;
 }
 internal class ChannelEvent
 {
 public string
 Event,
 Channel;
 public ChannelEvent()
 {
 
 }
 }
}
  • The code is very unoptimised; rampant if-nesting, tons of methods, etc. Not very efficient or aesthetically pleasing.(削除) The code is very unoptimised; rampant if-nesting, tons of methods, etc. Not very efficient or aesthetically pleasing. (削除ここまで) Solved this for a while!
  • The method of storing user objects is slow. Having to write the whole file over again with each change seems very inefficient, but I'm unsure of a superior method (This is a bit better since it now only commits one write operation per message).
  • The code is unmodular; making a change often requires a stop of the debugging process.
  • The code is very unoptimised; rampant if-nesting, tons of methods, etc. Not very efficient or aesthetically pleasing.
  • The method of storing user objects is slow. Having to write the whole file over again with each change seems very inefficient, but I'm unsure of a superior method
  • The code is unmodular; making a change often requires a stop of the debugging process

Interface IRCBot inherits from

using System;
namespace IRCBot {
 internal interface IModule
 {
 void OnChannelMessage(ChannelMessage e);
 }
 internal class ChannelMessage
 {
 public DateTime Time;
 public string
 Nickname,
 Realname,
 Hostname,
 Type,
 Recipient,
 Args;
 }
 internal class ChannelEvent
 {
 public string
 Event,
 Channel;
 public ChannelEvent()
 {
 
 }
 }
}
  • (削除) The code is very unoptimised; rampant if-nesting, tons of methods, etc. Not very efficient or aesthetically pleasing. (削除ここまで) Solved this for a while!
  • The method of storing user objects is slow. Having to write the whole file over again with each change seems very inefficient, but I'm unsure of a superior method (This is a bit better since it now only commits one write operation per message).
  • The code is unmodular; making a change often requires a stop of the debugging process.
refractored code to be more efficient and far cleaner
Source Link
internal class IRCBot : IDisposable, IModule {
 { private readonly Dictionary<string, List<string>> users = new Dictionary<string, List<string>>();
 private readonly Dictionary<string, int> userAttempts = new Dictionary<string, int>();
 private readonly Dictionary<string, string> commands = new Dictionary<string, string>
 {
 {"join", "(join <channel>) - joins specified channel."},
 {"part", "(part <channel> <message*>) - parts specified channel."},
 {"leave", "(part <channel> <message*>) - parts specified channel."},
 {"say", "(say <channel*> <message>) - sends privmsg to target channel."},
 {"chanlist/channels""chanlist", "Provides a list of channels joined."},
 {"channels", "Provides a list of channels joined."},
 {"userlist", "List all users currently in database and their access number."},
 {"define", "(define <word> <part of speech*>) - outputs a dictionary definition for the specified word."},
 {"lookup", "(lookup <target article>) - outputs the contents of a specified wikipedia article."},
 {"message", "(message <recipient> <mesaage>) - sends a message to specified user, to be sent when they login again."},
 {"seen", "(seen <target>) - Outputs the last DateTime of the target user being active."},
 {"about", "Print out the version and creator information of the bot."},
 {"shutdown", "Closes program."}
 };
 private Config _config;
 private TcpClient _connection;
 private StreamWriter _log;
 private NetworkStream _ns;
 private StreamReader _sr;
 private StreamWriter _sw;

 private readonly Dictionary<string, List<string>> users = new Dictionary<string, List<string>>();
 private readonly Dictionary<string, int> userAttempts = new Dictionary<string, int>(); 

 private readonly List<string> channels = new List<string>();
 private readonly List<string> nameDenyList = new List<string>()
 {
 "NickServ", "ChanServ",
 "vervet.foonetic.net",
 "Eve"
 };
 private List<User> userList;

 private string[] ex;
 private string user = string.Empty;
 private string realn = string.Empty;
 private readonly char[] sep = { ' ' };

 private string recipient;
 // set config 
 public IRCBot(Config config) {
 _config = config;
 }
 public void Dispose() {
 _sr?.Close();
 _sw?.Close();
 _ns?.Close();
 _log?.Close();
 _connection?.Close();
 }

 // command operations for main _switch()
 privatepublic void Join()
 {
 if (ex.Length >= 6)
  if (channels.Contains(ex[5]))
 SendMessageOnChannelEvent("I'm already in thatChannelEvent channel."e);
  else
 {
 SendMessage("Joining " + ex[5] + ".");
 SendData("JOIN", ex[5]);
 channels.Add(ex[5]);
 }
 throw elsenew SendMessageNotImplementedException("Too few parameters.");
 }
  private void Part()
 {
 if (ex.Length >= 6)
 if (ex[5].StartsWith("#"))
 if (channels.Contains(ex[5]))
 public void OnChannelMessage(ChannelMessage c) {
 recipient = c.Recipient;
 
 if (QueryName(c.Realname) == null
 && !nameDenyList.Contains(c.Realname)) {
 userList.Add(new User {
 Name = c.Realname,
 Access = 2,
 Seen = DateTime.UtcNow
 });
 } else if (QueryName(c.Realname) != null)
 userList.First(e => e.Name == c.Realname).Seen = DateTime.UtcNow;
 if (!userAttempts.ContainsKey(c.Realname))
 userAttempts.Add(c.Realname, 0);
 if (!users.ContainsKey(c.Recipient)
 && c.Recipient.StartsWith("#"))
 users.Add(c.Recipient, new List<String>());
 File.WriteAllText("users.json", JsonConvert.SerializeObject(userList, Formatting.Indented));
 string[] arg = null;
 if (c.Args != null) {
 arg = c.Args.ToLower().Split(new char[] { ' ' }, 4);
 }
 switch (c.Type) {
 case "PRIVMSG":
 if (arg == null) return;
 if (QueryName(c.Realname) == null) return;
 var access = userList.First(e => e.Name == c.Realname).Access;
 string msg,
 chan;
 if (arg[0] != "eve"
 && arg[0] != "eve,")
 return;
 if (UserTimeout(c.Realname)) return;
 if (arg[1] != null)
 switch (arg[1]) {
 case "join":
 if (access > 1) {
 SendMessage("Insufficient permissions.");
 return;
 }
 if (String.IsNullOrEmpty(arg[2])) {
 SendMessage("Insufficient parameters. Type 'eve help join' to view correct usage.");
 }
 if (!arg[2].StartsWith("#")) {
 SendMessage("Channel argument must be a proper channel name (i.e. starts with '#').");
 return;
 }
 if (channels.Contains(arg[2]))
 {
 SendMessage("I'm already in that channel.");
 return;
 }
 Join(arg[2]);
 break;
 case "part":
 case "leave":
 if (access > 1) {
 SendMessage("Insufficient permissions.");
 return;
 }
 if (String.IsNullOrEmpty(arg[2])) {
 SendMessage("Insufficient parameters. Type 'eve help part' to view correct usage.");
 return;
 }
 if (!arg[2].StartsWith("#")) {
 SendMessage("Channel argument must be a proper channel name (i.e. starts with '#').");
 return;
 }
 if (!channels.Contains(arg[2])) {
 SendMessage("I'm not in that channel.");
 return;
 }
 Part(arg[2], arg[3]);
 break;
 case "say":
 if (arg.Length < 3
 || (arg[2].StartsWith("#")
 && arg.Length < 4)) {
 SendMessage("Insufficient parameters. Type 'eve help say' to view correct usage.");
 return;
 }
 msg = (!arg[2].StartsWith("#") && arg.Length > 4)
 ? arg[2] + " " + arg[3]
 : arg[2];
 chan = (arg[2].StartsWith("#")) ? arg[2] : null;
 Say(chan, msg);
 break;
 case "chanlist":
 case "channels":
 SendMessage(string.Join(" ", channels.ToArray()));
 break;
 case "define":
 if (arg.Length < 3) {
 SendMessage("Insufficient parameters. Type 'eve help define' to view correct usage.");
 return;
 }
 var pos = (arg.Length < 4) ? null : arg[3];
 Define(arg[2], pos);
 break;
 case "lookup":
 if (arg.Length < 3) {
 SendMessage("Insufficient parameters. Type 'eve help lookup' to view correct usage.");
 return;
 }
 var query = (arg.Length < 4) ? arg[2] : arg[2] + "%20" + arg[3];
 query = query.Replace(" ", "%20");
 Lookup(query, c.Nickname);
 break;
 case "message":
 if (arg.Length < 3
 || arg.Length < 4) {
 SendMessage("Insufficient parameters. Type 'eve help message' to view correct usage.");
 return;
 }
 if (QueryName(arg[2]) == null) {
 SendMessage("User does not exist in database.");
 return;
 }
 Message(c.Realname, arg[2], Regex.Escape(arg[3]));
 break;
 case "help":
 if (arg.Length > 3
 && !commands.ContainsKey(arg[2])) {
 SendMessage("Command does not exist.");
 return;
 }
 var cmd = (arg.Length < 3) ? null : arg[2];
 Help(c.Nickname, cmd);
 break;
 case "userlist":
 Userlist();
 break;
 case "seen":
 if (arg.Length < 3) {
 SendMessage("Insufficient parameters. Type 'eve help message' to view correct usage.");
 return;
 }
 if (QueryName(arg[2]) == null) {
 SendMessage("User does not exist in database.");
 return;
 }
 Seen(arg[2]);
 break;
 case "about":
 SendMessage("Evealyn Bot is a sophisticated and damn fine IRC bot created by SemiViral. Version 1.0");
 break;
 case "shutdown":
 if (access > 1) {
 SendMessage("Goodybe.");
 Eve.Run = false;
 } else SendMessage("Insufficient permissions.");
 break;
 default:
 SendMessage("Invalid command.");
 break;
 } else
 SendMessage("Please provide a command. Type 'eve help' to obtain my command list.");
 break;
 case "JOIN":
 Console.WriteLine(c.Realname);
 if (c.Realname == "Eve") return;
 if (QueryName(c.Realname) != null) {
 foreach (var m in userList.First(e => e.Name == c.Realname).Messages)
 SendData("PRIVMSG", c.Nickname + " (" + m.Date + ") " + m.Sender + ": " + Regex.Unescape(m.Contents));
 userList.First(e => e.Name == c.Realname).Messages = null;
 }
 users[c.Recipient].Add(c.Realname);
 break;
 case "PART":
 users[c.Recipient].Remove(c.Realname);
 break;
 case "MODE":
 if (!_config.Joined)
 {
 if (ex_config.Length >= 7)
 {
 SendMessage("Leaving channel " + ex[5] + " for reason: "Joined += ex[6]);true;
 SendData("PART""PRIVMSG", ex[5] + " ""NICKSERV +IDENTIFY ex[6]evepass");
 }
 foreach (var s in else_config.Channels)
 {
 SendMessage("Leaving channel " + ex[5] + ".");
 SendDataJoin("PART", ex[5]s);
 }

 channels.Remove(ex[5]);
 }
 elsebreak;
 SendMessage("I'm not in that channel case "353":
 var key = Regex.Matches(c.Args, @"(#\w+)");
 else
 var list = key.Cast<Match>().Select(match => match.Value).ToList();
 {
 SendMessage("Leaving channel " + ex[2] + " foreach (var s in c."Args.Split(':');[1].Split(' '))
 SendData("PART", ex[2] users[list[0]].Add(s);
 } break;
 else}
 SendMessage File.WriteAllText("Too"users.json", fewJsonConvert.SerializeObject(userList, parametersFormatting."Indented));
 }

 // command operations for main switch()
  private void SayJoin(string chan)
 {
 if (ex.Length >= 6)
 if (ex[5].StartsWithSendMessage("#"))
 "Joining " SendData("PRIVMSG",+ ex[5]chan + "." + ex[6]);
 else
  SendMessageSendData(ex[5]"JOIN", chan);
 else SendMessage("Please provide a message to sendchannels."Add(chan);
 }
 private void DefinePart()
 string chan, string msg) {
 if (ex.Lengthmsg >== 5null) {
 {
 SendMessage("Leaving channel " + chan + ".");
 var url = ex.Length >SendData("PART", 6chan);
 } else {
 ? "https://api.pearson.com:443/v2/dictionaries/lasde/entries?headword=" + ex[5] + "&part_of_speech=" + ex[6] +
 SendMessage("Leaving channel " + chan + " for reason: " + msg);
 "&limit=1"
 SendData("PART", chan + " " + msg);
 : "https://api.pearson.com:443/v2/dictionaries/lasde/entries?headword=" + ex[5] + "&limit=1";}
 var entry = JObjectchannels.Parse(HttpGETRemove(url)chan);
 users.Remove(chan);
 var _out = new Dictionary<string, string>();}
 private ifvoid (Say(int)string entry.SelectToken("count")chan, >string 0msg) {
 _out.Add("word",if (string) entryString.SelectTokenIsNullOrEmpty("results[0].headword"chan));
 _out.Add("pos", (string) entry.SelectTokenSendMessage("results[0].part_of_speech")msg);
 else
 _out.Add("def", (string) entry.SelectToken("results[0].senses[0].definition[0]"));
 SendData("PRIVMSG", chan + " " + msg);
 _out.Add("ex", (string) entry.SelectToken("results[0].senses[0].examples[0].text"));}
 private void Define(string word, string pos) {
  var sOuturl = string(String.IsNullOrEmpty(_out["ex"]pos))
 ? _out["word"] + " [" + _out["pos"]"https://api.pearson.com:443/v2/dictionaries/lasde/entries?headword=" + "] — "word + _out["def"]"&limit=1"
 : "https://api.pearson.com:443/v2/dictionaries/lasde/entries?headword=" + word + "&part_of_speech=" :+ _out["word"]pos + " [" + _out["pos"] + "]  " + _out["def"] + " (ex. " + _out["ex"] + ")";"&limit=1";
 var entry = JObject.Parse(HttpGET(url));
 SendMessage var _out = new Dictionary<string, string>(sOut);
 if ((int)entry.SelectToken("count") < 1) }{
 else SendMessage("No"Query resultsreturned foundno results.");
 return;
 }
 else SendMessage("Too few parameters.");
 }

 private void Lookup()
  _out.Add("word", {(string)entry.SelectToken("results[0].headword"));
 if_out.Add("pos", (exstring)entry.Length >= 6SelectToken("results[0].part_of_speech")
 {);
 ex[5] = ex_out.Length >= 7 ? ex[5] + " " + ex[6] :Add("def", ex[5];(string)entry.SelectToken("results[0].senses[0].definition[0]"));
 ex[5] = ex[5]_out.ReplaceAdd(" ""ex", "%20"(string)entry.SelectToken("results[0].senses[0].examples[0].text"));
 var responsesOut = HttpGET("https://en.wikipedia.org/w/apiString.php?format=json&action=query&prop=extracts&exintro=&explaintext=&titles=" +IsNullOrEmpty(_out["ex"]))
 ? _out["word"] + " [" + _out["pos"] + "]  " + ex[5]);_out["def"]
 var pages = JObject.Parse(response)["query"]["pages"].Values().First();
 : _out["word"] + " [" + _out["pos"] + "]  " + var_out["def"] title+ =" (string) pages["title"];
 var contentex. =" Regex.Replace((string)+ pages["extract"],_out["ex"] @"\r\n?|\n",+ """);";
 var _out = StrSplitSendMessage(content, 510sOut);
 Console.WriteLine(_out);}
 private void Lookup(string varquery, _intstring =nick) 0;{
 foreach (var s inresponse _out)=
 {HttpGET("https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro=&explaintext=&titles=" +
 if (_int == 0 query);
 var pages = {JObject.Parse(response)["query"]["pages"].Values().First();
 var title = (string)pages["title"];
 SendData("PRIVMSG", user + "var "content += title + " — " + sRegex.Replace((string);
 pages["extract"], @"\r\n?|\n", _int++;"");
 var _out = StrSplit(content, }450);
 foreach (var s in else_out)
 SendData("PRIVMSG", usernick + " " + s);
 }
 }
 else
 {
 SendMessage("Too few parameters.");
 }
 }
 private void Help(string nick, string cmd) {
 if (String.IsNullOrEmpty(cmd)) {
 SendData("PRIVMSG", usernick + " Each command must be proceeded with \"eve\" or \"eve,\" to be properly queried.");
 foreach (var s in commands)
 SendData("PRIVMSG", usernick + " " + s.Key + ": " + s.Value);
 SendData("PRIVMSG", usernick + " (* - optional parameter)");
 } else {
 SendData("PRIVMSG", nick + " " + cmd + ": " + commands[cmd]);
 }
 }
 private void Userlist() {
 StringBuildervar _out = new StringBuilder();
 foreach (var s in userList) {
 _out.Append(s.Name + "(" + s.Access + ") ");
 }
 SendMessage(_out.ToString());
 _out = null;
 }

 private void _Message()
 {
 if (ex.Length == 7)
 if (userList.FirstOrDefault(e => e.Name == ex[5]) != null)
 {
 var m = new Message
 {
 Sender = realn,
 Contents = ex[6],
 Date = DateTime.UtcNow
 };

 private void Message(string sender, string who, ifstring (userList.First(emsg) =>{
 e.Name == realn).Messages == null)
 var m = new Message {
 userList.First(e => e.Name == ex[5]).MessagesSender = new List<Message> {m};sender,
 Contents = msg,
 else
 Date = DateTime.UtcNow
 userList.First(e => e.Name == ex[5]).Messages.Add(m)};
 if (QueryName(who).Messages == null)
 SendMessage userList.First("Messagee recorded=> ande.Name will== bewho).Messages sent= tonew "List<Message> +{ ex[5]m };
 else
 userList.First(e => e.Name == who).Messages.Add(m);
 File.WriteAllText("users.json", JsonConvert.SerializeObject(userList, Formatting.Indented));
 } else SendMessage("User does not exist in database.");
 "Message recorded and will be sent elseto SendMessage("Too" few+ paramaters"who);
 }
 private void Seen()
 {
 if (ex.Length >= 6)
 if (userList.FirstOrDefault(e => e.Name == realn) !=string nullwho) {
 var u = userList.FirstOrDefault(e => e.Name == realnwho);
 SendMessage(u.Name + " was last seen on: " + u.Seen + " (UTC)");
 } else SendMessage("User not in directory.");
 else SendMessage("Not enough parameters");
 }
 // split input string by maxlen and return array
 public static IEnumerable<string> StrSplit(string str, int maxLength) {
 for (var i = 0; i < str.Length; i += maxLength)
 yield return str.Substring(i, Math.Min(maxLength, str.Length - i));
 }
 public User QueryName(string name) {
 return userList.FirstOrDefault(e => e.Name == name);
 }
 // check whether or not respond to user by
 // identifying the amount of commands they've
 // issued in the past minute
 public bool UserTimeout()
 string who) {
 var doTimeout = false;
 if (userAttempts[realn]userAttempts[who] == 3)
 if (userList.FirstQueryName(e => e.Name == realnwho).Seen.AddMinutes(1) < DateTime.UtcNow)
 userAttempts[realn]userAttempts[who] = 0;
 else doTimeout = true;
 else
 if (userList.FirstQueryName(e => e.Name == realnwho).Access > 21)
 userAttempts[realn]userAttempts[who] += 1;
 return doTimeout;
 }
 // initialise connection to server
 public void Connect() {
 try {
 _connection = new TcpClient(_config.Server, _config.Port);
 } catch {
 Console.WriteLine("Connection failed.");
 }
 try {
 _ns = _connection.GetStream();
 _sr = new StreamReader(_ns);
 _sw = new StreamWriter(_ns);
 _log = new StreamWriter("_logs.txt", true);
  { _log.AutoFlush = true;
  true };

 Console.WriteLine(_config.Nick + " " + _config.Name);
 SendData("USER", _config.Nick + " 0 * " + _config.Name);
 SendData("NICK", _config.Nick);
 } catch {
 Console.WriteLine("Communication error.");
 throw;
 }
 userList = JsonConvert.DeserializeObject<List<User>>(File.ReadAllText("users.json"));
 if (userList == null) {
 Console.WriteLine("Failed to initialise JSON object from file");
 Console.ReadLine();
 Environment.Exit(0);return;
 }
 }
 // send raw data to server
 public void SendData(string cmd, string param) {
 if (param == null) {
 _sw.WriteLine(cmd);
 _sw.Flush();
 Console.WriteLine(cmd);
 } else {
 _sw.WriteLine(cmd + " " + param);
 _sw.Flush();
 Console.WriteLine(cmd + " " + param);
 }
 }
 public void SendMessage(string message) {
 SendData("PRIVMSG", ex[2]recipient + " " + message);
 }
 // send a GET request to given URL
 public string HttpGET(string url) {
 var request = (HttpWebRequest)WebRequest.Create(url);
 request.Method = "GET";
 string response;
 using (var httpr = (HttpWebResponse)request.GetResponse()) {
 response = new StreamReader(httpr.GetResponseStream()).ReadToEnd();
 }
 return response;
 }

 public void Runtime()
 {
 var shouldRun = true;
 while (shouldRun)
 {
 var data = _sr.ReadLine();
 ex = data.Split(sep, 7);
 user = ex[0].Split('!')[0].Substring(1);
 if (Regex.IsMatch(ex[0], @"(:.+!.+@*)"))
 {
 realn = ex[0].Split('!', '@')[1];
 if (realn.StartsWith("~"))
 realn = realn.Substring(1);
 }
 Console.WriteLine(data);
 _log.WriteLine(data);
 if (!_config.Joined)
 {
 if (ex[1] == "MODE") {
 SendData("PRIVMSG", "NICKSERV IDENTIFY ******");

 public foreachvoid Runtime(var s in _config.Channels) {
 var data = SendData_sr.ReadLine("JOIN", s);
 var _config.JoinedmTime = true;DateTime.UtcNow;
 var mRegex = new channels.AddRegex(s@"^:(?<Sender>[^\s]+);
 }
 }
 }
 
 if \s(ex[1] == "JOIN"?<Type>[^\s]+)
 {
 if \s(userList.FirstOrDefault?<Recipient>[^\s]+)\s?:?(e => e?<Args>.Name == realn*) !=", nullRegexOptions.Compiled);
 var sRegex = new Regex(@"^(?<Nickname>[^\s]+)!(?<Realname>[^\s]+)@(?<Hostname>[^\s]+)", {RegexOptions.Compiled);
 var aRegex = foreachnew Regex(var m in userList.First@"^:(e => e?<Arg1>[^\s]+)\s(?<Arg2>[^\s]+)\s(?<Arg3>[^\s]+)\s?:?(?<Arg4>.Name == realn*)", RegexOptions.MessagesCompiled);
 var pRegex = new SendDataRegex("PRIVMSG", user + " " + m.Sender + "@"^PING :(" + m?<Message>.Date + ")" +, mRegexOptions.ContentsNone);
 userListConsole.FirstWriteLine(e => e.Name == realndata).Messages = null;;
 File.WriteAllText("users.json", JsonConvert_log.SerializeObjectWriteLine(userList, Formatting.Indented)data);
 }
 }
 if (userListmRegex.FirstOrDefaultIsMatch(e => e.Name == realndata) == null
 && realn != "NickServ"
 && realn != "ChanServ"
 && realn != "Evealyn"
 && realn != "") {
 userList.Add(new User
 {
 Name = realn,
 Access = 2,
 var SeenmVal = DateTime.UtcNow
  });
 File.WriteAllText("users.json", JsonConvertmRegex.SerializeObjectMatch(userList, Formatting.Indented)data);
 }
 else
 {
  if (userList.FirstOrDefault(e => e.Name ==var realn)mSender != null)
 {
  userList.First(e => e.Name == realn)mVal.Seen = DateTimeGroups["Sender"].UtcNow;Value;
 var sMatch File.WriteAllText("users.json",= JsonConvertsRegex.SerializeObjectMatch(userList, Formatting.Indented)mSender);
 }
 }
 ifvar c = new ChannelMessage(ex[0]) =={
 "PING" Nickname = mSender,
 Realname = mSender,
 Hostname = mSender,
 Type = mVal.Groups["Type"].Value,
 Recipient = (mVal.Groups["Recipient"].Value.StartsWith(":"))
 SendData ? mVal.Groups["Recipient"].Value.Substring("PONG"1)
 : mVal.Groups["Recipient"].Value, ex[1]) Args = mVal.Groups["Args"].Value,
 Time = DateTime.UtcNow
 };
 if (ex.Length > 4)
 if (ex[3].ToLower() == ":eve"
 || ex[3]sMatch.ToLower() == ":eve,"Success)
 {
 if (!userAttempts.ContainsKey(realn))
 userAttempts.Add(realn, 0);
 if (!UserTimeout())
 {
 var commandrealname = ex[4];
 switch (command.ToLower())
 {
 case "join":
  if (userList.First(e => esMatch.Name == realn)Groups["Realname"].Access < 2)
 Join();
 break;
 case "part":
 case "leave":Value;
 if (userListc.First(eNickname =>= esMatch.Name == realn)Groups["Nickname"].Access < 2)
 Part();
 break;
 case "say":
 Say();
 break;
 case "chanlist":
 case "channels":Value;
 SendMessage(string.Join(", ", channelsc.ToArray()));
 break;
 case "define":
 Define();
 break;
 case "lookup":
 Lookup();
 break;
 case "message":
 _Message();
 break;
 case "help":
 Realname = Help();
 break;
 case "userlist":
 Userlistrealname.StartsWith("~");
 break;
 case "seen":
 Seen();
 break;
 case "about":
 SendMessage("Evealyn Bot is a sophisticated and damn fine IRC bot created by? SemiViralrealname. Version Substring(1.0");
  break;
 case "shutdown": if (userList.First(e => e.Name == realn).Access < 2)
 {realname;
 SendMessage("Goodybec.");
 shouldRunHostname = false;
 }
 break;
 default:
  SendMessage("Please provide a valid commandsMatch.");
 break;
 }
 }Groups["Hostname"].Value;
 }
 else if (ex[3] == "=")
 {
 // Create a List of users upon channel connections
 var u = new List<string>()
 {
 ex[5].Substring(1)
 };

 if OnChannelMessage(ex.Length > 6c);
 } else ex[6].Split('if ').ToList().ForEach(x => upRegex.AddIsMatch(xdata));
 // Add the list of channel users to
 // specified channel index{
 users.AddSendData(ex[4]"PONG", upRegex.Match(data).Value);
 }
 }
 }
 }
}
internal class Eve {
 {
public static bool Run = true;
  private static void Main(string[] args) {
 var conf = new Config() {
 Name = "Evealyn",
 Nick = "Eve",
 Port = 6667,
 Server = "irc.foonetic.net",
 Channels = new[] { "#testgrounds2", "#ministryofsillywalks" },
 };
Joined = false
 };
 using (var bot = new IRCBot.IRCBot(conf)) {
 {bot.Connect();
 conf.Joinedwhile =(Run) false;{
 bot.ConnectRuntime();
 bot.Runtime();}
 }
 Console.WriteLine("Bot has shutdown.");
 Console.ReadLine();
 }
 }
} 

The currently posted code is a second revision; I refactored it to use Regex and some far more efficient processing techniques.

internal class IRCBot : IDisposable
 {
 
 private readonly Dictionary<string, string> commands = new Dictionary<string, string>
 {
 {"join", "(join <channel>) - joins specified channel."},
 {"part", "(part <channel> <message*>) - parts specified channel."},
 {"say", "(say <channel*> <message>) - sends privmsg to target channel."},
 {"chanlist/channels", "Provides a list of channels joined."},
 {"channels", "Provides a list of channels joined."},
 {"userlist", "List all users currently in database and their access number."},
 {"define", "(define <word> <part of speech*>) - outputs a dictionary definition for the specified word."},
 {"lookup", "(lookup <target article>) - outputs the contents of a specified wikipedia article."},
 {"message", "(message <recipient> <mesaage>) - sends a message to specified user, to be sent when they login again."},
 {"seen", "(seen <target>) - Outputs the last DateTime of the target user being active."},
 {"about", "Print out the version and creator information of the bot."},
 {"shutdown", "Closes program."}
 };
 private Config _config;
 private TcpClient _connection;
 private StreamWriter _log;
 private NetworkStream _ns;
 private StreamReader _sr;
 private StreamWriter _sw;

 private readonly Dictionary<string, List<string>> users = new Dictionary<string, List<string>>();
 private readonly Dictionary<string, int> userAttempts = new Dictionary<string, int>(); 

 private readonly List<string> channels = new List<string>();
 private List<User> userList;

 private string[] ex;
 private string user = string.Empty;
 private string realn = string.Empty;
 private readonly char[] sep = { ' ' };

 // set config 
 public IRCBot(Config config) {
 _config = config;
 }
 public void Dispose() {
 _sr?.Close();
 _sw?.Close();
 _ns?.Close();
 _log?.Close();
 _connection?.Close();
 }

 // command operations for main _switch()
 private void Join()
 {
 if (ex.Length >= 6)
  if (channels.Contains(ex[5]))
 SendMessage("I'm already in that channel.");
  else
 {
 SendMessage("Joining " + ex[5] + ".");
 SendData("JOIN", ex[5]);
 channels.Add(ex[5]);
 }
  else SendMessage("Too few parameters.");
 }
  private void Part()
 {
 if (ex.Length >= 6)
 if (ex[5].StartsWith("#"))
 if (channels.Contains(ex[5]))
 {
 if (ex.Length >= 7)
 {
 SendMessage("Leaving channel " + ex[5] + " for reason: " + ex[6]);
 SendData("PART", ex[5] + " " + ex[6]);
 }
 else
 {
 SendMessage("Leaving channel " + ex[5] + ".");
 SendData("PART", ex[5]);
 }

 channels.Remove(ex[5]);
 }
 else SendMessage("I'm not in that channel.");
 else
 {
 SendMessage("Leaving channel " + ex[2] + ".");
 SendData("PART", ex[2]);
 }
 else SendMessage("Too few parameters.");
 }
 private void Say()
 {
 if (ex.Length >= 6)
 if (ex[5].StartsWith("#"))
  SendData("PRIVMSG", ex[5] + "" + ex[6]);
 else
  SendMessage(ex[5]);
 else SendMessage("Please provide a message to send.");
 }
 private void Define()
  {
 if (ex.Length > 5)
 {
 var url = ex.Length > 6
 ? "https://api.pearson.com:443/v2/dictionaries/lasde/entries?headword=" + ex[5] + "&part_of_speech=" + ex[6] +
 "&limit=1"
 : "https://api.pearson.com:443/v2/dictionaries/lasde/entries?headword=" + ex[5] + "&limit=1";
 var entry = JObject.Parse(HttpGET(url));
 var _out = new Dictionary<string, string>();
 if ((int) entry.SelectToken("count") > 0) {
 _out.Add("word", (string) entry.SelectToken("results[0].headword"));
 _out.Add("pos", (string) entry.SelectToken("results[0].part_of_speech"));
 _out.Add("def", (string) entry.SelectToken("results[0].senses[0].definition[0]"));
 _out.Add("ex", (string) entry.SelectToken("results[0].senses[0].examples[0].text"));
 var sOut = string.IsNullOrEmpty(_out["ex"])
 ? _out["word"] + " [" + _out["pos"] + "] — " + _out["def"]
 : _out["word"] + " [" + _out["pos"] + "]  " + _out["def"] + " (ex. " + _out["ex"] + ")";
 SendMessage(sOut);
 }
 else SendMessage("No results found.");
 }
 else SendMessage("Too few parameters.");
 }

 private void Lookup()
  {
 if (ex.Length >= 6)
 {
 ex[5] = ex.Length >= 7 ? ex[5] + " " + ex[6] : ex[5];
 ex[5] = ex[5].Replace(" ", "%20");
 var response = HttpGET("https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro=&explaintext=&titles=" +
 ex[5]);
 var pages = JObject.Parse(response)["query"]["pages"].Values().First();
 var title = (string) pages["title"];
 var content = Regex.Replace((string) pages["extract"], @"\r\n?|\n", "");
 var _out = StrSplit(content, 510);
 Console.WriteLine(_out);
 var _int = 0;
 foreach (var s in _out)
 {
 if (_int == 0)
 {
 SendData("PRIVMSG", user + " " + title + " — " + s);
  _int++;
 }
 else
 SendData("PRIVMSG", user + " " + s);
 }
 }
 else
 {
 SendMessage("Too few parameters.");
 }
 }
 private void Help()
 {
 SendData("PRIVMSG", user + " Each command must be proceeded with \"eve\" or \"eve,\" to be properly queried.");
 foreach (var s in commands)
 SendData("PRIVMSG", user + " " + s.Key + ": " + s.Value);
 SendData("PRIVMSG", user + " (* - optional parameter)");
 }
 private void Userlist() {
 StringBuilder _out = new StringBuilder();
 foreach (var s in userList) {
 _out.Append(s.Name + "(" + s.Access + ") ");
 }
 SendMessage(_out.ToString());
 _out = null;
 }

 private void _Message()
 {
 if (ex.Length == 7)
 if (userList.FirstOrDefault(e => e.Name == ex[5]) != null)
 {
 var m = new Message
 {
 Sender = realn,
 Contents = ex[6],
 Date = DateTime.UtcNow
 };

 if (userList.First(e => e.Name == realn).Messages == null)
 userList.First(e => e.Name == ex[5]).Messages = new List<Message> {m};
 else
 userList.First(e => e.Name == ex[5]).Messages.Add(m);
 SendMessage("Message recorded and will be sent to " + ex[5]);
 File.WriteAllText("users.json", JsonConvert.SerializeObject(userList, Formatting.Indented));
 } else SendMessage("User does not exist in database.");
  else SendMessage("Too few paramaters");
 }
 private void Seen()
 {
 if (ex.Length >= 6)
 if (userList.FirstOrDefault(e => e.Name == realn) != null) {
 var u = userList.FirstOrDefault(e => e.Name == realn);
 SendMessage(u.Name + " was last seen on: " + u.Seen + " (UTC)");
 } else SendMessage("User not in directory.");
 else SendMessage("Not enough parameters");
 }
 // split input string by maxlen and return array
 public static IEnumerable<string> StrSplit(string str, int maxLength) {
 for (var i = 0; i < str.Length; i += maxLength)
 yield return str.Substring(i, Math.Min(maxLength, str.Length - i));
 }
 // check whether or not respond to user by
 // identifying the amount of commands they've
 // issued in the past minute
 public bool UserTimeout()
  {
 var doTimeout = false;
 if (userAttempts[realn] == 3)
 if (userList.First(e => e.Name == realn).Seen.AddMinutes(1) < DateTime.UtcNow)
 userAttempts[realn] = 0;
 else doTimeout = true;
 else
 if (userList.First(e => e.Name == realn).Access > 2)
 userAttempts[realn] += 1;
 return doTimeout;
 }
 // initialise connection to server
 public void Connect() {
 try {
 _connection = new TcpClient(_config.Server, _config.Port);
 } catch {
 Console.WriteLine("Connection failed.");
 }
 try {
 _ns = _connection.GetStream();
 _sr = new StreamReader(_ns);
 _sw = new StreamWriter(_ns);
 _log = new StreamWriter("_logs.txt", true);
  _log.AutoFlush = true;
  
 Console.WriteLine(_config.Nick + " " + _config.Name);
 SendData("USER", _config.Nick + " 0 * " + _config.Name);
 SendData("NICK", _config.Nick);
 } catch {
 Console.WriteLine("Communication error.");
 throw;
 }
 userList = JsonConvert.DeserializeObject<List<User>>(File.ReadAllText("users.json"));
 if (userList == null) {
 Console.WriteLine("Failed to initialise JSON object from file");
 Console.ReadLine();
 Environment.Exit(0);
 }
 }
 // send raw data to server
 public void SendData(string cmd, string param) {
 if (param == null) {
 _sw.WriteLine(cmd);
 _sw.Flush();
 Console.WriteLine(cmd);
 } else {
 _sw.WriteLine(cmd + " " + param);
 _sw.Flush();
 Console.WriteLine(cmd + " " + param);
 }
 }
 public void SendMessage(string message) {
 SendData("PRIVMSG", ex[2] + " " + message);
 }
 // send a GET request to given URL
 public string HttpGET(string url) {
 var request = (HttpWebRequest)WebRequest.Create(url);
 request.Method = "GET";
 string response;
 using (var httpr = (HttpWebResponse)request.GetResponse()) {
 response = new StreamReader(httpr.GetResponseStream()).ReadToEnd();
 }
 return response;
 }

 public void Runtime()
 {
 var shouldRun = true;
 while (shouldRun)
 {
 var data = _sr.ReadLine();
 ex = data.Split(sep, 7);
 user = ex[0].Split('!')[0].Substring(1);
 if (Regex.IsMatch(ex[0], @"(:.+!.+@*)"))
 {
 realn = ex[0].Split('!', '@')[1];
 if (realn.StartsWith("~"))
 realn = realn.Substring(1);
 }
 Console.WriteLine(data);
 _log.WriteLine(data);
 if (!_config.Joined)
 {
 if (ex[1] == "MODE") {
 SendData("PRIVMSG", "NICKSERV IDENTIFY ******");

 foreach (var s in _config.Channels) {
 SendData("JOIN", s);
 _config.Joined = true;
 channels.Add(s);
 }
 }
 }
 
 if (ex[1] == "JOIN")
 {
 if (userList.FirstOrDefault(e => e.Name == realn) != null)
 {
 foreach (var m in userList.First(e => e.Name == realn).Messages)
 SendData("PRIVMSG", user + " " + m.Sender + " (" + m.Date + ")" + m.Contents);
 userList.First(e => e.Name == realn).Messages = null;
 File.WriteAllText("users.json", JsonConvert.SerializeObject(userList, Formatting.Indented));
 }
 }
 if (userList.FirstOrDefault(e => e.Name == realn) == null
 && realn != "NickServ"
 && realn != "ChanServ"
 && realn != "Evealyn"
 && realn != "") {
 userList.Add(new User
 {
 Name = realn,
 Access = 2,
  Seen = DateTime.UtcNow
  });
 File.WriteAllText("users.json", JsonConvert.SerializeObject(userList, Formatting.Indented));
 }
 else
 {
  if (userList.FirstOrDefault(e => e.Name == realn) != null)
 {
  userList.First(e => e.Name == realn).Seen = DateTime.UtcNow;
 File.WriteAllText("users.json", JsonConvert.SerializeObject(userList, Formatting.Indented));
 }
 }
 if (ex[0] == "PING")
 SendData("PONG", ex[1]);
 if (ex.Length > 4)
 if (ex[3].ToLower() == ":eve"
 || ex[3].ToLower() == ":eve,")
 {
 if (!userAttempts.ContainsKey(realn))
 userAttempts.Add(realn, 0);
 if (!UserTimeout())
 {
 var command = ex[4];
 switch (command.ToLower())
 {
 case "join":
  if (userList.First(e => e.Name == realn).Access < 2)
 Join();
 break;
 case "part":
 case "leave":
 if (userList.First(e => e.Name == realn).Access < 2)
 Part();
 break;
 case "say":
 Say();
 break;
 case "chanlist":
 case "channels":
 SendMessage(string.Join(", ", channels.ToArray()));
 break;
 case "define":
 Define();
 break;
 case "lookup":
 Lookup();
 break;
 case "message":
 _Message();
 break;
 case "help":
  Help();
 break;
 case "userlist":
 Userlist();
 break;
 case "seen":
 Seen();
 break;
 case "about":
 SendMessage("Evealyn Bot is a sophisticated and damn fine IRC bot created by SemiViral. Version 1.0");
  break;
 case "shutdown": if (userList.First(e => e.Name == realn).Access < 2)
 {
 SendMessage("Goodybe.");
 shouldRun = false;
 }
 break;
 default:
  SendMessage("Please provide a valid command.");
 break;
 }
 }
 }
 else if (ex[3] == "=")
 {
 // Create a List of users upon channel connections
 var u = new List<string>()
 {
 ex[5].Substring(1)
 };

 if (ex.Length > 6)
 ex[6].Split(' ').ToList().ForEach(x => u.Add(x));
 // Add the list of channel users to
 // specified channel index
 users.Add(ex[4], u);
 }
 }
 }
 }
internal class Eve
 {
 private static void Main(string[] args) {
 var conf = new Config() {
 Name = "Evealyn",
 Nick = "Eve",
 Port = 6667,
 Server = "irc.foonetic.net",
 Channels = new[] { "#testgrounds2", "#ministryofsillywalks" }
 };

 using (var bot = new IRCBot(conf))
 {
 conf.Joined = false;
 bot.Connect();
 bot.Runtime();
 }
 Console.WriteLine("Bot has shutdown.");
 Console.ReadLine();
 }
 }
} 
internal class IRCBot : IDisposable, IModule {
  private readonly Dictionary<string, List<string>> users = new Dictionary<string, List<string>>();
 private readonly Dictionary<string, int> userAttempts = new Dictionary<string, int>();
 private readonly Dictionary<string, string> commands = new Dictionary<string, string>
 {
 {"join", "(join <channel>) - joins specified channel."},
 {"part", "(part <channel> <message*>) - parts specified channel."},
 {"leave", "(part <channel> <message*>) - parts specified channel."},
 {"say", "(say <channel*> <message>) - sends privmsg to target channel."},
 {"chanlist", "Provides a list of channels joined."},
 {"channels", "Provides a list of channels joined."},
 {"userlist", "List all users currently in database and their access number."},
 {"define", "(define <word> <part of speech*>) - outputs a dictionary definition for the specified word."},
 {"lookup", "(lookup <target article>) - outputs the contents of a specified wikipedia article."},
 {"message", "(message <recipient> <mesaage>) - sends a message to specified user, to be sent when they login again."},
 {"seen", "(seen <target>) - Outputs the last DateTime of the target user being active."},
 {"about", "Print out the version and creator information of the bot."},
 {"shutdown", "Closes program."}
 };
 private Config _config;
 private TcpClient _connection;
 private StreamWriter _log;
 private NetworkStream _ns;
 private StreamReader _sr;
 private StreamWriter _sw;
 private readonly List<string> channels = new List<string>();
 private readonly List<string> nameDenyList = new List<string>()
 {
 "NickServ", "ChanServ",
 "vervet.foonetic.net",
 "Eve"
 };
 private List<User> userList;
 private string recipient;
 // set config 
 public IRCBot(Config config) {
 _config = config;
 }
 public void Dispose() {
 _sr?.Close();
 _sw?.Close();
 _ns?.Close();
 _log?.Close();
 _connection?.Close();
 }
 public void OnChannelEvent(ChannelEvent e) {
 throw new NotImplementedException();
 }
  public void OnChannelMessage(ChannelMessage c) {
 recipient = c.Recipient;
 
 if (QueryName(c.Realname) == null
 && !nameDenyList.Contains(c.Realname)) {
 userList.Add(new User {
 Name = c.Realname,
 Access = 2,
 Seen = DateTime.UtcNow
 });
 } else if (QueryName(c.Realname) != null)
 userList.First(e => e.Name == c.Realname).Seen = DateTime.UtcNow;
 if (!userAttempts.ContainsKey(c.Realname))
 userAttempts.Add(c.Realname, 0);
 if (!users.ContainsKey(c.Recipient)
 && c.Recipient.StartsWith("#"))
 users.Add(c.Recipient, new List<String>());
 File.WriteAllText("users.json", JsonConvert.SerializeObject(userList, Formatting.Indented));
 string[] arg = null;
 if (c.Args != null) {
 arg = c.Args.ToLower().Split(new char[] { ' ' }, 4);
 }
 switch (c.Type) {
 case "PRIVMSG":
 if (arg == null) return;
 if (QueryName(c.Realname) == null) return;
 var access = userList.First(e => e.Name == c.Realname).Access;
 string msg,
 chan;
 if (arg[0] != "eve"
 && arg[0] != "eve,")
 return;
 if (UserTimeout(c.Realname)) return;
 if (arg[1] != null)
 switch (arg[1]) {
 case "join":
 if (access > 1) {
 SendMessage("Insufficient permissions.");
 return;
 }
 if (String.IsNullOrEmpty(arg[2])) {
 SendMessage("Insufficient parameters. Type 'eve help join' to view correct usage.");
 }
 if (!arg[2].StartsWith("#")) {
 SendMessage("Channel argument must be a proper channel name (i.e. starts with '#').");
 return;
 }
 if (channels.Contains(arg[2]))
 {
 SendMessage("I'm already in that channel.");
 return;
 }
 Join(arg[2]);
 break;
 case "part":
 case "leave":
 if (access > 1) {
 SendMessage("Insufficient permissions.");
 return;
 }
 if (String.IsNullOrEmpty(arg[2])) {
 SendMessage("Insufficient parameters. Type 'eve help part' to view correct usage.");
 return;
 }
 if (!arg[2].StartsWith("#")) {
 SendMessage("Channel argument must be a proper channel name (i.e. starts with '#').");
 return;
 }
 if (!channels.Contains(arg[2])) {
 SendMessage("I'm not in that channel.");
 return;
 }
 Part(arg[2], arg[3]);
 break;
 case "say":
 if (arg.Length < 3
 || (arg[2].StartsWith("#")
 && arg.Length < 4)) {
 SendMessage("Insufficient parameters. Type 'eve help say' to view correct usage.");
 return;
 }
 msg = (!arg[2].StartsWith("#") && arg.Length > 4)
 ? arg[2] + " " + arg[3]
 : arg[2];
 chan = (arg[2].StartsWith("#")) ? arg[2] : null;
 Say(chan, msg);
 break;
 case "chanlist":
 case "channels":
 SendMessage(string.Join(" ", channels.ToArray()));
 break;
 case "define":
 if (arg.Length < 3) {
 SendMessage("Insufficient parameters. Type 'eve help define' to view correct usage.");
 return;
 }
 var pos = (arg.Length < 4) ? null : arg[3];
 Define(arg[2], pos);
 break;
 case "lookup":
 if (arg.Length < 3) {
 SendMessage("Insufficient parameters. Type 'eve help lookup' to view correct usage.");
 return;
 }
 var query = (arg.Length < 4) ? arg[2] : arg[2] + "%20" + arg[3];
 query = query.Replace(" ", "%20");
 Lookup(query, c.Nickname);
 break;
 case "message":
 if (arg.Length < 3
 || arg.Length < 4) {
 SendMessage("Insufficient parameters. Type 'eve help message' to view correct usage.");
 return;
 }
 if (QueryName(arg[2]) == null) {
 SendMessage("User does not exist in database.");
 return;
 }
 Message(c.Realname, arg[2], Regex.Escape(arg[3]));
 break;
 case "help":
 if (arg.Length > 3
 && !commands.ContainsKey(arg[2])) {
 SendMessage("Command does not exist.");
 return;
 }
 var cmd = (arg.Length < 3) ? null : arg[2];
 Help(c.Nickname, cmd);
 break;
 case "userlist":
 Userlist();
 break;
 case "seen":
 if (arg.Length < 3) {
 SendMessage("Insufficient parameters. Type 'eve help message' to view correct usage.");
 return;
 }
 if (QueryName(arg[2]) == null) {
 SendMessage("User does not exist in database.");
 return;
 }
 Seen(arg[2]);
 break;
 case "about":
 SendMessage("Evealyn Bot is a sophisticated and damn fine IRC bot created by SemiViral. Version 1.0");
 break;
 case "shutdown":
 if (access > 1) {
 SendMessage("Goodybe.");
 Eve.Run = false;
 } else SendMessage("Insufficient permissions.");
 break;
 default:
 SendMessage("Invalid command.");
 break;
 } else
 SendMessage("Please provide a command. Type 'eve help' to obtain my command list.");
 break;
 case "JOIN":
 Console.WriteLine(c.Realname);
 if (c.Realname == "Eve") return;
 if (QueryName(c.Realname) != null) {
 foreach (var m in userList.First(e => e.Name == c.Realname).Messages)
 SendData("PRIVMSG", c.Nickname + " (" + m.Date + ") " + m.Sender + ": " + Regex.Unescape(m.Contents));
 userList.First(e => e.Name == c.Realname).Messages = null;
 }
 users[c.Recipient].Add(c.Realname);
 break;
 case "PART":
 users[c.Recipient].Remove(c.Realname);
 break;
 case "MODE":
 if (!_config.Joined)
 {
 _config.Joined = true;
 SendData("PRIVMSG", "NICKSERV IDENTIFY evepass");
 foreach (var s in _config.Channels)
 {
 Join(s);
 }
 }
 break;
  case "353":
 var key = Regex.Matches(c.Args, @"(#\w+)");
 var list = key.Cast<Match>().Select(match => match.Value).ToList();
  foreach (var s in c.Args.Split(':')[1].Split(' '))
  users[list[0]].Add(s);
  break;
 }
  File.WriteAllText("users.json", JsonConvert.SerializeObject(userList, Formatting.Indented));
 }

 // command operations for main switch()
  private void Join(string chan)
 {
 SendMessage("Joining " + chan + ".");
 SendData("JOIN", chan);
 channels.Add(chan);
 }
 private void Part(string chan, string msg) {
 if (msg == null) {
 SendMessage("Leaving channel " + chan + ".");
 SendData("PART", chan);
 } else {
 SendMessage("Leaving channel " + chan + " for reason: " + msg);
 SendData("PART", chan + " " + msg);
 }
 channels.Remove(chan);
 users.Remove(chan);
 }
 private void Say(string chan, string msg) {
 if (String.IsNullOrEmpty(chan))
 SendMessage(msg);
 else
 SendData("PRIVMSG", chan + " " + msg);
 }
 private void Define(string word, string pos) {
  var url = (String.IsNullOrEmpty(pos))
 ? "https://api.pearson.com:443/v2/dictionaries/lasde/entries?headword=" + word + "&limit=1"
 : "https://api.pearson.com:443/v2/dictionaries/lasde/entries?headword=" + word + "&part_of_speech=" + pos + "&limit=1";
 var entry = JObject.Parse(HttpGET(url));
  var _out = new Dictionary<string, string>();
 if ((int)entry.SelectToken("count") < 1) {
 SendMessage("Query returned no results.");
 return;
 }
 _out.Add("word", (string)entry.SelectToken("results[0].headword"));
 _out.Add("pos", (string)entry.SelectToken("results[0].part_of_speech"));
 _out.Add("def", (string)entry.SelectToken("results[0].senses[0].definition[0]"));
 _out.Add("ex", (string)entry.SelectToken("results[0].senses[0].examples[0].text"));
 var sOut = (String.IsNullOrEmpty(_out["ex"]))
 ? _out["word"] + " [" + _out["pos"] + "]  " + _out["def"]
 : _out["word"] + " [" + _out["pos"] + "]  " + _out["def"] + " (ex. " + _out["ex"] + ")";
 SendMessage(sOut);
 }
 private void Lookup(string query, string nick) {
 var response =
 HttpGET("https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro=&explaintext=&titles=" +
  query);
 var pages = JObject.Parse(response)["query"]["pages"].Values().First();
 var title = (string)pages["title"];
 var content = title + " — " + Regex.Replace((string)pages["extract"], @"\r\n?|\n", "");
 var _out = StrSplit(content, 450);
 foreach (var s in _out)
 SendData("PRIVMSG", nick + " " + s);
 }
 private void Help(string nick, string cmd) {
 if (String.IsNullOrEmpty(cmd)) {
 SendData("PRIVMSG", nick + " Each command must be proceeded with \"eve\" or \"eve,\" to be properly queried.");
 foreach (var s in commands)
 SendData("PRIVMSG", nick + " " + s.Key + ": " + s.Value);
 SendData("PRIVMSG", nick + " (* - optional parameter)");
 } else {
 SendData("PRIVMSG", nick + " " + cmd + ": " + commands[cmd]);
 }
 }
 private void Userlist() {
 var _out = new StringBuilder();
 foreach (var s in userList) {
 _out.Append(s.Name + "(" + s.Access + ") ");
 }
 SendMessage(_out.ToString());
 }
 private void Message(string sender, string who, string msg) {
 var m = new Message {
 Sender = sender,
 Contents = msg,
 Date = DateTime.UtcNow
 };
 if (QueryName(who).Messages == null)
  userList.First(e => e.Name == who).Messages = new List<Message> { m };
 else
 userList.First(e => e.Name == who).Messages.Add(m);
 SendMessage("Message recorded and will be sent to " + who);
 }
 private void Seen(string who) {
 var u = userList.FirstOrDefault(e => e.Name == who);
 SendMessage(u.Name + " was last seen on: " + u.Seen + " (UTC)");
 }
 // split input string by maxlen and return array
 public static IEnumerable<string> StrSplit(string str, int maxLength) {
 for (var i = 0; i < str.Length; i += maxLength)
 yield return str.Substring(i, Math.Min(maxLength, str.Length - i));
 }
 public User QueryName(string name) {
 return userList.FirstOrDefault(e => e.Name == name);
 }
 // check whether or not respond to user by
 // identifying the amount of commands they've
 // issued in the past minute
 public bool UserTimeout(string who) {
 var doTimeout = false;
 if (userAttempts[who] == 3)
 if (QueryName(who).Seen.AddMinutes(1) < DateTime.UtcNow)
 userAttempts[who] = 0;
 else doTimeout = true;
 else
 if (QueryName(who).Access > 1)
 userAttempts[who] += 1;
 return doTimeout;
 }
 // initialise connection to server
 public void Connect() {
 try {
 _connection = new TcpClient(_config.Server, _config.Port);
 } catch {
 Console.WriteLine("Connection failed.");
 }
 try {
 _ns = _connection.GetStream();
 _sr = new StreamReader(_ns);
 _sw = new StreamWriter(_ns);
 _log = new StreamWriter("_logs.txt", true) { AutoFlush = true };

 Console.WriteLine(_config.Nick + " " + _config.Name);
 SendData("USER", _config.Nick + " 0 * " + _config.Name);
 SendData("NICK", _config.Nick);
 } catch {
 Console.WriteLine("Communication error.");
 throw;
 }
 userList = JsonConvert.DeserializeObject<List<User>>(File.ReadAllText("users.json"));
 if (userList == null) {
 Console.WriteLine("Failed to initialise JSON object from file");
 return;
 }
 }
 // send raw data to server
 public void SendData(string cmd, string param) {
 if (param == null) {
 _sw.WriteLine(cmd);
 _sw.Flush();
 Console.WriteLine(cmd);
 } else {
 _sw.WriteLine(cmd + " " + param);
 _sw.Flush();
 Console.WriteLine(cmd + " " + param);
 }
 }
 public void SendMessage(string message) {
 SendData("PRIVMSG", recipient + " " + message);
 }
 // send a GET request to given URL
 public string HttpGET(string url) {
 var request = (HttpWebRequest)WebRequest.Create(url);
 request.Method = "GET";
 string response;
 using (var httpr = (HttpWebResponse)request.GetResponse()) {
 response = new StreamReader(httpr.GetResponseStream()).ReadToEnd();
 }
 return response;
 }
 public void Runtime() {
 var data = _sr.ReadLine();
 var mTime = DateTime.UtcNow;
 var mRegex = new Regex(@"^:(?<Sender>[^\s]+)\s(?<Type>[^\s]+)\s(?<Recipient>[^\s]+)\s?:?(?<Args>.*)", RegexOptions.Compiled);
 var sRegex = new Regex(@"^(?<Nickname>[^\s]+)!(?<Realname>[^\s]+)@(?<Hostname>[^\s]+)", RegexOptions.Compiled);
 var aRegex = new Regex(@"^:(?<Arg1>[^\s]+)\s(?<Arg2>[^\s]+)\s(?<Arg3>[^\s]+)\s?:?(?<Arg4>.*)", RegexOptions.Compiled);
 var pRegex = new Regex(@"^PING :(?<Message>.+)", RegexOptions.None);
 Console.WriteLine(data);
 _log.WriteLine(data);
 if (mRegex.IsMatch(data)) {
 var mVal = mRegex.Match(data);
 var mSender = mVal.Groups["Sender"].Value;
 var sMatch = sRegex.Match(mSender);
 var c = new ChannelMessage() {
  Nickname = mSender,
 Realname = mSender,
 Hostname = mSender,
 Type = mVal.Groups["Type"].Value,
 Recipient = (mVal.Groups["Recipient"].Value.StartsWith(":"))
  ? mVal.Groups["Recipient"].Value.Substring(1)
 : mVal.Groups["Recipient"].Value,  Args = mVal.Groups["Args"].Value,
 Time = DateTime.UtcNow
 };
 if (sMatch.Success)
 {
 var realname = sMatch.Groups["Realname"].Value;
 c.Nickname = sMatch.Groups["Nickname"].Value;
 c.Realname = (realname.StartsWith("~")) ? realname.Substring(1) : realname;
 c.Hostname = sMatch.Groups["Hostname"].Value;
 }
 OnChannelMessage(c);
 } else if (pRegex.IsMatch(data)) {
 SendData("PONG", pRegex.Match(data).Value);
 }
 }
 }
}
internal class Eve {
 public static bool Run = true;
  private static void Main(string[] args) {
 var conf = new Config() {
 Name = "Evealyn",
 Nick = "Eve",
 Port = 6667,
 Server = "irc.foonetic.net",
 Channels = new[] { "#testgrounds2" },
 Joined = false
 };
 using (var bot = new IRCBot.IRCBot(conf)) {
 bot.Connect();
 while (Run) {
 bot.Runtime();
 }
 }
 Console.WriteLine("Bot has shutdown.");
 Console.ReadLine();
 }
} 

The currently posted code is a second revision; I refactored it to use Regex and some far more efficient processing techniques.

Tweeted twitter.com/StackCodeReview/status/675650543323389954
Clarification
Source Link
Loading
added 161 characters in body; edited tags
Source Link
Loading
edited tags
Link
200_success
  • 145.6k
  • 22
  • 190
  • 479
Loading
added 2 characters in body
Source Link
Loading
deleted 115 characters in body
Source Link
Loading
Source Link
Loading
lang-cs

AltStyle によって変換されたページ (->オリジナル) /