The easy to use and full featured Irc Bot everyone is talking about!
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  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 Dictionary<PrivilegeMode, AccessType> PrivilegeModeMapping = 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. public Dictionary<ChannelMode, AccessType> ChannelModeMapping = new Dictionary<ChannelMode, AccessType>() { { ChannelMode.v, AccessType.Voice }, { ChannelMode.h, AccessType.HalfOperator }, { ChannelMode.o, AccessType.Operator }, { ChannelMode.a, AccessType.SuperOperator }, { ChannelMode.q, AccessType.Founder } };
  23. private bool GhostSent;
  24. private int CurNickChoice;
  25. public Bot(ServerConfig serverConfig)
  26. {
  27. Modules = new List<Module>();
  28. GhostSent = false;
  29. CurNickChoice = 0;
  30. ServerConfig = serverConfig;
  31. IRC = new IRC(serverConfig.MaxMessageLength, serverConfig.MessageSendDelay);
  32. IRC.ConnectEvent += HandleConnectEvent;
  33. IRC.DisconnectEvent += HandleDisconnectEvent;
  34. IRC.Message.ServerReplyEvent += HandleReplyEvent;
  35. IRC.Message.ChannelMessageReceivedEvent += HandleChannelMessageReceivedEvent;
  36. IRC.Message.PrivateMessageReceivedEvent += HandlePrivateMessageReceivedEvent;
  37. IRC.Message.PrivateNoticeReceivedEvent += HandlePrivateNoticeReceivedEvent;
  38. IRC.Message.JoinChannelEvent += HandleJoinEvent;
  39. IRC.Message.KickEvent += HandleKickEvent;
  40. IRC.Message.ChannelModeChangeEvent += HandleChannelModeChangeEvent;
  41. LoadModules();
  42. }
  43. /// <summary>
  44. /// Trys to connect to one of the IPs of the given hostname. If the connection was successful, it will login the nick.
  45. /// </summary>
  46. public void Connect()
  47. {
  48. GhostSent = false;
  49. CurNickChoice = 0;
  50. bool serverConnected = false;
  51. int i = 0;
  52. do
  53. {
  54. if (ServerConfig.Hosts.Count > i)
  55. {
  56. IPAddress[] ipList = Dns.GetHostAddresses(ServerConfig.Hosts[i].Host);
  57. foreach (IPAddress ip in ipList)
  58. {
  59. serverConnected = IRC.Connect(ip, ServerConfig.Hosts[i].Port);
  60. if (serverConnected)
  61. {
  62. break;
  63. }
  64. }
  65. i++;
  66. }
  67. else
  68. {
  69. break;
  70. }
  71. }
  72. while (!serverConnected);
  73. if (serverConnected)
  74. {
  75. if (CurNickChoice < ServerConfig.Nicknames.Count)
  76. {
  77. IRC.Login(ServerConfig.Name, new Nick()
  78. {
  79. Nickname = ServerConfig.Nicknames[CurNickChoice],
  80. Host = Dns.GetHostName(),
  81. Realname = ServerConfig.Realname,
  82. Username = ServerConfig.Username
  83. });
  84. }
  85. else
  86. {
  87. Disconnect();
  88. }
  89. }
  90. }
  91. /// <summary>
  92. /// Disconnects from the current server.
  93. /// </summary>
  94. public void Disconnect()
  95. {
  96. IRC.Disconnect();
  97. Connected = false;
  98. LoggedIn = false;
  99. }
  100. public void LoadModules()
  101. {
  102. foreach (Module module in ServerConfig.Modules)
  103. {
  104. if (module.Enabled && !Modules.Exists(mod => mod.ClassName == module.ClassName))
  105. {
  106. Module loadedModule = module.CreateInstance(this);
  107. if (loadedModule.Loaded)
  108. {
  109. Modules.Add(loadedModule);
  110. }
  111. }
  112. }
  113. }
  114. public bool CheckChannelAccess(string channel, string nickname, AccessType access)
  115. {
  116. Channel foundChannel = IRC.Channels.Find(chan => chan.Name == channel);
  117. if (foundChannel != null)
  118. {
  119. Nick foundNick = foundChannel.Nicks.Find(nick => nick.Nickname == nickname);
  120. if (foundNick != null)
  121. {
  122. for (int i = 0; i < foundNick.Privileges.Count; i++)
  123. {
  124. switch (PrivilegeModeMapping[foundNick.Privileges[i]])
  125. {
  126. case AccessType.User:
  127. if (access == AccessType.User)
  128. {
  129. return true;
  130. }
  131. break;
  132. case AccessType.Voice:
  133. if (access == AccessType.User || access == AccessType.Voice)
  134. {
  135. return true;
  136. }
  137. break;
  138. case AccessType.HalfOperator:
  139. if (access == AccessType.User || access == AccessType.Voice || access == AccessType.HalfOperator)
  140. {
  141. return true;
  142. }
  143. break;
  144. case AccessType.Operator:
  145. if (access == AccessType.User || access == AccessType.Voice || access == AccessType.HalfOperator || access == AccessType.Operator)
  146. {
  147. return true;
  148. }
  149. break;
  150. case AccessType.SuperOperator:
  151. if (access == AccessType.User || access == AccessType.Voice || access == AccessType.HalfOperator || access == AccessType.Operator || access == AccessType.SuperOperator)
  152. {
  153. return true;
  154. }
  155. break;
  156. case AccessType.Founder:
  157. if (access == AccessType.User || access == AccessType.Voice || access == AccessType.HalfOperator || access == AccessType.Operator || access == AccessType.SuperOperator || access == AccessType.Founder)
  158. {
  159. return true;
  160. }
  161. break;
  162. case AccessType.Owner:
  163. return true;
  164. break;
  165. }
  166. }
  167. }
  168. }
  169. return false;
  170. }
  171. public bool CheckChannelAccess(string channel, string nickname, List<AccessType> access)
  172. {
  173. bool hasAccess = false;
  174. for (int i = 0; i < access.Count; i++)
  175. {
  176. hasAccess = CheckChannelAccess(channel, nickname, access[i]);
  177. if (hasAccess)
  178. {
  179. break;
  180. }
  181. }
  182. return hasAccess;
  183. }
  184. private void HandleConnectEvent()
  185. {
  186. Connected = true;
  187. }
  188. private void HandleDisconnectEvent()
  189. {
  190. Connected = false;
  191. }
  192. private void HandleJoinEvent(object sender, JoinChannelInfo info)
  193. {
  194. if (info.Nick.Nickname == IRC.Nickname)
  195. {
  196. if (!ServerConfig.Channels.Exists(chan => chan.Name == info.Channel))
  197. {
  198. ChannelConfig chanConfig = new ChannelConfig();
  199. chanConfig.Name = info.Channel;
  200. ServerConfig.Channels.Add(chanConfig);
  201. ServerConfig.Save();
  202. }
  203. }
  204. }
  205. private void HandleKickEvent(object sender, KickInfo info)
  206. {
  207. if (info.KickedNick.Nickname == IRC.Nickname)
  208. {
  209. ServerConfig.Channels.RemoveAll(chan => chan.Name == info.Channel);
  210. ServerConfig.Save();
  211. }
  212. }
  213. private void HandleChannelModeChangeEvent(object sender, ChannelModeChangeInfo e)
  214. {
  215. ChannelConfig channel = ServerConfig.Channels.Find(chan => chan.Name == e.Channel);
  216. if (channel != null)
  217. {
  218. foreach (ChannelModeInfo mode in e.Modes)
  219. {
  220. switch (mode.Mode)
  221. {
  222. case ChannelMode.k:
  223. if (mode.Set)
  224. {
  225. channel.Key = mode.Parameter;
  226. }
  227. else
  228. {
  229. channel.Key = string.Empty;
  230. }
  231. ServerConfig.Save();
  232. break;
  233. }
  234. }
  235. }
  236. }
  237. private void HandleReplyEvent(object sender, IReply e)
  238. {
  239. if (e.GetType() == typeof(ServerReplyMessage))
  240. {
  241. ServerReplyMessage reply = (ServerReplyMessage)e;
  242. switch (reply.ReplyCode)
  243. {
  244. case IRCReplyCode.RPL_WELCOME:
  245. // If the reply is Welcome, that means we are fully connected to the server.
  246. LoggedIn = true;
  247. if (!GhostSent && IRC.Nickname != ServerConfig.Nicknames[CurNickChoice])
  248. {
  249. IRC.SendPrivateMessage("NickServ", string.Format("GHOST {0} {1}", ServerConfig.Nicknames[CurNickChoice], ServerConfig.Password));
  250. Thread.Sleep(1000);
  251. IRC.SendNick(ServerConfig.Nicknames[CurNickChoice]);
  252. GhostSent = true;
  253. }
  254. // Identify to NickServ if need be
  255. IRC.SendPrivateMessage("NickServ", string.Format("IDENTIFY {0}", ServerConfig.Password));
  256. // Join all required channels
  257. // Delay joining channels for configured time
  258. Thread.Sleep(ServerConfig.JoinDelay);
  259. foreach (ChannelConfig channel in ServerConfig.Channels)
  260. {
  261. IRC.SendJoin(channel.Name, channel.Key);
  262. }
  263. break;
  264. }
  265. }
  266. else if (e.GetType() == typeof(ServerErrorMessage))
  267. {
  268. ServerErrorMessage error = (ServerErrorMessage) e;
  269. switch (error.ErrorCode)
  270. {
  271. case IRCErrorCode.ERR_NOTREGISTERED:
  272. if (ServerConfig.AutoRegister && ServerConfig.Password != string.Empty && ServerConfig.Email != string.Empty)
  273. {
  274. IRC.SendPrivateMessage("NickServ", string.Format("REGISTER {0} {1}", ServerConfig.Password, ServerConfig.Email));
  275. }
  276. break;
  277. case IRCErrorCode.ERR_NICKNAMEINUSE:
  278. if (LoggedIn == false)
  279. {
  280. string nick = string.Empty;
  281. if (IRC.Nickname == ServerConfig.Nicknames[CurNickChoice] && ServerConfig.Nicknames.Count > CurNickChoice + 1)
  282. {
  283. CurNickChoice++;
  284. nick = ServerConfig.Nicknames[CurNickChoice];
  285. }
  286. else
  287. {
  288. Random rand = new Random();
  289. nick = string.Format("{0}_{1}", ServerConfig.Nicknames.First(), rand.Next(100000).ToString());
  290. }
  291. IRC.Login(ServerConfig.Name, new Nick()
  292. {
  293. Nickname = nick,
  294. Host = Dns.GetHostName(),
  295. Realname = ServerConfig.Realname,
  296. Username = ServerConfig.Username
  297. });
  298. }
  299. break;
  300. }
  301. }
  302. }
  303. private void HandleChannelMessageReceivedEvent(object sender, ChannelMessage e)
  304. {
  305. // The message was a command
  306. if (e.Message.StartsWith(ServerConfig.CommandPrefix))
  307. {
  308. if (!ServerConfig.ChannelBlacklist.Contains(e.Channel)
  309. && !ServerConfig.NickBlacklist.Contains(e.Sender.Nickname)
  310. )
  311. {
  312. ParseCommandMessage(e.TimeStamp, e.Message, e.Sender, e.Channel, MessageType.Channel);
  313. }
  314. }
  315. }
  316. private void HandlePrivateMessageReceivedEvent(object sender, PrivateMessage e)
  317. {
  318. // The message was a command
  319. if (e.Message.StartsWith(ServerConfig.CommandPrefix))
  320. {
  321. if (!ServerConfig.NickBlacklist.Contains(e.Sender.Nickname))
  322. {
  323. ParseCommandMessage(e.TimeStamp, e.Message, e.Sender, e.Sender.Nickname, MessageType.Query);
  324. }
  325. }
  326. }
  327. private void HandlePrivateNoticeReceivedEvent(object sender, PrivateNotice e)
  328. {
  329. // The notice was a command
  330. if (e.Message.StartsWith(ServerConfig.CommandPrefix))
  331. {
  332. if (!ServerConfig.NickBlacklist.Contains(e.Sender.Nickname))
  333. {
  334. ParseCommandMessage(e.TimeStamp, e.Message, e.Sender, e.Sender.Nickname, MessageType.Notice);
  335. }
  336. }
  337. }
  338. private void ParseCommandMessage(DateTime timestamp, string message, Nick sender, string location, MessageType messageType)
  339. {
  340. // Extract command and arguments
  341. string[] msgArgs = message.Split(new[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries);
  342. string command = msgArgs[0].Remove(0, ServerConfig.CommandPrefix.Length);
  343. List<string> argsOnly = msgArgs.ToList();
  344. argsOnly.RemoveAt(0);
  345. // Find the module that contains the command
  346. Module module = Modules.Find(mod => mod.Commands.Exists(c => c.Triggers.Contains(command)) && mod.Loaded);
  347. if (module != null)
  348. {
  349. // Find the command
  350. Command cmd = module.Commands.Find(c => c.Triggers.Contains(command));
  351. if (cmd != null)
  352. {
  353. CommandMessage newCommand = new CommandMessage();
  354. List<CommandArgument> validArguments = cmd.Arguments.FindAll(arg => arg.MessageTypes.Contains(messageType));
  355. newCommand.Nick.Copy(sender);
  356. IRC.Channels.ForEach(channel => channel.Nicks.ForEach(nick =>
  357. {
  358. if (nick.Nickname == newCommand.Nick.Nickname)
  359. {
  360. newCommand.Nick.AddPrivileges(nick.Privileges);
  361. }
  362. }));
  363. newCommand.TimeStamp = timestamp;
  364. newCommand.Location = location;
  365. newCommand.MessageType = messageType;
  366. newCommand.Command = command;
  367. if (argsOnly.Count > 0)
  368. {
  369. string[] argSplit = argsOnly.First().Split(new[] { ' ' }, validArguments.Count, StringSplitOptions.RemoveEmptyEntries);
  370. for (int i = 0; i < validArguments.Count && i <= argSplit.GetUpperBound(0); i++)
  371. {
  372. newCommand.Arguments.Add(validArguments[i].Name, argSplit[i]);
  373. }
  374. }
  375. bool invalidArgs = false;
  376. for (int i = 0; i < newCommand.Arguments.Count; i++)
  377. {
  378. if (validArguments[i].AllowedValues.Count > 0)
  379. {
  380. // Check to see if any of the arguments are invalid
  381. string argVal = newCommand.Arguments[validArguments[i].Name];
  382. if (!validArguments[i].AllowedValues.Exists(val => val.ToLower() == argVal.ToLower()))
  383. {
  384. invalidArgs = true;
  385. string invalidMessage = string.Format("Invalid value for \u0002{0}\u000F in \u0002{1}{2} {3}\u000F. Valid options are \u0002{4}\u000F.", validArguments[i].Name, ServerConfig.CommandPrefix, command, string.Join(" ", validArguments.Select(arg => { if (arg.Required) { return "\u001F" + arg.Name + "\u000F\u0002"; } return "[\u001F" + arg.Name + "\u000F\u0002]"; })), string.Join(", ", validArguments[i].AllowedValues));
  386. switch (messageType)
  387. {
  388. case MessageType.Channel:
  389. case MessageType.Query:
  390. IRC.SendPrivateMessage(location, invalidMessage);
  391. break;
  392. case MessageType.Notice:
  393. IRC.SendNotice(location, invalidMessage);
  394. break;
  395. }
  396. break;
  397. }
  398. }
  399. }
  400. if (validArguments.FindAll(arg => arg.Required).Count <= newCommand.Arguments.Count)
  401. {
  402. if (!invalidArgs)
  403. {
  404. if (CommandReceivedEvent != null)
  405. {
  406. CommandReceivedEvent(newCommand);
  407. }
  408. }
  409. }
  410. else
  411. {
  412. string missingArgument = string.Format("Missing a required argument for \u0002{0}{1} {2}\u000F. The required arguments are \u0002{3}\u000F.", ServerConfig.CommandPrefix, command, string.Join(" ", validArguments.Select(arg => { if (arg.Required) { return "\u001F" + arg.Name + "\u000F\u0002"; } return "[\u001F" + arg.Name + "\u000F\u0002]"; })), string.Join(", ", validArguments.Where(arg => arg.Required).Select(arg => arg.Name)));
  413. if (messageType == MessageType.Channel || messageType == MessageType.Query)
  414. {
  415. IRC.SendPrivateMessage(location, missingArgument);
  416. }
  417. else if (messageType == MessageType.Notice)
  418. {
  419. IRC.SendNotice(location, missingArgument);
  420. }
  421. }
  422. }
  423. }
  424. }
  425. }
  426. }