The easy to use and full featured Irc Bot everyone is talking about!
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

Bot.cs 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Net;
  6. using System.Net.Sockets;
  7. using System.Text.RegularExpressions;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using Combot.IRCServices;
  11. using Combot.Configurations;
  12. using Combot.Databases;
  13. using Combot.IRCServices.Messaging;
  14. using Combot.Modules;
  15. namespace Combot
  16. {
  17. public class Bot
  18. {
  19. public event Action<CommandMessage> CommandReceivedEvent;
  20. public event Action<BotError> ErrorEvent;
  21. public ServerConfig ServerConfig;
  22. public IRC IRC;
  23. public Database Database;
  24. public List<Module> Modules;
  25. public bool Connected = false;
  26. public bool LoggedIn = false;
  27. public DateTime ConnectionTime;
  28. public DateTime LoadTime;
  29. 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 } };
  30. 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 } };
  31. private bool GhostSent;
  32. private int CurNickChoice;
  33. private int PreNickChoice;
  34. private int RetryCount;
  35. private bool RetryAllowed;
  36. public Bot(ServerConfig serverConfig)
  37. {
  38. Modules = new List<Module>();
  39. GhostSent = false;
  40. CurNickChoice = 0;
  41. PreNickChoice = -1;
  42. RetryCount = 0;
  43. ServerConfig = serverConfig;
  44. LoadTime = DateTime.Now;
  45. ConnectionTime = DateTime.Now;
  46. IRC = new IRC(serverConfig.MaxMessageLength, serverConfig.MessageSendDelay);
  47. IRC.ConnectEvent += HandleConnectEvent;
  48. IRC.DisconnectEvent += HandleDisconnectEvent;
  49. IRC.Message.ServerReplyEvent += HandleReplyEvent;
  50. IRC.Message.ChannelMessageReceivedEvent += HandleChannelMessageReceivedEvent;
  51. IRC.Message.PrivateMessageReceivedEvent += HandlePrivateMessageReceivedEvent;
  52. IRC.Message.PrivateNoticeReceivedEvent += HandlePrivateNoticeReceivedEvent;
  53. IRC.Message.JoinChannelEvent += HandleJoinEvent;
  54. IRC.Message.KickEvent += HandleKickEvent;
  55. IRC.Message.ChannelModeChangeEvent += HandleChannelModeChangeEvent;
  56. Database = new Database(serverConfig.Database);
  57. Database.MysqlErrorEvent += HandleMysqlErrorEvent;
  58. LoadModules();
  59. }
  60. /// <summary>
  61. /// Trys to connect to one of the IPs of the given hostname. If the connection was successful, it will login the nick.
  62. /// </summary>
  63. public void Connect()
  64. {
  65. ConnectionTime = DateTime.Now;
  66. GhostSent = false;
  67. CurNickChoice = 0;
  68. RetryAllowed = ServerConfig.Reconnect;
  69. bool serverConnected = false;
  70. int i = 0;
  71. do
  72. {
  73. if (ServerConfig.Hosts.Count > i)
  74. {
  75. try
  76. {
  77. IPAddress[] ipList = Dns.GetHostAddresses(ServerConfig.Hosts[i].Host);
  78. foreach (IPAddress ip in ipList)
  79. {
  80. serverConnected = IRC.Connect(ip, ServerConfig.Hosts[i].Port);
  81. if (serverConnected)
  82. {
  83. break;
  84. }
  85. }
  86. i++;
  87. }
  88. catch (SocketException)
  89. {
  90. break;
  91. }
  92. }
  93. else
  94. {
  95. break;
  96. }
  97. }
  98. while (!serverConnected);
  99. if (serverConnected)
  100. {
  101. if (CurNickChoice < ServerConfig.Nicknames.Count)
  102. {
  103. IRC.Login(ServerConfig.Name, new Nick()
  104. {
  105. Nickname = ServerConfig.Nicknames[CurNickChoice],
  106. Host = Dns.GetHostName(),
  107. Realname = ServerConfig.Realname,
  108. Username = ServerConfig.Username
  109. });
  110. }
  111. else
  112. {
  113. Disconnect();
  114. }
  115. }
  116. else
  117. {
  118. Reconnect();
  119. }
  120. }
  121. /// <summary>
  122. /// Disconnects from the current server.
  123. /// </summary>
  124. public void Disconnect()
  125. {
  126. RetryAllowed = false;
  127. RetryCount = 0;
  128. IRC.Disconnect();
  129. Connected = false;
  130. LoggedIn = false;
  131. }
  132. private void Reconnect()
  133. {
  134. if (RetryAllowed)
  135. {
  136. if (ErrorEvent != null)
  137. {
  138. ErrorEvent(new BotError() { Message = string.Format("Retrying connection in {0} seconds.", (int)Math.Pow(2, RetryCount)), Type = ErrorType.IRC });
  139. }
  140. Task.Run(() =>
  141. {
  142. Thread.Sleep(1000 * (int)Math.Pow(2, RetryCount));
  143. RetryCount++;
  144. Connect();
  145. });
  146. }
  147. }
  148. private void HandleConnectEvent()
  149. {
  150. Connected = true;
  151. RetryCount = 0;
  152. }
  153. private void HandleDisconnectEvent()
  154. {
  155. Connected = false;
  156. Reconnect();
  157. }
  158. public void LoadModules()
  159. {
  160. // Get all config files from Module directory
  161. string[] moduleLocations = Directory.GetDirectories(ServerConfig.ModuleLocation);
  162. foreach (string location in moduleLocations)
  163. {
  164. LoadModule(location);
  165. }
  166. }
  167. public bool LoadModule(string module)
  168. {
  169. Module newModule = new Module();
  170. newModule.ConfigPath = module;
  171. newModule.LoadConfig();
  172. if (newModule.Enabled && !Modules.Exists(mod => mod.ClassName == newModule.ClassName))
  173. {
  174. if (File.Exists(string.Format(@"{0}\{1}.dll", module, newModule.Name)))
  175. {
  176. Module loadedModule = newModule.CreateInstance(this);
  177. if (loadedModule.Loaded)
  178. {
  179. loadedModule.ModuleErrorEvent += HandleModuleErrorEvent;
  180. Modules.Add(loadedModule);
  181. return true;
  182. }
  183. }
  184. }
  185. return false;
  186. }
  187. public void UnloadModules()
  188. {
  189. List<Module> moduleList = Modules;
  190. for (int i = 0; i < moduleList.Count; i++)
  191. {
  192. UnloadModule(moduleList[i].Name);
  193. }
  194. }
  195. public bool UnloadModule(string moduleName)
  196. {
  197. Module module = Modules.Find(mod => mod.Name.ToLower() == moduleName.ToLower());
  198. if (module != null)
  199. {
  200. module.Loaded = false;
  201. Modules.Remove(module);
  202. return true;
  203. }
  204. return false;
  205. }
  206. public bool CheckChannelAccess(string channel, string nickname, AccessType access)
  207. {
  208. if (nickname == IRC.Nickname)
  209. {
  210. return true;
  211. }
  212. Channel foundChannel = IRC.Channels.Find(chan => chan.Name == channel);
  213. if (foundChannel != null)
  214. {
  215. Nick foundNick = foundChannel.Nicks.Find(nick => nick.Nickname == nickname);
  216. if (foundNick != null && ServerConfig.Owners.Contains(nickname) && foundNick.Modes.Contains(UserMode.r))
  217. {
  218. return true;
  219. }
  220. if (foundNick != null)
  221. {
  222. for (int i = 0; i < foundNick.Privileges.Count; i++)
  223. {
  224. switch (PrivilegeModeMapping[foundNick.Privileges[i]])
  225. {
  226. case AccessType.User:
  227. if (access == AccessType.User)
  228. {
  229. return true;
  230. }
  231. break;
  232. case AccessType.Voice:
  233. if (access == AccessType.User || access == AccessType.Voice)
  234. {
  235. return true;
  236. }
  237. break;
  238. case AccessType.HalfOperator:
  239. if (access == AccessType.User || access == AccessType.Voice || access == AccessType.HalfOperator)
  240. {
  241. return true;
  242. }
  243. break;
  244. case AccessType.Operator:
  245. if (access == AccessType.User || access == AccessType.Voice || access == AccessType.HalfOperator || access == AccessType.Operator)
  246. {
  247. return true;
  248. }
  249. break;
  250. case AccessType.SuperOperator:
  251. if (access == AccessType.User || access == AccessType.Voice || access == AccessType.HalfOperator || access == AccessType.Operator || access == AccessType.SuperOperator)
  252. {
  253. return true;
  254. }
  255. break;
  256. case AccessType.Founder:
  257. if (access == AccessType.User || access == AccessType.Voice || access == AccessType.HalfOperator || access == AccessType.Operator || access == AccessType.SuperOperator || access == AccessType.Founder)
  258. {
  259. return true;
  260. }
  261. break;
  262. case AccessType.Owner:
  263. return true;
  264. }
  265. }
  266. }
  267. }
  268. return false;
  269. }
  270. public bool CheckChannelAccess(string channel, string nickname, List<AccessType> access)
  271. {
  272. bool hasAccess = false;
  273. for (int i = 0; i < access.Count; i++)
  274. {
  275. hasAccess = CheckChannelAccess(channel, nickname, access[i]);
  276. if (hasAccess)
  277. {
  278. break;
  279. }
  280. }
  281. return hasAccess;
  282. }
  283. /// <summary>
  284. /// Checks to see if the first nick has access to perform a command on the second nick
  285. /// </summary>
  286. /// <param name="channel">Channel the command is being applied on</param>
  287. /// <param name="firstNick">The nick applying the command</param>
  288. /// <param name="secondNick">The nick the command is being performed on</param>
  289. /// <returns></returns>
  290. public bool CheckNickAccess(string channel, string firstNick, string secondNick)
  291. {
  292. if (firstNick == IRC.Nickname)
  293. {
  294. return true;
  295. }
  296. Channel foundChannel = IRC.Channels.Find(chan => chan.Name == channel);
  297. if (foundChannel != null)
  298. {
  299. Nick foundFirstNick = foundChannel.Nicks.Find(nick => nick.Nickname == firstNick);
  300. Nick foundSecondNick = foundChannel.Nicks.Find(nick => nick.Nickname == secondNick);
  301. if (foundFirstNick != null && ServerConfig.Owners.Contains(firstNick) && foundFirstNick.Modes.Contains(UserMode.r))
  302. {
  303. return true;
  304. }
  305. if (foundFirstNick != null && foundSecondNick != null)
  306. {
  307. for (int i = 0; i < foundSecondNick.Privileges.Count; i++)
  308. {
  309. switch (foundSecondNick.Privileges[i])
  310. {
  311. case PrivilegeMode.v:
  312. if (!foundFirstNick.Privileges.Contains(PrivilegeMode.v) && !foundFirstNick.Privileges.Contains(PrivilegeMode.h) && !foundFirstNick.Privileges.Contains(PrivilegeMode.o) && !foundFirstNick.Privileges.Contains(PrivilegeMode.a) && !foundFirstNick.Privileges.Contains(PrivilegeMode.q))
  313. {
  314. return false;
  315. }
  316. break;
  317. case PrivilegeMode.h:
  318. if (!foundFirstNick.Privileges.Contains(PrivilegeMode.h) && !foundFirstNick.Privileges.Contains(PrivilegeMode.o) && !foundFirstNick.Privileges.Contains(PrivilegeMode.a) && !foundFirstNick.Privileges.Contains(PrivilegeMode.q))
  319. {
  320. return false;
  321. }
  322. break;
  323. case PrivilegeMode.o:
  324. if (!foundFirstNick.Privileges.Contains(PrivilegeMode.o) && !foundFirstNick.Privileges.Contains(PrivilegeMode.a) && !foundFirstNick.Privileges.Contains(PrivilegeMode.q))
  325. {
  326. return false;
  327. }
  328. break;
  329. case PrivilegeMode.a:
  330. if (!foundFirstNick.Privileges.Contains(PrivilegeMode.a) && !foundFirstNick.Privileges.Contains(PrivilegeMode.q))
  331. {
  332. return false;
  333. }
  334. break;
  335. case PrivilegeMode.q:
  336. if (!foundFirstNick.Privileges.Contains(PrivilegeMode.q))
  337. {
  338. return false;
  339. }
  340. break;
  341. }
  342. }
  343. }
  344. else
  345. {
  346. return (foundFirstNick != null);
  347. }
  348. }
  349. else
  350. {
  351. return false;
  352. }
  353. return true;
  354. }
  355. public void ExecuteCommand(string message, string location, MessageType type)
  356. {
  357. ParseCommandMessage(DateTime.Now, message, new Nick { Nickname = IRC.Nickname }, location, type);
  358. }
  359. public void ExecuteCommand(string message, string location, MessageType type, Nick nick)
  360. {
  361. ParseCommandMessage(DateTime.Now, message, nick, location, type);
  362. }
  363. public string GetCommand(string message)
  364. {
  365. string command = string.Empty;
  366. string[] msgArgs = message.Split(new[] {' '}, 2, StringSplitOptions.RemoveEmptyEntries);
  367. if (msgArgs.Any())
  368. {
  369. if (msgArgs[0].StartsWith(ServerConfig.CommandPrefix))
  370. {
  371. command = msgArgs[0].Remove(0, ServerConfig.CommandPrefix.Length);
  372. }
  373. }
  374. return command;
  375. }
  376. public bool IsCommand(string message)
  377. {
  378. bool isCommand = false;
  379. string command = GetCommand(message);
  380. // Find the module that contains the command
  381. Module module = Modules.Find(mod => mod.Commands.Exists(c => c.Triggers.Contains(command)) && mod.Loaded && mod.Enabled);
  382. if (module != null)
  383. {
  384. // Find the command
  385. Command cmd = module.Commands.Find(c => c.Triggers.Contains(command));
  386. if (cmd != null)
  387. {
  388. isCommand = true;
  389. }
  390. }
  391. return isCommand;
  392. }
  393. private void HandleJoinEvent(object sender, JoinChannelInfo info)
  394. {
  395. if (info.Nick.Nickname == IRC.Nickname)
  396. {
  397. if (!ServerConfig.Channels.Exists(chan => chan.Name == info.Channel))
  398. {
  399. ChannelConfig chanConfig = new ChannelConfig();
  400. chanConfig.Name = info.Channel;
  401. ServerConfig.Channels.Add(chanConfig);
  402. ServerConfig.Save();
  403. }
  404. }
  405. }
  406. private void HandleKickEvent(object sender, KickInfo info)
  407. {
  408. if (info.KickedNick.Nickname == IRC.Nickname)
  409. {
  410. ServerConfig.Channels.RemoveAll(chan => chan.Name == info.Channel);
  411. ServerConfig.Save();
  412. }
  413. }
  414. private void HandleChannelModeChangeEvent(object sender, ChannelModeChangeInfo e)
  415. {
  416. ChannelConfig channel = ServerConfig.Channels.Find(chan => chan.Name == e.Channel);
  417. if (channel != null)
  418. {
  419. foreach (ChannelModeInfo mode in e.Modes)
  420. {
  421. switch (mode.Mode)
  422. {
  423. case ChannelMode.k:
  424. channel.Key = (mode.Set) ? mode.Parameter : string.Empty;
  425. ServerConfig.Save();
  426. break;
  427. }
  428. }
  429. }
  430. }
  431. private void HandleReplyEvent(object sender, IReply e)
  432. {
  433. if (e.GetType() == typeof(ServerReplyMessage))
  434. {
  435. ServerReplyMessage reply = (ServerReplyMessage)e;
  436. switch (reply.ReplyCode)
  437. {
  438. case IRCReplyCode.RPL_WELCOME:
  439. // If the reply is Welcome, that means we are fully connected to the server.
  440. LoggedIn = true;
  441. if (!GhostSent && PreNickChoice >= 0 && IRC.Nickname != ServerConfig.Nicknames[PreNickChoice])
  442. {
  443. IRC.Command.SendPrivateMessage("NickServ", string.Format("GHOST {0} {1}", ServerConfig.Nicknames[PreNickChoice], ServerConfig.Password));
  444. Thread.Sleep(1000);
  445. IRC.Command.SendNick(ServerConfig.Nicknames[PreNickChoice]);
  446. GhostSent = true;
  447. }
  448. // Identify to NickServ if need be
  449. IRC.Command.SendPrivateMessage("NickServ", string.Format("IDENTIFY {0}", ServerConfig.Password));
  450. // Join all required channels
  451. // Delay joining channels for configured time
  452. Thread.Sleep(ServerConfig.JoinDelay);
  453. foreach (ChannelConfig channel in ServerConfig.Channels)
  454. {
  455. IRC.Command.SendJoin(channel.Name, channel.Key);
  456. }
  457. break;
  458. }
  459. }
  460. else if (e.GetType() == typeof(ServerErrorMessage))
  461. {
  462. ServerErrorMessage error = (ServerErrorMessage) e;
  463. switch (error.ErrorCode)
  464. {
  465. case IRCErrorCode.ERR_NOTREGISTERED:
  466. if (ServerConfig.AutoRegister && ServerConfig.Password != string.Empty && ServerConfig.Email != string.Empty)
  467. {
  468. IRC.Command.SendPrivateMessage("NickServ", string.Format("REGISTER {0} {1}", ServerConfig.Password, ServerConfig.Email));
  469. }
  470. break;
  471. case IRCErrorCode.ERR_NICKNAMEINUSE:
  472. if (LoggedIn == false)
  473. {
  474. string nick;
  475. if (IRC.Nickname == ServerConfig.Nicknames[CurNickChoice] && ServerConfig.Nicknames.Count > CurNickChoice + 1)
  476. {
  477. GhostSent = false;
  478. CurNickChoice++;
  479. PreNickChoice++;
  480. nick = ServerConfig.Nicknames[CurNickChoice];
  481. }
  482. else
  483. {
  484. Random rand = new Random();
  485. nick = string.Format("{0}_{1}", ServerConfig.Nicknames.First(), rand.Next(100000).ToString());
  486. }
  487. IRC.Login(ServerConfig.Name, new Nick()
  488. {
  489. Nickname = nick,
  490. Host = Dns.GetHostName(),
  491. Realname = ServerConfig.Realname,
  492. Username = ServerConfig.Username
  493. });
  494. }
  495. break;
  496. }
  497. }
  498. }
  499. private void HandleChannelMessageReceivedEvent(object sender, ChannelMessage e)
  500. {
  501. // The message was a command
  502. if (e.Message.StartsWith(ServerConfig.CommandPrefix))
  503. {
  504. if (!ServerConfig.ChannelBlacklist.Contains(e.Channel)
  505. && !ServerConfig.NickBlacklist.Contains(e.Sender.Nickname)
  506. )
  507. {
  508. ParseCommandMessage(e.TimeStamp, e.Message, e.Sender, e.Channel, MessageType.Channel);
  509. }
  510. }
  511. }
  512. private void HandlePrivateMessageReceivedEvent(object sender, PrivateMessage e)
  513. {
  514. // The message was a command
  515. if (e.Message.StartsWith(ServerConfig.CommandPrefix))
  516. {
  517. if (!ServerConfig.NickBlacklist.Contains(e.Sender.Nickname))
  518. {
  519. ParseCommandMessage(e.TimeStamp, e.Message, e.Sender, e.Sender.Nickname, MessageType.Query);
  520. }
  521. }
  522. }
  523. private void HandlePrivateNoticeReceivedEvent(object sender, PrivateNotice e)
  524. {
  525. // The notice was a command
  526. if (e.Message.StartsWith(ServerConfig.CommandPrefix))
  527. {
  528. if (!ServerConfig.NickBlacklist.Contains(e.Sender.Nickname))
  529. {
  530. ParseCommandMessage(e.TimeStamp, e.Message, e.Sender, e.Sender.Nickname, MessageType.Notice);
  531. }
  532. }
  533. }
  534. private void ParseCommandMessage(DateTime timestamp, string message, Nick sender, string location, MessageType messageType)
  535. {
  536. // Extract command and arguments
  537. string[] msgArgs = message.Split(new[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries);
  538. string command = msgArgs[0].Remove(0, ServerConfig.CommandPrefix.Length);
  539. List<string> argsOnly = msgArgs.ToList();
  540. argsOnly.RemoveAt(0);
  541. // Find the module that contains the command
  542. Module module = Modules.Find(mod => mod.Commands.Exists(c => c.Triggers.Contains(command)) && mod.Loaded && mod.Enabled);
  543. if (module != null)
  544. {
  545. // Find the command
  546. Command cmd = module.Commands.Find(c => c.Triggers.Contains(command));
  547. if (cmd != null)
  548. {
  549. CommandMessage newCommand = new CommandMessage();
  550. newCommand.Nick.Copy(sender);
  551. bool nickFound = false;
  552. if (messageType == MessageType.Channel)
  553. {
  554. Channel foundChannel = IRC.Channels.Find(chan => chan.Name == location);
  555. if (foundChannel != null)
  556. {
  557. foundChannel.Nicks.ForEach(nick =>
  558. {
  559. if (nick.Nickname == newCommand.Nick.Nickname)
  560. {
  561. nickFound = true;
  562. newCommand.Nick.AddModes(nick.Modes);
  563. newCommand.Nick.AddPrivileges(nick.Privileges);
  564. }
  565. });
  566. }
  567. }
  568. else
  569. {
  570. IRC.Channels.ForEach(channel => channel.Nicks.ForEach(nick =>
  571. {
  572. if (nick.Nickname == newCommand.Nick.Nickname)
  573. {
  574. nickFound = true;
  575. newCommand.Nick.AddModes(nick.Modes);
  576. newCommand.Nick.AddPrivileges(nick.Privileges);
  577. }
  578. }));
  579. }
  580. // Nickname has not been found, so need to run a query for nick's modes
  581. if (!nickFound)
  582. {
  583. string whoStyle = string.Format(@"[^\s]+\s[^\s]+\s[^\s]+\s[^\s]+\s({0})\s(?<Modes>[^\s]+)\s:[\d]\s(.+)", newCommand.Nick.Nickname);
  584. Regex whoRegex = new Regex(whoStyle);
  585. IRC.Command.SendWho(newCommand.Nick.Nickname);
  586. ServerReplyMessage whoReply = IRC.Message.GetServerReply(IRCReplyCode.RPL_WHOREPLY, whoStyle);
  587. if (whoReply != null && whoReply.ReplyCode != 0)
  588. {
  589. Match whoMatch = whoRegex.Match(whoReply.Message);
  590. List<UserModeInfo> modeInfoList = IRC.ParseUserModeString(whoMatch.Groups["Modes"].ToString());
  591. modeInfoList.ForEach(info =>
  592. {
  593. if (info.Set)
  594. {
  595. newCommand.Nick.AddMode(info.Mode);
  596. }
  597. });
  598. }
  599. }
  600. newCommand.TimeStamp = timestamp;
  601. newCommand.Location = location;
  602. newCommand.MessageType = messageType;
  603. newCommand.Command = command;
  604. // Check arguments against required arguments
  605. List<string> usedArgs = new List<string>();
  606. if (argsOnly.Any())
  607. {
  608. usedArgs.AddRange(argsOnly.First().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList());
  609. }
  610. List<CommandArgument> validArguments = cmd.GetValidArguments(usedArgs, messageType);
  611. if (argsOnly.Count > 0)
  612. {
  613. string[] argSplit = argsOnly.First().Split(new[] { ' ' }, validArguments.Count, StringSplitOptions.RemoveEmptyEntries);
  614. for (int i = 0; i < validArguments.Count && i <= argSplit.GetUpperBound(0); i++)
  615. {
  616. newCommand.Arguments.Add(validArguments[i].Name, argSplit[i]);
  617. }
  618. }
  619. bool invalidArgs = false;
  620. for (int i = 0; i < newCommand.Arguments.Count; i++)
  621. {
  622. if (validArguments[i].AllowedValues.Count > 0)
  623. {
  624. // Check to see if any of the arguments are invalid
  625. string argVal = newCommand.Arguments[validArguments[i].Name];
  626. if (!validArguments[i].AllowedValues.Exists(val => val.ToLower() == argVal.ToLower()))
  627. {
  628. invalidArgs = true;
  629. string argHelp = string.Format(" \u0002{0}\u0002", string.Join(" ", validArguments.Select(arg =>
  630. {
  631. string argString = string.Empty;
  632. if (arg.DependentArguments.Count > 0)
  633. {
  634. argString = "(";
  635. }
  636. if (arg.Required)
  637. {
  638. argString += "\u001F" + arg.Name + "\u001F";
  639. }
  640. else
  641. {
  642. argString += "[\u001F" + arg.Name + "\u001F]";
  643. }
  644. if (arg.DependentArguments.Count > 0)
  645. {
  646. argString += string.Format("\u0002:When {0}\u0002)", string.Join(" or ", arg.DependentArguments.Select(dep => { return string.Format("\u0002\u001F{0}\u001F\u0002=\u0002{1}\u0002", dep.Name, string.Join(",", dep.Values)); })));
  647. }
  648. return argString;
  649. })));
  650. string invalidMessage = string.Format("Invalid value for \u0002{0}\u0002 in \u0002{1}{2}\u0002{3}. Valid options are \u0002{4}\u0002.", validArguments[i].Name, ServerConfig.CommandPrefix, command, argHelp, string.Join(", ", validArguments[i].AllowedValues));
  651. module.SendResponse(messageType, location, sender.Nickname, invalidMessage);
  652. break;
  653. }
  654. }
  655. }
  656. if (validArguments.FindAll(arg => arg.Required).Count <= newCommand.Arguments.Count)
  657. {
  658. if (!invalidArgs)
  659. {
  660. if (CommandReceivedEvent != null)
  661. {
  662. CommandReceivedEvent(newCommand);
  663. }
  664. }
  665. }
  666. else
  667. {
  668. string argHelp = string.Format(" \u0002{0}\u0002", string.Join(" ", validArguments.Select(arg =>
  669. {
  670. string argString = string.Empty;
  671. if (arg.DependentArguments.Count > 0)
  672. {
  673. argString = "(";
  674. }
  675. if (arg.Required)
  676. {
  677. argString += "\u001F" + arg.Name + "\u001F";
  678. }
  679. else
  680. {
  681. argString += "[\u001F" + arg.Name + "\u001F]";
  682. }
  683. if (arg.DependentArguments.Count > 0)
  684. {
  685. argString += string.Format("\u0002:When {0}\u0002)", string.Join(" or ", arg.DependentArguments.Select(dep => { return string.Format("\u0002\u001F{0}\u001F\u0002=\u0002{1}\u0002", dep.Name, string.Join(",", dep.Values)); })));
  686. }
  687. return argString;
  688. })));
  689. string missingArgument = string.Format("Missing a required argument for \u0002{0}{1}\u0002{2}. The required arguments are \u0002{3}\u0002.", ServerConfig.CommandPrefix, command, argHelp, string.Join(", ", validArguments.Where(arg => arg.Required).Select(arg => arg.Name)));
  690. module.SendResponse(messageType, location, sender.Nickname, missingArgument);
  691. }
  692. }
  693. }
  694. }
  695. private void HandleMysqlErrorEvent(object sender, string message)
  696. {
  697. BotError error = new BotError();
  698. error.Message = message;
  699. error.Type = ErrorType.MySQL;
  700. if (ErrorEvent != null)
  701. {
  702. ErrorEvent(error);
  703. }
  704. }
  705. private void HandleModuleErrorEvent(object sender, string message)
  706. {
  707. BotError error = new BotError();
  708. error.Message = message;
  709. error.Type = ErrorType.Module;
  710. if (ErrorEvent != null)
  711. {
  712. ErrorEvent(error);
  713. }
  714. }
  715. }
  716. }