(削除) 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.
- 173
- 7
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.
- 173
- 7
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.