The easy to use and full featured Irc Bot everyone is talking about!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Bot.cs 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Net;
  5. using System.Threading;
  6. using Combot.IRCServices;
  7. using Combot.Configurations;
  8. using Combot.IRCServices.Messaging;
  9. using Combot.Modules;
  10. namespace Combot
  11. {
  12. public class Bot
  13. {
  14. public event Action<CommandMessage> CommandReceivedEvent;
  15. public event Action<BotError> ErrorEvent;
  16. public ServerConfig ServerConfig;
  17. public IRC IRC;
  18. public List<Module> Modules;
  19. public bool Connected = false;
  20. public bool LoggedIn = false;
  21. public static Dictionary<PrivilegeMode, AccessType> AccessTypeMapping = new Dictionary<PrivilegeMode, AccessType>() { { PrivilegeMode.v, AccessType.Voice }, { PrivilegeMode.h, AccessType.HalfOperator }, { PrivilegeMode.o, AccessType.Operator }, { PrivilegeMode.a, AccessType.SuperOperator }, { PrivilegeMode.q, AccessType.Founder } };
  22. private bool GhostSent;
  23. public Bot(ServerConfig serverConfig)
  24. {
  25. IRC = new IRC();
  26. Modules = new List<Module>();
  27. GhostSent = false;
  28. ServerConfig = serverConfig;
  29. IRC.ConnectEvent += HandleConnectEvent;
  30. IRC.DisconnectEvent += HandleDisconnectEvent;
  31. IRC.Message.ServerReplyEvent += HandleReplyEvent;
  32. IRC.Message.ChannelMessageReceivedEvent += HandleChannelMessageReceivedEvent;
  33. IRC.Message.JoinChannelEvent += HandleJoinEvent;
  34. IRC.Message.KickEvent += HandleKickEvent;
  35. LoadModules();
  36. }
  37. /// <summary>
  38. /// Trys to connect to one of the IPs of the given hostname. If the connection was successful, it will login the nick.
  39. /// </summary>
  40. public void Connect()
  41. {
  42. GhostSent = false;
  43. bool serverConnected = false;
  44. int i = 0;
  45. do
  46. {
  47. if (ServerConfig.Hosts.Count > i)
  48. {
  49. IPAddress[] ipList = Dns.GetHostAddresses(ServerConfig.Hosts[i].Host);
  50. foreach (IPAddress ip in ipList)
  51. {
  52. serverConnected = IRC.Connect(ip, ServerConfig.Hosts[i].Port, 5000);
  53. if (serverConnected)
  54. {
  55. break;
  56. }
  57. }
  58. i++;
  59. }
  60. else
  61. {
  62. break;
  63. }
  64. }
  65. while (!serverConnected);
  66. if (serverConnected)
  67. {
  68. IRC.Login(ServerConfig.Name, new Nick()
  69. {
  70. Nickname = ServerConfig.Nickname,
  71. Host = Dns.GetHostName(),
  72. Realname = ServerConfig.Realname,
  73. Username = ServerConfig.Username
  74. });
  75. }
  76. }
  77. /// <summary>
  78. /// Disconnects from the current server.
  79. /// </summary>
  80. public void Disconnect()
  81. {
  82. IRC.Disconnect();
  83. Connected = false;
  84. LoggedIn = false;
  85. }
  86. public void LoadModules()
  87. {
  88. foreach (Module module in ServerConfig.Modules)
  89. {
  90. if (module.Enabled && !Modules.Exists(mod => mod.ClassName == module.ClassName))
  91. {
  92. Module loadedModule = module.CreateInstance(this);
  93. if (loadedModule.Loaded)
  94. {
  95. Modules.Add(loadedModule);
  96. }
  97. }
  98. }
  99. }
  100. private void HandleConnectEvent()
  101. {
  102. Connected = true;
  103. }
  104. private void HandleDisconnectEvent()
  105. {
  106. Connected = false;
  107. }
  108. private void HandleJoinEvent(object sender, JoinChannelInfo info)
  109. {
  110. if (info.Nick.Nickname == IRC.Nickname)
  111. {
  112. if (!ServerConfig.Channels.Exists(chan => chan.Name == info.Channel))
  113. {
  114. ChannelConfig chanConfig = new ChannelConfig();
  115. chanConfig.Name = info.Channel;
  116. ServerConfig.Channels.Add(chanConfig);
  117. ServerConfig.Save();
  118. }
  119. }
  120. }
  121. private void HandleKickEvent(object sender, KickInfo info)
  122. {
  123. if (info.KickedNick.Nickname == IRC.Nickname)
  124. {
  125. ServerConfig.Channels.RemoveAll(chan => chan.Name == info.Channel);
  126. ServerConfig.Save();
  127. }
  128. }
  129. private async void HandleReplyEvent(object sender, IReply e)
  130. {
  131. if (e.GetType() == typeof(ServerReplyMessage))
  132. {
  133. ServerReplyMessage reply = (ServerReplyMessage)e;
  134. switch (reply.ReplyCode)
  135. {
  136. case IRCReplyCode.RPL_WELCOME:
  137. // If the reply is Welcome, that means we are fully connected to the server.
  138. LoggedIn = true;
  139. if (!GhostSent && IRC.Nickname != ServerConfig.Nickname)
  140. {
  141. IRC.SendPrivateMessage("NickServ", string.Format("GHOST {0} {1}", ServerConfig.Nickname, ServerConfig.Password));
  142. Thread.Sleep(1000);
  143. IRC.SendNick(ServerConfig.Nickname);
  144. GhostSent = true;
  145. }
  146. // Identify to NickServ if need be
  147. IRC.SendPrivateMessage("NickServ", string.Format("IDENTIFY {0}", ServerConfig.Password));
  148. // Join all required channels
  149. // Delay joining channels for configured time
  150. Thread.Sleep(ServerConfig.JoinDelay);
  151. foreach (ChannelConfig channel in ServerConfig.Channels)
  152. {
  153. IRC.SendJoin(channel.Name, channel.Key);
  154. }
  155. break;
  156. }
  157. }
  158. else if (e.GetType() == typeof(ServerErrorMessage))
  159. {
  160. ServerErrorMessage error = (ServerErrorMessage) e;
  161. switch (error.ErrorCode)
  162. {
  163. case IRCErrorCode.ERR_NOTREGISTERED:
  164. if (ServerConfig.Password != string.Empty && ServerConfig.Email != string.Empty)
  165. {
  166. IRC.SendPrivateMessage("NickServ", string.Format("REGISTER {0} {1}", ServerConfig.Password, ServerConfig.Email));
  167. }
  168. break;
  169. case IRCErrorCode.ERR_NICKNAMEINUSE:
  170. if (LoggedIn == false)
  171. {
  172. string nick = string.Empty;
  173. if (IRC.Nickname == ServerConfig.Nickname && ServerConfig.SecondaryNickname != string.Empty)
  174. {
  175. nick = ServerConfig.SecondaryNickname;
  176. }
  177. else
  178. {
  179. Random rand = new Random();
  180. nick = string.Format("{0}_{1}", ServerConfig.Nickname, rand.Next(100000).ToString());
  181. }
  182. IRC.Login(ServerConfig.Name, new Nick()
  183. {
  184. Nickname = nick,
  185. Host = Dns.GetHostName(),
  186. Realname = ServerConfig.Realname,
  187. Username = ServerConfig.Username
  188. });
  189. }
  190. break;
  191. }
  192. }
  193. }
  194. private void HandleChannelMessageReceivedEvent(object sender, ChannelMessage e)
  195. {
  196. // The message was a command
  197. if (e.Message.StartsWith(ServerConfig.CommandPrefix))
  198. {
  199. if (!ServerConfig.ChannelBlacklist.Contains(e.Channel)
  200. && !ServerConfig.NickBlacklist.Contains(e.Sender.Nickname)
  201. )
  202. {
  203. ParseCommandMessage(e.TimeStamp, e.Message, e.Sender, e.Channel, LocationType.Channel);
  204. }
  205. }
  206. }
  207. private void ParseCommandMessage(DateTime timestamp, string message, Nick sender, string location, LocationType locationType)
  208. {
  209. // Extract command and arguments
  210. string[] msgArgs = message.Split(new[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries);
  211. string command = msgArgs[0].Remove(0, ServerConfig.CommandPrefix.Length);
  212. List<string> argsOnly = msgArgs.ToList();
  213. argsOnly.RemoveAt(0);
  214. Module module = Modules.Find(mod => mod.Commands.Exists(c => c.Triggers.Contains(command)) && mod.Loaded);
  215. if (module != null)
  216. {
  217. Command cmd = module.Commands.Find(c => c.Triggers.Contains(command));
  218. if (cmd != null)
  219. {
  220. CommandMessage newCommand = new CommandMessage();
  221. newCommand.Nick.Copy(sender);
  222. IRC.Channels.ForEach(channel => channel.Nicks.ForEach(nick =>
  223. {
  224. if (nick.Nickname == newCommand.Nick.Nickname)
  225. {
  226. newCommand.Nick.AddPrivileges(nick.Privileges);
  227. }
  228. }));
  229. newCommand.TimeStamp = timestamp;
  230. newCommand.Location = location;
  231. newCommand.LocationType = locationType;
  232. newCommand.Command = command;
  233. if (argsOnly.Count > 0)
  234. {
  235. string[] argSplit = argsOnly.First().Split(new[] {' '}, cmd.Arguments.Count + 1, StringSplitOptions.RemoveEmptyEntries);
  236. for (int i = 0; i < cmd.Arguments.Count && i <= argSplit.GetUpperBound(0); i++)
  237. {
  238. newCommand.Arguments.Add(cmd.Arguments[i].Name, argSplit[i]);
  239. }
  240. }
  241. if (cmd.Arguments.FindAll(arg => arg.Required).Count <= newCommand.Arguments.Count)
  242. {
  243. if (CommandReceivedEvent != null)
  244. {
  245. CommandReceivedEvent(newCommand);
  246. }
  247. }
  248. }
  249. }
  250. }
  251. }
  252. }